decompressors.zip: now working

This commit is contained in:
Vinícius Rodrigues Miguel 2021-03-21 19:11:27 -03:00
parent 0a81384dd8
commit e705024c61
5 changed files with 100 additions and 27 deletions

View File

@ -1,10 +1,7 @@
use std::{
fs,
path::{Path, PathBuf},
};
use std::{fs, io, path::{Path, PathBuf}};
use colored::Colorize;
use zip;
use zip::{self, read::ZipFile};
use crate::{error::{self, OuchResult}, utils};
use crate::file::File;
@ -14,9 +11,59 @@ use super::decompressor::Decompressor;
pub struct ZipDecompressor {}
impl ZipDecompressor {
fn check_for_comments(file: &ZipFile) {
let comment = file.comment();
if !comment.is_empty() {
println!("{}: Comment in {}: {}", "info".yellow(), file.name(), comment);
}
}
fn unpack_files(from: &Path, into: &Path) -> OuchResult<Vec<PathBuf>> {
let mut unpacked_files = vec![];
// placeholder return
Err(error::Error::IOError)
println!("{}: attempting to decompress {:?}", "ouch".bright_blue(), from);
let file = fs::File::open(from)?;
let mut archive = zip::ZipArchive::new(file)?;
for idx in 0..archive.len() {
let mut file = archive.by_index(idx)?;
let file_path = match file.enclosed_name() {
Some(path) => path.to_owned(),
None => continue,
};
let file_path = into.join(file_path);
Self::check_for_comments(&file);
if (&*file.name()).ends_with('/') {
println!("File {} extracted to \"{}\"", idx, file_path.display());
fs::create_dir_all(&file_path)?;
} else {
println!(
"{}: \"{}\" extracted. ({} bytes)",
"info".yellow(),
file_path.display(),
file.size()
);
if let Some(p) = file_path.parent() {
if !p.exists() {
fs::create_dir_all(&p).unwrap();
}
}
let mut outfile = fs::File::create(&file_path).unwrap();
io::copy(&mut file, &mut outfile).unwrap();
}
let file_path = fs::canonicalize(file_path.clone())?;
unpacked_files.push(file_path);
}
Ok(unpacked_files)
}
}
@ -30,6 +77,6 @@ impl Decompressor for ZipDecompressor {
let files_unpacked = Self::unpack_files(&from.path, destination_path)?;
// placeholder return
Err(error::Error::IOError)
Ok(files_unpacked)
}
}

View File

@ -10,43 +10,64 @@ pub enum Error {
InvalidUnicode,
InvalidInput,
IOError,
FileNotFound,
AlreadyExists,
InvalidZipArchive(&'static str),
PermissionDenied,
UnsupportedZipArchive(&'static str),
InputsMustHaveBeenDecompressible(String),
}
// This should be placed somewhere else
pub type OuchResult<T> = Result<T, Error>;
impl fmt::Display for Error {
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
use Error::*;
match self {
InvalidInput => write!(
Error::InvalidInput => write!(
f,
"When `-o/--output` is omitted, all input files should be compressed files."
),
Error::MissingExtensionError(filename) => {
write!(f, "cannot compress to \'{}\', likely because it has an unsupported (or missing) extension.", filename)
}
},
Error::InputsMustHaveBeenDecompressible(file) => {
write!(f, "file '{}' is not decompressible", file.red())
},
// TODO: find out a way to attach the missing file in question here
Error::FileNotFound => {
write!(f, "file not found!")
}
_ => {
err => {
// TODO
write!(f, "todo: missing description for error")
write!(f, "todo: missing description for error {:?}", err)
}
}
}
}
impl From<std::io::Error> for Error {
fn from(err: std::io::Error) -> Self {
// Ideally I'd store `err` as a variant of ouch's Error
// but I need Error to have Eq, which std::io::Error does not
// implement.
println!("{}: {:#?}", "error".red(), err);
match err.kind() {
std::io::ErrorKind::NotFound => Self::FileNotFound,
std::io::ErrorKind::PermissionDenied => Self::PermissionDenied,
std::io::ErrorKind::AlreadyExists => Self::AlreadyExists,
_other => {
println!("{}: {:#?}", "IO error".red(), err);
Self::IOError
}
}
}
}
Self::IOError
impl From<zip::result::ZipError> for Error {
fn from(err: zip::result::ZipError) -> Self {
use zip::result::ZipError::*;
match err {
Io(io_err) => Self::from(io_err),
InvalidArchive(filename) => Self::InvalidZipArchive(filename),
FileNotFound => Self::FileNotFound,
UnsupportedArchive(filename) => Self::UnsupportedZipArchive(filename)
}
}
}

View File

@ -26,13 +26,13 @@ impl Evaluator {
return Err(error::Error::InvalidInput);
}
let extension = file.extension.clone().unwrap();
let decompressor = match extension.second_ext {
let decompressor: Box<dyn Decompressor> = match extension.second_ext {
CompressionFormat::Tar => {
Box::new(TarDecompressor{})
},
// CompressionFormat::Zip => {
// Box::new(ZipDecompressor{})
// }
CompressionFormat::Zip => {
Box::new(ZipDecompressor{})
}
_ => {
todo!()
}
@ -43,7 +43,6 @@ impl Evaluator {
}
fn decompress_file(&self, file: &File) -> error::OuchResult<()> {
println!("{}: attempting to decompress {:?}", "ouch".bright_blue(), file.path);
let output_file = &self.command.output;
let decompressor = self.get_decompressor(file)?;
let files_unpacked = decompressor.decompress(file, output_file)?;

View File

@ -14,14 +14,20 @@ mod decompressors;
use error::OuchResult;
fn main() -> OuchResult<()>{
let print_error = |err| {
println!("{}: {}", "error".red(), err);
};
let matches = cli::get_matches();
match cli::Command::try_from(matches) {
Ok(command) => {
let mut eval = evaluator::Evaluator::new(command);
eval.evaluate()?;
match eval.evaluate() {
Ok(_) => {},
Err(err) => print_error(err)
}
}
Err(err) => {
print!("{}: {}\n", "error".red(), err);
print_error(err)
}
}
Ok(())

View File

@ -1,4 +1,4 @@
use std::{fs, path::Path};
use std::{fs, path::{Component, Path, PathBuf}};
use colored::Colorize;
use crate::{error::OuchResult, file::File};