Add internal gzip compression

This commit is contained in:
Andrew Phillips
2023-09-02 23:21:33 +00:00
parent d9d47e97a9
commit 0a6cefc99e
2 changed files with 85 additions and 2 deletions

View File

@@ -10,11 +10,13 @@ use enum_map::{EnumMap,Enum};
pub mod none; pub mod none;
pub mod lz4; pub mod lz4;
pub mod gzip;
pub mod program; pub mod program;
use none::CompressionEngineNone; use none::CompressionEngineNone;
use lz4::CompressionEngineLZ4; use lz4::CompressionEngineLZ4;
use program::CompressionProgram; use program::CompressionProgram;
use gzip::CompressionEngineGZip;
#[derive(Debug, Eq, PartialEq, Clone, strum::EnumIter, strum::Display, strum::EnumString, Enum)] #[derive(Debug, Eq, PartialEq, Clone, strum::EnumIter, strum::Display, strum::EnumString, Enum)]
#[strum(ascii_case_insensitive)] #[strum(ascii_case_insensitive)]
@@ -38,7 +40,7 @@ pub trait CompressionEngine {
lazy_static! { lazy_static! {
pub static ref COMPRESSION_PROGRAMS: EnumMap<CompressionType, Option<CompressionProgram>> = enum_map! { pub static ref COMPRESSION_PROGRAMS: EnumMap<CompressionType, Option<CompressionProgram>> = enum_map! {
CompressionType::LZ4 => None, CompressionType::LZ4 => None,
CompressionType::GZip => Some(CompressionProgram::new("gzip", vec!["-qcf"], vec!["-dcf"])), CompressionType::GZip => None,
CompressionType::BZip2 => Some(CompressionProgram::new("bzip2", vec!["-qcf"], vec!["-dcf"])), CompressionType::BZip2 => Some(CompressionProgram::new("bzip2", vec!["-qcf"], vec!["-dcf"])),
CompressionType::XZ => Some(CompressionProgram::new("xz", vec!["-qcf"], vec!["-dcf"])), CompressionType::XZ => Some(CompressionProgram::new("xz", vec!["-qcf"], vec!["-dcf"])),
CompressionType::ZStd => Some(CompressionProgram::new("zstd", vec!["-qcf"], vec!["-dcf"])), CompressionType::ZStd => Some(CompressionProgram::new("zstd", vec!["-qcf"], vec!["-dcf"])),
@@ -49,8 +51,9 @@ lazy_static! {
pub fn get_engine(compression_type: CompressionType) -> Result<Box<dyn CompressionEngine>> { pub fn get_engine(compression_type: CompressionType) -> Result<Box<dyn CompressionEngine>> {
match compression_type { match compression_type {
CompressionType::None => Ok(Box::new(CompressionEngineNone::new())),
CompressionType::LZ4 => Ok(Box::new(CompressionEngineLZ4::new())), CompressionType::LZ4 => Ok(Box::new(CompressionEngineLZ4::new())),
CompressionType::GZip => Ok(Box::new(CompressionEngineGZip::new())),
CompressionType::None => Ok(Box::new(CompressionEngineNone::new())),
compression_type => Ok(Box::new(COMPRESSION_PROGRAMS[compression_type.clone()].clone().unwrap())) compression_type => Ok(Box::new(COMPRESSION_PROGRAMS[compression_type.clone()].clone().unwrap()))
} }
} }

80
src/compression/gzip.rs Normal file
View File

@@ -0,0 +1,80 @@
use anyhow::Result;
use std::fs::File;
use std::io;
use std::io::Write;
use std::path::PathBuf;
use log::*;
use flate2::Compression;
use flate2::read::GzDecoder;
use flate2::write::GzEncoder;
use crate::compression::CompressionEngine;
#[derive(Debug, Eq, PartialEq, Clone, Default)]
pub struct CompressionEngineGZip {}
impl CompressionEngineGZip {
pub fn new() -> CompressionEngineGZip {
CompressionEngineGZip {}
}
}
impl CompressionEngine for CompressionEngineGZip {
fn is_supported(&self) -> bool {
true
}
fn cat(&self, file_path: PathBuf) -> Result<()> {
debug!("COMPRESSION: Outputting {:?} to STDOUT using {:?}", file_path, *self);
let mut stdout = io::stdout().lock();
let file = File::open(file_path)?;
let mut gzip_read = GzDecoder::new(file);
io::copy(&mut gzip_read, &mut stdout)?;
stdout.flush()?;
Ok(())
}
fn create(&self, file_path: PathBuf) -> Result<Box<dyn Write>> {
debug!("COMPRESSION: Writting to {:?} using {:?}", file_path, *self);
let file = File::create(file_path)?;
let gzip_write = GzEncoder::new(file, Compression::default());
Ok(Box::new(AutoFinishGzEncoder::new(gzip_write)))
}
}
pub struct AutoFinishGzEncoder<W: Write> {
encoder: Option<GzEncoder<W>>,
}
impl<W: Write> AutoFinishGzEncoder<W> {
fn new(gz_encoder: GzEncoder<W>) -> AutoFinishGzEncoder<W> {
AutoFinishGzEncoder {
encoder: Some(gz_encoder),
}
}
}
impl<W: Write> Drop for AutoFinishGzEncoder<W> {
fn drop(&mut self) {
if let Some(encoder) = self.encoder.take() {
debug!("COMPRESSION: Finishing");
let _ = encoder.finish();
}
}
}
impl<W: Write> Write for AutoFinishGzEncoder<W> {
fn write(&mut self, buf: &[u8]) -> io::Result<usize> {
self.encoder.as_mut().unwrap().write(buf)
}
fn flush(&mut self) -> io::Result<()> {
self.encoder.as_mut().unwrap().flush()
}
}