Skip to content

Commit 0721d85

Browse files
bk2204gitster
authored andcommitted
rev-parse: have --parseopt callers exit 0 on --help
The standard philosophy for Unix software when a help option (such as --help) is specified is that the software should exit 0, printing the help output to standard output, since the standard output is for user-requested output and the program performed the requested task successfully. If the user specifies an incorrect option, then the help output should be printed to standard error (since the user has made a mistake) and it should exit unsuccessfully. git rev-parse --parseopt properly directs the output in both of these cases, but it currently exits 129 when it receives a --help or -h option on the command line, which causes its invoking script to do the same. This is not in line with the usual behavior and it causes scripts using this command to exit unsuccessfully on --help as well. Note that Git subcommands implemented using scripts, such as git submodule, don't have this problem because Git itself intercepts the --help option and runs man (or a similar tool), which then exits 0. However, this still affects the myriad scripts that use this functionality because Git is widespread and the --parseopt functionality is a good way to get sensible option parsing across shells in a portable way. Because git rev-parse --parseopt is intended to be eval'd by the shell, when help output is to be printed to standard output, Git actually prints a cat command with a heredoc since the standard output is being evaluated by the shell. Thus, to do the right thing, simply add an "exit 0" right after the end of the heredoc, which will cause the invoking program to exit successfully. The usual invocation recommended by the manual page is this: eval "$(echo "$OPTS_SPEC" | git rev-parse --parseopt -- "$@" || echo exit $?)" Thus, the fact that git rev-parse --parseopt still exits 129 in this case is irrelevant, since the "echo exit $?" will print "exit 129", but that will be after the "exit 0" printed by Git—and thus ignored, since the shell will have already exited successfully. Update the tests for this case. Note that we no longer need to delete only the first and last lines in some tests, so add a command to delete the end of the heredoc as well. We could do something clever with sed to delete all but the last two lines or switch to head and tail, but those would be more complicated and less readable, so just stick with the simple approach. Signed-off-by: brian m. carlson <sandals@crustytoothpaste.net> Signed-off-by: Junio C Hamano <gitster@pobox.com>
1 parent 67ad421 commit 0721d85

4 files changed

Lines changed: 10 additions & 3 deletions

File tree

parse-options.c

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1451,7 +1451,7 @@ static enum parse_opt_result usage_with_options_internal(struct parse_opt_ctx_t
14511451
fputc('\n', outfile);
14521452

14531453
if (!err && ctx && ctx->flags & PARSE_OPT_SHELL_EVAL)
1454-
fputs("EOF\n", outfile);
1454+
fputs("EOF\nexit 0\n", outfile);
14551455

14561456
return PARSE_OPT_HELP;
14571457
}

t/t1502-rev-parse-parseopt.sh

Lines changed: 7 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -12,7 +12,7 @@ check_invalid_long_option () {
1212
cat <<-\EOF &&
1313
error: unknown option `'${opt#--}\''
1414
EOF
15-
sed -e 1d -e \$d <"$TEST_DIRECTORY/t1502/$spec.help"
15+
sed -e 1d -e /EOF/d -e \$d <"$TEST_DIRECTORY/t1502/$spec.help"
1616
} >expect &&
1717
test_expect_code 129 git rev-parse --parseopt -- $opt \
1818
2>output <"$TEST_DIRECTORY/t1502/$spec" &&
@@ -87,6 +87,7 @@ test_expect_success 'test --parseopt help output no switches' '
8787
| some-command does foo and bar!
8888
|
8989
|EOF
90+
|exit 0
9091
END_EXPECT
9192
test_expect_code 129 git rev-parse --parseopt -- -h > output < optionspec_no_switches &&
9293
test_cmp expect output
@@ -100,6 +101,7 @@ test_expect_success 'test --parseopt help output hidden switches' '
100101
| some-command does foo and bar!
101102
|
102103
|EOF
104+
|exit 0
103105
END_EXPECT
104106
test_expect_code 129 git rev-parse --parseopt -- -h > output < optionspec_only_hidden_switches &&
105107
test_cmp expect output
@@ -115,6 +117,7 @@ test_expect_success 'test --parseopt help-all output hidden switches' '
115117
| --[no-]hidden1 A hidden switch
116118
|
117119
|EOF
120+
|exit 0
118121
END_EXPECT
119122
test_expect_code 129 git rev-parse --parseopt -- --help-all > output < optionspec_only_hidden_switches &&
120123
test_cmp expect output
@@ -125,7 +128,7 @@ test_expect_success 'test --parseopt invalid switch help output' '
125128
cat <<-\EOF &&
126129
error: unknown option `does-not-exist'\''
127130
EOF
128-
sed -e 1d -e \$d <"$TEST_DIRECTORY/t1502/optionspec.help"
131+
sed -e 1d -e /EOF/d -e \$d <"$TEST_DIRECTORY/t1502/optionspec.help"
129132
} >expect &&
130133
test_expect_code 129 git rev-parse --parseopt -- --does-not-exist 1>/dev/null 2>output < optionspec &&
131134
test_cmp expect output
@@ -252,6 +255,7 @@ test_expect_success 'test --parseopt help output: "wrapped" options normal "or:"
252255
| -h, --help show the help
253256
|
254257
|EOF
258+
|exit 0
255259
END_EXPECT
256260
257261
test_must_fail git rev-parse --parseopt -- -h <spec >actual &&
@@ -289,6 +293,7 @@ test_expect_success 'test --parseopt help output: multi-line blurb after empty l
289293
| -h, --help show the help
290294
|
291295
|EOF
296+
|exit 0
292297
END_EXPECT
293298
294299
test_must_fail git rev-parse --parseopt -- -h <spec >actual &&

t/t1502/optionspec-neg.help

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -10,3 +10,4 @@ usage: some-command [options] <args>...
1010
--no-negative cannot be positivated
1111

1212
EOF
13+
exit 0

t/t1502/optionspec.help

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -34,3 +34,4 @@ Extras
3434
--[no-]extra1 line above used to cause a segfault but no longer does
3535

3636
EOF
37+
exit 0

0 commit comments

Comments
 (0)