Refactor `pijul_interaction::progress` to use `InteractionContext`

finchie
Jul 24, 2023, 4:42 AM
DGHQ46S3S2RQ27CXF4OES5GDXUI63VTSYYQFLXHG7PRKSVWB3SZAC

Dependencies

  • [2] JTELS6L3 Implement user input for `pijul-interaction`
  • [3] ABPFWGKH Create `pijul-interaction` crate
  • [4] EJ7TFFOW Re-adding Cargo.lock

Change contents

  • file deletion: progress.rs (----------)
    [3.1223][3.1225:1260](),[3.1260][3.1261:1261]()
    use std::time::Duration;
    use indicatif::MultiProgress;
    use lazy_static::lazy_static;
    use indicatif::ProgressStyle;
    lazy_static! {
    static ref MULTI_PROGRESS: MultiProgress = MultiProgress::new();
    }
    pub const DOWNLOAD_MESSAGE: &str = "Downloading changes";
    pub const APPLY_MESSAGE: &str = "Applying changes";
    pub const UPLOAD_MESSAGE: &str = "Uploading changes";
    pub const COMPLETE_MESSAGE: &str = "Completing changes";
    pub const OUTPUT_MESSAGE: &str = "Outputting repository";
    #[derive(Clone, Debug)]
    pub struct ProgressBar(Option<indicatif::ProgressBar>);
    impl Drop for ProgressBar {
    fn drop(&mut self) {
    // Make sure the progress bar doesn't disappear after completion
    if let Some(progress_bar) = &self.0 {
    progress_bar.finish();
    }
    }
    }
    impl ProgressBar {
    pub fn new(len: u64, message: &str) -> Result<Self, anyhow::Error> {
    let style =
    ProgressStyle::with_template("{msg:<20} [{bar:50}] {pos}/{len} [{elapsed_precise}]")?
    .progress_chars("=> ");
    let progress_bar = indicatif::ProgressBar::new(len)
    .with_style(style)
    .with_message(message.to_owned());
    MULTI_PROGRESS.add(progress_bar.clone());
    progress_bar.enable_steady_tick(Duration::from_millis(15));
    Ok(Self(Some(progress_bar)))
    }
    pub fn hidden() -> Self {
    Self(None)
    }
    pub fn inc(&self, delta: u64) {
    if let Some(progress) = self.0.clone() {
    progress.inc(delta);
    }
    }
    pub fn inner(&self) -> Option<indicatif::ProgressBar> {
    self.0.clone()
    }
    }
    #[derive(Clone, Debug)]
    pub struct Spinner(indicatif::ProgressBar);
    impl Drop for Spinner {
    fn drop(&mut self) {
    // Make sure the spinner doesn't disappear after completion
    self.finish().unwrap();
    }
    }
    impl Spinner {
    pub fn new(message: &str) -> Result<Self, anyhow::Error> {
    let style = ProgressStyle::with_template("{msg}{spinner}")?
    .tick_strings(&[". ", ".. ", "...", " "]);
    let spinner = indicatif::ProgressBar::new_spinner()
    .with_style(style)
    .with_message(message.to_owned());
    spinner.enable_steady_tick(Duration::from_millis(200));
    MULTI_PROGRESS.add(spinner.clone());
    Ok(Self(spinner))
    }
    pub fn finish(&self) -> Result<(), anyhow::Error> {
    self.0.set_style(ProgressStyle::with_template("{msg}")?);
    self.0
    .finish_with_message(format!("{}... done!", self.0.message()));
    Ok(())
    }
    }
  • file addition: progress (d--r------)
    [3.1223]
  • file addition: terminal.rs (----------)
    [0.20]
    use std::sync::Arc;
    use std::time::Duration;
    use super::{ProgressBarTrait, SpinnerTrait};
    use indicatif::{MultiProgress, ProgressBar, ProgressStyle};
    use lazy_static::lazy_static;
    lazy_static! {
    static ref MULTI_PROGRESS: MultiProgress = MultiProgress::new();
    }
    pub fn new_progress(len: u64, message: String) -> Arc<ProgressBar> {
    let style =
    ProgressStyle::with_template("{msg:<20} [{bar:50}] {pos}/{len} [{elapsed_precise}]")
    .unwrap()
    .progress_chars("=> ");
    let progress_bar = ProgressBar::new(len)
    .with_style(style)
    .with_message(message);
    MULTI_PROGRESS.add(progress_bar.clone());
    progress_bar.enable_steady_tick(Duration::from_millis(15));
    Arc::new(progress_bar)
    }
    impl ProgressBarTrait for Arc<ProgressBar> {
    fn inc(&self, delta: u64) {
    self.as_ref().inc(delta);
    }
    fn finish(&self) {
    // Only finish the progress bar if it's the last reference
    if Arc::strong_count(self) == 1 {
    self.as_ref().finish();
    }
    }
    fn boxed_clone(&self) -> Box<(dyn ProgressBarTrait)> {
    Box::new(self.clone())
    }
    }
    pub fn new_spinner(message: String) -> Arc<ProgressBar> {
    let style = ProgressStyle::with_template("{msg}{spinner}")
    .unwrap()
    .tick_strings(&[". ", ".. ", "...", " "]);
    let spinner = ProgressBar::new_spinner()
    .with_style(style)
    .with_message(message);
    spinner.enable_steady_tick(Duration::from_millis(200));
    MULTI_PROGRESS.add(spinner.clone());
    Arc::new(spinner)
    }
    impl SpinnerTrait for Arc<ProgressBar> {
    fn finish(&self) {
    // Only display finish message if it's the last reference
    if Arc::strong_count(self) == 1 {
    self.set_style(ProgressStyle::with_template("{msg}").unwrap());
    self.finish_with_message(format!("{}... done!", self.message()));
    }
    }
    fn boxed_clone(&self) -> Box<dyn SpinnerTrait> {
    Box::new(self.clone())
    }
    }
  • file addition: mod.rs (----------)
    [0.20]
    mod terminal;
    use super::{ProgressBar, Spinner};
    use crate::{InteractionError, InteractiveContext};
    pub trait ProgressBarTrait: Send {
    fn inc(&self, delta: u64);
    fn finish(&self);
    fn boxed_clone(&self) -> Box<dyn ProgressBarTrait>;
    }
    impl ProgressBar {
    pub fn new<S: ToString>(len: u64, message: S) -> Result<ProgressBar, InteractionError> {
    Ok(Self(match crate::get_context()? {
    InteractiveContext::Terminal | InteractiveContext::NotInteractive => {
    Box::new(terminal::new_progress(len, message.to_string()))
    }
    }))
    }
    pub fn inc(&self, delta: u64) {
    self.0.inc(delta);
    }
    fn finish(&self) {
    self.0.finish()
    }
    }
    impl Drop for ProgressBar {
    fn drop(&mut self) {
    self.finish();
    }
    }
    impl Clone for ProgressBar {
    fn clone(&self) -> Self {
    Self(self.0.boxed_clone())
    }
    }
    pub trait SpinnerTrait: Send {
    fn finish(&self);
    fn boxed_clone(&self) -> Box<dyn SpinnerTrait>;
    }
    impl Spinner {
    pub fn new<S: ToString>(message: S) -> Result<Spinner, InteractionError> {
    Ok(Self(match crate::get_context()? {
    InteractiveContext::Terminal | InteractiveContext::NotInteractive => {
    Box::new(terminal::new_spinner(message.to_string()))
    }
    }))
    }
    fn finish(&self) {
    self.0.finish();
    }
    }
    impl Drop for Spinner {
    fn drop(&mut self) {
    self.finish();
    }
    }
    impl Clone for Spinner {
    fn clone(&self) -> Self {
    Self(self.0.boxed_clone())
    }
    }
  • replacement in pijul-interaction/src/lib.rs at line 4
    [2.106][3.3870:3888](),[3.3869][3.3870:3888]()
    pub mod progress;
    [2.106]
    [2.107]
    mod progress;
  • edit in pijul-interaction/src/lib.rs at line 7
    [2.181]
    [2.181]
    use progress::{ProgressBarTrait, SpinnerTrait};
  • edit in pijul-interaction/src/lib.rs at line 9
    [2.206]
    [2.206]
    // TODO: these should be replaced with a more sophisticated localization system
    pub const DOWNLOAD_MESSAGE: &str = "Downloading changes";
    pub const APPLY_MESSAGE: &str = "Applying changes";
    pub const UPLOAD_MESSAGE: &str = "Uploading changes";
    pub const COMPLETE_MESSAGE: &str = "Completing changes";
    pub const OUTPUT_MESSAGE: &str = "Outputting repository";
  • edit in pijul-interaction/src/lib.rs at line 92
    [2.2614]
    /// A progress bar that is controlled by code
    pub struct ProgressBar(Box<dyn ProgressBarTrait>);
    /// An animated progress bar to indicate activity
    pub struct Spinner(Box<dyn SpinnerTrait>);
  • edit in pijul-interaction/src/input/mod.rs at line 117
    [2.12085][2.12085:12143]()
    // TODO: check if clippy catches Into<String> -> ToString
  • edit in pijul-interaction/Cargo.toml at line 12
    [3.4253][3.4253:4308]()
    anyhow = { version = "1.0", features = ["backtrace"] }
  • edit in Cargo.lock at line 2261
    [3.651][3.651:662]()
    "anyhow",