rust: Streamline and cleanup verbosity handling

Create one implementation for the verbose option to be used by all
tools. While at it, add a quiet option to decrease the verbosity.

Signed-off-by: Marc Hartmayer <mhartmay@linux.ibm.com>
Signed-off-by: Steffen Eiden <seiden@linux.ibm.com>
This commit is contained in:
Steffen Eiden
2024-11-07 11:03:41 +01:00
parent 576a230341
commit 53d803abf3
9 changed files with 125 additions and 123 deletions

View File

@@ -2,8 +2,8 @@
//
// Copyright IBM Corp. 2023, 2024
use clap::{ArgGroup, Args, Command, ValueHint};
use log::{info, warn};
use clap::{ArgAction, ArgGroup, Args, Command, ValueHint};
use log::{info, warn, LevelFilter};
use pv::misc::read_file;
use pv::{
misc::{create_file, open_file, read_certs},
@@ -174,7 +174,7 @@ pub fn get_reader_from_cli_file_arg<P: AsRef<Path>>(path: P) -> Result<Box<dyn R
}
}
/// Print an error that occured during CLI parsing
/// Print an error that occurred during CLI parsing
pub fn print_cli_error(e: clap::Error, mut cmd: Command) -> ExitCode {
let ret = if e.use_stderr() {
ExitCode::FAILURE
@@ -187,12 +187,12 @@ pub fn print_cli_error(e: clap::Error, mut cmd: Command) -> ExitCode {
}
/// Print an error to stderr
pub fn print_error<E>(e: &E, verbosity: u8) -> ExitCode
pub fn print_error<E>(e: &E, verbosity: LevelFilter) -> ExitCode
where
// Error trait is not required, but here to limit the usage to errors
E: AsRef<dyn std::error::Error> + std::fmt::Debug + std::fmt::Display,
{
if verbosity > 0 {
if verbosity > LevelFilter::Warn {
// Debug formatter also prints the whole error stack
// So only print it when on verbose
eprintln!("error: {e:?}")
@@ -202,6 +202,79 @@ where
ExitCode::FAILURE
}
#[derive(Args, Debug, Clone, Default)]
pub struct VerbosityOptions {
#[arg(
long,
short = 'v',
action = ArgAction::Count,
global = true,
)]
/// Provide more detailed output.
verbose: u8,
#[arg(
long,
short = 'q',
action = ArgAction::Count,
global = true,
conflicts_with = "verbose",
)]
/// Provide less output.
quiet: u8,
}
const fn to_level_filter(v: u8) -> LevelFilter {
match v {
0 => LevelFilter::Off,
1 => LevelFilter::Error,
2 => LevelFilter::Warn,
3 => LevelFilter::Info,
4 => LevelFilter::Debug,
5.. => LevelFilter::Trace,
}
}
impl VerbosityOptions {
fn verbosity(&self) -> u8 {
(LevelFilter::Warn as i16 + self.verbose as i16 - self.quiet as i16)
.clamp(u8::MIN.into(), u8::MAX.into()) as u8
}
pub fn to_level_filter(&self) -> LevelFilter {
to_level_filter(self.verbosity())
}
}
#[derive(Args, Debug, Clone, Default)]
pub struct DeprecatedVerbosityOptions {
#[clap(flatten)]
verbosity: VerbosityOptions,
#[arg(
short = 'V',
action = ArgAction::Count,
global = true,
hide = true,
)]
/// Provide more detailed output.
deprecated_verbose: u8,
}
impl DeprecatedVerbosityOptions {
pub fn to_level_filter(&self) -> LevelFilter {
if self.deprecated_verbose > 0 {
// Use eprintln as the logger is most likely not yet initialized.
eprintln!("WARNING: Use of deprecated flag '-V'. Use '-v' or '--verbose' instead.")
}
to_level_filter(
self.verbosity
.verbosity()
.saturating_add(self.deprecated_verbose),
)
}
}
#[cfg(test)]
mod test {
use clap::Parser;

View File

@@ -8,13 +8,14 @@ mod hexslice;
mod log;
mod tmpfile;
pub use crate::cli::CertificateOptions;
pub use crate::cli::{get_reader_from_cli_file_arg, get_writer_from_cli_file_arg};
pub use crate::cli::{print_cli_error, print_error};
pub use crate::cli::{CertificateOptions, DeprecatedVerbosityOptions, VerbosityOptions};
pub use crate::cli::{STDIN, STDOUT};
pub use crate::hexslice::HexSlice;
pub use crate::log::PvLogger;
pub use crate::tmpfile::TemporaryDirectory;
pub use ::log::LevelFilter;
/// Get the s390-tools release string
///
@@ -41,23 +42,18 @@ macro_rules! release_string {
}
#[macro_export]
/// Print the version to stdout
///
/// verbosity: integer if >0 more and more details printed
/// feat: (optional) list of features
/// rel_str: a string containig the release name
macro_rules! print_version {
($verbosity: expr, $year: expr $( ,$feat: expr)?) => {{
macro_rules! __print_version {
($year: expr, $verbosity: expr $( ,$feat: expr)?) => {{
println!(
"{} version {}\nCopyright IBM Corp. {}",
env!("CARGO_PKG_NAME"),
$crate::release_string!(),
$year,
);
if $verbosity > 0 {
if $verbosity > $crate::LevelFilter::Warn {
$($feat.iter().for_each(|f| print!("{f} ")); println!("(compiled)");)?
}
if $verbosity > 1 {
if $verbosity > $crate::LevelFilter::Info {
println!(
"\n{}-crate {}",
env!("CARGO_PKG_NAME"),
@@ -67,6 +63,20 @@ macro_rules! print_version {
}};
}
#[macro_export]
/// Print the version to stdout
///
/// `verbosity` (optional): `LogLevel`
/// `feat` (optional): list of features
/// `rel_str`: a string containig the release name
macro_rules! print_version {
($year: expr $( ;$feat: expr)?) => {
$crate::__print_version!($year, $crate::LevelFilter::Warn $(, $feat)*)
};
($year: expr, $verbosity: expr $( ;$feat: expr)?) => {
$crate::__print_version!($year, $verbosity $(, $feat)*)
};
}
/// Asserts a constant expression evaluates to `true`.
///
/// If the expression is not evaluated to `true` the compilation will fail.

View File

@@ -9,24 +9,14 @@ use log::{self, Level, LevelFilter, Log, Metadata, Record};
#[derive(Clone, Default, Debug)]
pub struct PvLogger;
fn to_level(verbosity: u8) -> LevelFilter {
match verbosity {
// Error and Warn on by default
0 => LevelFilter::Warn,
1 => LevelFilter::Info,
2 => LevelFilter::Debug,
_ => LevelFilter::Trace,
}
}
impl PvLogger {
/// Set self as the logger for this application.
///
/// # Errors
///
/// An error is returned if a logger has already been set.
pub fn start(&'static self, verbosity: u8) -> Result<(), log::SetLoggerError> {
log::set_logger(self).map(|()| log::set_max_level(to_level(verbosity)))
pub fn start(&'static self, filter: LevelFilter) -> Result<(), log::SetLoggerError> {
log::set_logger(self).map(|()| log::set_max_level(filter))
}
}