cmd/go: inject State parameter into run.runRun

This command modifies the call tree starting at `run.runRun` to inject
a `State` parameter to every function that is currently using the
global `modload.LoaderState` variable.  By explicilty passing a
`State` parameter, we can begin to eliminate the usage of the global
`modload.LoaderState`.

This commit is part of the overall effort to eliminate global
modloader state.

[git-generate]
cd src/cmd/go/internal/run
rf 'inject modload.LoaderState runRun'
cd ..
./rf-cleanup.zsh

Change-Id: I337323c087ed4e43af28973fad27152791eefbc2
Reviewed-on: https://go-review.googlesource.com/c/go/+/698063
TryBot-Bypass: Ian Alexander <jitsu@google.com>
Reviewed-by: Michael Matloob <matloob@google.com>
Reviewed-by: Michael Matloob <matloob@golang.org>
This commit is contained in:
Ian Alexander 2025-08-20 21:59:08 -04:00
parent 5113496805
commit 5b29875c8e
49 changed files with 867 additions and 863 deletions

View file

@ -21,6 +21,7 @@ import (
"cmd/go/internal/base" "cmd/go/internal/base"
"cmd/go/internal/cfg" "cmd/go/internal/cfg"
"cmd/go/internal/envcmd" "cmd/go/internal/envcmd"
"cmd/go/internal/modload"
"cmd/go/internal/web" "cmd/go/internal/web"
"cmd/go/internal/work" "cmd/go/internal/work"
) )
@ -44,7 +45,7 @@ func runBug(ctx context.Context, cmd *base.Command, args []string) {
if len(args) > 0 { if len(args) > 0 {
base.Fatalf("go: bug takes no arguments") base.Fatalf("go: bug takes no arguments")
} }
work.BuildInit() work.BuildInit(modload.LoaderState)
var buf strings.Builder var buf strings.Builder
buf.WriteString(bugHeader) buf.WriteString(bugHeader)

View file

@ -120,7 +120,7 @@ func init() {
} }
func runClean(ctx context.Context, cmd *base.Command, args []string) { func runClean(ctx context.Context, cmd *base.Command, args []string) {
modload.InitWorkfile() modload.InitWorkfile(modload.LoaderState)
if len(args) > 0 { if len(args) > 0 {
cacheFlag := "" cacheFlag := ""
switch { switch {
@ -142,13 +142,13 @@ func runClean(ctx context.Context, cmd *base.Command, args []string) {
// either the flags and arguments explicitly imply a package, // either the flags and arguments explicitly imply a package,
// or no other target (such as a cache) was requested to be cleaned. // or no other target (such as a cache) was requested to be cleaned.
cleanPkg := len(args) > 0 || cleanI || cleanR cleanPkg := len(args) > 0 || cleanI || cleanR
if (!modload.Enabled() || modload.HasModRoot()) && if (!modload.Enabled(modload.LoaderState) || modload.HasModRoot(modload.LoaderState)) &&
!cleanCache && !cleanModcache && !cleanTestcache && !cleanFuzzcache { !cleanCache && !cleanModcache && !cleanTestcache && !cleanFuzzcache {
cleanPkg = true cleanPkg = true
} }
if cleanPkg { if cleanPkg {
for _, pkg := range load.PackagesAndErrors(ctx, load.PackageOpts{}, args) { for _, pkg := range load.PackagesAndErrors(modload.LoaderState, ctx, load.PackageOpts{}, args) {
clean(pkg) clean(pkg)
} }
} }

View file

@ -191,14 +191,14 @@ func findEnv(env []cfg.EnvVar, name string) string {
// ExtraEnvVars returns environment variables that should not leak into child processes. // ExtraEnvVars returns environment variables that should not leak into child processes.
func ExtraEnvVars() []cfg.EnvVar { func ExtraEnvVars() []cfg.EnvVar {
gomod := "" gomod := ""
modload.Init() modload.Init(modload.LoaderState)
if modload.HasModRoot() { if modload.HasModRoot(modload.LoaderState) {
gomod = modload.ModFilePath() gomod = modload.ModFilePath()
} else if modload.Enabled() { } else if modload.Enabled(modload.LoaderState) {
gomod = os.DevNull gomod = os.DevNull
} }
modload.InitWorkfile() modload.InitWorkfile(modload.LoaderState)
gowork := modload.WorkFilePath() gowork := modload.WorkFilePath(modload.LoaderState)
// As a special case, if a user set off explicitly, report that in GOWORK. // As a special case, if a user set off explicitly, report that in GOWORK.
if cfg.Getenv("GOWORK") == "off" { if cfg.Getenv("GOWORK") == "off" {
gowork = "off" gowork = "off"
@ -336,7 +336,7 @@ func runEnv(ctx context.Context, cmd *base.Command, args []string) {
} }
} }
if needCostly { if needCostly {
work.BuildInit() work.BuildInit(modload.LoaderState)
env = append(env, ExtraEnvVarsCostly()...) env = append(env, ExtraEnvVarsCostly()...)
} }

View file

@ -59,8 +59,8 @@ func runFmt(ctx context.Context, cmd *base.Command, args []string) {
baseGofmtArgs := len(gofmtArgs) baseGofmtArgs := len(gofmtArgs)
baseGofmtArgLen := gofmtArgLen baseGofmtArgLen := gofmtArgLen
for _, pkg := range load.PackagesAndErrors(ctx, load.PackageOpts{}, args) { for _, pkg := range load.PackagesAndErrors(modload.LoaderState, ctx, load.PackageOpts{}, args) {
if modload.Enabled() && pkg.Module != nil && !pkg.Module.Main { if modload.Enabled(modload.LoaderState) && pkg.Module != nil && !pkg.Module.Main {
if !printed { if !printed {
fmt.Fprintf(os.Stderr, "go: not formatting packages in dependency modules\n") fmt.Fprintf(os.Stderr, "go: not formatting packages in dependency modules\n")
printed = true printed = true
@ -70,7 +70,7 @@ func runFmt(ctx context.Context, cmd *base.Command, args []string) {
if pkg.Error != nil { if pkg.Error != nil {
if _, ok := errors.AsType[*load.NoGoError](pkg.Error); ok { if _, ok := errors.AsType[*load.NoGoError](pkg.Error); ok {
// Skip this error, as we will format all files regardless. // Skip this error, as we will format all files regardless.
} else if _, ok := errors.AsType[*load.EmbedError](pkg.Error); ok && len(pkg.InternalAllGoFiles()) > 0 { } else if _, ok := errors.AsType[*load.EmbedError](pkg.Error); ok && len(pkg.InternalAllGoFiles()) > 0 {
// Skip this error, as we will format all files regardless. // Skip this error, as we will format all files regardless.
} else { } else {
base.Errorf("%v", pkg.Error) base.Errorf("%v", pkg.Error)

View file

@ -182,7 +182,7 @@ func init() {
} }
func runGenerate(ctx context.Context, cmd *base.Command, args []string) { func runGenerate(ctx context.Context, cmd *base.Command, args []string) {
modload.InitWorkfile() modload.InitWorkfile(modload.LoaderState)
if generateRunFlag != "" { if generateRunFlag != "" {
var err error var err error
@ -204,8 +204,8 @@ func runGenerate(ctx context.Context, cmd *base.Command, args []string) {
// Even if the arguments are .go files, this loop suffices. // Even if the arguments are .go files, this loop suffices.
printed := false printed := false
pkgOpts := load.PackageOpts{IgnoreImports: true} pkgOpts := load.PackageOpts{IgnoreImports: true}
for _, pkg := range load.PackagesAndErrors(ctx, pkgOpts, args) { for _, pkg := range load.PackagesAndErrors(modload.LoaderState, ctx, pkgOpts, args) {
if modload.Enabled() && pkg.Module != nil && !pkg.Module.Main { if modload.Enabled(modload.LoaderState) && pkg.Module != nil && !pkg.Module.Main {
if !printed { if !printed {
fmt.Fprintf(os.Stderr, "go: not generating in packages in dependency modules\n") fmt.Fprintf(os.Stderr, "go: not generating in packages in dependency modules\n")
printed = true printed = true

View file

@ -419,7 +419,7 @@ func (v *jsonFlag) needAny(fields ...string) bool {
var nl = []byte{'\n'} var nl = []byte{'\n'}
func runList(ctx context.Context, cmd *base.Command, args []string) { func runList(ctx context.Context, cmd *base.Command, args []string) {
modload.InitWorkfile() modload.InitWorkfile(modload.LoaderState)
if *listFmt != "" && listJson { if *listFmt != "" && listJson {
base.Fatalf("go list -f cannot be used with -json") base.Fatalf("go list -f cannot be used with -json")
@ -427,11 +427,11 @@ func runList(ctx context.Context, cmd *base.Command, args []string) {
if *listReuse != "" && !*listM { if *listReuse != "" && !*listM {
base.Fatalf("go list -reuse cannot be used without -m") base.Fatalf("go list -reuse cannot be used without -m")
} }
if *listReuse != "" && modload.HasModRoot() { if *listReuse != "" && modload.HasModRoot(modload.LoaderState) {
base.Fatalf("go list -reuse cannot be used inside a module") base.Fatalf("go list -reuse cannot be used inside a module")
} }
work.BuildInit() work.BuildInit(modload.LoaderState)
out := newTrackingWriter(os.Stdout) out := newTrackingWriter(os.Stdout)
defer out.w.Flush() defer out.w.Flush()
@ -496,12 +496,12 @@ func runList(ctx context.Context, cmd *base.Command, args []string) {
} }
} }
modload.Init() modload.Init(modload.LoaderState)
if *listRetracted { if *listRetracted {
if cfg.BuildMod == "vendor" { if cfg.BuildMod == "vendor" {
base.Fatalf("go list -retracted cannot be used when vendoring is enabled") base.Fatalf("go list -retracted cannot be used when vendoring is enabled")
} }
if !modload.Enabled() { if !modload.Enabled(modload.LoaderState) {
base.Fatalf("go list -retracted can only be used in module-aware mode") base.Fatalf("go list -retracted can only be used in module-aware mode")
} }
} }
@ -525,11 +525,11 @@ func runList(ctx context.Context, cmd *base.Command, args []string) {
base.Fatalf("go list -test cannot be used with -m") base.Fatalf("go list -test cannot be used with -m")
} }
if modload.Init(); !modload.Enabled() { if modload.Init(modload.LoaderState); !modload.Enabled(modload.LoaderState) {
base.Fatalf("go: list -m cannot be used with GO111MODULE=off") base.Fatalf("go: list -m cannot be used with GO111MODULE=off")
} }
modload.LoadModFile(ctx) // Sets cfg.BuildMod as a side-effect. modload.LoadModFile(modload.LoaderState, ctx) // Sets cfg.BuildMod as a side-effect.
if cfg.BuildMod == "vendor" { if cfg.BuildMod == "vendor" {
const actionDisabledFormat = "go: can't %s using the vendor directory\n\t(Use -mod=mod or -mod=readonly to bypass.)" const actionDisabledFormat = "go: can't %s using the vendor directory\n\t(Use -mod=mod or -mod=readonly to bypass.)"
@ -613,7 +613,7 @@ func runList(ctx context.Context, cmd *base.Command, args []string) {
SuppressBuildInfo: !*listExport && !listJsonFields.needAny("Stale", "StaleReason"), SuppressBuildInfo: !*listExport && !listJsonFields.needAny("Stale", "StaleReason"),
SuppressEmbedFiles: !*listExport && !listJsonFields.needAny("EmbedFiles", "TestEmbedFiles", "XTestEmbedFiles"), SuppressEmbedFiles: !*listExport && !listJsonFields.needAny("EmbedFiles", "TestEmbedFiles", "XTestEmbedFiles"),
} }
pkgs := load.PackagesAndErrors(ctx, pkgOpts, args) pkgs := load.PackagesAndErrors(modload.LoaderState, ctx, pkgOpts, args)
if !*listE { if !*listE {
w := 0 w := 0
for _, pkg := range pkgs { for _, pkg := range pkgs {
@ -727,7 +727,7 @@ func runList(ctx context.Context, cmd *base.Command, args []string) {
b.NeedExport = *listExport b.NeedExport = *listExport
b.NeedCompiledGoFiles = *listCompiled b.NeedCompiledGoFiles = *listCompiled
if cfg.BuildCover { if cfg.BuildCover {
load.PrepareForCoverageBuild(pkgs) load.PrepareForCoverageBuild(modload.LoaderState, pkgs)
} }
a := &work.Action{} a := &work.Action{}
// TODO: Use pkgsFilter? // TODO: Use pkgsFilter?

View file

@ -6,6 +6,7 @@ package load
import ( import (
"cmd/go/internal/base" "cmd/go/internal/base"
"cmd/go/internal/modload"
"cmd/internal/quoted" "cmd/internal/quoted"
"fmt" "fmt"
"strings" "strings"
@ -63,7 +64,7 @@ func (f *PerPackageFlag) set(v, cwd string) error {
return fmt.Errorf("parameter may not start with quote character %c", v[0]) return fmt.Errorf("parameter may not start with quote character %c", v[0])
} }
pattern := strings.TrimSpace(v[:i]) pattern := strings.TrimSpace(v[:i])
match = MatchPackage(pattern, cwd) match = MatchPackage(modload.LoaderState, pattern, cwd)
v = v[i+1:] v = v[i+1:]
} }
flags, err := quoted.Split(v) flags, err := quoted.Split(v)

View file

@ -45,12 +45,12 @@ func ParseGoDebug(text string) (key, value string, err error) {
// defaultGODEBUG returns the default GODEBUG setting for the main package p. // defaultGODEBUG returns the default GODEBUG setting for the main package p.
// When building a test binary, directives, testDirectives, and xtestDirectives // When building a test binary, directives, testDirectives, and xtestDirectives
// list additional directives from the package under test. // list additional directives from the package under test.
func defaultGODEBUG(p *Package, directives, testDirectives, xtestDirectives []build.Directive) string { func defaultGODEBUG(loaderstate *modload.State, p *Package, directives, testDirectives, xtestDirectives []build.Directive) string {
if p.Name != "main" { if p.Name != "main" {
return "" return ""
} }
goVersion := modload.LoaderState.MainModules.GoVersion() goVersion := loaderstate.MainModules.GoVersion(loaderstate)
if modload.LoaderState.RootMode == modload.NoRoot && p.Module != nil { if loaderstate.RootMode == modload.NoRoot && p.Module != nil {
// This is go install pkg@version or go run pkg@version. // This is go install pkg@version or go run pkg@version.
// Use the Go version from the package. // Use the Go version from the package.
// If there isn't one, then assume Go 1.20, // If there isn't one, then assume Go 1.20,
@ -73,7 +73,7 @@ func defaultGODEBUG(p *Package, directives, testDirectives, xtestDirectives []bu
} }
// Add directives from main module go.mod. // Add directives from main module go.mod.
for _, g := range modload.LoaderState.MainModules.Godebugs() { for _, g := range loaderstate.MainModules.Godebugs(loaderstate) {
if m == nil { if m == nil {
m = make(map[string]string) m = make(map[string]string)
} }

View file

@ -686,8 +686,8 @@ const (
) )
// LoadPackage does Load import, but without a parent package load context // LoadPackage does Load import, but without a parent package load context
func LoadPackage(ctx context.Context, opts PackageOpts, path, srcDir string, stk *ImportStack, importPos []token.Position, mode int) *Package { func LoadPackage(loaderstate *modload.State, ctx context.Context, opts PackageOpts, path, srcDir string, stk *ImportStack, importPos []token.Position, mode int) *Package {
p, err := loadImport(ctx, opts, nil, path, srcDir, nil, stk, importPos, mode) p, err := loadImport(loaderstate, ctx, opts, nil, path, srcDir, nil, stk, importPos, mode)
if err != nil { if err != nil {
base.Fatalf("internal error: loadImport of %q with nil parent returned an error", path) base.Fatalf("internal error: loadImport of %q with nil parent returned an error", path)
} }
@ -703,7 +703,7 @@ func LoadPackage(ctx context.Context, opts PackageOpts, path, srcDir string, stk
// The returned PackageError, if any, describes why parent is not allowed // The returned PackageError, if any, describes why parent is not allowed
// to import the named package, with the error referring to importPos. // to import the named package, with the error referring to importPos.
// The PackageError can only be non-nil when parent is not nil. // The PackageError can only be non-nil when parent is not nil.
func loadImport(ctx context.Context, opts PackageOpts, pre *preload, path, srcDir string, parent *Package, stk *ImportStack, importPos []token.Position, mode int) (*Package, *PackageError) { func loadImport(loaderstate *modload.State, ctx context.Context, opts PackageOpts, pre *preload, path, srcDir string, parent *Package, stk *ImportStack, importPos []token.Position, mode int) (*Package, *PackageError) {
ctx, span := trace.StartSpan(ctx, "modload.loadImport "+path) ctx, span := trace.StartSpan(ctx, "modload.loadImport "+path)
defer span.Done() defer span.Done()
@ -718,9 +718,9 @@ func loadImport(ctx context.Context, opts PackageOpts, pre *preload, path, srcDi
parentRoot = parent.Root parentRoot = parent.Root
parentIsStd = parent.Standard parentIsStd = parent.Standard
} }
bp, loaded, err := loadPackageData(ctx, path, parentPath, srcDir, parentRoot, parentIsStd, mode) bp, loaded, err := loadPackageData(loaderstate, ctx, path, parentPath, srcDir, parentRoot, parentIsStd, mode)
if loaded && pre != nil && !opts.IgnoreImports { if loaded && pre != nil && !opts.IgnoreImports {
pre.preloadImports(ctx, opts, bp.Imports, bp) pre.preloadImports(loaderstate, ctx, opts, bp.Imports, bp)
} }
if bp == nil { if bp == nil {
p := &Package{ p := &Package{
@ -771,7 +771,7 @@ func loadImport(ctx context.Context, opts PackageOpts, pre *preload, path, srcDi
// Load package. // Load package.
// loadPackageData may return bp != nil even if an error occurs, // loadPackageData may return bp != nil even if an error occurs,
// in order to return partial information. // in order to return partial information.
p.load(ctx, opts, path, stk, importPos, bp, err) p.load(loaderstate, ctx, opts, path, stk, importPos, bp, err)
if !cfg.ModulesEnabled && path != cleanImport(path) { if !cfg.ModulesEnabled && path != cleanImport(path) {
p.Error = &PackageError{ p.Error = &PackageError{
@ -784,7 +784,7 @@ func loadImport(ctx context.Context, opts PackageOpts, pre *preload, path, srcDi
} }
// Checked on every import because the rules depend on the code doing the importing. // Checked on every import because the rules depend on the code doing the importing.
if perr := disallowInternal(ctx, srcDir, parent, parentPath, p, stk); perr != nil { if perr := disallowInternal(loaderstate, ctx, srcDir, parent, parentPath, p, stk); perr != nil {
perr.setPos(importPos) perr.setPos(importPos)
return p, perr return p, perr
} }
@ -838,7 +838,7 @@ func extractFirstImport(importPos []token.Position) *token.Position {
// //
// loadPackageData returns a boolean, loaded, which is true if this is the // loadPackageData returns a boolean, loaded, which is true if this is the
// first time the package was loaded. Callers may preload imports in this case. // first time the package was loaded. Callers may preload imports in this case.
func loadPackageData(ctx context.Context, path, parentPath, parentDir, parentRoot string, parentIsStd bool, mode int) (bp *build.Package, loaded bool, err error) { func loadPackageData(loaderstate *modload.State, ctx context.Context, path, parentPath, parentDir, parentRoot string, parentIsStd bool, mode int) (bp *build.Package, loaded bool, err error) {
ctx, span := trace.StartSpan(ctx, "load.loadPackageData "+path) ctx, span := trace.StartSpan(ctx, "load.loadPackageData "+path)
defer span.Done() defer span.Done()
@ -883,7 +883,7 @@ func loadPackageData(ctx context.Context, path, parentPath, parentDir, parentRoo
r.path = newPath r.path = newPath
r.dir = dir r.dir = dir
} else if cfg.ModulesEnabled { } else if cfg.ModulesEnabled {
r.dir, r.path, r.err = modload.Lookup(parentPath, parentIsStd, path) r.dir, r.path, r.err = modload.Lookup(loaderstate, parentPath, parentIsStd, path)
} else if build.IsLocalImport(path) { } else if build.IsLocalImport(path) {
r.dir = filepath.Join(parentDir, path) r.dir = filepath.Join(parentDir, path)
r.path = dirToImportPath(r.dir) r.path = dirToImportPath(r.dir)
@ -892,7 +892,7 @@ func loadPackageData(ctx context.Context, path, parentPath, parentDir, parentRoo
// find out the key to use in packageCache without the // find out the key to use in packageCache without the
// overhead of repeated calls to buildContext.Import. // overhead of repeated calls to buildContext.Import.
// The code is also needed in a few other places anyway. // The code is also needed in a few other places anyway.
r.path = resolveImportPath(path, parentPath, parentDir, parentRoot, parentIsStd) r.path = resolveImportPath(loaderstate, path, parentPath, parentDir, parentRoot, parentIsStd)
} else if mode&ResolveModule != 0 { } else if mode&ResolveModule != 0 {
r.path = moduleImportPath(path, parentPath, parentDir, parentRoot) r.path = moduleImportPath(path, parentPath, parentDir, parentRoot)
} }
@ -921,7 +921,7 @@ func loadPackageData(ctx context.Context, path, parentPath, parentDir, parentRoo
} else { } else {
buildContext.GOPATH = "" // Clear GOPATH so packages are imported as pure module packages buildContext.GOPATH = "" // Clear GOPATH so packages are imported as pure module packages
} }
modroot := modload.PackageModRoot(ctx, r.path) modroot := modload.PackageModRoot(loaderstate, ctx, r.path)
if modroot == "" && str.HasPathPrefix(r.dir, cfg.GOROOTsrc) { if modroot == "" && str.HasPathPrefix(r.dir, cfg.GOROOTsrc) {
modroot = cfg.GOROOTsrc modroot = cfg.GOROOTsrc
gorootSrcCmd := filepath.Join(cfg.GOROOTsrc, "cmd") gorootSrcCmd := filepath.Join(cfg.GOROOTsrc, "cmd")
@ -942,7 +942,7 @@ func loadPackageData(ctx context.Context, path, parentPath, parentDir, parentRoo
if cfg.ModulesEnabled { if cfg.ModulesEnabled {
// Override data.p.Root, since ImportDir sets it to $GOPATH, if // Override data.p.Root, since ImportDir sets it to $GOPATH, if
// the module is inside $GOPATH/src. // the module is inside $GOPATH/src.
if info := modload.PackageModuleInfo(ctx, path); info != nil { if info := modload.PackageModuleInfo(loaderstate, ctx, path); info != nil {
data.p.Root = info.Dir data.p.Root = info.Dir
} }
} }
@ -989,7 +989,7 @@ func loadPackageData(ctx context.Context, path, parentPath, parentDir, parentRoo
if cfg.GOBIN != "" { if cfg.GOBIN != "" {
data.p.BinDir = cfg.GOBIN data.p.BinDir = cfg.GOBIN
} else if cfg.ModulesEnabled { } else if cfg.ModulesEnabled {
data.p.BinDir = modload.BinDir() data.p.BinDir = modload.BinDir(loaderstate)
} }
} }
@ -1068,7 +1068,7 @@ func newPreload() *preload {
// preloadMatches loads data for package paths matched by patterns. // preloadMatches loads data for package paths matched by patterns.
// When preloadMatches returns, some packages may not be loaded yet, but // When preloadMatches returns, some packages may not be loaded yet, but
// loadPackageData and loadImport are always safe to call. // loadPackageData and loadImport are always safe to call.
func (pre *preload) preloadMatches(ctx context.Context, opts PackageOpts, matches []*search.Match) { func (pre *preload) preloadMatches(loaderstate *modload.State, ctx context.Context, opts PackageOpts, matches []*search.Match) {
for _, m := range matches { for _, m := range matches {
for _, pkg := range m.Pkgs { for _, pkg := range m.Pkgs {
select { select {
@ -1077,10 +1077,10 @@ func (pre *preload) preloadMatches(ctx context.Context, opts PackageOpts, matche
case pre.sema <- struct{}{}: case pre.sema <- struct{}{}:
go func(pkg string) { go func(pkg string) {
mode := 0 // don't use vendoring or module import resolution mode := 0 // don't use vendoring or module import resolution
bp, loaded, err := loadPackageData(ctx, pkg, "", base.Cwd(), "", false, mode) bp, loaded, err := loadPackageData(loaderstate, ctx, pkg, "", base.Cwd(), "", false, mode)
<-pre.sema <-pre.sema
if bp != nil && loaded && err == nil && !opts.IgnoreImports { if bp != nil && loaded && err == nil && !opts.IgnoreImports {
pre.preloadImports(ctx, opts, bp.Imports, bp) pre.preloadImports(loaderstate, ctx, opts, bp.Imports, bp)
} }
}(pkg) }(pkg)
} }
@ -1091,7 +1091,7 @@ func (pre *preload) preloadMatches(ctx context.Context, opts PackageOpts, matche
// preloadImports queues a list of imports for preloading. // preloadImports queues a list of imports for preloading.
// When preloadImports returns, some packages may not be loaded yet, // When preloadImports returns, some packages may not be loaded yet,
// but loadPackageData and loadImport are always safe to call. // but loadPackageData and loadImport are always safe to call.
func (pre *preload) preloadImports(ctx context.Context, opts PackageOpts, imports []string, parent *build.Package) { func (pre *preload) preloadImports(loaderstate *modload.State, ctx context.Context, opts PackageOpts, imports []string, parent *build.Package) {
parentIsStd := parent.Goroot && parent.ImportPath != "" && search.IsStandardImportPath(parent.ImportPath) parentIsStd := parent.Goroot && parent.ImportPath != "" && search.IsStandardImportPath(parent.ImportPath)
for _, path := range imports { for _, path := range imports {
if path == "C" || path == "unsafe" { if path == "C" || path == "unsafe" {
@ -1102,10 +1102,10 @@ func (pre *preload) preloadImports(ctx context.Context, opts PackageOpts, import
return return
case pre.sema <- struct{}{}: case pre.sema <- struct{}{}:
go func(path string) { go func(path string) {
bp, loaded, err := loadPackageData(ctx, path, parent.ImportPath, parent.Dir, parent.Root, parentIsStd, ResolveImport) bp, loaded, err := loadPackageData(loaderstate, ctx, path, parent.ImportPath, parent.Dir, parent.Root, parentIsStd, ResolveImport)
<-pre.sema <-pre.sema
if bp != nil && loaded && err == nil && !opts.IgnoreImports { if bp != nil && loaded && err == nil && !opts.IgnoreImports {
pre.preloadImports(ctx, opts, bp.Imports, bp) pre.preloadImports(loaderstate, ctx, opts, bp.Imports, bp)
} }
}(path) }(path)
} }
@ -1160,12 +1160,12 @@ func ResolveImportPath(parent *Package, path string) (found string) {
parentRoot = parent.Root parentRoot = parent.Root
parentIsStd = parent.Standard parentIsStd = parent.Standard
} }
return resolveImportPath(path, parentPath, parentDir, parentRoot, parentIsStd) return resolveImportPath(modload.LoaderState, path, parentPath, parentDir, parentRoot, parentIsStd)
} }
func resolveImportPath(path, parentPath, parentDir, parentRoot string, parentIsStd bool) (found string) { func resolveImportPath(loaderstate *modload.State, path, parentPath, parentDir, parentRoot string, parentIsStd bool) (found string) {
if cfg.ModulesEnabled { if cfg.ModulesEnabled {
if _, p, e := modload.Lookup(parentPath, parentIsStd, path); e == nil { if _, p, e := modload.Lookup(loaderstate, parentPath, parentIsStd, path); e == nil {
return p return p
} }
return path return path
@ -1463,7 +1463,7 @@ func reusePackage(p *Package, stk *ImportStack) *Package {
// is allowed to import p. // is allowed to import p.
// If the import is allowed, disallowInternal returns the original package p. // If the import is allowed, disallowInternal returns the original package p.
// If not, it returns a new package containing just an appropriate error. // If not, it returns a new package containing just an appropriate error.
func disallowInternal(ctx context.Context, srcDir string, importer *Package, importerPath string, p *Package, stk *ImportStack) *PackageError { func disallowInternal(loaderstate *modload.State, ctx context.Context, srcDir string, importer *Package, importerPath string, p *Package, stk *ImportStack) *PackageError {
// golang.org/s/go14internal: // golang.org/s/go14internal:
// An import of a path containing the element “internal” // An import of a path containing the element “internal”
// is disallowed if the importing code is outside the tree // is disallowed if the importing code is outside the tree
@ -1552,7 +1552,7 @@ func disallowInternal(ctx context.Context, srcDir string, importer *Package, imp
// directory containing them. // directory containing them.
// If the directory is outside the main modules, this will resolve to ".", // If the directory is outside the main modules, this will resolve to ".",
// which is not a prefix of any valid module. // which is not a prefix of any valid module.
importerPath, _ = modload.LoaderState.MainModules.DirImportPath(ctx, importer.Dir) importerPath, _ = loaderstate.MainModules.DirImportPath(loaderstate, ctx, importer.Dir)
} }
parentOfInternal := p.ImportPath[:i] parentOfInternal := p.ImportPath[:i]
if str.HasPathPrefix(importerPath, parentOfInternal) { if str.HasPathPrefix(importerPath, parentOfInternal) {
@ -1771,7 +1771,7 @@ func (p *Package) DefaultExecName() string {
// load populates p using information from bp, err, which should // load populates p using information from bp, err, which should
// be the result of calling build.Context.Import. // be the result of calling build.Context.Import.
// stk contains the import stack, not including path itself. // stk contains the import stack, not including path itself.
func (p *Package) load(ctx context.Context, opts PackageOpts, path string, stk *ImportStack, importPos []token.Position, bp *build.Package, err error) { func (p *Package) load(loaderstate *modload.State, ctx context.Context, opts PackageOpts, path string, stk *ImportStack, importPos []token.Position, bp *build.Package, err error) {
p.copyBuild(opts, bp) p.copyBuild(opts, bp)
// The localPrefix is the path we interpret ./ imports relative to, // The localPrefix is the path we interpret ./ imports relative to,
@ -1835,7 +1835,7 @@ func (p *Package) load(ctx context.Context, opts PackageOpts, path string, stk *
elem = full elem = full
} }
if p.Internal.Build.BinDir == "" && cfg.ModulesEnabled { if p.Internal.Build.BinDir == "" && cfg.ModulesEnabled {
p.Internal.Build.BinDir = modload.BinDir() p.Internal.Build.BinDir = modload.BinDir(loaderstate)
} }
if p.Internal.Build.BinDir != "" { if p.Internal.Build.BinDir != "" {
// Install to GOBIN or bin of GOPATH entry. // Install to GOBIN or bin of GOPATH entry.
@ -1973,9 +1973,9 @@ func (p *Package) load(ctx context.Context, opts PackageOpts, path string, stk *
pkgPath = "command-line-arguments" pkgPath = "command-line-arguments"
} }
if cfg.ModulesEnabled { if cfg.ModulesEnabled {
p.Module = modload.PackageModuleInfo(ctx, pkgPath) p.Module = modload.PackageModuleInfo(loaderstate, ctx, pkgPath)
} }
p.DefaultGODEBUG = defaultGODEBUG(p, nil, nil, nil) p.DefaultGODEBUG = defaultGODEBUG(loaderstate, p, nil, nil, nil)
if !opts.SuppressEmbedFiles { if !opts.SuppressEmbedFiles {
p.EmbedFiles, p.Internal.Embed, err = resolveEmbed(p.Dir, p.EmbedPatterns) p.EmbedFiles, p.Internal.Embed, err = resolveEmbed(p.Dir, p.EmbedPatterns)
@ -2026,7 +2026,7 @@ func (p *Package) load(ctx context.Context, opts PackageOpts, path string, stk *
if path == "C" { if path == "C" {
continue continue
} }
p1, err := loadImport(ctx, opts, nil, path, p.Dir, p, stk, p.Internal.Build.ImportPos[path], ResolveImport) p1, err := loadImport(loaderstate, ctx, opts, nil, path, p.Dir, p, stk, p.Internal.Build.ImportPos[path], ResolveImport)
if err != nil && p.Error == nil { if err != nil && p.Error == nil {
p.Error = err p.Error = err
p.Incomplete = true p.Incomplete = true
@ -2813,7 +2813,7 @@ func TestPackageList(ctx context.Context, opts PackageOpts, roots []*Package) []
} }
walkTest := func(root *Package, path string) { walkTest := func(root *Package, path string) {
var stk ImportStack var stk ImportStack
p1, err := loadImport(ctx, opts, nil, path, root.Dir, root, &stk, root.Internal.Build.TestImportPos[path], ResolveImport) p1, err := loadImport(modload.LoaderState, ctx, opts, nil, path, root.Dir, root, &stk, root.Internal.Build.TestImportPos[path], ResolveImport)
if err != nil && root.Error == nil { if err != nil && root.Error == nil {
// Assign error importing the package to the importer. // Assign error importing the package to the importer.
root.Error = err root.Error = err
@ -2840,16 +2840,16 @@ func TestPackageList(ctx context.Context, opts PackageOpts, roots []*Package) []
// dependencies (like sync/atomic for coverage). // dependencies (like sync/atomic for coverage).
// TODO(jayconrod): delete this function and set flags automatically // TODO(jayconrod): delete this function and set flags automatically
// in LoadImport instead. // in LoadImport instead.
func LoadImportWithFlags(path, srcDir string, parent *Package, stk *ImportStack, importPos []token.Position, mode int) (*Package, *PackageError) { func LoadImportWithFlags(loaderstate *modload.State, path, srcDir string, parent *Package, stk *ImportStack, importPos []token.Position, mode int) (*Package, *PackageError) {
p, err := loadImport(context.TODO(), PackageOpts{}, nil, path, srcDir, parent, stk, importPos, mode) p, err := loadImport(loaderstate, context.TODO(), PackageOpts{}, nil, path, srcDir, parent, stk, importPos, mode)
setToolFlags(p) setToolFlags(p)
return p, err return p, err
} }
// LoadPackageWithFlags is the same as LoadImportWithFlags but without a parent. // LoadPackageWithFlags is the same as LoadImportWithFlags but without a parent.
// It's then guaranteed to not return an error // It's then guaranteed to not return an error
func LoadPackageWithFlags(path, srcDir string, stk *ImportStack, importPos []token.Position, mode int) *Package { func LoadPackageWithFlags(loaderstate *modload.State, path, srcDir string, stk *ImportStack, importPos []token.Position, mode int) *Package {
p := LoadPackage(context.TODO(), PackageOpts{}, path, srcDir, stk, importPos, mode) p := LoadPackage(loaderstate, context.TODO(), PackageOpts{}, path, srcDir, stk, importPos, mode)
setToolFlags(p) setToolFlags(p)
return p return p
} }
@ -2899,7 +2899,7 @@ type PackageOpts struct {
// //
// To obtain a flat list of packages, use PackageList. // To obtain a flat list of packages, use PackageList.
// To report errors loading packages, use ReportPackageErrors. // To report errors loading packages, use ReportPackageErrors.
func PackagesAndErrors(ctx context.Context, opts PackageOpts, patterns []string) []*Package { func PackagesAndErrors(loaderstate *modload.State, ctx context.Context, opts PackageOpts, patterns []string) []*Package {
ctx, span := trace.StartSpan(ctx, "load.PackagesAndErrors") ctx, span := trace.StartSpan(ctx, "load.PackagesAndErrors")
defer span.Done() defer span.Done()
@ -2911,7 +2911,7 @@ func PackagesAndErrors(ctx context.Context, opts PackageOpts, patterns []string)
// We need to test whether the path is an actual Go file and not a // We need to test whether the path is an actual Go file and not a
// package path or pattern ending in '.go' (see golang.org/issue/34653). // package path or pattern ending in '.go' (see golang.org/issue/34653).
if fi, err := fsys.Stat(p); err == nil && !fi.IsDir() { if fi, err := fsys.Stat(p); err == nil && !fi.IsDir() {
pkgs := []*Package{GoFilesPackage(ctx, opts, patterns)} pkgs := []*Package{GoFilesPackage(loaderstate, ctx, opts, patterns)}
setPGOProfilePath(pkgs) setPGOProfilePath(pkgs)
return pkgs return pkgs
} }
@ -2919,13 +2919,13 @@ func PackagesAndErrors(ctx context.Context, opts PackageOpts, patterns []string)
} }
var matches []*search.Match var matches []*search.Match
if modload.Init(); cfg.ModulesEnabled { if modload.Init(loaderstate); cfg.ModulesEnabled {
modOpts := modload.PackageOpts{ modOpts := modload.PackageOpts{
ResolveMissingImports: true, ResolveMissingImports: true,
LoadTests: opts.ModResolveTests, LoadTests: opts.ModResolveTests,
SilencePackageErrors: true, SilencePackageErrors: true,
} }
matches, _ = modload.LoadPackages(ctx, modOpts, patterns...) matches, _ = modload.LoadPackages(loaderstate, ctx, modOpts, patterns...)
} else { } else {
matches = search.ImportPaths(patterns) matches = search.ImportPaths(patterns)
} }
@ -2938,7 +2938,7 @@ func PackagesAndErrors(ctx context.Context, opts PackageOpts, patterns []string)
pre := newPreload() pre := newPreload()
defer pre.flush() defer pre.flush()
pre.preloadMatches(ctx, opts, matches) pre.preloadMatches(loaderstate, ctx, opts, matches)
for _, m := range matches { for _, m := range matches {
for _, pkg := range m.Pkgs { for _, pkg := range m.Pkgs {
@ -2952,7 +2952,7 @@ func PackagesAndErrors(ctx context.Context, opts PackageOpts, patterns []string)
// a literal and also a non-literal pattern. // a literal and also a non-literal pattern.
mode |= cmdlinePkgLiteral mode |= cmdlinePkgLiteral
} }
p, perr := loadImport(ctx, opts, pre, pkg, base.Cwd(), nil, &stk, nil, mode) p, perr := loadImport(loaderstate, ctx, opts, pre, pkg, base.Cwd(), nil, &stk, nil, mode)
if perr != nil { if perr != nil {
base.Fatalf("internal error: loadImport of %q with nil parent returned an error", pkg) base.Fatalf("internal error: loadImport of %q with nil parent returned an error", pkg)
} }
@ -3243,8 +3243,8 @@ func setToolFlags(pkgs ...*Package) {
// GoFilesPackage creates a package for building a collection of Go files // GoFilesPackage creates a package for building a collection of Go files
// (typically named on the command line). The target is named p.a for // (typically named on the command line). The target is named p.a for
// package p or named after the first Go file for package main. // package p or named after the first Go file for package main.
func GoFilesPackage(ctx context.Context, opts PackageOpts, gofiles []string) *Package { func GoFilesPackage(loaderstate *modload.State, ctx context.Context, opts PackageOpts, gofiles []string) *Package {
modload.Init() modload.Init(loaderstate)
for _, f := range gofiles { for _, f := range gofiles {
if !strings.HasSuffix(f, ".go") { if !strings.HasSuffix(f, ".go") {
@ -3289,7 +3289,7 @@ func GoFilesPackage(ctx context.Context, opts PackageOpts, gofiles []string) *Pa
ctxt.ReadDir = func(string) ([]fs.FileInfo, error) { return dirent, nil } ctxt.ReadDir = func(string) ([]fs.FileInfo, error) { return dirent, nil }
if cfg.ModulesEnabled { if cfg.ModulesEnabled {
modload.ImportFromFiles(ctx, gofiles) modload.ImportFromFiles(loaderstate, ctx, gofiles)
} }
var err error var err error
@ -3305,7 +3305,7 @@ func GoFilesPackage(ctx context.Context, opts PackageOpts, gofiles []string) *Pa
pkg := new(Package) pkg := new(Package)
pkg.Internal.Local = true pkg.Internal.Local = true
pkg.Internal.CmdlineFiles = true pkg.Internal.CmdlineFiles = true
pkg.load(ctx, opts, "command-line-arguments", &stk, nil, bp, err) pkg.load(loaderstate, ctx, opts, "command-line-arguments", &stk, nil, bp, err)
if !cfg.ModulesEnabled { if !cfg.ModulesEnabled {
pkg.Internal.LocalPrefix = dirToImportPath(dir) pkg.Internal.LocalPrefix = dirToImportPath(dir)
} }
@ -3319,7 +3319,7 @@ func GoFilesPackage(ctx context.Context, opts PackageOpts, gofiles []string) *Pa
if cfg.GOBIN != "" { if cfg.GOBIN != "" {
pkg.Target = filepath.Join(cfg.GOBIN, exe) pkg.Target = filepath.Join(cfg.GOBIN, exe)
} else if cfg.ModulesEnabled { } else if cfg.ModulesEnabled {
pkg.Target = filepath.Join(modload.BinDir(), exe) pkg.Target = filepath.Join(modload.BinDir(loaderstate), exe)
} }
} }
@ -3347,11 +3347,11 @@ func GoFilesPackage(ctx context.Context, opts PackageOpts, gofiles []string) *Pa
// module, but its go.mod file (if it has one) must not contain directives that // module, but its go.mod file (if it has one) must not contain directives that
// would cause it to be interpreted differently if it were the main module // would cause it to be interpreted differently if it were the main module
// (replace, exclude). // (replace, exclude).
func PackagesAndErrorsOutsideModule(ctx context.Context, opts PackageOpts, args []string) ([]*Package, error) { func PackagesAndErrorsOutsideModule(loaderstate *modload.State, ctx context.Context, opts PackageOpts, args []string) ([]*Package, error) {
if !modload.LoaderState.ForceUseModules { if !loaderstate.ForceUseModules {
panic("modload.ForceUseModules must be true") panic("modload.ForceUseModules must be true")
} }
if modload.LoaderState.RootMode != modload.NoRoot { if loaderstate.RootMode != modload.NoRoot {
panic("modload.RootMode must be NoRoot") panic("modload.RootMode must be NoRoot")
} }
@ -3404,12 +3404,12 @@ func PackagesAndErrorsOutsideModule(ctx context.Context, opts PackageOpts, args
allowed = nil allowed = nil
} }
noneSelected := func(path string) (version string) { return "none" } noneSelected := func(path string) (version string) { return "none" }
qrs, err := modload.QueryPackages(ctx, patterns[0], version, noneSelected, allowed) qrs, err := modload.QueryPackages(loaderstate, ctx, patterns[0], version, noneSelected, allowed)
if err != nil { if err != nil {
return nil, fmt.Errorf("%s: %w", args[0], err) return nil, fmt.Errorf("%s: %w", args[0], err)
} }
rootMod := qrs[0].Mod rootMod := qrs[0].Mod
deprecation, err := modload.CheckDeprecation(ctx, rootMod) deprecation, err := modload.CheckDeprecation(loaderstate, ctx, rootMod)
if err != nil { if err != nil {
return nil, fmt.Errorf("%s: %w", args[0], err) return nil, fmt.Errorf("%s: %w", args[0], err)
} }
@ -3438,12 +3438,12 @@ func PackagesAndErrorsOutsideModule(ctx context.Context, opts PackageOpts, args
// Since we are in NoRoot mode, the build list initially contains only // Since we are in NoRoot mode, the build list initially contains only
// the dummy command-line-arguments module. Add a requirement on the // the dummy command-line-arguments module. Add a requirement on the
// module that provides the packages named on the command line. // module that provides the packages named on the command line.
if _, err := modload.EditBuildList(ctx, nil, []module.Version{rootMod}); err != nil { if _, err := modload.EditBuildList(loaderstate, ctx, nil, []module.Version{rootMod}); err != nil {
return nil, fmt.Errorf("%s: %w", args[0], err) return nil, fmt.Errorf("%s: %w", args[0], err)
} }
// Load packages for all arguments. // Load packages for all arguments.
pkgs := PackagesAndErrors(ctx, opts, patterns) pkgs := PackagesAndErrors(loaderstate, ctx, opts, patterns)
// Check that named packages are all provided by the same module. // Check that named packages are all provided by the same module.
for _, pkg := range pkgs { for _, pkg := range pkgs {
@ -3471,14 +3471,14 @@ func PackagesAndErrorsOutsideModule(ctx context.Context, opts PackageOpts, args
} }
// EnsureImport ensures that package p imports the named package. // EnsureImport ensures that package p imports the named package.
func EnsureImport(p *Package, pkg string) { func EnsureImport(loaderstate *modload.State, p *Package, pkg string) {
for _, d := range p.Internal.Imports { for _, d := range p.Internal.Imports {
if d.Name == pkg { if d.Name == pkg {
return return
} }
} }
p1, err := LoadImportWithFlags(pkg, p.Dir, p, &ImportStack{}, nil, 0) p1, err := LoadImportWithFlags(loaderstate, pkg, p.Dir, p, &ImportStack{}, nil, 0)
if err != nil { if err != nil {
base.Fatalf("load %s: %v", pkg, err) base.Fatalf("load %s: %v", pkg, err)
} }
@ -3494,7 +3494,7 @@ func EnsureImport(p *Package, pkg string) {
// "go test -cover"). It walks through the packages being built (and // "go test -cover"). It walks through the packages being built (and
// dependencies) and marks them for coverage instrumentation when // dependencies) and marks them for coverage instrumentation when
// appropriate, and possibly adding additional deps where needed. // appropriate, and possibly adding additional deps where needed.
func PrepareForCoverageBuild(pkgs []*Package) { func PrepareForCoverageBuild(loaderstate *modload.State, pkgs []*Package) {
var match []func(*Package) bool var match []func(*Package) bool
matchMainModAndCommandLine := func(p *Package) bool { matchMainModAndCommandLine := func(p *Package) bool {
@ -3507,7 +3507,7 @@ func PrepareForCoverageBuild(pkgs []*Package) {
// the specific packages selected by the user-specified pattern(s). // the specific packages selected by the user-specified pattern(s).
match = make([]func(*Package) bool, len(cfg.BuildCoverPkg)) match = make([]func(*Package) bool, len(cfg.BuildCoverPkg))
for i := range cfg.BuildCoverPkg { for i := range cfg.BuildCoverPkg {
match[i] = MatchPackage(cfg.BuildCoverPkg[i], base.Cwd()) match[i] = MatchPackage(loaderstate, cfg.BuildCoverPkg[i], base.Cwd())
} }
} else { } else {
// Without -coverpkg, instrument only packages in the main module // Without -coverpkg, instrument only packages in the main module
@ -3519,10 +3519,10 @@ func PrepareForCoverageBuild(pkgs []*Package) {
// Visit the packages being built or installed, along with all of // Visit the packages being built or installed, along with all of
// their dependencies, and mark them to be instrumented, taking // their dependencies, and mark them to be instrumented, taking
// into account the matchers we've set up in the sequence above. // into account the matchers we've set up in the sequence above.
SelectCoverPackages(PackageList(pkgs), match, "build") SelectCoverPackages(loaderstate, PackageList(pkgs), match, "build")
} }
func SelectCoverPackages(roots []*Package, match []func(*Package) bool, op string) []*Package { func SelectCoverPackages(loaderstate *modload.State, roots []*Package, match []func(*Package) bool, op string) []*Package {
var warntag string var warntag string
var includeMain bool var includeMain bool
switch op { switch op {
@ -3602,7 +3602,7 @@ func SelectCoverPackages(roots []*Package, match []func(*Package) bool, op strin
// Force import of sync/atomic into package if atomic mode. // Force import of sync/atomic into package if atomic mode.
if cfg.BuildCoverMode == "atomic" { if cfg.BuildCoverMode == "atomic" {
EnsureImport(p, "sync/atomic") EnsureImport(loaderstate, p, "sync/atomic")
} }
} }

View file

@ -14,7 +14,7 @@ import (
) )
// MatchPackage(pattern, cwd)(p) reports whether package p matches pattern in the working directory cwd. // MatchPackage(pattern, cwd)(p) reports whether package p matches pattern in the working directory cwd.
func MatchPackage(pattern, cwd string) func(*Package) bool { func MatchPackage(loaderstate *modload.State, pattern, cwd string) func(*Package) bool {
switch { switch {
case search.IsRelativePath(pattern): case search.IsRelativePath(pattern):
// Split pattern into leading pattern-free directory path // Split pattern into leading pattern-free directory path
@ -54,13 +54,13 @@ func MatchPackage(pattern, cwd string) func(*Package) bool {
return func(p *Package) bool { return p.Standard } return func(p *Package) bool { return p.Standard }
case pattern == "cmd": case pattern == "cmd":
return func(p *Package) bool { return p.Standard && strings.HasPrefix(p.ImportPath, "cmd/") } return func(p *Package) bool { return p.Standard && strings.HasPrefix(p.ImportPath, "cmd/") }
case pattern == "tool" && modload.Enabled(): case pattern == "tool" && modload.Enabled(loaderstate):
return func(p *Package) bool { return func(p *Package) bool {
return modload.LoaderState.MainModules.Tools()[p.ImportPath] return loaderstate.MainModules.Tools()[p.ImportPath]
} }
case pattern == "work" && modload.Enabled(): case pattern == "work" && modload.Enabled(loaderstate):
return func(p *Package) bool { return func(p *Package) bool {
return p.Module != nil && modload.LoaderState.MainModules.Contains(p.Module.Path) return p.Module != nil && loaderstate.MainModules.Contains(p.Module.Path)
} }
default: default:

View file

@ -24,6 +24,7 @@ import (
"unicode/utf8" "unicode/utf8"
"cmd/go/internal/fsys" "cmd/go/internal/fsys"
"cmd/go/internal/modload"
"cmd/go/internal/str" "cmd/go/internal/str"
"cmd/go/internal/trace" "cmd/go/internal/trace"
) )
@ -106,7 +107,7 @@ func TestPackagesAndErrors(ctx context.Context, done func(), opts PackageOpts, p
defer pre.flush() defer pre.flush()
allImports := append([]string{}, p.TestImports...) allImports := append([]string{}, p.TestImports...)
allImports = append(allImports, p.XTestImports...) allImports = append(allImports, p.XTestImports...)
pre.preloadImports(ctx, opts, allImports, p.Internal.Build) pre.preloadImports(modload.LoaderState, ctx, opts, allImports, p.Internal.Build)
var ptestErr, pxtestErr *PackageError var ptestErr, pxtestErr *PackageError
var imports, ximports []*Package var imports, ximports []*Package
@ -116,7 +117,7 @@ func TestPackagesAndErrors(ctx context.Context, done func(), opts PackageOpts, p
stk.Push(ImportInfo{Pkg: p.ImportPath + " (test)"}) stk.Push(ImportInfo{Pkg: p.ImportPath + " (test)"})
rawTestImports := str.StringList(p.TestImports) rawTestImports := str.StringList(p.TestImports)
for i, path := range p.TestImports { for i, path := range p.TestImports {
p1, err := loadImport(ctx, opts, pre, path, p.Dir, p, &stk, p.Internal.Build.TestImportPos[path], ResolveImport) p1, err := loadImport(modload.LoaderState, ctx, opts, pre, path, p.Dir, p, &stk, p.Internal.Build.TestImportPos[path], ResolveImport)
if err != nil && ptestErr == nil { if err != nil && ptestErr == nil {
ptestErr = err ptestErr = err
incomplete = true incomplete = true
@ -145,7 +146,7 @@ func TestPackagesAndErrors(ctx context.Context, done func(), opts PackageOpts, p
var pxtestIncomplete bool var pxtestIncomplete bool
rawXTestImports := str.StringList(p.XTestImports) rawXTestImports := str.StringList(p.XTestImports)
for i, path := range p.XTestImports { for i, path := range p.XTestImports {
p1, err := loadImport(ctx, opts, pre, path, p.Dir, p, &stk, p.Internal.Build.XTestImportPos[path], ResolveImport) p1, err := loadImport(modload.LoaderState, ctx, opts, pre, path, p.Dir, p, &stk, p.Internal.Build.XTestImportPos[path], ResolveImport)
if err != nil && pxtestErr == nil { if err != nil && pxtestErr == nil {
pxtestErr = err pxtestErr = err
} }
@ -292,7 +293,7 @@ func TestPackagesAndErrors(ctx context.Context, done func(), opts PackageOpts, p
} }
pb := p.Internal.Build pb := p.Internal.Build
pmain.DefaultGODEBUG = defaultGODEBUG(pmain, pb.Directives, pb.TestDirectives, pb.XTestDirectives) pmain.DefaultGODEBUG = defaultGODEBUG(modload.LoaderState, pmain, pb.Directives, pb.TestDirectives, pb.XTestDirectives)
if pmain.Internal.BuildInfo == nil || pmain.DefaultGODEBUG != p.DefaultGODEBUG { if pmain.Internal.BuildInfo == nil || pmain.DefaultGODEBUG != p.DefaultGODEBUG {
// Either we didn't generate build info for the package under test (because it wasn't package main), or // Either we didn't generate build info for the package under test (because it wasn't package main), or
// the DefaultGODEBUG used to build the test main package is different from the DefaultGODEBUG // the DefaultGODEBUG used to build the test main package is different from the DefaultGODEBUG
@ -321,7 +322,7 @@ func TestPackagesAndErrors(ctx context.Context, done func(), opts PackageOpts, p
if dep == ptest.ImportPath { if dep == ptest.ImportPath {
pmain.Internal.Imports = append(pmain.Internal.Imports, ptest) pmain.Internal.Imports = append(pmain.Internal.Imports, ptest)
} else { } else {
p1, err := loadImport(ctx, opts, pre, dep, "", nil, &stk, nil, 0) p1, err := loadImport(modload.LoaderState, ctx, opts, pre, dep, "", nil, &stk, nil, 0)
if err != nil && pmain.Error == nil { if err != nil && pmain.Error == nil {
pmain.Error = err pmain.Error = err
pmain.Incomplete = true pmain.Incomplete = true

View file

@ -109,15 +109,15 @@ type ModuleJSON struct {
} }
func runDownload(ctx context.Context, cmd *base.Command, args []string) { func runDownload(ctx context.Context, cmd *base.Command, args []string) {
modload.InitWorkfile() modload.InitWorkfile(modload.LoaderState)
// Check whether modules are enabled and whether we're in a module. // Check whether modules are enabled and whether we're in a module.
modload.LoaderState.ForceUseModules = true modload.LoaderState.ForceUseModules = true
modload.ExplicitWriteGoMod = true modload.ExplicitWriteGoMod = true
haveExplicitArgs := len(args) > 0 haveExplicitArgs := len(args) > 0
if modload.HasModRoot() || modload.WorkFilePath() != "" { if modload.HasModRoot(modload.LoaderState) || modload.WorkFilePath(modload.LoaderState) != "" {
modload.LoadModFile(ctx) // to fill MainModules modload.LoadModFile(modload.LoaderState, ctx) // to fill MainModules
if haveExplicitArgs { if haveExplicitArgs {
for _, mainModule := range modload.LoaderState.MainModules.Versions() { for _, mainModule := range modload.LoaderState.MainModules.Versions() {
@ -130,7 +130,7 @@ func runDownload(ctx context.Context, cmd *base.Command, args []string) {
} }
} }
} }
} else if modload.WorkFilePath() != "" { } else if modload.WorkFilePath(modload.LoaderState) != "" {
// TODO(#44435): Think about what the correct query is to download the // TODO(#44435): Think about what the correct query is to download the
// right set of modules. Also see code review comment at // right set of modules. Also see code review comment at
// https://go-review.googlesource.com/c/go/+/359794/comments/ce946a80_6cf53992. // https://go-review.googlesource.com/c/go/+/359794/comments/ce946a80_6cf53992.
@ -169,7 +169,7 @@ func runDownload(ctx context.Context, cmd *base.Command, args []string) {
} }
if len(args) == 0 { if len(args) == 0 {
if modload.HasModRoot() { if modload.HasModRoot(modload.LoaderState) {
os.Stderr.WriteString("go: no module dependencies to download\n") os.Stderr.WriteString("go: no module dependencies to download\n")
} else { } else {
base.Errorf("go: no modules specified (see 'go help mod download')") base.Errorf("go: no modules specified (see 'go help mod download')")
@ -177,7 +177,7 @@ func runDownload(ctx context.Context, cmd *base.Command, args []string) {
base.Exit() base.Exit()
} }
if *downloadReuse != "" && modload.HasModRoot() { if *downloadReuse != "" && modload.HasModRoot(modload.LoaderState) {
base.Fatalf("go mod download -reuse cannot be used inside a module") base.Fatalf("go mod download -reuse cannot be used inside a module")
} }
@ -220,7 +220,7 @@ func runDownload(ctx context.Context, cmd *base.Command, args []string) {
// when we can. // when we can.
} }
if !haveExplicitArgs && modload.WorkFilePath() == "" { if !haveExplicitArgs && modload.WorkFilePath(modload.LoaderState) == "" {
// 'go mod download' is sometimes run without arguments to pre-populate the // 'go mod download' is sometimes run without arguments to pre-populate the
// module cache. In modules that aren't at go 1.17 or higher, it may fetch // module cache. In modules that aren't at go 1.17 or higher, it may fetch
// modules that aren't needed to build packages in the main module. This is // modules that aren't needed to build packages in the main module. This is
@ -291,7 +291,7 @@ func runDownload(ctx context.Context, cmd *base.Command, args []string) {
// with no arguments we download the module pattern "all", // with no arguments we download the module pattern "all",
// which may include dependencies that are normally pruned out // which may include dependencies that are normally pruned out
// of the individual modules in the workspace. // of the individual modules in the workspace.
if haveExplicitArgs || modload.WorkFilePath() != "" { if haveExplicitArgs || modload.WorkFilePath(modload.LoaderState) != "" {
var sw toolchain.Switcher var sw toolchain.Switcher
// Add errors to the Switcher in deterministic order so that they will be // Add errors to the Switcher in deterministic order so that they will be
// logged deterministically. // logged deterministically.
@ -347,7 +347,7 @@ func runDownload(ctx context.Context, cmd *base.Command, args []string) {
// //
// Don't save sums for 'go mod download' without arguments unless we're in // Don't save sums for 'go mod download' without arguments unless we're in
// workspace mode; see comment above. // workspace mode; see comment above.
if haveExplicitArgs || modload.WorkFilePath() != "" { if haveExplicitArgs || modload.WorkFilePath(modload.LoaderState) != "" {
if err := modload.WriteGoMod(ctx, modload.WriteOpts{}); err != nil { if err := modload.WriteGoMod(ctx, modload.WriteOpts{}); err != nil {
base.Error(err) base.Error(err)
} }

View file

@ -52,7 +52,7 @@ func init() {
} }
func runGraph(ctx context.Context, cmd *base.Command, args []string) { func runGraph(ctx context.Context, cmd *base.Command, args []string) {
modload.InitWorkfile() modload.InitWorkfile(modload.LoaderState)
if len(args) > 0 { if len(args) > 0 {
base.Fatalf("go: 'go mod graph' accepts no arguments") base.Fatalf("go: 'go mod graph' accepts no arguments")

View file

@ -130,7 +130,7 @@ func runTidy(ctx context.Context, cmd *base.Command, args []string) {
}) })
} }
modload.LoadPackages(ctx, modload.PackageOpts{ modload.LoadPackages(modload.LoaderState, ctx, modload.PackageOpts{
TidyGoVersion: tidyGo.String(), TidyGoVersion: tidyGo.String(),
Tags: imports.AnyTags(), Tags: imports.AnyTags(),
Tidy: true, Tidy: true,

View file

@ -66,8 +66,8 @@ func init() {
} }
func runVendor(ctx context.Context, cmd *base.Command, args []string) { func runVendor(ctx context.Context, cmd *base.Command, args []string) {
modload.InitWorkfile() modload.InitWorkfile(modload.LoaderState)
if modload.WorkFilePath() != "" { if modload.WorkFilePath(modload.LoaderState) != "" {
base.Fatalf("go: 'go mod vendor' cannot be run in workspace mode. Run 'go work vendor' to vendor the workspace or set 'GOWORK=off' to exit workspace mode.") base.Fatalf("go: 'go mod vendor' cannot be run in workspace mode. Run 'go work vendor' to vendor the workspace or set 'GOWORK=off' to exit workspace mode.")
} }
RunVendor(ctx, vendorE, vendorO, args) RunVendor(ctx, vendorE, vendorO, args)
@ -88,7 +88,7 @@ func RunVendor(ctx context.Context, vendorE bool, vendorO string, args []string)
AllowErrors: vendorE, AllowErrors: vendorE,
SilenceMissingStdImports: true, SilenceMissingStdImports: true,
} }
_, pkgs := modload.LoadPackages(ctx, loadOpts, "all") _, pkgs := modload.LoadPackages(modload.LoaderState, ctx, loadOpts, "all")
var vdir string var vdir string
switch { switch {
@ -97,7 +97,7 @@ func RunVendor(ctx context.Context, vendorE bool, vendorO string, args []string)
case vendorO != "": case vendorO != "":
vdir = filepath.Join(base.Cwd(), vendorO) vdir = filepath.Join(base.Cwd(), vendorO)
default: default:
vdir = filepath.Join(modload.VendorDir()) vdir = filepath.Join(modload.VendorDir(modload.LoaderState))
} }
if err := os.RemoveAll(vdir); err != nil { if err := os.RemoveAll(vdir); err != nil {
base.Fatal(err) base.Fatal(err)
@ -116,8 +116,8 @@ func RunVendor(ctx context.Context, vendorE bool, vendorO string, args []string)
includeAllReplacements := false includeAllReplacements := false
includeGoVersions := false includeGoVersions := false
isExplicit := map[module.Version]bool{} isExplicit := map[module.Version]bool{}
gv := modload.LoaderState.MainModules.GoVersion() gv := modload.LoaderState.MainModules.GoVersion(modload.LoaderState)
if gover.Compare(gv, "1.14") >= 0 && (modload.FindGoWork(base.Cwd()) != "" || modload.ModFile().Go != nil) { if gover.Compare(gv, "1.14") >= 0 && (modload.FindGoWork(modload.LoaderState, base.Cwd()) != "" || modload.ModFile().Go != nil) {
// If the Go version is at least 1.14, annotate all explicit 'require' and // If the Go version is at least 1.14, annotate all explicit 'require' and
// 'replace' targets found in the go.mod file so that we can perform a // 'replace' targets found in the go.mod file so that we can perform a
// stronger consistency check when -mod=vendor is set. // stronger consistency check when -mod=vendor is set.
@ -162,7 +162,7 @@ func RunVendor(ctx context.Context, vendorE bool, vendorO string, args []string)
replacementWritten := make(map[module.Version]bool) replacementWritten := make(map[module.Version]bool)
for _, m := range vendorMods { for _, m := range vendorMods {
replacement := modload.Replacement(m) replacement := modload.Replacement(modload.LoaderState, m)
line := moduleLine(m, replacement) line := moduleLine(m, replacement)
replacementWritten[m] = true replacementWritten[m] = true
io.WriteString(w, line) io.WriteString(w, line)
@ -215,7 +215,7 @@ func RunVendor(ctx context.Context, vendorE bool, vendorO string, args []string)
continue continue
} }
replacementWritten[r.Old] = true replacementWritten[r.Old] = true
rNew := modload.Replacement(r.Old) rNew := modload.Replacement(modload.LoaderState, r.Old)
if rNew == (module.Version{}) { if rNew == (module.Version{}) {
// There is no replacement. Don't try to write it. // There is no replacement. Don't try to write it.
continue continue
@ -269,7 +269,7 @@ func moduleLine(m, r module.Version) string {
} }
func vendorPkg(vdir, pkg string) { func vendorPkg(vdir, pkg string) {
src, realPath, _ := modload.Lookup("", false, pkg) src, realPath, _ := modload.Lookup(modload.LoaderState, "", false, pkg)
if src == "" { if src == "" {
base.Errorf("internal error: no pkg for %s\n", pkg) base.Errorf("internal error: no pkg for %s\n", pkg)
return return
@ -315,7 +315,7 @@ func vendorPkg(vdir, pkg string) {
} }
} }
var embedPatterns []string var embedPatterns []string
if gover.Compare(modload.LoaderState.MainModules.GoVersion(), "1.22") >= 0 { if gover.Compare(modload.LoaderState.MainModules.GoVersion(modload.LoaderState), "1.22") >= 0 {
embedPatterns = bp.EmbedPatterns embedPatterns = bp.EmbedPatterns
} else { } else {
// Maintain the behavior of https://github.com/golang/go/issues/63473 // Maintain the behavior of https://github.com/golang/go/issues/63473
@ -431,7 +431,7 @@ func matchPotentialSourceFile(dir string, info fs.DirEntry) bool {
return false return false
} }
if info.Name() == "go.mod" || info.Name() == "go.sum" { if info.Name() == "go.mod" || info.Name() == "go.sum" {
if gv := modload.LoaderState.MainModules.GoVersion(); gover.Compare(gv, "1.17") >= 0 { if gv := modload.LoaderState.MainModules.GoVersion(modload.LoaderState); gover.Compare(gv, "1.17") >= 0 {
// As of Go 1.17, we strip go.mod and go.sum files from dependency modules. // As of Go 1.17, we strip go.mod and go.sum files from dependency modules.
// Otherwise, 'go' commands invoked within the vendor subtree may misidentify // Otherwise, 'go' commands invoked within the vendor subtree may misidentify
// an arbitrary directory within the vendor tree as a module root. // an arbitrary directory within the vendor tree as a module root.

View file

@ -44,7 +44,7 @@ func init() {
} }
func runVerify(ctx context.Context, cmd *base.Command, args []string) { func runVerify(ctx context.Context, cmd *base.Command, args []string) {
modload.InitWorkfile() modload.InitWorkfile(modload.LoaderState)
if len(args) != 0 { if len(args) != 0 {
// NOTE(rsc): Could take a module pattern. // NOTE(rsc): Could take a module pattern.

View file

@ -63,7 +63,7 @@ func init() {
} }
func runWhy(ctx context.Context, cmd *base.Command, args []string) { func runWhy(ctx context.Context, cmd *base.Command, args []string) {
modload.InitWorkfile() modload.InitWorkfile(modload.LoaderState)
modload.LoaderState.ForceUseModules = true modload.LoaderState.ForceUseModules = true
modload.LoaderState.RootMode = modload.NeedRoot modload.LoaderState.RootMode = modload.NeedRoot
modload.ExplicitWriteGoMod = true // don't write go.mod in ListModules modload.ExplicitWriteGoMod = true // don't write go.mod in ListModules
@ -89,7 +89,7 @@ func runWhy(ctx context.Context, cmd *base.Command, args []string) {
} }
byModule := make(map[string][]string) byModule := make(map[string][]string)
_, pkgs := modload.LoadPackages(ctx, loadOpts, "all") _, pkgs := modload.LoadPackages(modload.LoaderState, ctx, loadOpts, "all")
for _, path := range pkgs { for _, path := range pkgs {
m := modload.PackageModule(path) m := modload.PackageModule(path)
if m.Path != "" { if m.Path != "" {
@ -120,9 +120,9 @@ func runWhy(ctx context.Context, cmd *base.Command, args []string) {
} }
} else { } else {
// Resolve to packages. // Resolve to packages.
matches, _ := modload.LoadPackages(ctx, loadOpts, args...) matches, _ := modload.LoadPackages(modload.LoaderState, ctx, loadOpts, args...)
modload.LoadPackages(ctx, loadOpts, "all") // rebuild graph, from main module (not from named packages) modload.LoadPackages(modload.LoaderState, ctx, loadOpts, "all") // rebuild graph, from main module (not from named packages)
sep := "" sep := ""
for _, m := range matches { for _, m := range matches {

View file

@ -94,7 +94,7 @@ func TestZipSums(t *testing.T) {
cfg.GOPROXY = "direct" cfg.GOPROXY = "direct"
cfg.GOSUMDB = "off" cfg.GOSUMDB = "off"
modload.Init() modload.Init(modload.LoaderState)
// Shard tests by downloading only every nth module when shard flags are set. // Shard tests by downloading only every nth module when shard flags are set.
// This makes it easier to test small groups of modules quickly. We avoid // This makes it easier to test small groups of modules quickly. We avoid

View file

@ -307,14 +307,14 @@ func runGet(ctx context.Context, cmd *base.Command, args []string) {
// Allow looking up modules for import paths when outside of a module. // Allow looking up modules for import paths when outside of a module.
// 'go get' is expected to do this, unlike other commands. // 'go get' is expected to do this, unlike other commands.
modload.AllowMissingModuleImports() modload.AllowMissingModuleImports(modload.LoaderState)
// 'go get' no longer builds or installs packages, so there's nothing to do // 'go get' no longer builds or installs packages, so there's nothing to do
// if there's no go.mod file. // if there's no go.mod file.
// TODO(#40775): make modload.Init return ErrNoModRoot instead of exiting. // TODO(#40775): make modload.Init return ErrNoModRoot instead of exiting.
// We could handle that here by printing a different message. // We could handle that here by printing a different message.
modload.Init() modload.Init(modload.LoaderState)
if !modload.HasModRoot() { if !modload.HasModRoot(modload.LoaderState) {
base.Fatalf("go: go.mod file not found in current directory or any parent directory.\n" + base.Fatalf("go: go.mod file not found in current directory or any parent directory.\n" +
"\t'go get' is no longer supported outside a module.\n" + "\t'go get' is no longer supported outside a module.\n" +
"\tTo build and install a command, use 'go install' with a version,\n" + "\tTo build and install a command, use 'go install' with a version,\n" +
@ -424,9 +424,9 @@ func runGet(ctx context.Context, cmd *base.Command, args []string) {
newReqs := reqsFromGoMod(modload.ModFile()) newReqs := reqsFromGoMod(modload.ModFile())
r.reportChanges(oldReqs, newReqs) r.reportChanges(oldReqs, newReqs)
if gowork := modload.FindGoWork(base.Cwd()); gowork != "" { if gowork := modload.FindGoWork(modload.LoaderState, base.Cwd()); gowork != "" {
wf, err := modload.ReadWorkFile(gowork) wf, err := modload.ReadWorkFile(gowork)
if err == nil && modload.UpdateWorkGoVersion(wf, modload.LoaderState.MainModules.GoVersion()) { if err == nil && modload.UpdateWorkGoVersion(wf, modload.LoaderState.MainModules.GoVersion(modload.LoaderState)) {
modload.WriteWorkFile(gowork, wf) modload.WriteWorkFile(gowork, wf)
} }
} }
@ -448,7 +448,7 @@ func updateTools(ctx context.Context, queries []*query, opts *modload.WriteOpts)
patterns = append(patterns, q.pattern) patterns = append(patterns, q.pattern)
} }
matches, _ := modload.LoadPackages(ctx, pkgOpts, patterns...) matches, _ := modload.LoadPackages(modload.LoaderState, ctx, pkgOpts, patterns...)
for i, m := range matches { for i, m := range matches {
if queries[i].version == "none" { if queries[i].version == "none" {
opts.DropTools = append(opts.DropTools, m.Pkgs...) opts.DropTools = append(opts.DropTools, m.Pkgs...)
@ -574,7 +574,7 @@ func newResolver(ctx context.Context, queries []*query) *resolver {
buildListVersion: initialVersion, buildListVersion: initialVersion,
initialVersion: initialVersion, initialVersion: initialVersion,
nonesByPath: map[string]*query{}, nonesByPath: map[string]*query{},
workspace: loadWorkspace(modload.FindGoWork(base.Cwd())), workspace: loadWorkspace(modload.FindGoWork(modload.LoaderState, base.Cwd())),
} }
for _, q := range queries { for _, q := range queries {
@ -645,7 +645,7 @@ func (r *resolver) noneForPath(mPath string) (nq *query, found bool) {
// allowed versions. // allowed versions.
func (r *resolver) queryModule(ctx context.Context, mPath, query string, selected func(string) string) (module.Version, error) { func (r *resolver) queryModule(ctx context.Context, mPath, query string, selected func(string) string) (module.Version, error) {
current := r.initialSelected(mPath) current := r.initialSelected(mPath)
rev, err := modload.Query(ctx, mPath, query, current, r.checkAllowedOr(query, selected)) rev, err := modload.Query(modload.LoaderState, ctx, mPath, query, current, r.checkAllowedOr(query, selected))
if err != nil { if err != nil {
return module.Version{}, err return module.Version{}, err
} }
@ -655,7 +655,7 @@ func (r *resolver) queryModule(ctx context.Context, mPath, query string, selecte
// queryPackages wraps modload.QueryPackage, substituting r.checkAllowedOr to // queryPackages wraps modload.QueryPackage, substituting r.checkAllowedOr to
// decide allowed versions. // decide allowed versions.
func (r *resolver) queryPackages(ctx context.Context, pattern, query string, selected func(string) string) (pkgMods []module.Version, err error) { func (r *resolver) queryPackages(ctx context.Context, pattern, query string, selected func(string) string) (pkgMods []module.Version, err error) {
results, err := modload.QueryPackages(ctx, pattern, query, selected, r.checkAllowedOr(query, selected)) results, err := modload.QueryPackages(modload.LoaderState, ctx, pattern, query, selected, r.checkAllowedOr(query, selected))
if len(results) > 0 { if len(results) > 0 {
pkgMods = make([]module.Version, 0, len(results)) pkgMods = make([]module.Version, 0, len(results))
for _, qr := range results { for _, qr := range results {
@ -668,7 +668,7 @@ func (r *resolver) queryPackages(ctx context.Context, pattern, query string, sel
// queryPattern wraps modload.QueryPattern, substituting r.checkAllowedOr to // queryPattern wraps modload.QueryPattern, substituting r.checkAllowedOr to
// decide allowed versions. // decide allowed versions.
func (r *resolver) queryPattern(ctx context.Context, pattern, query string, selected func(string) string) (pkgMods []module.Version, mod module.Version, err error) { func (r *resolver) queryPattern(ctx context.Context, pattern, query string, selected func(string) string) (pkgMods []module.Version, mod module.Version, err error) {
results, modOnly, err := modload.QueryPattern(ctx, pattern, query, selected, r.checkAllowedOr(query, selected)) results, modOnly, err := modload.QueryPattern(modload.LoaderState, ctx, pattern, query, selected, r.checkAllowedOr(query, selected))
if len(results) > 0 { if len(results) > 0 {
pkgMods = make([]module.Version, 0, len(results)) pkgMods = make([]module.Version, 0, len(results))
for _, qr := range results { for _, qr := range results {
@ -721,7 +721,7 @@ func (r *resolver) queryNone(ctx context.Context, q *query) {
if !q.isWildcard() { if !q.isWildcard() {
q.pathOnce(q.pattern, func() pathSet { q.pathOnce(q.pattern, func() pathSet {
hasModRoot := modload.HasModRoot() hasModRoot := modload.HasModRoot(modload.LoaderState)
if hasModRoot && modload.LoaderState.MainModules.Contains(q.pattern) { if hasModRoot && modload.LoaderState.MainModules.Contains(q.pattern) {
v := module.Version{Path: q.pattern} v := module.Version{Path: q.pattern}
// The user has explicitly requested to downgrade their own module to // The user has explicitly requested to downgrade their own module to
@ -746,7 +746,7 @@ func (r *resolver) queryNone(ctx context.Context, q *query) {
continue continue
} }
q.pathOnce(curM.Path, func() pathSet { q.pathOnce(curM.Path, func() pathSet {
if modload.HasModRoot() && curM.Version == "" && modload.LoaderState.MainModules.Contains(curM.Path) { if modload.HasModRoot(modload.LoaderState) && curM.Version == "" && modload.LoaderState.MainModules.Contains(curM.Path) {
return errSet(&modload.QueryMatchesMainModulesError{MainModules: []module.Version{curM}, Pattern: q.pattern, Query: q.version}) return errSet(&modload.QueryMatchesMainModulesError{MainModules: []module.Version{curM}, Pattern: q.pattern, Query: q.version})
} }
return pathSet{mod: module.Version{Path: curM.Path, Version: "none"}} return pathSet{mod: module.Version{Path: curM.Path, Version: "none"}}
@ -766,7 +766,7 @@ func (r *resolver) performLocalQueries(ctx context.Context) {
// Absolute paths like C:\foo and relative paths like ../foo... are // Absolute paths like C:\foo and relative paths like ../foo... are
// restricted to matching packages in the main module. // restricted to matching packages in the main module.
pkgPattern, mainModule := modload.LoaderState.MainModules.DirImportPath(ctx, q.pattern) pkgPattern, mainModule := modload.LoaderState.MainModules.DirImportPath(modload.LoaderState, ctx, q.pattern)
if pkgPattern == "." { if pkgPattern == "." {
modload.MustHaveModRoot() modload.MustHaveModRoot()
versions := modload.LoaderState.MainModules.Versions() versions := modload.LoaderState.MainModules.Versions()
@ -1275,13 +1275,13 @@ func (r *resolver) loadPackages(ctx context.Context, patterns []string, findPack
return nil return nil
} }
_, pkgs := modload.LoadPackages(ctx, opts, patterns...) _, pkgs := modload.LoadPackages(modload.LoaderState, ctx, opts, patterns...)
for _, pkgPath := range pkgs { for _, pkgPath := range pkgs {
const ( const (
parentPath = "" parentPath = ""
parentIsStd = false parentIsStd = false
) )
_, _, err := modload.Lookup(parentPath, parentIsStd, pkgPath) _, _, err := modload.Lookup(modload.LoaderState, parentPath, parentIsStd, pkgPath)
if err == nil { if err == nil {
continue continue
} }
@ -1651,7 +1651,7 @@ func (r *resolver) checkPackageProblems(ctx context.Context, pkgPatterns []strin
AllowErrors: true, AllowErrors: true,
SilenceNoGoErrors: true, SilenceNoGoErrors: true,
} }
matches, pkgs := modload.LoadPackages(ctx, pkgOpts, pkgPatterns...) matches, pkgs := modload.LoadPackages(modload.LoaderState, ctx, pkgOpts, pkgPatterns...)
for _, m := range matches { for _, m := range matches {
if len(m.Errs) > 0 { if len(m.Errs) > 0 {
base.SetExitStatus(1) base.SetExitStatus(1)
@ -1659,7 +1659,7 @@ func (r *resolver) checkPackageProblems(ctx context.Context, pkgPatterns []strin
} }
} }
for _, pkg := range pkgs { for _, pkg := range pkgs {
if dir, _, err := modload.Lookup("", false, pkg); err != nil { if dir, _, err := modload.Lookup(modload.LoaderState, "", false, pkg); err != nil {
if dir != "" && errors.Is(err, imports.ErrNoGo) { if dir != "" && errors.Is(err, imports.ErrNoGo) {
// Since dir is non-empty, we must have located source files // Since dir is non-empty, we must have located source files
// associated with either the package or its test — ErrNoGo must // associated with either the package or its test — ErrNoGo must
@ -1690,7 +1690,7 @@ func (r *resolver) checkPackageProblems(ctx context.Context, pkgPatterns []strin
} }
} }
reqs := modload.LoadModFile(ctx) reqs := modload.LoadModFile(modload.LoaderState, ctx)
for m := range relevantMods { for m := range relevantMods {
if reqs.IsDirect(m.Path) { if reqs.IsDirect(m.Path) {
relevantMods[m] |= direct relevantMods[m] |= direct
@ -1714,7 +1714,7 @@ func (r *resolver) checkPackageProblems(ctx context.Context, pkgPatterns []strin
for i := range retractions { for i := range retractions {
i := i i := i
r.work.Add(func() { r.work.Add(func() {
err := modload.CheckRetractions(ctx, retractions[i].m) err := modload.CheckRetractions(modload.LoaderState, ctx, retractions[i].m)
if _, ok := errors.AsType[*modload.ModuleRetractedError](err); ok { if _, ok := errors.AsType[*modload.ModuleRetractedError](err); ok {
retractions[i].message = err.Error() retractions[i].message = err.Error()
} }
@ -1735,7 +1735,7 @@ func (r *resolver) checkPackageProblems(ctx context.Context, pkgPatterns []strin
for i := range deprecations { for i := range deprecations {
i := i i := i
r.work.Add(func() { r.work.Add(func() {
deprecation, err := modload.CheckDeprecation(ctx, deprecations[i].m) deprecation, err := modload.CheckDeprecation(modload.LoaderState, ctx, deprecations[i].m)
if err != nil || deprecation == "" { if err != nil || deprecation == "" {
return return
} }
@ -1765,7 +1765,7 @@ func (r *resolver) checkPackageProblems(ctx context.Context, pkgPatterns []strin
i := i i := i
m := r.buildList[i] m := r.buildList[i]
mActual := m mActual := m
if mRepl := modload.Replacement(m); mRepl.Path != "" { if mRepl := modload.Replacement(modload.LoaderState, m); mRepl.Path != "" {
mActual = mRepl mActual = mRepl
} }
old := module.Version{Path: m.Path, Version: r.initialVersion[m.Path]} old := module.Version{Path: m.Path, Version: r.initialVersion[m.Path]}
@ -1773,7 +1773,7 @@ func (r *resolver) checkPackageProblems(ctx context.Context, pkgPatterns []strin
continue continue
} }
oldActual := old oldActual := old
if oldRepl := modload.Replacement(old); oldRepl.Path != "" { if oldRepl := modload.Replacement(modload.LoaderState, old); oldRepl.Path != "" {
oldActual = oldRepl oldActual = oldRepl
} }
if mActual == oldActual || mActual.Version == "" || !modfetch.HaveSum(oldActual) { if mActual == oldActual || mActual.Version == "" || !modfetch.HaveSum(oldActual) {
@ -1986,7 +1986,7 @@ func (r *resolver) updateBuildList(ctx context.Context, additions []module.Versi
} }
} }
changed, err := modload.EditBuildList(ctx, additions, resolved) changed, err := modload.EditBuildList(modload.LoaderState, ctx, additions, resolved)
if err != nil { if err != nil {
if errors.Is(err, gover.ErrTooNew) { if errors.Is(err, gover.ErrTooNew) {
toolchain.SwitchOrFatal(ctx, err) toolchain.SwitchOrFatal(ctx, err)

View file

@ -184,7 +184,7 @@ func (q *query) validate() error {
if q.pattern == "all" { if q.pattern == "all" {
// If there is no main module, "all" is not meaningful. // If there is no main module, "all" is not meaningful.
if !modload.HasModRoot() { if !modload.HasModRoot(modload.LoaderState) {
return fmt.Errorf(`cannot match "all": %v`, modload.ErrNoModRoot) return fmt.Errorf(`cannot match "all": %v`, modload.ErrNoModRoot)
} }
if !versionOkForMainModule(q.version) { if !versionOkForMainModule(q.version) {

View file

@ -51,8 +51,8 @@ func findStandardImportPath(path string) string {
// a given package. If modules are not enabled or if the package is in the // a given package. If modules are not enabled or if the package is in the
// standard library or if the package was not successfully loaded with // standard library or if the package was not successfully loaded with
// LoadPackages or ImportFromFiles, nil is returned. // LoadPackages or ImportFromFiles, nil is returned.
func PackageModuleInfo(ctx context.Context, pkgpath string) *modinfo.ModulePublic { func PackageModuleInfo(loaderstate *State, ctx context.Context, pkgpath string) *modinfo.ModulePublic {
if isStandardImportPath(pkgpath) || !Enabled() { if isStandardImportPath(pkgpath) || !Enabled(loaderstate) {
return nil return nil
} }
m, ok := findModule(loaded, pkgpath) m, ok := findModule(loaded, pkgpath)
@ -60,23 +60,23 @@ func PackageModuleInfo(ctx context.Context, pkgpath string) *modinfo.ModulePubli
return nil return nil
} }
rs := LoadModFile(ctx) rs := LoadModFile(loaderstate, ctx)
return moduleInfo(ctx, rs, m, 0, nil) return moduleInfo(loaderstate, ctx, rs, m, 0, nil)
} }
// PackageModRoot returns the module root directory for the module that provides // PackageModRoot returns the module root directory for the module that provides
// a given package. If modules are not enabled or if the package is in the // a given package. If modules are not enabled or if the package is in the
// standard library or if the package was not successfully loaded with // standard library or if the package was not successfully loaded with
// LoadPackages or ImportFromFiles, the empty string is returned. // LoadPackages or ImportFromFiles, the empty string is returned.
func PackageModRoot(ctx context.Context, pkgpath string) string { func PackageModRoot(loaderstate *State, ctx context.Context, pkgpath string) string {
if isStandardImportPath(pkgpath) || !Enabled() || cfg.BuildMod == "vendor" { if isStandardImportPath(pkgpath) || !Enabled(loaderstate) || cfg.BuildMod == "vendor" {
return "" return ""
} }
m, ok := findModule(loaded, pkgpath) m, ok := findModule(loaded, pkgpath)
if !ok { if !ok {
return "" return ""
} }
root, _, err := fetch(ctx, m) root, _, err := fetch(loaderstate, ctx, m)
if err != nil { if err != nil {
return "" return ""
} }
@ -84,26 +84,26 @@ func PackageModRoot(ctx context.Context, pkgpath string) string {
} }
func ModuleInfo(ctx context.Context, path string) *modinfo.ModulePublic { func ModuleInfo(ctx context.Context, path string) *modinfo.ModulePublic {
if !Enabled() { if !Enabled(LoaderState) {
return nil return nil
} }
if path, vers, found := strings.Cut(path, "@"); found { if path, vers, found := strings.Cut(path, "@"); found {
m := module.Version{Path: path, Version: vers} m := module.Version{Path: path, Version: vers}
return moduleInfo(ctx, nil, m, 0, nil) return moduleInfo(LoaderState, ctx, nil, m, 0, nil)
} }
rs := LoadModFile(ctx) rs := LoadModFile(LoaderState, ctx)
var ( var (
v string v string
ok bool ok bool
) )
if rs.pruning == pruned { if rs.pruning == pruned {
v, ok = rs.rootSelected(path) v, ok = rs.rootSelected(LoaderState, path)
} }
if !ok { if !ok {
mg, err := rs.Graph(ctx) mg, err := rs.Graph(LoaderState, ctx)
if err != nil { if err != nil {
base.Fatal(err) base.Fatal(err)
} }
@ -119,7 +119,7 @@ func ModuleInfo(ctx context.Context, path string) *modinfo.ModulePublic {
} }
} }
return moduleInfo(ctx, rs, module.Version{Path: path, Version: v}, 0, nil) return moduleInfo(LoaderState, ctx, rs, module.Version{Path: path, Version: v}, 0, nil)
} }
// addUpdate fills in m.Update if an updated version is available. // addUpdate fills in m.Update if an updated version is available.
@ -128,7 +128,7 @@ func addUpdate(ctx context.Context, m *modinfo.ModulePublic) {
return return
} }
info, err := Query(ctx, m.Path, "upgrade", m.Version, CheckAllowed) info, err := Query(LoaderState, ctx, m.Path, "upgrade", m.Version, CheckAllowed)
if _, ok := errors.AsType[*NoMatchingVersionError](err); ok || if _, ok := errors.AsType[*NoMatchingVersionError](err); ok ||
errors.Is(err, fs.ErrNotExist) || errors.Is(err, fs.ErrNotExist) ||
errors.Is(err, ErrDisallowed) { errors.Is(err, ErrDisallowed) {
@ -221,7 +221,7 @@ func addVersions(ctx context.Context, m *modinfo.ModulePublic, listRetracted boo
if listRetracted { if listRetracted {
allowed = CheckExclusions allowed = CheckExclusions
} }
v, origin, err := versions(ctx, m.Path, allowed) v, origin, err := versions(LoaderState, ctx, m.Path, allowed)
if err != nil && m.Error == nil { if err != nil && m.Error == nil {
m.Error = &modinfo.ModuleError{Err: err.Error()} m.Error = &modinfo.ModuleError{Err: err.Error()}
} }
@ -231,12 +231,12 @@ func addVersions(ctx context.Context, m *modinfo.ModulePublic, listRetracted boo
// addRetraction fills in m.Retracted if the module was retracted by its author. // addRetraction fills in m.Retracted if the module was retracted by its author.
// m.Error is set if there's an error loading retraction information. // m.Error is set if there's an error loading retraction information.
func addRetraction(ctx context.Context, m *modinfo.ModulePublic) { func addRetraction(loaderstate *State, ctx context.Context, m *modinfo.ModulePublic) {
if m.Version == "" { if m.Version == "" {
return return
} }
err := CheckRetractions(ctx, module.Version{Path: m.Path, Version: m.Version}) err := CheckRetractions(loaderstate, ctx, module.Version{Path: m.Path, Version: m.Version})
if err == nil { if err == nil {
return return
} else if _, ok := errors.AsType[*NoMatchingVersionError](err); ok || errors.Is(err, fs.ErrNotExist) { } else if _, ok := errors.AsType[*NoMatchingVersionError](err); ok || errors.Is(err, fs.ErrNotExist) {
@ -263,7 +263,7 @@ func addRetraction(ctx context.Context, m *modinfo.ModulePublic) {
// addDeprecation fills in m.Deprecated if the module was deprecated by its // addDeprecation fills in m.Deprecated if the module was deprecated by its
// author. m.Error is set if there's an error loading deprecation information. // author. m.Error is set if there's an error loading deprecation information.
func addDeprecation(ctx context.Context, m *modinfo.ModulePublic) { func addDeprecation(ctx context.Context, m *modinfo.ModulePublic) {
deprecation, err := CheckDeprecation(ctx, module.Version{Path: m.Path, Version: m.Version}) deprecation, err := CheckDeprecation(LoaderState, ctx, module.Version{Path: m.Path, Version: m.Version})
if _, ok := errors.AsType[*NoMatchingVersionError](err); ok || errors.Is(err, fs.ErrNotExist) { if _, ok := errors.AsType[*NoMatchingVersionError](err); ok || errors.Is(err, fs.ErrNotExist) {
// Ignore "no matching version" and "not found" errors. // Ignore "no matching version" and "not found" errors.
// This means the proxy has no matching version or no versions at all. // This means the proxy has no matching version or no versions at all.
@ -287,8 +287,8 @@ func addDeprecation(ctx context.Context, m *modinfo.ModulePublic) {
// moduleInfo returns information about module m, loaded from the requirements // moduleInfo returns information about module m, loaded from the requirements
// in rs (which may be nil to indicate that m was not loaded from a requirement // in rs (which may be nil to indicate that m was not loaded from a requirement
// graph). // graph).
func moduleInfo(ctx context.Context, rs *Requirements, m module.Version, mode ListMode, reuse map[module.Version]*modinfo.ModulePublic) *modinfo.ModulePublic { func moduleInfo(loaderstate *State, ctx context.Context, rs *Requirements, m module.Version, mode ListMode, reuse map[module.Version]*modinfo.ModulePublic) *modinfo.ModulePublic {
if m.Version == "" && LoaderState.MainModules.Contains(m.Path) { if m.Version == "" && loaderstate.MainModules.Contains(m.Path) {
info := &modinfo.ModulePublic{ info := &modinfo.ModulePublic{
Path: m.Path, Path: m.Path,
Version: m.Version, Version: m.Version,
@ -299,7 +299,7 @@ func moduleInfo(ctx context.Context, rs *Requirements, m module.Version, mode Li
} else { } else {
panic("internal error: GoVersion not set for main module") panic("internal error: GoVersion not set for main module")
} }
if modRoot := LoaderState.MainModules.ModRoot(m); modRoot != "" { if modRoot := loaderstate.MainModules.ModRoot(m); modRoot != "" {
info.Dir = modRoot info.Dir = modRoot
info.GoMod = modFilePath(modRoot) info.GoMod = modFilePath(modRoot)
} }
@ -322,7 +322,7 @@ func moduleInfo(ctx context.Context, rs *Requirements, m module.Version, mode Li
} }
checksumOk := func(suffix string) bool { checksumOk := func(suffix string) bool {
return rs == nil || m.Version == "" || !mustHaveSums() || return rs == nil || m.Version == "" || !mustHaveSums(loaderstate) ||
modfetch.HaveSum(module.Version{Path: m.Path, Version: m.Version + suffix}) modfetch.HaveSum(module.Version{Path: m.Path, Version: m.Version + suffix})
} }
@ -330,7 +330,7 @@ func moduleInfo(ctx context.Context, rs *Requirements, m module.Version, mode Li
if m.Version != "" { if m.Version != "" {
if old := reuse[mod]; old != nil { if old := reuse[mod]; old != nil {
if err := checkReuse(ctx, mod, old.Origin); err == nil { if err := checkReuse(loaderstate, ctx, mod, old.Origin); err == nil {
*m = *old *m = *old
m.Query = "" m.Query = ""
m.Dir = "" m.Dir = ""
@ -338,7 +338,7 @@ func moduleInfo(ctx context.Context, rs *Requirements, m module.Version, mode Li
} }
} }
if q, err := Query(ctx, m.Path, m.Version, "", nil); err != nil { if q, err := Query(loaderstate, ctx, m.Path, m.Version, "", nil); err != nil {
m.Error = &modinfo.ModuleError{Err: err.Error()} m.Error = &modinfo.ModuleError{Err: err.Error()}
} else { } else {
m.Version = q.Version m.Version = q.Version
@ -349,7 +349,7 @@ func moduleInfo(ctx context.Context, rs *Requirements, m module.Version, mode Li
if m.GoVersion == "" && checksumOk("/go.mod") { if m.GoVersion == "" && checksumOk("/go.mod") {
// Load the go.mod file to determine the Go version, since it hasn't // Load the go.mod file to determine the Go version, since it hasn't
// already been populated from rawGoVersion. // already been populated from rawGoVersion.
if summary, err := rawGoModSummary(mod); err == nil && summary.goVersion != "" { if summary, err := rawGoModSummary(loaderstate, mod); err == nil && summary.goVersion != "" {
m.GoVersion = summary.goVersion m.GoVersion = summary.goVersion
} }
} }
@ -377,7 +377,7 @@ func moduleInfo(ctx context.Context, rs *Requirements, m module.Version, mode Li
} }
if mode&ListRetracted != 0 { if mode&ListRetracted != 0 {
addRetraction(ctx, m) addRetraction(loaderstate, ctx, m)
} }
} }
} }
@ -389,7 +389,7 @@ func moduleInfo(ctx context.Context, rs *Requirements, m module.Version, mode Li
return info return info
} }
r := Replacement(m) r := Replacement(loaderstate, m)
if r.Path == "" { if r.Path == "" {
if cfg.BuildMod == "vendor" { if cfg.BuildMod == "vendor" {
// It's tempting to fill in the "Dir" field to point within the vendor // It's tempting to fill in the "Dir" field to point within the vendor
@ -418,7 +418,7 @@ func moduleInfo(ctx context.Context, rs *Requirements, m module.Version, mode Li
if filepath.IsAbs(r.Path) { if filepath.IsAbs(r.Path) {
info.Replace.Dir = r.Path info.Replace.Dir = r.Path
} else { } else {
info.Replace.Dir = filepath.Join(replaceRelativeTo(), r.Path) info.Replace.Dir = filepath.Join(replaceRelativeTo(loaderstate), r.Path)
} }
info.Replace.GoMod = filepath.Join(info.Replace.Dir, "go.mod") info.Replace.GoMod = filepath.Join(info.Replace.Dir, "go.mod")
} }

View file

@ -104,21 +104,21 @@ func mustHaveGoRoot(roots []module.Version) {
// //
// If vendoring is in effect, the caller must invoke initVendor on the returned // If vendoring is in effect, the caller must invoke initVendor on the returned
// *Requirements before any other method. // *Requirements before any other method.
func newRequirements(pruning modPruning, rootModules []module.Version, direct map[string]bool) *Requirements { func newRequirements(loaderstate *State, pruning modPruning, rootModules []module.Version, direct map[string]bool) *Requirements {
mustHaveGoRoot(rootModules) mustHaveGoRoot(rootModules)
if pruning != workspace { if pruning != workspace {
if LoaderState.workFilePath != "" { if loaderstate.workFilePath != "" {
panic("in workspace mode, but pruning is not workspace in newRequirements") panic("in workspace mode, but pruning is not workspace in newRequirements")
} }
} }
if pruning != workspace { if pruning != workspace {
if LoaderState.workFilePath != "" { if loaderstate.workFilePath != "" {
panic("in workspace mode, but pruning is not workspace in newRequirements") panic("in workspace mode, but pruning is not workspace in newRequirements")
} }
for i, m := range rootModules { for i, m := range rootModules {
if m.Version == "" && LoaderState.MainModules.Contains(m.Path) { if m.Version == "" && loaderstate.MainModules.Contains(m.Path) {
panic(fmt.Sprintf("newRequirements called with untrimmed build list: rootModules[%v] is a main module", i)) panic(fmt.Sprintf("newRequirements called with untrimmed build list: rootModules[%v] is a main module", i))
} }
if m.Path == "" || m.Version == "" { if m.Path == "" || m.Version == "" {
@ -162,10 +162,10 @@ func (rs *Requirements) String() string {
// initVendor initializes rs.graph from the given list of vendored module // initVendor initializes rs.graph from the given list of vendored module
// dependencies, overriding the graph that would normally be loaded from module // dependencies, overriding the graph that would normally be loaded from module
// requirements. // requirements.
func (rs *Requirements) initVendor(vendorList []module.Version) { func (rs *Requirements) initVendor(loaderstate *State, vendorList []module.Version) {
rs.graphOnce.Do(func() { rs.graphOnce.Do(func() {
roots := LoaderState.MainModules.Versions() roots := loaderstate.MainModules.Versions()
if inWorkspaceMode() { if inWorkspaceMode(loaderstate) {
// Use rs.rootModules to pull in the go and toolchain roots // Use rs.rootModules to pull in the go and toolchain roots
// from the go.work file and preserve the invariant that all // from the go.work file and preserve the invariant that all
// of rs.rootModules are in mg.g. // of rs.rootModules are in mg.g.
@ -176,7 +176,7 @@ func (rs *Requirements) initVendor(vendorList []module.Version) {
} }
if rs.pruning == pruned { if rs.pruning == pruned {
mainModule := LoaderState.MainModules.mustGetSingleMainModule() mainModule := loaderstate.MainModules.mustGetSingleMainModule(loaderstate)
// The roots of a single pruned module should already include every module in the // The roots of a single pruned module should already include every module in the
// vendor list, because the vendored modules are the same as those needed // vendor list, because the vendored modules are the same as those needed
// for graph pruning. // for graph pruning.
@ -184,7 +184,7 @@ func (rs *Requirements) initVendor(vendorList []module.Version) {
// Just to be sure, we'll double-check that here. // Just to be sure, we'll double-check that here.
inconsistent := false inconsistent := false
for _, m := range vendorList { for _, m := range vendorList {
if v, ok := rs.rootSelected(m.Path); !ok || v != m.Version { if v, ok := rs.rootSelected(loaderstate, m.Path); !ok || v != m.Version {
base.Errorf("go: vendored module %v should be required explicitly in go.mod", m) base.Errorf("go: vendored module %v should be required explicitly in go.mod", m)
inconsistent = true inconsistent = true
} }
@ -208,15 +208,15 @@ func (rs *Requirements) initVendor(vendorList []module.Version) {
// graph, but still distinguishes between direct and indirect // graph, but still distinguishes between direct and indirect
// dependencies. // dependencies.
vendorMod := module.Version{Path: "vendor/modules.txt", Version: ""} vendorMod := module.Version{Path: "vendor/modules.txt", Version: ""}
if inWorkspaceMode() { if inWorkspaceMode(loaderstate) {
for _, m := range LoaderState.MainModules.Versions() { for _, m := range loaderstate.MainModules.Versions() {
reqs, _ := rootsFromModFile(m, LoaderState.MainModules.ModFile(m), omitToolchainRoot) reqs, _ := rootsFromModFile(loaderstate, m, loaderstate.MainModules.ModFile(m), omitToolchainRoot)
mg.g.Require(m, append(reqs, vendorMod)) mg.g.Require(m, append(reqs, vendorMod))
} }
mg.g.Require(vendorMod, vendorList) mg.g.Require(vendorMod, vendorList)
} else { } else {
mainModule := LoaderState.MainModules.mustGetSingleMainModule() mainModule := loaderstate.MainModules.mustGetSingleMainModule(loaderstate)
mg.g.Require(mainModule, append(rs.rootModules, vendorMod)) mg.g.Require(mainModule, append(rs.rootModules, vendorMod))
mg.g.Require(vendorMod, vendorList) mg.g.Require(vendorMod, vendorList)
} }
@ -227,8 +227,8 @@ func (rs *Requirements) initVendor(vendorList []module.Version) {
} }
// GoVersion returns the Go language version for the Requirements. // GoVersion returns the Go language version for the Requirements.
func (rs *Requirements) GoVersion() string { func (rs *Requirements) GoVersion(loaderstate *State) string {
v, _ := rs.rootSelected("go") v, _ := rs.rootSelected(loaderstate, "go")
if v == "" { if v == "" {
panic("internal error: missing go version in modload.Requirements") panic("internal error: missing go version in modload.Requirements")
} }
@ -238,8 +238,8 @@ func (rs *Requirements) GoVersion() string {
// rootSelected returns the version of the root dependency with the given module // rootSelected returns the version of the root dependency with the given module
// path, or the zero module.Version and ok=false if the module is not a root // path, or the zero module.Version and ok=false if the module is not a root
// dependency. // dependency.
func (rs *Requirements) rootSelected(path string) (version string, ok bool) { func (rs *Requirements) rootSelected(loaderstate *State, path string) (version string, ok bool) {
if LoaderState.MainModules.Contains(path) { if loaderstate.MainModules.Contains(path) {
return "", true return "", true
} }
if v, ok := rs.maxRootVersion[path]; ok { if v, ok := rs.maxRootVersion[path]; ok {
@ -252,9 +252,9 @@ func (rs *Requirements) rootSelected(path string) (version string, ok bool) {
// of the same module or a requirement on any version of the main module. // of the same module or a requirement on any version of the main module.
// Redundant requirements should be pruned, but they may influence version // Redundant requirements should be pruned, but they may influence version
// selection. // selection.
func (rs *Requirements) hasRedundantRoot() bool { func (rs *Requirements) hasRedundantRoot(loaderstate *State) bool {
for i, m := range rs.rootModules { for i, m := range rs.rootModules {
if LoaderState.MainModules.Contains(m.Path) || (i > 0 && m.Path == rs.rootModules[i-1].Path) { if loaderstate.MainModules.Contains(m.Path) || (i > 0 && m.Path == rs.rootModules[i-1].Path) {
return true return true
} }
} }
@ -269,9 +269,9 @@ func (rs *Requirements) hasRedundantRoot() bool {
// //
// If the requirements of any relevant module fail to load, Graph also // If the requirements of any relevant module fail to load, Graph also
// returns a non-nil error of type *mvs.BuildListError. // returns a non-nil error of type *mvs.BuildListError.
func (rs *Requirements) Graph(ctx context.Context) (*ModuleGraph, error) { func (rs *Requirements) Graph(loaderstate *State, ctx context.Context) (*ModuleGraph, error) {
rs.graphOnce.Do(func() { rs.graphOnce.Do(func() {
mg, mgErr := readModGraph(ctx, rs.pruning, rs.rootModules, nil) mg, mgErr := readModGraph(loaderstate, ctx, rs.pruning, rs.rootModules, nil)
rs.graph.Store(&cachedGraph{mg, mgErr}) rs.graph.Store(&cachedGraph{mg, mgErr})
}) })
cached := rs.graph.Load() cached := rs.graph.Load()
@ -307,7 +307,7 @@ var readModGraphDebugOnce sync.Once
// //
// Unlike LoadModGraph, readModGraph does not attempt to diagnose or update // Unlike LoadModGraph, readModGraph does not attempt to diagnose or update
// inconsistent roots. // inconsistent roots.
func readModGraph(ctx context.Context, pruning modPruning, roots []module.Version, unprune map[module.Version]bool) (*ModuleGraph, error) { func readModGraph(loaderstate *State, ctx context.Context, pruning modPruning, roots []module.Version, unprune map[module.Version]bool) (*ModuleGraph, error) {
mustHaveGoRoot(roots) mustHaveGoRoot(roots)
if pruning == pruned { if pruning == pruned {
// Enable diagnostics for lazy module loading // Enable diagnostics for lazy module loading
@ -333,10 +333,10 @@ func readModGraph(ctx context.Context, pruning modPruning, roots []module.Versio
} }
var graphRoots []module.Version var graphRoots []module.Version
if inWorkspaceMode() { if inWorkspaceMode(loaderstate) {
graphRoots = roots graphRoots = roots
} else { } else {
graphRoots = LoaderState.MainModules.Versions() graphRoots = loaderstate.MainModules.Versions()
} }
var ( var (
mu sync.Mutex // guards mg.g and hasError during loading mu sync.Mutex // guards mg.g and hasError during loading
@ -347,10 +347,10 @@ func readModGraph(ctx context.Context, pruning modPruning, roots []module.Versio
) )
if pruning != workspace { if pruning != workspace {
if inWorkspaceMode() { if inWorkspaceMode(loaderstate) {
panic("pruning is not workspace in workspace mode") panic("pruning is not workspace in workspace mode")
} }
mg.g.Require(LoaderState.MainModules.mustGetSingleMainModule(), roots) mg.g.Require(loaderstate.MainModules.mustGetSingleMainModule(loaderstate), roots)
} }
type dedupKey struct { type dedupKey struct {
@ -367,7 +367,7 @@ func readModGraph(ctx context.Context, pruning modPruning, roots []module.Versio
// m's go.mod file indicates that it supports graph pruning. // m's go.mod file indicates that it supports graph pruning.
loadOne := func(m module.Version) (*modFileSummary, error) { loadOne := func(m module.Version) (*modFileSummary, error) {
return mg.loadCache.Do(m, func() (*modFileSummary, error) { return mg.loadCache.Do(m, func() (*modFileSummary, error) {
summary, err := goModSummary(m) summary, err := goModSummary(loaderstate, m)
mu.Lock() mu.Lock()
if err == nil { if err == nil {
@ -527,12 +527,12 @@ func (mg *ModuleGraph) findError() error {
return nil return nil
} }
func (mg *ModuleGraph) allRootsSelected() bool { func (mg *ModuleGraph) allRootsSelected(loaderstate *State) bool {
var roots []module.Version var roots []module.Version
if inWorkspaceMode() { if inWorkspaceMode(loaderstate) {
roots = LoaderState.MainModules.Versions() roots = loaderstate.MainModules.Versions()
} else { } else {
roots, _ = mg.g.RequiredBy(LoaderState.MainModules.mustGetSingleMainModule()) roots, _ = mg.g.RequiredBy(loaderstate.MainModules.mustGetSingleMainModule(loaderstate))
} }
for _, m := range roots { for _, m := range roots {
if mg.Selected(m.Path) != m.Version { if mg.Selected(m.Path) != m.Version {
@ -553,13 +553,13 @@ func (mg *ModuleGraph) allRootsSelected() bool {
// LoadModGraph need only be called if LoadPackages is not, // LoadModGraph need only be called if LoadPackages is not,
// typically in commands that care about modules but no particular package. // typically in commands that care about modules but no particular package.
func LoadModGraph(ctx context.Context, goVersion string) (*ModuleGraph, error) { func LoadModGraph(ctx context.Context, goVersion string) (*ModuleGraph, error) {
rs, err := loadModFile(ctx, nil) rs, err := loadModFile(LoaderState, ctx, nil)
if err != nil { if err != nil {
return nil, err return nil, err
} }
if goVersion != "" { if goVersion != "" {
v, _ := rs.rootSelected("go") v, _ := rs.rootSelected(LoaderState, "go")
if gover.Compare(v, gover.GoStrictVersion) >= 0 && gover.Compare(goVersion, v) < 0 { if gover.Compare(v, gover.GoStrictVersion) >= 0 && gover.Compare(goVersion, v) < 0 {
return nil, fmt.Errorf("requested Go version %s cannot load module graph (requires Go >= %s)", goVersion, v) return nil, fmt.Errorf("requested Go version %s cannot load module graph (requires Go >= %s)", goVersion, v)
} }
@ -569,13 +569,13 @@ func LoadModGraph(ctx context.Context, goVersion string) (*ModuleGraph, error) {
// Use newRequirements instead of convertDepth because convertDepth // Use newRequirements instead of convertDepth because convertDepth
// also updates roots; here, we want to report the unmodified roots // also updates roots; here, we want to report the unmodified roots
// even though they may seem inconsistent. // even though they may seem inconsistent.
rs = newRequirements(unpruned, rs.rootModules, rs.direct) rs = newRequirements(LoaderState, unpruned, rs.rootModules, rs.direct)
} }
return rs.Graph(ctx) return rs.Graph(LoaderState, ctx)
} }
rs, mg, err := expandGraph(ctx, rs) rs, mg, err := expandGraph(LoaderState, ctx, rs)
if err != nil { if err != nil {
return nil, err return nil, err
} }
@ -594,22 +594,22 @@ func LoadModGraph(ctx context.Context, goVersion string) (*ModuleGraph, error) {
// from those roots and any error encountered while loading that graph. // from those roots and any error encountered while loading that graph.
// expandGraph returns non-nil requirements and a non-nil graph regardless of // expandGraph returns non-nil requirements and a non-nil graph regardless of
// errors. On error, the roots might not be updated to be consistent. // errors. On error, the roots might not be updated to be consistent.
func expandGraph(ctx context.Context, rs *Requirements) (*Requirements, *ModuleGraph, error) { func expandGraph(loaderstate *State, ctx context.Context, rs *Requirements) (*Requirements, *ModuleGraph, error) {
mg, mgErr := rs.Graph(ctx) mg, mgErr := rs.Graph(loaderstate, ctx)
if mgErr != nil { if mgErr != nil {
// Without the graph, we can't update the roots: we don't know which // Without the graph, we can't update the roots: we don't know which
// versions of transitive dependencies would be selected. // versions of transitive dependencies would be selected.
return rs, mg, mgErr return rs, mg, mgErr
} }
if !mg.allRootsSelected() { if !mg.allRootsSelected(loaderstate) {
// The roots of rs are not consistent with the rest of the graph. Update // The roots of rs are not consistent with the rest of the graph. Update
// them. In an unpruned module this is a no-op for the build list as a whole — // them. In an unpruned module this is a no-op for the build list as a whole —
// it just promotes what were previously transitive requirements to be // it just promotes what were previously transitive requirements to be
// roots — but in a pruned module it may pull in previously-irrelevant // roots — but in a pruned module it may pull in previously-irrelevant
// transitive dependencies. // transitive dependencies.
newRS, rsErr := updateRoots(ctx, rs.direct, rs, nil, nil, false) newRS, rsErr := updateRoots(loaderstate, ctx, rs.direct, rs, nil, nil, false)
if rsErr != nil { if rsErr != nil {
// Failed to update roots, perhaps because of an error in a transitive // Failed to update roots, perhaps because of an error in a transitive
// dependency needed for the update. Return the original Requirements // dependency needed for the update. Return the original Requirements
@ -617,7 +617,7 @@ func expandGraph(ctx context.Context, rs *Requirements) (*Requirements, *ModuleG
return rs, mg, rsErr return rs, mg, rsErr
} }
rs = newRS rs = newRS
mg, mgErr = rs.Graph(ctx) mg, mgErr = rs.Graph(loaderstate, ctx)
} }
return rs, mg, mgErr return rs, mg, mgErr
@ -639,16 +639,16 @@ func expandGraph(ctx context.Context, rs *Requirements) (*Requirements, *ModuleG
// On success, EditBuildList reports whether the selected version of any module // On success, EditBuildList reports whether the selected version of any module
// in the build list may have been changed (possibly to or from "none") as a // in the build list may have been changed (possibly to or from "none") as a
// result. // result.
func EditBuildList(ctx context.Context, add, mustSelect []module.Version) (changed bool, err error) { func EditBuildList(loaderstate *State, ctx context.Context, add, mustSelect []module.Version) (changed bool, err error) {
rs, changed, err := editRequirements(ctx, LoadModFile(ctx), add, mustSelect) rs, changed, err := editRequirements(loaderstate, ctx, LoadModFile(loaderstate, ctx), add, mustSelect)
if err != nil { if err != nil {
return false, err return false, err
} }
LoaderState.requirements = rs loaderstate.requirements = rs
return changed, nil return changed, nil
} }
func overrideRoots(ctx context.Context, rs *Requirements, replace []module.Version) *Requirements { func overrideRoots(loaderstate *State, ctx context.Context, rs *Requirements, replace []module.Version) *Requirements {
drop := make(map[string]bool) drop := make(map[string]bool)
for _, m := range replace { for _, m := range replace {
drop[m.Path] = true drop[m.Path] = true
@ -661,7 +661,7 @@ func overrideRoots(ctx context.Context, rs *Requirements, replace []module.Versi
} }
roots = append(roots, replace...) roots = append(roots, replace...)
gover.ModSort(roots) gover.ModSort(roots)
return newRequirements(rs.pruning, roots, rs.direct) return newRequirements(loaderstate, rs.pruning, roots, rs.direct)
} }
// A ConstraintError describes inconsistent constraints in EditBuildList // A ConstraintError describes inconsistent constraints in EditBuildList
@ -765,28 +765,28 @@ func (c Conflict) String() string {
// tidyRoots trims the root dependencies to the minimal requirements needed to // tidyRoots trims the root dependencies to the minimal requirements needed to
// both retain the same versions of all packages in pkgs and satisfy the // both retain the same versions of all packages in pkgs and satisfy the
// graph-pruning invariants (if applicable). // graph-pruning invariants (if applicable).
func tidyRoots(ctx context.Context, rs *Requirements, pkgs []*loadPkg) (*Requirements, error) { func tidyRoots(loaderstate *State, ctx context.Context, rs *Requirements, pkgs []*loadPkg) (*Requirements, error) {
mainModule := LoaderState.MainModules.mustGetSingleMainModule() mainModule := loaderstate.MainModules.mustGetSingleMainModule(loaderstate)
if rs.pruning == unpruned { if rs.pruning == unpruned {
return tidyUnprunedRoots(ctx, mainModule, rs, pkgs) return tidyUnprunedRoots(loaderstate, ctx, mainModule, rs, pkgs)
} }
return tidyPrunedRoots(ctx, mainModule, rs, pkgs) return tidyPrunedRoots(loaderstate, ctx, mainModule, rs, pkgs)
} }
func updateRoots(ctx context.Context, direct map[string]bool, rs *Requirements, pkgs []*loadPkg, add []module.Version, rootsImported bool) (*Requirements, error) { func updateRoots(loaderstate *State, ctx context.Context, direct map[string]bool, rs *Requirements, pkgs []*loadPkg, add []module.Version, rootsImported bool) (*Requirements, error) {
switch rs.pruning { switch rs.pruning {
case unpruned: case unpruned:
return updateUnprunedRoots(ctx, direct, rs, add) return updateUnprunedRoots(loaderstate, ctx, direct, rs, add)
case pruned: case pruned:
return updatePrunedRoots(ctx, direct, rs, pkgs, add, rootsImported) return updatePrunedRoots(loaderstate, ctx, direct, rs, pkgs, add, rootsImported)
case workspace: case workspace:
return updateWorkspaceRoots(ctx, direct, rs, add) return updateWorkspaceRoots(loaderstate, ctx, direct, rs, add)
default: default:
panic(fmt.Sprintf("unsupported pruning mode: %v", rs.pruning)) panic(fmt.Sprintf("unsupported pruning mode: %v", rs.pruning))
} }
} }
func updateWorkspaceRoots(ctx context.Context, direct map[string]bool, rs *Requirements, add []module.Version) (*Requirements, error) { func updateWorkspaceRoots(loaderstate *State, ctx context.Context, direct map[string]bool, rs *Requirements, add []module.Version) (*Requirements, error) {
if len(add) != 0 { if len(add) != 0 {
// add should be empty in workspace mode because workspace mode implies // add should be empty in workspace mode because workspace mode implies
// -mod=readonly, which in turn implies no new requirements. The code path // -mod=readonly, which in turn implies no new requirements. The code path
@ -797,7 +797,7 @@ func updateWorkspaceRoots(ctx context.Context, direct map[string]bool, rs *Requi
// return an error. // return an error.
panic("add is not empty") panic("add is not empty")
} }
return newRequirements(workspace, rs.rootModules, direct), nil return newRequirements(loaderstate, workspace, rs.rootModules, direct), nil
} }
// tidyPrunedRoots returns a minimal set of root requirements that maintains the // tidyPrunedRoots returns a minimal set of root requirements that maintains the
@ -816,16 +816,16 @@ func updateWorkspaceRoots(ctx context.Context, direct map[string]bool, rs *Requi
// To ensure that the loading process eventually converges, the caller should // To ensure that the loading process eventually converges, the caller should
// add any needed roots from the tidy root set (without removing existing untidy // add any needed roots from the tidy root set (without removing existing untidy
// roots) until the set of roots has converged. // roots) until the set of roots has converged.
func tidyPrunedRoots(ctx context.Context, mainModule module.Version, old *Requirements, pkgs []*loadPkg) (*Requirements, error) { func tidyPrunedRoots(loaderstate *State, ctx context.Context, mainModule module.Version, old *Requirements, pkgs []*loadPkg) (*Requirements, error) {
var ( var (
roots []module.Version roots []module.Version
pathIsRoot = map[string]bool{mainModule.Path: true} pathIsRoot = map[string]bool{mainModule.Path: true}
) )
if v, ok := old.rootSelected("go"); ok { if v, ok := old.rootSelected(loaderstate, "go"); ok {
roots = append(roots, module.Version{Path: "go", Version: v}) roots = append(roots, module.Version{Path: "go", Version: v})
pathIsRoot["go"] = true pathIsRoot["go"] = true
} }
if v, ok := old.rootSelected("toolchain"); ok { if v, ok := old.rootSelected(loaderstate, "toolchain"); ok {
roots = append(roots, module.Version{Path: "toolchain", Version: v}) roots = append(roots, module.Version{Path: "toolchain", Version: v})
pathIsRoot["toolchain"] = true pathIsRoot["toolchain"] = true
} }
@ -847,7 +847,7 @@ func tidyPrunedRoots(ctx context.Context, mainModule module.Version, old *Requir
if !pkg.flags.has(pkgInAll) { if !pkg.flags.has(pkgInAll) {
continue continue
} }
if pkg.fromExternalModule() && !pathIsRoot[pkg.mod.Path] { if pkg.fromExternalModule(loaderstate) && !pathIsRoot[pkg.mod.Path] {
roots = append(roots, pkg.mod) roots = append(roots, pkg.mod)
pathIsRoot[pkg.mod.Path] = true pathIsRoot[pkg.mod.Path] = true
} }
@ -855,11 +855,11 @@ func tidyPrunedRoots(ctx context.Context, mainModule module.Version, old *Requir
queued[pkg] = true queued[pkg] = true
} }
gover.ModSort(roots) gover.ModSort(roots)
tidy := newRequirements(pruned, roots, old.direct) tidy := newRequirements(loaderstate, pruned, roots, old.direct)
for len(queue) > 0 { for len(queue) > 0 {
roots = tidy.rootModules roots = tidy.rootModules
mg, err := tidy.Graph(ctx) mg, err := tidy.Graph(loaderstate, ctx)
if err != nil { if err != nil {
return nil, err return nil, err
} }
@ -892,12 +892,12 @@ func tidyPrunedRoots(ctx context.Context, mainModule module.Version, old *Requir
if len(roots) > len(tidy.rootModules) { if len(roots) > len(tidy.rootModules) {
gover.ModSort(roots) gover.ModSort(roots)
tidy = newRequirements(pruned, roots, tidy.direct) tidy = newRequirements(loaderstate, pruned, roots, tidy.direct)
} }
} }
roots = tidy.rootModules roots = tidy.rootModules
_, err := tidy.Graph(ctx) _, err := tidy.Graph(loaderstate, ctx)
if err != nil { if err != nil {
return nil, err return nil, err
} }
@ -921,7 +921,7 @@ func tidyPrunedRoots(ctx context.Context, mainModule module.Version, old *Requir
pkg := pkg pkg := pkg
q.Add(func() { q.Add(func() {
skipModFile := true skipModFile := true
_, _, _, _, err := importFromModules(ctx, pkg.path, tidy, nil, skipModFile) _, _, _, _, err := importFromModules(loaderstate, ctx, pkg.path, tidy, nil, skipModFile)
if _, ok := errors.AsType[*AmbiguousImportError](err); ok { if _, ok := errors.AsType[*AmbiguousImportError](err); ok {
disambiguateRoot.Store(pkg.mod, true) disambiguateRoot.Store(pkg.mod, true)
} }
@ -938,8 +938,8 @@ func tidyPrunedRoots(ctx context.Context, mainModule module.Version, old *Requir
if len(roots) > len(tidy.rootModules) { if len(roots) > len(tidy.rootModules) {
module.Sort(roots) module.Sort(roots)
tidy = newRequirements(pruned, roots, tidy.direct) tidy = newRequirements(loaderstate, pruned, roots, tidy.direct)
_, err = tidy.Graph(ctx) _, err = tidy.Graph(loaderstate, ctx)
if err != nil { if err != nil {
return nil, err return nil, err
} }
@ -999,7 +999,7 @@ func tidyPrunedRoots(ctx context.Context, mainModule module.Version, old *Requir
// //
// (See https://golang.org/design/36460-lazy-module-loading#invariants for more // (See https://golang.org/design/36460-lazy-module-loading#invariants for more
// detail.) // detail.)
func updatePrunedRoots(ctx context.Context, direct map[string]bool, rs *Requirements, pkgs []*loadPkg, add []module.Version, rootsImported bool) (*Requirements, error) { func updatePrunedRoots(loaderstate *State, ctx context.Context, direct map[string]bool, rs *Requirements, pkgs []*loadPkg, add []module.Version, rootsImported bool) (*Requirements, error) {
roots := rs.rootModules roots := rs.rootModules
rootsUpgraded := false rootsUpgraded := false
@ -1009,7 +1009,7 @@ func updatePrunedRoots(ctx context.Context, direct map[string]bool, rs *Requirem
// either pkgInAll or pkgIsRoot is included as a root.” // either pkgInAll or pkgIsRoot is included as a root.”
needSort := false needSort := false
for _, pkg := range pkgs { for _, pkg := range pkgs {
if !pkg.fromExternalModule() { if !pkg.fromExternalModule(loaderstate) {
// pkg was not loaded from a module dependency, so we don't need // pkg was not loaded from a module dependency, so we don't need
// to do anything special to maintain that dependency. // to do anything special to maintain that dependency.
continue continue
@ -1058,7 +1058,7 @@ func updatePrunedRoots(ctx context.Context, direct map[string]bool, rs *Requirem
continue continue
} }
if _, ok := rs.rootSelected(pkg.mod.Path); ok { if _, ok := rs.rootSelected(loaderstate, pkg.mod.Path); ok {
// It is possible that the main module's go.mod file is incomplete or // It is possible that the main module's go.mod file is incomplete or
// otherwise erroneous — for example, perhaps the author forgot to 'git // otherwise erroneous — for example, perhaps the author forgot to 'git
// add' their updated go.mod file after adding a new package import, or // add' their updated go.mod file after adding a new package import, or
@ -1094,7 +1094,7 @@ func updatePrunedRoots(ctx context.Context, direct map[string]bool, rs *Requirem
} }
for _, m := range add { for _, m := range add {
if v, ok := rs.rootSelected(m.Path); !ok || gover.ModCompare(m.Path, v, m.Version) < 0 { if v, ok := rs.rootSelected(loaderstate, m.Path); !ok || gover.ModCompare(m.Path, v, m.Version) < 0 {
roots = append(roots, m) roots = append(roots, m)
rootsUpgraded = true rootsUpgraded = true
needSort = true needSort = true
@ -1111,7 +1111,7 @@ func updatePrunedRoots(ctx context.Context, direct map[string]bool, rs *Requirem
// We've added or upgraded one or more roots, so load the full module // We've added or upgraded one or more roots, so load the full module
// graph so that we can update those roots to be consistent with other // graph so that we can update those roots to be consistent with other
// requirements. // requirements.
if mustHaveCompleteRequirements() { if mustHaveCompleteRequirements(loaderstate) {
// Our changes to the roots may have moved dependencies into or out of // Our changes to the roots may have moved dependencies into or out of
// the graph-pruning horizon, which could in turn change the selected // the graph-pruning horizon, which could in turn change the selected
// versions of other modules. (For pruned modules adding or removing an // versions of other modules. (For pruned modules adding or removing an
@ -1119,9 +1119,9 @@ func updatePrunedRoots(ctx context.Context, direct map[string]bool, rs *Requirem
return rs, errGoModDirty return rs, errGoModDirty
} }
rs = newRequirements(pruned, roots, direct) rs = newRequirements(loaderstate, pruned, roots, direct)
var err error var err error
mg, err = rs.Graph(ctx) mg, err = rs.Graph(loaderstate, ctx)
if err != nil { if err != nil {
return rs, err return rs, err
} }
@ -1135,20 +1135,20 @@ func updatePrunedRoots(ctx context.Context, direct map[string]bool, rs *Requirem
// We've already loaded the full module graph, which includes the // We've already loaded the full module graph, which includes the
// requirements of all of the root modules — even the transitive // requirements of all of the root modules — even the transitive
// requirements, if they are unpruned! // requirements, if they are unpruned!
mg, _ = rs.Graph(ctx) mg, _ = rs.Graph(loaderstate, ctx)
} else if cfg.BuildMod == "vendor" { } else if cfg.BuildMod == "vendor" {
// We can't spot-check the requirements of other modules because we // We can't spot-check the requirements of other modules because we
// don't in general have their go.mod files available in the vendor // don't in general have their go.mod files available in the vendor
// directory. (Fortunately this case is impossible, because mg.graph is // directory. (Fortunately this case is impossible, because mg.graph is
// always non-nil in vendor mode!) // always non-nil in vendor mode!)
panic("internal error: rs.graph is unexpectedly nil with -mod=vendor") panic("internal error: rs.graph is unexpectedly nil with -mod=vendor")
} else if !spotCheckRoots(ctx, rs, spotCheckRoot) { } else if !spotCheckRoots(loaderstate, ctx, rs, spotCheckRoot) {
// We spot-checked the explicit requirements of the roots that are // We spot-checked the explicit requirements of the roots that are
// relevant to the packages we've loaded. Unfortunately, they're // relevant to the packages we've loaded. Unfortunately, they're
// inconsistent in some way; we need to load the full module graph // inconsistent in some way; we need to load the full module graph
// so that we can fix the roots properly. // so that we can fix the roots properly.
var err error var err error
mg, err = rs.Graph(ctx) mg, err = rs.Graph(loaderstate, ctx)
if err != nil { if err != nil {
return rs, err return rs, err
} }
@ -1158,7 +1158,7 @@ func updatePrunedRoots(ctx context.Context, direct map[string]bool, rs *Requirem
roots = make([]module.Version, 0, len(rs.rootModules)) roots = make([]module.Version, 0, len(rs.rootModules))
rootsUpgraded = false rootsUpgraded = false
inRootPaths := make(map[string]bool, len(rs.rootModules)+1) inRootPaths := make(map[string]bool, len(rs.rootModules)+1)
for _, mm := range LoaderState.MainModules.Versions() { for _, mm := range loaderstate.MainModules.Versions() {
inRootPaths[mm.Path] = true inRootPaths[mm.Path] = true
} }
for _, m := range rs.rootModules { for _, m := range rs.rootModules {
@ -1184,7 +1184,7 @@ func updatePrunedRoots(ctx context.Context, direct map[string]bool, rs *Requirem
var v string var v string
if mg == nil { if mg == nil {
v, _ = rs.rootSelected(m.Path) v, _ = rs.rootSelected(loaderstate, m.Path)
} else { } else {
v = mg.Selected(m.Path) v = mg.Selected(m.Path)
} }
@ -1218,12 +1218,12 @@ func updatePrunedRoots(ctx context.Context, direct map[string]bool, rs *Requirem
// preserve its cached ModuleGraph (if any). // preserve its cached ModuleGraph (if any).
return rs, nil return rs, nil
} }
return newRequirements(pruned, roots, direct), nil return newRequirements(loaderstate, pruned, roots, direct), nil
} }
// spotCheckRoots reports whether the versions of the roots in rs satisfy the // spotCheckRoots reports whether the versions of the roots in rs satisfy the
// explicit requirements of the modules in mods. // explicit requirements of the modules in mods.
func spotCheckRoots(ctx context.Context, rs *Requirements, mods map[module.Version]bool) bool { func spotCheckRoots(loaderstate *State, ctx context.Context, rs *Requirements, mods map[module.Version]bool) bool {
ctx, cancel := context.WithCancel(ctx) ctx, cancel := context.WithCancel(ctx)
defer cancel() defer cancel()
@ -1235,14 +1235,14 @@ func spotCheckRoots(ctx context.Context, rs *Requirements, mods map[module.Versi
return return
} }
summary, err := goModSummary(m) summary, err := goModSummary(loaderstate, m)
if err != nil { if err != nil {
cancel() cancel()
return return
} }
for _, r := range summary.require { for _, r := range summary.require {
if v, ok := rs.rootSelected(r.Path); ok && gover.ModCompare(r.Path, v, r.Version) < 0 { if v, ok := rs.rootSelected(loaderstate, r.Path); ok && gover.ModCompare(r.Path, v, r.Version) < 0 {
cancel() cancel()
return return
} }
@ -1264,7 +1264,7 @@ func spotCheckRoots(ctx context.Context, rs *Requirements, mods map[module.Versi
// the selected version of every module that provided or lexically could have // the selected version of every module that provided or lexically could have
// provided a package in pkgs, and includes the selected version of every such // provided a package in pkgs, and includes the selected version of every such
// module in direct as a root. // module in direct as a root.
func tidyUnprunedRoots(ctx context.Context, mainModule module.Version, old *Requirements, pkgs []*loadPkg) (*Requirements, error) { func tidyUnprunedRoots(loaderstate *State, ctx context.Context, mainModule module.Version, old *Requirements, pkgs []*loadPkg) (*Requirements, error) {
var ( var (
// keep is a set of modules that provide packages or are needed to // keep is a set of modules that provide packages or are needed to
// disambiguate imports. // disambiguate imports.
@ -1292,16 +1292,16 @@ func tidyUnprunedRoots(ctx context.Context, mainModule module.Version, old *Requ
// without its sum. See #47738. // without its sum. See #47738.
altMods = map[string]string{} altMods = map[string]string{}
) )
if v, ok := old.rootSelected("go"); ok { if v, ok := old.rootSelected(loaderstate, "go"); ok {
keep = append(keep, module.Version{Path: "go", Version: v}) keep = append(keep, module.Version{Path: "go", Version: v})
keptPath["go"] = true keptPath["go"] = true
} }
if v, ok := old.rootSelected("toolchain"); ok { if v, ok := old.rootSelected(loaderstate, "toolchain"); ok {
keep = append(keep, module.Version{Path: "toolchain", Version: v}) keep = append(keep, module.Version{Path: "toolchain", Version: v})
keptPath["toolchain"] = true keptPath["toolchain"] = true
} }
for _, pkg := range pkgs { for _, pkg := range pkgs {
if !pkg.fromExternalModule() { if !pkg.fromExternalModule(loaderstate) {
continue continue
} }
if m := pkg.mod; !keptPath[m.Path] { if m := pkg.mod; !keptPath[m.Path] {
@ -1350,7 +1350,7 @@ func tidyUnprunedRoots(ctx context.Context, mainModule module.Version, old *Requ
} }
} }
return newRequirements(unpruned, min, old.direct), nil return newRequirements(loaderstate, unpruned, min, old.direct), nil
} }
// updateUnprunedRoots returns a set of root requirements that includes the selected // updateUnprunedRoots returns a set of root requirements that includes the selected
@ -1367,8 +1367,8 @@ func tidyUnprunedRoots(ctx context.Context, mainModule module.Version, old *Requ
// by a dependency in add. // by a dependency in add.
// 4. Every version in add is selected at its given version unless upgraded by // 4. Every version in add is selected at its given version unless upgraded by
// (the dependencies of) an existing root or another module in add. // (the dependencies of) an existing root or another module in add.
func updateUnprunedRoots(ctx context.Context, direct map[string]bool, rs *Requirements, add []module.Version) (*Requirements, error) { func updateUnprunedRoots(loaderstate *State, ctx context.Context, direct map[string]bool, rs *Requirements, add []module.Version) (*Requirements, error) {
mg, err := rs.Graph(ctx) mg, err := rs.Graph(loaderstate, ctx)
if err != nil { if err != nil {
// We can't ignore errors in the module graph even if the user passed the -e // We can't ignore errors in the module graph even if the user passed the -e
// flag to try to push past them. If we can't load the complete module // flag to try to push past them. If we can't load the complete module
@ -1376,7 +1376,7 @@ func updateUnprunedRoots(ctx context.Context, direct map[string]bool, rs *Requir
return rs, err return rs, err
} }
if mustHaveCompleteRequirements() { if mustHaveCompleteRequirements(loaderstate) {
// Instead of actually updating the requirements, just check that no updates // Instead of actually updating the requirements, just check that no updates
// are needed. // are needed.
if rs == nil { if rs == nil {
@ -1396,7 +1396,7 @@ func updateUnprunedRoots(ctx context.Context, direct map[string]bool, rs *Requir
} }
} }
for mPath := range direct { for mPath := range direct {
if _, ok := rs.rootSelected(mPath); !ok { if _, ok := rs.rootSelected(loaderstate, mPath); !ok {
// Module m is supposed to be listed explicitly, but isn't. // Module m is supposed to be listed explicitly, but isn't.
// //
// Note that this condition is also detected (and logged with more // Note that this condition is also detected (and logged with more
@ -1435,7 +1435,7 @@ func updateUnprunedRoots(ctx context.Context, direct map[string]bool, rs *Requir
// This is only for convenience and clarity for end users: in an unpruned module, // This is only for convenience and clarity for end users: in an unpruned module,
// the choice of explicit vs. implicit dependency has no impact on MVS // the choice of explicit vs. implicit dependency has no impact on MVS
// selection (for itself or any other module). // selection (for itself or any other module).
keep := append(mg.BuildList()[LoaderState.MainModules.Len():], add...) keep := append(mg.BuildList()[loaderstate.MainModules.Len():], add...)
for _, m := range keep { for _, m := range keep {
if direct[m.Path] && !inRootPaths[m.Path] { if direct[m.Path] && !inRootPaths[m.Path] {
rootPaths = append(rootPaths, m.Path) rootPaths = append(rootPaths, m.Path)
@ -1444,14 +1444,14 @@ func updateUnprunedRoots(ctx context.Context, direct map[string]bool, rs *Requir
} }
var roots []module.Version var roots []module.Version
for _, mainModule := range LoaderState.MainModules.Versions() { for _, mainModule := range loaderstate.MainModules.Versions() {
min, err := mvs.Req(mainModule, rootPaths, &mvsReqs{roots: keep}) min, err := mvs.Req(mainModule, rootPaths, &mvsReqs{roots: keep})
if err != nil { if err != nil {
return rs, err return rs, err
} }
roots = append(roots, min...) roots = append(roots, min...)
} }
if LoaderState.MainModules.Len() > 1 { if loaderstate.MainModules.Len() > 1 {
gover.ModSort(roots) gover.ModSort(roots)
} }
if rs.pruning == unpruned && slices.Equal(roots, rs.rootModules) && maps.Equal(direct, rs.direct) { if rs.pruning == unpruned && slices.Equal(roots, rs.rootModules) && maps.Equal(direct, rs.direct) {
@ -1460,12 +1460,12 @@ func updateUnprunedRoots(ctx context.Context, direct map[string]bool, rs *Requir
return rs, nil return rs, nil
} }
return newRequirements(unpruned, roots, direct), nil return newRequirements(loaderstate, unpruned, roots, direct), nil
} }
// convertPruning returns a version of rs with the given pruning behavior. // convertPruning returns a version of rs with the given pruning behavior.
// If rs already has the given pruning, convertPruning returns rs unmodified. // If rs already has the given pruning, convertPruning returns rs unmodified.
func convertPruning(ctx context.Context, rs *Requirements, pruning modPruning) (*Requirements, error) { func convertPruning(loaderstate *State, ctx context.Context, rs *Requirements, pruning modPruning) (*Requirements, error) {
if rs.pruning == pruning { if rs.pruning == pruning {
return rs, nil return rs, nil
} else if rs.pruning == workspace || pruning == workspace { } else if rs.pruning == workspace || pruning == workspace {
@ -1477,7 +1477,7 @@ func convertPruning(ctx context.Context, rs *Requirements, pruning modPruning) (
// pruned module graph are a superset of the roots of an unpruned one, so // pruned module graph are a superset of the roots of an unpruned one, so
// we don't need to add any new roots — we just need to drop the ones that // we don't need to add any new roots — we just need to drop the ones that
// are redundant, which is exactly what updateUnprunedRoots does. // are redundant, which is exactly what updateUnprunedRoots does.
return updateUnprunedRoots(ctx, rs.direct, rs, nil) return updateUnprunedRoots(loaderstate, ctx, rs.direct, rs, nil)
} }
// We are converting an unpruned module to a pruned one. // We are converting an unpruned module to a pruned one.
@ -1487,9 +1487,9 @@ func convertPruning(ctx context.Context, rs *Requirements, pruning modPruning) (
// root set! “Include the transitive dependencies of every module in the build // root set! “Include the transitive dependencies of every module in the build
// list” is exactly what happens in a pruned module if we promote every module // list” is exactly what happens in a pruned module if we promote every module
// in the build list to a root. // in the build list to a root.
mg, err := rs.Graph(ctx) mg, err := rs.Graph(loaderstate, ctx)
if err != nil { if err != nil {
return rs, err return rs, err
} }
return newRequirements(pruned, mg.BuildList()[LoaderState.MainModules.Len():], rs.direct), nil return newRequirements(loaderstate, pruned, mg.BuildList()[loaderstate.MainModules.Len():], rs.direct), nil
} }

View file

@ -42,7 +42,7 @@ import (
// If pruning is enabled, the roots of the edited requirements include an // If pruning is enabled, the roots of the edited requirements include an
// explicit entry for each module path in tryUpgrade, mustSelect, and the roots // explicit entry for each module path in tryUpgrade, mustSelect, and the roots
// of rs, unless the selected version for the module path is "none". // of rs, unless the selected version for the module path is "none".
func editRequirements(ctx context.Context, rs *Requirements, tryUpgrade, mustSelect []module.Version) (edited *Requirements, changed bool, err error) { func editRequirements(loaderstate *State, ctx context.Context, rs *Requirements, tryUpgrade, mustSelect []module.Version) (edited *Requirements, changed bool, err error) {
if rs.pruning == workspace { if rs.pruning == workspace {
panic("editRequirements cannot edit workspace requirements") panic("editRequirements cannot edit workspace requirements")
} }
@ -82,7 +82,7 @@ func editRequirements(ctx context.Context, rs *Requirements, tryUpgrade, mustSel
} }
if rootPruning != rs.pruning { if rootPruning != rs.pruning {
rs, err = convertPruning(ctx, rs, rootPruning) rs, err = convertPruning(loaderstate, ctx, rs, rootPruning)
if err != nil { if err != nil {
return orig, false, err return orig, false, err
} }
@ -100,13 +100,13 @@ func editRequirements(ctx context.Context, rs *Requirements, tryUpgrade, mustSel
// dependencies, so we need to treat everything in the build list as // dependencies, so we need to treat everything in the build list as
// potentially relevant — that is, as what would be a “root” in a module // potentially relevant — that is, as what would be a “root” in a module
// with graph pruning enabled. // with graph pruning enabled.
mg, err := rs.Graph(ctx) mg, err := rs.Graph(loaderstate, ctx)
if err != nil { if err != nil {
// If we couldn't load the graph, we don't know what its requirements were // If we couldn't load the graph, we don't know what its requirements were
// to begin with, so we can't edit those requirements in a coherent way. // to begin with, so we can't edit those requirements in a coherent way.
return orig, false, err return orig, false, err
} }
bl := mg.BuildList()[LoaderState.MainModules.Len():] bl := mg.BuildList()[loaderstate.MainModules.Len():]
selectedRoot = make(map[string]string, len(bl)) selectedRoot = make(map[string]string, len(bl))
for _, m := range bl { for _, m := range bl {
selectedRoot[m.Path] = m.Version selectedRoot[m.Path] = m.Version
@ -224,7 +224,7 @@ func editRequirements(ctx context.Context, rs *Requirements, tryUpgrade, mustSel
// of every root. The upgraded roots are in addition to the original // of every root. The upgraded roots are in addition to the original
// roots, so we will have enough information to trace a path to each // roots, so we will have enough information to trace a path to each
// conflict we discover from one or more of the original roots. // conflict we discover from one or more of the original roots.
mg, upgradedRoots, err := extendGraph(ctx, rootPruning, roots, selectedRoot) mg, upgradedRoots, err := extendGraph(loaderstate, ctx, rootPruning, roots, selectedRoot)
if err != nil { if err != nil {
if mg == nil { if mg == nil {
return orig, false, err return orig, false, err
@ -391,7 +391,7 @@ func editRequirements(ctx context.Context, rs *Requirements, tryUpgrade, mustSel
// the edit. We want to make sure we consider keeping it as-is, // the edit. We want to make sure we consider keeping it as-is,
// even if it wouldn't normally be included. (For example, it might // even if it wouldn't normally be included. (For example, it might
// be a pseudo-version or pre-release.) // be a pseudo-version or pre-release.)
origMG, _ := orig.Graph(ctx) origMG, _ := orig.Graph(loaderstate, ctx)
origV := origMG.Selected(m.Path) origV := origMG.Selected(m.Path)
if conflict.Err != nil && origV == m.Version { if conflict.Err != nil && origV == m.Version {
@ -415,7 +415,7 @@ func editRequirements(ctx context.Context, rs *Requirements, tryUpgrade, mustSel
rejectedRoot[m] = true rejectedRoot[m] = true
prev := m prev := m
for { for {
prev, err = previousVersion(ctx, prev) prev, err = previousVersion(loaderstate, ctx, prev)
if gover.ModCompare(m.Path, m.Version, origV) > 0 && (gover.ModCompare(m.Path, prev.Version, origV) < 0 || err != nil) { if gover.ModCompare(m.Path, m.Version, origV) > 0 && (gover.ModCompare(m.Path, prev.Version, origV) < 0 || err != nil) {
// previousVersion skipped over origV. Insert it into the order. // previousVersion skipped over origV. Insert it into the order.
prev.Version = origV prev.Version = origV
@ -515,13 +515,13 @@ func editRequirements(ctx context.Context, rs *Requirements, tryUpgrade, mustSel
// The modules in mustSelect are always promoted to be explicit. // The modules in mustSelect are always promoted to be explicit.
for _, m := range mustSelect { for _, m := range mustSelect {
if m.Version != "none" && !LoaderState.MainModules.Contains(m.Path) { if m.Version != "none" && !loaderstate.MainModules.Contains(m.Path) {
rootPaths = append(rootPaths, m.Path) rootPaths = append(rootPaths, m.Path)
} }
} }
for _, m := range roots { for _, m := range roots {
if v, ok := rs.rootSelected(m.Path); ok && (v == m.Version || rs.direct[m.Path]) { if v, ok := rs.rootSelected(loaderstate, m.Path); ok && (v == m.Version || rs.direct[m.Path]) {
// m.Path was formerly a root, and either its version hasn't changed or // m.Path was formerly a root, and either its version hasn't changed or
// we believe that it provides a package directly imported by a package // we believe that it provides a package directly imported by a package
// or test in the main module. For now we'll assume that it is still // or test in the main module. For now we'll assume that it is still
@ -532,7 +532,7 @@ func editRequirements(ctx context.Context, rs *Requirements, tryUpgrade, mustSel
} }
} }
roots, err = mvs.Req(LoaderState.MainModules.mustGetSingleMainModule(), rootPaths, &mvsReqs{roots: roots}) roots, err = mvs.Req(loaderstate.MainModules.mustGetSingleMainModule(loaderstate), rootPaths, &mvsReqs{roots: roots})
if err != nil { if err != nil {
return nil, false, err return nil, false, err
} }
@ -563,7 +563,7 @@ func editRequirements(ctx context.Context, rs *Requirements, tryUpgrade, mustSel
direct[m.Path] = true direct[m.Path] = true
} }
} }
edited = newRequirements(rootPruning, roots, direct) edited = newRequirements(loaderstate, rootPruning, roots, direct)
// If we ended up adding a dependency that upgrades our go version far enough // If we ended up adding a dependency that upgrades our go version far enough
// to activate pruning, we must convert the edited Requirements in order to // to activate pruning, we must convert the edited Requirements in order to
@ -578,7 +578,7 @@ func editRequirements(ctx context.Context, rs *Requirements, tryUpgrade, mustSel
// those two modules will never be downgraded due to a conflict with any other // those two modules will never be downgraded due to a conflict with any other
// constraint. // constraint.
if rootPruning == unpruned { if rootPruning == unpruned {
if v, ok := edited.rootSelected("go"); ok && pruningForGoVersion(v) == pruned { if v, ok := edited.rootSelected(loaderstate, "go"); ok && pruningForGoVersion(v) == pruned {
// Since we computed the edit with the unpruned graph, and the pruned // Since we computed the edit with the unpruned graph, and the pruned
// graph is a strict subset of the unpruned graph, this conversion // graph is a strict subset of the unpruned graph, this conversion
// preserves the exact (edited) build list that we already computed. // preserves the exact (edited) build list that we already computed.
@ -587,7 +587,7 @@ func editRequirements(ctx context.Context, rs *Requirements, tryUpgrade, mustSel
// the graph. 'go get' will check for that sort of transition and log a // the graph. 'go get' will check for that sort of transition and log a
// message reminding the user how to clean up this mess we're about to // message reminding the user how to clean up this mess we're about to
// make. 😅 // make. 😅
edited, err = convertPruning(ctx, edited, pruned) edited, err = convertPruning(loaderstate, ctx, edited, pruned)
if err != nil { if err != nil {
return orig, false, err return orig, false, err
} }
@ -607,9 +607,9 @@ func editRequirements(ctx context.Context, rs *Requirements, tryUpgrade, mustSel
// The extended graph is useful for diagnosing version conflicts: for each // The extended graph is useful for diagnosing version conflicts: for each
// selected module version, it can provide a complete path of requirements from // selected module version, it can provide a complete path of requirements from
// some root to that version. // some root to that version.
func extendGraph(ctx context.Context, rootPruning modPruning, roots []module.Version, selectedRoot map[string]string) (mg *ModuleGraph, upgradedRoot map[module.Version]bool, err error) { func extendGraph(loaderstate *State, ctx context.Context, rootPruning modPruning, roots []module.Version, selectedRoot map[string]string) (mg *ModuleGraph, upgradedRoot map[module.Version]bool, err error) {
for { for {
mg, err = readModGraph(ctx, rootPruning, roots, upgradedRoot) mg, err = readModGraph(loaderstate, ctx, rootPruning, roots, upgradedRoot)
// We keep on going even if err is non-nil until we reach a steady state. // We keep on going even if err is non-nil until we reach a steady state.
// (Note that readModGraph returns a non-nil *ModuleGraph even in case of // (Note that readModGraph returns a non-nil *ModuleGraph even in case of
// errors.) The caller may be able to fix the errors by adjusting versions, // errors.) The caller may be able to fix the errors by adjusting versions,

View file

@ -262,7 +262,7 @@ func (e *invalidImportError) Unwrap() error {
// (https://go.dev/issue/56222) for modules with 'go' versions between 1.17 and // (https://go.dev/issue/56222) for modules with 'go' versions between 1.17 and
// 1.20, preventing unnecessary go.sum churn and network access in those // 1.20, preventing unnecessary go.sum churn and network access in those
// modules. // modules.
func importFromModules(ctx context.Context, path string, rs *Requirements, mg *ModuleGraph, skipModFile bool) (m module.Version, modroot, dir string, altMods []module.Version, err error) { func importFromModules(loaderstate *State, ctx context.Context, path string, rs *Requirements, mg *ModuleGraph, skipModFile bool) (m module.Version, modroot, dir string, altMods []module.Version, err error) {
invalidf := func(format string, args ...interface{}) (module.Version, string, string, []module.Version, error) { invalidf := func(format string, args ...interface{}) (module.Version, string, string, []module.Version, error) {
return module.Version{}, "", "", nil, &invalidImportError{ return module.Version{}, "", "", nil, &invalidImportError{
importPath: path, importPath: path,
@ -299,12 +299,12 @@ func importFromModules(ctx context.Context, path string, rs *Requirements, mg *M
// Is the package in the standard library? // Is the package in the standard library?
pathIsStd := search.IsStandardImportPath(path) pathIsStd := search.IsStandardImportPath(path)
if pathIsStd && modindex.IsStandardPackage(cfg.GOROOT, cfg.BuildContext.Compiler, path) { if pathIsStd && modindex.IsStandardPackage(cfg.GOROOT, cfg.BuildContext.Compiler, path) {
for _, mainModule := range LoaderState.MainModules.Versions() { for _, mainModule := range loaderstate.MainModules.Versions() {
if LoaderState.MainModules.InGorootSrc(mainModule) { if loaderstate.MainModules.InGorootSrc(mainModule) {
if dir, ok, err := dirInModule(path, LoaderState.MainModules.PathPrefix(mainModule), LoaderState.MainModules.ModRoot(mainModule), true); err != nil { if dir, ok, err := dirInModule(path, loaderstate.MainModules.PathPrefix(mainModule), loaderstate.MainModules.ModRoot(mainModule), true); err != nil {
return module.Version{}, LoaderState.MainModules.ModRoot(mainModule), dir, nil, err return module.Version{}, loaderstate.MainModules.ModRoot(mainModule), dir, nil, err
} else if ok { } else if ok {
return mainModule, LoaderState.MainModules.ModRoot(mainModule), dir, nil, nil return mainModule, loaderstate.MainModules.ModRoot(mainModule), dir, nil, nil
} }
} }
} }
@ -321,10 +321,10 @@ func importFromModules(ctx context.Context, path string, rs *Requirements, mg *M
// Everything must be in the main modules or the main module's or workspace's vendor directory. // Everything must be in the main modules or the main module's or workspace's vendor directory.
if cfg.BuildMod == "vendor" { if cfg.BuildMod == "vendor" {
var mainErr error var mainErr error
for _, mainModule := range LoaderState.MainModules.Versions() { for _, mainModule := range loaderstate.MainModules.Versions() {
modRoot := LoaderState.MainModules.ModRoot(mainModule) modRoot := loaderstate.MainModules.ModRoot(mainModule)
if modRoot != "" { if modRoot != "" {
dir, mainOK, err := dirInModule(path, LoaderState.MainModules.PathPrefix(mainModule), modRoot, true) dir, mainOK, err := dirInModule(path, loaderstate.MainModules.PathPrefix(mainModule), modRoot, true)
if mainErr == nil { if mainErr == nil {
mainErr = err mainErr = err
} }
@ -336,8 +336,8 @@ func importFromModules(ctx context.Context, path string, rs *Requirements, mg *M
} }
} }
if HasModRoot() { if HasModRoot(loaderstate) {
vendorDir := VendorDir() vendorDir := VendorDir(loaderstate)
dir, inVendorDir, _ := dirInModule(path, "", vendorDir, false) dir, inVendorDir, _ := dirInModule(path, "", vendorDir, false)
if inVendorDir { if inVendorDir {
readVendorList(vendorDir) readVendorList(vendorDir)
@ -345,13 +345,13 @@ func importFromModules(ctx context.Context, path string, rs *Requirements, mg *M
// vendor/modules.txt does not exist or the user manually added directories to the vendor directory. // vendor/modules.txt does not exist or the user manually added directories to the vendor directory.
// Go 1.23 and later require vendored packages to be present in modules.txt to be imported. // Go 1.23 and later require vendored packages to be present in modules.txt to be imported.
_, ok := vendorPkgModule[path] _, ok := vendorPkgModule[path]
if ok || (gover.Compare(LoaderState.MainModules.GoVersion(), gover.ExplicitModulesTxtImportVersion) < 0) { if ok || (gover.Compare(loaderstate.MainModules.GoVersion(loaderstate), gover.ExplicitModulesTxtImportVersion) < 0) {
mods = append(mods, vendorPkgModule[path]) mods = append(mods, vendorPkgModule[path])
dirs = append(dirs, dir) dirs = append(dirs, dir)
roots = append(roots, vendorDir) roots = append(roots, vendorDir)
} else { } else {
subCommand := "mod" subCommand := "mod"
if inWorkspaceMode() { if inWorkspaceMode(loaderstate) {
subCommand = "work" subCommand = "work"
} }
fmt.Fprintf(os.Stderr, "go: ignoring package %s which exists in the vendor directory but is missing from vendor/modules.txt. To sync the vendor directory run go %s vendor.\n", path, subCommand) fmt.Fprintf(os.Stderr, "go: ignoring package %s which exists in the vendor directory but is missing from vendor/modules.txt. To sync the vendor directory run go %s vendor.\n", path, subCommand)
@ -399,7 +399,7 @@ func importFromModules(ctx context.Context, path string, rs *Requirements, mg *M
ok bool ok bool
) )
if mg == nil { if mg == nil {
v, ok = rs.rootSelected(prefix) v, ok = rs.rootSelected(loaderstate, prefix)
} else { } else {
v, ok = mg.Selected(prefix), true v, ok = mg.Selected(prefix), true
} }
@ -408,7 +408,7 @@ func importFromModules(ctx context.Context, path string, rs *Requirements, mg *M
} }
m := module.Version{Path: prefix, Version: v} m := module.Version{Path: prefix, Version: v}
root, isLocal, err := fetch(ctx, m) root, isLocal, err := fetch(loaderstate, ctx, m)
if err != nil { if err != nil {
if _, ok := errors.AsType[*sumMissingError](err); ok { if _, ok := errors.AsType[*sumMissingError](err); ok {
// We are missing a sum needed to fetch a module in the build list. // We are missing a sum needed to fetch a module in the build list.
@ -471,8 +471,8 @@ func importFromModules(ctx context.Context, path string, rs *Requirements, mg *M
// If the module graph is pruned and this is a test-only dependency // If the module graph is pruned and this is a test-only dependency
// of a package in "all", we didn't necessarily load that file // of a package in "all", we didn't necessarily load that file
// when we read the module graph, so do it now to be sure. // when we read the module graph, so do it now to be sure.
if !skipModFile && cfg.BuildMod != "vendor" && mods[0].Path != "" && !LoaderState.MainModules.Contains(mods[0].Path) { if !skipModFile && cfg.BuildMod != "vendor" && mods[0].Path != "" && !loaderstate.MainModules.Contains(mods[0].Path) {
if _, err := goModSummary(mods[0]); err != nil { if _, err := goModSummary(loaderstate, mods[0]); err != nil {
return module.Version{}, "", "", nil, err return module.Version{}, "", "", nil, err
} }
} }
@ -483,7 +483,7 @@ func importFromModules(ctx context.Context, path string, rs *Requirements, mg *M
// We checked the full module graph and still didn't find the // We checked the full module graph and still didn't find the
// requested package. // requested package.
var queryErr error var queryErr error
if !HasModRoot() { if !HasModRoot(loaderstate) {
queryErr = ErrNoModRoot queryErr = ErrNoModRoot
} }
return module.Version{}, "", "", nil, &ImportMissingError{Path: path, QueryErr: queryErr, isStd: pathIsStd} return module.Version{}, "", "", nil, &ImportMissingError{Path: path, QueryErr: queryErr, isStd: pathIsStd}
@ -491,7 +491,7 @@ func importFromModules(ctx context.Context, path string, rs *Requirements, mg *M
// So far we've checked the root dependencies. // So far we've checked the root dependencies.
// Load the full module graph and try again. // Load the full module graph and try again.
mg, err = rs.Graph(ctx) mg, err = rs.Graph(loaderstate, ctx)
if err != nil { if err != nil {
// We might be missing one or more transitive (implicit) dependencies from // We might be missing one or more transitive (implicit) dependencies from
// the module graph, so we can't return an ImportMissingError here — one // the module graph, so we can't return an ImportMissingError here — one
@ -507,12 +507,12 @@ func importFromModules(ctx context.Context, path string, rs *Requirements, mg *M
// //
// Unlike QueryPattern, queryImport prefers to add a replaced version of a // Unlike QueryPattern, queryImport prefers to add a replaced version of a
// module *before* checking the proxies for a version to add. // module *before* checking the proxies for a version to add.
func queryImport(ctx context.Context, path string, rs *Requirements) (module.Version, error) { func queryImport(loaderstate *State, ctx context.Context, path string, rs *Requirements) (module.Version, error) {
// To avoid spurious remote fetches, try the latest replacement for each // To avoid spurious remote fetches, try the latest replacement for each
// module (golang.org/issue/26241). // module (golang.org/issue/26241).
var mods []module.Version var mods []module.Version
if LoaderState.MainModules != nil { // TODO(#48912): Ensure MainModules exists at this point, and remove the check. if loaderstate.MainModules != nil { // TODO(#48912): Ensure MainModules exists at this point, and remove the check.
for mp, mv := range LoaderState.MainModules.HighestReplaced() { for mp, mv := range loaderstate.MainModules.HighestReplaced() {
if !maybeInModule(path, mp) { if !maybeInModule(path, mp) {
continue continue
} }
@ -528,7 +528,7 @@ func queryImport(ctx context.Context, path string, rs *Requirements) (module.Ver
mv = module.ZeroPseudoVersion("v0") mv = module.ZeroPseudoVersion("v0")
} }
} }
mg, err := rs.Graph(ctx) mg, err := rs.Graph(loaderstate, ctx)
if err != nil { if err != nil {
return module.Version{}, err return module.Version{}, err
} }
@ -547,7 +547,7 @@ func queryImport(ctx context.Context, path string, rs *Requirements) (module.Ver
return len(mods[i].Path) > len(mods[j].Path) return len(mods[i].Path) > len(mods[j].Path)
}) })
for _, m := range mods { for _, m := range mods {
root, isLocal, err := fetch(ctx, m) root, isLocal, err := fetch(loaderstate, ctx, m)
if err != nil { if err != nil {
if _, ok := errors.AsType[*sumMissingError](err); ok { if _, ok := errors.AsType[*sumMissingError](err); ok {
return module.Version{}, &ImportMissingSumError{importPath: path} return module.Version{}, &ImportMissingSumError{importPath: path}
@ -567,7 +567,7 @@ func queryImport(ctx context.Context, path string, rs *Requirements) (module.Ver
// The package path is not valid to fetch remotely, // The package path is not valid to fetch remotely,
// so it can only exist in a replaced module, // so it can only exist in a replaced module,
// and we know from the above loop that it is not. // and we know from the above loop that it is not.
replacement := Replacement(mods[0]) replacement := Replacement(loaderstate, mods[0])
return module.Version{}, &PackageNotInModuleError{ return module.Version{}, &PackageNotInModuleError{
Mod: mods[0], Mod: mods[0],
Query: "latest", Query: "latest",
@ -607,12 +607,12 @@ func queryImport(ctx context.Context, path string, rs *Requirements) (module.Ver
// and return m, dir, ImportMissingError. // and return m, dir, ImportMissingError.
fmt.Fprintf(os.Stderr, "go: finding module for package %s\n", path) fmt.Fprintf(os.Stderr, "go: finding module for package %s\n", path)
mg, err := rs.Graph(ctx) mg, err := rs.Graph(loaderstate, ctx)
if err != nil { if err != nil {
return module.Version{}, err return module.Version{}, err
} }
candidates, err := QueryPackages(ctx, path, "latest", mg.Selected, CheckAllowed) candidates, err := QueryPackages(loaderstate, ctx, path, "latest", mg.Selected, CheckAllowed)
if err != nil { if err != nil {
if errors.Is(err, fs.ErrNotExist) { if errors.Is(err, fs.ErrNotExist) {
// Return "cannot find module providing package […]" instead of whatever // Return "cannot find module providing package […]" instead of whatever
@ -747,15 +747,15 @@ func dirInModule(path, mpath, mdir string, isLocal bool) (dir string, haveGoFile
// //
// The isLocal return value reports whether the replacement, // The isLocal return value reports whether the replacement,
// if any, is local to the filesystem. // if any, is local to the filesystem.
func fetch(ctx context.Context, mod module.Version) (dir string, isLocal bool, err error) { func fetch(loaderstate *State, ctx context.Context, mod module.Version) (dir string, isLocal bool, err error) {
if modRoot := LoaderState.MainModules.ModRoot(mod); modRoot != "" { if modRoot := loaderstate.MainModules.ModRoot(mod); modRoot != "" {
return modRoot, true, nil return modRoot, true, nil
} }
if r := Replacement(mod); r.Path != "" { if r := Replacement(loaderstate, mod); r.Path != "" {
if r.Version == "" { if r.Version == "" {
dir = r.Path dir = r.Path
if !filepath.IsAbs(dir) { if !filepath.IsAbs(dir) {
dir = filepath.Join(replaceRelativeTo(), dir) dir = filepath.Join(replaceRelativeTo(loaderstate), dir)
} }
// Ensure that the replacement directory actually exists: // Ensure that the replacement directory actually exists:
// dirInModule does not report errors for missing modules, // dirInModule does not report errors for missing modules,
@ -780,7 +780,7 @@ func fetch(ctx context.Context, mod module.Version) (dir string, isLocal bool, e
mod = r mod = r
} }
if mustHaveSums() && !modfetch.HaveSum(mod) { if mustHaveSums(loaderstate) && !modfetch.HaveSum(mod) {
return "", false, module.VersionError(mod, &sumMissingError{}) return "", false, module.VersionError(mod, &sumMissingError{})
} }
@ -790,8 +790,8 @@ func fetch(ctx context.Context, mod module.Version) (dir string, isLocal bool, e
// mustHaveSums reports whether we require that all checksums // mustHaveSums reports whether we require that all checksums
// needed to load or build packages are already present in the go.sum file. // needed to load or build packages are already present in the go.sum file.
func mustHaveSums() bool { func mustHaveSums(loaderstate *State) bool {
return HasModRoot() && cfg.BuildMod == "readonly" && !inWorkspaceMode() return HasModRoot(loaderstate) && cfg.BuildMod == "readonly" && !inWorkspaceMode(loaderstate)
} }
type sumMissingError struct { type sumMissingError struct {

View file

@ -69,12 +69,12 @@ func TestQueryImport(t *testing.T) {
LoaderState.RootMode = NoRoot LoaderState.RootMode = NoRoot
ctx := context.Background() ctx := context.Background()
rs := LoadModFile(ctx) rs := LoadModFile(LoaderState, ctx)
for _, tt := range importTests { for _, tt := range importTests {
t.Run(strings.ReplaceAll(tt.path, "/", "_"), func(t *testing.T) { t.Run(strings.ReplaceAll(tt.path, "/", "_"), func(t *testing.T) {
// Note that there is no build list, so Import should always fail. // Note that there is no build list, so Import should always fail.
m, err := queryImport(ctx, tt.path, rs) m, err := queryImport(LoaderState, ctx, tt.path, rs)
if tt.err == "" { if tt.err == "" {
if err != nil { if err != nil {

View file

@ -64,7 +64,7 @@ func EnterModule(ctx context.Context, enterModroot string) {
modfetch.Reset() modfetch.Reset()
LoaderState.modRoots = []string{enterModroot} LoaderState.modRoots = []string{enterModroot}
LoadModFile(ctx) LoadModFile(LoaderState, ctx)
} }
// EnterWorkspace enters workspace mode from module mode, applying the updated requirements to the main // EnterWorkspace enters workspace mode from module mode, applying the updated requirements to the main
@ -73,9 +73,9 @@ func EnterModule(ctx context.Context, enterModroot string) {
// EnterWorkspace will modify the global state they depend on in a non-thread-safe way. // EnterWorkspace will modify the global state they depend on in a non-thread-safe way.
func EnterWorkspace(ctx context.Context) (exit func(), err error) { func EnterWorkspace(ctx context.Context) (exit func(), err error) {
// Find the identity of the main module that will be updated before we reset modload state. // Find the identity of the main module that will be updated before we reset modload state.
mm := LoaderState.MainModules.mustGetSingleMainModule() mm := LoaderState.MainModules.mustGetSingleMainModule(LoaderState)
// Get the updated modfile we will use for that module. // Get the updated modfile we will use for that module.
_, _, updatedmodfile, err := UpdateGoModFromReqs(ctx, WriteOpts{}) _, _, updatedmodfile, err := UpdateGoModFromReqs(LoaderState, ctx, WriteOpts{})
if err != nil { if err != nil {
return nil, err return nil, err
} }
@ -85,12 +85,12 @@ func EnterWorkspace(ctx context.Context) (exit func(), err error) {
LoaderState.ForceUseModules = true LoaderState.ForceUseModules = true
// Load in workspace mode. // Load in workspace mode.
InitWorkfile() InitWorkfile(LoaderState)
LoadModFile(ctx) LoadModFile(LoaderState, ctx)
// Update the content of the previous main module, and recompute the requirements. // Update the content of the previous main module, and recompute the requirements.
*LoaderState.MainModules.ModFile(mm) = *updatedmodfile *LoaderState.MainModules.ModFile(mm) = *updatedmodfile
LoaderState.requirements = requirementsFromModFiles(ctx, LoaderState.MainModules.workFile, slices.Collect(maps.Values(LoaderState.MainModules.modFiles)), nil) LoaderState.requirements = requirementsFromModFiles(LoaderState, ctx, LoaderState.MainModules.workFile, slices.Collect(maps.Values(LoaderState.MainModules.modFiles)), nil)
return func() { return func() {
setState(oldstate) setState(oldstate)
@ -182,12 +182,12 @@ func (mms *MainModuleSet) InGorootSrc(m module.Version) bool {
return mms.inGorootSrc[m] return mms.inGorootSrc[m]
} }
func (mms *MainModuleSet) mustGetSingleMainModule() module.Version { func (mms *MainModuleSet) mustGetSingleMainModule(loaderstate *State) module.Version {
if mms == nil || len(mms.versions) == 0 { if mms == nil || len(mms.versions) == 0 {
panic("internal error: mustGetSingleMainModule called in context with no main modules") panic("internal error: mustGetSingleMainModule called in context with no main modules")
} }
if len(mms.versions) != 1 { if len(mms.versions) != 1 {
if inWorkspaceMode() { if inWorkspaceMode(loaderstate) {
panic("internal error: mustGetSingleMainModule called in workspace mode") panic("internal error: mustGetSingleMainModule called in workspace mode")
} else { } else {
panic("internal error: multiple main modules present outside of workspace mode") panic("internal error: multiple main modules present outside of workspace mode")
@ -196,14 +196,14 @@ func (mms *MainModuleSet) mustGetSingleMainModule() module.Version {
return mms.versions[0] return mms.versions[0]
} }
func (mms *MainModuleSet) GetSingleIndexOrNil() *modFileIndex { func (mms *MainModuleSet) GetSingleIndexOrNil(loaderstate *State) *modFileIndex {
if mms == nil { if mms == nil {
return nil return nil
} }
if len(mms.versions) == 0 { if len(mms.versions) == 0 {
return nil return nil
} }
return mms.indices[mms.mustGetSingleMainModule()] return mms.indices[mms.mustGetSingleMainModule(loaderstate)]
} }
func (mms *MainModuleSet) Index(m module.Version) *modFileIndex { func (mms *MainModuleSet) Index(m module.Version) *modFileIndex {
@ -246,12 +246,12 @@ func (mms *MainModuleSet) HighestReplaced() map[string]string {
// GoVersion returns the go version set on the single module, in module mode, // GoVersion returns the go version set on the single module, in module mode,
// or the go.work file in workspace mode. // or the go.work file in workspace mode.
func (mms *MainModuleSet) GoVersion() string { func (mms *MainModuleSet) GoVersion(loaderstate *State) string {
if inWorkspaceMode() { if inWorkspaceMode(loaderstate) {
return gover.FromGoWork(mms.workFile) return gover.FromGoWork(mms.workFile)
} }
if mms != nil && len(mms.versions) == 1 { if mms != nil && len(mms.versions) == 1 {
f := mms.ModFile(mms.mustGetSingleMainModule()) f := mms.ModFile(mms.mustGetSingleMainModule(loaderstate))
if f == nil { if f == nil {
// Special case: we are outside a module, like 'go run x.go'. // Special case: we are outside a module, like 'go run x.go'.
// Assume the local Go version. // Assume the local Go version.
@ -266,15 +266,15 @@ func (mms *MainModuleSet) GoVersion() string {
// Godebugs returns the godebug lines set on the single module, in module mode, // Godebugs returns the godebug lines set on the single module, in module mode,
// or on the go.work file in workspace mode. // or on the go.work file in workspace mode.
// The caller must not modify the result. // The caller must not modify the result.
func (mms *MainModuleSet) Godebugs() []*modfile.Godebug { func (mms *MainModuleSet) Godebugs(loaderstate *State) []*modfile.Godebug {
if inWorkspaceMode() { if inWorkspaceMode(loaderstate) {
if mms.workFile != nil { if mms.workFile != nil {
return mms.workFile.Godebug return mms.workFile.Godebug
} }
return nil return nil
} }
if mms != nil && len(mms.versions) == 1 { if mms != nil && len(mms.versions) == 1 {
f := mms.ModFile(mms.mustGetSingleMainModule()) f := mms.ModFile(mms.mustGetSingleMainModule(loaderstate))
if f == nil { if f == nil {
// Special case: we are outside a module, like 'go run x.go'. // Special case: we are outside a module, like 'go run x.go'.
return nil return nil
@ -315,16 +315,16 @@ const (
// To make permanent changes to the require statements // To make permanent changes to the require statements
// in go.mod, edit it before loading. // in go.mod, edit it before loading.
func ModFile() *modfile.File { func ModFile() *modfile.File {
Init() Init(LoaderState)
modFile := LoaderState.MainModules.ModFile(LoaderState.MainModules.mustGetSingleMainModule()) modFile := LoaderState.MainModules.ModFile(LoaderState.MainModules.mustGetSingleMainModule(LoaderState))
if modFile == nil { if modFile == nil {
die() die(LoaderState)
} }
return modFile return modFile
} }
func BinDir() string { func BinDir(loaderstate *State) string {
Init() Init(loaderstate)
if cfg.GOBIN != "" { if cfg.GOBIN != "" {
return cfg.GOBIN return cfg.GOBIN
} }
@ -337,13 +337,13 @@ func BinDir() string {
// InitWorkfile initializes the workFilePath variable for commands that // InitWorkfile initializes the workFilePath variable for commands that
// operate in workspace mode. It should not be called by other commands, // operate in workspace mode. It should not be called by other commands,
// for example 'go mod tidy', that don't operate in workspace mode. // for example 'go mod tidy', that don't operate in workspace mode.
func InitWorkfile() { func InitWorkfile(loaderstate *State) {
// Initialize fsys early because we need overlay to read go.work file. // Initialize fsys early because we need overlay to read go.work file.
fips140.Init() fips140.Init()
if err := fsys.Init(); err != nil { if err := fsys.Init(); err != nil {
base.Fatal(err) base.Fatal(err)
} }
LoaderState.workFilePath = FindGoWork(base.Cwd()) loaderstate.workFilePath = FindGoWork(loaderstate, base.Cwd())
} }
// FindGoWork returns the name of the go.work file for this command, // FindGoWork returns the name of the go.work file for this command,
@ -351,8 +351,8 @@ func InitWorkfile() {
// Most code should use Init and Enabled rather than use this directly. // Most code should use Init and Enabled rather than use this directly.
// It is exported mainly for Go toolchain switching, which must process // It is exported mainly for Go toolchain switching, which must process
// the go.work very early at startup. // the go.work very early at startup.
func FindGoWork(wd string) string { func FindGoWork(loaderstate *State, wd string) string {
if LoaderState.RootMode == NoRoot { if loaderstate.RootMode == NoRoot {
return "" return ""
} }
@ -371,8 +371,8 @@ func FindGoWork(wd string) string {
// WorkFilePath returns the absolute path of the go.work file, or "" if not in // WorkFilePath returns the absolute path of the go.work file, or "" if not in
// workspace mode. WorkFilePath must be called after InitWorkfile. // workspace mode. WorkFilePath must be called after InitWorkfile.
func WorkFilePath() string { func WorkFilePath(loaderstate *State) string {
return LoaderState.workFilePath return loaderstate.workFilePath
} }
// Reset clears all the initialized, cached state about the use of modules, // Reset clears all the initialized, cached state about the use of modules,
@ -451,11 +451,11 @@ var LoaderState = NewState()
// current module (if any), sets environment variables for Git subprocesses, and // current module (if any), sets environment variables for Git subprocesses, and
// configures the cfg, codehost, load, modfetch, and search packages for use // configures the cfg, codehost, load, modfetch, and search packages for use
// with modules. // with modules.
func Init() { func Init(loaderstate *State) {
if LoaderState.initialized { if loaderstate.initialized {
return return
} }
LoaderState.initialized = true loaderstate.initialized = true
fips140.Init() fips140.Init()
@ -468,11 +468,11 @@ func Init() {
default: default:
base.Fatalf("go: unknown environment setting GO111MODULE=%s", env) base.Fatalf("go: unknown environment setting GO111MODULE=%s", env)
case "auto": case "auto":
mustUseModules = LoaderState.ForceUseModules mustUseModules = loaderstate.ForceUseModules
case "on", "": case "on", "":
mustUseModules = true mustUseModules = true
case "off": case "off":
if LoaderState.ForceUseModules { if loaderstate.ForceUseModules {
base.Fatalf("go: modules disabled by GO111MODULE=off; see 'go help modules'") base.Fatalf("go: modules disabled by GO111MODULE=off; see 'go help modules'")
} }
mustUseModules = false mustUseModules = false
@ -496,15 +496,15 @@ func Init() {
if os.Getenv("GCM_INTERACTIVE") == "" { if os.Getenv("GCM_INTERACTIVE") == "" {
os.Setenv("GCM_INTERACTIVE", "never") os.Setenv("GCM_INTERACTIVE", "never")
} }
if LoaderState.modRoots != nil { if loaderstate.modRoots != nil {
// modRoot set before Init was called ("go mod init" does this). // modRoot set before Init was called ("go mod init" does this).
// No need to search for go.mod. // No need to search for go.mod.
} else if LoaderState.RootMode == NoRoot { } else if loaderstate.RootMode == NoRoot {
if cfg.ModFile != "" && !base.InGOFLAGS("-modfile") { if cfg.ModFile != "" && !base.InGOFLAGS("-modfile") {
base.Fatalf("go: -modfile cannot be used with commands that ignore the current module") base.Fatalf("go: -modfile cannot be used with commands that ignore the current module")
} }
LoaderState.modRoots = nil loaderstate.modRoots = nil
} else if LoaderState.workFilePath != "" { } else if loaderstate.workFilePath != "" {
// We're in workspace mode, which implies module mode. // We're in workspace mode, which implies module mode.
if cfg.ModFile != "" { if cfg.ModFile != "" {
base.Fatalf("go: -modfile cannot be used in workspace mode") base.Fatalf("go: -modfile cannot be used in workspace mode")
@ -514,7 +514,7 @@ func Init() {
if cfg.ModFile != "" { if cfg.ModFile != "" {
base.Fatalf("go: cannot find main module, but -modfile was set.\n\t-modfile cannot be used to set the module root directory.") base.Fatalf("go: cannot find main module, but -modfile was set.\n\t-modfile cannot be used to set the module root directory.")
} }
if LoaderState.RootMode == NeedRoot { if loaderstate.RootMode == NeedRoot {
base.Fatal(ErrNoModRoot) base.Fatal(ErrNoModRoot)
} }
if !mustUseModules { if !mustUseModules {
@ -529,14 +529,14 @@ func Init() {
// It's a bit of a peculiar thing to disallow but quite mysterious // It's a bit of a peculiar thing to disallow but quite mysterious
// when it happens. See golang.org/issue/26708. // when it happens. See golang.org/issue/26708.
fmt.Fprintf(os.Stderr, "go: warning: ignoring go.mod in system temp root %v\n", os.TempDir()) fmt.Fprintf(os.Stderr, "go: warning: ignoring go.mod in system temp root %v\n", os.TempDir())
if LoaderState.RootMode == NeedRoot { if loaderstate.RootMode == NeedRoot {
base.Fatal(ErrNoModRoot) base.Fatal(ErrNoModRoot)
} }
if !mustUseModules { if !mustUseModules {
return return
} }
} else { } else {
LoaderState.modRoots = []string{modRoot} loaderstate.modRoots = []string{modRoot}
} }
} }
if cfg.ModFile != "" && !strings.HasSuffix(cfg.ModFile, ".mod") { if cfg.ModFile != "" && !strings.HasSuffix(cfg.ModFile, ".mod") {
@ -545,13 +545,13 @@ func Init() {
// We're in module mode. Set any global variables that need to be set. // We're in module mode. Set any global variables that need to be set.
cfg.ModulesEnabled = true cfg.ModulesEnabled = true
setDefaultBuildMod() setDefaultBuildMod(loaderstate)
list := filepath.SplitList(cfg.BuildContext.GOPATH) list := filepath.SplitList(cfg.BuildContext.GOPATH)
if len(list) > 0 && list[0] != "" { if len(list) > 0 && list[0] != "" {
gopath = list[0] gopath = list[0]
if _, err := fsys.Stat(filepath.Join(gopath, "go.mod")); err == nil { if _, err := fsys.Stat(filepath.Join(gopath, "go.mod")); err == nil {
fmt.Fprintf(os.Stderr, "go: warning: ignoring go.mod in $GOPATH %v\n", gopath) fmt.Fprintf(os.Stderr, "go: warning: ignoring go.mod in $GOPATH %v\n", gopath)
if LoaderState.RootMode == NeedRoot { if loaderstate.RootMode == NeedRoot {
base.Fatal(ErrNoModRoot) base.Fatal(ErrNoModRoot)
} }
if !mustUseModules { if !mustUseModules {
@ -622,49 +622,49 @@ func FindGoMod(wd string) string {
// If modules are enabled but there is no main module, Enabled returns true // If modules are enabled but there is no main module, Enabled returns true
// and then the first use of module information will call die // and then the first use of module information will call die
// (usually through MustModRoot). // (usually through MustModRoot).
func Enabled() bool { func Enabled(loaderstate *State) bool {
Init() Init(loaderstate)
return LoaderState.modRoots != nil || cfg.ModulesEnabled return loaderstate.modRoots != nil || cfg.ModulesEnabled
} }
func VendorDir() string { func VendorDir(loaderstate *State) string {
if inWorkspaceMode() { if inWorkspaceMode(loaderstate) {
return filepath.Join(filepath.Dir(WorkFilePath()), "vendor") return filepath.Join(filepath.Dir(WorkFilePath(loaderstate)), "vendor")
} }
// Even if -mod=vendor, we could be operating with no mod root (and thus no // Even if -mod=vendor, we could be operating with no mod root (and thus no
// vendor directory). As long as there are no dependencies that is expected // vendor directory). As long as there are no dependencies that is expected
// to work. See script/vendor_outside_module.txt. // to work. See script/vendor_outside_module.txt.
modRoot := LoaderState.MainModules.ModRoot(LoaderState.MainModules.mustGetSingleMainModule()) modRoot := loaderstate.MainModules.ModRoot(loaderstate.MainModules.mustGetSingleMainModule(loaderstate))
if modRoot == "" { if modRoot == "" {
panic("vendor directory does not exist when in single module mode outside of a module") panic("vendor directory does not exist when in single module mode outside of a module")
} }
return filepath.Join(modRoot, "vendor") return filepath.Join(modRoot, "vendor")
} }
func inWorkspaceMode() bool { func inWorkspaceMode(loaderstate *State) bool {
if !LoaderState.initialized { if !loaderstate.initialized {
panic("inWorkspaceMode called before modload.Init called") panic("inWorkspaceMode called before modload.Init called")
} }
if !Enabled() { if !Enabled(loaderstate) {
return false return false
} }
return LoaderState.workFilePath != "" return loaderstate.workFilePath != ""
} }
// HasModRoot reports whether a main module or main modules are present. // HasModRoot reports whether a main module or main modules are present.
// HasModRoot may return false even if Enabled returns true: for example, 'get' // HasModRoot may return false even if Enabled returns true: for example, 'get'
// does not require a main module. // does not require a main module.
func HasModRoot() bool { func HasModRoot(loaderstate *State) bool {
Init() Init(loaderstate)
return LoaderState.modRoots != nil return loaderstate.modRoots != nil
} }
// MustHaveModRoot checks that a main module or main modules are present, // MustHaveModRoot checks that a main module or main modules are present,
// and calls base.Fatalf if there are no main modules. // and calls base.Fatalf if there are no main modules.
func MustHaveModRoot() { func MustHaveModRoot() {
Init() Init(LoaderState)
if !HasModRoot() { if !HasModRoot(LoaderState) {
die() die(LoaderState)
} }
} }
@ -686,11 +686,11 @@ func modFilePath(modRoot string) string {
return filepath.Join(modRoot, "go.mod") return filepath.Join(modRoot, "go.mod")
} }
func die() { func die(loaderstate *State) {
if cfg.Getenv("GO111MODULE") == "off" { if cfg.Getenv("GO111MODULE") == "off" {
base.Fatalf("go: modules disabled by GO111MODULE=off; see 'go help modules'") base.Fatalf("go: modules disabled by GO111MODULE=off; see 'go help modules'")
} }
if !inWorkspaceMode() { if !inWorkspaceMode(loaderstate) {
if dir, name := findAltConfig(base.Cwd()); dir != "" { if dir, name := findAltConfig(base.Cwd()); dir != "" {
rel, err := filepath.Rel(base.Cwd(), dir) rel, err := filepath.Rel(base.Cwd(), dir)
if err != nil { if err != nil {
@ -711,7 +711,7 @@ func die() {
type noMainModulesError struct{} type noMainModulesError struct{}
func (e noMainModulesError) Error() string { func (e noMainModulesError) Error() string {
if inWorkspaceMode() { if inWorkspaceMode(LoaderState) {
return "no modules were found in the current workspace; see 'go help work'" return "no modules were found in the current workspace; see 'go help work'"
} }
return "go.mod file not found in current directory or any parent directory; see 'go help modules'" return "go.mod file not found in current directory or any parent directory; see 'go help modules'"
@ -868,33 +868,33 @@ func UpdateWorkFile(wf *modfile.WorkFile) {
// other, but unlike LoadModGraph does not load the full module graph or check // other, but unlike LoadModGraph does not load the full module graph or check
// it for global consistency. Most callers outside of the modload package should // it for global consistency. Most callers outside of the modload package should
// use LoadModGraph instead. // use LoadModGraph instead.
func LoadModFile(ctx context.Context) *Requirements { func LoadModFile(loaderstate *State, ctx context.Context) *Requirements {
rs, err := loadModFile(ctx, nil) rs, err := loadModFile(loaderstate, ctx, nil)
if err != nil { if err != nil {
base.Fatal(err) base.Fatal(err)
} }
return rs return rs
} }
func loadModFile(ctx context.Context, opts *PackageOpts) (*Requirements, error) { func loadModFile(loaderstate *State, ctx context.Context, opts *PackageOpts) (*Requirements, error) {
if LoaderState.requirements != nil { if loaderstate.requirements != nil {
return LoaderState.requirements, nil return loaderstate.requirements, nil
} }
Init() Init(loaderstate)
var workFile *modfile.WorkFile var workFile *modfile.WorkFile
if inWorkspaceMode() { if inWorkspaceMode(loaderstate) {
var err error var err error
workFile, LoaderState.modRoots, err = LoadWorkFile(LoaderState.workFilePath) workFile, loaderstate.modRoots, err = LoadWorkFile(loaderstate.workFilePath)
if err != nil { if err != nil {
return nil, err return nil, err
} }
for _, modRoot := range LoaderState.modRoots { for _, modRoot := range loaderstate.modRoots {
sumFile := strings.TrimSuffix(modFilePath(modRoot), ".mod") + ".sum" sumFile := strings.TrimSuffix(modFilePath(modRoot), ".mod") + ".sum"
modfetch.WorkspaceGoSumFiles = append(modfetch.WorkspaceGoSumFiles, sumFile) modfetch.WorkspaceGoSumFiles = append(modfetch.WorkspaceGoSumFiles, sumFile)
} }
modfetch.GoSumFile = LoaderState.workFilePath + ".sum" modfetch.GoSumFile = loaderstate.workFilePath + ".sum"
} else if len(LoaderState.modRoots) == 0 { } else if len(loaderstate.modRoots) == 0 {
// We're in module mode, but not inside a module. // We're in module mode, but not inside a module.
// //
// Commands like 'go build', 'go run', 'go list' have no go.mod file to // Commands like 'go build', 'go run', 'go list' have no go.mod file to
@ -913,25 +913,25 @@ func loadModFile(ctx context.Context, opts *PackageOpts) (*Requirements, error)
// //
// See golang.org/issue/32027. // See golang.org/issue/32027.
} else { } else {
modfetch.GoSumFile = strings.TrimSuffix(modFilePath(LoaderState.modRoots[0]), ".mod") + ".sum" modfetch.GoSumFile = strings.TrimSuffix(modFilePath(loaderstate.modRoots[0]), ".mod") + ".sum"
} }
if len(LoaderState.modRoots) == 0 { if len(loaderstate.modRoots) == 0 {
// TODO(#49228): Instead of creating a fake module with an empty modroot, // TODO(#49228): Instead of creating a fake module with an empty modroot,
// make MainModules.Len() == 0 mean that we're in module mode but not inside // make MainModules.Len() == 0 mean that we're in module mode but not inside
// any module. // any module.
mainModule := module.Version{Path: "command-line-arguments"} mainModule := module.Version{Path: "command-line-arguments"}
LoaderState.MainModules = makeMainModules([]module.Version{mainModule}, []string{""}, []*modfile.File{nil}, []*modFileIndex{nil}, nil) loaderstate.MainModules = makeMainModules(loaderstate, []module.Version{mainModule}, []string{""}, []*modfile.File{nil}, []*modFileIndex{nil}, nil)
var ( var (
goVersion string goVersion string
pruning modPruning pruning modPruning
roots []module.Version roots []module.Version
direct = map[string]bool{"go": true} direct = map[string]bool{"go": true}
) )
if inWorkspaceMode() { if inWorkspaceMode(loaderstate) {
// Since we are in a workspace, the Go version for the synthetic // Since we are in a workspace, the Go version for the synthetic
// "command-line-arguments" module must not exceed the Go version // "command-line-arguments" module must not exceed the Go version
// for the workspace. // for the workspace.
goVersion = LoaderState.MainModules.GoVersion() goVersion = loaderstate.MainModules.GoVersion(loaderstate)
pruning = workspace pruning = workspace
roots = []module.Version{ roots = []module.Version{
mainModule, mainModule,
@ -947,26 +947,26 @@ func loadModFile(ctx context.Context, opts *PackageOpts) (*Requirements, error)
} }
} }
rawGoVersion.Store(mainModule, goVersion) rawGoVersion.Store(mainModule, goVersion)
LoaderState.requirements = newRequirements(pruning, roots, direct) loaderstate.requirements = newRequirements(loaderstate, pruning, roots, direct)
if cfg.BuildMod == "vendor" { if cfg.BuildMod == "vendor" {
// For issue 56536: Some users may have GOFLAGS=-mod=vendor set. // For issue 56536: Some users may have GOFLAGS=-mod=vendor set.
// Make sure it behaves as though the fake module is vendored // Make sure it behaves as though the fake module is vendored
// with no dependencies. // with no dependencies.
LoaderState.requirements.initVendor(nil) loaderstate.requirements.initVendor(loaderstate, nil)
} }
return LoaderState.requirements, nil return loaderstate.requirements, nil
} }
var modFiles []*modfile.File var modFiles []*modfile.File
var mainModules []module.Version var mainModules []module.Version
var indices []*modFileIndex var indices []*modFileIndex
var errs []error var errs []error
for _, modroot := range LoaderState.modRoots { for _, modroot := range loaderstate.modRoots {
gomod := modFilePath(modroot) gomod := modFilePath(modroot)
var fixed bool var fixed bool
data, f, err := ReadModFile(gomod, fixVersion(ctx, &fixed)) data, f, err := ReadModFile(gomod, fixVersion(loaderstate, ctx, &fixed))
if err != nil { if err != nil {
if inWorkspaceMode() { if inWorkspaceMode(loaderstate) {
if tooNew, ok := err.(*gover.TooNewError); ok && !strings.HasPrefix(cfg.CmdName, "work ") { if tooNew, ok := err.(*gover.TooNewError); ok && !strings.HasPrefix(cfg.CmdName, "work ") {
// Switching to a newer toolchain won't help - the go.work has the wrong version. // Switching to a newer toolchain won't help - the go.work has the wrong version.
// Report this more specific error, unless we are a command like 'go work use' // Report this more specific error, unless we are a command like 'go work use'
@ -981,7 +981,7 @@ func loadModFile(ctx context.Context, opts *PackageOpts) (*Requirements, error)
errs = append(errs, err) errs = append(errs, err)
continue continue
} }
if inWorkspaceMode() && !strings.HasPrefix(cfg.CmdName, "work ") { if inWorkspaceMode(loaderstate) && !strings.HasPrefix(cfg.CmdName, "work ") {
// Refuse to use workspace if its go version is too old. // Refuse to use workspace if its go version is too old.
// Disable this check if we are a workspace command like work use or work sync, // Disable this check if we are a workspace command like work use or work sync,
// which will fix the problem. // which will fix the problem.
@ -993,7 +993,7 @@ func loadModFile(ctx context.Context, opts *PackageOpts) (*Requirements, error)
} }
} }
if !inWorkspaceMode() { if !inWorkspaceMode(loaderstate) {
ok := true ok := true
for _, g := range f.Godebug { for _, g := range f.Godebug {
if err := CheckGodebug("godebug", g.Key, g.Value); err != nil { if err := CheckGodebug("godebug", g.Key, g.Value); err != nil {
@ -1022,45 +1022,45 @@ func loadModFile(ctx context.Context, opts *PackageOpts) (*Requirements, error)
return nil, errors.Join(errs...) return nil, errors.Join(errs...)
} }
LoaderState.MainModules = makeMainModules(mainModules, LoaderState.modRoots, modFiles, indices, workFile) loaderstate.MainModules = makeMainModules(loaderstate, mainModules, loaderstate.modRoots, modFiles, indices, workFile)
setDefaultBuildMod() // possibly enable automatic vendoring setDefaultBuildMod(loaderstate) // possibly enable automatic vendoring
rs := requirementsFromModFiles(ctx, workFile, modFiles, opts) rs := requirementsFromModFiles(loaderstate, ctx, workFile, modFiles, opts)
if cfg.BuildMod == "vendor" { if cfg.BuildMod == "vendor" {
readVendorList(VendorDir()) readVendorList(VendorDir(loaderstate))
versions := LoaderState.MainModules.Versions() versions := loaderstate.MainModules.Versions()
indexes := make([]*modFileIndex, 0, len(versions)) indexes := make([]*modFileIndex, 0, len(versions))
modFiles := make([]*modfile.File, 0, len(versions)) modFiles := make([]*modfile.File, 0, len(versions))
modRoots := make([]string, 0, len(versions)) modRoots := make([]string, 0, len(versions))
for _, m := range versions { for _, m := range versions {
indexes = append(indexes, LoaderState.MainModules.Index(m)) indexes = append(indexes, loaderstate.MainModules.Index(m))
modFiles = append(modFiles, LoaderState.MainModules.ModFile(m)) modFiles = append(modFiles, loaderstate.MainModules.ModFile(m))
modRoots = append(modRoots, LoaderState.MainModules.ModRoot(m)) modRoots = append(modRoots, loaderstate.MainModules.ModRoot(m))
} }
checkVendorConsistency(indexes, modFiles, modRoots) checkVendorConsistency(loaderstate, indexes, modFiles, modRoots)
rs.initVendor(vendorList) rs.initVendor(loaderstate, vendorList)
} }
if inWorkspaceMode() { if inWorkspaceMode(loaderstate) {
// We don't need to update the mod file so return early. // We don't need to update the mod file so return early.
LoaderState.requirements = rs loaderstate.requirements = rs
return rs, nil return rs, nil
} }
mainModule := LoaderState.MainModules.mustGetSingleMainModule() mainModule := loaderstate.MainModules.mustGetSingleMainModule(loaderstate)
if rs.hasRedundantRoot() { if rs.hasRedundantRoot(loaderstate) {
// If any module path appears more than once in the roots, we know that the // If any module path appears more than once in the roots, we know that the
// go.mod file needs to be updated even though we have not yet loaded any // go.mod file needs to be updated even though we have not yet loaded any
// transitive dependencies. // transitive dependencies.
var err error var err error
rs, err = updateRoots(ctx, rs.direct, rs, nil, nil, false) rs, err = updateRoots(loaderstate, ctx, rs.direct, rs, nil, nil, false)
if err != nil { if err != nil {
return nil, err return nil, err
} }
} }
if LoaderState.MainModules.Index(mainModule).goVersion == "" && rs.pruning != workspace { if loaderstate.MainModules.Index(mainModule).goVersion == "" && rs.pruning != workspace {
// TODO(#45551): Do something more principled instead of checking // TODO(#45551): Do something more principled instead of checking
// cfg.CmdName directly here. // cfg.CmdName directly here.
if cfg.BuildMod == "mod" && cfg.CmdName != "mod graph" && cfg.CmdName != "mod why" { if cfg.BuildMod == "mod" && cfg.CmdName != "mod graph" && cfg.CmdName != "mod why" {
@ -1069,8 +1069,8 @@ func loadModFile(ctx context.Context, opts *PackageOpts) (*Requirements, error)
if opts != nil && opts.TidyGoVersion != "" { if opts != nil && opts.TidyGoVersion != "" {
v = opts.TidyGoVersion v = opts.TidyGoVersion
} }
addGoStmt(LoaderState.MainModules.ModFile(mainModule), mainModule, v) addGoStmt(loaderstate.MainModules.ModFile(mainModule), mainModule, v)
rs = overrideRoots(ctx, rs, []module.Version{{Path: "go", Version: v}}) rs = overrideRoots(loaderstate, ctx, rs, []module.Version{{Path: "go", Version: v}})
// We need to add a 'go' version to the go.mod file, but we must assume // We need to add a 'go' version to the go.mod file, but we must assume
// that its existing contents match something between Go 1.11 and 1.16. // that its existing contents match something between Go 1.11 and 1.16.
@ -1079,7 +1079,7 @@ func loadModFile(ctx context.Context, opts *PackageOpts) (*Requirements, error)
// requirements to support pruning. // requirements to support pruning.
if gover.Compare(v, gover.ExplicitIndirectVersion) >= 0 { if gover.Compare(v, gover.ExplicitIndirectVersion) >= 0 {
var err error var err error
rs, err = convertPruning(ctx, rs, pruned) rs, err = convertPruning(loaderstate, ctx, rs, pruned)
if err != nil { if err != nil {
return nil, err return nil, err
} }
@ -1089,8 +1089,8 @@ func loadModFile(ctx context.Context, opts *PackageOpts) (*Requirements, error)
} }
} }
LoaderState.requirements = rs loaderstate.requirements = rs
return LoaderState.requirements, nil return loaderstate.requirements, nil
} }
func errWorkTooOld(gomod string, wf *modfile.WorkFile, goVers string) error { func errWorkTooOld(gomod string, wf *modfile.WorkFile, goVers string) error {
@ -1126,7 +1126,7 @@ func CheckReservedModulePath(path string) error {
func CreateModFile(ctx context.Context, modPath string) { func CreateModFile(ctx context.Context, modPath string) {
modRoot := base.Cwd() modRoot := base.Cwd()
LoaderState.modRoots = []string{modRoot} LoaderState.modRoots = []string{modRoot}
Init() Init(LoaderState)
modFilePath := modFilePath(modRoot) modFilePath := modFilePath(modRoot)
if _, err := fsys.Stat(modFilePath); err == nil { if _, err := fsys.Stat(modFilePath); err == nil {
base.Fatalf("go: %s already exists", modFilePath) base.Fatalf("go: %s already exists", modFilePath)
@ -1162,16 +1162,16 @@ func CreateModFile(ctx context.Context, modPath string) {
fmt.Fprintf(os.Stderr, "go: creating new go.mod: module %s\n", modPath) fmt.Fprintf(os.Stderr, "go: creating new go.mod: module %s\n", modPath)
modFile := new(modfile.File) modFile := new(modfile.File)
modFile.AddModuleStmt(modPath) modFile.AddModuleStmt(modPath)
LoaderState.MainModules = makeMainModules([]module.Version{modFile.Module.Mod}, []string{modRoot}, []*modfile.File{modFile}, []*modFileIndex{nil}, nil) LoaderState.MainModules = makeMainModules(LoaderState, []module.Version{modFile.Module.Mod}, []string{modRoot}, []*modfile.File{modFile}, []*modFileIndex{nil}, nil)
addGoStmt(modFile, modFile.Module.Mod, gover.Local()) // Add the go directive before converted module requirements. addGoStmt(modFile, modFile.Module.Mod, gover.Local()) // Add the go directive before converted module requirements.
rs := requirementsFromModFiles(ctx, nil, []*modfile.File{modFile}, nil) rs := requirementsFromModFiles(LoaderState, ctx, nil, []*modfile.File{modFile}, nil)
rs, err := updateRoots(ctx, rs.direct, rs, nil, nil, false) rs, err := updateRoots(LoaderState, ctx, rs.direct, rs, nil, nil, false)
if err != nil { if err != nil {
base.Fatal(err) base.Fatal(err)
} }
LoaderState.requirements = rs LoaderState.requirements = rs
if err := commitRequirements(ctx, WriteOpts{}); err != nil { if err := commitRequirements(LoaderState, ctx, WriteOpts{}); err != nil {
base.Fatal(err) base.Fatal(err)
} }
@ -1206,7 +1206,7 @@ func CreateModFile(ctx context.Context, modPath string) {
// and does nothing for versions that already appear to be canonical. // and does nothing for versions that already appear to be canonical.
// //
// The VersionFixer sets 'fixed' if it ever returns a non-canonical version. // The VersionFixer sets 'fixed' if it ever returns a non-canonical version.
func fixVersion(ctx context.Context, fixed *bool) modfile.VersionFixer { func fixVersion(loaderstate *State, ctx context.Context, fixed *bool) modfile.VersionFixer {
return func(path, vers string) (resolved string, err error) { return func(path, vers string) (resolved string, err error) {
defer func() { defer func() {
if err == nil && resolved != vers { if err == nil && resolved != vers {
@ -1239,7 +1239,7 @@ func fixVersion(ctx context.Context, fixed *bool) modfile.VersionFixer {
return vers, nil return vers, nil
} }
info, err := Query(ctx, path, vers, "", nil) info, err := Query(loaderstate, ctx, path, vers, "", nil)
if err != nil { if err != nil {
return "", err return "", err
} }
@ -1254,8 +1254,8 @@ func fixVersion(ctx context.Context, fixed *bool) modfile.VersionFixer {
// //
// This function affects the default cfg.BuildMod when outside of a module, // This function affects the default cfg.BuildMod when outside of a module,
// so it can only be called prior to Init. // so it can only be called prior to Init.
func AllowMissingModuleImports() { func AllowMissingModuleImports(loaderstate *State) {
if LoaderState.initialized { if loaderstate.initialized {
panic("AllowMissingModuleImports after Init") panic("AllowMissingModuleImports after Init")
} }
allowMissingModuleImports = true allowMissingModuleImports = true
@ -1263,7 +1263,7 @@ func AllowMissingModuleImports() {
// makeMainModules creates a MainModuleSet and associated variables according to // makeMainModules creates a MainModuleSet and associated variables according to
// the given main modules. // the given main modules.
func makeMainModules(ms []module.Version, rootDirs []string, modFiles []*modfile.File, indices []*modFileIndex, workFile *modfile.WorkFile) *MainModuleSet { func makeMainModules(loaderstate *State, ms []module.Version, rootDirs []string, modFiles []*modfile.File, indices []*modFileIndex, workFile *modfile.WorkFile) *MainModuleSet {
for _, m := range ms { for _, m := range ms {
if m.Version != "" { if m.Version != "" {
panic("mainModulesCalled with module.Version with non empty Version field: " + fmt.Sprintf("%#v", m)) panic("mainModulesCalled with module.Version with non empty Version field: " + fmt.Sprintf("%#v", m))
@ -1338,7 +1338,7 @@ func makeMainModules(ms []module.Version, rootDirs []string, modFiles []*modfile
continue continue
} }
var newV module.Version = r.New var newV module.Version = r.New
if WorkFilePath() != "" && newV.Version == "" && !filepath.IsAbs(newV.Path) { if WorkFilePath(loaderstate) != "" && newV.Version == "" && !filepath.IsAbs(newV.Path) {
// Since we are in a workspace, we may be loading replacements from // Since we are in a workspace, we may be loading replacements from
// multiple go.mod files. Relative paths in those replacement are // multiple go.mod files. Relative paths in those replacement are
// relative to the go.mod file, not the workspace, so the same string // relative to the go.mod file, not the workspace, so the same string
@ -1380,14 +1380,14 @@ func makeMainModules(ms []module.Version, rootDirs []string, modFiles []*modfile
// requirementsFromModFiles returns the set of non-excluded requirements from // requirementsFromModFiles returns the set of non-excluded requirements from
// the global modFile. // the global modFile.
func requirementsFromModFiles(ctx context.Context, workFile *modfile.WorkFile, modFiles []*modfile.File, opts *PackageOpts) *Requirements { func requirementsFromModFiles(loaderstate *State, ctx context.Context, workFile *modfile.WorkFile, modFiles []*modfile.File, opts *PackageOpts) *Requirements {
var roots []module.Version var roots []module.Version
direct := map[string]bool{} direct := map[string]bool{}
var pruning modPruning var pruning modPruning
if inWorkspaceMode() { if inWorkspaceMode(loaderstate) {
pruning = workspace pruning = workspace
roots = make([]module.Version, len(LoaderState.MainModules.Versions()), 2+len(LoaderState.MainModules.Versions())) roots = make([]module.Version, len(loaderstate.MainModules.Versions()), 2+len(loaderstate.MainModules.Versions()))
copy(roots, LoaderState.MainModules.Versions()) copy(roots, loaderstate.MainModules.Versions())
goVersion := gover.FromGoWork(workFile) goVersion := gover.FromGoWork(workFile)
var toolchain string var toolchain string
if workFile.Toolchain != nil { if workFile.Toolchain != nil {
@ -1396,16 +1396,16 @@ func requirementsFromModFiles(ctx context.Context, workFile *modfile.WorkFile, m
roots = appendGoAndToolchainRoots(roots, goVersion, toolchain, direct) roots = appendGoAndToolchainRoots(roots, goVersion, toolchain, direct)
direct = directRequirements(modFiles) direct = directRequirements(modFiles)
} else { } else {
pruning = pruningForGoVersion(LoaderState.MainModules.GoVersion()) pruning = pruningForGoVersion(loaderstate.MainModules.GoVersion(loaderstate))
if len(modFiles) != 1 { if len(modFiles) != 1 {
panic(fmt.Errorf("requirementsFromModFiles called with %v modfiles outside workspace mode", len(modFiles))) panic(fmt.Errorf("requirementsFromModFiles called with %v modfiles outside workspace mode", len(modFiles)))
} }
modFile := modFiles[0] modFile := modFiles[0]
roots, direct = rootsFromModFile(LoaderState.MainModules.mustGetSingleMainModule(), modFile, withToolchainRoot) roots, direct = rootsFromModFile(loaderstate, loaderstate.MainModules.mustGetSingleMainModule(loaderstate), modFile, withToolchainRoot)
} }
gover.ModSort(roots) gover.ModSort(roots)
rs := newRequirements(pruning, roots, direct) rs := newRequirements(loaderstate, pruning, roots, direct)
return rs return rs
} }
@ -1428,7 +1428,7 @@ func directRequirements(modFiles []*modfile.File) map[string]bool {
return direct return direct
} }
func rootsFromModFile(m module.Version, modFile *modfile.File, addToolchainRoot addToolchainRoot) (roots []module.Version, direct map[string]bool) { func rootsFromModFile(loaderstate *State, m module.Version, modFile *modfile.File, addToolchainRoot addToolchainRoot) (roots []module.Version, direct map[string]bool) {
direct = make(map[string]bool) direct = make(map[string]bool)
padding := 2 // Add padding for the toolchain and go version, added upon return. padding := 2 // Add padding for the toolchain and go version, added upon return.
if !addToolchainRoot { if !addToolchainRoot {
@ -1436,7 +1436,7 @@ func rootsFromModFile(m module.Version, modFile *modfile.File, addToolchainRoot
} }
roots = make([]module.Version, 0, padding+len(modFile.Require)) roots = make([]module.Version, 0, padding+len(modFile.Require))
for _, r := range modFile.Require { for _, r := range modFile.Require {
if index := LoaderState.MainModules.Index(m); index != nil && index.exclude[r.Mod] { if index := loaderstate.MainModules.Index(m); index != nil && index.exclude[r.Mod] {
if cfg.BuildMod == "mod" { if cfg.BuildMod == "mod" {
fmt.Fprintf(os.Stderr, "go: dropping requirement on excluded version %s %s\n", r.Mod.Path, r.Mod.Version) fmt.Fprintf(os.Stderr, "go: dropping requirement on excluded version %s %s\n", r.Mod.Path, r.Mod.Version)
} else { } else {
@ -1477,9 +1477,9 @@ func appendGoAndToolchainRoots(roots []module.Version, goVersion, toolchain stri
// setDefaultBuildMod sets a default value for cfg.BuildMod if the -mod flag // setDefaultBuildMod sets a default value for cfg.BuildMod if the -mod flag
// wasn't provided. setDefaultBuildMod may be called multiple times. // wasn't provided. setDefaultBuildMod may be called multiple times.
func setDefaultBuildMod() { func setDefaultBuildMod(loaderstate *State) {
if cfg.BuildModExplicit { if cfg.BuildModExplicit {
if inWorkspaceMode() && cfg.BuildMod != "readonly" && cfg.BuildMod != "vendor" { if inWorkspaceMode(loaderstate) && cfg.BuildMod != "readonly" && cfg.BuildMod != "vendor" {
switch cfg.CmdName { switch cfg.CmdName {
case "work sync", "mod graph", "mod verify", "mod why": case "work sync", "mod graph", "mod verify", "mod why":
// These commands run with BuildMod set to mod, but they don't take the // These commands run with BuildMod set to mod, but they don't take the
@ -1514,7 +1514,7 @@ func setDefaultBuildMod() {
cfg.BuildMod = "readonly" cfg.BuildMod = "readonly"
return return
} }
if LoaderState.modRoots == nil { if loaderstate.modRoots == nil {
if allowMissingModuleImports { if allowMissingModuleImports {
cfg.BuildMod = "mod" cfg.BuildMod = "mod"
} else { } else {
@ -1523,29 +1523,29 @@ func setDefaultBuildMod() {
return return
} }
if len(LoaderState.modRoots) >= 1 { if len(loaderstate.modRoots) >= 1 {
var goVersion string var goVersion string
var versionSource string var versionSource string
if inWorkspaceMode() { if inWorkspaceMode(loaderstate) {
versionSource = "go.work" versionSource = "go.work"
if wfg := LoaderState.MainModules.WorkFile().Go; wfg != nil { if wfg := loaderstate.MainModules.WorkFile().Go; wfg != nil {
goVersion = wfg.Version goVersion = wfg.Version
} }
} else { } else {
versionSource = "go.mod" versionSource = "go.mod"
index := LoaderState.MainModules.GetSingleIndexOrNil() index := loaderstate.MainModules.GetSingleIndexOrNil(loaderstate)
if index != nil { if index != nil {
goVersion = index.goVersion goVersion = index.goVersion
} }
} }
vendorDir := "" vendorDir := ""
if LoaderState.workFilePath != "" { if loaderstate.workFilePath != "" {
vendorDir = filepath.Join(filepath.Dir(LoaderState.workFilePath), "vendor") vendorDir = filepath.Join(filepath.Dir(loaderstate.workFilePath), "vendor")
} else { } else {
if len(LoaderState.modRoots) != 1 { if len(loaderstate.modRoots) != 1 {
panic(fmt.Errorf("outside workspace mode, but have %v modRoots", LoaderState.modRoots)) panic(fmt.Errorf("outside workspace mode, but have %v modRoots", loaderstate.modRoots))
} }
vendorDir = filepath.Join(LoaderState.modRoots[0], "vendor") vendorDir = filepath.Join(loaderstate.modRoots[0], "vendor")
} }
if fi, err := fsys.Stat(vendorDir); err == nil && fi.IsDir() { if fi, err := fsys.Stat(vendorDir); err == nil && fi.IsDir() {
if goVersion != "" { if goVersion != "" {
@ -1613,8 +1613,8 @@ func modulesTextIsForWorkspace(vendorDir string) (bool, error) {
return false, nil return false, nil
} }
func mustHaveCompleteRequirements() bool { func mustHaveCompleteRequirements(loaderstate *State) bool {
return cfg.BuildMod != "mod" && !inWorkspaceMode() return cfg.BuildMod != "mod" && !inWorkspaceMode(loaderstate)
} }
// addGoStmt adds a go directive to the go.mod file if it does not already // addGoStmt adds a go directive to the go.mod file if it does not already
@ -1809,21 +1809,21 @@ type WriteOpts struct {
// WriteGoMod writes the current build list back to go.mod. // WriteGoMod writes the current build list back to go.mod.
func WriteGoMod(ctx context.Context, opts WriteOpts) error { func WriteGoMod(ctx context.Context, opts WriteOpts) error {
LoaderState.requirements = LoadModFile(ctx) LoaderState.requirements = LoadModFile(LoaderState, ctx)
return commitRequirements(ctx, opts) return commitRequirements(LoaderState, ctx, opts)
} }
var errNoChange = errors.New("no update needed") var errNoChange = errors.New("no update needed")
// UpdateGoModFromReqs returns a modified go.mod file using the current // UpdateGoModFromReqs returns a modified go.mod file using the current
// requirements. It does not commit these changes to disk. // requirements. It does not commit these changes to disk.
func UpdateGoModFromReqs(ctx context.Context, opts WriteOpts) (before, after []byte, modFile *modfile.File, err error) { func UpdateGoModFromReqs(loaderstate *State, ctx context.Context, opts WriteOpts) (before, after []byte, modFile *modfile.File, err error) {
if LoaderState.MainModules.Len() != 1 || LoaderState.MainModules.ModRoot(LoaderState.MainModules.Versions()[0]) == "" { if loaderstate.MainModules.Len() != 1 || loaderstate.MainModules.ModRoot(loaderstate.MainModules.Versions()[0]) == "" {
// We aren't in a module, so we don't have anywhere to write a go.mod file. // We aren't in a module, so we don't have anywhere to write a go.mod file.
return nil, nil, nil, errNoChange return nil, nil, nil, errNoChange
} }
mainModule := LoaderState.MainModules.mustGetSingleMainModule() mainModule := loaderstate.MainModules.mustGetSingleMainModule(loaderstate)
modFile = LoaderState.MainModules.ModFile(mainModule) modFile = loaderstate.MainModules.ModFile(mainModule)
if modFile == nil { if modFile == nil {
// command-line-arguments has no .mod file to write. // command-line-arguments has no .mod file to write.
return nil, nil, nil, errNoChange return nil, nil, nil, errNoChange
@ -1836,7 +1836,7 @@ func UpdateGoModFromReqs(ctx context.Context, opts WriteOpts) (before, after []b
var list []*modfile.Require var list []*modfile.Require
toolchain := "" toolchain := ""
goVersion := "" goVersion := ""
for _, m := range LoaderState.requirements.rootModules { for _, m := range loaderstate.requirements.rootModules {
if m.Path == "go" { if m.Path == "go" {
goVersion = m.Version goVersion = m.Version
continue continue
@ -1847,7 +1847,7 @@ func UpdateGoModFromReqs(ctx context.Context, opts WriteOpts) (before, after []b
} }
list = append(list, &modfile.Require{ list = append(list, &modfile.Require{
Mod: m, Mod: m,
Indirect: !LoaderState.requirements.direct[m.Path], Indirect: !loaderstate.requirements.direct[m.Path],
}) })
} }
@ -1917,13 +1917,13 @@ func UpdateGoModFromReqs(ctx context.Context, opts WriteOpts) (before, after []b
// go.mod or go.sum are out of date in a semantically significant way. // go.mod or go.sum are out of date in a semantically significant way.
// //
// In workspace mode, commitRequirements only writes changes to go.work.sum. // In workspace mode, commitRequirements only writes changes to go.work.sum.
func commitRequirements(ctx context.Context, opts WriteOpts) (err error) { func commitRequirements(loaderstate *State, ctx context.Context, opts WriteOpts) (err error) {
if inWorkspaceMode() { if inWorkspaceMode(loaderstate) {
// go.mod files aren't updated in workspace mode, but we still want to // go.mod files aren't updated in workspace mode, but we still want to
// update the go.work.sum file. // update the go.work.sum file.
return modfetch.WriteGoSum(ctx, keepSums(ctx, loaded, LoaderState.requirements, addBuildListZipSums), mustHaveCompleteRequirements()) return modfetch.WriteGoSum(ctx, keepSums(loaderstate, ctx, loaded, loaderstate.requirements, addBuildListZipSums), mustHaveCompleteRequirements(loaderstate))
} }
_, updatedGoMod, modFile, err := UpdateGoModFromReqs(ctx, opts) _, updatedGoMod, modFile, err := UpdateGoModFromReqs(loaderstate, ctx, opts)
if err != nil { if err != nil {
if errors.Is(err, errNoChange) { if errors.Is(err, errNoChange) {
return nil return nil
@ -1931,7 +1931,7 @@ func commitRequirements(ctx context.Context, opts WriteOpts) (err error) {
return err return err
} }
index := LoaderState.MainModules.GetSingleIndexOrNil() index := loaderstate.MainModules.GetSingleIndexOrNil(loaderstate)
dirty := index.modFileIsDirty(modFile) || len(opts.DropTools) > 0 || len(opts.AddTools) > 0 dirty := index.modFileIsDirty(modFile) || len(opts.DropTools) > 0 || len(opts.AddTools) > 0
if dirty && cfg.BuildMod != "mod" { if dirty && cfg.BuildMod != "mod" {
// If we're about to fail due to -mod=readonly, // If we're about to fail due to -mod=readonly,
@ -1945,15 +1945,15 @@ func commitRequirements(ctx context.Context, opts WriteOpts) (err error) {
// Don't write go.mod, but write go.sum in case we added or trimmed sums. // Don't write go.mod, but write go.sum in case we added or trimmed sums.
// 'go mod init' shouldn't write go.sum, since it will be incomplete. // 'go mod init' shouldn't write go.sum, since it will be incomplete.
if cfg.CmdName != "mod init" { if cfg.CmdName != "mod init" {
if err := modfetch.WriteGoSum(ctx, keepSums(ctx, loaded, LoaderState.requirements, addBuildListZipSums), mustHaveCompleteRequirements()); err != nil { if err := modfetch.WriteGoSum(ctx, keepSums(loaderstate, ctx, loaded, loaderstate.requirements, addBuildListZipSums), mustHaveCompleteRequirements(loaderstate)); err != nil {
return err return err
} }
} }
return nil return nil
} }
mainModule := LoaderState.MainModules.mustGetSingleMainModule() mainModule := loaderstate.MainModules.mustGetSingleMainModule(loaderstate)
modFilePath := modFilePath(LoaderState.MainModules.ModRoot(mainModule)) modFilePath := modFilePath(loaderstate.MainModules.ModRoot(mainModule))
if fsys.Replaced(modFilePath) { if fsys.Replaced(modFilePath) {
if dirty { if dirty {
return errors.New("updates to go.mod needed, but go.mod is part of the overlay specified with -overlay") return errors.New("updates to go.mod needed, but go.mod is part of the overlay specified with -overlay")
@ -1962,13 +1962,13 @@ func commitRequirements(ctx context.Context, opts WriteOpts) (err error) {
} }
defer func() { defer func() {
// At this point we have determined to make the go.mod file on disk equal to new. // At this point we have determined to make the go.mod file on disk equal to new.
LoaderState.MainModules.SetIndex(mainModule, indexModFile(updatedGoMod, modFile, mainModule, false)) loaderstate.MainModules.SetIndex(mainModule, indexModFile(updatedGoMod, modFile, mainModule, false))
// Update go.sum after releasing the side lock and refreshing the index. // Update go.sum after releasing the side lock and refreshing the index.
// 'go mod init' shouldn't write go.sum, since it will be incomplete. // 'go mod init' shouldn't write go.sum, since it will be incomplete.
if cfg.CmdName != "mod init" { if cfg.CmdName != "mod init" {
if err == nil { if err == nil {
err = modfetch.WriteGoSum(ctx, keepSums(ctx, loaded, LoaderState.requirements, addBuildListZipSums), mustHaveCompleteRequirements()) err = modfetch.WriteGoSum(ctx, keepSums(loaderstate, ctx, loaded, loaderstate.requirements, addBuildListZipSums), mustHaveCompleteRequirements(loaderstate))
} }
} }
}() }()
@ -2011,7 +2011,7 @@ func commitRequirements(ctx context.Context, opts WriteOpts) (err error) {
// including any go.mod files needed to reconstruct the MVS result // including any go.mod files needed to reconstruct the MVS result
// or identify go versions, // or identify go versions,
// in addition to the checksums for every module in keepMods. // in addition to the checksums for every module in keepMods.
func keepSums(ctx context.Context, ld *loader, rs *Requirements, which whichSums) map[module.Version]bool { func keepSums(loaderstate *State, ctx context.Context, ld *loader, rs *Requirements, which whichSums) map[module.Version]bool {
// Every module in the full module graph contributes its requirements, // Every module in the full module graph contributes its requirements,
// so in order to ensure that the build list itself is reproducible, // so in order to ensure that the build list itself is reproducible,
// we need sums for every go.mod in the graph (regardless of whether // we need sums for every go.mod in the graph (regardless of whether
@ -2024,12 +2024,12 @@ func keepSums(ctx context.Context, ld *loader, rs *Requirements, which whichSums
// ambiguous import errors the next time we load the package. // ambiguous import errors the next time we load the package.
keepModSumsForZipSums := true keepModSumsForZipSums := true
if ld == nil { if ld == nil {
if gover.Compare(LoaderState.MainModules.GoVersion(), gover.TidyGoModSumVersion) < 0 && cfg.BuildMod != "mod" { if gover.Compare(loaderstate.MainModules.GoVersion(loaderstate), gover.TidyGoModSumVersion) < 0 && cfg.BuildMod != "mod" {
keepModSumsForZipSums = false keepModSumsForZipSums = false
} }
} else { } else {
keepPkgGoModSums := true keepPkgGoModSums := true
if gover.Compare(ld.requirements.GoVersion(), gover.TidyGoModSumVersion) < 0 && (ld.Tidy || cfg.BuildMod != "mod") { if gover.Compare(ld.requirements.GoVersion(loaderstate), gover.TidyGoModSumVersion) < 0 && (ld.Tidy || cfg.BuildMod != "mod") {
keepPkgGoModSums = false keepPkgGoModSums = false
keepModSumsForZipSums = false keepModSumsForZipSums = false
} }
@ -2047,21 +2047,21 @@ func keepSums(ctx context.Context, ld *loader, rs *Requirements, which whichSums
// minor, so we maintain the previous (buggy) behavior in 'go mod tidy' to // minor, so we maintain the previous (buggy) behavior in 'go mod tidy' to
// avoid introducing unnecessary churn. // avoid introducing unnecessary churn.
if keepPkgGoModSums { if keepPkgGoModSums {
r := resolveReplacement(pkg.mod) r := resolveReplacement(loaderstate, pkg.mod)
keep[modkey(r)] = true keep[modkey(r)] = true
} }
if rs.pruning == pruned && pkg.mod.Path != "" { if rs.pruning == pruned && pkg.mod.Path != "" {
if v, ok := rs.rootSelected(pkg.mod.Path); ok && v == pkg.mod.Version { if v, ok := rs.rootSelected(loaderstate, pkg.mod.Path); ok && v == pkg.mod.Version {
// pkg was loaded from a root module, and because the main module has // pkg was loaded from a root module, and because the main module has
// a pruned module graph we do not check non-root modules for // a pruned module graph we do not check non-root modules for
// conflicts for packages that can be found in roots. So we only need // conflicts for packages that can be found in roots. So we only need
// the checksums for the root modules that may contain pkg, not all // the checksums for the root modules that may contain pkg, not all
// possible modules. // possible modules.
for prefix := pkg.path; prefix != "."; prefix = path.Dir(prefix) { for prefix := pkg.path; prefix != "."; prefix = path.Dir(prefix) {
if v, ok := rs.rootSelected(prefix); ok && v != "none" { if v, ok := rs.rootSelected(loaderstate, prefix); ok && v != "none" {
m := module.Version{Path: prefix, Version: v} m := module.Version{Path: prefix, Version: v}
r := resolveReplacement(m) r := resolveReplacement(loaderstate, m)
keep[r] = true keep[r] = true
} }
} }
@ -2069,11 +2069,11 @@ func keepSums(ctx context.Context, ld *loader, rs *Requirements, which whichSums
} }
} }
mg, _ := rs.Graph(ctx) mg, _ := rs.Graph(loaderstate, ctx)
for prefix := pkg.path; prefix != "."; prefix = path.Dir(prefix) { for prefix := pkg.path; prefix != "."; prefix = path.Dir(prefix) {
if v := mg.Selected(prefix); v != "none" { if v := mg.Selected(prefix); v != "none" {
m := module.Version{Path: prefix, Version: v} m := module.Version{Path: prefix, Version: v}
r := resolveReplacement(m) r := resolveReplacement(loaderstate, m)
keep[r] = true keep[r] = true
} }
} }
@ -2085,27 +2085,27 @@ func keepSums(ctx context.Context, ld *loader, rs *Requirements, which whichSums
// Save sums for the root modules (or their replacements), but don't // Save sums for the root modules (or their replacements), but don't
// incur the cost of loading the graph just to find and retain the sums. // incur the cost of loading the graph just to find and retain the sums.
for _, m := range rs.rootModules { for _, m := range rs.rootModules {
r := resolveReplacement(m) r := resolveReplacement(loaderstate, m)
keep[modkey(r)] = true keep[modkey(r)] = true
if which == addBuildListZipSums { if which == addBuildListZipSums {
keep[r] = true keep[r] = true
} }
} }
} else { } else {
mg, _ := rs.Graph(ctx) mg, _ := rs.Graph(loaderstate, ctx)
mg.WalkBreadthFirst(func(m module.Version) { mg.WalkBreadthFirst(func(m module.Version) {
if _, ok := mg.RequiredBy(m); ok { if _, ok := mg.RequiredBy(m); ok {
// The requirements from m's go.mod file are present in the module graph, // The requirements from m's go.mod file are present in the module graph,
// so they are relevant to the MVS result regardless of whether m was // so they are relevant to the MVS result regardless of whether m was
// actually selected. // actually selected.
r := resolveReplacement(m) r := resolveReplacement(loaderstate, m)
keep[modkey(r)] = true keep[modkey(r)] = true
} }
}) })
if which == addBuildListZipSums { if which == addBuildListZipSums {
for _, m := range mg.BuildList() { for _, m := range mg.BuildList() {
r := resolveReplacement(m) r := resolveReplacement(loaderstate, m)
if keepModSumsForZipSums { if keepModSumsForZipSums {
keep[modkey(r)] = true // we need the go version from the go.mod file to do anything useful with the zipfile keep[modkey(r)] = true // we need the go version from the go.mod file to do anything useful with the zipfile
} }

View file

@ -69,7 +69,7 @@ func ListModules(ctx context.Context, args []string, mode ListMode, reuseFile st
} }
} }
rs, mods, err := listModules(ctx, LoadModFile(ctx), args, mode, reuse) rs, mods, err := listModules(ctx, LoadModFile(LoaderState, ctx), args, mode, reuse)
type token struct{} type token struct{}
sem := make(chan token, runtime.GOMAXPROCS(0)) sem := make(chan token, runtime.GOMAXPROCS(0))
@ -88,7 +88,7 @@ func ListModules(ctx context.Context, args []string, mode ListMode, reuseFile st
addVersions(ctx, m, mode&ListRetractedVersions != 0) addVersions(ctx, m, mode&ListRetractedVersions != 0)
} }
if mode&ListRetracted != 0 { if mode&ListRetracted != 0 {
addRetraction(ctx, m) addRetraction(LoaderState, ctx, m)
} }
if mode&ListDeprecated != 0 { if mode&ListDeprecated != 0 {
addDeprecation(ctx, m) addDeprecation(ctx, m)
@ -117,7 +117,7 @@ func ListModules(ctx context.Context, args []string, mode ListMode, reuseFile st
// but in general list -u is looking up other checksums in the checksum database // but in general list -u is looking up other checksums in the checksum database
// that won't be necessary later, so it makes sense not to write the go.sum back out. // that won't be necessary later, so it makes sense not to write the go.sum back out.
if !ExplicitWriteGoMod && mode&ListU == 0 { if !ExplicitWriteGoMod && mode&ListU == 0 {
err = commitRequirements(ctx, WriteOpts{}) err = commitRequirements(LoaderState, ctx, WriteOpts{})
} }
} }
return mods, err return mods, err
@ -130,7 +130,7 @@ func listModules(ctx context.Context, rs *Requirements, args []string, mode List
if gover.IsToolchain(m.Path) { if gover.IsToolchain(m.Path) {
continue continue
} }
ms = append(ms, moduleInfo(ctx, rs, m, mode, reuse)) ms = append(ms, moduleInfo(LoaderState, ctx, rs, m, mode, reuse))
} }
return rs, ms, nil return rs, ms, nil
} }
@ -145,25 +145,25 @@ func listModules(ctx context.Context, rs *Requirements, args []string, mode List
} }
if arg == "all" || strings.Contains(arg, "...") { if arg == "all" || strings.Contains(arg, "...") {
needFullGraph = true needFullGraph = true
if !HasModRoot() { if !HasModRoot(LoaderState) {
base.Fatalf("go: cannot match %q: %v", arg, ErrNoModRoot) base.Fatalf("go: cannot match %q: %v", arg, ErrNoModRoot)
} }
continue continue
} }
if path, vers, found := strings.Cut(arg, "@"); found { if path, vers, found := strings.Cut(arg, "@"); found {
if vers == "upgrade" || vers == "patch" { if vers == "upgrade" || vers == "patch" {
if _, ok := rs.rootSelected(path); !ok || rs.pruning == unpruned { if _, ok := rs.rootSelected(LoaderState, path); !ok || rs.pruning == unpruned {
needFullGraph = true needFullGraph = true
if !HasModRoot() { if !HasModRoot(LoaderState) {
base.Fatalf("go: cannot match %q: %v", arg, ErrNoModRoot) base.Fatalf("go: cannot match %q: %v", arg, ErrNoModRoot)
} }
} }
} }
continue continue
} }
if _, ok := rs.rootSelected(arg); !ok || rs.pruning == unpruned { if _, ok := rs.rootSelected(LoaderState, arg); !ok || rs.pruning == unpruned {
needFullGraph = true needFullGraph = true
if mode&ListVersions == 0 && !HasModRoot() { if mode&ListVersions == 0 && !HasModRoot(LoaderState) {
base.Fatalf("go: cannot match %q without -versions or an explicit version: %v", arg, ErrNoModRoot) base.Fatalf("go: cannot match %q without -versions or an explicit version: %v", arg, ErrNoModRoot)
} }
} }
@ -171,7 +171,7 @@ func listModules(ctx context.Context, rs *Requirements, args []string, mode List
var mg *ModuleGraph var mg *ModuleGraph
if needFullGraph { if needFullGraph {
rs, mg, mgErr = expandGraph(ctx, rs) rs, mg, mgErr = expandGraph(LoaderState, ctx, rs)
} }
matchedModule := map[module.Version]bool{} matchedModule := map[module.Version]bool{}
@ -179,7 +179,7 @@ func listModules(ctx context.Context, rs *Requirements, args []string, mode List
if path, vers, found := strings.Cut(arg, "@"); found { if path, vers, found := strings.Cut(arg, "@"); found {
var current string var current string
if mg == nil { if mg == nil {
current, _ = rs.rootSelected(path) current, _ = rs.rootSelected(LoaderState, path)
} else { } else {
current = mg.Selected(path) current = mg.Selected(path)
} }
@ -198,7 +198,7 @@ func listModules(ctx context.Context, rs *Requirements, args []string, mode List
// specific revision or used 'go list -retracted'. // specific revision or used 'go list -retracted'.
allowed = nil allowed = nil
} }
info, err := queryReuse(ctx, path, vers, current, allowed, reuse) info, err := queryReuse(LoaderState, ctx, path, vers, current, allowed, reuse)
if err != nil { if err != nil {
var origin *codehost.Origin var origin *codehost.Origin
if info != nil { if info != nil {
@ -217,7 +217,7 @@ func listModules(ctx context.Context, rs *Requirements, args []string, mode List
// *Requirements instead. // *Requirements instead.
var noRS *Requirements var noRS *Requirements
mod := moduleInfo(ctx, noRS, module.Version{Path: path, Version: info.Version}, mode, reuse) mod := moduleInfo(LoaderState, ctx, noRS, module.Version{Path: path, Version: info.Version}, mode, reuse)
if vers != mod.Version { if vers != mod.Version {
mod.Query = vers mod.Query = vers
} }
@ -237,7 +237,7 @@ func listModules(ctx context.Context, rs *Requirements, args []string, mode List
var v string var v string
if mg == nil { if mg == nil {
var ok bool var ok bool
v, ok = rs.rootSelected(arg) v, ok = rs.rootSelected(LoaderState, arg)
if !ok { if !ok {
// We checked rootSelected(arg) in the earlier args loop, so if there // We checked rootSelected(arg) in the earlier args loop, so if there
// is no such root we should have loaded a non-nil mg. // is no such root we should have loaded a non-nil mg.
@ -251,7 +251,7 @@ func listModules(ctx context.Context, rs *Requirements, args []string, mode List
continue continue
} }
if v != "none" { if v != "none" {
mods = append(mods, moduleInfo(ctx, rs, module.Version{Path: arg, Version: v}, mode, reuse)) mods = append(mods, moduleInfo(LoaderState, ctx, rs, module.Version{Path: arg, Version: v}, mode, reuse))
} else if cfg.BuildMod == "vendor" { } else if cfg.BuildMod == "vendor" {
// In vendor mode, we can't determine whether a missing module is “a // In vendor mode, we can't determine whether a missing module is “a
// known dependency” because the module graph is incomplete. // known dependency” because the module graph is incomplete.
@ -292,7 +292,7 @@ func listModules(ctx context.Context, rs *Requirements, args []string, mode List
fetchedMods := make([]*modinfo.ModulePublic, len(matches)) fetchedMods := make([]*modinfo.ModulePublic, len(matches))
for i, m := range matches { for i, m := range matches {
q.Add(func() { q.Add(func() {
fetchedMods[i] = moduleInfo(ctx, rs, m, mode, reuse) fetchedMods[i] = moduleInfo(LoaderState, ctx, rs, m, mode, reuse)
}) })
} }
<-q.Idle() <-q.Idle()

View file

@ -250,7 +250,7 @@ type PackageOpts struct {
// LoadPackages identifies the set of packages matching the given patterns and // LoadPackages identifies the set of packages matching the given patterns and
// loads the packages in the import graph rooted at that set. // loads the packages in the import graph rooted at that set.
func LoadPackages(ctx context.Context, opts PackageOpts, patterns ...string) (matches []*search.Match, loadedPackages []string) { func LoadPackages(loaderstate *State, ctx context.Context, opts PackageOpts, patterns ...string) (matches []*search.Match, loadedPackages []string) {
if opts.Tags == nil { if opts.Tags == nil {
opts.Tags = imports.Tags() opts.Tags = imports.Tags()
} }
@ -271,11 +271,11 @@ func LoadPackages(ctx context.Context, opts PackageOpts, patterns ...string) (ma
case m.IsLocal(): case m.IsLocal():
// Evaluate list of file system directories on first iteration. // Evaluate list of file system directories on first iteration.
if m.Dirs == nil { if m.Dirs == nil {
matchModRoots := LoaderState.modRoots matchModRoots := loaderstate.modRoots
if opts.MainModule != (module.Version{}) { if opts.MainModule != (module.Version{}) {
matchModRoots = []string{LoaderState.MainModules.ModRoot(opts.MainModule)} matchModRoots = []string{loaderstate.MainModules.ModRoot(opts.MainModule)}
} }
matchLocalDirs(ctx, matchModRoots, m, rs) matchLocalDirs(loaderstate, ctx, matchModRoots, m, rs)
} }
// Make a copy of the directory list and translate to import paths. // Make a copy of the directory list and translate to import paths.
@ -286,7 +286,7 @@ func LoadPackages(ctx context.Context, opts PackageOpts, patterns ...string) (ma
// the loader iterations. // the loader iterations.
m.Pkgs = m.Pkgs[:0] m.Pkgs = m.Pkgs[:0]
for _, dir := range m.Dirs { for _, dir := range m.Dirs {
pkg, err := resolveLocalPackage(ctx, dir, rs) pkg, err := resolveLocalPackage(loaderstate, ctx, dir, rs)
if err != nil { if err != nil {
if !m.IsLiteral() && (err == errPkgIsBuiltin || err == errPkgIsGorootSrc) { if !m.IsLiteral() && (err == errPkgIsBuiltin || err == errPkgIsGorootSrc) {
continue // Don't include "builtin" or GOROOT/src in wildcard patterns. continue // Don't include "builtin" or GOROOT/src in wildcard patterns.
@ -294,8 +294,8 @@ func LoadPackages(ctx context.Context, opts PackageOpts, patterns ...string) (ma
// If we're outside of a module, ensure that the failure mode // If we're outside of a module, ensure that the failure mode
// indicates that. // indicates that.
if !HasModRoot() { if !HasModRoot(loaderstate) {
die() die(loaderstate)
} }
if ld != nil { if ld != nil {
@ -311,7 +311,7 @@ func LoadPackages(ctx context.Context, opts PackageOpts, patterns ...string) (ma
case strings.Contains(m.Pattern(), "..."): case strings.Contains(m.Pattern(), "..."):
m.Errs = m.Errs[:0] m.Errs = m.Errs[:0]
mg, err := rs.Graph(ctx) mg, err := rs.Graph(loaderstate, ctx)
if err != nil { if err != nil {
// The module graph is (or may be) incomplete — perhaps we failed to // The module graph is (or may be) incomplete — perhaps we failed to
// load the requirements of some module. This is an error in matching // load the requirements of some module. This is an error in matching
@ -321,26 +321,26 @@ func LoadPackages(ctx context.Context, opts PackageOpts, patterns ...string) (ma
// necessarily prevent us from loading the packages we could find. // necessarily prevent us from loading the packages we could find.
m.Errs = append(m.Errs, err) m.Errs = append(m.Errs, err)
} }
matchPackages(ctx, m, opts.Tags, includeStd, mg.BuildList()) matchPackages(loaderstate, ctx, m, opts.Tags, includeStd, mg.BuildList())
case m.Pattern() == "work": case m.Pattern() == "work":
matchModules := LoaderState.MainModules.Versions() matchModules := loaderstate.MainModules.Versions()
if opts.MainModule != (module.Version{}) { if opts.MainModule != (module.Version{}) {
matchModules = []module.Version{opts.MainModule} matchModules = []module.Version{opts.MainModule}
} }
matchPackages(ctx, m, opts.Tags, omitStd, matchModules) matchPackages(loaderstate, ctx, m, opts.Tags, omitStd, matchModules)
case m.Pattern() == "all": case m.Pattern() == "all":
if ld == nil { if ld == nil {
// The initial roots are the packages and tools in the main module. // The initial roots are the packages and tools in the main module.
// loadFromRoots will expand that to "all". // loadFromRoots will expand that to "all".
m.Errs = m.Errs[:0] m.Errs = m.Errs[:0]
matchModules := LoaderState.MainModules.Versions() matchModules := loaderstate.MainModules.Versions()
if opts.MainModule != (module.Version{}) { if opts.MainModule != (module.Version{}) {
matchModules = []module.Version{opts.MainModule} matchModules = []module.Version{opts.MainModule}
} }
matchPackages(ctx, m, opts.Tags, omitStd, matchModules) matchPackages(loaderstate, ctx, m, opts.Tags, omitStd, matchModules)
for tool := range LoaderState.MainModules.Tools() { for tool := range loaderstate.MainModules.Tools() {
m.Pkgs = append(m.Pkgs, tool) m.Pkgs = append(m.Pkgs, tool)
} }
} else { } else {
@ -355,7 +355,7 @@ func LoadPackages(ctx context.Context, opts PackageOpts, patterns ...string) (ma
} }
case m.Pattern() == "tool": case m.Pattern() == "tool":
for tool := range LoaderState.MainModules.Tools() { for tool := range loaderstate.MainModules.Tools() {
m.Pkgs = append(m.Pkgs, tool) m.Pkgs = append(m.Pkgs, tool)
} }
default: default:
@ -364,12 +364,12 @@ func LoadPackages(ctx context.Context, opts PackageOpts, patterns ...string) (ma
} }
} }
initialRS, err := loadModFile(ctx, &opts) initialRS, err := loadModFile(loaderstate, ctx, &opts)
if err != nil { if err != nil {
base.Fatal(err) base.Fatal(err)
} }
ld := loadFromRoots(ctx, loaderParams{ ld := loadFromRoots(loaderstate, ctx, loaderParams{
PackageOpts: opts, PackageOpts: opts,
requirements: initialRS, requirements: initialRS,
@ -404,7 +404,7 @@ func LoadPackages(ctx context.Context, opts PackageOpts, patterns ...string) (ma
if opts.Tidy { if opts.Tidy {
if cfg.BuildV { if cfg.BuildV {
mg, _ := ld.requirements.Graph(ctx) mg, _ := ld.requirements.Graph(loaderstate, ctx)
for _, m := range initialRS.rootModules { for _, m := range initialRS.rootModules {
var unused bool var unused bool
if ld.requirements.pruning == unpruned { if ld.requirements.pruning == unpruned {
@ -416,7 +416,7 @@ func LoadPackages(ctx context.Context, opts PackageOpts, patterns ...string) (ma
// m is unused if it was dropped from the roots. If it is still present // m is unused if it was dropped from the roots. If it is still present
// as a transitive dependency, that transitive dependency is not needed // as a transitive dependency, that transitive dependency is not needed
// by any package or test in the main module. // by any package or test in the main module.
_, ok := ld.requirements.rootSelected(m.Path) _, ok := ld.requirements.rootSelected(loaderstate, m.Path)
unused = !ok unused = !ok
} }
if unused { if unused {
@ -425,9 +425,9 @@ func LoadPackages(ctx context.Context, opts PackageOpts, patterns ...string) (ma
} }
} }
keep := keepSums(ctx, ld, ld.requirements, loadedZipSumsOnly) keep := keepSums(loaderstate, ctx, ld, ld.requirements, loadedZipSumsOnly)
compatVersion := ld.TidyCompatibleVersion compatVersion := ld.TidyCompatibleVersion
goVersion := ld.requirements.GoVersion() goVersion := ld.requirements.GoVersion(loaderstate)
if compatVersion == "" { if compatVersion == "" {
if gover.Compare(goVersion, gover.GoStrictVersion) < 0 { if gover.Compare(goVersion, gover.GoStrictVersion) < 0 {
compatVersion = gover.Prev(goVersion) compatVersion = gover.Prev(goVersion)
@ -444,10 +444,10 @@ func LoadPackages(ctx context.Context, opts PackageOpts, patterns ...string) (ma
compatVersion = goVersion compatVersion = goVersion
} }
if compatPruning := pruningForGoVersion(compatVersion); compatPruning != ld.requirements.pruning { if compatPruning := pruningForGoVersion(compatVersion); compatPruning != ld.requirements.pruning {
compatRS := newRequirements(compatPruning, ld.requirements.rootModules, ld.requirements.direct) compatRS := newRequirements(loaderstate, compatPruning, ld.requirements.rootModules, ld.requirements.direct)
ld.checkTidyCompatibility(ctx, compatRS, compatVersion) ld.checkTidyCompatibility(loaderstate, ctx, compatRS, compatVersion)
for m := range keepSums(ctx, ld, compatRS, loadedZipSumsOnly) { for m := range keepSums(loaderstate, ctx, ld, compatRS, loadedZipSumsOnly) {
keep[m] = true keep[m] = true
} }
} }
@ -455,8 +455,8 @@ func LoadPackages(ctx context.Context, opts PackageOpts, patterns ...string) (ma
if opts.TidyDiff { if opts.TidyDiff {
cfg.BuildMod = "readonly" cfg.BuildMod = "readonly"
loaded = ld loaded = ld
LoaderState.requirements = loaded.requirements loaderstate.requirements = loaded.requirements
currentGoMod, updatedGoMod, _, err := UpdateGoModFromReqs(ctx, WriteOpts{}) currentGoMod, updatedGoMod, _, err := UpdateGoModFromReqs(loaderstate, ctx, WriteOpts{})
if err != nil { if err != nil {
base.Fatal(err) base.Fatal(err)
} }
@ -466,7 +466,7 @@ func LoadPackages(ctx context.Context, opts PackageOpts, patterns ...string) (ma
// Dropping compatibility for 1.16 may result in a strictly smaller go.sum. // Dropping compatibility for 1.16 may result in a strictly smaller go.sum.
// Update the keep map with only the loaded.requirements. // Update the keep map with only the loaded.requirements.
if gover.Compare(compatVersion, "1.16") > 0 { if gover.Compare(compatVersion, "1.16") > 0 {
keep = keepSums(ctx, loaded, LoaderState.requirements, addBuildListZipSums) keep = keepSums(loaderstate, ctx, loaded, loaderstate.requirements, addBuildListZipSums)
} }
currentGoSum, tidyGoSum := modfetch.TidyGoSum(keep) currentGoSum, tidyGoSum := modfetch.TidyGoSum(keep)
goSumDiff := diff.Diff("current/go.sum", currentGoSum, "tidy/go.sum", tidyGoSum) goSumDiff := diff.Diff("current/go.sum", currentGoSum, "tidy/go.sum", tidyGoSum)
@ -490,7 +490,7 @@ func LoadPackages(ctx context.Context, opts PackageOpts, patterns ...string) (ma
// loaded.requirements, but here we may have also loaded (and want to // loaded.requirements, but here we may have also loaded (and want to
// preserve checksums for) additional entities from compatRS, which are // preserve checksums for) additional entities from compatRS, which are
// only needed for compatibility with ld.TidyCompatibleVersion. // only needed for compatibility with ld.TidyCompatibleVersion.
if err := modfetch.WriteGoSum(ctx, keep, mustHaveCompleteRequirements()); err != nil { if err := modfetch.WriteGoSum(ctx, keep, mustHaveCompleteRequirements(loaderstate)); err != nil {
base.Fatal(err) base.Fatal(err)
} }
} }
@ -505,7 +505,7 @@ func LoadPackages(ctx context.Context, opts PackageOpts, patterns ...string) (ma
// to call WriteGoMod itself) or if ResolveMissingImports is false (the // to call WriteGoMod itself) or if ResolveMissingImports is false (the
// command wants to examine the package graph as-is). // command wants to examine the package graph as-is).
loaded = ld loaded = ld
LoaderState.requirements = loaded.requirements loaderstate.requirements = loaded.requirements
for _, pkg := range ld.pkgs { for _, pkg := range ld.pkgs {
if !pkg.isTest() { if !pkg.isTest() {
@ -515,7 +515,7 @@ func LoadPackages(ctx context.Context, opts PackageOpts, patterns ...string) (ma
sort.Strings(loadedPackages) sort.Strings(loadedPackages)
if !ExplicitWriteGoMod && opts.ResolveMissingImports { if !ExplicitWriteGoMod && opts.ResolveMissingImports {
if err := commitRequirements(ctx, WriteOpts{}); err != nil { if err := commitRequirements(loaderstate, ctx, WriteOpts{}); err != nil {
base.Fatal(err) base.Fatal(err)
} }
} }
@ -525,7 +525,7 @@ func LoadPackages(ctx context.Context, opts PackageOpts, patterns ...string) (ma
// matchLocalDirs is like m.MatchDirs, but tries to avoid scanning directories // matchLocalDirs is like m.MatchDirs, but tries to avoid scanning directories
// outside of the standard library and active modules. // outside of the standard library and active modules.
func matchLocalDirs(ctx context.Context, modRoots []string, m *search.Match, rs *Requirements) { func matchLocalDirs(loaderstate *State, ctx context.Context, modRoots []string, m *search.Match, rs *Requirements) {
if !m.IsLocal() { if !m.IsLocal() {
panic(fmt.Sprintf("internal error: resolveLocalDirs on non-local pattern %s", m.Pattern())) panic(fmt.Sprintf("internal error: resolveLocalDirs on non-local pattern %s", m.Pattern()))
} }
@ -543,10 +543,10 @@ func matchLocalDirs(ctx context.Context, modRoots []string, m *search.Match, rs
} }
modRoot := findModuleRoot(absDir) modRoot := findModuleRoot(absDir)
if !slices.Contains(modRoots, modRoot) && search.InDir(absDir, cfg.GOROOTsrc) == "" && pathInModuleCache(ctx, absDir, rs) == "" { if !slices.Contains(modRoots, modRoot) && search.InDir(absDir, cfg.GOROOTsrc) == "" && pathInModuleCache(loaderstate, ctx, absDir, rs) == "" {
m.Dirs = []string{} m.Dirs = []string{}
scope := "main module or its selected dependencies" scope := "main module or its selected dependencies"
if inWorkspaceMode() { if inWorkspaceMode(loaderstate) {
scope = "modules listed in go.work or their selected dependencies" scope = "modules listed in go.work or their selected dependencies"
} }
m.AddError(fmt.Errorf("directory prefix %s does not contain %s", base.ShortPath(absDir), scope)) m.AddError(fmt.Errorf("directory prefix %s does not contain %s", base.ShortPath(absDir), scope))
@ -558,7 +558,7 @@ func matchLocalDirs(ctx context.Context, modRoots []string, m *search.Match, rs
} }
// resolveLocalPackage resolves a filesystem path to a package path. // resolveLocalPackage resolves a filesystem path to a package path.
func resolveLocalPackage(ctx context.Context, dir string, rs *Requirements) (string, error) { func resolveLocalPackage(loaderstate *State, ctx context.Context, dir string, rs *Requirements) (string, error) {
var absDir string var absDir string
if filepath.IsAbs(dir) { if filepath.IsAbs(dir) {
absDir = filepath.Clean(dir) absDir = filepath.Clean(dir)
@ -596,13 +596,13 @@ func resolveLocalPackage(ctx context.Context, dir string, rs *Requirements) (str
} }
} }
for _, mod := range LoaderState.MainModules.Versions() { for _, mod := range loaderstate.MainModules.Versions() {
modRoot := LoaderState.MainModules.ModRoot(mod) modRoot := loaderstate.MainModules.ModRoot(mod)
if modRoot != "" && absDir == modRoot { if modRoot != "" && absDir == modRoot {
if absDir == cfg.GOROOTsrc { if absDir == cfg.GOROOTsrc {
return "", errPkgIsGorootSrc return "", errPkgIsGorootSrc
} }
return LoaderState.MainModules.PathPrefix(mod), nil return loaderstate.MainModules.PathPrefix(mod), nil
} }
} }
@ -611,8 +611,8 @@ func resolveLocalPackage(ctx context.Context, dir string, rs *Requirements) (str
// It's not strictly necessary but helpful to keep the checks. // It's not strictly necessary but helpful to keep the checks.
var pkgNotFoundErr error var pkgNotFoundErr error
pkgNotFoundLongestPrefix := "" pkgNotFoundLongestPrefix := ""
for _, mainModule := range LoaderState.MainModules.Versions() { for _, mainModule := range loaderstate.MainModules.Versions() {
modRoot := LoaderState.MainModules.ModRoot(mainModule) modRoot := loaderstate.MainModules.ModRoot(mainModule)
if modRoot != "" && str.HasFilePathPrefix(absDir, modRoot) && !strings.Contains(absDir[len(modRoot):], "@") { if modRoot != "" && str.HasFilePathPrefix(absDir, modRoot) && !strings.Contains(absDir[len(modRoot):], "@") {
suffix := filepath.ToSlash(str.TrimFilePathPrefix(absDir, modRoot)) suffix := filepath.ToSlash(str.TrimFilePathPrefix(absDir, modRoot))
if pkg, found := strings.CutPrefix(suffix, "vendor/"); found { if pkg, found := strings.CutPrefix(suffix, "vendor/"); found {
@ -620,14 +620,14 @@ func resolveLocalPackage(ctx context.Context, dir string, rs *Requirements) (str
return "", fmt.Errorf("without -mod=vendor, directory %s has no package path", absDir) return "", fmt.Errorf("without -mod=vendor, directory %s has no package path", absDir)
} }
readVendorList(VendorDir()) readVendorList(VendorDir(loaderstate))
if _, ok := vendorPkgModule[pkg]; !ok { if _, ok := vendorPkgModule[pkg]; !ok {
return "", fmt.Errorf("directory %s is not a package listed in vendor/modules.txt", absDir) return "", fmt.Errorf("directory %s is not a package listed in vendor/modules.txt", absDir)
} }
return pkg, nil return pkg, nil
} }
mainModulePrefix := LoaderState.MainModules.PathPrefix(mainModule) mainModulePrefix := loaderstate.MainModules.PathPrefix(mainModule)
if mainModulePrefix == "" { if mainModulePrefix == "" {
pkg := suffix pkg := suffix
if pkg == "builtin" { if pkg == "builtin" {
@ -668,13 +668,13 @@ func resolveLocalPackage(ctx context.Context, dir string, rs *Requirements) (str
return pkg, nil return pkg, nil
} }
pkg := pathInModuleCache(ctx, absDir, rs) pkg := pathInModuleCache(loaderstate, ctx, absDir, rs)
if pkg == "" { if pkg == "" {
dirstr := fmt.Sprintf("directory %s", base.ShortPath(absDir)) dirstr := fmt.Sprintf("directory %s", base.ShortPath(absDir))
if dirstr == "directory ." { if dirstr == "directory ." {
dirstr = "current directory" dirstr = "current directory"
} }
if inWorkspaceMode() { if inWorkspaceMode(loaderstate) {
if mr := findModuleRoot(absDir); mr != "" { if mr := findModuleRoot(absDir); mr != "" {
return "", fmt.Errorf("%s is contained in a module that is not one of the workspace modules listed in go.work. You can add the module to the workspace using:\n\tgo work use %s", dirstr, base.ShortPath(mr)) return "", fmt.Errorf("%s is contained in a module that is not one of the workspace modules listed in go.work. You can add the module to the workspace using:\n\tgo work use %s", dirstr, base.ShortPath(mr))
} }
@ -693,17 +693,17 @@ var (
// pathInModuleCache returns the import path of the directory dir, // pathInModuleCache returns the import path of the directory dir,
// if dir is in the module cache copy of a module in our build list. // if dir is in the module cache copy of a module in our build list.
func pathInModuleCache(ctx context.Context, dir string, rs *Requirements) string { func pathInModuleCache(loaderstate *State, ctx context.Context, dir string, rs *Requirements) string {
tryMod := func(m module.Version) (string, bool) { tryMod := func(m module.Version) (string, bool) {
if gover.IsToolchain(m.Path) { if gover.IsToolchain(m.Path) {
return "", false return "", false
} }
var root string var root string
var err error var err error
if repl := Replacement(m); repl.Path != "" && repl.Version == "" { if repl := Replacement(loaderstate, m); repl.Path != "" && repl.Version == "" {
root = repl.Path root = repl.Path
if !filepath.IsAbs(root) { if !filepath.IsAbs(root) {
root = filepath.Join(replaceRelativeTo(), root) root = filepath.Join(replaceRelativeTo(loaderstate), root)
} }
} else if repl.Path != "" { } else if repl.Path != "" {
root, err = modfetch.DownloadDir(ctx, repl) root, err = modfetch.DownloadDir(ctx, repl)
@ -728,7 +728,7 @@ func pathInModuleCache(ctx context.Context, dir string, rs *Requirements) string
if rs.pruning == pruned { if rs.pruning == pruned {
for _, m := range rs.rootModules { for _, m := range rs.rootModules {
if v, _ := rs.rootSelected(m.Path); v != m.Version { if v, _ := rs.rootSelected(loaderstate, m.Path); v != m.Version {
continue // m is a root, but we have a higher root for the same path. continue // m is a root, but we have a higher root for the same path.
} }
if importPath, ok := tryMod(m); ok { if importPath, ok := tryMod(m); ok {
@ -747,7 +747,7 @@ func pathInModuleCache(ctx context.Context, dir string, rs *Requirements) string
// versions of root modules may differ from what we already checked above. // versions of root modules may differ from what we already checked above.
// Re-check those paths too. // Re-check those paths too.
mg, _ := rs.Graph(ctx) mg, _ := rs.Graph(loaderstate, ctx)
var importPath string var importPath string
for _, m := range mg.BuildList() { for _, m := range mg.BuildList() {
var found bool var found bool
@ -766,8 +766,8 @@ func pathInModuleCache(ctx context.Context, dir string, rs *Requirements) string
// //
// TODO(bcmills): Silencing errors seems off. Take a closer look at this and // TODO(bcmills): Silencing errors seems off. Take a closer look at this and
// figure out what the error-reporting actually ought to be. // figure out what the error-reporting actually ought to be.
func ImportFromFiles(ctx context.Context, gofiles []string) { func ImportFromFiles(loaderstate *State, ctx context.Context, gofiles []string) {
rs := LoadModFile(ctx) rs := LoadModFile(loaderstate, ctx)
tags := imports.Tags() tags := imports.Tags()
imports, testImports, err := imports.ScanFiles(gofiles, tags) imports, testImports, err := imports.ScanFiles(gofiles, tags)
@ -775,7 +775,7 @@ func ImportFromFiles(ctx context.Context, gofiles []string) {
base.Fatal(err) base.Fatal(err)
} }
loaded = loadFromRoots(ctx, loaderParams{ loaded = loadFromRoots(loaderstate, ctx, loaderParams{
PackageOpts: PackageOpts{ PackageOpts: PackageOpts{
Tags: tags, Tags: tags,
ResolveMissingImports: true, ResolveMissingImports: true,
@ -788,10 +788,10 @@ func ImportFromFiles(ctx context.Context, gofiles []string) {
return roots return roots
}, },
}) })
LoaderState.requirements = loaded.requirements loaderstate.requirements = loaded.requirements
if !ExplicitWriteGoMod { if !ExplicitWriteGoMod {
if err := commitRequirements(ctx, WriteOpts{}); err != nil { if err := commitRequirements(loaderstate, ctx, WriteOpts{}); err != nil {
base.Fatal(err) base.Fatal(err)
} }
} }
@ -799,11 +799,11 @@ func ImportFromFiles(ctx context.Context, gofiles []string) {
// DirImportPath returns the effective import path for dir, // DirImportPath returns the effective import path for dir,
// provided it is within a main module, or else returns ".". // provided it is within a main module, or else returns ".".
func (mms *MainModuleSet) DirImportPath(ctx context.Context, dir string) (path string, m module.Version) { func (mms *MainModuleSet) DirImportPath(loaderstate *State, ctx context.Context, dir string) (path string, m module.Version) {
if !HasModRoot() { if !HasModRoot(loaderstate) {
return ".", module.Version{} return ".", module.Version{}
} }
LoadModFile(ctx) // Sets targetPrefix. LoadModFile(loaderstate, ctx) // Sets targetPrefix.
if !filepath.IsAbs(dir) { if !filepath.IsAbs(dir) {
dir = filepath.Join(base.Cwd(), dir) dir = filepath.Join(base.Cwd(), dir)
@ -820,7 +820,7 @@ func (mms *MainModuleSet) DirImportPath(ctx context.Context, dir string) (path s
return mms.PathPrefix(v), v return mms.PathPrefix(v), v
} }
if str.HasFilePathPrefix(dir, modRoot) { if str.HasFilePathPrefix(dir, modRoot) {
pathPrefix := LoaderState.MainModules.PathPrefix(v) pathPrefix := loaderstate.MainModules.PathPrefix(v)
if pathPrefix > longestPrefix { if pathPrefix > longestPrefix {
longestPrefix = pathPrefix longestPrefix = pathPrefix
longestPrefixVersion = v longestPrefixVersion = v
@ -853,13 +853,13 @@ func PackageModule(path string) module.Version {
// the package at path as imported from the package in parentDir. // the package at path as imported from the package in parentDir.
// Lookup requires that one of the Load functions in this package has already // Lookup requires that one of the Load functions in this package has already
// been called. // been called.
func Lookup(parentPath string, parentIsStd bool, path string) (dir, realPath string, err error) { func Lookup(loaderstate *State, parentPath string, parentIsStd bool, path string) (dir, realPath string, err error) {
if path == "" { if path == "" {
panic("Lookup called with empty package path") panic("Lookup called with empty package path")
} }
if parentIsStd { if parentIsStd {
path = loaded.stdVendor(parentPath, path) path = loaded.stdVendor(loaderstate, parentPath, path)
} }
pkg, ok := loaded.pkgCache.Get(path) pkg, ok := loaded.pkgCache.Get(path)
if !ok { if !ok {
@ -957,11 +957,11 @@ func (ld *loader) exitIfErrors(ctx context.Context) {
// goVersion reports the Go version that should be used for the loader's // goVersion reports the Go version that should be used for the loader's
// requirements: ld.TidyGoVersion if set, or ld.requirements.GoVersion() // requirements: ld.TidyGoVersion if set, or ld.requirements.GoVersion()
// otherwise. // otherwise.
func (ld *loader) goVersion() string { func (ld *loader) goVersion(loaderstate *State) string {
if ld.TidyGoVersion != "" { if ld.TidyGoVersion != "" {
return ld.TidyGoVersion return ld.TidyGoVersion
} }
return ld.requirements.GoVersion() return ld.requirements.GoVersion(loaderstate)
} }
// A loadPkg records information about a single loaded package. // A loadPkg records information about a single loaded package.
@ -1064,11 +1064,11 @@ func (pkg *loadPkg) isTest() bool {
// fromExternalModule reports whether pkg was loaded from a module other than // fromExternalModule reports whether pkg was loaded from a module other than
// the main module. // the main module.
func (pkg *loadPkg) fromExternalModule() bool { func (pkg *loadPkg) fromExternalModule(loaderstate *State) bool {
if pkg.mod.Path == "" { if pkg.mod.Path == "" {
return false // loaded from the standard library, not a module return false // loaded from the standard library, not a module
} }
return !LoaderState.MainModules.Contains(pkg.mod.Path) return !loaderstate.MainModules.Contains(pkg.mod.Path)
} }
var errMissing = errors.New("cannot find package") var errMissing = errors.New("cannot find package")
@ -1079,7 +1079,7 @@ var errMissing = errors.New("cannot find package")
// The set of root packages is returned by the params.listRoots function, and // The set of root packages is returned by the params.listRoots function, and
// expanded to the full set of packages by tracing imports (and possibly tests) // expanded to the full set of packages by tracing imports (and possibly tests)
// as needed. // as needed.
func loadFromRoots(ctx context.Context, params loaderParams) *loader { func loadFromRoots(loaderstate *State, ctx context.Context, params loaderParams) *loader {
ld := &loader{ ld := &loader{
loaderParams: params, loaderParams: params,
work: par.NewQueue(runtime.GOMAXPROCS(0)), work: par.NewQueue(runtime.GOMAXPROCS(0)),
@ -1095,7 +1095,7 @@ func loadFromRoots(ctx context.Context, params loaderParams) *loader {
// spot-checks in modules that do not maintain the expanded go.mod // spot-checks in modules that do not maintain the expanded go.mod
// requirements needed for graph pruning. // requirements needed for graph pruning.
var err error var err error
ld.requirements, _, err = expandGraph(ctx, ld.requirements) ld.requirements, _, err = expandGraph(loaderstate, ctx, ld.requirements)
if err != nil { if err != nil {
ld.error(err) ld.error(err)
} }
@ -1103,11 +1103,11 @@ func loadFromRoots(ctx context.Context, params loaderParams) *loader {
ld.exitIfErrors(ctx) ld.exitIfErrors(ctx)
updateGoVersion := func() { updateGoVersion := func() {
goVersion := ld.goVersion() goVersion := ld.goVersion(loaderstate)
if ld.requirements.pruning != workspace { if ld.requirements.pruning != workspace {
var err error var err error
ld.requirements, err = convertPruning(ctx, ld.requirements, pruningForGoVersion(goVersion)) ld.requirements, err = convertPruning(loaderstate, ctx, ld.requirements, pruningForGoVersion(goVersion))
if err != nil { if err != nil {
ld.error(err) ld.error(err)
ld.exitIfErrors(ctx) ld.exitIfErrors(ctx)
@ -1141,7 +1141,7 @@ func loadFromRoots(ctx context.Context, params loaderParams) *loader {
// set of root packages does not change then we can select the correct // set of root packages does not change then we can select the correct
// versions of all transitive imports on the first try and complete // versions of all transitive imports on the first try and complete
// loading in a single iteration. // loading in a single iteration.
changedBuildList := ld.preloadRootModules(ctx, rootPkgs) changedBuildList := ld.preloadRootModules(loaderstate, ctx, rootPkgs)
if changedBuildList { if changedBuildList {
// The build list has changed, so the set of root packages may have also // The build list has changed, so the set of root packages may have also
// changed. Start over to pick up the changes. (Preloading roots is much // changed. Start over to pick up the changes. (Preloading roots is much
@ -1154,7 +1154,7 @@ func loadFromRoots(ctx context.Context, params loaderParams) *loader {
inRoots := map[*loadPkg]bool{} inRoots := map[*loadPkg]bool{}
for _, path := range rootPkgs { for _, path := range rootPkgs {
root := ld.pkg(ctx, path, pkgIsRoot) root := ld.pkg(loaderstate, ctx, path, pkgIsRoot)
if !inRoots[root] { if !inRoots[root] {
ld.roots = append(ld.roots, root) ld.roots = append(ld.roots, root)
inRoots[root] = true inRoots[root] = true
@ -1170,7 +1170,7 @@ func loadFromRoots(ctx context.Context, params loaderParams) *loader {
ld.buildStacks() ld.buildStacks()
changed, err := ld.updateRequirements(ctx) changed, err := ld.updateRequirements(loaderstate, ctx)
if err != nil { if err != nil {
ld.error(err) ld.error(err)
break break
@ -1184,12 +1184,12 @@ func loadFromRoots(ctx context.Context, params loaderParams) *loader {
continue continue
} }
if !ld.ResolveMissingImports || (!HasModRoot() && !allowMissingModuleImports) { if !ld.ResolveMissingImports || (!HasModRoot(loaderstate) && !allowMissingModuleImports) {
// We've loaded as much as we can without resolving missing imports. // We've loaded as much as we can without resolving missing imports.
break break
} }
modAddedBy, err := ld.resolveMissingImports(ctx) modAddedBy, err := ld.resolveMissingImports(loaderstate, ctx)
if err != nil { if err != nil {
ld.error(err) ld.error(err)
break break
@ -1216,7 +1216,7 @@ func loadFromRoots(ctx context.Context, params loaderParams) *loader {
// iteration so we don't need to also update it here. (That would waste time // iteration so we don't need to also update it here. (That would waste time
// computing a "direct" map that we'll have to recompute later anyway.) // computing a "direct" map that we'll have to recompute later anyway.)
direct := ld.requirements.direct direct := ld.requirements.direct
rs, err := updateRoots(ctx, direct, ld.requirements, noPkgs, toAdd, ld.AssumeRootsImported) rs, err := updateRoots(loaderstate, ctx, direct, ld.requirements, noPkgs, toAdd, ld.AssumeRootsImported)
if err != nil { if err != nil {
// If an error was found in a newly added module, report the package // If an error was found in a newly added module, report the package
// import stack instead of the module requirement stack. Packages // import stack instead of the module requirement stack. Packages
@ -1244,7 +1244,7 @@ func loadFromRoots(ctx context.Context, params loaderParams) *loader {
// Tidy the build list, if applicable, before we report errors. // Tidy the build list, if applicable, before we report errors.
// (The process of tidying may remove errors from irrelevant dependencies.) // (The process of tidying may remove errors from irrelevant dependencies.)
if ld.Tidy { if ld.Tidy {
rs, err := tidyRoots(ctx, ld.requirements, ld.pkgs) rs, err := tidyRoots(loaderstate, ctx, ld.requirements, ld.pkgs)
if err != nil { if err != nil {
ld.error(err) ld.error(err)
} else { } else {
@ -1252,8 +1252,8 @@ func loadFromRoots(ctx context.Context, params loaderParams) *loader {
// Attempt to switch to the requested Go version. We have been using its // Attempt to switch to the requested Go version. We have been using its
// pruning and semantics all along, but there may have been — and may // pruning and semantics all along, but there may have been — and may
// still be — requirements on higher versions in the graph. // still be — requirements on higher versions in the graph.
tidy := overrideRoots(ctx, rs, []module.Version{{Path: "go", Version: ld.TidyGoVersion}}) tidy := overrideRoots(loaderstate, ctx, rs, []module.Version{{Path: "go", Version: ld.TidyGoVersion}})
mg, err := tidy.Graph(ctx) mg, err := tidy.Graph(loaderstate, ctx)
if err != nil { if err != nil {
ld.error(err) ld.error(err)
} }
@ -1285,7 +1285,7 @@ func loadFromRoots(ctx context.Context, params loaderParams) *loader {
if m.Path == "go" && ld.TidyGoVersion != "" { if m.Path == "go" && ld.TidyGoVersion != "" {
continue continue
} }
if v, ok := ld.requirements.rootSelected(m.Path); !ok || v != m.Version { if v, ok := ld.requirements.rootSelected(loaderstate, m.Path); !ok || v != m.Version {
ld.error(fmt.Errorf("internal error: a requirement on %v is needed but was not added during package loading (selected %s)", m, v)) ld.error(fmt.Errorf("internal error: a requirement on %v is needed but was not added during package loading (selected %s)", m, v))
} }
} }
@ -1334,7 +1334,7 @@ func loadFromRoots(ctx context.Context, params loaderParams) *loader {
ld.error(fmt.Errorf("%s: %w", pkg.stackText(), pkg.err)) ld.error(fmt.Errorf("%s: %w", pkg.stackText(), pkg.err))
} }
ld.checkMultiplePaths() ld.checkMultiplePaths(loaderstate)
return ld return ld
} }
@ -1357,7 +1357,7 @@ func loadFromRoots(ctx context.Context, params loaderParams) *loader {
// The "changed" return value reports whether the update changed the selected // The "changed" return value reports whether the update changed the selected
// version of any module that either provided a loaded package or may now // version of any module that either provided a loaded package or may now
// provide a package that was previously unresolved. // provide a package that was previously unresolved.
func (ld *loader) updateRequirements(ctx context.Context) (changed bool, err error) { func (ld *loader) updateRequirements(loaderstate *State, ctx context.Context) (changed bool, err error) {
rs := ld.requirements rs := ld.requirements
// direct contains the set of modules believed to provide packages directly // direct contains the set of modules believed to provide packages directly
@ -1390,16 +1390,16 @@ func (ld *loader) updateRequirements(ctx context.Context) (changed bool, err err
} }
} }
} }
if pkg.mod.Version != "" || !LoaderState.MainModules.Contains(pkg.mod.Path) { if pkg.mod.Version != "" || !loaderstate.MainModules.Contains(pkg.mod.Path) {
continue continue
} }
for _, dep := range pkg.imports { for _, dep := range pkg.imports {
if !dep.fromExternalModule() { if !dep.fromExternalModule(loaderstate) {
continue continue
} }
if inWorkspaceMode() { if inWorkspaceMode(loaderstate) {
// In workspace mode / workspace pruning mode, the roots are the main modules // In workspace mode / workspace pruning mode, the roots are the main modules
// rather than the main module's direct dependencies. The check below on the selected // rather than the main module's direct dependencies. The check below on the selected
// roots does not apply. // roots does not apply.
@ -1412,7 +1412,7 @@ func (ld *loader) updateRequirements(ctx context.Context) (changed bool, err err
// of the vendor directory anyway. // of the vendor directory anyway.
continue continue
} }
if mg, err := rs.Graph(ctx); err != nil { if mg, err := rs.Graph(loaderstate, ctx); err != nil {
return false, err return false, err
} else if _, ok := mg.RequiredBy(dep.mod); !ok { } else if _, ok := mg.RequiredBy(dep.mod); !ok {
// dep.mod is not an explicit dependency, but needs to be. // dep.mod is not an explicit dependency, but needs to be.
@ -1424,7 +1424,7 @@ func (ld *loader) updateRequirements(ctx context.Context) (changed bool, err err
} }
} }
} else if pkg.err == nil && cfg.BuildMod != "mod" { } else if pkg.err == nil && cfg.BuildMod != "mod" {
if v, ok := rs.rootSelected(dep.mod.Path); !ok || v != dep.mod.Version { if v, ok := rs.rootSelected(loaderstate, dep.mod.Path); !ok || v != dep.mod.Version {
// dep.mod is not an explicit dependency, but needs to be. // dep.mod is not an explicit dependency, but needs to be.
// Because we are not in "mod" mode, we will not be able to update it. // Because we are not in "mod" mode, we will not be able to update it.
// Instead, mark the importing package with an error. // Instead, mark the importing package with an error.
@ -1490,21 +1490,21 @@ func (ld *loader) updateRequirements(ctx context.Context) (changed bool, err err
// roots can only increase and the set of roots can only expand. The set // roots can only increase and the set of roots can only expand. The set
// of extant root paths is finite and the set of versions of each path is // of extant root paths is finite and the set of versions of each path is
// finite, so the iteration *must* reach a stable fixed-point. // finite, so the iteration *must* reach a stable fixed-point.
tidy, err := tidyRoots(ctx, rs, ld.pkgs) tidy, err := tidyRoots(loaderstate, ctx, rs, ld.pkgs)
if err != nil { if err != nil {
return false, err return false, err
} }
addRoots = tidy.rootModules addRoots = tidy.rootModules
} }
rs, err = updateRoots(ctx, direct, rs, ld.pkgs, addRoots, ld.AssumeRootsImported) rs, err = updateRoots(loaderstate, ctx, direct, rs, ld.pkgs, addRoots, ld.AssumeRootsImported)
if err != nil { if err != nil {
// We don't actually know what even the root requirements are supposed to be, // We don't actually know what even the root requirements are supposed to be,
// so we can't proceed with loading. Return the error to the caller // so we can't proceed with loading. Return the error to the caller
return false, err return false, err
} }
if rs.GoVersion() != ld.requirements.GoVersion() { if rs.GoVersion(loaderstate) != ld.requirements.GoVersion(loaderstate) {
// A change in the selected Go version may or may not affect the set of // A change in the selected Go version may or may not affect the set of
// loaded packages, but in some cases it can change the meaning of the "all" // loaded packages, but in some cases it can change the meaning of the "all"
// pattern, the level of pruning in the module graph, and even the set of // pattern, the level of pruning in the module graph, and even the set of
@ -1515,12 +1515,12 @@ func (ld *loader) updateRequirements(ctx context.Context) (changed bool, err err
// The roots of the module graph have changed in some way (not just the // The roots of the module graph have changed in some way (not just the
// "direct" markings). Check whether the changes affected any of the loaded // "direct" markings). Check whether the changes affected any of the loaded
// packages. // packages.
mg, err := rs.Graph(ctx) mg, err := rs.Graph(loaderstate, ctx)
if err != nil { if err != nil {
return false, err return false, err
} }
for _, pkg := range ld.pkgs { for _, pkg := range ld.pkgs {
if pkg.fromExternalModule() && mg.Selected(pkg.mod.Path) != pkg.mod.Version { if pkg.fromExternalModule(loaderstate) && mg.Selected(pkg.mod.Path) != pkg.mod.Version {
changed = true changed = true
break break
} }
@ -1540,7 +1540,7 @@ func (ld *loader) updateRequirements(ctx context.Context) (changed bool, err err
// //
// In some sense, we can think of this as upgraded the module providing // In some sense, we can think of this as upgraded the module providing
// pkg.path from "none" to a version higher than "none". // pkg.path from "none" to a version higher than "none".
if _, _, _, _, err = importFromModules(ctx, pkg.path, rs, nil, ld.skipImportModFiles); err == nil { if _, _, _, _, err = importFromModules(loaderstate, ctx, pkg.path, rs, nil, ld.skipImportModFiles); err == nil {
changed = true changed = true
break break
} }
@ -1558,7 +1558,7 @@ func (ld *loader) updateRequirements(ctx context.Context) (changed bool, err err
// The newly-resolved packages are added to the addedModuleFor map, and // The newly-resolved packages are added to the addedModuleFor map, and
// resolveMissingImports returns a map from each new module version to // resolveMissingImports returns a map from each new module version to
// the first missing package that module would resolve. // the first missing package that module would resolve.
func (ld *loader) resolveMissingImports(ctx context.Context) (modAddedBy map[module.Version]*loadPkg, err error) { func (ld *loader) resolveMissingImports(loaderstate *State, ctx context.Context) (modAddedBy map[module.Version]*loadPkg, err error) {
type pkgMod struct { type pkgMod struct {
pkg *loadPkg pkg *loadPkg
mod *module.Version mod *module.Version
@ -1582,11 +1582,11 @@ func (ld *loader) resolveMissingImports(ctx context.Context) (modAddedBy map[mod
var mod module.Version var mod module.Version
ld.work.Add(func() { ld.work.Add(func() {
var err error var err error
mod, err = queryImport(ctx, pkg.path, ld.requirements) mod, err = queryImport(loaderstate, ctx, pkg.path, ld.requirements)
if err != nil { if err != nil {
if ime, ok := errors.AsType[*ImportMissingError](err); ok { if ime, ok := errors.AsType[*ImportMissingError](err); ok {
for curstack := pkg.stack; curstack != nil; curstack = curstack.stack { for curstack := pkg.stack; curstack != nil; curstack = curstack.stack {
if LoaderState.MainModules.Contains(curstack.mod.Path) { if loaderstate.MainModules.Contains(curstack.mod.Path) {
ime.ImportingMainModule = curstack.mod ime.ImportingMainModule = curstack.mod
break break
} }
@ -1658,7 +1658,7 @@ func (ld *loader) resolveMissingImports(ctx context.Context) (modAddedBy map[mod
// ld.work queue, and its test (if requested) will also be populated once // ld.work queue, and its test (if requested) will also be populated once
// imports have been resolved. When ld.work goes idle, all transitive imports of // imports have been resolved. When ld.work goes idle, all transitive imports of
// the requested package (and its test, if requested) will have been loaded. // the requested package (and its test, if requested) will have been loaded.
func (ld *loader) pkg(ctx context.Context, path string, flags loadPkgFlags) *loadPkg { func (ld *loader) pkg(loaderstate *State, ctx context.Context, path string, flags loadPkgFlags) *loadPkg {
if flags.has(pkgImportsLoaded) { if flags.has(pkgImportsLoaded) {
panic("internal error: (*loader).pkg called with pkgImportsLoaded flag set") panic("internal error: (*loader).pkg called with pkgImportsLoaded flag set")
} }
@ -1667,20 +1667,20 @@ func (ld *loader) pkg(ctx context.Context, path string, flags loadPkgFlags) *loa
pkg := &loadPkg{ pkg := &loadPkg{
path: path, path: path,
} }
ld.applyPkgFlags(ctx, pkg, flags) ld.applyPkgFlags(loaderstate, ctx, pkg, flags)
ld.work.Add(func() { ld.load(ctx, pkg) }) ld.work.Add(func() { ld.load(loaderstate, ctx, pkg) })
return pkg return pkg
}) })
ld.applyPkgFlags(ctx, pkg, flags) ld.applyPkgFlags(loaderstate, ctx, pkg, flags)
return pkg return pkg
} }
// applyPkgFlags updates pkg.flags to set the given flags and propagate the // applyPkgFlags updates pkg.flags to set the given flags and propagate the
// (transitive) effects of those flags, possibly loading or enqueueing further // (transitive) effects of those flags, possibly loading or enqueueing further
// packages as a result. // packages as a result.
func (ld *loader) applyPkgFlags(ctx context.Context, pkg *loadPkg, flags loadPkgFlags) { func (ld *loader) applyPkgFlags(loaderstate *State, ctx context.Context, pkg *loadPkg, flags loadPkgFlags) {
if flags == 0 { if flags == 0 {
return return
} }
@ -1708,7 +1708,7 @@ func (ld *loader) applyPkgFlags(ctx context.Context, pkg *loadPkg, flags loadPkg
// so it's ok if we call it more than is strictly necessary. // so it's ok if we call it more than is strictly necessary.
wantTest := false wantTest := false
switch { switch {
case ld.allPatternIsRoot && LoaderState.MainModules.Contains(pkg.mod.Path): case ld.allPatternIsRoot && loaderstate.MainModules.Contains(pkg.mod.Path):
// We are loading the "all" pattern, which includes packages imported by // We are loading the "all" pattern, which includes packages imported by
// tests in the main module. This package is in the main module, so we // tests in the main module. This package is in the main module, so we
// need to identify the imports of its test even if LoadTests is not set. // need to identify the imports of its test even if LoadTests is not set.
@ -1729,13 +1729,13 @@ func (ld *loader) applyPkgFlags(ctx context.Context, pkg *loadPkg, flags loadPkg
if wantTest { if wantTest {
var testFlags loadPkgFlags var testFlags loadPkgFlags
if LoaderState.MainModules.Contains(pkg.mod.Path) || (ld.allClosesOverTests && new.has(pkgInAll)) { if loaderstate.MainModules.Contains(pkg.mod.Path) || (ld.allClosesOverTests && new.has(pkgInAll)) {
// Tests of packages in the main module are in "all", in the sense that // Tests of packages in the main module are in "all", in the sense that
// they cause the packages they import to also be in "all". So are tests // they cause the packages they import to also be in "all". So are tests
// of packages in "all" if "all" closes over test dependencies. // of packages in "all" if "all" closes over test dependencies.
testFlags |= pkgInAll testFlags |= pkgInAll
} }
ld.pkgTest(ctx, pkg, testFlags) ld.pkgTest(loaderstate, ctx, pkg, testFlags)
} }
} }
@ -1743,13 +1743,13 @@ func (ld *loader) applyPkgFlags(ctx context.Context, pkg *loadPkg, flags loadPkg
// We have just marked pkg with pkgInAll, or we have just loaded its // We have just marked pkg with pkgInAll, or we have just loaded its
// imports, or both. Now is the time to propagate pkgInAll to the imports. // imports, or both. Now is the time to propagate pkgInAll to the imports.
for _, dep := range pkg.imports { for _, dep := range pkg.imports {
ld.applyPkgFlags(ctx, dep, pkgInAll) ld.applyPkgFlags(loaderstate, ctx, dep, pkgInAll)
} }
} }
if new.has(pkgFromRoot) && !old.has(pkgFromRoot|pkgImportsLoaded) { if new.has(pkgFromRoot) && !old.has(pkgFromRoot|pkgImportsLoaded) {
for _, dep := range pkg.imports { for _, dep := range pkg.imports {
ld.applyPkgFlags(ctx, dep, pkgFromRoot) ld.applyPkgFlags(loaderstate, ctx, dep, pkgFromRoot)
} }
} }
} }
@ -1757,7 +1757,7 @@ func (ld *loader) applyPkgFlags(ctx context.Context, pkg *loadPkg, flags loadPkg
// preloadRootModules loads the module requirements needed to identify the // preloadRootModules loads the module requirements needed to identify the
// selected version of each module providing a package in rootPkgs, // selected version of each module providing a package in rootPkgs,
// adding new root modules to the module graph if needed. // adding new root modules to the module graph if needed.
func (ld *loader) preloadRootModules(ctx context.Context, rootPkgs []string) (changedBuildList bool) { func (ld *loader) preloadRootModules(loaderstate *State, ctx context.Context, rootPkgs []string) (changedBuildList bool) {
needc := make(chan map[module.Version]bool, 1) needc := make(chan map[module.Version]bool, 1)
needc <- map[module.Version]bool{} needc <- map[module.Version]bool{}
for _, path := range rootPkgs { for _, path := range rootPkgs {
@ -1768,12 +1768,12 @@ func (ld *loader) preloadRootModules(ctx context.Context, rootPkgs []string) (ch
// If the main module is tidy and the package is in "all" — or if we're // If the main module is tidy and the package is in "all" — or if we're
// lucky — we can identify all of its imports without actually loading the // lucky — we can identify all of its imports without actually loading the
// full module graph. // full module graph.
m, _, _, _, err := importFromModules(ctx, path, ld.requirements, nil, ld.skipImportModFiles) m, _, _, _, err := importFromModules(loaderstate, ctx, path, ld.requirements, nil, ld.skipImportModFiles)
if err != nil { if err != nil {
if _, ok := errors.AsType[*ImportMissingError](err); ok && ld.ResolveMissingImports { if _, ok := errors.AsType[*ImportMissingError](err); ok && ld.ResolveMissingImports {
// This package isn't provided by any selected module. // This package isn't provided by any selected module.
// If we can find it, it will be a new root dependency. // If we can find it, it will be a new root dependency.
m, err = queryImport(ctx, path, ld.requirements) m, err = queryImport(loaderstate, ctx, path, ld.requirements)
} }
if err != nil { if err != nil {
// We couldn't identify the root module containing this package. // We couldn't identify the root module containing this package.
@ -1786,7 +1786,7 @@ func (ld *loader) preloadRootModules(ctx context.Context, rootPkgs []string) (ch
return return
} }
v, ok := ld.requirements.rootSelected(m.Path) v, ok := ld.requirements.rootSelected(loaderstate, m.Path)
if !ok || v != m.Version { if !ok || v != m.Version {
// We found the requested package in m, but m is not a root, so // We found the requested package in m, but m is not a root, so
// loadModGraph will not load its requirements. We need to promote the // loadModGraph will not load its requirements. We need to promote the
@ -1814,7 +1814,7 @@ func (ld *loader) preloadRootModules(ctx context.Context, rootPkgs []string) (ch
} }
gover.ModSort(toAdd) gover.ModSort(toAdd)
rs, err := updateRoots(ctx, ld.requirements.direct, ld.requirements, nil, toAdd, ld.AssumeRootsImported) rs, err := updateRoots(loaderstate, ctx, ld.requirements.direct, ld.requirements, nil, toAdd, ld.AssumeRootsImported)
if err != nil { if err != nil {
// We are missing some root dependency, and for some reason we can't load // We are missing some root dependency, and for some reason we can't load
// enough of the module dependency graph to add the missing root. Package // enough of the module dependency graph to add the missing root. Package
@ -1836,11 +1836,11 @@ func (ld *loader) preloadRootModules(ctx context.Context, rootPkgs []string) (ch
} }
// load loads an individual package. // load loads an individual package.
func (ld *loader) load(ctx context.Context, pkg *loadPkg) { func (ld *loader) load(loaderstate *State, ctx context.Context, pkg *loadPkg) {
var mg *ModuleGraph var mg *ModuleGraph
if ld.requirements.pruning == unpruned { if ld.requirements.pruning == unpruned {
var err error var err error
mg, err = ld.requirements.Graph(ctx) mg, err = ld.requirements.Graph(loaderstate, ctx)
if err != nil { if err != nil {
// We already checked the error from Graph in loadFromRoots and/or // We already checked the error from Graph in loadFromRoots and/or
// updateRequirements, so we ignored the error on purpose and we should // updateRequirements, so we ignored the error on purpose and we should
@ -1855,17 +1855,17 @@ func (ld *loader) load(ctx context.Context, pkg *loadPkg) {
} }
var modroot string var modroot string
pkg.mod, modroot, pkg.dir, pkg.altMods, pkg.err = importFromModules(ctx, pkg.path, ld.requirements, mg, ld.skipImportModFiles) pkg.mod, modroot, pkg.dir, pkg.altMods, pkg.err = importFromModules(loaderstate, ctx, pkg.path, ld.requirements, mg, ld.skipImportModFiles)
if LoaderState.MainModules.Tools()[pkg.path] { if loaderstate.MainModules.Tools()[pkg.path] {
// Tools declared by main modules are always in "all". // Tools declared by main modules are always in "all".
// We apply the package flags before returning so that missing // We apply the package flags before returning so that missing
// tool dependencies report an error https://go.dev/issue/70582 // tool dependencies report an error https://go.dev/issue/70582
ld.applyPkgFlags(ctx, pkg, pkgInAll) ld.applyPkgFlags(loaderstate, ctx, pkg, pkgInAll)
} }
if pkg.dir == "" { if pkg.dir == "" {
return return
} }
if LoaderState.MainModules.Contains(pkg.mod.Path) { if loaderstate.MainModules.Contains(pkg.mod.Path) {
// Go ahead and mark pkg as in "all". This provides the invariant that a // Go ahead and mark pkg as in "all". This provides the invariant that a
// package that is *only* imported by other packages in "all" is always // package that is *only* imported by other packages in "all" is always
// marked as such before loading its imports. // marked as such before loading its imports.
@ -1875,7 +1875,7 @@ func (ld *loader) load(ctx context.Context, pkg *loadPkg) {
// about (by reducing churn on the flag bits of dependencies), and costs // about (by reducing churn on the flag bits of dependencies), and costs
// essentially nothing (these atomic flag ops are essentially free compared // essentially nothing (these atomic flag ops are essentially free compared
// to scanning source code for imports). // to scanning source code for imports).
ld.applyPkgFlags(ctx, pkg, pkgInAll) ld.applyPkgFlags(loaderstate, ctx, pkg, pkgInAll)
} }
if ld.AllowPackage != nil { if ld.AllowPackage != nil {
if err := ld.AllowPackage(ctx, pkg.path, pkg.mod); err != nil { if err := ld.AllowPackage(ctx, pkg.path, pkg.mod); err != nil {
@ -1907,13 +1907,13 @@ func (ld *loader) load(ctx context.Context, pkg *loadPkg) {
if pkg.inStd { if pkg.inStd {
// Imports from packages in "std" and "cmd" should resolve using // Imports from packages in "std" and "cmd" should resolve using
// GOROOT/src/vendor even when "std" is not the main module. // GOROOT/src/vendor even when "std" is not the main module.
path = ld.stdVendor(pkg.path, path) path = ld.stdVendor(loaderstate, pkg.path, path)
} }
pkg.imports = append(pkg.imports, ld.pkg(ctx, path, importFlags)) pkg.imports = append(pkg.imports, ld.pkg(loaderstate, ctx, path, importFlags))
} }
pkg.testImports = testImports pkg.testImports = testImports
ld.applyPkgFlags(ctx, pkg, pkgImportsLoaded) ld.applyPkgFlags(loaderstate, ctx, pkg, pkgImportsLoaded)
} }
// pkgTest locates the test of pkg, creating it if needed, and updates its state // pkgTest locates the test of pkg, creating it if needed, and updates its state
@ -1921,7 +1921,7 @@ func (ld *loader) load(ctx context.Context, pkg *loadPkg) {
// //
// pkgTest requires that the imports of pkg have already been loaded (flagged // pkgTest requires that the imports of pkg have already been loaded (flagged
// with pkgImportsLoaded). // with pkgImportsLoaded).
func (ld *loader) pkgTest(ctx context.Context, pkg *loadPkg, testFlags loadPkgFlags) *loadPkg { func (ld *loader) pkgTest(loaderstate *State, ctx context.Context, pkg *loadPkg, testFlags loadPkgFlags) *loadPkg {
if pkg.isTest() { if pkg.isTest() {
panic("pkgTest called on a test package") panic("pkgTest called on a test package")
} }
@ -1936,7 +1936,7 @@ func (ld *loader) pkgTest(ctx context.Context, pkg *loadPkg, testFlags loadPkgFl
err: pkg.err, err: pkg.err,
inStd: pkg.inStd, inStd: pkg.inStd,
} }
ld.applyPkgFlags(ctx, pkg.test, testFlags) ld.applyPkgFlags(loaderstate, ctx, pkg.test, testFlags)
createdTest = true createdTest = true
}) })
@ -1949,14 +1949,14 @@ func (ld *loader) pkgTest(ctx context.Context, pkg *loadPkg, testFlags loadPkgFl
} }
for _, path := range pkg.testImports { for _, path := range pkg.testImports {
if pkg.inStd { if pkg.inStd {
path = ld.stdVendor(test.path, path) path = ld.stdVendor(loaderstate, test.path, path)
} }
test.imports = append(test.imports, ld.pkg(ctx, path, importFlags)) test.imports = append(test.imports, ld.pkg(loaderstate, ctx, path, importFlags))
} }
pkg.testImports = nil pkg.testImports = nil
ld.applyPkgFlags(ctx, test, pkgImportsLoaded) ld.applyPkgFlags(loaderstate, ctx, test, pkgImportsLoaded)
} else { } else {
ld.applyPkgFlags(ctx, test, testFlags) ld.applyPkgFlags(loaderstate, ctx, test, testFlags)
} }
return test return test
@ -1964,7 +1964,7 @@ func (ld *loader) pkgTest(ctx context.Context, pkg *loadPkg, testFlags loadPkgFl
// stdVendor returns the canonical import path for the package with the given // stdVendor returns the canonical import path for the package with the given
// path when imported from the standard-library package at parentPath. // path when imported from the standard-library package at parentPath.
func (ld *loader) stdVendor(parentPath, path string) string { func (ld *loader) stdVendor(loaderstate *State, parentPath, path string) string {
if p, _, ok := fips140.ResolveImport(path); ok { if p, _, ok := fips140.ResolveImport(path); ok {
return p return p
} }
@ -1973,14 +1973,14 @@ func (ld *loader) stdVendor(parentPath, path string) string {
} }
if str.HasPathPrefix(parentPath, "cmd") { if str.HasPathPrefix(parentPath, "cmd") {
if !ld.VendorModulesInGOROOTSrc || !LoaderState.MainModules.Contains("cmd") { if !ld.VendorModulesInGOROOTSrc || !loaderstate.MainModules.Contains("cmd") {
vendorPath := pathpkg.Join("cmd", "vendor", path) vendorPath := pathpkg.Join("cmd", "vendor", path)
if _, err := os.Stat(filepath.Join(cfg.GOROOTsrc, filepath.FromSlash(vendorPath))); err == nil { if _, err := os.Stat(filepath.Join(cfg.GOROOTsrc, filepath.FromSlash(vendorPath))); err == nil {
return vendorPath return vendorPath
} }
} }
} else if !ld.VendorModulesInGOROOTSrc || !LoaderState.MainModules.Contains("std") || str.HasPathPrefix(parentPath, "vendor") { } else if !ld.VendorModulesInGOROOTSrc || !loaderstate.MainModules.Contains("std") || str.HasPathPrefix(parentPath, "vendor") {
// If we are outside of the 'std' module, resolve imports from within 'std' // If we are outside of the 'std' module, resolve imports from within 'std'
// to the vendor directory. // to the vendor directory.
// //
@ -2026,7 +2026,7 @@ func (ld *loader) computePatternAll() (all []string) {
// or as a replacement for another module, but not both at the same time. // or as a replacement for another module, but not both at the same time.
// //
// (See https://golang.org/issue/26607 and https://golang.org/issue/34650.) // (See https://golang.org/issue/26607 and https://golang.org/issue/34650.)
func (ld *loader) checkMultiplePaths() { func (ld *loader) checkMultiplePaths(loaderstate *State) {
mods := ld.requirements.rootModules mods := ld.requirements.rootModules
if cached := ld.requirements.graph.Load(); cached != nil { if cached := ld.requirements.graph.Load(); cached != nil {
if mg := cached.mg; mg != nil { if mg := cached.mg; mg != nil {
@ -2036,7 +2036,7 @@ func (ld *loader) checkMultiplePaths() {
firstPath := map[module.Version]string{} firstPath := map[module.Version]string{}
for _, mod := range mods { for _, mod := range mods {
src := resolveReplacement(mod) src := resolveReplacement(loaderstate, mod)
if prev, ok := firstPath[src]; !ok { if prev, ok := firstPath[src]; !ok {
firstPath[src] = mod.Path firstPath[src] = mod.Path
} else if prev != mod.Path { } else if prev != mod.Path {
@ -2047,8 +2047,8 @@ func (ld *loader) checkMultiplePaths() {
// checkTidyCompatibility emits an error if any package would be loaded from a // checkTidyCompatibility emits an error if any package would be loaded from a
// different module under rs than under ld.requirements. // different module under rs than under ld.requirements.
func (ld *loader) checkTidyCompatibility(ctx context.Context, rs *Requirements, compatVersion string) { func (ld *loader) checkTidyCompatibility(loaderstate *State, ctx context.Context, rs *Requirements, compatVersion string) {
goVersion := rs.GoVersion() goVersion := rs.GoVersion(loaderstate)
suggestUpgrade := false suggestUpgrade := false
suggestEFlag := false suggestEFlag := false
suggestFixes := func() { suggestFixes := func() {
@ -2065,7 +2065,7 @@ func (ld *loader) checkTidyCompatibility(ctx context.Context, rs *Requirements,
fmt.Fprintln(os.Stderr) fmt.Fprintln(os.Stderr)
goFlag := "" goFlag := ""
if goVersion != LoaderState.MainModules.GoVersion() { if goVersion != loaderstate.MainModules.GoVersion(loaderstate) {
goFlag = " -go=" + goVersion goFlag = " -go=" + goVersion
} }
@ -2094,7 +2094,7 @@ func (ld *loader) checkTidyCompatibility(ctx context.Context, rs *Requirements,
fmt.Fprintf(os.Stderr, "For information about 'go mod tidy' compatibility, see:\n\thttps://go.dev/ref/mod#graph-pruning\n") fmt.Fprintf(os.Stderr, "For information about 'go mod tidy' compatibility, see:\n\thttps://go.dev/ref/mod#graph-pruning\n")
} }
mg, err := rs.Graph(ctx) mg, err := rs.Graph(loaderstate, ctx)
if err != nil { if err != nil {
ld.error(fmt.Errorf("error loading go %s module graph: %w", compatVersion, err)) ld.error(fmt.Errorf("error loading go %s module graph: %w", compatVersion, err))
ld.switchIfErrors(ctx) ld.switchIfErrors(ctx)
@ -2132,7 +2132,7 @@ func (ld *loader) checkTidyCompatibility(ctx context.Context, rs *Requirements,
pkg := pkg pkg := pkg
ld.work.Add(func() { ld.work.Add(func() {
mod, _, _, _, err := importFromModules(ctx, pkg.path, rs, mg, ld.skipImportModFiles) mod, _, _, _, err := importFromModules(loaderstate, ctx, pkg.path, rs, mg, ld.skipImportModFiles)
if mod != pkg.mod { if mod != pkg.mod {
mismatches := <-mismatchMu mismatches := <-mismatchMu
mismatches[pkg] = mismatch{mod: mod, err: err} mismatches[pkg] = mismatch{mod: mod, err: err}

View file

@ -142,7 +142,7 @@ func CheckAllowed(ctx context.Context, m module.Version) error {
if err := CheckExclusions(ctx, m); err != nil { if err := CheckExclusions(ctx, m); err != nil {
return err return err
} }
if err := CheckRetractions(ctx, m); err != nil { if err := CheckRetractions(LoaderState, ctx, m); err != nil {
return err return err
} }
return nil return nil
@ -172,7 +172,7 @@ func (e *excludedError) Is(err error) bool { return err == ErrDisallowed }
// CheckRetractions returns an error if module m has been retracted by // CheckRetractions returns an error if module m has been retracted by
// its author. // its author.
func CheckRetractions(ctx context.Context, m module.Version) (err error) { func CheckRetractions(loaderstate *State, ctx context.Context, m module.Version) (err error) {
defer func() { defer func() {
if err == nil { if err == nil {
return return
@ -193,7 +193,7 @@ func CheckRetractions(ctx context.Context, m module.Version) (err error) {
// Cannot be retracted. // Cannot be retracted.
return nil return nil
} }
if repl := Replacement(module.Version{Path: m.Path}); repl.Path != "" { if repl := Replacement(loaderstate, module.Version{Path: m.Path}); repl.Path != "" {
// All versions of the module were replaced. // All versions of the module were replaced.
// Don't load retractions, since we'd just load the replacement. // Don't load retractions, since we'd just load the replacement.
return nil return nil
@ -210,11 +210,11 @@ func CheckRetractions(ctx context.Context, m module.Version) (err error) {
// We load the raw file here: the go.mod file may have a different module // We load the raw file here: the go.mod file may have a different module
// path that we expect if the module or its repository was renamed. // path that we expect if the module or its repository was renamed.
// We still want to apply retractions to other aliases of the module. // We still want to apply retractions to other aliases of the module.
rm, err := queryLatestVersionIgnoringRetractions(ctx, m.Path) rm, err := queryLatestVersionIgnoringRetractions(loaderstate, ctx, m.Path)
if err != nil { if err != nil {
return err return err
} }
summary, err := rawGoModSummary(rm) summary, err := rawGoModSummary(loaderstate, rm)
if err != nil && !errors.Is(err, gover.ErrTooNew) { if err != nil && !errors.Is(err, gover.ErrTooNew) {
return err return err
} }
@ -300,7 +300,7 @@ func ShortMessage(message, emptyDefault string) string {
// //
// CheckDeprecation returns an error if the message can't be loaded. // CheckDeprecation returns an error if the message can't be loaded.
// CheckDeprecation returns "", nil if there is no deprecation message. // CheckDeprecation returns "", nil if there is no deprecation message.
func CheckDeprecation(ctx context.Context, m module.Version) (deprecation string, err error) { func CheckDeprecation(loaderstate *State, ctx context.Context, m module.Version) (deprecation string, err error) {
defer func() { defer func() {
if err != nil { if err != nil {
err = fmt.Errorf("loading deprecation for %s: %w", m.Path, err) err = fmt.Errorf("loading deprecation for %s: %w", m.Path, err)
@ -312,17 +312,17 @@ func CheckDeprecation(ctx context.Context, m module.Version) (deprecation string
// Don't look up deprecation. // Don't look up deprecation.
return "", nil return "", nil
} }
if repl := Replacement(module.Version{Path: m.Path}); repl.Path != "" { if repl := Replacement(loaderstate, module.Version{Path: m.Path}); repl.Path != "" {
// All versions of the module were replaced. // All versions of the module were replaced.
// We'll look up deprecation separately for the replacement. // We'll look up deprecation separately for the replacement.
return "", nil return "", nil
} }
latest, err := queryLatestVersionIgnoringRetractions(ctx, m.Path) latest, err := queryLatestVersionIgnoringRetractions(loaderstate, ctx, m.Path)
if err != nil { if err != nil {
return "", err return "", err
} }
summary, err := rawGoModSummary(latest) summary, err := rawGoModSummary(loaderstate, latest)
if err != nil && !errors.Is(err, gover.ErrTooNew) { if err != nil && !errors.Is(err, gover.ErrTooNew) {
return "", err return "", err
} }
@ -342,28 +342,28 @@ func replacement(mod module.Version, replace map[module.Version]module.Version)
// Replacement returns the replacement for mod, if any. If the path in the // Replacement returns the replacement for mod, if any. If the path in the
// module.Version is relative it's relative to the single main module outside // module.Version is relative it's relative to the single main module outside
// workspace mode, or the workspace's directory in workspace mode. // workspace mode, or the workspace's directory in workspace mode.
func Replacement(mod module.Version) module.Version { func Replacement(loaderstate *State, mod module.Version) module.Version {
r, foundModRoot, _ := replacementFrom(mod) r, foundModRoot, _ := replacementFrom(loaderstate, mod)
return canonicalizeReplacePath(r, foundModRoot) return canonicalizeReplacePath(loaderstate, r, foundModRoot)
} }
// replacementFrom returns the replacement for mod, if any, the modroot of the replacement if it appeared in a go.mod, // replacementFrom returns the replacement for mod, if any, the modroot of the replacement if it appeared in a go.mod,
// and the source of the replacement. The replacement is relative to the go.work or go.mod file it appears in. // and the source of the replacement. The replacement is relative to the go.work or go.mod file it appears in.
func replacementFrom(mod module.Version) (r module.Version, modroot string, fromFile string) { func replacementFrom(loaderstate *State, mod module.Version) (r module.Version, modroot string, fromFile string) {
foundFrom, found, foundModRoot := "", module.Version{}, "" foundFrom, found, foundModRoot := "", module.Version{}, ""
if LoaderState.MainModules == nil { if loaderstate.MainModules == nil {
return module.Version{}, "", "" return module.Version{}, "", ""
} else if LoaderState.MainModules.Contains(mod.Path) && mod.Version == "" { } else if loaderstate.MainModules.Contains(mod.Path) && mod.Version == "" {
// Don't replace the workspace version of the main module. // Don't replace the workspace version of the main module.
return module.Version{}, "", "" return module.Version{}, "", ""
} }
if _, r, ok := replacement(mod, LoaderState.MainModules.WorkFileReplaceMap()); ok { if _, r, ok := replacement(mod, loaderstate.MainModules.WorkFileReplaceMap()); ok {
return r, "", LoaderState.workFilePath return r, "", loaderstate.workFilePath
} }
for _, v := range LoaderState.MainModules.Versions() { for _, v := range loaderstate.MainModules.Versions() {
if index := LoaderState.MainModules.Index(v); index != nil { if index := loaderstate.MainModules.Index(v); index != nil {
if from, r, ok := replacement(mod, index.replace); ok { if from, r, ok := replacement(mod, index.replace); ok {
modRoot := LoaderState.MainModules.ModRoot(v) modRoot := loaderstate.MainModules.ModRoot(v)
if foundModRoot != "" && foundFrom != from && found != r { if foundModRoot != "" && foundFrom != from && found != r {
base.Errorf("conflicting replacements found for %v in workspace modules defined by %v and %v", base.Errorf("conflicting replacements found for %v in workspace modules defined by %v and %v",
mod, modFilePath(foundModRoot), modFilePath(modRoot)) mod, modFilePath(foundModRoot), modFilePath(modRoot))
@ -376,21 +376,21 @@ func replacementFrom(mod module.Version) (r module.Version, modroot string, from
return found, foundModRoot, modFilePath(foundModRoot) return found, foundModRoot, modFilePath(foundModRoot)
} }
func replaceRelativeTo() string { func replaceRelativeTo(loaderstate *State) string {
if workFilePath := WorkFilePath(); workFilePath != "" { if workFilePath := WorkFilePath(loaderstate); workFilePath != "" {
return filepath.Dir(workFilePath) return filepath.Dir(workFilePath)
} }
return LoaderState.MainModules.ModRoot(LoaderState.MainModules.mustGetSingleMainModule()) return loaderstate.MainModules.ModRoot(loaderstate.MainModules.mustGetSingleMainModule(loaderstate))
} }
// canonicalizeReplacePath ensures that relative, on-disk, replaced module paths // canonicalizeReplacePath ensures that relative, on-disk, replaced module paths
// are relative to the workspace directory (in workspace mode) or to the module's // are relative to the workspace directory (in workspace mode) or to the module's
// directory (in module mode, as they already are). // directory (in module mode, as they already are).
func canonicalizeReplacePath(r module.Version, modRoot string) module.Version { func canonicalizeReplacePath(loaderstate *State, r module.Version, modRoot string) module.Version {
if filepath.IsAbs(r.Path) || r.Version != "" || modRoot == "" { if filepath.IsAbs(r.Path) || r.Version != "" || modRoot == "" {
return r return r
} }
workFilePath := WorkFilePath() workFilePath := WorkFilePath(loaderstate)
if workFilePath == "" { if workFilePath == "" {
return r return r
} }
@ -407,8 +407,8 @@ func canonicalizeReplacePath(r module.Version, modRoot string) module.Version {
// for m: either m itself, or the replacement for m (iff m is replaced). // for m: either m itself, or the replacement for m (iff m is replaced).
// It also returns the modroot of the module providing the replacement if // It also returns the modroot of the module providing the replacement if
// one was found. // one was found.
func resolveReplacement(m module.Version) module.Version { func resolveReplacement(loaderstate *State, m module.Version) module.Version {
if r := Replacement(m); r.Path != "" { if r := Replacement(loaderstate, m); r.Path != "" {
return r return r
} }
return m return m
@ -573,12 +573,12 @@ type retraction struct {
// module versions. // module versions.
// //
// The caller must not modify the returned summary. // The caller must not modify the returned summary.
func goModSummary(m module.Version) (*modFileSummary, error) { func goModSummary(loaderstate *State, m module.Version) (*modFileSummary, error) {
if m.Version == "" && !inWorkspaceMode() && LoaderState.MainModules.Contains(m.Path) { if m.Version == "" && !inWorkspaceMode(loaderstate) && loaderstate.MainModules.Contains(m.Path) {
panic("internal error: goModSummary called on a main module") panic("internal error: goModSummary called on a main module")
} }
if gover.IsToolchain(m.Path) { if gover.IsToolchain(m.Path) {
return rawGoModSummary(m) return rawGoModSummary(loaderstate, m)
} }
if cfg.BuildMod == "vendor" { if cfg.BuildMod == "vendor" {
@ -586,7 +586,7 @@ func goModSummary(m module.Version) (*modFileSummary, error) {
module: module.Version{Path: m.Path}, module: module.Version{Path: m.Path},
} }
readVendorList(VendorDir()) readVendorList(VendorDir(loaderstate))
if vendorVersion[m.Path] != m.Version { if vendorVersion[m.Path] != m.Version {
// This module is not vendored, so packages cannot be loaded from it and // This module is not vendored, so packages cannot be loaded from it and
// it cannot be relevant to the build. // it cannot be relevant to the build.
@ -601,15 +601,15 @@ func goModSummary(m module.Version) (*modFileSummary, error) {
return summary, nil return summary, nil
} }
actual := resolveReplacement(m) actual := resolveReplacement(loaderstate, m)
if mustHaveSums() && actual.Version != "" { if mustHaveSums(loaderstate) && actual.Version != "" {
key := module.Version{Path: actual.Path, Version: actual.Version + "/go.mod"} key := module.Version{Path: actual.Path, Version: actual.Version + "/go.mod"}
if !modfetch.HaveSum(key) { if !modfetch.HaveSum(key) {
suggestion := fmt.Sprintf(" for go.mod file; to add it:\n\tgo mod download %s", m.Path) suggestion := fmt.Sprintf(" for go.mod file; to add it:\n\tgo mod download %s", m.Path)
return nil, module.VersionError(actual, &sumMissingError{suggestion: suggestion}) return nil, module.VersionError(actual, &sumMissingError{suggestion: suggestion})
} }
} }
summary, err := rawGoModSummary(actual) summary, err := rawGoModSummary(loaderstate, actual)
if err != nil { if err != nil {
return nil, err return nil, err
} }
@ -641,8 +641,8 @@ func goModSummary(m module.Version) (*modFileSummary, error) {
} }
} }
for _, mainModule := range LoaderState.MainModules.Versions() { for _, mainModule := range loaderstate.MainModules.Versions() {
if index := LoaderState.MainModules.Index(mainModule); index != nil && len(index.exclude) > 0 { if index := loaderstate.MainModules.Index(mainModule); index != nil && len(index.exclude) > 0 {
// Drop any requirements on excluded versions. // Drop any requirements on excluded versions.
// Don't modify the cached summary though, since we might need the raw // Don't modify the cached summary though, since we might need the raw
// summary separately. // summary separately.
@ -676,7 +676,7 @@ func goModSummary(m module.Version) (*modFileSummary, error) {
// rawGoModSummary cannot be used on the main module outside of workspace mode. // rawGoModSummary cannot be used on the main module outside of workspace mode.
// The modFileSummary can still be used for retractions and deprecations // The modFileSummary can still be used for retractions and deprecations
// even if a TooNewError is returned. // even if a TooNewError is returned.
func rawGoModSummary(m module.Version) (*modFileSummary, error) { func rawGoModSummary(loaderstate *State, m module.Version) (*modFileSummary, error) {
if gover.IsToolchain(m.Path) { if gover.IsToolchain(m.Path) {
if m.Path == "go" && gover.Compare(m.Version, gover.GoStrictVersion) >= 0 { if m.Path == "go" && gover.Compare(m.Version, gover.GoStrictVersion) >= 0 {
// Declare that go 1.21.3 requires toolchain 1.21.3, // Declare that go 1.21.3 requires toolchain 1.21.3,
@ -686,7 +686,7 @@ func rawGoModSummary(m module.Version) (*modFileSummary, error) {
} }
return &modFileSummary{module: m}, nil return &modFileSummary{module: m}, nil
} }
if m.Version == "" && !inWorkspaceMode() && LoaderState.MainModules.Contains(m.Path) { if m.Version == "" && !inWorkspaceMode(loaderstate) && loaderstate.MainModules.Contains(m.Path) {
// Calling rawGoModSummary implies that we are treating m as a module whose // Calling rawGoModSummary implies that we are treating m as a module whose
// requirements aren't the roots of the module graph and can't be modified. // requirements aren't the roots of the module graph and can't be modified.
// //
@ -694,22 +694,22 @@ func rawGoModSummary(m module.Version) (*modFileSummary, error) {
// are the roots of the module graph and we expect them to be kept consistent. // are the roots of the module graph and we expect them to be kept consistent.
panic("internal error: rawGoModSummary called on a main module") panic("internal error: rawGoModSummary called on a main module")
} }
if m.Version == "" && inWorkspaceMode() && m.Path == "command-line-arguments" { if m.Version == "" && inWorkspaceMode(loaderstate) && m.Path == "command-line-arguments" {
// "go work sync" calls LoadModGraph to make sure the module graph is valid. // "go work sync" calls LoadModGraph to make sure the module graph is valid.
// If there are no modules in the workspace, we synthesize an empty // If there are no modules in the workspace, we synthesize an empty
// command-line-arguments module, which rawGoModData cannot read a go.mod for. // command-line-arguments module, which rawGoModData cannot read a go.mod for.
return &modFileSummary{module: m}, nil return &modFileSummary{module: m}, nil
} else if m.Version == "" && inWorkspaceMode() && LoaderState.MainModules.Contains(m.Path) { } else if m.Version == "" && inWorkspaceMode(loaderstate) && loaderstate.MainModules.Contains(m.Path) {
// When go get uses EnterWorkspace to check that the workspace loads properly, // When go get uses EnterWorkspace to check that the workspace loads properly,
// it will update the contents of the workspace module's modfile in memory. To use the updated // it will update the contents of the workspace module's modfile in memory. To use the updated
// contents of the modfile when doing the load, don't read from disk and instead // contents of the modfile when doing the load, don't read from disk and instead
// recompute a summary using the updated contents of the modfile. // recompute a summary using the updated contents of the modfile.
if mf := LoaderState.MainModules.ModFile(m); mf != nil { if mf := loaderstate.MainModules.ModFile(m); mf != nil {
return summaryFromModFile(m, LoaderState.MainModules.modFiles[m]) return summaryFromModFile(m, loaderstate.MainModules.modFiles[m])
} }
} }
return rawGoModSummaryCache.Do(m, func() (*modFileSummary, error) { return rawGoModSummaryCache.Do(m, func() (*modFileSummary, error) {
name, data, err := rawGoModData(m) name, data, err := rawGoModData(loaderstate, m)
if err != nil { if err != nil {
return nil, err return nil, err
} }
@ -781,15 +781,15 @@ var rawGoModSummaryCache par.ErrCache[module.Version, *modFileSummary]
// //
// Unlike rawGoModSummary, rawGoModData does not cache its results in memory. // Unlike rawGoModSummary, rawGoModData does not cache its results in memory.
// Use rawGoModSummary instead unless you specifically need these bytes. // Use rawGoModSummary instead unless you specifically need these bytes.
func rawGoModData(m module.Version) (name string, data []byte, err error) { func rawGoModData(loaderstate *State, m module.Version) (name string, data []byte, err error) {
if m.Version == "" { if m.Version == "" {
dir := m.Path dir := m.Path
if !filepath.IsAbs(dir) { if !filepath.IsAbs(dir) {
if inWorkspaceMode() && LoaderState.MainModules.Contains(m.Path) { if inWorkspaceMode(loaderstate) && loaderstate.MainModules.Contains(m.Path) {
dir = LoaderState.MainModules.ModRoot(m) dir = loaderstate.MainModules.ModRoot(m)
} else { } else {
// m is a replacement module with only a file path. // m is a replacement module with only a file path.
dir = filepath.Join(replaceRelativeTo(), dir) dir = filepath.Join(replaceRelativeTo(loaderstate), dir)
} }
} }
name = filepath.Join(dir, "go.mod") name = filepath.Join(dir, "go.mod")
@ -825,12 +825,12 @@ func rawGoModData(m module.Version) (name string, data []byte, err error) {
// //
// If the queried latest version is replaced, // If the queried latest version is replaced,
// queryLatestVersionIgnoringRetractions returns the replacement. // queryLatestVersionIgnoringRetractions returns the replacement.
func queryLatestVersionIgnoringRetractions(ctx context.Context, path string) (latest module.Version, err error) { func queryLatestVersionIgnoringRetractions(loaderstate *State, ctx context.Context, path string) (latest module.Version, err error) {
return latestVersionIgnoringRetractionsCache.Do(path, func() (module.Version, error) { return latestVersionIgnoringRetractionsCache.Do(path, func() (module.Version, error) {
ctx, span := trace.StartSpan(ctx, "queryLatestVersionIgnoringRetractions "+path) ctx, span := trace.StartSpan(ctx, "queryLatestVersionIgnoringRetractions "+path)
defer span.Done() defer span.Done()
if repl := Replacement(module.Version{Path: path}); repl.Path != "" { if repl := Replacement(loaderstate, module.Version{Path: path}); repl.Path != "" {
// All versions of the module were replaced. // All versions of the module were replaced.
// No need to query. // No need to query.
return repl, nil return repl, nil
@ -840,12 +840,12 @@ func queryLatestVersionIgnoringRetractions(ctx context.Context, path string) (la
// Ignore exclusions from the main module's go.mod. // Ignore exclusions from the main module's go.mod.
const ignoreSelected = "" const ignoreSelected = ""
var allowAll AllowedFunc var allowAll AllowedFunc
rev, err := Query(ctx, path, "latest", ignoreSelected, allowAll) rev, err := Query(loaderstate, ctx, path, "latest", ignoreSelected, allowAll)
if err != nil { if err != nil {
return module.Version{}, err return module.Version{}, err
} }
latest := module.Version{Path: path, Version: rev.Version} latest := module.Version{Path: path, Version: rev.Version}
if repl := resolveReplacement(latest); repl.Path != "" { if repl := resolveReplacement(loaderstate, latest); repl.Path != "" {
latest = repl latest = repl
} }
return latest, nil return latest, nil

View file

@ -53,7 +53,7 @@ func (r *mvsReqs) Required(mod module.Version) ([]module.Version, error) {
return nil, nil return nil, nil
} }
summary, err := goModSummary(mod) summary, err := goModSummary(LoaderState, mod)
if err != nil { if err != nil {
return nil, err return nil, err
} }
@ -79,11 +79,11 @@ func (*mvsReqs) Upgrade(m module.Version) (module.Version, error) {
return m, nil return m, nil
} }
func versions(ctx context.Context, path string, allowed AllowedFunc) (versions []string, origin *codehost.Origin, err error) { func versions(loaderstate *State, ctx context.Context, path string, allowed AllowedFunc) (versions []string, origin *codehost.Origin, err error) {
// Note: modfetch.Lookup and repo.Versions are cached, // Note: modfetch.Lookup and repo.Versions are cached,
// so there's no need for us to add extra caching here. // so there's no need for us to add extra caching here.
err = modfetch.TryProxies(func(proxy string) error { err = modfetch.TryProxies(func(proxy string) error {
repo, err := lookupRepo(ctx, proxy, path) repo, err := lookupRepo(loaderstate, ctx, proxy, path)
if err != nil { if err != nil {
return err return err
} }
@ -111,12 +111,12 @@ func versions(ctx context.Context, path string, allowed AllowedFunc) (versions [
// //
// Since the version of a main module is not found in the version list, // Since the version of a main module is not found in the version list,
// it has no previous version. // it has no previous version.
func previousVersion(ctx context.Context, m module.Version) (module.Version, error) { func previousVersion(loaderstate *State, ctx context.Context, m module.Version) (module.Version, error) {
if m.Version == "" && LoaderState.MainModules.Contains(m.Path) { if m.Version == "" && loaderstate.MainModules.Contains(m.Path) {
return module.Version{Path: m.Path, Version: "none"}, nil return module.Version{Path: m.Path, Version: "none"}, nil
} }
list, _, err := versions(ctx, m.Path, CheckAllowed) list, _, err := versions(loaderstate, ctx, m.Path, CheckAllowed)
if err != nil { if err != nil {
if errors.Is(err, os.ErrNotExist) { if errors.Is(err, os.ErrNotExist) {
return module.Version{Path: m.Path, Version: "none"}, nil return module.Version{Path: m.Path, Version: "none"}, nil
@ -132,5 +132,5 @@ func previousVersion(ctx context.Context, m module.Version) (module.Version, err
func (*mvsReqs) Previous(m module.Version) (module.Version, error) { func (*mvsReqs) Previous(m module.Version) (module.Version, error) {
// TODO(golang.org/issue/38714): thread tracing context through MVS. // TODO(golang.org/issue/38714): thread tracing context through MVS.
return previousVersion(context.TODO(), m) return previousVersion(LoaderState, context.TODO(), m)
} }

View file

@ -80,19 +80,19 @@ import (
// //
// Query often returns a non-nil *RevInfo with a non-nil error, // Query often returns a non-nil *RevInfo with a non-nil error,
// to provide an info.Origin that can allow the error to be cached. // to provide an info.Origin that can allow the error to be cached.
func Query(ctx context.Context, path, query, current string, allowed AllowedFunc) (*modfetch.RevInfo, error) { func Query(loaderstate *State, ctx context.Context, path, query, current string, allowed AllowedFunc) (*modfetch.RevInfo, error) {
ctx, span := trace.StartSpan(ctx, "modload.Query "+path) ctx, span := trace.StartSpan(ctx, "modload.Query "+path)
defer span.Done() defer span.Done()
return queryReuse(ctx, path, query, current, allowed, nil) return queryReuse(loaderstate, ctx, path, query, current, allowed, nil)
} }
// queryReuse is like Query but also takes a map of module info that can be reused // queryReuse is like Query but also takes a map of module info that can be reused
// if the validation criteria in Origin are met. // if the validation criteria in Origin are met.
func queryReuse(ctx context.Context, path, query, current string, allowed AllowedFunc, reuse map[module.Version]*modinfo.ModulePublic) (*modfetch.RevInfo, error) { func queryReuse(loaderstate *State, ctx context.Context, path, query, current string, allowed AllowedFunc, reuse map[module.Version]*modinfo.ModulePublic) (*modfetch.RevInfo, error) {
var info *modfetch.RevInfo var info *modfetch.RevInfo
err := modfetch.TryProxies(func(proxy string) (err error) { err := modfetch.TryProxies(func(proxy string) (err error) {
info, err = queryProxy(ctx, proxy, path, query, current, allowed, reuse) info, err = queryProxy(loaderstate, ctx, proxy, path, query, current, allowed, reuse)
return err return err
}) })
return info, err return info, err
@ -100,9 +100,9 @@ func queryReuse(ctx context.Context, path, query, current string, allowed Allowe
// checkReuse checks whether a revision of a given module // checkReuse checks whether a revision of a given module
// for a given module may be reused, according to the information in origin. // for a given module may be reused, according to the information in origin.
func checkReuse(ctx context.Context, m module.Version, old *codehost.Origin) error { func checkReuse(loaderstate *State, ctx context.Context, m module.Version, old *codehost.Origin) error {
return modfetch.TryProxies(func(proxy string) error { return modfetch.TryProxies(func(proxy string) error {
repo, err := lookupRepo(ctx, proxy, m.Path) repo, err := lookupRepo(loaderstate, ctx, proxy, m.Path)
if err != nil { if err != nil {
return err return err
} }
@ -197,7 +197,7 @@ func (queryDisabledError) Error() string {
return fmt.Sprintf("cannot query module due to -mod=%s\n\t(%s)", cfg.BuildMod, cfg.BuildModReason) return fmt.Sprintf("cannot query module due to -mod=%s\n\t(%s)", cfg.BuildMod, cfg.BuildModReason)
} }
func queryProxy(ctx context.Context, proxy, path, query, current string, allowed AllowedFunc, reuse map[module.Version]*modinfo.ModulePublic) (*modfetch.RevInfo, error) { func queryProxy(loaderstate *State, ctx context.Context, proxy, path, query, current string, allowed AllowedFunc, reuse map[module.Version]*modinfo.ModulePublic) (*modfetch.RevInfo, error) {
ctx, span := trace.StartSpan(ctx, "modload.queryProxy "+path+" "+query) ctx, span := trace.StartSpan(ctx, "modload.queryProxy "+path+" "+query)
defer span.Done() defer span.Done()
@ -211,7 +211,7 @@ func queryProxy(ctx context.Context, proxy, path, query, current string, allowed
allowed = func(context.Context, module.Version) error { return nil } allowed = func(context.Context, module.Version) error { return nil }
} }
if LoaderState.MainModules.Contains(path) && (query == "upgrade" || query == "patch") { if loaderstate.MainModules.Contains(path) && (query == "upgrade" || query == "patch") {
m := module.Version{Path: path} m := module.Version{Path: path}
if err := allowed(ctx, m); err != nil { if err := allowed(ctx, m); err != nil {
return nil, fmt.Errorf("internal error: main module version is not allowed: %w", err) return nil, fmt.Errorf("internal error: main module version is not allowed: %w", err)
@ -223,7 +223,7 @@ func queryProxy(ctx context.Context, proxy, path, query, current string, allowed
return nil, fmt.Errorf("can't query specific version (%q) of standard-library module %q", query, path) return nil, fmt.Errorf("can't query specific version (%q) of standard-library module %q", query, path)
} }
repo, err := lookupRepo(ctx, proxy, path) repo, err := lookupRepo(loaderstate, ctx, proxy, path)
if err != nil { if err != nil {
return nil, err return nil, err
} }
@ -296,7 +296,7 @@ func queryProxy(ctx context.Context, proxy, path, query, current string, allowed
return &clone return &clone
} }
releases, prereleases, err := qm.filterVersions(ctx, versions.List) releases, prereleases, err := qm.filterVersions(loaderstate, ctx, versions.List)
if err != nil { if err != nil {
return revWithOrigin(nil), err return revWithOrigin(nil), err
} }
@ -569,7 +569,7 @@ func (qm *queryMatcher) allowsVersion(ctx context.Context, v string) bool {
// //
// If the allowed predicate returns an error not equivalent to ErrDisallowed, // If the allowed predicate returns an error not equivalent to ErrDisallowed,
// filterVersions returns that error. // filterVersions returns that error.
func (qm *queryMatcher) filterVersions(ctx context.Context, versions []string) (releases, prereleases []string, err error) { func (qm *queryMatcher) filterVersions(loaderstate *State, ctx context.Context, versions []string) (releases, prereleases []string, err error) {
needIncompatible := qm.preferIncompatible needIncompatible := qm.preferIncompatible
var lastCompatible string var lastCompatible string
@ -602,7 +602,7 @@ func (qm *queryMatcher) filterVersions(ctx context.Context, versions []string) (
// ignore any version with a higher (+incompatible) major version. (See // ignore any version with a higher (+incompatible) major version. (See
// https://golang.org/issue/34165.) Note that we even prefer a // https://golang.org/issue/34165.) Note that we even prefer a
// compatible pre-release over an incompatible release. // compatible pre-release over an incompatible release.
ok, err := versionHasGoMod(ctx, module.Version{Path: qm.path, Version: lastCompatible}) ok, err := versionHasGoMod(loaderstate, ctx, module.Version{Path: qm.path, Version: lastCompatible})
if err != nil { if err != nil {
return nil, nil, err return nil, nil, err
} }
@ -639,11 +639,11 @@ type QueryResult struct {
// QueryPackages is like QueryPattern, but requires that the pattern match at // QueryPackages is like QueryPattern, but requires that the pattern match at
// least one package and omits the non-package result (if any). // least one package and omits the non-package result (if any).
func QueryPackages(ctx context.Context, pattern, query string, current func(string) string, allowed AllowedFunc) ([]QueryResult, error) { func QueryPackages(loaderstate *State, ctx context.Context, pattern, query string, current func(string) string, allowed AllowedFunc) ([]QueryResult, error) {
pkgMods, modOnly, err := QueryPattern(ctx, pattern, query, current, allowed) pkgMods, modOnly, err := QueryPattern(loaderstate, ctx, pattern, query, current, allowed)
if len(pkgMods) == 0 && err == nil { if len(pkgMods) == 0 && err == nil {
replacement := Replacement(modOnly.Mod) replacement := Replacement(loaderstate, modOnly.Mod)
return nil, &PackageNotInModuleError{ return nil, &PackageNotInModuleError{
Mod: modOnly.Mod, Mod: modOnly.Mod,
Replacement: replacement, Replacement: replacement,
@ -670,7 +670,7 @@ func QueryPackages(ctx context.Context, pattern, query string, current func(stri
// //
// QueryPattern always returns at least one QueryResult (which may be only // QueryPattern always returns at least one QueryResult (which may be only
// modOnly) or a non-nil error. // modOnly) or a non-nil error.
func QueryPattern(ctx context.Context, pattern, query string, current func(string) string, allowed AllowedFunc) (pkgMods []QueryResult, modOnly *QueryResult, err error) { func QueryPattern(loaderstate *State, ctx context.Context, pattern, query string, current func(string) string, allowed AllowedFunc) (pkgMods []QueryResult, modOnly *QueryResult, err error) {
ctx, span := trace.StartSpan(ctx, "modload.QueryPattern "+pattern+" "+query) ctx, span := trace.StartSpan(ctx, "modload.QueryPattern "+pattern+" "+query)
defer span.Done() defer span.Done()
@ -693,15 +693,15 @@ func QueryPattern(ctx context.Context, pattern, query string, current func(strin
} }
match = func(mod module.Version, roots []string, isLocal bool) *search.Match { match = func(mod module.Version, roots []string, isLocal bool) *search.Match {
m := search.NewMatch(pattern) m := search.NewMatch(pattern)
matchPackages(ctx, m, imports.AnyTags(), omitStd, []module.Version{mod}) matchPackages(loaderstate, ctx, m, imports.AnyTags(), omitStd, []module.Version{mod})
return m return m
} }
} else { } else {
match = func(mod module.Version, roots []string, isLocal bool) *search.Match { match = func(mod module.Version, roots []string, isLocal bool) *search.Match {
m := search.NewMatch(pattern) m := search.NewMatch(pattern)
prefix := mod.Path prefix := mod.Path
if LoaderState.MainModules.Contains(mod.Path) { if loaderstate.MainModules.Contains(mod.Path) {
prefix = LoaderState.MainModules.PathPrefix(module.Version{Path: mod.Path}) prefix = loaderstate.MainModules.PathPrefix(module.Version{Path: mod.Path})
} }
for _, root := range roots { for _, root := range roots {
if _, ok, err := dirInModule(pattern, prefix, root, isLocal); err != nil { if _, ok, err := dirInModule(pattern, prefix, root, isLocal); err != nil {
@ -715,8 +715,8 @@ func QueryPattern(ctx context.Context, pattern, query string, current func(strin
} }
var mainModuleMatches []module.Version var mainModuleMatches []module.Version
for _, mainModule := range LoaderState.MainModules.Versions() { for _, mainModule := range loaderstate.MainModules.Versions() {
m := match(mainModule, LoaderState.modRoots, true) m := match(mainModule, loaderstate.modRoots, true)
if len(m.Pkgs) > 0 { if len(m.Pkgs) > 0 {
if query != "upgrade" && query != "patch" { if query != "upgrade" && query != "patch" {
return nil, nil, &QueryMatchesPackagesInMainModuleError{ return nil, nil, &QueryMatchesPackagesInMainModuleError{
@ -756,7 +756,7 @@ func QueryPattern(ctx context.Context, pattern, query string, current func(strin
var ( var (
results []QueryResult results []QueryResult
candidateModules = modulePrefixesExcludingTarget(base) candidateModules = modulePrefixesExcludingTarget(loaderstate, base)
) )
if len(candidateModules) == 0 { if len(candidateModules) == 0 {
if modOnly != nil { if modOnly != nil {
@ -783,7 +783,7 @@ func QueryPattern(ctx context.Context, pattern, query string, current func(strin
pathCurrent := current(path) pathCurrent := current(path)
r.Mod.Path = path r.Mod.Path = path
r.Rev, err = queryProxy(ctx, proxy, path, query, pathCurrent, allowed, nil) r.Rev, err = queryProxy(loaderstate, ctx, proxy, path, query, pathCurrent, allowed, nil)
if err != nil { if err != nil {
return r, err return r, err
} }
@ -791,7 +791,7 @@ func QueryPattern(ctx context.Context, pattern, query string, current func(strin
if gover.IsToolchain(r.Mod.Path) { if gover.IsToolchain(r.Mod.Path) {
return r, nil return r, nil
} }
root, isLocal, err := fetch(ctx, r.Mod) root, isLocal, err := fetch(loaderstate, ctx, r.Mod)
if err != nil { if err != nil {
return r, err return r, err
} }
@ -801,7 +801,7 @@ func QueryPattern(ctx context.Context, pattern, query string, current func(strin
if err := firstError(m); err != nil { if err := firstError(m); err != nil {
return r, err return r, err
} }
replacement := Replacement(r.Mod) replacement := Replacement(loaderstate, r.Mod)
return r, &PackageNotInModuleError{ return r, &PackageNotInModuleError{
Mod: r.Mod, Mod: r.Mod,
Replacement: replacement, Replacement: replacement,
@ -812,7 +812,7 @@ func QueryPattern(ctx context.Context, pattern, query string, current func(strin
return r, nil return r, nil
} }
allResults, err := queryPrefixModules(ctx, candidateModules, queryModule) allResults, err := queryPrefixModules(loaderstate, ctx, candidateModules, queryModule)
results = allResults[:0] results = allResults[:0]
for _, r := range allResults { for _, r := range allResults {
if len(r.Packages) == 0 { if len(r.Packages) == 0 {
@ -838,11 +838,11 @@ func QueryPattern(ctx context.Context, pattern, query string, current func(strin
// itself, sorted by descending length. Prefixes that are not valid module paths // itself, sorted by descending length. Prefixes that are not valid module paths
// but are valid package paths (like "m" or "example.com/.gen") are included, // but are valid package paths (like "m" or "example.com/.gen") are included,
// since they might be replaced. // since they might be replaced.
func modulePrefixesExcludingTarget(path string) []string { func modulePrefixesExcludingTarget(loaderstate *State, path string) []string {
prefixes := make([]string, 0, strings.Count(path, "/")+1) prefixes := make([]string, 0, strings.Count(path, "/")+1)
mainModulePrefixes := make(map[string]bool) mainModulePrefixes := make(map[string]bool)
for _, m := range LoaderState.MainModules.Versions() { for _, m := range loaderstate.MainModules.Versions() {
mainModulePrefixes[m.Path] = true mainModulePrefixes[m.Path] = true
} }
@ -863,7 +863,7 @@ func modulePrefixesExcludingTarget(path string) []string {
return prefixes return prefixes
} }
func queryPrefixModules(ctx context.Context, candidateModules []string, queryModule func(ctx context.Context, path string) (QueryResult, error)) (found []QueryResult, err error) { func queryPrefixModules(loaderstate *State, ctx context.Context, candidateModules []string, queryModule func(ctx context.Context, path string) (QueryResult, error)) (found []QueryResult, err error) {
ctx, span := trace.StartSpan(ctx, "modload.queryPrefixModules") ctx, span := trace.StartSpan(ctx, "modload.queryPrefixModules")
defer span.Done() defer span.Done()
@ -905,7 +905,7 @@ func queryPrefixModules(ctx context.Context, candidateModules []string, queryMod
case *PackageNotInModuleError: case *PackageNotInModuleError:
// Given the option, prefer to attribute “package not in module” // Given the option, prefer to attribute “package not in module”
// to modules other than the main one. // to modules other than the main one.
if noPackage == nil || LoaderState.MainModules.Contains(noPackage.Mod.Path) { if noPackage == nil || loaderstate.MainModules.Contains(noPackage.Mod.Path) {
noPackage = rErr noPackage = rErr
} }
case *NoMatchingVersionError: case *NoMatchingVersionError:
@ -1096,8 +1096,8 @@ func (e *PackageNotInModuleError) ImportPath() string {
// go.mod with different content. Second, if we don't fetch the .zip, then // go.mod with different content. Second, if we don't fetch the .zip, then
// we don't need to verify it in go.sum. This makes 'go list -m -u' faster // we don't need to verify it in go.sum. This makes 'go list -m -u' faster
// and simpler. // and simpler.
func versionHasGoMod(_ context.Context, m module.Version) (bool, error) { func versionHasGoMod(loaderstate *State, _ context.Context, m module.Version) (bool, error) {
_, data, err := rawGoModData(m) _, data, err := rawGoModData(loaderstate, m)
if err != nil { if err != nil {
return false, err return false, err
} }
@ -1117,7 +1117,7 @@ type versionRepo interface {
var _ versionRepo = modfetch.Repo(nil) var _ versionRepo = modfetch.Repo(nil)
func lookupRepo(ctx context.Context, proxy, path string) (repo versionRepo, err error) { func lookupRepo(loaderstate *State, ctx context.Context, proxy, path string) (repo versionRepo, err error) {
if path != "go" && path != "toolchain" { if path != "go" && path != "toolchain" {
err = module.CheckPath(path) err = module.CheckPath(path)
} }
@ -1127,9 +1127,9 @@ func lookupRepo(ctx context.Context, proxy, path string) (repo versionRepo, err
repo = emptyRepo{path: path, err: err} repo = emptyRepo{path: path, err: err}
} }
if LoaderState.MainModules == nil { if loaderstate.MainModules == nil {
return repo, err return repo, err
} else if _, ok := LoaderState.MainModules.HighestReplaced()[path]; ok { } else if _, ok := loaderstate.MainModules.HighestReplaced()[path]; ok {
return &replacementRepo{repo: repo}, nil return &replacementRepo{repo: repo}, nil
} }
@ -1239,7 +1239,7 @@ func (rr *replacementRepo) Stat(ctx context.Context, rev string) (*modfetch.RevI
} }
} }
if r := Replacement(module.Version{Path: path, Version: v}); r.Path == "" { if r := Replacement(LoaderState, module.Version{Path: path, Version: v}); r.Path == "" {
return info, err return info, err
} }
return rr.replacementStat(v) return rr.replacementStat(v)

View file

@ -182,7 +182,7 @@ func TestQuery(t *testing.T) {
t.Run(strings.ReplaceAll(tt.path, "/", "_")+"/"+tt.query+"/"+tt.current+"/"+allow, func(t *testing.T) { t.Run(strings.ReplaceAll(tt.path, "/", "_")+"/"+tt.query+"/"+tt.current+"/"+allow, func(t *testing.T) {
t.Parallel() t.Parallel()
info, err := Query(ctx, tt.path, tt.query, tt.current, allowed) info, err := Query(LoaderState, ctx, tt.path, tt.query, tt.current, allowed)
if tt.err != "" { if tt.err != "" {
if err == nil { if err == nil {
t.Errorf("Query(_, %q, %q, %q, %v) = %v, want error %q", tt.path, tt.query, tt.current, allow, info.Version, tt.err) t.Errorf("Query(_, %q, %q, %q, %v) = %v, want error %q", tt.path, tt.query, tt.current, allow, info.Version, tt.err)

View file

@ -41,7 +41,7 @@ const (
// matchPackages is like m.MatchPackages, but uses a local variable (rather than // matchPackages is like m.MatchPackages, but uses a local variable (rather than
// a global) for tags, can include or exclude packages in the standard library, // a global) for tags, can include or exclude packages in the standard library,
// and is restricted to the given list of modules. // and is restricted to the given list of modules.
func matchPackages(ctx context.Context, m *search.Match, tags map[string]bool, filter stdFilter, modules []module.Version) { func matchPackages(loaderstate *State, ctx context.Context, m *search.Match, tags map[string]bool, filter stdFilter, modules []module.Version) {
ctx, span := trace.StartSpan(ctx, "modload.matchPackages") ctx, span := trace.StartSpan(ctx, "modload.matchPackages")
defer span.Done() defer span.Done()
@ -74,7 +74,7 @@ func matchPackages(ctx context.Context, m *search.Match, tags map[string]bool, f
) )
q := par.NewQueue(runtime.GOMAXPROCS(0)) q := par.NewQueue(runtime.GOMAXPROCS(0))
ignorePatternsMap := parseIgnorePatterns(ctx, treeCanMatch, modules) ignorePatternsMap := parseIgnorePatterns(loaderstate, ctx, treeCanMatch, modules)
walkPkgs := func(root, importPathRoot string, prune pruning) { walkPkgs := func(root, importPathRoot string, prune pruning) {
_, span := trace.StartSpan(ctx, "walkPkgs "+root) _, span := trace.StartSpan(ctx, "walkPkgs "+root)
defer span.Done() defer span.Done()
@ -171,13 +171,13 @@ func matchPackages(ctx context.Context, m *search.Match, tags map[string]bool, f
} }
if cfg.BuildMod == "vendor" { if cfg.BuildMod == "vendor" {
for _, mod := range LoaderState.MainModules.Versions() { for _, mod := range loaderstate.MainModules.Versions() {
if modRoot := LoaderState.MainModules.ModRoot(mod); modRoot != "" { if modRoot := loaderstate.MainModules.ModRoot(mod); modRoot != "" {
walkPkgs(modRoot, LoaderState.MainModules.PathPrefix(mod), pruneGoMod|pruneVendor) walkPkgs(modRoot, loaderstate.MainModules.PathPrefix(mod), pruneGoMod|pruneVendor)
} }
} }
if HasModRoot() { if HasModRoot(loaderstate) {
walkPkgs(VendorDir(), "", pruneVendor) walkPkgs(VendorDir(loaderstate), "", pruneVendor)
} }
return return
} }
@ -191,16 +191,16 @@ func matchPackages(ctx context.Context, m *search.Match, tags map[string]bool, f
root, modPrefix string root, modPrefix string
isLocal bool isLocal bool
) )
if LoaderState.MainModules.Contains(mod.Path) { if loaderstate.MainModules.Contains(mod.Path) {
if LoaderState.MainModules.ModRoot(mod) == "" { if loaderstate.MainModules.ModRoot(mod) == "" {
continue // If there is no main module, we can't search in it. continue // If there is no main module, we can't search in it.
} }
root = LoaderState.MainModules.ModRoot(mod) root = loaderstate.MainModules.ModRoot(mod)
modPrefix = LoaderState.MainModules.PathPrefix(mod) modPrefix = loaderstate.MainModules.PathPrefix(mod)
isLocal = true isLocal = true
} else { } else {
var err error var err error
root, isLocal, err = fetch(ctx, mod) root, isLocal, err = fetch(loaderstate, ctx, mod)
if err != nil { if err != nil {
m.AddError(err) m.AddError(err)
continue continue
@ -286,17 +286,17 @@ func walkFromIndex(index *modindex.Module, importPathRoot string, isMatch, treeC
func MatchInModule(ctx context.Context, pattern string, m module.Version, tags map[string]bool) *search.Match { func MatchInModule(ctx context.Context, pattern string, m module.Version, tags map[string]bool) *search.Match {
match := search.NewMatch(pattern) match := search.NewMatch(pattern)
if m == (module.Version{}) { if m == (module.Version{}) {
matchPackages(ctx, match, tags, includeStd, nil) matchPackages(LoaderState, ctx, match, tags, includeStd, nil)
} }
LoadModFile(ctx) // Sets Target, needed by fetch and matchPackages. LoadModFile(LoaderState, ctx) // Sets Target, needed by fetch and matchPackages.
if !match.IsLiteral() { if !match.IsLiteral() {
matchPackages(ctx, match, tags, omitStd, []module.Version{m}) matchPackages(LoaderState, ctx, match, tags, omitStd, []module.Version{m})
return match return match
} }
root, isLocal, err := fetch(ctx, m) root, isLocal, err := fetch(LoaderState, ctx, m)
if err != nil { if err != nil {
match.Errs = []error{err} match.Errs = []error{err}
return match return match
@ -322,7 +322,7 @@ func MatchInModule(ctx context.Context, pattern string, m module.Version, tags m
// parseIgnorePatterns collects all ignore patterns associated with the // parseIgnorePatterns collects all ignore patterns associated with the
// provided list of modules. // provided list of modules.
// It returns a map of module root -> *search.IgnorePatterns. // It returns a map of module root -> *search.IgnorePatterns.
func parseIgnorePatterns(ctx context.Context, treeCanMatch func(string) bool, modules []module.Version) map[string]*search.IgnorePatterns { func parseIgnorePatterns(loaderstate *State, ctx context.Context, treeCanMatch func(string) bool, modules []module.Version) map[string]*search.IgnorePatterns {
ignorePatternsMap := make(map[string]*search.IgnorePatterns) ignorePatternsMap := make(map[string]*search.IgnorePatterns)
for _, mod := range modules { for _, mod := range modules {
if gover.IsToolchain(mod.Path) || !treeCanMatch(mod.Path) { if gover.IsToolchain(mod.Path) || !treeCanMatch(mod.Path) {
@ -330,12 +330,12 @@ func parseIgnorePatterns(ctx context.Context, treeCanMatch func(string) bool, mo
} }
var modRoot string var modRoot string
var ignorePatterns []string var ignorePatterns []string
if LoaderState.MainModules.Contains(mod.Path) { if loaderstate.MainModules.Contains(mod.Path) {
modRoot = LoaderState.MainModules.ModRoot(mod) modRoot = loaderstate.MainModules.ModRoot(mod)
if modRoot == "" { if modRoot == "" {
continue continue
} }
modIndex := LoaderState.MainModules.Index(mod) modIndex := loaderstate.MainModules.Index(mod)
if modIndex == nil { if modIndex == nil {
continue continue
} }
@ -344,11 +344,11 @@ func parseIgnorePatterns(ctx context.Context, treeCanMatch func(string) bool, mo
// Skip getting ignore patterns for vendored modules because they // Skip getting ignore patterns for vendored modules because they
// do not have go.mod files. // do not have go.mod files.
var err error var err error
modRoot, _, err = fetch(ctx, mod) modRoot, _, err = fetch(loaderstate, ctx, mod)
if err != nil { if err != nil {
continue continue
} }
summary, err := goModSummary(mod) summary, err := goModSummary(loaderstate, mod)
if err != nil { if err != nil {
continue continue
} }

View file

@ -140,10 +140,10 @@ func readVendorList(vendorDir string) {
// checkVendorConsistency verifies that the vendor/modules.txt file matches (if // checkVendorConsistency verifies that the vendor/modules.txt file matches (if
// go 1.14) or at least does not contradict (go 1.13 or earlier) the // go 1.14) or at least does not contradict (go 1.13 or earlier) the
// requirements and replacements listed in the main module's go.mod file. // requirements and replacements listed in the main module's go.mod file.
func checkVendorConsistency(indexes []*modFileIndex, modFiles []*modfile.File, modRoots []string) { func checkVendorConsistency(loaderstate *State, indexes []*modFileIndex, modFiles []*modfile.File, modRoots []string) {
// readVendorList only needs the main module to get the directory // readVendorList only needs the main module to get the directory
// the vendor directory is in. // the vendor directory is in.
readVendorList(VendorDir()) readVendorList(VendorDir(loaderstate))
if len(modFiles) < 1 { if len(modFiles) < 1 {
// We should never get here if there are zero modfiles. Either // We should never get here if there are zero modfiles. Either
@ -154,7 +154,7 @@ func checkVendorConsistency(indexes []*modFileIndex, modFiles []*modfile.File, m
} }
pre114 := false pre114 := false
if !inWorkspaceMode() { // workspace mode was added after Go 1.14 if !inWorkspaceMode(loaderstate) { // workspace mode was added after Go 1.14
if len(indexes) != 1 { if len(indexes) != 1 {
panic(fmt.Errorf("not in workspace mode but number of indexes is %v, not 1", len(indexes))) panic(fmt.Errorf("not in workspace mode but number of indexes is %v, not 1", len(indexes)))
} }
@ -215,8 +215,8 @@ func checkVendorConsistency(indexes []*modFileIndex, modFiles []*modfile.File, m
continue // Don't print the same error more than once continue // Don't print the same error more than once
} }
seenrep[r.Old] = true seenrep[r.Old] = true
rNew, modRoot, replacementSource := replacementFrom(r.Old) rNew, modRoot, replacementSource := replacementFrom(loaderstate, r.Old)
rNewCanonical := canonicalizeReplacePath(rNew, modRoot) rNewCanonical := canonicalizeReplacePath(loaderstate, rNew, modRoot)
vr := vendorMeta[r.Old].Replacement vr := vendorMeta[r.Old].Replacement
if vr == (module.Version{}) { if vr == (module.Version{}) {
if rNewCanonical == (module.Version{}) { if rNewCanonical == (module.Version{}) {
@ -236,8 +236,8 @@ func checkVendorConsistency(indexes []*modFileIndex, modFiles []*modfile.File, m
for _, modFile := range modFiles { for _, modFile := range modFiles {
checkReplace(modFile.Replace) checkReplace(modFile.Replace)
} }
if LoaderState.MainModules.workFile != nil { if loaderstate.MainModules.workFile != nil {
checkReplace(LoaderState.MainModules.workFile.Replace) checkReplace(loaderstate.MainModules.workFile.Replace)
} }
for _, mod := range vendorList { for _, mod := range vendorList {
@ -252,7 +252,7 @@ func checkVendorConsistency(indexes []*modFileIndex, modFiles []*modfile.File, m
} }
if !foundRequire { if !foundRequire {
article := "" article := ""
if inWorkspaceMode() { if inWorkspaceMode(loaderstate) {
article = "a " article = "a "
} }
vendErrorf(mod, "is marked as explicit in vendor/modules.txt, but not explicitly required in %vgo.mod", article) vendErrorf(mod, "is marked as explicit in vendor/modules.txt, but not explicitly required in %vgo.mod", article)
@ -262,9 +262,9 @@ func checkVendorConsistency(indexes []*modFileIndex, modFiles []*modfile.File, m
} }
for _, mod := range vendorReplaced { for _, mod := range vendorReplaced {
r := Replacement(mod) r := Replacement(loaderstate, mod)
replacementSource := "go.mod" replacementSource := "go.mod"
if inWorkspaceMode() { if inWorkspaceMode(loaderstate) {
replacementSource = "the workspace" replacementSource = "the workspace"
} }
if r == (module.Version{}) { if r == (module.Version{}) {
@ -276,9 +276,9 @@ func checkVendorConsistency(indexes []*modFileIndex, modFiles []*modfile.File, m
if vendErrors.Len() > 0 { if vendErrors.Len() > 0 {
subcmd := "mod" subcmd := "mod"
if inWorkspaceMode() { if inWorkspaceMode(loaderstate) {
subcmd = "work" subcmd = "work"
} }
base.Fatalf("go: inconsistent vendoring in %s:%s\n\n\tTo ignore the vendor directory, use -mod=readonly or -mod=mod.\n\tTo sync the vendor directory, run:\n\t\tgo %s vendor", filepath.Dir(VendorDir()), vendErrors, subcmd) base.Fatalf("go: inconsistent vendoring in %s:%s\n\n\tTo ignore the vendor directory, use -mod=readonly or -mod=mod.\n\tTo sync the vendor directory, run:\n\t\tgo %s vendor", filepath.Dir(VendorDir(loaderstate)), vendErrors, subcmd)
} }
} }

View file

@ -78,13 +78,13 @@ func runRun(ctx context.Context, cmd *base.Command, args []string) {
// for -race and -msan. // for -race and -msan.
modload.LoaderState.ForceUseModules = true modload.LoaderState.ForceUseModules = true
modload.LoaderState.RootMode = modload.NoRoot modload.LoaderState.RootMode = modload.NoRoot
modload.AllowMissingModuleImports() modload.AllowMissingModuleImports(modload.LoaderState)
modload.Init() modload.Init(modload.LoaderState)
} else { } else {
modload.InitWorkfile() modload.InitWorkfile(modload.LoaderState)
} }
work.BuildInit() work.BuildInit(modload.LoaderState)
b := work.NewBuilder("") b := work.NewBuilder("")
defer func() { defer func() {
if err := b.Close(); err != nil { if err := b.Close(); err != nil {
@ -107,18 +107,18 @@ func runRun(ctx context.Context, cmd *base.Command, args []string) {
base.Fatalf("go: cannot run *_test.go files (%s)", file) base.Fatalf("go: cannot run *_test.go files (%s)", file)
} }
} }
p = load.GoFilesPackage(ctx, pkgOpts, files) p = load.GoFilesPackage(modload.LoaderState, ctx, pkgOpts, files)
} else if len(args) > 0 && !strings.HasPrefix(args[0], "-") { } else if len(args) > 0 && !strings.HasPrefix(args[0], "-") {
arg := args[0] arg := args[0]
var pkgs []*load.Package var pkgs []*load.Package
if strings.Contains(arg, "@") && !build.IsLocalImport(arg) && !filepath.IsAbs(arg) { if strings.Contains(arg, "@") && !build.IsLocalImport(arg) && !filepath.IsAbs(arg) {
var err error var err error
pkgs, err = load.PackagesAndErrorsOutsideModule(ctx, pkgOpts, args[:1]) pkgs, err = load.PackagesAndErrorsOutsideModule(modload.LoaderState, ctx, pkgOpts, args[:1])
if err != nil { if err != nil {
base.Fatal(err) base.Fatal(err)
} }
} else { } else {
pkgs = load.PackagesAndErrors(ctx, pkgOpts, args[:1]) pkgs = load.PackagesAndErrors(modload.LoaderState, ctx, pkgOpts, args[:1])
} }
if len(pkgs) == 0 { if len(pkgs) == 0 {
@ -140,7 +140,7 @@ func runRun(ctx context.Context, cmd *base.Command, args []string) {
load.CheckPackageErrors([]*load.Package{p}) load.CheckPackageErrors([]*load.Package{p})
if cfg.BuildCover { if cfg.BuildCover {
load.PrepareForCoverageBuild([]*load.Package{p}) load.PrepareForCoverageBuild(modload.LoaderState, []*load.Package{p})
} }
p.Internal.OmitDebug = true p.Internal.OmitDebug = true
@ -166,7 +166,7 @@ func runRun(ctx context.Context, cmd *base.Command, args []string) {
p.Internal.ExeName = p.DefaultExecName() p.Internal.ExeName = p.DefaultExecName()
} }
a1 := b.LinkAction(work.ModeBuild, work.ModeBuild, p) a1 := b.LinkAction(modload.LoaderState, work.ModeBuild, work.ModeBuild, p)
a1.CacheExecutable = true a1.CacheExecutable = true
a := &work.Action{Mode: "go run", Actor: work.ActorFunc(buildRunProgram), Args: cmdArgs, Deps: []*work.Action{a1}} a := &work.Action{Mode: "go run", Actor: work.ActorFunc(buildRunProgram), Args: cmdArgs, Deps: []*work.Action{a1}}
b.Do(ctx, a) b.Do(ctx, a)

View file

@ -24,7 +24,7 @@ func Increment() {
func incrementConfig() { func incrementConfig() {
if !modload.WillBeEnabled() { if !modload.WillBeEnabled() {
counter.Inc("go/mode:gopath") counter.Inc("go/mode:gopath")
} else if workfile := modload.FindGoWork(base.Cwd()); workfile != "" { } else if workfile := modload.FindGoWork(modload.LoaderState, base.Cwd()); workfile != "" {
counter.Inc("go/mode:workspace") counter.Inc("go/mode:workspace")
} else { } else {
counter.Inc("go/mode:module") counter.Inc("go/mode:module")

View file

@ -683,7 +683,7 @@ var defaultVetFlags = []string{
func runTest(ctx context.Context, cmd *base.Command, args []string) { func runTest(ctx context.Context, cmd *base.Command, args []string) {
pkgArgs, testArgs = testFlags(args) pkgArgs, testArgs = testFlags(args)
modload.InitWorkfile() // The test command does custom flag processing; initialize workspaces after that. modload.InitWorkfile(modload.LoaderState) // The test command does custom flag processing; initialize workspaces after that.
if cfg.DebugTrace != "" { if cfg.DebugTrace != "" {
var close func() error var close func() error
@ -704,13 +704,13 @@ func runTest(ctx context.Context, cmd *base.Command, args []string) {
work.FindExecCmd() // initialize cached result work.FindExecCmd() // initialize cached result
work.BuildInit() work.BuildInit(modload.LoaderState)
work.VetFlags = testVet.flags work.VetFlags = testVet.flags
work.VetExplicit = testVet.explicit work.VetExplicit = testVet.explicit
work.VetTool = base.Tool("vet") work.VetTool = base.Tool("vet")
pkgOpts := load.PackageOpts{ModResolveTests: true} pkgOpts := load.PackageOpts{ModResolveTests: true}
pkgs = load.PackagesAndErrors(ctx, pkgOpts, pkgArgs) pkgs = load.PackagesAndErrors(modload.LoaderState, ctx, pkgOpts, pkgArgs)
// We *don't* call load.CheckPackageErrors here because we want to report // We *don't* call load.CheckPackageErrors here because we want to report
// loading errors as per-package test setup errors later. // loading errors as per-package test setup errors later.
if len(pkgs) == 0 { if len(pkgs) == 0 {
@ -741,7 +741,7 @@ func runTest(ctx context.Context, cmd *base.Command, args []string) {
if !mainMods.Contains(m.Path) { if !mainMods.Contains(m.Path) {
base.Fatalf("cannot use -fuzz flag on package outside the main module") base.Fatalf("cannot use -fuzz flag on package outside the main module")
} }
} else if pkgs[0].Standard && modload.Enabled() { } else if pkgs[0].Standard && modload.Enabled(modload.LoaderState) {
// Because packages in 'std' and 'cmd' are part of the standard library, // Because packages in 'std' and 'cmd' are part of the standard library,
// they are only treated as part of a module in 'go mod' subcommands and // they are only treated as part of a module in 'go mod' subcommands and
// 'go get'. However, we still don't want to accidentally corrupt their // 'go get'. However, we still don't want to accidentally corrupt their
@ -867,13 +867,13 @@ func runTest(ctx context.Context, cmd *base.Command, args []string) {
if cfg.BuildCoverPkg != nil { if cfg.BuildCoverPkg != nil {
match := make([]func(*load.Package) bool, len(cfg.BuildCoverPkg)) match := make([]func(*load.Package) bool, len(cfg.BuildCoverPkg))
for i := range cfg.BuildCoverPkg { for i := range cfg.BuildCoverPkg {
match[i] = load.MatchPackage(cfg.BuildCoverPkg[i], base.Cwd()) match[i] = load.MatchPackage(modload.LoaderState, cfg.BuildCoverPkg[i], base.Cwd())
} }
// Select for coverage all dependencies matching the -coverpkg // Select for coverage all dependencies matching the -coverpkg
// patterns. // patterns.
plist := load.TestPackageList(ctx, pkgOpts, pkgs) plist := load.TestPackageList(ctx, pkgOpts, pkgs)
testCoverPkgs = load.SelectCoverPackages(plist, match, "test") testCoverPkgs = load.SelectCoverPackages(modload.LoaderState, plist, match, "test")
if len(testCoverPkgs) > 0 { if len(testCoverPkgs) > 0 {
// create a new singleton action that will collect up the // create a new singleton action that will collect up the
// meta-data files from all of the packages mentioned in // meta-data files from all of the packages mentioned in
@ -981,7 +981,7 @@ func runTest(ctx context.Context, cmd *base.Command, args []string) {
// happens we'll wind up building the Q compile action // happens we'll wind up building the Q compile action
// before updating its deps to include sync/atomic). // before updating its deps to include sync/atomic).
if cfg.BuildCoverMode == "atomic" && p.ImportPath != "sync/atomic" { if cfg.BuildCoverMode == "atomic" && p.ImportPath != "sync/atomic" {
load.EnsureImport(p, "sync/atomic") load.EnsureImport(modload.LoaderState, p, "sync/atomic")
} }
// Tag the package for static meta-data generation if no // Tag the package for static meta-data generation if no
// test files (this works only with the new coverage // test files (this works only with the new coverage
@ -1221,7 +1221,7 @@ func builderTest(b *work.Builder, ctx context.Context, pkgOpts load.PackageOpts,
} }
} }
a := b.LinkAction(work.ModeBuild, work.ModeBuild, pmain) a := b.LinkAction(modload.LoaderState, work.ModeBuild, work.ModeBuild, pmain)
a.Target = testDir + testBinary + cfg.ExeSuffix a.Target = testDir + testBinary + cfg.ExeSuffix
if cfg.Goos == "windows" { if cfg.Goos == "windows" {
// There are many reserved words on Windows that, // There are many reserved words on Windows that,

View file

@ -161,8 +161,8 @@ func listTools(ctx context.Context) {
fmt.Println(name) fmt.Println(name)
} }
modload.InitWorkfile() modload.InitWorkfile(modload.LoaderState)
modload.LoadModFile(ctx) modload.LoadModFile(modload.LoaderState, ctx)
modTools := slices.Sorted(maps.Keys(modload.LoaderState.MainModules.Tools())) modTools := slices.Sorted(maps.Keys(modload.LoaderState.MainModules.Tools()))
for _, tool := range modTools { for _, tool := range modTools {
fmt.Println(tool) fmt.Println(tool)
@ -252,8 +252,8 @@ func loadBuiltinTool(toolName string) string {
} }
func loadModTool(ctx context.Context, name string) string { func loadModTool(ctx context.Context, name string) string {
modload.InitWorkfile() modload.InitWorkfile(modload.LoaderState)
modload.LoadModFile(ctx) modload.LoadModFile(modload.LoaderState, ctx)
matches := []string{} matches := []string{}
for tool := range modload.LoaderState.MainModules.Tools() { for tool := range modload.LoaderState.MainModules.Tools() {
@ -336,7 +336,7 @@ func buildAndRunModtool(ctx context.Context, toolName, tool string, args []strin
} }
func buildAndRunTool(ctx context.Context, tool string, args []string, runTool work.ActorFunc) { func buildAndRunTool(ctx context.Context, tool string, args []string, runTool work.ActorFunc) {
work.BuildInit() work.BuildInit(modload.LoaderState)
b := work.NewBuilder("") b := work.NewBuilder("")
defer func() { defer func() {
if err := b.Close(); err != nil { if err := b.Close(); err != nil {
@ -345,11 +345,11 @@ func buildAndRunTool(ctx context.Context, tool string, args []string, runTool wo
}() }()
pkgOpts := load.PackageOpts{MainOnly: true} pkgOpts := load.PackageOpts{MainOnly: true}
p := load.PackagesAndErrors(ctx, pkgOpts, []string{tool})[0] p := load.PackagesAndErrors(modload.LoaderState, ctx, pkgOpts, []string{tool})[0]
p.Internal.OmitDebug = true p.Internal.OmitDebug = true
p.Internal.ExeName = p.DefaultExecName() p.Internal.ExeName = p.DefaultExecName()
a1 := b.LinkAction(work.ModeBuild, work.ModeBuild, p) a1 := b.LinkAction(modload.LoaderState, work.ModeBuild, work.ModeBuild, p)
a1.CacheExecutable = true a1.CacheExecutable = true
a := &work.Action{Mode: "go tool", Actor: runTool, Args: args, Deps: []*work.Action{a1}} a := &work.Action{Mode: "go tool", Actor: runTool, Args: args, Deps: []*work.Action{a1}}
b.Do(ctx, a) b.Do(ctx, a)

View file

@ -355,7 +355,7 @@ func Exec(gotoolchain string) {
modload.Reset() modload.Reset()
modload.LoaderState.ForceUseModules = true modload.LoaderState.ForceUseModules = true
modload.LoaderState.RootMode = modload.NoRoot modload.LoaderState.RootMode = modload.NoRoot
modload.Init() modload.Init(modload.LoaderState)
// Download and unpack toolchain module into module cache. // Download and unpack toolchain module into module cache.
// Note that multiple go commands might be doing this at the same time, // Note that multiple go commands might be doing this at the same time,
@ -529,7 +529,7 @@ func raceSafeCopy(old, new string) error {
// The toolchain line overrides the version line // The toolchain line overrides the version line
func modGoToolchain() (file, goVers, toolchain string) { func modGoToolchain() (file, goVers, toolchain string) {
wd := base.UncachedCwd() wd := base.UncachedCwd()
file = modload.FindGoWork(wd) file = modload.FindGoWork(modload.LoaderState, wd)
// $GOWORK can be set to a file that does not yet exist, if we are running 'go work init'. // $GOWORK can be set to a file that does not yet exist, if we are running 'go work init'.
// Do not try to load the file in that case // Do not try to load the file in that case
if _, err := os.Stat(file); err != nil { if _, err := os.Stat(file); err != nil {
@ -694,7 +694,7 @@ func maybeSwitchForGoInstallVersion(minVers string) {
// Set up modules without an explicit go.mod, to download go.mod. // Set up modules without an explicit go.mod, to download go.mod.
modload.LoaderState.ForceUseModules = true modload.LoaderState.ForceUseModules = true
modload.LoaderState.RootMode = modload.NoRoot modload.LoaderState.RootMode = modload.NoRoot
modload.Init() modload.Init(modload.LoaderState)
defer modload.Reset() defer modload.Reset()
// See internal/load.PackagesAndErrorsOutsideModule // See internal/load.PackagesAndErrorsOutsideModule
@ -705,7 +705,7 @@ func maybeSwitchForGoInstallVersion(minVers string) {
allowed = nil allowed = nil
} }
noneSelected := func(path string) (version string) { return "none" } noneSelected := func(path string) (version string) { return "none" }
_, err := modload.QueryPackages(ctx, path, version, noneSelected, allowed) _, err := modload.QueryPackages(modload.LoaderState, ctx, path, version, noneSelected, allowed)
if errors.Is(err, gover.ErrTooNew) { if errors.Is(err, gover.ErrTooNew) {
// Run early switch, same one go install or go run would eventually do, // Run early switch, same one go install or go run would eventually do,
// if it understood all the command-line flags. // if it understood all the command-line flags.

View file

@ -123,7 +123,7 @@ func run(ctx context.Context, cmd *base.Command, args []string) {
// The vet/fix commands do custom flag processing; // The vet/fix commands do custom flag processing;
// initialize workspaces after that. // initialize workspaces after that.
modload.InitWorkfile() modload.InitWorkfile(modload.LoaderState)
if cfg.DebugTrace != "" { if cfg.DebugTrace != "" {
var close func() error var close func() error
@ -142,7 +142,7 @@ func run(ctx context.Context, cmd *base.Command, args []string) {
ctx, span := trace.StartSpan(ctx, fmt.Sprint("Running ", cmd.Name(), " command")) ctx, span := trace.StartSpan(ctx, fmt.Sprint("Running ", cmd.Name(), " command"))
defer span.Done() defer span.Done()
work.BuildInit() work.BuildInit(modload.LoaderState)
// Flag theory: // Flag theory:
// //
@ -217,7 +217,7 @@ func run(ctx context.Context, cmd *base.Command, args []string) {
work.VetFlags = toolFlags work.VetFlags = toolFlags
pkgOpts := load.PackageOpts{ModResolveTests: true} pkgOpts := load.PackageOpts{ModResolveTests: true}
pkgs := load.PackagesAndErrors(ctx, pkgOpts, pkgArgs) pkgs := load.PackagesAndErrors(modload.LoaderState, ctx, pkgOpts, pkgArgs)
load.CheckPackageErrors(pkgs) load.CheckPackageErrors(pkgs)
if len(pkgs) == 0 { if len(pkgs) == 0 {
base.Fatalf("no packages to %s", cmd.Name()) base.Fatalf("no packages to %s", cmd.Name())

View file

@ -28,6 +28,7 @@ import (
"cmd/go/internal/cache" "cmd/go/internal/cache"
"cmd/go/internal/cfg" "cmd/go/internal/cfg"
"cmd/go/internal/load" "cmd/go/internal/load"
"cmd/go/internal/modload"
"cmd/go/internal/str" "cmd/go/internal/str"
"cmd/go/internal/trace" "cmd/go/internal/trace"
"cmd/internal/buildid" "cmd/internal/buildid"
@ -392,7 +393,7 @@ func (b *Builder) NewObjdir() string {
// at shlibpath. For the native toolchain this list is stored, newline separated, in // at shlibpath. For the native toolchain this list is stored, newline separated, in
// an ELF note with name "Go\x00\x00" and type 1. For GCCGO it is extracted from the // an ELF note with name "Go\x00\x00" and type 1. For GCCGO it is extracted from the
// .go_export section. // .go_export section.
func readpkglist(shlibpath string) (pkgs []*load.Package) { func readpkglist(loaderstate *modload.State, shlibpath string) (pkgs []*load.Package) {
var stk load.ImportStack var stk load.ImportStack
if cfg.BuildToolchainName == "gccgo" { if cfg.BuildToolchainName == "gccgo" {
f, err := elf.Open(shlibpath) f, err := elf.Open(shlibpath)
@ -412,7 +413,7 @@ func readpkglist(shlibpath string) (pkgs []*load.Package) {
for _, line := range bytes.Split(data, []byte{'\n'}) { for _, line := range bytes.Split(data, []byte{'\n'}) {
if path, found := bytes.CutPrefix(line, pkgpath); found { if path, found := bytes.CutPrefix(line, pkgpath); found {
path = bytes.TrimSuffix(path, []byte{';'}) path = bytes.TrimSuffix(path, []byte{';'})
pkgs = append(pkgs, load.LoadPackageWithFlags(string(path), base.Cwd(), &stk, nil, 0)) pkgs = append(pkgs, load.LoadPackageWithFlags(loaderstate, string(path), base.Cwd(), &stk, nil, 0))
} }
} }
} else { } else {
@ -423,7 +424,7 @@ func readpkglist(shlibpath string) (pkgs []*load.Package) {
scanner := bufio.NewScanner(bytes.NewBuffer(pkglistbytes)) scanner := bufio.NewScanner(bytes.NewBuffer(pkglistbytes))
for scanner.Scan() { for scanner.Scan() {
t := scanner.Text() t := scanner.Text()
pkgs = append(pkgs, load.LoadPackageWithFlags(t, base.Cwd(), &stk, nil, 0)) pkgs = append(pkgs, load.LoadPackageWithFlags(loaderstate, t, base.Cwd(), &stk, nil, 0))
} }
} }
return return
@ -445,7 +446,7 @@ func (b *Builder) cacheAction(mode string, p *load.Package, f func() *Action) *A
// AutoAction returns the "right" action for go build or go install of p. // AutoAction returns the "right" action for go build or go install of p.
func (b *Builder) AutoAction(mode, depMode BuildMode, p *load.Package) *Action { func (b *Builder) AutoAction(mode, depMode BuildMode, p *load.Package) *Action {
if p.Name == "main" { if p.Name == "main" {
return b.LinkAction(mode, depMode, p) return b.LinkAction(modload.LoaderState, mode, depMode, p)
} }
return b.CompileAction(mode, depMode, p) return b.CompileAction(mode, depMode, p)
} }
@ -913,7 +914,7 @@ func (b *Builder) vetAction(mode, depMode BuildMode, p *load.Package) *Action {
// LinkAction returns the action for linking p into an executable // LinkAction returns the action for linking p into an executable
// and possibly installing the result (according to mode). // and possibly installing the result (according to mode).
// depMode is the action (build or install) to use when compiling dependencies. // depMode is the action (build or install) to use when compiling dependencies.
func (b *Builder) LinkAction(mode, depMode BuildMode, p *load.Package) *Action { func (b *Builder) LinkAction(loaderstate *modload.State, mode, depMode BuildMode, p *load.Package) *Action {
// Construct link action. // Construct link action.
a := b.cacheAction("link", p, func() *Action { a := b.cacheAction("link", p, func() *Action {
a := &Action{ a := &Action{
@ -948,7 +949,7 @@ func (b *Builder) LinkAction(mode, depMode BuildMode, p *load.Package) *Action {
} }
a.Target = a.Objdir + filepath.Join("exe", name) + cfg.ExeSuffix a.Target = a.Objdir + filepath.Join("exe", name) + cfg.ExeSuffix
a.built = a.Target a.built = a.Target
b.addTransitiveLinkDeps(a, a1, "") b.addTransitiveLinkDeps(loaderstate, a, a1, "")
// Sequence the build of the main package (a1) strictly after the build // Sequence the build of the main package (a1) strictly after the build
// of all other dependencies that go into the link. It is likely to be after // of all other dependencies that go into the link. It is likely to be after
@ -1034,7 +1035,7 @@ func (b *Builder) installAction(a1 *Action, mode BuildMode) *Action {
// makes sure those are present in a.Deps. // makes sure those are present in a.Deps.
// If shlib is non-empty, then a corresponds to the build and installation of shlib, // If shlib is non-empty, then a corresponds to the build and installation of shlib,
// so any rebuild of shlib should not be added as a dependency. // so any rebuild of shlib should not be added as a dependency.
func (b *Builder) addTransitiveLinkDeps(a, a1 *Action, shlib string) { func (b *Builder) addTransitiveLinkDeps(loaderstate *modload.State, a, a1 *Action, shlib string) {
// Expand Deps to include all built packages, for the linker. // Expand Deps to include all built packages, for the linker.
// Use breadth-first search to find rebuilt-for-test packages // Use breadth-first search to find rebuilt-for-test packages
// before the standard ones. // before the standard ones.
@ -1075,7 +1076,7 @@ func (b *Builder) addTransitiveLinkDeps(a, a1 *Action, shlib string) {
// we'll end up building an overall library or executable that depends at runtime // we'll end up building an overall library or executable that depends at runtime
// on other libraries that are out-of-date, which is clearly not good either. // on other libraries that are out-of-date, which is clearly not good either.
// We call it ModeBuggyInstall to make clear that this is not right. // We call it ModeBuggyInstall to make clear that this is not right.
a.Deps = append(a.Deps, b.linkSharedAction(ModeBuggyInstall, ModeBuggyInstall, p1.Shlib, nil)) a.Deps = append(a.Deps, b.linkSharedAction(loaderstate, ModeBuggyInstall, ModeBuggyInstall, p1.Shlib, nil))
} }
} }
} }
@ -1116,21 +1117,21 @@ func (b *Builder) buildmodeShared(mode, depMode BuildMode, args []string, pkgs [
if err != nil { if err != nil {
base.Fatalf("%v", err) base.Fatalf("%v", err)
} }
return b.linkSharedAction(mode, depMode, name, a1) return b.linkSharedAction(modload.LoaderState, mode, depMode, name, a1)
} }
// linkSharedAction takes a grouping action a1 corresponding to a list of built packages // linkSharedAction takes a grouping action a1 corresponding to a list of built packages
// and returns an action that links them together into a shared library with the name shlib. // and returns an action that links them together into a shared library with the name shlib.
// If a1 is nil, shlib should be an absolute path to an existing shared library, // If a1 is nil, shlib should be an absolute path to an existing shared library,
// and then linkSharedAction reads that library to find out the package list. // and then linkSharedAction reads that library to find out the package list.
func (b *Builder) linkSharedAction(mode, depMode BuildMode, shlib string, a1 *Action) *Action { func (b *Builder) linkSharedAction(loaderstate *modload.State, mode, depMode BuildMode, shlib string, a1 *Action) *Action {
fullShlib := shlib fullShlib := shlib
shlib = filepath.Base(shlib) shlib = filepath.Base(shlib)
a := b.cacheAction("build-shlib "+shlib, nil, func() *Action { a := b.cacheAction("build-shlib "+shlib, nil, func() *Action {
if a1 == nil { if a1 == nil {
// TODO(rsc): Need to find some other place to store config, // TODO(rsc): Need to find some other place to store config,
// not in pkg directory. See golang.org/issue/22196. // not in pkg directory. See golang.org/issue/22196.
pkgs := readpkglist(fullShlib) pkgs := readpkglist(loaderstate, fullShlib)
a1 = &Action{ a1 = &Action{
Mode: "shlib packages", Mode: "shlib packages",
} }
@ -1173,7 +1174,7 @@ func (b *Builder) linkSharedAction(mode, depMode BuildMode, shlib string, a1 *Ac
} }
} }
var stk load.ImportStack var stk load.ImportStack
p := load.LoadPackageWithFlags(pkg, base.Cwd(), &stk, nil, 0) p := load.LoadPackageWithFlags(loaderstate, pkg, base.Cwd(), &stk, nil, 0)
if p.Error != nil { if p.Error != nil {
base.Fatalf("load %s: %v", pkg, p.Error) base.Fatalf("load %s: %v", pkg, p.Error)
} }
@ -1201,7 +1202,7 @@ func (b *Builder) linkSharedAction(mode, depMode BuildMode, shlib string, a1 *Ac
add(a, dep, true) add(a, dep, true)
} }
} }
b.addTransitiveLinkDeps(a, a1, shlib) b.addTransitiveLinkDeps(loaderstate, a, a1, shlib)
return a return a
}) })

View file

@ -459,8 +459,8 @@ func oneMainPkg(pkgs []*load.Package) []*load.Package {
var pkgsFilter = func(pkgs []*load.Package) []*load.Package { return pkgs } var pkgsFilter = func(pkgs []*load.Package) []*load.Package { return pkgs }
func runBuild(ctx context.Context, cmd *base.Command, args []string) { func runBuild(ctx context.Context, cmd *base.Command, args []string) {
modload.InitWorkfile() modload.InitWorkfile(modload.LoaderState)
BuildInit() BuildInit(modload.LoaderState)
b := NewBuilder("") b := NewBuilder("")
defer func() { defer func() {
if err := b.Close(); err != nil { if err := b.Close(); err != nil {
@ -468,7 +468,7 @@ func runBuild(ctx context.Context, cmd *base.Command, args []string) {
} }
}() }()
pkgs := load.PackagesAndErrors(ctx, load.PackageOpts{AutoVCS: true}, args) pkgs := load.PackagesAndErrors(modload.LoaderState, ctx, load.PackageOpts{AutoVCS: true}, args)
load.CheckPackageErrors(pkgs) load.CheckPackageErrors(pkgs)
explicitO := len(cfg.BuildO) > 0 explicitO := len(cfg.BuildO) > 0
@ -503,7 +503,7 @@ func runBuild(ctx context.Context, cmd *base.Command, args []string) {
} }
if cfg.BuildCover { if cfg.BuildCover {
load.PrepareForCoverageBuild(pkgs) load.PrepareForCoverageBuild(modload.LoaderState, pkgs)
} }
if cfg.BuildO != "" { if cfg.BuildO != "" {
@ -694,10 +694,10 @@ func runInstall(ctx context.Context, cmd *base.Command, args []string) {
} }
} }
modload.InitWorkfile() modload.InitWorkfile(modload.LoaderState)
BuildInit() BuildInit(modload.LoaderState)
pkgs := load.PackagesAndErrors(ctx, load.PackageOpts{AutoVCS: true}, args) pkgs := load.PackagesAndErrors(modload.LoaderState, ctx, load.PackageOpts{AutoVCS: true}, args)
if cfg.ModulesEnabled && !modload.HasModRoot() { if cfg.ModulesEnabled && !modload.HasModRoot(modload.LoaderState) {
haveErrors := false haveErrors := false
allMissingErrors := true allMissingErrors := true
for _, pkg := range pkgs { for _, pkg := range pkgs {
@ -722,7 +722,7 @@ func runInstall(ctx context.Context, cmd *base.Command, args []string) {
load.CheckPackageErrors(pkgs) load.CheckPackageErrors(pkgs)
if cfg.BuildCover { if cfg.BuildCover {
load.PrepareForCoverageBuild(pkgs) load.PrepareForCoverageBuild(modload.LoaderState, pkgs)
} }
InstallPackages(ctx, args, pkgs) InstallPackages(ctx, args, pkgs)
@ -861,9 +861,9 @@ func InstallPackages(ctx context.Context, patterns []string, pkgs []*load.Packag
func installOutsideModule(ctx context.Context, args []string) { func installOutsideModule(ctx context.Context, args []string) {
modload.LoaderState.ForceUseModules = true modload.LoaderState.ForceUseModules = true
modload.LoaderState.RootMode = modload.NoRoot modload.LoaderState.RootMode = modload.NoRoot
modload.AllowMissingModuleImports() modload.AllowMissingModuleImports(modload.LoaderState)
modload.Init() modload.Init(modload.LoaderState)
BuildInit() BuildInit(modload.LoaderState)
// Load packages. Ignore non-main packages. // Load packages. Ignore non-main packages.
// Print a warning if an argument contains "..." and matches no main packages. // Print a warning if an argument contains "..." and matches no main packages.
@ -872,7 +872,7 @@ func installOutsideModule(ctx context.Context, args []string) {
// TODO(golang.org/issue/40276): don't report errors loading non-main packages // TODO(golang.org/issue/40276): don't report errors loading non-main packages
// matched by a pattern. // matched by a pattern.
pkgOpts := load.PackageOpts{MainOnly: true} pkgOpts := load.PackageOpts{MainOnly: true}
pkgs, err := load.PackagesAndErrorsOutsideModule(ctx, pkgOpts, args) pkgs, err := load.PackagesAndErrorsOutsideModule(modload.LoaderState, ctx, pkgOpts, args)
if err != nil { if err != nil {
base.Fatal(err) base.Fatal(err)
} }

View file

@ -2193,7 +2193,7 @@ func (noToolchain) cc(b *Builder, a *Action, ofile, cfile string) error {
// gcc runs the gcc C compiler to create an object from a single C file. // gcc runs the gcc C compiler to create an object from a single C file.
func (b *Builder) gcc(a *Action, workdir, out string, flags []string, cfile string) error { func (b *Builder) gcc(a *Action, workdir, out string, flags []string, cfile string) error {
p := a.Package p := a.Package
return b.ccompile(a, out, flags, cfile, b.GccCmd(p.Dir, workdir)) return b.ccompile(modload.LoaderState, a, out, flags, cfile, b.GccCmd(p.Dir, workdir))
} }
// gas runs the gcc c compiler to create an object file from a single C assembly file. // gas runs the gcc c compiler to create an object file from a single C assembly file.
@ -2207,23 +2207,23 @@ func (b *Builder) gas(a *Action, workdir, out string, flags []string, sfile stri
return fmt.Errorf("package using cgo has Go assembly file %s", sfile) return fmt.Errorf("package using cgo has Go assembly file %s", sfile)
} }
} }
return b.ccompile(a, out, flags, sfile, b.GccCmd(p.Dir, workdir)) return b.ccompile(modload.LoaderState, a, out, flags, sfile, b.GccCmd(p.Dir, workdir))
} }
// gxx runs the g++ C++ compiler to create an object from a single C++ file. // gxx runs the g++ C++ compiler to create an object from a single C++ file.
func (b *Builder) gxx(a *Action, workdir, out string, flags []string, cxxfile string) error { func (b *Builder) gxx(a *Action, workdir, out string, flags []string, cxxfile string) error {
p := a.Package p := a.Package
return b.ccompile(a, out, flags, cxxfile, b.GxxCmd(p.Dir, workdir)) return b.ccompile(modload.LoaderState, a, out, flags, cxxfile, b.GxxCmd(p.Dir, workdir))
} }
// gfortran runs the gfortran Fortran compiler to create an object from a single Fortran file. // gfortran runs the gfortran Fortran compiler to create an object from a single Fortran file.
func (b *Builder) gfortran(a *Action, workdir, out string, flags []string, ffile string) error { func (b *Builder) gfortran(a *Action, workdir, out string, flags []string, ffile string) error {
p := a.Package p := a.Package
return b.ccompile(a, out, flags, ffile, b.gfortranCmd(p.Dir, workdir)) return b.ccompile(modload.LoaderState, a, out, flags, ffile, b.gfortranCmd(p.Dir, workdir))
} }
// ccompile runs the given C or C++ compiler and creates an object from a single source file. // ccompile runs the given C or C++ compiler and creates an object from a single source file.
func (b *Builder) ccompile(a *Action, outfile string, flags []string, file string, compiler []string) error { func (b *Builder) ccompile(loaderstate *modload.State, a *Action, outfile string, flags []string, file string, compiler []string) error {
p := a.Package p := a.Package
sh := b.Shell(a) sh := b.Shell(a)
file = mkAbs(p.Dir, file) file = mkAbs(p.Dir, file)
@ -2260,7 +2260,7 @@ func (b *Builder) ccompile(a *Action, outfile string, flags []string, file strin
} else if m.Dir == "" { } else if m.Dir == "" {
// The module is in the vendor directory. Replace the entire vendor // The module is in the vendor directory. Replace the entire vendor
// directory path, because the module's Dir is not filled in. // directory path, because the module's Dir is not filled in.
from = modload.VendorDir() from = modload.VendorDir(loaderstate)
toPath = "vendor" toPath = "vendor"
} else { } else {
from = m.Dir from = m.Dir
@ -2310,7 +2310,7 @@ func (b *Builder) ccompile(a *Action, outfile string, flags []string, file strin
} }
} }
if len(newFlags) < len(flags) { if len(newFlags) < len(flags) {
return b.ccompile(a, outfile, newFlags, file, compiler) return b.ccompile(loaderstate, a, outfile, newFlags, file, compiler)
} }
} }
@ -3383,7 +3383,7 @@ func (b *Builder) swigDoIntSize(objdir string) (intsize string, err error) {
} }
srcs := []string{src} srcs := []string{src}
p := load.GoFilesPackage(context.TODO(), load.PackageOpts{}, srcs) p := load.GoFilesPackage(modload.LoaderState, context.TODO(), load.PackageOpts{}, srcs)
if _, _, e := BuildToolchain.gc(b, &Action{Mode: "swigDoIntSize", Package: p, Objdir: objdir}, "", nil, nil, "", false, "", srcs); e != nil { if _, _, e := BuildToolchain.gc(b, &Action{Mode: "swigDoIntSize", Package: p, Objdir: objdir}, "", nil, nil, "", false, "", srcs); e != nil {
return "32", nil return "32", nil

View file

@ -50,14 +50,14 @@ func makeCfgChangedEnv() []string {
return slices.Clip(env) return slices.Clip(env)
} }
func BuildInit() { func BuildInit(loaderstate *modload.State) {
if buildInitStarted { if buildInitStarted {
base.Fatalf("go: internal error: work.BuildInit called more than once") base.Fatalf("go: internal error: work.BuildInit called more than once")
} }
buildInitStarted = true buildInitStarted = true
base.AtExit(closeBuilders) base.AtExit(closeBuilders)
modload.Init() modload.Init(loaderstate)
instrumentInit() instrumentInit()
buildModeInit() buildModeInit()
cfgChangedEnv = makeCfgChangedEnv() cfgChangedEnv = makeCfgChangedEnv()

View file

@ -143,8 +143,8 @@ func runEditwork(ctx context.Context, cmd *base.Command, args []string) {
if len(args) == 1 { if len(args) == 1 {
gowork = args[0] gowork = args[0]
} else { } else {
modload.InitWorkfile() modload.InitWorkfile(modload.LoaderState)
gowork = modload.WorkFilePath() gowork = modload.WorkFilePath(modload.LoaderState)
} }
if gowork == "" { if gowork == "" {
base.Fatalf("go: no go.work file found\n\t(run 'go work init' first or specify path using GOWORK environment variable)") base.Fatalf("go: no go.work file found\n\t(run 'go work init' first or specify path using GOWORK environment variable)")

View file

@ -44,11 +44,11 @@ func init() {
} }
func runInit(ctx context.Context, cmd *base.Command, args []string) { func runInit(ctx context.Context, cmd *base.Command, args []string) {
modload.InitWorkfile() modload.InitWorkfile(modload.LoaderState)
modload.LoaderState.ForceUseModules = true modload.LoaderState.ForceUseModules = true
gowork := modload.WorkFilePath() gowork := modload.WorkFilePath(modload.LoaderState)
if gowork == "" { if gowork == "" {
gowork = filepath.Join(base.Cwd(), "go.work") gowork = filepath.Join(base.Cwd(), "go.work")
} }

View file

@ -49,8 +49,8 @@ func init() {
func runSync(ctx context.Context, cmd *base.Command, args []string) { func runSync(ctx context.Context, cmd *base.Command, args []string) {
modload.LoaderState.ForceUseModules = true modload.LoaderState.ForceUseModules = true
modload.InitWorkfile() modload.InitWorkfile(modload.LoaderState)
if modload.WorkFilePath() == "" { if modload.WorkFilePath(modload.LoaderState) == "" {
base.Fatalf("go: no go.work file found\n\t(run 'go work init' first or specify path using GOWORK environment variable)") base.Fatalf("go: no go.work file found\n\t(run 'go work init' first or specify path using GOWORK environment variable)")
} }
@ -73,7 +73,7 @@ func runSync(ctx context.Context, cmd *base.Command, args []string) {
} }
for _, m := range mms.Versions() { for _, m := range mms.Versions() {
opts.MainModule = m opts.MainModule = m
_, pkgs := modload.LoadPackages(ctx, opts, "all") _, pkgs := modload.LoadPackages(modload.LoaderState, ctx, opts, "all")
opts.MainModule = module.Version{} // reset opts.MainModule = module.Version{} // reset
var ( var (
@ -91,7 +91,7 @@ func runSync(ctx context.Context, cmd *base.Command, args []string) {
mustSelectFor[m] = mustSelect mustSelectFor[m] = mustSelect
} }
workFilePath := modload.WorkFilePath() // save go.work path because EnterModule clobbers it. workFilePath := modload.WorkFilePath(modload.LoaderState) // save go.work path because EnterModule clobbers it.
var goV string var goV string
for _, m := range mms.Versions() { for _, m := range mms.Versions() {
@ -114,12 +114,12 @@ func runSync(ctx context.Context, cmd *base.Command, args []string) {
// so we don't write some go.mods with the "before" toolchain // so we don't write some go.mods with the "before" toolchain
// and others with the "after" toolchain. If nothing else, that // and others with the "after" toolchain. If nothing else, that
// discrepancy could show up in auto-recorded toolchain lines. // discrepancy could show up in auto-recorded toolchain lines.
changed, err := modload.EditBuildList(ctx, nil, mustSelectFor[m]) changed, err := modload.EditBuildList(modload.LoaderState, ctx, nil, mustSelectFor[m])
if err != nil { if err != nil {
continue continue
} }
if changed { if changed {
modload.LoadPackages(ctx, modload.PackageOpts{ modload.LoadPackages(modload.LoaderState, ctx, modload.PackageOpts{
Tags: imports.AnyTags(), Tags: imports.AnyTags(),
Tidy: true, Tidy: true,
VendorModulesInGOROOTSrc: true, VendorModulesInGOROOTSrc: true,
@ -131,7 +131,7 @@ func runSync(ctx context.Context, cmd *base.Command, args []string) {
}, "all") }, "all")
modload.WriteGoMod(ctx, modload.WriteOpts{}) modload.WriteGoMod(ctx, modload.WriteOpts{})
} }
goV = gover.Max(goV, modload.LoaderState.MainModules.GoVersion()) goV = gover.Max(goV, modload.LoaderState.MainModules.GoVersion(modload.LoaderState))
} }
wf, err := modload.ReadWorkFile(workFilePath) wf, err := modload.ReadWorkFile(workFilePath)

View file

@ -62,8 +62,8 @@ func init() {
func runUse(ctx context.Context, cmd *base.Command, args []string) { func runUse(ctx context.Context, cmd *base.Command, args []string) {
modload.LoaderState.ForceUseModules = true modload.LoaderState.ForceUseModules = true
modload.InitWorkfile() modload.InitWorkfile(modload.LoaderState)
gowork := modload.WorkFilePath() gowork := modload.WorkFilePath(modload.LoaderState)
if gowork == "" { if gowork == "" {
base.Fatalf("go: no go.work file found\n\t(run 'go work init' first or specify path using GOWORK environment variable)") base.Fatalf("go: no go.work file found\n\t(run 'go work init' first or specify path using GOWORK environment variable)")
} }

View file

@ -46,8 +46,8 @@ func init() {
} }
func runVendor(ctx context.Context, cmd *base.Command, args []string) { func runVendor(ctx context.Context, cmd *base.Command, args []string) {
modload.InitWorkfile() modload.InitWorkfile(modload.LoaderState)
if modload.WorkFilePath() == "" { if modload.WorkFilePath(modload.LoaderState) == "" {
base.Fatalf("go: no go.work file found\n\t(run 'go work init' first or specify path using GOWORK environment variable)") base.Fatalf("go: no go.work file found\n\t(run 'go work init' first or specify path using GOWORK environment variable)")
} }