1 // Copyright 2023 The Go Authors. All rights reserved.
2 // Use of this source code is governed by a BSD-style
3 // license that can be found in the LICENSE file.
15 // FromToolchain returns the Go version for the named toolchain,
16 // derived from the name itself (not by running the toolchain).
17 // A toolchain is named "goVERSION".
18 // A suffix after the VERSION introduced by a -, space, or tab is removed.
21 // FromToolchain("go1.2.3") == "1.2.3"
22 // FromToolchain("go1.2.3-bigcorp") == "1.2.3"
23 // FromToolchain("invalid") == ""
24 func FromToolchain(name string) string {
25 if strings.ContainsAny(name, "\\/") {
26 // The suffix must not include a path separator, since that would cause
27 // exec.LookPath to resolve it from a relative directory instead of from
33 if strings.HasPrefix(name, "go") {
38 // Some builds use custom suffixes; strip them.
39 if i := strings.IndexAny(v, " \t-"); i >= 0 {
48 func maybeToolchainVersion(name string) string {
52 return FromToolchain(name)
55 // Startup records the information that went into the startup-time version switch.
56 // It is initialized by switchGoToolchain.
58 GOTOOLCHAIN string // $GOTOOLCHAIN setting
59 AutoFile string // go.mod or go.work file consulted
60 AutoGoVersion string // go line found in file
61 AutoToolchain string // toolchain line found in file
64 // A TooNewError explains that a module is too new for this version of Go.
65 type TooNewError struct {
68 Toolchain string // for callers if they want to use it, but not printed
71 func (e *TooNewError) Error() string {
73 if Startup.GOTOOLCHAIN != "" && Startup.GOTOOLCHAIN != "auto" {
74 explain = "; GOTOOLCHAIN=" + Startup.GOTOOLCHAIN
76 if Startup.AutoFile != "" && (Startup.AutoGoVersion != "" || Startup.AutoToolchain != "") {
77 explain += fmt.Sprintf("; %s sets ", base.ShortPath(Startup.AutoFile))
78 if Startup.AutoToolchain != "" {
79 explain += "toolchain " + Startup.AutoToolchain
81 explain += "go " + Startup.AutoGoVersion
84 return fmt.Sprintf("%v requires go >= %v (running go %v%v)", e.What, e.GoVersion, Local(), explain)
87 var ErrTooNew = errors.New("module too new")
89 func (e *TooNewError) Is(err error) bool {
90 return err == ErrTooNew
93 // A Switcher provides the ability to switch to a new toolchain in response to TooNewErrors.
94 // See [cmd/go/internal/toolchain.Switcher] for documentation.
95 type Switcher interface {
97 Switch(ctx context.Context)