diff --git a/src/uu/sort/Cargo.toml b/src/uu/sort/Cargo.toml index c41bf8ca3..bcfb7bfa3 100644 --- a/src/uu/sort/Cargo.toml +++ b/src/uu/sort/Cargo.toml @@ -16,7 +16,7 @@ path = "src/sort.rs" [dependencies] binary-heap-plus = "0.4.1" -clap = { version = "3.2", features = ["wrap_help", "cargo"] } +clap = { version = "4.0", features = ["wrap_help", "cargo"] } compare = "0.1.0" ctrlc = { version = "3.0", features = ["termination"] } fnv = "1.0.7" diff --git a/src/uu/sort/src/sort.rs b/src/uu/sort/src/sort.rs index 5f21c508e..c1bb750be 100644 --- a/src/uu/sort/src/sort.rs +++ b/src/uu/sort/src/sort.rs @@ -26,7 +26,7 @@ mod tmp_dir; use chunks::LineData; use clap::builder::ValueParser; -use clap::{crate_version, Arg, Command}; +use clap::{crate_version, Arg, ArgAction, Command}; use custom_str_cmp::custom_str_cmp; use ext_sort::ext_sort; use fnv::FnvHasher; @@ -99,6 +99,7 @@ mod options { } pub const HELP: &str = "help"; + pub const VERSION: &str = "version"; pub const DICTIONARY_ORDER: &str = "dictionary-order"; pub const MERGE: &str = "merge"; pub const DEBUG: &str = "debug"; @@ -1044,8 +1045,12 @@ impl FieldSelector { } /// Creates an `Arg` that conflicts with all other sort modes. -fn make_sort_mode_arg<'a>(mode: &'a str, short: char, help: &'a str) -> Arg<'a> { - let mut arg = Arg::new(mode).short(short).long(mode).help(help); +fn make_sort_mode_arg(mode: &'static str, short: char, help: &'static str) -> Arg { + let mut arg = Arg::new(mode) + .short(short) + .long(mode) + .help(help) + .action(ArgAction::SetTrue); for possible_mode in &options::modes::ALL_SORT_MODES { if *possible_mode != mode { arg = arg.conflicts_with(possible_mode); @@ -1075,7 +1080,7 @@ pub fn uumain(args: impl uucore::Args) -> UResult<()> { } }; - settings.debug = matches.contains_id(options::DEBUG); + settings.debug = matches.get_flag(options::DEBUG); // check whether user specified a zero terminated list of files for input, otherwise read files from args let mut files: Vec = if matches.contains_id(options::FILES0_FROM) { @@ -1103,42 +1108,42 @@ pub fn uumain(args: impl uucore::Args) -> UResult<()> { .unwrap_or_default() }; - settings.mode = if matches.contains_id(options::modes::HUMAN_NUMERIC) + settings.mode = if matches.get_flag(options::modes::HUMAN_NUMERIC) || matches .get_one::(options::modes::SORT) .map(|s| s.as_str()) == Some("human-numeric") { SortMode::HumanNumeric - } else if matches.contains_id(options::modes::MONTH) + } else if matches.get_flag(options::modes::MONTH) || matches .get_one::(options::modes::SORT) .map(|s| s.as_str()) == Some("month") { SortMode::Month - } else if matches.contains_id(options::modes::GENERAL_NUMERIC) + } else if matches.get_flag(options::modes::GENERAL_NUMERIC) || matches .get_one::(options::modes::SORT) .map(|s| s.as_str()) == Some("general-numeric") { SortMode::GeneralNumeric - } else if matches.contains_id(options::modes::NUMERIC) + } else if matches.get_flag(options::modes::NUMERIC) || matches .get_one::(options::modes::SORT) .map(|s| s.as_str()) == Some("numeric") { SortMode::Numeric - } else if matches.contains_id(options::modes::VERSION) + } else if matches.get_flag(options::modes::VERSION) || matches .get_one::(options::modes::SORT) .map(|s| s.as_str()) == Some("version") { SortMode::Version - } else if matches.contains_id(options::modes::RANDOM) + } else if matches.get_flag(options::modes::RANDOM) || matches .get_one::(options::modes::SORT) .map(|s| s.as_str()) @@ -1150,8 +1155,8 @@ pub fn uumain(args: impl uucore::Args) -> UResult<()> { SortMode::Default }; - settings.dictionary_order = matches.contains_id(options::DICTIONARY_ORDER); - settings.ignore_non_printing = matches.contains_id(options::IGNORE_NONPRINTING); + settings.dictionary_order = matches.get_flag(options::DICTIONARY_ORDER); + settings.ignore_non_printing = matches.get_flag(options::IGNORE_NONPRINTING); if matches.contains_id(options::PARALLEL) { // "0" is default - threads = num of cores settings.threads = matches @@ -1190,11 +1195,11 @@ pub fn uumain(args: impl uucore::Args) -> UResult<()> { })?; } - settings.zero_terminated = matches.contains_id(options::ZERO_TERMINATED); - settings.merge = matches.contains_id(options::MERGE); + settings.zero_terminated = matches.get_flag(options::ZERO_TERMINATED); + settings.merge = matches.get_flag(options::MERGE); settings.check = matches.contains_id(options::check::CHECK); - if matches.contains_id(options::check::CHECK_SILENT) + if matches.get_flag(options::check::CHECK_SILENT) || matches!( matches .get_one::(options::check::CHECK) @@ -1206,13 +1211,13 @@ pub fn uumain(args: impl uucore::Args) -> UResult<()> { settings.check = true; }; - settings.ignore_case = matches.contains_id(options::IGNORE_CASE); + settings.ignore_case = matches.get_flag(options::IGNORE_CASE); - settings.ignore_leading_blanks = matches.contains_id(options::IGNORE_LEADING_BLANKS); + settings.ignore_leading_blanks = matches.get_flag(options::IGNORE_LEADING_BLANKS); - settings.reverse = matches.contains_id(options::REVERSE); - settings.stable = matches.contains_id(options::STABLE); - settings.unique = matches.contains_id(options::UNIQUE); + settings.reverse = matches.get_flag(options::REVERSE); + settings.stable = matches.get_flag(options::STABLE); + settings.unique = matches.get_flag(options::UNIQUE); if files.is_empty() { /* if no file, default to stdin */ @@ -1299,22 +1304,30 @@ pub fn uumain(args: impl uucore::Args) -> UResult<()> { result } -pub fn uu_app<'a>() -> Command<'a> { +pub fn uu_app() -> Command { Command::new(uucore::util_name()) .version(crate_version!()) .about(ABOUT) .after_help(LONG_HELP_KEYS) .override_usage(format_usage(USAGE)) .infer_long_args(true) + .disable_help_flag(true) + .disable_version_flag(true) .arg( Arg::new(options::HELP) .long(options::HELP) - .help("Print help information."), + .help("Print help information.") + .action(ArgAction::Help), + ) + .arg( + Arg::new(options::VERSION) + .long(options::VERSION) + .help("Print version information.") + .action(ArgAction::Version), ) .arg( Arg::new(options::modes::SORT) .long(options::modes::SORT) - .takes_value(true) .value_parser([ "general-numeric", "human-numeric", @@ -1365,21 +1378,22 @@ pub fn uu_app<'a>() -> Command<'a> { options::modes::GENERAL_NUMERIC, options::modes::HUMAN_NUMERIC, options::modes::MONTH, - ]), + ]) + .action(ArgAction::SetTrue), ) .arg( Arg::new(options::MERGE) .short('m') .long(options::MERGE) - .help("merge already sorted files; do not sort"), + .help("merge already sorted files; do not sort") + .action(ArgAction::SetTrue), ) .arg( Arg::new(options::check::CHECK) .short('c') .long(options::check::CHECK) - .takes_value(true) .require_equals(true) - .min_values(0) + .num_args(0..) .value_parser([ options::check::SILENT, options::check::QUIET, @@ -1396,13 +1410,15 @@ pub fn uu_app<'a>() -> Command<'a> { .help( "exit successfully if the given file is already sorted, \ and exit with status 1 otherwise.", - ), + ) + .action(ArgAction::SetTrue), ) .arg( Arg::new(options::IGNORE_CASE) .short('f') .long(options::IGNORE_CASE) - .help("fold lower case to upper case characters"), + .help("fold lower case to upper case characters") + .action(ArgAction::SetTrue), ) .arg( Arg::new(options::IGNORE_NONPRINTING) @@ -1414,20 +1430,21 @@ pub fn uu_app<'a>() -> Command<'a> { options::modes::GENERAL_NUMERIC, options::modes::HUMAN_NUMERIC, options::modes::MONTH, - ]), + ]) + .action(ArgAction::SetTrue), ) .arg( Arg::new(options::IGNORE_LEADING_BLANKS) .short('b') .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") + .action(ArgAction::SetTrue), ) .arg( Arg::new(options::OUTPUT) .short('o') .long(options::OUTPUT) .help("write output to FILENAME instead of stdout") - .takes_value(true) .value_name("FILENAME") .value_hint(clap::ValueHint::FilePath), ) @@ -1435,48 +1452,49 @@ pub fn uu_app<'a>() -> Command<'a> { Arg::new(options::REVERSE) .short('r') .long(options::REVERSE) - .help("reverse the output"), + .help("reverse the output") + .action(ArgAction::SetTrue), ) .arg( Arg::new(options::STABLE) .short('s') .long(options::STABLE) - .help("stabilize sort by disabling last-resort comparison"), + .help("stabilize sort by disabling last-resort comparison") + .action(ArgAction::SetTrue), ) .arg( Arg::new(options::UNIQUE) .short('u') .long(options::UNIQUE) - .help("output only the first of an equal run"), + .help("output only the first of an equal run") + .action(ArgAction::SetTrue), ) .arg( Arg::new(options::KEY) .short('k') .long(options::KEY) .help("sort by a key") - .multiple_occurrences(true) - .number_of_values(1) - .takes_value(true), + .action(ArgAction::Append) + .num_args(1), ) .arg( Arg::new(options::SEPARATOR) .short('t') .long(options::SEPARATOR) .help("custom separator for -k") - .takes_value(true) .value_parser(ValueParser::os_string()), ) .arg( Arg::new(options::ZERO_TERMINATED) .short('z') .long(options::ZERO_TERMINATED) - .help("line delimiter is NUL, not newline"), + .help("line delimiter is NUL, not newline") + .action(ArgAction::SetTrue), ) .arg( Arg::new(options::PARALLEL) .long(options::PARALLEL) .help("change the number of threads running concurrently to NUM_THREADS") - .takes_value(true) .value_name("NUM_THREADS"), ) .arg( @@ -1484,7 +1502,6 @@ pub fn uu_app<'a>() -> Command<'a> { .short('S') .long(options::BUF_SIZE) .help("sets the maximum SIZE of each segment in number of sorted items") - .takes_value(true) .value_name("SIZE"), ) .arg( @@ -1492,7 +1509,6 @@ pub fn uu_app<'a>() -> Command<'a> { .short('T') .long(options::TMP_DIR) .help("use DIR for temporaries, not $TMPDIR or /tmp") - .takes_value(true) .value_name("DIR") .value_hint(clap::ValueHint::DirPath), ) @@ -1513,21 +1529,20 @@ pub fn uu_app<'a>() -> Command<'a> { Arg::new(options::FILES0_FROM) .long(options::FILES0_FROM) .help("read input from the files specified by NUL-terminated NUL_FILES") - .takes_value(true) .value_name("NUL_FILES") - .multiple_occurrences(true) + .action(ArgAction::Append) .value_parser(ValueParser::os_string()) .value_hint(clap::ValueHint::FilePath), ) .arg( Arg::new(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") + .action(ArgAction::SetTrue), ) .arg( Arg::new(options::FILES) - .multiple_occurrences(true) - .takes_value(true) + .action(ArgAction::Append) .value_parser(ValueParser::os_string()) .value_hint(clap::ValueHint::FilePath), )