@@ -3,7 +3,8 @@ use crate::sources::registry::CRATES_IO_HTTP_INDEX;
3
3
use crate :: sources:: source:: Source ;
4
4
use crate :: sources:: { DirectorySource , CRATES_IO_DOMAIN , CRATES_IO_INDEX , CRATES_IO_REGISTRY } ;
5
5
use crate :: sources:: { GitSource , PathSource , RegistrySource } ;
6
- use crate :: util:: { config, CanonicalUrl , CargoResult , Config , IntoUrl , ToSemver } ;
6
+ use crate :: util:: interning:: InternedString ;
7
+ use crate :: util:: { config, CanonicalUrl , CargoResult , Config , IntoUrl } ;
7
8
use anyhow:: Context ;
8
9
use serde:: de;
9
10
use serde:: ser;
@@ -50,14 +51,37 @@ struct SourceIdInner {
50
51
/// The source kind.
51
52
kind : SourceKind ,
52
53
/// For example, the exact Git revision of the specified branch for a Git Source.
53
- precise : Option < String > ,
54
+ precise : Option < Precise > ,
54
55
/// Name of the remote registry.
55
56
///
56
57
/// WARNING: this is not always set when the name is not known,
57
58
/// e.g. registry coming from `--index` or Cargo.lock
58
59
registry_key : Option < KeyOf > ,
59
60
}
60
61
62
+ #[ derive( Eq , PartialEq , Clone , Debug , Hash ) ]
63
+ enum Precise {
64
+ Locked ,
65
+ Updated {
66
+ name : InternedString ,
67
+ from : semver:: Version ,
68
+ to : semver:: Version ,
69
+ } ,
70
+ GitUrlFragment ( String ) ,
71
+ }
72
+
73
+ impl fmt:: Display for Precise {
74
+ fn fmt ( & self , f : & mut Formatter < ' _ > ) -> fmt:: Result {
75
+ match self {
76
+ Precise :: Locked => "locked" . fmt ( f) ,
77
+ Precise :: Updated { name, from, to } => {
78
+ write ! ( f, "{name}={from}->{to}" )
79
+ }
80
+ Precise :: GitUrlFragment ( s) => s. fmt ( f) ,
81
+ }
82
+ }
83
+ }
84
+
61
85
/// The possible kinds of code source.
62
86
/// Along with [`SourceIdInner`], this fully defines the source.
63
87
#[ derive( Debug , Clone , PartialEq , Eq , Hash ) ]
@@ -178,17 +202,15 @@ impl SourceId {
178
202
let precise = url. fragment ( ) . map ( |s| s. to_owned ( ) ) ;
179
203
url. set_fragment ( None ) ;
180
204
url. set_query ( None ) ;
181
- Ok ( SourceId :: for_git ( & url, reference) ?. with_precise ( precise) )
205
+ Ok ( SourceId :: for_git ( & url, reference) ?. with_git_precise ( precise) )
182
206
}
183
207
"registry" => {
184
208
let url = url. into_url ( ) ?;
185
- Ok ( SourceId :: new ( SourceKind :: Registry , url, None ) ?
186
- . with_precise ( Some ( "locked" . to_string ( ) ) ) )
209
+ Ok ( SourceId :: new ( SourceKind :: Registry , url, None ) ?. with_locked_precise ( ) )
187
210
}
188
211
"sparse" => {
189
212
let url = string. into_url ( ) ?;
190
- Ok ( SourceId :: new ( SourceKind :: SparseRegistry , url, None ) ?
191
- . with_precise ( Some ( "locked" . to_string ( ) ) ) )
213
+ Ok ( SourceId :: new ( SourceKind :: SparseRegistry , url, None ) ?. with_locked_precise ( ) )
192
214
}
193
215
"path" => {
194
216
let url = url. into_url ( ) ?;
@@ -332,10 +354,10 @@ impl SourceId {
332
354
pub fn display_registry_name ( self ) -> String {
333
355
if let Some ( key) = self . inner . registry_key . as_ref ( ) . map ( |k| k. key ( ) ) {
334
356
key. into ( )
335
- } else if self . precise ( ) . is_some ( ) {
357
+ } else if self . has_precise ( ) {
336
358
// We remove `precise` here to retrieve an permissive version of
337
359
// `SourceIdInner`, which may contain the registry name.
338
- self . with_precise ( None ) . display_registry_name ( )
360
+ self . without_precise ( ) . display_registry_name ( )
339
361
} else {
340
362
url_display ( self . url ( ) )
341
363
}
@@ -444,37 +466,81 @@ impl SourceId {
444
466
}
445
467
}
446
468
447
- /// Gets the value of the precise field.
448
- pub fn precise ( self ) -> Option < & ' static str > {
449
- self . inner . precise . as_deref ( )
469
+ /// Check if the precise data field has bean set
470
+ pub fn has_precise ( self ) -> bool {
471
+ self . inner . precise . is_some ( )
472
+ }
473
+
474
+ /// Check if the precise data field has bean set to "locked"
475
+ pub fn has_locked_precise ( self ) -> bool {
476
+ self . inner . precise == Some ( Precise :: Locked )
477
+ }
478
+
479
+ /// Check if two sources have the same precise data field
480
+ pub fn has_same_precise_as ( self , other : Self ) -> bool {
481
+ self . inner . precise == other. inner . precise
450
482
}
451
483
452
484
/// Check if the precise data field stores information for this `name`
453
485
/// from a call to [SourceId::with_precise_registry_version].
454
486
///
455
487
/// If so return the version currently in the lock file and the version to be updated to.
456
- /// If specified, our own source will have a precise version listed of the form
457
- // `<pkg>=<p_req>-><f_req>` where `<pkg>` is the name of a crate on
458
- // this source, `<p_req>` is the version installed and `<f_req>` is the
459
- // version requested (argument to `--precise`).
460
488
pub fn precise_registry_version (
461
489
self ,
462
- name : & str ,
463
- ) -> Option < ( semver:: Version , semver:: Version ) > {
464
- self . inner
465
- . precise
466
- . as_deref ( )
467
- . and_then ( |p| p. strip_prefix ( name) ?. strip_prefix ( '=' ) )
468
- . map ( |p| {
469
- let ( current, requested) = p. split_once ( "->" ) . unwrap ( ) ;
470
- ( current. to_semver ( ) . unwrap ( ) , requested. to_semver ( ) . unwrap ( ) )
471
- } )
490
+ pkg : & str ,
491
+ ) -> Option < ( & semver:: Version , & semver:: Version ) > {
492
+ match & self . inner . precise {
493
+ Some ( Precise :: Updated { name, from, to } ) if name == pkg => Some ( ( from, to) ) ,
494
+ _ => None ,
495
+ }
496
+ }
497
+
498
+ pub fn precise_git_fragment ( self ) -> Option < & ' static str > {
499
+ match & self . inner . precise {
500
+ Some ( Precise :: GitUrlFragment ( s) ) => Some ( & s[ ..8 ] ) ,
501
+ _ => None ,
502
+ }
503
+ }
504
+
505
+ pub fn precise_git_oid ( self ) -> CargoResult < Option < git2:: Oid > > {
506
+ Ok ( match self . inner . precise . as_ref ( ) {
507
+ Some ( Precise :: GitUrlFragment ( s) ) => {
508
+ Some ( git2:: Oid :: from_str ( s) . with_context ( || {
509
+ format ! ( "precise value for git is not a git revision: {}" , s)
510
+ } ) ?)
511
+ }
512
+ _ => None ,
513
+ } )
472
514
}
473
515
474
516
/// Creates a new `SourceId` from this source with the given `precise`.
475
- pub fn with_precise ( self , v : Option < String > ) -> SourceId {
517
+ pub fn with_git_precise ( self , fragment : Option < String > ) -> SourceId {
476
518
SourceId :: wrap ( SourceIdInner {
477
- precise : v,
519
+ precise : fragment. map ( |f| Precise :: GitUrlFragment ( f) ) ,
520
+ ..( * self . inner ) . clone ( )
521
+ } )
522
+ }
523
+
524
+ /// Creates a new `SourceId` from this source without a `precise`.
525
+ pub fn without_precise ( self ) -> SourceId {
526
+ SourceId :: wrap ( SourceIdInner {
527
+ precise : None ,
528
+ ..( * self . inner ) . clone ( )
529
+ } )
530
+ }
531
+
532
+ /// Creates a new `SourceId` from this source without a `precise`.
533
+ pub fn with_locked_precise ( self ) -> SourceId {
534
+ SourceId :: wrap ( SourceIdInner {
535
+ precise : Some ( Precise :: Locked ) ,
536
+ ..( * self . inner ) . clone ( )
537
+ } )
538
+ }
539
+
540
+ /// Creates a new `SourceId` from this source with the `precise` from some other `SourceId`.
541
+ pub fn with_precise_from ( self , v : Self ) -> SourceId {
542
+ SourceId :: wrap ( SourceIdInner {
543
+ precise : v. inner . precise . clone ( ) ,
478
544
..( * self . inner ) . clone ( )
479
545
} )
480
546
}
@@ -487,13 +553,21 @@ impl SourceId {
487
553
/// The data can be read with [SourceId::precise_registry_version]
488
554
pub fn with_precise_registry_version (
489
555
self ,
490
- name : impl fmt :: Display ,
491
- version : & semver:: Version ,
556
+ name : InternedString ,
557
+ version : semver:: Version ,
492
558
precise : & str ,
493
559
) -> CargoResult < SourceId > {
494
- semver:: Version :: parse ( precise)
560
+ let precise = semver:: Version :: parse ( precise)
495
561
. with_context ( || format ! ( "invalid version format for precise version `{precise}`" ) ) ?;
496
- Ok ( self . with_precise ( Some ( format ! ( "{}={}->{}" , name, version, precise) ) ) )
562
+
563
+ Ok ( SourceId :: wrap ( SourceIdInner {
564
+ precise : Some ( Precise :: Updated {
565
+ name,
566
+ from : version,
567
+ to : precise,
568
+ } ) ,
569
+ ..( * self . inner ) . clone ( )
570
+ } ) )
497
571
}
498
572
499
573
/// Returns `true` if the remote registry is the standard <https://crates.io>.
@@ -625,7 +699,8 @@ impl fmt::Display for SourceId {
625
699
write ! ( f, "?{}" , pretty) ?;
626
700
}
627
701
628
- if let Some ( ref s) = self . inner . precise {
702
+ if let Some ( s) = & self . inner . precise {
703
+ let s = s. to_string ( ) ;
629
704
let len = cmp:: min ( s. len ( ) , 8 ) ;
630
705
write ! ( f, "#{}" , & s[ ..len] ) ?;
631
706
}
0 commit comments