diff mbox series

[RFC,v3,5/6] parse-options: parse into argv_array

Message ID 20200728222455.3023400-6-emilyshaffer@google.com (mailing list archive)
State New, archived
Headers show
Series propose config-based hooks | expand

Commit Message

Emily Shaffer July 28, 2020, 10:24 p.m. UTC
parse-options already knows how to read into a string_list, and it knows
how to read into an argv_array as a passthrough (that is, including the
argument as well as its value). string_list and argv_array serve similar
purposes but are somewhat painful to convert between; so, let's teach
parse-options to read values of string arguments directly into an
argv_array without preserving the argument name.

This is useful if collecting generic arguments to pass through to
another command, for example, 'git hook run --arg "--quiet" --arg
"--format=pretty" some-hook'. The resulting argv_array would contain
{ "--quiet", "--format=pretty" }.

The implementation is based on that of OPT_STRING_LIST.

Signed-off-by: Emily Shaffer <emilyshaffer@google.com>
---
 Documentation/technical/api-parse-options.txt |  5 +++++
 parse-options-cb.c                            | 16 ++++++++++++++++
 parse-options.h                               |  4 ++++
 3 files changed, 25 insertions(+)

Comments

Junio C Hamano July 29, 2020, 7:33 p.m. UTC | #1
Emily Shaffer <emilyshaffer@google.com> writes:

> parse-options already knows how to read into a string_list, and it knows
> how to read into an argv_array as a passthrough (that is, including the
> argument as well as its value). string_list and argv_array serve similar
> purposes but are somewhat painful to convert between; so, let's teach
> parse-options to read values of string arguments directly into an
> argv_array without preserving the argument name.
>
> This is useful if collecting generic arguments to pass through to
> another command, for example, 'git hook run --arg "--quiet" --arg
> "--format=pretty" some-hook'. The resulting argv_array would contain
> { "--quiet", "--format=pretty" }.
>
> The implementation is based on that of OPT_STRING_LIST.

Be it argv_array or strvec, I think this is a useful thing to do.

I grepped for the users of OPT_STRING_LIST() to see if some of them
are better served by this, but none of them stood out as candidates
that are particularly good match.

> +int parse_opt_argv_array(const struct option *opt, const char *arg, int unset)
> +{
> +	struct argv_array *v = opt->value;
> +
> +	if (unset) {
> +		argv_array_clear(v);
> +		return 0;
> +	}
> +
> +	if (!arg)
> +		return -1;

I think the calling parse_options() loop would catch this negative
return and raise an error, but is it better for this code to stay
silent or would it be better to say that opt->long_name/short_name 
is not a boolean?

> +	argv_array_push(v, arg);
> +	return 0;
> +}
Junio C Hamano July 30, 2020, 11:41 p.m. UTC | #2
Junio C Hamano <gitster@pobox.com> writes:

> Be it argv_array or strvec, I think this is a useful thing to do.
>
> I grepped for the users of OPT_STRING_LIST() to see if some of them
> are better served by this, but none of them stood out as candidates
> that are particularly good match.
>
>> +int parse_opt_argv_array(const struct option *opt, const char *arg, int unset)
>> +{
>> +	struct argv_array *v = opt->value;
>> +
>> +	if (unset) {
>> +		argv_array_clear(v);
>> +		return 0;
>> +	}
>> +
>> +	if (!arg)
>> +		return -1;
>
> I think the calling parse_options() loop would catch this negative
> return and raise an error, but is it better for this code to stay
> silent or would it be better to say that opt->long_name/short_name 
> is not a boolean?

I am still waiting for this to be answered, but I queued the whole
topic, these last two steps included, just to see how bad adjusting
to the strvec API migration would be.  It wasn't too bad.

I would not recommend you, or other contributors who use argv-array
API in their topics, to build on top of jk/strvec, not just yet, as
I expect it to go through at least one more reroll to update the
details.

Thanks.
diff mbox series

Patch

diff --git a/Documentation/technical/api-parse-options.txt b/Documentation/technical/api-parse-options.txt
index 2e2e7c10c6..1e97343338 100644
--- a/Documentation/technical/api-parse-options.txt
+++ b/Documentation/technical/api-parse-options.txt
@@ -173,6 +173,11 @@  There are some macros to easily define options:
 	The string argument is stored as an element in `string_list`.
 	Use of `--no-option` will clear the list of preceding values.
 
+`OPT_ARGV_ARRAY(short, long, &struct argv_array, arg_str, description)`::
+	Introduce an option with a string argument.
+	The string argument is stored as an element in `argv_array`.
+	Use of `--no-option` will clear the list of preceding values.
+
 `OPT_INTEGER(short, long, &int_var, description)`::
 	Introduce an option with integer argument.
 	The integer is put into `int_var`.
diff --git a/parse-options-cb.c b/parse-options-cb.c
index 86cd393013..94c2dd397a 100644
--- a/parse-options-cb.c
+++ b/parse-options-cb.c
@@ -205,6 +205,22 @@  int parse_opt_string_list(const struct option *opt, const char *arg, int unset)
 	return 0;
 }
 
+int parse_opt_argv_array(const struct option *opt, const char *arg, int unset)
+{
+	struct argv_array *v = opt->value;
+
+	if (unset) {
+		argv_array_clear(v);
+		return 0;
+	}
+
+	if (!arg)
+		return -1;
+
+	argv_array_push(v, arg);
+	return 0;
+}
+
 int parse_opt_noop_cb(const struct option *opt, const char *arg, int unset)
 {
 	return 0;
diff --git a/parse-options.h b/parse-options.h
index 46af942093..e2e2de75c8 100644
--- a/parse-options.h
+++ b/parse-options.h
@@ -177,6 +177,9 @@  struct option {
 #define OPT_STRING_LIST(s, l, v, a, h) \
 				    { OPTION_CALLBACK, (s), (l), (v), (a), \
 				      (h), 0, &parse_opt_string_list }
+#define OPT_ARGV_ARRAY(s, l, v, a, h) \
+				    { OPTION_CALLBACK, (s), (l), (v), (a), \
+				      (h), 0, &parse_opt_argv_array }
 #define OPT_UYN(s, l, v, h)         { OPTION_CALLBACK, (s), (l), (v), NULL, \
 				      (h), PARSE_OPT_NOARG, &parse_opt_tertiary }
 #define OPT_EXPIRY_DATE(s, l, v, h) \
@@ -296,6 +299,7 @@  int parse_opt_commits(const struct option *, const char *, int);
 int parse_opt_commit(const struct option *, const char *, int);
 int parse_opt_tertiary(const struct option *, const char *, int);
 int parse_opt_string_list(const struct option *, const char *, int);
+int parse_opt_argv_array(const struct option *, const char *, int);
 int parse_opt_noop_cb(const struct option *, const char *, int);
 enum parse_opt_result parse_opt_unknown_cb(struct parse_opt_ctx_t *ctx,
 					   const struct option *,