use std::fmt::Display;
use std::io;
use std::path::PathBuf;
use thiserror::Error;
use tr::tr;
#[derive(Debug)]
pub enum PathType {
File,
Directory,
Symlink,
}
impl Display for PathType {
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
match self {
PathType::File => write!(f, "{}", tr!("file")),
PathType::Directory => write!(f, "{}", tr!("directory")),
PathType::Symlink => write!(f, "{}", tr!("symbolic link")),
}
}
}
#[derive(Debug)]
pub enum PathErrorKind {
NotValidUTF8 {
for_item: String,
path_type: PathType,
},
DoesNotExist,
CannotCreate(PathType, io::Error),
CannotDelete(PathType, io::Error),
CannotRename(PathType, PathBuf, io::Error),
NotInsideDirectory(String, PathBuf),
}
#[derive(Error, Debug)]
pub struct PathError {
pub path: PathBuf,
pub kind: PathErrorKind,
}
impl PathError {
pub fn cannot_create_dir<P: Into<PathBuf>>(path: P, source: io::Error) -> PathError {
PathError {
path: path.into(),
kind: PathErrorKind::CannotCreate(PathType::Directory, source),
}
}
pub fn cannot_create_file<P: Into<PathBuf>>(path: P, source: io::Error) -> PathError {
PathError {
path: path.into(),
kind: PathErrorKind::CannotCreate(PathType::File, source),
}
}
pub fn cannot_delete_dir<P: Into<PathBuf>>(path: P, source: io::Error) -> PathError {
PathError {
path: path.into(),
kind: PathErrorKind::CannotDelete(PathType::Directory, source),
}
}
pub fn cannot_delete_file<P: Into<PathBuf>>(path: P, source: io::Error) -> PathError {
PathError {
path: path.into(),
kind: PathErrorKind::CannotCreate(PathType::Directory, source),
}
}
pub fn cannot_rename_file<P: Into<PathBuf>>(from: P, to: P, source: io::Error) -> PathError {
PathError {
path: from.into(),
kind: PathErrorKind::CannotRename(PathType::File, to.into(), source),
}
}
pub fn does_not_exist<P: Into<PathBuf>>(path: P) -> PathError {
PathError {
path: path.into(),
kind: PathErrorKind::DoesNotExist,
}
}
pub fn not_valid_utf8<F: Into<String>, P: Into<PathBuf>>(
path: P,
for_item: F,
path_type: PathType,
) -> PathError {
PathError {
path: path.into(),
kind: PathErrorKind::NotValidUTF8 {
for_item: for_item.into(),
path_type,
},
}
}
pub fn not_inside_dir<S: Into<String>, P: Into<PathBuf>>(
path: P,
parent_name: S,
parent_path: P,
) -> PathError {
PathError {
path: path.into(),
kind: PathErrorKind::NotInsideDirectory(parent_name.into(), parent_path.into()),
}
}
}
impl Display for PathError {
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
let message = match &self.kind {
PathErrorKind::NotValidUTF8 {
for_item,
path_type,
} => {
tr!(
"The path (\"{0}\") for {1} {2} does not have valid a utf-8 encoding.",
self.path.to_string_lossy(),
for_item,
path_type
)
}
PathErrorKind::DoesNotExist => tr!(
"The path \"{0}\" does not exist on the filesystem.",
self.path.to_string_lossy()
),
PathErrorKind::CannotCreate(path_type, source) => tr!(
"Cannot create the {0} \"{1}\" because: \"{2}\".",
path_type,
self.path.to_string_lossy(),
source
),
PathErrorKind::CannotDelete(path_type, source) => tr!(
"Cannot delete the {0} \"{1}\" because: \"{2}\".",
path_type,
self.path.to_string_lossy(),
source
),
PathErrorKind::CannotRename(path_type, to, source) => tr!(
"Cannot rename the {0} \"{1}\" to \"{2}\" because {3}.",
path_type,
self.path.to_string_lossy(),
to.to_string_lossy(),
source
),
PathErrorKind::NotInsideDirectory(parent_name, parent_dir) => tr!(
"The path \"{0}\" is not inside the \"{1}\" directory: \"{2}\".",
self.path.to_string_lossy(),
parent_name,
parent_dir.to_string_lossy(),
),
};
write!(f, "{}", message)
}
}