mirror of
https://github.com/uutils/coreutils
synced 2024-11-15 09:27:21 +00:00
refactor/uucore ~ correct implementation of executable!() for multicall
- Use an atomic bool to track whether the utility name is the second or the first argument. - Add tests
This commit is contained in:
parent
38f3d13f7f
commit
44981cab01
6 changed files with 117 additions and 43 deletions
|
@ -70,6 +70,7 @@ fn main() {
|
|||
Some(OsString::from(*util))
|
||||
} else {
|
||||
// unmatched binary name => regard as multi-binary container and advance argument list
|
||||
uucore::set_utility_is_second_arg();
|
||||
args.next()
|
||||
};
|
||||
|
||||
|
|
|
@ -38,7 +38,7 @@ pub fn uumain(args: impl uucore::Args) -> i32 {
|
|||
let name = util_name!();
|
||||
|
||||
let config_result: Result<base_common::Config, String> =
|
||||
base_common::parse_base_cmd_args(args, name, VERSION, ABOUT, &usage);
|
||||
base_common::parse_base_cmd_args(args, &name, VERSION, ABOUT, &usage);
|
||||
let config = config_result.unwrap_or_else(|s| crash!(BASE_CMD_PARSE_ERROR, "{}", s));
|
||||
|
||||
// Create a reference to stdin so we can return a locked stdin from
|
||||
|
@ -52,12 +52,12 @@ pub fn uumain(args: impl uucore::Args) -> i32 {
|
|||
config.wrap_cols,
|
||||
config.ignore_garbage,
|
||||
config.decode,
|
||||
name,
|
||||
&name,
|
||||
);
|
||||
|
||||
0
|
||||
}
|
||||
|
||||
pub fn uu_app() -> App<'static, 'static> {
|
||||
base_common::base_app(util_name!(), VERSION, ABOUT)
|
||||
base_common::base_app(&util_name!(), VERSION, ABOUT)
|
||||
}
|
||||
|
|
|
@ -38,7 +38,7 @@ pub fn uumain(args: impl uucore::Args) -> i32 {
|
|||
let usage = usage();
|
||||
let name = util_name!();
|
||||
let config_result: Result<base_common::Config, String> =
|
||||
base_common::parse_base_cmd_args(args, name, VERSION, ABOUT, &usage);
|
||||
base_common::parse_base_cmd_args(args, &name, VERSION, ABOUT, &usage);
|
||||
let config = config_result.unwrap_or_else(|s| crash!(BASE_CMD_PARSE_ERROR, "{}", s));
|
||||
|
||||
// Create a reference to stdin so we can return a locked stdin from
|
||||
|
@ -52,7 +52,7 @@ pub fn uumain(args: impl uucore::Args) -> i32 {
|
|||
config.wrap_cols,
|
||||
config.ignore_garbage,
|
||||
config.decode,
|
||||
name,
|
||||
&name,
|
||||
);
|
||||
|
||||
0
|
||||
|
|
|
@ -77,6 +77,15 @@ pub use crate::features::wide;
|
|||
//## core functions
|
||||
|
||||
use std::ffi::OsString;
|
||||
use std::sync::atomic::Ordering;
|
||||
|
||||
pub fn get_utility_is_second_arg() -> bool {
|
||||
crate::macros::UTILITY_IS_SECOND_ARG.load(Ordering::SeqCst)
|
||||
}
|
||||
|
||||
pub fn set_utility_is_second_arg() {
|
||||
crate::macros::UTILITY_IS_SECOND_ARG.store(true, Ordering::SeqCst)
|
||||
}
|
||||
|
||||
pub enum InvalidEncodingHandling {
|
||||
Ignore,
|
||||
|
|
|
@ -1,3 +1,5 @@
|
|||
use std::sync::atomic::AtomicBool;
|
||||
|
||||
// This file is part of the uutils coreutils package.
|
||||
//
|
||||
// (c) Alex Lyon <arcterus@mail.com>
|
||||
|
@ -5,40 +7,22 @@
|
|||
// For the full copyright and license information, please view the LICENSE
|
||||
// file that was distributed with this source code.
|
||||
|
||||
/// Whether we were called as a multicall binary ("coreutils <utility>")
|
||||
pub static UTILITY_IS_SECOND_ARG: AtomicBool = AtomicBool::new(false);
|
||||
|
||||
/// Get the executable path (as `OsString`).
|
||||
#[macro_export]
|
||||
macro_rules! executable_os(
|
||||
() => ({
|
||||
&uucore::args_os().next().unwrap()
|
||||
$crate::args_os().next().unwrap()
|
||||
})
|
||||
);
|
||||
|
||||
/// Get the executable path (as `String`; lossless).
|
||||
/// Get the executable path (as `String`).
|
||||
#[macro_export]
|
||||
macro_rules! executable(
|
||||
() => ({
|
||||
let exe = match $crate::executable_os!().to_str() {
|
||||
// * UTF-8
|
||||
Some(s) => s.to_string(),
|
||||
// * "lossless" debug format (if/when `executable_os!()` is not well-formed UTF-8)
|
||||
None => format!("{:?}", $crate::executable_os!())
|
||||
};
|
||||
&exe.to_owned()
|
||||
})
|
||||
);
|
||||
|
||||
/// Get the executable name.
|
||||
#[macro_export]
|
||||
macro_rules! executable_name(
|
||||
() => ({
|
||||
let stem = &std::path::Path::new($crate::executable_os!()).file_stem().unwrap().to_owned();
|
||||
let exe = match stem.to_str() {
|
||||
// * UTF-8
|
||||
Some(s) => s.to_string(),
|
||||
// * "lossless" debug format (if/when `executable_os!()` is not well-formed UTF-8)
|
||||
None => format!("{:?}", stem)
|
||||
};
|
||||
&exe.to_owned()
|
||||
$crate::executable_os!().to_string_lossy().to_string()
|
||||
})
|
||||
);
|
||||
|
||||
|
@ -46,13 +30,11 @@ macro_rules! executable_name(
|
|||
#[macro_export]
|
||||
macro_rules! util_name(
|
||||
() => ({
|
||||
let crate_name = env!("CARGO_PKG_NAME");
|
||||
let name = if crate_name.starts_with("uu_") {
|
||||
&crate_name[3..]
|
||||
if $crate::get_utility_is_second_arg() {
|
||||
$crate::args_os().nth(1).unwrap().to_string_lossy().to_string()
|
||||
} else {
|
||||
crate_name
|
||||
};
|
||||
&name.to_owned()
|
||||
$crate::executable!()
|
||||
}
|
||||
})
|
||||
);
|
||||
|
||||
|
@ -62,14 +44,15 @@ macro_rules! util_name(
|
|||
#[macro_export]
|
||||
macro_rules! execution_phrase(
|
||||
() => ({
|
||||
let exe = if (executable_name!() == util_name!()) {
|
||||
executable!().to_string()
|
||||
} else {
|
||||
format!("{} {}", executable!(), util_name!())
|
||||
.as_str()
|
||||
.to_owned()
|
||||
};
|
||||
&exe.to_owned()
|
||||
if $crate::get_utility_is_second_arg() {
|
||||
$crate::args_os()
|
||||
.take(2)
|
||||
.map(|os_str| os_str.to_string_lossy().to_string())
|
||||
.collect::<Vec<_>>()
|
||||
.join(" ")
|
||||
} else {
|
||||
$crate::executable!()
|
||||
}
|
||||
})
|
||||
);
|
||||
|
||||
|
|
81
tests/test_util_name.rs
Normal file
81
tests/test_util_name.rs
Normal file
|
@ -0,0 +1,81 @@
|
|||
mod common;
|
||||
|
||||
use common::util::TestScenario;
|
||||
|
||||
#[test]
|
||||
#[cfg(feature = "ls")]
|
||||
fn execution_phrase_double() {
|
||||
use std::process::Command;
|
||||
|
||||
let scenario = TestScenario::new("ls");
|
||||
let output = Command::new(&scenario.bin_path)
|
||||
.arg("ls")
|
||||
.arg("--some-invalid-arg")
|
||||
.output()
|
||||
.unwrap();
|
||||
assert!(String::from_utf8(output.stderr)
|
||||
.unwrap()
|
||||
.contains(&format!("USAGE:\n {} ls", scenario.bin_path.display(),)));
|
||||
}
|
||||
|
||||
#[test]
|
||||
#[cfg(feature = "ls")]
|
||||
fn execution_phrase_single() {
|
||||
use std::process::Command;
|
||||
|
||||
let scenario = TestScenario::new("ls");
|
||||
std::fs::copy(scenario.bin_path, scenario.fixtures.plus("uu-ls")).unwrap();
|
||||
let output = Command::new(scenario.fixtures.plus("uu-ls"))
|
||||
.arg("--some-invalid-arg")
|
||||
.output()
|
||||
.unwrap();
|
||||
assert!(String::from_utf8(output.stderr).unwrap().contains(&format!(
|
||||
"USAGE:\n {}",
|
||||
scenario.fixtures.plus("uu-ls").display()
|
||||
)));
|
||||
}
|
||||
|
||||
#[test]
|
||||
#[cfg(feature = "sort")]
|
||||
fn util_name_double() {
|
||||
use std::{
|
||||
io::Write,
|
||||
process::{Command, Stdio},
|
||||
};
|
||||
|
||||
let scenario = TestScenario::new("sort");
|
||||
let mut child = Command::new(&scenario.bin_path)
|
||||
.arg("sort")
|
||||
.stdin(Stdio::piped())
|
||||
.stderr(Stdio::piped())
|
||||
.spawn()
|
||||
.unwrap();
|
||||
// input invalid utf8 to cause an error
|
||||
child.stdin.take().unwrap().write_all(&[255]).unwrap();
|
||||
let output = child.wait_with_output().unwrap();
|
||||
assert!(String::from_utf8(output.stderr).unwrap().contains("sort: "));
|
||||
}
|
||||
|
||||
#[test]
|
||||
#[cfg(feature = "sort")]
|
||||
fn util_name_single() {
|
||||
use std::{
|
||||
io::Write,
|
||||
process::{Command, Stdio},
|
||||
};
|
||||
|
||||
let scenario = TestScenario::new("sort");
|
||||
std::fs::copy(scenario.bin_path, scenario.fixtures.plus("uu-sort")).unwrap();
|
||||
let mut child = Command::new(scenario.fixtures.plus("uu-sort"))
|
||||
.stdin(Stdio::piped())
|
||||
.stderr(Stdio::piped())
|
||||
.spawn()
|
||||
.unwrap();
|
||||
// input invalid utf8 to cause an error
|
||||
child.stdin.take().unwrap().write_all(&[255]).unwrap();
|
||||
let output = child.wait_with_output().unwrap();
|
||||
assert!(String::from_utf8(output.stderr).unwrap().contains(&format!(
|
||||
"{}: ",
|
||||
scenario.fixtures.plus("uu-sort").display()
|
||||
)));
|
||||
}
|
Loading…
Reference in a new issue