diff --git a/src/conflict.rs b/src/conflict.rs index 5ff88bc..99fccc3 100644 --- a/src/conflict.rs +++ b/src/conflict.rs @@ -985,7 +985,7 @@ impl<'i, I: Interner> fmt::Display for DisplayUnsat<'i, I> { &ConflictCause::Constrains(version_set_id) => { writeln!( f, - "{indent}The constraint at the root level {version_set} could not be fulfilled", + "{indent}root constraint '{version_set}' cannot be fulfilled", version_set = self.interner.display_version_set(version_set_id), )?; } diff --git a/src/snapshot.rs b/src/snapshot.rs index 08b3fab..38edef6 100644 --- a/src/snapshot.rs +++ b/src/snapshot.rs @@ -356,19 +356,45 @@ impl<'s> SnapshotProvider<'s> { } /// Adds another requirement that matches any version of a package - pub fn add_package_requirement(&mut self, name: NameId) -> VersionSetId { + pub fn add_package_requirement(&mut self, name: NameId, matcher: &str) -> VersionSetId { let id = self.snapshot.version_sets.max() + self.additional_version_sets.len(); let package = self.package(name); - let version_set = VersionSet { - name, - display: "*".to_string(), - matching_candidates: package.solvables.iter().copied().collect(), - }; + // match packages if not `*` + if matcher != "*" { + let matching_candidates = package + .solvables + .iter() + .copied() + .filter(|&s| { + self.solvable(s) + .display + .contains(matcher) + }) + .collect(); + + let version_set = VersionSet { + name, + display: format!("{} {}", package.name, matcher), + matching_candidates, + }; + + self.additional_version_sets.push(version_set); + return VersionSetId::from_usize(id); + } else { + // if `*` match all packages + let matching_candidates = package.solvables.iter().copied().collect(); + + let version_set = VersionSet { + name, + display: "*".to_string(), + matching_candidates, + }; - self.additional_version_sets.push(version_set); - VersionSetId::from_usize(id) + self.additional_version_sets.push(version_set); + return VersionSetId::from_usize(id); + } } fn solvable(&self, solvable: SolvableId) -> &Solvable { diff --git a/tests/snapshots/solver__root_constraints.snap b/tests/snapshots/solver__root_constraints.snap new file mode 100644 index 0000000..8f04d16 --- /dev/null +++ b/tests/snapshots/solver__root_constraints.snap @@ -0,0 +1,8 @@ +--- +source: tests/solver.rs +expression: "solve_for_snapshot(snapshot_provider, &[union_req], &[icons_req])" +--- +The following packages are incompatible +└─ union * can be installed with any of the following options: + └─ union union=1 +├─ root constraint 'union 5' cannot be fulfilled diff --git a/tests/solver.rs b/tests/solver.rs index a266ace..42ab32b 100644 --- a/tests/solver.rs +++ b/tests/solver.rs @@ -1332,9 +1332,9 @@ fn test_snapshot() { let mut snapshot_provider = snapshot.provider(); - let menu_req = snapshot_provider.add_package_requirement(menu_name_id); + let menu_req = snapshot_provider.add_package_requirement(menu_name_id, "*"); - assert_snapshot!(solve_for_snapshot(snapshot_provider, &[menu_req])); + assert_snapshot!(solve_for_snapshot(snapshot_provider, &[menu_req], &[])); } #[test] @@ -1354,12 +1354,40 @@ fn test_snapshot_union_requirements() { let mut snapshot_provider = snapshot.provider(); - let intl_req = snapshot_provider.add_package_requirement(intl_name_id); - let union_req = snapshot_provider.add_package_requirement(union_name_id); + let intl_req = snapshot_provider.add_package_requirement(intl_name_id, "*"); + let union_req = snapshot_provider.add_package_requirement(union_name_id, "*"); assert_snapshot!(solve_for_snapshot( snapshot_provider, - &[intl_req, union_req] + &[intl_req, union_req], + &[] + )); +} + +#[test] +fn test_root_constraints() { + let provider = BundleBoxProvider::from_packages(&[ + ("icons", 2, vec![]), + ("icons", 1, vec![]), + ("intl", 5, vec![]), + ("intl", 3, vec![]), + ("union", 1, vec!["icons"]), + ]); + + let icons_name_id = provider.package_name("icons"); + let union_name_id = provider.package_name("union"); + + let snapshot = provider.into_snapshot(); + + let mut snapshot_provider = snapshot.provider(); + + let union_req = snapshot_provider.add_package_requirement(union_name_id, "*"); + let icons_req = snapshot_provider.add_package_requirement(union_name_id, "5"); + + assert_snapshot!(solve_for_snapshot( + snapshot_provider, + &[union_req], + &[icons_req] )); } @@ -1401,9 +1429,10 @@ fn serialize_snapshot(snapshot: &DependencySnapshot, destination: impl AsRef String { +fn solve_for_snapshot(provider: SnapshotProvider, root_reqs: &[VersionSetId], root_constraints: &[VersionSetId]) -> String { let mut solver = Solver::new(provider); - let problem = Problem::new().requirements(root_reqs.iter().copied().map(Into::into).collect()); + let problem = Problem::new().requirements(root_reqs.iter().copied().map(Into::into).collect()) + .constraints(root_constraints.iter().copied().map(Into::into).collect()); match solver.solve(problem) { Ok(solvables) => transaction_to_string(solver.provider(), &solvables), Err(UnsolvableOrCancelled::Unsolvable(conflict)) => { diff --git a/tools/solve-snapshot/src/main.rs b/tools/solve-snapshot/src/main.rs index be7f732..901996c 100644 --- a/tools/solve-snapshot/src/main.rs +++ b/tools/solve-snapshot/src/main.rs @@ -88,7 +88,7 @@ fn main() { 0 => { // Add a package requirement let (package, _) = snapshot.packages.iter().choose(&mut rng).unwrap(); - let package_requirement = provider.add_package_requirement(package); + let package_requirement = provider.add_package_requirement(package, "*"); requirements.push(package_requirement.into()); } 1 => {