semver

package module
v3.2.1 Latest Latest
Warning

This package is not in the latest version of its module.

Go to latest
Published: Dec 31, 2019 License: BSD-3-Clause Imports: 4 Imported by: 0

README

Semantic Versioning for Golang

GoDoc

A library for parsing and processing of Versions and Ranges in:

  • Semantic Versioning (semver) v2.0.0 notation
    • used by npmjs.org, pypi.org…
  • Gentoo's ebuild format
  • The fastest implementation, and the one that'll actually parse all semver variants correctly and without errors.
  • Sorting is in O(n).

Does not rely on regular expressions neither does it use package reflection.

$ sed -i -e 's@ignore@3rdparty@g' *_test.go
$ go test -tags 3rdparty -run=XXX -benchmem -bench=.

BenchmarkLibraryOne_NewVersion-24        2000000   815 ns/op   145 B/op   4 allocs/op
BenchmarkLibraryTwo_Make-24              4000000   300 ns/op    94 B/op   3 allocs/op
Benchmark_NewVersion-24                 30000000    37.2 ns/op   0 B/op   0 allocs/op ←

BenchmarkLibraryOne_NewConstraint-24      200000  6350 ns/op  2096 B/op  18 allocs/op
BenchmarkLibraryTwo_ParseRange-24        1000000  1440 ns/op   480 B/op  13 allocs/op
BenchmarkSemverNewRange-24              10000000   120 ns/op     0 B/op   0 allocs/op ←

BenchmarkLibraryOne_Compare-24           1000000  1005 ns/op   395 B/op  12 allocs/op
BenchmarkLibraryTwo_Compare-24         100000000    20.2 ns/op   0 B/op   0 allocs/op
BenchmarkSemverCompare-24              200000000     6.88 ns/op  0 B/op   0 allocs/op ←

Licensed under a BSD-style license.

Usage

Using go modules you'd just:

import "blitznote.com/src/semver/v3"

… or, with older versions of Go leave out the version suffix /v… and:

$ dep ensure --add blitznote.com/src/semver@^3

After which you can use the module as usual, like this:

v1 := semver.MustParse("1.2.3-beta")
v2 := semver.MustParse("2.0.0-alpha20140805.456-rc3+build1800")
v1.Less(v2) // true

r1, _ := NewRange("~1.2")
r1.Contains(v1)      // true
r1.IsSatisfiedBy(v1) // false (pre-releases don't satisfy)

Also check its go.dev listing and Gentoo Linux Ebuild File Format, Gentoo's notation of dependencies.

Please Note

It is, ordered from lowest to highest:

alpha < beta < pre < rc < (no release type/»common«) < r (revision) < p

Therefore it is:

Version("1.0.0-pre1") < Version("1.0.0") < Version("1.0.0-p1")
Limitations

Version 2 no longer supports dot-tag notation. That is, 1.8.rc2 will be rejected, valid are 1.8rc2 and 1.8-rc2.

Contribute

Pull requests are welcome.

For anything written in Assembly, please contribute your implementation for one architecture only at first. We'll work with this and once it's in, follow up with more if you like.

Please add your name and email address to a file AUTHORS and/or CONTRIBUTORS.
Thanks!

Documentation

Overview

Package semver contains types and functions for parsing of Versions and (Version-)Ranges.

Example (Range)
v1 := semver.MustParse("1.2.3-beta")
r1, _ := semver.NewRange([]byte("~1.2"))

fmt.Println(r1.Contains(v1))
fmt.Println(r1.IsSatisfiedBy(v1)) // pre-releases don't satisfy
Output:

true
false
Example (Version)
v1 := semver.MustParse("1.2.3-beta")
v2 := semver.MustParse("2.0.0-alpha20140805.456-rc3+build1800")

fmt.Println(v1.Less(v2))
Output:

true

Index

Examples

Constants

This section is empty.

Variables

This section is empty.

Functions

func Compare

func Compare(a, b Version) int

Compare computes the difference between two Versions and returns its signum.

1  if a > b
0  if a == b
-1 if a < b

The 'build' is not compared.

Example
v1 := semver.MustParse("v1")
v2 := semver.MustParse("v2.0")
v3 := semver.MustParse("v3.0.0")

fmt.Println("Compare", v3, v2, "=", semver.Compare(v3, v2))
fmt.Println("Compare", v2, v2, "=", semver.Compare(v2, v2))
fmt.Println("Compare", v1, v2, "=", semver.Compare(v1, v2))
Output:

Compare 3.0.0 2.0.0 = 1
Compare 2.0.0 2.0.0 = 0
Compare 1.0.0 2.0.0 = -1

func Satisfies

func Satisfies(aVersion, aRange string) (bool, error)

Satisfies is a convenience function for former NodeJS developers, and works on two strings.

Please see Range's IsSatisfiedBy for details.

Types

type InvalidStringValue

type InvalidStringValue string

InvalidStringValue instances are returned as error on any conversion failure.

func (InvalidStringValue) Error

func (e InvalidStringValue) Error() string

Error implements the error interface.

func (InvalidStringValue) IsInvalid

func (e InvalidStringValue) IsInvalid() bool

IsInvalid satisfies a function IsInvalid(). This is used by some input validator packages.

type Range

type Range struct {
	// contains filtered or unexported fields
}

Range is a subset of the universe of Versions: It can have a lower and upper boundary. For example, "1.2–2.0" is such a Range, with two boundaries.

func NewRange

func NewRange(str []byte) (Range, error)

NewRange translates into a Range.

func (Range) Contains

func (r Range) Contains(v Version) bool

Contains returns true if a Version is inside this Range.

If in doubt use IsSatisfiedBy.

Example (First)
v := semver.MustParse("1.4.3")
r, _ := semver.NewRange([]byte("^1.2"))

fmt.Println(r.Contains(v))
Output:

true
Example (Prerelases)
v := semver.MustParse("1.4.3-beta")
r, _ := semver.NewRange([]byte("1.2 <2.0.0"))

fmt.Println(r.Contains(v))
Output:

true
Example (Second)
v := semver.MustParse("1.4.3")
r, _ := semver.NewRange([]byte("1.2 <2.0.0"))

fmt.Println(r.Contains(v))
Output:

true

func (Range) GetLowerBoundary

func (r Range) GetLowerBoundary() *Version

GetLowerBoundary gets you the lower (left) boundary.

Example
r, _ := semver.NewRange([]byte("^1.2"))
fmt.Println(*r.GetLowerBoundary())
Output:

1.2.0

func (Range) GetUpperBoundary

func (r Range) GetUpperBoundary() *Version

GetUpperBoundary gets you the high (right) boundary.

Example (First)
r, _ := semver.NewRange([]byte("1.2 <2.0.0"))
fmt.Println(*r.GetUpperBoundary())
Output:

2.0.0
Example (Second)
r, _ := semver.NewRange([]byte("~1.2.3"))
fmt.Println(*r.GetUpperBoundary())
Output:

1.3.0

func (Range) IsSatisfiedBy

func (r Range) IsSatisfiedBy(v Version) bool

IsSatisfiedBy works like Contains, but rejects pre-releases if neither of the bounds is a pre-release.

Use this in the context of pulling in packages because it follows the spirit of §9 SemVer. Also see https://github.com/npm/node-semver/issues/64

Example (Full)
v := semver.MustParse("1.2.3")
r, _ := semver.NewRange([]byte("~1.2"))

fmt.Println(r.IsSatisfiedBy(v))
Output:

true
Example (Prerelases)
// Unlike with Contains, this won't select prereleases.
pre := semver.MustParse("1.2.3-beta")
r, _ := semver.NewRange([]byte("~1.2"))

fmt.Println(r.IsSatisfiedBy(pre))
Output:

false

type Version

type Version struct {
	// contains filtered or unexported fields
}

Version represents a version: Columns consisting of up to four unsigned integers (1.2.4.99) optionally further divided into 'release' and 'specifier' (1.2-634.0-99.8).

func MustParse

func MustParse(str string) Version

MustParse is NewVersion for strings, and panics on errors.

Use this in tests or with constants, e. g. whenever you control the input.

This is a convenience function for a cloud plattform provider.

Example
v := semver.MustParse("v1.14")
fmt.Println(v)
Output:

1.14.0

func NewVersion

func NewVersion(str []byte) (Version, error)

NewVersion translates the given string, which must be free of whitespace, into a single Version.

An io.Reader will give you []byte, hence this (and most functions internally) works on []byte to have as few conversion as possible.

Example
for _, str := range []string{"v1.14", "6.0.2.1", "14b6"} {
	v, err := semver.NewVersion([]byte(str))
	fmt.Println(v, err)
}
Output:

1.14.0 <nil>
6.0.2.1 <nil>
14.0.0 Given string does not resemble a Version

func (Version) Bytes

func (t Version) Bytes() []byte

Bytes returns a slice with the minimal human-readable representation of this Version.

Unlike String(), which returns a minimum of columns, this will conserve space at the expense of legibility. In other words, `len(v.Bytes()) ≤ len(v.String())`.

Example (First)
v := semver.MustParse("1.0")
fmt.Println(v.Bytes())
Output:

[49]
Example (Minimal)
v := semver.MustParse("1.13beta")

fmt.Println("Bytes()  =", string(v.Bytes()))
fmt.Println("String() =", v.String())
Output:

Bytes()  = 1.13-beta
String() = 1.13.0-beta
Example (Second)
v := semver.MustParse("4.8")
fmt.Println(v.Bytes())
Output:

[52 46 56]

func (Version) IsAPreRelease

func (t Version) IsAPreRelease() bool

IsAPreRelease is used to discriminate pre-releases.

Example
v, pre := semver.MustParse("1.12"), semver.MustParse("1.13beta")

fmt.Println(v, "is a pre-release:", v.IsAPreRelease())
fmt.Println(pre, "is a pre-release:", pre.IsAPreRelease())
Output:

1.12.0 is a pre-release: false
1.13.0-beta is a pre-release: true

func (Version) Less

func (t Version) Less(o Version) bool

Less is a convenience function for sorting.

Example
l, r := semver.MustParse("v2"), semver.MustParse("v3")
fmt.Println(l.Less(r), ",", l, "is 'less' than", r)

l, r = semver.MustParse("v1+build7"), semver.MustParse("v1+build9")
fmt.Println(l.Less(r), ",", l, "is 'less' than", r)
Output:

true , 2.0.0 is 'less' than 3.0.0
true , 1.0.0+build7 is 'less' than 1.0.0+build9

func (Version) LimitedEqual

func (t Version) LimitedEqual(o Version) bool

LimitedEqual returns true if two versions share the same: prefix, which is the "actual version", (pre-)release type, and (pre-)release version. The exception are patch-levels, which are always equal.

Use this, for example, to tell a beta from a regular version; or to accept a patched version as regular version.

A thing confusing but convention is to read this from right to left.

Example (First)
// The version prefix does, but the first pre-release type does not match.
pre := semver.MustParse("1.0.0-pre")
rc := semver.MustParse("1.0.0-rc")

fmt.Println(pre.LimitedEqual(rc))
Output:

false
Example (Second)
// The difference is beyond LimitedEqual's cutoff, so these "equal".
a := semver.MustParse("1.0.0-beta-pre3")
b := semver.MustParse("1.0.0-beta-pre5")

fmt.Println(a.LimitedEqual(b))
Output:

true
Example (Third)
regular := semver.MustParse("1.0.0")
patched := semver.MustParse("1.0.0-p1")

// A patched version supposedly does more, so is more than; and its unequal.
fmt.Println(patched.LimitedEqual(regular))
// This will work because the regular version is a subset is in its subset.
fmt.Println(regular.LimitedEqual(patched))
Output:

false
true

func (Version) Major

func (t Version) Major() int

Major returns the major of a version.

Example
v := semver.MustParse("v1.2.3")
fmt.Println(v.Major())
Output:

1

func (Version) MarshalBinary

func (t Version) MarshalBinary() ([]byte, error)

MarshalBinary implements the encoding.BinaryMarshaler interface.

Anecdotically, encoders for binary protocols use this.

func (Version) MarshalJSON

func (t Version) MarshalJSON() ([]byte, error)

MarshalJSON implements the json.Marshaler interface.

func (Version) MarshalText

func (t Version) MarshalText() ([]byte, error)

MarshalText implements the encoding.TextMarshaler interface.

Anecdotically, anything that writes XML will use this.

func (Version) Minor

func (t Version) Minor() int

Minor returns the minor of a version.

Example
v := semver.MustParse("v1.2.3")
fmt.Println(v.Minor())
Output:

2

func (Version) NextVersions deprecated

func (t Version) NextVersions(minReleaseType int, numberedPre bool) []*Version

NextVersions returns a list of possible next versions after t. For each of the three version points, pre-releases are given as options starting with the minimum release type (-4 <= 0), and those release types are numbered if numberedPre is true. Release types:

alpha: -4
beta:  -3
pre:   -2
rc:    -1
common: 0

Thus, if you don't want any pre-release options, set minReleaseType to 0.

Deprecated: This is a legacy method for the Caddyserver's build infrastructure. Do not rely on it, they are free to~ and can change it anytime.

func (*Version) Parse deprecated

func (t *Version) Parse(str string) error

Parse reads a string into the given version, overwriting any existing values.

Deprecated: Use the idiomatic UnmarshalText instead.

func (Version) Patch

func (t Version) Patch() int

Patch returns the patch of a version.

Example
v := semver.MustParse("v1.2.3")
fmt.Println(v.Patch())
Output:

3

func (*Version) Scan

func (t *Version) Scan(src interface{}) error

Scan implements the sql.Scanner interface.

Example
a, b, c := new(semver.Version), new(semver.Version), new(semver.Version)
errA := a.Scan("5.5.65")
errB := b.Scan(int64(12))
errC := c.Scan(-1)

fmt.Println(a, errA)
fmt.Println(b, errB)
fmt.Println(c, errC)
Output:

5.5.65 <nil>
12.0.0 <nil>
0.0.0 Cannot read this type into a Version

func (Version) String

func (t Version) String() string

String returns the string representation of t.

Anecdotically, fmt.Println will use this.

Example
str := "v2.1"
v := semver.MustParse(str)
fmt.Println(str, "is", v.String(), "but as Bytes():", string(v.Bytes()))
Output:

v2.1 is 2.1.0 but as Bytes(): 2.1

func (*Version) UnmarshalBinary

func (t *Version) UnmarshalBinary(b []byte) error

UnmarshalBinary implements the encoding.BinaryUnmarshaler interface.

func (*Version) UnmarshalJSON

func (t *Version) UnmarshalJSON(b []byte) error

UnmarshalJSON implements the json.Unmarshaler interface.

func (*Version) UnmarshalText

func (t *Version) UnmarshalText(b []byte) error

UnmarshalText implements the encoding.TextUnmarshaler interface.

func (Version) Value deprecated

func (t Version) Value() (interface{}, error)

Value implements the driver.Valuer interface, as found in database/sql.

Deprecated: Use string(Version) instead.

type VersionPtrs

type VersionPtrs []*Version

VersionPtrs represents an array with elements derived from~ but smaller than Versions. Use this a proxy for sorting of large collections of Versions, to minimize memory moves.

func (VersionPtrs) Len

func (p VersionPtrs) Len() int

Len implements the sort.Interface.

func (VersionPtrs) Less

func (p VersionPtrs) Less(i, j int) bool

Less implements the sort.Interface.

func (VersionPtrs) Sort

func (p VersionPtrs) Sort()

Sort reorders the pointers so that the Versions appear in ascending order.

For that it will use optimized algorithms usually less time-complex than the generic ones found in package 'Sort'. Specifically, variants of radix sort expected to run in O(n).

Allocates a copy of VersionPtrs.

func (VersionPtrs) Swap

func (p VersionPtrs) Swap(i, j int)

Swap implements the sort.Interface.

Jump to

Keyboard shortcuts

? : This menu
/ : Search site
f or F : Jump to
y or Y : Canonical URL