summaryrefslogtreecommitdiffstats
path: root/src/cmd/go/internal/gover/toolchain.go
diff options
context:
space:
mode:
Diffstat (limited to 'src/cmd/go/internal/gover/toolchain.go')
-rw-r--r--src/cmd/go/internal/gover/toolchain.go108
1 files changed, 108 insertions, 0 deletions
diff --git a/src/cmd/go/internal/gover/toolchain.go b/src/cmd/go/internal/gover/toolchain.go
new file mode 100644
index 0000000..43b117e
--- /dev/null
+++ b/src/cmd/go/internal/gover/toolchain.go
@@ -0,0 +1,108 @@
+// 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 gover
+
+import (
+ "cmd/go/internal/base"
+ "context"
+ "errors"
+ "fmt"
+ "strings"
+)
+
+// FromToolchain returns the Go version for the named toolchain,
+// derived from the name itself (not by running the toolchain).
+// A toolchain is named "goVERSION".
+// A suffix after the VERSION introduced by a -, space, or tab is removed.
+// Examples:
+//
+// FromToolchain("go1.2.3") == "1.2.3"
+// FromToolchain("go1.2.3-bigcorp") == "1.2.3"
+// FromToolchain("invalid") == ""
+func FromToolchain(name string) string {
+ if strings.ContainsAny(name, "\\/") {
+ // The suffix must not include a path separator, since that would cause
+ // exec.LookPath to resolve it from a relative directory instead of from
+ // $PATH.
+ return ""
+ }
+
+ var v string
+ if strings.HasPrefix(name, "go") {
+ v = name[2:]
+ } else {
+ return ""
+ }
+ // Some builds use custom suffixes; strip them.
+ if i := strings.IndexAny(v, " \t-"); i >= 0 {
+ v = v[:i]
+ }
+ if !IsValid(v) {
+ return ""
+ }
+ return v
+}
+
+func maybeToolchainVersion(name string) string {
+ if IsValid(name) {
+ return name
+ }
+ return FromToolchain(name)
+}
+
+// ToolchainMax returns the maximum of x and y interpreted as toolchain names,
+// compared using Compare(FromToolchain(x), FromToolchain(y)).
+// If x and y compare equal, Max returns x.
+func ToolchainMax(x, y string) string {
+ if Compare(FromToolchain(x), FromToolchain(y)) < 0 {
+ return y
+ }
+ return x
+}
+
+// Startup records the information that went into the startup-time version switch.
+// It is initialized by switchGoToolchain.
+var Startup struct {
+ GOTOOLCHAIN string // $GOTOOLCHAIN setting
+ AutoFile string // go.mod or go.work file consulted
+ AutoGoVersion string // go line found in file
+ AutoToolchain string // toolchain line found in file
+}
+
+// A TooNewError explains that a module is too new for this version of Go.
+type TooNewError struct {
+ What string
+ GoVersion string
+ Toolchain string // for callers if they want to use it, but not printed
+}
+
+func (e *TooNewError) Error() string {
+ var explain string
+ if Startup.GOTOOLCHAIN != "" && Startup.GOTOOLCHAIN != "auto" {
+ explain = "; GOTOOLCHAIN=" + Startup.GOTOOLCHAIN
+ }
+ if Startup.AutoFile != "" && (Startup.AutoGoVersion != "" || Startup.AutoToolchain != "") {
+ explain += fmt.Sprintf("; %s sets ", base.ShortPath(Startup.AutoFile))
+ if Startup.AutoToolchain != "" {
+ explain += "toolchain " + Startup.AutoToolchain
+ } else {
+ explain += "go " + Startup.AutoGoVersion
+ }
+ }
+ return fmt.Sprintf("%v requires go >= %v (running go %v%v)", e.What, e.GoVersion, Local(), explain)
+}
+
+var ErrTooNew = errors.New("module too new")
+
+func (e *TooNewError) Is(err error) bool {
+ return err == ErrTooNew
+}
+
+// A Switcher provides the ability to switch to a new toolchain in response to TooNewErrors.
+// See [cmd/go/internal/toolchain.Switcher] for documentation.
+type Switcher interface {
+ Error(err error)
+ Switch(ctx context.Context)
+}