github.com/go-asm/go@v1.21.1-0.20240213172139-40c5ead50c48/cmd/go/gover/toolchain.go (about) 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. 4 5 package gover 6 7 import ( 8 "context" 9 "errors" 10 "fmt" 11 "strings" 12 13 "github.com/go-asm/go/cmd/go/base" 14 ) 15 16 // FromToolchain returns the Go version for the named toolchain, 17 // derived from the name itself (not by running the toolchain). 18 // A toolchain is named "goVERSION". 19 // A suffix after the VERSION introduced by a -, space, or tab is removed. 20 // Examples: 21 // 22 // FromToolchain("go1.2.3") == "1.2.3" 23 // FromToolchain("go1.2.3-bigcorp") == "1.2.3" 24 // FromToolchain("invalid") == "" 25 func FromToolchain(name string) string { 26 if strings.ContainsAny(name, "\\/") { 27 // The suffix must not include a path separator, since that would cause 28 // exec.LookPath to resolve it from a relative directory instead of from 29 // $PATH. 30 return "" 31 } 32 33 var v string 34 if strings.HasPrefix(name, "go") { 35 v = name[2:] 36 } else { 37 return "" 38 } 39 // Some builds use custom suffixes; strip them. 40 if i := strings.IndexAny(v, " \t-"); i >= 0 { 41 v = v[:i] 42 } 43 if !IsValid(v) { 44 return "" 45 } 46 return v 47 } 48 49 func maybeToolchainVersion(name string) string { 50 if IsValid(name) { 51 return name 52 } 53 return FromToolchain(name) 54 } 55 56 // ToolchainMax returns the maximum of x and y interpreted as toolchain names, 57 // compared using Compare(FromToolchain(x), FromToolchain(y)). 58 // If x and y compare equal, Max returns x. 59 func ToolchainMax(x, y string) string { 60 if Compare(FromToolchain(x), FromToolchain(y)) < 0 { 61 return y 62 } 63 return x 64 } 65 66 // Startup records the information that went into the startup-time version switch. 67 // It is initialized by switchGoToolchain. 68 var Startup struct { 69 GOTOOLCHAIN string // $GOTOOLCHAIN setting 70 AutoFile string // go.mod or go.work file consulted 71 AutoGoVersion string // go line found in file 72 AutoToolchain string // toolchain line found in file 73 } 74 75 // A TooNewError explains that a module is too new for this version of Go. 76 type TooNewError struct { 77 What string 78 GoVersion string 79 Toolchain string // for callers if they want to use it, but not printed 80 } 81 82 func (e *TooNewError) Error() string { 83 var explain string 84 if Startup.GOTOOLCHAIN != "" && Startup.GOTOOLCHAIN != "auto" { 85 explain = "; GOTOOLCHAIN=" + Startup.GOTOOLCHAIN 86 } 87 if Startup.AutoFile != "" && (Startup.AutoGoVersion != "" || Startup.AutoToolchain != "") { 88 explain += fmt.Sprintf("; %s sets ", base.ShortPath(Startup.AutoFile)) 89 if Startup.AutoToolchain != "" { 90 explain += "toolchain " + Startup.AutoToolchain 91 } else { 92 explain += "go " + Startup.AutoGoVersion 93 } 94 } 95 return fmt.Sprintf("%v requires go >= %v (running go %v%v)", e.What, e.GoVersion, Local(), explain) 96 } 97 98 var ErrTooNew = errors.New("module too new") 99 100 func (e *TooNewError) Is(err error) bool { 101 return err == ErrTooNew 102 } 103 104 // A Switcher provides the ability to switch to a new toolchain in response to TooNewErrors. 105 // See [github.com/go-asm/go/cmd/go/toolchain.Switcher] for documentation. 106 type Switcher interface { 107 Error(err error) 108 Switch(ctx context.Context) 109 }