mirror of
https://github.com/git/git
synced 2024-10-30 04:01:21 +00:00
Merge branch 'ps/cat-file-null-output'
"git cat-file --batch" and friends learned "-Z" that uses NUL delimiter for both input and output. * ps/cat-file-null-output: cat-file: add option '-Z' that delimits input and output with NUL cat-file: simplify reading from standard input strbuf: provide CRLF-aware helper to read until a specified delimiter t1006: modernize test style to use `test_cmp` t1006: don't strip timestamps from expected results
This commit is contained in:
commit
a9ea4c23dc
5 changed files with 232 additions and 138 deletions
|
@ -14,7 +14,7 @@ SYNOPSIS
|
||||||
'git cat-file' (-t | -s) [--allow-unknown-type] <object>
|
'git cat-file' (-t | -s) [--allow-unknown-type] <object>
|
||||||
'git cat-file' (--batch | --batch-check | --batch-command) [--batch-all-objects]
|
'git cat-file' (--batch | --batch-check | --batch-command) [--batch-all-objects]
|
||||||
[--buffer] [--follow-symlinks] [--unordered]
|
[--buffer] [--follow-symlinks] [--unordered]
|
||||||
[--textconv | --filters] [-z]
|
[--textconv | --filters] [-Z]
|
||||||
'git cat-file' (--textconv | --filters)
|
'git cat-file' (--textconv | --filters)
|
||||||
[<rev>:<path|tree-ish> | --path=<path|tree-ish> <rev>]
|
[<rev>:<path|tree-ish> | --path=<path|tree-ish> <rev>]
|
||||||
|
|
||||||
|
@ -243,10 +243,16 @@ respectively print:
|
||||||
/etc/passwd
|
/etc/passwd
|
||||||
--
|
--
|
||||||
|
|
||||||
|
-Z::
|
||||||
|
Only meaningful with `--batch`, `--batch-check`, or
|
||||||
|
`--batch-command`; input and output is NUL-delimited instead of
|
||||||
|
newline-delimited.
|
||||||
|
|
||||||
-z::
|
-z::
|
||||||
Only meaningful with `--batch`, `--batch-check`, or
|
Only meaningful with `--batch`, `--batch-check`, or
|
||||||
`--batch-command`; input is NUL-delimited instead of
|
`--batch-command`; input is NUL-delimited instead of
|
||||||
newline-delimited.
|
newline-delimited. This option is deprecated in favor of
|
||||||
|
`-Z` as the output can otherwise be ambiguous.
|
||||||
|
|
||||||
|
|
||||||
OUTPUT
|
OUTPUT
|
||||||
|
@ -384,6 +390,11 @@ notdir SP <size> LF
|
||||||
is printed when, during symlink resolution, a file is used as a
|
is printed when, during symlink resolution, a file is used as a
|
||||||
directory name.
|
directory name.
|
||||||
|
|
||||||
|
Alternatively, when `-Z` is passed, the line feeds in any of the above examples
|
||||||
|
are replaced with NUL terminators. This ensures that output will be parsable if
|
||||||
|
the output itself would contain a linefeed and is thus recommended for
|
||||||
|
scripting purposes.
|
||||||
|
|
||||||
CAVEATS
|
CAVEATS
|
||||||
-------
|
-------
|
||||||
|
|
||||||
|
|
|
@ -42,7 +42,8 @@ struct batch_options {
|
||||||
int all_objects;
|
int all_objects;
|
||||||
int unordered;
|
int unordered;
|
||||||
int transform_mode; /* may be 'w' or 'c' for --filters or --textconv */
|
int transform_mode; /* may be 'w' or 'c' for --filters or --textconv */
|
||||||
int nul_terminated;
|
char input_delim;
|
||||||
|
char output_delim;
|
||||||
const char *format;
|
const char *format;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
@ -437,11 +438,12 @@ static void print_object_or_die(struct batch_options *opt, struct expand_data *d
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
static void print_default_format(struct strbuf *scratch, struct expand_data *data)
|
static void print_default_format(struct strbuf *scratch, struct expand_data *data,
|
||||||
|
struct batch_options *opt)
|
||||||
{
|
{
|
||||||
strbuf_addf(scratch, "%s %s %"PRIuMAX"\n", oid_to_hex(&data->oid),
|
strbuf_addf(scratch, "%s %s %"PRIuMAX"%c", oid_to_hex(&data->oid),
|
||||||
type_name(data->type),
|
type_name(data->type),
|
||||||
(uintmax_t)data->size);
|
(uintmax_t)data->size, opt->output_delim);
|
||||||
}
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
|
@ -470,8 +472,8 @@ static void batch_object_write(const char *obj_name,
|
||||||
&data->oid, &data->info,
|
&data->oid, &data->info,
|
||||||
OBJECT_INFO_LOOKUP_REPLACE);
|
OBJECT_INFO_LOOKUP_REPLACE);
|
||||||
if (ret < 0) {
|
if (ret < 0) {
|
||||||
printf("%s missing\n",
|
printf("%s missing%c",
|
||||||
obj_name ? obj_name : oid_to_hex(&data->oid));
|
obj_name ? obj_name : oid_to_hex(&data->oid), opt->output_delim);
|
||||||
fflush(stdout);
|
fflush(stdout);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
@ -492,17 +494,17 @@ static void batch_object_write(const char *obj_name,
|
||||||
strbuf_reset(scratch);
|
strbuf_reset(scratch);
|
||||||
|
|
||||||
if (!opt->format) {
|
if (!opt->format) {
|
||||||
print_default_format(scratch, data);
|
print_default_format(scratch, data, opt);
|
||||||
} else {
|
} else {
|
||||||
strbuf_expand(scratch, opt->format, expand_format, data);
|
strbuf_expand(scratch, opt->format, expand_format, data);
|
||||||
strbuf_addch(scratch, '\n');
|
strbuf_addch(scratch, opt->output_delim);
|
||||||
}
|
}
|
||||||
|
|
||||||
batch_write(opt, scratch->buf, scratch->len);
|
batch_write(opt, scratch->buf, scratch->len);
|
||||||
|
|
||||||
if (opt->batch_mode == BATCH_MODE_CONTENTS) {
|
if (opt->batch_mode == BATCH_MODE_CONTENTS) {
|
||||||
print_object_or_die(opt, data);
|
print_object_or_die(opt, data);
|
||||||
batch_write(opt, "\n", 1);
|
batch_write(opt, &opt->output_delim, 1);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -520,22 +522,25 @@ static void batch_one_object(const char *obj_name,
|
||||||
if (result != FOUND) {
|
if (result != FOUND) {
|
||||||
switch (result) {
|
switch (result) {
|
||||||
case MISSING_OBJECT:
|
case MISSING_OBJECT:
|
||||||
printf("%s missing\n", obj_name);
|
printf("%s missing%c", obj_name, opt->output_delim);
|
||||||
break;
|
break;
|
||||||
case SHORT_NAME_AMBIGUOUS:
|
case SHORT_NAME_AMBIGUOUS:
|
||||||
printf("%s ambiguous\n", obj_name);
|
printf("%s ambiguous%c", obj_name, opt->output_delim);
|
||||||
break;
|
break;
|
||||||
case DANGLING_SYMLINK:
|
case DANGLING_SYMLINK:
|
||||||
printf("dangling %"PRIuMAX"\n%s\n",
|
printf("dangling %"PRIuMAX"%c%s%c",
|
||||||
(uintmax_t)strlen(obj_name), obj_name);
|
(uintmax_t)strlen(obj_name),
|
||||||
|
opt->output_delim, obj_name, opt->output_delim);
|
||||||
break;
|
break;
|
||||||
case SYMLINK_LOOP:
|
case SYMLINK_LOOP:
|
||||||
printf("loop %"PRIuMAX"\n%s\n",
|
printf("loop %"PRIuMAX"%c%s%c",
|
||||||
(uintmax_t)strlen(obj_name), obj_name);
|
(uintmax_t)strlen(obj_name),
|
||||||
|
opt->output_delim, obj_name, opt->output_delim);
|
||||||
break;
|
break;
|
||||||
case NOT_DIR:
|
case NOT_DIR:
|
||||||
printf("notdir %"PRIuMAX"\n%s\n",
|
printf("notdir %"PRIuMAX"%c%s%c",
|
||||||
(uintmax_t)strlen(obj_name), obj_name);
|
(uintmax_t)strlen(obj_name),
|
||||||
|
opt->output_delim, obj_name, opt->output_delim);
|
||||||
break;
|
break;
|
||||||
default:
|
default:
|
||||||
BUG("unknown get_sha1_with_context result %d\n",
|
BUG("unknown get_sha1_with_context result %d\n",
|
||||||
|
@ -547,9 +552,9 @@ static void batch_one_object(const char *obj_name,
|
||||||
}
|
}
|
||||||
|
|
||||||
if (ctx.mode == 0) {
|
if (ctx.mode == 0) {
|
||||||
printf("symlink %"PRIuMAX"\n%s\n",
|
printf("symlink %"PRIuMAX"%c%s%c",
|
||||||
(uintmax_t)ctx.symlink_path.len,
|
(uintmax_t)ctx.symlink_path.len,
|
||||||
ctx.symlink_path.buf);
|
opt->output_delim, ctx.symlink_path.buf, opt->output_delim);
|
||||||
fflush(stdout);
|
fflush(stdout);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
@ -694,20 +699,12 @@ static void batch_objects_command(struct batch_options *opt,
|
||||||
struct queued_cmd *queued_cmd = NULL;
|
struct queued_cmd *queued_cmd = NULL;
|
||||||
size_t alloc = 0, nr = 0;
|
size_t alloc = 0, nr = 0;
|
||||||
|
|
||||||
while (1) {
|
while (strbuf_getdelim_strip_crlf(&input, stdin, opt->input_delim) != EOF) {
|
||||||
int i, ret;
|
int i;
|
||||||
const struct parse_cmd *cmd = NULL;
|
const struct parse_cmd *cmd = NULL;
|
||||||
const char *p = NULL, *cmd_end;
|
const char *p = NULL, *cmd_end;
|
||||||
struct queued_cmd call = {0};
|
struct queued_cmd call = {0};
|
||||||
|
|
||||||
if (opt->nul_terminated)
|
|
||||||
ret = strbuf_getline_nul(&input, stdin);
|
|
||||||
else
|
|
||||||
ret = strbuf_getline(&input, stdin);
|
|
||||||
|
|
||||||
if (ret)
|
|
||||||
break;
|
|
||||||
|
|
||||||
if (!input.len)
|
if (!input.len)
|
||||||
die(_("empty command in input"));
|
die(_("empty command in input"));
|
||||||
if (isspace(*input.buf))
|
if (isspace(*input.buf))
|
||||||
|
@ -851,16 +848,7 @@ static int batch_objects(struct batch_options *opt)
|
||||||
goto cleanup;
|
goto cleanup;
|
||||||
}
|
}
|
||||||
|
|
||||||
while (1) {
|
while (strbuf_getdelim_strip_crlf(&input, stdin, opt->input_delim) != EOF) {
|
||||||
int ret;
|
|
||||||
if (opt->nul_terminated)
|
|
||||||
ret = strbuf_getline_nul(&input, stdin);
|
|
||||||
else
|
|
||||||
ret = strbuf_getline(&input, stdin);
|
|
||||||
|
|
||||||
if (ret == EOF)
|
|
||||||
break;
|
|
||||||
|
|
||||||
if (data.split_on_whitespace) {
|
if (data.split_on_whitespace) {
|
||||||
/*
|
/*
|
||||||
* Split at first whitespace, tying off the beginning
|
* Split at first whitespace, tying off the beginning
|
||||||
|
@ -929,6 +917,8 @@ int cmd_cat_file(int argc, const char **argv, const char *prefix)
|
||||||
const char *exp_type = NULL, *obj_name = NULL;
|
const char *exp_type = NULL, *obj_name = NULL;
|
||||||
struct batch_options batch = {0};
|
struct batch_options batch = {0};
|
||||||
int unknown_type = 0;
|
int unknown_type = 0;
|
||||||
|
int input_nul_terminated = 0;
|
||||||
|
int nul_terminated = 0;
|
||||||
|
|
||||||
const char * const usage[] = {
|
const char * const usage[] = {
|
||||||
N_("git cat-file <type> <object>"),
|
N_("git cat-file <type> <object>"),
|
||||||
|
@ -936,7 +926,7 @@ int cmd_cat_file(int argc, const char **argv, const char *prefix)
|
||||||
N_("git cat-file (-t | -s) [--allow-unknown-type] <object>"),
|
N_("git cat-file (-t | -s) [--allow-unknown-type] <object>"),
|
||||||
N_("git cat-file (--batch | --batch-check | --batch-command) [--batch-all-objects]\n"
|
N_("git cat-file (--batch | --batch-check | --batch-command) [--batch-all-objects]\n"
|
||||||
" [--buffer] [--follow-symlinks] [--unordered]\n"
|
" [--buffer] [--follow-symlinks] [--unordered]\n"
|
||||||
" [--textconv | --filters] [-z]"),
|
" [--textconv | --filters] [-Z]"),
|
||||||
N_("git cat-file (--textconv | --filters)\n"
|
N_("git cat-file (--textconv | --filters)\n"
|
||||||
" [<rev>:<path|tree-ish> | --path=<path|tree-ish> <rev>]"),
|
" [<rev>:<path|tree-ish> | --path=<path|tree-ish> <rev>]"),
|
||||||
NULL
|
NULL
|
||||||
|
@ -965,7 +955,9 @@ int cmd_cat_file(int argc, const char **argv, const char *prefix)
|
||||||
N_("like --batch, but don't emit <contents>"),
|
N_("like --batch, but don't emit <contents>"),
|
||||||
PARSE_OPT_OPTARG | PARSE_OPT_NONEG,
|
PARSE_OPT_OPTARG | PARSE_OPT_NONEG,
|
||||||
batch_option_callback),
|
batch_option_callback),
|
||||||
OPT_BOOL('z', NULL, &batch.nul_terminated, N_("stdin is NUL-terminated")),
|
OPT_BOOL_F('z', NULL, &input_nul_terminated, N_("stdin is NUL-terminated"),
|
||||||
|
PARSE_OPT_HIDDEN),
|
||||||
|
OPT_BOOL('Z', NULL, &nul_terminated, N_("stdin and stdout is NUL-terminated")),
|
||||||
OPT_CALLBACK_F(0, "batch-command", &batch, N_("format"),
|
OPT_CALLBACK_F(0, "batch-command", &batch, N_("format"),
|
||||||
N_("read commands from stdin"),
|
N_("read commands from stdin"),
|
||||||
PARSE_OPT_OPTARG | PARSE_OPT_NONEG,
|
PARSE_OPT_OPTARG | PARSE_OPT_NONEG,
|
||||||
|
@ -1024,9 +1016,18 @@ int cmd_cat_file(int argc, const char **argv, const char *prefix)
|
||||||
else if (batch.all_objects)
|
else if (batch.all_objects)
|
||||||
usage_msg_optf(_("'%s' requires a batch mode"), usage, options,
|
usage_msg_optf(_("'%s' requires a batch mode"), usage, options,
|
||||||
"--batch-all-objects");
|
"--batch-all-objects");
|
||||||
else if (batch.nul_terminated)
|
else if (input_nul_terminated)
|
||||||
usage_msg_optf(_("'%s' requires a batch mode"), usage, options,
|
usage_msg_optf(_("'%s' requires a batch mode"), usage, options,
|
||||||
"-z");
|
"-z");
|
||||||
|
else if (nul_terminated)
|
||||||
|
usage_msg_optf(_("'%s' requires a batch mode"), usage, options,
|
||||||
|
"-Z");
|
||||||
|
|
||||||
|
batch.input_delim = batch.output_delim = '\n';
|
||||||
|
if (input_nul_terminated)
|
||||||
|
batch.input_delim = '\0';
|
||||||
|
if (nul_terminated)
|
||||||
|
batch.input_delim = batch.output_delim = '\0';
|
||||||
|
|
||||||
/* Batch defaults */
|
/* Batch defaults */
|
||||||
if (batch.buffer_output < 0)
|
if (batch.buffer_output < 0)
|
||||||
|
|
11
strbuf.c
11
strbuf.c
|
@ -721,11 +721,11 @@ static int strbuf_getdelim(struct strbuf *sb, FILE *fp, int term)
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
int strbuf_getline(struct strbuf *sb, FILE *fp)
|
int strbuf_getdelim_strip_crlf(struct strbuf *sb, FILE *fp, int term)
|
||||||
{
|
{
|
||||||
if (strbuf_getwholeline(sb, fp, '\n'))
|
if (strbuf_getwholeline(sb, fp, term))
|
||||||
return EOF;
|
return EOF;
|
||||||
if (sb->buf[sb->len - 1] == '\n') {
|
if (term == '\n' && sb->buf[sb->len - 1] == '\n') {
|
||||||
strbuf_setlen(sb, sb->len - 1);
|
strbuf_setlen(sb, sb->len - 1);
|
||||||
if (sb->len && sb->buf[sb->len - 1] == '\r')
|
if (sb->len && sb->buf[sb->len - 1] == '\r')
|
||||||
strbuf_setlen(sb, sb->len - 1);
|
strbuf_setlen(sb, sb->len - 1);
|
||||||
|
@ -733,6 +733,11 @@ int strbuf_getline(struct strbuf *sb, FILE *fp)
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
int strbuf_getline(struct strbuf *sb, FILE *fp)
|
||||||
|
{
|
||||||
|
return strbuf_getdelim_strip_crlf(sb, fp, '\n');
|
||||||
|
}
|
||||||
|
|
||||||
int strbuf_getline_lf(struct strbuf *sb, FILE *fp)
|
int strbuf_getline_lf(struct strbuf *sb, FILE *fp)
|
||||||
{
|
{
|
||||||
return strbuf_getdelim(sb, fp, '\n');
|
return strbuf_getdelim(sb, fp, '\n');
|
||||||
|
|
12
strbuf.h
12
strbuf.h
|
@ -475,6 +475,18 @@ int strbuf_readlink(struct strbuf *sb, const char *path, size_t hint);
|
||||||
*/
|
*/
|
||||||
ssize_t strbuf_write(struct strbuf *sb, FILE *stream);
|
ssize_t strbuf_write(struct strbuf *sb, FILE *stream);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Read from a FILE * until the specified terminator is encountered,
|
||||||
|
* overwriting the existing contents of the strbuf.
|
||||||
|
*
|
||||||
|
* Reading stops after the terminator or at EOF. The terminator is
|
||||||
|
* removed from the buffer before returning. If the terminator is LF
|
||||||
|
* and if it is preceded by a CR, then the whole CRLF is stripped.
|
||||||
|
* Returns 0 unless there was nothing left before EOF, in which case
|
||||||
|
* it returns `EOF`.
|
||||||
|
*/
|
||||||
|
int strbuf_getdelim_strip_crlf(struct strbuf *sb, FILE *fp, int term);
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Read a line from a FILE *, overwriting the existing contents of
|
* Read a line from a FILE *, overwriting the existing contents of
|
||||||
* the strbuf. The strbuf_getline*() family of functions share
|
* the strbuf. The strbuf_getline*() family of functions share
|
||||||
|
|
|
@ -89,7 +89,8 @@ done
|
||||||
for opt in --buffer \
|
for opt in --buffer \
|
||||||
--follow-symlinks \
|
--follow-symlinks \
|
||||||
--batch-all-objects \
|
--batch-all-objects \
|
||||||
-z
|
-z \
|
||||||
|
-Z
|
||||||
do
|
do
|
||||||
test_expect_success "usage: bad option combination: $opt without batch mode" '
|
test_expect_success "usage: bad option combination: $opt without batch mode" '
|
||||||
test_incompatible_usage git cat-file $opt &&
|
test_incompatible_usage git cat-file $opt &&
|
||||||
|
@ -109,26 +110,12 @@ strlen () {
|
||||||
echo_without_newline "$1" | wc -c | sed -e 's/^ *//'
|
echo_without_newline "$1" | wc -c | sed -e 's/^ *//'
|
||||||
}
|
}
|
||||||
|
|
||||||
maybe_remove_timestamp () {
|
|
||||||
if test -z "$2"; then
|
|
||||||
echo_without_newline "$1"
|
|
||||||
else
|
|
||||||
echo_without_newline "$(printf '%s\n' "$1" | remove_timestamp)"
|
|
||||||
fi
|
|
||||||
}
|
|
||||||
|
|
||||||
remove_timestamp () {
|
|
||||||
sed -e 's/ [0-9][0-9]* [-+][0-9][0-9][0-9][0-9]$//'
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
run_tests () {
|
run_tests () {
|
||||||
type=$1
|
type=$1
|
||||||
sha1=$2
|
sha1=$2
|
||||||
size=$3
|
size=$3
|
||||||
content=$4
|
content=$4
|
||||||
pretty_content=$5
|
pretty_content=$5
|
||||||
no_ts=$6
|
|
||||||
|
|
||||||
batch_output="$sha1 $type $size
|
batch_output="$sha1 $type $size
|
||||||
$content"
|
$content"
|
||||||
|
@ -163,21 +150,21 @@ $content"
|
||||||
|
|
||||||
test -z "$content" ||
|
test -z "$content" ||
|
||||||
test_expect_success "Content of $type is correct" '
|
test_expect_success "Content of $type is correct" '
|
||||||
maybe_remove_timestamp "$content" $no_ts >expect &&
|
echo_without_newline "$content" >expect &&
|
||||||
maybe_remove_timestamp "$(git cat-file $type $sha1)" $no_ts >actual &&
|
git cat-file $type $sha1 >actual &&
|
||||||
test_cmp expect actual
|
test_cmp expect actual
|
||||||
'
|
'
|
||||||
|
|
||||||
test_expect_success "Pretty content of $type is correct" '
|
test_expect_success "Pretty content of $type is correct" '
|
||||||
maybe_remove_timestamp "$pretty_content" $no_ts >expect &&
|
echo_without_newline "$pretty_content" >expect &&
|
||||||
maybe_remove_timestamp "$(git cat-file -p $sha1)" $no_ts >actual &&
|
git cat-file -p $sha1 >actual &&
|
||||||
test_cmp expect actual
|
test_cmp expect actual
|
||||||
'
|
'
|
||||||
|
|
||||||
test -z "$content" ||
|
test -z "$content" ||
|
||||||
test_expect_success "--batch output of $type is correct" '
|
test_expect_success "--batch output of $type is correct" '
|
||||||
maybe_remove_timestamp "$batch_output" $no_ts >expect &&
|
echo "$batch_output" >expect &&
|
||||||
maybe_remove_timestamp "$(echo $sha1 | git cat-file --batch)" $no_ts >actual &&
|
echo $sha1 | git cat-file --batch >actual &&
|
||||||
test_cmp expect actual
|
test_cmp expect actual
|
||||||
'
|
'
|
||||||
|
|
||||||
|
@ -191,9 +178,8 @@ $content"
|
||||||
do
|
do
|
||||||
test -z "$content" ||
|
test -z "$content" ||
|
||||||
test_expect_success "--batch-command $opt output of $type content is correct" '
|
test_expect_success "--batch-command $opt output of $type content is correct" '
|
||||||
maybe_remove_timestamp "$batch_output" $no_ts >expect &&
|
echo "$batch_output" >expect &&
|
||||||
maybe_remove_timestamp "$(test_write_lines "contents $sha1" |
|
test_write_lines "contents $sha1" | git cat-file --batch-command $opt >actual &&
|
||||||
git cat-file --batch-command $opt)" $no_ts >actual &&
|
|
||||||
test_cmp expect actual
|
test_cmp expect actual
|
||||||
'
|
'
|
||||||
|
|
||||||
|
@ -228,10 +214,9 @@ $content"
|
||||||
test_expect_success "--batch without type ($type)" '
|
test_expect_success "--batch without type ($type)" '
|
||||||
{
|
{
|
||||||
echo "$size" &&
|
echo "$size" &&
|
||||||
maybe_remove_timestamp "$content" $no_ts
|
echo "$content"
|
||||||
} >expect &&
|
} >expect &&
|
||||||
echo $sha1 | git cat-file --batch="%(objectsize)" >actual.full &&
|
echo $sha1 | git cat-file --batch="%(objectsize)" >actual &&
|
||||||
maybe_remove_timestamp "$(cat actual.full)" $no_ts >actual &&
|
|
||||||
test_cmp expect actual
|
test_cmp expect actual
|
||||||
'
|
'
|
||||||
|
|
||||||
|
@ -239,10 +224,9 @@ $content"
|
||||||
test_expect_success "--batch without size ($type)" '
|
test_expect_success "--batch without size ($type)" '
|
||||||
{
|
{
|
||||||
echo "$type" &&
|
echo "$type" &&
|
||||||
maybe_remove_timestamp "$content" $no_ts
|
echo "$content"
|
||||||
} >expect &&
|
} >expect &&
|
||||||
echo $sha1 | git cat-file --batch="%(objecttype)" >actual.full &&
|
echo $sha1 | git cat-file --batch="%(objecttype)" >actual &&
|
||||||
maybe_remove_timestamp "$(cat actual.full)" $no_ts >actual &&
|
|
||||||
test_cmp expect actual
|
test_cmp expect actual
|
||||||
'
|
'
|
||||||
}
|
}
|
||||||
|
@ -284,7 +268,7 @@ test_expect_success '--batch-check without %(rest) considers whole line' '
|
||||||
|
|
||||||
tree_sha1=$(git write-tree)
|
tree_sha1=$(git write-tree)
|
||||||
tree_size=$(($(test_oid rawsz) + 13))
|
tree_size=$(($(test_oid rawsz) + 13))
|
||||||
tree_pretty_content="100644 blob $hello_sha1 hello"
|
tree_pretty_content="100644 blob $hello_sha1 hello${LF}"
|
||||||
|
|
||||||
run_tests 'tree' $tree_sha1 $tree_size "" "$tree_pretty_content"
|
run_tests 'tree' $tree_sha1 $tree_size "" "$tree_pretty_content"
|
||||||
|
|
||||||
|
@ -292,12 +276,12 @@ commit_message="Initial commit"
|
||||||
commit_sha1=$(echo_without_newline "$commit_message" | git commit-tree $tree_sha1)
|
commit_sha1=$(echo_without_newline "$commit_message" | git commit-tree $tree_sha1)
|
||||||
commit_size=$(($(test_oid hexsz) + 137))
|
commit_size=$(($(test_oid hexsz) + 137))
|
||||||
commit_content="tree $tree_sha1
|
commit_content="tree $tree_sha1
|
||||||
author $GIT_AUTHOR_NAME <$GIT_AUTHOR_EMAIL> 0 +0000
|
author $GIT_AUTHOR_NAME <$GIT_AUTHOR_EMAIL> $GIT_AUTHOR_DATE
|
||||||
committer $GIT_COMMITTER_NAME <$GIT_COMMITTER_EMAIL> 0 +0000
|
committer $GIT_COMMITTER_NAME <$GIT_COMMITTER_EMAIL> $GIT_COMMITTER_DATE
|
||||||
|
|
||||||
$commit_message"
|
$commit_message"
|
||||||
|
|
||||||
run_tests 'commit' $commit_sha1 $commit_size "$commit_content" "$commit_content" 1
|
run_tests 'commit' $commit_sha1 $commit_size "$commit_content" "$commit_content"
|
||||||
|
|
||||||
tag_header_without_timestamp="object $hello_sha1
|
tag_header_without_timestamp="object $hello_sha1
|
||||||
type blob
|
type blob
|
||||||
|
@ -311,11 +295,13 @@ $tag_description"
|
||||||
tag_sha1=$(echo_without_newline "$tag_content" | git hash-object -t tag --stdin -w)
|
tag_sha1=$(echo_without_newline "$tag_content" | git hash-object -t tag --stdin -w)
|
||||||
tag_size=$(strlen "$tag_content")
|
tag_size=$(strlen "$tag_content")
|
||||||
|
|
||||||
run_tests 'tag' $tag_sha1 $tag_size "$tag_content" "$tag_content" 1
|
run_tests 'tag' $tag_sha1 $tag_size "$tag_content" "$tag_content"
|
||||||
|
|
||||||
test_expect_success \
|
test_expect_success "Reach a blob from a tag pointing to it" '
|
||||||
"Reach a blob from a tag pointing to it" \
|
echo_without_newline "$hello_content" >expect &&
|
||||||
"test '$hello_content' = \"\$(git cat-file blob $tag_sha1)\""
|
git cat-file blob $tag_sha1 >actual &&
|
||||||
|
test_cmp expect actual
|
||||||
|
'
|
||||||
|
|
||||||
for batch in batch batch-check batch-command
|
for batch in batch batch-check batch-command
|
||||||
do
|
do
|
||||||
|
@ -351,30 +337,47 @@ do
|
||||||
done
|
done
|
||||||
|
|
||||||
test_expect_success "--batch-check for a non-existent named object" '
|
test_expect_success "--batch-check for a non-existent named object" '
|
||||||
test "foobar42 missing
|
cat >expect <<-EOF &&
|
||||||
foobar84 missing" = \
|
foobar42 missing
|
||||||
"$( ( echo foobar42 && echo_without_newline foobar84 ) | git cat-file --batch-check)"
|
foobar84 missing
|
||||||
|
EOF
|
||||||
|
|
||||||
|
printf "foobar42\nfoobar84" >in &&
|
||||||
|
git cat-file --batch-check <in >actual &&
|
||||||
|
test_cmp expect actual
|
||||||
'
|
'
|
||||||
|
|
||||||
test_expect_success "--batch-check for a non-existent hash" '
|
test_expect_success "--batch-check for a non-existent hash" '
|
||||||
test "0000000000000000000000000000000000000042 missing
|
cat >expect <<-EOF &&
|
||||||
0000000000000000000000000000000000000084 missing" = \
|
0000000000000000000000000000000000000042 missing
|
||||||
"$( ( echo 0000000000000000000000000000000000000042 &&
|
0000000000000000000000000000000000000084 missing
|
||||||
echo_without_newline 0000000000000000000000000000000000000084 ) |
|
EOF
|
||||||
git cat-file --batch-check)"
|
|
||||||
|
printf "0000000000000000000000000000000000000042\n0000000000000000000000000000000000000084" >in &&
|
||||||
|
git cat-file --batch-check <in >actual &&
|
||||||
|
test_cmp expect actual
|
||||||
'
|
'
|
||||||
|
|
||||||
test_expect_success "--batch for an existent and a non-existent hash" '
|
test_expect_success "--batch for an existent and a non-existent hash" '
|
||||||
test "$tag_sha1 tag $tag_size
|
cat >expect <<-EOF &&
|
||||||
$tag_content
|
$tag_sha1 tag $tag_size
|
||||||
0000000000000000000000000000000000000000 missing" = \
|
$tag_content
|
||||||
"$( ( echo $tag_sha1 &&
|
0000000000000000000000000000000000000000 missing
|
||||||
echo_without_newline 0000000000000000000000000000000000000000 ) |
|
EOF
|
||||||
git cat-file --batch)"
|
|
||||||
|
printf "$tag_sha1\n0000000000000000000000000000000000000000" >in &&
|
||||||
|
git cat-file --batch <in >actual &&
|
||||||
|
test_cmp expect actual
|
||||||
'
|
'
|
||||||
|
|
||||||
test_expect_success "--batch-check for an empty line" '
|
test_expect_success "--batch-check for an empty line" '
|
||||||
test " missing" = "$(echo | git cat-file --batch-check)"
|
cat >expect <<-EOF &&
|
||||||
|
missing
|
||||||
|
EOF
|
||||||
|
|
||||||
|
echo >in &&
|
||||||
|
git cat-file --batch-check <in >actual &&
|
||||||
|
test_cmp expect actual
|
||||||
'
|
'
|
||||||
|
|
||||||
test_expect_success 'empty --batch-check notices missing object' '
|
test_expect_success 'empty --batch-check notices missing object' '
|
||||||
|
@ -390,23 +393,34 @@ deadbeef
|
||||||
|
|
||||||
"
|
"
|
||||||
|
|
||||||
batch_output="$hello_sha1 blob $hello_size
|
printf "%s\0" \
|
||||||
$hello_content
|
"$hello_sha1 blob $hello_size" \
|
||||||
$commit_sha1 commit $commit_size
|
"$hello_content" \
|
||||||
$commit_content
|
"$commit_sha1 commit $commit_size" \
|
||||||
$tag_sha1 tag $tag_size
|
"$commit_content" \
|
||||||
$tag_content
|
"$tag_sha1 tag $tag_size" \
|
||||||
deadbeef missing
|
"$tag_content" \
|
||||||
missing"
|
"deadbeef missing" \
|
||||||
|
" missing" >batch_output
|
||||||
|
|
||||||
test_expect_success '--batch with multiple sha1s gives correct format' '
|
test_expect_success '--batch with multiple sha1s gives correct format' '
|
||||||
test "$(maybe_remove_timestamp "$batch_output" 1)" = "$(maybe_remove_timestamp "$(echo_without_newline "$batch_input" | git cat-file --batch)" 1)"
|
tr "\0" "\n" <batch_output >expect &&
|
||||||
|
echo_without_newline "$batch_input" >in &&
|
||||||
|
git cat-file --batch <in >actual &&
|
||||||
|
test_cmp expect actual
|
||||||
'
|
'
|
||||||
|
|
||||||
test_expect_success '--batch, -z with multiple sha1s gives correct format' '
|
test_expect_success '--batch, -z with multiple sha1s gives correct format' '
|
||||||
echo_without_newline_nul "$batch_input" >in &&
|
echo_without_newline_nul "$batch_input" >in &&
|
||||||
test "$(maybe_remove_timestamp "$batch_output" 1)" = \
|
tr "\0" "\n" <batch_output >expect &&
|
||||||
"$(maybe_remove_timestamp "$(git cat-file --batch -z <in)" 1)"
|
git cat-file --batch -z <in >actual &&
|
||||||
|
test_cmp expect actual
|
||||||
|
'
|
||||||
|
|
||||||
|
test_expect_success '--batch, -Z with multiple sha1s gives correct format' '
|
||||||
|
echo_without_newline_nul "$batch_input" >in &&
|
||||||
|
git cat-file --batch -Z <in >actual &&
|
||||||
|
test_cmp batch_output actual
|
||||||
'
|
'
|
||||||
|
|
||||||
batch_check_input="$hello_sha1
|
batch_check_input="$hello_sha1
|
||||||
|
@ -417,36 +431,55 @@ deadbeef
|
||||||
|
|
||||||
"
|
"
|
||||||
|
|
||||||
batch_check_output="$hello_sha1 blob $hello_size
|
printf "%s\0" \
|
||||||
$tree_sha1 tree $tree_size
|
"$hello_sha1 blob $hello_size" \
|
||||||
$commit_sha1 commit $commit_size
|
"$tree_sha1 tree $tree_size" \
|
||||||
$tag_sha1 tag $tag_size
|
"$commit_sha1 commit $commit_size" \
|
||||||
deadbeef missing
|
"$tag_sha1 tag $tag_size" \
|
||||||
missing"
|
"deadbeef missing" \
|
||||||
|
" missing" >batch_check_output
|
||||||
|
|
||||||
test_expect_success "--batch-check with multiple sha1s gives correct format" '
|
test_expect_success "--batch-check with multiple sha1s gives correct format" '
|
||||||
test "$batch_check_output" = \
|
tr "\0" "\n" <batch_check_output >expect &&
|
||||||
"$(echo_without_newline "$batch_check_input" | git cat-file --batch-check)"
|
echo_without_newline "$batch_check_input" >in &&
|
||||||
|
git cat-file --batch-check <in >actual &&
|
||||||
|
test_cmp expect actual
|
||||||
'
|
'
|
||||||
|
|
||||||
test_expect_success "--batch-check, -z with multiple sha1s gives correct format" '
|
test_expect_success "--batch-check, -z with multiple sha1s gives correct format" '
|
||||||
|
tr "\0" "\n" <batch_check_output >expect &&
|
||||||
echo_without_newline_nul "$batch_check_input" >in &&
|
echo_without_newline_nul "$batch_check_input" >in &&
|
||||||
test "$batch_check_output" = "$(git cat-file --batch-check -z <in)"
|
git cat-file --batch-check -z <in >actual &&
|
||||||
|
test_cmp expect actual
|
||||||
'
|
'
|
||||||
|
|
||||||
test_expect_success FUNNYNAMES '--batch-check, -z with newline in input' '
|
test_expect_success "--batch-check, -Z with multiple sha1s gives correct format" '
|
||||||
|
echo_without_newline_nul "$batch_check_input" >in &&
|
||||||
|
git cat-file --batch-check -Z <in >actual &&
|
||||||
|
test_cmp batch_check_output actual
|
||||||
|
'
|
||||||
|
|
||||||
|
test_expect_success FUNNYNAMES 'setup with newline in input' '
|
||||||
touch -- "newline${LF}embedded" &&
|
touch -- "newline${LF}embedded" &&
|
||||||
git add -- "newline${LF}embedded" &&
|
git add -- "newline${LF}embedded" &&
|
||||||
git commit -m "file with newline embedded" &&
|
git commit -m "file with newline embedded" &&
|
||||||
test_tick &&
|
test_tick &&
|
||||||
|
|
||||||
printf "HEAD:newline${LF}embedded" >in &&
|
printf "HEAD:newline${LF}embedded" >in
|
||||||
git cat-file --batch-check -z <in >actual &&
|
'
|
||||||
|
|
||||||
|
test_expect_success FUNNYNAMES '--batch-check, -z with newline in input' '
|
||||||
|
git cat-file --batch-check -z <in >actual &&
|
||||||
echo "$(git rev-parse "HEAD:newline${LF}embedded") blob 0" >expect &&
|
echo "$(git rev-parse "HEAD:newline${LF}embedded") blob 0" >expect &&
|
||||||
test_cmp expect actual
|
test_cmp expect actual
|
||||||
'
|
'
|
||||||
|
|
||||||
|
test_expect_success FUNNYNAMES '--batch-check, -Z with newline in input' '
|
||||||
|
git cat-file --batch-check -Z <in >actual &&
|
||||||
|
printf "%s\0" "$(git rev-parse "HEAD:newline${LF}embedded") blob 0" >expect &&
|
||||||
|
test_cmp expect actual
|
||||||
|
'
|
||||||
|
|
||||||
batch_command_multiple_info="info $hello_sha1
|
batch_command_multiple_info="info $hello_sha1
|
||||||
info $tree_sha1
|
info $tree_sha1
|
||||||
info $commit_sha1
|
info $commit_sha1
|
||||||
|
@ -470,7 +503,13 @@ test_expect_success '--batch-command with multiple info calls gives correct form
|
||||||
echo "$batch_command_multiple_info" | tr "\n" "\0" >in &&
|
echo "$batch_command_multiple_info" | tr "\n" "\0" >in &&
|
||||||
git cat-file --batch-command --buffer -z <in >actual &&
|
git cat-file --batch-command --buffer -z <in >actual &&
|
||||||
|
|
||||||
test_cmp expect actual
|
test_cmp expect actual &&
|
||||||
|
|
||||||
|
echo "$batch_command_multiple_info" | tr "\n" "\0" >in &&
|
||||||
|
tr "\n" "\0" <expect >expect_nul &&
|
||||||
|
git cat-file --batch-command --buffer -Z <in >actual &&
|
||||||
|
|
||||||
|
test_cmp expect_nul actual
|
||||||
'
|
'
|
||||||
|
|
||||||
batch_command_multiple_contents="contents $hello_sha1
|
batch_command_multiple_contents="contents $hello_sha1
|
||||||
|
@ -480,27 +519,30 @@ contents deadbeef
|
||||||
flush"
|
flush"
|
||||||
|
|
||||||
test_expect_success '--batch-command with multiple command calls gives correct format' '
|
test_expect_success '--batch-command with multiple command calls gives correct format' '
|
||||||
remove_timestamp >expect <<-EOF &&
|
printf "%s\0" \
|
||||||
$hello_sha1 blob $hello_size
|
"$hello_sha1 blob $hello_size" \
|
||||||
$hello_content
|
"$hello_content" \
|
||||||
$commit_sha1 commit $commit_size
|
"$commit_sha1 commit $commit_size" \
|
||||||
$commit_content
|
"$commit_content" \
|
||||||
$tag_sha1 tag $tag_size
|
"$tag_sha1 tag $tag_size" \
|
||||||
$tag_content
|
"$tag_content" \
|
||||||
deadbeef missing
|
"deadbeef missing" >expect_nul &&
|
||||||
EOF
|
tr "\0" "\n" <expect_nul >expect &&
|
||||||
|
|
||||||
echo "$batch_command_multiple_contents" >in &&
|
echo "$batch_command_multiple_contents" >in &&
|
||||||
git cat-file --batch-command --buffer <in >actual_raw &&
|
git cat-file --batch-command --buffer <in >actual &&
|
||||||
|
|
||||||
remove_timestamp <actual_raw >actual &&
|
|
||||||
test_cmp expect actual &&
|
test_cmp expect actual &&
|
||||||
|
|
||||||
echo "$batch_command_multiple_contents" | tr "\n" "\0" >in &&
|
echo "$batch_command_multiple_contents" | tr "\n" "\0" >in &&
|
||||||
git cat-file --batch-command --buffer -z <in >actual_raw &&
|
git cat-file --batch-command --buffer -z <in >actual &&
|
||||||
|
|
||||||
remove_timestamp <actual_raw >actual &&
|
test_cmp expect actual &&
|
||||||
test_cmp expect actual
|
|
||||||
|
echo "$batch_command_multiple_contents" | tr "\n" "\0" >in &&
|
||||||
|
git cat-file --batch-command --buffer -Z <in >actual &&
|
||||||
|
|
||||||
|
test_cmp expect_nul actual
|
||||||
'
|
'
|
||||||
|
|
||||||
test_expect_success 'setup blobs which are likely to delta' '
|
test_expect_success 'setup blobs which are likely to delta' '
|
||||||
|
@ -840,6 +882,13 @@ test_expect_success 'git cat-file --batch-check --follow-symlinks works for brok
|
||||||
test_cmp expect actual
|
test_cmp expect actual
|
||||||
'
|
'
|
||||||
|
|
||||||
|
test_expect_success 'git cat-file --batch-check --follow-symlinks -Z works for broken in-repo, same-dir links' '
|
||||||
|
printf "HEAD:broken-same-dir-link\0" >in &&
|
||||||
|
printf "dangling 25\0HEAD:broken-same-dir-link\0" >expect &&
|
||||||
|
git cat-file --batch-check --follow-symlinks -Z <in >actual &&
|
||||||
|
test_cmp expect actual
|
||||||
|
'
|
||||||
|
|
||||||
test_expect_success 'git cat-file --batch-check --follow-symlinks works for same-dir links-to-links' '
|
test_expect_success 'git cat-file --batch-check --follow-symlinks works for same-dir links-to-links' '
|
||||||
echo HEAD:link-to-link | git cat-file --batch-check --follow-symlinks >actual &&
|
echo HEAD:link-to-link | git cat-file --batch-check --follow-symlinks >actual &&
|
||||||
test_cmp found actual
|
test_cmp found actual
|
||||||
|
@ -854,6 +903,15 @@ test_expect_success 'git cat-file --batch-check --follow-symlinks works for pare
|
||||||
test_cmp expect actual
|
test_cmp expect actual
|
||||||
'
|
'
|
||||||
|
|
||||||
|
test_expect_success 'git cat-file --batch-check --follow-symlinks -Z works for parent-dir links' '
|
||||||
|
echo HEAD:dir/parent-dir-link | git cat-file --batch-check --follow-symlinks >actual &&
|
||||||
|
test_cmp found actual &&
|
||||||
|
printf "notdir 29\0HEAD:dir/parent-dir-link/nope\0" >expect &&
|
||||||
|
printf "HEAD:dir/parent-dir-link/nope\0" >in &&
|
||||||
|
git cat-file --batch-check --follow-symlinks -Z <in >actual &&
|
||||||
|
test_cmp expect actual
|
||||||
|
'
|
||||||
|
|
||||||
test_expect_success 'git cat-file --batch-check --follow-symlinks works for .. links' '
|
test_expect_success 'git cat-file --batch-check --follow-symlinks works for .. links' '
|
||||||
echo dangling 22 >expect &&
|
echo dangling 22 >expect &&
|
||||||
echo HEAD:dir/link-dir/nope >>expect &&
|
echo HEAD:dir/link-dir/nope >>expect &&
|
||||||
|
@ -968,6 +1026,13 @@ test_expect_success 'git cat-file --batch-check --follow-symlink breaks loops' '
|
||||||
test_cmp expect actual
|
test_cmp expect actual
|
||||||
'
|
'
|
||||||
|
|
||||||
|
test_expect_success 'git cat-file --batch-check --follow-symlink -Z breaks loops' '
|
||||||
|
printf "loop 10\0HEAD:loop1\0" >expect &&
|
||||||
|
printf "HEAD:loop1\0" >in &&
|
||||||
|
git cat-file --batch-check --follow-symlinks -Z <in >actual &&
|
||||||
|
test_cmp expect actual
|
||||||
|
'
|
||||||
|
|
||||||
test_expect_success 'git cat-file --batch --follow-symlink returns correct sha and mode' '
|
test_expect_success 'git cat-file --batch --follow-symlink returns correct sha and mode' '
|
||||||
echo HEAD:morx | git cat-file --batch >expect &&
|
echo HEAD:morx | git cat-file --batch >expect &&
|
||||||
echo HEAD:morx | git cat-file --batch --follow-symlinks >actual &&
|
echo HEAD:morx | git cat-file --batch --follow-symlinks >actual &&
|
||||||
|
|
Loading…
Reference in a new issue