1
Fork 0
mirror of https://github.com/RGBCube/uutils-coreutils synced 2025-07-30 04:27:45 +00:00

sort: clap 3

This commit is contained in:
Terts Diepraam 2022-01-11 14:51:52 +01:00
parent d0a52c95e6
commit b43839a8a8
3 changed files with 67 additions and 62 deletions

View file

@ -16,7 +16,7 @@ path = "src/sort.rs"
[dependencies] [dependencies]
binary-heap-plus = "0.4.1" binary-heap-plus = "0.4.1"
clap = { version = "2.33", features = ["wrap_help"] } clap = { version = "3.0", features = ["wrap_help", "cargo"] }
compare = "0.1.0" compare = "0.1.0"
ctrlc = { version = "3.0", features = ["termination"] } ctrlc = { version = "3.0", features = ["termination"] }
fnv = "1.0.7" fnv = "1.0.7"

View file

@ -1046,8 +1046,8 @@ With no FILE, or when FILE is -, read standard input.",
} }
/// Creates an `Arg` that conflicts with all other sort modes. /// Creates an `Arg` that conflicts with all other sort modes.
fn make_sort_mode_arg<'a, 'b>(mode: &'a str, short: &'b str, help: &'b str) -> Arg<'a, 'b> { fn make_sort_mode_arg<'a>(mode: &'a str, short: char, help: &'a str) -> Arg<'a> {
let mut arg = Arg::with_name(mode).short(short).long(mode).help(help); let mut arg = Arg::new(mode).short(short).long(mode).help(help);
for possible_mode in &options::modes::ALL_SORT_MODES { for possible_mode in &options::modes::ALL_SORT_MODES {
if *possible_mode != mode { if *possible_mode != mode {
arg = arg.conflicts_with(possible_mode); arg = arg.conflicts_with(possible_mode);
@ -1064,7 +1064,10 @@ pub fn uumain(args: impl uucore::Args) -> UResult<()> {
let usage = usage(); let usage = usage();
let mut settings: GlobalSettings = Default::default(); let mut settings: GlobalSettings = Default::default();
let matches = match uu_app().usage(&usage[..]).get_matches_from_safe(args) { let matches = match uu_app()
.override_usage(&usage[..])
.try_get_matches_from(args)
{
Ok(t) => t, Ok(t) => t,
Err(e) => { Err(e) => {
// not all clap "Errors" are because of a failure to parse arguments. // not all clap "Errors" are because of a failure to parse arguments.
@ -1072,11 +1075,9 @@ pub fn uumain(args: impl uucore::Args) -> UResult<()> {
// nor return with a non-zero exit code in this case (we should print to stdout and return 0). // nor return with a non-zero exit code in this case (we should print to stdout and return 0).
// This logic is similar to the code in clap, but we return 2 as the exit code in case of real failure // This logic is similar to the code in clap, but we return 2 as the exit code in case of real failure
// (clap returns 1). // (clap returns 1).
e.print().unwrap();
if e.use_stderr() { if e.use_stderr() {
eprintln!("{}", e.message);
set_exit_code(2); set_exit_code(2);
} else {
println!("{}", e.message);
} }
return Ok(()); return Ok(());
} }
@ -1209,11 +1210,11 @@ pub fn uumain(args: impl uucore::Args) -> UResult<()> {
)); ));
} }
if let Some(arg) = matches.args.get(options::SEPARATOR) { if let Some(arg) = matches.value_of_os(options::SEPARATOR) {
let mut separator = arg.vals[0].to_str().ok_or_else(|| { let mut separator = arg.to_str().ok_or_else(|| {
UUsageError::new( UUsageError::new(
2, 2,
format!("separator is not valid unicode: {}", arg.vals[0].quote()), format!("separator is not valid unicode: {}", arg.quote()),
) )
})?; })?;
if separator == "\\0" { if separator == "\\0" {
@ -1276,12 +1277,12 @@ pub fn uumain(args: impl uucore::Args) -> UResult<()> {
exec(&mut files, &settings, output, &mut tmp_dir) exec(&mut files, &settings, output, &mut tmp_dir)
} }
pub fn uu_app() -> App<'static, 'static> { pub fn uu_app<'a>() -> App<'a> {
App::new(uucore::util_name()) App::new(uucore::util_name())
.version(crate_version!()) .version(crate_version!())
.about(ABOUT) .about(ABOUT)
.arg( .arg(
Arg::with_name(options::modes::SORT) Arg::new(options::modes::SORT)
.long(options::modes::SORT) .long(options::modes::SORT)
.takes_value(true) .takes_value(true)
.possible_values(&[ .possible_values(&[
@ -1296,37 +1297,37 @@ pub fn uu_app() -> App<'static, 'static> {
) )
.arg(make_sort_mode_arg( .arg(make_sort_mode_arg(
options::modes::HUMAN_NUMERIC, options::modes::HUMAN_NUMERIC,
"h", 'h',
"compare according to human readable sizes, eg 1M > 100k", "compare according to human readable sizes, eg 1M > 100k",
)) ))
.arg(make_sort_mode_arg( .arg(make_sort_mode_arg(
options::modes::MONTH, options::modes::MONTH,
"M", 'M',
"compare according to month name abbreviation", "compare according to month name abbreviation",
)) ))
.arg(make_sort_mode_arg( .arg(make_sort_mode_arg(
options::modes::NUMERIC, options::modes::NUMERIC,
"n", 'n',
"compare according to string numerical value", "compare according to string numerical value",
)) ))
.arg(make_sort_mode_arg( .arg(make_sort_mode_arg(
options::modes::GENERAL_NUMERIC, options::modes::GENERAL_NUMERIC,
"g", 'g',
"compare according to string general numerical value", "compare according to string general numerical value",
)) ))
.arg(make_sort_mode_arg( .arg(make_sort_mode_arg(
options::modes::VERSION, options::modes::VERSION,
"V", 'V',
"Sort by SemVer version number, eg 1.12.2 > 1.1.2", "Sort by SemVer version number, eg 1.12.2 > 1.1.2",
)) ))
.arg(make_sort_mode_arg( .arg(make_sort_mode_arg(
options::modes::RANDOM, options::modes::RANDOM,
"R", 'R',
"shuffle in random order", "shuffle in random order",
)) ))
.arg( .arg(
Arg::with_name(options::DICTIONARY_ORDER) Arg::new(options::DICTIONARY_ORDER)
.short("d") .short('d')
.long(options::DICTIONARY_ORDER) .long(options::DICTIONARY_ORDER)
.help("consider only blanks and alphanumeric characters") .help("consider only blanks and alphanumeric characters")
.conflicts_with_all(&[ .conflicts_with_all(&[
@ -1337,14 +1338,14 @@ pub fn uu_app() -> App<'static, 'static> {
]), ]),
) )
.arg( .arg(
Arg::with_name(options::MERGE) Arg::new(options::MERGE)
.short("m") .short('m')
.long(options::MERGE) .long(options::MERGE)
.help("merge already sorted files; do not sort"), .help("merge already sorted files; do not sort"),
) )
.arg( .arg(
Arg::with_name(options::check::CHECK) Arg::new(options::check::CHECK)
.short("c") .short('c')
.long(options::check::CHECK) .long(options::check::CHECK)
.takes_value(true) .takes_value(true)
.require_equals(true) .require_equals(true)
@ -1358,8 +1359,8 @@ pub fn uu_app() -> App<'static, 'static> {
.help("check for sorted input; do not sort"), .help("check for sorted input; do not sort"),
) )
.arg( .arg(
Arg::with_name(options::check::CHECK_SILENT) Arg::new(options::check::CHECK_SILENT)
.short("C") .short('C')
.long(options::check::CHECK_SILENT) .long(options::check::CHECK_SILENT)
.conflicts_with(options::OUTPUT) .conflicts_with(options::OUTPUT)
.help( .help(
@ -1368,14 +1369,14 @@ pub fn uu_app() -> App<'static, 'static> {
), ),
) )
.arg( .arg(
Arg::with_name(options::IGNORE_CASE) Arg::new(options::IGNORE_CASE)
.short("f") .short('f')
.long(options::IGNORE_CASE) .long(options::IGNORE_CASE)
.help("fold lower case to upper case characters"), .help("fold lower case to upper case characters"),
) )
.arg( .arg(
Arg::with_name(options::IGNORE_NONPRINTING) Arg::new(options::IGNORE_NONPRINTING)
.short("i") .short('i')
.long(options::IGNORE_NONPRINTING) .long(options::IGNORE_NONPRINTING)
.help("ignore nonprinting characters") .help("ignore nonprinting characters")
.conflicts_with_all(&[ .conflicts_with_all(&[
@ -1386,113 +1387,116 @@ pub fn uu_app() -> App<'static, 'static> {
]), ]),
) )
.arg( .arg(
Arg::with_name(options::IGNORE_LEADING_BLANKS) Arg::new(options::IGNORE_LEADING_BLANKS)
.short("b") .short('b')
.long(options::IGNORE_LEADING_BLANKS) .long(options::IGNORE_LEADING_BLANKS)
.help("ignore leading blanks when finding sort keys in each line"), .help("ignore leading blanks when finding sort keys in each line"),
) )
.arg( .arg(
Arg::with_name(options::OUTPUT) Arg::new(options::OUTPUT)
.short("o") .short('o')
.long(options::OUTPUT) .long(options::OUTPUT)
.help("write output to FILENAME instead of stdout") .help("write output to FILENAME instead of stdout")
.takes_value(true) .takes_value(true)
.value_name("FILENAME"), .value_name("FILENAME"),
) )
.arg( .arg(
Arg::with_name(options::REVERSE) Arg::new(options::REVERSE)
.short("r") .short('r')
.long(options::REVERSE) .long(options::REVERSE)
.help("reverse the output"), .help("reverse the output"),
) )
.arg( .arg(
Arg::with_name(options::STABLE) Arg::new(options::STABLE)
.short("s") .short('s')
.long(options::STABLE) .long(options::STABLE)
.help("stabilize sort by disabling last-resort comparison"), .help("stabilize sort by disabling last-resort comparison"),
) )
.arg( .arg(
Arg::with_name(options::UNIQUE) Arg::new(options::UNIQUE)
.short("u") .short('u')
.long(options::UNIQUE) .long(options::UNIQUE)
.help("output only the first of an equal run"), .help("output only the first of an equal run"),
) )
.arg( .arg(
Arg::with_name(options::KEY) Arg::new(options::KEY)
.short("k") .short('k')
.long(options::KEY) .long(options::KEY)
.help("sort by a key") .help("sort by a key")
.long_help(LONG_HELP_KEYS) .long_help(LONG_HELP_KEYS)
.multiple(true) .multiple_occurrences(true)
.number_of_values(1) .number_of_values(1)
.takes_value(true), .takes_value(true),
) )
.arg( .arg(
Arg::with_name(options::SEPARATOR) Arg::new(options::SEPARATOR)
.short("t") .short('t')
.long(options::SEPARATOR) .long(options::SEPARATOR)
.help("custom separator for -k") .help("custom separator for -k")
.takes_value(true), .takes_value(true)
.allow_invalid_utf8(true),
) )
.arg( .arg(
Arg::with_name(options::ZERO_TERMINATED) Arg::new(options::ZERO_TERMINATED)
.short("z") .short('z')
.long(options::ZERO_TERMINATED) .long(options::ZERO_TERMINATED)
.help("line delimiter is NUL, not newline"), .help("line delimiter is NUL, not newline"),
) )
.arg( .arg(
Arg::with_name(options::PARALLEL) Arg::new(options::PARALLEL)
.long(options::PARALLEL) .long(options::PARALLEL)
.help("change the number of threads running concurrently to NUM_THREADS") .help("change the number of threads running concurrently to NUM_THREADS")
.takes_value(true) .takes_value(true)
.value_name("NUM_THREADS"), .value_name("NUM_THREADS"),
) )
.arg( .arg(
Arg::with_name(options::BUF_SIZE) Arg::new(options::BUF_SIZE)
.short("S") .short('S')
.long(options::BUF_SIZE) .long(options::BUF_SIZE)
.help("sets the maximum SIZE of each segment in number of sorted items") .help("sets the maximum SIZE of each segment in number of sorted items")
.takes_value(true) .takes_value(true)
.value_name("SIZE"), .value_name("SIZE"),
) )
.arg( .arg(
Arg::with_name(options::TMP_DIR) Arg::new(options::TMP_DIR)
.short("T") .short('T')
.long(options::TMP_DIR) .long(options::TMP_DIR)
.help("use DIR for temporaries, not $TMPDIR or /tmp") .help("use DIR for temporaries, not $TMPDIR or /tmp")
.takes_value(true) .takes_value(true)
.value_name("DIR"), .value_name("DIR"),
) )
.arg( .arg(
Arg::with_name(options::COMPRESS_PROG) Arg::new(options::COMPRESS_PROG)
.long(options::COMPRESS_PROG) .long(options::COMPRESS_PROG)
.help("compress temporary files with PROG, decompress with PROG -d") .help("compress temporary files with PROG, decompress with PROG -d")
.long_help("PROG has to take input from stdin and output to stdout") .long_help("PROG has to take input from stdin and output to stdout")
.value_name("PROG"), .value_name("PROG"),
) )
.arg( .arg(
Arg::with_name(options::BATCH_SIZE) Arg::new(options::BATCH_SIZE)
.long(options::BATCH_SIZE) .long(options::BATCH_SIZE)
.help("Merge at most N_MERGE inputs at once.") .help("Merge at most N_MERGE inputs at once.")
.value_name("N_MERGE"), .value_name("N_MERGE"),
) )
.arg( .arg(
Arg::with_name(options::FILES0_FROM) Arg::new(options::FILES0_FROM)
.long(options::FILES0_FROM) .long(options::FILES0_FROM)
.help("read input from the files specified by NUL-terminated NUL_FILES") .help("read input from the files specified by NUL-terminated NUL_FILES")
.takes_value(true) .takes_value(true)
.value_name("NUL_FILES") .value_name("NUL_FILES")
.multiple(true), .multiple_occurrences(true)
.allow_invalid_utf8(true),
) )
.arg( .arg(
Arg::with_name(options::DEBUG) Arg::new(options::DEBUG)
.long(options::DEBUG) .long(options::DEBUG)
.help("underline the parts of the line that are actually used for sorting"), .help("underline the parts of the line that are actually used for sorting"),
) )
.arg( .arg(
Arg::with_name(options::FILES) Arg::new(options::FILES)
.multiple(true) .multiple_occurrences(true)
.takes_value(true), .takes_value(true)
.allow_invalid_utf8(true),
) )
} }

View file

@ -996,7 +996,8 @@ fn test_conflict_check_out() {
.arg("-o=/dev/null") .arg("-o=/dev/null")
.fails() .fails()
.stderr_contains( .stderr_contains(
"error: The argument '--output <FILENAME>' cannot be used with '--check", // the rest of the message might be subject to change
"error: The argument",
); );
} }
} }