Expand description
§pubsat — SAT-based dependency resolution
pubsat is a backend-agnostic, ecosystem-agnostic SAT-based
dependency resolver for semver-shaped constraint problems. The
same engine should serve a JS-style package manager, a private
artifact registry, a build-tool internal resolver, or any
other workflow with a “pick the right versions” sub-problem.
§Modules
version— node-semver-compatible range parser (caret, tilde, hyphen, x-ranges, unions, dist tags) withVersionSetoperations.constraint— ecosystem-independentConstraintvocabulary.registry—PackageRegistrytrait, single-flightedCachedRegistrywrapper, and in-processMockRegistry.graph—DependencyGraph(petgraph-backed) with cycle detection.encoding—ConstraintEncoderlowering constraints to CNF.builder—DependencyGraphBuilderthat walks a registry concurrently.resolver—DependencyResolverthat orchestrates the full pipeline with greedy “prefer newest” SAT assumptions.sat— backend-agnostic SAT types and theSatSolvertrait, with aVarisatSolverimpl behind the defaultvarisat-solverfeature.error—ResolutionError,SatError, and theirResultaliases.
§Example: parse and evaluate a range
use pubsat::version::VersionSet;
use semver::Version;
use std::str::FromStr;
let range: VersionSet = "^1.2.3".parse().unwrap();
assert!(range.satisfies(&Version::from_str("1.5.0").unwrap()));
assert!(range.satisfies(&Version::from_str("1.2.3").unwrap()));
assert!(!range.satisfies(&Version::from_str("2.0.0").unwrap()));
assert!(!range.satisfies(&Version::from_str("1.2.2").unwrap()));§Example: end-to-end resolution
use std::sync::Arc;
use pubsat::builder::DependencyGraphBuilder;
use pubsat::registry::{MockRegistry, VersionMetadata};
use pubsat::resolver::DependencyResolver;
use pubsat::version::VersionSet;
use semver::Version;
let vs = |s: &str| -> VersionSet { s.parse().unwrap() };
let registry = Arc::new(
MockRegistry::new()
.with_versions("chalk", &["4.1.0", "5.0.0"])
.with_versions("ansi-styles", &["4.3.0", "6.2.1"])
.with_dependency("chalk", "4.1.0", "ansi-styles", vs("^4.0.0"))
.with_dependency("chalk", "5.0.0", "ansi-styles", vs("^6.0.0")),
);
let root = VersionMetadata::new("my-app", Version::new(1, 0, 0))
.with_dependency("chalk", vs("^5.0.0"));
let graph = DependencyGraphBuilder::new(registry.clone())
.build(root)
.await
.unwrap();
let resolution = DependencyResolver::new(registry)
.resolve(graph)
.await
.unwrap();
// resolution.packages: [ansi-styles@6.2.1, chalk@5.0.0]
assert_eq!(resolution.packages.len(), 2);§Design context
See docs/design/architecture.md for the design
rationale (why SAT and not PubGrub, hot-path lessons, the
comparison with prior art).
Modules§
- builder
- Dependency-graph builder.
- constraint
- Constraint types describing dependency relationships.
- encoding
- Lowering
Constraints to CNF for SAT solving. - error
- Error types for dependency resolution
- graph
- Dependency-graph types.
- registry
- Package-registry abstraction.
- resolver
- Top-level resolver.
- sat
- SAT solver abstraction layer
- version
- Semantic versioning logic and constraint evaluation