Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions crates/uv-build-frontend/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -328,6 +328,7 @@ impl SourceBuild {
.and_then(|name| extra_build_requires.get(name).cloned())
.unwrap_or_default()
.into_iter()
.map(Requirement::from)
.collect();

// Create a virtual environment, or install into the shared environment if requested.
Expand Down
85 changes: 78 additions & 7 deletions crates/uv-distribution-types/src/build_requires.rs
Original file line number Diff line number Diff line change
@@ -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
Expand All @@ -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, _>>()
}
}
8 changes: 4 additions & 4 deletions crates/uv-distribution/src/index/built_wheel_index.rs
Original file line number Diff line number Diff line change
Expand Up @@ -5,8 +5,8 @@ use uv_cache_info::CacheInfo;
use uv_cache_key::cache_digest;
use uv_configuration::{ConfigSettings, PackageConfigSettings};
use uv_distribution_types::{
DirectUrlSourceDist, DirectorySourceDist, ExtraBuildRequires, GitSourceDist, Hashed,
PathSourceDist, Requirement,
DirectUrlSourceDist, DirectorySourceDist, ExtraBuildRequirement, ExtraBuildRequires,
GitSourceDist, Hashed, PathSourceDist,
};
use uv_normalize::PackageName;
use uv_platform_tags::Tags;
Expand Down Expand Up @@ -267,8 +267,8 @@ impl<'a> BuiltWheelIndex<'a> {
}
}

/// Determine the extra build dependencies for the given package name.
fn extra_build_requires_for(&self, name: &PackageName) -> &[Requirement] {
/// Determine the extra build requirements for the given package name.
fn extra_build_requires_for(&self, name: &PackageName) -> &[ExtraBuildRequirement] {
self.extra_build_requires
.get(name)
.map(Vec::as_slice)
Expand Down
95 changes: 54 additions & 41 deletions crates/uv-distribution/src/metadata/build_requires.rs
Original file line number Diff line number Diff line change
Expand Up @@ -2,9 +2,11 @@ use std::collections::BTreeMap;
use std::path::Path;

use uv_configuration::SourceStrategy;
use uv_distribution_types::{ExtraBuildRequires, IndexLocations, Requirement};
use uv_distribution_types::{
ExtraBuildRequirement, ExtraBuildRequires, IndexLocations, Requirement,
};
use uv_normalize::PackageName;
use uv_workspace::pyproject::{ExtraBuildDependencies, ToolUvSources};
use uv_workspace::pyproject::{ExtraBuildDependencies, ExtraBuildDependency, ToolUvSources};
use uv_workspace::{
DiscoveryOptions, MemberDiscovery, ProjectWorkspace, Workspace, WorkspaceCache,
};
Expand Down Expand Up @@ -248,50 +250,48 @@ impl LoweredExtraBuildDependencies {
// Lower each package's extra build dependencies
let mut build_requires = ExtraBuildRequires::default();
for (package_name, requirements) in extra_build_dependencies {
let lowered: Vec<Requirement> = requirements
let lowered: Vec<ExtraBuildRequirement> = requirements
.into_iter()
.flat_map(|requirement| {
let requirement_name = requirement.name.clone();
let extra = requirement.marker.top_level_extra_name();
let group = None;
LoweredRequirement::from_requirement(
requirement,
None,
workspace.install_path(),
project_sources,
project_indexes,
extra.as_deref(),
group,
index_locations,
workspace,
None,
)
.map(
move |requirement| match requirement {
Ok(requirement) => Ok(requirement.into_inner()),
Err(err) => Err(MetadataError::LoweringError(
requirement_name.clone(),
Box::new(err),
)),
},
)
})
.flat_map(
|ExtraBuildDependency {
requirement,
match_runtime,
}| {
let requirement_name = requirement.name.clone();
let extra = requirement.marker.top_level_extra_name();
let group = None;
LoweredRequirement::from_requirement(
requirement,
None,
workspace.install_path(),
project_sources,
project_indexes,
extra.as_deref(),
group,
index_locations,
workspace,
None,
)
.map(move |requirement| {
match requirement {
Ok(requirement) => Ok(ExtraBuildRequirement {
requirement: requirement.into_inner(),
match_runtime,
}),
Err(err) => Err(MetadataError::LoweringError(
requirement_name.clone(),
Box::new(err),
)),
}
})
},
)
.collect::<Result<Vec<_>, _>>()?;
build_requires.insert(package_name, lowered);
}
Ok(Self(build_requires))
}
SourceStrategy::Disabled => Ok(Self(
extra_build_dependencies
.into_iter()
.map(|(name, requirements)| {
(
name,
requirements.into_iter().map(Requirement::from).collect(),
)
})
.collect(),
)),
SourceStrategy::Disabled => Ok(Self::from_non_lowered(extra_build_dependencies)),
}
}

Expand All @@ -308,7 +308,20 @@ impl LoweredExtraBuildDependencies {
.map(|(name, requirements)| {
(
name,
requirements.into_iter().map(Requirement::from).collect(),
requirements
.into_iter()
.map(
|ExtraBuildDependency {
requirement,
match_runtime,
}| {
ExtraBuildRequirement {
requirement: requirement.into(),
match_runtime,
}
},
)
.collect::<Vec<_>>(),
)
})
.collect(),
Expand Down
6 changes: 3 additions & 3 deletions crates/uv-distribution/src/source/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -32,8 +32,8 @@ use uv_client::{
use uv_configuration::{BuildKind, BuildOutput, ConfigSettings, SourceStrategy};
use uv_distribution_filename::{SourceDistExtension, WheelFilename};
use uv_distribution_types::{
BuildableSource, DirectorySourceUrl, GitSourceUrl, HashPolicy, Hashed, IndexUrl, PathSourceUrl,
Requirement, SourceDist, SourceUrl,
BuildableSource, DirectorySourceUrl, ExtraBuildRequirement, GitSourceUrl, HashPolicy, Hashed,
IndexUrl, PathSourceUrl, SourceDist, SourceUrl,
};
use uv_extract::hash::Hasher;
use uv_fs::{rename_with_retry, write_atomic};
Expand Down Expand Up @@ -405,7 +405,7 @@ impl<'a, T: BuildContext> SourceDistributionBuilder<'a, T> {
}

/// Determine the extra build dependencies for the given package name.
fn extra_build_dependencies_for(&self, name: Option<&PackageName>) -> &[Requirement] {
fn extra_build_dependencies_for(&self, name: Option<&PackageName>) -> &[ExtraBuildRequirement] {
name.and_then(|name| {
self.build_context
.extra_build_requires()
Expand Down
5 changes: 2 additions & 3 deletions crates/uv-scripts/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -16,7 +16,7 @@ use uv_pypi_types::VerbatimParsedUrl;
use uv_redacted::DisplaySafeUrl;
use uv_settings::{GlobalOptions, ResolverInstallerOptions};
use uv_warnings::warn_user;
use uv_workspace::pyproject::Sources;
use uv_workspace::pyproject::{ExtraBuildDependency, Sources};

static FINDER: LazyLock<Finder> = LazyLock::new(|| Finder::new(b"# /// script"));

Expand Down Expand Up @@ -428,8 +428,7 @@ pub struct ToolUv {
pub override_dependencies: Option<Vec<uv_pep508::Requirement<VerbatimParsedUrl>>>,
pub constraint_dependencies: Option<Vec<uv_pep508::Requirement<VerbatimParsedUrl>>>,
pub build_constraint_dependencies: Option<Vec<uv_pep508::Requirement<VerbatimParsedUrl>>>,
pub extra_build_dependencies:
Option<BTreeMap<PackageName, Vec<uv_pep508::Requirement<VerbatimParsedUrl>>>>,
pub extra_build_dependencies: Option<BTreeMap<PackageName, Vec<ExtraBuildDependency>>>,
pub sources: Option<BTreeMap<PackageName, Sources>>,
}

Expand Down
Loading
Loading