1
Fork 0
mirror of https://github.com/RGBCube/uutils-coreutils synced 2025-07-28 19:47:45 +00:00

false,true: Implement custom help, version

This avoids hacking around the short options of these command line
arguments that have been introduced by clap. Additionally, we test and
correctly handle the combination of both version and help. The GNU
binary will ignore both arguments in this case while clap would perform
the first one. A test for this edge case was added.
This commit is contained in:
Andreas Molzer 2022-02-01 14:29:26 +01:00
parent c1e108933f
commit 23a544c485
4 changed files with 69 additions and 38 deletions

View file

@ -4,7 +4,7 @@
// *
// * For the full copyright and license information, please view the LICENSE
// * file that was distributed with this source code.
use clap::{App, Arg, ArgSettings, ErrorKind};
use clap::{App, AppSettings, Arg};
use std::io::Write;
use uucore::error::{set_exit_code, UResult};
@ -18,7 +18,7 @@ static ABOUT: &str = "
#[uucore::main]
pub fn uumain(args: impl uucore::Args) -> UResult<()> {
let app = uu_app();
let mut app = uu_app();
// Mirror GNU options, always return `1`. In particular even the 'successful' cases of no-op,
// and the interrupted display of help and version should return `1`. Also, we return Ok in all
@ -26,14 +26,21 @@ pub fn uumain(args: impl uucore::Args) -> UResult<()> {
// and unwind through the standard library allocation handling machinery.
set_exit_code(1);
if let Err(err) = app.try_get_matches_from(args) {
if let ErrorKind::DisplayHelp | ErrorKind::DisplayVersion = err.kind {
if let Err(print_fail) = err.print() {
if let Ok(matches) = app.try_get_matches_from_mut(args) {
let error = if matches.index_of("help").is_some() {
app.print_long_help()
} else if matches.index_of("version").is_some() {
writeln!(std::io::stdout(), "{}", app.render_version())
} else {
Ok(())
};
// Try to display this error.
if let Err(print_fail) = error {
// Completely ignore any error here, no more failover and we will fail in any case.
let _ = writeln!(std::io::stderr(), "{}: {}", uucore::util_name(), print_fail);
}
}
}
Ok(())
}
@ -42,16 +49,17 @@ pub fn uu_app<'a>() -> App<'a> {
App::new(uucore::util_name())
.version(clap::crate_version!())
.about(ABOUT)
// Hide the default -V and -h for version and help.
// This requires us to overwrite short, not short_aliases.
// We provide our own help and version options, to ensure maximum compatibility with GNU.
.setting(AppSettings::DisableHelpFlag | AppSettings::DisableVersionFlag)
.arg(
Arg::new("dummy-help")
.short('h')
.setting(ArgSettings::Hidden),
Arg::new("help")
.long("help")
.help("Print help information")
.exclusive(true),
)
.arg(
Arg::new("dummy-version")
.short('V')
.setting(ArgSettings::Hidden),
Arg::new("version")
.long("version")
.help("Print version information"),
)
}

View file

@ -4,7 +4,7 @@
// *
// * For the full copyright and license information, please view the LICENSE
// * file that was distributed with this source code.
use clap::{App, Arg, ArgSettings, ErrorKind};
use clap::{App, AppSettings, Arg};
use std::io::Write;
use uucore::error::{set_exit_code, UResult};
@ -18,11 +18,18 @@ static ABOUT: &str = "
#[uucore::main]
pub fn uumain(args: impl uucore::Args) -> UResult<()> {
let app = uu_app();
let mut app = uu_app();
if let Err(err) = app.try_get_matches_from(args) {
if let ErrorKind::DisplayHelp | ErrorKind::DisplayVersion = err.kind {
if let Err(print_fail) = err.print() {
if let Ok(matches) = app.try_get_matches_from_mut(args) {
let error = if matches.index_of("help").is_some() {
app.print_long_help()
} else if matches.index_of("version").is_some() {
writeln!(std::io::stdout(), "{}", app.render_version())
} else {
Ok(())
};
if let Err(print_fail) = error {
// Try to display this error.
let _ = writeln!(std::io::stderr(), "{}: {}", uucore::util_name(), print_fail);
// Mirror GNU options. When failing to print warnings or version flags, then we exit
@ -31,7 +38,6 @@ pub fn uumain(args: impl uucore::Args) -> UResult<()> {
set_exit_code(1);
}
}
}
Ok(())
}
@ -40,16 +46,17 @@ pub fn uu_app<'a>() -> App<'a> {
App::new(uucore::util_name())
.version(clap::crate_version!())
.about(ABOUT)
// Hide the default -V and -h for version and help.
// This requires us to overwrite short, not short_aliases.
// We provide our own help and version options, to ensure maximum compatibility with GNU.
.setting(AppSettings::DisableHelpFlag | AppSettings::DisableVersionFlag)
.arg(
Arg::new("dummy-help")
.short('h')
.setting(ArgSettings::Hidden),
Arg::new("help")
.long("help")
.help("Print help information")
.exclusive(true),
)
.arg(
Arg::new("dummy-version")
.short('V')
.setting(ArgSettings::Hidden),
Arg::new("version")
.long("version")
.help("Print version information"),
)
}

View file

@ -25,11 +25,19 @@ fn test_help() {
#[test]
fn test_short_options() {
for option in ["-h", "-v"] {
for option in ["-h", "-V"] {
new_ucmd!().arg(option).fails().stdout_is("");
}
}
#[test]
fn test_conflict() {
new_ucmd!()
.args(&["--help", "--version"])
.fails()
.stdout_is("");
}
#[test]
#[cfg(any(target_os = "linux", target_os = "freebsd", target_os = "netbsd"))]
fn test_full() {

View file

@ -25,11 +25,19 @@ fn test_help() {
#[test]
fn test_short_options() {
for option in ["-h", "-v"] {
for option in ["-h", "-V"] {
new_ucmd!().arg(option).succeeds().stdout_is("");
}
}
#[test]
fn test_conflict() {
new_ucmd!()
.args(&["--help", "--version"])
.succeeds()
.stdout_is("");
}
#[test]
#[cfg(any(target_os = "linux", target_os = "freebsd", target_os = "netbsd"))]
fn test_full() {