Skip to content

Commit 9294589

Browse files
committed
Auto merge of #9196 - ehuss:backports, r=alexcrichton
[beta] backports for 1.51 Beta backports for the following: * Fix panic with doc collision orphan. (#9142) * This is an important regression that is fairly easy to hit. * Do not exit prematurely if anything failed installing. (#9185) * This is not a regression, but I think an important fix. * Add schema field to the index (#9161) * This is only the first commit from the PR which checks for the `v` field in the index, and skips entries that are not understood. The reason to backport is to get this in as early as possible so that if we do decide to start using it in the future, it works as early as possible. This otherwise doesn't do anything, so I think it should be safe. * Fix warnings of the new non_fmt_panic lint (#9148) * Fixes CI for a new warning in nightly.
2 parents 34170fc + d864971 commit 9294589

File tree

13 files changed

+249
-33
lines changed

13 files changed

+249
-33
lines changed

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

+1-1
Original file line numberDiff line numberDiff line change
@@ -177,7 +177,7 @@ rustup does not appear to be installed. Make sure that the appropriate
177177
},
178178
}
179179

180-
panic!(message);
180+
panic!("{}", message);
181181
}
182182

183183
/// The alternate target-triple to build with.

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

+16-3
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

+2
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/cargo_compile.rs

+20-9
Original file line numberDiff line numberDiff line change
@@ -507,7 +507,7 @@ pub fn create_bcx<'a, 'cfg>(
507507
// TODO: In theory, Cargo should also dedupe the roots, but I'm uncertain
508508
// what heuristics to use in that case.
509509
if build_config.mode == (CompileMode::Doc { deps: true }) {
510-
remove_duplicate_doc(build_config, &mut unit_graph);
510+
remove_duplicate_doc(build_config, &units, &mut unit_graph);
511511
}
512512

513513
if build_config
@@ -1508,14 +1508,11 @@ fn opt_patterns_and_names(
15081508
/// - Different sources. See `collision_doc_sources` test.
15091509
///
15101510
/// Ideally this would not be necessary.
1511-
fn remove_duplicate_doc(build_config: &BuildConfig, unit_graph: &mut UnitGraph) {
1512-
// NOTE: There is some risk that this can introduce problems because it
1513-
// may create orphans in the unit graph (parts of the tree get detached
1514-
// from the roots). I currently can't think of any ways this will cause a
1515-
// problem because all other parts of Cargo traverse the graph starting
1516-
// from the roots. Perhaps this should scan for detached units and remove
1517-
// them too?
1518-
//
1511+
fn remove_duplicate_doc(
1512+
build_config: &BuildConfig,
1513+
root_units: &[Unit],
1514+
unit_graph: &mut UnitGraph,
1515+
) {
15191516
// First, create a mapping of crate_name -> Unit so we can see where the
15201517
// duplicates are.
15211518
let mut all_docs: HashMap<String, Vec<Unit>> = HashMap::new();
@@ -1601,4 +1598,18 @@ fn remove_duplicate_doc(build_config: &BuildConfig, unit_graph: &mut UnitGraph)
16011598
for unit_deps in unit_graph.values_mut() {
16021599
unit_deps.retain(|unit_dep| !removed_units.contains(&unit_dep.unit));
16031600
}
1601+
// Remove any orphan units that were detached from the graph.
1602+
let mut visited = HashSet::new();
1603+
fn visit(unit: &Unit, graph: &UnitGraph, visited: &mut HashSet<Unit>) {
1604+
if !visited.insert(unit.clone()) {
1605+
return;
1606+
}
1607+
for dep in &graph[unit] {
1608+
visit(&dep.unit, graph, visited);
1609+
}
1610+
}
1611+
for unit in root_units {
1612+
visit(unit, unit_graph, &mut visited);
1613+
}
1614+
unit_graph.retain(|unit, _| visited.contains(unit));
16041615
}

src/cargo/ops/cargo_install.rs

+7-9
Original file line numberDiff line numberDiff line change
@@ -119,17 +119,15 @@ pub fn install(
119119
// able to run these commands.
120120
let dst = root.join("bin").into_path_unlocked();
121121
let path = env::var_os("PATH").unwrap_or_default();
122-
for path in env::split_paths(&path) {
123-
if path == dst {
124-
return Ok(());
125-
}
126-
}
122+
let dst_in_path = env::split_paths(&path).any(|path| path == dst);
127123

128-
config.shell().warn(&format!(
129-
"be sure to add `{}` to your PATH to be \
124+
if !dst_in_path {
125+
config.shell().warn(&format!(
126+
"be sure to add `{}` to your PATH to be \
130127
able to run the installed binaries",
131-
dst.display()
132-
))?;
128+
dst.display()
129+
))?;
130+
}
133131
}
134132

135133
if scheduled_error {

src/cargo/ops/registry.rs

+1
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

+32-5
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

+18
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/cargo_command.rs

+1-1
Original file line numberDiff line numberDiff line change
@@ -365,5 +365,5 @@ fn closed_output_ok() {
365365
.unwrap();
366366
let status = child.wait().unwrap();
367367
assert!(status.success());
368-
assert!(s.is_empty(), s);
368+
assert!(s.is_empty(), "{}", s);
369369
}

tests/testsuite/collisions.rs

+49-2
Original file line numberDiff line numberDiff line change
@@ -3,9 +3,8 @@
33
//! Ideally these should never happen, but I don't think we'll ever be able to
44
//! prevent all collisions.
55
6-
use cargo_test_support::basic_manifest;
7-
use cargo_test_support::project;
86
use cargo_test_support::registry::Package;
7+
use cargo_test_support::{basic_manifest, cross_compile, project};
98
use std::env;
109

1110
#[cargo_test]
@@ -431,3 +430,51 @@ the same path; see <https://github.com/rust-lang/cargo/issues/6313>.
431430
)
432431
.run();
433432
}
433+
434+
#[cargo_test]
435+
fn collision_doc_target() {
436+
// collision in doc with --target, doesn't fail due to orphans
437+
if cross_compile::disabled() {
438+
return;
439+
}
440+
441+
Package::new("orphaned", "1.0.0").publish();
442+
Package::new("bar", "1.0.0")
443+
.dep("orphaned", "1.0")
444+
.publish();
445+
Package::new("bar", "2.0.0").publish();
446+
let p = project()
447+
.file(
448+
"Cargo.toml",
449+
r#"
450+
[package]
451+
name = "foo"
452+
version = "0.1.0"
453+
454+
[dependencies]
455+
bar2 = { version = "2.0", package="bar" }
456+
bar = "1.0"
457+
"#,
458+
)
459+
.file("src/lib.rs", "")
460+
.build();
461+
462+
p.cargo("doc --target")
463+
.arg(cross_compile::alternate())
464+
.with_stderr_unordered(
465+
"\
466+
[UPDATING] [..]
467+
[DOWNLOADING] crates ...
468+
[DOWNLOADED] orphaned v1.0.0 [..]
469+
[DOWNLOADED] bar v2.0.0 [..]
470+
[DOWNLOADED] bar v1.0.0 [..]
471+
[CHECKING] orphaned v1.0.0
472+
[DOCUMENTING] bar v2.0.0
473+
[CHECKING] bar v2.0.0
474+
[CHECKING] bar v1.0.0
475+
[DOCUMENTING] foo v0.1.0 [..]
476+
[FINISHED] [..]
477+
",
478+
)
479+
.run();
480+
}

0 commit comments

Comments
 (0)