Commit 2a06fe5f59f1b7b42f63bd9afe5187935c341321

Stefan Sperling 2019-08-24T12:58:07

indicate non-existent paths in 'got status' and make 'got diff' error for them

diff --git a/got/got.1 b/got/got.1
index bc24b56..45c8c5c 100644
--- a/got/got.1
+++ b/got/got.1
@@ -243,6 +243,9 @@ using the following status codes:
 .It \(a~ Ta versioned file is obstructed by a non-regular file
 .It ? Ta unversioned item not tracked by
 .Nm
+.It N Ta non-existent
+.Ar path
+specified on the command line
 .El
 .Pp
 If no
diff --git a/got/got.c b/got/got.c
index 9ae1a22..34e0719 100644
--- a/got/got.c
+++ b/got/got.c
@@ -1823,6 +1823,8 @@ print_diff(void *arg, unsigned char status, unsigned char staged_status,
 	} else {
 		if (staged_status == GOT_STATUS_DELETE)
 			return NULL;
+		if (status == GOT_STATUS_NONEXISTENT)
+			return got_error_set_errno(ENOENT, path);
 		if (status != GOT_STATUS_MODIFY &&
 		    status != GOT_STATUS_ADD &&
 		    status != GOT_STATUS_DELETE &&
@@ -3847,6 +3849,20 @@ usage_remove(void)
 }
 
 static const struct got_error *
+print_remove_status(void *arg, unsigned char status,
+    unsigned char staged_status, const char *path,
+    struct got_object_id *blob_id, struct got_object_id *staged_blob_id,
+    struct got_object_id *commit_id)
+{
+	if (status == GOT_STATUS_NONEXISTENT)
+		return NULL;
+	if (status == staged_status && (status == GOT_STATUS_DELETE))
+		status = GOT_STATUS_NO_CHANGE;
+	printf("%c%c %s\n", status, staged_status, path);
+	return NULL;
+}
+
+static const struct got_error *
 cmd_remove(int argc, char *argv[])
 {
 	const struct got_error *error = NULL;
@@ -3904,7 +3920,7 @@ cmd_remove(int argc, char *argv[])
 		goto done;
 
 	error = got_worktree_schedule_delete(worktree, &paths,
-	    delete_local_mods, print_status, NULL, repo);
+	    delete_local_mods, print_remove_status, NULL, repo);
 	if (error)
 		goto done;
 done:
diff --git a/include/got_worktree.h b/include/got_worktree.h
index 1bd4eff..096c4e4 100644
--- a/include/got_worktree.h
+++ b/include/got_worktree.h
@@ -31,6 +31,7 @@ struct got_fileindex;
 #define GOT_STATUS_MISSING	'!'
 #define GOT_STATUS_UNVERSIONED	'?'
 #define GOT_STATUS_OBSTRUCTED	'~'
+#define GOT_STATUS_NONEXISTENT	'N'
 #define GOT_STATUS_REVERT	'R'
 #define GOT_STATUS_CANNOT_DELETE 'd'
 #define GOT_STATUS_BUMP_BASE	'b'
diff --git a/lib/worktree.c b/lib/worktree.c
index 30b65e9..9a7c693 100644
--- a/lib/worktree.c
+++ b/lib/worktree.c
@@ -2508,6 +2508,8 @@ void *status_arg, struct got_repository *repo)
 	if (lstat(ondisk_path, &sb) == -1) {
 		if (errno != ENOENT)
 			return got_error_from_errno2("lstat", ondisk_path);
+		return (*status_cb)(status_arg, GOT_STATUS_NONEXISTENT,
+		    GOT_STATUS_NO_CHANGE, path, NULL, NULL, NULL);
 		return NULL;
 	}
 
@@ -5560,6 +5562,8 @@ check_stage_ok(void *arg, unsigned char status,
 
 	if (status == GOT_STATUS_UNVERSIONED)
 		return NULL;
+	if (status == GOT_STATUS_NONEXISTENT)
+		return got_error_set_errno(ENOENT, relpath);
 
 	ie = got_fileindex_entry_get(a->fileindex, relpath, strlen(relpath));
 	if (ie == NULL)
@@ -5703,6 +5707,9 @@ stage_path(void *arg, unsigned char status,
 	case GOT_STATUS_CONFLICT:
 		err = got_error_path(relpath, GOT_ERR_STAGE_CONFLICT);
 		break;
+	case GOT_STATUS_NONEXISTENT:
+		err = got_error_set_errno(ENOENT, relpath);
+		break;
 	default:
 		err = got_error_path(relpath, GOT_ERR_FILE_STATUS);
 		break;
diff --git a/regress/cmdline/diff.sh b/regress/cmdline/diff.sh
index e7cea61..455469c 100755
--- a/regress/cmdline/diff.sh
+++ b/regress/cmdline/diff.sh
@@ -62,6 +62,29 @@ function test_diff_basic {
 	ret="$?"
 	if [ "$ret" != "0" ]; then
 		diff -u $testroot/stdout.expected $testroot/stdout
+		test_done "$testroot" "$ret"
+		return 1
+	fi
+
+	# diff non-existent path
+	(cd $testroot/wt && got diff nonexistent > $testroot/stdout \
+		2> $testroot/stderr)
+
+	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: nonexistent: 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
 	fi
 	test_done "$testroot" "$ret"
 }
diff --git a/regress/cmdline/stage.sh b/regress/cmdline/stage.sh
index e7fb40f..abe3641 100755
--- a/regress/cmdline/stage.sh
+++ b/regress/cmdline/stage.sh
@@ -156,7 +156,8 @@ function test_stage_nonexistent {
 
 	(cd $testroot/wt && got stage nonexistent-file \
 		> $testroot/stdout 2> $testroot/stderr)
-	echo "got: no changes to stage" > $testroot/stderr.expected
+	echo "got: nonexistent-file: No such file or directory" \
+		> $testroot/stderr.expected
 	cmp -s $testroot/stderr.expected $testroot/stderr
 	ret="$?"
 	if [ "$ret" != "0" ]; then
diff --git a/regress/cmdline/update.sh b/regress/cmdline/update.sh
index ec4a92d..1cdd633 100755
--- a/regress/cmdline/update.sh
+++ b/regress/cmdline/update.sh
@@ -1052,7 +1052,7 @@ function test_update_conflict_wt_rm_vs_repo_rm {
 	fi
 
 	# beta is now gone... we don't flag tree conflicts yet
-	echo -n > $testroot/stdout.expected
+	echo "N  beta" > $testroot/stdout.expected
 	echo -n > $testroot/stderr.expected
 	(cd $testroot/wt && got status beta > $testroot/stdout \
 		2> $testroot/stderr)