1
Fork 0
mirror of https://github.com/RGBCube/uutils-coreutils synced 2025-07-31 13:07:46 +00:00

sort: update to clap 4

This commit is contained in:
Terts Diepraam 2022-10-01 00:00:53 +02:00
parent 6a98c4c7d0
commit c11d6b45cc
2 changed files with 64 additions and 49 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 = "3.2", features = ["wrap_help", "cargo"] } clap = { version = "4.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

@ -26,7 +26,7 @@ mod tmp_dir;
use chunks::LineData; use chunks::LineData;
use clap::builder::ValueParser; 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 custom_str_cmp::custom_str_cmp;
use ext_sort::ext_sort; use ext_sort::ext_sort;
use fnv::FnvHasher; use fnv::FnvHasher;
@ -99,6 +99,7 @@ mod options {
} }
pub const HELP: &str = "help"; pub const HELP: &str = "help";
pub const VERSION: &str = "version";
pub const DICTIONARY_ORDER: &str = "dictionary-order"; pub const DICTIONARY_ORDER: &str = "dictionary-order";
pub const MERGE: &str = "merge"; pub const MERGE: &str = "merge";
pub const DEBUG: &str = "debug"; pub const DEBUG: &str = "debug";
@ -1044,8 +1045,12 @@ impl FieldSelector {
} }
/// 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>(mode: &'a str, short: char, help: &'a str) -> Arg<'a> { 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); let mut arg = Arg::new(mode)
.short(short)
.long(mode)
.help(help)
.action(ArgAction::SetTrue);
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);
@ -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 // check whether user specified a zero terminated list of files for input, otherwise read files from args
let mut files: Vec<OsString> = if matches.contains_id(options::FILES0_FROM) { let mut files: Vec<OsString> = if matches.contains_id(options::FILES0_FROM) {
@ -1103,42 +1108,42 @@ pub fn uumain(args: impl uucore::Args) -> UResult<()> {
.unwrap_or_default() .unwrap_or_default()
}; };
settings.mode = if matches.contains_id(options::modes::HUMAN_NUMERIC) settings.mode = if matches.get_flag(options::modes::HUMAN_NUMERIC)
|| matches || matches
.get_one::<String>(options::modes::SORT) .get_one::<String>(options::modes::SORT)
.map(|s| s.as_str()) .map(|s| s.as_str())
== Some("human-numeric") == Some("human-numeric")
{ {
SortMode::HumanNumeric SortMode::HumanNumeric
} else if matches.contains_id(options::modes::MONTH) } else if matches.get_flag(options::modes::MONTH)
|| matches || matches
.get_one::<String>(options::modes::SORT) .get_one::<String>(options::modes::SORT)
.map(|s| s.as_str()) .map(|s| s.as_str())
== Some("month") == Some("month")
{ {
SortMode::Month SortMode::Month
} else if matches.contains_id(options::modes::GENERAL_NUMERIC) } else if matches.get_flag(options::modes::GENERAL_NUMERIC)
|| matches || matches
.get_one::<String>(options::modes::SORT) .get_one::<String>(options::modes::SORT)
.map(|s| s.as_str()) .map(|s| s.as_str())
== Some("general-numeric") == Some("general-numeric")
{ {
SortMode::GeneralNumeric SortMode::GeneralNumeric
} else if matches.contains_id(options::modes::NUMERIC) } else if matches.get_flag(options::modes::NUMERIC)
|| matches || matches
.get_one::<String>(options::modes::SORT) .get_one::<String>(options::modes::SORT)
.map(|s| s.as_str()) .map(|s| s.as_str())
== Some("numeric") == Some("numeric")
{ {
SortMode::Numeric SortMode::Numeric
} else if matches.contains_id(options::modes::VERSION) } else if matches.get_flag(options::modes::VERSION)
|| matches || matches
.get_one::<String>(options::modes::SORT) .get_one::<String>(options::modes::SORT)
.map(|s| s.as_str()) .map(|s| s.as_str())
== Some("version") == Some("version")
{ {
SortMode::Version SortMode::Version
} else if matches.contains_id(options::modes::RANDOM) } else if matches.get_flag(options::modes::RANDOM)
|| matches || matches
.get_one::<String>(options::modes::SORT) .get_one::<String>(options::modes::SORT)
.map(|s| s.as_str()) .map(|s| s.as_str())
@ -1150,8 +1155,8 @@ pub fn uumain(args: impl uucore::Args) -> UResult<()> {
SortMode::Default SortMode::Default
}; };
settings.dictionary_order = matches.contains_id(options::DICTIONARY_ORDER); settings.dictionary_order = matches.get_flag(options::DICTIONARY_ORDER);
settings.ignore_non_printing = matches.contains_id(options::IGNORE_NONPRINTING); settings.ignore_non_printing = matches.get_flag(options::IGNORE_NONPRINTING);
if matches.contains_id(options::PARALLEL) { if matches.contains_id(options::PARALLEL) {
// "0" is default - threads = num of cores // "0" is default - threads = num of cores
settings.threads = matches 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.zero_terminated = matches.get_flag(options::ZERO_TERMINATED);
settings.merge = matches.contains_id(options::MERGE); settings.merge = matches.get_flag(options::MERGE);
settings.check = matches.contains_id(options::check::CHECK); 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!(
matches matches
.get_one::<String>(options::check::CHECK) .get_one::<String>(options::check::CHECK)
@ -1206,13 +1211,13 @@ pub fn uumain(args: impl uucore::Args) -> UResult<()> {
settings.check = true; 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.reverse = matches.get_flag(options::REVERSE);
settings.stable = matches.contains_id(options::STABLE); settings.stable = matches.get_flag(options::STABLE);
settings.unique = matches.contains_id(options::UNIQUE); settings.unique = matches.get_flag(options::UNIQUE);
if files.is_empty() { if files.is_empty() {
/* if no file, default to stdin */ /* if no file, default to stdin */
@ -1299,22 +1304,30 @@ pub fn uumain(args: impl uucore::Args) -> UResult<()> {
result result
} }
pub fn uu_app<'a>() -> Command<'a> { pub fn uu_app() -> Command {
Command::new(uucore::util_name()) Command::new(uucore::util_name())
.version(crate_version!()) .version(crate_version!())
.about(ABOUT) .about(ABOUT)
.after_help(LONG_HELP_KEYS) .after_help(LONG_HELP_KEYS)
.override_usage(format_usage(USAGE)) .override_usage(format_usage(USAGE))
.infer_long_args(true) .infer_long_args(true)
.disable_help_flag(true)
.disable_version_flag(true)
.arg( .arg(
Arg::new(options::HELP) Arg::new(options::HELP)
.long(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(
Arg::new(options::modes::SORT) Arg::new(options::modes::SORT)
.long(options::modes::SORT) .long(options::modes::SORT)
.takes_value(true)
.value_parser([ .value_parser([
"general-numeric", "general-numeric",
"human-numeric", "human-numeric",
@ -1365,21 +1378,22 @@ pub fn uu_app<'a>() -> Command<'a> {
options::modes::GENERAL_NUMERIC, options::modes::GENERAL_NUMERIC,
options::modes::HUMAN_NUMERIC, options::modes::HUMAN_NUMERIC,
options::modes::MONTH, options::modes::MONTH,
]), ])
.action(ArgAction::SetTrue),
) )
.arg( .arg(
Arg::new(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")
.action(ArgAction::SetTrue),
) )
.arg( .arg(
Arg::new(options::check::CHECK) Arg::new(options::check::CHECK)
.short('c') .short('c')
.long(options::check::CHECK) .long(options::check::CHECK)
.takes_value(true)
.require_equals(true) .require_equals(true)
.min_values(0) .num_args(0..)
.value_parser([ .value_parser([
options::check::SILENT, options::check::SILENT,
options::check::QUIET, options::check::QUIET,
@ -1396,13 +1410,15 @@ pub fn uu_app<'a>() -> Command<'a> {
.help( .help(
"exit successfully if the given file is already sorted, \ "exit successfully if the given file is already sorted, \
and exit with status 1 otherwise.", and exit with status 1 otherwise.",
), )
.action(ArgAction::SetTrue),
) )
.arg( .arg(
Arg::new(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")
.action(ArgAction::SetTrue),
) )
.arg( .arg(
Arg::new(options::IGNORE_NONPRINTING) Arg::new(options::IGNORE_NONPRINTING)
@ -1414,20 +1430,21 @@ pub fn uu_app<'a>() -> Command<'a> {
options::modes::GENERAL_NUMERIC, options::modes::GENERAL_NUMERIC,
options::modes::HUMAN_NUMERIC, options::modes::HUMAN_NUMERIC,
options::modes::MONTH, options::modes::MONTH,
]), ])
.action(ArgAction::SetTrue),
) )
.arg( .arg(
Arg::new(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")
.action(ArgAction::SetTrue),
) )
.arg( .arg(
Arg::new(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)
.value_name("FILENAME") .value_name("FILENAME")
.value_hint(clap::ValueHint::FilePath), .value_hint(clap::ValueHint::FilePath),
) )
@ -1435,48 +1452,49 @@ pub fn uu_app<'a>() -> Command<'a> {
Arg::new(options::REVERSE) Arg::new(options::REVERSE)
.short('r') .short('r')
.long(options::REVERSE) .long(options::REVERSE)
.help("reverse the output"), .help("reverse the output")
.action(ArgAction::SetTrue),
) )
.arg( .arg(
Arg::new(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")
.action(ArgAction::SetTrue),
) )
.arg( .arg(
Arg::new(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")
.action(ArgAction::SetTrue),
) )
.arg( .arg(
Arg::new(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")
.multiple_occurrences(true) .action(ArgAction::Append)
.number_of_values(1) .num_args(1),
.takes_value(true),
) )
.arg( .arg(
Arg::new(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)
.value_parser(ValueParser::os_string()), .value_parser(ValueParser::os_string()),
) )
.arg( .arg(
Arg::new(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")
.action(ArgAction::SetTrue),
) )
.arg( .arg(
Arg::new(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)
.value_name("NUM_THREADS"), .value_name("NUM_THREADS"),
) )
.arg( .arg(
@ -1484,7 +1502,6 @@ pub fn uu_app<'a>() -> Command<'a> {
.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)
.value_name("SIZE"), .value_name("SIZE"),
) )
.arg( .arg(
@ -1492,7 +1509,6 @@ pub fn uu_app<'a>() -> Command<'a> {
.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)
.value_name("DIR") .value_name("DIR")
.value_hint(clap::ValueHint::DirPath), .value_hint(clap::ValueHint::DirPath),
) )
@ -1513,21 +1529,20 @@ pub fn uu_app<'a>() -> Command<'a> {
Arg::new(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)
.value_name("NUL_FILES") .value_name("NUL_FILES")
.multiple_occurrences(true) .action(ArgAction::Append)
.value_parser(ValueParser::os_string()) .value_parser(ValueParser::os_string())
.value_hint(clap::ValueHint::FilePath), .value_hint(clap::ValueHint::FilePath),
) )
.arg( .arg(
Arg::new(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")
.action(ArgAction::SetTrue),
) )
.arg( .arg(
Arg::new(options::FILES) Arg::new(options::FILES)
.multiple_occurrences(true) .action(ArgAction::Append)
.takes_value(true)
.value_parser(ValueParser::os_string()) .value_parser(ValueParser::os_string())
.value_hint(clap::ValueHint::FilePath), .value_hint(clap::ValueHint::FilePath),
) )