rust/hg-core/src/progress.rs
author Rapha?l Gom?s <rgomes@octobus.net>
Mon, 30 Sep 2024 16:04:51 +0200
changeset 52038 92e23ba257d1
parent 52037 3ae7c43ad8aa
child 52306 a876ab6c3fd5
permissions -rw-r--r--
rust-hg-cpython: add an `HgProgressBar` util This will be the entry point for all progress bars from a Python context in upcoming patches. Like the `Progress` trait, this is subject to change once we have more use cases, but this is good enough for now.
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
}