Enable extra build dependencies to 'match runtime' versions (#15036)
## Summary This is an alternative to https://github.com/astral-sh/uv/pull/14944 that functions a little differently. Rather than adding separate strategies, you can instead say: ```toml [tool.uv.extra-build-dependencies] child = [{ requirement = "anyio", match-runtime = true }] ``` Which will then enforce that `anyio` uses the same version as in the lockfile.
This commit is contained in:
@@ -1,15 +1,24 @@
|
||||
use std::collections::BTreeMap;
|
||||
|
||||
use uv_cache_key::{CacheKey, CacheKeyHasher};
|
||||
use uv_normalize::PackageName;
|
||||
|
||||
use crate::Requirement;
|
||||
use crate::{Name, Requirement, RequirementSource, Resolution};
|
||||
|
||||
#[derive(Debug, thiserror::Error)]
|
||||
pub enum ExtraBuildRequiresError {
|
||||
#[error(
|
||||
"`{0}` was declared as an extra build dependency with `match-runtime = true`, but was not found in the resolution"
|
||||
)]
|
||||
NotFound(PackageName),
|
||||
}
|
||||
|
||||
/// Lowered extra build dependencies with source resolution applied.
|
||||
#[derive(Debug, Clone, Default)]
|
||||
pub struct ExtraBuildRequires(BTreeMap<PackageName, Vec<Requirement>>);
|
||||
pub struct ExtraBuildRequires(BTreeMap<PackageName, Vec<ExtraBuildRequirement>>);
|
||||
|
||||
impl std::ops::Deref for ExtraBuildRequires {
|
||||
type Target = BTreeMap<PackageName, Vec<Requirement>>;
|
||||
type Target = BTreeMap<PackageName, Vec<ExtraBuildRequirement>>;
|
||||
|
||||
fn deref(&self) -> &Self::Target {
|
||||
&self.0
|
||||
@@ -23,16 +32,78 @@ impl std::ops::DerefMut for ExtraBuildRequires {
|
||||
}
|
||||
|
||||
impl IntoIterator for ExtraBuildRequires {
|
||||
type Item = (PackageName, Vec<Requirement>);
|
||||
type IntoIter = std::collections::btree_map::IntoIter<PackageName, Vec<Requirement>>;
|
||||
type Item = (PackageName, Vec<ExtraBuildRequirement>);
|
||||
type IntoIter = std::collections::btree_map::IntoIter<PackageName, Vec<ExtraBuildRequirement>>;
|
||||
|
||||
fn into_iter(self) -> Self::IntoIter {
|
||||
self.0.into_iter()
|
||||
}
|
||||
}
|
||||
|
||||
impl FromIterator<(PackageName, Vec<Requirement>)> for ExtraBuildRequires {
|
||||
fn from_iter<T: IntoIterator<Item = (PackageName, Vec<Requirement>)>>(iter: T) -> Self {
|
||||
impl FromIterator<(PackageName, Vec<ExtraBuildRequirement>)> for ExtraBuildRequires {
|
||||
fn from_iter<T: IntoIterator<Item = (PackageName, Vec<ExtraBuildRequirement>)>>(
|
||||
iter: T,
|
||||
) -> Self {
|
||||
Self(iter.into_iter().collect())
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Debug, Clone, PartialEq, Eq)]
|
||||
pub struct ExtraBuildRequirement {
|
||||
/// The underlying [`Requirement`] for the build requirement.
|
||||
pub requirement: Requirement,
|
||||
/// Whether this build requirement should match the runtime environment.
|
||||
pub match_runtime: bool,
|
||||
}
|
||||
|
||||
impl From<ExtraBuildRequirement> for Requirement {
|
||||
fn from(value: ExtraBuildRequirement) -> Self {
|
||||
value.requirement
|
||||
}
|
||||
}
|
||||
|
||||
impl CacheKey for ExtraBuildRequirement {
|
||||
fn cache_key(&self, state: &mut CacheKeyHasher) {
|
||||
self.requirement.cache_key(state);
|
||||
self.match_runtime.cache_key(state);
|
||||
}
|
||||
}
|
||||
|
||||
impl ExtraBuildRequires {
|
||||
/// Apply runtime constraints from a resolution to the extra build requirements.
|
||||
pub fn match_runtime(
|
||||
self,
|
||||
resolution: &Resolution,
|
||||
) -> Result<ExtraBuildRequires, ExtraBuildRequiresError> {
|
||||
self.into_iter()
|
||||
.map(|(name, requirements)| {
|
||||
let requirements = requirements
|
||||
.into_iter()
|
||||
.map(|requirement| match requirement {
|
||||
ExtraBuildRequirement {
|
||||
requirement,
|
||||
match_runtime: true,
|
||||
} => {
|
||||
let dist = resolution
|
||||
.distributions()
|
||||
.find(|dist| dist.name() == &requirement.name)
|
||||
.ok_or_else(|| {
|
||||
ExtraBuildRequiresError::NotFound(requirement.name.clone())
|
||||
})?;
|
||||
let requirement = Requirement {
|
||||
source: RequirementSource::from(dist),
|
||||
..requirement
|
||||
};
|
||||
Ok::<_, ExtraBuildRequiresError>(ExtraBuildRequirement {
|
||||
requirement,
|
||||
match_runtime: true,
|
||||
})
|
||||
}
|
||||
requirement => Ok(requirement),
|
||||
})
|
||||
.collect::<Result<Vec<_>, _>>()?;
|
||||
Ok::<_, ExtraBuildRequiresError>((name, requirements))
|
||||
})
|
||||
.collect::<Result<ExtraBuildRequires, _>>()
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user