Clippy dev subcommand to build and serve website

This commit is contained in:
David Tolnay
2020-10-08 05:18:22 -07:00
parent 171ab9bf9f
commit e6a71066c8
5 changed files with 87 additions and 2 deletions

View File

@@ -8,6 +8,7 @@ edition = "2018"
bytecount = "0.6" bytecount = "0.6"
clap = "2.33" clap = "2.33"
itertools = "0.9" itertools = "0.9"
opener = "0.4"
regex = "1" regex = "1"
shell-escape = "0.1" shell-escape = "0.1"
walkdir = "2" walkdir = "2"

View File

@@ -13,6 +13,7 @@ use walkdir::WalkDir;
pub mod fmt; pub mod fmt;
pub mod new_lint; pub mod new_lint;
pub mod ra_setup; pub mod ra_setup;
pub mod serve;
pub mod stderr_length_check; pub mod stderr_length_check;
pub mod update_lints; pub mod update_lints;

View File

@@ -1,7 +1,7 @@
#![cfg_attr(feature = "deny-warnings", deny(warnings))] #![cfg_attr(feature = "deny-warnings", deny(warnings))]
use clap::{App, Arg, SubCommand}; use clap::{App, Arg, SubCommand};
use clippy_dev::{fmt, new_lint, ra_setup, stderr_length_check, update_lints}; use clippy_dev::{fmt, new_lint, ra_setup, serve, stderr_length_check, update_lints};
fn main() { fn main() {
let matches = App::new("Clippy developer tooling") let matches = App::new("Clippy developer tooling")
@@ -100,6 +100,19 @@ fn main() {
.required(true), .required(true),
), ),
) )
.subcommand(
SubCommand::with_name("serve")
.about("Launch a local 'ALL the Clippy Lints' website in a browser")
.arg(
Arg::with_name("port")
.long("port")
.short("p")
.help("Local port for the http server")
.default_value("8000")
.validator_os(serve::validate_port),
)
.arg(Arg::with_name("lint").help("Which lint's page to load initially (optional)")),
)
.get_matches(); .get_matches();
match matches.subcommand() { match matches.subcommand() {
@@ -129,6 +142,11 @@ fn main() {
stderr_length_check::check(); stderr_length_check::check();
}, },
("ra-setup", Some(matches)) => ra_setup::run(matches.value_of("rustc-repo-path")), ("ra-setup", Some(matches)) => ra_setup::run(matches.value_of("rustc-repo-path")),
("serve", Some(matches)) => {
let port = matches.value_of("port").unwrap().parse().unwrap();
let lint = matches.value_of("lint");
serve::run(port, lint);
},
_ => {}, _ => {},
} }
} }

64
clippy_dev/src/serve.rs Normal file
View File

@@ -0,0 +1,64 @@
use std::ffi::{OsStr, OsString};
use std::path::Path;
use std::process::Command;
use std::thread;
use std::time::{Duration, SystemTime};
pub fn run(port: u16, lint: Option<&str>) -> ! {
let mut url = Some(match lint {
None => format!("http://localhost:{}", port),
Some(lint) => format!("http://localhost:{}/#{}", port, lint),
});
loop {
if mtime("util/gh-pages/lints.json") < mtime("clippy_lints/src") {
Command::new("python3")
.arg("util/export.py")
.spawn()
.unwrap()
.wait()
.unwrap();
}
if let Some(url) = url.take() {
thread::spawn(move || {
Command::new("python3")
.arg("-m")
.arg("http.server")
.arg(port.to_string())
.current_dir("util/gh-pages")
.spawn()
.unwrap();
// Give some time for python to start
thread::sleep(Duration::from_millis(500));
// Launch browser after first export.py has completed and http.server is up
let _ = opener::open(url);
});
}
thread::sleep(Duration::from_millis(1000));
}
}
fn mtime(path: impl AsRef<Path>) -> SystemTime {
let path = path.as_ref();
if path.is_dir() {
path.read_dir()
.into_iter()
.flatten()
.flatten()
.map(|entry| mtime(&entry.path()))
.max()
.unwrap_or(SystemTime::UNIX_EPOCH)
} else {
path.metadata()
.and_then(|metadata| metadata.modified())
.unwrap_or(SystemTime::UNIX_EPOCH)
}
}
#[allow(clippy::missing_errors_doc)]
pub fn validate_port(arg: &OsStr) -> Result<(), OsString> {
match arg.to_string_lossy().parse::<u16>() {
Ok(_port) => Ok(()),
Err(err) => Err(OsString::from(err.to_string())),
}
}

View File

@@ -189,7 +189,8 @@ declare_clippy_lint! {
* The section of lines prefixed with `///` constitutes the lint documentation * The section of lines prefixed with `///` constitutes the lint documentation
section. This is the default documentation style and will be displayed section. This is the default documentation style and will be displayed
[like this][example_lint_page]. [like this][example_lint_page]. To render and open this documentation locally
in a browser, run `cargo dev serve`.
* `FOO_FUNCTIONS` is the name of our lint. Be sure to follow the * `FOO_FUNCTIONS` is the name of our lint. Be sure to follow the
[lint naming guidelines][lint_naming] here when naming your lint. [lint naming guidelines][lint_naming] here when naming your lint.
In short, the name should state the thing that is being checked for and In short, the name should state the thing that is being checked for and