diff --git a/cmd/eg/eg_test.go b/cmd/eg/eg_test.go new file mode 100644 index 00000000..de4b0880 --- /dev/null +++ b/cmd/eg/eg_test.go @@ -0,0 +1,79 @@ +// Copyright 2016 The Go Authors. All rights reserved. +// Use of this source code is governed by a BSD-style +// license that can be found in the LICENSE file. + +package main + +import ( + "bytes" + "flag" + "fmt" + "io/ioutil" + "os" + "os/exec" + "path/filepath" + "strings" + "testing" +) + +var ( + sub = flag.Bool("subtest", false, "Indicates that the program should act as the eg command rather than as a test") +) + +func TestVendor(t *testing.T) { + if *sub { + if err := doMain(); err != nil { + fmt.Fprintf(os.Stderr, "eg: %s\n", err) + os.Exit(1) + } + os.Exit(0) + } + + tests := []struct { + args []string + goldFile string + }{ + { + args: []string{"-t", "A.template", "--", "A1.go"}, + goldFile: "A1.golden", + }, + } + + curdir, err := os.Getwd() + if err != nil { + t.Fatalf("os.Getwd: %v", err) + } + + for _, tt := range tests { + cmd := exec.Command(os.Args[0], append([]string{"-test.run=TestVendor", "-subtest"}, tt.args...)...) + cmd.Dir = filepath.Join(curdir, "testdata/src/prog") + + cmd.Env = append(cmd.Env, "GOPATH="+filepath.Join(curdir, "testdata")) + for _, env := range os.Environ() { + if strings.HasPrefix(env, "GOPATH=") { + continue + } + cmd.Env = append(cmd.Env, env) + } + + goldFile := filepath.Join(cmd.Dir, tt.goldFile) + gold, err := ioutil.ReadFile(goldFile) + if err != nil { + t.Errorf("read golden file %q: %v", goldFile, err) + continue + } + + var stdout bytes.Buffer + cmd.Stdout = &stdout + cmd.Stderr = os.Stderr + err = cmd.Run() + if err != nil { + t.Errorf("eg %q exec: %v", tt.args, err) + continue + } + + if have, want := stdout.Bytes(), gold; !bytes.Equal(have, want) { + t.Errorf("eg %q output does not match contents of %q:\n%s\n!=\n%s\n", tt.args, tt.goldFile, have, want) + } + } +} diff --git a/cmd/eg/testdata/src/dep0/dep0.go b/cmd/eg/testdata/src/dep0/dep0.go new file mode 100644 index 00000000..4307c09a --- /dev/null +++ b/cmd/eg/testdata/src/dep0/dep0.go @@ -0,0 +1,5 @@ +package dep0 + +func C() {} + +func D() {} diff --git a/cmd/eg/testdata/src/prog/A.template b/cmd/eg/testdata/src/prog/A.template new file mode 100644 index 00000000..04561f5d --- /dev/null +++ b/cmd/eg/testdata/src/prog/A.template @@ -0,0 +1,11 @@ +package eg + +import ( + "dep0" + "dep1" +) + +// Test of adding a dependency that is found via a "vendor" directory + +func before() { dep0.D() } +func after() { dep1.E() } diff --git a/cmd/eg/testdata/src/prog/A1.go b/cmd/eg/testdata/src/prog/A1.go new file mode 100644 index 00000000..350d1b06 --- /dev/null +++ b/cmd/eg/testdata/src/prog/A1.go @@ -0,0 +1,10 @@ +package main + +import ( + "dep0" +) + +func example() { + dep0.C() + dep0.D() +} diff --git a/cmd/eg/testdata/src/prog/A1.golden b/cmd/eg/testdata/src/prog/A1.golden new file mode 100644 index 00000000..24db78bb --- /dev/null +++ b/cmd/eg/testdata/src/prog/A1.golden @@ -0,0 +1,11 @@ +package main + +import ( + "dep0" + "dep1" +) + +func example() { + dep0.C() + dep1.E() +} diff --git a/cmd/eg/testdata/src/prog/vendor/dep1/dep1.go b/cmd/eg/testdata/src/prog/vendor/dep1/dep1.go new file mode 100644 index 00000000..45943ca8 --- /dev/null +++ b/cmd/eg/testdata/src/prog/vendor/dep1/dep1.go @@ -0,0 +1,3 @@ +package dep1 + +func E() {} diff --git a/refactor/eg/rewrite.go b/refactor/eg/rewrite.go index d91a99cc..49710e17 100644 --- a/refactor/eg/rewrite.go +++ b/refactor/eg/rewrite.go @@ -98,7 +98,7 @@ func (tr *Transformer) Transform(info *types.Info, pkg *types.Package, file *ast if tr.nsubsts > 0 { pkgs := make(map[string]*types.Package) for obj := range tr.importedObjs { - pkgs[obj.Pkg().Path()] = obj.Pkg() + pkgs[vendorlessImportPath(obj.Pkg().Path())] = obj.Pkg() } for _, imp := range file.Imports { @@ -344,3 +344,19 @@ func updateTypeInfo(info *types.Info, new, old ast.Expr) { info.Types[new] = tv } } + +// vendorlessImportPath returns the devendorized version of the provided import path. +// e.g. "foo/bar/vendor/a/b" => "a/b" +// +// This function is taken from fix.go in the golang.org/x/tools/imports +// package. +func vendorlessImportPath(ipath string) string { + // Devendorize for use in import statement. + if i := strings.LastIndex(ipath, "/vendor/"); i >= 0 { + return ipath[i+len("/vendor/"):] + } + if strings.HasPrefix(ipath, "vendor/") { + return ipath[len("vendor/"):] + } + return ipath +} diff --git a/refactor/eg/rewrite_test.go b/refactor/eg/rewrite_test.go new file mode 100644 index 00000000..382aab7c --- /dev/null +++ b/refactor/eg/rewrite_test.go @@ -0,0 +1,36 @@ +// Copyright 2016 The Go Authors. All rights reserved. +// Use of this source code is governed by a BSD-style +// license that can be found in the LICENSE file. + +package eg + +import "testing" + +func TestVendorlessImportPath(t *testing.T) { + tests := []struct { + path string + ipath string + }{ + {"a/b/c", "a/b/c"}, + {"a/b/vendor/c", "c"}, + {"a/vendor/b/c", "b/c"}, + {"vendor/a/b/c", "a/b/c"}, + {"a/b/vendor/vendor/c", "c"}, + {"a/vendor/b/vendor/c", "c"}, + {"vendor/a/b/vendor/c", "c"}, + {"vendor/a/vendor/b/c", "b/c"}, + {"a/vendor/vendor/b/c", "b/c"}, + {"vendor/vendor/a/b/c", "a/b/c"}, + + {"a/b/notvendor/c", "a/b/notvendor/c"}, + {"a/b/vendors/c", "a/b/vendors/c"}, + {"a/b/notvendors/c", "a/b/notvendors/c"}, + {"notvendor/a/b/c", "notvendor/a/b/c"}, + } + + for _, tt := range tests { + if have, want := vendorlessImportPath(tt.path), tt.ipath; have != want { + t.Errorf("vendorlessImportPath(%q); %q != %q", tt.path, have, want) + } + } +}