Show requirement sources in pip-compile output (#149)

Builds up a complete resolved graph from PubGrub, and shows the sources
that led to each package being included in the resolution, like
`pip-compile`.

Closes https://github.com/astral-sh/puffin/issues/60.
This commit is contained in:
Charlie Marsh 2023-10-20 01:14:59 -04:00 committed by GitHub
parent e662fe341b
commit 8001c792e7
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
20 changed files with 336 additions and 233 deletions

View file

@ -71,11 +71,11 @@ pub(crate) async fn pip_compile(
derivation_tree.collapse_no_versions();
#[allow(clippy::print_stderr)]
{
eprintln!("{}: {}", "error".red().bold(), "no solution found".bold());
eprintln!(
"{}",
pubgrub::report::DefaultStringReporter::report(&derivation_tree)
);
let report = miette::Report::msg(pubgrub::report::DefaultStringReporter::report(
&derivation_tree,
))
.context("No solution found when resolving dependencies:");
eprint!("{report:?}");
}
return Ok(ExitStatus::Failure);
}
@ -111,7 +111,7 @@ pub(crate) async fn pip_compile(
"{}",
format!("# {}", env::args().join(" ")).green()
)?;
writeln!(writer, "{resolution}")?;
write!(writer, "{resolution}")?;
Ok(ExitStatus::Success)
}

View file

@ -16,7 +16,6 @@ use puffin_installer::{
};
use puffin_interpreter::PythonExecutable;
use puffin_package::package_name::PackageName;
use puffin_resolver::Resolution;
use crate::commands::reporters::{
DownloadReporter, InstallReporter, UnzipReporter, WheelFinderReporter,
@ -93,8 +92,8 @@ pub(crate) async fn sync_requirements(
let client = PypiClientBuilder::default().cache(cache).build();
// Resolve the dependencies.
let resolution = if remote.is_empty() {
Resolution::default()
let remote = if remote.is_empty() {
Vec::new()
} else {
let start = std::time::Instant::now();
@ -115,33 +114,32 @@ pub(crate) async fn sync_requirements(
)?;
resolution
.into_files()
.map(RemoteDistribution::from_file)
.collect::<Result<Vec<_>>>()?
};
// Download any missing distributions.
let staging = tempfile::tempdir()?;
let uncached = resolution
.into_files()
.map(RemoteDistribution::from_file)
.collect::<Result<Vec<_>>>()?;
let downloads = if uncached.is_empty() {
let downloads = if remote.is_empty() {
vec![]
} else {
let start = std::time::Instant::now();
let downloader = puffin_installer::Downloader::new(&client, cache)
.with_reporter(DownloadReporter::from(printer).with_length(uncached.len() as u64));
.with_reporter(DownloadReporter::from(printer).with_length(remote.len() as u64));
let downloads = downloader
.download(&uncached, cache.unwrap_or(staging.path()))
.download(&remote, cache.unwrap_or(staging.path()))
.await?;
let s = if uncached.len() == 1 { "" } else { "s" };
let s = if remote.len() == 1 { "" } else { "s" };
writeln!(
printer,
"{}",
format!(
"Downloaded {} in {}",
format!("{} package{}", uncached.len(), s).bold(),
format!("{} package{}", remote.len(), s).bold(),
elapsed(start.elapsed())
)
.dimmed()