Remove PubGrubVersion (#924)

## Summary

I'm running into some annoyances converting `&Version` to
`&PubGrubVersion` (which is just a wrapper type around `Version`), and I
realized... We don't even need `PubGrubVersion`?

The reason we "need" it today is due to the orphan trait rule: `Version`
is defined in `pep440_rs`, but we want to `impl
pubgrub::version::Version for Version` in the resolver crate.

Instead of introducing a new type here, which leads to a lot of
awkwardness around conversion and API isolation, what if we instead just
implement `pubgrub::version::Version` in `pep440_rs` via a feature? That
way, we can just use `Version` everywhere without any confusion and
conversion for the wrapper type.
This commit is contained in:
Charlie Marsh 2024-01-15 08:51:12 -05:00 committed by GitHub
parent 8860a9c29e
commit 9a3f3d385c
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
20 changed files with 179 additions and 254 deletions

2
Cargo.lock generated
View file

@ -2045,6 +2045,8 @@ name = "pep440_rs"
version = "0.3.12"
dependencies = [
"indoc",
"once_cell",
"pubgrub",
"pyo3",
"serde",
"tracing",

View file

@ -17,6 +17,8 @@ name = "pep440_rs"
crate-type = ["rlib", "cdylib"]
[dependencies]
once_cell = { workspace = true }
pubgrub = { workspace = true, optional = true }
pyo3 = { workspace = true, optional = true, features = ["extension-module", "abi3-py37"] }
serde = { workspace = true, features = ["derive"], optional = true }
tracing = { workspace = true, optional = true }
@ -24,4 +26,4 @@ unicode-width = { workspace = true }
unscanny = { workspace = true }
[dev-dependencies]
indoc = "2.0.4"
indoc = { version = "2.0.4" }

View file

@ -34,29 +34,26 @@
//! the version matching needs to catch all sorts of special cases
#![deny(missing_docs)]
#[cfg(feature = "pyo3")]
pub use version::PyVersion;
pub use {
version::{
LocalSegment, Operator, OperatorParseError, PreRelease, Version, VersionParseError,
VersionPattern, VersionPatternParseError,
VersionPattern, VersionPatternParseError, MIN_VERSION,
},
version_specifier::{
parse_version_specifiers, VersionSpecifier, VersionSpecifiers, VersionSpecifiersParseError,
},
};
#[cfg(feature = "pyo3")]
use pyo3::{pymodule, types::PyModule, PyResult, Python};
#[cfg(feature = "pyo3")]
pub use version::PyVersion;
mod version;
mod version_specifier;
/// Python bindings shipped as `pep440_rs`
#[cfg(feature = "pyo3")]
#[pymodule]
#[pyo3::pymodule]
#[pyo3(name = "_pep440_rs")]
pub fn python_module(_py: Python, module: &PyModule) -> PyResult<()> {
pub fn python_module(_py: pyo3::Python, module: &pyo3::types::PyModule) -> pyo3::PyResult<()> {
module.add_class::<PyVersion>()?;
module.add_class::<Operator>()?;
module.add_class::<VersionSpecifier>()?;

View file

@ -2194,6 +2194,29 @@ fn parse_u64(bytes: &[u8]) -> Result<u64, VersionParseError> {
Ok(n)
}
/// The minimum version that can be represented by a [`Version`].
pub static MIN_VERSION: once_cell::sync::Lazy<Version> =
once_cell::sync::Lazy::new(|| Version::from_str("0a0.dev0").unwrap());
#[cfg(feature = "pubgrub")]
impl pubgrub::version::Version for Version {
fn lowest() -> Self {
MIN_VERSION.to_owned()
}
fn bump(&self) -> Self {
let mut next = self.clone();
if let Some(dev) = next.dev() {
next = next.with_dev(Some(dev + 1));
} else if let Some(post) = next.post() {
next = next.with_post(Some(post + 1));
} else {
next = next.with_post(Some(0)).with_dev(Some(0));
}
next
}
}
#[cfg(test)]
mod tests {
use std::str::FromStr;

View file

@ -13,18 +13,10 @@ use pep440_rs::Version;
use platform_tags::Tags;
use puffin_normalize::PackageName;
#[derive(Debug, Clone)]
pub struct FlatIndex<T: Into<Version> + From<Version> + Ord>(
pub BTreeMap<T, PrioritizedDistribution>,
);
#[derive(Debug, Clone, Default)]
pub struct FlatIndex(pub BTreeMap<Version, PrioritizedDistribution>);
impl<T: Into<Version> + From<Version> + Ord> Default for FlatIndex<T> {
fn default() -> Self {
Self(BTreeMap::default())
}
}
impl<T: Into<Version> + From<Version> + Ord> FlatIndex<T> {
impl FlatIndex {
/// Collect all the files from `--find-links` into a override hashmap we can pass into version map creation.
#[instrument(skip_all)]
pub fn from_files(
@ -44,7 +36,7 @@ impl<T: Into<Version> + From<Version> + Ord> FlatIndex<T> {
}
fn add_file(
version_map: &mut FlatIndex<T>,
version_map: &mut FlatIndex,
file: File,
filename: DistFilename,
tags: &Tags,
@ -62,7 +54,7 @@ impl<T: Into<Version> + From<Version> + Ord> FlatIndex<T> {
file,
index,
}));
match version_map.0.entry(version.into()) {
match version_map.0.entry(version) {
Entry::Occupied(mut entry) => {
entry.get_mut().insert_built(dist, None, None, priority);
}
@ -79,7 +71,7 @@ impl<T: Into<Version> + From<Version> + Ord> FlatIndex<T> {
file,
index,
}));
match version_map.0.entry(filename.version.clone().into()) {
match version_map.0.entry(filename.version.clone()) {
Entry::Occupied(mut entry) => {
entry.get_mut().insert_source(dist, None, None);
}
@ -91,7 +83,7 @@ impl<T: Into<Version> + From<Version> + Ord> FlatIndex<T> {
}
}
pub fn iter(&self) -> impl Iterator<Item = (&T, &PrioritizedDistribution)> {
pub fn iter(&self) -> impl Iterator<Item = (&Version, &PrioritizedDistribution)> {
self.0.iter()
}
}

View file

@ -17,7 +17,7 @@ cache-key = { path = "../cache-key" }
distribution-filename = { path = "../distribution-filename", features = ["serde"] }
distribution-types = { path = "../distribution-types" }
install-wheel-rs = { path = "../install-wheel-rs" }
pep440_rs = { path = "../pep440-rs" }
pep440_rs = { path = "../pep440-rs", features = ["pubgrub"] }
pep508_rs = { path = "../pep508-rs" }
platform-host = { path = "../platform-host" }
platform-tags = { path = "../platform-tags" }

View file

@ -3,12 +3,11 @@ use rustc_hash::FxHashMap;
use distribution_types::{Dist, DistributionMetadata, Name};
use distribution_types::{DistRequiresPython, ResolvableDist};
use pep440_rs::VersionSpecifiers;
use pep440_rs::{Version, VersionSpecifiers};
use pep508_rs::{Requirement, VersionOrUrl};
use puffin_normalize::PackageName;
use crate::prerelease_mode::PreReleaseStrategy;
use crate::pubgrub::PubGrubVersion;
use crate::python_requirement::PythonRequirement;
use crate::resolution_mode::ResolutionStrategy;
use crate::version_map::VersionMap;
@ -52,10 +51,10 @@ impl CandidateSelector {
/// A set of pinned packages that should be preserved during resolution, if possible.
#[derive(Debug, Clone)]
struct Preferences(FxHashMap<PackageName, PubGrubVersion>);
struct Preferences(FxHashMap<PackageName, Version>);
impl Preferences {
fn get(&self, package_name: &PackageName) -> Option<&PubGrubVersion> {
fn get(&self, package_name: &PackageName) -> Option<&Version> {
self.0.get(package_name)
}
}
@ -74,8 +73,10 @@ impl From<&[Requirement]> for Preferences {
let [version_specifier] = version_specifiers.as_ref() else {
return None;
};
let version = PubGrubVersion::from(version_specifier.version().clone());
Some((requirement.name.clone(), version))
Some((
requirement.name.clone(),
version_specifier.version().clone(),
))
})
.collect(),
)
@ -94,7 +95,7 @@ impl CandidateSelector {
pub(crate) fn select<'a>(
&'a self,
package_name: &'a PackageName,
range: &Range<PubGrubVersion>,
range: &Range<Version>,
version_map: &'a VersionMap,
) -> Option<Candidate<'a>> {
// If the package has a preference (e.g., an existing version from an existing lockfile),
@ -161,15 +162,15 @@ impl CandidateSelector {
/// Select the first-matching [`Candidate`] from a set of candidate versions and files,
/// preferring wheels over source distributions.
fn select_candidate<'a>(
versions: impl Iterator<Item = (&'a PubGrubVersion, ResolvableDist<'a>)>,
versions: impl Iterator<Item = (&'a Version, ResolvableDist<'a>)>,
package_name: &'a PackageName,
range: &Range<PubGrubVersion>,
range: &Range<Version>,
allow_prerelease: AllowPreRelease,
) -> Option<Candidate<'a>> {
#[derive(Debug)]
enum PreReleaseCandidate<'a> {
NotNecessary,
IfNecessary(&'a PubGrubVersion, ResolvableDist<'a>),
IfNecessary(&'a Version, ResolvableDist<'a>),
}
let mut prerelease = None;
@ -221,13 +222,13 @@ pub(crate) struct Candidate<'a> {
/// The name of the package.
name: &'a PackageName,
/// The version of the package.
version: &'a PubGrubVersion,
version: &'a Version,
/// The file to use for resolving and installing the package.
dist: ResolvableDist<'a>,
}
impl<'a> Candidate<'a> {
fn new(name: &'a PackageName, version: &'a PubGrubVersion, dist: ResolvableDist<'a>) -> Self {
fn new(name: &'a PackageName, version: &'a Version, dist: ResolvableDist<'a>) -> Self {
Self {
name,
version,
@ -241,7 +242,7 @@ impl<'a> Candidate<'a> {
}
/// Return the version of the package.
pub(crate) fn version(&self) -> &PubGrubVersion {
pub(crate) fn version(&self) -> &Version {
self.version
}
@ -299,6 +300,6 @@ impl Name for Candidate<'_> {
impl DistributionMetadata for Candidate<'_> {
fn version_or_url(&self) -> distribution_types::VersionOrUrl {
distribution_types::VersionOrUrl::Version(self.version.into())
distribution_types::VersionOrUrl::Version(self.version)
}
}

View file

@ -8,13 +8,14 @@ use thiserror::Error;
use url::Url;
use distribution_types::{BuiltDist, PathBuiltDist, PathSourceDist, SourceDist};
use pep440_rs::Version;
use pep508_rs::Requirement;
use puffin_distribution::DistributionDatabaseError;
use puffin_normalize::PackageName;
use puffin_traits::OnceMap;
use crate::candidate_selector::CandidateSelector;
use crate::pubgrub::{PubGrubPackage, PubGrubPython, PubGrubReportFormatter, PubGrubVersion};
use crate::pubgrub::{PubGrubPackage, PubGrubPython, PubGrubReportFormatter};
use crate::python_requirement::PythonRequirement;
use crate::version_map::VersionMap;
@ -76,7 +77,7 @@ pub enum ResolveError {
/// Package whose dependencies we want.
package: Box<PubGrubPackage>,
/// Version of the package for which we want the dependencies.
version: Box<PubGrubVersion>,
version: Box<Version>,
},
/// Something unexpected happened.
@ -90,11 +91,11 @@ impl<T> From<futures::channel::mpsc::TrySendError<T>> for ResolveError {
}
}
impl From<pubgrub::error::PubGrubError<PubGrubPackage, Range<PubGrubVersion>, Infallible>>
impl From<pubgrub::error::PubGrubError<PubGrubPackage, Range<Version>, Infallible>>
for ResolveError
{
fn from(
value: pubgrub::error::PubGrubError<PubGrubPackage, Range<PubGrubVersion>, Infallible>,
value: pubgrub::error::PubGrubError<PubGrubPackage, Range<Version>, Infallible>,
) -> Self {
match value {
// These are all never type variant that can never match, but never is experimental
@ -124,8 +125,8 @@ impl From<pubgrub::error::PubGrubError<PubGrubPackage, Range<PubGrubVersion>, In
/// A wrapper around [`pubgrub::error::PubGrubError::NoSolution`] that displays a resolution failure report.
#[derive(Debug)]
pub struct NoSolutionError {
derivation_tree: DerivationTree<PubGrubPackage, Range<PubGrubVersion>>,
available_versions: FxHashMap<PubGrubPackage, Vec<PubGrubVersion>>,
derivation_tree: DerivationTree<PubGrubPackage, Range<Version>>,
available_versions: FxHashMap<PubGrubPackage, Vec<Version>>,
selector: Option<CandidateSelector>,
}
@ -169,14 +170,12 @@ impl NoSolutionError {
PubGrubPackage::Python(PubGrubPython::Installed) => {
available_versions.insert(
package.clone(),
vec![PubGrubVersion::from(python_requirement.installed().clone())],
vec![python_requirement.installed().clone()],
);
}
PubGrubPackage::Python(PubGrubPython::Target) => {
available_versions.insert(
package.clone(),
vec![PubGrubVersion::from(python_requirement.target().clone())],
);
available_versions
.insert(package.clone(), vec![python_requirement.target().clone()]);
}
PubGrubPackage::Package(name, ..) => {
if let Some(entry) = package_versions.get(name) {

View file

@ -8,7 +8,6 @@ use rustc_hash::FxHashMap;
use distribution_filename::DistFilename;
use distribution_types::{Dist, IndexUrl, Resolution};
use pep440_rs::Version;
use pep508_rs::{Requirement, VersionOrUrl};
use platform_tags::Tags;
use puffin_client::{FlatIndex, RegistryClient, SimpleMetadata};
@ -22,7 +21,7 @@ pub struct DistFinder<'a> {
client: &'a RegistryClient,
reporter: Option<Box<dyn Reporter>>,
interpreter: &'a Interpreter,
flat_index: &'a FxHashMap<PackageName, FlatIndex<Version>>,
flat_index: &'a FxHashMap<PackageName, FlatIndex>,
}
impl<'a> DistFinder<'a> {
@ -31,7 +30,7 @@ impl<'a> DistFinder<'a> {
tags: &'a Tags,
client: &'a RegistryClient,
interpreter: &'a Interpreter,
flat_index: &'a FxHashMap<PackageName, FlatIndex<Version>>,
flat_index: &'a FxHashMap<PackageName, FlatIndex>,
) -> Self {
Self {
tags,
@ -57,7 +56,7 @@ impl<'a> DistFinder<'a> {
async fn resolve_requirement(
&self,
requirement: &Requirement,
flat_index: Option<&FlatIndex<Version>>,
flat_index: Option<&FlatIndex>,
) -> Result<(PackageName, Dist), ResolveError> {
match requirement.version_or_url.as_ref() {
None | Some(VersionOrUrl::VersionSpecifier(_)) => {
@ -119,7 +118,7 @@ impl<'a> DistFinder<'a> {
requirement: &Requirement,
metadata: SimpleMetadata,
index: &IndexUrl,
flat_index: Option<&FlatIndex<Version>>,
flat_index: Option<&FlatIndex>,
) -> Option<Dist> {
// Prioritize the flat index by initializing the "best" matches with its entries.
let matching_override = if let Some(flat_index) = flat_index {

View file

@ -16,7 +16,7 @@ impl FilePins {
/// Pin a candidate package.
pub(crate) fn insert(&mut self, candidate: &Candidate) {
self.0.entry(candidate.name().clone()).or_default().insert(
candidate.version().clone().into(),
candidate.version().clone(),
candidate.install().dist.clone(),
);
}

View file

@ -1,4 +1,5 @@
use itertools::Itertools;
use pep440_rs::Version;
use pubgrub::range::Range;
use pubgrub::type_aliases::DependencyConstraints;
use tracing::warn;
@ -8,11 +9,11 @@ use puffin_normalize::{ExtraName, PackageName};
use crate::overrides::Overrides;
use crate::pubgrub::specifier::PubGrubSpecifier;
use crate::pubgrub::{PubGrubPackage, PubGrubVersion};
use crate::pubgrub::PubGrubPackage;
use crate::ResolveError;
#[derive(Debug)]
pub struct PubGrubDependencies(DependencyConstraints<PubGrubPackage, Range<PubGrubVersion>>);
pub struct PubGrubDependencies(DependencyConstraints<PubGrubPackage, Range<Version>>);
impl PubGrubDependencies {
/// Generate a set of `PubGrub` dependencies from a set of requirements.
@ -24,8 +25,7 @@ impl PubGrubDependencies {
source: Option<&PackageName>,
env: &MarkerEnvironment,
) -> Result<Self, ResolveError> {
let mut dependencies =
DependencyConstraints::<PubGrubPackage, Range<PubGrubVersion>>::default();
let mut dependencies = DependencyConstraints::<PubGrubPackage, Range<Version>>::default();
// Iterate over all declared requirements.
for requirement in overrides.apply(requirements) {
@ -126,23 +126,23 @@ impl PubGrubDependencies {
Ok(Self(dependencies))
}
/// Insert a [`PubGrubPackage`] and [`PubGrubVersion`] range into the set of dependencies.
/// Insert a [`PubGrubPackage`] and [`Version`] range into the set of dependencies.
pub(crate) fn insert(
&mut self,
package: PubGrubPackage,
version: Range<PubGrubVersion>,
) -> Option<Range<PubGrubVersion>> {
version: Range<Version>,
) -> Option<Range<Version>> {
self.0.insert(package, version)
}
/// Iterate over the dependencies.
pub(crate) fn iter(&self) -> impl Iterator<Item = (&PubGrubPackage, &Range<PubGrubVersion>)> {
pub(crate) fn iter(&self) -> impl Iterator<Item = (&PubGrubPackage, &Range<Version>)> {
self.0.iter()
}
}
/// Convert a [`PubGrubDependencies`] to a [`DependencyConstraints`].
impl From<PubGrubDependencies> for DependencyConstraints<PubGrubPackage, Range<PubGrubVersion>> {
impl From<PubGrubDependencies> for DependencyConstraints<PubGrubPackage, Range<Version>> {
fn from(dependencies: PubGrubDependencies) -> Self {
dependencies.0
}
@ -152,7 +152,7 @@ impl From<PubGrubDependencies> for DependencyConstraints<PubGrubPackage, Range<P
fn to_pubgrub(
requirement: &Requirement,
extra: Option<ExtraName>,
) -> Result<(PubGrubPackage, Range<PubGrubVersion>), ResolveError> {
) -> Result<(PubGrubPackage, Range<Version>), ResolveError> {
match requirement.version_or_url.as_ref() {
// The requirement has no specifier (e.g., `flask`).
None => Ok((
@ -180,12 +180,12 @@ fn to_pubgrub(
}
}
/// Merge two [`PubGrubVersion`] ranges.
/// Merge two [`Version`] ranges.
fn merge_versions(
package: &PubGrubPackage,
left: &Range<PubGrubVersion>,
right: &Range<PubGrubVersion>,
) -> Result<Range<PubGrubVersion>, ResolveError> {
left: &Range<Version>,
right: &Range<Version>,
) -> Result<Range<Version>, ResolveError> {
let result = left.intersection(right);
if result.is_empty() {
Err(ResolveError::ConflictingVersions(

View file

@ -1,17 +1,16 @@
use distribution_types::{DistributionMetadata, Name, VersionOrUrl};
use pep440_rs::Version;
use pep508_rs::VerbatimUrl;
use puffin_normalize::PackageName;
use crate::pubgrub::PubGrubVersion;
#[derive(Debug)]
pub(crate) enum PubGrubDistribution<'a> {
Registry(&'a PackageName, &'a PubGrubVersion),
Registry(&'a PackageName, &'a Version),
Url(&'a PackageName, &'a VerbatimUrl),
}
impl<'a> PubGrubDistribution<'a> {
pub(crate) fn from_registry(name: &'a PackageName, version: &'a PubGrubVersion) -> Self {
pub(crate) fn from_registry(name: &'a PackageName, version: &'a Version) -> Self {
Self::Registry(name, version)
}
@ -32,7 +31,7 @@ impl Name for PubGrubDistribution<'_> {
impl DistributionMetadata for PubGrubDistribution<'_> {
fn version_or_url(&self) -> VersionOrUrl {
match self {
Self::Registry(_, version) => VersionOrUrl::Version((*version).into()),
Self::Registry(_, version) => VersionOrUrl::Version(version),
Self::Url(_, url) => VersionOrUrl::Url(url),
}
}

View file

@ -4,7 +4,6 @@ pub(crate) use crate::pubgrub::package::{PubGrubPackage, PubGrubPython};
pub(crate) use crate::pubgrub::priority::{PubGrubPriorities, PubGrubPriority};
pub(crate) use crate::pubgrub::report::PubGrubReportFormatter;
pub(crate) use crate::pubgrub::specifier::PubGrubSpecifier;
pub(crate) use crate::pubgrub::version::{PubGrubVersion, MIN_VERSION};
mod dependencies;
mod distribution;
@ -12,4 +11,3 @@ mod package;
mod priority;
mod report;
mod specifier;
mod version;

View file

@ -4,6 +4,7 @@ use std::ops::Bound;
use derivative::Derivative;
use owo_colors::OwoColorize;
use pep440_rs::Version;
use pubgrub::range::Range;
use pubgrub::report::{DerivationTree, Derived, External, ReportFormatter};
use pubgrub::term::Term;
@ -13,21 +14,18 @@ use rustc_hash::{FxHashMap, FxHashSet};
use crate::candidate_selector::CandidateSelector;
use crate::prerelease_mode::PreReleaseStrategy;
use super::{PubGrubPackage, PubGrubVersion};
use super::PubGrubPackage;
#[derive(Debug)]
pub(crate) struct PubGrubReportFormatter<'a> {
/// The versions that were available for each package
pub(crate) available_versions: &'a FxHashMap<PubGrubPackage, Vec<PubGrubVersion>>,
pub(crate) available_versions: &'a FxHashMap<PubGrubPackage, Vec<Version>>,
}
impl ReportFormatter<PubGrubPackage, Range<PubGrubVersion>> for PubGrubReportFormatter<'_> {
impl ReportFormatter<PubGrubPackage, Range<Version>> for PubGrubReportFormatter<'_> {
type Output = String;
fn format_external(
&self,
external: &External<PubGrubPackage, Range<PubGrubVersion>>,
) -> Self::Output {
fn format_external(&self, external: &External<PubGrubPackage, Range<Version>>) -> Self::Output {
match external {
External::NotRoot(package, version) => {
format!("we are solving dependencies of {package} {version}")
@ -93,7 +91,7 @@ impl ReportFormatter<PubGrubPackage, Range<PubGrubVersion>> for PubGrubReportFor
}
/// Try to print terms of an incompatibility in a human-readable way.
fn format_terms(&self, terms: &Map<PubGrubPackage, Term<Range<PubGrubVersion>>>) -> String {
fn format_terms(&self, terms: &Map<PubGrubPackage, Term<Range<Version>>>) -> String {
let terms_vec: Vec<_> = terms.iter().collect();
match terms_vec.as_slice() {
[] | [(PubGrubPackage::Root(_), _)] => "the requirements are unsatisfiable".into(),
@ -154,9 +152,9 @@ impl ReportFormatter<PubGrubPackage, Range<PubGrubVersion>> for PubGrubReportFor
/// Simplest case, we just combine two external incompatibilities.
fn explain_both_external(
&self,
external1: &External<PubGrubPackage, Range<PubGrubVersion>>,
external2: &External<PubGrubPackage, Range<PubGrubVersion>>,
current_terms: &Map<PubGrubPackage, Term<Range<PubGrubVersion>>>,
external1: &External<PubGrubPackage, Range<Version>>,
external2: &External<PubGrubPackage, Range<Version>>,
current_terms: &Map<PubGrubPackage, Term<Range<Version>>>,
) -> String {
let external1 = self.format_external(external1);
let external2 = self.format_external(external2);
@ -174,10 +172,10 @@ impl ReportFormatter<PubGrubPackage, Range<PubGrubVersion>> for PubGrubReportFor
fn explain_both_ref(
&self,
ref_id1: usize,
derived1: &Derived<PubGrubPackage, Range<PubGrubVersion>>,
derived1: &Derived<PubGrubPackage, Range<Version>>,
ref_id2: usize,
derived2: &Derived<PubGrubPackage, Range<PubGrubVersion>>,
current_terms: &Map<PubGrubPackage, Term<Range<PubGrubVersion>>>,
derived2: &Derived<PubGrubPackage, Range<Version>>,
current_terms: &Map<PubGrubPackage, Term<Range<Version>>>,
) -> String {
// TODO: order should be chosen to make it more logical.
@ -201,9 +199,9 @@ impl ReportFormatter<PubGrubPackage, Range<PubGrubVersion>> for PubGrubReportFor
fn explain_ref_and_external(
&self,
ref_id: usize,
derived: &Derived<PubGrubPackage, Range<PubGrubVersion>>,
external: &External<PubGrubPackage, Range<PubGrubVersion>>,
current_terms: &Map<PubGrubPackage, Term<Range<PubGrubVersion>>>,
derived: &Derived<PubGrubPackage, Range<Version>>,
external: &External<PubGrubPackage, Range<Version>>,
current_terms: &Map<PubGrubPackage, Term<Range<Version>>>,
) -> String {
// TODO: order should be chosen to make it more logical.
@ -223,8 +221,8 @@ impl ReportFormatter<PubGrubPackage, Range<PubGrubVersion>> for PubGrubReportFor
/// Add an external cause to the chain of explanations.
fn and_explain_external(
&self,
external: &External<PubGrubPackage, Range<PubGrubVersion>>,
current_terms: &Map<PubGrubPackage, Term<Range<PubGrubVersion>>>,
external: &External<PubGrubPackage, Range<Version>>,
current_terms: &Map<PubGrubPackage, Term<Range<Version>>>,
) -> String {
let external = self.format_external(external);
let terms = self.format_terms(current_terms);
@ -240,8 +238,8 @@ impl ReportFormatter<PubGrubPackage, Range<PubGrubVersion>> for PubGrubReportFor
fn and_explain_ref(
&self,
ref_id: usize,
derived: &Derived<PubGrubPackage, Range<PubGrubVersion>>,
current_terms: &Map<PubGrubPackage, Term<Range<PubGrubVersion>>>,
derived: &Derived<PubGrubPackage, Range<Version>>,
current_terms: &Map<PubGrubPackage, Term<Range<Version>>>,
) -> String {
let derived = self.format_terms(&derived.terms);
let current = self.format_terms(current_terms);
@ -257,9 +255,9 @@ impl ReportFormatter<PubGrubPackage, Range<PubGrubVersion>> for PubGrubReportFor
/// Add an already explained incompat to the chain of explanations.
fn and_explain_prior_and_external(
&self,
prior_external: &External<PubGrubPackage, Range<PubGrubVersion>>,
external: &External<PubGrubPackage, Range<PubGrubVersion>>,
current_terms: &Map<PubGrubPackage, Term<Range<PubGrubVersion>>>,
prior_external: &External<PubGrubPackage, Range<Version>>,
external: &External<PubGrubPackage, Range<Version>>,
current_terms: &Map<PubGrubPackage, Term<Range<Version>>>,
) -> String {
let prior_external = self.format_external(prior_external);
let external = self.format_external(external);
@ -278,9 +276,9 @@ impl PubGrubReportFormatter<'_> {
/// Simplify a [`Range`] of versions using the available versions for a package.
fn simplify_set<'a>(
&self,
set: &'a Range<PubGrubVersion>,
set: &'a Range<Version>,
package: &PubGrubPackage,
) -> Cow<'a, Range<PubGrubVersion>> {
) -> Cow<'a, Range<Version>> {
if set == &Range::full() {
Cow::Borrowed(set)
} else {
@ -294,7 +292,7 @@ impl PubGrubReportFormatter<'_> {
/// their requirements.
pub(crate) fn hints(
&self,
derivation_tree: &DerivationTree<PubGrubPackage, Range<PubGrubVersion>>,
derivation_tree: &DerivationTree<PubGrubPackage, Range<Version>>,
selector: &CandidateSelector,
) -> FxHashSet<PubGrubHint> {
/// Returns `true` if pre-releases were allowed for a package.
@ -324,7 +322,7 @@ impl PubGrubReportFormatter<'_> {
match derivation_tree {
DerivationTree::External(external) => match external {
External::NoVersions(package, set) => {
if set.bounds().any(PubGrubVersion::any_prerelease) {
if set.bounds().any(Version::any_prerelease) {
// A pre-release marker appeared in the version requirements.
if !allowed_prerelease(package, selector) {
hints.insert(PubGrubHint::PreReleaseRequested {
@ -373,14 +371,14 @@ pub(crate) enum PubGrubHint {
PreReleaseAvailable {
package: PubGrubPackage,
#[derivative(PartialEq = "ignore", Hash = "ignore")]
version: PubGrubVersion,
version: Version,
},
/// A requirement included a pre-release marker, but pre-releases weren't enabled for that
/// package.
PreReleaseRequested {
package: PubGrubPackage,
#[derivative(PartialEq = "ignore", Hash = "ignore")]
range: Range<PubGrubVersion>,
range: Range<Version>,
},
}
@ -414,7 +412,7 @@ impl std::fmt::Display for PubGrubHint {
/// A [`Term`] and [`PubGrubPackage`] combination for display.
struct PackageTerm<'a> {
package: &'a PubGrubPackage,
term: &'a Term<Range<PubGrubVersion>>,
term: &'a Term<Range<Version>>,
}
impl std::fmt::Display for PackageTerm<'_> {
@ -434,10 +432,7 @@ impl std::fmt::Display for PackageTerm<'_> {
}
impl PackageTerm<'_> {
fn new<'a>(
package: &'a PubGrubPackage,
term: &'a Term<Range<PubGrubVersion>>,
) -> PackageTerm<'a> {
fn new<'a>(package: &'a PubGrubPackage, term: &'a Term<Range<Version>>) -> PackageTerm<'a> {
PackageTerm { package, term }
}
}
@ -453,7 +448,7 @@ enum PackageRangeKind {
#[derive(Debug)]
struct PackageRange<'a> {
package: &'a PubGrubPackage,
range: &'a Range<PubGrubVersion>,
range: &'a Range<Version>,
kind: PackageRangeKind,
}
@ -506,7 +501,7 @@ impl std::fmt::Display for PackageRange<'_> {
impl PackageRange<'_> {
fn compatibility<'a>(
package: &'a PubGrubPackage,
range: &'a Range<PubGrubVersion>,
range: &'a Range<Version>,
) -> PackageRange<'a> {
PackageRange {
package,
@ -515,10 +510,7 @@ impl PackageRange<'_> {
}
}
fn dependency<'a>(
package: &'a PubGrubPackage,
range: &'a Range<PubGrubVersion>,
) -> PackageRange<'a> {
fn dependency<'a>(package: &'a PubGrubPackage, range: &'a Range<Version>) -> PackageRange<'a> {
PackageRange {
package,
range,

View file

@ -1,16 +1,15 @@
use anyhow::Result;
use pubgrub::range::Range;
use pep440_rs::{Operator, VersionSpecifier};
use pep440_rs::{Operator, Version, VersionSpecifier};
use crate::pubgrub::version::PubGrubVersion;
use crate::ResolveError;
/// A range of versions that can be used to satisfy a requirement.
#[derive(Debug)]
pub(crate) struct PubGrubSpecifier(Range<PubGrubVersion>);
pub(crate) struct PubGrubSpecifier(Range<Version>);
impl From<PubGrubSpecifier> for Range<PubGrubVersion> {
impl From<PubGrubSpecifier> for Range<Version> {
/// Convert a `PubGrub` specifier to a range of versions.
fn from(specifier: PubGrubSpecifier) -> Self {
specifier.0
@ -24,45 +23,43 @@ impl TryFrom<&VersionSpecifier> for PubGrubSpecifier {
fn try_from(specifier: &VersionSpecifier) -> Result<Self, ResolveError> {
let ranges = match specifier.operator() {
Operator::Equal => {
let version = PubGrubVersion::from(specifier.version().clone());
let version = specifier.version().clone();
Range::singleton(version)
}
Operator::ExactEqual => {
let version = PubGrubVersion::from(specifier.version().clone());
let version = specifier.version().clone();
Range::singleton(version)
}
Operator::NotEqual => {
let version = PubGrubVersion::from(specifier.version().clone());
let version = specifier.version().clone();
Range::singleton(version).complement()
}
Operator::TildeEqual => {
let [rest @ .., last, _] = specifier.version().release() else {
return Err(ResolveError::InvalidTildeEquals(specifier.clone()));
};
let upper = PubGrubVersion::from(
pep440_rs::Version::new(rest.iter().chain([&(last + 1)]))
.with_epoch(specifier.version().epoch())
.with_dev(Some(0)),
);
let version = PubGrubVersion::from(specifier.version().clone());
let upper = pep440_rs::Version::new(rest.iter().chain([&(last + 1)]))
.with_epoch(specifier.version().epoch())
.with_dev(Some(0));
let version = specifier.version().clone();
Range::from_range_bounds(version..upper)
}
Operator::LessThan => {
let version = PubGrubVersion::from(specifier.version().clone());
let version = specifier.version().clone();
Range::strictly_lower_than(version)
}
Operator::LessThanEqual => {
let version = PubGrubVersion::from(specifier.version().clone());
let version = specifier.version().clone();
Range::lower_than(version)
}
Operator::GreaterThan => {
// Per PEP 440: "The exclusive ordered comparison >V MUST NOT allow a post-release of
// the given version unless V itself is a post release."
let version = PubGrubVersion::from(specifier.version().clone());
let version = specifier.version().clone();
Range::strictly_higher_than(version)
}
Operator::GreaterThanEqual => {
let version = PubGrubVersion::from(specifier.version().clone());
let version = specifier.version().clone();
Range::higher_than(version)
}
Operator::EqualStar => {
@ -81,7 +78,7 @@ impl TryFrom<&VersionSpecifier> for PubGrubSpecifier {
*release.last_mut().unwrap() += 1;
high = high.with_release(release);
}
Range::from_range_bounds(PubGrubVersion::from(low)..PubGrubVersion::from(high))
Range::from_range_bounds(low..high)
}
Operator::NotEqualStar => {
let low = specifier.version().clone().with_dev(Some(0));
@ -99,8 +96,7 @@ impl TryFrom<&VersionSpecifier> for PubGrubSpecifier {
*release.last_mut().unwrap() += 1;
high = high.with_release(release);
}
Range::from_range_bounds(PubGrubVersion::from(low)..PubGrubVersion::from(high))
.complement()
Range::from_range_bounds(low..high).complement()
}
};

View file

@ -1,69 +0,0 @@
use std::str::FromStr;
use once_cell::sync::Lazy;
/// A PubGrub-compatible wrapper around a PEP 440 version.
#[derive(Clone, PartialEq, Eq, PartialOrd, Ord, Hash)]
pub struct PubGrubVersion(pep440_rs::Version);
impl PubGrubVersion {
/// Returns the smallest PEP 440 version that is larger than `self`.
pub fn next(&self) -> PubGrubVersion {
let mut next = self.clone();
if let Some(dev) = next.0.dev() {
next.0 = next.0.with_dev(Some(dev + 1));
} else if let Some(post) = next.0.post() {
next.0 = next.0.with_post(Some(post + 1));
} else {
next.0 = next.0.with_post(Some(0)).with_dev(Some(0));
}
next
}
pub fn any_prerelease(&self) -> bool {
self.0.any_prerelease()
}
}
impl std::fmt::Display for PubGrubVersion {
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
self.0.fmt(f)
}
}
impl std::fmt::Debug for PubGrubVersion {
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
self.0.fmt(f)
}
}
impl pubgrub::version::Version for PubGrubVersion {
fn lowest() -> Self {
MIN_VERSION.to_owned()
}
fn bump(&self) -> Self {
self.next()
}
}
impl<'a> From<&'a PubGrubVersion> for &'a pep440_rs::Version {
fn from(version: &'a PubGrubVersion) -> Self {
&version.0
}
}
impl From<pep440_rs::Version> for PubGrubVersion {
fn from(version: pep440_rs::Version) -> Self {
Self(version)
}
}
impl From<PubGrubVersion> for pep440_rs::Version {
fn from(version: PubGrubVersion) -> Self {
version.0
}
}
pub(crate) static MIN_VERSION: Lazy<PubGrubVersion> =
Lazy::new(|| PubGrubVersion::from(pep440_rs::Version::from_str("0a0.dev0").unwrap()));

View file

@ -19,7 +19,7 @@ use puffin_traits::OnceMap;
use pypi_types::{Hashes, Metadata21};
use crate::pins::FilePins;
use crate::pubgrub::{PubGrubDistribution, PubGrubPackage, PubGrubPriority, PubGrubVersion};
use crate::pubgrub::{PubGrubDistribution, PubGrubPackage, PubGrubPriority};
use crate::version_map::VersionMap;
use crate::ResolveError;
@ -28,7 +28,7 @@ use crate::ResolveError;
#[derive(Debug)]
pub struct ResolutionGraph {
/// The underlying graph.
petgraph: petgraph::graph::Graph<Dist, Range<PubGrubVersion>, petgraph::Directed>,
petgraph: petgraph::graph::Graph<Dist, Range<Version>, petgraph::Directed>,
/// The metadata for every distribution in this resolution.
hashes: FxHashMap<PackageName, Vec<Hashes>>,
/// The set of editable requirements in this resolution.
@ -40,12 +40,12 @@ pub struct ResolutionGraph {
impl ResolutionGraph {
/// Create a new graph from the resolved `PubGrub` state.
pub(crate) fn from_state(
selection: &SelectedDependencies<PubGrubPackage, PubGrubVersion>,
selection: &SelectedDependencies<PubGrubPackage, Version>,
pins: &FilePins,
packages: &OnceMap<PackageName, VersionMap>,
distributions: &OnceMap<PackageId, Metadata21>,
redirects: &DashMap<Url, Url>,
state: &State<PubGrubPackage, Range<PubGrubVersion>, PubGrubPriority>,
state: &State<PubGrubPackage, Range<Version>, PubGrubPriority>,
editables: FxHashMap<PackageName, (LocalEditable, Metadata21)>,
) -> Result<Self, ResolveError> {
// TODO(charlie): petgraph is a really heavy and unnecessary dependency here. We should
@ -63,7 +63,7 @@ impl ResolutionGraph {
PubGrubPackage::Package(package_name, None, None) => {
// Create the distribution.
let pinned_package = pins
.get(package_name, &Version::from(version.clone()))
.get(package_name, version)
.expect("Every package should be pinned")
.clone();
@ -116,9 +116,8 @@ impl ResolutionGraph {
let metadata = entry.value();
if !metadata.provides_extras.contains(extra) {
let version = Version::from(version.clone());
let pinned_package = pins
.get(package_name, &version)
.get(package_name, version)
.expect("Every package should be pinned")
.clone();
@ -208,9 +207,7 @@ impl ResolutionGraph {
}
/// Return the underlying graph.
pub fn petgraph(
&self,
) -> &petgraph::graph::Graph<Dist, Range<PubGrubVersion>, petgraph::Directed> {
pub fn petgraph(&self) -> &petgraph::graph::Graph<Dist, Range<Version>, petgraph::Directed> {
&self.petgraph
}
}

View file

@ -21,7 +21,7 @@ use distribution_types::{
BuiltDist, Dist, DistributionMetadata, LocalEditable, Name, PackageId, RemoteSource,
SourceDist, VersionOrUrl,
};
use pep440_rs::VersionSpecifiers;
use pep440_rs::{Version, VersionSpecifiers, MIN_VERSION};
use pep508_rs::{MarkerEnvironment, Requirement};
use platform_tags::Tags;
use puffin_client::RegistryClient;
@ -38,7 +38,7 @@ use crate::overrides::Overrides;
use crate::pins::FilePins;
use crate::pubgrub::{
PubGrubDependencies, PubGrubDistribution, PubGrubPackage, PubGrubPriorities, PubGrubPython,
PubGrubSpecifier, PubGrubVersion, MIN_VERSION,
PubGrubSpecifier,
};
use crate::python_requirement::PythonRequirement;
use crate::resolution::ResolutionGraph;
@ -244,7 +244,7 @@ impl<'a, Provider: ResolverProvider> Resolver<'a, Provider> {
// Start the solve.
let mut state = State::init(root.clone(), MIN_VERSION.clone());
let mut added_dependencies: FxHashMap<PubGrubPackage, FxHashSet<PubGrubVersion>> =
let mut added_dependencies: FxHashMap<PubGrubPackage, FxHashSet<Version>> =
FxHashMap::default();
let mut next = root;
@ -393,7 +393,7 @@ impl<'a, Provider: ResolverProvider> Resolver<'a, Provider> {
/// Visit the set of [`PubGrubPackage`] candidates prior to selection. This allows us to fetch
/// metadata for all of the packages in parallel.
fn pre_visit<'data>(
packages: impl Iterator<Item = (&'data PubGrubPackage, &'data Range<PubGrubVersion>)>,
packages: impl Iterator<Item = (&'data PubGrubPackage, &'data Range<Version>)>,
request_sink: &futures::channel::mpsc::UnboundedSender<Request>,
) -> Result<(), ResolveError> {
// Iterate over the potential packages, and fetch file metadata for any of them. These
@ -412,26 +412,26 @@ impl<'a, Provider: ResolverProvider> Resolver<'a, Provider> {
async fn choose_version(
&self,
package: &PubGrubPackage,
range: &Range<PubGrubVersion>,
range: &Range<Version>,
pins: &mut FilePins,
request_sink: &futures::channel::mpsc::UnboundedSender<Request>,
) -> Result<Option<PubGrubVersion>, ResolveError> {
) -> Result<Option<Version>, ResolveError> {
return match package {
PubGrubPackage::Root(_) => Ok(Some(MIN_VERSION.clone())),
PubGrubPackage::Python(PubGrubPython::Installed) => {
let version = PubGrubVersion::from(self.python_requirement.installed().clone());
if range.contains(&version) {
Ok(Some(version))
let version = self.python_requirement.installed();
if range.contains(version) {
Ok(Some(version.clone()))
} else {
Ok(None)
}
}
PubGrubPackage::Python(PubGrubPython::Target) => {
let version = PubGrubVersion::from(self.python_requirement.target().clone());
if range.contains(&version) {
Ok(Some(version))
let version = self.python_requirement.target();
if range.contains(version) {
Ok(Some(version.clone()))
} else {
Ok(None)
}
@ -458,7 +458,7 @@ impl<'a, Provider: ResolverProvider> Resolver<'a, Provider> {
if let Ok(wheel_filename) = WheelFilename::try_from(url.raw()) {
// If the URL is that of a wheel, extract the version.
let version = PubGrubVersion::from(wheel_filename.version);
let version = wheel_filename.version;
if range.contains(&version) {
Ok(Some(version))
} else {
@ -469,9 +469,9 @@ impl<'a, Provider: ResolverProvider> Resolver<'a, Provider> {
let dist = PubGrubDistribution::from_url(package_name, url);
let entry = self.index.distributions.wait(&dist.package_id()).await;
let metadata = entry.value();
let version = PubGrubVersion::from(metadata.version.clone());
if range.contains(&version) {
Ok(Some(version))
let version = &metadata.version;
if range.contains(version) {
Ok(Some(version.clone()))
} else {
Ok(None)
}
@ -554,7 +554,7 @@ impl<'a, Provider: ResolverProvider> Resolver<'a, Provider> {
async fn get_dependencies(
&self,
package: &PubGrubPackage,
version: &PubGrubVersion,
version: &Version,
priorities: &mut PubGrubPriorities,
request_sink: &futures::channel::mpsc::UnboundedSender<Request>,
) -> Result<Dependencies, ResolveError> {
@ -592,7 +592,7 @@ impl<'a, Provider: ResolverProvider> Resolver<'a, Provider> {
None,
Some(editable.url().clone()),
),
Range::singleton(PubGrubVersion::from(metadata.version.clone())),
Range::singleton(metadata.version.clone()),
);
}
@ -825,7 +825,7 @@ impl<'a, Provider: ResolverProvider> Resolver<'a, Provider> {
}
}
fn on_progress(&self, package: &PubGrubPackage, version: &PubGrubVersion) {
fn on_progress(&self, package: &PubGrubPackage, version: &Version) {
if let Some(reporter) = self.reporter.as_ref() {
match package {
PubGrubPackage::Root(_) => {}
@ -834,7 +834,7 @@ impl<'a, Provider: ResolverProvider> Resolver<'a, Provider> {
reporter.on_progress(package_name, VersionOrUrl::Url(url));
}
PubGrubPackage::Package(package_name, _extra, None) => {
reporter.on_progress(package_name, VersionOrUrl::Version(version.into()));
reporter.on_progress(package_name, VersionOrUrl::Version(version));
}
}
}
@ -856,7 +856,7 @@ enum Request {
/// A request to fetch the metadata for a built or source distribution.
Dist(Dist),
/// A request to pre-fetch the metadata for a package and the best-guess distribution.
Prefetch(PackageName, Range<PubGrubVersion>),
Prefetch(PackageName, Range<Version>),
}
#[derive(Debug)]
@ -879,5 +879,5 @@ enum Dependencies {
/// Package dependencies are not usable
Unusable(Option<String>),
/// Container for all available package versions.
Known(DependencyConstraints<PubGrubPackage, Range<PubGrubVersion>>),
Known(DependencyConstraints<PubGrubPackage, Range<Version>>),
}

View file

@ -14,7 +14,6 @@ use puffin_normalize::PackageName;
use puffin_traits::BuildContext;
use pypi_types::Metadata21;
use crate::pubgrub::PubGrubVersion;
use crate::python_requirement::PythonRequirement;
use crate::version_map::VersionMap;
use crate::yanks::AllowedYanks;
@ -49,7 +48,7 @@ pub trait ResolverProvider: Send + Sync {
pub struct DefaultResolverProvider<'a, Context: BuildContext + Send + Sync> {
client: &'a RegistryClient,
/// These are the entries from `--find-links` that act as overrides for index responses.
flat_index: FxHashMap<PackageName, FlatIndex<PubGrubVersion>>,
flat_index: FxHashMap<PackageName, FlatIndex>,
fetcher: DistributionDatabase<'a, Context>,
tags: &'a Tags,
python_requirement: PythonRequirement<'a>,

View file

@ -6,19 +6,19 @@ use tracing::{instrument, warn};
use distribution_filename::DistFilename;
use distribution_types::{Dist, IndexUrl, PrioritizedDistribution, ResolvableDist};
use pep440_rs::Version;
use platform_tags::Tags;
use puffin_client::{FlatIndex, SimpleMetadata};
use puffin_normalize::PackageName;
use puffin_warnings::warn_user_once;
use pypi_types::{Hashes, Yanked};
use crate::pubgrub::PubGrubVersion;
use crate::python_requirement::PythonRequirement;
use crate::yanks::AllowedYanks;
/// A map from versions to distributions.
#[derive(Debug, Default, Clone)]
pub struct VersionMap(BTreeMap<PubGrubVersion, PrioritizedDistribution>);
pub struct VersionMap(BTreeMap<Version, PrioritizedDistribution>);
impl VersionMap {
/// Initialize a [`VersionMap`] from the given metadata.
@ -32,10 +32,10 @@ impl VersionMap {
python_requirement: &PythonRequirement,
allowed_yanks: &AllowedYanks,
exclude_newer: Option<&DateTime<Utc>>,
flat_index: Option<FlatIndex<PubGrubVersion>>,
flat_index: Option<FlatIndex>,
) -> Self {
// If we have packages of the same name from find links, gives them priority, otherwise start empty
let mut version_map: BTreeMap<PubGrubVersion, PrioritizedDistribution> =
let mut version_map: BTreeMap<Version, PrioritizedDistribution> =
flat_index.map(|overrides| overrides.0).unwrap_or_default();
// Collect compatible distributions.
@ -87,7 +87,7 @@ impl VersionMap {
file,
index.clone(),
);
match version_map.entry(version.clone().into()) {
match version_map.entry(version.clone()) {
Entry::Occupied(mut entry) => {
entry.get_mut().insert_built(
dist,
@ -112,7 +112,7 @@ impl VersionMap {
file,
index.clone(),
);
match version_map.entry(version.clone().into()) {
match version_map.entry(version.clone()) {
Entry::Occupied(mut entry) => {
entry
.get_mut()
@ -135,21 +135,19 @@ impl VersionMap {
}
/// Return the [`DistFile`] for the given version, if any.
pub(crate) fn get(&self, version: &PubGrubVersion) -> Option<ResolvableDist> {
pub(crate) fn get(&self, version: &Version) -> Option<ResolvableDist> {
self.0.get(version).and_then(PrioritizedDistribution::get)
}
/// Return an iterator over the versions and distributions.
pub(crate) fn iter(
&self,
) -> impl DoubleEndedIterator<Item = (&PubGrubVersion, ResolvableDist)> {
pub(crate) fn iter(&self) -> impl DoubleEndedIterator<Item = (&Version, ResolvableDist)> {
self.0
.iter()
.filter_map(|(version, dist)| Some((version, dist.get()?)))
}
/// Return the [`Hashes`] for the given version, if any.
pub(crate) fn hashes(&self, version: &PubGrubVersion) -> Vec<Hashes> {
pub(crate) fn hashes(&self, version: &Version) -> Vec<Hashes> {
self.0
.get(version)
.map(|file| file.hashes().to_vec())
@ -157,8 +155,8 @@ impl VersionMap {
}
}
impl From<FlatIndex<PubGrubVersion>> for VersionMap {
fn from(flat_index: FlatIndex<PubGrubVersion>) -> Self {
impl From<FlatIndex> for VersionMap {
fn from(flat_index: FlatIndex) -> Self {
Self(flat_index.0)
}
}