1
- use std:: iter;
2
-
1
+ use either:: Either ;
3
2
use rustc_hash:: FxHashMap ;
4
3
use same_file:: is_same_file;
5
4
use tracing:: debug;
@@ -8,7 +7,7 @@ use uv_cache_key::CanonicalUrl;
8
7
use uv_distribution_types:: Verbatim ;
9
8
use uv_git:: GitResolver ;
10
9
use uv_normalize:: PackageName ;
11
- use uv_pep508:: VerbatimUrl ;
10
+ use uv_pep508:: { MarkerTree , VerbatimUrl } ;
12
11
use uv_pypi_types:: { ParsedDirectoryUrl , ParsedUrl , VerbatimParsedUrl } ;
13
12
14
13
use crate :: { DependencyMode , Manifest , ResolveError , ResolverEnvironment } ;
@@ -24,10 +23,10 @@ use crate::{DependencyMode, Manifest, ResolveError, ResolverEnvironment};
24
23
/// [`crate::fork_urls::ForkUrls`].
25
24
#[ derive( Debug , Default ) ]
26
25
pub ( crate ) struct Urls {
27
- /// URL requirements in overrides. There can only be a single URL per package in overrides
28
- /// (since it replaces all other URLs), and an override URL replaces all requirements and
29
- /// constraints URLs .
30
- overrides : FxHashMap < PackageName , VerbatimParsedUrl > ,
26
+ /// URL requirements in overrides. An override URL replaces all requirements and constraints
27
+ /// URLs. There can be multiple URLs for the same package as long as they are in different
28
+ /// forks .
29
+ overrides : FxHashMap < PackageName , Vec < ( MarkerTree , VerbatimParsedUrl ) > > ,
31
30
/// URLs from regular requirements or from constraints. There can be multiple URLs for the same
32
31
/// package as long as they are in different forks.
33
32
regular : FxHashMap < PackageName , Vec < VerbatimParsedUrl > > ,
@@ -41,7 +40,8 @@ impl Urls {
41
40
dependencies : DependencyMode ,
42
41
) -> Result < Self , ResolveError > {
43
42
let mut urls: FxHashMap < PackageName , Vec < VerbatimParsedUrl > > = FxHashMap :: default ( ) ;
44
- let mut overrides: FxHashMap < PackageName , VerbatimParsedUrl > = FxHashMap :: default ( ) ;
43
+ let mut overrides: FxHashMap < PackageName , Vec < ( MarkerTree , VerbatimParsedUrl ) > > =
44
+ FxHashMap :: default ( ) ;
45
45
46
46
// Add all direct regular requirements and constraints URL.
47
47
for requirement in manifest. requirements_no_overrides ( env, dependencies) {
@@ -86,16 +86,10 @@ impl Urls {
86
86
// a requirements.txt entry `./anyio`, we still use the URL. See
87
87
// `allow_recursive_url_local_path_override_constraint`.
88
88
urls. remove ( & requirement. name ) ;
89
- let previous = overrides. insert ( requirement. name . clone ( ) , url. clone ( ) ) ;
90
- if let Some ( previous) = previous {
91
- if !same_resource ( & previous. parsed_url , & url. parsed_url , git) {
92
- return Err ( ResolveError :: ConflictingOverrideUrls (
93
- requirement. name . clone ( ) ,
94
- previous. verbatim . verbatim ( ) . to_string ( ) ,
95
- url. verbatim . verbatim ( ) . to_string ( ) ,
96
- ) ) ;
97
- }
98
- }
89
+ overrides
90
+ . entry ( requirement. name . clone ( ) )
91
+ . or_default ( )
92
+ . push ( ( requirement. marker , url) ) ;
99
93
}
100
94
101
95
Ok ( Self {
@@ -104,41 +98,47 @@ impl Urls {
104
98
} )
105
99
}
106
100
107
- /// Check and canonicalize the URL of a requirement .
101
+ /// Return an iterator over the allowed URLs for the given package .
108
102
///
109
103
/// If we have a URL override, apply it unconditionally for registry and URL requirements.
110
- /// Otherwise, there are two case: For a URL requirement (`url` isn't `None`), check that the
111
- /// URL is allowed and return its canonical form. For registry requirements, we return `None`
112
- /// if there is no override.
104
+ /// Otherwise, there are two case: for a URL requirement (`url` isn't `None`), check that the
105
+ /// URL is allowed and return its canonical form.
106
+ ///
107
+ /// For registry requirements, we return an empty iterator.
113
108
pub ( crate ) fn get_url < ' a > (
114
109
& ' a self ,
115
- env : & ResolverEnvironment ,
110
+ env : & ' a ResolverEnvironment ,
116
111
name : & ' a PackageName ,
117
112
url : Option < & ' a VerbatimParsedUrl > ,
118
113
git : & ' a GitResolver ,
119
- ) -> Result < Option < & ' a VerbatimParsedUrl > , ResolveError > {
120
- if let Some ( override_url) = self . get_override ( name) {
121
- Ok ( Some ( override_url) )
114
+ ) -> Result < impl Iterator < Item = & ' a VerbatimParsedUrl > , ResolveError > {
115
+ if let Some ( override_urls) = self . get_overrides ( name) {
116
+ Ok ( Either :: Left ( Either :: Left (
117
+ override_urls. into_iter ( ) . filter_map ( |( marker, url) | {
118
+ if env. included_by_marker ( * marker) {
119
+ Some ( url)
120
+ } else {
121
+ None
122
+ }
123
+ } ) ,
124
+ ) ) )
122
125
} else if let Some ( url) = url {
123
- Ok ( Some ( self . canonicalize_allowed_url (
124
- env,
125
- name,
126
- git,
127
- & url. verbatim ,
128
- & url. parsed_url ,
129
- ) ?) )
126
+ let url =
127
+ self . canonicalize_allowed_url ( env, name, git, & url. verbatim , & url. parsed_url ) ?;
128
+ Ok ( Either :: Left ( Either :: Right ( std:: iter:: once ( url) ) ) )
130
129
} else {
131
- Ok ( None )
130
+ Ok ( Either :: Right ( std :: iter :: empty ( ) ) )
132
131
}
133
132
}
134
133
134
+ /// Return `true` if the package has any URL (from overrides or regular requirements).
135
135
pub ( crate ) fn any_url ( & self , name : & PackageName ) -> bool {
136
- self . get_override ( name) . is_some ( ) || self . get_regular ( name) . is_some ( )
136
+ self . get_overrides ( name) . is_some ( ) || self . get_regular ( name) . is_some ( )
137
137
}
138
138
139
139
/// Return the [`VerbatimUrl`] override for the given package, if any.
140
- fn get_override ( & self , package : & PackageName ) -> Option < & VerbatimParsedUrl > {
141
- self . overrides . get ( package)
140
+ fn get_overrides ( & self , package : & PackageName ) -> Option < & [ ( MarkerTree , VerbatimParsedUrl ) ] > {
141
+ self . overrides . get ( package) . map ( Vec :: as_slice )
142
142
}
143
143
144
144
/// Return the allowed [`VerbatimUrl`]s for given package from regular requirements and
@@ -174,7 +174,7 @@ impl Urls {
174
174
let mut conflicting_urls: Vec < _ > = matching_urls
175
175
. into_iter ( )
176
176
. map ( |parsed_url| parsed_url. verbatim . verbatim ( ) . to_string ( ) )
177
- . chain ( iter:: once ( verbatim_url. verbatim ( ) . to_string ( ) ) )
177
+ . chain ( std :: iter:: once ( verbatim_url. verbatim ( ) . to_string ( ) ) )
178
178
. collect ( ) ;
179
179
conflicting_urls. sort ( ) ;
180
180
return Err ( ResolveError :: ConflictingUrls {
0 commit comments