define type vcsGetOption struct

This commit is contained in:
Songmu 2019-12-17 23:03:53 +09:00
parent ddbfb719e7
commit 676ed981c9
4 changed files with 214 additions and 98 deletions

View file

@ -51,18 +51,18 @@ func withFakeGitBackend(t *testing.T, block func(*testing.T, string, *_cloneArgs
var originalGitBackend = GitBackend
tmpBackend := &VCSBackend{
Clone: func(remote *url.URL, local string, shallow, silent bool, branch string) error {
Clone: func(vg *vcsGetOption) error {
cloneArgs = _cloneArgs{
remote: remote,
local: filepath.FromSlash(local),
shallow: shallow,
branch: branch,
remote: vg.url,
local: filepath.FromSlash(vg.dir),
shallow: vg.shallow,
branch: vg.branch,
}
return nil
},
Update: func(local string, silent bool) error {
Update: func(vg *vcsGetOption) error {
updateArgs = _updateArgs{
local: local,
local: vg.dir,
}
return nil
},

View file

@ -135,7 +135,13 @@ func (g *getter) getRemoteRepository(remote RemoteRepository) error {
}
if getRepoLock(localRepoRoot) {
return vcs.Clone(repoURL, localRepoRoot, g.shallow, g.silent, g.branch)
return vcs.Clone(&vcsGetOption{
url: repoURL,
dir: localRepoRoot,
shallow: g.shallow,
silent: g.silent,
branch: g.branch,
})
}
return nil
}
@ -146,7 +152,10 @@ func (g *getter) getRemoteRepository(remote RemoteRepository) error {
return fmt.Errorf("failed to detect VCS for %q", fpath)
}
if getRepoLock(localRepoRoot) {
return vcs.Update(localRepoRoot, g.silent)
return vcs.Update(&vcsGetOption{
dir: localRepoRoot,
silent: g.silent,
})
}
return nil
}

127
vcs.go
View file

@ -26,36 +26,43 @@ func runInDir(silent bool) func(dir, command string, args ...string) error {
// A VCSBackend represents a VCS backend.
type VCSBackend struct {
// Clones a remote repository to local path.
Clone func(*url.URL, string, bool, bool, string) error
Clone func(*vcsGetOption) error
// Updates a cloned local repository.
Update func(string, bool) error
Update func(*vcsGetOption) error
// Returns VCS specific files
Contents func() []string
}
type vcsGetOption struct {
url *url.URL
dir string
recursive, shallow, silent bool
branch string
}
// GitBackend is the VCSBackend of git
var GitBackend = &VCSBackend{
// support submodules?
Clone: func(remote *url.URL, local string, shallow, silent bool, branch string) error {
dir, _ := filepath.Split(local)
Clone: func(vg *vcsGetOption) error {
dir, _ := filepath.Split(vg.dir)
err := os.MkdirAll(dir, 0755)
if err != nil {
return err
}
args := []string{"clone"}
if shallow {
if vg.shallow {
args = append(args, "--depth", "1")
}
if branch != "" {
args = append(args, "--branch", branch, "--single-branch")
if vg.branch != "" {
args = append(args, "--branch", vg.branch, "--single-branch")
}
args = append(args, remote.String(), local)
args = append(args, vg.url.String(), vg.dir)
return run(silent)("git", args...)
return run(vg.silent)("git", args...)
},
Update: func(local string, silent bool) error {
return runInDir(silent)(local, "git", "pull", "--ff-only")
Update: func(vg *vcsGetOption) error {
return runInDir(vg.silent)(vg.dir, "git", "pull", "--ff-only")
},
Contents: func() []string {
return []string{".git"}
@ -64,28 +71,29 @@ var GitBackend = &VCSBackend{
// SubversionBackend is the VCSBackend for subversion
var SubversionBackend = &VCSBackend{
Clone: func(remote *url.URL, local string, shallow, silent bool, branch string) error {
dir, _ := filepath.Split(local)
Clone: func(vg *vcsGetOption) error {
dir, _ := filepath.Split(vg.dir)
err := os.MkdirAll(dir, 0755)
if err != nil {
return err
}
args := []string{"checkout"}
if shallow {
if vg.shallow {
args = append(args, "--depth", "1")
}
if branch != "" {
copied := *remote
remote := vg.url
if vg.branch != "" {
copied := *vg.url
remote = &copied
remote.Path += "/branches/" + url.PathEscape(branch)
remote.Path += "/branches/" + url.PathEscape(vg.branch)
}
args = append(args, remote.String(), local)
args = append(args, remote.String(), vg.dir)
return run(silent)("svn", args...)
return run(vg.silent)("svn", args...)
},
Update: func(local string, silent bool) error {
return runInDir(silent)(local, "svn", "update")
Update: func(vg *vcsGetOption) error {
return runInDir(vg.silent)(vg.dir, "svn", "update")
},
Contents: func() []string {
return []string{".svn"}
@ -95,22 +103,23 @@ var SubversionBackend = &VCSBackend{
// GitsvnBackend is the VCSBackend for git-svn
var GitsvnBackend = &VCSBackend{
// git-svn seems not supporting shallow clone currently.
Clone: func(remote *url.URL, local string, ignoredShallow, silent bool, branch string) error {
dir, _ := filepath.Split(local)
Clone: func(vg *vcsGetOption) error {
dir, _ := filepath.Split(vg.dir)
err := os.MkdirAll(dir, 0755)
if err != nil {
return err
}
if branch != "" {
remote := vg.url
if vg.branch != "" {
copied := *remote
remote = &copied
remote.Path += "/branches/" + url.PathEscape(branch)
remote.Path += "/branches/" + url.PathEscape(vg.branch)
}
return run(silent)("git", "svn", "clone", remote.String(), local)
return run(vg.silent)("git", "svn", "clone", remote.String(), vg.dir)
},
Update: func(local string, silent bool) error {
return runInDir(silent)(local, "git", "svn", "rebase")
Update: func(vg *vcsGetOption) error {
return runInDir(vg.silent)(vg.dir, "git", "svn", "rebase")
},
Contents: func() []string {
return []string{".git/svn"}
@ -120,22 +129,22 @@ var GitsvnBackend = &VCSBackend{
// MercurialBackend is the VCSBackend for mercurial
var MercurialBackend = &VCSBackend{
// Mercurial seems not supporting shallow clone currently.
Clone: func(remote *url.URL, local string, ignoredShallow, silent bool, branch string) error {
dir, _ := filepath.Split(local)
Clone: func(vg *vcsGetOption) error {
dir, _ := filepath.Split(vg.dir)
err := os.MkdirAll(dir, 0755)
if err != nil {
return err
}
args := []string{"clone"}
if branch != "" {
args = append(args, "--branch", branch)
if vg.branch != "" {
args = append(args, "--branch", vg.branch)
}
args = append(args, remote.String(), local)
args = append(args, vg.url.String(), vg.dir)
return run(silent)("hg", args...)
return run(vg.silent)("hg", args...)
},
Update: func(local string, silent bool) error {
return runInDir(silent)(local, "hg", "pull", "--update")
Update: func(vg *vcsGetOption) error {
return runInDir(vg.silent)(vg.dir, "hg", "pull", "--update")
},
Contents: func() []string {
return []string{".hg"}
@ -144,27 +153,27 @@ var MercurialBackend = &VCSBackend{
// DarcsBackend is the VCSBackend for darcs
var DarcsBackend = &VCSBackend{
Clone: func(remote *url.URL, local string, shallow, silent bool, branch string) error {
if branch != "" {
Clone: func(vg *vcsGetOption) error {
if vg.branch != "" {
return errors.New("Darcs does not support branch")
}
dir, _ := filepath.Split(local)
dir, _ := filepath.Split(vg.dir)
err := os.MkdirAll(dir, 0755)
if err != nil {
return err
}
args := []string{"get"}
if shallow {
if vg.shallow {
args = append(args, "--lazy")
}
args = append(args, remote.String(), local)
args = append(args, vg.url.String(), vg.dir)
return run(silent)("darcs", args...)
return run(vg.silent)("darcs", args...)
},
Update: func(local string, silent bool) error {
return runInDir(silent)(local, "darcs", "pull")
Update: func(vg *vcsGetOption) error {
return runInDir(vg.silent)(vg.dir, "darcs", "pull")
},
Contents: func() []string {
return []string{"_darcs"}
@ -172,10 +181,10 @@ var DarcsBackend = &VCSBackend{
}
var cvsDummyBackend = &VCSBackend{
Clone: func(remote *url.URL, local string, ignoredShallow, silent bool, branch string) error {
Clone: func(vg *vcsGetOption) error {
return errors.New("CVS clone is not supported")
},
Update: func(local string, silent bool) error {
Update: func(vg *vcsGetOption) error {
return errors.New("CVS update is not supported")
},
Contents: func() []string {
@ -187,21 +196,21 @@ const fossilRepoName = ".fossil" // same as Go
// FossilBackend is the VCSBackend for fossil
var FossilBackend = &VCSBackend{
Clone: func(remote *url.URL, local string, shallow, silent bool, branch string) error {
if branch != "" {
Clone: func(vg *vcsGetOption) error {
if vg.branch != "" {
return errors.New("Fossil does not support cloning specific branch")
}
if err := os.MkdirAll(local, 0755); err != nil {
if err := os.MkdirAll(vg.dir, 0755); err != nil {
return err
}
if err := run(silent)("fossil", "clone", remote.String(), filepath.Join(local, fossilRepoName)); err != nil {
if err := run(vg.silent)("fossil", "clone", vg.url.String(), filepath.Join(vg.dir, fossilRepoName)); err != nil {
return err
}
return runInDir(silent)(local, "fossil", "open", fossilRepoName)
return runInDir(vg.silent)(vg.dir, "fossil", "open", fossilRepoName)
},
Update: func(local string, silent bool) error {
return runInDir(silent)(local, "fossil", "update")
Update: func(vg *vcsGetOption) error {
return runInDir(vg.silent)(vg.dir, "fossil", "update")
},
Contents: func() []string {
return []string{".fslckout", "_FOSSIL_"}
@ -211,20 +220,20 @@ var FossilBackend = &VCSBackend{
// BazaarBackend is the VCSBackend for bazaar
var BazaarBackend = &VCSBackend{
// bazaar seems not supporting shallow clone currently.
Clone: func(remote *url.URL, local string, ignoredShallow, silent bool, branch string) error {
if branch != "" {
Clone: func(vg *vcsGetOption) error {
if vg.branch != "" {
return errors.New("--branch option is unavailable for Bazaar since branch is included in remote URL")
}
dir, _ := filepath.Split(local)
dir, _ := filepath.Split(vg.dir)
err := os.MkdirAll(dir, 0755)
if err != nil {
return err
}
return run(silent)("bzr", "branch", remote.String(), local)
return run(vg.silent)("bzr", "branch", vg.url.String(), vg.dir)
},
Update: func(local string, silent bool) error {
Update: func(vg *vcsGetOption) error {
// Without --overwrite bzr will not pull tags that changed.
return runInDir(silent)(local, "bzr", "pull", "--overwrite")
return runInDir(vg.silent)(vg.dir, "bzr", "pull", "--overwrite")
},
Contents: func() []string {
return []string{".bzr"}

View file

@ -34,152 +34,229 @@ func TestVCSBackend(t *testing.T) {
}{{
name: "[git] clone",
f: func() error {
return GitBackend.Clone(remoteDummyURL, localDir, false, false, "")
return GitBackend.Clone(&vcsGetOption{
url: remoteDummyURL,
dir: localDir,
})
},
expect: []string{"git", "clone", remoteDummyURL.String(), localDir},
}, {
name: "[git] shallow clone",
f: func() error {
return GitBackend.Clone(remoteDummyURL, localDir, true, true, "")
return GitBackend.Clone(&vcsGetOption{
url: remoteDummyURL,
dir: localDir,
shallow: true,
silent: true,
})
},
expect: []string{"git", "clone", "--depth", "1", remoteDummyURL.String(), localDir},
}, {
name: "[git] clone specific branch",
f: func() error {
return GitBackend.Clone(remoteDummyURL, localDir, false, false, "hello")
return GitBackend.Clone(&vcsGetOption{
url: remoteDummyURL,
dir: localDir,
branch: "hello",
})
},
expect: []string{"git", "clone", "--branch", "hello", "--single-branch", remoteDummyURL.String(), localDir},
}, {
name: "[git] update",
f: func() error {
return GitBackend.Update(localDir, false)
return GitBackend.Update(&vcsGetOption{
dir: localDir,
})
},
expect: []string{"git", "pull", "--ff-only"},
dir: localDir,
}, {
name: "[svn] checkout",
f: func() error {
return SubversionBackend.Clone(remoteDummyURL, localDir, false, false, "")
return SubversionBackend.Clone(&vcsGetOption{
url: remoteDummyURL,
dir: localDir,
})
},
expect: []string{"svn", "checkout", remoteDummyURL.String(), localDir},
}, {
name: "[svn] checkout shallow",
f: func() error {
return SubversionBackend.Clone(remoteDummyURL, localDir, true, false, "")
return SubversionBackend.Clone(&vcsGetOption{
url: remoteDummyURL,
dir: localDir,
shallow: true,
})
},
expect: []string{"svn", "checkout", "--depth", "1", remoteDummyURL.String(), localDir},
}, {
name: "[svn] checkout specific branch",
f: func() error {
return SubversionBackend.Clone(remoteDummyURL, localDir, false, false, "hello")
return SubversionBackend.Clone(&vcsGetOption{
url: remoteDummyURL,
dir: localDir,
branch: "hello",
})
},
expect: []string{"svn", "checkout", remoteDummyURL.String() + "/branches/hello", localDir},
}, {
name: "[svn] update",
f: func() error {
return SubversionBackend.Update(localDir, true)
return SubversionBackend.Update(&vcsGetOption{
dir: localDir,
silent: true,
})
},
expect: []string{"svn", "update"},
dir: localDir,
}, {
name: "[git-svn] clone",
f: func() error {
return GitsvnBackend.Clone(remoteDummyURL, localDir, false, false, "")
return GitsvnBackend.Clone(&vcsGetOption{
url: remoteDummyURL,
dir: localDir,
})
},
expect: []string{"git", "svn", "clone", remoteDummyURL.String(), localDir},
}, {
name: "[git-svn] update",
f: func() error {
return GitsvnBackend.Update(localDir, false)
return GitsvnBackend.Update(&vcsGetOption{
dir: localDir,
})
},
expect: []string{"git", "svn", "rebase"},
dir: localDir,
}, {
name: "[git-svn] clone shallow",
f: func() error {
return GitsvnBackend.Clone(remoteDummyURL, localDir, true, false, "")
return GitsvnBackend.Clone(&vcsGetOption{
url: remoteDummyURL,
dir: localDir,
shallow: true,
})
},
expect: []string{"git", "svn", "clone", remoteDummyURL.String(), localDir},
}, {
name: "[git-svn] clone specific branch",
f: func() error {
return GitsvnBackend.Clone(remoteDummyURL, localDir, false, false, "hello")
return GitsvnBackend.Clone(&vcsGetOption{
url: remoteDummyURL,
dir: localDir,
branch: "hello",
})
},
expect: []string{"git", "svn", "clone", remoteDummyURL.String() + "/branches/hello", localDir},
}, {
name: "[hg] clone",
f: func() error {
return MercurialBackend.Clone(remoteDummyURL, localDir, false, false, "")
return MercurialBackend.Clone(&vcsGetOption{
url: remoteDummyURL,
dir: localDir,
})
},
expect: []string{"hg", "clone", remoteDummyURL.String(), localDir},
}, {
name: "[hg] update",
f: func() error {
return MercurialBackend.Update(localDir, false)
return MercurialBackend.Update(&vcsGetOption{
dir: localDir,
})
},
expect: []string{"hg", "pull", "--update"},
dir: localDir,
}, {
name: "[hg] clone shallow",
f: func() error {
return MercurialBackend.Clone(remoteDummyURL, localDir, true, false, "")
return MercurialBackend.Clone(&vcsGetOption{
url: remoteDummyURL,
dir: localDir,
shallow: true,
})
},
expect: []string{"hg", "clone", remoteDummyURL.String(), localDir},
}, {
name: "[hg] clone specific branch",
f: func() error {
return MercurialBackend.Clone(remoteDummyURL, localDir, false, false, "hello")
return MercurialBackend.Clone(&vcsGetOption{
url: remoteDummyURL,
dir: localDir,
branch: "hello",
})
},
expect: []string{"hg", "clone", "--branch", "hello", remoteDummyURL.String(), localDir},
}, {
name: "[darcs] clone",
f: func() error {
return DarcsBackend.Clone(remoteDummyURL, localDir, false, false, "")
return DarcsBackend.Clone(&vcsGetOption{
url: remoteDummyURL,
dir: localDir,
})
},
expect: []string{"darcs", "get", remoteDummyURL.String(), localDir},
}, {
name: "[darcs] clone shallow",
f: func() error {
return DarcsBackend.Clone(remoteDummyURL, localDir, true, false, "")
return DarcsBackend.Clone(&vcsGetOption{
url: remoteDummyURL,
dir: localDir,
shallow: true,
})
},
expect: []string{"darcs", "get", "--lazy", remoteDummyURL.String(), localDir},
}, {
name: "[darcs] update",
f: func() error {
return DarcsBackend.Update(localDir, false)
return DarcsBackend.Update(&vcsGetOption{
dir: localDir,
})
},
expect: []string{"darcs", "pull"},
dir: localDir,
}, {
name: "[bzr] clone",
f: func() error {
return BazaarBackend.Clone(remoteDummyURL, localDir, false, false, "")
return BazaarBackend.Clone(&vcsGetOption{
url: remoteDummyURL,
dir: localDir,
})
},
expect: []string{"bzr", "branch", remoteDummyURL.String(), localDir},
}, {
name: "[bzr] update",
f: func() error {
return BazaarBackend.Update(localDir, false)
return BazaarBackend.Update(&vcsGetOption{
dir: localDir,
})
},
expect: []string{"bzr", "pull", "--overwrite"},
dir: localDir,
}, {
name: "[bzr] clone shallow",
f: func() error {
return BazaarBackend.Clone(remoteDummyURL, localDir, true, false, "")
return BazaarBackend.Clone(&vcsGetOption{
url: remoteDummyURL,
dir: localDir,
shallow: true,
})
},
expect: []string{"bzr", "branch", remoteDummyURL.String(), localDir},
}, {
name: "[fossil] clone",
f: func() error {
return FossilBackend.Clone(remoteDummyURL, localDir, false, false, "")
return FossilBackend.Clone(&vcsGetOption{
url: remoteDummyURL,
dir: localDir,
})
},
expect: []string{"fossil", "open", fossilRepoName},
dir: localDir,
}, {
name: "[fossil] update",
f: func() error {
return FossilBackend.Update(localDir, false)
return FossilBackend.Update(&vcsGetOption{
dir: localDir,
})
},
expect: []string{"fossil", "update"},
dir: localDir,
@ -206,15 +283,24 @@ func TestCvsDummyBackend(t *testing.T) {
defer os.RemoveAll(tempDir)
localDir := filepath.Join(tempDir, "repo")
if err := cvsDummyBackend.Clone(remoteDummyURL, localDir, false, false, ""); err == nil {
if err := cvsDummyBackend.Clone(&vcsGetOption{
url: remoteDummyURL,
dir: localDir,
}); err == nil {
t.Error("error should be occurred, but nil")
}
if err := cvsDummyBackend.Clone(remoteDummyURL, localDir, true, false, ""); err == nil {
if err := cvsDummyBackend.Clone(&vcsGetOption{
url: remoteDummyURL,
dir: localDir,
shallow: true,
}); err == nil {
t.Error("error should be occurred, but nil")
}
if err := cvsDummyBackend.Update(localDir, false); err == nil {
if err := cvsDummyBackend.Update(&vcsGetOption{
dir: localDir,
}); err == nil {
t.Error("error should be occurred, but nil")
}
}
@ -224,15 +310,27 @@ func TestBranchOptionIgnoredErrors(t *testing.T) {
defer os.RemoveAll(tempDir)
localDir := filepath.Join(tempDir, "repo")
if err := DarcsBackend.Clone(remoteDummyURL, localDir, false, false, "hello"); err == nil {
if err := DarcsBackend.Clone(&vcsGetOption{
url: remoteDummyURL,
dir: localDir,
branch: "hello",
}); err == nil {
t.Error("error should be occurred, but nil")
}
if err := FossilBackend.Clone(remoteDummyURL, localDir, false, false, "hello"); err == nil {
if err := FossilBackend.Clone(&vcsGetOption{
url: remoteDummyURL,
dir: localDir,
branch: "hello",
}); err == nil {
t.Error("error should be occurred, but nil")
}
if err := BazaarBackend.Clone(remoteDummyURL, localDir, false, false, "hello"); err == nil {
if err := BazaarBackend.Clone(&vcsGetOption{
url: remoteDummyURL,
dir: localDir,
branch: "hello",
}); err == nil {
t.Error("error should be occurred, but nil")
}
}