Skip to content

Commit b15ad5b

Browse files
committed
Add conflict to map
1 parent 3badaec commit b15ad5b

20 files changed

Lines changed: 1017 additions & 415 deletions

File tree

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

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -216,6 +216,7 @@ impl From<&ResolvedDist> for RequirementSource {
216216
uv_pep440::VersionSpecifier::equals_version(version.clone()),
217217
),
218218
index: Some(wheels.best_wheel().index.url().clone()),
219+
conflict: None,
219220
},
220221
Dist::Built(BuiltDist::DirectUrl(wheel)) => {
221222
let mut location = wheel.url.to_url();
@@ -237,6 +238,7 @@ impl From<&ResolvedDist> for RequirementSource {
237238
uv_pep440::VersionSpecifier::equals_version(sdist.version.clone()),
238239
),
239240
index: Some(sdist.index.url().clone()),
241+
conflict: None,
240242
},
241243
Dist::Source(SourceDist::DirectUrl(sdist)) => {
242244
let mut location = sdist.url.to_url();
@@ -272,6 +274,7 @@ impl From<&ResolvedDist> for RequirementSource {
272274
uv_pep440::VersionSpecifier::equals_version(dist.version().clone()),
273275
),
274276
index: None,
277+
conflict: None,
275278
},
276279
}
277280
}

crates/uv-distribution/src/metadata/lowering.rs

Lines changed: 22 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -13,7 +13,9 @@ use uv_git::GitReference;
1313
use uv_normalize::PackageName;
1414
use uv_pep440::VersionSpecifiers;
1515
use uv_pep508::{MarkerTree, VerbatimUrl, VersionOrUrl};
16-
use uv_pypi_types::{ParsedUrlError, Requirement, RequirementSource, VerbatimParsedUrl};
16+
use uv_pypi_types::{
17+
ConflictItem, ParsedUrlError, Requirement, RequirementSource, VerbatimParsedUrl,
18+
};
1719
use uv_warnings::warn_user_once;
1820
use uv_workspace::pyproject::{PyProjectToml, Source, Sources};
1921
use uv_workspace::Workspace;
@@ -180,7 +182,7 @@ impl LoweredRequirement {
180182
Source::Registry {
181183
index,
182184
marker,
183-
extra: _,
185+
extra,
184186
} => {
185187
// Identify the named index from either the project indexes or the workspace indexes,
186188
// in that order.
@@ -199,8 +201,14 @@ impl LoweredRequirement {
199201
index,
200202
));
201203
};
202-
let source =
203-
registry_source(&requirement, index.into_url(), lower_bound)?;
204+
let conflict = extra
205+
.map(|extra| ConflictItem::from((project_name.clone(), extra)));
206+
let source = registry_source(
207+
&requirement,
208+
index.into_url(),
209+
conflict,
210+
lower_bound,
211+
)?;
204212
(source, marker)
205213
}
206214
Source::Workspace {
@@ -423,8 +431,13 @@ impl LoweredRequirement {
423431
index,
424432
));
425433
};
426-
let source =
427-
registry_source(&requirement, index.into_url(), lower_bound)?;
434+
let conflict = None;
435+
let source = registry_source(
436+
&requirement,
437+
index.into_url(),
438+
conflict,
439+
lower_bound,
440+
)?;
428441
(source, marker)
429442
}
430443
Source::Workspace { .. } => {
@@ -557,6 +570,7 @@ fn url_source(url: Url, subdirectory: Option<PathBuf>) -> Result<RequirementSour
557570
fn registry_source(
558571
requirement: &uv_pep508::Requirement<VerbatimParsedUrl>,
559572
index: Url,
573+
conflict: Option<ConflictItem>,
560574
bounds: LowerBound,
561575
) -> Result<RequirementSource, LoweringError> {
562576
match &requirement.version_or_url {
@@ -570,11 +584,13 @@ fn registry_source(
570584
Ok(RequirementSource::Registry {
571585
specifier: VersionSpecifiers::empty(),
572586
index: Some(index),
587+
conflict,
573588
})
574589
}
575590
Some(VersionOrUrl::VersionSpecifier(version)) => Ok(RequirementSource::Registry {
576591
specifier: version.clone(),
577592
index: Some(index),
593+
conflict,
578594
}),
579595
Some(VersionOrUrl::Url(_)) => Err(LoweringError::ConflictingUrls),
580596
}

crates/uv-distribution/src/metadata/mod.rs

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -90,6 +90,9 @@ impl Metadata {
9090
bounds,
9191
)
9292
.await?;
93+
//
94+
// println!("name: {:?}", name);
95+
// println!("requires_dist: {:#?}", requires_dist);
9396

9497
// Combine with the remaining metadata.
9598
Ok(Self {

crates/uv-pep508/src/marker/tree.rs

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -435,7 +435,7 @@ impl MarkerValueExtra {
435435
}
436436

437437
/// Convert the [`MarkerValueExtra`] to an [`ExtraName`], if possible.
438-
fn to_extra(self) -> Option<ExtraName> {
438+
fn into_extra(self) -> Option<ExtraName> {
439439
match self {
440440
Self::Extra(extra) => Some(extra),
441441
Self::Arbitrary(_) => None,
@@ -1130,7 +1130,7 @@ impl MarkerTree {
11301130
let extra_expression = self.top_level_extra()?;
11311131

11321132
match extra_expression {
1133-
MarkerExpression::Extra { name, .. } => name.to_extra(),
1133+
MarkerExpression::Extra { name, .. } => name.into_extra(),
11341134
_ => None,
11351135
}
11361136
}

crates/uv-pypi-types/src/requirement.rs

Lines changed: 28 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -16,8 +16,8 @@ use uv_pep508::{
1616
};
1717

1818
use crate::{
19-
Hashes, ParsedArchiveUrl, ParsedDirectoryUrl, ParsedGitUrl, ParsedPathUrl, ParsedUrl,
20-
ParsedUrlError, VerbatimParsedUrl,
19+
ConflictItem, Hashes, ParsedArchiveUrl, ParsedDirectoryUrl, ParsedGitUrl, ParsedPathUrl,
20+
ParsedUrl, ParsedUrlError, VerbatimParsedUrl,
2121
};
2222

2323
#[derive(Debug, Error)]
@@ -192,11 +192,13 @@ impl From<uv_pep508::Requirement<VerbatimParsedUrl>> for Requirement {
192192
None => RequirementSource::Registry {
193193
specifier: VersionSpecifiers::empty(),
194194
index: None,
195+
conflict: None,
195196
},
196197
// The most popular case: just a name, a version range and maybe extras.
197198
Some(VersionOrUrl::VersionSpecifier(specifier)) => RequirementSource::Registry {
198199
specifier,
199200
index: None,
201+
conflict: None,
200202
},
201203
Some(VersionOrUrl::Url(url)) => {
202204
RequirementSource::from_parsed_url(url.parsed_url, url.verbatim)
@@ -229,7 +231,9 @@ impl Display for Requirement {
229231
)?;
230232
}
231233
match &self.source {
232-
RequirementSource::Registry { specifier, index } => {
234+
RequirementSource::Registry {
235+
specifier, index, ..
236+
} => {
233237
write!(f, "{specifier}")?;
234238
if let Some(index) = index {
235239
write!(f, " (index: {index})")?;
@@ -283,6 +287,8 @@ pub enum RequirementSource {
283287
specifier: VersionSpecifiers,
284288
/// Choose a version from the index at the given URL.
285289
index: Option<Url>,
290+
/// The conflict item associated with the source, if any.
291+
conflict: Option<ConflictItem>,
286292
},
287293
// TODO(konsti): Track and verify version specifier from `project.dependencies` matches the
288294
// version in remote location.
@@ -513,7 +519,9 @@ impl Display for RequirementSource {
513519
/// rather than for inclusion in a `requirements.txt` file.
514520
fn fmt(&self, f: &mut Formatter<'_>) -> std::fmt::Result {
515521
match self {
516-
Self::Registry { specifier, index } => {
522+
Self::Registry {
523+
specifier, index, ..
524+
} => {
517525
write!(f, "{specifier}")?;
518526
if let Some(index) = index {
519527
write!(f, " (index: {index})")?;
@@ -571,6 +579,7 @@ enum RequirementSourceWire {
571579
#[serde(skip_serializing_if = "VersionSpecifiers::is_empty", default)]
572580
specifier: VersionSpecifiers,
573581
index: Option<Url>,
582+
conflict: Option<ConflictItem>,
574583
},
575584
}
576585

@@ -580,11 +589,16 @@ impl From<RequirementSource> for RequirementSourceWire {
580589
RequirementSource::Registry {
581590
specifier,
582591
mut index,
592+
conflict,
583593
} => {
584594
if let Some(index) = index.as_mut() {
585595
redact_credentials(index);
586596
}
587-
Self::Registry { specifier, index }
597+
Self::Registry {
598+
specifier,
599+
index,
600+
conflict,
601+
}
588602
}
589603
RequirementSource::Url {
590604
subdirectory,
@@ -686,9 +700,15 @@ impl TryFrom<RequirementSourceWire> for RequirementSource {
686700

687701
fn try_from(wire: RequirementSourceWire) -> Result<RequirementSource, RequirementError> {
688702
match wire {
689-
RequirementSourceWire::Registry { specifier, index } => {
690-
Ok(Self::Registry { specifier, index })
691-
}
703+
RequirementSourceWire::Registry {
704+
specifier,
705+
index,
706+
conflict,
707+
} => Ok(Self::Registry {
708+
specifier,
709+
index,
710+
conflict,
711+
}),
692712
RequirementSourceWire::Git { git } => {
693713
let mut repository = Url::parse(&git)?;
694714

crates/uv-pypi-types/src/requirement/tests.rs

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -13,6 +13,7 @@ fn roundtrip() {
1313
source: RequirementSource::Registry {
1414
specifier: ">1,<2".parse().unwrap(),
1515
index: None,
16+
conflict: None,
1617
},
1718
origin: None,
1819
};

crates/uv-resolver/src/lock/mod.rs

Lines changed: 6 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -3757,6 +3757,7 @@ fn normalize_requirement(
37573757
RequirementSource::Registry {
37583758
specifier,
37593759
mut index,
3760+
conflict,
37603761
} => {
37613762
if let Some(index) = index.as_mut() {
37623763
redact_credentials(index);
@@ -3765,7 +3766,11 @@ fn normalize_requirement(
37653766
name: requirement.name,
37663767
extras: requirement.extras,
37673768
marker: requirement.marker,
3768-
source: RequirementSource::Registry { specifier, index },
3769+
source: RequirementSource::Registry {
3770+
specifier,
3771+
index,
3772+
conflict,
3773+
},
37693774
origin: None,
37703775
})
37713776
}

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

Lines changed: 1 addition & 32 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
use rustc_hash::FxHashMap;
22
use uv_pep508::{MarkerTree, PackageName};
3-
use uv_pypi_types::{ConflictItemRef, Requirement};
3+
use uv_pypi_types::Requirement;
44

55
use crate::ResolverEnvironment;
66

@@ -64,35 +64,4 @@ impl<T> ForkMap<T> {
6464
.map(|entry| &entry.value)
6565
.collect()
6666
}
67-
68-
/// Returns a list of values associated with a package that are compatible with the given fork.
69-
///
70-
/// Compatibility implies that the markers on the requirement that contained this value
71-
/// are not disjoint with the given fork. Note that this does not imply that the requirement
72-
/// diverged in the given fork - values from overlapping forks may be combined.
73-
pub(crate) fn get_without_conflicts(
74-
&self,
75-
name: &PackageName,
76-
parent_name: Option<&PackageName>,
77-
env: &ResolverEnvironment,
78-
) -> Vec<&T> {
79-
let Some(values) = self.0.get(name) else {
80-
return Vec::new();
81-
};
82-
values
83-
.iter()
84-
.filter(|entry| env.included_by_marker(&entry.marker))
85-
.filter(|entry| {
86-
let Some(parent_name) = parent_name else {
87-
return true;
88-
};
89-
let Some(extra) = entry.marker.top_level_extra_name() else {
90-
return true;
91-
};
92-
let group = ConflictItemRef::from((parent_name, &extra));
93-
env.included_by_group(group)
94-
})
95-
.map(|entry| &entry.value)
96-
.collect()
97-
}
9867
}

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

Lines changed: 25 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,7 @@
11
use uv_distribution_types::IndexUrl;
22
use uv_normalize::PackageName;
33
use uv_pep508::VerbatimUrl;
4-
use uv_pypi_types::RequirementSource;
4+
use uv_pypi_types::{ConflictItem, RequirementSource};
55

66
use crate::resolver::ForkMap;
77
use crate::{DependencyMode, Manifest, ResolverEnvironment};
@@ -20,7 +20,13 @@ use crate::{DependencyMode, Manifest, ResolverEnvironment};
2020
///
2121
/// [`Indexes`] would contain a single entry mapping `torch` to `https://download.pytorch.org/whl/cu121`.
2222
#[derive(Debug, Default, Clone)]
23-
pub(crate) struct Indexes(ForkMap<IndexUrl>);
23+
pub(crate) struct Indexes(ForkMap<Entry>);
24+
25+
#[derive(Debug, Clone)]
26+
struct Entry {
27+
index: IndexUrl,
28+
conflict: Option<ConflictItem>,
29+
}
2430

2531
impl Indexes {
2632
/// Determine the set of explicit, pinned indexes in the [`Manifest`].
@@ -33,13 +39,16 @@ impl Indexes {
3339

3440
for requirement in manifest.requirements(env, dependencies) {
3541
let RequirementSource::Registry {
36-
index: Some(index), ..
42+
index: Some(index),
43+
conflict,
44+
..
3745
} = &requirement.source
3846
else {
3947
continue;
4048
};
4149
let index = IndexUrl::from(VerbatimUrl::from_url(index.clone()));
42-
indexes.add(&requirement, index);
50+
let conflict = conflict.clone();
51+
indexes.add(&requirement, Entry { index, conflict });
4352
}
4453

4554
Self(indexes)
@@ -51,12 +60,17 @@ impl Indexes {
5160
}
5261

5362
/// Return the explicit index used for a package in the given fork.
54-
pub(crate) fn get(
55-
&self,
56-
name: &PackageName,
57-
parent: Option<&PackageName>,
58-
env: &ResolverEnvironment,
59-
) -> Vec<&IndexUrl> {
60-
self.0.get_without_conflicts(name, parent, env)
63+
pub(crate) fn get(&self, name: &PackageName, env: &ResolverEnvironment) -> Vec<&IndexUrl> {
64+
let entries = self.0.get(name, env);
65+
entries
66+
.iter()
67+
.filter(|entry| {
68+
entry
69+
.conflict
70+
.as_ref()
71+
.map_or(true, |conflict| env.included_by_group(conflict.as_ref()))
72+
})
73+
.map(|entry| &entry.index)
74+
.collect()
6175
}
6276
}

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

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -2256,7 +2256,7 @@ impl ForkState {
22562256
};
22572257

22582258
// If the package is pinned to an exact index, add it to the fork.
2259-
for index in indexes.get(name, self.next.name_no_root(), &self.env) {
2259+
for index in indexes.get(name, &self.env) {
22602260
self.fork_indexes.insert(name, index, &self.env)?;
22612261
}
22622262
}

0 commit comments

Comments
 (0)