Check target-dependant doc folders

When checking the fingerprint for rustdoc and applying
the corresponding logic, we don't only need to consider
the `target/doc` folder (Host target) but also triple targets.

So now the actual compilation targets are checked during the
rustdoc_fingerprint processing and they're treated as the Host/doc
folder.
This commit is contained in:
CPerezz 2021-01-31 23:43:27 +01:00
parent d2572a2800
commit 7c45021328
No known key found for this signature in database
GPG key ID: 6EE573EDC452F806
2 changed files with 117 additions and 25 deletions

View file

@ -9,7 +9,7 @@ use serde::{Deserialize, Serialize};
use std::cell::RefCell;
use std::collections::hash_map::{Entry, HashMap};
use std::env;
use std::path::PathBuf;
use std::path::{Path, PathBuf};
use std::str::{self, FromStr};
/// Information about the platform target gleaned from querying rustc.
@ -755,28 +755,20 @@ impl RustcTargetData {
/// Structure used to deal with Rustdoc fingerprinting
#[derive(Debug, Serialize, Deserialize)]
pub struct RustDocFingerprint {
rustc_vv: String,
pub rustc_vv: String,
}
impl RustDocFingerprint {
/// Read the `RustDocFingerprint` info from the fingerprint file.
fn read<'a, 'cfg>(cx: &Context<'a, 'cfg>) -> CargoResult<Self> {
let rustdoc_data = paths::read(
&cx.files()
.host_root()
.join(".rustdoc_fingerprint")
.with_extension("json"),
)?;
let rustdoc_data = paths::read(&cx.files().host_root().join(".rustdoc_fingerprint.json"))?;
serde_json::from_str(&rustdoc_data).map_err(|e| anyhow::anyhow!("{:?}", e))
}
/// Write the `RustDocFingerprint` info into the fingerprint file.
fn write<'a, 'cfg>(&self, cx: &Context<'a, 'cfg>) -> CargoResult<()> {
paths::write(
&cx.files()
.host_root()
.join(".rustdoc_fingerprint.json")
.with_extension("json"),
&cx.files().host_root().join(".rustdoc_fingerprint.json"),
serde_json::to_string(&self)?.as_bytes(),
)
}
@ -793,14 +785,28 @@ impl RustDocFingerprint {
let actual_rustdoc_target_data = RustDocFingerprint {
rustc_vv: cx.bcx.rustc().verbose_version.clone(),
};
let doc_dir = cx.files().host_root().join("doc");
// Collect all of the target doc paths for which the docs need to be compiled for.
let doc_dirs: Vec<PathBuf> = cx
.compilation
.root_output
.iter()
.map(|(ck, _)| match ck {
CompileKind::Host => cx.files().host_root().to_path_buf(),
CompileKind::Target(t) => cx.files().host_root().join(Path::new(t.rustc_target())),
})
.map(|path| path.join("doc"))
.collect();
// Check wether `.rustdoc_fingerprint.json` exists
match Self::read(cx) {
Ok(fingerprint) => {
// Check if rustc_version matches the one we just used. Otherways,
// remove the `doc` folder to trigger a re-compilation of the docs.
if fingerprint.rustc_vv != actual_rustdoc_target_data.rustc_vv {
paths::remove_dir_all(&doc_dir)?;
doc_dirs
.iter()
.try_for_each(|path| paths::remove_dir_all(&path))?;
actual_rustdoc_target_data.write(cx)?
}
}
@ -810,7 +816,9 @@ impl RustDocFingerprint {
// exists neither, we simply do nothing and continue.
Err(_) => {
// We don't care if this suceeds as explained above.
let _ = paths::remove_dir_all(doc_dir);
let _ = doc_dirs
.iter()
.try_for_each(|path| paths::remove_dir_all(&path));
actual_rustdoc_target_data.write(cx)?
}
}

View file

@ -1,10 +1,10 @@
//! Tests for the `cargo doc` command.
use cargo::core::compiler::RustDocFingerprint;
use cargo_test_support::paths::CargoPathExt;
use cargo_test_support::registry::Package;
use cargo_test_support::{basic_lib_manifest, basic_manifest, git, project};
use cargo_test_support::{is_nightly, rustc_host};
use serde::{Deserialize, Serialize};
use std::fs;
use std::str;
@ -1641,15 +1641,7 @@ fn crate_versions_flag_is_overridden() {
}
#[cargo_test]
fn doc_fingerprint_versioning_consistent() {
#[derive(Debug, Serialize, Deserialize)]
pub struct RustDocFingerprint {
rustc_vv: String,
}
// Test that using different Rustc versions forces a
// doc re-compilation producing new html, css & js files.
fn doc_fingerprint_is_versioning_consistent() {
// Random rustc verbose version
let old_rustc_verbose_version = format!(
"\
@ -1730,3 +1722,95 @@ LLVM version: 9.0
(String::from_utf8_lossy(&output.stdout).as_ref())
);
}
#[cargo_test]
fn doc_fingerprint_respects_target_paths() {
// Random rustc verbose version
let old_rustc_verbose_version = format!(
"\
rustc 1.41.1 (f3e1a954d 2020-02-24)
binary: rustc
commit-hash: f3e1a954d2ead4e2fc197c7da7d71e6c61bad196
commit-date: 2020-02-24
host: {}
release: 1.41.1
LLVM version: 9.0
",
rustc_host()
);
// Create the dummy project.
let dummy_project = project()
.file(
"Cargo.toml",
r#"
[package]
name = "foo"
version = "1.2.4"
authors = []
"#,
)
.file("src/lib.rs", "//! These are the docs!")
.build();
dummy_project
.cargo("doc --target x86_64-unknown-linux-gnu")
.run();
let fingerprint: RustDocFingerprint =
serde_json::from_str(&dummy_project.read_file("target/.rustdoc_fingerprint.json"))
.expect("JSON Serde fail");
// Check that the fingerprint contains the actual rustc version
// which has been used to compile the docs.
let output = std::process::Command::new("rustc")
.arg("-vV")
.output()
.expect("Failed to get actual rustc verbose version");
assert_eq!(
fingerprint.rustc_vv,
(String::from_utf8_lossy(&output.stdout).as_ref())
);
// As the test shows above. Now we have generated the `doc/` folder and inside
// the rustdoc fingerprint file is located with the correct rustc version.
// So we will remove it and create a new fingerprint with an old rustc version
// inside it. We will also place a bogus file inside of the `doc/` folder to ensure
// it gets removed as we expect on the next doc compilation.
dummy_project.change_file(
"target/.rustdoc_fingerprint.json",
&old_rustc_verbose_version,
);
fs::write(
dummy_project
.build_dir()
.join("x86_64-unknown-linux-gnu/doc/bogus_file"),
String::from("This is a bogus file and should be removed!"),
)
.expect("Error writing test bogus file");
// Now if we trigger another compilation, since the fingerprint contains an old version
// of rustc, cargo should remove the entire `/doc` folder (including the fingerprint)
// and generating another one with the actual version.
// It should also remove the bogus file we created above.
dummy_project
.cargo("doc --target x86_64-unknown-linux-gnu")
.run();
assert!(!dummy_project
.build_dir()
.join("x86_64-unknown-linux-gnu/doc/bogus_file")
.exists());
let fingerprint: RustDocFingerprint =
serde_json::from_str(&dummy_project.read_file("target/.rustdoc_fingerprint.json"))
.expect("JSON Serde fail");
// Check that the fingerprint contains the actual rustc version
// which has been used to compile the docs.
assert_eq!(
fingerprint.rustc_vv,
(String::from_utf8_lossy(&output.stdout).as_ref())
);
}