mirror of
https://github.com/uutils/coreutils
synced 2024-12-18 17:14:42 +00:00
Merge pull request #915 from jerenept/master
Added some functionality and tests to cp
This commit is contained in:
commit
56b840c48e
4 changed files with 81 additions and 15 deletions
53
src/cp/cp.rs
53
src/cp/cp.rs
|
@ -35,6 +35,9 @@ pub fn uumain(args: Vec<String>) -> i32 {
|
||||||
|
|
||||||
opts.optflag("h", "help", "display this help and exit");
|
opts.optflag("h", "help", "display this help and exit");
|
||||||
opts.optflag("", "version", "output version information and exit");
|
opts.optflag("", "version", "output version information and exit");
|
||||||
|
opts.optopt("t", "target-directory", "copy all SOURCE arguments into DIRECTORY", "DEST");
|
||||||
|
opts.optflag("T", "no-target-directory", "Treat DEST as a regular file and not a directory");
|
||||||
|
opts.optflag("v", "verbose", "explicitly state what is being done");
|
||||||
|
|
||||||
let matches = match opts.parse(&args[1..]) {
|
let matches = match opts.parse(&args[1..]) {
|
||||||
Ok(m) => m,
|
Ok(m) => m,
|
||||||
|
@ -43,7 +46,6 @@ pub fn uumain(args: Vec<String>) -> i32 {
|
||||||
panic!()
|
panic!()
|
||||||
},
|
},
|
||||||
};
|
};
|
||||||
|
|
||||||
let usage = opts.usage("Copy SOURCE to DEST, or multiple SOURCE(s) to DIRECTORY.");
|
let usage = opts.usage("Copy SOURCE to DEST, or multiple SOURCE(s) to DIRECTORY.");
|
||||||
let mode = if matches.opt_present("version") {
|
let mode = if matches.opt_present("version") {
|
||||||
Mode::Version
|
Mode::Version
|
||||||
|
@ -70,29 +72,47 @@ fn help(usage: &str) {
|
||||||
let msg = format!("{0} {1}\n\n\
|
let msg = format!("{0} {1}\n\n\
|
||||||
Usage: {0} SOURCE DEST\n \
|
Usage: {0} SOURCE DEST\n \
|
||||||
or: {0} SOURCE... DIRECTORY\n \
|
or: {0} SOURCE... DIRECTORY\n \
|
||||||
or: {0} -t DIRECTORY SOURCE\n\
|
or: {0} -t DIRECTORY SOURCE...\n\
|
||||||
\n\
|
\n\
|
||||||
{2}", NAME, VERSION, usage);
|
{2}", NAME, VERSION, usage);
|
||||||
println!("{}", msg);
|
println!("{}", msg);
|
||||||
}
|
}
|
||||||
|
|
||||||
fn copy(matches: getopts::Matches) {
|
fn copy(matches: getopts::Matches) {
|
||||||
|
let verbose = matches.opt_present("verbose");
|
||||||
let sources: Vec<String> = if matches.free.is_empty() {
|
let sources: Vec<String> = if matches.free.is_empty() {
|
||||||
show_error!("Missing SOURCE argument. Try --help.");
|
show_error!("Missing SOURCE or DEST argument. Try --help.");
|
||||||
panic!()
|
panic!()
|
||||||
} else {
|
} else if !matches.opt_present("target-directory") {
|
||||||
// All but the last argument:
|
|
||||||
matches.free[..matches.free.len() - 1].iter().cloned().collect()
|
matches.free[..matches.free.len() - 1].iter().cloned().collect()
|
||||||
|
} else {
|
||||||
|
matches.free.iter().cloned().collect()
|
||||||
};
|
};
|
||||||
let dest = if matches.free.len() < 2 {
|
let dest_str = if matches.opt_present("target-directory") {
|
||||||
|
matches.opt_str("target-directory").expect("Option -t/--target-directory requires an argument")
|
||||||
|
} else {
|
||||||
|
matches.free[matches.free.len() - 1].clone()
|
||||||
|
};
|
||||||
|
let dest = if matches.free.len() < 2 && !matches.opt_present("target-directory") {
|
||||||
show_error!("Missing DEST argument. Try --help.");
|
show_error!("Missing DEST argument. Try --help.");
|
||||||
panic!()
|
panic!()
|
||||||
} else {
|
} else {
|
||||||
// Only the last argument:
|
//the argument to the -t/--target-directory= options
|
||||||
Path::new(&matches.free[matches.free.len() - 1])
|
let path = Path::new(&dest_str);
|
||||||
|
if !path.is_dir() && matches.opt_present("target-directory") {
|
||||||
|
show_error!("Target {} is not a directory", matches.opt_str("target-directory").unwrap());
|
||||||
|
panic!()
|
||||||
|
} else {
|
||||||
|
path
|
||||||
|
}
|
||||||
|
|
||||||
};
|
};
|
||||||
|
|
||||||
assert!(sources.len() >= 1);
|
assert!(sources.len() >= 1);
|
||||||
|
if matches.opt_present("no-target-directory") && dest.is_dir() {
|
||||||
|
show_error!("Can't overwrite directory {} with non-directory", dest.display());
|
||||||
|
panic!()
|
||||||
|
}
|
||||||
|
|
||||||
if sources.len() == 1 {
|
if sources.len() == 1 {
|
||||||
let source = Path::new(&sources[0]);
|
let source = Path::new(&sources[0]);
|
||||||
|
@ -112,8 +132,14 @@ fn copy(matches: getopts::Matches) {
|
||||||
dest.display());
|
dest.display());
|
||||||
panic!();
|
panic!();
|
||||||
}
|
}
|
||||||
|
let mut full_dest = dest.to_path_buf();
|
||||||
if let Err(err) = fs::copy(source, dest) {
|
if dest.is_dir() {
|
||||||
|
full_dest.push(source.file_name().unwrap()); //the destination path is the destination
|
||||||
|
} // directory + the file name we're copying
|
||||||
|
if verbose {
|
||||||
|
println!("{} -> {}", source.display(), full_dest.display());
|
||||||
|
}
|
||||||
|
if let Err(err) = fs::copy(source, full_dest) {
|
||||||
show_error!("{}", err);
|
show_error!("{}", err);
|
||||||
panic!();
|
panic!();
|
||||||
}
|
}
|
||||||
|
@ -122,7 +148,6 @@ fn copy(matches: getopts::Matches) {
|
||||||
show_error!("TARGET must be a directory");
|
show_error!("TARGET must be a directory");
|
||||||
panic!();
|
panic!();
|
||||||
}
|
}
|
||||||
|
|
||||||
for src in &sources {
|
for src in &sources {
|
||||||
let source = Path::new(&src);
|
let source = Path::new(&src);
|
||||||
|
|
||||||
|
@ -133,9 +158,11 @@ fn copy(matches: getopts::Matches) {
|
||||||
|
|
||||||
let mut full_dest = dest.to_path_buf();
|
let mut full_dest = dest.to_path_buf();
|
||||||
|
|
||||||
full_dest.push(source.to_str().unwrap());
|
full_dest.push(source.file_name().unwrap());
|
||||||
|
|
||||||
println!("{}", full_dest.display());
|
if verbose {
|
||||||
|
println!("{} -> {}", source.display(), full_dest.display());
|
||||||
|
}
|
||||||
|
|
||||||
let io_result = fs::copy(source, full_dest);
|
let io_result = fs::copy(source, full_dest);
|
||||||
|
|
||||||
|
|
0
tests/fixtures/cp/hello_dir/hello.txt
vendored
Normal file
0
tests/fixtures/cp/hello_dir/hello.txt
vendored
Normal file
1
tests/fixtures/cp/hello_dir_with_file/hello_world.txt
vendored
Normal file
1
tests/fixtures/cp/hello_dir_with_file/hello_world.txt
vendored
Normal file
|
@ -0,0 +1 @@
|
||||||
|
Hello, World!
|
|
@ -1,9 +1,11 @@
|
||||||
use common::util::*;
|
use common::util::*;
|
||||||
|
|
||||||
static UTIL_NAME: &'static str = "cp";
|
static UTIL_NAME: &'static str = "cp";
|
||||||
|
|
||||||
static TEST_HELLO_WORLD_SOURCE: &'static str = "hello_world.txt";
|
static TEST_HELLO_WORLD_SOURCE: &'static str = "hello_world.txt";
|
||||||
static TEST_HELLO_WORLD_DEST: &'static str = "copy_of_hello_world.txt";
|
static TEST_HELLO_WORLD_DEST: &'static str = "copy_of_hello_world.txt";
|
||||||
|
static TEST_COPY_TO_FOLDER: &'static str = "hello_dir/";
|
||||||
|
static TEST_COPY_TO_FOLDER_FILE: &'static str = "hello_dir/hello_world.txt";
|
||||||
|
static TEST_COPY_FROM_FOLDER_FILE: &'static str = "hello_dir_with_file/hello_world.txt";
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
fn test_cp_cp() {
|
fn test_cp_cp() {
|
||||||
|
@ -15,8 +17,44 @@ fn test_cp_cp() {
|
||||||
|
|
||||||
// Check that the exit code represents a successful copy.
|
// Check that the exit code represents a successful copy.
|
||||||
let exit_success = result.success;
|
let exit_success = result.success;
|
||||||
assert_eq!(exit_success, true);
|
assert!(exit_success);
|
||||||
|
|
||||||
// Check the content of the destination file that was copied.
|
// Check the content of the destination file that was copied.
|
||||||
assert_eq!(at.read(TEST_HELLO_WORLD_DEST), "Hello, World!\n");
|
assert_eq!(at.read(TEST_HELLO_WORLD_DEST), "Hello, World!\n");
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn test_cp_with_dirs_t() {
|
||||||
|
let ts = TestSet::new(UTIL_NAME);
|
||||||
|
let at = &ts.fixtures;
|
||||||
|
|
||||||
|
//using -t option
|
||||||
|
let result_to_dir_t = ts.util_cmd()
|
||||||
|
.arg("-t")
|
||||||
|
.arg(TEST_COPY_TO_FOLDER)
|
||||||
|
.arg(TEST_HELLO_WORLD_SOURCE)
|
||||||
|
.run();
|
||||||
|
assert!(result_to_dir_t.success);
|
||||||
|
assert_eq!(at.read(TEST_COPY_TO_FOLDER_FILE), "Hello, World!\n");
|
||||||
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn test_cp_with_dirs() {
|
||||||
|
let ts = TestSet::new(UTIL_NAME);
|
||||||
|
let at = &ts.fixtures;
|
||||||
|
|
||||||
|
//using -t option
|
||||||
|
let result_to_dir = ts.util_cmd()
|
||||||
|
.arg(TEST_HELLO_WORLD_SOURCE)
|
||||||
|
.arg(TEST_COPY_TO_FOLDER)
|
||||||
|
.run();
|
||||||
|
assert!(result_to_dir.success);
|
||||||
|
assert_eq!(at.read(TEST_COPY_TO_FOLDER_FILE), "Hello, World!\n");
|
||||||
|
|
||||||
|
let result_from_dir = ts.util_cmd()
|
||||||
|
.arg(TEST_COPY_FROM_FOLDER_FILE)
|
||||||
|
.arg(TEST_HELLO_WORLD_DEST)
|
||||||
|
.run();
|
||||||
|
assert!(result_from_dir.success);
|
||||||
|
assert_eq!(at.read(TEST_HELLO_WORLD_DEST), "Hello, World!\n");
|
||||||
|
}
|
Loading…
Reference in a new issue