Skip to content

Commit 2f6439a

Browse files
committed
Auto merge of #6136 - dtolnay:serve, r=flip1995
Clippy dev subcommand to build and serve website This PR adds `clippy dev serve` which will pop open a browser with a local rendered 'ALL the Clippy Lints' website, and re-render as you edit stuff. --- changelog: none
2 parents 6fb3b2c + e6a7106 commit 2f6439a

File tree

5 files changed

+87
-2
lines changed

5 files changed

+87
-2
lines changed

clippy_dev/Cargo.toml

+1
Original file line numberDiff line numberDiff line change
@@ -8,6 +8,7 @@ edition = "2018"
88
bytecount = "0.6"
99
clap = "2.33"
1010
itertools = "0.9"
11+
opener = "0.4"
1112
regex = "1"
1213
shell-escape = "0.1"
1314
walkdir = "2"

clippy_dev/src/lib.rs

+1
Original file line numberDiff line numberDiff line change
@@ -13,6 +13,7 @@ use walkdir::WalkDir;
1313
pub mod fmt;
1414
pub mod new_lint;
1515
pub mod ra_setup;
16+
pub mod serve;
1617
pub mod stderr_length_check;
1718
pub mod update_lints;
1819

clippy_dev/src/main.rs

+19-1
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,7 @@
11
#![cfg_attr(feature = "deny-warnings", deny(warnings))]
22

33
use clap::{App, Arg, SubCommand};
4-
use clippy_dev::{fmt, new_lint, ra_setup, stderr_length_check, update_lints};
4+
use clippy_dev::{fmt, new_lint, ra_setup, serve, stderr_length_check, update_lints};
55

66
fn main() {
77
let matches = App::new("Clippy developer tooling")
@@ -100,6 +100,19 @@ fn main() {
100100
.required(true),
101101
),
102102
)
103+
.subcommand(
104+
SubCommand::with_name("serve")
105+
.about("Launch a local 'ALL the Clippy Lints' website in a browser")
106+
.arg(
107+
Arg::with_name("port")
108+
.long("port")
109+
.short("p")
110+
.help("Local port for the http server")
111+
.default_value("8000")
112+
.validator_os(serve::validate_port),
113+
)
114+
.arg(Arg::with_name("lint").help("Which lint's page to load initially (optional)")),
115+
)
103116
.get_matches();
104117

105118
match matches.subcommand() {
@@ -129,6 +142,11 @@ fn main() {
129142
stderr_length_check::check();
130143
},
131144
("ra-setup", Some(matches)) => ra_setup::run(matches.value_of("rustc-repo-path")),
145+
("serve", Some(matches)) => {
146+
let port = matches.value_of("port").unwrap().parse().unwrap();
147+
let lint = matches.value_of("lint");
148+
serve::run(port, lint);
149+
},
132150
_ => {},
133151
}
134152
}

clippy_dev/src/serve.rs

+64
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,64 @@
1+
use std::ffi::{OsStr, OsString};
2+
use std::path::Path;
3+
use std::process::Command;
4+
use std::thread;
5+
use std::time::{Duration, SystemTime};
6+
7+
pub fn run(port: u16, lint: Option<&str>) -> ! {
8+
let mut url = Some(match lint {
9+
None => format!("http://localhost:{}", port),
10+
Some(lint) => format!("http://localhost:{}/#{}", port, lint),
11+
});
12+
13+
loop {
14+
if mtime("util/gh-pages/lints.json") < mtime("clippy_lints/src") {
15+
Command::new("python3")
16+
.arg("util/export.py")
17+
.spawn()
18+
.unwrap()
19+
.wait()
20+
.unwrap();
21+
}
22+
if let Some(url) = url.take() {
23+
thread::spawn(move || {
24+
Command::new("python3")
25+
.arg("-m")
26+
.arg("http.server")
27+
.arg(port.to_string())
28+
.current_dir("util/gh-pages")
29+
.spawn()
30+
.unwrap();
31+
// Give some time for python to start
32+
thread::sleep(Duration::from_millis(500));
33+
// Launch browser after first export.py has completed and http.server is up
34+
let _ = opener::open(url);
35+
});
36+
}
37+
thread::sleep(Duration::from_millis(1000));
38+
}
39+
}
40+
41+
fn mtime(path: impl AsRef<Path>) -> SystemTime {
42+
let path = path.as_ref();
43+
if path.is_dir() {
44+
path.read_dir()
45+
.into_iter()
46+
.flatten()
47+
.flatten()
48+
.map(|entry| mtime(&entry.path()))
49+
.max()
50+
.unwrap_or(SystemTime::UNIX_EPOCH)
51+
} else {
52+
path.metadata()
53+
.and_then(|metadata| metadata.modified())
54+
.unwrap_or(SystemTime::UNIX_EPOCH)
55+
}
56+
}
57+
58+
#[allow(clippy::missing_errors_doc)]
59+
pub fn validate_port(arg: &OsStr) -> Result<(), OsString> {
60+
match arg.to_string_lossy().parse::<u16>() {
61+
Ok(_port) => Ok(()),
62+
Err(err) => Err(OsString::from(err.to_string())),
63+
}
64+
}

doc/adding_lints.md

+2-1
Original file line numberDiff line numberDiff line change
@@ -189,7 +189,8 @@ declare_clippy_lint! {
189189

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

0 commit comments

Comments
 (0)