Documentation ¶
Overview ¶
pakr (package resolver) provides a way to generically define both an index of total available packages, and a list of requirements/selections from that index, and resolve a package solution if possible.
- A "product" is a unique name that will have 1 or more package versions.
- A "package" is a specific version of a product, with specific dependencies.
Example (Conflict) ¶
P := NewPackage // Define an index that represents all available Packages // and their dependencies index := []Dependency{ { P("A", "1.0.0"), []Packages{ {P("C", "1.0.0")}, }, }, { P("B", "1.0.0"), []Packages{ {P("C", "2.0.0")}, }, }, } // Our specific constraints that we want to solve required := Packages{ P("A", "1.0.0"), P("B", "1.0.0")} // Just set our specific requires to be each Package defined // in the Dependency index resolver := NewResolver(required, index) solved, err := resolver.Resolve() if err != nil { panic(err.Error()) } if solved { panic("Resolver was expected to fail, but succeeded.") } fmt.Println("The following requirements cannot be satisfied:") for _, c := range resolver.Conflicts() { fmt.Printf(" %s\n", c.PackageName()) } fmt.Println("\nDetails:") detailed, _ := resolver.DetailedConflicts() fmt.Println(detailed)
Output: The following requirements cannot be satisfied: A-1.0.0 B-1.0.0 Details: Package A-1.0.0 depends on one of (C-1.0.0) Package B-1.0.0 depends on one of (C-2.0.0) Package C-2.0.0 conflicts with (C-1.0.0)
Example (Solve) ¶
P := NewPackage // Define an index that represents all available Packages // and their dependencies index := []Dependency{ { P("A", "1.0.0"), []Packages{ {P("B", "1.0.0")}, }, }, { P("A", "2.0.0"), []Packages{ {P("B", "2.0.0")}, }, }, { P("B", "2.0.0"), []Packages{ {P("C", "1.0.0")}, }, }, } // Our specific constraints that we want to solve required := Packages{P("A", "2.0.0")} // Just set our specific requires to be each Package defined // in the Dependency index resolver := NewResolver(required, index) solved, err := resolver.Resolve() if err != nil { panic(err.Error()) } if !solved { panic("Resolver was expected to succeed, but failed.") } solutions := resolver.Solution() sort.Sort(solutions) for _, pkg := range solutions { fmt.Println(pkg.PackageName()) }
Output: A-2.0.0 B-2.0.0 C-1.0.0
Index ¶
- Constants
- type Dependency
- type Package
- type PackageRelation
- type PackageRelations
- type Packager
- type Packages
- type ProductMap
- type Relation
- type Resolver
- func (r *Resolver) Conflicts() Packages
- func (r *Resolver) DetailedConflicts() (PackageRelations, error)
- func (r *Resolver) Initialize() error
- func (r *Resolver) IsPackageConflict(p Packager) bool
- func (r *Resolver) IsPackageNameConflict(packageName string) bool
- func (r *Resolver) PackageByName(packageName string) (Packager, error)
- func (r *Resolver) RequireTemp(p Packager)
- func (r *Resolver) Resolve() (bool, error)
- func (r *Resolver) SetPackageIndex(index []Dependency)
- func (r *Resolver) SetRequirements(requires Packages)
- func (r *Resolver) Solution() Packages
- func (r *Resolver) Solved() bool
Examples ¶
Constants ¶
const ( // Leave the package index in its original order ResolveSortNone resolveSort = iota // Sort packages to prefer lower versions first ResolveSortLow // Sort packages to prefer higher versions first ResolveSortHigh )
Variables ¶
This section is empty.
Functions ¶
This section is empty.
Types ¶
type Dependency ¶
Defines a Package, and all of its direct dependencies. Dependencies are lists of expanded Package version ranges. So for each package that is a dependency, all allowable Package versions are listed.
func NewDependency ¶
func NewDependency(p Packager) *Dependency
Return a new Dependencies instance, with a Packager and an empty list of Version sets
func (*Dependency) AddVersionSet ¶
func (p *Dependency) AddVersionSet(vers Packages)
AddVersionSet appends a list of Package version of a Product, to the Depends list.
type Package ¶
type Package struct {
// contains filtered or unexported fields
}
A Package is a specific version of a Product
func NewPackage ¶
NewPackage creates a new Package with a product name and version
func (*Package) PackageName ¶
PackageName returns the <Name>-<Version> of the Package
func (*Package) ProductName ¶
ProductName returns the unversioned name of the product
type PackageRelation ¶
PackageRelation relationship of either one Package to the overall requirements, or two packages to eachother
func (*PackageRelation) String ¶
func (r *PackageRelation) String() string
Generate the string representation of the relationship as a descriptive phrase.
type PackageRelations ¶
type PackageRelations []*PackageRelation
PackageRelations is a list of PackageRelation objects
func (PackageRelations) String ¶
func (p PackageRelations) String() string
Generate all descriptive phrases for contained relationships, separated by newlines
type Packager ¶
Packager interface represents an object that defines its Product name, Package name, and version identifier. Packages are variants of the same Product, with a different version number. A Product has 1 or more Packages, defining different versions.
type Packages ¶
type Packages []Packager
A slice of Packagers that supports sorting
type ProductMap ¶
type ProductMap struct {
// contains filtered or unexported fields
}
A struct that tracks mappings of Product names to package sets, and Package names to Packagers. Create with NewProductMap()
func NewProductMap ¶
func NewProductMap() *ProductMap
ProductMap tracks Packages, organizing them as a mapping of Product names to sets of Packages (version of each Product)
func (*ProductMap) Add ¶
func (m *ProductMap) Add(p Packager)
Add a Package to the mapping It will be organized by its Product name
func (*ProductMap) NumPackages ¶
func (m *ProductMap) NumPackages() int
Return the number of tracked packages
func (*ProductMap) NumProducts ¶
func (m *ProductMap) NumProducts() int
Return the number of tracked products
func (*ProductMap) PackageByName ¶
func (m *ProductMap) PackageByName(packageName string) (Packager, error)
Looks up and returns a Package by its PackageName Returns a non-nil error if not found
func (*ProductMap) Packages ¶
func (m *ProductMap) Packages(productName string) []Packager
Retrieve all Packages mapped by their Product name
type Relation ¶
type Relation string
A constant defining a relationship of a Packages contribution to a set of requirements
type Resolver ¶
type Resolver struct {
// contains filtered or unexported fields
}
A Resolver attempts to solve a package solution from a given set of constraints and assumptions for a package index list
func NewResolver ¶
func NewResolver(requires Packages, index []Dependency) *Resolver
NewResolver creates a new Resolver, from a given package dependency list
func NewSortResolver ¶
func NewSortResolver(requires Packages, index []Dependency, sortMode resolveSort) *Resolver
NewSortResolver creates a new Resolver, from a given package dependency list. Specify a sort order operation to apply to the packages when intializing the index. Sort order affects the preference in choosing higher vs lower version packages in the solution.
func (*Resolver) Conflicts ¶
Returns a package list of all Packages that were requirements, or added with RequireTemp(), that caused the Resolver to fail. Only makes sense to call this after having called Resolve() and finding that the resolve was not successful.
func (*Resolver) DetailedConflicts ¶
func (r *Resolver) DetailedConflicts() (PackageRelations, error)
If the previous call to Resolve() returned false, meaning the currently requirements are no solvable, then this method builds a list of the packages involved in the conflict.
Returns a slice of PackageRelations, which describe 1 or 2 packages, and a descriptive Relation flag
func (*Resolver) Initialize ¶
Resets all internal state, and initializes based on the currently set package dependency requirements This gets called automatically when calling SetRequirements()
func (*Resolver) IsPackageConflict ¶
Return true if a given required Package caused the Resolver to fail. Only makes sense to call this after having called Resolve() and finding that the resolve was not successful.
func (*Resolver) IsPackageNameConflict ¶
Return true if a given required package (by name) caused the Resolver to fail. Only makes sense to call this after having called Resolve() and finding that the resolve was not successful.
func (*Resolver) PackageByName ¶
Return a Package by its name. If the Package is not known to the Resolver, return an error
func (*Resolver) RequireTemp ¶
Add a package as a requirement that must be satisfied by the solver. This addition is only valid until the next call to Resolve(), after which it will be removed.
func (*Resolver) Resolve ¶
Attempt to resolve a package solution with the currently set criteria. Returns a bool indicating whether the Resolver succeeded or conflicted. Returns a non-nil error if there was an internal error.
func (*Resolver) SetPackageIndex ¶
func (r *Resolver) SetPackageIndex(index []Dependency)
Set the package dependency list. Resets the internal solver and state.
func (*Resolver) SetRequirements ¶
Set the package dependency list. Resets the internal solver and state.