1use std::ffi::OsStr;
5use std::path::{Path, PathBuf};
6use std::process::Command;
7
8use ignore::DirEntry;
9
10use crate::walk::walk_no_read;
11
12fn run_eslint(args: &[PathBuf], config_folder: PathBuf, bad: &mut bool) {
13 let mut child = match Command::new("npx")
14 .arg("eslint")
15 .arg("-c")
16 .arg(config_folder.join(".eslintrc.js"))
17 .args(args)
18 .spawn()
19 {
20 Ok(child) => child,
21 Err(error) => {
22 *bad = true;
23 eprintln!("failed to run eslint: {error:?}");
24 return;
25 }
26 };
27 match child.wait() {
28 Ok(exit_status) => {
29 if exit_status.success() {
30 return;
31 }
32 eprintln!("eslint command failed");
33 }
34 Err(error) => eprintln!("eslint command failed: {error:?}"),
35 }
36 *bad = true;
37}
38
39fn get_eslint_version_inner(global: bool) -> Option<String> {
40 let mut command = Command::new("npm");
41 command.arg("list").arg("--parseable").arg("--long").arg("--depth=0");
42 if global {
43 command.arg("--global");
44 }
45 let output = command.output().ok()?;
46 let lines = String::from_utf8_lossy(&output.stdout);
47 lines.lines().find_map(|l| l.split(':').nth(1)?.strip_prefix("eslint@")).map(|v| v.to_owned())
48}
49
50fn get_eslint_version() -> Option<String> {
51 get_eslint_version_inner(false).or_else(|| get_eslint_version_inner(true))
52}
53
54pub fn check(librustdoc_path: &Path, tools_path: &Path, src_path: &Path, bad: &mut bool) {
55 let eslint_version_path = src_path.join("ci/docker/host-x86_64/tidy/eslint.version");
56 let eslint_version = match std::fs::read_to_string(&eslint_version_path) {
57 Ok(version) => version.trim().to_string(),
58 Err(error) => {
59 *bad = true;
60 eprintln!("failed to read `{}`: {error:?}", eslint_version_path.display());
61 return;
62 }
63 };
64 match get_eslint_version() {
68 Some(version) => {
69 if version != eslint_version {
70 *bad = true;
71 eprintln!(
72 "⚠️ Installed version of eslint (`{version}`) is different than the \
73 one used in the CI (`{eslint_version}`)",
74 );
75 eprintln!(
76 "You can install this version using `npm update eslint` or by using \
77 `npm install eslint@{eslint_version}`",
78 );
79 return;
80 }
81 }
82 None => {
83 eprintln!("`eslint` doesn't seem to be installed. Skipping tidy check for JS files.");
84 eprintln!("You can install it using `npm install eslint@{eslint_version}`");
85 return;
86 }
87 }
88 let mut files_to_check = Vec::new();
89 walk_no_read(
90 &[&librustdoc_path.join("html/static/js")],
91 |path, is_dir| is_dir || !path.extension().is_some_and(|ext| ext == OsStr::new("js")),
92 &mut |path: &DirEntry| {
93 files_to_check.push(path.path().into());
94 },
95 );
96 println!("Running eslint on rustdoc JS files");
97 run_eslint(&files_to_check, librustdoc_path.join("html/static"), bad);
98
99 run_eslint(&[tools_path.join("rustdoc-js/tester.js")], tools_path.join("rustdoc-js"), bad);
100 run_eslint(&[tools_path.join("rustdoc-gui/tester.js")], tools_path.join("rustdoc-gui"), bad);
101}