@@ -2,7 +2,7 @@ use std::collections::{HashMap, HashSet};
2
2
3
3
use anyhow:: bail;
4
4
use log:: { debug, trace} ;
5
- use semver:: { Version , VersionReq } ;
5
+ use semver:: VersionReq ;
6
6
use url:: Url ;
7
7
8
8
use crate :: core:: PackageSet ;
@@ -233,13 +233,24 @@ impl<'cfg> PackageRegistry<'cfg> {
233
233
/// Note that the patch list specified here *will not* be available to
234
234
/// `query` until `lock_patches` is called below, which should be called
235
235
/// once all patches have been added.
236
+ ///
237
+ /// The return value is a `Vec` of patches that should *not* be locked.
238
+ /// This happens when the patch is locked, but the patch has been updated
239
+ /// so the locked value is no longer correct.
236
240
pub fn patch (
237
241
& mut self ,
238
242
url : & Url ,
239
- deps : & [ ( & Dependency , Option < Dependency > ) ] ,
240
- ) -> CargoResult < ( ) > {
243
+ deps : & [ ( & Dependency , Option < ( Dependency , PackageId ) > ) ] ,
244
+ ) -> CargoResult < Vec < ( Dependency , PackageId ) > > {
245
+ // NOTE: None of this code is aware of required features. If a patch
246
+ // is missing a required feature, you end up with an "unused patch"
247
+ // warning, which is very hard to understand. Ideally the warning
248
+ // would be tailored to indicate *why* it is unused.
241
249
let canonical = CanonicalUrl :: new ( url) ?;
242
250
251
+ // Return value of patches that shouldn't be locked.
252
+ let mut unlock_patches = Vec :: new ( ) ;
253
+
243
254
// First up we need to actually resolve each `deps` specification to
244
255
// precisely one summary. We're not using the `query` method below as it
245
256
// internally uses maps we're building up as part of this method
@@ -251,8 +262,15 @@ impl<'cfg> PackageRegistry<'cfg> {
251
262
// of summaries which should be the same length as `deps` above.
252
263
let unlocked_summaries = deps
253
264
. iter ( )
254
- . map ( |( orig_dep, locked_dep) | {
255
- let dep = locked_dep. as_ref ( ) . unwrap_or ( orig_dep) ;
265
+ . map ( |( orig_patch, locked) | {
266
+ // Remove double reference in orig_patch. Is there maybe a
267
+ // magic pattern that could avoid this?
268
+ let orig_patch = * orig_patch;
269
+ // Use the locked patch if it exists, otherwise use the original.
270
+ let dep = match locked {
271
+ Some ( ( locked_patch, _locked_id) ) => locked_patch,
272
+ None => orig_patch,
273
+ } ;
256
274
debug ! (
257
275
"registering a patch for `{}` with `{}`" ,
258
276
url,
@@ -275,7 +293,21 @@ impl<'cfg> PackageRegistry<'cfg> {
275
293
. get_mut ( dep. source_id ( ) )
276
294
. expect ( "loaded source not present" ) ;
277
295
let summaries = source. query_vec ( dep) ?;
278
- let summary = summary_for_patch ( orig_dep, locked_dep, url, summaries, source) ?;
296
+ let ( summary, should_unlock) =
297
+ summary_for_patch ( orig_patch, & locked, summaries, source) . chain_err ( || {
298
+ format ! (
299
+ "patch for `{}` in `{}` did not resolve to any crates" ,
300
+ orig_patch. package_name( ) ,
301
+ url,
302
+ )
303
+ } ) ?;
304
+ debug ! (
305
+ "patch summary is {:?} should_unlock={:?}" ,
306
+ summary, should_unlock
307
+ ) ;
308
+ if let Some ( unlock_id) = should_unlock {
309
+ unlock_patches. push ( ( orig_patch. clone ( ) , unlock_id) ) ;
310
+ }
279
311
280
312
if * summary. package_id ( ) . source_id ( ) . canonical_url ( ) == canonical {
281
313
anyhow:: bail!(
@@ -313,7 +345,7 @@ impl<'cfg> PackageRegistry<'cfg> {
313
345
self . patches_available . insert ( canonical. clone ( ) , ids) ;
314
346
self . patches . insert ( canonical, unlocked_summaries) ;
315
347
316
- Ok ( ( ) )
348
+ Ok ( unlock_patches )
317
349
}
318
350
319
351
/// Lock all patch summaries added via `patch`, making them available to
@@ -327,6 +359,7 @@ impl<'cfg> PackageRegistry<'cfg> {
327
359
assert ! ( !self . patches_locked) ;
328
360
for summaries in self . patches . values_mut ( ) {
329
361
for summary in summaries {
362
+ debug ! ( "locking patch {:?}" , summary) ;
330
363
* summary = lock ( & self . locked , & self . patches_available , summary. clone ( ) ) ;
331
364
}
332
365
}
@@ -711,60 +744,68 @@ fn lock(
711
744
} )
712
745
}
713
746
714
- /// This is a helper for generating a user-friendly error message for a bad patch .
747
+ /// This is a helper for selecting the summary, or generating a helpful error message .
715
748
fn summary_for_patch (
716
749
orig_patch : & Dependency ,
717
- locked_patch : & Option < Dependency > ,
718
- url : & Url ,
750
+ locked : & Option < ( Dependency , PackageId ) > ,
719
751
mut summaries : Vec < Summary > ,
720
752
source : & mut dyn Source ,
721
- ) -> CargoResult < Summary > {
753
+ ) -> CargoResult < ( Summary , Option < PackageId > ) > {
722
754
if summaries. len ( ) == 1 {
723
- return Ok ( summaries. pop ( ) . unwrap ( ) ) ;
755
+ return Ok ( ( summaries. pop ( ) . unwrap ( ) , None ) ) ;
724
756
}
725
- // Helpers to create a comma-separated string of versions.
726
- let versions = |versions : & mut [ & Version ] | -> String {
727
- versions. sort ( ) ;
728
- let versions: Vec < _ > = versions. into_iter ( ) . map ( |v| v. to_string ( ) ) . collect ( ) ;
729
- versions. join ( ", " )
730
- } ;
731
- let summary_versions = |summaries : & [ Summary ] | -> String {
732
- let mut vers: Vec < _ > = summaries. iter ( ) . map ( |summary| summary. version ( ) ) . collect ( ) ;
733
- versions ( & mut vers)
757
+ let best_summary = |summaries : & mut Vec < Summary > | -> Summary {
758
+ // TODO: This could maybe honor -Zminimal-versions?
759
+ summaries. sort_by ( |a, b| a. version ( ) . cmp ( b. version ( ) ) ) ;
760
+ summaries. pop ( ) . unwrap ( )
734
761
} ;
735
762
if summaries. len ( ) > 1 {
736
- anyhow :: bail! (
737
- "patch for `{}` in `{}` resolved to more than one candidate \n \
738
- Found versions: {} \n \
739
- Update the patch definition to select only one package, \
740
- or remove the extras from the patch location." ,
741
- orig_patch . package_name ( ) ,
742
- url ,
743
- summary_versions ( & summaries )
744
- ) ;
763
+ let summary = best_summary ( & mut summaries ) ;
764
+ if let Some ( ( _dep , lock_id ) ) = locked {
765
+ // I can't think of a scenario where this might happen (locked by
766
+ // definition should only match at most one summary). Maybe if the
767
+ // source is broken?
768
+ return Ok ( ( summary , Some ( * lock_id ) ) ) ;
769
+ } else {
770
+ return Ok ( ( summary , None ) ) ;
771
+ }
745
772
}
773
+ assert ! ( summaries. is_empty( ) ) ;
746
774
// No summaries found, try to help the user figure out what is wrong.
747
- let extra = if let Some ( locked_patch) = locked_patch {
748
- let found = match source. query_vec ( orig_patch) {
749
- Ok ( unlocked_summaries) => format ! ( " (found {})" , summary_versions( & unlocked_summaries) ) ,
775
+ if let Some ( ( locked_patch, locked_id) ) = locked {
776
+ // Since the locked patch did not match anything, try the unlocked one.
777
+ let mut orig_matches = match source. query_vec ( orig_patch) {
778
+ Ok ( summaries) => summaries,
750
779
Err ( e) => {
751
780
log:: warn!(
752
781
"could not determine unlocked summaries for dep {:?}: {:?}" ,
753
782
orig_patch,
754
783
e
755
784
) ;
756
- "" . to_string ( )
785
+ Vec :: new ( )
757
786
}
758
787
} ;
759
- format ! (
760
- "The patch is locked to {} in Cargo.lock, \
761
- but the version in the patch location does not match{}.\n \
762
- Make sure the patch points to the correct version.\n \
763
- If it does, run `cargo update -p {}` to update Cargo.lock.",
764
- locked_patch. version_req( ) ,
765
- found,
766
- locked_patch. package_name( ) ,
767
- )
788
+ if orig_matches. is_empty ( ) {
789
+ // This should be relatively unusual. For example, a patch of
790
+ // {version="0.1.2", ...} and the patch location no longer contains a
791
+ // version that matches "0.1.2". It is unusual to explicitly write a
792
+ // version in the patch.
793
+ anyhow:: bail!(
794
+ "The patch is locked to {} in Cargo.lock, but the version in the \
795
+ patch location does not match any packages in the patch location.\n \
796
+ Make sure the patch points to the correct version.",
797
+ locked_patch. version_req( ) ,
798
+ ) ;
799
+ }
800
+ let summary = best_summary ( & mut orig_matches) ;
801
+ debug ! (
802
+ "locked patch no longer matches, but unlocked version should work. \
803
+ locked={:?} unlocked={:?} summary={:?}",
804
+ locked, orig_patch, summary
805
+ ) ;
806
+ // The unlocked version found a match. This returns a value to
807
+ // indicate that this entry should be unlocked.
808
+ return Ok ( ( summary, Some ( * locked_id) ) ) ;
768
809
} else {
769
810
// Try checking if there are *any* packages that match this by name.
770
811
let name_only_dep =
@@ -777,8 +818,12 @@ fn summary_for_patch(
777
818
. collect :: < Vec < _ > > ( ) ;
778
819
match vers. len ( ) {
779
820
0 => format ! ( "" ) ,
780
- 1 => format ! ( "version `{}`" , versions( & mut vers) ) ,
781
- _ => format ! ( "versions `{}`" , versions( & mut vers) ) ,
821
+ 1 => format ! ( "version `{}`" , vers[ 0 ] ) ,
822
+ _ => {
823
+ vers. sort ( ) ;
824
+ let strs: Vec < _ > = vers. into_iter ( ) . map ( |v| v. to_string ( ) ) . collect ( ) ;
825
+ format ! ( "versions `{}`" , strs. join( ", " ) )
826
+ }
782
827
}
783
828
}
784
829
Err ( e) => {
@@ -791,27 +836,21 @@ fn summary_for_patch(
791
836
}
792
837
} ;
793
838
if found. is_empty ( ) {
794
- format ! (
839
+ anyhow :: bail !(
795
840
"The patch location does not appear to contain any packages \
796
841
matching the name `{}`.",
797
842
orig_patch. package_name( )
798
- )
843
+ ) ;
799
844
} else {
800
- format ! (
845
+ anyhow :: bail !(
801
846
"The patch location contains a `{}` package with {}, but the patch \
802
847
definition requires `{}`.\n \
803
848
Check that the version in the patch location is what you expect, \
804
849
and update the patch definition to match.",
805
850
orig_patch. package_name( ) ,
806
851
found,
807
852
orig_patch. version_req( )
808
- )
853
+ ) ;
809
854
}
810
- } ;
811
- anyhow:: bail!(
812
- "patch for `{}` in `{}` did not resolve to any crates.\n {}" ,
813
- orig_patch. package_name( ) ,
814
- url,
815
- extra
816
- ) ;
855
+ }
817
856
}
0 commit comments