semver

package module
v0.1.3 Latest Latest
Warning

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

Go to latest
Published: Oct 2, 2021 License: BSD-3-Clause Imports: 3 Imported by: 1

README

semver

🦔 semver and constraint parsing with a focus on performance

Go Reference GitHub tag Build Status BSD license codecov Go Report Card



semver provides semantic version and constraint parsing, comparison, and testing.

There are many semver packages. This one aims to be the fastest at parsing and comparing values, with low memory usage. On average, this package is roughly ten times faster at parsing versions and constraints than the popular Masterminds/semver and hashicorp/go-version packages. View more stats in the benchmarks.

Versions can be compared with one another to determine which is newer. Constraints specify inclusions and exclusions of semver ranges that a given version must satisfy. Typically, constraints are used when expressing a dependency.

Quick start

import (
  "log"

  "github.com/jbowes/semver"
)

func main() {
  // Parse a version. Two versions can also be Compare()ed
  ver, err := semver.Parse("1.0.2")
  if err != nil {
    log.Fatal("invalid semver")
  }

  // Parse a Constraint, typically used to express dependency
  constr, err := semver.ParseConstraint(">=1.0.0")
  if err != nil {
    log.Fatalln("invalid constraint")
  }

  // Check if a Version satisfies a Constraint
  if constr.Check(ver) {
    log.Printf("%s satisfies constraint %s\n", ver, constr)
  } else {
    log.Printf("%s does not satisfy constraint %s\n", ver, constr)
  }
}

For more usage and examples, see the GoDoc Reference

Contributing

I would love your help!

semver is still a work in progress. You can help by:

  • Opening a pull request to resolve an open issue.
  • Adding a feature or enhancement of your own! If it might be big, please open an issue first so we can discuss it.
  • Improving this README or adding other documentation to semver.
  • Letting me know if you're using semver.

Documentation

Overview

Package semver provides semantic version and constraint parsing, comparison, and testing.

There are many semver packages. This one aims to be the fastest at parsing and comparing values, with low memory usage.

Versions can be compared with one another to determine which is newer. Constraints specify inclusions and exclusions of semver ranges that a given version must satisfy. Typically, constraints are used when expressing a dependency.

Parsing of semver values, and comparison of them, strictly follows the rules outlined in Semantic Versioning 2.0.0 (https://semver.org). Constraint parsing and testing follows the syntax and semantics of npm version specifiers (https://semver.npmjs.com/). This behaviour is only what exists now; feature requests or contributions are welcome to expand on it!

Normalized Constraint forms

Internally during parsing, and when returning string representations, Constraints are normalized in their representation.

Rules for normalization:

  • replace the empty match-any value "" with *
  • replace any whitespace with a single space
  • surround `||` with a single space on each side, if missing
  • remove '='.
  • replace partial semver (2.0) with wildcard version (2.0.x)
  • replace partial wildcard (2.x) with full wildcard (2.x.x) special case: leave full wildcard (*, x, X) as-is, but convert to *.
  • for wildcard with leading op (including tilde and semver), replace wildcards with 0.
  • replace remaining wildcard semver (including previous partial) with >= and < clauses (eg 2.x.x becomes >=2.0.0 < 3.0.0)
  • replace tilde with >= and < clauses (eg ~2.1.1 becomes >=2.1.1 < 2.2.0)
  • replace caret with >= and < clauses (eg ^2.1.1 becomes >=2.1.1 < 3.0.0)
  • replace hyphenated ranges with >= and <= clauses (eg 2.1.0 - 2.2.0 becomes >=2.1.0 <=2.2.0)

Normalized constraints are not canonical. Two Constraints can have different normalized forms but still be equivalent.

Example
package main

import (
	"fmt"

	"github.com/jbowes/semver"
)

func main() {
	v, err := semver.Parse("1.2.1")
	if err != nil {
		fmt.Println("invalid semver!")
	}

	c, err := semver.ParseConstraint(">=1.1.9 <2.0.0")
	if err != nil {
		fmt.Println("invalid constraint!")
	}

	if c.Check(v) {
		fmt.Printf("%s satisfies %s\n", v, c)
	} else {
		fmt.Printf("%s does not satisfy %s\n", v, c)
	}

}
Output:
1.2.1 satisfies >=1.1.9 <2.0.0

Index

Examples

Constants

This section is empty.

Variables

This section is empty.

Functions

This section is empty.

Types

type Constraint

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

Constraint is a constraint specifier on a set of versions. Constraint specifiers follow the syntax (for now) of npm: https://semver.npmjs.com/

func ParseConstraint

func ParseConstraint(con string) (*Constraint, error)

ParseConstraint returns the version constraint(s) parsed from the string con. If con is not a valid version constraint, an error is returned.

Example
package main

import (
	"fmt"

	"github.com/jbowes/semver"
)

func main() {
	c, err := semver.ParseConstraint(">=1.1.9 <2.0.0")
	if err != nil {
		fmt.Println("invalid constraint!")
	}

	fmt.Println(c)

}
Output:
>=1.1.9 <2.0.0
Example (Normalized)

Internally, and when String()ified, Constraints are normalized.

package main

import (
	"fmt"

	"github.com/jbowes/semver"
)

func main() {
	c, err := semver.ParseConstraint("~1.2.7")
	if err != nil {
		fmt.Println("invalid constraint!")
	}

	fmt.Println(c)

}
Output:
>=1.2.7 <1.3.0

func (*Constraint) Check

func (c *Constraint) Check(v *Version) bool

Check returns a bool indicating if Version v satisfies Constraint c.

Example (Or)

Multiple constraints are ANDed together, and may be explicitly ORed.

package main

import (
	"fmt"

	"github.com/jbowes/semver"
)

func main() {
	c, err := semver.ParseConstraint("~1.2.7 || 2.0.0")
	if err != nil {
		fmt.Println("invalid constraint!")
	}

	v1, err := semver.Parse("1.2.8")
	if err != nil {
		fmt.Println("invalid version!")
	}

	v2, err := semver.Parse("2.0.0")
	if err != nil {
		fmt.Println("invalid version!")
	}

	v3, err := semver.Parse("1.3.0")
	if err != nil {
		fmt.Println("invalid version!")
	}

	fmt.Println(c.Check(v1))
	fmt.Println(c.Check(v2))
	fmt.Println(c.Check(v3))

}
Output:
true
true
false
Example (Wildcard)
package main

import (
	"fmt"

	"github.com/jbowes/semver"
)

func main() {
	c, err := semver.ParseConstraint("*")
	if err != nil {
		fmt.Println("invalid constraint!")
	}

	v1, err := semver.Parse("1.2.8")
	if err != nil {
		fmt.Println("invalid version!")
	}

	fmt.Println(c.Check(v1))

}
Output:
true

func (*Constraint) String

func (c *Constraint) String() string

String returns the normalized string representation of a Constraint.

type Version

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

Version is a valid semver version as defined by https://semver.org

func Parse

func Parse(ver string) (*Version, error)

Parse returns the semver version parsed from the string ver. If ver is not a valid semver version, an error is returned.

Example
package main

import (
	"fmt"

	"github.com/jbowes/semver"
)

func main() {
	v, err := semver.Parse("1.2.0-rc.0+happysunshine")
	if err != nil {
		fmt.Println("invalid semver!")
	}

	fmt.Println(v)
}
Output:
1.2.0-rc.0+happysunshine

func (*Version) Compare

func (v *Version) Compare(other *Version) int

Compare returns an integer comparing semver Version v with other, following the rules outlined in the semver spec at https://semver.org/#spec-item-11

If v has higher precedence than other, 1 is returned. If other has higher precedence, -1 is returned. If the two versions are equal, zero is returned. A nil Version has lower precedence than a non-nil version. Two nil versions have the same precedence.

Example
package main

import (
	"fmt"

	"github.com/jbowes/semver"
)

func main() {
	v1, err := semver.Parse("1.2.0-rc.0+happysunshine")
	if err != nil {
		fmt.Println("invalid semver!")
	}

	v2, err := semver.Parse("1.4.0")
	if err != nil {
		fmt.Println("invalid semver!")
	}

	fmt.Println(v1.Compare(v2))
}
Output:
-1
Example (BuildField)

In accordance with the semver spec, build fields are ignored for determining version precedence.

package main

import (
	"fmt"

	"github.com/jbowes/semver"
)

func main() {
	v1, err := semver.Parse("1.0.0+somebuild")
	if err != nil {
		fmt.Println("invalid semver!")
	}

	v2, err := semver.Parse("1.0.0+builds.are.ignored.for.comparison")
	if err != nil {
		fmt.Println("invalid semver!")
	}

	fmt.Println(v1.Compare(v2))
}
Output:
0

func (*Version) Prerelease added in v0.1.0

func (v *Version) Prerelease() string

Prerelease returns the prerelease portion of a Version. If the version had no prerelease or is nil, the empty string is returned.

Note: This method is considered experimental, and may be removed or changed before v1.0.0

func (*Version) String

func (v *Version) String() string

String returns the string representation of the Version.

Notes

Bugs

  • Multiple prerelease versions are not compared within a constraint, only the first.

  • 1.x.3 is not a valid constraint, and should not parse.

  • hyphen constraint ranges are not supported

Jump to

Keyboard shortcuts

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