@@ -2,7 +2,8 @@ use crate::core::PackageId;
22use crate :: sources:: registry:: CRATES_IO_HTTP_INDEX ;
33use crate :: sources:: { DirectorySource , CRATES_IO_DOMAIN , CRATES_IO_INDEX , CRATES_IO_REGISTRY } ;
44use crate :: sources:: { GitSource , PathSource , RegistrySource } ;
5- use crate :: util:: { config, CanonicalUrl , CargoResult , Config , IntoUrl } ;
5+ use crate :: util:: { config, CanonicalUrl , CargoResult , Config , IntoUrl , ToSemver } ;
6+ use anyhow:: Context ;
67use serde:: de;
78use serde:: ser;
89use std:: cmp:: { self , Ordering } ;
@@ -430,11 +431,6 @@ impl SourceId {
430431 }
431432 }
432433
433- /// Gets the value of the precise field.
434- pub fn precise ( self ) -> Option < & ' static str > {
435- self . inner . precise . as_deref ( )
436- }
437-
438434 /// Gets the Git reference if this is a git source, otherwise `None`.
439435 pub fn git_reference ( self ) -> Option < & ' static GitReference > {
440436 match self . inner . kind {
@@ -443,6 +439,33 @@ impl SourceId {
443439 }
444440 }
445441
442+ /// Gets the value of the precise field.
443+ pub fn precise ( self ) -> Option < & ' static str > {
444+ self . inner . precise . as_deref ( )
445+ }
446+
447+ /// Check if the precise data field stores information for this `name`
448+ /// from a call to [SourceId::with_precise_registry_version].
449+ ///
450+ /// If so return the version currently in the lock file and the version to be updated to.
451+ /// If specified, our own source will have a precise version listed of the form
452+ // `<pkg>=<p_req>-><f_req>` where `<pkg>` is the name of a crate on
453+ // this source, `<p_req>` is the version installed and `<f_req>` is the
454+ // version requested (argument to `--precise`).
455+ pub fn precise_registry_version (
456+ self ,
457+ name : & str ,
458+ ) -> Option < ( semver:: Version , semver:: Version ) > {
459+ self . inner
460+ . precise
461+ . as_deref ( )
462+ . and_then ( |p| p. strip_prefix ( name) ?. strip_prefix ( '=' ) )
463+ . map ( |p| {
464+ let ( current, requested) = p. split_once ( "->" ) . unwrap ( ) ;
465+ ( current. to_semver ( ) . unwrap ( ) , requested. to_semver ( ) . unwrap ( ) )
466+ } )
467+ }
468+
446469 /// Creates a new `SourceId` from this source with the given `precise`.
447470 pub fn with_precise ( self , v : Option < String > ) -> SourceId {
448471 SourceId :: wrap ( SourceIdInner {
@@ -451,6 +474,23 @@ impl SourceId {
451474 } )
452475 }
453476
477+ /// When updating a lock file on a version using `cargo update --precise`
478+ /// the requested version is stored in the precise field.
479+ /// On a registry dependency we also need to keep track of the package that
480+ /// should be updated and even which of the versions should be updated.
481+ /// All of this gets encoded in the precise field using this method.
482+ /// The data can be read with [SourceId::precise_registry_version]
483+ pub fn with_precise_registry_version (
484+ self ,
485+ name : impl fmt:: Display ,
486+ version : & semver:: Version ,
487+ precise : & str ,
488+ ) -> CargoResult < SourceId > {
489+ semver:: Version :: parse ( precise)
490+ . with_context ( || format ! ( "invalid version format for precise version `{precise}`" ) ) ?;
491+ Ok ( self . with_precise ( Some ( format ! ( "{}={}->{}" , name, version, precise) ) ) )
492+ }
493+
454494 /// Returns `true` if the remote registry is the standard <https://crates.io>.
455495 pub fn is_crates_io ( self ) -> bool {
456496 match self . inner . kind {
0 commit comments