Commit 50952927133492b33519e6b09474d9a9ae77abb6

Stefan Sperling 2019-01-12T21:00:42

fix various issues in new update implementation

diff --git a/lib/fileindex.c b/lib/fileindex.c
index b3b7b35..afdeab7 100644
--- a/lib/fileindex.c
+++ b/lib/fileindex.c
@@ -100,9 +100,8 @@ got_fileindex_entry_free(struct got_fileindex_entry *entry)
 	free(entry);
 }
 
-const struct got_error *
-got_fileindex_entry_add(struct got_fileindex *fileindex,
-    struct got_fileindex_entry *entry)
+static const struct got_error *
+add_entry(struct got_fileindex *fileindex, struct got_fileindex_entry *entry)
 {
 	if (fileindex->nentries >= GOT_FILEIDX_MAX_ENTRIES)
 		return got_error(GOT_ERR_NO_SPACE);
@@ -112,6 +111,16 @@ got_fileindex_entry_add(struct got_fileindex *fileindex,
 	return NULL;
 }
 
+const struct got_error *
+got_fileindex_entry_add(struct got_fileindex *fileindex,
+    struct got_fileindex_entry *entry)
+{
+	/* Flag this entry until it gets written out to disk. */
+	entry->flags |= GOT_INDEX_ENTRY_F_INTENT_TO_ADD;
+
+	return add_entry(fileindex, entry);
+}
+
 void
 got_fileindex_entry_remove(struct got_fileindex *fileindex,
     struct got_fileindex_entry *entry)
@@ -309,6 +318,7 @@ got_fileindex_write(struct got_fileindex *fileindex, FILE *outfile)
 		return got_ferror(outfile, GOT_ERR_IO);
 
 	RB_FOREACH(entry, got_fileindex_tree, &fileindex->entries) {
+		entry->flags &= ~GOT_INDEX_ENTRY_F_INTENT_TO_ADD;
 		err = write_fileindex_entry(&ctx, entry, outfile);
 		if (err)
 			return err;
@@ -505,7 +515,7 @@ got_fileindex_read(struct got_fileindex *fileindex, FILE *infile)
 		err = read_fileindex_entry(&entry, &ctx, infile);
 		if (err)
 			return err;
-		err = got_fileindex_entry_add(fileindex, entry);
+		err = add_entry(fileindex, entry);
 		if (err)
 			return err;
 	}
@@ -525,7 +535,6 @@ in_same_subdir(struct got_fileindex_entry *ie, const char *parent_path,
     struct got_tree_entry *te)
 {
 	size_t parent_len = strlen(parent_path);
-	size_t te_name_len = strlen(te->name);
 	char *ie_name;
 
 	if (!got_path_is_child(ie->path, parent_path, parent_len))
@@ -534,12 +543,8 @@ in_same_subdir(struct got_fileindex_entry *ie, const char *parent_path,
 	ie_name = ie->path + parent_len;
 	while (ie_name[0] == '/')
 		ie_name++;
-	if (strncmp(ie_name, te->name, te_name_len) != 0)
-		return 0;
-	if (ie_name[te_name_len] == '/')
-		return 0;
 
-	return 1;
+	return strchr(ie_name, '/') == NULL;
 }
 
 static int
@@ -551,15 +556,15 @@ cmp_entries(struct got_fileindex_entry *ie, const char *parent_path,
 
 	if (!in_same_subdir(ie, parent_path, te)) {
 		if (parent_path[0])
-			return got_compare_paths(ie->path, parent_path);
-		return got_compare_paths(ie->path, te->name);
+			return strcmp(ie->path, parent_path);
+		return strcmp(ie->path, te->name);
 	}
 
 	ie_name = ie->path + parent_len;
 	while (ie_name[0] == '/')
 		ie_name++;
 
-	return got_compare_paths(ie_name, te->name);
+	return strcmp(ie_name, te->name);
 }
 
 static const struct got_error *
@@ -567,6 +572,20 @@ diff_fileindex_tree(struct got_fileindex *, struct got_fileindex_entry **,
     struct got_tree_object *, const char *, struct got_repository *,
     struct got_fileindex_diff_cb *, void *);
 
+struct got_fileindex_entry *
+walk_fileindex(struct got_fileindex *fileindex, struct got_fileindex_entry *ie)
+{
+	struct got_fileindex_entry *next;
+
+	next = RB_NEXT(got_fileindex_tree, &fileindex->entries, ie);
+
+	/* Skip entries which were newly added by diff callbacks. */
+	while (next && (next->flags & GOT_INDEX_ENTRY_F_INTENT_TO_ADD))
+		next = RB_NEXT(got_fileindex_tree, &fileindex->entries, next);
+
+	return next;
+}
+
 static const struct got_error *
 walk_tree(struct got_tree_entry **next, struct got_fileindex *fileindex,
     struct got_fileindex_entry **ie, struct got_tree_entry *te,
@@ -635,13 +654,11 @@ diff_fileindex_tree(struct got_fileindex *fileindex,
 				    path);
 				if (err)
 					break;
-				*ie = RB_NEXT(got_fileindex_tree,
-				    &fileindex->entries, *ie);
+				*ie = walk_fileindex(fileindex, *ie);
 				err = walk_tree(&te, fileindex, ie, te,
 				    path, repo, cb, cb_arg);
-			} else if (cmp < 0) {
-				next = RB_NEXT(got_fileindex_tree,
-				    &fileindex->entries, *ie);
+			} else if (cmp < 0 ) {
+				next = walk_fileindex(fileindex, *ie);
 				err = cb->diff_old(cb_arg, *ie, path);
 				if (err)
 					break;
@@ -656,8 +673,7 @@ diff_fileindex_tree(struct got_fileindex *fileindex,
 			if (err)
 				break;
 		} else if (*ie) {
-			next = RB_NEXT(got_fileindex_tree,
-			    &fileindex->entries, *ie);
+			next = walk_fileindex(fileindex, *ie);
 			err = cb->diff_old(cb_arg, *ie, path);
 			if (err)
 				break;
diff --git a/lib/got_lib_fileindex.h b/lib/got_lib_fileindex.h
index 791dba0..3aee1d3 100644
--- a/lib/got_lib_fileindex.h
+++ b/lib/got_lib_fileindex.h
@@ -53,6 +53,7 @@ struct got_fileindex_entry {
 #define GOT_INDEX_ENTRY_F_STAGE		0x00003000
 #define GOT_INDEX_ENTRY_F_EXTENDED	0x00004000
 #define GOT_INDEX_ENTRY_F_ASSUME_VALID	0x00008000
+#define GOT_INDEX_ENTRY_F_INTENT_TO_ADD	0x20000000
 
 	/*
 	 * UNIX-style path, relative to work tree root.
@@ -77,7 +78,7 @@ static inline int
 got_fileindex_cmp(const struct got_fileindex_entry *e1,
     const struct got_fileindex_entry *e2)
 {
-	return got_compare_paths(e1->path, e2->path);
+	return strcmp(e1->path, e2->path);
 }
 
 RB_PROTOTYPE(got_fileindex_tree, got_fileindex_entry, entry, got_fileindex_cmp);
diff --git a/regress/cmdline/update.sh b/regress/cmdline/update.sh
index 1572dea..e28a356 100755
--- a/regress/cmdline/update.sh
+++ b/regress/cmdline/update.sh
@@ -302,6 +302,63 @@ function test_update_sibling_dirs_with_common_prefix {
 	test_done "$testroot" "0"
 }
 
+function test_update_dir_with_dot_sibling {
+	local testroot=`test_init update_dir_with_dot_sibling`
+
+	got checkout $testroot/repo $testroot/wt > /dev/null
+	if [ "$?" != "0" ]; then
+		test_done "$testroot" "$?"
+		return 1
+	fi
+
+	echo text > $testroot/repo/epsilon.txt
+	(cd $testroot/repo && git add epsilon.txt)
+	git_commit $testroot/repo -m "adding sibling of epsilon"
+	echo change > $testroot/repo/epsilon/zeta
+	git_commit $testroot/repo -m "changing epsilon/zeta"
+
+	echo "A  epsilon.txt" > $testroot/stdout.expected
+	echo "U  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
+
+	echo "another change" > $testroot/repo/epsilon/zeta
+	git_commit $testroot/repo -m "changing epsilon/zeta again"
+
+	echo "U  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
+
+	cmp $testroot/stdout.expected $testroot/stdout
+	if [ "$?" != "0" ]; then
+		diff -u $testroot/stdout.expected $testroot/stdout
+		test_done "$testroot" "$?"
+		return 1
+	fi
+
+	test_done "$testroot" "0"
+}
+
 run_test test_update_basic
 run_test test_update_adds_file
 run_test test_update_deletes_file
@@ -309,3 +366,4 @@ run_test test_update_deletes_dir
 run_test test_update_deletes_dir_with_path_prefix
 run_test test_update_deletes_dir_recursively
 run_test test_update_sibling_dirs_with_common_prefix
+run_test test_update_dir_with_dot_sibling