Add dedicated `PubGrubPackage::UrlPackage` for URL dependencies

Instead of using `PubGrubPackage::Package(.., Option<Url>)`
This commit is contained in:
Zanie 2023-11-09 11:47:40 -06:00
parent 210b481be8
commit a510a2f882
6 changed files with 82 additions and 152 deletions

View File

@ -1,10 +1,9 @@
use fxhash::FxHashMap;
use itertools::Itertools;
use pubgrub::range::Range;
use tracing::warn;
use pep508_rs::{MarkerEnvironment, Requirement, VersionOrUrl};
use puffin_cache::CanonicalUrl;
use puffin_normalize::{ExtraName, PackageName};
use crate::pubgrub::specifier::PubGrubSpecifier;
@ -57,21 +56,6 @@ impl PubGrubDependencies {
let (package, version) = result?;
dependencies.push((package.clone(), version.clone()));
// if let Some(entry) = dependencies.get_key_value(&package) {
// // Merge the versions.
// let version = merge_versions(entry.1, &version);
// // Merge the package.
// if let Some(package) = merge_package(entry.0, &package)? {
// dependencies.remove(&package);
// dependencies.insert(package, version);
// } else {
// dependencies.insert(package, version);
// }
// } else {
// dependencies.insert(package.clone(), version.clone());
// }
}
}
@ -107,18 +91,6 @@ impl PubGrubDependencies {
let (package, version) = result?;
dependencies.push((package.clone(), version.clone()));
// if let Some(entry) = dependencies.get_key_value(&package) {
// // Merge the versions.
// let version = merge_versions(entry.1, &version);
// // Merge the package.
// if let Some(package) = merge_package(entry.0, &package)? {
// dependencies.insert(package, version);
// } else {
// dependencies.insert(package, version);
// }
// }
}
}
@ -151,12 +123,12 @@ fn to_pubgrub(
match requirement.version_or_url.as_ref() {
// The requirement has no specifier (e.g., `flask`).
None => Ok((
PubGrubPackage::Package(requirement.name.clone(), extra, None),
PubGrubPackage::Package(requirement.name.clone(), extra),
Range::full(),
)),
// The requirement has a URL (e.g., `flask @ file:///path/to/flask`).
Some(VersionOrUrl::Url(url)) => Ok((
PubGrubPackage::Package(requirement.name.clone(), extra, Some(url.clone())),
PubGrubPackage::UrlPackage(requirement.name.clone(), extra, url.clone()),
Range::full(),
)),
// The requirement has a specifier (e.g., `flask>=1.0`).
@ -168,67 +140,9 @@ fn to_pubgrub(
range.intersection(&specifier.into())
})?;
Ok((
PubGrubPackage::Package(requirement.name.clone(), extra, None),
PubGrubPackage::Package(requirement.name.clone(), extra),
version,
))
}
}
}
/// Merge two [`PubGrubVersion`] ranges.
fn merge_versions(
left: &Range<PubGrubVersion>,
right: &Range<PubGrubVersion>,
) -> Range<PubGrubVersion> {
left.intersection(right)
}
/// Merge two [`PubGrubPackage`] instances.
fn merge_package(
left: &PubGrubPackage,
right: &PubGrubPackage,
) -> Result<Option<PubGrubPackage>, ResolveError> {
match (left, right) {
// Either package is `root`.
(PubGrubPackage::Root(_), _) | (_, PubGrubPackage::Root(_)) => Ok(None),
// Left package has a URL. Propagate the URL.
(PubGrubPackage::Package(name, extra, Some(url)), PubGrubPackage::Package(.., None)) => {
Ok(Some(PubGrubPackage::Package(
name.clone(),
extra.clone(),
Some(url.clone()),
)))
}
// Right package has a URL.
(PubGrubPackage::Package(.., None), PubGrubPackage::Package(name, extra, Some(url))) => {
Ok(Some(PubGrubPackage::Package(
name.clone(),
extra.clone(),
Some(url.clone()),
)))
}
// Neither package has a URL.
(PubGrubPackage::Package(_name, _extra, None), PubGrubPackage::Package(.., None)) => {
Ok(None)
}
// Both packages have a URL.
(
PubGrubPackage::Package(name, _extra, Some(left)),
PubGrubPackage::Package(.., Some(right)),
) => {
if CanonicalUrl::new(left) == CanonicalUrl::new(right) {
Ok(None)
} else {
Err(ResolveError::ConflictingUrls(
name.clone(),
left.to_string(),
right.to_string(),
))
}
}
}
}

View File

@ -14,7 +14,8 @@ use puffin_normalize::{ExtraName, PackageName};
#[derivative(PartialEq, Hash)]
pub enum PubGrubPackage {
Root(Option<PackageName>),
Package(
Package(PackageName, Option<ExtraName>),
UrlPackage(
PackageName,
Option<ExtraName>,
/// The URL of the package, if it was specified in the requirement.
@ -66,7 +67,7 @@ pub enum PubGrubPackage {
#[derivative(PartialEq = "ignore")]
#[derivative(PartialOrd = "ignore")]
#[derivative(Hash = "ignore")]
Option<Url>,
Url,
),
}
@ -80,8 +81,13 @@ impl std::fmt::Display for PubGrubPackage {
write!(f, "root")
}
}
PubGrubPackage::Package(name, None, ..) => write!(f, "{name}"),
PubGrubPackage::Package(name, Some(extra), ..) => {
PubGrubPackage::Package(name, None) => write!(f, "{name}"),
PubGrubPackage::Package(name, Some(extra)) => {
write!(f, "{name}[{extra}]")
}
PubGrubPackage::UrlPackage(name, None, ..) => write!(f, "{name}"),
PubGrubPackage::UrlPackage(name, Some(extra), ..) => {
write!(f, "{name}[{extra}]")
}
}

View File

@ -20,7 +20,7 @@ impl PubGrubPriorities {
pub(crate) fn get(&self, package: &PubGrubPackage) -> Option<PubGrubPriority> {
match package {
PubGrubPackage::Root(_) => Some(Reverse(0)),
PubGrubPackage::Package(name, _, _) => self
PubGrubPackage::Package(name, ..) | PubGrubPackage::UrlPackage(name, ..) => self
.0
.get(name)
.copied()

View File

@ -269,10 +269,16 @@ impl ResolutionFailureReporter {
let terms_vec: Vec<_> = terms.iter().collect();
match terms_vec.as_slice() {
[] | [(PubGrubPackage::Root(_), _)] => "version solving failed".into(),
[(package @ PubGrubPackage::Package(..), Term::Positive(range))] => {
[(
package @ (PubGrubPackage::Package(..) | PubGrubPackage::UrlPackage(..)),
Term::Positive(range),
)] => {
format!("{package}{range} is forbidden")
}
[(package @ PubGrubPackage::Package(..), Term::Negative(range))] => {
[(
package @ (PubGrubPackage::Package(..) | PubGrubPackage::UrlPackage(..)),
Term::Negative(range),
)] => {
format!("{package}{range} is mandatory")
}
[(p1, Term::Positive(r1)), (p2, Term::Negative(r2))] => {

View File

@ -70,7 +70,7 @@ impl Graph {
FxHashMap::with_capacity_and_hasher(selection.len(), BuildHasherDefault::default());
for (package, version) in selection {
match package {
PubGrubPackage::Package(package_name, None, None) => {
PubGrubPackage::Package(package_name, None) => {
let version = Version::from(version.clone());
let file = pins
.get(package_name)
@ -83,7 +83,7 @@ impl Graph {
let index = graph.add_node(pinned_package);
inverse.insert(package_name, index);
}
PubGrubPackage::Package(package_name, None, Some(url)) => {
PubGrubPackage::UrlPackage(package_name, None, url) => {
let url = redirects
.get(url)
.map_or_else(|| url.clone(), |url| url.value().clone());
@ -103,10 +103,13 @@ impl Graph {
if let Kind::FromDependencyOf(self_package, self_version, dependency_package, _) =
&state.incompatibility_store[*id].kind
{
let PubGrubPackage::Package(self_package, None, _) = self_package else {
let (PubGrubPackage::Package(self_package, None)
| PubGrubPackage::UrlPackage(self_package, None, _)) = self_package
else {
continue;
};
let PubGrubPackage::Package(dependency_package, None, _) = dependency_package
let (PubGrubPackage::Package(dependency_package, None)
| PubGrubPackage::UrlPackage(dependency_package, None, _)) = dependency_package
else {
continue;
};

View File

@ -9,6 +9,7 @@ use futures::channel::mpsc::UnboundedReceiver;
use futures::{pin_mut, FutureExt, StreamExt, TryFutureExt};
use fxhash::{FxHashMap, FxHashSet};
use pubgrub::error::PubGrubError;
use pubgrub::range::Range;
use pubgrub::solver::{Incompatibility, State};
use tokio::select;
@ -281,14 +282,14 @@ impl<'a, Context: BuildContext + Sync> Resolver<'a, Context> {
) -> Result<(), ResolveError> {
match package {
PubGrubPackage::Root(_) => {}
PubGrubPackage::Package(package_name, _extra, None) => {
PubGrubPackage::Package(package_name, _extra) => {
// Emit a request to fetch the metadata for this package.
if in_flight.insert_package(package_name) {
priorities.add(package_name.clone());
request_sink.unbounded_send(Request::Package(package_name.clone()))?;
}
}
PubGrubPackage::Package(package_name, _extra, Some(url)) => {
PubGrubPackage::UrlPackage(package_name, _extra, url) => {
// Emit a request to fetch the metadata for this package.
if in_flight.insert_url(url) {
priorities.add(package_name.clone());
@ -318,7 +319,7 @@ impl<'a, Context: BuildContext + Sync> Resolver<'a, Context> {
// Iterate over the potential packages, and fetch file metadata for any of them. These
// represent our current best guesses for the versions that we _might_ select.
for (package, range) in packages {
let PubGrubPackage::Package(package_name, _extra, None) = package else {
let PubGrubPackage::Package(package_name, _extra) = package else {
continue;
};
@ -372,7 +373,7 @@ impl<'a, Context: BuildContext + Sync> Resolver<'a, Context> {
return match package {
PubGrubPackage::Root(_) => Ok(Some(MIN_VERSION.clone())),
PubGrubPackage::Package(package_name, _extra, Some(url)) => {
PubGrubPackage::UrlPackage(package_name, _extra, url) => {
debug!("Searching for a compatible version of {package_name} @ {url} ({range})",);
// If the URL wasn't declared in the direct dependencies or constraints, reject it.
@ -404,7 +405,7 @@ impl<'a, Context: BuildContext + Sync> Resolver<'a, Context> {
}
}
PubGrubPackage::Package(package_name, _extra, None) => {
PubGrubPackage::Package(package_name, _extra) => {
// Wait for the metadata to be available.
let entry = self.index.packages.wait(package_name).await.unwrap();
let version_map = entry.value();
@ -470,7 +471,7 @@ impl<'a, Context: BuildContext + Sync> Resolver<'a, Context> {
in_flight: &mut InFlight,
request_sink: &futures::channel::mpsc::UnboundedSender<Request>,
) -> Result<Dependencies, ResolveError> {
match package {
let (package_name, extra, entry) = match package {
PubGrubPackage::Root(_) => {
// Add the root requirements.
let constraints = PubGrubDependencies::try_from_requirements(
@ -488,53 +489,53 @@ impl<'a, Context: BuildContext + Sync> Resolver<'a, Context> {
Self::visit_package(package, priorities, in_flight, request_sink)?;
}
Ok(Dependencies::Known(constraints.into()))
return Ok(Dependencies::Known(constraints.into()));
}
PubGrubPackage::Package(package_name, extra, url) => {
PubGrubPackage::Package(package_name, extra) => {
// Wait for the metadata to be available.
let entry = match url {
Some(url) => self.index.versions.wait(url.as_str()).await.unwrap(),
None => {
let versions = pins.get(package_name).unwrap();
let file = versions.get(version.into()).unwrap();
self.index.versions.wait(&file.hashes.sha256).await.unwrap()
}
};
let metadata = entry.value();
let mut constraints = PubGrubDependencies::try_from_requirements(
&metadata.requires_dist,
&self.constraints,
extra.as_ref(),
Some(package_name),
self.markers,
)?;
for (package, version) in constraints.iter() {
debug!("Adding transitive dependency: {package} {version}");
// Emit a request to fetch the metadata for this package.
Self::visit_package(package, priorities, in_flight, request_sink)?;
}
if let Some(extra) = extra {
if !metadata
.provides_extras
.iter()
.any(|provided_extra| provided_extra == extra)
{
return Ok(Dependencies::Unknown);
}
constraints.insert(
PubGrubPackage::Package(package_name.clone(), None, None),
Range::singleton(version.clone()),
);
}
Ok(Dependencies::Known(constraints.into()))
let versions = pins.get(package_name).unwrap();
let file = versions.get(version.into()).unwrap();
let entry = self.index.versions.wait(&file.hashes.sha256).await.unwrap();
(package_name, extra, entry)
}
PubGrubPackage::UrlPackage(package_name, extra, url) => {
let entry = self.index.versions.wait(url.as_str()).await.unwrap();
(package_name, extra, entry)
}
};
let metadata = entry.value();
let mut constraints = PubGrubDependencies::try_from_requirements(
&metadata.requires_dist,
&self.constraints,
extra.as_ref(),
Some(package_name),
self.markers,
)?;
for (package, version) in constraints.iter() {
debug!("Adding transitive dependency: {package} {version}");
// Emit a request to fetch the metadata for this package.
Self::visit_package(package, priorities, in_flight, request_sink)?;
}
if let Some(extra) = extra {
if !metadata
.provides_extras
.iter()
.any(|provided_extra| provided_extra == extra)
{
return Ok(Dependencies::Unknown);
}
constraints.insert(
PubGrubPackage::Package(package_name.clone(), None),
Range::singleton(version.clone()),
);
}
Ok(Dependencies::Known(constraints.into()))
}
/// Fetch the metadata for a stream of packages and versions.
@ -808,10 +809,10 @@ impl<'a, Context: BuildContext + Sync> Resolver<'a, Context> {
if let Some(reporter) = self.reporter.as_ref() {
match package {
PubGrubPackage::Root(_) => {}
PubGrubPackage::Package(package_name, extra, Some(url)) => {
PubGrubPackage::UrlPackage(package_name, extra, url) => {
reporter.on_progress(package_name, extra.as_ref(), VersionOrUrl::Url(url));
}
PubGrubPackage::Package(package_name, extra, None) => {
PubGrubPackage::Package(package_name, extra) => {
reporter.on_progress(
package_name,
extra.as_ref(),