diff options
author | CosmicHorror <CosmicHorrorDev@pm.me> | 2023-05-10 23:53:57 -0600 |
---|---|---|
committer | GitHub <noreply@github.com> | 2023-05-11 00:53:57 -0500 |
commit | 27c217a43ed9c459a987eca5707b3f3e839b156c (patch) | |
tree | 9ce27de2d184d9a0391ad583082503bbdff2585f | |
parent | b6ea084dc9d25b2f89a199e151fa1c7e3da301f2 (diff) |
Improve error message for failed replacements (#186)
-rw-r--r-- | src/error.rs | 27 | ||||
-rw-r--r-- | src/input.rs | 26 |
2 files changed, 44 insertions, 9 deletions
diff --git a/src/error.rs b/src/error.rs index 67a18f8..e757cf4 100644 --- a/src/error.rs +++ b/src/error.rs @@ -1,3 +1,8 @@ +use std::{ + fmt::{self, Write}, + path::PathBuf, +}; + #[derive(thiserror::Error)] pub enum Error { #[error("invalid regex {0}")] @@ -7,7 +12,27 @@ pub enum Error { #[error("failed to move file: {0}")] TempfilePersist(#[from] tempfile::PersistError), #[error("file doesn't have parent path: {0}")] - InvalidPath(std::path::PathBuf), + InvalidPath(PathBuf), + #[error("failed processing files:\n{0}")] + FailedProcessing(FailedJobs), +} + +pub struct FailedJobs(Vec<(PathBuf, Error)>); + +impl From<Vec<(PathBuf, Error)>> for FailedJobs { + fn from(vec: Vec<(PathBuf, Error)>) -> Self { + Self(vec) + } +} + +impl fmt::Display for FailedJobs { + fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { + f.write_str("\tFailedJobs(\n")?; + for (path, err) in &self.0 { + f.write_str(&format!("\t{:?}: {}\n", path, err))?; + } + f.write_char(')') + } } // pretty-print the error diff --git a/src/input.rs b/src/input.rs index e5c715d..2c8990c 100644 --- a/src/input.rs +++ b/src/input.rs @@ -1,4 +1,4 @@ -use crate::{Replacer, Result}; +use crate::{Error, Replacer, Result}; use std::{fs::File, io::prelude::*, path::PathBuf}; #[derive(Debug)] @@ -57,14 +57,24 @@ impl App { (Source::Files(paths), false) => { use rayon::prelude::*; - #[allow(unused_must_use)] - paths.par_iter().for_each(|p| { - self.replacer.replace_file(p).map_err(|e| { - eprintln!("Error processing {}: {}", p.display(), e) - }); - }); + let failed_jobs: Vec<_> = paths + .par_iter() + .filter_map(|p| { + if let Err(e) = self.replacer.replace_file(p) { + Some((p.to_owned(), e)) + } else { + None + } + }) + .collect(); - Ok(()) + if failed_jobs.is_empty() { + Ok(()) + } else { + let failed_jobs = + crate::error::FailedJobs::from(failed_jobs); + Err(Error::FailedProcessing(failed_jobs)) + } } (Source::Files(paths), true) => { let stdout = std::io::stdout(); |