diff mbox series

[v2,3/6] parse-options: stop supporting "" in the usagestr array

Message ID patch-v2-3.6-11f4a119563-20210910T153147Z-avarab@gmail.com (mailing list archive)
State Superseded
Headers show
Series parse-options: properly align continued usage output & related | expand

Commit Message

Ævar Arnfjörð Bjarmason Sept. 10, 2021, 3:38 p.m. UTC
The strings in the the "usagestr" array have special handling for the
empty string dating back to f389c808b67 (Rework make_usage to print
the usage message immediately, 2007-10-14).

We'll prefix all strings after the first one with "or: ". Then if we
encountered a "" we'll emit all strings after that point verbatim
without any "or: " prefixing.

This gets rid of that special case, which was added in
f389c808b67 (Rework make_usage to print the usage message immediately,
2007-10-14). It was only used "blame" (the "credential-cache*" use of
it was removed in the preceding commit). Before this change we'd emit:

    $ git blame -h
    usage: git blame [<options>] [<rev-opts>] [<rev>] [--] <file>

        <rev-opts> are documented in git-rev-list(1)

This changes that output to simply use "[<git-rev-list args>]" instead
of "[<rev-opts>]". This accomplishes the same, is more consistent as
"git bundle" and "git blame" use the same way of referring to these
options now.

The use of this in "blame" dated back to 5817da01434 (git-blame:
migrate to incremental parse-option [1/2], 2008-07-08), and the use in
"bundle" to 2e0afafebd8 (Add git-bundle: move objects and
references by archive, 2007-02-22).

Once we get rid of this special case we can also use usage_msg_opt()
to emit the error message we'd get on an invalid "-L <range>"
argument, which means we can get rid of the old-style "blame_usage"
variable.

It's possible that this change introduce breakage somewhere. We'd only
catch these cases at runtime, and the "git rev-parse --parseopt"
command is used by shellscripts, see bac199b7b17 (Update
git-sh-setup(1) to allow transparent use of git-rev-parse --parseopt,
2007-11-04). I've grepped the codebase for "OPTIONS_SPEC",
"char.*\*.*usage\[\]" etc. I'm fairly sure there no outstanding users
of this functionality.

Signed-off-by: Ævar Arnfjörð Bjarmason <avarab@gmail.com>
---
 builtin/blame.c               |  9 +++------
 builtin/rev-parse.c           |  3 +++
 parse-options.c               |  8 +-------
 t/helper/test-parse-options.c |  2 --
 t/t0040-parse-options.sh      |  2 --
 t/t1502-rev-parse-parseopt.sh | 34 ++++++++++++++++++----------------
 6 files changed, 25 insertions(+), 33 deletions(-)

Comments

Junio C Hamano Sept. 11, 2021, 12:21 a.m. UTC | #1
Ævar Arnfjörð Bjarmason  <avarab@gmail.com> writes:

> The strings in the the "usagestr" array have special handling for the
> empty string dating back to f389c808b67 (Rework make_usage to print
> the usage message immediately, 2007-10-14).
>
> We'll prefix all strings after the first one with "or: ". Then if we
> encountered a "" we'll emit all strings after that point verbatim
> without any "or: " prefixing.
>
> This gets rid of that special case, which was added in
> f389c808b67 (Rework make_usage to print the usage message immediately,
> 2007-10-14). It was only used "blame" (the "credential-cache*" use of

used *by* "blame"

> it was removed in the preceding commit). Before this change we'd emit:
>
>     $ git blame -h
>     usage: git blame [<options>] [<rev-opts>] [<rev>] [--] <file>
>
>         <rev-opts> are documented in git-rev-list(1)

The most crucial information is missing.  It may be shared with the
previous step but it is even worse in this step.

Why is this loss of feature a desirable thing in the first place?

What are we gaining by breaking the "after listing the alternative
forms concatenated with 'or:', we can give a general description,
before going onto the list of options"?

Without that explained, the remainder of the proposed log message
reads more like an excuse for breaking the feature, justifying that
the loss of feature can be worked around, than the description of a
solution.

Thanks.
Ævar Arnfjörð Bjarmason Sept. 11, 2021, 2:46 a.m. UTC | #2
On Fri, Sep 10 2021, Junio C Hamano wrote:

> Ævar Arnfjörð Bjarmason  <avarab@gmail.com> writes:
>
>> The strings in the the "usagestr" array have special handling for the
>> empty string dating back to f389c808b67 (Rework make_usage to print
>> the usage message immediately, 2007-10-14).
>>
>> We'll prefix all strings after the first one with "or: ". Then if we
>> encountered a "" we'll emit all strings after that point verbatim
>> without any "or: " prefixing.
>>
>> This gets rid of that special case, which was added in
>> f389c808b67 (Rework make_usage to print the usage message immediately,
>> 2007-10-14). It was only used "blame" (the "credential-cache*" use of
>
> used *by* "blame"
>
>> it was removed in the preceding commit). Before this change we'd emit:
>>
>>     $ git blame -h
>>     usage: git blame [<options>] [<rev-opts>] [<rev>] [--] <file>
>>
>>         <rev-opts> are documented in git-rev-list(1)
>
> The most crucial information is missing.  It may be shared with the
> previous step but it is even worse in this step.
>
> Why is this loss of feature a desirable thing in the first place?
>
> What are we gaining by breaking the "after listing the alternative
> forms concatenated with 'or:', we can give a general description,
> before going onto the list of options"?
>
> Without that explained, the remainder of the proposed log message
> reads more like an excuse for breaking the feature, justifying that
> the loss of feature can be worked around, than the description of a
> solution.

Making it the same as how "git bundle" describes it doesn't seem
anywhere close to breaking it, and that also goes to the point you had
about brevity on another patch.

I think that passing custom or generated help advice here might make
sense generally, i.e. we might eventually want to expand that to all
built-in as part of improving the -h and --help output, see e.g. the
note at the bottom of "git --help".

But if we do that let's do that with an API where we simply pass this
custom string in as another parameter to the function, rather than
having a state machine to parse it out of the array we use for the
"usage:" and "or:" list of lines.
Junio C Hamano Sept. 11, 2021, 6:52 a.m. UTC | #3
Ævar Arnfjörð Bjarmason <avarab@gmail.com> writes:

> But if we do that let's do that with an API where we simply pass this
> custom string in as another parameter to the function, rather than
> having a state machine to parse it out of the array we use for the
> "usage:" and "or:" list of lines.

Sorry, but I do not follow.  A perfectly fine way to encode the
three (usage:, or:, and text) kind of information in a single array
is what this step is breaking, and then you propose to keep the two
still in that same array, with only the third kind kicked out to
"another parameter", which does not make much sense to me.
diff mbox series

Patch

diff --git a/builtin/blame.c b/builtin/blame.c
index 641523ff9af..45d9873a999 100644
--- a/builtin/blame.c
+++ b/builtin/blame.c
@@ -29,12 +29,8 @@ 
 #include "refs.h"
 #include "tag.h"
 
-static char blame_usage[] = N_("git blame [<options>] [<rev-opts>] [<rev>] [--] <file>");
-
 static const char *blame_opt_usage[] = {
-	blame_usage,
-	"",
-	N_("<rev-opts> are documented in git-rev-list(1)"),
+	N_("git blame [<options>] [<git rev-list args>] [<rev>] [--] <file>"),
 	NULL
 };
 
@@ -1107,7 +1103,8 @@  int cmd_blame(int argc, const char **argv, const char *prefix)
 				    nth_line_cb, &sb, lno, anchor,
 				    &bottom, &top, sb.path,
 				    the_repository->index))
-			usage(blame_usage);
+			usage_msg_opt(_("Invalid -L <range> parameters"),
+				      blame_opt_usage, options);
 		if ((!lno && (top || bottom)) || lno < bottom)
 			die(Q_("file %s has only %lu line",
 			       "file %s has only %lu lines",
diff --git a/builtin/rev-parse.c b/builtin/rev-parse.c
index 22c4e1a4ff0..aeebfd52805 100644
--- a/builtin/rev-parse.c
+++ b/builtin/rev-parse.c
@@ -436,7 +436,10 @@  static int cmd_parseopt(int argc, const char **argv, const char *prefix)
 	for (;;) {
 		if (strbuf_getline(&sb, stdin) == EOF)
 			die(_("premature end of input"));
+		if (!sb.len)
+			die(_("empty lines are not permitted before the `--' separator"));
 		ALLOC_GROW(usage, unb + 1, usz);
+
 		if (!strcmp("--", sb.buf)) {
 			if (unb < 1)
 				die(_("no usage string given before the `--' separator"));
diff --git a/parse-options.c b/parse-options.c
index 2abff136a17..950a8279beb 100644
--- a/parse-options.c
+++ b/parse-options.c
@@ -924,18 +924,12 @@  static int usage_with_options_internal(struct parse_opt_ctx_t *ctx,
 		fprintf(outfile, "cat <<\\EOF\n");
 
 	fprintf_ln(outfile, _("usage: %s"), _(*usagestr++));
-	while (*usagestr && **usagestr)
+	while (*usagestr) {
 		/*
 		 * TRANSLATORS: the colon here should align with the
 		 * one in "usage: %s" translation.
 		 */
 		fprintf_ln(outfile, _("   or: %s"), _(*usagestr++));
-	while (*usagestr) {
-		if (**usagestr)
-			fprintf_ln(outfile, _("    %s"), _(*usagestr));
-		else
-			fputc('\n', outfile);
-		usagestr++;
 	}
 
 	need_newline = 1;
diff --git a/t/helper/test-parse-options.c b/t/helper/test-parse-options.c
index 2051ce57db7..e00aef073b0 100644
--- a/t/helper/test-parse-options.c
+++ b/t/helper/test-parse-options.c
@@ -102,8 +102,6 @@  int cmd__parse_options(int argc, const char **argv)
 	const char *prefix = "prefix/";
 	const char *usage[] = {
 		"test-tool parse-options <options>",
-		"",
-		"A helper function for the parse-options API.",
 		NULL
 	};
 	struct string_list expect = STRING_LIST_INIT_NODUP;
diff --git a/t/t0040-parse-options.sh b/t/t0040-parse-options.sh
index ad4746d899a..2910874ece5 100755
--- a/t/t0040-parse-options.sh
+++ b/t/t0040-parse-options.sh
@@ -10,8 +10,6 @@  test_description='our own option parser'
 cat >expect <<\EOF
 usage: test-tool parse-options <options>
 
-    A helper function for the parse-options API.
-
     --yes                 get a boolean
     -D, --no-doubt        begins with 'no-'
     -B, --no-fear         be brave
diff --git a/t/t1502-rev-parse-parseopt.sh b/t/t1502-rev-parse-parseopt.sh
index b29563fc997..6badc650d64 100755
--- a/t/t1502-rev-parse-parseopt.sh
+++ b/t/t1502-rev-parse-parseopt.sh
@@ -6,8 +6,6 @@  test_description='test git rev-parse --parseopt'
 test_expect_success 'setup optionspec' '
 	sed -e "s/^|//" >optionspec <<\EOF
 |some-command [options] <args>...
-|
-|some-command does foo and bar!
 |--
 |h,help    show the help
 |
@@ -41,8 +39,6 @@  EOF
 test_expect_success 'setup optionspec-no-switches' '
 	sed -e "s/^|//" >optionspec_no_switches <<\EOF
 |some-command [options] <args>...
-|
-|some-command does foo and bar!
 |--
 EOF
 '
@@ -50,8 +46,6 @@  EOF
 test_expect_success 'setup optionspec-only-hidden-switches' '
 	sed -e "s/^|//" >optionspec_only_hidden_switches <<\EOF
 |some-command [options] <args>...
-|
-|some-command does foo and bar!
 |--
 |hidden1* A hidden switch
 EOF
@@ -62,8 +56,6 @@  test_expect_success 'test --parseopt help output' '
 |cat <<\EOF
 |usage: some-command [options] <args>...
 |
-|    some-command does foo and bar!
-|
 |    -h, --help            show the help
 |    --foo                 some nifty option --foo
 |    --bar ...             some cool option --bar with an argument
@@ -103,8 +95,6 @@  test_expect_success 'test --parseopt help output no switches' '
 |cat <<\EOF
 |usage: some-command [options] <args>...
 |
-|    some-command does foo and bar!
-|
 |EOF
 END_EXPECT
 	test_expect_code 129 git rev-parse --parseopt -- -h > output < optionspec_no_switches &&
@@ -116,8 +106,6 @@  test_expect_success 'test --parseopt help output hidden switches' '
 |cat <<\EOF
 |usage: some-command [options] <args>...
 |
-|    some-command does foo and bar!
-|
 |EOF
 END_EXPECT
 	test_expect_code 129 git rev-parse --parseopt -- -h > output < optionspec_only_hidden_switches &&
@@ -129,8 +117,6 @@  test_expect_success 'test --parseopt help-all output hidden switches' '
 |cat <<\EOF
 |usage: some-command [options] <args>...
 |
-|    some-command does foo and bar!
-|
 |    --hidden1             A hidden switch
 |
 |EOF
@@ -144,8 +130,6 @@  test_expect_success 'test --parseopt invalid switch help output' '
 |error: unknown option `does-not-exist'\''
 |usage: some-command [options] <args>...
 |
-|    some-command does foo and bar!
-|
 |    -h, --help            show the help
 |    --foo                 some nifty option --foo
 |    --bar ...             some cool option --bar with an argument
@@ -282,4 +266,22 @@  test_expect_success 'test --parseopt --stuck-long and short option with unset op
 	test_cmp expect output
 '
 
+test_expect_success 'test --parseopt help output hidden switches' '
+	sed -e "s/^|//" >optionspec-trailing-line <<-\EOF &&
+	|some-command [options] <args>...
+	|
+	|
+	|--
+	|h,help    show the help
+	EOF
+
+	cat >expect <<-\EOF &&
+	fatal: empty lines are not permitted before the `--'"'"' separator
+	EOF
+
+	test_must_fail git rev-parse --parseopt -- -h >out < optionspec-trailing-line 2>actual &&
+	test_must_be_empty out &&
+	test_cmp expect actual
+'
+
 test_done