Skip to content

Commit 78731f0

Browse files
committed
Merge branch 'tb/cat-file-z' into next
Operating modes like "--batch" of "git cat-file" command learned to take NUL-terminated input, instead of one-item-per-line. * tb/cat-file-z: builtin/cat-file.c: support NUL-delimited input with `-z` t1006: extract --batch-command inputs to variables
2 parents 8e6237d + db9d67f commit 78731f0

File tree

3 files changed

+88
-19
lines changed

3 files changed

+88
-19
lines changed

Documentation/git-cat-file.txt

Lines changed: 6 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -14,7 +14,7 @@ SYNOPSIS
1414
'git cat-file' (-t | -s) [--allow-unknown-type] <object>
1515
'git cat-file' (--batch | --batch-check | --batch-command) [--batch-all-objects]
1616
[--buffer] [--follow-symlinks] [--unordered]
17-
[--textconv | --filters]
17+
[--textconv | --filters] [-z]
1818
'git cat-file' (--textconv | --filters)
1919
[<rev>:<path|tree-ish> | --path=<path|tree-ish> <rev>]
2020

@@ -213,6 +213,11 @@ respectively print:
213213
/etc/passwd
214214
--
215215

216+
-z::
217+
Only meaningful with `--batch`, `--batch-check`, or
218+
`--batch-command`; input is NUL-delimited instead of
219+
newline-delimited.
220+
216221

217222
OUTPUT
218223
------

builtin/cat-file.c

Lines changed: 25 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -32,6 +32,7 @@ struct batch_options {
3232
int all_objects;
3333
int unordered;
3434
int transform_mode; /* may be 'w' or 'c' for --filters or --textconv */
35+
int nul_terminated;
3536
const char *format;
3637
};
3738

@@ -650,12 +651,20 @@ static void batch_objects_command(struct batch_options *opt,
650651
struct queued_cmd *queued_cmd = NULL;
651652
size_t alloc = 0, nr = 0;
652653

653-
while (!strbuf_getline(&input, stdin)) {
654-
int i;
654+
while (1) {
655+
int i, ret;
655656
const struct parse_cmd *cmd = NULL;
656657
const char *p = NULL, *cmd_end;
657658
struct queued_cmd call = {0};
658659

660+
if (opt->nul_terminated)
661+
ret = strbuf_getline_nul(&input, stdin);
662+
else
663+
ret = strbuf_getline(&input, stdin);
664+
665+
if (ret)
666+
break;
667+
659668
if (!input.len)
660669
die(_("empty command in input"));
661670
if (isspace(*input.buf))
@@ -799,7 +808,16 @@ static int batch_objects(struct batch_options *opt)
799808
goto cleanup;
800809
}
801810

802-
while (strbuf_getline(&input, stdin) != EOF) {
811+
while (1) {
812+
int ret;
813+
if (opt->nul_terminated)
814+
ret = strbuf_getline_nul(&input, stdin);
815+
else
816+
ret = strbuf_getline(&input, stdin);
817+
818+
if (ret == EOF)
819+
break;
820+
803821
if (data.split_on_whitespace) {
804822
/*
805823
* Split at first whitespace, tying off the beginning
@@ -904,6 +922,7 @@ int cmd_cat_file(int argc, const char **argv, const char *prefix)
904922
N_("like --batch, but don't emit <contents>"),
905923
PARSE_OPT_OPTARG | PARSE_OPT_NONEG,
906924
batch_option_callback),
925+
OPT_BOOL('z', NULL, &batch.nul_terminated, N_("stdin is NUL-terminated")),
907926
OPT_CALLBACK_F(0, "batch-command", &batch, N_("format"),
908927
N_("read commands from stdin"),
909928
PARSE_OPT_OPTARG | PARSE_OPT_NONEG,
@@ -962,6 +981,9 @@ int cmd_cat_file(int argc, const char **argv, const char *prefix)
962981
else if (batch.all_objects)
963982
usage_msg_optf(_("'%s' requires a batch mode"), usage, options,
964983
"--batch-all-objects");
984+
else if (batch.nul_terminated)
985+
usage_msg_optf(_("'%s' requires a batch mode"), usage, options,
986+
"-z");
965987

966988
/* Batch defaults */
967989
if (batch.buffer_output < 0)

t/t1006-cat-file.sh

Lines changed: 57 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -88,7 +88,8 @@ done
8888

8989
for opt in --buffer \
9090
--follow-symlinks \
91-
--batch-all-objects
91+
--batch-all-objects \
92+
-z
9293
do
9394
test_expect_success "usage: bad option combination: $opt without batch mode" '
9495
test_incompatible_usage git cat-file $opt &&
@@ -100,6 +101,10 @@ echo_without_newline () {
100101
printf '%s' "$*"
101102
}
102103

104+
echo_without_newline_nul () {
105+
echo_without_newline "$@" | tr '\n' '\0'
106+
}
107+
103108
strlen () {
104109
echo_without_newline "$1" | wc -c | sed -e 's/^ *//'
105110
}
@@ -398,6 +403,12 @@ test_expect_success '--batch with multiple sha1s gives correct format' '
398403
test "$(maybe_remove_timestamp "$batch_output" 1)" = "$(maybe_remove_timestamp "$(echo_without_newline "$batch_input" | git cat-file --batch)" 1)"
399404
'
400405

406+
test_expect_success '--batch, -z with multiple sha1s gives correct format' '
407+
echo_without_newline_nul "$batch_input" >in &&
408+
test "$(maybe_remove_timestamp "$batch_output" 1)" = \
409+
"$(maybe_remove_timestamp "$(git cat-file --batch -z <in)" 1)"
410+
'
411+
401412
batch_check_input="$hello_sha1
402413
$tree_sha1
403414
$commit_sha1
@@ -418,6 +429,30 @@ test_expect_success "--batch-check with multiple sha1s gives correct format" '
418429
"$(echo_without_newline "$batch_check_input" | git cat-file --batch-check)"
419430
'
420431

432+
test_expect_success "--batch-check, -z with multiple sha1s gives correct format" '
433+
echo_without_newline_nul "$batch_check_input" >in &&
434+
test "$batch_check_output" = "$(git cat-file --batch-check -z <in)"
435+
'
436+
437+
test_expect_success FUNNYNAMES '--batch-check, -z with newline in input' '
438+
touch -- "newline${LF}embedded" &&
439+
git add -- "newline${LF}embedded" &&
440+
git commit -m "file with newline embedded" &&
441+
test_tick &&
442+
443+
printf "HEAD:newline${LF}embedded" >in &&
444+
git cat-file --batch-check -z <in >actual &&
445+
446+
echo "$(git rev-parse "HEAD:newline${LF}embedded") blob 0" >expect &&
447+
test_cmp expect actual
448+
'
449+
450+
batch_command_multiple_info="info $hello_sha1
451+
info $tree_sha1
452+
info $commit_sha1
453+
info $tag_sha1
454+
info deadbeef"
455+
421456
test_expect_success '--batch-command with multiple info calls gives correct format' '
422457
cat >expect <<-EOF &&
423458
$hello_sha1 blob $hello_size
@@ -427,17 +462,23 @@ test_expect_success '--batch-command with multiple info calls gives correct form
427462
deadbeef missing
428463
EOF
429464
430-
git cat-file --batch-command --buffer >actual <<-EOF &&
431-
info $hello_sha1
432-
info $tree_sha1
433-
info $commit_sha1
434-
info $tag_sha1
435-
info deadbeef
436-
EOF
465+
echo "$batch_command_multiple_info" >in &&
466+
git cat-file --batch-command --buffer <in >actual &&
467+
468+
test_cmp expect actual &&
469+
470+
echo "$batch_command_multiple_info" | tr "\n" "\0" >in &&
471+
git cat-file --batch-command --buffer -z <in >actual &&
437472
438473
test_cmp expect actual
439474
'
440475

476+
batch_command_multiple_contents="contents $hello_sha1
477+
contents $commit_sha1
478+
contents $tag_sha1
479+
contents deadbeef
480+
flush"
481+
441482
test_expect_success '--batch-command with multiple command calls gives correct format' '
442483
remove_timestamp >expect <<-EOF &&
443484
$hello_sha1 blob $hello_size
@@ -449,13 +490,14 @@ test_expect_success '--batch-command with multiple command calls gives correct f
449490
deadbeef missing
450491
EOF
451492
452-
git cat-file --batch-command --buffer >actual_raw <<-EOF &&
453-
contents $hello_sha1
454-
contents $commit_sha1
455-
contents $tag_sha1
456-
contents deadbeef
457-
flush
458-
EOF
493+
echo "$batch_command_multiple_contents" >in &&
494+
git cat-file --batch-command --buffer <in >actual_raw &&
495+
496+
remove_timestamp <actual_raw >actual &&
497+
test_cmp expect actual &&
498+
499+
echo "$batch_command_multiple_contents" | tr "\n" "\0" >in &&
500+
git cat-file --batch-command --buffer -z <in >actual_raw &&
459501
460502
remove_timestamp <actual_raw >actual &&
461503
test_cmp expect actual

0 commit comments

Comments
 (0)