use anyhow::Result;
use console::style;
use indicatif::{ProgressBar, ProgressDrawTarget, ProgressStyle};
use std::time::{Duration, Instant};
use crate::{
application::operations::install_operation::InstallOperation,
models::{
common::enums::{Channel, Filetype, Provider},
upstream::Package,
},
providers::provider_manager::ProviderManager,
services::storage::{config_storage::ConfigStorage, package_storage::PackageStorage},
utils::static_paths::UpstreamPaths,
};
pub async fn run(
name: String,
repo_slug: String,
kind: Filetype,
version: Option<String>,
provider: Provider,
base_url: Option<String>,
channel: Channel,
match_pattern: Option<String>,
exclude_pattern: Option<String>,
create_entry: bool,
ignore_checksums: bool,
) -> Result<()> {
const PROGRESS_UPDATE_INTERVAL: Duration = Duration::from_millis(100);
println!(
"{}",
style(format!("Installing {} from {} ...", &name, &provider)).cyan()
);
let paths = UpstreamPaths::new();
let config = ConfigStorage::new(&paths.config.config_file)?;
let mut package_storage = PackageStorage::new(&paths.config.packages_file)?;
let github_token = config.get_config().github.api_token.as_deref();
let gitlab_token = config.get_config().gitlab.api_token.as_deref();
let gitea_token = config.get_config().gitea.api_token.as_deref();
let provider_manager =
ProviderManager::new(github_token, gitlab_token, gitea_token, base_url.as_deref())?;
let mut package_installer =
InstallOperation::new(&provider_manager, &mut package_storage, &paths)?;
let package = Package::with_defaults(
name,
repo_slug,
kind,
match_pattern,
exclude_pattern,
channel,
provider,
base_url,
);
let pb = ProgressBar::new(0);
pb.set_draw_target(ProgressDrawTarget::stderr_with_hz(10));
pb.set_style(ProgressStyle::with_template(
"{spinner:.green} [{elapsed_precise}] [{bar:40.cyan/blue}] {bytes}/{total_bytes} ({eta}) {msg}",
)?);
pb.enable_steady_tick(Duration::from_millis(120));
let pb_ref = &pb;
let mut last_emit: Option<Instant> = None;
let mut last_progress: Option<(u64, u64)> = None;
let mut download_progress_callback = Some(|downloaded: u64, total: u64| {
last_progress = Some((downloaded, total));
let should_emit = last_emit
.map(|t| t.elapsed() >= PROGRESS_UPDATE_INTERVAL)
.unwrap_or(true);
if should_emit {
pb_ref.set_length(total);
pb_ref.set_position(downloaded);
last_emit = Some(Instant::now());
}
});
let mut message_callback = Some(move |msg: &str| {
pb_ref.println(msg);
});
package_installer
.install_single(
package,
&version,
&create_entry,
ignore_checksums,
&mut download_progress_callback,
&mut message_callback,
)
.await?;
if let Some((downloaded, total)) = last_progress {
pb.set_length(total);
pb.set_position(downloaded);
}
pb.set_position(pb.length().unwrap_or(0));
pb.finish_with_message("Install complete");
println!("{}", style("Install complete.").green());
Ok(())
}