mirror of
https://github.com/Hopiu/lychee.git
synced 2026-05-20 11:31:53 +00:00
* Upgrade to 2024 edition * Revert expr_2021 -> expr * resolve merge conflicts * make lint happy
171 lines
4.3 KiB
Rust
171 lines
4.3 KiB
Rust
use log::Level;
|
|
use log::LevelFilter;
|
|
use serde::Deserialize;
|
|
|
|
/// Control the verbosity of the CLI output
|
|
///
|
|
/// By default this will only report errors and warnings.
|
|
///
|
|
/// To control the verbosity, use the `-v` and `-q` flags on the command line:
|
|
/// - `-qq` silence output
|
|
/// - `-q` mute warnings
|
|
/// - `-v` show info
|
|
/// - `-vv` show debug
|
|
/// - `-vvv` show trace
|
|
#[derive(clap::Args, Debug, Default, Clone, PartialEq, Eq)]
|
|
#[command(arg_required_else_help = true)]
|
|
pub(crate) struct Verbosity {
|
|
/// Pass many times for more log output
|
|
///
|
|
/// By default, it'll only report errors and warnings.
|
|
/// Passing `-v` one time also prints info,
|
|
/// `-vv` enables debugging logging, `-vvv` trace.
|
|
#[arg(
|
|
long,
|
|
short = 'v',
|
|
action = clap::ArgAction::Count,
|
|
global = true,
|
|
help = Self::verbose_help(),
|
|
long_help = Self::verbose_long_help(),
|
|
conflicts_with = "quiet",
|
|
)]
|
|
verbose: u8,
|
|
|
|
#[arg(
|
|
long,
|
|
short = 'q',
|
|
action = clap::ArgAction::Count,
|
|
global = true,
|
|
help = Self::quiet_help(),
|
|
long_help = Self::quiet_long_help(),
|
|
conflicts_with = "verbose",
|
|
)]
|
|
quiet: u8,
|
|
}
|
|
|
|
impl Verbosity {
|
|
/// Get the log level.
|
|
///
|
|
/// `None` means all output is disabled.
|
|
pub(crate) const fn log_level(&self) -> Level {
|
|
level_enum(self.verbosity())
|
|
}
|
|
|
|
/// Get the log level filter.
|
|
pub(crate) fn log_level_filter(&self) -> LevelFilter {
|
|
level_enum(self.verbosity()).to_level_filter()
|
|
}
|
|
|
|
#[allow(clippy::cast_possible_wrap)]
|
|
const fn verbosity(&self) -> i8 {
|
|
level_value(log::Level::Warn) - (self.quiet as i8) + (self.verbose as i8)
|
|
}
|
|
|
|
const fn verbose_help() -> &'static str {
|
|
"Set verbosity level; more output per occurrence (e.g. `-v` or `-vv`)"
|
|
}
|
|
|
|
const fn verbose_long_help() -> Option<&'static str> {
|
|
None
|
|
}
|
|
|
|
const fn quiet_help() -> &'static str {
|
|
"Less output per occurrence (e.g. `-q` or `-qq`)"
|
|
}
|
|
|
|
const fn quiet_long_help() -> Option<&'static str> {
|
|
None
|
|
}
|
|
}
|
|
|
|
#[cfg(test)]
|
|
impl Verbosity {
|
|
pub(crate) const fn debug() -> Self {
|
|
Self {
|
|
#[allow(clippy::cast_sign_loss)]
|
|
verbose: level_value(log::Level::Debug) as u8,
|
|
quiet: 0,
|
|
}
|
|
}
|
|
}
|
|
|
|
// Implement Deserialize for `Verbosity`
|
|
// This can be deserialized from a string like "warn", "warning", or "Warning"
|
|
// for example
|
|
impl<'de> Deserialize<'de> for Verbosity {
|
|
#[allow(clippy::cast_sign_loss)]
|
|
fn deserialize<D>(deserializer: D) -> Result<Self, D::Error>
|
|
where
|
|
D: serde::Deserializer<'de>,
|
|
{
|
|
let s = String::deserialize(deserializer)?;
|
|
let level = match s.to_lowercase().as_str() {
|
|
"error" => Level::Error,
|
|
"warn" | "warning" => Level::Warn,
|
|
"info" => Level::Info,
|
|
"debug" => Level::Debug,
|
|
"trace" => Level::Trace,
|
|
level => {
|
|
return Err(serde::de::Error::custom(format!(
|
|
"invalid log level `{level}`"
|
|
)));
|
|
}
|
|
};
|
|
Ok(Verbosity {
|
|
verbose: level_value(level) as u8,
|
|
quiet: 0,
|
|
})
|
|
}
|
|
}
|
|
|
|
const fn level_value(level: Level) -> i8 {
|
|
match level {
|
|
log::Level::Error => 0,
|
|
log::Level::Warn => 1,
|
|
log::Level::Info => 2,
|
|
log::Level::Debug => 3,
|
|
log::Level::Trace => 4,
|
|
}
|
|
}
|
|
|
|
const fn level_enum(verbosity: i8) -> log::Level {
|
|
match verbosity {
|
|
0 => log::Level::Error,
|
|
1 => log::Level::Warn,
|
|
2 => log::Level::Info,
|
|
3 => log::Level::Debug,
|
|
_ => log::Level::Trace,
|
|
}
|
|
}
|
|
|
|
use std::fmt;
|
|
|
|
impl fmt::Display for Verbosity {
|
|
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
|
|
write!(f, "{}", self.verbose)
|
|
}
|
|
}
|
|
|
|
#[cfg(test)]
|
|
mod test {
|
|
use super::*;
|
|
|
|
#[test]
|
|
fn verify_app() {
|
|
#[derive(Debug, clap::Parser)]
|
|
struct Cli {
|
|
#[clap(flatten)]
|
|
verbose: Verbosity,
|
|
}
|
|
|
|
use clap::CommandFactory;
|
|
Cli::command().debug_assert();
|
|
}
|
|
|
|
#[test]
|
|
fn test_default_log_level() {
|
|
let verbosity = Verbosity::default();
|
|
assert_eq!(verbosity.log_level(), Level::Warn);
|
|
assert!(verbosity.log_level() >= Level::Warn);
|
|
}
|
|
}
|