Add `--clear` to `uv build` to remove old build artifacts (#16371)

Add `uv build --clear` that behaves like `rm -r ./dist && uv build` to
clear artifacts from previous builds. This avoids accidentally
publishing the wrong artifacts and removes accumulated old builds.

See https://github.com/astral-sh/uv/issues/10293#issuecomment-3405904013
Fixes #10293
This commit is contained in:
konsti 2025-10-27 19:15:17 +01:00 committed by GitHub
parent fe5d944afa
commit 804f1ff808
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
6 changed files with 88 additions and 2 deletions

View File

@ -2635,6 +2635,10 @@ pub struct BuildArgs {
#[arg(long, conflicts_with = "list")]
pub force_pep517: bool,
/// Clear the output directory before the build, removing stale artifacts.
#[arg(long)]
pub clear: bool,
/// Constrain build dependencies using the given requirements files when building distributions.
///
/// Constraints files are `requirements.txt`-like files that only control the _version_ of a

View File

@ -109,6 +109,7 @@ pub(crate) async fn build_frontend(
list: bool,
build_logs: bool,
force_pep517: bool,
clear: bool,
build_constraints: Vec<RequirementsSource>,
hash_checking: Option<HashCheckingMode>,
python: Option<String>,
@ -134,6 +135,7 @@ pub(crate) async fn build_frontend(
list,
build_logs,
force_pep517,
clear,
&build_constraints,
hash_checking,
python.as_deref(),
@ -177,6 +179,7 @@ async fn build_impl(
list: bool,
build_logs: bool,
force_pep517: bool,
clear: bool,
build_constraints: &[RequirementsSource],
hash_checking: Option<HashCheckingMode>,
python_request: Option<&str>,
@ -342,6 +345,7 @@ async fn build_impl(
hash_checking,
build_logs,
force_pep517,
clear,
build_constraints,
build_isolation,
extra_build_dependencies,
@ -449,6 +453,7 @@ async fn build_package(
hash_checking: Option<HashCheckingMode>,
build_logs: bool,
force_pep517: bool,
clear: bool,
build_constraints: &[RequirementsSource],
build_isolation: &BuildIsolation,
extra_build_dependencies: &ExtraBuildDependencies,
@ -481,6 +486,11 @@ async fn build_package(
}
};
// Clear the output directory if requested
if clear && output_dir.exists() {
fs_err::remove_dir_all(&*output_dir)?;
}
// (1) Explicit request from user
let mut interpreter_request = python_request.map(PythonRequest::parse);

View File

@ -1073,6 +1073,7 @@ async fn run(mut cli: Cli) -> Result<ExitStatus> {
args.list,
args.build_logs,
args.force_pep517,
args.clear,
build_constraints,
args.hash_checking,
args.python,

View File

@ -2873,6 +2873,7 @@ pub(crate) struct BuildSettings {
pub(crate) list: bool,
pub(crate) build_logs: bool,
pub(crate) force_pep517: bool,
pub(crate) clear: bool,
pub(crate) build_constraints: Vec<PathBuf>,
pub(crate) hash_checking: Option<HashCheckingMode>,
pub(crate) python: Option<String>,
@ -2897,6 +2898,7 @@ impl BuildSettings {
wheel,
list,
force_pep517,
clear,
build_constraints,
require_hashes,
no_require_hashes,
@ -2923,11 +2925,12 @@ impl BuildSettings {
wheel,
list,
build_logs: flag(build_logs, no_build_logs, "build-logs").unwrap_or(true),
force_pep517,
clear,
build_constraints: build_constraints
.into_iter()
.filter_map(Maybe::into_option)
.collect(),
force_pep517,
hash_checking: HashCheckingMode::from_args(
flag(require_hashes, no_require_hashes, "require-hashes"),
flag(verify_hashes, no_verify_hashes, "verify-hashes"),

View File

@ -2146,3 +2146,70 @@ fn test_workspace_trailing_slash() {
Successfully built dist/child-0.1.0-py3-none-any.whl
");
}
/// Test `uv build --clear`.
#[test]
fn build_clear() -> Result<()> {
let context = TestContext::new("3.12");
let project = context.temp_dir.child("project");
context.init().arg(project.path()).assert().success();
// Regular build
uv_snapshot!(&context.filters(), context.build().arg("project").arg("--no-build-logs"), @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
"###);
project
.child("dist")
.child("project-0.1.0.tar.gz")
.assert(predicate::path::is_file());
project
.child("dist")
.child("project-0.1.0-py3-none-any.whl")
.assert(predicate::path::is_file());
// Add a marker file to verify `--clear` removes it
fs_err::write(project.child("dist").child("marker.txt"), "marker")?;
project
.child("dist")
.child("marker.txt")
.assert(predicate::path::is_file());
// Build with `--clear` to remove the marker file
uv_snapshot!(&context.filters(), context.build().arg("project").arg("--clear").arg("--no-build-logs"), @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
"###);
project
.child("dist")
.child("marker.txt")
.assert(predicate::path::missing());
project
.child("dist")
.child("project-0.1.0.tar.gz")
.assert(predicate::path::is_file());
project
.child("dist")
.child("project-0.1.0-py3-none-any.whl")
.assert(predicate::path::is_file());
Ok(())
}

View File

@ -5641,7 +5641,8 @@ uv build [OPTIONS] [SRC]
<p>May also be set with the <code>UV_BUILD_CONSTRAINT</code> environment variable.</p></dd><dt id="uv-build--cache-dir"><a href="#uv-build--cache-dir"><code>--cache-dir</code></a> <i>cache-dir</i></dt><dd><p>Path to the cache directory.</p>
<p>Defaults to <code>$XDG_CACHE_HOME/uv</code> or <code>$HOME/.cache/uv</code> on macOS and Linux, and <code>%LOCALAPPDATA%\uv\cache</code> on Windows.</p>
<p>To view the location of the cache directory, run <code>uv cache dir</code>.</p>
<p>May also be set with the <code>UV_CACHE_DIR</code> environment variable.</p></dd><dt id="uv-build--color"><a href="#uv-build--color"><code>--color</code></a> <i>color-choice</i></dt><dd><p>Control the use of color in output.</p>
<p>May also be set with the <code>UV_CACHE_DIR</code> environment variable.</p></dd><dt id="uv-build--clear"><a href="#uv-build--clear"><code>--clear</code></a></dt><dd><p>Clear the output directory before the build, removing stale artifacts</p>
</dd><dt id="uv-build--color"><a href="#uv-build--color"><code>--color</code></a> <i>color-choice</i></dt><dd><p>Control the use of color in output.</p>
<p>By default, uv will automatically detect support for colors when writing to a terminal.</p>
<p>Possible values:</p>
<ul>