Source File
gover.go
Belonging Package
internal/gover
// Copyright 2023 The Go Authors. All rights reserved.// Use of this source code is governed by a BSD-style// license that can be found in the LICENSE file.// Package gover implements support for Go toolchain versions like 1.21.0 and 1.21rc1.// (For historical reasons, Go does not use semver for its toolchains.)// This package provides the same basic analysis that golang.org/x/mod/semver does for semver.//// The go/version package should be imported instead of this one when possible.// Note that this package works on "1.21" while go/version works on "go1.21".package goverimport ()// A Version is a parsed Go version: major[.Minor[.Patch]][kind[pre]]// The numbers are the original decimal strings to avoid integer overflows// and since there is very little actual math. (Probably overflow doesn't matter in practice,// but at the time this code was written, there was an existing test that used// go1.99999999999, which does not fit in an int on 32-bit platforms.// The "big decimal" representation avoids the problem entirely.)type Version struct {Major string // decimalMinor string // decimal or ""Patch string // decimal or ""Kind string // "", "alpha", "beta", "rc"Pre string // decimal or ""}// Compare returns -1, 0, or +1 depending on whether// x < y, x == y, or x > y, interpreted as toolchain versions.// The versions x and y must not begin with a "go" prefix: just "1.21" not "go1.21".// Malformed versions compare less than well-formed versions and equal to each other.// The language version "1.21" compares less than the release candidate and eventual releases "1.21rc1" and "1.21.0".func (, string) int {:= Parse():= Parse()if := CmpInt(.Major, .Major); != 0 {return}if := CmpInt(.Minor, .Minor); != 0 {return}if := CmpInt(.Patch, .Patch); != 0 {return}if := cmp.Compare(.Kind, .Kind); != 0 { // "" < alpha < beta < rcreturn}if := CmpInt(.Pre, .Pre); != 0 {return}return 0}// Max returns the maximum of x and y interpreted as toolchain versions,// compared using Compare.// If x and y compare equal, Max returns x.func (, string) string {if Compare(, ) < 0 {return}return}// IsLang reports whether v denotes the overall Go language version// and not a specific release. Starting with the Go 1.21 release, "1.x" denotes// the overall language version; the first release is "1.x.0".// The distinction is important because the relative ordering is//// 1.21 < 1.21rc1 < 1.21.0//// meaning that Go 1.21rc1 and Go 1.21.0 will both handle go.mod files that// say "go 1.21", but Go 1.21rc1 will not handle files that say "go 1.21.0".func ( string) bool {:= Parse()return != Version{} && .Patch == "" && .Kind == "" && .Pre == ""}// Lang returns the Go language version. For example, Lang("1.2.3") == "1.2".func ( string) string {:= Parse()if .Minor == "" || .Major == "1" && .Minor == "0" {return .Major}return .Major + "." + .Minor}// IsValid reports whether the version x is valid.func ( string) bool {return Parse() != Version{}}// Parse parses the Go version string x into a version.// It returns the zero version if x is malformed.func ( string) Version {var Version// Parse major version.var bool.Major, , = cutInt()if ! {return Version{}}if == "" {// Interpret "1" as "1.0.0"..Minor = "0".Patch = "0"return}// Parse . before minor version.if [0] != '.' {return Version{}}// Parse minor version..Minor, , = cutInt([1:])if ! {return Version{}}if == "" {// Patch missing is same as "0" for older versions.// Starting in Go 1.21, patch missing is different from explicit .0.if CmpInt(.Minor, "21") < 0 {.Patch = "0"}return}// Parse patch if present.if [0] == '.' {.Patch, , = cutInt([1:])if ! || != "" {// Note that we are disallowing prereleases (alpha, beta, rc) for patch releases here (x != "").// Allowing them would be a bit confusing because we already have:// 1.21 < 1.21rc1// But a prerelease of a patch would have the opposite effect:// 1.21.3rc1 < 1.21.3// We've never needed them before, so let's not start now.return Version{}}return}// Parse prerelease.:= 0for < len() && ([] < '0' || '9' < []) {if [] < 'a' || 'z' < [] {return Version{}}++}if == 0 {return Version{}}.Kind, = [:], [:]if == "" {return}.Pre, , = cutInt()if ! || != "" {return Version{}}return}// cutInt scans the leading decimal number at the start of x to an integer// and returns that value and the rest of the string.func ( string) (, string, bool) {:= 0for < len() && '0' <= [] && [] <= '9' {++}if == 0 || [0] == '0' && != 1 { // no digits or unnecessary leading zeroreturn "", "", false}return [:], [:], true}// CmpInt returns cmp.Compare(x, y) interpreting x and y as decimal numbers.// (Copied from golang.org/x/mod/semver's compareInt.)func (, string) int {if == {return 0}if len() < len() {return -1}if len() > len() {return +1}if < {return -1} else {return +1}}// DecInt returns the decimal string decremented by 1, or the empty string// if the decimal is all zeroes.// (Copied from golang.org/x/mod/module's decDecimal.)func ( string) string {// Scan right to left turning 0s to 9s until you find a digit to decrement.:= []byte():= len() - 1for ; >= 0 && [] == '0'; -- {[] = '9'}if < 0 {// decimal is all zerosreturn ""}if == 0 && [] == '1' && len() > 1 {= [1:]} else {[]--}return string()}
The pages are generated with Golds v0.7.6. (GOOS=linux GOARCH=amd64)