mirror of
https://github.com/ouch-org/ouch.git
synced 2025-07-20 08:30:13 +00:00
Early progress in supporting .tar files
This commit is contained in:
parent
155fca4526
commit
b6d4e50cca
131
Cargo.lock
generated
131
Cargo.lock
generated
@ -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",
|
||||
]
|
||||
|
@ -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"
|
@ -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 {
|
||||
|
1
src/decompressors/decompressor.rs
Normal file
1
src/decompressors/decompressor.rs
Normal file
@ -0,0 +1 @@
|
||||
/// This file should/could store a Decompressor trait
|
1
src/decompressors/mod.rs
Normal file
1
src/decompressors/mod.rs
Normal file
@ -0,0 +1 @@
|
||||
pub mod tar;
|
33
src/decompressors/tar.rs
Normal file
33
src/decompressors/tar.rs
Normal 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(())
|
||||
}
|
||||
}
|
15
src/error.rs
15
src/error.rs
@ -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
|
||||
}
|
||||
}
|
@ -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(())
|
||||
}
|
||||
}
|
@ -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
|
||||
|
42
src/main.rs
42
src/main.rs
@ -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();
|
||||
}
|
||||
}
|
||||
|
Loading…
x
Reference in New Issue
Block a user