diff mbox series

[3/3] builtin/diff-blob: Add "-z" option

Message ID 20241213042312.2890841-4-jltobler@gmail.com (mailing list archive)
State New
Headers show
Series batch blob diff generation | expand

Commit Message

Justin Tobler Dec. 13, 2024, 4:23 a.m. UTC
The "--stdin" option for git-diff-blob(1) reads two space separated
blobs for each line of input. A blob may be specified by its ID or a
path-scoped revision that resolves to a blob. It is possible for the
path to contain whitespace or newline characters which must be escaped.

To make input more simple, teach git-diff-blob(1) the "-z" option which
changes the input delimiter for each blob to a NUL character. With this
option, the command waits two NUL terminated blobs to read and then
generates the diff. The diff output is also NUL terminated to help
differentiate between outputted diffs.

Signed-off-by: Justin Tobler <jltobler@gmail.com>
---
 Documentation/git-diff-blob.txt |  6 +++++-
 builtin/diff-blob.c             | 37 +++++++++++++++++++++++++--------
 2 files changed, 33 insertions(+), 10 deletions(-)
diff mbox series

Patch

diff --git a/Documentation/git-diff-blob.txt b/Documentation/git-diff-blob.txt
index f6ecd522fa..36cd686bb1 100644
--- a/Documentation/git-diff-blob.txt
+++ b/Documentation/git-diff-blob.txt
@@ -10,7 +10,7 @@  SYNOPSIS
 --------
 [verse]
 'git diff-blob' <blob> <blob>
-'git diff-blob' --stdin
+'git diff-blob' --stdin [-z]
 
 DESCRIPTION
 -----------
@@ -26,6 +26,10 @@  OPTIONS
 	from the command line.  Instead, it reads lines containing two <blob>
 	from its standard input.  (Use a single space as separator.)
 
+-z::
+	When `--stdin` has been given, use NUL characters to separate blob
+	inputs and diff outputs.
+
 include::pretty-formats.txt[]
 
 include::diff-format.txt[]
diff --git a/builtin/diff-blob.c b/builtin/diff-blob.c
index 45edfdd979..60c92cec9c 100644
--- a/builtin/diff-blob.c
+++ b/builtin/diff-blob.c
@@ -81,23 +81,39 @@  static void parse_blob_stdin(struct object_array *blob_pair,
 	object_context_release(&oc);
 }
 
-static void diff_blob_stdin(struct repository *repo, struct diff_options *opts)
+static void diff_blob_stdin(struct repository *repo, struct diff_options *opts,
+			    int null_term)
 {
 	struct strbuf sb = STRBUF_INIT;
 	struct string_list_item *item;
 
-	while (strbuf_getline(&sb, stdin) != EOF) {
+	while (1) {
 		struct object_array blob_pair = OBJECT_ARRAY_INIT;
 		struct string_list list = STRING_LIST_INIT_NODUP;
 
-		if (string_list_split_in_place(&list, sb.buf, " ", -1) != 2)
-			die("two blobs not provided");
+		if (null_term) {
+			if (strbuf_getline_nul(&sb, stdin) == EOF)
+				break;
+			parse_blob_stdin(&blob_pair, repo, sb.buf);
 
-		for_each_string_list_item(item, &list) {
-			parse_blob_stdin(&blob_pair, repo, item->string);
+			if (strbuf_getline_nul(&sb, stdin) == EOF)
+				break;
+			parse_blob_stdin(&blob_pair, repo, sb.buf);
+		} else {
+			if (strbuf_getline(&sb, stdin) == EOF)
+				break;
+
+			if (string_list_split_in_place(&list, sb.buf, " ", -1) != 2)
+				die("two blobs not provided");
+
+			for_each_string_list_item(item, &list) {
+				parse_blob_stdin(&blob_pair, repo, item->string);
+			}
 		}
 
 		diff_blobs(&blob_pair.objects[0], &blob_pair.objects[1], opts);
+		if (null_term)
+			printf("%c", '\0');
 
 		string_list_clear(&list, 1);
 		object_array_clear(&blob_pair);
@@ -112,16 +128,19 @@  int cmd_diff_blob(int argc, const char **argv, const char *prefix,
 	struct object_array_entry *old_blob, *new_blob;
 	struct rev_info revs;
 	int read_stdin = 0;
+	int null_term = 0;
 	int ret;
 
 	const char * const usage[] = {
 		N_("git diff-blob <blob> <blob>"),
-		N_("git diff-blob --stdin"),
+		N_("git diff-blob --stdin [-z]"),
 		NULL
 	};
 	struct option options[] = {
 		OPT_BOOL(0, "stdin", &read_stdin,
 			N_("read blob pairs from stdin")),
+		OPT_BOOL('z', NULL, &null_term,
+			N_("inputed blobs and outputted diffs terminated with NUL")),
 		OPT_END()
 	};
 
@@ -149,13 +168,13 @@  int cmd_diff_blob(int argc, const char **argv, const char *prefix,
 			usage_with_options(usage, options);
 
 		revs.diffopt.no_free = 1;
-		diff_blob_stdin(repo, &revs.diffopt);
+		diff_blob_stdin(repo, &revs.diffopt, null_term);
 		revs.diffopt.no_free = 0;
 		diff_free(&revs.diffopt);
 
 		break;
 	case 2:
-		if (read_stdin)
+		if (read_stdin || null_term)
 			usage_with_options(usage, options);
 
 		old_blob = &revs.pending.objects[0];