1
1
use std:: collections:: HashMap ;
2
2
3
+ use semver:: VersionReq ;
4
+ use url:: Url ;
5
+
3
6
use core:: { Source , SourceId , SourceMap , Summary , Dependency , PackageId } ;
4
7
use core:: PackageSet ;
5
8
use util:: { Config , profile} ;
@@ -77,6 +80,7 @@ pub struct PackageRegistry<'cfg> {
77
80
78
81
locked : LockedMap ,
79
82
source_config : SourceConfigMap < ' cfg > ,
83
+ patches : HashMap < Url , Vec < Summary > > ,
80
84
}
81
85
82
86
type LockedMap = HashMap < SourceId , HashMap < String , Vec < ( PackageId , Vec < PackageId > ) > > > ;
@@ -97,6 +101,7 @@ impl<'cfg> PackageRegistry<'cfg> {
97
101
overrides : Vec :: new ( ) ,
98
102
source_config : source_config,
99
103
locked : HashMap :: new ( ) ,
104
+ patches : HashMap :: new ( ) ,
100
105
} )
101
106
}
102
107
@@ -175,6 +180,39 @@ impl<'cfg> PackageRegistry<'cfg> {
175
180
sub_vec. push ( ( id, deps) ) ;
176
181
}
177
182
183
+ pub fn patch ( & mut self , url : & Url , deps : & [ Dependency ] ) -> CargoResult < ( ) > {
184
+ let deps = deps. iter ( ) . map ( |dep| {
185
+ let mut summaries = self . query_vec ( dep) ?. into_iter ( ) ;
186
+ let summary = match summaries. next ( ) {
187
+ Some ( summary) => summary,
188
+ None => {
189
+ bail ! ( "patch for `{}` in `{}` did not resolve to any crates" ,
190
+ dep. name( ) , url)
191
+ }
192
+ } ;
193
+ if summaries. next ( ) . is_some ( ) {
194
+ bail ! ( "patch for `{}` in `{}` resolved to more than one candidate" ,
195
+ dep. name( ) , url)
196
+ }
197
+ if summary. package_id ( ) . source_id ( ) . url ( ) == url {
198
+ bail ! ( "patch for `{}` in `{}` points to the same source, but \
199
+ patches must point to different sources",
200
+ dep. name( ) , url) ;
201
+ }
202
+ Ok ( summary)
203
+ } ) . collect :: < CargoResult < Vec < _ > > > ( ) . chain_err ( || {
204
+ format ! ( "failed to resolve patches for `{}`" , url)
205
+ } ) ?;
206
+
207
+ self . patches . insert ( url. clone ( ) , deps) ;
208
+
209
+ Ok ( ( ) )
210
+ }
211
+
212
+ pub fn patches ( & self ) -> & HashMap < Url , Vec < Summary > > {
213
+ & self . patches
214
+ }
215
+
178
216
fn load ( & mut self , source_id : & SourceId , kind : Kind ) -> CargoResult < ( ) > {
179
217
( || {
180
218
let source = self . source_config . load ( source_id) ?;
@@ -222,7 +260,7 @@ impl<'cfg> PackageRegistry<'cfg> {
222
260
/// possible. If we're unable to map a dependency though, we just pass it on
223
261
/// through.
224
262
pub fn lock ( & self , summary : Summary ) -> Summary {
225
- lock ( & self . locked , summary)
263
+ lock ( & self . locked , & self . patches , summary)
226
264
}
227
265
228
266
fn warn_bad_override ( & self ,
@@ -274,39 +312,97 @@ impl<'cfg> Registry for PackageRegistry<'cfg> {
274
312
fn query ( & mut self ,
275
313
dep : & Dependency ,
276
314
f : & mut FnMut ( Summary ) ) -> CargoResult < ( ) > {
277
- // Ensure the requested source_id is loaded
278
- self . ensure_loaded ( dep. source_id ( ) , Kind :: Normal ) . chain_err ( || {
279
- format ! ( "failed to load source for a dependency \
280
- on `{}`", dep. name( ) )
281
- } ) ?;
282
-
283
-
284
315
let ( override_summary, n, to_warn) = {
285
316
// Look for an override and get ready to query the real source.
286
317
let override_summary = self . query_overrides ( & dep) ?;
287
- let source = self . sources . get_mut ( dep. source_id ( ) ) ;
288
- match ( override_summary, source) {
289
- ( Some ( _) , None ) => bail ! ( "override found but no real ones" ) ,
290
- ( None , None ) => return Ok ( ( ) ) ,
291
-
292
- // If we don't have an override then we just ship everything
293
- // upstairs after locking the summary
294
- ( None , Some ( source) ) => {
295
- let locked = & self . locked ;
296
- return source. query ( dep, & mut |summary| f ( lock ( locked, summary) ) )
318
+
319
+ // Next up on our list of candidates is to check the `[patch]`
320
+ // section of the manifest. Here we look through all patches
321
+ // relevant to the source that `dep` points to, and then we match
322
+ // name/version. Note that we don't use `dep.matches(..)` because
323
+ // the patches, by definition, come from a different source.
324
+ // This means that `dep.matches(..)` will always return false, when
325
+ // what we really care about is the name/version match.
326
+ let mut patches = Vec :: < Summary > :: new ( ) ;
327
+ if let Some ( extra) = self . patches . get ( dep. source_id ( ) . url ( ) ) {
328
+ patches. extend ( extra. iter ( ) . filter ( |s| {
329
+ dep. matches_ignoring_source ( s)
330
+ } ) . cloned ( ) ) ;
331
+ }
332
+
333
+ // A crucial feature of the `[patch]` feature is that we *don't*
334
+ // query the actual registry if we have a "locked" dependency. A
335
+ // locked dep basically just means a version constraint of `=a.b.c`,
336
+ // and because patches take priority over the actual source then if
337
+ // we have a candidate we're done.
338
+ if patches. len ( ) == 1 && dep. is_locked ( ) {
339
+ let patch = patches. remove ( 0 ) ;
340
+ match override_summary {
341
+ Some ( summary) => ( summary, 1 , Some ( patch) ) ,
342
+ None => {
343
+ f ( patch) ;
344
+ return Ok ( ( ) )
345
+ }
297
346
}
347
+ } else {
348
+ if patches. len ( ) > 0 {
349
+ debug ! ( "found {} patches with an unlocked dep, \
350
+ looking at sources", patches. len( ) ) ;
351
+ }
352
+
353
+ // Ensure the requested source_id is loaded
354
+ self . ensure_loaded ( dep. source_id ( ) , Kind :: Normal ) . chain_err ( || {
355
+ format ! ( "failed to load source for a dependency \
356
+ on `{}`", dep. name( ) )
357
+ } ) ?;
358
+
359
+ let source = self . sources . get_mut ( dep. source_id ( ) ) ;
360
+ match ( override_summary, source) {
361
+ ( Some ( _) , None ) => bail ! ( "override found but no real ones" ) ,
362
+ ( None , None ) => return Ok ( ( ) ) ,
363
+
364
+ // If we don't have an override then we just ship
365
+ // everything upstairs after locking the summary
366
+ ( None , Some ( source) ) => {
367
+ for patch in patches. iter ( ) {
368
+ f ( patch. clone ( ) ) ;
369
+ }
370
+
371
+ // Our sources shouldn't ever come back to us with two
372
+ // summaries that have the same version. We could,
373
+ // however, have an `[patch]` section which is in use
374
+ // to override a version in the registry. This means
375
+ // that if our `summary` in this loop has the same
376
+ // version as something in `patches` that we've
377
+ // already selected, then we skip this `summary`.
378
+ let locked = & self . locked ;
379
+ let all_patches = & self . patches ;
380
+ return source. query ( dep, & mut |summary| {
381
+ for patch in patches. iter ( ) {
382
+ let patch = patch. package_id ( ) . version ( ) ;
383
+ if summary. package_id ( ) . version ( ) == patch {
384
+ return
385
+ }
386
+ }
387
+ f ( lock ( locked, all_patches, summary) )
388
+ } )
389
+ }
298
390
299
- // If we have an override summary then we query the source to sanity
300
- // check its results. We don't actually use any of the summaries it
301
- // gives us though.
302
- ( Some ( override_summary) , Some ( source) ) => {
303
- let mut n = 0 ;
304
- let mut to_warn = None ;
305
- source. query ( dep, & mut |summary| {
306
- n += 1 ;
307
- to_warn = Some ( summary) ;
308
- } ) ?;
309
- ( override_summary, n, to_warn)
391
+ // If we have an override summary then we query the source
392
+ // to sanity check its results. We don't actually use any of
393
+ // the summaries it gives us though.
394
+ ( Some ( override_summary) , Some ( source) ) => {
395
+ if patches. len ( ) > 0 {
396
+ bail ! ( "found patches and a path override" )
397
+ }
398
+ let mut n = 0 ;
399
+ let mut to_warn = None ;
400
+ source. query ( dep, & mut |summary| {
401
+ n += 1 ;
402
+ to_warn = Some ( summary) ;
403
+ } ) ?;
404
+ ( override_summary, n, to_warn)
405
+ }
310
406
}
311
407
}
312
408
} ;
@@ -321,7 +417,9 @@ impl<'cfg> Registry for PackageRegistry<'cfg> {
321
417
}
322
418
}
323
419
324
- fn lock ( locked : & LockedMap , summary : Summary ) -> Summary {
420
+ fn lock ( locked : & LockedMap ,
421
+ patches : & HashMap < Url , Vec < Summary > > ,
422
+ summary : Summary ) -> Summary {
325
423
let pair = locked. get ( summary. source_id ( ) ) . and_then ( |map| {
326
424
map. get ( summary. name ( ) )
327
425
} ) . and_then ( |vec| {
@@ -335,7 +433,7 @@ fn lock(locked: &LockedMap, summary: Summary) -> Summary {
335
433
Some ( & ( ref precise, _) ) => summary. override_id ( precise. clone ( ) ) ,
336
434
None => summary,
337
435
} ;
338
- summary. map_dependencies ( |mut dep| {
436
+ summary. map_dependencies ( |dep| {
339
437
trace ! ( "\t {}/{}/{}" , dep. name( ) , dep. version_req( ) ,
340
438
dep. source_id( ) ) ;
341
439
@@ -362,6 +460,7 @@ fn lock(locked: &LockedMap, summary: Summary) -> Summary {
362
460
let locked = locked_deps. iter ( ) . find ( |id| dep. matches_id ( id) ) ;
363
461
if let Some ( locked) = locked {
364
462
trace ! ( "\t first hit on {}" , locked) ;
463
+ let mut dep = dep. clone ( ) ;
365
464
dep. lock_to ( locked) ;
366
465
return dep
367
466
}
@@ -375,17 +474,43 @@ fn lock(locked: &LockedMap, summary: Summary) -> Summary {
375
474
} ) . and_then ( |vec| {
376
475
vec. iter ( ) . find ( |& & ( ref id, _) | dep. matches_id ( id) )
377
476
} ) ;
378
- match v {
379
- Some ( & ( ref id, _) ) => {
380
- trace ! ( "\t second hit on {}" , id) ;
381
- dep. lock_to ( id) ;
477
+ if let Some ( & ( ref id, _) ) = v {
478
+ trace ! ( "\t second hit on {}" , id) ;
479
+ let mut dep = dep. clone ( ) ;
480
+ dep. lock_to ( id) ;
481
+ return dep
482
+ }
483
+
484
+ // Finally we check to see if any registered patches correspond to
485
+ // this dependency.
486
+ let v = patches. get ( dep. source_id ( ) . url ( ) ) . map ( |vec| {
487
+ let dep2 = dep. clone ( ) ;
488
+ let mut iter = vec. iter ( ) . filter ( move |s| {
489
+ dep2. name ( ) == s. package_id ( ) . name ( ) &&
490
+ dep2. version_req ( ) . matches ( s. package_id ( ) . version ( ) )
491
+ } ) ;
492
+ ( iter. next ( ) , iter)
493
+ } ) ;
494
+ if let Some ( ( Some ( summary) , mut remaining) ) = v {
495
+ assert ! ( remaining. next( ) . is_none( ) ) ;
496
+ let patch_source = summary. package_id ( ) . source_id ( ) ;
497
+ let patch_locked = locked. get ( patch_source) . and_then ( |m| {
498
+ m. get ( summary. package_id ( ) . name ( ) )
499
+ } ) . map ( |list| {
500
+ list. iter ( ) . any ( |& ( ref id, _) | id == summary. package_id ( ) )
501
+ } ) . unwrap_or ( false ) ;
502
+
503
+ if patch_locked {
504
+ trace ! ( "\t third hit on {}" , summary. package_id( ) ) ;
505
+ let req = VersionReq :: exact ( summary. package_id ( ) . version ( ) ) ;
506
+ let mut dep = dep. clone ( ) ;
507
+ dep. set_version_req ( req) ;
382
508
return dep
383
509
}
384
- None => {
385
- trace ! ( "\t remaining unlocked" ) ;
386
- dep
387
- }
388
510
}
511
+
512
+ trace ! ( "\t nope, unlocked" ) ;
513
+ return dep
389
514
} )
390
515
}
391
516
0 commit comments