From 76cfb0516ac215da699e911549681fa367218c0f Mon Sep 17 00:00:00 2001 From: Brian Starke Date: Wed, 15 Feb 2017 21:25:20 -0500 Subject: [PATCH 01/12] resolve symlinks if project root is within symlinked directory --- context.go | 8 ++++++++ context_test.go | 23 +++++++++++++++++++++++ 2 files changed, 31 insertions(+) diff --git a/context.go b/context.go index 4bec820997..243409ea0e 100644 --- a/context.go +++ b/context.go @@ -27,6 +27,7 @@ func NewContext() (*Ctx, error) { // this way we get the default GOPATH that was added in 1.8 buildContext := build.Default wd, err := os.Getwd() + if err != nil { return nil, errors.Wrap(err, "getting work directory") } @@ -124,6 +125,13 @@ func (c *Ctx) LoadProject(path string) (*Project, error) { // // The second returned string indicates which GOPATH value was used. func (c *Ctx) SplitAbsoluteProjectRoot(path string) (string, error) { + // the path may lie within a symlinked directory, resolve that first + path, err := filepath.EvalSymlinks(path) + + if err != nil { + return "", fmt.Errorf("failed to resolve symlinks: %s", err) + } + srcprefix := filepath.Join(c.GOPATH, "src") + string(filepath.Separator) if strings.HasPrefix(path, srcprefix) { // filepath.ToSlash because we're dealing with an import path now, diff --git a/context_test.go b/context_test.go index 58bc0e7b4b..00ae915212 100644 --- a/context_test.go +++ b/context_test.go @@ -5,6 +5,7 @@ package dep import ( + "fmt" "os" "path/filepath" "testing" @@ -35,6 +36,7 @@ func TestSplitAbsoluteProjectRoot(t *testing.T) { defer h.Cleanup() h.TempDir("src") + h.Setenv("GOPATH", h.Path(".")) depCtx := &Ctx{GOPATH: h.Path(".")} @@ -44,6 +46,9 @@ func TestSplitAbsoluteProjectRoot(t *testing.T) { } for _, want := range importPaths { + // actually create the directory so lstat won't fail + h.TempDir(fmt.Sprintf("src/%s", want)) + fullpath := filepath.Join(depCtx.GOPATH, "src", want) got, err := depCtx.SplitAbsoluteProjectRoot(fullpath) if err != nil { @@ -59,6 +64,24 @@ func TestSplitAbsoluteProjectRoot(t *testing.T) { if err == nil { t.Fatalf("should have gotten error but did not for tra/la/la/la: %s", got) } + + // test resolving project root is symlinked + want := "real/full/path" + symlinkedPath := filepath.Join(depCtx.GOPATH, "src", "sympath") + + h.TempDir(filepath.Join("src", want)) + + os.Symlink( + filepath.Join(depCtx.GOPATH, "src", want), + symlinkedPath) + + got, err = depCtx.SplitAbsoluteProjectRoot(symlinkedPath) + if err != nil { + t.Fatal(err) + } + if got != want { + t.Fatalf("expected %s, got %s", want, got) + } } func TestAbsoluteProjectRoot(t *testing.T) { From 6c8491c792d63c99a793f1ff15bccdf55f297fb9 Mon Sep 17 00:00:00 2001 From: Brian Starke Date: Wed, 15 Feb 2017 21:33:24 -0500 Subject: [PATCH 02/12] small cleanup --- context.go | 5 ++--- context_test.go | 5 ++--- 2 files changed, 4 insertions(+), 6 deletions(-) diff --git a/context.go b/context.go index 243409ea0e..c7e683deb1 100644 --- a/context.go +++ b/context.go @@ -27,7 +27,6 @@ func NewContext() (*Ctx, error) { // this way we get the default GOPATH that was added in 1.8 buildContext := build.Default wd, err := os.Getwd() - if err != nil { return nil, errors.Wrap(err, "getting work directory") } @@ -125,11 +124,11 @@ func (c *Ctx) LoadProject(path string) (*Project, error) { // // The second returned string indicates which GOPATH value was used. func (c *Ctx) SplitAbsoluteProjectRoot(path string) (string, error) { - // the path may lie within a symlinked directory, resolve that first + // the path may lie within a symlinked directory, resolve those first path, err := filepath.EvalSymlinks(path) if err != nil { - return "", fmt.Errorf("failed to resolve symlinks: %s", err) + return "", fmt.Errorf("failed attempt to resolve symlinks: %s", err) } srcprefix := filepath.Join(c.GOPATH, "src") + string(filepath.Separator) diff --git a/context_test.go b/context_test.go index 00ae915212..caeb18787d 100644 --- a/context_test.go +++ b/context_test.go @@ -5,7 +5,6 @@ package dep import ( - "fmt" "os" "path/filepath" "testing" @@ -46,8 +45,8 @@ func TestSplitAbsoluteProjectRoot(t *testing.T) { } for _, want := range importPaths { - // actually create the directory so lstat won't fail - h.TempDir(fmt.Sprintf("src/%s", want)) + // create the target directory so lstat doesn't fail + h.TempDir(filepath.Join("src", want)) fullpath := filepath.Join(depCtx.GOPATH, "src", want) got, err := depCtx.SplitAbsoluteProjectRoot(fullpath) From 0047ea12e2e5a6d42c9f40074dbf093f92dcda80 Mon Sep 17 00:00:00 2001 From: Brian Starke Date: Tue, 21 Feb 2017 13:22:38 -0500 Subject: [PATCH 03/12] Moved symlink evaluation to LoadProject function, split out symlink eval test in to it's own test case --- context.go | 15 ++++++++------- context_test.go | 48 +++++++++++++++++++++++++++--------------------- 2 files changed, 35 insertions(+), 28 deletions(-) diff --git a/context.go b/context.go index c7e683deb1..6c1033bfc2 100644 --- a/context.go +++ b/context.go @@ -27,6 +27,7 @@ func NewContext() (*Ctx, error) { // this way we get the default GOPATH that was added in 1.8 buildContext := build.Default wd, err := os.Getwd() + if err != nil { return nil, errors.Wrap(err, "getting work directory") } @@ -75,6 +76,13 @@ func (c *Ctx) LoadProject(path string) (*Project, error) { return nil, err } + // the path may lie within a symlinked directory, resolve that + // before moving forward + p.AbsRoot, err = filepath.EvalSymlinks(p.AbsRoot) + if err != nil { + return nil, errors.Wrapf(err, "eval symlinks") + } + ip, err := c.SplitAbsoluteProjectRoot(p.AbsRoot) if err != nil { return nil, errors.Wrap(err, "split absolute project root") @@ -124,13 +132,6 @@ func (c *Ctx) LoadProject(path string) (*Project, error) { // // The second returned string indicates which GOPATH value was used. func (c *Ctx) SplitAbsoluteProjectRoot(path string) (string, error) { - // the path may lie within a symlinked directory, resolve those first - path, err := filepath.EvalSymlinks(path) - - if err != nil { - return "", fmt.Errorf("failed attempt to resolve symlinks: %s", err) - } - srcprefix := filepath.Join(c.GOPATH, "src") + string(filepath.Separator) if strings.HasPrefix(path, srcprefix) { // filepath.ToSlash because we're dealing with an import path now, diff --git a/context_test.go b/context_test.go index caeb18787d..f7a6d6abac 100644 --- a/context_test.go +++ b/context_test.go @@ -7,6 +7,7 @@ package dep import ( "os" "path/filepath" + "strings" "testing" "github.com/golang/dep/test" @@ -45,9 +46,6 @@ func TestSplitAbsoluteProjectRoot(t *testing.T) { } for _, want := range importPaths { - // create the target directory so lstat doesn't fail - h.TempDir(filepath.Join("src", want)) - fullpath := filepath.Join(depCtx.GOPATH, "src", want) got, err := depCtx.SplitAbsoluteProjectRoot(fullpath) if err != nil { @@ -63,24 +61,6 @@ func TestSplitAbsoluteProjectRoot(t *testing.T) { if err == nil { t.Fatalf("should have gotten error but did not for tra/la/la/la: %s", got) } - - // test resolving project root is symlinked - want := "real/full/path" - symlinkedPath := filepath.Join(depCtx.GOPATH, "src", "sympath") - - h.TempDir(filepath.Join("src", want)) - - os.Symlink( - filepath.Join(depCtx.GOPATH, "src", want), - symlinkedPath) - - got, err = depCtx.SplitAbsoluteProjectRoot(symlinkedPath) - if err != nil { - t.Fatal(err) - } - if got != want { - t.Fatalf("expected %s, got %s", want, got) - } } func TestAbsoluteProjectRoot(t *testing.T) { @@ -227,6 +207,32 @@ func TestLoadProject(t *testing.T) { } } +func TestLoadProjectWithSymlinkedDir(t *testing.T) { + tg := test.NewHelper(t) + defer tg.Cleanup() + + tg.TempDir("src") + tg.TempDir("src/real") + tg.TempDir("src/real/path") + tg.TempFile("src/real/path/manifest.json", `{"dependencies":{}}`) + tg.TempFile("src/real/path/lock.json", `{"memo":"cdafe8641b28cd16fe025df278b0a49b9416859345d8b6ba0ace0272b74925ee","projects":[]}`) + tg.Setenv("GOPATH", tg.Path(".")) + ctx := &Ctx{GOPATH: tg.Path(".")} + + symlinkedPath := filepath.Join(ctx.GOPATH, "src", "sympath") + os.Symlink(filepath.Join(ctx.GOPATH, "src/real/path"), symlinkedPath) + + p, err := ctx.LoadProject(symlinkedPath) + + if err != nil { + t.Fatalf("Error loading project: %s", err) + } + + if !strings.HasSuffix(p.AbsRoot, "/real/path") { + t.Fatalf("Expected AbsRoot to end with '/real/path', AbsRoot is %s", p.AbsRoot) + } +} + func TestLoadProjectNotFoundErrors(t *testing.T) { tg := test.NewHelper(t) defer tg.Cleanup() From 5a56a598361321d95ad50e6ccf58ed539ead1462 Mon Sep 17 00:00:00 2001 From: Brian Starke Date: Tue, 21 Feb 2017 13:46:27 -0500 Subject: [PATCH 04/12] use filepath join to use correct os.Separator in file path --- context_test.go | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/context_test.go b/context_test.go index f7a6d6abac..c0f4775e7c 100644 --- a/context_test.go +++ b/context_test.go @@ -228,7 +228,7 @@ func TestLoadProjectWithSymlinkedDir(t *testing.T) { t.Fatalf("Error loading project: %s", err) } - if !strings.HasSuffix(p.AbsRoot, "/real/path") { + if !strings.HasSuffix(p.AbsRoot, filepath.Join("real", "path")) { t.Fatalf("Expected AbsRoot to end with '/real/path', AbsRoot is %s", p.AbsRoot) } } From c922a91d2505aa9478987fca9568699ce80dd0c6 Mon Sep 17 00:00:00 2001 From: Brian Starke Date: Sat, 11 Mar 2017 18:41:53 -0500 Subject: [PATCH 05/12] check if real path is within GOPATH before resolving --- context.go | 34 +++++++++++++++++++++-- context_test.go | 72 +++++++++++++++++++++++++++++++------------------ 2 files changed, 78 insertions(+), 28 deletions(-) diff --git a/context.go b/context.go index 5e3d008ab7..2281391211 100644 --- a/context.go +++ b/context.go @@ -78,9 +78,9 @@ func (c *Ctx) LoadProject(path string) (*Project, error) { // the path may lie within a symlinked directory, resolve that // before moving forward - p.AbsRoot, err = filepath.EvalSymlinks(p.AbsRoot) + p.AbsRoot, err = c.resolveProjectRoot(p.AbsRoot) if err != nil { - return nil, errors.Wrapf(err, "eval symlinks") + return nil, errors.Wrapf(err, "resolve project root") } ip, err := c.SplitAbsoluteProjectRoot(p.AbsRoot) @@ -126,6 +126,36 @@ func (c *Ctx) LoadProject(path string) (*Project, error) { return p, nil } +// resolveProjectRoot evaluates the root directory and does the following: +// +// If the passed path is a symlink outside GOPATH to a directory within a +// GOPATH, the resolved full real path is returned. +// +// If the passed path is a symlink within a GOPATH, we return an error. +// +// If the passed path isn't a symlink at all, we just pass through. +func (c *Ctx) resolveProjectRoot(path string) (string, error) { + // Determine if this is a symlink + resolved, err := filepath.EvalSymlinks(path) + if err != nil { + return "", errors.Wrap(err, "resolveProjectRoot") + } + + // Not a symlink, move on + if resolved == path { + return path, nil + } + + // Determine if the symlink is within the GOPATH, in which case we're not + // sure how to resolve it. + if strings.HasPrefix(path, c.GOPATH) { + return "", fmt.Errorf("''%s' is linked to another path within GOPATH", path) + } + + // Return the resolved path + return resolved, nil +} + // SplitAbsoluteProjectRoot takes an absolute path and compares it against declared // GOPATH(s) to determine what portion of the input path should be treated as an // import path - as a project root. diff --git a/context_test.go b/context_test.go index 5dd40fb3c5..a2ea762ad4 100644 --- a/context_test.go +++ b/context_test.go @@ -209,32 +209,6 @@ func TestLoadProject(t *testing.T) { } } -func TestLoadProjectWithSymlinkedDir(t *testing.T) { - tg := test.NewHelper(t) - defer tg.Cleanup() - - tg.TempDir("src") - tg.TempDir("src/real") - tg.TempDir("src/real/path") - tg.TempFile("src/real/path/manifest.json", `{"dependencies":{}}`) - tg.TempFile("src/real/path/lock.json", `{"memo":"cdafe8641b28cd16fe025df278b0a49b9416859345d8b6ba0ace0272b74925ee","projects":[]}`) - tg.Setenv("GOPATH", tg.Path(".")) - ctx := &Ctx{GOPATH: tg.Path(".")} - - symlinkedPath := filepath.Join(ctx.GOPATH, "src", "sympath") - os.Symlink(filepath.Join(ctx.GOPATH, "src/real/path"), symlinkedPath) - - p, err := ctx.LoadProject(symlinkedPath) - - if err != nil { - t.Fatalf("Error loading project: %s", err) - } - - if !strings.HasSuffix(p.AbsRoot, filepath.Join("real", "path")) { - t.Fatalf("Expected AbsRoot to end with '/real/path', AbsRoot is %s", p.AbsRoot) - } -} - func TestLoadProjectNotFoundErrors(t *testing.T) { tg := test.NewHelper(t) defer tg.Cleanup() @@ -373,3 +347,49 @@ func TestCaseInsentitiveGOPATH(t *testing.T) { t.Fatalf("expected %s, got %s", ip, pr) } } + +func TestResolveProjectRoot(t *testing.T) { + tg := test.NewHelper(t) + defer tg.Cleanup() + + tg.TempDir("go") + tg.TempDir("go/src") + tg.TempDir("sym") + tg.TempDir("go/src/real") + tg.TempDir("go/src/real/path") + tg.TempDir("go/src/sym") + + tg.Setenv("GOPATH", tg.Path(filepath.Join(".", "go"))) + + ctx := &Ctx{GOPATH: tg.Path(filepath.Join(".", "go"))} + + realPath := filepath.Join(ctx.GOPATH, "src/real/path") + symlinkedPath := filepath.Join(tg.Path("."), "sym", "symlink") + symlinkedInGoPath := filepath.Join(ctx.GOPATH, "src/sym/path") + os.Symlink(realPath, symlinkedPath) + os.Symlink(realPath, symlinkedInGoPath) + + // Real path should be returned, no symlinks to deal with + p, err := ctx.resolveProjectRoot(realPath) + if err != nil { + t.Fatalf("Error resolving project root: %s", err) + } + if p != realPath { + t.Fatalf("Expected path to be %s, got %s", realPath, p) + } + + // Real path should be returned, symlink is outside GOPATH + p, err = ctx.resolveProjectRoot(symlinkedPath) + if err != nil { + t.Fatalf("Error resolving project root: %s", err) + } + if p != realPath { + t.Fatalf("Expected path to be %s, got %s", realPath, p) + } + + // Sylinked path is inside GOPATH, should return error + _, err = ctx.resolveProjectRoot(symlinkedInGoPath) + if err == nil { + t.Fatalf("Expected an error") + } +} From ab79f83fea0cb36fa97fa40ae97a1869fe5dc1ed Mon Sep 17 00:00:00 2001 From: Brian Starke Date: Tue, 14 Mar 2017 14:58:47 -0400 Subject: [PATCH 06/12] fixes from review, added lstat passthrough --- context.go | 16 +++++++++++----- context_test.go | 6 +++--- 2 files changed, 14 insertions(+), 8 deletions(-) diff --git a/context.go b/context.go index 2281391211..b2373b19b8 100644 --- a/context.go +++ b/context.go @@ -135,20 +135,26 @@ func (c *Ctx) LoadProject(path string) (*Project, error) { // // If the passed path isn't a symlink at all, we just pass through. func (c *Ctx) resolveProjectRoot(path string) (string, error) { - // Determine if this is a symlink - resolved, err := filepath.EvalSymlinks(path) + // Determine if this path is a Symlink + l, err := os.Lstat(path) if err != nil { return "", errors.Wrap(err, "resolveProjectRoot") } - // Not a symlink, move on - if resolved == path { + // Pass through if not + if l.Mode()&os.ModeSymlink == 0 { return path, nil } + // Resolve path + resolved, err := filepath.EvalSymlinks(path) + if err != nil { + return "", errors.Wrap(err, "resolveProjectRoot") + } + // Determine if the symlink is within the GOPATH, in which case we're not // sure how to resolve it. - if strings.HasPrefix(path, c.GOPATH) { + if filepath.HasPrefix(path, c.GOPATH) { return "", fmt.Errorf("''%s' is linked to another path within GOPATH", path) } diff --git a/context_test.go b/context_test.go index a2ea762ad4..b6fe61a225 100644 --- a/context_test.go +++ b/context_test.go @@ -375,7 +375,7 @@ func TestResolveProjectRoot(t *testing.T) { t.Fatalf("Error resolving project root: %s", err) } if p != realPath { - t.Fatalf("Expected path to be %s, got %s", realPath, p) + t.Fatalf("Want path to be %s, got %s", realPath, p) } // Real path should be returned, symlink is outside GOPATH @@ -384,10 +384,10 @@ func TestResolveProjectRoot(t *testing.T) { t.Fatalf("Error resolving project root: %s", err) } if p != realPath { - t.Fatalf("Expected path to be %s, got %s", realPath, p) + t.Fatalf("Want path to be %s, got %s", realPath, p) } - // Sylinked path is inside GOPATH, should return error + // Symlinked path is inside GOPATH, should return error _, err = ctx.resolveProjectRoot(symlinkedInGoPath) if err == nil { t.Fatalf("Expected an error") From 4e3205d7554b64a1e690ca2d5fb6321c683570dc Mon Sep 17 00:00:00 2001 From: Brian Starke Date: Thu, 6 Apr 2017 16:46:03 -0400 Subject: [PATCH 07/12] check all GOPATHS --- context.go | 27 +++++++++++++++++++-------- 1 file changed, 19 insertions(+), 8 deletions(-) diff --git a/context.go b/context.go index b2373b19b8..f09c09e8b3 100644 --- a/context.go +++ b/context.go @@ -18,7 +18,8 @@ import ( // Ctx defines the supporting context of the tool. type Ctx struct { - GOPATH string // Go path + GOPATH string // Selected Go path + GOPATHS []string // Other Go paths } // NewContext creates a struct with the project's GOPATH. It assumes @@ -32,14 +33,23 @@ func NewContext() (*Ctx, error) { return nil, errors.Wrap(err, "getting work directory") } wd = filepath.FromSlash(wd) + ctx := &Ctx{} + for _, gp := range filepath.SplitList(buildContext.GOPATH) { gp = filepath.FromSlash(gp) + if filepath.HasPrefix(wd, gp) { - return &Ctx{GOPATH: gp}, nil + ctx.GOPATH = gp } + + ctx.GOPATHS = append(ctx.GOPATHS, gp) } - return nil, errors.New("project not in a GOPATH") + if ctx.GOPATH == "" { + return nil, errors.New("project not in a GOPATH") + } + + return ctx, nil } func (c *Ctx) SourceManager() (*gps.SourceMgr, error) { @@ -76,7 +86,7 @@ func (c *Ctx) LoadProject(path string) (*Project, error) { return nil, err } - // the path may lie within a symlinked directory, resolve that + // The path may lie within a symlinked directory, resolve the path // before moving forward p.AbsRoot, err = c.resolveProjectRoot(p.AbsRoot) if err != nil { @@ -152,13 +162,14 @@ func (c *Ctx) resolveProjectRoot(path string) (string, error) { return "", errors.Wrap(err, "resolveProjectRoot") } - // Determine if the symlink is within the GOPATH, in which case we're not + // Determine if the symlink is within and of the GOPATHs, in which case we're not // sure how to resolve it. - if filepath.HasPrefix(path, c.GOPATH) { - return "", fmt.Errorf("''%s' is linked to another path within GOPATH", path) + for _, gp := range c.GOPATHS { + if filepath.HasPrefix(path, gp) { + return "", fmt.Errorf("''%s' is linked to another path within GOPATH", path) + } } - // Return the resolved path return resolved, nil } From f5c52ec2ef4ad160f65b1d2f3d3824d7c5f2e49b Mon Sep 17 00:00:00 2001 From: Brian Starke Date: Thu, 6 Apr 2017 16:50:44 -0400 Subject: [PATCH 08/12] clearer error message --- context.go | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/context.go b/context.go index f09c09e8b3..9fd2751e96 100644 --- a/context.go +++ b/context.go @@ -162,11 +162,11 @@ func (c *Ctx) resolveProjectRoot(path string) (string, error) { return "", errors.Wrap(err, "resolveProjectRoot") } - // Determine if the symlink is within and of the GOPATHs, in which case we're not + // Determine if the symlink is within any of the GOPATHs, in which case we're not // sure how to resolve it. for _, gp := range c.GOPATHS { if filepath.HasPrefix(path, gp) { - return "", fmt.Errorf("''%s' is linked to another path within GOPATH", path) + return "", fmt.Errorf("''%s' is linked to another path within a GOPATH (%s)", path, gp) } } From 0628b80684b019c9a737801f67381f2400b69d48 Mon Sep 17 00:00:00 2001 From: Brian Starke Date: Thu, 6 Apr 2017 16:54:22 -0400 Subject: [PATCH 09/12] remove extra quotation mark --- context.go | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/context.go b/context.go index 9fd2751e96..3541540b2c 100644 --- a/context.go +++ b/context.go @@ -166,7 +166,7 @@ func (c *Ctx) resolveProjectRoot(path string) (string, error) { // sure how to resolve it. for _, gp := range c.GOPATHS { if filepath.HasPrefix(path, gp) { - return "", fmt.Errorf("''%s' is linked to another path within a GOPATH (%s)", path, gp) + return "", fmt.Errorf("'%s' is linked to another path within a GOPATH (%s)", path, gp) } } From f569ebc39c822b7ce9973691d01f08c085ce9e84 Mon Sep 17 00:00:00 2001 From: Brian Starke Date: Thu, 6 Apr 2017 17:10:53 -0400 Subject: [PATCH 10/12] Forgot to commit test updates --- context_test.go | 9 +++++++-- 1 file changed, 7 insertions(+), 2 deletions(-) diff --git a/context_test.go b/context_test.go index b6fe61a225..bacc375d03 100644 --- a/context_test.go +++ b/context_test.go @@ -361,7 +361,12 @@ func TestResolveProjectRoot(t *testing.T) { tg.Setenv("GOPATH", tg.Path(filepath.Join(".", "go"))) - ctx := &Ctx{GOPATH: tg.Path(filepath.Join(".", "go"))} + ctx := &Ctx{ + GOPATH: tg.Path(filepath.Join(".", "go")), + GOPATHS: []string{ + tg.Path(filepath.Join(".", "go")), + }, + } realPath := filepath.Join(ctx.GOPATH, "src/real/path") symlinkedPath := filepath.Join(tg.Path("."), "sym", "symlink") @@ -390,6 +395,6 @@ func TestResolveProjectRoot(t *testing.T) { // Symlinked path is inside GOPATH, should return error _, err = ctx.resolveProjectRoot(symlinkedInGoPath) if err == nil { - t.Fatalf("Expected an error") + t.Fatalf("Wanted an error") } } From c2deecc8e6555d81510882a80ae788f058afd663 Mon Sep 17 00:00:00 2001 From: Brian Starke Date: Thu, 6 Apr 2017 17:30:32 -0400 Subject: [PATCH 11/12] use errors package instead of fmt --- context.go | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/context.go b/context.go index 12e2615aba..2e1c800255 100644 --- a/context.go +++ b/context.go @@ -165,7 +165,7 @@ func (c *Ctx) resolveProjectRoot(path string) (string, error) { // sure how to resolve it. for _, gp := range c.GOPATHS { if filepath.HasPrefix(path, gp) { - return "", fmt.Errorf("'%s' is linked to another path within a GOPATH (%s)", path, gp) + return "", errors.Errorf("'%s' is linked to another path within a GOPATH (%s)", path, gp) } } From 753c8dd9d664e77eebc6c1e71576ef58d25e5363 Mon Sep 17 00:00:00 2001 From: Brian Starke Date: Mon, 10 Apr 2017 17:58:07 -0400 Subject: [PATCH 12/12] Add test case for multiple GOPATH situation --- context_test.go | 24 ++++++++++++++++++++++-- 1 file changed, 22 insertions(+), 2 deletions(-) diff --git a/context_test.go b/context_test.go index bacc375d03..753d05c863 100644 --- a/context_test.go +++ b/context_test.go @@ -354,25 +354,36 @@ func TestResolveProjectRoot(t *testing.T) { tg.TempDir("go") tg.TempDir("go/src") - tg.TempDir("sym") tg.TempDir("go/src/real") tg.TempDir("go/src/real/path") tg.TempDir("go/src/sym") + tg.TempDir("gotwo") // Another directory used as a GOPATH + tg.TempDir("gotwo/src") + tg.TempDir("gotwo/src/real") + tg.TempDir("gotwo/src/real/path") + tg.TempDir("gotwo/src/sym") + + tg.TempDir("sym") // Directory for symlinks + tg.Setenv("GOPATH", tg.Path(filepath.Join(".", "go"))) ctx := &Ctx{ GOPATH: tg.Path(filepath.Join(".", "go")), GOPATHS: []string{ tg.Path(filepath.Join(".", "go")), + tg.Path(filepath.Join(".", "gotwo")), }, } - realPath := filepath.Join(ctx.GOPATH, "src/real/path") + realPath := filepath.Join(ctx.GOPATH, "src", "real", "path") + realPathTwo := filepath.Join(ctx.GOPATHS[1], "src", "real", "path") symlinkedPath := filepath.Join(tg.Path("."), "sym", "symlink") symlinkedInGoPath := filepath.Join(ctx.GOPATH, "src/sym/path") + symlinkedInOtherGoPath := filepath.Join(tg.Path("."), "sym", "symtwo") os.Symlink(realPath, symlinkedPath) os.Symlink(realPath, symlinkedInGoPath) + os.Symlink(realPathTwo, symlinkedInOtherGoPath) // Real path should be returned, no symlinks to deal with p, err := ctx.resolveProjectRoot(realPath) @@ -392,6 +403,15 @@ func TestResolveProjectRoot(t *testing.T) { t.Fatalf("Want path to be %s, got %s", realPath, p) } + // Real path should be returned, symlink is in another GOPATH + p, err = ctx.resolveProjectRoot(symlinkedInOtherGoPath) + if err != nil { + t.Fatalf("Error resolving project root: %s", err) + } + if p != realPathTwo { + t.Fatalf("Want path to be %s, got %s", realPathTwo, p) + } + // Symlinked path is inside GOPATH, should return error _, err = ctx.resolveProjectRoot(symlinkedInGoPath) if err == nil {