]> Cypherpunks.ru repositories - gostls13.git/blob - src/cmd/go/internal/gover/toolchain.go
a24df98168056b771a8eca885349e845f89f7621
[gostls13.git] / src / cmd / go / internal / gover / toolchain.go
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         "cmd/go/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 // Startup records the information that went into the startup-time version switch.
56 // It is initialized by switchGoToolchain.
57 var Startup struct {
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
62 }
63
64 // A TooNewError explains that a module is too new for this version of Go.
65 type TooNewError struct {
66         What      string
67         GoVersion string
68         Toolchain string // for callers if they want to use it, but not printed
69 }
70
71 func (e *TooNewError) Error() string {
72         var explain string
73         if Startup.GOTOOLCHAIN != "" && Startup.GOTOOLCHAIN != "auto" {
74                 explain = "; GOTOOLCHAIN=" + Startup.GOTOOLCHAIN
75         }
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
80                 } else {
81                         explain += "go " + Startup.AutoGoVersion
82                 }
83         }
84         return fmt.Sprintf("%v requires go >= %v (running go %v%v)", e.What, e.GoVersion, Local(), explain)
85 }
86
87 var ErrTooNew = errors.New("module too new")
88
89 func (e *TooNewError) Is(err error) bool {
90         return err == ErrTooNew
91 }
92
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 {
96         Error(err error)
97         Switch(ctx context.Context)
98 }