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>;
31 pub struct FinalError {
38 pub fn with_title(title: impl ToString) -> Self {
39 Self { title: title.to_string(), details: vec![], hints: vec![] }
42 pub fn detail(&mut self, detail: impl ToString) -> &mut Self {
43 self.details.push(detail.to_string());
47 pub fn hint(&mut self, hint: impl ToString) -> &mut Self {
48 self.hints.push(hint.to_string());
52 pub fn display(&self) {
54 eprintln!("{}[ERROR]{} {}", red(), reset(), self.title);
57 for detail in &self.details {
58 eprintln!(" {}-{} {}", white(), yellow(), detail);
62 if !self.hints.is_empty() {
63 // Separate by one blank line.
65 for hint in &self.hints {
66 eprintln!("{}hint:{} {}", green(), reset(), hint);
70 // Make sure to fix colors
71 eprint!("{}", reset());
74 pub fn display_and_crash(&self) -> ! {
76 std::process::exit(crate::EXIT_FAILURE)
80 impl fmt::Display for Error {
81 fn fmt(&self, _: &mut fmt::Formatter) -> fmt::Result {
83 Error::MissingExtensionError(filename) => {
84 FinalError::with_title(format!("Cannot compress to {:?}", filename))
85 .detail("Ouch could not detect the compression format")
86 .hint("Use a supported format extension, like '.zip' or '.tar.gz'")
87 .hint("Check https://github.com/vrmiguel/ouch for a full list of supported formats")
90 Error::WalkdirError { reason } => {
91 FinalError::with_title(reason).display();
93 Error::FileNotFound(file) => {
94 if file == Path::new("") {
95 FinalError::with_title("file not found!")
97 FinalError::with_title(format!("file {:?} not found!", file))
101 Error::CompressingRootFolder => {
102 FinalError::with_title("It seems you're trying to compress the root folder.")
103 .detail("This is unadvisable since ouch does compressions in-memory.")
104 .hint("Use a more appropriate tool for this, such as rsync.")
107 Error::MissingArgumentsForCompression => {
108 FinalError::with_title("Could not compress")
109 .detail("The compress command requires at least 2 arguments")
110 .hint("You must provide:")
111 .hint(" - At least one input argument.")
112 .hint(" - The output argument.")
114 .hint("Example: `ouch compress image.png img.zip`")
117 Error::InternalError => {
118 FinalError::with_title("InternalError :(")
119 .detail("This should not have happened")
120 .detail("It's probably our fault")
121 .detail("Please help us improve by reporting the issue at:")
122 .detail(format!(" {}https://github.com/vrmiguel/ouch/issues ", cyan()))
125 Error::OofError(err) => {
126 FinalError::with_title(err).display();
128 Error::IoError { reason } => {
129 FinalError::with_title(reason).display();
131 Error::CompressionTypo => {
132 FinalError::with_title("Possible typo detected")
133 .hint(format!("Did you mean '{}ouch compress{}'?", magenta(), reset()))
144 impl From<std::io::Error> for Error {
145 fn from(err: std::io::Error) -> Self {
147 std::io::ErrorKind::NotFound => panic!("{}", err),
148 std::io::ErrorKind::PermissionDenied => Self::PermissionDenied,
149 std::io::ErrorKind::AlreadyExists => Self::AlreadyExists,
150 _other => Self::IoError { reason: err.to_string() },
155 impl From<zip::result::ZipError> for Error {
156 fn from(err: zip::result::ZipError) -> Self {
157 use zip::result::ZipError::*;
159 Io(io_err) => Self::from(io_err),
160 InvalidArchive(filename) => Self::InvalidZipArchive(filename),
161 FileNotFound => Self::FileNotFound("".into()),
162 UnsupportedArchive(filename) => Self::UnsupportedZipArchive(filename),
167 impl From<walkdir::Error> for Error {
168 fn from(err: walkdir::Error) -> Self {
169 Self::WalkdirError { reason: err.to_string() }
173 impl From<oof::OofError> for Error {
174 fn from(err: oof::OofError) -> Self {