rev-parse --parseopt: add the --stuck-long mode

Add the --stuck-long option to output the options in their long form if available, and with their arguments stuck. Contrary to the default form (non stuck arguments and short options), this can be parsed unambiguously when using options with optional arguments : - in the non stuck form, when an option is taking an optional argument you cannot know if the next argument is its optional argument, or the next option. - the long options form allows to differentiate between an empty argument '--option=' and an unset argument '--option', which is not possible with short options. Signed-off-by: Nicolas Vigier <boklm@mars-attacks.org> Signed-off-by: Junio C Hamano <gitster@pobox.com>

Nicolas Vigier committed Oct 31, 2013 at 12:08 UTC f8c872127d4c48a6ec02abce34cb059ddeb6402a
3 files changed +55 -6
Documentation/git-rev-parse.txt
+7 -1
@@ -50,6 +50,10 @@ Options for --parseopt
50 the first non-option argument. This can be used to parse sub-commands
51 that take options themselves.
52
53 +--stuck-long::
54 + Only meaningful in `--parseopt` mode. Output the options in their
55 + long form if available, and with their arguments stuck.
56 +
57 Options for Filtering
58 ~~~~~~~~~~~~~~~~~~~~~
59
@@ -285,7 +289,9 @@ Each line of options has this format:
289 `<flags>` are of `*`, `=`, `?` or `!`.
290 * Use `=` if the option takes an argument.
291
288 - * Use `?` to mean that the option is optional (though its use is discouraged).
292 + * Use `?` to mean that the option takes an optional argument. You
293 + probably want to use the `--stuck-long` mode to be able to
294 + unambiguously parse the optional argument.
295
296 * Use `*` to mean that this option should not be listed in the usage
297 generated for the `-h` argument. It's shown for `--help-all` as
builtin/rev-parse.c
+9 -2
@@ -30,6 +30,8 @@ static int abbrev_ref;
30 static int abbrev_ref_strict;
31 static int output_sq;
32
33 +static int stuck_long;
34 +
35 /*
36 * Some arguments are relevant "revision" arguments,
37 * others are about output format or other details.
@@ -320,12 +322,15 @@ static int parseopt_dump(const struct option *o, const char *arg, int unset)
322 struct strbuf *parsed = o->value;
323 if (unset)
324 strbuf_addf(parsed, " --no-%s", o->long_name);
323 - else if (o->short_name)
325 + else if (o->short_name && (o->long_name == NULL || !stuck_long))
326 strbuf_addf(parsed, " -%c", o->short_name);
327 else
328 strbuf_addf(parsed, " --%s", o->long_name);
329 if (arg) {
328 - strbuf_addch(parsed, ' ');
330 + if (!stuck_long)
331 + strbuf_addch(parsed, ' ');
332 + else if (o->long_name)
333 + strbuf_addch(parsed, '=');
334 sq_quote_buf(parsed, arg);
335 }
336 return 0;
@@ -351,6 +356,8 @@ static int cmd_parseopt(int argc, const char **argv, const char *prefix)
356 OPT_BOOL(0, "stop-at-non-option", &stop_at_non_option,
357 N_("stop parsing after the "
358 "first non-option argument")),
359 + OPT_BOOL(0, "stuck-long", &stuck_long,
360 + N_("output in stuck long form")),
361 OPT_END(),
362 };
363
t/t1502-rev-parse-parseopt.sh
+39 -3
@@ -12,9 +12,11 @@ usage: some-command [options] <args>...
12 -h, --help show the help
13 --foo some nifty option --foo
14 --bar ... some cool option --bar with an argument
15 + -b, --baz a short and long option
16
17 An option group Header
18 -C[...] option C with an optional argument
19 + -d, --data[=...] short and long option with an optional argument
20
21 Extras
22 --extra1 line above used to cause a segfault but no longer does
@@ -31,9 +33,11 @@ h,help show the help
33
34 foo some nifty option --foo
35 bar= some cool option --bar with an argument
36 +b,baz a short and long option
37
38 An option group Header
39 C? option C with an optional argument
40 +d,data? short and long option with an optional argument
41
42 Extras
43 extra1 line above used to cause a segfault but no longer does
@@ -45,16 +49,16 @@ test_expect_success 'test --parseopt help output' '
49 '
50
51 cat > expect <<EOF
48 -set -- --foo --bar 'ham' -- 'arg'
52 +set -- --foo --bar 'ham' -b -- 'arg'
53 EOF
54
55 test_expect_success 'test --parseopt' '
52 - git rev-parse --parseopt -- --foo --bar=ham arg < optionspec > output &&
56 + git rev-parse --parseopt -- --foo --bar=ham --baz arg < optionspec > output &&
57 test_cmp expect output
58 '
59
60 test_expect_success 'test --parseopt with mixed options and arguments' '
57 - git rev-parse --parseopt -- --foo arg --bar=ham < optionspec > output &&
61 + git rev-parse --parseopt -- --foo arg --bar=ham --baz < optionspec > output &&
62 test_cmp expect output
63 '
64
@@ -99,4 +103,36 @@ test_expect_success 'test --parseopt --keep-dashdash --stop-at-non-option withou
103 test_cmp expect output
104 '
105
106 +cat > expect <<EOF
107 +set -- --foo --bar='z' --baz -C'Z' --data='A' -- 'arg'
108 +EOF
109 +
110 +test_expect_success 'test --parseopt --stuck-long' '
111 + git rev-parse --parseopt --stuck-long -- --foo --bar=z -b arg -CZ -dA <optionspec >output &&
112 + test_cmp expect output
113 +'
114 +
115 +cat > expect <<EOF
116 +set -- --data='' -C --baz -- 'arg'
117 +EOF
118 +
119 +test_expect_success 'test --parseopt --stuck-long and empty optional argument' '
120 + git rev-parse --parseopt --stuck-long -- --data= arg -C -b <optionspec >output &&
121 + test_cmp expect output
122 +'
123 +
124 +cat > expect <<EOF
125 +set -- --data --baz -- 'arg'
126 +EOF
127 +
128 +test_expect_success 'test --parseopt --stuck-long and long option with unset optional argument' '
129 + git rev-parse --parseopt --stuck-long -- --data arg -b <optionspec >output &&
130 + test_cmp expect output
131 +'
132 +
133 +test_expect_success 'test --parseopt --stuck-long and short option with unset optional argument' '
134 + git rev-parse --parseopt --stuck-long -- -d arg -b <optionspec >output &&
135 + test_cmp expect output
136 +'
137 +
138 test_done