@@ -3,9 +3,9 @@ use std::{cmp, fmt, hash};
3
3
4
4
use core:: compiler:: CompileMode ;
5
5
use core:: interning:: InternedString ;
6
- use core:: Shell ;
6
+ use core:: { PackageId , PackageIdSpec , PackageSet , Shell } ;
7
7
use util:: lev_distance:: lev_distance;
8
- use util:: toml:: { StringOrBool , TomlProfile , U32OrBool } ;
8
+ use util:: toml:: { ProfilePackageSpec , StringOrBool , TomlProfile , U32OrBool } ;
9
9
use util:: CargoResult ;
10
10
11
11
/// Collection of all user profiles.
@@ -55,7 +55,7 @@ impl Profiles {
55
55
/// workspace.
56
56
pub fn get_profile (
57
57
& self ,
58
- pkg_name : & str ,
58
+ pkg_id : & PackageId ,
59
59
is_member : bool ,
60
60
profile_for : ProfileFor ,
61
61
mode : CompileMode ,
@@ -86,7 +86,7 @@ impl Profiles {
86
86
CompileMode :: Bench => & self . bench ,
87
87
CompileMode :: Doc { .. } => & self . doc ,
88
88
} ;
89
- let mut profile = maker. profile_for ( pkg_name , is_member, profile_for) ;
89
+ let mut profile = maker. profile_for ( Some ( pkg_id ) , is_member, profile_for) ;
90
90
// `panic` should not be set for tests/benches, or any of their
91
91
// dependencies.
92
92
if profile_for == ProfileFor :: TestDependency || mode. is_any_test ( ) {
@@ -112,18 +112,14 @@ impl Profiles {
112
112
/// select for the package that was actually built.
113
113
pub fn base_profile ( & self , release : bool ) -> Profile {
114
114
if release {
115
- self . release . profile_for ( "" , true , ProfileFor :: Any )
115
+ self . release . profile_for ( None , true , ProfileFor :: Any )
116
116
} else {
117
- self . dev . profile_for ( "" , true , ProfileFor :: Any )
117
+ self . dev . profile_for ( None , true , ProfileFor :: Any )
118
118
}
119
119
}
120
120
121
121
/// Used to check for overrides for non-existing packages.
122
- pub fn validate_packages (
123
- & self ,
124
- shell : & mut Shell ,
125
- packages : & HashSet < & str > ,
126
- ) -> CargoResult < ( ) > {
122
+ pub fn validate_packages ( & self , shell : & mut Shell , packages : & PackageSet ) -> CargoResult < ( ) > {
127
123
self . dev . validate_packages ( shell, packages) ?;
128
124
self . release . validate_packages ( shell, packages) ?;
129
125
self . test . validate_packages ( shell, packages) ?;
@@ -149,7 +145,12 @@ struct ProfileMaker {
149
145
}
150
146
151
147
impl ProfileMaker {
152
- fn profile_for ( & self , pkg_name : & str , is_member : bool , profile_for : ProfileFor ) -> Profile {
148
+ fn profile_for (
149
+ & self ,
150
+ pkg_id : Option < & PackageId > ,
151
+ is_member : bool ,
152
+ profile_for : ProfileFor ,
153
+ ) -> Profile {
153
154
let mut profile = self . default ;
154
155
if let Some ( ref toml) = self . toml {
155
156
merge_profile ( & mut profile, toml) ;
@@ -160,19 +161,38 @@ impl ProfileMaker {
160
161
}
161
162
if let Some ( ref overrides) = toml. overrides {
162
163
if !is_member {
163
- if let Some ( star ) = overrides. get ( "*" ) {
164
- merge_profile ( & mut profile, star ) ;
164
+ if let Some ( all ) = overrides. get ( & ProfilePackageSpec :: All ) {
165
+ merge_profile ( & mut profile, all ) ;
165
166
}
166
167
}
167
- if let Some ( byname) = overrides. get ( pkg_name) {
168
- merge_profile ( & mut profile, byname) ;
168
+ if let Some ( pkg_id) = pkg_id {
169
+ let mut matches = overrides. iter ( ) . filter_map (
170
+ |( key, spec_profile) | match key {
171
+ & ProfilePackageSpec :: All => None ,
172
+ & ProfilePackageSpec :: Spec ( ref s) => if s. matches ( pkg_id) {
173
+ Some ( spec_profile)
174
+ } else {
175
+ None
176
+ } ,
177
+ } ,
178
+ ) ;
179
+ if let Some ( spec_profile) = matches. next ( ) {
180
+ merge_profile ( & mut profile, spec_profile) ;
181
+ // `validate_packages` should ensure that there are
182
+ // no additional matches.
183
+ assert ! (
184
+ matches. next( ) . is_none( ) ,
185
+ "package `{}` matched multiple profile overrides" ,
186
+ pkg_id
187
+ ) ;
188
+ }
169
189
}
170
190
}
171
191
}
172
192
profile
173
193
}
174
194
175
- fn validate_packages ( & self , shell : & mut Shell , packages : & HashSet < & str > ) -> CargoResult < ( ) > {
195
+ fn validate_packages ( & self , shell : & mut Shell , packages : & PackageSet ) -> CargoResult < ( ) > {
176
196
let toml = match self . toml {
177
197
Some ( ref toml) => toml,
178
198
None => return Ok ( ( ) ) ,
@@ -181,23 +201,88 @@ impl ProfileMaker {
181
201
Some ( ref overrides) => overrides,
182
202
None => return Ok ( ( ) ) ,
183
203
} ;
184
- for key in overrides. keys ( ) . filter ( |k| k. as_str ( ) != "*" ) {
185
- if !packages. contains ( key. as_str ( ) ) {
204
+ // Verify that a package doesn't match multiple spec overrides.
205
+ let mut found = HashSet :: new ( ) ;
206
+ for pkg_id in packages. package_ids ( ) {
207
+ let matches: Vec < & PackageIdSpec > = overrides
208
+ . keys ( )
209
+ . filter_map ( |key| match key {
210
+ & ProfilePackageSpec :: All => None ,
211
+ & ProfilePackageSpec :: Spec ( ref spec) => if spec. matches ( pkg_id) {
212
+ Some ( spec)
213
+ } else {
214
+ None
215
+ } ,
216
+ } )
217
+ . collect ( ) ;
218
+ match matches. len ( ) {
219
+ 0 => { }
220
+ 1 => {
221
+ found. insert ( matches[ 0 ] . clone ( ) ) ;
222
+ }
223
+ _ => {
224
+ let specs = matches
225
+ . iter ( )
226
+ . map ( |spec| spec. to_string ( ) )
227
+ . collect :: < Vec < _ > > ( )
228
+ . join ( ", " ) ;
229
+ bail ! (
230
+ "multiple profile overrides in profile `{}` match package `{}`\n \
231
+ found profile override specs: {}",
232
+ self . default . name,
233
+ pkg_id,
234
+ specs
235
+ ) ;
236
+ }
237
+ }
238
+ }
239
+
240
+ // Verify every override matches at least one package.
241
+ let missing_specs = overrides. keys ( ) . filter_map ( |key| {
242
+ if let & ProfilePackageSpec :: Spec ( ref spec) = key {
243
+ if !found. contains ( spec) {
244
+ return Some ( spec) ;
245
+ }
246
+ }
247
+ None
248
+ } ) ;
249
+ for spec in missing_specs {
250
+ // See if there is an exact name match.
251
+ let name_matches: Vec < String > = packages
252
+ . package_ids ( )
253
+ . filter_map ( |pkg_id| {
254
+ if pkg_id. name ( ) . as_str ( ) == spec. name ( ) {
255
+ Some ( pkg_id. to_string ( ) )
256
+ } else {
257
+ None
258
+ }
259
+ } )
260
+ . collect ( ) ;
261
+ if name_matches. len ( ) == 0 {
186
262
let suggestion = packages
187
- . iter ( )
188
- . map ( |p| ( lev_distance ( key , p ) , p) )
263
+ . package_ids ( )
264
+ . map ( |p| ( lev_distance ( spec . name ( ) , & p . name ( ) ) , p. name ( ) ) )
189
265
. filter ( |& ( d, _) | d < 4 )
190
266
. min_by_key ( |p| p. 0 )
191
267
. map ( |p| p. 1 ) ;
192
268
match suggestion {
193
269
Some ( p) => shell. warn ( format ! (
194
- "package `{}` for profile override not found\n \n Did you mean `{}`?" ,
195
- key, p
270
+ "profile override spec `{}` did not match any packages\n \n \
271
+ Did you mean `{}`?",
272
+ spec, p
196
273
) ) ?,
197
- None => {
198
- shell. warn ( format ! ( "package `{}` for profile override not found" , key) ) ?
199
- }
200
- } ;
274
+ None => shell. warn ( format ! (
275
+ "profile override spec `{}` did not match any packages" ,
276
+ spec
277
+ ) ) ?,
278
+ }
279
+ } else {
280
+ shell. warn ( format ! (
281
+ "version or URL in profile override spec `{}` does not \
282
+ match any of the packages: {}",
283
+ spec,
284
+ name_matches. join( ", " )
285
+ ) ) ?;
201
286
}
202
287
}
203
288
Ok ( ( ) )
0 commit comments