add --follow-symlinks flag into compress command with test case

Signed-off-by: tommady <tommady@users.noreply.github.com>
This commit is contained in:
tommady 2025-04-13 04:41:47 +00:00
parent 1e52f6c24d
commit 3633764004
No known key found for this signature in database
GPG Key ID: 175B664929DF2F2F
6 changed files with 61 additions and 16 deletions

View File

@ -104,6 +104,7 @@ pub fn build_archive_from_paths<W>(
writer: W,
file_visibility_policy: FileVisibilityPolicy,
quiet: bool,
follow_symlinks: bool,
) -> crate::Result<W>
where
W: Write,
@ -144,7 +145,7 @@ where
if path.is_dir() {
builder.append_dir(path, path)?;
} else if path.is_symlink() {
} else if path.is_symlink() && !follow_symlinks {
let target_path = path.read_link()?;
let mut header = tar::Header::new_gnu();

View File

@ -170,6 +170,7 @@ pub fn build_archive_from_paths<W>(
writer: W,
file_visibility_policy: FileVisibilityPolicy,
quiet: bool,
follow_symlinks: bool,
) -> crate::Result<W>
where
W: Write + Seek,
@ -247,7 +248,7 @@ where
if metadata.is_dir() {
writer.add_directory(entry_name, options)?;
} else if path.is_symlink() {
} else if path.is_symlink() && !follow_symlinks {
let target_path = path.read_link()?;
let target_name = target_path.to_str().ok_or_else(|| {
FinalError::with_title("Zip requires that all directories names are valid UTF-8")

View File

@ -81,6 +81,10 @@ pub enum Subcommand {
/// conflicts with --level and --fast
#[arg(long, group = "compression-level")]
slow: bool,
/// Tar and Zip specific: add the symlink target to the archive instead of the symlink itself
#[arg(long)]
follow_symlinks: bool,
},
/// Decompresses one or more files, optionally into another folder
#[command(visible_alias = "d")]
@ -201,6 +205,7 @@ mod tests {
level: None,
fast: false,
slow: false,
follow_symlinks: false,
},
..mock_cli_args()
}
@ -214,6 +219,7 @@ mod tests {
level: None,
fast: false,
slow: false,
follow_symlinks: false,
},
..mock_cli_args()
}
@ -227,6 +233,7 @@ mod tests {
level: None,
fast: false,
slow: false,
follow_symlinks: false,
},
..mock_cli_args()
}
@ -251,6 +258,7 @@ mod tests {
level: None,
fast: false,
slow: false,
follow_symlinks: false,
},
format: Some("tar.gz".into()),
..mock_cli_args()

View File

@ -31,6 +31,7 @@ pub fn compress_files(
output_file: fs::File,
output_path: &Path,
quiet: bool,
follow_symlinks: bool,
question_policy: QuestionPolicy,
file_visibility_policy: FileVisibilityPolicy,
level: Option<i16>,
@ -108,7 +109,14 @@ pub fn compress_files(
io::copy(&mut reader, &mut writer)?;
}
Tar => {
archive::tar::build_archive_from_paths(&files, output_path, &mut writer, file_visibility_policy, quiet)?;
archive::tar::build_archive_from_paths(
&files,
output_path,
&mut writer,
file_visibility_policy,
quiet,
follow_symlinks,
)?;
writer.flush()?;
}
Zip => {
@ -131,6 +139,7 @@ pub fn compress_files(
&mut vec_buffer,
file_visibility_policy,
quiet,
follow_symlinks,
)?;
vec_buffer.rewind()?;
io::copy(&mut vec_buffer, &mut writer)?;

View File

@ -67,6 +67,7 @@ pub fn run(
level,
fast,
slow,
follow_symlinks,
} => {
// After cleaning, if there are no input files left, exit
if files.is_empty() {
@ -109,6 +110,7 @@ pub fn run(
output_file,
&output_path,
args.quiet,
follow_symlinks,
question_policy,
file_visibility_policy,
level,

View File

@ -482,11 +482,11 @@ fn symlink_pack_and_unpack(
return Ok(());
}
let temp_dir = tempdir().unwrap();
let temp_dir = tempdir()?;
let root_path = temp_dir.path();
let src_files_path = root_path.join("src_files");
fs::create_dir_all(&src_files_path).unwrap();
fs::create_dir_all(&src_files_path)?;
let mut files_path = ["file1.txt", "file2.txt", "file3.txt", "file4.txt", "file5.txt"]
.into_iter()
@ -499,13 +499,13 @@ fn symlink_pack_and_unpack(
.collect::<Vec<_>>();
let dest_files_path = root_path.join("dest_files");
fs::create_dir_all(&dest_files_path).unwrap();
fs::create_dir_all(&dest_files_path)?;
let symlink_path = src_files_path.join(Path::new("symlink"));
#[cfg(unix)]
std::os::unix::fs::symlink(&files_path[0], &symlink_path).unwrap();
std::os::unix::fs::symlink(&files_path[0], &symlink_path)?;
#[cfg(windows)]
std::os::windows::fs::symlink_file(&files_path[0], &symlink_path).unwrap();
std::os::windows::fs::symlink_file(&files_path[0], &symlink_path)?;
files_path.push(symlink_path);
@ -513,6 +513,34 @@ fn symlink_pack_and_unpack(
crate::utils::cargo_bin()
.arg("compress")
.args(files_path.clone())
.arg(archive)
.assert()
.success();
crate::utils::cargo_bin()
.arg("decompress")
.arg(archive)
.arg("-d")
.arg(&dest_files_path)
.assert()
.success();
assert_same_directory(&src_files_path, &dest_files_path, false);
// check the symlink stand still
for f in dest_files_path.as_path().read_dir()? {
let f = f?;
if f.file_name() == "symlink" {
assert!(f.file_type()?.is_symlink())
}
}
fs::remove_file(archive)?;
fs::remove_dir_all(&dest_files_path)?;
crate::utils::cargo_bin()
.arg("compress")
.arg("--follow-symlinks")
.args(files_path)
.arg(archive)
.assert()
@ -526,13 +554,9 @@ fn symlink_pack_and_unpack(
.assert()
.success();
println!("archive: {:?}", archive);
assert_same_directory(&src_files_path, &dest_files_path, false);
// check the symlink stand still
for f in dest_files_path.as_path().read_dir().unwrap() {
let f = f.unwrap();
if f.file_name() == "symlink" {
assert!(f.file_type().unwrap().is_symlink())
}
// check there is no symlinks
for f in dest_files_path.as_path().read_dir()? {
let f = f?;
assert!(!f.file_type().unwrap().is_symlink())
}
}