git-cat-file: Add --batch option

--batch is similar to --batch-check, except that the contents of each object is
also printed. The output's form is:

<sha1> SP <type> SP <size> LF
<contents> LF

Signed-off-by: Adam Roben <aroben@apple.com>
Signed-off-by: Junio C Hamano <gitster@pobox.com>
This commit is contained in:
Adam Roben
2008-04-23 15:17:47 -04:00
committed by Junio C Hamano
parent 05d5667fec
commit a8128ed628
3 changed files with 117 additions and 38 deletions

View File

@ -9,7 +9,7 @@ git-cat-file - Provide content or type/size information for repository objects
SYNOPSIS SYNOPSIS
-------- --------
'git-cat-file' [-t | -s | -e | -p | <type>] <object> 'git-cat-file' [-t | -s | -e | -p | <type>] <object>
'git-cat-file' --batch-check < <list-of-objects> 'git-cat-file' [--batch | --batch-check] < <list-of-objects>
DESCRIPTION DESCRIPTION
----------- -----------
@ -50,6 +50,10 @@ OPTIONS
or to ask for a "blob" with <object> being a tag object that or to ask for a "blob" with <object> being a tag object that
points at it. points at it.
--batch::
Print the SHA1, type, size, and contents of each object provided on
stdin. May not be combined with any other options or arguments.
--batch-check:: --batch-check::
Print the SHA1, type, and size of each object provided on stdin. May not be Print the SHA1, type, and size of each object provided on stdin. May not be
combined with any other options or arguments. combined with any other options or arguments.
@ -67,6 +71,14 @@ If '-p' is specified, the contents of <object> are pretty-printed.
If <type> is specified, the raw (though uncompressed) contents of the <object> If <type> is specified, the raw (though uncompressed) contents of the <object>
will be returned. will be returned.
If '--batch' is specified, output of the following form is printed for each
object specified on stdin:
------------
<sha1> SP <type> SP <size> LF
<contents> LF
------------
If '--batch-check' is specified, output of the following form is printed for If '--batch-check' is specified, output of the following form is printed for
each object specified fon stdin: each object specified fon stdin:
@ -74,8 +86,8 @@ each object specified fon stdin:
<sha1> SP <type> SP <size> LF <sha1> SP <type> SP <size> LF
------------ ------------
Additionally, output of the following form is printed for each object specified For both '--batch' and '--batch-check', output of the following form is printed
on stdin that does not exist in the repository: for each object specified on stdin that does not exist in the repository:
------------ ------------
<object> SP missing LF <object> SP missing LF

View File

@ -143,11 +143,12 @@ static int cat_one_file(int opt, const char *exp_type, const char *obj_name)
return 0; return 0;
} }
static int batch_one_object(const char *obj_name) static int batch_one_object(const char *obj_name, int print_contents)
{ {
unsigned char sha1[20]; unsigned char sha1[20];
enum object_type type; enum object_type type;
unsigned long size; unsigned long size;
void *contents = contents;
if (!obj_name) if (!obj_name)
return 1; return 1;
@ -157,22 +158,33 @@ static int batch_one_object(const char *obj_name)
return 0; return 0;
} }
type = sha1_object_info(sha1, &size); if (print_contents)
contents = read_sha1_file(sha1, &type, &size);
else
type = sha1_object_info(sha1, &size);
if (type <= 0) if (type <= 0)
return 1; return 1;
printf("%s %s %lu\n", sha1_to_hex(sha1), typename(type), size); printf("%s %s %lu\n", sha1_to_hex(sha1), typename(type), size);
fflush(stdout);
if (print_contents) {
write_or_die(1, contents, size);
printf("\n");
fflush(stdout);
}
return 0; return 0;
} }
static int batch_objects(void) static int batch_objects(int print_contents)
{ {
struct strbuf buf; struct strbuf buf;
strbuf_init(&buf, 0); strbuf_init(&buf, 0);
while (strbuf_getline(&buf, stdin, '\n') != EOF) { while (strbuf_getline(&buf, stdin, '\n') != EOF) {
int error = batch_one_object(buf.buf); int error = batch_one_object(buf.buf, print_contents);
if (error) if (error)
return error; return error;
} }
@ -180,37 +192,51 @@ static int batch_objects(void)
return 0; return 0;
} }
static const char cat_file_usage[] = "git-cat-file [ [-t|-s|-e|-p|<type>] <sha1> | --batch-check < <list_of_sha1s> ]"; static const char cat_file_usage[] = "git-cat-file [ [-t|-s|-e|-p|<type>] <sha1> | [--batch|--batch-check] < <list_of_sha1s> ]";
int cmd_cat_file(int argc, const char **argv, const char *prefix) int cmd_cat_file(int argc, const char **argv, const char *prefix)
{ {
int i, opt = 0, batch_check = 0; int i, opt = 0, batch = 0, batch_check = 0;
const char *exp_type = NULL, *obj_name = NULL; const char *exp_type = NULL, *obj_name = NULL;
git_config(git_default_config); git_config(git_default_config);
for (i = 1; i < argc; ++i) { for (i = 1; i < argc; ++i) {
const char *arg = argv[i]; const char *arg = argv[i];
int is_batch = 0, is_batch_check = 0;
if (!strcmp(arg, "--batch-check")) { is_batch = !strcmp(arg, "--batch");
if (!is_batch)
is_batch_check = !strcmp(arg, "--batch-check");
if (is_batch || is_batch_check) {
if (opt) { if (opt) {
error("git-cat-file: Can't use --batch-check with -%c", opt); error("git-cat-file: Can't use %s with -%c", arg, opt);
usage(cat_file_usage); usage(cat_file_usage);
} else if (exp_type) { } else if (exp_type) {
error("git-cat-file: Can't use --batch-check when a type (\"%s\") is specified", exp_type); error("git-cat-file: Can't use %s when a type (\"%s\") is specified", arg, exp_type);
usage(cat_file_usage); usage(cat_file_usage);
} else if (obj_name) { } else if (obj_name) {
error("git-cat-file: Can't use --batch-check when an object (\"%s\") is specified", obj_name); error("git-cat-file: Can't use %s when an object (\"%s\") is specified", arg, obj_name);
usage(cat_file_usage); usage(cat_file_usage);
} }
batch_check = 1; if ((is_batch && batch_check) || (is_batch_check && batch)) {
error("git-cat-file: Can't use %s with %s", arg, is_batch ? "--batch-check" : "--batch");
usage(cat_file_usage);
}
if (is_batch)
batch = 1;
else
batch_check = 1;
continue; continue;
} }
if (!strcmp(arg, "-t") || !strcmp(arg, "-s") || !strcmp(arg, "-e") || !strcmp(arg, "-p")) { if (!strcmp(arg, "-t") || !strcmp(arg, "-s") || !strcmp(arg, "-e") || !strcmp(arg, "-p")) {
if (batch_check) { if (batch || batch_check) {
error("git-cat-file: Can't use %s with --batch-check", arg); error("git-cat-file: Can't use %s with %s", arg, batch ? "--batch" : "--batch-check");
usage(cat_file_usage); usage(cat_file_usage);
} }
@ -223,8 +249,8 @@ int cmd_cat_file(int argc, const char **argv, const char *prefix)
usage(cat_file_usage); usage(cat_file_usage);
if (!exp_type) { if (!exp_type) {
if (batch_check) { if (batch || batch_check) {
error("git-cat-file: Can't specify a type (\"%s\") with --batch-check", arg); error("git-cat-file: Can't specify a type (\"%s\") with %s", arg, batch ? "--batch" : "--batch-check");
usage(cat_file_usage); usage(cat_file_usage);
} }
@ -235,16 +261,17 @@ int cmd_cat_file(int argc, const char **argv, const char *prefix)
if (obj_name) if (obj_name)
usage(cat_file_usage); usage(cat_file_usage);
// We should have hit one of the earlier if (batch_check) cases before // We should have hit one of the earlier if (batch || batch_check) cases before
// getting here. // getting here.
assert(!batch);
assert(!batch_check); assert(!batch_check);
obj_name = arg; obj_name = arg;
break; break;
} }
if (batch_check) if (batch || batch_check)
return batch_objects(); return batch_objects(batch);
if (!exp_type || !obj_name) if (!exp_type || !obj_name)
usage(cat_file_usage); usage(cat_file_usage);

View File

@ -28,6 +28,9 @@ run_tests () {
pretty_content=$5 pretty_content=$5
no_ts=$6 no_ts=$6
batch_output="$sha1 $type $size
$content"
test_expect_success "$type exists" ' test_expect_success "$type exists" '
git cat-file -e $sha1 git cat-file -e $sha1
' '
@ -68,6 +71,20 @@ run_tests () {
fi fi
' '
test -z "$content" ||
test_expect_success "--batch output of $type is correct" '
expect="$(maybe_remove_timestamp "$batch_output" $no_ts)"
actual="$(maybe_remove_timestamp "$(echo $sha1 | git cat-file --batch)" no_ts)"
if test "z$expect" = "z$actual"
then
: happy
else
echo "Oops: expected $expect"
echo "but got $actual"
false
fi
'
test_expect_success "--batch-check output of $type is correct" ' test_expect_success "--batch-check output of $type is correct" '
expect="$sha1 $type $size" expect="$sha1 $type $size"
actual="$(echo_without_newline $sha1 | git cat-file --batch-check)" actual="$(echo_without_newline $sha1 | git cat-file --batch-check)"
@ -131,29 +148,32 @@ test_expect_success \
"Reach a blob from a tag pointing to it" \ "Reach a blob from a tag pointing to it" \
"test '$hello_content' = \"\$(git cat-file blob $tag_sha1)\"" "test '$hello_content' = \"\$(git cat-file blob $tag_sha1)\""
for opt in t s e p for batch in batch batch-check
do do
test_expect_success "Passing -$opt with --batch-check fails" ' for opt in t s e p
test_must_fail git cat-file --batch-check -$opt $hello_sha1 do
test_expect_success "Passing -$opt with --$batch fails" '
test_must_fail git cat-file --$batch -$opt $hello_sha1
'
test_expect_success "Passing --$batch with -$opt fails" '
test_must_fail git cat-file -$opt --$batch $hello_sha1
'
done
test_expect_success "Passing <type> with --$batch fails" '
test_must_fail git cat-file --$batch blob $hello_sha1
' '
test_expect_success "Passing --batch-check with -$opt fails" ' test_expect_success "Passing --$batch with <type> fails" '
test_must_fail git cat-file -$opt --batch-check $hello_sha1 test_must_fail git cat-file blob --$batch $hello_sha1
'
test_expect_success "Passing sha1 with --$batch fails" '
test_must_fail git cat-file --$batch $hello_sha1
' '
done done
test_expect_success "Passing <type> with --batch-check fails" '
test_must_fail git cat-file --batch-check blob $hello_sha1
'
test_expect_success "Passing --batch-check with <type> fails" '
test_must_fail git cat-file blob --batch-check $hello_sha1
'
test_expect_success "Passing sha1 with --batch-check fails" '
test_must_fail git cat-file --batch-check $hello_sha1
'
test_expect_success "--batch-check for a non-existent object" ' test_expect_success "--batch-check for a non-existent object" '
test "deadbeef missing" = \ test "deadbeef missing" = \
"$(echo_without_newline deadbeef | git cat-file --batch-check)" "$(echo_without_newline deadbeef | git cat-file --batch-check)"
@ -163,6 +183,26 @@ test_expect_success "--batch-check for an emtpy line" '
test " missing" = "$(echo | git cat-file --batch-check)" test " missing" = "$(echo | git cat-file --batch-check)"
' '
batch_input="$hello_sha1
$commit_sha1
$tag_sha1
deadbeef
"
batch_output="$hello_sha1 blob $hello_size
$hello_content
$commit_sha1 commit $commit_size
$commit_content
$tag_sha1 tag $tag_size
$tag_content
deadbeef missing
missing"
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)\""
batch_check_input="$hello_sha1 batch_check_input="$hello_sha1
$tree_sha1 $tree_sha1
$commit_sha1 $commit_sha1