@@ -8,6 +8,7 @@ use crate::sources::{GitSource, PathSource, RegistrySource};
8
8
use crate :: util:: interning:: InternedString ;
9
9
use crate :: util:: { context, CanonicalUrl , CargoResult , GlobalContext , IntoUrl } ;
10
10
use anyhow:: Context as _;
11
+ use cargo_util_schemas:: core:: PatchInfo ;
11
12
use serde:: de;
12
13
use serde:: ser;
13
14
use std:: cmp:: { self , Ordering } ;
@@ -176,6 +177,14 @@ impl SourceId {
176
177
let url = url. into_url ( ) ?;
177
178
SourceId :: new ( SourceKind :: Path , url, None )
178
179
}
180
+ "patched" => {
181
+ let mut url = url. into_url ( ) ?;
182
+ let patch_info = PatchInfo :: from_query ( url. query_pairs ( ) )
183
+ . with_context ( || format ! ( "parse `{url}`" ) ) ?;
184
+ url. set_fragment ( None ) ;
185
+ url. set_query ( None ) ;
186
+ SourceId :: for_patches ( SourceId :: from_url ( url. as_str ( ) ) ?, patch_info)
187
+ }
179
188
kind => Err ( anyhow:: format_err!( "unsupported source protocol: {}" , kind) ) ,
180
189
}
181
190
}
@@ -245,6 +254,16 @@ impl SourceId {
245
254
SourceId :: new ( SourceKind :: Directory , url, None )
246
255
}
247
256
257
+ pub fn for_patches ( orig_source_id : SourceId , patch_info : PatchInfo ) -> CargoResult < SourceId > {
258
+ let url = orig_source_id. as_encoded_url ( ) ;
259
+ // `Url::set_scheme` disallow conversions between non-special and speicial schemes,
260
+ // so parse the url from string again.
261
+ let url = format ! ( "patched+{url}" )
262
+ . parse ( )
263
+ . with_context ( || format ! ( "cannot set patched scheme on `{url}`" ) ) ?;
264
+ SourceId :: new ( SourceKind :: Patched ( patch_info) , url, None )
265
+ }
266
+
248
267
/// Returns the `SourceId` corresponding to the main repository.
249
268
///
250
269
/// This is the main cargo registry by default, but it can be overridden in
@@ -666,7 +685,13 @@ impl fmt::Display for SourceId {
666
685
}
667
686
SourceKind :: LocalRegistry => write ! ( f, "registry `{}`" , url_display( & self . inner. url) ) ,
668
687
SourceKind :: Directory => write ! ( f, "dir {}" , url_display( & self . inner. url) ) ,
669
- SourceKind :: Patched ( _) => todo ! ( ) ,
688
+ SourceKind :: Patched ( ref patch_info) => {
689
+ let n = patch_info. patches ( ) . len ( ) ;
690
+ let plural = if n == 1 { "" } else { "s" } ;
691
+ let name = patch_info. name ( ) ;
692
+ let version = patch_info. version ( ) ;
693
+ write ! ( f, "{name}@{version} with {n} patch file{plural}" )
694
+ }
670
695
}
671
696
}
672
697
}
@@ -732,6 +757,14 @@ impl<'a> fmt::Display for SourceIdAsUrl<'a> {
732
757
write ! ( f, "#{}" , precise) ?;
733
758
}
734
759
}
760
+
761
+ if let SourceIdInner {
762
+ kind : SourceKind :: Patched ( patch_info) ,
763
+ ..
764
+ } = & self . inner
765
+ {
766
+ write ! ( f, "?{}" , patch_info. as_query( ) ) ?;
767
+ }
735
768
Ok ( ( ) )
736
769
}
737
770
}
@@ -808,6 +841,8 @@ mod tests {
808
841
use std:: hash:: Hasher ;
809
842
use std:: path:: Path ;
810
843
844
+ use cargo_util_schemas:: core:: PatchInfo ;
845
+
811
846
let gen_hash = |source_id : SourceId | {
812
847
let mut hasher = std:: collections:: hash_map:: DefaultHasher :: new ( ) ;
813
848
source_id. stable_hash ( Path :: new ( "/tmp/ws" ) , & mut hasher) ;
@@ -852,6 +887,12 @@ mod tests {
852
887
let source_id = SourceId :: for_directory ( path) . unwrap ( ) ;
853
888
assert_eq ! ( gen_hash( source_id) , 17459999773908528552 ) ;
854
889
assert_eq ! ( crate :: util:: hex:: short_hash( & source_id) , "6568fe2c2fab5bfe" ) ;
890
+
891
+ let patch_info = PatchInfo :: new ( "foo" . into ( ) , "1.0.0" . into ( ) , vec ! [ path. into( ) ] ) ;
892
+ let registry_source_id = SourceId :: for_registry ( & url) . unwrap ( ) ;
893
+ let source_id = SourceId :: for_patches ( registry_source_id, patch_info) . unwrap ( ) ;
894
+ assert_eq ! ( gen_hash( source_id) , 10476212805277277232 ) ;
895
+ assert_eq ! ( crate :: util:: hex:: short_hash( & source_id) , "45f3b913ab447282" ) ;
855
896
}
856
897
857
898
#[ test]
0 commit comments