Skip to content

Commit c26ed63

Browse files
committed
Add doc comments to explain scrape-examples feature
1 parent b325a8d commit c26ed63

File tree

8 files changed

+97
-74
lines changed

8 files changed

+97
-74
lines changed

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

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -78,6 +78,9 @@ pub struct Context<'a, 'cfg> {
7878
/// See Context::find_metadata_units for more details.
7979
pub metadata_for_doc_units: HashMap<Unit, Metadata>,
8080

81+
/// Set of metadata of Docscrape units that fail before completion, e.g.
82+
/// because the target has a type error. This is in an Arc<Mutex<..>>
83+
/// because it is continuously updated as the job progresses.
8184
pub failed_scrape_units: Arc<Mutex<HashSet<Metadata>>>,
8285
}
8386

src/cargo/core/compiler/job_queue.rs

Lines changed: 14 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -348,23 +348,29 @@ enum Message {
348348
BuildPlanMsg(String, ProcessBuilder, Arc<Vec<OutputFile>>),
349349
Stdout(String),
350350
Stderr(String),
351+
352+
// This is for general stderr output from subprocesses
351353
Diagnostic {
352354
id: JobId,
353355
level: String,
354356
diag: String,
355357
fixable: bool,
356358
},
357-
// This is distinct from Diagnostic because it gets emitted through
358-
// a different Shell pathway
359-
Warning {
360-
id: JobId,
361-
warning: String,
362-
},
359+
// This handles duplicate output that is suppressed, for showing
360+
// only a count of duplicate messages instead
363361
WarningCount {
364362
id: JobId,
365363
emitted: bool,
366364
fixable: bool,
367365
},
366+
// This is for warnings generated by Cargo's interpretation of the
367+
// subprocess output, e.g. scrape-examples prints a warning if a
368+
// unit fails to be scraped
369+
Warning {
370+
id: JobId,
371+
warning: String,
372+
},
373+
368374
FixDiagnostic(diagnostic_server::Message),
369375
Token(io::Result<Acquired>),
370376
Finish(JobId, Artifact, CargoResult<()>),
@@ -412,6 +418,7 @@ impl<'a, 'cfg> JobState<'a, 'cfg> {
412418
Ok(())
413419
}
414420

421+
/// See [`Message::Diagnostic`] and [`Message::WarningCount`].
415422
pub fn emit_diag(&self, level: String, diag: String, fixable: bool) -> CargoResult<()> {
416423
if let Some(dedupe) = self.output {
417424
let emitted = dedupe.emit_diag(&diag)?;
@@ -433,6 +440,7 @@ impl<'a, 'cfg> JobState<'a, 'cfg> {
433440
Ok(())
434441
}
435442

443+
/// See [`Message::Warning`].
436444
pub fn warning(&self, warning: String) -> CargoResult<()> {
437445
self.messages.push_bounded(Message::Warning {
438446
id: self.id,

src/cargo/core/compiler/mod.rs

Lines changed: 1 addition & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -654,8 +654,7 @@ fn rustdoc(cx: &mut Context<'_, '_>, unit: &Unit) -> CargoResult<Work> {
654654
rustdoc.arg("-C").arg(format!("metadata={}", metadata));
655655

656656
let scrape_output_path = |unit: &Unit| -> CargoResult<PathBuf> {
657-
cx.outputs(unit)
658-
.map(|outputs| outputs[0].path.to_path_buf())
657+
cx.outputs(unit).map(|outputs| outputs[0].path.clone())
659658
};
660659

661660
if unit.mode.is_doc_scrape() {

src/cargo/core/compiler/rustdoc.rs

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -191,6 +191,8 @@ pub fn add_root_urls(
191191
Ok(())
192192
}
193193

194+
/// Indicates whether a target should have examples scraped from it
195+
/// by rustdoc. Configured within Cargo.toml.
194196
#[derive(Clone, Hash, PartialEq, Eq, PartialOrd, Ord, Debug, Copy)]
195197
pub enum RustdocScrapeExamples {
196198
Enabled,

src/cargo/core/manifest.rs

Lines changed: 1 addition & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -12,6 +12,7 @@ use serde::Serialize;
1212
use toml_edit::easy as toml;
1313
use url::Url;
1414

15+
use crate::core::compiler::rustdoc::RustdocScrapeExamples;
1516
use crate::core::compiler::{CompileKind, CrateType};
1617
use crate::core::resolver::ResolveBehavior;
1718
use crate::core::{Dependency, PackageId, PackageIdSpec, SourceId, Summary};
@@ -21,8 +22,6 @@ use crate::util::interning::InternedString;
2122
use crate::util::toml::{TomlManifest, TomlProfiles};
2223
use crate::util::{short_hash, Config, Filesystem};
2324

24-
use super::compiler::rustdoc::RustdocScrapeExamples;
25-
2625
pub enum EitherManifest {
2726
Real(Manifest),
2827
Virtual(VirtualManifest),

src/cargo/ops/cargo_compile/compile_filter.rs

Lines changed: 66 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,9 @@
11
//! Filters and their rules to select which Cargo targets will be built.
22
33
use crate::core::compiler::CompileMode;
4-
use crate::core::{Target, TargetKind};
4+
use crate::core::dependency::DepKind;
5+
use crate::core::resolver::HasDevUnits;
6+
use crate::core::{Package, Target, TargetKind};
57
use crate::util::restricted_names::is_glob_pattern;
68

79
#[derive(Debug, PartialEq, Eq, Clone)]
@@ -299,4 +301,67 @@ impl CompileFilter {
299301
}
300302
}
301303
}
304+
305+
/// Generate a CompileFilter that represents the maximal set of targets
306+
/// that should be considered for scraped examples.
307+
pub(super) fn refine_for_docscrape(
308+
&self,
309+
to_builds: &[&Package],
310+
has_dev_units: HasDevUnits,
311+
) -> CompileFilter {
312+
// In general, the goal is to scrape examples from (a) whatever targets
313+
// the user is documenting, and (b) Example targets. However, if the user
314+
// is documenting a library with dev-dependencies, those dev-deps are not
315+
// needed for the library, while dev-deps are needed for the examples.
316+
//
317+
// If scrape-examples caused `cargo doc` to start requiring dev-deps, this
318+
// would be a breaking change to crates whose dev-deps don't compile.
319+
// Therefore we ONLY want to scrape Example targets if either:
320+
// (1) No package has dev-dependencies, so this is a moot issue, OR
321+
// (2) The provided CompileFilter requires dev-dependencies anyway.
322+
//
323+
// The next two variables represent these two conditions.
324+
325+
let no_pkg_has_dev_deps = to_builds.iter().all(|pkg| {
326+
pkg.summary()
327+
.dependencies()
328+
.iter()
329+
.all(|dep| !matches!(dep.kind(), DepKind::Development))
330+
});
331+
332+
let reqs_dev_deps = matches!(has_dev_units, HasDevUnits::Yes);
333+
334+
let example_filter = if no_pkg_has_dev_deps || reqs_dev_deps {
335+
FilterRule::All
336+
} else {
337+
FilterRule::none()
338+
};
339+
340+
match self {
341+
CompileFilter::Only {
342+
all_targets,
343+
lib,
344+
bins,
345+
tests,
346+
benches,
347+
..
348+
} => CompileFilter::Only {
349+
all_targets: *all_targets,
350+
lib: lib.clone(),
351+
bins: bins.clone(),
352+
examples: example_filter,
353+
tests: tests.clone(),
354+
benches: benches.clone(),
355+
},
356+
357+
CompileFilter::Default { .. } => CompileFilter::Only {
358+
all_targets: false,
359+
lib: LibRule::Default,
360+
bins: FilterRule::none(),
361+
examples: example_filter,
362+
tests: FilterRule::none(),
363+
benches: FilterRule::none(),
364+
},
365+
}
366+
}
302367
}

src/cargo/ops/cargo_compile/mod.rs

Lines changed: 1 addition & 52 deletions
Original file line numberDiff line numberDiff line change
@@ -41,7 +41,6 @@ use crate::core::compiler::{standard_lib, CrateType, TargetInfo};
4141
use crate::core::compiler::{BuildConfig, BuildContext, Compilation, Context};
4242
use crate::core::compiler::{CompileKind, CompileMode, CompileTarget, RustcTargetData, Unit};
4343
use crate::core::compiler::{DefaultExecutor, Executor, UnitInterner};
44-
use crate::core::dependency::DepKind;
4544
use crate::core::profiles::{Profiles, UnitFor};
4645
use crate::core::resolver::features::{self, CliFeatures, FeaturesFor};
4746
use crate::core::resolver::{HasDevUnits, Resolve};
@@ -370,7 +369,7 @@ pub fn create_bcx<'a, 'cfg>(
370369

371370
let should_scrape = build_config.mode.is_doc() && config.cli_unstable().rustdoc_scrape_examples;
372371
let mut scrape_units = if should_scrape {
373-
let scrape_filter = filter_for_scrape_units(&to_builds, has_dev_units, filter);
372+
let scrape_filter = filter.refine_for_docscrape(&to_builds, has_dev_units);
374373
let all_units = generate_targets(
375374
ws,
376375
&to_builds,
@@ -567,56 +566,6 @@ pub fn create_bcx<'a, 'cfg>(
567566
Ok(bcx)
568567
}
569568

570-
/// Generate a CompileFilter that represents the maximal set of targets that should be
571-
/// considered for scraping. Should be a subset of the CLI-provided CompileFilter.
572-
fn filter_for_scrape_units(
573-
to_builds: &[&Package],
574-
has_dev_units: HasDevUnits,
575-
filter: &CompileFilter,
576-
) -> CompileFilter {
577-
let no_pkg_has_dev_deps = to_builds.iter().all(|pkg| {
578-
pkg.summary()
579-
.dependencies()
580-
.iter()
581-
.all(|dep| !matches!(dep.kind(), DepKind::Development))
582-
});
583-
584-
// We are allowed to include examples ONLY if they cannot possibly require dev dependencies,
585-
// or if dev dependencies are already required anyway due to the user's configuration.
586-
let example_filter = if matches!(has_dev_units, HasDevUnits::Yes) || no_pkg_has_dev_deps {
587-
FilterRule::All
588-
} else {
589-
FilterRule::none()
590-
};
591-
592-
match filter {
593-
CompileFilter::Only {
594-
all_targets,
595-
lib,
596-
bins,
597-
tests,
598-
benches,
599-
..
600-
} => CompileFilter::Only {
601-
all_targets: *all_targets,
602-
lib: lib.clone(),
603-
bins: bins.clone(),
604-
examples: example_filter,
605-
tests: tests.clone(),
606-
benches: benches.clone(),
607-
},
608-
609-
CompileFilter::Default { .. } => CompileFilter::Only {
610-
all_targets: false,
611-
lib: LibRule::Default,
612-
bins: FilterRule::none(),
613-
examples: example_filter,
614-
tests: FilterRule::none(),
615-
benches: FilterRule::none(),
616-
},
617-
}
618-
}
619-
620569
/// A proposed target.
621570
///
622571
/// Proposed targets are later filtered into actual `Unit`s based on whether or

tests/testsuite/docscrape.rs

Lines changed: 9 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,5 @@
1-
//! Tests for the `cargo doc` command.
1+
//! Tests for the `cargo doc` command with `-Zrustdoc-scrape-examples`.
22
3-
use cargo_test_support::is_nightly;
43
use cargo_test_support::project;
54

65
#[cargo_test(nightly, reason = "rustdoc scrape examples flags are unstable")]
@@ -41,11 +40,6 @@ fn basic() {
4140

4241
#[cargo_test(nightly, reason = "rustdoc scrape examples flags are unstable")]
4342
fn avoid_build_script_cycle() {
44-
if !is_nightly() {
45-
// -Z rustdoc-scrape-examples is unstable
46-
return;
47-
}
48-
4943
let p = project()
5044
// package with build dependency
5145
.file(
@@ -81,7 +75,7 @@ fn avoid_build_script_cycle() {
8175
.file("bar/build.rs", "fn main(){}")
8276
.build();
8377

84-
p.cargo("doc --all -Zunstable-options -Zrustdoc-scrape-examples")
78+
p.cargo("doc --workspace -Zunstable-options -Zrustdoc-scrape-examples")
8579
.masquerade_as_nightly_cargo(&["rustdoc-scrape-examples"])
8680
.run();
8781
}
@@ -138,7 +132,7 @@ fn complex_reverse_dependencies() {
138132
.file("b/src/lib.rs", "")
139133
.build();
140134

141-
p.cargo("doc --all --examples -Zunstable-options -Zrustdoc-scrape-examples")
135+
p.cargo("doc --workspace --examples -Zunstable-options -Zrustdoc-scrape-examples")
142136
.masquerade_as_nightly_cargo(&["rustdoc-scrape-examples"])
143137
.run();
144138
}
@@ -208,7 +202,7 @@ fn configure_target() {
208202
}
209203

210204
#[cargo_test(nightly, reason = "rustdoc scrape examples flags are unstable")]
211-
fn configure_profile() {
205+
fn configure_profile_issue_10500() {
212206
let p = project()
213207
.file(
214208
"Cargo.toml",
@@ -277,7 +271,7 @@ fn issue_10545() {
277271
.file("b/src/lib.rs", "")
278272
.build();
279273

280-
p.cargo("doc --all -Zunstable-options -Zrustdoc-scrape-examples")
274+
p.cargo("doc --workspace -Zunstable-options -Zrustdoc-scrape-examples")
281275
.masquerade_as_nightly_cargo(&["rustdoc-scrape-examples"])
282276
.run();
283277
}
@@ -412,6 +406,10 @@ error: expected one of `!` or `::`, found `NOT`
412406

413407
#[cargo_test(nightly, reason = "rustdoc scrape examples flags are unstable")]
414408
fn no_scrape_with_dev_deps() {
409+
// Tests that a crate with dev-dependencies does not have its examples
410+
// scraped unless explicitly prompted to check them. See
411+
// `CompileFilter::refine_for_docscrape` for details on why.
412+
415413
let p = project()
416414
.file(
417415
"Cargo.toml",

0 commit comments

Comments
 (0)