Skip to content

Commit bf3c820

Browse files
authored
fix: use indicatif-log-bridge to avoid breaking progress bar on log (#1747)
Tentative fix for #1746 using [`indicatif-log-bridge`](https://github.com/djugei/indicatif-log-bridge). Marking as "draft" PR since it adds some flickering to the progress bar. I have to investigate this. Fixes #1746.
1 parent 8e134b6 commit bf3c820

2 files changed

Lines changed: 38 additions & 3 deletions

File tree

src/config/logging.rs

Lines changed: 22 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -17,6 +17,8 @@ use log4rs::{
1717
use serde::{Deserialize, Serialize};
1818
use serde_with::{DisplayFromStr, serde_as};
1919

20+
use crate::config::progress_options::multi_progress;
21+
2022
/// Logging Config
2123
#[serde_as]
2224
#[derive(Default, Debug, Parser, Clone, Deserialize, Serialize, Merge)]
@@ -77,6 +79,7 @@ impl LoggingOptions {
7779
.target(Target::Stderr)
7880
.encoder(Box::new(PatternEncoder::new("{h([{l}])} {m}{n}")))
7981
.build();
82+
let stdout = PbPauseAppender(stdout);
8083

8184
let mut root_builder = Root::builder().appender("stdout");
8285
let mut config_builder = Config::builder().appender(
@@ -119,3 +122,22 @@ impl LoggingOptions {
119122
Ok(())
120123
}
121124
}
125+
126+
/// A wrapper around [`ConsoleAppender`] that suspends the progress bar when writing logs.
127+
#[derive(Debug)]
128+
struct PbPauseAppender(ConsoleAppender);
129+
130+
impl log4rs::append::Append for PbPauseAppender {
131+
fn append(&self, record: &log::Record<'_>) -> Result<()> {
132+
multi_progress().suspend(|| self.0.append(record))
133+
}
134+
135+
fn flush(&self) {
136+
// as of log4rs 1.4.0, <ConsoleAppender as Append>::flush does nothing,
137+
// so we do not need to pause the progress bar here. In the future,
138+
// if log4rs changes this behavior, we might need to add a suspend here.
139+
// But that's not necessary right now, so we just call flush directly
140+
// to avoid unnecessary suspends.
141+
self.0.flush();
142+
}
143+
}

src/config/progress_options.rs

Lines changed: 16 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -3,11 +3,11 @@
33
use std::{fmt::Write, time::Duration};
44

55
use std::io::IsTerminal;
6-
use std::sync::{Arc, Mutex};
6+
use std::sync::{Arc, Mutex, OnceLock};
77
use std::time::Instant;
88

99
use bytesize::ByteSize;
10-
use indicatif::{HumanDuration, ProgressBar, ProgressState, ProgressStyle};
10+
use indicatif::{HumanDuration, MultiProgress, ProgressBar, ProgressState, ProgressStyle};
1111

1212
use clap::Parser;
1313
use conflate::Merge;
@@ -19,6 +19,19 @@ use serde_with::{DisplayFromStr, serde_as};
1919

2020
use rustic_core::{Progress, ProgressBars, ProgressType, RusticProgress};
2121

22+
/// Returns the global `MultiProgress` instance used by all interactive progress bars.
23+
///
24+
/// Must be shared with `indicatif_log_bridge::LogWrapper` so that log output
25+
/// suspends progress bars before printing.
26+
pub fn multi_progress() -> &'static MultiProgress {
27+
static MP: OnceLock<MultiProgress> = OnceLock::new();
28+
MP.get_or_init(|| {
29+
let mp = MultiProgress::new();
30+
mp.set_move_cursor(true);
31+
mp
32+
})
33+
}
34+
2235
mod constants {
2336
use std::time::Duration;
2437

@@ -110,7 +123,7 @@ pub struct InteractiveProgress {
110123
impl InteractiveProgress {
111124
fn new(prefix: &str, kind: ProgressType, tick_interval: Duration) -> Self {
112125
let style = Self::initial_style(kind);
113-
let bar = ProgressBar::new(0).with_style(style);
126+
let bar = multi_progress().add(ProgressBar::new(0).with_style(style));
114127
bar.set_prefix(prefix.to_string());
115128
bar.enable_steady_tick(tick_interval);
116129
Self { bar, kind }

0 commit comments

Comments
 (0)