git/list[1] front-page[2] threads[3] people[4] search[5] about
 

Re: [PATCH 09/20] parse-options: add support for parsing subcommands

From
Junio C Hamano <gitster@pobox.com>
Date
Jul 25, 2022, 17:37 UTC
Message-ID
<xmqqa68x5c1i.fsf@gitster.g>
In-Reply-To
<20220725123857.2773963-10-szeder.dev@gmail.com>
SZEDER Gábor <szeder.dev@gmail.com> writes:
Show 16 quoted lines
> The approach is guided by the following observations:
> ...
> So in the end subcommand declaration and parsing would look something
> like this:
>
>     parse_opt_subcommand_fn *fn = NULL;
>     struct option builtin_commit_graph_options[] = {
>         OPT_STRING(0, "object-dir", &opts.obj_dir, N_("dir"),
>                    N_("the object directory to store the graph")),
>         OPT_SUBCOMMAND("verify", &fn, graph_verify),
>         OPT_SUBCOMMAND("write", &fn, graph_write),
>         OPT_END(),
>     };
>     argc = parse_options(argc, argv, prefix, options,
>                          builtin_commit_graph_usage, 0);
>     return fn(argc, argv, prefix);

All makes sense and exactly as I expected to see, after reading the later steps [10-20/20] that make use of the facility. Nicely designed.

> Here each OPT_SUBCOMMAND specifies the name of the subcommand and the
> function implementing it, and the same pointer to 'fn' where
> parse_options() will store the function associated with the given
> subcommand.

Puzzling. Isn't parse_options() an read-only operation with respect to the elements of the struct option array?

With s/store/expect to find/, I would understand the above, though.
> There is no need to check whether 'fn' is non-NULL before
> invoking it:

Again, this is puzzling. "There is no need to"---to whom does this statement mean to advise? The implementor of the new codepath IN parse_options() to handle OPT_SUBCOMMAND()?

> if there were no subcommands given on the command line
> then the parse_options() call would error out and show usage.  
I think that you mean to say
    When one or more OPT_SUBCOMMAND elements exist in an array of
    struct option, parse_options() will error out if none of them
    triggers.

and that makes sense, but I cannot quite tell how it relates to the previous sentence about fn possibly being NULL.

Ahh, OK. Let's try to rephrase to see if I can make it easier to understand.

    Here each OPT_SUBCOMMAND specifies ... with the given
    subcommand.
    After parse_options() returns, the variable 'fn' would have been
    updated to point at the function to call, if one of the
    subcommand specified by the OPT_SUBCOMMAND() is given on the
    command line.
    - When the PARSE_OPT_SUBCOMMAND_OPTIONAL flag is given to
      parse_options(), and no subcommand is given on the command
      line, the variable 'fn' is left intact.  This can be used to
      implement a command with the "default" subcommand by
      initializing the variable 'fn' to the default value.
    - Otherwise, parse_options() will error out and show usage, when
      no subcommand is given.
    - If more than one subcommands are given from the command line,
      parse_options() will stop at the first one, and treat the
      remainder of the command line as arguments to the subcommand.
    
> In case
> a command has a default operation mode, 'fn' should be initialized to
> the function implementing that mode, and parse_options() should be
> invoked with the PARSE_OPT_SUBCOMMAND_OPTIONAL flag.
OK.
Show 6 quoted lines
> Some thoughts about the implementation:
>
>   - Arguably it is a bit weird that the same pointer to 'fn' have to
>     be specified as 'value' for each OPT_SUBCOMMAND, but we need a way
>     to tell parse_options() where to put the function associated with
>     the given subcommand, and I didn't like the alternatives:

I do not find this so disturbing. This is similar to CMDMODE in spirit in that only one has to be chosen. CMDMODE needs to go an extra mile to ensure that by checking the current value in the variable pointed by the pointer because the parser does not stop immediately after getting one, but SUBCOMMAND can afford to be simpler because the parser immediately stops once a subcommand is found.

In a sense, OPT_SUBCOMMAND() does not have to exist as the first-class mechanism. With just two primitives:

 - a flag that says "after seeing this option, immediately stop
   parsing".
 - something similar to OPT_SET_INT() but works with a function pointer.

we can go 80% of the way to implement OPT_SUBCOMMAND() as a thin wrapper (there is "one of the OPT_SET_FUNC() must be triggered" that needs new code specific to the need, which is the other 20%).

Show 11 quoted lines
>   - I decided against automatically calling the subcommand function
>     from within parse_options(), because:
>
>       - There are commands that have to perform additional actions
>         after option parsing but before calling the function
>         implementing the specified subcommand.
>
>       - The return code of the subcommand is usually the return code
>         of the git command, but preserving the return code of the
>         automatically called subcommand function would have made the
>         API awkward.

Yes, the above makes perfect sense. Also I suspect that we would find some cases where being able to use two or more variables become handy.

Show 7 quoted lines
> +			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");
> +			}

"these" without giving the violating value? A "%d" would be cheap addition, but I see this was copied from elsewhere.

Thanks.
Previous: SZEDER GáborNext: SZEDER Gábor
Message 30 of 97 in “parse-options: handle subcommands”
  1. 00/20 parse-options: handle subcommandsSZEDER Gábor, Jul 25, 2022
  2. 01/20 git.c: update NO_PARSEOPT markingsSZEDER Gábor, Jul 25, 2022
  3. Ævar Arnfjörð BjarmasonJul 25, 2022
  4. SZEDER GáborAug 2, 2022
  5. Junio C HamanoAug 2, 2022
  6. Ævar Arnfjörð BjarmasonAug 3, 2022
  7. SZEDER GáborAug 3, 2022
  8. Ævar Arnfjörð BjarmasonAug 4, 2022
  9. Junio C HamanoAug 11, 2022
  10. SZEDER GáborAug 12, 2022
  11. Junio C HamanoAug 12, 2022
  12. SZEDER GáborJul 26, 2022
  13. 02/20 t3301-notes.sh: check that default operation mode doesn't take argumentsSZEDER Gábor, Jul 25, 2022
  14. 03/20 t5505-remote.sh: check the behavior without a subcommandSZEDER Gábor, Jul 25, 2022
  15. Ævar Arnfjörð BjarmasonJul 25, 2022
  16. 04/20 t0040-parse-options: test parse_options() with various 'parse_opt_flags'SZEDER Gábor, Jul 25, 2022
  17. Ævar Arnfjörð BjarmasonJul 25, 2022
  18. SZEDER GáborAug 12, 2022
  19. 05/20 api-parse-options.txt: fix description of OPT_CMDMODESZEDER Gábor, Jul 25, 2022
  20. 06/20 parse-options: PARSE_OPT_KEEP_UNKNOWN only applies to --optionsSZEDER Gábor, Jul 25, 2022
  21. 07/20 parse-options: clarify the limitations of PARSE_OPT_NODASHSZEDER Gábor, Jul 25, 2022
  22. 08/20 parse-options: drop leading space from '--git-completion-helper' outputSZEDER Gábor, Jul 25, 2022
  23. 10/20 builtin/bundle.c: let parse-options parse subcommandsSZEDER Gábor, Jul 25, 2022
  24. 09/20 parse-options: add support for parsing subcommandsSZEDER Gábor, Jul 25, 2022
  25. Ævar Arnfjörð BjarmasonJul 25, 2022
  26. SZEDER GáborJul 25, 2022
  27. Ævar Arnfjörð BjarmasonJul 25, 2022
  28. SZEDER GáborJul 25, 2022
  29. SZEDER GáborAug 12, 2022
  30. Junio C HamanoJul 25, 2022
  31. 11/20 builtin/commit-graph.c: let parse-options parse subcommandsSZEDER Gábor, Jul 25, 2022
  32. 12/20 builtin/gc.c: let parse-options parse 'git maintenance's subcommandsSZEDER Gábor, Jul 25, 2022
  33. 13/20 builtin/hook.c: let parse-option parse subcommandsSZEDER Gábor, Jul 25, 2022
  34. 15/20 builtin/notes.c: let parse-options parse subcommandsSZEDER Gábor, Jul 25, 2022
  35. Junio C HamanoJul 25, 2022
  36. 14/20 builtin/multi-pack-index.c: let parse-options parse subcommandsSZEDER Gábor, Jul 25, 2022
  37. 16/20 builtin/reflog.c: let parse-options parse subcommandsSZEDER Gábor, Jul 25, 2022
  38. 17/20 builtin/remote.c: let parse-options parse subcommandsSZEDER Gábor, Jul 25, 2022
  39. 18/20 builtin/sparse-checkout.c: let parse-options parse subcommandsSZEDER Gábor, Jul 25, 2022
  40. 19/20 builtin/stash.c: let parse-options parse subcommandsSZEDER Gábor, Jul 25, 2022
  41. 20/20 builtin/worktree.c: let parse-options parse subcommandsSZEDER Gábor, Jul 25, 2022
  42. Derrick StoleeJul 25, 2022
  43. SZEDER GáborJul 25, 2022
  44. Derrick StoleeJul 25, 2022
  45. Ævar Arnfjörð BjarmasonJul 25, 2022
  46. Junio C HamanoJul 25, 2022
  47. Johannes SchindelinJul 26, 2022
  48. Ævar Arnfjörð BjarmasonJul 26, 2022
  49. 00/20 parse-options: handle subcommandsSZEDER Gábor, Aug 19, 2022
  50. 09/20 parse-options: add support for parsing subcommandsSZEDER Gábor, Aug 19, 2022
  51. Ævar Arnfjörð BjarmasonAug 19, 2022
  52. Ævar Arnfjörð BjarmasonAug 19, 2022
  53. 15/20 builtin/notes.c: let parse-options parse subcommandsSZEDER Gábor, Aug 19, 2022
  54. Ævar Arnfjörð BjarmasonAug 19, 2022
  55. SZEDER GáborAug 21, 2022
  56. 17/20 builtin/remote.c: let parse-options parse subcommandsSZEDER Gábor, Aug 19, 2022
  57. 02/20 t3301-notes.sh: check that default operation mode doesn't take argumentsSZEDER Gábor, Aug 19, 2022
  58. 13/20 builtin/hook.c: let parse-options parse subcommandsSZEDER Gábor, Aug 19, 2022
  59. 10/20 builtin/bundle.c: let parse-options parse subcommandsSZEDER Gábor, Aug 19, 2022
  60. Ævar Arnfjörð BjarmasonAug 19, 2022
  61. 12/20 builtin/gc.c: let parse-options parse 'git maintenance's subcommandsSZEDER Gábor, Aug 19, 2022
  62. Junio C HamanoAug 19, 2022
  63. 16/20 builtin/reflog.c: let parse-options parse subcommandsSZEDER Gábor, Aug 19, 2022
  64. Ævar Arnfjörð BjarmasonAug 19, 2022
  65. 11/20 builtin/commit-graph.c: let parse-options parse subcommandsSZEDER Gábor, Aug 19, 2022
  66. Ævar Arnfjörð BjarmasonAug 19, 2022
  67. Ævar Arnfjörð BjarmasonAug 19, 2022
  68. SZEDER GáborAug 19, 2022
  69. 18/20 builtin/sparse-checkout.c: let parse-options parse subcommandsSZEDER Gábor, Aug 19, 2022
  70. 01/20 git.c: update NO_PARSEOPT markingsSZEDER Gábor, Aug 19, 2022
  71. 14/20 builtin/multi-pack-index.c: let parse-options parse subcommandsSZEDER Gábor, Aug 19, 2022
  72. Ævar Arnfjörð BjarmasonAug 19, 2022
  73. 04/20 t0040-parse-options: test parse_options() with various 'parse_opt_flags'SZEDER Gábor, Aug 19, 2022
  74. Ævar Arnfjörð BjarmasonAug 19, 2022
  75. SZEDER GáborAug 20, 2022
  76. Junio C HamanoAug 19, 2022
  77. SZEDER GáborAug 20, 2022
  78. Junio C HamanoAug 20, 2022
  79. 08/20 parse-options: drop leading space from '--git-completion-helper' outputSZEDER Gábor, Aug 19, 2022
  80. Ævar Arnfjörð BjarmasonAug 19, 2022
  81. SZEDER GáborAug 19, 2022
  82. 19/20 builtin/stash.c: let parse-options parse subcommandsSZEDER Gábor, Aug 19, 2022
  83. Ævar Arnfjörð BjarmasonAug 19, 2022
  84. SZEDER GáborAug 20, 2022
  85. 06/20 parse-options: PARSE_OPT_KEEP_UNKNOWN only applies to --optionsSZEDER Gábor, Aug 19, 2022
  86. 05/20 api-parse-options.txt: fix description of OPT_CMDMODESZEDER Gábor, Aug 19, 2022
  87. 20/20 builtin/worktree.c: let parse-options parse subcommandsSZEDER Gábor, Aug 19, 2022
  88. 07/20 parse-options: clarify the limitations of PARSE_OPT_NODASHSZEDER Gábor, Aug 19, 2022
  89. 03/20 t5505-remote.sh: check the behavior without a subcommandSZEDER Gábor, Aug 19, 2022
  90. 0/5 parse-options: minor cleanups for handling subcommandsSZEDER Gábor, Sep 5, 2022
  91. 2/5 test-parse-options.c: don't use for loop initial declarationSZEDER Gábor, Sep 5, 2022
  92. 1/5 t0040-parse-options: remove leftover debuggingSZEDER Gábor, Sep 5, 2022
  93. 3/5 test-parse-options.c: fix style of comparison with zeroSZEDER Gábor, Sep 5, 2022
  94. 4/5 notes: simplify default operation mode arguments checkSZEDER Gábor, Sep 5, 2022
  95. 5/5 notes, remote: show unknown subcommands between `'SZEDER Gábor, Sep 5, 2022
  96. Junio C HamanoSep 7, 2022
  97. SZEDER GáborSep 7, 2022

Read the whole thread, see it on lore, or plain text.

$ cat FOOTERMessages come from the public archive at lore.kernel.org/git, fetched every hour. The front page is chosen and written each morning by an AI editor and can be wrong; the threads themselves are the record. About and API. For agents: an MCP server at https://gitlist.dev/mcp, and any thread, story or person page as Markdown by adding .md to its URL (or sending Accept: text/markdown). Details in /llms.txt.