From 53041af73cd5142ca28195589a8c24c0965e0ba8 Mon Sep 17 00:00:00 2001 From: Michael Zhang Date: Thu, 30 Dec 2021 21:57:26 -0600 Subject: [PATCH] Exit status now depends on Result --- src/errors.rs | 43 ++++++++++++++++++++++++++++++++++++++++++- src/main.rs | 8 +++++++- src/mounts.rs | 2 +- src/ops/put.rs | 10 ++++++++-- src/utils.rs | 3 +-- 5 files changed, 59 insertions(+), 7 deletions(-) diff --git a/src/errors.rs b/src/errors.rs index 377ab95..3b8a759 100644 --- a/src/errors.rs +++ b/src/errors.rs @@ -1,4 +1,4 @@ -use std::path::PathBuf; +use std::{fmt, iter, path::PathBuf}; /// Result convenience type for the Error type pub type Result = std::result::Result; @@ -10,6 +10,9 @@ pub enum Error { #[error("IO error: {0}")] Io(#[from] std::io::Error), + #[error("Path doesn't exist: {0}")] + FileDoesntExist(PathBuf), + #[error("Could not open file {0:?}: {1}")] OpenFile(PathBuf, std::io::Error), @@ -36,6 +39,44 @@ pub enum Error { #[error("Put error: {0}")] Put(#[from] crate::ops::put::PutError), + + #[error("{0} and {1}")] + And(Box, Box), + + #[error("{0}")] + Multiple(MultipleErrors), +} + +impl Error { + /// Construct an error consisting of multiple errors + pub fn multiple(errors: impl Iterator) -> Self { + Error::Multiple(MultipleErrors( + errors + .map(|err| -> Box> { + match err { + Error::Multiple(MultipleErrors(errors)) => { + Box::new(errors.into_iter()) + } + _ => Box::new(iter::once(err)), + } + }) + .flatten() + .collect(), + )) + } +} + +#[derive(Debug)] +pub struct MultipleErrors(Vec); + +impl fmt::Display for MultipleErrors { + fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { + writeln!(f, "")?; + for err in self.0.iter() { + writeln!(f, "- {}", err)?; + } + Ok(()) + } } /// Errors related to .trashinfo files diff --git a/src/main.rs b/src/main.rs index 8804dab..18e9ff1 100644 --- a/src/main.rs +++ b/src/main.rs @@ -1,5 +1,10 @@ #![deny(warnings)] +#[macro_use] +extern crate log; + +use std::process::exit; + use garbage::{ ops::{self, EmptyOptions, ListOptions, PutOptions, RestoreOptions}, Result, @@ -61,7 +66,8 @@ fn main() { match run(opt.command) { Ok(_) => (), Err(err) => { - eprintln!("Error: {}", err); + error!("{}", err); + exit(1); } } } diff --git a/src/mounts.rs b/src/mounts.rs index 0ef0e2c..68c500b 100644 --- a/src/mounts.rs +++ b/src/mounts.rs @@ -4,8 +4,8 @@ use std::fs::File; use std::io::Read; use std::path::{Path, PathBuf}; -use libmount::mountinfo::Parser; use libc::c_ulong; +use libmount::mountinfo::Parser; use crate::errors::Error; use crate::utils; diff --git a/src/ops/put.rs b/src/ops/put.rs index 0f8b962..199414a 100644 --- a/src/ops/put.rs +++ b/src/ops/put.rs @@ -65,11 +65,13 @@ pub struct PutOptions { /// Throw some files into the trash. pub fn put(options: PutOptions) -> Result<()> { + let mut errors = vec![]; + for path in options.paths.iter() { let abs_path = utils::into_absolute(&path)?; if !abs_path.exists() { - error!("Skipping non-existent path {:?}", path); + errors.push(Error::FileDoesntExist(path.clone())); continue; } @@ -102,7 +104,11 @@ pub fn put(options: PutOptions) -> Result<()> { } } - Ok(()) + if errors.is_empty() { + Ok(()) + } else { + Err(Error::multiple(errors.into_iter())) + } } /// DeletionStrategy describes a strategy by which a file is deleted diff --git a/src/utils.rs b/src/utils.rs index 8f444de..0264abf 100644 --- a/src/utils.rs +++ b/src/utils.rs @@ -24,8 +24,7 @@ pub fn into_absolute(path: impl AsRef) -> Result { for component in path.components() { match component { Component::Prefix(_) => unimplemented!("windows lol"), - Component::RootDir => { - } + Component::RootDir => {} Component::CurDir => {} Component::ParentDir => { new_path.pop();