this repo has no description
0
fork

Configure Feed

Select the types of activity you want to include in your feed.

at d3807962cbbaf22fd7cefbdbbdc9f641519931df 123 lines 3.8 kB view raw
1use crate::utils::*; 2use bzip2::write::{BzDecoder, BzEncoder}; 3use bzip2::Compression; 4use clap::Args; 5use std::{ 6 fs::File, 7 io::{self, Read, Write}, 8}; 9 10#[derive(Args, Debug)] 11pub struct Bzip2Args { 12 #[clap(flatten)] 13 pub common_args: CommonArgs, 14 15 #[clap(flatten)] 16 pub level_args: LevelArgs, 17} 18 19pub struct Bzip2 { 20 pub level: u32, // 0-9 21} 22 23impl Default for Bzip2 { 24 fn default() -> Self { 25 Bzip2 { level: 6 } 26 } 27} 28 29impl Bzip2 { 30 pub fn new(args: &Bzip2Args) -> Self { 31 Bzip2 { 32 level: args.level_args.level.level, 33 } 34 } 35} 36 37impl Compressor for Bzip2 { 38 /// The standard extension for the bz2 format. 39 fn extension(&self) -> &str { 40 "bz2" 41 } 42 43 /// Full name for bz2. 44 fn name(&self) -> &str { 45 "bzip2" 46 } 47 48 /// Compress an input file or pipe to a bz2 archive 49 fn compress(&self, input: CmprssInput, output: CmprssOutput) -> Result<(), io::Error> { 50 let mut input_stream = match input { 51 CmprssInput::Path(paths) => { 52 if paths.len() > 1 { 53 return cmprss_error("only 1 file can be compressed at a time"); 54 } 55 Box::new(File::open(paths[0].as_path())?) 56 } 57 CmprssInput::Pipe(pipe) => Box::new(pipe) as Box<dyn Read + Send>, 58 }; 59 let output_stream: Box<dyn Write + Send> = match output { 60 CmprssOutput::Path(path) => Box::new(File::create(path)?), 61 CmprssOutput::Pipe(pipe) => Box::new(pipe) as Box<dyn Write + Send>, 62 }; 63 let mut encoder = BzEncoder::new(output_stream, Compression::new(self.level)); 64 io::copy(&mut input_stream, &mut encoder)?; 65 Ok(()) 66 } 67 68 /// Extract a bz2 archive to a file or pipe 69 fn extract(&self, input: CmprssInput, output: CmprssOutput) -> Result<(), io::Error> { 70 let mut input_stream = match input { 71 CmprssInput::Path(paths) => { 72 if paths.len() > 1 { 73 return cmprss_error("only 1 file can be extracted at a time"); 74 } 75 Box::new(File::open(paths[0].as_path())?) 76 } 77 CmprssInput::Pipe(pipe) => Box::new(pipe) as Box<dyn Read + Send>, 78 }; 79 let output_stream: Box<dyn Write + Send> = match output { 80 CmprssOutput::Path(path) => Box::new(File::create(path)?), 81 CmprssOutput::Pipe(pipe) => Box::new(pipe) as Box<dyn Write + Send>, 82 }; 83 let mut decoder = BzDecoder::new(output_stream); 84 io::copy(&mut input_stream, &mut decoder)?; 85 Ok(()) 86 } 87} 88 89#[cfg(test)] 90mod tests { 91 use super::*; 92 use assert_fs::prelude::*; 93 use predicates::prelude::*; 94 95 #[test] 96 fn roundtrip() -> Result<(), Box<dyn std::error::Error>> { 97 let compressor = Bzip2::default(); 98 99 let file = assert_fs::NamedTempFile::new("test.txt")?; 100 file.write_str("garbage data for testing")?; 101 let working_dir = assert_fs::TempDir::new()?; 102 let archive = working_dir.child("archive.".to_owned() + compressor.extension()); 103 archive.assert(predicate::path::missing()); 104 105 // Roundtrip compress/extract 106 compressor.compress( 107 CmprssInput::Path(vec![file.path().to_path_buf()]), 108 CmprssOutput::Path(archive.path().to_path_buf()), 109 )?; 110 archive.assert(predicate::path::is_file()); 111 compressor.extract( 112 CmprssInput::Path(vec![archive.path().to_path_buf()]), 113 CmprssOutput::Path(working_dir.child("test.txt").path().to_path_buf()), 114 )?; 115 116 // Assert the files are identical 117 working_dir 118 .child("test.txt") 119 .assert(predicate::path::eq_file(file.path())); 120 121 Ok(()) 122 } 123}