github.com/bir3/gocompiler@v0.9.2202/src/cmd/gocmd/internal/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 "github.com/bir3/gocompiler/src/cmd/gocmd/internal/base" 9 "context" 10 "errors" 11 "fmt" 12 "strings" 13 ) 14 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. 19 // Examples: 20 // 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 28 // $PATH. 29 return "" 30 } 31 32 var v string 33 if strings.HasPrefix(name, "go") { 34 v = name[2:] 35 } else { 36 return "" 37 } 38 // Some builds use custom suffixes; strip them. 39 if i := strings.IndexAny(v, " \t-"); i >= 0 { 40 v = v[:i] 41 } 42 if !IsValid(v) { 43 return "" 44 } 45 return v 46 } 47 48 func maybeToolchainVersion(name string) string { 49 if IsValid(name) { 50 return name 51 } 52 return FromToolchain(name) 53 } 54 55 // ToolchainMax returns the maximum of x and y interpreted as toolchain names, 56 // compared using Compare(FromToolchain(x), FromToolchain(y)). 57 // If x and y compare equal, Max returns x. 58 func ToolchainMax(x, y string) string { 59 if Compare(FromToolchain(x), FromToolchain(y)) < 0 { 60 return y 61 } 62 return x 63 } 64 65 // Startup records the information that went into the startup-time version switch. 66 // It is initialized by switchGoToolchain. 67 var Startup struct { 68 GOTOOLCHAIN string // $GOTOOLCHAIN setting 69 AutoFile string // go.mod or go.work file consulted 70 AutoGoVersion string // go line found in file 71 AutoToolchain string // toolchain line found in file 72 } 73 74 // A TooNewError explains that a module is too new for this version of Go. 75 type TooNewError struct { 76 What string 77 GoVersion string 78 Toolchain string // for callers if they want to use it, but not printed 79 } 80 81 func (e *TooNewError) Error() string { 82 var explain string 83 if Startup.GOTOOLCHAIN != "" && Startup.GOTOOLCHAIN != "auto" { 84 explain = "; GOTOOLCHAIN=" + Startup.GOTOOLCHAIN 85 } 86 if Startup.AutoFile != "" && (Startup.AutoGoVersion != "" || Startup.AutoToolchain != "") { 87 explain += fmt.Sprintf("; %s sets ", base.ShortPath(Startup.AutoFile)) 88 if Startup.AutoToolchain != "" { 89 explain += "toolchain " + Startup.AutoToolchain 90 } else { 91 explain += "go " + Startup.AutoGoVersion 92 } 93 } 94 return fmt.Sprintf("%v requires go >= %v (running go %v%v)", e.What, e.GoVersion, Local(), explain) 95 } 96 97 var ErrTooNew = errors.New("module too new") 98 99 func (e *TooNewError) Is(err error) bool { 100 return err == ErrTooNew 101 } 102 103 // A Switcher provides the ability to switch to a new toolchain in response to TooNewErrors. 104 // See [cmd/go/internal/toolchain.Switcher] for documentation. 105 type Switcher interface { 106 Error(err error) 107 Switch(ctx context.Context) 108 }