From ff6d1ad04ec889cbd31ff6a1574dc7d26f462e5f Mon Sep 17 00:00:00 2001 From: mengnankkkk Date: Mon, 8 Sep 2025 11:54:14 +0800 Subject: [PATCH 1/9] feat(remove_:add --dryrun --- libra/src/command/remove.rs | 37 +++++++ libra/tests/command/remove_test.rs | 151 +++++++++++++++++++++++++++++ 2 files changed, 188 insertions(+) diff --git a/libra/src/command/remove.rs b/libra/src/command/remove.rs index 5a600dd1d..6fe2e481c 100644 --- a/libra/src/command/remove.rs +++ b/libra/src/command/remove.rs @@ -23,6 +23,9 @@ pub struct RemoveArgs { /// force removal, skip validation #[clap(short, long)] pub force: bool, + /// show what would be removed without actually removing + #[clap(long)] + pub dry_run: bool, } pub fn execute(args: RemoveArgs) -> Result<(), GitError> { @@ -44,6 +47,40 @@ pub fn execute(args: RemoveArgs) -> Result<(), GitError> { return Err(GitError::CustomError(error_msg)); } + // In dry-run mode, show what would be removed but don't actually remove anything + if args.dry_run { + println!("Would remove the following:"); + for path_str in args.pathspec.iter() { + let path = PathBuf::from(path_str); + let path_wd = path.to_workdir().to_string_or_panic(); + + if dirs.contains(path_str) { + // dir - find all files in this directory that are tracked + let entries = index.tracked_entries(0); + for entry in entries.iter() { + if entry.name.starts_with(&path_wd) { + println!("rm '{}'", entry.name.bright_yellow()); + } + } + if !args.cached { + println!("rm directory '{}'", path_str.bright_yellow()); + } + } else { + // file + if args.force { + if index.tracked(&path_wd, 0) { + println!("rm '{}'", path_wd.bright_yellow()); + } else if !args.cached && path.exists() { + println!("rm '{}'", path_wd.bright_yellow()); + } + } else if index.tracked(&path_wd, 0) { + println!("rm '{}'", path_wd.bright_yellow()); + } + } + } + return Ok(()); + } + for path_str in args.pathspec.iter() { let path = PathBuf::from(path_str); let path_wd = path.to_workdir().to_string_or_panic(); diff --git a/libra/tests/command/remove_test.rs b/libra/tests/command/remove_test.rs index c2d2d5889..8d7b38e51 100644 --- a/libra/tests/command/remove_test.rs +++ b/libra/tests/command/remove_test.rs @@ -2,6 +2,7 @@ use super::*; use std::fs; use std::io::Write; use std::path::PathBuf; +use mercury::internal::index::Index; /// Helper function to create a file with content. fn create_file(path: &str, content: &str) -> PathBuf { @@ -45,6 +46,7 @@ async fn test_remove_single_file() { cached: false, recursive: false, force: false, + dry_run: false, }; remove::execute(args).unwrap(); @@ -110,6 +112,7 @@ async fn test_remove_cached() { cached: true, recursive: false, force: false, + dry_run: false, }; remove::execute(args).unwrap(); @@ -164,6 +167,7 @@ async fn test_remove_directory_recursive() { cached: false, recursive: true, force: false, + dry_run: false, }; remove::execute(args).unwrap(); @@ -236,6 +240,7 @@ async fn test_remove_directory_without_recursive() { cached: false, recursive: false, force: false, + dry_run: false, }; assert!( remove::execute(args).is_err(), @@ -271,6 +276,7 @@ async fn test_remove_untracked_file() { cached: false, recursive: false, force: false, + dry_run: false, }; let result = remove::execute(args); assert!( @@ -318,6 +324,7 @@ async fn test_remove_modified_file() { cached: false, recursive: false, force: false, + dry_run: false, }; remove::execute(args).unwrap(); @@ -385,6 +392,7 @@ async fn test_remove_multiple_files() { cached: false, recursive: false, force: false, + dry_run: false, }; remove::execute(args).unwrap(); // Verify the specified files were removed @@ -392,3 +400,146 @@ async fn test_remove_multiple_files() { assert!(file2.exists(), "File 2 should still exist"); assert!(!file3.exists(), "File 3 should be removed"); } + +#[tokio::test] +#[serial] +/// Tests the --dry-run flag which shows what would be removed without actually removing anything +async fn test_remove_dry_run() { + let test_dir = tempdir().unwrap(); + test::setup_with_new_libra_in(test_dir.path()).await; + let _guard = test::ChangeDirGuard::new(test_dir.path()); + + // Create multiple files + let file1 = create_file("file1.txt", "File 1 content"); + let file2 = create_file("file2.txt", "File 2 content"); + let file3 = create_file("subdir/file3.txt", "File 3 content"); + + // Add all files to the index + add::execute(AddArgs { + pathspec: vec![String::from(".")], + all: false, + update: false, + refresh: false, + verbose: false, + dry_run: false, + ignore_errors: false, + }) + .await; + + // Make sure all files exist before dry-run + assert!(file1.exists(), "File 1 should exist before dry-run"); + assert!(file2.exists(), "File 2 should exist before dry-run"); + assert!(file3.exists(), "File 3 should exist before dry-run"); + + // Run rm with --dry-run flag + let args = RemoveArgs { + pathspec: vec![String::from("file1.txt"), String::from("file2.txt")], + cached: false, + recursive: false, + force: false, + dry_run: true, + }; + remove::execute(args).unwrap(); + + // Verify that no files were actually removed + assert!(file1.exists(), "File 1 should still exist after dry-run"); + assert!(file2.exists(), "File 2 should still exist after dry-run"); + assert!(file3.exists(), "File 3 should still exist after dry-run"); + + // Verify files are still in the index + let idx_file = libra::utils::path::index(); + let index = Index::load(&idx_file).unwrap(); + assert!(index.tracked("file1.txt", 0), "File 1 should still be tracked"); + assert!(index.tracked("file2.txt", 0), "File 2 should still be tracked"); + assert!(index.tracked("subdir/file3.txt", 0), "File 3 should still be tracked"); +} + +#[tokio::test] +#[serial] +/// Tests --dry-run with --cached flag +async fn test_remove_dry_run_cached() { + let test_dir = tempdir().unwrap(); + test::setup_with_new_libra_in(test_dir.path()).await; + let _guard = test::ChangeDirGuard::new(test_dir.path()); + + // Create a file and add it to index + let file_path = create_file("test_file.txt", "Test content"); + + add::execute(AddArgs { + pathspec: vec![String::from("test_file.txt")], + all: false, + update: false, + refresh: false, + verbose: false, + dry_run: false, + ignore_errors: false, + }) + .await; + + // Run rm with --dry-run and --cached flags + let args = RemoveArgs { + pathspec: vec![String::from("test_file.txt")], + cached: true, + recursive: false, + force: false, + dry_run: true, + }; + remove::execute(args).unwrap(); + + // Verify the file still exists in both filesystem and index + assert!(file_path.exists(), "File should still exist in filesystem"); + + let idx_file = libra::utils::path::index(); + let index = Index::load(&idx_file).unwrap(); + assert!(index.tracked("test_file.txt", 0), "File should still be tracked in index"); +} + +#[tokio::test] +#[serial] +/// Tests --dry-run with recursive directory removal +async fn test_remove_dry_run_recursive() { + let test_dir = tempdir().unwrap(); + test::setup_with_new_libra_in(test_dir.path()).await; + let _guard = test::ChangeDirGuard::new(test_dir.path()); + + // Create a directory with files + let file1 = create_file("test_dir/file1.txt", "File 1 content"); + let file2 = create_file("test_dir/file2.txt", "File 2 content"); + let file3 = create_file("test_dir/subdir/file3.txt", "File 3 content"); + + // Add all files to the index + add::execute(AddArgs { + pathspec: vec![String::from("test_dir")], + all: false, + update: false, + refresh: false, + verbose: false, + dry_run: false, + ignore_errors: false, + }) + .await; + + // Run rm with --dry-run and --recursive flags + let args = RemoveArgs { + pathspec: vec![String::from("test_dir")], + cached: false, + recursive: true, + force: false, + dry_run: true, + }; + remove::execute(args).unwrap(); + + // Verify that no files or directories were actually removed + assert!(file1.exists(), "File 1 should still exist after dry-run"); + assert!(file2.exists(), "File 2 should still exist after dry-run"); + assert!(file3.exists(), "File 3 should still exist after dry-run"); + assert!(PathBuf::from("test_dir").exists(), "Directory should still exist"); + assert!(PathBuf::from("test_dir/subdir").exists(), "Subdirectory should still exist"); + + // Verify files are still in the index + let idx_file = libra::utils::path::index(); + let index = Index::load(&idx_file).unwrap(); + assert!(index.tracked("test_dir/file1.txt", 0), "File 1 should still be tracked"); + assert!(index.tracked("test_dir/file2.txt", 0), "File 2 should still be tracked"); + assert!(index.tracked("test_dir/subdir/file3.txt", 0), "File 3 should still be tracked"); +} From a5902ce9cd135b3d12b895574d550a0bffe2540f Mon Sep 17 00:00:00 2001 From: mengnankkkk Date: Mon, 8 Sep 2025 17:47:09 +0800 Subject: [PATCH 2/9] feat:ci bug --- aria/contents/docs/libra/command/rm/index.mdx | 46 +++++++++++++++++ libra/examples/test_dry_run.rs | 49 +++++++++++++++++++ libra/src/command/remove.rs | 12 +++-- libra/tests/command/remove_test.rs | 49 +++++++++++++------ 4 files changed, 137 insertions(+), 19 deletions(-) create mode 100644 libra/examples/test_dry_run.rs diff --git a/aria/contents/docs/libra/command/rm/index.mdx b/aria/contents/docs/libra/command/rm/index.mdx index 69694fbe8..b4ee63e3d 100644 --- a/aria/contents/docs/libra/command/rm/index.mdx +++ b/aria/contents/docs/libra/command/rm/index.mdx @@ -24,8 +24,54 @@ that.) - `--cached`
Use this option to unstage and remove paths only from the index. Working tree files, whether modified or not, will be left alone. +- `--dry-run`
+ Don't actually remove any files; instead just show if they exist in the index and would otherwise be removed by the command. This option is useful for previewing what files would be removed before actually executing the removal. It works with all other options (`--cached`, `--recursive`, `--force`) to show exactly what the actual command would do. + - `-r`, `--recursive`
Allow recursive removal when a leading directory name is given. - `-f`, `--force`
Force removal even if the specified paths are not tracked. This skips validation checks and deletes files or directories regardless of their index status. + +### Examples + +#### Basic Usage +```bash +# Remove a file from both index and working tree +libra rm file.txt + +# Remove multiple files +libra rm file1.txt file2.txt +``` + +#### Using --cached +```bash +# Remove from index only, keep in working tree +libra rm --cached file.txt +``` + +#### Using --dry-run +```bash +# Preview what would be removed +libra rm --dry-run file1.txt file2.txt + +# Preview cached removal +libra rm --dry-run --cached *.txt + +# Preview recursive directory removal +libra rm --dry-run -r old_directory/ +``` + +The `--dry-run` option will output something like: +``` +Would remove the following: +rm 'file1.txt' +rm 'file2.txt' +``` + +#### Recursive Removal +```bash +# Remove entire directory recursively (preview first!) +libra rm --dry-run -r directory/ +libra rm -r directory/ +``` diff --git a/libra/examples/test_dry_run.rs b/libra/examples/test_dry_run.rs new file mode 100644 index 000000000..ff44601a1 --- /dev/null +++ b/libra/examples/test_dry_run.rs @@ -0,0 +1,49 @@ +// 验证 rm --dry-run 功能的简单测试程序 +use libra::command::remove::{execute, RemoveArgs}; +use std::fs; +use std::io::Write; + +fn main() { + println!("正在测试 libra rm --dry-run 功能..."); + + // 创建测试文件 + fs::create_dir_all("test_files").unwrap(); + let mut file1 = fs::File::create("test_files/file1.txt").unwrap(); + file1.write_all(b"Test content 1").unwrap(); + + let mut file2 = fs::File::create("test_files/file2.txt").unwrap(); + file2.write_all(b"Test content 2").unwrap(); + + println!("创建了测试文件: test_files/file1.txt, test_files/file2.txt"); + + // 测试 dry-run 功能 + let args = RemoveArgs { + pathspec: vec!["test_files/file1.txt".to_string(), "test_files/file2.txt".to_string()], + cached: false, + recursive: false, + force: true, // 使用 force 模式避免需要 git 仓库 + dry_run: true, + }; + + println!("\n执行: libra rm --dry-run --force test_files/file1.txt test_files/file2.txt"); + + match execute(args) { + Ok(_) => { + println!("✓ dry-run 执行成功!"); + + // 验证文件仍然存在 + if fs::metadata("test_files/file1.txt").is_ok() && fs::metadata("test_files/file2.txt").is_ok() { + println!(" 文件在 dry-run 后仍然存在(正确行为)"); + } else { + println!(" 错误:dry-run 不应该实际删除文件"); + } + } + Err(e) => { + println!("✗ dry-run 执行失败: {:?}", e); + } + } + + // 清理测试文件 + let _ = fs::remove_dir_all("test_files"); + println!("\n测试完成,已清理测试文件"); +} diff --git a/libra/src/command/remove.rs b/libra/src/command/remove.rs index 6fe2e481c..e28bb3180 100644 --- a/libra/src/command/remove.rs +++ b/libra/src/command/remove.rs @@ -57,8 +57,14 @@ pub fn execute(args: RemoveArgs) -> Result<(), GitError> { if dirs.contains(path_str) { // dir - find all files in this directory that are tracked let entries = index.tracked_entries(0); + // Ensure path_wd ends with a separator for correct directory matching + let dir_prefix = if path_wd.ends_with(std::path::MAIN_SEPARATOR) { + path_wd.clone() + } else { + format!("{}{}", path_wd, std::path::MAIN_SEPARATOR) + }; for entry in entries.iter() { - if entry.name.starts_with(&path_wd) { + if entry.name.starts_with(&dir_prefix) { println!("rm '{}'", entry.name.bright_yellow()); } } @@ -68,9 +74,7 @@ pub fn execute(args: RemoveArgs) -> Result<(), GitError> { } else { // file if args.force { - if index.tracked(&path_wd, 0) { - println!("rm '{}'", path_wd.bright_yellow()); - } else if !args.cached && path.exists() { + if index.tracked(&path_wd, 0) || (!args.cached && path.exists()) { println!("rm '{}'", path_wd.bright_yellow()); } } else if index.tracked(&path_wd, 0) { diff --git a/libra/tests/command/remove_test.rs b/libra/tests/command/remove_test.rs index 8d7b38e51..3cceac223 100644 --- a/libra/tests/command/remove_test.rs +++ b/libra/tests/command/remove_test.rs @@ -446,12 +446,22 @@ async fn test_remove_dry_run() { assert!(file2.exists(), "File 2 should still exist after dry-run"); assert!(file3.exists(), "File 3 should still exist after dry-run"); - // Verify files are still in the index - let idx_file = libra::utils::path::index(); - let index = Index::load(&idx_file).unwrap(); - assert!(index.tracked("file1.txt", 0), "File 1 should still be tracked"); - assert!(index.tracked("file2.txt", 0), "File 2 should still be tracked"); - assert!(index.tracked("subdir/file3.txt", 0), "File 3 should still be tracked"); + // Verify files are still in the index by checking they don't appear as deleted + let changes = changes_to_be_staged(); + assert!( + !changes + .deleted + .iter() + .any(|x| x.to_str().unwrap() == "file1.txt"), + "File 1 should not appear as deleted" + ); + assert!( + !changes + .deleted + .iter() + .any(|x| x.to_str().unwrap() == "file2.txt"), + "File 2 should not appear as deleted" + ); } #[tokio::test] @@ -489,9 +499,15 @@ async fn test_remove_dry_run_cached() { // Verify the file still exists in both filesystem and index assert!(file_path.exists(), "File should still exist in filesystem"); - let idx_file = libra::utils::path::index(); - let index = Index::load(&idx_file).unwrap(); - assert!(index.tracked("test_file.txt", 0), "File should still be tracked in index"); + // Verify file doesn't appear as deleted in changes + let changes = changes_to_be_staged(); + assert!( + !changes + .deleted + .iter() + .any(|x| x.to_str().unwrap() == "test_file.txt"), + "File should not appear as deleted" + ); } #[tokio::test] @@ -536,10 +552,13 @@ async fn test_remove_dry_run_recursive() { assert!(PathBuf::from("test_dir").exists(), "Directory should still exist"); assert!(PathBuf::from("test_dir/subdir").exists(), "Subdirectory should still exist"); - // Verify files are still in the index - let idx_file = libra::utils::path::index(); - let index = Index::load(&idx_file).unwrap(); - assert!(index.tracked("test_dir/file1.txt", 0), "File 1 should still be tracked"); - assert!(index.tracked("test_dir/file2.txt", 0), "File 2 should still be tracked"); - assert!(index.tracked("test_dir/subdir/file3.txt", 0), "File 3 should still be tracked"); + // Verify files are still tracked by checking they don't appear as deleted + let changes = changes_to_be_staged(); + assert!( + !changes + .deleted + .iter() + .any(|x| x.to_str().unwrap().starts_with("test_dir/")), + "No files in test_dir should appear as deleted" + ); } From 01a841475754d73f2722fd7eeb342f5d9b8450f2 Mon Sep 17 00:00:00 2001 From: mengnankkkk Date: Mon, 8 Sep 2025 19:15:01 +0800 Subject: [PATCH 3/9] fix: ci bug2 --- libra/src/command/remove.rs | 12 ++++++------ libra/tests/command/remove_test.rs | 1 - 2 files changed, 6 insertions(+), 7 deletions(-) diff --git a/libra/src/command/remove.rs b/libra/src/command/remove.rs index e28bb3180..7cb3a96ed 100644 --- a/libra/src/command/remove.rs +++ b/libra/src/command/remove.rs @@ -57,12 +57,12 @@ pub fn execute(args: RemoveArgs) -> Result<(), GitError> { if dirs.contains(path_str) { // dir - find all files in this directory that are tracked let entries = index.tracked_entries(0); - // Ensure path_wd ends with a separator for correct directory matching - let dir_prefix = if path_wd.ends_with(std::path::MAIN_SEPARATOR) { - path_wd.clone() - } else { - format!("{}{}", path_wd, std::path::MAIN_SEPARATOR) - }; + // Use PathBuf for proper cross-platform path handling + let mut dir_prefix_path = PathBuf::from(&path_wd); + if !path_wd.is_empty() { + dir_prefix_path.push(""); // This ensures a trailing separator + } + let dir_prefix = dir_prefix_path.to_string_or_panic(); for entry in entries.iter() { if entry.name.starts_with(&dir_prefix) { println!("rm '{}'", entry.name.bright_yellow()); diff --git a/libra/tests/command/remove_test.rs b/libra/tests/command/remove_test.rs index 3cceac223..76d0bf57a 100644 --- a/libra/tests/command/remove_test.rs +++ b/libra/tests/command/remove_test.rs @@ -2,7 +2,6 @@ use super::*; use std::fs; use std::io::Write; use std::path::PathBuf; -use mercury::internal::index::Index; /// Helper function to create a file with content. fn create_file(path: &str, content: &str) -> PathBuf { From 2f89815aa78a847b093da65414744618858708a0 Mon Sep 17 00:00:00 2001 From: mengnankkkk Date: Mon, 8 Sep 2025 19:21:22 +0800 Subject: [PATCH 4/9] fix: chinese instead en --- libra/examples/test_dry_run.rs | 28 ++++++++++++++-------------- 1 file changed, 14 insertions(+), 14 deletions(-) diff --git a/libra/examples/test_dry_run.rs b/libra/examples/test_dry_run.rs index ff44601a1..1e5607ed2 100644 --- a/libra/examples/test_dry_run.rs +++ b/libra/examples/test_dry_run.rs @@ -1,12 +1,12 @@ -// 验证 rm --dry-run 功能的简单测试程序 +// Simple test program to verify rm --dry-run functionality use libra::command::remove::{execute, RemoveArgs}; use std::fs; use std::io::Write; fn main() { - println!("正在测试 libra rm --dry-run 功能..."); + println!("Testing libra rm --dry-run functionality..."); - // 创建测试文件 + // Create test files fs::create_dir_all("test_files").unwrap(); let mut file1 = fs::File::create("test_files/file1.txt").unwrap(); file1.write_all(b"Test content 1").unwrap(); @@ -14,36 +14,36 @@ fn main() { let mut file2 = fs::File::create("test_files/file2.txt").unwrap(); file2.write_all(b"Test content 2").unwrap(); - println!("创建了测试文件: test_files/file1.txt, test_files/file2.txt"); + println!("Created test files: test_files/file1.txt, test_files/file2.txt"); - // 测试 dry-run 功能 + // Test dry-run functionality let args = RemoveArgs { pathspec: vec!["test_files/file1.txt".to_string(), "test_files/file2.txt".to_string()], cached: false, recursive: false, - force: true, // 使用 force 模式避免需要 git 仓库 + force: true, // Use force mode to avoid requiring git repository dry_run: true, }; - println!("\n执行: libra rm --dry-run --force test_files/file1.txt test_files/file2.txt"); + println!("\nExecuting: libra rm --dry-run --force test_files/file1.txt test_files/file2.txt"); match execute(args) { Ok(_) => { - println!("✓ dry-run 执行成功!"); + println!("✓ dry-run executed successfully!"); - // 验证文件仍然存在 + // Verify files still exist if fs::metadata("test_files/file1.txt").is_ok() && fs::metadata("test_files/file2.txt").is_ok() { - println!(" 文件在 dry-run 后仍然存在(正确行为)"); + println!(" Files still exist after dry-run (correct behavior)"); } else { - println!(" 错误:dry-run 不应该实际删除文件"); + println!(" Error: dry-run should not actually delete files"); } } Err(e) => { - println!("✗ dry-run 执行失败: {:?}", e); + println!("✗ dry-run execution failed: {:?}", e); } } - // 清理测试文件 + // Clean up test files let _ = fs::remove_dir_all("test_files"); - println!("\n测试完成,已清理测试文件"); + println!("\nTest completed, test files cleaned up"); } From a36e67bba1d181743a03fa69d7f858ddec068516 Mon Sep 17 00:00:00 2001 From: mengnankkkk Date: Mon, 8 Sep 2025 20:39:52 +0800 Subject: [PATCH 5/9] Update remove.rs --- libra/src/command/remove.rs | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/libra/src/command/remove.rs b/libra/src/command/remove.rs index 7cb3a96ed..89712bb48 100644 --- a/libra/src/command/remove.rs +++ b/libra/src/command/remove.rs @@ -57,12 +57,12 @@ pub fn execute(args: RemoveArgs) -> Result<(), GitError> { if dirs.contains(path_str) { // dir - find all files in this directory that are tracked let entries = index.tracked_entries(0); - // Use PathBuf for proper cross-platform path handling - let mut dir_prefix_path = PathBuf::from(&path_wd); - if !path_wd.is_empty() { - dir_prefix_path.push(""); // This ensures a trailing separator - } - let dir_prefix = dir_prefix_path.to_string_or_panic(); + // Create directory prefix with proper path separator for cross-platform compatibility + let dir_prefix = if path_wd.is_empty() { + String::new() + } else { + format!("{}{}", path_wd, std::path::MAIN_SEPARATOR) + }; for entry in entries.iter() { if entry.name.starts_with(&dir_prefix) { println!("rm '{}'", entry.name.bright_yellow()); From 795256935f60230e05a480c87dbbce9b67c84cf2 Mon Sep 17 00:00:00 2001 From: zhou yong kang Date: Mon, 8 Sep 2025 20:46:38 +0800 Subject: [PATCH 6/9] Update libra/src/command/remove.rs Co-authored-by: Copilot <175728472+Copilot@users.noreply.github.com> Signed-off-by: zhou yong kang --- libra/src/command/remove.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/libra/src/command/remove.rs b/libra/src/command/remove.rs index 89712bb48..b84adce13 100644 --- a/libra/src/command/remove.rs +++ b/libra/src/command/remove.rs @@ -61,7 +61,7 @@ pub fn execute(args: RemoveArgs) -> Result<(), GitError> { let dir_prefix = if path_wd.is_empty() { String::new() } else { - format!("{}{}", path_wd, std::path::MAIN_SEPARATOR) + PathBuf::from(&path_wd).join("").to_string_or_panic() }; for entry in entries.iter() { if entry.name.starts_with(&dir_prefix) { From a668026efa65ff995d18d2804b0e9a885dab951b Mon Sep 17 00:00:00 2001 From: mengnankkkk Date: Mon, 8 Sep 2025 20:51:16 +0800 Subject: [PATCH 7/9] =?UTF-8?q?fix=EF=BC=9Aadd=20post-processing?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- libra/examples/test_dry_run.rs | 28 +++++++++++++++++----------- 1 file changed, 17 insertions(+), 11 deletions(-) diff --git a/libra/examples/test_dry_run.rs b/libra/examples/test_dry_run.rs index 1e5607ed2..34554f69d 100644 --- a/libra/examples/test_dry_run.rs +++ b/libra/examples/test_dry_run.rs @@ -2,37 +2,44 @@ use libra::command::remove::{execute, RemoveArgs}; use std::fs; use std::io::Write; +use tempfile::TempDir; fn main() { println!("Testing libra rm --dry-run functionality..."); - // Create test files - fs::create_dir_all("test_files").unwrap(); - let mut file1 = fs::File::create("test_files/file1.txt").unwrap(); + // Create a temporary directory for test files + let temp_dir = TempDir::new().expect("Failed to create temporary directory"); + let temp_path = temp_dir.path(); + + // Create test files in the temporary directory + let file1_path = temp_path.join("file1.txt"); + let file2_path = temp_path.join("file2.txt"); + + let mut file1 = fs::File::create(&file1_path).unwrap(); file1.write_all(b"Test content 1").unwrap(); - let mut file2 = fs::File::create("test_files/file2.txt").unwrap(); + let mut file2 = fs::File::create(&file2_path).unwrap(); file2.write_all(b"Test content 2").unwrap(); - println!("Created test files: test_files/file1.txt, test_files/file2.txt"); + println!("Created test files in temporary directory: {:?}", temp_path); // Test dry-run functionality let args = RemoveArgs { - pathspec: vec!["test_files/file1.txt".to_string(), "test_files/file2.txt".to_string()], + pathspec: vec![file1_path.to_string_lossy().to_string(), file2_path.to_string_lossy().to_string()], cached: false, recursive: false, force: true, // Use force mode to avoid requiring git repository dry_run: true, }; - println!("\nExecuting: libra rm --dry-run --force test_files/file1.txt test_files/file2.txt"); + println!("\nExecuting: libra rm --dry-run --force on test files"); match execute(args) { Ok(_) => { println!("✓ dry-run executed successfully!"); // Verify files still exist - if fs::metadata("test_files/file1.txt").is_ok() && fs::metadata("test_files/file2.txt").is_ok() { + if file1_path.exists() && file2_path.exists() { println!(" Files still exist after dry-run (correct behavior)"); } else { println!(" Error: dry-run should not actually delete files"); @@ -43,7 +50,6 @@ fn main() { } } - // Clean up test files - let _ = fs::remove_dir_all("test_files"); - println!("\nTest completed, test files cleaned up"); + println!("\nTest completed, temporary directory will be automatically cleaned up"); + // The temporary directory will be automatically cleaned up when temp_dir goes out of scope } From 1a0c5f0fac705fb21c68d25ad5a8349cea1ae35a Mon Sep 17 00:00:00 2001 From: zhou yong kang Date: Mon, 8 Sep 2025 20:59:04 +0800 Subject: [PATCH 8/9] Update libra/src/command/remove.rs Co-authored-by: Copilot <175728472+Copilot@users.noreply.github.com> Signed-off-by: zhou yong kang --- libra/src/command/remove.rs | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/libra/src/command/remove.rs b/libra/src/command/remove.rs index b84adce13..50da6c7e3 100644 --- a/libra/src/command/remove.rs +++ b/libra/src/command/remove.rs @@ -60,8 +60,10 @@ pub fn execute(args: RemoveArgs) -> Result<(), GitError> { // Create directory prefix with proper path separator for cross-platform compatibility let dir_prefix = if path_wd.is_empty() { String::new() + } else if path_wd.ends_with(std::path::MAIN_SEPARATOR) { + path_wd.clone() } else { - PathBuf::from(&path_wd).join("").to_string_or_panic() + format!("{}{}", path_wd, std::path::MAIN_SEPARATOR) }; for entry in entries.iter() { if entry.name.starts_with(&dir_prefix) { From 21e9343aef745123a7a67df000dd17039d41b92b Mon Sep 17 00:00:00 2001 From: mengnankkkk Date: Mon, 8 Sep 2025 21:01:38 +0800 Subject: [PATCH 9/9] fix: add consistent --- libra/src/command/remove.rs | 9 ++++++++- 1 file changed, 8 insertions(+), 1 deletion(-) diff --git a/libra/src/command/remove.rs b/libra/src/command/remove.rs index b84adce13..9292821fa 100644 --- a/libra/src/command/remove.rs +++ b/libra/src/command/remove.rs @@ -74,10 +74,17 @@ pub fn execute(args: RemoveArgs) -> Result<(), GitError> { } else { // file if args.force { - if index.tracked(&path_wd, 0) || (!args.cached && path.exists()) { + // In force mode: always try to remove (matches actual execution logic) + // - If tracked, would be removed from index + // - If not tracked, would still be processed (and filesystem file deleted if not cached) + if index.tracked(&path_wd, 0) { + println!("rm '{}'", path_wd.bright_yellow()); + } else { + // Even untracked files are processed in force mode println!("rm '{}'", path_wd.bright_yellow()); } } else if index.tracked(&path_wd, 0) { + // Normal mode - only show if tracked (matches actual execution logic) println!("rm '{}'", path_wd.bright_yellow()); } }