Commit Diff


commit - efaf56b722e9595f43c4177384f7e54c88fbc285
commit + 90285c3b5b24fe56d9ea77e33199bcd395595b95
blob - a0db6ed9feeabdacaad31a547840dd969d114d4a
blob + 59cca6fff1cd992952d074f19528f0b9831465d0
--- got/Makefile
+++ got/Makefile
@@ -3,8 +3,9 @@
 PROG=		got
 SRCS=		got.c blame.c commit_graph.c delta.c diff.c diffoffset.c \
 		diffreg.c error.c fileindex.c object.c object_cache.c \
-		object_idset.c object_parse.c opentemp.c path.c pack.c \
-		privsep.c reference.c repository.c sha1.c worktree.c inflate.c
+		object_idset.c object_parse.c opentemp.c path.c pathset.c \
+		pack.c privsep.c reference.c repository.c sha1.c worktree.c \
+		inflate.c
 
 CPPFLAGS = -I${.CURDIR}/../include -I${.CURDIR}/../lib \
 	-DGOT_LIBEXECDIR=${GOT_LIBEXECDIR}
blob - e43e15f1fb069fc763545860dc8cdbbdb516522a
blob + a728112ef99a5c737f7c452c927196b2e2bc58e0
--- lib/worktree.c
+++ lib/worktree.c
@@ -39,6 +39,7 @@
 
 #include "got_lib_worktree.h"
 #include "got_lib_path.h"
+#include "got_lib_pathset.h"
 #include "got_lib_sha1.h"
 #include "got_lib_fileindex.h"
 #include "got_lib_inflate.h"
@@ -740,13 +741,14 @@ done:
 struct collect_missing_entry_args {
 	struct got_fileindex *fileindex;
 	const struct got_tree_entries *entries;
-	struct got_fileindex missing_entries;
+	struct got_pathset *missing_entries;
 	const char *current_subdir;
 };
 
 static const struct got_error *
 collect_missing_file(void *args, struct got_fileindex_entry *entry)
 {
+	const struct got_error *err = NULL;
 	struct collect_missing_entry_args *a = args;
 	char *start, *end;
 	ptrdiff_t len;
@@ -781,7 +783,51 @@ collect_missing_file(void *args, struct got_fileindex_
 		return NULL;
 
 	got_fileindex_entry_remove(a->fileindex, entry);
-	return got_fileindex_entry_add(&a->missing_entries, entry);
+	err = got_pathset_add(a->missing_entries, entry->path, NULL);
+	got_fileindex_entry_free(entry);
+	return err;
+}
+
+struct remove_missing_file_args {
+    const char *root_path;
+    got_worktree_checkout_cb progress_cb;
+    void *progress_arg;
+    got_worktree_cancel_cb cancel_cb;
+    void *cancel_arg;
+};
+
+static const struct got_error *
+remove_missing_file(const char *path, void *data, void *arg)
+{
+	const struct got_error *err = NULL;
+	char *ondisk_path = NULL;
+	struct remove_missing_file_args *a = arg;
+
+	if (a->cancel_cb) {
+		err = (*a->cancel_cb)(a->cancel_arg);
+		if (err)
+			return err;
+	}
+
+	(*a->progress_cb)(a->progress_arg, GOT_STATUS_DELETE, path);
+
+	if (asprintf(&ondisk_path, "%s/%s", a->root_path, path) == -1)
+		return got_error_from_errno();
+
+	if (unlink(ondisk_path) == -1)
+		err = got_error_from_errno();
+	else {
+		char *parent = dirname(ondisk_path);
+		while (parent && strcmp(parent, a->root_path) != 0) {
+			if (rmdir(parent) == -1 && errno != ENOTEMPTY) {
+				err = got_error_from_errno();
+				break;
+			}
+			parent = dirname(parent);
+		}
+	}
+	free(ondisk_path);
+	return err;
 }
 
 /* Remove files which exist in the file index but not in the tree. */
@@ -793,58 +839,27 @@ remove_missing_files(struct got_worktree *worktree, co
 {
 	const struct got_error *err = NULL;
 	struct collect_missing_entry_args a;
-	struct got_fileindex_entry *entry, *tmp;
+	struct remove_missing_file_args a2;
 
 	a.fileindex = fileindex;
 	a.entries = entries;
-	a.missing_entries.nentries = 0;
+	a.missing_entries = got_pathset_alloc();
+	if (a.missing_entries == NULL)
+		return got_error_from_errno();
 	a.current_subdir = apply_path_prefix(worktree, path);
-	TAILQ_INIT(&a.missing_entries.entries);
 	err = got_fileindex_for_each_entry_safe(fileindex,
 	    collect_missing_file, &a);
 	if (err)
 		return err;
 
-	TAILQ_FOREACH_SAFE(entry, &a.missing_entries.entries, entry, tmp) {
-		char *ondisk_path = NULL;
+	a2.root_path = worktree->root_path;
+	a2.cancel_cb = cancel_cb;
+	a2.cancel_arg = cancel_arg;
+	a2.progress_cb = progress_cb;
+	a2.progress_arg = progress_arg;
 
-		if (cancel_cb) {
-			err = (*cancel_cb)(cancel_arg);
-			if (err)
-				break;
-		}
-
-		(*progress_cb)(progress_arg, GOT_STATUS_DELETE, entry->path);
-
-		if (asprintf(&ondisk_path, "%s/%s", worktree->root_path,
-		    entry->path) == -1) {
-			err = got_error_from_errno();
-			break;
-		}
-
-		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;
-
-		TAILQ_REMOVE(&a.missing_entries.entries, entry, entry);
-		got_fileindex_entry_free(entry);
-	}
-
-	if (err) {
-		while (!TAILQ_EMPTY(&a.missing_entries.entries)) {
-			entry = TAILQ_FIRST(&a.missing_entries.entries);
-			TAILQ_REMOVE(&a.missing_entries.entries, entry, entry);
-			got_fileindex_entry_free(entry);
-		}
-	}
-
+	err = got_pathset_for_each(a.missing_entries, remove_missing_file, &a2);
+	got_pathset_free(a.missing_entries);
 	return err;
 }
 
blob - 5c505f1af4c5dc561754cca6e9a7158054f939d5
blob + eb351e57fada625d5e0502ffd0f5e3a0b7065c4b
--- regress/cmdline/update.sh
+++ regress/cmdline/update.sh
@@ -199,8 +199,50 @@ function test_update_deletes_dir_with_path_prefix {
 	test_done "$testroot" "0"
 }
 
+function test_update_deletes_dir_recursively {
+	local testroot=`test_init update_deletes_dir_recursively`
+	local first_rev=`git_show_head $testroot/repo`
+
+	mkdir $testroot/repo/epsilon/psi
+	echo mu > $testroot/repo/epsilon/psi/mu
+	mkdir $testroot/repo/epsilon/psi/chi
+	echo tau > $testroot/repo/epsilon/psi/chi/tau
+	(cd $testroot/repo && git add .)
+	git_commit $testroot/repo -m "adding a sub-directory beneath epsilon"
+
+	# check out the epsilon/ sub-tree
+	got checkout -p epsilon $testroot/repo $testroot/wt > /dev/null
+	if [ "$?" != "0" ]; then
+		test_done "$testroot" "$?"
+		return 1
+	fi
+
+	# update back to first commit and expect psi/mu to be deleted
+	echo "D  psi/chi/tau" > $testroot/stdout.expected
+	echo "D  psi/mu" >> $testroot/stdout.expected
+	echo "Updated to commit $first_rev" >> $testroot/stdout.expected
+
+	(cd $testroot/wt && got update -c $first_rev > $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/psi ]; then
+		echo "removed dir psi still exists on disk" >&2
+		test_done "$testroot" "1"
+		return 1
+	fi
+
+	test_done "$testroot" "0"
+}
+
 run_test test_update_basic
 run_test test_update_adds_file
 run_test test_update_deletes_file
 run_test test_update_deletes_dir
 run_test test_update_deletes_dir_with_path_prefix
+run_test test_update_deletes_dir_recursively
blob - 622918d65a3235175fbd16aaffcc60725d7d93cc
blob + 7046be709f854cb231dae101e6b5e9fe1670cc55
--- regress/idset/Makefile
+++ regress/idset/Makefile
@@ -1,9 +1,9 @@
 .PATH:${.CURDIR}/../../lib
 
 PROG = idset_test
-SRCS = error.c object.c privsep.c sha1.c pack.c inflate.c path.c opentemp.c \
-	delta.c repository.c reference.c worktree.c fileindex.c object_cache.c \
-	object_idset.c object_parse.c idset_test.c
+SRCS = error.c object.c privsep.c sha1.c pack.c inflate.c path.c pathset.c \
+	opentemp.c delta.c repository.c reference.c worktree.c fileindex.c \
+	object_cache.c object_idset.c object_parse.c idset_test.c
 
 CPPFLAGS = -I${.CURDIR}/../../include -I${.CURDIR}/../../lib
 LDADD = -lutil -lz
blob - 5da0a61342d57368a2ad4a97cf0cfcacf13e6028
blob + 7eba96e9e3b3cf49fc84691bde7194b8a506ac39
--- regress/repository/Makefile
+++ regress/repository/Makefile
@@ -4,7 +4,7 @@ PROG = repository_test
 SRCS = path.c repository.c error.c reference.c object.c object_cache.c \
 	object_idset.c object_parse.c opentemp.c sha1.c diff.c diffreg.c \
 	pack.c privsep.c delta.c fileindex.c worktree.c inflate.c \
-	repository_test.c
+	pathset.c repository_test.c
 
 CPPFLAGS = -I${.CURDIR}/../../include -I${.CURDIR}/../../lib \
 	-DGOT_LIBEXECDIR=${GOT_LIBEXECDIR}
blob - 967be5ea5fc6fb725eea04040ce5afa44a56ca59
blob + c7e2786beead1950de2cd83f434b064dc3366aa0
--- regress/worktree/Makefile
+++ regress/worktree/Makefile
@@ -2,7 +2,7 @@
 
 PROG = worktree_test
 SRCS = worktree.c repository.c object.c object_cache.c object_idset.c \
-	object_parse.c opentemp.c path.c error.c reference.c sha1.c \
+	object_parse.c opentemp.c path.c pathset.c error.c reference.c sha1.c \
 	pack.c privsep.c delta.c inflate.c fileindex.c worktree_test.c
 
 CPPFLAGS = -I${.CURDIR}/../../include -I${.CURDIR}/../../lib \
blob - 72f8d6d7e4c381ebb68b1e052998d0843ff100aa
blob + fb527723e3ad29a2d4e54676089954a3376cfaa1
--- tog/Makefile
+++ tog/Makefile
@@ -3,8 +3,8 @@
 PROG=		tog
 SRCS=		tog.c blame.c commit_graph.c delta.c diff.c diffoffset.c \
 		diffreg.c error.c fileindex.c object.c object_cache.c \
-		object_idset.c object_parse.c opentemp.c path.c pack.c \
-		privsep.c reference.c repository.c sha1.c worktree.c \
+		object_idset.c object_parse.c opentemp.c path.c pathset.c \
+		pack.c privsep.c reference.c repository.c sha1.c worktree.c \
 		utf8.c inflate.c
 
 CPPFLAGS = -I${.CURDIR}/../include -I${.CURDIR}/../lib \