-
Notifications
You must be signed in to change notification settings - Fork 38
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
feat: constraining dependencies #124
base: dev
Are you sure you want to change the base?
Changes from all commits
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -105,7 +105,7 @@ impl<P: Package, VS: VersionSet> Incompatibility<P, VS> { | |
} | ||
|
||
/// Build an incompatibility from a given dependency. | ||
pub fn from_dependency(package: P, version: VS::V, dep: (&P, &VS)) -> Self { | ||
pub fn from_required_dependency(package: P, version: VS::V, dep: (&P, &VS)) -> Self { | ||
let set1 = VS::singleton(version); | ||
let (p2, set2) = dep; | ||
Self { | ||
|
@@ -117,6 +117,19 @@ impl<P: Package, VS: VersionSet> Incompatibility<P, VS> { | |
} | ||
} | ||
|
||
/// Build an incompatibility from a given constraint. | ||
pub fn from_constrained_dependency(package: P, version: VS::V, dep: (&P, &VS)) -> Self { | ||
let set1 = VS::singleton(version); | ||
let (p2, set2) = dep; | ||
Self { | ||
package_terms: SmallMap::Two([ | ||
(package.clone(), Term::Positive(set1.clone())), | ||
(p2.clone(), Term::Positive(set2.complement())), | ||
]), | ||
kind: Kind::FromDependencyOf(package, set1, p2.clone(), set2.clone()), | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Currently weather it is constrained or required does not appear in the kind at all. This does not affect the correctness of the algorithm, as kind is only used for error messages. Do we think it's important to have this distinction available when generating error messages?
Allso, is |
||
} | ||
} | ||
|
||
/// Prior cause of two incompatibilities using the rule of resolution. | ||
pub fn prior_cause( | ||
incompat: Id<Self>, | ||
|
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -166,7 +166,10 @@ pub fn resolve<P: Package, VS: VersionSet>( | |
version: v.clone(), | ||
}); | ||
} | ||
if let Some((dependent, _)) = x.iter().find(|(_, r)| r == &&VS::empty()) { | ||
if let Some((dependent, _)) = x | ||
.iter() | ||
.find(|(_, r)| matches!(r, Requirement::Required(r) if r == &VS::empty())) | ||
{ | ||
return Err(PubGrubError::DependencyOnTheEmptySet { | ||
package: p.clone(), | ||
version: v.clone(), | ||
|
@@ -215,7 +218,17 @@ pub enum Dependencies<P: Package, VS: VersionSet> { | |
/// Package dependencies are unavailable. | ||
Unknown, | ||
/// Container for all available package versions. | ||
Known(DependencyConstraints<P, VS>), | ||
Known(DependencyConstraints<P, Requirement<VS>>), | ||
} | ||
|
||
/// An enum that defines the type of dependency. | ||
#[derive(Clone, Debug)] | ||
pub enum Requirement<VS: VersionSet> { | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. this will need to There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Or we could decide to break compatibility of serialized data? or start defining a serialized format more in line with the internal representation of incompatiblities (list of pairs of pkg, and +/- version set) which is not going to change soon as this would not be a "pubgrub" algorithm anymore? Then will have manually written serialize and deserializers. |
||
/// A dependency that is resolved as part of the solution. | ||
Required(VS), | ||
|
||
/// Constrains the version of package but does not require inclusion of the package. | ||
Constrained(VS), | ||
} | ||
|
||
/// Trait that allows the algorithm to retrieve available packages and their dependencies. | ||
|
@@ -311,7 +324,7 @@ where | |
)] | ||
#[cfg_attr(feature = "serde", serde(transparent))] | ||
pub struct OfflineDependencyProvider<P: Package, VS: VersionSet> { | ||
dependencies: Map<P, BTreeMap<VS::V, DependencyConstraints<P, VS>>>, | ||
dependencies: Map<P, BTreeMap<VS::V, DependencyConstraints<P, Requirement<VS>>>>, | ||
} | ||
|
||
impl<P: Package, VS: VersionSet> OfflineDependencyProvider<P, VS> { | ||
|
@@ -324,10 +337,11 @@ impl<P: Package, VS: VersionSet> OfflineDependencyProvider<P, VS> { | |
|
||
/// Registers the dependencies of a package and version pair. | ||
/// Dependencies must be added with a single call to | ||
/// [add_dependencies](OfflineDependencyProvider::add_dependencies). | ||
/// All subsequent calls to | ||
/// [add_dependencies](OfflineDependencyProvider::add_dependencies) for a given | ||
/// package version pair will replace the dependencies by the new ones. | ||
/// [add_dependencies](OfflineDependencyProvider::add_dependencies), | ||
/// [add_constraints](OfflineDependencyProvider::add_constraints), or | ||
/// [add_requirements](OfflineDependencyProvider::add_requirements). | ||
/// All subsequent calls to any of those functions for a given package version pair will replace the | ||
/// dependencies by the new ones. | ||
/// | ||
/// The API does not allow to add dependencies one at a time to uphold an assumption that | ||
/// [OfflineDependencyProvider.get_dependencies(p, v)](OfflineDependencyProvider::get_dependencies) | ||
|
@@ -338,14 +352,76 @@ impl<P: Package, VS: VersionSet> OfflineDependencyProvider<P, VS> { | |
version: impl Into<VS::V>, | ||
dependencies: I, | ||
) { | ||
let package_deps = dependencies.into_iter().collect(); | ||
let v = version.into(); | ||
*self | ||
let entries = self | ||
.dependencies | ||
.entry(package) | ||
.or_default() | ||
.entry(v) | ||
.or_default(); | ||
for (dep, range) in dependencies.into_iter() { | ||
entries.insert(dep, Requirement::Required(range)); | ||
} | ||
} | ||
|
||
/// Registers the dependencies of a package and version pair that may *not* be included in the final | ||
/// solution but if it is included in the solution (through another package for example) it must meet | ||
/// the requirements defined in this function call.. | ||
/// Dependencies must be added with a single call to | ||
/// [add_dependencies](OfflineDependencyProvider::add_dependencies), | ||
/// [add_constraints](OfflineDependencyProvider::add_constraints), or | ||
/// [add_requirements](OfflineDependencyProvider::add_requirements). | ||
/// All subsequent calls to any of those functions for a given package version pair will replace the | ||
/// dependencies by the new ones. | ||
/// | ||
/// The API does not allow to add dependencies one at a time to uphold an assumption that | ||
/// [OfflineDependencyProvider.get_dependencies(p, v)](OfflineDependencyProvider::get_dependencies) | ||
/// provides all dependencies of a given package (p) and version (v) pair. | ||
pub fn add_constraints<I: IntoIterator<Item = (P, VS)>>( | ||
&mut self, | ||
package: P, | ||
version: impl Into<VS::V>, | ||
dependencies: I, | ||
) { | ||
let v = version.into(); | ||
let entries = self | ||
.dependencies | ||
.entry(package) | ||
.or_default() | ||
.entry(v) | ||
.or_default(); | ||
for (package, constraint) in dependencies.into_iter() { | ||
entries.insert(package, Requirement::Constrained(constraint)); | ||
} | ||
} | ||
|
||
/// Registers the dependencies of a package and version pair. | ||
/// Dependencies must be added with a single call to | ||
/// [add_dependencies](OfflineDependencyProvider::add_dependencies), | ||
/// [add_constraints](OfflineDependencyProvider::add_constraints), or | ||
/// [add_requirements](OfflineDependencyProvider::add_requirements). | ||
/// All subsequent calls to any of those functions for a given package version pair will replace the | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. This is no longer true. At a minimum these comments need to be updated. These calls now append items to an existing list. There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Indeed, I'm not a big fan of making it easy for people to make mistakes. I'd say we probably make |
||
/// dependencies by the new ones. | ||
/// | ||
/// The API does not allow to add dependencies one at a time to uphold an assumption that | ||
/// [OfflineDependencyProvider.get_dependencies(p, v)](OfflineDependencyProvider::get_dependencies) | ||
/// provides all dependencies of a given package (p) and version (v) pair. | ||
pub fn add_requirements<I: IntoIterator<Item = (P, Requirement<VS>)>>( | ||
&mut self, | ||
package: P, | ||
version: impl Into<VS::V>, | ||
dependencies: I, | ||
) { | ||
let v = version.into(); | ||
let entries = self | ||
.dependencies | ||
.entry(package) | ||
.or_default() | ||
.entry(v) | ||
.or_default() = package_deps; | ||
.or_default(); | ||
for (package, req) in dependencies.into_iter() { | ||
entries.insert(package, req); | ||
} | ||
} | ||
|
||
/// Lists packages that have been saved. | ||
|
@@ -361,7 +437,11 @@ impl<P: Package, VS: VersionSet> OfflineDependencyProvider<P, VS> { | |
|
||
/// Lists dependencies of a given package and version. | ||
/// Returns [None] if no information is available regarding that package and version pair. | ||
fn dependencies(&self, package: &P, version: &VS::V) -> Option<DependencyConstraints<P, VS>> { | ||
fn dependencies( | ||
&self, | ||
package: &P, | ||
version: &VS::V, | ||
) -> Option<DependencyConstraints<P, Requirement<VS>>> { | ||
self.dependencies.get(package)?.get(version).cloned() | ||
} | ||
} | ||
|
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I'd suggest rename
dep
intop
orpkg
here to fit with the type annotation