1
Fork 0
mirror of https://github.com/RGBCube/uutils-coreutils synced 2025-07-30 12:37:49 +00:00

Merge pull request #1610 from sylvestre/sort-clap

refactor(sort): move to use of 'clap'
This commit is contained in:
Roy Ivy III 2020-10-25 18:56:58 -05:00 committed by GitHub
commit 5837bc4fc9
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
3 changed files with 136 additions and 91 deletions

2
Cargo.lock generated
View file

@ -2096,7 +2096,7 @@ dependencies = [
name = "uu_sort" name = "uu_sort"
version = "0.0.1" version = "0.0.1"
dependencies = [ dependencies = [
"getopts 0.2.21 (registry+https://github.com/rust-lang/crates.io-index)", "clap 2.33.3 (registry+https://github.com/rust-lang/crates.io-index)",
"itertools 0.8.2 (registry+https://github.com/rust-lang/crates.io-index)", "itertools 0.8.2 (registry+https://github.com/rust-lang/crates.io-index)",
"semver 0.9.0 (registry+https://github.com/rust-lang/crates.io-index)", "semver 0.9.0 (registry+https://github.com/rust-lang/crates.io-index)",
"uucore 0.0.4 (git+https://github.com/uutils/uucore.git?branch=canary)", "uucore 0.0.4 (git+https://github.com/uutils/uucore.git?branch=canary)",

View file

@ -15,7 +15,7 @@ edition = "2018"
path = "src/sort.rs" path = "src/sort.rs"
[dependencies] [dependencies]
getopts = "0.2.18" clap = "2.33"
itertools = "0.8.0" itertools = "0.8.0"
semver = "0.9.0" semver = "0.9.0"
uucore = { version="0.0.4", package="uucore", git="https://github.com/uutils/uucore.git", branch="canary", features=["fs"] } uucore = { version="0.0.4", package="uucore", git="https://github.com/uutils/uucore.git", branch="canary", features=["fs"] }

View file

@ -8,13 +8,14 @@
// spell-checker:ignore (ToDO) outfile nondictionary // spell-checker:ignore (ToDO) outfile nondictionary
extern crate getopts; extern crate clap;
extern crate semver; extern crate semver;
extern crate itertools; extern crate itertools;
#[macro_use] #[macro_use]
extern crate uucore; extern crate uucore;
use clap::{App, Arg};
use itertools::Itertools; use itertools::Itertools;
use semver::Version; use semver::Version;
use std::cmp::Ordering; use std::cmp::Ordering;
@ -26,10 +27,27 @@ use std::path::Path;
use uucore::fs::is_stdin_interactive; // for Iterator::dedup() use uucore::fs::is_stdin_interactive; // for Iterator::dedup()
static NAME: &str = "sort"; static NAME: &str = "sort";
static ABOUT: &str = "Display sorted concatenation of all FILE(s).";
static VERSION: &str = env!("CARGO_PKG_VERSION"); static VERSION: &str = env!("CARGO_PKG_VERSION");
const DECIMAL_PT: char = '.'; static OPT_HUMAN_NUMERIC_SORT: &str = "human-numeric-sort";
const THOUSANDS_SEP: char = ','; static OPT_MONTH_SORT: &str = "month-sort";
static OPT_NUMERIC_SORT: &str = "numeric-sort";
static OPT_VERSION_SORT: &str = "version-sort";
static OPT_DICTIONARY_ORDER: &str = "dictionary-order";
static OPT_MERGE: &str = "merge";
static OPT_CHECK: &str = "check";
static OPT_IGNORE_CASE: &str = "ignore-case";
static OPT_OUTPUT: &str = "output";
static OPT_REVERSE: &str = "reverse";
static OPT_STABLE: &str = "stable";
static OPT_UNIQUE: &str = "unique";
static ARG_FILES: &str = "files";
static DECIMAL_PT: char = '.';
static THOUSANDS_SEP: char = ',';
enum SortMode { enum SortMode {
Numeric, Numeric,
@ -142,68 +160,9 @@ impl<'a> Iterator for FileMerger<'a> {
} }
} }
} }
fn get_usage() -> String {
pub fn uumain(args: impl uucore::Args) -> i32 { format!(
let args = args.collect_str(); "{0} {1}
let mut settings: Settings = Default::default();
let mut opts = getopts::Options::new();
opts.optflag(
"d",
"dictionary-order",
"consider only blanks and alphanumeric characters",
);
opts.optflag(
"f",
"ignore-case",
"fold lower case to upper case characters",
);
opts.optflag(
"n",
"numeric-sort",
"compare according to string numerical value",
);
opts.optflag(
"h",
"human-numeric-sort",
"compare according to human readable sizes, eg 1M > 100k",
);
opts.optflag(
"M",
"month-sort",
"compare according to month name abbreviation",
);
opts.optflag("r", "reverse", "reverse the output");
opts.optflag("h", "help", "display this help and exit");
opts.optflag("", "version", "output version information and exit");
opts.optflag("m", "merge", "merge already sorted files; do not sort");
opts.optopt(
"o",
"output",
"write output to FILENAME instead of stdout",
"FILENAME",
);
opts.optflag(
"s",
"stable",
"stabilize sort by disabling last-resort comparison",
);
opts.optflag("u", "unique", "output only the first of an equal run");
opts.optflag(
"V",
"version-sort",
"Sort by SemVer version number, eg 1.12.2 > 1.1.2",
);
opts.optflag("c", "check", "check for sorted input; do not sort");
let matches = match opts.parse(&args[1..]) {
Ok(m) => m,
Err(f) => crash!(1, "Invalid options\n{}", f),
};
if matches.opt_present("help") {
let msg = format!(
"{0} {1}
Usage: Usage:
{0} [OPTION]... [FILE]... {0} [OPTION]... [FILE]...
@ -213,44 +172,130 @@ Write the sorted concatenation of all FILE(s) to standard output.
Mandatory arguments for long options are mandatory for short options too. Mandatory arguments for long options are mandatory for short options too.
With no FILE, or when FILE is -, read standard input.", With no FILE, or when FILE is -, read standard input.",
NAME, VERSION NAME, VERSION
); )
print!("{}", opts.usage(&msg)); }
return 0;
}
if matches.opt_present("version") { pub fn uumain(args: impl uucore::Args) -> i32 {
println!("{} {}", NAME, VERSION); let args = args.collect_str();
return 0; let usage = get_usage();
} let mut settings: Settings = Default::default();
settings.mode = if matches.opt_present("numeric-sort") { let matches = App::new(executable!())
SortMode::Numeric .version(VERSION)
} else if matches.opt_present("human-numeric-sort") { .about(ABOUT)
.usage(&usage[..])
.arg(
Arg::with_name(OPT_HUMAN_NUMERIC_SORT)
.short("h")
.long(OPT_HUMAN_NUMERIC_SORT)
.help("compare according to human readable sizes, eg 1M > 100k"),
)
.arg(
Arg::with_name(OPT_MONTH_SORT)
.short("M")
.long(OPT_MONTH_SORT)
.help("compare according to month name abbreviation"),
)
.arg(
Arg::with_name(OPT_NUMERIC_SORT)
.short("n")
.long(OPT_NUMERIC_SORT)
.help("compare according to string numerical value"),
)
.arg(
Arg::with_name(OPT_VERSION_SORT)
.short("V")
.long(OPT_VERSION_SORT)
.help("Sort by SemVer version number, eg 1.12.2 > 1.1.2"),
)
.arg(
Arg::with_name(OPT_DICTIONARY_ORDER)
.short("d")
.long(OPT_DICTIONARY_ORDER)
.help("consider only blanks and alphanumeric characters"),
)
.arg(
Arg::with_name(OPT_MERGE)
.short("m")
.long(OPT_MERGE)
.help("merge already sorted files; do not sort"),
)
.arg(
Arg::with_name(OPT_CHECK)
.short("c")
.long(OPT_CHECK)
.help("check for sorted input; do not sort"),
)
.arg(
Arg::with_name(OPT_IGNORE_CASE)
.short("f")
.long(OPT_IGNORE_CASE)
.help("fold lower case to upper case characters"),
)
.arg(
Arg::with_name(OPT_OUTPUT)
.short("o")
.long(OPT_OUTPUT)
.help("write output to FILENAME instead of stdout")
.takes_value(true)
.value_name("FILENAME"),
)
.arg(
Arg::with_name(OPT_REVERSE)
.short("r")
.long(OPT_REVERSE)
.help("reverse the output"),
)
.arg(
Arg::with_name(OPT_STABLE)
.short("s")
.long(OPT_STABLE)
.help("stabilize sort by disabling last-resort comparison"),
)
.arg(
Arg::with_name(OPT_UNIQUE)
.short("u")
.long(OPT_UNIQUE)
.help("output only the first of an equal run"),
)
.arg(Arg::with_name(ARG_FILES).multiple(true).takes_value(true))
.get_matches_from(args);
let mut files: Vec<String> = matches
.values_of(ARG_FILES)
.map(|v| v.map(ToString::to_string).collect())
.unwrap_or_default();
settings.mode = if matches.is_present(OPT_HUMAN_NUMERIC_SORT) {
SortMode::HumanNumeric SortMode::HumanNumeric
} else if matches.opt_present("month-sort") { } else if matches.is_present(OPT_MONTH_SORT) {
SortMode::Month SortMode::Month
} else if matches.opt_present("version-sort") { } else if matches.is_present(OPT_NUMERIC_SORT) {
SortMode::Numeric
} else if matches.is_present(OPT_VERSION_SORT) {
SortMode::Version SortMode::Version
} else { } else {
SortMode::Default SortMode::Default
}; };
settings.merge = matches.opt_present("merge"); if matches.is_present(OPT_DICTIONARY_ORDER) {
settings.reverse = matches.opt_present("reverse");
settings.outfile = matches.opt_str("output");
settings.stable = matches.opt_present("stable");
settings.unique = matches.opt_present("unique");
settings.check = matches.opt_present("check");
if matches.opt_present("dictionary-order") {
settings.transform_fns.push(remove_nondictionary_chars); settings.transform_fns.push(remove_nondictionary_chars);
} }
if matches.opt_present("ignore-case") {
settings.merge = matches.is_present(OPT_MERGE);
settings.check = matches.is_present(OPT_CHECK);
if matches.is_present(OPT_IGNORE_CASE) {
settings.transform_fns.push(|s| s.to_uppercase()); settings.transform_fns.push(|s| s.to_uppercase());
} }
let mut files = matches.free; settings.outfile = matches.value_of(OPT_OUTPUT).map(String::from);
settings.reverse = matches.is_present(OPT_REVERSE);
settings.stable = matches.is_present(OPT_STABLE);
settings.unique = matches.is_present(OPT_UNIQUE);
//let mut files = matches.free;
if files.is_empty() { if files.is_empty() {
/* if no file, default to stdin */ /* if no file, default to stdin */
files.push("-".to_owned()); files.push("-".to_owned());