Surface PubGrub derivation trees (#108)

I think the derivation trees could be stronger but this exposes
PubGrub's proof-like error messages.

Closes #102.
This commit is contained in:
Charlie Marsh 2023-10-16 14:14:36 -04:00 committed by GitHub
parent bae52d5edd
commit 5f5788e866
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
7 changed files with 50 additions and 14 deletions

1
Cargo.lock generated
View file

@ -1826,6 +1826,7 @@ dependencies = [
"pep508_rs", "pep508_rs",
"platform-host", "platform-host",
"platform-tags", "platform-tags",
"pubgrub",
"puffin-client", "puffin-client",
"puffin-installer", "puffin-installer",
"puffin-interpreter", "puffin-interpreter",

View file

@ -14,6 +14,7 @@ pep440_rs = { path = "../pep440-rs" }
pep508_rs = { path = "../pep508-rs" } pep508_rs = { path = "../pep508-rs" }
platform-host = { path = "../platform-host" } platform-host = { path = "../platform-host" }
platform-tags = { path = "../platform-tags" } platform-tags = { path = "../platform-tags" }
pubgrub = { path = "../../vendor/pubgrub" }
puffin-client = { path = "../puffin-client" } puffin-client = { path = "../puffin-client" }
puffin-installer = { path = "../puffin-installer" } puffin-installer = { path = "../puffin-installer" }
puffin-interpreter = { path = "../puffin-interpreter" } puffin-interpreter = { path = "../puffin-interpreter" }

View file

@ -5,6 +5,7 @@ use std::path::Path;
use anyhow::Result; use anyhow::Result;
use colored::Colorize; use colored::Colorize;
use pubgrub::report::Reporter;
use tracing::debug; use tracing::debug;
use platform_host::Platform; use platform_host::Platform;
@ -62,7 +63,23 @@ pub(crate) async fn compile(
// Resolve the dependencies. // Resolve the dependencies.
let resolver = puffin_resolver::Resolver::new(requirements, markers, &tags, &client); let resolver = puffin_resolver::Resolver::new(requirements, markers, &tags, &client);
let resolution = resolver.resolve().await?; let resolution = match resolver.resolve().await {
Err(puffin_resolver::ResolveError::PubGrub(pubgrub::error::PubGrubError::NoSolution(
mut derivation_tree,
))) => {
derivation_tree.collapse_no_versions();
#[allow(clippy::print_stderr)]
{
eprintln!("{}: {}", "error".red().bold(), "no solution found".bold());
eprintln!(
"{}",
pubgrub::report::DefaultStringReporter::report(&derivation_tree)
);
}
return Ok(ExitStatus::Failure);
}
result => result,
}?;
let s = if resolution.len() == 1 { "" } else { "s" }; let s = if resolution.len() == 1 { "" } else { "s" };
writeln!( writeln!(

View file

@ -1,11 +1,12 @@
use std::path::PathBuf; use std::path::PathBuf;
use std::process::ExitCode; use std::process::ExitCode;
use crate::commands::ExitStatus;
use clap::{Args, Parser, Subcommand}; use clap::{Args, Parser, Subcommand};
use colored::Colorize; use colored::Colorize;
use directories::ProjectDirs; use directories::ProjectDirs;
use crate::commands::ExitStatus;
mod commands; mod commands;
mod logging; mod logging;
mod printer; mod printer;

View file

@ -1,3 +1,4 @@
pub use error::ResolveError;
pub use resolution::{PinnedPackage, Resolution}; pub use resolution::{PinnedPackage, Resolution};
pub use resolver::Resolver; pub use resolver::Resolver;
pub use wheel_finder::{Reporter, WheelFinder}; pub use wheel_finder::{Reporter, WheelFinder};

View file

@ -17,7 +17,7 @@ pub enum PubGrubPackage {
impl std::fmt::Display for PubGrubPackage { impl std::fmt::Display for PubGrubPackage {
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
match self { match self {
PubGrubPackage::Root => write!(f, "<root>"), PubGrubPackage::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}]") write!(f, "{name}[{extra}]")

View file

@ -1,6 +1,7 @@
//! Given a set of requirements, find a set of compatible packages. //! Given a set of requirements, find a set of compatible packages.
use std::borrow::Borrow; use std::borrow::Borrow;
use std::collections::hash_map::Entry;
use std::collections::{BTreeMap, HashMap, HashSet}; use std::collections::{BTreeMap, HashMap, HashSet};
use std::str::FromStr; use std::str::FromStr;
use std::sync::Arc; use std::sync::Arc;
@ -158,16 +159,13 @@ impl<'a> Resolver<'a> {
// Fetch the list of candidates. // Fetch the list of candidates.
let Some(potential_packages) = state.partial_solution.potential_packages() else { let Some(potential_packages) = state.partial_solution.potential_packages() else {
let Some(selected_dependencies) = state.partial_solution.extract_solution() else { let Some(selection) = state.partial_solution.extract_solution() else {
return Err(PubGrubError::Failure( return Err(PubGrubError::Failure(
"How did we end up with no package to choose but no solution?".into(), "How did we end up with no package to choose but no solution?".into(),
) )
.into()); .into());
}; };
return Ok(PubGrubResolution { return Ok(PubGrubResolution { selection, pins });
selected_dependencies,
pins,
});
}; };
// Choose a package version. // Choose a package version.
@ -415,12 +413,23 @@ impl<'a> Resolver<'a> {
for (package, version) in for (package, version) in
iter_requirements(self.requirements.iter(), None, self.markers) iter_requirements(self.requirements.iter(), None, self.markers)
{ {
constraints.insert(package, version); match constraints.entry(package) {
Entry::Occupied(mut entry) => {
entry.insert(entry.get().intersection(&version));
}
Entry::Vacant(entry) => {
entry.insert(version);
}
}
} }
Ok(Dependencies::Known(constraints)) Ok(Dependencies::Known(constraints))
} }
PubGrubPackage::Package(package_name, extra) => { PubGrubPackage::Package(package_name, extra) => {
debug!("Fetching dependencies for {}[{:?}]", package_name, extra); if let Some(extra) = extra.as_ref() {
debug!("Fetching dependencies for {}[{:?}]", package_name, extra);
} else {
debug!("Fetching dependencies for {}", package_name);
}
// Wait for the metadata to be available. // Wait for the metadata to be available.
let versions = pins.get(package_name).unwrap(); let versions = pins.get(package_name).unwrap();
@ -429,7 +438,6 @@ impl<'a> Resolver<'a> {
let metadata = entry.value(); let metadata = entry.value();
let mut constraints = DependencyConstraints::default(); let mut constraints = DependencyConstraints::default();
for (package, version) in for (package, version) in
iter_requirements(metadata.requires_dist.iter(), extra.as_ref(), self.markers) iter_requirements(metadata.requires_dist.iter(), extra.as_ref(), self.markers)
{ {
@ -443,7 +451,14 @@ impl<'a> Resolver<'a> {
} }
// Add it to the constraints. // Add it to the constraints.
constraints.insert(package, version); match constraints.entry(package) {
Entry::Occupied(mut entry) => {
entry.insert(entry.get().intersection(&version));
}
Entry::Vacant(entry) => {
entry.insert(version);
}
}
} }
if let Some(extra) = extra { if let Some(extra) = extra {
@ -512,7 +527,7 @@ enum Dependencies {
#[derive(Debug)] #[derive(Debug)]
struct PubGrubResolution { struct PubGrubResolution {
/// The selected dependencies. /// The selected dependencies.
selected_dependencies: SelectedDependencies<PubGrubPackage, PubGrubVersion>, selection: SelectedDependencies<PubGrubPackage, PubGrubVersion>,
/// The selected file (source or built distribution) for each package. /// The selected file (source or built distribution) for each package.
pins: HashMap<PackageName, HashMap<pep440_rs::Version, File>>, pins: HashMap<PackageName, HashMap<pep440_rs::Version, File>>,
} }
@ -520,7 +535,7 @@ struct PubGrubResolution {
impl From<PubGrubResolution> for Resolution { impl From<PubGrubResolution> for Resolution {
fn from(value: PubGrubResolution) -> Self { fn from(value: PubGrubResolution) -> Self {
let mut packages = BTreeMap::new(); let mut packages = BTreeMap::new();
for (package, version) in value.selected_dependencies { for (package, version) in value.selection {
let PubGrubPackage::Package(package_name, None) = package else { let PubGrubPackage::Package(package_name, None) = package else {
continue; continue;
}; };