11use  std:: collections:: HashMap ; 
22
3+ use  semver:: VersionReq ; 
4+ use  url:: Url ; 
5+ 
36use  core:: { Source ,  SourceId ,  SourceMap ,  Summary ,  Dependency ,  PackageId } ; 
47use  core:: PackageSet ; 
58use  util:: { Config ,  profile} ; 
@@ -77,6 +80,7 @@ pub struct PackageRegistry<'cfg> {
7780
7881    locked :  LockedMap , 
7982    source_config :  SourceConfigMap < ' cfg > , 
83+     patches :  HashMap < Url ,  Vec < Summary > > , 
8084} 
8185
8286type  LockedMap  = HashMap < SourceId ,  HashMap < String ,  Vec < ( PackageId ,  Vec < PackageId > ) > > > ; 
@@ -97,6 +101,7 @@ impl<'cfg> PackageRegistry<'cfg> {
97101            overrides :  Vec :: new ( ) , 
98102            source_config :  source_config, 
99103            locked :  HashMap :: new ( ) , 
104+             patches :  HashMap :: new ( ) , 
100105        } ) 
101106    } 
102107
@@ -175,6 +180,39 @@ impl<'cfg> PackageRegistry<'cfg> {
175180        sub_vec. push ( ( id,  deps) ) ; 
176181    } 
177182
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+ 
178216    fn  load ( & mut  self ,  source_id :  & SourceId ,  kind :  Kind )  -> CargoResult < ( ) >  { 
179217        ( || { 
180218            let  source = self . source_config . load ( source_id) ?; 
@@ -222,7 +260,7 @@ impl<'cfg> PackageRegistry<'cfg> {
222260     /// possible. If we're unable to map a dependency though, we just pass it on 
223261     /// through. 
224262     pub  fn  lock ( & self ,  summary :  Summary )  -> Summary  { 
225-         lock ( & self . locked ,  summary) 
263+         lock ( & self . locked ,  & self . patches ,   summary) 
226264    } 
227265
228266    fn  warn_bad_override ( & self , 
@@ -274,39 +312,97 @@ impl<'cfg> Registry for PackageRegistry<'cfg> {
274312    fn  query ( & mut  self , 
275313             dep :  & Dependency , 
276314             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- 
284315        let  ( override_summary,  n,  to_warn)  = { 
285316            // Look for an override and get ready to query the real source. 
286317            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+                     } 
297346                } 
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+                     } 
298390
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+                     } 
310406                } 
311407            } 
312408        } ; 
@@ -321,7 +417,9 @@ impl<'cfg> Registry for PackageRegistry<'cfg> {
321417    } 
322418} 
323419
324- fn  lock ( locked :  & LockedMap ,  summary :  Summary )  -> Summary  { 
420+ fn  lock ( locked :  & LockedMap , 
421+         patches :  & HashMap < Url ,  Vec < Summary > > , 
422+         summary :  Summary )  -> Summary  { 
325423    let  pair = locked. get ( summary. source_id ( ) ) . and_then ( |map| { 
326424        map. get ( summary. name ( ) ) 
327425    } ) . and_then ( |vec| { 
@@ -335,7 +433,7 @@ fn lock(locked: &LockedMap, summary: Summary) -> Summary {
335433        Some ( & ( ref  precise,  _) )  => summary. override_id ( precise. clone ( ) ) , 
336434        None  => summary, 
337435    } ; 
338-     summary. map_dependencies ( |mut   dep| { 
436+     summary. map_dependencies ( |dep| { 
339437        trace ! ( "\t {}/{}/{}" ,  dep. name( ) ,  dep. version_req( ) , 
340438               dep. source_id( ) ) ; 
341439
@@ -362,6 +460,7 @@ fn lock(locked: &LockedMap, summary: Summary) -> Summary {
362460            let  locked = locked_deps. iter ( ) . find ( |id| dep. matches_id ( id) ) ; 
363461            if  let  Some ( locked)  = locked { 
364462                trace ! ( "\t first hit on {}" ,  locked) ; 
463+                 let  mut  dep = dep. clone ( ) ; 
365464                dep. lock_to ( locked) ; 
366465                return  dep
367466            } 
@@ -375,17 +474,43 @@ fn lock(locked: &LockedMap, summary: Summary) -> Summary {
375474        } ) . and_then ( |vec| { 
376475            vec. iter ( ) . find ( |& & ( ref  id,  _) | dep. matches_id ( id) ) 
377476        } ) ; 
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) ; 
382508                return  dep
383509            } 
384-             None  => { 
385-                 trace ! ( "\t remaining unlocked" ) ; 
386-                 dep
387-             } 
388510        } 
511+ 
512+         trace ! ( "\t nope, unlocked" ) ; 
513+         return  dep
389514    } ) 
390515} 
391516
0 commit comments