github.com/gopherjs/gopherjs@v1.19.0-beta1.0.20240506212314-27071a8796e4/compiler/version_check.go (about)

     1  //go:build go1.19
     2  
     3  package compiler
     4  
     5  import (
     6  	"fmt"
     7  	"os"
     8  	"os/exec"
     9  	"path/filepath"
    10  	"strconv"
    11  	"strings"
    12  )
    13  
    14  // Version is the GopherJS compiler version string.
    15  const Version = "1.19.0-beta1+go1.19.13"
    16  
    17  // GoVersion is the current Go 1.x version that GopherJS is compatible with.
    18  const GoVersion = 19
    19  
    20  // CheckGoVersion checks the version of the Go distribution
    21  // at goroot, and reports an error if it's not compatible
    22  // with this version of the GopherJS compiler.
    23  func CheckGoVersion(goroot string) error {
    24  	if nvc, err := strconv.ParseBool(os.Getenv("GOPHERJS_SKIP_VERSION_CHECK")); err == nil && nvc {
    25  		return nil
    26  	}
    27  	v, err := goRootVersion(goroot)
    28  	if err != nil {
    29  		return fmt.Errorf("unable to detect Go version for %q: %w", goroot, err)
    30  	}
    31  	if !strings.HasPrefix(v, "go1."+strconv.Itoa(GoVersion)) {
    32  		return fmt.Errorf("GopherJS %s requires a Go 1.%d.x distribution, but found version %s", Version, GoVersion, v)
    33  	}
    34  	return nil
    35  }
    36  
    37  // goRootVersion determines the Go release for the given GOROOT installation.
    38  func goRootVersion(goroot string) (string, error) {
    39  	if b, err := os.ReadFile(filepath.Join(goroot, "VERSION")); err == nil {
    40  		// Standard Go distribution has a VERSION file inside its GOROOT,
    41  		// checking its first line is the most efficient option.
    42  		v, _, _ := strings.Cut(string(b), "\n")
    43  		return v, nil
    44  	}
    45  
    46  	// Fall back to the "go version" command.
    47  	cmd := exec.Command(filepath.Join(goroot, "bin", "go"), "version")
    48  	out, err := cmd.Output()
    49  	if err != nil {
    50  		return "", fmt.Errorf("`go version` command failed: %w", err)
    51  	}
    52  	// Expected output: go version go1.18.1 linux/amd64
    53  	parts := strings.Split(string(out), " ")
    54  	if len(parts) != 4 {
    55  		return "", fmt.Errorf("unexpected `go version` output %q, expected 4 words", string(out))
    56  	}
    57  	return parts[2], nil
    58  }
    59  
    60  // GoRelease does a best-effort to identify the Go release we are building with.
    61  // If unable to determine the precise version for the given GOROOT, falls back
    62  // to the best guess available.
    63  func GoRelease(goroot string) string {
    64  	v, err := goRootVersion(goroot)
    65  	if err == nil {
    66  		// Prefer using the actual version of the GOROOT we are working with.
    67  		return v
    68  	}
    69  
    70  	// Use Go version GopherJS release was tested against as a fallback. By
    71  	// convention, it is included in the GopherJS version after the plus sign.
    72  	parts := strings.Split(Version, "+")
    73  	if len(parts) == 2 {
    74  		return parts[1]
    75  	}
    76  
    77  	// If everything else fails, return just the Go version without patch level.
    78  	return fmt.Sprintf("go1.%d", GoVersion)
    79  }