mirror of
https://github.com/ouch-org/ouch.git
synced 2025-06-07 12:05:46 +00:00
decompressors.zip: now working
This commit is contained in:
parent
0a81384dd8
commit
e705024c61
@ -1,10 +1,7 @@
|
|||||||
use std::{
|
use std::{fs, io, path::{Path, PathBuf}};
|
||||||
fs,
|
|
||||||
path::{Path, PathBuf},
|
|
||||||
};
|
|
||||||
|
|
||||||
use colored::Colorize;
|
use colored::Colorize;
|
||||||
use zip;
|
use zip::{self, read::ZipFile};
|
||||||
|
|
||||||
use crate::{error::{self, OuchResult}, utils};
|
use crate::{error::{self, OuchResult}, utils};
|
||||||
use crate::file::File;
|
use crate::file::File;
|
||||||
@ -14,9 +11,59 @@ use super::decompressor::Decompressor;
|
|||||||
pub struct ZipDecompressor {}
|
pub struct ZipDecompressor {}
|
||||||
|
|
||||||
impl 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>> {
|
fn unpack_files(from: &Path, into: &Path) -> OuchResult<Vec<PathBuf>> {
|
||||||
|
|
||||||
|
let mut unpacked_files = vec![];
|
||||||
|
|
||||||
// placeholder return
|
// 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)?;
|
let files_unpacked = Self::unpack_files(&from.path, destination_path)?;
|
||||||
|
|
||||||
// placeholder return
|
// 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,
|
InvalidUnicode,
|
||||||
InvalidInput,
|
InvalidInput,
|
||||||
IOError,
|
IOError,
|
||||||
|
FileNotFound,
|
||||||
|
AlreadyExists,
|
||||||
|
InvalidZipArchive(&'static str),
|
||||||
|
PermissionDenied,
|
||||||
|
UnsupportedZipArchive(&'static str),
|
||||||
InputsMustHaveBeenDecompressible(String),
|
InputsMustHaveBeenDecompressible(String),
|
||||||
}
|
}
|
||||||
|
|
||||||
// This should be placed somewhere else
|
|
||||||
pub type OuchResult<T> = Result<T, Error>;
|
pub type OuchResult<T> = Result<T, Error>;
|
||||||
|
|
||||||
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 {
|
||||||
use Error::*;
|
|
||||||
|
|
||||||
match self {
|
match self {
|
||||||
InvalidInput => write!(
|
Error::InvalidInput => write!(
|
||||||
f,
|
f,
|
||||||
"When `-o/--output` is omitted, all input files should be compressed files."
|
"When `-o/--output` is omitted, all input files should be compressed files."
|
||||||
),
|
),
|
||||||
Error::MissingExtensionError(filename) => {
|
Error::MissingExtensionError(filename) => {
|
||||||
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, "file '{}' is not decompressible", file.red())
|
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
|
// TODO
|
||||||
write!(f, "todo: missing description for error")
|
write!(f, "todo: missing description for error {:?}", err)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
impl From<std::io::Error> for Error {
|
impl From<std::io::Error> for Error {
|
||||||
fn from(err: std::io::Error) -> Self {
|
fn from(err: std::io::Error) -> Self {
|
||||||
// Ideally I'd store `err` as a variant of ouch's Error
|
match err.kind() {
|
||||||
// but I need Error to have Eq, which std::io::Error does not
|
std::io::ErrorKind::NotFound => Self::FileNotFound,
|
||||||
// implement.
|
std::io::ErrorKind::PermissionDenied => Self::PermissionDenied,
|
||||||
println!("{}: {:#?}", "error".red(), err);
|
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);
|
return Err(error::Error::InvalidInput);
|
||||||
}
|
}
|
||||||
let extension = file.extension.clone().unwrap();
|
let extension = file.extension.clone().unwrap();
|
||||||
let decompressor = match extension.second_ext {
|
let decompressor: Box<dyn Decompressor> = match extension.second_ext {
|
||||||
CompressionFormat::Tar => {
|
CompressionFormat::Tar => {
|
||||||
Box::new(TarDecompressor{})
|
Box::new(TarDecompressor{})
|
||||||
},
|
},
|
||||||
// CompressionFormat::Zip => {
|
CompressionFormat::Zip => {
|
||||||
// Box::new(ZipDecompressor{})
|
Box::new(ZipDecompressor{})
|
||||||
// }
|
}
|
||||||
_ => {
|
_ => {
|
||||||
todo!()
|
todo!()
|
||||||
}
|
}
|
||||||
@ -43,7 +43,6 @@ impl Evaluator {
|
|||||||
}
|
}
|
||||||
|
|
||||||
fn decompress_file(&self, file: &File) -> error::OuchResult<()> {
|
fn decompress_file(&self, file: &File) -> error::OuchResult<()> {
|
||||||
println!("{}: attempting to decompress {:?}", "ouch".bright_blue(), file.path);
|
|
||||||
let output_file = &self.command.output;
|
let output_file = &self.command.output;
|
||||||
let decompressor = self.get_decompressor(file)?;
|
let decompressor = self.get_decompressor(file)?;
|
||||||
let files_unpacked = decompressor.decompress(file, output_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;
|
use error::OuchResult;
|
||||||
|
|
||||||
fn main() -> OuchResult<()>{
|
fn main() -> OuchResult<()>{
|
||||||
|
let print_error = |err| {
|
||||||
|
println!("{}: {}", "error".red(), err);
|
||||||
|
};
|
||||||
let matches = cli::get_matches();
|
let matches = cli::get_matches();
|
||||||
match cli::Command::try_from(matches) {
|
match cli::Command::try_from(matches) {
|
||||||
Ok(command) => {
|
Ok(command) => {
|
||||||
let mut eval = evaluator::Evaluator::new(command);
|
let mut eval = evaluator::Evaluator::new(command);
|
||||||
eval.evaluate()?;
|
match eval.evaluate() {
|
||||||
|
Ok(_) => {},
|
||||||
|
Err(err) => print_error(err)
|
||||||
|
}
|
||||||
}
|
}
|
||||||
Err(err) => {
|
Err(err) => {
|
||||||
print!("{}: {}\n", "error".red(), err);
|
print_error(err)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
Ok(())
|
Ok(())
|
||||||
|
@ -1,4 +1,4 @@
|
|||||||
use std::{fs, path::Path};
|
use std::{fs, path::{Component, Path, PathBuf}};
|
||||||
|
|
||||||
use colored::Colorize;
|
use colored::Colorize;
|
||||||
use crate::{error::OuchResult, file::File};
|
use crate::{error::OuchResult, file::File};
|
||||||
|
Loading…
x
Reference in New Issue
Block a user