mirror of
https://github.com/rust-lang/cargo.git
synced 2025-09-25 11:14:46 +00:00
Add a schema version to the index.
This commit is contained in:
parent
ab64d1393b
commit
196673bb1e
@ -327,6 +327,7 @@ pub struct Package {
|
||||
links: Option<String>,
|
||||
rust_version: Option<String>,
|
||||
cargo_features: Vec<String>,
|
||||
v: Option<u32>,
|
||||
}
|
||||
|
||||
#[derive(Clone)]
|
||||
@ -401,6 +402,7 @@ impl Package {
|
||||
links: None,
|
||||
rust_version: None,
|
||||
cargo_features: Vec::new(),
|
||||
v: None,
|
||||
}
|
||||
}
|
||||
|
||||
@ -554,6 +556,14 @@ impl Package {
|
||||
self
|
||||
}
|
||||
|
||||
/// Sets the index schema version for this package.
|
||||
///
|
||||
/// See [`cargo::sources::registry::RegistryPackage`] for more information.
|
||||
pub fn schema_version(&mut self, version: u32) -> &mut Package {
|
||||
self.v = Some(version);
|
||||
self
|
||||
}
|
||||
|
||||
/// Creates the package and place it in the registry.
|
||||
///
|
||||
/// This does not actually use Cargo's publishing system, but instead
|
||||
@ -599,7 +609,7 @@ impl Package {
|
||||
} else {
|
||||
serde_json::json!(self.name)
|
||||
};
|
||||
let line = serde_json::json!({
|
||||
let mut json = serde_json::json!({
|
||||
"name": name,
|
||||
"vers": self.vers,
|
||||
"deps": deps,
|
||||
@ -607,8 +617,11 @@ impl Package {
|
||||
"features": self.features,
|
||||
"yanked": self.yanked,
|
||||
"links": self.links,
|
||||
})
|
||||
.to_string();
|
||||
});
|
||||
if let Some(v) = self.v {
|
||||
json["v"] = serde_json::json!(v);
|
||||
}
|
||||
let line = json.to_string();
|
||||
|
||||
let file = match self.name.len() {
|
||||
1 => format!("1/{}", self.name),
|
||||
|
@ -56,6 +56,8 @@ pub struct NewCrate {
|
||||
pub repository: Option<String>,
|
||||
pub badges: BTreeMap<String, BTreeMap<String, String>>,
|
||||
pub links: Option<String>,
|
||||
#[serde(skip_serializing_if = "Option::is_none")]
|
||||
pub v: Option<u32>,
|
||||
}
|
||||
|
||||
#[derive(Serialize)]
|
||||
|
@ -305,6 +305,7 @@ fn transmit(
|
||||
license_file: license_file.clone(),
|
||||
badges: badges.clone(),
|
||||
links: links.clone(),
|
||||
v: None,
|
||||
},
|
||||
tarball,
|
||||
);
|
||||
|
@ -72,7 +72,8 @@ use crate::sources::registry::{RegistryData, RegistryPackage};
|
||||
use crate::util::interning::InternedString;
|
||||
use crate::util::paths;
|
||||
use crate::util::{internal, CargoResult, Config, Filesystem, ToSemver};
|
||||
use log::info;
|
||||
use anyhow::bail;
|
||||
use log::{debug, info};
|
||||
use semver::{Version, VersionReq};
|
||||
use std::collections::{HashMap, HashSet};
|
||||
use std::fs;
|
||||
@ -233,6 +234,8 @@ enum MaybeIndexSummary {
|
||||
pub struct IndexSummary {
|
||||
pub summary: Summary,
|
||||
pub yanked: bool,
|
||||
/// Schema version, see [`RegistryPackage`].
|
||||
v: u32,
|
||||
}
|
||||
|
||||
/// A representation of the cache on disk that Cargo maintains of summaries.
|
||||
@ -305,6 +308,7 @@ impl<'cfg> RegistryIndex<'cfg> {
|
||||
// minimize the amount of work being done here and parse as little as
|
||||
// necessary.
|
||||
let raw_data = &summaries.raw_data;
|
||||
let max_version = 1;
|
||||
Ok(summaries
|
||||
.versions
|
||||
.iter_mut()
|
||||
@ -318,6 +322,19 @@ impl<'cfg> RegistryIndex<'cfg> {
|
||||
}
|
||||
},
|
||||
)
|
||||
.filter(move |is| {
|
||||
if is.v > max_version {
|
||||
debug!(
|
||||
"unsupported schema version {} ({} {})",
|
||||
is.v,
|
||||
is.summary.name(),
|
||||
is.summary.version()
|
||||
);
|
||||
false
|
||||
} else {
|
||||
true
|
||||
}
|
||||
})
|
||||
.filter(move |is| {
|
||||
is.summary
|
||||
.unstable_gate(namespaced_features, weak_dep_features)
|
||||
@ -578,7 +595,14 @@ impl Summaries {
|
||||
// actually happens to verify that our cache is indeed fresh and
|
||||
// computes exactly the same value as before.
|
||||
if cfg!(debug_assertions) && cache_contents.is_some() {
|
||||
assert_eq!(cache_bytes, cache_contents);
|
||||
if cache_bytes != cache_contents {
|
||||
panic!(
|
||||
"original cache contents:\n{:?}\n\
|
||||
does not equal new cache contents:\n{:?}\n",
|
||||
cache_contents.as_ref().map(|s| String::from_utf8_lossy(s)),
|
||||
cache_bytes.as_ref().map(|s| String::from_utf8_lossy(s)),
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
// Once we have our `cache_bytes` which represents the `Summaries` we're
|
||||
@ -659,19 +683,19 @@ impl<'a> SummariesCache<'a> {
|
||||
.split_first()
|
||||
.ok_or_else(|| anyhow::format_err!("malformed cache"))?;
|
||||
if *first_byte != CURRENT_CACHE_VERSION {
|
||||
anyhow::bail!("looks like a different Cargo's cache, bailing out");
|
||||
bail!("looks like a different Cargo's cache, bailing out");
|
||||
}
|
||||
let mut iter = split(rest, 0);
|
||||
if let Some(update) = iter.next() {
|
||||
if update != last_index_update.as_bytes() {
|
||||
anyhow::bail!(
|
||||
bail!(
|
||||
"cache out of date: current index ({}) != cache ({})",
|
||||
last_index_update,
|
||||
str::from_utf8(update)?,
|
||||
)
|
||||
}
|
||||
} else {
|
||||
anyhow::bail!("malformed file");
|
||||
bail!("malformed file");
|
||||
}
|
||||
let mut ret = SummariesCache::default();
|
||||
while let Some(version) = iter.next() {
|
||||
@ -749,7 +773,9 @@ impl IndexSummary {
|
||||
features,
|
||||
yanked,
|
||||
links,
|
||||
v,
|
||||
} = serde_json::from_slice(line)?;
|
||||
let v = v.unwrap_or(1);
|
||||
log::trace!("json parsed registry {}/{}", name, vers);
|
||||
let pkgid = PackageId::new(name, &vers, source_id)?;
|
||||
let deps = deps
|
||||
@ -761,6 +787,7 @@ impl IndexSummary {
|
||||
Ok(IndexSummary {
|
||||
summary,
|
||||
yanked: yanked.unwrap_or(false),
|
||||
v,
|
||||
})
|
||||
}
|
||||
}
|
||||
|
@ -269,6 +269,24 @@ pub struct RegistryPackage<'a> {
|
||||
/// Added early 2018 (see <https://github.com/rust-lang/cargo/pull/4978>),
|
||||
/// can be `None` if published before then.
|
||||
links: Option<InternedString>,
|
||||
/// The schema version for this entry.
|
||||
///
|
||||
/// If this is None, it defaults to version 1. Entries with unknown
|
||||
/// versions are ignored.
|
||||
///
|
||||
/// This provides a method to safely introduce changes to index entries
|
||||
/// and allow older versions of cargo to ignore newer entries it doesn't
|
||||
/// understand. This is honored as of 1.51, so unfortunately older
|
||||
/// versions will ignore it, and potentially misinterpret version 1 and
|
||||
/// newer entries.
|
||||
///
|
||||
/// The intent is that versions older than 1.51 will work with a
|
||||
/// pre-existing `Cargo.lock`, but they may not correctly process `cargo
|
||||
/// update` or build a lock from scratch. In that case, cargo may
|
||||
/// incorrectly select a new package that uses a new index format. A
|
||||
/// workaround is to downgrade any packages that are incompatible with the
|
||||
/// `--precise` flag of `cargo update`.
|
||||
v: Option<u32>,
|
||||
}
|
||||
|
||||
#[test]
|
||||
|
@ -78,6 +78,7 @@ mod multitarget;
|
||||
mod net_config;
|
||||
mod new;
|
||||
mod offline;
|
||||
mod old_cargos;
|
||||
mod out_dir;
|
||||
mod owner;
|
||||
mod package;
|
||||
|
@ -2170,3 +2170,33 @@ fn package_lock_inside_package_is_overwritten() {
|
||||
|
||||
assert_eq!(ok.metadata().unwrap().len(), 2);
|
||||
}
|
||||
|
||||
#[cargo_test]
|
||||
fn ignores_unknown_index_version() {
|
||||
// If the version field is not understood, it is ignored.
|
||||
Package::new("bar", "1.0.0").publish();
|
||||
Package::new("bar", "1.0.1").schema_version(9999).publish();
|
||||
|
||||
let p = project()
|
||||
.file(
|
||||
"Cargo.toml",
|
||||
r#"
|
||||
[package]
|
||||
name = "foo"
|
||||
version = "0.1.0"
|
||||
|
||||
[dependencies]
|
||||
bar = "1.0"
|
||||
"#,
|
||||
)
|
||||
.file("src/lib.rs", "")
|
||||
.build();
|
||||
|
||||
p.cargo("tree")
|
||||
.with_stdout(
|
||||
"foo v0.1.0 [..]\n\
|
||||
└── bar v1.0.0\n\
|
||||
",
|
||||
)
|
||||
.run();
|
||||
}
|
||||
|
Loading…
x
Reference in New Issue
Block a user