Skip to content
4 changes: 2 additions & 2 deletions src/commands/debug_files/find.rs
Original file line number Diff line number Diff line change
Expand Up @@ -117,7 +117,7 @@ fn find_ids(
.filter(|e| e.file_type().is_file());

let mut found_files = vec![];
let pb = ProgressBar::new_spinner();
let mut pb = ProgressBar::new_spinner();
Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Needs to become mut to handle set_prefix

pb.set_style(
ProgressStyle::default_spinner()
.tick_chars("/|\\- ")
Expand All @@ -136,7 +136,7 @@ fn find_ids(
pb.set_message(p);
}
pb.tick();
pb.set_prefix(&format!("{}", found_files.len()));
pb.set_prefix(format!("{}", found_files.len()));

let found: Vec<_> = types
.iter()
Expand Down
2 changes: 1 addition & 1 deletion src/utils/chunks/upload.rs
Original file line number Diff line number Diff line change
Expand Up @@ -182,7 +182,7 @@ where
);

let api = Api::current();
let pb = ProgressBar::new(chunked_objects.len());
let mut pb = ProgressBar::new(chunked_objects.len());
pb.set_style(progress_style);
pb.set_prefix(">");

Expand Down
12 changes: 6 additions & 6 deletions src/utils/dif_upload/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -636,7 +636,7 @@ fn search_difs(options: &DifUpload) -> Result<Vec<DifMatch<'static>>> {
\n found {prefix:.yellow} {msg:.dim}",
);

let pb = ProgressBar::new_spinner();
let mut pb = ProgressBar::new_spinner();
pb.enable_steady_tick(100);
pb.set_style(progress_style);

Expand Down Expand Up @@ -668,7 +668,7 @@ fn search_difs(options: &DifUpload) -> Result<Vec<DifMatch<'static>>> {
}
};

pb.set_prefix(&collected.len().to_string());
pb.set_prefix(collected.len().to_string());
Ok(())
})?;
}
Expand Down Expand Up @@ -958,7 +958,7 @@ where
\n{wide_bar} {pos}/{len}",
);

let pb = ProgressBar::new(items.len());
let mut pb = ProgressBar::new(items.len());
pb.set_style(progress_style);
pb.set_prefix(">");

Expand Down Expand Up @@ -1019,7 +1019,7 @@ fn process_symbol_maps<'a>(
\n{wide_bar} {pos}/{len}",
);

let pb = ProgressBar::new(len);
let mut pb = ProgressBar::new(len);
pb.set_style(progress_style);
pb.set_prefix(">");

Expand Down Expand Up @@ -1110,7 +1110,7 @@ fn create_source_bundles<'a>(
\n{wide_bar} {pos}/{len}",
);

let pb = ProgressBar::new(difs.len());
let mut pb = ProgressBar::new(difs.len());
pb.set_style(progress_style);
pb.set_prefix(">");

Expand Down Expand Up @@ -1166,7 +1166,7 @@ fn create_il2cpp_mappings<'a>(difs: &[DifMatch<'a>]) -> Result<Vec<DifMatch<'a>>
\n{wide_bar} {pos}/{len}",
);

let pb = ProgressBar::new(difs.len());
let mut pb = ProgressBar::new(difs.len());
pb.set_style(progress_style);
pb.set_prefix(">");

Expand Down
6 changes: 3 additions & 3 deletions src/utils/file_search.rs
Original file line number Diff line number Diff line change
Expand Up @@ -98,7 +98,7 @@ impl ReleaseFileSearch {
\n found {prefix:.yellow} {msg:.dim}",
);

let pb = ProgressBar::new_spinner();
let mut pb = ProgressBar::new_spinner();
pb.enable_steady_tick(100);
pb.set_style(progress_style);

Expand Down Expand Up @@ -139,7 +139,7 @@ impl ReleaseFileSearch {
if file.file_type().is_some_and(|t| t.is_dir()) {
continue;
}
pb.set_message(&format!("{}", file.path().display()));
pb.set_message(format!("{}", file.path().display()));

info!("found: {} ({} bytes)", file.path().display(), {
#[expect(clippy::unwrap_used, reason = "legacy code")]
Expand All @@ -164,7 +164,7 @@ impl ReleaseFileSearch {
};
collected.push(file_match);

pb.set_prefix(&collected.len().to_string());
pb.set_prefix(collected.len().to_string());
}

pb.finish_and_clear();
Expand Down
2 changes: 1 addition & 1 deletion src/utils/file_upload.rs
Original file line number Diff line number Diff line change
Expand Up @@ -680,7 +680,7 @@ fn build_artifact_bundle(
\n{wide_bar} {pos}/{len}",
);

let pb = ProgressBar::new(files.len());
let mut pb = ProgressBar::new(files.len());
pb.set_style(progress_style);
pb.set_prefix(">");

Expand Down
129 changes: 97 additions & 32 deletions src/utils/progress.rs
Original file line number Diff line number Diff line change
@@ -1,76 +1,141 @@
use parking_lot::RwLock;
use std::env;
use std::ops::Deref;
use std::io::IsTerminal as _;
use std::sync::Arc;
use std::time::Instant;

use crate::utils::logging;

pub use indicatif::ProgressStyle;

pub fn is_progress_bar_visible() -> bool {
env::var("SENTRY_NO_PROGRESS_BAR") != Ok("1".into())
/// By default, use the progress bar when we can detect we're running in a terminal.
/// `SENTRY_NO_PROGRESS_BAR` takes precedence and can be used to disable the progress bar
/// regardless of whether or not we're in a terminal.
pub fn use_progress_bar() -> bool {
if env::var("SENTRY_NO_PROGRESS_BAR") == Ok("1".into()) {
return false;
}
std::io::stdout().is_terminal() && std::io::stderr().is_terminal()
}

/// Wrapper that optionally holds a progress bar.
/// If there's a progress bar, forward calls to it.
/// Otherwise, forward messages to `log` calls.
pub struct ProgressBar {
inner: Arc<indicatif::ProgressBar>,
inner: Option<Arc<indicatif::ProgressBar>>,
start: Instant,
prefix: Option<String>,
}

impl ProgressBar {
pub fn new(len: usize) -> Self {
if is_progress_bar_visible() {
indicatif::ProgressBar::new(len as u64).into()
if use_progress_bar() {
Self::from_indicatif(indicatif::ProgressBar::new(len as u64))
} else {
Self::hidden()
Self::no_progress_bar()
}
}

pub fn new_spinner() -> Self {
if is_progress_bar_visible() {
indicatif::ProgressBar::new_spinner().into()
if use_progress_bar() {
Self::from_indicatif(indicatif::ProgressBar::new_spinner())
} else {
Self::hidden()
Self::no_progress_bar()
}
}

pub fn hidden() -> Self {
indicatif::ProgressBar::hidden().into()
fn from_indicatif(pb: indicatif::ProgressBar) -> Self {
let inner = Arc::new(pb);
logging::set_progress_bar(Some(Arc::downgrade(&inner)));
ProgressBar {
inner: Some(inner),
start: Instant::now(),
prefix: None,
}
}

fn no_progress_bar() -> Self {
ProgressBar {
inner: None,
start: Instant::now(),
prefix: None,
}
}

pub fn finish_with_duration(&self, op: &str) {
let dur = self.start.elapsed();
// We could use `dur.as_secs_f64()`, but its unnecessarily precise (micros). Millis are enough for our purpose.
let msg = format!("{op} completed in {}s", dur.as_millis() as f64 / 1000.0);
let progress_style = ProgressStyle::default_bar().template("{prefix:.dim} {msg}");
self.inner.set_style(progress_style);
self.inner.set_prefix(">");
self.inner.finish_with_message(&msg);
logging::set_progress_bar(None);

if let Some(inner) = &self.inner {
let progress_style = ProgressStyle::default_bar().template("{prefix:.dim} {msg}");
inner.set_style(progress_style);
inner.set_prefix(">");
inner.finish_with_message(&msg);
logging::set_progress_bar(None);
} else {
log::info!("> {msg}");
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

log::info! by default would be hidden (as log level is by default at WARN). I think eprintln! is therefore more suitable here, assuming these final messages typically show in the stderr when running in terminal

Suggested change
log::info!("> {msg}");
eprintln!("> {msg}");

}
}

pub fn finish_and_clear(&self) {
self.inner.finish_and_clear();
logging::set_progress_bar(None);
if let Some(inner) = &self.inner {
inner.finish_and_clear();
logging::set_progress_bar(None);
}
}
}

impl From<indicatif::ProgressBar> for ProgressBar {
fn from(pb: indicatif::ProgressBar) -> Self {
let inner = Arc::new(pb);
logging::set_progress_bar(Some(Arc::downgrade(&inner)));
ProgressBar {
inner,
start: Instant::now(),
pub fn set_style(&self, style: ProgressStyle) {
if let Some(inner) = &self.inner {
inner.set_style(style);
}
}

pub fn set_message<S: AsRef<str>>(&self, msg: S) {
if let Some(inner) = &self.inner {
inner.set_message(msg.as_ref());
} else {
log::debug!(
"{}{}",
self.prefix
.as_deref()
.map(|s| format!("{s} "))
.unwrap_or_else(|| String::new()),
msg.as_ref()
);
}
}
}

impl Deref for ProgressBar {
type Target = indicatif::ProgressBar;
pub fn tick(&self) {
if let Some(inner) = &self.inner {
inner.tick();
}
}

fn deref(&self) -> &Self::Target {
&self.inner
pub fn set_prefix<S: AsRef<str>>(&mut self, prefix: S) {
if let Some(inner) = &self.inner {
inner.set_prefix(prefix.as_ref());
} else {
self.prefix = Some(prefix.as_ref().to_owned());
}
Comment on lines +118 to +120
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Going along with my previous suggestion, getting rid of logging in the no progress bar case lets us simplify here. We can probably even remove the prefix field from the struct.

Suggested change
} else {
self.prefix = Some(prefix.as_ref().to_owned());
}
}

}

pub fn set_position(&self, pos: u64) {
if let Some(inner) = &self.inner {
inner.set_position(pos);
}
}

pub fn inc(&self, delta: u64) {
if let Some(inner) = &self.inner {
inner.inc(delta);
}
}

pub fn enable_steady_tick(&self, interval: u64) {
if let Some(inner) = &self.inner {
inner.enable_steady_tick(interval);
}
}
}

Expand Down
Loading