{"thread":{"id":"51336","subject":"[PATCH] fetch: only run 'gc' once when fetching multiple remotes","startedAt":"2019-06-19T09:46:40Z","lastAt":"2019-11-25T13:53:50Z","messageCount":61,"participants":["Nguyễn Thái Ngọc Duy","Ævar Arnfjörð Bjarmason","Duy Nguyen","Jeff King","Junio C Hamano","SZEDER Gábor"],"isPatch":true,"patchVersion":1,"patchTotal":null},"messages":[{"id":"377491","messageId":"20190619094630.32557-1-pclouds@gmail.com","threadId":"51336","inReplyTo":null,"subject":"[PATCH] fetch: only run 'gc' once when fetching multiple remotes","fromName":"Nguyễn Thái Ngọc Duy","fromEmail":"pclouds@gmail.com","sentAt":"2019-06-19T09:46:30Z","receivedAt":"2019-06-19T09:46:40Z","isPatch":true,"sender":{"key":"pclouds@gmail.com","avatar":"https://avatars.githubusercontent.com/u/720?v=4"},"body":"In multiple remotes mode, git-fetch is launched for n-1 remotes and the\nlast remote is handled by the current process. Each of these processes\nwill in turn run 'gc' at the end.\n\nThis is not really a problem because even if multiple 'gc --auto' is run\nat the same time we still handle it correctly. It does show multiple\n\"auto packing in the background\" messages though. And we may waste some\nresources when gc actually runs because we still do some stuff before\nchecking the lock and moving it to background.\n\nSo let's try to avoid that. We should only need one 'gc' run after all\nobjects and references are added anyway. Add a new option --no-auto-gc\nthat will be used by those n-1 processes. 'gc --auto' will always run on\nthe main fetch process (*).\n\n(*) even if we fetch remotes in parallel at some point in future, this\n    should still be fine because we should \"join\" all those processes\n    before this step.\n\nSigned-off-by: Nguyễn Thái Ngọc Duy <pclouds@gmail.com>\n---\n Documentation/fetch-options.txt |  4 ++++\n builtin/fetch.c                 | 17 +++++++++++------\n t/t5514-fetch-multiple.sh       |  7 +++++--\n 3 files changed, 20 insertions(+), 8 deletions(-)\n\ndiff --git a/Documentation/fetch-options.txt b/Documentation/fetch-options.txt\nindex 91c47752ec..592f391298 100644\n--- a/Documentation/fetch-options.txt\n+++ b/Documentation/fetch-options.txt\n@@ -88,6 +88,10 @@ ifndef::git-pull[]\n \tAllow several <repository> and <group> arguments to be\n \tspecified. No <refspec>s may be specified.\n \n+--[no-]auto-gc::\n+\tRun `git gc --auto` at the end to perform garbage collection\n+\tif needed. This is enabled by default.\n+\n -p::\n --prune::\n \tBefore fetching, remove any remote-tracking references that no\ndiff --git a/builtin/fetch.c b/builtin/fetch.c\nindex 4ba63d5ac6..6a3c507897 100644\n--- a/builtin/fetch.c\n+++ b/builtin/fetch.c\n@@ -48,6 +48,7 @@ static int prune_tags = -1; /* unspecified */\n \n static int all, append, dry_run, force, keep, multiple, update_head_ok, verbosity, deepen_relative;\n static int progress = -1;\n+static int enable_auto_gc = 1;\n static int tags = TAGS_DEFAULT, unshallow, update_shallow, deepen;\n static int max_children = 1;\n static enum transport_family family;\n@@ -169,6 +170,8 @@ static struct option builtin_fetch_options[] = {\n \tOPT_STRING_LIST(0, \"negotiation-tip\", &negotiation_tip, N_(\"revision\"),\n \t\t\tN_(\"report that we have only objects reachable from this object\")),\n \tOPT_PARSE_LIST_OBJECTS_FILTER(&filter_options),\n+\tOPT_BOOL(0, \"auto-gc\", &enable_auto_gc,\n+\t\t N_(\"run 'gc --auto' after fetching\")),\n \tOPT_END()\n };\n \n@@ -1424,7 +1427,7 @@ static int fetch_multiple(struct string_list *list)\n \t\t\treturn errcode;\n \t}\n \n-\targv_array_pushl(&argv, \"fetch\", \"--append\", NULL);\n+\targv_array_pushl(&argv, \"fetch\", \"--append\", \"--no-auto-gc\", NULL);\n \tadd_options_to_argv(&argv);\n \n \tfor (i = 0; i < list->nr; i++) {\n@@ -1674,11 +1677,13 @@ int cmd_fetch(int argc, const char **argv, const char *prefix)\n \n \tclose_all_packs(the_repository->objects);\n \n-\targv_array_pushl(&argv_gc_auto, \"gc\", \"--auto\", NULL);\n-\tif (verbosity < 0)\n-\t\targv_array_push(&argv_gc_auto, \"--quiet\");\n-\trun_command_v_opt(argv_gc_auto.argv, RUN_GIT_CMD);\n-\targv_array_clear(&argv_gc_auto);\n+\tif (enable_auto_gc) {\n+\t\targv_array_pushl(&argv_gc_auto, \"gc\", \"--auto\", NULL);\n+\t\tif (verbosity < 0)\n+\t\t\targv_array_push(&argv_gc_auto, \"--quiet\");\n+\t\trun_command_v_opt(argv_gc_auto.argv, RUN_GIT_CMD);\n+\t\targv_array_clear(&argv_gc_auto);\n+\t}\n \n \treturn result;\n }\ndiff --git a/t/t5514-fetch-multiple.sh b/t/t5514-fetch-multiple.sh\nindex 0030c92e1a..5426d4b5ab 100755\n--- a/t/t5514-fetch-multiple.sh\n+++ b/t/t5514-fetch-multiple.sh\n@@ -105,9 +105,12 @@ test_expect_success 'git fetch --multiple (two remotes)' '\n \t git remote rm origin &&\n \t git remote add one ../one &&\n \t git remote add two ../two &&\n-\t git fetch --multiple one two &&\n+\t GIT_TRACE=1 git fetch --multiple one two 2>trace &&\n \t git branch -r > output &&\n-\t test_cmp ../expect output)\n+\t test_cmp ../expect output &&\n+\t grep \"built-in: git gc\" trace >gc &&\n+\t test_line_count = 1 gc\n+\t)\n '\n \n test_expect_success 'git fetch --multiple (bad remote names)' '\n-- \n2.22.0.rc0.322.g2b0371e29a\n\n"},{"id":"377501","messageId":"20190619102601.24913-1-avarab@gmail.com","threadId":"51336","inReplyTo":"20190619094630.32557-1-pclouds@gmail.com","subject":"[RFC/PATCH] gc: run more pre-detach operations under lock","fromName":"Ævar Arnfjörð Bjarmason","fromEmail":"avarab@gmail.com","sentAt":"2019-06-19T10:26:00Z","receivedAt":"2019-06-19T10:26:18Z","isPatch":true,"sender":{"key":"avarab@gmail.com","avatar":"https://avatars.githubusercontent.com/u/45301?v=4"},"body":"Continue the work started in c45af94dbc (\"gc: run pre-detach\noperations under lock\", 2017-07-11).\n\nNow we'll take the lock before we print out \"Auto packing the\nrepository[...]\", and we'll optimistically tolerate a locking failure\nat that point instead of dying.\n\nThis (mostly) solves two issues:\n\n 1) Fetching in parallel from multiple remotes (or other\n    parallel/concurrent \"gc --auto\") would, when the need_to_gc()\n    heuristic fired, emit a bunch of \"Auto packing the repository in\n    background\" messages. See [1] for a description of a \"pfetch\"\n    alias that can trigger such an issue. Now we'll (usually) only\n    print one of these messages.\n\n 2) Because we'd call hold_lock_file_for_update() with\n    \"LOCK_DIE_ON_ERROR\" such concurrent \"gc\" would error out with\n    \"Another git process seems to be running[...]\".\n\n    Now we'll (usually) avoid that by saying that \"gc --auto\" locking\n    isn't so important. We tolerate a lock failure on \"gc --auto\" with\n    the assumption that a \"gc --auto\" runs frequently enough that any\n    one such invocation can fail, whereas without \"--auto\" we'll error\n    on failure to acquire the lock\n\nWhy \"mostly\" and \"usually\"? There's still unaddressed caveats with\nthese two, respectively:\n\n 1) The gc.pid lock is only held while the \"git gc\" runs. Thus a\n    \"pfetch\" operation as described in [1] might start N jobs, one of\n    which runs \"gc\", finishes, and then \"gc --auto\" finds it needs to\n    run again in the context of a single (from the user's perspective)\n    git command.\n\n    I don't think that's worth dealing with. The cases where we'll\n    find we need to take action \"gc --auto\" right after it's finished\n    are rare (see e.g. [2]).\n\n 2) There's still the unresolved race condition noted in c45af94dbc\n    where we \"hand off\" the lock to the child process we fork under\n    gc.autoDetach=true. It means we might start another \"gc --auto\" if\n    we're so unlucky as to make the check and get the lock in the time\n    the \"real\" earlier \"gc --auto\" parent/child process takes to\n    \"unlock() && fork() && lock()\".\n\n    Fixing that is outside the scope of this change. It's fixable by\n    refactoring the lockfile.c code and daemonize() so that we'd e.g.:\n\n      1. parent: lock() in parent, write PID to gc.pid\n      2. parent: fork() the child process\n      3. child: spin for X amount of time waiting until gc.pid lists\n         our PID, not our parent's\n      4. parent: amend the gc.pid lock to\n         s/PARENT_PID/CHILD_PID/ (in-place rename(gc.pid.new,\n         gc.pid)), fsync(gc.pid) and exit()\n      5. child: notices updated gc.pid, proceeds with its gc. Does\n         delete_tempfile(gc.pid) before exit()\n      6. parent: Once lock is handed over (child trusted to poll the\n         lock) exit() without delete_tempfile(gc.pid)\n\n    Using some cross-process lock handover like that we could\n    guarantee that there's never a point at which an outside process\n    could get the gc.pid lock, that the PID written in the file always\n    referred to a live process, and with #3 reasonably\n    guarantee (aside from pathological scheduling shenanigans) that we\n    don't blindly hand the PID off to a process that's already\n    finished with its gc.\n\nTesting for this new behavior is hard.\n\n1. https://public-inbox.org/git/20170712200054.mxcabiyttijpbkbb@sigill.intra.peff.net/ (should\n   be https://public-inbox.org/git/87bmopzbqx.fsf@gmail.com/ but vger\n   seems to not have gotten a copy)\n2. https://public-inbox.org/git/87fu6bmr0j.fsf@evledraar.gmail.com/\n\nSigned-off-by: Ævar Arnfjörð Bjarmason <avarab@gmail.com>\n---\n\nThis patch is part of a WIP branch I have that's a bit of a mess. It's\nmore-gc-detach-under-lock on github.com/avar/git.git. It doesn't apply\non master because it relies on some previous test work, but for RFC\npurposes I figured it was better to send it stand-alone.\n\nBut I think this sort of approach is better than Duy's proposed patch,\nbecause...\n\nOn Wed, Jun 19 2019, Nguyễn Thái Ngọc Duy wrote:\n\n> So let's try to avoid that. We should only need one 'gc' run after all\n> objects and references are added anyway. Add a new option --no-auto-gc\n> that will be used by those n-1 processes. 'gc --auto' will always run on\n> the main fetch process (*).\n>\n> (*) even if we fetch remotes in parallel at some point in future, this\n>     should still be fine because we should \"join\" all those processes\n>     before this step.\n\nThis is what I'm trying to fix in my version of this patch. This is\nonly true for yours if you assume that the user is going to be\ninvoking \"fetch\" in a single terminal window, IOW that we have an\nimplicit global mutex of one top-level git command at a time.\n\nWheras mine fixes e.g. the same issue for:\n\n    parallel 'git fetch {}' ::: $(git remote)\n\nDitto for you running a \"git\" command and your editor running a\n\"fetch\" at the same time.\n\nA similar \"one terminal\" assumption was made when changing the\nauto-detach behavior in your 62aad1849f (\"gc --auto: do not lock refs\nin the background\", 2014-05-25).\n\nTo be clear, I think that (and your patch here) would (mostly) be an\nimprovement. I just wonder if we can do better.\n\nI got stuck with this WIP series of mine because while it's mostly\nready sans the 'Why \"mostly\" and \"usually\"' caveats mentioned in my\ncommit message, I wondered if we couldn't do much better by:\n\n a) Do some version of reverting your 62aad1849f, this would entirely\n    get rid of this need for handing off a lock to a child (noted\n    above), but as-is would have e.g. \"commit\" run into a *.lock.\n\n    Is that mitigated by 4ff0f01cb7 (\"refs: retry acquiring reference\n    locks for 100ms\", 2017-08-21)? Or could we have \"gc\" run in some\n    \"lock-less\" mode where it does all the work of expiring a\n    ref/reflog at a given OID, and if it changed just tries again\n    without needing to *.lock it except for the brief period of\n    changing the already prepared file?\n\n b) If we couldn't do \"a\" for whatever reason implement some \"locking\n    priority\" where a not-gc command could create a file (which \"gc\"\n    would poll) saying \"I want it for real work, release it!\", or\n    alternatively \"gc\" would create \"*.locked-by-gc\" in addition to\n    \"*.lock\" files, and if the \"*.locked-by-gc\" was seen when the\n    100ms retry would kick in, we'd make that say 10 seconds instead\n    of 100 ms.\n\n builtin/gc.c  | 19 ++++++++++++-------\n lockfile.c    |  2 ++\n lockfile.h    |  8 +++++++-\n t/t6500-gc.sh |  8 ++++----\n 4 files changed, 25 insertions(+), 12 deletions(-)\n\ndiff --git a/builtin/gc.c b/builtin/gc.c\nindex d12316fa48..2cd5803e86 100644\n--- a/builtin/gc.c\n+++ b/builtin/gc.c\n@@ -391,7 +391,7 @@ static int need_to_gc(void)\n }\n \n /* return NULL on success, else hostname running the gc */\n-static const char *lock_repo_for_gc(int force, pid_t* ret_pid)\n+static const char *lock_repo_for_gc(int force, pid_t* ret_pid, int die_on_error)\n {\n \tstruct lock_file lock = LOCK_INIT;\n \tchar my_host[HOST_NAME_MAX + 1];\n@@ -401,13 +401,17 @@ static const char *lock_repo_for_gc(int force, pid_t* ret_pid)\n \tFILE *fp;\n \tint fd;\n \tchar *pidfile_path;\n+\tint flags = die_on_error ? LOCK_DIE_ON_ERROR : LOCK_QUIET_ON_ERROR;\n \n \tif (xgethostname(my_host, sizeof(my_host)))\n \t\txsnprintf(my_host, sizeof(my_host), \"unknown\");\n \n \tpidfile_path = git_pathdup(\"gc.pid\");\n-\tfd = hold_lock_file_for_update(&lock, pidfile_path,\n-\t\t\t\t       LOCK_DIE_ON_ERROR);\n+\tfd = hold_lock_file_for_update(&lock, pidfile_path, flags);\n+\tif (fd < 0) {\n+\t\tassert(!die_on_error); /* should die in unable_to_lock_die() */\n+\t\treturn pidfile_path;\n+\t}\n \tif (!force) {\n \t\tstatic char locking_host[HOST_NAME_MAX + 1];\n \t\tstatic char *scan_fmt;\n@@ -533,7 +537,7 @@ int cmd_gc(int argc, const char **argv, const char *prefix)\n \tint auto_gc = 0;\n \tint quiet = -1;\n \tint force = 0;\n-\tconst char *name;\n+\tconst char *name = NULL;\n \tpid_t pid;\n \tint daemonized = 0;\n \tint keep_base_pack = -1;\n@@ -599,6 +603,8 @@ int cmd_gc(int argc, const char **argv, const char *prefix)\n \t\t */\n \t\tif (!need_to_gc())\n \t\t\treturn 0;\n+\t\tif (lock_repo_for_gc(force, &pid, 0))\n+\t\t\treturn 0;\n \t\tif (!quiet) {\n \t\t\tif (detach_auto)\n \t\t\t\tfprintf(stderr, _(\"Auto packing the repository in background for optimum performance.\\n\"));\n@@ -616,8 +622,6 @@ int cmd_gc(int argc, const char **argv, const char *prefix)\n \t\t\t\t/* Last gc --auto failed. Skip this one. */\n \t\t\t\treturn 0;\n \n-\t\t\tif (lock_repo_for_gc(force, &pid))\n-\t\t\t\treturn 0;\n \t\t\tgc_before_repack(); /* dies on failure */\n \t\t\tgit_test_sleep(\"GIT_TEST_GC_SLEEP_PRE_FORK\");\n \t\t\tdelete_tempfile(&pidfile);\n@@ -644,7 +648,8 @@ int cmd_gc(int argc, const char **argv, const char *prefix)\n \t\tstring_list_clear(&keep_pack, 0);\n \t}\n \n-\tname = lock_repo_for_gc(force, &pid);\n+\tif (!pidfile)\n+\t\tname = lock_repo_for_gc(force, &pid, 1);\n \tif (name) {\n \t\tif (auto_gc)\n \t\t\treturn 0; /* be quiet on --auto */\ndiff --git a/lockfile.c b/lockfile.c\nindex 8e8ab4f29f..2a86d3a656 100644\n--- a/lockfile.c\n+++ b/lockfile.c\n@@ -173,6 +173,8 @@ int hold_lock_file_for_update_timeout(struct lock_file *lk, const char *path,\n \t\t\t\t      int flags, long timeout_ms)\n {\n \tint fd = lock_file_timeout(lk, path, flags, timeout_ms);\n+\tif (flags & LOCK_QUIET_ON_ERROR)\n+\t\treturn fd;\n \tif (fd < 0) {\n \t\tif (flags & LOCK_DIE_ON_ERROR)\n \t\t\tunable_to_lock_die(path, errno);\ndiff --git a/lockfile.h b/lockfile.h\nindex 9843053ce8..dc366d70cc 100644\n--- a/lockfile.h\n+++ b/lockfile.h\n@@ -135,10 +135,16 @@ struct lock_file {\n \n /*\n  * ... this flag can be passed instead to return -1 and give the usual\n- * error message upon an error.\n+ * error message upon an error, or ...\n  */\n #define LOCK_REPORT_ON_ERROR 4\n \n+/*\n+ * ... just be quiet and let the caller handle it by checking the\n+ * return return value.\n+ */\n+#define LOCK_QUIET_ON_ERROR 8\n+\n /*\n  * Usually symbolic links in the destination path are resolved. This\n  * means that (1) the lockfile is created by adding \".lock\" to the\ndiff --git a/t/t6500-gc.sh b/t/t6500-gc.sh\nindex 363ca18980..4dea98f1c3 100755\n--- a/t/t6500-gc.sh\n+++ b/t/t6500-gc.sh\n@@ -175,14 +175,14 @@ test_racy_gc_auto () {\n \t\"\n }\n \n-test_racy_gc_auto failure false N/A N/A N/A\n+test_racy_gc_auto success false N/A N/A N/A\n for fork_works in true false\n do\n \tfor sleep_before_fork in 0 1\n \tdo\n \t\tfor sleep_before_fork_no_lock in 0 1\n \t\tdo\n-\t\t\ttest_racy_gc_auto failure true $sleep_before_fork $sleep_before_fork_no_lock $fork_works\n+\t\t\ttest_racy_gc_auto success true $sleep_before_fork $sleep_before_fork_no_lock $fork_works\n \t\tdone\n \tdone\n done\n@@ -204,8 +204,8 @@ test_racy_faked_gc_auto () {\n \t\ttest_line_count = 0 errors\n \t\"\n }\n-test_racy_faked_gc_auto failure true\n-test_racy_faked_gc_auto failure false\n+test_racy_faked_gc_auto success true\n+test_racy_faked_gc_auto success false\n \n run_and_wait_for_auto_gc () {\n \t# We read stdout from gc for the side effect of waiting until the\n-- \n2.22.0.rc1.257.g3120a18244\n\n"},{"id":"377513","messageId":"CACsJy8AqA3TmNP62ko4c5Et39jsADYf9nKQByz28y-YQjNyKag@mail.gmail.com","threadId":"51336","inReplyTo":"20190619102601.24913-1-avarab@gmail.com","subject":"Re: [RFC/PATCH] gc: run more pre-detach operations under lock","fromName":"Duy Nguyen","fromEmail":"pclouds@gmail.com","sentAt":"2019-06-19T12:51:00Z","receivedAt":"2019-06-19T12:51:28Z","isPatch":true,"sender":{"key":"pclouds@gmail.com","avatar":"https://avatars.githubusercontent.com/u/720?v=4"},"body":"On Wed, Jun 19, 2019 at 5:26 PM Ævar Arnfjörð Bjarmason\n<avarab@gmail.com> wrote:\n> This patch is part of a WIP branch I have that's a bit of a mess. It's\n> more-gc-detach-under-lock on github.com/avar/git.git. It doesn't apply\n> on master because it relies on some previous test work, but for RFC\n> purposes I figured it was better to send it stand-alone.\n>\n> But I think this sort of approach is better than Duy's proposed patch,\n> because...\n>\n> On Wed, Jun 19 2019, Nguyễn Thái Ngọc Duy wrote:\n>\n> > So let's try to avoid that. We should only need one 'gc' run after all\n> > objects and references are added anyway. Add a new option --no-auto-gc\n> > that will be used by those n-1 processes. 'gc --auto' will always run on\n> > the main fetch process (*).\n> >\n> > (*) even if we fetch remotes in parallel at some point in future, this\n> >     should still be fine because we should \"join\" all those processes\n> >     before this step.\n>\n> This is what I'm trying to fix in my version of this patch. This is\n> only true for yours if you assume that the user is going to be\n> invoking \"fetch\" in a single terminal window, IOW that we have an\n> implicit global mutex of one top-level git command at a time.\n>\n> Wheras mine fixes e.g. the same issue for:\n>\n>     parallel 'git fetch {}' ::: $(git remote)\n>\n> Ditto for you running a \"git\" command and your editor running a\n> \"fetch\" at the same time.\n\nYou could sort of avoid the problem here too with\n\nparallel 'git fetch --no-auto-gc {}' ::: $(git remote)\ngit gc --auto\n\nIt's definitely simpler, but of course we have to manually add\n--no-auto-gc in everywhere we need, so not quite as elegant.\n\nActually you could already do that with 'git -c gc.auto=false fetch', I guess.\n-- \nDuy\n"},{"id":"377545","messageId":"87k1dh8ne4.fsf@evledraar.gmail.com","threadId":"51336","inReplyTo":"CACsJy8AqA3TmNP62ko4c5Et39jsADYf9nKQByz28y-YQjNyKag@mail.gmail.com","subject":"Re: [RFC/PATCH] gc: run more pre-detach operations under lock","fromName":"Ævar Arnfjörð Bjarmason","fromEmail":"avarab@gmail.com","sentAt":"2019-06-19T18:01:55Z","receivedAt":"2019-06-19T18:02:00Z","isPatch":true,"sender":{"key":"avarab@gmail.com","avatar":"https://avatars.githubusercontent.com/u/45301?v=4"},"body":"\nOn Wed, Jun 19 2019, Duy Nguyen wrote:\n\n> On Wed, Jun 19, 2019 at 5:26 PM Ævar Arnfjörð Bjarmason\n> <avarab@gmail.com> wrote:\n>> This patch is part of a WIP branch I have that's a bit of a mess. It's\n>> more-gc-detach-under-lock on github.com/avar/git.git. It doesn't apply\n>> on master because it relies on some previous test work, but for RFC\n>> purposes I figured it was better to send it stand-alone.\n>>\n>> But I think this sort of approach is better than Duy's proposed patch,\n>> because...\n>>\n>> On Wed, Jun 19 2019, Nguyễn Thái Ngọc Duy wrote:\n>>\n>> > So let's try to avoid that. We should only need one 'gc' run after all\n>> > objects and references are added anyway. Add a new option --no-auto-gc\n>> > that will be used by those n-1 processes. 'gc --auto' will always run on\n>> > the main fetch process (*).\n>> >\n>> > (*) even if we fetch remotes in parallel at some point in future, this\n>> >     should still be fine because we should \"join\" all those processes\n>> >     before this step.\n>>\n>> This is what I'm trying to fix in my version of this patch. This is\n>> only true for yours if you assume that the user is going to be\n>> invoking \"fetch\" in a single terminal window, IOW that we have an\n>> implicit global mutex of one top-level git command at a time.\n>>\n>> Wheras mine fixes e.g. the same issue for:\n>>\n>>     parallel 'git fetch {}' ::: $(git remote)\n>>\n>> Ditto for you running a \"git\" command and your editor running a\n>> \"fetch\" at the same time.\n>\n> You could sort of avoid the problem here too with\n>\n> parallel 'git fetch --no-auto-gc {}' ::: $(git remote)\n> git gc --auto\n>\n> It's definitely simpler, but of course we have to manually add\n> --no-auto-gc in everywhere we need, so not quite as elegant.\n>\n> Actually you could already do that with 'git -c gc.auto=false fetch', I guess.\n\nThe point of the 'parallel' example is to show disconnected git\ncommands, think trying to run 'git' in a terminal while your editor\nasynchronously runs a polling 'fetch', or a server with multiple\nconcurrent clients running 'gc --auto'.\n\nThat's the question my RFC patch raises. As far as I can tell the\napproach in your patch is only needed because our locking for gc is\nbuggy, rather than introduce the caveat that an fetch(N) operation won't\ndo \"gc\" until it's finished (we may have hundreds, thousands of remotes,\nI use that for some more obscure use-cases) shouldn't we just fix the\nlocking?\n"},{"id":"377549","messageId":"20190619185934.GC28145@sigill.intra.peff.net","threadId":"51336","inReplyTo":"20190619094630.32557-1-pclouds@gmail.com","subject":"Re: [PATCH] fetch: only run 'gc' once when fetching multiple remotes","fromName":"Jeff King","fromEmail":"peff@peff.net","sentAt":"2019-06-19T18:59:34Z","receivedAt":"2019-06-19T18:59:37Z","isPatch":true,"sender":{"key":"peff@peff.net","avatar":"https://avatars.githubusercontent.com/u/45925?v=4"},"body":"On Wed, Jun 19, 2019 at 04:46:30PM +0700, Nguyễn Thái Ngọc Duy wrote:\n\n> In multiple remotes mode, git-fetch is launched for n-1 remotes and the\n> last remote is handled by the current process. Each of these processes\n> will in turn run 'gc' at the end.\n> \n> This is not really a problem because even if multiple 'gc --auto' is run\n> at the same time we still handle it correctly. It does show multiple\n> \"auto packing in the background\" messages though. And we may waste some\n> resources when gc actually runs because we still do some stuff before\n> checking the lock and moving it to background.\n> \n> So let's try to avoid that. We should only need one 'gc' run after all\n> objects and references are added anyway. Add a new option --no-auto-gc\n> that will be used by those n-1 processes. 'gc --auto' will always run on\n> the main fetch process (*).\n\nYeah, that makes sense.\n\nI was surprised that we needed a new command-line option here, but I\nguess the sub-fetch processes really have no idea that they're\nsubservient to a multi-remote fetch (they do get \"--append\", but of\ncourse somebody could specify that independently).\n\nAnother option would be to just pass \"-c gc.auto=0\" to the child\nprocesses to inhibit auto-gc. But maybe it makes sense to have a nicer\ninterface (after all, somebody else could be doing the same \"let's do a\nbunch of fetches in a row\" without using the multi-fetch code).\n\nThough there I kind of wonder if this would apply to other scripted\nuses, too. E.g., if I'm doing a bunch of commits, I might want to\ninhibit auto-gc and then run it myself at the end. Should we support\n\"GIT_AUTO_GC=0\" in the environment (and a matching \"git --no-auto-gc\n...\" option that could be used here)?\n\n>  Documentation/fetch-options.txt |  4 ++++\n>  builtin/fetch.c                 | 17 +++++++++++------\n>  t/t5514-fetch-multiple.sh       |  7 +++++--\n>  3 files changed, 20 insertions(+), 8 deletions(-)\n\nMy musings above aside, the patch looks correct to me.\n\n-Peff\n"},{"id":"377550","messageId":"20190619190845.GD28145@sigill.intra.peff.net","threadId":"51336","inReplyTo":"CACsJy8AqA3TmNP62ko4c5Et39jsADYf9nKQByz28y-YQjNyKag@mail.gmail.com","subject":"Re: [RFC/PATCH] gc: run more pre-detach operations under lock","fromName":"Jeff King","fromEmail":"peff@peff.net","sentAt":"2019-06-19T19:08:45Z","receivedAt":"2019-06-19T19:08:48Z","isPatch":true,"sender":{"key":"peff@peff.net","avatar":"https://avatars.githubusercontent.com/u/45925?v=4"},"body":"On Wed, Jun 19, 2019 at 07:51:00PM +0700, Duy Nguyen wrote:\n\n> > Wheras mine fixes e.g. the same issue for:\n> >\n> >     parallel 'git fetch {}' ::: $(git remote)\n> >\n> > Ditto for you running a \"git\" command and your editor running a\n> > \"fetch\" at the same time.\n> \n> You could sort of avoid the problem here too with\n> \n> parallel 'git fetch --no-auto-gc {}' ::: $(git remote)\n> git gc --auto\n> \n> It's definitely simpler, but of course we have to manually add\n> --no-auto-gc in everywhere we need, so not quite as elegant.\n\nThis has the added advantage that the gc is deterministically run only\nonce after all of the fetches. Whereas any locking scheme is going to\nrun it randomly for at least _one_ of the fetches, but there may be\nother fetches afterwards.\n\nIn a sense it might not matter, because any fetches which complete after\nthe auto-gc finishes would either trigger a new auto-gc or not. And if\nnot, then one could argue that it wasn't necessary.\n\nBut as a general rule, the cost of gc scales with the repo size, not\nwith the number of unpacked objects. So it's more efficient to stick as\nmany updates as you can into a single gc; the cost is running a gc at\nall, not the incremental cost of including the new fetches. Or put\nanother way, by leaving some fetches from this round of commands out of\nthe gc, we will require another expensive gc sooner.\n\n> Actually you could already do that with 'git -c gc.auto=false fetch', I guess.\n\nYeah. I wrote my other response before reading this part of the thread,\nbut IMHO Ævar's example argues even more for \"git --no-auto-gc\".\n\n-Peff\n"},{"id":"377551","messageId":"20190619191037.GE28145@sigill.intra.peff.net","threadId":"51336","inReplyTo":"87k1dh8ne4.fsf@evledraar.gmail.com","subject":"Re: [RFC/PATCH] gc: run more pre-detach operations under lock","fromName":"Jeff King","fromEmail":"peff@peff.net","sentAt":"2019-06-19T19:10:37Z","receivedAt":"2019-06-19T19:10:42Z","isPatch":true,"sender":{"key":"peff@peff.net","avatar":"https://avatars.githubusercontent.com/u/45925?v=4"},"body":"On Wed, Jun 19, 2019 at 08:01:55PM +0200, Ævar Arnfjörð Bjarmason wrote:\n\n> > You could sort of avoid the problem here too with\n> >\n> > parallel 'git fetch --no-auto-gc {}' ::: $(git remote)\n> > git gc --auto\n> >\n> > It's definitely simpler, but of course we have to manually add\n> > --no-auto-gc in everywhere we need, so not quite as elegant.\n> >\n> > Actually you could already do that with 'git -c gc.auto=false fetch', I guess.\n> \n> The point of the 'parallel' example is to show disconnected git\n> commands, think trying to run 'git' in a terminal while your editor\n> asynchronously runs a polling 'fetch', or a server with multiple\n> concurrent clients running 'gc --auto'.\n> \n> That's the question my RFC patch raises. As far as I can tell the\n> approach in your patch is only needed because our locking for gc is\n> buggy, rather than introduce the caveat that an fetch(N) operation won't\n> do \"gc\" until it's finished (we may have hundreds, thousands of remotes,\n> I use that for some more obscure use-cases) shouldn't we just fix the\n> locking?\n\nI think there may be room for both approaches. Yours fixes the repeated\nmessage in the more general case, but Duy's suggestion is the most\nefficient thing.\n\nI agree that the \"thousands of remotes\" case means we might want to gc\nin the interim. But we probably ought to do that deterministically\nrather than hoping that the pattern of lock contention makes sense.\n\n-Peff\n"},{"id":"377593","messageId":"87imt18a2r.fsf@evledraar.gmail.com","threadId":"51336","inReplyTo":"20190619191037.GE28145@sigill.intra.peff.net","subject":"Re: [RFC/PATCH] gc: run more pre-detach operations under lock","fromName":"Ævar Arnfjörð Bjarmason","fromEmail":"avarab@gmail.com","sentAt":"2019-06-19T22:49:32Z","receivedAt":"2019-06-19T22:49:37Z","isPatch":true,"sender":{"key":"avarab@gmail.com","avatar":"https://avatars.githubusercontent.com/u/45301?v=4"},"body":"\nOn Wed, Jun 19 2019, Jeff King wrote:\n\n> On Wed, Jun 19, 2019 at 08:01:55PM +0200, Ævar Arnfjörð Bjarmason wrote:\n>\n>> > You could sort of avoid the problem here too with\n>> >\n>> > parallel 'git fetch --no-auto-gc {}' ::: $(git remote)\n>> > git gc --auto\n>> >\n>> > It's definitely simpler, but of course we have to manually add\n>> > --no-auto-gc in everywhere we need, so not quite as elegant.\n>> >\n>> > Actually you could already do that with 'git -c gc.auto=false fetch', I guess.\n>>\n>> The point of the 'parallel' example is to show disconnected git\n>> commands, think trying to run 'git' in a terminal while your editor\n>> asynchronously runs a polling 'fetch', or a server with multiple\n>> concurrent clients running 'gc --auto'.\n>>\n>> That's the question my RFC patch raises. As far as I can tell the\n>> approach in your patch is only needed because our locking for gc is\n>> buggy, rather than introduce the caveat that an fetch(N) operation won't\n>> do \"gc\" until it's finished (we may have hundreds, thousands of remotes,\n>> I use that for some more obscure use-cases) shouldn't we just fix the\n>> locking?\n>\n> I think there may be room for both approaches. Yours fixes the repeated\n> message in the more general case, but Duy's suggestion is the most\n> efficient thing.\n>\n> I agree that the \"thousands of remotes\" case means we might want to gc\n> in the interim. But we probably ought to do that deterministically\n> rather than hoping that the pattern of lock contention makes sense.\n\nWe do it deterministically, when gc.auto thresholds et al are exceeded\nwe kick one off without waiting for other stuff, if we can get the lock.\n\nI don't think this desire to just wait a bit until all the fetches are\ncomplete makes sense as a special-case.\n\nIf, as you noted in <20190619190845.GD28145@sigill.intra.peff.net>, the\ndesire is to reduce GC CPU use then you're better off just tweaking the\nlimits upwards. Then you get that with everything, like when you run\n\"commit\" in a for-loop, not just this one special case of \"fetch\".\n\nWe have existing potentially long-running operations like \"fetch\",\n\"rebase\" and \"git svn fetch\" that run \"gc --auto\" for their incremental\nsteps, and that's a feature.\n\nIt keeps \"gc --auto\" dumb enough to avoid a pathological case where\nwe'll have a ballooning objects dir because we figure we can run\nsomething \"at the end\", when \"the end\" could be hours away, and we're\nadding a new pack or hundreds of loose objects every second.\n\nSo I don't think Duy's patch is a good way to go.\n\nThe rationale in its commit message for including it can be better\naddressed by something like my WIP for just fixing the locking\nmechanism, since it fixes the stated problems of multiple \"auto packing\nin the background\" messages and the \"we may waste some resources\" (we\ntake the lock earlier before doing 'real' work) without introducing its\nown pathological case of deferring \"gc --auto\" too much as we have\nunchecked object growth.\n\nI think that's really important. It's OK if \"gc --auto\" isn't optimal,\nbut we should really avoid such pathological cases.\n\nIt's also important that it's easy to explain, i.e. if this patch goes\nin I think it should update the second paragraph of the git-gc.txt\ndocs. I.e. now it's not just:\n\n    When common porcelain operations that create objects are run, they\n    will check whether the repository has grown substantially since the\n    last maintenance[...]\n\nBut also something like:\n\n    Except in cases where we're running porcelain commads that\n    themselves might re-run aggregates of themselves, in which case we\n    defer \"gc\" until the end. This currently only applies to \"fetch\",\n    but other commands such as \"rebase\" etc. might learn to do this in\n    the future. Note that if the sub-commands are numerous enough this\n    might itself become pathological as \"gc --auto\" is deferred too\n    much, so use option/config XYZ to ...\n\nOr whatever...\n"},{"id":"377594","messageId":"20190619233046.27503-1-avarab@gmail.com","threadId":"51336","inReplyTo":"87imt18a2r.fsf@evledraar.gmail.com","subject":"[PATCH 0/6] Change <non-empty?> GIT_TEST_* variables to <boolean>","fromName":"Ævar Arnfjörð Bjarmason","fromEmail":"avarab@gmail.com","sentAt":"2019-06-19T23:30:40Z","receivedAt":"2019-06-19T23:30:58Z","isPatch":true,"sender":{"key":"avarab@gmail.com","avatar":"https://avatars.githubusercontent.com/u/45301?v=4"},"body":"This changes the remaining <non-empty?> special snowflake test modes\nto <boolean> and gets rid of test_tristate() in favor of the now\nstandard \"boolea\" test.\n\nI'm replying to my \"gc: run more pre-detach operations under lock\"\nthread because one of the things my WIP patches to make gc locking\nless sucky depends on is new GIT_TEST_GC_* test modes to test its\nracyness, which in turn depends on these cleanups.\n\nÆvar Arnfjörð Bjarmason (6):\n  env--helper: new undocumented builtin wrapping git_env_*()\n  t6040 test: stop using global \"script\" variable\n  tests: make GIT_TEST_GETTEXT_POISON a boolean\n  tests README: re-flow a previously changed paragraph\n  tests: replace test_tristate with \"git env--helper\"\n  tests: make GIT_TEST_FAIL_PREREQS a boolean\n\n .gitignore                |  1 +\n Makefile                  |  1 +\n builtin.h                 |  1 +\n builtin/env--helper.c     | 74 +++++++++++++++++++++++++++++++++++++++\n ci/lib.sh                 |  2 +-\n gettext.c                 |  6 ++--\n git-sh-i18n.sh            |  4 ++-\n git.c                     |  1 +\n po/README                 |  2 +-\n t/README                  | 12 +++----\n t/lib-git-daemon.sh       |  7 ++--\n t/lib-git-svn.sh          | 11 +++---\n t/lib-httpd.sh            | 15 ++++----\n t/t0000-basic.sh          | 10 +++---\n t/t0016-env-helper.sh     | 70 ++++++++++++++++++++++++++++++++++++\n t/t0205-gettext-poison.sh |  2 +-\n t/t5512-ls-remote.sh      |  3 +-\n t/t6040-tracking-info.sh  |  6 ++--\n t/t7201-co.sh             |  2 +-\n t/t9902-completion.sh     |  2 +-\n t/test-lib-functions.sh   | 58 +++++-------------------------\n t/test-lib.sh             | 29 ++++++++++++---\n 22 files changed, 220 insertions(+), 99 deletions(-)\n create mode 100644 builtin/env--helper.c\n create mode 100755 t/t0016-env-helper.sh\n\n-- \n2.22.0.rc1.257.g3120a18244\n\n"},{"id":"377595","messageId":"20190619233046.27503-2-avarab@gmail.com","threadId":"51336","inReplyTo":"87imt18a2r.fsf@evledraar.gmail.com","subject":"[PATCH 1/6] env--helper: new undocumented builtin wrapping git_env_*()","fromName":"Ævar Arnfjörð Bjarmason","fromEmail":"avarab@gmail.com","sentAt":"2019-06-19T23:30:41Z","receivedAt":"2019-06-19T23:31:01Z","isPatch":true,"sender":{"key":"avarab@gmail.com","avatar":"https://avatars.githubusercontent.com/u/45301?v=4"},"body":"We have many GIT_TEST_* variables that accept a <boolean> because\nthey're implemented in C, and then some that take <non-empty?> because\nthey're implemented at least partially in shellscript.\n\nAdd a helper that wraps git_env_bool() and git_env_ulong() as the\nfirst step in fixing this. This isn't being added as a test-tool mode\nbecause some of these are used outside the test suite.\n\nPart of what this tool does can be done via a trick with \"git config\"\nadded in 83d842dc8c (\"tests: turn on network daemon tests by default\",\n2014-02-10) for test_tristate(), i.e.:\n\n    git -c magic.variable=\"$1\" config --bool magic.variable 2>/dev/null\n\nBut as subsequent changes will show being able to pass along the\ndefault value makes all the difference, and we'll be able to replace\ntest_tristate() itself with that.\n\nThe --mode-bool option will be used by subsequent patches, but not\n--mode-ulong. I figured it was easy enough to add it & test for it so\nI left it in so we'd have wrappers for both git_env_*() functions.\n\nSigned-off-by: Ævar Arnfjörð Bjarmason <avarab@gmail.com>\n---\n .gitignore            |  1 +\n Makefile              |  1 +\n builtin.h             |  1 +\n builtin/env--helper.c | 74 +++++++++++++++++++++++++++++++++++++++++++\n git.c                 |  1 +\n t/t0016-env-helper.sh | 70 ++++++++++++++++++++++++++++++++++++++++\n 6 files changed, 148 insertions(+)\n create mode 100644 builtin/env--helper.c\n create mode 100755 t/t0016-env-helper.sh\n\ndiff --git a/.gitignore b/.gitignore\nindex 4470d7cfc0..1f7a83fb3c 100644\n--- a/.gitignore\n+++ b/.gitignore\n@@ -58,6 +58,7 @@\n /git-difftool\n /git-difftool--helper\n /git-describe\n+/git-env--helper\n /git-fast-export\n /git-fast-import\n /git-fetch\ndiff --git a/Makefile b/Makefile\nindex f58bf14c7b..f2cfc8d812 100644\n--- a/Makefile\n+++ b/Makefile\n@@ -1059,6 +1059,7 @@ BUILTIN_OBJS += builtin/diff-index.o\n BUILTIN_OBJS += builtin/diff-tree.o\n BUILTIN_OBJS += builtin/diff.o\n BUILTIN_OBJS += builtin/difftool.o\n+BUILTIN_OBJS += builtin/env--helper.o\n BUILTIN_OBJS += builtin/fast-export.o\n BUILTIN_OBJS += builtin/fetch-pack.o\n BUILTIN_OBJS += builtin/fetch.o\ndiff --git a/builtin.h b/builtin.h\nindex ec7e0954c4..93bd49fe4f 100644\n--- a/builtin.h\n+++ b/builtin.h\n@@ -160,6 +160,7 @@ int cmd_diff_index(int argc, const char **argv, const char *prefix);\n int cmd_diff(int argc, const char **argv, const char *prefix);\n int cmd_diff_tree(int argc, const char **argv, const char *prefix);\n int cmd_difftool(int argc, const char **argv, const char *prefix);\n+int cmd_env__helper(int argc, const char **argv, const char *prefix);\n int cmd_fast_export(int argc, const char **argv, const char *prefix);\n int cmd_fetch(int argc, const char **argv, const char *prefix);\n int cmd_fetch_pack(int argc, const char **argv, const char *prefix);\ndiff --git a/builtin/env--helper.c b/builtin/env--helper.c\nnew file mode 100644\nindex 0000000000..2bb65ecf3f\n--- /dev/null\n+++ b/builtin/env--helper.c\n@@ -0,0 +1,74 @@\n+#include \"builtin.h\"\n+#include \"config.h\"\n+#include \"parse-options.h\"\n+\n+static char const * const env__helper_usage[] = {\n+\tN_(\"git env--helper [--mode-bool | --mode-ulong] --env-variable=<VAR> --env-default=<DEF> [<options>]\"),\n+\tNULL\n+};\n+\n+int cmd_env__helper(int argc, const char **argv, const char *prefix)\n+{\n+\tenum {\n+\t\tENV_HELPER_BOOL = 1,\n+\t\tENV_HELPER_ULONG,\n+\t} cmdmode = 0;\n+\tint exit_code = 0;\n+\tint quiet = 0;\n+\tconst char *env_variable = NULL;\n+\tconst char *env_default = NULL;\n+\tint ret;\n+\tint ret_int, tmp_int;\n+\tunsigned long ret_ulong, tmp_ulong;\n+\tstruct option opts[] = {\n+\t\tOPT_CMDMODE(0, \"mode-bool\", &cmdmode,\n+\t\t\t    N_(\"invoke git_env_bool(...)\"), ENV_HELPER_BOOL),\n+\t\tOPT_CMDMODE(0, \"mode-ulong\", &cmdmode,\n+\t\t\t    N_(\"invoke git_env_ulong(...)\"), ENV_HELPER_ULONG),\n+\t\tOPT_STRING(0, \"variable\", &env_variable, N_(\"name\"),\n+\t\t\t   N_(\"which environment variable to ask git_env_*(...) about\")),\n+\t\tOPT_STRING(0, \"default\", &env_default, N_(\"value\"),\n+\t\t\t   N_(\"what default value does git_env_*(...) fall back on?\")),\n+\t\tOPT_BOOL(0, \"exit-code\", &exit_code,\n+\t\t\t N_(\"exit code determined by truth of the git_env_*() function\")),\n+\t\tOPT_BOOL(0, \"quiet\", &quiet,\n+\t\t\t N_(\"don't print the git_env_*() return value\")),\n+\t\tOPT_END(),\n+\t};\n+\n+\tif (parse_options(argc, argv, prefix, opts, env__helper_usage, 0))\n+\t\tusage_with_options(env__helper_usage, opts);\n+\tif (!env_variable || !env_default ||\n+\t    !*env_variable || !*env_default)\n+\t\tusage_with_options(env__helper_usage, opts);\n+\n+\tswitch (cmdmode) {\n+\tcase ENV_HELPER_BOOL:\n+\t\ttmp_int = strtol(env_default, (char **)&env_default, 10);\n+\t\tif (*env_default) {\n+\t\t\terror(_(\"option `--default' expects a numerical value with `--mode-bool`\"));\n+\t\t\tusage_with_options(env__helper_usage, opts);\n+\t\t}\n+\t\tret_int = git_env_bool(env_variable, tmp_int);\n+\t\tif (!quiet)\n+\t\t\tprintf(\"%d\\n\", ret_int);\n+\t\tret = ret_int;\n+\t\tbreak;\n+\tcase ENV_HELPER_ULONG:\n+\t\ttmp_ulong = strtoll(env_default, (char **)&env_default, 10);\n+\t\tif (*env_default) {\n+\t\t\terror(_(\"option `--default' expects a numerical value with `--mode-ulong`\"));\n+\t\t\tusage_with_options(env__helper_usage, opts);\n+\t\t}\n+\t\tret_ulong = git_env_ulong(env_variable, tmp_ulong);\n+\t\tif (!quiet)\n+\t\t\tprintf(\"%lu\\n\", ret_ulong);\n+\t\tret = ret_ulong;\n+\t\tbreak;\n+\t}\n+\n+\tif (exit_code)\n+\t\treturn !ret;\n+\n+\treturn 0;\n+}\ndiff --git a/git.c b/git.c\nindex c2eec470c9..a43e1dd98e 100644\n--- a/git.c\n+++ b/git.c\n@@ -500,6 +500,7 @@ static struct cmd_struct commands[] = {\n \t{ \"diff-index\", cmd_diff_index, RUN_SETUP | NO_PARSEOPT },\n \t{ \"diff-tree\", cmd_diff_tree, RUN_SETUP | NO_PARSEOPT },\n \t{ \"difftool\", cmd_difftool, RUN_SETUP_GENTLY },\n+\t{ \"env--helper\", cmd_env__helper },\n \t{ \"fast-export\", cmd_fast_export, RUN_SETUP },\n \t{ \"fetch\", cmd_fetch, RUN_SETUP },\n \t{ \"fetch-pack\", cmd_fetch_pack, RUN_SETUP | NO_PARSEOPT },\ndiff --git a/t/t0016-env-helper.sh b/t/t0016-env-helper.sh\nnew file mode 100755\nindex 0000000000..4dc4ab35e5\n--- /dev/null\n+++ b/t/t0016-env-helper.sh\n@@ -0,0 +1,70 @@\n+#!/bin/sh\n+\n+test_description='test env--helper'\n+\n+. ./test-lib.sh\n+\n+\n+test_expect_success 'env--helper usage' '\n+\ttest_must_fail git env--helper &&\n+\ttest_must_fail git env--helper --mode-bool &&\n+\ttest_must_fail git env--helper --mode-ulong &&\n+\ttest_must_fail git env--helper --mode-bool --variable &&\n+\ttest_must_fail git env--helper --mode-bool --variable --default &&\n+\ttest_must_fail git env--helper --mode-bool --variable= --default=\n+'\n+\n+test_expect_success 'env--helper bad default values' '\n+\ttest_must_fail git env--helper --mode-bool --variable=MISSING --default=1xyz &&\n+\ttest_must_fail git env--helper --mode-ulong --variable=MISSING --default=1xyz\n+'\n+\n+test_expect_success 'env--helper --mode-bool' '\n+\techo 1 >expected &&\n+\tgit env--helper --mode-bool --variable=MISSING --default=1 --exit-code >actual &&\n+\ttest_cmp expected actual &&\n+\n+\techo 0 >expected &&\n+\ttest_must_fail git env--helper --mode-bool --variable=MISSING --default=0 --exit-code >actual &&\n+\ttest_cmp expected actual &&\n+\n+\tgit env--helper --mode-bool --variable=MISSING --default=0 >actual &&\n+\ttest_cmp expected actual &&\n+\n+\t>expected &&\n+\tgit env--helper --mode-bool --variable=MISSING --default=1 --exit-code --quiet >actual &&\n+\ttest_cmp expected actual &&\n+\n+\tEXISTS=true git env--helper --mode-bool --variable=EXISTS --default=0 --exit-code --quiet >actual &&\n+\ttest_cmp expected actual &&\n+\n+\techo 1 >expected &&\n+\tEXISTS=true git env--helper --mode-bool --variable=EXISTS --default=0 --exit-code >actual &&\n+\ttest_cmp expected actual\n+'\n+\n+test_expect_success 'env--helper --mode-ulong' '\n+\techo 1234567890 >expected &&\n+\tgit env--helper --mode-ulong --variable=MISSING --default=1234567890 --exit-code >actual &&\n+\ttest_cmp expected actual &&\n+\n+\techo 0 >expected &&\n+\ttest_must_fail git env--helper --mode-ulong --variable=MISSING --default=0 --exit-code >actual &&\n+\ttest_cmp expected actual &&\n+\n+\tgit env--helper --mode-ulong --variable=MISSING --default=0 >actual &&\n+\ttest_cmp expected actual &&\n+\n+\t>expected &&\n+\tgit env--helper --mode-ulong --variable=MISSING --default=1234567890 --exit-code --quiet >actual &&\n+\ttest_cmp expected actual &&\n+\n+\tEXISTS=1234567890 git env--helper --mode-ulong --variable=EXISTS --default=0 --exit-code --quiet >actual &&\n+\ttest_cmp expected actual &&\n+\n+\techo 1234567890 >expected &&\n+\tEXISTS=1234567890 git env--helper --mode-ulong --variable=EXISTS --default=0 --exit-code >actual &&\n+\ttest_cmp expected actual\n+'\n+\n+test_done\n-- \n2.22.0.rc1.257.g3120a18244\n\n"},{"id":"377596","messageId":"20190619233046.27503-3-avarab@gmail.com","threadId":"51336","inReplyTo":"87imt18a2r.fsf@evledraar.gmail.com","subject":"[PATCH 2/6] t6040 test: stop using global \"script\" variable","fromName":"Ævar Arnfjörð Bjarmason","fromEmail":"avarab@gmail.com","sentAt":"2019-06-19T23:30:42Z","receivedAt":"2019-06-19T23:31:03Z","isPatch":true,"sender":{"key":"avarab@gmail.com","avatar":"https://avatars.githubusercontent.com/u/45301?v=4"},"body":"Change test code added in c0234b2ef6 (\"stat_tracking_info(): clear\nobject flags used during counting\", 2008-07-03) to stop using the\n\"script\" variable also used for lazy prerequisites in\ntest-lib-functions.sh.\n\nSince this test uses test_i18ncmp and expects to use its own \"script\"\nvariable twice it implicitly depends on the C_LOCALE_OUTPUT\nprerequisite not being a lazy prerequisite. A follow-up change will\nmake it a lazy prerequisite, so we must remove this landmine before\ninadvertently stepping on it as we make that change.\n\nSigned-off-by: Ævar Arnfjörð Bjarmason <avarab@gmail.com>\n---\n t/t6040-tracking-info.sh | 6 +++---\n 1 file changed, 3 insertions(+), 3 deletions(-)\n\ndiff --git a/t/t6040-tracking-info.sh b/t/t6040-tracking-info.sh\nindex 716283b274..970b25a289 100755\n--- a/t/t6040-tracking-info.sh\n+++ b/t/t6040-tracking-info.sh\n@@ -38,7 +38,7 @@ test_expect_success setup '\n \tadvance h\n '\n \n-script='s/^..\\(b.\\) *[0-9a-f]* \\(.*\\)$/\\1 \\2/p'\n+t6040_script='s/^..\\(b.\\) *[0-9a-f]* \\(.*\\)$/\\1 \\2/p'\n cat >expect <<\\EOF\n b1 [ahead 1, behind 1] d\n b2 [ahead 1, behind 1] d\n@@ -53,7 +53,7 @@ test_expect_success 'branch -v' '\n \t\tcd test &&\n \t\tgit branch -v\n \t) |\n-\tsed -n -e \"$script\" >actual &&\n+\tsed -n -e \"$t6040_script\" >actual &&\n \ttest_i18ncmp expect actual\n '\n \n@@ -71,7 +71,7 @@ test_expect_success 'branch -vv' '\n \t\tcd test &&\n \t\tgit branch -vv\n \t) |\n-\tsed -n -e \"$script\" >actual &&\n+\tsed -n -e \"$t6040_script\" >actual &&\n \ttest_i18ncmp expect actual\n '\n \n-- \n2.22.0.rc1.257.g3120a18244\n\n"},{"id":"377597","messageId":"20190619233046.27503-4-avarab@gmail.com","threadId":"51336","inReplyTo":"87imt18a2r.fsf@evledraar.gmail.com","subject":"[PATCH 3/6] tests: make GIT_TEST_GETTEXT_POISON a boolean","fromName":"Ævar Arnfjörð Bjarmason","fromEmail":"avarab@gmail.com","sentAt":"2019-06-19T23:30:43Z","receivedAt":"2019-06-19T23:31:04Z","isPatch":true,"sender":{"key":"avarab@gmail.com","avatar":"https://avatars.githubusercontent.com/u/45301?v=4"},"body":"Change the GIT_TEST_GETTEXT_POISON variable from being \"non-empty?\" to\nbeing a more standard boolean variable.\n\nSince it needed to be checked in both C code and shellscript (via test\n-n) it was one of the remaining shellscript-like variables. Now that\nwe have \"git env--helper\" we can change that.\n\nSigned-off-by: Ævar Arnfjörð Bjarmason <avarab@gmail.com>\n---\n ci/lib.sh                 | 2 +-\n gettext.c                 | 6 ++----\n git-sh-i18n.sh            | 4 +++-\n po/README                 | 2 +-\n t/README                  | 4 ++--\n t/t0205-gettext-poison.sh | 2 +-\n t/t7201-co.sh             | 2 +-\n t/t9902-completion.sh     | 2 +-\n t/test-lib.sh             | 4 ++++\n 9 files changed, 16 insertions(+), 12 deletions(-)\n\ndiff --git a/ci/lib.sh b/ci/lib.sh\nindex 288a5b3884..fd799ae663 100755\n--- a/ci/lib.sh\n+++ b/ci/lib.sh\n@@ -184,7 +184,7 @@ osx-clang|osx-gcc)\n \texport GIT_SKIP_TESTS=\"t9810 t9816\"\n \t;;\n GIT_TEST_GETTEXT_POISON)\n-\texport GIT_TEST_GETTEXT_POISON=YesPlease\n+\texport GIT_TEST_GETTEXT_POISON=true\n \t;;\n esac\n \ndiff --git a/gettext.c b/gettext.c\nindex d4021d690c..5c71f4c8b9 100644\n--- a/gettext.c\n+++ b/gettext.c\n@@ -50,10 +50,8 @@ const char *get_preferred_languages(void)\n int use_gettext_poison(void)\n {\n \tstatic int poison_requested = -1;\n-\tif (poison_requested == -1) {\n-\t\tconst char *v = getenv(\"GIT_TEST_GETTEXT_POISON\");\n-\t\tpoison_requested = v && strlen(v) ? 1 : 0;\n-\t}\n+\tif (poison_requested == -1)\n+\t\tpoison_requested = git_env_bool(\"GIT_TEST_GETTEXT_POISON\", 0);\n \treturn poison_requested;\n }\n \ndiff --git a/git-sh-i18n.sh b/git-sh-i18n.sh\nindex e1d917fd27..de8ae67d7b 100644\n--- a/git-sh-i18n.sh\n+++ b/git-sh-i18n.sh\n@@ -17,7 +17,9 @@ export TEXTDOMAINDIR\n \n # First decide what scheme to use...\n GIT_INTERNAL_GETTEXT_SH_SCHEME=fallthrough\n-if test -n \"$GIT_TEST_GETTEXT_POISON\"\n+if test -n \"$GIT_TEST_GETTEXT_POISON\" &&\n+\t    git env--helper --mode-bool --variable=GIT_TEST_GETTEXT_POISON \\\n+\t\t--default=0 --exit-code --quiet\n then\n \tGIT_INTERNAL_GETTEXT_SH_SCHEME=poison\n elif test -n \"@@USE_GETTEXT_SCHEME@@\"\ndiff --git a/po/README b/po/README\nindex aa704ffcb7..07595d369b 100644\n--- a/po/README\n+++ b/po/README\n@@ -293,7 +293,7 @@ To smoke out issues like these, Git tested with a translation mode that\n emits gibberish on every call to gettext. To use it run the test suite\n with it, e.g.:\n \n-    cd t && GIT_TEST_GETTEXT_POISON=YesPlease prove -j 9 ./t[0-9]*.sh\n+    cd t && GIT_TEST_GETTEXT_POISON=true prove -j 9 ./t[0-9]*.sh\n \n If tests break with it you should inspect them manually and see if\n what you're translating is sane, i.e. that you're not translating\ndiff --git a/t/README b/t/README\nindex 9747971d58..9a131f472e 100644\n--- a/t/README\n+++ b/t/README\n@@ -343,8 +343,8 @@ whether this mode is active, and e.g. skip some tests that are hard to\n refactor to deal with it. The \"SYMLINKS\" prerequisite is currently\n excluded as so much relies on it, but this might change in the future.\n \n-GIT_TEST_GETTEXT_POISON=<non-empty?> turns all strings marked for\n-translation into gibberish if non-empty (think \"test -n\"). Used for\n+GIT_TEST_GETTEXT_POISON=<boolean> turns all strings marked for\n+translation into gibberish if true. Used for\n spotting those tests that need to be marked with a C_LOCALE_OUTPUT\n prerequisite when adding more strings for translation. See \"Testing\n marked strings\" in po/README for details.\ndiff --git a/t/t0205-gettext-poison.sh b/t/t0205-gettext-poison.sh\nindex a06269f38a..1675d3e171 100755\n--- a/t/t0205-gettext-poison.sh\n+++ b/t/t0205-gettext-poison.sh\n@@ -5,7 +5,7 @@\n \n test_description='Gettext Shell poison'\n \n-GIT_TEST_GETTEXT_POISON=YesPlease\n+GIT_TEST_GETTEXT_POISON=true\n export GIT_TEST_GETTEXT_POISON\n . ./lib-gettext.sh\n \ndiff --git a/t/t7201-co.sh b/t/t7201-co.sh\nindex 5990299fc9..b696bae5f5 100755\n--- a/t/t7201-co.sh\n+++ b/t/t7201-co.sh\n@@ -249,7 +249,7 @@ test_expect_success 'checkout to detach HEAD (with advice declined)' '\n test_expect_success 'checkout to detach HEAD' '\n \tgit config advice.detachedHead true &&\n \tgit checkout -f renamer && git clean -f &&\n-\tGIT_TEST_GETTEXT_POISON= git checkout renamer^ 2>messages &&\n+\tGIT_TEST_GETTEXT_POISON=false git checkout renamer^ 2>messages &&\n \tgrep \"HEAD is now at 7329388\" messages &&\n \ttest_line_count -gt 1 messages &&\n \tH=$(git rev-parse --verify HEAD) &&\ndiff --git a/t/t9902-completion.sh b/t/t9902-completion.sh\nindex 43cf313a1c..75512c3403 100755\n--- a/t/t9902-completion.sh\n+++ b/t/t9902-completion.sh\n@@ -1706,7 +1706,7 @@ test_expect_success 'sourcing the completion script clears cached commands' '\n '\n \n test_expect_success 'sourcing the completion script clears cached merge strategies' '\n-\tGIT_TEST_GETTEXT_POISON= &&\n+\tGIT_TEST_GETTEXT_POISON=false &&\n \t__git_compute_merge_strategies &&\n \tverbose test -n \"$__git_merge_strategies\" &&\n \t. \"$GIT_BUILD_DIR/contrib/completion/git-completion.bash\" &&\ndiff --git a/t/test-lib.sh b/t/test-lib.sh\nindex 4b346467df..bdd5017d24 100644\n--- a/t/test-lib.sh\n+++ b/t/test-lib.sh\n@@ -1443,6 +1443,10 @@ then\n \tunset GIT_TEST_GETTEXT_POISON_ORIG\n fi\n \n+test_lazy_prereq C_LOCALE_OUTPUT '\n+\t! git env--helper --mode-bool --variable=GIT_TEST_GETTEXT_POISON --default=0 --exit-code --quiet\n+'\n+\n # Can we rely on git's output in the C locale?\n if test -z \"$GIT_TEST_GETTEXT_POISON\"\n then\n-- \n2.22.0.rc1.257.g3120a18244\n\n"},{"id":"377599","messageId":"20190619233046.27503-6-avarab@gmail.com","threadId":"51336","inReplyTo":"87imt18a2r.fsf@evledraar.gmail.com","subject":"[PATCH 5/6] tests: replace test_tristate with \"git env--helper\"","fromName":"Ævar Arnfjörð Bjarmason","fromEmail":"avarab@gmail.com","sentAt":"2019-06-19T23:30:45Z","receivedAt":"2019-06-19T23:31:06Z","isPatch":true,"sender":{"key":"avarab@gmail.com","avatar":"https://avatars.githubusercontent.com/u/45301?v=4"},"body":"The test_tristate helper introduced in 83d842dc8c (\"tests: turn on\nnetwork daemon tests by default\", 2014-02-10) can now be better\nimplemented with \"git env--helper\" to give the variables in question\nthe standard boolean behavior.\n\nThe reason for the \"tristate\" was to have all of false/true/auto,\nwhere \"auto\" meant either \"false\" or \"true\" depending on what the\nfallback was. With the --default option to \"git env--helper\" we can\nsimply have e.g. GIT_TEST_HTTPD where we know if it's true because the\nuser asked explicitly (\"true\"), or true implicitly (\"auto\").\n\nThis breaks backwards compatibility for explicitly setting \"auto\" for\nthese variables, but I don't think anyone cares. That was always\nintended to be internal.\n\nThis means the test_normalize_bool() code in test-lib-functions.sh\ngoes away in addition to test_tristate(). We still need the\ntest_skip_or_die() helper, but now it takes the variable name instead\nof the value, and uses \"git env--bool\" to distinguish a default \"true\"\nfrom an explicit \"true\" (in those \"explicit true\" cases we want to\nfail the test in question).\n\nSigned-off-by: Ævar Arnfjörð Bjarmason <avarab@gmail.com>\n---\n t/lib-git-daemon.sh     |  7 +++---\n t/lib-git-svn.sh        | 11 +++-----\n t/lib-httpd.sh          | 15 ++++++-----\n t/t5512-ls-remote.sh    |  3 +--\n t/test-lib-functions.sh | 56 ++++++-----------------------------------\n 5 files changed, 22 insertions(+), 70 deletions(-)\n\ndiff --git a/t/lib-git-daemon.sh b/t/lib-git-daemon.sh\nindex 7b3407134e..770c5218ea 100644\n--- a/t/lib-git-daemon.sh\n+++ b/t/lib-git-daemon.sh\n@@ -15,8 +15,7 @@\n #\n #\ttest_done\n \n-test_tristate GIT_TEST_GIT_DAEMON\n-if test \"$GIT_TEST_GIT_DAEMON\" = false\n+if ! git env--helper --mode-bool --variable=GIT_TEST_GIT_DAEMON --default=1 --exit-code --quiet\n then\n \tskip_all=\"git-daemon testing disabled (unset GIT_TEST_GIT_DAEMON to enable)\"\n \ttest_done\n@@ -24,7 +23,7 @@ fi\n \n if test_have_prereq !PIPE\n then\n-\ttest_skip_or_die $GIT_TEST_GIT_DAEMON \"file system does not support FIFOs\"\n+\ttest_skip_or_die GIT_TEST_GIT_DAEMON \"file system does not support FIFOs\"\n fi\n \n test_set_port LIB_GIT_DAEMON_PORT\n@@ -73,7 +72,7 @@ start_git_daemon() {\n \t\tkill \"$GIT_DAEMON_PID\"\n \t\twait \"$GIT_DAEMON_PID\"\n \t\tunset GIT_DAEMON_PID\n-\t\ttest_skip_or_die $GIT_TEST_GIT_DAEMON \\\n+\t\ttest_skip_or_die GIT_TEST_GIT_DAEMON \\\n \t\t\t\"git daemon failed to start\"\n \tfi\n }\ndiff --git a/t/lib-git-svn.sh b/t/lib-git-svn.sh\nindex c1271d6863..853d33a57a 100644\n--- a/t/lib-git-svn.sh\n+++ b/t/lib-git-svn.sh\n@@ -69,14 +69,12 @@ svn_cmd () {\n maybe_start_httpd () {\n \tloc=${1-svn}\n \n-\ttest_tristate GIT_SVN_TEST_HTTPD\n-\tcase $GIT_SVN_TEST_HTTPD in\n-\ttrue)\n+\tif git env--helper --mode-bool --variable=GIT_TEST_HTTPD --default=0 --exit-code --quiet\t\n+\tthen\n \t\t. \"$TEST_DIRECTORY\"/lib-httpd.sh\n \t\tLIB_HTTPD_SVN=\"$loc\"\n \t\tstart_httpd\n-\t\t;;\n-\tesac\n+\tfi\n }\n \n convert_to_rev_db () {\n@@ -106,8 +104,7 @@ EOF\n }\n \n require_svnserve () {\n-\ttest_tristate GIT_TEST_SVNSERVE\n-\tif ! test \"$GIT_TEST_SVNSERVE\" = true\n+\tif ! git env--helper --mode-bool --variable=GIT_TEST_SVNSERVE --default=0 --exit-code --quiet\n \tthen\n \t\tskip_all='skipping svnserve test. (set $GIT_TEST_SVNSERVE to enable)'\n \t\ttest_done\ndiff --git a/t/lib-httpd.sh b/t/lib-httpd.sh\nindex b3cc62bd36..eef3250552 100644\n--- a/t/lib-httpd.sh\n+++ b/t/lib-httpd.sh\n@@ -41,15 +41,14 @@ then\n \ttest_done\n fi\n \n-test_tristate GIT_TEST_HTTPD\n-if test \"$GIT_TEST_HTTPD\" = false\n+if ! git env--helper --mode-bool --variable=GIT_TEST_HTTPD --default=1 --exit-code --quiet\n then\n \tskip_all=\"Network testing disabled (unset GIT_TEST_HTTPD to enable)\"\n \ttest_done\n fi\n \n if ! test_have_prereq NOT_ROOT; then\n-\ttest_skip_or_die $GIT_TEST_HTTPD \\\n+\ttest_skip_or_die GIT_TEST_HTTPD \\\n \t\t\"Cannot run httpd tests as root\"\n fi\n \n@@ -95,7 +94,7 @@ GIT_TRACE=$GIT_TRACE; export GIT_TRACE\n \n if ! test -x \"$LIB_HTTPD_PATH\"\n then\n-\ttest_skip_or_die $GIT_TEST_HTTPD \"no web server found at '$LIB_HTTPD_PATH'\"\n+\ttest_skip_or_die GIT_TEST_HTTPD \"no web server found at '$LIB_HTTPD_PATH'\"\n fi\n \n HTTPD_VERSION=$($LIB_HTTPD_PATH -v | \\\n@@ -107,19 +106,19 @@ then\n \tthen\n \t\tif ! test $HTTPD_VERSION -ge 2\n \t\tthen\n-\t\t\ttest_skip_or_die $GIT_TEST_HTTPD \\\n+\t\t\ttest_skip_or_die GIT_TEST_HTTPD \\\n \t\t\t\t\"at least Apache version 2 is required\"\n \t\tfi\n \t\tif ! test -d \"$DEFAULT_HTTPD_MODULE_PATH\"\n \t\tthen\n-\t\t\ttest_skip_or_die $GIT_TEST_HTTPD \\\n+\t\t\ttest_skip_or_die GIT_TEST_HTTPD \\\n \t\t\t\t\"Apache module directory not found\"\n \t\tfi\n \n \t\tLIB_HTTPD_MODULE_PATH=\"$DEFAULT_HTTPD_MODULE_PATH\"\n \tfi\n else\n-\ttest_skip_or_die $GIT_TEST_HTTPD \\\n+\ttest_skip_or_die GIT_TEST_HTTPD \\\n \t\t\"Could not identify web server at '$LIB_HTTPD_PATH'\"\n fi\n \n@@ -184,7 +183,7 @@ start_httpd() {\n \tif test $? -ne 0\n \tthen\n \t\tcat \"$HTTPD_ROOT_PATH\"/error.log >&4 2>/dev/null\n-\t\ttest_skip_or_die $GIT_TEST_HTTPD \"web server setup failed\"\n+\t\ttest_skip_or_die GIT_TEST_HTTPD \"web server setup failed\"\n \tfi\n }\n \ndiff --git a/t/t5512-ls-remote.sh b/t/t5512-ls-remote.sh\nindex e3c4a48c85..7161148280 100755\n--- a/t/t5512-ls-remote.sh\n+++ b/t/t5512-ls-remote.sh\n@@ -267,8 +267,7 @@ test_expect_success 'ls-remote --symref omits filtered-out matches' '\n '\n \n test_lazy_prereq GIT_DAEMON '\n-\ttest_tristate GIT_TEST_GIT_DAEMON &&\n-\ttest \"$GIT_TEST_GIT_DAEMON\" != false\n+\tgit env--helper --mode-bool --variable=GIT_TEST_GIT_DAEMON --default=1 --exit-code --quiet\n '\n \n # This test spawns a daemon, so run it only if the user would be OK with\ndiff --git a/t/test-lib-functions.sh b/t/test-lib-functions.sh\nindex 0367cec5fd..527508c350 100644\n--- a/t/test-lib-functions.sh\n+++ b/t/test-lib-functions.sh\n@@ -1035,62 +1035,20 @@ perl () {\n \tcommand \"$PERL_PATH\" \"$@\" 2>&7\n } 7>&2 2>&4\n \n-# Is the value one of the various ways to spell a boolean true/false?\n-test_normalize_bool () {\n-\tgit -c magic.variable=\"$1\" config --bool magic.variable 2>/dev/null\n-}\n-\n-# Given a variable $1, normalize the value of it to one of \"true\",\n-# \"false\", or \"auto\" and store the result to it.\n-#\n-#     test_tristate GIT_TEST_HTTPD\n-#\n-# A variable set to an empty string is set to 'false'.\n-# A variable set to 'false' or 'auto' keeps its value.\n-# Anything else is set to 'true'.\n-# An unset variable defaults to 'auto'.\n-#\n-# The last rule is to allow people to set the variable to an empty\n-# string and export it to decline testing the particular feature\n-# for versions both before and after this change.  We used to treat\n-# both unset and empty variable as a signal for \"do not test\" and\n-# took any non-empty string as \"please test\".\n-\n-test_tristate () {\n-\tif eval \"test x\\\"\\${$1+isset}\\\" = xisset\"\n-\tthen\n-\t\t# explicitly set\n-\t\teval \"\n-\t\t\tcase \\\"\\$$1\\\" in\n-\t\t\t'')\t$1=false ;;\n-\t\t\tauto)\t;;\n-\t\t\t*)\t$1=\\$(test_normalize_bool \\$$1 || echo true) ;;\n-\t\t\tesac\n-\t\t\"\n-\telse\n-\t\teval \"$1=auto\"\n-\tfi\n-}\n-\n # Exit the test suite, either by skipping all remaining tests or by\n-# exiting with an error. If \"$1\" is \"auto\", we then we assume we were\n-# opportunistically trying to set up some tests and we skip. If it is\n-# \"true\", then we report a failure.\n+# exiting with an error. If our prerequisite variable $1 falls back\n+# on a default assume we were opportunistically trying to set up some\n+# tests and we skip. If it is explicitly \"true\", then we report a failure.\n #\n # The error/skip message should be given by $2.\n #\n test_skip_or_die () {\n-\tcase \"$1\" in\n-\tauto)\n+\tif ! git env--helper --mode-bool --variable=$1 --default=0 --exit-code --quiet\n+\tthen\n \t\tskip_all=$2\n \t\ttest_done\n-\t\t;;\n-\ttrue)\n-\t\terror \"$2\"\n-\t\t;;\n-\t*)\n-\t\terror \"BUG: test tristate is '$1' (real error: $2)\"\n-\tesac\n+\tfi\n+\terror \"$2\"\n }\n \n # The following mingw_* functions obey POSIX shell syntax, but are actually\n-- \n2.22.0.rc1.257.g3120a18244\n\n"},{"id":"377598","messageId":"20190619233046.27503-5-avarab@gmail.com","threadId":"51336","inReplyTo":"87imt18a2r.fsf@evledraar.gmail.com","subject":"[PATCH 4/6] tests README: re-flow a previously changed paragraph","fromName":"Ævar Arnfjörð Bjarmason","fromEmail":"avarab@gmail.com","sentAt":"2019-06-19T23:30:44Z","receivedAt":"2019-06-19T23:31:07Z","isPatch":true,"sender":{"key":"avarab@gmail.com","avatar":"https://avatars.githubusercontent.com/u/45301?v=4"},"body":"A previous change to the \"GIT_TEST_GETTEXT_POISON\" variable left this\nparagraph needing to be re-flowed. Let's do that in this separate\nchange to make it easy to see that there's no change here when viewed\nwith \"--word-diff\".\n\nSigned-off-by: Ævar Arnfjörð Bjarmason <avarab@gmail.com>\n---\n t/README | 8 ++++----\n 1 file changed, 4 insertions(+), 4 deletions(-)\n\ndiff --git a/t/README b/t/README\nindex 9a131f472e..072c9854d1 100644\n--- a/t/README\n+++ b/t/README\n@@ -344,10 +344,10 @@ refactor to deal with it. The \"SYMLINKS\" prerequisite is currently\n excluded as so much relies on it, but this might change in the future.\n \n GIT_TEST_GETTEXT_POISON=<boolean> turns all strings marked for\n-translation into gibberish if true. Used for\n-spotting those tests that need to be marked with a C_LOCALE_OUTPUT\n-prerequisite when adding more strings for translation. See \"Testing\n-marked strings\" in po/README for details.\n+translation into gibberish if true. Used for spotting those tests that\n+need to be marked with a C_LOCALE_OUTPUT prerequisite when adding more\n+strings for translation. See \"Testing marked strings\" in po/README for\n+details.\n \n GIT_TEST_SPLIT_INDEX=<boolean> forces split-index mode on the whole\n test suite. Accept any boolean values that are accepted by git-config.\n-- \n2.22.0.rc1.257.g3120a18244\n\n"},{"id":"377600","messageId":"20190619233046.27503-7-avarab@gmail.com","threadId":"51336","inReplyTo":"87imt18a2r.fsf@evledraar.gmail.com","subject":"[PATCH 6/6] tests: make GIT_TEST_FAIL_PREREQS a boolean","fromName":"Ævar Arnfjörð Bjarmason","fromEmail":"avarab@gmail.com","sentAt":"2019-06-19T23:30:46Z","receivedAt":"2019-06-19T23:31:09Z","isPatch":true,"sender":{"key":"avarab@gmail.com","avatar":"https://avatars.githubusercontent.com/u/45301?v=4"},"body":"Change the GIT_TEST_FAIL_PREREQS variable from being \"non-empty?\" to\nbeing a more standard boolean variable. I recently added the variable\nin dfe1a17df9 (\"tests: add a special setup where prerequisites fail\",\n2019-05-13), having to add another \"non-empty?\" special-case is what\nprompted me to write the \"git env--helper\" utility being used here.\n\nConverting this one is a bit tricky since we use it so early and\nfrequently in the guts of the test code itself, so let's set a\nGIT_TEST_FAIL_PREREQS_INTERNAL which can be tested with the old \"test\n-n\" for the purposes of the shell code, and change the user-exposed\nand documented GIT_TEST_FAIL_PREREQS variable to a boolean.\n\nSigned-off-by: Ævar Arnfjörð Bjarmason <avarab@gmail.com>\n---\n t/README                |  2 +-\n t/t0000-basic.sh        | 10 +++++-----\n t/test-lib-functions.sh |  2 +-\n t/test-lib.sh           | 25 +++++++++++++++++++++----\n 4 files changed, 28 insertions(+), 11 deletions(-)\n\ndiff --git a/t/README b/t/README\nindex 072c9854d1..60d5b77bcc 100644\n--- a/t/README\n+++ b/t/README\n@@ -334,7 +334,7 @@ that cannot be easily covered by a few specific test cases. These\n could be enabled by running the test suite with correct GIT_TEST_\n environment set.\n \n-GIT_TEST_FAIL_PREREQS<non-empty?> fails all prerequisites. This is\n+GIT_TEST_FAIL_PREREQS=<boolean> fails all prerequisites. This is\n useful for discovering issues with the tests where say a later test\n implicitly depends on an optional earlier test.\n \ndiff --git a/t/t0000-basic.sh b/t/t0000-basic.sh\nindex 31de7e90f3..e89438e619 100755\n--- a/t/t0000-basic.sh\n+++ b/t/t0000-basic.sh\n@@ -726,7 +726,7 @@ donthaveit=yes\n test_expect_success DONTHAVEIT 'unmet prerequisite causes test to be skipped' '\n \tdonthaveit=no\n '\n-if test -z \"$GIT_TEST_FAIL_PREREQS\" -a $haveit$donthaveit != yesyes\n+if test -z \"$GIT_TEST_FAIL_PREREQS_INTERNAL\" -a $haveit$donthaveit != yesyes\n then\n \tsay \"bug in test framework: prerequisite tags do not work reliably\"\n \texit 1\n@@ -747,7 +747,7 @@ donthaveiteither=yes\n test_expect_success DONTHAVEIT,HAVEIT 'unmet prerequisites causes test to be skipped' '\n \tdonthaveiteither=no\n '\n-if test -z \"$GIT_TEST_FAIL_PREREQS\" -a $haveit$donthaveit$donthaveiteither != yesyesyes\n+if test -z \"$GIT_TEST_FAIL_PREREQS_INTERNAL\" -a $haveit$donthaveit$donthaveiteither != yesyesyes\n then\n \tsay \"bug in test framework: multiple prerequisite tags do not work reliably\"\n \texit 1\n@@ -763,7 +763,7 @@ test_expect_success !LAZY_TRUE 'missing lazy prereqs skip tests' '\n \tdonthavetrue=no\n '\n \n-if test -z \"$GIT_TEST_FAIL_PREREQS\" -a \"$havetrue$donthavetrue\" != yesyes\n+if test -z \"$GIT_TEST_FAIL_PREREQS_INTERNAL\" -a \"$havetrue$donthavetrue\" != yesyes\n then\n \tsay 'bug in test framework: lazy prerequisites do not work'\n \texit 1\n@@ -779,7 +779,7 @@ test_expect_success LAZY_FALSE 'missing negative lazy prereqs will skip' '\n \thavefalse=no\n '\n \n-if test -z \"$GIT_TEST_FAIL_PREREQS\" -a \"$nothavefalse$havefalse\" != yesyes\n+if test -z \"$GIT_TEST_FAIL_PREREQS_INTERNAL\" -a \"$nothavefalse$havefalse\" != yesyes\n then\n \tsay 'bug in test framework: negative lazy prerequisites do not work'\n \texit 1\n@@ -790,7 +790,7 @@ test_expect_success 'tests clean up after themselves' '\n \ttest_when_finished clean=yes\n '\n \n-if test -z \"$GIT_TEST_FAIL_PREREQS\" -a $clean != yes\n+if test -z \"$GIT_TEST_FAIL_PREREQS_INTERNAL\" -a $clean != yes\n then\n \tsay \"bug in test framework: basic cleanup command does not work reliably\"\n \texit 1\ndiff --git a/t/test-lib-functions.sh b/t/test-lib-functions.sh\nindex 527508c350..3fba71c358 100644\n--- a/t/test-lib-functions.sh\n+++ b/t/test-lib-functions.sh\n@@ -309,7 +309,7 @@ test_unset_prereq () {\n }\n \n test_set_prereq () {\n-\tif test -n \"$GIT_TEST_FAIL_PREREQS\"\n+\tif test -n \"$GIT_TEST_FAIL_PREREQS_INTERNAL\"\n \tthen\n \t\tcase \"$1\" in\n \t\t# The \"!\" case is handled below with\ndiff --git a/t/test-lib.sh b/t/test-lib.sh\nindex bdd5017d24..552461435e 100644\n--- a/t/test-lib.sh\n+++ b/t/test-lib.sh\n@@ -1389,6 +1389,27 @@ yes () {\n \tdone\n }\n \n+# The GIT_TEST_FAIL_PREREQS code hooks into test_set_prereq(), and\n+# thus needs to be set up really early, and set an internal variable\n+# for convenience so the hot test_set_prereq() codepath doesn't need\n+# to call \"git env--helper\". Only do that work if needed by seeing if\n+# GIT_TEST_FAIL_PREREQS is set at all.\n+GIT_TEST_FAIL_PREREQS_INTERNAL=\n+if test -n \"$GIT_TEST_FAIL_PREREQS\"\n+then\n+\tif git env--helper --mode-bool --variable=GIT_TEST_FAIL_PREREQS \\\n+\t\t--default=0 --exit-code --quiet\n+\tthen\n+\t\tGIT_TEST_FAIL_PREREQS_INTERNAL=true\n+\t\ttest_set_prereq FAIL_PREREQS\n+\tfi\n+else\n+\ttest_lazy_prereq FAIL_PREREQS '\n+\t\tgit env--helper --mode-bool --variable=GIT_TEST_FAIL_PREREQS \\\n+\t\t\t--default=0 --exit-code --quiet\n+\t'\n+fi\n+\n # Fix some commands on Windows\n uname_s=$(uname -s)\n case $uname_s in\n@@ -1611,7 +1632,3 @@ test_lazy_prereq SHA1 '\n test_lazy_prereq REBASE_P '\n \ttest -z \"$GIT_TEST_SKIP_REBASE_P\"\n '\n-\n-test_lazy_prereq FAIL_PREREQS '\n-\ttest -n \"$GIT_TEST_FAIL_PREREQS\"\n-'\n-- \n2.22.0.rc1.257.g3120a18244\n\n"},{"id":"377644","messageId":"CACsJy8A5K4hNKy1LupQJ8is4AgTAyzfW+qhMYkcBmS_kvnE23Q@mail.gmail.com","threadId":"51336","inReplyTo":"20190619185934.GC28145@sigill.intra.peff.net","subject":"Re: [PATCH] fetch: only run 'gc' once when fetching multiple remotes","fromName":"Duy Nguyen","fromEmail":"pclouds@gmail.com","sentAt":"2019-06-20T10:11:03Z","receivedAt":"2019-06-20T10:11:32Z","isPatch":true,"sender":{"key":"pclouds@gmail.com","avatar":"https://avatars.githubusercontent.com/u/720?v=4"},"body":"On Thu, Jun 20, 2019 at 1:59 AM Jeff King <peff@peff.net> wrote:\n> I was surprised that we needed a new command-line option here, but I\n> guess the sub-fetch processes really have no idea that they're\n> subservient to a multi-remote fetch (they do get \"--append\", but of\n> course somebody could specify that independently).\n>\n> Another option would be to just pass \"-c gc.auto=0\" to the child\n> processes to inhibit auto-gc. But maybe it makes sense to have a nicer\n> interface (after all, somebody else could be doing the same \"let's do a\n> bunch of fetches in a row\" without using the multi-fetch code).\n\nNah to me -c is much nicer (and flexible too). The only thing I'm not\nsure about is whether a user could override it. If fetch.c adds -c\ngc.auto=0 automatically, and the user wants auto gc back, will \"git -c\ngc.auto=non-zero fetch --multiple\" still work?\n\nI haven't checked git_config_push_parameter() carefully, but I have an\nimpression that the parameter order there is \"wrong\", at least in this\ncase.\n\n> Though there I kind of wonder if this would apply to other scripted\n> uses, too. E.g., if I'm doing a bunch of commits, I might want to\n> inhibit auto-gc and then run it myself at the end. Should we support\n> \"GIT_AUTO_GC=0\" in the environment (and a matching \"git --no-auto-gc\n> ...\" option that could be used here)?\n\nexport GIT_CONFIG=gc.auto=0 ?\n-- \nDuy\n"},{"id":"377645","messageId":"20190620102103.GA15212@sigill.intra.peff.net","threadId":"51336","inReplyTo":"CACsJy8A5K4hNKy1LupQJ8is4AgTAyzfW+qhMYkcBmS_kvnE23Q@mail.gmail.com","subject":"Re: [PATCH] fetch: only run 'gc' once when fetching multiple remotes","fromName":"Jeff King","fromEmail":"peff@peff.net","sentAt":"2019-06-20T10:21:03Z","receivedAt":"2019-06-20T10:21:06Z","isPatch":true,"sender":{"key":"peff@peff.net","avatar":"https://avatars.githubusercontent.com/u/45925?v=4"},"body":"On Thu, Jun 20, 2019 at 05:11:03PM +0700, Duy Nguyen wrote:\n\n> > Another option would be to just pass \"-c gc.auto=0\" to the child\n> > processes to inhibit auto-gc. But maybe it makes sense to have a nicer\n> > interface (after all, somebody else could be doing the same \"let's do a\n> > bunch of fetches in a row\" without using the multi-fetch code).\n> \n> Nah to me -c is much nicer (and flexible too). The only thing I'm not\n> sure about is whether a user could override it. If fetch.c adds -c\n> gc.auto=0 automatically, and the user wants auto gc back, will \"git -c\n> gc.auto=non-zero fetch --multiple\" still work?\n> \n> I haven't checked git_config_push_parameter() carefully, but I have an\n> impression that the parameter order there is \"wrong\", at least in this\n> case.\n\nIt depends what you're trying to get it to do.\n\nI'd expect that command to turn on auto-gc for just the outer fetch\n(i.e., overriding any on-disk disabling of auto-gc), but keep it off for\nthe child fetches. And I think that is how it would behave: the outer\nfetch only sees the config you provided. The inner ones see\n\"gc.auto=non-zero gc.auto=0-zero\" because git_config_push_parameter()\nappends. And they accept the latter under last-one-wins rules.\n\nIf you expect to be able to re-enable auto-gc in the child fetches, then\nI don't think there would be a way to do that.\n\n> > Though there I kind of wonder if this would apply to other scripted\n> > uses, too. E.g., if I'm doing a bunch of commits, I might want to\n> > inhibit auto-gc and then run it myself at the end. Should we support\n> > \"GIT_AUTO_GC=0\" in the environment (and a matching \"git --no-auto-gc\n> > ...\" option that could be used here)?\n> \n> export GIT_CONFIG=gc.auto=0 ?\n\nAlmost. The parser for GIT_CONFIG_PARAMETERS is very picky about seeing\nsingle quotes around each item, which makes it a little unfriendly to\nuse manually. Plus there may be existing values if your script was\ninvoked as \"git -c whatever my-script\".\n\nIt's probably not that big a deal for a script to just use \"git -c\ngc.auto\" to inhibit auto-gc for each command that needs it.\n\n-Peff\n"},{"id":"377646","messageId":"CACsJy8AjXXOpcKrSV4z6kEM=eyFDWSyf==tJZzvDyEN591XdGw@mail.gmail.com","threadId":"51336","inReplyTo":"87imt18a2r.fsf@evledraar.gmail.com","subject":"Re: [RFC/PATCH] gc: run more pre-detach operations under lock","fromName":"Duy Nguyen","fromEmail":"pclouds@gmail.com","sentAt":"2019-06-20T10:26:34Z","receivedAt":"2019-06-20T10:27:02Z","isPatch":true,"sender":{"key":"pclouds@gmail.com","avatar":"https://avatars.githubusercontent.com/u/720?v=4"},"body":"On Thu, Jun 20, 2019 at 5:49 AM Ævar Arnfjörð Bjarmason\n<avarab@gmail.com> wrote:\n>\n>\n> On Wed, Jun 19 2019, Jeff King wrote:\n>\n> > On Wed, Jun 19, 2019 at 08:01:55PM +0200, Ævar Arnfjörð Bjarmason wrote:\n> >\n> >> > You could sort of avoid the problem here too with\n> >> >\n> >> > parallel 'git fetch --no-auto-gc {}' ::: $(git remote)\n> >> > git gc --auto\n> >> >\n> >> > It's definitely simpler, but of course we have to manually add\n> >> > --no-auto-gc in everywhere we need, so not quite as elegant.\n> >> >\n> >> > Actually you could already do that with 'git -c gc.auto=false fetch', I guess.\n> >>\n> >> The point of the 'parallel' example is to show disconnected git\n> >> commands, think trying to run 'git' in a terminal while your editor\n> >> asynchronously runs a polling 'fetch', or a server with multiple\n> >> concurrent clients running 'gc --auto'.\n> >>\n> >> That's the question my RFC patch raises. As far as I can tell the\n> >> approach in your patch is only needed because our locking for gc is\n> >> buggy, rather than introduce the caveat that an fetch(N) operation won't\n> >> do \"gc\" until it's finished (we may have hundreds, thousands of remotes,\n> >> I use that for some more obscure use-cases) shouldn't we just fix the\n> >> locking?\n> >\n> > I think there may be room for both approaches. Yours fixes the repeated\n> > message in the more general case, but Duy's suggestion is the most\n> > efficient thing.\n> >\n> > I agree that the \"thousands of remotes\" case means we might want to gc\n> > in the interim. But we probably ought to do that deterministically\n> > rather than hoping that the pattern of lock contention makes sense.\n>\n> We do it deterministically, when gc.auto thresholds et al are exceeded\n> we kick one off without waiting for other stuff, if we can get the lock.\n>\n> I don't think this desire to just wait a bit until all the fetches are\n> complete makes sense as a special-case.\n>\n> If, as you noted in <20190619190845.GD28145@sigill.intra.peff.net>, the\n> desire is to reduce GC CPU use then you're better off just tweaking the\n> limits upwards. Then you get that with everything, like when you run\n> \"commit\" in a for-loop, not just this one special case of \"fetch\".\n>\n> We have existing potentially long-running operations like \"fetch\",\n> \"rebase\" and \"git svn fetch\" that run \"gc --auto\" for their incremental\n> steps, and that's a feature.\n\ngc --auto is added at arbitrary points to help garbage collection. I\ndon't think it's ever intended to \"do gc at this and that exact\nmoment\", just \"hey this command has taken a lot of time already (i.e.\nno instant response needed) and it may have added a bit more garbage,\nlet's just check real quick\".\n\n> It keeps \"gc --auto\" dumb enough to avoid a pathological case where\n> we'll have a ballooning objects dir because we figure we can run\n> something \"at the end\", when \"the end\" could be hours away, and we're\n> adding a new pack or hundreds of loose objects every second.\n\nAre we optimizing for a rare (large scale) case? Such setup requires\ntuning regardless to me.\n\n> So I don't think Duy's patch is a good way to go.\n\nThis reminds me of being perfect is the enemy of the good. A normal\nuser has a couple remotes at most, finishing fast (enough) and in such\ncase it's a good idea to wait until everything is in before running\ngc.\n\nOf course making git-gc more robust wrt. parallel access is great, but\nit's hard work. Dealing with locks is always tricky, especially when\nnew locks can come up any time.\n\nHaving said that, I don't mind if my patch gets dropped. It was just a\n\"hey that multiple gc output looks strange, hah the fix is quite\nsimple\" moment for me.\n-- \nDuy\n"},{"id":"377649","messageId":"20190620104325.GA15942@sigill.intra.peff.net","threadId":"51336","inReplyTo":"87imt18a2r.fsf@evledraar.gmail.com","subject":"Re: [RFC/PATCH] gc: run more pre-detach operations under lock","fromName":"Jeff King","fromEmail":"peff@peff.net","sentAt":"2019-06-20T10:43:25Z","receivedAt":"2019-06-20T10:43:28Z","isPatch":true,"sender":{"key":"peff@peff.net","avatar":"https://avatars.githubusercontent.com/u/45925?v=4"},"body":"On Thu, Jun 20, 2019 at 12:49:32AM +0200, Ævar Arnfjörð Bjarmason wrote:\n\n> We do it deterministically, when gc.auto thresholds et al are exceeded\n> we kick one off without waiting for other stuff, if we can get the lock.\n> \n> I don't think this desire to just wait a bit until all the fetches are\n> complete makes sense as a special-case.\n> \n> If, as you noted in <20190619190845.GD28145@sigill.intra.peff.net>, the\n> desire is to reduce GC CPU use then you're better off just tweaking the\n> limits upwards. Then you get that with everything, like when you run\n> \"commit\" in a for-loop, not just this one special case of \"fetch\".\n\nIf you tweak the limit upwards, then you're more likely to exist in the\nnon-gc'd state, where reads are penalized. The gc limit is a tradeoff\nbetween paying the price for maintenance work versus paying the price\nfor having an unmaintained state. So the optimal time is generally right\nafter you've finished a big chunk of writing, but before you've started\ndoing a bunch of reading (for continuous operations that are reading and\nwriting, there's probably some periodic crossover point every N units of\noperation).\n\nThat said, I doubt it matters more than a few percent either way (if\nthat). So I'm fine if we want to optimize for simplicity.\n\n-Peff\n"},{"id":"377682","messageId":"xmqqo92snn0o.fsf@gitster-ct.c.googlers.com","threadId":"51336","inReplyTo":"20190619233046.27503-1-avarab@gmail.com","subject":"Re: [PATCH 0/6] Change <non-empty?> GIT_TEST_* variables to <boolean>","fromName":"Junio C Hamano","fromEmail":"gitster@pobox.com","sentAt":"2019-06-20T18:13:11Z","receivedAt":"2019-06-20T18:20:52Z","isPatch":true,"sender":{"key":"gitster@pobox.com","avatar":"https://avatars.githubusercontent.com/u/54884?v=4"},"body":"Ævar Arnfjörð Bjarmason  <avarab@gmail.com> writes:\n\n> This changes the remaining <non-empty?> special snowflake test modes\n> to <boolean> and gets rid of test_tristate() in favor of the now\n> standard \"boolea\" test.\n>\n> I'm replying to my \"gc: run more pre-detach operations under lock\"\n> thread because one of the things my WIP patches to make gc locking\n> less sucky depends on is new GIT_TEST_GC_* test modes to test its\n> racyness, which in turn depends on these cleanups.\n\nThat sounds like the \"gc: run more ...\" depends on these (iow, that\nshould be the reply to these, not the other way around)?\n\nI am asking because I see obvious value in these \"uniformly require\n<boolean>\" consistency change (which could be backward incompatible,\nbut as long as these are GIT_TEST_*, we do not mind too much forcing\ndevelopers to adjust), but not yet in the \"gc: run more ...\" one,\nand do not want these to be taken hostage.\n\nThanks.\n\n>\n> Ævar Arnfjörð Bjarmason (6):\n>   env--helper: new undocumented builtin wrapping git_env_*()\n>   t6040 test: stop using global \"script\" variable\n>   tests: make GIT_TEST_GETTEXT_POISON a boolean\n>   tests README: re-flow a previously changed paragraph\n>   tests: replace test_tristate with \"git env--helper\"\n>   tests: make GIT_TEST_FAIL_PREREQS a boolean\n>\n>  .gitignore                |  1 +\n>  Makefile                  |  1 +\n>  builtin.h                 |  1 +\n>  builtin/env--helper.c     | 74 +++++++++++++++++++++++++++++++++++++++\n>  ci/lib.sh                 |  2 +-\n>  gettext.c                 |  6 ++--\n>  git-sh-i18n.sh            |  4 ++-\n>  git.c                     |  1 +\n>  po/README                 |  2 +-\n>  t/README                  | 12 +++----\n>  t/lib-git-daemon.sh       |  7 ++--\n>  t/lib-git-svn.sh          | 11 +++---\n>  t/lib-httpd.sh            | 15 ++++----\n>  t/t0000-basic.sh          | 10 +++---\n>  t/t0016-env-helper.sh     | 70 ++++++++++++++++++++++++++++++++++++\n>  t/t0205-gettext-poison.sh |  2 +-\n>  t/t5512-ls-remote.sh      |  3 +-\n>  t/t6040-tracking-info.sh  |  6 ++--\n>  t/t7201-co.sh             |  2 +-\n>  t/t9902-completion.sh     |  2 +-\n>  t/test-lib-functions.sh   | 58 +++++-------------------------\n>  t/test-lib.sh             | 29 ++++++++++++---\n>  22 files changed, 220 insertions(+), 99 deletions(-)\n>  create mode 100644 builtin/env--helper.c\n>  create mode 100755 t/t0016-env-helper.sh\n"},{"id":"377688","messageId":"xmqqef3onl29.fsf@gitster-ct.c.googlers.com","threadId":"51336","inReplyTo":"20190619191037.GE28145@sigill.intra.peff.net","subject":"Re: [RFC/PATCH] gc: run more pre-detach operations under lock","fromName":"Junio C Hamano","fromEmail":"gitster@pobox.com","sentAt":"2019-06-20T18:55:26Z","receivedAt":"2019-06-20T18:55:31Z","isPatch":true,"sender":{"key":"gitster@pobox.com","avatar":"https://avatars.githubusercontent.com/u/54884?v=4"},"body":"Jeff King <peff@peff.net> writes:\n\n> I think there may be room for both approaches. Yours fixes the repeated\n> message in the more general case, but Duy's suggestion is the most\n> efficient thing.\n\nYeah, not just the most efficient, but it is a low-hanging-fruit\nthat is very obvious.\n\n> I agree that the \"thousands of remotes\" case means we might want to gc\n> in the interim. But we probably ought to do that deterministically\n> rather than hoping that the pattern of lock contention makes sense.\n\nIn the process chain starting from the topmost \"git fetch\n<multiple>\", that calls multiple \"git fetch <one>\" for individual\nremotes, that does network transfer and calls \"git index-pack\" (or\n\"git unpack-objects\"), the bottommost layer knows how much cruft one\nstep among \"thousands of remotes\" created for a later \"gc\", but\nthere is no mechanism for them to report the information back to\ntheir callers.  Unlike \"git svn\" that periodically calls the auto gc\nevery N commits and can claim to be aware of its cruft creation rate\n;-), the information available to the topmost \"git fetch\" is only\nthe number of underlying fetches, counting a no-op fetch and a fetch\nthat is close to a full clone equally, which is not a good way to\ngauge the cruft creation rate X-<.\n\nA useful deteministic triggering would be a good thing to aim in the\nlonger run, but would be somewhat involved to design and implement,\nI am afraid.\n"},{"id":"377690","messageId":"xmqqa7ecnjot.fsf@gitster-ct.c.googlers.com","threadId":"51336","inReplyTo":"20190619233046.27503-2-avarab@gmail.com","subject":"Re: [PATCH 1/6] env--helper: new undocumented builtin wrapping git_env_*()","fromName":"Junio C Hamano","fromEmail":"gitster@pobox.com","sentAt":"2019-06-20T19:25:06Z","receivedAt":"2019-06-20T19:25:19Z","isPatch":true,"sender":{"key":"gitster@pobox.com","avatar":"https://avatars.githubusercontent.com/u/54884?v=4"},"body":"Ævar Arnfjörð Bjarmason  <avarab@gmail.com> writes:\n\n> +\tstruct option opts[] = {\n> +\t\tOPT_CMDMODE(0, \"mode-bool\", &cmdmode,\n> +\t\t\t    N_(\"invoke git_env_bool(...)\"), ENV_HELPER_BOOL),\n> +\t\tOPT_CMDMODE(0, \"mode-ulong\", &cmdmode,\n> +\t\t\t    N_(\"invoke git_env_ulong(...)\"), ENV_HELPER_ULONG),\n\nIt may be a fairly useless nitpick, but is there a reason why we\nshould not just reuse \"--type=<bool|int|...>\" that is understood by\n\"git config\"?  In the longer term, it might make sense to expose\nthis subcommand as \"git env\" that sits next to \"git config\", and at\nthat point we would regret if we miss the opportunity for obvious\nparallel between the two.\n\n> +\t\tOPT_STRING(0, \"variable\", &env_variable, N_(\"name\"),\n> +\t\t\t   N_(\"which environment variable to ask git_env_*(...) about\")),\n> +\t\tOPT_STRING(0, \"default\", &env_default, N_(\"value\"),\n> +\t\t\t   N_(\"what default value does git_env_*(...) fall back on?\")),\n> +\t\tOPT_BOOL(0, \"exit-code\", &exit_code,\n> +\t\t\t N_(\"exit code determined by truth of the git_env_*() function\")),\n> +\t\tOPT_BOOL(0, \"quiet\", &quiet,\n> +\t\t\t N_(\"don't print the git_env_*() return value\")),\n> +\t\tOPT_END(),\n> +\t};\n> +\n> +\tif (parse_options(argc, argv, prefix, opts, env__helper_usage, 0))\n> +\t\tusage_with_options(env__helper_usage, opts);\n> +\tif (!env_variable || !env_default ||\n> +\t    !*env_variable || !*env_default)\n> +\t\tusage_with_options(env__helper_usage, opts);\n\nThe default must be supplied?  That makes it smell like it should\nnot be a command line \"option\", as it is not optional at all.  Off\nthe top of my head without the benefit of insight you gained by\nworking on the remainder of the series (read: this is merely my knee\njerk reaction, and it is very probable that there is sound rationale\nwhy your design is not like what I'll outline), I would imagine an\ninterface that look more like:\n\n $ git env --type=bool --default=yes GIT_TEST_FOO \n\n    Says \"true\"/\"false\" on the standard output and exits with\n    success status if $GIT_TEST_FOO is set to the usual\n    truth/falsehood values, and gives \"true\" on the exits with\n    success status if $GIT_TEST_FOO is unset.\n\n $ git env --type=bool GIT_TEST_FOO\n\n    The same as above when $GIT_TEST_FOO is set; exits with failure\n    when GIT_TEST_FOO is not exported.\n\n $ git env --type=bool [--default=yes] --exit-code GIT_TEST_FOO\n\n    Similar to the above two, but the standard output is silent, and\n    true/false/failure are given via the exit status (perhaps 0, 1\n    and 125 or something like that).\n\n> +\tswitch (cmdmode) {\n> +\tcase ENV_HELPER_BOOL:\n> +\t\ttmp_int = strtol(env_default, (char **)&env_default, 10);\n> +\t\tif (*env_default) {\n> +\t\t\terror(_(\"option `--default' expects a numerical value with `--mode-bool`\"));\n\nNo kidding.  \"--mode-bool\" does not like \"--default=false\"?\n\n"},{"id":"377692","messageId":"xmqqy31wm3ql.fsf@gitster-ct.c.googlers.com","threadId":"51336","inReplyTo":"20190619233046.27503-3-avarab@gmail.com","subject":"Re: [PATCH 2/6] t6040 test: stop using global \"script\" variable","fromName":"Junio C Hamano","fromEmail":"gitster@pobox.com","sentAt":"2019-06-20T19:54:58Z","receivedAt":"2019-06-20T19:55:06Z","isPatch":true,"sender":{"key":"gitster@pobox.com","avatar":"https://avatars.githubusercontent.com/u/54884?v=4"},"body":"Ævar Arnfjörð Bjarmason  <avarab@gmail.com> writes:\n\n> Change test code added in c0234b2ef6 (\"stat_tracking_info(): clear\n> object flags used during counting\", 2008-07-03) to stop using the\n> \"script\" variable also used for lazy prerequisites in\n> test-lib-functions.sh.\n>\n> Since this test uses test_i18ncmp and expects to use its own \"script\"\n> variable twice it implicitly depends on the C_LOCALE_OUTPUT\n> prerequisite not being a lazy prerequisite. A follow-up change will\n> make it a lazy prerequisite, so we must remove this landmine before\n> inadvertently stepping on it as we make that change.\n\nWell spotted (eh, I suspect that you didn't until you actually stomped\non the landmine and saw it trigger, and then pretending to have had\nthe perfect foresight in this series, which is perfectly fine ;-),\nand nicely done.\n\n>\n> Signed-off-by: Ævar Arnfjörð Bjarmason <avarab@gmail.com>\n> ---\n>  t/t6040-tracking-info.sh | 6 +++---\n>  1 file changed, 3 insertions(+), 3 deletions(-)\n>\n> diff --git a/t/t6040-tracking-info.sh b/t/t6040-tracking-info.sh\n> index 716283b274..970b25a289 100755\n> --- a/t/t6040-tracking-info.sh\n> +++ b/t/t6040-tracking-info.sh\n> @@ -38,7 +38,7 @@ test_expect_success setup '\n>  \tadvance h\n>  '\n>  \n> -script='s/^..\\(b.\\) *[0-9a-f]* \\(.*\\)$/\\1 \\2/p'\n> +t6040_script='s/^..\\(b.\\) *[0-9a-f]* \\(.*\\)$/\\1 \\2/p'\n>  cat >expect <<\\EOF\n>  b1 [ahead 1, behind 1] d\n>  b2 [ahead 1, behind 1] d\n> @@ -53,7 +53,7 @@ test_expect_success 'branch -v' '\n>  \t\tcd test &&\n>  \t\tgit branch -v\n>  \t) |\n> -\tsed -n -e \"$script\" >actual &&\n> +\tsed -n -e \"$t6040_script\" >actual &&\n>  \ttest_i18ncmp expect actual\n>  '\n>  \n> @@ -71,7 +71,7 @@ test_expect_success 'branch -vv' '\n>  \t\tcd test &&\n>  \t\tgit branch -vv\n>  \t) |\n> -\tsed -n -e \"$script\" >actual &&\n> +\tsed -n -e \"$t6040_script\" >actual &&\n>  \ttest_i18ncmp expect actual\n>  '\n"},{"id":"377694","messageId":"xmqqtvckm3h8.fsf@gitster-ct.c.googlers.com","threadId":"51336","inReplyTo":"20190619233046.27503-4-avarab@gmail.com","subject":"Re: [PATCH 3/6] tests: make GIT_TEST_GETTEXT_POISON a boolean","fromName":"Junio C Hamano","fromEmail":"gitster@pobox.com","sentAt":"2019-06-20T20:00:35Z","receivedAt":"2019-06-20T20:00:44Z","isPatch":true,"sender":{"key":"gitster@pobox.com","avatar":"https://avatars.githubusercontent.com/u/54884?v=4"},"body":"Ævar Arnfjörð Bjarmason  <avarab@gmail.com> writes:\n\n> Change the GIT_TEST_GETTEXT_POISON variable from being \"non-empty?\" to\n> being a more standard boolean variable.\n>\n> Since it needed to be checked in both C code and shellscript (via test\n> -n) it was one of the remaining shellscript-like variables. Now that\n> we have \"git env--helper\" we can change that.\n>\n> Signed-off-by: Ævar Arnfjörð Bjarmason <avarab@gmail.com>\n> ---\n\nHmph.  Even though I earlier said \"we do not terribly mind breaking\ndevelopers and that is why we allow these patches\", I have second\nthoughts.  Turning \"If it is empty, it is false\" to \"if you want to\nsay false, say it in one of those approved ways\" is one thing.\nForcing SWITCH=YesPlease to be rewritten to SWITCH=yes is quite\ndifferent---we are breaking everybody who would have to read and\nfollow po/README and t/README.\n\nWe _might_ have to grandfarther YesPlease as a special value that is\nunderstood by \"git env\" (but not \"git config\") to ease the\ntransition, as that token has been used as a sample true value in\nmany places.\n\nBut let's read on.  Assuming that breaking those who hardcoded\nYesPlease in their scripts is OK, this patch looked sensible.\n\nThanks.\n\n"},{"id":"377695","messageId":"xmqqmuicm3d4.fsf@gitster-ct.c.googlers.com","threadId":"51336","inReplyTo":"20190619233046.27503-1-avarab@gmail.com","subject":"Re: [PATCH 0/6] Change <non-empty?> GIT_TEST_* variables to <boolean>","fromName":"Junio C Hamano","fromEmail":"gitster@pobox.com","sentAt":"2019-06-20T20:03:03Z","receivedAt":"2019-06-20T20:03:07Z","isPatch":true,"sender":{"key":"gitster@pobox.com","avatar":"https://avatars.githubusercontent.com/u/54884?v=4"},"body":"Ævar Arnfjörð Bjarmason  <avarab@gmail.com> writes:\n\n> This changes the remaining <non-empty?> special snowflake test modes\n> to <boolean> and gets rid of test_tristate() in favor of the now\n> standard \"boolea\" test.\n\nIs that \"boolean\" test?\n\nI had a lot of trouble with the external interface to \"env--helper\",\nbut I kind of liked the changes to the tests that makes the use of\nthese environment variables uniform and consistent.  One fewer\nthings to remember.\n\nIn addition to the other review on 1/6, t0016 is taken at the tip of\n'pu'; we would want to renumber to avoid test-lint complaints.\n"},{"id":"377701","messageId":"87fto47z0f.fsf@evledraar.gmail.com","threadId":"51336","inReplyTo":"xmqqo92snn0o.fsf@gitster-ct.c.googlers.com","subject":"Re: [PATCH 0/6] Change <non-empty?> GIT_TEST_* variables to <boolean>","fromName":"Ævar Arnfjörð Bjarmason","fromEmail":"avarab@gmail.com","sentAt":"2019-06-20T21:00:48Z","receivedAt":"2019-06-20T21:00:53Z","isPatch":true,"sender":{"key":"avarab@gmail.com","avatar":"https://avatars.githubusercontent.com/u/45301?v=4"},"body":"\nOn Thu, Jun 20 2019, Junio C Hamano wrote:\n\n> Ævar Arnfjörð Bjarmason  <avarab@gmail.com> writes:\n>\n>> This changes the remaining <non-empty?> special snowflake test modes\n>> to <boolean> and gets rid of test_tristate() in favor of the now\n>> standard \"boolea\" test.\n>>\n>> I'm replying to my \"gc: run more pre-detach operations under lock\"\n>> thread because one of the things my WIP patches to make gc locking\n>> less sucky depends on is new GIT_TEST_GC_* test modes to test its\n>> racyness, which in turn depends on these cleanups.\n>\n> That sounds like the \"gc: run more ...\" depends on these (iow, that\n> should be the reply to these, not the other way around)?\n\nYeah the tests in that otherwise unrelated series loosely depends on\nthis, so I figured I'd try to get this in first.\n\n> I am asking because I see obvious value in these \"uniformly require\n> <boolean>\" consistency change (which could be backward incompatible,\n> but as long as these are GIT_TEST_*, we do not mind too much forcing\n> developers to adjust), but not yet in the \"gc: run more ...\" one,\n> and do not want these to be taken hostage.\n\nYeah these should be viewed independently. Perhaps I shouldn't have\nfilled that In-Reply-To...\n\n>>\n>> Ævar Arnfjörð Bjarmason (6):\n>>   env--helper: new undocumented builtin wrapping git_env_*()\n>>   t6040 test: stop using global \"script\" variable\n>>   tests: make GIT_TEST_GETTEXT_POISON a boolean\n>>   tests README: re-flow a previously changed paragraph\n>>   tests: replace test_tristate with \"git env--helper\"\n>>   tests: make GIT_TEST_FAIL_PREREQS a boolean\n>>\n>>  .gitignore                |  1 +\n>>  Makefile                  |  1 +\n>>  builtin.h                 |  1 +\n>>  builtin/env--helper.c     | 74 +++++++++++++++++++++++++++++++++++++++\n>>  ci/lib.sh                 |  2 +-\n>>  gettext.c                 |  6 ++--\n>>  git-sh-i18n.sh            |  4 ++-\n>>  git.c                     |  1 +\n>>  po/README                 |  2 +-\n>>  t/README                  | 12 +++----\n>>  t/lib-git-daemon.sh       |  7 ++--\n>>  t/lib-git-svn.sh          | 11 +++---\n>>  t/lib-httpd.sh            | 15 ++++----\n>>  t/t0000-basic.sh          | 10 +++---\n>>  t/t0016-env-helper.sh     | 70 ++++++++++++++++++++++++++++++++++++\n>>  t/t0205-gettext-poison.sh |  2 +-\n>>  t/t5512-ls-remote.sh      |  3 +-\n>>  t/t6040-tracking-info.sh  |  6 ++--\n>>  t/t7201-co.sh             |  2 +-\n>>  t/t9902-completion.sh     |  2 +-\n>>  t/test-lib-functions.sh   | 58 +++++-------------------------\n>>  t/test-lib.sh             | 29 ++++++++++++---\n>>  22 files changed, 220 insertions(+), 99 deletions(-)\n>>  create mode 100644 builtin/env--helper.c\n>>  create mode 100755 t/t0016-env-helper.sh\n"},{"id":"377704","messageId":"20190620210915.11297-1-avarab@gmail.com","threadId":"51336","inReplyTo":"20190619233046.27503-1-avarab@gmail.com","subject":"[PATCH v2 0/8] Change <non-empty?> GIT_TEST_* variables to <boolean>","fromName":"Ævar Arnfjörð Bjarmason","fromEmail":"avarab@gmail.com","sentAt":"2019-06-20T21:09:07Z","receivedAt":"2019-06-20T21:09:29Z","isPatch":true,"sender":{"key":"avarab@gmail.com","avatar":"https://avatars.githubusercontent.com/u/45301?v=4"},"body":"This v2 fixes tricky bugs I noticed after sending v1 in calling\ngettext so early in the setup, and the t0016 name clash with pu Junio\npointed out.\n\nI didn't change the \"env--helper\" interface as suggested because I\nalready had this ready and figured I'd send a v2 for review of the\nstuff I have now.\n\nThe interface suggested in\n<xmqqa7ecnjot.fsf@gitster-ct.c.googlers.com> is indeed prettier. FWIW\nI did things like --mode-bool instead of --type=bool because it's\neasier to do just with the getopt framework, likewise --variable=X\ninstead of \"X\" being last on the argv since you can do it all with the\nflag parsing doing the work for you, and since it's an internal-only\ncommand I figured it didn't matter much.\n\nÆvar Arnfjörð Bjarmason (8):\n  config tests: simplify include cycle test\n  env--helper: new undocumented builtin wrapping git_env_*()\n  config.c: refactor die_bad_number() to not call gettext() early\n  t6040 test: stop using global \"script\" variable\n  tests: make GIT_TEST_GETTEXT_POISON a boolean\n  tests README: re-flow a previously changed paragraph\n  tests: replace test_tristate with \"git env--helper\"\n  tests: make GIT_TEST_FAIL_PREREQS a boolean\n\n .gitignore                |  1 +\n Makefile                  |  1 +\n builtin.h                 |  1 +\n builtin/env--helper.c     | 74 +++++++++++++++++++++++++++++++++\n ci/lib.sh                 |  2 +-\n config.c                  | 28 +++++++++----\n gettext.c                 |  6 +--\n git-sh-i18n.sh            |  4 +-\n git.c                     |  1 +\n po/README                 |  2 +-\n t/README                  | 12 +++---\n t/lib-git-daemon.sh       |  7 ++--\n t/lib-git-svn.sh          | 11 ++---\n t/lib-httpd.sh            | 15 ++++---\n t/t0000-basic.sh          | 10 ++---\n t/t0017-env-helper.sh     | 86 +++++++++++++++++++++++++++++++++++++++\n t/t0205-gettext-poison.sh |  7 +++-\n t/t1305-config-include.sh | 21 ++++------\n t/t5512-ls-remote.sh      |  3 +-\n t/t6040-tracking-info.sh  |  6 +--\n t/t7201-co.sh             |  2 +-\n t/t9902-completion.sh     |  2 +-\n t/test-lib-functions.sh   | 58 ++++----------------------\n t/test-lib.sh             | 33 +++++++++++----\n 24 files changed, 266 insertions(+), 127 deletions(-)\n create mode 100644 builtin/env--helper.c\n create mode 100755 t/t0017-env-helper.sh\n\nRange-diff:\n-:  ---------- > 1:  c3483c37a1 config tests: simplify include cycle test\n1:  8da3cd4240 ! 2:  e689759f7c env--helper: new undocumented builtin wrapping git_env_*()\n    @@ -154,10 +154,10 @@\n      \t{ \"fetch\", cmd_fetch, RUN_SETUP },\n      \t{ \"fetch-pack\", cmd_fetch_pack, RUN_SETUP | NO_PARSEOPT },\n     \n    - diff --git a/t/t0016-env-helper.sh b/t/t0016-env-helper.sh\n    + diff --git a/t/t0017-env-helper.sh b/t/t0017-env-helper.sh\n      new file mode 100755\n      --- /dev/null\n    - +++ b/t/t0016-env-helper.sh\n    + +++ b/t/t0017-env-helper.sh\n     @@\n     +#!/bin/sh\n     +\n-:  ---------- > 3:  f759d5e91e config.c: refactor die_bad_number() to not call gettext() early\n2:  8315c4ecdc = 4:  1ac798e8ce t6040 test: stop using global \"script\" variable\n3:  f1ee208d70 ! 5:  d7d6e6c874 tests: make GIT_TEST_GETTEXT_POISON a boolean\n    @@ -7,7 +7,30 @@\n     \n         Since it needed to be checked in both C code and shellscript (via test\n         -n) it was one of the remaining shellscript-like variables. Now that\n    -    we have \"git env--helper\" we can change that.\n    +    we have \"env--helper\" we can change that.\n    +\n    +    There's a couple of tricky edge cases that arise because we're using\n    +    git_env_bool() early, and the config-reading \"env--helper\".\n    +\n    +    If GIT_TEST_GETTEXT_POISON is set to an invalid value die_bad_number()\n    +    will die, but to do so it would usually call gettext(). Let's detect\n    +    the special case of GIT_TEST_GETTEXT_POISON and always emit that\n    +    message in the C locale, lest we infinitely loop.\n    +\n    +    As seen in the updated tests in t0016-env-helper.sh there's also a\n    +    caveat related to \"env--helper\" needing to read the config for trace2\n    +    purposes.\n    +\n    +    Since the C_LOCALE_OUTPUT prerequisite is lazy and relies on\n    +    \"env--helper\" we could get invalid results if we failed to read the\n    +    config (e.g. because we'd loop on includes) when combined with\n    +    e.g. \"test_i18ngrep\" wanting to check with \"env--helper\" if\n    +    GIT_TEST_GETTEXT_POISON was true or not.\n    +\n    +    I'm crossing my fingers and hoping that a test similar to the one I\n    +    removed in the earlier \"config tests: simplify include cycle test\"\n    +    change in this series won't happen again, and testing for this\n    +    explicitly in \"env--helper\"'s own tests.\n     \n         Signed-off-by: Ævar Arnfjörð Bjarmason <avarab@gmail.com>\n     \n    @@ -24,6 +47,26 @@\n      esac\n      \n     \n    + diff --git a/config.c b/config.c\n    + --- a/config.c\n    + +++ b/config.c\n    +@@\n    + \tif (!value)\n    + \t\tvalue = \"\";\n    + \n    ++\tif (!strcmp(name, \"GIT_TEST_GETTEXT_POISON\"))\n    ++\t\t/*\n    ++\t\t * We explicitly *don't* use _() here since it would\n    ++\t\t * cause an infinite loop with _() needing to call\n    ++\t\t * use_gettext_poison(). This is why marked up\n    ++\t\t * translations with N_() above.\n    ++\t\t */\n    ++\t\tdie(bad_numeric, value, name, error_type);\n    ++\n    + \tif (!(cf && cf->name))\n    + \t\tdie(_(bad_numeric), value, name, _(error_type));\n    + \n    +\n      diff --git a/gettext.c b/gettext.c\n      --- a/gettext.c\n      +++ b/gettext.c\n    @@ -84,6 +127,31 @@\n      prerequisite when adding more strings for translation. See \"Testing\n      marked strings\" in po/README for details.\n     \n    + diff --git a/t/t0017-env-helper.sh b/t/t0017-env-helper.sh\n    + --- a/t/t0017-env-helper.sh\n    + +++ b/t/t0017-env-helper.sh\n    +@@\n    + \ttest_cmp expected actual\n    + '\n    + \n    ++test_expect_success 'env--helper reads config thanks to trace2' '\n    ++\tmkdir home &&\n    ++\tgit config -f home/.gitconfig include.path cycle &&\n    ++\tgit config -f home/cycle include.path .gitconfig &&\n    ++\n    ++\ttest_must_fail \\\n    ++\t\tenv HOME=\"$(pwd)/home\" GIT_TEST_GETTEXT_POISON=false \\\n    ++\t\tgit config -l 2>err &&\n    ++\tgrep \"exceeded maximum include depth\" err &&\n    ++\n    ++\ttest_must_fail \\\n    ++\t\tenv HOME=\"$(pwd)/home\" GIT_TEST_GETTEXT_POISON=true \\\n    ++\t\tgit -C cycle env--helper --mode-bool --variable=GIT_TEST_GETTEXT_POISON --default=0 --exit-code --quiet 2>err &&\n    ++\tgrep \"# GETTEXT POISON #\" err\n    ++'\n    ++\n    + test_done\n    +\n      diff --git a/t/t0205-gettext-poison.sh b/t/t0205-gettext-poison.sh\n      --- a/t/t0205-gettext-poison.sh\n      +++ b/t/t0205-gettext-poison.sh\n    @@ -96,6 +164,29 @@\n      export GIT_TEST_GETTEXT_POISON\n      . ./lib-gettext.sh\n      \n    +@@\n    +     test_cmp expect actual\n    + '\n    + \n    ++test_expect_success \"gettext: invalid GIT_TEST_GETTEXT_POISON value doesn't infinitely loop\" \"\n    ++\ttest_must_fail env GIT_TEST_GETTEXT_POISON=xyz git version 2>error &&\n    ++\tgrep \\\"fatal: bad numeric config value 'xyz' for 'GIT_TEST_GETTEXT_POISON': invalid unit\\\" error\n    ++\"\n    ++\n    + test_done\n    +\n    + diff --git a/t/t1305-config-include.sh b/t/t1305-config-include.sh\n    + --- a/t/t1305-config-include.sh\n    + +++ b/t/t1305-config-include.sh\n    +@@\n    + \tgit -C cycle config include.path cycle &&\n    + \tgit config -f cycle/cycle include.path config &&\n    + \ttest_must_fail \\\n    +-\t\tenv GIT_TEST_GETTEXT_POISON= \\\n    ++\t\tenv GIT_TEST_GETTEXT_POISON=false \\\n    + \t\tgit -C cycle config --get-all test.value 2>stderr &&\n    + \tgrep \"exceeded maximum include depth\" stderr\n    + '\n     \n      diff --git a/t/t7201-co.sh b/t/t7201-co.sh\n      --- a/t/t7201-co.sh\n    @@ -130,10 +221,14 @@\n      \tunset GIT_TEST_GETTEXT_POISON_ORIG\n      fi\n      \n    +-# Can we rely on git's output in the C locale?\n    +-if test -z \"$GIT_TEST_GETTEXT_POISON\"\n    +-then\n    +-\ttest_set_prereq C_LOCALE_OUTPUT\n    +-fi\n     +test_lazy_prereq C_LOCALE_OUTPUT '\n     +\t! git env--helper --mode-bool --variable=GIT_TEST_GETTEXT_POISON --default=0 --exit-code --quiet\n     +'\n    -+\n    - # Can we rely on git's output in the C locale?\n    - if test -z \"$GIT_TEST_GETTEXT_POISON\"\n    + \n    + if test -z \"$GIT_TEST_CHECK_CACHE_TREE\"\n      then\n4:  f1e28dff36 = 6:  954428b3cd tests README: re-flow a previously changed paragraph\n5:  f046cf21fb = 7:  79b41cf01b tests: replace test_tristate with \"git env--helper\"\n6:  e2c68e0239 = 8:  a9aa166b66 tests: make GIT_TEST_FAIL_PREREQS a boolean\n-- \n2.22.0.455.g172b71a6c5\n\n"},{"id":"377705","messageId":"20190620210915.11297-2-avarab@gmail.com","threadId":"51336","inReplyTo":"20190619233046.27503-1-avarab@gmail.com","subject":"[PATCH v2 1/8] config tests: simplify include cycle test","fromName":"Ævar Arnfjörð Bjarmason","fromEmail":"avarab@gmail.com","sentAt":"2019-06-20T21:09:08Z","receivedAt":"2019-06-20T21:09:31Z","isPatch":true,"sender":{"key":"avarab@gmail.com","avatar":"https://avatars.githubusercontent.com/u/45301?v=4"},"body":"Simplify an overly verbose test added in 9b25a0b52e (\"config: add\ninclude directive\", 2012-02-06). The \"expect\" file was never used, and\nby using .gitconfig it's not as intuitive to reproduce this manually\nwith \"-d\" as some other tests, since HOME needs to be set in the\nenvironment.\n\nAlso remove the use of test_i18ngrep added in a769bfc74f (\"config.c:\nmark more strings for translation\", 2018-07-21) in favor of overriding\nthe GIT_TEST_GETTEXT_POISON value.\n\nUsing the i18n test wrappers hasn't been needed since my\n6cdccfce1e (\"i18n: make GETTEXT_POISON a runtime option\", 2018-11-08).\nAs a follow-up change to the yet-to-be-added t0017-env-helper.sh will\nshow, doing it this way can hide a regression when combined with\ntrace2's early config reading. That early config reading was added in\nbce9db6de9 (\"trace2: use system/global config for default trace2\nsettings\", 2019-04-15).\n\nSo let's remove the testing for that potential regression here, I'll\ninstead add it explicitly to t0017-env-helper.sh in a follow-up\nchange.\n\nSigned-off-by: Ævar Arnfjörð Bjarmason <avarab@gmail.com>\n---\n t/t1305-config-include.sh | 21 +++++++--------------\n 1 file changed, 7 insertions(+), 14 deletions(-)\n\ndiff --git a/t/t1305-config-include.sh b/t/t1305-config-include.sh\nindex 579a86b7f8..6b388ba2d0 100755\n--- a/t/t1305-config-include.sh\n+++ b/t/t1305-config-include.sh\n@@ -310,20 +310,13 @@ test_expect_success SYMLINKS 'conditional include, gitdir matching symlink, icas\n '\n \n test_expect_success 'include cycles are detected' '\n-\tcat >.gitconfig <<-\\EOF &&\n-\t[test]value = gitconfig\n-\t[include]path = cycle\n-\tEOF\n-\tcat >cycle <<-\\EOF &&\n-\t[test]value = cycle\n-\t[include]path = .gitconfig\n-\tEOF\n-\tcat >expect <<-\\EOF &&\n-\tgitconfig\n-\tcycle\n-\tEOF\n-\ttest_must_fail git config --get-all test.value 2>stderr &&\n-\ttest_i18ngrep \"exceeded maximum include depth\" stderr\n+\tgit init --bare cycle &&\n+\tgit -C cycle config include.path cycle &&\n+\tgit config -f cycle/cycle include.path config &&\n+\ttest_must_fail \\\n+\t\tenv GIT_TEST_GETTEXT_POISON= \\\n+\t\tgit -C cycle config --get-all test.value 2>stderr &&\n+\tgrep \"exceeded maximum include depth\" stderr\n '\n \n test_done\n-- \n2.22.0.455.g172b71a6c5\n\n"},{"id":"377706","messageId":"20190620210915.11297-3-avarab@gmail.com","threadId":"51336","inReplyTo":"20190619233046.27503-1-avarab@gmail.com","subject":"[PATCH v2 2/8] env--helper: new undocumented builtin wrapping git_env_*()","fromName":"Ævar Arnfjörð Bjarmason","fromEmail":"avarab@gmail.com","sentAt":"2019-06-20T21:09:09Z","receivedAt":"2019-06-20T21:09:33Z","isPatch":true,"sender":{"key":"avarab@gmail.com","avatar":"https://avatars.githubusercontent.com/u/45301?v=4"},"body":"We have many GIT_TEST_* variables that accept a <boolean> because\nthey're implemented in C, and then some that take <non-empty?> because\nthey're implemented at least partially in shellscript.\n\nAdd a helper that wraps git_env_bool() and git_env_ulong() as the\nfirst step in fixing this. This isn't being added as a test-tool mode\nbecause some of these are used outside the test suite.\n\nPart of what this tool does can be done via a trick with \"git config\"\nadded in 83d842dc8c (\"tests: turn on network daemon tests by default\",\n2014-02-10) for test_tristate(), i.e.:\n\n    git -c magic.variable=\"$1\" config --bool magic.variable 2>/dev/null\n\nBut as subsequent changes will show being able to pass along the\ndefault value makes all the difference, and we'll be able to replace\ntest_tristate() itself with that.\n\nThe --mode-bool option will be used by subsequent patches, but not\n--mode-ulong. I figured it was easy enough to add it & test for it so\nI left it in so we'd have wrappers for both git_env_*() functions.\n\nSigned-off-by: Ævar Arnfjörð Bjarmason <avarab@gmail.com>\n---\n .gitignore            |  1 +\n Makefile              |  1 +\n builtin.h             |  1 +\n builtin/env--helper.c | 74 +++++++++++++++++++++++++++++++++++++++++++\n git.c                 |  1 +\n t/t0017-env-helper.sh | 70 ++++++++++++++++++++++++++++++++++++++++\n 6 files changed, 148 insertions(+)\n create mode 100644 builtin/env--helper.c\n create mode 100755 t/t0017-env-helper.sh\n\ndiff --git a/.gitignore b/.gitignore\nindex 4470d7cfc0..1f7a83fb3c 100644\n--- a/.gitignore\n+++ b/.gitignore\n@@ -58,6 +58,7 @@\n /git-difftool\n /git-difftool--helper\n /git-describe\n+/git-env--helper\n /git-fast-export\n /git-fast-import\n /git-fetch\ndiff --git a/Makefile b/Makefile\nindex f58bf14c7b..f2cfc8d812 100644\n--- a/Makefile\n+++ b/Makefile\n@@ -1059,6 +1059,7 @@ BUILTIN_OBJS += builtin/diff-index.o\n BUILTIN_OBJS += builtin/diff-tree.o\n BUILTIN_OBJS += builtin/diff.o\n BUILTIN_OBJS += builtin/difftool.o\n+BUILTIN_OBJS += builtin/env--helper.o\n BUILTIN_OBJS += builtin/fast-export.o\n BUILTIN_OBJS += builtin/fetch-pack.o\n BUILTIN_OBJS += builtin/fetch.o\ndiff --git a/builtin.h b/builtin.h\nindex ec7e0954c4..93bd49fe4f 100644\n--- a/builtin.h\n+++ b/builtin.h\n@@ -160,6 +160,7 @@ int cmd_diff_index(int argc, const char **argv, const char *prefix);\n int cmd_diff(int argc, const char **argv, const char *prefix);\n int cmd_diff_tree(int argc, const char **argv, const char *prefix);\n int cmd_difftool(int argc, const char **argv, const char *prefix);\n+int cmd_env__helper(int argc, const char **argv, const char *prefix);\n int cmd_fast_export(int argc, const char **argv, const char *prefix);\n int cmd_fetch(int argc, const char **argv, const char *prefix);\n int cmd_fetch_pack(int argc, const char **argv, const char *prefix);\ndiff --git a/builtin/env--helper.c b/builtin/env--helper.c\nnew file mode 100644\nindex 0000000000..2bb65ecf3f\n--- /dev/null\n+++ b/builtin/env--helper.c\n@@ -0,0 +1,74 @@\n+#include \"builtin.h\"\n+#include \"config.h\"\n+#include \"parse-options.h\"\n+\n+static char const * const env__helper_usage[] = {\n+\tN_(\"git env--helper [--mode-bool | --mode-ulong] --env-variable=<VAR> --env-default=<DEF> [<options>]\"),\n+\tNULL\n+};\n+\n+int cmd_env__helper(int argc, const char **argv, const char *prefix)\n+{\n+\tenum {\n+\t\tENV_HELPER_BOOL = 1,\n+\t\tENV_HELPER_ULONG,\n+\t} cmdmode = 0;\n+\tint exit_code = 0;\n+\tint quiet = 0;\n+\tconst char *env_variable = NULL;\n+\tconst char *env_default = NULL;\n+\tint ret;\n+\tint ret_int, tmp_int;\n+\tunsigned long ret_ulong, tmp_ulong;\n+\tstruct option opts[] = {\n+\t\tOPT_CMDMODE(0, \"mode-bool\", &cmdmode,\n+\t\t\t    N_(\"invoke git_env_bool(...)\"), ENV_HELPER_BOOL),\n+\t\tOPT_CMDMODE(0, \"mode-ulong\", &cmdmode,\n+\t\t\t    N_(\"invoke git_env_ulong(...)\"), ENV_HELPER_ULONG),\n+\t\tOPT_STRING(0, \"variable\", &env_variable, N_(\"name\"),\n+\t\t\t   N_(\"which environment variable to ask git_env_*(...) about\")),\n+\t\tOPT_STRING(0, \"default\", &env_default, N_(\"value\"),\n+\t\t\t   N_(\"what default value does git_env_*(...) fall back on?\")),\n+\t\tOPT_BOOL(0, \"exit-code\", &exit_code,\n+\t\t\t N_(\"exit code determined by truth of the git_env_*() function\")),\n+\t\tOPT_BOOL(0, \"quiet\", &quiet,\n+\t\t\t N_(\"don't print the git_env_*() return value\")),\n+\t\tOPT_END(),\n+\t};\n+\n+\tif (parse_options(argc, argv, prefix, opts, env__helper_usage, 0))\n+\t\tusage_with_options(env__helper_usage, opts);\n+\tif (!env_variable || !env_default ||\n+\t    !*env_variable || !*env_default)\n+\t\tusage_with_options(env__helper_usage, opts);\n+\n+\tswitch (cmdmode) {\n+\tcase ENV_HELPER_BOOL:\n+\t\ttmp_int = strtol(env_default, (char **)&env_default, 10);\n+\t\tif (*env_default) {\n+\t\t\terror(_(\"option `--default' expects a numerical value with `--mode-bool`\"));\n+\t\t\tusage_with_options(env__helper_usage, opts);\n+\t\t}\n+\t\tret_int = git_env_bool(env_variable, tmp_int);\n+\t\tif (!quiet)\n+\t\t\tprintf(\"%d\\n\", ret_int);\n+\t\tret = ret_int;\n+\t\tbreak;\n+\tcase ENV_HELPER_ULONG:\n+\t\ttmp_ulong = strtoll(env_default, (char **)&env_default, 10);\n+\t\tif (*env_default) {\n+\t\t\terror(_(\"option `--default' expects a numerical value with `--mode-ulong`\"));\n+\t\t\tusage_with_options(env__helper_usage, opts);\n+\t\t}\n+\t\tret_ulong = git_env_ulong(env_variable, tmp_ulong);\n+\t\tif (!quiet)\n+\t\t\tprintf(\"%lu\\n\", ret_ulong);\n+\t\tret = ret_ulong;\n+\t\tbreak;\n+\t}\n+\n+\tif (exit_code)\n+\t\treturn !ret;\n+\n+\treturn 0;\n+}\ndiff --git a/git.c b/git.c\nindex c2eec470c9..a43e1dd98e 100644\n--- a/git.c\n+++ b/git.c\n@@ -500,6 +500,7 @@ static struct cmd_struct commands[] = {\n \t{ \"diff-index\", cmd_diff_index, RUN_SETUP | NO_PARSEOPT },\n \t{ \"diff-tree\", cmd_diff_tree, RUN_SETUP | NO_PARSEOPT },\n \t{ \"difftool\", cmd_difftool, RUN_SETUP_GENTLY },\n+\t{ \"env--helper\", cmd_env__helper },\n \t{ \"fast-export\", cmd_fast_export, RUN_SETUP },\n \t{ \"fetch\", cmd_fetch, RUN_SETUP },\n \t{ \"fetch-pack\", cmd_fetch_pack, RUN_SETUP | NO_PARSEOPT },\ndiff --git a/t/t0017-env-helper.sh b/t/t0017-env-helper.sh\nnew file mode 100755\nindex 0000000000..4dc4ab35e5\n--- /dev/null\n+++ b/t/t0017-env-helper.sh\n@@ -0,0 +1,70 @@\n+#!/bin/sh\n+\n+test_description='test env--helper'\n+\n+. ./test-lib.sh\n+\n+\n+test_expect_success 'env--helper usage' '\n+\ttest_must_fail git env--helper &&\n+\ttest_must_fail git env--helper --mode-bool &&\n+\ttest_must_fail git env--helper --mode-ulong &&\n+\ttest_must_fail git env--helper --mode-bool --variable &&\n+\ttest_must_fail git env--helper --mode-bool --variable --default &&\n+\ttest_must_fail git env--helper --mode-bool --variable= --default=\n+'\n+\n+test_expect_success 'env--helper bad default values' '\n+\ttest_must_fail git env--helper --mode-bool --variable=MISSING --default=1xyz &&\n+\ttest_must_fail git env--helper --mode-ulong --variable=MISSING --default=1xyz\n+'\n+\n+test_expect_success 'env--helper --mode-bool' '\n+\techo 1 >expected &&\n+\tgit env--helper --mode-bool --variable=MISSING --default=1 --exit-code >actual &&\n+\ttest_cmp expected actual &&\n+\n+\techo 0 >expected &&\n+\ttest_must_fail git env--helper --mode-bool --variable=MISSING --default=0 --exit-code >actual &&\n+\ttest_cmp expected actual &&\n+\n+\tgit env--helper --mode-bool --variable=MISSING --default=0 >actual &&\n+\ttest_cmp expected actual &&\n+\n+\t>expected &&\n+\tgit env--helper --mode-bool --variable=MISSING --default=1 --exit-code --quiet >actual &&\n+\ttest_cmp expected actual &&\n+\n+\tEXISTS=true git env--helper --mode-bool --variable=EXISTS --default=0 --exit-code --quiet >actual &&\n+\ttest_cmp expected actual &&\n+\n+\techo 1 >expected &&\n+\tEXISTS=true git env--helper --mode-bool --variable=EXISTS --default=0 --exit-code >actual &&\n+\ttest_cmp expected actual\n+'\n+\n+test_expect_success 'env--helper --mode-ulong' '\n+\techo 1234567890 >expected &&\n+\tgit env--helper --mode-ulong --variable=MISSING --default=1234567890 --exit-code >actual &&\n+\ttest_cmp expected actual &&\n+\n+\techo 0 >expected &&\n+\ttest_must_fail git env--helper --mode-ulong --variable=MISSING --default=0 --exit-code >actual &&\n+\ttest_cmp expected actual &&\n+\n+\tgit env--helper --mode-ulong --variable=MISSING --default=0 >actual &&\n+\ttest_cmp expected actual &&\n+\n+\t>expected &&\n+\tgit env--helper --mode-ulong --variable=MISSING --default=1234567890 --exit-code --quiet >actual &&\n+\ttest_cmp expected actual &&\n+\n+\tEXISTS=1234567890 git env--helper --mode-ulong --variable=EXISTS --default=0 --exit-code --quiet >actual &&\n+\ttest_cmp expected actual &&\n+\n+\techo 1234567890 >expected &&\n+\tEXISTS=1234567890 git env--helper --mode-ulong --variable=EXISTS --default=0 --exit-code >actual &&\n+\ttest_cmp expected actual\n+'\n+\n+test_done\n-- \n2.22.0.455.g172b71a6c5\n\n"},{"id":"377707","messageId":"20190620210915.11297-4-avarab@gmail.com","threadId":"51336","inReplyTo":"20190619233046.27503-1-avarab@gmail.com","subject":"[PATCH v2 3/8] config.c: refactor die_bad_number() to not call gettext() early","fromName":"Ævar Arnfjörð Bjarmason","fromEmail":"avarab@gmail.com","sentAt":"2019-06-20T21:09:10Z","receivedAt":"2019-06-20T21:09:34Z","isPatch":true,"sender":{"key":"avarab@gmail.com","avatar":"https://avatars.githubusercontent.com/u/45301?v=4"},"body":"Prepare die_bad_number() for a change to specially handle\nGIT_TEST_GETTEXT_POISON calling git_env_bool() by making\ndie_bad_number() not call gettext() early, which would in turn call\ngit_env_bool().\n\nThere's no meaningful change here yet, just a re-arrangement of the\ncurrent code to make that subsequent change easier to read.\n\nSigned-off-by: Ævar Arnfjörð Bjarmason <avarab@gmail.com>\n---\n config.c | 19 ++++++++++---------\n 1 file changed, 10 insertions(+), 9 deletions(-)\n\ndiff --git a/config.c b/config.c\nindex 296a6d9cc4..374cb33005 100644\n--- a/config.c\n+++ b/config.c\n@@ -949,34 +949,35 @@ int git_parse_ssize_t(const char *value, ssize_t *ret)\n NORETURN\n static void die_bad_number(const char *name, const char *value)\n {\n-\tconst char * error_type = (errno == ERANGE)? _(\"out of range\"):_(\"invalid unit\");\n+\tconst char *error_type = (errno == ERANGE) ?\n+\t\tN_(\"out of range\") : N_(\"invalid unit\");\n+\tconst char *bad_numeric = N_(\"bad numeric config value '%s' for '%s': %s\");\n \n \tif (!value)\n \t\tvalue = \"\";\n \n \tif (!(cf && cf->name))\n-\t\tdie(_(\"bad numeric config value '%s' for '%s': %s\"),\n-\t\t    value, name, error_type);\n+\t\tdie(_(bad_numeric), value, name, _(error_type));\n \n \tswitch (cf->origin_type) {\n \tcase CONFIG_ORIGIN_BLOB:\n \t\tdie(_(\"bad numeric config value '%s' for '%s' in blob %s: %s\"),\n-\t\t    value, name, cf->name, error_type);\n+\t\t    value, name, cf->name, _(error_type));\n \tcase CONFIG_ORIGIN_FILE:\n \t\tdie(_(\"bad numeric config value '%s' for '%s' in file %s: %s\"),\n-\t\t    value, name, cf->name, error_type);\n+\t\t    value, name, cf->name, _(error_type));\n \tcase CONFIG_ORIGIN_STDIN:\n \t\tdie(_(\"bad numeric config value '%s' for '%s' in standard input: %s\"),\n-\t\t    value, name, error_type);\n+\t\t    value, name, _(error_type));\n \tcase CONFIG_ORIGIN_SUBMODULE_BLOB:\n \t\tdie(_(\"bad numeric config value '%s' for '%s' in submodule-blob %s: %s\"),\n-\t\t    value, name, cf->name, error_type);\n+\t\t    value, name, cf->name, _(error_type));\n \tcase CONFIG_ORIGIN_CMDLINE:\n \t\tdie(_(\"bad numeric config value '%s' for '%s' in command line %s: %s\"),\n-\t\t    value, name, cf->name, error_type);\n+\t\t    value, name, cf->name, _(error_type));\n \tdefault:\n \t\tdie(_(\"bad numeric config value '%s' for '%s' in %s: %s\"),\n-\t\t    value, name, cf->name, error_type);\n+\t\t    value, name, cf->name, _(error_type));\n \t}\n }\n \n-- \n2.22.0.455.g172b71a6c5\n\n"},{"id":"377708","messageId":"20190620210915.11297-5-avarab@gmail.com","threadId":"51336","inReplyTo":"20190619233046.27503-1-avarab@gmail.com","subject":"[PATCH v2 4/8] t6040 test: stop using global \"script\" variable","fromName":"Ævar Arnfjörð Bjarmason","fromEmail":"avarab@gmail.com","sentAt":"2019-06-20T21:09:11Z","receivedAt":"2019-06-20T21:09:36Z","isPatch":true,"sender":{"key":"avarab@gmail.com","avatar":"https://avatars.githubusercontent.com/u/45301?v=4"},"body":"Change test code added in c0234b2ef6 (\"stat_tracking_info(): clear\nobject flags used during counting\", 2008-07-03) to stop using the\n\"script\" variable also used for lazy prerequisites in\ntest-lib-functions.sh.\n\nSince this test uses test_i18ncmp and expects to use its own \"script\"\nvariable twice it implicitly depends on the C_LOCALE_OUTPUT\nprerequisite not being a lazy prerequisite. A follow-up change will\nmake it a lazy prerequisite, so we must remove this landmine before\ninadvertently stepping on it as we make that change.\n\nSigned-off-by: Ævar Arnfjörð Bjarmason <avarab@gmail.com>\n---\n t/t6040-tracking-info.sh | 6 +++---\n 1 file changed, 3 insertions(+), 3 deletions(-)\n\ndiff --git a/t/t6040-tracking-info.sh b/t/t6040-tracking-info.sh\nindex 716283b274..970b25a289 100755\n--- a/t/t6040-tracking-info.sh\n+++ b/t/t6040-tracking-info.sh\n@@ -38,7 +38,7 @@ test_expect_success setup '\n \tadvance h\n '\n \n-script='s/^..\\(b.\\) *[0-9a-f]* \\(.*\\)$/\\1 \\2/p'\n+t6040_script='s/^..\\(b.\\) *[0-9a-f]* \\(.*\\)$/\\1 \\2/p'\n cat >expect <<\\EOF\n b1 [ahead 1, behind 1] d\n b2 [ahead 1, behind 1] d\n@@ -53,7 +53,7 @@ test_expect_success 'branch -v' '\n \t\tcd test &&\n \t\tgit branch -v\n \t) |\n-\tsed -n -e \"$script\" >actual &&\n+\tsed -n -e \"$t6040_script\" >actual &&\n \ttest_i18ncmp expect actual\n '\n \n@@ -71,7 +71,7 @@ test_expect_success 'branch -vv' '\n \t\tcd test &&\n \t\tgit branch -vv\n \t) |\n-\tsed -n -e \"$script\" >actual &&\n+\tsed -n -e \"$t6040_script\" >actual &&\n \ttest_i18ncmp expect actual\n '\n \n-- \n2.22.0.455.g172b71a6c5\n\n"},{"id":"377709","messageId":"20190620210915.11297-6-avarab@gmail.com","threadId":"51336","inReplyTo":"20190619233046.27503-1-avarab@gmail.com","subject":"[PATCH v2 5/8] tests: make GIT_TEST_GETTEXT_POISON a boolean","fromName":"Ævar Arnfjörð Bjarmason","fromEmail":"avarab@gmail.com","sentAt":"2019-06-20T21:09:12Z","receivedAt":"2019-06-20T21:09:37Z","isPatch":true,"sender":{"key":"avarab@gmail.com","avatar":"https://avatars.githubusercontent.com/u/45301?v=4"},"body":"Change the GIT_TEST_GETTEXT_POISON variable from being \"non-empty?\" to\nbeing a more standard boolean variable.\n\nSince it needed to be checked in both C code and shellscript (via test\n-n) it was one of the remaining shellscript-like variables. Now that\nwe have \"env--helper\" we can change that.\n\nThere's a couple of tricky edge cases that arise because we're using\ngit_env_bool() early, and the config-reading \"env--helper\".\n\nIf GIT_TEST_GETTEXT_POISON is set to an invalid value die_bad_number()\nwill die, but to do so it would usually call gettext(). Let's detect\nthe special case of GIT_TEST_GETTEXT_POISON and always emit that\nmessage in the C locale, lest we infinitely loop.\n\nAs seen in the updated tests in t0016-env-helper.sh there's also a\ncaveat related to \"env--helper\" needing to read the config for trace2\npurposes.\n\nSince the C_LOCALE_OUTPUT prerequisite is lazy and relies on\n\"env--helper\" we could get invalid results if we failed to read the\nconfig (e.g. because we'd loop on includes) when combined with\ne.g. \"test_i18ngrep\" wanting to check with \"env--helper\" if\nGIT_TEST_GETTEXT_POISON was true or not.\n\nI'm crossing my fingers and hoping that a test similar to the one I\nremoved in the earlier \"config tests: simplify include cycle test\"\nchange in this series won't happen again, and testing for this\nexplicitly in \"env--helper\"'s own tests.\n\nSigned-off-by: Ævar Arnfjörð Bjarmason <avarab@gmail.com>\n---\n ci/lib.sh                 |  2 +-\n config.c                  |  9 +++++++++\n gettext.c                 |  6 ++----\n git-sh-i18n.sh            |  4 +++-\n po/README                 |  2 +-\n t/README                  |  4 ++--\n t/t0017-env-helper.sh     | 16 ++++++++++++++++\n t/t0205-gettext-poison.sh |  7 ++++++-\n t/t1305-config-include.sh |  2 +-\n t/t7201-co.sh             |  2 +-\n t/t9902-completion.sh     |  2 +-\n t/test-lib.sh             |  8 +++-----\n 12 files changed, 46 insertions(+), 18 deletions(-)\n\ndiff --git a/ci/lib.sh b/ci/lib.sh\nindex 288a5b3884..fd799ae663 100755\n--- a/ci/lib.sh\n+++ b/ci/lib.sh\n@@ -184,7 +184,7 @@ osx-clang|osx-gcc)\n \texport GIT_SKIP_TESTS=\"t9810 t9816\"\n \t;;\n GIT_TEST_GETTEXT_POISON)\n-\texport GIT_TEST_GETTEXT_POISON=YesPlease\n+\texport GIT_TEST_GETTEXT_POISON=true\n \t;;\n esac\n \ndiff --git a/config.c b/config.c\nindex 374cb33005..b985d60fa4 100644\n--- a/config.c\n+++ b/config.c\n@@ -956,6 +956,15 @@ static void die_bad_number(const char *name, const char *value)\n \tif (!value)\n \t\tvalue = \"\";\n \n+\tif (!strcmp(name, \"GIT_TEST_GETTEXT_POISON\"))\n+\t\t/*\n+\t\t * We explicitly *don't* use _() here since it would\n+\t\t * cause an infinite loop with _() needing to call\n+\t\t * use_gettext_poison(). This is why marked up\n+\t\t * translations with N_() above.\n+\t\t */\n+\t\tdie(bad_numeric, value, name, error_type);\n+\n \tif (!(cf && cf->name))\n \t\tdie(_(bad_numeric), value, name, _(error_type));\n \ndiff --git a/gettext.c b/gettext.c\nindex d4021d690c..5c71f4c8b9 100644\n--- a/gettext.c\n+++ b/gettext.c\n@@ -50,10 +50,8 @@ const char *get_preferred_languages(void)\n int use_gettext_poison(void)\n {\n \tstatic int poison_requested = -1;\n-\tif (poison_requested == -1) {\n-\t\tconst char *v = getenv(\"GIT_TEST_GETTEXT_POISON\");\n-\t\tpoison_requested = v && strlen(v) ? 1 : 0;\n-\t}\n+\tif (poison_requested == -1)\n+\t\tpoison_requested = git_env_bool(\"GIT_TEST_GETTEXT_POISON\", 0);\n \treturn poison_requested;\n }\n \ndiff --git a/git-sh-i18n.sh b/git-sh-i18n.sh\nindex e1d917fd27..de8ae67d7b 100644\n--- a/git-sh-i18n.sh\n+++ b/git-sh-i18n.sh\n@@ -17,7 +17,9 @@ export TEXTDOMAINDIR\n \n # First decide what scheme to use...\n GIT_INTERNAL_GETTEXT_SH_SCHEME=fallthrough\n-if test -n \"$GIT_TEST_GETTEXT_POISON\"\n+if test -n \"$GIT_TEST_GETTEXT_POISON\" &&\n+\t    git env--helper --mode-bool --variable=GIT_TEST_GETTEXT_POISON \\\n+\t\t--default=0 --exit-code --quiet\n then\n \tGIT_INTERNAL_GETTEXT_SH_SCHEME=poison\n elif test -n \"@@USE_GETTEXT_SCHEME@@\"\ndiff --git a/po/README b/po/README\nindex aa704ffcb7..07595d369b 100644\n--- a/po/README\n+++ b/po/README\n@@ -293,7 +293,7 @@ To smoke out issues like these, Git tested with a translation mode that\n emits gibberish on every call to gettext. To use it run the test suite\n with it, e.g.:\n \n-    cd t && GIT_TEST_GETTEXT_POISON=YesPlease prove -j 9 ./t[0-9]*.sh\n+    cd t && GIT_TEST_GETTEXT_POISON=true prove -j 9 ./t[0-9]*.sh\n \n If tests break with it you should inspect them manually and see if\n what you're translating is sane, i.e. that you're not translating\ndiff --git a/t/README b/t/README\nindex 9747971d58..9a131f472e 100644\n--- a/t/README\n+++ b/t/README\n@@ -343,8 +343,8 @@ whether this mode is active, and e.g. skip some tests that are hard to\n refactor to deal with it. The \"SYMLINKS\" prerequisite is currently\n excluded as so much relies on it, but this might change in the future.\n \n-GIT_TEST_GETTEXT_POISON=<non-empty?> turns all strings marked for\n-translation into gibberish if non-empty (think \"test -n\"). Used for\n+GIT_TEST_GETTEXT_POISON=<boolean> turns all strings marked for\n+translation into gibberish if true. Used for\n spotting those tests that need to be marked with a C_LOCALE_OUTPUT\n prerequisite when adding more strings for translation. See \"Testing\n marked strings\" in po/README for details.\ndiff --git a/t/t0017-env-helper.sh b/t/t0017-env-helper.sh\nindex 4dc4ab35e5..f62814241d 100755\n--- a/t/t0017-env-helper.sh\n+++ b/t/t0017-env-helper.sh\n@@ -67,4 +67,20 @@ test_expect_success 'env--helper --mode-ulong' '\n \ttest_cmp expected actual\n '\n \n+test_expect_success 'env--helper reads config thanks to trace2' '\n+\tmkdir home &&\n+\tgit config -f home/.gitconfig include.path cycle &&\n+\tgit config -f home/cycle include.path .gitconfig &&\n+\n+\ttest_must_fail \\\n+\t\tenv HOME=\"$(pwd)/home\" GIT_TEST_GETTEXT_POISON=false \\\n+\t\tgit config -l 2>err &&\n+\tgrep \"exceeded maximum include depth\" err &&\n+\n+\ttest_must_fail \\\n+\t\tenv HOME=\"$(pwd)/home\" GIT_TEST_GETTEXT_POISON=true \\\n+\t\tgit -C cycle env--helper --mode-bool --variable=GIT_TEST_GETTEXT_POISON --default=0 --exit-code --quiet 2>err &&\n+\tgrep \"# GETTEXT POISON #\" err\n+'\n+\n test_done\ndiff --git a/t/t0205-gettext-poison.sh b/t/t0205-gettext-poison.sh\nindex a06269f38a..f9fa16ad83 100755\n--- a/t/t0205-gettext-poison.sh\n+++ b/t/t0205-gettext-poison.sh\n@@ -5,7 +5,7 @@\n \n test_description='Gettext Shell poison'\n \n-GIT_TEST_GETTEXT_POISON=YesPlease\n+GIT_TEST_GETTEXT_POISON=true\n export GIT_TEST_GETTEXT_POISON\n . ./lib-gettext.sh\n \n@@ -31,4 +31,9 @@ test_expect_success 'eval_gettext: our eval_gettext() fallback has poison semant\n     test_cmp expect actual\n '\n \n+test_expect_success \"gettext: invalid GIT_TEST_GETTEXT_POISON value doesn't infinitely loop\" \"\n+\ttest_must_fail env GIT_TEST_GETTEXT_POISON=xyz git version 2>error &&\n+\tgrep \\\"fatal: bad numeric config value 'xyz' for 'GIT_TEST_GETTEXT_POISON': invalid unit\\\" error\n+\"\n+\n test_done\ndiff --git a/t/t1305-config-include.sh b/t/t1305-config-include.sh\nindex 6b388ba2d0..de294c990e 100755\n--- a/t/t1305-config-include.sh\n+++ b/t/t1305-config-include.sh\n@@ -314,7 +314,7 @@ test_expect_success 'include cycles are detected' '\n \tgit -C cycle config include.path cycle &&\n \tgit config -f cycle/cycle include.path config &&\n \ttest_must_fail \\\n-\t\tenv GIT_TEST_GETTEXT_POISON= \\\n+\t\tenv GIT_TEST_GETTEXT_POISON=false \\\n \t\tgit -C cycle config --get-all test.value 2>stderr &&\n \tgrep \"exceeded maximum include depth\" stderr\n '\ndiff --git a/t/t7201-co.sh b/t/t7201-co.sh\nindex 5990299fc9..b696bae5f5 100755\n--- a/t/t7201-co.sh\n+++ b/t/t7201-co.sh\n@@ -249,7 +249,7 @@ test_expect_success 'checkout to detach HEAD (with advice declined)' '\n test_expect_success 'checkout to detach HEAD' '\n \tgit config advice.detachedHead true &&\n \tgit checkout -f renamer && git clean -f &&\n-\tGIT_TEST_GETTEXT_POISON= git checkout renamer^ 2>messages &&\n+\tGIT_TEST_GETTEXT_POISON=false git checkout renamer^ 2>messages &&\n \tgrep \"HEAD is now at 7329388\" messages &&\n \ttest_line_count -gt 1 messages &&\n \tH=$(git rev-parse --verify HEAD) &&\ndiff --git a/t/t9902-completion.sh b/t/t9902-completion.sh\nindex 43cf313a1c..75512c3403 100755\n--- a/t/t9902-completion.sh\n+++ b/t/t9902-completion.sh\n@@ -1706,7 +1706,7 @@ test_expect_success 'sourcing the completion script clears cached commands' '\n '\n \n test_expect_success 'sourcing the completion script clears cached merge strategies' '\n-\tGIT_TEST_GETTEXT_POISON= &&\n+\tGIT_TEST_GETTEXT_POISON=false &&\n \t__git_compute_merge_strategies &&\n \tverbose test -n \"$__git_merge_strategies\" &&\n \t. \"$GIT_BUILD_DIR/contrib/completion/git-completion.bash\" &&\ndiff --git a/t/test-lib.sh b/t/test-lib.sh\nindex 4b346467df..c45b0d2611 100644\n--- a/t/test-lib.sh\n+++ b/t/test-lib.sh\n@@ -1443,11 +1443,9 @@ then\n \tunset GIT_TEST_GETTEXT_POISON_ORIG\n fi\n \n-# Can we rely on git's output in the C locale?\n-if test -z \"$GIT_TEST_GETTEXT_POISON\"\n-then\n-\ttest_set_prereq C_LOCALE_OUTPUT\n-fi\n+test_lazy_prereq C_LOCALE_OUTPUT '\n+\t! git env--helper --mode-bool --variable=GIT_TEST_GETTEXT_POISON --default=0 --exit-code --quiet\n+'\n \n if test -z \"$GIT_TEST_CHECK_CACHE_TREE\"\n then\n-- \n2.22.0.455.g172b71a6c5\n\n"},{"id":"377711","messageId":"20190620210915.11297-8-avarab@gmail.com","threadId":"51336","inReplyTo":"20190619233046.27503-1-avarab@gmail.com","subject":"[PATCH v2 7/8] tests: replace test_tristate with \"git env--helper\"","fromName":"Ævar Arnfjörð Bjarmason","fromEmail":"avarab@gmail.com","sentAt":"2019-06-20T21:09:14Z","receivedAt":"2019-06-20T21:09:38Z","isPatch":true,"sender":{"key":"avarab@gmail.com","avatar":"https://avatars.githubusercontent.com/u/45301?v=4"},"body":"The test_tristate helper introduced in 83d842dc8c (\"tests: turn on\nnetwork daemon tests by default\", 2014-02-10) can now be better\nimplemented with \"git env--helper\" to give the variables in question\nthe standard boolean behavior.\n\nThe reason for the \"tristate\" was to have all of false/true/auto,\nwhere \"auto\" meant either \"false\" or \"true\" depending on what the\nfallback was. With the --default option to \"git env--helper\" we can\nsimply have e.g. GIT_TEST_HTTPD where we know if it's true because the\nuser asked explicitly (\"true\"), or true implicitly (\"auto\").\n\nThis breaks backwards compatibility for explicitly setting \"auto\" for\nthese variables, but I don't think anyone cares. That was always\nintended to be internal.\n\nThis means the test_normalize_bool() code in test-lib-functions.sh\ngoes away in addition to test_tristate(). We still need the\ntest_skip_or_die() helper, but now it takes the variable name instead\nof the value, and uses \"git env--bool\" to distinguish a default \"true\"\nfrom an explicit \"true\" (in those \"explicit true\" cases we want to\nfail the test in question).\n\nSigned-off-by: Ævar Arnfjörð Bjarmason <avarab@gmail.com>\n---\n t/lib-git-daemon.sh     |  7 +++---\n t/lib-git-svn.sh        | 11 +++-----\n t/lib-httpd.sh          | 15 ++++++-----\n t/t5512-ls-remote.sh    |  3 +--\n t/test-lib-functions.sh | 56 ++++++-----------------------------------\n 5 files changed, 22 insertions(+), 70 deletions(-)\n\ndiff --git a/t/lib-git-daemon.sh b/t/lib-git-daemon.sh\nindex 7b3407134e..770c5218ea 100644\n--- a/t/lib-git-daemon.sh\n+++ b/t/lib-git-daemon.sh\n@@ -15,8 +15,7 @@\n #\n #\ttest_done\n \n-test_tristate GIT_TEST_GIT_DAEMON\n-if test \"$GIT_TEST_GIT_DAEMON\" = false\n+if ! git env--helper --mode-bool --variable=GIT_TEST_GIT_DAEMON --default=1 --exit-code --quiet\n then\n \tskip_all=\"git-daemon testing disabled (unset GIT_TEST_GIT_DAEMON to enable)\"\n \ttest_done\n@@ -24,7 +23,7 @@ fi\n \n if test_have_prereq !PIPE\n then\n-\ttest_skip_or_die $GIT_TEST_GIT_DAEMON \"file system does not support FIFOs\"\n+\ttest_skip_or_die GIT_TEST_GIT_DAEMON \"file system does not support FIFOs\"\n fi\n \n test_set_port LIB_GIT_DAEMON_PORT\n@@ -73,7 +72,7 @@ start_git_daemon() {\n \t\tkill \"$GIT_DAEMON_PID\"\n \t\twait \"$GIT_DAEMON_PID\"\n \t\tunset GIT_DAEMON_PID\n-\t\ttest_skip_or_die $GIT_TEST_GIT_DAEMON \\\n+\t\ttest_skip_or_die GIT_TEST_GIT_DAEMON \\\n \t\t\t\"git daemon failed to start\"\n \tfi\n }\ndiff --git a/t/lib-git-svn.sh b/t/lib-git-svn.sh\nindex c1271d6863..853d33a57a 100644\n--- a/t/lib-git-svn.sh\n+++ b/t/lib-git-svn.sh\n@@ -69,14 +69,12 @@ svn_cmd () {\n maybe_start_httpd () {\n \tloc=${1-svn}\n \n-\ttest_tristate GIT_SVN_TEST_HTTPD\n-\tcase $GIT_SVN_TEST_HTTPD in\n-\ttrue)\n+\tif git env--helper --mode-bool --variable=GIT_TEST_HTTPD --default=0 --exit-code --quiet\t\n+\tthen\n \t\t. \"$TEST_DIRECTORY\"/lib-httpd.sh\n \t\tLIB_HTTPD_SVN=\"$loc\"\n \t\tstart_httpd\n-\t\t;;\n-\tesac\n+\tfi\n }\n \n convert_to_rev_db () {\n@@ -106,8 +104,7 @@ EOF\n }\n \n require_svnserve () {\n-\ttest_tristate GIT_TEST_SVNSERVE\n-\tif ! test \"$GIT_TEST_SVNSERVE\" = true\n+\tif ! git env--helper --mode-bool --variable=GIT_TEST_SVNSERVE --default=0 --exit-code --quiet\n \tthen\n \t\tskip_all='skipping svnserve test. (set $GIT_TEST_SVNSERVE to enable)'\n \t\ttest_done\ndiff --git a/t/lib-httpd.sh b/t/lib-httpd.sh\nindex b3cc62bd36..eef3250552 100644\n--- a/t/lib-httpd.sh\n+++ b/t/lib-httpd.sh\n@@ -41,15 +41,14 @@ then\n \ttest_done\n fi\n \n-test_tristate GIT_TEST_HTTPD\n-if test \"$GIT_TEST_HTTPD\" = false\n+if ! git env--helper --mode-bool --variable=GIT_TEST_HTTPD --default=1 --exit-code --quiet\n then\n \tskip_all=\"Network testing disabled (unset GIT_TEST_HTTPD to enable)\"\n \ttest_done\n fi\n \n if ! test_have_prereq NOT_ROOT; then\n-\ttest_skip_or_die $GIT_TEST_HTTPD \\\n+\ttest_skip_or_die GIT_TEST_HTTPD \\\n \t\t\"Cannot run httpd tests as root\"\n fi\n \n@@ -95,7 +94,7 @@ GIT_TRACE=$GIT_TRACE; export GIT_TRACE\n \n if ! test -x \"$LIB_HTTPD_PATH\"\n then\n-\ttest_skip_or_die $GIT_TEST_HTTPD \"no web server found at '$LIB_HTTPD_PATH'\"\n+\ttest_skip_or_die GIT_TEST_HTTPD \"no web server found at '$LIB_HTTPD_PATH'\"\n fi\n \n HTTPD_VERSION=$($LIB_HTTPD_PATH -v | \\\n@@ -107,19 +106,19 @@ then\n \tthen\n \t\tif ! test $HTTPD_VERSION -ge 2\n \t\tthen\n-\t\t\ttest_skip_or_die $GIT_TEST_HTTPD \\\n+\t\t\ttest_skip_or_die GIT_TEST_HTTPD \\\n \t\t\t\t\"at least Apache version 2 is required\"\n \t\tfi\n \t\tif ! test -d \"$DEFAULT_HTTPD_MODULE_PATH\"\n \t\tthen\n-\t\t\ttest_skip_or_die $GIT_TEST_HTTPD \\\n+\t\t\ttest_skip_or_die GIT_TEST_HTTPD \\\n \t\t\t\t\"Apache module directory not found\"\n \t\tfi\n \n \t\tLIB_HTTPD_MODULE_PATH=\"$DEFAULT_HTTPD_MODULE_PATH\"\n \tfi\n else\n-\ttest_skip_or_die $GIT_TEST_HTTPD \\\n+\ttest_skip_or_die GIT_TEST_HTTPD \\\n \t\t\"Could not identify web server at '$LIB_HTTPD_PATH'\"\n fi\n \n@@ -184,7 +183,7 @@ start_httpd() {\n \tif test $? -ne 0\n \tthen\n \t\tcat \"$HTTPD_ROOT_PATH\"/error.log >&4 2>/dev/null\n-\t\ttest_skip_or_die $GIT_TEST_HTTPD \"web server setup failed\"\n+\t\ttest_skip_or_die GIT_TEST_HTTPD \"web server setup failed\"\n \tfi\n }\n \ndiff --git a/t/t5512-ls-remote.sh b/t/t5512-ls-remote.sh\nindex e3c4a48c85..7161148280 100755\n--- a/t/t5512-ls-remote.sh\n+++ b/t/t5512-ls-remote.sh\n@@ -267,8 +267,7 @@ test_expect_success 'ls-remote --symref omits filtered-out matches' '\n '\n \n test_lazy_prereq GIT_DAEMON '\n-\ttest_tristate GIT_TEST_GIT_DAEMON &&\n-\ttest \"$GIT_TEST_GIT_DAEMON\" != false\n+\tgit env--helper --mode-bool --variable=GIT_TEST_GIT_DAEMON --default=1 --exit-code --quiet\n '\n \n # This test spawns a daemon, so run it only if the user would be OK with\ndiff --git a/t/test-lib-functions.sh b/t/test-lib-functions.sh\nindex 0367cec5fd..527508c350 100644\n--- a/t/test-lib-functions.sh\n+++ b/t/test-lib-functions.sh\n@@ -1035,62 +1035,20 @@ perl () {\n \tcommand \"$PERL_PATH\" \"$@\" 2>&7\n } 7>&2 2>&4\n \n-# Is the value one of the various ways to spell a boolean true/false?\n-test_normalize_bool () {\n-\tgit -c magic.variable=\"$1\" config --bool magic.variable 2>/dev/null\n-}\n-\n-# Given a variable $1, normalize the value of it to one of \"true\",\n-# \"false\", or \"auto\" and store the result to it.\n-#\n-#     test_tristate GIT_TEST_HTTPD\n-#\n-# A variable set to an empty string is set to 'false'.\n-# A variable set to 'false' or 'auto' keeps its value.\n-# Anything else is set to 'true'.\n-# An unset variable defaults to 'auto'.\n-#\n-# The last rule is to allow people to set the variable to an empty\n-# string and export it to decline testing the particular feature\n-# for versions both before and after this change.  We used to treat\n-# both unset and empty variable as a signal for \"do not test\" and\n-# took any non-empty string as \"please test\".\n-\n-test_tristate () {\n-\tif eval \"test x\\\"\\${$1+isset}\\\" = xisset\"\n-\tthen\n-\t\t# explicitly set\n-\t\teval \"\n-\t\t\tcase \\\"\\$$1\\\" in\n-\t\t\t'')\t$1=false ;;\n-\t\t\tauto)\t;;\n-\t\t\t*)\t$1=\\$(test_normalize_bool \\$$1 || echo true) ;;\n-\t\t\tesac\n-\t\t\"\n-\telse\n-\t\teval \"$1=auto\"\n-\tfi\n-}\n-\n # Exit the test suite, either by skipping all remaining tests or by\n-# exiting with an error. If \"$1\" is \"auto\", we then we assume we were\n-# opportunistically trying to set up some tests and we skip. If it is\n-# \"true\", then we report a failure.\n+# exiting with an error. If our prerequisite variable $1 falls back\n+# on a default assume we were opportunistically trying to set up some\n+# tests and we skip. If it is explicitly \"true\", then we report a failure.\n #\n # The error/skip message should be given by $2.\n #\n test_skip_or_die () {\n-\tcase \"$1\" in\n-\tauto)\n+\tif ! git env--helper --mode-bool --variable=$1 --default=0 --exit-code --quiet\n+\tthen\n \t\tskip_all=$2\n \t\ttest_done\n-\t\t;;\n-\ttrue)\n-\t\terror \"$2\"\n-\t\t;;\n-\t*)\n-\t\terror \"BUG: test tristate is '$1' (real error: $2)\"\n-\tesac\n+\tfi\n+\terror \"$2\"\n }\n \n # The following mingw_* functions obey POSIX shell syntax, but are actually\n-- \n2.22.0.455.g172b71a6c5\n\n"},{"id":"377710","messageId":"20190620210915.11297-7-avarab@gmail.com","threadId":"51336","inReplyTo":"20190619233046.27503-1-avarab@gmail.com","subject":"[PATCH v2 6/8] tests README: re-flow a previously changed paragraph","fromName":"Ævar Arnfjörð Bjarmason","fromEmail":"avarab@gmail.com","sentAt":"2019-06-20T21:09:13Z","receivedAt":"2019-06-20T21:09:39Z","isPatch":true,"sender":{"key":"avarab@gmail.com","avatar":"https://avatars.githubusercontent.com/u/45301?v=4"},"body":"A previous change to the \"GIT_TEST_GETTEXT_POISON\" variable left this\nparagraph needing to be re-flowed. Let's do that in this separate\nchange to make it easy to see that there's no change here when viewed\nwith \"--word-diff\".\n\nSigned-off-by: Ævar Arnfjörð Bjarmason <avarab@gmail.com>\n---\n t/README | 8 ++++----\n 1 file changed, 4 insertions(+), 4 deletions(-)\n\ndiff --git a/t/README b/t/README\nindex 9a131f472e..072c9854d1 100644\n--- a/t/README\n+++ b/t/README\n@@ -344,10 +344,10 @@ refactor to deal with it. The \"SYMLINKS\" prerequisite is currently\n excluded as so much relies on it, but this might change in the future.\n \n GIT_TEST_GETTEXT_POISON=<boolean> turns all strings marked for\n-translation into gibberish if true. Used for\n-spotting those tests that need to be marked with a C_LOCALE_OUTPUT\n-prerequisite when adding more strings for translation. See \"Testing\n-marked strings\" in po/README for details.\n+translation into gibberish if true. Used for spotting those tests that\n+need to be marked with a C_LOCALE_OUTPUT prerequisite when adding more\n+strings for translation. See \"Testing marked strings\" in po/README for\n+details.\n \n GIT_TEST_SPLIT_INDEX=<boolean> forces split-index mode on the whole\n test suite. Accept any boolean values that are accepted by git-config.\n-- \n2.22.0.455.g172b71a6c5\n\n"},{"id":"377712","messageId":"20190620210915.11297-9-avarab@gmail.com","threadId":"51336","inReplyTo":"20190619233046.27503-1-avarab@gmail.com","subject":"[PATCH v2 8/8] tests: make GIT_TEST_FAIL_PREREQS a boolean","fromName":"Ævar Arnfjörð Bjarmason","fromEmail":"avarab@gmail.com","sentAt":"2019-06-20T21:09:15Z","receivedAt":"2019-06-20T21:09:43Z","isPatch":true,"sender":{"key":"avarab@gmail.com","avatar":"https://avatars.githubusercontent.com/u/45301?v=4"},"body":"Change the GIT_TEST_FAIL_PREREQS variable from being \"non-empty?\" to\nbeing a more standard boolean variable. I recently added the variable\nin dfe1a17df9 (\"tests: add a special setup where prerequisites fail\",\n2019-05-13), having to add another \"non-empty?\" special-case is what\nprompted me to write the \"git env--helper\" utility being used here.\n\nConverting this one is a bit tricky since we use it so early and\nfrequently in the guts of the test code itself, so let's set a\nGIT_TEST_FAIL_PREREQS_INTERNAL which can be tested with the old \"test\n-n\" for the purposes of the shell code, and change the user-exposed\nand documented GIT_TEST_FAIL_PREREQS variable to a boolean.\n\nSigned-off-by: Ævar Arnfjörð Bjarmason <avarab@gmail.com>\n---\n t/README                |  2 +-\n t/t0000-basic.sh        | 10 +++++-----\n t/test-lib-functions.sh |  2 +-\n t/test-lib.sh           | 25 +++++++++++++++++++++----\n 4 files changed, 28 insertions(+), 11 deletions(-)\n\ndiff --git a/t/README b/t/README\nindex 072c9854d1..60d5b77bcc 100644\n--- a/t/README\n+++ b/t/README\n@@ -334,7 +334,7 @@ that cannot be easily covered by a few specific test cases. These\n could be enabled by running the test suite with correct GIT_TEST_\n environment set.\n \n-GIT_TEST_FAIL_PREREQS<non-empty?> fails all prerequisites. This is\n+GIT_TEST_FAIL_PREREQS=<boolean> fails all prerequisites. This is\n useful for discovering issues with the tests where say a later test\n implicitly depends on an optional earlier test.\n \ndiff --git a/t/t0000-basic.sh b/t/t0000-basic.sh\nindex 31de7e90f3..e89438e619 100755\n--- a/t/t0000-basic.sh\n+++ b/t/t0000-basic.sh\n@@ -726,7 +726,7 @@ donthaveit=yes\n test_expect_success DONTHAVEIT 'unmet prerequisite causes test to be skipped' '\n \tdonthaveit=no\n '\n-if test -z \"$GIT_TEST_FAIL_PREREQS\" -a $haveit$donthaveit != yesyes\n+if test -z \"$GIT_TEST_FAIL_PREREQS_INTERNAL\" -a $haveit$donthaveit != yesyes\n then\n \tsay \"bug in test framework: prerequisite tags do not work reliably\"\n \texit 1\n@@ -747,7 +747,7 @@ donthaveiteither=yes\n test_expect_success DONTHAVEIT,HAVEIT 'unmet prerequisites causes test to be skipped' '\n \tdonthaveiteither=no\n '\n-if test -z \"$GIT_TEST_FAIL_PREREQS\" -a $haveit$donthaveit$donthaveiteither != yesyesyes\n+if test -z \"$GIT_TEST_FAIL_PREREQS_INTERNAL\" -a $haveit$donthaveit$donthaveiteither != yesyesyes\n then\n \tsay \"bug in test framework: multiple prerequisite tags do not work reliably\"\n \texit 1\n@@ -763,7 +763,7 @@ test_expect_success !LAZY_TRUE 'missing lazy prereqs skip tests' '\n \tdonthavetrue=no\n '\n \n-if test -z \"$GIT_TEST_FAIL_PREREQS\" -a \"$havetrue$donthavetrue\" != yesyes\n+if test -z \"$GIT_TEST_FAIL_PREREQS_INTERNAL\" -a \"$havetrue$donthavetrue\" != yesyes\n then\n \tsay 'bug in test framework: lazy prerequisites do not work'\n \texit 1\n@@ -779,7 +779,7 @@ test_expect_success LAZY_FALSE 'missing negative lazy prereqs will skip' '\n \thavefalse=no\n '\n \n-if test -z \"$GIT_TEST_FAIL_PREREQS\" -a \"$nothavefalse$havefalse\" != yesyes\n+if test -z \"$GIT_TEST_FAIL_PREREQS_INTERNAL\" -a \"$nothavefalse$havefalse\" != yesyes\n then\n \tsay 'bug in test framework: negative lazy prerequisites do not work'\n \texit 1\n@@ -790,7 +790,7 @@ test_expect_success 'tests clean up after themselves' '\n \ttest_when_finished clean=yes\n '\n \n-if test -z \"$GIT_TEST_FAIL_PREREQS\" -a $clean != yes\n+if test -z \"$GIT_TEST_FAIL_PREREQS_INTERNAL\" -a $clean != yes\n then\n \tsay \"bug in test framework: basic cleanup command does not work reliably\"\n \texit 1\ndiff --git a/t/test-lib-functions.sh b/t/test-lib-functions.sh\nindex 527508c350..3fba71c358 100644\n--- a/t/test-lib-functions.sh\n+++ b/t/test-lib-functions.sh\n@@ -309,7 +309,7 @@ test_unset_prereq () {\n }\n \n test_set_prereq () {\n-\tif test -n \"$GIT_TEST_FAIL_PREREQS\"\n+\tif test -n \"$GIT_TEST_FAIL_PREREQS_INTERNAL\"\n \tthen\n \t\tcase \"$1\" in\n \t\t# The \"!\" case is handled below with\ndiff --git a/t/test-lib.sh b/t/test-lib.sh\nindex c45b0d2611..238ef62401 100644\n--- a/t/test-lib.sh\n+++ b/t/test-lib.sh\n@@ -1389,6 +1389,27 @@ yes () {\n \tdone\n }\n \n+# The GIT_TEST_FAIL_PREREQS code hooks into test_set_prereq(), and\n+# thus needs to be set up really early, and set an internal variable\n+# for convenience so the hot test_set_prereq() codepath doesn't need\n+# to call \"git env--helper\". Only do that work if needed by seeing if\n+# GIT_TEST_FAIL_PREREQS is set at all.\n+GIT_TEST_FAIL_PREREQS_INTERNAL=\n+if test -n \"$GIT_TEST_FAIL_PREREQS\"\n+then\n+\tif git env--helper --mode-bool --variable=GIT_TEST_FAIL_PREREQS \\\n+\t\t--default=0 --exit-code --quiet\n+\tthen\n+\t\tGIT_TEST_FAIL_PREREQS_INTERNAL=true\n+\t\ttest_set_prereq FAIL_PREREQS\n+\tfi\n+else\n+\ttest_lazy_prereq FAIL_PREREQS '\n+\t\tgit env--helper --mode-bool --variable=GIT_TEST_FAIL_PREREQS \\\n+\t\t\t--default=0 --exit-code --quiet\n+\t'\n+fi\n+\n # Fix some commands on Windows\n uname_s=$(uname -s)\n case $uname_s in\n@@ -1605,7 +1626,3 @@ test_lazy_prereq SHA1 '\n test_lazy_prereq REBASE_P '\n \ttest -z \"$GIT_TEST_SKIP_REBASE_P\"\n '\n-\n-test_lazy_prereq FAIL_PREREQS '\n-\ttest -n \"$GIT_TEST_FAIL_PREREQS\"\n-'\n-- \n2.22.0.455.g172b71a6c5\n\n"},{"id":"377714","messageId":"87ef3o7ws1.fsf@evledraar.gmail.com","threadId":"51336","inReplyTo":"CACsJy8AjXXOpcKrSV4z6kEM=eyFDWSyf==tJZzvDyEN591XdGw@mail.gmail.com","subject":"Re: [RFC/PATCH] gc: run more pre-detach operations under lock","fromName":"Ævar Arnfjörð Bjarmason","fromEmail":"avarab@gmail.com","sentAt":"2019-06-20T21:49:02Z","receivedAt":"2019-06-20T21:49:09Z","isPatch":true,"sender":{"key":"avarab@gmail.com","avatar":"https://avatars.githubusercontent.com/u/45301?v=4"},"body":"\nOn Thu, Jun 20 2019, Duy Nguyen wrote:\n\n> On Thu, Jun 20, 2019 at 5:49 AM Ævar Arnfjörð Bjarmason\n> <avarab@gmail.com> wrote:\n>>\n>>\n>> On Wed, Jun 19 2019, Jeff King wrote:\n>>\n>> > On Wed, Jun 19, 2019 at 08:01:55PM +0200, Ævar Arnfjörð Bjarmason wrote:\n>> >\n>> >> > You could sort of avoid the problem here too with\n>> >> >\n>> >> > parallel 'git fetch --no-auto-gc {}' ::: $(git remote)\n>> >> > git gc --auto\n>> >> >\n>> >> > It's definitely simpler, but of course we have to manually add\n>> >> > --no-auto-gc in everywhere we need, so not quite as elegant.\n>> >> >\n>> >> > Actually you could already do that with 'git -c gc.auto=false fetch', I guess.\n>> >>\n>> >> The point of the 'parallel' example is to show disconnected git\n>> >> commands, think trying to run 'git' in a terminal while your editor\n>> >> asynchronously runs a polling 'fetch', or a server with multiple\n>> >> concurrent clients running 'gc --auto'.\n>> >>\n>> >> That's the question my RFC patch raises. As far as I can tell the\n>> >> approach in your patch is only needed because our locking for gc is\n>> >> buggy, rather than introduce the caveat that an fetch(N) operation won't\n>> >> do \"gc\" until it's finished (we may have hundreds, thousands of remotes,\n>> >> I use that for some more obscure use-cases) shouldn't we just fix the\n>> >> locking?\n>> >\n>> > I think there may be room for both approaches. Yours fixes the repeated\n>> > message in the more general case, but Duy's suggestion is the most\n>> > efficient thing.\n>> >\n>> > I agree that the \"thousands of remotes\" case means we might want to gc\n>> > in the interim. But we probably ought to do that deterministically\n>> > rather than hoping that the pattern of lock contention makes sense.\n>>\n>> We do it deterministically, when gc.auto thresholds et al are exceeded\n>> we kick one off without waiting for other stuff, if we can get the lock.\n>>\n>> I don't think this desire to just wait a bit until all the fetches are\n>> complete makes sense as a special-case.\n>>\n>> If, as you noted in <20190619190845.GD28145@sigill.intra.peff.net>, the\n>> desire is to reduce GC CPU use then you're better off just tweaking the\n>> limits upwards. Then you get that with everything, like when you run\n>> \"commit\" in a for-loop, not just this one special case of \"fetch\".\n>>\n>> We have existing potentially long-running operations like \"fetch\",\n>> \"rebase\" and \"git svn fetch\" that run \"gc --auto\" for their incremental\n>> steps, and that's a feature.\n>\n> gc --auto is added at arbitrary points to help garbage collection. I\n> don't think it's ever intended to \"do gc at this and that exact\n> moment\", just \"hey this command has taken a lot of time already (i.e.\n> no instant response needed) and it may have added a bit more garbage,\n> let's just check real quick\".\n\nI don't mean we can't ever change the algorithm, but that we've\ndocumented:\n\n    When common porcelain operations that create objects are run, they\n    will check whether the repository has grown substantially since the\n    last maintenance[...]\n\nThe \"fetch\" command is a common porcelain operation, when it fetches\nfrom N remotes it just runs an invocation of itself, so thus far it's\nboth worked & been intuitive that if we needed (potentially multiple)\ngc's while doing that we'd just go ahead and run it then, even if\nsomething concurrent was happening.\n\nNo that's not optimal in many cases, but at least doesn't create caveats\nwe don't have now where we have runaway object growth.\n\n>> It keeps \"gc --auto\" dumb enough to avoid a pathological case where\n>> we'll have a ballooning objects dir because we figure we can run\n>> something \"at the end\", when \"the end\" could be hours away, and we're\n>> adding a new pack or hundreds of loose objects every second.\n>\n> Are we optimizing for a rare (large scale) case? Such setup requires\n> tuning regardless to me.\n\nAt least for me it doesn't require custom tuning before this patch of\nyours.\n\nI.e. now \"gc --auto\" is dumb enough that you can run it on everything\nfrom stuff that just does \"commit\" from cron, user's laptops, massive\nrebases that take forever, and e.g. \"stats\" like jobs where for\n<reasons> I'll add thousands of repos and \"fetch --all\" them (so e.g. I\ncan run \"log --author=<x> --all\").\n\nYeah of course I'm an advanced user and I can just grumble and manually\ninvoke fetch, actually I'll probably submit a follow-up patch to add a\ngc.* config to disable this thing.\n\nBut I think even if the use-case is rather obscure it's important that\nif at all possible we keep \"gc\" elastic enough to work for pretty much\nall combinations of object-adding porcelain commands, and I think in\nthis case we're better off doing things differently...\n\n>> So I don't think Duy's patch is a good way to go.\n>\n> This reminds me of being perfect is the enemy of the good. A normal\n> user has a couple remotes at most, finishing fast (enough) and in such\n> case it's a good idea to wait until everything is in before running\n> gc.\n\nEven a user with two remotes will run into issues with your patch where\n\"gc\" will print things twice, or outright error due to concurrent access\nby another process, which as has been discussed here on-list is *very*\ncommon e.g. with editor integration.\n\nSo the extent of my complains about this is:\n\n 1) The edge case with runaway object growth (obscure)\n\n 2) It doesn't really fix the bug except for the narrow case of users\n    who invoke things one-terminal-at-a-time and don't e.g. have an\n    editor with \"git\" integration & a terminal (not obscure).\n\nMaybe I should have led with #2 :)\n\nAnyway, I'm not *just* complaining. I have patches too, but so far I'm\nup to 8 patches on what's probably just the first one-third of\nit. *Sigh*.\n\nBut the 2/3 of that if you want to dig through my crappy WIP code on\nGitHub is instrumenting the test suite to demonstrate that with an\napproach like what your patch does we still get these GC race\nconditions, because our locking still sucks, which brings me to...\n\n> Of course making git-gc more robust wrt. parallel access is great, but\n> it's hard work. Dealing with locks is always tricky, especially when\n> new locks can come up any time.\n\nI've poked at it a bit now, and it's really not hard, I think it's just\nthat nobody looked at it hard enough before.\n\nThe issue is that currently we do:\n\n    1. parent: do_we_need_gc();\n    2. parent: say_way_will_gc();\n    3. parent: lock();\n    4. parent: do_a_bit_of_work();\n    5. parent: unlock();\n    6. parent: fork();\n    7. child: lock();\n    8. child: do_a_lot_of_work();\n    9. child: unlock();\n\nMy RFC patch currently changes that to:\n\n    1. parent: do_we_need_gc();\n    2. parent: lock_or_silently_exit();\n    3. parent: say_way_will_gc();\n    4. parent: do_a_bit_of_work();\n    5. parent: unlock();\n    6. parent: fork();\n    7. child: lock();\n    8. child: do_a_lot_of_work();\n    9. child: unlock();\n\nI.e. we won't duplicate the message, but *do* introduce the caveat that\nit's in principle possible nobody gc's, but in practice when we fail to\nget the lock in lock_or_silently_exit() it's because we lost the race to\na sister process that's going to do the actual GC, so all is well.\n\nBut we are left with the brief race when we fork. My RFC patch proposed\nsome elaborate PID hand-over dance to deal with this. But having looked\nat it again I think we can easily get rid of that race too with just:\n\n    1. parent: do_we_need_gc();\n    2. parent: lock_or_silently_exit();\n    3. parent: say_way_will_gc();\n    4. parent: do_a_bit_of_work();\n    5. parent: fork();\n    6. parent: <writes child pid to gc.lock>\n    7. parent: <exits without unlocking gc.lock>\n    8. child: do_a_lot_of_work();\n    9. child: unlock();\n\nWhich can fail in cases where the child segfaults, or manages to exit\nearlier than the parent etc, hence my earlier proposed elaborate pid\nhand-over dance.\n\nBut looking at it again we only usurp an existing gc.lock if the mtime\nis >12hrs, so it's OK if we have very rare cases where the PID info got\ncorrupted, we can still back ourselves out of it, which is what I was\nparanoid about.\n\nFurthermore the gc.lock contains the <hostname><pid> of the working\nprocess, but we can in a backwards-compatible way add new entries to\nthat file, i.e. list both the child & parent pid. Older clients will\njust read whichever one comes first, but if we make new versions check\nboth we can be more paranoid going forward.\n\n> Having said that, I don't mind if my patch gets dropped. It was just a\n> \"hey that multiple gc output looks strange, hah the fix is quite\n> simple\" moment for me.\n"},{"id":"377715","messageId":"xmqqpnn7lxet.fsf@gitster-ct.c.googlers.com","threadId":"51336","inReplyTo":"20190620210915.11297-3-avarab@gmail.com","subject":"Re: [PATCH v2 2/8] env--helper: new undocumented builtin wrapping git_env_*()","fromName":"Junio C Hamano","fromEmail":"gitster@pobox.com","sentAt":"2019-06-20T22:11:38Z","receivedAt":"2019-06-20T22:11:46Z","isPatch":true,"sender":{"key":"gitster@pobox.com","avatar":"https://avatars.githubusercontent.com/u/54884?v=4"},"body":"Ævar Arnfjörð Bjarmason  <avarab@gmail.com> writes:\n\n> +\tswitch (cmdmode) {\n> +\tcase ENV_HELPER_BOOL:\n> +\t\ttmp_int = strtol(env_default, (char **)&env_default, 10);\n> +\t\tif (*env_default) {\n> +\t\t\terror(_(\"option `--default' expects a numerical value with `--mode-bool`\"));\n> +\t\t\tusage_with_options(env__helper_usage, opts);\n> +\t\t}\n> +\t\tret_int = git_env_bool(env_variable, tmp_int);\n> +\t\tif (!quiet)\n> +\t\t\tprintf(\"%d\\n\", ret_int);\n> +\t\tret = ret_int;\n> +\t\tbreak;\n> +\tcase ENV_HELPER_ULONG:\n> +\t\ttmp_ulong = strtoll(env_default, (char **)&env_default, 10);\n> +\t\tif (*env_default) {\n> +\t\t\terror(_(\"option `--default' expects a numerical value with `--mode-ulong`\"));\n> +\t\t\tusage_with_options(env__helper_usage, opts);\n> +\t\t}\n> +\t\tret_ulong = git_env_ulong(env_variable, tmp_ulong);\n> +\t\tif (!quiet)\n> +\t\t\tprintf(\"%lu\\n\", ret_ulong);\n> +\t\tret = ret_ulong;\n> +\t\tbreak;\n\nPerhaps have something like 'default: BUG(\"wrong cmdmode\");'\n\n> +\t}\n> +\n> +\tif (exit_code)\n> +\t\treturn !ret;\n\nas I am getting\n\n    error: 'ret' may be used uninitialized in this function [-Werror=maybe-uninitialized]\n\nfrom here.\n\nGiving an otherwise useless initial value to ret would be a\nworkaround.\n"},{"id":"377716","messageId":"xmqqlfxvlwyg.fsf@gitster-ct.c.googlers.com","threadId":"51336","inReplyTo":"xmqqpnn7lxet.fsf@gitster-ct.c.googlers.com","subject":"Re: [PATCH v2 2/8] env--helper: new undocumented builtin wrapping git_env_*()","fromName":"Junio C Hamano","fromEmail":"gitster@pobox.com","sentAt":"2019-06-20T22:21:27Z","receivedAt":"2019-06-20T22:21:32Z","isPatch":true,"sender":{"key":"gitster@pobox.com","avatar":"https://avatars.githubusercontent.com/u/54884?v=4"},"body":"Junio C Hamano <gitster@pobox.com> writes:\n\n> ...\n> as I am getting\n>\n>     error: 'ret' may be used uninitialized in this function [-Werror=maybe-uninitialized]\n>\n> from here.\n>\n> Giving an otherwise useless initial value to ret would be a\n> workaround.\n\nI've added this on top of the topic before merging to keep the\nintegration going at least for now.\n\ncommit 8f86948797a1152594a8dee50d0878604fec3e80\nAuthor: Junio C Hamano <gitster@pobox.com>\nDate:   Thu Jun 20 15:13:14 2019 -0700\n\n    SQUASH??? avoid maybe-uninitialized\n\ndiff --git a/builtin/env--helper.c b/builtin/env--helper.c\nindex 2bb65ecf3f..29df0567fb 100644\n--- a/builtin/env--helper.c\n+++ b/builtin/env--helper.c\n@@ -43,6 +43,9 @@ int cmd_env__helper(int argc, const char **argv, const char *prefix)\n \t\tusage_with_options(env__helper_usage, opts);\n \n \tswitch (cmdmode) {\n+\tdefault:\n+\t\tBUG(\"wrong cmdmode\");\n+\t\tbreak;\n \tcase ENV_HELPER_BOOL:\n \t\ttmp_int = strtol(env_default, (char **)&env_default, 10);\n \t\tif (*env_default) {\n"},{"id":"377719","messageId":"87blyr8ijr.fsf@evledraar.gmail.com","threadId":"51336","inReplyTo":"xmqqlfxvlwyg.fsf@gitster-ct.c.googlers.com","subject":"Re: [PATCH v2 2/8] env--helper: new undocumented builtin wrapping git_env_*()","fromName":"Ævar Arnfjörð Bjarmason","fromEmail":"avarab@gmail.com","sentAt":"2019-06-21T08:11:04Z","receivedAt":"2019-06-21T08:11:09Z","isPatch":true,"sender":{"key":"avarab@gmail.com","avatar":"https://avatars.githubusercontent.com/u/45301?v=4"},"body":"\nOn Fri, Jun 21 2019, Junio C Hamano wrote:\n\n> Junio C Hamano <gitster@pobox.com> writes:\n>\n>> ...\n>> as I am getting\n>>\n>>     error: 'ret' may be used uninitialized in this function [-Werror=maybe-uninitialized]\n>>\n>> from here.\n>>\n>> Giving an otherwise useless initial value to ret would be a\n>> workaround.\n>\n> I've added this on top of the topic before merging to keep the\n> integration going at least for now.\n>\n> commit 8f86948797a1152594a8dee50d0878604fec3e80\n> Author: Junio C Hamano <gitster@pobox.com>\n> Date:   Thu Jun 20 15:13:14 2019 -0700\n>\n>     SQUASH??? avoid maybe-uninitialized\n>\n> diff --git a/builtin/env--helper.c b/builtin/env--helper.c\n> index 2bb65ecf3f..29df0567fb 100644\n> --- a/builtin/env--helper.c\n> +++ b/builtin/env--helper.c\n> @@ -43,6 +43,9 @@ int cmd_env__helper(int argc, const char **argv, const char *prefix)\n>  \t\tusage_with_options(env__helper_usage, opts);\n>\n>  \tswitch (cmdmode) {\n> +\tdefault:\n> +\t\tBUG(\"wrong cmdmode\");\n> +\t\tbreak;\n>  \tcase ENV_HELPER_BOOL:\n>  \t\ttmp_int = strtol(env_default, (char **)&env_default, 10);\n>  \t\tif (*env_default) {\n\nIn this case the compiler is wrong, and gcc/clang in e.g. Debian\nunstable doesn't warn about this since the analyzer sees that it's\nimpossible for \"ret\" to be uninitialized.\n\nI can change it anyway, and if I rewrite the UI of this command it might\ngo away anyway.\n\nJust thought I'd ask if appeasing older analyzers is what we want for\nthese sorts of optional warnings in general.\n"},{"id":"377728","messageId":"20190621101812.27300-2-avarab@gmail.com","threadId":"51336","inReplyTo":"20190620210915.11297-1-avarab@gmail.com","subject":"[PATCH v3 1/8] config tests: simplify include cycle test","fromName":"Ævar Arnfjörð Bjarmason","fromEmail":"avarab@gmail.com","sentAt":"2019-06-21T10:18:05Z","receivedAt":"2019-06-21T10:18:29Z","isPatch":true,"sender":{"key":"avarab@gmail.com","avatar":"https://avatars.githubusercontent.com/u/45301?v=4"},"body":"Simplify an overly verbose test added in 9b25a0b52e (\"config: add\ninclude directive\", 2012-02-06). The \"expect\" file was never used, and\nby using .gitconfig it's not as intuitive to reproduce this manually\nwith \"-d\" as some other tests, since HOME needs to be set in the\nenvironment.\n\nAlso remove the use of test_i18ngrep added in a769bfc74f (\"config.c:\nmark more strings for translation\", 2018-07-21) in favor of overriding\nthe GIT_TEST_GETTEXT_POISON value.\n\nUsing the i18n test wrappers hasn't been needed since my\n6cdccfce1e (\"i18n: make GETTEXT_POISON a runtime option\", 2018-11-08).\nAs a follow-up change to the yet-to-be-added t0017-env-helper.sh will\nshow, doing it this way can hide a regression when combined with\ntrace2's early config reading. That early config reading was added in\nbce9db6de9 (\"trace2: use system/global config for default trace2\nsettings\", 2019-04-15).\n\nSo let's remove the testing for that potential regression here, I'll\ninstead add it explicitly to t0017-env-helper.sh in a follow-up\nchange.\n\nSigned-off-by: Ævar Arnfjörð Bjarmason <avarab@gmail.com>\n---\n t/t1305-config-include.sh | 21 +++++++--------------\n 1 file changed, 7 insertions(+), 14 deletions(-)\n\ndiff --git a/t/t1305-config-include.sh b/t/t1305-config-include.sh\nindex 579a86b7f8..6b388ba2d0 100755\n--- a/t/t1305-config-include.sh\n+++ b/t/t1305-config-include.sh\n@@ -310,20 +310,13 @@ test_expect_success SYMLINKS 'conditional include, gitdir matching symlink, icas\n '\n \n test_expect_success 'include cycles are detected' '\n-\tcat >.gitconfig <<-\\EOF &&\n-\t[test]value = gitconfig\n-\t[include]path = cycle\n-\tEOF\n-\tcat >cycle <<-\\EOF &&\n-\t[test]value = cycle\n-\t[include]path = .gitconfig\n-\tEOF\n-\tcat >expect <<-\\EOF &&\n-\tgitconfig\n-\tcycle\n-\tEOF\n-\ttest_must_fail git config --get-all test.value 2>stderr &&\n-\ttest_i18ngrep \"exceeded maximum include depth\" stderr\n+\tgit init --bare cycle &&\n+\tgit -C cycle config include.path cycle &&\n+\tgit config -f cycle/cycle include.path config &&\n+\ttest_must_fail \\\n+\t\tenv GIT_TEST_GETTEXT_POISON= \\\n+\t\tgit -C cycle config --get-all test.value 2>stderr &&\n+\tgrep \"exceeded maximum include depth\" stderr\n '\n \n test_done\n-- \n2.22.0.455.g172b71a6c5\n\n"},{"id":"377729","messageId":"20190621101812.27300-1-avarab@gmail.com","threadId":"51336","inReplyTo":"20190620210915.11297-1-avarab@gmail.com","subject":"[PATCH v3 0/8] Change <non-empty?> GIT_TEST_* variables to <boolean>","fromName":"Ævar Arnfjörð Bjarmason","fromEmail":"avarab@gmail.com","sentAt":"2019-06-21T10:18:04Z","receivedAt":"2019-06-21T10:18:29Z","isPatch":true,"sender":{"key":"avarab@gmail.com","avatar":"https://avatars.githubusercontent.com/u/45301?v=4"},"body":"Now with:\n\n * The --type=bool etc. Ui change to env--bool.\n\n * I considered supporting YesPlease for gettext poison, but didn't go\n   for it. Details in updated commit message.\n\n * \"default\" \"case\" arm fork warning on some compilers.\n\nÆvar Arnfjörð Bjarmason (8):\n  config tests: simplify include cycle test\n  env--helper: new undocumented builtin wrapping git_env_*()\n  config.c: refactor die_bad_number() to not call gettext() early\n  t6040 test: stop using global \"script\" variable\n  tests: make GIT_TEST_GETTEXT_POISON a boolean\n  tests README: re-flow a previously changed paragraph\n  tests: replace test_tristate with \"git env--helper\"\n  tests: make GIT_TEST_FAIL_PREREQS a boolean\n\n .gitignore                |  1 +\n Makefile                  |  1 +\n builtin.h                 |  1 +\n builtin/env--helper.c     | 95 +++++++++++++++++++++++++++++++++++++\n ci/lib.sh                 |  2 +-\n config.c                  | 28 +++++++----\n gettext.c                 |  6 +--\n git-sh-i18n.sh            |  4 +-\n git.c                     |  1 +\n po/README                 |  2 +-\n t/README                  | 12 ++---\n t/lib-git-daemon.sh       |  7 ++-\n t/lib-git-svn.sh          | 11 ++---\n t/lib-httpd.sh            | 15 +++---\n t/t0000-basic.sh          | 10 ++--\n t/t0017-env-helper.sh     | 99 +++++++++++++++++++++++++++++++++++++++\n t/t0205-gettext-poison.sh |  7 ++-\n t/t1305-config-include.sh | 21 +++------\n t/t5512-ls-remote.sh      |  3 +-\n t/t6040-tracking-info.sh  |  6 +--\n t/t7201-co.sh             |  2 +-\n t/t9902-completion.sh     |  2 +-\n t/test-lib-functions.sh   | 58 ++++-------------------\n t/test-lib.sh             | 31 ++++++++----\n 24 files changed, 298 insertions(+), 127 deletions(-)\n create mode 100644 builtin/env--helper.c\n create mode 100755 t/t0017-env-helper.sh\n\nRange-diff:\n1:  c3483c37a1 = 1:  c3483c37a1 config tests: simplify include cycle test\n2:  e689759f7c ! 2:  39cb96739a env--helper: new undocumented builtin wrapping git_env_*()\n    @@ -20,9 +20,11 @@\n         default value makes all the difference, and we'll be able to replace\n         test_tristate() itself with that.\n     \n    -    The --mode-bool option will be used by subsequent patches, but not\n    -    --mode-ulong. I figured it was easy enough to add it & test for it so\n    -    I left it in so we'd have wrappers for both git_env_*() functions.\n    +    The --type=bool option will be used by subsequent patches, but not\n    +    --type=ulong. I figured it was easy enough to add it & test for it so\n    +    I left it in so we'd have wrappers for both git_env_*() functions, and\n    +    to have a template to make it obvious how we'd add --type=int etc. if\n    +    it's needed in the future.\n     \n         Signed-off-by: Ævar Arnfjörð Bjarmason <avarab@gmail.com>\n     \n    @@ -72,74 +74,95 @@\n     +#include \"parse-options.h\"\n     +\n     +static char const * const env__helper_usage[] = {\n    -+\tN_(\"git env--helper [--mode-bool | --mode-ulong] --env-variable=<VAR> --env-default=<DEF> [<options>]\"),\n    ++\tN_(\"git env--helper --type=[bool|ulong] <options> <env-var>\"),\n     +\tNULL\n     +};\n     +\n    ++enum {\n    ++\tENV_HELPER_TYPE_BOOL = 1,\n    ++\tENV_HELPER_TYPE_ULONG\n    ++} cmdmode = 0;\n    ++\n    ++static int option_parse_type(const struct option *opt, const char *arg,\n    ++\t\t\t     int unset)\n    ++{\n    ++\tif (!strcmp(arg, \"bool\"))\n    ++\t\tcmdmode = ENV_HELPER_TYPE_BOOL;\n    ++\telse if (!strcmp(arg, \"ulong\"))\n    ++\t\tcmdmode = ENV_HELPER_TYPE_ULONG;\n    ++\telse\n    ++\t\tdie(_(\"unrecognized --type argument, %s\"), arg);\n    ++\n    ++\treturn 0;\n    ++}\n    ++\n     +int cmd_env__helper(int argc, const char **argv, const char *prefix)\n     +{\n    -+\tenum {\n    -+\t\tENV_HELPER_BOOL = 1,\n    -+\t\tENV_HELPER_ULONG,\n    -+\t} cmdmode = 0;\n     +\tint exit_code = 0;\n    -+\tint quiet = 0;\n     +\tconst char *env_variable = NULL;\n     +\tconst char *env_default = NULL;\n     +\tint ret;\n    -+\tint ret_int, tmp_int;\n    -+\tunsigned long ret_ulong, tmp_ulong;\n    ++\tint ret_int, default_int;\n    ++\tunsigned long ret_ulong, default_ulong;\n     +\tstruct option opts[] = {\n    -+\t\tOPT_CMDMODE(0, \"mode-bool\", &cmdmode,\n    -+\t\t\t    N_(\"invoke git_env_bool(...)\"), ENV_HELPER_BOOL),\n    -+\t\tOPT_CMDMODE(0, \"mode-ulong\", &cmdmode,\n    -+\t\t\t    N_(\"invoke git_env_ulong(...)\"), ENV_HELPER_ULONG),\n    -+\t\tOPT_STRING(0, \"variable\", &env_variable, N_(\"name\"),\n    -+\t\t\t   N_(\"which environment variable to ask git_env_*(...) about\")),\n    ++\t\tOPT_CALLBACK_F(0, \"type\", &cmdmode, N_(\"type\"),\n    ++\t\t\t       N_(\"value is given this type\"), PARSE_OPT_NONEG,\n    ++\t\t\t       option_parse_type),\n     +\t\tOPT_STRING(0, \"default\", &env_default, N_(\"value\"),\n    -+\t\t\t   N_(\"what default value does git_env_*(...) fall back on?\")),\n    ++\t\t\t   N_(\"default for git_env_*(...) to fall back on\")),\n     +\t\tOPT_BOOL(0, \"exit-code\", &exit_code,\n    -+\t\t\t N_(\"exit code determined by truth of the git_env_*() function\")),\n    -+\t\tOPT_BOOL(0, \"quiet\", &quiet,\n    -+\t\t\t N_(\"don't print the git_env_*() return value\")),\n    ++\t\t\t N_(\"be quiet only use git_env_*() value as exit code\")),\n     +\t\tOPT_END(),\n     +\t};\n     +\n    -+\tif (parse_options(argc, argv, prefix, opts, env__helper_usage, 0))\n    ++\targc = parse_options(argc, argv, prefix, opts, env__helper_usage,\n    ++\t\t\t     PARSE_OPT_KEEP_UNKNOWN);\n    ++\tif (env_default && !*env_default)\n     +\t\tusage_with_options(env__helper_usage, opts);\n    -+\tif (!env_variable || !env_default ||\n    -+\t    !*env_variable || !*env_default)\n    ++\tif (!cmdmode)\n     +\t\tusage_with_options(env__helper_usage, opts);\n    ++\tif (argc != 1)\n    ++\t\tusage_with_options(env__helper_usage, opts);\n    ++\tenv_variable = argv[0];\n     +\n     +\tswitch (cmdmode) {\n    -+\tcase ENV_HELPER_BOOL:\n    -+\t\ttmp_int = strtol(env_default, (char **)&env_default, 10);\n    -+\t\tif (*env_default) {\n    -+\t\t\terror(_(\"option `--default' expects a numerical value with `--mode-bool`\"));\n    -+\t\t\tusage_with_options(env__helper_usage, opts);\n    ++\tcase ENV_HELPER_TYPE_BOOL:\n    ++\t\tif (env_default) {\n    ++\t\t\tdefault_int = git_parse_maybe_bool(env_default);\n    ++\t\t\tif (default_int == -1) {\n    ++\t\t\t\terror(_(\"option `--default' expects a boolean value with `--type=bool`, not `%s`\"),\n    ++\t\t\t\t      env_default);\n    ++\t\t\t\tusage_with_options(env__helper_usage, opts);\n    ++\t\t\t}\n    ++\t\t} else {\n    ++\t\t\tdefault_int = 0;\n     +\t\t}\n    -+\t\tret_int = git_env_bool(env_variable, tmp_int);\n    -+\t\tif (!quiet)\n    -+\t\t\tprintf(\"%d\\n\", ret_int);\n    ++\t\tret_int = git_env_bool(env_variable, default_int);\n    ++\t\tif (!exit_code)\n    ++\t\t\tputs(ret_int ? \"true\" : \"false\");\n     +\t\tret = ret_int;\n     +\t\tbreak;\n    -+\tcase ENV_HELPER_ULONG:\n    -+\t\ttmp_ulong = strtoll(env_default, (char **)&env_default, 10);\n    -+\t\tif (*env_default) {\n    -+\t\t\terror(_(\"option `--default' expects a numerical value with `--mode-ulong`\"));\n    -+\t\t\tusage_with_options(env__helper_usage, opts);\n    ++\tcase ENV_HELPER_TYPE_ULONG:\n    ++\t\tif (env_default) {\n    ++\t\t\tif (!git_parse_ulong(env_default, &default_ulong)) {\n    ++\t\t\t\terror(_(\"option `--default' expects an unsigned long value with `--type=ulong`, not `%s`\"),\n    ++\t\t\t\t      env_default);\n    ++\t\t\t\tusage_with_options(env__helper_usage, opts);\n    ++\t\t\t}\n    ++\t\t} else {\n    ++\t\t\tdefault_ulong = 0;\n     +\t\t}\n    -+\t\tret_ulong = git_env_ulong(env_variable, tmp_ulong);\n    -+\t\tif (!quiet)\n    ++\t\tret_ulong = git_env_ulong(env_variable, default_ulong);\n    ++\t\tif (!exit_code)\n     +\t\t\tprintf(\"%lu\\n\", ret_ulong);\n     +\t\tret = ret_ulong;\n     +\t\tbreak;\n    ++\tdefault:\n    ++\t\tBUG(\"unknown <type> value\");\n    ++\t\tbreak;\n     +\t}\n     +\n    -+\tif (exit_code)\n    -+\t\treturn !ret;\n    -+\n    -+\treturn 0;\n    ++\treturn !ret;\n     +}\n     \n      diff --git a/git.c b/git.c\n    @@ -168,64 +191,77 @@\n     +\n     +test_expect_success 'env--helper usage' '\n     +\ttest_must_fail git env--helper &&\n    -+\ttest_must_fail git env--helper --mode-bool &&\n    -+\ttest_must_fail git env--helper --mode-ulong &&\n    -+\ttest_must_fail git env--helper --mode-bool --variable &&\n    -+\ttest_must_fail git env--helper --mode-bool --variable --default &&\n    -+\ttest_must_fail git env--helper --mode-bool --variable= --default=\n    ++\ttest_must_fail git env--helper --type=bool &&\n    ++\ttest_must_fail git env--helper --type=ulong &&\n    ++\ttest_must_fail git env--helper --type=bool &&\n    ++\ttest_must_fail git env--helper --type=bool --default &&\n    ++\ttest_must_fail git env--helper --type=bool --default= &&\n    ++\ttest_must_fail git env--helper --defaultxyz\n     +'\n     +\n     +test_expect_success 'env--helper bad default values' '\n    -+\ttest_must_fail git env--helper --mode-bool --variable=MISSING --default=1xyz &&\n    -+\ttest_must_fail git env--helper --mode-ulong --variable=MISSING --default=1xyz\n    ++\ttest_must_fail git env--helper --type=bool --default=1xyz MISSING &&\n    ++\ttest_must_fail git env--helper --type=ulong --default=1xyz MISSING\n     +'\n     +\n    -+test_expect_success 'env--helper --mode-bool' '\n    -+\techo 1 >expected &&\n    -+\tgit env--helper --mode-bool --variable=MISSING --default=1 --exit-code >actual &&\n    ++test_expect_success 'env--helper --type=bool' '\n    ++\t# Test various --default bool values\n    ++\techo true >expected &&\n    ++\tgit env--helper --type=bool --default=1 MISSING >actual &&\n     +\ttest_cmp expected actual &&\n    -+\n    -+\techo 0 >expected &&\n    -+\ttest_must_fail git env--helper --mode-bool --variable=MISSING --default=0 --exit-code >actual &&\n    ++\tgit env--helper --type=bool --default=yes MISSING >actual &&\n     +\ttest_cmp expected actual &&\n    -+\n    -+\tgit env--helper --mode-bool --variable=MISSING --default=0 >actual &&\n    ++\tgit env--helper --type=bool --default=true MISSING >actual &&\n     +\ttest_cmp expected actual &&\n    -+\n    -+\t>expected &&\n    -+\tgit env--helper --mode-bool --variable=MISSING --default=1 --exit-code --quiet >actual &&\n    ++\techo false >expected &&\n    ++\ttest_must_fail git env--helper --type=bool --default=0 MISSING >actual &&\n     +\ttest_cmp expected actual &&\n    -+\n    -+\tEXISTS=true git env--helper --mode-bool --variable=EXISTS --default=0 --exit-code --quiet >actual &&\n    ++\ttest_must_fail git env--helper --type=bool --default=no MISSING >actual &&\n    ++\ttest_cmp expected actual &&\n    ++\ttest_must_fail git env--helper --type=bool --default=false MISSING >actual &&\n     +\ttest_cmp expected actual &&\n     +\n    -+\techo 1 >expected &&\n    -+\tEXISTS=true git env--helper --mode-bool --variable=EXISTS --default=0 --exit-code >actual &&\n    -+\ttest_cmp expected actual\n    ++\t# No output with --exit-code\n    ++\tgit env--helper --type=bool --default=true --exit-code MISSING >actual.out 2>actual.err &&\n    ++\ttest_must_be_empty actual.out &&\n    ++\ttest_must_be_empty actual.err &&\n    ++\ttest_must_fail git env--helper --type=bool --default=false --exit-code MISSING >actual.out 2>actual.err &&\n    ++\ttest_must_be_empty actual.out &&\n    ++\ttest_must_be_empty actual.err &&\n    ++\n    ++\t# Existing variable\n    ++\tEXISTS=true git env--helper --type=bool --default=false --exit-code EXISTS >actual.out 2>actual.err &&\n    ++\ttest_must_be_empty actual.out &&\n    ++\ttest_must_be_empty actual.err &&\n    ++\ttest_must_fail \\\n    ++\t\tenv EXISTS=false \\\n    ++\t\tgit env--helper --type=bool --default=true --exit-code EXISTS >actual.out 2>actual.err &&\n    ++\ttest_must_be_empty actual.out &&\n    ++\ttest_must_be_empty actual.err\n     +'\n     +\n    -+test_expect_success 'env--helper --mode-ulong' '\n    ++test_expect_success 'env--helper --type=ulong' '\n     +\techo 1234567890 >expected &&\n    -+\tgit env--helper --mode-ulong --variable=MISSING --default=1234567890 --exit-code >actual &&\n    -+\ttest_cmp expected actual &&\n    ++\tgit env--helper --type=ulong --default=1234567890 MISSING >actual.out 2>actual.err &&\n    ++\ttest_cmp expected actual.out &&\n    ++\ttest_must_be_empty actual.err &&\n     +\n     +\techo 0 >expected &&\n    -+\ttest_must_fail git env--helper --mode-ulong --variable=MISSING --default=0 --exit-code >actual &&\n    ++\ttest_must_fail git env--helper --type=ulong --default=0 MISSING >actual &&\n     +\ttest_cmp expected actual &&\n     +\n    -+\tgit env--helper --mode-ulong --variable=MISSING --default=0 >actual &&\n    -+\ttest_cmp expected actual &&\n    ++\tgit env--helper --type=ulong --default=1234567890 --exit-code MISSING >actual.out 2>actual.err &&\n    ++\ttest_must_be_empty actual.out &&\n    ++\ttest_must_be_empty actual.err &&\n     +\n    -+\t>expected &&\n    -+\tgit env--helper --mode-ulong --variable=MISSING --default=1234567890 --exit-code --quiet >actual &&\n    -+\ttest_cmp expected actual &&\n    -+\n    -+\tEXISTS=1234567890 git env--helper --mode-ulong --variable=EXISTS --default=0 --exit-code --quiet >actual &&\n    -+\ttest_cmp expected actual &&\n    ++\tEXISTS=1234567890 git env--helper --type=ulong --default=0 EXISTS --exit-code >actual.out 2>actual.err &&\n    ++\ttest_must_be_empty actual.out &&\n    ++\ttest_must_be_empty actual.err &&\n     +\n     +\techo 1234567890 >expected &&\n    -+\tEXISTS=1234567890 git env--helper --mode-ulong --variable=EXISTS --default=0 --exit-code >actual &&\n    -+\ttest_cmp expected actual\n    ++\tEXISTS=1234567890 git env--helper --type=ulong --default=0 EXISTS >actual.out 2>actual.err &&\n    ++\ttest_cmp expected actual.out &&\n    ++\ttest_must_be_empty actual.err\n     +'\n     +\n     +test_done\n3:  f759d5e91e = 3:  8a88f263bf config.c: refactor die_bad_number() to not call gettext() early\n4:  1ac798e8ce = 4:  6594a95d6e t6040 test: stop using global \"script\" variable\n5:  d7d6e6c874 ! 5:  248c0f9d46 tests: make GIT_TEST_GETTEXT_POISON a boolean\n    @@ -17,7 +17,7 @@\n         the special case of GIT_TEST_GETTEXT_POISON and always emit that\n         message in the C locale, lest we infinitely loop.\n     \n    -    As seen in the updated tests in t0016-env-helper.sh there's also a\n    +    As seen in the updated tests in t0017-env-helper.sh there's also a\n         caveat related to \"env--helper\" needing to read the config for trace2\n         purposes.\n     \n    @@ -32,6 +32,21 @@\n         change in this series won't happen again, and testing for this\n         explicitly in \"env--helper\"'s own tests.\n     \n    +    This change breaks existing uses of\n    +    e.g. GIT_TEST_GETTEXT_POISON=YesPlease, which we've documented in\n    +    po/README and other places. As noted in [1] we might want to consider\n    +    also accepting \"YesPlease\" in \"env--helper\" as a special-case.\n    +\n    +    But as the lack of uproar over 6cdccfce1e (\"i18n: make GETTEXT_POISON\n    +    a runtime option\", 2018-11-08) demonstrates the audience for this\n    +    option is a really narrow set of git developers, who shouldn't have\n    +    much trouble modifying their test scripts, so I think it's better to\n    +    deal with that minor headache now and make all the relevant GIT_TEST_*\n    +    variables boolean in the same way than carry the \"YesPlease\"\n    +    special-case forward.\n    +\n    +    1. https://public-inbox.org/git/xmqqtvckm3h8.fsf@gitster-ct.c.googlers.com/\n    +\n         Signed-off-by: Ævar Arnfjörð Bjarmason <avarab@gmail.com>\n     \n      diff --git a/ci/lib.sh b/ci/lib.sh\n    @@ -93,8 +108,8 @@\n      GIT_INTERNAL_GETTEXT_SH_SCHEME=fallthrough\n     -if test -n \"$GIT_TEST_GETTEXT_POISON\"\n     +if test -n \"$GIT_TEST_GETTEXT_POISON\" &&\n    -+\t    git env--helper --mode-bool --variable=GIT_TEST_GETTEXT_POISON \\\n    -+\t\t--default=0 --exit-code --quiet\n    ++\t    git env--helper --type=bool --default=0 --exit-code \\\n    ++\t\tGIT_TEST_GETTEXT_POISON\n      then\n      \tGIT_INTERNAL_GETTEXT_SH_SCHEME=poison\n      elif test -n \"@@USE_GETTEXT_SCHEME@@\"\n    @@ -131,7 +146,7 @@\n      --- a/t/t0017-env-helper.sh\n      +++ b/t/t0017-env-helper.sh\n     @@\n    - \ttest_cmp expected actual\n    + \ttest_must_be_empty actual.err\n      '\n      \n     +test_expect_success 'env--helper reads config thanks to trace2' '\n    @@ -146,7 +161,7 @@\n     +\n     +\ttest_must_fail \\\n     +\t\tenv HOME=\"$(pwd)/home\" GIT_TEST_GETTEXT_POISON=true \\\n    -+\t\tgit -C cycle env--helper --mode-bool --variable=GIT_TEST_GETTEXT_POISON --default=0 --exit-code --quiet 2>err &&\n    ++\t\tgit -C cycle env--helper --type=bool --default=0 --exit-code GIT_TEST_GETTEXT_POISON 2>err &&\n     +\tgrep \"# GETTEXT POISON #\" err\n     +'\n     +\n    @@ -227,7 +242,7 @@\n     -\ttest_set_prereq C_LOCALE_OUTPUT\n     -fi\n     +test_lazy_prereq C_LOCALE_OUTPUT '\n    -+\t! git env--helper --mode-bool --variable=GIT_TEST_GETTEXT_POISON --default=0 --exit-code --quiet\n    ++\t! git env--helper --type=bool --default=0 --exit-code GIT_TEST_GETTEXT_POISON\n     +'\n      \n      if test -z \"$GIT_TEST_CHECK_CACHE_TREE\"\n6:  954428b3cd = 6:  c9d44aa306 tests README: re-flow a previously changed paragraph\n7:  79b41cf01b ! 7:  b0bab6adc8 tests: replace test_tristate with \"git env--helper\"\n    @@ -35,7 +35,7 @@\n      \n     -test_tristate GIT_TEST_GIT_DAEMON\n     -if test \"$GIT_TEST_GIT_DAEMON\" = false\n    -+if ! git env--helper --mode-bool --variable=GIT_TEST_GIT_DAEMON --default=1 --exit-code --quiet\n    ++if ! git env--helper --type=bool --default=true --exit-code GIT_TEST_GIT_DAEMON\n      then\n      \tskip_all=\"git-daemon testing disabled (unset GIT_TEST_GIT_DAEMON to enable)\"\n      \ttest_done\n    @@ -68,7 +68,7 @@\n     -\ttest_tristate GIT_SVN_TEST_HTTPD\n     -\tcase $GIT_SVN_TEST_HTTPD in\n     -\ttrue)\n    -+\tif git env--helper --mode-bool --variable=GIT_TEST_HTTPD --default=0 --exit-code --quiet\t\n    ++\tif git env--helper --type=bool --default=false --exit-code GIT_TEST_HTTPD\n     +\tthen\n      \t\t. \"$TEST_DIRECTORY\"/lib-httpd.sh\n      \t\tLIB_HTTPD_SVN=\"$loc\"\n    @@ -85,7 +85,7 @@\n      require_svnserve () {\n     -\ttest_tristate GIT_TEST_SVNSERVE\n     -\tif ! test \"$GIT_TEST_SVNSERVE\" = true\n    -+\tif ! git env--helper --mode-bool --variable=GIT_TEST_SVNSERVE --default=0 --exit-code --quiet\n    ++\tif ! git env--helper --type=bool --default=false --exit-code GIT_TEST_SVNSERVE\n      \tthen\n      \t\tskip_all='skipping svnserve test. (set $GIT_TEST_SVNSERVE to enable)'\n      \t\ttest_done\n    @@ -99,7 +99,7 @@\n      \n     -test_tristate GIT_TEST_HTTPD\n     -if test \"$GIT_TEST_HTTPD\" = false\n    -+if ! git env--helper --mode-bool --variable=GIT_TEST_HTTPD --default=1 --exit-code --quiet\n    ++if ! git env--helper --type=bool --default=true --exit-code GIT_TEST_HTTPD\n      then\n      \tskip_all=\"Network testing disabled (unset GIT_TEST_HTTPD to enable)\"\n      \ttest_done\n    @@ -162,7 +162,7 @@\n      test_lazy_prereq GIT_DAEMON '\n     -\ttest_tristate GIT_TEST_GIT_DAEMON &&\n     -\ttest \"$GIT_TEST_GIT_DAEMON\" != false\n    -+\tgit env--helper --mode-bool --variable=GIT_TEST_GIT_DAEMON --default=1 --exit-code --quiet\n    ++\tgit env--helper --type=bool --default=true --exit-code GIT_TEST_GIT_DAEMON\n      '\n      \n      # This test spawns a daemon, so run it only if the user would be OK with\n8:  a9aa166b66 ! 8:  d1a32debba tests: make GIT_TEST_FAIL_PREREQS a boolean\n    @@ -90,6 +90,15 @@\n      \tthen\n      \t\tcase \"$1\" in\n      \t\t# The \"!\" case is handled below with\n    +@@\n    + # The error/skip message should be given by $2.\n    + #\n    + test_skip_or_die () {\n    +-\tif ! git env--helper --mode-bool --variable=$1 --default=0 --exit-code --quiet\n    ++\tif ! git env--helper --type=bool --default=false --exit-code $1\n    + \tthen\n    + \t\tskip_all=$2\n    + \t\ttest_done\n     \n      diff --git a/t/test-lib.sh b/t/test-lib.sh\n      --- a/t/test-lib.sh\n    @@ -106,16 +115,14 @@\n     +GIT_TEST_FAIL_PREREQS_INTERNAL=\n     +if test -n \"$GIT_TEST_FAIL_PREREQS\"\n     +then\n    -+\tif git env--helper --mode-bool --variable=GIT_TEST_FAIL_PREREQS \\\n    -+\t\t--default=0 --exit-code --quiet\n    ++\tif git env--helper --type=bool --default=0 --exit-code GIT_TEST_FAIL_PREREQS\n     +\tthen\n     +\t\tGIT_TEST_FAIL_PREREQS_INTERNAL=true\n     +\t\ttest_set_prereq FAIL_PREREQS\n     +\tfi\n     +else\n     +\ttest_lazy_prereq FAIL_PREREQS '\n    -+\t\tgit env--helper --mode-bool --variable=GIT_TEST_FAIL_PREREQS \\\n    -+\t\t\t--default=0 --exit-code --quiet\n    ++\t\tgit env--helper --type=bool --default=0 --exit-code GIT_TEST_FAIL_PREREQS\n     +\t'\n     +fi\n     +\n-- \n2.22.0.455.g172b71a6c5\n\n"},{"id":"377730","messageId":"20190621101812.27300-3-avarab@gmail.com","threadId":"51336","inReplyTo":"20190620210915.11297-1-avarab@gmail.com","subject":"[PATCH v3 2/8] env--helper: new undocumented builtin wrapping git_env_*()","fromName":"Ævar Arnfjörð Bjarmason","fromEmail":"avarab@gmail.com","sentAt":"2019-06-21T10:18:06Z","receivedAt":"2019-06-21T10:18:32Z","isPatch":true,"sender":{"key":"avarab@gmail.com","avatar":"https://avatars.githubusercontent.com/u/45301?v=4"},"body":"We have many GIT_TEST_* variables that accept a <boolean> because\nthey're implemented in C, and then some that take <non-empty?> because\nthey're implemented at least partially in shellscript.\n\nAdd a helper that wraps git_env_bool() and git_env_ulong() as the\nfirst step in fixing this. This isn't being added as a test-tool mode\nbecause some of these are used outside the test suite.\n\nPart of what this tool does can be done via a trick with \"git config\"\nadded in 83d842dc8c (\"tests: turn on network daemon tests by default\",\n2014-02-10) for test_tristate(), i.e.:\n\n    git -c magic.variable=\"$1\" config --bool magic.variable 2>/dev/null\n\nBut as subsequent changes will show being able to pass along the\ndefault value makes all the difference, and we'll be able to replace\ntest_tristate() itself with that.\n\nThe --type=bool option will be used by subsequent patches, but not\n--type=ulong. I figured it was easy enough to add it & test for it so\nI left it in so we'd have wrappers for both git_env_*() functions, and\nto have a template to make it obvious how we'd add --type=int etc. if\nit's needed in the future.\n\nSigned-off-by: Ævar Arnfjörð Bjarmason <avarab@gmail.com>\n---\n .gitignore            |  1 +\n Makefile              |  1 +\n builtin.h             |  1 +\n builtin/env--helper.c | 95 +++++++++++++++++++++++++++++++++++++++++++\n git.c                 |  1 +\n t/t0017-env-helper.sh | 83 +++++++++++++++++++++++++++++++++++++\n 6 files changed, 182 insertions(+)\n create mode 100644 builtin/env--helper.c\n create mode 100755 t/t0017-env-helper.sh\n\ndiff --git a/.gitignore b/.gitignore\nindex 4470d7cfc0..1f7a83fb3c 100644\n--- a/.gitignore\n+++ b/.gitignore\n@@ -58,6 +58,7 @@\n /git-difftool\n /git-difftool--helper\n /git-describe\n+/git-env--helper\n /git-fast-export\n /git-fast-import\n /git-fetch\ndiff --git a/Makefile b/Makefile\nindex f58bf14c7b..f2cfc8d812 100644\n--- a/Makefile\n+++ b/Makefile\n@@ -1059,6 +1059,7 @@ BUILTIN_OBJS += builtin/diff-index.o\n BUILTIN_OBJS += builtin/diff-tree.o\n BUILTIN_OBJS += builtin/diff.o\n BUILTIN_OBJS += builtin/difftool.o\n+BUILTIN_OBJS += builtin/env--helper.o\n BUILTIN_OBJS += builtin/fast-export.o\n BUILTIN_OBJS += builtin/fetch-pack.o\n BUILTIN_OBJS += builtin/fetch.o\ndiff --git a/builtin.h b/builtin.h\nindex ec7e0954c4..93bd49fe4f 100644\n--- a/builtin.h\n+++ b/builtin.h\n@@ -160,6 +160,7 @@ int cmd_diff_index(int argc, const char **argv, const char *prefix);\n int cmd_diff(int argc, const char **argv, const char *prefix);\n int cmd_diff_tree(int argc, const char **argv, const char *prefix);\n int cmd_difftool(int argc, const char **argv, const char *prefix);\n+int cmd_env__helper(int argc, const char **argv, const char *prefix);\n int cmd_fast_export(int argc, const char **argv, const char *prefix);\n int cmd_fetch(int argc, const char **argv, const char *prefix);\n int cmd_fetch_pack(int argc, const char **argv, const char *prefix);\ndiff --git a/builtin/env--helper.c b/builtin/env--helper.c\nnew file mode 100644\nindex 0000000000..1083c0f707\n--- /dev/null\n+++ b/builtin/env--helper.c\n@@ -0,0 +1,95 @@\n+#include \"builtin.h\"\n+#include \"config.h\"\n+#include \"parse-options.h\"\n+\n+static char const * const env__helper_usage[] = {\n+\tN_(\"git env--helper --type=[bool|ulong] <options> <env-var>\"),\n+\tNULL\n+};\n+\n+enum {\n+\tENV_HELPER_TYPE_BOOL = 1,\n+\tENV_HELPER_TYPE_ULONG\n+} cmdmode = 0;\n+\n+static int option_parse_type(const struct option *opt, const char *arg,\n+\t\t\t     int unset)\n+{\n+\tif (!strcmp(arg, \"bool\"))\n+\t\tcmdmode = ENV_HELPER_TYPE_BOOL;\n+\telse if (!strcmp(arg, \"ulong\"))\n+\t\tcmdmode = ENV_HELPER_TYPE_ULONG;\n+\telse\n+\t\tdie(_(\"unrecognized --type argument, %s\"), arg);\n+\n+\treturn 0;\n+}\n+\n+int cmd_env__helper(int argc, const char **argv, const char *prefix)\n+{\n+\tint exit_code = 0;\n+\tconst char *env_variable = NULL;\n+\tconst char *env_default = NULL;\n+\tint ret;\n+\tint ret_int, default_int;\n+\tunsigned long ret_ulong, default_ulong;\n+\tstruct option opts[] = {\n+\t\tOPT_CALLBACK_F(0, \"type\", &cmdmode, N_(\"type\"),\n+\t\t\t       N_(\"value is given this type\"), PARSE_OPT_NONEG,\n+\t\t\t       option_parse_type),\n+\t\tOPT_STRING(0, \"default\", &env_default, N_(\"value\"),\n+\t\t\t   N_(\"default for git_env_*(...) to fall back on\")),\n+\t\tOPT_BOOL(0, \"exit-code\", &exit_code,\n+\t\t\t N_(\"be quiet only use git_env_*() value as exit code\")),\n+\t\tOPT_END(),\n+\t};\n+\n+\targc = parse_options(argc, argv, prefix, opts, env__helper_usage,\n+\t\t\t     PARSE_OPT_KEEP_UNKNOWN);\n+\tif (env_default && !*env_default)\n+\t\tusage_with_options(env__helper_usage, opts);\n+\tif (!cmdmode)\n+\t\tusage_with_options(env__helper_usage, opts);\n+\tif (argc != 1)\n+\t\tusage_with_options(env__helper_usage, opts);\n+\tenv_variable = argv[0];\n+\n+\tswitch (cmdmode) {\n+\tcase ENV_HELPER_TYPE_BOOL:\n+\t\tif (env_default) {\n+\t\t\tdefault_int = git_parse_maybe_bool(env_default);\n+\t\t\tif (default_int == -1) {\n+\t\t\t\terror(_(\"option `--default' expects a boolean value with `--type=bool`, not `%s`\"),\n+\t\t\t\t      env_default);\n+\t\t\t\tusage_with_options(env__helper_usage, opts);\n+\t\t\t}\n+\t\t} else {\n+\t\t\tdefault_int = 0;\n+\t\t}\n+\t\tret_int = git_env_bool(env_variable, default_int);\n+\t\tif (!exit_code)\n+\t\t\tputs(ret_int ? \"true\" : \"false\");\n+\t\tret = ret_int;\n+\t\tbreak;\n+\tcase ENV_HELPER_TYPE_ULONG:\n+\t\tif (env_default) {\n+\t\t\tif (!git_parse_ulong(env_default, &default_ulong)) {\n+\t\t\t\terror(_(\"option `--default' expects an unsigned long value with `--type=ulong`, not `%s`\"),\n+\t\t\t\t      env_default);\n+\t\t\t\tusage_with_options(env__helper_usage, opts);\n+\t\t\t}\n+\t\t} else {\n+\t\t\tdefault_ulong = 0;\n+\t\t}\n+\t\tret_ulong = git_env_ulong(env_variable, default_ulong);\n+\t\tif (!exit_code)\n+\t\t\tprintf(\"%lu\\n\", ret_ulong);\n+\t\tret = ret_ulong;\n+\t\tbreak;\n+\tdefault:\n+\t\tBUG(\"unknown <type> value\");\n+\t\tbreak;\n+\t}\n+\n+\treturn !ret;\n+}\ndiff --git a/git.c b/git.c\nindex c2eec470c9..a43e1dd98e 100644\n--- a/git.c\n+++ b/git.c\n@@ -500,6 +500,7 @@ static struct cmd_struct commands[] = {\n \t{ \"diff-index\", cmd_diff_index, RUN_SETUP | NO_PARSEOPT },\n \t{ \"diff-tree\", cmd_diff_tree, RUN_SETUP | NO_PARSEOPT },\n \t{ \"difftool\", cmd_difftool, RUN_SETUP_GENTLY },\n+\t{ \"env--helper\", cmd_env__helper },\n \t{ \"fast-export\", cmd_fast_export, RUN_SETUP },\n \t{ \"fetch\", cmd_fetch, RUN_SETUP },\n \t{ \"fetch-pack\", cmd_fetch_pack, RUN_SETUP | NO_PARSEOPT },\ndiff --git a/t/t0017-env-helper.sh b/t/t0017-env-helper.sh\nnew file mode 100755\nindex 0000000000..709bbbd275\n--- /dev/null\n+++ b/t/t0017-env-helper.sh\n@@ -0,0 +1,83 @@\n+#!/bin/sh\n+\n+test_description='test env--helper'\n+\n+. ./test-lib.sh\n+\n+\n+test_expect_success 'env--helper usage' '\n+\ttest_must_fail git env--helper &&\n+\ttest_must_fail git env--helper --type=bool &&\n+\ttest_must_fail git env--helper --type=ulong &&\n+\ttest_must_fail git env--helper --type=bool &&\n+\ttest_must_fail git env--helper --type=bool --default &&\n+\ttest_must_fail git env--helper --type=bool --default= &&\n+\ttest_must_fail git env--helper --defaultxyz\n+'\n+\n+test_expect_success 'env--helper bad default values' '\n+\ttest_must_fail git env--helper --type=bool --default=1xyz MISSING &&\n+\ttest_must_fail git env--helper --type=ulong --default=1xyz MISSING\n+'\n+\n+test_expect_success 'env--helper --type=bool' '\n+\t# Test various --default bool values\n+\techo true >expected &&\n+\tgit env--helper --type=bool --default=1 MISSING >actual &&\n+\ttest_cmp expected actual &&\n+\tgit env--helper --type=bool --default=yes MISSING >actual &&\n+\ttest_cmp expected actual &&\n+\tgit env--helper --type=bool --default=true MISSING >actual &&\n+\ttest_cmp expected actual &&\n+\techo false >expected &&\n+\ttest_must_fail git env--helper --type=bool --default=0 MISSING >actual &&\n+\ttest_cmp expected actual &&\n+\ttest_must_fail git env--helper --type=bool --default=no MISSING >actual &&\n+\ttest_cmp expected actual &&\n+\ttest_must_fail git env--helper --type=bool --default=false MISSING >actual &&\n+\ttest_cmp expected actual &&\n+\n+\t# No output with --exit-code\n+\tgit env--helper --type=bool --default=true --exit-code MISSING >actual.out 2>actual.err &&\n+\ttest_must_be_empty actual.out &&\n+\ttest_must_be_empty actual.err &&\n+\ttest_must_fail git env--helper --type=bool --default=false --exit-code MISSING >actual.out 2>actual.err &&\n+\ttest_must_be_empty actual.out &&\n+\ttest_must_be_empty actual.err &&\n+\n+\t# Existing variable\n+\tEXISTS=true git env--helper --type=bool --default=false --exit-code EXISTS >actual.out 2>actual.err &&\n+\ttest_must_be_empty actual.out &&\n+\ttest_must_be_empty actual.err &&\n+\ttest_must_fail \\\n+\t\tenv EXISTS=false \\\n+\t\tgit env--helper --type=bool --default=true --exit-code EXISTS >actual.out 2>actual.err &&\n+\ttest_must_be_empty actual.out &&\n+\ttest_must_be_empty actual.err\n+'\n+\n+test_expect_success 'env--helper --type=ulong' '\n+\techo 1234567890 >expected &&\n+\tgit env--helper --type=ulong --default=1234567890 MISSING >actual.out 2>actual.err &&\n+\ttest_cmp expected actual.out &&\n+\ttest_must_be_empty actual.err &&\n+\n+\techo 0 >expected &&\n+\ttest_must_fail git env--helper --type=ulong --default=0 MISSING >actual &&\n+\ttest_cmp expected actual &&\n+\n+\tgit env--helper --type=ulong --default=1234567890 --exit-code MISSING >actual.out 2>actual.err &&\n+\ttest_must_be_empty actual.out &&\n+\ttest_must_be_empty actual.err &&\n+\n+\tEXISTS=1234567890 git env--helper --type=ulong --default=0 EXISTS --exit-code >actual.out 2>actual.err &&\n+\ttest_must_be_empty actual.out &&\n+\ttest_must_be_empty actual.err &&\n+\n+\techo 1234567890 >expected &&\n+\tEXISTS=1234567890 git env--helper --type=ulong --default=0 EXISTS >actual.out 2>actual.err &&\n+\ttest_cmp expected actual.out &&\n+\ttest_must_be_empty actual.err\n+'\n+\n+test_done\n-- \n2.22.0.455.g172b71a6c5\n\n"},{"id":"377731","messageId":"20190621101812.27300-4-avarab@gmail.com","threadId":"51336","inReplyTo":"20190620210915.11297-1-avarab@gmail.com","subject":"[PATCH v3 3/8] config.c: refactor die_bad_number() to not call gettext() early","fromName":"Ævar Arnfjörð Bjarmason","fromEmail":"avarab@gmail.com","sentAt":"2019-06-21T10:18:07Z","receivedAt":"2019-06-21T10:18:32Z","isPatch":true,"sender":{"key":"avarab@gmail.com","avatar":"https://avatars.githubusercontent.com/u/45301?v=4"},"body":"Prepare die_bad_number() for a change to specially handle\nGIT_TEST_GETTEXT_POISON calling git_env_bool() by making\ndie_bad_number() not call gettext() early, which would in turn call\ngit_env_bool().\n\nThere's no meaningful change here yet, just a re-arrangement of the\ncurrent code to make that subsequent change easier to read.\n\nSigned-off-by: Ævar Arnfjörð Bjarmason <avarab@gmail.com>\n---\n config.c | 19 ++++++++++---------\n 1 file changed, 10 insertions(+), 9 deletions(-)\n\ndiff --git a/config.c b/config.c\nindex 296a6d9cc4..374cb33005 100644\n--- a/config.c\n+++ b/config.c\n@@ -949,34 +949,35 @@ int git_parse_ssize_t(const char *value, ssize_t *ret)\n NORETURN\n static void die_bad_number(const char *name, const char *value)\n {\n-\tconst char * error_type = (errno == ERANGE)? _(\"out of range\"):_(\"invalid unit\");\n+\tconst char *error_type = (errno == ERANGE) ?\n+\t\tN_(\"out of range\") : N_(\"invalid unit\");\n+\tconst char *bad_numeric = N_(\"bad numeric config value '%s' for '%s': %s\");\n \n \tif (!value)\n \t\tvalue = \"\";\n \n \tif (!(cf && cf->name))\n-\t\tdie(_(\"bad numeric config value '%s' for '%s': %s\"),\n-\t\t    value, name, error_type);\n+\t\tdie(_(bad_numeric), value, name, _(error_type));\n \n \tswitch (cf->origin_type) {\n \tcase CONFIG_ORIGIN_BLOB:\n \t\tdie(_(\"bad numeric config value '%s' for '%s' in blob %s: %s\"),\n-\t\t    value, name, cf->name, error_type);\n+\t\t    value, name, cf->name, _(error_type));\n \tcase CONFIG_ORIGIN_FILE:\n \t\tdie(_(\"bad numeric config value '%s' for '%s' in file %s: %s\"),\n-\t\t    value, name, cf->name, error_type);\n+\t\t    value, name, cf->name, _(error_type));\n \tcase CONFIG_ORIGIN_STDIN:\n \t\tdie(_(\"bad numeric config value '%s' for '%s' in standard input: %s\"),\n-\t\t    value, name, error_type);\n+\t\t    value, name, _(error_type));\n \tcase CONFIG_ORIGIN_SUBMODULE_BLOB:\n \t\tdie(_(\"bad numeric config value '%s' for '%s' in submodule-blob %s: %s\"),\n-\t\t    value, name, cf->name, error_type);\n+\t\t    value, name, cf->name, _(error_type));\n \tcase CONFIG_ORIGIN_CMDLINE:\n \t\tdie(_(\"bad numeric config value '%s' for '%s' in command line %s: %s\"),\n-\t\t    value, name, cf->name, error_type);\n+\t\t    value, name, cf->name, _(error_type));\n \tdefault:\n \t\tdie(_(\"bad numeric config value '%s' for '%s' in %s: %s\"),\n-\t\t    value, name, cf->name, error_type);\n+\t\t    value, name, cf->name, _(error_type));\n \t}\n }\n \n-- \n2.22.0.455.g172b71a6c5\n\n"},{"id":"377732","messageId":"20190621101812.27300-5-avarab@gmail.com","threadId":"51336","inReplyTo":"20190620210915.11297-1-avarab@gmail.com","subject":"[PATCH v3 4/8] t6040 test: stop using global \"script\" variable","fromName":"Ævar Arnfjörð Bjarmason","fromEmail":"avarab@gmail.com","sentAt":"2019-06-21T10:18:08Z","receivedAt":"2019-06-21T10:18:34Z","isPatch":true,"sender":{"key":"avarab@gmail.com","avatar":"https://avatars.githubusercontent.com/u/45301?v=4"},"body":"Change test code added in c0234b2ef6 (\"stat_tracking_info(): clear\nobject flags used during counting\", 2008-07-03) to stop using the\n\"script\" variable also used for lazy prerequisites in\ntest-lib-functions.sh.\n\nSince this test uses test_i18ncmp and expects to use its own \"script\"\nvariable twice it implicitly depends on the C_LOCALE_OUTPUT\nprerequisite not being a lazy prerequisite. A follow-up change will\nmake it a lazy prerequisite, so we must remove this landmine before\ninadvertently stepping on it as we make that change.\n\nSigned-off-by: Ævar Arnfjörð Bjarmason <avarab@gmail.com>\n---\n t/t6040-tracking-info.sh | 6 +++---\n 1 file changed, 3 insertions(+), 3 deletions(-)\n\ndiff --git a/t/t6040-tracking-info.sh b/t/t6040-tracking-info.sh\nindex 716283b274..970b25a289 100755\n--- a/t/t6040-tracking-info.sh\n+++ b/t/t6040-tracking-info.sh\n@@ -38,7 +38,7 @@ test_expect_success setup '\n \tadvance h\n '\n \n-script='s/^..\\(b.\\) *[0-9a-f]* \\(.*\\)$/\\1 \\2/p'\n+t6040_script='s/^..\\(b.\\) *[0-9a-f]* \\(.*\\)$/\\1 \\2/p'\n cat >expect <<\\EOF\n b1 [ahead 1, behind 1] d\n b2 [ahead 1, behind 1] d\n@@ -53,7 +53,7 @@ test_expect_success 'branch -v' '\n \t\tcd test &&\n \t\tgit branch -v\n \t) |\n-\tsed -n -e \"$script\" >actual &&\n+\tsed -n -e \"$t6040_script\" >actual &&\n \ttest_i18ncmp expect actual\n '\n \n@@ -71,7 +71,7 @@ test_expect_success 'branch -vv' '\n \t\tcd test &&\n \t\tgit branch -vv\n \t) |\n-\tsed -n -e \"$script\" >actual &&\n+\tsed -n -e \"$t6040_script\" >actual &&\n \ttest_i18ncmp expect actual\n '\n \n-- \n2.22.0.455.g172b71a6c5\n\n"},{"id":"377733","messageId":"20190621101812.27300-7-avarab@gmail.com","threadId":"51336","inReplyTo":"20190620210915.11297-1-avarab@gmail.com","subject":"[PATCH v3 6/8] tests README: re-flow a previously changed paragraph","fromName":"Ævar Arnfjörð Bjarmason","fromEmail":"avarab@gmail.com","sentAt":"2019-06-21T10:18:10Z","receivedAt":"2019-06-21T10:18:36Z","isPatch":true,"sender":{"key":"avarab@gmail.com","avatar":"https://avatars.githubusercontent.com/u/45301?v=4"},"body":"A previous change to the \"GIT_TEST_GETTEXT_POISON\" variable left this\nparagraph needing to be re-flowed. Let's do that in this separate\nchange to make it easy to see that there's no change here when viewed\nwith \"--word-diff\".\n\nSigned-off-by: Ævar Arnfjörð Bjarmason <avarab@gmail.com>\n---\n t/README | 8 ++++----\n 1 file changed, 4 insertions(+), 4 deletions(-)\n\ndiff --git a/t/README b/t/README\nindex 9a131f472e..072c9854d1 100644\n--- a/t/README\n+++ b/t/README\n@@ -344,10 +344,10 @@ refactor to deal with it. The \"SYMLINKS\" prerequisite is currently\n excluded as so much relies on it, but this might change in the future.\n \n GIT_TEST_GETTEXT_POISON=<boolean> turns all strings marked for\n-translation into gibberish if true. Used for\n-spotting those tests that need to be marked with a C_LOCALE_OUTPUT\n-prerequisite when adding more strings for translation. See \"Testing\n-marked strings\" in po/README for details.\n+translation into gibberish if true. Used for spotting those tests that\n+need to be marked with a C_LOCALE_OUTPUT prerequisite when adding more\n+strings for translation. See \"Testing marked strings\" in po/README for\n+details.\n \n GIT_TEST_SPLIT_INDEX=<boolean> forces split-index mode on the whole\n test suite. Accept any boolean values that are accepted by git-config.\n-- \n2.22.0.455.g172b71a6c5\n\n"},{"id":"377734","messageId":"20190621101812.27300-6-avarab@gmail.com","threadId":"51336","inReplyTo":"20190620210915.11297-1-avarab@gmail.com","subject":"[PATCH v3 5/8] tests: make GIT_TEST_GETTEXT_POISON a boolean","fromName":"Ævar Arnfjörð Bjarmason","fromEmail":"avarab@gmail.com","sentAt":"2019-06-21T10:18:09Z","receivedAt":"2019-06-21T10:18:37Z","isPatch":true,"sender":{"key":"avarab@gmail.com","avatar":"https://avatars.githubusercontent.com/u/45301?v=4"},"body":"Change the GIT_TEST_GETTEXT_POISON variable from being \"non-empty?\" to\nbeing a more standard boolean variable.\n\nSince it needed to be checked in both C code and shellscript (via test\n-n) it was one of the remaining shellscript-like variables. Now that\nwe have \"env--helper\" we can change that.\n\nThere's a couple of tricky edge cases that arise because we're using\ngit_env_bool() early, and the config-reading \"env--helper\".\n\nIf GIT_TEST_GETTEXT_POISON is set to an invalid value die_bad_number()\nwill die, but to do so it would usually call gettext(). Let's detect\nthe special case of GIT_TEST_GETTEXT_POISON and always emit that\nmessage in the C locale, lest we infinitely loop.\n\nAs seen in the updated tests in t0017-env-helper.sh there's also a\ncaveat related to \"env--helper\" needing to read the config for trace2\npurposes.\n\nSince the C_LOCALE_OUTPUT prerequisite is lazy and relies on\n\"env--helper\" we could get invalid results if we failed to read the\nconfig (e.g. because we'd loop on includes) when combined with\ne.g. \"test_i18ngrep\" wanting to check with \"env--helper\" if\nGIT_TEST_GETTEXT_POISON was true or not.\n\nI'm crossing my fingers and hoping that a test similar to the one I\nremoved in the earlier \"config tests: simplify include cycle test\"\nchange in this series won't happen again, and testing for this\nexplicitly in \"env--helper\"'s own tests.\n\nThis change breaks existing uses of\ne.g. GIT_TEST_GETTEXT_POISON=YesPlease, which we've documented in\npo/README and other places. As noted in [1] we might want to consider\nalso accepting \"YesPlease\" in \"env--helper\" as a special-case.\n\nBut as the lack of uproar over 6cdccfce1e (\"i18n: make GETTEXT_POISON\na runtime option\", 2018-11-08) demonstrates the audience for this\noption is a really narrow set of git developers, who shouldn't have\nmuch trouble modifying their test scripts, so I think it's better to\ndeal with that minor headache now and make all the relevant GIT_TEST_*\nvariables boolean in the same way than carry the \"YesPlease\"\nspecial-case forward.\n\n1. https://public-inbox.org/git/xmqqtvckm3h8.fsf@gitster-ct.c.googlers.com/\n\nSigned-off-by: Ævar Arnfjörð Bjarmason <avarab@gmail.com>\n---\n ci/lib.sh                 |  2 +-\n config.c                  |  9 +++++++++\n gettext.c                 |  6 ++----\n git-sh-i18n.sh            |  4 +++-\n po/README                 |  2 +-\n t/README                  |  4 ++--\n t/t0017-env-helper.sh     | 16 ++++++++++++++++\n t/t0205-gettext-poison.sh |  7 ++++++-\n t/t1305-config-include.sh |  2 +-\n t/t7201-co.sh             |  2 +-\n t/t9902-completion.sh     |  2 +-\n t/test-lib.sh             |  8 +++-----\n 12 files changed, 46 insertions(+), 18 deletions(-)\n\ndiff --git a/ci/lib.sh b/ci/lib.sh\nindex 288a5b3884..fd799ae663 100755\n--- a/ci/lib.sh\n+++ b/ci/lib.sh\n@@ -184,7 +184,7 @@ osx-clang|osx-gcc)\n \texport GIT_SKIP_TESTS=\"t9810 t9816\"\n \t;;\n GIT_TEST_GETTEXT_POISON)\n-\texport GIT_TEST_GETTEXT_POISON=YesPlease\n+\texport GIT_TEST_GETTEXT_POISON=true\n \t;;\n esac\n \ndiff --git a/config.c b/config.c\nindex 374cb33005..b985d60fa4 100644\n--- a/config.c\n+++ b/config.c\n@@ -956,6 +956,15 @@ static void die_bad_number(const char *name, const char *value)\n \tif (!value)\n \t\tvalue = \"\";\n \n+\tif (!strcmp(name, \"GIT_TEST_GETTEXT_POISON\"))\n+\t\t/*\n+\t\t * We explicitly *don't* use _() here since it would\n+\t\t * cause an infinite loop with _() needing to call\n+\t\t * use_gettext_poison(). This is why marked up\n+\t\t * translations with N_() above.\n+\t\t */\n+\t\tdie(bad_numeric, value, name, error_type);\n+\n \tif (!(cf && cf->name))\n \t\tdie(_(bad_numeric), value, name, _(error_type));\n \ndiff --git a/gettext.c b/gettext.c\nindex d4021d690c..5c71f4c8b9 100644\n--- a/gettext.c\n+++ b/gettext.c\n@@ -50,10 +50,8 @@ const char *get_preferred_languages(void)\n int use_gettext_poison(void)\n {\n \tstatic int poison_requested = -1;\n-\tif (poison_requested == -1) {\n-\t\tconst char *v = getenv(\"GIT_TEST_GETTEXT_POISON\");\n-\t\tpoison_requested = v && strlen(v) ? 1 : 0;\n-\t}\n+\tif (poison_requested == -1)\n+\t\tpoison_requested = git_env_bool(\"GIT_TEST_GETTEXT_POISON\", 0);\n \treturn poison_requested;\n }\n \ndiff --git a/git-sh-i18n.sh b/git-sh-i18n.sh\nindex e1d917fd27..8eef60b43f 100644\n--- a/git-sh-i18n.sh\n+++ b/git-sh-i18n.sh\n@@ -17,7 +17,9 @@ export TEXTDOMAINDIR\n \n # First decide what scheme to use...\n GIT_INTERNAL_GETTEXT_SH_SCHEME=fallthrough\n-if test -n \"$GIT_TEST_GETTEXT_POISON\"\n+if test -n \"$GIT_TEST_GETTEXT_POISON\" &&\n+\t    git env--helper --type=bool --default=0 --exit-code \\\n+\t\tGIT_TEST_GETTEXT_POISON\n then\n \tGIT_INTERNAL_GETTEXT_SH_SCHEME=poison\n elif test -n \"@@USE_GETTEXT_SCHEME@@\"\ndiff --git a/po/README b/po/README\nindex aa704ffcb7..07595d369b 100644\n--- a/po/README\n+++ b/po/README\n@@ -293,7 +293,7 @@ To smoke out issues like these, Git tested with a translation mode that\n emits gibberish on every call to gettext. To use it run the test suite\n with it, e.g.:\n \n-    cd t && GIT_TEST_GETTEXT_POISON=YesPlease prove -j 9 ./t[0-9]*.sh\n+    cd t && GIT_TEST_GETTEXT_POISON=true prove -j 9 ./t[0-9]*.sh\n \n If tests break with it you should inspect them manually and see if\n what you're translating is sane, i.e. that you're not translating\ndiff --git a/t/README b/t/README\nindex 9747971d58..9a131f472e 100644\n--- a/t/README\n+++ b/t/README\n@@ -343,8 +343,8 @@ whether this mode is active, and e.g. skip some tests that are hard to\n refactor to deal with it. The \"SYMLINKS\" prerequisite is currently\n excluded as so much relies on it, but this might change in the future.\n \n-GIT_TEST_GETTEXT_POISON=<non-empty?> turns all strings marked for\n-translation into gibberish if non-empty (think \"test -n\"). Used for\n+GIT_TEST_GETTEXT_POISON=<boolean> turns all strings marked for\n+translation into gibberish if true. Used for\n spotting those tests that need to be marked with a C_LOCALE_OUTPUT\n prerequisite when adding more strings for translation. See \"Testing\n marked strings\" in po/README for details.\ndiff --git a/t/t0017-env-helper.sh b/t/t0017-env-helper.sh\nindex 709bbbd275..c1ecf6aeac 100755\n--- a/t/t0017-env-helper.sh\n+++ b/t/t0017-env-helper.sh\n@@ -80,4 +80,20 @@ test_expect_success 'env--helper --type=ulong' '\n \ttest_must_be_empty actual.err\n '\n \n+test_expect_success 'env--helper reads config thanks to trace2' '\n+\tmkdir home &&\n+\tgit config -f home/.gitconfig include.path cycle &&\n+\tgit config -f home/cycle include.path .gitconfig &&\n+\n+\ttest_must_fail \\\n+\t\tenv HOME=\"$(pwd)/home\" GIT_TEST_GETTEXT_POISON=false \\\n+\t\tgit config -l 2>err &&\n+\tgrep \"exceeded maximum include depth\" err &&\n+\n+\ttest_must_fail \\\n+\t\tenv HOME=\"$(pwd)/home\" GIT_TEST_GETTEXT_POISON=true \\\n+\t\tgit -C cycle env--helper --type=bool --default=0 --exit-code GIT_TEST_GETTEXT_POISON 2>err &&\n+\tgrep \"# GETTEXT POISON #\" err\n+'\n+\n test_done\ndiff --git a/t/t0205-gettext-poison.sh b/t/t0205-gettext-poison.sh\nindex a06269f38a..f9fa16ad83 100755\n--- a/t/t0205-gettext-poison.sh\n+++ b/t/t0205-gettext-poison.sh\n@@ -5,7 +5,7 @@\n \n test_description='Gettext Shell poison'\n \n-GIT_TEST_GETTEXT_POISON=YesPlease\n+GIT_TEST_GETTEXT_POISON=true\n export GIT_TEST_GETTEXT_POISON\n . ./lib-gettext.sh\n \n@@ -31,4 +31,9 @@ test_expect_success 'eval_gettext: our eval_gettext() fallback has poison semant\n     test_cmp expect actual\n '\n \n+test_expect_success \"gettext: invalid GIT_TEST_GETTEXT_POISON value doesn't infinitely loop\" \"\n+\ttest_must_fail env GIT_TEST_GETTEXT_POISON=xyz git version 2>error &&\n+\tgrep \\\"fatal: bad numeric config value 'xyz' for 'GIT_TEST_GETTEXT_POISON': invalid unit\\\" error\n+\"\n+\n test_done\ndiff --git a/t/t1305-config-include.sh b/t/t1305-config-include.sh\nindex 6b388ba2d0..de294c990e 100755\n--- a/t/t1305-config-include.sh\n+++ b/t/t1305-config-include.sh\n@@ -314,7 +314,7 @@ test_expect_success 'include cycles are detected' '\n \tgit -C cycle config include.path cycle &&\n \tgit config -f cycle/cycle include.path config &&\n \ttest_must_fail \\\n-\t\tenv GIT_TEST_GETTEXT_POISON= \\\n+\t\tenv GIT_TEST_GETTEXT_POISON=false \\\n \t\tgit -C cycle config --get-all test.value 2>stderr &&\n \tgrep \"exceeded maximum include depth\" stderr\n '\ndiff --git a/t/t7201-co.sh b/t/t7201-co.sh\nindex 5990299fc9..b696bae5f5 100755\n--- a/t/t7201-co.sh\n+++ b/t/t7201-co.sh\n@@ -249,7 +249,7 @@ test_expect_success 'checkout to detach HEAD (with advice declined)' '\n test_expect_success 'checkout to detach HEAD' '\n \tgit config advice.detachedHead true &&\n \tgit checkout -f renamer && git clean -f &&\n-\tGIT_TEST_GETTEXT_POISON= git checkout renamer^ 2>messages &&\n+\tGIT_TEST_GETTEXT_POISON=false git checkout renamer^ 2>messages &&\n \tgrep \"HEAD is now at 7329388\" messages &&\n \ttest_line_count -gt 1 messages &&\n \tH=$(git rev-parse --verify HEAD) &&\ndiff --git a/t/t9902-completion.sh b/t/t9902-completion.sh\nindex 43cf313a1c..75512c3403 100755\n--- a/t/t9902-completion.sh\n+++ b/t/t9902-completion.sh\n@@ -1706,7 +1706,7 @@ test_expect_success 'sourcing the completion script clears cached commands' '\n '\n \n test_expect_success 'sourcing the completion script clears cached merge strategies' '\n-\tGIT_TEST_GETTEXT_POISON= &&\n+\tGIT_TEST_GETTEXT_POISON=false &&\n \t__git_compute_merge_strategies &&\n \tverbose test -n \"$__git_merge_strategies\" &&\n \t. \"$GIT_BUILD_DIR/contrib/completion/git-completion.bash\" &&\ndiff --git a/t/test-lib.sh b/t/test-lib.sh\nindex 4b346467df..ed5d69dfe5 100644\n--- a/t/test-lib.sh\n+++ b/t/test-lib.sh\n@@ -1443,11 +1443,9 @@ then\n \tunset GIT_TEST_GETTEXT_POISON_ORIG\n fi\n \n-# Can we rely on git's output in the C locale?\n-if test -z \"$GIT_TEST_GETTEXT_POISON\"\n-then\n-\ttest_set_prereq C_LOCALE_OUTPUT\n-fi\n+test_lazy_prereq C_LOCALE_OUTPUT '\n+\t! git env--helper --type=bool --default=0 --exit-code GIT_TEST_GETTEXT_POISON\n+'\n \n if test -z \"$GIT_TEST_CHECK_CACHE_TREE\"\n then\n-- \n2.22.0.455.g172b71a6c5\n\n"},{"id":"377735","messageId":"20190621101812.27300-8-avarab@gmail.com","threadId":"51336","inReplyTo":"20190620210915.11297-1-avarab@gmail.com","subject":"[PATCH v3 7/8] tests: replace test_tristate with \"git env--helper\"","fromName":"Ævar Arnfjörð Bjarmason","fromEmail":"avarab@gmail.com","sentAt":"2019-06-21T10:18:11Z","receivedAt":"2019-06-21T10:18:38Z","isPatch":true,"sender":{"key":"avarab@gmail.com","avatar":"https://avatars.githubusercontent.com/u/45301?v=4"},"body":"The test_tristate helper introduced in 83d842dc8c (\"tests: turn on\nnetwork daemon tests by default\", 2014-02-10) can now be better\nimplemented with \"git env--helper\" to give the variables in question\nthe standard boolean behavior.\n\nThe reason for the \"tristate\" was to have all of false/true/auto,\nwhere \"auto\" meant either \"false\" or \"true\" depending on what the\nfallback was. With the --default option to \"git env--helper\" we can\nsimply have e.g. GIT_TEST_HTTPD where we know if it's true because the\nuser asked explicitly (\"true\"), or true implicitly (\"auto\").\n\nThis breaks backwards compatibility for explicitly setting \"auto\" for\nthese variables, but I don't think anyone cares. That was always\nintended to be internal.\n\nThis means the test_normalize_bool() code in test-lib-functions.sh\ngoes away in addition to test_tristate(). We still need the\ntest_skip_or_die() helper, but now it takes the variable name instead\nof the value, and uses \"git env--bool\" to distinguish a default \"true\"\nfrom an explicit \"true\" (in those \"explicit true\" cases we want to\nfail the test in question).\n\nSigned-off-by: Ævar Arnfjörð Bjarmason <avarab@gmail.com>\n---\n t/lib-git-daemon.sh     |  7 +++---\n t/lib-git-svn.sh        | 11 +++-----\n t/lib-httpd.sh          | 15 ++++++-----\n t/t5512-ls-remote.sh    |  3 +--\n t/test-lib-functions.sh | 56 ++++++-----------------------------------\n 5 files changed, 22 insertions(+), 70 deletions(-)\n\ndiff --git a/t/lib-git-daemon.sh b/t/lib-git-daemon.sh\nindex 7b3407134e..fb8f887080 100644\n--- a/t/lib-git-daemon.sh\n+++ b/t/lib-git-daemon.sh\n@@ -15,8 +15,7 @@\n #\n #\ttest_done\n \n-test_tristate GIT_TEST_GIT_DAEMON\n-if test \"$GIT_TEST_GIT_DAEMON\" = false\n+if ! git env--helper --type=bool --default=true --exit-code GIT_TEST_GIT_DAEMON\n then\n \tskip_all=\"git-daemon testing disabled (unset GIT_TEST_GIT_DAEMON to enable)\"\n \ttest_done\n@@ -24,7 +23,7 @@ fi\n \n if test_have_prereq !PIPE\n then\n-\ttest_skip_or_die $GIT_TEST_GIT_DAEMON \"file system does not support FIFOs\"\n+\ttest_skip_or_die GIT_TEST_GIT_DAEMON \"file system does not support FIFOs\"\n fi\n \n test_set_port LIB_GIT_DAEMON_PORT\n@@ -73,7 +72,7 @@ start_git_daemon() {\n \t\tkill \"$GIT_DAEMON_PID\"\n \t\twait \"$GIT_DAEMON_PID\"\n \t\tunset GIT_DAEMON_PID\n-\t\ttest_skip_or_die $GIT_TEST_GIT_DAEMON \\\n+\t\ttest_skip_or_die GIT_TEST_GIT_DAEMON \\\n \t\t\t\"git daemon failed to start\"\n \tfi\n }\ndiff --git a/t/lib-git-svn.sh b/t/lib-git-svn.sh\nindex c1271d6863..5d4ae629e1 100644\n--- a/t/lib-git-svn.sh\n+++ b/t/lib-git-svn.sh\n@@ -69,14 +69,12 @@ svn_cmd () {\n maybe_start_httpd () {\n \tloc=${1-svn}\n \n-\ttest_tristate GIT_SVN_TEST_HTTPD\n-\tcase $GIT_SVN_TEST_HTTPD in\n-\ttrue)\n+\tif git env--helper --type=bool --default=false --exit-code GIT_TEST_HTTPD\n+\tthen\n \t\t. \"$TEST_DIRECTORY\"/lib-httpd.sh\n \t\tLIB_HTTPD_SVN=\"$loc\"\n \t\tstart_httpd\n-\t\t;;\n-\tesac\n+\tfi\n }\n \n convert_to_rev_db () {\n@@ -106,8 +104,7 @@ EOF\n }\n \n require_svnserve () {\n-\ttest_tristate GIT_TEST_SVNSERVE\n-\tif ! test \"$GIT_TEST_SVNSERVE\" = true\n+\tif ! git env--helper --type=bool --default=false --exit-code GIT_TEST_SVNSERVE\n \tthen\n \t\tskip_all='skipping svnserve test. (set $GIT_TEST_SVNSERVE to enable)'\n \t\ttest_done\ndiff --git a/t/lib-httpd.sh b/t/lib-httpd.sh\nindex b3cc62bd36..0d985758c6 100644\n--- a/t/lib-httpd.sh\n+++ b/t/lib-httpd.sh\n@@ -41,15 +41,14 @@ then\n \ttest_done\n fi\n \n-test_tristate GIT_TEST_HTTPD\n-if test \"$GIT_TEST_HTTPD\" = false\n+if ! git env--helper --type=bool --default=true --exit-code GIT_TEST_HTTPD\n then\n \tskip_all=\"Network testing disabled (unset GIT_TEST_HTTPD to enable)\"\n \ttest_done\n fi\n \n if ! test_have_prereq NOT_ROOT; then\n-\ttest_skip_or_die $GIT_TEST_HTTPD \\\n+\ttest_skip_or_die GIT_TEST_HTTPD \\\n \t\t\"Cannot run httpd tests as root\"\n fi\n \n@@ -95,7 +94,7 @@ GIT_TRACE=$GIT_TRACE; export GIT_TRACE\n \n if ! test -x \"$LIB_HTTPD_PATH\"\n then\n-\ttest_skip_or_die $GIT_TEST_HTTPD \"no web server found at '$LIB_HTTPD_PATH'\"\n+\ttest_skip_or_die GIT_TEST_HTTPD \"no web server found at '$LIB_HTTPD_PATH'\"\n fi\n \n HTTPD_VERSION=$($LIB_HTTPD_PATH -v | \\\n@@ -107,19 +106,19 @@ then\n \tthen\n \t\tif ! test $HTTPD_VERSION -ge 2\n \t\tthen\n-\t\t\ttest_skip_or_die $GIT_TEST_HTTPD \\\n+\t\t\ttest_skip_or_die GIT_TEST_HTTPD \\\n \t\t\t\t\"at least Apache version 2 is required\"\n \t\tfi\n \t\tif ! test -d \"$DEFAULT_HTTPD_MODULE_PATH\"\n \t\tthen\n-\t\t\ttest_skip_or_die $GIT_TEST_HTTPD \\\n+\t\t\ttest_skip_or_die GIT_TEST_HTTPD \\\n \t\t\t\t\"Apache module directory not found\"\n \t\tfi\n \n \t\tLIB_HTTPD_MODULE_PATH=\"$DEFAULT_HTTPD_MODULE_PATH\"\n \tfi\n else\n-\ttest_skip_or_die $GIT_TEST_HTTPD \\\n+\ttest_skip_or_die GIT_TEST_HTTPD \\\n \t\t\"Could not identify web server at '$LIB_HTTPD_PATH'\"\n fi\n \n@@ -184,7 +183,7 @@ start_httpd() {\n \tif test $? -ne 0\n \tthen\n \t\tcat \"$HTTPD_ROOT_PATH\"/error.log >&4 2>/dev/null\n-\t\ttest_skip_or_die $GIT_TEST_HTTPD \"web server setup failed\"\n+\t\ttest_skip_or_die GIT_TEST_HTTPD \"web server setup failed\"\n \tfi\n }\n \ndiff --git a/t/t5512-ls-remote.sh b/t/t5512-ls-remote.sh\nindex e3c4a48c85..43e1d8d4d2 100755\n--- a/t/t5512-ls-remote.sh\n+++ b/t/t5512-ls-remote.sh\n@@ -267,8 +267,7 @@ test_expect_success 'ls-remote --symref omits filtered-out matches' '\n '\n \n test_lazy_prereq GIT_DAEMON '\n-\ttest_tristate GIT_TEST_GIT_DAEMON &&\n-\ttest \"$GIT_TEST_GIT_DAEMON\" != false\n+\tgit env--helper --type=bool --default=true --exit-code GIT_TEST_GIT_DAEMON\n '\n \n # This test spawns a daemon, so run it only if the user would be OK with\ndiff --git a/t/test-lib-functions.sh b/t/test-lib-functions.sh\nindex 0367cec5fd..527508c350 100644\n--- a/t/test-lib-functions.sh\n+++ b/t/test-lib-functions.sh\n@@ -1035,62 +1035,20 @@ perl () {\n \tcommand \"$PERL_PATH\" \"$@\" 2>&7\n } 7>&2 2>&4\n \n-# Is the value one of the various ways to spell a boolean true/false?\n-test_normalize_bool () {\n-\tgit -c magic.variable=\"$1\" config --bool magic.variable 2>/dev/null\n-}\n-\n-# Given a variable $1, normalize the value of it to one of \"true\",\n-# \"false\", or \"auto\" and store the result to it.\n-#\n-#     test_tristate GIT_TEST_HTTPD\n-#\n-# A variable set to an empty string is set to 'false'.\n-# A variable set to 'false' or 'auto' keeps its value.\n-# Anything else is set to 'true'.\n-# An unset variable defaults to 'auto'.\n-#\n-# The last rule is to allow people to set the variable to an empty\n-# string and export it to decline testing the particular feature\n-# for versions both before and after this change.  We used to treat\n-# both unset and empty variable as a signal for \"do not test\" and\n-# took any non-empty string as \"please test\".\n-\n-test_tristate () {\n-\tif eval \"test x\\\"\\${$1+isset}\\\" = xisset\"\n-\tthen\n-\t\t# explicitly set\n-\t\teval \"\n-\t\t\tcase \\\"\\$$1\\\" in\n-\t\t\t'')\t$1=false ;;\n-\t\t\tauto)\t;;\n-\t\t\t*)\t$1=\\$(test_normalize_bool \\$$1 || echo true) ;;\n-\t\t\tesac\n-\t\t\"\n-\telse\n-\t\teval \"$1=auto\"\n-\tfi\n-}\n-\n # Exit the test suite, either by skipping all remaining tests or by\n-# exiting with an error. If \"$1\" is \"auto\", we then we assume we were\n-# opportunistically trying to set up some tests and we skip. If it is\n-# \"true\", then we report a failure.\n+# exiting with an error. If our prerequisite variable $1 falls back\n+# on a default assume we were opportunistically trying to set up some\n+# tests and we skip. If it is explicitly \"true\", then we report a failure.\n #\n # The error/skip message should be given by $2.\n #\n test_skip_or_die () {\n-\tcase \"$1\" in\n-\tauto)\n+\tif ! git env--helper --mode-bool --variable=$1 --default=0 --exit-code --quiet\n+\tthen\n \t\tskip_all=$2\n \t\ttest_done\n-\t\t;;\n-\ttrue)\n-\t\terror \"$2\"\n-\t\t;;\n-\t*)\n-\t\terror \"BUG: test tristate is '$1' (real error: $2)\"\n-\tesac\n+\tfi\n+\terror \"$2\"\n }\n \n # The following mingw_* functions obey POSIX shell syntax, but are actually\n-- \n2.22.0.455.g172b71a6c5\n\n"},{"id":"377736","messageId":"20190621101812.27300-9-avarab@gmail.com","threadId":"51336","inReplyTo":"20190620210915.11297-1-avarab@gmail.com","subject":"[PATCH v3 8/8] tests: make GIT_TEST_FAIL_PREREQS a boolean","fromName":"Ævar Arnfjörð Bjarmason","fromEmail":"avarab@gmail.com","sentAt":"2019-06-21T10:18:12Z","receivedAt":"2019-06-21T10:18:40Z","isPatch":true,"sender":{"key":"avarab@gmail.com","avatar":"https://avatars.githubusercontent.com/u/45301?v=4"},"body":"Change the GIT_TEST_FAIL_PREREQS variable from being \"non-empty?\" to\nbeing a more standard boolean variable. I recently added the variable\nin dfe1a17df9 (\"tests: add a special setup where prerequisites fail\",\n2019-05-13), having to add another \"non-empty?\" special-case is what\nprompted me to write the \"git env--helper\" utility being used here.\n\nConverting this one is a bit tricky since we use it so early and\nfrequently in the guts of the test code itself, so let's set a\nGIT_TEST_FAIL_PREREQS_INTERNAL which can be tested with the old \"test\n-n\" for the purposes of the shell code, and change the user-exposed\nand documented GIT_TEST_FAIL_PREREQS variable to a boolean.\n\nSigned-off-by: Ævar Arnfjörð Bjarmason <avarab@gmail.com>\n---\n t/README                |  2 +-\n t/t0000-basic.sh        | 10 +++++-----\n t/test-lib-functions.sh |  4 ++--\n t/test-lib.sh           | 23 +++++++++++++++++++----\n 4 files changed, 27 insertions(+), 12 deletions(-)\n\ndiff --git a/t/README b/t/README\nindex 072c9854d1..60d5b77bcc 100644\n--- a/t/README\n+++ b/t/README\n@@ -334,7 +334,7 @@ that cannot be easily covered by a few specific test cases. These\n could be enabled by running the test suite with correct GIT_TEST_\n environment set.\n \n-GIT_TEST_FAIL_PREREQS<non-empty?> fails all prerequisites. This is\n+GIT_TEST_FAIL_PREREQS=<boolean> fails all prerequisites. This is\n useful for discovering issues with the tests where say a later test\n implicitly depends on an optional earlier test.\n \ndiff --git a/t/t0000-basic.sh b/t/t0000-basic.sh\nindex 31de7e90f3..e89438e619 100755\n--- a/t/t0000-basic.sh\n+++ b/t/t0000-basic.sh\n@@ -726,7 +726,7 @@ donthaveit=yes\n test_expect_success DONTHAVEIT 'unmet prerequisite causes test to be skipped' '\n \tdonthaveit=no\n '\n-if test -z \"$GIT_TEST_FAIL_PREREQS\" -a $haveit$donthaveit != yesyes\n+if test -z \"$GIT_TEST_FAIL_PREREQS_INTERNAL\" -a $haveit$donthaveit != yesyes\n then\n \tsay \"bug in test framework: prerequisite tags do not work reliably\"\n \texit 1\n@@ -747,7 +747,7 @@ donthaveiteither=yes\n test_expect_success DONTHAVEIT,HAVEIT 'unmet prerequisites causes test to be skipped' '\n \tdonthaveiteither=no\n '\n-if test -z \"$GIT_TEST_FAIL_PREREQS\" -a $haveit$donthaveit$donthaveiteither != yesyesyes\n+if test -z \"$GIT_TEST_FAIL_PREREQS_INTERNAL\" -a $haveit$donthaveit$donthaveiteither != yesyesyes\n then\n \tsay \"bug in test framework: multiple prerequisite tags do not work reliably\"\n \texit 1\n@@ -763,7 +763,7 @@ test_expect_success !LAZY_TRUE 'missing lazy prereqs skip tests' '\n \tdonthavetrue=no\n '\n \n-if test -z \"$GIT_TEST_FAIL_PREREQS\" -a \"$havetrue$donthavetrue\" != yesyes\n+if test -z \"$GIT_TEST_FAIL_PREREQS_INTERNAL\" -a \"$havetrue$donthavetrue\" != yesyes\n then\n \tsay 'bug in test framework: lazy prerequisites do not work'\n \texit 1\n@@ -779,7 +779,7 @@ test_expect_success LAZY_FALSE 'missing negative lazy prereqs will skip' '\n \thavefalse=no\n '\n \n-if test -z \"$GIT_TEST_FAIL_PREREQS\" -a \"$nothavefalse$havefalse\" != yesyes\n+if test -z \"$GIT_TEST_FAIL_PREREQS_INTERNAL\" -a \"$nothavefalse$havefalse\" != yesyes\n then\n \tsay 'bug in test framework: negative lazy prerequisites do not work'\n \texit 1\n@@ -790,7 +790,7 @@ test_expect_success 'tests clean up after themselves' '\n \ttest_when_finished clean=yes\n '\n \n-if test -z \"$GIT_TEST_FAIL_PREREQS\" -a $clean != yes\n+if test -z \"$GIT_TEST_FAIL_PREREQS_INTERNAL\" -a $clean != yes\n then\n \tsay \"bug in test framework: basic cleanup command does not work reliably\"\n \texit 1\ndiff --git a/t/test-lib-functions.sh b/t/test-lib-functions.sh\nindex 527508c350..1cd0655f96 100644\n--- a/t/test-lib-functions.sh\n+++ b/t/test-lib-functions.sh\n@@ -309,7 +309,7 @@ test_unset_prereq () {\n }\n \n test_set_prereq () {\n-\tif test -n \"$GIT_TEST_FAIL_PREREQS\"\n+\tif test -n \"$GIT_TEST_FAIL_PREREQS_INTERNAL\"\n \tthen\n \t\tcase \"$1\" in\n \t\t# The \"!\" case is handled below with\n@@ -1043,7 +1043,7 @@ perl () {\n # The error/skip message should be given by $2.\n #\n test_skip_or_die () {\n-\tif ! git env--helper --mode-bool --variable=$1 --default=0 --exit-code --quiet\n+\tif ! git env--helper --type=bool --default=false --exit-code $1\n \tthen\n \t\tskip_all=$2\n \t\ttest_done\ndiff --git a/t/test-lib.sh b/t/test-lib.sh\nindex ed5d69dfe5..1af4e50653 100644\n--- a/t/test-lib.sh\n+++ b/t/test-lib.sh\n@@ -1389,6 +1389,25 @@ yes () {\n \tdone\n }\n \n+# The GIT_TEST_FAIL_PREREQS code hooks into test_set_prereq(), and\n+# thus needs to be set up really early, and set an internal variable\n+# for convenience so the hot test_set_prereq() codepath doesn't need\n+# to call \"git env--helper\". Only do that work if needed by seeing if\n+# GIT_TEST_FAIL_PREREQS is set at all.\n+GIT_TEST_FAIL_PREREQS_INTERNAL=\n+if test -n \"$GIT_TEST_FAIL_PREREQS\"\n+then\n+\tif git env--helper --type=bool --default=0 --exit-code GIT_TEST_FAIL_PREREQS\n+\tthen\n+\t\tGIT_TEST_FAIL_PREREQS_INTERNAL=true\n+\t\ttest_set_prereq FAIL_PREREQS\n+\tfi\n+else\n+\ttest_lazy_prereq FAIL_PREREQS '\n+\t\tgit env--helper --type=bool --default=0 --exit-code GIT_TEST_FAIL_PREREQS\n+\t'\n+fi\n+\n # Fix some commands on Windows\n uname_s=$(uname -s)\n case $uname_s in\n@@ -1605,7 +1624,3 @@ test_lazy_prereq SHA1 '\n test_lazy_prereq REBASE_P '\n \ttest -z \"$GIT_TEST_SKIP_REBASE_P\"\n '\n-\n-test_lazy_prereq FAIL_PREREQS '\n-\ttest -n \"$GIT_TEST_FAIL_PREREQS\"\n-'\n-- \n2.22.0.455.g172b71a6c5\n\n"},{"id":"377747","messageId":"xmqqh88jkmiz.fsf@gitster-ct.c.googlers.com","threadId":"51336","inReplyTo":"87blyr8ijr.fsf@evledraar.gmail.com","subject":"Re: [PATCH v2 2/8] env--helper: new undocumented builtin wrapping git_env_*()","fromName":"Junio C Hamano","fromEmail":"gitster@pobox.com","sentAt":"2019-06-21T15:04:20Z","receivedAt":"2019-06-21T15:04:25Z","isPatch":true,"sender":{"key":"gitster@pobox.com","avatar":"https://avatars.githubusercontent.com/u/54884?v=4"},"body":"Ævar Arnfjörð Bjarmason <avarab@gmail.com> writes:\n\n> Just thought I'd ask if appeasing older analyzers is what we want for\n> these sorts of optional warnings in general.\n\nYeah, examples of such \"let's help users with common compilers so\nthat they can focus on real errors\" are abound.\n\nThanks.\n"},{"id":"377754","messageId":"xmqqr27mkgty.fsf@gitster-ct.c.googlers.com","threadId":"51336","inReplyTo":"20190621101812.27300-3-avarab@gmail.com","subject":"Re: [PATCH v3 2/8] env--helper: new undocumented builtin wrapping git_env_*()","fromName":"Junio C Hamano","fromEmail":"gitster@pobox.com","sentAt":"2019-06-21T17:07:21Z","receivedAt":"2019-06-21T17:07:26Z","isPatch":true,"sender":{"key":"gitster@pobox.com","avatar":"https://avatars.githubusercontent.com/u/54884?v=4"},"body":"Ævar Arnfjörð Bjarmason  <avarab@gmail.com> writes:\n\n> The --type=bool option will be used by subsequent patches, but not\n> --type=ulong. I figured it was easy enough to add it & test for it so\n> I left it in so we'd have wrappers for both git_env_*() functions, and\n> to have a template to make it obvious how we'd add --type=int etc. if\n> it's needed in the future.\n\nYup, it is fine to start small/minimal.  In addition, obviously we\nwould eventually want \"string\" type (in fact, it would probably be\nthe reasonable default when --type=<type> option is missing, once\nthis becomes a real command and not a test helper).\n\n> +static char const * const env__helper_usage[] = {\n> +\tN_(\"git env--helper --type=[bool|ulong] <options> <env-var>\"),\n\nThis makes it look as if --type=<type> is not among options, which I\nam not sure is the impression we would want to give, as I doubt we\nwould want to keep it mandatory in the long run, but I'd say it is\nOK for two reasons (1) as we start minimal, it is OK to keep this\nmandatory, and (2) this gives us a place to enumerate available\ntypes.\n\nThe output from \"git env--helper -h\" may redundantly list the\n\"--type\" option, though.\n\n> +\targc = parse_options(argc, argv, prefix, opts, env__helper_usage,\n> +\t\t\t     PARSE_OPT_KEEP_UNKNOWN);\n\nWhy KEEP_UNKNOWN?\n\n> +\tif (env_default && !*env_default)\n> +\t\tusage_with_options(env__helper_usage, opts);\n> +\tif (!cmdmode)\n> +\t\tusage_with_options(env__helper_usage, opts);\n> +\tif (argc != 1)\n> +\t\tusage_with_options(env__helper_usage, opts);\n> +\tenv_variable = argv[0];\n> +\n> +\tswitch (cmdmode) {\n> +\tcase ENV_HELPER_TYPE_BOOL:\n> +\t\tif (env_default) {\n> +\t\t\tdefault_int = git_parse_maybe_bool(env_default);\n> +\t\t\tif (default_int == -1) {\n> +\t\t\t\terror(_(\"option `--default' expects a boolean value with `--type=bool`, not `%s`\"),\n> +\t\t\t\t      env_default);\n> +\t\t\t\tusage_with_options(env__helper_usage, opts);\n> +\t\t\t}\n\nOK, that more-or-less is equivalent to what git_config_bool_or_int()\ndoes, except that I would say \"if (default_int < 0)\" to match the\noriginal more closely if I were doing this.\n\n> +\t\t} else {\n> +\t\t\tdefault_int = 0;\n> +\t\t}\n> +\t\tret_int = git_env_bool(env_variable, default_int);\n> +\t\tif (!exit_code)\n> +\t\t\tputs(ret_int ? \"true\" : \"false\");\n> +\t\tret = ret_int;\n> +\t\tbreak;\n\nI do not think we want to assign 0 to 'ret' if we are not doing\n\"exit_code\".  \"We successfully found that the variable's value is\nfalse, said that to standard output, and signal success by exiting\nwith 0 status\" is what we would want, no?\n\n> +\tcase ENV_HELPER_TYPE_ULONG:\n> +\t\tif (env_default) {\n> +\t\t\tif (!git_parse_ulong(env_default, &default_ulong)) {\n> +\t\t\t\terror(_(\"option `--default' expects an unsigned long value with `--type=ulong`, not `%s`\"),\n> +\t\t\t\t      env_default);\n> +\t\t\t\tusage_with_options(env__helper_usage, opts);\n> +\t\t\t}\n> +\t\t} else {\n> +\t\t\tdefault_ulong = 0;\n> +\t\t}\n> +\t\tret_ulong = git_env_ulong(env_variable, default_ulong);\n> +\t\tif (!exit_code)\n> +\t\t\tprintf(\"%lu\\n\", ret_ulong);\n> +\t\tret = ret_ulong;\n\nLikewise.\n\n> +\t\tbreak;\n> +\tdefault:\n> +\t\tBUG(\"unknown <type> value\");\n> +\t\tbreak;\n> +\t}\n> +\n> +\treturn !ret;\n> +}\n> diff --git a/git.c b/git.c\n> index c2eec470c9..a43e1dd98e 100644\n> --- a/git.c\n> +++ b/git.c\n> @@ -500,6 +500,7 @@ static struct cmd_struct commands[] = {\n>  \t{ \"diff-index\", cmd_diff_index, RUN_SETUP | NO_PARSEOPT },\n>  \t{ \"diff-tree\", cmd_diff_tree, RUN_SETUP | NO_PARSEOPT },\n>  \t{ \"difftool\", cmd_difftool, RUN_SETUP_GENTLY },\n> +\t{ \"env--helper\", cmd_env__helper },\n>  \t{ \"fast-export\", cmd_fast_export, RUN_SETUP },\n>  \t{ \"fetch\", cmd_fetch, RUN_SETUP },\n>  \t{ \"fetch-pack\", cmd_fetch_pack, RUN_SETUP | NO_PARSEOPT },\n> diff --git a/t/t0017-env-helper.sh b/t/t0017-env-helper.sh\n> new file mode 100755\n> index 0000000000..709bbbd275\n> --- /dev/null\n> +++ b/t/t0017-env-helper.sh\n> @@ -0,0 +1,83 @@\n> +#!/bin/sh\n> +\n> +test_description='test env--helper'\n> +\n> +. ./test-lib.sh\n> +\n> +\n> +test_expect_success 'env--helper usage' '\n> +\ttest_must_fail git env--helper &&\n> +\ttest_must_fail git env--helper --type=bool &&\n> +\ttest_must_fail git env--helper --type=ulong &&\n> +\ttest_must_fail git env--helper --type=bool &&\n> +\ttest_must_fail git env--helper --type=bool --default &&\n> +\ttest_must_fail git env--helper --type=bool --default= &&\n> +\ttest_must_fail git env--helper --defaultxyz\n> +'\n> +\n> +test_expect_success 'env--helper bad default values' '\n\nI think\n\n\tsane_unset MISSING &&\n\nis needed, as I do not think test-lib.sh filters that variable from\nthe tester's environment from being seen by us.\n\n> +\ttest_must_fail git env--helper --type=bool --default=1xyz MISSING &&\n> +\ttest_must_fail git env--helper --type=ulong --default=1xyz MISSING\n\nBoth I and you know that the current implementation of env--helper\nhappens to notice and bail for failing to parse --default without\neven consulting the variable, but we do not have to rely on such an\nimplementation detail.\n\nSpeaking of that particular implementation detail, if the variable\nis not missing, should we even parse and complain what is in --default?\nI think the answer is \"yes, for catching bugs in the script, that is\nmore useful behaviour\".\n\nIf that is the design principle, we should also test cases where an\nexisting variable is given with a --default that is unparseable and\nmake sure that the command fails.\n\n> +'\n> +\n> +test_expect_success 'env--helper --type=bool' '\n\nDitto for sane_unset MISSING upfront.\n\n> +\t# Test various --default bool values\n> +\techo true >expected &&\n> +\tgit env--helper --type=bool --default=1 MISSING >actual &&\n> +\ttest_cmp expected actual &&\n> +\tgit env--helper --type=bool --default=yes MISSING >actual &&\n> +\ttest_cmp expected actual &&\n> +\tgit env--helper --type=bool --default=true MISSING >actual &&\n> +\ttest_cmp expected actual &&\n> +\techo false >expected &&\n> +\ttest_must_fail git env--helper --type=bool --default=0 MISSING >actual &&\n> +\ttest_cmp expected actual &&\n\nAs I said already, it is a horrible calling convention to make the\nmode that produces textual output to fail when the variable is set\nto false.  The above two should read more like\n\n    echo true >expect &&\n    git env--helper --type=bool --default=true MISSING >actual &&\n    test_cmp expect actual &&\n    echo false >expect &&\n    git env--helper --type=bool --default=0 MISSING >actual &&\n    test_cmp expect actual &&\n\n"},{"id":"377898","messageId":"xmqqr27jhqwc.fsf@gitster-ct.c.googlers.com","threadId":"51336","inReplyTo":"20190621101812.27300-6-avarab@gmail.com","subject":"Re: [PATCH v3 5/8] tests: make GIT_TEST_GETTEXT_POISON a boolean","fromName":"Junio C Hamano","fromEmail":"gitster@pobox.com","sentAt":"2019-06-24T16:47:15Z","receivedAt":"2019-06-24T16:47:26Z","isPatch":true,"sender":{"key":"gitster@pobox.com","avatar":"https://avatars.githubusercontent.com/u/54884?v=4"},"body":"Ævar Arnfjörð Bjarmason  <avarab@gmail.com> writes:\n\n> diff --git a/config.c b/config.c\n> index 374cb33005..b985d60fa4 100644\n> --- a/config.c\n> +++ b/config.c\n> @@ -956,6 +956,15 @@ static void die_bad_number(const char *name, const char *value)\n>  \tif (!value)\n>  \t\tvalue = \"\";\n>  \n> +\tif (!strcmp(name, \"GIT_TEST_GETTEXT_POISON\"))\n> +\t\t/*\n> +\t\t * We explicitly *don't* use _() here since it would\n> +\t\t * cause an infinite loop with _() needing to call\n> +\t\t * use_gettext_poison(). This is why marked up\n> +\t\t * translations with N_() above.\n> +\t\t */\n> +\t\tdie(bad_numeric, value, name, error_type);\n\n;-)  Nicely explained.\n\n> diff --git a/git-sh-i18n.sh b/git-sh-i18n.sh\n> index e1d917fd27..8eef60b43f 100644\n> --- a/git-sh-i18n.sh\n> +++ b/git-sh-i18n.sh\n> @@ -17,7 +17,9 @@ export TEXTDOMAINDIR\n>  \n>  # First decide what scheme to use...\n>  GIT_INTERNAL_GETTEXT_SH_SCHEME=fallthrough\n> -if test -n \"$GIT_TEST_GETTEXT_POISON\"\n> +if test -n \"$GIT_TEST_GETTEXT_POISON\" &&\n> +\t    git env--helper --type=bool --default=0 --exit-code \\\n> +\t\tGIT_TEST_GETTEXT_POISON\n\nThe helper is called only when GIT_TEST_GETTEXT_POISON has a\nnon-empty string as its value, so it's default is meaningless, no?\n"},{"id":"381952","messageId":"20190906121326.23056-1-szeder.dev@gmail.com","threadId":"51336","inReplyTo":"20190621101812.27300-8-avarab@gmail.com","subject":"[PATCH 1/2] t/lib-git-svn.sh: check GIT_TEST_SVN_HTTPD when running SVN HTTP tests","fromName":"SZEDER Gábor","fromEmail":"szeder.dev@gmail.com","sentAt":"2019-09-06T12:13:25Z","receivedAt":"2019-09-06T12:13:34Z","isPatch":true,"sender":{"key":"szeder.dev@gmail.com","avatar":"https://avatars.githubusercontent.com/u/116324?v=4"},"body":"Once upon a time the GIT_SVN_TEST_HTTPD environment variable needed to\nbe set to enable SVN HTTP tests [1].\n\nThen 3b072c577b (tests: replace test_tristate with \"git env--helper\",\n2019-06-21) came along, and attempted to turn GIT_SVN_TEST_HTTPD into\na bool, but while doing so it mistyped the variable name, and started\nto check GIT_TEST_HTTPD instead.  Consequently, if someone explicitly\nset GIT_TEST_HTTPD to true and has only the general 'git-svn'\ndependencies installed but not the Subversion server modules for\nApache (libapache2-mod-svn), then a couple of 'git-svn' tests fail,\nbecause they can't start httpd due to the missing module.\n\nWe could simply fix this by checking the GIT_SVN_TEST_HTTPD\nvariablewith 'git env--helper', but notice that the name of this\nvariable doesn't conform to our usual GIT_TEST_* convention.\n\nSo let's check the GIT_TEST_SVN_HTTPD instead.\n\n[1] a8a5d25118 (git svn: migrate tests to use lib-httpd, 2016-07-23)\n\nSigned-off-by: SZEDER Gábor <szeder.dev@gmail.com>\n---\n t/lib-git-svn.sh | 2 +-\n 1 file changed, 1 insertion(+), 1 deletion(-)\n\ndiff --git a/t/lib-git-svn.sh b/t/lib-git-svn.sh\nindex 5d4ae629e1..bc0b9c71f8 100644\n--- a/t/lib-git-svn.sh\n+++ b/t/lib-git-svn.sh\n@@ -69,7 +69,7 @@ svn_cmd () {\n maybe_start_httpd () {\n \tloc=${1-svn}\n \n-\tif git env--helper --type=bool --default=false --exit-code GIT_TEST_HTTPD\n+\tif git env--helper --type=bool --default=false --exit-code GIT_TEST_SVN_HTTPD\n \tthen\n \t\t. \"$TEST_DIRECTORY\"/lib-httpd.sh\n \t\tLIB_HTTPD_SVN=\"$loc\"\n-- \n2.23.0.331.g4e51dcdf11\n\n"},{"id":"381953","messageId":"20190906121326.23056-2-szeder.dev@gmail.com","threadId":"51336","inReplyTo":"20190906121326.23056-1-szeder.dev@gmail.com","subject":"[PATCH 2/2] ci: restore running httpd tests","fromName":"SZEDER Gábor","fromEmail":"szeder.dev@gmail.com","sentAt":"2019-09-06T12:13:26Z","receivedAt":"2019-09-06T12:13:35Z","isPatch":true,"sender":{"key":"szeder.dev@gmail.com","avatar":"https://avatars.githubusercontent.com/u/116324?v=4"},"body":"Once upon a time GIT_TEST_HTTPD was a tristate variable and we\nexported 'GIT_TEST_HTTPD=YesPlease' in our CI scripts to make sure\nthat we run the httpd tests in the Linux Clang and GCC build jobs, or\nerror out if they can't be run for any reason [1].\n\nThen 3b072c577b (tests: replace test_tristate with \"git env--helper\",\n2019-06-21) came along, turned GIT_TEST_HTTPD into a bool, but forgot\nto update our CI scripts accordingly.  So, since GIT_TEST_HTTPD is set\nexplicitly, but its value is not one of the standardized true values,\nour CI jobs have been simply skipping the httpd tests in the last\ncouple of weeks.\n\nSet 'GIT_TEST_HTTPD=true' to restore running httpd tests in our CI\njobs.\n\n[1] a1157b76eb (travis-ci: set GIT_TEST_HTTPD in 'ci/lib-travisci.sh',\n    2017-12-12)\n\nSigned-off-by: SZEDER Gábor <szeder.dev@gmail.com>\n---\n ci/lib.sh | 2 +-\n 1 file changed, 1 insertion(+), 1 deletion(-)\n\ndiff --git a/ci/lib.sh b/ci/lib.sh\nindex 44db2d5cbb..29dc740d40 100755\n--- a/ci/lib.sh\n+++ b/ci/lib.sh\n@@ -160,7 +160,7 @@ linux-clang|linux-gcc)\n \t\texport CC=gcc-8\n \tfi\n \n-\texport GIT_TEST_HTTPD=YesPlease\n+\texport GIT_TEST_HTTPD=true\n \n \t# The Linux build installs the defined dependency versions below.\n \t# The OS X build installs much more recent versions, whichever\n-- \n2.23.0.331.g4e51dcdf11\n\n"},{"id":"381968","messageId":"xmqqd0gdnyr9.fsf@gitster-ct.c.googlers.com","threadId":"51336","inReplyTo":"20190906121326.23056-2-szeder.dev@gmail.com","subject":"Re: [PATCH 2/2] ci: restore running httpd tests","fromName":"Junio C Hamano","fromEmail":"gitster@pobox.com","sentAt":"2019-09-06T17:03:06Z","receivedAt":"2019-09-06T17:03:11Z","isPatch":true,"sender":{"key":"gitster@pobox.com","avatar":"https://avatars.githubusercontent.com/u/54884?v=4"},"body":"SZEDER Gábor <szeder.dev@gmail.com> writes:\n\n> Once upon a time GIT_TEST_HTTPD was a tristate variable and we\n> exported 'GIT_TEST_HTTPD=YesPlease' in our CI scripts to make sure\n> that we run the httpd tests in the Linux Clang and GCC build jobs, or\n> error out if they can't be run for any reason [1].\n\nWow.  I vaguely recall having mumbled about keeping YesPlease as an\nextra synomym for 'yes' for safety against misconversions, as its\nuse in the build/test infrastructure is so ingrained, but at the end\nwent with the standard set of boolean without doing such extending,\nwith the hope that soon any misconversion would be found out.\n\nThis discovery of a misconversion took 3 months, which may or may\nnot match the definition of \"soon\" X-<.\n\nThe fix is obviously correct.  Thanks.\n\n> Then 3b072c577b (tests: replace test_tristate with \"git env--helper\",\n> 2019-06-21) came along, turned GIT_TEST_HTTPD into a bool, but forgot\n> to update our CI scripts accordingly.  So, since GIT_TEST_HTTPD is set\n> explicitly, but its value is not one of the standardized true values,\n> our CI jobs have been simply skipping the httpd tests in the last\n> couple of weeks.\n>\n> Set 'GIT_TEST_HTTPD=true' to restore running httpd tests in our CI\n> jobs.\n>\n> [1] a1157b76eb (travis-ci: set GIT_TEST_HTTPD in 'ci/lib-travisci.sh',\n>     2017-12-12)\n>\n> Signed-off-by: SZEDER Gábor <szeder.dev@gmail.com>\n> ---\n>  ci/lib.sh | 2 +-\n>  1 file changed, 1 insertion(+), 1 deletion(-)\n>\n> diff --git a/ci/lib.sh b/ci/lib.sh\n> index 44db2d5cbb..29dc740d40 100755\n> --- a/ci/lib.sh\n> +++ b/ci/lib.sh\n> @@ -160,7 +160,7 @@ linux-clang|linux-gcc)\n>  \t\texport CC=gcc-8\n>  \tfi\n>  \n> -\texport GIT_TEST_HTTPD=YesPlease\n> +\texport GIT_TEST_HTTPD=true\n>  \n>  \t# The Linux build installs the defined dependency versions below.\n>  \t# The OS X build installs much more recent versions, whichever\n"},{"id":"381981","messageId":"20190906191300.GA10769@sigill.intra.peff.net","threadId":"51336","inReplyTo":"20190906121326.23056-2-szeder.dev@gmail.com","subject":"Re: [PATCH 2/2] ci: restore running httpd tests","fromName":"Jeff King","fromEmail":"peff@peff.net","sentAt":"2019-09-06T19:13:01Z","receivedAt":"2019-09-06T19:13:03Z","isPatch":true,"sender":{"key":"peff@peff.net","avatar":"https://avatars.githubusercontent.com/u/45925?v=4"},"body":"On Fri, Sep 06, 2019 at 02:13:26PM +0200, SZEDER Gábor wrote:\n\n> Once upon a time GIT_TEST_HTTPD was a tristate variable and we\n> exported 'GIT_TEST_HTTPD=YesPlease' in our CI scripts to make sure\n> that we run the httpd tests in the Linux Clang and GCC build jobs, or\n> error out if they can't be run for any reason [1].\n\nYikes, good catch.\n\nI wonder if it would be possible for the test suite to catch this. I\nthink env--helper would have written a message to stderr, but because we\nuse --exit-code, we can't tell the difference between that and \"false\".\n\nI think we'd have go back to something more like:\n\n  test_tristate () {\n\tbool=$(git env--helper --type=bool --default=true \"$1\") ||\n\t\teval \"error \\\"$1 is not a bool: \\$$1\\\"\"\n\ttest \"$bool\" = \"true\"\n  }\n  ...\n  if test_tristate GIT_TEST_HTTPD\n  then\n\t... use httpd ...\n  fi\n\nNot sure if it's worth it.\n\n-Peff\n"},{"id":"382003","messageId":"20190907101637.GE32087@szeder.dev","threadId":"51336","inReplyTo":"20190906191300.GA10769@sigill.intra.peff.net","subject":"Re: [PATCH 2/2] ci: restore running httpd tests","fromName":"SZEDER Gábor","fromEmail":"szeder.dev@gmail.com","sentAt":"2019-09-07T10:16:37Z","receivedAt":"2019-09-07T10:16:45Z","isPatch":true,"sender":{"key":"szeder.dev@gmail.com","avatar":"https://avatars.githubusercontent.com/u/116324?v=4"},"body":"On Fri, Sep 06, 2019 at 03:13:01PM -0400, Jeff King wrote:\n> On Fri, Sep 06, 2019 at 02:13:26PM +0200, SZEDER Gábor wrote:\n> \n> > Once upon a time GIT_TEST_HTTPD was a tristate variable and we\n> > exported 'GIT_TEST_HTTPD=YesPlease' in our CI scripts to make sure\n> > that we run the httpd tests in the Linux Clang and GCC build jobs, or\n> > error out if they can't be run for any reason [1].\n> \n> Yikes, good catch.\n> \n> I wonder if it would be possible for the test suite to catch this. I\n> think env--helper would have written a message to stderr, but because we\n> use --exit-code, we can't tell the difference between that and \"false\".\n\nNo, '--exit-code' only suppresses the printing of 'true' and 'false',\nbut it doesn't have any effect on the command's exit code.  And if the\nvalue of the environment variable is not a bool, then it does print an\nerror message to standard error, and, more importantly, exits with 128\n(as opposed to 1 indicating false).  So we could tell the difference,\nbut as it happens the command is invoked as 'if ! git env-helper ...',\nwhich then interprets that 128 the same as on ordinary false.\n\n  $ VAR=false git env--helper --type=bool --default=false --exit-code VAR ; echo $?\n  1\n  $ VAR=true git env--helper --type=bool --default=false --exit-code VAR ; echo $?\n  0\n  $ VAR=YesPlease git env--helper --type=bool --default=false --exit-code VAR ; echo $?\n  fatal: bad numeric config value 'YesPlease' for 'VAR': invalid unit\n  128\n\n\n> I think we'd have go back to something more like:\n> \n>   test_tristate () {\n\nThe env var is supposed to be a bool, so there is no third state\nanymore.\n\n> \tbool=$(git env--helper --type=bool --default=true \"$1\") ||\n\nSome callsites use '--default=false', so we need a second parameter to\nspecify the default.\n\n> \t\teval \"error \\\"$1 is not a bool: \\$$1\\\"\"\n> \ttest \"$bool\" = \"true\"\n>   }\n>   ...\n>   if test_tristate GIT_TEST_HTTPD\n>   then\n> \t... use httpd ...\n>   fi\n> \n> Not sure if it's worth it.\n\nWell...  On one hand, there are no other similar issues in our CI\nscripts (there is still a GIT_TEST_CLONE_2GB=YesPlease, but it's only\never checked with 'test -z' in 't5608-clone-2gb.sh', so it works as\nexpected, even though it's inconsistent, and\n'GIT_TEST_CLONE_2GB=NoThanks' would do the wrong thing).\n\nOTOH, some unsuspecting devs might still have a\n'GIT_TEST_foo=YesPlease' in their 'config.mak' from the old days...\n\nFurthermore, as for the \"good catch\", I just got lucky, and not only\nonce but several times in a row: that Perforce filehost outage the\nother day errored one of my builds, so I came up with a fix [1], for\nonce took the extra effort and checked it on Azure Pipelines, and\nsince that was my first ever build over there, out of curiosity I\nscrolled through the whole build output, by chance those \"skipped:\nNetwork testing disabled (unset GIT_TEST_HTTPD to enable)\" lines\ncaught my eye, shrugged and thought that Dscho should better fix this,\nbut then an hour later got suspicious, so looked up a recent Travis CI\nbuild, and...  here we are.\n\nI have to wonder how much longer it could have been remained\nunnoticed, if the Perforce filehost hadn't failed or if I hadn't made\nthe gitgitgadget PR for my fix, or...\n\nAnyway, this is just a long-winded way to say that I think we should\nvalidate those bools properly and error loudly on an invalid value\neven if it doesn't seem to worth it.\n\n\n[1] https://public-inbox.org/git/20190906102711.6401-1-szeder.dev@gmail.com/T/\n\n"},{"id":"386820","messageId":"20191122131437.25849-1-szeder.dev@gmail.com","threadId":"51336","inReplyTo":"20190907101637.GE32087@szeder.dev","subject":"[PATCH 0/2] tests: catch non-bool GIT_TEST_* values","fromName":"SZEDER Gábor","fromEmail":"szeder.dev@gmail.com","sentAt":"2019-11-22T13:14:35Z","receivedAt":"2019-11-22T13:14:46Z","isPatch":true,"sender":{"key":"szeder.dev@gmail.com","avatar":"https://avatars.githubusercontent.com/u/116324?v=4"},"body":"On Sat, Sep 07, 2019 at 12:16:37PM +0200, SZEDER Gábor wrote:\n> On Fri, Sep 06, 2019 at 03:13:01PM -0400, Jeff King wrote:\n> > I wonder if it would be possible for the test suite to catch this.\n\n[i.e. to catch a non-boolean value of a supposedly boolean GIT_TEST_*\nenvironment variable]\n\n> > Not sure if it's worth it.\n\n[...]\n\n> Anyway, this is just a long-winded way to say that I think we should\n> validate those bools properly and error loudly on an invalid value\n> even if it doesn't seem to worth it.\n\nI was playing with a new GIT_TEST boolean environment variable,\nmistyped it's value, and then it took me surprisingly long to figure\nout why the damn tests were not doing what I thought they should.\n\nSo now I'm fairly convinced that it's definitely worth doing.  And the\ncallsites look much nicer, too.\n\nThese patches should apply cleanly both on current 'master' or on\n'sg/git-test-boolean' (i.e. the email thread I'm replying to).  We\nhaven't introduced any new 'git env--helper' invocations in the test\nsuite/framework since then.\n\n\nSZEDER Gábor (2):\n  tests: add 'test_bool_env' to catch non-bool GIT_TEST_* values\n  t5608-clone-2gb.sh: turn GIT_TEST_CLONE_2GB into a bool\n\n ci/lib.sh               |  2 +-\n t/README                |  9 +++++++++\n t/lib-git-daemon.sh     |  2 +-\n t/lib-git-svn.sh        |  4 ++--\n t/lib-httpd.sh          |  2 +-\n t/t0000-basic.sh        | 34 ++++++++++++++++++++++++++++++++++\n t/t5512-ls-remote.sh    |  2 +-\n t/t5608-clone-2gb.sh    |  2 +-\n t/test-lib-functions.sh | 30 +++++++++++++++++++++++++++++-\n t/test-lib.sh           | 10 +++++-----\n 10 files changed, 84 insertions(+), 13 deletions(-)\n\n-- \n2.24.0.532.ge18579ded8\n\n"},{"id":"386821","messageId":"20191122131437.25849-2-szeder.dev@gmail.com","threadId":"51336","inReplyTo":"20191122131437.25849-1-szeder.dev@gmail.com","subject":"[PATCH 1/2] tests: add 'test_bool_env' to catch non-bool GIT_TEST_* values","fromName":"SZEDER Gábor","fromEmail":"szeder.dev@gmail.com","sentAt":"2019-11-22T13:14:36Z","receivedAt":"2019-11-22T13:14:47Z","isPatch":true,"sender":{"key":"szeder.dev@gmail.com","avatar":"https://avatars.githubusercontent.com/u/116324?v=4"},"body":"Since 3b072c577b (tests: replace test_tristate with \"git env--helper\",\n2019-06-21) we get the normalized bool values of various GIT_TEST_*\nenvironment variables via 'git env--helper'.  Now, while the 'git\nenv--helper' command itself does catch invalid values in the\nenvironment variable or in the given --default and exits with error\n(exit code 128 or 129, respectively), it's invoked in conditions like\n'if ! git env--helper ...', which means that all invalid bool values\nare interpreted the same as the ordinary 'false' (exit code 1).  This\nhas led to inadvertently skipped httpd tests in our CI builds for a\ncouple of weeks, see 3960290675 (ci: restore running httpd tests,\n2019-09-06).\n\nLet's be more careful about what the test suite accepts as bool values\nin GIT_TEST_* environment variables, and error out loud and clear on\ninvalid values instead of simply skipping tests.  Add the\n'test_bool_env' helper function to encapsulate the invocation of 'git\nenv--helper' and the verification of its exit code, and replace all\ninvocations of that command in our test framework and test suite with\na call to this new helper (except in 't0017-env-helper.sh', of\ncourse).\n\n  $ GIT_TEST_GIT_DAEMON=YesPlease ./t5570-git-daemon.sh\n  fatal: bad numeric config value 'YesPlease' for 'GIT_TEST_GIT_DAEMON': invalid unit\n  error: test_bool_env requires bool values both for $GIT_TEST_GIT_DAEMON and for the default fallback\n\nSigned-off-by: SZEDER Gábor <szeder.dev@gmail.com>\n---\n t/README                |  9 +++++++++\n t/lib-git-daemon.sh     |  2 +-\n t/lib-git-svn.sh        |  4 ++--\n t/lib-httpd.sh          |  2 +-\n t/t0000-basic.sh        | 34 ++++++++++++++++++++++++++++++++++\n t/t5512-ls-remote.sh    |  2 +-\n t/test-lib-functions.sh | 30 +++++++++++++++++++++++++++++-\n t/test-lib.sh           | 10 +++++-----\n 8 files changed, 82 insertions(+), 11 deletions(-)\n\ndiff --git a/t/README b/t/README\nindex 60d5b77bcc..94e09d025e 100644\n--- a/t/README\n+++ b/t/README\n@@ -978,6 +978,15 @@ library for your script to use.\n    output to the downstream---unlike the real version, it generates\n    only up to 99 lines.\n \n+ - test_bool_env <env-variable-name> <default-value>\n+\n+   Given the name of an environment variable with a bool value,\n+   normalize its value to a 0 (true) or 1 (false or empty string)\n+   return code.  Return with code corresponding to the given default\n+   value if the variable is unset.\n+   Abort the test script if either the value of the variable or the\n+   default are not valid bool values.\n+\n \n Prerequisites\n -------------\ndiff --git a/t/lib-git-daemon.sh b/t/lib-git-daemon.sh\nindex fb8f887080..e62569222b 100644\n--- a/t/lib-git-daemon.sh\n+++ b/t/lib-git-daemon.sh\n@@ -15,7 +15,7 @@\n #\n #\ttest_done\n \n-if ! git env--helper --type=bool --default=true --exit-code GIT_TEST_GIT_DAEMON\n+if ! test_bool_env GIT_TEST_GIT_DAEMON true\n then\n \tskip_all=\"git-daemon testing disabled (unset GIT_TEST_GIT_DAEMON to enable)\"\n \ttest_done\ndiff --git a/t/lib-git-svn.sh b/t/lib-git-svn.sh\nindex bc0b9c71f8..7d248e6588 100644\n--- a/t/lib-git-svn.sh\n+++ b/t/lib-git-svn.sh\n@@ -69,7 +69,7 @@ svn_cmd () {\n maybe_start_httpd () {\n \tloc=${1-svn}\n \n-\tif git env--helper --type=bool --default=false --exit-code GIT_TEST_SVN_HTTPD\n+\tif test_bool_env GIT_TEST_SVN_HTTPD false\n \tthen\n \t\t. \"$TEST_DIRECTORY\"/lib-httpd.sh\n \t\tLIB_HTTPD_SVN=\"$loc\"\n@@ -104,7 +104,7 @@ EOF\n }\n \n require_svnserve () {\n-\tif ! git env--helper --type=bool --default=false --exit-code GIT_TEST_SVNSERVE\n+\tif ! test_bool_env GIT_TEST_SVNSERVE false\n \tthen\n \t\tskip_all='skipping svnserve test. (set $GIT_TEST_SVNSERVE to enable)'\n \t\ttest_done\ndiff --git a/t/lib-httpd.sh b/t/lib-httpd.sh\nindex 0d985758c6..656997b4d6 100644\n--- a/t/lib-httpd.sh\n+++ b/t/lib-httpd.sh\n@@ -41,7 +41,7 @@ then\n \ttest_done\n fi\n \n-if ! git env--helper --type=bool --default=true --exit-code GIT_TEST_HTTPD\n+if ! test_bool_env GIT_TEST_HTTPD true\n then\n \tskip_all=\"Network testing disabled (unset GIT_TEST_HTTPD to enable)\"\n \ttest_done\ndiff --git a/t/t0000-basic.sh b/t/t0000-basic.sh\nindex 9ca0818cbe..a297170915 100755\n--- a/t/t0000-basic.sh\n+++ b/t/t0000-basic.sh\n@@ -878,6 +878,40 @@ test_expect_success 'test_oid can look up data for SHA-256' '\n \ttest \"$hexsz\" -eq 64\n '\n \n+test_expect_success 'test_bool_env' '\n+\t(\n+\t\tsane_unset envvar &&\n+\n+\t\ttest_bool_env envvar true &&\n+\t\t! test_bool_env envvar false &&\n+\n+\t\tenvvar= &&\n+\t\texport envvar &&\n+\t\t! test_bool_env envvar true &&\n+\t\t! test_bool_env envvar false &&\n+\n+\t\tenvvar=true &&\n+\t\ttest_bool_env envvar true &&\n+\t\ttest_bool_env envvar false &&\n+\n+\t\tenvvar=false &&\n+\t\t! test_bool_env envvar true &&\n+\t\t! test_bool_env envvar false &&\n+\n+\t\tenvvar=invalid &&\n+\t\t# When encountering an invalid bool value, test_bool_env\n+\t\t# prints its error message to the original stderr of the\n+\t\t# test script, hence the redirection of fd 7, and aborts\n+\t\t# with \"exit 1\", hence the subshell.\n+\t\t! ( test_bool_env envvar true ) 7>err &&\n+\t\tgrep \"error: test_bool_env requires bool values\" err &&\n+\n+\t\tenvvar=true &&\n+\t\t! ( test_bool_env envvar invalid ) 7>err &&\n+\t\tgrep \"error: test_bool_env requires bool values\" err\n+\t)\n+'\n+\n ################################################################\n # Basics of the basics\n \ndiff --git a/t/t5512-ls-remote.sh b/t/t5512-ls-remote.sh\nindex 43e1d8d4d2..d7b9f9078f 100755\n--- a/t/t5512-ls-remote.sh\n+++ b/t/t5512-ls-remote.sh\n@@ -267,7 +267,7 @@ test_expect_success 'ls-remote --symref omits filtered-out matches' '\n '\n \n test_lazy_prereq GIT_DAEMON '\n-\tgit env--helper --type=bool --default=true --exit-code GIT_TEST_GIT_DAEMON\n+\ttest_bool_env GIT_TEST_GIT_DAEMON true\n '\n \n # This test spawns a daemon, so run it only if the user would be OK with\ndiff --git a/t/test-lib-functions.sh b/t/test-lib-functions.sh\nindex e0b3f28d3a..bf5080cb9b 100644\n--- a/t/test-lib-functions.sh\n+++ b/t/test-lib-functions.sh\n@@ -1173,6 +1173,34 @@ perl () {\n \tcommand \"$PERL_PATH\" \"$@\" 2>&7\n } 7>&2 2>&4\n \n+# Given the name of an environment variable with a bool value, normalize\n+# its value to a 0 (true) or 1 (false or empty string) return code.\n+#\n+#   test_bool_env GIT_TEST_HTTPD <default-value>\n+#\n+# Return with code corresponding to the given default value if the variable\n+# is unset.\n+# Abort the test script if either the value of the variable or the default\n+# are not valid bool values.\n+\n+test_bool_env () {\n+\tif test $# != 2\n+\tthen\n+\t\tBUG \"test_bool_env requires two parameters (variable name and default value)\"\n+\tfi\n+\n+\tgit env--helper --type=bool --default=\"$2\" --exit-code \"$1\"\n+\tret=$?\n+\tcase $ret in\n+\t0|1)\t# unset or valid bool value\n+\t\t;;\n+\t*)\t# invalid bool value or something unexpected\n+\t\terror >&7 \"test_bool_env requires bool values both for \\$$1 and for the default fallback\"\n+\t\t;;\n+\tesac\n+\treturn $ret\n+}\n+\n # Exit the test suite, either by skipping all remaining tests or by\n # exiting with an error. If our prerequisite variable $1 falls back\n # on a default assume we were opportunistically trying to set up some\n@@ -1181,7 +1209,7 @@ perl () {\n # The error/skip message should be given by $2.\n #\n test_skip_or_die () {\n-\tif ! git env--helper --type=bool --default=false --exit-code $1\n+\tif ! test_bool_env \"$1\" false\n \tthen\n \t\tskip_all=$2\n \t\ttest_done\ndiff --git a/t/test-lib.sh b/t/test-lib.sh\nindex 30b07e310f..959568fa43 100644\n--- a/t/test-lib.sh\n+++ b/t/test-lib.sh\n@@ -1391,19 +1391,19 @@ yes () {\n # The GIT_TEST_FAIL_PREREQS code hooks into test_set_prereq(), and\n # thus needs to be set up really early, and set an internal variable\n # for convenience so the hot test_set_prereq() codepath doesn't need\n-# to call \"git env--helper\". Only do that work if needed by seeing if\n-# GIT_TEST_FAIL_PREREQS is set at all.\n+# to call \"git env--helper\" (via test_bool_env). Only do that work\n+# if needed by seeing if GIT_TEST_FAIL_PREREQS is set at all.\n GIT_TEST_FAIL_PREREQS_INTERNAL=\n if test -n \"$GIT_TEST_FAIL_PREREQS\"\n then\n-\tif git env--helper --type=bool --default=0 --exit-code GIT_TEST_FAIL_PREREQS\n+\tif test_bool_env GIT_TEST_FAIL_PREREQS false\n \tthen\n \t\tGIT_TEST_FAIL_PREREQS_INTERNAL=true\n \t\ttest_set_prereq FAIL_PREREQS\n \tfi\n else\n \ttest_lazy_prereq FAIL_PREREQS '\n-\t\tgit env--helper --type=bool --default=0 --exit-code GIT_TEST_FAIL_PREREQS\n+\t\ttest_bool_env GIT_TEST_FAIL_PREREQS false\n \t'\n fi\n \n@@ -1462,7 +1462,7 @@ then\n fi\n \n test_lazy_prereq C_LOCALE_OUTPUT '\n-\t! git env--helper --type=bool --default=0 --exit-code GIT_TEST_GETTEXT_POISON\n+\t! test_bool_env GIT_TEST_GETTEXT_POISON false\n '\n \n if test -z \"$GIT_TEST_CHECK_CACHE_TREE\"\n-- \n2.24.0.532.ge18579ded8\n\n"},{"id":"386822","messageId":"20191122131437.25849-3-szeder.dev@gmail.com","threadId":"51336","inReplyTo":"20191122131437.25849-1-szeder.dev@gmail.com","subject":"[PATCH 2/2] t5608-clone-2gb.sh: turn GIT_TEST_CLONE_2GB into a bool","fromName":"SZEDER Gábor","fromEmail":"szeder.dev@gmail.com","sentAt":"2019-11-22T13:14:37Z","receivedAt":"2019-11-22T13:14:50Z","isPatch":true,"sender":{"key":"szeder.dev@gmail.com","avatar":"https://avatars.githubusercontent.com/u/116324?v=4"},"body":"The GIT_TEST_CLONE_2GB environment variable is only ever checked with\n'test -z' in 't5608-clone-2gb.sh', so any non-empty value is\ninterpreted as \"yes, run these expensive tests\", even\n'GIT_TEST_CLONE_2GB=NoThanks'.\n\nSimilar GIT_TEST_* environment variables have already been turned into\nbools in 3b072c577b (tests: replace test_tristate with \"git\nenv--helper\", 2019-06-21), so let's turn GIT_TEST_CLONE_2GB into a\nbool as well, to follow suit.\n\nOur CI builds set GIT_TEST_CLONE_2GB=YesPlease, so adjust them\naccordingly, thus removing the last 'YesPlease' from our CI scripts.\n\nSigned-off-by: SZEDER Gábor <szeder.dev@gmail.com>\n---\n ci/lib.sh            | 2 +-\n t/t5608-clone-2gb.sh | 2 +-\n 2 files changed, 2 insertions(+), 2 deletions(-)\n\ndiff --git a/ci/lib.sh b/ci/lib.sh\nindex 29dc740d40..2540bb6110 100755\n--- a/ci/lib.sh\n+++ b/ci/lib.sh\n@@ -151,7 +151,7 @@ fi\n \n export DEVELOPER=1\n export DEFAULT_TEST_TARGET=prove\n-export GIT_TEST_CLONE_2GB=YesPlease\n+export GIT_TEST_CLONE_2GB=true\n \n case \"$jobname\" in\n linux-clang|linux-gcc)\ndiff --git a/t/t5608-clone-2gb.sh b/t/t5608-clone-2gb.sh\nindex 2c6bc07344..eee0842888 100755\n--- a/t/t5608-clone-2gb.sh\n+++ b/t/t5608-clone-2gb.sh\n@@ -3,7 +3,7 @@\n test_description='Test cloning a repository larger than 2 gigabyte'\n . ./test-lib.sh\n \n-if test -z \"$GIT_TEST_CLONE_2GB\"\n+if ! test_bool_env GIT_TEST_CLONE_2GB false\n then\n \tsay 'Skipping expensive 2GB clone test; enable it with GIT_TEST_CLONE_2GB=t'\n else\n-- \n2.24.0.532.ge18579ded8\n\n"},{"id":"386987","messageId":"20191125135016.GA632@sigill.intra.peff.net","threadId":"51336","inReplyTo":"20191122131437.25849-2-szeder.dev@gmail.com","subject":"Re: [PATCH 1/2] tests: add 'test_bool_env' to catch non-bool GIT_TEST_* values","fromName":"Jeff King","fromEmail":"peff@peff.net","sentAt":"2019-11-25T13:50:16Z","receivedAt":"2019-11-25T13:50:18Z","isPatch":true,"sender":{"key":"peff@peff.net","avatar":"https://avatars.githubusercontent.com/u/45925?v=4"},"body":"On Fri, Nov 22, 2019 at 02:14:36PM +0100, SZEDER Gábor wrote:\n\n> Let's be more careful about what the test suite accepts as bool values\n> in GIT_TEST_* environment variables, and error out loud and clear on\n> invalid values instead of simply skipping tests.  Add the\n> 'test_bool_env' helper function to encapsulate the invocation of 'git\n> env--helper' and the verification of its exit code, and replace all\n> invocations of that command in our test framework and test suite with\n> a call to this new helper (except in 't0017-env-helper.sh', of\n> course).\n> \n>   $ GIT_TEST_GIT_DAEMON=YesPlease ./t5570-git-daemon.sh\n>   fatal: bad numeric config value 'YesPlease' for 'GIT_TEST_GIT_DAEMON': invalid unit\n>   error: test_bool_env requires bool values both for $GIT_TEST_GIT_DAEMON and for the default fallback\n\nThis patch looks good to me. A few musings below, but I'm not sure if\nthey're worth acting on.\n\n> +test_bool_env () {\n> +\tif test $# != 2\n> +\tthen\n> +\t\tBUG \"test_bool_env requires two parameters (variable name and default value)\"\n> +\tfi\n> +\n> +\tgit env--helper --type=bool --default=\"$2\" --exit-code \"$1\"\n> +\tret=$?\n> +\tcase $ret in\n> +\t0|1)\t# unset or valid bool value\n> +\t\t;;\n> +\t*)\t# invalid bool value or something unexpected\n> +\t\terror >&7 \"test_bool_env requires bool values both for \\$$1 and for the default fallback\"\n> +\t\t;;\n> +\tesac\n> +\treturn $ret\n> +}\n\nThe magic of exit code \"1\" is undocumented, but we have to rely on it\nhere. I suggested earlier that we could do:\n\n  if ! val=$(git env--helper --type=bool --default=\"$2\" \"$1\")\n    error ...\n  fi\n  test \"$val\" = \"true\"\n\nbut as you noted, we exit with code 1 for \"false\" even without\n--exit-code. IMHO this is a mis-design in the interface of env--helper.\n\nI think it would be an option to change it. It's an undocumented\ndouble-dashed internal helper, so I don't think we need to worry about\nbreaking compatibility. There's only one other caller that you didn't\ntouch in this patch, and it uses --exit-code (more on that in a second).\n\n> +test_expect_success 'test_bool_env' '\n\nThese tests make sense. In fact, they're much more interesting than the\nones in t0017, since these cover a superset of the code that's actually\nused in practice. t0017 covers non-exit-code and --ulong invocations,\nbut nobody uses them!\n\nI'm wondering if this whole env--helper thing is kind of\nover-engineered. Should it actually be a test-tool helper instead of a\nshipped builtin? The only call outside of the test suite is this one in\ngit-sh-i18n:\n\n  # First decide what scheme to use...\n  GIT_INTERNAL_GETTEXT_SH_SCHEME=fallthrough\n  if test -n \"$GIT_TEST_GETTEXT_POISON\" &&\n              git env--helper --type=bool --default=0 --exit-code \\\n                  GIT_TEST_GETTEXT_POISON\n  then\n          GIT_INTERNAL_GETTEXT_SH_SCHEME=poison\n  elif test -n \"@@USE_GETTEXT_SCHEME@@\"\n  ...\n\nwhich suffers from the same problem your patch is fixing. But since this\nis again a test-suite thing, it seems like it would be simpler for the\ntest suite to just set GIT_INTERNAL_GETTEXT_SH_SCHEME=poison itself\n(with a little rearranging here to let that override the \"fallthrough\"\ncase).\n\nThat would make the remaining --exit-code problem go away, remove some\ntest cruft from production code, and remove the last non-test-suite\ncaller of env--helper.\n\nAt that point we could make it a test-tool builtin. Or even implement it\npurely in shell, saving some processes (that would require duplicating\nthe internal bool logic, but that's way shorter than the boilerplate\nneeded to expose it via env--helper).\n\nI do think env--helper _could_ be useful for user scripts. But then I\nthink we'd need to document and rename it to make it clear that it's\npart of Git's plumbing that you can depend on.\n\n-Peff\n"},{"id":"386988","messageId":"20191125135347.GB494@sigill.intra.peff.net","threadId":"51336","inReplyTo":"20191122131437.25849-3-szeder.dev@gmail.com","subject":"Re: [PATCH 2/2] t5608-clone-2gb.sh: turn GIT_TEST_CLONE_2GB into a bool","fromName":"Jeff King","fromEmail":"peff@peff.net","sentAt":"2019-11-25T13:53:47Z","receivedAt":"2019-11-25T13:53:50Z","isPatch":true,"sender":{"key":"peff@peff.net","avatar":"https://avatars.githubusercontent.com/u/45925?v=4"},"body":"On Fri, Nov 22, 2019 at 02:14:37PM +0100, SZEDER Gábor wrote:\n\n> The GIT_TEST_CLONE_2GB environment variable is only ever checked with\n> 'test -z' in 't5608-clone-2gb.sh', so any non-empty value is\n> interpreted as \"yes, run these expensive tests\", even\n> 'GIT_TEST_CLONE_2GB=NoThanks'.\n> \n> Similar GIT_TEST_* environment variables have already been turned into\n> bools in 3b072c577b (tests: replace test_tristate with \"git\n> env--helper\", 2019-06-21), so let's turn GIT_TEST_CLONE_2GB into a\n> bool as well, to follow suit.\n> \n> Our CI builds set GIT_TEST_CLONE_2GB=YesPlease, so adjust them\n> accordingly, thus removing the last 'YesPlease' from our CI scripts.\n\nThis might break the setup of some developer or tester who put a similar\nvalue into their config.mak. But I think that's worth it to reduce\nconfusion in the long run, especially since they will get a very clear\nerror message due to your first patch.\n\n-Peff\n"}]}