use crate::indicator::{ProgressConfig, ProgressFactory, ProgressIndicator, ProgressStyle};
use std::sync::{Arc, Mutex};
use std::time::Duration;
pub struct ProgressHandle {
indicator: Arc<Mutex<Box<dyn ProgressIndicator>>>,
is_finished: Arc<Mutex<bool>>,
current_value: Arc<Mutex<u64>>,
total: Option<u64>,
}
impl ProgressHandle {
pub fn enable_steady_tick(&self, _interval: Duration) {
}
pub fn finish_and_clear(&self) {
if let Ok(mut indicator) = self.indicator.lock() {
indicator.complete(None);
}
if let Ok(mut finished) = self.is_finished.lock() {
*finished = true;
}
}
pub fn finish_with_message(&self, message: String) {
if let Ok(mut indicator) = self.indicator.lock() {
indicator.complete(Some(message));
}
if let Ok(mut finished) = self.is_finished.lock() {
*finished = true;
}
}
pub fn inc(&self, delta: u64) {
if let Ok(mut current) = self.current_value.lock() {
*current += delta;
if let Ok(mut indicator) = self.indicator.lock() {
indicator.update(*current, self.total);
}
}
}
pub fn set_message(&self, message: String) {
if let Ok(mut indicator) = self.indicator.lock() {
indicator.set_message(message);
}
}
pub fn finish(&self) {
self.finish_and_clear();
}
pub fn is_finished(&self) -> bool {
self.is_finished.lock().map(|f| *f).unwrap_or(false)
}
}
pub struct ProgressReporter {
no_progress: bool,
progress_indicators: Vec<Arc<Mutex<Box<dyn ProgressIndicator>>>>,
}
impl ProgressReporter {
pub fn new(no_progress: bool) -> Self {
Self {
no_progress,
progress_indicators: Vec::new(),
}
}
pub fn new_batch(no_progress: bool) -> Self {
Self {
no_progress,
progress_indicators: Vec::new(),
}
}
fn create_progress_handle(
&mut self,
indicator: Box<dyn ProgressIndicator>,
total: Option<u64>,
) -> ProgressHandle {
let arc_indicator = Arc::new(Mutex::new(indicator));
self.progress_indicators.push(arc_indicator.clone());
ProgressHandle {
indicator: arc_indicator,
is_finished: Arc::new(Mutex::new(false)),
current_value: Arc::new(Mutex::new(0)),
total,
}
}
pub fn create_spinner(&mut self, _message: &str) -> ProgressHandle {
let mut indicator = ProgressFactory::create(self.no_progress);
let config = ProgressConfig::new(ProgressStyle::Count);
indicator.start(config);
self.create_progress_handle(indicator, None)
}
pub fn create_bar(&mut self, total: u64, _message: &str) -> ProgressHandle {
let mut indicator = ProgressFactory::create(self.no_progress);
let config = ProgressConfig::new(ProgressStyle::Count).with_total(total);
indicator.start(config);
self.create_progress_handle(indicator, Some(total))
}
pub fn create_jdk_removal_spinner(
&mut self,
jdk_path: &str,
formatted_size: &str,
) -> ProgressHandle {
let mut indicator = ProgressFactory::create(self.no_progress);
let config = ProgressConfig::new(ProgressStyle::Count);
indicator.start(config);
indicator.set_message(format!(
"Preparing removal of {jdk_path} ({formatted_size})..."
));
self.create_progress_handle(indicator, None)
}
pub fn create_batch_removal_bar(&mut self, total_jdks: u64) -> ProgressHandle {
let mut indicator = ProgressFactory::create(self.no_progress);
let config = ProgressConfig::new(ProgressStyle::Count).with_total(total_jdks);
indicator.start(config);
self.create_progress_handle(indicator, Some(total_jdks))
}
}
impl Default for ProgressReporter {
fn default() -> Self {
Self::new(false)
}
}
#[cfg(test)]
mod tests {
use super::*;
#[test]
fn test_new_progress_reporter() {
let reporter = ProgressReporter::new(false);
assert!(!reporter.no_progress);
assert!(reporter.progress_indicators.is_empty());
}
#[test]
fn test_new_batch_progress_reporter() {
let reporter = ProgressReporter::new_batch(false);
assert!(!reporter.no_progress);
assert!(reporter.progress_indicators.is_empty());
}
#[test]
fn test_create_spinner() {
let mut reporter = ProgressReporter::new(false);
let spinner = reporter.create_spinner("Test message");
assert!(!spinner.is_finished());
spinner.finish();
assert!(spinner.is_finished());
}
#[test]
fn test_create_bar() {
let mut reporter = ProgressReporter::new(false);
let bar = reporter.create_bar(10, "Test items");
assert!(!bar.is_finished());
bar.finish();
assert!(bar.is_finished());
}
#[test]
fn test_create_jdk_removal_spinner() {
let mut reporter = ProgressReporter::new(false);
let spinner = reporter.create_jdk_removal_spinner("/test/jdk", "512 MB");
assert!(!spinner.is_finished());
spinner.finish();
assert!(spinner.is_finished());
}
#[test]
fn test_create_batch_removal_bar() {
let mut reporter = ProgressReporter::new_batch(false);
let bar = reporter.create_batch_removal_bar(5);
assert!(!bar.is_finished());
bar.finish();
assert!(bar.is_finished());
}
}