make 'got update' remove empty directories
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118
diff --git a/lib/worktree.c b/lib/worktree.c
index 6e5fc2e..82b3c5f 100644
--- a/lib/worktree.c
+++ b/lib/worktree.c
@@ -18,6 +18,7 @@
#include <sys/limits.h>
#include <sys/queue.h>
+#include <stddef.h>
#include <string.h>
#include <stdio.h>
#include <stdlib.h>
@@ -747,22 +748,29 @@ static const struct got_error *
collect_missing_file(void *args, struct got_fileindex_entry *entry)
{
struct collect_missing_entry_args *a = args;
- char *name;
+ char *start, *end;
+ ptrdiff_t len;
struct got_tree_entry *te;
int found = 0;
- if (a->path_prefix[0] == '\0' && strchr(entry->path, '/') != NULL)
- return NULL;
if (a->path_prefix[0] != '\0' &&
strncmp(a->path_prefix, entry->path, strlen(a->path_prefix)) != 0)
return NULL;
- name = basename(entry->path);
- if (name == NULL)
- return got_error_from_errno();
+ start = entry->path + strlen(a->path_prefix);
+ while (start[0] == '/')
+ start++;
+ end = strchr(start, '/');
+ if (end == NULL) {
+ end = strchr(start, '\0');
+ if (end == NULL)
+ return got_error(GOT_ERR_BAD_PATH);
+ }
+ len = end - start;
SIMPLEQ_FOREACH(te, &a->entries->head, entry) {
- if (strcmp(te->name, name) == 0) {
+ if (strncmp(start, te->name, len) == 0 &&
+ te->name[len] == '\0') {
found = 1;
break;
}
@@ -816,6 +824,11 @@ remove_missing_files(struct got_worktree *worktree, const char *path,
if (unlink(ondisk_path) == -1)
err = got_error_from_errno();
+ else {
+ char *parent = dirname(ondisk_path);
+ if (rmdir(parent) == -1 && errno != ENOTEMPTY)
+ err = got_error_from_errno();
+ }
free(ondisk_path);
if (err)
break;
diff --git a/regress/cmdline/update.sh b/regress/cmdline/update.sh
index 67fd426..cc23e63 100755
--- a/regress/cmdline/update.sh
+++ b/regress/cmdline/update.sh
@@ -145,6 +145,52 @@ function test_update_deletes_file {
test_done "$testroot" "$ret"
}
+function test_update_deletes_dir {
+ local testroot=`test_init update_deletes_dir`
+
+ got checkout $testroot/repo $testroot/wt > /dev/null
+ if [ "$?" != "0" ]; then
+ test_done "$testroot" "$?"
+ return 1
+ fi
+
+ (cd $testroot/repo && git_rm $testroot/repo -r epsilon)
+ git_commit $testroot/repo -m "deleting a directory"
+
+ echo "D epsilon/zeta" > $testroot/stdout.expected
+ echo -n "Updated to commit " >> $testroot/stdout.expected
+ git_show_head $testroot/repo >> $testroot/stdout.expected
+ echo >> $testroot/stdout.expected
+
+ (cd $testroot/wt && got update > $testroot/stdout)
+
+ cmp $testroot/stdout.expected $testroot/stdout
+ if [ "$?" != "0" ]; then
+ diff -u $testroot/stdout.expected $testroot/stdout
+ test_done "$testroot" "$?"
+ return 1
+ fi
+
+ if [ -e $testroot/wt/epsilon ]; then
+ echo "removed dir epsilon still exists on disk" >&2
+ return 1
+ fi
+
+ echo "alpha" >> $testroot/content.expected
+ echo "beta" >> $testroot/content.expected
+ echo "delta" >> $testroot/content.expected
+ cat $testroot/wt/alpha $testroot/wt/beta \
+ $testroot/wt/gamma/delta > $testroot/content
+
+ cmp $testroot/content.expected $testroot/content
+ ret="$?"
+ if [ "$ret" != "0" ]; then
+ diff -u $testroot/content.expected $testroot/content
+ fi
+ test_done "$testroot" "$ret"
+}
+
run_test test_update_basic
run_test test_update_adds_file
run_test test_update_deletes_file
+run_test test_update_deletes_dir