From fa002d88284fd1622f68229c47eba7c688c81ed9 Mon Sep 17 00:00:00 2001 From: Teddy Wing Date: Sun, 13 Jun 2021 12:58:33 +0200 Subject: run(): Return multiple errors Return all errors from repo processing. This allows us to provide information on all errors that happened while processing, but continue processing all the repos even if there's an error in one of them. A new `MultiError` type wraps a list of errors to do this. --- src/main.rs | 63 +++++++++++++++++++++++++++++++++++++++++++++++++------------ 1 file changed, 51 insertions(+), 12 deletions(-) (limited to 'src') diff --git a/src/main.rs b/src/main.rs index 15f0898..ce5d370 100644 --- a/src/main.rs +++ b/src/main.rs @@ -28,6 +28,7 @@ use rusqlite; use reflectub::{database, git, github}; use std::env; +use std::fmt; use std::fs; use std::io; use std::path::{Path, PathBuf}; @@ -39,19 +40,47 @@ fn main() { match run() { Ok(_) => (), Err(e) => { - eprint!("error"); - - for cause in e.chain() { - eprint!(": {}", cause); - } - - eprintln!(); + eprintln!("error: {}", e); process::exit(exitcode::SOFTWARE); }, }; } + +#[derive(Debug, thiserror::Error)] +struct MultiError { + errors: Vec, + // errors: Vec>, +} + +impl fmt::Display for MultiError { + fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { + write!( + f, + "{}", + self.errors + .iter() + .map(|e| format!("{:#}", e)) + .collect::>() + .join("\n"), + ) + } +} + +impl From for MultiError { + fn from(error: anyhow::Error) -> Self { + MultiError { errors: vec![error] } + } +} + +impl From> for MultiError { + fn from(errors: Vec) -> Self { + MultiError { errors: errors } + } +} + + fn print_usage(opts: &Options) { print!( "{}", @@ -59,7 +88,7 @@ fn print_usage(opts: &Options) { ); } -fn run() -> anyhow::Result<()> { +fn run() -> Result<(), MultiError> { let args: Vec = env::args().collect(); let mut opts = Options::new(); @@ -70,7 +99,8 @@ fn run() -> anyhow::Result<()> { opts.optflag("h", "help", "print this help menu"); opts.optflag("V", "version", "show the program version"); - let opt_matches = opts.parse(&args[1..])?; + let opt_matches = opts.parse(&args[1..]) + .map_err(anyhow::Error::new)?; if opt_matches.opt_present("h") { print_usage(&opts); @@ -110,7 +140,8 @@ fn run() -> anyhow::Result<()> { let base_cgitrc = opt_matches.opt_str("cgitrc") .map(|s| PathBuf::from(s)); - let repos = github::fetch_repos(username)?; + let repos = github::fetch_repos(username) + .map_err(anyhow::Error::new)?; let db = database::Db::connect(&database_file) .context("unable to connect to database")?; @@ -118,7 +149,7 @@ fn run() -> anyhow::Result<()> { db.create() .context("unable to create database")?; - let _results: anyhow::Result<()> = repos[..2].par_iter() + let errors: Vec<_> = repos[..2].par_iter() .map(|repo| { dbg!("Thread", std::thread::current().id()); @@ -130,8 +161,15 @@ fn run() -> anyhow::Result<()> { max_repo_size_bytes, ) }) + .filter(|r| r.is_err()) + + // `e` should always be an error. + .map(|e| e.err().unwrap()) .collect(); - // TODO: Return errors + + if errors.len() > 0 { + return Err(MultiError::from(errors)) + } Ok(()) } @@ -144,6 +182,7 @@ fn process_repo( base_cgitrc: Option, max_repo_size_bytes: Option, ) -> anyhow::Result<()> { + anyhow::bail!("test"); if let Some(max_repo_size_bytes) = max_repo_size_bytes { if is_repo_oversize(repo.size, max_repo_size_bytes) { return Ok(()); -- cgit v1.2.3