mirror of
https://github.com/RGBCube/uutils-coreutils
synced 2025-07-30 20:47:46 +00:00
Merge pull request #2162 from bashi8128/basename-clap
basename: move from getopts to clap
This commit is contained in:
commit
1edf4064f3
3 changed files with 100 additions and 39 deletions
|
@ -15,6 +15,7 @@ edition = "2018"
|
||||||
path = "src/basename.rs"
|
path = "src/basename.rs"
|
||||||
|
|
||||||
[dependencies]
|
[dependencies]
|
||||||
|
clap = "2.33.2"
|
||||||
uucore = { version=">=0.0.8", package="uucore", path="../../uucore" }
|
uucore = { version=">=0.0.8", package="uucore", path="../../uucore" }
|
||||||
uucore_procs = { version=">=0.0.5", package="uucore_procs", path="../../uucore_procs" }
|
uucore_procs = { version=">=0.0.5", package="uucore_procs", path="../../uucore_procs" }
|
||||||
|
|
||||||
|
|
|
@ -10,83 +10,106 @@
|
||||||
#[macro_use]
|
#[macro_use]
|
||||||
extern crate uucore;
|
extern crate uucore;
|
||||||
|
|
||||||
|
use clap::{App, Arg};
|
||||||
use std::path::{is_separator, PathBuf};
|
use std::path::{is_separator, PathBuf};
|
||||||
use uucore::InvalidEncodingHandling;
|
use uucore::InvalidEncodingHandling;
|
||||||
|
|
||||||
static NAME: &str = "basename";
|
static VERSION: &str = env!("CARGO_PKG_VERSION");
|
||||||
static SYNTAX: &str = "NAME [SUFFIX]";
|
|
||||||
static SUMMARY: &str = "Print NAME with any leading directory components removed
|
static SUMMARY: &str = "Print NAME with any leading directory components removed
|
||||||
If specified, also remove a trailing SUFFIX";
|
If specified, also remove a trailing SUFFIX";
|
||||||
static LONG_HELP: &str = "";
|
|
||||||
|
fn get_usage() -> String {
|
||||||
|
format!(
|
||||||
|
"{0} NAME [SUFFIX]
|
||||||
|
{0} OPTION... NAME...",
|
||||||
|
executable!()
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
pub mod options {
|
||||||
|
pub static MULTIPLE: &str = "multiple";
|
||||||
|
pub static NAME: &str = "name";
|
||||||
|
pub static SUFFIX: &str = "suffix";
|
||||||
|
pub static ZERO: &str = "zero";
|
||||||
|
}
|
||||||
|
|
||||||
pub fn uumain(args: impl uucore::Args) -> i32 {
|
pub fn uumain(args: impl uucore::Args) -> i32 {
|
||||||
let args = args
|
let args = args
|
||||||
.collect_str(InvalidEncodingHandling::ConvertLossy)
|
.collect_str(InvalidEncodingHandling::ConvertLossy)
|
||||||
.accept_any();
|
.accept_any();
|
||||||
|
let usage = get_usage();
|
||||||
//
|
//
|
||||||
// Argument parsing
|
// Argument parsing
|
||||||
//
|
//
|
||||||
let matches = app!(SYNTAX, SUMMARY, LONG_HELP)
|
let matches = App::new(executable!())
|
||||||
.optflag(
|
.version(VERSION)
|
||||||
"a",
|
.about(SUMMARY)
|
||||||
"multiple",
|
.usage(&usage[..])
|
||||||
"Support more than one argument. Treat every argument as a name.",
|
.arg(
|
||||||
|
Arg::with_name(options::MULTIPLE)
|
||||||
|
.short("a")
|
||||||
|
.long(options::MULTIPLE)
|
||||||
|
.help("support multiple arguments and treat each as a NAME"),
|
||||||
)
|
)
|
||||||
.optopt(
|
.arg(Arg::with_name(options::NAME).multiple(true).hidden(true))
|
||||||
"s",
|
.arg(
|
||||||
"suffix",
|
Arg::with_name(options::SUFFIX)
|
||||||
"Remove a trailing suffix. This option implies the -a option.",
|
.short("s")
|
||||||
"SUFFIX",
|
.long(options::SUFFIX)
|
||||||
|
.value_name("SUFFIX")
|
||||||
|
.help("remove a trailing SUFFIX; implies -a"),
|
||||||
)
|
)
|
||||||
.optflag(
|
.arg(
|
||||||
"z",
|
Arg::with_name(options::ZERO)
|
||||||
"zero",
|
.short("z")
|
||||||
"Output a zero byte (ASCII NUL) at the end of each line, rather than a newline.",
|
.long(options::ZERO)
|
||||||
|
.help("end each output line with NUL, not newline"),
|
||||||
)
|
)
|
||||||
.parse(args);
|
.get_matches_from(args);
|
||||||
|
|
||||||
// too few arguments
|
// too few arguments
|
||||||
if matches.free.is_empty() {
|
if !matches.is_present(options::NAME) {
|
||||||
crash!(
|
crash!(
|
||||||
1,
|
1,
|
||||||
"{0}: {1}\nTry '{0} --help' for more information.",
|
"{1}\nTry '{0} --help' for more information.",
|
||||||
NAME,
|
executable!(),
|
||||||
"missing operand"
|
"missing operand"
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
let opt_s = matches.opt_present("s");
|
|
||||||
let opt_a = matches.opt_present("a");
|
let opt_suffix = matches.is_present(options::SUFFIX);
|
||||||
let opt_z = matches.opt_present("z");
|
let opt_multiple = matches.is_present(options::MULTIPLE);
|
||||||
let multiple_paths = opt_s || opt_a;
|
let opt_zero = matches.is_present(options::ZERO);
|
||||||
|
let multiple_paths = opt_suffix || opt_multiple;
|
||||||
// too many arguments
|
// too many arguments
|
||||||
if !multiple_paths && matches.free.len() > 2 {
|
if !multiple_paths && matches.occurrences_of(options::NAME) > 2 {
|
||||||
crash!(
|
crash!(
|
||||||
1,
|
1,
|
||||||
"{0}: extra operand '{1}'\nTry '{0} --help' for more information.",
|
"extra operand '{1}'\nTry '{0} --help' for more information.",
|
||||||
NAME,
|
executable!(),
|
||||||
matches.free[2]
|
matches.values_of(options::NAME).unwrap().nth(2).unwrap()
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
let suffix = if opt_s {
|
let suffix = if opt_suffix {
|
||||||
matches.opt_str("s").unwrap()
|
matches.value_of(options::SUFFIX).unwrap()
|
||||||
} else if !opt_a && matches.free.len() > 1 {
|
} else if !opt_multiple && matches.occurrences_of(options::NAME) > 1 {
|
||||||
matches.free[1].clone()
|
matches.values_of(options::NAME).unwrap().nth(1).unwrap()
|
||||||
} else {
|
} else {
|
||||||
"".to_owned()
|
""
|
||||||
};
|
};
|
||||||
|
|
||||||
//
|
//
|
||||||
// Main Program Processing
|
// Main Program Processing
|
||||||
//
|
//
|
||||||
|
|
||||||
let paths = if multiple_paths {
|
let paths: Vec<_> = if multiple_paths {
|
||||||
&matches.free[..]
|
matches.values_of(options::NAME).unwrap().collect()
|
||||||
} else {
|
} else {
|
||||||
&matches.free[0..1]
|
matches.values_of(options::NAME).unwrap().take(1).collect()
|
||||||
};
|
};
|
||||||
|
|
||||||
let line_ending = if opt_z { "\0" } else { "\n" };
|
let line_ending = if opt_zero { "\0" } else { "\n" };
|
||||||
for path in paths {
|
for path in paths {
|
||||||
print!("{}{}", basename(&path, &suffix), line_ending);
|
print!("{}{}", basename(&path, &suffix), line_ending);
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,6 +1,29 @@
|
||||||
use crate::common::util::*;
|
use crate::common::util::*;
|
||||||
use std::ffi::OsStr;
|
use std::ffi::OsStr;
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn test_help() {
|
||||||
|
for help_flg in vec!["-h", "--help"] {
|
||||||
|
new_ucmd!()
|
||||||
|
.arg(&help_flg)
|
||||||
|
.succeeds()
|
||||||
|
.no_stderr()
|
||||||
|
.stdout_contains("USAGE:");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn test_version() {
|
||||||
|
for version_flg in vec!["-V", "--version"] {
|
||||||
|
assert!(new_ucmd!()
|
||||||
|
.arg(&version_flg)
|
||||||
|
.succeeds()
|
||||||
|
.no_stderr()
|
||||||
|
.stdout_str()
|
||||||
|
.starts_with("basename"));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
fn test_directory() {
|
fn test_directory() {
|
||||||
new_ucmd!()
|
new_ucmd!()
|
||||||
|
@ -81,11 +104,25 @@ fn test_no_args() {
|
||||||
expect_error(vec![]);
|
expect_error(vec![]);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn test_no_args_output() {
|
||||||
|
new_ucmd!()
|
||||||
|
.fails()
|
||||||
|
.stderr_is("basename: error: missing operand\nTry 'basename --help' for more information.");
|
||||||
|
}
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
fn test_too_many_args() {
|
fn test_too_many_args() {
|
||||||
expect_error(vec!["a", "b", "c"]);
|
expect_error(vec!["a", "b", "c"]);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn test_too_many_args_output() {
|
||||||
|
new_ucmd!().args(&["a", "b", "c"]).fails().stderr_is(
|
||||||
|
"basename: error: extra operand 'c'\nTry 'basename --help' for more information.",
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
fn test_invalid_utf8_args(os_str: &OsStr) {
|
fn test_invalid_utf8_args(os_str: &OsStr) {
|
||||||
let test_vec = vec![os_str.to_os_string()];
|
let test_vec = vec![os_str.to_os_string()];
|
||||||
new_ucmd!().args(&test_vec).succeeds().stdout_is("fo<EFBFBD>o\n");
|
new_ucmd!().args(&test_vec).succeeds().stdout_is("fo<EFBFBD>o\n");
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue