This modifies the semver handling to specifically use uint32 instead of architecture-dependent uint so bounds checking is consistent across architectures and only needs to be done in one place.
162 lines
4.9 KiB
Go
162 lines
4.9 KiB
Go
// Copyright (c) 2013-2014 The btcsuite developers
|
|
// Copyright (c) 2015-2021 The Decred developers
|
|
// Use of this source code is governed by an ISC
|
|
// license that can be found in the LICENSE file.
|
|
|
|
// Package version provides a single location to house the version information
|
|
// for dcrd and other utilities provided in the same repository.
|
|
package version
|
|
|
|
import (
|
|
"bytes"
|
|
"fmt"
|
|
"regexp"
|
|
"strconv"
|
|
"strings"
|
|
)
|
|
|
|
const (
|
|
// semanticAlphabet defines the allowed characters for the pre-release and
|
|
// build metadata portions of a semantic version string.
|
|
semanticAlphabet = "0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz-."
|
|
)
|
|
|
|
// semverRE is a regular expression used to parse a semantic version string into
|
|
// its constituent parts.
|
|
var semverRE = regexp.MustCompile(`^(0|[1-9]\d*)\.(0|[1-9]\d*)\.(0|[1-9]\d*)` +
|
|
`(?:-((?:0|[1-9]\d*|\d*[a-zA-Z-][0-9a-zA-Z-]*)(?:\.(?:0|[1-9]\d*|\d*` +
|
|
`[a-zA-Z-][0-9a-zA-Z-]*))*))?(?:\+([0-9a-zA-Z-]+(?:\.[0-9a-zA-Z-]+)*))?$`)
|
|
|
|
// These variables define the application version and follow the semantic
|
|
// versioning 2.0.0 spec (https://semver.org/).
|
|
var (
|
|
// Note for maintainers:
|
|
//
|
|
// The expected process for setting the version in releases is as follows:
|
|
// - Create a release branch of the form 'release-vMAJOR.MINOR'
|
|
// - Modify the Version variable below on that branch to:
|
|
// - Remove the pre-release portion
|
|
// - Set the build metadata to 'release.local'
|
|
// - Update the Version variable below on the master branch to the next
|
|
// expected version while retaining a pre-release of 'pre'
|
|
//
|
|
// These steps ensure that building from source produces versions that are
|
|
// distinct from reproducible builds that override the Version via linker
|
|
// flags.
|
|
|
|
// Version is the application version per the semantic versioning 2.0.0 spec
|
|
// (https://semver.org/).
|
|
//
|
|
// It is defined as a variable so it can be overridden during the build
|
|
// process with:
|
|
// '-ldflags "-X github.com/decred/dcrd/internal/version.Version=fullsemver"'
|
|
// if needed.
|
|
//
|
|
// It MUST be a full semantic version per the semantic versioning spec or
|
|
// the package will panic at runtime. Of particular note is the pre-release
|
|
// and build metadata portions MUST only contain characters from
|
|
// semanticAlphabet.
|
|
Version = "1.7.0-pre"
|
|
|
|
// NOTE: The following values are set via init by parsing the above Version
|
|
// string.
|
|
|
|
// These fields are the individual semantic version components that define
|
|
// the application version.
|
|
Major uint32
|
|
Minor uint32
|
|
Patch uint32
|
|
PreRelease string
|
|
BuildMetadata string
|
|
)
|
|
|
|
// parseUint32 converts the passed string to an unsigned integer or returns an
|
|
// error if it is invalid.
|
|
func parseUint32(s string, fieldName string) (uint32, error) {
|
|
val, err := strconv.ParseUint(s, 10, 32)
|
|
if err != nil {
|
|
return 0, fmt.Errorf("malformed semver %s: %w", fieldName, err)
|
|
}
|
|
return uint32(val), err
|
|
}
|
|
|
|
// checkSemString returns an error if the passed string contains characters that
|
|
// are not in the provided alphabet.
|
|
func checkSemString(s, alphabet, fieldName string) error {
|
|
for _, r := range s {
|
|
if !strings.ContainsRune(alphabet, r) {
|
|
return fmt.Errorf("malformed semver %s: %q invalid", fieldName, r)
|
|
}
|
|
}
|
|
return nil
|
|
}
|
|
|
|
// parseSemVer parses various semver components from the provided string.
|
|
func parseSemVer(s string) (uint32, uint32, uint32, string, string, error) {
|
|
// Parse the various semver component from the version string via a regular
|
|
// expression.
|
|
m := semverRE.FindStringSubmatch(s)
|
|
if m == nil {
|
|
err := fmt.Errorf("malformed version string %q: does not conform to "+
|
|
"semver specification", s)
|
|
return 0, 0, 0, "", "", err
|
|
}
|
|
|
|
major, err := parseUint32(m[1], "major")
|
|
if err != nil {
|
|
return 0, 0, 0, "", "", err
|
|
}
|
|
|
|
minor, err := parseUint32(m[2], "minor")
|
|
if err != nil {
|
|
return 0, 0, 0, "", "", err
|
|
}
|
|
|
|
patch, err := parseUint32(m[3], "patch")
|
|
if err != nil {
|
|
return 0, 0, 0, "", "", err
|
|
}
|
|
|
|
preRel := m[4]
|
|
err = checkSemString(preRel, semanticAlphabet, "pre-release")
|
|
if err != nil {
|
|
return 0, 0, 0, s, s, err
|
|
}
|
|
|
|
build := m[5]
|
|
err = checkSemString(build, semanticAlphabet, "buildmetadata")
|
|
if err != nil {
|
|
return 0, 0, 0, s, s, err
|
|
}
|
|
|
|
return major, minor, patch, preRel, build, nil
|
|
}
|
|
|
|
func init() {
|
|
var err error
|
|
Major, Minor, Patch, PreRelease, BuildMetadata, err = parseSemVer(Version)
|
|
if err != nil {
|
|
panic(err)
|
|
}
|
|
}
|
|
|
|
// String returns the application version as a properly formed string per the
|
|
// semantic versioning 2.0.0 spec (https://semver.org/).
|
|
func String() string {
|
|
return Version
|
|
}
|
|
|
|
// NormalizeString returns the passed string stripped of all characters which
|
|
// are not valid according to the semantic versioning guidelines for pre-release
|
|
// and build metadata strings. In particular they MUST only contain characters
|
|
// in semanticAlphabet.
|
|
func NormalizeString(str string) string {
|
|
var result bytes.Buffer
|
|
for _, r := range str {
|
|
if strings.ContainsRune(semanticAlphabet, r) {
|
|
result.WriteRune(r)
|
|
}
|
|
}
|
|
return result.String()
|
|
}
|