6 use crate::{oof, utils::colors::*};
8 #[derive(Debug, PartialEq)]
10 UnknownExtensionError(String),
11 MissingExtensionError(PathBuf),
12 // TODO: get rid of this error variant
15 IoError { reason: String },
16 FileNotFound(PathBuf),
18 InvalidZipArchive(&'static str),
20 UnsupportedZipArchive(&'static str),
22 OofError(oof::OofError),
23 CompressingRootFolder,
24 MissingArgumentsForCompression,
26 WalkdirError { reason: String },
29 pub type Result<T> = std::result::Result<T, Error>;
32 pub struct FinalError {
38 impl Display for FinalError {
39 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
41 writeln!(f, "{}[ERROR]{} {}", red(), reset(), self.title)?;
44 for detail in &self.details {
45 writeln!(f, " {}-{} {}", white(), yellow(), detail)?;
49 if !self.hints.is_empty() {
50 // Separate by one blank line.
52 for hint in &self.hints {
53 writeln!(f, "{}hint:{} {}", green(), reset(), hint)?;
57 write!(f, "{}", reset())
62 pub fn with_title(title: impl ToString) -> Self {
63 Self { title: title.to_string(), details: vec![], hints: vec![] }
66 pub fn detail(&mut self, detail: impl ToString) -> &mut Self {
67 self.details.push(detail.to_string());
71 pub fn hint(&mut self, hint: impl ToString) -> &mut Self {
72 self.hints.push(hint.to_string());
76 pub fn to_owned(&mut self) -> Self {
80 pub fn display_and_crash(&self) -> ! {
81 eprintln!("{}", self);
82 std::process::exit(crate::EXIT_FAILURE)
86 impl fmt::Display for Error {
87 fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
88 let err = match self {
89 Error::MissingExtensionError(filename) => {
90 let error = FinalError::with_title(format!("Cannot compress to {:?}", filename))
91 .detail("Ouch could not detect the compression format")
92 .hint("Use a supported format extension, like '.zip' or '.tar.gz'")
93 .hint("Check https://github.com/vrmiguel/ouch for a full list of supported formats")
98 Error::WalkdirError { reason } => FinalError::with_title(reason),
99 Error::FileNotFound(file) => {
100 let error = if file == Path::new("") {
101 FinalError::with_title("file not found!")
103 FinalError::with_title(format!("file {:?} not found!", file))
108 Error::CompressingRootFolder => {
109 let error = FinalError::with_title("It seems you're trying to compress the root folder.")
110 .detail("This is unadvisable since ouch does compressions in-memory.")
111 .hint("Use a more appropriate tool for this, such as rsync.")
116 Error::MissingArgumentsForCompression => {
117 let error = FinalError::with_title("Could not compress")
118 .detail("The compress command requires at least 2 arguments")
119 .hint("You must provide:")
120 .hint(" - At least one input argument.")
121 .hint(" - The output argument.")
123 .hint("Example: `ouch compress image.png img.zip`")
128 Error::InternalError => {
129 let error = FinalError::with_title("InternalError :(")
130 .detail("This should not have happened")
131 .detail("It's probably our fault")
132 .detail("Please help us improve by reporting the issue at:")
133 .detail(format!(" {}https://github.com/vrmiguel/ouch/issues ", cyan()))
138 Error::OofError(err) => FinalError::with_title(err),
139 Error::IoError { reason } => FinalError::with_title(reason),
140 Error::CompressionTypo => FinalError::with_title("Possible typo detected")
141 .hint(format!("Did you mean '{}ouch compress{}'?", magenta(), reset()))
152 impl From<std::io::Error> for Error {
153 fn from(err: std::io::Error) -> Self {
155 std::io::ErrorKind::NotFound => panic!("{}", err),
156 std::io::ErrorKind::PermissionDenied => Self::PermissionDenied,
157 std::io::ErrorKind::AlreadyExists => Self::AlreadyExists,
158 _other => Self::IoError { reason: err.to_string() },
163 impl From<zip::result::ZipError> for Error {
164 fn from(err: zip::result::ZipError) -> Self {
165 use zip::result::ZipError::*;
167 Io(io_err) => Self::from(io_err),
168 InvalidArchive(filename) => Self::InvalidZipArchive(filename),
169 FileNotFound => Self::FileNotFound("".into()),
170 UnsupportedArchive(filename) => Self::UnsupportedZipArchive(filename),
175 impl From<walkdir::Error> for Error {
176 fn from(err: walkdir::Error) -> Self {
177 Self::WalkdirError { reason: err.to_string() }
181 impl From<oof::OofError> for Error {
182 fn from(err: oof::OofError) -> Self {