Source file 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  }
    99  

View as plain text