68
68
69
69
use crate :: core:: dependency:: Dependency ;
70
70
use crate :: core:: { PackageId , SourceId , Summary } ;
71
- use crate :: sources:: registry:: { RegistryData , RegistryPackage } ;
71
+ use crate :: sources:: registry:: { RegistryData , RegistryPackage , INDEX_V_MAX } ;
72
72
use crate :: util:: interning:: InternedString ;
73
73
use crate :: util:: paths;
74
74
use crate :: util:: { internal, CargoResult , Config , Filesystem , ToSemver } ;
75
- use log:: info;
75
+ use anyhow:: bail;
76
+ use log:: { debug, info} ;
76
77
use semver:: { Version , VersionReq } ;
77
78
use std:: collections:: { HashMap , HashSet } ;
79
+ use std:: convert:: TryInto ;
78
80
use std:: fs;
79
81
use std:: path:: Path ;
80
82
use std:: str;
@@ -233,6 +235,8 @@ enum MaybeIndexSummary {
233
235
pub struct IndexSummary {
234
236
pub summary : Summary ,
235
237
pub yanked : bool ,
238
+ /// Schema version, see [`RegistryPackage`].
239
+ v : u32 ,
236
240
}
237
241
238
242
/// A representation of the cache on disk that Cargo maintains of summaries.
@@ -305,6 +309,11 @@ impl<'cfg> RegistryIndex<'cfg> {
305
309
// minimize the amount of work being done here and parse as little as
306
310
// necessary.
307
311
let raw_data = & summaries. raw_data ;
312
+ let max_version = if namespaced_features || weak_dep_features {
313
+ INDEX_V_MAX
314
+ } else {
315
+ 1
316
+ } ;
308
317
Ok ( summaries
309
318
. versions
310
319
. iter_mut ( )
@@ -318,6 +327,19 @@ impl<'cfg> RegistryIndex<'cfg> {
318
327
}
319
328
} ,
320
329
)
330
+ . filter ( move |is| {
331
+ if is. v > max_version {
332
+ debug ! (
333
+ "unsupported schema version {} ({} {})" ,
334
+ is. v,
335
+ is. summary. name( ) ,
336
+ is. summary. version( )
337
+ ) ;
338
+ false
339
+ } else {
340
+ true
341
+ }
342
+ } )
321
343
. filter ( move |is| {
322
344
is. summary
323
345
. unstable_gate ( namespaced_features, weak_dep_features)
@@ -550,6 +572,14 @@ impl Summaries {
550
572
let summary = match IndexSummary :: parse ( config, line, source_id) {
551
573
Ok ( summary) => summary,
552
574
Err ( e) => {
575
+ // This should only happen when there is an index
576
+ // entry from a future version of cargo that this
577
+ // version doesn't understand. Hopefully, those future
578
+ // versions of cargo correctly set INDEX_V_MAX and
579
+ // CURRENT_CACHE_VERSION, otherwise this will skip
580
+ // entries in the cache preventing those newer
581
+ // versions from reading them (that is, until the
582
+ // cache is rebuilt).
553
583
log:: info!( "failed to parse {:?} registry package: {}" , relative, e) ;
554
584
continue ;
555
585
}
@@ -578,7 +608,14 @@ impl Summaries {
578
608
// actually happens to verify that our cache is indeed fresh and
579
609
// computes exactly the same value as before.
580
610
if cfg ! ( debug_assertions) && cache_contents. is_some ( ) {
581
- assert_eq ! ( cache_bytes, cache_contents) ;
611
+ if cache_bytes != cache_contents {
612
+ panic ! (
613
+ "original cache contents:\n {:?}\n \
614
+ does not equal new cache contents:\n {:?}\n ",
615
+ cache_contents. as_ref( ) . map( |s| String :: from_utf8_lossy( s) ) ,
616
+ cache_bytes. as_ref( ) . map( |s| String :: from_utf8_lossy( s) ) ,
617
+ ) ;
618
+ }
582
619
}
583
620
584
621
// Once we have our `cache_bytes` which represents the `Summaries` we're
@@ -630,9 +667,9 @@ impl Summaries {
630
667
// Implementation of serializing/deserializing the cache of summaries on disk.
631
668
// Currently the format looks like:
632
669
//
633
- // +--------------+-------------+---+
634
- // | version byte | git sha rev | 0 |
635
- // +--------------+-------------+---+
670
+ // +--------------------+---------------------- +-------------+---+
671
+ // | cache version byte | index format version | git sha rev | 0 |
672
+ // +--------------------+---------------------- +-------------+---+
636
673
//
637
674
// followed by...
638
675
//
@@ -649,8 +686,14 @@ impl Summaries {
649
686
// versions of Cargo share the same cache they don't get too confused. The git
650
687
// sha lets us know when the file needs to be regenerated (it needs regeneration
651
688
// whenever the index itself updates).
689
+ //
690
+ // Cache versions:
691
+ // * `1`: The original version.
692
+ // * `2`: Added the "index format version" field so that if the index format
693
+ // changes, different versions of cargo won't get confused reading each
694
+ // other's caches.
652
695
653
- const CURRENT_CACHE_VERSION : u8 = 1 ;
696
+ const CURRENT_CACHE_VERSION : u8 = 2 ;
654
697
655
698
impl < ' a > SummariesCache < ' a > {
656
699
fn parse ( data : & ' a [ u8 ] , last_index_update : & str ) -> CargoResult < SummariesCache < ' a > > {
@@ -659,19 +702,32 @@ impl<'a> SummariesCache<'a> {
659
702
. split_first ( )
660
703
. ok_or_else ( || anyhow:: format_err!( "malformed cache" ) ) ?;
661
704
if * first_byte != CURRENT_CACHE_VERSION {
662
- anyhow:: bail!( "looks like a different Cargo's cache, bailing out" ) ;
705
+ bail ! ( "looks like a different Cargo's cache, bailing out" ) ;
706
+ }
707
+ let index_v_bytes = rest
708
+ . get ( ..4 )
709
+ . ok_or_else ( || anyhow:: anyhow!( "cache expected 4 bytes for index version" ) ) ?;
710
+ let index_v = u32:: from_le_bytes ( index_v_bytes. try_into ( ) . unwrap ( ) ) ;
711
+ if index_v != INDEX_V_MAX {
712
+ bail ! (
713
+ "index format version {} doesn't match the version I know ({})" ,
714
+ index_v,
715
+ INDEX_V_MAX
716
+ ) ;
663
717
}
718
+ let rest = & rest[ 4 ..] ;
719
+
664
720
let mut iter = split ( rest, 0 ) ;
665
721
if let Some ( update) = iter. next ( ) {
666
722
if update != last_index_update. as_bytes ( ) {
667
- anyhow :: bail!(
723
+ bail ! (
668
724
"cache out of date: current index ({}) != cache ({})" ,
669
725
last_index_update,
670
726
str :: from_utf8( update) ?,
671
727
)
672
728
}
673
729
} else {
674
- anyhow :: bail!( "malformed file" ) ;
730
+ bail ! ( "malformed file" ) ;
675
731
}
676
732
let mut ret = SummariesCache :: default ( ) ;
677
733
while let Some ( version) = iter. next ( ) {
@@ -692,6 +748,7 @@ impl<'a> SummariesCache<'a> {
692
748
. sum ( ) ;
693
749
let mut contents = Vec :: with_capacity ( size) ;
694
750
contents. push ( CURRENT_CACHE_VERSION ) ;
751
+ contents. extend ( & u32:: to_le_bytes ( INDEX_V_MAX ) ) ;
695
752
contents. extend_from_slice ( index_version. as_bytes ( ) ) ;
696
753
contents. push ( 0 ) ;
697
754
for ( version, data) in self . versions . iter ( ) {
@@ -741,26 +798,41 @@ impl IndexSummary {
741
798
///
742
799
/// The `line` provided is expected to be valid JSON.
743
800
fn parse ( config : & Config , line : & [ u8 ] , source_id : SourceId ) -> CargoResult < IndexSummary > {
801
+ // ****CAUTION**** Please be extremely careful with returning errors
802
+ // from this function. Entries that error are not included in the
803
+ // index cache, and can cause cargo to get confused when switching
804
+ // between different versions that understand the index differently.
805
+ // Make sure to consider the INDEX_V_MAX and CURRENT_CACHE_VERSION
806
+ // values carefully when making changes here.
744
807
let RegistryPackage {
745
808
name,
746
809
vers,
747
810
cksum,
748
811
deps,
749
- features,
812
+ mut features,
813
+ features2,
750
814
yanked,
751
815
links,
816
+ v,
752
817
} = serde_json:: from_slice ( line) ?;
818
+ let v = v. unwrap_or ( 1 ) ;
753
819
log:: trace!( "json parsed registry {}/{}" , name, vers) ;
754
820
let pkgid = PackageId :: new ( name, & vers, source_id) ?;
755
821
let deps = deps
756
822
. into_iter ( )
757
823
. map ( |dep| dep. into_dep ( source_id) )
758
824
. collect :: < CargoResult < Vec < _ > > > ( ) ?;
825
+ if let Some ( features2) = features2 {
826
+ for ( name, values) in features2 {
827
+ features. entry ( name) . or_default ( ) . extend ( values) ;
828
+ }
829
+ }
759
830
let mut summary = Summary :: new ( config, pkgid, deps, & features, links) ?;
760
831
summary. set_checksum ( cksum) ;
761
832
Ok ( IndexSummary {
762
833
summary,
763
834
yanked : yanked. unwrap_or ( false ) ,
835
+ v,
764
836
} )
765
837
}
766
838
}
0 commit comments