Skip to content

Commit fa94b11

Browse files
committed
precise as enum not string
1 parent 939ebc0 commit fa94b11

File tree

6 files changed

+99
-51
lines changed

6 files changed

+99
-51
lines changed

src/cargo/core/resolver/encode.rs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -776,7 +776,7 @@ pub fn encodable_package_id(
776776
}
777777
}
778778
}
779-
let mut source = encodable_source_id(id_to_encode.with_precise(None), resolve_version);
779+
let mut source = encodable_source_id(id_to_encode.without_precise(), resolve_version);
780780
if let Some(counts) = &state.counts {
781781
let version_counts = &counts[&id.name()];
782782
if version_counts[&id.version()] == 1 {

src/cargo/core/source_id.rs

Lines changed: 88 additions & 36 deletions
Original file line numberDiff line numberDiff line change
@@ -3,7 +3,8 @@ use crate::sources::registry::CRATES_IO_HTTP_INDEX;
33
use crate::sources::source::Source;
44
use crate::sources::{DirectorySource, CRATES_IO_DOMAIN, CRATES_IO_INDEX, CRATES_IO_REGISTRY};
55
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};
78
use anyhow::Context;
89
use serde::de;
910
use 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

457-
/// Check if the precise data field has bean set to "Locked"
474+
/// 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
}

src/cargo/ops/cargo_generate_lockfile.rs

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -105,14 +105,14 @@ pub fn update_lockfile(ws: &Workspace<'_>, opts: &UpdateOptions<'_>) -> CargoRes
105105
if pid.source_id().is_registry() {
106106
pid.source_id().with_precise_registry_version(
107107
pid.name(),
108-
pid.version(),
108+
pid.version().clone(),
109109
precise,
110110
)?
111111
} else {
112-
pid.source_id().with_precise(Some(precise.to_string()))
112+
pid.source_id().with_git_precise(Some(precise.to_string()))
113113
}
114114
}
115-
None => pid.source_id().with_precise(None),
115+
None => pid.source_id().without_precise(),
116116
});
117117
}
118118
if let Ok(unused_id) =
@@ -147,7 +147,7 @@ pub fn update_lockfile(ws: &Workspace<'_>, opts: &UpdateOptions<'_>) -> CargoRes
147147
format!(
148148
"{} -> #{}",
149149
removed[0],
150-
&added[0].source_id().precise().unwrap()[..8]
150+
&added[0].source_id().precise_git_fragment().unwrap()
151151
)
152152
} else {
153153
format!("{} -> v{}", removed[0], added[0].version())

src/cargo/ops/vendor.rs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -258,7 +258,7 @@ fn sync(
258258
} else {
259259
// Remove `precise` since that makes the source name very long,
260260
// and isn't needed to disambiguate multiple sources.
261-
source_id.with_precise(None).as_url().to_string()
261+
source_id.without_precise().as_url().to_string()
262262
};
263263

264264
let source = if source_id.is_crates_io() {

src/cargo/sources/git/source.rs

Lines changed: 4 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -89,13 +89,7 @@ impl<'cfg> GitSource<'cfg> {
8989

9090
let remote = GitRemote::new(source_id.url());
9191
let manifest_reference = source_id.git_reference().unwrap().clone();
92-
let locked_rev =
93-
match source_id.precise() {
94-
Some(s) => Some(git2::Oid::from_str(s).with_context(|| {
95-
format!("precise value for git is not a git revision: {}", s)
96-
})?),
97-
None => None,
98-
};
92+
let locked_rev = source_id.precise_git_oid()?;
9993
let ident = ident_shallow(
10094
&source_id,
10195
config
@@ -290,7 +284,9 @@ impl<'cfg> Source for GitSource<'cfg> {
290284
.join(short_id.as_str());
291285
db.copy_to(actual_rev, &checkout_path, self.config)?;
292286

293-
let source_id = self.source_id.with_precise(Some(actual_rev.to_string()));
287+
let source_id = self
288+
.source_id
289+
.with_git_precise(Some(actual_rev.to_string()));
294290
let path_source = PathSource::new_recursive(&checkout_path, source_id, self.config);
295291

296292
self.path_source = Some(path_source);

src/cargo/sources/registry/index.rs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -663,7 +663,7 @@ impl<'cfg> RegistryIndex<'cfg> {
663663

664664
// Handle `cargo update --precise` here.
665665
let precise = source_id.precise_registry_version(name.as_str());
666-
let summaries = summaries.filter(|s| match &precise {
666+
let summaries = summaries.filter(|s| match precise {
667667
Some((current, requested)) => {
668668
if req.matches(current) {
669669
// Unfortunately crates.io allows versions to differ only

0 commit comments

Comments
 (0)