feat(cli): Print arguments if argument parsing fails (#3560)

* fix(#3554): Print the command line argv on clap error

This is a very bare implementation that just prints the error
and then a note with the arguments passed, it does this manually
and doesn't use clap. I've also chosen to use `Vec`'s `Debug`
implementation instead of rolling my own one because I thought it was
good enough, but there might be a better way of doing all this.

Altogether, I think this will be very useful to help in the diagnostic
of other bugs :)

* fix(#3554): Print the command line argv on clap error

This is a very bare implementation that just prints the error
and then a note with the arguments passed, it does this manually
and doesn't use clap. I've also chosen to use `Vec`'s `Debug`
implementation instead of rolling my own one because I thought it was
good enough, but there might be a better way of doing all this.

Altogether, I think this will be very useful to help in the diagnostic
of other bugs :)

EDIT: removed `dbg!`, set it to exit always.

* correctness(exit): don't print argv / exit with error on help and
version error kinds

* fix: Avoid panicking when stdout/stderr closing unexpectedly

* refactor(cli): use `use_stderr` instead of manual match for error kinds

`clap` uses `use_stderr` to reliably check whether the error given is
actually an error coming from user input or rather a hint to display
other info (version, help, etc.)

Also reworded/moved a couple of comments so that they explain better
what is the thought process behind the code
This commit is contained in:
Jesús Lapastora 2022-02-06 23:04:28 +01:00 committed by GitHub
parent 589576d3eb
commit c3cc40d2ac
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23

View File

@ -108,7 +108,38 @@ fn main() {
let _ = ansi_term::enable_ansi_support();
logger::init();
let args = Cli::parse();
let args = match Cli::try_parse() {
Ok(args) => args,
Err(e) => {
// if the error is not printed to stderr, this means it was not really
// an error but rather some information is going to be listed, therefore
// we won't print the arguments passed
let is_info_only = !e.use_stderr();
// print the error and void panicking in case of stdout/stderr closing unexpectedly
let _ = e.print();
// if there was no mistake by the user and we're only going to display information,
// we won't put arguments or exit with non-zero code
let exit_code = if is_info_only {
0
} else {
// print the arguments
// avoid panicking in case of stderr closing
let mut stderr = io::stderr();
use io::Write;
let _ = writeln!(
stderr,
"\nNOTE:\n passed arguments: {:?}",
// collect into a vec to format args as a slice
std::env::args().skip(1).collect::<Vec<_>>()
);
// clap exits with status 2 on error:
// https://docs.rs/clap/latest/clap/struct.Error.html#method.exit
2
};
std::process::exit(exit_code);
}
};
log::trace!("Parsed arguments: {:#?}", args);
match args.command {