All of lore.kernel.org
 help / color / mirror / Atom feed
From: "Ævar Arnfjörð Bjarmason" <avarab@gmail.com>
To: "SZEDER Gábor" <szeder.dev@gmail.com>
Cc: git@vger.kernel.org
Subject: Re: [PATCH 09/20] parse-options: add support for parsing subcommands
Date: Mon, 25 Jul 2022 21:41:52 +0200	[thread overview]
Message-ID: <220725.86wnc1nf6c.gmgdl@evledraar.gmail.com> (raw)
In-Reply-To: <20220725192947.GB2543@szeder.dev>


On Mon, Jul 25 2022, SZEDER Gábor wrote:

> On Mon, Jul 25, 2022 at 04:43:30PM +0200, Ævar Arnfjörð Bjarmason wrote:
>> > diff --git a/builtin/blame.c b/builtin/blame.c
>> > index 02e39420b6..a9fe8cf7a6 100644
>> > --- a/builtin/blame.c
>> > +++ b/builtin/blame.c
>> > @@ -920,6 +920,7 @@ int cmd_blame(int argc, const char **argv, const char *prefix)
>> >  			break;
>> >  		case PARSE_OPT_HELP:
>> >  		case PARSE_OPT_ERROR:
>> > +		case PARSE_OPT_SUBCOMMAND:
>> >  			exit(129);
>> >  		case PARSE_OPT_COMPLETE:
>> >  			exit(0);
>> > diff --git a/builtin/shortlog.c b/builtin/shortlog.c
>> > index 086dfee45a..7a1e1fe7c0 100644
>> > --- a/builtin/shortlog.c
>> > +++ b/builtin/shortlog.c
>> > @@ -381,6 +381,7 @@ int cmd_shortlog(int argc, const char **argv, const char *prefix)
>> >  			break;
>> >  		case PARSE_OPT_HELP:
>> >  		case PARSE_OPT_ERROR:
>> > +		case PARSE_OPT_SUBCOMMAND:
>> >  			exit(129);
>> >  		case PARSE_OPT_COMPLETE:
>> >  			exit(0);
>> 
>> This feels a bit like carrying forward an API wart, i.e. shouldn't we
>> instead BUG() if we are returning a PARSE_OPT_SUBCOMMAND from
>> parse_options_step() for options lists that don't have
>> PARSE_OPT_SUBCOMMAND in them?
>> 
>> I.e. is this even reachable, or just something to suppress the compiler
>> complaining about missing enum labels?
>
> I think it's as good as unreachable, because neither of these two
> commands have subcommands.  However, without these hunks the compiler
> invoked with '-Wswitch' (implied by '-Wall') does indeed complain.

Yeah, we should add a case, but let's just do:

	case PARSE_OPT_SUBCOMMAND:
		BUG("unreachable");

>> ...but why not...
>> 
>> >  static void parse_options_start_1(struct parse_opt_ctx_t *ctx,
>> >  				  int argc, const char **argv, const char *prefix,
>> >  				  const struct option *options,
>> > @@ -515,6 +547,19 @@ static void parse_options_start_1(struct parse_opt_ctx_t *ctx,
>> >  	ctx->prefix = prefix;
>> >  	ctx->cpidx = ((flags & PARSE_OPT_KEEP_ARGV0) != 0);
>> >  	ctx->flags = flags;
>> > +	ctx->has_subcommands = has_subcommands(options);
>> > +	if (!ctx->has_subcommands && (flags & PARSE_OPT_SUBCOMMAND_OPTIONAL))
>> > +		BUG("Using PARSE_OPT_SUBCOMMAND_OPTIONAL without subcommands");
>> > +	if (ctx->has_subcommands) {
>> > +		if (flags & PARSE_OPT_STOP_AT_NON_OPTION)
>> > +			BUG("subcommands are incompatible with PARSE_OPT_STOP_AT_NON_OPTION");
>> > +		if (!(flags & PARSE_OPT_SUBCOMMAND_OPTIONAL)) {
>> > +			if (flags & PARSE_OPT_KEEP_UNKNOWN_OPT)
>> > +				BUG("subcommands are incompatible with PARSE_OPT_KEEP_UNKNOWN unless in combination with PARSE_OPT_SUBCOMMAND_OPTIONAL");
>> > +			if (flags & PARSE_OPT_KEEP_DASHDASH)
>> > +				BUG("subcommands are incompatible with PARSE_OPT_KEEP_DASHDASH unless in combination with PARSE_OPT_SUBCOMMAND_OPTIONAL");
>> > +		}
>> > +	}
>> 
>> ...move this into parse_options_check()? I.e. we'd need to loop over the
>> list once, but it seems like this should belong there.
>> 
>> We have an existing bug in-tree due to usage_with_options() not doing a
>> parse_options_check() (I have a local fix...), checking this sort of
>> thing there instead of in parse_options_start() is therefore the right
>> thing to do, i.e. we shoudl have a one-stop "does this options variable
>> look sane?".
>
> The checks added in this hunk (and the existing checks in the hunk's
> after-context) are not about the elements of the 'struct option'
> array, like the checks in parse_options_check(), but rather about the
> sensibility of parse_options()'s 'parse_opt_flags' parameter.
> usage_with_options() doesn't have (and doesn't at all need) such a
> parameter.

Ah, sorry, I was just confused. FWIW it's because I split out *that*
part into another helper a while ago:
https://github.com/avar/git/commit/55dda82a409

Which might be worthhile doing/stealing heere while we're at it,
i.e. the flags checking has become quite ab ig part of
parse_options_start_1(), or just leave it for later...

>> > +				error(_("unknown subcommand: %s"), arg);
>> 
>> s/%s/'%s'/ while we're at it, perhaps?
>
> Indeed, though it should be `%s', because that's what surrounds
> unknown switches and options in the corresponding error messages.
>
>> > +				usage_with_options(usagestr, options);
>> > +			case PARSE_OPT_COMPLETE:
>> > +			case PARSE_OPT_HELP:
>> > +			case PARSE_OPT_ERROR:
>> > +			case PARSE_OPT_DONE:
>> > +			case PARSE_OPT_NON_OPTION:
>> > +				BUG("parse_subcommand() cannot return these");
>> 
>> nit: BUG("got bad %d", v) or whatever, i.e. say what we got?
>
> All these are impossible, so I don't think it matters.  This is
> another case of the compiler with '-Wswitch' complaining, and follows
> suit of similar switch statements after the calls to parse_short_opt()
> and parse_long_opt() functions.

*nod*, and this one's a BUG(), which is good...

>> > @@ -206,6 +217,11 @@ struct option {
>> >  #define OPT_ALIAS(s, l, source_long_name) \
>> >  	{ OPTION_ALIAS, (s), (l), (source_long_name) }
>> >  
>> > +#define OPT_SUBCOMMAND(l, v, fn)      { OPTION_SUBCOMMAND, 0, (l), (v), NULL, \
>> > +					NULL, 0, NULL, 0, NULL, 0, (fn) }
>> > +#define OPT_SUBCOMMAND_F(l, v, fn, f) { OPTION_SUBCOMMAND, 0, (l), (v), NULL, \
>> > +					NULL, (f), NULL, 0, NULL, 0, (fn) }
>> 
>> Nit, I know you're carrying forward existing patterns, but since that
>> all pre-dated designated init perhaps we could just (untested):
>> 	
>> 	#define OPT_SUBCOMMAND_F(l, v, fn, f) { \
>> 		.type = OPTION_SUBCOMMAND, \
>> 		.long_name = (l), \
>> 		.value = (v), \
>> 		.ll_callback = (fn), \
>> 	}
>> 	#define OPT_SUBCOMMAND(l, v, fn) OPT_SUBCOMMAND_F((l), (v), (fn), 0)
>> 
>> Which IMO is much nicer. I have some patches somewhere to convert these
>> to saner patterns (I think not designated init, but the X() can be
>> defined in terms of X_F() like that, but since this is new we can use
>> designated init all the way...
>
> Oh, I love this idea!  But are we there yet?  I remember the weather
> balloon about designated initializers, but I'm not sure whether we've
> already made the decision to allow them.

Yes, we've got a thoroughly hard dependency on that part of C99 for a
while now, and it's OK to add new ones (especially in cases like these,
where it makes thigs easier to read).

> If we do, then I'm inclined
> to volunteer to clean up all those OPT_* macros in 'parse-options.h'
> with designated initializers, 

Sounds good, you might want to steal this & perhaps some things on the
same branch: https://github.com/avar/git/commit/a1a5e9c68c8

I didn't convert them to designated init, but some macros are "missing",
some are needlessy copy/pasted when X_F() could be defined in terms of
X() etc.

FWIW I thought it would eventually make sense to rename the members of
the struct itself, so we'd e.g. just have a "t" and "l" name, so we
could use that inline instead of the OPT_*() (we could use the long
names too, but that would probably be too verbose).

That would allow adding optional arguments, which e.g. would be handy
for things like "...and here's a list of what options this is
incompatible with".

>
>> > +{
>> > +	int i;
>> 
>> Nit: missing \n (usual style of variable decl);
>
> Hm, speaking of newer C features, what about 'for (int i = 0; ...)'?

Junio says this November, but see:
https://lore.kernel.org/git/220725.86zggxpfed.gmgdl@evledraar.gmail.com/

>> > +		error("'cmd' is mandatory");
>> > +		usage_with_options(usage, test_flag_options);
>> 
>> nit: I think you want usage_msg_optf() or usage_msg_opt().
>
> Maybe... but I don't know what they do ;)  Though I remember removing
> a couple of similar error() and usage_with_options() pairs from the
> builtin commands.

It's just helpers for "usage_with_options, except with a message, e.g.:

	$ ./git cat-file a b c
	fatal: only two arguments allowed in <type> <object> mode, not 3

	usage: git cat-file <type> <object>


  reply	other threads:[~2022-07-25 19:52 UTC|newest]

Thread overview: 97+ messages / expand[flat|nested]  mbox.gz  Atom feed  top
2022-07-25 12:38 [PATCH 00/20] parse-options: handle subcommands SZEDER Gábor
2022-07-25 12:38 ` [PATCH 01/20] git.c: update NO_PARSEOPT markings SZEDER Gábor
2022-07-25 14:31   ` Ævar Arnfjörð Bjarmason
2022-08-02 17:37     ` SZEDER Gábor
2022-08-02 21:00       ` Junio C Hamano
2022-08-03 13:11         ` Ævar Arnfjörð Bjarmason
2022-08-03 21:34         ` SZEDER Gábor
2022-08-04  7:47           ` Ævar Arnfjörð Bjarmason
2022-08-11 21:35           ` Junio C Hamano
2022-08-12 15:28             ` SZEDER Gábor
2022-08-12 16:46               ` Junio C Hamano
2022-07-26 19:55   ` SZEDER Gábor
2022-07-25 12:38 ` [PATCH 02/20] t3301-notes.sh: check that default operation mode doesn't take arguments SZEDER Gábor
2022-07-25 12:38 ` [PATCH 03/20] t5505-remote.sh: check the behavior without a subcommand SZEDER Gábor
2022-07-25 14:37   ` Ævar Arnfjörð Bjarmason
2022-07-25 12:38 ` [PATCH 04/20] t0040-parse-options: test parse_options() with various 'parse_opt_flags' SZEDER Gábor
2022-07-25 14:38   ` Ævar Arnfjörð Bjarmason
2022-08-12 15:04     ` SZEDER Gábor
2022-07-25 12:38 ` [PATCH 05/20] api-parse-options.txt: fix description of OPT_CMDMODE SZEDER Gábor
2022-07-25 12:38 ` [PATCH 06/20] parse-options: PARSE_OPT_KEEP_UNKNOWN only applies to --options SZEDER Gábor
2022-07-25 12:38 ` [PATCH 07/20] parse-options: clarify the limitations of PARSE_OPT_NODASH SZEDER Gábor
2022-07-25 12:38 ` [PATCH 08/20] parse-options: drop leading space from '--git-completion-helper' output SZEDER Gábor
2022-07-25 12:38 ` [PATCH 09/20] parse-options: add support for parsing subcommands SZEDER Gábor
2022-07-25 14:43   ` Ævar Arnfjörð Bjarmason
2022-07-25 19:29     ` SZEDER Gábor
2022-07-25 19:41       ` Ævar Arnfjörð Bjarmason [this message]
2022-07-25 21:02         ` SZEDER Gábor
2022-08-12 15:15         ` SZEDER Gábor
2022-07-25 17:37   ` Junio C Hamano
2022-07-25 12:38 ` [PATCH 10/20] builtin/bundle.c: let parse-options parse subcommands SZEDER Gábor
2022-07-25 12:38 ` [PATCH 11/20] builtin/commit-graph.c: " SZEDER Gábor
2022-07-25 12:38 ` [PATCH 12/20] builtin/gc.c: let parse-options parse 'git maintenance's subcommands SZEDER Gábor
2022-07-25 12:38 ` [PATCH 13/20] builtin/hook.c: let parse-option parse subcommands SZEDER Gábor
2022-07-25 12:38 ` [PATCH 14/20] builtin/multi-pack-index.c: let parse-options " SZEDER Gábor
2022-07-25 12:38 ` [PATCH 15/20] builtin/notes.c: " SZEDER Gábor
2022-07-25 16:49   ` Junio C Hamano
2022-07-25 12:38 ` [PATCH 16/20] builtin/reflog.c: " SZEDER Gábor
2022-07-25 12:38 ` [PATCH 17/20] builtin/remote.c: " SZEDER Gábor
2022-07-25 12:38 ` [PATCH 18/20] builtin/sparse-checkout.c: " SZEDER Gábor
2022-07-25 12:38 ` [PATCH 19/20] builtin/stash.c: " SZEDER Gábor
2022-07-25 12:38 ` [PATCH 20/20] builtin/worktree.c: " SZEDER Gábor
2022-07-25 13:15 ` [PATCH 00/20] parse-options: handle subcommands Derrick Stolee
2022-07-25 16:00   ` SZEDER Gábor
2022-07-25 16:08     ` Derrick Stolee
2022-07-25 17:13 ` Ævar Arnfjörð Bjarmason
2022-07-25 17:56 ` Junio C Hamano
2022-07-26 15:42   ` Johannes Schindelin
2022-07-26 18:02     ` Ævar Arnfjörð Bjarmason
2022-08-19 16:03 ` [PATCH v2 " SZEDER Gábor
2022-08-19 16:03   ` [PATCH v2 01/20] git.c: update NO_PARSEOPT markings SZEDER Gábor
2022-08-19 16:03   ` [PATCH v2 02/20] t3301-notes.sh: check that default operation mode doesn't take arguments SZEDER Gábor
2022-08-19 16:03   ` [PATCH v2 03/20] t5505-remote.sh: check the behavior without a subcommand SZEDER Gábor
2022-08-19 16:03   ` [PATCH v2 04/20] t0040-parse-options: test parse_options() with various 'parse_opt_flags' SZEDER Gábor
2022-08-19 17:23     ` Ævar Arnfjörð Bjarmason
2022-08-20 11:14       ` SZEDER Gábor
2022-08-19 18:18     ` Junio C Hamano
2022-08-20 10:31       ` SZEDER Gábor
2022-08-20 21:27         ` Junio C Hamano
2022-08-19 16:03   ` [PATCH v2 05/20] api-parse-options.txt: fix description of OPT_CMDMODE SZEDER Gábor
2022-08-19 16:03   ` [PATCH v2 06/20] parse-options: PARSE_OPT_KEEP_UNKNOWN only applies to --options SZEDER Gábor
2022-08-19 16:03   ` [PATCH v2 07/20] parse-options: clarify the limitations of PARSE_OPT_NODASH SZEDER Gábor
2022-08-19 16:03   ` [PATCH v2 08/20] parse-options: drop leading space from '--git-completion-helper' output SZEDER Gábor
2022-08-19 17:30     ` Ævar Arnfjörð Bjarmason
2022-08-19 18:35       ` SZEDER Gábor
2022-08-19 16:04   ` [PATCH v2 09/20] parse-options: add support for parsing subcommands SZEDER Gábor
2022-08-19 17:33     ` Ævar Arnfjörð Bjarmason
2022-08-19 19:03     ` Ævar Arnfjörð Bjarmason
2022-08-19 16:04   ` [PATCH v2 10/20] builtin/bundle.c: let parse-options parse subcommands SZEDER Gábor
2022-08-19 17:50     ` Ævar Arnfjörð Bjarmason
2022-08-19 16:04   ` [PATCH v2 11/20] builtin/commit-graph.c: " SZEDER Gábor
2022-08-19 17:53     ` Ævar Arnfjörð Bjarmason
2022-08-19 17:56       ` Ævar Arnfjörð Bjarmason
2022-08-19 18:22       ` SZEDER Gábor
2022-08-19 16:04   ` [PATCH v2 12/20] builtin/gc.c: let parse-options parse 'git maintenance's subcommands SZEDER Gábor
2022-08-19 20:59     ` Junio C Hamano
2022-08-19 16:04   ` [PATCH v2 13/20] builtin/hook.c: let parse-options parse subcommands SZEDER Gábor
2022-08-19 16:04   ` [PATCH v2 14/20] builtin/multi-pack-index.c: " SZEDER Gábor
2022-08-19 17:57     ` Ævar Arnfjörð Bjarmason
2022-08-19 16:04   ` [PATCH v2 15/20] builtin/notes.c: " SZEDER Gábor
2022-08-19 18:01     ` Ævar Arnfjörð Bjarmason
2022-08-21 17:56       ` SZEDER Gábor
2022-08-19 16:04   ` [PATCH v2 16/20] builtin/reflog.c: " SZEDER Gábor
2022-08-19 18:08     ` Ævar Arnfjörð Bjarmason
2022-08-19 16:04   ` [PATCH v2 17/20] builtin/remote.c: " SZEDER Gábor
2022-08-19 16:04   ` [PATCH v2 18/20] builtin/sparse-checkout.c: " SZEDER Gábor
2022-08-19 16:04   ` [PATCH v2 19/20] builtin/stash.c: " SZEDER Gábor
2022-08-19 19:06     ` Ævar Arnfjörð Bjarmason
2022-08-20 10:27       ` SZEDER Gábor
2022-08-19 16:04   ` [PATCH v2 20/20] builtin/worktree.c: " SZEDER Gábor
2022-09-05 18:50   ` [PATCH 0/5] parse-options: minor cleanups for handling subcommands SZEDER Gábor
2022-09-05 18:50     ` [PATCH 1/5] t0040-parse-options: remove leftover debugging SZEDER Gábor
2022-09-05 18:50     ` [PATCH 2/5] test-parse-options.c: don't use for loop initial declaration SZEDER Gábor
2022-09-05 18:50     ` [PATCH 3/5] test-parse-options.c: fix style of comparison with zero SZEDER Gábor
2022-09-05 18:50     ` [PATCH 4/5] notes: simplify default operation mode arguments check SZEDER Gábor
2022-09-05 18:50     ` [PATCH 5/5] notes, remote: show unknown subcommands between `' SZEDER Gábor
2022-09-07 19:12     ` [PATCH 0/5] parse-options: minor cleanups for handling subcommands Junio C Hamano
2022-09-07 21:22       ` SZEDER Gábor

Reply instructions:

You may reply publicly to this message via plain-text email
using any one of the following methods:

* Save the following mbox file, import it into your mail client,
  and reply-to-all from there: mbox

  Avoid top-posting and favor interleaved quoting:
  https://en.wikipedia.org/wiki/Posting_style#Interleaved_style

* Reply using the --to, --cc, and --in-reply-to
  switches of git-send-email(1):

  git send-email \
    --in-reply-to=220725.86wnc1nf6c.gmgdl@evledraar.gmail.com \
    --to=avarab@gmail.com \
    --cc=git@vger.kernel.org \
    --cc=szeder.dev@gmail.com \
    /path/to/YOUR_REPLY

  https://kernel.org/pub/software/scm/git/docs/git-send-email.html

* If your mail client supports setting the In-Reply-To header
  via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line before the message body.
This is an external index of several public inboxes,
see mirroring instructions on how to clone and mirror
all data and code used by this external index.