mirror of
https://github.com/ouch-org/ouch.git
synced 2025-06-05 02:55:31 +00:00
decompressors.zip: now working
This commit is contained in:
parent
0a81384dd8
commit
e705024c61
@ -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)
|
||||
}
|
||||
}
|
45
src/error.rs
45
src/error.rs
@ -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)
|
||||
}
|
||||
}
|
||||
}
|
@ -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)?;
|
||||
|
10
src/main.rs
10
src/main.rs
@ -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(())
|
||||
|
@ -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};
|
||||
|
Loading…
x
Reference in New Issue
Block a user