"cmd/go/internal/base"
"cmd/go/internal/cfg"
"cmd/go/internal/fsys"
+ "cmd/go/internal/gover"
"cmd/go/internal/imports"
"cmd/go/internal/modfetch"
"cmd/go/internal/modindex"
"cmd/go/internal/str"
"golang.org/x/mod/module"
- "golang.org/x/mod/semver"
)
// loaded is the most recently-used package loader.
// PackageOpts control the behavior of the LoadPackages function.
type PackageOpts struct {
- // GoVersion is the Go version to which the go.mod file should be updated
+ // TidyGoVersion is the Go version to which the go.mod file should be updated
// after packages have been loaded.
//
- // An empty GoVersion means to use the Go version already specified in the
+ // An empty TidyGoVersion means to use the Go version already specified in the
// main module's go.mod file, or the latest Go version if there is no main
// module.
- GoVersion string
+ TidyGoVersion string
// Tags are the build tags in effect (as interpreted by the
// cmd/go/internal/imports package).
Tags map[string]bool
// Tidy, if true, requests that the build list and go.sum file be reduced to
- // the minimial dependencies needed to reproducibly reload the requested
+ // the minimal dependencies needed to reproducibly reload the requested
// packages.
Tidy bool
// Resolve the query against this module.
MainModule module.Version
+
+ // If Switcher is non-nil, then LoadPackages passes all encountered errors
+ // to Switcher.Error and tries Switcher.Switch before base.ExitIfErrors.
+ Switcher gover.Switcher
}
// LoadPackages identifies the set of packages matching the given patterns and
}
}
- initialRS := LoadModFile(ctx)
+ initialRS, err := loadModFile(ctx, &opts)
+ if err != nil {
+ base.Fatal(err)
+ }
ld := loadFromRoots(ctx, loaderParams{
PackageOpts: opts,
if !ld.SilencePackageErrors {
for _, match := range matches {
for _, err := range match.Errs {
- ld.errorf("%v\n", err)
+ ld.error(err)
}
}
}
- base.ExitIfErrors()
+ ld.exitIfErrors(ctx)
if !opts.SilenceUnmatchedWarnings {
search.WarnUnmatched(matches)
if opts.Tidy {
if cfg.BuildV {
mg, _ := ld.requirements.Graph(ctx)
-
for _, m := range initialRS.rootModules {
var unused bool
if ld.requirements.pruning == unpruned {
}
keep := keepSums(ctx, ld, ld.requirements, loadedZipSumsOnly)
- if compatDepth := pruningForGoVersion(ld.TidyCompatibleVersion); compatDepth != ld.requirements.pruning {
- compatRS := newRequirements(compatDepth, ld.requirements.rootModules, ld.requirements.direct)
- ld.checkTidyCompatibility(ctx, compatRS)
+ compatVersion := ld.TidyCompatibleVersion
+ goVersion := ld.requirements.GoVersion()
+ if compatVersion == "" {
+ if gover.Compare(goVersion, gover.GoStrictVersion) < 0 {
+ compatVersion = gover.Prev(goVersion)
+ } else {
+ // Starting at GoStrictVersion, we no longer maintain compatibility with
+ // versions older than what is listed in the go.mod file.
+ compatVersion = goVersion
+ }
+ }
+ if gover.Compare(compatVersion, goVersion) > 0 {
+ // Each version of the Go toolchain knows how to interpret go.mod and
+ // go.sum files produced by all previous versions, so a compatibility
+ // version higher than the go.mod version adds nothing.
+ compatVersion = goVersion
+ }
+ if compatPruning := pruningForGoVersion(compatVersion); compatPruning != ld.requirements.pruning {
+ compatRS := newRequirements(compatPruning, ld.requirements.rootModules, ld.requirements.direct)
+ ld.checkTidyCompatibility(ctx, compatRS, compatVersion)
for m := range keepSums(ctx, ld, compatRS, loadedZipSumsOnly) {
keep[m] = true
// loaded.requirements, but here we may have also loaded (and want to
// preserve checksums for) additional entities from compatRS, which are
// only needed for compatibility with ld.TidyCompatibleVersion.
- if err := modfetch.WriteGoSum(keep, mustHaveCompleteRequirements()); err != nil {
- base.Fatalf("go: %v", err)
+ if err := modfetch.WriteGoSum(ctx, keep, mustHaveCompleteRequirements()); err != nil {
+ base.Fatal(err)
}
}
-
- // Update the go.mod file's Go version if necessary.
- if modFile := ModFile(); modFile != nil && ld.GoVersion != "" {
- modFile.AddGoStmt(ld.GoVersion)
- }
}
// Success! Update go.mod and go.sum (if needed) and return the results.
sort.Strings(loadedPackages)
if !ExplicitWriteGoMod && opts.ResolveMissingImports {
- if err := commitRequirements(ctx); err != nil {
- base.Fatalf("go: %v", err)
+ if err := commitRequirements(ctx, WriteOpts{}); err != nil {
+ base.Fatal(err)
}
}
return "", fmt.Errorf("without -mod=vendor, directory %s has no package path", absDir)
}
- readVendorList(mainModule)
+ readVendorList(VendorDir())
if _, ok := vendorPkgModule[pkg]; !ok {
return "", fmt.Errorf("directory %s is not a package listed in vendor/modules.txt", absDir)
}
// 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 {
tryMod := func(m module.Version) (string, bool) {
+ if gover.IsToolchain(m.Path) {
+ return "", false
+ }
var root string
var err error
if repl := Replacement(m); repl.Path != "" && repl.Version == "" {
root = filepath.Join(replaceRelativeTo(), root)
}
} else if repl.Path != "" {
- root, err = modfetch.DownloadDir(repl)
+ root, err = modfetch.DownloadDir(ctx, repl)
} else {
- root, err = modfetch.DownloadDir(m)
+ root, err = modfetch.DownloadDir(ctx, m)
}
if err != nil {
return "", false
tags := imports.Tags()
imports, testImports, err := imports.ScanFiles(gofiles, tags)
if err != nil {
- base.Fatalf("go: %v", err)
+ base.Fatal(err)
}
loaded = loadFromRoots(ctx, loaderParams{
requirements = loaded.requirements
if !ExplicitWriteGoMod {
- if err := commitRequirements(ctx); err != nil {
- base.Fatalf("go: %v", err)
+ if err := commitRequirements(ctx, WriteOpts{}); err != nil {
+ base.Fatal(err)
}
}
}
longestPrefixVersion = v
suffix := filepath.ToSlash(str.TrimFilePathPrefix(dir, modRoot))
if strings.HasPrefix(suffix, "vendor/") {
- longestPrefixPath = strings.TrimPrefix(suffix, "vendor/")
+ longestPrefixPath = suffix[len("vendor/"):]
continue
}
longestPrefixPath = pathpkg.Join(mms.PathPrefix(v), suffix)
ld.pkgs = nil
}
-// errorf reports an error via either os.Stderr or base.Errorf,
+// error reports an error via either os.Stderr or base.Error,
// according to whether ld.AllowErrors is set.
-func (ld *loader) errorf(format string, args ...any) {
+func (ld *loader) error(err error) {
if ld.AllowErrors {
- fmt.Fprintf(os.Stderr, format, args...)
+ fmt.Fprintf(os.Stderr, "go: %v\n", err)
+ } else if ld.Switcher != nil {
+ ld.Switcher.Error(err)
} else {
- base.Errorf(format, args...)
+ base.Error(err)
}
}
+// switchIfErrors switches toolchains if a switch is needed.
+func (ld *loader) switchIfErrors(ctx context.Context) {
+ if ld.Switcher != nil {
+ ld.Switcher.Switch(ctx)
+ }
+}
+
+// exitIfErrors switches toolchains if a switch is needed
+// or else exits if any errors have been reported.
+func (ld *loader) exitIfErrors(ctx context.Context) {
+ ld.switchIfErrors(ctx)
+ base.ExitIfErrors()
+}
+
+// goVersion reports the Go version that should be used for the loader's
+// requirements: ld.TidyGoVersion if set, or ld.requirements.GoVersion()
+// otherwise.
+func (ld *loader) goVersion() string {
+ if ld.TidyGoVersion != "" {
+ return ld.TidyGoVersion
+ }
+ return ld.requirements.GoVersion()
+}
+
// A loadPkg records information about a single loaded package.
type loadPkg struct {
// Populated at construction time:
work: par.NewQueue(runtime.GOMAXPROCS(0)),
}
- if ld.GoVersion == "" {
- ld.GoVersion = MainModules.GoVersion()
-
- if ld.Tidy && versionLess(LatestGoVersion(), ld.GoVersion) {
- ld.errorf("go: go.mod file indicates go %s, but maximum version supported by tidy is %s\n", ld.GoVersion, LatestGoVersion())
- base.ExitIfErrors()
- }
- }
-
- if ld.Tidy {
- if ld.TidyCompatibleVersion == "" {
- ld.TidyCompatibleVersion = priorGoVersion(ld.GoVersion)
- } else if versionLess(ld.GoVersion, ld.TidyCompatibleVersion) {
- // Each version of the Go toolchain knows how to interpret go.mod and
- // go.sum files produced by all previous versions, so a compatibility
- // version higher than the go.mod version adds nothing.
- ld.TidyCompatibleVersion = ld.GoVersion
- }
-
- if semver.Compare("v"+ld.GoVersion, tidyGoModSumVersionV) < 0 {
- ld.skipImportModFiles = true
- }
- }
-
- if semver.Compare("v"+ld.GoVersion, narrowAllVersionV) < 0 && !ld.UseVendorAll {
- // The module's go version explicitly predates the change in "all" for graph
- // pruning, so continue to use the older interpretation.
- ld.allClosesOverTests = true
- }
-
- var err error
- desiredPruning := pruningForGoVersion(ld.GoVersion)
- if ld.requirements.pruning == workspace {
- desiredPruning = workspace
- }
- ld.requirements, err = convertPruning(ctx, ld.requirements, desiredPruning)
- if err != nil {
- ld.errorf("go: %v\n", err)
- }
-
if ld.requirements.pruning == unpruned {
// If the module graph does not support pruning, we assume that we will need
// the full module graph in order to load package dependencies.
var err error
ld.requirements, _, err = expandGraph(ctx, ld.requirements)
if err != nil {
- ld.errorf("go: %v\n", err)
+ ld.error(err)
}
}
+ ld.exitIfErrors(ctx)
+
+ updateGoVersion := func() {
+ goVersion := ld.goVersion()
+
+ if ld.requirements.pruning != workspace {
+ var err error
+ ld.requirements, err = convertPruning(ctx, ld.requirements, pruningForGoVersion(goVersion))
+ if err != nil {
+ ld.error(err)
+ ld.exitIfErrors(ctx)
+ }
+ }
+
+ // If the module's Go version omits go.sum entries for go.mod files for test
+ // dependencies of external packages, avoid loading those files in the first
+ // place.
+ ld.skipImportModFiles = ld.Tidy && gover.Compare(goVersion, gover.TidyGoModSumVersion) < 0
+
+ // If the module's go version explicitly predates the change in "all" for
+ // graph pruning, continue to use the older interpretation.
+ ld.allClosesOverTests = gover.Compare(goVersion, gover.NarrowAllVersion) < 0 && !ld.UseVendorAll
+ }
for {
ld.reset()
+ updateGoVersion()
// Load the root packages and their imports.
// Note: the returned roots can change on each iteration,
changed, err := ld.updateRequirements(ctx)
if err != nil {
- ld.errorf("go: %v\n", err)
+ ld.error(err)
break
}
if changed {
break
}
- modAddedBy := ld.resolveMissingImports(ctx)
+ modAddedBy, err := ld.resolveMissingImports(ctx)
+ if err != nil {
+ ld.error(err)
+ break
+ }
if len(modAddedBy) == 0 {
// The roots are stable, and we've resolved all of the missing packages
// that we can.
for m := range modAddedBy {
toAdd = append(toAdd, m)
}
- module.Sort(toAdd) // to make errors deterministic
+ gover.ModSort(toAdd) // to make errors deterministic
// We ran updateRequirements before resolving missing imports and it didn't
// make any changes, so we know that the requirement graph is already
// are more descriptive.
if err, ok := err.(*mvs.BuildListError); ok {
if pkg := modAddedBy[err.Module()]; pkg != nil {
- ld.errorf("go: %s: %v\n", pkg.stackText(), err.Err)
+ ld.error(fmt.Errorf("%s: %w", pkg.stackText(), err.Err))
break
}
}
- ld.errorf("go: %v\n", err)
+ ld.error(err)
break
}
if reflect.DeepEqual(rs.rootModules, ld.requirements.rootModules) {
}
ld.requirements = rs
}
- base.ExitIfErrors() // TODO(bcmills): Is this actually needed?
+ ld.exitIfErrors(ctx)
// Tidy the build list, if applicable, before we report errors.
// (The process of tidying may remove errors from irrelevant dependencies.)
if ld.Tidy {
rs, err := tidyRoots(ctx, ld.requirements, ld.pkgs)
if err != nil {
- ld.errorf("go: %v\n", err)
- base.ExitIfErrors()
+ ld.error(err)
} else {
+ if ld.TidyGoVersion != "" {
+ // 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
+ // still be — requirements on higher versions in the graph.
+ tidy := overrideRoots(ctx, rs, []module.Version{{Path: "go", Version: ld.TidyGoVersion}})
+ mg, err := tidy.Graph(ctx)
+ if err != nil {
+ ld.error(err)
+ }
+ if v := mg.Selected("go"); v == ld.TidyGoVersion {
+ rs = tidy
+ } else {
+ conflict := Conflict{
+ Path: mg.g.FindPath(func(m module.Version) bool {
+ return m.Path == "go" && m.Version == v
+ })[1:],
+ Constraint: module.Version{Path: "go", Version: ld.TidyGoVersion},
+ }
+ msg := conflict.Summary()
+ if cfg.BuildV {
+ msg = conflict.String()
+ }
+ ld.error(errors.New(msg))
+ }
+ }
+
if ld.requirements.pruning == pruned {
- // We continuously add tidy roots to ld.requirements during loading, so at
- // this point the tidy roots should be a subset of the roots of
- // ld.requirements, ensuring that no new dependencies are brought inside
- // the graph-pruning horizon.
+ // We continuously add tidy roots to ld.requirements during loading, so
+ // at this point the tidy roots (other than possibly the "go" version
+ // edited above) should be a subset of the roots of ld.requirements,
+ // ensuring that no new dependencies are brought inside the
+ // graph-pruning horizon.
// If that is not the case, there is a bug in the loading loop above.
for _, m := range rs.rootModules {
+ if m.Path == "go" && ld.TidyGoVersion != "" {
+ continue
+ }
if v, ok := ld.requirements.rootSelected(m.Path); !ok || v != m.Version {
- ld.errorf("go: internal error: a requirement on %v is needed but was not added during package loading\n", m)
- base.ExitIfErrors()
+ ld.error(fmt.Errorf("internal error: a requirement on %v is needed but was not added during package loading (selected %s)", m, v))
}
}
}
+
ld.requirements = rs
}
+
+ ld.exitIfErrors(ctx)
}
// Report errors, if any.
// Add importer go version information to import errors of standard
// library packages arising from newer releases.
if importer := pkg.stack; importer != nil {
- if v, ok := rawGoVersion.Load(importer.mod); ok && versionLess(LatestGoVersion(), v.(string)) {
+ if v, ok := rawGoVersion.Load(importer.mod); ok && gover.Compare(gover.Local(), v.(string)) < 0 {
stdErr.importerGoVersion = v.(string)
}
}
continue
}
- ld.errorf("%s: %v\n", pkg.stackText(), pkg.err)
+ ld.error(fmt.Errorf("%s: %w", pkg.stackText(), pkg.err))
}
ld.checkMultiplePaths()
return ld
}
-// versionLess returns whether a < b according to semantic version precedence.
-// Both strings are interpreted as go version strings, e.g. "1.19".
-func versionLess(a, b string) bool {
- return semver.Compare("v"+a, "v"+b) < 0
-}
-
// updateRequirements ensures that ld.requirements is consistent with the
// information gained from ld.pkgs.
//
}
}
+ var maxTooNew *gover.TooNewError
for _, pkg := range ld.pkgs {
+ if pkg.err != nil {
+ if tooNew := (*gover.TooNewError)(nil); errors.As(pkg.err, &tooNew) {
+ if maxTooNew == nil || gover.Compare(tooNew.GoVersion, maxTooNew.GoVersion) > 0 {
+ maxTooNew = tooNew
+ }
+ }
+ }
if pkg.mod.Version != "" || !MainModules.Contains(pkg.mod.Path) {
continue
}
+
for _, dep := range pkg.imports {
if !dep.fromExternalModule() {
continue
// 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
// roots does not apply.
+ if cfg.BuildMod == "vendor" {
+ // In workspace vendor mode, we don't need to load the requirements of the workspace
+ // modules' dependencies so the check below doesn't work. But that's okay, because
+ // checking whether modules are required directly for the purposes of pruning is
+ // less important in vendor mode: if we were able to load the package, we have
+ // everything we need to build the package, and dependencies' tests are pruned out
+ // of the vendor directory anyway.
+ continue
+ }
if mg, err := rs.Graph(ctx); err != nil {
return false, err
} else if _, ok := mg.RequiredBy(dep.mod); !ok {
direct[dep.mod.Path] = true
}
}
+ if maxTooNew != nil {
+ return false, maxTooNew
+ }
var addRoots []module.Version
if ld.Tidy {
return false, err
}
- if rs != ld.requirements && !reflect.DeepEqual(rs.rootModules, ld.requirements.rootModules) {
+ if rs.GoVersion() != ld.requirements.GoVersion() {
+ // 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"
+ // pattern, the level of pruning in the module graph, and even the set of
+ // packages present in the standard library. If it has changed, it's best to
+ // reload packages once more to be sure everything is stable.
+ changed = true
+ } else if rs != ld.requirements && !reflect.DeepEqual(rs.rootModules, ld.requirements.rootModules) {
// 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
// packages.
// The newly-resolved packages are added to the addedModuleFor map, and
// resolveMissingImports returns a map from each new module version to
// the first missing package that module would resolve.
-func (ld *loader) resolveMissingImports(ctx context.Context) (modAddedBy map[module.Version]*loadPkg) {
+func (ld *loader) resolveMissingImports(ctx context.Context) (modAddedBy map[module.Version]*loadPkg, err error) {
type pkgMod struct {
pkg *loadPkg
mod *module.Version
<-ld.work.Idle()
modAddedBy = map[module.Version]*loadPkg{}
+
+ var (
+ maxTooNew *gover.TooNewError
+ maxTooNewPkg *loadPkg
+ )
+ for _, pm := range pkgMods {
+ if tooNew := (*gover.TooNewError)(nil); errors.As(pm.pkg.err, &tooNew) {
+ if maxTooNew == nil || gover.Compare(tooNew.GoVersion, maxTooNew.GoVersion) > 0 {
+ maxTooNew = tooNew
+ maxTooNewPkg = pm.pkg
+ }
+ }
+ }
+ if maxTooNew != nil {
+ fmt.Fprintf(os.Stderr, "go: toolchain upgrade needed to resolve %s\n", maxTooNewPkg.path)
+ return nil, maxTooNew
+ }
+
for _, pm := range pkgMods {
pkg, mod := pm.pkg, *pm.mod
if mod.Path == "" {
}
}
- return modAddedBy
+ return modAddedBy, nil
}
// pkg locates the *loadPkg for path, creating and queuing it for loading if
for m := range need {
toAdd = append(toAdd, m)
}
- module.Sort(toAdd)
+ gover.ModSort(toAdd)
rs, err := updateRoots(ctx, ld.requirements.direct, ld.requirements, nil, toAdd, ld.AssumeRootsImported)
if err != nil {
// 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
// loading is doomed to fail, so fail quickly.
- ld.errorf("go: %v\n", err)
- base.ExitIfErrors()
+ ld.error(err)
+ ld.exitIfErrors(ctx)
return false
}
if reflect.DeepEqual(rs.rootModules, ld.requirements.rootModules) {
if prev, ok := firstPath[src]; !ok {
firstPath[src] = mod.Path
} else if prev != mod.Path {
- ld.errorf("go: %s@%s used for two different module paths (%s and %s)\n", src.Path, src.Version, prev, mod.Path)
+ ld.error(fmt.Errorf("%s@%s used for two different module paths (%s and %s)", src.Path, src.Version, prev, mod.Path))
}
}
}
// checkTidyCompatibility emits an error if any package would be loaded from a
// different module under rs than under ld.requirements.
-func (ld *loader) checkTidyCompatibility(ctx context.Context, rs *Requirements) {
+func (ld *loader) checkTidyCompatibility(ctx context.Context, rs *Requirements, compatVersion string) {
+ goVersion := rs.GoVersion()
suggestUpgrade := false
suggestEFlag := false
suggestFixes := func() {
fmt.Fprintln(os.Stderr)
goFlag := ""
- if ld.GoVersion != MainModules.GoVersion() {
- goFlag = " -go=" + ld.GoVersion
+ if goVersion != MainModules.GoVersion() {
+ goFlag = " -go=" + goVersion
}
compatFlag := ""
- if ld.TidyCompatibleVersion != priorGoVersion(ld.GoVersion) {
- compatFlag = " -compat=" + ld.TidyCompatibleVersion
+ if compatVersion != gover.Prev(goVersion) {
+ compatFlag = " -compat=" + compatVersion
}
if suggestUpgrade {
eDesc := ""
eDesc = ", leaving some packages unresolved"
eFlag = " -e"
}
- fmt.Fprintf(os.Stderr, "To upgrade to the versions selected by go %s%s:\n\tgo mod tidy%s -go=%s && go mod tidy%s -go=%s%s\n", ld.TidyCompatibleVersion, eDesc, eFlag, ld.TidyCompatibleVersion, eFlag, ld.GoVersion, compatFlag)
+ fmt.Fprintf(os.Stderr, "To upgrade to the versions selected by go %s%s:\n\tgo mod tidy%s -go=%s && go mod tidy%s -go=%s%s\n", compatVersion, eDesc, eFlag, compatVersion, eFlag, goVersion, compatFlag)
} else if suggestEFlag {
// If some packages are missing but no package is upgraded, then we
// shouldn't suggest upgrading to the Go 1.16 versions explicitly — that
// wouldn't actually fix anything for Go 1.16 users, and *would* break
// something for Go 1.17 users.
- fmt.Fprintf(os.Stderr, "To proceed despite packages unresolved in go %s:\n\tgo mod tidy -e%s%s\n", ld.TidyCompatibleVersion, goFlag, compatFlag)
+ fmt.Fprintf(os.Stderr, "To proceed despite packages unresolved in go %s:\n\tgo mod tidy -e%s%s\n", compatVersion, goFlag, compatFlag)
}
- fmt.Fprintf(os.Stderr, "If reproducibility with go %s is not needed:\n\tgo mod tidy%s -compat=%s\n", ld.TidyCompatibleVersion, goFlag, ld.GoVersion)
+ fmt.Fprintf(os.Stderr, "If reproducibility with go %s is not needed:\n\tgo mod tidy%s -compat=%s\n", compatVersion, goFlag, goVersion)
// TODO(#46141): Populate the linked wiki page.
fmt.Fprintf(os.Stderr, "For other options, see:\n\thttps://golang.org/doc/modules/pruning\n")
mg, err := rs.Graph(ctx)
if err != nil {
- ld.errorf("go: error loading go %s module graph: %v\n", ld.TidyCompatibleVersion, err)
+ ld.error(fmt.Errorf("error loading go %s module graph: %w", compatVersion, err))
+ ld.switchIfErrors(ctx)
suggestFixes()
+ ld.exitIfErrors(ctx)
return
}
for _, m := range ld.requirements.rootModules {
if v := mg.Selected(m.Path); v != m.Version {
fmt.Fprintln(os.Stderr)
- base.Fatalf("go: internal error: failed to diagnose selected-version mismatch for module %s: go %s selects %s, but go %s selects %s\n\tPlease report this at https://golang.org/issue.", m.Path, ld.GoVersion, m.Version, ld.TidyCompatibleVersion, v)
+ base.Fatalf("go: internal error: failed to diagnose selected-version mismatch for module %s: go %s selects %s, but go %s selects %s\n\tPlease report this at https://golang.org/issue.", m.Path, goVersion, m.Version, compatVersion, v)
}
}
return
if pkg.isTest() {
// We already did (or will) report an error for the package itself,
- // so don't report a duplicate (and more vebose) error for its test.
+ // so don't report a duplicate (and more verbose) error for its test.
if _, ok := mismatches[pkg.testOf]; !ok {
base.Fatalf("go: internal error: mismatch recorded for test %s, but not its non-test package", pkg.path)
}
Path: pkg.mod.Path,
Version: mg.Selected(pkg.mod.Path),
}
- ld.errorf("%s loaded from %v,\n\tbut go %s would fail to locate it in %s\n", pkg.stackText(), pkg.mod, ld.TidyCompatibleVersion, selected)
+ ld.error(fmt.Errorf("%s loaded from %v,\n\tbut go %s would fail to locate it in %s", pkg.stackText(), pkg.mod, compatVersion, selected))
} else {
if ambiguous := (*AmbiguousImportError)(nil); errors.As(mismatch.err, &ambiguous) {
// TODO: Is this check needed?
}
- ld.errorf("%s loaded from %v,\n\tbut go %s would fail to locate it:\n\t%v\n", pkg.stackText(), pkg.mod, ld.TidyCompatibleVersion, mismatch.err)
+ ld.error(fmt.Errorf("%s loaded from %v,\n\tbut go %s would fail to locate it:\n\t%v", pkg.stackText(), pkg.mod, compatVersion, mismatch.err))
}
suggestEFlag = true
// pkg.err should have already been logged elsewhere — along with a
// stack trace — so log only the import path and non-error info here.
suggestUpgrade = true
- ld.errorf("%s failed to load from any module,\n\tbut go %s would load it from %v\n", pkg.path, ld.TidyCompatibleVersion, mismatch.mod)
+ ld.error(fmt.Errorf("%s failed to load from any module,\n\tbut go %s would load it from %v", pkg.path, compatVersion, mismatch.mod))
case pkg.mod != mismatch.mod:
// The package is loaded successfully by both Go versions, but from a
// unnoticed!) variations in behavior between builds with different
// toolchains.
suggestUpgrade = true
- ld.errorf("%s loaded from %v,\n\tbut go %s would select %v\n", pkg.stackText(), pkg.mod, ld.TidyCompatibleVersion, mismatch.mod.Version)
+ ld.error(fmt.Errorf("%s loaded from %v,\n\tbut go %s would select %v\n", pkg.stackText(), pkg.mod, compatVersion, mismatch.mod.Version))
default:
base.Fatalf("go: internal error: mismatch recorded for package %s, but no differences found", pkg.path)
}
}
+ ld.switchIfErrors(ctx)
suggestFixes()
- base.ExitIfErrors()
+ ld.exitIfErrors(ctx)
}
// scanDir is like imports.ScanDir but elides known magic imports from the list,