From 5fd050584e80687452a6dde798824cd312e1b74a Mon Sep 17 00:00:00 2001 From: Chawye Hsu Date: Tue, 10 Dec 2024 11:06:40 +0800 Subject: [PATCH] feat(hok): add global `--verbose` flag and switch to use `tracing_subscriber` for enhanced logging Signed-off-by: Chawye Hsu --- Cargo.lock | 142 ++++++++++++++++++++++++++++++++++++++----------- Cargo.toml | 3 +- src/cmd/mod.rs | 86 ++++++++++++++++++++++++------ src/lib.rs | 27 ++-------- 4 files changed, 184 insertions(+), 74 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index 20d9638..d77e254 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -216,6 +216,16 @@ dependencies = [ "clap_derive", ] +[[package]] +name = "clap-verbosity-flag" +version = "3.0.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "54381ae56ad222eea3f529c692879e9c65e07945ae48d3dc4d1cb18dbec8cf44" +dependencies = [ + "clap 4.5.23", + "tracing-core", +] + [[package]] name = "clap_builder" version = "4.5.23" @@ -486,19 +496,6 @@ version = "0.3.6" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "a357d28ed41a50f9c765dbfe56cbc04a64e53e5fc58ba79fbc34c10ef3df831f" -[[package]] -name = "env_logger" -version = "0.8.4" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a19187fea3ac7e84da7dacf48de0c45d63c6a76f9490dae389aead16c243fce3" -dependencies = [ - "atty", - "humantime", - "log", - "regex", - "termcolor", -] - [[package]] name = "errno" version = "0.3.9" @@ -713,21 +710,16 @@ version = "0.1.0-beta.7" dependencies = [ "anyhow", "clap 4.5.23", + "clap-verbosity-flag", "clap_complete", "crossterm", - "env_logger", "indicatif", "libscoop", "regex", "remove_dir_all", + "tracing-subscriber", ] -[[package]] -name = "humantime" -version = "2.1.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9a3a5bfb195931eeb336b2a7b4d761daec841b97f947d34394601737a7bba5e4" - [[package]] name = "iana-time-zone" version = "0.1.57" @@ -941,6 +933,15 @@ version = "0.4.19" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "b06a4cde4c0f271a446782e3eff8de789548ce57dbc8eca9292c27f4a42004b4" +[[package]] +name = "matchers" +version = "0.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8263075bb86c5a1b1427b5ae862e8889656f126e9f77c484496e8b47cf5c5558" +dependencies = [ + "regex-automata 0.1.10", +] + [[package]] name = "md-5" version = "0.10.5" @@ -996,6 +997,16 @@ dependencies = [ "winapi", ] +[[package]] +name = "nu-ansi-term" +version = "0.46.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "77a8165726e8236064dbb45459242600304b42a5ea24ee2948e18e023bf7ba84" +dependencies = [ + "overload", + "winapi", +] + [[package]] name = "num-traits" version = "0.2.16" @@ -1099,6 +1110,12 @@ version = "6.5.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "4d5d9eb14b174ee9aa2ef96dc2b94637a2d4b6e7cb873c7e171f0c20c6cf3eac" +[[package]] +name = "overload" +version = "0.1.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b15813163c1d831bf4a13c3610c05c0d03b39feb07f7e09fa234dac9b15aaf39" + [[package]] name = "parking_lot" version = "0.12.1" @@ -1277,8 +1294,17 @@ checksum = "81bc1d4caf89fac26a70747fe603c130093b53c773888797a6329091246d651a" dependencies = [ "aho-corasick", "memchr", - "regex-automata", - "regex-syntax", + "regex-automata 0.3.6", + "regex-syntax 0.7.4", +] + +[[package]] +name = "regex-automata" +version = "0.1.10" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "6c230d73fb8d8c1b9c0b3135c5142a8acee3a0558fb8db5cf1cb65f8d7862132" +dependencies = [ + "regex-syntax 0.6.29", ] [[package]] @@ -1289,9 +1315,15 @@ checksum = "fed1ceff11a1dddaee50c9dc8e4938bd106e9d89ae372f192311e7da498e3b69" dependencies = [ "aho-corasick", "memchr", - "regex-syntax", + "regex-syntax 0.7.4", ] +[[package]] +name = "regex-syntax" +version = "0.6.29" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f162c6dd7b008981e4d40210aca20b4bd0f9b60ca9271061b07f78537722f2e1" + [[package]] name = "regex-syntax" version = "0.7.4" @@ -1417,6 +1449,15 @@ dependencies = [ "digest", ] +[[package]] +name = "sharded-slab" +version = "0.1.7" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f40ca3c46823713e0d4209592e8d6e826aa57e928f09752619fc696c499637f6" +dependencies = [ + "lazy_static", +] + [[package]] name = "signal-hook" version = "0.3.17" @@ -1513,15 +1554,6 @@ dependencies = [ "winapi", ] -[[package]] -name = "termcolor" -version = "1.2.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "be55cf8942feac5c765c2c993422806843c9a9a45d4d5c407ad6dd2ea95eb9b6" -dependencies = [ - "winapi-util", -] - [[package]] name = "terminal_size" version = "0.4.1" @@ -1558,6 +1590,16 @@ dependencies = [ "syn", ] +[[package]] +name = "thread_local" +version = "1.1.8" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8b9ef9bad013ada3808854ceac7b46812a6465ba368859a37e2100283d2d719c" +dependencies = [ + "cfg-if", + "once_cell", +] + [[package]] name = "tinytemplate" version = "1.2.1" @@ -1612,6 +1654,36 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "e672c95779cf947c5311f83787af4fa8fffd12fb27e4993211a84bdfd9610f9c" dependencies = [ "once_cell", + "valuable", +] + +[[package]] +name = "tracing-log" +version = "0.2.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ee855f1f400bd0e5c02d150ae5de3840039a3f54b025156404e34c23c03f47c3" +dependencies = [ + "log", + "once_cell", + "tracing-core", +] + +[[package]] +name = "tracing-subscriber" +version = "0.3.19" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e8189decb5ac0fa7bc8b96b7cb9b2701d60d48805aca84a238004d665fcc4008" +dependencies = [ + "matchers", + "nu-ansi-term", + "once_cell", + "regex", + "sharded-slab", + "smallvec", + "thread_local", + "tracing", + "tracing-core", + "tracing-log", ] [[package]] @@ -1664,6 +1736,12 @@ version = "0.2.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "711b9620af191e0cdc7468a8d14e709c3dcdb115b36f838e601583af800a370a" +[[package]] +name = "valuable" +version = "0.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "830b7e5d4d90034032940e4ace0d9a9a057e7a45cd94e6c007832e39edb82f6d" + [[package]] name = "vcpkg" version = "0.2.15" diff --git a/Cargo.toml b/Cargo.toml index 5dee13b..95f668c 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -17,12 +17,13 @@ path = "src/lib.rs" [dependencies] anyhow = "1.0" clap = { version = "4.5", features = ["wrap_help", "cargo", "derive"] } +clap-verbosity-flag = { version = "3.0.1", features = ["tracing"], default-features = false } clap_complete = "4.5.38" crossterm = "0.28" -env_logger = "0.8.3" indicatif = "0.17.5" regex = "1.5.3" remove_dir_all = "0.7.0" +tracing-subscriber = { version = "0.3.19", features = ["env-filter"] } [dependencies.libscoop] version = "0.1.0-beta.7" diff --git a/src/cmd/mod.rs b/src/cmd/mod.rs index ced9760..3fcfcdd 100644 --- a/src/cmd/mod.rs +++ b/src/cmd/mod.rs @@ -1,4 +1,9 @@ use clap::{crate_description, crate_name, crate_version, Parser, Subcommand}; +use clap_verbosity_flag::Verbosity; +use libscoop::Session; +use tracing_subscriber::{ + filter::LevelFilter, layer::SubscriberExt, util::SubscriberInitExt, EnvFilter, +}; mod bucket; mod cache; @@ -18,13 +23,16 @@ mod update; mod upgrade; use crate::Result; -use libscoop::Session; #[derive(Parser)] #[command( name = crate_name!(), version = crate_version!(), about = crate_description!(), + long_about = format!("{} + +If you find any bugs or have a feature request, please open an issue on +GitHub: https://github.com/chawyehsu/hok/issues", crate_description!()), subcommand_required = true, arg_required_else_help = true, max_term_width = 100, @@ -36,6 +44,10 @@ use libscoop::Session; pub struct Cli { #[command(subcommand)] pub command: Command, + + /// The verbosity level + #[command(flatten)] + verbose: Verbosity, } #[derive(Subcommand)] @@ -63,25 +75,65 @@ pub enum Command { } /// CLI entry point -pub fn start(session: &Session) -> Result<()> { +pub fn start() -> Result<()> { let args = Cli::parse(); + setup_logger(args.verbose.tracing_level_filter())?; + + let session = Session::default(); + let user_agent = format!("Scoop/1.0 (+https://scoop.sh/) Hok/{}", crate_version!()); + let _ = session.set_user_agent(&user_agent); match args.command { - Command::Bucket(args) => bucket::execute(args, session), - Command::Cache(args) => cache::execute(args, session), - Command::Cat(args) => cat::execute(args, session), - Command::Cleanup(args) => cleanup::execute(args, session), + Command::Bucket(args) => bucket::execute(args, &session), + Command::Cache(args) => cache::execute(args, &session), + Command::Cat(args) => cat::execute(args, &session), + Command::Cleanup(args) => cleanup::execute(args, &session), Command::Completions(args) => completions::execute(args), - Command::Config(args) => config::execute(args, session), - Command::Hold(args) => hold::execute(args, session), - Command::Home(args) => home::execute(args, session), - Command::Info(args) => info::execute(args, session), - Command::Install(args) => install::execute(args, session), - Command::List(args) => list::execute(args, session), - Command::Search(args) => search::execute(args, session), - Command::Unhold(args) => unhold::execute(args, session), - Command::Uninstall(args) => uninstall::execute(args, session), - Command::Update(args) => update::execute(args, session), - Command::Upgrade(args) => upgrade::execute(args, session), + Command::Config(args) => config::execute(args, &session), + Command::Hold(args) => hold::execute(args, &session), + Command::Home(args) => home::execute(args, &session), + Command::Info(args) => info::execute(args, &session), + Command::Install(args) => install::execute(args, &session), + Command::List(args) => list::execute(args, &session), + Command::Search(args) => search::execute(args, &session), + Command::Unhold(args) => unhold::execute(args, &session), + Command::Uninstall(args) => uninstall::execute(args, &session), + Command::Update(args) => update::execute(args, &session), + Command::Upgrade(args) => upgrade::execute(args, &session), + } +} + +fn setup_logger(level_filter: LevelFilter) -> Result<()> { + // filter for low-level/depedency logs + let low_level_filter = match level_filter { + LevelFilter::OFF => LevelFilter::OFF, + LevelFilter::ERROR => LevelFilter::ERROR, + LevelFilter::WARN => LevelFilter::WARN, + LevelFilter::INFO => LevelFilter::WARN, + LevelFilter::DEBUG => LevelFilter::INFO, + LevelFilter::TRACE => LevelFilter::TRACE, + }; + + let mut layer_env_filter = EnvFilter::builder() + .with_default_directive(level_filter.into()) + .from_env()?; + + // The custom `HOK_LOG_LEVEL` environment variable was introduced to set the + // log level for hok since the first version. + if let Ok(level) = std::env::var("HOK_LOG_LEVEL") { + layer_env_filter = layer_env_filter.add_directive(format!("libscoop={level}").parse()?); } + + layer_env_filter = layer_env_filter + // add low-level filter for git2 + .add_directive(format!("git2={}", low_level_filter).parse()?); + + let layer_fmt = tracing_subscriber::fmt::layer().without_time(); + + tracing_subscriber::registry() + .with(layer_env_filter) + .with(layer_fmt) + .init(); + + Ok(()) } diff --git a/src/lib.rs b/src/lib.rs index 4223cad..51f55bf 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -2,7 +2,6 @@ use crossterm::{ style::{Color, Print, SetForegroundColor}, ExecutableCommand, }; -use libscoop::Session; use std::{fmt::Display, io}; mod cmd; @@ -11,16 +10,6 @@ mod util; type Result = anyhow::Result; -fn create_logger() -> Result<()> { - let env = env_logger::Env::default() - .filter_or("HOK_LOG_LEVEL", "error") - .write_style("never"); - match env_logger::try_init_from_env(env) { - Ok(_) => Ok(()), - Err(e) => Err(e.into()), - } -} - fn error(input: &T) -> io::Result<()> { let mut stderr = io::stderr(); stderr @@ -32,8 +21,8 @@ fn error(input: &T) -> io::Result<()> { Ok(()) } -fn report(err: anyhow::Error) { - let _ = error(&err); +fn report(err: &anyhow::Error) { + let _ = error(err); if let Some(cause) = err.source() { eprintln!("\nCaused by:"); for (i, e) in std::iter::successors(Some(cause), |e| e.source()).enumerate() { @@ -43,15 +32,5 @@ fn report(err: anyhow::Error) { } pub fn create_app() -> bool { - let _ = create_logger(); - let session = Session::default(); - let _ = session.set_user_agent("Scoop/1.0 (+http://scoop.sh/) Hok/0.1.0"); - - match cmd::start(&session) { - Ok(_) => false, - Err(e) => { - report(e); - true - } - } + cmd::start().inspect_err(report).is_err() }