From f2dd0d90be3386f346ba2a7f8a143f99f2d9730e Mon Sep 17 00:00:00 2001 From: Charlie Marsh Date: Sun, 29 Oct 2023 19:00:09 -0700 Subject: [PATCH] Add a resolver reporter (#225) Closes https://github.com/astral-sh/puffin/issues/223. --- crates/puffin-cli/src/commands/pip_compile.rs | 4 +- crates/puffin-cli/src/commands/reporters.rs | 32 +++++++++++++++- crates/puffin-resolver/src/lib.rs | 4 +- crates/puffin-resolver/src/resolver.rs | 37 +++++++++++++++++++ 4 files changed, 73 insertions(+), 4 deletions(-) diff --git a/crates/puffin-cli/src/commands/pip_compile.rs b/crates/puffin-cli/src/commands/pip_compile.rs index 328bc021a..a8647302f 100644 --- a/crates/puffin-cli/src/commands/pip_compile.rs +++ b/crates/puffin-cli/src/commands/pip_compile.rs @@ -18,6 +18,7 @@ use puffin_dispatch::BuildDispatch; use puffin_interpreter::Virtualenv; use puffin_resolver::{Manifest, PreReleaseMode, ResolutionMode}; +use crate::commands::reporters::ResolverReporter; use crate::commands::{elapsed, ExitStatus}; use crate::index_urls::IndexUrls; use crate::printer::Printer; @@ -110,7 +111,8 @@ pub(crate) async fn pip_compile( &tags, &client, &build_dispatch, - ); + ) + .with_reporter(ResolverReporter::from(printer)); let resolution = match resolver.resolve().await { Err(puffin_resolver::ResolveError::PubGrub(pubgrub::error::PubGrubError::NoSolution( mut derivation_tree, diff --git a/crates/puffin-cli/src/commands/reporters.rs b/crates/puffin-cli/src/commands/reporters.rs index 8281ede33..56dd535c2 100644 --- a/crates/puffin-cli/src/commands/reporters.rs +++ b/crates/puffin-cli/src/commands/reporters.rs @@ -1,4 +1,5 @@ use indicatif::{ProgressBar, ProgressStyle}; +use std::time::Duration; use pep440_rs::Version; use puffin_package::package_name::PackageName; @@ -29,7 +30,7 @@ impl WheelFinderReporter { } } -impl puffin_resolver::Reporter for WheelFinderReporter { +impl puffin_resolver::WheelFinderReporter for WheelFinderReporter { fn on_progress(&self, package: &puffin_resolver::PinnedPackage) { self.progress .set_message(format!("{}=={}", package.name(), package.version())); @@ -145,3 +146,32 @@ impl puffin_installer::InstallReporter for InstallReporter { self.progress.finish_and_clear(); } } + +#[derive(Debug)] +pub(crate) struct ResolverReporter { + progress: ProgressBar, +} + +impl From for ResolverReporter { + fn from(printer: Printer) -> Self { + let progress = ProgressBar::with_draw_target(None, printer.target()); + progress.set_message("Resolving dependencies..."); + progress.enable_steady_tick(Duration::from_millis(200)); + progress.set_style( + ProgressStyle::with_template("{spinner:.white} {wide_msg:.dim}") + .unwrap() + .tick_strings(&["⠋", "⠙", "⠹", "⠸", "⠼", "⠴", "⠦", "⠧", "⠇", "⠏"]), + ); + Self { progress } + } +} + +impl puffin_resolver::ResolverReporter for ResolverReporter { + fn on_progress(&self, name: &PackageName, version: &Version) { + self.progress.set_message(format!("{name}=={version}")); + } + + fn on_complete(&self) { + self.progress.finish_and_clear(); + } +} diff --git a/crates/puffin-resolver/src/lib.rs b/crates/puffin-resolver/src/lib.rs index 5ec0e935d..6f2689a4f 100644 --- a/crates/puffin-resolver/src/lib.rs +++ b/crates/puffin-resolver/src/lib.rs @@ -3,9 +3,9 @@ pub use manifest::Manifest; pub use prerelease_mode::PreReleaseMode; pub use resolution::{Graph, PinnedPackage}; pub use resolution_mode::ResolutionMode; -pub use resolver::Resolver; +pub use resolver::{Reporter as ResolverReporter, Resolver}; pub use source_distribution::BuiltSourceDistributionCache; -pub use wheel_finder::{Reporter, WheelFinder}; +pub use wheel_finder::{Reporter as WheelFinderReporter, WheelFinder}; mod candidate_selector; mod distribution; diff --git a/crates/puffin-resolver/src/resolver.rs b/crates/puffin-resolver/src/resolver.rs index 01676c13e..056e7af07 100644 --- a/crates/puffin-resolver/src/resolver.rs +++ b/crates/puffin-resolver/src/resolver.rs @@ -50,6 +50,7 @@ pub struct Resolver<'a, Context: BuildContext + Sync> { selector: CandidateSelector, index: Arc, build_context: &'a Context, + reporter: Option>, } #[derive(Debug, Default)] @@ -92,6 +93,16 @@ impl<'a, Context: BuildContext + Sync> Resolver<'a, Context> { tags, client, build_context, + reporter: None, + } + } + + /// Set the [`Reporter`] to use for this installer. + #[must_use] + pub fn with_reporter(self, reporter: impl Reporter + 'static) -> Self { + Self { + reporter: Some(Box::new(reporter)), + ..self } } @@ -121,6 +132,8 @@ impl<'a, Context: BuildContext + Sync> Resolver<'a, Context> { } }; + self.on_complete(); + Ok(resolution) } @@ -210,6 +223,8 @@ impl<'a, Context: BuildContext + Sync> Resolver<'a, Context> { Some(version) => version, }; + self.on_progress(&next, &version); + if added_dependencies .entry(next.clone()) .or_default() @@ -620,6 +635,28 @@ impl<'a, Context: BuildContext + Sync> Resolver<'a, Context> { }), } } + + fn on_progress(&self, package: &PubGrubPackage, version: &PubGrubVersion) { + if let Some(reporter) = self.reporter.as_ref() { + if let PubGrubPackage::Package(package_name, _) = package { + reporter.on_progress(package_name, version.into()); + } + } + } + + fn on_complete(&self) { + if let Some(reporter) = self.reporter.as_ref() { + reporter.on_complete(); + } + } +} + +pub trait Reporter: Send + Sync { + /// Callback to invoke when a dependency is resolved. + fn on_progress(&self, name: &PackageName, version: &pep440_rs::Version); + + /// Callback to invoke when the resolution is complete. + fn on_complete(&self); } /// Fetch the metadata for an item