History

implement progress trait for logs with throttling

Sebastian Thiel committed 6 years ago

Commit 287eca91 parent e82e63f5 files · +121 −6Browse files

Showing the changes to git-features/src (1 of 5 files). Show all

Unified · Split

git-features/src/progress.rs+103−5
@@ -1,8 +1,21 @@
1/// The severity of a message
2#[derive(Debug, Copy, Clone, Eq, PartialEq, Ord, PartialOrd)]
3pub enum MessageLevel {
4 /// Rarely sent information related to the progress, not to be confused with the progress itself
5 Info,
6 /// Used to indicate that a task has failed, along with the reason
7 Failure,
8 /// Indicates a task was completed successfully
9 Success,
10}
11
1pub trait Progress {12pub trait Progress {
13 type SubProgress: Progress;
14
2 /// Adds a new child, whose parent is this instance, with the given name.15 /// Adds a new child, whose parent is this instance, with the given name.
3 ///16 ///
4 /// This will make the child progress to appear contained in the parent progress.17 /// This will make the child progress to appear contained in the parent progress.
5 fn add_child(&self, name: impl Into<String>) -> Self;18 fn add_child(&mut self, name: impl Into<String>) -> Self::SubProgress;
6 19
7 /// Initialize the Item for receiving progress information.20 /// Initialize the Item for receiving progress information.
8 ///21 ///
@@ -19,15 +32,100 @@ pub trait Progress { · 10 unmodified lines
19 /// **Note** that this method can be called multiple times, changing the bounded-ness and unit at will.32 /// **Note** that this method can be called multiple times, changing the bounded-ness and unit at will.
20 fn init(&mut self, max: Option<u32>, unit: Option<&'static str>);33 fn init(&mut self, max: Option<u32>, unit: Option<&'static str>);
21 34
22 /// Set the current progress to the given `step`.35 /// Set the current progress to the given `step`. The cost of this call is negligible,
36 /// making manual throttling *not* necessary.
23 ///37 ///
24 /// **Note**: that this call has no effect unless `init(…)` was called before.38 /// **Note**: that this call has no effect unless `init(…)` was called before.
25 fn set(&mut self, step: u32);39 fn set(&mut self, step: u32);
26 40
41 /// Create a `message` of the given `level` and store it with the progress tree.
42 ///
43 /// Use this to provide additional,human-readable information about the progress
44 /// made, including indicating success or failure.
45 fn message(&self, level: MessageLevel, message: impl Into<String>);
46
27 /// Create a message providing additional information about the progress thus far.47 /// Create a message providing additional information about the progress thus far.
28 fn info(&self, name: impl Into<String>) -> Self;48 fn info(&self, message: impl Into<String>) {
49 self.message(MessageLevel::Info, message)
50 }
29 /// Create a message indicating the task is done successfully51 /// Create a message indicating the task is done successfully
30 fn done(&self, name: impl Into<String>) -> Self;52 fn done(&self, message: impl Into<String>) {
53 self.message(MessageLevel::Success, message)
54 }
31 /// Create a message indicating the task failed55 /// Create a message indicating the task failed
32 fn fail(&self, name: impl Into<String>) -> Self;56 fn fail(&self, message: impl Into<String>) {
57 self.message(MessageLevel::Failure, message)
58 }
59}
60
61#[cfg(feature = "progress-log")]
62mod log {
63 use crate::progress::{MessageLevel, Progress};
64 use std::time::Duration;
65
66 pub struct LogProgress {
67 name: String,
68 max: Option<u32>,
69 unit: Option<&'static str>,
70 last_set: Option<std::time::SystemTime>,
71 }
72
73 const EMIT_LOG_EVERY_S: f32 = 0.5;
74
75 impl LogProgress {
76 pub fn new(name: impl Into<String>) -> Self {
77 LogProgress {
78 name: name.into(),
79 max: None,
80 unit: None,
81 last_set: None,
82 }
83 }
84 }
85
86 impl Progress for LogProgress {
87 type SubProgress = LogProgress;
88
89 fn add_child(&mut self, name: impl Into<String>) -> Self::SubProgress {
90 LogProgress::new(format!("{}::{}", self.name, Into::<String>::into(name)))
91 }
92
93 fn init(&mut self, max: Option<u32>, unit: Option<&'static str>) {
94 self.max = max;
95 self.unit = unit;
96 }
97
98 fn set(&mut self, step: u32) {
99 let now = std::time::SystemTime::now();
100 let last = self.last_set.unwrap_or(now);
101 if now
102 .duration_since(last)
103 .unwrap_or_else(|_| Duration::default())
104 .as_secs_f32()
105 > EMIT_LOG_EVERY_S
106 {
107 match (self.max, self.unit) {
108 (Some(max), Some(unit)) => {
109 log::info!("{} → {} / {} {}", self.name, step, max, unit)
110 }
111 (None, Some(unit)) => log::info!("{} → {} {}", self.name, step, unit),
112 (Some(max), None) => log::info!("{} → {} / {}", self.name, step, max),
113 (None, None) => log::info!("{} → {}", self.name, step),
114 }
115 }
116 self.last_set = Some(now);
117 }
118
119 fn message(&self, level: MessageLevel, message: impl Into<String>) {
120 let message: String = message.into();
121 match level {
122 MessageLevel::Info => log::info!("ℹ{} → {}", self.name, message),
123 MessageLevel::Failure => log::error!("𐄂{} → {}", self.name, message),
124 MessageLevel::Success => log::info!("✓{} → {}", self.name, message),
125 }
126 }
127 }
33}128}
129
130#[cfg(feature = "progress-log")]
131pub use self::log::LogProgress;