Early progress in supporting .tar files

This commit is contained in:
Vinícius Rodrigues Miguel 2021-03-21 04:09:28 -03:00
parent 155fca4526
commit b6d4e50cca
10 changed files with 237 additions and 65 deletions

131
Cargo.lock generated
View File

@ -15,6 +15,12 @@ version = "1.0.2"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "f26201604c87b1e01bd3d98f8d5d9a8fcbb815e8cedb41ffccbeb4bf593a35fe"
[[package]]
name = "adler32"
version = "1.2.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "aae1277d39aeec15cb388266ecc24b11c80469deae6067e17a1a7aa9e5c1f234"
[[package]]
name = "ansi_term"
version = "0.11.0"
@ -48,9 +54,9 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "9d117600f438b1707d4e4ae15d3595657288f8235a0eb593e80ecc98ab34e1bc"
dependencies = [
"addr2line",
"cfg-if",
"cfg-if 1.0.0",
"libc",
"miniz_oxide",
"miniz_oxide 0.4.4",
"object",
"rustc-demangle",
]
@ -71,6 +77,22 @@ version = "1.2.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "cf1de2fe8c75bc145a2f577add951f8134889b4795d47466a54a5c846d691693"
[[package]]
name = "byteorder"
version = "1.4.3"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "14c189c53d098945499cdfa7ecc63567cf3886b3332b312a5b4585d8d3a6a610"
[[package]]
name = "bzip2"
version = "0.3.3"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "42b7c3cbf0fa9c1b82308d57191728ca0256cb821220f4e2fd410a72ade26e3b"
dependencies = [
"bzip2-sys",
"libc",
]
[[package]]
name = "bzip2"
version = "0.4.2"
@ -98,6 +120,12 @@ version = "1.0.67"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "e3c69b077ad434294d3ce9f1f6143a2a4b89a8a2d54ef813d85003a4fd1137fd"
[[package]]
name = "cfg-if"
version = "0.1.10"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "4785bdd1c96b2a846b2bd7cc02e86b6b3dbf14e7e53446c4f54c92a361040822"
[[package]]
name = "cfg-if"
version = "1.0.0"
@ -136,7 +164,7 @@ version = "1.2.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "81156fece84ab6a9f2afdb109ce3ae577e42b1228441eded99bd77f627953b1a"
dependencies = [
"cfg-if",
"cfg-if 1.0.0",
]
[[package]]
@ -171,15 +199,27 @@ dependencies = [
]
[[package]]
name = "flate2"
version = "1.0.20"
name = "filetime"
version = "0.2.14"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "cd3aec53de10fe96d7d8c565eb17f2c687bb5518a2ec453b5b1252964526abe0"
checksum = "1d34cfa13a63ae058bfa601fe9e313bbdb3746427c1459185464ce0fcf62e1e8"
dependencies = [
"cfg-if",
"cfg-if 1.0.0",
"libc",
"redox_syscall",
"winapi",
]
[[package]]
name = "flate2"
version = "1.0.14"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "2cfff41391129e0a856d6d822600b8d71179d46879e310417eb9c762eb178b42"
dependencies = [
"cfg-if 0.1.10",
"crc32fast",
"libc",
"miniz_oxide",
"miniz_oxide 0.3.7",
]
[[package]]
@ -220,6 +260,15 @@ dependencies = [
"pkg-config",
]
[[package]]
name = "miniz_oxide"
version = "0.3.7"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "791daaae1ed6889560f8c4359194f56648355540573244a5448a83ba1ecc7435"
dependencies = [
"adler32",
]
[[package]]
name = "miniz_oxide"
version = "0.4.4"
@ -237,8 +286,8 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "3ea40fb13399dd0e9780ea3d82cb6cf27f489f63d820aa7dc9ec967750dc6d58"
dependencies = [
"bgzip",
"bzip2",
"cfg-if",
"bzip2 0.4.2",
"cfg-if 1.0.0",
"enum_primitive",
"flate2",
"thiserror",
@ -276,6 +325,8 @@ dependencies = [
"clap",
"colored",
"niffler",
"tar",
"zip",
]
[[package]]
@ -302,6 +353,15 @@ dependencies = [
"proc-macro2",
]
[[package]]
name = "redox_syscall"
version = "0.2.5"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "94341e4e44e24f6b591b59e47a8a027df12e008d73fd5672dbea9cc22f4507d9"
dependencies = [
"bitflags",
]
[[package]]
name = "rustc-demangle"
version = "0.1.18"
@ -337,6 +397,17 @@ dependencies = [
"unicode-xid",
]
[[package]]
name = "tar"
version = "0.4.33"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "c0bcfbd6a598361fda270d82469fff3d65089dc33e175c9a131f7b4cd395f228"
dependencies = [
"filetime",
"libc",
"xattr",
]
[[package]]
name = "textwrap"
version = "0.11.0"
@ -366,6 +437,17 @@ dependencies = [
"syn",
]
[[package]]
name = "time"
version = "0.1.44"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "6db9e6914ab8b1ae1c260a4ae7a49b6c5611b40328a735b21862567685e73255"
dependencies = [
"libc",
"wasi",
"winapi",
]
[[package]]
name = "unicode-width"
version = "0.1.8"
@ -384,6 +466,12 @@ version = "0.8.2"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "f1bddf1187be692e79c5ffeab891132dfb0f236ed36a43c7ed39f1165ee20191"
[[package]]
name = "wasi"
version = "0.10.0+wasi-snapshot-preview1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "1a143597ca7c7793eff794def352d41792a93c481eb1042423ff7ff72ba2c31f"
[[package]]
name = "winapi"
version = "0.3.9"
@ -406,6 +494,15 @@ version = "0.4.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "712e227841d057c1ee1cd2fb22fa7e5a5461ae8e48fa2ca79ec42cfc1931183f"
[[package]]
name = "xattr"
version = "0.2.2"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "244c3741f4240ef46274860397c7c74e50eb23624996930e484c16679633a54c"
dependencies = [
"libc",
]
[[package]]
name = "xz2"
version = "0.1.6"
@ -414,3 +511,17 @@ checksum = "c179869f34fc7c01830d3ce7ea2086bc3a07e0d35289b667d0a8bf910258926c"
dependencies = [
"lzma-sys",
]
[[package]]
name = "zip"
version = "0.5.11"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "8264fcea9b7a036a4a5103d7153e988dbc2ebbafb34f68a3c2d404b6b82d74b6"
dependencies = [
"byteorder",
"bzip2 0.3.3",
"crc32fast",
"flate2",
"thiserror",
"time",
]

View File

@ -10,3 +10,5 @@ edition = "2018"
colored = "2.0.0"
niffler = "2.3.1"
clap = "2.33.3"
zip = "0.5.11"
tar = "0.4.33"

View File

@ -124,12 +124,6 @@ impl TryFrom<clap::ArgMatches<'static>> for Command {
let input_files = process_decompressible_input(input_files)?;
println!(
"{}: attempting to decompress input files into {}",
"info".yellow(),
output_file
);
let input_files = input_files.into_iter().map(File::from).collect();
return Ok(Command {

View File

@ -0,0 +1 @@
/// This file should/could store a Decompressor trait

1
src/decompressors/mod.rs Normal file
View File

@ -0,0 +1 @@
pub mod tar;

33
src/decompressors/tar.rs Normal file
View File

@ -0,0 +1,33 @@
use std::{fs, path::{Path, PathBuf}};
use crate::file::File;
use crate::error::OuchResult;
use colored::Colorize;
pub struct Decompressor {}
impl Decompressor {
pub fn decompress(from: &File, into: &Option<File>) -> OuchResult<()> {
let destination_path = match into {
Some(output) => {
// Must be None according to the way command-line arg. parsing in Ouch works
assert_eq!(output.extension, None);
Path::new(&output.path)
}
None => Path::new(".")
};
if !destination_path.exists() {
println!("{}: attempting to create folder {:?}.", "info".yellow(), &destination_path);
std::fs::create_dir_all(destination_path)?;
println!("{}: directory {:#?} created.", "info".yellow(), fs::canonicalize(&destination_path)?);
}
Ok(())
}
}

View File

@ -9,6 +9,7 @@ pub enum Error {
// TODO: get rid of this error variant
InvalidUnicode,
InvalidInput,
IOError,
InputsMustHaveBeenDecompressible(String),
}
@ -32,8 +33,20 @@ impl fmt::Display for Error {
}
_ => {
// TODO
write!(f, "")
write!(f, "todo: missing description for error")
}
}
}
}
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);
Self::IOError
}
}

View File

@ -1,8 +1,8 @@
use std::{convert::TryFrom, path::{PathBuf}};
use colored::Colorize;
use crate::{cli::{Command, CommandKind}, error, extension::CompressionFormat, file::File};
use crate::decompressors::tar;
pub struct Evaluator {
command: Command,
@ -10,53 +10,48 @@ pub struct Evaluator {
}
impl Evaluator {
// todo: remove this?
pub fn new(command: Command) -> Self {
Self {
command
}
}
fn handle_compression(files_to_compress: &[PathBuf], output_file: &Option<File>) {
}
fn decompress_file(mut filename: &PathBuf, mut extension: CompressionFormat, output_file: &Option<File>) -> error::OuchResult<()> {
loop {
println!("{}: attempting to decompress '{:?}'", "ouch".bright_blue(), filename);
fn decompress_file(&self, file: &File) -> error::OuchResult<()> {
println!("{}: attempting to decompress {:?}", "ouch".bright_blue(), file.path);
if file.extension.is_none() {
// This block *should* be unreachable
eprintln!("{}: reached Evaluator::decompress_file without known extension.", "internal error".red());
return Err(error::Error::InvalidInput);
}
let extension = file.extension.clone().unwrap();
let output_file = &self.command.output;
match extension.second_ext {
CompressionFormat::Tar => tar::Decompressor::decompress(file, output_file)?,
_ => {
todo!()
}
}
// TODO: decompress first extension
Ok(())
}
fn handle_decompression(files_to_decompress: &[File], output_file: &Option<File>) {
// for (filename, extension) in files_to_decompress {
// // println!("file: {:?}, extension: {:?}", filename, extension);
// // TODO: actually decompress anything ;-;
// // Once decompressed, check if the file can be decompressed further
// // e.g.: "foobar.tar.gz" -> "foobar.tar"
// let filename: &PathBuf = &filename.as_path().file_stem().unwrap().into();
// match CompressionFormat::try_from(filename) {
// Ok(extension) => {
// println!("{}: attempting to decompress {:?}, ext: {:?}", "info".yellow(), filename, extension);
// },
// Err(err) => {
// continue;
// }
// }
// }
}
pub fn evaluate(&mut self) {
pub fn evaluate(&mut self) -> error::OuchResult<()> {
match &self.command.kind {
CommandKind::Compression(files_to_compress) => {
Evaluator::handle_compression(files_to_compress, &self.command.output);
for _file in files_to_compress {
todo!();
}
}
CommandKind::Decompression(files_to_decompress) => {
Evaluator::handle_decompression(files_to_decompress, &self.command.output);
for file in files_to_decompress {
self.decompress_file(file)?;
}
}
}
Ok(())
}
}

View File

@ -6,10 +6,10 @@ use CompressionFormat::*;
/// Represents the extension of a file, but only really caring about
/// compression formats (and .tar).
/// Ex.: Extension::new("file.tar.gz") == Extension { first_ext: Some(Tar), second_ext: Gzip }
#[derive(Debug, PartialEq, Eq)]
#[derive(Clone, Debug, PartialEq, Eq)]
pub struct Extension {
first_ext: Option<CompressionFormat>,
second_ext: CompressionFormat
pub first_ext: Option<CompressionFormat>,
pub second_ext: CompressionFormat
}
impl From<CompressionFormat> for Extension {
@ -86,7 +86,7 @@ pub fn get_extension_from_filename(filename: &str) -> Option<(&str, &str)> {
}
}
#[derive(PartialEq, Eq, Debug)]
#[derive(Clone, PartialEq, Eq, Debug)]
/// Accepted extensions for input and output
pub enum CompressionFormat {
// .gz

View File

@ -1,6 +1,7 @@
use std::{convert::TryFrom};
use std::{convert::TryFrom, fs::File, path::{Path, PathBuf}};
use colored::Colorize;
use tar::Archive;
mod cli;
mod error;
@ -9,15 +10,36 @@ mod file;
mod test;
mod evaluator;
mod decompressors;
fn main() {
let matches = cli::get_matches();
match cli::Command::try_from(matches) {
Ok(command) => {
let mut eval = evaluator::Evaluator::new(command);
eval.evaluate();
}
Err(err) => {
print!("{}: {}\n", "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();
// }
// Err(err) => {
// print!("{}: {}\n", "error".red(), err);
// }
// }
// Testing tar unarchival
let file = File::open("ouch.tar").unwrap();
let mut a = Archive::new(file);
for file in a.entries().unwrap() {
// Make sure there wasn't an I/O error
let mut file = file.unwrap();
let path = if let Ok(path) = file.path() {
path
} else {
continue;
};
let name = path.to_string_lossy();
file.unpack(format!("{}", name)).unwrap();
}
}