mirror of https://github.com/golang/go.git
cmd/go: switch to newer toolchain in go get as needed
If we run 'go get go@1.40' or 'go get m@v' where m has a go.mod that says 'go 1.40', we need to write a new go.mod that says 'go 1.40'. But we can't be sure we know how to write a Go 1.40-compatible go.mod. Instead, download the latest point release of Go 1.40 and invoke it to finish the get command. For #57001. Change-Id: I4133fc3c2ecf91226a6c09a3086275ecc517e223 Reviewed-on: https://go-review.googlesource.com/c/go/+/498118 TryBot-Result: Gopher Robot <gobot@golang.org> Reviewed-by: Bryan Mills <bcmills@google.com> Run-TryBot: Russ Cox <rsc@golang.org> Auto-Submit: Russ Cox <rsc@golang.org>
This commit is contained in:
parent
5b603f79fb
commit
301370c81c
|
|
@ -254,6 +254,12 @@ func runEnv(ctx context.Context, cmd *base.Command, args []string) {
|
|||
base.Fatalf("go: %v", cfg.ExperimentErr)
|
||||
}
|
||||
|
||||
for _, arg := range args {
|
||||
if strings.Contains(arg, "=") {
|
||||
base.Fatalf("go: invalid variable name %q (use -w to set variable)", arg)
|
||||
}
|
||||
}
|
||||
|
||||
env := cfg.CmdEnv
|
||||
env = append(env, ExtraEnvVars()...)
|
||||
|
||||
|
|
|
|||
|
|
@ -10,7 +10,9 @@
|
|||
// depending on the module path.
|
||||
package gover
|
||||
|
||||
import "cmp"
|
||||
import (
|
||||
"cmp"
|
||||
)
|
||||
|
||||
// A version is a parsed Go version: major[.minor[.patch]][kind[pre]]
|
||||
// The numbers are the original decimal strings to avoid integer overflows
|
||||
|
|
@ -76,6 +78,11 @@ func Lang(x string) string {
|
|||
return v.major + "." + v.minor
|
||||
}
|
||||
|
||||
// IsPrerelease reports whether v denotes a Go prerelease version.
|
||||
func IsPrerelease(x string) bool {
|
||||
return parse(x).kind != ""
|
||||
}
|
||||
|
||||
// Prev returns the Go major release immediately preceding v,
|
||||
// or v itself if v is the first Go major release (1.0) or not a supported
|
||||
// Go version.
|
||||
|
|
|
|||
|
|
@ -77,6 +77,7 @@ var isLangTests = []testCase1[string, bool]{
|
|||
{"1.21", true},
|
||||
{"1.20", false}, // == 1.20.0
|
||||
{"1.19", false}, // == 1.20.0
|
||||
{"1.3", false}, // == 1.3.0
|
||||
{"1.2", false}, // == 1.2.0
|
||||
{"1", false}, // == 1.0.0
|
||||
}
|
||||
|
|
@ -113,6 +114,7 @@ type testCase3[In1, In2, In3, Out any] struct {
|
|||
}
|
||||
|
||||
func test1[In, Out any](t *testing.T, tests []testCase1[In, Out], name string, f func(In) Out) {
|
||||
t.Helper()
|
||||
for _, tt := range tests {
|
||||
if out := f(tt.in); !reflect.DeepEqual(out, tt.out) {
|
||||
t.Errorf("%s(%v) = %v, want %v", name, tt.in, out, tt.out)
|
||||
|
|
@ -121,6 +123,7 @@ func test1[In, Out any](t *testing.T, tests []testCase1[In, Out], name string, f
|
|||
}
|
||||
|
||||
func test2[In1, In2, Out any](t *testing.T, tests []testCase2[In1, In2, Out], name string, f func(In1, In2) Out) {
|
||||
t.Helper()
|
||||
for _, tt := range tests {
|
||||
if out := f(tt.in1, tt.in2); !reflect.DeepEqual(out, tt.out) {
|
||||
t.Errorf("%s(%+v, %+v) = %+v, want %+v", name, tt.in1, tt.in2, out, tt.out)
|
||||
|
|
@ -129,6 +132,7 @@ func test2[In1, In2, Out any](t *testing.T, tests []testCase2[In1, In2, Out], na
|
|||
}
|
||||
|
||||
func test3[In1, In2, In3, Out any](t *testing.T, tests []testCase3[In1, In2, In3, Out], name string, f func(In1, In2, In3) Out) {
|
||||
t.Helper()
|
||||
for _, tt := range tests {
|
||||
if out := f(tt.in1, tt.in2, tt.in3); !reflect.DeepEqual(out, tt.out) {
|
||||
t.Errorf("%s(%+v, %+v, %+v) = %+v, want %+v", name, tt.in1, tt.in2, tt.in3, out, tt.out)
|
||||
|
|
|
|||
|
|
@ -101,3 +101,12 @@ func ModIsPrefix(path, vers string) bool {
|
|||
}
|
||||
return true
|
||||
}
|
||||
|
||||
// ModIsPrerelease reports whether v is a prerelease version for the module with the given path.
|
||||
// The caller is assumed to have checked that ModIsValid(path, vers) is true.
|
||||
func ModIsPrerelease(path, vers string) bool {
|
||||
if IsToolchain(path) {
|
||||
return IsPrerelease(vers)
|
||||
}
|
||||
return semver.Prerelease(vers) != ""
|
||||
}
|
||||
|
|
|
|||
|
|
@ -78,7 +78,7 @@ func (e *TooNewError) Error() string {
|
|||
explain += "toolchain " + Startup.AutoToolchain
|
||||
}
|
||||
}
|
||||
return fmt.Sprintf("%v requires go %v (running go %v%v)", e.What, e.GoVersion, Local(), explain)
|
||||
return fmt.Sprintf("%v requires go >= %v (running go %v%v)", e.What, e.GoVersion, Local(), explain)
|
||||
}
|
||||
|
||||
var ErrTooNew = errors.New("module too new")
|
||||
|
|
|
|||
|
|
@ -43,6 +43,7 @@ import (
|
|||
"cmd/go/internal/modload"
|
||||
"cmd/go/internal/par"
|
||||
"cmd/go/internal/search"
|
||||
"cmd/go/internal/toolchain"
|
||||
"cmd/go/internal/work"
|
||||
|
||||
"golang.org/x/mod/modfile"
|
||||
|
|
@ -379,6 +380,14 @@ func runGet(ctx context.Context, cmd *base.Command, args []string) {
|
|||
oldReqs := reqsFromGoMod(modload.ModFile())
|
||||
|
||||
if err := modload.WriteGoMod(ctx); err != nil {
|
||||
if tooNew, ok := err.(*gover.TooNewError); ok {
|
||||
// This can happen for 'go get go@newversion'
|
||||
// when all the required modules are old enough
|
||||
// but the command line is not.
|
||||
// TODO(bcmills): Perhaps LoadModGraph should catch this,
|
||||
// in which case the tryVersion here should be removed.
|
||||
tryVersion(ctx, tooNew.GoVersion)
|
||||
}
|
||||
base.Fatalf("go: %v", err)
|
||||
}
|
||||
|
||||
|
|
@ -1211,6 +1220,20 @@ func (r *resolver) resolveQueries(ctx context.Context, queries []*query) (change
|
|||
for {
|
||||
prevResolved := resolved
|
||||
|
||||
// If we found modules that were too new, find the max of the required versions
|
||||
// and then try to switch to a newer toolchain.
|
||||
goVers := ""
|
||||
for _, q := range queries {
|
||||
for _, cs := range q.candidates {
|
||||
if e, ok := cs.err.(*gover.TooNewError); ok && gover.Compare(goVers, e.GoVersion) < 0 {
|
||||
goVers = e.GoVersion
|
||||
}
|
||||
}
|
||||
}
|
||||
if goVers != "" {
|
||||
tryVersion(ctx, goVers)
|
||||
}
|
||||
|
||||
for _, q := range queries {
|
||||
unresolved := q.candidates[:0]
|
||||
|
||||
|
|
@ -1885,3 +1908,22 @@ func isNoSuchPackageVersion(err error) bool {
|
|||
var noPackage *modload.PackageNotInModuleError
|
||||
return isNoSuchModuleVersion(err) || errors.As(err, &noPackage)
|
||||
}
|
||||
|
||||
// tryVersion tries to switch to a Go toolchain appropriate for version,
|
||||
// which was either found in a go.mod file of a dependency or resolved
|
||||
// on the command line from go@v.
|
||||
func tryVersion(ctx context.Context, version string) {
|
||||
if !gover.IsValid(version) {
|
||||
fmt.Fprintf(os.Stderr, "go: misuse of tryVersion: invalid version %q\n", version)
|
||||
return
|
||||
}
|
||||
if (!toolchain.HasAuto() && !toolchain.HasPath()) || gover.Compare(version, gover.Local()) <= 0 {
|
||||
return
|
||||
}
|
||||
tv, err := toolchain.NewerToolchain(ctx, version)
|
||||
if err != nil {
|
||||
base.Errorf("go: %v\n", err)
|
||||
}
|
||||
fmt.Fprintf(os.Stderr, "go: switching to %v\n", tv)
|
||||
toolchain.SwitchTo(tv)
|
||||
}
|
||||
|
|
|
|||
|
|
@ -609,7 +609,10 @@ func EditBuildList(ctx context.Context, add, mustSelect []module.Version) (chang
|
|||
|
||||
// OverrideRoots edits the global requirement roots by replacing the specific module versions.
|
||||
func OverrideRoots(ctx context.Context, replace []module.Version) {
|
||||
rs := requirements
|
||||
requirements = overrideRoots(ctx, requirements, replace)
|
||||
}
|
||||
|
||||
func overrideRoots(ctx context.Context, rs *Requirements, replace []module.Version) *Requirements {
|
||||
drop := make(map[string]bool)
|
||||
for _, m := range replace {
|
||||
drop[m.Path] = true
|
||||
|
|
@ -622,7 +625,7 @@ func OverrideRoots(ctx context.Context, replace []module.Version) {
|
|||
}
|
||||
roots = append(roots, replace...)
|
||||
gover.ModSort(roots)
|
||||
requirements = newRequirements(rs.pruning, roots, rs.direct)
|
||||
return newRequirements(rs.pruning, roots, rs.direct)
|
||||
}
|
||||
|
||||
// A ConstraintError describes inconsistent constraints in EditBuildList
|
||||
|
|
|
|||
|
|
@ -848,7 +848,16 @@ func loadModFile(ctx context.Context, opts *PackageOpts) *Requirements {
|
|||
// TODO(#45551): Do something more principled instead of checking
|
||||
// cfg.CmdName directly here.
|
||||
if cfg.BuildMod == "mod" && cfg.CmdName != "mod graph" && cfg.CmdName != "mod why" {
|
||||
// go line is missing from go.mod; add one there and add to derived requirements.
|
||||
addGoStmt(MainModules.ModFile(mainModule), mainModule, gover.Local())
|
||||
if cfg.CmdName != "mod tidy" {
|
||||
// We want to add the "go" line to the module load in general,
|
||||
// if we do it in "mod tidy", then go mod tidy -go=older for some older version
|
||||
// when we are in a module with no go line will see gover.Local() in the
|
||||
// requirement graph and then report that -go=older is invalid.
|
||||
// go test -run=Script/mod_tidy_version will fail without the tidy exclusion.
|
||||
rs = overrideRoots(ctx, rs, []module.Version{{Path: "go", Version: gover.Local()}})
|
||||
}
|
||||
|
||||
// We need to add a 'go' version to the go.mod file, but we must assume
|
||||
// that its existing contents match something between Go 1.11 and 1.16.
|
||||
|
|
@ -1163,10 +1172,8 @@ func requirementsFromModFiles(ctx context.Context, workFile *modfile.WorkFile, m
|
|||
roots = append(roots, module.Version{Path: "go", Version: workFile.Go.Version})
|
||||
direct["go"] = true
|
||||
}
|
||||
if workFile.Toolchain != nil {
|
||||
roots = append(roots, module.Version{Path: "toolchain", Version: workFile.Toolchain.Name})
|
||||
direct["toolchain"] = true
|
||||
}
|
||||
// Do not add toolchain to roots.
|
||||
// We only want to see it in roots if it is on the command line.
|
||||
} else {
|
||||
pruning = pruningForGoVersion(MainModules.GoVersion())
|
||||
if len(modFiles) != 1 {
|
||||
|
|
@ -1197,10 +1204,8 @@ func requirementsFromModFiles(ctx context.Context, workFile *modfile.WorkFile, m
|
|||
roots = append(roots, module.Version{Path: "go", Version: modFile.Go.Version})
|
||||
direct["go"] = true
|
||||
}
|
||||
if modFile.Toolchain != nil {
|
||||
roots = append(roots, module.Version{Path: "toolchain", Version: modFile.Toolchain.Name})
|
||||
direct["toolchain"] = true
|
||||
}
|
||||
// Do not add "toolchain" to roots.
|
||||
// We only want to see it in roots if it is on the command line.
|
||||
}
|
||||
gover.ModSort(roots)
|
||||
rs := newRequirements(pruning, roots, direct)
|
||||
|
|
@ -1546,8 +1551,10 @@ func commitRequirements(ctx context.Context) (err error) {
|
|||
|
||||
var list []*modfile.Require
|
||||
toolchain := ""
|
||||
wroteGo := false
|
||||
for _, m := range requirements.rootModules {
|
||||
if m.Path == "go" {
|
||||
wroteGo = true
|
||||
forceGoStmt(modFile, mainModule, m.Version)
|
||||
continue
|
||||
}
|
||||
|
|
@ -1561,27 +1568,49 @@ func commitRequirements(ctx context.Context) (err error) {
|
|||
})
|
||||
}
|
||||
|
||||
var oldToolchain string
|
||||
if modFile.Toolchain != nil {
|
||||
oldToolchain = modFile.Toolchain.Name
|
||||
}
|
||||
oldToolVers := gover.FromToolchain(oldToolchain)
|
||||
|
||||
// Update go and toolchain lines.
|
||||
tv := gover.FromToolchain(toolchain)
|
||||
toolVers := gover.FromToolchain(toolchain)
|
||||
|
||||
// Set go version if missing.
|
||||
if modFile.Go == nil || modFile.Go.Version == "" {
|
||||
wroteGo = true
|
||||
v := modFileGoVersion(modFile)
|
||||
if tv != "" && gover.Compare(v, tv) > 0 {
|
||||
v = tv
|
||||
if toolVers != "" && gover.Compare(v, toolVers) > 0 {
|
||||
v = toolVers
|
||||
}
|
||||
modFile.AddGoStmt(v)
|
||||
}
|
||||
if gover.Compare(modFile.Go.Version, gover.Local()) > 0 {
|
||||
// TODO: Reinvoke the newer toolchain if GOTOOLCHAIN=auto.
|
||||
base.Fatalf("go: %v", &gover.TooNewError{What: "updating go.mod", GoVersion: modFile.Go.Version})
|
||||
// We cannot assume that we know how to update a go.mod to a newer version.
|
||||
return &gover.TooNewError{What: "updating go.mod", GoVersion: modFile.Go.Version}
|
||||
}
|
||||
|
||||
// If toolchain is older than go version, drop it.
|
||||
if gover.Compare(modFile.Go.Version, tv) >= 0 {
|
||||
// If we update the go line and don't have an explicit instruction
|
||||
// for what to write in toolchain, make sure toolchain is at least our local version,
|
||||
// for reproducibility.
|
||||
if wroteGo && toolchain == "" && gover.Compare(oldToolVers, gover.Local()) < 0 && gover.Compare(modFile.Go.Version, GoStrictVersion) >= 0 {
|
||||
toolVers = gover.Local()
|
||||
toolchain = "go" + toolVers
|
||||
}
|
||||
|
||||
// Default to old toolchain.
|
||||
if toolchain == "" {
|
||||
toolchain = oldToolchain
|
||||
toolVers = oldToolVers
|
||||
}
|
||||
if toolchain == "none" {
|
||||
toolchain = ""
|
||||
}
|
||||
|
||||
// Remove or add toolchain as needed.
|
||||
if toolchain == "" {
|
||||
// If toolchain is older than go version, drop it.
|
||||
if toolchain == "" || gover.Compare(modFile.Go.Version, toolVers) >= 0 {
|
||||
modFile.DropToolchainStmt()
|
||||
} else {
|
||||
modFile.AddToolchainStmt(toolchain)
|
||||
|
|
|
|||
|
|
@ -511,13 +511,16 @@ func (i *modFileIndex) modFileIsDirty(modFile *modfile.File) bool {
|
|||
}
|
||||
|
||||
// go.mod files did not always require a 'go' version, so do not error out
|
||||
// if one is missing — we may be inside an older module in the module cache
|
||||
// if one is missing — we may be inside an older module
|
||||
// and want to bias toward providing useful behavior.
|
||||
// go lines are required if we need to declare version 1.17 or later.
|
||||
// Note that as of CL 303229, a missing go directive implies 1.16,
|
||||
// not “the latest Go version”.
|
||||
if goV != i.goVersion && i.goVersion == "" && cfg.BuildMod != "mod" && gover.Compare(goV, "1.17") < 0 {
|
||||
goV = ""
|
||||
if toolchain != i.toolchain && i.toolchain == "" {
|
||||
toolchain = ""
|
||||
}
|
||||
}
|
||||
|
||||
if goV != i.goVersion ||
|
||||
|
|
|
|||
|
|
@ -546,7 +546,7 @@ func (qm *queryMatcher) filterVersions(ctx context.Context, versions []string) (
|
|||
}
|
||||
}
|
||||
|
||||
if semver.Prerelease(v) != "" {
|
||||
if gover.ModIsPrerelease(qm.path, v) {
|
||||
prereleases = append(prereleases, v)
|
||||
} else {
|
||||
releases = append(releases, v)
|
||||
|
|
|
|||
|
|
@ -0,0 +1,55 @@
|
|||
// Copyright 2023 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.
|
||||
|
||||
//go:build !js && !wasip1
|
||||
|
||||
package toolchain
|
||||
|
||||
import (
|
||||
"cmd/go/internal/base"
|
||||
"internal/godebug"
|
||||
"os"
|
||||
"os/exec"
|
||||
"runtime"
|
||||
"syscall"
|
||||
)
|
||||
|
||||
// execGoToolchain execs the Go toolchain with the given name (gotoolchain),
|
||||
// GOROOT directory, and go command executable.
|
||||
// The GOROOT directory is empty if we are invoking a command named
|
||||
// gotoolchain found in $PATH.
|
||||
func execGoToolchain(gotoolchain, dir, exe string) {
|
||||
os.Setenv(gotoolchainSwitchEnv, "1")
|
||||
if dir == "" {
|
||||
os.Unsetenv("GOROOT")
|
||||
} else {
|
||||
os.Setenv("GOROOT", dir)
|
||||
}
|
||||
|
||||
// On Windows, there is no syscall.Exec, so the best we can do
|
||||
// is run a subprocess and exit with the same status.
|
||||
// Doing the same on Unix would be a problem because it wouldn't
|
||||
// propagate signals and such, but there are no signals on Windows.
|
||||
// We also use the exec case when GODEBUG=gotoolchainexec=0,
|
||||
// to allow testing this code even when not on Windows.
|
||||
if godebug.New("#gotoolchainexec").Value() == "0" || runtime.GOOS == "windows" {
|
||||
cmd := exec.Command(exe, os.Args[1:]...)
|
||||
cmd.Stdin = os.Stdin
|
||||
cmd.Stdout = os.Stdout
|
||||
cmd.Stderr = os.Stderr
|
||||
err := cmd.Run()
|
||||
if err != nil {
|
||||
if e, ok := err.(*exec.ExitError); ok && e.ProcessState != nil {
|
||||
if e.ProcessState.Exited() {
|
||||
os.Exit(e.ProcessState.ExitCode())
|
||||
}
|
||||
base.Fatalf("exec %s: %s", gotoolchain, e.ProcessState)
|
||||
}
|
||||
base.Fatalf("exec %s: %s", exe, err)
|
||||
}
|
||||
os.Exit(0)
|
||||
}
|
||||
err := syscall.Exec(exe, os.Args, os.Environ())
|
||||
base.Fatalf("exec %s: %v", gotoolchain, err)
|
||||
}
|
||||
|
|
@ -4,8 +4,10 @@
|
|||
|
||||
//go:build js || wasip1
|
||||
|
||||
package main
|
||||
package toolchain
|
||||
|
||||
// nop for systems that don't even define syscall.Exec, like js/wasm.
|
||||
func switchGoToolchain() {
|
||||
import "cmd/go/internal/base"
|
||||
|
||||
func execGoToolchain(gotoolchain, dir, exe string) {
|
||||
base.Fatalf("execGoToolchain unsupported")
|
||||
}
|
||||
|
|
@ -2,15 +2,13 @@
|
|||
// Use of this source code is governed by a BSD-style
|
||||
// license that can be found in the LICENSE file.
|
||||
|
||||
//go:build !js && !wasip1
|
||||
|
||||
package main
|
||||
// Package toolchain implements dynamic switching of Go toolchains.
|
||||
package toolchain
|
||||
|
||||
import (
|
||||
"context"
|
||||
"fmt"
|
||||
"go/build"
|
||||
"internal/godebug"
|
||||
"io/fs"
|
||||
"log"
|
||||
"os"
|
||||
|
|
@ -18,12 +16,12 @@ import (
|
|||
"path/filepath"
|
||||
"runtime"
|
||||
"strings"
|
||||
"syscall"
|
||||
|
||||
"cmd/go/internal/base"
|
||||
"cmd/go/internal/cfg"
|
||||
"cmd/go/internal/gover"
|
||||
"cmd/go/internal/modcmd"
|
||||
"cmd/go/internal/modfetch"
|
||||
"cmd/go/internal/modload"
|
||||
"cmd/go/internal/run"
|
||||
|
||||
|
|
@ -51,10 +49,11 @@ const (
|
|||
gotoolchainSwitchEnv = "GOTOOLCHAIN_INTERNAL_SWITCH"
|
||||
)
|
||||
|
||||
// switchGoToolchain invokes a different Go toolchain if directed by
|
||||
// Switch invokes a different Go toolchain if directed by
|
||||
// the GOTOOLCHAIN environment variable or the user's configuration
|
||||
// or go.mod file.
|
||||
func switchGoToolchain() {
|
||||
// It must be called early in startup.
|
||||
func Switch() {
|
||||
log.SetPrefix("go: ")
|
||||
defer log.SetPrefix("")
|
||||
|
||||
|
|
@ -93,7 +92,6 @@ func switchGoToolchain() {
|
|||
minToolchain = "go" + minVers
|
||||
}
|
||||
|
||||
pathOnly := gotoolchain == "path"
|
||||
if gotoolchain == "auto" || gotoolchain == "path" {
|
||||
gotoolchain = minToolchain
|
||||
|
||||
|
|
@ -155,6 +153,103 @@ func switchGoToolchain() {
|
|||
base.Fatalf("invalid GOTOOLCHAIN %q", gotoolchain)
|
||||
}
|
||||
|
||||
SwitchTo(gotoolchain)
|
||||
}
|
||||
|
||||
// NewerToolchain returns the name of the toolchain to use when we need
|
||||
// to reinvoke a newer toolchain that must support at least the given Go version.
|
||||
//
|
||||
// If the latest major release is 1.N.0, we use the latest patch release of 1.(N-1) if that's >= version.
|
||||
// Otherwise we use the latest 1.N if that's allowed.
|
||||
// Otherwise we use the latest release.
|
||||
func NewerToolchain(ctx context.Context, version string) (string, error) {
|
||||
var versions *modfetch.Versions
|
||||
err := modfetch.TryProxies(func(proxy string) error {
|
||||
v, err := modfetch.Lookup(ctx, proxy, "go").Versions(ctx, "")
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
versions = v
|
||||
return nil
|
||||
})
|
||||
if err != nil {
|
||||
return "", err
|
||||
}
|
||||
return newerToolchain(version, versions.List)
|
||||
}
|
||||
|
||||
// newerToolchain implements NewerToolchain where the list of choices is known.
|
||||
// It is separated out for easier testing of this logic.
|
||||
func newerToolchain(need string, list []string) (string, error) {
|
||||
// Consider each release in the list, from newest to oldest,
|
||||
// considering only entries >= need and then only entries
|
||||
// that are the latest in their language family
|
||||
// (the latest 1.40, the latest 1.39, and so on).
|
||||
// We prefer the latest patch release before the most recent release family,
|
||||
// so if the latest release is 1.40.1 we'll take the latest 1.39.X.
|
||||
// Failing that, we prefer the latest patch release before the most recent
|
||||
// prerelease family, so if the latest release is 1.40rc1 is out but 1.39 is okay,
|
||||
// we'll still take 1.39.X.
|
||||
// Failing that we'll take the latest release.
|
||||
latest := ""
|
||||
for i := len(list) - 1; i >= 0; i-- {
|
||||
v := list[i]
|
||||
if gover.Compare(v, need) < 0 {
|
||||
break
|
||||
}
|
||||
if gover.Lang(latest) == gover.Lang(v) {
|
||||
continue
|
||||
}
|
||||
newer := latest
|
||||
latest = v
|
||||
if newer != "" && !gover.IsPrerelease(newer) {
|
||||
// latest is the last patch release of Go 1.X, and we saw a non-prerelease of Go 1.(X+1),
|
||||
// so latest is the one we want.
|
||||
break
|
||||
}
|
||||
}
|
||||
if latest == "" {
|
||||
return "", fmt.Errorf("no releases found for go >= %v", need)
|
||||
}
|
||||
return "go" + latest, nil
|
||||
}
|
||||
|
||||
// HasAuto reports whether the GOTOOLCHAIN setting allows "auto" upgrades.
|
||||
func HasAuto() bool {
|
||||
env := cfg.Getenv("GOTOOLCHAIN")
|
||||
return env == "auto" || strings.HasSuffix(env, "+auto")
|
||||
}
|
||||
|
||||
// HasPath reports whether the GOTOOLCHAIN setting allows "path" upgrades.
|
||||
func HasPath() bool {
|
||||
env := cfg.Getenv("GOTOOLCHAIN")
|
||||
return env == "path" || strings.HasSuffix(env, "+path")
|
||||
}
|
||||
|
||||
// SwitchTo invokes the specified Go toolchain or else prints an error and exits the process.
|
||||
// If $GOTOOLCHAIN is set to path or min+path, SwitchTo only considers the PATH
|
||||
// as a source of Go toolchains. Otherwise SwitchTo tries the PATH but then downloads
|
||||
// a toolchain if necessary.
|
||||
func SwitchTo(gotoolchain string) {
|
||||
log.SetPrefix("go: ")
|
||||
|
||||
env := cfg.Getenv("GOTOOLCHAIN")
|
||||
pathOnly := env == "path" || strings.HasSuffix(env, "+path")
|
||||
|
||||
// For testing, if TESTGO_VERSION is already in use
|
||||
// (only happens in the cmd/go test binary)
|
||||
// and TESTGO_VERSION_SWITCH=1 is set,
|
||||
// "switch" toolchains by changing TESTGO_VERSION
|
||||
// and reinvoking the current binary.
|
||||
if gover.TestVersion != "" && os.Getenv("TESTGO_VERSION_SWITCH") == "1" {
|
||||
os.Setenv("TESTGO_VERSION", gotoolchain)
|
||||
exe, err := os.Executable()
|
||||
if err != nil {
|
||||
base.Fatalf("%v", err)
|
||||
}
|
||||
execGoToolchain(gotoolchain, os.Getenv("GOROOT"), exe)
|
||||
}
|
||||
|
||||
// Look in PATH for the toolchain before we download one.
|
||||
// This allows custom toolchains as well as reuse of toolchains
|
||||
// already installed using go install golang.org/dl/go1.2.3@latest.
|
||||
|
|
@ -169,6 +264,7 @@ func switchGoToolchain() {
|
|||
}
|
||||
|
||||
// Set up modules without an explicit go.mod, to download distribution.
|
||||
modload.Reset()
|
||||
modload.ForceUseModules = true
|
||||
modload.RootMode = modload.NoRoot
|
||||
modload.Init()
|
||||
|
|
@ -238,46 +334,6 @@ func switchGoToolchain() {
|
|||
execGoToolchain(gotoolchain, dir, filepath.Join(dir, "bin/go"))
|
||||
}
|
||||
|
||||
// execGoToolchain execs the Go toolchain with the given name (gotoolchain),
|
||||
// GOROOT directory, and go command executable.
|
||||
// The GOROOT directory is empty if we are invoking a command named
|
||||
// gotoolchain found in $PATH.
|
||||
func execGoToolchain(gotoolchain, dir, exe string) {
|
||||
os.Setenv(gotoolchainSwitchEnv, "1")
|
||||
if dir == "" {
|
||||
os.Unsetenv("GOROOT")
|
||||
} else {
|
||||
os.Setenv("GOROOT", dir)
|
||||
}
|
||||
|
||||
// On Windows, there is no syscall.Exec, so the best we can do
|
||||
// is run a subprocess and exit with the same status.
|
||||
// Doing the same on Unix would be a problem because it wouldn't
|
||||
// propagate signals and such, but there are no signals on Windows.
|
||||
// We also use the exec case when GODEBUG=gotoolchainexec=0,
|
||||
// to allow testing this code even when not on Windows.
|
||||
if godebug.New("#gotoolchainexec").Value() == "0" || runtime.GOOS == "windows" {
|
||||
cmd := exec.Command(exe, os.Args[1:]...)
|
||||
cmd.Stdin = os.Stdin
|
||||
cmd.Stdout = os.Stdout
|
||||
cmd.Stderr = os.Stderr
|
||||
fmt.Fprintln(os.Stderr, cmd.Args)
|
||||
err := cmd.Run()
|
||||
if err != nil {
|
||||
if e, ok := err.(*exec.ExitError); ok && e.ProcessState != nil {
|
||||
if e.ProcessState.Exited() {
|
||||
os.Exit(e.ProcessState.ExitCode())
|
||||
}
|
||||
base.Fatalf("exec %s: %s", gotoolchain, e.ProcessState)
|
||||
}
|
||||
base.Fatalf("exec %s: %s", exe, err)
|
||||
}
|
||||
os.Exit(0)
|
||||
}
|
||||
err := syscall.Exec(exe, os.Args, os.Environ())
|
||||
base.Fatalf("exec %s: %v", gotoolchain, err)
|
||||
}
|
||||
|
||||
// modGoToolchain finds the enclosing go.work or go.mod file
|
||||
// and returns the go version and toolchain lines from the file.
|
||||
// The toolchain line overrides the version line
|
||||
|
|
@ -0,0 +1,66 @@
|
|||
// Copyright 2023 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 toolchain
|
||||
|
||||
import (
|
||||
"strings"
|
||||
"testing"
|
||||
)
|
||||
|
||||
func TestNewerToolchain(t *testing.T) {
|
||||
for _, tt := range newerToolchainTests {
|
||||
out, err := newerToolchain(tt.need, tt.list)
|
||||
if (err != nil) != (out == "") {
|
||||
t.Errorf("newerToolchain(%v, %v) = %v, %v, want error", tt.need, tt.list, out, err)
|
||||
continue
|
||||
}
|
||||
if out != tt.out {
|
||||
t.Errorf("newerToolchain(%v, %v) = %v, %v want %v, nil", tt.need, tt.list, out, err, tt.out)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
var f = strings.Fields
|
||||
|
||||
var relRC = []string{"1.39.0", "1.39.1", "1.39.2", "1.40.0", "1.40.1", "1.40.2", "1.41rc1"}
|
||||
var rel2 = []string{"1.39.0", "1.39.1", "1.39.2", "1.40.0", "1.40.1", "1.40.2"}
|
||||
var rel0 = []string{"1.39.0", "1.39.1", "1.39.2", "1.40.0"}
|
||||
var newerToolchainTests = []struct {
|
||||
need string
|
||||
list []string
|
||||
out string
|
||||
}{
|
||||
{"1.30", rel0, "go1.39.2"},
|
||||
{"1.30", rel2, "go1.39.2"},
|
||||
{"1.30", relRC, "go1.39.2"},
|
||||
{"1.38", rel0, "go1.39.2"},
|
||||
{"1.38", rel2, "go1.39.2"},
|
||||
{"1.38", relRC, "go1.39.2"},
|
||||
{"1.38.1", rel0, "go1.39.2"},
|
||||
{"1.38.1", rel2, "go1.39.2"},
|
||||
{"1.38.1", relRC, "go1.39.2"},
|
||||
{"1.39", rel0, "go1.39.2"},
|
||||
{"1.39", rel2, "go1.39.2"},
|
||||
{"1.39", relRC, "go1.39.2"},
|
||||
{"1.39.2", rel0, "go1.39.2"},
|
||||
{"1.39.2", rel2, "go1.39.2"},
|
||||
{"1.39.2", relRC, "go1.39.2"},
|
||||
{"1.39.3", rel0, "go1.40.0"},
|
||||
{"1.39.3", rel2, "go1.40.2"},
|
||||
{"1.39.3", relRC, "go1.40.2"},
|
||||
{"1.40", rel0, "go1.40.0"},
|
||||
{"1.40", rel2, "go1.40.2"},
|
||||
{"1.40", relRC, "go1.40.2"},
|
||||
{"1.40.1", rel0, ""},
|
||||
{"1.40.1", rel2, "go1.40.2"},
|
||||
{"1.40.1", relRC, "go1.40.2"},
|
||||
{"1.41", rel0, ""},
|
||||
{"1.41", rel2, ""},
|
||||
{"1.41", relRC, "go1.41rc1"},
|
||||
{"1.41.0", rel0, ""},
|
||||
{"1.41.0", rel2, ""},
|
||||
{"1.41.0", relRC, ""},
|
||||
{"1.40", nil, ""},
|
||||
}
|
||||
|
|
@ -7,6 +7,7 @@
|
|||
package main
|
||||
|
||||
import (
|
||||
"cmd/go/internal/toolchain"
|
||||
"cmd/go/internal/workcmd"
|
||||
"context"
|
||||
"flag"
|
||||
|
|
@ -91,7 +92,7 @@ var _ = go11tag
|
|||
|
||||
func main() {
|
||||
log.SetFlags(0)
|
||||
switchGoToolchain()
|
||||
toolchain.Switch()
|
||||
|
||||
flag.Usage = base.Usage
|
||||
flag.Parse()
|
||||
|
|
|
|||
|
|
@ -0,0 +1,8 @@
|
|||
golang.org/toolchain v0.0.1-go1.18.1.linux-amd64
|
||||
written by hand
|
||||
-- .info --
|
||||
{"Version":"v0.0.1-go1.18.1.linux-amd64"}
|
||||
-- .mod --
|
||||
golang.org/toolchain
|
||||
-- go.mod --
|
||||
golang.org/toolchain
|
||||
|
|
@ -0,0 +1,8 @@
|
|||
golang.org/toolchain v0.0.1-go1.18.3.linux-amd64
|
||||
written by hand
|
||||
-- .info --
|
||||
{"Version":"v0.0.1-go1.18.3.linux-amd64"}
|
||||
-- .mod --
|
||||
golang.org/toolchain
|
||||
-- go.mod --
|
||||
golang.org/toolchain
|
||||
|
|
@ -0,0 +1,8 @@
|
|||
golang.org/toolchain v0.0.1-go1.18.5.linux-amd64
|
||||
written by hand
|
||||
-- .info --
|
||||
{"Version":"v0.0.1-go1.18.5.linux-amd64"}
|
||||
-- .mod --
|
||||
golang.org/toolchain
|
||||
-- go.mod --
|
||||
golang.org/toolchain
|
||||
|
|
@ -0,0 +1,8 @@
|
|||
golang.org/toolchain v0.0.1-go1.18.7.linux-amd64
|
||||
written by hand
|
||||
-- .info --
|
||||
{"Version":"v0.0.1-go1.18.7.linux-amd64"}
|
||||
-- .mod --
|
||||
golang.org/toolchain
|
||||
-- go.mod --
|
||||
golang.org/toolchain
|
||||
|
|
@ -0,0 +1,8 @@
|
|||
golang.org/toolchain v0.0.1-go1.18.9.linux-amd64
|
||||
written by hand
|
||||
-- .info --
|
||||
{"Version":"v0.0.1-go1.18.9.linux-amd64"}
|
||||
-- .mod --
|
||||
golang.org/toolchain
|
||||
-- go.mod --
|
||||
golang.org/toolchain
|
||||
|
|
@ -0,0 +1,8 @@
|
|||
golang.org/toolchain v0.0.1-go1.18.linux-amd64
|
||||
written by hand
|
||||
-- .info --
|
||||
{"Version":"v0.0.1-go1.18.linux-amd64"}
|
||||
-- .mod --
|
||||
golang.org/toolchain
|
||||
-- go.mod --
|
||||
golang.org/toolchain
|
||||
|
|
@ -0,0 +1,8 @@
|
|||
golang.org/toolchain v0.0.1-go1.22.0.linux-amd64
|
||||
written by hand
|
||||
-- .info --
|
||||
{"Version":"v0.0.1-go1.22.0.linux-amd64"}
|
||||
-- .mod --
|
||||
golang.org/toolchain
|
||||
-- go.mod --
|
||||
golang.org/toolchain
|
||||
|
|
@ -0,0 +1,8 @@
|
|||
golang.org/toolchain v0.0.1-go1.22.1.linux-amd64
|
||||
written by hand
|
||||
-- .info --
|
||||
{"Version":"v0.0.1-go1.22.1.linux-amd64"}
|
||||
-- .mod --
|
||||
golang.org/toolchain
|
||||
-- go.mod --
|
||||
golang.org/toolchain
|
||||
|
|
@ -0,0 +1,8 @@
|
|||
golang.org/toolchain v0.0.1-go1.22.3.linux-amd64
|
||||
written by hand
|
||||
-- .info --
|
||||
{"Version":"v0.0.1-go1.22.3.linux-amd64"}
|
||||
-- .mod --
|
||||
golang.org/toolchain
|
||||
-- go.mod --
|
||||
golang.org/toolchain
|
||||
|
|
@ -0,0 +1,8 @@
|
|||
golang.org/toolchain v0.0.1-go1.22.5.linux-amd64
|
||||
written by hand
|
||||
-- .info --
|
||||
{"Version":"v0.0.1-go1.22.5.linux-amd64"}
|
||||
-- .mod --
|
||||
golang.org/toolchain
|
||||
-- go.mod --
|
||||
golang.org/toolchain
|
||||
|
|
@ -0,0 +1,8 @@
|
|||
golang.org/toolchain v0.0.1-go1.22.7.linux-amd64
|
||||
written by hand
|
||||
-- .info --
|
||||
{"Version":"v0.0.1-go1.22.7.linux-amd64"}
|
||||
-- .mod --
|
||||
golang.org/toolchain
|
||||
-- go.mod --
|
||||
golang.org/toolchain
|
||||
|
|
@ -0,0 +1,8 @@
|
|||
golang.org/toolchain v0.0.1-go1.22.9.linux-amd64
|
||||
written by hand
|
||||
-- .info --
|
||||
{"Version":"v0.0.1-go1.22.9.linux-amd64"}
|
||||
-- .mod --
|
||||
golang.org/toolchain
|
||||
-- go.mod --
|
||||
golang.org/toolchain
|
||||
8
src/cmd/go/testdata/mod/golang.org_toolchain_v0.0.1-go1.22rc1.linux-amd64.txt
vendored
Normal file
8
src/cmd/go/testdata/mod/golang.org_toolchain_v0.0.1-go1.22rc1.linux-amd64.txt
vendored
Normal file
|
|
@ -0,0 +1,8 @@
|
|||
golang.org/toolchain v0.0.1-go1.22rc1.linux-amd64
|
||||
written by hand
|
||||
-- .info --
|
||||
{"Version":"v0.0.1-go1.22rc1.linux-amd64"}
|
||||
-- .mod --
|
||||
golang.org/toolchain
|
||||
-- go.mod --
|
||||
golang.org/toolchain
|
||||
|
|
@ -0,0 +1,8 @@
|
|||
golang.org/toolchain v0.0.1-go1.23.0.linux-amd64
|
||||
written by hand
|
||||
-- .info --
|
||||
{"Version":"v0.0.1-go1.23.0.linux-amd64"}
|
||||
-- .mod --
|
||||
golang.org/toolchain
|
||||
-- go.mod --
|
||||
golang.org/toolchain
|
||||
|
|
@ -0,0 +1,8 @@
|
|||
golang.org/toolchain v0.0.1-go1.23.5.linux-amd64
|
||||
written by hand
|
||||
-- .info --
|
||||
{"Version":"v0.0.1-go1.23.5.linux-amd64"}
|
||||
-- .mod --
|
||||
golang.org/toolchain
|
||||
-- go.mod --
|
||||
golang.org/toolchain
|
||||
|
|
@ -0,0 +1,8 @@
|
|||
golang.org/toolchain v0.0.1-go1.23.9.linux-amd64
|
||||
written by hand
|
||||
-- .info --
|
||||
{"Version":"v0.0.1-go1.23.9.linux-amd64"}
|
||||
-- .mod --
|
||||
golang.org/toolchain
|
||||
-- go.mod --
|
||||
golang.org/toolchain
|
||||
8
src/cmd/go/testdata/mod/golang.org_toolchain_v0.0.1-go1.24rc1.linux-amd64.txt
vendored
Normal file
8
src/cmd/go/testdata/mod/golang.org_toolchain_v0.0.1-go1.24rc1.linux-amd64.txt
vendored
Normal file
|
|
@ -0,0 +1,8 @@
|
|||
golang.org/toolchain v0.0.1-go1.24rc1.linux-amd64
|
||||
written by hand
|
||||
-- .info --
|
||||
{"Version":"v0.0.1-go1.24rc1.linux-amd64"}
|
||||
-- .mod --
|
||||
golang.org/toolchain
|
||||
-- go.mod --
|
||||
golang.org/toolchain
|
||||
|
|
@ -0,0 +1,25 @@
|
|||
rsc.io/needall 0.0.1
|
||||
written by hand
|
||||
|
||||
-- .mod --
|
||||
module rsc.io/needall
|
||||
go 1.23
|
||||
|
||||
require rsc.io/needgo121 v0.0.1
|
||||
require rsc.io/needgo122 v0.0.1
|
||||
require rsc.io/needgo123 v0.0.1
|
||||
|
||||
-- go.mod --
|
||||
module rsc.io/needall
|
||||
go 1.23
|
||||
|
||||
require rsc.io/needgo121 v0.0.1
|
||||
require rsc.io/needgo122 v0.0.1
|
||||
require rsc.io/needgo123 v0.0.1
|
||||
|
||||
-- .info --
|
||||
{"Version":"v0.0.1"}
|
||||
-- p.go --
|
||||
package p
|
||||
|
||||
func F() {}
|
||||
|
|
@ -0,0 +1,17 @@
|
|||
rsc.io/needgo1183 v0.0.1
|
||||
written by hand
|
||||
|
||||
-- .mod --
|
||||
module rsc.io/needgo1183
|
||||
go 1.18.3
|
||||
|
||||
-- go.mod --
|
||||
module rsc.io/needgo1183
|
||||
go 1.18.3
|
||||
|
||||
-- .info --
|
||||
{"Version":"v0.0.1"}
|
||||
-- p.go --
|
||||
package p
|
||||
|
||||
func F() {}
|
||||
|
|
@ -0,0 +1,17 @@
|
|||
rsc.io/needgo118 0.0.1
|
||||
written by hand
|
||||
|
||||
-- .mod --
|
||||
module rsc.io/needgo118
|
||||
go 1.18
|
||||
|
||||
-- go.mod --
|
||||
module rsc.io/needgo118
|
||||
go 1.18
|
||||
|
||||
-- .info --
|
||||
{"Version":"v0.0.1"}
|
||||
-- p.go --
|
||||
package p
|
||||
|
||||
func F() {}
|
||||
|
|
@ -0,0 +1,17 @@
|
|||
rsc.io/needgo121 0.0.1
|
||||
written by hand
|
||||
|
||||
-- .mod --
|
||||
module rsc.io/needgo121
|
||||
go 1.21
|
||||
|
||||
-- go.mod --
|
||||
module rsc.io/needgo121
|
||||
go 1.21
|
||||
|
||||
-- .info --
|
||||
{"Version":"v0.0.1"}
|
||||
-- p.go --
|
||||
package p
|
||||
|
||||
func F() {}
|
||||
|
|
@ -0,0 +1,17 @@
|
|||
rsc.io/needgo1223 0.0.1
|
||||
written by hand
|
||||
|
||||
-- .mod --
|
||||
module rsc.io/needgo1223
|
||||
go 1.22.3
|
||||
|
||||
-- go.mod --
|
||||
module rsc.io/needgo1223
|
||||
go 1.22.3
|
||||
|
||||
-- .info --
|
||||
{"Version":"v0.0.1"}
|
||||
-- p.go --
|
||||
package p
|
||||
|
||||
func F() {}
|
||||
|
|
@ -0,0 +1,17 @@
|
|||
rsc.io/needgo122 0.0.1
|
||||
written by hand
|
||||
|
||||
-- .mod --
|
||||
module rsc.io/needgo122
|
||||
go 1.22
|
||||
|
||||
-- go.mod --
|
||||
module rsc.io/needgo122
|
||||
go 1.22
|
||||
|
||||
-- .info --
|
||||
{"Version":"v0.0.1"}
|
||||
-- p.go --
|
||||
package p
|
||||
|
||||
func F() {}
|
||||
|
|
@ -0,0 +1,17 @@
|
|||
rsc.io/needgo123 0.0.1
|
||||
written by hand
|
||||
|
||||
-- .mod --
|
||||
module rsc.io/needgo123
|
||||
go 1.23
|
||||
|
||||
-- go.mod --
|
||||
module rsc.io/needgo123
|
||||
go 1.23
|
||||
|
||||
-- .info --
|
||||
{"Version":"v0.0.1"}
|
||||
-- p.go --
|
||||
package p
|
||||
|
||||
func F() {}
|
||||
|
|
@ -0,0 +1,17 @@
|
|||
rsc.io/needgo124 0.0.1
|
||||
written by hand
|
||||
|
||||
-- .mod --
|
||||
module rsc.io/needgo124
|
||||
go 1.24
|
||||
|
||||
-- go.mod --
|
||||
module rsc.io/needgo124
|
||||
go 1.24
|
||||
|
||||
-- .info --
|
||||
{"Version":"v0.0.1"}
|
||||
-- p.go --
|
||||
package p
|
||||
|
||||
func F() {}
|
||||
|
|
@ -73,13 +73,13 @@ env TESTGO_VERSION=go1.100
|
|||
# toolchain local in go.mod
|
||||
cp go1999toolchainlocal go.mod
|
||||
! go build
|
||||
stderr '^go: go.mod requires go 1.999 \(running go 1.100; go.mod sets go 1.999, toolchain local\)$'
|
||||
stderr '^go: go.mod requires go >= 1.999 \(running go 1.100; go.mod sets go 1.999, toolchain local\)$'
|
||||
|
||||
# toolchain local in go.work
|
||||
cp empty go.mod
|
||||
cp go1999toolchainlocal go.work
|
||||
! go build
|
||||
stderr '^go: go.work requires go 1.999 \(running go 1.100; go.work sets go 1.999, toolchain local\)$'
|
||||
stderr '^go: go.work requires go >= 1.999 \(running go 1.100; go.work sets go 1.999, toolchain local\)$'
|
||||
rm go.work
|
||||
|
||||
# toolchain line in go.work
|
||||
|
|
|
|||
|
|
@ -0,0 +1,130 @@
|
|||
env TESTGO_VERSION=go1.21
|
||||
env TESTGO_VERSION_SWITCH=1
|
||||
|
||||
# GOTOOLCHAIN=auto should run the newer toolchain
|
||||
env GOTOOLCHAIN=auto
|
||||
cp go.mod.new go.mod
|
||||
go get rsc.io/needgo121 rsc.io/needgo122 rsc.io/needgo123 rsc.io/needall
|
||||
stderr '^go: switching to go1.23.9$'
|
||||
stderr '^go: added rsc.io/needall v0.0.1'
|
||||
! stderr 'requires go >= 1.23'
|
||||
grep 'go 1.23' go.mod
|
||||
grep 'toolchain go1.23.9' go.mod
|
||||
|
||||
# GOTOOLCHAIN=min+auto should run the newer toolchain
|
||||
env GOTOOLCHAIN=go1.21+auto
|
||||
cp go.mod.new go.mod
|
||||
go get rsc.io/needgo121 rsc.io/needgo122 rsc.io/needgo123 rsc.io/needall
|
||||
stderr '^go: switching to go1.23.9$'
|
||||
stderr '^go: added rsc.io/needall v0.0.1'
|
||||
! stderr 'requires go >= 1.23'
|
||||
grep 'go 1.23' go.mod
|
||||
grep 'toolchain go1.23.9' go.mod
|
||||
|
||||
# GOTOOLCHAIN=go1.21 should NOT run the newer toolchain
|
||||
env GOTOOLCHAIN=go1.21
|
||||
cp go.mod.new go.mod
|
||||
! go get rsc.io/needgo121 rsc.io/needgo122 rsc.io/needgo123 rsc.io/needall
|
||||
! stderr 'switching to go'
|
||||
stderr 'rsc.io/needgo122@v0.0.1 requires go >= 1.22'
|
||||
stderr 'rsc.io/needgo123@v0.0.1 requires go >= 1.23'
|
||||
stderr 'rsc.io/needall@v0.0.1 requires go >= 1.23'
|
||||
stderr 'requires go >= 1.23'
|
||||
! stderr 'requires go >= 1.21' # that's us!
|
||||
cmp go.mod go.mod.new
|
||||
|
||||
# GOTOOLCHAIN=local should NOT run the newer toolchain
|
||||
env GOTOOLCHAIN=local
|
||||
cp go.mod.new go.mod
|
||||
! go get rsc.io/needgo121 rsc.io/needgo122 rsc.io/needgo123 rsc.io/needall
|
||||
! stderr 'switching to go'
|
||||
stderr 'rsc.io/needgo122@v0.0.1 requires go >= 1.22'
|
||||
stderr 'rsc.io/needgo123@v0.0.1 requires go >= 1.23'
|
||||
stderr 'rsc.io/needall@v0.0.1 requires go >= 1.23'
|
||||
stderr 'requires go >= 1.23'
|
||||
! stderr 'requires go >= 1.21' # that's us!
|
||||
cmp go.mod go.mod.new
|
||||
|
||||
# go get go@1.22 should resolve to the latest 1.22
|
||||
env GOTOOLCHAIN=local
|
||||
cp go.mod.new go.mod
|
||||
! go get go@1.22
|
||||
stderr '^go: updating go.mod requires go >= 1.22.9 \(running go 1.21; GOTOOLCHAIN=local\)'
|
||||
|
||||
env GOTOOLCHAIN=auto
|
||||
cp go.mod.new go.mod
|
||||
go get go@1.22
|
||||
stderr '^go: switching to go1.22.9$'
|
||||
|
||||
# go get go@1.22rc1 should use 1.22rc1 exactly, not a later release.
|
||||
env GOTOOLCHAIN=local
|
||||
cp go.mod.new go.mod
|
||||
! go get go@1.22rc1
|
||||
stderr '^go: updating go.mod requires go >= 1.22rc1 \(running go 1.21; GOTOOLCHAIN=local\)'
|
||||
|
||||
env GOTOOLCHAIN=auto
|
||||
cp go.mod.new go.mod
|
||||
go get go@1.22rc1
|
||||
stderr '^go: switching to go1.22.9$'
|
||||
stderr '^go: upgraded go 1.1 => 1.22rc1$'
|
||||
stderr '^go: added toolchain go1.22.9$'
|
||||
|
||||
# go get go@1.22.1 should use 1.22.1 exactly, not a later release.
|
||||
env GOTOOLCHAIN=local
|
||||
cp go.mod.new go.mod
|
||||
! go get go@1.22.1
|
||||
stderr '^go: updating go.mod requires go >= 1.22.1 \(running go 1.21; GOTOOLCHAIN=local\)'
|
||||
|
||||
env GOTOOLCHAIN=auto
|
||||
cp go.mod.new go.mod
|
||||
go get go@1.22.1
|
||||
stderr '^go: switching to go1.22.9$'
|
||||
stderr '^go: upgraded go 1.1 => 1.22.1$'
|
||||
stderr '^go: added toolchain go1.22.9$'
|
||||
|
||||
# go get needgo122 (says 'go 1.22') should use 1.22.0, the earliest release we have available
|
||||
# (ignoring prereleases).
|
||||
env GOTOOLCHAIN=local
|
||||
cp go.mod.new go.mod
|
||||
! go get rsc.io/needgo122
|
||||
stderr '^go: rsc.io/needgo122@v0.0.1 requires go >= 1.22 \(running go 1.21; GOTOOLCHAIN=local\)'
|
||||
|
||||
env GOTOOLCHAIN=auto
|
||||
cp go.mod.new go.mod
|
||||
go get rsc.io/needgo122
|
||||
stderr '^go: upgraded go 1.1 => 1.22$'
|
||||
stderr '^go: switching to go1.22.9$'
|
||||
stderr '^go: added toolchain go1.22.9$'
|
||||
|
||||
# go get needgo1223 (says 'go 1.22.3') should use go 1.22.3
|
||||
env GOTOOLCHAIN=local
|
||||
cp go.mod.new go.mod
|
||||
! go get rsc.io/needgo1223
|
||||
stderr '^go: rsc.io/needgo1223@v0.0.1 requires go >= 1.22.3 \(running go 1.21; GOTOOLCHAIN=local\)'
|
||||
|
||||
env GOTOOLCHAIN=auto
|
||||
cp go.mod.new go.mod
|
||||
go get rsc.io/needgo1223
|
||||
stderr '^go: upgraded go 1.1 => 1.22.3$'
|
||||
stderr '^go: switching to go1.22.9$'
|
||||
stderr '^go: added toolchain go1.22.9$'
|
||||
|
||||
# go get needgo124 (says 'go 1.24') should use go 1.24rc1, the only version available
|
||||
env GOTOOLCHAIN=local
|
||||
cp go.mod.new go.mod
|
||||
! go get rsc.io/needgo124
|
||||
stderr '^go: rsc.io/needgo124@v0.0.1 requires go >= 1.24 \(running go 1.21; GOTOOLCHAIN=local\)'
|
||||
|
||||
env GOTOOLCHAIN=auto
|
||||
cp go.mod.new go.mod
|
||||
go get rsc.io/needgo124
|
||||
stderr '^go: switching to go1.24rc1'
|
||||
stderr '^go: upgraded go 1.1 => 1.24$'
|
||||
stderr '^go: added toolchain go1.24rc1$'
|
||||
|
||||
-- go.mod.new --
|
||||
module m
|
||||
go 1.1
|
||||
|
||||
-- p.go --
|
||||
package p
|
||||
|
|
@ -1,6 +1,6 @@
|
|||
env TESTGO_VERSION=go1.21
|
||||
! go mod download rsc.io/future@v1.0.0
|
||||
stderr '^go: rsc.io/future@v1.0.0 requires go 1.999 \(running go 1.21; go.mod sets go 1.21\)$'
|
||||
stderr '^go: rsc.io/future@v1.0.0 requires go >= 1.999 \(running go 1.21; go.mod sets go 1.21\)$'
|
||||
|
||||
-- go.mod --
|
||||
module m
|
||||
|
|
|
|||
|
|
@ -4,9 +4,9 @@ env GO111MODULE=on
|
|||
env TESTGO_VERSION=go1.21
|
||||
|
||||
! go list
|
||||
stderr -count=1 '^go: sub@v1.0.0: sub requires go 1.999 \(running go 1.21; go.mod sets go 1.1\)$'
|
||||
stderr -count=1 '^go: sub@v1.0.0: sub requires go >= 1.999 \(running go 1.21; go.mod sets go 1.1\)$'
|
||||
! go build sub
|
||||
stderr -count=1 '^go: sub@v1.0.0: sub requires go 1.999 \(running go 1.21; go.mod sets go 1.1\)$'
|
||||
stderr -count=1 '^go: sub@v1.0.0: sub requires go >= 1.999 \(running go 1.21; go.mod sets go 1.1\)$'
|
||||
|
||||
-- go.mod --
|
||||
module m
|
||||
|
|
|
|||
|
|
@ -3,24 +3,24 @@
|
|||
# go.mod too new
|
||||
env GOTOOLCHAIN=local
|
||||
! go build .
|
||||
stderr '^go: go.mod requires go 1.99999 \(running go 1\..+\)$'
|
||||
stderr '^go: go.mod requires go >= 1.99999 \(running go 1\..+\)$'
|
||||
|
||||
# go.mod referenced from go.work too new
|
||||
cp go.work.old go.work
|
||||
! go build .
|
||||
stderr '^go: go.mod requires go 1.99999 \(running go 1\..+\)$'
|
||||
stderr '^go: go.mod requires go >= 1.99999 \(running go 1\..+\)$'
|
||||
|
||||
# go.work too new
|
||||
cp go.work.new go.work
|
||||
cp go.mod.old go.mod
|
||||
! go build .
|
||||
stderr '^go: go.work requires go 1.99999 \(running go 1\..+\)$'
|
||||
stderr '^go: go.work requires go >= 1.99999 \(running go 1\..+\)$'
|
||||
|
||||
# vendor too new
|
||||
rm go.work
|
||||
mv notvendor vendor
|
||||
! go build -mod=vendor .
|
||||
stderr '^go: golang.org/x/text in vendor'${/}'modules.txt requires go 1.99999 \(running go 1\..+\)$'
|
||||
stderr '^go: golang.org/x/text in vendor'${/}'modules.txt requires go >= 1.99999 \(running go 1\..+\)$'
|
||||
|
||||
-- go.mod --
|
||||
module example
|
||||
|
|
|
|||
|
|
@ -1,68 +1,69 @@
|
|||
[!net:golang.org] skip
|
||||
|
||||
env GOPROXY=https://proxy.golang.org/
|
||||
env TESTGO_VERSION=go1.100
|
||||
go get toolchain@go1.20.1
|
||||
stderr '^go: added toolchain go1.20.1$'
|
||||
env TESTGO_VERSION_SWITCH=1
|
||||
|
||||
go get toolchain@go1.22.1
|
||||
stderr '^go: added toolchain go1.22.1$'
|
||||
! stderr '(added|removed|upgraded|downgraded) go'
|
||||
grep 'toolchain go1.20.1' go.mod
|
||||
grep 'toolchain go1.22.1' go.mod
|
||||
|
||||
go get toolchain@none
|
||||
stderr '^go: removed toolchain go1.20.1$'
|
||||
stderr '^go: removed toolchain go1.22.1$'
|
||||
! stderr '(added|removed|upgraded|downgraded) go'
|
||||
! grep toolchain go.mod
|
||||
|
||||
go get toolchain@go1.20.1
|
||||
stderr '^go: added toolchain go1.20.1$'
|
||||
go get toolchain@go1.22.1
|
||||
stderr '^go: added toolchain go1.22.1$'
|
||||
! stderr '(added|removed|upgraded|downgraded) go'
|
||||
grep 'toolchain go1.20.1' go.mod
|
||||
grep 'toolchain go1.22.1' go.mod
|
||||
|
||||
cat go.mod
|
||||
go get go@1.20.3
|
||||
stderr '^go: upgraded go 1.10 => 1.20.3$'
|
||||
stderr '^go: removed toolchain go1.20.1$'
|
||||
grep 'go 1.20.3' go.mod
|
||||
go get go@1.22.3
|
||||
stderr '^go: upgraded go 1.10 => 1.22.3$'
|
||||
stderr '^go: upgraded toolchain go1.22.1 => go1.100$'
|
||||
grep 'go 1.22.3' go.mod
|
||||
|
||||
go get go@1.22.3 toolchain@1.22.3
|
||||
stderr '^go: removed toolchain go1.100$'
|
||||
! grep toolchain go.mod
|
||||
|
||||
go get go@1.20.1 toolchain@go1.20.3
|
||||
stderr '^go: downgraded go 1.20.3 => 1.20.1$'
|
||||
stderr '^go: added toolchain go1.20.3$'
|
||||
grep 'go 1.20.1' go.mod
|
||||
grep 'toolchain go1.20.3' go.mod
|
||||
go get go@1.22.1 toolchain@go1.22.3
|
||||
stderr '^go: downgraded go 1.22.3 => 1.22.1$'
|
||||
stderr '^go: added toolchain go1.22.3$'
|
||||
grep 'go 1.22.1' go.mod
|
||||
grep 'toolchain go1.22.3' go.mod
|
||||
|
||||
go get go@1.20.3
|
||||
stderr '^go: upgraded go 1.20.1 => 1.20.3$'
|
||||
stderr '^go: removed toolchain go1.20.3$'
|
||||
grep 'go 1.20.3' go.mod
|
||||
go get go@1.22.3 toolchain@1.22.3
|
||||
stderr '^go: upgraded go 1.22.1 => 1.22.3$'
|
||||
stderr '^go: removed toolchain go1.22.3$'
|
||||
grep 'go 1.22.3' go.mod
|
||||
! grep toolchain go.mod
|
||||
|
||||
go get toolchain@1.20.1
|
||||
stderr '^go: downgraded go 1.20.3 => 1.20.1$'
|
||||
# ! stderr toolchain
|
||||
grep 'go 1.20.1' go.mod
|
||||
go get toolchain@1.22.1
|
||||
stderr '^go: downgraded go 1.22.3 => 1.22.1$'
|
||||
! stderr toolchain # already gone, was not added
|
||||
grep 'go 1.22.1' go.mod
|
||||
! grep toolchain go.mod
|
||||
|
||||
env TESTGO_VERSION=go1.20.1
|
||||
env TESTGO_VERSION=go1.22.1
|
||||
env GOTOOLCHAIN=local
|
||||
! go get go@1.20.3
|
||||
stderr 'go: updating go.mod requires go 1.20.3 \(running go 1.20.1; GOTOOLCHAIN=local\)$'
|
||||
|
||||
go get toolchain@1.20.3
|
||||
grep 'toolchain go1.20.3' go.mod
|
||||
! go get go@1.22.3
|
||||
stderr 'go: updating go.mod requires go >= 1.22.3 \(running go 1.22.1; GOTOOLCHAIN=local\)$'
|
||||
|
||||
env TESTGO_VERSION=go1.30
|
||||
go get go@1.20.1
|
||||
grep 'go 1.20.1' go.mod
|
||||
go get m2@v1.0.0
|
||||
stderr '^go: upgraded go 1.20.1 => 1.22$'
|
||||
stderr '^go: added m2 v1.0.0$'
|
||||
grep 'go 1.22' go.mod
|
||||
go get toolchain@1.22.3
|
||||
grep 'toolchain go1.22.3' go.mod
|
||||
|
||||
go mod edit -toolchain=go1.29.0 # cannot go get because it doesn't exist
|
||||
go get go@1.28.0
|
||||
go get go@1.22.1
|
||||
grep 'go 1.22.1' go.mod
|
||||
go get m2@v1.0.0
|
||||
stderr '^go: upgraded go 1.22.1 => 1.23$'
|
||||
stderr '^go: added m2 v1.0.0$'
|
||||
grep 'go 1.23$' go.mod
|
||||
|
||||
go get toolchain@go1.23.9 go@1.23.5
|
||||
go get toolchain@none
|
||||
stderr '^go: removed toolchain go1.29.0'
|
||||
stderr '^go: removed toolchain go1.23.9'
|
||||
! stderr ' go 1'
|
||||
grep 'go 1.28.0' go.mod
|
||||
grep 'go 1.23.5' go.mod
|
||||
|
||||
-- go.mod --
|
||||
module m
|
||||
|
|
@ -72,4 +73,4 @@ replace m2 v1.0.0 => ./m2
|
|||
|
||||
-- m2/go.mod --
|
||||
module m2
|
||||
go 1.22
|
||||
go 1.23
|
||||
|
|
|
|||
|
|
@ -0,0 +1,28 @@
|
|||
# Commands in an old module with no go line and no toolchain line,
|
||||
# or with only a go line, should succeed.
|
||||
# (They should not fail due to the go.mod not being tidy.)
|
||||
|
||||
# No go line, no toolchain line.
|
||||
go list
|
||||
|
||||
# Old go line, no toolchain line.
|
||||
go mod edit -go=1.16
|
||||
go list
|
||||
|
||||
go mod edit -go=1.20
|
||||
go list
|
||||
|
||||
# New go line, no toolchain line, using same toolchain.
|
||||
env TESTGO_VERSION=1.21
|
||||
go mod edit -go=1.21
|
||||
go list
|
||||
|
||||
# New go line, no toolchain line, using newer Go version.
|
||||
# (Until we need to update the go line, no toolchain addition.)
|
||||
env TESTGO_VERSION=1.21.0
|
||||
go list
|
||||
|
||||
-- go.mod --
|
||||
module m
|
||||
-- p.go --
|
||||
package p
|
||||
Loading…
Reference in New Issue