Documentation
¶
Overview ¶
Package semanticpuppet is a pure-Go (no cgo) port of the Ruby semantic_puppet gem. It implements the two value types that Puppet uses to reason about module versions and dependency constraints:
Version parses and compares strings that conform to the Semantic Versioning 2.0.0 specification (https://semver.org). It exposes the MAJOR.MINOR.PATCH triple, the optional pre-release and build-metadata identifiers, SemVer precedence (build metadata is ignored), stability queries and next-version bumps.
VersionRange parses and evaluates the version-range grammar that semantic_puppet accepts (which follows node-semver): plain versions, the comparators <, <=, >, >=, =, hyphen ranges (1.0.0 - 2.0.0), the tilde (~, ~>, ~=) and caret (^) approximation operators, x-ranges (1.x, 1.2.x, *) and logical-or (||) unions. A range answers membership (VersionRange.Include/VersionRange.Cover) and can be intersected with another range (VersionRange.Intersection).
On top of these value types it ports the gem's module-dependency graph solver (SemanticPuppet::Dependency):
Source is the injectable provider seam that yields the available ModuleRelease values for a module name; AddSource/Sources/ ClearSources manage the source list as the gem's singleton does.
Query builds a dependency Graph for a set of top-level constraints and fetches the transitive universe of releases; Resolve walks that graph, backtracking on conflict and preferring the newest satisfying (stable-over-prerelease) release, and returns the resolved release set or an *UnsatisfiableGraph. Module- and graph-level constraints (Graph.AddConstraint/Graph.AddGraphConstraint) and dependency cycles are honoured exactly as in the gem.
The port is faithful to the observable behaviour of the gem, including its prerelease-inclusion rule: a pre-release version is only matched by a range when some clause of the range explicitly names a pre-release sharing the same MAJOR.MINOR.PATCH triple.
The package is pure Go, uses only the standard library and has no dependency on any Ruby runtime; every value type is Go-typed so that a Ruby binding layer (such as go-embedded-ruby) can marshal Ruby values onto these types.
Index ¶
- Variables
- func AddSource(s Source)
- func ClearSources()
- func IsValid(ver string) bool
- func SortVersions(versions []*Version)
- func Unsatisfiable() string
- type BaseSource
- type ByVersion
- type Graph
- func (g *Graph) Add(nodes ...*ModuleRelease)
- func (g *Graph) AddConstraint(source, mod, desc string, test func(*ModuleRelease) bool)
- func (g *Graph) AddGraphConstraint(source string, test func([]*ModuleRelease) bool)
- func (g *Graph) Children() map[string]*ModuleRelease
- func (g *Graph) Dependencies() map[string][]*ModuleRelease
- func (g *Graph) DependencyNames() []string
- func (g *Graph) Modules() []string
- func (g *Graph) PopulateChildren(nodes []*ModuleRelease)
- func (g *Graph) Satisfied() bool
- func (g *Graph) SatisfiesConstraints(rel *ModuleRelease) bool
- func (g *Graph) SatisfiesDependency(rel *ModuleRelease) bool
- func (g *Graph) SatisfiesGraph(solution []*ModuleRelease) bool
- type ModuleRelease
- func CreateRelease(src Source, name, version string, deps map[string]string) (*ModuleRelease, error)
- func FetchReleases(name string) []*ModuleRelease
- func NewModuleRelease(src Source, name string, version *Version, deps map[string]*VersionRange) *ModuleRelease
- func Resolve(graph *Graph) ([]*ModuleRelease, error)
- func (g *ModuleRelease) Add(nodes ...*ModuleRelease)
- func (g *ModuleRelease) Children() map[string]*ModuleRelease
- func (m *ModuleRelease) Compare(o *ModuleRelease) int
- func (g *ModuleRelease) Dependencies() map[string][]*ModuleRelease
- func (g *ModuleRelease) DependencyNames() []string
- func (m *ModuleRelease) Eql(o *ModuleRelease) bool
- func (m *ModuleRelease) Name() string
- func (g *ModuleRelease) PopulateChildren(nodes []*ModuleRelease)
- func (g *ModuleRelease) Satisfied() bool
- func (g *ModuleRelease) SatisfiesConstraints(rel *ModuleRelease) bool
- func (g *ModuleRelease) SatisfiesDependency(rel *ModuleRelease) bool
- func (m *ModuleRelease) String() string
- func (m *ModuleRelease) Version() *Version
- type ParseError
- type Source
- type UnsatisfiableGraph
- type Version
- func (v *Version) Build() string
- func (v *Version) Compare(other *Version) int
- func (v *Version) Equal(other *Version) bool
- func (v *Version) Major() int
- func (v *Version) Minor() int
- func (v *Version) NextMajor() *Version
- func (v *Version) NextMinor() *Version
- func (v *Version) NextPatch() *Version
- func (v *Version) Patch() int
- func (v *Version) Prerelease() string
- func (v *Version) Stable() bool
- func (v *Version) String() string
- func (v *Version) ToStable() *Version
- type VersionRange
- func (r *VersionRange) Cover(version *Version) bool
- func (r *VersionRange) Equal(other *VersionRange) bool
- func (r *VersionRange) Include(version *Version) bool
- func (r *VersionRange) Inspect() string
- func (r *VersionRange) Intersection(other *VersionRange) *VersionRange
- func (r *VersionRange) Max() *Version
- func (r *VersionRange) Min() *Version
- func (r *VersionRange) String() string
Constants ¶
This section is empty.
Variables ¶
var ErrInvalidRange = errors.New("invalid version range")
ErrInvalidRange is returned (wrapped) by ParseRange when a string is not a valid version range. Use errors.Is to test for it.
var ErrInvalidVersion = errors.New("invalid semantic version")
ErrInvalidVersion is returned (wrapped) by Parse when a string is not a valid Semantic Version. Use errors.Is to test for it.
Functions ¶
func AddSource ¶
func AddSource(s Source)
AddSource appends a source to the list, mirroring Dependency.add_source.
func ClearSources ¶
func ClearSources()
ClearSources empties the source list, mirroring Dependency.clear_sources.
func SortVersions ¶
func SortVersions(versions []*Version)
SortVersions sorts versions in ascending SemVer precedence order, in place.
func Unsatisfiable ¶
func Unsatisfiable() string
Unsatisfiable returns the module that the most recent Resolve failure could not satisfy, or "" if there was none. It mirrors Dependency.unsatisfiable.
Types ¶
type BaseSource ¶
type BaseSource struct{}
BaseSource can be embedded in a Source implementation to inherit the gem's default priority of 0.
func (BaseSource) Priority ¶
func (BaseSource) Priority() int
Priority returns 0, the default source priority.
type ByVersion ¶
type ByVersion []*Version
ByVersion attaches sort.Interface to a slice of versions, ordering them by ascending SemVer precedence.
type Graph ¶
type Graph struct {
// contains filtered or unexported fields
}
Graph is the root of a dependency query: the set of top-level module constraints plus any additional module- or graph-level constraints. It mirrors SemanticPuppet::Dependency::Graph. Build one with Query.
func Query ¶
Query builds a dependency Graph for the given top-level module ranges and eagerly fetches the transitive universe of releases from the configured sources. It mirrors Dependency.query. It returns an error wrapping ErrInvalidRange if any range string is malformed.
func (*Graph) Add ¶
func (g *Graph) Add(nodes ...*ModuleRelease)
Add records the given releases against any matching dependency, keeping each dependency's release list sorted. It mirrors GraphNode#<<.
func (*Graph) AddConstraint ¶
func (g *Graph) AddConstraint(source, mod, desc string, test func(*ModuleRelease) bool)
AddConstraint adds a module-level constraint: releases of mod must satisfy test. desc describes the constraint and source names its origin. It mirrors GraphNode#add_constraint as exposed on the graph.
func (*Graph) AddGraphConstraint ¶
func (g *Graph) AddGraphConstraint(source string, test func([]*ModuleRelease) bool)
AddGraphConstraint adds a whole-solution constraint: every candidate solution (partial or complete) must satisfy test. It mirrors Graph#add_graph_constraint.
func (*Graph) Children ¶
func (g *Graph) Children() map[string]*ModuleRelease
Children returns the resolved child nodes populated by [PopulateChildren]. It mirrors GraphNode#children.
func (*Graph) Dependencies ¶
func (g *Graph) Dependencies() map[string][]*ModuleRelease
Dependencies returns the map of dependency name to the satisfying releases discovered for it. It mirrors GraphNode#dependencies.
func (*Graph) DependencyNames ¶
func (g *Graph) DependencyNames() []string
DependencyNames returns the dependency names in registration order. It mirrors GraphNode#dependency_names.
func (*Graph) Modules ¶
Modules returns the top-level module names of the query. It mirrors Graph#modules.
func (*Graph) PopulateChildren ¶
func (g *Graph) PopulateChildren(nodes []*ModuleRelease)
PopulateChildren walks a resolved solution and records, for each satisfied dependency, the release that satisfies it, recursing across the solution. It mirrors GraphNode#populate_children.
func (*Graph) Satisfied ¶
func (g *Graph) Satisfied() bool
Satisfied reports whether every registered dependency has at least one satisfying release. It mirrors GraphNode#satisfied?.
func (*Graph) SatisfiesConstraints ¶
func (g *Graph) SatisfiesConstraints(rel *ModuleRelease) bool
SatisfiesConstraints reports whether rel passes every constraint recorded for rel's module name. It mirrors GraphNode#satisfies_constraints?.
func (*Graph) SatisfiesDependency ¶
func (g *Graph) SatisfiesDependency(rel *ModuleRelease) bool
SatisfiesDependency reports whether rel is a satisfying release for one of this node's dependencies. It mirrors GraphNode#satisfies_dependency?.
func (*Graph) SatisfiesGraph ¶
func (g *Graph) SatisfiesGraph(solution []*ModuleRelease) bool
SatisfiesGraph reports whether solution violates no graph-level constraint. It mirrors Graph#satisfies_graph?.
type ModuleRelease ¶
type ModuleRelease struct {
// contains filtered or unexported fields
}
ModuleRelease is one published release of a module: a name, a Version and a set of dependency constraints. It mirrors SemanticPuppet::Dependency::ModuleRelease.
func CreateRelease ¶
func CreateRelease(src Source, name, version string, deps map[string]string) (*ModuleRelease, error)
CreateRelease builds a ModuleRelease belonging to src, mirroring Source#create_release. version is a Semantic Version string; deps maps a dependency name to a version-range string (an empty string is treated as ">= 0.0.0", matching the gem's nil handling). It returns an error wrapping ErrInvalidVersion or ErrInvalidRange for malformed input.
func FetchReleases ¶
func FetchReleases(name string) []*ModuleRelease
FetchReleases returns every distinct release available for name across all sources (first source to offer a given version wins). It mirrors Dependency.fetch_releases.
func NewModuleRelease ¶
func NewModuleRelease(src Source, name string, version *Version, deps map[string]*VersionRange) *ModuleRelease
NewModuleRelease constructs a release owned by src with the given name, version and dependency ranges. It mirrors ModuleRelease#initialize: each dependency becomes both a registered dependency and a constraint requiring the dependency's version to fall within range.
func Resolve ¶
func Resolve(graph *Graph) ([]*ModuleRelease, error)
Resolve resolves graph into a flat list of releases satisfying every transitive dependency and constraint, preferring the newest satisfying (stable-over-prerelease) release and backtracking on conflict. It mirrors Dependency.resolve. On failure it returns an *UnsatisfiableGraph.
func (*ModuleRelease) Add ¶
func (g *ModuleRelease) Add(nodes ...*ModuleRelease)
Add records the given releases against any matching dependency, keeping each dependency's release list sorted. It mirrors GraphNode#<<.
func (*ModuleRelease) Children ¶
func (g *ModuleRelease) Children() map[string]*ModuleRelease
Children returns the resolved child nodes populated by [PopulateChildren]. It mirrors GraphNode#children.
func (*ModuleRelease) Compare ¶
func (m *ModuleRelease) Compare(o *ModuleRelease) int
Compare orders releases by [priority, name, version], mirroring ModuleRelease#<=>.
func (*ModuleRelease) Dependencies ¶
func (g *ModuleRelease) Dependencies() map[string][]*ModuleRelease
Dependencies returns the map of dependency name to the satisfying releases discovered for it. It mirrors GraphNode#dependencies.
func (*ModuleRelease) DependencyNames ¶
func (g *ModuleRelease) DependencyNames() []string
DependencyNames returns the dependency names in registration order. It mirrors GraphNode#dependency_names.
func (*ModuleRelease) Eql ¶
func (m *ModuleRelease) Eql(o *ModuleRelease) bool
Eql reports whether two releases are equal by name, version and dependency set, mirroring ModuleRelease#eql?/#==. A nil operand is never equal.
func (*ModuleRelease) PopulateChildren ¶
func (g *ModuleRelease) PopulateChildren(nodes []*ModuleRelease)
PopulateChildren walks a resolved solution and records, for each satisfied dependency, the release that satisfies it, recursing across the solution. It mirrors GraphNode#populate_children.
func (*ModuleRelease) Satisfied ¶
func (g *ModuleRelease) Satisfied() bool
Satisfied reports whether every registered dependency has at least one satisfying release. It mirrors GraphNode#satisfied?.
func (*ModuleRelease) SatisfiesConstraints ¶
func (g *ModuleRelease) SatisfiesConstraints(rel *ModuleRelease) bool
SatisfiesConstraints reports whether rel passes every constraint recorded for rel's module name. It mirrors GraphNode#satisfies_constraints?.
func (*ModuleRelease) SatisfiesDependency ¶
func (g *ModuleRelease) SatisfiesDependency(rel *ModuleRelease) bool
SatisfiesDependency reports whether rel is a satisfying release for one of this node's dependencies. It mirrors GraphNode#satisfies_dependency?.
func (*ModuleRelease) String ¶
func (m *ModuleRelease) String() string
String renders the release for diagnostics, mirroring ModuleRelease#to_s.
func (*ModuleRelease) Version ¶
func (m *ModuleRelease) Version() *Version
Version returns the release's version.
type ParseError ¶
type ParseError struct {
// Kind is "version" or "range".
Kind string
// Input is the offending string.
Input string
// contains filtered or unexported fields
}
ParseError describes a failure to parse a version or version range. It wraps either ErrInvalidVersion or ErrInvalidRange.
func (*ParseError) Error ¶
func (e *ParseError) Error() string
func (*ParseError) Unwrap ¶
func (e *ParseError) Unwrap() error
Unwrap returns the sentinel error (ErrInvalidVersion or ErrInvalidRange).
type Source ¶
type Source interface {
// Priority orders sources when the same version is offered by more than
// one of them; a release's priority participates in release ordering.
Priority() int
// Fetch returns the releases the source knows about for name (possibly
// empty). It must not return nil-typed elements.
Fetch(name string) []*ModuleRelease
}
Source is the provider seam of the resolver. Given a module name it yields every release it knows about for that name. Implementations are injected via AddSource; the resolver never performs any I/O of its own, so tests can supply a fixed universe of releases.
It mirrors SemanticPuppet::Dependency::Source. The base gem class also has a default priority of 0 and a create_release helper; BaseSource provides the former and CreateRelease the latter.
type UnsatisfiableGraph ¶
type UnsatisfiableGraph struct {
// Modules is the list of top-level module names of the graph.
Modules []string
// Unsatisfied is the module that could not be satisfied, or "" when the
// resolver could not attribute the failure to a single module.
Unsatisfied string
// contains filtered or unexported fields
}
UnsatisfiableGraph is returned by Resolve when no consistent set of releases satisfies the graph. It mirrors SemanticPuppet::Dependency::UnsatisfiableGraph.
func (*UnsatisfiableGraph) Error ¶
func (e *UnsatisfiableGraph) Error() string
Error returns the human-readable failure message.
type Version ¶
type Version struct {
// contains filtered or unexported fields
}
Version is an immutable Semantic Version 2.0.0 value. The zero value is not usable; construct one with Parse.
func MaxVersion ¶
MaxVersion returns the highest-precedence version among versions, or nil if no versions are supplied.
func MinVersion ¶
MinVersion returns the lowest-precedence version among versions, or nil if no versions are supplied.
func MustParse ¶
MustParse is like Parse but panics if ver is not a valid version. It is intended for use with constant version strings.
func Parse ¶
Parse parses ver as a Semantic Version 2.0.0 string of the form MAJOR.MINOR.PATCH, optionally followed by a "-prerelease" and/or a "+build" section. It returns an error wrapping ErrInvalidVersion for malformed input, including numeric pre-release identifiers with leading zeroes.
func (*Version) Build ¶
Build returns the build-metadata identifier without its leading '+', or the empty string if there is no build metadata.
func (*Version) Compare ¶
Compare compares v and other by SemVer precedence, returning -1, 0 or +1. Build metadata is ignored, as required by the specification.
func (*Version) Equal ¶
Equal reports whether v and other are identical, including pre-release and build metadata (an absent pre-release differs from an empty one).
func (*Version) Prerelease ¶
Prerelease returns the pre-release identifier without its leading '-', or the empty string if there is no pre-release.
func (*Version) Stable ¶
Stable reports whether this is a stable release, i.e. it carries no pre-release identifier.
type VersionRange ¶
type VersionRange struct {
// contains filtered or unexported fields
}
VersionRange is an immutable set of versions expressed as a union of comparator clauses. Construct one with ParseRange.
func MustParseRange ¶
func MustParseRange(rangeString string) *VersionRange
MustParseRange is like ParseRange but panics on error. It is intended for use with constant range strings.
func ParseRange ¶
func ParseRange(rangeString string) (*VersionRange, error)
ParseRange parses a version-range string. It accepts plain versions ("1.2.3"), the comparators <, <=, >, >=, =, hyphen ranges ("1.0.0 - 2.0.0"), the tilde (~, ~>, ~=) and caret (^) operators, x-ranges ("1.x", "1.2.x", "*") and logical-or unions ("... || ..."). An empty string matches every version. It returns an error wrapping ErrInvalidRange for malformed input.
func (*VersionRange) Cover ¶
func (r *VersionRange) Cover(version *Version) bool
Cover is an alias for VersionRange.Include.
func (*VersionRange) Equal ¶
func (r *VersionRange) Equal(other *VersionRange) bool
Equal reports whether r and other consist of the same matcher clauses.
func (*VersionRange) Include ¶
func (r *VersionRange) Include(version *Version) bool
Include reports whether version is a member of the range. A pre-release version is only matched when a clause of the range explicitly names a pre-release sharing the same major.minor.patch triple.
func (*VersionRange) Inspect ¶
func (r *VersionRange) Inspect() string
Inspect returns the canonical representation of the range assembled from its matcher clauses, independent of how it was originally written.
func (*VersionRange) Intersection ¶
func (r *VersionRange) Intersection(other *VersionRange) *VersionRange
Intersection returns the range covering exactly the versions matched by both r and other. If the ranges do not overlap, an empty range is returned.
func (*VersionRange) Max ¶
func (r *VersionRange) Max() *Version
Max returns the version that ends the range, or nil if the range is a union of more than one disjoint clause.
func (*VersionRange) Min ¶
func (r *VersionRange) Min() *Version
Min returns the version that begins the range, or nil if the range is a union of more than one disjoint clause.
func (*VersionRange) String ¶
func (r *VersionRange) String() string
String returns the string the range was parsed from, or the canonical inspect form for ranges produced by intersection.