Skip to content

Commit 56f441b

Browse files
committed
Auto merge of #543 - jyn514:doc-runs, r=Mark-Simulacrum
Add a mode for reading docs.rs metadata when running rustdoc Closes #532 Before merging, I need to publish the `docsrs-metadata` package to crates.io so crater doesn't depend on a git version.
2 parents 34be8a1 + fbebafb commit 56f441b

13 files changed

+350
-33
lines changed

Cargo.lock

Lines changed: 11 additions & 0 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

Cargo.toml

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -20,6 +20,7 @@ crates-index = "0.16.2"
2020
crossbeam-utils = "0.5"
2121
crossbeam-channel = "0.5"
2222
csv = "1.0.2"
23+
docsrs-metadata = { git = "https://github.com/rust-lang/docs.rs/" }
2324
dotenv = "0.13"
2425
failure = "0.1.3"
2526
flate2 = "1"
Lines changed: 15 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,15 @@
1+
[package]
2+
name = "docs-rs-features"
3+
version = "0.1.0"
4+
authors = ["Joshua Nelson <[email protected]>"]
5+
edition = "2018"
6+
7+
# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html
8+
9+
[dependencies]
10+
11+
[package.metadata.docs.rs]
12+
features = ["docs_rs_feature"]
13+
14+
[features]
15+
docs_rs_feature = []
Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,6 @@
1+
#[cfg(feature = "docs_rs_feature")]
2+
compile_error!("oh no, a hidden regression!");
3+
4+
fn main() {
5+
println!("Hello, world!");
6+
}

src/runner/test.rs

Lines changed: 78 additions & 31 deletions
Original file line numberDiff line numberDiff line change
@@ -5,12 +5,13 @@ use crate::results::{BrokenReason, EncodingType, FailureReason, TestResult, Writ
55
use crate::runner::tasks::TaskCtx;
66
use crate::runner::OverrideResult;
77
use cargo_metadata::diagnostic::DiagnosticLevel;
8-
use cargo_metadata::{Message, Metadata, PackageId};
8+
use cargo_metadata::{Message, Metadata, Package, Target};
9+
use docsrs_metadata::Metadata as DocsrsMetadata;
910
use failure::Error;
1011
use remove_dir_all::remove_dir_all;
1112
use rustwide::cmd::{CommandError, ProcessLinesActions, SandboxBuilder};
1213
use rustwide::{Build, PrepareError};
13-
use std::collections::{BTreeSet, HashSet};
14+
use std::collections::{BTreeSet, HashMap, HashSet};
1415
use std::convert::TryFrom;
1516

1617
fn failure_reason(err: &Error) -> FailureReason {
@@ -64,7 +65,7 @@ pub(super) fn detect_broken<T>(res: Result<T, Error>) -> Result<T, Error> {
6465
}
6566
}
6667

67-
fn get_local_packages(build_env: &Build) -> Fallible<HashSet<PackageId>> {
68+
fn get_local_packages(build_env: &Build) -> Fallible<Vec<Package>> {
6869
Ok(build_env
6970
.cargo()
7071
.args(&["metadata", "--no-deps", "--format-version=1"])
@@ -73,17 +74,20 @@ fn get_local_packages(build_env: &Build) -> Fallible<HashSet<PackageId>> {
7374
.stdout_lines()
7475
.iter()
7576
.filter_map(|line| serde_json::from_str::<Metadata>(line).ok())
76-
.flat_map(|metadata| metadata.packages.into_iter().map(|pkg| pkg.id))
77-
.collect::<HashSet<_>>())
77+
.flat_map(|metadata| metadata.packages)
78+
.collect())
7879
}
7980

8081
fn run_cargo<DB: WriteResults>(
8182
ctx: &TaskCtx<DB>,
8283
build_env: &Build,
8384
args: &[&str],
8485
check_errors: bool,
85-
local_packages_id: &HashSet<PackageId>,
86+
local_packages: &[Package],
87+
env: HashMap<&'static str, String>,
8688
) -> Fallible<()> {
89+
let local_packages_id: HashSet<_> = local_packages.iter().map(|p| &p.id).collect();
90+
8791
let mut args = args.to_vec();
8892
if let Some(ref tc_cargoflags) = ctx.toolchain.cargoflags {
8993
args.extend(tc_cargoflags.split(' '));
@@ -167,6 +171,9 @@ fn run_cargo<DB: WriteResults>(
167171
.env("CARGO_INCREMENTAL", "0")
168172
.env("RUST_BACKTRACE", "full")
169173
.env(rustflags_env, rustflags);
174+
for (var, data) in env {
175+
command = command.env(var, data);
176+
}
170177

171178
if check_errors {
172179
command = command.process_lines(&mut detect_error);
@@ -197,7 +204,7 @@ fn run_cargo<DB: WriteResults>(
197204
pub(super) fn run_test<DB: WriteResults>(
198205
action: &str,
199206
ctx: &TaskCtx<DB>,
200-
test_fn: fn(&TaskCtx<DB>, &Build, &HashSet<PackageId>) -> Fallible<TestResult>,
207+
test_fn: fn(&TaskCtx<DB>, &Build, &[Package]) -> Fallible<TestResult>,
201208
) -> Fallible<()> {
202209
if let Some(res) = ctx
203210
.db
@@ -239,8 +246,8 @@ pub(super) fn run_test<DB: WriteResults>(
239246
}
240247

241248
detect_broken(build.run(|build| {
242-
let local_packages_id = get_local_packages(build)?;
243-
test_fn(ctx, build, &local_packages_id)
249+
let local_packages = get_local_packages(build)?;
250+
test_fn(ctx, build, &local_packages)
244251
}))
245252
},
246253
)?;
@@ -251,21 +258,23 @@ pub(super) fn run_test<DB: WriteResults>(
251258
fn build<DB: WriteResults>(
252259
ctx: &TaskCtx<DB>,
253260
build_env: &Build,
254-
local_packages_id: &HashSet<PackageId>,
261+
local_packages: &[Package],
255262
) -> Fallible<()> {
256263
run_cargo(
257264
ctx,
258265
build_env,
259266
&["build", "--frozen", "--message-format=json"],
260267
true,
261-
local_packages_id,
268+
local_packages,
269+
HashMap::default(),
262270
)?;
263271
run_cargo(
264272
ctx,
265273
build_env,
266274
&["test", "--frozen", "--no-run", "--message-format=json"],
267275
true,
268-
local_packages_id,
276+
local_packages,
277+
HashMap::default(),
269278
)?;
270279
Ok(())
271280
}
@@ -276,14 +285,15 @@ fn test<DB: WriteResults>(ctx: &TaskCtx<DB>, build_env: &Build) -> Fallible<()>
276285
build_env,
277286
&["test", "--frozen"],
278287
false,
279-
&HashSet::new(),
288+
&[],
289+
HashMap::default(),
280290
)
281291
}
282292

283293
pub(super) fn test_build_and_test<DB: WriteResults>(
284294
ctx: &TaskCtx<DB>,
285295
build_env: &Build,
286-
local_packages_id: &HashSet<PackageId>,
296+
local_packages_id: &[Package],
287297
) -> Fallible<TestResult> {
288298
let build_r = build(ctx, build_env, local_packages_id);
289299
let test_r = if build_r.is_ok() {
@@ -303,7 +313,7 @@ pub(super) fn test_build_and_test<DB: WriteResults>(
303313
pub(super) fn test_build_only<DB: WriteResults>(
304314
ctx: &TaskCtx<DB>,
305315
build_env: &Build,
306-
local_packages_id: &HashSet<PackageId>,
316+
local_packages_id: &[Package],
307317
) -> Fallible<TestResult> {
308318
if let Err(err) = build(ctx, build_env, local_packages_id) {
309319
Ok(TestResult::BuildFail(failure_reason(&err)))
@@ -315,7 +325,7 @@ pub(super) fn test_build_only<DB: WriteResults>(
315325
pub(super) fn test_check_only<DB: WriteResults>(
316326
ctx: &TaskCtx<DB>,
317327
build_env: &Build,
318-
local_packages_id: &HashSet<PackageId>,
328+
local_packages_id: &[Package],
319329
) -> Fallible<TestResult> {
320330
if let Err(err) = run_cargo(
321331
ctx,
@@ -329,6 +339,7 @@ pub(super) fn test_check_only<DB: WriteResults>(
329339
],
330340
true,
331341
local_packages_id,
342+
HashMap::default(),
332343
) {
333344
Ok(TestResult::BuildFail(failure_reason(&err)))
334345
} else {
@@ -339,7 +350,7 @@ pub(super) fn test_check_only<DB: WriteResults>(
339350
pub(super) fn test_clippy_only<DB: WriteResults>(
340351
ctx: &TaskCtx<DB>,
341352
build_env: &Build,
342-
local_packages_id: &HashSet<PackageId>,
353+
local_packages: &[Package],
343354
) -> Fallible<TestResult> {
344355
if let Err(err) = run_cargo(
345356
ctx,
@@ -352,7 +363,8 @@ pub(super) fn test_clippy_only<DB: WriteResults>(
352363
"--message-format=json",
353364
],
354365
true,
355-
local_packages_id,
366+
local_packages,
367+
HashMap::default(),
356368
) {
357369
Ok(TestResult::BuildFail(failure_reason(&err)))
358370
} else {
@@ -363,29 +375,64 @@ pub(super) fn test_clippy_only<DB: WriteResults>(
363375
pub(super) fn test_rustdoc<DB: WriteResults>(
364376
ctx: &TaskCtx<DB>,
365377
build_env: &Build,
366-
local_packages_id: &HashSet<PackageId>,
378+
local_packages: &[Package],
367379
) -> Fallible<TestResult> {
368-
let res = run_cargo(
369-
ctx,
370-
build_env,
380+
let run = |cargo_args, env| {
381+
let res = run_cargo(ctx, build_env, cargo_args, true, local_packages, env);
382+
383+
// Make sure to remove the built documentation
384+
// There is no point in storing it after the build is done
385+
remove_dir_all(&build_env.host_target_dir().join("doc"))?;
386+
387+
res
388+
};
389+
390+
// first, run a normal `cargo doc`
391+
let res = run(
371392
&[
372393
"doc",
373394
"--frozen",
374395
"--no-deps",
375396
"--document-private-items",
376397
"--message-format=json",
377398
],
378-
true,
379-
local_packages_id,
399+
HashMap::default(),
380400
);
401+
if let Err(err) = res {
402+
return Ok(TestResult::BuildFail(failure_reason(&err)));
403+
}
381404

382-
// Make sure to remove the built documentation
383-
// There is no point in storing it after the build is done
384-
remove_dir_all(&build_env.host_target_dir().join("doc"))?;
405+
// next, if this is a library, run it with docs.rs metadata applied.
406+
if local_packages
407+
.iter()
408+
.any(|p| p.targets.iter().any(is_library))
409+
{
410+
let src = build_env.host_source_dir();
411+
let metadata = DocsrsMetadata::from_crate_root(src)?;
412+
let cargo_args = metadata.cargo_args(
413+
&["--frozen".into(), "--message-format=json".into()],
414+
&["--document-private-items".into()],
415+
);
416+
assert_eq!(cargo_args[0], "rustdoc");
417+
let cargo_args: Vec<_> = cargo_args.iter().map(|s| s.as_str()).collect();
418+
let mut env = metadata.environment_variables();
419+
// docsrs-metadata requires a nightly environment, but crater sometimes runs tests on beta and
420+
// stable.
421+
env.insert("RUSTC_BOOTSTRAP", "1".to_string());
385422

386-
if let Err(err) = res {
387-
Ok(TestResult::BuildFail(failure_reason(&err)))
388-
} else {
389-
Ok(TestResult::TestPass)
423+
if let Err(err) = run(&cargo_args, env) {
424+
return Ok(TestResult::BuildFail(failure_reason(&err)));
425+
}
390426
}
427+
428+
Ok(TestResult::TestPass)
429+
}
430+
431+
fn is_library(target: &Target) -> bool {
432+
// Some examples and tests can be libraries (e.g. if they use `cdylib`).
433+
target.crate_types.iter().any(|ty| ty != "bin")
434+
&& target
435+
.kind
436+
.iter()
437+
.all(|k| !["example", "test", "bench"].contains(&k.as_str()))
391438
}

src/runner/unstable_features.rs

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -2,7 +2,7 @@ use crate::prelude::*;
22
use crate::results::TestResult;
33
use crate::results::WriteResults;
44
use crate::runner::tasks::TaskCtx;
5-
use cargo_metadata::PackageId;
5+
use cargo_metadata::Package;
66
use rustwide::Build;
77
use std::collections::HashSet;
88
use std::path::Path;
@@ -11,7 +11,7 @@ use walkdir::{DirEntry, WalkDir};
1111
pub(super) fn find_unstable_features<DB: WriteResults>(
1212
_ctx: &TaskCtx<DB>,
1313
build: &Build,
14-
_local_packages_id: &HashSet<PackageId>,
14+
_local_packages_id: &[Package],
1515
) -> Fallible<TestResult> {
1616
let mut features = HashSet::new();
1717

tests/minicrater/doc/config.toml

Lines changed: 27 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,27 @@
1+
[server.bot-acl]
2+
rust-teams = true
3+
github = ["pietroalbini"]
4+
5+
[server.labels]
6+
remove = "^S-"
7+
experiment-queued = "S-waiting-on-crater"
8+
experiment-completed = "S-waiting-on-review"
9+
10+
[server.distributed]
11+
chunk-size = 32
12+
13+
[demo-crates]
14+
crates = []
15+
github-repos = []
16+
local-crates = ["build-pass", "docs-rs-features"]
17+
18+
[sandbox]
19+
memory-limit = "512M"
20+
build-log-max-size = "2M"
21+
build-log-max-lines = 1000
22+
23+
[crates]
24+
25+
[github-repos]
26+
27+
[local-crates]
Lines changed: 34 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,34 @@
1+
{
2+
"available_archives": [
3+
{
4+
"name": "All the crates",
5+
"path": "logs-archives/all.tar.gz"
6+
},
7+
{
8+
"name": "test-pass crates",
9+
"path": "logs-archives/test-pass.tar.gz"
10+
},
11+
{
12+
"name": "build-fail crates",
13+
"path": "logs-archives/build-fail.tar.gz"
14+
}
15+
],
16+
"crates_count": 2,
17+
"nav": [
18+
{
19+
"active": false,
20+
"label": "Summary",
21+
"url": "index.html"
22+
},
23+
{
24+
"active": false,
25+
"label": "Full report",
26+
"url": "full.html"
27+
},
28+
{
29+
"active": true,
30+
"label": "Downloads",
31+
"url": "downloads.html"
32+
}
33+
]
34+
}

0 commit comments

Comments
 (0)