Skip to content

Commit 3f1d3f7

Browse files
committed
Include extras and dependency groups in derivation chains
1 parent 9cb9841 commit 3f1d3f7

4 files changed

Lines changed: 51 additions & 21 deletions

File tree

crates/uv-distribution-types/src/derivation.rs

Lines changed: 21 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
use uv_normalize::PackageName;
1+
use uv_normalize::{ExtraName, GroupName, PackageName};
22
use uv_pep440::Version;
33
use version_ranges::Ranges;
44

@@ -65,6 +65,10 @@ impl IntoIterator for DerivationChain {
6565
pub struct DerivationStep {
6666
/// The name of the package.
6767
pub name: PackageName,
68+
/// The enabled extra of the package, if any.
69+
pub extra: Option<ExtraName>,
70+
/// The enabled dependency group of the package, if any.
71+
pub group: Option<GroupName>,
6872
/// The version of the package.
6973
pub version: Version,
7074
/// The constraints applied to the subsequent package in the chain.
@@ -73,9 +77,17 @@ pub struct DerivationStep {
7377

7478
impl DerivationStep {
7579
/// Create a [`DerivationStep`] from a package name and version.
76-
pub fn new(name: PackageName, version: Version, range: Ranges<Version>) -> Self {
80+
pub fn new(
81+
name: PackageName,
82+
extra: Option<ExtraName>,
83+
group: Option<GroupName>,
84+
version: Version,
85+
range: Ranges<Version>,
86+
) -> Self {
7787
Self {
7888
name,
89+
extra,
90+
group,
7991
version,
8092
range,
8193
}
@@ -84,6 +96,12 @@ impl DerivationStep {
8496

8597
impl std::fmt::Display for DerivationStep {
8698
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
87-
write!(f, "{}=={}", self.name, self.version)
99+
if let Some(extra) = &self.extra {
100+
write!(f, "{}[{}]=={}", self.name, extra, self.version)
101+
} else if let Some(group) = &self.group {
102+
write!(f, "{}:{}=={}", self.name, group, self.version)
103+
} else {
104+
write!(f, "{}=={}", self.name, self.version)
105+
}
88106
}
89107
}

crates/uv-resolver/src/resolver/derivation.rs

Lines changed: 25 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -1,11 +1,12 @@
11
use std::collections::VecDeque;
22

3+
use petgraph::visit::EdgeRef;
34
use petgraph::Direction;
45
use pubgrub::{Kind, Range, SelectedDependencies, State};
56
use rustc_hash::FxHashSet;
67

78
use uv_distribution_types::{
8-
DerivationChain, DerivationStep, DistRef, Name, Node, Resolution, ResolvedDist,
9+
DerivationChain, DerivationStep, DistRef, Edge, Name, Node, Resolution, ResolvedDist,
910
};
1011
use uv_pep440::Version;
1112

@@ -40,11 +41,11 @@ impl DerivationChainBuilder {
4041

4142
// Perform a BFS to find the shortest path to the root.
4243
let mut queue = VecDeque::new();
43-
queue.push_back((target, Vec::new()));
44+
queue.push_back((target, None, None, Vec::new()));
4445

4546
// TODO(charlie): Consider respecting markers here.
4647
let mut seen = FxHashSet::default();
47-
while let Some((node, mut path)) = queue.pop_front() {
48+
while let Some((node, extra, group, mut path)) = queue.pop_front() {
4849
if !seen.insert(node) {
4950
continue;
5051
}
@@ -55,16 +56,25 @@ impl DerivationChainBuilder {
5556
return Some(DerivationChain::from_iter(path));
5657
}
5758
Node::Dist { dist, .. } => {
58-
path.push(DerivationStep::new(
59-
dist.name().clone(),
60-
dist.version().clone(),
61-
Range::empty(),
62-
));
63-
for neighbor in resolution
64-
.graph()
65-
.neighbors_directed(node, Direction::Incoming)
66-
{
67-
queue.push_back((neighbor, path.clone()));
59+
for edge in resolution.graph().edges_directed(node, Direction::Incoming) {
60+
let mut path = path.clone();
61+
path.push(DerivationStep::new(
62+
dist.name().clone(),
63+
extra.clone(),
64+
group.clone(),
65+
dist.version().clone(),
66+
Range::empty(),
67+
));
68+
let target = edge.source();
69+
let extra = match edge.weight() {
70+
Edge::Optional(extra, ..) => Some(extra.clone()),
71+
_ => None,
72+
};
73+
let group = match edge.weight() {
74+
Edge::Dev(group, ..) => Some(group.clone()),
75+
_ => None,
76+
};
77+
queue.push_back((target, extra, group, path));
6878
}
6979
}
7080
}
@@ -109,6 +119,8 @@ impl DerivationChainBuilder {
109119
// Add to the current path.
110120
path.push(DerivationStep::new(
111121
name.clone(),
122+
p1.extra().cloned(),
123+
p1.dev().cloned(),
112124
version.clone(),
113125
v2.clone(),
114126
));

crates/uv/tests/it/lock.rs

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -19940,7 +19940,7 @@ fn lock_derivation_chain_extra() -> Result<()> {
1994019940
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
1994119941
SyntaxError: Missing parentheses in call to 'print'. Did you mean print(...)?
1994219942

19943-
help: `wsgiref` was included because `project==0.1.0` depends on `wsgiref (>=0.1)`
19943+
help: `wsgiref` was included because `project[wsgi]==0.1.0` depends on `wsgiref (>=0.1)`
1994419944
"###);
1994519945

1994619946
Ok(())
@@ -20000,7 +20000,7 @@ fn lock_derivation_chain_group() -> Result<()> {
2000020000
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
2000120001
SyntaxError: Missing parentheses in call to 'print'. Did you mean print(...)?
2000220002

20003-
help: `wsgiref` was included because `project==0.1.0` depends on `wsgiref (*)`
20003+
help: `wsgiref` was included because `project:wsgi==0.1.0` depends on `wsgiref (*)`
2000420004
"###);
2000520005

2000620006
Ok(())

crates/uv/tests/it/sync.rs

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -792,7 +792,7 @@ fn sync_build_isolation_extra() -> Result<()> {
792792
File "<string>", line 8, in <module>
793793
ModuleNotFoundError: No module named 'hatchling'
794794
795-
help: `source-distribution` was included because `project==0.1.0` depends on `source-distribution`
795+
help: `source-distribution` was included because `project[compile]==0.1.0` depends on `source-distribution`
796796
"###);
797797

798798
// Running `uv sync` with `--all-extras` should also fail.
@@ -4398,7 +4398,7 @@ fn sync_derivation_chain_extra() -> Result<()> {
43984398
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
43994399
SyntaxError: Missing parentheses in call to 'print'. Did you mean print(...)?
44004400
4401-
help: `wsgiref` was included because `project==0.1.0` depends on `wsgiref`
4401+
help: `wsgiref` was included because `project[wsgi]==0.1.0` depends on `wsgiref`
44024402
"###);
44034403

44044404
Ok(())
@@ -4464,7 +4464,7 @@ fn sync_derivation_chain_group() -> Result<()> {
44644464
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
44654465
SyntaxError: Missing parentheses in call to 'print'. Did you mean print(...)?
44664466
4467-
help: `wsgiref` was included because `project==0.1.0` depends on `wsgiref`
4467+
help: `wsgiref` was included because `project:wsgi==0.1.0` depends on `wsgiref`
44684468
"###);
44694469

44704470
Ok(())

0 commit comments

Comments
 (0)