]> git.lizzy.rs Git - rust.git/blob - src/tools/html-checker/main.rs
Rollup merge of #85766 - workingjubilee:file-options, r=yaahc
[rust.git] / src / tools / html-checker / main.rs
1 use std::env;
2 use std::path::Path;
3 use std::process::{Command, Output};
4
5 fn check_html_file(file: &Path) -> usize {
6     let to_mute = &[
7         // "disabled" on <link> or "autocomplete" on <select> emit this warning
8         "PROPRIETARY_ATTRIBUTE",
9         // It complains when multiple in the same page link to the same anchor for some reason...
10         "ANCHOR_NOT_UNIQUE",
11         // If a <span> contains only HTML elements and no text, it complains about it.
12         "TRIM_EMPTY_ELEMENT",
13         // FIXME: the three next warnings are about <pre> elements which are not supposed to
14         //        contain HTML. The solution here would be to replace them with a <div>
15         "MISSING_ENDTAG_BEFORE",
16         "INSERTING_TAG",
17         "DISCARDING_UNEXPECTED",
18         // This error is caused by nesting the Notable Traits tooltip within an <h4> tag.
19         // The solution is to avoid doing that, but we need to have the <h4> tags for accessibility
20         // reasons, and we need the Notable Traits tooltip to help everyone understand the Iterator
21         // combinators
22         "TAG_NOT_ALLOWED_IN",
23     ];
24     let to_mute_s = to_mute.join(",");
25     let mut command = Command::new("tidy");
26     command
27         .arg("-errors")
28         .arg("-quiet")
29         .arg("--mute-id") // this option is useful in case we want to mute more warnings
30         .arg("yes")
31         .arg("--mute")
32         .arg(&to_mute_s)
33         .arg(file);
34
35     let Output { status, stderr, .. } = command.output().expect("failed to run tidy command");
36     if status.success() {
37         0
38     } else {
39         let stderr = String::from_utf8(stderr).expect("String::from_utf8 failed...");
40         if stderr.is_empty() && status.code() != Some(2) {
41             0
42         } else {
43             eprintln!(
44                 "=> Errors for `{}` (error code: {}) <=",
45                 file.display(),
46                 status.code().unwrap_or(-1)
47             );
48             eprintln!("{}", stderr);
49             stderr.lines().count()
50         }
51     }
52 }
53
54 const DOCS_TO_CHECK: &[&str] =
55     &["alloc", "core", "proc_macro", "implementors", "src", "std", "test"];
56
57 // Returns the number of files read and the number of errors.
58 fn find_all_html_files(dir: &Path) -> (usize, usize) {
59     let mut files_read = 0;
60     let mut errors = 0;
61
62     for entry in walkdir::WalkDir::new(dir).into_iter().filter_entry(|e| {
63         e.depth() != 1
64             || e.file_name()
65                 .to_str()
66                 .map(|s| DOCS_TO_CHECK.into_iter().any(|d| *d == s))
67                 .unwrap_or(false)
68     }) {
69         let entry = entry.expect("failed to read file");
70         if !entry.file_type().is_file() {
71             continue;
72         }
73         let entry = entry.path();
74         if entry.extension().and_then(|s| s.to_str()) == Some("html") {
75             errors += check_html_file(&entry);
76             files_read += 1;
77         }
78     }
79     (files_read, errors)
80 }
81
82 /// Default `tidy` command for macOS is too old that it does not have `mute-id` and `mute` options.
83 /// `tidy` on macOS Monterey was released on 31 October 2006, and the same date can be seen seven
84 /// years ago at <https://stackoverflow.com/questions/22283382/overwrite-osx-tidy>. Accordingly,
85 /// the macOS environment using pre-installed `tidy` should immediately suspend HTML checker process
86 /// and show a hint to install a newer one.
87 #[cfg(target_os = "macos")]
88 fn check_tidy_version() -> Result<(), String> {
89     let output = Command::new("tidy").arg("-v").output().expect("failed to run tidy command");
90     let version = String::from_utf8(output.stdout).expect("failed to read version of tidy command");
91     if version.contains("HTML Tidy for Mac OS X released on 31 October 2006") {
92         eprintln!("The pre-installed HTML Tidy for macOS is not supported.");
93         eprintln!("Consider installing a newer one and re-running.");
94         eprintln!("If you're using Homebrew, you can install it by the following command:");
95         eprintln!("    brew install tidy-html5");
96         eprintln!();
97         Err("HTML check failed: 1 error".to_string())
98     } else {
99         Ok(())
100     }
101 }
102
103 fn main() -> Result<(), String> {
104     let args = env::args().collect::<Vec<_>>();
105     if args.len() != 2 {
106         return Err(format!("Usage: {} <doc folder>", args[0]));
107     }
108     #[cfg(target_os = "macos")]
109     check_tidy_version()?;
110
111     println!("Running HTML checker...");
112
113     let (files_read, errors) = find_all_html_files(&Path::new(&args[1]));
114     println!("Done! Read {} files...", files_read);
115     if errors > 0 {
116         Err(format!("HTML check failed: {} errors", errors))
117     } else {
118         println!("No error found!");
119         Ok(())
120     }
121 }