]> Cypherpunks repositories - gostls13.git/commitdiff
cmd/go: return more errors from ReadModFile, loadModFile
authorRuss Cox <rsc@golang.org>
Thu, 1 Jun 2023 18:13:20 +0000 (14:13 -0400)
committerGopher Robot <gobot@golang.org>
Fri, 2 Jun 2023 02:54:20 +0000 (02:54 +0000)
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 <bcmills@google.com>
Auto-Submit: Russ Cox <rsc@golang.org>
TryBot-Result: Gopher Robot <gobot@golang.org>
Run-TryBot: Russ Cox <rsc@golang.org>

src/cmd/go/internal/gover/toolchain.go
src/cmd/go/internal/modload/buildlist.go
src/cmd/go/internal/modload/init.go
src/cmd/go/internal/modload/load.go
src/cmd/go/internal/modload/modfile.go
src/cmd/go/testdata/script/mod_goline_too_new.txt
src/cmd/go/testdata/script/mod_invalid_path.txt
src/cmd/go/testdata/script/mod_invalid_version.txt

index f27e313524fb096fcfed9099992cdb17978d5070..7bd9229fcb54d41ba7ede42543ed1a0f35fa7da3 100644 (file)
@@ -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 {
index d71962dd6bd99e1d7b60dd2aa2ae312097939e5b..ecc07ed91ff6c52ff53f6df7ea5afc00519efada 100644 (file)
@@ -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")
index 737aaa910631f1a54210a74c6a8290b50d7c1473..c4b30fc14d951f7416e2abf66d2d4bb08ecd34e5 100644 (file)
@@ -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.
index 0a06b1b1253dcb0b80573ec4c92ca8783a735809..c597d53dde0552e7bffb7e4e46d28e89910de2e1 100644 (file)
@@ -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,
index e4a54869ed4858d7e2931ae10df5d493b3c58795..72fc293d8f2d88af63d687d25a3870a2778c2615 100644 (file)
@@ -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
index 97b0af52c1d17b689fad8a329b5edda5645737ab..29077df62574fd934c4af44002ed55541345d453 100644 (file)
@@ -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
index 667b76e340a5c4a02f1c22c95b75efde9313ed5e..975de5ebcabfcb79dd71c547e28fe84026898ed1 100644 (file)
@@ -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
index c841f27a214ff73d1af9c909552681cc0956f0d9..a0427b39a089e6696f6f45bb565d14082ce73974 100644 (file)
@@ -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