From 6a3aae8aea2448432d4fd0f7c3a22778beaab831 Mon Sep 17 00:00:00 2001 From: David Tolnay Date: Thu, 21 May 2020 19:48:44 -0700 Subject: [PATCH] Add flag to open docs: x.py doc --open Tested with: # opens doc/index.html x.py doc --stage 0 --open x.py doc --stage 0 --open src/doc # opens doc/book/index.html x.py doc --stage 0 --open src/doc/book # opens doc/std/index.html x.py doc --stage 0 --open src/libstd # opens doc/proc_macro/index.html x.py doc --stage 0 --open src/libproc_macro # opens both x.py doc --stage 0 --open src/libstd src/libproc_macro --- Cargo.lock | 1 + src/bootstrap/Cargo.toml | 1 + src/bootstrap/builder.rs | 2 +- src/bootstrap/doc.rs | 59 +++++++++++++++++++++++++++++++++++++++- src/bootstrap/flags.rs | 14 +++++++++- 5 files changed, 74 insertions(+), 3 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index d81fd6e8d3a..b0b9e2c27df 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -213,6 +213,7 @@ dependencies = [ "lazy_static 1.4.0", "libc", "num_cpus", + "opener", "pretty_assertions", "serde", "serde_json", diff --git a/src/bootstrap/Cargo.toml b/src/bootstrap/Cargo.toml index f7856f6a7fc..c4918d7f2e7 100644 --- a/src/bootstrap/Cargo.toml +++ b/src/bootstrap/Cargo.toml @@ -48,6 +48,7 @@ toml = "0.5" lazy_static = "1.3.0" time = "0.1" ignore = "0.4.10" +opener = "0.4" [target.'cfg(windows)'.dependencies.winapi] version = "0.3" diff --git a/src/bootstrap/builder.rs b/src/bootstrap/builder.rs index 4bc81a7b42d..5489b1bc66b 100644 --- a/src/bootstrap/builder.rs +++ b/src/bootstrap/builder.rs @@ -503,7 +503,7 @@ impl<'a> Builder<'a> { Subcommand::Check { ref paths } => (Kind::Check, &paths[..]), Subcommand::Clippy { ref paths } => (Kind::Clippy, &paths[..]), Subcommand::Fix { ref paths } => (Kind::Fix, &paths[..]), - Subcommand::Doc { ref paths } => (Kind::Doc, &paths[..]), + Subcommand::Doc { ref paths, .. } => (Kind::Doc, &paths[..]), Subcommand::Test { ref paths, .. } => (Kind::Test, &paths[..]), Subcommand::Bench { ref paths, .. } => (Kind::Bench, &paths[..]), Subcommand::Dist { ref paths } => (Kind::Dist, &paths[..]), diff --git a/src/bootstrap/doc.rs b/src/bootstrap/doc.rs index 7eab92ddc92..be5e3bfee30 100644 --- a/src/bootstrap/doc.rs +++ b/src/bootstrap/doc.rs @@ -70,6 +70,35 @@ book!( RustdocBook, "src/doc/rustdoc", "rustdoc"; ); +fn open(builder: &Builder<'_>, path: impl AsRef) { + if builder.config.dry_run || !builder.config.cmd.open() { + return; + } + + let path = path.as_ref(); + builder.info(&format!("Opening doc {}", path.to_string_lossy())); + + // ignore error + let _ = opener::open(path); +} + +// "src/libstd" -> ["src", "libstd"] +// +// Used for deciding whether a particular step is one requested by the user on +// the `x.py doc` command line, which determines whether `--open` will open that +// page. +fn components_simplified(path: &PathBuf) -> Vec<&str> { + path.iter().map(|component| component.to_str().unwrap_or("???")).collect() +} + +fn is_explicit_request(builder: &Builder<'_>, path: &str) -> bool { + builder + .paths + .iter() + .map(components_simplified) + .any(|requested| requested.iter().copied().eq(path.split("/"))) +} + #[derive(Debug, Copy, Clone, Hash, PartialEq, Eq)] pub struct UnstableBook { target: Interned, @@ -200,6 +229,12 @@ impl Step for TheBook { invoke_rustdoc(builder, compiler, target, path); } + + if is_explicit_request(builder, "src/doc/book") { + let out = builder.doc_out(target); + let index = out.join("book").join("index.html"); + open(builder, &index); + } } } @@ -338,6 +373,13 @@ impl Step for Standalone { } builder.run(&mut cmd); } + + // We open doc/index.html as the default if invoked as `x.py doc --open` + // with no particular explicit doc requested (e.g. src/libcore). + if builder.paths.is_empty() || is_explicit_request(builder, "src/doc") { + let index = out.join("index.html"); + open(builder, &index); + } } } @@ -418,10 +460,25 @@ impl Step for Std { builder.run(&mut cargo.into()); }; - for krate in &["alloc", "core", "std", "proc_macro", "test"] { + let krates = ["alloc", "core", "std", "proc_macro", "test"]; + for krate in &krates { run_cargo_rustdoc_for(krate); } builder.cp_r(&my_out, &out); + + // Look for src/libstd, src/libcore etc in the `x.py doc` arguments and + // open the corresponding rendered docs. + for path in builder.paths.iter().map(components_simplified) { + if path.get(0) == Some(&"src") + && path.get(1).map_or(false, |dir| dir.starts_with("lib")) + { + let requested_crate = &path[1][3..]; + if krates.contains(&requested_crate) { + let index = out.join(requested_crate).join("index.html"); + open(builder, &index); + } + } + } } } diff --git a/src/bootstrap/flags.rs b/src/bootstrap/flags.rs index 646b9e05d99..cfaa43f3970 100644 --- a/src/bootstrap/flags.rs +++ b/src/bootstrap/flags.rs @@ -61,6 +61,7 @@ pub enum Subcommand { }, Doc { paths: Vec, + open: bool, }, Test { paths: Vec, @@ -248,6 +249,9 @@ To learn more about a subcommand, run `./x.py -h`", "bench" => { opts.optmulti("", "test-args", "extra arguments", "ARGS"); } + "doc" => { + opts.optflag("", "open", "open the docs in a browser"); + } "clean" => { opts.optflag("", "all", "clean all build artifacts"); } @@ -404,6 +408,7 @@ Arguments: ./x.py doc src/doc/book ./x.py doc src/doc/nomicon ./x.py doc src/doc/book src/libstd + ./x.py doc src/libstd --open If no arguments are passed then everything is documented: @@ -479,7 +484,7 @@ Arguments: }, }, "bench" => Subcommand::Bench { paths, test_args: matches.opt_strs("test-args") }, - "doc" => Subcommand::Doc { paths }, + "doc" => Subcommand::Doc { paths, open: matches.opt_present("open") }, "clean" => { if !paths.is_empty() { println!("\nclean does not take a path argument\n"); @@ -613,6 +618,13 @@ impl Subcommand { _ => None, } } + + pub fn open(&self) -> bool { + match *self { + Subcommand::Doc { open, .. } => open, + _ => false, + } + } } fn split(s: &[String]) -> Vec {