зеркало из https://github.com/golang/dep.git
Integrate context for essential vcs cmds
get, update, and listVersions are changed. There's a lot more to do here, but these are the most essential ones.
This commit is contained in:
Родитель
7e65302c73
Коммит
75dec7b2dc
28
cmd.go
28
cmd.go
|
@ -22,13 +22,12 @@ type monitoredCmd struct {
|
|||
stderr *activityBuffer
|
||||
}
|
||||
|
||||
func newMonitoredCmd(ctx context.Context, cmd *exec.Cmd, timeout time.Duration) *monitoredCmd {
|
||||
func newMonitoredCmd(cmd *exec.Cmd, timeout time.Duration) *monitoredCmd {
|
||||
stdout, stderr := newActivityBuffer(), newActivityBuffer()
|
||||
cmd.Stdout, cmd.Stderr = stdout, stderr
|
||||
return &monitoredCmd{
|
||||
cmd: cmd,
|
||||
timeout: timeout,
|
||||
ctx: ctx,
|
||||
stdout: stdout,
|
||||
stderr: stderr,
|
||||
}
|
||||
|
@ -37,7 +36,12 @@ func newMonitoredCmd(ctx context.Context, cmd *exec.Cmd, timeout time.Duration)
|
|||
// run will wait for the command to finish and return the error, if any. If the
|
||||
// command does not show any activity for more than the specified timeout the
|
||||
// process will be killed.
|
||||
func (c *monitoredCmd) run() error {
|
||||
func (c *monitoredCmd) run(ctx context.Context) error {
|
||||
// Check for cancellation before even starting
|
||||
if ctx.Err() != nil {
|
||||
return ctx.Err()
|
||||
}
|
||||
|
||||
ticker := time.NewTicker(c.timeout)
|
||||
done := make(chan error, 1)
|
||||
defer ticker.Stop()
|
||||
|
@ -53,7 +57,7 @@ func (c *monitoredCmd) run() error {
|
|||
|
||||
return &timeoutError{c.timeout}
|
||||
}
|
||||
case <-c.ctx.Done():
|
||||
case <-ctx.Done():
|
||||
if err := c.cmd.Process.Kill(); err != nil {
|
||||
return &killCmdError{err}
|
||||
}
|
||||
|
@ -70,8 +74,8 @@ func (c *monitoredCmd) hasTimedOut() bool {
|
|||
c.stdout.lastActivity().Before(t)
|
||||
}
|
||||
|
||||
func (c *monitoredCmd) combinedOutput() ([]byte, error) {
|
||||
if err := c.run(); err != nil {
|
||||
func (c *monitoredCmd) combinedOutput(ctx context.Context) ([]byte, error) {
|
||||
if err := c.run(ctx); err != nil {
|
||||
return c.stderr.buf.Bytes(), err
|
||||
}
|
||||
|
||||
|
@ -121,12 +125,12 @@ func (e killCmdError) Error() string {
|
|||
return fmt.Sprintf("error killing command: %s", e.err)
|
||||
}
|
||||
|
||||
func runFromCwd(cmd string, args ...string) ([]byte, error) {
|
||||
c := newMonitoredCmd(context.TODO(), exec.Command(cmd, args...), 2*time.Minute)
|
||||
return c.combinedOutput()
|
||||
func runFromCwd(ctx context.Context, cmd string, args ...string) ([]byte, error) {
|
||||
c := newMonitoredCmd(exec.Command(cmd, args...), 2*time.Minute)
|
||||
return c.combinedOutput(ctx)
|
||||
}
|
||||
|
||||
func runFromRepoDir(repo vcs.Repo, cmd string, args ...string) ([]byte, error) {
|
||||
c := newMonitoredCmd(context.TODO(), repo.CmdFromDir(cmd, args...), 2*time.Minute)
|
||||
return c.combinedOutput()
|
||||
func runFromRepoDir(ctx context.Context, repo vcs.Repo, cmd string, args ...string) ([]byte, error) {
|
||||
c := newMonitoredCmd(repo.CmdFromDir(cmd, args...), 2*time.Minute)
|
||||
return c.combinedOutput(ctx)
|
||||
}
|
||||
|
|
11
cmd_test.go
11
cmd_test.go
|
@ -10,13 +10,18 @@ import (
|
|||
)
|
||||
|
||||
func mkTestCmd(iterations int) *monitoredCmd {
|
||||
return newMonitoredCmd(context.Background(),
|
||||
return newMonitoredCmd(
|
||||
exec.Command("./echosleep", "-n", fmt.Sprint(iterations)),
|
||||
200*time.Millisecond,
|
||||
)
|
||||
}
|
||||
|
||||
func TestMonitoredCmd(t *testing.T) {
|
||||
// Sleeps make this a bit slow
|
||||
if testing.Short() {
|
||||
t.Skip("skipping test with sleeps on short")
|
||||
}
|
||||
|
||||
err := exec.Command("go", "build", "./_testdata/cmd/echosleep.go").Run()
|
||||
if err != nil {
|
||||
t.Errorf("Unable to build echosleep binary: %s", err)
|
||||
|
@ -24,7 +29,7 @@ func TestMonitoredCmd(t *testing.T) {
|
|||
defer os.Remove("./echosleep")
|
||||
|
||||
cmd := mkTestCmd(2)
|
||||
err = cmd.run()
|
||||
err = cmd.run(context.Background())
|
||||
if err != nil {
|
||||
t.Errorf("Expected command not to fail: %s", err)
|
||||
}
|
||||
|
@ -35,7 +40,7 @@ func TestMonitoredCmd(t *testing.T) {
|
|||
}
|
||||
|
||||
cmd2 := mkTestCmd(10)
|
||||
err = cmd2.run()
|
||||
err = cmd2.run(context.Background())
|
||||
if err == nil {
|
||||
t.Error("Expected command to fail")
|
||||
}
|
||||
|
|
|
@ -97,7 +97,7 @@ func (m maybeGitSource) try(ctx context.Context, cachedir string, c singleSource
|
|||
}
|
||||
|
||||
// Pinging invokes the same action as calling listVersions, so just do that.
|
||||
vl, err := src.listVersions()
|
||||
vl, err := src.listVersions(ctx)
|
||||
if err != nil {
|
||||
return nil, 0, fmt.Errorf("remote repository at %s does not exist, or is inaccessible", ustr)
|
||||
}
|
||||
|
@ -154,7 +154,7 @@ func (m maybeGopkginSource) try(ctx context.Context, cachedir string, c singleSo
|
|||
}
|
||||
|
||||
// Pinging invokes the same action as calling listVersions, so just do that.
|
||||
vl, err := src.listVersions()
|
||||
vl, err := src.listVersions(ctx)
|
||||
if err != nil {
|
||||
return nil, 0, fmt.Errorf("remote repository at %s does not exist, or is inaccessible", ustr)
|
||||
}
|
||||
|
|
21
source.go
21
source.go
|
@ -463,7 +463,7 @@ func (sg *sourceGateway) require(ctx context.Context, wanted sourceState) (errSt
|
|||
}
|
||||
case sourceExistsLocally:
|
||||
if !sg.src.existsLocally(ctx) {
|
||||
err = sg.src.initLocal()
|
||||
err = sg.src.initLocal(ctx)
|
||||
if err == nil {
|
||||
addlState |= sourceHasLatestLocally
|
||||
} else {
|
||||
|
@ -472,12 +472,12 @@ func (sg *sourceGateway) require(ctx context.Context, wanted sourceState) (errSt
|
|||
}
|
||||
case sourceHasLatestVersionList:
|
||||
var pvl []PairedVersion
|
||||
pvl, err = sg.src.listVersions()
|
||||
pvl, err = sg.src.listVersions(ctx)
|
||||
if err != nil {
|
||||
sg.cache.storeVersionMap(pvl, true)
|
||||
}
|
||||
case sourceHasLatestLocally:
|
||||
err = sg.src.updateLocal()
|
||||
err = sg.src.updateLocal(ctx)
|
||||
}
|
||||
|
||||
if err != nil {
|
||||
|
@ -502,9 +502,9 @@ type source interface {
|
|||
existsLocally(context.Context) bool
|
||||
existsUpstream(context.Context) bool
|
||||
upstreamURL() string
|
||||
initLocal() error
|
||||
updateLocal() error
|
||||
listVersions() ([]PairedVersion, error)
|
||||
initLocal(context.Context) error
|
||||
updateLocal(context.Context) error
|
||||
listVersions(context.Context) ([]PairedVersion, error)
|
||||
getManifestAndLock(ProjectRoot, Revision, ProjectAnalyzer) (Manifest, Lock, error)
|
||||
listPackages(ProjectRoot, Revision) (pkgtree.PackageTree, error)
|
||||
revisionPresentIn(Revision) (bool, error)
|
||||
|
@ -524,6 +524,7 @@ func (bs *baseVCSSource) existsLocally(ctx context.Context) bool {
|
|||
return bs.crepo.r.CheckLocal()
|
||||
}
|
||||
|
||||
// TODO reimpl for git
|
||||
func (bs *baseVCSSource) existsUpstream(ctx context.Context) bool {
|
||||
return bs.crepo.r.Ping()
|
||||
}
|
||||
|
@ -557,9 +558,9 @@ func (bs *baseVCSSource) revisionPresentIn(r Revision) (bool, error) {
|
|||
|
||||
// initLocal clones/checks out the upstream repository to disk for the first
|
||||
// time.
|
||||
func (bs *baseVCSSource) initLocal() error {
|
||||
func (bs *baseVCSSource) initLocal(ctx context.Context) error {
|
||||
bs.crepo.mut.Lock()
|
||||
err := bs.crepo.r.Get()
|
||||
err := bs.crepo.r.get(ctx)
|
||||
bs.crepo.mut.Unlock()
|
||||
if err != nil {
|
||||
return unwrapVcsErr(err)
|
||||
|
@ -569,9 +570,9 @@ func (bs *baseVCSSource) initLocal() error {
|
|||
|
||||
// updateLocal ensures the local data we have about the source is fully up to date
|
||||
// with what's out there over the network.
|
||||
func (bs *baseVCSSource) updateLocal() error {
|
||||
func (bs *baseVCSSource) updateLocal(ctx context.Context) error {
|
||||
bs.crepo.mut.Lock()
|
||||
err := bs.crepo.r.Update()
|
||||
err := bs.crepo.r.update(ctx)
|
||||
bs.crepo.mut.Unlock()
|
||||
if err != nil {
|
||||
return unwrapVcsErr(err)
|
||||
|
|
|
@ -55,7 +55,8 @@ func testGitSourceInteractions(t *testing.T) {
|
|||
url: u,
|
||||
}
|
||||
|
||||
isrc, state, err := mb.try(context.Background(), cpath, newMemoryCache())
|
||||
ctx := context.Background()
|
||||
isrc, state, err := mb.try(ctx, cpath, newMemoryCache())
|
||||
if err != nil {
|
||||
t.Errorf("Unexpected error while setting up gitSource for test repo: %s", err)
|
||||
rf()
|
||||
|
@ -67,7 +68,7 @@ func testGitSourceInteractions(t *testing.T) {
|
|||
t.Errorf("Expected return state to be %v, got %v", wantstate, state)
|
||||
}
|
||||
|
||||
err = isrc.initLocal()
|
||||
err = isrc.initLocal(ctx)
|
||||
if err != nil {
|
||||
t.Errorf("Error on cloning git repo: %s", err)
|
||||
rf()
|
||||
|
@ -85,7 +86,7 @@ func testGitSourceInteractions(t *testing.T) {
|
|||
t.Errorf("Expected %s as source URL, got %s", un, src.upstreamURL())
|
||||
}
|
||||
|
||||
pvlist, err := src.listVersions()
|
||||
pvlist, err := src.listVersions(ctx)
|
||||
if err != nil {
|
||||
t.Errorf("Unexpected error getting version pairs from git repo: %s", err)
|
||||
rf()
|
||||
|
@ -161,7 +162,8 @@ func testGopkginSourceInteractions(t *testing.T) {
|
|||
major: major,
|
||||
}
|
||||
|
||||
isrc, state, err := mb.try(context.Background(), cpath, newMemoryCache())
|
||||
ctx := context.Background()
|
||||
isrc, state, err := mb.try(ctx, cpath, newMemoryCache())
|
||||
if err != nil {
|
||||
t.Errorf("Unexpected error while setting up gopkginSource for test repo: %s", err)
|
||||
return
|
||||
|
@ -172,7 +174,7 @@ func testGopkginSourceInteractions(t *testing.T) {
|
|||
t.Errorf("Expected return state to be %v, got %v", wantstate, state)
|
||||
}
|
||||
|
||||
err = isrc.initLocal()
|
||||
err = isrc.initLocal(ctx)
|
||||
if err != nil {
|
||||
t.Errorf("Error on cloning git repo: %s", err)
|
||||
rf()
|
||||
|
@ -201,7 +203,7 @@ func testGopkginSourceInteractions(t *testing.T) {
|
|||
t.Errorf("Revision %s that should exist was not present", rev)
|
||||
}
|
||||
|
||||
pvlist, err := src.listVersions()
|
||||
pvlist, err := src.listVersions(ctx)
|
||||
if err != nil {
|
||||
t.Errorf("Unexpected error getting version pairs from hg repo: %s", err)
|
||||
}
|
||||
|
@ -217,7 +219,7 @@ func testGopkginSourceInteractions(t *testing.T) {
|
|||
}
|
||||
|
||||
// Run again, this time to ensure cache outputs correctly
|
||||
pvlist, err = src.listVersions()
|
||||
pvlist, err = src.listVersions(ctx)
|
||||
if err != nil {
|
||||
t.Errorf("Unexpected error getting version pairs from hg repo: %s", err)
|
||||
}
|
||||
|
@ -304,7 +306,8 @@ func testBzrSourceInteractions(t *testing.T) {
|
|||
url: u,
|
||||
}
|
||||
|
||||
isrc, state, err := mb.try(context.Background(), cpath, newMemoryCache())
|
||||
ctx := context.Background()
|
||||
isrc, state, err := mb.try(ctx, cpath, newMemoryCache())
|
||||
if err != nil {
|
||||
t.Errorf("Unexpected error while setting up bzrSource for test repo: %s", err)
|
||||
rf()
|
||||
|
@ -316,7 +319,7 @@ func testBzrSourceInteractions(t *testing.T) {
|
|||
t.Errorf("Expected return state to be %v, got %v", wantstate, state)
|
||||
}
|
||||
|
||||
err = isrc.initLocal()
|
||||
err = isrc.initLocal(ctx)
|
||||
if err != nil {
|
||||
t.Errorf("Error on cloning git repo: %s", err)
|
||||
rf()
|
||||
|
@ -349,7 +352,7 @@ func testBzrSourceInteractions(t *testing.T) {
|
|||
t.Errorf("Revision that should exist was not present")
|
||||
}
|
||||
|
||||
pvlist, err := src.listVersions()
|
||||
pvlist, err := src.listVersions(ctx)
|
||||
if err != nil {
|
||||
t.Errorf("Unexpected error getting version pairs from bzr repo: %s", err)
|
||||
}
|
||||
|
@ -365,7 +368,7 @@ func testBzrSourceInteractions(t *testing.T) {
|
|||
}
|
||||
|
||||
// Run again, this time to ensure cache outputs correctly
|
||||
pvlist, err = src.listVersions()
|
||||
pvlist, err = src.listVersions(ctx)
|
||||
if err != nil {
|
||||
t.Errorf("Unexpected error getting version pairs from bzr repo: %s", err)
|
||||
}
|
||||
|
@ -420,7 +423,8 @@ func testHgSourceInteractions(t *testing.T) {
|
|||
url: u,
|
||||
}
|
||||
|
||||
isrc, state, err := mb.try(context.Background(), cpath, newMemoryCache())
|
||||
ctx := context.Background()
|
||||
isrc, state, err := mb.try(ctx, cpath, newMemoryCache())
|
||||
if err != nil {
|
||||
t.Errorf("Unexpected error while setting up hgSource for test repo: %s", err)
|
||||
return
|
||||
|
@ -431,7 +435,7 @@ func testHgSourceInteractions(t *testing.T) {
|
|||
t.Errorf("Expected return state to be %v, got %v", wantstate, state)
|
||||
}
|
||||
|
||||
err = isrc.initLocal()
|
||||
err = isrc.initLocal(ctx)
|
||||
if err != nil {
|
||||
t.Errorf("Error on cloning git repo: %s", err)
|
||||
rf()
|
||||
|
@ -459,7 +463,7 @@ func testHgSourceInteractions(t *testing.T) {
|
|||
t.Errorf("Revision that should exist was not present")
|
||||
}
|
||||
|
||||
pvlist, err := src.listVersions()
|
||||
pvlist, err := src.listVersions(ctx)
|
||||
if err != nil {
|
||||
t.Errorf("Unexpected error getting version pairs from hg repo: %s", err)
|
||||
}
|
||||
|
@ -475,7 +479,7 @@ func testHgSourceInteractions(t *testing.T) {
|
|||
}
|
||||
|
||||
// Run again, this time to ensure cache outputs correctly
|
||||
pvlist, err = src.listVersions()
|
||||
pvlist, err = src.listVersions(ctx)
|
||||
if err != nil {
|
||||
t.Errorf("Unexpected error getting version pairs from hg repo: %s", err)
|
||||
}
|
||||
|
|
174
vcs_repo.go
174
vcs_repo.go
|
@ -1,9 +1,8 @@
|
|||
package gps
|
||||
|
||||
import (
|
||||
"bytes"
|
||||
"context"
|
||||
"encoding/xml"
|
||||
"io/ioutil"
|
||||
"os"
|
||||
"path/filepath"
|
||||
"runtime"
|
||||
|
@ -13,6 +12,14 @@ import (
|
|||
"github.com/Masterminds/vcs"
|
||||
)
|
||||
|
||||
type ctxRepo interface {
|
||||
vcs.Repo
|
||||
get(context.Context) error
|
||||
update(context.Context) error
|
||||
//updateVersion(context.Context) error
|
||||
//ping(context.Context) (bool, error)
|
||||
}
|
||||
|
||||
// original implementation of these methods come from
|
||||
// https://github.com/Masterminds/vcs
|
||||
|
||||
|
@ -20,80 +27,86 @@ type gitRepo struct {
|
|||
*vcs.GitRepo
|
||||
}
|
||||
|
||||
func (r *gitRepo) Get() error {
|
||||
out, err := runFromCwd("git", "clone", "--recursive", r.Remote(), r.LocalPath())
|
||||
func newVcsRemoteErrorOr(msg string, err error, out string) error {
|
||||
if err == context.Canceled || err == context.DeadlineExceeded {
|
||||
return err
|
||||
}
|
||||
return vcs.NewRemoteError(msg, err, out)
|
||||
}
|
||||
|
||||
// There are some windows cases where Git cannot create the parent directory,
|
||||
// if it does not already exist, to the location it's trying to create the
|
||||
// repo. Catch that error and try to handle it.
|
||||
func newVcsLocalErrorOr(msg string, err error, out string) error {
|
||||
if err == context.Canceled || err == context.DeadlineExceeded {
|
||||
return err
|
||||
}
|
||||
return vcs.NewLocalError(msg, err, out)
|
||||
}
|
||||
|
||||
func (r *gitRepo) get(ctx context.Context) error {
|
||||
out, err := runFromCwd(ctx, "git", "clone", "--recursive", r.Remote(), r.LocalPath())
|
||||
|
||||
// There are some windows cases where Git cannot create the parent
|
||||
// directory, of the location where it's trying to create the repo. Catch
|
||||
// that error and try to handle it.
|
||||
if err != nil && r.isUnableToCreateDir(err) {
|
||||
basePath := filepath.Dir(filepath.FromSlash(r.LocalPath()))
|
||||
if _, err := os.Stat(basePath); os.IsNotExist(err) {
|
||||
err = os.MkdirAll(basePath, 0755)
|
||||
if err != nil {
|
||||
return vcs.NewLocalError("unable to create directory", err, "")
|
||||
return newVcsLocalErrorOr("unable to create directory", err, "")
|
||||
}
|
||||
|
||||
out, err = runFromCwd("git", "clone", r.Remote(), r.LocalPath())
|
||||
out, err = runFromCwd(ctx, "git", "clone", r.Remote(), r.LocalPath())
|
||||
if err != nil {
|
||||
return vcs.NewRemoteError("unable to get repository", err, string(out))
|
||||
return newVcsRemoteErrorOr("unable to get repository", err, string(out))
|
||||
}
|
||||
return err
|
||||
}
|
||||
} else if err != nil {
|
||||
return vcs.NewRemoteError("unable to get repository", err, string(out))
|
||||
return newVcsRemoteErrorOr("unable to get repository", err, string(out))
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
func (r *gitRepo) Update() error {
|
||||
func (r *gitRepo) update(ctx context.Context) error {
|
||||
// Perform a fetch to make sure everything is up to date.
|
||||
//out, err := runFromRepoDir(r, "git", "fetch", "--tags", "--prune", r.RemoteLocation)
|
||||
out, err := runFromRepoDir(r, "git", "fetch", "--tags", r.RemoteLocation)
|
||||
//out, err := runFromRepoDir(ctx, r, "git", "fetch", "--tags", "--prune", r.RemoteLocation)
|
||||
out, err := runFromRepoDir(ctx, r, "git", "fetch", "--tags", r.RemoteLocation)
|
||||
if err != nil {
|
||||
return vcs.NewRemoteError("unable to update repository", err, string(out))
|
||||
return newVcsRemoteErrorOr("unable to update repository", err, string(out))
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
// When in a detached head state, such as when an individual commit is checked
|
||||
// out do not attempt a pull. It will cause an error.
|
||||
detached, err := r.isDetachedHead()
|
||||
func (r *gitRepo) updateVersion(ctx context.Context, v string) error {
|
||||
out, err := runFromRepoDir(ctx, r, "git", "checkout", v)
|
||||
if err != nil {
|
||||
return vcs.NewLocalError("unable to update repository", err, "")
|
||||
return newVcsLocalErrorOr("Unable to update checked out version", err, string(out))
|
||||
}
|
||||
|
||||
if detached {
|
||||
return nil
|
||||
}
|
||||
|
||||
out, err = runFromRepoDir(r, "git", "pull")
|
||||
if err != nil {
|
||||
return vcs.NewRemoteError("unable to update repository", err, string(out))
|
||||
}
|
||||
|
||||
return r.defendAgainstSubmodules()
|
||||
return r.defendAgainstSubmodules(ctx)
|
||||
}
|
||||
|
||||
// defendAgainstSubmodules tries to keep repo state sane in the event of
|
||||
// submodules. Or nested submodules. What a great idea, submodules.
|
||||
func (r *gitRepo) defendAgainstSubmodules() error {
|
||||
func (r *gitRepo) defendAgainstSubmodules(ctx context.Context) error {
|
||||
// First, update them to whatever they should be, if there should happen to be any.
|
||||
out, err := runFromRepoDir(r, "git", "submodule", "update", "--init", "--recursive")
|
||||
out, err := runFromRepoDir(ctx, r, "git", "submodule", "update", "--init", "--recursive")
|
||||
if err != nil {
|
||||
return vcs.NewLocalError("unexpected error while defensively updating submodules", err, string(out))
|
||||
return newVcsLocalErrorOr("unexpected error while defensively updating submodules", err, string(out))
|
||||
}
|
||||
|
||||
// Now, do a special extra-aggressive clean in case changing versions caused
|
||||
// one or more submodules to go away.
|
||||
out, err = runFromRepoDir(r, "git", "clean", "-x", "-d", "-f", "-f")
|
||||
out, err = runFromRepoDir(ctx, r, "git", "clean", "-x", "-d", "-f", "-f")
|
||||
if err != nil {
|
||||
return vcs.NewLocalError("unexpected error while defensively cleaning up after possible derelict submodule directories", err, string(out))
|
||||
return newVcsLocalErrorOr("unexpected error while defensively cleaning up after possible derelict submodule directories", err, string(out))
|
||||
}
|
||||
|
||||
// Then, repeat just in case there are any nested submodules that went away.
|
||||
out, err = runFromRepoDir(r, "git", "submodule", "foreach", "--recursive", "git", "clean", "-x", "-d", "-f", "-f")
|
||||
out, err = runFromRepoDir(ctx, r, "git", "submodule", "foreach", "--recursive", "git", "clean", "-x", "-d", "-f", "-f")
|
||||
if err != nil {
|
||||
return vcs.NewLocalError("unexpected error while defensively cleaning up after possible derelict nested submodule directories", err, string(out))
|
||||
return newVcsLocalErrorOr("unexpected error while defensively cleaning up after possible derelict nested submodule directories", err, string(out))
|
||||
}
|
||||
|
||||
return nil
|
||||
|
@ -117,52 +130,36 @@ func (r *gitRepo) isUnableToCreateDir(err error) bool {
|
|||
return false
|
||||
}
|
||||
|
||||
// isDetachedHead will detect if git repo is in "detached head" state.
|
||||
func (r *gitRepo) isDetachedHead() (bool, error) {
|
||||
p := filepath.Join(r.LocalPath(), ".git", "HEAD")
|
||||
contents, err := ioutil.ReadFile(p)
|
||||
if err != nil {
|
||||
return false, err
|
||||
}
|
||||
|
||||
contents = bytes.TrimSpace(contents)
|
||||
if bytes.HasPrefix(contents, []byte("ref: ")) {
|
||||
return false, nil
|
||||
}
|
||||
|
||||
return true, nil
|
||||
}
|
||||
|
||||
type bzrRepo struct {
|
||||
*vcs.BzrRepo
|
||||
}
|
||||
|
||||
func (r *bzrRepo) Get() error {
|
||||
func (r *bzrRepo) get(ctx context.Context) error {
|
||||
basePath := filepath.Dir(filepath.FromSlash(r.LocalPath()))
|
||||
if _, err := os.Stat(basePath); os.IsNotExist(err) {
|
||||
err = os.MkdirAll(basePath, 0755)
|
||||
if err != nil {
|
||||
return vcs.NewLocalError("unable to create directory", err, "")
|
||||
return newVcsLocalErrorOr("unable to create directory", err, "")
|
||||
}
|
||||
}
|
||||
|
||||
out, err := runFromCwd("bzr", "branch", r.Remote(), r.LocalPath())
|
||||
out, err := runFromCwd(ctx, "bzr", "branch", r.Remote(), r.LocalPath())
|
||||
if err != nil {
|
||||
return vcs.NewRemoteError("unable to get repository", err, string(out))
|
||||
return newVcsRemoteErrorOr("unable to get repository", err, string(out))
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
func (r *bzrRepo) Update() error {
|
||||
out, err := runFromRepoDir(r, "bzr", "pull")
|
||||
func (r *bzrRepo) update(ctx context.Context) error {
|
||||
out, err := runFromRepoDir(ctx, r, "bzr", "pull")
|
||||
if err != nil {
|
||||
return vcs.NewRemoteError("unable to update repository", err, string(out))
|
||||
return newVcsRemoteErrorOr("unable to update repository", err, string(out))
|
||||
}
|
||||
|
||||
out, err = runFromRepoDir(r, "bzr", "update")
|
||||
out, err = runFromRepoDir(ctx, r, "bzr", "update")
|
||||
if err != nil {
|
||||
return vcs.NewRemoteError("unable to update repository", err, string(out))
|
||||
return newVcsRemoteErrorOr("unable to update repository", err, string(out))
|
||||
}
|
||||
|
||||
return nil
|
||||
|
@ -172,33 +169,33 @@ type hgRepo struct {
|
|||
*vcs.HgRepo
|
||||
}
|
||||
|
||||
func (r *hgRepo) Get() error {
|
||||
out, err := runFromCwd("hg", "clone", r.Remote(), r.LocalPath())
|
||||
func (r *hgRepo) get(ctx context.Context) error {
|
||||
out, err := runFromCwd(ctx, "hg", "clone", r.Remote(), r.LocalPath())
|
||||
if err != nil {
|
||||
return vcs.NewRemoteError("unable to get repository", err, string(out))
|
||||
return newVcsRemoteErrorOr("unable to get repository", err, string(out))
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
func (r *hgRepo) Update() error {
|
||||
return r.UpdateVersion(``)
|
||||
func (r *hgRepo) update(ctx context.Context) error {
|
||||
return r.updateVersion(ctx, "")
|
||||
}
|
||||
|
||||
func (r *hgRepo) UpdateVersion(version string) error {
|
||||
out, err := runFromRepoDir(r, "hg", "pull")
|
||||
func (r *hgRepo) updateVersion(ctx context.Context, version string) error {
|
||||
out, err := runFromRepoDir(ctx, r, "hg", "pull")
|
||||
if err != nil {
|
||||
return vcs.NewRemoteError("unable to update checked out version", err, string(out))
|
||||
return newVcsRemoteErrorOr("unable to update checked out version", err, string(out))
|
||||
}
|
||||
|
||||
if len(strings.TrimSpace(version)) > 0 {
|
||||
out, err = runFromRepoDir(r, "hg", "update", version)
|
||||
out, err = runFromRepoDir(ctx, r, "hg", "update", version)
|
||||
} else {
|
||||
out, err = runFromRepoDir(r, "hg", "update")
|
||||
out, err = runFromRepoDir(ctx, r, "hg", "update")
|
||||
}
|
||||
|
||||
if err != nil {
|
||||
return vcs.NewRemoteError("unable to update checked out version", err, string(out))
|
||||
return newVcsRemoteErrorOr("unable to update checked out version", err, string(out))
|
||||
}
|
||||
|
||||
return nil
|
||||
|
@ -208,7 +205,7 @@ type svnRepo struct {
|
|||
*vcs.SvnRepo
|
||||
}
|
||||
|
||||
func (r *svnRepo) Get() error {
|
||||
func (r *svnRepo) get(ctx context.Context) error {
|
||||
remote := r.Remote()
|
||||
if strings.HasPrefix(remote, "/") {
|
||||
remote = "file://" + remote
|
||||
|
@ -216,33 +213,34 @@ func (r *svnRepo) Get() error {
|
|||
remote = "file:///" + remote
|
||||
}
|
||||
|
||||
out, err := runFromCwd("svn", "checkout", remote, r.LocalPath())
|
||||
out, err := runFromCwd(ctx, "svn", "checkout", remote, r.LocalPath())
|
||||
if err != nil {
|
||||
return vcs.NewRemoteError("unable to get repository", err, string(out))
|
||||
return newVcsRemoteErrorOr("unable to get repository", err, string(out))
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
func (r *svnRepo) Update() error {
|
||||
out, err := runFromRepoDir(r, "svn", "update")
|
||||
func (r *svnRepo) update(ctx context.Context) error {
|
||||
out, err := runFromRepoDir(ctx, r, "svn", "update")
|
||||
if err != nil {
|
||||
return vcs.NewRemoteError("unable to update repository", err, string(out))
|
||||
return newVcsRemoteErrorOr("unable to update repository", err, string(out))
|
||||
}
|
||||
|
||||
return err
|
||||
}
|
||||
|
||||
func (r *svnRepo) UpdateVersion(version string) error {
|
||||
out, err := runFromRepoDir(r, "svn", "update", "-r", version)
|
||||
func (r *svnRepo) updateVersion(ctx context.Context, version string) error {
|
||||
out, err := runFromRepoDir(ctx, r, "svn", "update", "-r", version)
|
||||
if err != nil {
|
||||
return vcs.NewRemoteError("unable to update checked out version", err, string(out))
|
||||
return newVcsRemoteErrorOr("unable to update checked out version", err, string(out))
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
func (r *svnRepo) CommitInfo(id string) (*vcs.CommitInfo, error) {
|
||||
ctx := context.TODO()
|
||||
// There are cases where Svn log doesn't return anything for HEAD or BASE.
|
||||
// svn info does provide details for these but does not have elements like
|
||||
// the commit message.
|
||||
|
@ -255,15 +253,15 @@ func (r *svnRepo) CommitInfo(id string) (*vcs.CommitInfo, error) {
|
|||
Commit commit `xml:"entry>commit"`
|
||||
}
|
||||
|
||||
out, err := runFromRepoDir(r, "svn", "info", "-r", id, "--xml")
|
||||
out, err := runFromRepoDir(ctx, r, "svn", "info", "-r", id, "--xml")
|
||||
if err != nil {
|
||||
return nil, vcs.NewLocalError("unable to retrieve commit information", err, string(out))
|
||||
return nil, newVcsLocalErrorOr("unable to retrieve commit information", err, string(out))
|
||||
}
|
||||
|
||||
infos := new(info)
|
||||
err = xml.Unmarshal(out, &infos)
|
||||
if err != nil {
|
||||
return nil, vcs.NewLocalError("unable to retrieve commit information", err, string(out))
|
||||
return nil, newVcsLocalErrorOr("unable to retrieve commit information", err, string(out))
|
||||
}
|
||||
|
||||
id = infos.Commit.Revision
|
||||
|
@ -272,9 +270,9 @@ func (r *svnRepo) CommitInfo(id string) (*vcs.CommitInfo, error) {
|
|||
}
|
||||
}
|
||||
|
||||
out, err := runFromRepoDir(r, "svn", "log", "-r", id, "--xml")
|
||||
out, err := runFromRepoDir(ctx, r, "svn", "log", "-r", id, "--xml")
|
||||
if err != nil {
|
||||
return nil, vcs.NewRemoteError("unable to retrieve commit information", err, string(out))
|
||||
return nil, newVcsRemoteErrorOr("unable to retrieve commit information", err, string(out))
|
||||
}
|
||||
|
||||
type logentry struct {
|
||||
|
@ -291,7 +289,7 @@ func (r *svnRepo) CommitInfo(id string) (*vcs.CommitInfo, error) {
|
|||
logs := new(log)
|
||||
err = xml.Unmarshal(out, &logs)
|
||||
if err != nil {
|
||||
return nil, vcs.NewLocalError("unable to retrieve commit information", err, string(out))
|
||||
return nil, newVcsLocalErrorOr("unable to retrieve commit information", err, string(out))
|
||||
}
|
||||
|
||||
if len(logs.Logs) == 0 {
|
||||
|
@ -307,7 +305,7 @@ func (r *svnRepo) CommitInfo(id string) (*vcs.CommitInfo, error) {
|
|||
if len(logs.Logs[0].Date) > 0 {
|
||||
ci.Date, err = time.Parse(time.RFC3339Nano, logs.Logs[0].Date)
|
||||
if err != nil {
|
||||
return nil, vcs.NewLocalError("unable to retrieve commit information", err, string(out))
|
||||
return nil, newVcsLocalErrorOr("unable to retrieve commit information", err, string(out))
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -2,6 +2,7 @@ package gps
|
|||
|
||||
import (
|
||||
"bytes"
|
||||
"context"
|
||||
"fmt"
|
||||
"os"
|
||||
"os/exec"
|
||||
|
@ -10,7 +11,6 @@ import (
|
|||
"sync"
|
||||
|
||||
"github.com/Masterminds/semver"
|
||||
"github.com/Masterminds/vcs"
|
||||
"github.com/sdboyer/gps/internal/fs"
|
||||
)
|
||||
|
||||
|
@ -21,6 +21,7 @@ type gitSource struct {
|
|||
}
|
||||
|
||||
func (s *gitSource) exportRevisionTo(rev Revision, to string) error {
|
||||
ctx := context.TODO()
|
||||
r := s.crepo.r
|
||||
|
||||
if err := os.MkdirAll(to, 0777); err != nil {
|
||||
|
@ -40,7 +41,7 @@ func (s *gitSource) exportRevisionTo(rev Revision, to string) error {
|
|||
// could have an err here...but it's hard to imagine how?
|
||||
defer fs.RenameWithFallback(bak, idx)
|
||||
|
||||
out, err := runFromRepoDir(r, "git", "read-tree", rev.String())
|
||||
out, err := runFromRepoDir(ctx, r, "git", "read-tree", rev.String())
|
||||
if err != nil {
|
||||
return fmt.Errorf("%s: %s", out, err)
|
||||
}
|
||||
|
@ -56,7 +57,7 @@ func (s *gitSource) exportRevisionTo(rev Revision, to string) error {
|
|||
// though we have a bunch of housekeeping to do to set up, then tear
|
||||
// down, the sparse checkout controls, as well as restore the original
|
||||
// index and HEAD.
|
||||
out, err = runFromRepoDir(r, "git", "checkout-index", "-a", "--prefix="+to)
|
||||
out, err = runFromRepoDir(ctx, r, "git", "checkout-index", "-a", "--prefix="+to)
|
||||
if err != nil {
|
||||
return fmt.Errorf("%s: %s", out, err)
|
||||
}
|
||||
|
@ -64,7 +65,7 @@ func (s *gitSource) exportRevisionTo(rev Revision, to string) error {
|
|||
return nil
|
||||
}
|
||||
|
||||
func (s *gitSource) listVersions() (vlist []PairedVersion, err error) {
|
||||
func (s *gitSource) listVersions(ctx context.Context) (vlist []PairedVersion, err error) {
|
||||
r := s.crepo.r
|
||||
var out []byte
|
||||
c := exec.Command("git", "ls-remote", r.Remote())
|
||||
|
@ -184,8 +185,8 @@ type gopkginSource struct {
|
|||
major uint64
|
||||
}
|
||||
|
||||
func (s *gopkginSource) listVersions() ([]PairedVersion, error) {
|
||||
ovlist, err := s.gitSource.listVersions()
|
||||
func (s *gopkginSource) listVersions(ctx context.Context) ([]PairedVersion, error) {
|
||||
ovlist, err := s.gitSource.listVersions(ctx)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
@ -251,27 +252,11 @@ type bzrSource struct {
|
|||
baseVCSSource
|
||||
}
|
||||
|
||||
func (s *bzrSource) update() error {
|
||||
r := s.crepo.r
|
||||
|
||||
out, err := runFromRepoDir(r, "bzr", "pull")
|
||||
if err != nil {
|
||||
return vcs.NewRemoteError("Unable to update repository", err, string(out))
|
||||
}
|
||||
|
||||
out, err = runFromRepoDir(r, "bzr", "update")
|
||||
if err != nil {
|
||||
return vcs.NewRemoteError("Unable to update repository", err, string(out))
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
func (s *bzrSource) listVersions() ([]PairedVersion, error) {
|
||||
func (s *bzrSource) listVersions(ctx context.Context) ([]PairedVersion, error) {
|
||||
r := s.crepo.r
|
||||
|
||||
// Now, list all the tags
|
||||
out, err := runFromRepoDir(r, "bzr", "tags", "--show-ids", "-v")
|
||||
out, err := runFromRepoDir(ctx, r, "bzr", "tags", "--show-ids", "-v")
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("%s: %s", err, string(out))
|
||||
}
|
||||
|
@ -279,7 +264,7 @@ func (s *bzrSource) listVersions() ([]PairedVersion, error) {
|
|||
all := bytes.Split(bytes.TrimSpace(out), []byte("\n"))
|
||||
|
||||
var branchrev []byte
|
||||
branchrev, err = runFromRepoDir(r, "bzr", "version-info", "--custom", "--template={revision_id}", "--revision=branch:.")
|
||||
branchrev, err = runFromRepoDir(ctx, r, "bzr", "version-info", "--custom", "--template={revision_id}", "--revision=branch:.")
|
||||
br := string(branchrev)
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("%s: %s", err, br)
|
||||
|
@ -309,29 +294,12 @@ type hgSource struct {
|
|||
baseVCSSource
|
||||
}
|
||||
|
||||
// TODO dead code?
|
||||
func (s *hgSource) update() error {
|
||||
r := s.crepo.r
|
||||
|
||||
out, err := runFromRepoDir(r, "hg", "pull")
|
||||
if err != nil {
|
||||
return vcs.NewLocalError("Unable to update checked out version", err, string(out))
|
||||
}
|
||||
|
||||
out, err = runFromRepoDir(r, "hg", "update")
|
||||
if err != nil {
|
||||
return vcs.NewLocalError("Unable to update checked out version", err, string(out))
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
func (s *hgSource) listVersions() ([]PairedVersion, error) {
|
||||
func (s *hgSource) listVersions(ctx context.Context) ([]PairedVersion, error) {
|
||||
var vlist []PairedVersion
|
||||
|
||||
r := s.crepo.r
|
||||
// Now, list all the tags
|
||||
out, err := runFromRepoDir(r, "hg", "tags", "--debug", "--verbose")
|
||||
out, err := runFromRepoDir(ctx, r, "hg", "tags", "--debug", "--verbose")
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("%s: %s", err, string(out))
|
||||
}
|
||||
|
@ -365,7 +333,7 @@ func (s *hgSource) listVersions() ([]PairedVersion, error) {
|
|||
// bookmarks next, because the presence of the magic @ bookmark has to
|
||||
// determine how we handle the branches
|
||||
var magicAt bool
|
||||
out, err = runFromRepoDir(r, "hg", "bookmarks", "--debug")
|
||||
out, err = runFromRepoDir(ctx, r, "hg", "bookmarks", "--debug")
|
||||
if err != nil {
|
||||
// better nothing than partial and misleading
|
||||
return nil, fmt.Errorf("%s: %s", err, string(out))
|
||||
|
@ -398,7 +366,7 @@ func (s *hgSource) listVersions() ([]PairedVersion, error) {
|
|||
}
|
||||
}
|
||||
|
||||
out, err = runFromRepoDir(r, "hg", "branches", "-c", "--debug")
|
||||
out, err = runFromRepoDir(ctx, r, "hg", "branches", "-c", "--debug")
|
||||
if err != nil {
|
||||
// better nothing than partial and misleading
|
||||
return nil, fmt.Errorf("%s: %s", err, string(out))
|
||||
|
@ -437,7 +405,7 @@ type repo struct {
|
|||
mut sync.RWMutex
|
||||
|
||||
// Object for direct repo interaction
|
||||
r vcs.Repo
|
||||
r ctxRepo
|
||||
|
||||
// Whether or not the cache repo is in sync (think dvcs) with upstream
|
||||
synced bool
|
||||
|
|
Загрузка…
Ссылка в новой задаче