mirror of
https://github.com/ouch-org/ouch.git
synced 2025-06-07 12:05:46 +00:00
Merge pull request #10 from vrmiguel/better-error-messages
Better error messages
This commit is contained in:
commit
0f453e9dfc
@ -29,7 +29,7 @@ pub enum Flags {
|
|||||||
// Flag -y, --yes supplied
|
// Flag -y, --yes supplied
|
||||||
AlwaysYes,
|
AlwaysYes,
|
||||||
// Flag -n, --no supplied
|
// Flag -n, --no supplied
|
||||||
AlwaysNo
|
AlwaysNo,
|
||||||
}
|
}
|
||||||
|
|
||||||
#[derive(PartialEq, Eq, Debug)]
|
#[derive(PartialEq, Eq, Debug)]
|
||||||
@ -104,7 +104,7 @@ pub fn parse_matches(matches: clap::ArgMatches<'static>) -> crate::Result<(Comma
|
|||||||
(true, true) => unreachable!(),
|
(true, true) => unreachable!(),
|
||||||
(true, _) => Flags::AlwaysYes,
|
(true, _) => Flags::AlwaysYes,
|
||||||
(_, true) => Flags::AlwaysNo,
|
(_, true) => Flags::AlwaysNo,
|
||||||
(_, _) => Flags::None
|
(_, _) => Flags::None,
|
||||||
};
|
};
|
||||||
|
|
||||||
Ok((Command::try_from(matches)?, flag))
|
Ok((Command::try_from(matches)?, flag))
|
||||||
@ -179,7 +179,6 @@ impl TryFrom<clap::ArgMatches<'static>> for Command {
|
|||||||
output: Some(File {
|
output: Some(File {
|
||||||
path: output_file.into(),
|
path: output_file.into(),
|
||||||
contents_in_memory: None,
|
contents_in_memory: None,
|
||||||
// extension: output_file_extension.ok(),
|
|
||||||
extension: Some(output_file_extension.unwrap()),
|
extension: Some(output_file_extension.unwrap()),
|
||||||
}),
|
}),
|
||||||
})
|
})
|
||||||
|
@ -36,8 +36,7 @@ impl BzipCompressor {
|
|||||||
let bytes = match file.contents_in_memory {
|
let bytes = match file.contents_in_memory {
|
||||||
Some(bytes) => bytes,
|
Some(bytes) => bytes,
|
||||||
None => {
|
None => {
|
||||||
// TODO: error message,
|
return Err(crate::Error::InternalError);
|
||||||
return Err(crate::Error::InvalidInput);
|
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
|
@ -14,8 +14,8 @@ impl TarCompressor {
|
|||||||
// TODO: implement this
|
// TODO: implement this
|
||||||
fn make_archive_from_memory(_input: File) -> crate::Result<Vec<u8>> {
|
fn make_archive_from_memory(_input: File) -> crate::Result<Vec<u8>> {
|
||||||
println!(
|
println!(
|
||||||
"{}: .tar.tar and .zip.tar is currently unimplemented.",
|
"{} .tar.tar and .zip.tar is currently unimplemented.",
|
||||||
"error".red()
|
"[ERROR]".red()
|
||||||
);
|
);
|
||||||
Err(crate::Error::InvalidZipArchive(""))
|
Err(crate::Error::InvalidZipArchive(""))
|
||||||
}
|
}
|
||||||
|
@ -1,9 +1,6 @@
|
|||||||
use std::path::PathBuf;
|
use std::path::PathBuf;
|
||||||
|
|
||||||
use crate::{
|
use crate::{cli::Flags, file::File};
|
||||||
cli::Flags,
|
|
||||||
file::File
|
|
||||||
};
|
|
||||||
|
|
||||||
pub enum DecompressionResult {
|
pub enum DecompressionResult {
|
||||||
FilesUnpacked(Vec<PathBuf>),
|
FilesUnpacked(Vec<PathBuf>),
|
||||||
@ -11,5 +8,10 @@ pub enum DecompressionResult {
|
|||||||
}
|
}
|
||||||
|
|
||||||
pub trait Decompressor {
|
pub trait Decompressor {
|
||||||
fn decompress(&self, from: File, into: &Option<File>, flags: Flags) -> crate::Result<DecompressionResult>;
|
fn decompress(
|
||||||
|
&self,
|
||||||
|
from: File,
|
||||||
|
into: &Option<File>,
|
||||||
|
flags: Flags,
|
||||||
|
) -> crate::Result<DecompressionResult>;
|
||||||
}
|
}
|
||||||
|
@ -24,9 +24,7 @@ impl TarDecompressor {
|
|||||||
let confirm = Confirmation::new("Do you want to overwrite 'FILE'?", Some("FILE"));
|
let confirm = Confirmation::new("Do you want to overwrite 'FILE'?", Some("FILE"));
|
||||||
|
|
||||||
let mut archive: Archive<Box<dyn Read>> = match from.contents_in_memory {
|
let mut archive: Archive<Box<dyn Read>> = match from.contents_in_memory {
|
||||||
Some(bytes) => {
|
Some(bytes) => tar::Archive::new(Box::new(Cursor::new(bytes))),
|
||||||
tar::Archive::new(Box::new(Cursor::new(bytes)))
|
|
||||||
},
|
|
||||||
None => {
|
None => {
|
||||||
let file = fs::File::open(&from.path)?;
|
let file = fs::File::open(&from.path)?;
|
||||||
tar::Archive::new(Box::new(file))
|
tar::Archive::new(Box::new(file))
|
||||||
@ -62,7 +60,12 @@ impl TarDecompressor {
|
|||||||
}
|
}
|
||||||
|
|
||||||
impl Decompressor for TarDecompressor {
|
impl Decompressor for TarDecompressor {
|
||||||
fn decompress(&self, from: File, into: &Option<File>, flags: Flags) -> crate::Result<DecompressionResult> {
|
fn decompress(
|
||||||
|
&self,
|
||||||
|
from: File,
|
||||||
|
into: &Option<File>,
|
||||||
|
flags: Flags,
|
||||||
|
) -> crate::Result<DecompressionResult> {
|
||||||
let destination_path = utils::get_destination_path(into);
|
let destination_path = utils::get_destination_path(into);
|
||||||
|
|
||||||
utils::create_path_if_non_existent(destination_path)?;
|
utils::create_path_if_non_existent(destination_path)?;
|
||||||
|
@ -62,19 +62,34 @@ impl DecompressorToMemory {
|
|||||||
}
|
}
|
||||||
|
|
||||||
impl Decompressor for GzipDecompressor {
|
impl Decompressor for GzipDecompressor {
|
||||||
fn decompress(&self, from: File, into: &Option<File>, _: Flags) -> crate::Result<DecompressionResult> {
|
fn decompress(
|
||||||
|
&self,
|
||||||
|
from: File,
|
||||||
|
into: &Option<File>,
|
||||||
|
_: Flags,
|
||||||
|
) -> crate::Result<DecompressionResult> {
|
||||||
DecompressorToMemory::decompress(from, CompressionFormat::Gzip, into)
|
DecompressorToMemory::decompress(from, CompressionFormat::Gzip, into)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl Decompressor for BzipDecompressor {
|
impl Decompressor for BzipDecompressor {
|
||||||
fn decompress(&self, from: File, into: &Option<File>, _: Flags) -> crate::Result<DecompressionResult> {
|
fn decompress(
|
||||||
|
&self,
|
||||||
|
from: File,
|
||||||
|
into: &Option<File>,
|
||||||
|
_: Flags,
|
||||||
|
) -> crate::Result<DecompressionResult> {
|
||||||
DecompressorToMemory::decompress(from, CompressionFormat::Bzip, into)
|
DecompressorToMemory::decompress(from, CompressionFormat::Bzip, into)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl Decompressor for LzmaDecompressor {
|
impl Decompressor for LzmaDecompressor {
|
||||||
fn decompress(&self, from: File, into: &Option<File>, _: Flags) -> crate::Result<DecompressionResult> {
|
fn decompress(
|
||||||
|
&self,
|
||||||
|
from: File,
|
||||||
|
into: &Option<File>,
|
||||||
|
_: Flags,
|
||||||
|
) -> crate::Result<DecompressionResult> {
|
||||||
DecompressorToMemory::decompress(from, CompressionFormat::Lzma, into)
|
DecompressorToMemory::decompress(from, CompressionFormat::Lzma, into)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -95,11 +95,7 @@ impl ZipDecompressor {
|
|||||||
}
|
}
|
||||||
|
|
||||||
fn unpack_files(from: File, into: &Path, flags: Flags) -> crate::Result<Vec<PathBuf>> {
|
fn unpack_files(from: File, into: &Path, flags: Flags) -> crate::Result<Vec<PathBuf>> {
|
||||||
println!(
|
println!("{} decompressing {:?}", "[OUCH]".bright_blue(), &from.path);
|
||||||
"{} decompressing {:?}",
|
|
||||||
"[OUCH]".bright_blue(),
|
|
||||||
&from.path
|
|
||||||
);
|
|
||||||
|
|
||||||
match from.contents_in_memory {
|
match from.contents_in_memory {
|
||||||
Some(bytes) => {
|
Some(bytes) => {
|
||||||
|
43
src/error.rs
43
src/error.rs
@ -2,7 +2,7 @@ use std::{fmt, path::PathBuf};
|
|||||||
|
|
||||||
use colored::Colorize;
|
use colored::Colorize;
|
||||||
|
|
||||||
#[derive(PartialEq, Eq, Debug)]
|
#[derive(PartialEq, Eq)]
|
||||||
pub enum Error {
|
pub enum Error {
|
||||||
UnknownExtensionError(String),
|
UnknownExtensionError(String),
|
||||||
MissingExtensionError(String),
|
MissingExtensionError(String),
|
||||||
@ -17,24 +17,57 @@ pub enum Error {
|
|||||||
UnsupportedZipArchive(&'static str),
|
UnsupportedZipArchive(&'static str),
|
||||||
InputsMustHaveBeenDecompressible(PathBuf),
|
InputsMustHaveBeenDecompressible(PathBuf),
|
||||||
InternalError,
|
InternalError,
|
||||||
|
CompressingRootFolder,
|
||||||
|
WalkdirError
|
||||||
}
|
}
|
||||||
|
|
||||||
pub type Result<T> = std::result::Result<T, Error>;
|
pub type Result<T> = std::result::Result<T, Error>;
|
||||||
|
|
||||||
|
// impl std::error::Error for Error {
|
||||||
|
// fn source(&self) -> Option<&(dyn std::error::Error + 'static)> {
|
||||||
|
// // TODO: get rid of PartialEq and Eq in self::Error in order to
|
||||||
|
// // correctly use `source`.
|
||||||
|
// None
|
||||||
|
// }
|
||||||
|
// }
|
||||||
|
|
||||||
|
impl fmt::Debug for Error {
|
||||||
|
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
|
||||||
|
write!(f, "{}", self)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
impl fmt::Display for Error {
|
impl fmt::Display for Error {
|
||||||
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
|
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
|
||||||
write!(f, "{} ", "[ERROR]".red())?;
|
|
||||||
match self {
|
match self {
|
||||||
Error::MissingExtensionError(filename) => {
|
Error::MissingExtensionError(filename) => {
|
||||||
|
write!(f, "{} ", "[ERROR]".red())?;
|
||||||
write!(f, "cannot compress to \'{}\', likely because it has an unsupported (or missing) extension.", filename)
|
write!(f, "cannot compress to \'{}\', likely because it has an unsupported (or missing) extension.", filename)
|
||||||
}
|
}
|
||||||
Error::InputsMustHaveBeenDecompressible(file) => {
|
Error::InputsMustHaveBeenDecompressible(file) => {
|
||||||
|
write!(f, "{} ", "[ERROR]".red())?;
|
||||||
write!(f, "file '{:?}' is not decompressible", file)
|
write!(f, "file '{:?}' is not decompressible", file)
|
||||||
}
|
}
|
||||||
|
Error::WalkdirError => {
|
||||||
|
// Already printed in the From block
|
||||||
|
write!(f, "")
|
||||||
|
}
|
||||||
Error::FileNotFound(file) => {
|
Error::FileNotFound(file) => {
|
||||||
|
write!(f, "{} ", "[ERROR]".red())?;
|
||||||
// TODO: check if file == ""
|
// TODO: check if file == ""
|
||||||
write!(f, "file {:?} not found!", file)
|
write!(f, "file {:?} not found!", file)
|
||||||
}
|
}
|
||||||
|
Error::CompressingRootFolder => {
|
||||||
|
write!(f, "{} ", "[ERROR]".red())?;
|
||||||
|
let spacing = " ";
|
||||||
|
writeln!(f, "It seems you're trying to compress the root folder.")?;
|
||||||
|
writeln!(f, "{}This is unadvisable since ouch does compressions in-memory.", spacing)?;
|
||||||
|
write!(f, "{}Use a more appropriate tool for this, such as {}.", spacing, "rsync".green())
|
||||||
|
}
|
||||||
|
Error::InternalError => {
|
||||||
|
write!(f, "{} ", "[ERROR]".red())?;
|
||||||
|
write!(f, "You've reached an internal error! This really should not have happened.\nPlease file an issue at {}", "https://github.com/vrmiguel/ouch".green())
|
||||||
|
}
|
||||||
_err => {
|
_err => {
|
||||||
// TODO
|
// TODO
|
||||||
write!(f, "")
|
write!(f, "")
|
||||||
@ -50,7 +83,7 @@ impl From<std::io::Error> for Error {
|
|||||||
std::io::ErrorKind::PermissionDenied => Self::PermissionDenied,
|
std::io::ErrorKind::PermissionDenied => Self::PermissionDenied,
|
||||||
std::io::ErrorKind::AlreadyExists => Self::AlreadyExists,
|
std::io::ErrorKind::AlreadyExists => Self::AlreadyExists,
|
||||||
_other => {
|
_other => {
|
||||||
println!("{}: {}", "IO error".red(), err);
|
println!("{} {}", "[IO error]".red(), err);
|
||||||
Self::IoError
|
Self::IoError
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -71,7 +104,7 @@ impl From<zip::result::ZipError> for Error {
|
|||||||
|
|
||||||
impl From<walkdir::Error> for Error {
|
impl From<walkdir::Error> for Error {
|
||||||
fn from(err: walkdir::Error) -> Self {
|
fn from(err: walkdir::Error) -> Self {
|
||||||
eprintln!("{}: {}", "error".red(), err);
|
eprintln!("{} {}", "[ERROR]".red(), err);
|
||||||
Self::InvalidInput
|
Self::WalkdirError
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -29,10 +29,10 @@ impl Evaluator {
|
|||||||
None => {
|
None => {
|
||||||
// This block *should* be unreachable
|
// This block *should* be unreachable
|
||||||
eprintln!(
|
eprintln!(
|
||||||
"{}: reached Evaluator::get_decompressor without known extension.",
|
"{} reached Evaluator::get_decompressor without known extension.",
|
||||||
"internal error".red()
|
"[internal error]".red()
|
||||||
);
|
);
|
||||||
return Err(crate::Error::InvalidInput);
|
return Err(crate::Error::InternalError);
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
@ -71,8 +71,8 @@ impl Evaluator {
|
|||||||
None => {
|
None => {
|
||||||
// This block *should* be unreachable
|
// This block *should* be unreachable
|
||||||
eprintln!(
|
eprintln!(
|
||||||
"{}: reached Evaluator::get_decompressor without known extension.",
|
"{} reached Evaluator::get_decompressor without known extension.",
|
||||||
"internal error".red()
|
"[internal error]".red()
|
||||||
);
|
);
|
||||||
return Err(crate::Error::InvalidInput);
|
return Err(crate::Error::InvalidInput);
|
||||||
}
|
}
|
||||||
|
@ -12,7 +12,14 @@ mod utils;
|
|||||||
use error::{Error, Result};
|
use error::{Error, Result};
|
||||||
use evaluator::Evaluator;
|
use evaluator::Evaluator;
|
||||||
|
|
||||||
fn main() -> crate::Result<()> {
|
fn main() {
|
||||||
|
if let Err(err) = run() {
|
||||||
|
println!("{}", err);
|
||||||
|
std::process::exit(127);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
fn run() -> crate::Result<()> {
|
||||||
let matches = cli::get_matches();
|
let matches = cli::get_matches();
|
||||||
let (command, flags) = cli::parse_matches(matches)?;
|
let (command, flags) = cli::parse_matches(matches)?;
|
||||||
Evaluator::evaluate(command, flags)
|
Evaluator::evaluate(command, flags)
|
||||||
|
27
src/utils.rs
27
src/utils.rs
@ -13,11 +13,6 @@ where
|
|||||||
{
|
{
|
||||||
let exists = path.as_ref().exists();
|
let exists = path.as_ref().exists();
|
||||||
if !exists {
|
if !exists {
|
||||||
eprintln!(
|
|
||||||
"{}: could not find file {:?}",
|
|
||||||
"[ERROR]".red(),
|
|
||||||
path.as_ref()
|
|
||||||
);
|
|
||||||
return Err(crate::Error::FileNotFound(PathBuf::from(path.as_ref())));
|
return Err(crate::Error::FileNotFound(PathBuf::from(path.as_ref())));
|
||||||
}
|
}
|
||||||
Ok(())
|
Ok(())
|
||||||
@ -70,28 +65,18 @@ pub(crate) fn change_dir_and_return_parent(filename: &PathBuf) -> crate::Result<
|
|||||||
let parent = if let Some(parent) = filename.parent() {
|
let parent = if let Some(parent) = filename.parent() {
|
||||||
parent
|
parent
|
||||||
} else {
|
} else {
|
||||||
let spacing = " ";
|
return Err(crate::Error::CompressingRootFolder);
|
||||||
println!(
|
|
||||||
"{} It seems you're trying to compress the root folder.",
|
|
||||||
"[WARNING]".red()
|
|
||||||
);
|
|
||||||
println!(
|
|
||||||
"{}This is unadvisable since ouch does compressions in-memory.",
|
|
||||||
spacing
|
|
||||||
);
|
|
||||||
println!(
|
|
||||||
"{}Use a more appropriate tool for this, such as {}.",
|
|
||||||
spacing,
|
|
||||||
"rsync".green()
|
|
||||||
);
|
|
||||||
return Err(crate::Error::InvalidInput);
|
|
||||||
};
|
};
|
||||||
|
|
||||||
env::set_current_dir(parent)?;
|
env::set_current_dir(parent)?;
|
||||||
Ok(previous_location)
|
Ok(previous_location)
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn permission_for_overwriting(path: &PathBuf, flags: Flags, confirm: &Confirmation) -> crate::Result<bool> {
|
pub fn permission_for_overwriting(
|
||||||
|
path: &PathBuf,
|
||||||
|
flags: Flags,
|
||||||
|
confirm: &Confirmation,
|
||||||
|
) -> crate::Result<bool> {
|
||||||
match flags {
|
match flags {
|
||||||
Flags::AlwaysYes => return Ok(true),
|
Flags::AlwaysYes => return Ok(true),
|
||||||
Flags::AlwaysNo => return Ok(false),
|
Flags::AlwaysNo => return Ok(false),
|
||||||
|
Loading…
x
Reference in New Issue
Block a user