uv/crates/uv-configuration/src/overrides.rs
konsti 081f20c53e
Add support for tool.uv into distribution building (#3904)
With the change, we remove the special casing of workspace dependencies
and resolve `tool.uv` for all git and directory distributions. This
gives us support for non-editable workspace dependencies and path
dependencies in other workspaces. It removes a lot of special casing
around workspaces. These changes are the groundwork for supporting
`tool.uv` with dynamic metadata.

The basis for this change is moving `Requirement` from
`distribution-types` to `pypi-types` and the lowering logic from
`uv-requirements` to `uv-distribution`. This changes should be split out
in separate PRs.

I've included an example workspace `albatross-root-workspace2` where
`bird-feeder` depends on `a` from another workspace `ab`. There's a
bunch of failing tests and regressed error messages that still need
fixing. It does fix the audited package count for the workspace tests.
2024-05-31 02:42:03 +00:00

50 lines
1.7 KiB
Rust

use std::hash::BuildHasherDefault;
use either::Either;
use pypi_types::Requirement;
use rustc_hash::FxHashMap;
use uv_normalize::PackageName;
/// A set of overrides for a set of requirements.
#[derive(Debug, Default, Clone)]
pub struct Overrides(FxHashMap<PackageName, Vec<Requirement>>);
impl Overrides {
/// Create a new set of overrides from a set of requirements.
pub fn from_requirements(requirements: Vec<Requirement>) -> Self {
let mut overrides: FxHashMap<PackageName, Vec<Requirement>> =
FxHashMap::with_capacity_and_hasher(requirements.len(), BuildHasherDefault::default());
for requirement in requirements {
overrides
.entry(requirement.name.clone())
.or_default()
.push(requirement);
}
Self(overrides)
}
/// Return an iterator over all [`Requirement`]s in the override set.
pub fn requirements(&self) -> impl Iterator<Item = &Requirement> {
self.0.values().flat_map(|requirements| requirements.iter())
}
/// Get the overrides for a package.
pub fn get(&self, name: &PackageName) -> Option<&Vec<Requirement>> {
self.0.get(name)
}
/// Apply the overrides to a set of requirements.
pub fn apply<'a>(
&'a self,
requirements: impl IntoIterator<Item = &'a Requirement>,
) -> impl Iterator<Item = &Requirement> {
requirements.into_iter().flat_map(|requirement| {
if let Some(overrides) = self.get(&requirement.name) {
Either::Left(overrides.iter())
} else {
Either::Right(std::iter::once(requirement))
}
})
}
}