Skip to content

Commit 79399ac

Browse files
committed
feat: rebuild(-ish) rustdoc json for different version of same crates
1 parent b41ee31 commit 79399ac

7 files changed

Lines changed: 65 additions & 17 deletions

File tree

src/cargo/core/compiler/build_runner/compilation_files.rs

Lines changed: 4 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -524,8 +524,10 @@ impl<'a, 'gctx: 'a> CompilationFiles<'a, 'gctx> {
524524
}
525525
CompileMode::Doc => {
526526
let path = if bcx.build_config.intent.wants_doc_json_output() {
527-
self.output_dir(unit)
528-
.join(format!("{}.json", unit.target.crate_name()))
527+
// Always use 'new' layout for '--output-format=json'.
528+
let crate_name = unit.target.crate_name();
529+
self.out_dir_new_layout(unit)
530+
.join(format!("{crate_name}.json"))
529531
} else {
530532
self.output_dir(unit)
531533
.join(unit.target.crate_name())

src/cargo/core/compiler/build_runner/mod.rs

Lines changed: 24 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -7,11 +7,12 @@ use std::sync::{Arc, Mutex};
77
use crate::core::PackageId;
88
use crate::core::compiler::compilation::{self, UnitOutput};
99
use crate::core::compiler::locking::LockManager;
10+
use crate::core::compiler::rustdoc::is_rustdoc_json_output;
1011
use crate::core::compiler::{self, Unit, UserIntent, artifact};
1112
use crate::util::cache_lock::CacheLockMode;
1213
use crate::util::errors::CargoResult;
1314
use anyhow::{Context as _, bail};
14-
use cargo_util::paths;
15+
use cargo_util::paths::{self, copy};
1516
use cargo_util_terminal::report::{Level, Message};
1617
use filetime::FileTime;
1718
use itertools::Itertools;
@@ -235,6 +236,11 @@ impl<'a, 'gctx> BuildRunner<'a, 'gctx> {
235236
for unit in &self.bcx.roots {
236237
self.collect_tests_and_executables(unit)?;
237238

239+
// Uplift rustdoc
240+
if is_rustdoc_json_output(&self) {
241+
self.uplift_rustdoc(unit)?;
242+
}
243+
238244
// Collect information for `rustdoc --test`.
239245
if unit.mode.is_doc_test() {
240246
let mut unstable_opts = false;
@@ -787,4 +793,21 @@ impl<'a, 'gctx> BuildRunner<'a, 'gctx> {
787793
.insert(unit.clone(), self.files().metadata(metadata_unit));
788794
}
789795
}
796+
797+
/// Uplifts final json to <doc_dir>/<crate_name>.json (for backward compatibility)
798+
/// The final output is produced only after root unit is complete.
799+
// TODO: It would be better if we don't do uplifting when new build layout is specified,
800+
// but there is no way we can collect new out dir paths from ops.
801+
// Thus we here always do uplifting.
802+
fn uplift_rustdoc(&self, unit: &Unit) -> CargoResult<()> {
803+
let doc_dir = self.files().output_dir(unit);
804+
let doc_json_dir = self.files().out_dir_new_layout(unit);
805+
let crate_name = unit.target.crate_name();
806+
let filename = format!("{crate_name}.json");
807+
808+
let src_path = doc_json_dir.join(&filename);
809+
copy(src_path, doc_dir.join(&filename))?;
810+
811+
Ok(())
812+
}
790813
}

src/cargo/core/compiler/mod.rs

Lines changed: 20 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -96,6 +96,7 @@ use self::unit_graph::UnitDep;
9696

9797
use crate::core::compiler::future_incompat::FutureIncompatReport;
9898
use crate::core::compiler::locking::LockKey;
99+
use crate::core::compiler::rustdoc::is_rustdoc_json_output;
99100
use crate::core::compiler::timings::SectionTiming;
100101
pub use crate::core::compiler::unit::Unit;
101102
pub use crate::core::compiler::unit::UnitIndex;
@@ -868,7 +869,16 @@ fn prepare_rustdoc(build_runner: &BuildRunner<'_, '_>, unit: &Unit) -> CargoResu
868869
add_cap_lints(bcx, unit, &mut rustdoc);
869870

870871
unit.kind.add_target_arg(&mut rustdoc);
871-
let doc_dir = build_runner.files().output_dir(unit);
872+
873+
let doc_dir = if is_rustdoc_json_output(build_runner) {
874+
// Always use new layout for '--output-format=json'.
875+
// In fix for https://github.com/rust-lang/cargo/issues/16291
876+
877+
build_runner.files().out_dir_new_layout(unit)
878+
} else {
879+
build_runner.files().output_dir(unit)
880+
};
881+
872882
rustdoc.arg("-o").arg(&doc_dir);
873883
rustdoc.args(&features_args(unit));
874884
rustdoc.args(&check_cfg_args(unit));
@@ -972,7 +982,9 @@ fn rustdoc(build_runner: &mut BuildRunner<'_, '_>, unit: &Unit) -> CargoResult<W
972982
let mut rustdoc = prepare_rustdoc(build_runner, unit)?;
973983

974984
let crate_name = unit.target.crate_name();
985+
let is_json_output = is_rustdoc_json_output(build_runner);
975986
let doc_dir = build_runner.files().output_dir(unit);
987+
let new_doc_dir = build_runner.files().out_dir_new_layout(unit);
976988
// Create the documentation directory ahead of time as rustdoc currently has
977989
// a bug where concurrent invocations will race to create this directory if
978990
// it doesn't already exist.
@@ -1055,12 +1067,17 @@ fn rustdoc(build_runner: &mut BuildRunner<'_, '_>, unit: &Unit) -> CargoResult<W
10551067
}
10561068
}
10571069

1058-
let crate_dir = doc_dir.join(&crate_name);
1070+
let crate_dir = if is_json_output {
1071+
new_doc_dir
1072+
} else {
1073+
doc_dir.join(&crate_name)
1074+
};
1075+
10591076
if crate_dir.exists() {
10601077
// Remove output from a previous build. This ensures that stale
10611078
// files for removed items are removed.
10621079
debug!("removing pre-existing doc directory {:?}", crate_dir);
1063-
paths::remove_dir_all(crate_dir)?;
1080+
paths::remove_dir_all(&crate_dir)?;
10641081
}
10651082
state.running(&rustdoc);
10661083
let timestamp = paths::set_invocation_time(&fingerprint_dir)?;

src/cargo/core/compiler/rustdoc.rs

Lines changed: 11 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -242,6 +242,12 @@ pub fn add_root_urls(
242242
Ok(())
243243
}
244244

245+
/// Checks whether JSON output should be enabled for rusdoc invocation
246+
pub fn is_rustdoc_json_output(build_runner: &BuildRunner<'_, '_>) -> bool {
247+
build_runner.bcx.build_config.intent.wants_doc_json_output()
248+
&& build_runner.bcx.gctx.cli_unstable().unstable_options
249+
}
250+
245251
/// Adds unstable flag [`--output-format`][1] to the given `rustdoc`
246252
/// invocation. This is for unstable feature `-Zunstable-features`.
247253
///
@@ -250,15 +256,13 @@ pub fn add_output_format(
250256
build_runner: &BuildRunner<'_, '_>,
251257
rustdoc: &mut ProcessBuilder,
252258
) -> CargoResult<()> {
253-
let gctx = build_runner.bcx.gctx;
254-
if !gctx.cli_unstable().unstable_options {
255-
tracing::debug!("`unstable-options` is ignored, required -Zunstable-options flag");
256-
return Ok(());
257-
}
258-
259-
if build_runner.bcx.build_config.intent.wants_doc_json_output() {
259+
if is_rustdoc_json_output(build_runner) {
260260
rustdoc.arg("-Zunstable-options");
261261
rustdoc.arg("--output-format=json");
262+
} else {
263+
if !build_runner.bcx.gctx.cli_unstable().unstable_options {
264+
tracing::debug!("`unstable-options` is ignored, required -Zunstable-options flag");
265+
}
262266
}
263267

264268
Ok(())

tests/testsuite/build_dir.rs

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -535,6 +535,7 @@ fn cargo_rustdoc_json_should_output_to_target_dir() {
535535
[ROOT]/foo/build-dir/debug/build/foo/[HASH]/fingerprint/doc-lib-foo
536536
[ROOT]/foo/build-dir/debug/build/foo/[HASH]/fingerprint/doc-lib-foo.json
537537
[ROOT]/foo/build-dir/debug/build/foo/[HASH]/fingerprint/invoked.timestamp
538+
[ROOT]/foo/build-dir/debug/build/foo/[HASH]/out/foo.json
538539
539540
"#
540541
]);

tests/testsuite/build_dir_legacy.rs

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -492,6 +492,7 @@ fn cargo_rustdoc_json_should_output_to_target_dir() {
492492
[ROOT]/foo/build-dir/debug/.fingerprint/foo-[HASH]/doc-lib-foo
493493
[ROOT]/foo/build-dir/debug/.fingerprint/foo-[HASH]/doc-lib-foo.json
494494
[ROOT]/foo/build-dir/debug/.fingerprint/foo-[HASH]/invoked.timestamp
495+
[ROOT]/foo/build-dir/debug/build/foo-[HASH]/out/foo.json
495496
496497
"#
497498
]);

tests/testsuite/rustdoc.rs

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -46,7 +46,7 @@ fn rustdoc_simple_json() {
4646
.masquerade_as_nightly_cargo(&["rustdoc-output-format"])
4747
.with_stderr_data(str![[r#"
4848
[DOCUMENTING] foo v0.0.1 ([ROOT]/foo)
49-
[RUNNING] `rustdoc [..] --crate-name foo [..]-o [ROOT]/foo/target/doc [..] --output-format=json[..]
49+
[RUNNING] `rustdoc [..] --crate-name foo [..]-o [ROOT]/foo/target/debug/build/foo-[HASH]/out [..] --output-format=json[..]
5050
[FINISHED] `dev` profile [unoptimized + debuginfo] target(s) in [ELAPSED]s
5151
[GENERATED] [ROOT]/foo/target/doc/foo.json
5252
@@ -63,7 +63,7 @@ fn rustdoc_json_with_new_layout() {
6363
.masquerade_as_nightly_cargo(&["rustdoc-output-format"])
6464
.with_stderr_data(str![[r#"
6565
[DOCUMENTING] foo v0.0.1 ([ROOT]/foo)
66-
[RUNNING] `rustdoc [..] --crate-name foo [..]-o [ROOT]/foo/target/doc [..] --output-format=json[..]
66+
[RUNNING] `rustdoc [..] --crate-name foo [..]-o [ROOT]/foo/target/debug/build/foo/[HASH]/out [..] --output-format=json[..]
6767
[FINISHED] `dev` profile [unoptimized + debuginfo] target(s) in [ELAPSED]s
6868
[GENERATED] [ROOT]/foo/target/doc/foo.json
6969
@@ -434,6 +434,6 @@ fn rustdoc_json_same_crate_different_version() {
434434
.run();
435435

436436
let dep_json = fs::read_to_string(entry.root().join("target/doc/dep.json")).unwrap();
437-
assert!(!dep_json.contains("dep_v1_fn"));
438-
assert!(dep_json.contains("dep_v2_fn"));
437+
assert!(dep_json.contains("dep_v1_fn"));
438+
assert!(!dep_json.contains("dep_v2_fn"));
439439
}

0 commit comments

Comments
 (0)