this repo has no description
0
fork

Configure Feed

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

at d7eac9681af468ef2dd62f00e8a09e36cf744585 178 lines 5.4 kB view raw
1use crate::{ 2 progress::{ProgressArgs, copy_with_progress}, 3 utils::*, 4}; 5use anyhow::bail; 6use clap::Args; 7use std::{ 8 fs::File, 9 io::{self, BufReader, BufWriter, Read, Write}, 10}; 11use xz2::read::XzDecoder; 12use xz2::write::XzEncoder; 13 14#[derive(Args, Debug)] 15pub struct XzArgs { 16 #[clap(flatten)] 17 pub common_args: CommonArgs, 18 19 #[clap(flatten)] 20 progress_args: ProgressArgs, 21 22 #[clap(flatten)] 23 pub level_args: LevelArgs, 24} 25 26pub struct Xz { 27 pub level: i32, 28 pub progress_args: ProgressArgs, 29} 30 31impl Default for Xz { 32 fn default() -> Self { 33 let validator = DefaultCompressionValidator; 34 Xz { 35 level: validator.default_level(), 36 progress_args: ProgressArgs::default(), 37 } 38 } 39} 40 41impl Xz { 42 pub fn new(args: &XzArgs) -> Xz { 43 let validator = DefaultCompressionValidator; 44 let level = validator.validate_and_clamp_level(args.level_args.level.level); 45 46 Xz { 47 level, 48 progress_args: args.progress_args, 49 } 50 } 51} 52 53impl Compressor for Xz { 54 /// The standard extension for the xz format. 55 fn extension(&self) -> &str { 56 "xz" 57 } 58 59 /// Full name for xz. 60 fn name(&self) -> &str { 61 "xz" 62 } 63 64 fn compress(&self, input: CmprssInput, output: CmprssOutput) -> Result { 65 let mut file_size = None; 66 let mut input_stream = match input { 67 CmprssInput::Path(paths) => { 68 if paths.len() > 1 { 69 bail!("Multiple input files not supported for xz"); 70 } 71 let path = &paths[0]; 72 file_size = Some(std::fs::metadata(path)?.len()); 73 Box::new(BufReader::new(File::open(path)?)) as Box<dyn Read + Send> 74 } 75 CmprssInput::Pipe(pipe) => Box::new(pipe) as Box<dyn Read + Send>, 76 CmprssInput::Reader(reader) => reader.0, 77 }; 78 if let CmprssOutput::Writer(writer) = output { 79 let mut encoder = XzEncoder::new(writer, self.level as u32); 80 io::copy(&mut input_stream, &mut encoder)?; 81 encoder.finish()?; 82 } else { 83 let output_stream: Box<dyn Write + Send> = match &output { 84 CmprssOutput::Path(path) => Box::new(BufWriter::new(File::create(path)?)), 85 CmprssOutput::Pipe(pipe) => Box::new(pipe) as Box<dyn Write + Send>, 86 CmprssOutput::Writer(_) => unreachable!(), 87 }; 88 let mut encoder = XzEncoder::new(output_stream, self.level as u32); 89 copy_with_progress( 90 &mut input_stream, 91 &mut encoder, 92 self.progress_args.chunk_size.size_in_bytes, 93 file_size, 94 self.progress_args.progress, 95 &output, 96 )?; 97 } 98 99 Ok(()) 100 } 101 102 fn extract(&self, input: CmprssInput, output: CmprssOutput) -> Result { 103 let mut file_size = None; 104 let input_stream: Box<dyn Read + Send> = match input { 105 CmprssInput::Path(paths) => { 106 if paths.len() > 1 { 107 bail!("Multiple input files not supported for xz extraction"); 108 } 109 let path = &paths[0]; 110 file_size = Some(std::fs::metadata(path)?.len()); 111 Box::new(BufReader::new(File::open(path)?)) as Box<dyn Read + Send> 112 } 113 CmprssInput::Pipe(pipe) => Box::new(pipe) as Box<dyn Read + Send>, 114 CmprssInput::Reader(reader) => reader.0, 115 }; 116 let mut decoder = XzDecoder::new(input_stream); 117 118 if let CmprssOutput::Writer(mut writer) = output { 119 io::copy(&mut decoder, &mut writer)?; 120 } else { 121 let mut output_stream: Box<dyn Write + Send> = match &output { 122 CmprssOutput::Path(path) => Box::new(BufWriter::new(File::create(path)?)), 123 CmprssOutput::Pipe(pipe) => Box::new(pipe) as Box<dyn Write + Send>, 124 CmprssOutput::Writer(_) => unreachable!(), 125 }; 126 copy_with_progress( 127 &mut decoder, 128 &mut *output_stream, 129 self.progress_args.chunk_size.size_in_bytes, 130 file_size, 131 self.progress_args.progress, 132 &output, 133 )?; 134 } 135 136 Ok(()) 137 } 138} 139 140#[cfg(test)] 141mod tests { 142 use super::*; 143 use crate::test_utils::*; 144 145 /// Test the basic interface of the Xz compressor 146 #[test] 147 fn test_xz_interface() { 148 let compressor = Xz::default(); 149 test_compressor_interface(&compressor, "xz", Some("xz")); 150 } 151 152 /// Test the default compression level 153 #[test] 154 fn test_xz_default_compression() -> Result { 155 let compressor = Xz::default(); 156 test_compression(&compressor) 157 } 158 159 /// Test fast compression level 160 #[test] 161 fn test_xz_fast_compression() -> Result { 162 let fast_compressor = Xz { 163 level: 1, 164 progress_args: ProgressArgs::default(), 165 }; 166 test_compression(&fast_compressor) 167 } 168 169 /// Test best compression level 170 #[test] 171 fn test_xz_best_compression() -> Result { 172 let best_compressor = Xz { 173 level: 9, 174 progress_args: ProgressArgs::default(), 175 }; 176 test_compression(&best_compressor) 177 } 178}