1
0
mirror of https://github.com/golang/go synced 2024-11-08 02:36:18 -07:00

cmd/go: clarify errors for commands run outside a module

The new error message tells the user what was wrong (no go.mod found)
and directs them to 'go help modules', which links to tutorials.

Fixes #44745

Change-Id: I98f31fec4a8757eb1792b45491519da4c552cb0f
Reviewed-on: https://go-review.googlesource.com/c/go/+/298650
Trust: Jay Conrod <jayconrod@google.com>
Run-TryBot: Jay Conrod <jayconrod@google.com>
TryBot-Result: Go Bot <gobot@golang.org>
Reviewed-by: Bryan C. Mills <bcmills@google.com>
This commit is contained in:
Jay Conrod 2021-03-04 10:35:17 -05:00
parent a99ff24a26
commit b87e9b9f68
9 changed files with 47 additions and 59 deletions

View File

@ -186,7 +186,7 @@ func (q *query) validate() error {
if q.pattern == "all" { if q.pattern == "all" {
// If there is no main module, "all" is not meaningful. // If there is no main module, "all" is not meaningful.
if !modload.HasModRoot() { if !modload.HasModRoot() {
return fmt.Errorf(`cannot match "all": working directory is not part of a module`) return fmt.Errorf(`cannot match "all": %v`, modload.ErrNoModRoot)
} }
if !versionOkForMainModule(q.version) { if !versionOkForMainModule(q.version) {
// TODO(bcmills): "all@none" seems like a totally reasonable way to // TODO(bcmills): "all@none" seems like a totally reasonable way to

View File

@ -51,7 +51,7 @@ func (e *ImportMissingError) Error() string {
if e.isStd { if e.isStd {
return fmt.Sprintf("package %s is not in GOROOT (%s)", e.Path, filepath.Join(cfg.GOROOT, "src", e.Path)) return fmt.Sprintf("package %s is not in GOROOT (%s)", e.Path, filepath.Join(cfg.GOROOT, "src", e.Path))
} }
if e.QueryErr != nil { if e.QueryErr != nil && e.QueryErr != ErrNoModRoot {
return fmt.Sprintf("cannot find module providing package %s: %v", e.Path, e.QueryErr) return fmt.Sprintf("cannot find module providing package %s: %v", e.Path, e.QueryErr)
} }
if cfg.BuildMod == "mod" || (cfg.BuildMod == "readonly" && allowMissingModuleImports) { if cfg.BuildMod == "mod" || (cfg.BuildMod == "readonly" && allowMissingModuleImports) {
@ -66,13 +66,11 @@ func (e *ImportMissingError) Error() string {
return fmt.Sprintf("module %s provides package %s and is replaced but not required; to add it:\n\tgo get %s", e.replaced.Path, e.Path, suggestArg) return fmt.Sprintf("module %s provides package %s and is replaced but not required; to add it:\n\tgo get %s", e.replaced.Path, e.Path, suggestArg)
} }
suggestion := "" message := fmt.Sprintf("no required module provides package %s", e.Path)
if !HasModRoot() { if e.QueryErr != nil {
suggestion = ": working directory is not part of a module" return fmt.Sprintf("%s: %v", message, e.QueryErr)
} else {
suggestion = fmt.Sprintf("; to add it:\n\tgo get %s", e.Path)
} }
return fmt.Sprintf("no required module provides package %s%s", e.Path, suggestion) return fmt.Sprintf("%s; to add it:\n\tgo get %s", message, e.Path)
} }
if e.newMissingVersion != "" { if e.newMissingVersion != "" {
@ -318,7 +316,11 @@ func importFromBuildList(ctx context.Context, path string, buildList []module.Ve
return mods[0], dirs[0], nil return mods[0], dirs[0], nil
} }
return module.Version{}, "", &ImportMissingError{Path: path, isStd: pathIsStd} var queryErr error
if !HasModRoot() {
queryErr = ErrNoModRoot
}
return module.Version{}, "", &ImportMissingError{Path: path, QueryErr: queryErr, isStd: pathIsStd}
} }
// queryImport attempts to locate a module that can be added to the current // queryImport attempts to locate a module that can be added to the current

View File

@ -177,7 +177,7 @@ func Init() {
base.Fatalf("go: cannot find main module, but -modfile was set.\n\t-modfile cannot be used to set the module root directory.") base.Fatalf("go: cannot find main module, but -modfile was set.\n\t-modfile cannot be used to set the module root directory.")
} }
if RootMode == NeedRoot { if RootMode == NeedRoot {
base.Fatalf("go: cannot find main module; see 'go help modules'") base.Fatalf("go: %v", ErrNoModRoot)
} }
if !mustUseModules { if !mustUseModules {
// GO111MODULE is 'auto', and we can't find a module root. // GO111MODULE is 'auto', and we can't find a module root.
@ -338,9 +338,11 @@ func die() {
} }
base.Fatalf("go: cannot find main module, but found %s in %s\n\tto create a module there, run:\n\t%sgo mod init", name, dir, cdCmd) base.Fatalf("go: cannot find main module, but found %s in %s\n\tto create a module there, run:\n\t%sgo mod init", name, dir, cdCmd)
} }
base.Fatalf("go: cannot find main module; see 'go help modules'") base.Fatalf("go: %v", ErrNoModRoot)
} }
var ErrNoModRoot = errors.New("go.mod file not found in current directory or any parent directory; see 'go help modules'")
// LoadModFile sets Target and, if there is a main module, parses the initial // LoadModFile sets Target and, if there is a main module, parses the initial
// build list from its go.mod file. // build list from its go.mod file.
// //

View File

@ -73,7 +73,7 @@ func listModules(ctx context.Context, args []string, listVersions, listRetracted
base.Fatalf("go: cannot use relative path %s to specify module", arg) base.Fatalf("go: cannot use relative path %s to specify module", arg)
} }
if !HasModRoot() && (arg == "all" || strings.Contains(arg, "...")) { if !HasModRoot() && (arg == "all" || strings.Contains(arg, "...")) {
base.Fatalf("go: cannot match %q: working directory is not part of a module", arg) base.Fatalf("go: cannot match %q: %v", arg, ErrNoModRoot)
} }
if i := strings.Index(arg, "@"); i >= 0 { if i := strings.Index(arg, "@"); i >= 0 {
path := arg[:i] path := arg[:i]

View File

@ -96,28 +96,12 @@ func runRun(ctx context.Context, cmd *base.Command, args []string) {
base.Fatalf("go run: no go files listed") base.Fatalf("go run: no go files listed")
} }
cmdArgs := args[i:] cmdArgs := args[i:]
if p.Error != nil { load.CheckPackageErrors([]*load.Package{p})
base.Fatalf("%s", p.Error)
}
p.Internal.OmitDebug = true
if len(p.DepsErrors) > 0 {
// Since these are errors in dependencies,
// the same error might show up multiple times,
// once in each package that depends on it.
// Only print each once.
printed := map[*load.PackageError]bool{}
for _, err := range p.DepsErrors {
if !printed[err] {
printed[err] = true
base.Errorf("%s", err)
}
}
}
base.ExitIfErrors()
if p.Name != "main" { if p.Name != "main" {
base.Fatalf("go run: cannot run non-main package") base.Fatalf("go run: cannot run non-main package")
} }
p.Internal.OmitDebug = true
p.Target = "" // must build - not up to date p.Target = "" // must build - not up to date
if p.Internal.CmdlineFiles { if p.Internal.CmdlineFiles {
//set executable name if go file is given as cmd-argument //set executable name if go file is given as cmd-argument

View File

@ -18,7 +18,7 @@ stdout '^m$'
# Test that we ignore directories when trying to find alternate config files. # Test that we ignore directories when trying to find alternate config files.
cd $WORK/gopkgdir/x cd $WORK/gopkgdir/x
! go list . ! go list .
stderr 'cannot find main module' stderr '^go: go.mod file not found in current directory or any parent directory; see ''go help modules''$'
! stderr 'Gopkg.lock' ! stderr 'Gopkg.lock'
-- $WORK/test/Gopkg.lock -- -- $WORK/test/Gopkg.lock --

View File

@ -49,7 +49,7 @@ rm go.mod
# Test that we ignore directories when trying to find go.mod. # Test that we ignore directories when trying to find go.mod.
cd $WORK/gomoddir cd $WORK/gomoddir
! go list . ! go list .
stderr 'cannot find main module' stderr '^go: go.mod file not found in current directory or any parent directory; see ''go help modules''$'
[!symlink] stop [!symlink] stop

View File

@ -12,13 +12,13 @@ stdout 'NUL|/dev/null'
# 'go list' without arguments implicitly operates on the current directory, # 'go list' without arguments implicitly operates on the current directory,
# which is not in a module. # which is not in a module.
! go list ! go list
stderr 'cannot find main module' stderr '^go: go.mod file not found in current directory or any parent directory; see ''go help modules''$'
go list -m go list -m
stdout '^command-line-arguments$' stdout '^command-line-arguments$'
# 'go list' in the working directory should fail even if there is a a 'package # 'go list' in the working directory should fail even if there is a a 'package
# main' present: without a main module, we do not know its package path. # main' present: without a main module, we do not know its package path.
! go list ./needmod ! go list ./needmod
stderr 'cannot find main module' stderr '^go: go.mod file not found in current directory or any parent directory; see ''go help modules''$'
# 'go list all' lists the transitive import graph of the main module, # 'go list all' lists the transitive import graph of the main module,
# which is empty if there is no main module. # which is empty if there is no main module.
@ -41,7 +41,7 @@ stdout 'command-line-arguments'
# 'go list' on a package from a module should fail. # 'go list' on a package from a module should fail.
! go list example.com/printversion ! go list example.com/printversion
stderr '^no required module provides package example.com/printversion: working directory is not part of a module$' stderr '^no required module provides package example.com/printversion: go.mod file not found in current directory or any parent directory; see ''go help modules''$'
# 'go list -m' with an explicit version should resolve that version. # 'go list -m' with an explicit version should resolve that version.
@ -54,19 +54,19 @@ stdout 'v1.0.0\s+v1.0.1\s+v1.1.0'
# 'go list -m all' should fail. "all" is not meaningful outside of a module. # 'go list -m all' should fail. "all" is not meaningful outside of a module.
! go list -m all ! go list -m all
stderr 'go: cannot match "all": working directory is not part of a module' stderr 'go: cannot match "all": go.mod file not found in current directory or any parent directory; see ''go help modules''$'
# 'go list -m <mods> all' should also fail. # 'go list -m <mods> all' should also fail.
! go list -m example.com/printversion@v1.0.0 all ! go list -m example.com/printversion@v1.0.0 all
stderr 'go: cannot match "all": working directory is not part of a module' stderr 'go: cannot match "all": go.mod file not found in current directory or any parent directory; see ''go help modules''$'
! stdout 'example.com/version' ! stdout 'example.com/version'
# 'go list -m' with wildcards should fail. Wildcards match modules in the # 'go list -m' with wildcards should fail. Wildcards match modules in the
# build list, so they aren't meaningful outside a module. # build list, so they aren't meaningful outside a module.
! go list -m ... ! go list -m ...
stderr 'go: cannot match "...": working directory is not part of a module' stderr 'go: cannot match "...": go.mod file not found in current directory or any parent directory; see ''go help modules''$'
! go list -m rsc.io/quote/... ! go list -m rsc.io/quote/...
stderr 'go: cannot match "rsc.io/quote/...": working directory is not part of a module' stderr 'go: cannot match "rsc.io/quote/...": go.mod file not found in current directory or any parent directory; see ''go help modules''$'
# 'go clean' should skip the current directory if it isn't in a module. # 'go clean' should skip the current directory if it isn't in a module.
@ -76,20 +76,20 @@ go clean -n
# 'go mod graph' should fail, since there's no module graph. # 'go mod graph' should fail, since there's no module graph.
! go mod graph ! go mod graph
stderr 'cannot find main module' stderr '^go: go.mod file not found in current directory or any parent directory; see ''go help modules''$'
# 'go mod why' should fail, since there is no main module to depend on anything. # 'go mod why' should fail, since there is no main module to depend on anything.
! go mod why -m example.com/version ! go mod why -m example.com/version
stderr 'cannot find main module' stderr '^go: go.mod file not found in current directory or any parent directory; see ''go help modules''$'
# 'go mod edit', 'go mod tidy', and 'go mod fmt' should fail: # 'go mod edit', 'go mod tidy', and 'go mod fmt' should fail:
# there is no go.mod file to edit. # there is no go.mod file to edit.
! go mod tidy ! go mod tidy
stderr 'cannot find main module' stderr '^go: go.mod file not found in current directory or any parent directory; see ''go help modules''$'
! go mod edit -fmt ! go mod edit -fmt
stderr 'cannot find main module' stderr '^go: go.mod file not found in current directory or any parent directory; see ''go help modules''$'
! go mod edit -require example.com/version@v1.0.0 ! go mod edit -require example.com/version@v1.0.0
stderr 'cannot find main module' stderr '^go: go.mod file not found in current directory or any parent directory; see ''go help modules''$'
# 'go mod download' without arguments should report an error. # 'go mod download' without arguments should report an error.
@ -104,33 +104,33 @@ exists $GOPATH/pkg/mod/cache/download/example.com/printversion/@v/v1.0.0.zip
# 'go mod download all' should fail. "all" is not meaningful outside of a module. # 'go mod download all' should fail. "all" is not meaningful outside of a module.
! go mod download all ! go mod download all
stderr 'go: cannot match "all": working directory is not part of a module' stderr 'go: cannot match "all": go.mod file not found in current directory or any parent directory; see ''go help modules''$'
# 'go mod vendor' should fail: it starts by clearing the existing vendor # 'go mod vendor' should fail: it starts by clearing the existing vendor
# directory, and we don't know where that is. # directory, and we don't know where that is.
! go mod vendor ! go mod vendor
stderr 'cannot find main module' stderr '^go: go.mod file not found in current directory or any parent directory; see ''go help modules''$'
# 'go mod verify' should fail: we have no modules to verify. # 'go mod verify' should fail: we have no modules to verify.
! go mod verify ! go mod verify
stderr 'cannot find main module' stderr '^go: go.mod file not found in current directory or any parent directory; see ''go help modules''$'
# 'go get' without arguments implicitly operates on the main module, and thus # 'go get' without arguments implicitly operates on the main module, and thus
# should fail. # should fail.
! go get ! go get
stderr 'cannot find main module' stderr '^go: go.mod file not found in current directory or any parent directory; see ''go help modules''$'
! go get -u ! go get -u
stderr 'cannot find main module' stderr '^go: go.mod file not found in current directory or any parent directory; see ''go help modules''$'
! go get -u ./needmod ! go get -u ./needmod
stderr 'cannot find main module' stderr '^go: go.mod file not found in current directory or any parent directory; see ''go help modules''$'
# 'go get -u all' upgrades the transitive import graph of the main module, # 'go get -u all' upgrades the transitive import graph of the main module,
# which is empty. # which is empty.
! go get -u all ! go get -u all
stderr 'go get: cannot match "all": working directory is not part of a module' stderr '^go get: cannot match "all": go.mod file not found in current directory or any parent directory; see ''go help modules''$'
# 'go get' should check the proposed module graph for consistency, # 'go get' should check the proposed module graph for consistency,
# even though we won't write it anywhere. # even though we won't write it anywhere.
@ -147,16 +147,16 @@ exists $GOPATH/pkg/mod/example.com/version@v1.0.0
# 'go build' without arguments implicitly operates on the current directory, and should fail. # 'go build' without arguments implicitly operates on the current directory, and should fail.
cd needmod cd needmod
! go build ! go build
stderr 'cannot find main module' stderr '^go: go.mod file not found in current directory or any parent directory; see ''go help modules''$'
cd .. cd ..
# 'go build' of a non-module directory should fail too. # 'go build' of a non-module directory should fail too.
! go build ./needmod ! go build ./needmod
stderr 'cannot find main module' stderr '^go: go.mod file not found in current directory or any parent directory; see ''go help modules''$'
# 'go build' of source files should fail if they import anything outside std. # 'go build' of source files should fail if they import anything outside std.
! go build -n ./needmod/needmod.go ! go build -n ./needmod/needmod.go
stderr '^needmod[/\\]needmod.go:10:2: no required module provides package example.com/version: working directory is not part of a module$' stderr '^needmod[/\\]needmod.go:10:2: no required module provides package example.com/version: go.mod file not found in current directory or any parent directory; see ''go help modules''$'
# 'go build' of source files should succeed if they do not import anything outside std. # 'go build' of source files should succeed if they do not import anything outside std.
go build -n -o ignore ./stdonly/stdonly.go go build -n -o ignore ./stdonly/stdonly.go
@ -179,7 +179,7 @@ go doc fmt
# 'go doc' should fail for a package path outside a module. # 'go doc' should fail for a package path outside a module.
! go doc example.com/version ! go doc example.com/version
stderr 'doc: no required module provides package example.com/version: working directory is not part of a module' stderr 'doc: no required module provides package example.com/version: go.mod file not found in current directory or any parent directory; see ''go help modules''$'
# 'go install' with a version should succeed if all constraints are met. # 'go install' with a version should succeed if all constraints are met.
# See mod_install_pkg_version. # See mod_install_pkg_version.
@ -194,7 +194,7 @@ stderr '^go install: version is required when current directory is not in a modu
# 'go install' should fail if a source file imports a package that must be # 'go install' should fail if a source file imports a package that must be
# resolved to a module. # resolved to a module.
! go install ./needmod/needmod.go ! go install ./needmod/needmod.go
stderr 'needmod[/\\]needmod.go:10:2: no required module provides package example.com/version: working directory is not part of a module' stderr 'needmod[/\\]needmod.go:10:2: no required module provides package example.com/version: go.mod file not found in current directory or any parent directory; see ''go help modules''$'
# 'go install' should succeed with a package in GOROOT. # 'go install' should succeed with a package in GOROOT.
go install cmd/addr2line go install cmd/addr2line
@ -206,12 +206,12 @@ stderr 'can only use path@version syntax with'
# 'go run' should fail if a package argument must be resolved to a module. # 'go run' should fail if a package argument must be resolved to a module.
! go run example.com/printversion ! go run example.com/printversion
stderr '^no required module provides package example.com/printversion: working directory is not part of a module$' stderr '^no required module provides package example.com/printversion: go.mod file not found in current directory or any parent directory; see ''go help modules''$'
# 'go run' should fail if a source file imports a package that must be # 'go run' should fail if a source file imports a package that must be
# resolved to a module. # resolved to a module.
! go run ./needmod/needmod.go ! go run ./needmod/needmod.go
stderr '^needmod[/\\]needmod.go:10:2: no required module provides package example.com/version: working directory is not part of a module$' stderr '^needmod[/\\]needmod.go:10:2: no required module provides package example.com/version: go.mod file not found in current directory or any parent directory; see ''go help modules''$'
# 'go fmt' should be able to format files outside of a module. # 'go fmt' should be able to format files outside of a module.

View File

@ -644,7 +644,7 @@ func TestImportPackageOutsideModule(t *testing.T) {
ctxt.GOPATH = gopath ctxt.GOPATH = gopath
ctxt.Dir = filepath.Join(gopath, "src/example.com/p") ctxt.Dir = filepath.Join(gopath, "src/example.com/p")
want := "working directory is not part of a module" want := "go.mod file not found in current directory or any parent directory"
if _, err := ctxt.Import("example.com/p", gopath, FindOnly); err == nil { if _, err := ctxt.Import("example.com/p", gopath, FindOnly); err == nil {
t.Fatal("importing package when no go.mod is present succeeded unexpectedly") t.Fatal("importing package when no go.mod is present succeeded unexpectedly")
} else if errStr := err.Error(); !strings.Contains(errStr, want) { } else if errStr := err.Error(); !strings.Contains(errStr, want) {