rust/hg-core/src/progress.rs
author Rapha?l Gom?s <rgomes@octobus.net>
Tue, 05 Nov 2024 15:21:09 +0100
branchstable
changeset 52186 e6a44bc91bc2
parent 52038 92e23ba257d1
child 52306 a876ab6c3fd5
permissions -rw-r--r--
rust-update: make `update_from_null` respect `worker.numcpu` config option This was overlooked in the original series. This is important for tests (because we run many at once), and for the occasional end user that wants to keep their CPU usage in check. A future series should clean up this `worker` parameter tunelling business by rewriting the config in Rust, but doing so on stable would be a very bad idea.
Ignore whitespace changes - Everywhere: Within whitespace: At end of lines:
52037
3ae7c43ad8aa rust: add `Progress` trait for progress bars
Rapha?l Gom?s <rgomes@octobus.net>
parents:
diff changeset
     1
//! Progress-bar related things
3ae7c43ad8aa rust: add `Progress` trait for progress bars
Rapha?l Gom?s <rgomes@octobus.net>
parents:
diff changeset
     2
52038
92e23ba257d1 rust-hg-cpython: add an `HgProgressBar` util
Rapha?l Gom?s <rgomes@octobus.net>
parents: 52037
diff changeset
     3
use std::{
92e23ba257d1 rust-hg-cpython: add an `HgProgressBar` util
Rapha?l Gom?s <rgomes@octobus.net>
parents: 52037
diff changeset
     4
    sync::atomic::{AtomicBool, Ordering},
92e23ba257d1 rust-hg-cpython: add an `HgProgressBar` util
Rapha?l Gom?s <rgomes@octobus.net>
parents: 52037
diff changeset
     5
    time::Duration,
92e23ba257d1 rust-hg-cpython: add an `HgProgressBar` util
Rapha?l Gom?s <rgomes@octobus.net>
parents: 52037
diff changeset
     6
};
92e23ba257d1 rust-hg-cpython: add an `HgProgressBar` util
Rapha?l Gom?s <rgomes@octobus.net>
parents: 52037
diff changeset
     7
92e23ba257d1 rust-hg-cpython: add an `HgProgressBar` util
Rapha?l Gom?s <rgomes@octobus.net>
parents: 52037
diff changeset
     8
use indicatif::{ProgressBar, ProgressDrawTarget, ProgressStyle};
92e23ba257d1 rust-hg-cpython: add an `HgProgressBar` util
Rapha?l Gom?s <rgomes@octobus.net>
parents: 52037
diff changeset
     9
52037
3ae7c43ad8aa rust: add `Progress` trait for progress bars
Rapha?l Gom?s <rgomes@octobus.net>
parents:
diff changeset
    10
/// A generic determinate progress bar trait
3ae7c43ad8aa rust: add `Progress` trait for progress bars
Rapha?l Gom?s <rgomes@octobus.net>
parents:
diff changeset
    11
pub trait Progress: Send + Sync + 'static {
3ae7c43ad8aa rust: add `Progress` trait for progress bars
Rapha?l Gom?s <rgomes@octobus.net>
parents:
diff changeset
    12
    /// Set the current position and optionally the total
3ae7c43ad8aa rust: add `Progress` trait for progress bars
Rapha?l Gom?s <rgomes@octobus.net>
parents:
diff changeset
    13
    fn update(&self, pos: u64, total: Option<u64>);
3ae7c43ad8aa rust: add `Progress` trait for progress bars
Rapha?l Gom?s <rgomes@octobus.net>
parents:
diff changeset
    14
    /// Increment the current position and optionally the total
3ae7c43ad8aa rust: add `Progress` trait for progress bars
Rapha?l Gom?s <rgomes@octobus.net>
parents:
diff changeset
    15
    fn increment(&self, step: u64, total: Option<u64>);
3ae7c43ad8aa rust: add `Progress` trait for progress bars
Rapha?l Gom?s <rgomes@octobus.net>
parents:
diff changeset
    16
    /// Declare that progress is over and the progress bar should be deleted
3ae7c43ad8aa rust: add `Progress` trait for progress bars
Rapha?l Gom?s <rgomes@octobus.net>
parents:
diff changeset
    17
    fn complete(self);
3ae7c43ad8aa rust: add `Progress` trait for progress bars
Rapha?l Gom?s <rgomes@octobus.net>
parents:
diff changeset
    18
}
52038
92e23ba257d1 rust-hg-cpython: add an `HgProgressBar` util
Rapha?l Gom?s <rgomes@octobus.net>
parents: 52037
diff changeset
    19
92e23ba257d1 rust-hg-cpython: add an `HgProgressBar` util
Rapha?l Gom?s <rgomes@octobus.net>
parents: 52037
diff changeset
    20
const PROGRESS_DELAY: Duration = Duration::from_secs(1);
92e23ba257d1 rust-hg-cpython: add an `HgProgressBar` util
Rapha?l Gom?s <rgomes@octobus.net>
parents: 52037
diff changeset
    21
92e23ba257d1 rust-hg-cpython: add an `HgProgressBar` util
Rapha?l Gom?s <rgomes@octobus.net>
parents: 52037
diff changeset
    22
/// A generic (determinate) progress bar. Stays hidden until [`PROGRESS_DELAY`]
92e23ba257d1 rust-hg-cpython: add an `HgProgressBar` util
Rapha?l Gom?s <rgomes@octobus.net>
parents: 52037
diff changeset
    23
/// to prevent flickering a progress bar for super fast operations.
92e23ba257d1 rust-hg-cpython: add an `HgProgressBar` util
Rapha?l Gom?s <rgomes@octobus.net>
parents: 52037
diff changeset
    24
pub struct HgProgressBar {
92e23ba257d1 rust-hg-cpython: add an `HgProgressBar` util
Rapha?l Gom?s <rgomes@octobus.net>
parents: 52037
diff changeset
    25
    progress: ProgressBar,
92e23ba257d1 rust-hg-cpython: add an `HgProgressBar` util
Rapha?l Gom?s <rgomes@octobus.net>
parents: 52037
diff changeset
    26
    has_been_shown: AtomicBool,
92e23ba257d1 rust-hg-cpython: add an `HgProgressBar` util
Rapha?l Gom?s <rgomes@octobus.net>
parents: 52037
diff changeset
    27
}
92e23ba257d1 rust-hg-cpython: add an `HgProgressBar` util
Rapha?l Gom?s <rgomes@octobus.net>
parents: 52037
diff changeset
    28
92e23ba257d1 rust-hg-cpython: add an `HgProgressBar` util
Rapha?l Gom?s <rgomes@octobus.net>
parents: 52037
diff changeset
    29
impl HgProgressBar {
92e23ba257d1 rust-hg-cpython: add an `HgProgressBar` util
Rapha?l Gom?s <rgomes@octobus.net>
parents: 52037
diff changeset
    30
    // TODO pass config to check progress.disable/assume-tty/delay/etc.
92e23ba257d1 rust-hg-cpython: add an `HgProgressBar` util
Rapha?l Gom?s <rgomes@octobus.net>
parents: 52037
diff changeset
    31
    /// Return a new progress bar with `topic` as the prefix.
92e23ba257d1 rust-hg-cpython: add an `HgProgressBar` util
Rapha?l Gom?s <rgomes@octobus.net>
parents: 52037
diff changeset
    32
    /// The progress and total are both set to 0, and it is hidden until the
92e23ba257d1 rust-hg-cpython: add an `HgProgressBar` util
Rapha?l Gom?s <rgomes@octobus.net>
parents: 52037
diff changeset
    33
    /// next call to `update` given that more than a second has elapsed.
92e23ba257d1 rust-hg-cpython: add an `HgProgressBar` util
Rapha?l Gom?s <rgomes@octobus.net>
parents: 52037
diff changeset
    34
    pub fn new(topic: &str) -> Self {
92e23ba257d1 rust-hg-cpython: add an `HgProgressBar` util
Rapha?l Gom?s <rgomes@octobus.net>
parents: 52037
diff changeset
    35
        let template =
92e23ba257d1 rust-hg-cpython: add an `HgProgressBar` util
Rapha?l Gom?s <rgomes@octobus.net>
parents: 52037
diff changeset
    36
            format!("{} {{wide_bar}} {{pos}}/{{len}} {{eta}} ", topic);
92e23ba257d1 rust-hg-cpython: add an `HgProgressBar` util
Rapha?l Gom?s <rgomes@octobus.net>
parents: 52037
diff changeset
    37
        let style = ProgressStyle::with_template(&template).unwrap();
92e23ba257d1 rust-hg-cpython: add an `HgProgressBar` util
Rapha?l Gom?s <rgomes@octobus.net>
parents: 52037
diff changeset
    38
        let progress_bar = ProgressBar::new(0).with_style(style);
92e23ba257d1 rust-hg-cpython: add an `HgProgressBar` util
Rapha?l Gom?s <rgomes@octobus.net>
parents: 52037
diff changeset
    39
        // Hide the progress bar and only show it if we've elapsed more
92e23ba257d1 rust-hg-cpython: add an `HgProgressBar` util
Rapha?l Gom?s <rgomes@octobus.net>
parents: 52037
diff changeset
    40
        // than a second
92e23ba257d1 rust-hg-cpython: add an `HgProgressBar` util
Rapha?l Gom?s <rgomes@octobus.net>
parents: 52037
diff changeset
    41
        progress_bar.set_draw_target(ProgressDrawTarget::hidden());
92e23ba257d1 rust-hg-cpython: add an `HgProgressBar` util
Rapha?l Gom?s <rgomes@octobus.net>
parents: 52037
diff changeset
    42
        Self {
92e23ba257d1 rust-hg-cpython: add an `HgProgressBar` util
Rapha?l Gom?s <rgomes@octobus.net>
parents: 52037
diff changeset
    43
            progress: progress_bar,
92e23ba257d1 rust-hg-cpython: add an `HgProgressBar` util
Rapha?l Gom?s <rgomes@octobus.net>
parents: 52037
diff changeset
    44
            has_been_shown: false.into(),
92e23ba257d1 rust-hg-cpython: add an `HgProgressBar` util
Rapha?l Gom?s <rgomes@octobus.net>
parents: 52037
diff changeset
    45
        }
92e23ba257d1 rust-hg-cpython: add an `HgProgressBar` util
Rapha?l Gom?s <rgomes@octobus.net>
parents: 52037
diff changeset
    46
    }
92e23ba257d1 rust-hg-cpython: add an `HgProgressBar` util
Rapha?l Gom?s <rgomes@octobus.net>
parents: 52037
diff changeset
    47
92e23ba257d1 rust-hg-cpython: add an `HgProgressBar` util
Rapha?l Gom?s <rgomes@octobus.net>
parents: 52037
diff changeset
    48
    /// Called whenever the progress changes to determine whether to start
92e23ba257d1 rust-hg-cpython: add an `HgProgressBar` util
Rapha?l Gom?s <rgomes@octobus.net>
parents: 52037
diff changeset
    49
    /// showing the progress bar
92e23ba257d1 rust-hg-cpython: add an `HgProgressBar` util
Rapha?l Gom?s <rgomes@octobus.net>
parents: 52037
diff changeset
    50
    fn maybe_show(&self) {
92e23ba257d1 rust-hg-cpython: add an `HgProgressBar` util
Rapha?l Gom?s <rgomes@octobus.net>
parents: 52037
diff changeset
    51
        if self.progress.is_hidden()
92e23ba257d1 rust-hg-cpython: add an `HgProgressBar` util
Rapha?l Gom?s <rgomes@octobus.net>
parents: 52037
diff changeset
    52
            && self.progress.elapsed() > PROGRESS_DELAY
92e23ba257d1 rust-hg-cpython: add an `HgProgressBar` util
Rapha?l Gom?s <rgomes@octobus.net>
parents: 52037
diff changeset
    53
        {
92e23ba257d1 rust-hg-cpython: add an `HgProgressBar` util
Rapha?l Gom?s <rgomes@octobus.net>
parents: 52037
diff changeset
    54
            // Catch a race condition whereby we check if it's hidden, then
92e23ba257d1 rust-hg-cpython: add an `HgProgressBar` util
Rapha?l Gom?s <rgomes@octobus.net>
parents: 52037
diff changeset
    55
            // set the draw target from another thread, then do it again from
92e23ba257d1 rust-hg-cpython: add an `HgProgressBar` util
Rapha?l Gom?s <rgomes@octobus.net>
parents: 52037
diff changeset
    56
            // this thread, which results in multiple progress bar lines being
92e23ba257d1 rust-hg-cpython: add an `HgProgressBar` util
Rapha?l Gom?s <rgomes@octobus.net>
parents: 52037
diff changeset
    57
            // left drawn.
92e23ba257d1 rust-hg-cpython: add an `HgProgressBar` util
Rapha?l Gom?s <rgomes@octobus.net>
parents: 52037
diff changeset
    58
            let has_been_shown =
92e23ba257d1 rust-hg-cpython: add an `HgProgressBar` util
Rapha?l Gom?s <rgomes@octobus.net>
parents: 52037
diff changeset
    59
                self.has_been_shown.fetch_or(true, Ordering::Relaxed);
92e23ba257d1 rust-hg-cpython: add an `HgProgressBar` util
Rapha?l Gom?s <rgomes@octobus.net>
parents: 52037
diff changeset
    60
            if !has_been_shown {
92e23ba257d1 rust-hg-cpython: add an `HgProgressBar` util
Rapha?l Gom?s <rgomes@octobus.net>
parents: 52037
diff changeset
    61
                // Here we are certain that we're the only thread that has
92e23ba257d1 rust-hg-cpython: add an `HgProgressBar` util
Rapha?l Gom?s <rgomes@octobus.net>
parents: 52037
diff changeset
    62
                // set `has_been_shown` and we can change the draw target
92e23ba257d1 rust-hg-cpython: add an `HgProgressBar` util
Rapha?l Gom?s <rgomes@octobus.net>
parents: 52037
diff changeset
    63
                self.progress.set_draw_target(ProgressDrawTarget::stderr());
92e23ba257d1 rust-hg-cpython: add an `HgProgressBar` util
Rapha?l Gom?s <rgomes@octobus.net>
parents: 52037
diff changeset
    64
                self.progress.tick();
92e23ba257d1 rust-hg-cpython: add an `HgProgressBar` util
Rapha?l Gom?s <rgomes@octobus.net>
parents: 52037
diff changeset
    65
            }
92e23ba257d1 rust-hg-cpython: add an `HgProgressBar` util
Rapha?l Gom?s <rgomes@octobus.net>
parents: 52037
diff changeset
    66
        }
92e23ba257d1 rust-hg-cpython: add an `HgProgressBar` util
Rapha?l Gom?s <rgomes@octobus.net>
parents: 52037
diff changeset
    67
    }
92e23ba257d1 rust-hg-cpython: add an `HgProgressBar` util
Rapha?l Gom?s <rgomes@octobus.net>
parents: 52037
diff changeset
    68
}
92e23ba257d1 rust-hg-cpython: add an `HgProgressBar` util
Rapha?l Gom?s <rgomes@octobus.net>
parents: 52037
diff changeset
    69
92e23ba257d1 rust-hg-cpython: add an `HgProgressBar` util
Rapha?l Gom?s <rgomes@octobus.net>
parents: 52037
diff changeset
    70
impl Progress for HgProgressBar {
92e23ba257d1 rust-hg-cpython: add an `HgProgressBar` util
Rapha?l Gom?s <rgomes@octobus.net>
parents: 52037
diff changeset
    71
    fn update(&self, pos: u64, total: Option<u64>) {
92e23ba257d1 rust-hg-cpython: add an `HgProgressBar` util
Rapha?l Gom?s <rgomes@octobus.net>
parents: 52037
diff changeset
    72
        self.progress.update(|state| {
92e23ba257d1 rust-hg-cpython: add an `HgProgressBar` util
Rapha?l Gom?s <rgomes@octobus.net>
parents: 52037
diff changeset
    73
            state.set_pos(pos);
92e23ba257d1 rust-hg-cpython: add an `HgProgressBar` util
Rapha?l Gom?s <rgomes@octobus.net>
parents: 52037
diff changeset
    74
            if let Some(t) = total {
92e23ba257d1 rust-hg-cpython: add an `HgProgressBar` util
Rapha?l Gom?s <rgomes@octobus.net>
parents: 52037
diff changeset
    75
                state.set_len(t)
92e23ba257d1 rust-hg-cpython: add an `HgProgressBar` util
Rapha?l Gom?s <rgomes@octobus.net>
parents: 52037
diff changeset
    76
            }
92e23ba257d1 rust-hg-cpython: add an `HgProgressBar` util
Rapha?l Gom?s <rgomes@octobus.net>
parents: 52037
diff changeset
    77
        });
92e23ba257d1 rust-hg-cpython: add an `HgProgressBar` util
Rapha?l Gom?s <rgomes@octobus.net>
parents: 52037
diff changeset
    78
        self.maybe_show();
92e23ba257d1 rust-hg-cpython: add an `HgProgressBar` util
Rapha?l Gom?s <rgomes@octobus.net>
parents: 52037
diff changeset
    79
    }
92e23ba257d1 rust-hg-cpython: add an `HgProgressBar` util
Rapha?l Gom?s <rgomes@octobus.net>
parents: 52037
diff changeset
    80
92e23ba257d1 rust-hg-cpython: add an `HgProgressBar` util
Rapha?l Gom?s <rgomes@octobus.net>
parents: 52037
diff changeset
    81
    fn increment(&self, step: u64, total: Option<u64>) {
92e23ba257d1 rust-hg-cpython: add an `HgProgressBar` util
Rapha?l Gom?s <rgomes@octobus.net>
parents: 52037
diff changeset
    82
        self.progress.inc(step);
92e23ba257d1 rust-hg-cpython: add an `HgProgressBar` util
Rapha?l Gom?s <rgomes@octobus.net>
parents: 52037
diff changeset
    83
        if let Some(t) = total {
92e23ba257d1 rust-hg-cpython: add an `HgProgressBar` util
Rapha?l Gom?s <rgomes@octobus.net>
parents: 52037
diff changeset
    84
            self.progress.set_length(t)
92e23ba257d1 rust-hg-cpython: add an `HgProgressBar` util
Rapha?l Gom?s <rgomes@octobus.net>
parents: 52037
diff changeset
    85
        }
92e23ba257d1 rust-hg-cpython: add an `HgProgressBar` util
Rapha?l Gom?s <rgomes@octobus.net>
parents: 52037
diff changeset
    86
        self.maybe_show();
92e23ba257d1 rust-hg-cpython: add an `HgProgressBar` util
Rapha?l Gom?s <rgomes@octobus.net>
parents: 52037
diff changeset
    87
    }
92e23ba257d1 rust-hg-cpython: add an `HgProgressBar` util
Rapha?l Gom?s <rgomes@octobus.net>
parents: 52037
diff changeset
    88
92e23ba257d1 rust-hg-cpython: add an `HgProgressBar` util
Rapha?l Gom?s <rgomes@octobus.net>
parents: 52037
diff changeset
    89
    fn complete(self) {
92e23ba257d1 rust-hg-cpython: add an `HgProgressBar` util
Rapha?l Gom?s <rgomes@octobus.net>
parents: 52037
diff changeset
    90
        self.progress.finish_and_clear();
92e23ba257d1 rust-hg-cpython: add an `HgProgressBar` util
Rapha?l Gom?s <rgomes@octobus.net>
parents: 52037
diff changeset
    91
    }
92e23ba257d1 rust-hg-cpython: add an `HgProgressBar` util
Rapha?l Gom?s <rgomes@octobus.net>
parents: 52037
diff changeset
    92
}