From 8d05683bd161cd4ae7545e8fe63f2ddc0e8e8b56 Mon Sep 17 00:00:00 2001 From: mxve <68632137+mxve@users.noreply.github.com> Date: Thu, 29 Aug 2024 22:02:19 +0200 Subject: [PATCH] everything tbh --- Cargo.lock | 1 + Cargo.toml | 1 + src/github.rs | 2 +- src/global.rs | 50 ++++++++++++- src/http_async.rs | 11 ++- src/iw4x.rs | 16 ++-- src/main.rs | 182 ++++++++++++++++++--------------------------- src/misc.rs | 32 ++++---- src/self_update.rs | 2 +- src/structs.rs | 12 +++ 10 files changed, 168 insertions(+), 141 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index 326e599..1aa1336 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -26,6 +26,7 @@ dependencies = [ "futures-util", "indicatif", "mslnk", + "once_cell", "openssl", "rand", "reqwest", diff --git a/Cargo.toml b/Cargo.toml index a67e3fa..b8ec7b6 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -17,6 +17,7 @@ serde_json = "1.0.125" rand = "0.8.5" semver = "1.0.23" colored = "2.1.0" +once_cell = "1.19.0" reqwest = { version = "0.12.5", features = ["stream"] } futures-util = "0.3.30" indicatif = "0.17.8" diff --git a/src/github.rs b/src/github.rs index 54907e5..74a67c6 100644 --- a/src/github.rs +++ b/src/github.rs @@ -28,5 +28,5 @@ pub async fn latest_version(owner: &str, repo: &str) -> Version { } pub fn latest_release_url(owner: &str, repo: &str) -> String { - format!("https://github.com/{}/{}/releases/latest", owner, repo) + format!("https://github.com/{owner}/{repo}/releases/latest") } diff --git a/src/global.rs b/src/global.rs index b546946..fc4b33b 100644 --- a/src/global.rs +++ b/src/global.rs @@ -1,5 +1,53 @@ -pub const MASTER: &str = "cdn.alterware.ovh"; +use crate::structs::PrintPrefix; +use colored::Colorize; +use once_cell::sync::Lazy; +use std::collections::HashMap; +use std::sync::Mutex; + pub const GH_OWNER: &str = "mxve"; pub const GH_REPO: &str = "alterware-launcher"; pub const GH_IW4X_OWNER: &str = "iw4x"; pub const GH_IW4X_REPO: &str = "iw4x-client"; + +pub static MASTER: Lazy> = + Lazy::new(|| Mutex::new("https://cdn.alterware.ovh".to_owned())); + +pub static PREFIXES: Lazy> = Lazy::new(|| { + HashMap::from([ + ( + "info", + PrintPrefix { + text: "Info".bright_magenta(), + padding: 8, + }, + ), + ( + "downloading", + PrintPrefix { + text: "Downloading".bright_yellow(), + padding: 1, + }, + ), + ( + "checked", + PrintPrefix { + text: "Checked".bright_blue(), + padding: 5, + }, + ), + ( + "removed", + PrintPrefix { + text: "Removed".bright_red(), + padding: 5, + }, + ), + ( + "error", + PrintPrefix { + text: "Error".red(), + padding: 7, + }, + ), + ]) +}); diff --git a/src/http_async.rs b/src/http_async.rs index 70971d2..eee6559 100644 --- a/src/http_async.rs +++ b/src/http_async.rs @@ -3,7 +3,6 @@ use std::fs::File; use std::io::Write; use std::path::PathBuf; -use colored::*; use futures_util::StreamExt; use indicatif::ProgressBar; use reqwest::Client; @@ -29,18 +28,18 @@ pub async fn download_file_progress( ) .send() .await - .or(Err(format!("Failed to GET from '{}'", &url)))?; + .or(Err(format!("Failed to GET from '{url}'")))?; // Fix for CF shenanigans let total_size = res.content_length().unwrap_or(size); pb.set_length(total_size); let msg = format!( - "[{}] {} ({})", - "Downloading".bright_yellow(), + "{}{} ({})", + misc::prefix("downloading"), misc::cute_path(path), misc::human_readable_bytes(total_size) ); pb.println(&msg); - info!("{}", msg); + info!("{msg}"); pb.set_message(path.file_name().unwrap().to_str().unwrap().to_string()); let mut file = @@ -109,7 +108,7 @@ pub async fn get_body(url: &str) -> Result, String> { .await { Ok(res) => { - debug!("{} {}", res.status().to_string(), url); + debug!("{} {url}", res.status().to_string()); let body = res.bytes().await.or(Err("Failed to get body"))?; Ok(body.to_vec()) } diff --git a/src/iw4x.rs b/src/iw4x.rs index f01ae26..080addf 100644 --- a/src/iw4x.rs +++ b/src/iw4x.rs @@ -3,7 +3,6 @@ use crate::global::*; use crate::http_async; use crate::misc; -use colored::*; use std::{fs, path::Path}; pub fn local_revision(dir: &Path) -> u16 { @@ -23,20 +22,17 @@ pub async fn update(dir: &Path) { let local = local_revision(dir); if remote <= local && dir.join("iw4x.dll").exists() { - crate::println_info!( - "[{}] No files to download for IW4x", - "Info".bright_magenta(), - ); + crate::println_info!("No files to download for IW4x"); return; } crate::println_info!( - "[{}] Downloading outdated or missing files for IW4x", - "Info".bright_magenta() + "{}Downloading outdated or missing files for IW4x", + misc::prefix("info") ); crate::println_info!( - "[{}] {}", - "Downloading".bright_yellow(), + "{}{}", + misc::prefix("downloading"), misc::cute_path(&dir.join("iw4x.dll")) ); http_async::download_file( @@ -48,5 +44,5 @@ pub async fn update(dir: &Path) { ) .await .unwrap(); - fs::write(dir.join(".iw4xrevision"), format!("r{}", remote)).unwrap(); + fs::write(dir.join(".iw4xrevision"), format!("r{remote}")).unwrap(); } diff --git a/src/main.rs b/src/main.rs index dd2b964..37d409a 100644 --- a/src/main.rs +++ b/src/main.rs @@ -30,7 +30,7 @@ fn get_installed_games(games: &Vec) -> Vec<(u32, PathBuf)> { let steamdir = match steamdir_result { Ok(steamdir) => steamdir, Err(error) => { - crate::println_error!("Error locating Steam: {}", error); + crate::println_error!("Error locating Steam: {error}"); return installed_games; } }; @@ -55,7 +55,7 @@ fn create_shortcut(path: &Path, target: &Path, icon: String, args: String) { sl.set_arguments(Some(args)); sl.set_icon_location(Some(icon)); sl.create_lnk(path).unwrap_or_else(|error| { - crate::println_error!("Error creating shortcut.\n{:#?}", error); + crate::println_error!("Error creating shortcut.\n{error}"); }); } else { crate::println_error!("Error creating shortcut."); @@ -70,10 +70,10 @@ fn setup_client_links(game: &Game, game_dir: &Path) { for c in game.client.iter() { create_shortcut( - &game_dir.join(format!("launch-{}.lnk", c)), + &game_dir.join(format!("launch-{c}.lnk")), &game_dir.join("alterware-launcher.exe"), game_dir - .join(format!("{}.exe", c)) + .join(format!("{c}.exe")) .to_string_lossy() .into_owned(), c.to_string(), @@ -86,16 +86,14 @@ fn setup_desktop_links(path: &Path, game: &Game) { println!("Create Desktop shortcut? (Y/n)"); let input = misc::stdin().to_ascii_lowercase(); - if input == "y" || input.is_empty() { + if input != "n" { let desktop = PathBuf::from(&format!("{}\\Desktop", env::var("USERPROFILE").unwrap())); for c in game.client.iter() { create_shortcut( - &desktop.join(format!("{}.lnk", c)), + &desktop.join(format!("{c}.lnk")), &path.join("alterware-launcher.exe"), - path.join(format!("{}.exe", c)) - .to_string_lossy() - .into_owned(), + path.join(format!("{c}.exe")).to_string_lossy().into_owned(), c.to_string(), ); } @@ -103,14 +101,14 @@ fn setup_desktop_links(path: &Path, game: &Game) { } #[cfg(windows)] -async fn auto_install(path: &Path, game: &Game<'_>, master_url: &String) { +async fn auto_install(path: &Path, game: &Game<'_>) { setup_client_links(game, path); setup_desktop_links(path, game); - update(game, path, false, false, None, master_url, None).await; + update(game, path, false, false, None, None).await; } #[cfg(windows)] -async fn windows_launcher_install(games: &Vec>, master_url: &String) { +async fn windows_launcher_install(games: &Vec>) { crate::println_info!( "{}", "No game specified/found. Checking for installed Steam games..".yellow() @@ -124,7 +122,7 @@ async fn windows_launcher_install(games: &Vec>, master_url: &String) { crate::println_info!("Found game in current directory."); crate::println_info!("Installing AlterWare client for {}.", id); let game = games.iter().find(|&g| g.app_id == *id).unwrap(); - auto_install(path, game, master_url).await; + auto_install(path, game).await; crate::println_info!("Installation complete. Please run the launcher again or use a shortcut to launch the game."); std::io::stdin().read_line(&mut String::new()).unwrap(); std::process::exit(0); @@ -134,7 +132,7 @@ async fn windows_launcher_install(games: &Vec>, master_url: &String) { println!("Installed games:"); for (id, path) in installed_games.iter() { - println!("{}: {}", id, path.display()); + println!("{id}: {}", path.display()); } println!("Enter the ID of the game you want to install the AlterWare client for:"); @@ -148,11 +146,16 @@ async fn windows_launcher_install(games: &Vec>, master_url: &String) { let target_path = path.join("alterware-launcher.exe"); if launcher_path != target_path { - fs::copy(launcher_path, target_path).unwrap(); + fs::copy(launcher_path, &target_path).unwrap(); crate::println_info!("Launcher copied to {}", path.display()); } - auto_install(path, game, master_url).await; - crate::println_info!("Installation complete. Please run the launcher again or use a shortcut to launch the game."); + auto_install(path, game).await; + crate::println_info!("Installation complete."); + crate::println_info!("Please use one of the shortcuts (on your Desktop or in the game folder) to play."); + crate::println_info!( + "Alternatively run the launcher again from the game folder {}", + target_path.display() + ); std::io::stdin().read_line(&mut String::new()).unwrap(); break; } @@ -168,7 +171,7 @@ async fn windows_launcher_install(games: &Vec>, master_url: &String) { } fn total_download_size(cdn_info: &Vec, remote_dir: &str) -> u64 { - let remote_dir = format!("{}/", remote_dir); + let remote_dir = format!("{remote_dir}/"); let mut size: u64 = 0; for file in cdn_info { if !file.name.starts_with(&remote_dir) || file.name == "iw4/iw4x.dll" { @@ -186,11 +189,10 @@ async fn update_dir( hashes: &mut HashMap, pb: &ProgressBar, skip_iw4x_sp: bool, - master_url: &String, ) { misc::pb_style_download(pb, false); - let remote_dir_pre = format!("{}/", remote_dir); + let remote_dir_pre = format!("{remote_dir}/"); let mut files_to_download: Vec = vec![]; @@ -215,13 +217,9 @@ async fn update_dir( if hash_local != hash_remote { files_to_download.push(file.clone()); } else { - let msg = format!( - "[{}] {}", - "Checked".bright_blue(), - misc::cute_path(&file_path) - ); + let msg = format!("{}{}", misc::prefix("checked"), misc::cute_path(&file_path)); pb.println(&msg); - info!("{}", msg); + info!("{msg}"); hashes.insert(file_name.to_owned(), file.blake3.to_lowercase()); } } else { @@ -231,22 +229,21 @@ async fn update_dir( if files_to_download.is_empty() { let msg = format!( - "[{}] No files to download for {}", - "Info".bright_magenta(), + "{}No files to download for {}", + misc::prefix("info"), remote_dir ); pb.println(&msg); - info!("{}", msg); + info!("{msg}"); return; } let msg = format!( - "[{}] Downloading outdated or missing files for {}, {}", - "Info".bright_magenta(), - remote_dir, + "{}Downloading outdated or missing files for {remote_dir}, {}", + misc::prefix("info"), misc::human_readable_bytes(total_download_size(&files_to_download, remote_dir)) ); pb.println(&msg); - info!("{}", msg); + info!("{msg}"); misc::pb_style_download(pb, true); let client = reqwest::Client::new(); @@ -258,24 +255,27 @@ async fn update_dir( fs::create_dir_all(parent).unwrap(); } } - + // Prompt user to retry downloads if they fail - let mut download_complete : bool = false; + let mut download_complete: bool = false; while !download_complete { if let Err(err) = http_async::download_file_progress( &client, pb, - &format!("{}/{}", master_url, file.name), + &format!("{}/{}", MASTER.lock().unwrap(), file.name), &file_path, file.size as u64, ) .await { - println!("Failed to download file {}, retry? (Y/n)", file_path.clone().display()); + println!( + "Failed to download file {}, retry? (Y/n)", + file_path.clone().display() + ); let input = misc::stdin().to_ascii_lowercase(); if input == "n" { panic!("{err}"); - } + } }; download_complete = true; } @@ -286,7 +286,7 @@ async fn update_dir( if file_name.ends_with(".exe") { let perms = std::os::unix::fs::PermissionsExt::from_mode(0o755); fs::set_permissions(&file_path, perms).unwrap_or_else(|error| { - crate::println_error!("Error setting permissions for {}: {:#?}", file_name, error); + crate::println_error!("Error setting permissions for {file_name}: {error}"); }) } } @@ -299,15 +299,15 @@ async fn update( bonus_content: bool, force: bool, skip_iw4x_sp: Option, - master_url: &String, ignore_required_files: Option, ) { let skip_iw4x_sp = skip_iw4x_sp.unwrap_or(false); let ignore_required_files = ignore_required_files.unwrap_or(false); - let res = http_async::get_body_string(format!("{}/files.json", master_url).as_str()) - .await - .unwrap(); + let res = + http_async::get_body_string(format!("{}/files.json", MASTER.lock().unwrap()).as_str()) + .await + .unwrap(); let cdn_info: Vec = serde_json::from_str(&res).unwrap(); if !ignore_required_files && !game.required_files_exist(dir) { @@ -323,7 +323,7 @@ async fn update( match fs::remove_file(dir.join(".sha-sums")) { Ok(_) => {} Err(error) => { - crate::println_error!("Error removing .sha-sums: {:#?}", error); + crate::println_error!("Error removing .sha-sums: {error}"); } } } @@ -381,15 +381,15 @@ async fn update( } crate::println_info!( - "[{}] {}", - "Removed".bright_red(), + "{}{}", + misc::prefix("removed"), misc::cute_path(&file_path) ); if fs::remove_file(&file_path).is_err() { crate::println_error!( - "[{}] Couldn't delete {}", - "Error".bright_red(), + "{}Couldn't delete {}", + misc::prefix("error"), misc::cute_path(&file_path) ); } @@ -400,29 +400,11 @@ async fn update( } let pb = ProgressBar::new(0); - update_dir( - &cdn_info, - game.engine, - dir, - &mut hashes, - &pb, - skip_iw4x_sp, - master_url, - ) - .await; + update_dir(&cdn_info, game.engine, dir, &mut hashes, &pb, skip_iw4x_sp).await; if bonus_content && !game.bonus.is_empty() { for bonus in game.bonus.iter() { - update_dir( - &cdn_info, - bonus, - dir, - &mut hashes, - &pb, - skip_iw4x_sp, - master_url, - ) - .await; + update_dir(&cdn_info, bonus, dir, &mut hashes, &pb, skip_iw4x_sp).await; } } @@ -433,37 +415,29 @@ async fn update( if file_path.is_file() { if fs::remove_file(&file_path).is_err() { println!( - "[{}] Couldn't delete {}", - "Error".bright_red(), + "{}Couldn't delete {}", + misc::prefix("error"), misc::cute_path(&file_path) ); } else { - println!( - "[{}] {}", - "Removed".bright_red(), - misc::cute_path(&file_path) - ); + println!("{}{}", misc::prefix("removed"), misc::cute_path(&file_path)); } } else if file_path.is_dir() { if fs::remove_dir_all(&file_path).is_err() { println!( - "[{}] Couldn't delete {}", - "Error".bright_red(), + "{}Couldn't delete {}", + misc::prefix("error"), misc::cute_path(&file_path) ); } else { - println!( - "[{}] {}", - "Removed".bright_red(), - misc::cute_path(&file_path) - ); + println!("{}{}", misc::prefix("removed"), misc::cute_path(&file_path)); } } } let mut hash_file_content = String::new(); for (file, hash) in hashes.iter() { - hash_file_content.push_str(&format!("{} {}\n", hash, file)); + hash_file_content.push_str(&format!("{hash} {file}\n")); } fs::write(dir.join(".hashes"), hash_file_content).unwrap(); } @@ -471,7 +445,7 @@ async fn update( #[cfg(windows)] fn launch(file_path: &PathBuf, args: &str) { println!("\n\nJoin the AlterWare Discord server:\nhttps://discord.gg/2ETE8engZM\n\n"); - crate::println_info!("Launching {} {}", file_path.display(), args); + crate::println_info!("Launching {} {args}", file_path.display()); let exit_status = std::process::Command::new(file_path) .args(args.trim().split(' ')) .current_dir(file_path.parent().unwrap()) @@ -480,7 +454,7 @@ fn launch(file_path: &PathBuf, args: &str) { .wait() .expect("Failed to wait for the game process to finish"); - crate::println_error!("Game exited with {}", exit_status); + crate::println_error!("Game exited with {exit_status}"); if !exit_status.success() { misc::stdin(); } @@ -489,7 +463,7 @@ fn launch(file_path: &PathBuf, args: &str) { #[cfg(unix)] fn launch(file_path: &PathBuf, args: &str) { println!("\n\nJoin the AlterWare Discord server:\nhttps://discord.gg/2ETE8engZM\n\n"); - crate::println_info!("Launching {} {}", file_path.display(), args); + crate::println_info!("Launching {} {args}", file_path.display()); let exit_status = if misc::is_program_in_path("wine") { println!("Found wine, launching game using wine.\nIf you run into issues or want to launch a different way, run {} manually.", file_path.display()); std::process::Command::new("wine") @@ -509,7 +483,7 @@ fn launch(file_path: &PathBuf, args: &str) { .expect("Failed to wait for the game process to finish") }; - crate::println_error!("Game exited with {}", exit_status); + crate::println_error!("Game exited with {exit_status}"); if !exit_status.success() { misc::stdin(); } @@ -610,7 +584,7 @@ async fn main() { "AlterWare Launcher".bright_green(), env!("CARGO_PKG_VERSION") ); - println!("https://github.com/{}/{}", GH_OWNER, GH_REPO); + println!("https://github.com/{GH_OWNER}/{GH_REPO}"); println!( "\n{}{}{}{}{}{}{}", "For ".on_black(), @@ -637,10 +611,9 @@ async fn main() { let mut cfg = config::load(install_path.join("alterware-launcher.json")); - let master_url = if cfg.use_https { - format!("https://{}", MASTER) - } else { - format!("http://{}", MASTER) + if !cfg.use_https { + let mut master_url = MASTER.lock().unwrap(); + *master_url = master_url.replace("https://", "http://"); }; if !arg_bool(&args, "--skip-launcher-update") && !cfg.skip_self_update { @@ -693,9 +666,10 @@ async fn main() { std::process::exit(0); } - let games_json = http_async::get_body_string(format!("{}/games.json", master_url).as_str()) - .await - .unwrap(); + let games_json = + http_async::get_body_string(format!("{}/games.json", MASTER.lock().unwrap()).as_str()) + .await + .unwrap(); let games: Vec = serde_json::from_str(&games_json).unwrap_or_else(|error| { crate::println_error!("Error parsing games.json: {:#?}", error); misc::stdin(); @@ -722,7 +696,7 @@ async fn main() { println!("Multiple clients installed, set the client as the first argument to launch a specific client."); println!("Select a client to launch:"); for (i, c) in g.client.iter().enumerate() { - println!("{}: {}", i, c); + println!("{i}: {c}"); } game = String::from(g.client[misc::stdin().parse::().unwrap()]); break 'main; @@ -759,15 +733,6 @@ async fn main() { } } - if cfg.engine == "iw4" && !cfg.args.contains("+set logfile 1") { - cfg.args = format!("{} +set logfile 1", cfg.args); - config::save_value_s( - install_path.join("alterware-launcher.json"), - "args", - cfg.args.clone(), - ); - } - if cfg.ask_bonus_content && !g.bonus.is_empty() { println!("Download bonus content? (Y/n)"); let input = misc::stdin().to_ascii_lowercase(); @@ -790,12 +755,11 @@ async fn main() { cfg.download_bonus_content, cfg.force_update, Some(&game != "iw4x-sp"), - &master_url, Some(ignore_required_files), ) .await; if !cfg.update_only { - launch(&install_path.join(format!("{}.exe", c)), &cfg.args); + launch(&install_path.join(format!("{c}.exe")), &cfg.args); } return; } @@ -803,9 +767,9 @@ async fn main() { } #[cfg(windows)] - windows_launcher_install(&games, &master_url).await; + windows_launcher_install(&games).await; - crate::println_error!("{}", "Game not found!".bright_red()); + crate::println_error!("Game not found!"); println!("Place the launcher in the game folder, if that doesn't work specify the client on the command line (ex. alterware-launcher.exe iw4-sp)"); println!("Press enter to exit..."); std::io::stdin().read_line(&mut String::new()).unwrap(); diff --git a/src/misc.rs b/src/misc.rs index 1501099..53c52d0 100644 --- a/src/misc.rs +++ b/src/misc.rs @@ -1,7 +1,7 @@ +use indicatif::{ProgressBar, ProgressStyle}; use std::{fs, path::Path}; -use colored::Colorize; -use indicatif::{ProgressBar, ProgressStyle}; +use crate::global; pub fn file_blake3(file: &std::path::Path) -> std::io::Result { let mut blake3 = blake3::Hasher::new(); @@ -31,7 +31,7 @@ pub fn rev_to_int(rev: &str) -> u16 { } pub fn fatal_error(error: &str) { - crate::println_error!("{}: {}", "Error".bright_red(), error); + crate::println_error!("{}: {error}", prefix("error")); stdin(); std::process::exit(1); } @@ -44,7 +44,7 @@ pub fn human_readable_bytes(bytes: u64) -> String { bytes /= 1024.0; i += 1; } - format!("{:.2}{}", bytes, units[i]) + format!("{bytes:.2}{}", units[i]) } pub fn pb_style_download(pb: &ProgressBar, state: bool) { @@ -66,7 +66,7 @@ pub fn cute_path(path: &Path) -> String { pub fn is_program_in_path(program: &str) -> bool { if let Ok(path) = std::env::var("PATH") { for p in path.split(':') { - let p_str = format!("{}/{}", p, program); + let p_str = format!("{p}/{program}"); if fs::metadata(p_str).is_ok() { return true; } @@ -78,7 +78,7 @@ pub fn is_program_in_path(program: &str) -> bool { #[macro_export] macro_rules! println_info { ($($arg:tt)*) => {{ - println!($($arg)*); + println!("{}", format!("{}{}", $crate::misc::prefix("info"), format!($($arg)*))); info!($($arg)*); }} } @@ -86,7 +86,7 @@ macro_rules! println_info { #[macro_export] macro_rules! println_error { ($($arg:tt)*) => {{ - eprintln!($($arg)*); + eprintln!("{}", format!("{}{}", $crate::misc::prefix("error"), format!($($arg)*))); error!($($arg)*); }} } @@ -97,7 +97,7 @@ fn install_dependency(path: &Path, args: &[&str]) { match runas::Command::new(path).args(args).status() { Ok(status) => { if !status.success() && !matches!(status.code(), Some(1638) | Some(3010)) { - println_error!("Error installing dependency {}, {}", path.display(), status); + println_error!("Error installing dependency {}, {status}", path.display()); } else { info!("{} installed successfully", path.display()); } @@ -109,7 +109,7 @@ fn install_dependency(path: &Path, args: &[&str]) { path.display() ); } else { - println_error!("Error running file {}: {}", path.display(), e); + println_error!("Error running file {}: {e}", path.display()); } } } @@ -121,19 +121,19 @@ fn install_dependency(path: &Path, args: &[&str]) { #[cfg(windows)] async fn download_and_install_dependency(url: &str, path: &Path, args: &[&str]) { if !path.exists() { - info!("Downloading {} from {}", path.display(), url); + info!("Downloading {} from {url}", path.display()); if let Some(parent) = path.parent() { match fs::create_dir_all(parent) { Ok(_) => (), Err(e) => { - println_error!("Error creating directory {}: {}", parent.display(), e); + println_error!("Error creating directory {}: {e}", parent.display()); return; } } } match crate::http_async::download_file(url, &std::path::PathBuf::from(path)).await { Ok(_) => info!("Downloaded {}", path.display()), - Err(e) => println_error!("Error downloading {}: {}", path.display(), e), + Err(e) => println_error!("Error downloading {}: {e}", path.display()), } } install_dependency(path, args); @@ -154,7 +154,13 @@ pub async fn install_dependencies(install_path: &Path) { for (name, url, file, args) in redists.iter() { let path = redist_dir.join(file); - println_info!("Installing {}", name); + println_info!("Installing {name}"); download_and_install_dependency(url, &path, args).await; } } + +pub fn prefix(tag_name: &str) -> String { + global::PREFIXES + .get(tag_name) + .map_or_else(|| tag_name.to_string(), |tag| tag.formatted()) +} diff --git a/src/self_update.rs b/src/self_update.rs index 3cef6fa..3d2f9ff 100644 --- a/src/self_update.rs +++ b/src/self_update.rs @@ -102,7 +102,7 @@ pub async fn run(update_only: bool) { // restarting spawns a new console, automation should manually restart on exit code 201 if !update_only { let restart_error = restart().to_string(); - crate::println_error!("Failed to restart launcher: {}", restart_error); + crate::println_error!("Failed to restart launcher: {restart_error}"); println!("Please restart the launcher manually."); misc::stdin(); } diff --git a/src/structs.rs b/src/structs.rs index 8cf7cfe..94552e4 100644 --- a/src/structs.rs +++ b/src/structs.rs @@ -1,3 +1,4 @@ +use colored::*; use std::path::Path; #[derive(serde::Deserialize, serde::Serialize, Clone)] @@ -62,3 +63,14 @@ impl Default for Config { } } } + +pub struct PrintPrefix { + pub text: ColoredString, + pub padding: usize, +} + +impl PrintPrefix { + pub fn formatted(&self) -> String { + format!("[{}]{:width$}", self.text, "", width = self.padding).to_string() + } +}