---
src/errors.rs | 37 +++++++++++++++++++++++++++++++++++--
src/info.rs | 17 ++++++++++-------
src/ops/put.rs | 10 ++++++----
src/ops/restore.rs | 12 ++++++++----
4 files changed, 59 insertions(+), 17 deletions(-)
diff --git a/src/errors.rs b/src/errors.rs
index 6346f97..9db81ae 100644
--- a/src/errors.rs
+++ b/src/errors.rs
@@ -1,12 +1,45 @@
-use std::path::PathBuf;
+use std::{
+ fmt::{Display, Formatter, Result as FmtResult},
+ path::PathBuf,
+};
/// Result convenience type for the Error type
pub type Result<T, E = Error> = std::result::Result<T, E>;
+/// Errors plus their surrounding context.
+#[derive(Debug, Error)]
+pub struct Error {
+ /// The cause of the error.
+ #[source]
+ pub kind: ErrorKind,
+
+ /// A stack of things that were being done when the error occurred.
+ pub context: Vec<String>,
+}
+
+impl Display for Error {
+ fn fmt(&self, fmt: &mut Formatter) -> FmtResult {
+ writeln!(fmt, "{}", self.kind)?;
+ for entry in self.context.iter().rev() {
+ writeln!(fmt, "caused by {}", entry)?;
+ }
+ Ok(())
+ }
+}
+
+impl<T: Into<ErrorKind>> From<T> for Error {
+ fn from(kind: T) -> Error {
+ Error {
+ kind: kind.into(),
+ context: Vec::new(),
+ }
+ }
+}
+
/// All errors that could happen
#[derive(Debug, Error)]
#[allow(missing_docs)]
-pub enum Error {
+pub enum ErrorKind {
#[error("IO error: {0}")]
Io(#[from] std::io::Error),
diff --git a/src/info.rs b/src/info.rs
index a52ae26..58b3e10 100644
--- a/src/info.rs
+++ b/src/info.rs
@@ -7,7 +7,7 @@ use std::path::{Path, PathBuf};
use chrono::{DateTime, Local, TimeZone};
use percent_encoding::percent_decode;
-use crate::errors::{Error, TrashInfoError};
+use crate::errors::{Error, ErrorKind, TrashInfoError};
use crate::utils;
const DATE_FORMAT: &str = "%Y-%m-%dT%H:%M:%S";
@@ -63,10 +63,11 @@ impl TrashInfo {
// first line must be "[Trash Info]"
if i == 0 {
if line != "[Trash Info]" {
- return Err(Error::BadTrashInfo(
+ return Err(ErrorKind::BadTrashInfo(
info_path,
TrashInfoError::MissingHeader,
- ));
+ )
+ .into());
} else {
continue;
}
@@ -95,20 +96,22 @@ impl TrashInfo {
let path = match path {
Some(path) => path,
None => {
- return Err(Error::BadTrashInfo(
+ return Err(ErrorKind::BadTrashInfo(
info_path,
TrashInfoError::MissingPath,
- ))
+ )
+ .into())
}
};
let deletion_date = match deletion_date {
Some(deletion_date) => deletion_date,
None => {
- return Err(Error::BadTrashInfo(
+ return Err(ErrorKind::BadTrashInfo(
info_path,
TrashInfoError::MissingDate,
- ))
+ )
+ .into())
}
};
diff --git a/src/ops/put.rs b/src/ops/put.rs
index 6d42b7d..50bc2e6 100644
--- a/src/ops/put.rs
+++ b/src/ops/put.rs
@@ -6,7 +6,7 @@ use std::path::{Path, PathBuf};
use chrono::Local;
-use crate::errors::{Error, Result};
+use crate::errors::{ErrorKind, Result};
use crate::utils::{self};
use crate::{TrashDir, TrashInfo};
use crate::{HOME_MOUNT, MOUNTS};
@@ -79,7 +79,7 @@ pub fn put(options: PutOptions) -> Result<()> {
|| (current_dir.parent().is_some()
&& abs_path == current_dir.parent().unwrap())
{
- return Err(Error::Put(PutError::CannotTrashDotDirs));
+ return Err(ErrorKind::Put(PutError::CannotTrashDotDirs).into());
}
// pick the best strategy for deleting this particular file
@@ -202,7 +202,7 @@ impl DeletionStrategy {
}
};
if !should_continue {
- return Err(Error::Put(PutError::CancelledByUser));
+ return Err(ErrorKind::Put(PutError::CancelledByUser).into());
}
}
@@ -213,7 +213,9 @@ impl DeletionStrategy {
let elapsed_str = elapsed.to_string();
let target_file = match target.file_name() {
Some(file) => file.to_os_string(),
- None => return Err(Error::Put(PutError::InvalidFilename)),
+ None => {
+ return Err(ErrorKind::Put(PutError::InvalidFilename).into())
+ }
};
let file_name = concat_os_str!(elapsed_str, ".", target_file);
// {
diff --git a/src/ops/restore.rs b/src/ops/restore.rs
index 4103e91..c0d363e 100644
--- a/src/ops/restore.rs
+++ b/src/ops/restore.rs
@@ -3,7 +3,7 @@ use std::fs;
use std::io;
use std::path::PathBuf;
-use crate::errors::{Error, Result};
+use crate::errors::{ErrorKind, Result};
use crate::list;
use crate::TrashDir;
@@ -26,7 +26,10 @@ pub fn restore(options: RestoreOptions) -> Result<()> {
let trash_dir = TrashDir::from_opt(options.trash_dir.as_ref());
if trash_dir.check_info_dir()?.is_none() {
- return Err(Error::TrashDirDoesntExist(trash_dir.path().to_path_buf()));
+ return Err(ErrorKind::TrashDirDoesntExist(
+ trash_dir.path().to_path_buf(),
+ )
+ .into());
}
// get list of files sorted by deletion date
@@ -54,9 +57,10 @@ pub fn restore(options: RestoreOptions) -> Result<()> {
};
if files.len() == 0 {
- return Err(Error::NoFilesInThisDirectory(
+ return Err(ErrorKind::NoFilesInThisDirectory(
trash_dir.path().to_path_buf(),
- ));
+ )
+ .into());
}
list::print_files_list(files.iter(), true);
--
2.28.0