Add `UV_HIDE_BUILD_OUTPUT` to omit build logs (#16885)

## Summary

Closes #16804.
This commit is contained in:
Charlie Marsh 2025-12-02 16:43:01 -08:00 committed by GitHub
parent e7af5838bb
commit eb65f9ff74
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
9 changed files with 126 additions and 3 deletions

1
Cargo.lock generated
View File

@ -5994,6 +5994,7 @@ dependencies = [
"uv-distribution-filename", "uv-distribution-filename",
"uv-distribution-types", "uv-distribution-types",
"uv-extract", "uv-extract",
"uv-flags",
"uv-fs", "uv-fs",
"uv-git", "uv-git",
"uv-git-types", "uv-git-types",

View File

@ -24,6 +24,7 @@ uv-configuration = { workspace = true }
uv-distribution-filename = { workspace = true } uv-distribution-filename = { workspace = true }
uv-distribution-types = { workspace = true } uv-distribution-types = { workspace = true }
uv-extract = { workspace = true } uv-extract = { workspace = true }
uv-flags = { workspace = true }
uv-fs = { workspace = true, features = ["tokio"] } uv-fs = { workspace = true, features = ["tokio"] }
uv-git = { workspace = true } uv-git = { workspace = true }
uv-git-types = { workspace = true } uv-git-types = { workspace = true }

View File

@ -2503,7 +2503,11 @@ impl<'a, T: BuildContext> SourceDistributionBuilder<'a, T> {
} else { } else {
BuildKind::Wheel BuildKind::Wheel
}, },
BuildOutput::Debug, if uv_flags::contains(uv_flags::EnvironmentFlags::HIDE_BUILD_OUTPUT) {
BuildOutput::Quiet
} else {
BuildOutput::Debug
},
self.build_stack.cloned().unwrap_or_default(), self.build_stack.cloned().unwrap_or_default(),
) )
.await .await
@ -2604,7 +2608,11 @@ impl<'a, T: BuildContext> SourceDistributionBuilder<'a, T> {
source.as_dist(), source.as_dist(),
source_strategy, source_strategy,
build_kind, build_kind,
BuildOutput::Debug, if uv_flags::contains(uv_flags::EnvironmentFlags::HIDE_BUILD_OUTPUT) {
BuildOutput::Quiet
} else {
BuildOutput::Debug
},
self.build_stack.cloned().unwrap_or_default(), self.build_stack.cloned().unwrap_or_default(),
) )
.await .await

View File

@ -6,6 +6,7 @@ bitflags::bitflags! {
#[derive(Debug, Clone, Copy, PartialEq, Eq, Default)] #[derive(Debug, Clone, Copy, PartialEq, Eq, Default)]
pub struct EnvironmentFlags: u32 { pub struct EnvironmentFlags: u32 {
const SKIP_WHEEL_FILENAME_CHECK = 1 << 0; const SKIP_WHEEL_FILENAME_CHECK = 1 << 0;
const HIDE_BUILD_OUTPUT = 1 << 1;
} }
} }

View File

@ -585,6 +585,7 @@ pub struct Concurrency {
#[derive(Debug, Clone)] #[derive(Debug, Clone)]
pub struct EnvironmentOptions { pub struct EnvironmentOptions {
pub skip_wheel_filename_check: Option<bool>, pub skip_wheel_filename_check: Option<bool>,
pub hide_build_output: Option<bool>,
pub python_install_bin: Option<bool>, pub python_install_bin: Option<bool>,
pub python_install_registry: Option<bool>, pub python_install_registry: Option<bool>,
pub install_mirrors: PythonInstallMirrors, pub install_mirrors: PythonInstallMirrors,
@ -613,6 +614,7 @@ impl EnvironmentOptions {
skip_wheel_filename_check: parse_boolish_environment_variable( skip_wheel_filename_check: parse_boolish_environment_variable(
EnvVars::UV_SKIP_WHEEL_FILENAME_CHECK, EnvVars::UV_SKIP_WHEEL_FILENAME_CHECK,
)?, )?,
hide_build_output: parse_boolish_environment_variable(EnvVars::UV_HIDE_BUILD_OUTPUT)?,
python_install_bin: parse_boolish_environment_variable(EnvVars::UV_PYTHON_INSTALL_BIN)?, python_install_bin: parse_boolish_environment_variable(EnvVars::UV_PYTHON_INSTALL_BIN)?,
python_install_registry: parse_boolish_environment_variable( python_install_registry: parse_boolish_environment_variable(
EnvVars::UV_PYTHON_INSTALL_REGISTRY, EnvVars::UV_PYTHON_INSTALL_REGISTRY,
@ -775,6 +777,9 @@ impl From<&EnvironmentOptions> for EnvironmentFlags {
if options.skip_wheel_filename_check == Some(true) { if options.skip_wheel_filename_check == Some(true) {
flags.insert(Self::SKIP_WHEEL_FILENAME_CHECK); flags.insert(Self::SKIP_WHEEL_FILENAME_CHECK);
} }
if options.hide_build_output == Some(true) {
flags.insert(Self::HIDE_BUILD_OUTPUT);
}
flags flags
} }
} }

View File

@ -1236,4 +1236,9 @@ impl EnvVars {
/// around invalid artifacts in rare cases. /// around invalid artifacts in rare cases.
#[attr_added_in("0.8.23")] #[attr_added_in("0.8.23")]
pub const UV_SKIP_WHEEL_FILENAME_CHECK: &'static str = "UV_SKIP_WHEEL_FILENAME_CHECK"; pub const UV_SKIP_WHEEL_FILENAME_CHECK: &'static str = "UV_SKIP_WHEEL_FILENAME_CHECK";
/// Suppress output from the build backend when building source distributions, even in the event
/// of build failures.
#[attr_added_in("0.9.14")]
pub const UV_HIDE_BUILD_OUTPUT: &'static str = "UV_HIDE_BUILD_OUTPUT";
} }

View File

@ -663,7 +663,7 @@ async fn build_package(
let build_output = match printer { let build_output = match printer {
Printer::Default | Printer::NoProgress | Printer::Verbose => { Printer::Default | Printer::NoProgress | Printer::Verbose => {
if build_logs { if build_logs && !uv_flags::contains(uv_flags::EnvironmentFlags::HIDE_BUILD_OUTPUT) {
BuildOutput::Stderr BuildOutput::Stderr
} else { } else {
BuildOutput::Quiet BuildOutput::Quiet

View File

@ -1180,6 +1180,102 @@ fn build_no_build_logs() -> Result<()> {
Ok(()) Ok(())
} }
/// Test that `UV_HIDE_BUILD_OUTPUT` suppresses build output.
#[test]
fn build_hide_build_output_env_var() -> Result<()> {
let context = TestContext::new("3.12");
let project = context.temp_dir.child("project");
let pyproject_toml = project.child("pyproject.toml");
pyproject_toml.write_str(
r#"
[project]
name = "project"
version = "0.1.0"
requires-python = ">=3.12"
dependencies = ["anyio==3.7.0"]
[build-system]
requires = ["hatchling"]
build-backend = "hatchling.build"
"#,
)?;
project
.child("src")
.child("project")
.child("__init__.py")
.touch()?;
project.child("README").touch()?;
uv_snapshot!(&context.filters(), context.build().arg("project").env(EnvVars::UV_HIDE_BUILD_OUTPUT, "1"), @r###"
success: true
exit_code: 0
----- stdout -----
----- stderr -----
Building source distribution...
Building wheel from source distribution...
Successfully built project/dist/project-0.1.0.tar.gz
Successfully built project/dist/project-0.1.0-py3-none-any.whl
"###);
Ok(())
}
/// Test that `UV_HIDE_BUILD_OUTPUT` hides build output even on failure.
#[test]
fn build_hide_build_output_on_failure() -> Result<()> {
let context = TestContext::new("3.12");
let filters = context
.filters()
.into_iter()
.chain([(r"\\\.", "")])
.collect::<Vec<_>>();
let project = context.temp_dir.child("project");
let pyproject_toml = project.child("pyproject.toml");
pyproject_toml.write_str(
r#"
[project]
name = "project"
version = "0.1.0"
requires-python = ">=3.12"
[build-system]
requires = ["setuptools"]
build-backend = "setuptools.build_meta"
"#,
)?;
// Create a `setup.py` that prints an environment variable before failing.
project.child("setup.py").write_str(indoc! {r#"
import os
import sys
print("FOO=" + os.environ.get("FOO", "not-set"), file=sys.stderr)
sys.stderr.flush()
raise Exception("Build failed intentionally!")
"#})?;
// With `UV_HIDE_BUILD_OUTPUT`, the output is hidden even on failure.
uv_snapshot!(&filters, context.build().arg("project").env(EnvVars::UV_HIDE_BUILD_OUTPUT, "1").env("FOO", "bar"), @r###"
success: false
exit_code: 2
----- stdout -----
----- stderr -----
Building source distribution...
× Failed to build `[TEMP_DIR]/project`
The build backend returned an error
Call to `setuptools.build_meta.build_sdist` failed (exit status: 1)
hint: This usually indicates a problem with the package or the build environment.
"###);
Ok(())
}
#[test] #[test]
fn build_tool_uv_sources() -> Result<()> { fn build_tool_uv_sources() -> Result<()> {
let context = TestContext::new("3.12"); let context = TestContext::new("3.12");

View File

@ -150,6 +150,12 @@ Equivalent to the `--token` argument for self update. A GitHub token for authent
Enables fetching files stored in Git LFS when installing a package from a Git repository. Enables fetching files stored in Git LFS when installing a package from a Git repository.
### `UV_HIDE_BUILD_OUTPUT`
<small class="added-in">added in `0.9.14`</small>
Suppress output from the build backend when building source distributions, even in the event
of build failures.
### `UV_HTTP_RETRIES` ### `UV_HTTP_RETRIES`
<small class="added-in">added in `0.7.21`</small> <small class="added-in">added in `0.7.21`</small>