diff --git a/src/conflict.rs b/src/conflict.rs index 15fb086..4a7276b 100644 --- a/src/conflict.rs +++ b/src/conflict.rs @@ -982,7 +982,14 @@ impl<'i, I: Interner> fmt::Display for DisplayUnsat<'i, I> { // The only possible conflict at the root level is a Locked conflict match conflict { - ConflictCause::Constrains(_) | ConflictCause::ForbidMultipleInstances => { + &ConflictCause::Constrains(version_set_id) => { + writeln!( + f, + "{indent}constraint '{version_set}' cannot be fulfilled", + version_set = self.interner.display_version_set(version_set_id), + )?; + } + &ConflictCause::ForbidMultipleInstances => { unreachable!() } &ConflictCause::Locked(solvable_id) => { diff --git a/src/snapshot.rs b/src/snapshot.rs index 08b3fab..fcef386 100644 --- a/src/snapshot.rs +++ b/src/snapshot.rs @@ -355,19 +355,29 @@ impl<'s> SnapshotProvider<'s> { } } - /// Adds another requirement that matches any version of a package - pub fn add_package_requirement(&mut self, name: NameId) -> VersionSetId { + /// Adds another requirement that matches any version of a package. + /// If you use "*" as the matcher, it will match any version of the package. + 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 { + let matching_candidates = package + .solvables + .iter() + .copied() + .filter(|&s| matcher == "*" || self.solvable(s).display.contains(matcher)) + .collect(); + + self.additional_version_sets.push(VersionSet { name, - display: "*".to_string(), - matching_candidates: package.solvables.iter().copied().collect(), - }; + display: if matcher == "*" { + "*".to_string() + } else { + format!("{} {}", package.name, matcher) + }, + matching_candidates, + }); - self.additional_version_sets.push(version_set); VersionSetId::from_usize(id) } diff --git a/tests/snapshots/solver__root_constraints.snap b/tests/snapshots/solver__root_constraints.snap new file mode 100644 index 0000000..f498bff --- /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 +├─ constraint 'union 5' cannot be fulfilled diff --git a/tests/solver.rs b/tests/solver.rs index a266ace..61494c7 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,34 @@ 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", 1, vec![]), ("union", 1, vec!["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 union_constraint = snapshot_provider.add_package_requirement(union_name_id, "5"); + + assert_snapshot!(solve_for_snapshot( + snapshot_provider, + &[union_req], + &[union_constraint] )); } @@ -1401,9 +1423,15 @@ 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 => {