interp: support yet another vendoring case
* interp: support another vendoring case Namely, when the vendor dir is a sibling (or an uncle) relative to the current pkg Fixes #758 * make linter happier * address review comments * fix, cleanup, add unit tests * add dummy files to force dirs into git
This commit is contained in:
11
example/pkg/_pkg12/src/guthib.com/foo/main.go
Normal file
11
example/pkg/_pkg12/src/guthib.com/foo/main.go
Normal file
@@ -0,0 +1,11 @@
|
||||
package main
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
|
||||
"guthib.com/foo/pkg"
|
||||
)
|
||||
|
||||
func main() {
|
||||
fmt.Printf("%s", pkg.NewSample()())
|
||||
}
|
||||
17
example/pkg/_pkg12/src/guthib.com/foo/pkg/pkg.go
Normal file
17
example/pkg/_pkg12/src/guthib.com/foo/pkg/pkg.go
Normal file
@@ -0,0 +1,17 @@
|
||||
package pkg
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
|
||||
"guthib.com/bar"
|
||||
)
|
||||
|
||||
func Here() string {
|
||||
return "hello"
|
||||
}
|
||||
|
||||
func NewSample() func() string {
|
||||
return func() string {
|
||||
return fmt.Sprintf("%s %s", bar.Bar(), Here())
|
||||
}
|
||||
}
|
||||
6
example/pkg/_pkg12/src/guthib.com/foo/vendor/guthib.com/bar/bar.go
generated
vendored
Normal file
6
example/pkg/_pkg12/src/guthib.com/foo/vendor/guthib.com/bar/bar.go
generated
vendored
Normal file
@@ -0,0 +1,6 @@
|
||||
package bar
|
||||
|
||||
// Bar is bar
|
||||
func Bar() string {
|
||||
return "Yo"
|
||||
}
|
||||
@@ -83,6 +83,18 @@ func TestPackages(t *testing.T) {
|
||||
expected: "Fromage",
|
||||
evalFile: "./_pkg11/src/foo/foo.go",
|
||||
},
|
||||
{
|
||||
desc: "vendor dir is a sibling or an uncle",
|
||||
goPath: "./_pkg12/",
|
||||
expected: "Yo hello",
|
||||
topImport: "guthib.com/foo/pkg",
|
||||
},
|
||||
{
|
||||
desc: "eval main with vendor as a sibling",
|
||||
goPath: "./_pkg12/",
|
||||
expected: "Yo hello",
|
||||
evalFile: "./_pkg12/src/guthib.com/foo/main.go",
|
||||
},
|
||||
}
|
||||
|
||||
for _, test := range testCases {
|
||||
@@ -116,7 +128,7 @@ func TestPackages(t *testing.T) {
|
||||
os.Stdout = pw
|
||||
|
||||
if _, err := i.Eval(string(data)); err != nil {
|
||||
t.Fatal(err)
|
||||
fatalStderrf(t, "%v", err)
|
||||
}
|
||||
|
||||
var buf bytes.Buffer
|
||||
@@ -127,10 +139,10 @@ func TestPackages(t *testing.T) {
|
||||
}()
|
||||
|
||||
if err := pw.Close(); err != nil {
|
||||
t.Fatal(err)
|
||||
fatalStderrf(t, "%v", err)
|
||||
}
|
||||
if err := <-errC; err != nil {
|
||||
t.Fatal(err)
|
||||
fatalStderrf(t, "%v", err)
|
||||
}
|
||||
msg = buf.String()
|
||||
} else {
|
||||
@@ -153,12 +165,17 @@ func TestPackages(t *testing.T) {
|
||||
}
|
||||
|
||||
if msg != test.expected {
|
||||
t.Errorf("Got %q, want %q", msg, test.expected)
|
||||
fatalStderrf(t, "Got %q, want %q", msg, test.expected)
|
||||
}
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
func fatalStderrf(t *testing.T, format string, args ...interface{}) {
|
||||
fmt.Fprintf(os.Stderr, format+"\n", args...)
|
||||
t.FailNow()
|
||||
}
|
||||
|
||||
func TestPackagesError(t *testing.T) {
|
||||
testCases := []struct {
|
||||
desc string
|
||||
|
||||
@@ -22,7 +22,7 @@ func (interp *Interpreter) importSrc(rPath, path string) (string, error) {
|
||||
// In all other cases, absolute import paths are resolved from the GOPATH
|
||||
// and the nested "vendor" directories.
|
||||
if isPathRelative(path) {
|
||||
if rPath == "main" {
|
||||
if rPath == mainID {
|
||||
rPath = "."
|
||||
}
|
||||
dir = filepath.Join(filepath.Dir(interp.Name), rPath, path)
|
||||
@@ -153,7 +153,7 @@ func (interp *Interpreter) importSrc(rPath, path string) (string, error) {
|
||||
|
||||
func (interp *Interpreter) rootFromSourceLocation(rPath string) (string, error) {
|
||||
sourceFile := interp.Name
|
||||
if rPath != "main" || !strings.HasSuffix(sourceFile, ".go") {
|
||||
if rPath != mainID || !strings.HasSuffix(sourceFile, ".go") {
|
||||
return rPath, nil
|
||||
}
|
||||
wd, err := os.Getwd()
|
||||
@@ -188,13 +188,62 @@ func pkgDir(goPath string, root, path string) (string, string, error) {
|
||||
return "", "", fmt.Errorf("unable to find source related to: %q", path)
|
||||
}
|
||||
|
||||
return pkgDir(goPath, previousRoot(root), path)
|
||||
rootPath := filepath.Join(goPath, "src", root)
|
||||
prevRoot, err := previousRoot(rootPath, root)
|
||||
if err != nil {
|
||||
return "", "", err
|
||||
}
|
||||
|
||||
// Find the previous source root (vendor > vendor > ... > GOPATH).
|
||||
func previousRoot(root string) string {
|
||||
splitRoot := strings.Split(root, string(filepath.Separator))
|
||||
return pkgDir(goPath, prevRoot, path)
|
||||
}
|
||||
|
||||
const vendor = "vendor"
|
||||
|
||||
// Find the previous source root (vendor > vendor > ... > GOPATH).
|
||||
func previousRoot(rootPath, root string) (string, error) {
|
||||
rootPath = filepath.Clean(rootPath)
|
||||
parent, final := filepath.Split(rootPath)
|
||||
parent = filepath.Clean(parent)
|
||||
|
||||
// TODO(mpl): maybe it works for the special case main, but can't be bothered for now.
|
||||
if root != mainID && final != vendor {
|
||||
root = strings.TrimSuffix(root, string(filepath.Separator))
|
||||
prefix := strings.TrimSuffix(rootPath, root)
|
||||
|
||||
// look for the closest vendor in one of our direct ancestors, as it takes priority.
|
||||
var vendored string
|
||||
for {
|
||||
fi, err := os.Lstat(filepath.Join(parent, vendor))
|
||||
if err == nil && fi.IsDir() {
|
||||
vendored = strings.TrimPrefix(strings.TrimPrefix(parent, prefix), string(filepath.Separator))
|
||||
break
|
||||
}
|
||||
if !os.IsNotExist(err) {
|
||||
return "", err
|
||||
}
|
||||
|
||||
// stop when we reach GOPATH/src/blah
|
||||
parent = filepath.Dir(parent)
|
||||
if parent == prefix {
|
||||
break
|
||||
}
|
||||
|
||||
// just an additional failsafe, stop if we reach the filesystem root.
|
||||
// TODO(mpl): It should probably be a critical error actually,
|
||||
// as we shouldn't have gone that high up in the tree.
|
||||
if parent == string(filepath.Separator) {
|
||||
break
|
||||
}
|
||||
}
|
||||
|
||||
if vendored != "" {
|
||||
return vendored, nil
|
||||
}
|
||||
}
|
||||
|
||||
// TODO(mpl): the algorithm below might be redundant with the one above,
|
||||
// but keeping it for now. Investigate/simplify/remove later.
|
||||
splitRoot := strings.Split(root, string(filepath.Separator))
|
||||
var index int
|
||||
for i := len(splitRoot) - 1; i >= 0; i-- {
|
||||
if splitRoot[i] == "vendor" {
|
||||
@@ -204,10 +253,10 @@ func previousRoot(root string) string {
|
||||
}
|
||||
|
||||
if index == 0 {
|
||||
return ""
|
||||
return "", nil
|
||||
}
|
||||
|
||||
return filepath.Join(splitRoot[:index]...)
|
||||
return filepath.Join(splitRoot[:index]...), nil
|
||||
}
|
||||
|
||||
func effectivePkg(root, path string) string {
|
||||
|
||||
@@ -198,6 +198,7 @@ func Test_previousRoot(t *testing.T) {
|
||||
testCases := []struct {
|
||||
desc string
|
||||
root string
|
||||
rootPathSuffix string
|
||||
expected string
|
||||
}{
|
||||
{
|
||||
@@ -215,6 +216,18 @@ func Test_previousRoot(t *testing.T) {
|
||||
root: "github.com/foo/pkg/vendor/guthib.com/containous/fromage/vendor/guthib.com/containous/fuu",
|
||||
expected: "github.com/foo/pkg/vendor/guthib.com/containous/fromage",
|
||||
},
|
||||
{
|
||||
desc: "vendor is sibling",
|
||||
root: "github.com/foo/bar",
|
||||
rootPathSuffix: "testdata/src/github.com/foo/bar",
|
||||
expected: "github.com/foo",
|
||||
},
|
||||
{
|
||||
desc: "vendor is uncle",
|
||||
root: "github.com/foo/bar/baz",
|
||||
rootPathSuffix: "testdata/src/github.com/foo/bar/baz",
|
||||
expected: "github.com/foo",
|
||||
},
|
||||
}
|
||||
|
||||
for _, test := range testCases {
|
||||
@@ -222,7 +235,20 @@ func Test_previousRoot(t *testing.T) {
|
||||
t.Run(test.desc, func(t *testing.T) {
|
||||
t.Parallel()
|
||||
|
||||
p := previousRoot(test.root)
|
||||
var rootPath string
|
||||
if test.rootPathSuffix != "" {
|
||||
wd, err := os.Getwd()
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
rootPath = filepath.Join(wd, test.rootPathSuffix)
|
||||
} else {
|
||||
rootPath = vendor
|
||||
}
|
||||
p, err := previousRoot(rootPath, test.root)
|
||||
if err != nil {
|
||||
t.Error(err)
|
||||
}
|
||||
|
||||
if p != test.expected {
|
||||
t.Errorf("got: %s, want: %s", p, test.expected)
|
||||
|
||||
1
interp/testdata/src/github.com/foo/bar/baz/baz.go
vendored
Normal file
1
interp/testdata/src/github.com/foo/bar/baz/baz.go
vendored
Normal file
@@ -0,0 +1 @@
|
||||
package baz
|
||||
1
interp/testdata/src/github.com/foo/vendor/whatever/whatever.go
vendored
Normal file
1
interp/testdata/src/github.com/foo/vendor/whatever/whatever.go
vendored
Normal file
@@ -0,0 +1 @@
|
||||
package whatever
|
||||
Reference in New Issue
Block a user