mirror of
https://github.com/RGBCube/uutils-coreutils
synced 2025-07-29 20:17:45 +00:00
Merge branch 'main' into tail_notify
This commit is contained in:
commit
7dae3f7b9a
13 changed files with 126 additions and 45 deletions
2
.github/dependabot.yml
vendored
2
.github/dependabot.yml
vendored
|
@ -7,6 +7,6 @@ updates:
|
||||||
open-pull-requests-limit: 5
|
open-pull-requests-limit: 5
|
||||||
- package-ecosystem: "github-actions"
|
- package-ecosystem: "github-actions"
|
||||||
directory: "/"
|
directory: "/"
|
||||||
schedule:
|
schedule:
|
||||||
interval: daily
|
interval: daily
|
||||||
open-pull-requests-limit: 5
|
open-pull-requests-limit: 5
|
||||||
|
|
2
.vscode/extensions.json
vendored
2
.vscode/extensions.json
vendored
|
@ -6,7 +6,7 @@
|
||||||
// "streetsidesoftware.code-spell-checker" ~ `cspell` spell-checker support
|
// "streetsidesoftware.code-spell-checker" ~ `cspell` spell-checker support
|
||||||
{
|
{
|
||||||
"recommendations": [
|
"recommendations": [
|
||||||
"matklad.rust-analyzer",
|
"rust-lang.rust-analyzer",
|
||||||
"streetsidesoftware.code-spell-checker",
|
"streetsidesoftware.code-spell-checker",
|
||||||
"foxundermoon.shell-format"
|
"foxundermoon.shell-format"
|
||||||
]
|
]
|
||||||
|
|
3
Cargo.lock
generated
3
Cargo.lock
generated
|
@ -1207,6 +1207,7 @@ dependencies = [
|
||||||
"bitflags",
|
"bitflags",
|
||||||
"cfg-if 1.0.0",
|
"cfg-if 1.0.0",
|
||||||
"libc",
|
"libc",
|
||||||
|
"memoffset",
|
||||||
]
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
|
@ -2518,7 +2519,7 @@ name = "uu_kill"
|
||||||
version = "0.0.13"
|
version = "0.0.13"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"clap 3.1.18",
|
"clap 3.1.18",
|
||||||
"libc",
|
"nix",
|
||||||
"uucore",
|
"uucore",
|
||||||
]
|
]
|
||||||
|
|
||||||
|
|
|
@ -99,7 +99,7 @@ fn to_magnitude_and_suffix_not_powers_of_1024(n: u128) -> Result<String, ()> {
|
||||||
|
|
||||||
if rem % (SI_BASES[i] / 10) == 0 {
|
if rem % (SI_BASES[i] / 10) == 0 {
|
||||||
Ok(format!("{}.{}{}", quot, tenths_place, suffix))
|
Ok(format!("{}.{}{}", quot, tenths_place, suffix))
|
||||||
} else if tenths_place + 1 == 10 {
|
} else if tenths_place + 1 == 10 || quot >= 10 {
|
||||||
Ok(format!("{}{}", quot + 1, suffix))
|
Ok(format!("{}{}", quot + 1, suffix))
|
||||||
} else {
|
} else {
|
||||||
Ok(format!("{}.{}{}", quot, tenths_place + 1, suffix))
|
Ok(format!("{}.{}{}", quot, tenths_place + 1, suffix))
|
||||||
|
@ -245,6 +245,7 @@ mod tests {
|
||||||
assert_eq!(to_magnitude_and_suffix(1001).unwrap(), "1.1kB");
|
assert_eq!(to_magnitude_and_suffix(1001).unwrap(), "1.1kB");
|
||||||
assert_eq!(to_magnitude_and_suffix(1023).unwrap(), "1.1kB");
|
assert_eq!(to_magnitude_and_suffix(1023).unwrap(), "1.1kB");
|
||||||
assert_eq!(to_magnitude_and_suffix(1025).unwrap(), "1.1kB");
|
assert_eq!(to_magnitude_and_suffix(1025).unwrap(), "1.1kB");
|
||||||
|
assert_eq!(to_magnitude_and_suffix(10_001).unwrap(), "11kB");
|
||||||
assert_eq!(to_magnitude_and_suffix(999_000).unwrap(), "999kB");
|
assert_eq!(to_magnitude_and_suffix(999_000).unwrap(), "999kB");
|
||||||
|
|
||||||
assert_eq!(to_magnitude_and_suffix(999_001).unwrap(), "1MB");
|
assert_eq!(to_magnitude_and_suffix(999_001).unwrap(), "1MB");
|
||||||
|
|
|
@ -148,6 +148,7 @@ impl fmt::Display for OptionsError {
|
||||||
"option --output: field {} used more than once",
|
"option --output: field {} used more than once",
|
||||||
s.quote()
|
s.quote()
|
||||||
),
|
),
|
||||||
|
#[allow(clippy::print_in_format_impl)]
|
||||||
Self::FilesystemTypeBothSelectedAndExcluded(types) => {
|
Self::FilesystemTypeBothSelectedAndExcluded(types) => {
|
||||||
for t in types {
|
for t in types {
|
||||||
eprintln!(
|
eprintln!(
|
||||||
|
|
|
@ -16,7 +16,7 @@ path = "src/kill.rs"
|
||||||
|
|
||||||
[dependencies]
|
[dependencies]
|
||||||
clap = { version = "3.1", features = ["wrap_help", "cargo"] }
|
clap = { version = "3.1", features = ["wrap_help", "cargo"] }
|
||||||
libc = "0.2.126"
|
nix = { version = "0.24.1", features = ["signal"] }
|
||||||
uucore = { version=">=0.0.11", package="uucore", path="../../uucore", features=["signals"] }
|
uucore = { version=">=0.0.11", package="uucore", path="../../uucore", features=["signals"] }
|
||||||
|
|
||||||
[[bin]]
|
[[bin]]
|
||||||
|
|
|
@ -5,16 +5,17 @@
|
||||||
// * For the full copyright and license information, please view the LICENSE file
|
// * For the full copyright and license information, please view the LICENSE file
|
||||||
// * that was distributed with this source code.
|
// * that was distributed with this source code.
|
||||||
|
|
||||||
// spell-checker:ignore (ToDO) signalname pids
|
// spell-checker:ignore (ToDO) signalname pids killpg
|
||||||
|
|
||||||
#[macro_use]
|
#[macro_use]
|
||||||
extern crate uucore;
|
extern crate uucore;
|
||||||
|
|
||||||
use clap::{crate_version, Arg, Command};
|
use clap::{crate_version, Arg, Command};
|
||||||
use libc::{c_int, pid_t};
|
use nix::sys::signal::{self, Signal};
|
||||||
|
use nix::unistd::Pid;
|
||||||
use std::io::Error;
|
use std::io::Error;
|
||||||
use uucore::display::Quotable;
|
use uucore::display::Quotable;
|
||||||
use uucore::error::{UResult, USimpleError};
|
use uucore::error::{FromIo, UError, UResult, USimpleError};
|
||||||
use uucore::signals::{signal_by_name_or_value, ALL_SIGNALS};
|
use uucore::signals::{signal_by_name_or_value, ALL_SIGNALS};
|
||||||
use uucore::{format_usage, InvalidEncodingHandling};
|
use uucore::{format_usage, InvalidEncodingHandling};
|
||||||
|
|
||||||
|
@ -22,10 +23,9 @@ static ABOUT: &str = "Send signal to processes or list information about signals
|
||||||
const USAGE: &str = "{} [OPTIONS]... PID...";
|
const USAGE: &str = "{} [OPTIONS]... PID...";
|
||||||
|
|
||||||
pub mod options {
|
pub mod options {
|
||||||
pub static PIDS_OR_SIGNALS: &str = "pids_of_signals";
|
pub static PIDS_OR_SIGNALS: &str = "pids_or_signals";
|
||||||
pub static LIST: &str = "list";
|
pub static LIST: &str = "list";
|
||||||
pub static TABLE: &str = "table";
|
pub static TABLE: &str = "table";
|
||||||
pub static TABLE_OLD: &str = "table_old";
|
|
||||||
pub static SIGNAL: &str = "signal";
|
pub static SIGNAL: &str = "signal";
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -45,7 +45,7 @@ pub fn uumain(args: impl uucore::Args) -> UResult<()> {
|
||||||
|
|
||||||
let matches = uu_app().get_matches_from(args);
|
let matches = uu_app().get_matches_from(args);
|
||||||
|
|
||||||
let mode = if matches.is_present(options::TABLE) || matches.is_present(options::TABLE_OLD) {
|
let mode = if matches.is_present(options::TABLE) {
|
||||||
Mode::Table
|
Mode::Table
|
||||||
} else if matches.is_present(options::LIST) {
|
} else if matches.is_present(options::LIST) {
|
||||||
Mode::List
|
Mode::List
|
||||||
|
@ -67,8 +67,12 @@ pub fn uumain(args: impl uucore::Args) -> UResult<()> {
|
||||||
} else {
|
} else {
|
||||||
15_usize //SIGTERM
|
15_usize //SIGTERM
|
||||||
};
|
};
|
||||||
|
let sig: Signal = (sig as i32)
|
||||||
|
.try_into()
|
||||||
|
.map_err(|e| std::io::Error::from_raw_os_error(e as i32))?;
|
||||||
let pids = parse_pids(&pids_or_signals)?;
|
let pids = parse_pids(&pids_or_signals)?;
|
||||||
kill(sig, &pids)
|
kill(sig, &pids);
|
||||||
|
Ok(())
|
||||||
}
|
}
|
||||||
Mode::Table => {
|
Mode::Table => {
|
||||||
table();
|
table();
|
||||||
|
@ -84,21 +88,21 @@ pub fn uu_app<'a>() -> Command<'a> {
|
||||||
.about(ABOUT)
|
.about(ABOUT)
|
||||||
.override_usage(format_usage(USAGE))
|
.override_usage(format_usage(USAGE))
|
||||||
.infer_long_args(true)
|
.infer_long_args(true)
|
||||||
|
.allow_negative_numbers(true)
|
||||||
.arg(
|
.arg(
|
||||||
Arg::new(options::LIST)
|
Arg::new(options::LIST)
|
||||||
.short('l')
|
.short('l')
|
||||||
.long(options::LIST)
|
.long(options::LIST)
|
||||||
.help("Lists signals")
|
.help("Lists signals")
|
||||||
.conflicts_with(options::TABLE)
|
.conflicts_with(options::TABLE),
|
||||||
.conflicts_with(options::TABLE_OLD),
|
|
||||||
)
|
)
|
||||||
.arg(
|
.arg(
|
||||||
Arg::new(options::TABLE)
|
Arg::new(options::TABLE)
|
||||||
.short('t')
|
.short('t')
|
||||||
|
.short_alias('L')
|
||||||
.long(options::TABLE)
|
.long(options::TABLE)
|
||||||
.help("Lists table of signals"),
|
.help("Lists table of signals"),
|
||||||
)
|
)
|
||||||
.arg(Arg::new(options::TABLE_OLD).short('L').hide(true))
|
|
||||||
.arg(
|
.arg(
|
||||||
Arg::new(options::SIGNAL)
|
Arg::new(options::SIGNAL)
|
||||||
.short('s')
|
.short('s')
|
||||||
|
@ -190,21 +194,21 @@ fn parse_signal_value(signal_name: &str) -> UResult<usize> {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
fn parse_pids(pids: &[String]) -> UResult<Vec<usize>> {
|
fn parse_pids(pids: &[String]) -> UResult<Vec<i32>> {
|
||||||
pids.iter()
|
pids.iter()
|
||||||
.map(|x| {
|
.map(|x| {
|
||||||
x.parse::<usize>().map_err(|e| {
|
x.parse::<i32>().map_err(|e| {
|
||||||
USimpleError::new(1, format!("failed to parse argument {}: {}", x.quote(), e))
|
USimpleError::new(1, format!("failed to parse argument {}: {}", x.quote(), e))
|
||||||
})
|
})
|
||||||
})
|
})
|
||||||
.collect()
|
.collect()
|
||||||
}
|
}
|
||||||
|
|
||||||
fn kill(signal_value: usize, pids: &[usize]) -> UResult<()> {
|
fn kill(sig: Signal, pids: &[i32]) {
|
||||||
for &pid in pids {
|
for &pid in pids {
|
||||||
if unsafe { libc::kill(pid as pid_t, signal_value as c_int) } != 0 {
|
if let Err(e) = signal::kill(Pid::from_raw(pid), sig) {
|
||||||
show!(USimpleError::new(1, format!("{}", Error::last_os_error())));
|
show!(Error::from_raw_os_error(e as i32)
|
||||||
|
.map_err_context(|| format!("sending signal to {} failed", pid)));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
Ok(())
|
|
||||||
}
|
}
|
||||||
|
|
|
@ -17,7 +17,7 @@ use std::env;
|
||||||
use std::error::Error;
|
use std::error::Error;
|
||||||
use std::fmt::Display;
|
use std::fmt::Display;
|
||||||
use std::iter;
|
use std::iter;
|
||||||
use std::path::{is_separator, Path, PathBuf};
|
use std::path::{is_separator, Path, PathBuf, MAIN_SEPARATOR};
|
||||||
|
|
||||||
use rand::Rng;
|
use rand::Rng;
|
||||||
use tempfile::Builder;
|
use tempfile::Builder;
|
||||||
|
@ -129,6 +129,19 @@ pub fn uumain(args: impl uucore::Args) -> UResult<()> {
|
||||||
};
|
};
|
||||||
let filename = path.file_name();
|
let filename = path.file_name();
|
||||||
let template = filename.unwrap().to_str().unwrap();
|
let template = filename.unwrap().to_str().unwrap();
|
||||||
|
// If the command line was `mktemp aXXX/b`, then we will
|
||||||
|
// find that `tmp`, which is the result of getting the
|
||||||
|
// parent when treating the argument as a path, contains
|
||||||
|
// at least three consecutive Xs. This means that there
|
||||||
|
// was a path separator in the suffix, which is not
|
||||||
|
// allowed.
|
||||||
|
if tmp.display().to_string().contains("XXX") {
|
||||||
|
return Err(MkTempError::SuffixContainsDirSeparator(format!(
|
||||||
|
"{}{}",
|
||||||
|
MAIN_SEPARATOR, template
|
||||||
|
))
|
||||||
|
.into());
|
||||||
|
}
|
||||||
(template, tmp)
|
(template, tmp)
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
|
@ -139,12 +152,14 @@ pub fn uumain(args: impl uucore::Args) -> UResult<()> {
|
||||||
let dry_run = matches.is_present(OPT_DRY_RUN);
|
let dry_run = matches.is_present(OPT_DRY_RUN);
|
||||||
let suppress_file_err = matches.is_present(OPT_QUIET);
|
let suppress_file_err = matches.is_present(OPT_QUIET);
|
||||||
|
|
||||||
let (prefix, rand, suffix) = parse_template(template, matches.value_of(OPT_SUFFIX))?;
|
// If `--tmpdir` is given, the template cannot be an absolute
|
||||||
|
// path. For example, `mktemp --tmpdir=a /XXX` is not allowed.
|
||||||
if matches.is_present(OPT_TMPDIR) && PathBuf::from(prefix).is_absolute() {
|
if matches.is_present(OPT_TMPDIR) && PathBuf::from(template).is_absolute() {
|
||||||
return Err(MkTempError::InvalidTemplate(template.into()).into());
|
return Err(MkTempError::InvalidTemplate(template.into()).into());
|
||||||
}
|
}
|
||||||
|
|
||||||
|
let (prefix, rand, suffix) = parse_template(template, matches.value_of(OPT_SUFFIX))?;
|
||||||
|
|
||||||
let res = if dry_run {
|
let res = if dry_run {
|
||||||
dry_exec(tmpdir, prefix, rand, suffix)
|
dry_exec(tmpdir, prefix, rand, suffix)
|
||||||
} else {
|
} else {
|
||||||
|
|
|
@ -13,7 +13,7 @@ mod error;
|
||||||
#[macro_use]
|
#[macro_use]
|
||||||
extern crate uucore;
|
extern crate uucore;
|
||||||
|
|
||||||
use clap::{crate_version, Arg, ArgMatches, Command};
|
use clap::{crate_version, Arg, ArgMatches, Command, ErrorKind};
|
||||||
use std::env;
|
use std::env;
|
||||||
use std::ffi::OsString;
|
use std::ffi::OsString;
|
||||||
use std::fs;
|
use std::fs;
|
||||||
|
@ -70,13 +70,26 @@ static ARG_FILES: &str = "files";
|
||||||
|
|
||||||
#[uucore::main]
|
#[uucore::main]
|
||||||
pub fn uumain(args: impl uucore::Args) -> UResult<()> {
|
pub fn uumain(args: impl uucore::Args) -> UResult<()> {
|
||||||
let matches = uu_app()
|
let help = format!(
|
||||||
.after_help(&*format!(
|
"{}\n{}",
|
||||||
"{}\n{}",
|
LONG_HELP,
|
||||||
LONG_HELP,
|
backup_control::BACKUP_CONTROL_LONG_HELP
|
||||||
backup_control::BACKUP_CONTROL_LONG_HELP
|
);
|
||||||
))
|
let mut app = uu_app().after_help(&*help);
|
||||||
.get_matches_from(args);
|
let matches = app
|
||||||
|
.try_get_matches_from_mut(args)
|
||||||
|
.unwrap_or_else(|e| e.exit());
|
||||||
|
|
||||||
|
if !matches.is_present(OPT_TARGET_DIRECTORY) && matches.occurrences_of(ARG_FILES) == 1 {
|
||||||
|
app.error(
|
||||||
|
ErrorKind::TooFewValues,
|
||||||
|
format!(
|
||||||
|
"The argument '<{}>...' requires at least 2 values, but only 1 was provided",
|
||||||
|
ARG_FILES
|
||||||
|
),
|
||||||
|
)
|
||||||
|
.exit();
|
||||||
|
}
|
||||||
|
|
||||||
let files: Vec<OsString> = matches
|
let files: Vec<OsString> = matches
|
||||||
.values_of_os(ARG_FILES)
|
.values_of_os(ARG_FILES)
|
||||||
|
@ -181,7 +194,7 @@ pub fn uu_app<'a>() -> Command<'a> {
|
||||||
Arg::new(ARG_FILES)
|
Arg::new(ARG_FILES)
|
||||||
.multiple_occurrences(true)
|
.multiple_occurrences(true)
|
||||||
.takes_value(true)
|
.takes_value(true)
|
||||||
.min_values(2)
|
.min_values(1)
|
||||||
.required(true)
|
.required(true)
|
||||||
.allow_invalid_utf8(true)
|
.allow_invalid_utf8(true)
|
||||||
.value_hint(clap::ValueHint::AnyPath)
|
.value_hint(clap::ValueHint::AnyPath)
|
||||||
|
|
|
@ -31,20 +31,20 @@ impl SeqError {
|
||||||
/// The [`String`] argument as read from the command-line.
|
/// The [`String`] argument as read from the command-line.
|
||||||
fn arg(&self) -> &str {
|
fn arg(&self) -> &str {
|
||||||
match self {
|
match self {
|
||||||
SeqError::ParseError(s, _) => s,
|
Self::ParseError(s, _) => s,
|
||||||
SeqError::ZeroIncrement(s) => s,
|
Self::ZeroIncrement(s) => s,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/// The type of argument that is causing the error.
|
/// The type of argument that is causing the error.
|
||||||
fn argtype(&self) -> &str {
|
fn argtype(&self) -> &str {
|
||||||
match self {
|
match self {
|
||||||
SeqError::ParseError(_, e) => match e {
|
Self::ParseError(_, e) => match e {
|
||||||
ParseNumberError::Float => "floating point argument",
|
ParseNumberError::Float => "floating point argument",
|
||||||
ParseNumberError::Nan => "'not-a-number' argument",
|
ParseNumberError::Nan => "'not-a-number' argument",
|
||||||
ParseNumberError::Hex => "hexadecimal argument",
|
ParseNumberError::Hex => "hexadecimal argument",
|
||||||
},
|
},
|
||||||
SeqError::ZeroIncrement(_) => "Zero increment value",
|
Self::ZeroIncrement(_) => "Zero increment value",
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -53,18 +53,16 @@ impl UError for SeqError {
|
||||||
fn code(&self) -> i32 {
|
fn code(&self) -> i32 {
|
||||||
1
|
1
|
||||||
}
|
}
|
||||||
|
|
||||||
|
fn usage(&self) -> bool {
|
||||||
|
true
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl Error for SeqError {}
|
impl Error for SeqError {}
|
||||||
|
|
||||||
impl Display for SeqError {
|
impl Display for SeqError {
|
||||||
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
|
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
|
||||||
write!(
|
write!(f, "invalid {}: {}", self.argtype(), self.arg().quote())
|
||||||
f,
|
|
||||||
"invalid {}: {}\nTry '{} --help' for more information.",
|
|
||||||
self.argtype(),
|
|
||||||
self.arg().quote(),
|
|
||||||
uucore::execution_phrase(),
|
|
||||||
)
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -5,6 +5,9 @@
|
||||||
// * For the full copyright and license information, please view the LICENSE
|
// * For the full copyright and license information, please view the LICENSE
|
||||||
// * file that was distributed with this source code.
|
// * file that was distributed with this source code.
|
||||||
|
|
||||||
|
// TODO remove this when https://github.com/rust-lang/rust-clippy/issues/6902 is fixed
|
||||||
|
#![allow(clippy::use_self)]
|
||||||
|
|
||||||
use clap::{crate_version, Arg, ArgMatches, Command};
|
use clap::{crate_version, Arg, ArgMatches, Command};
|
||||||
use std::fs::File;
|
use std::fs::File;
|
||||||
use std::io::{self, stdin, stdout, BufRead, BufReader, BufWriter, Read, Write};
|
use std::io::{self, stdin, stdout, BufRead, BufReader, BufWriter, Read, Write};
|
||||||
|
|
|
@ -414,6 +414,22 @@ fn test_mktemp_directory_tmpdir() {
|
||||||
assert!(PathBuf::from(result.stdout_str().trim()).is_dir());
|
assert!(PathBuf::from(result.stdout_str().trim()).is_dir());
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// Test that an absolute path is disallowed when --tmpdir is provided.
|
||||||
|
#[test]
|
||||||
|
fn test_tmpdir_absolute_path() {
|
||||||
|
#[cfg(windows)]
|
||||||
|
let path = r"C:\XXX";
|
||||||
|
#[cfg(not(windows))]
|
||||||
|
let path = "/XXX";
|
||||||
|
new_ucmd!()
|
||||||
|
.args(&["--tmpdir=a", path])
|
||||||
|
.fails()
|
||||||
|
.stderr_only(format!(
|
||||||
|
"mktemp: invalid template, '{}'; with --tmpdir, it may not be absolute\n",
|
||||||
|
path
|
||||||
|
));
|
||||||
|
}
|
||||||
|
|
||||||
/// Decide whether a string matches a given template.
|
/// Decide whether a string matches a given template.
|
||||||
///
|
///
|
||||||
/// In the template, the character `'X'` is treated as a wildcard,
|
/// In the template, the character `'X'` is treated as a wildcard,
|
||||||
|
@ -496,3 +512,18 @@ fn test_template_path_separator() {
|
||||||
"a/bXXX".quote()
|
"a/bXXX".quote()
|
||||||
));
|
));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// Test that a suffix with a path separator is invalid.
|
||||||
|
#[test]
|
||||||
|
fn test_suffix_path_separator() {
|
||||||
|
#[cfg(not(windows))]
|
||||||
|
new_ucmd!()
|
||||||
|
.arg("aXXX/b")
|
||||||
|
.fails()
|
||||||
|
.stderr_only("mktemp: invalid suffix '/b', contains directory separator\n");
|
||||||
|
#[cfg(windows)]
|
||||||
|
new_ucmd!()
|
||||||
|
.arg(r"aXXX\b")
|
||||||
|
.fails()
|
||||||
|
.stderr_only("mktemp: invalid suffix '\\b', contains directory separator\n");
|
||||||
|
}
|
||||||
|
|
|
@ -641,6 +641,20 @@ fn test_mv_target_dir() {
|
||||||
assert!(at.file_exists(&format!("{}/{}", dir, file_b)));
|
assert!(at.file_exists(&format!("{}/{}", dir, file_b)));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn test_mv_target_dir_single_source() {
|
||||||
|
let (at, mut ucmd) = at_and_ucmd!();
|
||||||
|
let dir = "test_mv_target_dir_single_source_dir";
|
||||||
|
let file = "test_mv_target_dir_single_source_file";
|
||||||
|
|
||||||
|
at.touch(file);
|
||||||
|
at.mkdir(dir);
|
||||||
|
ucmd.arg("-t").arg(dir).arg(file).succeeds().no_stderr();
|
||||||
|
|
||||||
|
assert!(!at.file_exists(file));
|
||||||
|
assert!(at.file_exists(&format!("{}/{}", dir, file)));
|
||||||
|
}
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
fn test_mv_overwrite_dir() {
|
fn test_mv_overwrite_dir() {
|
||||||
let (at, mut ucmd) = at_and_ucmd!();
|
let (at, mut ucmd) = at_and_ucmd!();
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue