42
42
//! Listed from most recent to oldest, these are some of the changes we've made
43
43
//! to `Cargo.lock`'s serialization format:
44
44
//!
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
+ //!
45
52
//! * The entries in `dependencies` arrays have been shortened and the
46
53
//! `checksum` field now shows up directly in `[[package]]` instead of always
47
54
//! at the end of the file. The goal of this change was to ideally reduce
89
96
//! special fashion to make sure we have strict control over the on-disk
90
97
//! format.
91
98
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;
96
105
use log:: debug;
97
106
use serde:: de;
98
107
use serde:: ser;
99
108
use 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 ;
107
112
108
113
/// The `Cargo.lock` structure.
109
114
#[ derive( Serialize , Deserialize , Debug ) ]
110
115
pub struct EncodableResolve {
116
+ version : Option < u32 > ,
111
117
package : Option < Vec < EncodableDependency > > ,
112
118
/// `root` is optional to allow backward compatibility.
113
119
root : Option < EncodableDependency > ,
@@ -136,8 +142,19 @@ impl EncodableResolve {
136
142
let path_deps = build_path_deps ( ws) ;
137
143
let mut checksums = HashMap :: new ( ) ;
138
144
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
+ } ;
141
158
142
159
let packages = {
143
160
let mut packages = self . package . unwrap_or_default ( ) ;
@@ -176,7 +193,7 @@ impl EncodableResolve {
176
193
// that here, and we also bump our version up to 2 since V1
177
194
// didn't ever encode this field.
178
195
if let Some ( cksum) = & pkg. checksum {
179
- version = ResolveVersion :: V2 ;
196
+ version = version . max ( ResolveVersion :: V2 ) ;
180
197
checksums. insert ( id, Some ( cksum. clone ( ) ) ) ;
181
198
}
182
199
@@ -213,7 +230,7 @@ impl EncodableResolve {
213
230
let by_source = match & enc_id. version {
214
231
Some ( version) => by_version. get ( version) ?,
215
232
None => {
216
- version = ResolveVersion :: V2 ;
233
+ version = version . max ( ResolveVersion :: V2 ) ;
217
234
if by_version. len ( ) == 1 {
218
235
by_version. values ( ) . next ( ) . unwrap ( )
219
236
} else {
@@ -245,7 +262,7 @@ impl EncodableResolve {
245
262
// the lock file
246
263
} else if by_source. len ( ) == 1 {
247
264
let id = by_source. values ( ) . next ( ) . unwrap ( ) ;
248
- version = ResolveVersion :: V2 ;
265
+ version = version . max ( ResolveVersion :: V2 ) ;
249
266
Some ( * id)
250
267
251
268
// ... and failing that we probably had a bad git merge of
@@ -317,7 +334,7 @@ impl EncodableResolve {
317
334
// If `checksum` was listed in `[metadata]` but we were previously
318
335
// listed as `V2` then assume some sort of bad git merge happened, so
319
336
// 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 {
321
338
checksums. drain ( ) ;
322
339
}
323
340
for k in to_remove {
@@ -539,13 +556,13 @@ impl<'a> ser::Serialize for Resolve {
539
556
540
557
let mut metadata = self . metadata ( ) . clone ( ) ;
541
558
542
- if * self . version ( ) == ResolveVersion :: V1 {
559
+ if self . version ( ) == ResolveVersion :: V1 {
543
560
for & id in ids. iter ( ) . filter ( |id| !id. source_id ( ) . is_path ( ) ) {
544
561
let checksum = match self . checksums ( ) [ & id] {
545
562
Some ( ref s) => & s[ ..] ,
546
563
None => "<none>" ,
547
564
} ;
548
- let id = encodable_package_id ( id, & state) ;
565
+ let id = encodable_package_id ( id, & state, self . version ( ) ) ;
549
566
metadata. insert ( format ! ( "checksum {}" , id. to_string( ) ) , checksum. to_string ( ) ) ;
550
567
}
551
568
}
@@ -566,9 +583,10 @@ impl<'a> ser::Serialize for Resolve {
566
583
source : encode_source ( id. source_id ( ) ) ,
567
584
dependencies : None ,
568
585
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
572
590
} ,
573
591
} )
574
592
. collect ( ) ,
@@ -578,6 +596,10 @@ impl<'a> ser::Serialize for Resolve {
578
596
root : None ,
579
597
metadata,
580
598
patch,
599
+ version : match self . version ( ) {
600
+ ResolveVersion :: V3 => Some ( 1 ) ,
601
+ ResolveVersion :: V2 | ResolveVersion :: V1 => None ,
602
+ } ,
581
603
}
582
604
. serialize ( s)
583
605
}
@@ -589,7 +611,7 @@ pub struct EncodeState<'a> {
589
611
590
612
impl < ' a > EncodeState < ' a > {
591
613
pub fn new ( resolve : & ' a Resolve ) -> EncodeState < ' a > {
592
- let counts = if * resolve. version ( ) = = ResolveVersion :: V2 {
614
+ let counts = if resolve. version ( ) > = ResolveVersion :: V2 {
593
615
let mut map = HashMap :: new ( ) ;
594
616
for id in resolve. iter ( ) {
595
617
let slot = map
@@ -613,11 +635,14 @@ fn encodable_resolve_node(
613
635
state : & EncodeState < ' _ > ,
614
636
) -> EncodableDependency {
615
637
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
+ ) ,
617
642
None => {
618
643
let mut deps = resolve
619
644
. deps_not_replaced ( id)
620
- . map ( |( id, _) | encodable_package_id ( id, state) )
645
+ . map ( |( id, _) | encodable_package_id ( id, state, resolve . version ( ) ) )
621
646
. collect :: < Vec < _ > > ( ) ;
622
647
deps. sort ( ) ;
623
648
( None , Some ( deps) )
@@ -630,16 +655,30 @@ fn encodable_resolve_node(
630
655
source : encode_source ( id. source_id ( ) ) ,
631
656
dependencies : deps,
632
657
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
636
662
} ,
637
663
}
638
664
}
639
665
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 {
641
671
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 ) ) ;
643
682
if let Some ( counts) = & state. counts {
644
683
let version_counts = & counts[ & id. name ( ) ] ;
645
684
if version_counts[ & id. version ( ) ] == 1 {
0 commit comments