mirror of
https://github.com/RGBCube/uutils-coreutils
synced 2025-07-27 11:07:44 +00:00
Merge branch 'main' into 6175-env-empty-string
This commit is contained in:
commit
3848e6c271
10 changed files with 870 additions and 665 deletions
|
@ -1,3 +1,4 @@
|
|||
msrv = "1.85.0"
|
||||
avoid-breaking-exported-api = false
|
||||
check-private-items = true
|
||||
cognitive-complexity-threshold = 24
|
||||
|
|
1
Cargo.lock
generated
1
Cargo.lock
generated
|
@ -3031,6 +3031,7 @@ dependencies = [
|
|||
"clap",
|
||||
"crossterm",
|
||||
"nix",
|
||||
"tempfile",
|
||||
"unicode-segmentation",
|
||||
"unicode-width 0.2.0",
|
||||
"uucore",
|
||||
|
|
|
@ -342,7 +342,6 @@ thiserror = "2.0.3"
|
|||
time = { version = "0.3.36" }
|
||||
unicode-segmentation = "1.11.0"
|
||||
unicode-width = "0.2.0"
|
||||
utf-8 = "0.7.6"
|
||||
utmp-classic = "0.1.6"
|
||||
uutils_term_grid = "0.7"
|
||||
walkdir = "2.5"
|
||||
|
|
|
@ -1259,13 +1259,17 @@ fn parse_path_args(
|
|||
return Err("missing file operand".into());
|
||||
} else if paths.len() == 1 && options.target_dir.is_none() {
|
||||
// Only one file specified
|
||||
return Err(format!("missing destination file operand after {:?}", paths[0]).into());
|
||||
return Err(format!(
|
||||
"missing destination file operand after {}",
|
||||
paths[0].display().to_string().quote()
|
||||
)
|
||||
.into());
|
||||
}
|
||||
|
||||
// Return an error if the user requested to copy more than one
|
||||
// file source to a file target
|
||||
if options.no_target_dir && options.target_dir.is_none() && paths.len() > 2 {
|
||||
return Err(format!("extra operand {:?}", paths[2]).into());
|
||||
return Err(format!("extra operand {:}", paths[2].display().to_string().quote()).into());
|
||||
}
|
||||
|
||||
let target = match options.target_dir {
|
||||
|
|
|
@ -84,7 +84,12 @@ pub(crate) fn copy_on_write(
|
|||
// support COW).
|
||||
match reflink_mode {
|
||||
ReflinkMode::Always => {
|
||||
return Err(format!("failed to clone {source:?} from {dest:?}: {error}").into());
|
||||
return Err(format!(
|
||||
"failed to clone {} from {}: {error}",
|
||||
source.display(),
|
||||
dest.display()
|
||||
)
|
||||
.into());
|
||||
}
|
||||
_ => {
|
||||
copy_debug.reflink = OffloadReflinkDebug::Yes;
|
||||
|
|
|
@ -33,3 +33,6 @@ crossterm = { workspace = true, features = ["use-dev-tty"] }
|
|||
[[bin]]
|
||||
name = "more"
|
||||
path = "src/main.rs"
|
||||
|
||||
[dev-dependencies]
|
||||
tempfile = { workspace = true }
|
||||
|
|
File diff suppressed because it is too large
Load diff
|
@ -826,7 +826,7 @@ fn rename_dir_fallback(
|
|||
io::ErrorKind::PermissionDenied,
|
||||
"Permission denied",
|
||||
)),
|
||||
_ => Err(io::Error::new(io::ErrorKind::Other, format!("{err:?}"))),
|
||||
_ => Err(io::Error::other(format!("{err:?}"))),
|
||||
},
|
||||
_ => Ok(()),
|
||||
}
|
||||
|
|
|
@ -2,13 +2,12 @@
|
|||
//
|
||||
// For the full copyright and license information, please view the LICENSE
|
||||
// file that was distributed with this source code.
|
||||
|
||||
// spell-checker:ignore (flags) reflink (fs) tmpfs (linux) rlimit Rlim NOFILE clob btrfs neve ROOTDIR USERDIR procfs outfile uufs xattrs
|
||||
// spell-checker:ignore bdfl hlsl IRWXO IRWXG nconfined matchpathcon libselinux-devel
|
||||
use uutests::at_and_ucmd;
|
||||
use uutests::new_ucmd;
|
||||
use uutests::path_concat;
|
||||
use uucore::display::Quotable;
|
||||
use uutests::util::TestScenario;
|
||||
use uutests::util_name;
|
||||
use uutests::{at_and_ucmd, new_ucmd, path_concat, util_name};
|
||||
|
||||
#[cfg(not(windows))]
|
||||
use std::fs::set_permissions;
|
||||
|
@ -3946,10 +3945,10 @@ fn test_cp_only_source_no_target() {
|
|||
let ts = TestScenario::new(util_name!());
|
||||
let at = &ts.fixtures;
|
||||
at.touch("a");
|
||||
ts.ucmd()
|
||||
.arg("a")
|
||||
.fails()
|
||||
.stderr_contains("missing destination file operand after \"a\"");
|
||||
ts.ucmd().arg("a").fails().stderr_contains(format!(
|
||||
"missing destination file operand after {}",
|
||||
"a".quote()
|
||||
));
|
||||
}
|
||||
|
||||
#[test]
|
||||
|
|
|
@ -2,56 +2,58 @@
|
|||
//
|
||||
// For the full copyright and license information, please view the LICENSE
|
||||
// file that was distributed with this source code.
|
||||
use std::io::IsTerminal;
|
||||
#[cfg(target_family = "unix")]
|
||||
use uutests::at_and_ucmd;
|
||||
use uutests::new_ucmd;
|
||||
use uutests::util::TestScenario;
|
||||
use uutests::util_name;
|
||||
|
||||
use std::io::IsTerminal;
|
||||
|
||||
use uutests::{at_and_ucmd, new_ucmd, util::TestScenario, util_name};
|
||||
|
||||
#[cfg(unix)]
|
||||
#[test]
|
||||
fn test_more_no_arg() {
|
||||
fn test_no_arg() {
|
||||
if std::io::stdout().is_terminal() {
|
||||
new_ucmd!().fails().stderr_contains("more: bad usage");
|
||||
new_ucmd!()
|
||||
.terminal_simulation(true)
|
||||
.fails()
|
||||
.stderr_contains("more: bad usage");
|
||||
}
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_valid_arg() {
|
||||
if std::io::stdout().is_terminal() {
|
||||
let scene = TestScenario::new(util_name!());
|
||||
let at = &scene.fixtures;
|
||||
let args_list: Vec<&[&str]> = vec![
|
||||
&["-c"],
|
||||
&["--clean-print"],
|
||||
&["-p"],
|
||||
&["--print-over"],
|
||||
&["-s"],
|
||||
&["--squeeze"],
|
||||
&["-u"],
|
||||
&["--plain"],
|
||||
&["-n", "10"],
|
||||
&["--lines", "0"],
|
||||
&["--number", "0"],
|
||||
&["-F", "10"],
|
||||
&["--from-line", "0"],
|
||||
&["-P", "something"],
|
||||
&["--pattern", "-1"],
|
||||
];
|
||||
for args in args_list {
|
||||
test_alive(args);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
fn test_alive(args: &[&str]) {
|
||||
let (at, mut ucmd) = at_and_ucmd!();
|
||||
let file = "test_file";
|
||||
at.touch(file);
|
||||
|
||||
scene.ucmd().arg(file).arg("-c").succeeds();
|
||||
scene.ucmd().arg(file).arg("--print-over").succeeds();
|
||||
|
||||
scene.ucmd().arg(file).arg("-p").succeeds();
|
||||
scene.ucmd().arg(file).arg("--clean-print").succeeds();
|
||||
|
||||
scene.ucmd().arg(file).arg("-s").succeeds();
|
||||
scene.ucmd().arg(file).arg("--squeeze").succeeds();
|
||||
|
||||
scene.ucmd().arg(file).arg("-u").succeeds();
|
||||
scene.ucmd().arg(file).arg("--plain").succeeds();
|
||||
|
||||
scene.ucmd().arg(file).arg("-n").arg("10").succeeds();
|
||||
scene.ucmd().arg(file).arg("--lines").arg("0").succeeds();
|
||||
scene.ucmd().arg(file).arg("--number").arg("0").succeeds();
|
||||
|
||||
scene.ucmd().arg(file).arg("-F").arg("10").succeeds();
|
||||
scene
|
||||
.ucmd()
|
||||
ucmd.args(args)
|
||||
.arg(file)
|
||||
.arg("--from-line")
|
||||
.arg("0")
|
||||
.succeeds();
|
||||
|
||||
scene.ucmd().arg(file).arg("-P").arg("something").succeeds();
|
||||
scene.ucmd().arg(file).arg("--pattern").arg("-1").succeeds();
|
||||
}
|
||||
.run_no_wait()
|
||||
.make_assertion()
|
||||
.is_alive();
|
||||
}
|
||||
|
||||
#[test]
|
||||
|
@ -67,59 +69,46 @@ fn test_invalid_arg() {
|
|||
}
|
||||
|
||||
#[test]
|
||||
fn test_argument_from_file() {
|
||||
if std::io::stdout().is_terminal() {
|
||||
let scene = TestScenario::new(util_name!());
|
||||
let at = &scene.fixtures;
|
||||
|
||||
let file = "test_file";
|
||||
|
||||
at.write(file, "1\n2");
|
||||
|
||||
// output all lines
|
||||
scene
|
||||
.ucmd()
|
||||
.arg("-F")
|
||||
.arg("0")
|
||||
.arg(file)
|
||||
.succeeds()
|
||||
.no_stderr()
|
||||
.stdout_contains("1")
|
||||
.stdout_contains("2");
|
||||
|
||||
// output only the second line
|
||||
scene
|
||||
.ucmd()
|
||||
.arg("-F")
|
||||
.arg("2")
|
||||
.arg(file)
|
||||
.succeeds()
|
||||
.no_stderr()
|
||||
.stdout_contains("2")
|
||||
.stdout_does_not_contain("1");
|
||||
}
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_more_dir_arg() {
|
||||
fn test_file_arg() {
|
||||
// Run the test only if there's a valid terminal, else do nothing
|
||||
// Maybe we could capture the error, i.e. "Device not found" in that case
|
||||
// but I am leaving this for later
|
||||
if std::io::stdout().is_terminal() {
|
||||
new_ucmd!()
|
||||
.arg(".")
|
||||
// Directory as argument
|
||||
let mut ucmd = TestScenario::new(util_name!()).ucmd();
|
||||
ucmd.arg(".")
|
||||
.succeeds()
|
||||
.stderr_contains("'.' is a directory.");
|
||||
|
||||
// Single argument errors
|
||||
let (at, mut ucmd) = at_and_ucmd!();
|
||||
at.mkdir_all("folder");
|
||||
ucmd.arg("folder")
|
||||
.succeeds()
|
||||
.stderr_contains("is a directory");
|
||||
|
||||
ucmd = TestScenario::new(util_name!()).ucmd();
|
||||
ucmd.arg("nonexistent_file")
|
||||
.succeeds()
|
||||
.stderr_contains("No such file or directory");
|
||||
|
||||
// Multiple nonexistent files
|
||||
ucmd = TestScenario::new(util_name!()).ucmd();
|
||||
ucmd.arg("file2")
|
||||
.arg("file3")
|
||||
.succeeds()
|
||||
.stderr_contains("file2")
|
||||
.stderr_contains("file3");
|
||||
}
|
||||
}
|
||||
|
||||
#[test]
|
||||
#[cfg(target_family = "unix")]
|
||||
fn test_more_invalid_file_perms() {
|
||||
fn test_invalid_file_perms() {
|
||||
if std::io::stdout().is_terminal() {
|
||||
use std::fs::{Permissions, set_permissions};
|
||||
use std::os::unix::fs::PermissionsExt;
|
||||
|
||||
if std::io::stdout().is_terminal() {
|
||||
let (at, mut ucmd) = at_and_ucmd!();
|
||||
let permissions = Permissions::from_mode(0o244);
|
||||
at.make_file("invalid-perms.txt");
|
||||
|
@ -129,89 +118,3 @@ fn test_more_invalid_file_perms() {
|
|||
.stderr_contains("permission denied");
|
||||
}
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_more_error_on_single_arg() {
|
||||
if std::io::stdout().is_terminal() {
|
||||
let ts = TestScenario::new("more");
|
||||
ts.fixtures.mkdir_all("folder");
|
||||
ts.ucmd()
|
||||
.arg("folder")
|
||||
.succeeds()
|
||||
.stderr_contains("is a directory");
|
||||
ts.ucmd()
|
||||
.arg("file1")
|
||||
.succeeds()
|
||||
.stderr_contains("No such file or directory");
|
||||
}
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_more_error_on_multiple_files() {
|
||||
if std::io::stdout().is_terminal() {
|
||||
let ts = TestScenario::new("more");
|
||||
ts.fixtures.mkdir_all("folder");
|
||||
ts.fixtures.make_file("file1");
|
||||
ts.ucmd()
|
||||
.arg("folder")
|
||||
.arg("file2")
|
||||
.arg("file1")
|
||||
.succeeds()
|
||||
.stderr_contains("folder")
|
||||
.stderr_contains("file2")
|
||||
.stdout_contains("file1");
|
||||
ts.ucmd()
|
||||
.arg("file2")
|
||||
.arg("file3")
|
||||
.succeeds()
|
||||
.stderr_contains("file2")
|
||||
.stderr_contains("file3");
|
||||
}
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_more_pattern_found() {
|
||||
if std::io::stdout().is_terminal() {
|
||||
let scene = TestScenario::new(util_name!());
|
||||
let at = &scene.fixtures;
|
||||
|
||||
let file = "test_file";
|
||||
|
||||
at.write(file, "line1\nline2");
|
||||
|
||||
// output only the second line "line2"
|
||||
scene
|
||||
.ucmd()
|
||||
.arg("-P")
|
||||
.arg("line2")
|
||||
.arg(file)
|
||||
.succeeds()
|
||||
.no_stderr()
|
||||
.stdout_does_not_contain("line1")
|
||||
.stdout_contains("line2");
|
||||
}
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_more_pattern_not_found() {
|
||||
if std::io::stdout().is_terminal() {
|
||||
let scene = TestScenario::new(util_name!());
|
||||
let at = &scene.fixtures;
|
||||
|
||||
let file = "test_file";
|
||||
|
||||
let file_content = "line1\nline2";
|
||||
at.write(file, file_content);
|
||||
|
||||
scene
|
||||
.ucmd()
|
||||
.arg("-P")
|
||||
.arg("something")
|
||||
.arg(file)
|
||||
.succeeds()
|
||||
.no_stderr()
|
||||
.stdout_contains("Pattern not found")
|
||||
.stdout_contains("line1")
|
||||
.stdout_contains("line2");
|
||||
}
|
||||
}
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue