Skip to content

Commit b04e19f

Browse files
committed
refactor(cli): replace verbose/quiet bool pairs with Verbosity enum
exarch-cli's output-formatter and progress-selection code took separate verbose/quiet bool parameters, allowing the nonsensical verbose=true, quiet=true state and, in extract, resolving it inconsistently between the formatter (quiet-wins) and the progress reporter (verbose-wins). create_formatter, HumanFormatter::new, HumanFormatter::with_writers, commands::extract::execute, and commands::create::execute now take a single output::Verbosity (Quiet | Normal | Verbose), resolved once via impl From<&cli::Cli> for Verbosity and threaded through every call site, closing the split-ArgMatches-level gap where clap's conflicts_with does not catch --verbose and --quiet passed at different argument levels. Closes #550
1 parent 27c44b4 commit b04e19f

6 files changed

Lines changed: 191 additions & 58 deletions

File tree

CHANGELOG.md

Lines changed: 19 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -18,6 +18,25 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
1818

1919
### Changed
2020

21+
- **`exarch-cli`'s output-formatter and progress-selection code took separate `verbose: bool, quiet: bool`
22+
parameters, allowing the nonsensical `verbose: true, quiet: true` state and, in `extract`, resolving it
23+
inconsistently between the formatter (quiet-wins) and the progress reporter (verbose-wins) (#550)**:
24+
`output::create_formatter`, `HumanFormatter::new`, `HumanFormatter::with_writers`,
25+
`commands::extract::execute`, and `commands::create::execute` now take a single `output::Verbosity`
26+
(`Quiet` | `Normal` | `Verbose`) instead, resolved once via `impl From<&cli::Cli> for Verbosity` in
27+
`main.rs` and threaded through every call site. `--verbose`/`--quiet` remain independent `clap` flags
28+
with `conflicts_with` on `--quiet`; that check only rejects the pair when both land in the same
29+
`ArgMatches` level (e.g. `exarch list --verbose --quiet`), so a split-level combination such as
30+
`exarch --verbose extract archive.tar.gz out --quiet` still parses with both `true`
31+
`Verbosity::from_flags` resolves that case deterministically to `Quiet`, the same tie-break the
32+
formatter already used.
33+
34+
**Behavior change**: `extract`'s progress reporter previously selected `VerboseProgress` whenever
35+
`--verbose` was passed, even together with `--quiet` (verbose-wins), while the formatter suppressed the
36+
summary (quiet-wins) — so `--verbose extract ... --quiet` printed per-entry progress lines but no
37+
summary. Both now consistently resolve to `Quiet` (no progress output, no summary) through the same
38+
`Verbosity` value.
39+
2140
- **`exarch-cli`'s `--atomic --force` swap path now bundles the pinned temp directory's
2241
`pin`/`name`/`id`/`parent_display` identifiers into a `TempOrphanRef` struct (#538)** instead of
2342
threading the same four parameters through `move_destination_to_backup` (7 params, down to 4) and

crates/exarch-cli/src/commands/create.rs

Lines changed: 10 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -2,14 +2,19 @@
22
33
use crate::cli::CreateArgs;
44
use crate::output::OutputFormatter;
5+
use crate::output::Verbosity;
56
use crate::progress::CliProgress;
67
use anyhow::Context;
78
use anyhow::Result;
89
use exarch_core::CreationConfig;
910
use exarch_core::NoopProgress;
1011
use exarch_core::create_archive_with_progress;
1112

12-
pub fn execute(args: &CreateArgs, formatter: &mut dyn OutputFormatter, quiet: bool) -> Result<()> {
13+
pub fn execute(
14+
args: &CreateArgs,
15+
formatter: &mut dyn OutputFormatter,
16+
verbosity: Verbosity,
17+
) -> Result<()> {
1318
// Check if output exists
1419
if args.output.exists() && !args.force {
1520
anyhow::bail!(
@@ -42,7 +47,7 @@ pub fn execute(args: &CreateArgs, formatter: &mut dyn OutputFormatter, quiet: bo
4247
config.exclude_patterns.extend(args.exclude.iter().cloned());
4348

4449
// Create archive with progress if TTY is detected
45-
let report = if !quiet && CliProgress::should_show() {
50+
let report = if verbosity != Verbosity::Quiet && CliProgress::should_show() {
4651
let mut progress = CliProgress::new(100, "Creating");
4752
create_archive_with_progress(&args.output, &args.sources, &config, &mut progress)
4853
.with_context(|| format!("Failed to create archive: {}", args.output.display()))?
@@ -186,7 +191,7 @@ mod tests {
186191
let args = make_args(out, src);
187192
let mut formatter = AlwaysCallSpyFormatter::new();
188193

189-
execute(&args, &mut formatter, true).unwrap();
194+
execute(&args, &mut formatter, Verbosity::Quiet).unwrap();
190195

191196
assert!(
192197
formatter.was_called(),
@@ -204,7 +209,7 @@ mod tests {
204209
let args = make_args(out, src);
205210
let mut formatter = AlwaysCallSpyFormatter::new();
206211

207-
execute(&args, &mut formatter, false).unwrap();
212+
execute(&args, &mut formatter, Verbosity::Normal).unwrap();
208213

209214
assert!(formatter.was_called());
210215
}
@@ -221,7 +226,7 @@ mod tests {
221226
let args = make_args(out, src);
222227
let mut formatter = SpyFormatter::new(true);
223228

224-
execute(&args, &mut formatter, true).unwrap();
229+
execute(&args, &mut formatter, Verbosity::Quiet).unwrap();
225230

226231
assert!(
227232
!formatter.was_called(),

crates/exarch-cli/src/commands/extract.rs

Lines changed: 8 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -7,6 +7,7 @@ use crate::commands::atomic_swap::DestEntryKind;
77
use crate::commands::atomic_swap::PinnedDir;
88
use crate::error::add_archive_context;
99
use crate::output::OutputFormatter;
10+
use crate::output::Verbosity;
1011
use crate::progress::CliProgress;
1112
use crate::progress::VerboseProgress;
1213
use anyhow::Context;
@@ -719,8 +720,7 @@ fn filter_banned_components(raw: &[String]) -> Vec<String> {
719720
pub fn execute(
720721
args: &ExtractArgs,
721722
formatter: &mut dyn OutputFormatter,
722-
verbose: bool,
723-
quiet: bool,
723+
verbosity: Verbosity,
724724
) -> Result<()> {
725725
let output_dir = match &args.output_dir {
726726
Some(dir) => dir.clone(),
@@ -817,12 +817,12 @@ pub fn execute(
817817
.with_atomic(args.atomic && atomic_force_target.is_none())
818818
.with_skip_duplicates(!args.force);
819819

820-
let mut progress: Box<dyn ProgressCallback> = if verbose {
821-
Box::new(VerboseProgress::new())
822-
} else if !quiet && CliProgress::should_show() {
823-
Box::new(CliProgress::new(entry_count, "Extracting"))
824-
} else {
825-
Box::new(NoopProgress)
820+
let mut progress: Box<dyn ProgressCallback> = match verbosity {
821+
Verbosity::Verbose => Box::new(VerboseProgress::new()),
822+
Verbosity::Normal if CliProgress::should_show() => {
823+
Box::new(CliProgress::new(entry_count, "Extracting"))
824+
}
825+
Verbosity::Quiet | Verbosity::Normal => Box::new(NoopProgress),
826826
};
827827

828828
let report = if let Some(target) = atomic_force_target {

crates/exarch-cli/src/main.rs

Lines changed: 11 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -11,16 +11,21 @@ use clap::Parser;
1111
use error::StrictWarning;
1212
use error::VerificationFailed;
1313
use output::OutputFormatter;
14+
use output::Verbosity;
1415
use std::process;
1516

16-
fn run(cli: &cli::Cli, formatter: &mut dyn OutputFormatter) -> (anyhow::Result<()>, &'static str) {
17+
fn run(
18+
cli: &cli::Cli,
19+
verbosity: Verbosity,
20+
formatter: &mut dyn OutputFormatter,
21+
) -> (anyhow::Result<()>, &'static str) {
1722
match &cli.command {
1823
cli::Commands::Extract(args) => (
19-
commands::extract::execute(args, formatter, cli.verbose, cli.quiet),
24+
commands::extract::execute(args, formatter, verbosity),
2025
"extract",
2126
),
2227
cli::Commands::Create(args) => (
23-
commands::create::execute(args, formatter, cli.quiet),
28+
commands::create::execute(args, formatter, verbosity),
2429
"create",
2530
),
2631
cli::Commands::List(args) => (commands::list::execute(args, formatter), "list"),
@@ -34,9 +39,10 @@ fn run(cli: &cli::Cli, formatter: &mut dyn OutputFormatter) -> (anyhow::Result<(
3439

3540
fn main() {
3641
let cli = cli::Cli::parse();
37-
let mut formatter = output::create_formatter(cli.json, cli.verbose, cli.quiet);
42+
let verbosity = Verbosity::from(&cli);
43+
let mut formatter = output::create_formatter(cli.json, verbosity);
3844

39-
let (result, operation) = run(&cli, formatter.as_mut());
45+
let (result, operation) = run(&cli, verbosity, formatter.as_mut());
4046
if let Err(err) = result {
4147
if err.is::<StrictWarning>() {
4248
process::exit(2);

0 commit comments

Comments
 (0)