Skip to content

Commit 5809faa

Browse files
committed
Reject match-runtime = true for dynamic packages
1 parent 7eb076a commit 5809faa

File tree

5 files changed

+61
-7
lines changed

5 files changed

+61
-7
lines changed

crates/uv-build-frontend/src/error.rs

Lines changed: 6 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -91,6 +91,10 @@ pub enum Error {
9191
NoSourceDistBuilds,
9292
#[error("Cyclic build dependency detected for `{0}`")]
9393
CyclicBuildDependency(PackageName),
94+
#[error(
95+
"Extra build requirement `{0}` was declared with `match-runtime = true`, but `{1}` does not declare static metadata, making runtime-matching impossible"
96+
)]
97+
UnmatchedRuntime(PackageName, PackageName),
9498
}
9599

96100
impl IsBuildBackendError for Error {
@@ -106,7 +110,8 @@ impl IsBuildBackendError for Error {
106110
| Self::Virtualenv(_)
107111
| Self::NoSourceDistBuild(_)
108112
| Self::NoSourceDistBuilds
109-
| Self::CyclicBuildDependency(_) => false,
113+
| Self::CyclicBuildDependency(_)
114+
| Self::UnmatchedRuntime(_, _) => false,
110115
Self::CommandFailed(_, _)
111116
| Self::BuildBackend(_)
112117
| Self::MissingHeader(_)

crates/uv-build-frontend/src/lib.rs

Lines changed: 20 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -34,7 +34,8 @@ use uv_configuration::Preview;
3434
use uv_configuration::{BuildKind, BuildOutput, SourceStrategy};
3535
use uv_distribution::BuildRequires;
3636
use uv_distribution_types::{
37-
ConfigSettings, ExtraBuildRequires, IndexLocations, Requirement, Resolution,
37+
ConfigSettings, ExtraBuildRequirement, ExtraBuildRequires, IndexLocations, Requirement,
38+
Resolution,
3839
};
3940
use uv_fs::LockedFile;
4041
use uv_fs::{PythonExt, Simplified};
@@ -326,13 +327,28 @@ impl SourceBuild {
326327
.or(fallback_package_version)
327328
.cloned();
328329

329-
let extra_build_dependencies: Vec<Requirement> = package_name
330+
let extra_build_dependencies = package_name
330331
.as_ref()
331332
.and_then(|name| extra_build_requires.get(name).cloned())
332333
.unwrap_or_default()
333334
.into_iter()
334-
.map(Requirement::from)
335-
.collect();
335+
.map(|requirement| {
336+
match requirement {
337+
ExtraBuildRequirement {
338+
requirement,
339+
match_runtime: true,
340+
} if requirement.source.is_empty() => {
341+
Err(Error::UnmatchedRuntime(
342+
requirement.name.clone(),
343+
// SAFETY: if `package_name` is `None`, the iterator is empty.
344+
package_name.clone().unwrap(),
345+
))
346+
}
347+
requirement => Ok(requirement),
348+
}
349+
})
350+
.map_ok(Requirement::from)
351+
.collect::<Result<Vec<_>, _>>()?;
336352

337353
// Create a virtual environment, or install into the shared environment if requested.
338354
let venv = if let Some(venv) = build_isolation.shared_environment(package_name.as_ref()) {

crates/uv-dispatch/src/lib.rs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -480,7 +480,7 @@ impl BuildContext for BuildDispatch<'_> {
480480
self.workspace_cache(),
481481
config_settings,
482482
self.build_isolation,
483-
self.extra_build_requires(),
483+
self.extra_build_requires,
484484
&build_stack,
485485
build_kind,
486486
environment_variables,

crates/uv-distribution-types/src/build_requires.rs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -95,7 +95,7 @@ impl ExtraBuildRequires {
9595
};
9696
Ok::<_, ExtraBuildRequiresError>(ExtraBuildRequirement {
9797
requirement,
98-
match_runtime: true,
98+
match_runtime: false,
9999
})
100100
}
101101
requirement => Ok(requirement),

crates/uv/tests/it/sync.rs

Lines changed: 33 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -13089,3 +13089,36 @@ fn sync_extra_build_variables() -> Result<()> {
1308913089

1309013090
Ok(())
1309113091
}
13092+
13093+
#[test]
13094+
fn reject_unmatched_runtime() -> Result<()> {
13095+
let context = TestContext::new("3.12").with_exclude_newer("2025-01-01T00:00Z");
13096+
13097+
let pyproject_toml = context.temp_dir.child("pyproject.toml");
13098+
pyproject_toml.write_str(
13099+
r#"
13100+
[project]
13101+
name = "foo"
13102+
version = "0.1.0"
13103+
requires-python = ">=3.12"
13104+
dependencies = ["source-distribution", "iniconfig"]
13105+
13106+
[tool.uv.extra-build-dependencies]
13107+
source-distribution = [{ requirement = "iniconfig", match-runtime = true }]
13108+
"#,
13109+
)?;
13110+
13111+
uv_snapshot!(context.filters(), context.lock(), @r"
13112+
success: false
13113+
exit_code: 1
13114+
----- stdout -----
13115+
13116+
----- stderr -----
13117+
warning: The `extra-build-dependencies` option is experimental and may change without warning. Pass `--preview-features extra-build-dependencies` to disable this warning.
13118+
× Failed to download and build `source-distribution==0.0.3`
13119+
╰─▶ Extra build requirement `iniconfig` was declared with `match-runtime = true`, but `source-distribution` does not declare static metadata, making runtime-matching impossible
13120+
help: `source-distribution` (v0.0.3) was included because `foo` (v0.1.0) depends on `source-distribution`
13121+
");
13122+
13123+
Ok(())
13124+
}

0 commit comments

Comments
 (0)