mirror of
https://github.com/astral-sh/uv.git
synced 2025-07-07 21:35:00 +00:00
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:
parent
bae52d5edd
commit
5f5788e866
7 changed files with 50 additions and 14 deletions
1
Cargo.lock
generated
1
Cargo.lock
generated
|
@ -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",
|
||||||
|
|
|
@ -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" }
|
||||||
|
|
|
@ -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!(
|
||||||
|
|
|
@ -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;
|
||||||
|
|
|
@ -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};
|
||||||
|
|
|
@ -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}]")
|
||||||
|
|
|
@ -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;
|
||||||
};
|
};
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue