From 052d176f4ac5139a0048cf89a903149b99b3e2bd Mon Sep 17 00:00:00 2001 From: trivernis Date: Sun, 28 Aug 2022 18:08:29 +0200 Subject: [PATCH] Reimplement logging by utilizing the tracing crate Signed-off-by: trivernis --- Cargo.lock | 147 ++++++++++++++++-------- Cargo.toml | 7 +- src/internal/clean.rs | 9 +- src/internal/detect.rs | 24 ++-- src/internal/initialise.rs | 35 ++---- src/internal/mod.rs | 5 - src/internal/sort.rs | 21 +--- src/internal/structs.rs | 1 - src/internal/sudoloop.rs | 9 +- src/internal/utils.rs | 204 ++-------------------------------- src/logging/fmt_layer.rs | 146 ++++++++++++++++++++++++ src/logging/handler.rs | 177 +++++++++++++++++++++++++++++ src/logging/mod.rs | 69 ++++++++++++ src/main.rs | 41 ++----- src/operations/aur_install.rs | 64 +++++------ src/operations/clean.rs | 31 ++---- src/operations/install.rs | 13 +-- src/operations/search.rs | 20 ++-- src/operations/uninstall.rs | 15 +-- src/operations/upgrade.rs | 27 ++--- 20 files changed, 628 insertions(+), 437 deletions(-) create mode 100644 src/logging/fmt_layer.rs create mode 100644 src/logging/handler.rs create mode 100644 src/logging/mod.rs diff --git a/Cargo.lock b/Cargo.lock index 8b7b4b1..8805615 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -13,13 +13,16 @@ dependencies = [ "color-eyre", "colored", "crossterm", + "dialoguer", "futures", + "indicatif", + "lazy_static", "libc", "native-tls", + "parking_lot", "regex", "rusqlite", "serde", - "spinoff", "textwrap", "tokio", "toml", @@ -257,6 +260,20 @@ dependencies = [ "winapi", ] +[[package]] +name = "console" +version = "0.15.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "89eab4d20ce20cea182308bca13088fecea9c05f6776cf287205d41a0ed3c847" +dependencies = [ + "encode_unicode", + "libc", + "once_cell", + "terminal_size", + "unicode-width", + "winapi", +] + [[package]] name = "core-foundation" version = "0.9.3" @@ -298,6 +315,23 @@ dependencies = [ "winapi", ] +[[package]] +name = "dialoguer" +version = "0.10.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a92e7e37ecef6857fdc0c0c5d42fd5b0938e46590c2183cc92dd310a6d078eb1" +dependencies = [ + "console", + "tempfile", + "zeroize", +] + +[[package]] +name = "encode_unicode" +version = "0.3.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a357d28ed41a50f9c765dbfe56cbc04a64e53e5fc58ba79fbc34c10ef3df831f" + [[package]] name = "encoding_rs" version = "0.8.31" @@ -338,6 +372,12 @@ dependencies = [ "instant", ] +[[package]] +name = "fixedbitset" +version = "0.4.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0ce7134b9999ecaf8bcd65542e436736ef32ddca1b3e06094cb6ec5755203b80" + [[package]] name = "fnv" version = "1.0.7" @@ -625,6 +665,18 @@ dependencies = [ "hashbrown", ] +[[package]] +name = "indicatif" +version = "0.17.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "fcc42b206e70d86ec03285b123e65a5458c92027d1fb2ae3555878b8113b3ddf" +dependencies = [ + "console", + "number_prefix", + "tokio", + "unicode-width", +] + [[package]] name = "instant" version = "0.1.12" @@ -696,12 +748,6 @@ dependencies = [ "cfg-if", ] -[[package]] -name = "maplit" -version = "1.0.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "3e2e65a1a2e43cfcb47a895c4c8b10d1f4a61097f9f254f183aee60cad9c651d" - [[package]] name = "matchers" version = "0.1.0" @@ -768,6 +814,22 @@ dependencies = [ "tempfile", ] +[[package]] +name = "num_cpus" +version = "1.13.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "19e64526ebdee182341572e50e9ad03965aa510cd94427a4549448f285e957a1" +dependencies = [ + "hermit-abi", + "libc", +] + +[[package]] +name = "number_prefix" +version = "0.4.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "830b246a0e5f20af87141b25c173cd1b609bd7779a4617d6ec582abaf90870f3" + [[package]] name = "object" version = "0.29.0" @@ -856,10 +918,13 @@ version = "0.9.3" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "09a279cbf25cb0757810394fbc1e359949b59e348145c643a939a525692e6929" dependencies = [ + "backtrace", "cfg-if", "libc", + "petgraph", "redox_syscall", "smallvec", + "thread-id", "windows-sys", ] @@ -869,6 +934,16 @@ version = "2.1.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "d4fd5641d01c8f18a23da7b6fe29298ff4b55afcccdf78973b24cf3175fee32e" +[[package]] +name = "petgraph" +version = "0.6.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e6d5014253a1331579ce62aa67443b4a658c5e7dd03d4bc6d302b94474888143" +dependencies = [ + "fixedbitset", + "indexmap", +] + [[package]] name = "pin-project-lite" version = "0.2.9" @@ -1030,12 +1105,6 @@ version = "0.1.21" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "7ef03e0a2b150c7a90d01faf6254c9c48a41e95fb2a8c2ac1c6f0d2b9aefc342" -[[package]] -name = "rustversion" -version = "1.0.9" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "97477e48b4cf8603ad5f7aaf897467cf42ab4218a38ef76fb14c2d6773a6d6a8" - [[package]] name = "ryu" version = "1.0.11" @@ -1194,46 +1263,12 @@ dependencies = [ "winapi", ] -[[package]] -name = "spinoff" -version = "0.5.3" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "3c139aa6a2b4ed01ef761dfd593eb5b02218dbf35a3a0f10940b72f5bfe70426" -dependencies = [ - "colored", - "maplit", - "once_cell", - "strum", -] - [[package]] name = "strsim" version = "0.10.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "73473c0e59e6d5812c5dfe2a064a6444949f089e20eec9a2e5506596494e4623" -[[package]] -name = "strum" -version = "0.24.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "063e6045c0e62079840579a7e47a355ae92f60eb74daaf156fb1e84ba164e63f" -dependencies = [ - "strum_macros", -] - -[[package]] -name = "strum_macros" -version = "0.24.3" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1e385be0d24f186b4ce2f9982191e7101bb737312ad61c1f2f984f34bcf85d59" -dependencies = [ - "heck", - "proc-macro2", - "quote", - "rustversion", - "syn", -] - [[package]] name = "syn" version = "1.0.99" @@ -1310,6 +1345,17 @@ dependencies = [ "syn", ] +[[package]] +name = "thread-id" +version = "4.0.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5fdfe0627923f7411a43ec9ec9c39c3a9b4151be313e0922042581fb6c9b717f" +dependencies = [ + "libc", + "redox_syscall", + "winapi", +] + [[package]] name = "thread_local" version = "1.1.4" @@ -1345,6 +1391,7 @@ dependencies = [ "libc", "memchr", "mio", + "num_cpus", "once_cell", "pin-project-lite", "signal-hook-registry", @@ -1738,3 +1785,9 @@ checksum = "80d0f4e272c85def139476380b12f9ac60926689dd2e01d4923222f40580869d" dependencies = [ "winapi", ] + +[[package]] +name = "zeroize" +version = "1.5.7" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c394b5bd0c6f669e7275d9c20aa90ae064cb22e75a1cad54e1b34088034b149f" diff --git a/Cargo.toml b/Cargo.toml index 2112777..6f29b97 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -39,12 +39,15 @@ futures = "0.3.23" tracing = "0.1.36" tracing-subscriber = { version = "0.3.15", features = ["env-filter"] } textwrap = "0.15.0" -spinoff = "0.5.3" crossterm = "0.25.0" toml = "0.5.9" clap_complete = "3.2.4" color-eyre = { version = "0.6.2", features = ["issue-url", "url"] } +indicatif = { version = "0.17.0", features = ["tokio"] } +lazy_static = "1.4.0" +parking_lot = { version = "0.12.1", features = ["deadlock_detection"] } +dialoguer = "0.10.2" [dependencies.tokio] version = "1.20.1" -features = ["rt", "io-std", "io-util", "process", "time", "macros", "tracing", "fs"] +features = ["rt", "rt-multi-thread", "io-std", "io-util", "process", "time", "macros", "tracing", "fs"] diff --git a/src/internal/clean.rs b/src/internal/clean.rs index 5a45d51..85bcd8e 100644 --- a/src/internal/clean.rs +++ b/src/internal/clean.rs @@ -1,13 +1,10 @@ use regex::Regex; -use crate::{log, Options}; - /// Strips packages from versioning and other extraneous information. -pub fn clean(a: &[String], options: Options) -> Vec { +pub fn clean(a: &[String]) -> Vec { // Strip versioning from package names let r = Regex::new(r"(\S+)((?:>=|<=|>|<|=\W)\S+$)").unwrap(); let mut cleaned: Vec = vec![]; - let verbosity = options.verbosity; // Push cleaned package names to vector for b in a { @@ -19,9 +16,7 @@ pub fn clean(a: &[String], options: Options) -> Vec { } } - if verbosity >= 1 { - log!("Cleaned: {:?}\nInto: {:?}", a, cleaned); - } + tracing::debug!("Cleaned: {:?}\nInto: {:?}", a, cleaned); cleaned } diff --git a/src/internal/detect.rs b/src/internal/detect.rs index 64c7a25..3b667f9 100644 --- a/src/internal/detect.rs +++ b/src/internal/detect.rs @@ -2,12 +2,16 @@ use crate::internal::commands::ShellCommand; use crate::internal::config; use crate::internal::error::SilentUnwrap; use crate::internal::exit_code::AppExitCode; -use crate::{prompt, spinner, warn}; +use crate::logging::get_logger; +use crate::prompt; + +use super::prompt_sudo_single; /// Searches the filesystem for .pacnew files and helps the user deal with them. pub async fn detect() { - // Start spinner - let sp = spinner!("Scanning for pacnew files"); + prompt_sudo_single().await.expect("Sudo prompt failed"); + let pb = get_logger().new_progress_spinner(); + pb.set_message("Scanning for pacnew files"); let mut pacnew = vec![]; @@ -27,11 +31,13 @@ pub async fn detect() { // If pacnew files are found, warn the user and prompt to pacdiff if pacnew.is_empty() { - sp.stop_bold("No pacnew files found"); + pb.finish_with_message("No pacnew files found"); + get_logger().reset_output_type(); } else { - sp.stop_bold("It appears that at least one program you have installed / upgraded has installed a .pacnew config file. These are created when you have modified a program's configuration, and a package upgrade could not automatically merge the new file."); + pb.finish_with_message("It appears that at least one program you have installed / upgraded has installed a .pacnew config file. These are created when you have modified a program's configuration, and a package upgrade could not automatically merge the new file."); + get_logger().reset_output_type(); - let choice = prompt!(default false, "Would you like Amethyst to run pacdiff to deal with this? You can always deal with this later by running `sudo pacdiff`"); + let choice = prompt!(default no, "Would you like Amethyst to run pacdiff to deal with this? You can always deal with this later by running `sudo pacdiff`"); if choice { let config = config::read(); if config.base.pacdiff_warn { @@ -41,9 +47,9 @@ pub async fn detect() { .await .silent_unwrap(AppExitCode::PacmanError); } else { - warn!("Pacdiff uses vimdiff by default to edit files for merging. You can focus panes by mousing over them and pressing left click, and scroll up and down using your mouse's scroll wheel (or the arrow keys). To exit vimdiff, press the following key combination: ESC, :qa!, ENTER"); - warn!("You can surpress this warning in the future by setting `pacdiff_warn` to \"false\" in ~/.config/ame/config.toml"); - let cont = prompt!(default false, "Continue?"); + tracing::warn!("Pacdiff uses vimdiff by default to edit files for merging. You can focus panes by mousing over them and pressing left click, and scroll up and down using your mouse's scroll wheel (or the arrow keys). To exit vimdiff, press the following key combination: ESC, :qa!, ENTER"); + tracing::warn!("You can surpress this warning in the future by setting `pacdiff_warn` to \"false\" in ~/.config/ame/config.toml"); + let cont = prompt!(default no, "Continue?"); if cont { ShellCommand::pacdiff() .elevated() diff --git a/src/internal/initialise.rs b/src/internal/initialise.rs index 9d09a36..db4305b 100644 --- a/src/internal/initialise.rs +++ b/src/internal/initialise.rs @@ -2,19 +2,16 @@ use std::env; use std::path::Path; use std::process::Command; -use crate::{crash, internal::exit_code::AppExitCode, log, Options}; +use crate::{crash, internal::exit_code::AppExitCode}; -pub fn init(options: Options) { - let verbosity = options.verbosity; +pub fn init() { let homedir = env::var("HOME").unwrap(); if !Path::new(&format!("{}/.local/share/ame", homedir)).exists() { let r = std::fs::create_dir_all(format!("{}/.local/share/ame", homedir)); match r { Ok(_) => { - if verbosity >= 1 { - log!("Created path: {}/.local/share/ame", homedir); - } + tracing::debug!("Created path: {}/.local/share/ame", homedir); } Err(e) => { crash!( @@ -31,9 +28,7 @@ pub fn init(options: Options) { let r = std::fs::create_dir_all(format!("{}/.cache/ame", homedir)); match r { Ok(_) => { - if verbosity >= 1 { - log!("Created path: {}/.cache/ame", homedir); - } + tracing::debug!("Created path: {}/.cache/ame", homedir); } Err(e) => { crash!( @@ -48,9 +43,7 @@ pub fn init(options: Options) { let r = std::fs::remove_dir_all(format!("{}/.cache/ame", homedir)); match r { Ok(_) => { - if verbosity >= 1 { - log!("Removing cache: {}/.cache/ame", homedir); - } + tracing::debug!("Removing cache: {}/.cache/ame", homedir); } Err(e) => { crash!( @@ -64,9 +57,7 @@ pub fn init(options: Options) { let r2 = std::fs::create_dir_all(format!("{}/.cache/ame", homedir)); match r2 { Ok(_) => { - if verbosity >= 1 { - log!("Created path: {}/.cache/ame", homedir); - } + tracing::debug!("Created path: {}/.cache/ame", homedir); } Err(e2) => { crash!( @@ -86,9 +77,7 @@ pub fn init(options: Options) { .status(); match r { Ok(_) => { - if verbosity >= 1 { - log!("Set correct permissions for path: {}/.cache/ame", homedir); - } + tracing::debug!("Set correct permissions for path: {}/.cache/ame", homedir); } Err(e) => { crash!( @@ -106,12 +95,10 @@ pub fn init(options: Options) { .status(); match r { Ok(_) => { - if verbosity >= 1 { - log!( - "Set correct permissions for path: {}/.local/share/ame", - homedir - ); - } + tracing::debug!( + "Set correct permissions for path: {}/.local/share/ame", + homedir + ); } Err(e) => { crash!( diff --git a/src/internal/mod.rs b/src/internal/mod.rs index 9ba022c..18d9952 100644 --- a/src/internal/mod.rs +++ b/src/internal/mod.rs @@ -45,11 +45,6 @@ pub fn uwu_enabled() -> bool { config.extra.uwu.unwrap_or(false) } -pub fn uwu_debug_enabled() -> bool { - let config = config::read(); - config.extra.uwu_debug.unwrap_or(false) -} - /// Checks if we're running in a tty. If we do we can assume that /// the output can safely be colorized. pub fn is_tty() -> bool { diff --git a/src/internal/sort.rs b/src/internal/sort.rs index 4608010..1f55bb0 100644 --- a/src/internal/sort.rs +++ b/src/internal/sort.rs @@ -1,7 +1,7 @@ use std::process::{Command, Stdio}; use crate::internal::{clean, rpc, structs}; -use crate::{log, Options}; +use crate::Options; use super::error::SilentUnwrap; use super::exit_code::AppExitCode; @@ -11,13 +11,10 @@ pub async fn sort(input: &[String], options: Options) -> structs::Sorted { let mut repo_packages: Vec = vec![]; let mut aur_packages: Vec = vec![]; let mut missing_packages: Vec = vec![]; - let verbosity = options.verbosity; - let packages = clean(input, options); + let packages = clean(input); - if verbosity >= 1 { - log!("Sorting: {:?}", packages.join(" ")); - } + tracing::debug!("Sorting: {:?}", packages.join(" ")); for package in packages { let rs = Command::new("pacman") @@ -28,23 +25,17 @@ pub async fn sort(input: &[String], options: Options) -> structs::Sorted { .expect("Something has gone wrong"); if let Some(0) = rs.code() { - if verbosity >= 1 { - log!("{} found in repos", package); - } + tracing::debug!("{} found in repos", package); repo_packages.push(package.to_string()); } else if rpc::rpcinfo(&package) .await .silent_unwrap(AppExitCode::RpcError) .is_some() { - if verbosity >= 1 { - log!("{} found in AUR", package); - } + tracing::debug!("{} found in AUR", package); aur_packages.push(package.to_string()); } else { - if verbosity >= 1 { - log!("{} not found", package); - } + tracing::debug!("{} not found", package); missing_packages.push(package.to_string()); } } diff --git a/src/internal/structs.rs b/src/internal/structs.rs index ed632c3..9c3f075 100644 --- a/src/internal/structs.rs +++ b/src/internal/structs.rs @@ -18,7 +18,6 @@ impl Sorted { #[derive(Clone, Debug, Copy)] /// Options to be passed down to internal functions pub struct Options { - pub verbosity: usize, pub noconfirm: bool, pub asdeps: bool, } diff --git a/src/internal/sudoloop.rs b/src/internal/sudoloop.rs index 2e2c7d1..d2a7a4b 100644 --- a/src/internal/sudoloop.rs +++ b/src/internal/sudoloop.rs @@ -2,6 +2,8 @@ use std::time::Duration; use crate::ShellCommand; +use super::error::AppResult; + /// Loop sudo so it doesn't time out #[tracing::instrument(level = "trace")] pub async fn start_sudoloop() { @@ -16,5 +18,10 @@ pub async fn start_sudoloop() { #[tracing::instrument(level = "trace")] async fn prompt_sudo() { - while ShellCommand::sudo().arg("-v").wait_success().await.is_err() {} + while prompt_sudo_single().await.is_err() {} +} + +#[tracing::instrument(level = "trace")] +pub async fn prompt_sudo_single() -> AppResult<()> { + ShellCommand::sudo().arg("-v").wait_success().await } diff --git a/src/internal/utils.rs b/src/internal/utils.rs index 90359f2..d32e170 100644 --- a/src/internal/utils.rs +++ b/src/internal/utils.rs @@ -1,36 +1,8 @@ -use colored::Colorize; -use std::io; -use std::io::Write; use std::process::exit; -use std::time::UNIX_EPOCH; -use textwrap::wrap; use crate::internal::exit_code::AppExitCode; -use crate::{internal, uwu}; - -const OK_SYMBOL: &str = "❖"; -const ERR_SYMBOL: &str = "X"; -const WARN_SYMBOL: &str = "!"; -const PROMPT_SYMBOL: &str = "?"; - -const PROMPT_YN_DEFAULT_TRUE: &str = "[Y/n]"; -const PROMPT_YN_DEFAULT_FALSE: &str = "[y/N]"; - -#[macro_export] -/// Macro for printing a message to stdout. -macro_rules! info { - ($($arg:tt)+) => { - $crate::internal::utils::log_info(format!($($arg)+)) - } -} - -#[macro_export] -/// Macro for printing a warning message non-destructively. -macro_rules! warn { - ($($arg:tt)+) => { - $crate::internal::utils::log_warn(format!($($arg)+)) - } -} +use crate::logging::get_logger; +use crate::logging::handler::PromptDefault; #[macro_export] /// Macro for printing a message and destructively exiting @@ -40,179 +12,27 @@ macro_rules! crash { } } -#[macro_export] -/// Macro for logging to stderr -macro_rules! log { - ($($arg:tt)+) => { - $crate::internal::utils::log_debug(format!($($arg)+)) - } -} - #[macro_export] /// Macro for prompting the user with a yes/no question. macro_rules! prompt { - (default $default:expr, $($arg:tt)+) => { - $crate::internal::utils::prompt_yn(format!($($arg)+), $default) - } -} - -#[macro_export] -/// Macro for creating a spinner. -macro_rules! spinner { - ($($arg:tt)+) => { - $crate::internal::utils::spinner_fn(format!($($arg)+)) - } -} - -/// Print a formatted message to stdout. -pub fn log_info(msg: String) { - let msg = if internal::uwu_enabled() { - uwu!(&msg) - } else { - msg + (default yes, $($arg:tt)+) => { + $crate::internal::utils::prompt_yn(format!($($arg)+), $crate::logging::handler::PromptDefault::Yes) }; - - let opts = textwrap::Options::new(crossterm::terminal::size().unwrap().0 as usize - 2) - .subsequent_indent(" "); - - println!( - "{} {}", - OK_SYMBOL.purple(), - wrap(&msg, opts).join("\n").bold() - ); -} - -/// Print a non-destructive warning message -pub fn log_warn(msg: String) { - let msg = if internal::uwu_enabled() { - uwu!(&msg) - } else { - msg + (default no, $($arg:tt)+) => { + $crate::internal::utils::prompt_yn(format!($($arg)+), $crate::logging::handler::PromptDefault::No) }; - - let opts = textwrap::Options::new(crossterm::terminal::size().unwrap().0 as usize - 2) - .subsequent_indent(" "); - - println!( - "{} {}", - WARN_SYMBOL.yellow(), - wrap(&msg, opts).join("\n").yellow().bold() - ); + (no default, $($arg:tt)+) => { + $crate::internal::utils::prompt_yn(format!($($arg)+), $crate::logging::handler::PromptDefault::None) + } } /// Logs a message and exits the program with the given exit code. pub fn log_and_crash(msg: String, exit_code: AppExitCode) -> ! { - let msg = if internal::uwu_enabled() { - uwu!(&msg) - } else { - msg - }; - - let opts = textwrap::Options::new(crossterm::terminal::size().unwrap().0 as usize - 2) - .subsequent_indent(" "); - - println!( - "{} {}", - ERR_SYMBOL.red().bold(), - wrap(&msg, opts).join("\n").red().bold() - ); + tracing::error!(msg); exit(exit_code as i32); } -/// Logs a message to stderr with timestamp -pub fn log_debug(msg: String) { - let msg = if internal::uwu_enabled() && internal::uwu_debug_enabled() { - uwu!(&msg) - } else { - msg - }; - - eprintln!( - "{} {}", - std::time::SystemTime::now() - .duration_since(UNIX_EPOCH) - .unwrap() - .as_secs(), - msg - ); -} - /// Prompts the user for a yes/no answer. -pub fn prompt_yn(question: String, default_true: bool) -> bool { - let yn_prompt = if default_true { - PROMPT_YN_DEFAULT_TRUE - } else { - PROMPT_YN_DEFAULT_FALSE - }; - - let question = if internal::uwu_enabled() { - uwu!(&question) - } else { - question - }; - - let opts = textwrap::Options::new(crossterm::terminal::size().unwrap().0 as usize - 2) - .subsequent_indent(" "); - - print!( - "{} {} {}: ", - PROMPT_SYMBOL.purple(), - wrap(&question, opts).join("\n").bold(), - yn_prompt - ); - - let mut yn: String = String::new(); - - io::stdout().flush().ok(); - io::stdin().read_line(&mut yn).unwrap(); - - if yn.trim().to_lowercase() == "n" || yn.trim().to_lowercase() == "no" { - false - } else if yn.trim().to_lowercase() == "y" || yn.trim().to_lowercase() == "yes" { - true - } else { - default_true - } -} - -pub struct Spinner { - spinner: spinoff::Spinner, -} - -impl Spinner { - pub fn stop_bold(self, text: &str) { - let text = if internal::uwu_enabled() { - uwu!(text) - } else { - text.to_string() - }; - - let opts = textwrap::Options::new(crossterm::terminal::size().unwrap().0 as usize - 2) - .subsequent_indent(" "); - - let symbol = format!("{}", OK_SYMBOL.purple()); - let text = format!("{}", wrap(&text, opts).join("\n").bold()); - - self.spinner.stop_and_persist(&symbol, &text); - } -} - -/// Returns a spinner that can be used to display progress. -pub fn spinner_fn(text: String) -> Spinner { - let text = if internal::uwu_enabled() { - uwu!(&text) - } else { - text - }; - - let opts = textwrap::Options::new(crossterm::terminal::size().unwrap().0 as usize - 2) - .subsequent_indent(" "); - - Spinner { - spinner: spinoff::Spinner::new( - spinoff::Spinners::Line, - format!("{}", wrap(&text, opts).join("\n").bold()), - spinoff::Color::Magenta, - ), - } +pub fn prompt_yn(question: String, prompt_default: PromptDefault) -> bool { + get_logger().prompt(question, prompt_default) } diff --git a/src/logging/fmt_layer.rs b/src/logging/fmt_layer.rs new file mode 100644 index 0000000..2c187c7 --- /dev/null +++ b/src/logging/fmt_layer.rs @@ -0,0 +1,146 @@ +use colored::Colorize; +use std::collections::HashMap; +use std::sync::Arc; +use tracing_subscriber::registry::LookupSpan; + +use tracing::field::Visit; +use tracing::{span, Level, Metadata, Subscriber}; +use tracing_subscriber::Layer; + +use super::handler::LogHandler; +use super::Verbosity; + +const ENABLED_MODULES: &[&str] = &["ame"]; + +pub struct AmeFormatLayer { + logger: Arc, +} + +impl AmeFormatLayer { + pub fn new(logger: Arc) -> Self { + Self { logger } + } + + fn is_level_loggable(&self, level: &Level) -> bool { + self.logger.is_loggable(Verbosity::from_level(level)) + } + + fn is_enabled(&self, metadata: &Metadata) -> bool { + let level = metadata.level(); + if !self.is_level_loggable(level) { + false + } else if let Some(module_path) = metadata.module_path() { + ENABLED_MODULES.iter().any(|m| module_path.starts_with(m)) + } else { + false + } + } + + fn log(&self, msg: String, level: &Level) { + match Verbosity::from_level(level) { + Verbosity::Error => self.logger.log_error(msg), + Verbosity::Warning => self.logger.log_warning(msg), + Verbosity::Info => self.logger.log_info(msg), + Verbosity::Debug => self.logger.log_debug(msg), + Verbosity::Trace => self.logger.log_trace(msg), + } + } +} + +impl LookupSpan<'a>> Layer for AmeFormatLayer { + /// When entering a span + fn on_new_span( + &self, + attrs: &span::Attributes<'_>, + _id: &span::Id, + _ctx: tracing_subscriber::layer::Context<'_, S>, + ) { + let metadata = attrs.metadata(); + if self.is_enabled(metadata) { + let mut visitor = ValueDebugStorage::default(); + attrs.record(&mut visitor); + let fields: Vec = visitor + .values + .into_iter() + .map(|(k, v)| format!("{k} = {v}")) + .collect(); + let mut fields_str = fields.join("\n "); + + if !fields_str.is_empty() { + fields_str = format!("\n {fields_str}"); + } + + if let Some(module) = metadata.module_path() { + self.log( + format!( + "{} {}::{} {}", + "ENTER".italic(), + module, + metadata.name(), + fields_str.dimmed() + ), + metadata.level(), + ) + } else { + self.log( + format!( + "{} {} {}", + "ENTER".italic(), + metadata.name(), + fields_str.dimmed() + ), + metadata.level(), + ) + } + } + } + + fn on_exit(&self, id: &span::Id, ctx: tracing_subscriber::layer::Context<'_, S>) { + let span = ctx.span(id).unwrap(); + let metadata = span.metadata(); + + if self.is_enabled(metadata) { + if let Some(module) = metadata.module_path() { + self.log( + format!("{} {}::{}", "EXIT".italic(), module, metadata.name(),), + metadata.level(), + ); + } else { + self.log( + format!("{} {}", "EXIT".italic(), metadata.name()), + metadata.level(), + ); + } + } + } + + fn on_event( + &self, + event: &tracing::Event<'_>, + _ctx: tracing_subscriber::layer::Context<'_, S>, + ) { + let metadata = event.metadata(); + + if self.is_enabled(metadata) { + let mut visitor = ValueDebugStorage::default(); + event.record(&mut visitor); + let mut values = visitor.values; + + if let Some(msg) = values.remove("message") { + self.log(msg, metadata.level()) + } + } + } +} + +#[derive(Default)] +pub struct ValueDebugStorage { + pub values: HashMap, +} + +impl Visit for ValueDebugStorage { + fn record_debug(&mut self, field: &tracing::field::Field, value: &dyn std::fmt::Debug) { + self.values + .insert(field.name().to_string(), format!("{:?}", value)); + } +} diff --git a/src/logging/handler.rs b/src/logging/handler.rs new file mode 100644 index 0000000..968ac06 --- /dev/null +++ b/src/logging/handler.rs @@ -0,0 +1,177 @@ +use colored::Colorize; +use indicatif::{MultiProgress, ProgressBar}; +use std::{ + sync::{atomic::AtomicBool, Arc}, + time::Duration, +}; + +use crate::uwu; +use dialoguer::Confirm; + +use super::Verbosity; +use parking_lot::RwLock; + +const OK_SYMBOL: &str = "❖"; +const ERR_SYMBOL: &str = "X"; +const WARN_SYMBOL: &str = "!"; +const DEBUG_SYMBOL: &str = "⌘"; +const TRACE_SYMBOL: &str = "🗲"; +const PROMPT_SYMBOL: &str = "?"; + +pub struct LogHandler { + level: Arc>, + output_type: Arc>, + uwu_enabled: Arc, +} + +impl Default for LogHandler { + fn default() -> Self { + Self { + level: Arc::new(RwLock::new(Verbosity::Info)), + output_type: Arc::new(RwLock::new(OutputType::Stderr)), + uwu_enabled: Arc::new(AtomicBool::new(false)), + } + } +} + +#[allow(unused)] +pub enum OutputType { + Stdout, + Stderr, + MultiProgress(Arc), + Progress(Arc), +} + +#[allow(unused)] +pub enum PromptDefault { + Yes, + No, + None, +} + +impl LogHandler { + pub fn log_error(&self, msg: String) { + if self.is_loggable(Verbosity::Error) { + let msg = self.preformat_msg(msg); + let msg = format!("{} {}", ERR_SYMBOL.red().bold(), msg.bold().red()); + self.log(msg); + } + } + + pub fn log_warning(&self, msg: String) { + if self.is_loggable(Verbosity::Warning) { + let msg = self.preformat_msg(msg); + let msg = format!("{} {}", WARN_SYMBOL.yellow(), msg.yellow().bold()); + self.log(msg); + } + } + + pub fn log_info(&self, msg: String) { + if self.is_loggable(Verbosity::Info) { + let msg = self.preformat_msg(msg); + let msg = format!("{} {}", OK_SYMBOL.purple(), msg.bold()); + self.log(msg); + } + } + + pub fn log_debug(&self, msg: String) { + if self.is_loggable(Verbosity::Debug) { + let msg = self.preformat_msg(msg); + let msg = format!("{} {}", DEBUG_SYMBOL.blue(), msg); + + self.log(msg); + } + } + + pub fn log_trace(&self, msg: String) { + if self.is_loggable(Verbosity::Trace) { + let msg = self.preformat_msg(msg); + let msg = format!("{} {}", TRACE_SYMBOL.cyan(), msg.dimmed()); + self.log(msg); + } + } + + /// Prompts the user with a question and a default selection + pub fn prompt(&self, question: String, p_default: PromptDefault) -> bool { + let question = self.preformat_msg(question); + let question = format!("{} {}", PROMPT_SYMBOL.purple(), question.bold()); + let mut confirm = Confirm::new(); + confirm.with_prompt(question); + + match p_default { + PromptDefault::Yes => { + confirm.default(true); + } + PromptDefault::No => { + confirm.default(false); + } + PromptDefault::None => {} + } + confirm.interact().unwrap() + } + + pub fn set_verbosity(&self, level: Verbosity) { + (*self.level.write()) = level; + } + + pub fn reset_output_type(&self) { + self.set_output_type(OutputType::Stdout); + } + + /// Creates a new progress spinner and registers it on the log handler + pub fn new_progress_spinner(&self) -> Arc { + let progress_bar = ProgressBar::new_spinner().with_message("Scanning for pacnew files"); + progress_bar.enable_steady_tick(Duration::from_millis(250)); + let pb = Arc::new(progress_bar); + self.set_progress_bar(pb.clone()); + + pb + } + + /// Registeres a progress bar on the log handler + pub fn set_progress_bar(&self, pb: Arc) { + self.set_output_type(OutputType::Progress(pb)) + } + + /// Sets the output type of the log handler to either stdout/stderr or a progress bar + pub fn set_output_type(&self, output: OutputType) { + (*self.output_type.write()) = output; + } + + pub fn set_uwu_enabled(&self, enabled: bool) { + self.uwu_enabled + .store(enabled, std::sync::atomic::Ordering::Relaxed); + } + + pub(crate) fn is_loggable(&self, level: Verbosity) -> bool { + (*self.level.read()) >= level + } + + fn preformat_msg(&self, msg: String) -> String { + let msg = self.apply_uwu(msg); + let opts = textwrap::Options::new(crossterm::terminal::size().unwrap().0 as usize - 2) + .subsequent_indent(" "); + + textwrap::wrap(&msg, opts).join("\n") + } + + fn apply_uwu(&self, msg: String) -> String { + if self.uwu_enabled.load(std::sync::atomic::Ordering::Relaxed) { + uwu!(msg) + } else { + msg + } + } + + fn log(&self, msg: String) { + let output_type = self.output_type.read(); + match &*output_type { + OutputType::Stdout => println!("{}", msg), + OutputType::Stderr => eprintln!("{}", msg), + OutputType::MultiProgress(m) => { + let _ = m.println(msg); + } + OutputType::Progress(p) => p.println(msg), + }; + } +} diff --git a/src/logging/mod.rs b/src/logging/mod.rs new file mode 100644 index 0000000..b93210e --- /dev/null +++ b/src/logging/mod.rs @@ -0,0 +1,69 @@ +use std::sync::Arc; + +use lazy_static::lazy_static; +use tracing::Level; +use tracing_subscriber::prelude::__tracing_subscriber_SubscriberExt; +use tracing_subscriber::Registry; + +mod fmt_layer; +use fmt_layer::AmeFormatLayer; + +use crate::internal::uwu_enabled; + +use self::handler::LogHandler; +pub mod handler; + +#[derive(Clone, Copy, Debug, PartialEq, Eq, PartialOrd, Ord)] +pub enum Verbosity { + #[allow(dead_code)] + Error = 0, + #[allow(dead_code)] + Warning = 1, + Info = 2, + Debug = 3, + Trace = 4, +} + +impl From for Verbosity { + fn from(num_verbosity: usize) -> Self { + match num_verbosity { + 0 => Self::Info, + 1 => Self::Debug, + 2 => Self::Trace, + _ => Self::Info, + } + } +} + +impl Verbosity { + fn from_level(l: &Level) -> Self { + match *l { + Level::ERROR => Self::Error, + Level::WARN => Self::Warning, + Level::INFO => Self::Info, + Level::DEBUG => Self::Debug, + Level::TRACE => Self::Trace, + } + } +} + +/// Initializes the tracing logger +/// Can be used for debug purposes _or_ verbose output +pub fn init_logger(verbosity: Verbosity) { + let logger = get_logger(); + logger.set_verbosity(verbosity); + logger.set_uwu_enabled(uwu_enabled()); + let ame_layer = AmeFormatLayer::new(logger); + + let subscriber = Registry::default().with(ame_layer); + tracing::subscriber::set_global_default(subscriber).unwrap(); +} + +/// Returns the global logger instance +pub fn get_logger() -> Arc { + lazy_static! { + static ref LOGGER: Arc = Arc::new(LogHandler::default()); + } + + Arc::clone(&LOGGER) +} diff --git a/src/main.rs b/src/main.rs index 33c097c..80366a9 100644 --- a/src/main.rs +++ b/src/main.rs @@ -10,34 +10,32 @@ use crate::internal::exit_code::AppExitCode; use crate::internal::{init, sort, start_sudoloop, structs::Options}; use clap_complete::{Generator, Shell}; use std::str::FromStr; -use tracing_subscriber::fmt::format::FmtSpan; -use tracing_subscriber::EnvFilter; mod args; mod builder; mod internal; +mod logging; mod operations; +use logging::init_logger; -#[tokio::main(flavor = "current_thread")] +#[tokio::main] async fn main() { color_eyre::install().unwrap(); if unsafe { libc::geteuid() } == 0 { crash!( AppExitCode::RunAsRoot, "Running amethyst as root is disallowed as it can lead to system breakage. Instead, amethyst will prompt you when it needs superuser permissions"); } - init_logger(); let args: Args = Args::parse(); + init_logger(args.verbose.into()); - let verbosity = args.verbose; let noconfirm = args.no_confirm; let options = Options { - verbosity, noconfirm, asdeps: false, }; - init(options); + init(); if args.sudoloop { start_sudoloop().await; @@ -49,11 +47,11 @@ async fn main() { Operation::Search(search_args) => cmd_search(search_args, options).await, Operation::Query(query_args) => cmd_query(query_args).await, Operation::Upgrade(upgrade_args) => { - info!("Performing system upgrade"); + tracing::info!("Performing system upgrade"); operations::upgrade(upgrade_args, options).await; } Operation::Clean => { - info!("Removing orphaned packages"); + tracing::info!("Removing orphaned packages"); operations::clean(options).await; } Operation::Info(info_args) => cmd_info(info_args).await, @@ -64,21 +62,6 @@ async fn main() { detect().await; } -/// Initializes the tracing logger -/// Can be used for debug purposes _or_ verbose output -fn init_logger() { - const DEFAULT_ENV_FILTER: &str = "warn"; - let filter_string = std::env::var("AME_LOG").unwrap_or_else(|_| DEFAULT_ENV_FILTER.to_string()); - let env_filter = - EnvFilter::from_str(&*filter_string).expect("failed to parse env filter string"); - tracing_subscriber::fmt::SubscriberBuilder::default() - .with_env_filter(env_filter) - .with_writer(std::io::stdout) - .with_span_events(FmtSpan::NEW | FmtSpan::CLOSE) - .compact() - .init(); -} - #[tracing::instrument(level = "trace")] async fn cmd_install(args: InstallArgs, options: Options) { let packages = args.packages; @@ -113,14 +96,14 @@ async fn cmd_install(args: InstallArgs, options: Options) { .split_whitespace() .collect::>() .join(", "); - info!("You have .pacnew files in /etc ({pacnew_files}) that you haven't removed or acted upon, it is recommended you do that now" ); + tracing::info!("You have .pacnew files in /etc ({pacnew_files}) that you haven't removed or acted upon, it is recommended you do that now" ); } } #[tracing::instrument(level = "trace")] async fn cmd_remove(args: RemoveArgs, options: Options) { let packages = args.packages; - info!("Uninstalling packages: {}", &packages.join(", ")); + tracing::info!("Uninstalling packages: {}", &packages.join(", ")); operations::uninstall(packages, options).await; } @@ -129,16 +112,16 @@ async fn cmd_search(args: SearchArgs, options: Options) { let query_string = args.search; if args.aur { - info!("Searching AUR for {}", &query_string); + tracing::info!("Searching AUR for {}", &query_string); operations::aur_search(&query_string, args.by, options).await; } if args.repo { - info!("Searching repos for {}", &query_string); + tracing::info!("Searching repos for {}", &query_string); operations::search(&query_string, options).await; } if !args.aur && !args.repo { - info!("Searching AUR and repos for {}", &query_string); + tracing::info!("Searching AUR and repos for {}", &query_string); operations::search(&query_string, options).await; operations::aur_search(&query_string, args.by, options).await; } diff --git a/src/operations/aur_install.rs b/src/operations/aur_install.rs index d582479..5fa719b 100644 --- a/src/operations/aur_install.rs +++ b/src/operations/aur_install.rs @@ -9,7 +9,7 @@ use crate::internal::commands::ShellCommand; use crate::internal::error::SilentUnwrap; use crate::internal::exit_code::AppExitCode; use crate::internal::rpc::rpcinfo; -use crate::{crash, info, internal::fs_utils::rmdir_recursive, log, prompt, Options}; +use crate::{crash, internal::fs_utils::rmdir_recursive, prompt, Options}; /// Installs a given list of packages from the aur #[tracing::instrument(level = "trace")] @@ -17,14 +17,11 @@ use crate::{crash, info, internal::fs_utils::rmdir_recursive, log, prompt, Optio pub async fn aur_install(packages: Vec, options: Options) { let url = crate::internal::rpc::URL; let cachedir = format!("{}/.cache/ame/", env::var("HOME").unwrap()); - let verbosity = options.verbosity; let noconfirm = options.noconfirm; - if verbosity >= 1 { - log!("Installing from AUR: {:?}", &packages); - } + tracing::debug!("Installing from AUR: {:?}", &packages); - info!("Installing packages {} from the AUR", packages.join(", ")); + tracing::info!("Installing packages {} from the AUR", packages.join(", ")); for package_name in packages { let rpcres = rpcinfo(&package_name) @@ -38,11 +35,9 @@ pub async fn aur_install(packages: Vec, options: Options) { let package = rpcres.unwrap(); let pkg_name = package.metadata.name; - if verbosity >= 1 { - log!("Cloning {} into cachedir", pkg_name); - } + tracing::debug!("Cloning {} into cachedir", pkg_name); - info!("Cloning package source"); + tracing::info!("Cloning package source"); set_current_dir(Path::new(&cachedir)).unwrap(); ShellCommand::git() @@ -52,36 +47,31 @@ pub async fn aur_install(packages: Vec, options: Options) { .await .silent_unwrap(AppExitCode::GitError); - if verbosity >= 1 { - log!( - "Cloned {} into cachedir, moving on to resolving dependencies", - pkg_name - ); - log!( - "Raw dependencies for package {} are:\n{:?}", - pkg_name, - package.depends, - ); - log!( - "Raw makedepends for package {} are:\n{:?}", - pkg_name, - package.make_depends.join(", "), - ); - } + tracing::debug!( + "Cloned {} into cachedir, moving on to resolving dependencies", + pkg_name + ); + tracing::debug!( + "Raw dependencies for package {} are:\n{:?}", + pkg_name, + package.depends, + ); + tracing::debug!( + "Raw makedepends for package {} are:\n{:?}", + pkg_name, + package.make_depends.join(", "), + ); // dep sorting - log!("Sorting dependencies"); + tracing::debug!("Sorting dependencies"); let sorted = crate::internal::sort(&package.depends, options).await; - log!("Sorting make dependencies"); + tracing::debug!("Sorting make dependencies"); let md_sorted = crate::internal::sort(&package.make_depends, options).await; - if verbosity >= 1 { - log!("Sorted dependencies for {} are:\n{:?}", pkg_name, &sorted); - log!("Sorted makedepends for {} are:\n{:?}", pkg_name, &md_sorted); - } + tracing::debug!("Sorted dependencies for {} are:\n{:?}", pkg_name, &sorted); + tracing::debug!("Sorted makedepends for {} are:\n{:?}", pkg_name, &md_sorted); let newopts = Options { - verbosity, noconfirm, asdeps: true, }; @@ -96,7 +86,7 @@ pub async fn aur_install(packages: Vec, options: Options) { } if !noconfirm { - let p1 = prompt!(default false, + let p1 = prompt!(default no, "Would you like to review {}'s PKGBUILD (and any .install files if present)?", pkg_name, ); @@ -126,7 +116,7 @@ pub async fn aur_install(packages: Vec, options: Options) { .silent_unwrap(AppExitCode::Other); } - let p2 = prompt!(default true, "Would you still like to install {}?", pkg_name); + let p2 = prompt!(default yes, "Would you still like to install {}?", pkg_name); if !p2 { fs::remove_dir_all(format!("{}/{}", cachedir, pkg_name)) .await @@ -137,7 +127,7 @@ pub async fn aur_install(packages: Vec, options: Options) { } // dep installing - info!("Moving on to install dependencies"); + tracing::info!("Moving on to install dependencies"); if !sorted.repo.is_empty() { crate::operations::install(sorted.repo, newopts).await; @@ -157,7 +147,7 @@ pub async fn aur_install(packages: Vec, options: Options) { } // package building and installing - info!("Building time!"); + tracing::info!("Building time!"); set_current_dir(format!("{}/{}", cachedir, pkg_name)).unwrap(); let status = ShellCommand::makepkg() .args(makepkg_args) diff --git a/src/operations/clean.rs b/src/operations/clean.rs index 82af6c1..4444ead 100644 --- a/src/operations/clean.rs +++ b/src/operations/clean.rs @@ -1,18 +1,15 @@ use tokio::process::Command; use crate::crash; -use crate::info; use crate::internal::commands::ShellCommand; use crate::internal::error::SilentUnwrap; use crate::internal::exit_code::AppExitCode; -use crate::log; use crate::prompt; use crate::Options; /// Removes orphaned packages and cache #[tracing::instrument(level = "trace")] pub async fn clean(options: Options) { - let verbosity = options.verbosity; let noconfirm = options.noconfirm; // Check for orphaned packages @@ -24,17 +21,17 @@ pub async fn clean(options: Options) { if orphaned_packages.stdout.as_str().is_empty() { // If no orphaned packages found, do nothing - info!("No orphaned packages found"); + tracing::info!("No orphaned packages found"); } else { // Prompt users whether to remove orphaned packages - info!( + tracing::info!( "Removing orphans would uninstall the following packages: \n{}", &orphaned_packages.stdout ); - let cont = prompt!(default false, "Continue?"); + let cont = prompt!(default no, "Continue?"); if !cont { // If user doesn't want to continue, break - info!("Exiting"); + tracing::info!("Exiting"); std::process::exit(AppExitCode::PacmanError as i32); } @@ -52,9 +49,7 @@ pub async fn clean(options: Options) { } } - if verbosity >= 1 { - log!("Removing orphans: {:?}", orphaned_packages_vec); - } + tracing::debug!("Removing orphans: {:?}", orphaned_packages_vec); // Remove orphaned packages let pacman_result = ShellCommand::pacman() @@ -66,7 +61,7 @@ pub async fn clean(options: Options) { if pacman_result.success() { // If pacman succeeded, notify user - info!("Successfully removed orphans"); + tracing::info!("Successfully removed orphans"); } else { // If pacman failed, crash crash!(AppExitCode::PacmanError, "Failed to remove orphans",); @@ -74,7 +69,7 @@ pub async fn clean(options: Options) { } // Prompt the user whether to clear the Amethyst cache - let clear_ame_cache = prompt!(default false, "Clear Amethyst's internal PKGBUILD cache?"); + let clear_ame_cache = prompt!(default no, "Clear Amethyst's internal PKGBUILD cache?"); if clear_ame_cache { // Remove ~/.cache/ame Command::new("rm") @@ -91,7 +86,7 @@ pub async fn clean(options: Options) { let clear_pacman_cache = if noconfirm { true } else { - prompt!(default false, "Also clear pacman's package cache?") + prompt!(default no, "Also clear pacman's package cache?") }; if clear_pacman_cache { @@ -107,9 +102,7 @@ pub async fn clean(options: Options) { paccache_args.push("--noconfirm"); } - if verbosity >= 1 { - log!("Clearing using `paccache -r`"); - } + tracing::debug!("Clearing using `paccache -r`"); // Clear pacman's cache (keeping latest 3 versions of installed packages) Command::new("sudo") @@ -127,9 +120,7 @@ pub async fn clean(options: Options) { .await .unwrap(); - if verbosity >= 1 { - log!("Clearing using `pacman -Sc`"); - } + tracing::debug!("Clearing using `pacman -Sc`"); // Clear pacman's cache (keeping only installed packages) let pacman_result = ShellCommand::pacman() @@ -141,7 +132,7 @@ pub async fn clean(options: Options) { if pacman_result.success() { // If pacman succeeded, notify user - info!("Successfully cleared package cache"); + tracing::info!("Successfully cleared package cache"); } else { // If pacman failed, crash crash!(AppExitCode::PacmanError, "Failed to clear package cache",); diff --git a/src/operations/install.rs b/src/operations/install.rs index 1123cbc..2e21039 100644 --- a/src/operations/install.rs +++ b/src/operations/install.rs @@ -1,16 +1,13 @@ use crate::builder::pacman::PacmanInstallBuilder; use crate::internal::exit_code::AppExitCode; -use crate::{crash, info, log, Options}; +use crate::{crash, Options}; #[tracing::instrument(level = "trace")] pub async fn install(packages: Vec, options: Options) { - info!("Installing packages {} from repos", &packages.join(", ")); - let verbosity = options.verbosity; + tracing::info!("Installing packages {} from repos", &packages.join(", ")); if !packages.is_empty() { - if verbosity >= 1 { - log!("Installing from repos: {:?}", &packages); - } + tracing::debug!("Installing from repos: {:?}", &packages); let result = PacmanInstallBuilder::from_options(options) .packages(packages.clone()) @@ -25,8 +22,6 @@ pub async fn install(packages: Vec, options: Options) { ); } - if verbosity >= 1 { - log!("Installing packages: {:?} was successful", &packages); - } + tracing::debug!("Installing packages: {:?} was successful", &packages); } } diff --git a/src/operations/search.rs b/src/operations/search.rs index e51ad45..4165533 100644 --- a/src/operations/search.rs +++ b/src/operations/search.rs @@ -4,12 +4,11 @@ use crate::internal::commands::ShellCommand; use crate::internal::error::SilentUnwrap; use crate::internal::exit_code::AppExitCode; use crate::internal::rpc::rpcsearch; -use crate::{log, Options}; +use crate::Options; use aur_rpc::SearchField; #[tracing::instrument(level = "trace")] pub async fn aur_search(query: &str, by_field: Option, options: Options) { - let verbosity = options.verbosity; let packages = rpcsearch(query.to_string(), by_field.map(SearchBy::into)) .await .silent_unwrap(AppExitCode::RpcError); @@ -22,14 +21,11 @@ pub async fn aur_search(query: &str, by_field: Option, options: Option ) } - if verbosity >= 1 { - log!("Found {total_results} resuls for \"{query}\" in AUR",); - } + tracing::debug!("Found {total_results} resuls for \"{query}\" in AUR",); } #[tracing::instrument(level = "trace")] pub async fn repo_search(query: &str, options: Options) { - let verbosity = options.verbosity; let output = ShellCommand::pacman() .arg("-Ss") .arg(query) @@ -38,13 +34,11 @@ pub async fn repo_search(query: &str, options: Options) { .silent_unwrap(AppExitCode::PacmanError) .stdout; - if verbosity >= 1 { - log!( - "Found {} results for \"{}\" in repos", - &output.split('\n').count() / 2, - &query - ); - } + tracing::debug!( + "Found {} results for \"{}\" in repos", + &output.split('\n').count() / 2, + &query + ); println!("{}", output) } diff --git a/src/operations/uninstall.rs b/src/operations/uninstall.rs index 24029ee..fe89e3d 100644 --- a/src/operations/uninstall.rs +++ b/src/operations/uninstall.rs @@ -5,7 +5,7 @@ use tokio::fs; use crate::internal::commands::ShellCommand; use crate::internal::error::SilentUnwrap; use crate::internal::exit_code::AppExitCode; -use crate::{log, Options}; +use crate::Options; #[tracing::instrument(level = "trace")] pub async fn uninstall(packages: Vec, options: Options) { @@ -15,10 +15,7 @@ pub async fn uninstall(packages: Vec, options: Options) { if options.noconfirm { pacman_args.push("--noconfirm"); } - let verbosity = options.verbosity; - if verbosity >= 1 { - log!("Uninstalling: {:?}", &packages); - } + tracing::debug!("Uninstalling: {:?}", &packages); ShellCommand::pacman() .elevated() @@ -27,9 +24,7 @@ pub async fn uninstall(packages: Vec, options: Options) { .await .silent_unwrap(AppExitCode::PacmanError); - if verbosity >= 1 { - log!("Uninstalling packages: {:?} exited with code 0", &packages); - } + tracing::debug!("Uninstalling packages: {:?} exited with code 0", &packages); for package in packages { if Path::new(&format!( @@ -39,9 +34,7 @@ pub async fn uninstall(packages: Vec, options: Options) { )) .exists() { - if verbosity >= 1 { - log!("Old cache directory found, deleting"); - } + tracing::debug!("Old cache directory found, deleting"); fs::remove_dir_all(Path::new(&format!( "{}/.cache/ame/{}", env::var("HOME").unwrap(), diff --git a/src/operations/upgrade.rs b/src/operations/upgrade.rs index dbc63b5..1dae44c 100644 --- a/src/operations/upgrade.rs +++ b/src/operations/upgrade.rs @@ -5,7 +5,7 @@ use crate::internal::error::SilentUnwrap; use crate::internal::exit_code::AppExitCode; use crate::internal::rpc::rpcinfo; use crate::operations::aur_install::aur_install; -use crate::{info, log, prompt, warn, Options}; +use crate::{prompt, Options}; /// Upgrades all installed packages #[tracing::instrument(level = "trace")] @@ -16,11 +16,14 @@ pub async fn upgrade(args: UpgradeArgs, options: Options) { if args.aur { upgrade_aur(options).await; } + if !args.aur && !args.repo { + upgrade_repo(options).await; + upgrade_aur(options).await; + } } #[tracing::instrument(level = "trace")] async fn upgrade_repo(options: Options) { - let verbosity = options.verbosity; let noconfirm = options.noconfirm; let mut pacman_args = vec!["-Syu"]; @@ -28,9 +31,7 @@ async fn upgrade_repo(options: Options) { pacman_args.push("--noconfirm"); } - if verbosity >= 1 { - log!("Upgrading repo packages"); - } + tracing::debug!("Upgrading repo packages"); let pacman_result = ShellCommand::pacman() .elevated() @@ -40,13 +41,13 @@ async fn upgrade_repo(options: Options) { .silent_unwrap(AppExitCode::PacmanError); if pacman_result.success() { - info!("Successfully upgraded repo packages"); + tracing::info!("Successfully upgraded repo packages"); } else { - let continue_upgrading = prompt!(default false, + let continue_upgrading = prompt!(default no, "Failed to upgrade repo packages, continue to upgrading AUR packages?", ); if !continue_upgrading { - info!("Exiting"); + tracing::info!("Exiting"); std::process::exit(AppExitCode::PacmanError as i32); } } @@ -54,11 +55,7 @@ async fn upgrade_repo(options: Options) { #[tracing::instrument(level = "trace")] async fn upgrade_aur(options: Options) { - let verbosity = options.verbosity; - - if verbosity >= 1 { - log!("Upgrading AUR packages"); - } + tracing::debug!("Upgrading AUR packages"); let non_native_pkgs = PacmanQueryBuilder::foreign() .color(PacmanColor::Never) @@ -84,13 +81,13 @@ async fn upgrade_aur(options: Options) { aur_upgrades.push(pkg.name); } } else { - warn!("Could not find the remote package for {}", pkg.name); + tracing::warn!("Could not find the remote package for {}", pkg.name); } } if !aur_upgrades.is_empty() { aur_install(aur_upgrades, options).await; } else { - info!("No upgrades available for installed AUR packages"); + tracing::info!("No upgrades available for installed AUR packages"); } }