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:
parent
879ab2ecb0
commit
0ea35f3fbc
2 changed files with 71 additions and 9 deletions
|
@ -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 {
|
||||
copy_file_to_file(&sources[0], &target.to_path_buf(), &b)
|
||||
} else {
|
||||
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 {
|
||||
show_error!(
|
||||
"invalid target {}: No such file or directory",
|
||||
target.display()
|
||||
);
|
||||
1
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -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");
|
||||
}
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue