summaryrefslogtreecommitdiff
path: root/cli/util/progress_bar.rs
diff options
context:
space:
mode:
Diffstat (limited to 'cli/util/progress_bar.rs')
-rw-r--r--cli/util/progress_bar.rs143
1 files changed, 143 insertions, 0 deletions
diff --git a/cli/util/progress_bar.rs b/cli/util/progress_bar.rs
new file mode 100644
index 000000000..5b49fb279
--- /dev/null
+++ b/cli/util/progress_bar.rs
@@ -0,0 +1,143 @@
+// Copyright 2018-2022 the Deno authors. All rights reserved. MIT license.
+
+use crate::colors;
+use deno_core::parking_lot::Mutex;
+use indexmap::IndexSet;
+use std::sync::Arc;
+use std::time::Duration;
+
+#[derive(Clone, Debug, Default)]
+pub struct ProgressBar(Arc<Mutex<ProgressBarInner>>);
+
+#[derive(Debug)]
+struct ProgressBarInner {
+ pb: Option<indicatif::ProgressBar>,
+ is_tty: bool,
+ in_flight: IndexSet<String>,
+}
+
+impl Default for ProgressBarInner {
+ fn default() -> Self {
+ Self {
+ pb: None,
+ is_tty: colors::is_tty(),
+ in_flight: IndexSet::default(),
+ }
+ }
+}
+
+impl ProgressBarInner {
+ fn get_or_create_pb(&mut self) -> indicatif::ProgressBar {
+ if let Some(pb) = self.pb.as_ref() {
+ return pb.clone();
+ }
+
+ let pb = indicatif::ProgressBar::new_spinner();
+ pb.enable_steady_tick(Duration::from_millis(120));
+ pb.set_prefix("Download");
+ pb.set_style(
+ indicatif::ProgressStyle::with_template(
+ "{prefix:.green} {spinner:.green} {msg}",
+ )
+ .unwrap()
+ .tick_strings(&["⠋", "⠙", "⠹", "⠸", "⠼", "⠴", "⠦", "⠧", "⠇", "⠏"]),
+ );
+ self.pb = Some(pb);
+ self.pb.as_ref().unwrap().clone()
+ }
+
+ fn add_in_flight(&mut self, msg: &str) {
+ if self.in_flight.contains(msg) {
+ return;
+ }
+
+ self.in_flight.insert(msg.to_string());
+ }
+
+ /// Returns if removed "in-flight" was last entry and progress
+ /// bar needs to be updated.
+ fn remove_in_flight(&mut self, msg: &str) -> bool {
+ if !self.in_flight.contains(msg) {
+ return false;
+ }
+
+ let mut is_last = false;
+ if let Some(last) = self.in_flight.last() {
+ is_last = last == msg;
+ }
+ self.in_flight.remove(msg);
+ is_last
+ }
+
+ fn update_progress_bar(&mut self) {
+ let pb = self.get_or_create_pb();
+ if let Some(msg) = self.in_flight.last() {
+ pb.set_message(msg.clone());
+ }
+ }
+}
+
+pub struct UpdateGuard {
+ pb: ProgressBar,
+ msg: String,
+ noop: bool,
+}
+
+impl Drop for UpdateGuard {
+ fn drop(&mut self) {
+ if self.noop {
+ return;
+ }
+
+ let mut inner = self.pb.0.lock();
+ if inner.remove_in_flight(&self.msg) {
+ inner.update_progress_bar();
+ }
+ }
+}
+
+impl ProgressBar {
+ pub fn update(&self, msg: &str) -> UpdateGuard {
+ let mut guard = UpdateGuard {
+ pb: self.clone(),
+ msg: msg.to_string(),
+ noop: false,
+ };
+ let mut inner = self.0.lock();
+
+ // If we're not running in TTY we're just gonna fallback
+ // to using logger crate.
+ if !inner.is_tty {
+ log::log!(log::Level::Info, "{} {}", colors::green("Download"), msg);
+ guard.noop = true;
+ return guard;
+ }
+
+ inner.add_in_flight(msg);
+ inner.update_progress_bar();
+ guard
+ }
+
+ pub fn clear(&self) {
+ let mut inner = self.0.lock();
+
+ if let Some(pb) = inner.pb.as_ref() {
+ pb.finish_and_clear();
+ inner.pb = None;
+ }
+ }
+
+ pub fn clear_guard(&self) -> ClearGuard {
+ ClearGuard { pb: self.clone() }
+ }
+}
+
+pub struct ClearGuard {
+ pb: ProgressBar,
+}
+
+impl Drop for ClearGuard {
+ fn drop(&mut self) {
+ self.pb.clear();
+ }
+}