diff --git a/examples/unsat_root_message_no_version.rs b/examples/unsat_root_message_no_version.rs index ac258e34..5e0ac824 100644 --- a/examples/unsat_root_message_no_version.rs +++ b/examples/unsat_root_message_no_version.rs @@ -99,6 +99,13 @@ impl ReportFormatter> for CustomReportFormatter format!("{package} {package_set} depends on {dependency} {dependency_set}") } } + External::UnusableDependencies(package, set, ..) => { + if set == &Range::full() { + format!("dependencies of {package} are unusable") + } else { + format!("dependencies of {package} at version {set} are unusable") + } + } } } } diff --git a/src/internal/core.rs b/src/internal/core.rs index b3d3fb22..ec73647d 100644 --- a/src/internal/core.rs +++ b/src/internal/core.rs @@ -25,6 +25,7 @@ pub struct State { root_package: P, root_version: VS::V, + /// The set of incompatibilities for each package. pub incompatibilities: Map>>, /// Store the ids of incompatibilities that are already contradicted. diff --git a/src/internal/incompatibility.rs b/src/internal/incompatibility.rs index 48d63761..78c39b00 100644 --- a/src/internal/incompatibility.rs +++ b/src/internal/incompatibility.rs @@ -34,12 +34,14 @@ use crate::version_set::VersionSet; #[derive(Debug, Clone)] pub struct Incompatibility { package_terms: SmallMap>, + /// The reason why this version or combination of versions can't be selected. pub kind: Kind, } /// Type alias of unique identifiers for incompatibilities. pub type IncompId = Id>; +/// The reason why a version or combination of versions can't be selected. #[derive(Debug, Clone)] pub enum Kind { /// Initial incompatibility aiming at picking the root package for the first decision. @@ -48,6 +50,8 @@ pub enum Kind { NoVersions(P, VS), /// Dependencies of the package are unavailable for versions in that range. UnavailableDependencies(P, VS), + /// Dependencies of the package are unusable for versions in that range. + UnusableDependencies(P, VS, Option), /// Incompatibility coming from the dependencies of a given package. FromDependencyOf(P, VS, P, VS), /// Derived from two causes. Stores cause ids. @@ -107,6 +111,17 @@ impl Incompatibility { } } + /// Create an incompatibility to remember + /// that a package version is not selectable + /// because its dependencies are not usable. + pub fn unusable_dependencies(package: P, version: VS::V, reason: Option) -> Self { + let set = VS::singleton(version); + Self { + package_terms: SmallMap::One([(package.clone(), Term::Positive(set.clone()))]), + kind: Kind::UnusableDependencies(package, set, reason), + } + } + /// Build an incompatibility from a given dependency. pub fn from_dependency(package: P, versions: VS, dep: (&P, &VS)) -> Self { let (p2, set2) = dep; @@ -123,6 +138,7 @@ impl Incompatibility { } } + /// The two packages causing the incompatibility, if it was derived from dependencies. pub fn as_dependency(&self) -> Option<(&P, &P)> { match &self.kind { Kind::FromDependencyOf(p1, _, p2, _) => Some((p1, p2)), @@ -255,6 +271,9 @@ impl Incompatibility { Kind::UnavailableDependencies(package, set) => { DerivationTree::External(External::UnavailableDependencies(package, set)) } + Kind::UnusableDependencies(package, set, reason) => { + DerivationTree::External(External::UnusableDependencies(package, set, reason)) + } Kind::FromDependencyOf(package, set, dep_package, dep_set) => DerivationTree::External( External::FromDependencyOf(package, set, dep_package, dep_set), ), diff --git a/src/report.rs b/src/report.rs index 481d06e9..33b90c6d 100644 --- a/src/report.rs +++ b/src/report.rs @@ -49,6 +49,8 @@ pub enum External { NoVersions(P, VS), /// Dependencies of the package are unavailable for versions in that set. UnavailableDependencies(P, VS), + /// Dependencies of the package are unusable for versions in that set. + UnusableDependencies(P, VS, Option), /// Incompatibility coming from the dependencies of a given package. FromDependencyOf(P, VS, P, VS), } @@ -124,6 +126,13 @@ impl DerivationTree { DerivationTree::External(External::UnavailableDependencies(_, r)) => Some( DerivationTree::External(External::UnavailableDependencies(package, set.union(&r))), ), + DerivationTree::External(External::UnusableDependencies(_, r, reason)) => { + Some(DerivationTree::External(External::UnusableDependencies( + package, + set.union(&r), + reason, + ))) + } DerivationTree::External(External::FromDependencyOf(p1, r1, p2, r2)) => { if p1 == package { Some(DerivationTree::External(External::FromDependencyOf( @@ -169,6 +178,29 @@ impl fmt::Display for External { ) } } + Self::UnusableDependencies(package, set, reason) => { + if let Some(reason) = reason { + if set == &VS::full() { + write!(f, "dependencies of {} are unusable: {reason}", package) + } else { + write!( + f, + "dependencies of {} at version {} are unusable: {reason}", + package, set + ) + } + } else { + if set == &VS::full() { + write!(f, "dependencies of {} are unusable", package) + } else { + write!( + f, + "dependencies of {} at version {} are unusable", + package, set + ) + } + } + } Self::FromDependencyOf(p, set_p, dep, set_dep) => { if set_p == &VS::full() && set_dep == &VS::full() { write!(f, "{} depends on {}", p, dep) diff --git a/tests/examples.rs b/tests/examples.rs index f968bba1..8bcc8c74 100644 --- a/tests/examples.rs +++ b/tests/examples.rs @@ -231,12 +231,12 @@ fn confusing_with_lots_of_holes() { }; assert_eq!( &DefaultStringReporter::report(&derivation_tree), - r#"Because there is no available version for bar and foo 1 | 2 | 3 | 4 | 5 depends on bar, foo 1 | 2 | 3 | 4 | 5 is forbidden. -And because there is no version of foo in <1 | >1, <2 | >2, <3 | >3, <4 | >4, <5 | >5 and root 1 depends on foo, root 1 is forbidden."# + r#"Because there is no available version for bar and foo ==1, ==2, ==3, ==4, ==5 depends on bar, foo ==1, ==2, ==3, ==4, ==5 is forbidden. +And because there is no version of foo in <1, >1, <2, >2, <3, >3, <4, >4, <5, >5 and root ==1 depends on foo, root ==1 is forbidden."# ); derivation_tree.collapse_no_versions(); assert_eq!( &DefaultStringReporter::report(&derivation_tree), - "Because foo depends on bar and root 1 depends on foo, root 1 is forbidden." + "Because foo depends on bar and root ==1 depends on foo, root ==1 is forbidden." ); }