Use bounded ranges rather than constructing manual ranges (#228)

I didn't realize this, but they made a bunch of improvements to how
PubGrub represents versions which lets us greatly simplify our own
PubGrub version wrapper
(https://github.com/pubgrub-rs/guide/pull/6/files).
This commit is contained in:
Charlie Marsh 2023-10-29 20:58:43 -07:00 committed by GitHub
parent fb2d4fc421
commit e73d3f0ff8
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
3 changed files with 29 additions and 74 deletions

View file

@ -1,4 +1,5 @@
use anyhow::Result; use anyhow::Result;
use itertools::Itertools;
use pubgrub::range::Range; use pubgrub::range::Range;
use pep508_rs::{MarkerEnvironment, Requirement}; use pep508_rs::{MarkerEnvironment, Requirement};
@ -8,7 +9,7 @@ use puffin_package::package_name::PackageName;
pub(crate) use crate::pubgrub::package::PubGrubPackage; pub(crate) use crate::pubgrub::package::PubGrubPackage;
pub(crate) use crate::pubgrub::priority::{PubGrubPriorities, PubGrubPriority}; pub(crate) use crate::pubgrub::priority::{PubGrubPriorities, PubGrubPriority};
pub(crate) use crate::pubgrub::specifier::PubGrubSpecifier; pub(crate) use crate::pubgrub::specifier::PubGrubSpecifier;
pub(crate) use crate::pubgrub::version::{PubGrubVersion, MAX_VERSION, MIN_VERSION}; pub(crate) use crate::pubgrub::version::{PubGrubVersion, MIN_VERSION};
mod package; mod package;
mod priority; mod priority;
@ -67,19 +68,10 @@ pub(crate) fn version_range(
return Ok(Range::full()); return Ok(Range::full());
}; };
let mut final_range = Range::full(); specifiers
for spec in specifiers.iter() { .iter()
let spec_range = .map(PubGrubSpecifier::try_from)
PubGrubSpecifier::try_from(spec)? .fold_ok(Range::full(), |range, specifier| {
.into_iter() range.intersection(&specifier.into())
.fold(Range::empty(), |accum, range| { })
accum.union(&if range.end < *MAX_VERSION {
Range::between(range.start, range.end)
} else {
Range::higher_than(range.start)
})
});
final_range = final_range.intersection(&spec_range);
}
Ok(final_range)
} }

View file

@ -1,21 +1,18 @@
use std::ops::Range;
use anyhow::Result; use anyhow::Result;
use pubgrub::range::Range;
use pep440_rs::{Operator, VersionSpecifier}; use pep440_rs::{Operator, VersionSpecifier};
use crate::pubgrub::version::{PubGrubVersion, MAX_VERSION, MIN_VERSION}; use crate::pubgrub::version::PubGrubVersion;
/// A range of versions that can be used to satisfy a requirement. /// A range of versions that can be used to satisfy a requirement.
#[derive(Debug)] #[derive(Debug)]
pub(crate) struct PubGrubSpecifier(Vec<Range<PubGrubVersion>>); pub(crate) struct PubGrubSpecifier(Range<PubGrubVersion>);
impl IntoIterator for PubGrubSpecifier { impl From<PubGrubSpecifier> for Range<PubGrubVersion> {
type Item = Range<PubGrubVersion>; /// Convert a `PubGrub` specifier to a range of versions.
type IntoIter = std::vec::IntoIter<Self::Item>; fn from(specifier: PubGrubSpecifier) -> Self {
specifier.0
fn into_iter(self) -> Self::IntoIter {
self.0.into_iter()
} }
} }
@ -27,18 +24,15 @@ impl TryFrom<&VersionSpecifier> for PubGrubSpecifier {
let ranges = match specifier.operator() { let ranges = match specifier.operator() {
Operator::Equal => { Operator::Equal => {
let version = PubGrubVersion::from(specifier.version().clone()); let version = PubGrubVersion::from(specifier.version().clone());
vec![version.clone()..version.next()] Range::singleton(version)
} }
Operator::ExactEqual => { Operator::ExactEqual => {
let version = PubGrubVersion::from(specifier.version().clone()); let version = PubGrubVersion::from(specifier.version().clone());
vec![version.clone()..version.next()] Range::singleton(version)
} }
Operator::NotEqual => { Operator::NotEqual => {
let version = PubGrubVersion::from(specifier.version().clone()); let version = PubGrubVersion::from(specifier.version().clone());
vec![ Range::singleton(version).complement()
MIN_VERSION.clone()..version.clone(),
version.next()..MAX_VERSION.clone(),
]
} }
Operator::TildeEqual => { Operator::TildeEqual => {
let [rest @ .., last, _] = specifier.version().release.as_slice() else { let [rest @ .., last, _] = specifier.version().release.as_slice() else {
@ -58,29 +52,16 @@ impl TryFrom<&VersionSpecifier> for PubGrubSpecifier {
.copied() .copied()
.collect(), .collect(),
}); });
let lower = PubGrubVersion::from(specifier.version().clone()); let version = PubGrubVersion::from(specifier.version().clone());
vec![lower..upper] Range::from_range_bounds(version..upper)
} }
Operator::LessThan => { Operator::LessThan => {
// Per PEP 440: "The exclusive ordered comparison <V MUST NOT allow a pre-release of let version = PubGrubVersion::from(specifier.version().clone());
// the specified version unless the specified version is itself a pre-release." Range::strictly_lower_than(version)
if specifier.version().any_prerelease() {
let version = PubGrubVersion::from(specifier.version().clone());
vec![MIN_VERSION.clone()..version.clone()]
} else {
let max_version = pep440_rs::Version {
post: None,
dev: Some(0),
local: None,
..specifier.version().clone()
};
let version = PubGrubVersion::from(max_version);
vec![MIN_VERSION.clone()..version.clone()]
}
} }
Operator::LessThanEqual => { Operator::LessThanEqual => {
let version = PubGrubVersion::from(specifier.version().clone()); let version = PubGrubVersion::from(specifier.version().clone());
vec![MIN_VERSION.clone()..version.next()] Range::lower_than(version)
} }
Operator::GreaterThan => { Operator::GreaterThan => {
// Per PEP 440: "The exclusive ordered comparison >V MUST NOT allow a post-release of // Per PEP 440: "The exclusive ordered comparison >V MUST NOT allow a post-release of
@ -93,20 +74,18 @@ impl TryFrom<&VersionSpecifier> for PubGrubSpecifier {
} else { } else {
low.post = Some(usize::MAX); low.post = Some(usize::MAX);
} }
let version = PubGrubVersion::from(specifier.version().clone());
let version = PubGrubVersion::from(low); Range::strictly_higher_than(version)
vec![version..MAX_VERSION.clone()]
} }
Operator::GreaterThanEqual => { Operator::GreaterThanEqual => {
let version = PubGrubVersion::from(specifier.version().clone()); let version = PubGrubVersion::from(specifier.version().clone());
vec![version..MAX_VERSION.clone()] Range::higher_than(version)
} }
Operator::EqualStar => { Operator::EqualStar => {
let low = pep440_rs::Version { let low = pep440_rs::Version {
dev: Some(0), dev: Some(0),
..specifier.version().clone() ..specifier.version().clone()
}; };
let mut high = pep440_rs::Version { let mut high = pep440_rs::Version {
dev: Some(0), dev: Some(0),
..specifier.version().clone() ..specifier.version().clone()
@ -122,15 +101,13 @@ impl TryFrom<&VersionSpecifier> for PubGrubSpecifier {
} else { } else {
*high.release.last_mut().unwrap() += 1; *high.release.last_mut().unwrap() += 1;
} }
Range::from_range_bounds(PubGrubVersion::from(low)..PubGrubVersion::from(high))
vec![PubGrubVersion::from(low)..PubGrubVersion::from(high)]
} }
Operator::NotEqualStar => { Operator::NotEqualStar => {
let low = pep440_rs::Version { let low = pep440_rs::Version {
dev: Some(0), dev: Some(0),
..specifier.version().clone() ..specifier.version().clone()
}; };
let mut high = pep440_rs::Version { let mut high = pep440_rs::Version {
dev: Some(0), dev: Some(0),
..specifier.version().clone() ..specifier.version().clone()
@ -146,11 +123,8 @@ impl TryFrom<&VersionSpecifier> for PubGrubSpecifier {
} else { } else {
*high.release.last_mut().unwrap() += 1; *high.release.last_mut().unwrap() += 1;
} }
Range::from_range_bounds(PubGrubVersion::from(low)..PubGrubVersion::from(high))
vec![ .complement()
MIN_VERSION.clone()..PubGrubVersion::from(low),
PubGrubVersion::from(high)..MAX_VERSION.clone(),
]
} }
}; };

View file

@ -62,14 +62,3 @@ impl From<PubGrubVersion> for pep440_rs::Version {
pub(crate) static MIN_VERSION: Lazy<PubGrubVersion> = pub(crate) static MIN_VERSION: Lazy<PubGrubVersion> =
Lazy::new(|| PubGrubVersion::from(pep440_rs::Version::from_str("0a0.dev0").unwrap())); Lazy::new(|| PubGrubVersion::from(pep440_rs::Version::from_str("0a0.dev0").unwrap()));
pub(crate) static MAX_VERSION: Lazy<PubGrubVersion> = Lazy::new(|| {
PubGrubVersion(pep440_rs::Version {
epoch: usize::MAX,
release: vec![usize::MAX, usize::MAX, usize::MAX],
pre: None,
post: Some(usize::MAX),
dev: None,
local: None,
})
});