@@ -117,13 +117,16 @@ use crate::util::errors::CargoResult;
117
117
use crate :: util:: interning:: InternedString ;
118
118
use crate :: util:: { Graph , internal} ;
119
119
use anyhow:: { Context as _, bail} ;
120
+ use cargo_util_schemas:: core:: SourceKind ;
120
121
use serde:: de;
121
122
use serde:: ser;
122
123
use serde:: { Deserialize , Serialize } ;
124
+ use std:: cmp:: Ordering ;
123
125
use std:: collections:: { BTreeMap , HashMap , HashSet } ;
124
126
use std:: fmt;
125
127
use std:: str:: FromStr ;
126
128
use tracing:: debug;
129
+ use url:: Url ;
127
130
128
131
/// The `Cargo.lock` structure.
129
132
#[ derive( Serialize , Deserialize , Debug ) ]
@@ -207,16 +210,18 @@ pub fn into_resolve(
207
210
}
208
211
let id = match pkg
209
212
. source
210
- . as_deref ( )
211
- . or_else ( || get_source_id ( & path_deps, pkg) )
213
+ . as_ref ( )
214
+ . map ( |source| SourceId :: from_url ( & source. source_str ( ) ) )
215
+ . transpose ( ) ?
216
+ . or_else ( || get_source_id ( & path_deps, & pkg) . copied ( ) )
212
217
{
213
218
// We failed to find a local package in the workspace.
214
219
// It must have been removed and should be ignored.
215
220
None => {
216
221
debug ! ( "path dependency now missing {} v{}" , pkg. name, pkg. version) ;
217
222
continue ;
218
223
}
219
- Some ( & source) => PackageId :: try_new ( & pkg. name , & pkg. version , source) ?,
224
+ Some ( source) => PackageId :: try_new ( & pkg. name , & pkg. version , source) ?,
220
225
} ;
221
226
222
227
// If a package has a checksum listed directly on it then record
@@ -274,7 +279,9 @@ pub fn into_resolve(
274
279
// format. That means we have to handle the `None` case a bit more
275
280
// carefully.
276
281
match & enc_id. source {
277
- Some ( source) => by_source. get ( source) . cloned ( ) ,
282
+ Some ( source) => by_source
283
+ . get ( & SourceId :: from_url ( & source. source_str ( ) ) . unwrap ( ) )
284
+ . cloned ( ) ,
278
285
None => {
279
286
// Look through all possible packages ids for this
280
287
// name/version. If there's only one `path` dependency then
@@ -373,10 +380,12 @@ pub fn into_resolve(
373
380
for pkg in resolve. patch . unused {
374
381
let id = match pkg
375
382
. source
376
- . as_deref ( )
377
- . or_else ( || get_source_id ( & path_deps, & pkg) )
383
+ . as_ref ( )
384
+ . map ( |source| SourceId :: from_url ( & source. source_str ( ) ) )
385
+ . transpose ( ) ?
386
+ . or_else ( || get_source_id ( & path_deps, & pkg) . copied ( ) )
378
387
{
379
- Some ( & src) => PackageId :: try_new ( & pkg. name , & pkg. version , src) ?,
388
+ Some ( src) => PackageId :: try_new ( & pkg. name , & pkg. version , src) ?,
380
389
None => continue ,
381
390
} ;
382
391
unused_patches. push ( id) ;
@@ -530,54 +539,58 @@ pub struct EncodableDependency {
530
539
replace : Option < EncodablePackageId > ,
531
540
}
532
541
533
- /// Pretty much equivalent to [`SourceId`] with a different serialization method.
534
- ///
535
- /// The serialization for `SourceId` doesn't do URL encode for parameters.
536
- /// In contrast, this type is aware of that whenever [`ResolveVersion`] allows
537
- /// us to do so (v4 or later).
538
- #[ derive( Debug , PartialOrd , Ord , Clone ) ]
542
+ #[ derive( Debug , Clone ) ]
539
543
pub struct EncodableSourceId {
540
- inner : SourceId ,
541
- /// We don't care about the deserialization of this, as the `url` crate
542
- /// will always decode as the URL was encoded. Only when a [`Resolve`]
543
- /// turns into a [`EncodableResolve`] will it set the value accordingly
544
- /// via [`encodable_source_id`].
545
- encoded : bool ,
544
+ /// Full string of the source
545
+ source_str : String ,
546
+ /// Used for sources ordering
547
+ kind : SourceKind ,
548
+ /// Used for sources ordering
549
+ url : Url ,
546
550
}
547
551
548
552
impl EncodableSourceId {
549
- /// Creates a `EncodableSourceId` that always encodes URL params.
550
- fn new ( inner : SourceId ) -> Self {
551
- Self {
552
- inner,
553
- encoded : true ,
554
- }
553
+ fn new ( source : String ) -> CargoResult < Self > {
554
+ let source_str = source. clone ( ) ;
555
+ let ( kind, url) = source
556
+ . split_once ( '+' )
557
+ . ok_or_else ( || anyhow:: format_err!( "invalid source `{}`" , source_str) ) ?;
558
+
559
+ let url =
560
+ Url :: parse ( url) . map_err ( |s| anyhow:: format_err!( "invalid url `{}`: {}" , url, s) ) ?;
561
+
562
+ let kind = match kind {
563
+ "git" => {
564
+ let reference = GitReference :: from_query ( url. query_pairs ( ) ) ;
565
+ SourceKind :: Git ( reference)
566
+ }
567
+ "registry" => SourceKind :: Registry ,
568
+ "sparse" => SourceKind :: SparseRegistry ,
569
+ "path" => SourceKind :: Path ,
570
+ kind => anyhow:: bail!( "unsupported source protocol: {}" , kind) ,
571
+ } ;
572
+
573
+ Ok ( Self {
574
+ source_str,
575
+ kind,
576
+ url,
577
+ } )
555
578
}
556
579
557
- /// Creates a `EncodableSourceId` that doesn't encode URL params. This is
558
- /// for backward compatibility for order lockfile version.
559
- fn without_url_encoded ( inner : SourceId ) -> Self {
560
- Self {
561
- inner,
562
- encoded : false ,
563
- }
580
+ pub fn kind ( & self ) -> & SourceKind {
581
+ & self . kind
564
582
}
565
583
566
- /// Encodes the inner [`SourceId`] as a URL.
567
- fn as_url ( & self ) -> impl fmt:: Display + ' _ {
568
- if self . encoded {
569
- self . inner . as_encoded_url ( )
570
- } else {
571
- self . inner . as_url ( )
572
- }
584
+ pub fn url ( & self ) -> & Url {
585
+ & self . url
573
586
}
574
- }
575
587
576
- impl std:: ops:: Deref for EncodableSourceId {
577
- type Target = SourceId ;
588
+ pub fn source_str ( & self ) -> & String {
589
+ & self . source_str
590
+ }
578
591
579
- fn deref ( & self ) -> & Self :: Target {
580
- & self . inner
592
+ fn as_url ( & self ) -> impl fmt :: Display + ' _ {
593
+ self . source_str . clone ( )
581
594
}
582
595
}
583
596
@@ -596,28 +609,39 @@ impl<'de> de::Deserialize<'de> for EncodableSourceId {
596
609
D : de:: Deserializer < ' de > ,
597
610
{
598
611
let s = String :: deserialize ( d) ?;
599
- let sid = SourceId :: from_url ( & s) . map_err ( de:: Error :: custom) ?;
600
- Ok ( EncodableSourceId {
601
- inner : sid,
602
- encoded : false ,
603
- } )
612
+ Ok ( EncodableSourceId :: new ( s) . map_err ( de:: Error :: custom) ?)
604
613
}
605
614
}
606
615
607
616
impl std:: hash:: Hash for EncodableSourceId {
608
617
fn hash < H : std:: hash:: Hasher > ( & self , state : & mut H ) {
609
- self . inner . hash ( state)
618
+ self . kind . hash ( state) ;
619
+ self . url . hash ( state) ;
610
620
}
611
621
}
612
622
613
623
impl std:: cmp:: PartialEq for EncodableSourceId {
614
624
fn eq ( & self , other : & Self ) -> bool {
615
- self . inner == other. inner
625
+ self . kind == other. kind && self . url == other . url
616
626
}
617
627
}
618
628
619
629
impl std:: cmp:: Eq for EncodableSourceId { }
620
630
631
+ impl PartialOrd for EncodableSourceId {
632
+ fn partial_cmp ( & self , other : & EncodableSourceId ) -> Option < Ordering > {
633
+ Some ( self . cmp ( other) )
634
+ }
635
+ }
636
+
637
+ impl Ord for EncodableSourceId {
638
+ fn cmp ( & self , other : & EncodableSourceId ) -> Ordering {
639
+ self . kind
640
+ . cmp ( & other. kind )
641
+ . then_with ( || self . url . cmp ( & other. url ) )
642
+ }
643
+ }
644
+
621
645
#[ derive( Debug , PartialOrd , Ord , PartialEq , Eq , Hash , Clone ) ]
622
646
pub struct EncodablePackageId {
623
647
name : String ,
@@ -648,7 +672,7 @@ impl FromStr for EncodablePackageId {
648
672
let source_id = match s. next ( ) {
649
673
Some ( s) => {
650
674
if let Some ( s) = s. strip_prefix ( '(' ) . and_then ( |s| s. strip_suffix ( ')' ) ) {
651
- Some ( SourceId :: from_url ( s ) ?)
675
+ Some ( EncodableSourceId :: new ( s . to_string ( ) ) ?)
652
676
} else {
653
677
anyhow:: bail!( "invalid serialized PackageId" )
654
678
}
@@ -659,8 +683,7 @@ impl FromStr for EncodablePackageId {
659
683
Ok ( EncodablePackageId {
660
684
name : name. to_string ( ) ,
661
685
version : version. map ( |v| v. to_string ( ) ) ,
662
- // Default to url encoded.
663
- source : source_id. map ( EncodableSourceId :: new) ,
686
+ source : source_id,
664
687
} )
665
688
}
666
689
}
@@ -850,10 +873,13 @@ fn encodable_source_id(id: SourceId, version: ResolveVersion) -> Option<Encodabl
850
873
if id. is_path ( ) {
851
874
None
852
875
} else {
853
- Some ( if version >= ResolveVersion :: V4 {
854
- EncodableSourceId :: new ( id)
855
- } else {
856
- EncodableSourceId :: without_url_encoded ( id)
857
- } )
876
+ Some (
877
+ if version >= ResolveVersion :: V4 {
878
+ EncodableSourceId :: new ( id. as_encoded_url ( ) . to_string ( ) )
879
+ } else {
880
+ EncodableSourceId :: new ( id. as_url ( ) . to_string ( ) )
881
+ }
882
+ . expect ( "source ID should have valid URLs" ) ,
883
+ )
858
884
}
859
885
}
0 commit comments