1
Fork 0
mirror of https://github.com/RGBCube/uutils-coreutils synced 2025-07-28 11:37:44 +00:00

Implement install create leading components(-D) option (#2092)

* Implement install's create leading components(-D) option

* Format changes

* Add install test to check fail on long dir name
This commit is contained in:
Sivachandran 2021-04-20 01:33:13 +05:30 committed by GitHub
parent 879ab2ecb0
commit 0ea35f3fbc
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
2 changed files with 71 additions and 9 deletions

View file

@ -41,6 +41,7 @@ pub struct Behavior {
compare: bool,
strip: bool,
strip_program: String,
create_leading: bool,
}
#[derive(Clone, Eq, PartialEq)]
@ -70,7 +71,7 @@ static OPT_BACKUP: &str = "backup";
static OPT_BACKUP_2: &str = "backup2";
static OPT_DIRECTORY: &str = "directory";
static OPT_IGNORED: &str = "ignored";
static OPT_CREATED: &str = "created";
static OPT_CREATE_LEADING: &str = "create-leading";
static OPT_GROUP: &str = "group";
static OPT_MODE: &str = "mode";
static OPT_OWNER: &str = "owner";
@ -133,9 +134,9 @@ pub fn uumain(args: impl uucore::Args) -> i32 {
.arg(
// TODO implement flag
Arg::with_name(OPT_CREATED)
Arg::with_name(OPT_CREATE_LEADING)
.short("D")
.help("(unimplemented) create all leading components of DEST except the last, then copy SOURCE to DEST")
.help("create all leading components of DEST except the last, then copy SOURCE to DEST")
)
.arg(
Arg::with_name(OPT_GROUP)
@ -266,8 +267,6 @@ fn check_unimplemented<'a>(matches: &ArgMatches) -> Result<(), &'a str> {
Err("--backup")
} else if matches.is_present(OPT_BACKUP_2) {
Err("-b")
} else if matches.is_present(OPT_CREATED) {
Err("-D")
} else if matches.is_present(OPT_SUFFIX) {
Err("--suffix, -S")
} else if matches.is_present(OPT_TARGET_DIRECTORY) {
@ -343,6 +342,7 @@ fn behavior(matches: &ArgMatches) -> Result<Behavior, i32> {
.value_of(OPT_STRIP_PROGRAM)
.unwrap_or(DEFAULT_STRIP_PROGRAM),
),
create_leading: matches.is_present(OPT_CREATE_LEADING),
})
}
@ -410,12 +410,35 @@ fn standard(paths: Vec<String>, b: Behavior) -> i32 {
.iter()
.map(PathBuf::from)
.collect::<Vec<_>>();
let target = Path::new(paths.last().unwrap());
if (target.is_file() || is_new_file_path(target)) && sources.len() == 1 {
if sources.len() > 1 || (target.exists() && target.is_dir()) {
copy_files_into_dir(sources, &target.to_path_buf(), &b)
} else {
if let Some(parent) = target.parent() {
if !parent.exists() && b.create_leading {
if let Err(e) = fs::create_dir_all(parent) {
show_error!("failed to create {}: {}", parent.display(), e);
return 1;
}
if mode::chmod(&parent, b.mode()).is_err() {
show_error!("failed to chmod {}", parent.display());
return 1;
}
}
}
if target.is_file() || is_new_file_path(target) {
copy_file_to_file(&sources[0], &target.to_path_buf(), &b)
} else {
copy_files_into_dir(sources, &target.to_path_buf(), &b)
show_error!(
"invalid target {}: No such file or directory",
target.display()
);
1
}
}
}

View file

@ -359,7 +359,7 @@ fn test_install_target_new_file_failing_nonexistent_parent() {
ucmd.arg(file1)
.arg(format!("{}/{}", dir, file2))
.fails()
.stderr_contains(&"not a directory");
.stderr_contains(&"No such file or directory");
}
#[test]
@ -649,3 +649,42 @@ fn test_install_and_strip_with_non_existent_program() {
.stderr;
assert!(stderr.contains("No such file or directory"));
}
#[test]
fn test_install_creating_leading_dirs() {
let scene = TestScenario::new(util_name!());
let at = &scene.fixtures;
let source = "create_leading_test_file";
let target = "dir1/dir2/dir3/test_file";
at.touch(source);
scene
.ucmd()
.arg("-D")
.arg(source)
.arg(at.plus(target))
.succeeds()
.no_stderr();
}
#[test]
#[cfg(not(windows))]
fn test_install_creating_leading_dir_fails_on_long_name() {
let scene = TestScenario::new(util_name!());
let at = &scene.fixtures;
let source = "create_leading_test_file";
let target = format!("{}/test_file", "d".repeat(libc::PATH_MAX as usize + 1));
at.touch(source);
scene
.ucmd()
.arg("-D")
.arg(source)
.arg(at.plus(target.as_str()))
.fails()
.stderr_contains("failed to create");
}