Refactor compression into multiple files
This commit is contained in:
@@ -1,19 +1,20 @@
|
|||||||
use anyhow::{Context, Result, anyhow};
|
use anyhow::{Result};
|
||||||
use strum::IntoEnumIterator;
|
use strum::IntoEnumIterator;
|
||||||
use std::fs::File;
|
|
||||||
use std::io;
|
|
||||||
use std::io::Write;
|
|
||||||
use std::process::{Command,Stdio};
|
|
||||||
use std::path::PathBuf;
|
use std::path::PathBuf;
|
||||||
use std::env;
|
use std::io::Write;
|
||||||
use std::fs;
|
|
||||||
use std::os::unix::fs::PermissionsExt;
|
|
||||||
use log::*;
|
|
||||||
use lazy_static::lazy_static;
|
use lazy_static::lazy_static;
|
||||||
extern crate enum_map;
|
extern crate enum_map;
|
||||||
use enum_map::enum_map;
|
use enum_map::enum_map;
|
||||||
use enum_map::{EnumMap,Enum};
|
use enum_map::{EnumMap,Enum};
|
||||||
|
|
||||||
|
pub mod none;
|
||||||
|
pub mod lz4;
|
||||||
|
pub mod program;
|
||||||
|
|
||||||
|
use none::CompressionEngineNone;
|
||||||
|
use lz4::CompressionEngineLZ4;
|
||||||
|
use program::CompressionProgram;
|
||||||
|
|
||||||
#[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)]
|
||||||
@@ -27,12 +28,10 @@ pub enum CompressionType {
|
|||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
#[derive(Debug, Eq, PartialEq, Clone)]
|
pub trait CompressionEngine {
|
||||||
pub struct CompressionProgram {
|
fn is_supported(&self) -> bool;
|
||||||
pub program: String,
|
fn cat(&self, file_path: PathBuf) -> Result<()>;
|
||||||
pub compress: Vec<String>,
|
fn create(&self, file_path: PathBuf) -> Result<Box<dyn Write>>;
|
||||||
pub decompress: Vec<String>,
|
|
||||||
pub supported: bool
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
@@ -47,168 +46,6 @@ lazy_static! {
|
|||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
impl CompressionProgram {
|
|
||||||
pub fn new(program: &str, compress: Vec<&str>, decompress: Vec<&str>) -> CompressionProgram {
|
|
||||||
let program_path = get_program_path(program);
|
|
||||||
let supported = program_path.is_ok();
|
|
||||||
|
|
||||||
CompressionProgram {
|
|
||||||
program: program_path.unwrap_or(program.to_string()),
|
|
||||||
compress: compress.iter().map(|s| {s.to_string()}).collect(),
|
|
||||||
decompress: decompress.iter().map(|s| {s.to_string()}).collect(),
|
|
||||||
supported
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
pub trait CompressionEngine {
|
|
||||||
fn is_supported(&self) -> bool;
|
|
||||||
fn cat(&self, file_path: PathBuf) -> Result<()>;
|
|
||||||
fn create(&self, file_path: PathBuf) -> Result<Box<dyn Write>>;
|
|
||||||
}
|
|
||||||
|
|
||||||
impl CompressionEngine for CompressionProgram {
|
|
||||||
fn is_supported(&self) -> bool {
|
|
||||||
self.supported
|
|
||||||
}
|
|
||||||
|
|
||||||
fn cat(&self, file_path: PathBuf) -> Result<()> {
|
|
||||||
debug!("COMPRESSION: Outputting {:?} to STDOUT using {:?}", file_path, *self);
|
|
||||||
let program = self.program.clone();
|
|
||||||
let args = self.decompress.clone();
|
|
||||||
|
|
||||||
debug!("COMPRESSION: Executing command: {:?} {:?} writing to {:?}", program, args, file_path);
|
|
||||||
|
|
||||||
let file = File::open(file_path).context("Unable to open file for reading")?;
|
|
||||||
|
|
||||||
let mut process = Command::new(program.clone())
|
|
||||||
.args(args.clone())
|
|
||||||
.stdin(file)
|
|
||||||
.spawn()
|
|
||||||
.context(anyhow!("Unable to spawn child process: {:?} {:?}", program, args))?;
|
|
||||||
|
|
||||||
let result = process.wait()
|
|
||||||
.context(anyhow!("Unable to wait for child process: {:?} {:?}", program, args))?;
|
|
||||||
|
|
||||||
if result.success() {
|
|
||||||
Ok(())
|
|
||||||
} else {
|
|
||||||
Err(anyhow!("Decompression program returned {}", result))
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
fn create(&self, file_path: PathBuf) -> Result<Box<dyn Write>> {
|
|
||||||
debug!("COMPRESSION: Writting to {:?} using {:?}", file_path, *self);
|
|
||||||
|
|
||||||
let program = self.program.clone();
|
|
||||||
let args = self.compress.clone();
|
|
||||||
|
|
||||||
debug!("COMPRESSION: Executing command: {:?} {:?} writing to {:?}", program, args, file_path);
|
|
||||||
|
|
||||||
let file = File::create(file_path).context("Unable to open file for writing")?;
|
|
||||||
|
|
||||||
let process = Command::new(program.clone())
|
|
||||||
.args(args.clone())
|
|
||||||
.stdin(Stdio::piped())
|
|
||||||
.stdout(file)
|
|
||||||
.spawn()
|
|
||||||
.context(anyhow!("Problem spawning child process: {:?} {:?}", program, args))?;
|
|
||||||
|
|
||||||
Ok(Box::new(process.stdin.unwrap()))
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
#[derive(Debug, Eq, PartialEq, Clone, Default)]
|
|
||||||
pub struct CompressionEngineNone {}
|
|
||||||
|
|
||||||
impl CompressionEngineNone {
|
|
||||||
pub fn new() -> CompressionEngineNone {
|
|
||||||
CompressionEngineNone {}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
impl CompressionEngine for CompressionEngineNone {
|
|
||||||
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 mut file = File::open(file_path)?;
|
|
||||||
|
|
||||||
io::copy(&mut file, &mut stdout)?;
|
|
||||||
stdout.flush()?;
|
|
||||||
|
|
||||||
Ok(())
|
|
||||||
}
|
|
||||||
|
|
||||||
fn create(&self, file_path: PathBuf) -> Result<Box<dyn Write>> {
|
|
||||||
debug!("COMPRESSION: Writting to {:?} using {:?}", file_path, *self);
|
|
||||||
Ok(Box::new(File::create(file_path)?))
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
#[derive(Debug, Eq, PartialEq, Clone, Default)]
|
|
||||||
pub struct CompressionEngineLZ4 {}
|
|
||||||
|
|
||||||
impl CompressionEngineLZ4 {
|
|
||||||
pub fn new() -> CompressionEngineLZ4 {
|
|
||||||
CompressionEngineLZ4 {}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
impl CompressionEngine for CompressionEngineLZ4 {
|
|
||||||
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 lz4_read = lz4_flex::frame::FrameDecoder::new(file);
|
|
||||||
|
|
||||||
io::copy(&mut lz4_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 lz4_write = lz4_flex::frame::FrameEncoder::new(file).auto_finish();
|
|
||||||
|
|
||||||
Ok(Box::new(lz4_write))
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
fn get_program_path(program: &str) -> Result<String> {
|
|
||||||
debug!("COMPRESSION: Looking for executable: {}", program);
|
|
||||||
if let Ok(path) = env::var("PATH") {
|
|
||||||
for p in path.split(':') {
|
|
||||||
let p_str = format!("{}/{}", p, program);
|
|
||||||
let stat = fs::metadata(p_str.clone());
|
|
||||||
if let Ok(stat) = stat {
|
|
||||||
let md = stat;
|
|
||||||
let permissions = md.permissions();
|
|
||||||
if md.is_file() && permissions.mode() & 0o111 != 0 {
|
|
||||||
return Ok(p_str);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
Err(anyhow!("Unable to find binary {} in PATH", program))
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
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 {
|
||||||
|
|||||||
47
src/compression/lz4.rs
Normal file
47
src/compression/lz4.rs
Normal file
@@ -0,0 +1,47 @@
|
|||||||
|
use anyhow::Result;
|
||||||
|
use std::fs::File;
|
||||||
|
use std::io;
|
||||||
|
use std::io::Write;
|
||||||
|
use std::path::PathBuf;
|
||||||
|
use log::*;
|
||||||
|
extern crate enum_map;
|
||||||
|
|
||||||
|
use crate::compression::CompressionEngine;
|
||||||
|
|
||||||
|
#[derive(Debug, Eq, PartialEq, Clone, Default)]
|
||||||
|
pub struct CompressionEngineLZ4 {}
|
||||||
|
|
||||||
|
impl CompressionEngineLZ4 {
|
||||||
|
pub fn new() -> CompressionEngineLZ4 {
|
||||||
|
CompressionEngineLZ4 {}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl CompressionEngine for CompressionEngineLZ4 {
|
||||||
|
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 lz4_read = lz4_flex::frame::FrameDecoder::new(file);
|
||||||
|
|
||||||
|
io::copy(&mut lz4_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 lz4_write = lz4_flex::frame::FrameEncoder::new(file).auto_finish();
|
||||||
|
|
||||||
|
Ok(Box::new(lz4_write))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
39
src/compression/none.rs
Normal file
39
src/compression/none.rs
Normal file
@@ -0,0 +1,39 @@
|
|||||||
|
use anyhow::Result;
|
||||||
|
use std::fs::File;
|
||||||
|
use std::io;
|
||||||
|
use std::io::Write;
|
||||||
|
use std::path::PathBuf;
|
||||||
|
use log::*;
|
||||||
|
|
||||||
|
use crate::compression::CompressionEngine;
|
||||||
|
|
||||||
|
#[derive(Debug, Eq, PartialEq, Clone, Default)]
|
||||||
|
pub struct CompressionEngineNone {}
|
||||||
|
|
||||||
|
impl CompressionEngineNone {
|
||||||
|
pub fn new() -> CompressionEngineNone {
|
||||||
|
CompressionEngineNone {}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl CompressionEngine for CompressionEngineNone {
|
||||||
|
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 mut file = File::open(file_path)?;
|
||||||
|
|
||||||
|
io::copy(&mut file, &mut stdout)?;
|
||||||
|
stdout.flush()?;
|
||||||
|
|
||||||
|
Ok(())
|
||||||
|
}
|
||||||
|
|
||||||
|
fn create(&self, file_path: PathBuf) -> Result<Box<dyn Write>> {
|
||||||
|
debug!("COMPRESSION: Writting to {:?} using {:?}", file_path, *self);
|
||||||
|
Ok(Box::new(File::create(file_path)?))
|
||||||
|
}
|
||||||
|
}
|
||||||
104
src/compression/program.rs
Normal file
104
src/compression/program.rs
Normal file
@@ -0,0 +1,104 @@
|
|||||||
|
use anyhow::{Context, Result, anyhow};
|
||||||
|
use std::fs::File;
|
||||||
|
use std::io::Write;
|
||||||
|
use std::process::{Command,Stdio};
|
||||||
|
use std::path::PathBuf;
|
||||||
|
use std::env;
|
||||||
|
use std::fs;
|
||||||
|
use std::os::unix::fs::PermissionsExt;
|
||||||
|
use log::*;
|
||||||
|
|
||||||
|
use crate::compression::CompressionEngine;
|
||||||
|
|
||||||
|
|
||||||
|
#[derive(Debug, Eq, PartialEq, Clone)]
|
||||||
|
pub struct CompressionProgram {
|
||||||
|
pub program: String,
|
||||||
|
pub compress: Vec<String>,
|
||||||
|
pub decompress: Vec<String>,
|
||||||
|
pub supported: bool
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
impl CompressionProgram {
|
||||||
|
pub fn new(program: &str, compress: Vec<&str>, decompress: Vec<&str>) -> CompressionProgram {
|
||||||
|
let program_path = get_program_path(program);
|
||||||
|
let supported = program_path.is_ok();
|
||||||
|
|
||||||
|
CompressionProgram {
|
||||||
|
program: program_path.unwrap_or(program.to_string()),
|
||||||
|
compress: compress.iter().map(|s| {s.to_string()}).collect(),
|
||||||
|
decompress: decompress.iter().map(|s| {s.to_string()}).collect(),
|
||||||
|
supported
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl CompressionEngine for CompressionProgram {
|
||||||
|
fn is_supported(&self) -> bool {
|
||||||
|
self.supported
|
||||||
|
}
|
||||||
|
|
||||||
|
fn cat(&self, file_path: PathBuf) -> Result<()> {
|
||||||
|
debug!("COMPRESSION: Outputting {:?} to STDOUT using {:?}", file_path, *self);
|
||||||
|
let program = self.program.clone();
|
||||||
|
let args = self.decompress.clone();
|
||||||
|
|
||||||
|
debug!("COMPRESSION: Executing command: {:?} {:?} writing to {:?}", program, args, file_path);
|
||||||
|
|
||||||
|
let file = File::open(file_path).context("Unable to open file for reading")?;
|
||||||
|
|
||||||
|
let mut process = Command::new(program.clone())
|
||||||
|
.args(args.clone())
|
||||||
|
.stdin(file)
|
||||||
|
.spawn()
|
||||||
|
.context(anyhow!("Unable to spawn child process: {:?} {:?}", program, args))?;
|
||||||
|
|
||||||
|
let result = process.wait()
|
||||||
|
.context(anyhow!("Unable to wait for child process: {:?} {:?}", program, args))?;
|
||||||
|
|
||||||
|
if result.success() {
|
||||||
|
Ok(())
|
||||||
|
} else {
|
||||||
|
Err(anyhow!("Decompression program returned {}", result))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
fn create(&self, file_path: PathBuf) -> Result<Box<dyn Write>> {
|
||||||
|
debug!("COMPRESSION: Writting to {:?} using {:?}", file_path, *self);
|
||||||
|
|
||||||
|
let program = self.program.clone();
|
||||||
|
let args = self.compress.clone();
|
||||||
|
|
||||||
|
debug!("COMPRESSION: Executing command: {:?} {:?} writing to {:?}", program, args, file_path);
|
||||||
|
|
||||||
|
let file = File::create(file_path).context("Unable to open file for writing")?;
|
||||||
|
|
||||||
|
let process = Command::new(program.clone())
|
||||||
|
.args(args.clone())
|
||||||
|
.stdin(Stdio::piped())
|
||||||
|
.stdout(file)
|
||||||
|
.spawn()
|
||||||
|
.context(anyhow!("Problem spawning child process: {:?} {:?}", program, args))?;
|
||||||
|
|
||||||
|
Ok(Box::new(process.stdin.unwrap()))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
fn get_program_path(program: &str) -> Result<String> {
|
||||||
|
debug!("COMPRESSION: Looking for executable: {}", program);
|
||||||
|
if let Ok(path) = env::var("PATH") {
|
||||||
|
for p in path.split(':') {
|
||||||
|
let p_str = format!("{}/{}", p, program);
|
||||||
|
let stat = fs::metadata(p_str.clone());
|
||||||
|
if let Ok(stat) = stat {
|
||||||
|
let md = stat;
|
||||||
|
let permissions = md.permissions();
|
||||||
|
if md.is_file() && permissions.mode() & 0o111 != 0 {
|
||||||
|
return Ok(p_str);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
Err(anyhow!("Unable to find binary {} in PATH", program))
|
||||||
|
}
|
||||||
@@ -29,10 +29,13 @@ use chrono::prelude::*;
|
|||||||
#[macro_use]
|
#[macro_use]
|
||||||
extern crate lazy_static;
|
extern crate lazy_static;
|
||||||
|
|
||||||
use crate::compression::CompressionType;
|
|
||||||
pub mod compression;
|
pub mod compression;
|
||||||
pub mod db;
|
pub mod db;
|
||||||
|
|
||||||
|
use compression::CompressionType;
|
||||||
|
use compression::program::CompressionProgram;
|
||||||
|
|
||||||
|
|
||||||
use humansize::{format_size, BINARY};
|
use humansize::{format_size, BINARY};
|
||||||
|
|
||||||
use is_terminal::IsTerminal;
|
use is_terminal::IsTerminal;
|
||||||
@@ -651,9 +654,9 @@ fn mode_status(_cmd: &mut Command, args: Args, data_path: PathBuf, db_path: Path
|
|||||||
};
|
};
|
||||||
|
|
||||||
for compression_type in CompressionType::iter() {
|
for compression_type in CompressionType::iter() {
|
||||||
let compression_program: compression::CompressionProgram = match &compression::COMPRESSION_PROGRAMS[compression_type.clone()] {
|
let compression_program: CompressionProgram = match &compression::COMPRESSION_PROGRAMS[compression_type.clone()] {
|
||||||
Some(compression_program) => compression_program.clone(),
|
Some(compression_program) => compression_program.clone(),
|
||||||
None => compression::CompressionProgram {
|
None => CompressionProgram {
|
||||||
program: "".to_string(),
|
program: "".to_string(),
|
||||||
compress: Vec::new(),
|
compress: Vec::new(),
|
||||||
decompress: Vec::new(),
|
decompress: Vec::new(),
|
||||||
|
|||||||
Reference in New Issue
Block a user