mirror of https://github.com/golang/go.git
cmd/go: only generate a go.mod file during 'go mod init'
In the general case, we do not know the correct module path for a new module unless we have checked its VCS tags for a major version. If we do not know the correct path, then we should not synthesize a go.mod file automatically from it. On the other hand, we don't want to run VCS commands in the working directory without an explicit request by the user to do so: 'go mod init' can reasonably invoke a VCS command, but 'go build' should not. Therefore, we should only create a go.mod file during 'go mod init'. This change removes the previous behavior of synthesizing a file automatically, and instead suggests a command that the user can opt to run explicitly. Updates #29433 Updates #27009 Updates #30228 Change-Id: I8c4554969db17156e97428df220b129a4d361040 Reviewed-on: https://go-review.googlesource.com/c/162699 Run-TryBot: Bryan C. Mills <bcmills@google.com> TryBot-Result: Gobot Gobot <gobot@golang.org> Reviewed-by: Jay Conrod <jayconrod@google.com>
This commit is contained in:
parent
4c89a10fb9
commit
65c2069a9f
|
|
@ -154,7 +154,7 @@ func Init() {
|
||||||
die() // Don't init a module that we're just going to ignore.
|
die() // Don't init a module that we're just going to ignore.
|
||||||
}
|
}
|
||||||
// No automatic enabling in GOPATH.
|
// No automatic enabling in GOPATH.
|
||||||
if root, _ := FindModuleRoot(cwd, "", false); root != "" {
|
if root := findModuleRoot(cwd); root != "" {
|
||||||
cfg.GoModInGOPATH = filepath.Join(root, "go.mod")
|
cfg.GoModInGOPATH = filepath.Join(root, "go.mod")
|
||||||
}
|
}
|
||||||
return
|
return
|
||||||
|
|
@ -164,7 +164,7 @@ func Init() {
|
||||||
// Running 'go mod init': go.mod will be created in current directory.
|
// Running 'go mod init': go.mod will be created in current directory.
|
||||||
modRoot = cwd
|
modRoot = cwd
|
||||||
} else {
|
} else {
|
||||||
modRoot, _ = FindModuleRoot(cwd, "", MustUseModules)
|
modRoot = findModuleRoot(cwd)
|
||||||
if modRoot == "" {
|
if modRoot == "" {
|
||||||
if !MustUseModules {
|
if !MustUseModules {
|
||||||
// GO111MODULE is 'auto' (or unset), and we can't find a module root.
|
// GO111MODULE is 'auto' (or unset), and we can't find a module root.
|
||||||
|
|
@ -302,6 +302,19 @@ func die() {
|
||||||
if inGOPATH && !MustUseModules {
|
if inGOPATH && !MustUseModules {
|
||||||
base.Fatalf("go: modules disabled inside GOPATH/src by GO111MODULE=auto; see 'go help modules'")
|
base.Fatalf("go: modules disabled inside GOPATH/src by GO111MODULE=auto; see 'go help modules'")
|
||||||
}
|
}
|
||||||
|
if cwd != "" {
|
||||||
|
if dir, name := findAltConfig(cwd); dir != "" {
|
||||||
|
rel, err := filepath.Rel(cwd, dir)
|
||||||
|
if err != nil {
|
||||||
|
rel = dir
|
||||||
|
}
|
||||||
|
cdCmd := ""
|
||||||
|
if rel != "." {
|
||||||
|
cdCmd = fmt.Sprintf("cd %s && ", rel)
|
||||||
|
}
|
||||||
|
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: cannot find main module; see 'go help modules'")
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -330,12 +343,6 @@ func InitMod() {
|
||||||
gomod := filepath.Join(modRoot, "go.mod")
|
gomod := filepath.Join(modRoot, "go.mod")
|
||||||
data, err := ioutil.ReadFile(gomod)
|
data, err := ioutil.ReadFile(gomod)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
if os.IsNotExist(err) {
|
|
||||||
legacyModInit()
|
|
||||||
modFileToBuildList()
|
|
||||||
WriteGoMod()
|
|
||||||
return
|
|
||||||
}
|
|
||||||
base.Fatalf("go: %v", err)
|
base.Fatalf("go: %v", err)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -349,7 +356,7 @@ func InitMod() {
|
||||||
|
|
||||||
if len(f.Syntax.Stmt) == 0 || f.Module == nil {
|
if len(f.Syntax.Stmt) == 0 || f.Module == nil {
|
||||||
// Empty mod file. Must add module path.
|
// Empty mod file. Must add module path.
|
||||||
path, err := FindModulePath(modRoot)
|
path, err := findModulePath(modRoot)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
base.Fatalf("go: %v", err)
|
base.Fatalf("go: %v", err)
|
||||||
}
|
}
|
||||||
|
|
@ -387,7 +394,7 @@ func Allowed(m module.Version) bool {
|
||||||
|
|
||||||
func legacyModInit() {
|
func legacyModInit() {
|
||||||
if modFile == nil {
|
if modFile == nil {
|
||||||
path, err := FindModulePath(modRoot)
|
path, err := findModulePath(modRoot)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
base.Fatalf("go: %v", err)
|
base.Fatalf("go: %v", err)
|
||||||
}
|
}
|
||||||
|
|
@ -454,19 +461,13 @@ var altConfigs = []string{
|
||||||
".git/config",
|
".git/config",
|
||||||
}
|
}
|
||||||
|
|
||||||
// Exported only for testing.
|
func findModuleRoot(dir string) (root string) {
|
||||||
func FindModuleRoot(dir, limit string, legacyConfigOK bool) (root, file string) {
|
|
||||||
dir = filepath.Clean(dir)
|
dir = filepath.Clean(dir)
|
||||||
dir1 := dir
|
|
||||||
limit = filepath.Clean(limit)
|
|
||||||
|
|
||||||
// Look for enclosing go.mod.
|
// Look for enclosing go.mod.
|
||||||
for {
|
for {
|
||||||
if fi, err := os.Stat(filepath.Join(dir, "go.mod")); err == nil && !fi.IsDir() {
|
if fi, err := os.Stat(filepath.Join(dir, "go.mod")); err == nil && !fi.IsDir() {
|
||||||
return dir, "go.mod"
|
return dir
|
||||||
}
|
|
||||||
if dir == limit {
|
|
||||||
break
|
|
||||||
}
|
}
|
||||||
d := filepath.Dir(dir)
|
d := filepath.Dir(dir)
|
||||||
if d == dir {
|
if d == dir {
|
||||||
|
|
@ -474,37 +475,41 @@ func FindModuleRoot(dir, limit string, legacyConfigOK bool) (root, file string)
|
||||||
}
|
}
|
||||||
dir = d
|
dir = d
|
||||||
}
|
}
|
||||||
|
return ""
|
||||||
|
}
|
||||||
|
|
||||||
// Failing that, look for enclosing alternate version config.
|
func findAltConfig(dir string) (root, name string) {
|
||||||
if legacyConfigOK {
|
dir = filepath.Clean(dir)
|
||||||
dir = dir1
|
for {
|
||||||
for {
|
for _, name := range altConfigs {
|
||||||
for _, name := range altConfigs {
|
if fi, err := os.Stat(filepath.Join(dir, name)); err == nil && !fi.IsDir() {
|
||||||
if fi, err := os.Stat(filepath.Join(dir, name)); err == nil && !fi.IsDir() {
|
if rel := search.InDir(dir, cfg.BuildContext.GOROOT); rel == "." {
|
||||||
return dir, name
|
// Don't suggest creating a module from $GOROOT/.git/config.
|
||||||
|
return "", ""
|
||||||
}
|
}
|
||||||
|
return dir, name
|
||||||
}
|
}
|
||||||
if dir == limit {
|
|
||||||
break
|
|
||||||
}
|
|
||||||
d := filepath.Dir(dir)
|
|
||||||
if d == dir {
|
|
||||||
break
|
|
||||||
}
|
|
||||||
dir = d
|
|
||||||
}
|
}
|
||||||
|
d := filepath.Dir(dir)
|
||||||
|
if d == dir {
|
||||||
|
break
|
||||||
|
}
|
||||||
|
dir = d
|
||||||
}
|
}
|
||||||
|
|
||||||
return "", ""
|
return "", ""
|
||||||
}
|
}
|
||||||
|
|
||||||
// Exported only for testing.
|
func findModulePath(dir string) (string, error) {
|
||||||
func FindModulePath(dir string) (string, error) {
|
|
||||||
if CmdModModule != "" {
|
if CmdModModule != "" {
|
||||||
// Running go mod init x/y/z; return x/y/z.
|
// Running go mod init x/y/z; return x/y/z.
|
||||||
return CmdModModule, nil
|
return CmdModModule, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// TODO(bcmills): once we have located a plausible module path, we should
|
||||||
|
// query version control (if available) to verify that it matches the major
|
||||||
|
// version of the most recent tag.
|
||||||
|
// See https://golang.org/issue/29433 and https://golang.org/issue/27009.
|
||||||
|
|
||||||
// Cast about for import comments,
|
// Cast about for import comments,
|
||||||
// first in top-level directory, then in subdirectories.
|
// first in top-level directory, then in subdirectories.
|
||||||
list, _ := ioutil.ReadDir(dir)
|
list, _ := ioutil.ReadDir(dir)
|
||||||
|
|
|
||||||
|
|
@ -1,42 +0,0 @@
|
||||||
// Copyright 2018 The Go Authors. All rights reserved.
|
|
||||||
// Use of this source code is governed by a BSD-style
|
|
||||||
// license that can be found in the LICENSE file.
|
|
||||||
|
|
||||||
package modload
|
|
||||||
|
|
||||||
import (
|
|
||||||
"io/ioutil"
|
|
||||||
"os"
|
|
||||||
"path/filepath"
|
|
||||||
"testing"
|
|
||||||
)
|
|
||||||
|
|
||||||
func TestFindModuleRootIgnoreDir(t *testing.T) {
|
|
||||||
// In Plan 9, directories are automatically created in /n.
|
|
||||||
// For example, /n/go.mod always exist, but it's a directory.
|
|
||||||
// Test that we ignore directories when trying to find go.mod and other config files.
|
|
||||||
|
|
||||||
dir, err := ioutil.TempDir("", "gotest")
|
|
||||||
if err != nil {
|
|
||||||
t.Fatalf("failed to create temporary directory: %v", err)
|
|
||||||
}
|
|
||||||
defer os.RemoveAll(dir)
|
|
||||||
if err := os.Mkdir(filepath.Join(dir, "go.mod"), os.ModeDir|0755); err != nil {
|
|
||||||
t.Fatalf("Mkdir failed: %v", err)
|
|
||||||
}
|
|
||||||
for _, name := range altConfigs {
|
|
||||||
if err := os.MkdirAll(filepath.Join(dir, name), os.ModeDir|0755); err != nil {
|
|
||||||
t.Fatalf("MkdirAll failed: %v", err)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
p := filepath.Join(dir, "example")
|
|
||||||
if err := os.Mkdir(p, os.ModeDir|0755); err != nil {
|
|
||||||
t.Fatalf("Mkdir failed: %v", err)
|
|
||||||
}
|
|
||||||
if root, _ := FindModuleRoot(p, "", false); root != "" {
|
|
||||||
t.Errorf("FindModuleRoot(%q, \"\", false): %q, want empty string", p, root)
|
|
||||||
}
|
|
||||||
if root, _ := FindModuleRoot(p, "", true); root != "" {
|
|
||||||
t.Errorf("FindModuleRoot(%q, \"\", true): %q, want empty string", p, root)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
@ -111,7 +111,7 @@ func ImportPaths(patterns []string) []*search.Match {
|
||||||
} else {
|
} else {
|
||||||
pkg = Target.Path + suffix
|
pkg = Target.Path + suffix
|
||||||
}
|
}
|
||||||
} else if sub := search.InDir(dir, cfg.GOROOTsrc); sub != "" && !strings.Contains(sub, "@") {
|
} else if sub := search.InDir(dir, cfg.GOROOTsrc); sub != "" && sub != "." && !strings.Contains(sub, "@") {
|
||||||
pkg = filepath.ToSlash(sub)
|
pkg = filepath.ToSlash(sub)
|
||||||
} else if path := pathInModuleCache(dir); path != "" {
|
} else if path := pathInModuleCache(dir); path != "" {
|
||||||
pkg = path
|
pkg = path
|
||||||
|
|
|
||||||
|
|
@ -1,9 +1,31 @@
|
||||||
env GO111MODULE=on
|
env GO111MODULE=on
|
||||||
|
|
||||||
|
# We should not create a go.mod file unless the user ran 'go mod init' explicitly.
|
||||||
|
# However, we should suggest 'go mod init' if we can find an alternate config file.
|
||||||
cd $WORK/test/x
|
cd $WORK/test/x
|
||||||
|
! go list .
|
||||||
|
stderr 'found Gopkg.lock in .*[/\\]test'
|
||||||
|
stderr '\s*cd \.\. && go mod init'
|
||||||
|
|
||||||
|
# The command we suggested should succeed.
|
||||||
|
cd ..
|
||||||
|
go mod init
|
||||||
go list -m all
|
go list -m all
|
||||||
stdout '^m$'
|
stdout '^m$'
|
||||||
|
|
||||||
|
# In Plan 9, directories are automatically created in /n.
|
||||||
|
# For example, /n/Gopkg.lock always exists, but it's a directory.
|
||||||
|
# Test that we ignore directories when trying to find alternate config files.
|
||||||
|
cd $WORK/gopkgdir/x
|
||||||
|
! go list .
|
||||||
|
stderr 'cannot find main module'
|
||||||
|
! stderr 'Gopkg.lock'
|
||||||
|
! stderr 'go mod init'
|
||||||
|
|
||||||
-- $WORK/test/Gopkg.lock --
|
-- $WORK/test/Gopkg.lock --
|
||||||
-- $WORK/test/x/x.go --
|
-- $WORK/test/x/x.go --
|
||||||
package x // import "m/x"
|
package x // import "m/x"
|
||||||
|
-- $WORK/gopkgdir/Gopkg.lock/README.txt --
|
||||||
|
../Gopkg.lock is a directory, not a file.
|
||||||
|
-- $WORK/gopkgdir/x/x.go --
|
||||||
|
package x // import "m/x"
|
||||||
|
|
|
||||||
|
|
@ -1,10 +1,23 @@
|
||||||
env GO111MODULE=on
|
env GO111MODULE=on
|
||||||
|
|
||||||
# detect root of module tree as root of enclosing git repo
|
# We should not create a go.mod file unless the user ran 'go mod init' explicitly.
|
||||||
|
# However, we should suggest 'go mod init' if we can find an alternate config file.
|
||||||
cd $WORK/test/x
|
cd $WORK/test/x
|
||||||
|
! go list .
|
||||||
|
stderr 'found .git/config in .*[/\\]test'
|
||||||
|
stderr '\s*cd \.\. && go mod init'
|
||||||
|
|
||||||
|
# The command we suggested should succeed.
|
||||||
|
cd ..
|
||||||
|
go mod init
|
||||||
go list -m all
|
go list -m all
|
||||||
stdout '^m$'
|
stdout '^m$'
|
||||||
|
|
||||||
|
# We should not suggest creating a go.mod file in $GOROOT, even though there may be a .git/config there.
|
||||||
|
cd $GOROOT
|
||||||
|
! go list .
|
||||||
|
! stderr 'go mod init'
|
||||||
|
|
||||||
-- $WORK/test/.git/config --
|
-- $WORK/test/.git/config --
|
||||||
-- $WORK/test/x/x.go --
|
-- $WORK/test/x/x.go --
|
||||||
package x // import "m/x"
|
package x // import "m/x"
|
||||||
|
|
|
||||||
|
|
@ -1,6 +1,15 @@
|
||||||
env GO111MODULE=on
|
env GO111MODULE=on
|
||||||
|
|
||||||
|
# We should not create a go.mod file unless the user ran 'go mod init' explicitly.
|
||||||
|
# However, we should suggest 'go mod init' if we can find an alternate config file.
|
||||||
cd $WORK/test/x
|
cd $WORK/test/x
|
||||||
|
! go list .
|
||||||
|
stderr 'found glide.lock in .*[/\\]test'
|
||||||
|
stderr '\s*cd \.\. && go mod init'
|
||||||
|
|
||||||
|
# The command we suggested should succeed.
|
||||||
|
cd ..
|
||||||
|
go mod init
|
||||||
go list -m all
|
go list -m all
|
||||||
stdout '^m$'
|
stdout '^m$'
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -1,6 +1,15 @@
|
||||||
env GO111MODULE=on
|
env GO111MODULE=on
|
||||||
|
|
||||||
|
# We should not create a go.mod file unless the user ran 'go mod init' explicitly.
|
||||||
|
# However, we should suggest 'go mod init' if we can find an alternate config file.
|
||||||
cd $WORK/test/x
|
cd $WORK/test/x
|
||||||
|
! go list .
|
||||||
|
stderr 'found GLOCKFILE in .*[/\\]test'
|
||||||
|
stderr '\s*cd \.\. && go mod init'
|
||||||
|
|
||||||
|
# The command we suggested should succeed.
|
||||||
|
cd ..
|
||||||
|
go mod init
|
||||||
go list -m all
|
go list -m all
|
||||||
stdout '^m$'
|
stdout '^m$'
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -1,6 +1,15 @@
|
||||||
env GO111MODULE=on
|
env GO111MODULE=on
|
||||||
|
|
||||||
|
# We should not create a go.mod file unless the user ran 'go mod init' explicitly.
|
||||||
|
# However, we should suggest 'go mod init' if we can find an alternate config file.
|
||||||
cd $WORK/test/x
|
cd $WORK/test/x
|
||||||
|
! go list .
|
||||||
|
stderr 'found Godeps/Godeps.json in .*[/\\]test'
|
||||||
|
stderr '\s*cd \.\. && go mod init'
|
||||||
|
|
||||||
|
# The command we suggested should succeed.
|
||||||
|
cd ..
|
||||||
|
go mod init
|
||||||
go list -m all
|
go list -m all
|
||||||
stdout '^m$'
|
stdout '^m$'
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -1,6 +1,15 @@
|
||||||
env GO111MODULE=on
|
env GO111MODULE=on
|
||||||
|
|
||||||
|
# We should not create a go.mod file unless the user ran 'go mod init' explicitly.
|
||||||
|
# However, we should suggest 'go mod init' if we can find an alternate config file.
|
||||||
cd $WORK/test/x
|
cd $WORK/test/x
|
||||||
|
! go list .
|
||||||
|
stderr 'found dependencies.tsv in .*[/\\]test'
|
||||||
|
stderr '\s*cd \.\. && go mod init'
|
||||||
|
|
||||||
|
# The command we suggested should succeed.
|
||||||
|
cd ..
|
||||||
|
go mod init
|
||||||
go list -m all
|
go list -m all
|
||||||
stdout '^m$'
|
stdout '^m$'
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -1,6 +1,15 @@
|
||||||
env GO111MODULE=on
|
env GO111MODULE=on
|
||||||
|
|
||||||
|
# We should not create a go.mod file unless the user ran 'go mod init' explicitly.
|
||||||
|
# However, we should suggest 'go mod init' if we can find an alternate config file.
|
||||||
cd $WORK/test/x
|
cd $WORK/test/x
|
||||||
|
! go list .
|
||||||
|
stderr 'found vendor.conf in .*[/\\]test'
|
||||||
|
stderr '\s*cd \.\. && go mod init'
|
||||||
|
|
||||||
|
# The command we suggested should succeed.
|
||||||
|
cd ..
|
||||||
|
go mod init
|
||||||
go list -m all
|
go list -m all
|
||||||
stdout '^m$'
|
stdout '^m$'
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -1,6 +1,15 @@
|
||||||
env GO111MODULE=on
|
env GO111MODULE=on
|
||||||
|
|
||||||
|
# We should not create a go.mod file unless the user ran 'go mod init' explicitly.
|
||||||
|
# However, we should suggest 'go mod init' if we can find an alternate config file.
|
||||||
cd $WORK/test/x
|
cd $WORK/test/x
|
||||||
|
! go list .
|
||||||
|
stderr 'found vendor/vendor.json in .*[/\\]test'
|
||||||
|
stderr '\s*cd \.\. && go mod init'
|
||||||
|
|
||||||
|
# The command we suggested should succeed.
|
||||||
|
cd ..
|
||||||
|
go mod init
|
||||||
go list -m all
|
go list -m all
|
||||||
stdout '^m$'
|
stdout '^m$'
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -1,6 +1,15 @@
|
||||||
env GO111MODULE=on
|
env GO111MODULE=on
|
||||||
|
|
||||||
|
# We should not create a go.mod file unless the user ran 'go mod init' explicitly.
|
||||||
|
# However, we should suggest 'go mod init' if we can find an alternate config file.
|
||||||
cd $WORK/test/x
|
cd $WORK/test/x
|
||||||
|
! go list .
|
||||||
|
stderr 'found vendor/manifest in .*[/\\]test'
|
||||||
|
stderr '\s*cd \.\. && go mod init'
|
||||||
|
|
||||||
|
# The command we suggested should succeed.
|
||||||
|
cd ..
|
||||||
|
go mod init
|
||||||
go list -m all
|
go list -m all
|
||||||
stdout '^m$'
|
stdout '^m$'
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -1,6 +1,15 @@
|
||||||
env GO111MODULE=on
|
env GO111MODULE=on
|
||||||
|
|
||||||
|
# We should not create a go.mod file unless the user ran 'go mod init' explicitly.
|
||||||
|
# However, we should suggest 'go mod init' if we can find an alternate config file.
|
||||||
cd $WORK/test/x
|
cd $WORK/test/x
|
||||||
|
! go list .
|
||||||
|
stderr 'found vendor.yml in .*[/\\]test'
|
||||||
|
stderr '\s*cd \.\. && go mod init'
|
||||||
|
|
||||||
|
# The command we suggested should succeed.
|
||||||
|
cd ..
|
||||||
|
go mod init
|
||||||
go list -m all
|
go list -m all
|
||||||
stdout '^m$'
|
stdout '^m$'
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -43,6 +43,13 @@ go mod init
|
||||||
stderr 'empty'
|
stderr 'empty'
|
||||||
rm go.mod
|
rm go.mod
|
||||||
|
|
||||||
|
# In Plan 9, directories are automatically created in /n.
|
||||||
|
# For example, /n/go.mod always exist, but it's a directory.
|
||||||
|
# Test that we ignore directories when trying to find go.mod.
|
||||||
|
cd $WORK/gomoddir
|
||||||
|
! go list .
|
||||||
|
stderr 'cannot find main module'
|
||||||
|
|
||||||
[!symlink] stop
|
[!symlink] stop
|
||||||
|
|
||||||
# gplink1/src/empty where gopathlink -> GOPATH
|
# gplink1/src/empty where gopathlink -> GOPATH
|
||||||
|
|
@ -89,3 +96,8 @@ package y
|
||||||
package z
|
package z
|
||||||
-- $GOPATH/src/example.com/x/y/z/Godeps/Godeps.json --
|
-- $GOPATH/src/example.com/x/y/z/Godeps/Godeps.json --
|
||||||
{"ImportPath": "unexpected.com/z"}
|
{"ImportPath": "unexpected.com/z"}
|
||||||
|
|
||||||
|
-- $WORK/gomoddir/go.mod/README.txt --
|
||||||
|
../go.mod is a directory, not a file.
|
||||||
|
-- $WORK/gomoddir/p.go --
|
||||||
|
package p
|
||||||
|
|
|
||||||
Loading…
Reference in New Issue