use anyhow::Result;
use indicatif::{MultiProgress, ProgressBar, ProgressStyle};
use std::path::PathBuf;
use std::sync::{Arc, Mutex};
use super::config::{
DEFAULT_PROGRESS_BAR_LENGTH, PROGRESS_CHARS, PROGRESS_TEMPLATE,
};
use super::stats::SyncStatistics;
pub struct ProcessingContext {
pub repositories: Vec<(String, PathBuf)>,
pub max_name_length: usize,
pub multi_progress: MultiProgress,
pub progress_style: ProgressStyle,
pub statistics: Arc<Mutex<SyncStatistics>>,
pub semaphore: Arc<tokio::sync::Semaphore>,
pub max_concurrency: usize,
pub total_repos: usize,
pub start_time: std::time::Instant,
}
pub struct GenericProcessingContext<T> {
pub repositories: Vec<(String, PathBuf)>,
pub max_name_length: usize,
pub multi_progress: MultiProgress,
pub progress_style: ProgressStyle,
pub statistics: Arc<Mutex<T>>,
pub semaphore: Arc<tokio::sync::Semaphore>,
pub total_repos: usize,
pub start_time: std::time::Instant,
}
pub fn create_processing_context(
repositories: Vec<(String, PathBuf)>,
start_time: std::time::Instant,
concurrent_limit: usize,
) -> Result<ProcessingContext> {
let total_repos = repositories.len();
let max_name_length = repositories
.iter()
.map(|(name, _)| name.len())
.max()
.unwrap_or(0);
let multi_progress = MultiProgress::new();
let progress_style = create_progress_style()?;
let statistics = Arc::new(Mutex::new(SyncStatistics::new()));
let semaphore = Arc::new(tokio::sync::Semaphore::new(concurrent_limit));
Ok(ProcessingContext {
repositories,
max_name_length,
multi_progress,
progress_style,
statistics,
semaphore,
max_concurrency: concurrent_limit,
total_repos,
start_time,
})
}
pub fn create_generic_processing_context<T>(
repositories: Vec<(String, PathBuf)>,
start_time: std::time::Instant,
statistics: T,
concurrent_limit: usize,
) -> Result<GenericProcessingContext<T>> {
let total_repos = repositories.len();
let max_name_length = repositories
.iter()
.map(|(name, _)| name.len())
.max()
.unwrap_or(0);
let multi_progress = MultiProgress::new();
let progress_style = create_progress_style()?;
let statistics = Arc::new(Mutex::new(statistics));
let semaphore = Arc::new(tokio::sync::Semaphore::new(concurrent_limit));
Ok(GenericProcessingContext {
repositories,
max_name_length,
multi_progress,
progress_style,
statistics,
semaphore,
total_repos,
start_time,
})
}
pub(crate) fn create_progress_bar(
multi: &MultiProgress,
style: &ProgressStyle,
repo_name: &str,
) -> ProgressBar {
let pb = multi.add(ProgressBar::new(DEFAULT_PROGRESS_BAR_LENGTH));
pb.set_style(style.clone());
pb.set_prefix(format!("🟡 {}", repo_name));
pb.set_message("syncing...");
pb
}
pub(crate) fn create_progress_style() -> Result<ProgressStyle> {
Ok(ProgressStyle::default_bar()
.template(PROGRESS_TEMPLATE)?
.progress_chars(PROGRESS_CHARS))
}
pub async fn acquire_semaphore_permit(
semaphore: &'_ Arc<tokio::sync::Semaphore>,
) -> tokio::sync::SemaphorePermit<'_> {
semaphore
.acquire()
.await
.expect("Failed to acquire semaphore permit")
}
pub(crate) fn acquire_stats_lock<T>(stats: &'_ Arc<Mutex<T>>) -> std::sync::MutexGuard<'_, T> {
stats.lock().expect("Failed to acquire statistics lock")
}
pub(crate) fn create_separator_progress_bar(multi_progress: &MultiProgress) -> ProgressBar {
let separator_pb = multi_progress.add(ProgressBar::new(0));
separator_pb.set_style(ProgressStyle::default_bar().template(" ").expect("Failed to create separator progress bar template - this indicates an invalid template string"));
separator_pb.finish();
separator_pb
}
pub(crate) fn create_footer_progress_bar(multi_progress: &MultiProgress) -> ProgressBar {
let footer_pb = multi_progress.add(ProgressBar::new(0));
let footer_style = ProgressStyle::default_bar()
.template("{wide_msg}")
.expect("Failed to create footer progress style - this indicates an invalid template string in the progress bar configuration");
footer_pb.set_style(footer_style);
footer_pb
}