Auto merge of #9419 - ehuss:doc-meta-rebuild, r=alexcrichton

Fix rebuild issues with rustdoc.

This fixes two issues related to rebuilds with rustdoc:

* Switching features when running `cargo doc` would result in Cargo not rebuilding the documentation. This is because it was keeping the fingerprints in separate directories based on the features used. However, the rustdoc output isn't keyed off the metadata hash, so although the old fingerprint seemed "up to date", in reality the documentation was rewritten and needs to be rebuilt. The solution is to use a simplified hash for the fingerprint directory name.
* Removing items does not remove the files from the doc directory. This changes it to clear the package's doc directory before running rustdoc, to ensure any stale files are removed.

I'm a little concerned about potential performance impact of running `remove_dir_all`, but I think it shouldn't be too bad?

Fixes #7370
This commit is contained in:
bors 2021-04-27 14:35:53 +00:00
commit 4369396ce7
3 changed files with 46 additions and 4 deletions

View file

@ -615,7 +615,7 @@ fn hash_rustc_version(bcx: &BuildContext<'_, '_>, hasher: &mut StableHasher) {
/// Returns whether or not this unit should use a metadata hash.
fn should_use_metadata(bcx: &BuildContext<'_, '_>, unit: &Unit) -> bool {
if unit.mode.is_doc_test() {
if unit.mode.is_doc_test() || unit.mode.is_doc() {
// Doc tests do not have metadata.
return false;
}

View file

@ -599,7 +599,8 @@ fn rustdoc(cx: &mut Context<'_, '_>, unit: &Unit) -> CargoResult<Work> {
// script_metadata is not needed here, it is only for tests.
let mut rustdoc = cx.compilation.rustdoc_process(unit, None)?;
rustdoc.inherit_jobserver(&cx.jobserver);
rustdoc.arg("--crate-name").arg(&unit.target.crate_name());
let crate_name = unit.target.crate_name();
rustdoc.arg("--crate-name").arg(&crate_name);
add_path_args(bcx.ws, unit, &mut rustdoc);
add_cap_lints(bcx, unit, &mut rustdoc);
@ -613,7 +614,7 @@ fn rustdoc(cx: &mut Context<'_, '_>, unit: &Unit) -> CargoResult<Work> {
// it doesn't already exist.
paths::create_dir_all(&doc_dir)?;
rustdoc.arg("-o").arg(doc_dir);
rustdoc.arg("-o").arg(&doc_dir);
for feat in &unit.features {
rustdoc.arg("--cfg").arg(&format!("feature=\"{}\"", feat));
@ -653,6 +654,13 @@ fn rustdoc(cx: &mut Context<'_, '_>, unit: &Unit) -> CargoResult<Work> {
}
}
}
let crate_dir = doc_dir.join(&crate_name);
if crate_dir.exists() {
// Remove output from a previous build. This ensures that stale
// files for removed items are removed.
log::debug!("removing pre-existing doc directory {:?}", crate_dir);
paths::remove_dir_all(crate_dir)?;
}
state.running(&rustdoc);
rustdoc

View file

@ -863,10 +863,44 @@ fn features() {
r#"#[cfg(feature = "bar")] pub fn bar() {}"#,
)
.build();
p.cargo("doc --features foo").run();
p.cargo("doc --features foo")
.with_stderr(
"\
[COMPILING] bar v0.0.1 [..]
[DOCUMENTING] bar v0.0.1 [..]
[DOCUMENTING] foo v0.0.1 [..]
[FINISHED] [..]
",
)
.run();
assert!(p.root().join("target/doc").is_dir());
assert!(p.root().join("target/doc/foo/fn.foo.html").is_file());
assert!(p.root().join("target/doc/bar/fn.bar.html").is_file());
// Check that turning the feature off will remove the files.
p.cargo("doc")
.with_stderr(
"\
[COMPILING] bar v0.0.1 [..]
[DOCUMENTING] bar v0.0.1 [..]
[DOCUMENTING] foo v0.0.1 [..]
[FINISHED] [..]
",
)
.run();
assert!(!p.root().join("target/doc/foo/fn.foo.html").is_file());
assert!(!p.root().join("target/doc/bar/fn.bar.html").is_file());
// And switching back will rebuild and bring them back.
p.cargo("doc --features foo")
.with_stderr(
"\
[DOCUMENTING] bar v0.0.1 [..]
[DOCUMENTING] foo v0.0.1 [..]
[FINISHED] [..]
",
)
.run();
assert!(p.root().join("target/doc/foo/fn.foo.html").is_file());
assert!(p.root().join("target/doc/bar/fn.bar.html").is_file());
}
#[cargo_test]