wasm_pack/
progressbar.rs

1//! Fancy progress bar functionality.
2
3use crate::emoji;
4use anyhow::{bail, Error, Result};
5use console::style;
6use std::sync::atomic::{AtomicBool, AtomicU8, Ordering};
7
8#[repr(u8)]
9#[derive(Debug, Clone, Copy)]
10/// The maximum log level for wasm-pack
11// The ordering is important: the least verbose must be at
12// the top and the most verbose at the bottom
13pub enum LogLevel {
14    /// Logs only error
15    Error,
16    /// Logs only warn and error
17    Warn,
18    /// Logs everything
19    Info,
20}
21
22impl std::str::FromStr for LogLevel {
23    type Err = Error;
24    fn from_str(s: &str) -> Result<Self> {
25        match s {
26            "error" => Ok(LogLevel::Error),
27            "warn" => Ok(LogLevel::Warn),
28            "info" => Ok(LogLevel::Info),
29            _ => bail!("Unknown log-level: {}", s),
30        }
31    }
32}
33
34/// Synchronized progress bar and status message printing.
35pub struct ProgressOutput {
36    quiet: AtomicBool,
37    log_level: AtomicU8,
38}
39
40impl ProgressOutput {
41    /// Returns a new ProgressOutput
42    pub const fn new() -> Self {
43        Self {
44            quiet: AtomicBool::new(false),
45            log_level: AtomicU8::new(LogLevel::Info as u8),
46        }
47    }
48
49    /// Print the given message.
50    fn message(&self, message: &str) {
51        eprintln!("{}", message);
52    }
53
54    /// Returns whether it should silence stdout or not
55    pub fn quiet(&self) -> bool {
56        self.quiet.load(Ordering::SeqCst)
57    }
58
59    /// Causes it to silence stdout
60    pub fn set_quiet(&self, quiet: bool) {
61        self.quiet.store(quiet, Ordering::SeqCst);
62    }
63
64    /// Returns whether the specified log level is enabled or not
65    pub fn is_log_enabled(&self, level: LogLevel) -> bool {
66        (level as u8) <= self.log_level.load(Ordering::SeqCst)
67    }
68
69    /// Sets the log level for wasm-pack
70    pub fn set_log_level(&self, log_level: LogLevel) {
71        self.log_level.store(log_level as u8, Ordering::SeqCst);
72    }
73
74    /// Add an informational message.
75    pub fn info(&self, message: &str) {
76        if !self.quiet() && self.is_log_enabled(LogLevel::Info) {
77            let info = format!("{}: {}", style("[INFO]").bold().dim(), message,);
78            self.message(&info);
79        }
80    }
81
82    /// Add a warning message.
83    pub fn warn(&self, message: &str) {
84        if !self.quiet() && self.is_log_enabled(LogLevel::Warn) {
85            let warn = format!(
86                "{}: {} {}",
87                style("[WARN]").bold().dim(),
88                emoji::WARN,
89                message
90            );
91            self.message(&warn);
92        }
93    }
94
95    /// Add an error message.
96    pub fn error(&self, message: &str) {
97        if self.is_log_enabled(LogLevel::Error) {
98            let err = format!(
99                "{}: {} {}",
100                style("[ERR]").bold().dim(),
101                emoji::ERROR,
102                message
103            );
104            self.message(&err);
105        }
106    }
107}
108
109impl Default for ProgressOutput {
110    fn default() -> Self {
111        ProgressOutput::new()
112    }
113}