aboutsummaryrefslogtreecommitdiff
path: root/src/cmd/go/internal/modload/init.go
diff options
context:
space:
mode:
authorBryan C. Mills <bcmills@google.com>2021-03-15 12:40:34 -0400
committerBryan C. Mills <bcmills@google.com>2021-03-17 21:24:05 +0000
commit7e00049b5545cac8705d6df1e337c5ddc70e65e4 (patch)
treef0ae39ba49ac7c649d14412d1949dd9fdf516de8 /src/cmd/go/internal/modload/init.go
parent4313c2886160613ca62742d0f46665cf8954213c (diff)
downloadgo-7e00049b5545cac8705d6df1e337c5ddc70e65e4.tar.gz
go-7e00049b5545cac8705d6df1e337c5ddc70e65e4.zip
cmd/go: only add a 'go' directive to the main module when the go.mod file will be written
Then, write the 'go.mod' file with that version before further processing. That way, if the command errors out due to a change in behavior, the reason for the change in behavior will be visible in the file diffs. If the 'go.mod' file cannot be written (due to -mod=readonly or -mod=vendor), assume Go 1.11 instead of the current Go release. (cmd/go has added 'go' directives automatically, including in 'go mod init', since Go 1.12.) For #44976 Change-Id: If9d4af557366f134f40ce4c5638688ba3bab8380 Reviewed-on: https://go-review.googlesource.com/c/go/+/302051 Trust: Bryan C. Mills <bcmills@google.com> Run-TryBot: Bryan C. Mills <bcmills@google.com> TryBot-Result: Go Bot <gobot@golang.org> Reviewed-by: Jay Conrod <jayconrod@google.com> Reviewed-by: Michael Matloob <matloob@golang.org>
Diffstat (limited to 'src/cmd/go/internal/modload/init.go')
-rw-r--r--src/cmd/go/internal/modload/init.go107
1 files changed, 72 insertions, 35 deletions
diff --git a/src/cmd/go/internal/modload/init.go b/src/cmd/go/internal/modload/init.go
index 8ec1c8681a..2466a3bdfd 100644
--- a/src/cmd/go/internal/modload/init.go
+++ b/src/cmd/go/internal/modload/init.go
@@ -35,11 +35,30 @@ import (
"golang.org/x/mod/semver"
)
+// Variables set by other packages.
+//
+// TODO(#40775): See if these can be plumbed as explicit parameters.
+var (
+ // RootMode determines whether a module root is needed.
+ RootMode Root
+
+ // ForceUseModules may be set to force modules to be enabled when
+ // GO111MODULE=auto or to report an error when GO111MODULE=off.
+ ForceUseModules bool
+
+ allowMissingModuleImports bool
+)
+
+// Variables set in Init.
var (
initialized bool
+ modRoot string
+ gopath string
+)
- modRoot string
- Target module.Version
+// Variables set in initTarget (during {Load,Create}ModFile).
+var (
+ Target module.Version
// targetPrefix is the path prefix for packages in Target, without a trailing
// slash. For most modules, targetPrefix is just Target.Path, but the
@@ -49,17 +68,6 @@ var (
// targetInGorootSrc caches whether modRoot is within GOROOT/src.
// The "std" module is special within GOROOT/src, but not otherwise.
targetInGorootSrc bool
-
- gopath string
-
- // RootMode determines whether a module root is needed.
- RootMode Root
-
- // ForceUseModules may be set to force modules to be enabled when
- // GO111MODULE=auto or to report an error when GO111MODULE=off.
- ForceUseModules bool
-
- allowMissingModuleImports bool
)
type Root int
@@ -362,6 +370,7 @@ func LoadModFile(ctx context.Context) {
Target = module.Version{Path: "command-line-arguments"}
targetPrefix = "command-line-arguments"
buildList = []module.Version{Target}
+ rawGoVersion.Store(Target, latestGoVersion())
return
}
@@ -377,24 +386,29 @@ func LoadModFile(ctx context.Context) {
// Errors returned by modfile.Parse begin with file:line.
base.Fatalf("go: errors parsing go.mod:\n%s\n", err)
}
- modFile = f
- index = indexModFile(data, f, fixed)
-
if f.Module == nil {
// No module declaration. Must add module path.
base.Fatalf("go: no module declaration in go.mod. To specify the module path:\n\tgo mod edit -module=example.com/mod")
}
+ modFile = f
+ initTarget(f.Module.Mod)
+ index = indexModFile(data, f, fixed)
+
if err := checkModulePathLax(f.Module.Mod.Path); err != nil {
base.Fatalf("go: %v", err)
}
setDefaultBuildMod() // possibly enable automatic vendoring
- modFileToBuildList()
+ buildList = modFileToBuildList(modFile)
if cfg.BuildMod == "vendor" {
readVendorList()
checkVendorConsistency()
}
+ if index.goVersionV == "" && cfg.BuildMod == "mod" {
+ addGoStmt()
+ WriteGoMod()
+ }
}
// CreateModFile initializes a new module by creating a go.mod file.
@@ -427,6 +441,7 @@ func CreateModFile(ctx context.Context, modPath string) {
fmt.Fprintf(os.Stderr, "go: creating new go.mod: module %s\n", modPath)
modFile = new(modfile.File)
modFile.AddModuleStmt(modPath)
+ initTarget(modFile.Module.Mod)
addGoStmt() // Add the go directive before converted module requirements.
convertedFrom, err := convertLegacyConfig(modPath)
@@ -437,7 +452,7 @@ func CreateModFile(ctx context.Context, modPath string) {
base.Fatalf("go: %v", err)
}
- modFileToBuildList()
+ buildList = modFileToBuildList(modFile)
WriteGoMod()
// Suggest running 'go mod tidy' unless the project is empty. Even if we
@@ -563,19 +578,31 @@ func AllowMissingModuleImports() {
allowMissingModuleImports = true
}
-// modFileToBuildList initializes buildList from the modFile.
-func modFileToBuildList() {
- Target = modFile.Module.Mod
- targetPrefix = Target.Path
+// initTarget sets Target and associated variables according to modFile,
+func initTarget(m module.Version) {
+ Target = m
+ targetPrefix = m.Path
+
if rel := search.InDir(base.Cwd, cfg.GOROOTsrc); rel != "" {
targetInGorootSrc = true
- if Target.Path == "std" {
+ if m.Path == "std" {
+ // The "std" module in GOROOT/src is the Go standard library. Unlike other
+ // modules, the packages in the "std" module have no import-path prefix.
+ //
+ // Modules named "std" outside of GOROOT/src do not receive this special
+ // treatment, so it is possible to run 'go test .' in other GOROOTs to
+ // test individual packages using a combination of the modified package
+ // and the ordinary standard library.
+ // (See https://golang.org/issue/30756.)
targetPrefix = ""
}
}
+}
+// modFileToBuildList returns the list of non-excluded requirements from f.
+func modFileToBuildList(f *modfile.File) []module.Version {
list := []module.Version{Target}
- for _, r := range modFile.Require {
+ for _, r := range f.Require {
if index != nil && index.exclude[r.Mod] {
if cfg.BuildMod == "mod" {
fmt.Fprintf(os.Stderr, "go: dropping requirement on excluded version %s %s\n", r.Mod.Path, r.Mod.Version)
@@ -586,7 +613,7 @@ func modFileToBuildList() {
list = append(list, r.Mod)
}
}
- buildList = list
+ return list
}
// setDefaultBuildMod sets a default value for cfg.BuildMod if the -mod flag
@@ -650,20 +677,29 @@ func convertLegacyConfig(modPath string) (from string, err error) {
return "", nil
}
-// addGoStmt adds a go directive to the go.mod file if it does not already include one.
-// The 'go' version added, if any, is the latest version supported by this toolchain.
+// addGoStmt adds a go directive to the go.mod file if it does not already
+// include one. The 'go' version added, if any, is the latest version supported
+// by this toolchain.
func addGoStmt() {
if modFile.Go != nil && modFile.Go.Version != "" {
return
}
+ v := latestGoVersion()
+ if err := modFile.AddGoStmt(v); err != nil {
+ base.Fatalf("go: internal error: %v", err)
+ }
+ rawGoVersion.Store(Target, v)
+}
+
+// latestGoVersion returns the latest version of the Go language supported by
+// this toolchain.
+func latestGoVersion() string {
tags := build.Default.ReleaseTags
version := tags[len(tags)-1]
if !strings.HasPrefix(version, "go") || !modfile.GoVersionRE.MatchString(version[2:]) {
base.Fatalf("go: unrecognized default version %q", version)
}
- if err := modFile.AddGoStmt(version[2:]); err != nil {
- base.Fatalf("go: internal error: %v", err)
- }
+ return version[2:]
}
var altConfigs = []string{
@@ -880,10 +916,6 @@ func WriteGoMod() {
return
}
- if cfg.BuildMod != "readonly" {
- addGoStmt()
- }
-
if loaded != nil {
reqs := MinReqs()
min, err := reqs.Required(Target)
@@ -1010,7 +1042,12 @@ func keepSums(keepBuildListZips bool) map[module.Version]bool {
}
buildList, err := mvs.BuildList(Target, reqs)
if err != nil {
- panic(fmt.Sprintf("unexpected error reloading build list: %v", err))
+ // This call to mvs.BuildList should not fail if we have already read the
+ // complete build list. However, the initial “build list” initialized by
+ // modFileToBuildList is not complete: it contains only the explicit
+ // dependencies of the main module. So this call can fair if this is the
+ // first time we have actually loaded the real build list.
+ base.Fatalf("go: %v", err)
}
actualMods := make(map[string]module.Version)