1
Fork 0
mirror of https://github.com/RGBCube/uutils-coreutils synced 2025-07-29 12:07:46 +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"
version = "0.0.1"
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)",
"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)",

View file

@ -15,7 +15,7 @@ edition = "2018"
path = "src/sort.rs"
[dependencies]
getopts = "0.2.18"
clap = "2.33"
itertools = "0.8.0"
semver = "0.9.0"
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
extern crate getopts;
extern crate clap;
extern crate semver;
extern crate itertools;
#[macro_use]
extern crate uucore;
use clap::{App, Arg};
use itertools::Itertools;
use semver::Version;
use std::cmp::Ordering;
@ -26,10 +27,27 @@ use std::path::Path;
use uucore::fs::is_stdin_interactive; // for Iterator::dedup()
static NAME: &str = "sort";
static ABOUT: &str = "Display sorted concatenation of all FILE(s).";
static VERSION: &str = env!("CARGO_PKG_VERSION");
const DECIMAL_PT: char = '.';
const THOUSANDS_SEP: char = ',';
static OPT_HUMAN_NUMERIC_SORT: &str = "human-numeric-sort";
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 {
Numeric,
@ -142,68 +160,9 @@ impl<'a> Iterator for FileMerger<'a> {
}
}
}
pub fn uumain(args: impl uucore::Args) -> i32 {
let args = args.collect_str();
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}
fn get_usage() -> String {
format!(
"{0} {1}
Usage:
{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.
With no FILE, or when FILE is -, read standard input.",
NAME, VERSION
);
print!("{}", opts.usage(&msg));
return 0;
}
NAME, VERSION
)
}
if matches.opt_present("version") {
println!("{} {}", NAME, VERSION);
return 0;
}
pub fn uumain(args: impl uucore::Args) -> i32 {
let args = args.collect_str();
let usage = get_usage();
let mut settings: Settings = Default::default();
settings.mode = if matches.opt_present("numeric-sort") {
SortMode::Numeric
} else if matches.opt_present("human-numeric-sort") {
let matches = App::new(executable!())
.version(VERSION)
.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
} else if matches.opt_present("month-sort") {
} else if matches.is_present(OPT_MONTH_SORT) {
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
} else {
SortMode::Default
};
settings.merge = matches.opt_present("merge");
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") {
if matches.is_present(OPT_DICTIONARY_ORDER) {
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());
}
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 no file, default to stdin */
files.push("-".to_owned());