diff --git a/src/cli.rs b/src/cli.rs index 69cb256..7e9a284 100644 --- a/src/cli.rs +++ b/src/cli.rs @@ -4,7 +4,7 @@ use clap::{Arg, Values}; use colored::Colorize; use crate::error; -use crate::extension::{Extension, CompressionFormat}; +use crate::extension::Extension; use crate::file::File; #[derive(PartialEq, Eq, Debug)] diff --git a/src/compressors/compressor.rs b/src/compressors/compressor.rs index 4ca801f..729d770 100644 --- a/src/compressors/compressor.rs +++ b/src/compressors/compressor.rs @@ -2,22 +2,17 @@ use std::path::PathBuf; use crate::{error::OuchResult, file::File}; -pub enum CompressionResult { - ZipArchive(Vec), - TarArchive(Vec), - FileInMemory(Vec) +// pub enum CompressionResult { +// ZipArchive(Vec), +// TarArchive(Vec), +// FileInMemory(Vec) +// } + +pub enum Entry { + Files(Vec), + InMemory(File) } pub trait Compressor { - fn compress(&self, from: Vec) -> OuchResult; -} - -// -// -// -// -// -// -// -// -// \ No newline at end of file + fn compress(&self, from: Vec) -> OuchResult>; +} \ No newline at end of file diff --git a/src/compressors/mod.rs b/src/compressors/mod.rs index 7d48bca..2d18d41 100644 --- a/src/compressors/mod.rs +++ b/src/compressors/mod.rs @@ -1,5 +1,5 @@ mod tar; mod compressor; -pub use compressor::{Compressor, CompressionResult}; +pub use compressor::{Compressor}; pub use self::tar::TarCompressor; \ No newline at end of file diff --git a/src/compressors/tar.rs b/src/compressors/tar.rs index 572118c..2e800b3 100644 --- a/src/compressors/tar.rs +++ b/src/compressors/tar.rs @@ -1,42 +1,62 @@ -use std::{fs::File, path::Path}; +use std::{fs, path::PathBuf}; -use tar::Builder; +use colored::Colorize; +use tar::{Builder, Header}; use walkdir::WalkDir; -use crate::{decompressors::TarDecompressor, error::OuchResult}; -use crate::compressors::Compressor; -use super::compressor::CompressionResult; +use crate::{compressors::Compressor, error::{Error, OuchResult}, file::{self, File}}; pub struct TarCompressor {} impl TarCompressor { - fn make_archive_in_memory(input_files: Vec) -> OuchResult> { + + fn make_archive_from_memory(input: File) -> OuchResult> { + + let contents = match input.contents { + Some(bytes) => bytes, + None => { + eprintln!("{}: reached TarCompressor::make_archive_from_memory without known content.", "internal error".red()); + return Err(Error::InvalidInput); + } + }; + + let mut header = Header::new_gnu(); + + header.set_path(&input.path).unwrap(); + header.set_size(contents.len() as u64); + header.set_cksum(); + + + let mut b = Builder::new(Vec::new()); + b.append_data(&mut header, &input.path, &*contents)?; + + Ok(b.into_inner()?) + } + + fn make_archive_from_files(input_files: Vec) -> OuchResult> { let buf = Vec::new(); let mut b = Builder::new(buf); for file in input_files { - for entry in WalkDir::new(&file.path) { + for entry in WalkDir::new(&file) { let entry = entry.unwrap(); let path = entry.path(); if path.is_dir() { continue; } - b.append_file(path, &mut File::open(path).unwrap()).unwrap(); + b.append_file(path, &mut fs::File::open(path).unwrap()).unwrap(); } } - Ok(b.into_inner()?) } } impl Compressor for TarCompressor { - fn compress(&self, from: Vec) -> OuchResult { - Ok(CompressionResult::TarArchive( - TarCompressor::make_archive_in_memory(from)? - )) + fn compress(&self, from: Vec) -> OuchResult> { + Ok( + TarCompressor::make_archive_from_files(from)? + ) } -} - -// fn compress(&self, from: Vec, into: &Option) -> OuchResult; \ No newline at end of file +} \ No newline at end of file diff --git a/src/evaluator.rs b/src/evaluator.rs index d9cedb9..8aee8a8 100644 --- a/src/evaluator.rs +++ b/src/evaluator.rs @@ -2,23 +2,71 @@ use std::{ffi::OsStr, fs, io::Write, path::PathBuf}; use colored::Colorize; -use crate::{decompressors::Decompressor, extension::{self, Extension}}; -use crate::decompressors::TarDecompressor; +use crate::{compressors::TarCompressor, decompressors::TarDecompressor}; use crate::decompressors::ZipDecompressor; use crate::{ cli::{Command, CommandKind}, - decompressors::{DecompressionResult, NifflerDecompressor}, + decompressors::{ + Decompressor, + DecompressionResult, + NifflerDecompressor + }, + compressors::Compressor, error::{self, OuchResult}, - extension::CompressionFormat, + extension::{ + Extension, + CompressionFormat, + }, file::File, utils, }; + pub struct Evaluator { // verbosity: Verbosity } impl Evaluator { + fn get_compressor( + file: &File, + ) -> error::OuchResult<(Option>, Box)> { + if file.extension.is_none() { + // This block *should* be unreachable + eprintln!( + "{}: reached Evaluator::get_decompressor without known extension.", + "internal error".red() + ); + return Err(error::Error::InvalidInput); + } + let extension = file.extension.clone().unwrap(); + + // Supported first compressors: + // .tar and .zip + let first_compressor: Option> = match extension.first_ext { + Some(ext) => match ext { + CompressionFormat::Tar => Some(Box::new(TarCompressor {})), + + // CompressionFormat::Zip => Some(Box::new(ZipCompressor {})), + + // _other => Some(Box::new(NifflerCompressor {})), + _other => { + todo!(); + } + }, + None => None, + }; + + // Supported second compressors: + // any + let second_compressor: Box = match extension.second_ext { + CompressionFormat::Tar => Box::new(TarCompressor {}), + _other => todo!() + // + }; + + Ok((first_compressor, second_compressor)) + } + fn get_decompressor( file: &File, ) -> error::OuchResult<(Option>, Box)> { @@ -31,7 +79,7 @@ impl Evaluator { return Err(error::Error::InvalidInput); } let extension = file.extension.clone().unwrap(); - + let second_decompressor: Box = match extension.second_ext { CompressionFormat::Tar => Box::new(TarDecompressor {}), @@ -64,10 +112,11 @@ impl Evaluator { output_file: &Option, extension: Option, ) -> OuchResult<()> { - let output_file_path = utils::get_destination_path(output_file); - let mut filename = file_path.file_stem().unwrap_or(output_file_path.as_os_str()); + let mut filename = file_path + .file_stem() + .unwrap_or(output_file_path.as_os_str()); if filename == "." { // I believe this is only possible when the supplied inout has a name // of the sort `.tar` or `.zip' and no output has been supplied. @@ -97,7 +146,6 @@ impl Evaluator { // If there is a decompressor to use, we'll create a file in-memory and decompress it - let decompression_result = decompressor.decompress(file, output_file)?; if let DecompressionResult::FileInMemory(_) = decompression_result { // Should not be reachable. @@ -107,6 +155,11 @@ impl Evaluator { Ok(()) } + fn compress_files(files: Vec, output: File) -> error::OuchResult<()> { + let (first_decompressor, second_decompressor) = Self::get_compressor(&output)?; + Ok(()) + } + fn decompress_file(file: File, output: &Option) -> error::OuchResult<()> { // let output_file = &command.output; let (first_decompressor, second_decompressor) = Self::get_decompressor(&file)?; @@ -120,7 +173,13 @@ impl Evaluator { DecompressionResult::FileInMemory(bytes) => { // We'll now decompress a file currently in memory. // This will currently happen in the case of .bz, .xz and .lzma - Self::decompress_file_in_memory(bytes, file_path, first_decompressor, output, extension)?; + Self::decompress_file_in_memory( + bytes, + file_path, + first_decompressor, + output, + extension, + )?; } DecompressionResult::FilesUnpacked(_files) => { // If the file's last extension was an archival method, @@ -138,12 +197,12 @@ impl Evaluator { pub fn evaluate(command: Command) -> error::OuchResult<()> { let output = command.output.clone(); - + match command.kind { CommandKind::Compression(files_to_compress) => { - for _file in files_to_compress { - todo!(); - } + // Safe to unwrap since output is mandatory for compression + let output = output.unwrap(); + Self::compress_files(files_to_compress, output)?; } CommandKind::Decompression(files_to_decompress) => { for file in files_to_decompress { diff --git a/src/file.rs b/src/file.rs index 78b87a5..22391ac 100644 --- a/src/file.rs +++ b/src/file.rs @@ -1,6 +1,6 @@ use std::path::PathBuf; -use crate::extension::{CompressionFormat, Extension}; +use crate::extension::Extension; #[derive(Debug, Clone, PartialEq, Eq)] diff --git a/src/main.rs b/src/main.rs index 046089d..02a8020 100644 --- a/src/main.rs +++ b/src/main.rs @@ -1,4 +1,4 @@ -use std::{convert::TryFrom, fs, path::{Path, PathBuf}}; +use std::{convert::TryFrom}; use colored::Colorize; @@ -13,43 +13,39 @@ mod utils; mod compressors; mod decompressors; -use compressors::{CompressionResult, Compressor, TarCompressor}; -use error::OuchResult; -use file::File; +fn main() -> error::OuchResult<()>{ + let print_error = |err| { + println!("{}: {}", "error".red(), err); + }; + let matches = cli::get_matches(); + match cli::Command::try_from(matches) { + Ok(command) => { + match evaluator::Evaluator::evaluate(command) { + Ok(_) => {}, + Err(err) => print_error(err) + } + } + Err(err) => { + print_error(err) + } + } -fn main() -> OuchResult<()>{ - // let print_error = |err| { - // println!("{}: {}", "error".red(), err); + // let compressor = TarCompressor {}; + + // let file = File { + // path: PathBuf::from("target"), + // contents: None, + // extension: None, // }; - // let matches = cli::get_matches(); - // match cli::Command::try_from(matches) { - // Ok(command) => { - // match evaluator::Evaluator::evaluate(command) { - // Ok(_) => {}, - // Err(err) => print_error(err) - // } - // } - // Err(err) => { - // print_error(err) - // } - // } - let compressor = TarCompressor {}; + // let ok = compressor.compress(vec![file])?; - let file = File { - path: PathBuf::from("target"), - contents: None, - extension: None, - }; + // let ok = match ok { + // CompressionResult::TarArchive(bytes) => bytes, + // _ => unreachable!() + // }; - let ok = compressor.compress(vec![file])?; - - let ok = match ok { - CompressionResult::TarArchive(bytes) => bytes, - _ => unreachable!() - }; - - fs::write(Path::new("great.tar"), ok)?; + // fs::write(Path::new("great.tar"), ok)?; Ok(()) }