Merge pull request #385 from Masterminds/update/vcs-1.6.0
Updated dependencies:
diff --git a/glide.lock b/glide.lock
index 1bbde7a..eeae594 100644
--- a/glide.lock
+++ b/glide.lock
@@ -1,12 +1,12 @@
-hash: 83c7c3c86a8d50d46ac2731938195e348f2445e6106325a4f90976563c946bd8
-updated: 2016-03-23T21:38:59.47773549-04:00
+hash: 3a5b11283c409c77e79505c08a39550a966d62fb0896f4355c10d699482840a3
+updated: 2016-04-18T09:49:03.335458835-04:00
imports:
- name: github.com/codegangsta/cli
- version: 9fec0fad02befc9209347cc6d620e68e1b45f74d
+ version: 71f57d300dd6a780ac1856c005c4b518cfd498ec
- name: github.com/Masterminds/semver
version: 808ed7761c233af2de3f9729a041d68c62527f3a
- name: github.com/Masterminds/vcs
- version: b22ee1673cdd03ef47bb0b422736a7f17ff0648c
+ version: fa85cceafacd29c84a8aa6e68967bb9f1754e5e3
- name: gopkg.in/yaml.v2
version: a83829b6f1293c91addabc89d0571c246397bbf4
devImports: []
diff --git a/glide.yaml b/glide.yaml
index a8eb79a..e9e3a02 100644
--- a/glide.yaml
+++ b/glide.yaml
@@ -11,7 +11,7 @@
import:
- package: gopkg.in/yaml.v2
- package: github.com/Masterminds/vcs
- version: ^1.5.1
+ version: ^1.6.0
- package: github.com/codegangsta/cli
- package: github.com/Masterminds/semver
version: ^1.0.0
diff --git a/vendor/github.com/Masterminds/vcs/CHANGELOG.md b/vendor/github.com/Masterminds/vcs/CHANGELOG.md
index 96af5ec..7a04e56 100644
--- a/vendor/github.com/Masterminds/vcs/CHANGELOG.md
+++ b/vendor/github.com/Masterminds/vcs/CHANGELOG.md
@@ -1,3 +1,17 @@
+# 1.6.0 (2016-04-18)
+
+- Issue #26: Added Init method to initialize a repo at the local location
+ (thanks tony).
+- Issue #19: Added method to retrieve tags for a commit.
+- Issue #24: Reworked errors returned from common methods. Now differing
+ VCS implementations return the same errors. The original VCS specific error
+ is available on the error. See the docs for more details.
+- Issue #25: Export the function RunFromDir which runs VCS commands from the
+ root of the local directory. This is useful for those that want to build and
+ extend on top of the vcs package (thanks tony).
+- Issue #22: Added Ping command to test if remote location is present and
+ accessible.
+
# 1.5.1 (2016-03-23)
- Fixing bug parsing some Git commit dates.
diff --git a/vendor/github.com/Masterminds/vcs/bzr.go b/vendor/github.com/Masterminds/vcs/bzr.go
index 965b598..1d36137 100644
--- a/vendor/github.com/Masterminds/vcs/bzr.go
+++ b/vendor/github.com/Masterminds/vcs/bzr.go
@@ -1,6 +1,8 @@
package vcs
import (
+ "fmt"
+ "net/url"
"os"
"os/exec"
"path/filepath"
@@ -39,7 +41,7 @@
c.Env = envForDir(c.Dir)
out, err := c.CombinedOutput()
if err != nil {
- return nil, err
+ return nil, NewLocalError("Unable to retrieve local repo information", err, string(out))
}
m := bzrDetectURL.FindStringSubmatch(string(out))
@@ -70,36 +72,76 @@
if _, err := os.Stat(basePath); os.IsNotExist(err) {
err = os.MkdirAll(basePath, 0755)
if err != nil {
- return err
+ return NewLocalError("Unable to create directory", err, "")
}
}
- _, err := s.run("bzr", "branch", s.Remote(), s.LocalPath())
- return err
+ out, err := s.run("bzr", "branch", s.Remote(), s.LocalPath())
+ if err != nil {
+ return NewRemoteError("Unable to get repository", err, string(out))
+ }
+
+ return nil
+}
+
+// Init initializes a bazaar repository at local location.
+func (s *BzrRepo) Init() error {
+ out, err := s.run("bzr", "init", s.LocalPath())
+
+ // There are some windows cases where bazaar 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.
+ if err != nil && s.isUnableToCreateDir(err) {
+
+ basePath := filepath.Dir(filepath.FromSlash(s.LocalPath()))
+ if _, err := os.Stat(basePath); os.IsNotExist(err) {
+ err = os.MkdirAll(basePath, 0755)
+ if err != nil {
+ return NewLocalError("Unable to initialize repository", err, "")
+ }
+
+ out, err = s.run("bzr", "init", s.LocalPath())
+ if err != nil {
+ return NewLocalError("Unable to initialize repository", err, string(out))
+ }
+ return nil
+ }
+
+ } else if err != nil {
+ return NewLocalError("Unable to initialize repository", err, string(out))
+ }
+
+ return nil
}
// Update performs a Bzr pull and update to an existing checkout.
func (s *BzrRepo) Update() error {
- _, err := s.runFromDir("bzr", "pull")
+ out, err := s.RunFromDir("bzr", "pull")
if err != nil {
- return err
+ return NewRemoteError("Unable to update repository", err, string(out))
}
- _, err = s.runFromDir("bzr", "update")
- return err
+ out, err = s.RunFromDir("bzr", "update")
+ if err != nil {
+ return NewRemoteError("Unable to update repository", err, string(out))
+ }
+ return nil
}
// UpdateVersion sets the version of a package currently checked out via Bzr.
func (s *BzrRepo) UpdateVersion(version string) error {
- _, err := s.runFromDir("bzr", "update", "-r", version)
- return err
+ out, err := s.RunFromDir("bzr", "update", "-r", version)
+ if err != nil {
+ return NewLocalError("Unable to update checked out version", err, string(out))
+ }
+ return nil
}
// Version retrieves the current version.
func (s *BzrRepo) Version() (string, error) {
- out, err := s.runFromDir("bzr", "revno", "--tree")
+ out, err := s.RunFromDir("bzr", "revno", "--tree")
if err != nil {
- return "", err
+ return "", NewLocalError("Unable to retrieve checked out version", err, string(out))
}
return strings.TrimSpace(string(out)), nil
@@ -107,13 +149,13 @@
// Date retrieves the date on the latest commit.
func (s *BzrRepo) Date() (time.Time, error) {
- out, err := s.runFromDir("bzr", "version-info", "--custom", "--template={date}")
+ out, err := s.RunFromDir("bzr", "version-info", "--custom", "--template={date}")
if err != nil {
- return time.Time{}, err
+ return time.Time{}, NewLocalError("Unable to retrieve revision date", err, string(out))
}
t, err := time.Parse(longForm, string(out))
if err != nil {
- return time.Time{}, err
+ return time.Time{}, NewLocalError("Unable to retrieve revision date", err, string(out))
}
return t, nil
}
@@ -138,9 +180,9 @@
// Tags returns a list of available tags on the repository.
func (s *BzrRepo) Tags() ([]string, error) {
- out, err := s.runFromDir("bzr", "tags")
+ out, err := s.RunFromDir("bzr", "tags")
if err != nil {
- return []string{}, err
+ return []string{}, NewLocalError("Unable to retrieve tags", err, string(out))
}
tags := s.referenceList(string(out), `(?m-s)^(\S+)`)
return tags, nil
@@ -149,7 +191,7 @@
// IsReference returns if a string is a reference. A reference can be a
// commit id or tag.
func (s *BzrRepo) IsReference(r string) bool {
- _, err := s.runFromDir("bzr", "revno", "-r", r)
+ _, err := s.RunFromDir("bzr", "revno", "-r", r)
if err == nil {
return true
}
@@ -160,14 +202,14 @@
// IsDirty returns if the checkout has been modified from the checked
// out reference.
func (s *BzrRepo) IsDirty() bool {
- out, err := s.runFromDir("bzr", "diff")
+ out, err := s.RunFromDir("bzr", "diff")
return err != nil || len(out) != 0
}
// CommitInfo retrieves metadata about a commit.
func (s *BzrRepo) CommitInfo(id string) (*CommitInfo, error) {
r := "-r" + id
- out, err := s.runFromDir("bzr", "log", r, "--log-format=long")
+ out, err := s.RunFromDir("bzr", "log", r, "--log-format=long")
if err != nil {
return nil, ErrRevisionUnavailable
}
@@ -188,7 +230,7 @@
ts := strings.TrimSpace(strings.TrimPrefix(l, "timestamp:"))
ci.Date, err = time.Parse(format, ts)
if err != nil {
- return nil, err
+ return nil, NewLocalError("Unable to retrieve commit information", err, string(out))
}
} else if strings.TrimSpace(l) == "message:" {
track = i
@@ -206,3 +248,60 @@
return ci, nil
}
+
+// TagsFromCommit retrieves tags from a commit id.
+func (s *BzrRepo) TagsFromCommit(id string) ([]string, error) {
+ out, err := s.RunFromDir("bzr", "tags", "-r", id)
+ if err != nil {
+ return []string{}, NewLocalError("Unable to retrieve tags", err, string(out))
+ }
+
+ tags := s.referenceList(string(out), `(?m-s)^(\S+)`)
+ return tags, nil
+}
+
+// Ping returns if remote location is accessible.
+func (s *BzrRepo) Ping() bool {
+
+ // Running bzr info is slow. Many of the projects are on launchpad which
+ // has a public 1.0 API we can use.
+ u, err := url.Parse(s.Remote())
+ if err == nil {
+ if u.Host == "launchpad.net" {
+ try := strings.TrimPrefix(u.Path, "/")
+
+ // get returns the body and an err. If the status code is not a 200
+ // an error is returned. Launchpad returns a 404 for a codebase that
+ // does not exist. Otherwise it returns a JSON object describing it.
+ _, er := get("https://api.launchpad.net/1.0/" + try)
+ if er == nil {
+ return true
+ }
+ return false
+ }
+ }
+
+ // This is the same command that Go itself uses but it's not fast (or fast
+ // enough by my standards). A faster method would be useful.
+ _, err = s.run("bzr", "info", s.Remote())
+ if err != nil {
+ return false
+ }
+
+ return true
+}
+
+// Multi-lingual manner check for the VCS error that it couldn't create directory.
+// https://bazaar.launchpad.net/~bzr-pqm/bzr/bzr.dev/files/head:/po/
+func (s *BzrRepo) isUnableToCreateDir(err error) bool {
+ msg := err.Error()
+ if strings.HasPrefix(msg, fmt.Sprintf("Parent directory of %s does not exist.", s.LocalPath())) ||
+ strings.HasPrefix(msg, fmt.Sprintf("Nadřazený adresář %s neexistuje.", s.LocalPath())) ||
+ strings.HasPrefix(msg, fmt.Sprintf("El directorio padre de %s no existe.", s.LocalPath())) ||
+ strings.HasPrefix(msg, fmt.Sprintf("%s の親ディレクトリがありません。", s.LocalPath())) ||
+ strings.HasPrefix(msg, fmt.Sprintf("Родительская директория для %s не существует.", s.LocalPath())) {
+ return true
+ }
+
+ return false
+}
diff --git a/vendor/github.com/Masterminds/vcs/bzr_test.go b/vendor/github.com/Masterminds/vcs/bzr_test.go
index ce61d75..6125444 100644
--- a/vendor/github.com/Masterminds/vcs/bzr_test.go
+++ b/vendor/github.com/Masterminds/vcs/bzr_test.go
@@ -123,6 +123,22 @@
t.Error("Bzr tags is not reporting the correct version")
}
+ tags, err = repo.TagsFromCommit("2")
+ if err != nil {
+ t.Error(err)
+ }
+ if len(tags) != 0 {
+ t.Error("Bzr is incorrectly returning tags for a commit")
+ }
+
+ tags, err = repo.TagsFromCommit("3")
+ if err != nil {
+ t.Error(err)
+ }
+ if len(tags) != 1 || tags[0] != "1.0.0" {
+ t.Error("Bzr is incorrectly returning tags for a commit")
+ }
+
branches, err := repo.Branches()
if err != nil {
t.Error(err)
@@ -196,3 +212,68 @@
t.Error(nrerr)
}
}
+
+func TestBzrPing(t *testing.T) {
+ tempDir, err := ioutil.TempDir("", "go-vcs-bzr-tests")
+ if err != nil {
+ t.Error(err)
+ }
+ defer func() {
+ err = os.RemoveAll(tempDir)
+ if err != nil {
+ t.Error(err)
+ }
+ }()
+
+ repo, err := NewBzrRepo("https://launchpad.net/govcstestbzrrepo", tempDir)
+ if err != nil {
+ t.Error(err)
+ }
+
+ ping := repo.Ping()
+ if !ping {
+ t.Error("Bzr unable to ping working repo")
+ }
+
+ repo, err = NewBzrRepo("https://launchpad.net/ihopethisneverexistsbecauseitshouldnt", tempDir)
+ if err != nil {
+ t.Error(err)
+ }
+
+ ping = repo.Ping()
+ if ping {
+ t.Error("Bzr got a ping response from when it should not have")
+ }
+}
+
+func TestBzrInit(t *testing.T) {
+ tempDir, err := ioutil.TempDir("", "go-vcs-bzr-tests")
+ repoDir := tempDir + "/repo"
+ if err != nil {
+ t.Error(err)
+ }
+ defer func() {
+ err = os.RemoveAll(tempDir)
+ if err != nil {
+ t.Error(err)
+ }
+ }()
+
+ repo, err := NewBzrRepo(repoDir, repoDir)
+ if err != nil {
+ t.Error(err)
+ }
+
+ err = repo.Init()
+ if err != nil {
+ t.Error(err)
+ }
+
+ v, err := repo.Version()
+ if err != nil {
+ t.Error(err)
+ }
+ if v != "0" {
+ t.Errorf("Bzr Init returns wrong version: %s", v)
+ }
+}
diff --git a/vendor/github.com/Masterminds/vcs/errors.go b/vendor/github.com/Masterminds/vcs/errors.go
new file mode 100644
index 0000000..ea8c5fc
--- /dev/null
+++ b/vendor/github.com/Masterminds/vcs/errors.go
@@ -0,0 +1,107 @@
+package vcs
+
+import "errors"
+
+// The vcs package provides ways to work with errors that hide the underlying
+// implementation details but make them accessible if needed. For basic errors
+// that do not have underlying implementation specific details or the underlying
+// details are likely not necessairy there are errors for comparison.
+//
+// For example:
+//
+// ci, err := repo.CommitInfo("123")
+// if err == vcs.ErrRevisionUnavailable {
+// // The commit id was not available in the VCS.
+// }
+//
+// There are other times where getting the details are more useful. For example,
+// if you're performing a repo.Get() and an error occurs. In general you'll want
+// to consistently know it failed. But, you may want to know the underlying
+// details (opt-in) to them. For those cases there is a different form of error
+// handling.
+//
+// For example:
+//
+// err := repo.Get()
+// if err != nil {
+// // A RemoteError was returned. This has access to the output of the
+// // vcs command, original error, and has a consistent cross vcs message.
+// }
+//
+// The errors returned here can be used in type switches to detect the underlying
+// error. For example:
+//
+// switch err.(type) {
+// case *vcs.RemoteError:
+// // This an error connecting to a remote system.
+// }
+//
+// For more information on using type switches to detect error types you can
+// read the Go wiki at https://github.com/golang/go/wiki/Errors
+
+var (
+ // ErrWrongVCS is returned when an action is tried on the wrong VCS.
+ ErrWrongVCS = errors.New("Wrong VCS detected")
+
+ // ErrCannotDetectVCS is returned when VCS cannot be detected from URI string.
+ ErrCannotDetectVCS = errors.New("Cannot detect VCS")
+
+ // ErrWrongRemote occurs when the passed in remote does not match the VCS
+ // configured endpoint.
+ ErrWrongRemote = errors.New("The Remote does not match the VCS endpoint")
+
+ // ErrRevisionUnavailable happens when commit revision information is
+ // unavailable.
+ ErrRevisionUnavailable = errors.New("Revision unavailable")
+)
+
+// RemoteError is returned when an operation fails against a remote repo
+type RemoteError struct {
+ vcsError
+}
+
+// NewRemoteError constructs a RemoteError
+func NewRemoteError(msg string, err error, out string) error {
+ e := &RemoteError{}
+ e.s = msg
+ e.e = err
+ e.o = out
+
+ return e
+}
+
+// LocalError is returned when a local operation has an error
+type LocalError struct {
+ vcsError
+}
+
+// NewLocalError constructs a LocalError
+func NewLocalError(msg string, err error, out string) error {
+ e := &LocalError{}
+ e.s = msg
+ e.e = err
+ e.o = out
+
+ return e
+}
+
+type vcsError struct {
+ s string
+ e error // The original error
+ o string // The output from executing the command
+}
+
+// Error implements the Error interface
+func (e *vcsError) Error() string {
+ return e.s
+}
+
+// Original retrieves the underlying implementation specific error.
+func (e *vcsError) Original() error {
+ return e.e
+}
+
+// Out retrieves the output of the original command that was run.
+func (e *vcsError) Out() string {
+ return e.o
+}
diff --git a/vendor/github.com/Masterminds/vcs/errors_test.go b/vendor/github.com/Masterminds/vcs/errors_test.go
new file mode 100644
index 0000000..2effd7c
--- /dev/null
+++ b/vendor/github.com/Masterminds/vcs/errors_test.go
@@ -0,0 +1,36 @@
+package vcs
+
+import (
+ "errors"
+ "testing"
+)
+
+func TestNewRemoteError(t *testing.T) {
+ base := errors.New("Foo error")
+ out := "This is a test"
+ msg := "remote error msg"
+
+ e := NewRemoteError(msg, base, out)
+
+ switch e.(type) {
+ case *RemoteError:
+ // This is the right error type
+ default:
+ t.Error("Wrong error type returned from NewRemoteError")
+ }
+}
+
+func TestNewLocalError(t *testing.T) {
+ base := errors.New("Foo error")
+ out := "This is a test"
+ msg := "local error msg"
+
+ e := NewLocalError(msg, base, out)
+
+ switch e.(type) {
+ case *LocalError:
+ // This is the right error type
+ default:
+ t.Error("Wrong error type returned from NewLocalError")
+ }
+}
diff --git a/vendor/github.com/Masterminds/vcs/git.go b/vendor/github.com/Masterminds/vcs/git.go
index 636ddc7..5d4b956 100644
--- a/vendor/github.com/Masterminds/vcs/git.go
+++ b/vendor/github.com/Masterminds/vcs/git.go
@@ -33,7 +33,7 @@
c.Env = envForDir(c.Dir)
out, err := c.CombinedOutput()
if err != nil {
- return nil, err
+ return nil, NewLocalError("Unable to retrieve local repo information", err, string(out))
}
localRemote := strings.TrimSpace(string(out))
@@ -64,7 +64,7 @@
// Get is used to perform an initial clone of a repository.
func (s *GitRepo) Get() error {
- _, err := s.run("git", "clone", s.Remote(), s.LocalPath())
+ out, err := s.run("git", "clone", s.Remote(), s.LocalPath())
// 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
@@ -75,53 +75,93 @@
if _, err := os.Stat(basePath); os.IsNotExist(err) {
err = os.MkdirAll(basePath, 0755)
if err != nil {
- return err
+ return NewLocalError("Unable to create directory", err, "")
}
- _, err = s.run("git", "clone", s.Remote(), s.LocalPath())
+ out, err = s.run("git", "clone", s.Remote(), s.LocalPath())
+ if err != nil {
+ return NewRemoteError("Unable to get repository", err, string(out))
+ }
return err
}
+ } else if err != nil {
+ return NewRemoteError("Unable to get repository", err, string(out))
}
- return err
+ return nil
+}
+
+// Init initializes a git repository at local location.
+func (s *GitRepo) Init() error {
+ out, err := s.run("git", "init", s.LocalPath())
+
+ // 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.
+ if err != nil && s.isUnableToCreateDir(err) {
+
+ basePath := filepath.Dir(filepath.FromSlash(s.LocalPath()))
+ if _, err := os.Stat(basePath); os.IsNotExist(err) {
+ err = os.MkdirAll(basePath, 0755)
+ if err != nil {
+ return NewLocalError("Unable to initialize repository", err, "")
+ }
+
+ out, err = s.run("git", "init", s.LocalPath())
+ if err != nil {
+ return NewLocalError("Unable to initialize repository", err, string(out))
+ }
+ return nil
+ }
+
+ } else if err != nil {
+ return NewLocalError("Unable to initialize repository", err, string(out))
+ }
+
+ return nil
}
// Update performs an Git fetch and pull to an existing checkout.
func (s *GitRepo) Update() error {
// Perform a fetch to make sure everything is up to date.
- _, err := s.runFromDir("git", "fetch", s.RemoteLocation)
+ out, err := s.RunFromDir("git", "fetch", s.RemoteLocation)
if err != nil {
- return err
+ return NewRemoteError("Unable to update repository", err, string(out))
}
// 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 := isDetachedHead(s.LocalPath())
-
if err != nil {
- return err
+ return NewLocalError("Unable to update repository", err, "")
}
if detached == true {
return nil
}
- _, err = s.runFromDir("git", "pull")
- return err
+ out, err = s.RunFromDir("git", "pull")
+ if err != nil {
+ return NewRemoteError("Unable to update repository", err, string(out))
+ }
+ return nil
}
// UpdateVersion sets the version of a package currently checked out via Git.
func (s *GitRepo) UpdateVersion(version string) error {
- _, err := s.runFromDir("git", "checkout", version)
- return err
+ out, err := s.RunFromDir("git", "checkout", version)
+ if err != nil {
+ return NewLocalError("Unable to update checked out version", err, string(out))
+ }
+ return nil
}
// Version retrieves the current version.
func (s *GitRepo) Version() (string, error) {
- out, err := s.runFromDir("git", "rev-parse", "HEAD")
+ out, err := s.RunFromDir("git", "rev-parse", "HEAD")
if err != nil {
- return "", err
+ return "", NewLocalError("Unable to retrieve checked out version", err, string(out))
}
return strings.TrimSpace(string(out)), nil
@@ -129,22 +169,22 @@
// Date retrieves the date on the latest commit.
func (s *GitRepo) Date() (time.Time, error) {
- out, err := s.runFromDir("git", "log", "-1", "--date=iso", "--pretty=format:%cd")
+ out, err := s.RunFromDir("git", "log", "-1", "--date=iso", "--pretty=format:%cd")
if err != nil {
- return time.Time{}, err
+ return time.Time{}, NewLocalError("Unable to retrieve revision date", err, string(out))
}
t, err := time.Parse(longForm, string(out))
if err != nil {
- return time.Time{}, err
+ return time.Time{}, NewLocalError("Unable to retrieve revision date", err, string(out))
}
return t, nil
}
// Branches returns a list of available branches on the RemoteLocation
func (s *GitRepo) Branches() ([]string, error) {
- out, err := s.runFromDir("git", "show-ref")
+ out, err := s.RunFromDir("git", "show-ref")
if err != nil {
- return []string{}, err
+ return []string{}, NewLocalError("Unable to retrieve branches", err, string(out))
}
branches := s.referenceList(string(out), `(?m-s)(?:`+s.RemoteLocation+`)/(\S+)$`)
return branches, nil
@@ -152,9 +192,9 @@
// Tags returns a list of available tags on the RemoteLocation
func (s *GitRepo) Tags() ([]string, error) {
- out, err := s.runFromDir("git", "show-ref")
+ out, err := s.RunFromDir("git", "show-ref")
if err != nil {
- return []string{}, err
+ return []string{}, NewLocalError("Unable to retrieve tags", err, string(out))
}
tags := s.referenceList(string(out), `(?m-s)(?:tags)/(\S+)$`)
return tags, nil
@@ -172,7 +212,7 @@
// IsReference returns if a string is a reference. A reference can be a
// commit id, branch, or tag.
func (s *GitRepo) IsReference(r string) bool {
- _, err := s.runFromDir("git", "rev-parse", "--verify", r)
+ _, err := s.RunFromDir("git", "rev-parse", "--verify", r)
if err == nil {
return true
}
@@ -180,7 +220,7 @@
// Some refs will fail rev-parse. For example, a remote branch that has
// not been checked out yet. This next step should pickup the other
// possible references.
- _, err = s.runFromDir("git", "show-ref", r)
+ _, err = s.RunFromDir("git", "show-ref", r)
if err == nil {
return true
}
@@ -191,14 +231,14 @@
// IsDirty returns if the checkout has been modified from the checked
// out reference.
func (s *GitRepo) IsDirty() bool {
- out, err := s.runFromDir("git", "diff")
+ out, err := s.RunFromDir("git", "diff")
return err != nil || len(out) != 0
}
// CommitInfo retrieves metadata about a commit.
func (s *GitRepo) CommitInfo(id string) (*CommitInfo, error) {
fm := `--pretty=format:"<logentry><commit>%H</commit><author>%an <%ae></author><date>%aD</date><message>%s</message></logentry>"`
- out, err := s.runFromDir("git", "log", id, fm, "-1")
+ out, err := s.RunFromDir("git", "log", id, fm, "-1")
if err != nil {
return nil, ErrRevisionUnavailable
}
@@ -211,12 +251,12 @@
}{}
err = xml.Unmarshal(out, &cis)
if err != nil {
- return nil, err
+ return nil, NewLocalError("Unable to retrieve commit information", err, string(out))
}
t, err := time.Parse("Mon, _2 Jan 2006 15:04:05 -0700", cis.Date)
if err != nil {
- return nil, err
+ return nil, NewLocalError("Unable to retrieve commit information", err, string(out))
}
ci := &CommitInfo{
@@ -229,6 +269,49 @@
return ci, nil
}
+// TagsFromCommit retrieves tags from a commit id.
+func (s *GitRepo) TagsFromCommit(id string) ([]string, error) {
+ // This is imperfect and a better method would be great.
+
+ var re []string
+
+ out, err := s.RunFromDir("git", "show-ref", "-d")
+ if err != nil {
+ return []string{}, NewLocalError("Unable to retrieve tags", err, string(out))
+ }
+
+ lines := strings.Split(string(out), "\n")
+ var list []string
+ for _, i := range lines {
+ if strings.HasPrefix(strings.TrimSpace(i), id) {
+ list = append(list, i)
+ }
+ }
+ tags := s.referenceList(strings.Join(list, "\n"), `(?m-s)(?:tags)/(\S+)$`)
+ for _, t := range tags {
+ re = append(re, t)
+ }
+
+ return re, nil
+}
+
+// Ping returns if remote location is accessible.
+func (s *GitRepo) Ping() bool {
+ c := exec.Command("git", "ls-remote", s.Remote())
+
+ // If prompted for a username and password, which GitHub does for all things
+ // not public, it's considered not available. To make it available the
+ // remote needs to be different.
+ c.Env = mergeEnvLists([]string{"GIT_TERMINAL_PROMPT=0"}, os.Environ())
+ _, err := c.CombinedOutput()
+ if err != nil {
+ return false
+ }
+
+ return true
+}
+
+// isDetachedHead will detect if git repo is in "detached head" state.
func isDetachedHead(dir string) (bool, error) {
c := exec.Command("git", "status", "-uno")
c.Dir = dir
@@ -242,8 +325,9 @@
return detached, nil
}
-// In a multi-langual manner check for the Git error that it couldn't create
-// the directory.
+// isUnableToCreateDir checks for an error in Init() to see if an error
+// where the parent directory of the VCS local path doesn't exist. This is
+// done in a multi-lingual manner.
func (s *GitRepo) isUnableToCreateDir(err error) bool {
msg := err.Error()
if strings.HasPrefix(msg, "could not create work tree dir") ||
diff --git a/vendor/github.com/Masterminds/vcs/git_test.go b/vendor/github.com/Masterminds/vcs/git_test.go
index a1a4f93..5fe6259 100644
--- a/vendor/github.com/Masterminds/vcs/git_test.go
+++ b/vendor/github.com/Masterminds/vcs/git_test.go
@@ -15,7 +15,6 @@
// with a known git service.
func TestGit(t *testing.T) {
-
tempDir, err := ioutil.TempDir("", "go-vcs-git-tests")
if err != nil {
t.Error(err)
@@ -141,6 +140,22 @@
t.Error("Git tags is not reporting the correct version")
}
+ tags, err = repo.TagsFromCommit("74dd547545b7df4aa285bcec1b54e2b76f726395")
+ if err != nil {
+ t.Error(err)
+ }
+ if len(tags) != 0 {
+ t.Error("Git is incorrectly returning tags for a commit")
+ }
+
+ tags, err = repo.TagsFromCommit("30605f6ac35fcb075ad0bfa9296f90a7d891523e")
+ if err != nil {
+ t.Error(err)
+ }
+ if len(tags) != 1 || tags[0] != "1.0.0" {
+ t.Error("Git is incorrectly returning tags for a commit")
+ }
+
branches, err := repo.Branches()
if err != nil {
t.Error(err)
@@ -215,3 +230,65 @@
t.Error(nrerr)
}
}
+
+func TestGitPing(t *testing.T) {
+ tempDir, err := ioutil.TempDir("", "go-vcs-git-tests")
+ if err != nil {
+ t.Error(err)
+ }
+ defer func() {
+ err = os.RemoveAll(tempDir)
+ if err != nil {
+ t.Error(err)
+ }
+ }()
+
+ repo, err := NewGitRepo("https://github.com/Masterminds/VCSTestRepo", tempDir)
+ if err != nil {
+ t.Error(err)
+ }
+
+ ping := repo.Ping()
+ if !ping {
+ t.Error("Git unable to ping working repo")
+ }
+
+ repo, err = NewGitRepo("https://github.com/Masterminds/ihopethisneverexistsbecauseitshouldnt", tempDir)
+ if err != nil {
+ t.Error(err)
+ }
+
+ ping = repo.Ping()
+ if ping {
+ t.Error("Git got a ping response from when it should not have")
+ }
+}
+
+func TestGitInit(t *testing.T) {
+ tempDir, err := ioutil.TempDir("", "go-vcs-git-tests")
+ repoDir := tempDir + "/repo"
+ if err != nil {
+ t.Error(err)
+ }
+ defer func() {
+ err = os.RemoveAll(tempDir)
+ if err != nil {
+ t.Error(err)
+ }
+ }()
+
+ repo, err := NewGitRepo(repoDir, repoDir)
+ if err != nil {
+ t.Error(err)
+ }
+
+ err = repo.Init()
+ if err != nil {
+ t.Error(err)
+ }
+
+ _, err = repo.RunFromDir("git", "status")
+ if err != nil {
+ t.Error(err)
+ }
+}
diff --git a/vendor/github.com/Masterminds/vcs/hg.go b/vendor/github.com/Masterminds/vcs/hg.go
index e3fe575..4ce055c 100644
--- a/vendor/github.com/Masterminds/vcs/hg.go
+++ b/vendor/github.com/Masterminds/vcs/hg.go
@@ -36,7 +36,7 @@
c.Env = envForDir(c.Dir)
out, err := c.CombinedOutput()
if err != nil {
- return nil, err
+ return nil, NewLocalError("Unable to retrieve local repo information", err, string(out))
}
m := hgDetectURL.FindStringSubmatch(string(out))
@@ -66,31 +66,49 @@
// Get is used to perform an initial clone of a repository.
func (s *HgRepo) Get() error {
- _, err := s.run("hg", "clone", s.Remote(), s.LocalPath())
- return err
+ out, err := s.run("hg", "clone", s.Remote(), s.LocalPath())
+ if err != nil {
+ return NewRemoteError("Unable to get repository", err, string(out))
+ }
+ return nil
+}
+
+// Init will initialize a mercurial repository at local location.
+func (s *HgRepo) Init() error {
+ out, err := s.run("hg", "init", s.LocalPath())
+ if err != nil {
+ return NewLocalError("Unable to initialize repository", err, string(out))
+ }
+ return nil
}
// Update performs a Mercurial pull to an existing checkout.
func (s *HgRepo) Update() error {
- _, err := s.runFromDir("hg", "update")
- return err
+ out, err := s.RunFromDir("hg", "update")
+ if err != nil {
+ return NewRemoteError("Unable to update repository", err, string(out))
+ }
+ return nil
}
// UpdateVersion sets the version of a package currently checked out via Hg.
func (s *HgRepo) UpdateVersion(version string) error {
- _, err := s.runFromDir("hg", "pull")
+ out, err := s.RunFromDir("hg", "pull")
if err != nil {
- return err
+ return NewLocalError("Unable to update checked out version", err, string(out))
}
- _, err = s.runFromDir("hg", "update", version)
- return err
+ out, err = s.RunFromDir("hg", "update", version)
+ if err != nil {
+ return NewLocalError("Unable to update checked out version", err, string(out))
+ }
+ return nil
}
// Version retrieves the current version.
func (s *HgRepo) Version() (string, error) {
- out, err := s.runFromDir("hg", "identify")
+ out, err := s.RunFromDir("hg", "identify")
if err != nil {
- return "", err
+ return "", NewLocalError("Unable to retrieve checked out version", err, string(out))
}
parts := strings.SplitN(string(out), " ", 2)
@@ -102,15 +120,15 @@
func (s *HgRepo) Date() (time.Time, error) {
version, err := s.Version()
if err != nil {
- return time.Time{}, err
+ return time.Time{}, NewLocalError("Unable to retrieve revision date", err, "")
}
- out, err := s.runFromDir("hg", "log", "-r", version, "--template", "{date|isodatesec}")
+ out, err := s.RunFromDir("hg", "log", "-r", version, "--template", "{date|isodatesec}")
if err != nil {
- return time.Time{}, err
+ return time.Time{}, NewLocalError("Unable to retrieve revision date", err, string(out))
}
t, err := time.Parse(longForm, string(out))
if err != nil {
- return time.Time{}, err
+ return time.Time{}, NewLocalError("Unable to retrieve revision date", err, string(out))
}
return t, nil
}
@@ -126,9 +144,9 @@
// Branches returns a list of available branches
func (s *HgRepo) Branches() ([]string, error) {
- out, err := s.runFromDir("hg", "branches")
+ out, err := s.RunFromDir("hg", "branches")
if err != nil {
- return []string{}, err
+ return []string{}, NewLocalError("Unable to retrieve branches", err, string(out))
}
branches := s.referenceList(string(out), `(?m-s)^(\S+)`)
return branches, nil
@@ -136,9 +154,9 @@
// Tags returns a list of available tags
func (s *HgRepo) Tags() ([]string, error) {
- out, err := s.runFromDir("hg", "tags")
+ out, err := s.RunFromDir("hg", "tags")
if err != nil {
- return []string{}, err
+ return []string{}, NewLocalError("Unable to retrieve tags", err, string(out))
}
tags := s.referenceList(string(out), `(?m-s)^(\S+)`)
return tags, nil
@@ -147,7 +165,7 @@
// IsReference returns if a string is a reference. A reference can be a
// commit id, branch, or tag.
func (s *HgRepo) IsReference(r string) bool {
- _, err := s.runFromDir("hg", "log", "-r", r)
+ _, err := s.RunFromDir("hg", "log", "-r", r)
if err == nil {
return true
}
@@ -158,13 +176,13 @@
// IsDirty returns if the checkout has been modified from the checked
// out reference.
func (s *HgRepo) IsDirty() bool {
- out, err := s.runFromDir("hg", "diff")
+ out, err := s.RunFromDir("hg", "diff")
return err != nil || len(out) != 0
}
// CommitInfo retrieves metadata about a commit.
func (s *HgRepo) CommitInfo(id string) (*CommitInfo, error) {
- out, err := s.runFromDir("hg", "log", "-r", id, "--style=xml")
+ out, err := s.RunFromDir("hg", "log", "-r", id, "--style=xml")
if err != nil {
return nil, ErrRevisionUnavailable
}
@@ -187,7 +205,7 @@
logs := &Log{}
err = xml.Unmarshal(out, &logs)
if err != nil {
- return nil, err
+ return nil, NewLocalError("Unable to retrieve commit information", err, string(out))
}
if len(logs.Logs) == 0 {
return nil, ErrRevisionUnavailable
@@ -202,9 +220,53 @@
if logs.Logs[0].Date != "" {
ci.Date, err = time.Parse(time.RFC3339, logs.Logs[0].Date)
if err != nil {
- return nil, err
+ return nil, NewLocalError("Unable to retrieve commit information", err, string(out))
}
}
return ci, nil
}
+
+// TagsFromCommit retrieves tags from a commit id.
+func (s *HgRepo) TagsFromCommit(id string) ([]string, error) {
+ // Hg has a single tag per commit. If a second tag is added to a commit a
+ // new commit is created and the tag is attached to that new commit.
+ out, err := s.RunFromDir("hg", "log", "-r", id, "--style=xml")
+ if err != nil {
+ return []string{}, NewLocalError("Unable to retrieve tags", err, string(out))
+ }
+
+ type Logentry struct {
+ Node string `xml:"node,attr"`
+ Tag string `xml:"tag"`
+ }
+ type Log struct {
+ XMLName xml.Name `xml:"log"`
+ Logs []Logentry `xml:"logentry"`
+ }
+
+ logs := &Log{}
+ err = xml.Unmarshal(out, &logs)
+ if err != nil {
+ return []string{}, NewLocalError("Unable to retrieve tags", err, string(out))
+ }
+ if len(logs.Logs) == 0 {
+ return []string{}, NewLocalError("Unable to retrieve tags", err, string(out))
+ }
+
+ t := strings.TrimSpace(logs.Logs[0].Tag)
+ if t != "" {
+ return []string{t}, nil
+ }
+ return []string{}, nil
+}
+
+// Ping returns if remote location is accessible.
+func (s *HgRepo) Ping() bool {
+ _, err := s.run("hg", "identify", s.Remote())
+ if err != nil {
+ return false
+ }
+
+ return true
+}
diff --git a/vendor/github.com/Masterminds/vcs/hg_test.go b/vendor/github.com/Masterminds/vcs/hg_test.go
index 9b81937..d63f0d8 100644
--- a/vendor/github.com/Masterminds/vcs/hg_test.go
+++ b/vendor/github.com/Masterminds/vcs/hg_test.go
@@ -2,6 +2,7 @@
import (
"io/ioutil"
+ "strings"
"time"
//"log"
"os"
@@ -123,6 +124,22 @@
t.Error("Hg tags is not reporting the correct version")
}
+ tags, err = repo.TagsFromCommit("a5494ba2177f")
+ if err != nil {
+ t.Error(err)
+ }
+ if len(tags) != 0 {
+ t.Error("Hg is incorrectly returning tags for a commit")
+ }
+
+ tags, err = repo.TagsFromCommit("d680e82228d2")
+ if err != nil {
+ t.Error(err)
+ }
+ if len(tags) != 1 || tags[0] != "1.0.0" {
+ t.Error("Hg is incorrectly returning tags for a commit")
+ }
+
branches, err := repo.Branches()
if err != nil {
t.Error(err)
@@ -199,3 +216,68 @@
t.Error(nrerr)
}
}
+
+func TestHgPing(t *testing.T) {
+ tempDir, err := ioutil.TempDir("", "go-vcs-hg-tests")
+ if err != nil {
+ t.Error(err)
+ }
+ defer func() {
+ err = os.RemoveAll(tempDir)
+ if err != nil {
+ t.Error(err)
+ }
+ }()
+
+ repo, err := NewHgRepo("https://bitbucket.org/mattfarina/testhgrepo", tempDir)
+ if err != nil {
+ t.Error(err)
+ }
+
+ ping := repo.Ping()
+ if !ping {
+ t.Error("Hg unable to ping working repo")
+ }
+
+ repo, err = NewHgRepo("https://bitbucket.org/mattfarina/ihopethisneverexistsbecauseitshouldnt", tempDir)
+ if err != nil {
+ t.Error(err)
+ }
+
+ ping = repo.Ping()
+ if ping {
+ t.Error("Hg got a ping response from when it should not have")
+ }
+}
+
+func TestHgInit(t *testing.T) {
+ tempDir, err := ioutil.TempDir("", "go-vcs-hg-tests")
+ repoDir := tempDir + "/repo"
+ if err != nil {
+ t.Error(err)
+ }
+ defer func() {
+ err = os.RemoveAll(tempDir)
+ if err != nil {
+ t.Error(err)
+ }
+ }()
+
+ repo, err := NewHgRepo(repoDir, repoDir)
+ if err != nil {
+ t.Error(err)
+ }
+
+ err = repo.Init()
+ if err != nil {
+ t.Error(err)
+ }
+
+ v, err := repo.Version()
+ if err != nil {
+ t.Error(err)
+ }
+ if !strings.HasPrefix(v, "000000") {
+ t.Errorf("Hg Init reporting wrong initial version: %s", v)
+ }
+}
diff --git a/vendor/github.com/Masterminds/vcs/repo.go b/vendor/github.com/Masterminds/vcs/repo.go
index 318d1ec..61a39a0 100644
--- a/vendor/github.com/Masterminds/vcs/repo.go
+++ b/vendor/github.com/Masterminds/vcs/repo.go
@@ -26,7 +26,6 @@
package vcs
import (
- "errors"
"fmt"
"io/ioutil"
"log"
@@ -37,22 +36,6 @@
"time"
)
-var (
- // ErrWrongVCS is returned when an action is tried on the wrong VCS.
- ErrWrongVCS = errors.New("Wrong VCS detected")
-
- // ErrCannotDetectVCS is returned when VCS cannot be detected from URI string.
- ErrCannotDetectVCS = errors.New("Cannot detect VCS")
-
- // ErrWrongRemote occurs when the passed in remote does not match the VCS
- // configured endpoint.
- ErrWrongRemote = errors.New("The Remote does not match the VCS endpoint")
-
- // ErrRevisionUnavailable happens when commit revision information is
- // unavailable.
- ErrRevisionUnavailable = errors.New("Revision unavailable")
-)
-
// Logger is where you can provide a logger, implementing the log.Logger interface,
// where verbose output from each VCS will be written. The default logger does
// not log data. To log data supply your own logger or change the output location
@@ -97,6 +80,9 @@
// Get is used to perform an initial clone/checkout of a repository.
Get() error
+ // Initializes a new repository locally.
+ Init() error
+
// Update performs an update to an existing checkout of a repository.
Update() error
@@ -118,9 +104,6 @@
// Tags returns a list of available tags on the repository.
Tags() ([]string, error)
- // TODO: Provide a consistent manner to get reference information across
- // multiple VCS.
-
// IsReference returns if a string is a reference. A reference can be a
// commit id, branch, or tag.
IsReference(string) bool
@@ -131,6 +114,15 @@
// CommitInfo retrieves metadata about a commit.
CommitInfo(string) (*CommitInfo, error)
+
+ // TagsFromCommit retrieves tags from a commit id.
+ TagsFromCommit(string) ([]string, error)
+
+ // Ping returns if remote location is accessible.
+ Ping() bool
+
+ // RunFromDir executes a command from repo's directory.
+ RunFromDir(cmd string, args ...string) ([]byte, error)
}
// NewRepo returns a Repo based on trying to detect the source control from the
@@ -219,7 +211,7 @@
return out, err
}
-func (b *base) runFromDir(cmd string, args ...string) ([]byte, error) {
+func (b *base) RunFromDir(cmd string, args ...string) ([]byte, error) {
c := exec.Command(cmd, args...)
c.Dir = b.local
c.Env = envForDir(c.Dir)
diff --git a/vendor/github.com/Masterminds/vcs/svn.go b/vendor/github.com/Masterminds/vcs/svn.go
index f14ccf9..85f60b5 100644
--- a/vendor/github.com/Masterminds/vcs/svn.go
+++ b/vendor/github.com/Masterminds/vcs/svn.go
@@ -4,6 +4,7 @@
"encoding/xml"
"os"
"os/exec"
+ "path/filepath"
"regexp"
"strings"
"time"
@@ -35,7 +36,7 @@
// the repo passed in here.
out, err := exec.Command("svn", "info", local).CombinedOutput()
if err != nil {
- return nil, err
+ return nil, NewLocalError("Unable to retrieve local repo information", err, string(out))
}
m := svnDetectURL.FindStringSubmatch(string(out))
@@ -67,28 +68,68 @@
// Note, because SVN isn't distributed this is a checkout without
// a clone.
func (s *SvnRepo) Get() error {
- _, err := s.run("svn", "checkout", s.Remote(), s.LocalPath())
- return err
+ remote := s.Remote()
+ if strings.HasPrefix(remote, "/") {
+ remote = "file://" + remote
+ }
+ out, err := s.run("svn", "checkout", remote, s.LocalPath())
+ if err != nil {
+ return NewRemoteError("Unable to get repository", err, string(out))
+ }
+ return nil
+}
+
+// Init will create a svn repository at remote location.
+func (s *SvnRepo) Init() error {
+ out, err := s.run("svnadmin", "create", s.Remote())
+
+ if err != nil && s.isUnableToCreateDir(err) {
+
+ basePath := filepath.Dir(filepath.FromSlash(s.Remote()))
+ if _, err := os.Stat(basePath); os.IsNotExist(err) {
+ err = os.MkdirAll(basePath, 0755)
+ if err != nil {
+ return NewLocalError("Unable to initialize repository", err, "")
+ }
+
+ out, err = s.run("svnadmin", "create", s.Remote())
+ if err != nil {
+ return NewLocalError("Unable to initialize repository", err, string(out))
+ }
+ return nil
+ }
+
+ } else if err != nil {
+ return NewLocalError("Unable to initialize repository", err, string(out))
+ }
+
+ return nil
}
// Update performs an SVN update to an existing checkout.
func (s *SvnRepo) Update() error {
- _, err := s.runFromDir("svn", "update")
+ out, err := s.RunFromDir("svn", "update")
+ if err != nil {
+ return NewRemoteError("Unable to update repository", err, string(out))
+ }
return err
}
// UpdateVersion sets the version of a package currently checked out via SVN.
func (s *SvnRepo) UpdateVersion(version string) error {
- _, err := s.runFromDir("svn", "update", "-r", version)
- return err
+ out, err := s.RunFromDir("svn", "update", "-r", version)
+ if err != nil {
+ return NewRemoteError("Unable to update checked out version", err, string(out))
+ }
+ return nil
}
// Version retrieves the current version.
func (s *SvnRepo) Version() (string, error) {
- out, err := s.runFromDir("svnversion", ".")
+ out, err := s.RunFromDir("svnversion", ".")
s.log(out)
if err != nil {
- return "", err
+ return "", NewLocalError("Unable to retrieve checked out version", err, string(out))
}
return strings.TrimSpace(string(out)), nil
}
@@ -97,16 +138,16 @@
func (s *SvnRepo) Date() (time.Time, error) {
version, err := s.Version()
if err != nil {
- return time.Time{}, err
+ return time.Time{}, NewLocalError("Unable to retrieve revision date", err, "")
}
- out, err := s.runFromDir("svn", "pget", "svn:date", "--revprop", "-r", version)
+ out, err := s.RunFromDir("svn", "pget", "svn:date", "--revprop", "-r", version)
if err != nil {
- return time.Time{}, err
+ return time.Time{}, NewLocalError("Unable to retrieve revision date", err, string(out))
}
const longForm = "2006-01-02T15:04:05.000000Z\n"
t, err := time.Parse(longForm, string(out))
if err != nil {
- return time.Time{}, err
+ return time.Time{}, NewLocalError("Unable to retrieve revision date", err, string(out))
}
return t, nil
}
@@ -144,7 +185,7 @@
// IsReference returns if a string is a reference. A reference is a commit id.
// Branches and tags are part of the path.
func (s *SvnRepo) IsReference(r string) bool {
- out, err := s.runFromDir("svn", "log", "-r", r)
+ out, err := s.RunFromDir("svn", "log", "-r", r)
// This is a complete hack. There must be a better way to do this. Pull
// requests welcome. When the reference isn't real you get a line of
@@ -162,15 +203,15 @@
// IsDirty returns if the checkout has been modified from the checked
// out reference.
func (s *SvnRepo) IsDirty() bool {
- out, err := s.runFromDir("svn", "diff")
+ out, err := s.RunFromDir("svn", "diff")
return err != nil || len(out) != 0
}
// CommitInfo retrieves metadata about a commit.
func (s *SvnRepo) CommitInfo(id string) (*CommitInfo, error) {
- out, err := s.runFromDir("svn", "log", "-r", id, "--xml")
+ out, err := s.RunFromDir("svn", "log", "-r", id, "--xml")
if err != nil {
- return nil, err
+ return nil, NewRemoteError("Unable to retrieve commit information", err, string(out))
}
type Logentry struct {
@@ -186,7 +227,7 @@
logs := &Log{}
err = xml.Unmarshal(out, &logs)
if err != nil {
- return nil, err
+ return nil, NewLocalError("Unable to retrieve commit information", err, string(out))
}
if len(logs.Logs) == 0 {
return nil, ErrRevisionUnavailable
@@ -201,9 +242,37 @@
if len(logs.Logs[0].Date) > 0 {
ci.Date, err = time.Parse(time.RFC3339Nano, logs.Logs[0].Date)
if err != nil {
- return nil, err
+ return nil, NewLocalError("Unable to retrieve commit information", err, string(out))
}
}
return ci, nil
}
+
+// TagsFromCommit retrieves tags from a commit id.
+func (s *SvnRepo) TagsFromCommit(id string) ([]string, error) {
+ // Svn tags are a convention implemented as paths. See the details on the
+ // Tag() method for more information.
+ return []string{}, nil
+}
+
+// Ping returns if remote location is accessible.
+func (s *SvnRepo) Ping() bool {
+ _, err := s.run("svn", "--non-interactive", "info", s.Remote())
+ if err != nil {
+ return false
+ }
+
+ return true
+}
+
+// isUnableToCreateDir checks for an error in Init() to see if an error
+// where the parent directory of the VCS local path doesn't exist.
+func (s *SvnRepo) isUnableToCreateDir(err error) bool {
+ msg := err.Error()
+ if strings.HasPrefix(msg, "E000002") {
+ return true
+ }
+
+ return false
+}
diff --git a/vendor/github.com/Masterminds/vcs/svn_test.go b/vendor/github.com/Masterminds/vcs/svn_test.go
index 8c8d0ee..349b072 100644
--- a/vendor/github.com/Masterminds/vcs/svn_test.go
+++ b/vendor/github.com/Masterminds/vcs/svn_test.go
@@ -134,6 +134,14 @@
t.Error("Svn is incorrectly returning tags")
}
+ tags, err = repo.TagsFromCommit("2")
+ if err != nil {
+ t.Error(err)
+ }
+ if len(tags) != 0 {
+ t.Error("Svn is incorrectly returning tags for a commit")
+ }
+
branches, err := repo.Branches()
if err != nil {
t.Error(err)
@@ -207,3 +215,74 @@
t.Error(nrerr)
}
}
+
+func TestSvnPing(t *testing.T) {
+ tempDir, err := ioutil.TempDir("", "go-vcs-svn-tests")
+ if err != nil {
+ t.Error(err)
+ }
+ defer func() {
+ err = os.RemoveAll(tempDir)
+ if err != nil {
+ t.Error(err)
+ }
+ }()
+
+ repo, err := NewSvnRepo("https://github.com/Masterminds/VCSTestRepo/trunk", tempDir)
+ if err != nil {
+ t.Error(err)
+ }
+
+ ping := repo.Ping()
+ if !ping {
+ t.Error("Svn unable to ping working repo")
+ }
+
+ repo, err = NewSvnRepo("https://github.com/Masterminds/ihopethisneverexistsbecauseitshouldnt", tempDir)
+ if err != nil {
+ t.Error(err)
+ }
+
+ ping = repo.Ping()
+ if ping {
+ t.Error("Svn got a ping response from when it should not have")
+ }
+}
+
+func TestSvnInit(t *testing.T) {
+ tempDir, err := ioutil.TempDir("", "go-vcs-svn-tests")
+ remoteDir := tempDir + "/remoteDir"
+ localDir := tempDir + "/localDir"
+ if err != nil {
+ t.Error(err)
+ }
+ defer func() {
+ err = os.RemoveAll(tempDir)
+ if err != nil {
+ t.Error(err)
+ }
+ }()
+
+ repo, err := NewSvnRepo(remoteDir, localDir)
+ if err != nil {
+ t.Error(err)
+ }
+
+ err = repo.Init()
+ if err != nil {
+ t.Error(err)
+ }
+
+ err = repo.Get()
+ if err != nil {
+ t.Error(err)
+ }
+
+ v, err := repo.Version()
+ if err != nil {
+ t.Error(err)
+ }
+ if v != "0" {
+ t.Errorf("Svn Init returns wrong version: %s", v)
+ }
+}
diff --git a/vendor/github.com/codegangsta/cli/README.md b/vendor/github.com/codegangsta/cli/README.md
index bb769fe..d9371cf 100644
--- a/vendor/github.com/codegangsta/cli/README.md
+++ b/vendor/github.com/codegangsta/cli/README.md
@@ -329,6 +329,45 @@
...
```
+### Subcommands categories
+
+For additional organization in apps that have many subcommands, you can
+associate a category for each command to group them together in the help
+output.
+
+E.g.
+
+```go
+...
+ app.Commands = []cli.Command{
+ {
+ Name: "noop",
+ },
+ {
+ Name: "add",
+ Category: "template",
+ },
+ {
+ Name: "remove",
+ Category: "template",
+ },
+ }
+...
+```
+
+Will include:
+
+```
+...
+COMMANDS:
+ noop
+
+ Template actions:
+ add
+ remove
+...
+```
+
### Bash Completion
You can enable completion commands by setting the `EnableBashCompletion`
diff --git a/vendor/github.com/codegangsta/cli/app.go b/vendor/github.com/codegangsta/cli/app.go
index 6632ec0..bd20a2d 100644
--- a/vendor/github.com/codegangsta/cli/app.go
+++ b/vendor/github.com/codegangsta/cli/app.go
@@ -5,7 +5,8 @@
"io"
"io/ioutil"
"os"
- "path"
+ "path/filepath"
+ "sort"
"time"
)
@@ -34,6 +35,8 @@
HideHelp bool
// Boolean to hide built-in version flag and the VERSION section of help
HideVersion bool
+ // Populate on app startup, only gettable throught method Categories()
+ categories CommandCategories
// An action to execute when the bash-completion flag is set
BashComplete func(context *Context)
// An action to execute before any subcommands are run, but after the context is ready
@@ -77,8 +80,8 @@
// Creates a new cli Application with some reasonable defaults for Name, Usage, Version and Action.
func NewApp() *App {
return &App{
- Name: path.Base(os.Args[0]),
- HelpName: path.Base(os.Args[0]),
+ Name: filepath.Base(os.Args[0]),
+ HelpName: filepath.Base(os.Args[0]),
Usage: "A new cli application",
UsageText: "",
Version: "0.0.0",
@@ -104,6 +107,12 @@
}
a.Commands = newCmds
+ a.categories = CommandCategories{}
+ for _, command := range a.Commands {
+ a.categories = a.categories.AddCommand(command.Category, command)
+ }
+ sort.Sort(a.categories)
+
// append help to commands
if a.Command(helpCommand.Name) == nil && !a.HideHelp {
a.Commands = append(a.Commands, helpCommand)
@@ -316,6 +325,11 @@
return nil
}
+// Returnes the array containing all the categories with the commands they contain
+func (a *App) Categories() CommandCategories {
+ return a.categories
+}
+
func (a *App) hasFlag(flag Flag) bool {
for _, f := range a.Flags {
if flag == f {
diff --git a/vendor/github.com/codegangsta/cli/app_test.go b/vendor/github.com/codegangsta/cli/app_test.go
index 7feaf1f..ebf26c7 100644
--- a/vendor/github.com/codegangsta/cli/app_test.go
+++ b/vendor/github.com/codegangsta/cli/app_test.go
@@ -8,6 +8,7 @@
"io"
"io/ioutil"
"os"
+ "reflect"
"strings"
"testing"
)
@@ -939,6 +940,55 @@
}
}
+func TestApp_Run_Categories(t *testing.T) {
+ app := NewApp()
+ app.Name = "categories"
+ app.Commands = []Command{
+ Command{
+ Name: "command1",
+ Category: "1",
+ },
+ Command{
+ Name: "command2",
+ Category: "1",
+ },
+ Command{
+ Name: "command3",
+ Category: "2",
+ },
+ }
+ buf := new(bytes.Buffer)
+ app.Writer = buf
+
+ app.Run([]string{"categories"})
+
+ expect := CommandCategories{
+ &CommandCategory{
+ Name: "1",
+ Commands: []Command{
+ app.Commands[0],
+ app.Commands[1],
+ },
+ },
+ &CommandCategory{
+ Name: "2",
+ Commands: []Command{
+ app.Commands[2],
+ },
+ },
+ }
+ if !reflect.DeepEqual(app.Categories(), expect) {
+ t.Fatalf("expected categories %#v, to equal %#v", app.Categories(), expect)
+ }
+
+ output := buf.String()
+ t.Logf("output: %q\n", buf.Bytes())
+
+ if !strings.Contains(output, "1:\n command1") {
+ t.Errorf("want buffer to include category %q, did not: \n%q", "1:\n command1", output)
+ }
+}
+
func TestApp_Run_DoesNotOverwriteErrorFromBefore(t *testing.T) {
app := NewApp()
app.Action = func(c *Context) {}
diff --git a/vendor/github.com/codegangsta/cli/category.go b/vendor/github.com/codegangsta/cli/category.go
new file mode 100644
index 0000000..7dbf218
--- /dev/null
+++ b/vendor/github.com/codegangsta/cli/category.go
@@ -0,0 +1,30 @@
+package cli
+
+type CommandCategories []*CommandCategory
+
+type CommandCategory struct {
+ Name string
+ Commands Commands
+}
+
+func (c CommandCategories) Less(i, j int) bool {
+ return c[i].Name < c[j].Name
+}
+
+func (c CommandCategories) Len() int {
+ return len(c)
+}
+
+func (c CommandCategories) Swap(i, j int) {
+ c[i], c[j] = c[j], c[i]
+}
+
+func (c CommandCategories) AddCommand(category string, command Command) CommandCategories {
+ for _, commandCategory := range c {
+ if commandCategory.Name == category {
+ commandCategory.Commands = append(commandCategory.Commands, command)
+ return c
+ }
+ }
+ return append(c, &CommandCategory{Name: category, Commands: []Command{command}})
+}
diff --git a/vendor/github.com/codegangsta/cli/command.go b/vendor/github.com/codegangsta/cli/command.go
index 0153713..1a05b54 100644
--- a/vendor/github.com/codegangsta/cli/command.go
+++ b/vendor/github.com/codegangsta/cli/command.go
@@ -3,6 +3,7 @@
import (
"fmt"
"io/ioutil"
+ "sort"
"strings"
)
@@ -22,6 +23,8 @@
Description string
// A short description of the arguments of this command
ArgsUsage string
+ // The category the command is part of
+ Category string
// The function to call when checking for bash command completions
BashComplete func(context *Context)
// An action to execute before any sub-subcommands are run, but after the context is ready
@@ -37,7 +40,7 @@
// If this function is not set, the "Incorrect usage" is displayed and the execution is interrupted.
OnUsageError func(context *Context, err error) error
// List of child commands
- Subcommands []Command
+ Subcommands Commands
// List of flags to parse
Flags []Flag
// Treat all flags as normal arguments if true
@@ -59,6 +62,8 @@
return strings.Join(c.commandNamePath, " ")
}
+type Commands []Command
+
// Invokes the command given the context, parses ctx.Args() to generate command-specific flags
func (c Command) Run(ctx *Context) (err error) {
if len(c.Subcommands) > 0 {
@@ -227,6 +232,13 @@
app.Email = ctx.App.Email
app.Writer = ctx.App.Writer
+ app.categories = CommandCategories{}
+ for _, command := range c.Subcommands {
+ app.categories = app.categories.AddCommand(command.Category, command)
+ }
+
+ sort.Sort(app.categories)
+
// bash completion
app.EnableBashCompletion = ctx.App.EnableBashCompletion
if c.BashComplete != nil {
diff --git a/vendor/github.com/codegangsta/cli/help.go b/vendor/github.com/codegangsta/cli/help.go
index d3a12a2..adf157d 100644
--- a/vendor/github.com/codegangsta/cli/help.go
+++ b/vendor/github.com/codegangsta/cli/help.go
@@ -23,9 +23,10 @@
AUTHOR(S):
{{range .Authors}}{{ . }}{{end}}
{{end}}{{if .Commands}}
-COMMANDS:
- {{range .Commands}}{{join .Names ", "}}{{ "\t" }}{{.Usage}}
- {{end}}{{end}}{{if .Flags}}
+COMMANDS:{{range .Categories}}{{if .Name}}
+ {{.Name}}{{ ":" }}{{end}}{{range .Commands}}
+ {{.Name}}{{with .ShortName}}, {{.}}{{end}}{{ "\t" }}{{.Usage}}{{end}}
+{{end}}{{end}}{{if .Flags}}
GLOBAL OPTIONS:
{{range .Flags}}{{.}}
{{end}}{{end}}{{if .Copyright }}
@@ -41,7 +42,10 @@
{{.HelpName}} - {{.Usage}}
USAGE:
- {{.HelpName}}{{if .Flags}} [command options]{{end}} {{if .ArgsUsage}}{{.ArgsUsage}}{{else}}[arguments...]{{end}}{{if .Description}}
+ {{.HelpName}}{{if .Flags}} [command options]{{end}} {{if .ArgsUsage}}{{.ArgsUsage}}{{else}}[arguments...]{{end}}{{if .Category}}
+
+CATEGORY:
+ {{.Category}}{{end}}{{if .Description}}
DESCRIPTION:
{{.Description}}{{end}}{{if .Flags}}
@@ -60,9 +64,10 @@
USAGE:
{{.HelpName}} command{{if .Flags}} [command options]{{end}} {{if .ArgsUsage}}{{.ArgsUsage}}{{else}}[arguments...]{{end}}
-COMMANDS:
- {{range .Commands}}{{join .Names ", "}}{{ "\t" }}{{.Usage}}
- {{end}}{{if .Flags}}
+COMMANDS:{{range .Categories}}{{if .Name}}
+ {{.Name}}{{ ":" }}{{end}}{{range .Commands}}
+ {{.Name}}{{with .ShortName}}, {{.}}{{end}}{{ "\t" }}{{.Usage}}{{end}}
+{{end}}{{if .Flags}}
OPTIONS:
{{range .Flags}}{{.}}
{{end}}{{end}}