diff --git a/src/ci/docker/host-x86_64/mingw-check-tidy/Dockerfile b/src/ci/docker/host-x86_64/mingw-check-tidy/Dockerfile index 8d2c5e004e479..5ffd3926c6663 100644 --- a/src/ci/docker/host-x86_64/mingw-check-tidy/Dockerfile +++ b/src/ci/docker/host-x86_64/mingw-check-tidy/Dockerfile @@ -28,9 +28,6 @@ COPY scripts/nodejs.sh /scripts/ RUN sh /scripts/nodejs.sh /node ENV PATH="/node/bin:${PATH}" -# Install eslint -COPY host-x86_64/mingw-check-tidy/eslint.version /tmp/ - COPY scripts/sccache.sh /scripts/ RUN sh /scripts/sccache.sh @@ -41,9 +38,7 @@ RUN pip3 install --no-deps --no-cache-dir --require-hashes -r /tmp/reuse-require COPY host-x86_64/mingw-check-1/validate-toolstate.sh /scripts/ COPY host-x86_64/mingw-check-1/validate-error-codes.sh /scripts/ -RUN bash -c 'npm install -g eslint@$(cat /tmp/eslint.version)' - # NOTE: intentionally uses python2 for x.py so we can test it still works. # validate-toolstate only runs in our CI, so it's ok for it to only support python3. ENV SCRIPT TIDY_PRINT_DIFF=1 python2.7 ../x.py test --stage 0 \ - src/tools/tidy tidyselftest --extra-checks=py,cpp + src/tools/tidy tidyselftest --extra-checks=py,cpp,js diff --git a/src/tools/tidy/src/ext_tool_checks.rs b/src/tools/tidy/src/ext_tool_checks.rs index 4f9a20fa9e294..850ac21054b8e 100644 --- a/src/tools/tidy/src/ext_tool_checks.rs +++ b/src/tools/tidy/src/ext_tool_checks.rs @@ -22,6 +22,8 @@ use std::path::{Path, PathBuf}; use std::process::Command; use std::{fmt, fs, io}; +use crate::walk::walk_no_read; + const MIN_PY_REV: (u32, u32) = (3, 9); const MIN_PY_REV_STR: &str = "≥3.9"; @@ -56,8 +58,8 @@ fn check_impl( extra_checks: Option<&str>, pos_args: &[String], ) -> Result<(), Error> { - let show_diff = std::env::var("TIDY_PRINT_DIFF") - .map_or(false, |v| v.eq_ignore_ascii_case("true") || v == "1"); + let show_diff = + std::env::var("TIDY_PRINT_DIFF").is_ok_and(|v| v.eq_ignore_ascii_case("true") || v == "1"); // Split comma-separated args up let lint_args = match extra_checks { @@ -72,6 +74,8 @@ fn check_impl( let shell_lint = lint_args.contains(&"shell:lint") || shell_all; let cpp_all = lint_args.contains(&"cpp"); let cpp_fmt = lint_args.contains(&"cpp:fmt") || cpp_all; + let js_all = lint_args.contains(&"js"); + let js_lint = lint_args.contains(&"js:lint") || js_all; let mut py_path = None; @@ -224,6 +228,44 @@ fn check_impl( shellcheck_runner(&merge_args(&cfg_args, &file_args_shc))?; } + if js_lint { + eprintln!("running `eslint` on JS files"); + let src_path = root_path.join("src"); + let eslint_version_path = + src_path.join("ci/docker/host-x86_64/mingw-check-tidy/eslint.version"); + let eslint_version = fs::read_to_string(&eslint_version_path) + .map_err(|error| { + Error::Generic(format!( + "failed to read `eslint` version file `{}`: {error:?}", + eslint_version_path.display() + )) + })? + .trim() + .to_string(); + let mut files_to_check = Vec::new(); + let librustdoc_path = src_path.join("librustdoc"); + let tools_path = src_path.join("tools"); + walk_no_read( + &[&librustdoc_path.join("html/static/js")], + |path, is_dir| is_dir || path.extension() != Some(OsStr::new("js")), + &mut |path| { + files_to_check.push(path.path().into()); + }, + ); + run_eslint(&eslint_version, &files_to_check, librustdoc_path.join("html/static"))?; + + run_eslint( + &eslint_version, + &[tools_path.join("rustdoc-js/tester.js")], + tools_path.join("rustdoc-js"), + )?; + run_eslint( + &eslint_version, + &[tools_path.join("rustdoc-gui/tester.js")], + tools_path.join("rustdoc-gui"), + )?; + } + Ok(()) } @@ -532,6 +574,24 @@ fn find_with_extension( Ok(output) } +fn run_eslint(eslint_version: &str, args: &[PathBuf], config_folder: PathBuf) -> Result<(), Error> { + match Command::new("npx") + .arg(format!("eslint@{eslint_version}")) + .arg("-c") + .arg(config_folder.join(".eslintrc.js")) + .args(args) + .output() + { + Ok(output) if output.status.success() => Ok(()), + Ok(_) => Err(Error::FailedCheck("eslint")), + Err(_) => Err(Error::MissingReq( + "`npx`", + "`eslint` JS linter", + Some("`npx` comes bundled with `node` and `npm`".to_string()), + )), + } +} + #[derive(Debug)] enum Error { Io(io::Error), diff --git a/src/tools/tidy/src/lib.rs b/src/tools/tidy/src/lib.rs index 28aa80225b177..201c3af47fb72 100644 --- a/src/tools/tidy/src/lib.rs +++ b/src/tools/tidy/src/lib.rs @@ -82,7 +82,6 @@ pub mod mir_opt_tests; pub mod pal; pub mod rustdoc_css_themes; pub mod rustdoc_gui_tests; -pub mod rustdoc_js; pub mod rustdoc_json; pub mod rustdoc_templates; pub mod style; diff --git a/src/tools/tidy/src/main.rs b/src/tools/tidy/src/main.rs index 0b66017b86522..90165eeb45974 100644 --- a/src/tools/tidy/src/main.rs +++ b/src/tools/tidy/src/main.rs @@ -35,7 +35,6 @@ fn main() { let library_path = root_path.join("library"); let compiler_path = root_path.join("compiler"); let librustdoc_path = src_path.join("librustdoc"); - let tools_path = src_path.join("tools"); let crashes_path = tests_path.join("crashes"); let args: Vec = env::args().skip(1).collect(); @@ -109,7 +108,6 @@ fn main() { check!(rustdoc_gui_tests, &tests_path); check!(rustdoc_css_themes, &librustdoc_path); check!(rustdoc_templates, &librustdoc_path); - check!(rustdoc_js, &librustdoc_path, &tools_path, &src_path); check!(rustdoc_json, &src_path); check!(known_bug, &crashes_path); check!(unknown_revision, &tests_path); diff --git a/src/tools/tidy/src/rustdoc_js.rs b/src/tools/tidy/src/rustdoc_js.rs deleted file mode 100644 index 2517e2de12ce5..0000000000000 --- a/src/tools/tidy/src/rustdoc_js.rs +++ /dev/null @@ -1,99 +0,0 @@ -//! Tidy check to ensure that rustdoc templates didn't forget a `{# #}` to strip extra whitespace -//! characters. - -use std::ffi::OsStr; -use std::path::{Path, PathBuf}; -use std::process::Command; - -use ignore::DirEntry; - -use crate::walk::walk_no_read; - -fn run_eslint(args: &[PathBuf], config_folder: PathBuf, bad: &mut bool) { - let mut child = match Command::new("npx") - .arg("eslint") - .arg("-c") - .arg(config_folder.join(".eslintrc.js")) - .args(args) - .spawn() - { - Ok(child) => child, - Err(error) => { - *bad = true; - eprintln!("failed to run eslint: {error:?}"); - return; - } - }; - match child.wait() { - Ok(exit_status) => { - if exit_status.success() { - return; - } - eprintln!("eslint command failed"); - } - Err(error) => eprintln!("eslint command failed: {error:?}"), - } - *bad = true; -} - -fn get_eslint_version_inner(global: bool) -> Option { - let mut command = Command::new("npm"); - command.arg("list").arg("--parseable").arg("--long").arg("--depth=0"); - if global { - command.arg("--global"); - } - let output = command.output().ok()?; - let lines = String::from_utf8_lossy(&output.stdout); - lines.lines().find_map(|l| l.split(':').nth(1)?.strip_prefix("eslint@")).map(|v| v.to_owned()) -} - -fn get_eslint_version() -> Option { - get_eslint_version_inner(false).or_else(|| get_eslint_version_inner(true)) -} - -pub fn check(librustdoc_path: &Path, tools_path: &Path, src_path: &Path, bad: &mut bool) { - let eslint_version_path = - src_path.join("ci/docker/host-x86_64/mingw-check-tidy/eslint.version"); - let eslint_version = match std::fs::read_to_string(&eslint_version_path) { - Ok(version) => version.trim().to_string(), - Err(error) => { - *bad = true; - eprintln!("failed to read `{}`: {error:?}", eslint_version_path.display()); - return; - } - }; - match get_eslint_version() { - Some(version) => { - if version != eslint_version { - *bad = true; - eprintln!( - "⚠️ Installed version of eslint (`{version}`) is different than the \ - one used in the CI (`{eslint_version}`)", - ); - eprintln!( - "You can install this version using `npm update eslint` or by using \ - `npm install eslint@{eslint_version}`", - ); - return; - } - } - None => { - eprintln!("`eslint` doesn't seem to be installed. Skipping tidy check for JS files."); - eprintln!("You can install it using `npm install eslint@{eslint_version}`"); - return; - } - } - let mut files_to_check = Vec::new(); - walk_no_read( - &[&librustdoc_path.join("html/static/js")], - |path, is_dir| is_dir || !path.extension().is_some_and(|ext| ext == OsStr::new("js")), - &mut |path: &DirEntry| { - files_to_check.push(path.path().into()); - }, - ); - println!("Running eslint on rustdoc JS files"); - run_eslint(&files_to_check, librustdoc_path.join("html/static"), bad); - - run_eslint(&[tools_path.join("rustdoc-js/tester.js")], tools_path.join("rustdoc-js"), bad); - run_eslint(&[tools_path.join("rustdoc-gui/tester.js")], tools_path.join("rustdoc-gui"), bad); -}