Add a new core.abbreviatedOptions which corresponds to the newly added GIT_TEST_DISALLOW_ABBREVIATED_OPTIONS test mode. This allows e.g. script authors to enact the same sort of paranoia about option abbreviation as our own test suite now uses by default. I'm renaming GIT_TEST_DISALLOW_ABBREVIATED_OPTIONS to GIT_TEST_ABBREVIATED_OPTIONS for consistency with the new configuration variable, and I've picked the shorter core.abbreviatedOptions instead of core.disallowAbbreviatedOptions because it's easier to reason about a variable that's true by default than about one that has a negation in its name. While I'm at it, factor out the check for the environment variable into a parse_options_config() which similar to the code added in 62c23938fa ("tests: add a special setup where rebase.useBuiltin is off", 2018-11-14) will first check the environment variable, and then the configuration. Using git_env_bool() means it's a bit of a pain to distinguish between the case where GIT_TEST_ABBREVIATED_OPTIONS is set to "true" or "false" v.s. being empty, hence the test_when_finished/export/sane_unset dance in the test that's being added, but I think that's more sane than introducing a "bool but not in the same way as the rest" GIT_TEST_* variable. Signed-off-by: Ævar Arnfjörð Bjarmason <avarab@xxxxxxxxx> --- Documentation/config/core.txt | 12 ++++++++++++ parse-options.c | 19 +++++++++++++++---- t/README | 4 ++-- t/t0040-parse-options.sh | 22 +++++++++++++++++----- t/test-lib.sh | 6 +++--- 5 files changed, 49 insertions(+), 14 deletions(-) diff --git a/Documentation/config/core.txt b/Documentation/config/core.txt index 7e9b6c8f4c..5a42ec3940 100644 --- a/Documentation/config/core.txt +++ b/Documentation/config/core.txt @@ -1,3 +1,15 @@ +core.abbreviatedOptions:: + Defaults to `true` which allows options to be abbreviated as + long as they aren't ambiguous, e.g. for linkgit:git-init[1] + the `--bare` option can be abbreviated as `--bar`, `--ba` or + even `--b` since no other option starts with those + prefixes. However, if such an option were added in the future + any use of these abbreviations would break. ++ +By setting this to false (e.g. in scripts) you can defend against such +future breakages by enforcing that options must always be fully +provided. + core.fileMode:: Tells Git if the executable bit of files in the working tree is to be honored. diff --git a/parse-options.c b/parse-options.c index acc3a93660..d6a291f705 100644 --- a/parse-options.c +++ b/parse-options.c @@ -6,7 +6,7 @@ #include "color.h" #include "utf8.h" -static int disallow_abbreviated_options; +static int abbreviated_options = 1; #define OPT_SHORT 1 #define OPT_UNSET 2 @@ -346,7 +346,7 @@ static enum parse_opt_result parse_long_opt( return get_value(p, options, all_opts, flags ^ opt_flags); } - if (disallow_abbreviated_options && (ambiguous_option || abbrev_option)) + if (!abbreviated_options && (ambiguous_option || abbrev_option)) die("disallowed abbreviated or ambiguous option '%.*s'", (int)(arg_end - arg), arg); @@ -456,6 +456,17 @@ static void parse_options_check(const struct option *opts) exit(128); } +static void parse_options_config(void) +{ + int env = git_env_bool("GIT_TEST_ABBREVIATED_OPTIONS", -1); + if (env != -1) { + abbreviated_options = env; + return; + } + git_config_get_bool("core.abbreviatedoptions", &abbreviated_options); + return; +} + void parse_options_start(struct parse_opt_ctx_t *ctx, int argc, const char **argv, const char *prefix, const struct option *options, int flags) @@ -480,6 +491,7 @@ void parse_options_start(struct parse_opt_ctx_t *ctx, (flags & PARSE_OPT_KEEP_ARGV0)) BUG("Can't keep argv0 if you don't have it"); parse_options_check(options); + parse_options_config(); } static void show_negated_gitcomp(const struct option *opts, int nr_noopts) @@ -714,9 +726,8 @@ int parse_options(int argc, const char **argv, const char *prefix, { struct parse_opt_ctx_t ctx; - disallow_abbreviated_options = - git_env_bool("GIT_TEST_DISALLOW_ABBREVIATED_OPTIONS", 0); + parse_options_config(); parse_options_start(&ctx, argc, argv, prefix, options, flags); switch (parse_options_step(&ctx, options, usagestr)) { case PARSE_OPT_HELP: diff --git a/t/README b/t/README index 9ed3051a1c..1d628baf31 100644 --- a/t/README +++ b/t/README @@ -399,9 +399,9 @@ GIT_TEST_SIDEBAND_ALL=<boolean>, when true, overrides the fetch-pack to not request sideband-all (even if the server advertises sideband-all). -GIT_TEST_DISALLOW_ABBREVIATED_OPTIONS=<boolean>, when true (which is +GIT_TEST_ABBREVIATED_OPTIONS=<boolean>, when false (which is the default when running tests), errors out when an abbreviated option -is used. +is used. Overrides the core.abbreviatedOptions setting. Naming Tests ------------ diff --git a/t/t0040-parse-options.sh b/t/t0040-parse-options.sh index 5f6a16336d..19685d1582 100755 --- a/t/t0040-parse-options.sh +++ b/t/t0040-parse-options.sh @@ -203,27 +203,39 @@ file: (not set) EOF test_expect_success 'unambiguously abbreviated option' ' - GIT_TEST_DISALLOW_ABBREVIATED_OPTIONS=false \ + GIT_TEST_ABBREVIATED_OPTIONS=true \ test-tool parse-options --int 2 --boolean --no-bo >output 2>output.err && test_must_be_empty output.err && test_cmp expect output ' test_expect_success 'unambiguously abbreviated option with "="' ' - GIT_TEST_DISALLOW_ABBREVIATED_OPTIONS=false \ + GIT_TEST_ABBREVIATED_OPTIONS=true \ test-tool parse-options --expect="integer: 2" --int=2 ' test_expect_success 'ambiguously abbreviated option' ' - test_expect_code 129 env GIT_TEST_DISALLOW_ABBREVIATED_OPTIONS=false \ + test_expect_code 129 env GIT_TEST_ABBREVIATED_OPTIONS=true \ test-tool parse-options --strin 123 ' test_expect_success 'non ambiguous option (after two options it abbreviates)' ' - GIT_TEST_DISALLOW_ABBREVIATED_OPTIONS=false \ + GIT_TEST_ABBREVIATED_OPTIONS=true \ test-tool parse-options --expect="string: 123" --st 123 ' +test_expect_success 'abbreviated options configured with core.abbreviatedOptions' ' + test_when_finished " + rm -rf A B C && + GIT_TEST_ABBREVIATED_OPTIONS=$GIT_TEST_ABBREVIATED_OPTIONS && + export GIT_TEST_ABBREVIATED_OPTIONS + " && + git init --bare A && + test_must_fail git init --ba B && + sane_unset GIT_TEST_ABBREVIATED_OPTIONS && + git -c core.abbreviatedOptions=true init --ba C +' + cat >typo.err <<\EOF error: did you mean `--boolean` (with two dashes ?) EOF @@ -329,7 +341,7 @@ file: (not set) EOF test_expect_success 'negation of OPT_NONEG flags is not ambiguous' ' - GIT_TEST_DISALLOW_ABBREVIATED_OPTIONS=false \ + GIT_TEST_ABBREVIATED_OPTIONS=true \ test-tool parse-options --no-ambig >output 2>output.err && test_must_be_empty output.err && test_cmp expect output diff --git a/t/test-lib.sh b/t/test-lib.sh index e550009411..4b0dd8a1a9 100644 --- a/t/test-lib.sh +++ b/t/test-lib.sh @@ -58,9 +58,9 @@ fi export PERL_PATH SHELL_PATH # Disallow the use of abbreviated options in the test suite by default -test -n "$GIT_TEST_DISALLOW_ABBREVIATED_OPTIONS" || { - GIT_TEST_DISALLOW_ABBREVIATED_OPTIONS=true - export GIT_TEST_DISALLOW_ABBREVIATED_OPTIONS +test -n "$GIT_TEST_ABBREVIATED_OPTIONS" || { + GIT_TEST_ABBREVIATED_OPTIONS=false + export GIT_TEST_ABBREVIATED_OPTIONS } ################################################################ -- 2.21.0.360.g471c308f928