1
Fork 0
mirror of https://github.com/RGBCube/uutils-coreutils synced 2025-07-27 19:17:43 +00:00

Merge pull request #1118 from KeenS/install-file

install: allow to install a file to a file
This commit is contained in:
Alex Lyon 2017-12-27 02:28:05 -08:00 committed by GitHub
commit 0fdf2df3eb
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
3 changed files with 203 additions and 113 deletions

227
Cargo.lock generated
View file

@ -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]]
name = "advapi32-sys"
version = "0.2.0"
@ -435,6 +326,9 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
[[package]]
name = "false"
version = "0.0.1"
dependencies = [
"uucore 0.0.1",
]
[[package]]
name = "filetime"
@ -593,7 +487,7 @@ dependencies = [
name = "join"
version = "0.0.1"
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",
]
@ -1170,6 +1064,7 @@ version = "0.0.1"
dependencies = [
"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)",
"glob 0.2.11 (registry+https://github.com/rust-lang/crates.io-index)",
"libstdbuf 0.0.1",
"uucore 0.0.1",
]
@ -1345,6 +1240,9 @@ dependencies = [
[[package]]
name = "true"
version = "0.0.1"
dependencies = [
"uucore 0.0.1",
]
[[package]]
name = "truncate"
@ -1467,6 +1365,115 @@ dependencies = [
"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]]
name = "vec_map"
version = "0.8.0"

View file

@ -109,7 +109,7 @@ fn parse_opts(args: Vec<String>) -> getopts::Matches {
// TODO implement flag
.optflag("C", "compare", "(unimplemented) compare each pair of source and destination\n \
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")
// TODO implement flag
.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.
///
/// Returns an integer intended as a program return code.
@ -296,9 +303,13 @@ fn standard(paths: &[PathBuf], b: Behaviour) -> i32 {
1
} else {
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 }
}
/// 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.
///
/// # Parameters

View file

@ -28,6 +28,20 @@ fn test_install_basic() {
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]
fn test_install_unimplemented_arg() {
let (at, mut ucmd) = at_and_ucmd!();
@ -136,3 +150,47 @@ fn test_install_mode_directories() {
let permissions = at.metadata(component).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"))
}