| use std::ffi::OsStr; | |
| use std::path::{Path, PathBuf}; | |
| use std::process::Command; | |
| use std::{fs, process}; | |
| const EXTENSIONS: &[&str] = | |
| &["rs", "py", "js", "sh", "c", "cpp", "h", "md", "css", "ftl", "toml", "yml", "yaml"]; | |
| fn has_supported_extension(path: &Path) -> bool { | |
| path.extension().is_some_and(|ext| EXTENSIONS.iter().any(|e| ext == OsStr::new(e))) | |
| } | |
| fn list_tracked_files() -> Result<Vec<PathBuf>, String> { | |
| let output = Command::new("git") | |
| .args(["ls-files", "-z"]) | |
| .output() | |
| .map_err(|e| format!("Failed to run `git ls-files`: {e}"))?; | |
| if !output.status.success() { | |
| let stderr = String::from_utf8_lossy(&output.stderr); | |
| return Err(format!("`git ls-files` failed: {stderr}")); | |
| } | |
| let mut files = Vec::new(); | |
| for entry in output.stdout.split(|b| *b == 0) { | |
| if entry.is_empty() { | |
| continue; | |
| } | |
| let path = std::str::from_utf8(entry).unwrap(); | |
| files.push(PathBuf::from(path)); | |
| } | |
| Ok(files) | |
| } | |
| pub(crate) fn run() -> ! { | |
| let files = list_tracked_files().unwrap(); | |
| let mut error_count = 0; | |
| // Avoid embedding the task marker in source so greps only find real occurrences. | |
| let todo_marker = "todo".to_ascii_uppercase(); | |
| for file in files { | |
| if !has_supported_extension(&file) { | |
| continue; | |
| } | |
| let bytes = fs::read(&file).unwrap(); | |
| let contents = std::str::from_utf8(&bytes).unwrap(); | |
| for (i, line) in contents.split('\n').enumerate() { | |
| let trimmed = line.trim(); | |
| if trimmed.contains(&todo_marker) { | |
| eprintln!( | |
| "{}:{}: {} is used for tasks that should be done before merging a PR; if you want to leave a message in the codebase use FIXME", | |
| file.display(), | |
| i + 1, | |
| todo_marker | |
| ); | |
| error_count += 1; | |
| } | |
| } | |
| } | |
| if error_count == 0 { | |
| process::exit(0); | |
| } | |
| eprintln!("found {} {}(s)", error_count, todo_marker); | |
| process::exit(1); | |
| } |