mirror of
https://github.com/RGBCube/uutils-coreutils
synced 2025-07-30 12:37:49 +00:00
Merge branch 'master' into split-uresult
This commit is contained in:
commit
64effa5e78
23 changed files with 208 additions and 432 deletions
6
.github/workflows/CICD.yml
vendored
6
.github/workflows/CICD.yml
vendored
|
@ -844,13 +844,13 @@ jobs:
|
||||||
## Generate coverage data
|
## Generate coverage data
|
||||||
COVERAGE_REPORT_DIR="target/debug"
|
COVERAGE_REPORT_DIR="target/debug"
|
||||||
COVERAGE_REPORT_FILE="${COVERAGE_REPORT_DIR}/lcov.info"
|
COVERAGE_REPORT_FILE="${COVERAGE_REPORT_DIR}/lcov.info"
|
||||||
# GRCOV_IGNORE_OPTION='--ignore build.rs --ignore "/*" --ignore "[a-zA-Z]:/*"' ## `grcov` ignores these params when passed as an environment variable (why?)
|
# GRCOV_IGNORE_OPTION='--ignore build.rs --ignore "vendor/*" --ignore "/*" --ignore "[a-zA-Z]:/*"' ## `grcov` ignores these params when passed as an environment variable (why?)
|
||||||
# GRCOV_EXCLUDE_OPTION='--excl-br-line "^\s*((debug_)?assert(_eq|_ne)?!|#\[derive\()"' ## `grcov` ignores these params when passed as an environment variable (why?)
|
# GRCOV_EXCLUDE_OPTION='--excl-br-line "^\s*((debug_)?assert(_eq|_ne)?!|#\[derive\()"' ## `grcov` ignores these params when passed as an environment variable (why?)
|
||||||
mkdir -p "${COVERAGE_REPORT_DIR}"
|
mkdir -p "${COVERAGE_REPORT_DIR}"
|
||||||
# display coverage files
|
# display coverage files
|
||||||
grcov . --output-type files --ignore build.rs --ignore "/*" --ignore "[a-zA-Z]:/*" --excl-br-line "^\s*((debug_)?assert(_eq|_ne)?!|#\[derive\()" | sort --unique
|
grcov . --output-type files --ignore build.rs --ignore "vendor/*" --ignore "/*" --ignore "[a-zA-Z]:/*" --excl-br-line "^\s*((debug_)?assert(_eq|_ne)?!|#\[derive\()" | sort --unique
|
||||||
# generate coverage report
|
# generate coverage report
|
||||||
grcov . --output-type lcov --output-path "${COVERAGE_REPORT_FILE}" --branch --ignore build.rs --ignore "/*" --ignore "[a-zA-Z]:/*" --excl-br-line "^\s*((debug_)?assert(_eq|_ne)?!|#\[derive\()"
|
grcov . --output-type lcov --output-path "${COVERAGE_REPORT_FILE}" --branch --ignore build.rs --ignore "vendor/*" --ignore "/*" --ignore "[a-zA-Z]:/*" --excl-br-line "^\s*((debug_)?assert(_eq|_ne)?!|#\[derive\()"
|
||||||
echo ::set-output name=report::${COVERAGE_REPORT_FILE}
|
echo ::set-output name=report::${COVERAGE_REPORT_FILE}
|
||||||
- name: Upload coverage results (to Codecov.io)
|
- name: Upload coverage results (to Codecov.io)
|
||||||
uses: codecov/codecov-action@v1
|
uses: codecov/codecov-action@v1
|
||||||
|
|
1
Cargo.lock
generated
1
Cargo.lock
generated
|
@ -3238,7 +3238,6 @@ dependencies = [
|
||||||
"data-encoding-macro",
|
"data-encoding-macro",
|
||||||
"dns-lookup",
|
"dns-lookup",
|
||||||
"dunce",
|
"dunce",
|
||||||
"getopts",
|
|
||||||
"lazy_static",
|
"lazy_static",
|
||||||
"libc",
|
"libc",
|
||||||
"nix 0.23.1",
|
"nix 0.23.1",
|
||||||
|
|
|
@ -2,7 +2,8 @@
|
||||||
|
|
||||||
#![allow(clippy::upper_case_acronyms)]
|
#![allow(clippy::upper_case_acronyms)]
|
||||||
|
|
||||||
use uucore::{display::Quotable, show_error, show_usage_error, show_warning};
|
use uucore::error::{UResult, USimpleError, UUsageError};
|
||||||
|
use uucore::{display::Quotable, show_error, show_warning};
|
||||||
|
|
||||||
use clap::{App, Arg};
|
use clap::{App, Arg};
|
||||||
use selinux::{OpaqueSecurityContext, SecurityContext};
|
use selinux::{OpaqueSecurityContext, SecurityContext};
|
||||||
|
@ -60,7 +61,8 @@ fn get_usage() -> String {
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn uumain(args: impl uucore::Args) -> i32 {
|
#[uucore_procs::gen_uumain]
|
||||||
|
pub fn uumain(args: impl uucore::Args) -> UResult<()> {
|
||||||
let usage = get_usage();
|
let usage = get_usage();
|
||||||
|
|
||||||
let config = uu_app().usage(usage.as_ref());
|
let config = uu_app().usage(usage.as_ref());
|
||||||
|
@ -72,14 +74,13 @@ pub fn uumain(args: impl uucore::Args) -> i32 {
|
||||||
match r.kind {
|
match r.kind {
|
||||||
clap::ErrorKind::HelpDisplayed | clap::ErrorKind::VersionDisplayed => {
|
clap::ErrorKind::HelpDisplayed | clap::ErrorKind::VersionDisplayed => {
|
||||||
println!("{}", r);
|
println!("{}", r);
|
||||||
return libc::EXIT_SUCCESS;
|
return Ok(());
|
||||||
}
|
}
|
||||||
_ => {}
|
_ => {}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
show_usage_error!("{}.\n", r);
|
return Err(UUsageError::new(libc::EXIT_FAILURE, format!("{}.\n", r)));
|
||||||
return libc::EXIT_FAILURE;
|
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
|
@ -98,8 +99,10 @@ pub fn uumain(args: impl uucore::Args) -> i32 {
|
||||||
|
|
||||||
match result {
|
match result {
|
||||||
Err(r) => {
|
Err(r) => {
|
||||||
show_error!("{}.", report_full_error(&r));
|
return Err(USimpleError::new(
|
||||||
return libc::EXIT_FAILURE;
|
libc::EXIT_FAILURE,
|
||||||
|
format!("{}.", report_full_error(&r)),
|
||||||
|
));
|
||||||
}
|
}
|
||||||
|
|
||||||
Ok(file_context) => SELinuxSecurityContext::File(file_context),
|
Ok(file_context) => SELinuxSecurityContext::File(file_context),
|
||||||
|
@ -111,14 +114,18 @@ pub fn uumain(args: impl uucore::Args) -> i32 {
|
||||||
Ok(context) => context,
|
Ok(context) => context,
|
||||||
|
|
||||||
Err(_r) => {
|
Err(_r) => {
|
||||||
show_error!("Invalid security context {}.", context.quote());
|
return Err(USimpleError::new(
|
||||||
return libc::EXIT_FAILURE;
|
libc::EXIT_FAILURE,
|
||||||
|
format!("Invalid security context {}.", context.quote()),
|
||||||
|
));
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
if SecurityContext::from_c_str(&c_context, false).check() == Some(false) {
|
if SecurityContext::from_c_str(&c_context, false).check() == Some(false) {
|
||||||
show_error!("Invalid security context {}.", context.quote());
|
return Err(USimpleError::new(
|
||||||
return libc::EXIT_FAILURE;
|
libc::EXIT_FAILURE,
|
||||||
|
format!("Invalid security context {}.", context.quote()),
|
||||||
|
));
|
||||||
}
|
}
|
||||||
|
|
||||||
SELinuxSecurityContext::String(Some(c_context))
|
SELinuxSecurityContext::String(Some(c_context))
|
||||||
|
@ -132,8 +139,10 @@ pub fn uumain(args: impl uucore::Args) -> i32 {
|
||||||
Ok(r) => Some(r),
|
Ok(r) => Some(r),
|
||||||
|
|
||||||
Err(r) => {
|
Err(r) => {
|
||||||
show_error!("{}.", report_full_error(&r));
|
return Err(USimpleError::new(
|
||||||
return libc::EXIT_FAILURE;
|
libc::EXIT_FAILURE,
|
||||||
|
format!("{}.", report_full_error(&r)),
|
||||||
|
));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
|
@ -142,13 +151,13 @@ pub fn uumain(args: impl uucore::Args) -> i32 {
|
||||||
|
|
||||||
let results = process_files(&options, &context, root_dev_ino);
|
let results = process_files(&options, &context, root_dev_ino);
|
||||||
if results.is_empty() {
|
if results.is_empty() {
|
||||||
return libc::EXIT_SUCCESS;
|
return Ok(());
|
||||||
}
|
}
|
||||||
|
|
||||||
for result in &results {
|
for result in &results {
|
||||||
show_error!("{}.", report_full_error(result));
|
show_error!("{}.", report_full_error(result));
|
||||||
}
|
}
|
||||||
libc::EXIT_FAILURE
|
Err(libc::EXIT_FAILURE.into())
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn uu_app() -> App<'static, 'static> {
|
pub fn uu_app() -> App<'static, 'static> {
|
||||||
|
|
|
@ -466,12 +466,7 @@ pub fn uumain(args: impl uucore::Args) -> UResult<()> {
|
||||||
delim = "=";
|
delim = "=";
|
||||||
}
|
}
|
||||||
if delim.chars().count() > 1 {
|
if delim.chars().count() > 1 {
|
||||||
Err(msg_opt_invalid_should_be!(
|
Err("invalid input: The '--delimiter' ('-d') option expects empty or 1 character long, but was provided a value 2 characters or longer".into())
|
||||||
"empty or 1 character long",
|
|
||||||
"a value 2 characters or longer",
|
|
||||||
"--delimiter",
|
|
||||||
"-d"
|
|
||||||
))
|
|
||||||
} else {
|
} else {
|
||||||
let delim = if delim.is_empty() {
|
let delim = if delim.is_empty() {
|
||||||
"\0".to_owned()
|
"\0".to_owned()
|
||||||
|
@ -503,13 +498,9 @@ pub fn uumain(args: impl uucore::Args) -> UResult<()> {
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
(ref b, ref c, ref f) if b.is_some() || c.is_some() || f.is_some() => Err(
|
(ref b, ref c, ref f) if b.is_some() || c.is_some() || f.is_some() => Err(
|
||||||
msg_expects_no_more_than_one_of!("--fields (-f)", "--chars (-c)", "--bytes (-b)"),
|
"invalid usage: expects no more than one of --fields (-f), --chars (-c) or --bytes (-b)".into()
|
||||||
),
|
),
|
||||||
_ => Err(msg_expects_one_of!(
|
_ => Err("invalid usage: expects one of --fields (-f), --chars (-c) or --bytes (-b)".into()),
|
||||||
"--fields (-f)",
|
|
||||||
"--chars (-c)",
|
|
||||||
"--bytes (-b)"
|
|
||||||
)),
|
|
||||||
};
|
};
|
||||||
|
|
||||||
let mode_parse = match mode_parse {
|
let mode_parse = match mode_parse {
|
||||||
|
@ -518,20 +509,12 @@ pub fn uumain(args: impl uucore::Args) -> UResult<()> {
|
||||||
Mode::Bytes(_, _) | Mode::Characters(_, _)
|
Mode::Bytes(_, _) | Mode::Characters(_, _)
|
||||||
if matches.is_present(options::DELIMITER) =>
|
if matches.is_present(options::DELIMITER) =>
|
||||||
{
|
{
|
||||||
Err(msg_opt_only_usable_if!(
|
Err("invalid input: The '--delimiter' ('-d') option only usable if printing a sequence of fields".into())
|
||||||
"printing a sequence of fields",
|
|
||||||
"--delimiter",
|
|
||||||
"-d"
|
|
||||||
))
|
|
||||||
}
|
}
|
||||||
Mode::Bytes(_, _) | Mode::Characters(_, _)
|
Mode::Bytes(_, _) | Mode::Characters(_, _)
|
||||||
if matches.is_present(options::ONLY_DELIMITED) =>
|
if matches.is_present(options::ONLY_DELIMITED) =>
|
||||||
{
|
{
|
||||||
Err(msg_opt_only_usable_if!(
|
Err("invalid input: The '--only-delimited' ('-s') option only usable if printing a sequence of fields".into())
|
||||||
"printing a sequence of fields",
|
|
||||||
"--only-delimited",
|
|
||||||
"-s"
|
|
||||||
))
|
|
||||||
}
|
}
|
||||||
_ => Ok(mode),
|
_ => Ok(mode),
|
||||||
},
|
},
|
||||||
|
|
|
@ -18,7 +18,7 @@ use std::env;
|
||||||
use std::fs;
|
use std::fs;
|
||||||
#[cfg(not(windows))]
|
#[cfg(not(windows))]
|
||||||
use std::fs::Metadata;
|
use std::fs::Metadata;
|
||||||
use std::io::{stderr, ErrorKind, Result, Write};
|
use std::io::{ErrorKind, Result};
|
||||||
use std::iter;
|
use std::iter;
|
||||||
#[cfg(not(windows))]
|
#[cfg(not(windows))]
|
||||||
use std::os::unix::fs::MetadataExt;
|
use std::os::unix::fs::MetadataExt;
|
||||||
|
@ -292,8 +292,7 @@ fn du(
|
||||||
let read = match fs::read_dir(&my_stat.path) {
|
let read = match fs::read_dir(&my_stat.path) {
|
||||||
Ok(read) => read,
|
Ok(read) => read,
|
||||||
Err(e) => {
|
Err(e) => {
|
||||||
safe_writeln!(
|
eprintln!(
|
||||||
stderr(),
|
|
||||||
"{}: cannot read directory {}: {}",
|
"{}: cannot read directory {}: {}",
|
||||||
options.util_name,
|
options.util_name,
|
||||||
my_stat.path.quote(),
|
my_stat.path.quote(),
|
||||||
|
|
|
@ -413,7 +413,7 @@ impl<'a> State<'a> {
|
||||||
|
|
||||||
// This is fatal if the check is enabled.
|
// This is fatal if the check is enabled.
|
||||||
if input.check_order == CheckOrder::Enabled {
|
if input.check_order == CheckOrder::Enabled {
|
||||||
exit!(1);
|
std::process::exit(1);
|
||||||
}
|
}
|
||||||
|
|
||||||
self.has_failed = true;
|
self.has_failed = true;
|
||||||
|
|
|
@ -220,16 +220,32 @@ fn format_string(
|
||||||
options: &NumfmtOptions,
|
options: &NumfmtOptions,
|
||||||
implicit_padding: Option<isize>,
|
implicit_padding: Option<isize>,
|
||||||
) -> Result<String> {
|
) -> Result<String> {
|
||||||
|
// strip the (optional) suffix before applying any transformation
|
||||||
|
let source_without_suffix = match &options.suffix {
|
||||||
|
Some(suffix) => source.strip_suffix(suffix).unwrap_or(source),
|
||||||
|
None => source,
|
||||||
|
};
|
||||||
|
|
||||||
let number = transform_to(
|
let number = transform_to(
|
||||||
transform_from(source, &options.transform.from)?,
|
transform_from(source_without_suffix, &options.transform.from)?,
|
||||||
&options.transform.to,
|
&options.transform.to,
|
||||||
options.round,
|
options.round,
|
||||||
)?;
|
)?;
|
||||||
|
|
||||||
|
// bring back the suffix before applying padding
|
||||||
|
let number_with_suffix = match &options.suffix {
|
||||||
|
Some(suffix) => format!("{}{}", number, suffix),
|
||||||
|
None => number,
|
||||||
|
};
|
||||||
|
|
||||||
Ok(match implicit_padding.unwrap_or(options.padding) {
|
Ok(match implicit_padding.unwrap_or(options.padding) {
|
||||||
0 => number,
|
0 => number_with_suffix,
|
||||||
p if p > 0 => format!("{:>padding$}", number, padding = p as usize),
|
p if p > 0 => format!("{:>padding$}", number_with_suffix, padding = p as usize),
|
||||||
p => format!("{:<padding$}", number, padding = p.abs() as usize),
|
p => format!(
|
||||||
|
"{:<padding$}",
|
||||||
|
number_with_suffix,
|
||||||
|
padding = p.abs() as usize
|
||||||
|
),
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -142,6 +142,8 @@ fn parse_options(args: &ArgMatches) -> Result<NumfmtOptions> {
|
||||||
_ => unreachable!("Should be restricted by clap"),
|
_ => unreachable!("Should be restricted by clap"),
|
||||||
};
|
};
|
||||||
|
|
||||||
|
let suffix = args.value_of(options::SUFFIX).map(|s| s.to_owned());
|
||||||
|
|
||||||
Ok(NumfmtOptions {
|
Ok(NumfmtOptions {
|
||||||
transform,
|
transform,
|
||||||
padding,
|
padding,
|
||||||
|
@ -149,6 +151,7 @@ fn parse_options(args: &ArgMatches) -> Result<NumfmtOptions> {
|
||||||
fields,
|
fields,
|
||||||
delimiter,
|
delimiter,
|
||||||
round,
|
round,
|
||||||
|
suffix,
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -242,5 +245,14 @@ pub fn uu_app() -> App<'static, 'static> {
|
||||||
.default_value("from-zero")
|
.default_value("from-zero")
|
||||||
.possible_values(&["up", "down", "from-zero", "towards-zero", "nearest"]),
|
.possible_values(&["up", "down", "from-zero", "towards-zero", "nearest"]),
|
||||||
)
|
)
|
||||||
|
.arg(
|
||||||
|
Arg::with_name(options::SUFFIX)
|
||||||
|
.long(options::SUFFIX)
|
||||||
|
.help(
|
||||||
|
"print SUFFIX after each formatted number, and accept \
|
||||||
|
inputs optionally ending with SUFFIX",
|
||||||
|
)
|
||||||
|
.value_name("SUFFIX"),
|
||||||
|
)
|
||||||
.arg(Arg::with_name(options::NUMBER).hidden(true).multiple(true))
|
.arg(Arg::with_name(options::NUMBER).hidden(true).multiple(true))
|
||||||
}
|
}
|
||||||
|
|
|
@ -11,6 +11,7 @@ pub const HEADER_DEFAULT: &str = "1";
|
||||||
pub const NUMBER: &str = "NUMBER";
|
pub const NUMBER: &str = "NUMBER";
|
||||||
pub const PADDING: &str = "padding";
|
pub const PADDING: &str = "padding";
|
||||||
pub const ROUND: &str = "round";
|
pub const ROUND: &str = "round";
|
||||||
|
pub const SUFFIX: &str = "suffix";
|
||||||
pub const TO: &str = "to";
|
pub const TO: &str = "to";
|
||||||
pub const TO_DEFAULT: &str = "none";
|
pub const TO_DEFAULT: &str = "none";
|
||||||
|
|
||||||
|
@ -26,6 +27,7 @@ pub struct NumfmtOptions {
|
||||||
pub fields: Vec<Range>,
|
pub fields: Vec<Range>,
|
||||||
pub delimiter: Option<String>,
|
pub delimiter: Option<String>,
|
||||||
pub round: RoundMethod,
|
pub round: RoundMethod,
|
||||||
|
pub suffix: Option<String>,
|
||||||
}
|
}
|
||||||
|
|
||||||
#[derive(Clone, Copy)]
|
#[derive(Clone, Copy)]
|
||||||
|
|
|
@ -410,7 +410,7 @@ fn get_size(size_str_opt: Option<String>) -> Option<u64> {
|
||||||
util_name(),
|
util_name(),
|
||||||
size_str_opt.unwrap().maybe_quote()
|
size_str_opt.unwrap().maybe_quote()
|
||||||
);
|
);
|
||||||
exit!(1);
|
std::process::exit(1);
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
|
@ -20,17 +20,23 @@ mod platform {
|
||||||
}
|
}
|
||||||
|
|
||||||
fn main() {
|
fn main() {
|
||||||
let manifest_dir = env::var("CARGO_MANIFEST_DIR").expect("Could not find manifest dir");
|
|
||||||
let profile = env::var("PROFILE").expect("Could not determine profile");
|
|
||||||
|
|
||||||
let out_dir = env::var("OUT_DIR").unwrap();
|
let out_dir = env::var("OUT_DIR").unwrap();
|
||||||
let libstdbuf = format!(
|
let mut target_dir = Path::new(&out_dir);
|
||||||
"{}/../../../{}/{}/deps/liblibstdbuf{}",
|
|
||||||
manifest_dir,
|
// Depending on how this is util is built, the directory structure. This seems to work for now.
|
||||||
env::var("CARGO_TARGET_DIR").unwrap_or_else(|_| "target".to_string()),
|
// Here are three cases to test when changing this:
|
||||||
profile,
|
// - cargo run
|
||||||
platform::DYLIB_EXT
|
// - cross run
|
||||||
);
|
// - cargo install --git
|
||||||
|
let mut name = target_dir.file_name().unwrap().to_string_lossy();
|
||||||
|
while name != "target" && !name.starts_with("cargo-install") {
|
||||||
|
target_dir = target_dir.parent().unwrap();
|
||||||
|
name = target_dir.file_name().unwrap().to_string_lossy();
|
||||||
|
}
|
||||||
|
let mut libstdbuf = target_dir.to_path_buf();
|
||||||
|
libstdbuf.push(env::var("PROFILE").unwrap());
|
||||||
|
libstdbuf.push("deps");
|
||||||
|
libstdbuf.push(format!("liblibstdbuf{}", platform::DYLIB_EXT));
|
||||||
|
|
||||||
fs::copy(libstdbuf, Path::new(&out_dir).join("libstdbuf.so")).unwrap();
|
fs::copy(libstdbuf, Path::new(&out_dir).join("libstdbuf.so")).unwrap();
|
||||||
}
|
}
|
||||||
|
|
|
@ -12,9 +12,10 @@ extern crate uucore;
|
||||||
|
|
||||||
use clap::{crate_version, App, Arg};
|
use clap::{crate_version, App, Arg};
|
||||||
use std::fs::File;
|
use std::fs::File;
|
||||||
use std::io::{stdin, Read, Result};
|
use std::io::{stdin, Read};
|
||||||
use std::path::Path;
|
use std::path::Path;
|
||||||
use uucore::display::Quotable;
|
use uucore::display::Quotable;
|
||||||
|
use uucore::error::{FromIo, UResult, USimpleError};
|
||||||
use uucore::InvalidEncodingHandling;
|
use uucore::InvalidEncodingHandling;
|
||||||
|
|
||||||
static NAME: &str = "sum";
|
static NAME: &str = "sum";
|
||||||
|
@ -65,26 +66,25 @@ fn sysv_sum(mut reader: Box<dyn Read>) -> (usize, u16) {
|
||||||
(blocks_read, ret as u16)
|
(blocks_read, ret as u16)
|
||||||
}
|
}
|
||||||
|
|
||||||
fn open(name: &str) -> Result<Box<dyn Read>> {
|
fn open(name: &str) -> UResult<Box<dyn Read>> {
|
||||||
match name {
|
match name {
|
||||||
"-" => Ok(Box::new(stdin()) as Box<dyn Read>),
|
"-" => Ok(Box::new(stdin()) as Box<dyn Read>),
|
||||||
_ => {
|
_ => {
|
||||||
let path = &Path::new(name);
|
let path = &Path::new(name);
|
||||||
if path.is_dir() {
|
if path.is_dir() {
|
||||||
return Err(std::io::Error::new(
|
return Err(USimpleError::new(
|
||||||
std::io::ErrorKind::InvalidInput,
|
2,
|
||||||
"Is a directory",
|
format!("{}: Is a directory", name.maybe_quote()),
|
||||||
));
|
));
|
||||||
};
|
};
|
||||||
// Silent the warning as we want to the error message
|
// Silent the warning as we want to the error message
|
||||||
#[allow(clippy::question_mark)]
|
|
||||||
if path.metadata().is_err() {
|
if path.metadata().is_err() {
|
||||||
return Err(std::io::Error::new(
|
return Err(USimpleError::new(
|
||||||
std::io::ErrorKind::NotFound,
|
2,
|
||||||
"No such file or directory",
|
format!("{}: No such file or directory", name.maybe_quote()),
|
||||||
));
|
));
|
||||||
};
|
};
|
||||||
let f = File::open(path)?;
|
let f = File::open(path).map_err_context(String::new)?;
|
||||||
Ok(Box::new(f) as Box<dyn Read>)
|
Ok(Box::new(f) as Box<dyn Read>)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -96,7 +96,8 @@ mod options {
|
||||||
pub static SYSTEM_V_COMPATIBLE: &str = "sysv";
|
pub static SYSTEM_V_COMPATIBLE: &str = "sysv";
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn uumain(args: impl uucore::Args) -> i32 {
|
#[uucore_procs::gen_uumain]
|
||||||
|
pub fn uumain(args: impl uucore::Args) -> UResult<()> {
|
||||||
let args = args
|
let args = args
|
||||||
.collect_str(InvalidEncodingHandling::ConvertLossy)
|
.collect_str(InvalidEncodingHandling::ConvertLossy)
|
||||||
.accept_any();
|
.accept_any();
|
||||||
|
@ -116,13 +117,11 @@ pub fn uumain(args: impl uucore::Args) -> i32 {
|
||||||
files.len() > 1
|
files.len() > 1
|
||||||
};
|
};
|
||||||
|
|
||||||
let mut exit_code = 0;
|
|
||||||
for file in &files {
|
for file in &files {
|
||||||
let reader = match open(file) {
|
let reader = match open(file) {
|
||||||
Ok(f) => f,
|
Ok(f) => f,
|
||||||
Err(error) => {
|
Err(error) => {
|
||||||
show_error!("{}: {}", file.maybe_quote(), error);
|
show!(error);
|
||||||
exit_code = 2;
|
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
@ -138,8 +137,7 @@ pub fn uumain(args: impl uucore::Args) -> i32 {
|
||||||
println!("{} {}", sum, blocks);
|
println!("{} {}", sum, blocks);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
Ok(())
|
||||||
exit_code
|
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn uu_app() -> App<'static, 'static> {
|
pub fn uu_app() -> App<'static, 'static> {
|
||||||
|
|
|
@ -9,14 +9,10 @@
|
||||||
|
|
||||||
extern crate libc;
|
extern crate libc;
|
||||||
|
|
||||||
#[macro_use]
|
|
||||||
extern crate uucore;
|
|
||||||
|
|
||||||
use clap::{crate_version, App, Arg};
|
use clap::{crate_version, App, Arg};
|
||||||
use std::path::Path;
|
use std::path::Path;
|
||||||
use uucore::display::Quotable;
|
use uucore::display::Quotable;
|
||||||
|
use uucore::error::{UResult, USimpleError};
|
||||||
static EXIT_ERR: i32 = 1;
|
|
||||||
|
|
||||||
static ABOUT: &str = "Synchronize cached writes to persistent storage";
|
static ABOUT: &str = "Synchronize cached writes to persistent storage";
|
||||||
pub mod options {
|
pub mod options {
|
||||||
|
@ -72,6 +68,7 @@ mod platform {
|
||||||
use std::mem;
|
use std::mem;
|
||||||
use std::os::windows::prelude::*;
|
use std::os::windows::prelude::*;
|
||||||
use std::path::Path;
|
use std::path::Path;
|
||||||
|
use uucore::crash;
|
||||||
use uucore::wide::{FromWide, ToWide};
|
use uucore::wide::{FromWide, ToWide};
|
||||||
|
|
||||||
unsafe fn flush_volume(name: &str) {
|
unsafe fn flush_volume(name: &str) {
|
||||||
|
@ -164,7 +161,8 @@ fn usage() -> String {
|
||||||
format!("{0} [OPTION]... FILE...", uucore::execution_phrase())
|
format!("{0} [OPTION]... FILE...", uucore::execution_phrase())
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn uumain(args: impl uucore::Args) -> i32 {
|
#[uucore_procs::gen_uumain]
|
||||||
|
pub fn uumain(args: impl uucore::Args) -> UResult<()> {
|
||||||
let usage = usage();
|
let usage = usage();
|
||||||
|
|
||||||
let matches = uu_app().usage(&usage[..]).get_matches_from(args);
|
let matches = uu_app().usage(&usage[..]).get_matches_from(args);
|
||||||
|
@ -176,11 +174,10 @@ pub fn uumain(args: impl uucore::Args) -> i32 {
|
||||||
|
|
||||||
for f in &files {
|
for f in &files {
|
||||||
if !Path::new(&f).exists() {
|
if !Path::new(&f).exists() {
|
||||||
crash!(
|
return Err(USimpleError::new(
|
||||||
EXIT_ERR,
|
1,
|
||||||
"cannot stat {}: No such file or directory",
|
format!("cannot stat {}: No such file or directory", f.quote()),
|
||||||
f.quote()
|
));
|
||||||
);
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -194,7 +191,7 @@ pub fn uumain(args: impl uucore::Args) -> i32 {
|
||||||
} else {
|
} else {
|
||||||
sync();
|
sync();
|
||||||
}
|
}
|
||||||
0
|
Ok(())
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn uu_app() -> App<'static, 'static> {
|
pub fn uu_app() -> App<'static, 'static> {
|
||||||
|
|
|
@ -14,6 +14,7 @@ use std::fs::OpenOptions;
|
||||||
use std::io::{copy, sink, stdin, stdout, Error, ErrorKind, Read, Result, Write};
|
use std::io::{copy, sink, stdin, stdout, Error, ErrorKind, Read, Result, Write};
|
||||||
use std::path::PathBuf;
|
use std::path::PathBuf;
|
||||||
use uucore::display::Quotable;
|
use uucore::display::Quotable;
|
||||||
|
use uucore::error::UResult;
|
||||||
|
|
||||||
#[cfg(unix)]
|
#[cfg(unix)]
|
||||||
use uucore::libc;
|
use uucore::libc;
|
||||||
|
@ -37,7 +38,8 @@ fn usage() -> String {
|
||||||
format!("{0} [OPTION]... [FILE]...", uucore::execution_phrase())
|
format!("{0} [OPTION]... [FILE]...", uucore::execution_phrase())
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn uumain(args: impl uucore::Args) -> i32 {
|
#[uucore_procs::gen_uumain]
|
||||||
|
pub fn uumain(args: impl uucore::Args) -> UResult<()> {
|
||||||
let usage = usage();
|
let usage = usage();
|
||||||
|
|
||||||
let matches = uu_app().usage(&usage[..]).get_matches_from(args);
|
let matches = uu_app().usage(&usage[..]).get_matches_from(args);
|
||||||
|
@ -52,8 +54,8 @@ pub fn uumain(args: impl uucore::Args) -> i32 {
|
||||||
};
|
};
|
||||||
|
|
||||||
match tee(options) {
|
match tee(options) {
|
||||||
Ok(_) => 0,
|
Ok(_) => Ok(()),
|
||||||
Err(_) => 1,
|
Err(_) => Err(1.into()),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -13,7 +13,8 @@ mod parser;
|
||||||
use clap::{crate_version, App, AppSettings};
|
use clap::{crate_version, App, AppSettings};
|
||||||
use parser::{parse, Operator, Symbol, UnaryOperator};
|
use parser::{parse, Operator, Symbol, UnaryOperator};
|
||||||
use std::ffi::{OsStr, OsString};
|
use std::ffi::{OsStr, OsString};
|
||||||
use uucore::{display::Quotable, show_error};
|
use uucore::display::Quotable;
|
||||||
|
use uucore::error::{UResult, USimpleError};
|
||||||
|
|
||||||
const USAGE: &str = "test EXPRESSION
|
const USAGE: &str = "test EXPRESSION
|
||||||
or: test
|
or: test
|
||||||
|
@ -91,7 +92,8 @@ pub fn uu_app() -> App<'static, 'static> {
|
||||||
.setting(AppSettings::DisableVersion)
|
.setting(AppSettings::DisableVersion)
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn uumain(mut args: impl uucore::Args) -> i32 {
|
#[uucore_procs::gen_uumain]
|
||||||
|
pub fn uumain(mut args: impl uucore::Args) -> UResult<()> {
|
||||||
let program = args.next().unwrap_or_else(|| OsString::from("test"));
|
let program = args.next().unwrap_or_else(|| OsString::from("test"));
|
||||||
let binary_name = uucore::util_name();
|
let binary_name = uucore::util_name();
|
||||||
let mut args: Vec<_> = args.collect();
|
let mut args: Vec<_> = args.collect();
|
||||||
|
@ -109,13 +111,12 @@ pub fn uumain(mut args: impl uucore::Args) -> i32 {
|
||||||
.setting(AppSettings::NeedsLongHelp)
|
.setting(AppSettings::NeedsLongHelp)
|
||||||
.setting(AppSettings::NeedsLongVersion)
|
.setting(AppSettings::NeedsLongVersion)
|
||||||
.get_matches_from(std::iter::once(program).chain(args.into_iter()));
|
.get_matches_from(std::iter::once(program).chain(args.into_iter()));
|
||||||
return 0;
|
return Ok(());
|
||||||
}
|
}
|
||||||
// If invoked via name '[', matching ']' must be in the last arg
|
// If invoked via name '[', matching ']' must be in the last arg
|
||||||
let last = args.pop();
|
let last = args.pop();
|
||||||
if last.as_deref() != Some(OsStr::new("]")) {
|
if last.as_deref() != Some(OsStr::new("]")) {
|
||||||
show_error!("missing ']'");
|
return Err(USimpleError::new(2, "missing ']'"));
|
||||||
return 2;
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -124,15 +125,12 @@ pub fn uumain(mut args: impl uucore::Args) -> i32 {
|
||||||
match result {
|
match result {
|
||||||
Ok(result) => {
|
Ok(result) => {
|
||||||
if result {
|
if result {
|
||||||
0
|
Ok(())
|
||||||
} else {
|
} else {
|
||||||
1
|
Err(1.into())
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
Err(e) => {
|
Err(e) => Err(USimpleError::new(2, e)),
|
||||||
show_error!("{}", e);
|
|
||||||
2
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -12,6 +12,7 @@
|
||||||
use clap::{crate_version, App, Arg};
|
use clap::{crate_version, App, Arg};
|
||||||
use std::ffi::CStr;
|
use std::ffi::CStr;
|
||||||
use std::io::Write;
|
use std::io::Write;
|
||||||
|
use uucore::error::{UResult, UUsageError};
|
||||||
use uucore::InvalidEncodingHandling;
|
use uucore::InvalidEncodingHandling;
|
||||||
|
|
||||||
static ABOUT: &str = "Print the file name of the terminal connected to standard input.";
|
static ABOUT: &str = "Print the file name of the terminal connected to standard input.";
|
||||||
|
@ -24,21 +25,17 @@ fn usage() -> String {
|
||||||
format!("{0} [OPTION]...", uucore::execution_phrase())
|
format!("{0} [OPTION]...", uucore::execution_phrase())
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn uumain(args: impl uucore::Args) -> i32 {
|
#[uucore_procs::gen_uumain]
|
||||||
|
pub fn uumain(args: impl uucore::Args) -> UResult<()> {
|
||||||
let usage = usage();
|
let usage = usage();
|
||||||
let args = args
|
let args = args
|
||||||
.collect_str(InvalidEncodingHandling::ConvertLossy)
|
.collect_str(InvalidEncodingHandling::ConvertLossy)
|
||||||
.accept_any();
|
.accept_any();
|
||||||
|
|
||||||
let matches = uu_app().usage(&usage[..]).get_matches_from_safe(args);
|
let matches = uu_app()
|
||||||
|
.usage(&usage[..])
|
||||||
let matches = match matches {
|
.get_matches_from_safe(args)
|
||||||
Ok(m) => m,
|
.map_err(|e| UUsageError::new(2, format!("{}", e)))?;
|
||||||
Err(e) => {
|
|
||||||
eprint!("{}", e);
|
|
||||||
return 2;
|
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
||||||
let silent = matches.is_present(options::SILENT);
|
let silent = matches.is_present(options::SILENT);
|
||||||
|
|
||||||
|
@ -68,9 +65,9 @@ pub fn uumain(args: impl uucore::Args) -> i32 {
|
||||||
}
|
}
|
||||||
|
|
||||||
if atty::is(atty::Stream::Stdin) {
|
if atty::is(atty::Stream::Stdin) {
|
||||||
libc::EXIT_SUCCESS
|
Ok(())
|
||||||
} else {
|
} else {
|
||||||
libc::EXIT_FAILURE
|
Err(libc::EXIT_FAILURE.into())
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -17,6 +17,7 @@ use std::io::{stdin, stdout, BufRead, BufReader, BufWriter, Read, Stdout, Write}
|
||||||
use std::str::from_utf8;
|
use std::str::from_utf8;
|
||||||
use unicode_width::UnicodeWidthChar;
|
use unicode_width::UnicodeWidthChar;
|
||||||
use uucore::display::Quotable;
|
use uucore::display::Quotable;
|
||||||
|
use uucore::error::{FromIo, UResult};
|
||||||
use uucore::InvalidEncodingHandling;
|
use uucore::InvalidEncodingHandling;
|
||||||
|
|
||||||
static NAME: &str = "unexpand";
|
static NAME: &str = "unexpand";
|
||||||
|
@ -90,16 +91,15 @@ impl Options {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn uumain(args: impl uucore::Args) -> i32 {
|
#[uucore_procs::gen_uumain]
|
||||||
|
pub fn uumain(args: impl uucore::Args) -> UResult<()> {
|
||||||
let args = args
|
let args = args
|
||||||
.collect_str(InvalidEncodingHandling::Ignore)
|
.collect_str(InvalidEncodingHandling::Ignore)
|
||||||
.accept_any();
|
.accept_any();
|
||||||
|
|
||||||
let matches = uu_app().get_matches_from(args);
|
let matches = uu_app().get_matches_from(args);
|
||||||
|
|
||||||
unexpand(Options::new(matches));
|
unexpand(Options::new(matches)).map_err_context(String::new)
|
||||||
|
|
||||||
0
|
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn uu_app() -> App<'static, 'static> {
|
pub fn uu_app() -> App<'static, 'static> {
|
||||||
|
@ -242,7 +242,7 @@ fn next_char_info(uflag: bool, buf: &[u8], byte: usize) -> (CharType, usize, usi
|
||||||
(ctype, cwidth, nbytes)
|
(ctype, cwidth, nbytes)
|
||||||
}
|
}
|
||||||
|
|
||||||
fn unexpand(options: Options) {
|
fn unexpand(options: Options) -> std::io::Result<()> {
|
||||||
let mut output = BufWriter::new(stdout());
|
let mut output = BufWriter::new(stdout());
|
||||||
let ts = &options.tabstops[..];
|
let ts = &options.tabstops[..];
|
||||||
let mut buf = Vec::new();
|
let mut buf = Vec::new();
|
||||||
|
@ -273,7 +273,7 @@ fn unexpand(options: Options) {
|
||||||
init,
|
init,
|
||||||
true,
|
true,
|
||||||
);
|
);
|
||||||
crash_if_err!(1, output.write_all(&buf[byte..]));
|
output.write_all(&buf[byte..])?;
|
||||||
scol = col;
|
scol = col;
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
@ -293,7 +293,7 @@ fn unexpand(options: Options) {
|
||||||
};
|
};
|
||||||
|
|
||||||
if !tabs_buffered {
|
if !tabs_buffered {
|
||||||
crash_if_err!(1, output.write_all(&buf[byte..byte + nbytes]));
|
output.write_all(&buf[byte..byte + nbytes])?;
|
||||||
scol = col; // now printed up to this column
|
scol = col; // now printed up to this column
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -318,7 +318,7 @@ fn unexpand(options: Options) {
|
||||||
} else {
|
} else {
|
||||||
0
|
0
|
||||||
};
|
};
|
||||||
crash_if_err!(1, output.write_all(&buf[byte..byte + nbytes]));
|
output.write_all(&buf[byte..byte + nbytes])?;
|
||||||
scol = col; // we've now printed up to this column
|
scol = col; // we've now printed up to this column
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -337,9 +337,9 @@ fn unexpand(options: Options) {
|
||||||
init,
|
init,
|
||||||
true,
|
true,
|
||||||
);
|
);
|
||||||
crash_if_err!(1, output.flush());
|
output.flush()?;
|
||||||
buf.truncate(0); // clear out the buffer
|
buf.truncate(0); // clear out the buffer
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
crash_if_err!(1, output.flush())
|
output.flush()
|
||||||
}
|
}
|
||||||
|
|
|
@ -19,7 +19,6 @@ path="src/lib/lib.rs"
|
||||||
clap = "2.33.3"
|
clap = "2.33.3"
|
||||||
dns-lookup = { version="1.0.5", optional=true }
|
dns-lookup = { version="1.0.5", optional=true }
|
||||||
dunce = "1.0.0"
|
dunce = "1.0.0"
|
||||||
getopts = "<= 0.2.21"
|
|
||||||
wild = "2.0"
|
wild = "2.0"
|
||||||
# * optional
|
# * optional
|
||||||
thiserror = { version="1.0", optional=true }
|
thiserror = { version="1.0", optional=true }
|
||||||
|
|
|
@ -18,7 +18,6 @@ mod parser; // string parsing modules
|
||||||
|
|
||||||
// * cross-platform modules
|
// * cross-platform modules
|
||||||
pub use crate::mods::backup_control;
|
pub use crate::mods::backup_control;
|
||||||
pub use crate::mods::coreopts;
|
|
||||||
pub use crate::mods::display;
|
pub use crate::mods::display;
|
||||||
pub use crate::mods::error;
|
pub use crate::mods::error;
|
||||||
pub use crate::mods::os;
|
pub use crate::mods::os;
|
||||||
|
|
|
@ -26,9 +26,7 @@
|
||||||
//! - From custom messages: [`show_error!`], [`show_usage_error!`]
|
//! - From custom messages: [`show_error!`], [`show_usage_error!`]
|
||||||
//! - Print warnings: [`show_warning!`]
|
//! - Print warnings: [`show_warning!`]
|
||||||
//! - Terminate util execution
|
//! - Terminate util execution
|
||||||
//! - Terminate regularly: [`exit!`], [`return_if_err!`]
|
//! - Crash program: [`crash!`], [`crash_if_err!`]
|
||||||
//! - Crash program: [`crash!`], [`crash_if_err!`], [`safe_unwrap!`]
|
|
||||||
//! - Unwrapping result types: [`safe_unwrap!`]
|
|
||||||
|
|
||||||
// spell-checker:ignore sourcepath targetpath
|
// spell-checker:ignore sourcepath targetpath
|
||||||
|
|
||||||
|
@ -223,22 +221,10 @@ macro_rules! show_usage_error(
|
||||||
})
|
})
|
||||||
);
|
);
|
||||||
|
|
||||||
//====
|
|
||||||
|
|
||||||
/// Calls [`std::process::exit`] with the provided exit code.
|
|
||||||
///
|
|
||||||
/// Why not call exit directly?
|
|
||||||
#[macro_export]
|
|
||||||
macro_rules! exit(
|
|
||||||
($exit_code:expr) => ({
|
|
||||||
::std::process::exit($exit_code)
|
|
||||||
})
|
|
||||||
);
|
|
||||||
|
|
||||||
/// Display an error and [`exit!`]
|
/// Display an error and [`exit!`]
|
||||||
///
|
///
|
||||||
/// Displays the provided error message using [`show_error!`], then invokes
|
/// Displays the provided error message using [`show_error!`], then invokes
|
||||||
/// [`exit!`] with the provided exit code.
|
/// [`std::process::exit`] with the provided exit code.
|
||||||
///
|
///
|
||||||
/// # Examples
|
/// # Examples
|
||||||
///
|
///
|
||||||
|
@ -255,7 +241,7 @@ macro_rules! exit(
|
||||||
macro_rules! crash(
|
macro_rules! crash(
|
||||||
($exit_code:expr, $($args:tt)+) => ({
|
($exit_code:expr, $($args:tt)+) => ({
|
||||||
$crate::show_error!($($args)+);
|
$crate::show_error!($($args)+);
|
||||||
$crate::exit!($exit_code)
|
std::process::exit($exit_code);
|
||||||
})
|
})
|
||||||
);
|
);
|
||||||
|
|
||||||
|
@ -288,150 +274,3 @@ macro_rules! crash_if_err(
|
||||||
}
|
}
|
||||||
)
|
)
|
||||||
);
|
);
|
||||||
|
|
||||||
/// Unwrap some Result, crashing instead of panicking.
|
|
||||||
///
|
|
||||||
/// Drop this in favor of `crash_if_err!`
|
|
||||||
#[macro_export]
|
|
||||||
macro_rules! safe_unwrap(
|
|
||||||
($exp:expr) => (
|
|
||||||
match $exp {
|
|
||||||
Ok(m) => m,
|
|
||||||
Err(f) => $crate::crash!(1, "{}", f.to_string())
|
|
||||||
}
|
|
||||||
)
|
|
||||||
);
|
|
||||||
|
|
||||||
//====
|
|
||||||
|
|
||||||
/// Unwraps the Result. Instead of panicking, it shows the error and then
|
|
||||||
/// returns from the function with the provided exit code.
|
|
||||||
/// Assumes the current function returns an i32 value.
|
|
||||||
///
|
|
||||||
/// Replace with `crash_if_err`?
|
|
||||||
#[macro_export]
|
|
||||||
macro_rules! return_if_err(
|
|
||||||
($exit_code:expr, $exp:expr) => (
|
|
||||||
match $exp {
|
|
||||||
Ok(m) => m,
|
|
||||||
Err(f) => {
|
|
||||||
$crate::show_error!("{}", f);
|
|
||||||
return $exit_code;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
)
|
|
||||||
);
|
|
||||||
|
|
||||||
//====
|
|
||||||
|
|
||||||
/// This is used exclusively by du...
|
|
||||||
#[macro_export]
|
|
||||||
macro_rules! safe_writeln(
|
|
||||||
($fd:expr, $($args:tt)+) => (
|
|
||||||
match writeln!($fd, $($args)+) {
|
|
||||||
Ok(_) => {}
|
|
||||||
Err(f) => panic!("{}", f)
|
|
||||||
}
|
|
||||||
)
|
|
||||||
);
|
|
||||||
|
|
||||||
//-- message templates
|
|
||||||
|
|
||||||
//-- message templates : (join utility sub-macros)
|
|
||||||
|
|
||||||
// used only by "cut"
|
|
||||||
#[macro_export]
|
|
||||||
macro_rules! snippet_list_join_oxford_comma {
|
|
||||||
($conjunction:expr, $valOne:expr, $valTwo:expr) => (
|
|
||||||
format!("{}, {} {}", $valOne, $conjunction, $valTwo)
|
|
||||||
);
|
|
||||||
($conjunction:expr, $valOne:expr, $valTwo:expr $(, $remaining_values:expr)*) => (
|
|
||||||
format!("{}, {}", $valOne, $crate::snippet_list_join_oxford_comma!($conjunction, $valTwo $(, $remaining_values)*))
|
|
||||||
);
|
|
||||||
}
|
|
||||||
|
|
||||||
// used only by "cut"
|
|
||||||
#[macro_export]
|
|
||||||
macro_rules! snippet_list_join {
|
|
||||||
($conjunction:expr, $valOne:expr, $valTwo:expr) => (
|
|
||||||
format!("{} {} {}", $valOne, $conjunction, $valTwo)
|
|
||||||
);
|
|
||||||
($conjunction:expr, $valOne:expr, $valTwo:expr $(, $remaining_values:expr)*) => (
|
|
||||||
format!("{}, {}", $valOne, $crate::snippet_list_join_oxford_comma!($conjunction, $valTwo $(, $remaining_values)*))
|
|
||||||
);
|
|
||||||
}
|
|
||||||
|
|
||||||
//-- message templates : invalid input
|
|
||||||
|
|
||||||
#[macro_export]
|
|
||||||
macro_rules! msg_invalid_input {
|
|
||||||
($reason: expr) => {
|
|
||||||
format!("invalid input: {}", $reason)
|
|
||||||
};
|
|
||||||
}
|
|
||||||
|
|
||||||
// -- message templates : invalid input : flag
|
|
||||||
|
|
||||||
#[macro_export]
|
|
||||||
macro_rules! msg_invalid_opt_use {
|
|
||||||
($about:expr, $flag:expr) => {
|
|
||||||
$crate::msg_invalid_input!(format!("The '{}' option {}", $flag, $about))
|
|
||||||
};
|
|
||||||
($about:expr, $long_flag:expr, $short_flag:expr) => {
|
|
||||||
$crate::msg_invalid_input!(format!(
|
|
||||||
"The '{}' ('{}') option {}",
|
|
||||||
$long_flag, $short_flag, $about
|
|
||||||
))
|
|
||||||
};
|
|
||||||
}
|
|
||||||
|
|
||||||
// Only used by "cut"
|
|
||||||
#[macro_export]
|
|
||||||
macro_rules! msg_opt_only_usable_if {
|
|
||||||
($clause:expr, $flag:expr) => {
|
|
||||||
$crate::msg_invalid_opt_use!(format!("only usable if {}", $clause), $flag)
|
|
||||||
};
|
|
||||||
($clause:expr, $long_flag:expr, $short_flag:expr) => {
|
|
||||||
$crate::msg_invalid_opt_use!(
|
|
||||||
format!("only usable if {}", $clause),
|
|
||||||
$long_flag,
|
|
||||||
$short_flag
|
|
||||||
)
|
|
||||||
};
|
|
||||||
}
|
|
||||||
|
|
||||||
// Used only by "cut"
|
|
||||||
#[macro_export]
|
|
||||||
macro_rules! msg_opt_invalid_should_be {
|
|
||||||
($expects:expr, $received:expr, $flag:expr) => {
|
|
||||||
$crate::msg_invalid_opt_use!(
|
|
||||||
format!("expects {}, but was provided {}", $expects, $received),
|
|
||||||
$flag
|
|
||||||
)
|
|
||||||
};
|
|
||||||
($expects:expr, $received:expr, $long_flag:expr, $short_flag:expr) => {
|
|
||||||
$crate::msg_invalid_opt_use!(
|
|
||||||
format!("expects {}, but was provided {}", $expects, $received),
|
|
||||||
$long_flag,
|
|
||||||
$short_flag
|
|
||||||
)
|
|
||||||
};
|
|
||||||
}
|
|
||||||
|
|
||||||
// -- message templates : invalid input : input combinations
|
|
||||||
|
|
||||||
// UNUSED!
|
|
||||||
#[macro_export]
|
|
||||||
macro_rules! msg_expects_one_of {
|
|
||||||
($valOne:expr $(, $remaining_values:expr)*) => (
|
|
||||||
$crate::msg_invalid_input!(format!("expects one of {}", $crate::snippet_list_join!("or", $valOne $(, $remaining_values)*)))
|
|
||||||
);
|
|
||||||
}
|
|
||||||
|
|
||||||
// Used only by "cut"
|
|
||||||
#[macro_export]
|
|
||||||
macro_rules! msg_expects_no_more_than_one_of {
|
|
||||||
($valOne:expr $(, $remaining_values:expr)*) => (
|
|
||||||
$crate::msg_invalid_input!(format!("expects no more than one of {}", $crate::snippet_list_join!("or", $valOne $(, $remaining_values)*))) ;
|
|
||||||
);
|
|
||||||
}
|
|
||||||
|
|
|
@ -1,7 +1,6 @@
|
||||||
// mods ~ cross-platforms modules (core/bundler file)
|
// mods ~ cross-platforms modules (core/bundler file)
|
||||||
|
|
||||||
pub mod backup_control;
|
pub mod backup_control;
|
||||||
pub mod coreopts;
|
|
||||||
pub mod display;
|
pub mod display;
|
||||||
pub mod error;
|
pub mod error;
|
||||||
pub mod os;
|
pub mod os;
|
||||||
|
|
|
@ -1,141 +0,0 @@
|
||||||
pub struct HelpText<'a> {
|
|
||||||
pub name: &'a str,
|
|
||||||
pub version: &'a str,
|
|
||||||
pub syntax: &'a str,
|
|
||||||
pub summary: &'a str,
|
|
||||||
pub long_help: &'a str,
|
|
||||||
pub display_usage: bool,
|
|
||||||
}
|
|
||||||
|
|
||||||
pub struct CoreOptions<'a> {
|
|
||||||
options: getopts::Options,
|
|
||||||
help_text: HelpText<'a>,
|
|
||||||
}
|
|
||||||
|
|
||||||
impl<'a> CoreOptions<'a> {
|
|
||||||
pub fn new(help_text: HelpText<'a>) -> Self {
|
|
||||||
let mut ret = CoreOptions {
|
|
||||||
options: getopts::Options::new(),
|
|
||||||
help_text,
|
|
||||||
};
|
|
||||||
ret.options
|
|
||||||
.optflag("", "help", "print usage information")
|
|
||||||
.optflag("", "version", "print name and version number");
|
|
||||||
ret
|
|
||||||
}
|
|
||||||
pub fn optflagopt(
|
|
||||||
&mut self,
|
|
||||||
short_name: &str,
|
|
||||||
long_name: &str,
|
|
||||||
desc: &str,
|
|
||||||
hint: &str,
|
|
||||||
) -> &mut CoreOptions<'a> {
|
|
||||||
self.options.optflagopt(short_name, long_name, desc, hint);
|
|
||||||
self
|
|
||||||
}
|
|
||||||
pub fn optflag(
|
|
||||||
&mut self,
|
|
||||||
short_name: &str,
|
|
||||||
long_name: &str,
|
|
||||||
desc: &str,
|
|
||||||
) -> &mut CoreOptions<'a> {
|
|
||||||
self.options.optflag(short_name, long_name, desc);
|
|
||||||
self
|
|
||||||
}
|
|
||||||
pub fn optflagmulti(
|
|
||||||
&mut self,
|
|
||||||
short_name: &str,
|
|
||||||
long_name: &str,
|
|
||||||
desc: &str,
|
|
||||||
) -> &mut CoreOptions<'a> {
|
|
||||||
self.options.optflagmulti(short_name, long_name, desc);
|
|
||||||
self
|
|
||||||
}
|
|
||||||
pub fn optopt(
|
|
||||||
&mut self,
|
|
||||||
short_name: &str,
|
|
||||||
long_name: &str,
|
|
||||||
desc: &str,
|
|
||||||
hint: &str,
|
|
||||||
) -> &mut CoreOptions<'a> {
|
|
||||||
self.options.optopt(short_name, long_name, desc, hint);
|
|
||||||
self
|
|
||||||
}
|
|
||||||
pub fn optmulti(
|
|
||||||
&mut self,
|
|
||||||
short_name: &str,
|
|
||||||
long_name: &str,
|
|
||||||
desc: &str,
|
|
||||||
hint: &str,
|
|
||||||
) -> &mut CoreOptions<'a> {
|
|
||||||
self.options.optmulti(short_name, long_name, desc, hint);
|
|
||||||
self
|
|
||||||
}
|
|
||||||
pub fn usage(&self, summary: &str) -> String {
|
|
||||||
self.options.usage(summary)
|
|
||||||
}
|
|
||||||
pub fn parse(&mut self, args: Vec<String>) -> getopts::Matches {
|
|
||||||
let matches = match self.options.parse(&args[1..]) {
|
|
||||||
Ok(m) => Some(m),
|
|
||||||
Err(f) => {
|
|
||||||
eprint!("{}: error: ", self.help_text.name);
|
|
||||||
eprintln!("{}", f);
|
|
||||||
::std::process::exit(1);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
.unwrap();
|
|
||||||
if matches.opt_present("help") {
|
|
||||||
let usage_str = if self.help_text.display_usage {
|
|
||||||
format!(
|
|
||||||
"\n {}\n\n Reference\n",
|
|
||||||
self.options.usage(self.help_text.summary)
|
|
||||||
)
|
|
||||||
.replace("Options:", " Options:")
|
|
||||||
} else {
|
|
||||||
String::new()
|
|
||||||
};
|
|
||||||
print!(
|
|
||||||
"
|
|
||||||
{0} {1}
|
|
||||||
|
|
||||||
{0} {2}
|
|
||||||
{3}{4}
|
|
||||||
",
|
|
||||||
self.help_text.name,
|
|
||||||
self.help_text.version,
|
|
||||||
self.help_text.syntax,
|
|
||||||
usage_str,
|
|
||||||
self.help_text.long_help
|
|
||||||
);
|
|
||||||
crate::exit!(0);
|
|
||||||
} else if matches.opt_present("version") {
|
|
||||||
println!("{} {}", self.help_text.name, self.help_text.version);
|
|
||||||
crate::exit!(0);
|
|
||||||
}
|
|
||||||
matches
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
#[macro_export]
|
|
||||||
macro_rules! app {
|
|
||||||
($syntax: expr, $summary: expr, $long_help: expr) => {
|
|
||||||
uucore::coreopts::CoreOptions::new(uucore::coreopts::HelpText {
|
|
||||||
name: uucore::util_name(),
|
|
||||||
version: env!("CARGO_PKG_VERSION"),
|
|
||||||
syntax: $syntax,
|
|
||||||
summary: $summary,
|
|
||||||
long_help: $long_help,
|
|
||||||
display_usage: true,
|
|
||||||
})
|
|
||||||
};
|
|
||||||
($syntax: expr, $summary: expr, $long_help: expr, $display_usage: expr) => {
|
|
||||||
uucore::coreopts::CoreOptions::new(uucore::coreopts::HelpText {
|
|
||||||
name: uucore::util_name(),
|
|
||||||
version: env!("CARGO_PKG_VERSION"),
|
|
||||||
syntax: $syntax,
|
|
||||||
summary: $summary,
|
|
||||||
long_help: $long_help,
|
|
||||||
display_usage: $display_usage,
|
|
||||||
})
|
|
||||||
};
|
|
||||||
}
|
|
|
@ -505,3 +505,66 @@ fn test_round() {
|
||||||
.stdout_only(exp.join("\n") + "\n");
|
.stdout_only(exp.join("\n") + "\n");
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn test_suffix_is_added_if_not_supplied() {
|
||||||
|
new_ucmd!()
|
||||||
|
.args(&["--suffix=TEST"])
|
||||||
|
.pipe_in("1000")
|
||||||
|
.succeeds()
|
||||||
|
.stdout_only("1000TEST\n");
|
||||||
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn test_suffix_is_preserved() {
|
||||||
|
new_ucmd!()
|
||||||
|
.args(&["--suffix=TEST"])
|
||||||
|
.pipe_in("1000TEST")
|
||||||
|
.succeeds()
|
||||||
|
.stdout_only("1000TEST\n");
|
||||||
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn test_suffix_is_only_applied_to_selected_field() {
|
||||||
|
new_ucmd!()
|
||||||
|
.args(&["--suffix=TEST", "--field=2"])
|
||||||
|
.pipe_in("1000 2000 3000")
|
||||||
|
.succeeds()
|
||||||
|
.stdout_only("1000 2000TEST 3000\n");
|
||||||
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn test_transform_with_suffix_on_input() {
|
||||||
|
new_ucmd!()
|
||||||
|
.args(&["--suffix=b", "--to=si"])
|
||||||
|
.pipe_in("2000b")
|
||||||
|
.succeeds()
|
||||||
|
.stdout_only("2.0Kb\n");
|
||||||
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn test_transform_without_suffix_on_input() {
|
||||||
|
new_ucmd!()
|
||||||
|
.args(&["--suffix=b", "--to=si"])
|
||||||
|
.pipe_in("2000")
|
||||||
|
.succeeds()
|
||||||
|
.stdout_only("2.0Kb\n");
|
||||||
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn test_transform_with_suffix_and_delimiter() {
|
||||||
|
new_ucmd!()
|
||||||
|
.args(&["--suffix=b", "--to=si", "-d=|"])
|
||||||
|
.pipe_in("1000b|2000|3000")
|
||||||
|
.succeeds()
|
||||||
|
.stdout_only("1.0Kb|2000|3000\n");
|
||||||
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn test_suffix_with_padding() {
|
||||||
|
new_ucmd!()
|
||||||
|
.args(&["--suffix=pad", "--padding=12"])
|
||||||
|
.pipe_in("1000 2000 3000")
|
||||||
|
.succeeds()
|
||||||
|
.stdout_only(" 1000pad 2000 3000\n");
|
||||||
|
}
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue