Un-rewriting the Godeps import rewrites
diff --git a/action/get.go b/action/get.go index e0fe9ad..e5135e8 100644 --- a/action/get.go +++ b/action/get.go
@@ -6,6 +6,7 @@ "strings" "github.com/Masterminds/glide/cfg" + "github.com/Masterminds/glide/godep" "github.com/Masterminds/glide/msg" gpath "github.com/Masterminds/glide/path" "github.com/Masterminds/glide/repo" @@ -75,6 +76,9 @@ } if !skipRecursive { // Write lock + if stripVendor { + confcopy = godep.RemoveGodepSubpackages(confcopy) + } writeLock(conf, confcopy, base) } else { msg.Warn("Skipping lockfile generation because full dependency tree is not being calculated") @@ -87,7 +91,10 @@ if stripVendor { msg.Info("Removing nested vendor and Godeps/_workspace directories...") - gpath.StripVendor() + err := gpath.StripVendor() + if err != nil { + msg.Err("Unable to strip vendor directories: %s", err) + } } }
diff --git a/action/install.go b/action/install.go index 5349962..3ae39c0 100644 --- a/action/install.go +++ b/action/install.go
@@ -66,7 +66,10 @@ if stripVendor { msg.Info("Removing nested vendor and Godeps/_workspace directories...") - gpath.StripVendor() + err := gpath.StripVendor() + if err != nil { + msg.Err("Unable to strip vendor directories: %s", err) + } } }
diff --git a/action/update.go b/action/update.go index 451392f..4b0da7b 100644 --- a/action/update.go +++ b/action/update.go
@@ -5,6 +5,7 @@ "github.com/Masterminds/glide/cfg" "github.com/Masterminds/glide/dependency" + "github.com/Masterminds/glide/godep" "github.com/Masterminds/glide/msg" gpath "github.com/Masterminds/glide/path" "github.com/Masterminds/glide/repo" @@ -73,6 +74,10 @@ // from the project. A removed dependency should warn and an added dependency // should be added to the glide.yaml file. See issue #193. + if stripVendor { + confcopy = godep.RemoveGodepSubpackages(confcopy) + } + if !skipRecursive { // Write lock hash, err := conf.Hash() @@ -97,6 +102,9 @@ if stripVendor { msg.Info("Removing nested vendor and Godeps/_workspace directories...") - gpath.StripVendor() + err := gpath.StripVendor() + if err != nil { + msg.Err("Unable to strip vendor directories: %s", err) + } } }
diff --git a/godep/godep.go b/godep/godep.go index aad445b..a7d0525 100644 --- a/godep/godep.go +++ b/godep/godep.go
@@ -7,6 +7,7 @@ "encoding/json" "os" "path/filepath" + "strings" "github.com/Masterminds/glide/cfg" "github.com/Masterminds/glide/msg" @@ -96,3 +97,29 @@ return buf, nil } + +// RemoveGodepSubpackages strips subpackages from a cfg.Config dependencies that +// contain "Godeps/_workspace/src" as part of the path. +func RemoveGodepSubpackages(c *cfg.Config) *cfg.Config { + for _, d := range c.Imports { + n := []string{} + for _, v := range d.Subpackages { + if !strings.HasPrefix(v, "Godeps/_workspace/src") { + n = append(n, v) + } + } + d.Subpackages = n + } + + for _, d := range c.DevImports { + n := []string{} + for _, v := range d.Subpackages { + if !strings.HasPrefix(v, "Godeps/_workspace/src") { + n = append(n, v) + } + } + d.Subpackages = n + } + + return c +}
diff --git a/path/strip.go b/path/strip.go index a3705b2..6f8698d 100644 --- a/path/strip.go +++ b/path/strip.go
@@ -1,8 +1,15 @@ package path import ( + "bytes" + "go/ast" + "go/parser" + "go/printer" + "go/token" "os" "path/filepath" + "strconv" + "strings" "github.com/Masterminds/glide/msg" ) @@ -47,7 +54,12 @@ return err } - return filepath.Walk(VendorDir, stripVendorHandler) + err := filepath.Walk(VendorDir, stripVendorHandler) + if err != nil { + return err + } + + return StripGodepWorkspace() } func stripVendorHandler(path string, info os.FileInfo, err error) error { @@ -57,9 +69,7 @@ } name := info.Name() - p := filepath.Dir(path) - pn := filepath.Base(p) - if name == "vendor" || (name == "_workspace" && pn == "Godeps") { + if name == "vendor" { if _, err := os.Stat(path); err == nil { if info.IsDir() { msg.Info("Removing: %s", path) @@ -72,3 +82,136 @@ } return nil } + +var godepMark = map[string]bool{} + +// StripGodepWorkspace removes any Godeps/_workspace directories and makes sure +// any rewrites are undone. +// Note, this is not concuccency safe. +func StripGodepWorkspace() error { + if _, err := os.Stat(VendorDir); err != nil { + if os.IsNotExist(err) { + msg.Debug("Vendor directory does not exist.") + } + + return err + } + + err := filepath.Walk(VendorDir, stripGodepWorkspaceHandler) + if err != nil { + return err + } + + // Walk the marked projects to make sure rewrites are undone. + for k := range godepMark { + msg.Info("Removing Godep rewrites for %s", k) + err := filepath.Walk(k, rewriteGodepfilesHandler) + if err != nil { + return err + } + } + + return nil +} + +func stripGodepWorkspaceHandler(path string, info os.FileInfo, err error) error { + // Skip the base vendor directory + if path == VendorDir { + return nil + } + + name := info.Name() + p := filepath.Dir(path) + pn := filepath.Base(p) + if name == "_workspace" && pn == "Godeps" { + if _, err := os.Stat(path); err == nil { + if info.IsDir() { + // Marking this location to make sure rewrites are undone. + pp := filepath.Dir(p) + godepMark[pp] = true + + msg.Info("Removing: %s", path) + return os.RemoveAll(path) + } + + msg.Debug("%s is not a directory. Skipping removal", path) + return nil + } + } + return nil +} + +func rewriteGodepfilesHandler(path string, info os.FileInfo, err error) error { + name := info.Name() + if name == "testdata" || name == "vendor" { + return filepath.SkipDir + } + + if info.IsDir() { + return nil + } + + if e := filepath.Ext(path); e != ".go" { + return nil + } + + fset := token.NewFileSet() + f, err := parser.ParseFile(fset, path, nil, parser.ParseComments) + if err != nil { + return err + } + + var changed bool + for _, s := range f.Imports { + n, err := strconv.Unquote(s.Path.Value) + if err != nil { + return err + } + q := rewriteGodepImport(n) + if q != name { + s.Path.Value = strconv.Quote(q) + changed = true + } + } + if !changed { + return nil + } + + printerConfig := &printer.Config{Mode: printer.TabIndent | printer.UseSpaces, Tabwidth: 8} + var buffer bytes.Buffer + if err = printerConfig.Fprint(&buffer, fset, f); err != nil { + return err + } + fset = token.NewFileSet() + f, err = parser.ParseFile(fset, name, &buffer, parser.ParseComments) + ast.SortImports(fset, f) + tpath := path + ".temp" + t, err := os.Create(tpath) + if err != nil { + return err + } + if err = printerConfig.Fprint(t, fset, f); err != nil { + return err + } + if err = t.Close(); err != nil { + return err + } + + msg.Debug("Rewriting Godep imports for %s", path) + + // This is required before the rename on windows. + if err = os.Remove(path); err != nil { + return err + } + return os.Rename(tpath, path) +} + +func rewriteGodepImport(n string) string { + if !strings.Contains(n, "Godeps/_workspace/src") { + return n + } + + i := strings.LastIndex(n, "Godeps/_workspace/src") + + return strings.TrimPrefix(n[i:], "Godeps/_workspace/src/") +}
diff --git a/path/strip_test.go b/path/strip_test.go index 6c11194..eb0789c 100644 --- a/path/strip_test.go +++ b/path/strip_test.go
@@ -65,3 +65,17 @@ t.Error(".svn directory not deleted") } } + +func TestRewriteGodepImport(t *testing.T) { + tests := map[string]string{ + "github.com/Masterminds/glide/action": "github.com/Masterminds/glide/action", + "github.com/tools/godep/Godeps/_workspace/src/github.com/kr/fs": "github.com/kr/fs", + } + + for k, v := range tests { + o := rewriteGodepImport(k) + if o != v { + t.Errorf("Incorrect Godep import path rewritten %s: %s", v, o) + } + } +}