From 2d37a46e4d1de12bfc88914b290ecfc883ced477 Mon Sep 17 00:00:00 2001 From: Tim Waugh Date: Fri, 18 Jan 2019 12:13:42 +0000 Subject: [PATCH 1/4] Re-factor template processing Previously the template string was being compiled every time it was used. Instead, compile it only once at the start, then use the compiled template each time it is needed. Signed-off-by: Tim Waugh --- main.go | 33 ++++++++------ retrodep/display.go | 15 ------ retrodep/display_test.go | 99 ---------------------------------------- 3 files changed, 20 insertions(+), 127 deletions(-) delete mode 100644 retrodep/display.go delete mode 100644 retrodep/display_test.go diff --git a/main.go b/main.go index 754d4af2..7847a5a1 100644 --- a/main.go +++ b/main.go @@ -19,6 +19,7 @@ import ( "bufio" "flag" "fmt" + "text/template" "io/ioutil" "os" "path/filepath" @@ -29,6 +30,8 @@ import ( "github.com/release-engineering/retrodep/retrodep" ) +const defaultTemplate string = "{{if .Rev}}@{{.Rev}}{{end}}{{if .Tag}} ={{.Tag}}{{end}}{{if .Ver}} ~{{.Ver}}{{end}}" + var log = logging.MustGetLogger("retrodep") var helpFlag = flag.Bool("help", false, "print help") @@ -37,7 +40,7 @@ var onlyImportPath = flag.Bool("only-importpath", false, "only show the top-leve var depsFlag = flag.Bool("deps", true, "show vendored dependencies") var excludeFrom = flag.String("exclude-from", "", "ignore directory entries matching globs in `exclusions`") var debugFlag = flag.Bool("debug", false, "show debugging output") -var template = flag.String("template", "", "go template to use for output with Repo, Rev, Tag and Ver") +var templateArg = flag.String("template", "", "go template to use for output with Repo, Rev, Tag and Ver") var exitFirst = flag.Bool("x", false, "exit on the first failure") var errorShown = false @@ -53,14 +56,10 @@ func displayUnknown(name string) { } } -func display(template string, name string, ref *retrodep.Reference) { +func display(tmpl *template.Template, name string, ref *retrodep.Reference) { var builder strings.Builder builder.WriteString(name) - var tmpl, err = retrodep.Display(template) - if err != nil { - log.Fatalf("Error parsing supplied template. %s ", err) - } - err = tmpl.Execute(&builder, ref) + err := tmpl.Execute(&builder, ref) if err != nil { log.Fatalf("Error generating output. %s ", err) } @@ -82,20 +81,20 @@ func getProject(src *retrodep.GoSource, importPath string) *retrodep.RepoPath { return main } -func showTopLevel(src *retrodep.GoSource) { +func showTopLevel(tmpl *template.Template, src *retrodep.GoSource) { main := getProject(src, *importPath) project, err := src.DescribeProject(main, src.Path) switch err { case retrodep.ErrorVersionNotFound: displayUnknown("*" + main.Root) case nil: - display(*template, "*"+main.Root, project) + display(tmpl, "*"+main.Root, project) default: log.Fatalf("%s: %s", src.Path, err) } } -func showVendored(src *retrodep.GoSource) { +func showVendored(tmpl *template.Template, src *retrodep.GoSource) { vendored, err := src.VendoredProjects() if err != nil { log.Fatal(err) @@ -116,7 +115,7 @@ func showVendored(src *retrodep.GoSource) { case retrodep.ErrorVersionNotFound: displayUnknown(project.Root) case nil: - display(*template, project.Root, vp) + display(tmpl, project.Root, vp) default: log.Fatalf("%s: %s\n", project.Root, err) } @@ -198,14 +197,22 @@ func processArgs(args []string) []*retrodep.GoSource { func main() { srcs := processArgs(os.Args) + customTemplate := *templateArg + if customTemplate == "" { + customTemplate = defaultTemplate + } + tmpl, err := template.New("output").Parse(customTemplate) + if err != nil { + log.Fatal(err) + } for _, src := range srcs { if *onlyImportPath { main := getProject(src, *importPath) fmt.Println("*" + main.Root) } else { - showTopLevel(src) + showTopLevel(tmpl, src) if *depsFlag { - showVendored(src) + showVendored(tmpl, src) } } } diff --git a/retrodep/display.go b/retrodep/display.go deleted file mode 100644 index 240905d3..00000000 --- a/retrodep/display.go +++ /dev/null @@ -1,15 +0,0 @@ -package retrodep - -import ( - "text/template" -) - -const defaultTemplate string = "{{if .Rev}}@{{.Rev}}{{end}}{{if .Tag}} ={{.Tag}}{{end}}{{if .Ver}} ~{{.Ver}}{{end}}" - -//Display a Reference using a template -func Display(customTemplate string) (*template.Template, error) { - if customTemplate == "" { - customTemplate = defaultTemplate - } - return template.New("output").Parse(customTemplate) -} diff --git a/retrodep/display_test.go b/retrodep/display_test.go deleted file mode 100644 index 134ab1d7..00000000 --- a/retrodep/display_test.go +++ /dev/null @@ -1,99 +0,0 @@ -package retrodep - -import ( - "fmt" - "strings" - "testing" -) - -func TestDisplayDefault(t *testing.T) { - const expected = "@4309345093405934509 =v0.0.1 ~v0.0.0.20181785" - ref := &Reference{Rev: "4309345093405934509", Tag: "v0.0.1", Ver: "v0.0.0.20181785"} - var builder strings.Builder - var tmpl, err = Display("") - if err != nil { - t.Fatal(err) - } - err = tmpl.Execute(&builder, ref) - if err != nil { - t.Fatal(err) - } - if builder.String() != expected { - t.Fatal(fmt.Sprintf("Expected: %s but got: %s", expected, builder.String())) - } -} - -func TestDisplayGarbage(t *testing.T) { - var _, err = Display("{{.") - if err == nil { - t.Fatal("Should have failed with Error") - } -} - -func TestDisplayNoTag(t *testing.T) { - const expected = "@4309345093405934509 ~v0.0.0.20181785" - ref := &Reference{Rev: "4309345093405934509", Ver: "v0.0.0.20181785"} - var builder strings.Builder - tmpl, err := Display("") - if err != nil { - t.Fatal(err) - } - err = tmpl.Execute(&builder, ref) - if err != nil { - t.Fatal(err) - } - if builder.String() != expected { - t.Fatal(fmt.Sprintf("Expected: %s but got: %s", expected, builder.String())) - } -} - -func TestDisplayTemplate(t *testing.T) { - const expected = ":v0.0.0.20181785" - ref := &Reference{Rev: "4309345093405934509", Ver: "v0.0.0.20181785"} - var builder strings.Builder - tmpl, err := Display("{{if .Tag}}:{{.Tag}}{{end}}{{if .Ver}}:{{.Ver}}{{end}}") - if err != nil { - t.Fatal(err) - } - err = tmpl.Execute(&builder, ref) - if err != nil { - t.Fatal(err) - } - if builder.String() != expected { - t.Fatal(fmt.Sprintf("Expected: %s but got: %s", expected, builder.String())) - } -} - -func TestDisplayTemplateElseIf(t *testing.T) { - const expected = ":v0.0.1" - ref := &Reference{Rev: "4309345093405934509", Tag: "v0.0.1", Ver: "v0.0.0.20181785"} - var builder strings.Builder - tmpl, err := Display("{{if .Tag}}:{{.Tag}}{{else if .Rev}}:{{.Rev}}{{end}}") - if err != nil { - t.Fatal(err) - } - err = tmpl.Execute(&builder, ref) - if err != nil { - t.Fatal(err) - } - if builder.String() != expected { - t.Fatal(fmt.Sprintf("Expected: %s but got: %s", expected, builder.String())) - } -} - -func TestDisplayRepo(t *testing.T) { - const repo = "https://github.com/release-engineering/retrodep" - ref := &Reference{Repo: repo} - var builder strings.Builder - tmpl, err := Display("{{.Repo}}") - if err != nil { - t.Fatal(err) - } - err = tmpl.Execute(&builder, ref) - if err != nil { - t.Fatal(err) - } - if builder.String() != repo { - t.Errorf("got %q, want %q", builder.String(), repo) - } -} From f5b768d6df61d6c02f29ffdbb0217aa386c480f3 Mon Sep 17 00:00:00 2001 From: Tim Waugh Date: Fri, 18 Jan 2019 13:47:00 +0000 Subject: [PATCH 2/4] Fix mistaken comment Signed-off-by: Tim Waugh --- retrodep/vendored.go | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/retrodep/vendored.go b/retrodep/vendored.go index e4d1c2b4..6d7cccde 100644 --- a/retrodep/vendored.go +++ b/retrodep/vendored.go @@ -239,7 +239,7 @@ type Reference struct { Tag string // Rev is the upstream revision from which the vendored - // copy was taken. If this is not known Reference is "". + // copy was taken. If this is not known Rev is "". Rev string // Ver is the semantic version or pseudo-version for the From 373af438551fb59c1a687185f2b46bdb8b98c740 Mon Sep 17 00:00:00 2001 From: Tim Waugh Date: Fri, 18 Jan 2019 13:53:07 +0000 Subject: [PATCH 3/4] Add .Pkg field for templating and add it to the default template This commit adds a command line argument -o to control output format. The only defined format is go-template=... which does not add the package name by default, unlike the now-deprecated -template argument which always starts with the package name. Signed-off-by: Tim Waugh --- README.md | 21 +++++++++++---------- main.go | 26 ++++++++++++++++++-------- retrodep/vendored.go | 8 +++++++- 3 files changed, 36 insertions(+), 19 deletions(-) diff --git a/README.md b/README.md index 43c6df4a..5da3c84a 100644 --- a/README.md +++ b/README.md @@ -18,24 +18,25 @@ Running ------- ``` -$ retrodep -h retrodep: help requested usage: retrodep [OPTION]... PATH -debug - show debugging output + show debugging output -deps - show vendored dependencies (default true) - -exclude-from string - ignore glob patterns listed in provided file + show vendored dependencies (default true) + -exclude-from exclusions + ignore directory entries matching globs in exclusions -help - print help + print help -importpath string - top-level import path + top-level import path + -o string + output format, one of: go-template=... -only-importpath - only show the top-level import path + only show the top-level import path -template string - go template to use for output with Repo, Rev, Tag and Ver - -x exit on the first failure + go template to use for output with Pkg, Repo, Rev, Tag and Ver (deprecated) + -x exit on the first failure ``` In many cases retrodep can work out the import path for the top-level project. In those cases, simply supply the directory name to examine: diff --git a/main.go b/main.go index 7847a5a1..7ed53fac 100644 --- a/main.go +++ b/main.go @@ -19,18 +19,18 @@ import ( "bufio" "flag" "fmt" - "text/template" "io/ioutil" "os" "path/filepath" "sort" "strings" + "text/template" "github.com/op/go-logging" "github.com/release-engineering/retrodep/retrodep" ) -const defaultTemplate string = "{{if .Rev}}@{{.Rev}}{{end}}{{if .Tag}} ={{.Tag}}{{end}}{{if .Ver}} ~{{.Ver}}{{end}}" +const defaultTemplate string = "{{.Pkg}}{{if .Rev}}@{{.Rev}}{{end}}{{if .Tag}} ={{.Tag}}{{end}}{{if .Ver}} ~{{.Ver}}{{end}}" var log = logging.MustGetLogger("retrodep") @@ -40,10 +40,12 @@ var onlyImportPath = flag.Bool("only-importpath", false, "only show the top-leve var depsFlag = flag.Bool("deps", true, "show vendored dependencies") var excludeFrom = flag.String("exclude-from", "", "ignore directory entries matching globs in `exclusions`") var debugFlag = flag.Bool("debug", false, "show debugging output") -var templateArg = flag.String("template", "", "go template to use for output with Repo, Rev, Tag and Ver") +var outputArg = flag.String("o", "", "output format, one of: go-template=...") +var templateArg = flag.String("template", "", "go template to use for output with Pkg, Repo, Rev, Tag and Ver (deprecated)") var exitFirst = flag.Bool("x", false, "exit on the first failure") var errorShown = false +var usage func(string) func displayUnknown(name string) { fmt.Printf("%s ?\n", name) @@ -88,7 +90,7 @@ func showTopLevel(tmpl *template.Template, src *retrodep.GoSource) { case retrodep.ErrorVersionNotFound: displayUnknown("*" + main.Root) case nil: - display(tmpl, "*"+main.Root, project) + display(tmpl, "*", project) default: log.Fatalf("%s: %s", src.Path, err) } @@ -115,7 +117,7 @@ func showVendored(tmpl *template.Template, src *retrodep.GoSource) { case retrodep.ErrorVersionNotFound: displayUnknown(project.Root) case nil: - display(tmpl, project.Root, vp) + display(tmpl, "", vp) default: log.Fatalf("%s: %s\n", project.Root, err) } @@ -152,7 +154,7 @@ func processArgs(args []string) []*retrodep.GoSource { cli.Usage = func() {} usageMsg := fmt.Sprintf("usage: %s [OPTION]... PATH", progName) - usage := func(flaw string) { + usage = func(flaw string) { log.Fatalf("%s: %s\n%s\n", progName, flaw, usageMsg) } err := cli.Parse(args[1:]) @@ -197,8 +199,16 @@ func processArgs(args []string) []*retrodep.GoSource { func main() { srcs := processArgs(os.Args) - customTemplate := *templateArg - if customTemplate == "" { + var customTemplate string + switch { + case *outputArg != "": + customTemplate = strings.TrimPrefix(*outputArg, "go-template=") + if customTemplate == *outputArg { + usage("unknown output format") + } + case *templateArg != "": + customTemplate = "{{.Pkg}}" + *templateArg + default: customTemplate = defaultTemplate } tmpl, err := template.New("output").Parse(customTemplate) diff --git a/retrodep/vendored.go b/retrodep/vendored.go index 6d7cccde..3a3fa10c 100644 --- a/retrodep/vendored.go +++ b/retrodep/vendored.go @@ -1,4 +1,4 @@ -// Copyright (C) 2018 Tim Waugh +// Copyright (C) 2018, 2019 Tim Waugh // // This program is free software: you can redistribute it and/or modify // it under the terms of the GNU General Public License as published by @@ -230,6 +230,9 @@ func matchFromRefs(strip bool, hashes *FileHashes, wt WorkingTree, subPath strin // Reference describes the origin of a vendored project. type Reference struct { + // Pkg is the name of the vendored package. + Pkg string + // Repo is the URL for the repository holding the source code. Repo string @@ -335,6 +338,7 @@ func (src GoSource) DescribeProject(project *RepoPath, dir string) (*Reference, } return &Reference{ + Pkg: project.Root, Repo: project.Repo, Rev: match, Ver: ver, @@ -364,6 +368,7 @@ func (src GoSource) DescribeProject(project *RepoPath, dir string) (*Reference, } return &Reference{ + Pkg: project.Root, Repo: project.Repo, Tag: match, Rev: rev, @@ -395,6 +400,7 @@ func (src GoSource) DescribeProject(project *RepoPath, dir string) (*Reference, } return &Reference{ + Pkg: project.Root, Repo: project.Repo, Rev: rev, Ver: ver, From b648bc0c0057f78c81eb6d2827dc19ff5e7c33b7 Mon Sep 17 00:00:00 2001 From: Tim Waugh Date: Tue, 22 Jan 2019 15:40:40 +0000 Subject: [PATCH 4/4] Add .TopPkg and TopVer fields for templating, and to default template Signed-off-by: Tim Waugh --- README.md | 29 +++++++++++---------- main.go | 28 +++++++++++++------- retrodep/vendored.go | 61 +++++++++++++++++++++++++++++++------------- 3 files changed, 77 insertions(+), 41 deletions(-) diff --git a/README.md b/README.md index 5da3c84a..9004f7e3 100644 --- a/README.md +++ b/README.md @@ -35,7 +35,7 @@ usage: retrodep [OPTION]... PATH -only-importpath only show the top-level import path -template string - go template to use for output with Pkg, Repo, Rev, Tag and Ver (deprecated) + go template to use for output with Reference fields (deprecated) -x exit on the first failure ``` @@ -69,24 +69,25 @@ Example output -------------- ``` -$ retrodep -importpath github.com/docker/distribution go/src/github.com/docker/distribution -*github.com/docker/distribution@90705d2fb81dda1466be49bd958ed8a0dd9a6145 ~v2.6.0rc.1-1.20180831002537-90705d2fb81d -github.com/opencontainers/image-spec@87998cd070d9e7a2c79f8b153a26bea0425582e5 =v1.0.0 ~v1.0.0 -github.com/ncw/swift@b964f2ca856aac39885e258ad25aec08d5f64ee6 ~v1.0.25-0.20160617142549-b964f2ca856a -golang.org/x/oauth2@2897dcade18a126645f1368de827f1e613a60049 ~v0.0.0-0.20160323192119-2897dcade18a -rsc.io/letsencrypt ? +$ retrodep $GOPATH/src/github.com/docker/distribution +github.com/docker/distribution:v2.7.1 +github.com/docker/distribution:v2.7.1/github.com/Azure/azure-sdk-for-go:v16.2.1 +github.com/docker/distribution:v2.7.1/github.com/Azure/go-autorest:v10.8.1 +github.com/docker/distribution:v2.7.1/github.com/Shopify/logrus-bugsnag:v0.0.0-0.20171204154709-577dee27f20d +github.com/docker/distribution:v2.7.1/github.com/aws/aws-sdk-go:v1.15.11 +github.com/docker/distribution:v2.7.1/github.com/beorn7/perks:v0.0.0-0.20160804124726-4c0e84591b9a +github.com/docker/distribution:v2.7.1/github.com/bshuster-repo/logrus-logstash-hook:0.4 +github.com/docker/distribution:v2.7.1/github.com/bugsnag/bugsnag-go:v1.0.3-0.20150204195350-f36a9b3a9e01 ... ``` In this example, -* github.com/docker/distribution is the top-level repository (indicated by \*) -* github.com/opencontainers/image-spec had a matching semantic version tag (v1.0.0) -* github.com/ncw/swift's matching commit had semantic version tag v1.0.24 reachable (so the next patch version would be v1.0.25) -* golang.org/x/oauth2 had a matching commit but no reachable semantic version tag -* rsc.io/letsencrypt had no matching commit (because the vendored source was from a fork) -* for github.com/docker/distribution, tag v2.6.0rc.1 was reachable from the matching commit (note, 1.timestamp instead of 0.timestamp) - +* github.com/docker/distribution is the top-level package, and the upstream semantic version tag v2.7.1 matches +* github.com/Azure/azure-sdk-for-go etc are vendored dependencies of distribution +* github.com/Azure/azure-sdk-for-go, github.com/Azure/go-autorest, github.com/aws/awk-sdk-go, and github.com/bshuster-repo/logrus-logstash-hook all had matches with upstream semantic version tags +* github.com/bugsnag/bugsnag-go matched a commit from which tag v1.0.2 was reachable (note: v1.0.2, not v1.0.3 -- see below) +* github.com/beorn7/perks matched a commit from which there were no reachable semantic version tags Pseudo-versions --------------- diff --git a/main.go b/main.go index 7ed53fac..0cb0936b 100644 --- a/main.go +++ b/main.go @@ -30,7 +30,7 @@ import ( "github.com/release-engineering/retrodep/retrodep" ) -const defaultTemplate string = "{{.Pkg}}{{if .Rev}}@{{.Rev}}{{end}}{{if .Tag}} ={{.Tag}}{{end}}{{if .Ver}} ~{{.Ver}}{{end}}" +const defaultTemplate string = "{{if .TopPkg}}{{.TopPkg}}:{{.TopVer}}/{{end}}{{.Pkg}}:{{.Ver}}" var log = logging.MustGetLogger("retrodep") @@ -83,20 +83,30 @@ func getProject(src *retrodep.GoSource, importPath string) *retrodep.RepoPath { return main } -func showTopLevel(tmpl *template.Template, src *retrodep.GoSource) { +func showTopLevel(tmpl *template.Template, src *retrodep.GoSource) *retrodep.Reference { main := getProject(src, *importPath) - project, err := src.DescribeProject(main, src.Path) + project, err := src.DescribeProject(main, src.Path, nil) + var topLevelMarker string + if *templateArg != "" { + topLevelMarker = "*" + } switch err { case retrodep.ErrorVersionNotFound: - displayUnknown("*" + main.Root) + displayUnknown(topLevelMarker + main.Root) case nil: - display(tmpl, "*", project) + display(tmpl, topLevelMarker, project) default: log.Fatalf("%s: %s", src.Path, err) } + + if err != nil { + return nil + } + + return project } -func showVendored(tmpl *template.Template, src *retrodep.GoSource) { +func showVendored(tmpl *template.Template, src *retrodep.GoSource, top *retrodep.Reference) { vendored, err := src.VendoredProjects() if err != nil { log.Fatal(err) @@ -112,7 +122,7 @@ func showVendored(tmpl *template.Template, src *retrodep.GoSource) { // Describe each vendored project for _, repo := range repos { project := vendored[repo] - vp, err := src.DescribeVendoredProject(project) + vp, err := src.DescribeVendoredProject(project, top) switch err { case retrodep.ErrorVersionNotFound: displayUnknown(project.Root) @@ -220,9 +230,9 @@ func main() { main := getProject(src, *importPath) fmt.Println("*" + main.Root) } else { - showTopLevel(tmpl, src) + top := showTopLevel(tmpl, src) if *depsFlag { - showVendored(tmpl, src) + showVendored(tmpl, src, top) } } } diff --git a/retrodep/vendored.go b/retrodep/vendored.go index 3a3fa10c..991491bd 100644 --- a/retrodep/vendored.go +++ b/retrodep/vendored.go @@ -230,7 +230,15 @@ func matchFromRefs(strip bool, hashes *FileHashes, wt WorkingTree, subPath strin // Reference describes the origin of a vendored project. type Reference struct { - // Pkg is the name of the vendored package. + // TopPkg is the name of the top-level package this package is + // vendored into, or "" if Pkg is the top-level package. + TopPkg string + + // TopVer is the Ver string (see below) for the TopPkg, if + // defined. + TopVer string + + // Pkg is the name of the package this Reference relates to. Pkg string // Repo is the URL for the repository holding the source code. @@ -273,8 +281,13 @@ func chooseBestTag(tags []string) string { // DescribeProject attempts to identify the tag in the version control // system which corresponds to the project, based on comparison with // files in dir. Vendored files and files whose names begin with "." -// are ignored. -func (src GoSource) DescribeProject(project *RepoPath, dir string) (*Reference, error) { +// are ignored. If top is not nil, it should be a Reference to the +// top-level package this project is vendored into. +func (src GoSource) DescribeProject( + project *RepoPath, + dir string, + top *Reference, +) (*Reference, error) { wt, err := NewWorkingTree(&project.RepoRoot) if err != nil { return nil, err @@ -323,6 +336,12 @@ func (src GoSource) DescribeProject(project *RepoPath, dir string) (*Reference, // project). strip := src.usesGodep && dir != src.Path + var toppkg, topver string + if top != nil { + toppkg = top.Pkg + topver = top.Ver + } + // First try to match against a specific version, if specified if project.Version != "" { matches, err := matchFromRefs(strip, hashes, wt, @@ -338,10 +357,12 @@ func (src GoSource) DescribeProject(project *RepoPath, dir string) (*Reference, } return &Reference{ - Pkg: project.Root, - Repo: project.Repo, - Rev: match, - Ver: ver, + TopPkg: toppkg, + TopVer: topver, + Pkg: project.Root, + Repo: project.Repo, + Rev: match, + Ver: ver, }, nil case ErrorVersionNotFound: // No match, carry on @@ -368,11 +389,13 @@ func (src GoSource) DescribeProject(project *RepoPath, dir string) (*Reference, } return &Reference{ - Pkg: project.Root, - Repo: project.Repo, - Tag: match, - Rev: rev, - Ver: match, + TopPkg: toppkg, + TopVer: topver, + Pkg: project.Root, + Repo: project.Repo, + Tag: match, + Rev: rev, + Ver: match, }, nil case ErrorVersionNotFound: // No match, carry on @@ -400,19 +423,21 @@ func (src GoSource) DescribeProject(project *RepoPath, dir string) (*Reference, } return &Reference{ - Pkg: project.Root, - Repo: project.Repo, - Rev: rev, - Ver: ver, + TopPkg: toppkg, + TopVer: topver, + Pkg: project.Root, + Repo: project.Repo, + Rev: rev, + Ver: ver, }, nil } // DescribeVendoredProject attempts to identify the tag in the version // control system which corresponds to the vendored copy of the // project. -func (src GoSource) DescribeVendoredProject(project *RepoPath) (*Reference, error) { +func (src GoSource) DescribeVendoredProject(project *RepoPath, top *Reference) (*Reference, error) { projRootImportPath := filepath.FromSlash(project.Root) projDir := filepath.Join(src.Vendor(), projRootImportPath) - ref, err := src.DescribeProject(project, projDir) + ref, err := src.DescribeProject(project, projDir, top) return ref, err }