pubgrub

Public API for the PubGrub version solver.

This module provides the dependency provider interface, an offline provider for tests and small graphs, and the resolve entrypoint.

Overview

PubGrub finds a set of package versions that satisfy all constraints and, when it cannot, returns a derivation tree that explains the conflict.

You provide:

The solver returns a dict.Dict(p, v) mapping selected packages to versions.

Quick start (offline provider)

import pubgrub
import pubgrub/version
import pubgrub/version_ranges as ranges

pub fn example() {
  let compare = version.compare

  let provider =
    pubgrub.offline_new()
    |> pubgrub.offline_add_dependencies("root", version.new(1, 0, 0), [
      #("foo", ranges.between(compare, version.new(1, 0, 0), version.new(2, 0, 0))),
    ])
    |> pubgrub.offline_add_dependencies("foo", version.new(1, 0, 0), [])

  let dp = pubgrub.offline_provider(provider, compare)
  pubgrub.resolve(dp, "root", version.new(1, 0, 0))
}

Provider design

DependencyProvider is intentionally generic. A real provider typically:

prioritize and compare_priority determine which package is selected next. Use a stable priority function to keep resolutions deterministic.

Pitfalls and tips

Related modules

Types

Dependencies for a specific package version.

pub type Dependencies(p, v, m) {
  Unavailable(m)
  Available(dict.Dict(p, version_ranges.Ranges(v)))
}

Constructors

Interface for querying package versions and their dependencies.

pub type DependencyProvider(p, v, m, err, priority) {
  DependencyProvider(
    compare: fn(v, v) -> order.Order,
    compare_priority: fn(priority, priority) -> order.Order,
    prioritize: fn(
      p,
      version_ranges.Ranges(v),
      PackageResolutionStatistics,
    ) -> priority,
    choose_version: fn(p, version_ranges.Ranges(v)) -> Result(
      option.Option(v),
      err,
    ),
    get_dependencies: fn(p, v) -> Result(
      Dependencies(p, v, m),
      err,
    ),
    should_cancel: fn() -> Result(Nil, err),
  )
}

Constructors

In-memory dependency provider for tests and simple usage.

pub type OfflineDependencyProvider(p, v) {
  OfflineDependencyProvider(
    dependencies: dict.Dict(
      p,
      dict.Dict(v, dict.Dict(p, version_ranges.Ranges(v))),
    ),
  )
}

Constructors

Conflict statistics used by prioritize.

pub type PackageResolutionStatistics {
  PackageResolutionStatistics(
    unit_propagation_affected: Int,
    unit_propagation_culprit: Int,
    dependencies_affected: Int,
    dependencies_culprit: Int,
  )
}

Constructors

  • PackageResolutionStatistics(
      unit_propagation_affected: Int,
      unit_propagation_culprit: Int,
      dependencies_affected: Int,
      dependencies_culprit: Int,
    )

Error variants produced by the solver.

pub type PubGrubError(p, v, m, err) {
  NoSolution(report.DerivationTree(p, v, m))
  ErrorRetrievingDependencies(
    package: p,
    version: v,
    source: err,
  )
  ErrorChoosingVersion(package: p, source: err)
  ErrorInShouldCancel(source: err)
}

Constructors

  • NoSolution(report.DerivationTree(p, v, m))
  • ErrorRetrievingDependencies(package: p, version: v, source: err)
  • ErrorChoosingVersion(package: p, source: err)
  • ErrorInShouldCancel(source: err)
pub type SemanticVersion =
  #(Int, Int, Int)

Values

pub fn conflict_count(stats: PackageResolutionStatistics) -> Int

Total conflict count from a statistics record.

pub fn empty_stats() -> PackageResolutionStatistics

Zeroed statistics value.

pub fn offline_add_dependencies(
  provider: OfflineDependencyProvider(p, v),
  package: p,
  version: v,
  dependencies: List(#(p, version_ranges.Ranges(v))),
) -> OfflineDependencyProvider(p, v)

Add dependencies for a package version to an offline provider.

pub fn offline_new() -> OfflineDependencyProvider(p, v)

Create an empty offline provider.

pub fn offline_packages(
  provider: OfflineDependencyProvider(p, v),
) -> List(p)

List packages known by an offline provider.

pub fn offline_provider(
  provider: OfflineDependencyProvider(p, v),
  compare: fn(v, v) -> order.Order,
) -> DependencyProvider(p, v, String, Nil, #(Int, Int))

Build a dependency provider backed by an offline provider.

pub fn offline_versions(
  provider: OfflineDependencyProvider(p, v),
  package: p,
) -> option.Option(List(v))

List available versions for a package, if present.

pub fn resolve(
  dependency_provider: DependencyProvider(p, v, m, err, priority),
  package: p,
  version: v,
) -> Result(dict.Dict(p, v), PubGrubError(p, v, m, err))

Resolve a dependency graph starting from a root package and version.

pub fn semantic_version_new(
  major: Int,
  minor: Int,
  patch: Int,
) -> #(Int, Int, Int)
pub fn semantic_version_to_string(
  ver: #(Int, Int, Int),
) -> String
Search Document