Skip to content

Commit b3fe468

Browse files
avargitster
authored andcommitted
cat-file: fix remaining usage bugs
With the migration of --batch-all-objects to OPT_CMDMODE() in the preceding commit one bug with combining it and other OPT_CMDMODE() options was solved, but we were still left with e.g. --buffer silently being discarded when not in batch mode. Fix all those bugs, and in addition emit errors telling the user specifically what options can't be combined with what other options, before this we'd usually just emit the cryptic usage text and leave the users to work it out by themselves. This change is rather large, because to do so we need to untangle the options processing so that we can not only error out, but emit sensible errors, and e.g. emit errors about options before errors about stray argc elements (as they might become valid if the option were removed). Some of the output changes ("error:" to "fatal:" with usage_msg_opt[f]()), but none of the exit codes change, except in those cases where we silently accepted bad option combinations before, now we'll error out. Signed-off-by: Ævar Arnfjörð Bjarmason <[email protected]> Signed-off-by: Junio C Hamano <[email protected]>
1 parent 485fd2c commit b3fe468

File tree

2 files changed

+84
-52
lines changed

2 files changed

+84
-52
lines changed

builtin/cat-file.c

Lines changed: 63 additions & 32 deletions
Original file line numberDiff line numberDiff line change
@@ -648,6 +648,8 @@ static int batch_option_callback(const struct option *opt,
648648
int cmd_cat_file(int argc, const char **argv, const char *prefix)
649649
{
650650
int opt = 0;
651+
int opt_cw = 0;
652+
int opt_epts = 0;
651653
const char *exp_type = NULL, *obj_name = NULL;
652654
struct batch_options batch = {0};
653655
int unknown_type = 0;
@@ -701,45 +703,74 @@ int cmd_cat_file(int argc, const char **argv, const char *prefix)
701703
batch.buffer_output = -1;
702704

703705
argc = parse_options(argc, argv, prefix, options, usage, 0);
704-
if (argc && batch.enabled)
705-
usage_with_options(usage, options);
706-
if (opt == 'b') {
707-
batch.all_objects = 1;
708-
} else if (opt) {
709-
if (batch.enabled && (opt == 'c' || opt == 'w'))
710-
batch.cmdmode = opt;
711-
else if (argc == 1)
712-
obj_name = argv[0];
713-
else
714-
usage_with_options(usage, options);
715-
} else if (!opt && !batch.enabled) {
716-
if (argc == 2) {
717-
exp_type = argv[0];
718-
obj_name = argv[1];
719-
} else
720-
usage_with_options(usage, options);
721-
} else if (batch.enabled && batch.cmdmode != opt)
722-
usage_with_options(usage, options);
706+
opt_cw = (opt == 'c' || opt == 'w');
707+
opt_epts = (opt == 'e' || opt == 'p' || opt == 't' || opt == 's');
723708

724-
if ((batch.follow_symlinks || batch.all_objects) && !batch.enabled) {
725-
usage_with_options(usage, options);
726-
}
727-
728-
if (force_path && opt != 'c' && opt != 'w') {
729-
error("--path=<path> needs --textconv or --filters");
730-
usage_with_options(usage, options);
731-
}
709+
/* --batch-all-objects? */
710+
if (opt == 'b')
711+
batch.all_objects = 1;
732712

733-
if (force_path && batch.enabled) {
734-
error("--path=<path> incompatible with --batch");
735-
usage_with_options(usage, options);
736-
}
713+
/* Option compatibility */
714+
if (force_path && !opt_cw)
715+
usage_msg_optf(_("'%s=<%s>' needs '%s' or '%s'"),
716+
usage, options,
717+
"--path", _("path|tree-ish"), "--filters",
718+
"--textconv");
737719

720+
/* Option compatibility with batch mode */
721+
if (batch.enabled)
722+
;
723+
else if (batch.follow_symlinks)
724+
usage_msg_optf(_("'%s' requires a batch mode"), usage, options,
725+
"--follow_symlinks");
726+
else if (batch.buffer_output >= 0)
727+
usage_msg_optf(_("'%s' requires a batch mode"), usage, options,
728+
"--buffer");
729+
else if (batch.all_objects)
730+
usage_msg_optf(_("'%s' requires a batch mode"), usage, options,
731+
"--batch-all-objects");
732+
733+
/* Batch defaults */
738734
if (batch.buffer_output < 0)
739735
batch.buffer_output = batch.all_objects;
740736

741-
if (batch.enabled)
737+
/* Return early if we're in batch mode? */
738+
if (batch.enabled) {
739+
if (opt_cw)
740+
batch.cmdmode = opt;
741+
else if (opt && opt != 'b')
742+
usage_msg_optf(_("'-%c' is incompatible with batch mode"),
743+
usage, options, opt);
744+
else if (argc)
745+
usage_msg_opt(_("batch modes take no arguments"), usage,
746+
options);
747+
742748
return batch_objects(&batch);
749+
}
750+
751+
if (opt) {
752+
if (!argc && opt == 'c')
753+
usage_msg_optf(_("<rev> required with '%s'"),
754+
usage, options, "--textconv");
755+
else if (!argc && opt == 'w')
756+
usage_msg_optf(_("<rev> required with '%s'"),
757+
usage, options, "--filters");
758+
else if (!argc && opt_epts)
759+
usage_msg_optf(_("<object> required with '-%c'"),
760+
usage, options, opt);
761+
else if (argc == 1)
762+
obj_name = argv[0];
763+
else
764+
usage_msg_opt(_("too many arguments"), usage, options);
765+
} else if (!argc) {
766+
usage_with_options(usage, options);
767+
} else if (argc != 2) {
768+
usage_msg_optf(_("only two arguments allowed in <type> <object> mode, not %d"),
769+
usage, options, argc);
770+
} else if (argc) {
771+
exp_type = argv[0];
772+
obj_name = argv[1];
773+
}
743774

744775
if (unknown_type && opt != 't' && opt != 's')
745776
die("git cat-file --allow-unknown-type: use with -s or -t");

t/t1006-cat-file.sh

Lines changed: 21 additions & 20 deletions
Original file line numberDiff line numberDiff line change
@@ -24,7 +24,7 @@ done
2424

2525
test_incompatible_usage () {
2626
test_expect_code 129 "$@" 2>err &&
27-
grep -E "^error:.**needs" err
27+
grep -E "^(fatal|error):.*(requires|incompatible with|needs)" err
2828
}
2929

3030
for opt in --batch --batch-check
@@ -34,48 +34,54 @@ do
3434
'
3535
done
3636

37+
test_missing_usage () {
38+
test_expect_code 129 "$@" 2>err &&
39+
grep -E "^fatal:.*required" err
40+
}
41+
3742
short_modes="-e -p -t -s"
3843
cw_modes="--textconv --filters"
3944

4045
for opt in $cw_modes
4146
do
4247
test_expect_success "usage: $opt requires another option" '
43-
test_expect_code 129 git cat-file $opt
48+
test_missing_usage git cat-file $opt
4449
'
4550
done
4651

4752
for opt in $short_modes
4853
do
4954
test_expect_success "usage: $opt requires another option" '
50-
test_expect_code 129 git cat-file $opt
55+
test_missing_usage git cat-file $opt
5156
'
5257

5358
for opt2 in --batch \
5459
--batch-check \
55-
--follow-symlinks
60+
--follow-symlinks \
61+
"--path=foo HEAD:some-path.txt"
5662
do
57-
test_expect_failure "usage: incompatible options: $opt and $opt2" '
63+
test_expect_success "usage: incompatible options: $opt and $opt2" '
5864
test_incompatible_usage git cat-file $opt $opt2
5965
'
6066
done
61-
62-
opt2="--path=foo HEAD:some-path.txt"
63-
test_expect_success "usage: incompatible options: $opt and $opt2" '
64-
test_incompatible_usage git cat-file $opt $opt2
65-
'
6667
done
6768

69+
test_too_many_arguments () {
70+
test_expect_code 129 "$@" 2>err &&
71+
grep -E "^fatal: too many arguments$" err
72+
}
73+
6874
for opt in $short_modes $cw_modes
6975
do
7076
args="one two three"
7177
test_expect_success "usage: too many arguments: $opt $args" '
72-
test_expect_code 129 git cat-file $opt $args
78+
test_too_many_arguments git cat-file $opt $args
7379
'
7480

7581
for opt2 in --buffer --follow-symlinks
7682
do
7783
test_expect_success "usage: incompatible arguments: $opt with batch option $opt2" '
78-
test_expect_code 129 git cat-file $opt $opt2
84+
test_incompatible_usage git cat-file $opt $opt2
7985
'
8086
done
8187
done
@@ -84,14 +90,9 @@ for opt in --buffer \
8490
--follow-symlinks \
8591
--batch-all-objects
8692
do
87-
status=success
88-
if test $opt = "--buffer"
89-
then
90-
status=failure
91-
fi
92-
test_expect_$status "usage: bad option combination: $opt without batch mode" '
93-
test_expect_code 129 git cat-file $opt &&
94-
test_expect_code 129 git cat-file $opt commit HEAD
93+
test_expect_success "usage: bad option combination: $opt without batch mode" '
94+
test_incompatible_usage git cat-file $opt &&
95+
test_incompatible_usage git cat-file $opt commit HEAD
9596
'
9697
done
9798

0 commit comments

Comments
 (0)