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 =
56 src_path.join("ci/docker/host-x86_64/mingw-check-tidy/eslint.version");
57 let eslint_version = match std::fs::read_to_string(&eslint_version_path) {
58 Ok(version) => version.trim().to_string(),
59 Err(error) => {
60 *bad = true;
61 eprintln!("failed to read `{}`: {error:?}", eslint_version_path.display());
62 return;
63 }
64 };
65 match get_eslint_version() {
66 Some(version) => {
67 if version != eslint_version {
68 *bad = true;
69 eprintln!(
70 "⚠️ Installed version of eslint (`{version}`) is different than the \
71 one used in the CI (`{eslint_version}`)",
72 );
73 eprintln!(
74 "You can install this version using `npm update eslint` or by using \
75 `npm install eslint@{eslint_version}`",
76 );
77 return;
78 }
79 }
80 None => {
81 eprintln!("`eslint` doesn't seem to be installed. Skipping tidy check for JS files.");
82 eprintln!("You can install it using `npm install eslint@{eslint_version}`");
83 return;
84 }
85 }
86 let mut files_to_check = Vec::new();
87 walk_no_read(
88 &[&librustdoc_path.join("html/static/js")],
89 |path, is_dir| is_dir || !path.extension().is_some_and(|ext| ext == OsStr::new("js")),
90 &mut |path: &DirEntry| {
91 files_to_check.push(path.path().into());
92 },
93 );
94 println!("Running eslint on rustdoc JS files");
95 run_eslint(&files_to_check, librustdoc_path.join("html/static"), bad);
96
97 run_eslint(&[tools_path.join("rustdoc-js/tester.js")], tools_path.join("rustdoc-js"), bad);
98 run_eslint(&[tools_path.join("rustdoc-gui/tester.js")], tools_path.join("rustdoc-gui"), bad);
99}