mirror of https://github.com/astral-sh/uv
parent
38f1d1adb0
commit
88acedafb9
|
|
@ -97,6 +97,10 @@ pub enum Error {
|
||||||
UnmatchedRuntime(PackageName, PackageName),
|
UnmatchedRuntime(PackageName, PackageName),
|
||||||
#[error("Build requires for `{0}` missing for metadata declared in `pyproject.toml`")]
|
#[error("Build requires for `{0}` missing for metadata declared in `pyproject.toml`")]
|
||||||
MissingBuildRequirementForMetadata(PackageName),
|
MissingBuildRequirementForMetadata(PackageName),
|
||||||
|
#[error(
|
||||||
|
"Build requirement `{0}` was declared with `match-runtime = true`, but there is no runtime environment to match against"
|
||||||
|
)]
|
||||||
|
UnmatchedRuntimeMetadata(PackageName),
|
||||||
}
|
}
|
||||||
|
|
||||||
impl IsBuildBackendError for Error {
|
impl IsBuildBackendError for Error {
|
||||||
|
|
@ -114,6 +118,7 @@ impl IsBuildBackendError for Error {
|
||||||
| Self::NoSourceDistBuilds
|
| Self::NoSourceDistBuilds
|
||||||
| Self::CyclicBuildDependency(_)
|
| Self::CyclicBuildDependency(_)
|
||||||
| Self::UnmatchedRuntime(_, _)
|
| Self::UnmatchedRuntime(_, _)
|
||||||
|
| Self::UnmatchedRuntimeMetadata(_)
|
||||||
| Self::MissingBuildRequirementForMetadata(_) => false,
|
| Self::MissingBuildRequirementForMetadata(_) => false,
|
||||||
Self::CommandFailed(_, _)
|
Self::CommandFailed(_, _)
|
||||||
| Self::BuildBackend(_)
|
| Self::BuildBackend(_)
|
||||||
|
|
|
||||||
|
|
@ -404,6 +404,7 @@ impl SourceBuild {
|
||||||
};
|
};
|
||||||
|
|
||||||
let resolved_requirements = Self::get_resolved_requirements(
|
let resolved_requirements = Self::get_resolved_requirements(
|
||||||
|
build_kind,
|
||||||
build_context,
|
build_context,
|
||||||
source_build_context,
|
source_build_context,
|
||||||
&DEFAULT_BACKEND,
|
&DEFAULT_BACKEND,
|
||||||
|
|
@ -528,10 +529,25 @@ impl SourceBuild {
|
||||||
}
|
}
|
||||||
|
|
||||||
fn apply_build_metadata<'a>(
|
fn apply_build_metadata<'a>(
|
||||||
|
build_kind: BuildKind,
|
||||||
metadata: &BTreeMap<PackageName, BuildDependencyMetadata>,
|
metadata: &BTreeMap<PackageName, BuildDependencyMetadata>,
|
||||||
build_requires: impl Iterator<Item = &'a Requirement>,
|
build_requires: impl Iterator<Item = &'a Requirement>,
|
||||||
top_level_resolution: &Resolution,
|
build_context: &impl BuildContext,
|
||||||
) -> Result<Vec<Requirement>, Box<Error>> {
|
) -> Result<Vec<Requirement>, Box<Error>> {
|
||||||
|
let top_level_resolution = build_context.top_level_resolution();
|
||||||
|
if top_level_resolution.is_none() {
|
||||||
|
for (package, metadata) in metadata {
|
||||||
|
if let Some(true) = metadata.match_runtime {
|
||||||
|
if !matches!(build_kind, BuildKind::Sdist) {
|
||||||
|
return Err(Box::new(Error::UnmatchedRuntimeMetadata(package.clone())));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
// Nothing needs runtime matching, carry on
|
||||||
|
return Ok(Vec::new());
|
||||||
|
}
|
||||||
|
// SAFETY: check above guarantees that top_level_resolution is Some
|
||||||
|
let top_level_resolution = top_level_resolution.unwrap();
|
||||||
let dists = top_level_resolution.distributions();
|
let dists = top_level_resolution.distributions();
|
||||||
let dists_by_name = dists
|
let dists_by_name = dists
|
||||||
.filter_map(|dist| metadata.get(dist.name()).map(|_| (dist.name(), dist)))
|
.filter_map(|dist| metadata.get(dist.name()).map(|_| (dist.name(), dist)))
|
||||||
|
|
@ -578,6 +594,7 @@ impl SourceBuild {
|
||||||
}
|
}
|
||||||
|
|
||||||
async fn get_resolved_requirements(
|
async fn get_resolved_requirements(
|
||||||
|
build_kind: BuildKind,
|
||||||
build_context: &impl BuildContext,
|
build_context: &impl BuildContext,
|
||||||
source_build_context: SourceBuildContext,
|
source_build_context: SourceBuildContext,
|
||||||
default_backend: &Pep517Backend,
|
default_backend: &Pep517Backend,
|
||||||
|
|
@ -622,17 +639,16 @@ impl SourceBuild {
|
||||||
};
|
};
|
||||||
|
|
||||||
if let Some(build_dep_metadata) = build_dep_metadata {
|
if let Some(build_dep_metadata) = build_dep_metadata {
|
||||||
if let Some(resolution) = build_context.top_level_resolution() {
|
|
||||||
let mut reqs_with_metadata = Self::apply_build_metadata(
|
let mut reqs_with_metadata = Self::apply_build_metadata(
|
||||||
|
build_kind,
|
||||||
&build_dep_metadata.0,
|
&build_dep_metadata.0,
|
||||||
requirements.iter(),
|
requirements.iter(),
|
||||||
resolution,
|
build_context,
|
||||||
)
|
)
|
||||||
.map_err(|err| *err)?;
|
.map_err(|err| *err)?;
|
||||||
reqs_with_metadata.extend(requirements.into_owned().into_iter());
|
reqs_with_metadata.extend(requirements.into_owned().into_iter());
|
||||||
requirements = Cow::Owned(reqs_with_metadata);
|
requirements = Cow::Owned(reqs_with_metadata);
|
||||||
}
|
}
|
||||||
}
|
|
||||||
|
|
||||||
build_context
|
build_context
|
||||||
.resolve(&requirements, build_stack)
|
.resolve(&requirements, build_stack)
|
||||||
|
|
|
||||||
|
|
@ -2084,3 +2084,56 @@ fn venv_included_in_sdist() -> Result<()> {
|
||||||
|
|
||||||
Ok(())
|
Ok(())
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// Runtime matching causes building a wheel to fail
|
||||||
|
#[test]
|
||||||
|
fn runtime_matching() -> Result<()> {
|
||||||
|
let context = TestContext::new("3.12");
|
||||||
|
|
||||||
|
let project = context.temp_dir.child("project");
|
||||||
|
project
|
||||||
|
.child("src")
|
||||||
|
.child("project")
|
||||||
|
.child("__init__.py")
|
||||||
|
.touch()?;
|
||||||
|
project.child("README").touch()?;
|
||||||
|
let pyproject_toml = project.child("pyproject.toml");
|
||||||
|
pyproject_toml.write_str(indoc! {r#"
|
||||||
|
[project]
|
||||||
|
name = "project"
|
||||||
|
version = "0.1.0"
|
||||||
|
requires-python = ">=3.12"
|
||||||
|
|
||||||
|
[tool.uv.build-dependencies-metadata.hatchling]
|
||||||
|
match-runtime = true
|
||||||
|
|
||||||
|
[build-system]
|
||||||
|
requires = ["hatchling"]
|
||||||
|
build-backend = "hatchling.build"
|
||||||
|
"#})?;
|
||||||
|
|
||||||
|
uv_snapshot!(context.filters(), context.build().current_dir(&project), @r"
|
||||||
|
success: false
|
||||||
|
exit_code: 2
|
||||||
|
----- stdout -----
|
||||||
|
|
||||||
|
----- stderr -----
|
||||||
|
Building source distribution...
|
||||||
|
Building wheel from source distribution...
|
||||||
|
× Failed to build `[TEMP_DIR]/project`
|
||||||
|
╰─▶ Build requirement `hatchling` was declared with `match-runtime = true`, but there is no runtime environment to match against
|
||||||
|
");
|
||||||
|
|
||||||
|
// But building a sdist is fine
|
||||||
|
uv_snapshot!(context.filters(), context.build().arg("--sdist").current_dir(&project), @r"
|
||||||
|
success: true
|
||||||
|
exit_code: 0
|
||||||
|
----- stdout -----
|
||||||
|
|
||||||
|
----- stderr -----
|
||||||
|
Building source distribution...
|
||||||
|
Successfully built dist/project-0.1.0.tar.gz
|
||||||
|
");
|
||||||
|
|
||||||
|
Ok(())
|
||||||
|
}
|
||||||
|
|
|
||||||
|
|
@ -30,6 +30,26 @@ build-constraint-dependencies = ["setuptools==60.0.0"]
|
||||||
|
|
||||||
---
|
---
|
||||||
|
|
||||||
|
### [`build-dependencies-metadata`](#build-dependencies-metadata) {: #build-dependencies-metadata }
|
||||||
|
|
||||||
|
Metadata for build dependencies.
|
||||||
|
|
||||||
|
This allows specifying metadata for build dependencies, such as runtime matching.
|
||||||
|
|
||||||
|
**Default value**: `None`
|
||||||
|
|
||||||
|
**Type**: `dict`
|
||||||
|
|
||||||
|
**Example usage**:
|
||||||
|
|
||||||
|
```toml title="pyproject.toml"
|
||||||
|
[tool.uv]
|
||||||
|
[build-dependencies-metadata.package1]
|
||||||
|
match-runtime = true
|
||||||
|
```
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
### [`conflicts`](#conflicts) {: #conflicts }
|
### [`conflicts`](#conflicts) {: #conflicts }
|
||||||
|
|
||||||
Declare collections of extras or dependency groups that are conflicting
|
Declare collections of extras or dependency groups that are conflicting
|
||||||
|
|
|
||||||
|
|
@ -46,6 +46,17 @@
|
||||||
"type": "string"
|
"type": "string"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
"build-dependencies-metadata": {
|
||||||
|
"description": "Metadata for build dependencies.\n\nThis allows specifying metadata for build dependencies, such as runtime matching.",
|
||||||
|
"anyOf": [
|
||||||
|
{
|
||||||
|
"$ref": "#/definitions/BuildDependenciesMetadata"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"type": "null"
|
||||||
|
}
|
||||||
|
]
|
||||||
|
},
|
||||||
"cache-dir": {
|
"cache-dir": {
|
||||||
"description": "Path to the cache directory.\n\nDefaults to `$XDG_CACHE_HOME/uv` or `$HOME/.cache/uv` on Linux and macOS, and\n`%LOCALAPPDATA%\\uv\\cache` on Windows.",
|
"description": "Path to the cache directory.\n\nDefaults to `$XDG_CACHE_HOME/uv` or `$HOME/.cache/uv` on Linux and macOS, and\n`%LOCALAPPDATA%\\uv\\cache` on Windows.",
|
||||||
"type": [
|
"type": [
|
||||||
|
|
@ -759,6 +770,23 @@
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
"BuildDependenciesMetadata": {
|
||||||
|
"type": "object",
|
||||||
|
"additionalProperties": {
|
||||||
|
"$ref": "#/definitions/BuildDependencyMetadata"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"BuildDependencyMetadata": {
|
||||||
|
"type": "object",
|
||||||
|
"properties": {
|
||||||
|
"match_runtime": {
|
||||||
|
"type": [
|
||||||
|
"boolean",
|
||||||
|
"null"
|
||||||
|
]
|
||||||
|
}
|
||||||
|
}
|
||||||
|
},
|
||||||
"CacheKey": {
|
"CacheKey": {
|
||||||
"anyOf": [
|
"anyOf": [
|
||||||
{
|
{
|
||||||
|
|
|
||||||
Loading…
Reference in New Issue