@@ -3,7 +3,8 @@ use crate::sources::registry::CRATES_IO_HTTP_INDEX;
33use crate :: sources:: source:: Source ;
44use crate :: sources:: { DirectorySource , CRATES_IO_DOMAIN , CRATES_IO_INDEX , CRATES_IO_REGISTRY } ;
55use 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 } ;
78use anyhow:: Context ;
89use serde:: de;
910use serde:: ser;
@@ -50,14 +51,37 @@ struct SourceIdInner {
5051 /// The source kind.
5152 kind : SourceKind ,
5253 /// For example, the exact Git revision of the specified branch for a Git Source.
53- precise : Option < String > ,
54+ precise : Option < Precise > ,
5455 /// Name of the remote registry.
5556 ///
5657 /// WARNING: this is not always set when the name is not known,
5758 /// e.g. registry coming from `--index` or Cargo.lock
5859 registry_key : Option < KeyOf > ,
5960}
6061
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+
6185/// The possible kinds of code source.
6286/// Along with [`SourceIdInner`], this fully defines the source.
6387#[ derive( Debug , Clone , PartialEq , Eq , Hash ) ]
@@ -178,17 +202,15 @@ impl SourceId {
178202 let precise = url. fragment ( ) . map ( |s| s. to_owned ( ) ) ;
179203 url. set_fragment ( None ) ;
180204 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) )
182206 }
183207 "registry" => {
184208 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 ( ) )
187210 }
188211 "sparse" => {
189212 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 ( ) )
192214 }
193215 "path" => {
194216 let url = url. into_url ( ) ?;
@@ -335,7 +357,7 @@ impl SourceId {
335357 } else if self . has_precise ( ) {
336358 // We remove `precise` here to retrieve an permissive version of
337359 // `SourceIdInner`, which may contain the registry name.
338- self . with_precise ( None ) . display_registry_name ( )
360+ self . without_precise ( ) . display_registry_name ( )
339361 } else {
340362 url_display ( self . url ( ) )
341363 }
@@ -444,19 +466,14 @@ impl SourceId {
444466 }
445467 }
446468
447- /// Gets the value of the precise field.
448- pub fn precise ( self ) -> Option < & ' static str > {
449- self . inner . precise . as_deref ( )
450- }
451-
452469 /// Check if the precise data field has bean set
453470 pub fn has_precise ( self ) -> bool {
454471 self . inner . precise . is_some ( )
455472 }
456473
457474 /// Check if the precise data field has bean set to "Locked"
458475 pub fn has_locked_precise ( self ) -> bool {
459- self . inner . precise . as_deref ( ) == Some ( " Locked" )
476+ self . inner . precise == Some ( Precise :: Locked )
460477 }
461478
462479 /// Check if two sources have the same precise data field
@@ -468,28 +485,54 @@ impl SourceId {
468485 /// from a call to [SourceId::with_precise_registry_version].
469486 ///
470487 /// If so return the version currently in the lock file and the version to be updated to.
471- /// If specified, our own source will have a precise version listed of the form
472- // `<pkg>=<p_req>-><f_req>` where `<pkg>` is the name of a crate on
473- // this source, `<p_req>` is the version installed and `<f_req>` is the
474- // version requested (argument to `--precise`).
475488 pub fn precise_registry_version (
476489 self ,
477- name : & str ,
478- ) -> Option < ( semver:: Version , semver:: Version ) > {
479- self . inner
480- . precise
481- . as_deref ( )
482- . and_then ( |p| p. strip_prefix ( name) ?. strip_prefix ( '=' ) )
483- . map ( |p| {
484- let ( current, requested) = p. split_once ( "->" ) . unwrap ( ) ;
485- ( current. to_semver ( ) . unwrap ( ) , requested. to_semver ( ) . unwrap ( ) )
486- } )
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+ } )
487514 }
488515
489516 /// Creates a new `SourceId` from this source with the given `precise`.
490- pub fn with_precise ( self , v : Option < String > ) -> SourceId {
517+ pub fn with_git_precise ( self , fragment : Option < String > ) -> SourceId {
518+ SourceId :: wrap ( SourceIdInner {
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 {
491526 SourceId :: wrap ( SourceIdInner {
492- precise : v,
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 ) ,
493536 ..( * self . inner ) . clone ( )
494537 } )
495538 }
@@ -510,13 +553,21 @@ impl SourceId {
510553 /// The data can be read with [SourceId::precise_registry_version]
511554 pub fn with_precise_registry_version (
512555 self ,
513- name : impl fmt :: Display ,
514- version : & semver:: Version ,
556+ name : InternedString ,
557+ version : semver:: Version ,
515558 precise : & str ,
516559 ) -> CargoResult < SourceId > {
517- semver:: Version :: parse ( precise)
560+ let precise = semver:: Version :: parse ( precise)
518561 . with_context ( || format ! ( "invalid version format for precise version `{precise}`" ) ) ?;
519- 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+ } ) )
520571 }
521572
522573 /// Returns `true` if the remote registry is the standard <https://crates.io>.
@@ -648,7 +699,8 @@ impl fmt::Display for SourceId {
648699 write ! ( f, "?{}" , pretty) ?;
649700 }
650701
651- if let Some ( ref s) = self . inner . precise {
702+ if let Some ( s) = & self . inner . precise {
703+ let s = s. to_string ( ) ;
652704 let len = cmp:: min ( s. len ( ) , 8 ) ;
653705 write ! ( f, "#{}" , & s[ ..len] ) ?;
654706 }
0 commit comments