Skip to content

Commit

Permalink
cmd/go/internal/modload: cache the Go language version for each modul…
Browse files Browse the repository at this point in the history
…e globally

Previously, this cache was a member of the (ephemeral) modload.loader
struct. However, the Go language version for a given module version
does not vary based on the build list, the set of loaded packages, the
build tags in use, the meaning of the "all" pattern, or anything else
that can be configured for an instance of the package loader. The map
containing that information is therefore not appropriate as a field of
the (configurable, package-list-dependent) loader struct.

The Go language version mapping could, in theory, be read from the
go.mod file in the module cache (or replacement directory) every time
it is needed: this map is just a cache, and as such it belongs
alongside the other caches and indexes in the modload package, which
are currently found in modfile.go.

We may want to do the same sort of global caching for the mapping from
each module.Version to its list of direct requirements (which are
similarly idempotent), but for now that is left for a future change.

For #36460
For #36876

Change-Id: I90ac176ffea97f30c47d6540c3dfb874dc9cfa4f
Reviewed-on: https://go-review.googlesource.com/c/go/+/244078
Reviewed-by: Jay Conrod <jayconrod@google.com>
Reviewed-by: Michael Matloob <matloob@golang.org>
  • Loading branch information
Bryan C. Mills committed Aug 24, 2020
1 parent c777863 commit 2a9636d
Show file tree
Hide file tree
Showing 4 changed files with 21 additions and 19 deletions.
15 changes: 10 additions & 5 deletions src/cmd/go/internal/modload/build.go
Original file line number Diff line number Diff line change
Expand Up @@ -126,8 +126,8 @@ func moduleInfo(ctx context.Context, m module.Version, fromBuildList bool) *modi
Version: m.Version,
Indirect: fromBuildList && loaded != nil && !loaded.direct[m.Path],
}
if loaded != nil {
info.GoVersion = loaded.goVersion[m.Path]
if v, ok := rawGoVersion.Load(m); ok {
info.GoVersion = v.(string)
}

// completeFromModCache fills in the extra fields in m using the module cache.
Expand Down Expand Up @@ -155,6 +155,8 @@ func moduleInfo(ctx context.Context, m module.Version, fromBuildList bool) *modi
}

if !fromBuildList {
// If this was an explicitly-versioned argument to 'go mod download' or
// 'go list -m', report the actual requested version, not its replacement.
completeFromModCache(info) // Will set m.Error in vendor mode.
return info
}
Expand All @@ -178,9 +180,12 @@ func moduleInfo(ctx context.Context, m module.Version, fromBuildList bool) *modi
// worth the cost, and we're going to overwrite the GoMod and Dir from the
// replacement anyway. See https://golang.org/issue/27859.
info.Replace = &modinfo.ModulePublic{
Path: r.Path,
Version: r.Version,
GoVersion: info.GoVersion,
Path: r.Path,
Version: r.Version,
}
if goV, ok := rawGoVersion.Load(r); ok {
info.Replace.GoVersion = goV.(string)
info.GoVersion = info.Replace.GoVersion
}
if r.Version == "" {
if filepath.IsAbs(r.Path) {
Expand Down
10 changes: 1 addition & 9 deletions src/cmd/go/internal/modload/load.go
Original file line number Diff line number Diff line change
Expand Up @@ -627,8 +627,7 @@ type loader struct {
pkgCache *par.Cache // map from string to *loadPkg

// computed at end of iterations
direct map[string]bool // imported directly by main module
goVersion map[string]string // go version recorded in each module
direct map[string]bool // imported directly by main module
}

// LoadTests controls whether the loaders load tests of the root packages.
Expand Down Expand Up @@ -754,13 +753,6 @@ func (ld *loader) load(roots func() []string) {
}
}

// Add Go versions, computed during walk.
ld.goVersion = make(map[string]string)
for _, m := range buildList {
v, _ := reqs.(*mvsReqs).versions.Load(m)
ld.goVersion[m.Path], _ = v.(string)
}

// Mix in direct markings (really, lack of indirect markings)
// from go.mod, unless we scanned the whole module
// and can therefore be sure we know better than go.mod.
Expand Down
7 changes: 7 additions & 0 deletions src/cmd/go/internal/modload/modfile.go
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,7 @@ package modload
import (
"cmd/go/internal/base"
"cmd/go/internal/cfg"
"sync"

"golang.org/x/mod/modfile"
"golang.org/x/mod/module"
Expand Down Expand Up @@ -164,3 +165,9 @@ func (i *modFileIndex) modFileIsDirty(modFile *modfile.File) bool {

return false
}

// rawGoVersion records the Go version parsed from each module's go.mod file.
//
// If a module is replaced, the version of the replacement is keyed by the
// replacement module.Version, not the version being replaced.
var rawGoVersion sync.Map // map[module.Version]string
8 changes: 3 additions & 5 deletions src/cmd/go/internal/modload/mvs.go
Original file line number Diff line number Diff line change
Expand Up @@ -11,7 +11,6 @@ import (
"os"
"path/filepath"
"sort"
"sync"

"cmd/go/internal/base"
"cmd/go/internal/cfg"
Expand All @@ -30,7 +29,6 @@ import (
type mvsReqs struct {
buildList []module.Version
cache par.Cache
versions sync.Map
}

// Reqs returns the current module requirement graph.
Expand Down Expand Up @@ -83,7 +81,7 @@ func (r *mvsReqs) modFileToList(f *modfile.File) []module.Version {
func (r *mvsReqs) required(mod module.Version) ([]module.Version, error) {
if mod == Target {
if modFile != nil && modFile.Go != nil {
r.versions.LoadOrStore(mod, modFile.Go.Version)
rawGoVersion.LoadOrStore(mod, modFile.Go.Version)
}
return append([]module.Version(nil), r.buildList[1:]...), nil
}
Expand Down Expand Up @@ -113,7 +111,7 @@ func (r *mvsReqs) required(mod module.Version) ([]module.Version, error) {
return nil, fmt.Errorf("parsing %s: %v", base.ShortPath(gomod), err)
}
if f.Go != nil {
r.versions.LoadOrStore(mod, f.Go.Version)
rawGoVersion.LoadOrStore(repl, f.Go.Version)
}
return r.modFileToList(f), nil
}
Expand Down Expand Up @@ -147,7 +145,7 @@ func (r *mvsReqs) required(mod module.Version) ([]module.Version, error) {
but was required as: %s`, mpath, origPath))
}
if f.Go != nil {
r.versions.LoadOrStore(mod, f.Go.Version)
rawGoVersion.LoadOrStore(mod, f.Go.Version)
}

return r.modFileToList(f), nil
Expand Down

0 comments on commit 2a9636d

Please sign in to comment.