Message ID | pull.1628.v2.git.1704268708720.gitgitgadget@gmail.com (mailing list archive) |
---|---|
State | Superseded |
Headers | show |
Series | [v2] write-or-die: make GIT_FLUSH a Boolean environment variable | expand |
On Wed, Jan 03, 2024 at 07:58:28AM +0000, Chandra Pratap via GitGitGadget wrote: [snip] > diff --git a/write-or-die.c b/write-or-die.c > index 42a2dc73cd3..a6acabd329f 100644 > --- a/write-or-die.c > +++ b/write-or-die.c > @@ -20,15 +20,12 @@ void maybe_flush_or_die(FILE *f, const char *desc) > { > static int skip_stdout_flush = -1; > struct stat st; > - char *cp; > > if (f == stdout) { > if (skip_stdout_flush < 0) { > - /* NEEDSWORK: make this a normal Boolean */ > - cp = getenv("GIT_FLUSH"); > - if (cp) > - skip_stdout_flush = (atoi(cp) == 0); > - else if ((fstat(fileno(stdout), &st) == 0) && > + if (!git_env_bool("GIT_FLUSH", -1)) > + skip_stdout_flush = 1; It's a bit surprising to pass `-1` as default value to `git_env_bool()` here, as this value would hint that the caller wants to explicitly handle the case where the "GIT_FLUSH" envvar is not set at all. We don't though, and essentially fall back to "GIT_FLUSH=1", so passing `1` as the fallback value would be less confusing. Anyway, the resulting behaviour is the same regardless of whether we pass `1` or `-1`, so I'm not sure whether this is worth a reroll. Patrick > + else if (!fstat(fileno(stdout), &st) && > S_ISREG(st.st_mode)) > skip_stdout_flush = 1; > else > > base-commit: 1a87c842ece327d03d08096395969aca5e0a6996 > -- > gitgitgadget >
"Chandra Pratap via GitGitGadget" <gitgitgadget@gmail.com> writes: > Documentation/git.txt | 16 +++++++--------- > write-or-die.c | 9 +++------ > 2 files changed, 10 insertions(+), 15 deletions(-) > > diff --git a/Documentation/git.txt b/Documentation/git.txt > index 2535a30194f..83fd60f2d11 100644 > --- a/Documentation/git.txt > +++ b/Documentation/git.txt > @@ -724,16 +724,14 @@ for further details. > waiting for someone with sufficient permissions to fix it. > > `GIT_FLUSH`:: > -// NEEDSWORK: make it into a usual Boolean environment variable > - If this environment variable is set to "1", then commands such > + If this Boolean environment variable is set to true, then commands such > as 'git blame' (in incremental mode), 'git rev-list', 'git log', > - 'git check-attr' and 'git check-ignore' will > - force a flush of the output stream after each record have been > - flushed. If this > - variable is set to "0", the output of these commands will be done > - using completely buffered I/O. If this environment variable is > - not set, Git will choose buffered or record-oriented flushing > - based on whether stdout appears to be redirected to a file or not. > + 'git check-attr' and 'git check-ignore' will force a flush of the output > + stream after each record have been flushed. If this variable is set to > + false, the output of these commands will be done using completely buffered > + I/O. If this environment variable is not set, Git will choose buffered or > + record-oriented flushing based on whether stdout appears to be redirected > + to a file or not. It is somewhat irritating to see that we need to change this many lines to just change "0" to "false" and "1" to "true". I wonder if it becomes easier to grok if we changed the description into a sub enumeration of three possibilities, but that would be outside the scope of this change [*]. > diff --git a/write-or-die.c b/write-or-die.c > index 42a2dc73cd3..a6acabd329f 100644 > --- a/write-or-die.c > +++ b/write-or-die.c > @@ -20,15 +20,12 @@ void maybe_flush_or_die(FILE *f, const char *desc) > { > static int skip_stdout_flush = -1; > struct stat st; > - char *cp; > > if (f == stdout) { > if (skip_stdout_flush < 0) { > - /* NEEDSWORK: make this a normal Boolean */ > - cp = getenv("GIT_FLUSH"); > - if (cp) > - skip_stdout_flush = (atoi(cp) == 0); > - else if ((fstat(fileno(stdout), &st) == 0) && > + if (!git_env_bool("GIT_FLUSH", -1)) > + skip_stdout_flush = 1; > + else if (!fstat(fileno(stdout), &st) && > S_ISREG(st.st_mode)) > skip_stdout_flush = 1; > else The above logic does not look correct to me, primarily because the return value of git_env_bool() is inspected only once to see if it is zero, and does not differentiate the "unset" case from other cases. Since git_env_bool(k, def) returns - "def" (-1 in this case) when k is not exported (in which case you need to do the "fstat" dance). - 0 when k is exported and has a string that is "false" (in which case you would want to set skip_stdout_flush to true). - 1 when k is exported and has a string that is "true" (in which case you would want to set skip_stdout_flush to false). - or dies if the string exported in k is bogus. shouldn't it be more like skip_stdout_flush = 0; /* assume flushing */ switch (git_env_bool("GIT_FLUSH", -1)) { case 0: /* told not to flush */ skip_stdout_flush = 1; ;; case -1: /* unspecified */ if (!fstat(...) && S_ISREG()) skip_stdout_flush = 1; ;; default: /* told to flush */ ;; } perhaps? [Footnote] * If I were to do this change, and if I were to also improve the style of the documentation before I forget, the way I would do so probably is with a two-patch series: (1) update "0" and "1" in the documentation with "false" and "true", without reflowing the text at all, and update the code. (2) rewrite the documentation to use 3-possibility sub-enumeration for values (imitate the way how other variables, like `diff.algorithm`, that can choose from a set of handful possible values are described). These two changes can be done in either order, but perhaps (1) is much less controversial change than the other, so I'd probably do so first.
On Wed, Jan 03, 2024 at 09:22:13AM +0100, Patrick Steinhardt wrote: > On Wed, Jan 03, 2024 at 07:58:28AM +0000, Chandra Pratap via GitGitGadget wrote: > [snip] > > diff --git a/write-or-die.c b/write-or-die.c > > index 42a2dc73cd3..a6acabd329f 100644 > > --- a/write-or-die.c > > +++ b/write-or-die.c > > @@ -20,15 +20,12 @@ void maybe_flush_or_die(FILE *f, const char *desc) > > { > > static int skip_stdout_flush = -1; > > struct stat st; > > - char *cp; > > > > if (f == stdout) { > > if (skip_stdout_flush < 0) { > > - /* NEEDSWORK: make this a normal Boolean */ > > - cp = getenv("GIT_FLUSH"); > > - if (cp) > > - skip_stdout_flush = (atoi(cp) == 0); > > - else if ((fstat(fileno(stdout), &st) == 0) && > > + if (!git_env_bool("GIT_FLUSH", -1)) > > + skip_stdout_flush = 1; > > It's a bit surprising to pass `-1` as default value to `git_env_bool()` > here, as this value would hint that the caller wants to explicitly > handle the case where the "GIT_FLUSH" envvar is not set at all. We don't > though, and essentially fall back to "GIT_FLUSH=1", so passing `1` as > the fallback value would be less confusing. > > Anyway, the resulting behaviour is the same regardless of whether we > pass `1` or `-1`, so I'm not sure whether this is worth a reroll. Hmm. If we pass -1 as the default value in the call to git_env_bool(), the only time we'll end up in the else branch is if the environment is set to some false-y value. I don't think that matches the existing behavior, since right now we'll infer skip_stdout_flush based on whether or not stdout is a regular file or something else. I think you'd probably want something closer to: --- 8< --- diff --git a/write-or-die.c b/write-or-die.c index 42a2dc73cd..f12e111688 100644 --- a/write-or-die.c +++ b/write-or-die.c @@ -19,20 +19,17 @@ void maybe_flush_or_die(FILE *f, const char *desc) { static int skip_stdout_flush = -1; - struct stat st; - char *cp; if (f == stdout) { if (skip_stdout_flush < 0) { - /* NEEDSWORK: make this a normal Boolean */ - cp = getenv("GIT_FLUSH"); - if (cp) - skip_stdout_flush = (atoi(cp) == 0); - else if ((fstat(fileno(stdout), &st) == 0) && - S_ISREG(st.st_mode)) - skip_stdout_flush = 1; - else - skip_stdout_flush = 0; + skip_stdout_flush = git_env_bool("GIT_FLUSH", -1); + if (skip_stdout_flush < 0) { + struct stat st; + if (fstat(fileno(f), &st)) + skip_stdout_flush = 0; + else + skip_stdout_flush = S_ISREG(st.st_mode); + } } if (skip_stdout_flush && !ferror(f)) return; --- >8 --- You could lose one level of indentation, but it costs an extra fstat() call in the case where GIT_FLUSH is set to some explicit value. Doing that would look like this ugly thing instead ;-): --- 8< --- diff --git a/write-or-die.c b/write-or-die.c index 42a2dc73cd..b3275d7577 100644 --- a/write-or-die.c +++ b/write-or-die.c @@ -19,20 +19,11 @@ void maybe_flush_or_die(FILE *f, const char *desc) { static int skip_stdout_flush = -1; - struct stat st; - char *cp; if (f == stdout) { if (skip_stdout_flush < 0) { - /* NEEDSWORK: make this a normal Boolean */ - cp = getenv("GIT_FLUSH"); - if (cp) - skip_stdout_flush = (atoi(cp) == 0); - else if ((fstat(fileno(stdout), &st) == 0) && - S_ISREG(st.st_mode)) - skip_stdout_flush = 1; - else - skip_stdout_flush = 0; + struct stat st; + skip_stdout_flush = git_env_bool("GIT_FLUSH", !fstat(fileno(f), &st) && S_ISREG(st.st_mode)); } if (skip_stdout_flush && !ferror(f)) return; --- >8 --- Thanks, Taylor
On Wed, Jan 03, 2024 at 12:15:26PM -0500, Taylor Blau wrote: > On Wed, Jan 03, 2024 at 09:22:13AM +0100, Patrick Steinhardt wrote: > > On Wed, Jan 03, 2024 at 07:58:28AM +0000, Chandra Pratap via GitGitGadget wrote: > > [snip] > > > diff --git a/write-or-die.c b/write-or-die.c > > > index 42a2dc73cd3..a6acabd329f 100644 > > > --- a/write-or-die.c > > > +++ b/write-or-die.c > > > @@ -20,15 +20,12 @@ void maybe_flush_or_die(FILE *f, const char *desc) > > > { > > > static int skip_stdout_flush = -1; > > > struct stat st; > > > - char *cp; > > > > > > if (f == stdout) { > > > if (skip_stdout_flush < 0) { > > > - /* NEEDSWORK: make this a normal Boolean */ > > > - cp = getenv("GIT_FLUSH"); > > > - if (cp) > > > - skip_stdout_flush = (atoi(cp) == 0); > > > - else if ((fstat(fileno(stdout), &st) == 0) && > > > + if (!git_env_bool("GIT_FLUSH", -1)) > > > + skip_stdout_flush = 1; > > > > It's a bit surprising to pass `-1` as default value to `git_env_bool()` > > here, as this value would hint that the caller wants to explicitly > > handle the case where the "GIT_FLUSH" envvar is not set at all. We don't > > though, and essentially fall back to "GIT_FLUSH=1", so passing `1` as > > the fallback value would be less confusing. > > > > Anyway, the resulting behaviour is the same regardless of whether we > > pass `1` or `-1`, so I'm not sure whether this is worth a reroll. > > Hmm. If we pass -1 as the default value in the call to git_env_bool(), > the only time we'll end up in the else branch is if the environment is > set to some false-y value. > > I don't think that matches the existing behavior, since right now we'll > infer skip_stdout_flush based on whether or not stdout is a regular file > or something else. > > I think you'd probably want something closer to: > > --- 8< --- > diff --git a/write-or-die.c b/write-or-die.c > index 42a2dc73cd..f12e111688 100644 > --- a/write-or-die.c > +++ b/write-or-die.c > @@ -19,20 +19,17 @@ > void maybe_flush_or_die(FILE *f, const char *desc) > { > static int skip_stdout_flush = -1; > - struct stat st; > - char *cp; > > if (f == stdout) { > if (skip_stdout_flush < 0) { > - /* NEEDSWORK: make this a normal Boolean */ > - cp = getenv("GIT_FLUSH"); > - if (cp) > - skip_stdout_flush = (atoi(cp) == 0); > - else if ((fstat(fileno(stdout), &st) == 0) && > - S_ISREG(st.st_mode)) > - skip_stdout_flush = 1; > - else > - skip_stdout_flush = 0; > + skip_stdout_flush = git_env_bool("GIT_FLUSH", -1); > + if (skip_stdout_flush < 0) { > + struct stat st; > + if (fstat(fileno(f), &st)) > + skip_stdout_flush = 0; > + else > + skip_stdout_flush = S_ISREG(st.st_mode); > + } > } > if (skip_stdout_flush && !ferror(f)) > return; > --- >8 --- Thanks for a nice reading - I can not imagine a better version.
Torsten Bögershausen <tboegi@web.de> writes: >> - cp = getenv("GIT_FLUSH"); >> - if (cp) >> - skip_stdout_flush = (atoi(cp) == 0); >> - else if ((fstat(fileno(stdout), &st) == 0) && >> - S_ISREG(st.st_mode)) >> - skip_stdout_flush = 1; >> - else >> - skip_stdout_flush = 0; >> + skip_stdout_flush = git_env_bool("GIT_FLUSH", -1); >> + if (skip_stdout_flush < 0) { >> + struct stat st; >> + if (fstat(fileno(f), &st)) >> + skip_stdout_flush = 0; >> + else >> + skip_stdout_flush = S_ISREG(st.st_mode); >> + } >> } >> if (skip_stdout_flush && !ferror(f)) >> return; >> --- >8 --- > > Thanks for a nice reading - I can not imagine a better version. Yup, the flow of the logic feels very natural with this version by making it clear that the case that the default "-1" is returned to us is where we need to figure out an appropriate value ourselves. An added bonus is that the scope "struct stat" has is limited to the absolute minimum. I like it, too. Thanks.
On Wed, Jan 03, 2024 at 11:18:50AM -0800, Junio C Hamano wrote: > > Thanks for a nice reading - I can not imagine a better version. > > Yup, the flow of the logic feels very natural with this version by > making it clear that the case that the default "-1" is returned to > us is where we need to figure out an appropriate value ourselves. > An added bonus is that the scope "struct stat" has is limited to the > absolute minimum. I like it, too. Thanks, both. Thanks, Taylor
diff --git a/Documentation/git.txt b/Documentation/git.txt index 2535a30194f..83fd60f2d11 100644 --- a/Documentation/git.txt +++ b/Documentation/git.txt @@ -724,16 +724,14 @@ for further details. waiting for someone with sufficient permissions to fix it. `GIT_FLUSH`:: -// NEEDSWORK: make it into a usual Boolean environment variable - If this environment variable is set to "1", then commands such + If this Boolean environment variable is set to true, then commands such as 'git blame' (in incremental mode), 'git rev-list', 'git log', - 'git check-attr' and 'git check-ignore' will - force a flush of the output stream after each record have been - flushed. If this - variable is set to "0", the output of these commands will be done - using completely buffered I/O. If this environment variable is - not set, Git will choose buffered or record-oriented flushing - based on whether stdout appears to be redirected to a file or not. + 'git check-attr' and 'git check-ignore' will force a flush of the output + stream after each record have been flushed. If this variable is set to + false, the output of these commands will be done using completely buffered + I/O. If this environment variable is not set, Git will choose buffered or + record-oriented flushing based on whether stdout appears to be redirected + to a file or not. `GIT_TRACE`:: Enables general trace messages, e.g. alias expansion, built-in diff --git a/write-or-die.c b/write-or-die.c index 42a2dc73cd3..a6acabd329f 100644 --- a/write-or-die.c +++ b/write-or-die.c @@ -20,15 +20,12 @@ void maybe_flush_or_die(FILE *f, const char *desc) { static int skip_stdout_flush = -1; struct stat st; - char *cp; if (f == stdout) { if (skip_stdout_flush < 0) { - /* NEEDSWORK: make this a normal Boolean */ - cp = getenv("GIT_FLUSH"); - if (cp) - skip_stdout_flush = (atoi(cp) == 0); - else if ((fstat(fileno(stdout), &st) == 0) && + if (!git_env_bool("GIT_FLUSH", -1)) + skip_stdout_flush = 1; + else if (!fstat(fileno(stdout), &st) && S_ISREG(st.st_mode)) skip_stdout_flush = 1; else