mirror of
https://github.com/ouch-org/ouch.git
synced 2025-07-21 09:00:15 +00:00
Add support for zip (and... .zip.zip) compression
This commit is contained in:
parent
d72ca9eeae
commit
22e131fb46
16
src/cli.rs
16
src/cli.rs
@ -1,7 +1,7 @@
|
||||
use std::{convert::TryFrom, path::PathBuf, vec::Vec};
|
||||
|
||||
use clap::{Arg, Values};
|
||||
use colored::Colorize;
|
||||
// use colored::Colorize;
|
||||
|
||||
use crate::error;
|
||||
use crate::extension::Extension;
|
||||
@ -97,11 +97,11 @@ impl TryFrom<clap::ArgMatches<'static>> for Command {
|
||||
if output_is_compressible {
|
||||
// The supplied output is compressible, so we'll compress our inputs to it
|
||||
|
||||
println!(
|
||||
"{}: trying to compress input files into '{}'",
|
||||
"info".yellow(),
|
||||
output_file
|
||||
);
|
||||
// println!(
|
||||
// "{}: trying to compress input files into '{}'",
|
||||
// "info".yellow(),
|
||||
// output_file
|
||||
// );
|
||||
|
||||
let input_files = input_files.map(PathBuf::from).collect();
|
||||
|
||||
@ -109,7 +109,7 @@ impl TryFrom<clap::ArgMatches<'static>> for Command {
|
||||
kind: CommandKind::Compression(input_files),
|
||||
output: Some(File {
|
||||
path: output_file.into(),
|
||||
contents: None,
|
||||
contents_in_memory: None,
|
||||
extension: Some(output_file_extension.unwrap())
|
||||
}),
|
||||
});
|
||||
@ -124,7 +124,7 @@ impl TryFrom<clap::ArgMatches<'static>> for Command {
|
||||
kind: CommandKind::Decompression(input_files),
|
||||
output: Some(File {
|
||||
path: output_file.into(),
|
||||
contents: None,
|
||||
contents_in_memory: None,
|
||||
extension: None
|
||||
})
|
||||
});
|
||||
|
@ -1,6 +1,9 @@
|
||||
mod tar;
|
||||
mod zip;
|
||||
mod compressor;
|
||||
|
||||
pub use compressor::{Compressor};
|
||||
pub use compressor::Compressor;
|
||||
pub use self::compressor::Entry;
|
||||
pub use self::tar::TarCompressor;
|
||||
pub use self::compressor::Entry;
|
||||
pub use self::zip::ZipCompressor;
|
||||
|
||||
|
@ -12,9 +12,10 @@ pub struct TarCompressor {}
|
||||
|
||||
impl TarCompressor {
|
||||
|
||||
// TODO: this function does not seem to be working correctly ;/
|
||||
fn make_archive_from_memory(input: File) -> OuchResult<Vec<u8>> {
|
||||
|
||||
let contents = match input.contents {
|
||||
let contents = match input.contents_in_memory {
|
||||
Some(bytes) => bytes,
|
||||
None => {
|
||||
eprintln!("{}: reached TarCompressor::make_archive_from_memory without known content.", "internal error".red());
|
||||
@ -24,13 +25,19 @@ impl TarCompressor {
|
||||
|
||||
let mut header = Header::new_gnu();
|
||||
|
||||
header.set_path(&input.path).unwrap();
|
||||
// header.set_path(&input.path.file_stem().unwrap())?;
|
||||
header.set_path(".")?;
|
||||
header.set_size(contents.len() as u64);
|
||||
header.set_cksum();
|
||||
header.set_mode(644);
|
||||
|
||||
|
||||
let mut b = Builder::new(Vec::new());
|
||||
b.append_data(&mut header, &input.path, &*contents)?;
|
||||
b.append_data(
|
||||
&mut header,
|
||||
&input.path.file_stem().unwrap(),
|
||||
&*contents
|
||||
)?;
|
||||
|
||||
Ok(b.into_inner()?)
|
||||
}
|
||||
@ -41,6 +48,8 @@ impl TarCompressor {
|
||||
let mut b = Builder::new(buf);
|
||||
|
||||
for filename in input_filenames {
|
||||
// TODO: check if filename is a file or a directory
|
||||
|
||||
for entry in WalkDir::new(&filename) {
|
||||
let entry = entry?;
|
||||
let path = entry.path();
|
||||
|
93
src/compressors/zip.rs
Normal file
93
src/compressors/zip.rs
Normal file
@ -0,0 +1,93 @@
|
||||
use std::{io::{Cursor, Write}, path::PathBuf};
|
||||
|
||||
use walkdir::WalkDir;
|
||||
|
||||
use crate::{
|
||||
compressors::Compressor,
|
||||
error::{Error, OuchResult},
|
||||
file::File,
|
||||
};
|
||||
|
||||
use super::compressor::Entry;
|
||||
|
||||
pub struct ZipCompressor {}
|
||||
|
||||
impl ZipCompressor {
|
||||
// TODO: this function does not seem to be working correctly ;/
|
||||
fn make_archive_from_memory(input: File) -> OuchResult<Vec<u8>> {
|
||||
let buffer = vec![];
|
||||
let mut writer = zip::ZipWriter::new(std::io::Cursor::new(buffer));
|
||||
|
||||
let inner_file_path: Box<str> = input
|
||||
.path
|
||||
.file_stem()
|
||||
.ok_or(
|
||||
// TODO: Is this reachable?
|
||||
Error::InvalidInput
|
||||
)?
|
||||
.to_string_lossy()
|
||||
.into();
|
||||
|
||||
let options =
|
||||
zip::write::FileOptions::default().compression_method(zip::CompressionMethod::Deflated);
|
||||
|
||||
// let ok = Box::from(inner_file_path.to_string_lossy());
|
||||
writer.start_file(inner_file_path, options)?;
|
||||
|
||||
let input_bytes = match input.contents_in_memory {
|
||||
Some(bytes) => bytes,
|
||||
None => {
|
||||
// TODO: error description, although this block should not be
|
||||
// reachable
|
||||
return Err(Error::InvalidInput);
|
||||
}
|
||||
};
|
||||
|
||||
writer.write(&*input_bytes)?;
|
||||
|
||||
|
||||
|
||||
let bytes = writer.finish().unwrap();
|
||||
|
||||
Ok(bytes.into_inner())
|
||||
}
|
||||
|
||||
fn make_archive_from_files(input_filenames: Vec<PathBuf>) -> OuchResult<Vec<u8>> {
|
||||
let buffer = vec![];
|
||||
let mut writer = zip::ZipWriter::new(Cursor::new(buffer));
|
||||
|
||||
let options =
|
||||
zip::write::FileOptions::default().compression_method(zip::CompressionMethod::Deflated);
|
||||
|
||||
for filename in input_filenames {
|
||||
for entry in WalkDir::new(filename) {
|
||||
let entry = entry?;
|
||||
let entry_path = &entry.path();
|
||||
if entry_path.is_dir() {
|
||||
continue;
|
||||
}
|
||||
writer
|
||||
.start_file(
|
||||
entry_path.to_string_lossy(),
|
||||
options
|
||||
)?;
|
||||
let file_bytes = std::fs::read(entry.path())?;
|
||||
writer.write(&*file_bytes)?;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
let bytes = writer.finish().unwrap();
|
||||
|
||||
Ok(bytes.into_inner())
|
||||
}
|
||||
}
|
||||
|
||||
impl Compressor for ZipCompressor {
|
||||
fn compress(&self, from: Entry) -> OuchResult<Vec<u8>> {
|
||||
match from {
|
||||
Entry::Files(filenames) => Ok(Self::make_archive_from_files(filenames)?),
|
||||
Entry::InMemory(file) => Ok(Self::make_archive_from_memory(file)?),
|
||||
}
|
||||
}
|
||||
}
|
@ -17,7 +17,7 @@ pub struct NifflerDecompressor {}
|
||||
impl NifflerDecompressor {
|
||||
fn unpack_file(from: &Path) -> OuchResult<Vec<u8>> {
|
||||
|
||||
println!("{}: trying to decompress {:?}", "info".yellow(), from);
|
||||
// println!("{}: trying to decompress {:?}", "info".yellow(), from);
|
||||
|
||||
let file = std::fs::read(from)?;
|
||||
|
||||
|
@ -17,7 +17,7 @@ impl TarDecompressor {
|
||||
println!("{}: attempting to decompress {:?}", "ouch".bright_blue(), &from.path);
|
||||
let mut files_unpacked = vec![];
|
||||
|
||||
let mut archive: Archive<Box<dyn Read>> = match from.contents {
|
||||
let mut archive: Archive<Box<dyn Read>> = match from.contents_in_memory {
|
||||
Some(bytes) => {
|
||||
tar::Archive::new(Box::new(Cursor::new(bytes)))
|
||||
}
|
||||
|
@ -80,7 +80,7 @@ impl ZipDecompressor {
|
||||
&from.path
|
||||
);
|
||||
|
||||
match from.contents {
|
||||
match from.contents_in_memory {
|
||||
Some(bytes) => {
|
||||
let mut archive = zip::ZipArchive::new(Cursor::new(bytes))?;
|
||||
Ok(Self::zip_decompress(&mut archive, into)?)
|
||||
|
@ -2,25 +2,33 @@ use std::{ffi::OsStr, fs, io::Write, path::PathBuf};
|
||||
|
||||
use colored::Colorize;
|
||||
|
||||
use crate::{compressors::{Entry, TarCompressor}, decompressors::TarDecompressor};
|
||||
use crate::decompressors::ZipDecompressor;
|
||||
use crate::{
|
||||
cli::{Command, CommandKind},
|
||||
decompressors::{
|
||||
Decompressor,
|
||||
DecompressionResult,
|
||||
NifflerDecompressor
|
||||
},
|
||||
compressors::Compressor,
|
||||
error::{self, OuchResult},
|
||||
extension::{
|
||||
Extension,
|
||||
CompressionFormat,
|
||||
},
|
||||
file::File,
|
||||
utils,
|
||||
use crate::compressors::{
|
||||
Entry,
|
||||
Compressor,
|
||||
TarCompressor,
|
||||
ZipCompressor
|
||||
};
|
||||
|
||||
use crate::decompressors::{
|
||||
Decompressor,
|
||||
TarDecompressor,
|
||||
ZipDecompressor,
|
||||
NifflerDecompressor,
|
||||
DecompressionResult
|
||||
};
|
||||
|
||||
use crate::extension::{
|
||||
Extension,
|
||||
CompressionFormat
|
||||
};
|
||||
|
||||
use crate::cli::{Command, CommandKind};
|
||||
|
||||
use crate::error::{self, OuchResult};
|
||||
|
||||
use crate::file::File;
|
||||
|
||||
use crate::utils;
|
||||
|
||||
pub struct Evaluator {
|
||||
// verbosity: Verbosity
|
||||
@ -46,7 +54,7 @@ impl Evaluator {
|
||||
Some(ext) => match ext {
|
||||
CompressionFormat::Tar => Some(Box::new(TarCompressor {})),
|
||||
|
||||
// CompressionFormat::Zip => Some(Box::new(ZipCompressor {})),
|
||||
CompressionFormat::Zip => Some(Box::new(ZipCompressor {})),
|
||||
|
||||
// _other => Some(Box::new(NifflerCompressor {})),
|
||||
_other => {
|
||||
@ -60,6 +68,7 @@ impl Evaluator {
|
||||
// any
|
||||
let second_compressor: Box<dyn Compressor> = match extension.second_ext {
|
||||
CompressionFormat::Tar => Box::new(TarCompressor {}),
|
||||
CompressionFormat::Zip => Box::new(ZipCompressor {}),
|
||||
_other => todo!()
|
||||
//
|
||||
};
|
||||
@ -138,7 +147,7 @@ impl Evaluator {
|
||||
|
||||
let file = File {
|
||||
path: filename,
|
||||
contents: Some(bytes),
|
||||
contents_in_memory: Some(bytes),
|
||||
extension,
|
||||
};
|
||||
|
||||
@ -166,7 +175,7 @@ impl Evaluator {
|
||||
let mut entry = Entry::Files(files);
|
||||
let bytes = first_compressor.compress(entry)?;
|
||||
|
||||
output.contents = Some(bytes);
|
||||
output.contents_in_memory = Some(bytes);
|
||||
|
||||
entry = Entry::InMemory(output);
|
||||
|
||||
|
@ -9,7 +9,7 @@ pub struct File {
|
||||
pub path: PathBuf,
|
||||
/// The bytes that compose the file.
|
||||
/// Only used when the whole file is kept in-memory
|
||||
pub contents: Option<Vec<u8>>,
|
||||
pub contents_in_memory: Option<Vec<u8>>,
|
||||
/// Note: extension here might be a misleading name since
|
||||
/// we don't really care about any extension other than supported compression ones.
|
||||
///
|
||||
@ -22,7 +22,7 @@ impl From<(PathBuf, Extension)> for File {
|
||||
fn from((path, format): (PathBuf, Extension)) -> Self {
|
||||
Self {
|
||||
path,
|
||||
contents: None,
|
||||
contents_in_memory: None,
|
||||
extension: Some(format),
|
||||
}
|
||||
}
|
||||
|
30
src/main.rs
30
src/main.rs
@ -1,6 +1,7 @@
|
||||
use std::{convert::TryFrom};
|
||||
use std::{convert::TryFrom, io::Write};
|
||||
|
||||
use colored::Colorize;
|
||||
use walkdir::WalkDir;
|
||||
|
||||
mod cli;
|
||||
mod error;
|
||||
@ -29,6 +30,31 @@ fn main() -> error::OuchResult<()>{
|
||||
print_error(err)
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
Ok(())
|
||||
}
|
||||
|
||||
// fn main() {
|
||||
// use zip::ZipWriter;
|
||||
|
||||
// let buf = vec![];
|
||||
// let mut writer = zip::ZipWriter::new(std::io::Cursor::new(buf));
|
||||
|
||||
// let options = zip::write::FileOptions::default().compression_method(zip::CompressionMethod::Deflated);
|
||||
|
||||
|
||||
// for entry in WalkDir::new("src/compressors/compressor.rs") {
|
||||
// let entry = entry.unwrap();
|
||||
// let entry_path = entry.path().clone();
|
||||
// if entry_path.is_dir() {
|
||||
// continue;
|
||||
// }
|
||||
// writer.start_file(entry_path.to_string_lossy(), options).unwrap();
|
||||
// let file_bytes = std::fs::read(entry.path()).unwrap();
|
||||
// writer.write(&*file_bytes).unwrap();
|
||||
// }
|
||||
|
||||
// let bytes = writer.finish().unwrap();
|
||||
|
||||
// std::fs::write("mainmain.rar", bytes.into_inner()).unwrap();
|
||||
// }
|
10
src/test.rs
10
src/test.rs
@ -23,13 +23,13 @@ mod cli {
|
||||
kind: Decompression(vec![
|
||||
File {
|
||||
path: "file.zip".into(),
|
||||
contents: None,
|
||||
contents_in_memory: None,
|
||||
extension: Some(Extension::from(Zip))
|
||||
}
|
||||
]),
|
||||
output: Some(File {
|
||||
path: "folder".into(),
|
||||
contents: None,
|
||||
contents_in_memory: None,
|
||||
extension: None
|
||||
}),
|
||||
}
|
||||
@ -49,12 +49,12 @@ mod cli {
|
||||
kind: Decompression(vec![
|
||||
File {
|
||||
path: "file.zip".into(),
|
||||
contents: None,
|
||||
contents_in_memory: None,
|
||||
extension: Some(Extension::from(Zip))
|
||||
},
|
||||
File {
|
||||
path: "file.tar".into(),
|
||||
contents: None,
|
||||
contents_in_memory: None,
|
||||
extension: Some(Extension::from(Tar))
|
||||
}
|
||||
],),
|
||||
@ -89,7 +89,7 @@ mod cli {
|
||||
output: Some(
|
||||
File {
|
||||
path: "file.tar".into(),
|
||||
contents: None,
|
||||
contents_in_memory: None,
|
||||
extension: Some(Extension::from(Tar))
|
||||
}
|
||||
),
|
||||
|
Loading…
x
Reference in New Issue
Block a user