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