diff --git a/Cargo.lock b/Cargo.lock index 68b82c9..c098ebd 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -148,6 +148,12 @@ dependencies = [ "miniz_oxide", ] +[[package]] +name = "fs-err" +version = "2.6.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5ebd3504ad6116843b8375ad70df74e7bfe83cac77a1f3fe73200c844d43bfe0" + [[package]] name = "getrandom" version = "0.2.3" @@ -284,6 +290,7 @@ dependencies = [ "bzip2", "clap", "flate2", + "fs-err", "infer", "libc", "once_cell", diff --git a/Cargo.toml b/Cargo.toml index c42ac8b..248f33a 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -15,6 +15,7 @@ description = "A command-line utility for easily compressing and decompressing f [dependencies] clap = "=3.0.0-beta.5" # Keep it pinned while in beta! atty = "0.2.14" +fs-err = "2.6.0" once_cell = "1.8.0" walkdir = "2.3.2" bzip2 = "0.4.3" diff --git a/src/archive/tar.rs b/src/archive/tar.rs index bb52d7e..6b23278 100644 --- a/src/archive/tar.rs +++ b/src/archive/tar.rs @@ -1,15 +1,17 @@ //! Contains Tar-specific building and unpacking functions use std::{ - env, fs, + env, io::prelude::*, path::{Path, PathBuf}, }; +use fs_err as fs; use tar; use walkdir::WalkDir; use crate::{ + error::FinalError, info, utils::{self, Bytes, QuestionPolicy}, }; @@ -62,7 +64,12 @@ where builder.append_dir(path, path)?; } else { let mut file = fs::File::open(path)?; - builder.append_file(path, &mut file)?; + builder.append_file(path, file.file_mut()).map_err(|err| { + FinalError::with_title("Could not create archive") + .detail("Unexpected error while trying to read file") + .detail(format!("Error: {}.", err)) + .into_owned() + })?; } } env::set_current_dir(previous_location)?; diff --git a/src/archive/zip.rs b/src/archive/zip.rs index 87d1a17..4ef9a85 100644 --- a/src/archive/zip.rs +++ b/src/archive/zip.rs @@ -1,11 +1,13 @@ //! Contains Zip-specific building and unpacking functions use std::{ - env, fs, + env, io::{self, prelude::*}, path::{Path, PathBuf}, }; +use fs_err as fs; + use walkdir::WalkDir; use zip::{self, read::ZipFile, ZipArchive}; @@ -126,10 +128,11 @@ fn check_for_comments(file: &ZipFile) { #[cfg(unix)] fn __unix_set_permissions(file_path: &Path, file: &ZipFile) -> crate::Result<()> { + use std::fs::Permissions; use std::os::unix::fs::PermissionsExt; if let Some(mode) = file.unix_mode() { - fs::set_permissions(file_path, fs::Permissions::from_mode(mode))?; + fs::set_permissions(file_path, Permissions::from_mode(mode))?; } Ok(()) diff --git a/src/cli.rs b/src/cli.rs index 1ec281b..e0b8441 100644 --- a/src/cli.rs +++ b/src/cli.rs @@ -6,6 +6,7 @@ use std::{ }; use clap::{Parser, ValueHint}; +use fs_err as fs; pub use crate::utils::QuestionPolicy; use crate::Error; @@ -73,7 +74,7 @@ impl Opts { } fn canonicalize(path: impl AsRef) -> crate::Result { - match std::fs::canonicalize(&path.as_ref()) { + match fs::canonicalize(&path.as_ref()) { Ok(abs_path) => Ok(abs_path), Err(io_err) => { if !path.as_ref().exists() { diff --git a/src/commands.rs b/src/commands.rs index 2543c67..6d99a77 100644 --- a/src/commands.rs +++ b/src/commands.rs @@ -3,11 +3,11 @@ //! Also, where correctly call functions based on the detected `Command`. use std::{ - fs, io::{self, BufReader, BufWriter, Read, Write}, path::{Path, PathBuf}, }; +use fs_err as fs; use utils::colors; use crate::{ diff --git a/src/error.rs b/src/error.rs index a8dd654..4773970 100644 --- a/src/error.rs +++ b/src/error.rs @@ -21,7 +21,7 @@ pub enum Error { FileNotFound(PathBuf), AlreadyExists, InvalidZipArchive(&'static str), - PermissionDenied, + PermissionDenied { error_title: String }, UnsupportedZipArchive(&'static str), InternalError, CompressingRootFolder, @@ -78,6 +78,10 @@ impl FinalError { self.hints.push(hint.to_string()); self } + + pub fn into_owned(&mut self) -> Self { + std::mem::take(self) + } } impl fmt::Display for Error { @@ -134,7 +138,9 @@ impl fmt::Display for Error { Error::UnknownExtensionError(_) => todo!(), Error::AlreadyExists => todo!(), Error::InvalidZipArchive(_) => todo!(), - Error::PermissionDenied => todo!(), + Error::PermissionDenied { error_title } => { + FinalError::with_title(error_title).detail("Permission denied").to_owned() + } Error::UnsupportedZipArchive(_) => todo!(), Error::Custom { reason } => reason.clone(), }; @@ -152,8 +158,8 @@ impl Error { impl From for Error { fn from(err: std::io::Error) -> Self { match err.kind() { - std::io::ErrorKind::NotFound => panic!("{}", err), - std::io::ErrorKind::PermissionDenied => Self::PermissionDenied, + std::io::ErrorKind::NotFound => todo!(), + std::io::ErrorKind::PermissionDenied => Self::PermissionDenied { error_title: err.to_string() }, std::io::ErrorKind::AlreadyExists => Self::AlreadyExists, _other => Self::IoError { reason: err.to_string() }, } @@ -177,3 +183,9 @@ impl From for Error { Self::WalkdirError { reason: err.to_string() } } } + +impl From for Error { + fn from(err: FinalError) -> Self { + Self::Custom { reason: err } + } +} diff --git a/src/utils.rs b/src/utils.rs index 7c3a0e7..3c77495 100644 --- a/src/utils.rs +++ b/src/utils.rs @@ -1,16 +1,17 @@ use std::{ cmp, env, ffi::OsStr, - fs::{self, ReadDir}, path::Component, path::{Path, PathBuf}, }; +use fs_err as fs; + use crate::{dialogs::Confirmation, info}; /// Checks if the given path represents an empty directory. pub fn dir_is_empty(dir_path: &Path) -> bool { - let is_empty = |mut rd: ReadDir| rd.next().is_none(); + let is_empty = |mut rd: std::fs::ReadDir| rd.next().is_none(); dir_path.read_dir().map(is_empty).unwrap_or_default() } diff --git a/tests/compress_and_decompress.rs b/tests/compress_and_decompress.rs index 45518d0..f78a5aa 100644 --- a/tests/compress_and_decompress.rs +++ b/tests/compress_and_decompress.rs @@ -1,12 +1,14 @@ mod utils; use std::{ - env, fs, + env, io::prelude::*, path::{Path, PathBuf}, time::Duration, }; +use fs_err as fs; + use ouch::{ cli::{Opts, QuestionPolicy, Subcommand}, commands::run, diff --git a/tests/utils.rs b/tests/utils.rs index e55aac2..0d0fdd0 100644 --- a/tests/utils.rs +++ b/tests/utils.rs @@ -2,10 +2,9 @@ #![allow(dead_code)] -use std::{ - fs, - path::{Path, PathBuf}, -}; +use std::path::{Path, PathBuf}; + +use fs_err as fs; use ouch::{ cli::{Opts, QuestionPolicy, Subcommand},