Skip to content

Commit 4d7f4fd

Browse files
committed
Build backend: Improve build frontend error handling
Move the error handling for `build_package` into an enum, to avoid `bail!` and duplicated `.context()` calls. No user-facing changes except unifying the source dist extension error message.
1 parent 7d82cbf commit 4d7f4fd

File tree

3 files changed

+62
-25
lines changed

3 files changed

+62
-25
lines changed

Cargo.lock

+1
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

crates/uv/Cargo.toml

+1
Original file line numberDiff line numberDiff line change
@@ -16,6 +16,7 @@ workspace = true
1616
[dependencies]
1717
uv-auth = { workspace = true }
1818
uv-build-backend = { workspace = true }
19+
uv-build-frontend = { workspace = true }
1920
uv-cache = { workspace = true }
2021
uv-cache-info = { workspace = true }
2122
uv-cache-key = { workspace = true }

crates/uv/src/commands/build_frontend.rs

+60-25
Original file line numberDiff line numberDiff line change
@@ -1,13 +1,20 @@
11
use std::borrow::Cow;
22
use std::fmt::Write as _;
3-
use std::io;
43
use std::io::Write as _;
54
use std::path::{Path, PathBuf};
5+
use std::{fmt, io};
66

7-
use anyhow::{bail, Context, Result};
7+
use anyhow::{Context, Result};
88
use owo_colors::OwoColorize;
9+
use thiserror::Error;
910
use tracing::{debug, instrument, trace};
1011

12+
use crate::commands::pip::operations;
13+
use crate::commands::project::find_requires_python;
14+
use crate::commands::reporters::PythonDownloadReporter;
15+
use crate::commands::ExitStatus;
16+
use crate::printer::Printer;
17+
use crate::settings::{ResolverSettings, ResolverSettingsRef};
1118
use uv_auth::store_credentials;
1219
use uv_build_backend::PyProjectToml;
1320
use uv_cache::{Cache, CacheBucket};
@@ -34,12 +41,42 @@ use uv_settings::PythonInstallMirrors;
3441
use uv_types::{BuildContext, BuildIsolation, HashStrategy};
3542
use uv_workspace::{DiscoveryOptions, Workspace, WorkspaceError};
3643

37-
use crate::commands::pip::operations;
38-
use crate::commands::project::find_requires_python;
39-
use crate::commands::reporters::PythonDownloadReporter;
40-
use crate::commands::ExitStatus;
41-
use crate::printer::Printer;
42-
use crate::settings::{ResolverSettings, ResolverSettingsRef};
44+
#[derive(Debug, Error)]
45+
enum Error {
46+
#[error(transparent)]
47+
Io(#[from] io::Error),
48+
#[error(transparent)]
49+
FindOrDownloadPython(#[from] uv_python::Error),
50+
#[error(transparent)]
51+
HashStrategy(#[from] uv_types::HashStrategyError),
52+
#[error(transparent)]
53+
FlatIndex(#[from] uv_client::FlatIndexError),
54+
#[error(transparent)]
55+
BuildPlan(anyhow::Error),
56+
#[error(transparent)]
57+
Extract(#[from] uv_extract::Error),
58+
#[error(transparent)]
59+
Operations(#[from] operations::Error),
60+
#[error(transparent)]
61+
Join(#[from] tokio::task::JoinError),
62+
#[error(transparent)]
63+
BuildBackend(#[from] uv_build_backend::Error),
64+
#[error(transparent)]
65+
BuildDispatch(anyhow::Error),
66+
#[error(transparent)]
67+
BuildFrontend(#[from] uv_build_frontend::Error),
68+
#[error("Failed to write message")]
69+
Fmt(#[from] fmt::Error),
70+
#[error("Can't use `--force-pep517` with `--list`")]
71+
ListForcePep517,
72+
#[error("Can only use `--list` with the uv backend")]
73+
ListNonUv,
74+
#[error(
75+
"`{0}` is not a valid build source. Expected to receive a source directory, or a source \
76+
distribution ending in one of: {1}."
77+
)]
78+
InvalidSourceDistExt(String, uv_distribution_filename::ExtensionError),
79+
}
4380

4481
/// Build source distributions and wheels.
4582
#[allow(clippy::fn_params_excessive_bools)]
@@ -334,7 +371,7 @@ async fn build_impl(
334371

335372
let report = miette::Report::new(Diagnostic {
336373
source: source.to_string(),
337-
cause: err,
374+
cause: err.into(),
338375
});
339376
anstream::eprint!("{report:?}");
340377

@@ -386,7 +423,7 @@ async fn build_package(
386423
link_mode: LinkMode,
387424
config_setting: &ConfigSettings,
388425
preview: PreviewMode,
389-
) -> Result<Vec<BuildMessage>> {
426+
) -> Result<Vec<BuildMessage>, Error> {
390427
let output_dir = if let Some(output_dir) = output_dir {
391428
Cow::Owned(std::path::absolute(output_dir)?)
392429
} else {
@@ -534,18 +571,18 @@ async fn build_package(
534571
prepare_output_directory(&output_dir).await?;
535572

536573
// Determine the build plan.
537-
let plan = BuildPlan::determine(&source, sdist, wheel)?;
574+
let plan = BuildPlan::determine(&source, sdist, wheel).map_err(Error::BuildPlan)?;
538575

539576
// Check if the build backend is matching uv version that allows calling in the uv build backend
540577
// directly.
541578
let build_action = if list {
542579
if force_pep517 {
543-
bail!("Can't use `--force-pep517` with `--list`");
580+
return Err(Error::ListForcePep517);
544581
}
545582

546583
if !check_fast_path(source.path()) {
547584
// TODO(konsti): Provide more context on what mismatched
548-
bail!("Can only use `--list` with the uv backend");
585+
return Err(Error::ListNonUv);
549586
}
550587

551588
BuildAction::List
@@ -614,9 +651,8 @@ async fn build_package(
614651
// Extract the source distribution into a temporary directory.
615652
let path = output_dir.join(sdist_build.filename());
616653
let reader = fs_err::tokio::File::open(&path).await?;
617-
let ext = SourceDistExtension::from_path(path.as_path()).map_err(|err| {
618-
anyhow::anyhow!("`{}` is not a valid source distribution, as it ends with an unsupported extension. Expected one of: {err}.", path.user_display())
619-
})?;
654+
let ext = SourceDistExtension::from_path(path.as_path())
655+
.map_err(|err| Error::InvalidSourceDistExt(path.user_display().to_string(), err))?;
620656
let temp_dir = tempfile::tempdir_in(cache.bucket(CacheBucket::SourceDistributions))?;
621657
uv_extract::stream::archive(reader, ext, temp_dir.path()).await?;
622658

@@ -719,10 +755,7 @@ async fn build_package(
719755
// Extract the source distribution into a temporary directory.
720756
let reader = fs_err::tokio::File::open(source.path()).await?;
721757
let ext = SourceDistExtension::from_path(source.path()).map_err(|err| {
722-
anyhow::anyhow!(
723-
"`{}` is not a valid build source. Expected to receive a source directory, or a source distribution ending in one of: {err}.",
724-
source.path().user_display()
725-
)
758+
Error::InvalidSourceDistExt(source.path().user_display().to_string(), err)
726759
})?;
727760
let temp_dir = tempfile::tempdir_in(&output_dir)?;
728761
uv_extract::stream::archive(reader, ext, temp_dir.path()).await?;
@@ -794,7 +827,7 @@ async fn build_sdist(
794827
subdirectory: Option<&Path>,
795828
version_id: Option<&str>,
796829
build_output: BuildOutput,
797-
) -> Result<BuildMessage> {
830+
) -> Result<BuildMessage, Error> {
798831
let build_result = match action {
799832
BuildAction::List => {
800833
let source_tree_ = source_tree.to_path_buf();
@@ -859,7 +892,8 @@ async fn build_sdist(
859892
BuildKind::Sdist,
860893
build_output,
861894
)
862-
.await?;
895+
.await
896+
.map_err(Error::BuildDispatch)?;
863897
let filename = builder.build(output_dir).await?;
864898
BuildMessage::Build {
865899
filename,
@@ -886,7 +920,7 @@ async fn build_wheel(
886920
subdirectory: Option<&Path>,
887921
version_id: Option<&str>,
888922
build_output: BuildOutput,
889-
) -> Result<BuildMessage> {
923+
) -> Result<BuildMessage, Error> {
890924
let build_message = match action {
891925
BuildAction::List => {
892926
let source_tree_ = source_tree.to_path_buf();
@@ -951,7 +985,8 @@ async fn build_wheel(
951985
BuildKind::Wheel,
952986
build_output,
953987
)
954-
.await?;
988+
.await
989+
.map_err(Error::BuildDispatch)?;
955990
let filename = builder.build(output_dir).await?;
956991
BuildMessage::Build {
957992
filename,
@@ -963,7 +998,7 @@ async fn build_wheel(
963998
}
964999

9651000
/// Create the output directory and add a `.gitignore`.
966-
async fn prepare_output_directory(output_dir: &Path) -> Result<()> {
1001+
async fn prepare_output_directory(output_dir: &Path) -> Result<(), Error> {
9671002
// Create the output directory.
9681003
fs_err::tokio::create_dir_all(&output_dir).await?;
9691004

0 commit comments

Comments
 (0)