feat: add --no-default-groups flag (#10618)

## Summary

Closes #10592.

## Test Plan

Snapshot tests.

---------

Co-authored-by: Charlie Marsh <charlie.r.marsh@gmail.com>
This commit is contained in:
Mathieu Kniewallner 2025-01-22 00:03:17 +01:00 committed by GitHub
parent cee8770cb0
commit 1479f52be7
No known key found for this signature in database
GPG key ID: B5690EEEBB952194
5 changed files with 297 additions and 9 deletions

View file

@ -1,5 +1,7 @@
use std::borrow::Cow;
use either::Either;
use uv_normalize::{GroupName, DEV_DEPENDENCIES};
#[derive(Debug, Default, Clone, Copy, PartialEq, Eq)]
@ -57,7 +59,8 @@ pub struct DevGroupsSpecification {
#[derive(Debug, Clone)]
pub enum GroupsSpecification {
/// Include dependencies from the specified groups.
/// Include dependencies from the specified groups alongside the default groups (omitting
/// those default groups that are explicitly excluded).
///
/// If the `include` is `IncludeGroups::Some`, it is guaranteed to omit groups in the `exclude`
/// list (i.e., they have an empty intersection).
@ -65,6 +68,10 @@ pub enum GroupsSpecification {
include: IncludeGroups,
exclude: Vec<GroupName>,
},
/// Include dependencies from the specified groups, omitting any default groups.
///
/// If the list is empty, no group will be included.
Explicit { include: Vec<GroupName> },
/// Only include dependencies from the specified groups, exclude all other dependencies.
///
/// The `include` list is guaranteed to omit groups in the `exclude` list (i.e., they have an
@ -86,7 +93,7 @@ impl GroupsSpecification {
/// Returns `true` if the specification allows for production dependencies.
pub fn prod(&self) -> bool {
matches!(self, Self::Include { .. })
matches!(self, Self::Include { .. } | Self::Explicit { .. })
}
/// Returns `true` if the specification is limited to a select set of groups.
@ -118,6 +125,11 @@ impl GroupsSpecification {
[group] => Some(Cow::Owned(format!("--only-group {group}"))),
[..] => Some(Cow::Borrowed("--only-group")),
},
Self::Explicit { include } => match include.as_slice() {
[] => Some(Cow::Borrowed("--no-default-groups")),
[group] => Some(Cow::Owned(format!("--group {group}"))),
[..] => Some(Cow::Borrowed("--group")),
},
}
}
@ -125,9 +137,12 @@ impl GroupsSpecification {
pub fn names(&self) -> impl Iterator<Item = &GroupName> {
match self {
GroupsSpecification::Include { include, exclude } => {
include.names().chain(exclude.iter())
Either::Left(include.names().chain(exclude.iter()))
}
GroupsSpecification::Only { include, exclude } => include.iter().chain(exclude.iter()),
GroupsSpecification::Only { include, exclude } => {
Either::Left(include.iter().chain(exclude.iter()))
}
GroupsSpecification::Explicit { include } => Either::Right(include.iter()),
}
}
@ -139,6 +154,7 @@ impl GroupsSpecification {
include.contains(group) && !exclude.contains(group)
}
GroupsSpecification::Only { include, .. } => include.contains(group),
GroupsSpecification::Explicit { include } => include.contains(group),
}
}
}
@ -178,6 +194,7 @@ impl DevGroupsSpecification {
only_dev: bool,
mut group: Vec<GroupName>,
no_group: Vec<GroupName>,
no_default_groups: bool,
mut only_group: Vec<GroupName>,
all_groups: bool,
) -> Self {
@ -191,7 +208,12 @@ impl DevGroupsSpecification {
None
};
let groups = if all_groups {
let groups = if no_default_groups {
// Remove groups specified with `--no-group`.
group.retain(|group| !no_group.contains(group));
Some(GroupsSpecification::Explicit { include: group })
} else if all_groups {
Some(GroupsSpecification::Include {
include: IncludeGroups::All,
exclude: no_group,
@ -376,6 +398,12 @@ impl DevGroupsManifest {
};
}
// If `--no-default-groups` was provided, only include group if it's explicitly
// included with `--group <group>`.
if let Some(GroupsSpecification::Explicit { include }) = self.spec.groups() {
return include.contains(group);
}
// If `--no-group` was provided, exclude the group from the list of defaults.
if let Some(GroupsSpecification::Include {
include: _,