mirror of
https://github.com/RGBCube/uutils-coreutils
synced 2025-07-28 03:27:44 +00:00
Merge pull request #1118 from KeenS/install-file
install: allow to install a file to a file
This commit is contained in:
commit
0fdf2df3eb
3 changed files with 203 additions and 113 deletions
227
Cargo.lock
generated
227
Cargo.lock
generated
|
@ -1,112 +1,3 @@
|
||||||
[root]
|
|
||||||
name = "uutils"
|
|
||||||
version = "0.0.1"
|
|
||||||
dependencies = [
|
|
||||||
"arch 0.0.1",
|
|
||||||
"base32 0.0.1",
|
|
||||||
"base64 0.0.1",
|
|
||||||
"basename 0.0.1",
|
|
||||||
"cat 0.0.1",
|
|
||||||
"chgrp 0.0.1",
|
|
||||||
"chmod 0.0.1",
|
|
||||||
"chown 0.0.1",
|
|
||||||
"chroot 0.0.1",
|
|
||||||
"cksum 0.0.1",
|
|
||||||
"comm 0.0.1",
|
|
||||||
"cp 0.0.1",
|
|
||||||
"cut 0.0.1",
|
|
||||||
"date 0.0.1",
|
|
||||||
"dircolors 0.0.1",
|
|
||||||
"dirname 0.0.1",
|
|
||||||
"du 0.0.1",
|
|
||||||
"echo 0.0.1",
|
|
||||||
"env 0.0.1",
|
|
||||||
"expand 0.0.1",
|
|
||||||
"expr 0.0.1",
|
|
||||||
"factor 0.0.1",
|
|
||||||
"false 0.0.1",
|
|
||||||
"filetime 0.1.14 (registry+https://github.com/rust-lang/crates.io-index)",
|
|
||||||
"fmt 0.0.1",
|
|
||||||
"fold 0.0.1",
|
|
||||||
"groups 0.0.1",
|
|
||||||
"hashsum 0.0.1",
|
|
||||||
"head 0.0.1",
|
|
||||||
"hostid 0.0.1",
|
|
||||||
"hostname 0.0.1",
|
|
||||||
"id 0.0.1",
|
|
||||||
"install 0.0.1",
|
|
||||||
"join 0.0.1",
|
|
||||||
"kill 0.0.1",
|
|
||||||
"lazy_static 0.2.10 (registry+https://github.com/rust-lang/crates.io-index)",
|
|
||||||
"libc 0.2.33 (registry+https://github.com/rust-lang/crates.io-index)",
|
|
||||||
"link 0.0.1",
|
|
||||||
"ln 0.0.1",
|
|
||||||
"logname 0.0.1",
|
|
||||||
"ls 0.0.1",
|
|
||||||
"mkdir 0.0.1",
|
|
||||||
"mkfifo 0.0.1",
|
|
||||||
"mknod 0.0.1",
|
|
||||||
"mktemp 0.0.1",
|
|
||||||
"more 0.0.1",
|
|
||||||
"mv 0.0.1",
|
|
||||||
"nice 0.0.1",
|
|
||||||
"nl 0.0.1",
|
|
||||||
"nohup 0.0.1",
|
|
||||||
"nproc 0.0.1",
|
|
||||||
"numfmt 0.0.1",
|
|
||||||
"od 0.0.1",
|
|
||||||
"paste 0.0.1",
|
|
||||||
"pathchk 0.0.1",
|
|
||||||
"pinky 0.0.1",
|
|
||||||
"printenv 0.0.1",
|
|
||||||
"printf 0.0.1",
|
|
||||||
"ptx 0.0.1",
|
|
||||||
"pwd 0.0.1",
|
|
||||||
"rand 0.3.18 (registry+https://github.com/rust-lang/crates.io-index)",
|
|
||||||
"readlink 0.0.1",
|
|
||||||
"realpath 0.0.1",
|
|
||||||
"regex 0.2.2 (registry+https://github.com/rust-lang/crates.io-index)",
|
|
||||||
"relpath 0.0.1",
|
|
||||||
"rm 0.0.1",
|
|
||||||
"rmdir 0.0.1",
|
|
||||||
"seq 0.0.1",
|
|
||||||
"shred 0.0.1",
|
|
||||||
"shuf 0.0.1",
|
|
||||||
"sleep 0.0.1",
|
|
||||||
"sort 0.0.1",
|
|
||||||
"split 0.0.1",
|
|
||||||
"stat 0.0.1",
|
|
||||||
"stdbuf 0.0.1",
|
|
||||||
"sum 0.0.1",
|
|
||||||
"sync 0.0.1",
|
|
||||||
"tac 0.0.1",
|
|
||||||
"tail 0.0.1",
|
|
||||||
"tee 0.0.1",
|
|
||||||
"tempdir 0.3.5 (registry+https://github.com/rust-lang/crates.io-index)",
|
|
||||||
"test 0.0.1",
|
|
||||||
"time 0.1.38 (registry+https://github.com/rust-lang/crates.io-index)",
|
|
||||||
"timeout 0.0.1",
|
|
||||||
"touch 0.0.1",
|
|
||||||
"tr 0.0.1",
|
|
||||||
"true 0.0.1",
|
|
||||||
"truncate 0.0.1",
|
|
||||||
"tsort 0.0.1",
|
|
||||||
"tty 0.0.1",
|
|
||||||
"uname 0.0.1",
|
|
||||||
"unexpand 0.0.1",
|
|
||||||
"unindent 0.1.2 (registry+https://github.com/rust-lang/crates.io-index)",
|
|
||||||
"uniq 0.0.1",
|
|
||||||
"unix_socket 0.5.0 (registry+https://github.com/rust-lang/crates.io-index)",
|
|
||||||
"unlink 0.0.1",
|
|
||||||
"uptime 0.0.1",
|
|
||||||
"users 0.0.1",
|
|
||||||
"uucore 0.0.1",
|
|
||||||
"wc 0.0.1",
|
|
||||||
"who 0.0.1",
|
|
||||||
"whoami 0.0.1",
|
|
||||||
"yes 0.0.1",
|
|
||||||
]
|
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "advapi32-sys"
|
name = "advapi32-sys"
|
||||||
version = "0.2.0"
|
version = "0.2.0"
|
||||||
|
@ -435,6 +326,9 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "false"
|
name = "false"
|
||||||
version = "0.0.1"
|
version = "0.0.1"
|
||||||
|
dependencies = [
|
||||||
|
"uucore 0.0.1",
|
||||||
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "filetime"
|
name = "filetime"
|
||||||
|
@ -593,7 +487,7 @@ dependencies = [
|
||||||
name = "join"
|
name = "join"
|
||||||
version = "0.0.1"
|
version = "0.0.1"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"getopts 0.2.15 (registry+https://github.com/rust-lang/crates.io-index)",
|
"clap 2.27.1 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||||
"uucore 0.0.1",
|
"uucore 0.0.1",
|
||||||
]
|
]
|
||||||
|
|
||||||
|
@ -1170,6 +1064,7 @@ version = "0.0.1"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"cc 1.0.3 (registry+https://github.com/rust-lang/crates.io-index)",
|
"cc 1.0.3 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||||
"getopts 0.2.15 (registry+https://github.com/rust-lang/crates.io-index)",
|
"getopts 0.2.15 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||||
|
"glob 0.2.11 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||||
"libstdbuf 0.0.1",
|
"libstdbuf 0.0.1",
|
||||||
"uucore 0.0.1",
|
"uucore 0.0.1",
|
||||||
]
|
]
|
||||||
|
@ -1345,6 +1240,9 @@ dependencies = [
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "true"
|
name = "true"
|
||||||
version = "0.0.1"
|
version = "0.0.1"
|
||||||
|
dependencies = [
|
||||||
|
"uucore 0.0.1",
|
||||||
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "truncate"
|
name = "truncate"
|
||||||
|
@ -1467,6 +1365,115 @@ dependencies = [
|
||||||
"time 0.1.38 (registry+https://github.com/rust-lang/crates.io-index)",
|
"time 0.1.38 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||||
]
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "uutils"
|
||||||
|
version = "0.0.1"
|
||||||
|
dependencies = [
|
||||||
|
"arch 0.0.1",
|
||||||
|
"base32 0.0.1",
|
||||||
|
"base64 0.0.1",
|
||||||
|
"basename 0.0.1",
|
||||||
|
"cat 0.0.1",
|
||||||
|
"chgrp 0.0.1",
|
||||||
|
"chmod 0.0.1",
|
||||||
|
"chown 0.0.1",
|
||||||
|
"chroot 0.0.1",
|
||||||
|
"cksum 0.0.1",
|
||||||
|
"comm 0.0.1",
|
||||||
|
"cp 0.0.1",
|
||||||
|
"cut 0.0.1",
|
||||||
|
"date 0.0.1",
|
||||||
|
"dircolors 0.0.1",
|
||||||
|
"dirname 0.0.1",
|
||||||
|
"du 0.0.1",
|
||||||
|
"echo 0.0.1",
|
||||||
|
"env 0.0.1",
|
||||||
|
"expand 0.0.1",
|
||||||
|
"expr 0.0.1",
|
||||||
|
"factor 0.0.1",
|
||||||
|
"false 0.0.1",
|
||||||
|
"filetime 0.1.14 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||||
|
"fmt 0.0.1",
|
||||||
|
"fold 0.0.1",
|
||||||
|
"groups 0.0.1",
|
||||||
|
"hashsum 0.0.1",
|
||||||
|
"head 0.0.1",
|
||||||
|
"hostid 0.0.1",
|
||||||
|
"hostname 0.0.1",
|
||||||
|
"id 0.0.1",
|
||||||
|
"install 0.0.1",
|
||||||
|
"join 0.0.1",
|
||||||
|
"kill 0.0.1",
|
||||||
|
"lazy_static 0.2.10 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||||
|
"libc 0.2.33 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||||
|
"link 0.0.1",
|
||||||
|
"ln 0.0.1",
|
||||||
|
"logname 0.0.1",
|
||||||
|
"ls 0.0.1",
|
||||||
|
"mkdir 0.0.1",
|
||||||
|
"mkfifo 0.0.1",
|
||||||
|
"mknod 0.0.1",
|
||||||
|
"mktemp 0.0.1",
|
||||||
|
"more 0.0.1",
|
||||||
|
"mv 0.0.1",
|
||||||
|
"nice 0.0.1",
|
||||||
|
"nl 0.0.1",
|
||||||
|
"nohup 0.0.1",
|
||||||
|
"nproc 0.0.1",
|
||||||
|
"numfmt 0.0.1",
|
||||||
|
"od 0.0.1",
|
||||||
|
"paste 0.0.1",
|
||||||
|
"pathchk 0.0.1",
|
||||||
|
"pinky 0.0.1",
|
||||||
|
"printenv 0.0.1",
|
||||||
|
"printf 0.0.1",
|
||||||
|
"ptx 0.0.1",
|
||||||
|
"pwd 0.0.1",
|
||||||
|
"rand 0.3.18 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||||
|
"readlink 0.0.1",
|
||||||
|
"realpath 0.0.1",
|
||||||
|
"regex 0.2.2 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||||
|
"relpath 0.0.1",
|
||||||
|
"rm 0.0.1",
|
||||||
|
"rmdir 0.0.1",
|
||||||
|
"seq 0.0.1",
|
||||||
|
"shred 0.0.1",
|
||||||
|
"shuf 0.0.1",
|
||||||
|
"sleep 0.0.1",
|
||||||
|
"sort 0.0.1",
|
||||||
|
"split 0.0.1",
|
||||||
|
"stat 0.0.1",
|
||||||
|
"stdbuf 0.0.1",
|
||||||
|
"sum 0.0.1",
|
||||||
|
"sync 0.0.1",
|
||||||
|
"tac 0.0.1",
|
||||||
|
"tail 0.0.1",
|
||||||
|
"tee 0.0.1",
|
||||||
|
"tempdir 0.3.5 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||||
|
"test 0.0.1",
|
||||||
|
"time 0.1.38 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||||
|
"timeout 0.0.1",
|
||||||
|
"touch 0.0.1",
|
||||||
|
"tr 0.0.1",
|
||||||
|
"true 0.0.1",
|
||||||
|
"truncate 0.0.1",
|
||||||
|
"tsort 0.0.1",
|
||||||
|
"tty 0.0.1",
|
||||||
|
"uname 0.0.1",
|
||||||
|
"unexpand 0.0.1",
|
||||||
|
"unindent 0.1.2 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||||
|
"uniq 0.0.1",
|
||||||
|
"unix_socket 0.5.0 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||||
|
"unlink 0.0.1",
|
||||||
|
"uptime 0.0.1",
|
||||||
|
"users 0.0.1",
|
||||||
|
"uucore 0.0.1",
|
||||||
|
"wc 0.0.1",
|
||||||
|
"who 0.0.1",
|
||||||
|
"whoami 0.0.1",
|
||||||
|
"yes 0.0.1",
|
||||||
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "vec_map"
|
name = "vec_map"
|
||||||
version = "0.8.0"
|
version = "0.8.0"
|
||||||
|
|
|
@ -109,7 +109,7 @@ fn parse_opts(args: Vec<String>) -> getopts::Matches {
|
||||||
// TODO implement flag
|
// TODO implement flag
|
||||||
.optflag("C", "compare", "(unimplemented) compare each pair of source and destination\n \
|
.optflag("C", "compare", "(unimplemented) compare each pair of source and destination\n \
|
||||||
files, and in some cases, do not modify the destination at all")
|
files, and in some cases, do not modify the destination at all")
|
||||||
.optflag("d", "directory", "treat all arguments as directory names\n \
|
.optflag("d", "directory", "treat all arguments as directory names.\n \
|
||||||
create all components of the specified directories")
|
create all components of the specified directories")
|
||||||
// TODO implement flag
|
// TODO implement flag
|
||||||
.optflag("D", "", "(unimplemented) create all leading components of DEST except the\n \
|
.optflag("D", "", "(unimplemented) create all leading components of DEST except the\n \
|
||||||
|
@ -286,6 +286,13 @@ fn directory(paths: &[PathBuf], b: Behaviour) -> i32 {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// Test if the path is a a new file path that can be
|
||||||
|
/// created immediately
|
||||||
|
fn is_new_file_path(path: &Path) -> bool {
|
||||||
|
path.is_file() ||
|
||||||
|
! path.exists() && path.parent().map(|p| p.is_dir()).unwrap_or(true)
|
||||||
|
}
|
||||||
|
|
||||||
/// Perform an install, given a list of paths and behaviour.
|
/// Perform an install, given a list of paths and behaviour.
|
||||||
///
|
///
|
||||||
/// Returns an integer intended as a program return code.
|
/// Returns an integer intended as a program return code.
|
||||||
|
@ -296,9 +303,13 @@ fn standard(paths: &[PathBuf], b: Behaviour) -> i32 {
|
||||||
1
|
1
|
||||||
} else {
|
} else {
|
||||||
let sources = &paths[0..paths.len() - 1];
|
let sources = &paths[0..paths.len() - 1];
|
||||||
let target_directory = &paths[paths.len() - 1];
|
let target = &paths[paths.len() - 1];
|
||||||
|
|
||||||
copy_files_into_dir(sources, target_directory, &b)
|
if (target.is_file() || is_new_file_path(target)) && sources.len() == 1 {
|
||||||
|
copy_file_to_file(&sources[0], target, &b)
|
||||||
|
} else {
|
||||||
|
copy_files_into_dir(sources, target, &b)
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -338,6 +349,20 @@ fn copy_files_into_dir(files: &[PathBuf], target_dir: &PathBuf, b: &Behaviour) -
|
||||||
if all_successful { 0 } else { 1 }
|
if all_successful { 0 } else { 1 }
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// Copy a file to another file.
|
||||||
|
///
|
||||||
|
/// Prints verbose information and error messages.
|
||||||
|
/// Returns an integer intended as a program return code.
|
||||||
|
///
|
||||||
|
/// # Parameters
|
||||||
|
///
|
||||||
|
/// _file_ must exist as a non-directory.
|
||||||
|
/// _target_ must be a non-directory
|
||||||
|
///
|
||||||
|
fn copy_file_to_file(file: &PathBuf, target: &PathBuf, b: &Behaviour) -> i32 {
|
||||||
|
if copy(file, &target, b).is_err() { 1 } else { 0 }
|
||||||
|
}
|
||||||
|
|
||||||
/// Copy one file to a new location, changing metadata.
|
/// Copy one file to a new location, changing metadata.
|
||||||
///
|
///
|
||||||
/// # Parameters
|
/// # Parameters
|
||||||
|
|
|
@ -28,6 +28,20 @@ fn test_install_basic() {
|
||||||
assert!(at.file_exists(&format!("{}/{}", dir, file2)));
|
assert!(at.file_exists(&format!("{}/{}", dir, file2)));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn test_install_failing_not_dir() {
|
||||||
|
let (at, mut ucmd) = at_and_ucmd!();
|
||||||
|
let file1 = "test_install_target_dir_file_a1";
|
||||||
|
let file2 = "test_install_target_dir_file_a2";
|
||||||
|
let file3 = "test_install_target_dir_file_a3";
|
||||||
|
|
||||||
|
at.touch(file1);
|
||||||
|
at.touch(file2);
|
||||||
|
at.touch(file3);
|
||||||
|
assert!(ucmd.arg(file1).arg(file2).arg(file3)
|
||||||
|
.fails().stderr.contains("not a directory"));
|
||||||
|
}
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
fn test_install_unimplemented_arg() {
|
fn test_install_unimplemented_arg() {
|
||||||
let (at, mut ucmd) = at_and_ucmd!();
|
let (at, mut ucmd) = at_and_ucmd!();
|
||||||
|
@ -136,3 +150,47 @@ fn test_install_mode_directories() {
|
||||||
let permissions = at.metadata(component).permissions();
|
let permissions = at.metadata(component).permissions();
|
||||||
assert_eq!(0o040333 as u32, PermissionsExt::mode(&permissions));
|
assert_eq!(0o040333 as u32, PermissionsExt::mode(&permissions));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn test_install_target_file() {
|
||||||
|
let (at, mut ucmd) = at_and_ucmd!();
|
||||||
|
let file1 = "test_install_target_file_file_i1";
|
||||||
|
let file2 = "test_install_target_file_file_i2";
|
||||||
|
|
||||||
|
at.touch(file1);
|
||||||
|
at.touch(file2);
|
||||||
|
ucmd.arg(file1).arg(file2).succeeds().no_stderr();
|
||||||
|
|
||||||
|
assert!(at.file_exists(file1));
|
||||||
|
assert!(at.file_exists(file2));
|
||||||
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn test_install_target_new_file() {
|
||||||
|
let (at, mut ucmd) = at_and_ucmd!();
|
||||||
|
let file = "test_install_target_new_filer_file_j";
|
||||||
|
let dir = "test_install_target_new_file_dir_j";
|
||||||
|
|
||||||
|
at.touch(file);
|
||||||
|
at.mkdir(dir);
|
||||||
|
ucmd.arg(file).arg(format!("{}/{}", dir, file)).succeeds().no_stderr();
|
||||||
|
|
||||||
|
assert!(at.file_exists(file));
|
||||||
|
assert!(at.file_exists(&format!("{}/{}", dir, file)));
|
||||||
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn test_install_target_new_file_failing_nonexistent_parent() {
|
||||||
|
let (at, mut ucmd) = at_and_ucmd!();
|
||||||
|
let file1 = "test_install_target_new_file_failing_file_k1";
|
||||||
|
let file2 = "test_install_target_new_file_failing_file_k2";
|
||||||
|
let dir = "test_install_target_new_file_failing_dir_k";
|
||||||
|
|
||||||
|
at.touch(file1);
|
||||||
|
|
||||||
|
let err = ucmd.arg(file1).arg(format!("{}/{}", dir, file2))
|
||||||
|
.fails().stderr;
|
||||||
|
|
||||||
|
assert!(err.contains("not a directory"))
|
||||||
|
}
|
||||||
|
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue