cmd/go: make the package loader a part of the module loader

This is a part of the project to remove global state in the module
loader. Before this change, the packageLoader was stored in a global
field "loaded" which meant that even though the module loader is no
longer global, part of the module loader still depended on global state.
This change will make progress to the point where we can potentially
have multiple module loaders in the same go/command execution.

Change-Id: If4963a8a9d0e04960cf5424e496114276a6a6964
Reviewed-on: https://go-review.googlesource.com/c/go/+/753220
Reviewed-by: Ian Alexander <jitsu@google.com>
LUCI-TryBot-Result: Go LUCI <golang-scoped@luci-project-accounts.iam.gserviceaccount.com>
Reviewed-by: Michael Matloob <matloob@google.com>
This commit is contained in:
Michael Matloob
2026-03-09 12:45:20 -04:00
parent 72327dd645
commit a61fd42897
7 changed files with 37 additions and 37 deletions

View File

@@ -106,7 +106,7 @@ func RunVendor(loaderstate *modload.State, ctx context.Context, vendorE bool, ve
modpkgs := make(map[module.Version][]string)
for _, pkg := range pkgs {
m := modload.PackageModule(pkg)
m := loaderstate.PackageModule(pkg)
if m.Path == "" || loaderstate.MainModules.Contains(m.Path) {
continue
}
@@ -294,7 +294,7 @@ func vendorPkg(s *modload.State, vdir, pkg string) {
return matchPotentialSourceFile(dir, info, goVersion)
}
copyDir(dst, src, matcher, copiedFiles)
if m := modload.PackageModule(realPath); m.Path != "" {
if m := s.PackageModule(realPath); m.Path != "" {
copyMetadata(m.Path, realPath, dst, src, copiedFiles)
}

View File

@@ -92,7 +92,7 @@ func runWhy(ctx context.Context, cmd *base.Command, args []string) {
byModule := make(map[string][]string)
_, pkgs := modload.LoadPackages(moduleLoaderState, ctx, loadOpts, "all")
for _, path := range pkgs {
m := modload.PackageModule(path)
m := moduleLoaderState.PackageModule(path)
if m.Path != "" {
byModule[m.Path] = append(byModule[m.Path], path)
}
@@ -102,13 +102,13 @@ func runWhy(ctx context.Context, cmd *base.Command, args []string) {
best := ""
bestDepth := 1000000000
for _, path := range byModule[m.Path] {
d := modload.WhyDepth(path)
d := moduleLoaderState.WhyDepth(path)
if d > 0 && d < bestDepth {
best = path
bestDepth = d
}
}
why := modload.Why(best)
why := moduleLoaderState.Why(best)
if why == "" {
vendoring := ""
if *whyVendor {
@@ -128,7 +128,7 @@ func runWhy(ctx context.Context, cmd *base.Command, args []string) {
sep := ""
for _, m := range matches {
for _, path := range m.Pkgs {
why := modload.Why(path)
why := moduleLoaderState.Why(path)
if why == "" {
vendoring := ""
if *whyVendor {

View File

@@ -1700,13 +1700,13 @@ func (r *resolver) checkPackageProblems(loaderstate *modload.State, ctx context.
}
}
}
if m := modload.PackageModule(pkg); m.Path != "" {
if m := loaderstate.PackageModule(pkg); m.Path != "" {
relevantMods[m] |= hasPkg
}
}
for _, match := range matches {
for _, pkg := range match.Pkgs {
m := modload.PackageModule(pkg)
m := loaderstate.PackageModule(pkg)
relevantMods[m] |= named
}
}

View File

@@ -54,7 +54,7 @@ func PackageModuleInfo(loaderstate *State, ctx context.Context, pkgpath string)
if isStandardImportPath(pkgpath) || !loaderstate.Enabled() {
return nil
}
m, ok := findModule(loaded, pkgpath)
m, ok := findModule(loaderstate.pkgLoader, pkgpath)
if !ok {
return nil
}
@@ -71,7 +71,7 @@ func PackageModRoot(loaderstate *State, ctx context.Context, pkgpath string) str
if isStandardImportPath(pkgpath) || !loaderstate.Enabled() || cfg.BuildMod == "vendor" {
return ""
}
m, ok := findModule(loaded, pkgpath)
m, ok := findModule(loaderstate.pkgLoader, pkgpath)
if !ok {
return ""
}

View File

@@ -435,6 +435,14 @@ type State struct {
modulesEnabled bool
MainModules *MainModuleSet
// pkgLoader is the most recently-used package loader.
// It holds details about individual packages.
//
// This variable should only be accessed directly in top-level exported
// functions. All other functions that require or produce a *packageLoader should pass
// or return it as an explicit parameter.
pkgLoader *packageLoader
// requirements is the requirement graph for the main module.
//
// It is always non-nil if the main module's go.mod file has been
@@ -1976,7 +1984,7 @@ func commitRequirements(loaderstate *State, ctx context.Context, opts WriteOpts)
if loaderstate.inWorkspaceMode() {
// go.mod files aren't updated in workspace mode, but we still want to
// update the go.work.sum file.
return loaderstate.Fetcher().WriteGoSum(ctx, keepSums(loaderstate, ctx, loaded, loaderstate.requirements, addBuildListZipSums), mustHaveCompleteRequirements(loaderstate))
return loaderstate.Fetcher().WriteGoSum(ctx, keepSums(loaderstate, ctx, loaderstate.pkgLoader, loaderstate.requirements, addBuildListZipSums), mustHaveCompleteRequirements(loaderstate))
}
_, updatedGoMod, modFile, err := UpdateGoModFromReqs(loaderstate, ctx, opts)
if err != nil {
@@ -2000,7 +2008,7 @@ func commitRequirements(loaderstate *State, ctx context.Context, opts WriteOpts)
// 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.
if cfg.CmdName != "mod init" {
if err := loaderstate.Fetcher().WriteGoSum(ctx, keepSums(loaderstate, ctx, loaded, loaderstate.requirements, addBuildListZipSums), mustHaveCompleteRequirements(loaderstate)); err != nil {
if err := loaderstate.Fetcher().WriteGoSum(ctx, keepSums(loaderstate, ctx, loaderstate.pkgLoader, loaderstate.requirements, addBuildListZipSums), mustHaveCompleteRequirements(loaderstate)); err != nil {
return err
}
}
@@ -2023,7 +2031,7 @@ func commitRequirements(loaderstate *State, ctx context.Context, opts WriteOpts)
// 'go mod init' shouldn't write go.sum, since it will be incomplete.
if cfg.CmdName != "mod init" {
if err == nil {
err = loaderstate.Fetcher().WriteGoSum(ctx, keepSums(loaderstate, ctx, loaded, loaderstate.requirements, addBuildListZipSums), mustHaveCompleteRequirements(loaderstate))
err = loaderstate.Fetcher().WriteGoSum(ctx, keepSums(loaderstate, ctx, loaderstate.pkgLoader, loaderstate.requirements, addBuildListZipSums), mustHaveCompleteRequirements(loaderstate))
}
}
}()

View File

@@ -128,14 +128,6 @@ import (
"golang.org/x/mod/module"
)
// loaded is the most recently-used package loader.
// It holds details about individual packages.
//
// This variable should only be accessed directly in top-level exported
// functions. All other functions that require or produce a *packageLoader should pass
// or return it as an explicit parameter.
var loaded *packageLoader
// PackageOpts control the behavior of the LoadPackages function.
type PackageOpts struct {
// TidyGoVersion is the Go version to which the go.mod file should be updated
@@ -454,8 +446,8 @@ func LoadPackages(loaderstate *State, ctx context.Context, opts PackageOpts, pat
if opts.TidyDiff {
cfg.BuildMod = "readonly"
loaded = ld
loaderstate.requirements = loaded.requirements
loaderstate.pkgLoader = ld
loaderstate.requirements = loaderstate.pkgLoader.requirements
currentGoMod, updatedGoMod, _, err := UpdateGoModFromReqs(loaderstate, ctx, WriteOpts{})
if err != nil {
base.Fatal(err)
@@ -466,7 +458,7 @@ func LoadPackages(loaderstate *State, ctx context.Context, opts PackageOpts, pat
// Dropping compatibility for 1.16 may result in a strictly smaller go.sum.
// Update the keep map with only the loaded.requirements.
if gover.Compare(compatVersion, "1.16") > 0 {
keep = keepSums(loaderstate, ctx, loaded, loaderstate.requirements, addBuildListZipSums)
keep = keepSums(loaderstate, ctx, loaderstate.pkgLoader, loaderstate.requirements, addBuildListZipSums)
}
currentGoSum, tidyGoSum := loaderstate.fetcher.TidyGoSum(keep)
goSumDiff := diff.Diff("current/go.sum", currentGoSum, "tidy/go.sum", tidyGoSum)
@@ -504,8 +496,8 @@ func LoadPackages(loaderstate *State, ctx context.Context, opts PackageOpts, pat
// We'll skip updating if ExplicitWriteGoMod is true (the caller has opted
// to call WriteGoMod itself) or if ResolveMissingImports is false (the
// command wants to examine the package graph as-is).
loaded = ld
loaderstate.requirements = loaded.requirements
loaderstate.pkgLoader = ld
loaderstate.requirements = loaderstate.pkgLoader.requirements
for _, pkg := range ld.pkgs {
if !pkg.isTest() {
@@ -775,7 +767,7 @@ func ImportFromFiles(loaderstate *State, ctx context.Context, gofiles []string)
base.Fatal(err)
}
loaded = loadFromRoots(loaderstate, ctx, loaderParams{
loaderstate.pkgLoader = loadFromRoots(loaderstate, ctx, loaderParams{
PackageOpts: PackageOpts{
Tags: tags,
ResolveMissingImports: true,
@@ -788,7 +780,7 @@ func ImportFromFiles(loaderstate *State, ctx context.Context, gofiles []string)
return roots
},
})
loaderstate.requirements = loaded.requirements
loaderstate.requirements = loaderstate.pkgLoader.requirements
if !ExplicitWriteGoMod {
if err := commitRequirements(loaderstate, ctx, WriteOpts{}); err != nil {
@@ -841,8 +833,8 @@ func (mms *MainModuleSet) DirImportPath(loaderstate *State, ctx context.Context,
}
// PackageModule returns the module providing the package named by the import path.
func PackageModule(path string) module.Version {
pkg, ok := loaded.pkgCache.Get(path)
func (loaderstate *State) PackageModule(path string) module.Version {
pkg, ok := loaderstate.pkgLoader.pkgCache.Get(path)
if !ok {
return module.Version{}
}
@@ -859,9 +851,9 @@ func Lookup(loaderstate *State, parentPath string, parentIsStd bool, path string
}
if parentIsStd {
path = loaded.stdVendor(loaderstate, parentPath, path)
path = loaderstate.pkgLoader.stdVendor(loaderstate, parentPath, path)
}
pkg, ok := loaded.pkgCache.Get(path)
pkg, ok := loaderstate.pkgLoader.pkgCache.Get(path)
if !ok {
// The loader should have found all the relevant paths.
// There are a few exceptions, though:
@@ -2391,8 +2383,8 @@ func (pkg *loadPkg) why() string {
// The package graph must have been loaded already, usually by LoadPackages.
// If there is no reason for the package to be in the current build,
// Why returns an empty string.
func Why(path string) string {
pkg, ok := loaded.pkgCache.Get(path)
func (loaderstate *State) Why(path string) string {
pkg, ok := loaderstate.pkgLoader.pkgCache.Get(path)
if !ok {
return ""
}
@@ -2402,9 +2394,9 @@ func Why(path string) string {
// WhyDepth returns the number of steps in the Why listing.
// If there is no reason for the package to be in the current build,
// WhyDepth returns 0.
func WhyDepth(path string) int {
func (loaderstate *State) WhyDepth(path string) int {
n := 0
pkg, _ := loaded.pkgCache.Get(path)
pkg, _ := loaderstate.pkgLoader.pkgCache.Get(path)
for p := pkg; p != nil; p = p.stack {
n++
}

View File

@@ -82,7 +82,7 @@ func runSync(ctx context.Context, cmd *base.Command, args []string) {
inMustSelect = map[module.Version]bool{}
)
for _, pkg := range pkgs {
if r := modload.PackageModule(pkg); r.Version != "" && !inMustSelect[r] {
if r := moduleLoaderState.PackageModule(pkg); r.Version != "" && !inMustSelect[r] {
// r has a known version, so force that version.
mustSelect = append(mustSelect, r)
inMustSelect[r] = true