4242//! Listed from most recent to oldest, these are some of the changes we've made
4343//! to `Cargo.lock`'s serialization format:
4444//!
45+ //! * A `version` marker is now at the top of the lock file which is a way for
46+ //! super-old Cargos (at least since this was implemented) to give a formal
47+ //! error if they see a lock file from a super-future Cargo. Additionally as
48+ //! part of this change the encoding of `git` dependencies in lock files
49+ //! changed where `branch = "master"` is now encoded with `branch=master`
50+ //! instead of with nothing at all.
51+ //!
4552//! * The entries in `dependencies` arrays have been shortened and the
4653//! `checksum` field now shows up directly in `[[package]]` instead of always
4754//! at the end of the file. The goal of this change was to ideally reduce
8996//! special fashion to make sure we have strict control over the on-disk
9097//! format.
9198
92- use std:: collections:: { BTreeMap , HashMap , HashSet } ;
93- use std:: fmt;
94- use std:: str:: FromStr ;
95-
99+ use super :: { Resolve , ResolveVersion } ;
100+ use crate :: core:: { Dependency , GitReference , Package , PackageId , SourceId , Workspace } ;
101+ use crate :: util:: errors:: { CargoResult , CargoResultExt } ;
102+ use crate :: util:: interning:: InternedString ;
103+ use crate :: util:: { internal, Graph } ;
104+ use anyhow:: bail;
96105use log:: debug;
97106use serde:: de;
98107use serde:: ser;
99108use serde:: { Deserialize , Serialize } ;
100-
101- use crate :: core:: { Dependency , Package , PackageId , SourceId , Workspace } ;
102- use crate :: util:: errors:: { CargoResult , CargoResultExt } ;
103- use crate :: util:: interning:: InternedString ;
104- use crate :: util:: { internal, Graph } ;
105-
106- use super :: { Resolve , ResolveVersion } ;
109+ use std:: collections:: { BTreeMap , HashMap , HashSet } ;
110+ use std:: fmt;
111+ use std:: str:: FromStr ;
107112
108113/// The `Cargo.lock` structure.
109114#[ derive( Serialize , Deserialize , Debug ) ]
110115pub struct EncodableResolve {
116+ version : Option < u32 > ,
111117 package : Option < Vec < EncodableDependency > > ,
112118 /// `root` is optional to allow backward compatibility.
113119 root : Option < EncodableDependency > ,
@@ -136,8 +142,19 @@ impl EncodableResolve {
136142 let path_deps = build_path_deps ( ws) ;
137143 let mut checksums = HashMap :: new ( ) ;
138144
139- // We assume an older format is being parsed until we see so otherwise.
140- let mut version = ResolveVersion :: V1 ;
145+ let mut version = match self . version {
146+ Some ( 1 ) => ResolveVersion :: V3 ,
147+ Some ( n) => bail ! (
148+ "lock file version `{}` was found, but this version of Cargo \
149+ does not understand this lock file, perhaps Cargo needs \
150+ to be updated?",
151+ n,
152+ ) ,
153+ // Historically Cargo did not have a version indicator in lock
154+ // files, so this could either be the V1 or V2 encoding. We assume
155+ // an older format is being parsed until we see so otherwise.
156+ None => ResolveVersion :: V1 ,
157+ } ;
141158
142159 let packages = {
143160 let mut packages = self . package . unwrap_or_default ( ) ;
@@ -176,7 +193,7 @@ impl EncodableResolve {
176193 // that here, and we also bump our version up to 2 since V1
177194 // didn't ever encode this field.
178195 if let Some ( cksum) = & pkg. checksum {
179- version = ResolveVersion :: V2 ;
196+ version = version . max ( ResolveVersion :: V2 ) ;
180197 checksums. insert ( id, Some ( cksum. clone ( ) ) ) ;
181198 }
182199
@@ -213,7 +230,7 @@ impl EncodableResolve {
213230 let by_source = match & enc_id. version {
214231 Some ( version) => by_version. get ( version) ?,
215232 None => {
216- version = ResolveVersion :: V2 ;
233+ version = version . max ( ResolveVersion :: V2 ) ;
217234 if by_version. len ( ) == 1 {
218235 by_version. values ( ) . next ( ) . unwrap ( )
219236 } else {
@@ -245,7 +262,7 @@ impl EncodableResolve {
245262 // the lock file
246263 } else if by_source. len ( ) == 1 {
247264 let id = by_source. values ( ) . next ( ) . unwrap ( ) ;
248- version = ResolveVersion :: V2 ;
265+ version = version . max ( ResolveVersion :: V2 ) ;
249266 Some ( * id)
250267
251268 // ... and failing that we probably had a bad git merge of
@@ -317,7 +334,7 @@ impl EncodableResolve {
317334 // If `checksum` was listed in `[metadata]` but we were previously
318335 // listed as `V2` then assume some sort of bad git merge happened, so
319336 // discard all checksums and let's regenerate them later.
320- if !to_remove. is_empty ( ) && version = = ResolveVersion :: V2 {
337+ if !to_remove. is_empty ( ) && version > = ResolveVersion :: V2 {
321338 checksums. drain ( ) ;
322339 }
323340 for k in to_remove {
@@ -539,13 +556,13 @@ impl<'a> ser::Serialize for Resolve {
539556
540557 let mut metadata = self . metadata ( ) . clone ( ) ;
541558
542- if * self . version ( ) == ResolveVersion :: V1 {
559+ if self . version ( ) == ResolveVersion :: V1 {
543560 for & id in ids. iter ( ) . filter ( |id| !id. source_id ( ) . is_path ( ) ) {
544561 let checksum = match self . checksums ( ) [ & id] {
545562 Some ( ref s) => & s[ ..] ,
546563 None => "<none>" ,
547564 } ;
548- let id = encodable_package_id ( id, & state) ;
565+ let id = encodable_package_id ( id, & state, self . version ( ) ) ;
549566 metadata. insert ( format ! ( "checksum {}" , id. to_string( ) ) , checksum. to_string ( ) ) ;
550567 }
551568 }
@@ -566,9 +583,10 @@ impl<'a> ser::Serialize for Resolve {
566583 source : encode_source ( id. source_id ( ) ) ,
567584 dependencies : None ,
568585 replace : None ,
569- checksum : match self . version ( ) {
570- ResolveVersion :: V2 => self . checksums ( ) . get ( id) . and_then ( |x| x. clone ( ) ) ,
571- ResolveVersion :: V1 => None ,
586+ checksum : if self . version ( ) >= ResolveVersion :: V2 {
587+ self . checksums ( ) . get ( id) . and_then ( |x| x. clone ( ) )
588+ } else {
589+ None
572590 } ,
573591 } )
574592 . collect ( ) ,
@@ -578,6 +596,10 @@ impl<'a> ser::Serialize for Resolve {
578596 root : None ,
579597 metadata,
580598 patch,
599+ version : match self . version ( ) {
600+ ResolveVersion :: V3 => Some ( 1 ) ,
601+ ResolveVersion :: V2 | ResolveVersion :: V1 => None ,
602+ } ,
581603 }
582604 . serialize ( s)
583605 }
@@ -589,7 +611,7 @@ pub struct EncodeState<'a> {
589611
590612impl < ' a > EncodeState < ' a > {
591613 pub fn new ( resolve : & ' a Resolve ) -> EncodeState < ' a > {
592- let counts = if * resolve. version ( ) = = ResolveVersion :: V2 {
614+ let counts = if resolve. version ( ) > = ResolveVersion :: V2 {
593615 let mut map = HashMap :: new ( ) ;
594616 for id in resolve. iter ( ) {
595617 let slot = map
@@ -613,11 +635,14 @@ fn encodable_resolve_node(
613635 state : & EncodeState < ' _ > ,
614636) -> EncodableDependency {
615637 let ( replace, deps) = match resolve. replacement ( id) {
616- Some ( id) => ( Some ( encodable_package_id ( id, state) ) , None ) ,
638+ Some ( id) => (
639+ Some ( encodable_package_id ( id, state, resolve. version ( ) ) ) ,
640+ None ,
641+ ) ,
617642 None => {
618643 let mut deps = resolve
619644 . deps_not_replaced ( id)
620- . map ( |( id, _) | encodable_package_id ( id, state) )
645+ . map ( |( id, _) | encodable_package_id ( id, state, resolve . version ( ) ) )
621646 . collect :: < Vec < _ > > ( ) ;
622647 deps. sort ( ) ;
623648 ( None , Some ( deps) )
@@ -630,16 +655,30 @@ fn encodable_resolve_node(
630655 source : encode_source ( id. source_id ( ) ) ,
631656 dependencies : deps,
632657 replace,
633- checksum : match resolve. version ( ) {
634- ResolveVersion :: V2 => resolve. checksums ( ) . get ( & id) . and_then ( |s| s. clone ( ) ) ,
635- ResolveVersion :: V1 => None ,
658+ checksum : if resolve. version ( ) >= ResolveVersion :: V2 {
659+ resolve. checksums ( ) . get ( & id) . and_then ( |s| s. clone ( ) )
660+ } else {
661+ None
636662 } ,
637663 }
638664}
639665
640- pub fn encodable_package_id ( id : PackageId , state : & EncodeState < ' _ > ) -> EncodablePackageId {
666+ pub fn encodable_package_id (
667+ id : PackageId ,
668+ state : & EncodeState < ' _ > ,
669+ resolve_version : ResolveVersion ,
670+ ) -> EncodablePackageId {
641671 let mut version = Some ( id. version ( ) . to_string ( ) ) ;
642- let mut source = encode_source ( id. source_id ( ) ) . map ( |s| s. with_precise ( None ) ) ;
672+ let mut id_to_encode = id. source_id ( ) ;
673+ if resolve_version <= ResolveVersion :: V2 {
674+ if let Some ( GitReference :: Branch ( b) ) = id_to_encode. git_reference ( ) {
675+ if b == "master" {
676+ id_to_encode =
677+ SourceId :: for_git ( id_to_encode. url ( ) , GitReference :: DefaultBranch ) . unwrap ( ) ;
678+ }
679+ }
680+ }
681+ let mut source = encode_source ( id_to_encode) . map ( |s| s. with_precise ( None ) ) ;
643682 if let Some ( counts) = & state. counts {
644683 let version_counts = & counts[ & id. name ( ) ] ;
645684 if version_counts[ & id. version ( ) ] == 1 {
0 commit comments