mirror of
https://github.com/golang/go
synced 2024-09-28 19:14:29 -06:00
cmd/go: move switch-only code from select.go to switch.go
Move NewerToolchain and related code from select.go to switch.go because it is only used for the Switch operation, not for Select. This is a separate CL containing only the code move, separate from any other changes. For #57001. Change-Id: I41cf0629b41fd55c30a1e799d857c06039ee99b6 Reviewed-on: https://go-review.googlesource.com/c/go/+/500798 Reviewed-by: Michael Matloob <matloob@golang.org> Run-TryBot: Russ Cox <rsc@golang.org> Auto-Submit: Russ Cox <rsc@golang.org> TryBot-Result: Gopher Robot <gobot@golang.org>
This commit is contained in:
parent
35268a9960
commit
e23273ddd4
@ -16,7 +16,6 @@ import (
|
|||||||
"os/exec"
|
"os/exec"
|
||||||
"path/filepath"
|
"path/filepath"
|
||||||
"runtime"
|
"runtime"
|
||||||
"sort"
|
|
||||||
"strconv"
|
"strconv"
|
||||||
"strings"
|
"strings"
|
||||||
|
|
||||||
@ -231,125 +230,6 @@ func Select() {
|
|||||||
Exec(gotoolchain)
|
Exec(gotoolchain)
|
||||||
}
|
}
|
||||||
|
|
||||||
// NewerToolchain returns the name of the toolchain to use when we need
|
|
||||||
// to switch to a newer toolchain that must support at least the given Go version.
|
|
||||||
// See https://go.dev/doc/toolchain#switch.
|
|
||||||
//
|
|
||||||
// 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) {
|
|
||||||
fetch := autoToolchains
|
|
||||||
if !HasAuto() {
|
|
||||||
fetch = pathToolchains
|
|
||||||
}
|
|
||||||
list, err := fetch(ctx)
|
|
||||||
if err != nil {
|
|
||||||
return "", err
|
|
||||||
}
|
|
||||||
return newerToolchain(version, list)
|
|
||||||
}
|
|
||||||
|
|
||||||
// autoToolchains returns the list of toolchain versions available to GOTOOLCHAIN=auto or =min+auto mode.
|
|
||||||
func autoToolchains(ctx context.Context) ([]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 nil, err
|
|
||||||
}
|
|
||||||
return versions.List, nil
|
|
||||||
}
|
|
||||||
|
|
||||||
// pathToolchains returns the list of toolchain versions available to GOTOOLCHAIN=path or =min+path mode.
|
|
||||||
func pathToolchains(ctx context.Context) ([]string, error) {
|
|
||||||
have := make(map[string]bool)
|
|
||||||
var list []string
|
|
||||||
for _, dir := range pathDirs() {
|
|
||||||
if dir == "" || !filepath.IsAbs(dir) {
|
|
||||||
// Refuse to use local directories in $PATH (hard-coding exec.ErrDot).
|
|
||||||
continue
|
|
||||||
}
|
|
||||||
entries, err := os.ReadDir(dir)
|
|
||||||
if err != nil {
|
|
||||||
continue
|
|
||||||
}
|
|
||||||
for _, de := range entries {
|
|
||||||
if de.IsDir() || !strings.HasPrefix(de.Name(), "go1.") {
|
|
||||||
continue
|
|
||||||
}
|
|
||||||
info, err := de.Info()
|
|
||||||
if err != nil {
|
|
||||||
continue
|
|
||||||
}
|
|
||||||
v, ok := pathVersion(dir, de, info)
|
|
||||||
if !ok || !strings.HasPrefix(v, "1.") || have[v] {
|
|
||||||
continue
|
|
||||||
}
|
|
||||||
have[v] = true
|
|
||||||
list = append(list, v)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
sort.Slice(list, func(i, j int) bool {
|
|
||||||
return gover.Compare(list[i], list[j]) < 0
|
|
||||||
})
|
|
||||||
return list, nil
|
|
||||||
}
|
|
||||||
|
|
||||||
// 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")
|
|
||||||
}
|
|
||||||
|
|
||||||
// TestVersionSwitch is set in the test go binary to the value in $TESTGO_VERSION_SWITCH.
|
// TestVersionSwitch is set in the test go binary to the value in $TESTGO_VERSION_SWITCH.
|
||||||
// Valid settings are:
|
// Valid settings are:
|
||||||
//
|
//
|
||||||
|
@ -8,9 +8,14 @@ import (
|
|||||||
"context"
|
"context"
|
||||||
"fmt"
|
"fmt"
|
||||||
"os"
|
"os"
|
||||||
|
"path/filepath"
|
||||||
|
"sort"
|
||||||
|
"strings"
|
||||||
|
|
||||||
"cmd/go/internal/base"
|
"cmd/go/internal/base"
|
||||||
|
"cmd/go/internal/cfg"
|
||||||
"cmd/go/internal/gover"
|
"cmd/go/internal/gover"
|
||||||
|
"cmd/go/internal/modfetch"
|
||||||
)
|
)
|
||||||
|
|
||||||
// A Switcher collects errors to be reported and then decides
|
// A Switcher collects errors to be reported and then decides
|
||||||
@ -105,3 +110,122 @@ func SwitchOrFatal(ctx context.Context, err error) {
|
|||||||
s.Switch(ctx)
|
s.Switch(ctx)
|
||||||
base.Exit()
|
base.Exit()
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// NewerToolchain returns the name of the toolchain to use when we need
|
||||||
|
// to switch to a newer toolchain that must support at least the given Go version.
|
||||||
|
// See https://go.dev/doc/toolchain#switch.
|
||||||
|
//
|
||||||
|
// 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) {
|
||||||
|
fetch := autoToolchains
|
||||||
|
if !HasAuto() {
|
||||||
|
fetch = pathToolchains
|
||||||
|
}
|
||||||
|
list, err := fetch(ctx)
|
||||||
|
if err != nil {
|
||||||
|
return "", err
|
||||||
|
}
|
||||||
|
return newerToolchain(version, list)
|
||||||
|
}
|
||||||
|
|
||||||
|
// autoToolchains returns the list of toolchain versions available to GOTOOLCHAIN=auto or =min+auto mode.
|
||||||
|
func autoToolchains(ctx context.Context) ([]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 nil, err
|
||||||
|
}
|
||||||
|
return versions.List, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
// pathToolchains returns the list of toolchain versions available to GOTOOLCHAIN=path or =min+path mode.
|
||||||
|
func pathToolchains(ctx context.Context) ([]string, error) {
|
||||||
|
have := make(map[string]bool)
|
||||||
|
var list []string
|
||||||
|
for _, dir := range pathDirs() {
|
||||||
|
if dir == "" || !filepath.IsAbs(dir) {
|
||||||
|
// Refuse to use local directories in $PATH (hard-coding exec.ErrDot).
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
entries, err := os.ReadDir(dir)
|
||||||
|
if err != nil {
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
for _, de := range entries {
|
||||||
|
if de.IsDir() || !strings.HasPrefix(de.Name(), "go1.") {
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
info, err := de.Info()
|
||||||
|
if err != nil {
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
v, ok := pathVersion(dir, de, info)
|
||||||
|
if !ok || !strings.HasPrefix(v, "1.") || have[v] {
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
have[v] = true
|
||||||
|
list = append(list, v)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
sort.Slice(list, func(i, j int) bool {
|
||||||
|
return gover.Compare(list[i], list[j]) < 0
|
||||||
|
})
|
||||||
|
return list, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
// 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")
|
||||||
|
}
|
||||||
|
Loading…
Reference in New Issue
Block a user