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 itertools::Itertools;
use pubgrub::range::Range; use pubgrub::range::Range;
use tracing::warn; use tracing::warn;
use pep508_rs::{MarkerEnvironment, Requirement, VersionOrUrl}; use pep508_rs::{MarkerEnvironment, Requirement, VersionOrUrl};
use puffin_cache::CanonicalUrl;
use puffin_normalize::{ExtraName, PackageName}; use puffin_normalize::{ExtraName, PackageName};
use crate::pubgrub::specifier::PubGrubSpecifier; use crate::pubgrub::specifier::PubGrubSpecifier;
@ -57,21 +56,6 @@ impl PubGrubDependencies {
let (package, version) = result?; let (package, version) = result?;
dependencies.push((package.clone(), version.clone())); 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?; let (package, version) = result?;
dependencies.push((package.clone(), version.clone())); 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() { match requirement.version_or_url.as_ref() {
// The requirement has no specifier (e.g., `flask`). // The requirement has no specifier (e.g., `flask`).
None => Ok(( None => Ok((
PubGrubPackage::Package(requirement.name.clone(), extra, None), PubGrubPackage::Package(requirement.name.clone(), extra),
Range::full(), Range::full(),
)), )),
// The requirement has a URL (e.g., `flask @ file:///path/to/flask`). // The requirement has a URL (e.g., `flask @ file:///path/to/flask`).
Some(VersionOrUrl::Url(url)) => Ok(( Some(VersionOrUrl::Url(url)) => Ok((
PubGrubPackage::Package(requirement.name.clone(), extra, Some(url.clone())), PubGrubPackage::UrlPackage(requirement.name.clone(), extra, url.clone()),
Range::full(), Range::full(),
)), )),
// The requirement has a specifier (e.g., `flask>=1.0`). // The requirement has a specifier (e.g., `flask>=1.0`).
@ -168,67 +140,9 @@ fn to_pubgrub(
range.intersection(&specifier.into()) range.intersection(&specifier.into())
})?; })?;
Ok(( Ok((
PubGrubPackage::Package(requirement.name.clone(), extra, None), PubGrubPackage::Package(requirement.name.clone(), extra),
version, 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)] #[derivative(PartialEq, Hash)]
pub enum PubGrubPackage { pub enum PubGrubPackage {
Root(Option<PackageName>), Root(Option<PackageName>),
Package( Package(PackageName, Option<ExtraName>),
UrlPackage(
PackageName, PackageName,
Option<ExtraName>, Option<ExtraName>,
/// The URL of the package, if it was specified in the requirement. /// The URL of the package, if it was specified in the requirement.
@ -66,7 +67,7 @@ pub enum PubGrubPackage {
#[derivative(PartialEq = "ignore")] #[derivative(PartialEq = "ignore")]
#[derivative(PartialOrd = "ignore")] #[derivative(PartialOrd = "ignore")]
#[derivative(Hash = "ignore")] #[derivative(Hash = "ignore")]
Option<Url>, Url,
), ),
} }
@ -80,8 +81,13 @@ impl std::fmt::Display for PubGrubPackage {
write!(f, "root") write!(f, "root")
} }
} }
PubGrubPackage::Package(name, None, ..) => write!(f, "{name}"), PubGrubPackage::Package(name, None) => write!(f, "{name}"),
PubGrubPackage::Package(name, Some(extra), ..) => { 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}]") write!(f, "{name}[{extra}]")
} }
} }

View File

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

View File

@ -269,10 +269,16 @@ impl ResolutionFailureReporter {
let terms_vec: Vec<_> = terms.iter().collect(); let terms_vec: Vec<_> = terms.iter().collect();
match terms_vec.as_slice() { match terms_vec.as_slice() {
[] | [(PubGrubPackage::Root(_), _)] => "version solving failed".into(), [] | [(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") format!("{package}{range} is forbidden")
} }
[(package @ PubGrubPackage::Package(..), Term::Negative(range))] => { [(
package @ (PubGrubPackage::Package(..) | PubGrubPackage::UrlPackage(..)),
Term::Negative(range),
)] => {
format!("{package}{range} is mandatory") format!("{package}{range} is mandatory")
} }
[(p1, Term::Positive(r1)), (p2, Term::Negative(r2))] => { [(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()); FxHashMap::with_capacity_and_hasher(selection.len(), BuildHasherDefault::default());
for (package, version) in selection { for (package, version) in selection {
match package { match package {
PubGrubPackage::Package(package_name, None, None) => { PubGrubPackage::Package(package_name, None) => {
let version = Version::from(version.clone()); let version = Version::from(version.clone());
let file = pins let file = pins
.get(package_name) .get(package_name)
@ -83,7 +83,7 @@ impl Graph {
let index = graph.add_node(pinned_package); let index = graph.add_node(pinned_package);
inverse.insert(package_name, index); inverse.insert(package_name, index);
} }
PubGrubPackage::Package(package_name, None, Some(url)) => { PubGrubPackage::UrlPackage(package_name, None, url) => {
let url = redirects let url = redirects
.get(url) .get(url)
.map_or_else(|| url.clone(), |url| url.value().clone()); .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, _) = if let Kind::FromDependencyOf(self_package, self_version, dependency_package, _) =
&state.incompatibility_store[*id].kind &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; continue;
}; };
let PubGrubPackage::Package(dependency_package, None, _) = dependency_package let (PubGrubPackage::Package(dependency_package, None)
| PubGrubPackage::UrlPackage(dependency_package, None, _)) = dependency_package
else { else {
continue; continue;
}; };

View File

@ -9,6 +9,7 @@ use futures::channel::mpsc::UnboundedReceiver;
use futures::{pin_mut, FutureExt, StreamExt, TryFutureExt}; use futures::{pin_mut, FutureExt, StreamExt, TryFutureExt};
use fxhash::{FxHashMap, FxHashSet}; use fxhash::{FxHashMap, FxHashSet};
use pubgrub::error::PubGrubError; use pubgrub::error::PubGrubError;
use pubgrub::range::Range; use pubgrub::range::Range;
use pubgrub::solver::{Incompatibility, State}; use pubgrub::solver::{Incompatibility, State};
use tokio::select; use tokio::select;
@ -281,14 +282,14 @@ impl<'a, Context: BuildContext + Sync> Resolver<'a, Context> {
) -> Result<(), ResolveError> { ) -> Result<(), ResolveError> {
match package { match package {
PubGrubPackage::Root(_) => {} PubGrubPackage::Root(_) => {}
PubGrubPackage::Package(package_name, _extra, None) => { PubGrubPackage::Package(package_name, _extra) => {
// Emit a request to fetch the metadata for this package. // Emit a request to fetch the metadata for this package.
if in_flight.insert_package(package_name) { if in_flight.insert_package(package_name) {
priorities.add(package_name.clone()); priorities.add(package_name.clone());
request_sink.unbounded_send(Request::Package(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. // Emit a request to fetch the metadata for this package.
if in_flight.insert_url(url) { if in_flight.insert_url(url) {
priorities.add(package_name.clone()); 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 // 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. // represent our current best guesses for the versions that we _might_ select.
for (package, range) in packages { for (package, range) in packages {
let PubGrubPackage::Package(package_name, _extra, None) = package else { let PubGrubPackage::Package(package_name, _extra) = package else {
continue; continue;
}; };
@ -372,7 +373,7 @@ impl<'a, Context: BuildContext + Sync> Resolver<'a, Context> {
return match package { return match package {
PubGrubPackage::Root(_) => Ok(Some(MIN_VERSION.clone())), 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})",); 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. // 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. // Wait for the metadata to be available.
let entry = self.index.packages.wait(package_name).await.unwrap(); let entry = self.index.packages.wait(package_name).await.unwrap();
let version_map = entry.value(); let version_map = entry.value();
@ -470,7 +471,7 @@ impl<'a, Context: BuildContext + Sync> Resolver<'a, Context> {
in_flight: &mut InFlight, in_flight: &mut InFlight,
request_sink: &futures::channel::mpsc::UnboundedSender<Request>, request_sink: &futures::channel::mpsc::UnboundedSender<Request>,
) -> Result<Dependencies, ResolveError> { ) -> Result<Dependencies, ResolveError> {
match package { let (package_name, extra, entry) = match package {
PubGrubPackage::Root(_) => { PubGrubPackage::Root(_) => {
// Add the root requirements. // Add the root requirements.
let constraints = PubGrubDependencies::try_from_requirements( let constraints = PubGrubDependencies::try_from_requirements(
@ -488,19 +489,21 @@ impl<'a, Context: BuildContext + Sync> Resolver<'a, Context> {
Self::visit_package(package, priorities, in_flight, request_sink)?; 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) => {
PubGrubPackage::Package(package_name, extra, url) => {
// Wait for the metadata to be available. // 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 versions = pins.get(package_name).unwrap();
let file = versions.get(version.into()).unwrap(); let file = versions.get(version.into()).unwrap();
self.index.versions.wait(&file.hashes.sha256).await.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 metadata = entry.value();
let mut constraints = PubGrubDependencies::try_from_requirements( let mut constraints = PubGrubDependencies::try_from_requirements(
@ -527,15 +530,13 @@ impl<'a, Context: BuildContext + Sync> Resolver<'a, Context> {
return Ok(Dependencies::Unknown); return Ok(Dependencies::Unknown);
} }
constraints.insert( constraints.insert(
PubGrubPackage::Package(package_name.clone(), None, None), PubGrubPackage::Package(package_name.clone(), None),
Range::singleton(version.clone()), Range::singleton(version.clone()),
); );
} }
Ok(Dependencies::Known(constraints.into())) Ok(Dependencies::Known(constraints.into()))
} }
}
}
/// Fetch the metadata for a stream of packages and versions. /// Fetch the metadata for a stream of packages and versions.
async fn fetch(&self, request_stream: UnboundedReceiver<Request>) -> Result<(), ResolveError> { async fn fetch(&self, request_stream: UnboundedReceiver<Request>) -> Result<(), ResolveError> {
@ -808,10 +809,10 @@ impl<'a, Context: BuildContext + Sync> Resolver<'a, Context> {
if let Some(reporter) = self.reporter.as_ref() { if let Some(reporter) = self.reporter.as_ref() {
match package { match package {
PubGrubPackage::Root(_) => {} 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)); 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( reporter.on_progress(
package_name, package_name,
extra.as_ref(), extra.as_ref(),