Skip to content
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
20 commits
Select commit Hold shift + click to select a range
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 2 additions & 0 deletions .github/workflows/ci.yml
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
name: CI
on:
pull_request:
merge_group:
push:
branches: [ release, dev ]
schedule: [ cron: "0 6 * * 4" ]
Expand Down Expand Up @@ -103,6 +104,7 @@ jobs:
check_commit_conventions:
name: Commit messages follow project guidelines
runs-on: ubuntu-latest
if: github.event_name != 'pull_request' || github.event.action == 'enqueued'
steps:
- uses: actions/checkout@v2
with:
Expand Down
40 changes: 40 additions & 0 deletions .github/workflows/permaref.yaml
Original file line number Diff line number Diff line change
@@ -0,0 +1,40 @@
# Automatically creates a tag for each commit to `main` so when we rebase
# changes on top of the upstream, we retain permanent references to each
# previous commit so they are not orphaned and eventually deleted.
name: Create permanent reference

on:
push:
branches:
- "main"

jobs:
release:
runs-on: ubuntu-latest
steps:
- name: Checkout
uses: actions/checkout@v3

- name: Get the permanent ref number
id: get_version
run: |
# Enable pipefail so git command failures do not result in null versions downstream
set -x

echo ::set-output name=LAST_PERMA_NUMBER::$(\
git ls-remote --tags --refs --sort="v:refname" \
https://github.com/zanieb/pubgrub.git | grep "tags/perma-" | tail -n1 | sed 's/.*\/perma-//' \
)

- name: Configure Git
run: |
git config user.name "$GITHUB_ACTOR"
git config user.email "[email protected]"

- name: Create and push the new tag
run: |
TAG="perma-$((LAST_PERMA_NUMBER + 1))"
git tag -a "$TAG" -m "Automatically created on push to `main`"
git push origin "$TAG"
env:
LAST_PERMA_NUMBER: ${{ steps.get_version.outputs.LAST_PERMA_NUMBER }}
2 changes: 1 addition & 1 deletion CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -48,7 +48,7 @@ The gist of it is:

#### Added

- Links to code items in the code documenation.
- Links to code items in the code documentation.
- New `"serde"` feature that allows serializing some library types, useful for making simple reproducible bug reports.
- New variants for `error::PubGrubError` which are `DependencyOnTheEmptySet`,
`SelfDependency`, `ErrorChoosingPackageVersion` and `ErrorInShouldCancel`.
Expand Down
6 changes: 5 additions & 1 deletion Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,7 @@ authors = [
"Alex Tokarev <[email protected]>",
"Jacob Finkelman <[email protected]>",
]
edition = "2018"
edition = "2021"
description = "PubGrub version solving algorithm"
readme = "README.md"
repository = "https://github.com/pubgrub-rs/pubgrub"
Expand All @@ -20,15 +20,19 @@ include = ["Cargo.toml", "LICENSE", "README.md", "src/**", "tests/**", "examples
# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html

[dependencies]
indexmap = "2.0.2"
priority-queue = "1.1.1"
thiserror = "1.0"
rustc-hash = "1.1.0"
serde = { version = "1.0", features = ["derive"], optional = true }
log = "0.4.14" # for debug logs in tests

[dev-dependencies]
proptest = "0.10.1"
ron = "0.6"
varisat = "0.2.2"
criterion = "0.3"
env_logger = "0.9.0"

[[bench]]
name = "large_case"
Expand Down
17 changes: 10 additions & 7 deletions benches/large_case.rs
Original file line number Diff line number Diff line change
Expand Up @@ -5,16 +5,19 @@ extern crate criterion;
use self::criterion::*;

use pubgrub::package::Package;
use pubgrub::range::Range;
use pubgrub::solver::{resolve, OfflineDependencyProvider};
use pubgrub::version::{NumberVersion, SemanticVersion, Version};
use pubgrub::version::{NumberVersion, SemanticVersion};
use pubgrub::version_set::VersionSet;
use serde::de::Deserialize;
use std::hash::Hash;

fn bench<'a, P: Package + Deserialize<'a>, V: Version + Hash + Deserialize<'a>>(
fn bench<'a, P: Package + Deserialize<'a>, VS: VersionSet + Deserialize<'a>>(
b: &mut Bencher,
case: &'a str,
) {
let dependency_provider: OfflineDependencyProvider<P, V> = ron::de::from_str(&case).unwrap();
) where
<VS as VersionSet>::V: Deserialize<'a>,
{
let dependency_provider: OfflineDependencyProvider<P, VS> = ron::de::from_str(&case).unwrap();

b.iter(|| {
for p in dependency_provider.packages() {
Expand All @@ -35,11 +38,11 @@ fn bench_nested(c: &mut Criterion) {
let data = std::fs::read_to_string(&case).unwrap();
if name.ends_with("u16_NumberVersion.ron") {
group.bench_function(name, |b| {
bench::<u16, NumberVersion>(b, &data);
bench::<u16, Range<NumberVersion>>(b, &data);
});
} else if name.ends_with("str_SemanticVersion.ron") {
group.bench_function(name, |b| {
bench::<&str, SemanticVersion>(b, &data);
bench::<&str, Range<SemanticVersion>>(b, &data);
});
}
}
Expand Down
30 changes: 16 additions & 14 deletions examples/branching_error_reporting.rs
Original file line number Diff line number Diff line change
Expand Up @@ -6,51 +6,53 @@ use pubgrub::report::{DefaultStringReporter, Reporter};
use pubgrub::solver::{resolve, OfflineDependencyProvider};
use pubgrub::version::SemanticVersion;

type SemVS = Range<SemanticVersion>;

// https://github.com/dart-lang/pub/blob/master/doc/solver.md#branching-error-reporting
fn main() {
let mut dependency_provider = OfflineDependencyProvider::<&str, SemanticVersion>::new();
let mut dependency_provider = OfflineDependencyProvider::<&str, SemVS>::new();
#[rustfmt::skip]
// root 1.0.0 depends on foo ^1.0.0
dependency_provider.add_dependencies(
"root", (1, 0, 0),
vec![("foo", Range::between((1, 0, 0), (2, 0, 0)))],
[("foo", Range::from_range_bounds((1, 0, 0)..(2, 0, 0)))],
);
#[rustfmt::skip]
// foo 1.0.0 depends on a ^1.0.0 and b ^1.0.0
dependency_provider.add_dependencies(
"foo", (1, 0, 0),
vec![
("a", Range::between((1, 0, 0), (2, 0, 0))),
("b", Range::between((1, 0, 0), (2, 0, 0))),
[
("a", Range::from_range_bounds((1, 0, 0)..(2, 0, 0))),
("b", Range::from_range_bounds((1, 0, 0)..(2, 0, 0))),
],
);
#[rustfmt::skip]
// foo 1.1.0 depends on x ^1.0.0 and y ^1.0.0
dependency_provider.add_dependencies(
"foo", (1, 1, 0),
vec![
("x", Range::between((1, 0, 0), (2, 0, 0))),
("y", Range::between((1, 0, 0), (2, 0, 0))),
[
("x", Range::from_range_bounds((1, 0, 0)..(2, 0, 0))),
("y", Range::from_range_bounds((1, 0, 0)..(2, 0, 0))),
],
);
#[rustfmt::skip]
// a 1.0.0 depends on b ^2.0.0
dependency_provider.add_dependencies(
"a", (1, 0, 0),
vec![("b", Range::between((2, 0, 0), (3, 0, 0)))],
[("b", Range::from_range_bounds((2, 0, 0)..(3, 0, 0)))],
);
// b 1.0.0 and 2.0.0 have no dependencies.
dependency_provider.add_dependencies("b", (1, 0, 0), vec![]);
dependency_provider.add_dependencies("b", (2, 0, 0), vec![]);
dependency_provider.add_dependencies("b", (1, 0, 0), []);
dependency_provider.add_dependencies("b", (2, 0, 0), []);
#[rustfmt::skip]
// x 1.0.0 depends on y ^2.0.0.
dependency_provider.add_dependencies(
"x", (1, 0, 0),
vec![("y", Range::between((2, 0, 0), (3, 0, 0)))],
[("y", Range::from_range_bounds((2, 0, 0)..(3, 0, 0)))],
);
// y 1.0.0 and 2.0.0 have no dependencies.
dependency_provider.add_dependencies("y", (1, 0, 0), vec![]);
dependency_provider.add_dependencies("y", (2, 0, 0), vec![]);
dependency_provider.add_dependencies("y", (1, 0, 0), []);
dependency_provider.add_dependencies("y", (2, 0, 0), []);

// Run the algorithm.
match resolve(&dependency_provider, "root", (1, 0, 0)) {
Expand Down
46 changes: 29 additions & 17 deletions examples/caching_dependency_provider.rs
Original file line number Diff line number Diff line change
Expand Up @@ -6,16 +6,21 @@ use std::error::Error;
use pubgrub::package::Package;
use pubgrub::range::Range;
use pubgrub::solver::{resolve, Dependencies, DependencyProvider, OfflineDependencyProvider};
use pubgrub::version::{NumberVersion, Version};
use pubgrub::version::NumberVersion;
use pubgrub::version_set::VersionSet;

type NumVS = Range<NumberVersion>;

// An example implementing caching dependency provider that will
// store queried dependencies in memory and check them before querying more from remote.
struct CachingDependencyProvider<P: Package, V: Version, DP: DependencyProvider<P, V>> {
struct CachingDependencyProvider<P: Package, VS: VersionSet, DP: DependencyProvider<P, VS>> {
remote_dependencies: DP,
cached_dependencies: RefCell<OfflineDependencyProvider<P, V>>,
cached_dependencies: RefCell<OfflineDependencyProvider<P, VS>>,
}

impl<P: Package, V: Version, DP: DependencyProvider<P, V>> CachingDependencyProvider<P, V, DP> {
impl<P: Package, VS: VersionSet, DP: DependencyProvider<P, VS>>
CachingDependencyProvider<P, VS, DP>
{
pub fn new(remote_dependencies_provider: DP) -> Self {
CachingDependencyProvider {
remote_dependencies: remote_dependencies_provider,
Expand All @@ -24,22 +29,15 @@ impl<P: Package, V: Version, DP: DependencyProvider<P, V>> CachingDependencyProv
}
}

impl<P: Package, V: Version, DP: DependencyProvider<P, V>> DependencyProvider<P, V>
for CachingDependencyProvider<P, V, DP>
impl<P: Package, VS: VersionSet, DP: DependencyProvider<P, VS>> DependencyProvider<P, VS>
for CachingDependencyProvider<P, VS, DP>
{
fn choose_package_version<T: std::borrow::Borrow<P>, U: std::borrow::Borrow<Range<V>>>(
&self,
packages: impl Iterator<Item = (T, U)>,
) -> Result<(T, Option<V>), Box<dyn Error>> {
self.remote_dependencies.choose_package_version(packages)
}

// Caches dependencies if they were already queried
fn get_dependencies(
&self,
package: &P,
version: &V,
) -> Result<Dependencies<P, V>, Box<dyn Error>> {
version: &VS::V,
) -> Result<Dependencies<P, VS>, Box<dyn Error + Send + Sync>> {
let mut cache = self.cached_dependencies.borrow_mut();
match cache.get_dependencies(package, version) {
Ok(Dependencies::Unknown) => {
Expand All @@ -49,7 +47,7 @@ impl<P: Package, V: Version, DP: DependencyProvider<P, V>> DependencyProvider<P,
cache.add_dependencies(
package.clone(),
version.clone(),
dependencies.clone().into_iter(),
dependencies.clone(),
);
Ok(Dependencies::Known(dependencies))
}
Expand All @@ -61,11 +59,25 @@ impl<P: Package, V: Version, DP: DependencyProvider<P, V>> DependencyProvider<P,
error @ Err(_) => error,
}
}

fn choose_version(
&self,
package: &P,
range: &VS,
) -> Result<Option<VS::V>, Box<dyn Error + Send + Sync>> {
self.remote_dependencies.choose_version(package, range)
}

type Priority = DP::Priority;

fn prioritize(&self, package: &P, range: &VS) -> Self::Priority {
self.remote_dependencies.prioritize(package, range)
}
}

fn main() {
// Simulating remote provider locally.
let mut remote_dependencies_provider = OfflineDependencyProvider::<&str, NumberVersion>::new();
let mut remote_dependencies_provider = OfflineDependencyProvider::<&str, NumVS>::new();

// Add dependencies as needed. Here only root package is added.
remote_dependencies_provider.add_dependencies("root", 1, Vec::new());
Expand Down
12 changes: 7 additions & 5 deletions examples/doc_interface.rs
Original file line number Diff line number Diff line change
Expand Up @@ -4,19 +4,21 @@ use pubgrub::range::Range;
use pubgrub::solver::{resolve, OfflineDependencyProvider};
use pubgrub::version::NumberVersion;

type NumVS = Range<NumberVersion>;

// `root` depends on `menu` and `icons`
// `menu` depends on `dropdown`
// `dropdown` depends on `icons`
// `icons` has no dependency
#[rustfmt::skip]
fn main() {
let mut dependency_provider = OfflineDependencyProvider::<&str, NumberVersion>::new();
let mut dependency_provider = OfflineDependencyProvider::<&str, NumVS>::new();
dependency_provider.add_dependencies(
"root", 1, vec![("menu", Range::any()), ("icons", Range::any())],
"root", 1, [("menu", Range::full()), ("icons", Range::full())],
);
dependency_provider.add_dependencies("menu", 1, vec![("dropdown", Range::any())]);
dependency_provider.add_dependencies("dropdown", 1, vec![("icons", Range::any())]);
dependency_provider.add_dependencies("icons", 1, vec![]);
dependency_provider.add_dependencies("menu", 1, [("dropdown", Range::full())]);
dependency_provider.add_dependencies("dropdown", 1, [("icons", Range::full())]);
dependency_provider.add_dependencies("icons", 1, []);

// Run the algorithm.
let solution = resolve(&dependency_provider, "root", 1);
Expand Down
Loading