From: Russ Cox Date: Thu, 1 Jun 2023 18:13:20 +0000 (-0400) Subject: cmd/go: return more errors from ReadModFile, loadModFile X-Git-Tag: go1.21rc1~120 X-Git-Url: http://www.git.cypherpunks.su/?a=commitdiff_plain;h=c71cbd544e3da139badd4c03612af41b63711705;p=gostls13.git cmd/go: return more errors from ReadModFile, loadModFile Return more errors instead of base.Fatalf, so we can handle them in the callers. For #57001. Change-Id: If3e63d3f64188148f5d750991f9cb1175790d89d Reviewed-on: https://go-review.googlesource.com/c/go/+/499983 Reviewed-by: Bryan Mills Auto-Submit: Russ Cox TryBot-Result: Gopher Robot Run-TryBot: Russ Cox --- diff --git a/src/cmd/go/internal/gover/toolchain.go b/src/cmd/go/internal/gover/toolchain.go index f27e313524..7bd9229fcb 100644 --- a/src/cmd/go/internal/gover/toolchain.go +++ b/src/cmd/go/internal/gover/toolchain.go @@ -60,6 +60,7 @@ var Startup struct { type TooNewError struct { What string GoVersion string + Toolchain string // for callers if they want to use it, but not printed } func (e *TooNewError) Error() string { diff --git a/src/cmd/go/internal/modload/buildlist.go b/src/cmd/go/internal/modload/buildlist.go index d71962dd6b..ecc07ed91f 100644 --- a/src/cmd/go/internal/modload/buildlist.go +++ b/src/cmd/go/internal/modload/buildlist.go @@ -541,7 +541,10 @@ func (mg *ModuleGraph) allRootsSelected() bool { // LoadModGraph need only be called if LoadPackages is not, // typically in commands that care about modules but no particular package. func LoadModGraph(ctx context.Context, goVersion string) (*ModuleGraph, error) { - rs := LoadModFile(ctx) + rs, err := loadModFile(ctx, nil) + if err != nil { + return nil, err + } if goVersion != "" { v, _ := rs.rootSelected("go") diff --git a/src/cmd/go/internal/modload/init.go b/src/cmd/go/internal/modload/init.go index 737aaa9106..c4b30fc14d 100644 --- a/src/cmd/go/internal/modload/init.go +++ b/src/cmd/go/internal/modload/init.go @@ -731,12 +731,16 @@ func UpdateWorkFile(wf *modfile.WorkFile) { // it for global consistency. Most callers outside of the modload package should // use LoadModGraph instead. func LoadModFile(ctx context.Context) *Requirements { - return loadModFile(ctx, nil) + rs, err := loadModFile(ctx, nil) + if err != nil { + base.Fatal(err) + } + return rs } -func loadModFile(ctx context.Context, opts *PackageOpts) *Requirements { +func loadModFile(ctx context.Context, opts *PackageOpts) (*Requirements, error) { if requirements != nil { - return requirements + return requirements, nil } Init() @@ -745,7 +749,7 @@ func loadModFile(ctx context.Context, opts *PackageOpts) *Requirements { var err error workFile, modRoots, err = loadWorkFile(workFilePath) if err != nil { - base.Fatalf("reading go.work: %v", err) + return nil, fmt.Errorf("reading go.work: %w", err) } for _, modRoot := range modRoots { sumFile := strings.TrimSuffix(modFilePath(modRoot), ".mod") + ".sum" @@ -796,22 +800,23 @@ func loadModFile(ctx context.Context, opts *PackageOpts) *Requirements { // with no dependencies. requirements.initVendor(nil) } - return requirements + return requirements, nil } var modFiles []*modfile.File var mainModules []module.Version var indices []*modFileIndex + var errs []error for _, modroot := range modRoots { gomod := modFilePath(modroot) var fixed bool data, f, err := ReadModFile(gomod, fixVersion(ctx, &fixed)) if err != nil { if inWorkspaceMode() { - base.Fatalf("go: cannot load module %s listed in go.work file: %v", base.ShortPath(gomod), err) - } else { - base.Fatalf("go: %v", err) + err = fmt.Errorf("cannot load module %s listed in go.work file: %w", base.ShortPath(gomod), err) } + errs = append(errs, err) + continue } modFiles = append(modFiles, f) @@ -823,9 +828,12 @@ func loadModFile(ctx context.Context, opts *PackageOpts) *Requirements { if pathErr, ok := err.(*module.InvalidPathError); ok { pathErr.Kind = "module" } - base.Fatalf("go: %v", err) + errs = append(errs, err) } } + if len(errs) > 0 { + return nil, errors.Join(errs...) + } MainModules = makeMainModules(mainModules, modRoots, modFiles, indices, workFile) setDefaultBuildMod() // possibly enable automatic vendoring @@ -835,7 +843,7 @@ func loadModFile(ctx context.Context, opts *PackageOpts) *Requirements { // We don't need to do anything for vendor or update the mod file so // return early. requirements = rs - return rs + return rs, nil } mainModule := MainModules.mustGetSingleMainModule() @@ -855,7 +863,7 @@ func loadModFile(ctx context.Context, opts *PackageOpts) *Requirements { var err error rs, err = updateRoots(ctx, rs.direct, rs, nil, nil, false) if err != nil { - base.Fatal(err) + return nil, err } } @@ -880,7 +888,7 @@ func loadModFile(ctx context.Context, opts *PackageOpts) *Requirements { var err error rs, err = convertPruning(ctx, rs, pruned) if err != nil { - base.Fatal(err) + return nil, err } } } else { @@ -889,7 +897,7 @@ func loadModFile(ctx context.Context, opts *PackageOpts) *Requirements { } requirements = rs - return requirements + return requirements, nil } // CreateModFile initializes a new module by creating a go.mod file. diff --git a/src/cmd/go/internal/modload/load.go b/src/cmd/go/internal/modload/load.go index 0a06b1b125..c597d53dde 100644 --- a/src/cmd/go/internal/modload/load.go +++ b/src/cmd/go/internal/modload/load.go @@ -341,7 +341,10 @@ func LoadPackages(ctx context.Context, opts PackageOpts, patterns ...string) (ma } } - initialRS := loadModFile(ctx, &opts) + initialRS, err := loadModFile(ctx, &opts) + if err != nil { + base.Fatal(err) + } ld := loadFromRoots(ctx, loaderParams{ PackageOpts: opts, diff --git a/src/cmd/go/internal/modload/modfile.go b/src/cmd/go/internal/modload/modfile.go index e4a54869ed..72fc293d8f 100644 --- a/src/cmd/go/internal/modload/modfile.go +++ b/src/cmd/go/internal/modload/modfile.go @@ -30,6 +30,7 @@ import ( // ReadModFile reads and parses the mod file at gomod. ReadModFile properly applies the // overlay, locks the file while reading, and applies fix, if applicable. func ReadModFile(gomod string, fix modfile.VersionFixer) (data []byte, f *modfile.File, err error) { + gomod = base.ShortPath(gomod) // use short path in any errors if gomodActual, ok := fsys.OverlayPath(gomod); ok { // Don't lock go.mod if it's part of the overlay. // On Plan 9, locking requires chmod, and we don't want to modify any file @@ -45,14 +46,18 @@ func ReadModFile(gomod string, fix modfile.VersionFixer) (data []byte, f *modfil f, err = modfile.Parse(gomod, data, fix) if err != nil { // Errors returned by modfile.Parse begin with file:line. - return nil, nil, fmt.Errorf("errors parsing go.mod:\n%s\n", err) + return nil, nil, fmt.Errorf("errors parsing %s:\n%w", gomod, err) } - if f.Go != nil && gover.Compare(f.Go.Version, gover.Local()) > 0 && cfg.CmdName != "mod edit" { - base.Fatalf("go: %v", &gover.TooNewError{What: base.ShortPath(gomod), GoVersion: f.Go.Version}) + if f.Go != nil && gover.Compare(f.Go.Version, gover.Local()) > 0 { + toolchain := "" + if f.Toolchain != nil { + toolchain = f.Toolchain.Name + } + return nil, nil, &gover.TooNewError{What: gomod, GoVersion: f.Go.Version, Toolchain: toolchain} } if f.Module == nil { // No module declaration. Must add module path. - return nil, nil, errors.New("no module declaration in go.mod. To specify the module path:\n\tgo mod edit -module=example.com/mod") + return nil, nil, fmt.Errorf("error reading %s: missing module declaration. To specify the module path:\n\tgo mod edit -module=example.com/mod", gomod) } return data, f, err diff --git a/src/cmd/go/testdata/script/mod_goline_too_new.txt b/src/cmd/go/testdata/script/mod_goline_too_new.txt index 97b0af52c1..29077df625 100644 --- a/src/cmd/go/testdata/script/mod_goline_too_new.txt +++ b/src/cmd/go/testdata/script/mod_goline_too_new.txt @@ -8,7 +8,7 @@ stderr '^go: go.mod requires go >= 1.99999 \(running go 1\..+\)$' # go.mod referenced from go.work too new cp go.work.old go.work ! go build . -stderr '^go: go.mod requires go >= 1.99999 \(running go 1\..+\)$' +stderr '^go: cannot load module go.mod listed in go.work file: go.mod requires go >= 1.99999 \(running go 1\..+\)$' # go.work too new cp go.work.new go.work diff --git a/src/cmd/go/testdata/script/mod_invalid_path.txt b/src/cmd/go/testdata/script/mod_invalid_path.txt index 667b76e340..975de5ebca 100644 --- a/src/cmd/go/testdata/script/mod_invalid_path.txt +++ b/src/cmd/go/testdata/script/mod_invalid_path.txt @@ -3,7 +3,7 @@ # Test that go list fails on a go.mod with no module declaration. cd $WORK/gopath/src/mod ! go list . -stderr '^go: no module declaration in go.mod. To specify the module path:\n\tgo mod edit -module=example.com/mod$' +stderr '^go: error reading go.mod: missing module declaration. To specify the module path:\n\tgo mod edit -module=example.com/mod$' # Test that go mod init in GOPATH doesn't add a module declaration # with a path that can't possibly be a module path, because diff --git a/src/cmd/go/testdata/script/mod_invalid_version.txt b/src/cmd/go/testdata/script/mod_invalid_version.txt index c841f27a21..a0427b39a0 100644 --- a/src/cmd/go/testdata/script/mod_invalid_version.txt +++ b/src/cmd/go/testdata/script/mod_invalid_version.txt @@ -50,7 +50,7 @@ cd outside stderr 'go: example.com@v0.0.0 \(replaced by \./\.\.\): parsing ..[/\\]go.mod: '$WORK'[/\\]gopath[/\\]src[/\\]go.mod:5: require golang.org/x/text: version "v2.1.1-0.20170915032832-14c0d48ead0c" invalid: should be v0 or v1, not v2' cd .. ! go list -m golang.org/x/text -stderr $WORK'[/\\]gopath[/\\]src[/\\]go.mod:5: require golang.org/x/text: version "v2.1.1-0.20170915032832-14c0d48ead0c" invalid: should be v0 or v1, not v2' +stderr '^go.mod:5: require golang.org/x/text: version "v2.1.1-0.20170915032832-14c0d48ead0c" invalid: should be v0 or v1, not v2' # A pseudo-version with fewer than 12 digits of SHA-1 prefix is invalid. cp go.mod.orig go.mod