this repo has no description
0
fork

Configure Feed

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

at d3807962cbbaf22fd7cefbdbbdc9f641519931df 133 lines 3.7 kB view raw
1use crate::utils::CmprssOutput; 2use clap::Args; 3use indicatif::{HumanBytes, ProgressBar}; 4use std::str::FromStr; 5 6#[derive(clap::ValueEnum, Clone, Copy, Debug, Default)] 7pub enum ProgressDisplay { 8 #[default] 9 Auto, 10 On, 11 Off, 12} 13 14#[derive(Debug, Clone, Copy)] 15pub struct ChunkSize { 16 pub size_in_bytes: usize, 17} 18 19impl Default for ChunkSize { 20 fn default() -> Self { 21 ChunkSize { 22 size_in_bytes: 8192, 23 } 24 } 25} 26 27impl FromStr for ChunkSize { 28 type Err = &'static str; 29 30 fn from_str(s: &str) -> Result<Self, Self::Err> { 31 // Try to parse s as just a number 32 if let Ok(num) = s.parse::<usize>() { 33 if num == 0 { 34 return Err("Invalid number"); 35 } 36 return Ok(ChunkSize { size_in_bytes: num }); 37 } 38 // Simplify so that we always assume base 2, regardless of whether we see 39 // 'kb' or 'kib' 40 let mut s = s.to_lowercase(); 41 if s.ends_with("ib") { 42 s.truncate(s.len() - 2); 43 s.push('b'); 44 }; 45 let (num_str, unit) = s.split_at(s.len() - 2); 46 let num = num_str.parse::<usize>().map_err(|_| "Invalid number")?; 47 48 let size_in_bytes = match unit { 49 "kb" => num * 1024, 50 "mb" => num * 1024 * 1024, 51 "gb" => num * 1024 * 1024 * 1024, 52 _ => return Err("Invalid unit"), 53 }; 54 if size_in_bytes == 0 { 55 return Err("Invalid number"); 56 } 57 58 Ok(ChunkSize { size_in_bytes }) 59 } 60} 61 62#[derive(Args, Debug, Default, Clone, Copy)] 63pub struct ProgressArgs { 64 /// Show progress. 65 #[arg(long, value_enum, default_value = "auto")] 66 pub progress: ProgressDisplay, 67 68 /// Chunk size to use during the copy when showing the progress bar. 69 #[arg(long, default_value = "8kib")] 70 pub chunk_size: ChunkSize, 71} 72 73/// Progress bar for the compress process 74pub struct Progress { 75 /// The progress bar 76 bar: ProgressBar, 77 /// The number of bytes read from the input 78 input_read: u64, 79 /// The number of bytes written to the output 80 output_written: u64, 81} 82 83/// Create a progress bar if necessary 84pub fn progress_bar( 85 input_size: Option<u64>, 86 progress: ProgressDisplay, 87 output: &CmprssOutput, 88) -> Option<Progress> { 89 match (progress, output) { 90 (ProgressDisplay::Auto, CmprssOutput::Pipe(_)) => None, 91 (ProgressDisplay::Off, _) => None, 92 (_, _) => Some(Progress::new(input_size)), 93 } 94} 95 96impl Progress { 97 /// Create a new progress bar 98 /// Draws to stderr by default 99 pub fn new(input_size: Option<u64>) -> Self { 100 let bar = match input_size { 101 Some(size) => ProgressBar::new(size), 102 None => ProgressBar::new_spinner(), 103 }; 104 bar.set_style( 105 indicatif::ProgressStyle::default_bar() 106 .template("{spinner:.green} [{elapsed_precise}] ({eta}) [{bar:40.cyan/blue}] {bytes}/{total_bytes} => {msg}").unwrap() 107 .progress_chars("#>-"), 108 ); 109 Progress { 110 bar, 111 input_read: 0, 112 output_written: 0, 113 } 114 } 115 116 /// Update the progress bar with the number of bytes read from the input 117 pub fn update_input(&mut self, bytes_read: u64) { 118 self.input_read = bytes_read; 119 self.bar.set_position(self.input_read); 120 } 121 122 /// Update the progress bar with the number of bytes written to the output 123 pub fn update_output(&mut self, bytes_written: u64) { 124 self.output_written = bytes_written; 125 self.bar 126 .set_message(HumanBytes(self.output_written).to_string()); 127 } 128 129 /// Finish the progress bar 130 pub fn finish(&self) { 131 self.bar.finish(); 132 } 133}