git.vger.kernel.org archive mirror
 help / color / mirror / Atom feed
* [PATCH] bugreport: add 'seconds' to default outfile name
@ 2023-10-14  4:01 Jacob Stopak
  2023-10-14 10:35 ` Kristoffer Haugsbakk
                   ` (2 more replies)
  0 siblings, 3 replies; 23+ messages in thread
From: Jacob Stopak @ 2023-10-14  4:01 UTC (permalink / raw)
  To: git; +Cc: Jacob Stopak

Currently, git bugreport postfixes the default bugreport filename (and
diagnostics zip filename if --diagnose is supplied) with the current
calendar hour and minute values, assuming the -s flag is absent.

If a user runs the bugreport command more than once within a calendar
minute, a filename conflict with an existing file occurs and the program
errors, since the new output filename was already used for the previous
file. If the user waits anywhere from 1 to 60 seconds (depending on
_when_ during the calendar minute the first command was run) the command
works again with no error since the default filename is now unique, and
multiple bug reports are able to be created with default settings.

This is a minor thing but can cause confusion especially for first time
users of the bugreport command, who are likely to run it multiple times
in quick succession to learn how it works, (like I did).

This patch adds the calendar second value to the default bugreport
filename. This technically just shortens the window during which the
issue occurs, but a single second is a small enough time increment that
users will avoid the filename conflict in practice in this scenario.

This means the user will end up with multiple bugreport files being
created if they run the command multiple times quickly, but that feels
more intuitive and consistent than an error arbitrarily occuring within
a calendar minute, especially given that the time window in which the
error currently occurs is variable as described above.

Signed-off-by: Jacob Stopak <jacob@initialcommit.io>
---
 builtin/bugreport.c | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

diff --git a/builtin/bugreport.c b/builtin/bugreport.c
index d2ae5c305d..b556c6e135 100644
--- a/builtin/bugreport.c
+++ b/builtin/bugreport.c
@@ -106,7 +106,7 @@ int cmd_bugreport(int argc, const char **argv, const char *prefix)
 	struct tm tm;
 	enum diagnose_mode diagnose = DIAGNOSE_NONE;
 	char *option_output = NULL;
-	char *option_suffix = "%Y-%m-%d-%H%M";
+	char *option_suffix = "%Y-%m-%d-%H%M%S";
 	const char *user_relative_path = NULL;
 	char *prefixed_filename;
 	size_t output_path_len;

base-commit: 493f4622739e9b64f24b465b21aa85870dd9dc09
-- 
2.42.0.297.g393e7d1581


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

* Re: [PATCH] bugreport: add 'seconds' to default outfile name
  2023-10-14  4:01 [PATCH] bugreport: add 'seconds' to default outfile name Jacob Stopak
@ 2023-10-14 10:35 ` Kristoffer Haugsbakk
  2023-10-14 16:27 ` Junio C Hamano
  2023-10-15  3:42 ` [PATCH v2 0/3] bugreport: include +i in outfile suffix as needed Jacob Stopak
  2 siblings, 0 replies; 23+ messages in thread
From: Kristoffer Haugsbakk @ 2023-10-14 10:35 UTC (permalink / raw)
  To: Jacob Stopak; +Cc: git

Hi Jacob

On Sat, Oct 14, 2023, at 06:01, Jacob Stopak wrote:
> This patch adds the calendar second value to the default bugreport

Nitpick: you can just say “Add the calendar”. “This patch” is redundant.

See `Documentation/SubmittingPatches` at `imperative-mood`.

-- 
Kristoffer

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

* Re: [PATCH] bugreport: add 'seconds' to default outfile name
  2023-10-14  4:01 [PATCH] bugreport: add 'seconds' to default outfile name Jacob Stopak
  2023-10-14 10:35 ` Kristoffer Haugsbakk
@ 2023-10-14 16:27 ` Junio C Hamano
  2023-10-14 16:33   ` Dragan Simic
  2023-10-15  3:01   ` Jacob Stopak
  2023-10-15  3:42 ` [PATCH v2 0/3] bugreport: include +i in outfile suffix as needed Jacob Stopak
  2 siblings, 2 replies; 23+ messages in thread
From: Junio C Hamano @ 2023-10-14 16:27 UTC (permalink / raw)
  To: Jacob Stopak; +Cc: git

Jacob Stopak <jacob@initialcommit.io> writes:

> Currently, git bugreport postfixes the default bugreport filename (and
> diagnostics zip filename if --diagnose is supplied) with the current
> calendar hour and minute values, assuming the -s flag is absent.

Is "postfix" a verb that is commonly understood?  I would say
"append" would be understood by more readers.  Also, is "calendar"
hour different from other kinds of hours, perhaps stopwatch hours
and microwave-oven hours?

> If a user runs the bugreport command more than once within a calendar
> minute, a filename conflict with an existing file occurs and the program
> errors, since the new output filename was already used for the previous
> file.

This is totally expected and you made an excellent observation.

I personally do not think it is a problem, simply because a quality
bug report that would capture information necessary to diagnose any
issue concisely in a readable fashion would take at least 90 seconds
or more to produce, though.

Instead of lengthening the filename for all files by 2 digits, the
command can retry by adding say "+1", "+2", etc. after the failed
filename to find a unique suffix within the same minute.  It would
mean that after writing git-bugreport-2023-10-14-0920.txt and you
start another one without spending enough time, the new one may
become git-bugreport-2023-10-14-0920+1.txt or something unique.  It
would be really unlikely that you would run out after failing to
find a vacant single digit suffix nine times, i.e. trying "+9".  It
would also help preserve existing user's workflow, e.g. they may
have written automation that assumes the down-to-minute format and
it would keep working on their bug reports without breaking.

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

* Re: [PATCH] bugreport: add 'seconds' to default outfile name
  2023-10-14 16:27 ` Junio C Hamano
@ 2023-10-14 16:33   ` Dragan Simic
  2023-10-14 17:45     ` Junio C Hamano
  2023-10-15  3:01   ` Jacob Stopak
  1 sibling, 1 reply; 23+ messages in thread
From: Dragan Simic @ 2023-10-14 16:33 UTC (permalink / raw)
  To: Junio C Hamano; +Cc: Jacob Stopak, git

On 2023-10-14 18:27, Junio C Hamano wrote:
> Jacob Stopak <jacob@initialcommit.io> writes:
>> If a user runs the bugreport command more than once within a calendar
>> minute, a filename conflict with an existing file occurs and the 
>> program
>> errors, since the new output filename was already used for the 
>> previous
>> file.
> 
> This is totally expected and you made an excellent observation.
> 
> I personally do not think it is a problem, simply because a quality
> bug report that would capture information necessary to diagnose any
> issue concisely in a readable fashion would take at least 90 seconds
> or more to produce, though.
> 
> Instead of lengthening the filename for all files by 2 digits, the
> command can retry by adding say "+1", "+2", etc. after the failed
> filename to find a unique suffix within the same minute.  It would
> mean that after writing git-bugreport-2023-10-14-0920.txt and you
> start another one without spending enough time, the new one may
> become git-bugreport-2023-10-14-0920+1.txt or something unique.

How about making the filename a bit shorter first, to make room for the 
additional two digits, so the example mentioned above would end up being 
named "git-bugreport-20231014-092037.txt"?

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

* Re: [PATCH] bugreport: add 'seconds' to default outfile name
  2023-10-14 16:33   ` Dragan Simic
@ 2023-10-14 17:45     ` Junio C Hamano
  2023-10-14 17:52       ` Dragan Simic
  0 siblings, 1 reply; 23+ messages in thread
From: Junio C Hamano @ 2023-10-14 17:45 UTC (permalink / raw)
  To: Dragan Simic; +Cc: Jacob Stopak, git

Dragan Simic <dsimic@manjaro.org> writes:

> How about making the filename a bit shorter first, to make room for
> the additional two digits, so the example mentioned above would end up
> being named "git-bugreport-20231014-092037.txt"?

The reason I stated not to unconditionally add two more digits is
*not* that I wanted to keep things shorter.  I wanted to keep names
stable and in the same shape as before for sensible people who spend
more than 60 seconds---only those who produce more than one within
the same minute will be affected.

What is your reason to want to make the filename shoter first?
It would break everybody, wouldn't it?


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

* Re: [PATCH] bugreport: add 'seconds' to default outfile name
  2023-10-14 17:45     ` Junio C Hamano
@ 2023-10-14 17:52       ` Dragan Simic
  2023-10-15  3:07         ` Jacob Stopak
  0 siblings, 1 reply; 23+ messages in thread
From: Dragan Simic @ 2023-10-14 17:52 UTC (permalink / raw)
  To: Junio C Hamano; +Cc: Jacob Stopak, git

On 2023-10-14 19:45, Junio C Hamano wrote:
> Dragan Simic <dsimic@manjaro.org> writes:
> 
>> How about making the filename a bit shorter first, to make room for
>> the additional two digits, so the example mentioned above would end up
>> being named "git-bugreport-20231014-092037.txt"?
> 
> The reason I stated not to unconditionally add two more digits is
> *not* that I wanted to keep things shorter.  I wanted to keep names
> stable and in the same shape as before for sensible people who spend
> more than 60 seconds---only those who produce more than one within
> the same minute will be affected.
> 
> What is your reason to want to make the filename shoter first?
> It would break everybody, wouldn't it?

Please note that I haven't researched in detail what else depends on the 
current filename format, which presumably is a whole bunch of stuff, I 
just suggested this filename compaction because I understood that the 
filename length was becoming an issue.

Speaking in general, I somehow find "20220712" a bit more readable than 
"2022-07-12" as part of a filename, but that's of course just my 
personal preference.

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

* Re: [PATCH] bugreport: add 'seconds' to default outfile name
  2023-10-14 16:27 ` Junio C Hamano
  2023-10-14 16:33   ` Dragan Simic
@ 2023-10-15  3:01   ` Jacob Stopak
  2023-10-15 17:06     ` Junio C Hamano
  1 sibling, 1 reply; 23+ messages in thread
From: Jacob Stopak @ 2023-10-15  3:01 UTC (permalink / raw)
  To: Junio C Hamano; +Cc: git

On Sat, Oct 14, 2023 at 09:27:27AM -0700, Junio C Hamano wrote:
> Jacob Stopak <jacob@initialcommit.io> writes:
> 
> Is "postfix" a verb that is commonly understood?  I would say
> "append" would be understood by more readers.

It's probably true that "append" or "suffix" (which is used in the code)
would be more easily understood. I'll switch in my updated messages.

> Also, is "calendar"
> hour different from other kinds of hours, perhaps stopwatch hours
> and microwave-oven hours?

Lol! By saying "calendar" I mean "falling on the official boundaries
of", like 11:15:00 - 11:16:00. Unlike the time between 11:15:30 -
11:16:30 which is also a minute, but it's not a "calendar" minute
because it overlaps into the next minute. I guess in this case it's more
of a "clock" minute than a "calendar" minute though ':D... I guess
"calendar" terminology is used more for months/years...

> I personally do not think it is a problem, simply because a quality
> bug report that would capture information necessary to diagnose any
> issue concisely in a readable fashion would take at least 90 seconds
> or more to produce, though.

This is true, when the user intentionally opens the bugreport with the
intent to start filling it out immediately, I assume they would almost
always cross the minute barrier and avoid the issue.

However, there are edge cases like the one I outlined, where the user
might open and close the report quickly, followed by rerunning the
command. This could be someone learning to use the command for the first
time. Or the case where a user only fills in a small part of the report
before closing it and running the command again.

These cases are certainly "the exception" but it seems the program could
be a bit more consistent/intuitive when they do occur.

> Instead of lengthening the filename for all files by 2 digits, the
> command can retry by adding say "+1", "+2", etc. after the failed
> filename to find a unique suffix within the same minute.  It would
> mean that after writing git-bugreport-2023-10-14-0920.txt and you
> start another one without spending enough time, the new one may
> become git-bugreport-2023-10-14-0920+1.txt or something unique.  It
> would be really unlikely that you would run out after failing to
> find a vacant single digit suffix nine times, i.e. trying "+9".  It
> would also help preserve existing user's workflow, e.g. they may
> have written automation that assumes the down-to-minute format and
> it would keep working on their bug reports without breaking.

I agree with all of this, and to me it's a better solution than
_appending_ the second value :). I have a patchset almost ready for this 
so I'll try to submit it later tonight.

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

* Re: [PATCH] bugreport: add 'seconds' to default outfile name
  2023-10-14 17:52       ` Dragan Simic
@ 2023-10-15  3:07         ` Jacob Stopak
  2023-10-15  3:13           ` Dragan Simic
  0 siblings, 1 reply; 23+ messages in thread
From: Jacob Stopak @ 2023-10-15  3:07 UTC (permalink / raw)
  To: Dragan Simic; +Cc: Junio C Hamano, git

On Sat, Oct 14, 2023 at 07:52:32PM +0200, Dragan Simic wrote:
> 
> Speaking in general, I somehow find "20220712" a bit more readable than
> "2022-07-12" as part of a filename, but that's of course just my personal
> preference.

It's funny how we all have our own preferences for this kind of thing.
Mine happens to be separating the date part from the rest of the
filename with an underscore, but using a hyphen to separate individual
date components like:

filename_2022-07-12.ext

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

* Re: [PATCH] bugreport: add 'seconds' to default outfile name
  2023-10-15  3:07         ` Jacob Stopak
@ 2023-10-15  3:13           ` Dragan Simic
  0 siblings, 0 replies; 23+ messages in thread
From: Dragan Simic @ 2023-10-15  3:13 UTC (permalink / raw)
  To: Jacob Stopak; +Cc: Junio C Hamano, git

On 2023-10-15 05:07, Jacob Stopak wrote:
> On Sat, Oct 14, 2023 at 07:52:32PM +0200, Dragan Simic wrote:
>> 
>> Speaking in general, I somehow find "20220712" a bit more readable 
>> than
>> "2022-07-12" as part of a filename, but that's of course just my 
>> personal
>> preference.
> 
> It's funny how we all have our own preferences for this kind of thing.
> Mine happens to be separating the date part from the rest of the
> filename with an underscore, but using a hyphen to separate individual
> date components like:
> 
> filename_2022-07-12.ext

Yes, it's quite funny.  I gave it some thought, and I think that my 
preference is a result of dealing with many PDF files containing 
schematics, for which some kind of a defacto standard is the "-20220712" 
naming convention.

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

* [PATCH v2 0/3] bugreport: include +i in outfile suffix as needed
  2023-10-14  4:01 [PATCH] bugreport: add 'seconds' to default outfile name Jacob Stopak
  2023-10-14 10:35 ` Kristoffer Haugsbakk
  2023-10-14 16:27 ` Junio C Hamano
@ 2023-10-15  3:42 ` Jacob Stopak
  2023-10-15  3:42   ` [PATCH v2 1/3] " Jacob Stopak
                     ` (2 more replies)
  2 siblings, 3 replies; 23+ messages in thread
From: Jacob Stopak @ 2023-10-15  3:42 UTC (permalink / raw)
  To: git; +Cc: Jacob Stopak, Junio C Hamano, Dragan Simic, Kristoffer Haugsbakk

Update git bugreport to allow creation of multiple bugreports with
default settings during a given minute interval.

Address several edge cases where users might run git bugreport multiple
times within a minute and expect multiple reports to be created.

Handle these cases by checking to see if a file with the default
timestamped filename already exists, and if so, appending a '+1' value
to the filename suffix. Keep doing so until a unique filename is reached
or '+9' is reached. At this point, if uniqueness is still not found,
the previous error that a file with the given name already exists.

If the --diagnose flag is supplied, apply the same '+i' incremented
filename suffix to the diagnostics zip file.

Reorder the code block that creates the diagnostics zip file so it isn't
created in the event the bugreport itself isn't created due to an error.

Jacob Stopak (3):
  bugreport: include +i in outfile suffix as needed
  bugreport: match diagnostics filename with report
  bugreport: don't create --diagnose zip w/o report

 builtin/bugreport.c | 54 ++++++++++++++++++++++++++++++---------------
 1 file changed, 36 insertions(+), 18 deletions(-)


base-commit: 493f4622739e9b64f24b465b21aa85870dd9dc09
-- 
2.42.0.298.gd89efca819.dirty


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

* [PATCH v2 1/3] bugreport: include +i in outfile suffix as needed
  2023-10-15  3:42 ` [PATCH v2 0/3] bugreport: include +i in outfile suffix as needed Jacob Stopak
@ 2023-10-15  3:42   ` Jacob Stopak
  2023-10-15 17:36     ` Junio C Hamano
  2023-10-16 21:40     ` [PATCH v3 0/1] " Jacob Stopak
  2023-10-15  3:42   ` [PATCH v2 2/3] bugreport: match diagnostics filename with report Jacob Stopak
  2023-10-15  3:42   ` [PATCH v2 3/3] bugreport: don't create --diagnose zip w/o report Jacob Stopak
  2 siblings, 2 replies; 23+ messages in thread
From: Jacob Stopak @ 2023-10-15  3:42 UTC (permalink / raw)
  To: git; +Cc: Jacob Stopak

When the -s flag is absent, git bugreport includes the current hour and
minute values in the default bugreport filename (and diagnostics zip
filename if --diagnose is supplied).

If a user runs the bugreport command more than once within a calendar
minute, a filename conflict with an existing file occurs and the program
errors, since the new output filename was already used for the previous
file. If the user waits anywhere from 1 to 60 seconds (depending on
_when during the calendar minute_ the first command was run) the command
works again with no error since the default filename is now unique, and
multiple bug reports are able to be created with default settings.

This is a minor thing but can cause confusion especially for first time
users of the bugreport command, who are likely to run it multiple times
in quick succession to learn how it works, (like I did).

Add a '+i' into the bugreport filename suffix to make the filename
unique, where 'i' is an integer starting at 1 and able to grow up to 9
in the unlikely event a user runs the command 9 times in a single
minute. This leads to default output filenames like:

git-bugreport-%Y-%m-%d-%H%M+1.txt
git-bugreport-%Y-%m-%d-%H%M+2.txt
...
git-bugreport-%Y-%m-%d-%H%M+9.txt

This means the user will end up with multiple bugreport files being
created if they run the command multiple times quickly, but that feels
more intuitive and consistent than an error arbitrarily occuring within
a calendar minute, especially given that the time window in which the
error currently occurs is variable as described above.

Signed-off-by: Jacob Stopak <jacob@initialcommit.io>
---
 builtin/bugreport.c | 26 +++++++++++++++++++++-----
 1 file changed, 21 insertions(+), 5 deletions(-)

diff --git a/builtin/bugreport.c b/builtin/bugreport.c
index d2ae5c305d..71ee7d7f4b 100644
--- a/builtin/bugreport.c
+++ b/builtin/bugreport.c
@@ -3,7 +3,6 @@
 #include "editor.h"
 #include "gettext.h"
 #include "parse-options.h"
-#include "strbuf.h"
 #include "help.h"
 #include "compat/compiler.h"
 #include "hook.h"
@@ -11,6 +10,7 @@
 #include "diagnose.h"
 #include "object-file.h"
 #include "setup.h"
+#include "dir.h"
 
 static void get_system_info(struct strbuf *sys_info)
 {
@@ -101,12 +101,13 @@ int cmd_bugreport(int argc, const char **argv, const char *prefix)
 {
 	struct strbuf buffer = STRBUF_INIT;
 	struct strbuf report_path = STRBUF_INIT;
+	struct strbuf option_suffix = STRBUF_INIT;
+	struct strbuf default_option_suffix = STRBUF_INIT;
 	int report = -1;
 	time_t now = time(NULL);
 	struct tm tm;
 	enum diagnose_mode diagnose = DIAGNOSE_NONE;
 	char *option_output = NULL;
-	char *option_suffix = "%Y-%m-%d-%H%M";
 	const char *user_relative_path = NULL;
 	char *prefixed_filename;
 	size_t output_path_len;
@@ -118,11 +119,14 @@ int cmd_bugreport(int argc, const char **argv, const char *prefix)
 			       PARSE_OPT_OPTARG, option_parse_diagnose),
 		OPT_STRING('o', "output-directory", &option_output, N_("path"),
 			   N_("specify a destination for the bugreport file(s)")),
-		OPT_STRING('s', "suffix", &option_suffix, N_("format"),
+		OPT_STRING('s', "suffix", &option_suffix.buf, N_("format"),
 			   N_("specify a strftime format suffix for the filename(s)")),
 		OPT_END()
 	};
 
+	strbuf_addstr(&default_option_suffix, "%Y-%m-%d-%H%M");
+	strbuf_addstr(&option_suffix, default_option_suffix.buf);
+
 	argc = parse_options(argc, argv, prefix, bugreport_options,
 			     bugreport_usage, 0);
 
@@ -134,9 +138,20 @@ int cmd_bugreport(int argc, const char **argv, const char *prefix)
 	output_path_len = report_path.len;
 
 	strbuf_addstr(&report_path, "git-bugreport-");
-	strbuf_addftime(&report_path, option_suffix, localtime_r(&now, &tm), 0, 0);
+	strbuf_addftime(&report_path, option_suffix.buf, localtime_r(&now, &tm), 0, 0);
 	strbuf_addstr(&report_path, ".txt");
 
+	if (strbuf_cmp(&option_suffix, &default_option_suffix) == 0) {
+		int i = 1;
+		int pos = report_path.len - 4;
+		while (file_exists(report_path.buf) && i < 10) {
+			if (i > 1)
+				strbuf_remove(&report_path, pos, 2);
+			strbuf_insertf(&report_path, pos, "+%d", i);
+			i++;
+		}
+	}
+
 	switch (safe_create_leading_directories(report_path.buf)) {
 	case SCLD_OK:
 	case SCLD_EXISTS:
@@ -151,7 +166,7 @@ int cmd_bugreport(int argc, const char **argv, const char *prefix)
 		struct strbuf zip_path = STRBUF_INIT;
 		strbuf_add(&zip_path, report_path.buf, output_path_len);
 		strbuf_addstr(&zip_path, "git-diagnostics-");
-		strbuf_addftime(&zip_path, option_suffix, localtime_r(&now, &tm), 0, 0);
+		strbuf_addftime(&zip_path, option_suffix.buf, localtime_r(&now, &tm), 0, 0);
 		strbuf_addstr(&zip_path, ".zip");
 
 		if (create_diagnostics_archive(&zip_path, diagnose))
@@ -188,6 +203,7 @@ int cmd_bugreport(int argc, const char **argv, const char *prefix)
 
 	free(prefixed_filename);
 	strbuf_release(&buffer);
+	strbuf_release(&default_option_suffix);
 
 	ret = !!launch_editor(report_path.buf, NULL, NULL);
 	strbuf_release(&report_path);
-- 
2.42.0.298.gd89efca819.dirty


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

* [PATCH v2 2/3] bugreport: match diagnostics filename with report
  2023-10-15  3:42 ` [PATCH v2 0/3] bugreport: include +i in outfile suffix as needed Jacob Stopak
  2023-10-15  3:42   ` [PATCH v2 1/3] " Jacob Stopak
@ 2023-10-15  3:42   ` Jacob Stopak
  2023-10-15  3:42   ` [PATCH v2 3/3] bugreport: don't create --diagnose zip w/o report Jacob Stopak
  2 siblings, 0 replies; 23+ messages in thread
From: Jacob Stopak @ 2023-10-15  3:42 UTC (permalink / raw)
  To: git; +Cc: Jacob Stopak

When using the --diagnose flag, match the diagnostics zip filename with
the bugreport filename in the scenario where '+i' syntax is used.

Signed-off-by: Jacob Stopak <jacob@initialcommit.io>
---
 builtin/bugreport.c | 3 ++-
 1 file changed, 2 insertions(+), 1 deletion(-)

diff --git a/builtin/bugreport.c b/builtin/bugreport.c
index 71ee7d7f4b..573d270677 100644
--- a/builtin/bugreport.c
+++ b/builtin/bugreport.c
@@ -112,6 +112,7 @@ int cmd_bugreport(int argc, const char **argv, const char *prefix)
 	char *prefixed_filename;
 	size_t output_path_len;
 	int ret;
+	int i = 1;
 
 	const struct option bugreport_options[] = {
 		OPT_CALLBACK_F(0, "diagnose", &diagnose, N_("mode"),
@@ -142,7 +143,6 @@ int cmd_bugreport(int argc, const char **argv, const char *prefix)
 	strbuf_addstr(&report_path, ".txt");
 
 	if (strbuf_cmp(&option_suffix, &default_option_suffix) == 0) {
-		int i = 1;
 		int pos = report_path.len - 4;
 		while (file_exists(report_path.buf) && i < 10) {
 			if (i > 1)
@@ -167,6 +167,7 @@ int cmd_bugreport(int argc, const char **argv, const char *prefix)
 		strbuf_add(&zip_path, report_path.buf, output_path_len);
 		strbuf_addstr(&zip_path, "git-diagnostics-");
 		strbuf_addftime(&zip_path, option_suffix.buf, localtime_r(&now, &tm), 0, 0);
+		if (i > 1) strbuf_addf(&zip_path, "+%d", i-1);
 		strbuf_addstr(&zip_path, ".zip");
 
 		if (create_diagnostics_archive(&zip_path, diagnose))
-- 
2.42.0.298.gd89efca819.dirty


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

* [PATCH v2 3/3] bugreport: don't create --diagnose zip w/o report
  2023-10-15  3:42 ` [PATCH v2 0/3] bugreport: include +i in outfile suffix as needed Jacob Stopak
  2023-10-15  3:42   ` [PATCH v2 1/3] " Jacob Stopak
  2023-10-15  3:42   ` [PATCH v2 2/3] bugreport: match diagnostics filename with report Jacob Stopak
@ 2023-10-15  3:42   ` Jacob Stopak
  2 siblings, 0 replies; 23+ messages in thread
From: Jacob Stopak @ 2023-10-15  3:42 UTC (permalink / raw)
  To: git; +Cc: Jacob Stopak

Prevent the diagnostics zip file from being created when the bugreport
itself is not created due to an error.

Signed-off-by: Jacob Stopak <jacob@initialcommit.io>
---
 builtin/bugreport.c | 31 ++++++++++++++++---------------
 1 file changed, 16 insertions(+), 15 deletions(-)

diff --git a/builtin/bugreport.c b/builtin/bugreport.c
index 573d270677..91567806c9 100644
--- a/builtin/bugreport.c
+++ b/builtin/bugreport.c
@@ -161,21 +161,6 @@ int cmd_bugreport(int argc, const char **argv, const char *prefix)
 		    report_path.buf);
 	}
 
-	/* Prepare diagnostics, if requested */
-	if (diagnose != DIAGNOSE_NONE) {
-		struct strbuf zip_path = STRBUF_INIT;
-		strbuf_add(&zip_path, report_path.buf, output_path_len);
-		strbuf_addstr(&zip_path, "git-diagnostics-");
-		strbuf_addftime(&zip_path, option_suffix.buf, localtime_r(&now, &tm), 0, 0);
-		if (i > 1) strbuf_addf(&zip_path, "+%d", i-1);
-		strbuf_addstr(&zip_path, ".zip");
-
-		if (create_diagnostics_archive(&zip_path, diagnose))
-			die_errno(_("unable to create diagnostics archive %s"), zip_path.buf);
-
-		strbuf_release(&zip_path);
-	}
-
 	/* Prepare the report contents */
 	get_bug_template(&buffer);
 
@@ -202,6 +187,22 @@ int cmd_bugreport(int argc, const char **argv, const char *prefix)
 	fprintf(stderr, _("Created new report at '%s'.\n"),
 		user_relative_path);
 
+	/* Prepare diagnostics, if requested */
+	if (diagnose != DIAGNOSE_NONE) {
+		struct strbuf zip_path = STRBUF_INIT;
+		strbuf_add(&zip_path, report_path.buf, output_path_len);
+		strbuf_addstr(&zip_path, "git-diagnostics-");
+		strbuf_addftime(&zip_path, option_suffix.buf, localtime_r(&now, &tm), 0, 0);
+		if (i > 1) strbuf_addf(&zip_path, "+%d", i-1);
+		strbuf_addstr(&zip_path, ".zip");
+
+		if (create_diagnostics_archive(&zip_path, diagnose))
+			die_errno(_("unable to create diagnostics archive %s"), zip_path.buf);
+
+		strbuf_release(&zip_path);
+	}
+
+
 	free(prefixed_filename);
 	strbuf_release(&buffer);
 	strbuf_release(&default_option_suffix);
-- 
2.42.0.298.gd89efca819.dirty


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

* Re: [PATCH] bugreport: add 'seconds' to default outfile name
  2023-10-15  3:01   ` Jacob Stopak
@ 2023-10-15 17:06     ` Junio C Hamano
  0 siblings, 0 replies; 23+ messages in thread
From: Junio C Hamano @ 2023-10-15 17:06 UTC (permalink / raw)
  To: Jacob Stopak; +Cc: git

Jacob Stopak <jacob@initialcommit.io> writes:

> Lol! By saying "calendar" I mean "falling on the official boundaries
> of", like 11:15:00 - 11:16:00. Unlike the time between 11:15:30 -
> 11:16:30 which is also a minute, but it's not a "calendar" minute
> because it overlaps into the next minute. I guess in this case it's more
> of a "clock" minute than a "calendar" minute though ':D... I guess
> "calendar" terminology is used more for months/years...

People use "calendar" days usually in order to to differenciate it
with "business" days.  It may take your package to come cross
country and take 5 business days, but if you ship it out on Friday,
it will not arrive by Wednesday.

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

* Re: [PATCH v2 1/3] bugreport: include +i in outfile suffix as needed
  2023-10-15  3:42   ` [PATCH v2 1/3] " Jacob Stopak
@ 2023-10-15 17:36     ` Junio C Hamano
  2023-10-16 21:40     ` [PATCH v3 0/1] " Jacob Stopak
  1 sibling, 0 replies; 23+ messages in thread
From: Junio C Hamano @ 2023-10-15 17:36 UTC (permalink / raw)
  To: Jacob Stopak; +Cc: git

Jacob Stopak <jacob@initialcommit.io> writes:

> When the -s flag is absent, git bugreport includes the current hour and
> minute values in the default bugreport filename (and diagnostics zip
> filename if --diagnose is supplied).
>
> If a user runs the bugreport command more than once within a calendar
> minute, a filename conflict with an existing file occurs and the program
> errors, since the new output filename was already used for the previous
> file. If the user waits anywhere from 1 to 60 seconds (depending on
> _when during the calendar minute_ the first command was run) the command

Drop "calendar" here (see below).  "If the user waits from running
the command within the same minute" may be easier to understand than
"from 1 to 60 seconds"; after all, the user does not have to wait
for more than 0.5 seconds if the previous attempt was within 0.5
seconds from the minute boundary.

> works again with no error since the default filename is now unique, and
> multiple bug reports are able to be created with default settings.
>
> This is a minor thing but can cause confusion especially for first time
> users of the bugreport command, who are likely to run it multiple times
> in quick succession to learn how it works, (like I did).

Perhaps we should refine the error message we give in this case and
we are done, then?

$ GIT_EDITOR=: git bugreport ; GIT_EDITOR=: git bugreport
Created new report at 'git-bugreport-2023-10-15-1008.txt'.
fatal: unable to create 'git-bugreport-2023-10-15-1008.txt': File exists

The second message can be a bit more friendly and suggest removing
the stale file.

> Add a '+i' into the bugreport filename suffix to make the filename
> unique, where 'i' is an integer starting at 1 and able to grow up to 9
> in the unlikely event a user runs the command 9 times in a single
> minute. This leads to default output filenames like:

What downside do you see in using 2023-10-15-1008+10 after you tried
9 of them?  The code to limit the upper bound smells like a wasted
effort that helps nobody in practice because it is "unlikely".

And limiting the upper bound also means you now have to have extra
code to deal with "we ran out---error out and help the user how to
recover" anyway.

Notice that you said "in a single minute" without "calendar" and the
sentence is perfectly understandable? (see above and below).

> This means the user will end up with multiple bugreport files being
> created if they run the command multiple times quickly, but that feels
> more intuitive and consistent than an error arbitrarily occuring within
> a calendar minute, especially given that the time window in which the
> error currently occurs is variable as described above.

And drop "calendar" here, too (see above).
"Within the same minute" is fine.

> @@ -3,7 +3,6 @@
>  #include "editor.h"
>  #include "gettext.h"
>  #include "parse-options.h"
> -#include "strbuf.h"

Looks like an unrelated change here.  The updated code does use
strbuf service, so even if other header files happen to include
it, keep including it here is a good discipline for readability.

> @@ -101,12 +101,13 @@ int cmd_bugreport(int argc, const char **argv, const char *prefix)
>  {
>  	struct strbuf buffer = STRBUF_INIT;
>  	struct strbuf report_path = STRBUF_INIT;
> +	struct strbuf option_suffix = STRBUF_INIT;
> +	struct strbuf default_option_suffix = STRBUF_INIT;
>  	int report = -1;
>  	time_t now = time(NULL);
>  	struct tm tm;
>  	enum diagnose_mode diagnose = DIAGNOSE_NONE;
>  	char *option_output = NULL;
> -	char *option_suffix = "%Y-%m-%d-%H%M";
>  	const char *user_relative_path = NULL;
>  	char *prefixed_filename;
>  	size_t output_path_len;
> @@ -118,11 +119,14 @@ int cmd_bugreport(int argc, const char **argv, const char *prefix)
>  			       PARSE_OPT_OPTARG, option_parse_diagnose),
>  		OPT_STRING('o', "output-directory", &option_output, N_("path"),
>  			   N_("specify a destination for the bugreport file(s)")),
> -		OPT_STRING('s', "suffix", &option_suffix, N_("format"),
> +		OPT_STRING('s', "suffix", &option_suffix.buf, N_("format"),
>  			   N_("specify a strftime format suffix for the filename(s)")),
>  		OPT_END()
>  	};
>  
> +	strbuf_addstr(&default_option_suffix, "%Y-%m-%d-%H%M");
> +	strbuf_addstr(&option_suffix, default_option_suffix.buf);

It usually pays for a reviewer when two variables, one called
default and the other not, gets initialized to the same value,
because it is a sign that there is something fishy going on.  A more
normal pattern is to set up the default, do whatever is needed and
if the non-default one has not been touched, then copy that default
value to the real one, and the code needed deviation from it for
whatever reason.  Let's read on.

> @@ -134,9 +138,20 @@ int cmd_bugreport(int argc, const char **argv, const char *prefix)
>  	output_path_len = report_path.len;
>  
>  	strbuf_addstr(&report_path, "git-bugreport-");
> -	strbuf_addftime(&report_path, option_suffix, localtime_r(&now, &tm), 0, 0);
> +	strbuf_addftime(&report_path, option_suffix.buf, localtime_r(&now, &tm), 0, 0);
>  	strbuf_addstr(&report_path, ".txt");

OK.

> +	if (strbuf_cmp(&option_suffix, &default_option_suffix) == 0) {

Style: never compare with 0 or NULL inside a conditional.

	if (!compare(...)) {

is the idiom to use.

You may have written it this way to avoid appending after what the
user gave you as a custom pattern, but this if() statement is a
failed way to do so.  The user can give what happens to be the same
as the hardcoded default pattern and you cannot tell if it came from
them or your initially hardcoded one by string comparison.

> +		int i = 1;
> +		int pos = report_path.len - 4;

Totally unclear where the magic "4" comes from.

> +		while (file_exists(report_path.buf) && i < 10) {
> +			if (i > 1)
> +				strbuf_remove(&report_path, pos, 2);
> +			strbuf_insertf(&report_path, pos, "+%d", i);
> +			i++;
> +		}
> +	}

We see TOCTOU here.

Do it more like this instead.

    * Discard default_option_suffix variable.

    * Introduce a boolean option_suffix_is_from_user and
      initialize it to false.

    * Initialize option_suffix to an empty string.

    * After parse_options() returns, if option_suffix is still
      empty, then add the default pattern.  Otherwise toggle
      option_suffix_is_from_user true.

    * Prepare the code so that you can recompute report_path as you
      need to increment the suffix added to option_suffix.

Then where we do xopen() on report_path.buf, have a fallback loop,
and you can do something like

    again:
	report = open(report_path.buf, O_CREAT | O_EXCL | O_WRONLY, 0666);
	if (report < 0 && errno == EEXISTS && !option_suffix_is_from_user) {
		increment_suffix(&report_path);
		goto again;
	} else if (report < 0) {
		die_errno(_("unable to open '%s'", report_path.buf));
	}

to avoid TOCTOU.

HTH.

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

* [PATCH v3 0/1] bugreport: include +i in outfile suffix as needed
  2023-10-15  3:42   ` [PATCH v2 1/3] " Jacob Stopak
  2023-10-15 17:36     ` Junio C Hamano
@ 2023-10-16 21:40     ` Jacob Stopak
  2023-10-16 21:40       ` [PATCH v3 1/1] " Jacob Stopak
  1 sibling, 1 reply; 23+ messages in thread
From: Jacob Stopak @ 2023-10-16 21:40 UTC (permalink / raw)
  To: git; +Cc: Jacob Stopak, Junio C Hamano

Similar functionality to the previous patch version but with the
following changes:

  * Remove the default_option_suffix variable and clean up the way the
    option_suffix value is set.

  * Refactor code for building report path and diagnostics zip file path
    into the new function build_path(...), which builds a fresh path
    from scratch each time it's called. Although it does take quite a few
    arguments, it reduces duplicated code and simplifies the code by
    removing the need for splicing or inserting the incrementable suffix.

  * Allow the increment value 'i' to grow as needed instead of stopping
    at 9.

  * Replace xopen() with open() so that the program doesn't die with an
    error if the file already exists.

  * Replace the while loop with a fallback loop to prevent TOCTOU.

  * Clean up commit message verbiage.

Some additional comments:

> Perhaps we should refine the error message we give in this case and
> we are done, then?

I had thought about this but due to the variable timed behavior I had
trouble coming up with a message that would convey clearly what's going
on and what the user should do. Here were some things that popped into
my head but they all sounded a bit silly to me:

"A bugreport with this name already exists, try again shortly"
or
"File exists: wait 1 minute and try again or use a custom suffix with -s"
or
"File exists: try again in 1 to 60 seconds :-P"

I think the reason they sound silly to me is that the user is only being
made aware of this info because the program happens to be operating this
way - instead of the program working in a smoother way where this type of
operational info wouldn't need to be conveyed.

> What downside do you see in using 2023-10-15-1008+10 after you tried
> 9 of them?  The code to limit the upper bound smells like a wasted
> effort that helps nobody in practice because it is "unlikely".

> And limiting the upper bound also means you now have to have extra
> code to deal with "we ran out---error out and help the user how to
> recover" anyway.

I completely agree with this and made these updates.

> Notice that you said "in a single minute" without "calendar" and the
> sentence is perfectly understandable?

I googled "calendar minute" and the only thing that came up was some
Java documentation... So I guess I just made it up... :'D

Jacob Stopak (1):
  bugreport: include +i in outfile suffix as needed

 builtin/bugreport.c | 83 +++++++++++++++++++++++++++++++--------------
 1 file changed, 57 insertions(+), 26 deletions(-)


base-commit: 493f4622739e9b64f24b465b21aa85870dd9dc09
-- 
2.42.0.297.g36452639b8


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

* [PATCH v3 1/1] bugreport: include +i in outfile suffix as needed
  2023-10-16 21:40     ` [PATCH v3 0/1] " Jacob Stopak
@ 2023-10-16 21:40       ` Jacob Stopak
  2023-10-16 22:55         ` Junio C Hamano
                           ` (2 more replies)
  0 siblings, 3 replies; 23+ messages in thread
From: Jacob Stopak @ 2023-10-16 21:40 UTC (permalink / raw)
  To: git; +Cc: Jacob Stopak

When the -s flag is absent, git bugreport includes the current hour and
minute values in the default bugreport filename (and diagnostics zip
filename if --diagnose is supplied).

If a user runs the bugreport command more than once within a minute, a
filename conflict with an existing file occurs and the program errors,
since the new output filename was already used for the previous file. If
the user waits anywhere from 1 to 60 seconds (depending on when during
the minute the first command was run) the command works again with no
error since the default filename is now unique, and multiple bug reports
are able to be created with default settings.

This is a minor thing but can cause confusion for first time users of
the bugreport command, who are likely to run it multiple times in quick
succession to learn how it works, (like I did). Or users who quickly
fill in a few details before closing and creating a new one.

Add a '+i' into the bugreport filename suffix where 'i' is an integer
starting at 1 and growing as needed until a unique filename is obtained.

This leads to default output filenames like:

git-bugreport-%Y-%m-%d-%H%M+1.txt
git-bugreport-%Y-%m-%d-%H%M+2.txt
...
git-bugreport-%Y-%m-%d-%H%M+i.txt

This means the user will end up with multiple bugreport files being
created if they run the command multiple times quickly, but that feels
more intuitive and consistent than an error arbitrarily occuring within
a minute, especially given that the time window in which the error
currently occurs is variable as described above.

If --diagnose is supplied, match the incremented suffix of the
diagnostics zip file to the bugreport.

Signed-off-by: Jacob Stopak <jacob@initialcommit.io>
---
 builtin/bugreport.c | 83 +++++++++++++++++++++++++++++++--------------
 1 file changed, 57 insertions(+), 26 deletions(-)

diff --git a/builtin/bugreport.c b/builtin/bugreport.c
index d2ae5c305d..ed65735873 100644
--- a/builtin/bugreport.c
+++ b/builtin/bugreport.c
@@ -11,6 +11,7 @@
 #include "diagnose.h"
 #include "object-file.h"
 #include "setup.h"
+#include "dir.h"
 
 static void get_system_info(struct strbuf *sys_info)
 {
@@ -97,20 +98,41 @@ static void get_header(struct strbuf *buf, const char *title)
 	strbuf_addf(buf, "\n\n[%s]\n", title);
 }
 
+static void build_path(struct strbuf *buf, const char *dir_path,
+		       const char *prefix, const char *suffix,
+		       time_t t, int *i, const char *ext)
+{
+	struct tm tm;
+
+	strbuf_reset(buf);
+	strbuf_addstr(buf, dir_path);
+	strbuf_complete(buf, '/');
+
+	strbuf_addstr(buf, prefix);
+	strbuf_addftime(buf, suffix, localtime_r(&t, &tm), 0, 0);
+
+	if (*i > 0)
+		strbuf_addf(buf, "+%d", *i);
+
+	strbuf_addstr(buf, ext);
+
+	(*i)++;
+}
+
 int cmd_bugreport(int argc, const char **argv, const char *prefix)
 {
 	struct strbuf buffer = STRBUF_INIT;
 	struct strbuf report_path = STRBUF_INIT;
 	int report = -1;
 	time_t now = time(NULL);
-	struct tm tm;
 	enum diagnose_mode diagnose = DIAGNOSE_NONE;
 	char *option_output = NULL;
-	char *option_suffix = "%Y-%m-%d-%H%M";
+	char *option_suffix = "";
+	int option_suffix_is_from_user = 0;
 	const char *user_relative_path = NULL;
 	char *prefixed_filename;
-	size_t output_path_len;
 	int ret;
+	int i = 0;
 
 	const struct option bugreport_options[] = {
 		OPT_CALLBACK_F(0, "diagnose", &diagnose, N_("mode"),
@@ -126,16 +148,16 @@ int cmd_bugreport(int argc, const char **argv, const char *prefix)
 	argc = parse_options(argc, argv, prefix, bugreport_options,
 			     bugreport_usage, 0);
 
+	if (!strlen(option_suffix))
+		option_suffix = "%Y-%m-%d-%H%M";
+	else
+		option_suffix_is_from_user = 1;
+
 	/* Prepare the path to put the result */
 	prefixed_filename = prefix_filename(prefix,
 					    option_output ? option_output : "");
-	strbuf_addstr(&report_path, prefixed_filename);
-	strbuf_complete(&report_path, '/');
-	output_path_len = report_path.len;
-
-	strbuf_addstr(&report_path, "git-bugreport-");
-	strbuf_addftime(&report_path, option_suffix, localtime_r(&now, &tm), 0, 0);
-	strbuf_addstr(&report_path, ".txt");
+	build_path(&report_path, prefixed_filename, "git-bugreport-",
+		   option_suffix, now, &i, ".txt");
 
 	switch (safe_create_leading_directories(report_path.buf)) {
 	case SCLD_OK:
@@ -146,20 +168,6 @@ int cmd_bugreport(int argc, const char **argv, const char *prefix)
 		    report_path.buf);
 	}
 
-	/* Prepare diagnostics, if requested */
-	if (diagnose != DIAGNOSE_NONE) {
-		struct strbuf zip_path = STRBUF_INIT;
-		strbuf_add(&zip_path, report_path.buf, output_path_len);
-		strbuf_addstr(&zip_path, "git-diagnostics-");
-		strbuf_addftime(&zip_path, option_suffix, localtime_r(&now, &tm), 0, 0);
-		strbuf_addstr(&zip_path, ".zip");
-
-		if (create_diagnostics_archive(&zip_path, diagnose))
-			die_errno(_("unable to create diagnostics archive %s"), zip_path.buf);
-
-		strbuf_release(&zip_path);
-	}
-
 	/* Prepare the report contents */
 	get_bug_template(&buffer);
 
@@ -169,14 +177,37 @@ int cmd_bugreport(int argc, const char **argv, const char *prefix)
 	get_header(&buffer, _("Enabled Hooks"));
 	get_populated_hooks(&buffer, !startup_info->have_repository);
 
-	/* fopen doesn't offer us an O_EXCL alternative, except with glibc. */
-	report = xopen(report_path.buf, O_CREAT | O_EXCL | O_WRONLY, 0666);
+	again:
+		/* fopen doesn't offer us an O_EXCL alternative, except with glibc. */
+		report = open(report_path.buf, O_CREAT | O_EXCL | O_WRONLY, 0666);
+		if (report < 0 && errno == EEXIST && !option_suffix_is_from_user) {
+			build_path(&report_path, prefixed_filename,
+				   "git-bugreport-", option_suffix, now, &i,
+				   ".txt");
+			goto again;
+		} else if (report < 0) {
+			die_errno(_("unable to open '%s'"), report_path.buf);
+		}
 
 	if (write_in_full(report, buffer.buf, buffer.len) < 0)
 		die_errno(_("unable to write to %s"), report_path.buf);
 
 	close(report);
 
+	/* Prepare diagnostics, if requested */
+	if (diagnose != DIAGNOSE_NONE) {
+		struct strbuf zip_path = STRBUF_INIT;
+		i--; /* Undo last increment to match zipfile suffix to bugreport */
+		build_path(&zip_path, prefixed_filename, "git-diagnostics-",
+			   option_suffix, now, &i, ".zip");
+
+		if (create_diagnostics_archive(&zip_path, diagnose))
+			die_errno(_("unable to create diagnostics archive %s"),
+				  zip_path.buf);
+
+		strbuf_release(&zip_path);
+	}
+
 	/*
 	 * We want to print the path relative to the user, but we still need the
 	 * path relative to us to give to the editor.
-- 
2.42.0.297.g36452639b8


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

* Re: [PATCH v3 1/1] bugreport: include +i in outfile suffix as needed
  2023-10-16 21:40       ` [PATCH v3 1/1] " Jacob Stopak
@ 2023-10-16 22:55         ` Junio C Hamano
  2023-10-17  3:17           ` Jacob Stopak
  2023-10-21  0:39         ` Junio C Hamano
  2023-10-26 21:19         ` Emily Shaffer
  2 siblings, 1 reply; 23+ messages in thread
From: Junio C Hamano @ 2023-10-16 22:55 UTC (permalink / raw)
  To: Jacob Stopak; +Cc: git

Jacob Stopak <jacob@initialcommit.io> writes:

>  builtin/bugreport.c | 83 +++++++++++++++++++++++++++++++--------------
>  1 file changed, 57 insertions(+), 26 deletions(-)

Looking good.  It is not easy to do an automated and reliable test
for this one for obvious reasons ;-), so let's queue it as-is.

Thanks.

> -	/* fopen doesn't offer us an O_EXCL alternative, except with glibc. */
> -	report = xopen(report_path.buf, O_CREAT | O_EXCL | O_WRONLY, 0666);
> +	again:
> +		/* fopen doesn't offer us an O_EXCL alternative, except with glibc. */
> +		report = open(report_path.buf, O_CREAT | O_EXCL | O_WRONLY, 0666);
> +		if (report < 0 && errno == EEXIST && !option_suffix_is_from_user) {
> +			build_path(&report_path, prefixed_filename,
> +				   "git-bugreport-", option_suffix, now, &i,
> +				   ".txt");
> +			goto again;
> +		} else if (report < 0) {
> +			die_errno(_("unable to open '%s'"), report_path.buf);
> +		}

I didn't expect a rewrite to add an extra level of indentation like
this, though ;-).

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

* Re: [PATCH v3 1/1] bugreport: include +i in outfile suffix as needed
  2023-10-16 22:55         ` Junio C Hamano
@ 2023-10-17  3:17           ` Jacob Stopak
  0 siblings, 0 replies; 23+ messages in thread
From: Jacob Stopak @ 2023-10-17  3:17 UTC (permalink / raw)
  To: Junio C Hamano; +Cc: git

On Mon, Oct 16, 2023 at 03:55:50PM -0700, Junio C Hamano wrote:
> Jacob Stopak <jacob@initialcommit.io> writes:
> 
> >  builtin/bugreport.c | 83 +++++++++++++++++++++++++++++++--------------
> >  1 file changed, 57 insertions(+), 26 deletions(-)
> 
> Looking good.  It is not easy to do an automated and reliable test
> for this one for obvious reasons ;-), so let's queue it as-is.
> 
> Thanks.
> 

Awesome! Thank you!

> > -	/* fopen doesn't offer us an O_EXCL alternative, except with glibc. */
> > -	report = xopen(report_path.buf, O_CREAT | O_EXCL | O_WRONLY, 0666);
> > +	again:
> > +		/* fopen doesn't offer us an O_EXCL alternative, except with glibc. */
> > +		report = open(report_path.buf, O_CREAT | O_EXCL | O_WRONLY, 0666);
> > +		if (report < 0 && errno == EEXIST && !option_suffix_is_from_user) {
> > +			build_path(&report_path, prefixed_filename,
> > +				   "git-bugreport-", option_suffix, now, &i,
> > +				   ".txt");
> > +			goto again;
> > +		} else if (report < 0) {
> > +			die_errno(_("unable to open '%s'"), report_path.buf);
> > +		}
> 
> I didn't expect a rewrite to add an extra level of indentation like
> this, though ;-).

Whoops... I looked in another file to check the indentation around a
goto label and misread how it should be. Let me know if I should submit
v4 with that corrected.

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

* Re: [PATCH v3 1/1] bugreport: include +i in outfile suffix as needed
  2023-10-16 21:40       ` [PATCH v3 1/1] " Jacob Stopak
  2023-10-16 22:55         ` Junio C Hamano
@ 2023-10-21  0:39         ` Junio C Hamano
  2023-10-26 21:19         ` Emily Shaffer
  2 siblings, 0 replies; 23+ messages in thread
From: Junio C Hamano @ 2023-10-21  0:39 UTC (permalink / raw)
  To: Jacob Stopak, Emily Shaffer; +Cc: git

Jacob Stopak <jacob@initialcommit.io> writes:

>  int cmd_bugreport(int argc, const char **argv, const char *prefix)
>  {
>  	struct strbuf buffer = STRBUF_INIT;
>  	struct strbuf report_path = STRBUF_INIT;
>  	int report = -1;
>  	time_t now = time(NULL);
> -	struct tm tm;
>  	enum diagnose_mode diagnose = DIAGNOSE_NONE;
>  	char *option_output = NULL;
> -	char *option_suffix = "%Y-%m-%d-%H%M";
> +	char *option_suffix = "";
> +	int option_suffix_is_from_user = 0;
>  	const char *user_relative_path = NULL;
>  	char *prefixed_filename;
> -	size_t output_path_len;
>  	int ret;
> +	int i = 0;

OK, I think between me and you, we stared at this piece of code long
enough to make ourselves numb.  The original "at most one report per
a minute" default came from the very original in 238b439d
(bugreport: add tool to generate debugging info, 2020-04-16) and
that is what we are changing, so let me summon its author as an area
expert for a pair of fresh eyes to see if they can offer any new
insights.

Thanks.

https://lore.kernel.org/git/20231016214045.146862-1-jacob@initialcommit.io/

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

* Re: [PATCH v3 1/1] bugreport: include +i in outfile suffix as needed
  2023-10-16 21:40       ` [PATCH v3 1/1] " Jacob Stopak
  2023-10-16 22:55         ` Junio C Hamano
  2023-10-21  0:39         ` Junio C Hamano
@ 2023-10-26 21:19         ` Emily Shaffer
  2023-10-27  6:34           ` Jacob Stopak
  2 siblings, 1 reply; 23+ messages in thread
From: Emily Shaffer @ 2023-10-26 21:19 UTC (permalink / raw)
  To: Jacob Stopak; +Cc: git

Thanks Jack for drawing my attention to the summoning, and sorry for
delay.

On Mon, Oct 16, 2023 at 02:40:45PM -0700, Jacob Stopak wrote:
> 
> When the -s flag is absent, git bugreport includes the current hour and
> minute values in the default bugreport filename (and diagnostics zip
> filename if --diagnose is supplied).
> 
> If a user runs the bugreport command more than once within a minute, a
> filename conflict with an existing file occurs and the program errors,
> since the new output filename was already used for the previous file. If
> the user waits anywhere from 1 to 60 seconds (depending on when during
> the minute the first command was run) the command works again with no
> error since the default filename is now unique, and multiple bug reports
> are able to be created with default settings.
> 
> This is a minor thing but can cause confusion for first time users of
> the bugreport command, who are likely to run it multiple times in quick
> succession to learn how it works, (like I did). Or users who quickly
> fill in a few details before closing and creating a new one.

Sure, agreed - I guess I got in the habit of testing by running `rm
git-bugreport*.txt && git bugreport --foo` and never thought about this
being annoying for an actual reporter :)

> 
> Add a '+i' into the bugreport filename suffix where 'i' is an integer
> starting at 1 and growing as needed until a unique filename is obtained.
> 
> This leads to default output filenames like:
> 
> git-bugreport-%Y-%m-%d-%H%M+1.txt
> git-bugreport-%Y-%m-%d-%H%M+2.txt
> ...
> git-bugreport-%Y-%m-%d-%H%M+i.txt
> 
> This means the user will end up with multiple bugreport files being
> created if they run the command multiple times quickly, but that feels
> more intuitive and consistent than an error arbitrarily occuring within
> a minute, especially given that the time window in which the error
> currently occurs is variable as described above.

Sure, and with the monotonic increases it's quite easy to locate the
bugreport that's the final one the user generated. This scheme seems
fine to me.

> 
> If --diagnose is supplied, match the incremented suffix of the
> diagnostics zip file to the bugreport.

Nice.

> 
> Signed-off-by: Jacob Stopak <jacob@initialcommit.io>
> ---
>  builtin/bugreport.c | 83 +++++++++++++++++++++++++++++++--------------
>  1 file changed, 57 insertions(+), 26 deletions(-)
> 
> diff --git a/builtin/bugreport.c b/builtin/bugreport.c
> index d2ae5c305d..ed65735873 100644
> --- a/builtin/bugreport.c
> +++ b/builtin/bugreport.c
> @@ -11,6 +11,7 @@
>  #include "diagnose.h"
>  #include "object-file.h"
>  #include "setup.h"
> +#include "dir.h"
>  
>  static void get_system_info(struct strbuf *sys_info)
>  {
> @@ -97,20 +98,41 @@ static void get_header(struct strbuf *buf, const char *title)
>  	strbuf_addf(buf, "\n\n[%s]\n", title);
>  }
>  
> +static void build_path(struct strbuf *buf, const char *dir_path,
> +		       const char *prefix, const char *suffix,
> +		       time_t t, int *i, const char *ext)
> +{
> +	struct tm tm;
> +
> +	strbuf_reset(buf);
> +	strbuf_addstr(buf, dir_path);
> +	strbuf_complete(buf, '/');
> +
> +	strbuf_addstr(buf, prefix);
> +	strbuf_addftime(buf, suffix, localtime_r(&t, &tm), 0, 0);
> +
> +	if (*i > 0)
> +		strbuf_addf(buf, "+%d", *i);
> +
> +	strbuf_addstr(buf, ext);
> +
> +	(*i)++;
> +}

I commented on the weirdness of having to decrement i for --diagnose
below, but I think I generally just wish that instead of build_path()
this function did create_file_with_optional_suffix() and returned the
final modified option_suffix(). Better still would be if this function
created (or at least tested) all the necessary output paths so you don't
end up succeeding in creating a bugreport.txt but failing in creating
the diagnostics.zip in some edge case, something like....

build_suffix(..., &option_suffix) {
  ... build timestamp ...
  while (...)
    for (final_path in eventual_paths) {
    	err = select(final_path);
	if (err)
	  final_path = strcat(most_of_path, i)
	else
	  break
(Yeah, that's very handwavey, but I hope you see what I'm getting at.)

Really, though, I mostly don't think I like leaving the control variable i raw
to the calling scope and making it be manipulated later. Fancy
pre-guessing-path-availability aside, I think you could achieve a more
pleasant solution even by letting build_path() become
create_file_with_optional_suffix() (that reports the optional suffix
eventually settled on).

> +
>  int cmd_bugreport(int argc, const char **argv, const char *prefix)
>  {
>  	struct strbuf buffer = STRBUF_INIT;
>  	struct strbuf report_path = STRBUF_INIT;
>  	int report = -1;
>  	time_t now = time(NULL);
> -	struct tm tm;
>  	enum diagnose_mode diagnose = DIAGNOSE_NONE;
>  	char *option_output = NULL;
> -	char *option_suffix = "%Y-%m-%d-%H%M";
> +	char *option_suffix = "";
> +	int option_suffix_is_from_user = 0;
>  	const char *user_relative_path = NULL;
>  	char *prefixed_filename;
> -	size_t output_path_len;
>  	int ret;
> +	int i = 0;
>  
>  	const struct option bugreport_options[] = {
>  		OPT_CALLBACK_F(0, "diagnose", &diagnose, N_("mode"),
> @@ -126,16 +148,16 @@ int cmd_bugreport(int argc, const char **argv, const char *prefix)
>  	argc = parse_options(argc, argv, prefix, bugreport_options,
>  			     bugreport_usage, 0);
>  
> +	if (!strlen(option_suffix))
> +		option_suffix = "%Y-%m-%d-%H%M";
> +	else
> +		option_suffix_is_from_user = 1;

Looking at where this is used, it looks like you're saying "if the user
specified the suffix manually and has this problem, then that sucks for
them, they put their own foot in it". But I don't know if I necessarily
follow that logic - I'd just as soon drop the exception, append an int
to the user-provided suffix, and document that we'll do that in the
manpage.

(This isn't something I feel strongly about, except that I think it
makes the code harder to follow for not very notable user benefit. I
also didn't look through the reviews up until now, so if this was
already hashed back and forth, just go ahead and ignore me.)

> +
>  	/* Prepare the path to put the result */
>  	prefixed_filename = prefix_filename(prefix,
>  					    option_output ? option_output : "");
> -	strbuf_addstr(&report_path, prefixed_filename);
> -	strbuf_complete(&report_path, '/');
> -	output_path_len = report_path.len;
> -
> -	strbuf_addstr(&report_path, "git-bugreport-");
> -	strbuf_addftime(&report_path, option_suffix, localtime_r(&now, &tm), 0, 0);
> -	strbuf_addstr(&report_path, ".txt");
> +	build_path(&report_path, prefixed_filename, "git-bugreport-",
> +		   option_suffix, now, &i, ".txt");
>  
>  	switch (safe_create_leading_directories(report_path.buf)) {
>  	case SCLD_OK:
> @@ -146,20 +168,6 @@ int cmd_bugreport(int argc, const char **argv, const char *prefix)
>  		    report_path.buf);
>  	}
>  
> -	/* Prepare diagnostics, if requested */
> -	if (diagnose != DIAGNOSE_NONE) {
> -		struct strbuf zip_path = STRBUF_INIT;
> -		strbuf_add(&zip_path, report_path.buf, output_path_len);
> -		strbuf_addstr(&zip_path, "git-diagnostics-");
> -		strbuf_addftime(&zip_path, option_suffix, localtime_r(&now, &tm), 0, 0);
> -		strbuf_addstr(&zip_path, ".zip");
> -
> -		if (create_diagnostics_archive(&zip_path, diagnose))
> -			die_errno(_("unable to create diagnostics archive %s"), zip_path.buf);
> -
> -		strbuf_release(&zip_path);
> -	}
> -
>  	/* Prepare the report contents */
>  	get_bug_template(&buffer);
>  
> @@ -169,14 +177,37 @@ int cmd_bugreport(int argc, const char **argv, const char *prefix)
>  	get_header(&buffer, _("Enabled Hooks"));
>  	get_populated_hooks(&buffer, !startup_info->have_repository);
>  
> -	/* fopen doesn't offer us an O_EXCL alternative, except with glibc. */
> -	report = xopen(report_path.buf, O_CREAT | O_EXCL | O_WRONLY, 0666);
> +	again:
> +		/* fopen doesn't offer us an O_EXCL alternative, except with glibc. */
> +		report = open(report_path.buf, O_CREAT | O_EXCL | O_WRONLY, 0666);
> +		if (report < 0 && errno == EEXIST && !option_suffix_is_from_user) {
> +			build_path(&report_path, prefixed_filename,
> +				   "git-bugreport-", option_suffix, now, &i,
> +				   ".txt");
> +			goto again;
> +		} else if (report < 0) {
Nit, but the double-checking of (report < 0) bothers me a little. Is it
nicer if it's nested?

	if (report < 0) {
		if (errno == EEXIST) {
			build_path(...);
			goto again;
		}

		die_errno(_(...));
	}

I like it a little more, but that's up to taste, I suppose.
> +			die_errno(_("unable to open '%s'"), report_path.buf);
> +		}
>  
>  	if (write_in_full(report, buffer.buf, buffer.len) < 0)
>  		die_errno(_("unable to write to %s"), report_path.buf);
>  
>  	close(report);
>  
> +	/* Prepare diagnostics, if requested */
> +	if (diagnose != DIAGNOSE_NONE) {
> +		struct strbuf zip_path = STRBUF_INIT;
> +		i--; /* Undo last increment to match zipfile suffix to bugreport */
I understand why you're doing this, but I'd rather see it decremented
(or more care taken in the increment logic elsewhere) closer to where it
is being increment-and-checked. If someone wants to add another
associated file besides the report and the diagnostics, then the logic
for the decrement becomes complicated (what happens if I run `git
bugreport --diagnostics --desktop_screencap`? what if I run only `git
bugreport --desktop_screencap`?). Even without that potential pain,
reading this comment here means I have to say "oh wait, what did I read
above? hold on, let me page it back in".

> +		build_path(&zip_path, prefixed_filename, "git-diagnostics-",
> +			   option_suffix, now, &i, ".zip");
> +
> +		if (create_diagnostics_archive(&zip_path, diagnose))
> +			die_errno(_("unable to create diagnostics archive %s"),
> +				  zip_path.buf);
> +
> +		strbuf_release(&zip_path);
> +	}
> +
>  	/*
>  	 * We want to print the path relative to the user, but we still need the
>  	 * path relative to us to give to the editor.
> -- 
> 2.42.0.297.g36452639b8

Last thing: it probably makes sense to mention this new behavior in the
manpage, especially if you'll apply that behavior to user-provided
suffixes too.

Thanks for your effort on the patch so far and again, sorry for the late
reply.
 - Emily

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

* Re: [PATCH v3 1/1] bugreport: include +i in outfile suffix as needed
  2023-10-26 21:19         ` Emily Shaffer
@ 2023-10-27  6:34           ` Jacob Stopak
  2024-01-06  4:54             ` Jacob Stopak
  0 siblings, 1 reply; 23+ messages in thread
From: Jacob Stopak @ 2023-10-27  6:34 UTC (permalink / raw)
  To: Emily Shaffer; +Cc: git

> > +static void build_path(struct strbuf *buf, const char *dir_path,
> > +		       const char *prefix, const char *suffix,
> > +		       time_t t, int *i, const char *ext)
> > +{
> > +	struct tm tm;
> > +
> > +	strbuf_reset(buf);
> > +	strbuf_addstr(buf, dir_path);
> > +	strbuf_complete(buf, '/');
> > +
> > +	strbuf_addstr(buf, prefix);
> > +	strbuf_addftime(buf, suffix, localtime_r(&t, &tm), 0, 0);
> > +
> > +	if (*i > 0)
> > +		strbuf_addf(buf, "+%d", *i);
> > +
> > +	strbuf_addstr(buf, ext);
> > +
> > +	(*i)++;
> > +}
> 
> I commented on the weirdness of having to decrement i for --diagnose
> below, but I think I generally just wish that instead of build_path()
> this function did create_file_with_optional_suffix() and returned the
> final modified option_suffix(). Better still would be if this function
> created (or at least tested) all the necessary output paths so you don't
> end up succeeding in creating a bugreport.txt but failing in creating
> the diagnostics.zip in some edge case, something like....

So the funny thing is that the existing behavior of the diagnostics file
just overwrites any existing diagnostics file with the same name, which
is at odds with how the bugreport throws an error in the case of a
conflict. I wasn't sure whether it made sense to touch that here since it
seemed possibly out of the scope of this change, given that there is
a separate "git diagnose" command to take into account.

But if we keep this behavior it basically means there's no need to test
the necessary diagnostics output paths when determining the path of the
bugreport itself, since whatever we pick for the bugreport will just
overwrite anything for the diagnotics zip if it already exists. The one
caveat is that any future files created should behave the same way...

But I get that this is perhaps inconsistent and it might be worth it to
make "git diagnose" work the same way as bugreport so it makes more sense
to do the kind of validations you mentioned.

> build_suffix(..., &option_suffix) {
>   ... build timestamp ...
>   while (...)
>     for (final_path in eventual_paths) {
>     	err = select(final_path);
> 	if (err)
> 	  final_path = strcat(most_of_path, i)
> 	else
> 	  break
> (Yeah, that's very handwavey, but I hope you see what I'm getting at.)
> 
> Really, though, I mostly don't think I like leaving the control variable i raw
> to the calling scope and making it be manipulated later. Fancy
> pre-guessing-path-availability aside, I think you could achieve a more
> pleasant solution even by letting build_path() become
> create_file_with_optional_suffix() (that reports the optional suffix
> eventually settled on).


Hmm... so when you say "create_file_with_optional_suffix", do you mean
a function that tests a set of paths to find the minimum incremented
suffix that will work for all the paths? Would it use the current method
the patch uses of trying to create the files and if creation fails we
know the file exists -> increment -> try again? Repeat until all the
files are able to be created and make sure to clean up any extras?
(And maybe just clean up everything since the actual files with content
will be created later on, now that the suffix is known).

An alternative could be to wrap `build_path()` in a function that does
this work, locally scope `i` in it, call build_path on each needed path,
and test creation until all paths are valid, clean up all the paths,
then return the suffix.

> > +	if (!strlen(option_suffix))
> > +		option_suffix = "%Y-%m-%d-%H%M";
> > +	else
> > +		option_suffix_is_from_user = 1;
> 
> Looking at where this is used, it looks like you're saying "if the user
> specified the suffix manually and has this problem, then that sucks for
> them, they put their own foot in it".
>
> But I don't know if I necessarily
> follow that logic - I'd just as soon drop the exception, append an int
> to the user-provided suffix, and document that we'll do that in the
> manpage.

Haha - it's interesting how we each interpreted the user's experience here,
and I was a bit torn about this too. But here are my thoughts on it:

If the user specifies their own suffix, it seems more natural and even
expected for them to just get an error if a file with that name already
exists. To me it's not that they put their foot in anything, it's that
they asked for a specific thing that we can't deliver since it's already
taken, so just let them know so they can either delete the existing one
or alter the custom suffix. Incremeting the filename without telling them
in this case might not be what they actually want, we're kindof guessing.

However, in the default case where no suffix is specified, the user likely
has no assumption or awareness about the suffix at all, which is why it
felt odd to throw an error out of the blue if the default suffix happens
to conflict with an existing file that was also created by default. The
user didn't ask for anything specific in this case, so would likely be
confused as to why they are getting an error when it just worked a second
ago. So I was thinking we can just handle it gracefully and give them the
incremented report.

> (This isn't something I feel strongly about, except that I think it
> makes the code harder to follow for not very notable user benefit. I
> also didn't look through the reviews up until now, so if this was
> already hashed back and forth, just go ahead and ignore me.)

Setting up the default variables like this was discussed, but not the
difference in behavior based on whether the user specifies a suffix.
Altho I do agree that we sacrifice some consistency here and it does add
an extra pathway to the code, imo there is a good enough reason to do it
as described above - to me it makes things more intuitive to the user.

> > +		/* fopen doesn't offer us an O_EXCL alternative, except with glibc. */
> > +		report = open(report_path.buf, O_CREAT | O_EXCL | O_WRONLY, 0666);
> > +		if (report < 0 && errno == EEXIST && !option_suffix_is_from_user) {
> > +			build_path(&report_path, prefixed_filename,
> > +				   "git-bugreport-", option_suffix, now, &i,
> > +				   ".txt");
> > +			goto again;
> > +		} else if (report < 0) {
> Nit, but the double-checking of (report < 0) bothers me a little. Is it
> nicer if it's nested?
> 
> 	if (report < 0) {
> 		if (errno == EEXIST) {
> 			build_path(...);
> 			goto again;
> 		}
> 
> 		die_errno(_(...));
> 	}
> 
> I like it a little more, but that's up to taste, I suppose.

I like yours better too :)

> > +			die_errno(_("unable to open '%s'"), report_path.buf);
> > +		}
> >  
> >  	if (write_in_full(report, buffer.buf, buffer.len) < 0)
> >  		die_errno(_("unable to write to %s"), report_path.buf);
> >  
> >  	close(report);
> >  
> > +	/* Prepare diagnostics, if requested */
> > +	if (diagnose != DIAGNOSE_NONE) {
> > +		struct strbuf zip_path = STRBUF_INIT;
> > +		i--; /* Undo last increment to match zipfile suffix to bugreport */
> I understand why you're doing this, but I'd rather see it decremented
> (or more care taken in the increment logic elsewhere) closer to where it
> is being increment-and-checked. If someone wants to add another
> associated file besides the report and the diagnostics, then the logic
> for the decrement becomes complicated (what happens if I run `git
> bugreport --diagnostics --desktop_screencap`? what if I run only `git
> bugreport --desktop_screencap`?). Even without that potential pain,
> reading this comment here means I have to say "oh wait, what did I read
> above? hold on, let me page it back in".
> 

Yeah these are great points and I completely agree! Even if we stick with
this method of doing things, the `i` decrement should be moved out of the
conditional and up closer to where the value of `i` is set.

> > +		build_path(&zip_path, prefixed_filename, "git-diagnostics-",
> > +			   option_suffix, now, &i, ".zip");
> > +
> > +		if (create_diagnostics_archive(&zip_path, diagnose))
> > +			die_errno(_("unable to create diagnostics archive %s"),
> > +				  zip_path.buf);
> > +
> > +		strbuf_release(&zip_path);
> > +	}
> > +
> >  	/*
> >  	 * We want to print the path relative to the user, but we still need the
> >  	 * path relative to us to give to the editor.
> > -- 
> > 2.42.0.297.g36452639b8
> 
> Last thing: it probably makes sense to mention this new behavior in the
> manpage, especially if you'll apply that behavior to user-provided
> suffixes too.

Sure I can add some docs to the manpage, altho as described above I
prefer throwing an error instead of adding the increment to the
user-provided suffixes :D

> Thanks for your effort on the patch so far and again, sorry for the late
> reply.
>  - Emily

No worries at all and thanks a lot for your review! I'll start working
on a v3 - it would be great to get your thoughts on the unresolved items.

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

* Re: [PATCH v3 1/1] bugreport: include +i in outfile suffix as needed
  2023-10-27  6:34           ` Jacob Stopak
@ 2024-01-06  4:54             ` Jacob Stopak
  0 siblings, 0 replies; 23+ messages in thread
From: Jacob Stopak @ 2024-01-06  4:54 UTC (permalink / raw)
  To: Emily Shaffer; +Cc: git

Hey Emily!

Hope you had a great holiday!

I think this thread might have gotten lost in the shuffle.

I had replied to your feedback a couple months ago with a few questions.

It would be great to get your further input before I continue working on
this one.

Best,
Jack

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

end of thread, other threads:[~2024-01-06  4:54 UTC | newest]

Thread overview: 23+ messages (download: mbox.gz / follow: Atom feed)
-- links below jump to the message on this page --
2023-10-14  4:01 [PATCH] bugreport: add 'seconds' to default outfile name Jacob Stopak
2023-10-14 10:35 ` Kristoffer Haugsbakk
2023-10-14 16:27 ` Junio C Hamano
2023-10-14 16:33   ` Dragan Simic
2023-10-14 17:45     ` Junio C Hamano
2023-10-14 17:52       ` Dragan Simic
2023-10-15  3:07         ` Jacob Stopak
2023-10-15  3:13           ` Dragan Simic
2023-10-15  3:01   ` Jacob Stopak
2023-10-15 17:06     ` Junio C Hamano
2023-10-15  3:42 ` [PATCH v2 0/3] bugreport: include +i in outfile suffix as needed Jacob Stopak
2023-10-15  3:42   ` [PATCH v2 1/3] " Jacob Stopak
2023-10-15 17:36     ` Junio C Hamano
2023-10-16 21:40     ` [PATCH v3 0/1] " Jacob Stopak
2023-10-16 21:40       ` [PATCH v3 1/1] " Jacob Stopak
2023-10-16 22:55         ` Junio C Hamano
2023-10-17  3:17           ` Jacob Stopak
2023-10-21  0:39         ` Junio C Hamano
2023-10-26 21:19         ` Emily Shaffer
2023-10-27  6:34           ` Jacob Stopak
2024-01-06  4:54             ` Jacob Stopak
2023-10-15  3:42   ` [PATCH v2 2/3] bugreport: match diagnostics filename with report Jacob Stopak
2023-10-15  3:42   ` [PATCH v2 3/3] bugreport: don't create --diagnose zip w/o report Jacob Stopak

This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox;
as well as URLs for NNTP newsgroup(s).