Change the errors away from using anyhow and add --all to empty

This commit is contained in:
Michael Zhang 2020-11-03 21:57:37 -06:00
parent 5579e5b951
commit 2d0421f041
Signed by: michael
GPG key ID: BDA47A31A3C8EE6B
14 changed files with 109 additions and 76 deletions

7
Cargo.lock generated
View file

@ -9,12 +9,6 @@ dependencies = [
"winapi",
]
[[package]]
name = "anyhow"
version = "1.0.33"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "a1fd36ffbb1fb7c834eac128ea8d0e310c5aeb635548f9d58861e1308d46e71c"
[[package]]
name = "arrayref"
version = "0.3.6"
@ -194,7 +188,6 @@ checksum = "a357d28ed41a50f9c765dbfe56cbc04a64e53e5fc58ba79fbc34c10ef3df831f"
name = "garbage"
version = "0.2.2"
dependencies = [
"anyhow",
"chrono",
"chrono-humanize",
"lazy_static",

View file

@ -11,7 +11,6 @@ name = "garbage"
path = "src/main.rs"
[dependencies]
anyhow = "1.0"
chrono = "0.4"
chrono-humanize = "0.1.1"
lazy_static = "1.4"

View file

@ -131,6 +131,7 @@ impl Iterator for TrashDirIter {
&name.as_bytes()[..name.len() - b".trashinfo".len()],
))
};
Some(
TrashInfo::from_files(entry.path(), deleted_path)
.map_err(Error::from),

View file

@ -1,15 +1,38 @@
use std::path::PathBuf;
/// Result convenience type for the Error type
pub type Result<T, E = Error> = std::result::Result<T, E>;
/// All errors that could happen
#[derive(Debug, Error)]
#[allow(missing_docs)]
pub enum Error {
#[error("IO error: {0}")]
Io(#[from] std::io::Error),
#[error("Walkdir error: {0}")]
WalkDir(#[from] walkdir::Error),
#[error("Bad .trashinfo file: {0}")]
BadTrashInfo(#[from] TrashInfoError),
#[error("Mount error: {0}")]
Mount(#[from] libmount::mountinfo::ParseError),
#[error("Strip prefix error: {0}")]
StripPrefix(#[from] std::path::StripPrefixError),
#[error("Bad .trashinfo file at {0:?}: {1}")]
BadTrashInfo(PathBuf, TrashInfoError),
#[error("Date parsing error: {0}")]
ParseDate(#[from] chrono::format::ParseError),
#[error("No trash directory exists at: {0:?}")]
TrashDirDoesntExist(PathBuf),
#[error("No files in the trash directory: {0:?}")]
NoFilesInThisDirectory(PathBuf),
#[error("Put error: {0}")]
Put(#[from] crate::ops::put::PutError),
}
/// Errors related to .trashinfo files
@ -18,8 +41,10 @@ pub enum Error {
pub enum TrashInfoError {
#[error("Missing [TrashInfo] header")]
MissingHeader,
#[error("Missing path attribute")]
MissingPath,
#[error("Missing date attribute")]
MissingDate,
}

View file

@ -64,6 +64,7 @@ impl TrashInfo {
if i == 0 {
if line != "[Trash Info]" {
return Err(Error::BadTrashInfo(
info_path,
TrashInfoError::MissingHeader,
));
} else {
@ -94,14 +95,20 @@ impl TrashInfo {
let path = match path {
Some(path) => path,
None => {
return Err(Error::BadTrashInfo(TrashInfoError::MissingPath))
return Err(Error::BadTrashInfo(
info_path,
TrashInfoError::MissingPath,
))
}
};
let deletion_date = match deletion_date {
Some(deletion_date) => deletion_date,
None => {
return Err(Error::BadTrashInfo(TrashInfoError::MissingDate))
return Err(Error::BadTrashInfo(
info_path,
TrashInfoError::MissingDate,
))
}
};

View file

@ -7,8 +7,6 @@ extern crate lazy_static;
#[macro_use]
extern crate structopt;
#[macro_use]
extern crate anyhow;
#[macro_use]
extern crate thiserror;
#[macro_use]
@ -26,7 +24,7 @@ use std::path::PathBuf;
use xdg::BaseDirectories;
pub use crate::dir::TrashDir;
pub use crate::errors::Error;
pub use crate::errors::{Error, Result};
pub use crate::info::TrashInfo;
use crate::mounts::Mounts;

View file

@ -1,10 +1,8 @@
#![deny(warnings)]
extern crate anyhow;
use anyhow::Result;
use garbage::ops::{
self, EmptyOptions, ListOptions, PutOptions, RestoreOptions,
use garbage::{
ops::{self, EmptyOptions, ListOptions, PutOptions, RestoreOptions},
Result,
};
use structopt::StructOpt;
@ -46,7 +44,7 @@ fn main() {
match run() {
Ok(_) => (),
Err(err) => {
eprintln!("Error: {:?}", err);
eprintln!("Error: {}", err);
// for cause in err.chain() {
// eprintln!("- {:?}", cause);
// }

View file

@ -4,9 +4,9 @@ use std::fs::File;
use std::io::Read;
use std::path::{Path, PathBuf};
use anyhow::Error;
use libmount::mountinfo::Parser;
use crate::errors::Error;
use crate::utils;
#[derive(Debug)]

View file

@ -1,9 +1,10 @@
use std::env;
use std::fs;
use std::path::PathBuf;
use anyhow::Result;
use chrono::{Duration, Local};
use crate::errors::Result;
use crate::TrashDir;
/// Options to pass to empty
@ -23,11 +24,16 @@ pub struct EmptyOptions {
/// By default, this is your home directory's trash ($XDG_DATA_HOME/Trash)
#[structopt(long = "trash-dir", parse(from_os_str))]
trash_dir: Option<PathBuf>,
/// Delete all files in the trash (by default, only files in the current
/// directory are listed)
#[structopt(short = "a", long = "all")]
all: bool,
}
/// Actually delete files in the trash.
pub fn empty(options: EmptyOptions) -> Result<()> {
let trash_dir = TrashDir::from_opt(options.trash_dir);
let trash_dir = TrashDir::from_opt(options.trash_dir.as_ref());
// cutoff date
let cutoff = if let Some(days) = options.days {
@ -36,28 +42,32 @@ pub fn empty(options: EmptyOptions) -> Result<()> {
Local::now()
};
for file in trash_dir.iter()? {
let file = file?;
let current_dir = env::current_dir()?;
trash_dir
.iter()?
.collect::<Result<Vec<_>>>()?
.into_iter()
// ignore files that were deleted after the cutoff (younger)
let ignore = file.deletion_date > cutoff;
if !ignore {
.filter(|info| info.deletion_date <= cutoff)
.filter(|info| options.all || info.path.starts_with(&current_dir))
.map(|info| -> Result<_> {
if options.dry {
println!("{:?}", file.path);
println!("deleting {:?}", info.path);
} else {
fs::remove_file(file.info_path)?;
fs::remove_file(info.info_path)?;
if file.deleted_path.exists() {
if file.deleted_path.is_dir() {
fs::remove_dir_all(file.deleted_path)?;
if info.deleted_path.exists() {
if info.deleted_path.is_dir() {
fs::remove_dir_all(info.deleted_path)?;
} else {
fs::remove_file(file.deleted_path)?;
fs::remove_file(info.deleted_path)?;
}
}
}
}
}
Ok(())
})
.collect::<Result<_>>()?;
Ok(())
}

View file

@ -1,10 +1,9 @@
use std::path::PathBuf;
use std::env;
use std::path::PathBuf;
use anyhow::Result;
use crate::dir::TrashDir;
use crate::errors::Result;
use crate::list;
use crate::TrashDir;
/// Options to pass to list
#[derive(StructOpt)]
@ -25,19 +24,16 @@ pub fn list(options: ListOptions) -> Result<()> {
let trash_dir = TrashDir::from_opt(options.trash_dir.as_ref());
let current_dir = env::current_dir()?;
let mut files = trash_dir
.iter()
.unwrap()
.filter_map(|entry| match entry {
Ok(info) => {
if !options.all && !info.path.starts_with(&current_dir) {
return None;
}
Some(info)
}
Err(err) => {
eprintln!("failed to get file info: {:?}", err);
.iter()?
.collect::<Result<Vec<_>>>()?
.into_iter()
.filter_map(|info| {
if !options.all && !info.path.starts_with(&current_dir) {
None
} else {
Some(info)
}
})
.collect::<Vec<_>>();

View file

@ -1,9 +1,9 @@
//! Operations that garbage can do.
mod empty;
mod list;
mod put;
mod restore;
pub(crate) mod empty;
pub(crate) mod list;
pub(crate) mod put;
pub(crate) mod restore;
pub use self::empty::{empty, EmptyOptions};
pub use self::list::{list, ListOptions};

View file

@ -4,15 +4,15 @@ use std::io::{self, Write};
use std::os::unix::fs::PermissionsExt;
use std::path::{Path, PathBuf};
use anyhow::Result;
use chrono::Local;
use crate::errors::{Error, Result};
use crate::utils::{self};
use crate::{TrashDir, TrashInfo};
use crate::{HOME_MOUNT, MOUNTS};
#[derive(Debug, Error)]
pub enum Error {
pub enum PutError {
// #[error("Refusing to remove directory {0} without '-r' option")]
// MissingRecursiveOption(PathBuf),
#[error("Refusing to remove '.' or '..', skipping...")]
@ -23,6 +23,9 @@ pub enum Error {
#[error("Invalid filename.")]
InvalidFilename,
#[error("Couldn't find mount point.")]
CouldntFindMountPoint,
}
/// Options to pass to put
@ -65,13 +68,14 @@ pub fn put(options: PutOptions) -> Result<()> {
for path in options.paths.iter() {
// don't allow deleting '.' or '..'
let current_dir = env::current_dir()?;
ensure!(
!(utils::into_absolute(&path)? == current_dir.as_path()
|| (current_dir.parent().is_some()
&& utils::into_absolute(&path)?
== current_dir.parent().unwrap())),
Error::CannotTrashDotDirs
);
if !(utils::into_absolute(&path)? == current_dir.as_path()
|| (current_dir.parent().is_some()
&& utils::into_absolute(&path)?
== current_dir.parent().unwrap()))
{
return Err(Error::Put(PutError::CannotTrashDotDirs));
}
// pick the best strategy for deleting this particular file
let strategy = if let Some(ref trash_dir) = options.trash_dir {
@ -112,7 +116,7 @@ impl DeletionStrategy {
let target = target.as_ref();
let target_mount = MOUNTS
.get_mount_point(target)
.ok_or_else(|| anyhow!("couldn't get mount point"))?;
.ok_or_else(|| PutError::CouldntFindMountPoint)?;
// first, are we on the home mount?
if target_mount == *HOME_MOUNT {
@ -193,7 +197,7 @@ impl DeletionStrategy {
}
};
if !should_continue {
bail!(Error::CancelledByUser);
return Err(Error::Put(PutError::CancelledByUser));
}
}
@ -204,9 +208,9 @@ impl DeletionStrategy {
let elapsed_str = elapsed.to_string();
let target_file = match target.file_name() {
Some(file) => file.to_os_string(),
None => bail!(Error::InvalidFilename),
None => return Err(Error::Put(PutError::InvalidFilename)),
};
let file_name = crate::concat_os_str!(elapsed_str, ".", target_file);
let file_name = concat_os_str!(elapsed_str, ".", target_file);
// {
// let buf = vec![0; elapsed_str.len() + 1 + target_file.len()];
// unimplemented!()
@ -220,7 +224,7 @@ impl DeletionStrategy {
let trash_file_path = trash_dir.files_dir()?.join(&file_name);
let trash_info_path = trash_dir
.info_dir()?
.join(crate::concat_os_str!(file_name, ".trashinfo"));
.join(concat_os_str!(file_name, ".trashinfo"));
let trash_info = TrashInfo {
path: utils::into_absolute(target)?,

View file

@ -3,8 +3,7 @@ use std::fs;
use std::io;
use std::path::PathBuf;
use anyhow::Result;
use crate::errors::{Error, Result};
use crate::list;
use crate::TrashDir;
@ -27,7 +26,7 @@ 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() {
bail!("There's no trash directory here.");
return Err(Error::TrashDirDoesntExist(trash_dir.path().to_path_buf()));
}
// get list of files sorted by deletion date
@ -55,7 +54,9 @@ pub fn restore(options: RestoreOptions) -> Result<()> {
};
if files.len() == 0 {
bail!("No files in this trash directory.");
return Err(Error::NoFilesInThisDirectory(
trash_dir.path().to_path_buf(),
));
}
list::print_files_list(files.iter(), true);

View file

@ -4,10 +4,11 @@ use std::fs;
use std::os::unix::ffi::OsStrExt;
use std::path::{Component, Path, PathBuf, MAIN_SEPARATOR};
use anyhow::Result;
use percent_encoding::AsciiSet;
use walkdir::WalkDir;
use crate::errors::Result;
const MASK: &AsciiSet = percent_encoding::CONTROLS;
pub fn into_absolute(path: impl AsRef<Path>) -> Result<PathBuf> {