Merge branch 'master' into thockin-print-path-on-recursive-hit
diff --git a/action/install.go b/action/install.go
index 8608dc8..bed3744 100644
--- a/action/install.go
+++ b/action/install.go
@@ -12,7 +12,7 @@
 )
 
 // Install installs a vendor directory based on an existing Glide configuration.
-func Install(installer *repo.Installer) {
+func Install(installer *repo.Installer, strip bool) {
 	base := "."
 	// Ensure GOPATH
 	EnsureGopath()
@@ -22,7 +22,7 @@
 	// Lockfile exists
 	if !gpath.HasLock(base) {
 		msg.Info("Lock file (glide.lock) does not exist. Performing update.")
-		Update(installer, false)
+		Update(installer, false, strip)
 		return
 	}
 	// Load lockfile
@@ -53,9 +53,16 @@
 	}
 
 	// VendoredCleanup. This should ONLY be run if UpdateVendored was specified.
-	if installer.UpdateVendored {
+	// When stripping VCS happens this will happen as well. No need for double
+	// effort.
+	if installer.UpdateVendored && !strip {
 		repo.VendoredCleanup(newConf)
 	}
+
+	if strip {
+		msg.Info("Removing version control data from vendor directory...")
+		gpath.StripVcs()
+	}
 }
 
 // LoadLockfile loads the contents of a glide.lock file.
diff --git a/action/update.go b/action/update.go
index e86e04a..cf87b28 100644
--- a/action/update.go
+++ b/action/update.go
@@ -11,7 +11,7 @@
 )
 
 // Update updates repos and the lock file from the main glide yaml.
-func Update(installer *repo.Installer, skipRecursive bool) {
+func Update(installer *repo.Installer, skipRecursive, strip bool) {
 	base := "."
 	EnsureGopath()
 	EnsureVendorDir()
@@ -58,7 +58,9 @@
 	}
 	// Vendored cleanup
 	// VendoredCleanup. This should ONLY be run if UpdateVendored was specified.
-	if installer.UpdateVendored {
+	// When stripping VCS happens this will happen as well. No need for double
+	// effort.
+	if installer.UpdateVendored && !strip {
 		repo.VendoredCleanup(confcopy)
 	}
 
@@ -87,4 +89,9 @@
 	} else {
 		msg.Warn("Skipping lockfile generation because full dependency tree is not being calculated")
 	}
+
+	if strip {
+		msg.Info("Removing version control data from vendor directory...")
+		gpath.StripVcs()
+	}
 }
diff --git a/cfg/cfg.go b/cfg/cfg.go
index 93ae060..e9ed812 100644
--- a/cfg/cfg.go
+++ b/cfg/cfg.go
@@ -19,6 +19,8 @@
 //       homepage: https://www.mattfarina.com
 //     ignore:
 //     - appengine
+//     excludeDirs:
+//     - node_modules
 //     import:
 //     - package: gopkg.in/yaml.v2
 //     - package: github.com/Masterminds/vcs
@@ -43,6 +45,8 @@
 //      owners of a security issue without filing a public bug.
 //    - ignore: A list of packages for Glide to ignore importing. These are package
 //      names to ignore rather than directories.
+//    - excludeDirs: A list of directories in the local codebase to exclude from
+//      scanning for dependencies.
 //    - import: A list of packages to import. Each package can include:
 //        - package: The name of the package to import and the only non-optional item.
 //        - version: A semantic version, semantic version range, branch, tag, or
diff --git a/cfg/config.go b/cfg/config.go
index 88bdc71..afeed9a 100644
--- a/cfg/config.go
+++ b/cfg/config.go
@@ -41,6 +41,10 @@
 	// those to skip.
 	Ignore []string `yaml:"ignore,omitempty"`
 
+	// Exclude contains a list of directories in the local application to
+	// exclude from scanning for dependencies.
+	Exclude []string `yaml:"excludeDirs,omitempty"`
+
 	// Imports contains a list of all non-development imports for a project. For
 	// more detail on how these are captured see the Dependency type.
 	Imports Dependencies `yaml:"import"`
@@ -58,6 +62,7 @@
 	License     string       `yaml:"license,omitempty"`
 	Owners      Owners       `yaml:"owners,omitempty"`
 	Ignore      []string     `yaml:"ignore,omitempty"`
+	Exclude     []string     `yaml:"excludeDirs,omitempty"`
 	Imports     Dependencies `yaml:"import"`
 	DevImports  Dependencies `yaml:"devimport,omitempty"`
 }
@@ -90,6 +95,7 @@
 	c.License = newConfig.License
 	c.Owners = newConfig.Owners
 	c.Ignore = newConfig.Ignore
+	c.Exclude = newConfig.Exclude
 	c.Imports = newConfig.Imports
 	c.DevImports = newConfig.DevImports
 
@@ -108,6 +114,7 @@
 		License:     c.License,
 		Owners:      c.Owners,
 		Ignore:      c.Ignore,
+		Exclude:     c.Exclude,
 	}
 	i, err := c.Imports.Clone().DeDupe()
 	if err != nil {
@@ -154,6 +161,18 @@
 	return false
 }
 
+// HasExclude returns true if the given name is listed on the exclude list.
+func (c *Config) HasExclude(ex string) bool {
+	ep := normalizeSlash(ex)
+	for _, v := range c.Exclude {
+		if vp := normalizeSlash(v); vp == ep {
+			return true
+		}
+	}
+
+	return false
+}
+
 // Clone performs a deep clone of the Config instance
 func (c *Config) Clone() *Config {
 	n := &Config{}
@@ -163,6 +182,7 @@
 	n.License = c.License
 	n.Owners = c.Owners.Clone()
 	n.Ignore = c.Ignore
+	n.Exclude = c.Exclude
 	n.Imports = c.Imports.Clone()
 	n.DevImports = c.DevImports.Clone()
 	return n
@@ -524,3 +544,7 @@
 		return ""
 	}
 }
+
+func normalizeSlash(k string) string {
+	return strings.Replace(k, "\\", "/", -1)
+}
diff --git a/dependency/resolver.go b/dependency/resolver.go
index 6c00a41..a0ba011 100644
--- a/dependency/resolver.go
+++ b/dependency/resolver.go
@@ -232,6 +232,12 @@
 		if err != nil && err != filepath.SkipDir {
 			return err
 		}
+		pt := strings.TrimPrefix(path, r.basedir+string(os.PathSeparator))
+		pt = strings.TrimSuffix(pt, string(os.PathSeparator))
+		if r.Config.HasExclude(pt) {
+			msg.Debug("Excluding %s", pt)
+			return filepath.SkipDir
+		}
 		if !fi.IsDir() {
 			return nil
 		}
diff --git a/docs/glide.yaml.md b/docs/glide.yaml.md
index 784910b..2216bee 100644
--- a/docs/glide.yaml.md
+++ b/docs/glide.yaml.md
@@ -14,6 +14,8 @@
         homepage: https://www.mattfarina.com
     ignore:
     - appengine
+    excludeDirs:
+    - node_modules
     import:
     - package: gopkg.in/yaml.v2
     - package: github.com/Masterminds/vcs
@@ -31,6 +33,7 @@
 - license: The license is either an [SPDX license](http://spdx.org/licenses/) string or the filepath to the license. This allows automation and consumers to easily identify the license.
 - `owners`: The owners is a list of one or more owners for the project. This can be a person or organization and is useful for things like notifying the owners of a security issue without filing a public bug.
 - `ignore`: A list of packages for Glide to ignore importing. These are package names to ignore rather than directories.
+- `excludeDirs`: A list of directories in the local codebase to exclude from scanning for dependencies.
 - `import`: A list of packages to import. Each package can include:
     - `package`: The name of the package to import and the only non-optional item. Package names follow the same patterns the `go` tool does. That means:
         - Package names that map to a VCS remote location end in .git, .bzr, .hg, or .svn. For example, `example.com/foo/pkg.git/subpkg`.
diff --git a/glide.go b/glide.go
index 6d4bed5..a1b6f64 100644
--- a/glide.go
+++ b/glide.go
@@ -404,6 +404,10 @@
 					Name:  "use-gopath",
 					Usage: "Copy dependencies from the GOPATH if they exist there.",
 				},
+				cli.BoolFlag{
+					Name:  "strip-vcs",
+					Usage: "Removes version control metada (e.g, .git directory) from the vendor folder.",
+				},
 			},
 			Action: func(c *cli.Context) {
 				installer := repo.NewInstaller()
@@ -415,7 +419,7 @@
 				installer.Home = gpath.Home()
 				installer.DeleteUnused = c.Bool("deleteOptIn")
 
-				action.Install(installer)
+				action.Install(installer, c.Bool("strip-vcs"))
 			},
 		},
 		{
@@ -488,6 +492,10 @@
 					Name:  "resolve-current",
 					Usage: "Resolve dependencies for only the current system rather than all build modes.",
 				},
+				cli.BoolFlag{
+					Name:  "strip-vcs",
+					Usage: "Removes version control metada (e.g, .git directory) from the vendor folder.",
+				},
 			},
 			Action: func(c *cli.Context) {
 
@@ -506,7 +514,7 @@
 				installer.Home = gpath.Home()
 				installer.DeleteUnused = c.Bool("deleteOptIn")
 
-				action.Update(installer, c.Bool("no-recursive"))
+				action.Update(installer, c.Bool("no-recursive"), c.Bool("strip-vcs"))
 			},
 		},
 		{
diff --git a/glide.lock b/glide.lock
index 8087d1c..5187ded 100644
--- a/glide.lock
+++ b/glide.lock
@@ -1,12 +1,12 @@
 hash: 1b76070c56de9f698ebbd32b2f36d2c972888fc0793f7843b0925e4faca65d4b
-updated: 2016-03-07T15:05:34.774169565-05:00
+updated: 2016-03-09T11:00:49.889321962-05:00
 imports:
 - name: github.com/codegangsta/cli
-  version: c31a7975863e7810c92e2e288a9ab074f9a88f29
+  version: aca5b047ed14d17224157c3434ea93bf6cdaadee
 - name: github.com/Masterminds/semver
   version: 513f3dcb3ecfb1248831fb5cb06a23a3cd5935dc
 - name: github.com/Masterminds/vcs
   version: 242477a09d9db06a848c5305525168f042d96871
 - name: gopkg.in/yaml.v2
-  version: f7716cbe52baa25d2e9b0d0da546fcf909fc16b4
+  version: a83829b6f1293c91addabc89d0571c246397bbf4
 devImports: []
diff --git a/path/path.go b/path/path.go
index f79125d..cfa46c2 100644
--- a/path/path.go
+++ b/path/path.go
@@ -1,7 +1,7 @@
 // Package path contains path and environment utilities for Glide.
 //
-//This includes tools to find and manipulate Go path variables, as well as
-//tools for copying from one path to another.
+// This includes tools to find and manipulate Go path variables, as well as
+// tools for copying from one path to another.
 package path
 
 import (
diff --git a/path/strip.go b/path/strip.go
new file mode 100644
index 0000000..e7abe29
--- /dev/null
+++ b/path/strip.go
@@ -0,0 +1,38 @@
+package path
+
+import (
+	"os"
+	"path/filepath"
+
+	"github.com/Masterminds/glide/msg"
+)
+
+// StripVcs removes VCS metadata (.git, .hg, .bzr, .svn) from the vendor/
+// directory.
+func StripVcs() error {
+	if _, err := os.Stat(VendorDir); err != nil {
+		if os.IsNotExist(err) {
+			msg.Debug("Vendor directory does not exist.")
+		}
+
+		return err
+	}
+	return filepath.Walk(VendorDir, stripHandler)
+}
+
+func stripHandler(path string, info os.FileInfo, err error) error {
+
+	name := info.Name()
+	if name == ".git" || name == ".bzr" || name == ".svn" || name == ".hg" {
+		if _, err := os.Stat(path); err == nil {
+			if info.IsDir() {
+				msg.Info("Removing: %s", path)
+				return os.RemoveAll(path)
+			}
+
+			msg.Debug("%s is not a directory. Skipping removal", path)
+			return nil
+		}
+	}
+	return nil
+}
diff --git a/path/strip_test.go b/path/strip_test.go
new file mode 100644
index 0000000..6c11194
--- /dev/null
+++ b/path/strip_test.go
@@ -0,0 +1,67 @@
+package path
+
+import (
+	"io/ioutil"
+	"os"
+	"path/filepath"
+	"testing"
+)
+
+func TestStripVcs(t *testing.T) {
+	tempDir, err := ioutil.TempDir("", "strip-vcs")
+	if err != nil {
+		t.Error(err)
+	}
+
+	defer func() {
+		err = os.RemoveAll(tempDir)
+		if err != nil {
+			t.Error(err)
+		}
+	}()
+
+	// Make VCS directories.
+	gp := filepath.Join(tempDir, ".git")
+	err = os.Mkdir(gp, 0755)
+	if err != nil {
+		t.Error(err)
+	}
+
+	bp := filepath.Join(tempDir, ".bzr")
+	err = os.Mkdir(bp, 0755)
+	if err != nil {
+		t.Error(err)
+	}
+
+	hp := filepath.Join(tempDir, ".hg")
+	err = os.Mkdir(hp, 0755)
+	if err != nil {
+		t.Error(err)
+	}
+
+	sp := filepath.Join(tempDir, ".svn")
+	err = os.Mkdir(sp, 0755)
+	if err != nil {
+		t.Error(err)
+	}
+
+	ov := VendorDir
+	VendorDir = tempDir
+
+	StripVcs()
+
+	VendorDir = ov
+
+	if _, err := os.Stat(gp); !os.IsNotExist(err) {
+		t.Error(".git directory not deleted")
+	}
+	if _, err := os.Stat(hp); !os.IsNotExist(err) {
+		t.Error(".hg directory not deleted")
+	}
+	if _, err := os.Stat(bp); !os.IsNotExist(err) {
+		t.Error(".bzr directory not deleted")
+	}
+	if _, err := os.Stat(sp); !os.IsNotExist(err) {
+		t.Error(".svn directory not deleted")
+	}
+}