mirror of
https://github.com/astral-sh/uv.git
synced 2025-08-03 18:38:21 +00:00
Omit transitive development dependencies from workspace lockfile (#5646)
## Summary Omit development dependencies from (e.g.) path dependencies. Closes https://github.com/astral-sh/uv/issues/5593.
This commit is contained in:
parent
cbb13e6584
commit
2574f5b3fd
5 changed files with 192 additions and 16 deletions
|
@ -181,7 +181,7 @@ impl Manifest {
|
|||
&'a self,
|
||||
markers: Option<&'a MarkerEnvironment>,
|
||||
mode: DependencyMode,
|
||||
) -> impl Iterator<Item = Cow<'a, PackageName>> + 'a {
|
||||
) -> impl Iterator<Item = Cow<'a, Requirement>> + 'a {
|
||||
match mode {
|
||||
// Include direct requirements, dependencies of editables, and transitive dependencies
|
||||
// of local packages.
|
||||
|
@ -200,26 +200,32 @@ impl Manifest {
|
|||
self.overrides
|
||||
.apply(&self.requirements)
|
||||
.filter(move |requirement| requirement.evaluate_markers(markers, &[])),
|
||||
)
|
||||
.map(|requirement| match requirement {
|
||||
Cow::Borrowed(requirement) => Cow::Borrowed(&requirement.name),
|
||||
Cow::Owned(requirement) => Cow::Owned(requirement.name),
|
||||
}),
|
||||
),
|
||||
),
|
||||
|
||||
// Restrict to the direct requirements.
|
||||
DependencyMode::Direct => Either::Right(
|
||||
self.overrides
|
||||
.apply(self.requirements.iter())
|
||||
.filter(move |requirement| requirement.evaluate_markers(markers, &[]))
|
||||
.map(|requirement| match requirement {
|
||||
Cow::Borrowed(requirement) => Cow::Borrowed(&requirement.name),
|
||||
Cow::Owned(requirement) => Cow::Owned(requirement.name),
|
||||
}),
|
||||
.filter(move |requirement| requirement.evaluate_markers(markers, &[])),
|
||||
),
|
||||
}
|
||||
}
|
||||
|
||||
/// Returns an iterator over the direct requirements, with overrides applied.
|
||||
///
|
||||
/// At time of writing, this is used for:
|
||||
/// - Determining which packages should have development dependencies included in the
|
||||
/// resolution (assuming the user enabled development dependencies).
|
||||
pub fn direct_requirements<'a>(
|
||||
&'a self,
|
||||
markers: Option<&'a MarkerEnvironment>,
|
||||
) -> impl Iterator<Item = Cow<'a, Requirement>> + 'a {
|
||||
self.overrides
|
||||
.apply(self.requirements.iter())
|
||||
.filter(move |requirement| requirement.evaluate_markers(markers, &[]))
|
||||
}
|
||||
|
||||
/// Apply the overrides and constraints to a set of requirements.
|
||||
///
|
||||
/// Constraints are always applied _on top_ of overrides, such that constraints are applied
|
||||
|
|
|
@ -56,7 +56,7 @@ impl ResolutionStrategy {
|
|||
ResolutionMode::LowestDirect => Self::LowestDirect(
|
||||
manifest
|
||||
.user_requirements(markers, dependencies)
|
||||
.map(|requirement| (*requirement).clone())
|
||||
.map(|requirement| requirement.name.clone())
|
||||
.collect(),
|
||||
),
|
||||
}
|
||||
|
|
35
crates/uv-resolver/src/resolver/groups.rs
Normal file
35
crates/uv-resolver/src/resolver/groups.rs
Normal file
|
@ -0,0 +1,35 @@
|
|||
use rustc_hash::FxHashMap;
|
||||
|
||||
use pep508_rs::MarkerEnvironment;
|
||||
use uv_normalize::{GroupName, PackageName};
|
||||
|
||||
use crate::Manifest;
|
||||
|
||||
/// A map of package names to their activated dependency groups.
|
||||
#[derive(Debug, Default, Clone)]
|
||||
pub(crate) struct Groups(FxHashMap<PackageName, Vec<GroupName>>);
|
||||
|
||||
impl Groups {
|
||||
/// Determine the set of enabled dependency groups in the [`Manifest`].
|
||||
pub(crate) fn from_manifest(manifest: &Manifest, markers: Option<&MarkerEnvironment>) -> Self {
|
||||
let mut groups = FxHashMap::default();
|
||||
|
||||
// Enable the groups for all direct dependencies. In practice, this tends to mean: when
|
||||
// development dependencies are enabled, enable them for all direct dependencies.
|
||||
for group in &manifest.dev {
|
||||
for requirement in manifest.direct_requirements(markers) {
|
||||
groups
|
||||
.entry(requirement.name.clone())
|
||||
.or_insert_with(Vec::new)
|
||||
.push(group.clone());
|
||||
}
|
||||
}
|
||||
|
||||
Self(groups)
|
||||
}
|
||||
|
||||
/// Retrieve the enabled dependency groups for a given package.
|
||||
pub(crate) fn get(&self, package: &PackageName) -> Option<&[GroupName]> {
|
||||
self.0.get(package).map(Vec::as_slice)
|
||||
}
|
||||
}
|
|
@ -60,6 +60,7 @@ pub(crate) use crate::resolver::availability::{
|
|||
IncompletePackage, ResolverVersion, UnavailablePackage, UnavailableReason, UnavailableVersion,
|
||||
};
|
||||
use crate::resolver::batch_prefetch::BatchPrefetcher;
|
||||
use crate::resolver::groups::Groups;
|
||||
pub(crate) use crate::resolver::index::FxOnceMap;
|
||||
pub use crate::resolver::index::InMemoryIndex;
|
||||
pub use crate::resolver::provider::{
|
||||
|
@ -74,6 +75,7 @@ use crate::{DependencyMode, Exclusions, FlatIndex, Options};
|
|||
mod availability;
|
||||
mod batch_prefetch;
|
||||
mod fork_map;
|
||||
mod groups;
|
||||
mod index;
|
||||
mod locals;
|
||||
mod provider;
|
||||
|
@ -93,7 +95,7 @@ struct ResolverState<InstalledPackages: InstalledPackagesProvider> {
|
|||
requirements: Vec<Requirement>,
|
||||
constraints: Constraints,
|
||||
overrides: Overrides,
|
||||
dev: Vec<GroupName>,
|
||||
groups: Groups,
|
||||
preferences: Preferences,
|
||||
git: GitResolver,
|
||||
exclusions: Exclusions,
|
||||
|
@ -224,11 +226,11 @@ impl<Provider: ResolverProvider, InstalledPackages: InstalledPackagesProvider>
|
|||
markers.marker_environment(),
|
||||
options.dependency_mode,
|
||||
),
|
||||
groups: Groups::from_manifest(&manifest, markers.marker_environment()),
|
||||
project: manifest.project,
|
||||
requirements: manifest.requirements,
|
||||
constraints: manifest.constraints,
|
||||
overrides: manifest.overrides,
|
||||
dev: manifest.dev,
|
||||
preferences: manifest.preferences,
|
||||
exclusions: manifest.exclusions,
|
||||
hasher: hasher.clone(),
|
||||
|
@ -1308,7 +1310,7 @@ impl<InstalledPackages: InstalledPackagesProvider> ResolverState<InstalledPackag
|
|||
// add a dependency from it to the same package with the group
|
||||
// enabled.
|
||||
if extra.is_none() && dev.is_none() {
|
||||
for group in &self.dev {
|
||||
for group in self.groups.get(name).into_iter().flatten() {
|
||||
if !metadata.dev_dependencies.contains_key(group) {
|
||||
continue;
|
||||
}
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue