Exit status now depends on Result

This commit is contained in:
Michael Zhang 2021-12-30 21:57:26 -06:00
parent b8d2be4abe
commit 53041af73c
Signed by: michael
GPG key ID: BDA47A31A3C8EE6B
5 changed files with 59 additions and 7 deletions

View file

@ -1,4 +1,4 @@
use std::path::PathBuf; use std::{fmt, iter, path::PathBuf};
/// Result convenience type for the Error type /// Result convenience type for the Error type
pub type Result<T, E = Error> = std::result::Result<T, E>; pub type Result<T, E = Error> = std::result::Result<T, E>;
@ -10,6 +10,9 @@ pub enum Error {
#[error("IO error: {0}")] #[error("IO error: {0}")]
Io(#[from] std::io::Error), Io(#[from] std::io::Error),
#[error("Path doesn't exist: {0}")]
FileDoesntExist(PathBuf),
#[error("Could not open file {0:?}: {1}")] #[error("Could not open file {0:?}: {1}")]
OpenFile(PathBuf, std::io::Error), OpenFile(PathBuf, std::io::Error),
@ -36,6 +39,44 @@ pub enum Error {
#[error("Put error: {0}")] #[error("Put error: {0}")]
Put(#[from] crate::ops::put::PutError), Put(#[from] crate::ops::put::PutError),
#[error("{0} and {1}")]
And(Box<Error>, Box<Error>),
#[error("{0}")]
Multiple(MultipleErrors),
}
impl Error {
/// Construct an error consisting of multiple errors
pub fn multiple(errors: impl Iterator<Item = Error>) -> Self {
Error::Multiple(MultipleErrors(
errors
.map(|err| -> Box<dyn Iterator<Item = Error>> {
match err {
Error::Multiple(MultipleErrors(errors)) => {
Box::new(errors.into_iter())
}
_ => Box::new(iter::once(err)),
}
})
.flatten()
.collect(),
))
}
}
#[derive(Debug)]
pub struct MultipleErrors(Vec<Error>);
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 /// Errors related to .trashinfo files

View file

@ -1,5 +1,10 @@
#![deny(warnings)] #![deny(warnings)]
#[macro_use]
extern crate log;
use std::process::exit;
use garbage::{ use garbage::{
ops::{self, EmptyOptions, ListOptions, PutOptions, RestoreOptions}, ops::{self, EmptyOptions, ListOptions, PutOptions, RestoreOptions},
Result, Result,
@ -61,7 +66,8 @@ fn main() {
match run(opt.command) { match run(opt.command) {
Ok(_) => (), Ok(_) => (),
Err(err) => { Err(err) => {
eprintln!("Error: {}", err); error!("{}", err);
exit(1);
} }
} }
} }

View file

@ -4,8 +4,8 @@ use std::fs::File;
use std::io::Read; use std::io::Read;
use std::path::{Path, PathBuf}; use std::path::{Path, PathBuf};
use libmount::mountinfo::Parser;
use libc::c_ulong; use libc::c_ulong;
use libmount::mountinfo::Parser;
use crate::errors::Error; use crate::errors::Error;
use crate::utils; use crate::utils;

View file

@ -65,11 +65,13 @@ pub struct PutOptions {
/// Throw some files into the trash. /// Throw some files into the trash.
pub fn put(options: PutOptions) -> Result<()> { pub fn put(options: PutOptions) -> Result<()> {
let mut errors = vec![];
for path in options.paths.iter() { for path in options.paths.iter() {
let abs_path = utils::into_absolute(&path)?; let abs_path = utils::into_absolute(&path)?;
if !abs_path.exists() { if !abs_path.exists() {
error!("Skipping non-existent path {:?}", path); errors.push(Error::FileDoesntExist(path.clone()));
continue; continue;
} }
@ -102,7 +104,11 @@ pub fn put(options: PutOptions) -> Result<()> {
} }
} }
if errors.is_empty() {
Ok(()) Ok(())
} else {
Err(Error::multiple(errors.into_iter()))
}
} }
/// DeletionStrategy describes a strategy by which a file is deleted /// DeletionStrategy describes a strategy by which a file is deleted

View file

@ -24,8 +24,7 @@ pub fn into_absolute(path: impl AsRef<Path>) -> Result<PathBuf> {
for component in path.components() { for component in path.components() {
match component { match component {
Component::Prefix(_) => unimplemented!("windows lol"), Component::Prefix(_) => unimplemented!("windows lol"),
Component::RootDir => { Component::RootDir => {}
}
Component::CurDir => {} Component::CurDir => {}
Component::ParentDir => { Component::ParentDir => {
new_path.pop(); new_path.pop();