PubGrub in Gleam
This repository is a Gleam port of the PubGrub version solving algorithm. PubGrub finds a set of package versions that satisfy all constraints and, when it cannot, produces a human-readable explanation for the conflict.
Features
- Generic solver over package and version types.
- Deterministic resolution with explicit version ordering.
- Range operations (union, intersection, complement).
- Conflict reporting with a derivation tree.
Getting started
Add this project as a dependency (local path or git) and use the public API in
src/pubgrub.gleam.
The solver requires a compare function for versions and a dependency provider.
An offline provider is included for tests and simple uses.
Minimal example
import gleam/dict
import gleam/order
import pubgrub
import pubgrub/version
import 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)
let result = pubgrub.resolve(dp, "root", version.new(1, 0, 0))
result
|> case {
Ok(solution) -> solution
Error(err) -> {
panic as "no solution"
}
}
}
Integration specs
The integration tests demonstrate a tiny, readable spec format:
[package-a:1.0.0]
package-b = '2.0.0'
[package-b:2.0.0]
package-c = '>= 1.0.0 and < 2.0.0'
See test/integration_resolution_test.gleam for more examples and the parser.
Ranges and comparisons
Ranges are created with an explicit compare function:
let range = ranges.between(version.compare, version.new(1, 0, 0), version.new(2, 0, 0))
This lets you use semantic versions or simple integers:
fn int_compare(a: Int, b: Int) -> order.Order {
case a < b { True -> order.Lt False -> case a > b { True -> order.Gt False -> order.Eq } }
}
Testing
Run:
gleam test
License
Mozilla Public License 2.0