6868
6969use crate :: core:: dependency:: Dependency ;
7070use crate :: core:: { PackageId , SourceId , Summary } ;
71- use crate :: sources:: registry:: { RegistryData , RegistryPackage } ;
71+ use crate :: sources:: registry:: { RegistryData , RegistryPackage , INDEX_V_MAX } ;
7272use crate :: util:: interning:: InternedString ;
7373use crate :: util:: paths;
7474use crate :: util:: { internal, CargoResult , Config , Filesystem , ToSemver } ;
7575use anyhow:: bail;
7676use log:: { debug, info} ;
7777use semver:: { Version , VersionReq } ;
7878use std:: collections:: { HashMap , HashSet } ;
79+ use std:: convert:: TryInto ;
7980use std:: fs;
8081use std:: path:: Path ;
8182use std:: str;
@@ -309,7 +310,7 @@ impl<'cfg> RegistryIndex<'cfg> {
309310 // necessary.
310311 let raw_data = & summaries. raw_data ;
311312 let max_version = if namespaced_features || weak_dep_features {
312- 2
313+ INDEX_V_MAX
313314 } else {
314315 1
315316 } ;
@@ -571,6 +572,14 @@ impl Summaries {
571572 let summary = match IndexSummary :: parse ( config, line, source_id) {
572573 Ok ( summary) => summary,
573574 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).
574583 log:: info!( "failed to parse {:?} registry package: {}" , relative, e) ;
575584 continue ;
576585 }
@@ -658,9 +667,9 @@ impl Summaries {
658667// Implementation of serializing/deserializing the cache of summaries on disk.
659668// Currently the format looks like:
660669//
661- // +--------------+-------------+---+
662- // | version byte | git sha rev | 0 |
663- // +--------------+-------------+---+
670+ // +--------------------+---------------------- +-------------+---+
671+ // | cache version byte | index format version | git sha rev | 0 |
672+ // +--------------------+---------------------- +-------------+---+
664673//
665674// followed by...
666675//
@@ -677,8 +686,14 @@ impl Summaries {
677686// versions of Cargo share the same cache they don't get too confused. The git
678687// sha lets us know when the file needs to be regenerated (it needs regeneration
679688// 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.
680695
681- const CURRENT_CACHE_VERSION : u8 = 1 ;
696+ const CURRENT_CACHE_VERSION : u8 = 2 ;
682697
683698impl < ' a > SummariesCache < ' a > {
684699 fn parse ( data : & ' a [ u8 ] , last_index_update : & str ) -> CargoResult < SummariesCache < ' a > > {
@@ -689,6 +704,19 @@ impl<'a> SummariesCache<'a> {
689704 if * first_byte != CURRENT_CACHE_VERSION {
690705 bail ! ( "looks like a different Cargo's cache, bailing out" ) ;
691706 }
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 {} is greater than the newest version I know ({})" ,
714+ index_v,
715+ INDEX_V_MAX
716+ ) ;
717+ }
718+ let rest = & rest[ 4 ..] ;
719+
692720 let mut iter = split ( rest, 0 ) ;
693721 if let Some ( update) = iter. next ( ) {
694722 if update != last_index_update. as_bytes ( ) {
@@ -720,6 +748,7 @@ impl<'a> SummariesCache<'a> {
720748 . sum ( ) ;
721749 let mut contents = Vec :: with_capacity ( size) ;
722750 contents. push ( CURRENT_CACHE_VERSION ) ;
751+ contents. extend ( & u32:: to_le_bytes ( INDEX_V_MAX ) ) ;
723752 contents. extend_from_slice ( index_version. as_bytes ( ) ) ;
724753 contents. push ( 0 ) ;
725754 for ( version, data) in self . versions . iter ( ) {
@@ -769,6 +798,12 @@ impl IndexSummary {
769798 ///
770799 /// The `line` provided is expected to be valid JSON.
771800 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.
772807 let RegistryPackage {
773808 name,
774809 vers,
0 commit comments