git@vger.kernel.org mailing list mirror (one of many)
 help / color / mirror / code / Atom feed
* [PATCH 0/2] parse-options.c: remove OPT_ARGUMENT
@ 2021-09-11 18:21 Ævar Arnfjörð Bjarmason
  2021-09-11 18:21 ` [PATCH 1/2] difftool: use "struct strvec" API in run_{dir,file}_diff() Ævar Arnfjörð Bjarmason
                   ` (2 more replies)
  0 siblings, 3 replies; 17+ messages in thread
From: Ævar Arnfjörð Bjarmason @ 2021-09-11 18:21 UTC (permalink / raw)
  To: git
  Cc: Junio C Hamano, Johannes Schindelin, Jeff King,
	Ævar Arnfjörð Bjarmason

We've only ever used parse-option.c's OPT_ARGUMENT() in one place, as
it turns out we can use an OPT_BOOL there instead. and get a net
reduction in code & complexity.

Ævar Arnfjörð Bjarmason (2):
  difftool: use "struct strvec" API in run_{dir,file}_diff()
  parse-options API: remove OPTION_ARGUMENT feature

 Documentation/technical/api-parse-options.txt |  5 --
 builtin/difftool.c                            | 50 +++++++++++--------
 parse-options.c                               | 13 -----
 parse-options.h                               |  3 --
 t/helper/test-parse-options.c                 |  1 -
 t/t0040-parse-options.sh                      |  5 --
 6 files changed, 28 insertions(+), 49 deletions(-)

-- 
2.33.0.995.ga5ea46173a2


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

* [PATCH 1/2] difftool: use "struct strvec" API in run_{dir,file}_diff()
  2021-09-11 18:21 [PATCH 0/2] parse-options.c: remove OPT_ARGUMENT Ævar Arnfjörð Bjarmason
@ 2021-09-11 18:21 ` Ævar Arnfjörð Bjarmason
  2021-09-12 22:39   ` Jeff King
  2021-09-11 18:21 ` [PATCH 2/2] parse-options API: remove OPTION_ARGUMENT feature Ævar Arnfjörð Bjarmason
  2021-09-13  3:35 ` [PATCH v2 0/4] difftool refactoring + remove OPT_ARGUMENT() macro Ævar Arnfjörð Bjarmason
  2 siblings, 1 reply; 17+ messages in thread
From: Ævar Arnfjörð Bjarmason @ 2021-09-11 18:21 UTC (permalink / raw)
  To: git
  Cc: Junio C Hamano, Johannes Schindelin, Jeff King,
	Ævar Arnfjörð Bjarmason

The underlying run_command() API can take either the "struct strvec
args", or a "const char **argv". Let's move to the former to use the
more "native" version of run_command() in both of these functions.

This change probably isn't worth in on its own, but sets us up to
simplify API use even more in a subsequent commit.

Signed-off-by: Ævar Arnfjörð Bjarmason <avarab@gmail.com>
---
 builtin/difftool.c | 46 +++++++++++++++++++++++++---------------------
 1 file changed, 25 insertions(+), 21 deletions(-)

diff --git a/builtin/difftool.c b/builtin/difftool.c
index 6a9242a8032..e656514bcac 100644
--- a/builtin/difftool.c
+++ b/builtin/difftool.c
@@ -331,7 +331,7 @@ static int checkout_path(unsigned mode, struct object_id *oid,
 }
 
 static int run_dir_diff(const char *extcmd, int symlinks, const char *prefix,
-			int argc, const char **argv)
+			struct strvec *args)
 {
 	char tmpdir[PATH_MAX];
 	struct strbuf info = STRBUF_INIT, lpath = STRBUF_INIT;
@@ -393,10 +393,8 @@ static int run_dir_diff(const char *extcmd, int symlinks, const char *prefix,
 	child.clean_on_exit = 1;
 	child.dir = prefix;
 	child.out = -1;
-	strvec_pushl(&child.args, "diff", "--raw", "--no-abbrev", "-z",
-		     NULL);
-	for (i = 0; i < argc; i++)
-		strvec_push(&child.args, argv[i]);
+	child.argv = args->v;
+
 	if (start_command(&child))
 		die("could not obtain raw diff");
 	fp = xfdopen(child.out, "r");
@@ -663,30 +661,30 @@ static int run_dir_diff(const char *extcmd, int symlinks, const char *prefix,
 	strbuf_release(&rdir);
 	strbuf_release(&wtdir);
 	strbuf_release(&buf);
+	strvec_clear(args);
 
 	return ret;
 }
 
-static int run_file_diff(int prompt, const char *prefix,
-			 int argc, const char **argv)
+static int run_file_diff(int prompt, const char *prefix, struct strvec *args)
 {
-	struct strvec args = STRVEC_INIT;
-	const char *env[] = {
-		"GIT_PAGER=", "GIT_EXTERNAL_DIFF=git-difftool--helper", NULL,
-		NULL
-	};
-	int i;
+	struct child_process cmd = CHILD_PROCESS_INIT;
+	int ret;
 
+	strvec_pushl(&cmd.env_array, "GIT_PAGER=",
+		     "GIT_EXTERNAL_DIFF=git-difftool--helper", NULL);
 	if (prompt > 0)
-		env[2] = "GIT_DIFFTOOL_PROMPT=true";
+		strvec_push(&cmd.env_array, "GIT_DIFFTOOL_PROMPT=true");
 	else if (!prompt)
-		env[2] = "GIT_DIFFTOOL_NO_PROMPT=true";
+		strvec_push(&cmd.env_array, "GIT_DIFFTOOL_NO_PROMPT=true");
 
+	cmd.git_cmd = 1;
+	cmd.dir = prefix;
+	cmd.argv = args->v;
 
-	strvec_push(&args, "diff");
-	for (i = 0; i < argc; i++)
-		strvec_push(&args, argv[i]);
-	return run_command_v_opt_cd_env(args.v, RUN_GIT_CMD, prefix, env);
+	ret = run_command(&cmd);
+	strvec_clear(args);
+	return ret;
 }
 
 int cmd_difftool(int argc, const char **argv, const char *prefix)
@@ -719,6 +717,7 @@ int cmd_difftool(int argc, const char **argv, const char *prefix)
 		OPT_ARGUMENT("no-index", &no_index, N_("passed to `diff`")),
 		OPT_END()
 	};
+	struct strvec args = STRVEC_INIT;
 
 	git_config(difftool_config, NULL);
 	symlinks = has_symlinks;
@@ -768,7 +767,12 @@ int cmd_difftool(int argc, const char **argv, const char *prefix)
 	 * will invoke a separate instance of 'git-difftool--helper' for
 	 * each file that changed.
 	 */
+	strvec_push(&args, "diff");
+	if (dir_diff)
+		strvec_pushl(&args, "--raw", "--no-abbrev", "-z", NULL);
+	strvec_pushv(&args, argv);
+
 	if (dir_diff)
-		return run_dir_diff(extcmd, symlinks, prefix, argc, argv);
-	return run_file_diff(prompt, prefix, argc, argv);
+		return run_dir_diff(extcmd, symlinks, prefix, &args);
+	return run_file_diff(prompt, prefix, &args);
 }
-- 
2.33.0.995.ga5ea46173a2


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

* [PATCH 2/2] parse-options API: remove OPTION_ARGUMENT feature
  2021-09-11 18:21 [PATCH 0/2] parse-options.c: remove OPT_ARGUMENT Ævar Arnfjörð Bjarmason
  2021-09-11 18:21 ` [PATCH 1/2] difftool: use "struct strvec" API in run_{dir,file}_diff() Ævar Arnfjörð Bjarmason
@ 2021-09-11 18:21 ` Ævar Arnfjörð Bjarmason
  2021-09-12 22:43   ` Jeff King
  2021-09-13  3:35 ` [PATCH v2 0/4] difftool refactoring + remove OPT_ARGUMENT() macro Ævar Arnfjörð Bjarmason
  2 siblings, 1 reply; 17+ messages in thread
From: Ævar Arnfjörð Bjarmason @ 2021-09-11 18:21 UTC (permalink / raw)
  To: git
  Cc: Junio C Hamano, Johannes Schindelin, Jeff King,
	Ævar Arnfjörð Bjarmason

As was noted in 1a85b49b87a (parse-options: make OPT_ARGUMENT() more
useful, 2019-03-14) there's only ever been one user of the
OPT_ARGUMENT(), that user was added in 20de316e334 (difftool: allow
running outside Git worktrees with --no-index, 2019-03-14).

The OPT_ARGUMENT() feature itself was added way back in
580d5bffdea (parse-options: new option type to treat an option-like
parameter as an argument., 2008-03-02), but as discussed in
1a85b49b87a wasn't used until 20de316e334 in 2019.

Now that the preceding commit has migrated this code over to using
"struct strvec" to manage the "args" member of a "struct
child_process", we can just use that directly instead of relying on
OPT_ARGUMENT.

This has a minor change in behavior in that if we'll pass --no-index
we'll now always pass it as the first argument, before we'd pass it in
whatever position the caller did. Preserving this was the real value
of OPT_ARGUMENT(), but as it turns out we didn't need that either. We
can always inject it as the first argument, the other end will parse
it just the same.

Note that we cannot remove the "out" and "cpidx" members of "struct
parse_opt_ctx_t" added in 580d5bffdea, while they were introduced with
OPT_ARGUMENT() we since used them for other things.

Signed-off-by: Ævar Arnfjörð Bjarmason <avarab@gmail.com>
---
 Documentation/technical/api-parse-options.txt |  5 -----
 builtin/difftool.c                            |  4 +++-
 parse-options.c                               | 13 -------------
 parse-options.h                               |  3 ---
 t/helper/test-parse-options.c                 |  1 -
 t/t0040-parse-options.sh                      |  5 -----
 6 files changed, 3 insertions(+), 28 deletions(-)

diff --git a/Documentation/technical/api-parse-options.txt b/Documentation/technical/api-parse-options.txt
index 5a60bbfa7f4..acfd5dc1d8b 100644
--- a/Documentation/technical/api-parse-options.txt
+++ b/Documentation/technical/api-parse-options.txt
@@ -198,11 +198,6 @@ There are some macros to easily define options:
 	The filename will be prefixed by passing the filename along with
 	the prefix argument of `parse_options()` to `prefix_filename()`.
 
-`OPT_ARGUMENT(long, &int_var, description)`::
-	Introduce a long-option argument that will be kept in `argv[]`.
-	If this option was seen, `int_var` will be set to one (except
-	if a `NULL` pointer was passed).
-
 `OPT_NUMBER_CALLBACK(&var, description, func_ptr)`::
 	Recognize numerical options like -123 and feed the integer as
 	if it was an argument to the function given by `func_ptr`.
diff --git a/builtin/difftool.c b/builtin/difftool.c
index e656514bcac..9aa77a91043 100644
--- a/builtin/difftool.c
+++ b/builtin/difftool.c
@@ -714,7 +714,7 @@ int cmd_difftool(int argc, const char **argv, const char *prefix)
 			    "tool returns a non - zero exit code")),
 		OPT_STRING('x', "extcmd", &extcmd, N_("command"),
 			   N_("specify a custom command for viewing diffs")),
-		OPT_ARGUMENT("no-index", &no_index, N_("passed to `diff`")),
+		OPT_BOOL(0, "no-index", &no_index, N_("passed to `diff`")),
 		OPT_END()
 	};
 	struct strvec args = STRVEC_INIT;
@@ -768,6 +768,8 @@ int cmd_difftool(int argc, const char **argv, const char *prefix)
 	 * each file that changed.
 	 */
 	strvec_push(&args, "diff");
+	if (no_index)
+		strvec_push(&args, "--no-index");
 	if (dir_diff)
 		strvec_pushl(&args, "--raw", "--no-abbrev", "-z", NULL);
 	strvec_pushv(&args, argv);
diff --git a/parse-options.c b/parse-options.c
index 2abff136a17..55c5821b08d 100644
--- a/parse-options.c
+++ b/parse-options.c
@@ -310,19 +310,6 @@ static enum parse_opt_result parse_long_opt(
 again:
 		if (!skip_prefix(arg, long_name, &rest))
 			rest = NULL;
-		if (options->type == OPTION_ARGUMENT) {
-			if (!rest)
-				continue;
-			if (*rest == '=')
-				return error(_("%s takes no value"),
-					     optname(options, flags));
-			if (*rest)
-				continue;
-			if (options->value)
-				*(int *)options->value = options->defval;
-			p->out[p->cpidx++] = arg - 2;
-			return PARSE_OPT_DONE;
-		}
 		if (!rest) {
 			/* abbreviated? */
 			if (!(p->flags & PARSE_OPT_KEEP_UNKNOWN) &&
diff --git a/parse-options.h b/parse-options.h
index a845a9d9527..39d90882548 100644
--- a/parse-options.h
+++ b/parse-options.h
@@ -8,7 +8,6 @@
 enum parse_opt_type {
 	/* special types */
 	OPTION_END,
-	OPTION_ARGUMENT,
 	OPTION_GROUP,
 	OPTION_NUMBER,
 	OPTION_ALIAS,
@@ -155,8 +154,6 @@ struct option {
 #define OPT_INTEGER_F(s, l, v, h, f)     { OPTION_INTEGER, (s), (l), (v), N_("n"), (h), (f) }
 
 #define OPT_END()                   { OPTION_END }
-#define OPT_ARGUMENT(l, v, h)       { OPTION_ARGUMENT, 0, (l), (v), NULL, \
-				      (h), PARSE_OPT_NOARG, NULL, 1 }
 #define OPT_GROUP(h)                { OPTION_GROUP, 0, NULL, NULL, NULL, (h) }
 #define OPT_BIT(s, l, v, h, b)      OPT_BIT_F(s, l, v, h, b, 0)
 #define OPT_BITOP(s, l, v, h, set, clear) { OPTION_BITOP, (s), (l), (v), NULL, (h), \
diff --git a/t/helper/test-parse-options.c b/t/helper/test-parse-options.c
index 2051ce57db7..a282b6ff13e 100644
--- a/t/helper/test-parse-options.c
+++ b/t/helper/test-parse-options.c
@@ -134,7 +134,6 @@ int cmd__parse_options(int argc, const char **argv)
 		OPT_NOOP_NOARG(0, "obsolete"),
 		OPT_STRING_LIST(0, "list", &list, "str", "add str to list"),
 		OPT_GROUP("Magic arguments"),
-		OPT_ARGUMENT("quux", NULL, "means --quux"),
 		OPT_NUMBER_CALLBACK(&integer, "set integer to NUM",
 			number_callback),
 		{ OPTION_COUNTUP, '+', NULL, &boolean, NULL, "same as -b",
diff --git a/t/t0040-parse-options.sh b/t/t0040-parse-options.sh
index ad4746d899a..da310ed29b1 100755
--- a/t/t0040-parse-options.sh
+++ b/t/t0040-parse-options.sh
@@ -37,7 +37,6 @@ String options
     --list <str>          add str to list
 
 Magic arguments
-    --quux                means --quux
     -NUM                  set integer to NUM
     +                     same as -b
     --ambiguous           positive ambiguity
@@ -263,10 +262,6 @@ test_expect_success 'detect possible typos' '
 	test_cmp typo.err output.err
 '
 
-test_expect_success 'keep some options as arguments' '
-	test-tool parse-options --expect="arg 00: --quux" --quux
-'
-
 cat >expect <<\EOF
 Callback: "four", 0
 boolean: 5
-- 
2.33.0.995.ga5ea46173a2


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

* Re: [PATCH 1/2] difftool: use "struct strvec" API in run_{dir,file}_diff()
  2021-09-11 18:21 ` [PATCH 1/2] difftool: use "struct strvec" API in run_{dir,file}_diff() Ævar Arnfjörð Bjarmason
@ 2021-09-12 22:39   ` Jeff King
  2021-09-12 22:41     ` Jeff King
  2021-09-13  0:10     ` Junio C Hamano
  0 siblings, 2 replies; 17+ messages in thread
From: Jeff King @ 2021-09-12 22:39 UTC (permalink / raw)
  To: Ævar Arnfjörð Bjarmason
  Cc: git, Junio C Hamano, Johannes Schindelin

On Sat, Sep 11, 2021 at 08:21:11PM +0200, Ævar Arnfjörð Bjarmason wrote:

> The underlying run_command() API can take either the "struct strvec
> args", or a "const char **argv". Let's move to the former to use the
> more "native" version of run_command() in both of these functions.

It sounds like we're moving to use child.args (the strvec interface)
instead of child.argv (the const char one). Which I support; I'd like to
eventually get rid of the argv interface entirely because it has
memory-ownership semantics that are easy to get wrong.

But this...

> @@ -393,10 +393,8 @@ static int run_dir_diff(const char *extcmd, int symlinks, const char *prefix,
>  	child.clean_on_exit = 1;
>  	child.dir = prefix;
>  	child.out = -1;
> -	strvec_pushl(&child.args, "diff", "--raw", "--no-abbrev", "-z",
> -		     NULL);
> -	for (i = 0; i < argc; i++)
> -		strvec_push(&child.args, argv[i]);
> +	child.argv = args->v;
> +

...is going in the opposite direction.

I'd much rather see us continue to use child.args here, like:

  strvec_pushv(&child.args, args->v);

Though really I do think passing the strvec into run_dir_diff() is
questionable in the first place. The caller depends on us to free the
memory in the strvec for them, which is...subtle.

It does let you immediately return here:

>  	if (dir_diff)
> -		return run_dir_diff(extcmd, symlinks, prefix, argc, argv);
> -	return run_file_diff(prompt, prefix, argc, argv);
> +		return run_dir_diff(extcmd, symlinks, prefix, &args);
> +	return run_file_diff(prompt, prefix, &args);

without doing any cleanup. But I think just:

  if (dir_diff)
	ret = run_dir_diff(...);
  else
	ret = run_file_diff(...);

  strvec_clear(&args);
  return ret;

would be a lot more obvious.

I almost suggested that this could be done even simpler by having the
caller pass in one of two pre-made argv lists (in addition to what's in
the original argv). But the _actual_ benefit you want here is making it
easy to construct those lists in the shared code of the caller. Your
commit message didn't at all make that clear (so to me it looked like
your "cleanup" was actively making things worse).

It only becomes apparent with the second patch. I would have found it
much easier to understand with something like the patch below. And then
a further patch to use strvec_pushv instead of manually looping (even
getting rid of the argc parameters entirely!), and one to convert
run_file_diff() to use a struct child_process (which fixes its memory
leak).


-- >8 --
difftool: prepare "diff" cmdline in cmd_difftool()

We call into either run_dir_diff() or run_file_diff(), each of which
sets up a child argv starting with "diff" and some hard-coded options
(depending on which mode we're using). Let's extract that logic into the
caller, which will make it easier to modify the options for cases which
affect both functions.

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

diff --git a/builtin/difftool.c b/builtin/difftool.c
index 6a9242a803..91a8e51b0c 100644
--- a/builtin/difftool.c
+++ b/builtin/difftool.c
@@ -393,8 +393,6 @@ static int run_dir_diff(const char *extcmd, int symlinks, const char *prefix,
 	child.clean_on_exit = 1;
 	child.dir = prefix;
 	child.out = -1;
-	strvec_pushl(&child.args, "diff", "--raw", "--no-abbrev", "-z",
-		     NULL);
 	for (i = 0; i < argc; i++)
 		strvec_push(&child.args, argv[i]);
 	if (start_command(&child))
@@ -683,7 +681,6 @@ static int run_file_diff(int prompt, const char *prefix,
 		env[2] = "GIT_DIFFTOOL_NO_PROMPT=true";
 
 
-	strvec_push(&args, "diff");
 	for (i = 0; i < argc; i++)
 		strvec_push(&args, argv[i]);
 	return run_command_v_opt_cd_env(args.v, RUN_GIT_CMD, prefix, env);
@@ -719,6 +716,7 @@ int cmd_difftool(int argc, const char **argv, const char *prefix)
 		OPT_ARGUMENT("no-index", &no_index, N_("passed to `diff`")),
 		OPT_END()
 	};
+	struct strvec args = STRVEC_INIT;
 
 	git_config(difftool_config, NULL);
 	symlinks = has_symlinks;
@@ -768,7 +766,12 @@ int cmd_difftool(int argc, const char **argv, const char *prefix)
 	 * will invoke a separate instance of 'git-difftool--helper' for
 	 * each file that changed.
 	 */
+	strvec_push(&args, "diff");
+	if (dir_diff)
+		strvec_pushl(&args, "--raw", "--no-abbrev", "-z", NULL);
+	strvec_pushv(&args, argv);
+
 	if (dir_diff)
-		return run_dir_diff(extcmd, symlinks, prefix, argc, argv);
-	return run_file_diff(prompt, prefix, argc, argv);
+		return run_dir_diff(extcmd, symlinks, prefix, args.nr, args.v);
+	return run_file_diff(prompt, prefix, args.nr, args.v);
 }
-- 
2.33.0.811.g40f7f3a89c

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

* Re: [PATCH 1/2] difftool: use "struct strvec" API in run_{dir,file}_diff()
  2021-09-12 22:39   ` Jeff King
@ 2021-09-12 22:41     ` Jeff King
  2021-09-13  0:10     ` Junio C Hamano
  1 sibling, 0 replies; 17+ messages in thread
From: Jeff King @ 2021-09-12 22:41 UTC (permalink / raw)
  To: Ævar Arnfjörð Bjarmason
  Cc: git, Junio C Hamano, Johannes Schindelin

On Sun, Sep 12, 2021 at 06:39:26PM -0400, Jeff King wrote:

> It only becomes apparent with the second patch. I would have found it
> much easier to understand with something like the patch below. And then
> a further patch to use strvec_pushv instead of manually looping (even
> getting rid of the argc parameters entirely!), and one to convert
> run_file_diff() to use a struct child_process (which fixes its memory
> leak).
> 
> -- >8 --
> difftool: prepare "diff" cmdline in cmd_difftool()

Note that this actually introduces a new leak of the strvec in the
caller. So it would probably want the "ret =" think I suggested to be
squashed in.

(I wasn't really planning to make a finished patch, but just trying to
illustrate what had confused me in your original. I ended up closer than
I had planned, though).

-Peff

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

* Re: [PATCH 2/2] parse-options API: remove OPTION_ARGUMENT feature
  2021-09-11 18:21 ` [PATCH 2/2] parse-options API: remove OPTION_ARGUMENT feature Ævar Arnfjörð Bjarmason
@ 2021-09-12 22:43   ` Jeff King
  0 siblings, 0 replies; 17+ messages in thread
From: Jeff King @ 2021-09-12 22:43 UTC (permalink / raw)
  To: Ævar Arnfjörð Bjarmason
  Cc: git, Junio C Hamano, Johannes Schindelin

On Sat, Sep 11, 2021 at 08:21:12PM +0200, Ævar Arnfjörð Bjarmason wrote:

> As was noted in 1a85b49b87a (parse-options: make OPT_ARGUMENT() more
> useful, 2019-03-14) there's only ever been one user of the
> OPT_ARGUMENT(), that user was added in 20de316e334 (difftool: allow
> running outside Git worktrees with --no-index, 2019-03-14).
> 
> The OPT_ARGUMENT() feature itself was added way back in
> 580d5bffdea (parse-options: new option type to treat an option-like
> parameter as an argument., 2008-03-02), but as discussed in
> 1a85b49b87a wasn't used until 20de316e334 in 2019.
> 
> Now that the preceding commit has migrated this code over to using
> "struct strvec" to manage the "args" member of a "struct
> child_process", we can just use that directly instead of relying on
> OPT_ARGUMENT.

Yeah, the change in difftool here looks fine (regardless of how the
cleanup in the first patch gets there). And I'm happy to see this
somewhat weird OPT_ macro go away if nobody is using it.

-Peff

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

* Re: [PATCH 1/2] difftool: use "struct strvec" API in run_{dir,file}_diff()
  2021-09-12 22:39   ` Jeff King
  2021-09-12 22:41     ` Jeff King
@ 2021-09-13  0:10     ` Junio C Hamano
  1 sibling, 0 replies; 17+ messages in thread
From: Junio C Hamano @ 2021-09-13  0:10 UTC (permalink / raw)
  To: Jeff King
  Cc: Ævar Arnfjörð Bjarmason, git, Johannes Schindelin

Jeff King <peff@peff.net> writes:

> On Sat, Sep 11, 2021 at 08:21:11PM +0200, Ævar Arnfjörð Bjarmason wrote:
>
>> The underlying run_command() API can take either the "struct strvec
>> args", or a "const char **argv". Let's move to the former to use the
>> more "native" version of run_command() in both of these functions.
>
> It sounds like we're moving to use child.args (the strvec interface)
> instead of child.argv (the const char one). Which I support; I'd like to
> eventually get rid of the argv interface entirely because it has
> memory-ownership semantics that are easy to get wrong.
>
> But this...
>
>> @@ -393,10 +393,8 @@ static int run_dir_diff(const char *extcmd, int symlinks, const char *prefix,
>>  	child.clean_on_exit = 1;
>>  	child.dir = prefix;
>>  	child.out = -1;
>> -	strvec_pushl(&child.args, "diff", "--raw", "--no-abbrev", "-z",
>> -		     NULL);
>> -	for (i = 0; i < argc; i++)
>> -		strvec_push(&child.args, argv[i]);
>> +	child.argv = args->v;
>> +
>
> ...is going in the opposite direction.
>
> I'd much rather see us continue to use child.args here, like:
>
>   strvec_pushv(&child.args, args->v);
>
> Though really I do think passing the strvec into run_dir_diff() is
> questionable in the first place. The caller depends on us to free the
> memory in the strvec for them, which is...subtle.
> ...
> +	strvec_push(&args, "diff");
> +	if (dir_diff)
> +		strvec_pushl(&args, "--raw", "--no-abbrev", "-z", NULL);
> +	strvec_pushv(&args, argv);
> +
>  	if (dir_diff)
> -		return run_dir_diff(extcmd, symlinks, prefix, argc, argv);
> -	return run_file_diff(prompt, prefix, argc, argv);
> +		return run_dir_diff(extcmd, symlinks, prefix, args.nr, args.v);
> +	return run_file_diff(prompt, prefix, args.nr, args.v);
>  }

Yes, I have to say that the end result of not having to rely on the
strvec type, in order to just call a main()- like function, makes it
much more pleasant read.


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

* [PATCH v2 0/4] difftool refactoring + remove OPT_ARGUMENT() macro
  2021-09-11 18:21 [PATCH 0/2] parse-options.c: remove OPT_ARGUMENT Ævar Arnfjörð Bjarmason
  2021-09-11 18:21 ` [PATCH 1/2] difftool: use "struct strvec" API in run_{dir,file}_diff() Ævar Arnfjörð Bjarmason
  2021-09-11 18:21 ` [PATCH 2/2] parse-options API: remove OPTION_ARGUMENT feature Ævar Arnfjörð Bjarmason
@ 2021-09-13  3:35 ` Ævar Arnfjörð Bjarmason
  2021-09-13  3:35   ` [PATCH v2 1/4] difftool: prepare "struct child_process" in cmd_difftool() Ævar Arnfjörð Bjarmason
                     ` (4 more replies)
  2 siblings, 5 replies; 17+ messages in thread
From: Ævar Arnfjörð Bjarmason @ 2021-09-13  3:35 UTC (permalink / raw)
  To: git
  Cc: Junio C Hamano, Johannes Schindelin, Jeff King,
	Ævar Arnfjörð Bjarmason

We've only ever used parse-option.c's OPT_ARGUMENT() in one place, as
it turns out we can use an OPT_BOOL there instead. and get a net
reduction in code & complexity.

I think this v2 should address the comments Jeff King had in
https://lore.kernel.org/git/YT6BnnXeAWn8BycF@coredump.intra.peff.net/;
there's now an amended version of his proposed patch as part of this,
but I prepended it with another one to prepare the "struct
child_process" in cmd_difftool().

Doing so nicely gets around the question of the strvec memory
management, since we can trust the run-command.c API to do that for
us, but couldn't in my v1 when we'd copy our own "struct strvec *" to
its "args".

Jeff King (1):
  difftool: prepare "diff" cmdline in cmd_difftool()

Ævar Arnfjörð Bjarmason (3):
  difftool: prepare "struct child_process" in cmd_difftool()
  difftool: use run_command() API in run_file_diff()
  parse-options API: remove OPTION_ARGUMENT feature

 Documentation/technical/api-parse-options.txt |  5 --
 builtin/difftool.c                            | 51 ++++++++++---------
 parse-options.c                               | 13 -----
 parse-options.h                               |  3 --
 t/helper/test-parse-options.c                 |  1 -
 t/t0040-parse-options.sh                      |  5 --
 6 files changed, 26 insertions(+), 52 deletions(-)

Range-diff against v1:
1:  e7481eb0c0c ! 1:  f57c6c9b069 difftool: use "struct strvec" API in run_{dir,file}_diff()
    @@ Metadata
     Author: Ævar Arnfjörð Bjarmason <avarab@gmail.com>
     
      ## Commit message ##
    -    difftool: use "struct strvec" API in run_{dir,file}_diff()
    +    difftool: prepare "struct child_process" in cmd_difftool()
     
    -    The underlying run_command() API can take either the "struct strvec
    -    args", or a "const char **argv". Let's move to the former to use the
    -    more "native" version of run_command() in both of these functions.
    -
    -    This change probably isn't worth in on its own, but sets us up to
    -    simplify API use even more in a subsequent commit.
    +    Move the preparation of the "struct child_process" from run_dir_diff()
    +    to its only caller, cmd_difftool(). This is in preparation for
    +    migrating run_file_diff() to using the run_command() API directly, and
    +    to move more of the shared setup of the two to cmd_difftool().
     
         Signed-off-by: Ævar Arnfjörð Bjarmason <avarab@gmail.com>
     
    @@ builtin/difftool.c: static int checkout_path(unsigned mode, struct object_id *oi
      
      static int run_dir_diff(const char *extcmd, int symlinks, const char *prefix,
     -			int argc, const char **argv)
    -+			struct strvec *args)
    ++			int argc, const char **argv,
    ++			struct child_process *child)
      {
      	char tmpdir[PATH_MAX];
      	struct strbuf info = STRBUF_INIT, lpath = STRBUF_INIT;
     @@ builtin/difftool.c: static int run_dir_diff(const char *extcmd, int symlinks, const char *prefix,
    - 	child.clean_on_exit = 1;
    - 	child.dir = prefix;
    - 	child.out = -1;
    + 	struct index_state wtindex;
    + 	struct checkout lstate, rstate;
    + 	int rc, flags = RUN_GIT_CMD, err = 0;
    +-	struct child_process child = CHILD_PROCESS_INIT;
    + 	const char *helper_argv[] = { "difftool--helper", NULL, NULL, NULL };
    + 	struct hashmap wt_modified, tmp_modified;
    + 	int indices_loaded = 0;
    +@@ builtin/difftool.c: static int run_dir_diff(const char *extcmd, int symlinks, const char *prefix,
    + 	rdir_len = rdir.len;
    + 	wtdir_len = wtdir.len;
    + 
    +-	child.no_stdin = 1;
    +-	child.git_cmd = 1;
    +-	child.use_shell = 0;
    +-	child.clean_on_exit = 1;
    +-	child.dir = prefix;
    +-	child.out = -1;
     -	strvec_pushl(&child.args, "diff", "--raw", "--no-abbrev", "-z",
    --		     NULL);
    --	for (i = 0; i < argc; i++)
    ++	child->no_stdin = 1;
    ++	child->git_cmd = 1;
    ++	child->use_shell = 0;
    ++	child->clean_on_exit = 1;
    ++	child->dir = prefix;
    ++	child->out = -1;
    ++	strvec_pushl(&child->args, "diff", "--raw", "--no-abbrev", "-z",
    + 		     NULL);
    + 	for (i = 0; i < argc; i++)
     -		strvec_push(&child.args, argv[i]);
    -+	child.argv = args->v;
    -+
    - 	if (start_command(&child))
    +-	if (start_command(&child))
    ++		strvec_push(&child->args, argv[i]);
    ++	if (start_command(child))
      		die("could not obtain raw diff");
    - 	fp = xfdopen(child.out, "r");
    -@@ builtin/difftool.c: static int run_dir_diff(const char *extcmd, int symlinks, const char *prefix,
    - 	strbuf_release(&rdir);
    - 	strbuf_release(&wtdir);
    - 	strbuf_release(&buf);
    -+	strvec_clear(args);
    - 
    - 	return ret;
    - }
    +-	fp = xfdopen(child.out, "r");
    ++	fp = xfdopen(child->out, "r");
      
    --static int run_file_diff(int prompt, const char *prefix,
    --			 int argc, const char **argv)
    -+static int run_file_diff(int prompt, const char *prefix, struct strvec *args)
    - {
    --	struct strvec args = STRVEC_INIT;
    --	const char *env[] = {
    --		"GIT_PAGER=", "GIT_EXTERNAL_DIFF=git-difftool--helper", NULL,
    --		NULL
    --	};
    --	int i;
    -+	struct child_process cmd = CHILD_PROCESS_INIT;
    -+	int ret;
    - 
    -+	strvec_pushl(&cmd.env_array, "GIT_PAGER=",
    -+		     "GIT_EXTERNAL_DIFF=git-difftool--helper", NULL);
    - 	if (prompt > 0)
    --		env[2] = "GIT_DIFFTOOL_PROMPT=true";
    -+		strvec_push(&cmd.env_array, "GIT_DIFFTOOL_PROMPT=true");
    - 	else if (!prompt)
    --		env[2] = "GIT_DIFFTOOL_NO_PROMPT=true";
    -+		strvec_push(&cmd.env_array, "GIT_DIFFTOOL_NO_PROMPT=true");
    - 
    -+	cmd.git_cmd = 1;
    -+	cmd.dir = prefix;
    -+	cmd.argv = args->v;
    - 
    --	strvec_push(&args, "diff");
    --	for (i = 0; i < argc; i++)
    --		strvec_push(&args, argv[i]);
    --	return run_command_v_opt_cd_env(args.v, RUN_GIT_CMD, prefix, env);
    -+	ret = run_command(&cmd);
    -+	strvec_clear(args);
    -+	return ret;
    - }
    + 	/* Build index info for left and right sides of the diff */
    + 	i = 0;
    +@@ builtin/difftool.c: static int run_dir_diff(const char *extcmd, int symlinks, const char *prefix,
      
    - int cmd_difftool(int argc, const char **argv, const char *prefix)
    + 	fclose(fp);
    + 	fp = NULL;
    +-	if (finish_command(&child)) {
    ++	if (finish_command(child)) {
    + 		ret = error("error occurred running diff --raw");
    + 		goto finish;
    + 	}
     @@ builtin/difftool.c: int cmd_difftool(int argc, const char **argv, const char *prefix)
      		OPT_ARGUMENT("no-index", &no_index, N_("passed to `diff`")),
      		OPT_END()
      	};
    -+	struct strvec args = STRVEC_INIT;
    ++	struct child_process child = CHILD_PROCESS_INIT;
      
      	git_config(difftool_config, NULL);
      	symlinks = has_symlinks;
     @@ builtin/difftool.c: int cmd_difftool(int argc, const char **argv, const char *prefix)
    - 	 * will invoke a separate instance of 'git-difftool--helper' for
      	 * each file that changed.
      	 */
    -+	strvec_push(&args, "diff");
    -+	if (dir_diff)
    -+		strvec_pushl(&args, "--raw", "--no-abbrev", "-z", NULL);
    -+	strvec_pushv(&args, argv);
    -+
      	if (dir_diff)
     -		return run_dir_diff(extcmd, symlinks, prefix, argc, argv);
    --	return run_file_diff(prompt, prefix, argc, argv);
    -+		return run_dir_diff(extcmd, symlinks, prefix, &args);
    -+	return run_file_diff(prompt, prefix, &args);
    ++		return run_dir_diff(extcmd, symlinks, prefix, argc, argv, &child);
    + 	return run_file_diff(prompt, prefix, argc, argv);
      }
-:  ----------- > 2:  1c2794115c7 difftool: prepare "diff" cmdline in cmd_difftool()
-:  ----------- > 3:  2b093bd71fc difftool: use run_command() API in run_file_diff()
2:  28b43789b11 ! 4:  4fddce0a38d parse-options API: remove OPTION_ARGUMENT feature
    @@ builtin/difftool.c: int cmd_difftool(int argc, const char **argv, const char *pr
     +		OPT_BOOL(0, "no-index", &no_index, N_("passed to `diff`")),
      		OPT_END()
      	};
    - 	struct strvec args = STRVEC_INIT;
    + 	struct child_process child = CHILD_PROCESS_INIT;
     @@ builtin/difftool.c: int cmd_difftool(int argc, const char **argv, const char *prefix)
      	 * each file that changed.
      	 */
    - 	strvec_push(&args, "diff");
    + 	strvec_push(&child.args, "diff");
     +	if (no_index)
    -+		strvec_push(&args, "--no-index");
    ++		strvec_push(&child.args, "--no-index");
      	if (dir_diff)
    - 		strvec_pushl(&args, "--raw", "--no-abbrev", "-z", NULL);
    - 	strvec_pushv(&args, argv);
    + 		strvec_pushl(&child.args, "--raw", "--no-abbrev", "-z", NULL);
    + 	strvec_pushv(&child.args, argv);
     
      ## parse-options.c ##
     @@ parse-options.c: static enum parse_opt_result parse_long_opt(
-- 
2.33.0.999.ga5f89b684e9


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

* [PATCH v2 1/4] difftool: prepare "struct child_process" in cmd_difftool()
  2021-09-13  3:35 ` [PATCH v2 0/4] difftool refactoring + remove OPT_ARGUMENT() macro Ævar Arnfjörð Bjarmason
@ 2021-09-13  3:35   ` Ævar Arnfjörð Bjarmason
  2021-09-13  3:35   ` [PATCH v2 2/4] difftool: prepare "diff" cmdline " Ævar Arnfjörð Bjarmason
                     ` (3 subsequent siblings)
  4 siblings, 0 replies; 17+ messages in thread
From: Ævar Arnfjörð Bjarmason @ 2021-09-13  3:35 UTC (permalink / raw)
  To: git
  Cc: Junio C Hamano, Johannes Schindelin, Jeff King,
	Ævar Arnfjörð Bjarmason

Move the preparation of the "struct child_process" from run_dir_diff()
to its only caller, cmd_difftool(). This is in preparation for
migrating run_file_diff() to using the run_command() API directly, and
to move more of the shared setup of the two to cmd_difftool().

Signed-off-by: Ævar Arnfjörð Bjarmason <avarab@gmail.com>
---
 builtin/difftool.c | 29 +++++++++++++++--------------
 1 file changed, 15 insertions(+), 14 deletions(-)

diff --git a/builtin/difftool.c b/builtin/difftool.c
index 6a9242a8032..9f08a8f3fd2 100644
--- a/builtin/difftool.c
+++ b/builtin/difftool.c
@@ -331,7 +331,8 @@ static int checkout_path(unsigned mode, struct object_id *oid,
 }
 
 static int run_dir_diff(const char *extcmd, int symlinks, const char *prefix,
-			int argc, const char **argv)
+			int argc, const char **argv,
+			struct child_process *child)
 {
 	char tmpdir[PATH_MAX];
 	struct strbuf info = STRBUF_INIT, lpath = STRBUF_INIT;
@@ -352,7 +353,6 @@ static int run_dir_diff(const char *extcmd, int symlinks, const char *prefix,
 	struct index_state wtindex;
 	struct checkout lstate, rstate;
 	int rc, flags = RUN_GIT_CMD, err = 0;
-	struct child_process child = CHILD_PROCESS_INIT;
 	const char *helper_argv[] = { "difftool--helper", NULL, NULL, NULL };
 	struct hashmap wt_modified, tmp_modified;
 	int indices_loaded = 0;
@@ -387,19 +387,19 @@ static int run_dir_diff(const char *extcmd, int symlinks, const char *prefix,
 	rdir_len = rdir.len;
 	wtdir_len = wtdir.len;
 
-	child.no_stdin = 1;
-	child.git_cmd = 1;
-	child.use_shell = 0;
-	child.clean_on_exit = 1;
-	child.dir = prefix;
-	child.out = -1;
-	strvec_pushl(&child.args, "diff", "--raw", "--no-abbrev", "-z",
+	child->no_stdin = 1;
+	child->git_cmd = 1;
+	child->use_shell = 0;
+	child->clean_on_exit = 1;
+	child->dir = prefix;
+	child->out = -1;
+	strvec_pushl(&child->args, "diff", "--raw", "--no-abbrev", "-z",
 		     NULL);
 	for (i = 0; i < argc; i++)
-		strvec_push(&child.args, argv[i]);
-	if (start_command(&child))
+		strvec_push(&child->args, argv[i]);
+	if (start_command(child))
 		die("could not obtain raw diff");
-	fp = xfdopen(child.out, "r");
+	fp = xfdopen(child->out, "r");
 
 	/* Build index info for left and right sides of the diff */
 	i = 0;
@@ -525,7 +525,7 @@ static int run_dir_diff(const char *extcmd, int symlinks, const char *prefix,
 
 	fclose(fp);
 	fp = NULL;
-	if (finish_command(&child)) {
+	if (finish_command(child)) {
 		ret = error("error occurred running diff --raw");
 		goto finish;
 	}
@@ -719,6 +719,7 @@ int cmd_difftool(int argc, const char **argv, const char *prefix)
 		OPT_ARGUMENT("no-index", &no_index, N_("passed to `diff`")),
 		OPT_END()
 	};
+	struct child_process child = CHILD_PROCESS_INIT;
 
 	git_config(difftool_config, NULL);
 	symlinks = has_symlinks;
@@ -769,6 +770,6 @@ int cmd_difftool(int argc, const char **argv, const char *prefix)
 	 * each file that changed.
 	 */
 	if (dir_diff)
-		return run_dir_diff(extcmd, symlinks, prefix, argc, argv);
+		return run_dir_diff(extcmd, symlinks, prefix, argc, argv, &child);
 	return run_file_diff(prompt, prefix, argc, argv);
 }
-- 
2.33.0.999.ga5f89b684e9


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

* [PATCH v2 2/4] difftool: prepare "diff" cmdline in cmd_difftool()
  2021-09-13  3:35 ` [PATCH v2 0/4] difftool refactoring + remove OPT_ARGUMENT() macro Ævar Arnfjörð Bjarmason
  2021-09-13  3:35   ` [PATCH v2 1/4] difftool: prepare "struct child_process" in cmd_difftool() Ævar Arnfjörð Bjarmason
@ 2021-09-13  3:35   ` Ævar Arnfjörð Bjarmason
  2021-09-13  3:35   ` [PATCH v2 3/4] difftool: use run_command() API in run_file_diff() Ævar Arnfjörð Bjarmason
                     ` (2 subsequent siblings)
  4 siblings, 0 replies; 17+ messages in thread
From: Ævar Arnfjörð Bjarmason @ 2021-09-13  3:35 UTC (permalink / raw)
  To: git
  Cc: Junio C Hamano, Johannes Schindelin, Jeff King,
	Ævar Arnfjörð Bjarmason

From: Jeff King <peff@peff.net>

We call into either run_dir_diff() or run_file_diff(), each of which
sets up a child argv starting with "diff" and some hard-coded options
(depending on which mode we're using). Let's extract that logic into the
caller, which will make it easier to modify the options for cases which
affect both functions.

Signed-off-by: Jeff King <peff@peff.net>
Signed-off-by: Ævar Arnfjörð Bjarmason <avarab@gmail.com>
---
 builtin/difftool.c | 15 +++++++--------
 1 file changed, 7 insertions(+), 8 deletions(-)

diff --git a/builtin/difftool.c b/builtin/difftool.c
index 9f08a8f3fd2..f8fcc67640f 100644
--- a/builtin/difftool.c
+++ b/builtin/difftool.c
@@ -331,7 +331,6 @@ static int checkout_path(unsigned mode, struct object_id *oid,
 }
 
 static int run_dir_diff(const char *extcmd, int symlinks, const char *prefix,
-			int argc, const char **argv,
 			struct child_process *child)
 {
 	char tmpdir[PATH_MAX];
@@ -393,10 +392,6 @@ static int run_dir_diff(const char *extcmd, int symlinks, const char *prefix,
 	child->clean_on_exit = 1;
 	child->dir = prefix;
 	child->out = -1;
-	strvec_pushl(&child->args, "diff", "--raw", "--no-abbrev", "-z",
-		     NULL);
-	for (i = 0; i < argc; i++)
-		strvec_push(&child->args, argv[i]);
 	if (start_command(child))
 		die("could not obtain raw diff");
 	fp = xfdopen(child->out, "r");
@@ -683,7 +678,6 @@ static int run_file_diff(int prompt, const char *prefix,
 		env[2] = "GIT_DIFFTOOL_NO_PROMPT=true";
 
 
-	strvec_push(&args, "diff");
 	for (i = 0; i < argc; i++)
 		strvec_push(&args, argv[i]);
 	return run_command_v_opt_cd_env(args.v, RUN_GIT_CMD, prefix, env);
@@ -769,7 +763,12 @@ int cmd_difftool(int argc, const char **argv, const char *prefix)
 	 * will invoke a separate instance of 'git-difftool--helper' for
 	 * each file that changed.
 	 */
+	strvec_push(&child.args, "diff");
+	if (dir_diff)
+		strvec_pushl(&child.args, "--raw", "--no-abbrev", "-z", NULL);
+	strvec_pushv(&child.args, argv);
+
 	if (dir_diff)
-		return run_dir_diff(extcmd, symlinks, prefix, argc, argv, &child);
-	return run_file_diff(prompt, prefix, argc, argv);
+		return run_dir_diff(extcmd, symlinks, prefix, &child);
+	return run_file_diff(prompt, prefix, child.args.nr, child.args.v);
 }
-- 
2.33.0.999.ga5f89b684e9


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

* [PATCH v2 3/4] difftool: use run_command() API in run_file_diff()
  2021-09-13  3:35 ` [PATCH v2 0/4] difftool refactoring + remove OPT_ARGUMENT() macro Ævar Arnfjörð Bjarmason
  2021-09-13  3:35   ` [PATCH v2 1/4] difftool: prepare "struct child_process" in cmd_difftool() Ævar Arnfjörð Bjarmason
  2021-09-13  3:35   ` [PATCH v2 2/4] difftool: prepare "diff" cmdline " Ævar Arnfjörð Bjarmason
@ 2021-09-13  3:35   ` Ævar Arnfjörð Bjarmason
  2021-09-13 18:04     ` Jeff King
  2021-09-13  3:35   ` [PATCH v2 4/4] parse-options API: remove OPTION_ARGUMENT feature Ævar Arnfjörð Bjarmason
  2021-09-13 18:04   ` [PATCH v2 0/4] difftool refactoring + remove OPT_ARGUMENT() macro Jeff King
  4 siblings, 1 reply; 17+ messages in thread
From: Ævar Arnfjörð Bjarmason @ 2021-09-13  3:35 UTC (permalink / raw)
  To: git
  Cc: Junio C Hamano, Johannes Schindelin, Jeff King,
	Ævar Arnfjörð Bjarmason

Change the run_file_diff() function to use the run_command() API
directly, instead of invoking the run_command_v_opt_cd_env() wrapper.

This allows it, like run_dir_diff(), to use the "args" from "struct
strvec", instead of the "const char **argv" passed into
cmd_difftool(). This will be used in the subsequent commit to get rid
of OPT_ARGUMENT() from cmd_difftool().

Signed-off-by: Ævar Arnfjörð Bjarmason <avarab@gmail.com>
---
 builtin/difftool.c | 13 ++++++-------
 1 file changed, 6 insertions(+), 7 deletions(-)

diff --git a/builtin/difftool.c b/builtin/difftool.c
index f8fcc67640f..de2e5545c81 100644
--- a/builtin/difftool.c
+++ b/builtin/difftool.c
@@ -663,24 +663,23 @@ static int run_dir_diff(const char *extcmd, int symlinks, const char *prefix,
 }
 
 static int run_file_diff(int prompt, const char *prefix,
-			 int argc, const char **argv)
+			 struct child_process *child)
 {
-	struct strvec args = STRVEC_INIT;
 	const char *env[] = {
 		"GIT_PAGER=", "GIT_EXTERNAL_DIFF=git-difftool--helper", NULL,
 		NULL
 	};
-	int i;
 
 	if (prompt > 0)
 		env[2] = "GIT_DIFFTOOL_PROMPT=true";
 	else if (!prompt)
 		env[2] = "GIT_DIFFTOOL_NO_PROMPT=true";
 
+	child->git_cmd = 1;
+	child->dir = prefix;
+	strvec_pushv(&child->env_array, env);
 
-	for (i = 0; i < argc; i++)
-		strvec_push(&args, argv[i]);
-	return run_command_v_opt_cd_env(args.v, RUN_GIT_CMD, prefix, env);
+	return run_command(child);
 }
 
 int cmd_difftool(int argc, const char **argv, const char *prefix)
@@ -770,5 +769,5 @@ int cmd_difftool(int argc, const char **argv, const char *prefix)
 
 	if (dir_diff)
 		return run_dir_diff(extcmd, symlinks, prefix, &child);
-	return run_file_diff(prompt, prefix, child.args.nr, child.args.v);
+	return run_file_diff(prompt, prefix, &child);
 }
-- 
2.33.0.999.ga5f89b684e9


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

* [PATCH v2 4/4] parse-options API: remove OPTION_ARGUMENT feature
  2021-09-13  3:35 ` [PATCH v2 0/4] difftool refactoring + remove OPT_ARGUMENT() macro Ævar Arnfjörð Bjarmason
                     ` (2 preceding siblings ...)
  2021-09-13  3:35   ` [PATCH v2 3/4] difftool: use run_command() API in run_file_diff() Ævar Arnfjörð Bjarmason
@ 2021-09-13  3:35   ` Ævar Arnfjörð Bjarmason
  2021-09-13  6:27     ` Junio C Hamano
  2021-09-13 18:04   ` [PATCH v2 0/4] difftool refactoring + remove OPT_ARGUMENT() macro Jeff King
  4 siblings, 1 reply; 17+ messages in thread
From: Ævar Arnfjörð Bjarmason @ 2021-09-13  3:35 UTC (permalink / raw)
  To: git
  Cc: Junio C Hamano, Johannes Schindelin, Jeff King,
	Ævar Arnfjörð Bjarmason

As was noted in 1a85b49b87a (parse-options: make OPT_ARGUMENT() more
useful, 2019-03-14) there's only ever been one user of the
OPT_ARGUMENT(), that user was added in 20de316e334 (difftool: allow
running outside Git worktrees with --no-index, 2019-03-14).

The OPT_ARGUMENT() feature itself was added way back in
580d5bffdea (parse-options: new option type to treat an option-like
parameter as an argument., 2008-03-02), but as discussed in
1a85b49b87a wasn't used until 20de316e334 in 2019.

Now that the preceding commit has migrated this code over to using
"struct strvec" to manage the "args" member of a "struct
child_process", we can just use that directly instead of relying on
OPT_ARGUMENT.

This has a minor change in behavior in that if we'll pass --no-index
we'll now always pass it as the first argument, before we'd pass it in
whatever position the caller did. Preserving this was the real value
of OPT_ARGUMENT(), but as it turns out we didn't need that either. We
can always inject it as the first argument, the other end will parse
it just the same.

Note that we cannot remove the "out" and "cpidx" members of "struct
parse_opt_ctx_t" added in 580d5bffdea, while they were introduced with
OPT_ARGUMENT() we since used them for other things.

Signed-off-by: Ævar Arnfjörð Bjarmason <avarab@gmail.com>
---
 Documentation/technical/api-parse-options.txt |  5 -----
 builtin/difftool.c                            |  4 +++-
 parse-options.c                               | 13 -------------
 parse-options.h                               |  3 ---
 t/helper/test-parse-options.c                 |  1 -
 t/t0040-parse-options.sh                      |  5 -----
 6 files changed, 3 insertions(+), 28 deletions(-)

diff --git a/Documentation/technical/api-parse-options.txt b/Documentation/technical/api-parse-options.txt
index 5a60bbfa7f4..acfd5dc1d8b 100644
--- a/Documentation/technical/api-parse-options.txt
+++ b/Documentation/technical/api-parse-options.txt
@@ -198,11 +198,6 @@ There are some macros to easily define options:
 	The filename will be prefixed by passing the filename along with
 	the prefix argument of `parse_options()` to `prefix_filename()`.
 
-`OPT_ARGUMENT(long, &int_var, description)`::
-	Introduce a long-option argument that will be kept in `argv[]`.
-	If this option was seen, `int_var` will be set to one (except
-	if a `NULL` pointer was passed).
-
 `OPT_NUMBER_CALLBACK(&var, description, func_ptr)`::
 	Recognize numerical options like -123 and feed the integer as
 	if it was an argument to the function given by `func_ptr`.
diff --git a/builtin/difftool.c b/builtin/difftool.c
index de2e5545c81..bb9fe7245a4 100644
--- a/builtin/difftool.c
+++ b/builtin/difftool.c
@@ -709,7 +709,7 @@ int cmd_difftool(int argc, const char **argv, const char *prefix)
 			    "tool returns a non - zero exit code")),
 		OPT_STRING('x', "extcmd", &extcmd, N_("command"),
 			   N_("specify a custom command for viewing diffs")),
-		OPT_ARGUMENT("no-index", &no_index, N_("passed to `diff`")),
+		OPT_BOOL(0, "no-index", &no_index, N_("passed to `diff`")),
 		OPT_END()
 	};
 	struct child_process child = CHILD_PROCESS_INIT;
@@ -763,6 +763,8 @@ int cmd_difftool(int argc, const char **argv, const char *prefix)
 	 * each file that changed.
 	 */
 	strvec_push(&child.args, "diff");
+	if (no_index)
+		strvec_push(&child.args, "--no-index");
 	if (dir_diff)
 		strvec_pushl(&child.args, "--raw", "--no-abbrev", "-z", NULL);
 	strvec_pushv(&child.args, argv);
diff --git a/parse-options.c b/parse-options.c
index 2abff136a17..55c5821b08d 100644
--- a/parse-options.c
+++ b/parse-options.c
@@ -310,19 +310,6 @@ static enum parse_opt_result parse_long_opt(
 again:
 		if (!skip_prefix(arg, long_name, &rest))
 			rest = NULL;
-		if (options->type == OPTION_ARGUMENT) {
-			if (!rest)
-				continue;
-			if (*rest == '=')
-				return error(_("%s takes no value"),
-					     optname(options, flags));
-			if (*rest)
-				continue;
-			if (options->value)
-				*(int *)options->value = options->defval;
-			p->out[p->cpidx++] = arg - 2;
-			return PARSE_OPT_DONE;
-		}
 		if (!rest) {
 			/* abbreviated? */
 			if (!(p->flags & PARSE_OPT_KEEP_UNKNOWN) &&
diff --git a/parse-options.h b/parse-options.h
index a845a9d9527..39d90882548 100644
--- a/parse-options.h
+++ b/parse-options.h
@@ -8,7 +8,6 @@
 enum parse_opt_type {
 	/* special types */
 	OPTION_END,
-	OPTION_ARGUMENT,
 	OPTION_GROUP,
 	OPTION_NUMBER,
 	OPTION_ALIAS,
@@ -155,8 +154,6 @@ struct option {
 #define OPT_INTEGER_F(s, l, v, h, f)     { OPTION_INTEGER, (s), (l), (v), N_("n"), (h), (f) }
 
 #define OPT_END()                   { OPTION_END }
-#define OPT_ARGUMENT(l, v, h)       { OPTION_ARGUMENT, 0, (l), (v), NULL, \
-				      (h), PARSE_OPT_NOARG, NULL, 1 }
 #define OPT_GROUP(h)                { OPTION_GROUP, 0, NULL, NULL, NULL, (h) }
 #define OPT_BIT(s, l, v, h, b)      OPT_BIT_F(s, l, v, h, b, 0)
 #define OPT_BITOP(s, l, v, h, set, clear) { OPTION_BITOP, (s), (l), (v), NULL, (h), \
diff --git a/t/helper/test-parse-options.c b/t/helper/test-parse-options.c
index 2051ce57db7..a282b6ff13e 100644
--- a/t/helper/test-parse-options.c
+++ b/t/helper/test-parse-options.c
@@ -134,7 +134,6 @@ int cmd__parse_options(int argc, const char **argv)
 		OPT_NOOP_NOARG(0, "obsolete"),
 		OPT_STRING_LIST(0, "list", &list, "str", "add str to list"),
 		OPT_GROUP("Magic arguments"),
-		OPT_ARGUMENT("quux", NULL, "means --quux"),
 		OPT_NUMBER_CALLBACK(&integer, "set integer to NUM",
 			number_callback),
 		{ OPTION_COUNTUP, '+', NULL, &boolean, NULL, "same as -b",
diff --git a/t/t0040-parse-options.sh b/t/t0040-parse-options.sh
index ad4746d899a..da310ed29b1 100755
--- a/t/t0040-parse-options.sh
+++ b/t/t0040-parse-options.sh
@@ -37,7 +37,6 @@ String options
     --list <str>          add str to list
 
 Magic arguments
-    --quux                means --quux
     -NUM                  set integer to NUM
     +                     same as -b
     --ambiguous           positive ambiguity
@@ -263,10 +262,6 @@ test_expect_success 'detect possible typos' '
 	test_cmp typo.err output.err
 '
 
-test_expect_success 'keep some options as arguments' '
-	test-tool parse-options --expect="arg 00: --quux" --quux
-'
-
 cat >expect <<\EOF
 Callback: "four", 0
 boolean: 5
-- 
2.33.0.999.ga5f89b684e9


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

* Re: [PATCH v2 4/4] parse-options API: remove OPTION_ARGUMENT feature
  2021-09-13  3:35   ` [PATCH v2 4/4] parse-options API: remove OPTION_ARGUMENT feature Ævar Arnfjörð Bjarmason
@ 2021-09-13  6:27     ` Junio C Hamano
  0 siblings, 0 replies; 17+ messages in thread
From: Junio C Hamano @ 2021-09-13  6:27 UTC (permalink / raw)
  To: Ævar Arnfjörð Bjarmason
  Cc: git, Johannes Schindelin, Jeff King

Ævar Arnfjörð Bjarmason  <avarab@gmail.com> writes:

> Now that the preceding commit has migrated this code over to using
> "struct strvec" to manage the "args" member of a "struct
> child_process", we can just use that directly instead of relying on
> OPT_ARGUMENT.

Nice.

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

* Re: [PATCH v2 3/4] difftool: use run_command() API in run_file_diff()
  2021-09-13  3:35   ` [PATCH v2 3/4] difftool: use run_command() API in run_file_diff() Ævar Arnfjörð Bjarmason
@ 2021-09-13 18:04     ` Jeff King
  2021-09-13 19:13       ` Ævar Arnfjörð Bjarmason
  0 siblings, 1 reply; 17+ messages in thread
From: Jeff King @ 2021-09-13 18:04 UTC (permalink / raw)
  To: Ævar Arnfjörð Bjarmason
  Cc: git, Junio C Hamano, Johannes Schindelin

On Mon, Sep 13, 2021 at 05:35:39AM +0200, Ævar Arnfjörð Bjarmason wrote:

> Change the run_file_diff() function to use the run_command() API
> directly, instead of invoking the run_command_v_opt_cd_env() wrapper.
> 
> This allows it, like run_dir_diff(), to use the "args" from "struct
> strvec", instead of the "const char **argv" passed into
> cmd_difftool(). This will be used in the subsequent commit to get rid
> of OPT_ARGUMENT() from cmd_difftool().

It also fixes the existing leak of its "args" strvec.

I like the general direction here of putting the child_process in the
parent. There's a few opportunities for further cleanup it opens, but
I'm happy whether you want to pursue them or not (I'm also happy to do
them as real patches on top myself, but don't want to de-rail your
series).

>  static int run_file_diff(int prompt, const char *prefix,
> -			 int argc, const char **argv)
> +			 struct child_process *child)
>  {
> -	struct strvec args = STRVEC_INIT;
>  	const char *env[] = {
>  		"GIT_PAGER=", "GIT_EXTERNAL_DIFF=git-difftool--helper", NULL,
>  		NULL
>  	};
> -	int i;
>  
>  	if (prompt > 0)
>  		env[2] = "GIT_DIFFTOOL_PROMPT=true";
>  	else if (!prompt)
>  		env[2] = "GIT_DIFFTOOL_NO_PROMPT=true";

This "save a NULL in env where we might stick something in later" is
ugly. Now that we have a child_process, it might be nicer as:

  strvec_push(&env.args, "GIT_PAGER=");
  strvec_push(&env.args, "GIT_EXTERNAL_DIFF=git-difftool--helper");
  if (prompt > 0)
	strvec_push(&env.args, "GIT_DIFFTOOL_PROMPT=true");
  else if (!prompt)
	strvec_push(&env.args, "GIT_DIFFTOOL_NO_PROMPT=true");

> +	child->git_cmd = 1;
> +	child->dir = prefix;

These are the same in run_dir_diff(). We could do more of the shared
prep of the child_process in the caller. Likewise, we might want to pick
up run_dir_diff()'s no_stdin and clean_on_exit settings (and unsetting
use_shell, but I think that is already pointless; it defaults to false
in the first place, and git_cmd takes precedence over it anyway).

-Peff

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

* Re: [PATCH v2 0/4] difftool refactoring + remove OPT_ARGUMENT() macro
  2021-09-13  3:35 ` [PATCH v2 0/4] difftool refactoring + remove OPT_ARGUMENT() macro Ævar Arnfjörð Bjarmason
                     ` (3 preceding siblings ...)
  2021-09-13  3:35   ` [PATCH v2 4/4] parse-options API: remove OPTION_ARGUMENT feature Ævar Arnfjörð Bjarmason
@ 2021-09-13 18:04   ` Jeff King
  4 siblings, 0 replies; 17+ messages in thread
From: Jeff King @ 2021-09-13 18:04 UTC (permalink / raw)
  To: Ævar Arnfjörð Bjarmason
  Cc: git, Junio C Hamano, Johannes Schindelin

On Mon, Sep 13, 2021 at 05:35:36AM +0200, Ævar Arnfjörð Bjarmason wrote:

> I think this v2 should address the comments Jeff King had in
> https://lore.kernel.org/git/YT6BnnXeAWn8BycF@coredump.intra.peff.net/;
> there's now an amended version of his proposed patch as part of this,
> but I prepended it with another one to prepare the "struct
> child_process" in cmd_difftool().
> 
> Doing so nicely gets around the question of the strvec memory
> management, since we can trust the run-command.c API to do that for
> us, but couldn't in my v1 when we'd copy our own "struct strvec *" to
> its "args".

Thanks for taking my suggestions into account. I like this approach, and
I don't see any bugs. I replied separately to patch 3 with some further
opportunities for cleanup, but with or without them, this is all a
strict improvement.

-Peff

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

* Re: [PATCH v2 3/4] difftool: use run_command() API in run_file_diff()
  2021-09-13 18:04     ` Jeff King
@ 2021-09-13 19:13       ` Ævar Arnfjörð Bjarmason
  2021-09-13 19:27         ` Jeff King
  0 siblings, 1 reply; 17+ messages in thread
From: Ævar Arnfjörð Bjarmason @ 2021-09-13 19:13 UTC (permalink / raw)
  To: Jeff King; +Cc: git, Junio C Hamano, Johannes Schindelin


On Mon, Sep 13 2021, Jeff King wrote:

> On Mon, Sep 13, 2021 at 05:35:39AM +0200, Ævar Arnfjörð Bjarmason wrote:
>
>> Change the run_file_diff() function to use the run_command() API
>> directly, instead of invoking the run_command_v_opt_cd_env() wrapper.
>> 
>> This allows it, like run_dir_diff(), to use the "args" from "struct
>> strvec", instead of the "const char **argv" passed into
>> cmd_difftool(). This will be used in the subsequent commit to get rid
>> of OPT_ARGUMENT() from cmd_difftool().
>
> It also fixes the existing leak of its "args" strvec.
>
> I like the general direction here of putting the child_process in the
> parent. There's a few opportunities for further cleanup it opens, but
> I'm happy whether you want to pursue them or not (I'm also happy to do
> them as real patches on top myself, but don't want to de-rail your
> series).

*nod*

>>  static int run_file_diff(int prompt, const char *prefix,
>> -			 int argc, const char **argv)
>> +			 struct child_process *child)
>>  {
>> -	struct strvec args = STRVEC_INIT;
>>  	const char *env[] = {
>>  		"GIT_PAGER=", "GIT_EXTERNAL_DIFF=git-difftool--helper", NULL,
>>  		NULL
>>  	};
>> -	int i;
>>  
>>  	if (prompt > 0)
>>  		env[2] = "GIT_DIFFTOOL_PROMPT=true";
>>  	else if (!prompt)
>>  		env[2] = "GIT_DIFFTOOL_NO_PROMPT=true";
>
> This "save a NULL in env where we might stick something in later" is
> ugly. Now that we have a child_process, it might be nicer as:
>
>   strvec_push(&env.args, "GIT_PAGER=");
>   strvec_push(&env.args, "GIT_EXTERNAL_DIFF=git-difftool--helper");
>   if (prompt > 0)
> 	strvec_push(&env.args, "GIT_DIFFTOOL_PROMPT=true");
>   else if (!prompt)
> 	strvec_push(&env.args, "GIT_DIFFTOOL_NO_PROMPT=true");

Yes, I had something like that in the earlier round, but decided to try
to keep the diff minimal, churn and all that. So it would be nice, but
let's do it as some later cleanup if someone's interested.

>> +	child->git_cmd = 1;
>> +	child->dir = prefix;
>
> These are the same in run_dir_diff(). We could do more of the shared
> prep of the child_process in the caller. Likewise, we might want to pick
> up run_dir_diff()'s no_stdin and clean_on_exit settings (and unsetting
> use_shell, but I think that is already pointless; it defaults to false
> in the first place, and git_cmd takes precedence over it anyway).

*nod*, but can be left for some other time.

Aside: I did most of that removal of "argv" from the child_process
struct you suggested, it's in
avar/run-command-use-less-argv-use-args-instead in my repo if you're
curious / wanted to pick any of that up. I won't be submitting it any
time soon for the reasons noted upthread.

In any case it has rather large semantic and textual conflicts with the
outstanding hook.[ch] topic, but with that branch + that applied + a few
changes on top I was able to get the whole tree compiling & testing
successfully earlier.

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

* Re: [PATCH v2 3/4] difftool: use run_command() API in run_file_diff()
  2021-09-13 19:13       ` Ævar Arnfjörð Bjarmason
@ 2021-09-13 19:27         ` Jeff King
  0 siblings, 0 replies; 17+ messages in thread
From: Jeff King @ 2021-09-13 19:27 UTC (permalink / raw)
  To: Ævar Arnfjörð Bjarmason
  Cc: git, Junio C Hamano, Johannes Schindelin

On Mon, Sep 13, 2021 at 09:13:43PM +0200, Ævar Arnfjörð Bjarmason wrote:

> Yes, I had something like that in the earlier round, but decided to try
> to keep the diff minimal, churn and all that. So it would be nice, but
> let's do it as some later cleanup if someone's interested.

OK, let's leave it for now, then.

> Aside: I did most of that removal of "argv" from the child_process
> struct you suggested, it's in
> avar/run-command-use-less-argv-use-args-instead in my repo if you're
> curious / wanted to pick any of that up. I won't be submitting it any
> time soon for the reasons noted upthread.

Yeah, it's rather far-reaching, which is why I didn't do a
mass-conversion when I introduced "args" in c460c0ecdc (run-command:
store an optional argv_array, 2014-05-15). My plan was to clean up spots
over time as we touched them, but of course that's quite a slow process.

Mostly I just didn't want to see any sites going the _other_ direction,
as in your original version of the series. :)

I'm quite happy with what you ended up with here.

-Peff

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

end of thread, other threads:[~2021-09-13 19:27 UTC | newest]

Thread overview: 17+ messages (download: mbox.gz / follow: Atom feed)
-- links below jump to the message on this page --
2021-09-11 18:21 [PATCH 0/2] parse-options.c: remove OPT_ARGUMENT Ævar Arnfjörð Bjarmason
2021-09-11 18:21 ` [PATCH 1/2] difftool: use "struct strvec" API in run_{dir,file}_diff() Ævar Arnfjörð Bjarmason
2021-09-12 22:39   ` Jeff King
2021-09-12 22:41     ` Jeff King
2021-09-13  0:10     ` Junio C Hamano
2021-09-11 18:21 ` [PATCH 2/2] parse-options API: remove OPTION_ARGUMENT feature Ævar Arnfjörð Bjarmason
2021-09-12 22:43   ` Jeff King
2021-09-13  3:35 ` [PATCH v2 0/4] difftool refactoring + remove OPT_ARGUMENT() macro Ævar Arnfjörð Bjarmason
2021-09-13  3:35   ` [PATCH v2 1/4] difftool: prepare "struct child_process" in cmd_difftool() Ævar Arnfjörð Bjarmason
2021-09-13  3:35   ` [PATCH v2 2/4] difftool: prepare "diff" cmdline " Ævar Arnfjörð Bjarmason
2021-09-13  3:35   ` [PATCH v2 3/4] difftool: use run_command() API in run_file_diff() Ævar Arnfjörð Bjarmason
2021-09-13 18:04     ` Jeff King
2021-09-13 19:13       ` Ævar Arnfjörð Bjarmason
2021-09-13 19:27         ` Jeff King
2021-09-13  3:35   ` [PATCH v2 4/4] parse-options API: remove OPTION_ARGUMENT feature Ævar Arnfjörð Bjarmason
2021-09-13  6:27     ` Junio C Hamano
2021-09-13 18:04   ` [PATCH v2 0/4] difftool refactoring + remove OPT_ARGUMENT() macro 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).