rustfs_cli/output/
progress.rs

1//! Progress bar utilities for transfer operations
2//!
3//! Provides consistent progress indication for long-running operations
4//! like file transfers and sync operations.
5
6use super::OutputConfig;
7
8/// Progress bar wrapper
9///
10/// Handles progress display based on output configuration.
11/// In quiet or JSON mode, progress is suppressed.
12#[derive(Debug)]
13#[allow(dead_code)]
14pub struct ProgressBar {
15    config: OutputConfig,
16    bar: Option<indicatif::ProgressBar>,
17}
18
19#[allow(dead_code)]
20impl ProgressBar {
21    /// Create a new progress bar with the given total size
22    pub fn new(config: OutputConfig, total: u64) -> Self {
23        let bar = if config.quiet || config.json || config.no_progress {
24            None
25        } else {
26            let bar = indicatif::ProgressBar::new(total);
27            bar.set_style(
28                indicatif::ProgressStyle::default_bar()
29                    .template("{spinner:.green} [{bar:40.cyan/blue}] {bytes}/{total_bytes} ({eta})")
30                    .expect("valid template")
31                    .progress_chars("#>-"),
32            );
33            Some(bar)
34        };
35
36        Self { config, bar }
37    }
38
39    /// Create a spinner for indeterminate progress
40    pub fn spinner(config: OutputConfig, message: &str) -> Self {
41        let bar = if config.quiet || config.json || config.no_progress {
42            None
43        } else {
44            let bar = indicatif::ProgressBar::new_spinner();
45            bar.set_style(
46                indicatif::ProgressStyle::default_spinner()
47                    .template("{spinner:.green} {msg}")
48                    .expect("valid template"),
49            );
50            bar.set_message(message.to_string());
51            bar.enable_steady_tick(std::time::Duration::from_millis(100));
52            Some(bar)
53        };
54
55        Self { config, bar }
56    }
57
58    /// Update progress
59    pub fn set_position(&self, pos: u64) {
60        if let Some(bar) = &self.bar {
61            bar.set_position(pos);
62        }
63    }
64
65    /// Increment progress
66    pub fn inc(&self, delta: u64) {
67        if let Some(bar) = &self.bar {
68            bar.inc(delta);
69        }
70    }
71
72    /// Set message
73    pub fn set_message(&self, message: &str) {
74        if let Some(bar) = &self.bar {
75            bar.set_message(message.to_string());
76        }
77    }
78
79    /// Finish with a message
80    pub fn finish_with_message(&self, message: &str) {
81        if let Some(bar) = &self.bar {
82            bar.finish_with_message(message.to_string());
83        }
84    }
85
86    /// Finish and clear the progress bar
87    pub fn finish_and_clear(&self) {
88        if let Some(bar) = &self.bar {
89            bar.finish_and_clear();
90        }
91    }
92
93    /// Check if progress bar is visible
94    pub fn is_visible(&self) -> bool {
95        self.bar.is_some()
96    }
97}
98
99#[cfg(test)]
100mod tests {
101    use super::*;
102
103    #[test]
104    fn test_progress_bar_quiet_mode() {
105        let config = OutputConfig {
106            quiet: true,
107            ..Default::default()
108        };
109        let bar = ProgressBar::new(config, 100);
110        assert!(!bar.is_visible());
111    }
112
113    #[test]
114    fn test_progress_bar_json_mode() {
115        let config = OutputConfig {
116            json: true,
117            ..Default::default()
118        };
119        let bar = ProgressBar::new(config, 100);
120        assert!(!bar.is_visible());
121    }
122
123    #[test]
124    fn test_progress_bar_no_progress() {
125        let config = OutputConfig {
126            no_progress: true,
127            ..Default::default()
128        };
129        let bar = ProgressBar::new(config, 100);
130        assert!(!bar.is_visible());
131    }
132
133    #[test]
134    fn test_progress_bar_normal() {
135        let config = OutputConfig::default();
136        let bar = ProgressBar::new(config, 100);
137        assert!(bar.is_visible());
138    }
139}