Skip to content

Commit

Permalink
Merge pull request #883 from nextstrain/feat/cli-organize-verbosity-f…
Browse files Browse the repository at this point in the history
…lags
  • Loading branch information
ivan-aksamentov authored Jun 22, 2022
2 parents 2cba8ff + d8f5f28 commit d98312a
Show file tree
Hide file tree
Showing 6 changed files with 142 additions and 49 deletions.
1 change: 0 additions & 1 deletion Cargo.lock

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

1 change: 0 additions & 1 deletion packages_rs/nextclade-cli/Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -12,7 +12,6 @@ publish = false
[dependencies]
assert2 = "0.3.6"
clap = { version = "3.1.8", features = ["derive"] }
clap-verbosity-flag = "1.0.0"
clap_complete = "3.1.1"
clap_complete_fig = "3.1.4"
color-eyre = "0.6.1"
Expand Down
1 change: 1 addition & 0 deletions packages_rs/nextclade-cli/src/cli/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -7,3 +7,4 @@ pub mod nextclade_dataset_get;
pub mod nextclade_dataset_list;
pub mod nextclade_loop;
pub mod nextclade_ordered_writer;
pub mod verbosity;
26 changes: 3 additions & 23 deletions packages_rs/nextclade-cli/src/cli/nextalign_cli.rs
Original file line number Diff line number Diff line change
@@ -1,12 +1,11 @@
use crate::cli::common::get_fasta_basename;
use crate::cli::verbosity::{Verbosity, WarnLevel};
use clap::{AppSettings, ArgEnum, CommandFactory, Parser, Subcommand, ValueHint};
use clap_complete::{generate, Generator, Shell};
use clap_complete_fig::Fig;
use clap_verbosity_flag::{Verbosity, WarnLevel};
use eyre::{eyre, ContextCompat, Report, WrapErr};
use itertools::Itertools;
use lazy_static::lazy_static;
use log::LevelFilter;
use nextclade::align::params::AlignPairwiseParamsOptional;
use nextclade::make_error;
use nextclade::utils::global_init::setup_logger;
Expand All @@ -18,7 +17,6 @@ use strum_macros::EnumIter;

lazy_static! {
static ref SHELLS: &'static [&'static str] = &["bash", "elvish", "fish", "fig", "powershell", "zsh"];
static ref VERBOSITIES: &'static [&'static str] = &["off", "error", "warn", "info", "debug", "trace"];
}

#[derive(Parser, Debug)]
Expand All @@ -37,17 +35,9 @@ pub struct NextalignArgs {
#[clap(subcommand)]
pub command: NextalignCommands,

/// Set verbosity level [default: warn]
#[clap(long, global = true, conflicts_with = "verbose", conflicts_with = "silent", possible_values(VERBOSITIES.iter()))]
pub verbosity: Option<LevelFilter>,

/// Disable all console output. Same as --verbosity=off
#[clap(long, global = true, conflicts_with = "verbose", conflicts_with = "verbosity")]
pub silent: bool,

/// Make output more quiet or more verbose
#[clap(flatten)]
pub verbose: Verbosity<WarnLevel>,
pub verbosity: Verbosity<WarnLevel>,
}

#[derive(Subcommand, Debug)]
Expand Down Expand Up @@ -426,17 +416,7 @@ pub fn nextalign_check_removed_args(run_args: &mut NextalignRunArgs) -> Result<(
pub fn nextalign_parse_cli_args() -> Result<NextalignArgs, Report> {
let mut args = NextalignArgs::parse();

// --verbosity=<level> and --silent take priority over -v and -q
let filter_level = if args.silent {
LevelFilter::Off
} else {
match args.verbosity {
None => args.verbose.log_level_filter(),
Some(verbosity) => verbosity,
}
};

setup_logger(filter_level);
setup_logger(args.verbosity.get_filter_level());

match &mut args.command {
NextalignCommands::Completions { shell } => {
Expand Down
27 changes: 3 additions & 24 deletions packages_rs/nextclade-cli/src/cli/nextclade_cli.rs
Original file line number Diff line number Diff line change
@@ -1,15 +1,13 @@
use crate::cli::common::get_fasta_basename;
use crate::cli::verbosity::{Verbosity, WarnLevel};
use crate::io::http_client::ProxyConfig;
use clap::{AppSettings, ArgEnum, ArgGroup, CommandFactory, Parser, Subcommand, ValueHint};
use clap_complete::{generate, Generator, Shell};
use clap_complete_fig::Fig;
use clap_verbosity_flag::{Verbosity, WarnLevel};
use eyre::{eyre, ContextCompat, Report, WrapErr};
use itertools::Itertools;
use lazy_static::lazy_static;
use log::LevelFilter;
use nextclade::align::params::AlignPairwiseParamsOptional;
use nextclade::io::fs::{basename_maybe, extension};
use nextclade::utils::global_init::setup_logger;
use nextclade::{getenv, make_error};
use std::fmt::Debug;
Expand All @@ -24,7 +22,6 @@ const DATA_FULL_DOMAIN: &str = getenv!("DATA_FULL_DOMAIN");

lazy_static! {
static ref SHELLS: &'static [&'static str] = &["bash", "elvish", "fish", "fig", "powershell", "zsh"];
static ref VERBOSITIES: &'static [&'static str] = &["off", "error", "warn", "info", "debug", "trace"];
}

#[derive(Parser, Debug)]
Expand All @@ -43,17 +40,9 @@ pub struct NextcladeArgs {
#[clap(subcommand)]
pub command: NextcladeCommands,

/// Set verbosity level [default: warn]
#[clap(long, global = true, conflicts_with = "verbose", conflicts_with = "silent", possible_values(VERBOSITIES.iter()))]
pub verbosity: Option<LevelFilter>,

/// Disable all console output. Same as --verbosity=off
#[clap(long, global = true, conflicts_with = "verbose", conflicts_with = "verbosity")]
pub silent: bool,

/// Make output more quiet or more verbose
#[clap(flatten)]
pub verbose: Verbosity<WarnLevel>,
pub verbosity: Verbosity<WarnLevel>,
}

#[derive(Subcommand, Debug)]
Expand Down Expand Up @@ -733,17 +722,7 @@ pub fn nextclade_check_removed_args(run_args: &mut NextcladeRunArgs) -> Result<(
pub fn nextclade_parse_cli_args() -> Result<NextcladeArgs, Report> {
let mut args = NextcladeArgs::parse();

// --verbosity=<level> and --silent take priority over -v and -q
let filter_level = if args.silent {
LevelFilter::Off
} else {
match args.verbosity {
None => args.verbose.log_level_filter(),
Some(verbosity) => verbosity,
}
};

setup_logger(filter_level);
setup_logger(args.verbosity.get_filter_level());

match &mut args.command {
NextcladeCommands::Completions { shell } => {
Expand Down
135 changes: 135 additions & 0 deletions packages_rs/nextclade-cli/src/cli/verbosity.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,135 @@
//! Inspired by clap-verbosity-flag:
//! https://github.com/rust-cli/clap-verbosity-flag
use clap::Args;
use lazy_static::lazy_static;
use log::{Level, LevelFilter};
use std::fmt::{Display, Formatter, Result};
use std::marker::PhantomData;

lazy_static! {
static ref VERBOSITIES: &'static [&'static str] = &["off", "error", "warn", "info", "debug", "trace"];
}

#[derive(Args, Debug, Clone)]
pub struct Verbosity<L: LogLevel = ErrorLevel> {
/// Set verbosity level of console output [default: warn]
#[clap(long, global = true, possible_values(VERBOSITIES.iter()))]
#[clap(conflicts_with = "quiet", conflicts_with = "verbose", conflicts_with = "silent")]
#[clap(display_order = 900)]
pub verbosity: Option<LevelFilter>,

/// Disable all console output. Same as `--verbosity=off`
#[clap(long, global = true)]
#[clap(conflicts_with = "quiet", conflicts_with = "verbose", conflicts_with = "verbosity")]
#[clap(display_order = 901)]
pub silent: bool,

/// Make console output more verbose. Add multiple occurrences to increase verbosity further.
#[clap(long, short = 'v', parse(from_occurrences), global = true)]
#[clap(conflicts_with = "quiet", conflicts_with = "verbosity", conflicts_with = "silent")]
#[clap(display_order = 902)]
verbose: i8,

/// Make console output more quiet. Add multiple occurrences to make output even more quiet.
#[clap(long, short = 'q', parse(from_occurrences), global = true)]
#[clap(conflicts_with = "verbose", conflicts_with = "verbosity")]
#[clap(display_order = 903)]
quiet: i8,

#[clap(skip)]
phantom: PhantomData<L>,
}

impl<L: LogLevel> Verbosity<L> {
pub fn get_filter_level(&self) -> LevelFilter {
// --verbosity=<level> and --silent take priority over -v and -q
if self.silent {
LevelFilter::Off
} else {
match self.verbosity {
Some(verbosity) => verbosity,
None => self.log_level_filter(),
}
}
}

/// Get the log level.
///
/// `None` means all output is disabled.
pub fn log_level(&self) -> Option<Level> {
level_enum(self.verbosity())
}

/// Get the log level filter.
pub fn log_level_filter(&self) -> LevelFilter {
level_enum(self.verbosity()).map_or(LevelFilter::Off, |l| l.to_level_filter())
}

/// If the user requested complete silence (i.e. not just no-logging).
pub fn is_silent(&self) -> bool {
self.log_level().is_none()
}

fn verbosity(&self) -> i8 {
level_value(L::default()) - self.quiet + self.verbose
}
}

const fn level_value(level: Option<Level>) -> i8 {
match level {
None => -1,
Some(Level::Error) => 0,
Some(Level::Warn) => 1,
Some(Level::Info) => 2,
Some(Level::Debug) => 3,
Some(Level::Trace) => 4,
}
}

const fn level_enum(verbosity: i8) -> Option<Level> {
match verbosity {
i8::MIN..=-1 => None,
0 => Some(Level::Error),
1 => Some(Level::Warn),
2 => Some(Level::Info),
3 => Some(Level::Debug),
4..=i8::MAX => Some(Level::Trace),
}
}

impl<L: LogLevel> Display for Verbosity<L> {
fn fmt(&self, f: &mut Formatter<'_>) -> Result {
write!(f, "{}", self.verbosity())
}
}

pub trait LogLevel {
fn default() -> Option<Level>;
}

#[derive(Copy, Clone, Debug, Default)]
pub struct ErrorLevel;

impl LogLevel for ErrorLevel {
fn default() -> Option<Level> {
Some(Level::Error)
}
}

#[derive(Copy, Clone, Debug, Default)]
pub struct WarnLevel;

impl LogLevel for WarnLevel {
fn default() -> Option<Level> {
Some(Level::Warn)
}
}

#[derive(Copy, Clone, Debug, Default)]
pub struct InfoLevel;

impl LogLevel for InfoLevel {
fn default() -> Option<Level> {
Some(Level::Info)
}
}

1 comment on commit d98312a

@vercel
Copy link

@vercel vercel bot commented on d98312a Jun 22, 2022

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Successfully deployed to the following URLs:

nextclade – ./

nextclade-git-master-nextstrain.vercel.app
nextclade-nextstrain.vercel.app
nextclade.vercel.app

Please sign in to comment.