Skip to content

Commit 5993fbb

Browse files
Jay Conrodtoothrot
Jay Conrod
authored andcommitted
[release-branch.go1.16] 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. Includes test fix from CL 298794 Fixes #44746 Change-Id: I98f31fec4a8757eb1792b45491519da4c552cb0f Reviewed-on: https://go-review.googlesource.com/c/go/+/298650 Trust: Jay Conrod <[email protected]> Run-TryBot: Jay Conrod <[email protected]> TryBot-Result: Go Bot <[email protected]> Reviewed-by: Bryan C. Mills <[email protected]> (cherry picked from commit b87e9b9) Reviewed-on: https://go-review.googlesource.com/c/go/+/298929
1 parent 6e04188 commit 5993fbb

File tree

10 files changed

+49
-61
lines changed

10 files changed

+49
-61
lines changed

src/cmd/go/internal/modget/query.go

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -186,7 +186,7 @@ func (q *query) validate() error {
186186
if q.pattern == "all" {
187187
// If there is no main module, "all" is not meaningful.
188188
if !modload.HasModRoot() {
189-
return fmt.Errorf(`cannot match "all": working directory is not part of a module`)
189+
return fmt.Errorf(`cannot match "all": %v`, modload.ErrNoModRoot)
190190
}
191191
if !versionOkForMainModule(q.version) {
192192
// TODO(bcmills): "all@none" seems like a totally reasonable way to

src/cmd/go/internal/modload/import.go

Lines changed: 10 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -51,7 +51,7 @@ func (e *ImportMissingError) Error() string {
5151
if e.isStd {
5252
return fmt.Sprintf("package %s is not in GOROOT (%s)", e.Path, filepath.Join(cfg.GOROOT, "src", e.Path))
5353
}
54-
if e.QueryErr != nil {
54+
if e.QueryErr != nil && e.QueryErr != ErrNoModRoot {
5555
return fmt.Sprintf("cannot find module providing package %s: %v", e.Path, e.QueryErr)
5656
}
5757
if cfg.BuildMod == "mod" || (cfg.BuildMod == "readonly" && allowMissingModuleImports) {
@@ -66,13 +66,11 @@ func (e *ImportMissingError) Error() string {
6666
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)
6767
}
6868

69-
suggestion := ""
70-
if !HasModRoot() {
71-
suggestion = ": working directory is not part of a module"
72-
} else {
73-
suggestion = fmt.Sprintf("; to add it:\n\tgo get %s", e.Path)
69+
message := fmt.Sprintf("no required module provides package %s", e.Path)
70+
if e.QueryErr != nil {
71+
return fmt.Sprintf("%s: %v", message, e.QueryErr)
7472
}
75-
return fmt.Sprintf("no required module provides package %s%s", e.Path, suggestion)
73+
return fmt.Sprintf("%s; to add it:\n\tgo get %s", message, e.Path)
7674
}
7775

7876
if e.newMissingVersion != "" {
@@ -318,7 +316,11 @@ func importFromBuildList(ctx context.Context, path string, buildList []module.Ve
318316
return mods[0], dirs[0], nil
319317
}
320318

321-
return module.Version{}, "", &ImportMissingError{Path: path, isStd: pathIsStd}
319+
var queryErr error
320+
if !HasModRoot() {
321+
queryErr = ErrNoModRoot
322+
}
323+
return module.Version{}, "", &ImportMissingError{Path: path, QueryErr: queryErr, isStd: pathIsStd}
322324
}
323325

324326
// queryImport attempts to locate a module that can be added to the current

src/cmd/go/internal/modload/init.go

Lines changed: 4 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -177,7 +177,7 @@ func Init() {
177177
base.Fatalf("go: cannot find main module, but -modfile was set.\n\t-modfile cannot be used to set the module root directory.")
178178
}
179179
if RootMode == NeedRoot {
180-
base.Fatalf("go: cannot find main module; see 'go help modules'")
180+
base.Fatalf("go: %v", ErrNoModRoot)
181181
}
182182
if !mustUseModules {
183183
// GO111MODULE is 'auto', and we can't find a module root.
@@ -338,9 +338,11 @@ func die() {
338338
}
339339
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)
340340
}
341-
base.Fatalf("go: cannot find main module; see 'go help modules'")
341+
base.Fatalf("go: %v", ErrNoModRoot)
342342
}
343343

344+
var ErrNoModRoot = errors.New("go.mod file not found in current directory or any parent directory; see 'go help modules'")
345+
344346
// LoadModFile sets Target and, if there is a main module, parses the initial
345347
// build list from its go.mod file.
346348
//

src/cmd/go/internal/modload/list.go

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -73,7 +73,7 @@ func listModules(ctx context.Context, args []string, listVersions, listRetracted
7373
base.Fatalf("go: cannot use relative path %s to specify module", arg)
7474
}
7575
if !HasModRoot() && (arg == "all" || strings.Contains(arg, "...")) {
76-
base.Fatalf("go: cannot match %q: working directory is not part of a module", arg)
76+
base.Fatalf("go: cannot match %q: %v", arg, ErrNoModRoot)
7777
}
7878
if i := strings.Index(arg, "@"); i >= 0 {
7979
path := arg[:i]

src/cmd/go/internal/run/run.go

Lines changed: 2 additions & 18 deletions
Original file line numberDiff line numberDiff line change
@@ -96,28 +96,12 @@ func runRun(ctx context.Context, cmd *base.Command, args []string) {
9696
base.Fatalf("go run: no go files listed")
9797
}
9898
cmdArgs := args[i:]
99-
if p.Error != nil {
100-
base.Fatalf("%s", p.Error)
101-
}
99+
load.CheckPackageErrors([]*load.Package{p})
102100

103-
p.Internal.OmitDebug = true
104-
if len(p.DepsErrors) > 0 {
105-
// Since these are errors in dependencies,
106-
// the same error might show up multiple times,
107-
// once in each package that depends on it.
108-
// Only print each once.
109-
printed := map[*load.PackageError]bool{}
110-
for _, err := range p.DepsErrors {
111-
if !printed[err] {
112-
printed[err] = true
113-
base.Errorf("%s", err)
114-
}
115-
}
116-
}
117-
base.ExitIfErrors()
118101
if p.Name != "main" {
119102
base.Fatalf("go run: cannot run non-main package")
120103
}
104+
p.Internal.OmitDebug = true
121105
p.Target = "" // must build - not up to date
122106
if p.Internal.CmdlineFiles {
123107
//set executable name if go file is given as cmd-argument

src/cmd/go/testdata/script/mod_convert_dep.txt

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -18,7 +18,7 @@ stdout '^m$'
1818
# Test that we ignore directories when trying to find alternate config files.
1919
cd $WORK/gopkgdir/x
2020
! go list .
21-
stderr 'cannot find main module'
21+
stderr '^go: go.mod file not found in current directory or any parent directory; see ''go help modules''$'
2222
! stderr 'Gopkg.lock'
2323

2424
-- $WORK/test/Gopkg.lock --

src/cmd/go/testdata/script/mod_find.txt

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -49,7 +49,7 @@ rm go.mod
4949
# Test that we ignore directories when trying to find go.mod.
5050
cd $WORK/gomoddir
5151
! go list .
52-
stderr 'cannot find main module'
52+
stderr '^go: go.mod file not found in current directory or any parent directory; see ''go help modules''$'
5353

5454
[!symlink] stop
5555

src/cmd/go/testdata/script/mod_install_pkg_version.txt

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -59,9 +59,9 @@ rm $GOPATH/bin
5959
env GO111MODULE=on
6060
go mod download rsc.io/[email protected]
6161
! go install $GOPATH/pkg/mod/rsc.io/[email protected]
62-
stderr '^go: cannot find main module; see ''go help modules''$'
62+
stderr '^go: go\.mod file not found in current directory or any parent directory; see ''go help modules''$'
6363
! go install ../pkg/mod/rsc.io/[email protected]
64-
stderr '^go: cannot find main module; see ''go help modules''$'
64+
stderr '^go: go\.mod file not found in current directory or any parent directory; see ''go help modules''$'
6565
mkdir tmp
6666
cd tmp
6767
go mod init tmp

src/cmd/go/testdata/script/mod_outside.txt

Lines changed: 26 additions & 26 deletions
Original file line numberDiff line numberDiff line change
@@ -12,13 +12,13 @@ stdout 'NUL|/dev/null'
1212
# 'go list' without arguments implicitly operates on the current directory,
1313
# which is not in a module.
1414
! go list
15-
stderr 'cannot find main module'
15+
stderr '^go: go.mod file not found in current directory or any parent directory; see ''go help modules''$'
1616
go list -m
1717
stdout '^command-line-arguments$'
1818
# 'go list' in the working directory should fail even if there is a a 'package
1919
# main' present: without a main module, we do not know its package path.
2020
! go list ./needmod
21-
stderr 'cannot find main module'
21+
stderr '^go: go.mod file not found in current directory or any parent directory; see ''go help modules''$'
2222

2323
# 'go list all' lists the transitive import graph of the main module,
2424
# which is empty if there is no main module.
@@ -41,7 +41,7 @@ stdout 'command-line-arguments'
4141

4242
# 'go list' on a package from a module should fail.
4343
! go list example.com/printversion
44-
stderr '^no required module provides package example.com/printversion: working directory is not part of a module$'
44+
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''$'
4545

4646

4747
# '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'
5454

5555
# 'go list -m all' should fail. "all" is not meaningful outside of a module.
5656
! go list -m all
57-
stderr 'go: cannot match "all": working directory is not part of a module'
57+
stderr 'go: cannot match "all": go.mod file not found in current directory or any parent directory; see ''go help modules''$'
5858

5959
# 'go list -m <mods> all' should also fail.
6060
! go list -m example.com/[email protected] all
61-
stderr 'go: cannot match "all": working directory is not part of a module'
61+
stderr 'go: cannot match "all": go.mod file not found in current directory or any parent directory; see ''go help modules''$'
6262
! stdout 'example.com/version'
6363

6464
# 'go list -m' with wildcards should fail. Wildcards match modules in the
6565
# build list, so they aren't meaningful outside a module.
6666
! go list -m ...
67-
stderr 'go: cannot match "...": working directory is not part of a module'
67+
stderr 'go: cannot match "...": go.mod file not found in current directory or any parent directory; see ''go help modules''$'
6868
! go list -m rsc.io/quote/...
69-
stderr 'go: cannot match "rsc.io/quote/...": working directory is not part of a module'
69+
stderr 'go: cannot match "rsc.io/quote/...": go.mod file not found in current directory or any parent directory; see ''go help modules''$'
7070

7171

7272
# 'go clean' should skip the current directory if it isn't in a module.
@@ -76,20 +76,20 @@ go clean -n
7676

7777
# 'go mod graph' should fail, since there's no module graph.
7878
! go mod graph
79-
stderr 'cannot find main module'
79+
stderr '^go: go.mod file not found in current directory or any parent directory; see ''go help modules''$'
8080

8181
# 'go mod why' should fail, since there is no main module to depend on anything.
8282
! go mod why -m example.com/version
83-
stderr 'cannot find main module'
83+
stderr '^go: go.mod file not found in current directory or any parent directory; see ''go help modules''$'
8484

8585
# 'go mod edit', 'go mod tidy', and 'go mod fmt' should fail:
8686
# there is no go.mod file to edit.
8787
! go mod tidy
88-
stderr 'cannot find main module'
88+
stderr '^go: go.mod file not found in current directory or any parent directory; see ''go help modules''$'
8989
! go mod edit -fmt
90-
stderr 'cannot find main module'
90+
stderr '^go: go.mod file not found in current directory or any parent directory; see ''go help modules''$'
9191
! go mod edit -require example.com/[email protected]
92-
stderr 'cannot find main module'
92+
stderr '^go: go.mod file not found in current directory or any parent directory; see ''go help modules''$'
9393

9494

9595
# '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
104104

105105
# 'go mod download all' should fail. "all" is not meaningful outside of a module.
106106
! go mod download all
107-
stderr 'go: cannot match "all": working directory is not part of a module'
107+
stderr 'go: cannot match "all": go.mod file not found in current directory or any parent directory; see ''go help modules''$'
108108

109109

110110
# 'go mod vendor' should fail: it starts by clearing the existing vendor
111111
# directory, and we don't know where that is.
112112
! go mod vendor
113-
stderr 'cannot find main module'
113+
stderr '^go: go.mod file not found in current directory or any parent directory; see ''go help modules''$'
114114

115115

116116
# 'go mod verify' should fail: we have no modules to verify.
117117
! go mod verify
118-
stderr 'cannot find main module'
118+
stderr '^go: go.mod file not found in current directory or any parent directory; see ''go help modules''$'
119119

120120

121121
# 'go get' without arguments implicitly operates on the main module, and thus
122122
# should fail.
123123
! go get
124-
stderr 'cannot find main module'
124+
stderr '^go: go.mod file not found in current directory or any parent directory; see ''go help modules''$'
125125
! go get -u
126-
stderr 'cannot find main module'
126+
stderr '^go: go.mod file not found in current directory or any parent directory; see ''go help modules''$'
127127
! go get -u ./needmod
128-
stderr 'cannot find main module'
128+
stderr '^go: go.mod file not found in current directory or any parent directory; see ''go help modules''$'
129129

130130
# 'go get -u all' upgrades the transitive import graph of the main module,
131131
# which is empty.
132132
! go get -u all
133-
stderr 'go get: cannot match "all": working directory is not part of a module'
133+
stderr '^go get: cannot match "all": go.mod file not found in current directory or any parent directory; see ''go help modules''$'
134134

135135
# 'go get' should check the proposed module graph for consistency,
136136
# even though we won't write it anywhere.
@@ -147,16 +147,16 @@ exists $GOPATH/pkg/mod/example.com/[email protected]
147147
# 'go build' without arguments implicitly operates on the current directory, and should fail.
148148
cd needmod
149149
! go build
150-
stderr 'cannot find main module'
150+
stderr '^go: go.mod file not found in current directory or any parent directory; see ''go help modules''$'
151151
cd ..
152152

153153
# 'go build' of a non-module directory should fail too.
154154
! go build ./needmod
155-
stderr 'cannot find main module'
155+
stderr '^go: go.mod file not found in current directory or any parent directory; see ''go help modules''$'
156156

157157
# 'go build' of source files should fail if they import anything outside std.
158158
! go build -n ./needmod/needmod.go
159-
stderr '^needmod[/\\]needmod.go:10:2: no required module provides package example.com/version: working directory is not part of a module$'
159+
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''$'
160160

161161
# 'go build' of source files should succeed if they do not import anything outside std.
162162
go build -n -o ignore ./stdonly/stdonly.go
@@ -179,7 +179,7 @@ go doc fmt
179179

180180
# 'go doc' should fail for a package path outside a module.
181181
! go doc example.com/version
182-
stderr 'doc: no required module provides package example.com/version: working directory is not part of a module'
182+
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''$'
183183

184184
# 'go install' with a version should succeed if all constraints are met.
185185
# See mod_install_pkg_version.
@@ -194,7 +194,7 @@ stderr '^go install: version is required when current directory is not in a modu
194194
# 'go install' should fail if a source file imports a package that must be
195195
# resolved to a module.
196196
! go install ./needmod/needmod.go
197-
stderr 'needmod[/\\]needmod.go:10:2: no required module provides package example.com/version: working directory is not part of a module'
197+
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''$'
198198

199199
# 'go install' should succeed with a package in GOROOT.
200200
go install cmd/addr2line
@@ -206,12 +206,12 @@ stderr 'can only use path@version syntax with'
206206

207207
# 'go run' should fail if a package argument must be resolved to a module.
208208
! go run example.com/printversion
209-
stderr '^no required module provides package example.com/printversion: working directory is not part of a module$'
209+
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''$'
210210

211211
# 'go run' should fail if a source file imports a package that must be
212212
# resolved to a module.
213213
! go run ./needmod/needmod.go
214-
stderr '^needmod[/\\]needmod.go:10:2: no required module provides package example.com/version: working directory is not part of a module$'
214+
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''$'
215215

216216

217217
# 'go fmt' should be able to format files outside of a module.

src/go/build/build_test.go

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -612,7 +612,7 @@ func TestImportPackageOutsideModule(t *testing.T) {
612612
ctxt.GOPATH = gopath
613613
ctxt.Dir = filepath.Join(gopath, "src/example.com/p")
614614

615-
want := "working directory is not part of a module"
615+
want := "go.mod file not found in current directory or any parent directory"
616616
if _, err := ctxt.Import("example.com/p", gopath, FindOnly); err == nil {
617617
t.Fatal("importing package when no go.mod is present succeeded unexpectedly")
618618
} else if errStr := err.Error(); !strings.Contains(errStr, want) {

0 commit comments

Comments
 (0)