diff --git a/src/cmd/go/internal/load/pkg.go b/src/cmd/go/internal/load/pkg.go index 360d265de6..41afa42f0f 100644 --- a/src/cmd/go/internal/load/pkg.go +++ b/src/cmd/go/internal/load/pkg.go @@ -2203,6 +2203,10 @@ func (p *Package) collectDeps() { } } +// vcsStatusCache maps repository directories (string) +// to their VCS information (vcsStatusError). +var vcsStatusCache par.Cache + // setBuildInfo gathers build information, formats it as a string to be // embedded in the binary, then sets p.Internal.BuildInfo to that string. // setBuildInfo should only be called on a main package with no errors. @@ -2365,11 +2369,20 @@ func (p *Package) setBuildInfo() { return } - st, err := vcsCmd.Status(vcsCmd, repoDir) - if err != nil { + type vcsStatusError struct { + Status vcs.Status + Err error + } + cached := vcsStatusCache.Do(repoDir, func() interface{} { + st, err := vcsCmd.Status(vcsCmd, repoDir) + return vcsStatusError{st, err} + }).(vcsStatusError) + if err := cached.Err; err != nil { setVCSError(err) return } + st := cached.Status + if st.Revision != "" { appendSetting(vcsCmd.Cmd+"revision", st.Revision) } diff --git a/src/cmd/go/testdata/script/version_buildvcs_git.txt b/src/cmd/go/testdata/script/version_buildvcs_git.txt index 3d56c6d8b4..72cbe28285 100644 --- a/src/cmd/go/testdata/script/version_buildvcs_git.txt +++ b/src/cmd/go/testdata/script/version_buildvcs_git.txt @@ -16,6 +16,7 @@ rm $GOBIN/a$GOEXE # If there is a repository, but it can't be used for some reason, # there should be an error. It should hint about -buildvcs=false. +# Also ensure that multiple errors are collected by "go list -e". cd .. mkdir .git env PATH=$WORK${/}fakebin${:}$oldpath @@ -24,6 +25,10 @@ chmod 0755 $WORK/fakebin/git cd a ! go install stderr '^error obtaining VCS status: exit status 1\n\tUse -buildvcs=false to disable VCS stamping.$' +go list -e -f '{{.ImportPath}}: {{.Error}}' ./... +stdout -count=1 '^example\.com/a: error obtaining VCS status' +stdout -count=1 '^example\.com/a/library: ' +stdout -count=1 '^example\.com/a/othermain: error obtaining VCS status' cd .. env PATH=$oldpath rm .git @@ -99,6 +104,14 @@ go version -m $GOBIN/d$GOEXE exec git checkout go.mod rm $GOBIN/d$GOEXE +# If we're loading multiple main packages, +# but they share the same VCS repository, +# we only need to execute VCS status commands once. +go list -x ./... +stdout -count=3 '^example.com' +stderr -count=1 '^git status' +stderr -count=1 '^git show' + -- $WORK/fakebin/git -- #!/bin/sh exit 1 @@ -114,6 +127,12 @@ go 1.18 -- repo/a/a.go -- package main +func main() {} +-- repo/a/library/f.go -- +package library +-- repo/a/othermain/f.go -- +package main + func main() {} -- repo/b/go.mod -- module example.com/b