tidepool_gvm/
progress_flat.rs1use std::io::{self, Write};
6
7#[derive(Clone)]
9pub struct BasicProgress {
10 label: String,
11 use_colors: bool,
12}
13
14impl BasicProgress {
15 pub fn new(label: String) -> Self {
17 let use_colors = Self::should_use_colors();
18 Self { label, use_colors }
19 }
20
21 fn should_use_colors() -> bool {
23 std::env::var("NO_COLOR").is_err() && std::env::var("TERM").unwrap_or_default() != "dumb"
24 }
25
26 pub fn show(&self, percent: f64, info: Option<&str>) {
28 let bar_width = 50;
29 let filled = (percent * bar_width as f64) as usize;
30 let empty = bar_width - filled;
31
32 let bar = format!("{}{}", "=".repeat(filled), " ".repeat(empty));
34
35 let info_text = info.unwrap_or("");
36
37 print!("\r{} [{}] {:.0}% {}", self.label, bar, percent * 100.0, info_text);
39
40 io::stdout().flush().ok();
41 }
42
43 pub fn show_download(&self, downloaded: u64, total: u64) {
45 let percent = if total > 0 { downloaded as f64 / total as f64 } else { 0.0 };
46 let info = if total > 0 {
47 format!("{}/{}", format_size(downloaded), format_size(total))
48 } else {
49 format_size(downloaded)
50 };
51 self.show(percent, Some(&info));
52 }
53
54 pub fn done(&self, message: &str) {
56 println!();
57 if self.use_colors {
58 println!("{message} ... \x1b[32mdone\x1b[0m.");
59 } else {
60 println!("{message} ... done.");
61 }
62 }
63
64 pub fn failed(&self, message: &str) {
66 println!();
67 if self.use_colors {
68 println!("{message} ... \x1b[31mfailed\x1b[0m.");
69 } else {
70 println!("{message} ... failed.");
71 }
72 }
73}
74
75pub struct InstallSteps {
77 use_colors: bool,
78}
79
80impl Default for InstallSteps {
81 fn default() -> Self {
82 Self::new()
83 }
84}
85
86impl InstallSteps {
87 pub fn new() -> Self {
88 let use_colors = std::env::var("NO_COLOR").is_err()
89 && std::env::var("TERM").unwrap_or_default() != "dumb";
90 Self { use_colors }
91 }
92
93 pub fn start(&self, version: &str) {
95 if self.use_colors {
96 println!("\x1b[36mInstalling 'go' ({version}) [64bit] from 'workspace'\x1b[0m");
97 } else {
98 println!("Installing 'go' ({version}) [64bit] from 'workspace'");
99 }
100 }
101
102 pub fn info(&self, message: &str) {
104 if self.use_colors {
105 println!("\x1b[90m{message}\x1b[0m");
106 } else {
107 println!("{message}");
108 }
109 }
110
111 pub fn warn(&self, message: &str) {
113 if self.use_colors {
114 println!("\x1b[33mWARN\x1b[0m {message}");
115 } else {
116 println!("WARN {message}");
117 }
118 }
119
120 pub fn complete(&self, version: &str) {
122 if self.use_colors {
123 println!("\x1b[32m'go' ({version}) was installed successfully!\x1b[0m");
124 } else {
125 println!("'go' ({version}) was installed successfully!");
126 }
127 }
128}
129
130fn format_size(bytes: u64) -> String {
132 const UNITS: &[&str] = &["B", "KB", "MB", "GB"];
133 let mut size = bytes as f64;
134 let mut unit_index = 0;
135
136 while size >= 1024.0 && unit_index < UNITS.len() - 1 {
137 size /= 1024.0;
138 unit_index += 1;
139 }
140
141 if unit_index == 0 {
142 format!("{bytes} {}", UNITS[unit_index])
143 } else {
144 format!("{size:.1}{}", UNITS[unit_index])
145 }
146}
147
148#[cfg(test)]
149mod tests {
150 use super::*;
151
152 #[test]
153 fn test_format_size() {
154 assert_eq!(format_size(1024), "1.0KB");
155 assert_eq!(format_size(1048576), "1.0MB");
156 assert_eq!(format_size(500), "500 B");
157 }
158
159 #[test]
160 fn test_basic_progress_creation() {
161 let progress = BasicProgress::new("Testing".to_string());
162 assert_eq!(progress.label, "Testing");
163 }
164}