use std::borrow::Cow;
use uv_distribution_types::{Requirement, ResolutionRecorder};
use uv_normalize::PackageName;
use uv_pep440::Version;
use crate::{Excludes, Overrides};
#[derive(Debug, Default, Clone)]
pub struct DependencyModifiers {
overrides: Overrides,
excludes: Excludes,
}
#[derive(Debug, Clone, Copy)]
pub enum DependencyModifierScope<'a> {
Global,
Package(&'a PackageName, &'a Version),
DependencyGroup(&'a PackageName, &'a Version),
}
impl DependencyModifiers {
#[must_use]
pub fn with_recorder(mut self, recorder: Option<ResolutionRecorder>) -> Self {
self.overrides = self.overrides.with_recorder(recorder.clone());
self.excludes = self.excludes.with_recorder(recorder);
self
}
pub fn new(overrides: Overrides, excludes: Excludes) -> Self {
Self {
overrides,
excludes,
}
}
pub fn has_scoped_package(&self, package: &PackageName) -> bool {
self.overrides.has_scoped_package(package) || self.excludes.has_scoped_package(package)
}
pub fn global_overrides(&self) -> impl Iterator<Item = &Requirement> {
self.overrides
.global_requirements()
.filter(|requirement| !self.excludes.contains(&requirement.name))
}
pub fn scoped_overrides(&self) -> impl Iterator<Item = &Requirement> {
self.overrides
.scoped_requirements()
.filter(|(package, version, requirement)| {
!self.excludes.contains_for_scope(
&self.overrides,
package,
*version,
&requirement.name,
)
})
.map(|(_, _, requirement)| requirement)
}
pub fn scoped_overrides_for(
&self,
package: &PackageName,
version: &Version,
) -> impl Iterator<Item = &Requirement> {
self.overrides
.scoped_requirements_for(package, version)
.filter(|requirement| {
!self
.excludes
.contains_for(package, version, &requirement.name)
})
}
pub fn is_excluded(&self, dependency: &PackageName) -> bool {
self.excludes.contains(dependency)
}
pub fn is_excluded_for(
&self,
package: &PackageName,
version: &Version,
dependency: &PackageName,
) -> bool {
self.excludes.contains_for(package, version, dependency)
}
pub fn apply<'a, 'scope, I>(
&'a self,
scope: DependencyModifierScope<'scope>,
requirements: I,
) -> impl Iterator<Item = Cow<'a, Requirement>> + use<'a, 'scope, I>
where
I: IntoIterator<Item = &'a Requirement>,
{
let (overrides, excludes) = match scope {
DependencyModifierScope::Global => (None, None),
DependencyModifierScope::Package(package, version) => {
(Some((package, version)), Some((package, version)))
}
DependencyModifierScope::DependencyGroup(package, version) => {
(None, Some((package, version)))
}
};
self.overrides
.apply_for_package(overrides, requirements)
.filter(move |requirement| {
!self
.excludes
.contains_for_package(excludes, &requirement.name)
})
}
}