constraints

package
v1.0.2 Latest Latest
Warning

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

Go to latest
Published: Jul 6, 2023 License: MIT Imports: 4 Imported by: 10

Documentation

Overview

Package constraints contains a high-level representation of version constraints that retains enough information for direct analysis and serialization as a string.

The package also contains parsers to produce that representation from various compact constraint specification formats.

The main "versions" package, available in the parent directory, can consume the high-level constraint representation from this package to construct a version set that contains all versions meeting the given constraints. Package "constraints" does not contain any functionalty for checking versions against constraints since that is provided by package "versions".

Index

Constants

This section is empty.

Variables

This section is empty.

Functions

This section is empty.

Types

type ConstraintDepth

type ConstraintDepth int
const (
	Unconstrained    ConstraintDepth = 0
	ConstrainedMajor ConstraintDepth = 1
	ConstrainedMinor ConstraintDepth = 2
	ConstrainedPatch ConstraintDepth = 3
)

func (ConstraintDepth) String added in v1.0.0

func (i ConstraintDepth) String() string

type IntersectionSpec

type IntersectionSpec []SelectionSpec

IntersectionSpec represents an "and" operation on nested version constraints.

func ParseRubyStyleAll

func ParseRubyStyleAll(strs ...string) (IntersectionSpec, error)

ParseRubyStyleAll is a helper wrapper around ParseRubyStyle that accepts multiple selection strings and combines them together into a single IntersectionSpec.

func ParseRubyStyleMulti

func ParseRubyStyleMulti(str string) (IntersectionSpec, error)

ParseRubyStyleMulti is similar to ParseRubyStyle, but rather than parsing only a single selection specification it instead expects one or more comma-separated specifications, returning the result as an IntersectionSpec.

type NumConstraint

type NumConstraint struct {
	Num           uint64
	Unconstrained bool
}

func (NumConstraint) String

func (c NumConstraint) String() string

type SelectionOp

type SelectionOp rune
const (
	OpUnconstrained               SelectionOp = 0
	OpGreaterThan                 SelectionOp = '>'
	OpLessThan                    SelectionOp = '<'
	OpGreaterThanOrEqual          SelectionOp = '≥'
	OpGreaterThanOrEqualPatchOnly SelectionOp = '~'
	OpGreaterThanOrEqualMinorOnly SelectionOp = '^'
	OpLessThanOrEqual             SelectionOp = '≤'
	OpEqual                       SelectionOp = '='
	OpNotEqual                    SelectionOp = '≠'
	OpMatch                       SelectionOp = '*'
)

func (SelectionOp) String added in v1.0.0

func (i SelectionOp) String() string

type SelectionSpec

type SelectionSpec struct {
	Boundary VersionSpec
	Operator SelectionOp
}

SelectionSpec represents applying a single operator to a particular "boundary" version.

func ParseRubyStyle

func ParseRubyStyle(str string) (SelectionSpec, error)

ParseRubyStyle parses a single selection constraint using a syntax similar to that used by rubygems and other Ruby tools.

Exact compatibility with rubygems is not guaranteed; "ruby-style" here just means that users familiar with rubygems should find familiar the choice of operators and their meanings.

ParseRubyStyle parses only a single specification, mimicking the usual rubygems approach of providing each selection as a separate string. The result can be combined with other results to create an IntersectionSpec that describes the effect of multiple such constraints.

type Spec

type Spec interface {
	// contains filtered or unexported methods
}

Spec is an interface type that UnionSpec, IntersectionSpec, SelectionSpec, and VersionSpec all belong to.

It's provided to allow generic code to be written that accepts and operates on all specs, but such code must still handle each type separately using e.g. a type switch. This is a closed type that will not have any new implementations added in future.

type UnionSpec

type UnionSpec []IntersectionSpec

UnionSpec represents an "or" operation on nested version constraints.

This is not directly representable in all of our supported constraint syntaxes.

func Parse

func Parse(str string) (UnionSpec, error)

Parse parses a constraint string using a syntax similar to that used by npm, Go "dep", Rust's "cargo", etc. Exact compatibility with any of these systems is not guaranteed, but instead we aim for familiarity in the choice of operators and their meanings. The syntax described here is considered the canonical syntax for this package, but a Ruby-style syntax is also offered via the function "ParseRubyStyle".

A constraint string is a sequence of selection sets delimited by ||, with each selection set being a whitespace-delimited sequence of selections. Each selection is then the combination of a matching operator and a boundary version. The following is an example of a complex constraint string illustrating all of these features:

>=1.0.0 <2.0.0 || 1.0.0-beta1 || =2.0.2

In practice constraint strings are usually simpler than this, but this complex example allows us to identify each of the parts by example:

Selection Sets:     ">=1.0.0 <2.0.0"
                    "1.0.0-beta1"
                    "=2.0.2"
Selections:         ">=1.0.0"
                    "<2.0.0"
                    "1.0.0-beta1"
                    "=2.0.2"
Matching Operators: ">=", "<", "=" are explicit operators
                    "1.0.0-beta1" has an implicit "=" operator
Boundary Versions:  "1.0.0", "2.0.0", "1.0.0-beta1", "2.0.2"

A constraint string describes the members of a version set by adding exact versions or ranges of versions to that set. A version is in the set if any one of the selection sets match that version. A selection set matches a version if all of its selections match that version. A selection matches a version if the version has the indicated relationship with the given boundary version.

In the above example, the first selection set matches all released versions whose major segment is 1, since both selections must apply. However, the remaining two selection sets describe two specific versions outside of that range that are also admitted, in addition to those in the indicated range.

The available matching operators are:

<  Less than
<= Less than or equal
>  Greater than
>= Greater than or equal
=  Equal
!  Not equal
~  Greater than with implied upper limit (described below)
^  Greater than excluding new major releases (described below)

If no operator is specified, the operator is implied to be "equal" for a full version specification, or a special additional "match" operator for a version containing wildcards as described below.

The "~" matching operator is a shorthand for expressing both a lower and upper limit within a single expression. The effect of this operator depends on how many segments are specified in the boundary version: if only one segment is specified then new minor and patch versions are accepted, whereas if two or three segments are specified then only patch versions are accepted. For example:

~1     is equivalent to >=1.0.0 <2.0.0
~1.0   is equivalent to >=1.0.0 <1.1.0
~1.2   is equivalent to >=1.2.0 <1.3.0
~1.2.0 is equivalent to >=1.2.0 <1.3.0
~1.2.3 is equivalent to >=1.2.3 <1.3.0

The "^" matching operator is similar to "~" except that it always constrains only the major version number. It has an additional special behavior for when the major version number is zero: in that case, the minor release number is constrained, reflecting the common semver convention that initial development releases mark breaking changes by incrementing the minor version. For example:

^1     is equivalent to >=1.0.0 <2.0.0
^1.2   is equivalent to >=1.2.0 <2.0.0
^1.2.3 is equivalent to >=1.2.3 <2.0.0
^0.1.0 is equivalent to >=0.1.0 <0.2.0
^0.1.2 is equivalent to >=0.1.2 <0.2.0

The boundary version can contain wildcards for the major, minor or patch segments, which are specified using the markers "*", "x", or "X". When used in a selection with no explicit operator, these specify the implied "match" operator and define ranges with similar meaning to the "~" and "^" operators:

1.*    is equivalent to >=1.0.0 <2.0.0
1.*.*  is equivalent to >=1.0.0 <2.0.0
1.0.*  is equivalent to >=1.0.0 <1.1.0

When wildcards are used, the first segment specified as a wildcard implies that all of the following segments are also wildcards. A version specification like "1.*.2" is invalid, because a wildcard minor version implies that the patch version must also be a wildcard.

Wildcards have no special meaning when used with explicit operators, and so they are merely replaced with zeros in such cases.

Explicit range syntax using a hyphen creates inclusive upper and lower bounds:

1.0.0 - 2.0.0 is equivalent to >=1.0.0 <=2.0.0
1.2.3 - 2.3.4 is equivalent to >=1.2.3 <=2.3.4

Requests of exact pre-release versions with the equals operator have no special meaning to the constraint parser, but are interpreted as explicit requests for those versions when interpreted by the MeetingConstraints function (and related functions) in the "versions" package, in the parent directory. Pre-release versions that are not explicitly requested are excluded from selection so that e.g. "^1.0.0" will not match a version "2.0.0-beta.1".

The result is always a UnionSpec, whose members are IntersectionSpecs each describing one selection set. In the common case where a string contains only one selection, both the UnionSpec and the IntersectionSpec will have only one element and can thus be effectively ignored by the caller. (Union and intersection of single sets are both no-op.) A valid string must contain at least one selection; if an empty selection is to be considered as either "no versions" or "all versions" then this special case must be handled by the caller prior to calling this function.

If there are syntax errors or ambiguities in the provided string then an error is returned. All errors returned by this function are suitable for display to English-speaking end-users, and avoid any Go-specific terminology.

type VersionSpec

type VersionSpec struct {
	Major      NumConstraint
	Minor      NumConstraint
	Patch      NumConstraint
	Prerelease string
	Metadata   string
}

VersionSpec represents the boundary within a SelectionSpec.

func ParseExactVersion

func ParseExactVersion(vs string) (VersionSpec, error)

ParseExactVersion parses a string that must contain the specification of a single, exact version, and then returns it as a VersionSpec.

This is primarily here to allow versions.ParseVersion to re-use the constraint grammar, and isn't very useful for direct use from calling applications.

func (VersionSpec) ConstrainToUpperBound

func (s VersionSpec) ConstrainToUpperBound() VersionSpec

ConstrainToUpperBound returns a copy of the receiver with all of its unconstrained numeric segments constrained to zero and its last constrained segment increased by one.

This operation is not meaningful for an entirely unconstrained VersionSpec, so will return the zero value of the type in that case.

func (VersionSpec) ConstrainToZero

func (s VersionSpec) ConstrainToZero() VersionSpec

ConstrainToZero returns a copy of the receiver with all of its unconstrained numeric segments constrained to zero.

func (VersionSpec) ConstraintBounds

func (s VersionSpec) ConstraintBounds() (SelectionSpec, SelectionSpec)

ConstraintBounds returns two exact VersionSpecs that represent the upper and lower bounds of the possibly-inexact receiver. If the receiver is already exact then the two bounds are identical and have operator OpEqual. If they are different then the lower bound is OpGreaterThanOrEqual and the upper bound is OpLessThan.

As a special case, if the version spec is entirely unconstrained the two bounds will be identical and the zero value of SelectionSpec. For consistency, this result is also returned if the receiver is already the zero value of VersionSpec, since a zero spec represents a lack of constraint.

The constraints must be consistent as defined by ConstraintDepth, or this method will panic.

func (VersionSpec) ConstraintDepth

func (s VersionSpec) ConstraintDepth() ConstraintDepth

ConstraintDepth returns the constraint depth of the receiver, which is the most specifc version number segment that is exactly constrained.

The constraints must be consistent, which means that if a given segment is unconstrained then all of the deeper segments must also be unconstrained. If not, this method will panic. Version specs produced by the parsers in this package are guaranteed to be consistent.

func (VersionSpec) IsExact

func (s VersionSpec) IsExact() bool

IsExact returns bool if all of the version numbers in the receiver are fully-constrained. This is the same as s.ConstraintDepth() == ConstrainedPatch

func (VersionSpec) String

func (s VersionSpec) String() string

Jump to

Keyboard shortcuts

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