Skip to content

Commit 19fd5cb

Browse files
committed
Add a schema version to the index.
1 parent a9652c0 commit 19fd5cb

File tree

6 files changed

+99
-8
lines changed

6 files changed

+99
-8
lines changed

crates/cargo-test-support/src/registry.rs

Lines changed: 16 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -327,6 +327,7 @@ pub struct Package {
327327
links: Option<String>,
328328
rust_version: Option<String>,
329329
cargo_features: Vec<String>,
330+
v: Option<u32>,
330331
}
331332

332333
#[derive(Clone)]
@@ -401,6 +402,7 @@ impl Package {
401402
links: None,
402403
rust_version: None,
403404
cargo_features: Vec::new(),
405+
v: None,
404406
}
405407
}
406408

@@ -554,6 +556,14 @@ impl Package {
554556
self
555557
}
556558

559+
/// Sets the index schema version for this package.
560+
///
561+
/// See [`cargo::sources::registry::RegistryPackage`] for more information.
562+
pub fn schema_version(&mut self, version: u32) -> &mut Package {
563+
self.v = Some(version);
564+
self
565+
}
566+
557567
/// Creates the package and place it in the registry.
558568
///
559569
/// This does not actually use Cargo's publishing system, but instead
@@ -599,16 +609,19 @@ impl Package {
599609
} else {
600610
serde_json::json!(self.name)
601611
};
602-
let line = serde_json::json!({
612+
let mut json = serde_json::json!({
603613
"name": name,
604614
"vers": self.vers,
605615
"deps": deps,
606616
"cksum": cksum,
607617
"features": self.features,
608618
"yanked": self.yanked,
609619
"links": self.links,
610-
})
611-
.to_string();
620+
});
621+
if let Some(v) = self.v {
622+
json["v"] = serde_json::json!(v);
623+
}
624+
let line = json.to_string();
612625

613626
let file = match self.name.len() {
614627
1 => format!("1/{}", self.name),

crates/crates-io/lib.rs

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -56,6 +56,8 @@ pub struct NewCrate {
5656
pub repository: Option<String>,
5757
pub badges: BTreeMap<String, BTreeMap<String, String>>,
5858
pub links: Option<String>,
59+
#[serde(skip_serializing_if = "Option::is_none")]
60+
pub v: Option<u32>,
5961
}
6062

6163
#[derive(Serialize)]

src/cargo/ops/registry.rs

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -305,6 +305,7 @@ fn transmit(
305305
license_file: license_file.clone(),
306306
badges: badges.clone(),
307307
links: links.clone(),
308+
v: None,
308309
},
309310
tarball,
310311
);

src/cargo/sources/registry/index.rs

Lines changed: 32 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -72,7 +72,8 @@ use crate::sources::registry::{RegistryData, RegistryPackage};
7272
use crate::util::interning::InternedString;
7373
use crate::util::paths;
7474
use crate::util::{internal, CargoResult, Config, Filesystem, ToSemver};
75-
use log::info;
75+
use anyhow::bail;
76+
use log::{debug, info};
7677
use semver::{Version, VersionReq};
7778
use std::collections::{HashMap, HashSet};
7879
use std::fs;
@@ -233,6 +234,8 @@ enum MaybeIndexSummary {
233234
pub struct IndexSummary {
234235
pub summary: Summary,
235236
pub yanked: bool,
237+
/// Schema version, see [`RegistryPackage`].
238+
v: u32,
236239
}
237240

238241
/// A representation of the cache on disk that Cargo maintains of summaries.
@@ -305,6 +308,7 @@ impl<'cfg> RegistryIndex<'cfg> {
305308
// minimize the amount of work being done here and parse as little as
306309
// necessary.
307310
let raw_data = &summaries.raw_data;
311+
let max_version = 1;
308312
Ok(summaries
309313
.versions
310314
.iter_mut()
@@ -318,6 +322,19 @@ impl<'cfg> RegistryIndex<'cfg> {
318322
}
319323
},
320324
)
325+
.filter(move |is| {
326+
if is.v > max_version {
327+
debug!(
328+
"unsupported schema version {} ({} {})",
329+
is.v,
330+
is.summary.name(),
331+
is.summary.version()
332+
);
333+
false
334+
} else {
335+
true
336+
}
337+
})
321338
.filter(move |is| {
322339
is.summary
323340
.unstable_gate(namespaced_features, weak_dep_features)
@@ -578,7 +595,14 @@ impl Summaries {
578595
// actually happens to verify that our cache is indeed fresh and
579596
// computes exactly the same value as before.
580597
if cfg!(debug_assertions) && cache_contents.is_some() {
581-
assert_eq!(cache_bytes, cache_contents);
598+
if cache_bytes != cache_contents {
599+
panic!(
600+
"original cache contents:\n{:?}\n\
601+
does not equal new cache contents:\n{:?}\n",
602+
cache_contents.as_ref().map(|s| String::from_utf8_lossy(s)),
603+
cache_bytes.as_ref().map(|s| String::from_utf8_lossy(s)),
604+
);
605+
}
582606
}
583607

584608
// Once we have our `cache_bytes` which represents the `Summaries` we're
@@ -659,19 +683,19 @@ impl<'a> SummariesCache<'a> {
659683
.split_first()
660684
.ok_or_else(|| anyhow::format_err!("malformed cache"))?;
661685
if *first_byte != CURRENT_CACHE_VERSION {
662-
anyhow::bail!("looks like a different Cargo's cache, bailing out");
686+
bail!("looks like a different Cargo's cache, bailing out");
663687
}
664688
let mut iter = split(rest, 0);
665689
if let Some(update) = iter.next() {
666690
if update != last_index_update.as_bytes() {
667-
anyhow::bail!(
691+
bail!(
668692
"cache out of date: current index ({}) != cache ({})",
669693
last_index_update,
670694
str::from_utf8(update)?,
671695
)
672696
}
673697
} else {
674-
anyhow::bail!("malformed file");
698+
bail!("malformed file");
675699
}
676700
let mut ret = SummariesCache::default();
677701
while let Some(version) = iter.next() {
@@ -749,7 +773,9 @@ impl IndexSummary {
749773
features,
750774
yanked,
751775
links,
776+
v,
752777
} = serde_json::from_slice(line)?;
778+
let v = v.unwrap_or(1);
753779
log::trace!("json parsed registry {}/{}", name, vers);
754780
let pkgid = PackageId::new(name, &vers, source_id)?;
755781
let deps = deps
@@ -761,6 +787,7 @@ impl IndexSummary {
761787
Ok(IndexSummary {
762788
summary,
763789
yanked: yanked.unwrap_or(false),
790+
v,
764791
})
765792
}
766793
}

src/cargo/sources/registry/mod.rs

Lines changed: 18 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -269,6 +269,24 @@ pub struct RegistryPackage<'a> {
269269
/// Added early 2018 (see <https://github.com/rust-lang/cargo/pull/4978>),
270270
/// can be `None` if published before then.
271271
links: Option<InternedString>,
272+
/// The schema version for this entry.
273+
///
274+
/// If this is None, it defaults to version 1. Entries with unknown
275+
/// versions are ignored.
276+
///
277+
/// This provides a method to safely introduce changes to index entries
278+
/// and allow older versions of cargo to ignore newer entries it doesn't
279+
/// understand. This is honored as of 1.51, so unfortunately older
280+
/// versions will ignore it, and potentially misinterpret version 1 and
281+
/// newer entries.
282+
///
283+
/// The intent is that versions older than 1.51 will work with a
284+
/// pre-existing `Cargo.lock`, but they may not correctly process `cargo
285+
/// update` or build a lock from scratch. In that case, cargo may
286+
/// incorrectly select a new package that uses a new index format. A
287+
/// workaround is to downgrade any packages that are incompatible with the
288+
/// `--precise` flag of `cargo update`.
289+
v: Option<u32>,
272290
}
273291

274292
#[test]

tests/testsuite/registry.rs

Lines changed: 30 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2170,3 +2170,33 @@ fn package_lock_inside_package_is_overwritten() {
21702170

21712171
assert_eq!(ok.metadata().unwrap().len(), 2);
21722172
}
2173+
2174+
#[cargo_test]
2175+
fn ignores_unknown_index_version() {
2176+
// If the version field is not understood, it is ignored.
2177+
Package::new("bar", "1.0.0").publish();
2178+
Package::new("bar", "1.0.1").schema_version(9999).publish();
2179+
2180+
let p = project()
2181+
.file(
2182+
"Cargo.toml",
2183+
r#"
2184+
[package]
2185+
name = "foo"
2186+
version = "0.1.0"
2187+
2188+
[dependencies]
2189+
bar = "1.0"
2190+
"#,
2191+
)
2192+
.file("src/lib.rs", "")
2193+
.build();
2194+
2195+
p.cargo("tree")
2196+
.with_stdout(
2197+
"foo v0.1.0 [..]\n\
2198+
└── bar v1.0.0\n\
2199+
",
2200+
)
2201+
.run();
2202+
}

0 commit comments

Comments
 (0)