Merge pull request #487 from hori-ryota/feature/fix-unknown-packageroot

Fix NormalizeName for subpackage of unknown host
diff --git a/CHANGELOG.md b/CHANGELOG.md
index a76e7d3..45e126d 100644
--- a/CHANGELOG.md
+++ b/CHANGELOG.md
@@ -1,3 +1,60 @@
+# Unreleased
+
+## Added
+- #533: Log VCS output with debug (`--debug` switch) when there was a VCS error (thanks @atombender)
+
+## Changed
+- #521: Sort subpackages for glide.yaml and glide.lock to avoid spurious diffs
+
+# Release 0.11.1 (2016-07-21)
+
+## Fixed
+- #505: Ignored dependency showing up in testImport
+
+# Release 0.11.0 (2016-07-05)
+
+## Added
+- #461: Resolve test imports
+- #458: Wizard and version detection are now on `glide get`
+- #444: New config wizard helps you find versions and set ranges. Can be run from
+  `glide init` or as separate command
+- #438: Added ability to read symlink basedirs (thanks @klnusbaum)
+- #436: Added .idea to .gitignore
+- #393 and #401: Added a PPA (https://github.com/Masterminds/glide-ppa) and instructions
+  on using it (thanks @franciscocpg)
+- #390: Added support for custom Go executable name. Needed for environments like
+  appengine. Environment variable GLIDE_GO_EXECUTABLE (thanks @dpmcnevin)
+- #382: `glide info` command takes a format string and returns info (thanks @franciscocpg)
+- #365: glide list: support json output format (thanks @chancez)
+
+## Changed
+- Tags are now in the form v[SemVer]. The change is the initial v on the tag.
+  This is to conform with other Go tools that require this.
+- #501: Updating the plugins documentation and adding listing
+- #500: Log an error if stripping version control data fails (thanks @alexbrand)
+- #496: Updated to github.com/Masterminds/semver 1.1.1
+- #495: Updated to github.com/Masterminds/vcs 1.8.0
+- #494: Glide install skips fetch when it is up to date
+- #489: Make shared funcs for lockfile usage (thanks @heewa)
+- #459: When a conflict occurs output the tag, if one exists, for the commit
+- #443: Updating message indentation to be uniform
+- #431: Updated the docs on subpackages
+- #433: The global shared cache was reworked in prep for future uses
+- #396: Don't update the lock file if nothing has changed
+
+## Fixed
+- #460: Sometimes ignored packages were written to lock file. Fixed.
+- #463: Fixed possible nil pointer issues
+- #453: Fix DeleteUnused flag which was not working (thanks @s-urbaniak)
+- #432: Fixed issue with new net/http/httptrace std lib package
+- #392: Correctly normalize Windows package paths (thanks @jrick)
+- #395: Creating the cache key did not handle SCP properly
+- #386: Fixed help text indentation
+- #383: Failed `glide get` had been updating files. No longer does this
+
+And thanks to @derelk, @franciscocpg, @shawnps, @kngu9, @tugberkugurlu, @rhcarvalho,
+@gyuho, and @7imon7ays for documentation updates.
+
 # Release 0.10.2 (2016-04-06)
 
 - Issue #362: Updated docs on how -update-vendored works to help avoid confusion.
diff --git a/README.md b/README.md
index 566bd30..39ef0e8 100644
--- a/README.md
+++ b/README.md
@@ -12,7 +12,7 @@
 installed by a tool (e.g. glide), similar to `go get` or they can be vendored and
 distributed with the package.
 
-[![Build Status](https://travis-ci.org/Masterminds/glide.svg)](https://travis-ci.org/Masterminds/glide) [![Go Report Card](http://goreportcard.com/badge/Masterminds/glide)](http://goreportcard.com/report/Masterminds/glide) [![GoDoc](https://godoc.org/github.com/Masterminds/glide?status.svg)](https://godoc.org/github.com/Masterminds/glide) [![Documentation Status](https://readthedocs.org/projects/glide/badge/?version=stable)](http://glide.readthedocs.org/en/stable/?badge=stable) [![Documentation Status](https://readthedocs.org/projects/glide/badge/?version=latest)](http://glide.readthedocs.org/en/latest/?badge=latest) [![Join the chat at https://gitter.im/Masterminds/glide](https://badges.gitter.im/Masterminds/glide.svg)](https://gitter.im/Masterminds/glide?utm_source=badge&utm_medium=badge&utm_campaign=pr-badge&utm_content=badge)
+[![Build Status](https://travis-ci.org/Masterminds/glide.svg)](https://travis-ci.org/Masterminds/glide) [![Go Report Card](https://goreportcard.com/badge/github.com/Masterminds/glide)](https://goreportcard.com/report/github.com/Masterminds/glide) [![GoDoc](https://godoc.org/github.com/Masterminds/glide?status.svg)](https://godoc.org/github.com/Masterminds/glide) [![Documentation Status](https://readthedocs.org/projects/glide/badge/?version=stable)](http://glide.readthedocs.org/en/stable/?badge=stable) [![Documentation Status](https://readthedocs.org/projects/glide/badge/?version=latest)](http://glide.readthedocs.org/en/latest/?badge=latest) [![Join the chat at https://gitter.im/Masterminds/glide](https://badges.gitter.im/Masterminds/glide.svg)](https://gitter.im/Masterminds/glide?utm_source=badge&utm_medium=badge&utm_campaign=pr-badge&utm_content=badge)
 
 ### Features
 
@@ -76,7 +76,13 @@
 
 ## Install
 
-On Mac OS X you can install the latest release via [Homebrew](https://github.com/Homebrew/homebrew):
+The easiest way to install the latest release on Mac or Linux is with the following script:
+
+```
+curl https://glide.sh/get | sh
+```
+
+On Mac OS X you can also install the latest release via [Homebrew](https://github.com/Homebrew/homebrew):
 
 ```
 $ brew install glide
diff --git a/action/get.go b/action/get.go
index 5b0b72e..5c34d5e 100644
--- a/action/get.go
+++ b/action/get.go
@@ -95,7 +95,10 @@
 
 	if strip {
 		msg.Info("Removing version control data from vendor directory...")
-		gpath.StripVcs()
+		err := gpath.StripVcs()
+		if err != nil {
+			msg.Err("Unable to strip version control data: %s", err)
+		}
 	}
 
 	if stripVendor {
diff --git a/action/install.go b/action/install.go
index 3deb9d2..ee91401 100644
--- a/action/install.go
+++ b/action/install.go
@@ -1,7 +1,6 @@
 package action
 
 import (
-	"io/ioutil"
 	"path/filepath"
 
 	"github.com/Masterminds/glide/cache"
@@ -31,10 +30,17 @@
 		return
 	}
 	// Load lockfile
-	lock, err := LoadLockfile(base, conf)
+	lock, err := cfg.ReadLockFile(filepath.Join(base, gpath.LockFile))
 	if err != nil {
 		msg.Die("Could not load lockfile.")
 	}
+	// Verify lockfile hasn't changed
+	hash, err := conf.Hash()
+	if err != nil {
+		msg.Die("Could not load lockfile.")
+	} else if hash != lock.Hash {
+		msg.Warn("Lock file may be out of date. Hash check of YAML failed. You may need to run 'update'")
+	}
 
 	// Delete unused packages
 	if installer.DeleteUnused {
@@ -66,7 +72,10 @@
 
 	if strip {
 		msg.Info("Removing version control data from vendor directory...")
-		gpath.StripVcs()
+		err := gpath.StripVcs()
+		if err != nil {
+			msg.Err("Unable to strip version control data: %s", err)
+		}
 	}
 
 	if stripVendor {
@@ -77,28 +86,3 @@
 		}
 	}
 }
-
-// LoadLockfile loads the contents of a glide.lock file.
-//
-// TODO: This should go in another package.
-func LoadLockfile(base string, conf *cfg.Config) (*cfg.Lockfile, error) {
-	yml, err := ioutil.ReadFile(filepath.Join(base, gpath.LockFile))
-	if err != nil {
-		return nil, err
-	}
-	lock, err := cfg.LockfileFromYaml(yml)
-	if err != nil {
-		return nil, err
-	}
-
-	hash, err := conf.Hash()
-	if err != nil {
-		return nil, err
-	}
-
-	if hash != lock.Hash {
-		msg.Warn("Lock file may be out of date. Hash check of YAML failed. You may need to run 'update'")
-	}
-
-	return lock, nil
-}
diff --git a/action/project_info.go b/action/project_info.go
index 5e0995e..379026e 100644
--- a/action/project_info.go
+++ b/action/project_info.go
@@ -6,13 +6,14 @@
 	"github.com/Masterminds/glide/msg"
 )
 
+// Info prints information about a project based on a passed in format.
 func Info(format string) {
 	conf := EnsureConfig()
 	var buffer bytes.Buffer
 	varInit := false
-	for _, var_format := range format {
+	for _, varfmt := range format {
 		if varInit {
-			switch var_format {
+			switch varfmt {
 			case 'n':
 				buffer.WriteString(conf.Name)
 			case 'd':
@@ -22,15 +23,15 @@
 			case 'l':
 				buffer.WriteString(conf.License)
 			default:
-				msg.Die("Invalid format %s", string(var_format))
+				msg.Die("Invalid format %s", string(varfmt))
 			}
 		} else {
-			switch var_format {
+			switch varfmt {
 			case '%':
 				varInit = true
 				continue
 			default:
-				buffer.WriteString(string(var_format))
+				buffer.WriteString(string(varfmt))
 			}
 		}
 		varInit = false
diff --git a/action/rebuild.go b/action/rebuild.go
index f76d948..dffde39 100644
--- a/action/rebuild.go
+++ b/action/rebuild.go
@@ -98,4 +98,3 @@
 	}
 	return err
 }
-
diff --git a/action/update.go b/action/update.go
index cb33e63..fdd90ad 100644
--- a/action/update.go
+++ b/action/update.go
@@ -117,7 +117,10 @@
 
 	if strip {
 		msg.Info("Removing version control data from vendor directory...")
-		gpath.StripVcs()
+		err := gpath.StripVcs()
+		if err != nil {
+			msg.Err("Unable to strip version control data: %s", err)
+		}
 	}
 
 	if stripVendor {
diff --git a/cfg/config.go b/cfg/config.go
index cdfd943..115c76d 100644
--- a/cfg/config.go
+++ b/cfg/config.go
@@ -5,6 +5,7 @@
 	"fmt"
 	"io/ioutil"
 	"reflect"
+	"sort"
 	"strings"
 
 	"github.com/Masterminds/glide/util"
@@ -390,6 +391,19 @@
 	Os          []string `yaml:"os,omitempty"`
 }
 
+// DependencyFromLock converts a Lock to a Dependency
+func DependencyFromLock(lock *Lock) *Dependency {
+	return &Dependency{
+		Name:        lock.Name,
+		Reference:   lock.Version,
+		Repository:  lock.Repository,
+		VcsType:     lock.VcsType,
+		Subpackages: lock.Subpackages,
+		Arch:        lock.Arch,
+		Os:          lock.Os,
+	}
+}
+
 // UnmarshalYAML is a hook for gopkg.in/yaml.v2 in the unmarshaling process
 func (d *Dependency) UnmarshalYAML(unmarshal func(interface{}) error) error {
 	newDep := &dep{}
@@ -554,6 +568,7 @@
 			s = append(s, item)
 		}
 	}
+	sort.Strings(s)
 	return s
 }
 
diff --git a/cfg/lock.go b/cfg/lock.go
index 2b2c4c8..8a26e24 100644
--- a/cfg/lock.go
+++ b/cfg/lock.go
@@ -34,6 +34,18 @@
 	return yml, nil
 }
 
+// MarshalYAML is a hook for gopkg.in/yaml.v2.
+// It sorts import subpackages lexicographically for reproducibility.
+func (lf *Lockfile) MarshalYAML() (interface{}, error) {
+	for _, imp := range lf.Imports {
+		sort.Strings(imp.Subpackages)
+	}
+	for _, imp := range lf.DevImports {
+		sort.Strings(imp.Subpackages)
+	}
+	return lf, nil
+}
+
 // WriteFile writes a Glide lock file.
 //
 // This is a convenience function that marshals the YAML and then writes it to
@@ -72,6 +84,19 @@
 	return sha256.Sum256(yml), nil
 }
 
+// ReadLockFile loads the contents of a glide.lock file.
+func ReadLockFile(lockpath string) (*Lockfile, error) {
+	yml, err := ioutil.ReadFile(lockpath)
+	if err != nil {
+		return nil, err
+	}
+	lock, err := LockfileFromYaml(yml)
+	if err != nil {
+		return nil, err
+	}
+	return lock, nil
+}
+
 // Locks is a slice of locked dependencies.
 type Locks []*Lock
 
@@ -130,6 +155,19 @@
 	}
 }
 
+// LockFromDependency converts a Dependency to a Lock
+func LockFromDependency(dep *Dependency) *Lock {
+	return &Lock{
+		Name:        dep.Name,
+		Version:     dep.Pin,
+		Repository:  dep.Repository,
+		VcsType:     dep.VcsType,
+		Subpackages: dep.Subpackages,
+		Arch:        dep.Arch,
+		Os:          dep.Os,
+	}
+}
+
 // NewLockfile is used to create an instance of Lockfile.
 func NewLockfile(ds, tds Dependencies, hash string) *Lockfile {
 	lf := &Lockfile{
@@ -140,29 +178,13 @@
 	}
 
 	for i := 0; i < len(ds); i++ {
-		lf.Imports[i] = &Lock{
-			Name:        ds[i].Name,
-			Version:     ds[i].Pin,
-			Repository:  ds[i].Repository,
-			VcsType:     ds[i].VcsType,
-			Subpackages: ds[i].Subpackages,
-			Arch:        ds[i].Arch,
-			Os:          ds[i].Os,
-		}
+		lf.Imports[i] = LockFromDependency(ds[i])
 	}
 
 	sort.Sort(lf.Imports)
 
 	for i := 0; i < len(tds); i++ {
-		lf.DevImports[i] = &Lock{
-			Name:        tds[i].Name,
-			Version:     tds[i].Pin,
-			Repository:  tds[i].Repository,
-			VcsType:     tds[i].VcsType,
-			Subpackages: tds[i].Subpackages,
-			Arch:        tds[i].Arch,
-			Os:          tds[i].Os,
-		}
+		lf.DevImports[i] = LockFromDependency(tds[i])
 	}
 
 	sort.Sort(lf.DevImports)
@@ -180,15 +202,8 @@
 
 	i := 0
 	for name, dep := range ds {
-		lf.Imports[i] = &Lock{
-			Name:        name,
-			Version:     dep.Pin,
-			Repository:  dep.Repository,
-			VcsType:     dep.VcsType,
-			Subpackages: dep.Subpackages,
-			Arch:        dep.Arch,
-			Os:          dep.Os,
-		}
+		lf.Imports[i] = LockFromDependency(dep)
+		lf.Imports[i].Name = name
 		i++
 	}
 
diff --git a/cfg/lock_test.go b/cfg/lock_test.go
index 78dcee3..81edcd0 100644
--- a/cfg/lock_test.go
+++ b/cfg/lock_test.go
@@ -2,6 +2,7 @@
 
 import (
 	"sort"
+	"strings"
 	"testing"
 )
 
@@ -32,3 +33,80 @@
 		t.Error("Sorting of dependencies failed")
 	}
 }
+
+const inputSubpkgYaml = `
+imports:
+- name: github.com/gogo/protobuf
+  version: 82d16f734d6d871204a3feb1a73cb220cc92574c
+  subpackages:
+  - plugin/equal
+  - sortkeys
+  - plugin/face
+  - plugin/gostring
+  - vanity
+  - plugin/grpc
+  - plugin/marshalto
+  - plugin/populate
+  - plugin/oneofcheck
+  - plugin/size
+  - plugin/stringer
+  - plugin/defaultcheck
+  - plugin/embedcheck
+  - plugin/description
+  - plugin/enumstringer
+  - gogoproto
+  - plugin/testgen
+  - plugin/union
+  - plugin/unmarshal
+  - protoc-gen-gogo/generator
+  - protoc-gen-gogo/plugin
+  - vanity/command
+  - protoc-gen-gogo/descriptor
+  - proto
+`
+const expectSubpkgYaml = `
+imports:
+- name: github.com/gogo/protobuf
+  version: 82d16f734d6d871204a3feb1a73cb220cc92574c
+  subpackages:
+  - gogoproto
+  - plugin/defaultcheck
+  - plugin/description
+  - plugin/embedcheck
+  - plugin/enumstringer
+  - plugin/equal
+  - plugin/face
+  - plugin/gostring
+  - plugin/grpc
+  - plugin/marshalto
+  - plugin/oneofcheck
+  - plugin/populate
+  - plugin/size
+  - plugin/stringer
+  - plugin/testgen
+  - plugin/union
+  - plugin/unmarshal
+  - proto
+  - protoc-gen-gogo/descriptor
+  - protoc-gen-gogo/generator
+  - protoc-gen-gogo/plugin
+  - sortkeys
+  - vanity
+  - vanity/command
+`
+
+func TestSortSubpackages(t *testing.T) {
+	lf, err := LockfileFromYaml([]byte(inputSubpkgYaml))
+	if err != nil {
+		t.Fatal(err)
+	}
+
+	out, err := lf.Marshal()
+	if err != nil {
+		t.Fatal(err)
+	}
+
+	if !strings.Contains(string(out), expectSubpkgYaml) {
+		t.Errorf("Expected %q\nto contain\n%q")
+	}
+}
diff --git a/docs/plugins.md b/docs/plugins.md
index 98f24ae..bc3b596 100644
--- a/docs/plugins.md
+++ b/docs/plugins.md
@@ -1,44 +1,47 @@
 # Glide Plugins
 
-(Not to be confused with Glade Plugins. Pew.)
+Glide supports a simple plugin system similar to Git.
 
-Glide supports a simple plugin system similar to Git. When Glide
-encounters a subcommand that it does not know, it will try to delegate
-it to another executable according to the following rules.
+## Existing Plugins
+
+Some plugins exist today for Glide including:
+
+* [glide-vc](https://github.com/sgotti/glide-vc) - The vendor cleaner allows you to strip files files not needed for building your application from the `vendor/` directory.
+* [glide-brew](https://github.com/heewa/glide-brew) - Convert Go deps managed by glide to Homebrew resources to help you make brew formulas for you Go programs.
+* [glide-hash](https://github.com/mattfarina/glide-hash) - Generates a hash of the `glide.yaml` file compatible with Glides internal hash.
+
+_Note, to add plugins to this list please create a pull request._
+
+## How Plugins Work
+
+When Glide encounters a subcommand that it does not know, it will try to delegate it to another executable according to the following rules.
 
 Example:
 
 ```
-$ glide in     # We know this command, so we execute it
-$ glide foo    # We don't know this command, so we look for a suitable
-               # plugin.
+$ glide install # We know this command, so we execute it
+$ glide foo     # We don't know this command, so we look for a suitable
+                # plugin.
 ```
 
-In the example above, when glide receives the command `foo`, which it
-does not know, it will do the following:
+In the example above, when glide receives the command `foo`, which it does not know, it will do the following:
 
 1. Transform the name from `foo` to `glide-foo`
-2. Look on the system `$PATH` for `glide-foo`. If it finds a program by
-   that name, execute it...
-3. Or else, look at the current project's root for `glide-foo`. (That
-   is, look in the same directory as glide.yaml). If found, execute it.
+2. Look on the system `$PATH` for `glide-foo`. If it finds a program by that name, execute it...
+3. Or else, look at the current project's root for `glide-foo`. (That is, look in the same directory as `glide.yaml`). If found, execute it.
 4. If no suitable command is found, exit with an error.
 
 ## Writing a Glide Plugin
 
-A Glide plugin can be written in any language you wish, provided that it
-can be executed from the command line as a subprocess of Glide. The
-example included with Glide is a simple Bash script. We could just as
-easily write Go, Python, Perl, or even Java code (with a wrapper) to
+A Glide plugin can be written in any language you wish, provided that it can be executed from the command line as a subprocess of Glide. The example included with Glide is a simple Bash script. We could just as easily write Go, Python, Perl, or even Java code (with a wrapper) to
 execute.
 
 A glide plugin must be in one of two locations:
 
-1. Somewhere on the PATH (including `$GLIDE_PATH/_vendor/bin`)
+1. Somewhere on the PATH
 2. In the same directory as `glide.yaml`
 
-It is recommended that system-wide Glide plugins go in `/usr/local/bin`
-while project-specific plugins go in the same directory as `glide.yaml`.
+It is recommended that system-wide Glide plugins go in `/usr/local/bin` or `$GOPATH/bin` while project-specific plugins go in the same directory as `glide.yaml`.
 
 ### Arguments and Flags
 
@@ -48,32 +51,15 @@
 $ glide foo -name=Matt myfile.txt
 ```
 
-Glide will interpret this as a request to execute `glide-foo` with the
-arguments `-name=Matt myfile.txt`. It will not attempt to interpret
-those arguments or modify them in any way.
+Glide will interpret this as a request to execute `glide-foo` with the arguments `-name=Matt myfile.txt`. It will not attempt to interpret those arguments or modify them in any way.
 
-Hypothetically, if Glide had a `-x` flag of its own, you could call
-this:
+Hypothetically, if Glide had a `-x` flag of its own, you could call this:
 
 ```
 $ glide -x foo -name=Matt myfile.txt
 ```
 
-In this case, glide would interpret and swollow the -x and pass the rest
-on to glide-foo as in the example above.
-
-### Environment Variables
-
-When Glide executes a plugin, it passes through all of its environment
-variables, including...
-
-- GOPATH: Gopath
-- PATH: Executable paths
-- GLIDE_GOPATH: Gopath (in case GOPATH gets overridden by another
-  script)
-- GLIDE_PROJECT: The path to the project
-- GLIDE_YAML: The path to the project's YAML
-- ALREADY_GLIDING: 1 if we are in a `glide in` session.
+In this case, glide would interpret and swollow the -x and pass the rest on to `glide-foo` as in the example above.
 
 ## Example Plugin
 
@@ -84,5 +70,3 @@
 
 echo "Hello"
 ```
-
-Yup, that's it. Also see `glide-example-plugin` for a bigger example.
diff --git a/docs/versions.md b/docs/versions.md
index a323fb2..047a5ce 100644
--- a/docs/versions.md
+++ b/docs/versions.md
@@ -27,7 +27,7 @@
 
 * `1.2.x` is equivalent to `>= 1.2.0, < 1.3.0`
 * `>= 1.2.x` is equivalent to `>= 1.2.0`
-* `<= 2.x` is equivalent to `<= 3`
+* `<= 2.x` is equivalent to `< 3`
 * `*` is equivalent to `>= 0.0.0`
 
 ## Tilde Range Comparisons (Patch)
diff --git a/glide.lock b/glide.lock
index 572094a..c869e2f 100644
--- a/glide.lock
+++ b/glide.lock
@@ -1,12 +1,12 @@
-hash: ebc39e5b2036ba2235316f2897fb9f2e696c6a7d5389416812722cc8ed3dfa21
-updated: 2016-06-10T16:27:29.24243625-04:00
+hash: 0653c17bcbf6f1df79990f3d2211dbcbc920ca528c513b00f5cab0a508c984ab
+updated: 2016-06-30T10:51:49.633776379-04:00
 imports:
 - name: github.com/codegangsta/cli
   version: 71f57d300dd6a780ac1856c005c4b518cfd498ec
 - name: github.com/Masterminds/semver
-  version: 808ed7761c233af2de3f9729a041d68c62527f3a
+  version: 8d0431362b544d1a3536cca26684828866a7de09
 - name: github.com/Masterminds/vcs
-  version: 7af28b64c5ec41b1558f5514fd938379822c237c
+  version: fbe9fb6ad5b5f35b3e82a7c21123cfc526cbf895
 - name: gopkg.in/yaml.v2
   version: a83829b6f1293c91addabc89d0571c246397bbf4
 testImports: []
diff --git a/glide.yaml b/glide.yaml
index a8c5b4a..dfc97e9 100644
--- a/glide.yaml
+++ b/glide.yaml
@@ -11,8 +11,8 @@
 import:
 - package: gopkg.in/yaml.v2
 - package: github.com/Masterminds/vcs
-  version: ^1.7.0
+  version: ^1.8.0
 - package: github.com/codegangsta/cli
   version: ~1.14.0
 - package: github.com/Masterminds/semver
-  version: ^1.0.0
+  version: ^1.1.1
diff --git a/godep/strip/strip.go b/godep/strip/strip.go
index e70d607..39d54e1 100644
--- a/godep/strip/strip.go
+++ b/godep/strip/strip.go
@@ -82,11 +82,11 @@
 
 func rewriteGodepfilesHandler(path string, info os.FileInfo, err error) error {
 	name := info.Name()
-	if name == "testdata" || name == "vendor" {
-		return filepath.SkipDir
-	}
 
 	if info.IsDir() {
+		if name == "testdata" || name == "vendor" {
+			return filepath.SkipDir
+		}
 		return nil
 	}
 
diff --git a/gom/parser.go b/gom/parser.go
index bf54f61..3bcd9e0 100644
--- a/gom/parser.go
+++ b/gom/parser.go
@@ -16,10 +16,10 @@
 var qx = `'[^']*'|"[^"]*"`
 var kx = `:[a-z][a-z0-9_]*`
 var ax = `(?:\s*` + kx + `\s*|,\s*` + kx + `\s*)`
-var re_group = regexp.MustCompile(`\s*group\s+((?:` + kx + `\s*|,\s*` + kx + `\s*)*)\s*do\s*$`)
-var re_end = regexp.MustCompile(`\s*end\s*$`)
-var re_gom = regexp.MustCompile(`^\s*gom\s+(` + qx + `)\s*((?:,\s*` + kx + `\s*=>\s*(?:` + qx + `|\s*\[\s*` + ax + `*\s*\]\s*))*)$`)
-var re_options = regexp.MustCompile(`(,\s*` + kx + `\s*=>\s*(?:` + qx + `|\s*\[\s*` + ax + `*\s*\]\s*)\s*)`)
+var reGroup = regexp.MustCompile(`\s*group\s+((?:` + kx + `\s*|,\s*` + kx + `\s*)*)\s*do\s*$`)
+var reEnd = regexp.MustCompile(`\s*end\s*$`)
+var reGom = regexp.MustCompile(`^\s*gom\s+(` + qx + `)\s*((?:,\s*` + kx + `\s*=>\s*(?:` + qx + `|\s*\[\s*` + ax + `*\s*\]\s*))*)$`)
+var reOptions = regexp.MustCompile(`(,\s*` + kx + `\s*=>\s*(?:` + qx + `|\s*\[\s*` + ax + `*\s*\]\s*)\s*)`)
 
 func unquote(name string) string {
 	name = strings.TrimSpace(name)
@@ -32,13 +32,13 @@
 }
 
 func parseOptions(line string, options map[string]interface{}) {
-	ss := re_options.FindAllStringSubmatch(line, -1)
-	re_a := regexp.MustCompile(ax)
+	ss := reOptions.FindAllStringSubmatch(line, -1)
+	reA := regexp.MustCompile(ax)
 	for _, s := range ss {
 		kvs := strings.SplitN(strings.TrimSpace(s[0])[1:], "=>", 2)
 		kvs[0], kvs[1] = strings.TrimSpace(kvs[0]), strings.TrimSpace(kvs[1])
 		if kvs[1][0] == '[' {
-			as := re_a.FindAllStringSubmatch(kvs[1][1:len(kvs[1])-1], -1)
+			as := reA.FindAllStringSubmatch(kvs[1][1:len(kvs[1])-1], -1)
 			a := []string{}
 			for i := range as {
 				it := strings.TrimSpace(as[i][0])
@@ -57,6 +57,7 @@
 	}
 }
 
+// Gom represents configuration from Gom.
 type Gom struct {
 	name    string
 	options map[string]interface{}
@@ -95,14 +96,14 @@
 		name := ""
 		options := make(map[string]interface{})
 		var items []string
-		if re_group.MatchString(line) {
-			envs = strings.Split(re_group.FindStringSubmatch(line)[1], ",")
+		if reGroup.MatchString(line) {
+			envs = strings.Split(reGroup.FindStringSubmatch(line)[1], ",")
 			for i := range envs {
 				envs[i] = strings.TrimSpace(envs[i])[1:]
 			}
 			valid = true
 			continue
-		} else if re_end.MatchString(line) {
+		} else if reEnd.MatchString(line) {
 			if !valid {
 				skip--
 				if skip < 0 {
@@ -114,8 +115,8 @@
 			continue
 		} else if skip > 0 {
 			continue
-		} else if re_gom.MatchString(line) {
-			items = re_gom.FindStringSubmatch(line)[1:]
+		} else if reGom.MatchString(line) {
+			items = reGom.FindStringSubmatch(line)[1:]
 			name = unquote(items[0])
 			parseOptions(items[1], options)
 		} else {
@@ -126,5 +127,4 @@
 		}
 		goms = append(goms, Gom{name, options})
 	}
-	return goms, nil
-}
\ No newline at end of file
+}
diff --git a/mkdocs.yml b/mkdocs.yml
index 29109e0..6d6764b 100644
--- a/mkdocs.yml
+++ b/mkdocs.yml
@@ -8,5 +8,6 @@
 - Commands: commands.md
 - Resolving Imports: resolving-imports.md
 - Vendor Directories: vendor.md
+- Plugins: plugins.md
 - F.A.Q.: faq.md
 theme: readthedocs
diff --git a/msg/msg.go b/msg/msg.go
index 34213fd..8b0f077 100644
--- a/msg/msg.go
+++ b/msg/msg.go
@@ -7,6 +7,8 @@
 	"os"
 	"strings"
 	"sync"
+
+	"github.com/Masterminds/vcs"
 )
 
 // Messenger provides the underlying implementation that displays output to
@@ -176,7 +178,6 @@
 	// locked to avoid displaying one message in the middle of another one.
 	m.Lock()
 	defer m.Unlock()
-
 	// Get rid of the annoying fact that messages need \n at the end, but do
 	// it in a backward compatible way.
 	if !strings.HasSuffix(msg, "\n") {
@@ -188,6 +189,21 @@
 	} else {
 		fmt.Fprintf(m.Stderr, msg, args...)
 	}
+
+	// If an arg is a vcs error print the output if in debug mode. This is
+	// capured here rather than calling Debug because concurrent operations
+	// could cause other messages to appear between the initial error and the
+	// debug output by unlocking and calling Debug.
+	if len(args) != 0 && !m.Quiet && m.IsDebugging {
+		if err, ok := args[len(args)-1].(error); ok {
+			switch t := err.(type) {
+			case *vcs.LocalError:
+				fmt.Fprintf(m.Stderr, "[DEBUG]\tOutput was: %s", strings.TrimSpace(t.Out()))
+			case *vcs.RemoteError:
+				fmt.Fprintf(m.Stderr, "[DEBUG]\tOutput was: %s", strings.TrimSpace(t.Out()))
+			}
+		}
+	}
 }
 
 // Msg prints a message with optional arguments, that can be printed, of
diff --git a/repo/installer.go b/repo/installer.go
index 6f4b2d0..13d3fb0 100644
--- a/repo/installer.go
+++ b/repo/installer.go
@@ -58,6 +58,7 @@
 	Updated *UpdateTracker
 }
 
+// NewInstaller returns an Installer instance ready to use. This is the constructor.
 func NewInstaller() *Installer {
 	i := &Installer{}
 	i.Updated = NewUpdateTracker()
@@ -93,28 +94,12 @@
 
 	newConf.Imports = make(cfg.Dependencies, len(lock.Imports))
 	for k, v := range lock.Imports {
-		newConf.Imports[k] = &cfg.Dependency{
-			Name:        v.Name,
-			Reference:   v.Version,
-			Repository:  v.Repository,
-			VcsType:     v.VcsType,
-			Subpackages: v.Subpackages,
-			Arch:        v.Arch,
-			Os:          v.Os,
-		}
+		newConf.Imports[k] = cfg.DependencyFromLock(v)
 	}
 
 	newConf.DevImports = make(cfg.Dependencies, len(lock.DevImports))
 	for k, v := range lock.DevImports {
-		newConf.DevImports[k] = &cfg.Dependency{
-			Name:        v.Name,
-			Reference:   v.Version,
-			Repository:  v.Repository,
-			VcsType:     v.VcsType,
-			Subpackages: v.Subpackages,
-			Arch:        v.Arch,
-			Os:          v.Os,
-		}
+		newConf.DevImports[k] = cfg.DependencyFromLock(v)
 	}
 
 	newConf.DeDupe()
@@ -126,8 +111,8 @@
 
 	msg.Info("Downloading dependencies. Please wait...")
 
-	ConcurrentUpdate(newConf.Imports, cwd, i, newConf)
-	ConcurrentUpdate(newConf.DevImports, cwd, i, newConf)
+	LazyConcurrentUpdate(newConf.Imports, cwd, i, newConf)
+	LazyConcurrentUpdate(newConf.DevImports, cwd, i, newConf)
 	return newConf, nil
 }
 
@@ -207,6 +192,9 @@
 	var tdeps cfg.Dependencies
 	for _, v := range imps {
 		n := res.Stripv(v)
+		if conf.HasIgnore(n) {
+			continue
+		}
 		rt, sub := util.NormalizeName(n)
 		if sub == "" {
 			sub = "."
@@ -225,6 +213,9 @@
 	if i.ResolveTest {
 		for _, v := range timps {
 			n := res.Stripv(v)
+			if conf.HasIgnore(n) {
+				continue
+			}
 			rt, sub := util.NormalizeName(n)
 			if sub == "" {
 				sub = "."
@@ -317,6 +308,43 @@
 	return conf.Imports
 }
 
+// LazyConcurrentUpdate updates only deps that are not already checkout out at the right version.
+//
+// This is only safe when updating from a lock file.
+func LazyConcurrentUpdate(deps []*cfg.Dependency, cwd string, i *Installer, c *cfg.Config) error {
+
+	newDeps := []*cfg.Dependency{}
+	for _, dep := range deps {
+		destPath := filepath.Join(i.VendorPath(), dep.Name)
+
+		// Get a VCS object for this directory
+		repo, err := dep.GetRepo(destPath)
+		if err != nil {
+			newDeps = append(newDeps, dep)
+			continue
+		}
+
+		ver, err := repo.Version()
+		if err != nil {
+			newDeps = append(newDeps, dep)
+			continue
+		}
+
+		if ver == dep.Reference {
+			msg.Info("--> Found desired version %s %s!", dep.Name, dep.Reference)
+			continue
+		}
+
+		msg.Debug("--> Queue %s for update (%s != %s).", dep.Name, ver, dep.Reference)
+		newDeps = append(newDeps, dep)
+	}
+	if len(newDeps) > 0 {
+		return ConcurrentUpdate(newDeps, cwd, i, c)
+	}
+
+	return nil
+}
+
 // ConcurrentUpdate takes a list of dependencies and updates in parallel.
 func ConcurrentUpdate(deps []*cfg.Dependency, cwd string, i *Installer, c *cfg.Config) error {
 	done := make(chan struct{}, concurrentWorkers)
diff --git a/repo/vcs.go b/repo/vcs.go
index 31bed50..3f5f80d 100644
--- a/repo/vcs.go
+++ b/repo/vcs.go
@@ -203,14 +203,14 @@
 		}
 
 		ver := dep.Reference
-		// Referenes in Git can begin with a ^ which is similar to semver.
+		// References in Git can begin with a ^ which is similar to semver.
 		// If there is a ^ prefix we assume it's a semver constraint rather than
 		// part of the git/VCS commit id.
 		if repo.IsReference(ver) && !strings.HasPrefix(ver, "^") {
 			msg.Info("--> Setting version for %s to %s.\n", dep.Name, ver)
 		} else {
 
-			// Create the constraing first to make sure it's valid before
+			// Create the constraint first to make sure it's valid before
 			// working on the repo.
 			constraint, err := semver.NewConstraint(ver)
 
diff --git a/vendor/github.com/Masterminds/semver/CHANGELOG.md b/vendor/github.com/Masterminds/semver/CHANGELOG.md
index 2382b75..c3808ea 100644
--- a/vendor/github.com/Masterminds/semver/CHANGELOG.md
+++ b/vendor/github.com/Masterminds/semver/CHANGELOG.md
@@ -1,4 +1,13 @@
-# Release 1.1.0 (2015-03-11)
+# Release 1.1.1 (2016-06-30)
+
+## Changed
+- Issue #9: Speed up version comparison performance (thanks @sdboyer)
+- Issue #8: Added benchmarks (thanks @sdboyer)
+- Updated Go Report Card URL to new location
+- Updated Readme to add code snippet formatting (thanks @mh-cbon)
+- Updating tagging to v[SemVer] structure for compatibility with other tools.
+
+# Release 1.1.0 (2016-03-11)
 
 - Issue #2: Implemented validation to provide reasons a versions failed a
   constraint.
diff --git a/vendor/github.com/Masterminds/semver/README.md b/vendor/github.com/Masterminds/semver/README.md
index aa133ea..1edec7a 100644
--- a/vendor/github.com/Masterminds/semver/README.md
+++ b/vendor/github.com/Masterminds/semver/README.md
@@ -7,13 +7,15 @@
 * Check if a semantic version fits within a set of constraints
 * Optionally work with a `v` prefix
 
-[![Build Status](https://travis-ci.org/Masterminds/semver.svg)](https://travis-ci.org/Masterminds/semver) [![Build status](https://ci.appveyor.com/api/projects/status/jfk66lib7hb985k8/branch/master?svg=true&passingText=windows%20build%20passing&failingText=windows%20build%20failing)](https://ci.appveyor.com/project/mattfarina/semver/branch/master) [![GoDoc](https://godoc.org/github.com/Masterminds/semver?status.png)](https://godoc.org/github.com/Masterminds/semver) [![Go Report Card](http://goreportcard.com/badge/Masterminds/semver)](http://goreportcard.com/report/Masterminds/semver)
+[![Build Status](https://travis-ci.org/Masterminds/semver.svg)](https://travis-ci.org/Masterminds/semver) [![Build status](https://ci.appveyor.com/api/projects/status/jfk66lib7hb985k8/branch/master?svg=true&passingText=windows%20build%20passing&failingText=windows%20build%20failing)](https://ci.appveyor.com/project/mattfarina/semver/branch/master) [![GoDoc](https://godoc.org/github.com/Masterminds/semver?status.png)](https://godoc.org/github.com/Masterminds/semver) [![Go Report Card](https://goreportcard.com/badge/github.com/Masterminds/semver)](https://goreportcard.com/report/github.com/Masterminds/semver)
 
 ## Parsing Semantic Versions
 
 To parse a semantic version use the `NewVersion` function. For example,
 
+```go
     v, err := semver.NewVersion("1.2.3-beta.1+build345")
+```
 
 If there is an error the version wasn't parseable. The version object has methods
 to get the parts of the version, compare it to other versions, convert the
@@ -25,6 +27,7 @@
 A set of versions can be sorted using the [`sort`](https://golang.org/pkg/sort/)
 package from the standard library. For example,
 
+```go
     raw := []string{"1.2.3", "1.0", "1.3", "2", "0.4.2",}
     vs := make([]*semver.Version, len(raw))
 	for i, r := range raw {
@@ -37,12 +40,14 @@
 	}
 
 	sort.Sort(semver.Collection(vs))
+```
 
 ## Checking Version Constraints
 
 Checking a version against version constraints is one of the most featureful
 parts of the package.
 
+```go
     c, err := semver.NewConstraint(">= 1.2.3")
     if err != nil {
         // Handle constraint not being parseable.
@@ -54,6 +59,7 @@
     }
     // Check if the version meets the constraints. The a variable will be true.
     a := c.Check(v)
+```
 
 ## Basic Comparisons
 
@@ -119,6 +125,7 @@
 against a constraint. When validation fails a slice of errors containing why a
 version didn't meet the constraint is returned. For example,
 
+```go
     c, err := semver.NewConstraint("<= 1.2.3, >= 1.4")
     if err != nil {
         // Handle constraint not being parseable.
@@ -139,6 +146,7 @@
         // "1.3 is greater than 1.2.3"
         // "1.3 is less than 1.4"
     }
+```
 
 # Contribute
 
diff --git a/vendor/github.com/Masterminds/semver/benchmark_test.go b/vendor/github.com/Masterminds/semver/benchmark_test.go
new file mode 100644
index 0000000..58a5c28
--- /dev/null
+++ b/vendor/github.com/Masterminds/semver/benchmark_test.go
@@ -0,0 +1,157 @@
+package semver_test
+
+import (
+	"testing"
+
+	"github.com/Masterminds/semver"
+)
+
+/* Constraint creation benchmarks */
+
+func benchNewConstraint(c string, b *testing.B) {
+	for i := 0; i < b.N; i++ {
+		semver.NewConstraint(c)
+	}
+}
+
+func BenchmarkNewConstraintUnary(b *testing.B) {
+	benchNewConstraint("=2.0", b)
+}
+
+func BenchmarkNewConstraintTilde(b *testing.B) {
+	benchNewConstraint("~2.0.0", b)
+}
+
+func BenchmarkNewConstraintCaret(b *testing.B) {
+	benchNewConstraint("^2.0.0", b)
+}
+
+func BenchmarkNewConstraintWildcard(b *testing.B) {
+	benchNewConstraint("1.x", b)
+}
+
+func BenchmarkNewConstraintRange(b *testing.B) {
+	benchNewConstraint(">=2.1.x, <3.1.0", b)
+}
+
+func BenchmarkNewConstraintUnion(b *testing.B) {
+	benchNewConstraint("~2.0.0 || =3.1.0", b)
+}
+
+/* Check benchmarks */
+
+func benchCheckVersion(c, v string, b *testing.B) {
+	version, _ := semver.NewVersion(v)
+	constraint, _ := semver.NewConstraint(c)
+
+	for i := 0; i < b.N; i++ {
+		constraint.Check(version)
+	}
+}
+
+func BenchmarkCheckVersionUnary(b *testing.B) {
+	benchCheckVersion("=2.0", "2.0.0", b)
+}
+
+func BenchmarkCheckVersionTilde(b *testing.B) {
+	benchCheckVersion("~2.0.0", "2.0.5", b)
+}
+
+func BenchmarkCheckVersionCaret(b *testing.B) {
+	benchCheckVersion("^2.0.0", "2.1.0", b)
+}
+
+func BenchmarkCheckVersionWildcard(b *testing.B) {
+	benchCheckVersion("1.x", "1.4.0", b)
+}
+
+func BenchmarkCheckVersionRange(b *testing.B) {
+	benchCheckVersion(">=2.1.x, <3.1.0", "2.4.5", b)
+}
+
+func BenchmarkCheckVersionUnion(b *testing.B) {
+	benchCheckVersion("~2.0.0 || =3.1.0", "3.1.0", b)
+}
+
+func benchValidateVersion(c, v string, b *testing.B) {
+	version, _ := semver.NewVersion(v)
+	constraint, _ := semver.NewConstraint(c)
+
+	for i := 0; i < b.N; i++ {
+		constraint.Validate(version)
+	}
+}
+
+/* Validate benchmarks, including fails */
+
+func BenchmarkValidateVersionUnary(b *testing.B) {
+	benchValidateVersion("=2.0", "2.0.0", b)
+}
+
+func BenchmarkValidateVersionUnaryFail(b *testing.B) {
+	benchValidateVersion("=2.0", "2.0.1", b)
+}
+
+func BenchmarkValidateVersionTilde(b *testing.B) {
+	benchValidateVersion("~2.0.0", "2.0.5", b)
+}
+
+func BenchmarkValidateVersionTildeFail(b *testing.B) {
+	benchValidateVersion("~2.0.0", "1.0.5", b)
+}
+
+func BenchmarkValidateVersionCaret(b *testing.B) {
+	benchValidateVersion("^2.0.0", "2.1.0", b)
+}
+
+func BenchmarkValidateVersionCaretFail(b *testing.B) {
+	benchValidateVersion("^2.0.0", "4.1.0", b)
+}
+
+func BenchmarkValidateVersionWildcard(b *testing.B) {
+	benchValidateVersion("1.x", "1.4.0", b)
+}
+
+func BenchmarkValidateVersionWildcardFail(b *testing.B) {
+	benchValidateVersion("1.x", "2.4.0", b)
+}
+
+func BenchmarkValidateVersionRange(b *testing.B) {
+	benchValidateVersion(">=2.1.x, <3.1.0", "2.4.5", b)
+}
+
+func BenchmarkValidateVersionRangeFail(b *testing.B) {
+	benchValidateVersion(">=2.1.x, <3.1.0", "1.4.5", b)
+}
+
+func BenchmarkValidateVersionUnion(b *testing.B) {
+	benchValidateVersion("~2.0.0 || =3.1.0", "3.1.0", b)
+}
+
+func BenchmarkValidateVersionUnionFail(b *testing.B) {
+	benchValidateVersion("~2.0.0 || =3.1.0", "3.1.1", b)
+}
+
+/* Version creation benchmarks */
+
+func benchNewVersion(v string, b *testing.B) {
+	for i := 0; i < b.N; i++ {
+		semver.NewVersion(v)
+	}
+}
+
+func BenchmarkNewVersionSimple(b *testing.B) {
+	benchNewVersion("1.0.0", b)
+}
+
+func BenchmarkNewVersionPre(b *testing.B) {
+	benchNewVersion("1.0.0-alpha", b)
+}
+
+func BenchmarkNewVersionMeta(b *testing.B) {
+	benchNewVersion("1.0.0+metadata", b)
+}
+
+func BenchmarkNewVersionMetaDash(b *testing.B) {
+	benchNewVersion("1.0.0+metadata-dash", b)
+}
diff --git a/vendor/github.com/Masterminds/semver/constraints.go b/vendor/github.com/Masterminds/semver/constraints.go
index 9a5e9da..b63f5f6 100644
--- a/vendor/github.com/Masterminds/semver/constraints.go
+++ b/vendor/github.com/Masterminds/semver/constraints.go
@@ -312,8 +312,6 @@
 	return true
 }
 
-type rwfunc func(i string) string
-
 var constraintRangeRegex *regexp.Regexp
 
 const cvRegex string = `v?([0-9|x|X|\*]+)(\.[0-9|x|X|\*]+)?(\.[0-9|x|X|\*]+)?` +
@@ -321,8 +319,12 @@
 	`(\+([0-9A-Za-z\-]+(\.[0-9A-Za-z\-]+)*))?`
 
 func isX(x string) bool {
-	l := strings.ToLower(x)
-	return l == "x" || l == "*"
+	switch x {
+	case "x", "*", "X":
+		return true
+	default:
+		return false
+	}
 }
 
 func rewriteRange(i string) string {
diff --git a/vendor/github.com/Masterminds/semver/version.go b/vendor/github.com/Masterminds/semver/version.go
index 75dbbc0..dbb93f8 100644
--- a/vendor/github.com/Masterminds/semver/version.go
+++ b/vendor/github.com/Masterminds/semver/version.go
@@ -152,12 +152,6 @@
 // Versions are compared by X.Y.Z. Build metadata is ignored. Prerelease is
 // lower than the version without a prerelease.
 func (v *Version) Compare(o *Version) int {
-
-	// Fastpath if both versions are the same.
-	if v.String() == o.String() {
-		return 0
-	}
-
 	// Compare the major, minor, and patch version for differences. If a
 	// difference is found return the comparison.
 	if d := compareSegment(v.Major(), o.Major()); d != 0 {
diff --git a/vendor/github.com/Masterminds/vcs/.travis.yml b/vendor/github.com/Masterminds/vcs/.travis.yml
index a8c32da..5c50c4a 100644
--- a/vendor/github.com/Masterminds/vcs/.travis.yml
+++ b/vendor/github.com/Masterminds/vcs/.travis.yml
@@ -18,4 +18,9 @@
 sudo: false
 
 notifications:
-  irc: "irc.freenode.net#masterminds"
+  webhooks:
+    urls:
+      - https://webhooks.gitter.im/e/06e3328629952dabe3e0
+    on_success: change  # options: [always|never|change] default: always
+    on_failure: always  # options: [always|never|change] default: always
+    on_start: never     # options: [always|never|change] default: always
diff --git a/vendor/github.com/Masterminds/vcs/CHANGELOG.md b/vendor/github.com/Masterminds/vcs/CHANGELOG.md
index d178685..6362674 100644
--- a/vendor/github.com/Masterminds/vcs/CHANGELOG.md
+++ b/vendor/github.com/Masterminds/vcs/CHANGELOG.md
@@ -1,4 +1,18 @@
-1.7.0 (2016-05-05)
+# 1.8.0 (2016-06-29)
+
+## Added
+- #43: Detect when tool (e.g., git, svn, etc) not installed
+- #49: Detect access denied and not found situations
+
+## Changed
+- #48: Updated Go Report Gard url to new format
+- Refactored SVN handling to detect when not in a top level directory
+- Updating tagging to v[SemVer] structure for compatibility with other tools.
+
+## Fixed
+- #45: Fixed hg's update method so that it pulls from remote before updates
+
+# 1.7.0 (2016-05-05)
 
 - Adds a glide.yaml file with some limited information.
 - Implements #37: Ability to export source as a directory.
diff --git a/vendor/github.com/Masterminds/vcs/README.md b/vendor/github.com/Masterminds/vcs/README.md
index 6025f2d..cdb981f 100644
--- a/vendor/github.com/Masterminds/vcs/README.md
+++ b/vendor/github.com/Masterminds/vcs/README.md
@@ -3,7 +3,7 @@
 Manage repos in varying version control systems with ease through a common
 interface.
 
-[![Build Status](https://travis-ci.org/Masterminds/vcs.svg)](https://travis-ci.org/Masterminds/vcs) [![GoDoc](https://godoc.org/github.com/Masterminds/vcs?status.png)](https://godoc.org/github.com/Masterminds/vcs) [![Go Report Card](http://goreportcard.com/badge/Masterminds/vcs)](http://goreportcard.com/report/Masterminds/vcs)
+[![Build Status](https://travis-ci.org/Masterminds/vcs.svg)](https://travis-ci.org/Masterminds/vcs) [![GoDoc](https://godoc.org/github.com/Masterminds/vcs?status.png)](https://godoc.org/github.com/Masterminds/vcs) [![Go Report Card](https://goreportcard.com/badge/github.com/Masterminds/vcs)](https://goreportcard.com/report/github.com/Masterminds/vcs)
 
 ## Quick Usage
 
diff --git a/vendor/github.com/Masterminds/vcs/bzr.go b/vendor/github.com/Masterminds/vcs/bzr.go
index a62451f..e8f55b6 100644
--- a/vendor/github.com/Masterminds/vcs/bzr.go
+++ b/vendor/github.com/Masterminds/vcs/bzr.go
@@ -16,6 +16,10 @@
 // NewBzrRepo creates a new instance of BzrRepo. The remote and local directories
 // need to be passed in.
 func NewBzrRepo(remote, local string) (*BzrRepo, error) {
+	ins := depInstalled("bzr")
+	if !ins {
+		return nil, NewLocalError("bzr is not installed", nil, "")
+	}
 	ltype, err := DetectVcsFromFS(local)
 
 	// Found a VCS other than Bzr. Need to report an error.
diff --git a/vendor/github.com/Masterminds/vcs/git.go b/vendor/github.com/Masterminds/vcs/git.go
index 778b6af..eb4b86e 100644
--- a/vendor/github.com/Masterminds/vcs/git.go
+++ b/vendor/github.com/Masterminds/vcs/git.go
@@ -14,6 +14,10 @@
 // NewGitRepo creates a new instance of GitRepo. The remote and local directories
 // need to be passed in.
 func NewGitRepo(remote, local string) (*GitRepo, error) {
+	ins := depInstalled("git")
+	if !ins {
+		return nil, NewLocalError("git is not installed", nil, "")
+	}
 	ltype, err := DetectVcsFromFS(local)
 
 	// Found a VCS other than Git. Need to report an error.
diff --git a/vendor/github.com/Masterminds/vcs/hg.go b/vendor/github.com/Masterminds/vcs/hg.go
index 0d7a994..df41cd6 100644
--- a/vendor/github.com/Masterminds/vcs/hg.go
+++ b/vendor/github.com/Masterminds/vcs/hg.go
@@ -14,6 +14,10 @@
 // NewHgRepo creates a new instance of HgRepo. The remote and local directories
 // need to be passed in.
 func NewHgRepo(remote, local string) (*HgRepo, error) {
+	ins := depInstalled("hg")
+	if !ins {
+		return nil, NewLocalError("hg is not installed", nil, "")
+	}
 	ltype, err := DetectVcsFromFS(local)
 
 	// Found a VCS other than Hg. Need to report an error.
@@ -84,11 +88,7 @@
 
 // Update performs a Mercurial pull to an existing checkout.
 func (s *HgRepo) Update() error {
-	out, err := s.RunFromDir("hg", "update")
-	if err != nil {
-		return NewRemoteError("Unable to update repository", err, string(out))
-	}
-	return nil
+	return s.UpdateVersion(``)
 }
 
 // UpdateVersion sets the version of a package currently checked out via Hg.
@@ -97,7 +97,11 @@
 	if err != nil {
 		return NewLocalError("Unable to update checked out version", err, string(out))
 	}
-	out, err = s.RunFromDir("hg", "update", version)
+	if len(strings.TrimSpace(version)) > 0 {
+		out, err = s.RunFromDir("hg", "update", version)
+	} else {
+		out, err = s.RunFromDir("hg", "update")
+	}
 	if err != nil {
 		return NewLocalError("Unable to update checked out version", err, string(out))
 	}
diff --git a/vendor/github.com/Masterminds/vcs/repo.go b/vendor/github.com/Masterminds/vcs/repo.go
index 99bc2d2..1298a5f 100644
--- a/vendor/github.com/Masterminds/vcs/repo.go
+++ b/vendor/github.com/Masterminds/vcs/repo.go
@@ -257,3 +257,11 @@
 	}
 	return out
 }
+
+func depInstalled(name string) bool {
+	if _, err := exec.LookPath(name); err != nil {
+		return false
+	}
+
+	return true
+}
diff --git a/vendor/github.com/Masterminds/vcs/repo_test.go b/vendor/github.com/Masterminds/vcs/repo_test.go
index 12f63f5..d61f6cb 100644
--- a/vendor/github.com/Masterminds/vcs/repo_test.go
+++ b/vendor/github.com/Masterminds/vcs/repo_test.go
@@ -60,3 +60,15 @@
 		t.Errorf("Not detecting repo switch from SVN to Git")
 	}
 }
+
+func TestDepInstalled(t *testing.T) {
+	i := depInstalled("git")
+	if i != true {
+		t.Error("depInstalled not finding installed dep.")
+	}
+
+	i = depInstalled("thisreallyisntinstalled")
+	if i != false {
+		t.Error("depInstalled finding not installed dep.")
+	}
+}
diff --git a/vendor/github.com/Masterminds/vcs/svn.go b/vendor/github.com/Masterminds/vcs/svn.go
index 48d089b..888ae09 100644
--- a/vendor/github.com/Masterminds/vcs/svn.go
+++ b/vendor/github.com/Masterminds/vcs/svn.go
@@ -2,21 +2,23 @@
 
 import (
 	"encoding/xml"
+	"fmt"
 	"os"
 	"os/exec"
 	"path/filepath"
-	"regexp"
 	"strings"
 	"time"
 )
 
-var svnDetectURL = regexp.MustCompile("URL: (?P<foo>.+)\n")
-
 // NewSvnRepo creates a new instance of SvnRepo. The remote and local directories
 // need to be passed in. The remote location should include the branch for SVN.
 // For example, if the package is https://github.com/Masterminds/cookoo/ the remote
 // should be https://github.com/Masterminds/cookoo/trunk for the trunk branch.
 func NewSvnRepo(remote, local string) (*SvnRepo, error) {
+	ins := depInstalled("svn")
+	if !ins {
+		return nil, NewLocalError("svn is not installed", nil, "")
+	}
 	ltype, err := DetectVcsFromFS(local)
 
 	// Found a VCS other than Svn. Need to report an error.
@@ -39,15 +41,18 @@
 			return nil, NewLocalError("Unable to retrieve local repo information", err, string(out))
 		}
 
-		m := svnDetectURL.FindStringSubmatch(string(out))
-		if m[1] != "" && m[1] != remote {
+		detectedRemote, err := detectRemoteFromInfoCommand(string(out))
+		if err != nil {
+			return nil, NewLocalError("Unable to retrieve local repo information", err, string(out))
+		}
+		if detectedRemote != "" && remote != "" && detectedRemote != remote {
 			return nil, ErrWrongRemote
 		}
 
 		// If no remote was passed in but one is configured for the locally
 		// checked out Svn repo use that one.
-		if remote == "" && m[1] != "" {
-			r.setRemote(m[1])
+		if remote == "" && detectedRemote != "" {
+			r.setRemote(detectedRemote)
 		}
 	}
 
@@ -185,12 +190,15 @@
 
 // CheckLocal verifies the local location is an SVN repo.
 func (s *SvnRepo) CheckLocal() bool {
-	if _, err := os.Stat(s.LocalPath() + "/.svn"); err == nil {
-		return true
+	sep := fmt.Sprintf("%c", os.PathSeparator)
+	psplit := strings.Split(s.LocalPath(), sep)
+	for i := 0; i < len(psplit); i++ {
+		path := fmt.Sprintf("%s%s", sep, filepath.Join(psplit[0:(len(psplit)-(i))]...))
+		if _, err := os.Stat(filepath.Join(path, ".svn")); err == nil {
+			return true
+		}
 	}
-
 	return false
-
 }
 
 // Tags returns []string{} as there are no formal tags in SVN. Tags are a
@@ -344,3 +352,24 @@
 
 	return false
 }
+
+// detectRemoteFromInfoCommand finds the remote url from the `svn info`
+// command's output without using  a regex. We avoid regex because URLs
+// are notoriously complex to accurately match with a regex and
+// splitting strings is less complex and often faster
+func detectRemoteFromInfoCommand(infoOut string) (string, error) {
+	sBytes := []byte(infoOut)
+	urlIndex := strings.Index(infoOut, "URL: ")
+	if urlIndex == -1 {
+		return "", fmt.Errorf("Remote not specified in svn info")
+	}
+	urlEndIndex := strings.Index(string(sBytes[urlIndex:]), "\n")
+	if urlEndIndex == -1 {
+		urlEndIndex = strings.Index(string(sBytes[urlIndex:]), "\r")
+		if urlEndIndex == -1 {
+			return "", fmt.Errorf("Unable to parse remote URL for svn info")
+		}
+	}
+
+	return string(sBytes[(urlIndex + 5):(urlIndex + urlEndIndex)]), nil
+}
diff --git a/vendor/github.com/Masterminds/vcs/vcs_remote_lookup.go b/vendor/github.com/Masterminds/vcs/vcs_remote_lookup.go
index 85fac7f..0567af8 100644
--- a/vendor/github.com/Masterminds/vcs/vcs_remote_lookup.go
+++ b/vendor/github.com/Masterminds/vcs/vcs_remote_lookup.go
@@ -88,6 +88,8 @@
 	t, e := detectVcsFromURL(vcsURL)
 	if e == nil {
 		return t, vcsURL, nil
+	} else if e != ErrCannotDetectVCS {
+		return NoVCS, "", e
 	}
 
 	// Pages like https://golang.org/x/net provide an html document with
@@ -114,6 +116,11 @@
 	}
 	defer resp.Body.Close()
 	if resp.StatusCode < 200 || resp.StatusCode >= 300 {
+		if resp.StatusCode == 404 {
+			return NoVCS, "", NewRemoteError(fmt.Sprintf("%s Not Found", vcsURL), nil, "")
+		} else if resp.StatusCode == 401 || resp.StatusCode == 403 {
+			return NoVCS, "", NewRemoteError(fmt.Sprintf("%s Access Denied", vcsURL), nil, "")
+		}
 		return NoVCS, "", ErrCannotDetectVCS
 	}
 
@@ -202,6 +209,10 @@
 		}
 		t, err := v.addCheck(info, u)
 		if err != nil {
+			switch err.(type) {
+			case *RemoteError:
+				return "", err
+			}
 			return "", ErrCannotDetectVCS
 		}
 
@@ -299,7 +310,11 @@
 	}
 	defer resp.Body.Close()
 	if resp.StatusCode != 200 {
-		// TODO(mattfarina): log the failed status
+		if resp.StatusCode == 404 {
+			return nil, NewRemoteError("Not Found", err, resp.Status)
+		} else if resp.StatusCode == 401 || resp.StatusCode == 403 {
+			return nil, NewRemoteError("Access Denied", err, resp.Status)
+		}
 		return nil, fmt.Errorf("%s: %s", url, resp.Status)
 	}
 	b, err := ioutil.ReadAll(resp.Body)
diff --git a/vendor/github.com/Masterminds/vcs/vcs_remote_lookup_test.go b/vendor/github.com/Masterminds/vcs/vcs_remote_lookup_test.go
index fd7663e..e97bba8 100644
--- a/vendor/github.com/Masterminds/vcs/vcs_remote_lookup_test.go
+++ b/vendor/github.com/Masterminds/vcs/vcs_remote_lookup_test.go
@@ -1,6 +1,7 @@
 package vcs
 
 import (
+	"strings"
 	"testing"
 )
 
@@ -58,7 +59,11 @@
 			t.Errorf("Error detecting VCS from URL(%s): %s", u, err)
 		}
 
-		if err != nil && err != ErrCannotDetectVCS && c.work == false {
+		if err != nil &&
+			err != ErrCannotDetectVCS &&
+			!strings.HasSuffix(err.Error(), "Not Found") &&
+			!strings.HasSuffix(err.Error(), "Access Denied") &&
+			c.work == false {
 			t.Errorf("Unexpected error returned (%s): %s", u, err)
 		}
 
@@ -67,3 +72,27 @@
 		}
 	}
 }
+
+func TestNotFound(t *testing.T) {
+	_, _, err := detectVcsFromRemote("https://mattfarina.com/notfound")
+	if err == nil || !strings.HasSuffix(err.Error(), " Not Found") {
+		t.Errorf("Failed to find not found repo")
+	}
+
+	_, err = NewRepo("https://mattfarina.com/notfound", "")
+	if err == nil || !strings.HasSuffix(err.Error(), " Not Found") {
+		t.Errorf("Failed to find not found repo")
+	}
+}
+
+func TestAccessDenied(t *testing.T) {
+	_, _, err := detectVcsFromRemote("https://bitbucket.org/mattfarina/private-repo-for-vcs-testing")
+	if err == nil || err.Error() != "Access Denied" {
+		t.Errorf("Failed to detect access denied")
+	}
+
+	_, err = NewRepo("https://bitbucket.org/mattfarina/private-repo-for-vcs-testing", "")
+	if err == nil || err.Error() != "Access Denied" {
+		t.Errorf("Failed to detect access denied")
+	}
+}