Skip to content

Commit

Permalink
cmd/go: return more errors from ReadModFile, loadModFile
Browse files Browse the repository at this point in the history
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>
  • Loading branch information
rsc authored and gopherbot committed Jun 2, 2023
1 parent 40c7be9 commit c71cbd5
Show file tree
Hide file tree
Showing 8 changed files with 42 additions and 22 deletions.
1 change: 1 addition & 0 deletions src/cmd/go/internal/gover/toolchain.go
Original file line number Diff line number Diff line change
Expand Up @@ -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 {
Expand Down
5 changes: 4 additions & 1 deletion src/cmd/go/internal/modload/buildlist.go
Original file line number Diff line number Diff line change
Expand Up @@ -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")
Expand Down
34 changes: 21 additions & 13 deletions src/cmd/go/internal/modload/init.go
Original file line number Diff line number Diff line change
Expand Up @@ -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()
Expand All @@ -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"
Expand Down Expand Up @@ -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)
Expand All @@ -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
Expand All @@ -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()
Expand All @@ -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
}
}

Expand All @@ -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 {
Expand All @@ -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.
Expand Down
5 changes: 4 additions & 1 deletion src/cmd/go/internal/modload/load.go
Original file line number Diff line number Diff line change
Expand Up @@ -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,
Expand Down
13 changes: 9 additions & 4 deletions src/cmd/go/internal/modload/modfile.go
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand All @@ -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
Expand Down
2 changes: 1 addition & 1 deletion src/cmd/go/testdata/script/mod_goline_too_new.txt
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand Down
2 changes: 1 addition & 1 deletion src/cmd/go/testdata/script/mod_invalid_path.txt
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand Down
2 changes: 1 addition & 1 deletion src/cmd/go/testdata/script/mod_invalid_version.txt
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand Down

0 comments on commit c71cbd5

Please sign in to comment.