mirror of
https://github.com/ouch-org/ouch.git
synced 2025-06-05 02:55:31 +00:00
Add support for Lzma decompression
This commit is contained in:
parent
e18dbbd667
commit
729dda819e
1
.gitignore
vendored
1
.gitignore
vendored
@ -1 +1,2 @@
|
||||
/target
|
||||
/tests
|
||||
|
@ -19,11 +19,11 @@ colored = "2.0.0"
|
||||
walkdir = "2.3.2"
|
||||
clap = "2.33.3"
|
||||
tar = "0.4.33"
|
||||
xz2 = "0.1"
|
||||
xz2 = "0.1.6"
|
||||
bzip2 = "0.4.2"
|
||||
flate2 = "1.0.20"
|
||||
|
||||
# Keeping zip locally since upstream zip is staying on an older flate2 version
|
||||
# in order to not increase MSRV, which is not something I particularly care about
|
||||
# for ouch
|
||||
zip = { path = "./third-party/zip" }
|
||||
zip = { version = "0.5.10", path = "./third-party/zip" }
|
||||
|
@ -3,9 +3,9 @@
|
||||
`ouch` is the Obvious Unified Compression (and decompression) Helper.
|
||||
|
||||
|
||||
| Supported formats | .tar | .zip | .tar.{.gz, .bz} | .zip.{.gz, .bz, .bz2} | .bz | .gz | .lz, .lzma |
|
||||
| Supported formats | .tar | .zip | .tar.{.lz,.gz, .bz} | .zip.{.lz, .gz, .bz, .bz2} | .bz | .gz | .lz, .lzma |
|
||||
|-------------------|------|------|------------------------------|------------------------------|-----|-----|------------|
|
||||
| Decompression | ✓ | ✓ | ✓ | ✓ | ✓ | ✓ | ✗ |
|
||||
| Decompression | ✓ | ✓ | ✓ | ✓ | ✓ | ✓ | ✓ |
|
||||
| Compression | ✓ | ✓ | ✗ | ✗ | ✗ | ✗ | ✗ |
|
||||
|
||||
## How does it work?
|
||||
|
11
src/cli.rs
11
src/cli.rs
@ -29,6 +29,13 @@ pub fn clap_app<'a, 'b>() -> clap::App<'a, 'b> {
|
||||
clap::App::new("ouch")
|
||||
.version("0.1.0")
|
||||
.about("ouch is a unified compression & decompression utility")
|
||||
.after_help(
|
||||
"ouch infers what to based on the extensions of the input files and output file received.
|
||||
Examples: `ouch -i movies.tar.gz classes.zip -o Videos/` in order to decompress files into a folder.
|
||||
`ouch -i headers/ sources/ Makefile -o my-project.tar.gz`
|
||||
`ouch -i image{1..50}.jpeg -o images.zip`
|
||||
Please relate any issues or contribute at https://github.com/vrmiguel/ouch")
|
||||
.author("Vinícius R. Miguel")
|
||||
.help_message("Displays this message and exits")
|
||||
.settings(&[
|
||||
clap::AppSettings::ColoredHelp,
|
||||
@ -40,7 +47,7 @@ pub fn clap_app<'a, 'b>() -> clap::App<'a, 'b> {
|
||||
.multiple(true)
|
||||
.long("input")
|
||||
.short("i")
|
||||
.help("Input files (TODO description)")
|
||||
.help("The input files or directories.")
|
||||
.takes_value(true),
|
||||
)
|
||||
.arg(
|
||||
@ -50,7 +57,7 @@ pub fn clap_app<'a, 'b>() -> clap::App<'a, 'b> {
|
||||
.multiple(false)
|
||||
.long("output")
|
||||
.short("o")
|
||||
.help("Output file (TODO description)")
|
||||
.help("The output directory or compressed file.")
|
||||
.takes_value(true),
|
||||
)
|
||||
}
|
||||
|
45
src/decompressors/lzma.rs
Normal file
45
src/decompressors/lzma.rs
Normal file
@ -0,0 +1,45 @@
|
||||
use std::{fs, io::Read};
|
||||
|
||||
use colored::Colorize;
|
||||
|
||||
use crate::{error::OuchResult, utils};
|
||||
use crate::file::File;
|
||||
|
||||
use super::decompressor::{DecompressionResult, Decompressor};
|
||||
|
||||
pub struct LzmaDecompressor {}
|
||||
|
||||
impl LzmaDecompressor {
|
||||
fn extract_to_memory(from: File) -> OuchResult<Vec<u8>> {
|
||||
let mut ret = vec![];
|
||||
|
||||
let from_path = from.path;
|
||||
if !from_path.exists() {
|
||||
eprintln!("{}: could not find {:?}", "error".red(), from_path);
|
||||
}
|
||||
|
||||
let input_bytes = fs::read(&from_path)?;
|
||||
|
||||
|
||||
xz2::read::XzDecoder::new_multi_decoder(&*input_bytes)
|
||||
.read_to_end(&mut ret)?;
|
||||
|
||||
println!("{}: extracted {:?} into memory. ({} bytes)", "info".yellow(), from_path, ret.len());
|
||||
|
||||
Ok(ret)
|
||||
}
|
||||
}
|
||||
|
||||
impl Decompressor for LzmaDecompressor {
|
||||
fn decompress(&self, from: File, into: &Option<File>) -> OuchResult<DecompressionResult> {
|
||||
let destination_path = utils::get_destination_path(into);
|
||||
|
||||
utils::create_path_if_non_existent(destination_path)?;
|
||||
|
||||
Ok(
|
||||
DecompressionResult::FileInMemory(
|
||||
Self::extract_to_memory(from)?
|
||||
)
|
||||
)
|
||||
}
|
||||
}
|
@ -1,7 +1,9 @@
|
||||
mod decompressor;
|
||||
mod unified;
|
||||
mod lzma;
|
||||
mod tar;
|
||||
mod zip;
|
||||
mod unified;
|
||||
|
||||
|
||||
pub use decompressor::Decompressor;
|
||||
pub use decompressor::DecompressionResult;
|
||||
@ -9,4 +11,4 @@ pub use self::tar::TarDecompressor;
|
||||
pub use self::zip::ZipDecompressor;
|
||||
pub use self::unified::GzipDecompressor;
|
||||
pub use self::unified::BzipDecompressor;
|
||||
pub use self::unified::LzmaDecompressor;
|
||||
pub use self::lzma::LzmaDecompressor;
|
@ -8,6 +8,7 @@ use crate::file::File;
|
||||
|
||||
use super::decompressor::{DecompressionResult, Decompressor};
|
||||
|
||||
#[derive(Debug)]
|
||||
pub struct TarDecompressor {}
|
||||
|
||||
impl TarDecompressor {
|
||||
|
@ -1,15 +1,15 @@
|
||||
use std::{
|
||||
io::{self, Read},
|
||||
path::{Path, PathBuf},
|
||||
path::Path,
|
||||
};
|
||||
|
||||
use bzip2::Compress;
|
||||
|
||||
use colored::Colorize;
|
||||
// use niffler;
|
||||
|
||||
use crate::{extension::CompressionFormat, file::File};
|
||||
use crate::{
|
||||
error::{self, OuchResult},
|
||||
error::OuchResult,
|
||||
utils,
|
||||
};
|
||||
|
||||
@ -17,23 +17,19 @@ use super::decompressor::DecompressionResult;
|
||||
use super::decompressor::Decompressor;
|
||||
|
||||
pub struct UnifiedDecompressor {}
|
||||
pub struct LzmaDecompressor {}
|
||||
pub struct GzipDecompressor {}
|
||||
pub struct BzipDecompressor {}
|
||||
|
||||
fn get_decoder<'a>(format: CompressionFormat, buffer: Box<dyn io::Read + Send + 'a>) -> Box<dyn io::Read + Send + 'a> {
|
||||
match format {
|
||||
CompressionFormat::Lzma => Box::new(xz2::read::XzDecoder::new(buffer)),
|
||||
CompressionFormat::Bzip => Box::new(bzip2::read::BzDecoder::new(buffer)),
|
||||
CompressionFormat::Gzip => Box::new(flate2::read::MultiGzDecoder::new(buffer)),
|
||||
other => unreachable!()
|
||||
_other => unreachable!()
|
||||
}
|
||||
}
|
||||
|
||||
impl UnifiedDecompressor {
|
||||
fn unpack_file(from: &Path, format: CompressionFormat) -> OuchResult<Vec<u8>> {
|
||||
// println!("{}: trying to decompress {:?}", "info".yellow(), from);
|
||||
|
||||
let file = std::fs::read(from)?;
|
||||
|
||||
let mut reader = get_decoder(format, Box::new(&file[..]));
|
||||
@ -62,12 +58,6 @@ impl UnifiedDecompressor {
|
||||
}
|
||||
}
|
||||
|
||||
impl Decompressor for LzmaDecompressor {
|
||||
fn decompress(&self, from: File, into: &Option<File>) -> OuchResult<DecompressionResult> {
|
||||
UnifiedDecompressor::decompress(from, CompressionFormat::Lzma, into)
|
||||
}
|
||||
}
|
||||
|
||||
impl Decompressor for GzipDecompressor {
|
||||
fn decompress(&self, from: File, into: &Option<File>) -> OuchResult<DecompressionResult> {
|
||||
UnifiedDecompressor::decompress(from, CompressionFormat::Gzip, into)
|
||||
|
@ -1,4 +1,4 @@
|
||||
use std::{fmt, path::PathBuf};
|
||||
use std::fmt;
|
||||
|
||||
use colored::Colorize;
|
||||
|
||||
@ -13,10 +13,8 @@ pub enum Error {
|
||||
FileNotFound,
|
||||
AlreadyExists,
|
||||
InvalidZipArchive(&'static str),
|
||||
UnsupportedArchive(PathBuf),
|
||||
PermissionDenied,
|
||||
UnsupportedZipArchive(&'static str),
|
||||
FileTooShort,
|
||||
InputsMustHaveBeenDecompressible(String),
|
||||
}
|
||||
|
||||
@ -40,9 +38,6 @@ impl fmt::Display for Error {
|
||||
Error::FileNotFound => {
|
||||
write!(f, "file not found!")
|
||||
}
|
||||
Error::UnsupportedArchive(path) => {
|
||||
write!(f, "ouch is currently uncapable of decompressing {:?}", path)
|
||||
}
|
||||
err => {
|
||||
// TODO
|
||||
write!(f, "todo: missing description for error {:?}", err)
|
||||
|
@ -15,6 +15,7 @@ use crate::decompressors::{
|
||||
ZipDecompressor,
|
||||
GzipDecompressor,
|
||||
BzipDecompressor,
|
||||
LzmaDecompressor,
|
||||
DecompressionResult
|
||||
};
|
||||
|
||||
@ -31,12 +32,10 @@ use crate::file::File;
|
||||
|
||||
use crate::utils;
|
||||
|
||||
pub struct Evaluator {
|
||||
// verbosity: Verbosity
|
||||
}
|
||||
pub struct Evaluator {}
|
||||
|
||||
impl Evaluator {
|
||||
fn get_compressor(
|
||||
pub fn get_compressor(
|
||||
file: &File,
|
||||
) -> error::OuchResult<(Option<Box<dyn Compressor>>, Box<dyn Compressor>)> {
|
||||
if file.extension.is_none() {
|
||||
@ -71,13 +70,12 @@ impl Evaluator {
|
||||
CompressionFormat::Tar => Box::new(TarCompressor {}),
|
||||
CompressionFormat::Zip => Box::new(ZipCompressor {}),
|
||||
_other => todo!()
|
||||
//
|
||||
};
|
||||
|
||||
Ok((first_compressor, second_compressor))
|
||||
}
|
||||
|
||||
fn get_decompressor(
|
||||
pub fn get_decompressor(
|
||||
file: &File,
|
||||
) -> error::OuchResult<(Option<Box<dyn Decompressor>>, Box<dyn Decompressor>)> {
|
||||
if file.extension.is_none() {
|
||||
@ -95,11 +93,9 @@ impl Evaluator {
|
||||
|
||||
CompressionFormat::Zip => Box::new(ZipDecompressor {}),
|
||||
|
||||
CompressionFormat::Gzip => Box::new(GzipDecompressor {}),
|
||||
CompressionFormat::Gzip => Box::new(GzipDecompressor{}),
|
||||
|
||||
CompressionFormat::Lzma => {
|
||||
todo!()
|
||||
}
|
||||
CompressionFormat::Lzma => Box::new(LzmaDecompressor{}),
|
||||
|
||||
CompressionFormat::Bzip => {
|
||||
Box::new(BzipDecompressor {})
|
||||
|
31
src/main.rs
31
src/main.rs
@ -1,7 +1,6 @@
|
||||
use std::{convert::TryFrom, io::Write};
|
||||
use std::convert::TryFrom;
|
||||
|
||||
use colored::Colorize;
|
||||
use walkdir::WalkDir;
|
||||
|
||||
mod cli;
|
||||
mod error;
|
||||
@ -34,27 +33,17 @@ fn main() -> error::OuchResult<()>{
|
||||
Ok(())
|
||||
}
|
||||
|
||||
// fn main() {
|
||||
// use zip::ZipWriter;
|
||||
// fn main() -> error::OuchResult<()> {
|
||||
// let bytes = fs::read("extension.tar.lzma")?;
|
||||
|
||||
// let buf = vec![];
|
||||
// let mut writer = zip::ZipWriter::new(std::io::Cursor::new(buf));
|
||||
// let mut ret = vec![];
|
||||
|
||||
// let options = zip::write::FileOptions::default().compression_method(zip::CompressionMethod::Deflated);
|
||||
// xz2::read::XzDecoder::new_multi_decoder(&*bytes)
|
||||
// .read_to_end(&mut ret)
|
||||
// .unwrap();
|
||||
|
||||
|
||||
// fs::write("extension.tar", &*bytes).unwrap();
|
||||
|
||||
// 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();
|
||||
// Ok(())
|
||||
// }
|
31
src/test.rs
31
src/test.rs
@ -201,3 +201,34 @@ mod extension_extraction {
|
||||
Ok(())
|
||||
}
|
||||
}
|
||||
|
||||
// #[cfg(test)]
|
||||
// mod evaluator {
|
||||
// use crate::extension::Extension;
|
||||
// use crate::error::OuchResult;
|
||||
// use crate::file::File;
|
||||
// use crate::evaluator::Evaluator;
|
||||
// use crate::decompressors::{Decompressor, TarDecompressor, GzipDecompressor};
|
||||
|
||||
// #[test]
|
||||
// fn test() -> OuchResult<()> {
|
||||
// let extension = Extension::new("folder.tar.gz")?;
|
||||
|
||||
// let file = File {
|
||||
// path: "folder.tar.gz".into(),
|
||||
// contents_in_memory: None,
|
||||
// extension: Some(extension),
|
||||
// };
|
||||
|
||||
// let (fst, snd) = Evaluator::get_decompressor(&file)?;
|
||||
|
||||
// let fst = fst.unwrap();
|
||||
|
||||
// assert_eq!(
|
||||
// fst,
|
||||
// Some(Box::new(TarDecompressor::{})
|
||||
// );
|
||||
|
||||
// Ok(())
|
||||
// }
|
||||
// }
|
Loading…
x
Reference in New Issue
Block a user