git@vger.kernel.org list mirror (unofficial, one of many)
 help / color / mirror / code / Atom feed
* [GSoC][PATCH v6] parse-options: do not show usage upon invalid option value
@ 2018-03-20 17:50 Paul-Sebastian Ungureanu
  2018-03-20 18:36 ` Eric Sunshine
  2018-03-21 18:22 ` Junio C Hamano
  0 siblings, 2 replies; 4+ messages in thread
From: Paul-Sebastian Ungureanu @ 2018-03-20 17:50 UTC (permalink / raw)
  To: git; +Cc: Paul-Sebastian Ungureanu

Usually, the usage should be shown only if the user does not know what
options are available. If the user specifies an invalid value, the user
is already aware of the available options. In this case, there is no
point in displaying the usage anymore.

This patch applies to "git tag --contains", "git branch --contains",
"git branch --points-at", "git for-each-ref --contains" and many more.

Signed-off-by: Paul-Sebastian Ungureanu <ungureanupaulsebastian@gmail.com>
---
 builtin/blame.c               |   1 +
 builtin/shortlog.c            |   1 +
 builtin/update-index.c        |   1 +
 parse-options.c               |  20 ++++---
 parse-options.h               |   1 +
 t/t0040-parse-options.sh      |   2 +-
 t/t0041-usage.sh              | 107 ++++++++++++++++++++++++++++++++++
 t/t3404-rebase-interactive.sh |   6 +-
 8 files changed, 125 insertions(+), 14 deletions(-)
 create mode 100755 t/t0041-usage.sh

diff --git a/builtin/blame.c b/builtin/blame.c
index 9dcb367b9..e8c6a4d6a 100644
--- a/builtin/blame.c
+++ b/builtin/blame.c
@@ -729,6 +729,7 @@ int cmd_blame(int argc, const char **argv, const char *prefix)
 	for (;;) {
 		switch (parse_options_step(&ctx, options, blame_opt_usage)) {
 		case PARSE_OPT_HELP:
+		case PARSE_OPT_ERROR:
 			exit(129);
 		case PARSE_OPT_DONE:
 			if (ctx.argv[0])
diff --git a/builtin/shortlog.c b/builtin/shortlog.c
index e29875b84..be4df6a03 100644
--- a/builtin/shortlog.c
+++ b/builtin/shortlog.c
@@ -283,6 +283,7 @@ int cmd_shortlog(int argc, const char **argv, const char *prefix)
 	for (;;) {
 		switch (parse_options_step(&ctx, options, shortlog_usage)) {
 		case PARSE_OPT_HELP:
+		case PARSE_OPT_ERROR:
 			exit(129);
 		case PARSE_OPT_DONE:
 			goto parse_done;
diff --git a/builtin/update-index.c b/builtin/update-index.c
index 58d1c2d28..34adf55a7 100644
--- a/builtin/update-index.c
+++ b/builtin/update-index.c
@@ -1059,6 +1059,7 @@ int cmd_update_index(int argc, const char **argv, const char *prefix)
 			break;
 		switch (parseopt_state) {
 		case PARSE_OPT_HELP:
+		case PARSE_OPT_ERROR:
 			exit(129);
 		case PARSE_OPT_NON_OPTION:
 		case PARSE_OPT_DONE:
diff --git a/parse-options.c b/parse-options.c
index d02eb8b01..47c09a82b 100644
--- a/parse-options.c
+++ b/parse-options.c
@@ -317,14 +317,16 @@ static int parse_long_opt(struct parse_opt_ctx_t *p, const char *arg,
 		return get_value(p, options, all_opts, flags ^ opt_flags);
 	}
 
-	if (ambiguous_option)
-		return error("Ambiguous option: %s "
+	if (ambiguous_option) {
+		error("Ambiguous option: %s "
 			"(could be --%s%s or --%s%s)",
 			arg,
 			(ambiguous_flags & OPT_UNSET) ?  "no-" : "",
 			ambiguous_option->long_name,
 			(abbrev_flags & OPT_UNSET) ?  "no-" : "",
 			abbrev_option->long_name);
+		return -3;
+	}
 	if (abbrev_option)
 		return get_value(p, abbrev_option, all_opts, abbrev_flags);
 	return -2;
@@ -434,7 +436,6 @@ int parse_options_step(struct parse_opt_ctx_t *ctx,
 		       const char * const usagestr[])
 {
 	int internal_help = !(ctx->flags & PARSE_OPT_NO_INTERNAL_HELP);
-	int err = 0;
 
 	/* we must reset ->opt, unknown short option leave it dangling */
 	ctx->opt = NULL;
@@ -459,7 +460,7 @@ int parse_options_step(struct parse_opt_ctx_t *ctx,
 			ctx->opt = arg + 1;
 			switch (parse_short_opt(ctx, options)) {
 			case -1:
-				goto show_usage_error;
+				return PARSE_OPT_ERROR;
 			case -2:
 				if (ctx->opt)
 					check_typos(arg + 1, options);
@@ -472,7 +473,7 @@ int parse_options_step(struct parse_opt_ctx_t *ctx,
 			while (ctx->opt) {
 				switch (parse_short_opt(ctx, options)) {
 				case -1:
-					goto show_usage_error;
+					return PARSE_OPT_ERROR;
 				case -2:
 					if (internal_help && *ctx->opt == 'h')
 						goto show_usage;
@@ -504,9 +505,11 @@ int parse_options_step(struct parse_opt_ctx_t *ctx,
 			goto show_usage;
 		switch (parse_long_opt(ctx, arg + 2, options)) {
 		case -1:
-			goto show_usage_error;
+			return PARSE_OPT_ERROR;
 		case -2:
 			goto unknown;
+		case -3:
+			goto show_usage;
 		}
 		continue;
 unknown:
@@ -517,10 +520,8 @@ int parse_options_step(struct parse_opt_ctx_t *ctx,
 	}
 	return PARSE_OPT_DONE;
 
- show_usage_error:
-	err = 1;
  show_usage:
-	return usage_with_options_internal(ctx, usagestr, options, 0, err);
+	return usage_with_options_internal(ctx, usagestr, options, 0, 0);
 }
 
 int parse_options_end(struct parse_opt_ctx_t *ctx)
@@ -539,6 +540,7 @@ int parse_options(int argc, const char **argv, const char *prefix,
 	parse_options_start(&ctx, argc, argv, prefix, options, flags);
 	switch (parse_options_step(&ctx, options, usagestr)) {
 	case PARSE_OPT_HELP:
+	case PARSE_OPT_ERROR:
 		exit(129);
 	case PARSE_OPT_NON_OPTION:
 	case PARSE_OPT_DONE:
diff --git a/parse-options.h b/parse-options.h
index af711227a..c77bb3b4f 100644
--- a/parse-options.h
+++ b/parse-options.h
@@ -188,6 +188,7 @@ enum {
 	PARSE_OPT_HELP = -1,
 	PARSE_OPT_DONE,
 	PARSE_OPT_NON_OPTION,
+	PARSE_OPT_ERROR,
 	PARSE_OPT_UNKNOWN
 };
 
diff --git a/t/t0040-parse-options.sh b/t/t0040-parse-options.sh
index 0c2fc81d7..04d474c84 100755
--- a/t/t0040-parse-options.sh
+++ b/t/t0040-parse-options.sh
@@ -291,7 +291,7 @@ test_expect_success 'OPT_CALLBACK() and OPT_BIT() work' '
 test_expect_success 'OPT_CALLBACK() and callback errors work' '
 	test_must_fail test-parse-options --no-length >output 2>output.err &&
 	test_i18ncmp expect output &&
-	test_i18ncmp expect.err output.err
+	test_must_be_empty output.err
 '
 
 cat >expect <<\EOF
diff --git a/t/t0041-usage.sh b/t/t0041-usage.sh
new file mode 100755
index 000000000..ac96bc3b9
--- /dev/null
+++ b/t/t0041-usage.sh
@@ -0,0 +1,107 @@
+#!/bin/sh
+
+test_description='Test commands behavior when given invalid argument value'
+
+. ./test-lib.sh
+
+test_expect_success 'setup ' '
+	test_commit "v1.0"
+'
+
+test_expect_success 'tag --contains <existent_tag>' '
+	git tag --contains "v1.0" 1>actual 2>actual.err &&
+	grep "v1.0" actual &&
+	test_line_count = 0 actual.err
+'
+
+test_expect_success 'tag --contains <inexistent_tag>' '
+	test_must_fail git tag --contains "notag" 1>actual 2>actual.err &&
+	test_line_count = 0 actual &&
+	test_i18ngrep "error" actual.err &&
+	test_must_fail test_i18ngrep "usage" actual.err
+'
+
+test_expect_success 'tag --no-contains <existent_tag>' '
+	git tag --no-contains "v1.0" 1>actual 2>actual.err  &&
+	test_line_count = 0 actual &&
+	test_line_count = 0 actual.err
+'
+
+test_expect_success 'tag --no-contains <inexistent_tag>' '
+	test_must_fail git tag --no-contains "notag" 1>actual 2>actual.err &&
+	test_line_count = 0 actual &&
+	test_i18ngrep "error" actual.err &&
+	test_must_fail test_i18ngrep "usage" actual.err
+'
+
+test_expect_success 'tag usage error' '
+	test_must_fail git tag --noopt 1>actual 2>actual.err &&
+	test_line_count = 0 actual &&
+	test_i18ngrep "usage" actual.err
+'
+
+test_expect_success 'branch --contains <existent_commit>' '
+	git branch --contains "master" 1>actual 2>actual.err &&
+	test_i18ngrep "master" actual &&
+	test_line_count = 0 actual.err
+'
+
+test_expect_success 'branch --contains <inexistent_commit>' '
+	test_must_fail git branch --no-contains "nocommit" 1>actual 2>actual.err &&
+	test_line_count = 0 actual &&
+	test_i18ngrep "error" actual.err &&
+	test_must_fail test_i18ngrep "usage" actual.err
+'
+
+test_expect_success 'branch --no-contains <existent_commit>' '
+	git branch --no-contains "master" 1>actual 2>actual.err &&
+	test_line_count = 0 actual &&
+	test_line_count = 0 actual.err
+'
+
+test_expect_success 'branch --no-contains <inexistent_commit>' '
+	test_must_fail git branch --no-contains "nocommit" 1>actual 2>actual.err &&
+	test_line_count = 0 actual &&
+	test_i18ngrep "error" actual.err &&
+	test_must_fail test_i18ngrep "usage" actual.err
+'
+
+test_expect_success 'branch usage error' '
+	test_must_fail git branch --noopt 1>actual 2>actual.err &&
+	test_line_count = 0 actual &&
+	test_i18ngrep "usage" actual.err
+'
+
+test_expect_success 'for-each-ref --contains <existent_object>' '
+	git for-each-ref --contains "master" 1>actual 2>actual.err &&
+	test_line_count = 2 actual &&
+	test_line_count = 0 actual.err
+'
+
+test_expect_success 'for-each-ref --contains <inexistent_object>' '
+	test_must_fail git for-each-ref --no-contains "noobject" 1>actual 2>actual.err &&
+	test_line_count = 0 actual &&
+	test_i18ngrep "error" actual.err &&
+	test_must_fail test_i18ngrep "usage" actual.err
+'
+
+test_expect_success 'for-each-ref --no-contains <existent_object>' '
+	git for-each-ref --no-contains "master" 1>actual 2>actual.err &&
+	test_line_count = 0 actual &&
+	test_line_count = 0 actual.err
+'
+
+test_expect_success 'for-each-ref --no-contains <inexistent_object>' '
+	test_must_fail git for-each-ref --no-contains "noobject" 1>actual 2>actual.err &&
+	test_line_count = 0 actual &&
+	test_i18ngrep "error" actual.err &&
+	test_must_fail test_i18ngrep "usage" actual.err
+'
+
+test_expect_success 'for-each-ref usage error' '
+	test_must_fail git for-each-ref --noopt 1>actual 2>actual.err &&
+	test_line_count = 0 actual &&
+	test_i18ngrep "usage" actual.err
+'
+
+test_done
diff --git a/t/t3404-rebase-interactive.sh b/t/t3404-rebase-interactive.sh
index ef2887bd8..cac8b2bd8 100755
--- a/t/t3404-rebase-interactive.sh
+++ b/t/t3404-rebase-interactive.sh
@@ -919,10 +919,8 @@ test_expect_success 'rebase --exec works without -i ' '
 test_expect_success 'rebase -i --exec without <CMD>' '
 	git reset --hard execute &&
 	set_fake_editor &&
-	test_must_fail git rebase -i --exec 2>tmp &&
-	sed -e "1d" tmp >actual &&
-	test_must_fail git rebase -h >expected &&
-	test_cmp expected actual &&
+	test_must_fail git rebase -i --exec 2>actual &&
+	test_i18ngrep "requires a value" actual &&
 	git checkout master
 '
 
-- 
2.16.2.346.g16307f54f.dirty


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

* Re: [GSoC][PATCH v6] parse-options: do not show usage upon invalid option value
  2018-03-20 17:50 [GSoC][PATCH v6] parse-options: do not show usage upon invalid option value Paul-Sebastian Ungureanu
@ 2018-03-20 18:36 ` Eric Sunshine
  2018-03-22 18:34   ` Paul-Sebastian Ungureanu
  2018-03-21 18:22 ` Junio C Hamano
  1 sibling, 1 reply; 4+ messages in thread
From: Eric Sunshine @ 2018-03-20 18:36 UTC (permalink / raw)
  To: Paul-Sebastian Ungureanu; +Cc: Git List

On Tue, Mar 20, 2018 at 1:50 PM, Paul-Sebastian Ungureanu
<ungureanupaulsebastian@gmail.com> wrote:
> Usually, the usage should be shown only if the user does not know what
> options are available. If the user specifies an invalid value, the user
> is already aware of the available options. In this case, there is no
> point in displaying the usage anymore.
>
> This patch applies to "git tag --contains", "git branch --contains",
> "git branch --points-at", "git for-each-ref --contains" and many more.
>
> Signed-off-by: Paul-Sebastian Ungureanu <ungureanupaulsebastian@gmail.com>
> ---

As this is a very active mailing list, with reviewers poring over many
(sometimes dozens of) patches each day, it is easy for a reviewer to
forget exact details of each individual submission and review comment.
As a patch contributor, you can help ease reviewers' burden by adding
commentary to your submission here, below the "---" line following
your sign-off. In particular, reviewers find it very helpful when you:

* describe in some detail what changed since the previous version of
the patch, showing that you understood and took into consideration
each of the review comments from the previous iteration

* a link, like this[1], pointing at the previous round (and perhaps
further back) so reviewers can refresh their memories about issues
raised previously; this also helps people wanting to review this round
who were not involved in earlier rounds

[1]: https://public-inbox.org/git/20180319185436.14309-1-ungureanupaulsebastian@gmail.com/

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

* Re: [GSoC][PATCH v6] parse-options: do not show usage upon invalid option value
  2018-03-20 17:50 [GSoC][PATCH v6] parse-options: do not show usage upon invalid option value Paul-Sebastian Ungureanu
  2018-03-20 18:36 ` Eric Sunshine
@ 2018-03-21 18:22 ` Junio C Hamano
  1 sibling, 0 replies; 4+ messages in thread
From: Junio C Hamano @ 2018-03-21 18:22 UTC (permalink / raw)
  To: Paul-Sebastian Ungureanu; +Cc: git

Paul-Sebastian Ungureanu <ungureanupaulsebastian@gmail.com> writes:

> diff --git a/t/t0041-usage.sh b/t/t0041-usage.sh
> new file mode 100755
> index 000000000..ac96bc3b9
> --- /dev/null
> +++ b/t/t0041-usage.sh
> @@ -0,0 +1,107 @@
> +#!/bin/sh
> +
> +test_description='Test commands behavior when given invalid argument value'
> +
> +. ./test-lib.sh
> +
> +test_expect_success 'setup ' '
> +	test_commit "v1.0"
> +'
> +
> +test_expect_success 'tag --contains <existent_tag>' '
> +	git tag --contains "v1.0" 1>actual 2>actual.err &&

It is not wrong per-se, but >redirection without a number redirects
fd#1, so "1>actual" is an unusual way to spell ">actual".

> +	grep "v1.0" actual &&
> +	test_line_count = 0 actual.err
> +'
> +
> +test_expect_success 'tag --contains <inexistent_tag>' '
> +	test_must_fail git tag --contains "notag" 1>actual 2>actual.err &&
> +	test_line_count = 0 actual &&
> +	test_i18ngrep "error" actual.err &&
> +	test_must_fail test_i18ngrep "usage" actual.err

test_must_fail mustn't be used like that for two reasons

 - It is to be used for "git" stuff, because it knows failing with
   segfault and other failure modes are _wrong_ and should not be
   happy even if the command "fail"ed.  We however do not expect
   commands that are not git (e.g. test_i18ngrep) to require special
   casing of the failure modes.

 - test_i18ngrep pretends to always "have found match" when running
   under GETTEXT_POISON build, so it will pretend that usage exists
   in actual.error.  test_must_fail will then say "oops, the string
   'usage' shouldn't appear in the output but it did", which is not
   what you want.

Perhaps

	test_i18ngrep ! "usage" actual.err

is what you want to say here instead.

In any case, the tests got a lot cleaner compared to the previous
round, and I feel that this patch is "getting there" ;-)

Thanks for working on it.

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

* Re: [GSoC][PATCH v6] parse-options: do not show usage upon invalid option value
  2018-03-20 18:36 ` Eric Sunshine
@ 2018-03-22 18:34   ` Paul-Sebastian Ungureanu
  0 siblings, 0 replies; 4+ messages in thread
From: Paul-Sebastian Ungureanu @ 2018-03-22 18:34 UTC (permalink / raw)
  To: Eric Sunshine; +Cc: Git List

Hi,

Thank you a lot for your advice! I will keep in mind your words next
time I will send a patch. 

Best regards,
Paul Ungurenanu

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

end of thread, other threads:[~2018-03-22 18:34 UTC | newest]

Thread overview: 4+ messages (download: mbox.gz / follow: Atom feed)
-- links below jump to the message on this page --
2018-03-20 17:50 [GSoC][PATCH v6] parse-options: do not show usage upon invalid option value Paul-Sebastian Ungureanu
2018-03-20 18:36 ` Eric Sunshine
2018-03-22 18:34   ` Paul-Sebastian Ungureanu
2018-03-21 18:22 ` Junio C Hamano

git@vger.kernel.org list mirror (unofficial, one of many)

This inbox may be cloned and mirrored by anyone:

	git clone --mirror https://public-inbox.org/git
	git clone --mirror http://ou63pmih66umazou.onion/git
	git clone --mirror http://czquwvybam4bgbro.onion/git
	git clone --mirror http://hjrcffqmbrq6wope.onion/git

	# If you have public-inbox 1.1+ installed, you may
	# initialize and index your mirror using the following commands:
	public-inbox-init -V1 git git/ https://public-inbox.org/git \
		git@vger.kernel.org
	public-inbox-index git

Example config snippet for mirrors.
Newsgroups are available over NNTP:
	nntp://news.public-inbox.org/inbox.comp.version-control.git
	nntp://7fh6tueqddpjyxjmgtdiueylzoqt6pt7hec3pukyptlmohoowvhde4yd.onion/inbox.comp.version-control.git
	nntp://ie5yzdi7fg72h7s4sdcztq5evakq23rdt33mfyfcddc5u3ndnw24ogqd.onion/inbox.comp.version-control.git
	nntp://4uok3hntl7oi7b4uf4rtfwefqeexfzil2w6kgk2jn5z2f764irre7byd.onion/inbox.comp.version-control.git
	nntp://news.gmane.io/gmane.comp.version-control.git
 note: .onion URLs require Tor: https://www.torproject.org/

code repositories for project(s) associated with this inbox:

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

AGPL code for this site: git clone https://public-inbox.org/public-inbox.git