From 92160e37df8949595c215838885c57ee683ddc14 Mon Sep 17 00:00:00 2001 From: Charlie Marsh Date: Sat, 7 Oct 2023 15:43:12 -0400 Subject: [PATCH] Surface error when unable to find package (#45) --- Cargo.lock | 1 + crates/puffin-cli/src/commands/compile.rs | 2 +- crates/puffin-cli/src/commands/sync.rs | 2 +- crates/puffin-cli/src/main.rs | 5 +--- crates/puffin-client/src/lib.rs | 1 + crates/puffin-resolver/Cargo.toml | 1 + crates/puffin-resolver/src/lib.rs | 29 +++++++++++++++++++---- 7 files changed, 30 insertions(+), 11 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index b5ef13007..d5e88e68c 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -1773,6 +1773,7 @@ dependencies = [ "platform-tags", "puffin-client", "puffin-package", + "thiserror", "tracing", "wheel-filename", ] diff --git a/crates/puffin-cli/src/commands/compile.rs b/crates/puffin-cli/src/commands/compile.rs index 97d731749..3f064d276 100644 --- a/crates/puffin-cli/src/commands/compile.rs +++ b/crates/puffin-cli/src/commands/compile.rs @@ -49,7 +49,7 @@ pub(crate) async fn compile(src: &Path, cache: Option<&Path>) -> Result, flags: SyncFlags) -> markers, &tags, &client, - puffin_resolver::Flags::NO_DEPS, + puffin_resolver::ResolveFlags::NO_DEPS, ) .await?; diff --git a/crates/puffin-cli/src/main.rs b/crates/puffin-cli/src/main.rs index 022d6c6fa..9ad4f2a37 100644 --- a/crates/puffin-cli/src/main.rs +++ b/crates/puffin-cli/src/main.rs @@ -95,10 +95,7 @@ async fn main() -> ExitCode { Err(err) => { #[allow(clippy::print_stderr)] { - eprintln!("{}", "puffin failed".red().bold()); - for cause in err.chain() { - eprintln!(" {} {cause}", "Cause:".bold()); - } + eprintln!("{}: {}", "error".red().bold(), err); } ExitStatus::Error.into() } diff --git a/crates/puffin-client/src/lib.rs b/crates/puffin-client/src/lib.rs index 2bbac2061..7d8b68bff 100644 --- a/crates/puffin-client/src/lib.rs +++ b/crates/puffin-client/src/lib.rs @@ -1,5 +1,6 @@ pub use api::{File, SimpleJson}; pub use client::{PypiClient, PypiClientBuilder}; +pub use error::PypiClientError; mod api; mod client; diff --git a/crates/puffin-resolver/Cargo.toml b/crates/puffin-resolver/Cargo.toml index 6b32a833e..a319ff77b 100644 --- a/crates/puffin-resolver/Cargo.toml +++ b/crates/puffin-resolver/Cargo.toml @@ -21,4 +21,5 @@ bitflags = { workspace = true } futures = { workspace = true } pep440_rs = { path = "../pep440-rs" } pep508_rs = { path = "../pep508-rs" } +thiserror = { workspace = true } tracing = { workspace = true } diff --git a/crates/puffin-resolver/src/lib.rs b/crates/puffin-resolver/src/lib.rs index a00b13d3b..c7c2dbd1c 100644 --- a/crates/puffin-resolver/src/lib.rs +++ b/crates/puffin-resolver/src/lib.rs @@ -5,6 +5,7 @@ use anyhow::Result; use bitflags::bitflags; use futures::future::Either; use futures::{StreamExt, TryFutureExt}; +use thiserror::Error; use tracing::debug; use pep440_rs::Version; @@ -45,20 +46,38 @@ impl PinnedPackage { bitflags! { #[derive(Debug, Copy, Clone, Default)] - pub struct Flags: u8 { + pub struct ResolveFlags: u8 { /// Don't install package dependencies. const NO_DEPS = 1 << 0; } } +#[derive(Error, Debug)] +pub enum ResolveError { + #[error("Failed to find a version of {0} that satisfies the requirement")] + NotFound(Requirement), + + #[error(transparent)] + Client(#[from] puffin_client::PypiClientError), + + #[error(transparent)] + TrySend(#[from] futures::channel::mpsc::SendError), +} + +impl From> for ResolveError { + fn from(value: futures::channel::mpsc::TrySendError) -> Self { + value.into_send_error().into() + } +} + /// Resolve a set of requirements into a set of pinned versions. pub async fn resolve( requirements: &Requirements, markers: &MarkerEnvironment, tags: &Tags, client: &PypiClient, - flags: Flags, -) -> Result { + flags: ResolveFlags, +) -> Result { // A channel to fetch package metadata (e.g., given `flask`, fetch all versions) and version // metadata (e.g., given `flask==1.0.0`, fetch the metadata for that version). let (package_sink, package_stream) = futures::channel::mpsc::unbounded(); @@ -128,7 +147,7 @@ pub async fn resolve( .iter() .all(|specifier| specifier.contains(&version)) }) else { - continue; + return Err(ResolveError::NotFound(requirement)); }; package_sink.unbounded_send(Request::Version(requirement, file.clone()))?; @@ -151,7 +170,7 @@ pub async fn resolve( }, ); - if !flags.intersects(Flags::NO_DEPS) { + if !flags.intersects(ResolveFlags::NO_DEPS) { // Enqueue its dependencies. for dependency in metadata.requires_dist { if !dependency.evaluate_markers(