evaluator: Verify if input files are decompressible

This commit is contained in:
Vinícius Miguel 2021-04-06 04:30:36 -03:00
parent 9b8dcb40fa
commit f9272b5ce5
16 changed files with 81 additions and 90 deletions

View File

@ -17,7 +17,7 @@ impl Bytes {
impl std::fmt::Display for Bytes {
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
let num = self.bytes;
debug_assert!(num >= 0.0);
debug_assert!(num >= 0.0);
if num < 1_f64 {
return write!(f, "{} B", num);
}
@ -27,4 +27,4 @@ impl std::fmt::Display for Bytes {
write!(f, "{:.2} ", num / delimiter.powi(exponent))?;
write!(f, "{}", UNITS[exponent as usize])
}
}
}

View File

@ -1,4 +1,9 @@
use std::{env, ffi::OsString, path::{Path, PathBuf}, vec::Vec};
use std::{
env,
ffi::OsString,
path::{Path, PathBuf},
vec::Vec,
};
use oof::{arg_flag, flag};
@ -39,9 +44,9 @@ pub struct ParsedArgs {
// pub program_called: OsString, // Useful?
}
fn canonicalize<'a, P>(path: P) -> crate::Result<PathBuf>
fn canonicalize<'a, P>(path: P) -> crate::Result<PathBuf>
where
P: AsRef<Path> + 'a
P: AsRef<Path> + 'a,
{
match std::fs::canonicalize(&path.as_ref()) {
Ok(abs_path) => Ok(abs_path),
@ -56,7 +61,7 @@ where
}
}
fn canonicalize_files<'a, P>(files: Vec<P>) -> crate::Result<Vec<PathBuf>>
fn canonicalize_files<'a, P>(files: Vec<P>) -> crate::Result<Vec<PathBuf>>
where
P: AsRef<Path> + 'a,
{
@ -105,7 +110,7 @@ pub fn parse_args_from(mut args: Vec<OsString>) -> crate::Result<ParsedArgs> {
// Defaults to decompression when there is no subcommand
None => {
flags_info.push(arg_flag!('o', "output"));
// Parse flags
let (args, mut flags) = oof::filter_flags(args, &flags_info)?;
@ -116,8 +121,9 @@ pub fn parse_args_from(mut args: Vec<OsString>) -> crate::Result<ParsedArgs> {
}
}
let files = files.map(Result::unwrap).collect();
let output_folder = flags.take_arg("output").map(PathBuf::from);
// TODO: ensure all files are decompressible
let command = Command::Decompress {
@ -130,4 +136,4 @@ pub fn parse_args_from(mut args: Vec<OsString>) -> crate::Result<ParsedArgs> {
};
Ok(parsed_args)
}
}

View File

@ -4,8 +4,8 @@ use colored::Colorize;
use super::{Compressor, Entry};
use crate::{
extension::CompressionFormat,
bytes::Bytes,
extension::CompressionFormat,
file::File,
utils::{check_for_multiple_files, ensure_exists},
};

View File

@ -4,9 +4,9 @@ use colored::Colorize;
use super::{Compressor, Entry};
use crate::{
bytes::Bytes,
extension::CompressionFormat,
file::File,
bytes::Bytes,
utils::{check_for_multiple_files, ensure_exists},
};

View File

@ -4,9 +4,9 @@ use colored::Colorize;
use super::{Compressor, Entry};
use crate::{
bytes::Bytes,
extension::CompressionFormat,
file::File,
bytes::Bytes,
utils::{check_for_multiple_files, ensure_exists},
};

View File

@ -68,7 +68,7 @@ impl ZipCompressor {
if entry_path.is_dir() {
continue;
}
writer.start_file(entry_path.to_string_lossy(), options)?;
println!("Compressing {:?}", entry_path);
let file_bytes = std::fs::read(entry.path())?;

View File

@ -8,13 +8,13 @@ use colored::Colorize;
use tar::{self, Archive};
use super::decompressor::{DecompressionResult, Decompressor};
use crate::{dialogs::Confirmation, file::File, bytes::Bytes, utils};
use crate::{bytes::Bytes, dialogs::Confirmation, file::File, utils};
#[derive(Debug)]
pub struct TarDecompressor {}
impl TarDecompressor {
fn unpack_files(from: File, into: &Path, flags: &oof::Flags) -> crate::Result<Vec<PathBuf>> {
fn unpack_files(from: File, into: &Path, flags: &oof::Flags) -> crate::Result<Vec<PathBuf>> {
println!(
"{}: attempting to decompress {:?}",
"ouch".bright_blue(),

View File

@ -6,8 +6,8 @@ use std::{
use colored::Colorize;
use super::decompressor::{DecompressionResult, Decompressor};
use crate::utils;
use crate::bytes::Bytes;
use crate::utils;
use crate::{extension::CompressionFormat, file::File};
struct DecompressorToMemory {}

View File

@ -8,7 +8,7 @@ use colored::Colorize;
use zip::{self, read::ZipFile, ZipArchive};
use super::decompressor::{DecompressionResult, Decompressor};
use crate::{dialogs::Confirmation, file::File, bytes::Bytes, utils};
use crate::{bytes::Bytes, dialogs::Confirmation, file::File, utils};
#[cfg(unix)]
fn __unix_set_permissions(file_path: &Path, file: &ZipFile) {

View File

@ -5,7 +5,7 @@ use colored::Colorize;
#[derive(PartialEq, Eq)]
pub enum Error {
UnknownExtensionError(String),
MissingExtensionError(String),
MissingExtensionError(PathBuf),
// TODO: get rid of this error variant
InvalidUnicode,
InvalidInput,
@ -35,7 +35,7 @@ impl fmt::Display for Error {
Error::MissingExtensionError(filename) => {
write!(f, "{} ", "[ERROR]".red())?;
// TODO: show MIME type of the unsupported file
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::WalkdirError => {
// Already printed in the From block

View File

@ -8,20 +8,19 @@ use colored::Colorize;
use crate::{
bytes::Bytes,
cli::{VERSION, Command},
cli::{Command, VERSION},
compressors::{
Entry, Compressor, BzipCompressor, GzipCompressor, LzmaCompressor, TarCompressor,
BzipCompressor, Compressor, Entry, GzipCompressor, LzmaCompressor, TarCompressor,
ZipCompressor,
},
decompressors::{
BzipDecompressor, DecompressionResult, Decompressor, GzipDecompressor, LzmaDecompressor,
TarDecompressor, ZipDecompressor,
},
dialogs::Confirmation,
extension::{CompressionFormat, Extension},
file::File,
},
dialogs::Confirmation,
extension::{CompressionFormat, Extension},
file::File,
utils,
debug
};
pub struct Evaluator {}
@ -33,7 +32,6 @@ impl Evaluator {
pub fn get_compressor(
file: &File,
) -> crate::Result<(Option<BoxedCompressor>, BoxedCompressor)> {
let extension = match &file.extension {
Some(extension) => extension.clone(),
None => {
@ -213,8 +211,16 @@ impl Evaluator {
file_path: &Path,
output: Option<&Path>,
flags: &oof::Flags,
) -> crate::Result<()> {
let file = debug!(File::from(file_path)?);
) -> crate::Result<()> {
// The file to be decompressed
let file = File::from(file_path)?;
// The file must have a supported decompressible format
if file.extension == None {
return Err(crate::Error::MissingExtensionError(PathBuf::from(
file_path,
)));
}
let output = match output {
Some(inner) => Some(File::from(inner)?),
None => None,
@ -289,4 +295,4 @@ fn help_message() {
println!(" ouch compress <input...> output-file");
println!("DECOMPRESSION USAGE:");
println!(" ouch <input> [-o/--output output-folder]");
}
}

View File

@ -57,7 +57,11 @@ impl Extension {
(os_str, snd) if os_str.is_empty() => (None, snd),
(fst, snd) => (Some(fst), snd),
},
None => return Err(crate::Error::MissingExtensionError(to_utf(file_name))),
None => {
return Err(crate::Error::MissingExtensionError(PathBuf::from(
file_name,
)))
}
};
let (first_ext, second_ext) = match (first_ext, second_ext) {
@ -119,7 +123,7 @@ impl TryFrom<&PathBuf> for CompressionFormat {
let ext = match ext.extension() {
Some(ext) => ext,
None => {
return Err(crate::Error::MissingExtensionError(String::new()));
return Err(crate::Error::MissingExtensionError(PathBuf::new()));
}
};
extension_from_os_str(ext)
@ -133,7 +137,7 @@ impl TryFrom<&str> for CompressionFormat {
let file_name = Path::new(file_name);
let ext = match file_name.extension() {
Some(ext) => ext,
None => return Err(crate::Error::MissingExtensionError(String::new())),
None => return Err(crate::Error::MissingExtensionError(PathBuf::new())),
};
extension_from_os_str(ext)

View File

@ -24,7 +24,7 @@ impl<'a> File<'a> {
Ok(File {
path,
contents_in_memory: None,
extension
extension,
})
}
}

View File

@ -23,6 +23,6 @@ fn main() {
}
fn run() -> crate::Result<()> {
let ParsedArgs { command, flags } = cli::parse_args()?;
let ParsedArgs { command, flags } = cli::parse_args()?;
Evaluator::evaluate(command, &flags)
}

View File

@ -27,7 +27,7 @@ where
#[cfg(test)]
mod argparsing {
use super::{make_dummy_files};
use super::make_dummy_files;
use crate::cli;
use crate::cli::Command;
use std::{ffi::OsString, fs, path::PathBuf};
@ -65,10 +65,13 @@ mod argparsing {
#[test]
fn test_arg_parsing_compress_subcommand() -> crate::Result<()> {
let files = vec!["a", "b", "c"];
make_dummy_files(&*files)?;
let files= files.iter().map(fs::canonicalize).map(Result::unwrap).collect();
let files = files
.iter()
.map(fs::canonicalize)
.map(Result::unwrap)
.collect();
let expected = Command::Compress {
files,
@ -107,70 +110,37 @@ mod argparsing {
mod byte_pretty_printing {
use crate::bytes::Bytes;
#[test]
fn bytes () {
assert_eq!(
&format!("{}", Bytes::new(234)),
"234.00 B"
);
fn bytes() {
assert_eq!(&format!("{}", Bytes::new(234)), "234.00 B");
assert_eq!(
&format!("{}", Bytes::new(999)),
"999.00 B"
);
assert_eq!(&format!("{}", Bytes::new(999)), "999.00 B");
}
#[test]
fn kilobytes () {
assert_eq!(
&format!("{}", Bytes::new(2234)),
"2.23 kB"
);
fn kilobytes() {
assert_eq!(&format!("{}", Bytes::new(2234)), "2.23 kB");
assert_eq!(
&format!("{}", Bytes::new(62500)),
"62.50 kB"
);
assert_eq!(&format!("{}", Bytes::new(62500)), "62.50 kB");
assert_eq!(
&format!("{}", Bytes::new(329990)),
"329.99 kB"
);
assert_eq!(&format!("{}", Bytes::new(329990)), "329.99 kB");
}
#[test]
fn megabytes () {
assert_eq!(
&format!("{}", Bytes::new(2750000)),
"2.75 MB"
);
fn megabytes() {
assert_eq!(&format!("{}", Bytes::new(2750000)), "2.75 MB");
assert_eq!(
&format!("{}", Bytes::new(55000000)),
"55.00 MB"
);
assert_eq!(&format!("{}", Bytes::new(55000000)), "55.00 MB");
assert_eq!(
&format!("{}", Bytes::new(987654321)),
"987.65 MB"
);
assert_eq!(&format!("{}", Bytes::new(987654321)), "987.65 MB");
}
#[test]
fn gigabytes () {
assert_eq!(
&format!("{}", Bytes::new(5280000000)),
"5.28 GB"
);
fn gigabytes() {
assert_eq!(&format!("{}", Bytes::new(5280000000)), "5.28 GB");
assert_eq!(
&format!("{}", Bytes::new(95200000000)),
"95.20 GB"
);
assert_eq!(&format!("{}", Bytes::new(95200000000)), "95.20 GB");
assert_eq!(
&format!("{}", Bytes::new(302000000000)),
"302.00 GB"
);
assert_eq!(&format!("{}", Bytes::new(302000000000)), "302.00 GB");
}
}

View File

@ -12,16 +12,19 @@ use crate::{dialogs::Confirmation, extension::CompressionFormat, file::File};
#[macro_export]
#[cfg(debug_assertions)]
macro_rules! debug {
($x:expr) => { dbg!($x) }
($x:expr) => {
dbg!($x)
};
}
#[macro_export]
#[cfg(not(debug_assertions))]
macro_rules! debug {
($x:expr) => { std::convert::identity($x) }
($x:expr) => {
std::convert::identity($x)
};
}
pub(crate) fn ensure_exists<'a, P>(path: P) -> crate::Result<()>
where
P: AsRef<Path> + 'a,
@ -82,7 +85,9 @@ pub(crate) fn change_dir_and_return_parent(filename: &Path) -> crate::Result<Pat
return Err(crate::Error::CompressingRootFolder);
};
env::set_current_dir(parent).ok().ok_or(crate::Error::CompressingRootFolder)?;
env::set_current_dir(parent)
.ok()
.ok_or(crate::Error::CompressingRootFolder)?;
Ok(previous_location)
}