This commit is contained in:
Jasha Sommer-Simpson 2025-05-07 01:29:35 +00:00 committed by GitHub
commit 32b74841c2
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
2 changed files with 110 additions and 3 deletions

View File

@ -48,6 +48,8 @@ impl Command for UCp {
)
.switch("progress", "display a progress bar", Some('p'))
.switch("no-clobber", "do not overwrite an existing file", Some('n'))
.switch("link", "hard-link files instead of copying", Some('l'))
.switch("symbolic-link", "make symbolic links instead of copying", Some('s'))
.named(
"preserve",
SyntaxShape::List(Box::new(SyntaxShape::String)),
@ -89,6 +91,21 @@ impl Command for UCp {
example: "cp -u myfile newfile",
result: None,
},
Example {
description: "",
example: "cp -s a b",
result: None,
},
Example {
description: "",
example: "cp -l a b",
result: None,
},
Example {
description: "",
example: "cp -r -l a b",
result: None,
},
Example {
description: "Copy file preserving mode and timestamps attributes",
example: "cp --preserve [ mode timestamps ] myfile newfile",
@ -115,10 +132,19 @@ impl Command for UCp {
_input: PipelineData,
) -> Result<PipelineData, ShellError> {
let interactive = call.has_flag(engine_state, stack, "interactive")?;
let (update, copy_mode) = if call.has_flag(engine_state, stack, "update")? {
(UpdateMode::ReplaceIfOlder, CopyMode::Update)
let update = if call.has_flag(engine_state, stack, "update")? {
UpdateMode::ReplaceIfOlder
} else {
(UpdateMode::ReplaceAll, CopyMode::Copy)
UpdateMode::ReplaceAll
};
let copy_mode = if call.has_flag(engine_state, stack, "link")? {
CopyMode::Link
} else if call.has_flag(engine_state, stack, "symbolic-link")? {
CopyMode::SymLink
} else if call.has_flag(engine_state, stack, "update")? {
CopyMode::Update
} else {
CopyMode::Copy
};
let force = call.has_flag(engine_state, stack, "force")?;

View File

@ -46,6 +46,48 @@ fn copies_a_file_impl(progress: bool) {
});
}
#[test]
fn copies_a_file_with_hardlink() {
copies_a_file_with_hardlink_impl(false);
copies_a_file_with_hardlink_impl(true);
}
fn copies_a_file_with_hardlink_impl(progress: bool) {
Playground::setup("ucp_test_1-hardlink", |dirs, _| {
let test_file = dirs.formats().join("sample.ini");
let progress_flag = if progress { "-p" } else { "" };
// Get the hash of the file content to check integrity after copy.
let first_hash = get_file_hash(test_file.display());
nu!(
cwd: dirs.root(),
"cp -l {} `{}` ucp_test_1-hardlink/sample.ini",
progress_flag,
test_file.display()
);
assert!(dirs.test().join("sample.ini").exists());
// Get the hash of the copied file content to check against first_hash.
let after_cp_hash = get_file_hash(dirs.test().join("sample.ini").display());
assert_eq!(first_hash, after_cp_hash);
// Modify file 1 by appending a line
nu!(
cwd: dirs.root(),
"echo 'new line' | save `{}` --append",
test_file.display()
);
// We will compare the contents of file 1 and file 2.
// Since we're using a hardlink, the updated hashes should be the same.
let first_hash_modified = get_file_hash(test_file.display());
assert_ne!(first_hash, first_hash_modified);
let after_cp_hash_modified = get_file_hash(dirs.test().join("sample.ini").display());
assert_eq!(first_hash_modified, after_cp_hash_modified);
});
}
#[test]
fn copies_the_file_inside_directory_if_path_to_copy_is_directory() {
copies_the_file_inside_directory_if_path_to_copy_is_directory_impl(false);
@ -729,6 +771,45 @@ fn test_cp_recurse() {
});
}
#[test]
fn test_cp_recurse_with_hardlink_flag() {
Playground::setup("ucp_test_22-hardlink", |dirs, sandbox| {
// Create the relevant target directories
sandbox.mkdir(TEST_COPY_FROM_FOLDER);
sandbox.mkdir(TEST_COPY_TO_FOLDER_NEW);
let src = dirs
.fixtures
.join("cp")
.join(TEST_COPY_FROM_FOLDER)
.join(TEST_COPY_FROM_FOLDER_FILE);
let src_hash = get_file_hash(src.display());
// Start test
nu!(
cwd: dirs.root(),
"cp -r -l {} ucp_test_22-hardlink/{}",
TEST_COPY_FROM_FOLDER,
TEST_COPY_TO_FOLDER_NEW,
);
let after_cp_hash = get_file_hash(dirs.test().join(TEST_COPY_TO_FOLDER_NEW_FILE).display());
assert_eq!(src_hash, after_cp_hash);
// Modify file 1 by appending a line
nu!(
cwd: dirs.root(),
"echo 'new line' | save `{}` --append",
src.display()
);
// We will compare the contents of file 1 and file 2.
// Since we're using a hardlink, the updated hashes should be the same.
let src_hash_modified = get_file_hash(src.display());
assert_ne!(src_hash, src_hash_modified);
let after_cp_hash_modified =
get_file_hash(dirs.test().join(TEST_COPY_TO_FOLDER_NEW_FILE).display());
assert_eq!(src_hash_modified, after_cp_hash_modified);
});
}
#[test]
fn test_cp_with_dirs() {
Playground::setup("ucp_test_23", |dirs, sandbox| {