зеркало из https://github.com/microsoft/git.git
Merge branch 'sg/parse-options-subcommand'
Introduce the "subcommand" mode to parse-options API and update the command line parser of Git commands with subcommands. * sg/parse-options-subcommand: (23 commits) remote: run "remote rm" argv through parse_options() maintenance: add parse-options boilerplate for subcommands pass subcommand "prefix" arguments to parse_options() builtin/worktree.c: let parse-options parse subcommands builtin/stash.c: let parse-options parse subcommands builtin/sparse-checkout.c: let parse-options parse subcommands builtin/remote.c: let parse-options parse subcommands builtin/reflog.c: let parse-options parse subcommands builtin/notes.c: let parse-options parse subcommands builtin/multi-pack-index.c: let parse-options parse subcommands builtin/hook.c: let parse-options parse subcommands builtin/gc.c: let parse-options parse 'git maintenance's subcommands builtin/commit-graph.c: let parse-options parse subcommands builtin/bundle.c: let parse-options parse subcommands parse-options: add support for parsing subcommands parse-options: drop leading space from '--git-completion-helper' output parse-options: clarify the limitations of PARSE_OPT_NODASH parse-options: PARSE_OPT_KEEP_UNKNOWN only applies to --options api-parse-options.txt: fix description of OPT_CMDMODE t0040-parse-options: test parse_options() with various 'parse_opt_flags' ...
This commit is contained in:
Коммит
d528044c83
|
@ -8,7 +8,8 @@ Basics
|
|||
------
|
||||
|
||||
The argument vector `argv[]` may usually contain mandatory or optional
|
||||
'non-option arguments', e.g. a filename or a branch, and 'options'.
|
||||
'non-option arguments', e.g. a filename or a branch, 'options', and
|
||||
'subcommands'.
|
||||
Options are optional arguments that start with a dash and
|
||||
that allow to change the behavior of a command.
|
||||
|
||||
|
@ -48,6 +49,33 @@ The parse-options API allows:
|
|||
option, e.g. `-a -b --option -- --this-is-a-file` indicates that
|
||||
`--this-is-a-file` must not be processed as an option.
|
||||
|
||||
Subcommands are special in a couple of ways:
|
||||
|
||||
* Subcommands only have long form, and they have no double dash prefix, no
|
||||
negated form, and no description, and they don't take any arguments, and
|
||||
can't be abbreviated.
|
||||
|
||||
* There must be exactly one subcommand among the arguments, or zero if the
|
||||
command has a default operation mode.
|
||||
|
||||
* All arguments following the subcommand are considered to be arguments of
|
||||
the subcommand, and, conversely, arguments meant for the subcommand may
|
||||
not preceed the subcommand.
|
||||
|
||||
Therefore, if the options array contains at least one subcommand and
|
||||
`parse_options()` encounters the first dashless argument, it will either:
|
||||
|
||||
* stop and return, if that dashless argument is a known subcommand, setting
|
||||
`value` to the function pointer associated with that subcommand, storing
|
||||
the name of the subcommand in argv[0], and leaving the rest of the
|
||||
arguments unprocessed, or
|
||||
|
||||
* stop and return, if it was invoked with the `PARSE_OPT_SUBCOMMAND_OPTIONAL`
|
||||
flag and that dashless argument doesn't match any subcommands, leaving
|
||||
`value` unchanged and the rest of the arguments unprocessed, or
|
||||
|
||||
* show error and usage, and abort.
|
||||
|
||||
Steps to parse options
|
||||
----------------------
|
||||
|
||||
|
@ -90,8 +118,8 @@ Flags are the bitwise-or of:
|
|||
Keep the first argument, which contains the program name. It's
|
||||
removed from argv[] by default.
|
||||
|
||||
`PARSE_OPT_KEEP_UNKNOWN`::
|
||||
Keep unknown arguments instead of erroring out. This doesn't
|
||||
`PARSE_OPT_KEEP_UNKNOWN_OPT`::
|
||||
Keep unknown options instead of erroring out. This doesn't
|
||||
work for all combinations of arguments as users might expect
|
||||
it to do. E.g. if the first argument in `--unknown --known`
|
||||
takes a value (which we can't know), the second one is
|
||||
|
@ -101,6 +129,8 @@ Flags are the bitwise-or of:
|
|||
non-option, not as a value belonging to the unknown option,
|
||||
the parser early. That's why parse_options() errors out if
|
||||
both options are set.
|
||||
Note that non-option arguments are always kept, even without
|
||||
this flag.
|
||||
|
||||
`PARSE_OPT_NO_INTERNAL_HELP`::
|
||||
By default, parse_options() handles `-h`, `--help` and
|
||||
|
@ -108,6 +138,13 @@ Flags are the bitwise-or of:
|
|||
turns it off and allows one to add custom handlers for these
|
||||
options, or to just leave them unknown.
|
||||
|
||||
`PARSE_OPT_SUBCOMMAND_OPTIONAL`::
|
||||
Don't error out when no subcommand is specified.
|
||||
|
||||
Note that `PARSE_OPT_STOP_AT_NON_OPTION` is incompatible with subcommands;
|
||||
while `PARSE_OPT_KEEP_DASHDASH` and `PARSE_OPT_KEEP_UNKNOWN_OPT` can only be
|
||||
used with subcommands when combined with `PARSE_OPT_SUBCOMMAND_OPTIONAL`.
|
||||
|
||||
Data Structure
|
||||
--------------
|
||||
|
||||
|
@ -236,10 +273,14 @@ There are some macros to easily define options:
|
|||
`OPT_CMDMODE(short, long, &int_var, description, enum_val)`::
|
||||
Define an "operation mode" option, only one of which in the same
|
||||
group of "operating mode" options that share the same `int_var`
|
||||
can be given by the user. `enum_val` is set to `int_var` when the
|
||||
can be given by the user. `int_var` is set to `enum_val` when the
|
||||
option is used, but an error is reported if other "operating mode"
|
||||
option has already set its value to the same `int_var`.
|
||||
In new commands consider using subcommands instead.
|
||||
|
||||
`OPT_SUBCOMMAND(long, &fn_ptr, subcommand_fn)`::
|
||||
Define a subcommand. `subcommand_fn` is put into `fn_ptr` when
|
||||
this subcommand is used.
|
||||
|
||||
The last element of the array must be `OPT_END()`.
|
||||
|
||||
|
|
|
@ -75,7 +75,7 @@ static int run_remote_archiver(int argc, const char **argv,
|
|||
|
||||
#define PARSE_OPT_KEEP_ALL ( PARSE_OPT_KEEP_DASHDASH | \
|
||||
PARSE_OPT_KEEP_ARGV0 | \
|
||||
PARSE_OPT_KEEP_UNKNOWN | \
|
||||
PARSE_OPT_KEEP_UNKNOWN_OPT | \
|
||||
PARSE_OPT_NO_INTERNAL_HELP )
|
||||
|
||||
int cmd_archive(int argc, const char **argv, const char *prefix)
|
||||
|
|
|
@ -1324,7 +1324,7 @@ int cmd_bisect__helper(int argc, const char **argv, const char *prefix)
|
|||
|
||||
argc = parse_options(argc, argv, prefix, options,
|
||||
git_bisect_helper_usage,
|
||||
PARSE_OPT_KEEP_DASHDASH | PARSE_OPT_KEEP_UNKNOWN);
|
||||
PARSE_OPT_KEEP_DASHDASH | PARSE_OPT_KEEP_UNKNOWN_OPT);
|
||||
|
||||
if (!cmdmode)
|
||||
usage_with_options(git_bisect_helper_usage, options);
|
||||
|
|
|
@ -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);
|
||||
|
|
|
@ -195,30 +195,19 @@ cleanup:
|
|||
|
||||
int cmd_bundle(int argc, const char **argv, const char *prefix)
|
||||
{
|
||||
parse_opt_subcommand_fn *fn = NULL;
|
||||
struct option options[] = {
|
||||
OPT_SUBCOMMAND("create", &fn, cmd_bundle_create),
|
||||
OPT_SUBCOMMAND("verify", &fn, cmd_bundle_verify),
|
||||
OPT_SUBCOMMAND("list-heads", &fn, cmd_bundle_list_heads),
|
||||
OPT_SUBCOMMAND("unbundle", &fn, cmd_bundle_unbundle),
|
||||
OPT_END()
|
||||
};
|
||||
int result;
|
||||
|
||||
argc = parse_options(argc, argv, prefix, options, builtin_bundle_usage,
|
||||
PARSE_OPT_STOP_AT_NON_OPTION);
|
||||
0);
|
||||
|
||||
packet_trace_identity("bundle");
|
||||
|
||||
if (argc < 2)
|
||||
usage_with_options(builtin_bundle_usage, options);
|
||||
|
||||
else if (!strcmp(argv[0], "create"))
|
||||
result = cmd_bundle_create(argc, argv, prefix);
|
||||
else if (!strcmp(argv[0], "verify"))
|
||||
result = cmd_bundle_verify(argc, argv, prefix);
|
||||
else if (!strcmp(argv[0], "list-heads"))
|
||||
result = cmd_bundle_list_heads(argc, argv, prefix);
|
||||
else if (!strcmp(argv[0], "unbundle"))
|
||||
result = cmd_bundle_unbundle(argc, argv, prefix);
|
||||
else {
|
||||
error(_("Unknown subcommand: %s"), argv[0]);
|
||||
usage_with_options(builtin_bundle_usage, options);
|
||||
}
|
||||
return result ? 1 : 0;
|
||||
return !!fn(argc, argv, prefix);
|
||||
}
|
||||
|
|
|
@ -58,7 +58,7 @@ static struct option *add_common_options(struct option *to)
|
|||
return parse_options_concat(common_opts, to);
|
||||
}
|
||||
|
||||
static int graph_verify(int argc, const char **argv)
|
||||
static int graph_verify(int argc, const char **argv, const char *prefix)
|
||||
{
|
||||
struct commit_graph *graph = NULL;
|
||||
struct object_directory *odb = NULL;
|
||||
|
@ -80,7 +80,7 @@ static int graph_verify(int argc, const char **argv)
|
|||
trace2_cmd_mode("verify");
|
||||
|
||||
opts.progress = isatty(2);
|
||||
argc = parse_options(argc, argv, NULL,
|
||||
argc = parse_options(argc, argv, prefix,
|
||||
options,
|
||||
builtin_commit_graph_verify_usage, 0);
|
||||
if (argc)
|
||||
|
@ -190,7 +190,7 @@ static int git_commit_graph_write_config(const char *var, const char *value,
|
|||
return 0;
|
||||
}
|
||||
|
||||
static int graph_write(int argc, const char **argv)
|
||||
static int graph_write(int argc, const char **argv, const char *prefix)
|
||||
{
|
||||
struct string_list pack_indexes = STRING_LIST_INIT_DUP;
|
||||
struct strbuf buf = STRBUF_INIT;
|
||||
|
@ -241,7 +241,7 @@ static int graph_write(int argc, const char **argv)
|
|||
|
||||
git_config(git_commit_graph_write_config, &opts);
|
||||
|
||||
argc = parse_options(argc, argv, NULL,
|
||||
argc = parse_options(argc, argv, prefix,
|
||||
options,
|
||||
builtin_commit_graph_write_usage, 0);
|
||||
if (argc)
|
||||
|
@ -307,26 +307,22 @@ cleanup:
|
|||
|
||||
int cmd_commit_graph(int argc, const char **argv, const char *prefix)
|
||||
{
|
||||
struct option *builtin_commit_graph_options = common_opts;
|
||||
parse_opt_subcommand_fn *fn = NULL;
|
||||
struct option builtin_commit_graph_options[] = {
|
||||
OPT_SUBCOMMAND("verify", &fn, graph_verify),
|
||||
OPT_SUBCOMMAND("write", &fn, graph_write),
|
||||
OPT_END(),
|
||||
};
|
||||
struct option *options = parse_options_concat(builtin_commit_graph_options, common_opts);
|
||||
|
||||
git_config(git_default_config, NULL);
|
||||
argc = parse_options(argc, argv, prefix,
|
||||
builtin_commit_graph_options,
|
||||
builtin_commit_graph_usage,
|
||||
PARSE_OPT_STOP_AT_NON_OPTION);
|
||||
if (!argc)
|
||||
goto usage;
|
||||
|
||||
read_replace_refs = 0;
|
||||
save_commit_buffer = 0;
|
||||
|
||||
if (!strcmp(argv[0], "verify"))
|
||||
return graph_verify(argc, argv);
|
||||
else if (argc && !strcmp(argv[0], "write"))
|
||||
return graph_write(argc, argv);
|
||||
argc = parse_options(argc, argv, prefix, options,
|
||||
builtin_commit_graph_usage, 0);
|
||||
FREE_AND_NULL(options);
|
||||
|
||||
error(_("unrecognized subcommand: %s"), argv[0]);
|
||||
usage:
|
||||
usage_with_options(builtin_commit_graph_usage,
|
||||
builtin_commit_graph_options);
|
||||
return fn(argc, argv, prefix);
|
||||
}
|
||||
|
|
|
@ -716,7 +716,7 @@ int cmd_difftool(int argc, const char **argv, const char *prefix)
|
|||
symlinks = has_symlinks;
|
||||
|
||||
argc = parse_options(argc, argv, prefix, builtin_difftool_options,
|
||||
builtin_difftool_usage, PARSE_OPT_KEEP_UNKNOWN |
|
||||
builtin_difftool_usage, PARSE_OPT_KEEP_UNKNOWN_OPT |
|
||||
PARSE_OPT_KEEP_DASHDASH);
|
||||
|
||||
if (tool_help)
|
||||
|
|
|
@ -50,7 +50,7 @@ int cmd_env__helper(int argc, const char **argv, const char *prefix)
|
|||
};
|
||||
|
||||
argc = parse_options(argc, argv, prefix, opts, env__helper_usage,
|
||||
PARSE_OPT_KEEP_UNKNOWN);
|
||||
PARSE_OPT_KEEP_UNKNOWN_OPT);
|
||||
if (env_default && !*env_default)
|
||||
usage_with_options(env__helper_usage, opts);
|
||||
if (!cmdmode)
|
||||
|
|
|
@ -1221,7 +1221,7 @@ int cmd_fast_export(int argc, const char **argv, const char *prefix)
|
|||
revs.sources = &revision_sources;
|
||||
revs.rewrite_parents = 1;
|
||||
argc = parse_options(argc, argv, prefix, options, fast_export_usage,
|
||||
PARSE_OPT_KEEP_ARGV0 | PARSE_OPT_KEEP_UNKNOWN);
|
||||
PARSE_OPT_KEEP_ARGV0 | PARSE_OPT_KEEP_UNKNOWN_OPT);
|
||||
argc = setup_revisions(argc, argv, &revs, NULL);
|
||||
if (argc > 1)
|
||||
usage_with_options (fast_export_usage, options);
|
||||
|
|
81
builtin/gc.c
81
builtin/gc.c
|
@ -1459,14 +1459,28 @@ static char *get_maintpath(void)
|
|||
return strbuf_detach(&sb, NULL);
|
||||
}
|
||||
|
||||
static int maintenance_register(void)
|
||||
static char const * const builtin_maintenance_register_usage[] = {
|
||||
N_("git maintenance register"),
|
||||
NULL
|
||||
};
|
||||
|
||||
static int maintenance_register(int argc, const char **argv, const char *prefix)
|
||||
{
|
||||
struct option options[] = {
|
||||
OPT_END(),
|
||||
};
|
||||
int rc;
|
||||
char *config_value;
|
||||
struct child_process config_set = CHILD_PROCESS_INIT;
|
||||
struct child_process config_get = CHILD_PROCESS_INIT;
|
||||
char *maintpath = get_maintpath();
|
||||
|
||||
argc = parse_options(argc, argv, prefix, options,
|
||||
builtin_maintenance_register_usage, 0);
|
||||
if (argc)
|
||||
usage_with_options(builtin_maintenance_register_usage,
|
||||
options);
|
||||
|
||||
/* Disable foreground maintenance */
|
||||
git_config_set("maintenance.auto", "false");
|
||||
|
||||
|
@ -1503,12 +1517,26 @@ done:
|
|||
return rc;
|
||||
}
|
||||
|
||||
static int maintenance_unregister(void)
|
||||
static char const * const builtin_maintenance_unregister_usage[] = {
|
||||
N_("git maintenance unregister"),
|
||||
NULL
|
||||
};
|
||||
|
||||
static int maintenance_unregister(int argc, const char **argv, const char *prefix)
|
||||
{
|
||||
struct option options[] = {
|
||||
OPT_END(),
|
||||
};
|
||||
int rc;
|
||||
struct child_process config_unset = CHILD_PROCESS_INIT;
|
||||
char *maintpath = get_maintpath();
|
||||
|
||||
argc = parse_options(argc, argv, prefix, options,
|
||||
builtin_maintenance_unregister_usage, 0);
|
||||
if (argc)
|
||||
usage_with_options(builtin_maintenance_unregister_usage,
|
||||
options);
|
||||
|
||||
config_unset.git_cmd = 1;
|
||||
strvec_pushl(&config_unset.args, "config", "--global", "--unset",
|
||||
"--fixed-value", "maintenance.repo", maintpath, NULL);
|
||||
|
@ -2490,6 +2518,7 @@ static int maintenance_start(int argc, const char **argv, const char *prefix)
|
|||
PARSE_OPT_NONEG, maintenance_opt_scheduler),
|
||||
OPT_END()
|
||||
};
|
||||
const char *register_args[] = { "register", NULL };
|
||||
|
||||
argc = parse_options(argc, argv, prefix, options,
|
||||
builtin_maintenance_start_usage, 0);
|
||||
|
@ -2499,34 +2528,46 @@ static int maintenance_start(int argc, const char **argv, const char *prefix)
|
|||
opts.scheduler = resolve_scheduler(opts.scheduler);
|
||||
validate_scheduler(opts.scheduler);
|
||||
|
||||
if (maintenance_register())
|
||||
if (maintenance_register(ARRAY_SIZE(register_args)-1, register_args, NULL))
|
||||
warning(_("failed to add repo to global config"));
|
||||
return update_background_schedule(&opts, 1);
|
||||
}
|
||||
|
||||
static int maintenance_stop(void)
|
||||
static const char *const builtin_maintenance_stop_usage[] = {
|
||||
N_("git maintenance stop"),
|
||||
NULL
|
||||
};
|
||||
|
||||
static int maintenance_stop(int argc, const char **argv, const char *prefix)
|
||||
{
|
||||
struct option options[] = {
|
||||
OPT_END()
|
||||
};
|
||||
argc = parse_options(argc, argv, prefix, options,
|
||||
builtin_maintenance_stop_usage, 0);
|
||||
if (argc)
|
||||
usage_with_options(builtin_maintenance_stop_usage, options);
|
||||
return update_background_schedule(NULL, 0);
|
||||
}
|
||||
|
||||
static const char builtin_maintenance_usage[] = N_("git maintenance <subcommand> [<options>]");
|
||||
static const char * const builtin_maintenance_usage[] = {
|
||||
N_("git maintenance <subcommand> [<options>]"),
|
||||
NULL,
|
||||
};
|
||||
|
||||
int cmd_maintenance(int argc, const char **argv, const char *prefix)
|
||||
{
|
||||
if (argc < 2 ||
|
||||
(argc == 2 && !strcmp(argv[1], "-h")))
|
||||
usage(builtin_maintenance_usage);
|
||||
parse_opt_subcommand_fn *fn = NULL;
|
||||
struct option builtin_maintenance_options[] = {
|
||||
OPT_SUBCOMMAND("run", &fn, maintenance_run),
|
||||
OPT_SUBCOMMAND("start", &fn, maintenance_start),
|
||||
OPT_SUBCOMMAND("stop", &fn, maintenance_stop),
|
||||
OPT_SUBCOMMAND("register", &fn, maintenance_register),
|
||||
OPT_SUBCOMMAND("unregister", &fn, maintenance_unregister),
|
||||
OPT_END(),
|
||||
};
|
||||
|
||||
if (!strcmp(argv[1], "run"))
|
||||
return maintenance_run(argc - 1, argv + 1, prefix);
|
||||
if (!strcmp(argv[1], "start"))
|
||||
return maintenance_start(argc - 1, argv + 1, prefix);
|
||||
if (!strcmp(argv[1], "stop"))
|
||||
return maintenance_stop();
|
||||
if (!strcmp(argv[1], "register"))
|
||||
return maintenance_register();
|
||||
if (!strcmp(argv[1], "unregister"))
|
||||
return maintenance_unregister();
|
||||
|
||||
die(_("invalid subcommand: %s"), argv[1]);
|
||||
argc = parse_options(argc, argv, prefix, builtin_maintenance_options,
|
||||
builtin_maintenance_usage, 0);
|
||||
return fn(argc, argv, prefix);
|
||||
}
|
||||
|
|
|
@ -67,18 +67,14 @@ usage:
|
|||
|
||||
int cmd_hook(int argc, const char **argv, const char *prefix)
|
||||
{
|
||||
parse_opt_subcommand_fn *fn = NULL;
|
||||
struct option builtin_hook_options[] = {
|
||||
OPT_SUBCOMMAND("run", &fn, run),
|
||||
OPT_END(),
|
||||
};
|
||||
|
||||
argc = parse_options(argc, argv, NULL, builtin_hook_options,
|
||||
builtin_hook_usage, PARSE_OPT_STOP_AT_NON_OPTION);
|
||||
if (!argc)
|
||||
goto usage;
|
||||
builtin_hook_usage, 0);
|
||||
|
||||
if (!strcmp(argv[0], "run"))
|
||||
return run(argc, argv, prefix);
|
||||
|
||||
usage:
|
||||
usage_with_options(builtin_hook_usage, builtin_hook_options);
|
||||
return fn(argc, argv, prefix);
|
||||
}
|
||||
|
|
|
@ -260,7 +260,7 @@ static void cmd_log_init_finish(int argc, const char **argv, const char *prefix,
|
|||
mailmap = use_mailmap_config;
|
||||
argc = parse_options(argc, argv, prefix,
|
||||
builtin_log_options, builtin_log_usage,
|
||||
PARSE_OPT_KEEP_ARGV0 | PARSE_OPT_KEEP_UNKNOWN |
|
||||
PARSE_OPT_KEEP_ARGV0 | PARSE_OPT_KEEP_UNKNOWN_OPT |
|
||||
PARSE_OPT_KEEP_DASHDASH);
|
||||
|
||||
if (quiet)
|
||||
|
@ -1989,7 +1989,7 @@ int cmd_format_patch(int argc, const char **argv, const char *prefix)
|
|||
*/
|
||||
argc = parse_options(argc, argv, prefix, builtin_format_patch_options,
|
||||
builtin_format_patch_usage,
|
||||
PARSE_OPT_KEEP_ARGV0 | PARSE_OPT_KEEP_UNKNOWN |
|
||||
PARSE_OPT_KEEP_ARGV0 | PARSE_OPT_KEEP_UNKNOWN_OPT |
|
||||
PARSE_OPT_KEEP_DASHDASH);
|
||||
|
||||
/* Make sure "0000-$sub.patch" gives non-negative length for $sub */
|
||||
|
|
|
@ -104,7 +104,8 @@ static void read_packs_from_stdin(struct string_list *to)
|
|||
strbuf_release(&buf);
|
||||
}
|
||||
|
||||
static int cmd_multi_pack_index_write(int argc, const char **argv)
|
||||
static int cmd_multi_pack_index_write(int argc, const char **argv,
|
||||
const char *prefix)
|
||||
{
|
||||
struct option *options;
|
||||
static struct option builtin_multi_pack_index_write_options[] = {
|
||||
|
@ -132,7 +133,7 @@ static int cmd_multi_pack_index_write(int argc, const char **argv)
|
|||
|
||||
if (isatty(2))
|
||||
opts.flags |= MIDX_PROGRESS;
|
||||
argc = parse_options(argc, argv, NULL,
|
||||
argc = parse_options(argc, argv, prefix,
|
||||
options, builtin_multi_pack_index_write_usage,
|
||||
0);
|
||||
if (argc)
|
||||
|
@ -160,7 +161,8 @@ static int cmd_multi_pack_index_write(int argc, const char **argv)
|
|||
opts.refs_snapshot, opts.flags);
|
||||
}
|
||||
|
||||
static int cmd_multi_pack_index_verify(int argc, const char **argv)
|
||||
static int cmd_multi_pack_index_verify(int argc, const char **argv,
|
||||
const char *prefix)
|
||||
{
|
||||
struct option *options;
|
||||
static struct option builtin_multi_pack_index_verify_options[] = {
|
||||
|
@ -174,7 +176,7 @@ static int cmd_multi_pack_index_verify(int argc, const char **argv)
|
|||
|
||||
if (isatty(2))
|
||||
opts.flags |= MIDX_PROGRESS;
|
||||
argc = parse_options(argc, argv, NULL,
|
||||
argc = parse_options(argc, argv, prefix,
|
||||
options, builtin_multi_pack_index_verify_usage,
|
||||
0);
|
||||
if (argc)
|
||||
|
@ -186,7 +188,8 @@ static int cmd_multi_pack_index_verify(int argc, const char **argv)
|
|||
return verify_midx_file(the_repository, opts.object_dir, opts.flags);
|
||||
}
|
||||
|
||||
static int cmd_multi_pack_index_expire(int argc, const char **argv)
|
||||
static int cmd_multi_pack_index_expire(int argc, const char **argv,
|
||||
const char *prefix)
|
||||
{
|
||||
struct option *options;
|
||||
static struct option builtin_multi_pack_index_expire_options[] = {
|
||||
|
@ -200,7 +203,7 @@ static int cmd_multi_pack_index_expire(int argc, const char **argv)
|
|||
|
||||
if (isatty(2))
|
||||
opts.flags |= MIDX_PROGRESS;
|
||||
argc = parse_options(argc, argv, NULL,
|
||||
argc = parse_options(argc, argv, prefix,
|
||||
options, builtin_multi_pack_index_expire_usage,
|
||||
0);
|
||||
if (argc)
|
||||
|
@ -212,7 +215,8 @@ static int cmd_multi_pack_index_expire(int argc, const char **argv)
|
|||
return expire_midx_packs(the_repository, opts.object_dir, opts.flags);
|
||||
}
|
||||
|
||||
static int cmd_multi_pack_index_repack(int argc, const char **argv)
|
||||
static int cmd_multi_pack_index_repack(int argc, const char **argv,
|
||||
const char *prefix)
|
||||
{
|
||||
struct option *options;
|
||||
static struct option builtin_multi_pack_index_repack_options[] = {
|
||||
|
@ -229,7 +233,7 @@ static int cmd_multi_pack_index_repack(int argc, const char **argv)
|
|||
|
||||
if (isatty(2))
|
||||
opts.flags |= MIDX_PROGRESS;
|
||||
argc = parse_options(argc, argv, NULL,
|
||||
argc = parse_options(argc, argv, prefix,
|
||||
options,
|
||||
builtin_multi_pack_index_repack_usage,
|
||||
0);
|
||||
|
@ -247,7 +251,15 @@ int cmd_multi_pack_index(int argc, const char **argv,
|
|||
const char *prefix)
|
||||
{
|
||||
int res;
|
||||
struct option *builtin_multi_pack_index_options = common_opts;
|
||||
parse_opt_subcommand_fn *fn = NULL;
|
||||
struct option builtin_multi_pack_index_options[] = {
|
||||
OPT_SUBCOMMAND("repack", &fn, cmd_multi_pack_index_repack),
|
||||
OPT_SUBCOMMAND("write", &fn, cmd_multi_pack_index_write),
|
||||
OPT_SUBCOMMAND("verify", &fn, cmd_multi_pack_index_verify),
|
||||
OPT_SUBCOMMAND("expire", &fn, cmd_multi_pack_index_expire),
|
||||
OPT_END(),
|
||||
};
|
||||
struct option *options = parse_options_concat(builtin_multi_pack_index_options, common_opts);
|
||||
|
||||
git_config(git_default_config, NULL);
|
||||
|
||||
|
@ -256,31 +268,12 @@ int cmd_multi_pack_index(int argc, const char **argv,
|
|||
the_repository->objects->odb)
|
||||
opts.object_dir = xstrdup(the_repository->objects->odb->path);
|
||||
|
||||
argc = parse_options(argc, argv, prefix,
|
||||
builtin_multi_pack_index_options,
|
||||
builtin_multi_pack_index_usage,
|
||||
PARSE_OPT_STOP_AT_NON_OPTION);
|
||||
argc = parse_options(argc, argv, prefix, options,
|
||||
builtin_multi_pack_index_usage, 0);
|
||||
FREE_AND_NULL(options);
|
||||
|
||||
if (!argc)
|
||||
goto usage;
|
||||
|
||||
if (!strcmp(argv[0], "repack"))
|
||||
res = cmd_multi_pack_index_repack(argc, argv);
|
||||
else if (!strcmp(argv[0], "write"))
|
||||
res = cmd_multi_pack_index_write(argc, argv);
|
||||
else if (!strcmp(argv[0], "verify"))
|
||||
res = cmd_multi_pack_index_verify(argc, argv);
|
||||
else if (!strcmp(argv[0], "expire"))
|
||||
res = cmd_multi_pack_index_expire(argc, argv);
|
||||
else {
|
||||
error(_("unrecognized subcommand: %s"), argv[0]);
|
||||
goto usage;
|
||||
}
|
||||
res = fn(argc, argv, prefix);
|
||||
|
||||
free(opts.object_dir);
|
||||
return res;
|
||||
|
||||
usage:
|
||||
usage_with_options(builtin_multi_pack_index_usage,
|
||||
builtin_multi_pack_index_options);
|
||||
}
|
||||
|
|
|
@ -994,17 +994,31 @@ static int get_ref(int argc, const char **argv, const char *prefix)
|
|||
|
||||
int cmd_notes(int argc, const char **argv, const char *prefix)
|
||||
{
|
||||
int result;
|
||||
const char *override_notes_ref = NULL;
|
||||
parse_opt_subcommand_fn *fn = list;
|
||||
struct option options[] = {
|
||||
OPT_STRING(0, "ref", &override_notes_ref, N_("notes-ref"),
|
||||
N_("use notes from <notes-ref>")),
|
||||
OPT_SUBCOMMAND("list", &fn, list),
|
||||
OPT_SUBCOMMAND("add", &fn, add),
|
||||
OPT_SUBCOMMAND("copy", &fn, copy),
|
||||
OPT_SUBCOMMAND("append", &fn, append_edit),
|
||||
OPT_SUBCOMMAND("edit", &fn, append_edit),
|
||||
OPT_SUBCOMMAND("show", &fn, show),
|
||||
OPT_SUBCOMMAND("merge", &fn, merge),
|
||||
OPT_SUBCOMMAND("remove", &fn, remove_cmd),
|
||||
OPT_SUBCOMMAND("prune", &fn, prune),
|
||||
OPT_SUBCOMMAND("get-ref", &fn, get_ref),
|
||||
OPT_END()
|
||||
};
|
||||
|
||||
git_config(git_default_config, NULL);
|
||||
argc = parse_options(argc, argv, prefix, options, git_notes_usage,
|
||||
PARSE_OPT_STOP_AT_NON_OPTION);
|
||||
PARSE_OPT_SUBCOMMAND_OPTIONAL);
|
||||
if (fn == list && argc && strcmp(argv[0], "list")) {
|
||||
error(_("unknown subcommand: %s"), argv[0]);
|
||||
usage_with_options(git_notes_usage, options);
|
||||
}
|
||||
|
||||
if (override_notes_ref) {
|
||||
struct strbuf sb = STRBUF_INIT;
|
||||
|
@ -1014,28 +1028,5 @@ int cmd_notes(int argc, const char **argv, const char *prefix)
|
|||
strbuf_release(&sb);
|
||||
}
|
||||
|
||||
if (argc < 1 || !strcmp(argv[0], "list"))
|
||||
result = list(argc, argv, prefix);
|
||||
else if (!strcmp(argv[0], "add"))
|
||||
result = add(argc, argv, prefix);
|
||||
else if (!strcmp(argv[0], "copy"))
|
||||
result = copy(argc, argv, prefix);
|
||||
else if (!strcmp(argv[0], "append") || !strcmp(argv[0], "edit"))
|
||||
result = append_edit(argc, argv, prefix);
|
||||
else if (!strcmp(argv[0], "show"))
|
||||
result = show(argc, argv, prefix);
|
||||
else if (!strcmp(argv[0], "merge"))
|
||||
result = merge(argc, argv, prefix);
|
||||
else if (!strcmp(argv[0], "remove"))
|
||||
result = remove_cmd(argc, argv, prefix);
|
||||
else if (!strcmp(argv[0], "prune"))
|
||||
result = prune(argc, argv, prefix);
|
||||
else if (!strcmp(argv[0], "get-ref"))
|
||||
result = get_ref(argc, argv, prefix);
|
||||
else {
|
||||
result = error(_("unknown subcommand: %s"), argv[0]);
|
||||
usage_with_options(git_notes_usage, options);
|
||||
}
|
||||
|
||||
return result ? 1 : 0;
|
||||
return !!fn(argc, argv, prefix);
|
||||
}
|
||||
|
|
|
@ -227,7 +227,7 @@ static int cmd_reflog_show(int argc, const char **argv, const char *prefix)
|
|||
|
||||
parse_options(argc, argv, prefix, options, reflog_show_usage,
|
||||
PARSE_OPT_KEEP_DASHDASH | PARSE_OPT_KEEP_ARGV0 |
|
||||
PARSE_OPT_KEEP_UNKNOWN);
|
||||
PARSE_OPT_KEEP_UNKNOWN_OPT);
|
||||
|
||||
return cmd_log_reflog(argc, argv, prefix);
|
||||
}
|
||||
|
@ -408,40 +408,21 @@ static int cmd_reflog_exists(int argc, const char **argv, const char *prefix)
|
|||
|
||||
int cmd_reflog(int argc, const char **argv, const char *prefix)
|
||||
{
|
||||
parse_opt_subcommand_fn *fn = NULL;
|
||||
struct option options[] = {
|
||||
OPT_SUBCOMMAND("show", &fn, cmd_reflog_show),
|
||||
OPT_SUBCOMMAND("expire", &fn, cmd_reflog_expire),
|
||||
OPT_SUBCOMMAND("delete", &fn, cmd_reflog_delete),
|
||||
OPT_SUBCOMMAND("exists", &fn, cmd_reflog_exists),
|
||||
OPT_END()
|
||||
};
|
||||
|
||||
argc = parse_options(argc, argv, prefix, options, reflog_usage,
|
||||
PARSE_OPT_SUBCOMMAND_OPTIONAL |
|
||||
PARSE_OPT_KEEP_DASHDASH | PARSE_OPT_KEEP_ARGV0 |
|
||||
PARSE_OPT_KEEP_UNKNOWN |
|
||||
PARSE_OPT_NO_INTERNAL_HELP);
|
||||
|
||||
/*
|
||||
* With "git reflog" we default to showing it. !argc is
|
||||
* impossible with PARSE_OPT_KEEP_ARGV0.
|
||||
*/
|
||||
if (argc == 1)
|
||||
goto log_reflog;
|
||||
|
||||
if (!strcmp(argv[1], "-h"))
|
||||
usage_with_options(reflog_usage, options);
|
||||
else if (*argv[1] == '-')
|
||||
goto log_reflog;
|
||||
|
||||
if (!strcmp(argv[1], "show"))
|
||||
return cmd_reflog_show(argc - 1, argv + 1, prefix);
|
||||
else if (!strcmp(argv[1], "expire"))
|
||||
return cmd_reflog_expire(argc - 1, argv + 1, prefix);
|
||||
else if (!strcmp(argv[1], "delete"))
|
||||
return cmd_reflog_delete(argc - 1, argv + 1, prefix);
|
||||
else if (!strcmp(argv[1], "exists"))
|
||||
return cmd_reflog_exists(argc - 1, argv + 1, prefix);
|
||||
|
||||
/*
|
||||
* Fall-through for e.g. "git reflog -1", "git reflog master",
|
||||
* as well as the plain "git reflog" above goto above.
|
||||
*/
|
||||
log_reflog:
|
||||
return cmd_log_reflog(argc, argv, prefix);
|
||||
PARSE_OPT_KEEP_UNKNOWN_OPT);
|
||||
if (fn)
|
||||
return fn(argc - 1, argv + 1, prefix);
|
||||
else
|
||||
return cmd_log_reflog(argc, argv, prefix);
|
||||
}
|
||||
|
|
106
builtin/remote.c
106
builtin/remote.c
|
@ -150,7 +150,7 @@ static int parse_mirror_opt(const struct option *opt, const char *arg, int not)
|
|||
return 0;
|
||||
}
|
||||
|
||||
static int add(int argc, const char **argv)
|
||||
static int add(int argc, const char **argv, const char *prefix)
|
||||
{
|
||||
int fetch = 0, fetch_tags = TAGS_DEFAULT;
|
||||
unsigned mirror = MIRROR_NONE;
|
||||
|
@ -177,8 +177,8 @@ static int add(int argc, const char **argv)
|
|||
OPT_END()
|
||||
};
|
||||
|
||||
argc = parse_options(argc, argv, NULL, options, builtin_remote_add_usage,
|
||||
0);
|
||||
argc = parse_options(argc, argv, prefix, options,
|
||||
builtin_remote_add_usage, 0);
|
||||
|
||||
if (argc != 2)
|
||||
usage_with_options(builtin_remote_add_usage, options);
|
||||
|
@ -680,7 +680,7 @@ static void handle_push_default(const char* old_name, const char* new_name)
|
|||
}
|
||||
|
||||
|
||||
static int mv(int argc, const char **argv)
|
||||
static int mv(int argc, const char **argv, const char *prefix)
|
||||
{
|
||||
int show_progress = isatty(2);
|
||||
struct option options[] = {
|
||||
|
@ -695,7 +695,7 @@ static int mv(int argc, const char **argv)
|
|||
int i, refs_renamed_nr = 0, refspec_updated = 0;
|
||||
struct progress *progress = NULL;
|
||||
|
||||
argc = parse_options(argc, argv, NULL, options,
|
||||
argc = parse_options(argc, argv, prefix, options,
|
||||
builtin_remote_rename_usage, 0);
|
||||
|
||||
if (argc != 2)
|
||||
|
@ -844,7 +844,7 @@ static int mv(int argc, const char **argv)
|
|||
return 0;
|
||||
}
|
||||
|
||||
static int rm(int argc, const char **argv)
|
||||
static int rm(int argc, const char **argv, const char *prefix)
|
||||
{
|
||||
struct option options[] = {
|
||||
OPT_END()
|
||||
|
@ -862,12 +862,14 @@ static int rm(int argc, const char **argv)
|
|||
cb_data.skipped = &skipped;
|
||||
cb_data.keep = &known_remotes;
|
||||
|
||||
if (argc != 2)
|
||||
argc = parse_options(argc, argv, prefix, options,
|
||||
builtin_remote_rm_usage, 0);
|
||||
if (argc != 1)
|
||||
usage_with_options(builtin_remote_rm_usage, options);
|
||||
|
||||
remote = remote_get(argv[1]);
|
||||
remote = remote_get(argv[0]);
|
||||
if (!remote_is_configured(remote, 1)) {
|
||||
error(_("No such remote: '%s'"), argv[1]);
|
||||
error(_("No such remote: '%s'"), argv[0]);
|
||||
exit(2);
|
||||
}
|
||||
|
||||
|
@ -1254,7 +1256,7 @@ static int show_all(void)
|
|||
return result;
|
||||
}
|
||||
|
||||
static int show(int argc, const char **argv)
|
||||
static int show(int argc, const char **argv, const char *prefix)
|
||||
{
|
||||
int no_query = 0, result = 0, query_flag = 0;
|
||||
struct option options[] = {
|
||||
|
@ -1263,7 +1265,8 @@ static int show(int argc, const char **argv)
|
|||
};
|
||||
struct show_info info = SHOW_INFO_INIT;
|
||||
|
||||
argc = parse_options(argc, argv, NULL, options, builtin_remote_show_usage,
|
||||
argc = parse_options(argc, argv, prefix, options,
|
||||
builtin_remote_show_usage,
|
||||
0);
|
||||
|
||||
if (argc < 1)
|
||||
|
@ -1357,7 +1360,7 @@ static int show(int argc, const char **argv)
|
|||
return result;
|
||||
}
|
||||
|
||||
static int set_head(int argc, const char **argv)
|
||||
static int set_head(int argc, const char **argv, const char *prefix)
|
||||
{
|
||||
int i, opt_a = 0, opt_d = 0, result = 0;
|
||||
struct strbuf buf = STRBUF_INIT, buf2 = STRBUF_INIT;
|
||||
|
@ -1370,8 +1373,8 @@ static int set_head(int argc, const char **argv)
|
|||
N_("delete refs/remotes/<name>/HEAD")),
|
||||
OPT_END()
|
||||
};
|
||||
argc = parse_options(argc, argv, NULL, options, builtin_remote_sethead_usage,
|
||||
0);
|
||||
argc = parse_options(argc, argv, prefix, options,
|
||||
builtin_remote_sethead_usage, 0);
|
||||
if (argc)
|
||||
strbuf_addf(&buf, "refs/remotes/%s/HEAD", argv[0]);
|
||||
|
||||
|
@ -1462,7 +1465,7 @@ static int prune_remote(const char *remote, int dry_run)
|
|||
return result;
|
||||
}
|
||||
|
||||
static int prune(int argc, const char **argv)
|
||||
static int prune(int argc, const char **argv, const char *prefix)
|
||||
{
|
||||
int dry_run = 0, result = 0;
|
||||
struct option options[] = {
|
||||
|
@ -1470,8 +1473,8 @@ static int prune(int argc, const char **argv)
|
|||
OPT_END()
|
||||
};
|
||||
|
||||
argc = parse_options(argc, argv, NULL, options, builtin_remote_prune_usage,
|
||||
0);
|
||||
argc = parse_options(argc, argv, prefix, options,
|
||||
builtin_remote_prune_usage, 0);
|
||||
|
||||
if (argc < 1)
|
||||
usage_with_options(builtin_remote_prune_usage, options);
|
||||
|
@ -1491,7 +1494,7 @@ static int get_remote_default(const char *key, const char *value, void *priv)
|
|||
return 0;
|
||||
}
|
||||
|
||||
static int update(int argc, const char **argv)
|
||||
static int update(int argc, const char **argv, const char *prefix)
|
||||
{
|
||||
int i, prune = -1;
|
||||
struct option options[] = {
|
||||
|
@ -1503,7 +1506,8 @@ static int update(int argc, const char **argv)
|
|||
int default_defined = 0;
|
||||
int retval;
|
||||
|
||||
argc = parse_options(argc, argv, NULL, options, builtin_remote_update_usage,
|
||||
argc = parse_options(argc, argv, prefix, options,
|
||||
builtin_remote_update_usage,
|
||||
PARSE_OPT_KEEP_ARGV0);
|
||||
|
||||
strvec_push(&fetch_argv, "fetch");
|
||||
|
@ -1574,7 +1578,7 @@ static int set_remote_branches(const char *remotename, const char **branches,
|
|||
return 0;
|
||||
}
|
||||
|
||||
static int set_branches(int argc, const char **argv)
|
||||
static int set_branches(int argc, const char **argv, const char *prefix)
|
||||
{
|
||||
int add_mode = 0;
|
||||
struct option options[] = {
|
||||
|
@ -1582,7 +1586,7 @@ static int set_branches(int argc, const char **argv)
|
|||
OPT_END()
|
||||
};
|
||||
|
||||
argc = parse_options(argc, argv, NULL, options,
|
||||
argc = parse_options(argc, argv, prefix, options,
|
||||
builtin_remote_setbranches_usage, 0);
|
||||
if (argc == 0) {
|
||||
error(_("no remote specified"));
|
||||
|
@ -1593,7 +1597,7 @@ static int set_branches(int argc, const char **argv)
|
|||
return set_remote_branches(argv[0], argv + 1, add_mode);
|
||||
}
|
||||
|
||||
static int get_url(int argc, const char **argv)
|
||||
static int get_url(int argc, const char **argv, const char *prefix)
|
||||
{
|
||||
int i, push_mode = 0, all_mode = 0;
|
||||
const char *remotename = NULL;
|
||||
|
@ -1607,7 +1611,8 @@ static int get_url(int argc, const char **argv)
|
|||
N_("return all URLs")),
|
||||
OPT_END()
|
||||
};
|
||||
argc = parse_options(argc, argv, NULL, options, builtin_remote_geturl_usage, 0);
|
||||
argc = parse_options(argc, argv, prefix, options,
|
||||
builtin_remote_geturl_usage, 0);
|
||||
|
||||
if (argc != 1)
|
||||
usage_with_options(builtin_remote_geturl_usage, options);
|
||||
|
@ -1646,7 +1651,7 @@ static int get_url(int argc, const char **argv)
|
|||
return 0;
|
||||
}
|
||||
|
||||
static int set_url(int argc, const char **argv)
|
||||
static int set_url(int argc, const char **argv, const char *prefix)
|
||||
{
|
||||
int i, push_mode = 0, add_mode = 0, delete_mode = 0;
|
||||
int matches = 0, negative_matches = 0;
|
||||
|
@ -1667,7 +1672,8 @@ static int set_url(int argc, const char **argv)
|
|||
N_("delete URLs")),
|
||||
OPT_END()
|
||||
};
|
||||
argc = parse_options(argc, argv, NULL, options, builtin_remote_seturl_usage,
|
||||
argc = parse_options(argc, argv, prefix, options,
|
||||
builtin_remote_seturl_usage,
|
||||
PARSE_OPT_KEEP_ARGV0);
|
||||
|
||||
if (add_mode && delete_mode)
|
||||
|
@ -1738,41 +1744,33 @@ out:
|
|||
|
||||
int cmd_remote(int argc, const char **argv, const char *prefix)
|
||||
{
|
||||
parse_opt_subcommand_fn *fn = NULL;
|
||||
struct option options[] = {
|
||||
OPT__VERBOSE(&verbose, N_("be verbose; must be placed before a subcommand")),
|
||||
OPT_SUBCOMMAND("add", &fn, add),
|
||||
OPT_SUBCOMMAND("rename", &fn, mv),
|
||||
OPT_SUBCOMMAND_F("rm", &fn, rm, PARSE_OPT_NOCOMPLETE),
|
||||
OPT_SUBCOMMAND("remove", &fn, rm),
|
||||
OPT_SUBCOMMAND("set-head", &fn, set_head),
|
||||
OPT_SUBCOMMAND("set-branches", &fn, set_branches),
|
||||
OPT_SUBCOMMAND("get-url", &fn, get_url),
|
||||
OPT_SUBCOMMAND("set-url", &fn, set_url),
|
||||
OPT_SUBCOMMAND("show", &fn, show),
|
||||
OPT_SUBCOMMAND("prune", &fn, prune),
|
||||
OPT_SUBCOMMAND("update", &fn, update),
|
||||
OPT_END()
|
||||
};
|
||||
int result;
|
||||
|
||||
argc = parse_options(argc, argv, prefix, options, builtin_remote_usage,
|
||||
PARSE_OPT_STOP_AT_NON_OPTION);
|
||||
PARSE_OPT_SUBCOMMAND_OPTIONAL);
|
||||
|
||||
if (argc < 1)
|
||||
result = show_all();
|
||||
else if (!strcmp(argv[0], "add"))
|
||||
result = add(argc, argv);
|
||||
else if (!strcmp(argv[0], "rename"))
|
||||
result = mv(argc, argv);
|
||||
else if (!strcmp(argv[0], "rm") || !strcmp(argv[0], "remove"))
|
||||
result = rm(argc, argv);
|
||||
else if (!strcmp(argv[0], "set-head"))
|
||||
result = set_head(argc, argv);
|
||||
else if (!strcmp(argv[0], "set-branches"))
|
||||
result = set_branches(argc, argv);
|
||||
else if (!strcmp(argv[0], "get-url"))
|
||||
result = get_url(argc, argv);
|
||||
else if (!strcmp(argv[0], "set-url"))
|
||||
result = set_url(argc, argv);
|
||||
else if (!strcmp(argv[0], "show"))
|
||||
result = show(argc, argv);
|
||||
else if (!strcmp(argv[0], "prune"))
|
||||
result = prune(argc, argv);
|
||||
else if (!strcmp(argv[0], "update"))
|
||||
result = update(argc, argv);
|
||||
else {
|
||||
error(_("Unknown subcommand: %s"), argv[0]);
|
||||
usage_with_options(builtin_remote_usage, options);
|
||||
if (fn) {
|
||||
return !!fn(argc, argv, prefix);
|
||||
} else {
|
||||
if (argc) {
|
||||
error(_("unknown subcommand: %s"), argv[0]);
|
||||
usage_with_options(builtin_remote_usage, options);
|
||||
}
|
||||
return !!show_all();
|
||||
}
|
||||
|
||||
return result ? 1 : 0;
|
||||
}
|
||||
|
|
|
@ -141,7 +141,7 @@ static int run_sequencer(int argc, const char **argv, struct replay_opts *opts)
|
|||
|
||||
argc = parse_options(argc, argv, NULL, options, usage_str,
|
||||
PARSE_OPT_KEEP_ARGV0 |
|
||||
PARSE_OPT_KEEP_UNKNOWN);
|
||||
PARSE_OPT_KEEP_UNKNOWN_OPT);
|
||||
|
||||
prepare_repo_settings(the_repository);
|
||||
the_repository->settings.command_requires_full_index = 0;
|
||||
|
|
|
@ -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);
|
||||
|
|
|
@ -48,7 +48,7 @@ static char const * const builtin_sparse_checkout_list_usage[] = {
|
|||
NULL
|
||||
};
|
||||
|
||||
static int sparse_checkout_list(int argc, const char **argv)
|
||||
static int sparse_checkout_list(int argc, const char **argv, const char *prefix)
|
||||
{
|
||||
static struct option builtin_sparse_checkout_list_options[] = {
|
||||
OPT_END(),
|
||||
|
@ -60,7 +60,7 @@ static int sparse_checkout_list(int argc, const char **argv)
|
|||
if (!core_apply_sparse_checkout)
|
||||
die(_("this worktree is not sparse"));
|
||||
|
||||
argc = parse_options(argc, argv, NULL,
|
||||
argc = parse_options(argc, argv, prefix,
|
||||
builtin_sparse_checkout_list_options,
|
||||
builtin_sparse_checkout_list_usage, 0);
|
||||
|
||||
|
@ -431,7 +431,7 @@ static struct sparse_checkout_init_opts {
|
|||
int sparse_index;
|
||||
} init_opts;
|
||||
|
||||
static int sparse_checkout_init(int argc, const char **argv)
|
||||
static int sparse_checkout_init(int argc, const char **argv, const char *prefix)
|
||||
{
|
||||
struct pattern_list pl;
|
||||
char *sparse_filename;
|
||||
|
@ -452,7 +452,7 @@ static int sparse_checkout_init(int argc, const char **argv)
|
|||
init_opts.cone_mode = -1;
|
||||
init_opts.sparse_index = -1;
|
||||
|
||||
argc = parse_options(argc, argv, NULL,
|
||||
argc = parse_options(argc, argv, prefix,
|
||||
builtin_sparse_checkout_init_options,
|
||||
builtin_sparse_checkout_init_usage, 0);
|
||||
|
||||
|
@ -767,7 +767,7 @@ static int sparse_checkout_add(int argc, const char **argv, const char *prefix)
|
|||
argc = parse_options(argc, argv, prefix,
|
||||
builtin_sparse_checkout_add_options,
|
||||
builtin_sparse_checkout_add_usage,
|
||||
PARSE_OPT_KEEP_UNKNOWN);
|
||||
PARSE_OPT_KEEP_UNKNOWN_OPT);
|
||||
|
||||
sanitize_paths(argc, argv, prefix, add_opts.skip_checks);
|
||||
|
||||
|
@ -813,7 +813,7 @@ static int sparse_checkout_set(int argc, const char **argv, const char *prefix)
|
|||
argc = parse_options(argc, argv, prefix,
|
||||
builtin_sparse_checkout_set_options,
|
||||
builtin_sparse_checkout_set_usage,
|
||||
PARSE_OPT_KEEP_UNKNOWN);
|
||||
PARSE_OPT_KEEP_UNKNOWN_OPT);
|
||||
|
||||
if (update_modes(&set_opts.cone_mode, &set_opts.sparse_index))
|
||||
return 1;
|
||||
|
@ -843,7 +843,8 @@ static struct sparse_checkout_reapply_opts {
|
|||
int sparse_index;
|
||||
} reapply_opts;
|
||||
|
||||
static int sparse_checkout_reapply(int argc, const char **argv)
|
||||
static int sparse_checkout_reapply(int argc, const char **argv,
|
||||
const char *prefix)
|
||||
{
|
||||
static struct option builtin_sparse_checkout_reapply_options[] = {
|
||||
OPT_BOOL(0, "cone", &reapply_opts.cone_mode,
|
||||
|
@ -859,7 +860,7 @@ static int sparse_checkout_reapply(int argc, const char **argv)
|
|||
reapply_opts.cone_mode = -1;
|
||||
reapply_opts.sparse_index = -1;
|
||||
|
||||
argc = parse_options(argc, argv, NULL,
|
||||
argc = parse_options(argc, argv, prefix,
|
||||
builtin_sparse_checkout_reapply_options,
|
||||
builtin_sparse_checkout_reapply_usage, 0);
|
||||
|
||||
|
@ -876,7 +877,8 @@ static char const * const builtin_sparse_checkout_disable_usage[] = {
|
|||
NULL
|
||||
};
|
||||
|
||||
static int sparse_checkout_disable(int argc, const char **argv)
|
||||
static int sparse_checkout_disable(int argc, const char **argv,
|
||||
const char *prefix)
|
||||
{
|
||||
static struct option builtin_sparse_checkout_disable_options[] = {
|
||||
OPT_END(),
|
||||
|
@ -895,7 +897,7 @@ static int sparse_checkout_disable(int argc, const char **argv)
|
|||
* forcibly return to a dense checkout regardless of initial state.
|
||||
*/
|
||||
|
||||
argc = parse_options(argc, argv, NULL,
|
||||
argc = parse_options(argc, argv, prefix,
|
||||
builtin_sparse_checkout_disable_options,
|
||||
builtin_sparse_checkout_disable_usage, 0);
|
||||
|
||||
|
@ -922,39 +924,25 @@ static int sparse_checkout_disable(int argc, const char **argv)
|
|||
|
||||
int cmd_sparse_checkout(int argc, const char **argv, const char *prefix)
|
||||
{
|
||||
static struct option builtin_sparse_checkout_options[] = {
|
||||
parse_opt_subcommand_fn *fn = NULL;
|
||||
struct option builtin_sparse_checkout_options[] = {
|
||||
OPT_SUBCOMMAND("list", &fn, sparse_checkout_list),
|
||||
OPT_SUBCOMMAND("init", &fn, sparse_checkout_init),
|
||||
OPT_SUBCOMMAND("set", &fn, sparse_checkout_set),
|
||||
OPT_SUBCOMMAND("add", &fn, sparse_checkout_add),
|
||||
OPT_SUBCOMMAND("reapply", &fn, sparse_checkout_reapply),
|
||||
OPT_SUBCOMMAND("disable", &fn, sparse_checkout_disable),
|
||||
OPT_END(),
|
||||
};
|
||||
|
||||
if (argc == 2 && !strcmp(argv[1], "-h"))
|
||||
usage_with_options(builtin_sparse_checkout_usage,
|
||||
builtin_sparse_checkout_options);
|
||||
|
||||
argc = parse_options(argc, argv, prefix,
|
||||
builtin_sparse_checkout_options,
|
||||
builtin_sparse_checkout_usage,
|
||||
PARSE_OPT_STOP_AT_NON_OPTION);
|
||||
builtin_sparse_checkout_usage, 0);
|
||||
|
||||
git_config(git_default_config, NULL);
|
||||
|
||||
prepare_repo_settings(the_repository);
|
||||
the_repository->settings.command_requires_full_index = 0;
|
||||
|
||||
if (argc > 0) {
|
||||
if (!strcmp(argv[0], "list"))
|
||||
return sparse_checkout_list(argc, argv);
|
||||
if (!strcmp(argv[0], "init"))
|
||||
return sparse_checkout_init(argc, argv);
|
||||
if (!strcmp(argv[0], "set"))
|
||||
return sparse_checkout_set(argc, argv, prefix);
|
||||
if (!strcmp(argv[0], "add"))
|
||||
return sparse_checkout_add(argc, argv, prefix);
|
||||
if (!strcmp(argv[0], "reapply"))
|
||||
return sparse_checkout_reapply(argc, argv);
|
||||
if (!strcmp(argv[0], "disable"))
|
||||
return sparse_checkout_disable(argc, argv);
|
||||
}
|
||||
|
||||
usage_with_options(builtin_sparse_checkout_usage,
|
||||
builtin_sparse_checkout_options);
|
||||
return fn(argc, argv, prefix);
|
||||
}
|
||||
|
|
|
@ -782,7 +782,7 @@ static int list_stash(int argc, const char **argv, const char *prefix)
|
|||
|
||||
argc = parse_options(argc, argv, prefix, options,
|
||||
git_stash_list_usage,
|
||||
PARSE_OPT_KEEP_UNKNOWN);
|
||||
PARSE_OPT_KEEP_UNKNOWN_OPT);
|
||||
|
||||
if (!ref_exists(ref_stash))
|
||||
return 0;
|
||||
|
@ -873,7 +873,7 @@ static int show_stash(int argc, const char **argv, const char *prefix)
|
|||
init_revisions(&rev, prefix);
|
||||
|
||||
argc = parse_options(argc, argv, prefix, options, git_stash_show_usage,
|
||||
PARSE_OPT_KEEP_ARGV0 | PARSE_OPT_KEEP_UNKNOWN |
|
||||
PARSE_OPT_KEEP_ARGV0 | PARSE_OPT_KEEP_UNKNOWN_OPT |
|
||||
PARSE_OPT_KEEP_DASHDASH);
|
||||
|
||||
strvec_push(&revision_args, argv[0]);
|
||||
|
@ -979,7 +979,7 @@ static int store_stash(int argc, const char **argv, const char *prefix)
|
|||
|
||||
argc = parse_options(argc, argv, prefix, options,
|
||||
git_stash_store_usage,
|
||||
PARSE_OPT_KEEP_UNKNOWN);
|
||||
PARSE_OPT_KEEP_UNKNOWN_OPT);
|
||||
|
||||
if (argc != 1) {
|
||||
if (!quiet)
|
||||
|
@ -1739,6 +1739,11 @@ static int push_stash(int argc, const char **argv, const char *prefix,
|
|||
include_untracked, only_staged);
|
||||
}
|
||||
|
||||
static int push_stash_unassumed(int argc, const char **argv, const char *prefix)
|
||||
{
|
||||
return push_stash(argc, argv, prefix, 0);
|
||||
}
|
||||
|
||||
static int save_stash(int argc, const char **argv, const char *prefix)
|
||||
{
|
||||
int keep_index = -1;
|
||||
|
@ -1787,15 +1792,28 @@ int cmd_stash(int argc, const char **argv, const char *prefix)
|
|||
pid_t pid = getpid();
|
||||
const char *index_file;
|
||||
struct strvec args = STRVEC_INIT;
|
||||
|
||||
parse_opt_subcommand_fn *fn = NULL;
|
||||
struct option options[] = {
|
||||
OPT_SUBCOMMAND("apply", &fn, apply_stash),
|
||||
OPT_SUBCOMMAND("clear", &fn, clear_stash),
|
||||
OPT_SUBCOMMAND("drop", &fn, drop_stash),
|
||||
OPT_SUBCOMMAND("pop", &fn, pop_stash),
|
||||
OPT_SUBCOMMAND("branch", &fn, branch_stash),
|
||||
OPT_SUBCOMMAND("list", &fn, list_stash),
|
||||
OPT_SUBCOMMAND("show", &fn, show_stash),
|
||||
OPT_SUBCOMMAND("store", &fn, store_stash),
|
||||
OPT_SUBCOMMAND("create", &fn, create_stash),
|
||||
OPT_SUBCOMMAND("push", &fn, push_stash_unassumed),
|
||||
OPT_SUBCOMMAND_F("save", &fn, save_stash, PARSE_OPT_NOCOMPLETE),
|
||||
OPT_END()
|
||||
};
|
||||
|
||||
git_config(git_stash_config, NULL);
|
||||
|
||||
argc = parse_options(argc, argv, prefix, options, git_stash_usage,
|
||||
PARSE_OPT_KEEP_UNKNOWN | PARSE_OPT_KEEP_DASHDASH);
|
||||
PARSE_OPT_SUBCOMMAND_OPTIONAL |
|
||||
PARSE_OPT_KEEP_UNKNOWN_OPT |
|
||||
PARSE_OPT_KEEP_DASHDASH);
|
||||
|
||||
prepare_repo_settings(the_repository);
|
||||
the_repository->settings.command_requires_full_index = 0;
|
||||
|
@ -1804,33 +1822,10 @@ int cmd_stash(int argc, const char **argv, const char *prefix)
|
|||
strbuf_addf(&stash_index_path, "%s.stash.%" PRIuMAX, index_file,
|
||||
(uintmax_t)pid);
|
||||
|
||||
if (!argc)
|
||||
return !!push_stash(0, NULL, prefix, 0);
|
||||
else if (!strcmp(argv[0], "apply"))
|
||||
return !!apply_stash(argc, argv, prefix);
|
||||
else if (!strcmp(argv[0], "clear"))
|
||||
return !!clear_stash(argc, argv, prefix);
|
||||
else if (!strcmp(argv[0], "drop"))
|
||||
return !!drop_stash(argc, argv, prefix);
|
||||
else if (!strcmp(argv[0], "pop"))
|
||||
return !!pop_stash(argc, argv, prefix);
|
||||
else if (!strcmp(argv[0], "branch"))
|
||||
return !!branch_stash(argc, argv, prefix);
|
||||
else if (!strcmp(argv[0], "list"))
|
||||
return !!list_stash(argc, argv, prefix);
|
||||
else if (!strcmp(argv[0], "show"))
|
||||
return !!show_stash(argc, argv, prefix);
|
||||
else if (!strcmp(argv[0], "store"))
|
||||
return !!store_stash(argc, argv, prefix);
|
||||
else if (!strcmp(argv[0], "create"))
|
||||
return !!create_stash(argc, argv, prefix);
|
||||
else if (!strcmp(argv[0], "push"))
|
||||
return !!push_stash(argc, argv, prefix, 0);
|
||||
else if (!strcmp(argv[0], "save"))
|
||||
return !!save_stash(argc, argv, prefix);
|
||||
else if (*argv[0] != '-')
|
||||
usage_msg_optf(_("unknown subcommand: %s"),
|
||||
git_stash_usage, options, argv[0]);
|
||||
if (fn)
|
||||
return !!fn(argc, argv, prefix);
|
||||
else if (!argc)
|
||||
return !!push_stash_unassumed(0, NULL, prefix);
|
||||
|
||||
/* Assume 'stash push' */
|
||||
strvec_push(&args, "push");
|
||||
|
|
|
@ -1112,31 +1112,24 @@ static int repair(int ac, const char **av, const char *prefix)
|
|||
|
||||
int cmd_worktree(int ac, const char **av, const char *prefix)
|
||||
{
|
||||
parse_opt_subcommand_fn *fn = NULL;
|
||||
struct option options[] = {
|
||||
OPT_SUBCOMMAND("add", &fn, add),
|
||||
OPT_SUBCOMMAND("prune", &fn, prune),
|
||||
OPT_SUBCOMMAND("list", &fn, list),
|
||||
OPT_SUBCOMMAND("lock", &fn, lock_worktree),
|
||||
OPT_SUBCOMMAND("unlock", &fn, unlock_worktree),
|
||||
OPT_SUBCOMMAND("move", &fn, move_worktree),
|
||||
OPT_SUBCOMMAND("remove", &fn, remove_worktree),
|
||||
OPT_SUBCOMMAND("repair", &fn, repair),
|
||||
OPT_END()
|
||||
};
|
||||
|
||||
git_config(git_worktree_config, NULL);
|
||||
|
||||
if (ac < 2)
|
||||
usage_with_options(worktree_usage, options);
|
||||
if (!prefix)
|
||||
prefix = "";
|
||||
if (!strcmp(av[1], "add"))
|
||||
return add(ac - 1, av + 1, prefix);
|
||||
if (!strcmp(av[1], "prune"))
|
||||
return prune(ac - 1, av + 1, prefix);
|
||||
if (!strcmp(av[1], "list"))
|
||||
return list(ac - 1, av + 1, prefix);
|
||||
if (!strcmp(av[1], "lock"))
|
||||
return lock_worktree(ac - 1, av + 1, prefix);
|
||||
if (!strcmp(av[1], "unlock"))
|
||||
return unlock_worktree(ac - 1, av + 1, prefix);
|
||||
if (!strcmp(av[1], "move"))
|
||||
return move_worktree(ac - 1, av + 1, prefix);
|
||||
if (!strcmp(av[1], "remove"))
|
||||
return remove_worktree(ac - 1, av + 1, prefix);
|
||||
if (!strcmp(av[1], "repair"))
|
||||
return repair(ac - 1, av + 1, prefix);
|
||||
usage_with_options(worktree_usage, options);
|
||||
|
||||
ac = parse_options(ac, av, prefix, options, worktree_usage, 0);
|
||||
return fn(ac, av, prefix);
|
||||
}
|
||||
|
|
2
diff.c
2
diff.c
|
@ -5661,7 +5661,7 @@ int diff_opt_parse(struct diff_options *options,
|
|||
|
||||
ac = parse_options(ac, av, prefix, options->parseopts, NULL,
|
||||
PARSE_OPT_KEEP_DASHDASH |
|
||||
PARSE_OPT_KEEP_UNKNOWN |
|
||||
PARSE_OPT_KEEP_UNKNOWN_OPT |
|
||||
PARSE_OPT_NO_INTERNAL_HELP |
|
||||
PARSE_OPT_ONE_SHOT |
|
||||
PARSE_OPT_STOP_AT_NON_OPTION);
|
||||
|
|
14
git.c
14
git.c
|
@ -489,14 +489,14 @@ static int run_builtin(struct cmd_struct *p, int argc, const char **argv)
|
|||
static struct cmd_struct commands[] = {
|
||||
{ "add", cmd_add, RUN_SETUP | NEED_WORK_TREE },
|
||||
{ "am", cmd_am, RUN_SETUP | NEED_WORK_TREE },
|
||||
{ "annotate", cmd_annotate, RUN_SETUP | NO_PARSEOPT },
|
||||
{ "annotate", cmd_annotate, RUN_SETUP },
|
||||
{ "apply", cmd_apply, RUN_SETUP_GENTLY },
|
||||
{ "archive", cmd_archive, RUN_SETUP_GENTLY },
|
||||
{ "bisect--helper", cmd_bisect__helper, RUN_SETUP },
|
||||
{ "blame", cmd_blame, RUN_SETUP },
|
||||
{ "branch", cmd_branch, RUN_SETUP | DELAY_PAGER_CONFIG },
|
||||
{ "bugreport", cmd_bugreport, RUN_SETUP_GENTLY },
|
||||
{ "bundle", cmd_bundle, RUN_SETUP_GENTLY | NO_PARSEOPT },
|
||||
{ "bundle", cmd_bundle, RUN_SETUP_GENTLY },
|
||||
{ "cat-file", cmd_cat_file, RUN_SETUP },
|
||||
{ "check-attr", cmd_check_attr, RUN_SETUP },
|
||||
{ "check-ignore", cmd_check_ignore, RUN_SETUP | NEED_WORK_TREE },
|
||||
|
@ -514,7 +514,7 @@ static struct cmd_struct commands[] = {
|
|||
{ "column", cmd_column, RUN_SETUP_GENTLY },
|
||||
{ "commit", cmd_commit, RUN_SETUP | NEED_WORK_TREE },
|
||||
{ "commit-graph", cmd_commit_graph, RUN_SETUP },
|
||||
{ "commit-tree", cmd_commit_tree, RUN_SETUP | NO_PARSEOPT },
|
||||
{ "commit-tree", cmd_commit_tree, RUN_SETUP },
|
||||
{ "config", cmd_config, RUN_SETUP_GENTLY | DELAY_PAGER_CONFIG },
|
||||
{ "count-objects", cmd_count_objects, RUN_SETUP },
|
||||
{ "credential", cmd_credential, RUN_SETUP_GENTLY | NO_PARSEOPT },
|
||||
|
@ -554,9 +554,9 @@ static struct cmd_struct commands[] = {
|
|||
{ "ls-files", cmd_ls_files, RUN_SETUP },
|
||||
{ "ls-remote", cmd_ls_remote, RUN_SETUP_GENTLY },
|
||||
{ "ls-tree", cmd_ls_tree, RUN_SETUP },
|
||||
{ "mailinfo", cmd_mailinfo, RUN_SETUP_GENTLY | NO_PARSEOPT },
|
||||
{ "mailinfo", cmd_mailinfo, RUN_SETUP_GENTLY },
|
||||
{ "mailsplit", cmd_mailsplit, NO_PARSEOPT },
|
||||
{ "maintenance", cmd_maintenance, RUN_SETUP | NO_PARSEOPT },
|
||||
{ "maintenance", cmd_maintenance, RUN_SETUP },
|
||||
{ "merge", cmd_merge, RUN_SETUP | NEED_WORK_TREE },
|
||||
{ "merge-base", cmd_merge_base, RUN_SETUP },
|
||||
{ "merge-file", cmd_merge_file, RUN_SETUP_GENTLY },
|
||||
|
@ -567,7 +567,7 @@ static struct cmd_struct commands[] = {
|
|||
{ "merge-recursive-theirs", cmd_merge_recursive, RUN_SETUP | NEED_WORK_TREE | NO_PARSEOPT },
|
||||
{ "merge-subtree", cmd_merge_recursive, RUN_SETUP | NEED_WORK_TREE | NO_PARSEOPT },
|
||||
{ "merge-tree", cmd_merge_tree, RUN_SETUP },
|
||||
{ "mktag", cmd_mktag, RUN_SETUP | NO_PARSEOPT },
|
||||
{ "mktag", cmd_mktag, RUN_SETUP },
|
||||
{ "mktree", cmd_mktree, RUN_SETUP },
|
||||
{ "multi-pack-index", cmd_multi_pack_index, RUN_SETUP },
|
||||
{ "mv", cmd_mv, RUN_SETUP | NEED_WORK_TREE },
|
||||
|
@ -628,7 +628,7 @@ static struct cmd_struct commands[] = {
|
|||
{ "verify-tag", cmd_verify_tag, RUN_SETUP },
|
||||
{ "version", cmd_version },
|
||||
{ "whatchanged", cmd_whatchanged, RUN_SETUP },
|
||||
{ "worktree", cmd_worktree, RUN_SETUP | NO_PARSEOPT },
|
||||
{ "worktree", cmd_worktree, RUN_SETUP },
|
||||
{ "write-tree", cmd_write_tree, RUN_SETUP },
|
||||
};
|
||||
|
||||
|
|
118
parse-options.c
118
parse-options.c
|
@ -324,6 +324,8 @@ static enum parse_opt_result parse_long_opt(
|
|||
const char *rest, *long_name = options->long_name;
|
||||
enum opt_parsed flags = OPT_LONG, opt_flags = OPT_LONG;
|
||||
|
||||
if (options->type == OPTION_SUBCOMMAND)
|
||||
continue;
|
||||
if (!long_name)
|
||||
continue;
|
||||
|
||||
|
@ -332,7 +334,7 @@ again:
|
|||
rest = NULL;
|
||||
if (!rest) {
|
||||
/* abbreviated? */
|
||||
if (!(p->flags & PARSE_OPT_KEEP_UNKNOWN) &&
|
||||
if (!(p->flags & PARSE_OPT_KEEP_UNKNOWN_OPT) &&
|
||||
!strncmp(long_name, arg, arg_end - arg)) {
|
||||
is_abbreviated:
|
||||
if (abbrev_option &&
|
||||
|
@ -419,6 +421,19 @@ static enum parse_opt_result parse_nodash_opt(struct parse_opt_ctx_t *p,
|
|||
return PARSE_OPT_ERROR;
|
||||
}
|
||||
|
||||
static enum parse_opt_result parse_subcommand(const char *arg,
|
||||
const struct option *options)
|
||||
{
|
||||
for (; options->type != OPTION_END; options++)
|
||||
if (options->type == OPTION_SUBCOMMAND &&
|
||||
!strcmp(options->long_name, arg)) {
|
||||
*(parse_opt_subcommand_fn **)options->value = options->subcommand_fn;
|
||||
return PARSE_OPT_SUBCOMMAND;
|
||||
}
|
||||
|
||||
return PARSE_OPT_UNKNOWN;
|
||||
}
|
||||
|
||||
static void check_typos(const char *arg, const struct option *options)
|
||||
{
|
||||
if (strlen(arg) < 3)
|
||||
|
@ -442,6 +457,7 @@ static void check_typos(const char *arg, const struct option *options)
|
|||
static void parse_options_check(const struct option *opts)
|
||||
{
|
||||
char short_opts[128];
|
||||
void *subcommand_value = NULL;
|
||||
|
||||
memset(short_opts, '\0', sizeof(short_opts));
|
||||
for (; opts->type != OPTION_END; opts++) {
|
||||
|
@ -489,6 +505,14 @@ static void parse_options_check(const struct option *opts)
|
|||
"Are you using parse_options_step() directly?\n"
|
||||
"That case is not supported yet.");
|
||||
break;
|
||||
case OPTION_SUBCOMMAND:
|
||||
if (!opts->value || !opts->subcommand_fn)
|
||||
optbug(opts, "OPTION_SUBCOMMAND needs a value and a subcommand function");
|
||||
if (!subcommand_value)
|
||||
subcommand_value = opts->value;
|
||||
else if (subcommand_value != opts->value)
|
||||
optbug(opts, "all OPTION_SUBCOMMANDs need the same value");
|
||||
break;
|
||||
default:
|
||||
; /* ok. (usually accepts an argument) */
|
||||
}
|
||||
|
@ -499,6 +523,14 @@ static void parse_options_check(const struct option *opts)
|
|||
BUG_if_bug("invalid 'struct option'");
|
||||
}
|
||||
|
||||
static int has_subcommands(const struct option *options)
|
||||
{
|
||||
for (; options->type != OPTION_END; options++)
|
||||
if (options->type == OPTION_SUBCOMMAND)
|
||||
return 1;
|
||||
return 0;
|
||||
}
|
||||
|
||||
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,7 +547,20 @@ 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;
|
||||
if ((flags & PARSE_OPT_KEEP_UNKNOWN) &&
|
||||
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_OPT 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");
|
||||
}
|
||||
}
|
||||
if ((flags & PARSE_OPT_KEEP_UNKNOWN_OPT) &&
|
||||
(flags & PARSE_OPT_STOP_AT_NON_OPTION) &&
|
||||
!(flags & PARSE_OPT_ONE_SHOT))
|
||||
BUG("STOP_AT_NON_OPTION and KEEP_UNKNOWN don't go together");
|
||||
|
@ -589,6 +634,7 @@ static int show_gitcomp(const struct option *opts, int show_all)
|
|||
int nr_noopts = 0;
|
||||
|
||||
for (; opts->type != OPTION_END; opts++) {
|
||||
const char *prefix = "--";
|
||||
const char *suffix = "";
|
||||
|
||||
if (!opts->long_name)
|
||||
|
@ -598,6 +644,9 @@ static int show_gitcomp(const struct option *opts, int show_all)
|
|||
continue;
|
||||
|
||||
switch (opts->type) {
|
||||
case OPTION_SUBCOMMAND:
|
||||
prefix = "";
|
||||
break;
|
||||
case OPTION_GROUP:
|
||||
continue;
|
||||
case OPTION_STRING:
|
||||
|
@ -620,7 +669,8 @@ static int show_gitcomp(const struct option *opts, int show_all)
|
|||
suffix = "=";
|
||||
if (starts_with(opts->long_name, "no-"))
|
||||
nr_noopts++;
|
||||
printf(" --%s%s", opts->long_name, suffix);
|
||||
printf("%s%s%s%s", opts == original_opts ? "" : " ",
|
||||
prefix, opts->long_name, suffix);
|
||||
}
|
||||
show_negated_gitcomp(original_opts, show_all, -1);
|
||||
show_negated_gitcomp(original_opts, show_all, nr_noopts);
|
||||
|
@ -743,10 +793,38 @@ enum parse_opt_result parse_options_step(struct parse_opt_ctx_t *ctx,
|
|||
if (*arg != '-' || !arg[1]) {
|
||||
if (parse_nodash_opt(ctx, arg, options) == 0)
|
||||
continue;
|
||||
if (ctx->flags & PARSE_OPT_STOP_AT_NON_OPTION)
|
||||
return PARSE_OPT_NON_OPTION;
|
||||
ctx->out[ctx->cpidx++] = ctx->argv[0];
|
||||
continue;
|
||||
if (!ctx->has_subcommands) {
|
||||
if (ctx->flags & PARSE_OPT_STOP_AT_NON_OPTION)
|
||||
return PARSE_OPT_NON_OPTION;
|
||||
ctx->out[ctx->cpidx++] = ctx->argv[0];
|
||||
continue;
|
||||
}
|
||||
switch (parse_subcommand(arg, options)) {
|
||||
case PARSE_OPT_SUBCOMMAND:
|
||||
return PARSE_OPT_SUBCOMMAND;
|
||||
case PARSE_OPT_UNKNOWN:
|
||||
if (ctx->flags & PARSE_OPT_SUBCOMMAND_OPTIONAL)
|
||||
/*
|
||||
* arg is neither a short or long
|
||||
* option nor a subcommand. Since
|
||||
* this command has a default
|
||||
* operation mode, we have to treat
|
||||
* this arg and all remaining args
|
||||
* as args meant to that default
|
||||
* operation mode.
|
||||
* So we are done parsing.
|
||||
*/
|
||||
return PARSE_OPT_DONE;
|
||||
error(_("unknown subcommand: `%s'"), arg);
|
||||
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:
|
||||
/* Impossible. */
|
||||
BUG("parse_subcommand() cannot return these");
|
||||
}
|
||||
}
|
||||
|
||||
/* lone -h asks for help */
|
||||
|
@ -774,6 +852,7 @@ enum parse_opt_result parse_options_step(struct parse_opt_ctx_t *ctx,
|
|||
goto show_usage;
|
||||
goto unknown;
|
||||
case PARSE_OPT_NON_OPTION:
|
||||
case PARSE_OPT_SUBCOMMAND:
|
||||
case PARSE_OPT_HELP:
|
||||
case PARSE_OPT_COMPLETE:
|
||||
BUG("parse_short_opt() cannot return these");
|
||||
|
@ -799,6 +878,7 @@ enum parse_opt_result parse_options_step(struct parse_opt_ctx_t *ctx,
|
|||
*(char *)ctx->argv[0] = '-';
|
||||
goto unknown;
|
||||
case PARSE_OPT_NON_OPTION:
|
||||
case PARSE_OPT_SUBCOMMAND:
|
||||
case PARSE_OPT_COMPLETE:
|
||||
case PARSE_OPT_HELP:
|
||||
BUG("parse_short_opt() cannot return these");
|
||||
|
@ -830,6 +910,7 @@ enum parse_opt_result parse_options_step(struct parse_opt_ctx_t *ctx,
|
|||
case PARSE_OPT_HELP:
|
||||
goto show_usage;
|
||||
case PARSE_OPT_NON_OPTION:
|
||||
case PARSE_OPT_SUBCOMMAND:
|
||||
case PARSE_OPT_COMPLETE:
|
||||
BUG("parse_long_opt() cannot return these");
|
||||
case PARSE_OPT_DONE:
|
||||
|
@ -839,7 +920,19 @@ enum parse_opt_result parse_options_step(struct parse_opt_ctx_t *ctx,
|
|||
unknown:
|
||||
if (ctx->flags & PARSE_OPT_ONE_SHOT)
|
||||
break;
|
||||
if (!(ctx->flags & PARSE_OPT_KEEP_UNKNOWN))
|
||||
if (ctx->has_subcommands &&
|
||||
(ctx->flags & PARSE_OPT_SUBCOMMAND_OPTIONAL) &&
|
||||
(ctx->flags & PARSE_OPT_KEEP_UNKNOWN_OPT)) {
|
||||
/*
|
||||
* Found an unknown option given to a command with
|
||||
* subcommands that has a default operation mode:
|
||||
* we treat this option and all remaining args as
|
||||
* arguments meant to that default operation mode.
|
||||
* So we are done parsing.
|
||||
*/
|
||||
return PARSE_OPT_DONE;
|
||||
}
|
||||
if (!(ctx->flags & PARSE_OPT_KEEP_UNKNOWN_OPT))
|
||||
return PARSE_OPT_UNKNOWN;
|
||||
ctx->out[ctx->cpidx++] = ctx->argv[0];
|
||||
ctx->opt = NULL;
|
||||
|
@ -884,7 +977,14 @@ int parse_options(int argc, const char **argv,
|
|||
case PARSE_OPT_COMPLETE:
|
||||
exit(0);
|
||||
case PARSE_OPT_NON_OPTION:
|
||||
case PARSE_OPT_SUBCOMMAND:
|
||||
break;
|
||||
case PARSE_OPT_DONE:
|
||||
if (ctx.has_subcommands &&
|
||||
!(flags & PARSE_OPT_SUBCOMMAND_OPTIONAL)) {
|
||||
error(_("need a subcommand"));
|
||||
usage_with_options(usagestr, options);
|
||||
}
|
||||
break;
|
||||
case PARSE_OPT_UNKNOWN:
|
||||
if (ctx.argv[0][1] == '-') {
|
||||
|
@ -1009,6 +1109,8 @@ static enum parse_opt_result usage_with_options_internal(struct parse_opt_ctx_t
|
|||
size_t pos;
|
||||
int pad;
|
||||
|
||||
if (opts->type == OPTION_SUBCOMMAND)
|
||||
continue;
|
||||
if (opts->type == OPTION_GROUP) {
|
||||
fputc('\n', outfile);
|
||||
need_newline = 0;
|
||||
|
|
|
@ -11,6 +11,7 @@ enum parse_opt_type {
|
|||
OPTION_GROUP,
|
||||
OPTION_NUMBER,
|
||||
OPTION_ALIAS,
|
||||
OPTION_SUBCOMMAND,
|
||||
/* options with no arguments */
|
||||
OPTION_BIT,
|
||||
OPTION_NEGBIT,
|
||||
|
@ -30,10 +31,11 @@ enum parse_opt_flags {
|
|||
PARSE_OPT_KEEP_DASHDASH = 1 << 0,
|
||||
PARSE_OPT_STOP_AT_NON_OPTION = 1 << 1,
|
||||
PARSE_OPT_KEEP_ARGV0 = 1 << 2,
|
||||
PARSE_OPT_KEEP_UNKNOWN = 1 << 3,
|
||||
PARSE_OPT_KEEP_UNKNOWN_OPT = 1 << 3,
|
||||
PARSE_OPT_NO_INTERNAL_HELP = 1 << 4,
|
||||
PARSE_OPT_ONE_SHOT = 1 << 5,
|
||||
PARSE_OPT_SHELL_EVAL = 1 << 6,
|
||||
PARSE_OPT_SUBCOMMAND_OPTIONAL = 1 << 7,
|
||||
};
|
||||
|
||||
enum parse_opt_option_flags {
|
||||
|
@ -56,6 +58,7 @@ enum parse_opt_result {
|
|||
PARSE_OPT_ERROR = -1, /* must be the same as error() */
|
||||
PARSE_OPT_DONE = 0, /* fixed so that "return 0" works */
|
||||
PARSE_OPT_NON_OPTION,
|
||||
PARSE_OPT_SUBCOMMAND,
|
||||
PARSE_OPT_UNKNOWN
|
||||
};
|
||||
|
||||
|
@ -67,6 +70,9 @@ typedef enum parse_opt_result parse_opt_ll_cb(struct parse_opt_ctx_t *ctx,
|
|||
const struct option *opt,
|
||||
const char *arg, int unset);
|
||||
|
||||
typedef int parse_opt_subcommand_fn(int argc, const char **argv,
|
||||
const char *prefix);
|
||||
|
||||
/*
|
||||
* `type`::
|
||||
* holds the type of the option, you must have an OPTION_END last in your
|
||||
|
@ -76,7 +82,8 @@ typedef enum parse_opt_result parse_opt_ll_cb(struct parse_opt_ctx_t *ctx,
|
|||
* the character to use as a short option name, '\0' if none.
|
||||
*
|
||||
* `long_name`::
|
||||
* the long option name, without the leading dashes, NULL if none.
|
||||
* the long option (without the leading dashes) or subcommand name,
|
||||
* NULL if none.
|
||||
*
|
||||
* `value`::
|
||||
* stores pointers to the values to be filled.
|
||||
|
@ -93,7 +100,7 @@ typedef enum parse_opt_result parse_opt_ll_cb(struct parse_opt_ctx_t *ctx,
|
|||
*
|
||||
* `help`::
|
||||
* the short help associated to what the option does.
|
||||
* Must never be NULL (except for OPTION_END).
|
||||
* Must never be NULL (except for OPTION_END and OPTION_SUBCOMMAND).
|
||||
* OPTION_GROUP uses this pointer to store the group header.
|
||||
* Should be wrapped by N_() for translation.
|
||||
*
|
||||
|
@ -109,7 +116,8 @@ typedef enum parse_opt_result parse_opt_ll_cb(struct parse_opt_ctx_t *ctx,
|
|||
* is last on the command line. If the option is
|
||||
* not last it will require an argument.
|
||||
* Should not be used with PARSE_OPT_OPTARG.
|
||||
* PARSE_OPT_NODASH: this option doesn't start with a dash.
|
||||
* PARSE_OPT_NODASH: this option doesn't start with a dash; can only be a
|
||||
* short option and can't accept arguments.
|
||||
* PARSE_OPT_LITERAL_ARGHELP: says that argh shouldn't be enclosed in brackets
|
||||
* (i.e. '<argh>') in the help message.
|
||||
* Useful for options with multiple parameters.
|
||||
|
@ -130,6 +138,9 @@ typedef enum parse_opt_result parse_opt_ll_cb(struct parse_opt_ctx_t *ctx,
|
|||
* `ll_callback`::
|
||||
* pointer to the callback to use for OPTION_LOWLEVEL_CALLBACK
|
||||
*
|
||||
* `subcommand_fn`::
|
||||
* pointer to a function to use for OPTION_SUBCOMMAND.
|
||||
* It will be put in value when the subcommand is given on the command line.
|
||||
*/
|
||||
struct option {
|
||||
enum parse_opt_type type;
|
||||
|
@ -144,6 +155,7 @@ struct option {
|
|||
intptr_t defval;
|
||||
parse_opt_ll_cb *ll_callback;
|
||||
intptr_t extra;
|
||||
parse_opt_subcommand_fn *subcommand_fn;
|
||||
};
|
||||
|
||||
#define OPT_BIT_F(s, l, v, h, b, f) { OPTION_BIT, (s), (l), (v), NULL, (h), \
|
||||
|
@ -205,6 +217,14 @@ struct option {
|
|||
#define OPT_ALIAS(s, l, source_long_name) \
|
||||
{ OPTION_ALIAS, (s), (l), (source_long_name) }
|
||||
|
||||
#define OPT_SUBCOMMAND_F(l, v, fn, f) { \
|
||||
.type = OPTION_SUBCOMMAND, \
|
||||
.long_name = (l), \
|
||||
.value = (v), \
|
||||
.flags = (f), \
|
||||
.subcommand_fn = (fn) }
|
||||
#define OPT_SUBCOMMAND(l, v, fn) OPT_SUBCOMMAND_F((l), (v), (fn), 0)
|
||||
|
||||
/*
|
||||
* parse_options() will filter out the processed options and leave the
|
||||
* non-option arguments in argv[]. argv0 is assumed program name and
|
||||
|
@ -294,6 +314,7 @@ struct parse_opt_ctx_t {
|
|||
int argc, cpidx, total;
|
||||
const char *opt;
|
||||
enum parse_opt_flags flags;
|
||||
unsigned has_subcommands;
|
||||
const char *prefix;
|
||||
const char **alias_groups; /* must be in groups of 3 elements! */
|
||||
struct option *updated_options;
|
||||
|
|
|
@ -192,3 +192,130 @@ int cmd__parse_options(int argc, const char **argv)
|
|||
|
||||
return ret;
|
||||
}
|
||||
|
||||
static void print_args(int argc, const char **argv)
|
||||
{
|
||||
for (int i = 0; i < argc; i++)
|
||||
printf("arg %02d: %s\n", i, argv[i]);
|
||||
}
|
||||
|
||||
static int parse_options_flags__cmd(int argc, const char **argv,
|
||||
enum parse_opt_flags test_flags)
|
||||
{
|
||||
const char *usage[] = {
|
||||
"<...> cmd [options]",
|
||||
NULL
|
||||
};
|
||||
int opt = 0;
|
||||
const struct option options[] = {
|
||||
OPT_INTEGER('o', "opt", &opt, "an integer option"),
|
||||
OPT_END()
|
||||
};
|
||||
|
||||
argc = parse_options(argc, argv, NULL, options, usage, test_flags);
|
||||
|
||||
printf("opt: %d\n", opt);
|
||||
print_args(argc, argv);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static enum parse_opt_flags test_flags = 0;
|
||||
static const struct option test_flag_options[] = {
|
||||
OPT_GROUP("flag-options:"),
|
||||
OPT_BIT(0, "keep-dashdash", &test_flags,
|
||||
"pass PARSE_OPT_KEEP_DASHDASH to parse_options()",
|
||||
PARSE_OPT_KEEP_DASHDASH),
|
||||
OPT_BIT(0, "stop-at-non-option", &test_flags,
|
||||
"pass PARSE_OPT_STOP_AT_NON_OPTION to parse_options()",
|
||||
PARSE_OPT_STOP_AT_NON_OPTION),
|
||||
OPT_BIT(0, "keep-argv0", &test_flags,
|
||||
"pass PARSE_OPT_KEEP_ARGV0 to parse_options()",
|
||||
PARSE_OPT_KEEP_ARGV0),
|
||||
OPT_BIT(0, "keep-unknown-opt", &test_flags,
|
||||
"pass PARSE_OPT_KEEP_UNKNOWN_OPT to parse_options()",
|
||||
PARSE_OPT_KEEP_UNKNOWN_OPT),
|
||||
OPT_BIT(0, "no-internal-help", &test_flags,
|
||||
"pass PARSE_OPT_NO_INTERNAL_HELP to parse_options()",
|
||||
PARSE_OPT_NO_INTERNAL_HELP),
|
||||
OPT_BIT(0, "subcommand-optional", &test_flags,
|
||||
"pass PARSE_OPT_SUBCOMMAND_OPTIONAL to parse_options()",
|
||||
PARSE_OPT_SUBCOMMAND_OPTIONAL),
|
||||
OPT_END()
|
||||
};
|
||||
|
||||
int cmd__parse_options_flags(int argc, const char **argv)
|
||||
{
|
||||
const char *usage[] = {
|
||||
"test-tool parse-options-flags [flag-options] cmd [options]",
|
||||
NULL
|
||||
};
|
||||
|
||||
argc = parse_options(argc, argv, NULL, test_flag_options, usage,
|
||||
PARSE_OPT_STOP_AT_NON_OPTION);
|
||||
|
||||
if (argc == 0 || strcmp(argv[0], "cmd")) {
|
||||
error("'cmd' is mandatory");
|
||||
usage_with_options(usage, test_flag_options);
|
||||
}
|
||||
|
||||
return parse_options_flags__cmd(argc, argv, test_flags);
|
||||
}
|
||||
|
||||
static int subcmd_one(int argc, const char **argv, const char *prefix)
|
||||
{
|
||||
printf("fn: subcmd_one\n");
|
||||
print_args(argc, argv);
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int subcmd_two(int argc, const char **argv, const char *prefix)
|
||||
{
|
||||
printf("fn: subcmd_two\n");
|
||||
print_args(argc, argv);
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int parse_subcommand__cmd(int argc, const char **argv,
|
||||
enum parse_opt_flags test_flags)
|
||||
{
|
||||
const char *usage[] = {
|
||||
"<...> cmd subcmd-one",
|
||||
"<...> cmd subcmd-two",
|
||||
NULL
|
||||
};
|
||||
parse_opt_subcommand_fn *fn = NULL;
|
||||
int opt = 0;
|
||||
struct option options[] = {
|
||||
OPT_SUBCOMMAND("subcmd-one", &fn, subcmd_one),
|
||||
OPT_SUBCOMMAND("subcmd-two", &fn, subcmd_two),
|
||||
OPT_INTEGER('o', "opt", &opt, "an integer option"),
|
||||
OPT_END()
|
||||
};
|
||||
|
||||
if (test_flags & PARSE_OPT_SUBCOMMAND_OPTIONAL)
|
||||
fn = subcmd_one;
|
||||
argc = parse_options(argc, argv, NULL, options, usage, test_flags);
|
||||
|
||||
printf("opt: %d\n", opt);
|
||||
|
||||
return fn(argc, argv, NULL);
|
||||
}
|
||||
|
||||
int cmd__parse_subcommand(int argc, const char **argv)
|
||||
{
|
||||
const char *usage[] = {
|
||||
"test-tool parse-subcommand [flag-options] cmd <subcommand>",
|
||||
NULL
|
||||
};
|
||||
|
||||
argc = parse_options(argc, argv, NULL, test_flag_options, usage,
|
||||
PARSE_OPT_STOP_AT_NON_OPTION);
|
||||
|
||||
if (argc == 0 || strcmp(argv[0], "cmd")) {
|
||||
error("'cmd' is mandatory");
|
||||
usage_with_options(usage, test_flag_options);
|
||||
}
|
||||
|
||||
return parse_subcommand__cmd(argc, argv, test_flags);
|
||||
}
|
||||
|
|
|
@ -24,7 +24,7 @@ int cmd__serve_v2(int argc, const char **argv)
|
|||
/* ignore all unknown cmdline switches for now */
|
||||
argc = parse_options(argc, argv, prefix, options, serve_usage,
|
||||
PARSE_OPT_KEEP_DASHDASH |
|
||||
PARSE_OPT_KEEP_UNKNOWN);
|
||||
PARSE_OPT_KEEP_UNKNOWN_OPT);
|
||||
|
||||
if (advertise_capabilities)
|
||||
protocol_v2_advertise_capabilities();
|
||||
|
|
|
@ -51,7 +51,9 @@ static struct test_cmd cmds[] = {
|
|||
{ "online-cpus", cmd__online_cpus },
|
||||
{ "pack-mtimes", cmd__pack_mtimes },
|
||||
{ "parse-options", cmd__parse_options },
|
||||
{ "parse-options-flags", cmd__parse_options_flags },
|
||||
{ "parse-pathspec-file", cmd__parse_pathspec_file },
|
||||
{ "parse-subcommand", cmd__parse_subcommand },
|
||||
{ "partial-clone", cmd__partial_clone },
|
||||
{ "path-utils", cmd__path_utils },
|
||||
{ "pcre2-config", cmd__pcre2_config },
|
||||
|
|
|
@ -41,7 +41,9 @@ int cmd__oidtree(int argc, const char **argv);
|
|||
int cmd__online_cpus(int argc, const char **argv);
|
||||
int cmd__pack_mtimes(int argc, const char **argv);
|
||||
int cmd__parse_options(int argc, const char **argv);
|
||||
int cmd__parse_options_flags(int argc, const char **argv);
|
||||
int cmd__parse_pathspec_file(int argc, const char** argv);
|
||||
int cmd__parse_subcommand(int argc, const char **argv);
|
||||
int cmd__partial_clone(int argc, const char **argv);
|
||||
int cmd__path_utils(int argc, const char **argv);
|
||||
int cmd__pcre2_config(int argc, const char **argv);
|
||||
|
|
|
@ -456,4 +456,259 @@ test_expect_success '--end-of-options treats remainder as args' '
|
|||
--end-of-options --verbose
|
||||
'
|
||||
|
||||
test_expect_success 'KEEP_DASHDASH works' '
|
||||
test-tool parse-options-flags --keep-dashdash cmd --opt=1 -- --opt=2 --unknown >actual &&
|
||||
cat >expect <<-\EOF &&
|
||||
opt: 1
|
||||
arg 00: --
|
||||
arg 01: --opt=2
|
||||
arg 02: --unknown
|
||||
EOF
|
||||
test_cmp expect actual
|
||||
'
|
||||
|
||||
test_expect_success 'KEEP_ARGV0 works' '
|
||||
test-tool parse-options-flags --keep-argv0 cmd arg0 --opt=3 >actual &&
|
||||
cat >expect <<-\EOF &&
|
||||
opt: 3
|
||||
arg 00: cmd
|
||||
arg 01: arg0
|
||||
EOF
|
||||
test_cmp expect actual
|
||||
'
|
||||
|
||||
test_expect_success 'STOP_AT_NON_OPTION works' '
|
||||
test-tool parse-options-flags --stop-at-non-option cmd --opt=4 arg0 --opt=5 --unknown >actual &&
|
||||
cat >expect <<-\EOF &&
|
||||
opt: 4
|
||||
arg 00: arg0
|
||||
arg 01: --opt=5
|
||||
arg 02: --unknown
|
||||
EOF
|
||||
test_cmp expect actual
|
||||
'
|
||||
|
||||
test_expect_success 'KEEP_UNKNOWN_OPT works' '
|
||||
test-tool parse-options-flags --keep-unknown-opt cmd --unknown=1 --opt=6 -u2 >actual &&
|
||||
cat >expect <<-\EOF &&
|
||||
opt: 6
|
||||
arg 00: --unknown=1
|
||||
arg 01: -u2
|
||||
EOF
|
||||
test_cmp expect actual
|
||||
'
|
||||
|
||||
test_expect_success 'NO_INTERNAL_HELP works for -h' '
|
||||
test_expect_code 129 test-tool parse-options-flags --no-internal-help cmd -h 2>err &&
|
||||
cat err &&
|
||||
grep "^error: unknown switch \`h$SQ" err &&
|
||||
grep "^usage: " err
|
||||
'
|
||||
|
||||
for help_opt in help help-all
|
||||
do
|
||||
test_expect_success "NO_INTERNAL_HELP works for --$help_opt" "
|
||||
test_expect_code 129 test-tool parse-options-flags --no-internal-help cmd --$help_opt 2>err &&
|
||||
cat err &&
|
||||
grep '^error: unknown option \`'$help_opt\' err &&
|
||||
grep '^usage: ' err
|
||||
"
|
||||
done
|
||||
|
||||
test_expect_success 'KEEP_UNKNOWN_OPT | NO_INTERNAL_HELP works' '
|
||||
test-tool parse-options-flags --keep-unknown-opt --no-internal-help cmd -h --help --help-all >actual &&
|
||||
cat >expect <<-\EOF &&
|
||||
opt: 0
|
||||
arg 00: -h
|
||||
arg 01: --help
|
||||
arg 02: --help-all
|
||||
EOF
|
||||
test_cmp expect actual
|
||||
'
|
||||
|
||||
test_expect_success 'subcommand - no subcommand shows error and usage' '
|
||||
test_expect_code 129 test-tool parse-subcommand cmd 2>err &&
|
||||
grep "^error: need a subcommand" err &&
|
||||
grep ^usage: err
|
||||
'
|
||||
|
||||
test_expect_success 'subcommand - subcommand after -- shows error and usage' '
|
||||
test_expect_code 129 test-tool parse-subcommand cmd -- subcmd-one 2>err &&
|
||||
grep "^error: need a subcommand" err &&
|
||||
grep ^usage: err
|
||||
'
|
||||
|
||||
test_expect_success 'subcommand - subcommand after --end-of-options shows error and usage' '
|
||||
test_expect_code 129 test-tool parse-subcommand cmd --end-of-options subcmd-one 2>err &&
|
||||
grep "^error: need a subcommand" err &&
|
||||
grep ^usage: err
|
||||
'
|
||||
|
||||
test_expect_success 'subcommand - unknown subcommand shows error and usage' '
|
||||
test_expect_code 129 test-tool parse-subcommand cmd nope 2>err &&
|
||||
grep "^error: unknown subcommand: \`nope$SQ" err &&
|
||||
grep ^usage: err
|
||||
'
|
||||
|
||||
test_expect_success 'subcommand - subcommands cannot be abbreviated' '
|
||||
test_expect_code 129 test-tool parse-subcommand cmd subcmd-o 2>err &&
|
||||
grep "^error: unknown subcommand: \`subcmd-o$SQ$" err &&
|
||||
grep ^usage: err
|
||||
'
|
||||
|
||||
test_expect_success 'subcommand - no negated subcommands' '
|
||||
test_expect_code 129 test-tool parse-subcommand cmd no-subcmd-one 2>err &&
|
||||
grep "^error: unknown subcommand: \`no-subcmd-one$SQ" err &&
|
||||
grep ^usage: err
|
||||
'
|
||||
|
||||
test_expect_success 'subcommand - simple' '
|
||||
test-tool parse-subcommand cmd subcmd-two >actual &&
|
||||
cat >expect <<-\EOF &&
|
||||
opt: 0
|
||||
fn: subcmd_two
|
||||
arg 00: subcmd-two
|
||||
EOF
|
||||
test_cmp expect actual
|
||||
'
|
||||
|
||||
test_expect_success 'subcommand - stop parsing at the first subcommand' '
|
||||
test-tool parse-subcommand cmd --opt=1 subcmd-two subcmd-one --opt=2 >actual &&
|
||||
cat >expect <<-\EOF &&
|
||||
opt: 1
|
||||
fn: subcmd_two
|
||||
arg 00: subcmd-two
|
||||
arg 01: subcmd-one
|
||||
arg 02: --opt=2
|
||||
EOF
|
||||
test_cmp expect actual
|
||||
'
|
||||
|
||||
test_expect_success 'subcommand - KEEP_ARGV0' '
|
||||
test-tool parse-subcommand --keep-argv0 cmd subcmd-two >actual &&
|
||||
cat >expect <<-\EOF &&
|
||||
opt: 0
|
||||
fn: subcmd_two
|
||||
arg 00: cmd
|
||||
arg 01: subcmd-two
|
||||
EOF
|
||||
test_cmp expect actual
|
||||
'
|
||||
|
||||
test_expect_success 'subcommand - SUBCOMMAND_OPTIONAL + subcommand not given' '
|
||||
test-tool parse-subcommand --subcommand-optional cmd >actual &&
|
||||
cat >expect <<-\EOF &&
|
||||
opt: 0
|
||||
fn: subcmd_one
|
||||
EOF
|
||||
test_cmp expect actual
|
||||
'
|
||||
|
||||
test_expect_success 'subcommand - SUBCOMMAND_OPTIONAL + given subcommand' '
|
||||
test-tool parse-subcommand --subcommand-optional cmd subcmd-two branch file >actual &&
|
||||
cat >expect <<-\EOF &&
|
||||
opt: 0
|
||||
fn: subcmd_two
|
||||
arg 00: subcmd-two
|
||||
arg 01: branch
|
||||
arg 02: file
|
||||
EOF
|
||||
test_cmp expect actual
|
||||
'
|
||||
|
||||
test_expect_success 'subcommand - SUBCOMMAND_OPTIONAL + subcommand not given + unknown dashless args' '
|
||||
test-tool parse-subcommand --subcommand-optional cmd branch file >actual &&
|
||||
cat >expect <<-\EOF &&
|
||||
opt: 0
|
||||
fn: subcmd_one
|
||||
arg 00: branch
|
||||
arg 01: file
|
||||
EOF
|
||||
test_cmp expect actual
|
||||
'
|
||||
|
||||
test_expect_success 'subcommand - SUBCOMMAND_OPTIONAL + subcommand not given + unknown option' '
|
||||
test_expect_code 129 test-tool parse-subcommand --subcommand-optional cmd --subcommand-opt 2>err &&
|
||||
grep "^error: unknown option" err &&
|
||||
grep ^usage: err
|
||||
'
|
||||
|
||||
test_expect_success 'subcommand - SUBCOMMAND_OPTIONAL | KEEP_UNKNOWN_OPT + subcommand not given + unknown option' '
|
||||
test-tool parse-subcommand --subcommand-optional --keep-unknown-opt cmd --subcommand-opt >actual &&
|
||||
cat >expect <<-\EOF &&
|
||||
opt: 0
|
||||
fn: subcmd_one
|
||||
arg 00: --subcommand-opt
|
||||
EOF
|
||||
test_cmp expect actual
|
||||
'
|
||||
|
||||
test_expect_success 'subcommand - SUBCOMMAND_OPTIONAL | KEEP_UNKNOWN_OPT + subcommand ignored after unknown option' '
|
||||
test-tool parse-subcommand --subcommand-optional --keep-unknown-opt cmd --subcommand-opt subcmd-two >actual &&
|
||||
cat >expect <<-\EOF &&
|
||||
opt: 0
|
||||
fn: subcmd_one
|
||||
arg 00: --subcommand-opt
|
||||
arg 01: subcmd-two
|
||||
EOF
|
||||
test_cmp expect actual
|
||||
'
|
||||
|
||||
test_expect_success 'subcommand - SUBCOMMAND_OPTIONAL | KEEP_UNKNOWN_OPT + command and subcommand options cannot be mixed' '
|
||||
test-tool parse-subcommand --subcommand-optional --keep-unknown-opt cmd --subcommand-opt branch --opt=1 >actual &&
|
||||
cat >expect <<-\EOF &&
|
||||
opt: 0
|
||||
fn: subcmd_one
|
||||
arg 00: --subcommand-opt
|
||||
arg 01: branch
|
||||
arg 02: --opt=1
|
||||
EOF
|
||||
test_cmp expect actual
|
||||
'
|
||||
|
||||
test_expect_success 'subcommand - SUBCOMMAND_OPTIONAL | KEEP_UNKNOWN_OPT | KEEP_ARGV0' '
|
||||
test-tool parse-subcommand --subcommand-optional --keep-unknown-opt --keep-argv0 cmd --subcommand-opt branch >actual &&
|
||||
cat >expect <<-\EOF &&
|
||||
opt: 0
|
||||
fn: subcmd_one
|
||||
arg 00: cmd
|
||||
arg 01: --subcommand-opt
|
||||
arg 02: branch
|
||||
EOF
|
||||
test_cmp expect actual
|
||||
'
|
||||
|
||||
test_expect_success 'subcommand - SUBCOMMAND_OPTIONAL | KEEP_UNKNOWN_OPT | KEEP_DASHDASH' '
|
||||
test-tool parse-subcommand --subcommand-optional --keep-unknown-opt --keep-dashdash cmd -- --subcommand-opt file >actual &&
|
||||
cat >expect <<-\EOF &&
|
||||
opt: 0
|
||||
fn: subcmd_one
|
||||
arg 00: --
|
||||
arg 01: --subcommand-opt
|
||||
arg 02: file
|
||||
EOF
|
||||
test_cmp expect actual
|
||||
'
|
||||
|
||||
test_expect_success 'subcommand - completion helper' '
|
||||
test-tool parse-subcommand cmd --git-completion-helper >actual &&
|
||||
echo "subcmd-one subcmd-two --opt= --no-opt" >expect &&
|
||||
test_cmp expect actual
|
||||
'
|
||||
|
||||
test_expect_success 'subcommands are incompatible with STOP_AT_NON_OPTION' '
|
||||
test_must_fail test-tool parse-subcommand --stop-at-non-option cmd subcmd-one 2>err &&
|
||||
grep ^BUG err
|
||||
'
|
||||
|
||||
test_expect_success 'subcommands are incompatible with KEEP_UNKNOWN_OPT unless in combination with SUBCOMMAND_OPTIONAL' '
|
||||
test_must_fail test-tool parse-subcommand --keep-unknown-opt cmd subcmd-two 2>err &&
|
||||
grep ^BUG err
|
||||
'
|
||||
|
||||
test_expect_success 'subcommands are incompatible with KEEP_DASHDASH unless in combination with SUBCOMMAND_OPTIONAL' '
|
||||
test_must_fail test-tool parse-subcommand --keep-dashdash cmd subcmd-two 2>err &&
|
||||
grep ^BUG err
|
||||
'
|
||||
|
||||
test_done
|
||||
|
|
|
@ -505,6 +505,11 @@ test_expect_success 'list notes with "git notes"' '
|
|||
test_cmp expect actual
|
||||
'
|
||||
|
||||
test_expect_success '"git notes" without subcommand does not take arguments' '
|
||||
test_expect_code 129 git notes HEAD^^ 2>err &&
|
||||
grep "^error: unknown subcommand" err
|
||||
'
|
||||
|
||||
test_expect_success 'list specific note with "git notes list <object>"' '
|
||||
git rev-parse refs/notes/commits:$commit_3 >expect &&
|
||||
git notes list HEAD^^ >actual &&
|
||||
|
|
|
@ -25,7 +25,7 @@ test_expect_success 'usage on main command -h emits a summary of subcommands' '
|
|||
grep -F "or: git stash show" usage
|
||||
'
|
||||
|
||||
test_expect_failure 'usage for subcommands should emit subcommand usage' '
|
||||
test_expect_success 'usage for subcommands should emit subcommand usage' '
|
||||
test_expect_code 129 git stash push -h >usage &&
|
||||
grep -F "usage: git stash [push" usage
|
||||
'
|
||||
|
|
|
@ -12,12 +12,12 @@ test_expect_success 'usage' '
|
|||
|
||||
test_expect_success 'usage shown without sub-command' '
|
||||
test_expect_code 129 git commit-graph 2>err &&
|
||||
! grep error: err
|
||||
grep usage: err
|
||||
'
|
||||
|
||||
test_expect_success 'usage shown with an error on unknown sub-command' '
|
||||
cat >expect <<-\EOF &&
|
||||
error: unrecognized subcommand: unknown
|
||||
error: unknown subcommand: `unknown'\''
|
||||
EOF
|
||||
test_expect_code 129 git commit-graph unknown 2>stderr &&
|
||||
grep error stderr >actual &&
|
||||
|
|
|
@ -241,6 +241,26 @@ test_expect_success 'add invalid foreign_vcs remote' '
|
|||
test_cmp expect actual
|
||||
'
|
||||
|
||||
test_expect_success 'without subcommand' '
|
||||
echo origin >expect &&
|
||||
git -C test remote >actual &&
|
||||
test_cmp expect actual
|
||||
'
|
||||
|
||||
test_expect_success 'without subcommand accepts -v' '
|
||||
cat >expect <<-EOF &&
|
||||
origin $(pwd)/one (fetch)
|
||||
origin $(pwd)/one (push)
|
||||
EOF
|
||||
git -C test remote -v >actual &&
|
||||
test_cmp expect actual
|
||||
'
|
||||
|
||||
test_expect_success 'without subcommand does not take arguments' '
|
||||
test_expect_code 129 git -C test remote origin 2>err &&
|
||||
grep "^error: unknown subcommand:" err
|
||||
'
|
||||
|
||||
cat >test/expect <<EOF
|
||||
* remote origin
|
||||
Fetch URL: $(pwd)/one
|
||||
|
|
|
@ -32,11 +32,13 @@ test_systemd_analyze_verify () {
|
|||
}
|
||||
|
||||
test_expect_success 'help text' '
|
||||
test_expect_code 129 git maintenance -h 2>err &&
|
||||
test_i18ngrep "usage: git maintenance <subcommand>" err &&
|
||||
test_expect_code 128 git maintenance barf 2>err &&
|
||||
test_i18ngrep "invalid subcommand: barf" err &&
|
||||
test_expect_code 129 git maintenance -h >actual &&
|
||||
test_i18ngrep "usage: git maintenance <subcommand>" actual &&
|
||||
test_expect_code 129 git maintenance barf 2>err &&
|
||||
test_i18ngrep "unknown subcommand: \`barf'\''" err &&
|
||||
test_i18ngrep "usage: git maintenance" err &&
|
||||
test_expect_code 129 git maintenance 2>err &&
|
||||
test_i18ngrep "error: need a subcommand" err &&
|
||||
test_i18ngrep "usage: git maintenance" err
|
||||
'
|
||||
|
||||
|
|
Загрузка…
Ссылка в новой задаче