git@vger.kernel.org mailing list mirror (one of many)
 help / color / mirror / code / Atom feed
* [PATCH 0/3] unused function parameters newly in next
@ 2022-08-25 10:45 Jeff King
  2022-08-25 10:47 ` [PATCH 1/3] pass subcommand "prefix" arguments to parse_options() Jeff King
                   ` (2 more replies)
  0 siblings, 3 replies; 5+ messages in thread
From: Jeff King @ 2022-08-25 10:45 UTC (permalink / raw
  To: git; +Cc: SZEDER Gábor

The sg/parse-options-subcommand topic was merged to 'next', and it
introduced a ton of -Wunused-parameter warnings. But I think in this
case it revealed some actual bugs, albeit minor.

Here are some fixes. I prepared them on top of that topic, which is
semantically necessary. But note that the topic is not itself at fault
for _introducing_ any bugs. It just revealed them. So I don't think
there's any need to pause its progress to master.

  [1/3]: pass subcommand "prefix" arguments to parse_options()
  [2/3]: maintenance: add parse-options boilerplate for subcommands
  [3/3]: remote: run "remote rm" argv through parse_options()

 builtin/commit-graph.c     |  4 ++--
 builtin/gc.c               | 43 +++++++++++++++++++++++++++++++++++++-
 builtin/multi-pack-index.c |  8 +++----
 builtin/remote.c           | 36 ++++++++++++++++++-------------
 builtin/sparse-checkout.c  |  8 +++----
 5 files changed, 73 insertions(+), 26 deletions(-)

-Peff

^ permalink raw reply	[flat|nested] 5+ messages in thread

* [PATCH 1/3] pass subcommand "prefix" arguments to parse_options()
  2022-08-25 10:45 [PATCH 0/3] unused function parameters newly in next Jeff King
@ 2022-08-25 10:47 ` Jeff King
  2022-08-25 16:47   ` Junio C Hamano
  2022-08-25 10:51 ` [PATCH 2/3] maintenance: add parse-options boilerplate for subcommands Jeff King
  2022-08-25 10:51 ` [PATCH 3/3] remote: run "remote rm" argv through parse_options() Jeff King
  2 siblings, 1 reply; 5+ messages in thread
From: Jeff King @ 2022-08-25 10:47 UTC (permalink / raw
  To: git; +Cc: SZEDER Gábor

Recent commits such as bf0a6b65fc (builtin/multi-pack-index.c: let
parse-options parse subcommands, 2022-08-19) converted a few functions
to match our usual argc/argv/prefix conventions, but the prefix argument
remains unused.

However, there is a good use for it: they should pass it to their own
parse_options() functions, where it may be used to adjust the value of
any filename options. In all but one of these functions, there's no
behavior change, since they don't use OPT_FILENAME. But this is an
actual fix for one option, which you can see by modifying the test suite
like so:

	diff --git a/t/t5326-multi-pack-bitmaps.sh b/t/t5326-multi-pack-bitmaps.sh
	index 4fe57414c1..d0974d4371 100755
	--- a/t/t5326-multi-pack-bitmaps.sh
	+++ b/t/t5326-multi-pack-bitmaps.sh
	@@ -186,7 +186,11 @@ test_expect_success 'writing a bitmap with --refs-snapshot' '

	 		# Then again, but with a refs snapshot which only sees
	 		# refs/tags/one.
	-		git multi-pack-index write --bitmap --refs-snapshot=snapshot &&
	+		(
	+			mkdir subdir &&
	+			cd subdir &&
	+			git multi-pack-index write --bitmap --refs-snapshot=../snapshot
	+		) &&

	 		test_path_is_file $midx &&
	 		test_path_is_file $midx-$(midx_checksum $objdir).bitmap &&

I'd emphasize that this wasn't broken by bf0a6b65fc; it has been broken
all along, because the sub-function never got to see the prefix. It is
that commit which is actually enabling us to fix it (and which also
brought attention to the problem because it triggers -Wunused-parameter!)

The other functions changed here don't use OPT_FILENAME at all. In their
cases this isn't fixing anything visible, but it's following the usual
pattern and future-proofing them against somebody adding new options and
being surprised.

I didn't include a test for the one visible case above. We don't
generally test routine parse-options behavior for individual options.
The challenge here was finding the problem, and now that this has been
done, it's not likely to regress. Likewise, we could apply the patch
above to cover it "for free" but it makes reading the rest of the test
unnecessarily complicated.

Signed-off-by: Jeff King <peff@peff.net>
---
 builtin/commit-graph.c     |  4 ++--
 builtin/multi-pack-index.c |  8 ++++----
 builtin/remote.c           | 28 ++++++++++++++++------------
 builtin/sparse-checkout.c  |  8 ++++----
 4 files changed, 26 insertions(+), 22 deletions(-)

diff --git a/builtin/commit-graph.c b/builtin/commit-graph.c
index 1eb5492cbd..dc3cc35394 100644
--- a/builtin/commit-graph.c
+++ b/builtin/commit-graph.c
@@ -80,7 +80,7 @@ static int graph_verify(int argc, const char **argv, const char *prefix)
 	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)
@@ -241,7 +241,7 @@ static int graph_write(int argc, const char **argv, const char *prefix)
 
 	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)
diff --git a/builtin/multi-pack-index.c b/builtin/multi-pack-index.c
index b8320d597b..248929f2e6 100644
--- a/builtin/multi-pack-index.c
+++ b/builtin/multi-pack-index.c
@@ -133,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)
@@ -176,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)
@@ -203,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)
@@ -233,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);
diff --git a/builtin/remote.c b/builtin/remote.c
index 4a6d47c03a..96f562f00a 100644
--- a/builtin/remote.c
+++ b/builtin/remote.c
@@ -177,8 +177,8 @@ static int add(int argc, const char **argv, const char *prefix)
 		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);
@@ -695,7 +695,7 @@ static int mv(int argc, const char **argv, const char *prefix)
 	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)
@@ -1264,7 +1264,8 @@ static int show(int argc, const char **argv, const char *prefix)
 	};
 	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)
@@ -1371,8 +1372,8 @@ static int set_head(int argc, const char **argv, const char *prefix)
 			 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]);
 
@@ -1471,8 +1472,8 @@ static int prune(int argc, const char **argv, const char *prefix)
 		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);
@@ -1504,7 +1505,8 @@ static int update(int argc, const char **argv, const char *prefix)
 	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");
@@ -1583,7 +1585,7 @@ static int set_branches(int argc, const char **argv, const char *prefix)
 		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"));
@@ -1608,7 +1610,8 @@ static int get_url(int argc, const char **argv, const char *prefix)
 			 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);
@@ -1668,7 +1671,8 @@ static int set_url(int argc, const char **argv, const char *prefix)
 			    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)
diff --git a/builtin/sparse-checkout.c b/builtin/sparse-checkout.c
index 7b39a150a9..287716db68 100644
--- a/builtin/sparse-checkout.c
+++ b/builtin/sparse-checkout.c
@@ -60,7 +60,7 @@ static int sparse_checkout_list(int argc, const char **argv, const char *prefix)
 	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);
 
@@ -452,7 +452,7 @@ static int sparse_checkout_init(int argc, const char **argv, const char *prefix)
 	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);
 
@@ -860,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);
 
@@ -897,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);
 
-- 
2.37.2.1034.gd926c9c740


^ permalink raw reply related	[flat|nested] 5+ messages in thread

* [PATCH 2/3] maintenance: add parse-options boilerplate for subcommands
  2022-08-25 10:45 [PATCH 0/3] unused function parameters newly in next Jeff King
  2022-08-25 10:47 ` [PATCH 1/3] pass subcommand "prefix" arguments to parse_options() Jeff King
@ 2022-08-25 10:51 ` Jeff King
  2022-08-25 10:51 ` [PATCH 3/3] remote: run "remote rm" argv through parse_options() Jeff King
  2 siblings, 0 replies; 5+ messages in thread
From: Jeff King @ 2022-08-25 10:51 UTC (permalink / raw
  To: git; +Cc: SZEDER Gábor

Several of the git-maintenance subcommands don't take any options, so
they don't bother looking at argv at all. This means they'll silently
accept garbage, like:

  $ git maintenance register --foo
  [no output]

  $ git maintenance stop bar
  [no output]

Let's give them the basic boilerplate to detect and handle these cases:

  $ git maintenance register --foo
  error: unknown option `foo'
  usage: git maintenance register

  $ git maintenance stop bar
  usage: git maintenance stop

We could reduce the number of lines of code here a bit with a shared
helper function. But it's worth building out the boilerplate, as it may
serve as the base for adding options later.

Note one complication: maintenance_start() calls directly into
maintenance_register(), so it now needs to pass a plausible argv (we
don't care, but parse_options() is expecting there to at least be an
argv[0] program name). This is an extra line of code, but it eliminates
the need for an explanatory comment.

Signed-off-by: Jeff King <peff@peff.net>
---
I kind of hate the register_args thing from the last paragraph.
parse-options is actually capable of handling a 0-length argc except
that it blindly walks past the first argument at the start. So loosening
it like this:

  diff --git a/parse-options.c b/parse-options.c
  index a1ec932f0f..c95ecd366a 100644
  --- a/parse-options.c
  +++ b/parse-options.c
  @@ -538,7 +538,7 @@ static void parse_options_start_1(struct parse_opt_ctx_t *ctx,
   {
          ctx->argc = argc;
          ctx->argv = argv;
  -       if (!(flags & PARSE_OPT_ONE_SHOT)) {
  +       if (!(flags & PARSE_OPT_ONE_SHOT) && ctx->argc) {
                  ctx->argc--;
                  ctx->argv++;
          }

makes the original code just work. But I dunno. It feels kind of subtle.
The solution in the patch below is ugly but fairly straightforward.

 builtin/gc.c | 43 ++++++++++++++++++++++++++++++++++++++++++-
 1 file changed, 42 insertions(+), 1 deletion(-)

diff --git a/builtin/gc.c b/builtin/gc.c
index 19d6b3b558..84549888f5 100644
--- a/builtin/gc.c
+++ b/builtin/gc.c
@@ -1465,14 +1465,28 @@ static char *get_maintpath(void)
 	return strbuf_detach(&sb, NULL);
 }
 
+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");
 
@@ -1509,12 +1523,26 @@ static int maintenance_register(int argc, const char **argv, const char *prefix)
 	return rc;
 }
 
+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);
@@ -2496,6 +2524,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);
@@ -2505,13 +2534,25 @@ 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(0, NULL, NULL)) /* It doesn't take any args */
+	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 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);
 }
 
-- 
2.37.2.1034.gd926c9c740


^ permalink raw reply related	[flat|nested] 5+ messages in thread

* [PATCH 3/3] remote: run "remote rm" argv through parse_options()
  2022-08-25 10:45 [PATCH 0/3] unused function parameters newly in next Jeff King
  2022-08-25 10:47 ` [PATCH 1/3] pass subcommand "prefix" arguments to parse_options() Jeff King
  2022-08-25 10:51 ` [PATCH 2/3] maintenance: add parse-options boilerplate for subcommands Jeff King
@ 2022-08-25 10:51 ` Jeff King
  2 siblings, 0 replies; 5+ messages in thread
From: Jeff King @ 2022-08-25 10:51 UTC (permalink / raw
  To: git; +Cc: SZEDER Gábor

The "git remote rm" command's option parsing is fairly primitive: it
insists on a single argument, which it treats as the remote name, and
displays a usage message otherwise.

This is OK, and maybe even convenient, as you could run:

  git remote rm --foo

to drop a remote named "--foo". But it's also weirdly unlike most of the
rest of Git, which would complain that there is no option "--foo". The
right way to spell it by our conventions is:

  git remote rm -- --foo

but this doesn't currently work.

So let's bring the command in line with the rest of Git (including its
sibling subcommands!) by feeding argv to parse_options(). We already
have an empty options array for the usage helper.

Note that we have to adjust the argc index down by one, as
parse_options() eats the program name from the start of the array.

Signed-off-by: Jeff King <peff@peff.net>
---
 builtin/remote.c | 8 +++++---
 1 file changed, 5 insertions(+), 3 deletions(-)

diff --git a/builtin/remote.c b/builtin/remote.c
index 96f562f00a..9aff864fd6 100644
--- a/builtin/remote.c
+++ b/builtin/remote.c
@@ -862,12 +862,14 @@ static int rm(int argc, const char **argv, const char *prefix)
 	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);
 	}
 
-- 
2.37.2.1034.gd926c9c740

^ permalink raw reply related	[flat|nested] 5+ messages in thread

* Re: [PATCH 1/3] pass subcommand "prefix" arguments to parse_options()
  2022-08-25 10:47 ` [PATCH 1/3] pass subcommand "prefix" arguments to parse_options() Jeff King
@ 2022-08-25 16:47   ` Junio C Hamano
  0 siblings, 0 replies; 5+ messages in thread
From: Junio C Hamano @ 2022-08-25 16:47 UTC (permalink / raw
  To: Jeff King; +Cc: git, SZEDER Gábor

Jeff King <peff@peff.net> writes:

> However, there is a good use for it: they should pass it to their own
> parse_options() functions, where it may be used to adjust the value of
> any filename options.

Oh, absolutely.  Not passing prefix if they use OPT_FILENAME would
be a bug.

> I'd emphasize that this wasn't broken by bf0a6b65fc; it has been broken
> all along, because the sub-function never got to see the prefix. It is
> that commit which is actually enabling us to fix it (and which also
> brought attention to the problem because it triggers -Wunused-parameter!)

Yeah.  I like that analysis.  With the commit, we pass prefix
through the callgraph, and now we can fix it ;-)

Thanks.

^ permalink raw reply	[flat|nested] 5+ messages in thread

end of thread, other threads:[~2022-08-25 16:49 UTC | newest]

Thread overview: 5+ messages (download: mbox.gz follow: Atom feed
-- links below jump to the message on this page --
2022-08-25 10:45 [PATCH 0/3] unused function parameters newly in next Jeff King
2022-08-25 10:47 ` [PATCH 1/3] pass subcommand "prefix" arguments to parse_options() Jeff King
2022-08-25 16:47   ` Junio C Hamano
2022-08-25 10:51 ` [PATCH 2/3] maintenance: add parse-options boilerplate for subcommands Jeff King
2022-08-25 10:51 ` [PATCH 3/3] remote: run "remote rm" argv through parse_options() Jeff King

Code repositories for project(s) associated with this public inbox

	https://80x24.org/mirrors/git.git

This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox;
as well as URLs for read-only IMAP folder(s) and NNTP newsgroup(s).