diff options
author | Daniel Baumann <daniel.baumann@progress-linux.org> | 2024-04-17 12:02:58 +0000 |
---|---|---|
committer | Daniel Baumann <daniel.baumann@progress-linux.org> | 2024-04-17 12:02:58 +0000 |
commit | 698f8c2f01ea549d77d7dc3338a12e04c11057b9 (patch) | |
tree | 173a775858bd501c378080a10dca74132f05bc50 /src/doc/book/tools/src/bin/lfp.rs | |
parent | Initial commit. (diff) | |
download | rustc-698f8c2f01ea549d77d7dc3338a12e04c11057b9.tar.xz rustc-698f8c2f01ea549d77d7dc3338a12e04c11057b9.zip |
Adding upstream version 1.64.0+dfsg1.upstream/1.64.0+dfsg1
Signed-off-by: Daniel Baumann <daniel.baumann@progress-linux.org>
Diffstat (limited to 'src/doc/book/tools/src/bin/lfp.rs')
-rw-r--r-- | src/doc/book/tools/src/bin/lfp.rs | 248 |
1 files changed, 248 insertions, 0 deletions
diff --git a/src/doc/book/tools/src/bin/lfp.rs b/src/doc/book/tools/src/bin/lfp.rs new file mode 100644 index 000000000..c4d4bce03 --- /dev/null +++ b/src/doc/book/tools/src/bin/lfp.rs @@ -0,0 +1,248 @@ +// We have some long regex literals, so: +// ignore-tidy-linelength + +use docopt::Docopt; +use serde::Deserialize; +use std::io::BufRead; +use std::{fs, io, path}; + +fn main() { + let args: Args = Docopt::new(USAGE) + .and_then(|d| d.deserialize()) + .unwrap_or_else(|e| e.exit()); + + let src_dir = &path::Path::new(&args.arg_src_dir); + let found_errs = walkdir::WalkDir::new(src_dir) + .min_depth(1) + .into_iter() + .map(|entry| match entry { + Ok(entry) => entry, + Err(err) => { + eprintln!("{:?}", err); + std::process::exit(911) + } + }) + .map(|entry| { + let path = entry.path(); + if is_file_of_interest(path) { + let err_vec = lint_file(path); + for err in &err_vec { + match *err { + LintingError::LineOfInterest(line_num, ref line) => { + eprintln!( + "{}:{}\t{}", + path.display(), + line_num, + line + ) + } + LintingError::UnableToOpenFile => { + eprintln!("Unable to open {}.", path.display()) + } + } + } + !err_vec.is_empty() + } else { + false + } + }) + .collect::<Vec<_>>() + .iter() + .any(|result| *result); + + if found_errs { + std::process::exit(1) + } else { + std::process::exit(0) + } +} + +const USAGE: &str = " +counter +Usage: + lfp <src-dir> + lfp (-h | --help) +Options: + -h --help Show this screen. +"; + +#[derive(Debug, Deserialize)] +struct Args { + arg_src_dir: String, +} + +fn lint_file(path: &path::Path) -> Vec<LintingError> { + match fs::File::open(path) { + Ok(file) => lint_lines(io::BufReader::new(&file).lines()), + Err(_) => vec![LintingError::UnableToOpenFile], + } +} + +fn lint_lines<I>(lines: I) -> Vec<LintingError> +where + I: Iterator<Item = io::Result<String>>, +{ + lines + .enumerate() + .map(|(line_num, line)| { + let raw_line = line.unwrap(); + if is_line_of_interest(&raw_line) { + Err(LintingError::LineOfInterest(line_num, raw_line)) + } else { + Ok(()) + } + }) + .filter(|result| result.is_err()) + .map(|result| result.unwrap_err()) + .collect() +} + +fn is_file_of_interest(path: &path::Path) -> bool { + path.extension().map_or(false, |ext| ext == "md") +} + +fn is_line_of_interest(line: &str) -> bool { + line.split_whitespace().any(|sub_string| { + sub_string.contains("file://") + && !sub_string.contains("file:///projects/") + }) +} + +#[derive(Debug)] +enum LintingError { + UnableToOpenFile, + LineOfInterest(usize, String), +} + +#[cfg(test)] +mod tests { + + use std::path; + + #[test] + fn lint_file_returns_a_vec_with_errs_when_lines_of_interest_are_found() { + let string = r#" + $ cargo run + Compiling guessing_game v0.1.0 (file:///home/you/projects/guessing_game) + Running `target/guessing_game` + Guess the number! + The secret number is: 61 + Please input your guess. + 10 + You guessed: 10 + Too small! + Please input your guess. + 99 + You guessed: 99 + Too big! + Please input your guess. + foo + Please input your guess. + 61 + You guessed: 61 + You win! + $ cargo run + Compiling guessing_game v0.1.0 (file:///home/you/projects/guessing_game) + Running `target/debug/guessing_game` + Guess the number! + The secret number is: 7 + Please input your guess. + 4 + You guessed: 4 + $ cargo run + Running `target/debug/guessing_game` + Guess the number! + The secret number is: 83 + Please input your guess. + 5 + $ cargo run + Compiling guessing_game v0.1.0 (file:///home/you/projects/guessing_game) + Running `target/debug/guessing_game` + Hello, world! + "#; + + let raw_lines = string.to_string(); + let lines = raw_lines.lines().map(|line| Ok(line.to_string())); + + let result_vec = super::lint_lines(lines); + + assert!(!result_vec.is_empty()); + assert_eq!(3, result_vec.len()); + } + + #[test] + fn lint_file_returns_an_empty_vec_when_no_lines_of_interest_are_found() { + let string = r#" + $ cargo run + Compiling guessing_game v0.1.0 (file:///projects/guessing_game) + Running `target/guessing_game` + Guess the number! + The secret number is: 61 + Please input your guess. + 10 + You guessed: 10 + Too small! + Please input your guess. + 99 + You guessed: 99 + Too big! + Please input your guess. + foo + Please input your guess. + 61 + You guessed: 61 + You win! + "#; + + let raw_lines = string.to_string(); + let lines = raw_lines.lines().map(|line| Ok(line.to_string())); + + let result_vec = super::lint_lines(lines); + + assert!(result_vec.is_empty()); + } + + #[test] + fn is_file_of_interest_returns_false_when_the_path_is_a_directory() { + let uninteresting_fn = "src/img"; + + assert!(!super::is_file_of_interest(path::Path::new( + uninteresting_fn + ))); + } + + #[test] + fn is_file_of_interest_returns_false_when_the_filename_does_not_have_the_md_extension( + ) { + let uninteresting_fn = "src/img/foo1.png"; + + assert!(!super::is_file_of_interest(path::Path::new( + uninteresting_fn + ))); + } + + #[test] + fn is_file_of_interest_returns_true_when_the_filename_has_the_md_extension() + { + let interesting_fn = "src/ch01-00-introduction.md"; + + assert!(super::is_file_of_interest(path::Path::new(interesting_fn))); + } + + #[test] + fn is_line_of_interest_does_not_report_a_line_if_the_line_contains_a_file_url_which_is_directly_followed_by_the_project_path( + ) { + let sample_line = + "Compiling guessing_game v0.1.0 (file:///projects/guessing_game)"; + + assert!(!super::is_line_of_interest(sample_line)); + } + + #[test] + fn is_line_of_interest_reports_a_line_if_the_line_contains_a_file_url_which_is_not_directly_followed_by_the_project_path( + ) { + let sample_line = "Compiling guessing_game v0.1.0 (file:///home/you/projects/guessing_game)"; + + assert!(super::is_line_of_interest(sample_line)); + } +} |