"cmd/go/internal/lockedfile"
"cmd/go/internal/modfetch"
"cmd/go/internal/search"
+ igover "internal/gover"
"golang.org/x/mod/modfile"
"golang.org/x/mod/module"
wf.Cleanup()
out := modfile.Format(wf.Syntax)
- return os.WriteFile(path, out, 0666)
+ return os.WriteFile(path, out, 0o666)
}
// UpdateWorkGoVersion updates the go line in wf to be at least goVers,
modFile := new(modfile.File)
modFile.AddModuleStmt(modPath)
loaderstate.MainModules = makeMainModules(loaderstate, []module.Version{modFile.Module.Mod}, []string{modRoot}, []*modfile.File{modFile}, []*modFileIndex{nil}, nil)
- addGoStmt(modFile, modFile.Module.Mod, gover.Local()) // Add the go directive before converted module requirements.
+ addGoStmt(modFile, modFile.Module.Mod, DefaultModInitGoVersion()) // Add the go directive before converted module requirements.
rs := requirementsFromModFiles(loaderstate, ctx, nil, []*modfile.File{modFile}, nil)
rs, err := updateRoots(loaderstate, ctx, rs.direct, rs, nil, nil, false)
return "", fmt.Errorf(msg, dir, reason)
}
-var (
- importCommentRE = lazyregexp.New(`(?m)^package[ \t]+[^ \t\r\n/]+[ \t]+//[ \t]+import[ \t]+(\"[^"]+\")[ \t]*\r?\n`)
-)
+var importCommentRE = lazyregexp.New(`(?m)^package[ \t]+[^ \t\r\n/]+[ \t]+//[ \t]+import[ \t]+(\"[^"]+\")[ \t]*\r?\n`)
func findImportComment(file string) string {
data, err := os.ReadFile(file)
}
return fmt.Errorf("unknown %s %q", verb, k)
}
+
+// DefaultModInitGoVersion returns the appropriate go version to include in a
+// newly initialized module or work file.
+//
+// If the current toolchain version is a stable version of Go 1.N.M, default to
+// go 1.(N-1).0
+//
+// If the current toolchain version is a pre-release version of Go 1.N (Release
+// Candidate M) or a development version of Go 1.N, default to go 1.(N-2).0
+func DefaultModInitGoVersion() string {
+ v := gover.Local()
+ if isPrereleaseOrDevelVersion(v) {
+ v = gover.Prev(gover.Prev(v))
+ } else {
+ v = gover.Prev(v)
+ }
+ if strings.Count(v, ".") < 2 {
+ v += ".0"
+ }
+ return v
+}
+
+func isPrereleaseOrDevelVersion(s string) bool {
+ v := igover.Parse(s)
+ return v.Kind != "" || v.Patch == ""
+}
"cmd/go/internal/base"
"cmd/go/internal/fsys"
- "cmd/go/internal/gover"
"cmd/go/internal/modload"
"golang.org/x/mod/modfile"
base.Fatalf("go: %s already exists", gowork)
}
- goV := gover.Local() // Use current Go version by default
wf := new(modfile.WorkFile)
wf.Syntax = new(modfile.FileSyntax)
- wf.AddGoStmt(goV)
+ wf.AddGoStmt(modload.DefaultModInitGoVersion())
workUse(ctx, moduleLoaderState, gowork, wf, args)
modload.WriteWorkFile(gowork, wf)
}
env GO111MODULE=on
+# Set go version so that we can test produced mod files for equality.
+env TESTGO_VERSION=go1.26.0
+
# Test that go mod edits and related mod flags work.
# Also test that they can use a dummy name that isn't resolvable. golang.org/issue/24100
go mod init x.x/y/z
stderr 'creating new go.mod: module x.x/y/z'
-cmpenv go.mod $WORK/go.mod.init
+cmp go.mod $WORK/go.mod.init
! go mod init
-cmpenv go.mod $WORK/go.mod.init
+cmp go.mod $WORK/go.mod.init
# go mod edits
go mod edit -droprequire=x.1 -require=x.1@v1.0.0 -require=x.2@v1.1.0 -droprequire=x.2 -exclude='x.1 @ v1.2.0' -exclude=x.1@v1.2.1 -exclude=x.1@v2.0.0+incompatible -replace=x.1@v1.3.0=y.1@v1.4.0 -replace='x.1@v1.4.0 = ../z' -retract=v1.6.0 -retract=[v1.1.0,v1.2.0] -retract=[v1.3.0,v1.4.0] -retract=v1.0.0
-cmpenv go.mod $WORK/go.mod.edit1
+cmp go.mod $WORK/go.mod.edit1
go mod edit -droprequire=x.1 -dropexclude=x.1@v1.2.1 -dropexclude=x.1@v2.0.0+incompatible -dropreplace=x.1@v1.3.0 -require=x.3@v1.99.0 -dropretract=v1.0.0 -dropretract=[v1.1.0,v1.2.0]
-cmpenv go.mod $WORK/go.mod.edit2
+cmp go.mod $WORK/go.mod.edit2
# -exclude and -retract reject invalid versions.
! go mod edit -exclude=example.com/m@bad
! go mod edit -exclude=gopkg.in/example.v1@v2.0.0
stderr '^go: -exclude=gopkg\.in/example\.v1@v2\.0\.0: version "v2\.0\.0" invalid: should be v1, not v2$'
-cmpenv go.mod $WORK/go.mod.edit2
+cmp go.mod $WORK/go.mod.edit2
# go mod edit -json
go mod edit -json
-cmpenv stdout $WORK/go.mod.json
+cmp stdout $WORK/go.mod.json
# go mod edit -json (retractions with rationales)
go mod edit -json $WORK/go.mod.retractrationale
# go mod edit -replace
go mod edit -replace=x.1@v1.3.0=y.1/v2@v2.3.5 -replace=x.1@v1.4.0=y.1/v2@v2.3.5
-cmpenv go.mod $WORK/go.mod.edit3
+cmp go.mod $WORK/go.mod.edit3
go mod edit -replace=x.1=y.1/v2@v2.3.6
-cmpenv go.mod $WORK/go.mod.edit4
+cmp go.mod $WORK/go.mod.edit4
go mod edit -dropreplace=x.1
-cmpenv go.mod $WORK/go.mod.edit5
+cmp go.mod $WORK/go.mod.edit5
go mod edit -replace=x.1=../y.1/@v2
-cmpenv go.mod $WORK/go.mod.edit6
+cmp go.mod $WORK/go.mod.edit6
! go mod edit -replace=x.1=y.1/@v2
stderr '^go: -replace=x.1=y.1/@v2: invalid new path: malformed import path "y.1/": trailing slash$'
# go mod edit -fmt
cp $WORK/go.mod.badfmt go.mod
go mod edit -fmt -print # -print should avoid writing file
-cmpenv stdout $WORK/go.mod.goodfmt
+cmp stdout $WORK/go.mod.goodfmt
cmp go.mod $WORK/go.mod.badfmt
go mod edit -fmt # without -print, should write file (and nothing to stdout)
! stdout .
-cmpenv go.mod $WORK/go.mod.goodfmt
+cmp go.mod $WORK/go.mod.goodfmt
# go mod edit -module
cd $WORK/m
go mod init a.a/b/c
go mod edit -module x.x/y/z
-cmpenv go.mod go.mod.edit
+cmp go.mod go.mod.edit
# golang.org/issue/30513: don't require go-gettable module paths.
cd $WORK/local
go mod init foo
go mod edit -module local-only -require=other-local@v1.0.0 -replace other-local@v1.0.0=./other
-cmpenv go.mod go.mod.edit
+cmp go.mod go.mod.edit
# go mod edit -godebug
cd $WORK/g
cp go.mod.start go.mod
go mod edit -godebug key=value
-cmpenv go.mod go.mod.edit
+cmp go.mod go.mod.edit
go mod edit -dropgodebug key2
-cmpenv go.mod go.mod.edit
+cmp go.mod go.mod.edit
go mod edit -dropgodebug key
-cmpenv go.mod go.mod.start
+cmp go.mod go.mod.start
# go mod edit -tool
cd $WORK/h
cp go.mod.start go.mod
go mod edit -tool example.com/tool
-cmpenv go.mod go.mod.edit
+cmp go.mod go.mod.edit
go mod edit -droptool example.com/tool2
-cmpenv go.mod go.mod.edit
+cmp go.mod go.mod.edit
go mod edit -droptool example.com/tool
-cmpenv go.mod go.mod.start
+cmp go.mod go.mod.start
# go mod edit -ignore
cd $WORK/i
cp go.mod.start go.mod
go mod edit -ignore example.com/ignore
-cmpenv go.mod go.mod.edit
+cmp go.mod go.mod.edit
go mod edit -dropignore example.com/ignore2
-cmpenv go.mod go.mod.edit
+cmp go.mod go.mod.edit
go mod edit -dropignore example.com/ignore
-cmpenv go.mod go.mod.start
+cmp go.mod go.mod.start
-- x.go --
package x
-- $WORK/go.mod.init --
module x.x/y/z
-go $goversion
+go 1.25.0
-- $WORK/go.mod.edit1 --
module x.x/y/z
-go $goversion
+go 1.25.0
require x.1 v1.0.0
-- $WORK/go.mod.edit2 --
module x.x/y/z
-go $goversion
+go 1.25.0
exclude x.1 v1.2.0
"Module": {
"Path": "x.x/y/z"
},
- "Go": "$goversion",
+ "Go": "1.25.0",
"Require": [
{
"Path": "x.3",
-- $WORK/go.mod.edit3 --
module x.x/y/z
-go $goversion
+go 1.25.0
exclude x.1 v1.2.0
-- $WORK/go.mod.edit4 --
module x.x/y/z
-go $goversion
+go 1.25.0
exclude x.1 v1.2.0
-- $WORK/go.mod.edit5 --
module x.x/y/z
-go $goversion
+go 1.25.0
exclude x.1 v1.2.0
-- $WORK/go.mod.edit6 --
module x.x/y/z
-go $goversion
+go 1.25.0
exclude x.1 v1.2.0
-- $WORK/local/go.mod.edit --
module local-only
-go $goversion
+go 1.25.0
require other-local v1.0.0
-- $WORK/m/go.mod.edit --
module x.x/y/z
-go $goversion
+go 1.25.0
-- $WORK/go.mod.retractrationale --
module x.x/y/z
go 1.24
-ignore example.com/ignore
\ No newline at end of file
+ignore example.com/ignore
--- /dev/null
+env TESTGO_VERSION=go1.28-devel
+go mod init example.com
+cmp go.mod go.mod.want-1.26.0
+rm go.mod
+env TESTGO_VERSION=go1.26.0
+go mod init example.com
+cmp go.mod go.mod.want-1.25.0
+rm go.mod
+env TESTGO_VERSION=go1.22.2
+go mod init example.com
+cmp go.mod go.mod.want-1.21.0
+rm go.mod
+env TESTGO_VERSION=go1.25.0-xyzzy
+go mod init example.com
+cmp go.mod go.mod.want-1.24.0
+rm go.mod
+env TESTGO_VERSION=go1.23rc3
+go mod init example.com
+cmp go.mod go.mod.want-1.21.0
+rm go.mod
+env TESTGO_VERSION=go1.18beta2
+go mod init example.com
+cmp go.mod go.mod.want-1.16.0
+-- go.mod.want-1.26.0 --
+module example.com
+
+go 1.26.0
+-- go.mod.want-1.25.0 --
+module example.com
+
+go 1.25.0
+-- go.mod.want-1.24.0 --
+module example.com
+
+go 1.24.0
+-- go.mod.want-1.22.0 --
+module example.com
+
+go 1.22.0
+-- go.mod.want-1.21.0 --
+module example.com
+
+go 1.21.0
+-- go.mod.want-1.16.0 --
+module example.com
+
+go 1.16.0
[short] skip 'runs go run'
+env TESTGO_VERSION=go1.26.0
! go work init doesnotexist
stderr 'go: directory doesnotexist does not exist'
../src/a
)
-- go.work.want --
-go $goversion
+go 1.25.0
use (
./a
# Test editing go.work files.
+env TESTGO_VERSION=go1.26.0
go work init m
cmpenv go.work go.work.want_initial
go 1.18
-- go.work.want_initial --
-go $goversion
+go 1.25.0
use ./m
-- go.work.want_use_n --
-go $goversion
+go 1.25.0
use (
./m
# 'go work init . .. foo/bar' should produce a go.work file
# with the same paths as 'go work init; go work use -r ..',
# and it should have 'use .' rather than 'use ./.' inside.
-
+env TESTGO_VERSION=go1.23
cd dir
go work init . .. foo/bar
go work use -r ..
cmp go.work go.work.init
-cmpenv go.work $WORK/go.work.want
+cmp go.work $WORK/go.work.want
-- go.mod --
module example
go 1.18
-- dir/go.mod --
module example
-go 1.18
+go 1.21.0
-- dir/foo/bar/go.mod --
module example
-go 1.18
+go 1.21.0
-- $WORK/go.work.want --
-go $goversion
+go 1.21.0
use (
.
# work init writes the current Go version to the go line
go work init
-grep '^go 1.50$' go.work
+grep '^go 1.48.0$' go.work
! grep toolchain go.work
-# work init with older modules should leave go 1.50 in the go.work.
+# work init with older modules should leave go 1.48.0 in the go.work.
rm go.work
go work init ./m1_22_0
-grep '^go 1.50$' go.work
+grep '^go 1.48.0$' go.work
! grep toolchain go.work
# work init with newer modules should bump go,
go work init ./m1_22_0
stderr '^go: m1_22_0'${/}'go.mod requires go >= 1.22.0; switching to go1.22.9$'
cat go.work
-grep '^go 1.22.9$' go.work
+grep '^go 1.22.0$' go.work
! grep toolchain go.work
--- /dev/null
+env TESTGO_VERSION=go1.28-devel
+go work init
+cmp go.work go.work.want-1.26.0
+rm go.work
+env TESTGO_VERSION=go1.26.0
+go work init
+cmp go.work go.work.want-1.25.0
+rm go.work
+env TESTGO_VERSION=go1.22.2
+go work init
+cmp go.work go.work.want-1.21.0
+rm go.work
+env TESTGO_VERSION=go1.25.0-xyzzy
+go work init
+cmp go.work go.work.want-1.24.0
+rm go.work
+env TESTGO_VERSION=go1.24rc3
+go work init
+cmp go.work go.work.want-1.22.0
+rm go.work
+env TESTGO_VERSION=go1.18beta2
+go work init
+cmp go.work go.work.want-1.16.0
+-- go.work.want-1.26.0 --
+go 1.26.0
+-- go.work.want-1.25.0 --
+go 1.25.0
+-- go.work.want-1.24.0 --
+go 1.24.0
+-- go.work.want-1.22.0 --
+go 1.22.0
+-- go.work.want-1.21.0 --
+go 1.21.0
+-- go.work.want-1.16.0 --
+go 1.16.0
go mod edit -C m1_24_rc0 -go=1.24rc0 -toolchain=go1.99.2
go work init ./m1_22_0 ./m1_22_1
-grep '^go 1.50$' go.work
+cat go.work
+grep '^go 1.48.0$' go.work
! grep toolchain go.work
-# work sync with older modules should leave go 1.50 in the go.work.
+# work sync with older modules should leave go 1.48.0 in the go.work.
go work sync
cat go.work
-grep '^go 1.50$' go.work
+grep '^go 1.48.0$' go.work
! grep toolchain go.work
# work sync with newer modules should update go 1.21 -> 1.22.1 and toolchain -> go1.22.9 in go.work
go mod edit -C m1_24_rc0 -go=1.24rc0 -toolchain=go1.99.2
go work init
-grep '^go 1.50$' go.work
+grep '^go 1.48.0$' go.work
! grep toolchain go.work
-# work use with older modules should leave go 1.50 in the go.work.
+# work use with older modules should leave go 1.48.0 in the go.work.
go work use ./m1_22_0
-grep '^go 1.50$' go.work
+grep '^go 1.48.0$' go.work
! grep toolchain go.work
# work use with newer modules should bump go and toolchain,