From 9566b2e3f862addf959e64ee945e7affd818b954 Mon Sep 17 00:00:00 2001 From: Valentin Date: Tue, 16 Dec 2025 17:21:39 +0700 Subject: [PATCH] Add output of files to be included to archive if verbose flag passed (#62) * Add output of files to be included to archive if verbose flag passed * Add test for verbose output * Fix test * Fix style --- src/uu/tar/src/operations/create.rs | 43 +++++++++++++++++++++++++---- tests/by-util/test_tar.rs | 25 +++++++++++++++++ 2 files changed, 62 insertions(+), 6 deletions(-) diff --git a/src/uu/tar/src/operations/create.rs b/src/uu/tar/src/operations/create.rs index 022cb62..4b296f8 100644 --- a/src/uu/tar/src/operations/create.rs +++ b/src/uu/tar/src/operations/create.rs @@ -4,8 +4,9 @@ // file that was distributed with this source code. use crate::errors::TarError; -use std::fs::File; -use std::path::Path; +use std::collections::VecDeque; +use std::fs::{self, File}; +use std::path::{self, Path, PathBuf}; use tar::Builder; use uucore::error::UResult; @@ -42,15 +43,27 @@ pub fn create_archive(archive_path: &Path, files: &[&Path], verbose: bool) -> UR // Add each file or directory to the archive for &path in files { - if verbose { - println!("{}", path.display()); - } - // Check if path exists if !path.exists() { return Err(TarError::FileNotFound(path.display().to_string()).into()); } + if verbose { + let to_print = get_tree(path)? + .iter() + .map(|p| (p.is_dir(), p.display().to_string())) + .map(|(is_dir, path)| { + if is_dir { + format!("{}{}", path, path::MAIN_SEPARATOR) + } else { + path + } + }) + .collect::>() + .join("\n"); + println!("{to_print}"); + } + // If it's a directory, recursively add all contents if path.is_dir() { builder.append_dir_all(path, path).map_err(|e| { @@ -79,3 +92,21 @@ pub fn create_archive(archive_path: &Path, files: &[&Path], verbose: bool) -> UR Ok(()) } + +fn get_tree(path: &Path) -> Result, std::io::Error> { + let mut paths = Vec::new(); + let mut stack = VecDeque::new(); + stack.push_back(path.to_path_buf()); + + while let Some(current) = stack.pop_back() { + paths.push(current.clone()); + if current.is_dir() { + for entry in fs::read_dir(current)? { + let child = entry?.path(); + stack.push_back(child); + } + } + } + + Ok(paths) +} diff --git a/tests/by-util/test_tar.rs b/tests/by-util/test_tar.rs index 741f2b4..b876c54 100644 --- a/tests/by-util/test_tar.rs +++ b/tests/by-util/test_tar.rs @@ -3,6 +3,8 @@ // For the full copyright and license information, please view the LICENSE // file that was distributed with this source code. +use std::path; + use uutests::{at_and_ucmd, new_ucmd}; // Basic CLI Tests @@ -30,6 +32,29 @@ fn test_version() { .stdout_contains("tar"); } +#[test] +fn test_verbose() { + let (at, mut ucmd) = at_and_ucmd!(); + + let separator = path::MAIN_SEPARATOR; + let dir1_path = "dir1"; + let dir2_path = format!("{dir1_path}{separator}dir2"); + let file1_path = format!("{dir1_path}{separator}file1.txt"); + let file2_path = format!("{dir2_path}{separator}file2.txt"); + + at.mkdir(dir1_path); + at.mkdir(&dir2_path); + at.write(&file1_path, "test content 1"); + at.write(&file2_path, "test content 2"); + + ucmd.args(&["-cvf", "archive.tar", dir1_path]) + .succeeds() + .stdout_contains(dir1_path) + .stdout_contains(dir2_path) + .stdout_contains(file1_path) + .stdout_contains(file2_path); +} + // Create operation tests #[test]