summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorCosmicHorror <CosmicHorrorDev@pm.me>2023-05-10 23:53:57 -0600
committerGitHub <noreply@github.com>2023-05-11 00:53:57 -0500
commit27c217a43ed9c459a987eca5707b3f3e839b156c (patch)
tree9ce27de2d184d9a0391ad583082503bbdff2585f
parentb6ea084dc9d25b2f89a199e151fa1c7e3da301f2 (diff)
Improve error message for failed replacements (#186)
-rw-r--r--src/error.rs27
-rw-r--r--src/input.rs26
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();