@@ -135,6 +135,8 @@ pub enum IndexSummary {
135135 Offline ( Summary ) ,
136136 /// From a newer schema version and is likely incomplete or inaccurate
137137 Unsupported ( Summary , u32 ) ,
138+ /// An error was encountered despite being a supported schema version
139+ Invalid ( Summary ) ,
138140}
139141
140142impl IndexSummary {
@@ -144,7 +146,8 @@ impl IndexSummary {
144146 IndexSummary :: Candidate ( sum)
145147 | IndexSummary :: Yanked ( sum)
146148 | IndexSummary :: Offline ( sum)
147- | IndexSummary :: Unsupported ( sum, _) => sum,
149+ | IndexSummary :: Unsupported ( sum, _)
150+ | IndexSummary :: Invalid ( sum) => sum,
148151 }
149152 }
150153
@@ -154,7 +157,8 @@ impl IndexSummary {
154157 IndexSummary :: Candidate ( sum)
155158 | IndexSummary :: Yanked ( sum)
156159 | IndexSummary :: Offline ( sum)
157- | IndexSummary :: Unsupported ( sum, _) => sum,
160+ | IndexSummary :: Unsupported ( sum, _)
161+ | IndexSummary :: Invalid ( sum) => sum,
158162 }
159163 }
160164
@@ -164,17 +168,13 @@ impl IndexSummary {
164168 IndexSummary :: Yanked ( s) => IndexSummary :: Yanked ( f ( s) ) ,
165169 IndexSummary :: Offline ( s) => IndexSummary :: Offline ( f ( s) ) ,
166170 IndexSummary :: Unsupported ( s, v) => IndexSummary :: Unsupported ( f ( s) , v. clone ( ) ) ,
171+ IndexSummary :: Invalid ( s) => IndexSummary :: Invalid ( f ( s) ) ,
167172 }
168173 }
169174
170175 /// Extract the package id from any variant
171176 pub fn package_id ( & self ) -> PackageId {
172- match self {
173- IndexSummary :: Candidate ( sum)
174- | IndexSummary :: Yanked ( sum)
175- | IndexSummary :: Offline ( sum)
176- | IndexSummary :: Unsupported ( sum, _) => sum. package_id ( ) ,
177- }
177+ self . as_summary ( ) . package_id ( )
178178 }
179179
180180 /// Returns `true` if the index summary is [`Yanked`].
@@ -259,8 +259,52 @@ pub struct IndexPackage<'a> {
259259 pub v : Option < u32 > ,
260260}
261261
262- /// A dependency as encoded in the [`IndexPackage`] index JSON.
262+ impl IndexPackage < ' _ > {
263+ fn to_summary ( & self , source_id : SourceId ) -> CargoResult < Summary > {
264+ // ****CAUTION**** Please be extremely careful with returning errors, see
265+ // `IndexSummary::parse` for details
266+ let pkgid = PackageId :: new ( self . name . into ( ) , self . vers . clone ( ) , source_id) ;
267+ let deps = self
268+ . deps
269+ . iter ( )
270+ . map ( |dep| dep. clone ( ) . into_dep ( source_id) )
271+ . collect :: < CargoResult < Vec < _ > > > ( ) ?;
272+ let mut features = self . features . clone ( ) ;
273+ if let Some ( features2) = & self . features2 {
274+ for ( name, values) in features2 {
275+ features. entry ( * name) . or_default ( ) . extend ( values) ;
276+ }
277+ }
278+ let mut summary = Summary :: new (
279+ pkgid,
280+ deps,
281+ & features,
282+ self . links ,
283+ self . rust_version . clone ( ) ,
284+ ) ?;
285+ summary. set_checksum ( self . cksum . clone ( ) ) ;
286+ Ok ( summary)
287+ }
288+ }
289+
263290#[ derive( Deserialize , Serialize ) ]
291+ struct IndexPackageMinimum {
292+ name : InternedString ,
293+ vers : Version ,
294+ }
295+
296+ #[ derive( Deserialize , Serialize , Default ) ]
297+ struct IndexPackageRustVersion {
298+ rust_version : Option < RustVersion > ,
299+ }
300+
301+ #[ derive( Deserialize , Serialize , Default ) ]
302+ struct IndexPackageV {
303+ v : Option < u32 > ,
304+ }
305+
306+ /// A dependency as encoded in the [`IndexPackage`] index JSON.
307+ #[ derive( Deserialize , Serialize , Clone ) ]
264308pub struct RegistryDependency < ' a > {
265309 /// Name of the dependency. If the dependency is renamed, the original
266310 /// would be stored in [`RegistryDependency::package`].
@@ -706,32 +750,45 @@ impl IndexSummary {
706750 // between different versions that understand the index differently.
707751 // Make sure to consider the INDEX_V_MAX and CURRENT_CACHE_VERSION
708752 // values carefully when making changes here.
709- let IndexPackage {
710- name,
711- vers,
712- cksum,
713- deps,
714- mut features,
715- features2,
716- yanked,
717- links,
718- rust_version,
719- v,
720- } = serde_json:: from_slice ( line) ?;
721- let v = v. unwrap_or ( 1 ) ;
722- tracing:: trace!( "json parsed registry {}/{}" , name, vers) ;
723- let pkgid = PackageId :: new ( name. into ( ) , vers. clone ( ) , source_id) ;
724- let deps = deps
725- . into_iter ( )
726- . map ( |dep| dep. into_dep ( source_id) )
727- . collect :: < CargoResult < Vec < _ > > > ( ) ?;
728- if let Some ( features2) = features2 {
729- for ( name, values) in features2 {
730- features. entry ( name) . or_default ( ) . extend ( values) ;
753+ let index_summary = ( || {
754+ let index = serde_json:: from_slice :: < IndexPackage < ' _ > > ( line) ?;
755+ let summary = index. to_summary ( source_id) ?;
756+ Ok ( ( index, summary) )
757+ } ) ( ) ;
758+ let ( index, summary, valid) = match index_summary {
759+ Ok ( ( index, summary) ) => ( index, summary, true ) ,
760+ Err ( err) => {
761+ let Ok ( IndexPackageMinimum { name, vers } ) =
762+ serde_json:: from_slice :: < IndexPackageMinimum > ( line)
763+ else {
764+ // If we can't recover, prefer the original error
765+ return Err ( err) ;
766+ } ;
767+ tracing:: info!(
768+ "recoverying from failed parse of registry package {name}@{vers}: {err}"
769+ ) ;
770+ let IndexPackageRustVersion { rust_version } =
771+ serde_json:: from_slice :: < IndexPackageRustVersion > ( line) . unwrap_or_default ( ) ;
772+ let IndexPackageV { v } =
773+ serde_json:: from_slice :: < IndexPackageV > ( line) . unwrap_or_default ( ) ;
774+ let index = IndexPackage {
775+ name,
776+ vers,
777+ rust_version,
778+ v,
779+ deps : Default :: default ( ) ,
780+ features : Default :: default ( ) ,
781+ features2 : Default :: default ( ) ,
782+ cksum : Default :: default ( ) ,
783+ yanked : Default :: default ( ) ,
784+ links : Default :: default ( ) ,
785+ } ;
786+ let summary = index. to_summary ( source_id) ?;
787+ ( index, summary, false )
731788 }
732- }
733- let mut summary = Summary :: new ( pkgid , deps , & features , links , rust_version ) ? ;
734- summary . set_checksum ( cksum ) ;
789+ } ;
790+ let v = index . v . unwrap_or ( 1 ) ;
791+ tracing :: trace! ( "json parsed registry {}/{}" , index . name , index . vers ) ;
735792
736793 let v_max = if bindeps {
737794 INDEX_V_MAX + 1
@@ -741,7 +798,9 @@ impl IndexSummary {
741798
742799 if v_max < v {
743800 Ok ( IndexSummary :: Unsupported ( summary, v) )
744- } else if yanked. unwrap_or ( false ) {
801+ } else if !valid {
802+ Ok ( IndexSummary :: Invalid ( summary) )
803+ } else if index. yanked . unwrap_or ( false ) {
745804 Ok ( IndexSummary :: Yanked ( summary) )
746805 } else {
747806 Ok ( IndexSummary :: Candidate ( summary) )
0 commit comments