commit 4e12cd97c02ae412c5a247dfaffa22ad58dd98b4 from: Stefan Sperling date: Tue Jan 25 22:48:26 2022 UTC make 'got rm' behave like rm(1) for paths found missing on disk ok millert@ commit - 4362cf9c24c2ad037cda602ae688bef54869f793 commit + 4e12cd97c02ae412c5a247dfaffa22ad58dd98b4 blob - 1ba9101f0a27f2b37c7a01f8d02db40c5c95a9fa blob + eaafde8411ebca559ac74b4970f3a9ee755e26b9 --- got/got.1 +++ got/got.1 @@ -1259,7 +1259,10 @@ The options for are as follows: .Bl -tag -width Ds .It Fl f -Perform the operation even if a file contains local modifications. +Perform the operation even if a file contains local modifications, +and do not raise an error if a specified +.Ar path +does not exist on disk. .It Fl k Keep affected files on disk. .It Fl R blob - f551f71ac97f147d51b0c32e92dce6513394be94 blob + 16b939dba60d2210e6c75b2ffbb51a4b1f8d608a --- got/got.c +++ got/got.c @@ -6981,6 +6981,7 @@ cmd_remove(int argc, char *argv[]) struct got_pathlist_head paths; struct got_pathlist_entry *pe; int ch, delete_local_mods = 0, can_recurse = 0, keep_on_disk = 0, i; + int ignore_missing_paths = 0; TAILQ_INIT(&paths); @@ -6988,6 +6989,7 @@ cmd_remove(int argc, char *argv[]) switch (ch) { case 'f': delete_local_mods = 1; + ignore_missing_paths = 1; break; case 'k': keep_on_disk = 1; @@ -7002,6 +7004,7 @@ cmd_remove(int argc, char *argv[]) delete_local_mods = 1; break; case GOT_STATUS_MISSING: + ignore_missing_paths = 1; break; default: errx(1, "invalid status code '%c'", @@ -7084,7 +7087,7 @@ cmd_remove(int argc, char *argv[]) error = got_worktree_schedule_delete(worktree, &paths, delete_local_mods, status_codes, print_remove_status, NULL, - repo, keep_on_disk); + repo, keep_on_disk, ignore_missing_paths); done: if (repo) { const struct got_error *close_err = got_repo_close(repo); blob - 2402196b13cc52e6f489e9fd9d985074fa7dcbfa blob + 2a33834a903f96a6f0206be4636193177a5f443d --- include/got_worktree.h +++ include/got_worktree.h @@ -194,7 +194,7 @@ const struct got_error *got_worktree_schedule_add(stru const struct got_error * got_worktree_schedule_delete(struct got_worktree *, struct got_pathlist_head *, int, const char *, - got_worktree_delete_cb, void *, struct got_repository *, int); + got_worktree_delete_cb, void *, struct got_repository *, int, int); /* A callback function which is used to select or reject a patch. */ typedef const struct got_error *(*got_worktree_patch_cb)(int *, void *, blob - 03ed920c296768d481852c8a28ea3acae1f379e1 blob + 7b9584f4e628041adfb0cb7d180a875fa9e5a922 --- lib/worktree.c +++ lib/worktree.c @@ -3954,6 +3954,7 @@ struct schedule_deletion_args { struct got_repository *repo; int delete_local_mods; int keep_on_disk; + int ignore_missing_paths; const char *status_codes; }; @@ -3968,6 +3969,12 @@ schedule_for_deletion(void *arg, unsigned char status, struct got_fileindex_entry *ie = NULL; struct stat sb; char *ondisk_path; + + if (status == GOT_STATUS_NONEXISTENT) { + if (a->ignore_missing_paths) + return NULL; + return got_error_set_errno(ENOENT, relpath); + } ie = got_fileindex_entry_get(a->fileindex, relpath, strlen(relpath)); if (ie == NULL) @@ -4018,6 +4025,10 @@ schedule_for_deletion(void *arg, unsigned char status, err = got_error_path(relpath, GOT_ERR_FILE_MODIFIED); goto done; } + if (status == GOT_STATUS_MISSING && !a->ignore_missing_paths) { + err = got_error_set_errno(ENOENT, relpath); + goto done; + } if (status != GOT_STATUS_MODIFY && status != GOT_STATUS_MISSING) { err = got_error_path(relpath, GOT_ERR_FILE_STATUS); @@ -4073,7 +4084,7 @@ got_worktree_schedule_delete(struct got_worktree *work struct got_pathlist_head *paths, int delete_local_mods, const char *status_codes, got_worktree_delete_cb progress_cb, void *progress_arg, - struct got_repository *repo, int keep_on_disk) + struct got_repository *repo, int keep_on_disk, int ignore_missing_paths) { struct got_fileindex *fileindex = NULL; char *fileindex_path = NULL; @@ -4096,6 +4107,7 @@ got_worktree_schedule_delete(struct got_worktree *work sda.repo = repo; sda.delete_local_mods = delete_local_mods; sda.keep_on_disk = keep_on_disk; + sda.ignore_missing_paths = ignore_missing_paths; sda.status_codes = status_codes; TAILQ_FOREACH(pe, paths, entry) { blob - cab753f3139225f2518ae82f6ba928625c46e9e6 blob + 8b4c659ae6120bad5862072ea9cc9fd55eaaaccd --- regress/cmdline/rm.sh +++ regress/cmdline/rm.sh @@ -159,8 +159,51 @@ test_rm_and_add_elsewhere() { return 1 fi + (cd $testroot/wt && got rm alpha > $testroot/stdout 2> $testroot/stderr) + ret="$?" + if [ "$ret" == "0" ]; then + echo "got rm command succeeded unexpectedly" >&2 + diff -u $testroot/stderr.expected $testroot/stderr + test_done "$testroot" "1" + return 1 + fi + + echo -n '' > $testroot/stdout.expected + cmp -s $testroot/stdout.expected $testroot/stdout + ret="$?" + if [ "$ret" != "0" ]; then + diff -u $testroot/stdout.expected $testroot/stdout + test_done "$testroot" "$ret" + return 1 + fi + + echo "got: alpha: No such file or directory" \ + > $testroot/stderr.expected + cmp -s $testroot/stderr.expected $testroot/stderr + ret="$?" + if [ "$ret" != "0" ]; then + diff -u $testroot/stderr.expected $testroot/stderr + test_done "$testroot" "$ret" + return 1 + fi + + (cd $testroot/wt && got rm -f alpha > $testroot/stdout) + ret="$?" + if [ "$ret" != "0" ]; then + echo "got rm command failed unexpectedly" >&2 + diff -u $testroot/stderr.expected $testroot/stderr + test_done "$testroot" "$ret" + return 1 + fi + echo 'D alpha' > $testroot/stdout.expected - (cd $testroot/wt && got rm alpha > $testroot/stdout) + cmp -s $testroot/stdout.expected $testroot/stdout + ret="$?" + if [ "$ret" != "0" ]; then + diff -u $testroot/stdout.expected $testroot/stdout + test_done "$testroot" "$ret" + return 1 + fi cmp -s $testroot/stdout.expected $testroot/stdout ret="$?" @@ -507,10 +550,82 @@ test_rm_status_code() { ret="$?" if [ "$ret" != "0" ]; then diff -u $testroot/stdout.expected $testroot/stdout + test_done "$testroot" "1" + return 1 + fi + + test_done "$testroot" "$ret" +} + +test_rm_nonexistent_directory() { + local testroot=`test_init rm_nonexistent_directory` + + got checkout $testroot/repo $testroot/wt > /dev/null + ret="$?" + if [ "$ret" != "0" ]; then + test_done "$testroot" "$ret" + return 1 + fi + + rm -r $testroot/wt/epsilon + + (cd $testroot/wt && got rm epsilon > $testroot/stdout \ + 2> $testroot/stderr) + ret="$?" + if [ "$ret" == "0" ]; then + echo "got rm command succeeded unexpectedly" >&2 + diff -u $testroot/stderr.expected $testroot/stderr test_done "$testroot" "1" return 1 fi + echo -n '' > $testroot/stdout.expected + cmp -s $testroot/stdout.expected $testroot/stdout + ret="$?" + if [ "$ret" != "0" ]; then + diff -u $testroot/stdout.expected $testroot/stdout + test_done "$testroot" "$ret" + return 1 + fi + + echo "got: epsilon: No such file or directory" \ + > $testroot/stderr.expected + cmp -s $testroot/stderr.expected $testroot/stderr + ret="$?" + if [ "$ret" != "0" ]; then + diff -u $testroot/stderr.expected $testroot/stderr + test_done "$testroot" "$ret" + return 1 + fi + + (cd $testroot/wt && got rm -f epsilon > $testroot/stdout \ + 2> $testroot/stderr) + ret="$?" + if [ "$ret" != "0" ]; then + echo "got rm command failed unexpectedly" >&2 + diff -u $testroot/stderr.expected $testroot/stderr + test_done "$testroot" "$ret" + return 1 + fi + + echo -n '' > $testroot/stdout.expected + cmp -s $testroot/stdout.expected $testroot/stdout + ret="$?" + if [ "$ret" != "0" ]; then + diff -u $testroot/stdout.expected $testroot/stdout + test_done "$testroot" "$ret" + return 1 + fi + + echo -n '' > $testroot/stderr.expected + cmp -s $testroot/stderr.expected $testroot/stderr + ret="$?" + if [ "$ret" != "0" ]; then + diff -u $testroot/stderr.expected $testroot/stderr + test_done "$testroot" "$ret" + return 1 + fi + test_done "$testroot" "$ret" } @@ -525,3 +640,4 @@ run_test test_rm_directory_keep_files run_test test_rm_subtree run_test test_rm_symlink run_test test_rm_status_code +run_test test_rm_nonexistent_directory