Skip to content

Commit

Permalink
Add an UnusableDependencies incompatibility kind (#4)
Browse files Browse the repository at this point in the history
  • Loading branch information
zanieb authored and konstin committed Mar 12, 2024
1 parent eb256c2 commit c8f56b2
Show file tree
Hide file tree
Showing 5 changed files with 62 additions and 3 deletions.
7 changes: 7 additions & 0 deletions examples/unsat_root_message_no_version.rs
Original file line number Diff line number Diff line change
Expand Up @@ -99,6 +99,13 @@ impl ReportFormatter<Package, Range<SemanticVersion>> 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")
}
}
}
}
}
Expand Down
1 change: 1 addition & 0 deletions src/internal/core.rs
Original file line number Diff line number Diff line change
Expand Up @@ -25,6 +25,7 @@ pub struct State<P: Package, VS: VersionSet, Priority: Ord + Clone> {
root_package: P,
root_version: VS::V,

/// The set of incompatibilities for each package.
pub incompatibilities: Map<P, Vec<IncompId<P, VS>>>,

/// Store the ids of incompatibilities that are already contradicted.
Expand Down
19 changes: 19 additions & 0 deletions src/internal/incompatibility.rs
Original file line number Diff line number Diff line change
Expand Up @@ -34,12 +34,14 @@ use crate::version_set::VersionSet;
#[derive(Debug, Clone)]
pub struct Incompatibility<P: Package, VS: VersionSet> {
package_terms: SmallMap<P, Term<VS>>,
/// The reason why this version or combination of versions can't be selected.
pub kind: Kind<P, VS>,
}

/// Type alias of unique identifiers for incompatibilities.
pub type IncompId<P, VS> = Id<Incompatibility<P, VS>>;

/// The reason why a version or combination of versions can't be selected.
#[derive(Debug, Clone)]
pub enum Kind<P: Package, VS: VersionSet> {
/// Initial incompatibility aiming at picking the root package for the first decision.
Expand All @@ -48,6 +50,8 @@ pub enum Kind<P: Package, VS: VersionSet> {
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<String>),
/// Incompatibility coming from the dependencies of a given package.
FromDependencyOf(P, VS, P, VS),
/// Derived from two causes. Stores cause ids.
Expand Down Expand Up @@ -107,6 +111,17 @@ impl<P: Package, VS: VersionSet> Incompatibility<P, VS> {
}
}

/// 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<String>) -> 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;
Expand All @@ -123,6 +138,7 @@ impl<P: Package, VS: VersionSet> Incompatibility<P, VS> {
}
}

/// 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)),
Expand Down Expand Up @@ -255,6 +271,9 @@ impl<P: Package, VS: VersionSet> Incompatibility<P, VS> {
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),
),
Expand Down
32 changes: 32 additions & 0 deletions src/report.rs
Original file line number Diff line number Diff line change
Expand Up @@ -49,6 +49,8 @@ pub enum External<P: Package, VS: VersionSet> {
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<String>),
/// Incompatibility coming from the dependencies of a given package.
FromDependencyOf(P, VS, P, VS),
}
Expand Down Expand Up @@ -124,6 +126,13 @@ impl<P: Package, VS: VersionSet> DerivationTree<P, VS> {
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(
Expand Down Expand Up @@ -169,6 +178,29 @@ impl<P: Package, VS: VersionSet> fmt::Display for External<P, VS> {
)
}
}
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)
Expand Down
6 changes: 3 additions & 3 deletions tests/examples.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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."
);
}

0 comments on commit c8f56b2

Please sign in to comment.