threads / patch / 52845

v8, 15 partshelp: add shell-path to --build-options

Subject: [PATCH v8 02/15] help: add shell-path to --build-options

## tl;dr

87 messages between Feb 20, 2020 and Mar 23, 2020. Diffs are folded; open one to read it.

replies: 86people: 5as markdown or json

Emily Shaffer· Feb 20, 2020, 01:58 UTC · lore

[PATCH v8 00/15] add git-bugreport tool

No longer relies on any topic branches, since mr/show-config-scope is merged. Range-diff at the bottom of the cover letter.

Since v7:
 - Dropped some POSIX regex magic in
   generate-bugreport-config-safelist.sh.
 - Added some advice in doc for scenarios when git-bugreport may not run
   nicely
 - Quit using unusual "return -foo(bar)" and start using "return
   !!foo(bar)"
 - Add a test to ensure path creation works outside of a git dir
 - Add some GNUC and GNUC_MINOR reporting
 - Use git_cmd instead of hardcoding "git" as the first arg when
   invoking another process
 - Fix some pesky whitespace
Thanks.
 - Emily
Emily Shaffer (15):
  help: move list_config_help to builtin/help
  help: add shell-path to --build-options
  bugreport: add tool to generate debugging info
  bugreport: gather git version and build info
  bugreport: add uname info
  bugreport: add compiler info
  bugreport: add git-remote-https version
  bugreport: include user interactive shell
  bugreport: generate config safelist based on docs
  bugreport: add config values from safelist
  bugreport: collect list of populated hooks
  bugreport: count loose objects
  bugreport: add packed object summary
  bugreport: list contents of $OBJDIR/info
  bugreport: summarize contents of alternates file
 .gitignore                              |   3 +
 Documentation/asciidoc.conf             |   9 +
 Documentation/asciidoctor-extensions.rb |   7 +
 Documentation/config/sendemail.txt      |  56 ++--
 Documentation/git-bugreport.txt         |  60 ++++
 Makefile                                |  27 +-
 bugreport.c                             | 418 ++++++++++++++++++++++++
 builtin/help.c                          |  86 +++++
 command-list.txt                        |   1 +
 compat/compiler.h                       |  27 ++
 generate-bugreport-config-safelist.sh   |  18 +
 generate-cmdlist.sh                     |  19 --
 generate-configlist.sh                  |  21 ++
 help.c                                  | 132 ++------
 help.h                                  |   2 +-
 object-store.h                          |   6 +
 packfile.c                              |   3 +-
 remote-curl.c                           |   8 +
 t/t0091-bugreport.sh                    |  61 ++++
 19 files changed, 808 insertions(+), 156 deletions(-)
 create mode 100644 Documentation/git-bugreport.txt
 create mode 100644 bugreport.c
 create mode 100644 compat/compiler.h
 create mode 100755 generate-bugreport-config-safelist.sh
 create mode 100755 generate-configlist.sh
 create mode 100755 t/t0091-bugreport.sh
 1:  429c7e093b =  1:  69f54afc6b help: move list_config_help to builtin/help
 2:  0cfb24f878 =  2:  9ea1c3ab34 help: add shell-path to --build-options
 3:  02bb151176 !  3:  8a290b5445 bugreport: add tool to generate debugging info
    @@ Documentation/git-bugreport.txt (new)
     + - Expected behavior
     + - Actual behavior
     +
    ++This tool is invoked via the typical Git setup process, which means that in some
    ++cases, it might not be able to launch - for example, if a relevant config file
    ++is unreadable. In this kind of scenario, it may be helpful to manually gather
    ++the kind of information listed above when manually asking for help.
    ++
     +OPTIONS
     +-------
     +-o <path>::
    @@ bugreport.c (new)
     +
     +	UNLEAK(buffer);
     +	UNLEAK(report_path);
    -+	return -launch_editor(report_path.buf, NULL, NULL);
    ++	return !!launch_editor(report_path.buf, NULL, NULL);
     +}
     
      ## command-list.txt ##
    @@ t/t0091-bugreport.sh (new)
     +	test_when_finished rm non-repo/git-bugreport-*
     +'
     +
    ++test_expect_success 'can create leading directories outside of a git dir' '
    ++	nongit git bugreport -o foo/bar/baz &&
    ++	test_when_finished rm -fr foo/bar/baz
    ++'
    ++
    ++
     +test_done
 4:  463612e409 !  4:  4eb4a7aef3 bugreport: gather git version and build info
    @@ Documentation/git-bugreport.txt: The following information is requested from the
     +
     + - 'git version --build-options'
     +
    - OPTIONS
    - -------
    - -o <path>::
    + This tool is invoked via the typical Git setup process, which means that in some
    + cases, it might not be able to launch - for example, if a relevant config file
    + is unreadable. In this kind of scenario, it may be helpful to manually gather
     
      ## bugreport.c ##
     @@
 5:  85e11ea125 !  5:  4e18b4678e bugreport: add uname info
    @@ Documentation/git-bugreport.txt: The following information is requested from the
       - 'git version --build-options'
     + - uname sysname, release, version, and machine strings
      
    - OPTIONS
    - -------
    + This tool is invoked via the typical Git setup process, which means that in some
    + cases, it might not be able to launch - for example, if a relevant config file
     
      ## bugreport.c ##
     @@
 6:  d9eafbaa48 !  6:  c18d17443d bugreport: add compiler info
    @@ Documentation/git-bugreport.txt: The following information is captured automatic
       - uname sysname, release, version, and machine strings
     + - Compiler-specific info string
      
    - OPTIONS
    - -------
    + This tool is invoked via the typical Git setup process, which means that in some
    + cases, it might not be able to launch - for example, if a relevant config file
     
      ## bugreport.c ##
     @@
    @@ compat/compiler.h (new)
     +
     +static inline void get_compiler_info(struct strbuf *info)
     +{
    -+	strbuf_addf(info, "glibc: %s", gnu_get_libc_version());
    ++	strbuf_addf(info, "glibc: %s\n", gnu_get_libc_version());
    ++#ifdef __GNUC__
    ++	strbuf_addf(info, "gnuc: %d.%d\n", __GNUC__, __GNUC_MINOR__);
    ++#endif
     +}
     +
     +#else
 7:  f5b6dd4174 !  7:  6d807cf857 bugreport: add git-remote-https version
    @@ Documentation/git-bugreport.txt: The following information is captured automatic
       - Compiler-specific info string
     + - 'git remote-https --build-info'
      
    - OPTIONS
    - -------
    + This tool is invoked via the typical Git setup process, which means that in some
    + cases, it might not be able to launch - for example, if a relevant config file
     
      ## bugreport.c ##
     @@
    @@ bugreport.c
     +{
     +	struct child_process cp = CHILD_PROCESS_INIT;
     +
    -+	argv_array_push(&cp.args, "git");
    ++	cp.git_cmd = 1;
     +	argv_array_push(&cp.args, "remote-https");
     +	argv_array_push(&cp.args, "--build-info");
     +	if (capture_command(&cp, version_info, 0))
 8:  3119c9c1e3 !  8:  f85e1b69d0 bugreport: include user interactive shell
    @@ Documentation/git-bugreport.txt: The following information is captured automatic
       - 'git remote-https --build-info'
     + - $SHELL
      
    - OPTIONS
    - -------
    + This tool is invoked via the typical Git setup process, which means that in some
    + cases, it might not be able to launch - for example, if a relevant config file
     
      ## bugreport.c ##
     @@ bugreport.c: static void get_git_remote_https_version_info(struct strbuf *version_info)
 9:  c35bab2735 !  9:  9980728360 bugreport: generate config safelist based on docs
    @@ generate-bugreport-config-safelist.sh (new)
     +# cat all regular files in Documentation/config
     +find Documentation/config -type f -exec cat {} \; |
     +# print the command name which matches the annotate-bugreport macro
    -+sed -n 's/^\([^[:blank:]]*\)[[:blank:]]\{1,\}annotate:bugreport\[include\].* ::$/  "\1",/p' \
    ++sed -n 's/^\([^ ]*\)  *annotate:bugreport\[include\].* ::$/  "\1",/p' \
     +	| sort
     +
     +cat <<EOF
10:  8a54ebdbbb ! 10:  e9cd8ffec9 bugreport: add config values from safelist
    @@ Documentation/git-bugreport.txt: The following information is captured automatic
       - $SHELL
     + - Selected config values
      
    - OPTIONS
    - -------
    + This tool is invoked via the typical Git setup process, which means that in some
    + cases, it might not be able to launch - for example, if a relevant config file
     
      ## Makefile ##
     @@ Makefile: git$X: git.o GIT-LDFLAGS $(BUILTIN_OBJS) $(GITLIBS)
11:  8bb5bcd8b8 ! 11:  881b62369d bugreport: collect list of populated hooks
    @@ Documentation/git-bugreport.txt: The following information is captured automatic
       - Selected config values
     + - A list of enabled hooks
      
    - OPTIONS
    - -------
    + This tool is invoked via the typical Git setup process, which means that in some
    + cases, it might not be able to launch - for example, if a relevant config file
     
      ## bugreport.c ##
     @@
12:  744dd6aeee ! 12:  715e48e9a7 bugreport: count loose objects
    @@ Documentation/git-bugreport.txt: The following information is captured automatic
       - A list of enabled hooks
     + - The number of loose objects in the repository
      
    - OPTIONS
    - -------
    + This tool is invoked via the typical Git setup process, which means that in some
    + cases, it might not be able to launch - for example, if a relevant config file
     
      ## bugreport.c ##
     @@
13:  2f23e272bf ! 13:  c9e2f1f1d8 bugreport: add packed object summary
    @@ Documentation/git-bugreport.txt: The following information is captured automatic
       - The number of loose objects in the repository
     + - The number of packs and packed objects in the repository
      
    - OPTIONS
    - -------
    + This tool is invoked via the typical Git setup process, which means that in some
    + cases, it might not be able to launch - for example, if a relevant config file
     
      ## bugreport.c ##
     @@ bugreport.c: static void get_loose_object_summary(struct strbuf *obj_info, int nongit) {
    @@ bugreport.c: int cmd_main(int argc, const char **argv)
     
      ## object-store.h ##
     @@
    - #include "list.h"
      #include "sha1-array.h"
      #include "strbuf.h"
    + #include "thread-utils.h"
     +#include "packfile.h"
      
      struct object_directory {
14:  7b5ae1aca1 ! 14:  89762a0de1 bugreport: list contents of $OBJDIR/info
    @@ Documentation/git-bugreport.txt: The following information is captured automatic
       - The number of packs and packed objects in the repository
     + - A list of the contents of .git/objects/info (or equivalent)
      
    - OPTIONS
    - -------
    + This tool is invoked via the typical Git setup process, which means that in some
    + cases, it might not be able to launch - for example, if a relevant config file
     
      ## bugreport.c ##
     @@ bugreport.c: static void get_packed_object_summary(struct strbuf *obj_info, int nongit)
    @@ bugreport.c: static void get_packed_object_summary(struct strbuf *obj_info, int
      }
      
     +static void list_contents_of_dir_recursively(struct strbuf *contents,
    -+				      	     struct strbuf *dirpath)
    ++					     struct strbuf *dirpath)
     +{
     +	struct dirent *d;
     +	DIR *dir;
15:  315b00ed54 ! 15:  aa81e197aa bugreport: summarize contents of alternates file
    @@ Documentation/git-bugreport.txt: The following information is captured automatic
       - A list of the contents of .git/objects/info (or equivalent)
     + - The number of valid and invalid alternates
      
    - OPTIONS
    - -------
    + This tool is invoked via the typical Git setup process, which means that in some
    + cases, it might not be able to launch - for example, if a relevant config file
     
      ## bugreport.c ##
     @@ bugreport.c: static void get_object_info_summary(struct strbuf *obj_info, int nongit)
-- 
2.25.0.265.gbab2e86ba0-goog
Emily Shaffer· Feb 20, 2020, 01:58 UTC · re: Emily Shaffer · lore

It may be useful to know which shell Git was built to try to point to, in the event that shell-based Git commands are failing. $SHELL_PATH is set during the build and used to launch the manpage viewer, as well as by git-compat-util.h, and it's used during tests. 'git version --build-options' is encouraged for use in bug reports, so it makes sense to include this information there.

Signed-off-by: Emily Shaffer <emilyshaffer@google.com>
---
 help.c | 1 +
 1 file changed, 1 insertion(+)
Show changes to help.c +1 −0
diff --git a/help.c b/help.c
index a21487db77..190722fb0a 100644
--- a/help.c
+++ b/help.c
@@ -654,6 +654,7 @@ int cmd_version(int argc, const char **argv, const char *prefix)
 			printf("no commit associated with this build\n");
 		printf("sizeof-long: %d\n", (int)sizeof(long));
 		printf("sizeof-size_t: %d\n", (int)sizeof(size_t));
+		printf("shell-path: %s\n", SHELL_PATH);
 		/* NEEDSWORK: also save and output GIT-BUILD_OPTIONS? */
 	}
 	return 0;
-- 
2.25.0.265.gbab2e86ba0-goog
Junio C Hamano· Feb 20, 2020, 19:03 UTC · re: Emily Shaffer · lore

Re: [PATCH v8 02/15] help: add shell-path to --build-options

Emily Shaffer <emilyshaffer@google.com> writes:
Show 6 quoted lines
> It may be useful to know which shell Git was built to try to point to,
> in the event that shell-based Git commands are failing. $SHELL_PATH is
> set during the build and used to launch the manpage viewer, as well as
> by git-compat-util.h, and it's used during tests. 'git version
> --build-options' is encouraged for use in bug reports, so it makes sense
> to include this information there.

It probably makes sense to capture PERL_PATH, PYTHON_PATH, TCLTK_PATH, and TCL_PATH, as they fall into exactly the same category as this one.

Show 17 quoted lines
> Signed-off-by: Emily Shaffer <emilyshaffer@google.com>
> ---
>  help.c | 1 +
>  1 file changed, 1 insertion(+)
>
> diff --git a/help.c b/help.c
> index a21487db77..190722fb0a 100644
> --- a/help.c
> +++ b/help.c
> @@ -654,6 +654,7 @@ int cmd_version(int argc, const char **argv, const char *prefix)
>  			printf("no commit associated with this build\n");
>  		printf("sizeof-long: %d\n", (int)sizeof(long));
>  		printf("sizeof-size_t: %d\n", (int)sizeof(size_t));
> +		printf("shell-path: %s\n", SHELL_PATH);
>  		/* NEEDSWORK: also save and output GIT-BUILD_OPTIONS? */
>  	}
>  	return 0;
Emily Shaffer· Feb 20, 2020, 21:15 UTC · re: Junio C Hamano · lore

Re: [PATCH v8 02/15] help: add shell-path to --build-options

On Thu, Feb 20, 2020 at 11:03:59AM -0800, Junio C Hamano wrote:
Show 12 quoted lines
> Emily Shaffer <emilyshaffer@google.com> writes:
> 
> > It may be useful to know which shell Git was built to try to point to,
> > in the event that shell-based Git commands are failing. $SHELL_PATH is
> > set during the build and used to launch the manpage viewer, as well as
> > by git-compat-util.h, and it's used during tests. 'git version
> > --build-options' is encouraged for use in bug reports, so it makes sense
> > to include this information there.
> 
> It probably makes sense to capture PERL_PATH, PYTHON_PATH,
> TCLTK_PATH, and TCL_PATH, as they fall into exactly the same
> category as this one.

SHELL_PATH was already made sure to exist in git-compat-util.h before this change; these other utility paths are not. Do you want me to add them now?

Show 18 quoted lines
> 
> > Signed-off-by: Emily Shaffer <emilyshaffer@google.com>
> > ---
> >  help.c | 1 +
> >  1 file changed, 1 insertion(+)
> >
> > diff --git a/help.c b/help.c
> > index a21487db77..190722fb0a 100644
> > --- a/help.c
> > +++ b/help.c
> > @@ -654,6 +654,7 @@ int cmd_version(int argc, const char **argv, const char *prefix)
> >  			printf("no commit associated with this build\n");
> >  		printf("sizeof-long: %d\n", (int)sizeof(long));
> >  		printf("sizeof-size_t: %d\n", (int)sizeof(size_t));
> > +		printf("shell-path: %s\n", SHELL_PATH);
> >  		/* NEEDSWORK: also save and output GIT-BUILD_OPTIONS? */
> >  	}
> >  	return 0;
Emily Shaffer· Feb 20, 2020, 01:58 UTC · re: Emily Shaffer · lore

[PATCH v8 01/15] help: move list_config_help to builtin/help

Starting in 3ac68a93fd2, help.o began to depend on builtin/branch.o, builtin/clean.o, and builtin/config.o. This meant that help.o was unusable outside of the context of the main Git executable.

To make help.o usable by other commands again, move list_config_help() into builtin/help.c (where it makes sense to assume other builtin libraries are present).

When command-list.h is included but a member is not used, we start to hear a compiler warning. Since the config list is generated in a fairly different way than the command list, and since commands and config options are semantically different, move the config list into its own header and move the generator into its own script and build rule.

Signed-off-by: Emily Shaffer <emilyshaffer@google.com>
---
 .gitignore             |  1 +
 Makefile               | 13 +++++--
 builtin/help.c         | 86 ++++++++++++++++++++++++++++++++++++++++++
 generate-cmdlist.sh    | 19 ----------
 generate-configlist.sh | 21 +++++++++++
 help.c                 | 85 -----------------------------------------
 help.h                 |  1 -
 7 files changed, 118 insertions(+), 108 deletions(-)
 create mode 100755 generate-configlist.sh
Show changes to 7 files +118 −108

.gitignore, Makefile, builtin/help.c, generate-cmdlist.sh, generate-configlist.sh, help.c, help.h

diff --git a/.gitignore b/.gitignore
index aebe7c0908..ea97de83f3 100644
--- a/.gitignore
+++ b/.gitignore
@@ -189,6 +189,7 @@
 /gitweb/gitweb.cgi
 /gitweb/static/gitweb.js
 /gitweb/static/gitweb.min.*
+/config-list.h
 /command-list.h
 *.tar.gz
 *.dsc
diff --git a/Makefile b/Makefile
index 6134104ae6..c552312d3f 100644
--- a/Makefile
+++ b/Makefile
@@ -815,6 +815,7 @@ LIB_FILE = libgit.a
 XDIFF_LIB = xdiff/lib.a
 VCSSVN_LIB = vcs-svn/lib.a
 
+GENERATED_H += config-list.h
 GENERATED_H += command-list.h
 
 LIB_H := $(sort $(patsubst ./%,%,$(shell git ls-files '*.h' ':!t/' ':!Documentation/' 2>/dev/null || \
@@ -2132,7 +2133,7 @@ git$X: git.o GIT-LDFLAGS $(BUILTIN_OBJS) $(GITLIBS)
 
 help.sp help.s help.o: command-list.h
 
-builtin/help.sp builtin/help.s builtin/help.o: command-list.h GIT-PREFIX
+builtin/help.sp builtin/help.s builtin/help.o: config-list.h GIT-PREFIX
 builtin/help.sp builtin/help.s builtin/help.o: EXTRA_CPPFLAGS = \
 	'-DGIT_HTML_PATH="$(htmldir_relative_SQ)"' \
 	'-DGIT_MAN_PATH="$(mandir_relative_SQ)"' \
@@ -2152,6 +2153,12 @@ $(BUILT_INS): git$X
 	ln -s $< $@ 2>/dev/null || \
 	cp $< $@
 
+config-list.h: generate-configlist.sh
+
+config-list.h:
+	$(QUIET_GEN)$(SHELL_PATH) ./generate-configlist.sh \
+		>$@+ && mv $@+ $@
+
 command-list.h: generate-cmdlist.sh command-list.txt
 
 command-list.h: $(wildcard Documentation/git*.txt) Documentation/*config.txt Documentation/config/*.txt
@@ -2785,7 +2792,7 @@ $(SP_OBJ): %.sp: %.c GIT-CFLAGS FORCE
 .PHONY: sparse $(SP_OBJ)
 sparse: $(SP_OBJ)
 
-EXCEPT_HDRS := command-list.h unicode-width.h compat/% xdiff/%
+EXCEPT_HDRS := command-list.h config-list.h unicode-width.h compat/% xdiff/%
 ifndef GCRYPT_SHA256
 	EXCEPT_HDRS += sha256/gcrypt.h
 endif
@@ -2807,7 +2814,7 @@ hdr-check: $(HCO)
 style:
 	git clang-format --style file --diff --extensions c,h
 
-check: command-list.h
+check: config-list.h command-list.h
 	@if sparse; \
 	then \
 		echo >&2 "Use 'make sparse' instead"; \
diff --git a/builtin/help.c b/builtin/help.c
index e5590d7787..1c5f2b9255 100644
--- a/builtin/help.c
+++ b/builtin/help.c
@@ -8,6 +8,7 @@
 #include "parse-options.h"
 #include "run-command.h"
 #include "column.h"
+#include "config-list.h"
 #include "help.h"
 #include "alias.h"
 
@@ -62,6 +63,91 @@ static const char * const builtin_help_usage[] = {
 	NULL
 };
 
+struct slot_expansion {
+	const char *prefix;
+	const char *placeholder;
+	void (*fn)(struct string_list *list, const char *prefix);
+	int found;
+};
+
+static void list_config_help(int for_human)
+{
+	struct slot_expansion slot_expansions[] = {
+		{ "advice", "*", list_config_advices },
+		{ "color.branch", "<slot>", list_config_color_branch_slots },
+		{ "color.decorate", "<slot>", list_config_color_decorate_slots },
+		{ "color.diff", "<slot>", list_config_color_diff_slots },
+		{ "color.grep", "<slot>", list_config_color_grep_slots },
+		{ "color.interactive", "<slot>", list_config_color_interactive_slots },
+		{ "color.remote", "<slot>", list_config_color_sideband_slots },
+		{ "color.status", "<slot>", list_config_color_status_slots },
+		{ "fsck", "<msg-id>", list_config_fsck_msg_ids },
+		{ "receive.fsck", "<msg-id>", list_config_fsck_msg_ids },
+		{ NULL, NULL, NULL }
+	};
+	const char **p;
+	struct slot_expansion *e;
+	struct string_list keys = STRING_LIST_INIT_DUP;
+	int i;
+
+	for (p = config_name_list; *p; p++) {
+		const char *var = *p;
+		struct strbuf sb = STRBUF_INIT;
+
+		for (e = slot_expansions; e->prefix; e++) {
+
+			strbuf_reset(&sb);
+			strbuf_addf(&sb, "%s.%s", e->prefix, e->placeholder);
+			if (!strcasecmp(var, sb.buf)) {
+				e->fn(&keys, e->prefix);
+				e->found++;
+				break;
+			}
+		}
+		strbuf_release(&sb);
+		if (!e->prefix)
+			string_list_append(&keys, var);
+	}
+
+	for (e = slot_expansions; e->prefix; e++)
+		if (!e->found)
+			BUG("slot_expansion %s.%s is not used",
+			    e->prefix, e->placeholder);
+
+	string_list_sort(&keys);
+	for (i = 0; i < keys.nr; i++) {
+		const char *var = keys.items[i].string;
+		const char *wildcard, *tag, *cut;
+
+		if (for_human) {
+			puts(var);
+			continue;
+		}
+
+		wildcard = strchr(var, '*');
+		tag = strchr(var, '<');
+
+		if (!wildcard && !tag) {
+			puts(var);
+			continue;
+		}
+
+		if (wildcard && !tag)
+			cut = wildcard;
+		else if (!wildcard && tag)
+			cut = tag;
+		else
+			cut = wildcard < tag ? wildcard : tag;
+
+		/*
+		 * We may produce duplicates, but that's up to
+		 * git-completion.bash to handle
+		 */
+		printf("%.*s\n", (int)(cut - var), var);
+	}
+	string_list_clear(&keys, 0);
+}
+
 static enum help_format parse_help_format(const char *format)
 {
 	if (!strcmp(format, "man"))
diff --git a/generate-cmdlist.sh b/generate-cmdlist.sh
index 71158f7d8b..45fecf8bdf 100755
--- a/generate-cmdlist.sh
+++ b/generate-cmdlist.sh
@@ -76,23 +76,6 @@ print_command_list () {
 	echo "};"
 }
 
-print_config_list () {
-	cat <<EOF
-static const char *config_name_list[] = {
-EOF
-	grep -h '^[a-zA-Z].*\..*::$' Documentation/*config.txt Documentation/config/*.txt |
-	sed '/deprecated/d; s/::$//; s/,  */\n/g' |
-	sort |
-	while read line
-	do
-		echo "	\"$line\","
-	done
-	cat <<EOF
-	NULL,
-};
-EOF
-}
-
 exclude_programs=
 while test "--exclude-program" = "$1"
 do
@@ -113,5 +96,3 @@ echo
 define_category_names "$1"
 echo
 print_command_list "$1"
-echo
-print_config_list
diff --git a/generate-configlist.sh b/generate-configlist.sh
new file mode 100755
index 0000000000..8692fe5cf4
--- /dev/null
+++ b/generate-configlist.sh
@@ -0,0 +1,21 @@
+#!/bin/sh
+
+echo "/* Automatically generated by generate-configlist.sh */"
+echo
+
+print_config_list () {
+	cat <<EOF
+static const char *config_name_list[] = {
+EOF
+	grep -h '^[a-zA-Z].*\..*::$' Documentation/*config.txt Documentation/config/*.txt |
+	sed '/deprecated/d; s/::$//; s/,  */\n/g' |
+	sort |
+	sed 's/^.*$/	"&",/'
+	cat <<EOF
+	NULL,
+};
+EOF
+}
+
+echo
+print_config_list
diff --git a/help.c b/help.c
index cf67624a94..a21487db77 100644
--- a/help.c
+++ b/help.c
@@ -407,91 +407,6 @@ void list_common_guides_help(void)
 	putchar('\n');
 }
 
-struct slot_expansion {
-	const char *prefix;
-	const char *placeholder;
-	void (*fn)(struct string_list *list, const char *prefix);
-	int found;
-};
-
-void list_config_help(int for_human)
-{
-	struct slot_expansion slot_expansions[] = {
-		{ "advice", "*", list_config_advices },
-		{ "color.branch", "<slot>", list_config_color_branch_slots },
-		{ "color.decorate", "<slot>", list_config_color_decorate_slots },
-		{ "color.diff", "<slot>", list_config_color_diff_slots },
-		{ "color.grep", "<slot>", list_config_color_grep_slots },
-		{ "color.interactive", "<slot>", list_config_color_interactive_slots },
-		{ "color.remote", "<slot>", list_config_color_sideband_slots },
-		{ "color.status", "<slot>", list_config_color_status_slots },
-		{ "fsck", "<msg-id>", list_config_fsck_msg_ids },
-		{ "receive.fsck", "<msg-id>", list_config_fsck_msg_ids },
-		{ NULL, NULL, NULL }
-	};
-	const char **p;
-	struct slot_expansion *e;
-	struct string_list keys = STRING_LIST_INIT_DUP;
-	int i;
-
-	for (p = config_name_list; *p; p++) {
-		const char *var = *p;
-		struct strbuf sb = STRBUF_INIT;
-
-		for (e = slot_expansions; e->prefix; e++) {
-
-			strbuf_reset(&sb);
-			strbuf_addf(&sb, "%s.%s", e->prefix, e->placeholder);
-			if (!strcasecmp(var, sb.buf)) {
-				e->fn(&keys, e->prefix);
-				e->found++;
-				break;
-			}
-		}
-		strbuf_release(&sb);
-		if (!e->prefix)
-			string_list_append(&keys, var);
-	}
-
-	for (e = slot_expansions; e->prefix; e++)
-		if (!e->found)
-			BUG("slot_expansion %s.%s is not used",
-			    e->prefix, e->placeholder);
-
-	string_list_sort(&keys);
-	for (i = 0; i < keys.nr; i++) {
-		const char *var = keys.items[i].string;
-		const char *wildcard, *tag, *cut;
-
-		if (for_human) {
-			puts(var);
-			continue;
-		}
-
-		wildcard = strchr(var, '*');
-		tag = strchr(var, '<');
-
-		if (!wildcard && !tag) {
-			puts(var);
-			continue;
-		}
-
-		if (wildcard && !tag)
-			cut = wildcard;
-		else if (!wildcard && tag)
-			cut = tag;
-		else
-			cut = wildcard < tag ? wildcard : tag;
-
-		/*
-		 * We may produce duplicates, but that's up to
-		 * git-completion.bash to handle
-		 */
-		printf("%.*s\n", (int)(cut - var), var);
-	}
-	string_list_clear(&keys, 0);
-}
-
 static int get_alias(const char *var, const char *value, void *data)
 {
 	struct string_list *list = data;
diff --git a/help.h b/help.h
index 7a455beeb7..9071894e8c 100644
--- a/help.h
+++ b/help.h
@@ -22,7 +22,6 @@ static inline void mput_char(char c, unsigned int num)
 void list_common_cmds_help(void);
 void list_all_cmds_help(void);
 void list_common_guides_help(void);
-void list_config_help(int for_human);
 
 void list_all_main_cmds(struct string_list *list);
 void list_all_other_cmds(struct string_list *list);
-- 
2.25.0.265.gbab2e86ba0-goog
Emily Shaffer· Feb 20, 2020, 01:58 UTC · re: Emily Shaffer · lore

[PATCH v8 03/15] bugreport: add tool to generate debugging info

Teach Git how to prompt the user for a good bug report: reproduction steps, expected behavior, and actual behavior. Later, Git can learn how to collect some diagnostic information from the repository.

If users can send us a well-written bug report which contains diagnostic information we would otherwise need to ask the user for, we can reduce the number of question-and-answer round trips between the reporter and the Git contributor.

Users may also wish to send a report like this to their local "Git expert" if they have put their repository into a state they are confused by.

Signed-off-by: Emily Shaffer <emilyshaffer@google.com>
---
 .gitignore                      |  1 +
 Documentation/git-bugreport.txt | 46 ++++++++++++++++
 Makefile                        |  5 ++
 bugreport.c                     | 94 +++++++++++++++++++++++++++++++++
 command-list.txt                |  1 +
 t/t0091-bugreport.sh            | 61 +++++++++++++++++++++
 6 files changed, 208 insertions(+)
 create mode 100644 Documentation/git-bugreport.txt
 create mode 100644 bugreport.c
 create mode 100755 t/t0091-bugreport.sh
Show changes to 6 files +208 −0

.gitignore, Documentation/git-bugreport.txt, Makefile, bugreport.c, command-list.txt, t/t0091-bugreport.sh

diff --git a/.gitignore b/.gitignore
index ea97de83f3..d89bf9e11e 100644
--- a/.gitignore
+++ b/.gitignore
@@ -25,6 +25,7 @@
 /git-bisect--helper
 /git-blame
 /git-branch
+/git-bugreport
 /git-bundle
 /git-cat-file
 /git-check-attr
diff --git a/Documentation/git-bugreport.txt b/Documentation/git-bugreport.txt
new file mode 100644
index 0000000000..1f9fde5cde
--- /dev/null
+++ b/Documentation/git-bugreport.txt
@@ -0,0 +1,46 @@
+git-bugreport(1)
+================
+
+NAME
+----
+git-bugreport - Collect information for user to file a bug report
+
+SYNOPSIS
+--------
+[verse]
+'git bugreport' [(-o | --output-directory) <path>] [(-s | --suffix) <format>]
+
+DESCRIPTION
+-----------
+Captures information about the user's machine, Git client, and repository state,
+as well as a form requesting information about the behavior the user observed,
+into a single text file which the user can then share, for example to the Git
+mailing list, in order to report an observed bug.
+
+The following information is requested from the user:
+
+ - Reproduction steps
+ - Expected behavior
+ - Actual behavior
+
+This tool is invoked via the typical Git setup process, which means that in some
+cases, it might not be able to launch - for example, if a relevant config file
+is unreadable. In this kind of scenario, it may be helpful to manually gather
+the kind of information listed above when manually asking for help.
+
+OPTIONS
+-------
+-o <path>::
+--output-directory <path>::
+	Place the resulting bug report file in `<path>` instead of the root of
+	the Git repository.
+
+-s <format>::
+--suffix <format>::
+	Specify an alternate suffix for the bugreport name, to create a file
+	named 'git-bugreport-<formatted suffix>'. This should take the form of a
+	link:strftime[3] format string; the current local time will be used.
+
+GIT
+---
+Part of the linkgit:git[1] suite
diff --git a/Makefile b/Makefile
index c552312d3f..9e6705061d 100644
--- a/Makefile
+++ b/Makefile
@@ -681,6 +681,7 @@ EXTRA_PROGRAMS =
 # ... and all the rest that could be moved out of bindir to gitexecdir
 PROGRAMS += $(EXTRA_PROGRAMS)
 
+PROGRAM_OBJS += bugreport.o
 PROGRAM_OBJS += credential-store.o
 PROGRAM_OBJS += daemon.o
 PROGRAM_OBJS += fast-import.o
@@ -2461,6 +2462,10 @@ endif
 git-%$X: %.o GIT-LDFLAGS $(GITLIBS)
 	$(QUIET_LINK)$(CC) $(ALL_CFLAGS) -o $@ $(ALL_LDFLAGS) $(filter %.o,$^) $(LIBS)
 
+git-bugreport$X: bugreport.o GIT-LDFLAGS $(GITLIBS)
+	$(QUIET_LINK)$(CC) $(ALL_CFLAGS) -o $@ $(ALL_LDFLAGS) $(filter %.o,$^) \
+		$(LIBS)
+
 git-imap-send$X: imap-send.o $(IMAP_SEND_BUILDDEPS) GIT-LDFLAGS $(GITLIBS)
 	$(QUIET_LINK)$(CC) $(ALL_CFLAGS) -o $@ $(ALL_LDFLAGS) $(filter %.o,$^) \
 		$(IMAP_SEND_LDFLAGS) $(LIBS)
diff --git a/bugreport.c b/bugreport.c
new file mode 100644
index 0000000000..8d4a76fdac
--- /dev/null
+++ b/bugreport.c
@@ -0,0 +1,94 @@
+#include "builtin.h"
+#include "parse-options.h"
+#include "stdio.h"
+#include "strbuf.h"
+#include "time.h"
+
+static const char * const bugreport_usage[] = {
+	N_("git bugreport [-o|--output-directory <file>] [-s|--suffix <format>]"),
+	NULL
+};
+
+static int get_bug_template(struct strbuf *template)
+{
+	const char template_text[] = N_(
+"Thank you for filling out a Git bug report!\n"
+"Please answer the following questions to help us understand your issue.\n"
+"\n"
+"What did you do before the bug happened? (Steps to reproduce your issue)\n"
+"\n"
+"What did you expect to happen? (Expected behavior)\n"
+"\n"
+"What happened instead? (Actual behavior)\n"
+"\n"
+"What's different between what you expected and what actually happened?\n"
+"\n"
+"Anything else you want to add:\n"
+"\n"
+"Please review the rest of the bug report below.\n"
+"You can delete any lines you don't wish to share.\n");
+
+	strbuf_addstr(template, template_text);
+	return 0;
+}
+
+int cmd_main(int argc, const char **argv)
+{
+	struct strbuf buffer = STRBUF_INIT;
+	struct strbuf report_path = STRBUF_INIT;
+	FILE *report;
+	time_t now = time(NULL);
+	char *option_output = NULL;
+	char *option_suffix = "%F-%H%M";
+	struct stat statbuf;
+
+	const struct option bugreport_options[] = {
+		OPT_STRING('o', "output-directory", &option_output, N_("path"),
+			   N_("specify a destination for the bugreport file")),
+		OPT_STRING('s', "suffix", &option_suffix, N_("format"),
+			   N_("specify a strftime format suffix for the filename")),
+		OPT_END()
+	};
+	argc = parse_options(argc, argv, "", bugreport_options,
+			     bugreport_usage, 0);
+
+	if (option_output) {
+		strbuf_addstr(&report_path, option_output);
+		strbuf_complete(&report_path, '/');
+	}
+
+
+	strbuf_addstr(&report_path, "git-bugreport-");
+	strbuf_addftime(&report_path, option_suffix, localtime(&now), 0, 0);
+	strbuf_addstr(&report_path, ".txt");
+
+	if (!stat(report_path.buf, &statbuf))
+		die("'%s' already exists", report_path.buf);
+
+	switch (safe_create_leading_directories(report_path.buf)) {
+	case SCLD_OK:
+	case SCLD_EXISTS:
+		break;
+	default:
+		die(_("could not create leading directories for '%s'"),
+		    report_path.buf);
+	}
+
+	get_bug_template(&buffer);
+
+	report = fopen_for_writing(report_path.buf);
+
+	if (report == NULL) {
+		strbuf_release(&report_path);
+		die("couldn't open '%s' for writing", report_path.buf);
+	}
+
+	strbuf_write(&buffer, report);
+	fclose(report);
+
+	fprintf(stderr, _("Created new report at '%s'.\n"), report_path.buf);
+
+	UNLEAK(buffer);
+	UNLEAK(report_path);
+	return !!launch_editor(report_path.buf, NULL, NULL);
+}
diff --git a/command-list.txt b/command-list.txt
index 2087894655..185e5e3f05 100644
--- a/command-list.txt
+++ b/command-list.txt
@@ -54,6 +54,7 @@ git-archive                             mainporcelain
 git-bisect                              mainporcelain           info
 git-blame                               ancillaryinterrogators          complete
 git-branch                              mainporcelain           history
+git-bugreport                           ancillaryinterrogators
 git-bundle                              mainporcelain
 git-cat-file                            plumbinginterrogators
 git-check-attr                          purehelpers
diff --git a/t/t0091-bugreport.sh b/t/t0091-bugreport.sh
new file mode 100755
index 0000000000..65f664fdac
--- /dev/null
+++ b/t/t0091-bugreport.sh
@@ -0,0 +1,61 @@
+#!/bin/sh
+
+test_description='git bugreport'
+
+. ./test-lib.sh
+
+# Headers "[System Info]" will be followed by a non-empty line if we put some
+# information there; we can make sure all our headers were followed by some
+# information to check if the command was successful.
+HEADER_PATTERN="^\[.*\]$"
+
+check_all_headers_populated () {
+	while read -r line
+	do
+		if test "$(grep "$HEADER_PATTERN" "$line")"
+		then
+			echo "$line"
+			read -r nextline
+			if test -z "$nextline"; then
+				return 1;
+			fi
+		fi
+	done
+}
+
+test_expect_success 'creates a report with content in the right places' '
+	git bugreport -s check-headers &&
+	check_all_headers_populated <git-bugreport-check-headers.txt &&
+	test_when_finished rm git-bugreport-check-headers.txt
+'
+
+test_expect_success 'dies if file with same name as report already exists' '
+	>>git-bugreport-duplicate.txt &&
+	test_must_fail git bugreport --suffix duplicate &&
+	test_when_finished rm git-bugreport-duplicate.txt
+'
+
+test_expect_success '--output-directory puts the report in the provided dir' '
+	git bugreport -o foo/ &&
+	test_path_is_file foo/git-bugreport-* &&
+	test_when_finished rm -fr foo/
+'
+
+test_expect_success 'incorrect arguments abort with usage' '
+	test_must_fail git bugreport --false 2>output &&
+	test_i18ngrep usage output &&
+	test_path_is_missing git-bugreport-*
+'
+
+test_expect_success 'runs outside of a git dir' '
+	nongit git bugreport &&
+	test_when_finished rm non-repo/git-bugreport-*
+'
+
+test_expect_success 'can create leading directories outside of a git dir' '
+	nongit git bugreport -o foo/bar/baz &&
+	test_when_finished rm -fr foo/bar/baz
+'
+
+
+test_done
-- 
2.25.0.265.gbab2e86ba0-goog
Junio C Hamano· Feb 20, 2020, 19:33 UTC · re: Emily Shaffer · lore

Re: [PATCH v8 03/15] bugreport: add tool to generate debugging info

Emily Shaffer <emilyshaffer@google.com> writes:
> +	argc = parse_options(argc, argv, "", bugreport_options,
> +			     bugreport_usage, 0);

Which one between an empty string and NULL is more appropriate to be passed as "prefix" here? I assume that this is *not* really a git program, and no repository/working-tree discovery is involved, and you won't be using OPT_FILENAME, so it would probably be OK.

Show 13 quoted lines
> +
> +	if (option_output) {
> +		strbuf_addstr(&report_path, option_output);
> +		strbuf_complete(&report_path, '/');
> +	}
> +
> +
> +	strbuf_addstr(&report_path, "git-bugreport-");
> +	strbuf_addftime(&report_path, option_suffix, localtime(&now), 0, 0);
> +	strbuf_addstr(&report_path, ".txt");
> +
> +	if (!stat(report_path.buf, &statbuf))
> +		die("'%s' already exists", report_path.buf);

Missed i18n/l10n, but I do not think it is a useful thing for this check to be here in the first place.

Show 12 quoted lines
> +	switch (safe_create_leading_directories(report_path.buf)) {
> +	case SCLD_OK:
> +	case SCLD_EXISTS:
> +		break;
> +	default:
> +		die(_("could not create leading directories for '%s'"),
> +		    report_path.buf);
> +	}
> +
> +	get_bug_template(&buffer);
> +
> +	report = fopen_for_writing(report_path.buf);

fopen_for_writing() does not give good semantics for what you seem to want to do here (i.e. to make sure you do not overwrite an existing one). It even has "if we cannot open it, retry after unlinking" logic in it, which screams "this function is designed for those who want to overwrite the file", and if you look at its callers, they are _all_ about opening a file for writing with a well known name like FETCH_HEAD, COMMIT_EDITMSG, etc.

Besides, a stat() that dies when a file exists would not help---since that check, you've spent non-zero time, creating leading directories and preparing boilerplate in the buffer, and there is no guarantee somebody else used the same filename in the meantime.

If you want to avoid overwriting an existing file (which I think is a good idea---I just do not think the earlier "if (!stat()) die()" is a good way to do so), the only sensible way to do so is to ask your open/creat to fail if there already is a file---that is how you'd avoid racing with another process that may be creating such a file. Grep for O_EXCL to find where the flag is used with O_CREAT to see how it is done.

> +	if (report == NULL) {
Style. "if (!report)"
> +		strbuf_release(&report_path);
> +		die("couldn't open '%s' for writing", report_path.buf);
Do we see a use-after-free here?  Also missed i18n/l10n.

It is embarrassing on the reviewers' side that this (which is not new in this round at all and hasn't changed since v6) hasn't been caught for a few rounds X-<.

Thanks.
Emily Shaffer· Feb 20, 2020, 22:33 UTC · re: Junio C Hamano · lore

Re: [PATCH v8 03/15] bugreport: add tool to generate debugging info

On Thu, Feb 20, 2020 at 11:33:26AM -0800, Junio C Hamano wrote:
Show 53 quoted lines
> Emily Shaffer <emilyshaffer@google.com> writes:
> 
> > +	argc = parse_options(argc, argv, "", bugreport_options,
> > +			     bugreport_usage, 0);
> 
> Which one between an empty string and NULL is more appropriate to be
> passed as "prefix" here?  I assume that this is *not* really a git
> program, and no repository/working-tree discovery is involved, and
> you won't be using OPT_FILENAME, so it would probably be OK.
> 
> > +
> > +	if (option_output) {
> > +		strbuf_addstr(&report_path, option_output);
> > +		strbuf_complete(&report_path, '/');
> > +	}
> > +
> > +
> > +	strbuf_addstr(&report_path, "git-bugreport-");
> > +	strbuf_addftime(&report_path, option_suffix, localtime(&now), 0, 0);
> > +	strbuf_addstr(&report_path, ".txt");
> > +
> > +	if (!stat(report_path.buf, &statbuf))
> > +		die("'%s' already exists", report_path.buf);
> 
> Missed i18n/l10n, but I do not think it is a useful thing for this
> check to be here in the first place.
> 
> > +	switch (safe_create_leading_directories(report_path.buf)) {
> > +	case SCLD_OK:
> > +	case SCLD_EXISTS:
> > +		break;
> > +	default:
> > +		die(_("could not create leading directories for '%s'"),
> > +		    report_path.buf);
> > +	}
> > +
> > +	get_bug_template(&buffer);
> > +
> > +	report = fopen_for_writing(report_path.buf);
> 
> fopen_for_writing() does not give good semantics for what you seem
> to want to do here (i.e. to make sure you do not overwrite an
> existing one).  It even has "if we cannot open it, retry after
> unlinking" logic in it, which screams "this function is designed for
> those who want to overwrite the file", and if you look at its
> callers, they are _all_ about opening a file for writing with a well
> known name like FETCH_HEAD, COMMIT_EDITMSG, etc.
> 
> Besides, a stat() that dies when a file exists would not
> help---since that check, you've spent non-zero time, creating
> leading directories and preparing boilerplate in the buffer,
> and there is no guarantee somebody else used the same filename
> in the meantime.
Good point. Ouch.
Show 8 quoted lines
> 
> If you want to avoid overwriting an existing file (which I think is
> a good idea---I just do not think the earlier "if (!stat()) die()"
> is a good way to do so), the only sensible way to do so is to ask
> your open/creat to fail if there already is a file---that is how
> you'd avoid racing with another process that may be creating such a
> file.  Grep for O_EXCL to find where the flag is used with O_CREAT
> to see how it is done.
Sure. Thanks, I reworked it to use open().

By the way, I noticed reading the GNU manual that file descriptors may not be supported outside of GNU environments; but I also noticed that 1) Git uses open() lots of places to use O_EXCL, and 2) fopen() doesn't support exclusive opens (except in glibc, and nobody is using that particular option in the Git codebase now). So I guess it's safe to use open()...

> 
> > +	if (report == NULL) {
> 
> Style. "if (!report)"

The type of 'report' changes using open(), so this check changes too. Now it says "if (report < 0)" - per the open() doc, it returns a positive fd or -1.

Show 5 quoted lines
> 
> > +		strbuf_release(&report_path);
> > +		die("couldn't open '%s' for writing", report_path.buf);
> 
> Do we see a use-after-free here?  Also missed i18n/l10n.

Hm. I suppose it's OK to UNLEAK() like we do at the successful exit since the die() will end the process. Added i18n too.

> It is embarrassing on the reviewers' side that this (which is not
> new in this round at all and hasn't changed since v6) hasn't been
> caught for a few rounds X-<.
Well, I'm embarrassed to have written it in the first place.
 - Emily
Johannes Schindelin· Feb 26, 2020, 16:12 UTC · re: Emily Shaffer · lore

Re: [PATCH v8 03/15] bugreport: add tool to generate debugging info

Hi Emily,
On Wed, 19 Feb 2020, Emily Shaffer wrote:
Show 48 quoted lines
> diff --git a/bugreport.c b/bugreport.c
> new file mode 100644
> index 0000000000..8d4a76fdac
> --- /dev/null
> +++ b/bugreport.c
> @@ -0,0 +1,94 @@
> +#include "builtin.h"
> +#include "parse-options.h"
> +#include "stdio.h"
> +#include "strbuf.h"
> +#include "time.h"
> +
> +static const char * const bugreport_usage[] = {
> +	N_("git bugreport [-o|--output-directory <file>] [-s|--suffix <format>]"),
> +	NULL
> +};
> +
> +static int get_bug_template(struct strbuf *template)
> +{
> +	const char template_text[] = N_(
> +"Thank you for filling out a Git bug report!\n"
> +"Please answer the following questions to help us understand your issue.\n"
> +"\n"
> +"What did you do before the bug happened? (Steps to reproduce your issue)\n"
> +"\n"
> +"What did you expect to happen? (Expected behavior)\n"
> +"\n"
> +"What happened instead? (Actual behavior)\n"
> +"\n"
> +"What's different between what you expected and what actually happened?\n"
> +"\n"
> +"Anything else you want to add:\n"
> +"\n"
> +"Please review the rest of the bug report below.\n"
> +"You can delete any lines you don't wish to share.\n");
> +
> +	strbuf_addstr(template, template_text);
> +	return 0;
> +}
> +
> +int cmd_main(int argc, const char **argv)
> +{
> +	struct strbuf buffer = STRBUF_INIT;
> +	struct strbuf report_path = STRBUF_INIT;
> +	FILE *report;
> +	time_t now = time(NULL);
> +	char *option_output = NULL;
> +	char *option_suffix = "%F-%H%M";
This is not a portable `strftime()` format. Let's squash this in?
-- snipsnap --
Subject: [PATCH] fixup??? bugreport: add tool to generate debugging info

The `%F` format is an optional extension to the ISO C standard, see https://pubs.opengroup.org/onlinepubs/9699919799/functions/strftime.html

And sure enough, in Git for Windows, this leads to a test failure because that format is not supported in the version of the MSVC runtime that we're stuck with.

Let's just use the long-hand instead.
Signed-off-by: Johannes Schindelin <johannes.schindelin@gmx.de>
---
 bugreport.c | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)
Show changes to bugreport.c +1 −2
diff --git a/bugreport.c b/bugreport.c
index a3528a2e2b8..3f78db182e6 100644
--- a/bugreport.c
+++ b/bugreport.c
@@ -338,7 +338,7 @@ int cmd_main(int argc, const char **argv)
 	FILE *report;
 	time_t now = time(NULL);
 	char *option_output = NULL;
-	char *option_suffix = "%F-%H%M";
+	char *option_suffix = "%Y-%m-%d-%H%M";
 	struct stat statbuf;
 	int nongit_ok = 0;

--
2.25.1.windows.1
Emily Shaffer· Feb 20, 2020, 01:58 UTC · re: Emily Shaffer · lore

[PATCH v8 04/15] bugreport: gather git version and build info

Knowing which version of Git a user has and how it was built allows us to more precisely pin down the circumstances when a certain issue occurs, so teach bugreport how to tell us the same output as 'git version --build-options'.

It's not ideal to directly call 'git version --build-options' because that output goes to stdout. Instead, wrap the version string in a helper within help.[ch] library, and call that helper from within the bugreport library.

Signed-off-by: Emily Shaffer <emilyshaffer@google.com>
---
 Documentation/git-bugreport.txt |  4 +++
 bugreport.c                     | 19 ++++++++++++-
 help.c                          | 48 ++++++++++++++++++++-------------
 help.h                          |  1 +
 4 files changed, 52 insertions(+), 20 deletions(-)
Show changes to 4 files +52 −20

Documentation/git-bugreport.txt, bugreport.c, help.c, help.h

diff --git a/Documentation/git-bugreport.txt b/Documentation/git-bugreport.txt
index 1f9fde5cde..f44ae8cbe7 100644
--- a/Documentation/git-bugreport.txt
+++ b/Documentation/git-bugreport.txt
@@ -23,6 +23,10 @@ The following information is requested from the user:
  - Expected behavior
  - Actual behavior
 
+The following information is captured automatically:
+
+ - 'git version --build-options'
+
 This tool is invoked via the typical Git setup process, which means that in some
 cases, it might not be able to launch - for example, if a relevant config file
 is unreadable. In this kind of scenario, it may be helpful to manually gather
diff --git a/bugreport.c b/bugreport.c
index 8d4a76fdac..27f813643d 100644
--- a/bugreport.c
+++ b/bugreport.c
@@ -1,8 +1,17 @@
-#include "builtin.h"
+#include "cache.h"
 #include "parse-options.h"
 #include "stdio.h"
 #include "strbuf.h"
 #include "time.h"
+#include "help.h"
+
+static void get_system_info(struct strbuf *sys_info)
+{
+	/* get git version from native cmd */
+	strbuf_addstr(sys_info, "git version:\n");
+	get_version_info(sys_info, 1);
+	strbuf_complete_line(sys_info);
+}
 
 static const char * const bugreport_usage[] = {
 	N_("git bugreport [-o|--output-directory <file>] [-s|--suffix <format>]"),
@@ -32,6 +41,11 @@ static int get_bug_template(struct strbuf *template)
 	return 0;
 }
 
+static void get_header(struct strbuf *buf, const char *title)
+{
+	strbuf_addf(buf, "\n\n[%s]\n", title);
+}
+
 int cmd_main(int argc, const char **argv)
 {
 	struct strbuf buffer = STRBUF_INIT;
@@ -76,6 +90,9 @@ int cmd_main(int argc, const char **argv)
 
 	get_bug_template(&buffer);
 
+	get_header(&buffer, "System Info");
+	get_system_info(&buffer);
+
 	report = fopen_for_writing(report_path.buf);
 
 	if (report == NULL) {
diff --git a/help.c b/help.c
index 190722fb0a..44cee69c11 100644
--- a/help.c
+++ b/help.c
@@ -622,8 +622,33 @@ const char *help_unknown_cmd(const char *cmd)
 	exit(1);
 }
 
+void get_version_info(struct strbuf *buf, int show_build_options)
+{
+	/*
+	 * The format of this string should be kept stable for compatibility
+	 * with external projects that rely on the output of "git version".
+	 *
+	 * Always show the version, even if other options are given.
+	 */
+	strbuf_addf(buf, "git version %s\n", git_version_string);
+
+	if (show_build_options) {
+		strbuf_addf(buf, "cpu: %s\n", GIT_HOST_CPU);
+		if (git_built_from_commit_string[0])
+			strbuf_addf(buf, "built from commit: %s\n",
+			       git_built_from_commit_string);
+		else
+			strbuf_addstr(buf, "no commit associated with this build\n");
+		strbuf_addf(buf, "sizeof-long: %d\n", (int)sizeof(long));
+		strbuf_addf(buf, "sizeof-size_t: %d\n", (int)sizeof(size_t));
+		strbuf_addf(buf, "shell-path: %s\n", SHELL_PATH);
+		/* NEEDSWORK: also save and output GIT-BUILD_OPTIONS? */
+	}
+}
+
 int cmd_version(int argc, const char **argv, const char *prefix)
 {
+	struct strbuf buf = STRBUF_INIT;
 	int build_options = 0;
 	const char * const usage[] = {
 		N_("git version [<options>]"),
@@ -637,26 +662,11 @@ int cmd_version(int argc, const char **argv, const char *prefix)
 
 	argc = parse_options(argc, argv, prefix, options, usage, 0);
 
-	/*
-	 * The format of this string should be kept stable for compatibility
-	 * with external projects that rely on the output of "git version".
-	 *
-	 * Always show the version, even if other options are given.
-	 */
-	printf("git version %s\n", git_version_string);
+	get_version_info(&buf, build_options);
+	printf("%s", buf.buf);
+
+	strbuf_release(&buf);
 
-	if (build_options) {
-		printf("cpu: %s\n", GIT_HOST_CPU);
-		if (git_built_from_commit_string[0])
-			printf("built from commit: %s\n",
-			       git_built_from_commit_string);
-		else
-			printf("no commit associated with this build\n");
-		printf("sizeof-long: %d\n", (int)sizeof(long));
-		printf("sizeof-size_t: %d\n", (int)sizeof(size_t));
-		printf("shell-path: %s\n", SHELL_PATH);
-		/* NEEDSWORK: also save and output GIT-BUILD_OPTIONS? */
-	}
 	return 0;
 }
 
diff --git a/help.h b/help.h
index 9071894e8c..500521b908 100644
--- a/help.h
+++ b/help.h
@@ -37,6 +37,7 @@ void add_cmdname(struct cmdnames *cmds, const char *name, int len);
 void exclude_cmds(struct cmdnames *cmds, struct cmdnames *excludes);
 int is_in_cmdlist(struct cmdnames *cmds, const char *name);
 void list_commands(unsigned int colopts, struct cmdnames *main_cmds, struct cmdnames *other_cmds);
+void get_version_info(struct strbuf *buf, int show_build_options);
 
 /*
  * call this to die(), when it is suspected that the user mistyped a
-- 
2.25.0.265.gbab2e86ba0-goog
Junio C Hamano· Feb 20, 2020, 20:07 UTC · re: Emily Shaffer · lore

Re: [PATCH v8 04/15] bugreport: gather git version and build info

Emily Shaffer <emilyshaffer@google.com> writes:
Show 6 quoted lines
> +static void get_system_info(struct strbuf *sys_info)
> +{
> +	/* get git version from native cmd */
> +	strbuf_addstr(sys_info, "git version:\n");
> +	get_version_info(sys_info, 1);
> +	strbuf_complete_line(sys_info);

It is a bit curious use of "don't do anything if sys_info ends with a complete line, but complete it if it ends with an imcomplete line". That tells the readers that we do not know what get_version_info() will do (now or in the future) to its output buffer.

Show 19 quoted lines
> +}
> ...
> diff --git a/help.c b/help.c
> index 190722fb0a..44cee69c11 100644
> --- a/help.c
> +++ b/help.c
> @@ -622,8 +622,33 @@ const char *help_unknown_cmd(const char *cmd)
>  	exit(1);
>  }
>  
> +void get_version_info(struct strbuf *buf, int show_build_options)
> +{
> +	/*
> +	 * The format of this string should be kept stable for compatibility
> +	 * with external projects that rely on the output of "git version".
> +	 *
> +	 * Always show the version, even if other options are given.
> +	 */
> +	strbuf_addf(buf, "git version %s\n", git_version_string);
This ends the output with a complete line when !show_build_options ...
Show 11 quoted lines
> +	if (show_build_options) {
> +		strbuf_addf(buf, "cpu: %s\n", GIT_HOST_CPU);
> +		if (git_built_from_commit_string[0])
> +			strbuf_addf(buf, "built from commit: %s\n",
> +			       git_built_from_commit_string);
> +		else
> +			strbuf_addstr(buf, "no commit associated with this build\n");
> +		strbuf_addf(buf, "sizeof-long: %d\n", (int)sizeof(long));
> +		strbuf_addf(buf, "sizeof-size_t: %d\n", (int)sizeof(size_t));
> +		strbuf_addf(buf, "shell-path: %s\n", SHELL_PATH);
> +		/* NEEDSWORK: also save and output GIT-BUILD_OPTIONS? */

... and the pattern indicates the output will end with a complete line when !!show_build_options, too.

> +	}
> +}

So, was the strbuf_complete_line() merely defensive programming? It may deserve a comment if it will stay there.

Show 35 quoted lines
>  int cmd_version(int argc, const char **argv, const char *prefix)
>  {
> +	struct strbuf buf = STRBUF_INIT;
>  	int build_options = 0;
>  	const char * const usage[] = {
>  		N_("git version [<options>]"),
> @@ -637,26 +662,11 @@ int cmd_version(int argc, const char **argv, const char *prefix)
>  
>  	argc = parse_options(argc, argv, prefix, options, usage, 0);
>  
> -	/*
> -	 * The format of this string should be kept stable for compatibility
> -	 * with external projects that rely on the output of "git version".
> -	 *
> -	 * Always show the version, even if other options are given.
> -	 */
> -	printf("git version %s\n", git_version_string);
> +	get_version_info(&buf, build_options);
> +	printf("%s", buf.buf);
> +
> +	strbuf_release(&buf);
>  
> -	if (build_options) {
> -		printf("cpu: %s\n", GIT_HOST_CPU);
> -		if (git_built_from_commit_string[0])
> -			printf("built from commit: %s\n",
> -			       git_built_from_commit_string);
> -		else
> -			printf("no commit associated with this build\n");
> -		printf("sizeof-long: %d\n", (int)sizeof(long));
> -		printf("sizeof-size_t: %d\n", (int)sizeof(size_t));
> -		printf("shell-path: %s\n", SHELL_PATH);
> -		/* NEEDSWORK: also save and output GIT-BUILD_OPTIONS? */
> -	}
>  	return 0;
Makes sense.
Emily Shaffer· Feb 20, 2020, 23:03 UTC · re: Junio C Hamano · lore

Re: [PATCH v8 04/15] bugreport: gather git version and build info

On Thu, Feb 20, 2020 at 12:07:46PM -0800, Junio C Hamano wrote:
Show 57 quoted lines
> Emily Shaffer <emilyshaffer@google.com> writes:
> 
> > +static void get_system_info(struct strbuf *sys_info)
> > +{
> > +	/* get git version from native cmd */
> > +	strbuf_addstr(sys_info, "git version:\n");
> > +	get_version_info(sys_info, 1);
> > +	strbuf_complete_line(sys_info);
> 
> It is a bit curious use of "don't do anything if sys_info ends with
> a complete line, but complete it if it ends with an imcomplete
> line".  That tells the readers that we do not know what
> get_version_info() will do (now or in the future) to its output
> buffer.
> 
> > +}
> > ...
> > diff --git a/help.c b/help.c
> > index 190722fb0a..44cee69c11 100644
> > --- a/help.c
> > +++ b/help.c
> > @@ -622,8 +622,33 @@ const char *help_unknown_cmd(const char *cmd)
> >  	exit(1);
> >  }
> >  
> > +void get_version_info(struct strbuf *buf, int show_build_options)
> > +{
> > +	/*
> > +	 * The format of this string should be kept stable for compatibility
> > +	 * with external projects that rely on the output of "git version".
> > +	 *
> > +	 * Always show the version, even if other options are given.
> > +	 */
> > +	strbuf_addf(buf, "git version %s\n", git_version_string);
> 
> This ends the output with a complete line when !show_build_options ...
> 
> > +	if (show_build_options) {
> > +		strbuf_addf(buf, "cpu: %s\n", GIT_HOST_CPU);
> > +		if (git_built_from_commit_string[0])
> > +			strbuf_addf(buf, "built from commit: %s\n",
> > +			       git_built_from_commit_string);
> > +		else
> > +			strbuf_addstr(buf, "no commit associated with this build\n");
> > +		strbuf_addf(buf, "sizeof-long: %d\n", (int)sizeof(long));
> > +		strbuf_addf(buf, "sizeof-size_t: %d\n", (int)sizeof(size_t));
> > +		strbuf_addf(buf, "shell-path: %s\n", SHELL_PATH);
> > +		/* NEEDSWORK: also save and output GIT-BUILD_OPTIONS? */
> 
> ... and the pattern indicates the output will end with a complete
> line when !!show_build_options, too.
> 
> > +	}
> > +}
> 
> So, was the strbuf_complete_line() merely defensive programming?  It
> may deserve a comment if it will stay there.

It was meant defensively, here and elsewhere in the series. I figured that for something like this, which is mostly bounded by human writing in an editor and then by file IO, spurious string-checking was not such a big deal.

Are you suggesting to comment around the strbuf_complete_line() calls, or to comment around get_version_info() that it should end in newline?

 - Emily
Junio C Hamano· Feb 20, 2020, 23:18 UTC · re: Emily Shaffer · lore

Re: [PATCH v8 04/15] bugreport: gather git version and build info

Emily Shaffer <emilyshaffer@google.com> writes:
Show 26 quoted lines
> On Thu, Feb 20, 2020 at 12:07:46PM -0800, Junio C Hamano wrote:
>> Emily Shaffer <emilyshaffer@google.com> writes:
>> 
>> > +static void get_system_info(struct strbuf *sys_info)
>> > +{
>> > +	/* get git version from native cmd */
>> > +	strbuf_addstr(sys_info, "git version:\n");
>> > +	get_version_info(sys_info, 1);
>> > +	strbuf_complete_line(sys_info);
>> 
>> It is a bit curious use of "don't do anything if sys_info ends with
>> a complete line, but complete it if it ends with an imcomplete
>> line".  That tells the readers that we do not know what
>> get_version_info() will do (now or in the future) to its output
>> buffer.
>>  ...
>> So, was the strbuf_complete_line() merely defensive programming?  It
>> may deserve a comment if it will stay there.
>
> It was meant defensively, here and elsewhere in the series. I figured
> that for something like this, which is mostly bounded by human writing
> in an editor and then by file IO, spurious string-checking was not such
> a big deal.
>
> Are you suggesting to comment around the strbuf_complete_line() calls,
> or to comment around get_version_info() that it should end in newline?

I meant a comment in get_system_info() next to the use of this particular use of strbuf_complete_line(), if the use stays there.

But after reading the whole series through, I saw no need to use strbuf_complete_line() in the first place, as there is no source of input that is not under our control (if we do not count sloppy programming, that is).

Emily Shaffer· Feb 20, 2020, 01:58 UTC · re: Emily Shaffer · lore

[PATCH v8 05/15] bugreport: add uname info

The contents of uname() can give us some insight into what sort of system the user is running on, and help us replicate their setup if need be. The domainname field is not guaranteed to be available, so don't collect it.

Signed-off-by: Emily Shaffer <emilyshaffer@google.com>
---
 Documentation/git-bugreport.txt |  1 +
 bugreport.c                     | 13 +++++++++++++
 2 files changed, 14 insertions(+)
Show changes to 2 files +14 −0

Documentation/git-bugreport.txt, bugreport.c

diff --git a/Documentation/git-bugreport.txt b/Documentation/git-bugreport.txt
index f44ae8cbe7..17b0d14e8d 100644
--- a/Documentation/git-bugreport.txt
+++ b/Documentation/git-bugreport.txt
@@ -26,6 +26,7 @@ The following information is requested from the user:
 The following information is captured automatically:
 
  - 'git version --build-options'
+ - uname sysname, release, version, and machine strings
 
 This tool is invoked via the typical Git setup process, which means that in some
 cases, it might not be able to launch - for example, if a relevant config file
diff --git a/bugreport.c b/bugreport.c
index 27f813643d..06a63cc283 100644
--- a/bugreport.c
+++ b/bugreport.c
@@ -7,10 +7,23 @@
 
 static void get_system_info(struct strbuf *sys_info)
 {
+	struct utsname uname_info;
+
 	/* get git version from native cmd */
 	strbuf_addstr(sys_info, "git version:\n");
 	get_version_info(sys_info, 1);
 	strbuf_complete_line(sys_info);
+
+	/* system call for other version info */
+	strbuf_addstr(sys_info, "uname -a: ");
+	if (uname(&uname_info))
+		strbuf_addf(sys_info, "uname() failed with code %d\n", errno);
+	else
+		strbuf_addf(sys_info, "%s %s %s %s\n",
+			    uname_info.sysname,
+			    uname_info.release,
+			    uname_info.version,
+			    uname_info.machine);
 }
 
 static const char * const bugreport_usage[] = {
-- 
2.25.0.265.gbab2e86ba0-goog
Junio C Hamano· Feb 20, 2020, 20:12 UTC · re: Emily Shaffer · lore

Re: [PATCH v8 05/15] bugreport: add uname info

Emily Shaffer <emilyshaffer@google.com> writes:
> +	/* system call for other version info */
> +	strbuf_addstr(sys_info, "uname -a: ");

Is that "-a" portable across systems? That is, when given "-a", would "uname" on all platforms show sysname, release, version and machine in that order and nothing else?

If we are merely saying "in this section, we are showing a selected subset from what we learned about the system with uname(2)", perhaps just stop at saying "uname: "?

> +	if (uname(&uname_info))
> +		strbuf_addf(sys_info, "uname() failed with code %d\n", errno);
i18n/l10n?  Don't we want to use strerror() here?
Show 9 quoted lines
> +	else
> +		strbuf_addf(sys_info, "%s %s %s %s\n",
> +			    uname_info.sysname,
> +			    uname_info.release,
> +			    uname_info.version,
> +			    uname_info.machine);
>  }
>  
>  static const char * const bugreport_usage[] = {
Emily Shaffer· Feb 20, 2020, 23:20 UTC · re: Junio C Hamano · lore

Re: [PATCH v8 05/15] bugreport: add uname info

On Thu, Feb 20, 2020 at 12:12:58PM -0800, Junio C Hamano wrote:
Show 12 quoted lines
> Emily Shaffer <emilyshaffer@google.com> writes:
> 
> > +	/* system call for other version info */
> > +	strbuf_addstr(sys_info, "uname -a: ");
> 
> Is that "-a" portable across systems?  That is, when given "-a",
> would "uname" on all platforms show sysname, release, version and
> machine in that order and nothing else?
> 
> If we are merely saying "in this section, we are showing a selected
> subset from what we learned about the system with uname(2)", perhaps
> just stop at saying "uname: "?

Sure, that's good enough for me. I think actually 'uname -a' on a GNU system isn't going to match what's output here anyways, since I don't show the nodename and 'uname -a' would.

Show 5 quoted lines
> 
> > +	if (uname(&uname_info))
> > +		strbuf_addf(sys_info, "uname() failed with code %d\n", errno);
> 
> i18n/l10n?  Don't we want to use strerror() here?

Much much earlier[1] in the series, you suggested not i18n/l10n the contents of the bugreport, as this list would probably be ill-equipped to process such a report. Since it's being added to sys_info, that means this line is bound for the finished report, not for the user.

Speaking of locale, strerror() will print the error in the current locale; if we're still assuming "the list only takes reports in English" should I be explicit and use strerror_l()? Should I print strerror() in current locale and include the errno, e.g. ("uname() failed with '%s' (%d)\n", strerror(errno), errno)?

[1] https://lore.kernel.org/git/xmqqzhka2tbv.fsf@gitster-ct.c.googlers.com
Emily Shaffer· Feb 20, 2020, 01:58 UTC · re: Emily Shaffer · lore

[PATCH v8 06/15] bugreport: add compiler info

To help pinpoint the source of a regression, it is useful to know some info about the compiler which the user's Git client was built with. By adding a generic get_compiler_info() in 'compat/' we can choose which relevant information to share per compiler; to get started, let's demonstrate the version of glibc if the user built with 'gcc'.

Signed-off-by: Emily Shaffer <emilyshaffer@google.com>
---
 Documentation/git-bugreport.txt |  1 +
 bugreport.c                     |  5 +++++
 compat/compiler.h               | 27 +++++++++++++++++++++++++++
 3 files changed, 33 insertions(+)
 create mode 100644 compat/compiler.h
Show changes to 3 files +33 −0

Documentation/git-bugreport.txt, bugreport.c, compat/compiler.h

diff --git a/Documentation/git-bugreport.txt b/Documentation/git-bugreport.txt
index 17b0d14e8d..643d1b2884 100644
--- a/Documentation/git-bugreport.txt
+++ b/Documentation/git-bugreport.txt
@@ -27,6 +27,7 @@ The following information is captured automatically:
 
  - 'git version --build-options'
  - uname sysname, release, version, and machine strings
+ - Compiler-specific info string
 
 This tool is invoked via the typical Git setup process, which means that in some
 cases, it might not be able to launch - for example, if a relevant config file
diff --git a/bugreport.c b/bugreport.c
index 06a63cc283..9a470c5588 100644
--- a/bugreport.c
+++ b/bugreport.c
@@ -4,6 +4,7 @@
 #include "strbuf.h"
 #include "time.h"
 #include "help.h"
+#include "compat/compiler.h"
 
 static void get_system_info(struct strbuf *sys_info)
 {
@@ -24,6 +25,10 @@ static void get_system_info(struct strbuf *sys_info)
 			    uname_info.release,
 			    uname_info.version,
 			    uname_info.machine);
+
+	strbuf_addstr(sys_info, "compiler info: ");
+	get_compiler_info(sys_info);
+	strbuf_complete_line(sys_info);
 }
 
 static const char * const bugreport_usage[] = {
diff --git a/compat/compiler.h b/compat/compiler.h
new file mode 100644
index 0000000000..ef41177233
--- /dev/null
+++ b/compat/compiler.h
@@ -0,0 +1,27 @@
+#ifndef COMPILER_H
+#define COMPILER_H
+
+#include "git-compat-util.h"
+#include "strbuf.h"
+
+#ifdef __GLIBC__
+#include <gnu/libc-version.h>
+
+static inline void get_compiler_info(struct strbuf *info)
+{
+	strbuf_addf(info, "glibc: %s\n", gnu_get_libc_version());
+#ifdef __GNUC__
+	strbuf_addf(info, "gnuc: %d.%d\n", __GNUC__, __GNUC_MINOR__);
+#endif
+}
+
+#else
+
+static inline void get_compiler_info(struct strbuf *info)
+{
+	strbuf_addstr(info, "get_compiler_info() not implemented");
+}
+
+#endif
+
+#endif /* COMPILER_H */
-- 
2.25.0.265.gbab2e86ba0-goog
Danh Doan· Feb 20, 2020, 02:49 UTC · re: Emily Shaffer · lore

Re: [PATCH v8 06/15] bugreport: add compiler info

On 2020-02-19 17:58:49-0800, Emily Shaffer <emilyshaffer@google.com> wrote:
Show 21 quoted lines
> diff --git a/compat/compiler.h b/compat/compiler.h
> new file mode 100644
> index 0000000000..ef41177233
> --- /dev/null
> +++ b/compat/compiler.h
> @@ -0,0 +1,27 @@
> +#ifndef COMPILER_H
> +#define COMPILER_H
> +
> +#include "git-compat-util.h"
> +#include "strbuf.h"
> +
> +#ifdef __GLIBC__
> +#include <gnu/libc-version.h>
> +
> +static inline void get_compiler_info(struct strbuf *info)
> +{
> +	strbuf_addf(info, "glibc: %s\n", gnu_get_libc_version());
> +#ifdef __GNUC__
> +	strbuf_addf(info, "gnuc: %d.%d\n", __GNUC__, __GNUC_MINOR__);
> +#endif
I think we're better having
- get_compiler_info placed under #ifdef __GNUC__ gate,
- get_libc_info under #ifdef __GLIBC

Then have a function to merge those information together. Correct me if I were wrong, as it is now, this is only useful for Linux people with glibc.

Anyway, clang also defines __GNUC__ and __GNUC_MINOR__, IIRC, FreeBSD people started to move to use clang instead of gcc as their default compiler.

Gentoo forks are also known to use clang to compile their ports.
-- 
Danh
Emily Shaffer· Feb 20, 2020, 23:23 UTC · re: Danh Doan · lore

Re: [PATCH v8 06/15] bugreport: add compiler info

On Thu, Feb 20, 2020 at 09:49:03AM +0700, Danh Doan wrote:
Show 37 quoted lines
> On 2020-02-19 17:58:49-0800, Emily Shaffer <emilyshaffer@google.com> wrote:
> > diff --git a/compat/compiler.h b/compat/compiler.h
> > new file mode 100644
> > index 0000000000..ef41177233
> > --- /dev/null
> > +++ b/compat/compiler.h
> > @@ -0,0 +1,27 @@
> > +#ifndef COMPILER_H
> > +#define COMPILER_H
> > +
> > +#include "git-compat-util.h"
> > +#include "strbuf.h"
> > +
> > +#ifdef __GLIBC__
> > +#include <gnu/libc-version.h>
> > +
> > +static inline void get_compiler_info(struct strbuf *info)
> > +{
> > +	strbuf_addf(info, "glibc: %s\n", gnu_get_libc_version());
> > +#ifdef __GNUC__
> > +	strbuf_addf(info, "gnuc: %d.%d\n", __GNUC__, __GNUC_MINOR__);
> > +#endif
> 
> I think we're better having
> 
> - get_compiler_info placed under #ifdef __GNUC__ gate,
> - get_libc_info under #ifdef __GLIBC
> 
> Then have a function to merge those information together.
> Correct me if I were wrong, as it is now,
> this is only useful for Linux people with glibc.
> 
> Anyway, clang also defines __GNUC__ and __GNUC_MINOR__,
> IIRC, FreeBSD people started to move to use clang instead of gcc
> as their default compiler.
> 
> Gentoo forks are also known to use clang to compile their ports.

Yeah, between your comments now and Dscho's comments on this patch in the last rollup, I'll go ahead and refactor it like you suggest.

 - Emily
Junio C Hamano· Feb 20, 2020, 20:23 UTC · re: Emily Shaffer · lore

Re: [PATCH v8 06/15] bugreport: add compiler info

Emily Shaffer <emilyshaffer@google.com> writes:
Show 39 quoted lines
> @@ -24,6 +25,10 @@ static void get_system_info(struct strbuf *sys_info)
>  			    uname_info.release,
>  			    uname_info.version,
>  			    uname_info.machine);
> +
> +	strbuf_addstr(sys_info, "compiler info: ");
> +	get_compiler_info(sys_info);
> +	strbuf_complete_line(sys_info);
>  }
>  
>  static const char * const bugreport_usage[] = {
> diff --git a/compat/compiler.h b/compat/compiler.h
> new file mode 100644
> index 0000000000..ef41177233
> --- /dev/null
> +++ b/compat/compiler.h
> @@ -0,0 +1,27 @@
> +#ifndef COMPILER_H
> +#define COMPILER_H
> +
> +#include "git-compat-util.h"
> +#include "strbuf.h"
> +
> +#ifdef __GLIBC__
> +#include <gnu/libc-version.h>
> +
> +static inline void get_compiler_info(struct strbuf *info)
> +{
> +	strbuf_addf(info, "glibc: %s\n", gnu_get_libc_version());
> +#ifdef __GNUC__
> +	strbuf_addf(info, "gnuc: %d.%d\n", __GNUC__, __GNUC_MINOR__);
> +#endif
> +}
> +
> +#else
> +
> +static inline void get_compiler_info(struct strbuf *info)
> +{
> +	strbuf_addstr(info, "get_compiler_info() not implemented");

i18n/l10n? Also don't deliberately leave the buffer end with an incomplete line like so---doing so _requires_ the caller above to have strbuf_complete_line() call, but there is no reason to do so.

strbuf_complete_line() does make sense if you insert something that is not controlled by us (e.g. "Please type whatever other comments you may have" to let the user give us free-form text, which may or may not end with a complete line), but otherwise it probably is a sign of being unnecessary sloppy.

> +}

OK, so the idea is to insert "#elif ..." and definition of get_compiler_info() for non GLIBC systems?

I am not sure why you want to make this a header with static inline implementations. Is it expected for this to be included from multiple source files? It would be more understandable if these were in the same file as where get_system_info() is, perhaps immediately before that function.

Also, it would probably be easier to manage if you have two separate helpers, one for what compiler is in use, and the other for what libc is in use.

> +
> +#endif
> +
> +#endif /* COMPILER_H */
Thanks.
Junio C Hamano· Feb 21, 2020, 00:26 UTC · re: Emily Shaffer · lore

Re: [PATCH v8 06/15] bugreport: add compiler info

Emily Shaffer <emilyshaffer@google.com> writes:
> +	strbuf_addstr(sys_info, "compiler info: ");
> +	get_compiler_info(sys_info);
> +	strbuf_complete_line(sys_info);

Continuing the response to 04/15 review, I do not think this is a good use of complete_line(), either. On an exotic platform you haven't seen, get_compiler_info() might stuff nothing in the output buffer, in which case we are left with an incomplete line that just says "compiler info: ", and it might be better not to leave that incomplete line hanging around by calling complete_line(), but an even better solution would be to make sure get_compiler_info() explicitly say it encountered a system totally new to it. And at that point, as long as everybody in get_compiler_info() ends its output with a complete line, there is no need for complete_line() on the caller's side.

Of course, you can make it a convention that all case arms or ifdef blocks in get_compiler_info() uniformly end what they have to say with an incomplete line and make it a responsibility of the caller to terminate the incomplete line. But in that case, you'd not be using complete_line(), but strbuf_addch('\n').

Emily Shaffer· Feb 20, 2020, 01:58 UTC · re: Emily Shaffer · lore

[PATCH v8 07/15] bugreport: add git-remote-https version

It's possible for git-remote-curl to be built separately from git; in that case we want to know what version of cURL is used by git-remote-curl, not necessarily which version was present at git-bugreport's build time. So instead, ask git-remote-curl for the version information it knows about.

Today, "git-remote-http" and "git-remote-https" are aliased to "git-remote-curl"; but in case we rely on a different library than cURL in the future, let's not explicitly reference cURL from bugreport.

For longevity purposes, invoke the alias "git-remote-https" instead of "git-remote-http".

Since it could have been built at a different time, also report the version and built-from commit of git-remote-curl alongside the cURL info.

Signed-off-by: Emily Shaffer <emilyshaffer@google.com>
---
 Documentation/git-bugreport.txt |  1 +
 bugreport.c                     | 16 ++++++++++++++++
 remote-curl.c                   |  8 ++++++++
 3 files changed, 25 insertions(+)
Show changes to 3 files +25 −0

Documentation/git-bugreport.txt, bugreport.c, remote-curl.c

diff --git a/Documentation/git-bugreport.txt b/Documentation/git-bugreport.txt
index 643d1b2884..8c7cb9a5d4 100644
--- a/Documentation/git-bugreport.txt
+++ b/Documentation/git-bugreport.txt
@@ -28,6 +28,7 @@ The following information is captured automatically:
  - 'git version --build-options'
  - uname sysname, release, version, and machine strings
  - Compiler-specific info string
+ - 'git remote-https --build-info'
 
 This tool is invoked via the typical Git setup process, which means that in some
 cases, it might not be able to launch - for example, if a relevant config file
diff --git a/bugreport.c b/bugreport.c
index 9a470c5588..fb2adfdf14 100644
--- a/bugreport.c
+++ b/bugreport.c
@@ -5,6 +5,18 @@
 #include "time.h"
 #include "help.h"
 #include "compat/compiler.h"
+#include "run-command.h"
+
+static void get_git_remote_https_version_info(struct strbuf *version_info)
+{
+	struct child_process cp = CHILD_PROCESS_INIT;
+
+	cp.git_cmd = 1;
+	argv_array_push(&cp.args, "remote-https");
+	argv_array_push(&cp.args, "--build-info");
+	if (capture_command(&cp, version_info, 0))
+	    strbuf_addstr(version_info, "'git-remote-https --build-info' not supported\n");
+}
 
 static void get_system_info(struct strbuf *sys_info)
 {
@@ -29,6 +41,10 @@ static void get_system_info(struct strbuf *sys_info)
 	strbuf_addstr(sys_info, "compiler info: ");
 	get_compiler_info(sys_info);
 	strbuf_complete_line(sys_info);
+
+	strbuf_addstr(sys_info, "git-remote-https --build-info:\n");
+	get_git_remote_https_version_info(sys_info);
+	strbuf_complete_line(sys_info);
 }
 
 static const char * const bugreport_usage[] = {
diff --git a/remote-curl.c b/remote-curl.c
index 8eb96152f5..73e52175c0 100644
--- a/remote-curl.c
+++ b/remote-curl.c
@@ -17,6 +17,7 @@
 #include "protocol.h"
 #include "quote.h"
 #include "transport.h"
+#include "version.h"
 
 static struct remote *remote;
 /* always ends with a trailing slash */
@@ -1375,6 +1376,13 @@ int cmd_main(int argc, const char **argv)
 	string_list_init(&options.deepen_not, 1);
 	string_list_init(&options.push_options, 1);
 
+	if (!strcmp("--build-info", argv[1])) {
+		printf("git-http-fetch version: %s\n", git_version_string);
+		printf("built from commit: %s\n", git_built_from_commit_string);
+		printf("curl version: %s\n", curl_version());
+		return 0;
+	}
+
 	/*
 	 * Just report "remote-curl" here (folding all the various aliases
 	 * ("git-remote-http", "git-remote-https", and etc.) here since they
-- 
2.25.0.265.gbab2e86ba0-goog
Junio C Hamano· Feb 20, 2020, 20:35 UTC · re: Emily Shaffer · lore

Re: [PATCH v8 07/15] bugreport: add git-remote-https version

Emily Shaffer <emilyshaffer@google.com> writes:
Show 42 quoted lines
> +static void get_git_remote_https_version_info(struct strbuf *version_info)
> +{
> +	struct child_process cp = CHILD_PROCESS_INIT;
> +
> +	cp.git_cmd = 1;
> +	argv_array_push(&cp.args, "remote-https");
> +	argv_array_push(&cp.args, "--build-info");
> +	if (capture_command(&cp, version_info, 0))
> +	    strbuf_addstr(version_info, "'git-remote-https --build-info' not supported\n");
> +}
>  
>  static void get_system_info(struct strbuf *sys_info)
>  {
> @@ -29,6 +41,10 @@ static void get_system_info(struct strbuf *sys_info)
>  	strbuf_addstr(sys_info, "compiler info: ");
>  	get_compiler_info(sys_info);
>  	strbuf_complete_line(sys_info);
> +
> +	strbuf_addstr(sys_info, "git-remote-https --build-info:\n");
> +	get_git_remote_https_version_info(sys_info);
> +	strbuf_complete_line(sys_info);
>  }
>  
>  static const char * const bugreport_usage[] = {
> diff --git a/remote-curl.c b/remote-curl.c
> index 8eb96152f5..73e52175c0 100644
> --- a/remote-curl.c
> +++ b/remote-curl.c
> @@ -17,6 +17,7 @@
>  #include "protocol.h"
>  #include "quote.h"
>  #include "transport.h"
> +#include "version.h"
>  
>  static struct remote *remote;
>  /* always ends with a trailing slash */
> @@ -1375,6 +1376,13 @@ int cmd_main(int argc, const char **argv)
>  	string_list_init(&options.deepen_not, 1);
>  	string_list_init(&options.push_options, 1);
>  
> +	if (!strcmp("--build-info", argv[1])) {
> +		printf("git-http-fetch version: %s\n", git_version_string);

We are letting bugreport grab this information from remote-curl, and they are different binaries, so git_version_string we see here is that of the remote-curl. Good.

Show 8 quoted lines
> +		printf("built from commit: %s\n", git_built_from_commit_string);
> +		printf("curl version: %s\n", curl_version());
> +		return 0;
> +	}
> +
>  	/*
>  	 * Just report "remote-curl" here (folding all the various aliases
>  	 * ("git-remote-http", "git-remote-https", and etc.) here since they

Makes sense, except that it is not clear what our overall stance on i18n/l10n of the bugreport output.

I think there are two schools of thought.  
 - You can stick to C local, with an expectation that developers can
   read reports in C locale.  This will allow developers to avoid
   having to read reports written in a language they do not
   understand, and also makes it easier to mechanically process
   reports.
 - You can make sure what matters in the report is localized to the
   end-users' locale.  This will avoid forcing end-users to send out
   a report that they may not even able to read (which is what
   happens if we did not do i18n/l10n).

I am not sure which way you are aiming at. The boilerplate text we saw in a very early part of the series were marked N_() but some of the messages in later parts of the series are not.

Emily Shaffer· Feb 20, 2020, 23:28 UTC · re: Junio C Hamano · lore

Re: [PATCH v8 07/15] bugreport: add git-remote-https version

On Thu, Feb 20, 2020 at 12:35:37PM -0800, Junio C Hamano wrote:
Show 77 quoted lines
> Emily Shaffer <emilyshaffer@google.com> writes:
> 
> > +static void get_git_remote_https_version_info(struct strbuf *version_info)
> > +{
> > +	struct child_process cp = CHILD_PROCESS_INIT;
> > +
> > +	cp.git_cmd = 1;
> > +	argv_array_push(&cp.args, "remote-https");
> > +	argv_array_push(&cp.args, "--build-info");
> > +	if (capture_command(&cp, version_info, 0))
> > +	    strbuf_addstr(version_info, "'git-remote-https --build-info' not supported\n");
> > +}
> >  
> >  static void get_system_info(struct strbuf *sys_info)
> >  {
> > @@ -29,6 +41,10 @@ static void get_system_info(struct strbuf *sys_info)
> >  	strbuf_addstr(sys_info, "compiler info: ");
> >  	get_compiler_info(sys_info);
> >  	strbuf_complete_line(sys_info);
> > +
> > +	strbuf_addstr(sys_info, "git-remote-https --build-info:\n");
> > +	get_git_remote_https_version_info(sys_info);
> > +	strbuf_complete_line(sys_info);
> >  }
> >  
> >  static const char * const bugreport_usage[] = {
> > diff --git a/remote-curl.c b/remote-curl.c
> > index 8eb96152f5..73e52175c0 100644
> > --- a/remote-curl.c
> > +++ b/remote-curl.c
> > @@ -17,6 +17,7 @@
> >  #include "protocol.h"
> >  #include "quote.h"
> >  #include "transport.h"
> > +#include "version.h"
> >  
> >  static struct remote *remote;
> >  /* always ends with a trailing slash */
> > @@ -1375,6 +1376,13 @@ int cmd_main(int argc, const char **argv)
> >  	string_list_init(&options.deepen_not, 1);
> >  	string_list_init(&options.push_options, 1);
> >  
> > +	if (!strcmp("--build-info", argv[1])) {
> > +		printf("git-http-fetch version: %s\n", git_version_string);
> 
> We are letting bugreport grab this information from remote-curl, and
> they are different binaries, so git_version_string we see here is
> that of the remote-curl.  Good.
> 
> > +		printf("built from commit: %s\n", git_built_from_commit_string);
> > +		printf("curl version: %s\n", curl_version());
> > +		return 0;
> > +	}
> > +
> >  	/*
> >  	 * Just report "remote-curl" here (folding all the various aliases
> >  	 * ("git-remote-http", "git-remote-https", and etc.) here since they
> 
> Makes sense, except that it is not clear what our overall stance on
> i18n/l10n of the bugreport output.
> 
> I think there are two schools of thought.  
> 
>  - You can stick to C local, with an expectation that developers can
>    read reports in C locale.  This will allow developers to avoid
>    having to read reports written in a language they do not
>    understand, and also makes it easier to mechanically process
>    reports.
> 
>  - You can make sure what matters in the report is localized to the
>    end-users' locale.  This will avoid forcing end-users to send out
>    a report that they may not even able to read (which is what
>    happens if we did not do i18n/l10n).
> 
> I am not sure which way you are aiming at.  The boilerplate text
> we saw in a very early part of the series were marked N_() but some
> of the messages in later parts of the series are not.

I mentioned it in another reply to you at a different point in the v8 conversation; I took away the localization on the boilerplate at your suggestion. Unfortunately I agree that we wouldn't be equipped to handle reports in other languages. Not being able to understand the user-fillable part of the report extends, I think, to not being able to understand the diagnostic info. If the point of the report is to skip back-and-forth, then writing back to say "actually, run all this stuff manually so we can see the output in English" is not going to achieve that goal.

 - Emily
Junio C Hamano· Feb 21, 2020, 03:44 UTC · re: Emily Shaffer · lore

Re: [PATCH v8 07/15] bugreport: add git-remote-https version

Emily Shaffer <emilyshaffer@google.com> writes:
> ... Unfortunately I agree that we wouldn't be equipped to handle
> reports in other languages.
I actually was anticipating a far better world ;-) 

There is no reason to limit the recipient of reports only to *us*. Use of Git and population proficient in Git would become wide enough that we should be able to expect that users who speak language X can be helped by experts who speak the same language X with their issues.

Emily Shaffer· Feb 25, 2020, 22:08 UTC · re: Junio C Hamano · lore

Re: [PATCH v8 07/15] bugreport: add git-remote-https version

On Thu, Feb 20, 2020 at 07:44:30PM -0800, Junio C Hamano wrote:
Show 12 quoted lines
> Emily Shaffer <emilyshaffer@google.com> writes:
> 
> > ... Unfortunately I agree that we wouldn't be equipped to handle
> > reports in other languages.
> 
> I actually was anticipating a far better world ;-) 
> 
> There is no reason to limit the recipient of reports only to *us*.
> Use of Git and population proficient in Git would become wide enough
> that we should be able to expect that users who speak language X can
> be helped by experts who speak the same language X with their
> issues.

Hm. I guess I got the opposite impression from you way back in v1. I do wish it had been communicated a little more clearly; it's frustrating to perceive a reversal after seven months of review. But that's probably on my own reading comprehension :)

Well, I certainly don't mind - but I did have a pretty long conversation with Jonathan Nieder last week about whether it's feasible to make the bugreport extremely stable while also being locale aware. As I understood it, he worried about someone having a misconfigured locale causing the bugreport tool to crash when it tries to set the locale.

But I'm having trouble figuring out how that can happen. It looks like we use libintl.h to do almost all of our string localization, which I have to assume is pretty robust. Or to put it another way, if the user's environment has broken libintl.h, then it seems like they also have bigger problems outside of Git which they would notice already.

(Side note: I went down a rabbit hole of trying to break my locale, and did manage to generate some garbage by setting 'LANG' to a non-UTF-8 character set and setting 'LANGUAGE' to a character set which does require UTF-8, that is, 'LANG=es_MX LANGUAGE=ko git status'.)

How about if I localize the bugreport template, headers, and formatted comments (e.g. "3745 local loose objects"), and include a tip in 'git help bugreport' suggesting that if it doesn't look right, maybe the user wants to run it with 'LANG= LANGUAGE= git bugreport' to ensure it actually gets generated?

I had another thought, actually, that this is maybe semantically similar problem to the malformed config we discussed earlier in the review. Does it make sense to include some kind of --safemode flag to 'git' which asks it to not perform localization and not read configs? I would propose adding it just to git-bugreport, and I could work around some locale weirdness that way, but with a broken config the attempt dies before git-bugreport binary is invoked at all.

 - Emily
Junio C Hamano· Feb 25, 2020, 22:26 UTC · re: Emily Shaffer · lore

Re: [PATCH v8 07/15] bugreport: add git-remote-https version

Emily Shaffer <emilyshaffer@google.com> writes:
Show 5 quoted lines
> How about if I localize the bugreport template, headers, and formatted
> comments (e.g. "3745 local loose objects"), and include a tip in 'git
> help bugreport' suggesting that if it doesn't look right, maybe the user
> wants to run it with 'LANG= LANGUAGE= git bugreport' to ensure it
> actually gets generated?

I think that will be what is going to happen anyway in the real world. We'd spend a reasonable effort for localization (and I personally am perfectly OK if the effort for the initial round is "almost zero"), but make sure C-locale is left as an escape hatch.

> I had another thought, actually, that this is maybe semantically similar
> problem to the malformed config we discussed earlier in the review. Does
> it make sense to include some kind of --safemode flag to 'git' which
> asks it to not perform localization and not read configs?

I suspect that "git --safemode" would always end up being buggy than running "git" under LANG=C LC_ALL=C GIT_CONFIG=/dev/null or something like that ;-)

Wouldn't it defeat more than 30% of the value of the tool if we do not read and report the contents of the configuration file(s)?

Emily Shaffer· Feb 25, 2020, 23:29 UTC · re: Junio C Hamano · lore

Re: [PATCH v8 07/15] bugreport: add git-remote-https version

On Tue, Feb 25, 2020 at 02:26:34PM -0800, Junio C Hamano wrote:
Show 12 quoted lines
> Emily Shaffer <emilyshaffer@google.com> writes:
> 
> > How about if I localize the bugreport template, headers, and formatted
> > comments (e.g. "3745 local loose objects"), and include a tip in 'git
> > help bugreport' suggesting that if it doesn't look right, maybe the user
> > wants to run it with 'LANG= LANGUAGE= git bugreport' to ensure it
> > actually gets generated?
> 
> I think that will be what is going to happen anyway in the real
> world.  We'd spend a reasonable effort for localization (and I
> personally am perfectly OK if the effort for the initial round is
> "almost zero"), but make sure C-locale is left as an escape hatch.
OK.
Show 12 quoted lines
> 
> > I had another thought, actually, that this is maybe semantically similar
> > problem to the malformed config we discussed earlier in the review. Does
> > it make sense to include some kind of --safemode flag to 'git' which
> > asks it to not perform localization and not read configs?
> 
> I suspect that "git --safemode" would always end up being buggy than
> running "git" under LANG=C LC_ALL=C GIT_CONFIG=/dev/null or something
> like that ;-)
> 
> Wouldn't it defeat more than 30% of the value of the tool if we
> do not read and report the contents of the configuration file(s)?

If you mean "the tool" = "Git", I won't argue with you. But if you mean "the tool" = "git-bugreport", I'd say that 70% of the value of the tool is better than 0% because my config is broken and I don't know why or how.

 - Emily
Junio C Hamano· Feb 25, 2020, 23:29 UTC · re: Emily Shaffer · lore

Re: [PATCH v8 07/15] bugreport: add git-remote-https version

Emily Shaffer <emilyshaffer@google.com> writes:
> Hm. I guess I got the opposite impression from you way back in v1. I do
> wish it had been communicated a little more clearly; it's frustrating to
> perceive a reversal after seven months of review. But that's probably on
> my own reading comprehension :)

Well, seven months is a long time for anybody to learn from repeated reading and gained experience to form an opinion and get affected by others' opinions. In any case, this is one of the reasons why I try to discourage people to have too many topics in flight before moving on to a new and different topic---the risk of ending up with fliping and flopping is just too high when you give people chance to forget. Rather, I'd prefer to see something simple to land first and then later refined.

On this particular issue, I actually do not have a preference. As long as the topic has a coherent position/stance, any one of

 (a) we do as much i18n as possible to help end-users, or
 (b) we stay away from i18n to ensure the reports are machine
     readable, or
 (c) somewhere in between with a clear criterion where you are
     drawing the line (e.g. "the introductory text is what we want
     the end-user to read, so it is i18ned, but the report about
     their environment are primarily for our use and we avoid
     localizing so that we can process mechanically"),

is fine. The important point is that we choose what we do with a solid guiding principle behind the decision.

In practice, every string in bugreport.c you have control over the use (or non-use) of _() around it, but codepaths that you call from existing parts of the system are likely to have their messages localized if they are meant for Porcelain use. So from that point of view, (a) would be easier to arrange than (b), I suspect.

Thanks.
Emily Shaffer· Feb 25, 2020, 23:55 UTC · re: Junio C Hamano · lore

Re: [PATCH v8 07/15] bugreport: add git-remote-https version

On Tue, Feb 25, 2020 at 03:29:08PM -0800, Junio C Hamano wrote:
Show 15 quoted lines
> Emily Shaffer <emilyshaffer@google.com> writes:
> 
> > Hm. I guess I got the opposite impression from you way back in v1. I do
> > wish it had been communicated a little more clearly; it's frustrating to
> > perceive a reversal after seven months of review. But that's probably on
> > my own reading comprehension :)
> 
> Well, seven months is a long time for anybody to learn from repeated
> reading and gained experience to form an opinion and get affected by
> others' opinions.  In any case, this is one of the reasons why I try
> to discourage people to have too many topics in flight before moving
> on to a new and different topic---the risk of ending up with fliping
> and flopping is just too high when you give people chance to forget.
> Rather, I'd prefer to see something simple to land first and then
> later refined.

I think it's exactly what happened with this topic. It's easy to say "don't have too many things out at once" in theory - but becomes less easy when you combine it with things like quarterly planning at dayjob, etc. In fact I have been trying to revive and push through old topics I had in flight because I had this same realization - my six topics were only each updated every month or so, meaning everyone (including me) forgot what was going on from revision to revision.

I wonder whether it makes sense to try and finalize the bare minimums of this feature, and then move the rest of the work to their own topics. I see a couple benefits:

 - Users can start trying out 'git bugreport' when they write us mails
   much sooner. Even the template alone would increase the quality of a
   number of the reports I see come into this list.
 - It may help insulate this topic from 'feature creep,' which in my
   opinion has plagued it from the start. While the entire topic of 15
   patches is in flux, it's hard for someone else to write their own
   patch adding, say, midex/commit-graph support, and so I feel
   obligated to write it myself - which of course increases the amount
   of time the topic lives on in review.
 - Of course smaller topics are easier to review, and a commit-graph
   expert is much more likely to click on the subject "[PATCH]
   bugreport: gather commit-graph diagnostics" than they are to click on
   the subject "[PATCH] add bugreport utility". That is, I'm guessing
   there will be more reviews on the semantics of the patch (is it the
   right diagnostic info? is it useful?) than there have been so far.

The downside is mailing list churn, and the possibility that with a minimum 'git-bugreport' checked in I find something better to do. I'm not too worried about the former; after all, that's what this list is for, right? As for the latter, after 7 months of flip and flop I don't think the risk is greater than it is now anyways ;) I think it makes sense to send the following topics:

/* To me, this sounds like minimum viable bugreport. "What went wrong,
 * and how do I build the same binary as you so I can reproduce it?"
add git-bugreport tool:
 - bugreport: add tool to generate debugging info
 - bugreport: gather git version and build info
 - bugreport: add uname info
 - bugreport: add compiler info
bugreport: add git-remote-https version
bugreport: include shell info
 - help: add shell-path to --build-options
 - bugreport: include user interactive shell
bugreport: include config info
 - help: move list_config_help to builtin/help
 - bugreport: generate config safelist based on docs
 - bugreport: add config values from safelist
bugreport: collect list of populated hooks
bugreport: include object store info
 - bugreport: count loose objects
 - bugreport: add packed object summary
 - bugreport: list contents of $OBJDIR/info

I'd like to send that first topic as vN+1 of this one, and I can hold the rest of the branches locally until we get it ironed out; once that topic makes it through to 'next' then I can send the rest again. What do you think?

Show 22 quoted lines
> On this particular issue, I actually do not have a preference.  As
> long as the topic has a coherent position/stance, any one of
> 
>  (a) we do as much i18n as possible to help end-users, or
> 
>  (b) we stay away from i18n to ensure the reports are machine
>      readable, or
> 
>  (c) somewhere in between with a clear criterion where you are
>      drawing the line (e.g. "the introductory text is what we want
>      the end-user to read, so it is i18ned, but the report about
>      their environment are primarily for our use and we avoid
>      localizing so that we can process mechanically"),
> 
> is fine.  The important point is that we choose what we do with a
> solid guiding principle behind the decision.
> 
> In practice, every string in bugreport.c you have control over the
> use (or non-use) of _() around it, but codepaths that you call from
> existing parts of the system are likely to have their messages
> localized if they are meant for Porcelain use.  So from that point
> of view, (a) would be easier to arrange than (b), I suspect.
Hm. Sounds convincing enough to me.
 - Emily
Emily Shaffer· Feb 20, 2020, 01:58 UTC · re: Emily Shaffer · lore

[PATCH v8 08/15] bugreport: include user interactive shell

It's possible a user may complain about the way that Git interacts with their interactive shell, e.g. autocompletion or shell prompt. In that case, it's useful for us to know which shell they're using interactively.

Signed-off-by: Emily Shaffer <emilyshaffer@google.com>
---
 Documentation/git-bugreport.txt | 1 +
 bugreport.c                     | 5 +++++
 2 files changed, 6 insertions(+)
Show changes to 2 files +6 −0

Documentation/git-bugreport.txt, bugreport.c

diff --git a/Documentation/git-bugreport.txt b/Documentation/git-bugreport.txt
index 8c7cb9a5d4..f7a13c0374 100644
--- a/Documentation/git-bugreport.txt
+++ b/Documentation/git-bugreport.txt
@@ -29,6 +29,7 @@ The following information is captured automatically:
  - uname sysname, release, version, and machine strings
  - Compiler-specific info string
  - 'git remote-https --build-info'
+ - $SHELL
 
 This tool is invoked via the typical Git setup process, which means that in some
 cases, it might not be able to launch - for example, if a relevant config file
diff --git a/bugreport.c b/bugreport.c
index fb2adfdf14..f143b9a8f8 100644
--- a/bugreport.c
+++ b/bugreport.c
@@ -21,6 +21,7 @@ static void get_git_remote_https_version_info(struct strbuf *version_info)
 static void get_system_info(struct strbuf *sys_info)
 {
 	struct utsname uname_info;
+	char *shell = NULL;
 
 	/* get git version from native cmd */
 	strbuf_addstr(sys_info, "git version:\n");
@@ -42,6 +43,10 @@ static void get_system_info(struct strbuf *sys_info)
 	get_compiler_info(sys_info);
 	strbuf_complete_line(sys_info);
 
+	shell = getenv("SHELL");
+	strbuf_addf(sys_info, "$SHELL (typically, interactive shell): %s\n",
+		    shell ? shell : "<unset>");
+
 	strbuf_addstr(sys_info, "git-remote-https --build-info:\n");
 	get_git_remote_https_version_info(sys_info);
 	strbuf_complete_line(sys_info);
-- 
2.25.0.265.gbab2e86ba0-goog
Emily Shaffer· Feb 20, 2020, 01:58 UTC · re: Emily Shaffer · lore

[PATCH v8 09/15] bugreport: generate config safelist based on docs

Add a new step to the build to generate a safelist of git-config variables which are appropriate to include in the output of git-bugreport. New variables can be added to the safelist by annotating their documentation in Documentation/config with the "annotate" macro, which is a no-op in AsciiDoc and AsciiDoctor.

Some configs are private in nature, and can contain remote URLs, passwords, or other sensitive information. In the event that a user doesn't notice their information while reviewing a bugreport, that user may leak their credentials to other individuals, mailing lists, or bug tracking tools inadvertently. Heuristic blocklisting of configuration keys is imperfect and prone to false negatives; given the nature of the information which can be leaked, a safelist is more reliable.

However, it's possible that in some situations, an organization may be less concerned with privacy of things like remote URLs and branch names, and more concerned with ease of diagnosis for their support staff. In those cases, it may make more sense for that organization to modify the code to use a blocklist. To that end, we should try to mark configs which are definitely safe, and configs which are definitely unsafe, and leave blank configs which are somewhere in between. To mark a config as safe, add "annotate:bugreport[include]" to the corresponding line in the config documentation; to mark it as unsafe, add "annotate:bugreport[exclude]" instead.

Generating bugreport-config-safelist.h at build time by grepping the documentation for this new macro helps us prevent staleness. The macro itself is a no-op and should not alter the appearance of the documentation in either AsciiDoc or AsciiDoctor, confirmable by running:

  cd Documentation
  ./doc-diff --asciidoctor HEAD^ HEAD
  ./doc-diff --asciidoc HEAD^ HEAD

Diffing the rendered HTML shows that only inline comments were added, which shouldn't be a problem.

Additionally, add annotations to the sendemail config documentation in order to demonstrate a proof of concept.

Helped-by: Martin Ågren <martin.agren@gmail.com>
Helped-by: Johannes Schindelin <Johannes.Schindelin@gmx.de>
Signed-off-by: Emily Shaffer <emilyshaffer@google.com>
---
 .gitignore                              |  1 +
 Documentation/asciidoc.conf             |  9 ++++
 Documentation/asciidoctor-extensions.rb |  7 ++++
 Documentation/config/sendemail.txt      | 56 ++++++++++++-------------
 Makefile                                |  7 ++++
 generate-bugreport-config-safelist.sh   | 18 ++++++++
 6 files changed, 70 insertions(+), 28 deletions(-)
 create mode 100755 generate-bugreport-config-safelist.sh
Show changes to 6 files +70 −28

.gitignore, Documentation/asciidoc.conf, Documentation/asciidoctor-extensions.rb, Documentation/config/sendemail.txt, Makefile, generate-bugreport-config-safelist.sh

diff --git a/.gitignore b/.gitignore
index d89bf9e11e..bd2f49b996 100644
--- a/.gitignore
+++ b/.gitignore
@@ -192,6 +192,7 @@
 /gitweb/static/gitweb.min.*
 /config-list.h
 /command-list.h
+/bugreport-config-safelist.h
 *.tar.gz
 *.dsc
 *.deb
diff --git a/Documentation/asciidoc.conf b/Documentation/asciidoc.conf
index 8fc4b67081..663e06481f 100644
--- a/Documentation/asciidoc.conf
+++ b/Documentation/asciidoc.conf
@@ -6,9 +6,14 @@
 #
 # Show Git link as: <command>(<section>); if section is defined, else just show
 # the command.
+#
+# The annotate macro does nothing as far as rendering is
+# concerned -- we just grep for it in the sources to populate
+# things like the bugreport safelist.
 
 [macros]
 (?su)[\\]?(?P<name>linkgit):(?P<target>\S*?)\[(?P<attrlist>.*?)\]=
+(?su)[\\]?(?P<name>annotate):(?P<target>\S*?)\[(?P<attrlist>.*?)\]=
 
 [attributes]
 asterisk=&#42;
@@ -28,6 +33,8 @@ ifdef::backend-docbook[]
 {0#<citerefentry>}
 {0#<refentrytitle>{target}</refentrytitle><manvolnum>{0}</manvolnum>}
 {0#</citerefentry>}
+[annotate-inlinemacro]
+{0#}
 endif::backend-docbook[]
 
 ifdef::backend-docbook[]
@@ -94,4 +101,6 @@ ifdef::backend-xhtml11[]
 git-relative-html-prefix=
 [linkgit-inlinemacro]
 <a href="{git-relative-html-prefix}{target}.html">{target}{0?({0})}</a>
+[annotate-inlinemacro]
+<!-- -->
 endif::backend-xhtml11[]
diff --git a/Documentation/asciidoctor-extensions.rb b/Documentation/asciidoctor-extensions.rb
index d906a00803..03c80af0e5 100644
--- a/Documentation/asciidoctor-extensions.rb
+++ b/Documentation/asciidoctor-extensions.rb
@@ -39,10 +39,17 @@ module Git
         output
       end
     end
+
+    class AnnotateProcessor < Asciidoctor::Extensions::InlineMacroProcessor
+      def process(parent, target, attrs)
+        ""
+      end
+    end
   end
 end
 
 Asciidoctor::Extensions.register do
   inline_macro Git::Documentation::LinkGitProcessor, :linkgit
   postprocessor Git::Documentation::DocumentPostProcessor
+  inline_macro Git::Documentation::AnnotateProcessor, :annotate
 end
diff --git a/Documentation/config/sendemail.txt b/Documentation/config/sendemail.txt
index 0006faf800..fe27473e44 100644
--- a/Documentation/config/sendemail.txt
+++ b/Documentation/config/sendemail.txt
@@ -4,7 +4,7 @@ sendemail.identity::
 	values in the 'sendemail' section. The default identity is
 	the value of `sendemail.identity`.
 
-sendemail.smtpEncryption::
+sendemail.smtpEncryption annotate:bugreport[include] ::
 	See linkgit:git-send-email[1] for description.  Note that this
 	setting is not subject to the 'identity' mechanism.
 
@@ -15,7 +15,7 @@ sendemail.smtpsslcertpath::
 	Path to ca-certificates (either a directory or a single file).
 	Set it to an empty string to disable certificate verification.
 
-sendemail.<identity>.*::
+sendemail.<identity>.* annotate:bugreport[exclude] ::
 	Identity-specific versions of the 'sendemail.*' parameters
 	found below, taking precedence over those when this
 	identity is selected, through either the command-line or
@@ -23,41 +23,41 @@ sendemail.<identity>.*::
 
 sendemail.aliasesFile::
 sendemail.aliasFileType::
-sendemail.annotate::
-sendemail.bcc::
-sendemail.cc::
-sendemail.ccCmd::
-sendemail.chainReplyTo::
-sendemail.confirm::
-sendemail.envelopeSender::
-sendemail.from::
-sendemail.multiEdit::
-sendemail.signedoffbycc::
-sendemail.smtpPass::
-sendemail.suppresscc::
-sendemail.suppressFrom::
-sendemail.to::
-sendemail.tocmd::
-sendemail.smtpDomain::
-sendemail.smtpServer::
-sendemail.smtpServerPort::
-sendemail.smtpServerOption::
-sendemail.smtpUser::
-sendemail.thread::
-sendemail.transferEncoding::
-sendemail.validate::
-sendemail.xmailer::
+sendemail.annotate annotate:bugreport[include] ::
+sendemail.bcc annotate:bugreport[include] ::
+sendemail.cc annotate:bugreport[include] ::
+sendemail.ccCmd annotate:bugreport[include] ::
+sendemail.chainReplyTo annotate:bugreport[include] ::
+sendemail.confirm annotate:bugreport[include] ::
+sendemail.envelopeSender annotate:bugreport[include] ::
+sendemail.from annotate:bugreport[include] ::
+sendemail.multiEdit annotate:bugreport[include] ::
+sendemail.signedoffbycc annotate:bugreport[include] ::
+sendemail.smtpPass annotate:bugreport[exclude] ::
+sendemail.suppresscc annotate:bugreport[include] ::
+sendemail.suppressFrom annotate:bugreport[include] ::
+sendemail.to annotate:bugreport[include] ::
+sendemail.tocmd annotate:bugreport[include] ::
+sendemail.smtpDomain annotate:bugreport[include] ::
+sendemail.smtpServer annotate:bugreport[include] ::
+sendemail.smtpServerPort annotate:bugreport[include] ::
+sendemail.smtpServerOption annotate:bugreport[include] ::
+sendemail.smtpUser annotate:bugreport[exclude] ::
+sendemail.thread annotate:bugreport[include] ::
+sendemail.transferEncoding annotate:bugreport[include] ::
+sendemail.validate annotate:bugreport[include] ::
+sendemail.xmailer annotate:bugreport[include] ::
 	See linkgit:git-send-email[1] for description.
 
 sendemail.signedoffcc (deprecated)::
 	Deprecated alias for `sendemail.signedoffbycc`.
 
-sendemail.smtpBatchSize::
+sendemail.smtpBatchSize annotate:bugreport[include] ::
 	Number of messages to be sent per connection, after that a relogin
 	will happen.  If the value is 0 or undefined, send all messages in
 	one connection.
 	See also the `--batch-size` option of linkgit:git-send-email[1].
 
-sendemail.smtpReloginDelay::
+sendemail.smtpReloginDelay annotate:bugreport[include] ::
 	Seconds wait before reconnecting to smtp server.
 	See also the `--relogin-delay` option of linkgit:git-send-email[1].
diff --git a/Makefile b/Makefile
index 9e6705061d..6bdd3b9337 100644
--- a/Makefile
+++ b/Makefile
@@ -818,6 +818,7 @@ VCSSVN_LIB = vcs-svn/lib.a
 
 GENERATED_H += config-list.h
 GENERATED_H += command-list.h
+GENERATED_H += bugreport-config-safelist.h
 
 LIB_H := $(sort $(patsubst ./%,%,$(shell git ls-files '*.h' ':!t/' ':!Documentation/' 2>/dev/null || \
 	$(FIND) . \
@@ -2167,6 +2168,12 @@ command-list.h: $(wildcard Documentation/git*.txt) Documentation/*config.txt Doc
 		$(patsubst %,--exclude-program %,$(EXCLUDED_PROGRAMS)) \
 		command-list.txt >$@+ && mv $@+ $@
 
+bugreport-config-safelist.h: generate-bugreport-config-safelist.sh
+
+bugreport-config-safelist.h: Documentation/config/*.txt
+	$(QUIET_GEN)$(SHELL_PATH) ./generate-bugreport-config-safelist.sh \
+		>$@+ && mv $@+ $@
+
 SCRIPT_DEFINES = $(SHELL_PATH_SQ):$(DIFF_SQ):$(GIT_VERSION):\
 	$(localedir_SQ):$(NO_CURL):$(USE_GETTEXT_SCHEME):$(SANE_TOOL_PATH_SQ):\
 	$(gitwebdir_SQ):$(PERL_PATH_SQ):$(SANE_TEXT_GREP):$(PAGER_ENV):\
diff --git a/generate-bugreport-config-safelist.sh b/generate-bugreport-config-safelist.sh
new file mode 100755
index 0000000000..a9e5b6b2a0
--- /dev/null
+++ b/generate-bugreport-config-safelist.sh
@@ -0,0 +1,18 @@
+#!/bin/sh
+
+cat <<EOF
+/* Automatically generated by bugreport-generate-config-safelist.sh */
+
+
+static const char *bugreport_config_safelist[] = {
+EOF
+
+# cat all regular files in Documentation/config
+find Documentation/config -type f -exec cat {} \; |
+# print the command name which matches the annotate-bugreport macro
+sed -n 's/^\([^ ]*\)  *annotate:bugreport\[include\].* ::$/  "\1",/p' \
+	| sort
+
+cat <<EOF
+};
+EOF
-- 
2.25.0.265.gbab2e86ba0-goog
Junio C Hamano· Feb 20, 2020, 20:40 UTC · re: Emily Shaffer · lore

Re: [PATCH v8 09/15] bugreport: generate config safelist based on docs

Emily Shaffer <emilyshaffer@google.com> writes:
Show 6 quoted lines
> --- /dev/null
> +++ b/generate-bugreport-config-safelist.sh
> @@ -0,0 +1,18 @@
> +#!/bin/sh
> +
> +cat <<EOF
Quote the EOF if you are not doing parameter expansion in HERE-DOC.
Show 12 quoted lines
> +/* Automatically generated by bugreport-generate-config-safelist.sh */
> +
> +
> +static const char *bugreport_config_safelist[] = {
> +EOF
> +
> +# cat all regular files in Documentation/config
> +find Documentation/config -type f -exec cat {} \; |
> +# print the command name which matches the annotate-bugreport macro
> +sed -n 's/^\([^ ]*\)  *annotate:bugreport\[include\].* ::$/  "\1",/p' \
> +	| sort
> +

End the first line with a pipe '|' instead of a backslash, and lose the pipe from the beginning of the second line.

> +cat <<EOF
> +};
> +EOF
Johannes Schindelin· Feb 26, 2020, 16:13 UTC · re: Emily Shaffer · lore

Re: [PATCH v8 09/15] bugreport: generate config safelist based on docs

Hi Emily,
On Wed, 19 Feb 2020, Emily Shaffer wrote:
Show 12 quoted lines
> diff --git a/Makefile b/Makefile
> index 9e6705061d..6bdd3b9337 100644
> --- a/Makefile
> +++ b/Makefile
> @@ -818,6 +818,7 @@ VCSSVN_LIB = vcs-svn/lib.a
>
>  GENERATED_H += config-list.h
>  GENERATED_H += command-list.h
> +GENERATED_H += bugreport-config-safelist.h
>
>  LIB_H := $(sort $(patsubst ./%,%,$(shell git ls-files '*.h' ':!t/' ':!Documentation/' 2>/dev/null || \
>  	$(FIND) . \

In order to pretend that we actually care about developers on Windows, let's squash this in?

-- snipsnap --
Subject: [PATCH] fixup??? bugreport: generate config safelist based on docs

The Visual Studio build is a special beast: as we cannot assume the presence of any Unix tools on Windows, we have to commit all of the files generated via shell scripts.

These two generated header files are no exception.
Signed-off-by: Johannes Schindelin <johannes.schindelin@gmx.de>
---
 config.mak.uname | 6 ++++--
 1 file changed, 4 insertions(+), 2 deletions(-)
Show changes to config.mak.uname +4 −3
diff --git a/config.mak.uname b/config.mak.uname
index 6d58d22cd5a..f1f36e43e47 100644
--- a/config.mak.uname
+++ b/config.mak.uname
@@ -788,8 +788,10 @@ vcxproj:
 	git add -f git/LinkOrCopyBuiltins.targets git-remote-http/LinkOrCopyRemoteHttp.targets

 	# Add command-list.h
-	$(MAKE) MSVC=1 SKIP_VCPKG=1 prefix=/mingw64 command-list.h
-	git add -f command-list.h
+	$(MAKE) MSVC=1 SKIP_VCPKG=1 prefix=/mingw64 command-list.h \
+		config-list.h bugreport-config-safelist.h
+	git add -f command-list.h \
+	 	config-list.h bugreport-config-safelist.h

 	# Add scripts
 	rm -f perl/perl.mak
--
2.25.1.windows.1
Junio C Hamano· Feb 26, 2020, 16:49 UTC · re: Johannes Schindelin · lore

Re: [PATCH v8 09/15] bugreport: generate config safelist based on docs

Johannes Schindelin <Johannes.Schindelin@gmx.de> writes:
Show 27 quoted lines
> Subject: [PATCH] fixup??? bugreport: generate config safelist based on docs
>
> The Visual Studio build is a special beast: as we cannot assume the
> presence of any Unix tools on Windows, we have to commit all of the
> files generated via shell scripts.
>
> These two generated header files are no exception.
>
> Signed-off-by: Johannes Schindelin <johannes.schindelin@gmx.de>
> ---
>  config.mak.uname | 6 ++++--
>  1 file changed, 4 insertions(+), 2 deletions(-)
>
> diff --git a/config.mak.uname b/config.mak.uname
> index 6d58d22cd5a..f1f36e43e47 100644
> --- a/config.mak.uname
> +++ b/config.mak.uname
> @@ -788,8 +788,10 @@ vcxproj:
>  	git add -f git/LinkOrCopyBuiltins.targets git-remote-http/LinkOrCopyRemoteHttp.targets
>
>  	# Add command-list.h
> -	$(MAKE) MSVC=1 SKIP_VCPKG=1 prefix=/mingw64 command-list.h
> -	git add -f command-list.h
> +	$(MAKE) MSVC=1 SKIP_VCPKG=1 prefix=/mingw64 command-list.h \
> +		config-list.h bugreport-config-safelist.h
> +	git add -f command-list.h \
> +	 	config-list.h bugreport-config-safelist.h
Two important questions are 
 - Is $(GENERATED_H) visible to you at this point in this makefile
   snippet that is included from the main Makefile?
 - Currently the list of files listed on $(GENERATED_H) match what
   you are building and adding here.  Is there a reason to believe
   two would ever diverge?

If the answers to the above are yes and no, there is an obvious futureproofing of the suggested patch, i.e.

- $(MAKE) MSVC=1 SKIP_VCPKG=1 prefix=/mingw64 command-list.h - git add -f command-list.h + $(MAKE) MSVC=1 SKIP_VCPKG=1 prefix=/mingw64 $(GENERATED_H) + git add -f $(GENERATED_H)

Emily Shaffer· Feb 20, 2020, 01:58 UTC · re: Emily Shaffer · lore

[PATCH v8 10/15] bugreport: add config values from safelist

Teach bugreport to gather the values of config options which are present in 'bugreport-config-safelist.h', and show their origin scope.

Many config options are sensitive, and many Git add-ons use config options which git-core does not know about; it is better only to gather config options which we know to be safe, rather than excluding options which we know to be unsafe.

Rather than including the path to someone's config, which can reveal filesystem layout and project names, just name the scope (e.g. system, global, local) of the config source.

Signed-off-by: Emily Shaffer <emilyshaffer@google.com>
---
 Documentation/git-bugreport.txt |  1 +
 Makefile                        |  2 ++
 bugreport.c                     | 34 +++++++++++++++++++++++++++++++++
 3 files changed, 37 insertions(+)
Show changes to 3 files +37 −0

Documentation/git-bugreport.txt, Makefile, bugreport.c

diff --git a/Documentation/git-bugreport.txt b/Documentation/git-bugreport.txt
index f7a13c0374..efe9719ea4 100644
--- a/Documentation/git-bugreport.txt
+++ b/Documentation/git-bugreport.txt
@@ -30,6 +30,7 @@ The following information is captured automatically:
  - Compiler-specific info string
  - 'git remote-https --build-info'
  - $SHELL
+ - Selected config values
 
 This tool is invoked via the typical Git setup process, which means that in some
 cases, it might not be able to launch - for example, if a relevant config file
diff --git a/Makefile b/Makefile
index 6bdd3b9337..bf4f3ede2a 100644
--- a/Makefile
+++ b/Makefile
@@ -2135,6 +2135,8 @@ git$X: git.o GIT-LDFLAGS $(BUILTIN_OBJS) $(GITLIBS)
 
 help.sp help.s help.o: command-list.h
 
+bugreport.sp bugreport.s bugreport.o: bugreport-config-safelist.h
+
 builtin/help.sp builtin/help.s builtin/help.o: config-list.h GIT-PREFIX
 builtin/help.sp builtin/help.s builtin/help.o: EXTRA_CPPFLAGS = \
 	'-DGIT_HTML_PATH="$(htmldir_relative_SQ)"' \
diff --git a/bugreport.c b/bugreport.c
index f143b9a8f8..70fb3b8fa6 100644
--- a/bugreport.c
+++ b/bugreport.c
@@ -6,6 +6,9 @@
 #include "help.h"
 #include "compat/compiler.h"
 #include "run-command.h"
+#include "config.h"
+#include "bugreport-config-safelist.h"
+#include "khash.h"
 
 static void get_git_remote_https_version_info(struct strbuf *version_info)
 {
@@ -52,6 +55,29 @@ static void get_system_info(struct strbuf *sys_info)
 	strbuf_complete_line(sys_info);
 }
 
+static void get_safelisted_config(struct strbuf *config_info)
+{
+	size_t idx;
+	struct string_list_item *it = NULL;
+	struct key_value_info *kv_info = NULL;
+
+	for (idx = 0; idx < ARRAY_SIZE(bugreport_config_safelist); idx++) {
+		const struct string_list *list =
+			git_config_get_value_multi(bugreport_config_safelist[idx]);
+
+		if (!list)
+			continue;
+
+		strbuf_addf(config_info, "%s:\n", bugreport_config_safelist[idx]);
+		for_each_string_list_item(it, list) {
+			kv_info = it->util;
+			strbuf_addf(config_info, "  %s (%s)\n", it->string,
+				    kv_info ? config_scope_name(kv_info->scope)
+					    : "source unknown");
+		}
+	}
+}
+
 static const char * const bugreport_usage[] = {
 	N_("git bugreport [-o|--output-directory <file>] [-s|--suffix <format>]"),
 	NULL
@@ -94,6 +120,7 @@ int cmd_main(int argc, const char **argv)
 	char *option_output = NULL;
 	char *option_suffix = "%F-%H%M";
 	struct stat statbuf;
+	int nongit_ok = 0;
 
 	const struct option bugreport_options[] = {
 		OPT_STRING('o', "output-directory", &option_output, N_("path"),
@@ -102,6 +129,10 @@ int cmd_main(int argc, const char **argv)
 			   N_("specify a strftime format suffix for the filename")),
 		OPT_END()
 	};
+
+	/* Prerequisite for hooks and config checks */
+	setup_git_directory_gently(&nongit_ok);
+
 	argc = parse_options(argc, argv, "", bugreport_options,
 			     bugreport_usage, 0);
 
@@ -132,6 +163,9 @@ int cmd_main(int argc, const char **argv)
 	get_header(&buffer, "System Info");
 	get_system_info(&buffer);
 
+	get_header(&buffer, "Safelisted Config Info");
+	get_safelisted_config(&buffer);
+
 	report = fopen_for_writing(report_path.buf);
 
 	if (report == NULL) {
-- 
2.25.0.265.gbab2e86ba0-goog
Junio C Hamano· Feb 20, 2020, 20:47 UTC · re: Emily Shaffer · lore

Re: [PATCH v8 10/15] bugreport: add config values from safelist

Emily Shaffer <emilyshaffer@google.com> writes:
Show 15 quoted lines
> @@ -94,6 +120,7 @@ int cmd_main(int argc, const char **argv)
>  	char *option_output = NULL;
>  	char *option_suffix = "%F-%H%M";
>  	struct stat statbuf;
> +	int nongit_ok = 0;
>  
>  	const struct option bugreport_options[] = {
>  		OPT_STRING('o', "output-directory", &option_output, N_("path"),
> @@ -102,6 +129,10 @@ int cmd_main(int argc, const char **argv)
>  			   N_("specify a strftime format suffix for the filename")),
>  		OPT_END()
>  	};
> +
> +	/* Prerequisite for hooks and config checks */
> +	setup_git_directory_gently(&nongit_ok);

Now this starts to break "-o" option when the command is run from a subdirectory of a git working tree, I suspect.

The setup() will discover that you are in a Git controlled working tree, goes up to the top-level of the working tree, so a user may expect

	cd t && git bugreport -o frotz

to create a new directory t/frotz, but it would instead create the directory frotz next to t/, no?

Using OPT_FILENAME and feeding correct prefix to parse_options() will correct this.

>  	argc = parse_options(argc, argv, "", bugreport_options,
>  			     bugreport_usage, 0);
Emily Shaffer· Feb 20, 2020, 01:58 UTC · re: Emily Shaffer · lore

[PATCH v8 11/15] bugreport: collect list of populated hooks

Occasionally a failure a user is seeing may be related to a specific hook which is being run, perhaps without the user realizing. While the contents of hooks can be sensitive - containing user data or process information specific to the user's organization - simply knowing that a hook is being run at a certain stage can help us to understand whether something is going wrong.

Without a definitive list of hook names within the code, we compile our own list from the documentation. This is likely prone to bitrot. To reduce the amount of code humans need to read, we turn the list into a string_list and iterate over it (as we are calling the same find_hook operation on each string). However, since bugreport should primarily be called by the user, the performance loss from massaging the string seems acceptable.

Signed-off-by: Emily Shaffer <emilyshaffer@google.com>
---
 Documentation/git-bugreport.txt |  1 +
 bugreport.c                     | 53 +++++++++++++++++++++++++++++++++
 2 files changed, 54 insertions(+)
Show changes to 2 files +54 −0

Documentation/git-bugreport.txt, bugreport.c

diff --git a/Documentation/git-bugreport.txt b/Documentation/git-bugreport.txt
index efe9719ea4..4d01528540 100644
--- a/Documentation/git-bugreport.txt
+++ b/Documentation/git-bugreport.txt
@@ -31,6 +31,7 @@ The following information is captured automatically:
  - 'git remote-https --build-info'
  - $SHELL
  - Selected config values
+ - A list of enabled hooks
 
 This tool is invoked via the typical Git setup process, which means that in some
 cases, it might not be able to launch - for example, if a relevant config file
diff --git a/bugreport.c b/bugreport.c
index 70fb3b8fa6..b5a0714a7f 100644
--- a/bugreport.c
+++ b/bugreport.c
@@ -9,6 +9,7 @@
 #include "config.h"
 #include "bugreport-config-safelist.h"
 #include "khash.h"
+#include "run-command.h"
 
 static void get_git_remote_https_version_info(struct strbuf *version_info)
 {
@@ -78,6 +79,55 @@ static void get_safelisted_config(struct strbuf *config_info)
 	}
 }
 
+static void get_populated_hooks(struct strbuf *hook_info, int nongit)
+{
+	/*
+	 * Doesn't look like there is a list of all possible hooks; so below is
+	 * a transcription of `git help hooks`.
+	 */
+	const char *hooks = "applypatch-msg,"
+			    "pre-applypatch,"
+			    "post-applypatch,"
+			    "pre-commit,"
+			    "pre-merge-commit,"
+			    "prepare-commit-msg,"
+			    "commit-msg,"
+			    "post-commit,"
+			    "pre-rebase,"
+			    "post-checkout,"
+			    "post-merge,"
+			    "pre-push,"
+			    "pre-receive,"
+			    "update,"
+			    "post-receive,"
+			    "post-update,"
+			    "push-to-checkout,"
+			    "pre-auto-gc,"
+			    "post-rewrite,"
+			    "sendemail-validate,"
+			    "fsmonitor-watchman,"
+			    "p4-pre-submit,"
+			    "post-index-changex";
+	struct string_list hooks_list = STRING_LIST_INIT_DUP;
+	struct string_list_item *iter = NULL;
+
+
+	if (nongit) {
+		strbuf_addstr(hook_info,
+			"not run from a git repository - no hooks to show\n");
+		return;
+	}
+
+	string_list_split(&hooks_list, hooks, ',', -1);
+
+	for_each_string_list_item(iter, &hooks_list) {
+		if (find_hook(iter->string)) {
+			strbuf_addstr(hook_info, iter->string);
+			strbuf_complete_line(hook_info);
+		}
+	}
+}
+
 static const char * const bugreport_usage[] = {
 	N_("git bugreport [-o|--output-directory <file>] [-s|--suffix <format>]"),
 	NULL
@@ -166,6 +216,9 @@ int cmd_main(int argc, const char **argv)
 	get_header(&buffer, "Safelisted Config Info");
 	get_safelisted_config(&buffer);
 
+	get_header(&buffer, "Enabled Hooks");
+	get_populated_hooks(&buffer, nongit_ok);
+
 	report = fopen_for_writing(report_path.buf);
 
 	if (report == NULL) {
-- 
2.25.0.265.gbab2e86ba0-goog
Junio C Hamano· Feb 20, 2020, 20:58 UTC · re: Emily Shaffer · lore

Re: [PATCH v8 11/15] bugreport: collect list of populated hooks

Emily Shaffer <emilyshaffer@google.com> writes:
Show 6 quoted lines
> +static void get_populated_hooks(struct strbuf *hook_info, int nongit)
> +{
> +	/*
> +	 * Doesn't look like there is a list of all possible hooks; so below is
> +	 * a transcription of `git help hooks`.
> +	 */
It may want to become a NEEDSWORK comment.
Show 23 quoted lines
> +	const char *hooks = "applypatch-msg,"
> +			    "pre-applypatch,"
> +			    "post-applypatch,"
> +			    "pre-commit,"
> +			    "pre-merge-commit,"
> +			    "prepare-commit-msg,"
> +			    "commit-msg,"
> +			    "post-commit,"
> +			    "pre-rebase,"
> +			    "post-checkout,"
> +			    "post-merge,"
> +			    "pre-push,"
> +			    "pre-receive,"
> +			    "update,"
> +			    "post-receive,"
> +			    "post-update,"
> +			    "push-to-checkout,"
> +			    "pre-auto-gc,"
> +			    "post-rewrite,"
> +			    "sendemail-validate,"
> +			    "fsmonitor-watchman,"
> +			    "p4-pre-submit,"
> +			    "post-index-changex";
Typo here?
Show 13 quoted lines
> +	struct string_list hooks_list = STRING_LIST_INIT_DUP;
> +	struct string_list_item *iter = NULL;
> +
> +
> +	if (nongit) {
> +		strbuf_addstr(hook_info,
> +			"not run from a git repository - no hooks to show\n");
> +		return;
> +	}
> +
> +	string_list_split(&hooks_list, hooks, ',', -1);
> +
> +	for_each_string_list_item(iter, &hooks_list) {

I do not get why you want to use string_list for this, especially if you need to use string_list_split.

To me,
	int i;
	const char *hook[] = {
		"applypatch-msg",
	        "pre-applypatch",
		...
		"post-index-change",
	};
	for (i = 0; i < ARRAY_SIZE(hook); i++) {
		if (hook[i] is enabled)
			strbuf_addf(hook_info, "%s\n", hook[i]);
	}

would be far easier to understand. Do you have an external source that can feed you a single long string of comma separated hook names in mind, so that the initialization of *hooks will become simpler that way, or something?

Show 20 quoted lines
> +		if (find_hook(iter->string)) {
> +			strbuf_addstr(hook_info, iter->string);
> +			strbuf_complete_line(hook_info);
> +		}
> +	}
> +}
> +
>  static const char * const bugreport_usage[] = {
>  	N_("git bugreport [-o|--output-directory <file>] [-s|--suffix <format>]"),
>  	NULL
> @@ -166,6 +216,9 @@ int cmd_main(int argc, const char **argv)
>  	get_header(&buffer, "Safelisted Config Info");
>  	get_safelisted_config(&buffer);
>  
> +	get_header(&buffer, "Enabled Hooks");
> +	get_populated_hooks(&buffer, nongit_ok);
> +
>  	report = fopen_for_writing(report_path.buf);
>  
>  	if (report == NULL) {
Emily Shaffer· Feb 25, 2020, 23:19 UTC · re: Junio C Hamano · lore

Re: [PATCH v8 11/15] bugreport: collect list of populated hooks

On Thu, Feb 20, 2020 at 12:58:32PM -0800, Junio C Hamano wrote:
Show 10 quoted lines
> Emily Shaffer <emilyshaffer@google.com> writes:
> 
> > +static void get_populated_hooks(struct strbuf *hook_info, int nongit)
> > +{
> > +	/*
> > +	 * Doesn't look like there is a list of all possible hooks; so below is
> > +	 * a transcription of `git help hooks`.
> > +	 */
> 
> It may want to become a NEEDSWORK comment.
Oh, good point. I'll rephrase it.
Show 26 quoted lines
> 
> > +	const char *hooks = "applypatch-msg,"
> > +			    "pre-applypatch,"
> > +			    "post-applypatch,"
> > +			    "pre-commit,"
> > +			    "pre-merge-commit,"
> > +			    "prepare-commit-msg,"
> > +			    "commit-msg,"
> > +			    "post-commit,"
> > +			    "pre-rebase,"
> > +			    "post-checkout,"
> > +			    "post-merge,"
> > +			    "pre-push,"
> > +			    "pre-receive,"
> > +			    "update,"
> > +			    "post-receive,"
> > +			    "post-update,"
> > +			    "push-to-checkout,"
> > +			    "pre-auto-gc,"
> > +			    "post-rewrite,"
> > +			    "sendemail-validate,"
> > +			    "fsmonitor-watchman,"
> > +			    "p4-pre-submit,"
> > +			    "post-index-changex";
> 
> Typo here?
Yep, I imagine from trying to press 'x' to remove the ',' from my list.
Show 37 quoted lines
> 
> > +	struct string_list hooks_list = STRING_LIST_INIT_DUP;
> > +	struct string_list_item *iter = NULL;
> > +
> > +
> > +	if (nongit) {
> > +		strbuf_addstr(hook_info,
> > +			"not run from a git repository - no hooks to show\n");
> > +		return;
> > +	}
> > +
> > +	string_list_split(&hooks_list, hooks, ',', -1);
> > +
> > +	for_each_string_list_item(iter, &hooks_list) {
> 
> I do not get why you want to use string_list for this, especially if
> you need to use string_list_split.
> 
> To me,
> 
> 	int i;
> 	const char *hook[] = {
> 		"applypatch-msg",
> 	        "pre-applypatch",
> 		...
> 		"post-index-change",
> 	};
> 
> 	for (i = 0; i < ARRAY_SIZE(hook); i++) {
> 		if (hook[i] is enabled)
> 			strbuf_addf(hook_info, "%s\n", hook[i]);
> 	}
> 
> would be far easier to understand.  Do you have an external source
> that can feed you a single long string of comma separated hook names
> in mind, so that the initialization of *hooks will become simpler
> that way, or something?

Huh. I'm having a hard time remembering why I did it this way. I think I wanted to use the string_list foreach? But you're right that it is pretty hard to understand, plus expensive; I'll just use an array like you suggest.

Show 21 quoted lines
> 
> > +		if (find_hook(iter->string)) {
> > +			strbuf_addstr(hook_info, iter->string);
> > +			strbuf_complete_line(hook_info);
> > +		}
> > +	}
> > +}
> > +
> >  static const char * const bugreport_usage[] = {
> >  	N_("git bugreport [-o|--output-directory <file>] [-s|--suffix <format>]"),
> >  	NULL
> > @@ -166,6 +216,9 @@ int cmd_main(int argc, const char **argv)
> >  	get_header(&buffer, "Safelisted Config Info");
> >  	get_safelisted_config(&buffer);
> >  
> > +	get_header(&buffer, "Enabled Hooks");
> > +	get_populated_hooks(&buffer, nongit_ok);
> > +
> >  	report = fopen_for_writing(report_path.buf);
> >  
> >  	if (report == NULL) {
Emily Shaffer· Feb 20, 2020, 01:58 UTC · re: Emily Shaffer · lore

[PATCH v8 12/15] bugreport: count loose objects

The number of unpacked objects in a user's repository may help us understand the root of the problem they're seeing, especially if a command is running unusually slowly.

Helped-by: Johannes Schindelin <Johannes.Schindelin@gmx.de>
Signed-off-by: Emily Shaffer <emilyshaffer@google.com>
---
 Documentation/git-bugreport.txt |  1 +
 bugreport.c                     | 52 +++++++++++++++++++++++++++++++++
 2 files changed, 53 insertions(+)
Show changes to 2 files +53 −0

Documentation/git-bugreport.txt, bugreport.c

diff --git a/Documentation/git-bugreport.txt b/Documentation/git-bugreport.txt
index 4d01528540..4fe1c60506 100644
--- a/Documentation/git-bugreport.txt
+++ b/Documentation/git-bugreport.txt
@@ -32,6 +32,7 @@ The following information is captured automatically:
  - $SHELL
  - Selected config values
  - A list of enabled hooks
+ - The number of loose objects in the repository
 
 This tool is invoked via the typical Git setup process, which means that in some
 cases, it might not be able to launch - for example, if a relevant config file
diff --git a/bugreport.c b/bugreport.c
index b5a0714a7f..fb7bc72723 100644
--- a/bugreport.c
+++ b/bugreport.c
@@ -10,6 +10,7 @@
 #include "bugreport-config-safelist.h"
 #include "khash.h"
 #include "run-command.h"
+#include "object-store.h"
 
 static void get_git_remote_https_version_info(struct strbuf *version_info)
 {
@@ -128,6 +129,54 @@ static void get_populated_hooks(struct strbuf *hook_info, int nongit)
 	}
 }
 
+static int loose_object_cb(const struct object_id *oid, const char *path,
+			   void *data) {
+	int *loose_object_count = data;
+
+	if (loose_object_count) {
+		(*loose_object_count)++;
+		return 0;
+	}
+
+	return 1;
+}
+
+static void get_loose_object_summary(struct strbuf *obj_info, int nongit) {
+
+	int local_loose_object_count = 0, total_loose_object_count = 0;
+	int local_count_questionable = 0, total_count_questionable = 0;
+
+	if (nongit) {
+		strbuf_addstr(obj_info,
+			"not run from a git repository - no objects to show\n");
+		return;
+	}
+
+	local_count_questionable = for_each_loose_object(
+					loose_object_cb,
+					&local_loose_object_count,
+					FOR_EACH_OBJECT_LOCAL_ONLY);
+
+	total_count_questionable = for_each_loose_object(
+					loose_object_cb,
+					&total_loose_object_count,
+					0);
+
+	strbuf_addf(obj_info, "%d local loose objects%s\n",
+		    local_loose_object_count,
+		    local_count_questionable ? " (problem during count)" : "");
+
+	strbuf_addf(obj_info, "%d alternate loose objects%s\n",
+		    total_loose_object_count - local_loose_object_count,
+		    (local_count_questionable || total_count_questionable)
+			? " (problem during count)"
+			: "");
+
+	strbuf_addf(obj_info, "%d total loose objects%s\n",
+		    total_loose_object_count,
+		    total_count_questionable ? " (problem during count)" : "");
+}
+
 static const char * const bugreport_usage[] = {
 	N_("git bugreport [-o|--output-directory <file>] [-s|--suffix <format>]"),
 	NULL
@@ -219,6 +268,9 @@ int cmd_main(int argc, const char **argv)
 	get_header(&buffer, "Enabled Hooks");
 	get_populated_hooks(&buffer, nongit_ok);
 
+	get_header(&buffer, "Loose Object Counts");
+	get_loose_object_summary(&buffer, nongit_ok);
+
 	report = fopen_for_writing(report_path.buf);
 
 	if (report == NULL) {
-- 
2.25.0.265.gbab2e86ba0-goog
Junio C Hamano· Feb 20, 2020, 21:04 UTC · re: Emily Shaffer · lore

Re: [PATCH v8 12/15] bugreport: count loose objects

Emily Shaffer <emilyshaffer@google.com> writes:
Show 49 quoted lines
> The number of unpacked objects in a user's repository may help us
> understand the root of the problem they're seeing, especially if a
> command is running unusually slowly.
>
> Helped-by: Johannes Schindelin <Johannes.Schindelin@gmx.de>
> Signed-off-by: Emily Shaffer <emilyshaffer@google.com>
> ---
>  Documentation/git-bugreport.txt |  1 +
>  bugreport.c                     | 52 +++++++++++++++++++++++++++++++++
>  2 files changed, 53 insertions(+)
>
> diff --git a/Documentation/git-bugreport.txt b/Documentation/git-bugreport.txt
> index 4d01528540..4fe1c60506 100644
> --- a/Documentation/git-bugreport.txt
> +++ b/Documentation/git-bugreport.txt
> @@ -32,6 +32,7 @@ The following information is captured automatically:
>   - $SHELL
>   - Selected config values
>   - A list of enabled hooks
> + - The number of loose objects in the repository
>  
>  This tool is invoked via the typical Git setup process, which means that in some
>  cases, it might not be able to launch - for example, if a relevant config file
> diff --git a/bugreport.c b/bugreport.c
> index b5a0714a7f..fb7bc72723 100644
> --- a/bugreport.c
> +++ b/bugreport.c
> @@ -10,6 +10,7 @@
>  #include "bugreport-config-safelist.h"
>  #include "khash.h"
>  #include "run-command.h"
> +#include "object-store.h"
>  
>  static void get_git_remote_https_version_info(struct strbuf *version_info)
>  {
> @@ -128,6 +129,54 @@ static void get_populated_hooks(struct strbuf *hook_info, int nongit)
>  	}
>  }
>  
> +static int loose_object_cb(const struct object_id *oid, const char *path,
> +			   void *data) {
> +	int *loose_object_count = data;
> +
> +	if (loose_object_count) {
> +		(*loose_object_count)++;
> +		return 0;
> +	}
> +
> +	return 1;

What is the point of returning 1 here to abort the iteration early? Wouldn't it be a BUG() if this callback ends up gettting called with NULL in data?

Show 50 quoted lines
> +}
> +
> +static void get_loose_object_summary(struct strbuf *obj_info, int nongit) {
> +
> +	int local_loose_object_count = 0, total_loose_object_count = 0;
> +	int local_count_questionable = 0, total_count_questionable = 0;
> +
> +	if (nongit) {
> +		strbuf_addstr(obj_info,
> +			"not run from a git repository - no objects to show\n");
> +		return;
> +	}
> +
> +	local_count_questionable = for_each_loose_object(
> +					loose_object_cb,
> +					&local_loose_object_count,
> +					FOR_EACH_OBJECT_LOCAL_ONLY);
> +
> +	total_count_questionable = for_each_loose_object(
> +					loose_object_cb,
> +					&total_loose_object_count,
> +					0);
> +	strbuf_addf(obj_info, "%d local loose objects%s\n",
> +		    local_loose_object_count,
> +		    local_count_questionable ? " (problem during count)" : "");
> +
> +	strbuf_addf(obj_info, "%d alternate loose objects%s\n",
> +		    total_loose_object_count - local_loose_object_count,
> +		    (local_count_questionable || total_count_questionable)
> +			? " (problem during count)"
> +			: "");
> +
> +	strbuf_addf(obj_info, "%d total loose objects%s\n",
> +		    total_loose_object_count,
> +		    total_count_questionable ? " (problem during count)" : "");
> +}
> +
>  static const char * const bugreport_usage[] = {
>  	N_("git bugreport [-o|--output-directory <file>] [-s|--suffix <format>]"),
>  	NULL
> @@ -219,6 +268,9 @@ int cmd_main(int argc, const char **argv)
>  	get_header(&buffer, "Enabled Hooks");
>  	get_populated_hooks(&buffer, nongit_ok);
>  
> +	get_header(&buffer, "Loose Object Counts");
> +	get_loose_object_summary(&buffer, nongit_ok);
> +
>  	report = fopen_for_writing(report_path.buf);
>  
>  	if (report == NULL) {
Emily Shaffer· Feb 25, 2020, 23:22 UTC · re: Junio C Hamano · lore

Re: [PATCH v8 12/15] bugreport: count loose objects

On Thu, Feb 20, 2020 at 01:04:33PM -0800, Junio C Hamano wrote:
Show 55 quoted lines
> Emily Shaffer <emilyshaffer@google.com> writes:
> 
> > The number of unpacked objects in a user's repository may help us
> > understand the root of the problem they're seeing, especially if a
> > command is running unusually slowly.
> >
> > Helped-by: Johannes Schindelin <Johannes.Schindelin@gmx.de>
> > Signed-off-by: Emily Shaffer <emilyshaffer@google.com>
> > ---
> >  Documentation/git-bugreport.txt |  1 +
> >  bugreport.c                     | 52 +++++++++++++++++++++++++++++++++
> >  2 files changed, 53 insertions(+)
> >
> > diff --git a/Documentation/git-bugreport.txt b/Documentation/git-bugreport.txt
> > index 4d01528540..4fe1c60506 100644
> > --- a/Documentation/git-bugreport.txt
> > +++ b/Documentation/git-bugreport.txt
> > @@ -32,6 +32,7 @@ The following information is captured automatically:
> >   - $SHELL
> >   - Selected config values
> >   - A list of enabled hooks
> > + - The number of loose objects in the repository
> >  
> >  This tool is invoked via the typical Git setup process, which means that in some
> >  cases, it might not be able to launch - for example, if a relevant config file
> > diff --git a/bugreport.c b/bugreport.c
> > index b5a0714a7f..fb7bc72723 100644
> > --- a/bugreport.c
> > +++ b/bugreport.c
> > @@ -10,6 +10,7 @@
> >  #include "bugreport-config-safelist.h"
> >  #include "khash.h"
> >  #include "run-command.h"
> > +#include "object-store.h"
> >  
> >  static void get_git_remote_https_version_info(struct strbuf *version_info)
> >  {
> > @@ -128,6 +129,54 @@ static void get_populated_hooks(struct strbuf *hook_info, int nongit)
> >  	}
> >  }
> >  
> > +static int loose_object_cb(const struct object_id *oid, const char *path,
> > +			   void *data) {
> > +	int *loose_object_count = data;
> > +
> > +	if (loose_object_count) {
> > +		(*loose_object_count)++;
> > +		return 0;
> > +	}
> > +
> > +	return 1;
> 
> What is the point of returning 1 here to abort the iteration early?
> Wouldn't it be a BUG() if this callback ends up gettting called with
> NULL in data?
Hrm. Wouldn't BUG() throw away the rest of the generated report?

Maybe it's better, in NULL case, to indicate an error occurred there and write that information into the report, and continue gathering the rest of the info.

Emily Shaffer· Feb 25, 2020, 23:26 UTC · re: Emily Shaffer · lore

Re: [PATCH v8 12/15] bugreport: count loose objects

On Tue, Feb 25, 2020 at 03:22:00PM -0800, Emily Shaffer wrote:
Show 62 quoted lines
> On Thu, Feb 20, 2020 at 01:04:33PM -0800, Junio C Hamano wrote:
> > Emily Shaffer <emilyshaffer@google.com> writes:
> > 
> > > The number of unpacked objects in a user's repository may help us
> > > understand the root of the problem they're seeing, especially if a
> > > command is running unusually slowly.
> > >
> > > Helped-by: Johannes Schindelin <Johannes.Schindelin@gmx.de>
> > > Signed-off-by: Emily Shaffer <emilyshaffer@google.com>
> > > ---
> > >  Documentation/git-bugreport.txt |  1 +
> > >  bugreport.c                     | 52 +++++++++++++++++++++++++++++++++
> > >  2 files changed, 53 insertions(+)
> > >
> > > diff --git a/Documentation/git-bugreport.txt b/Documentation/git-bugreport.txt
> > > index 4d01528540..4fe1c60506 100644
> > > --- a/Documentation/git-bugreport.txt
> > > +++ b/Documentation/git-bugreport.txt
> > > @@ -32,6 +32,7 @@ The following information is captured automatically:
> > >   - $SHELL
> > >   - Selected config values
> > >   - A list of enabled hooks
> > > + - The number of loose objects in the repository
> > >  
> > >  This tool is invoked via the typical Git setup process, which means that in some
> > >  cases, it might not be able to launch - for example, if a relevant config file
> > > diff --git a/bugreport.c b/bugreport.c
> > > index b5a0714a7f..fb7bc72723 100644
> > > --- a/bugreport.c
> > > +++ b/bugreport.c
> > > @@ -10,6 +10,7 @@
> > >  #include "bugreport-config-safelist.h"
> > >  #include "khash.h"
> > >  #include "run-command.h"
> > > +#include "object-store.h"
> > >  
> > >  static void get_git_remote_https_version_info(struct strbuf *version_info)
> > >  {
> > > @@ -128,6 +129,54 @@ static void get_populated_hooks(struct strbuf *hook_info, int nongit)
> > >  	}
> > >  }
> > >  
> > > +static int loose_object_cb(const struct object_id *oid, const char *path,
> > > +			   void *data) {
> > > +	int *loose_object_count = data;
> > > +
> > > +	if (loose_object_count) {
> > > +		(*loose_object_count)++;
> > > +		return 0;
> > > +	}
> > > +
> > > +	return 1;
> > 
> > What is the point of returning 1 here to abort the iteration early?
> > Wouldn't it be a BUG() if this callback ends up gettting called with
> > NULL in data?
> 
> Hrm. Wouldn't BUG() throw away the rest of the generated report?
> 
> Maybe it's better, in NULL case, to indicate an error occurred there and
> write that information into the report, and continue gathering the rest
> of the info.

Oh, hm. Now that I look twice, you're saying "bugreport gave its own callback a NULL". I guess it could also be that for_each_loose_object() decided to give a NULL context instead of the one we gave...

Even so, I dislike the idea of BUG() called from the tool you are trying to use to report a BUG() message. We do already report if 1 was returned "(problem during count)". I suppose I can try and make a more specific error if we know the callback data was definitely the problem.

 - Emily
Emily Shaffer· Feb 20, 2020, 01:58 UTC · re: Emily Shaffer · lore

[PATCH v8 13/15] bugreport: add packed object summary

Alongside the loose object counts, it can be useful to show the number of packs and packed objects. This way we can check whether the repo has an appropriate ratio of packed to loose objects to help determine whether it's behaving correctly.

Add a utility to easily traverse all packfiles in a given repository. Use it in packfile.c and remove a redundant call to prepare_packed_git(), which is already called in get_all_packs().

Signed-off-by: Emily Shaffer <emilyshaffer@google.com>
---
 Documentation/git-bugreport.txt |  1 +
 bugreport.c                     | 30 ++++++++++++++++++++++++++++++
 object-store.h                  |  6 ++++++
 packfile.c                      |  3 +--
 4 files changed, 38 insertions(+), 2 deletions(-)
Show changes to 4 files +38 −2

Documentation/git-bugreport.txt, bugreport.c, object-store.h, packfile.c

diff --git a/Documentation/git-bugreport.txt b/Documentation/git-bugreport.txt
index 4fe1c60506..eb41f0677f 100644
--- a/Documentation/git-bugreport.txt
+++ b/Documentation/git-bugreport.txt
@@ -33,6 +33,7 @@ The following information is captured automatically:
  - Selected config values
  - A list of enabled hooks
  - The number of loose objects in the repository
+ - The number of packs and packed objects in the repository
 
 This tool is invoked via the typical Git setup process, which means that in some
 cases, it might not be able to launch - for example, if a relevant config file
diff --git a/bugreport.c b/bugreport.c
index fb7bc72723..71191f1331 100644
--- a/bugreport.c
+++ b/bugreport.c
@@ -177,6 +177,33 @@ static void get_loose_object_summary(struct strbuf *obj_info, int nongit) {
 		    total_count_questionable ? " (problem during count)" : "");
 }
 
+static void get_packed_object_summary(struct strbuf *obj_info, int nongit)
+{
+	struct packed_git *pack = NULL;
+	int pack_count = 0;
+	int object_count = 0;
+
+	if (nongit) {
+		strbuf_addstr(obj_info,
+			"not run from a git repository - no objects to show\n");
+		return;
+	}
+
+	for_each_pack(the_repository, pack) {
+		pack_count++;
+		/*
+		 * To accurately count how many objects are packed, look inside
+		 * the packfile's index.
+		 */
+		open_pack_index(pack);
+		object_count += pack->num_objects;
+	}
+
+	strbuf_addf(obj_info, "%d total packs (%d objects)\n", pack_count,
+		    object_count);
+
+}
+
 static const char * const bugreport_usage[] = {
 	N_("git bugreport [-o|--output-directory <file>] [-s|--suffix <format>]"),
 	NULL
@@ -271,6 +298,9 @@ int cmd_main(int argc, const char **argv)
 	get_header(&buffer, "Loose Object Counts");
 	get_loose_object_summary(&buffer, nongit_ok);
 
+	get_header(&buffer, "Packed Object Summary");
+	get_packed_object_summary(&buffer, nongit_ok);
+
 	report = fopen_for_writing(report_path.buf);
 
 	if (report == NULL) {
diff --git a/object-store.h b/object-store.h
index 5b047637e3..f881a1756e 100644
--- a/object-store.h
+++ b/object-store.h
@@ -7,6 +7,7 @@
 #include "sha1-array.h"
 #include "strbuf.h"
 #include "thread-utils.h"
+#include "packfile.h"
 
 struct object_directory {
 	struct object_directory *next;
@@ -447,4 +448,9 @@ int for_each_object_in_pack(struct packed_git *p,
 int for_each_packed_object(each_packed_object_fn, void *,
 			   enum for_each_object_flags flags);
 
+#define for_each_pack(repo, pack) 		\
+		for (pack = get_all_packs(repo);\
+		     pack;			\
+		     pack = pack->next)
+
 #endif /* OBJECT_STORE_H */
diff --git a/packfile.c b/packfile.c
index 99dd1a7d09..95afcc1187 100644
--- a/packfile.c
+++ b/packfile.c
@@ -2095,8 +2095,7 @@ int for_each_packed_object(each_packed_object_fn cb, void *data,
 	int r = 0;
 	int pack_errors = 0;
 
-	prepare_packed_git(the_repository);
-	for (p = get_all_packs(the_repository); p; p = p->next) {
+	for_each_pack(the_repository, p) {
 		if ((flags & FOR_EACH_OBJECT_LOCAL_ONLY) && !p->pack_local)
 			continue;
 		if ((flags & FOR_EACH_OBJECT_PROMISOR_ONLY) &&
-- 
2.25.0.265.gbab2e86ba0-goog
Junio C Hamano· Feb 20, 2020, 22:04 UTC · re: Emily Shaffer · lore

Re: [PATCH v8 13/15] bugreport: add packed object summary

Emily Shaffer <emilyshaffer@google.com> writes:
Show 26 quoted lines
> +static void get_packed_object_summary(struct strbuf *obj_info, int nongit)
> +{
> +	struct packed_git *pack = NULL;
> +	int pack_count = 0;
> +	int object_count = 0;
> +
> +	if (nongit) {
> +		strbuf_addstr(obj_info,
> +			"not run from a git repository - no objects to show\n");
> +		return;
> +	}
> +
> +	for_each_pack(the_repository, pack) {
> +		pack_count++;
> +		/*
> +		 * To accurately count how many objects are packed, look inside
> +		 * the packfile's index.
> +		 */
> +		open_pack_index(pack);
> +		object_count += pack->num_objects;
> +	}
> +
> +	strbuf_addf(obj_info, "%d total packs (%d objects)\n", pack_count,
> +		    object_count);
> +
> +}
Makes sense.
Show 8 quoted lines
> @@ -447,4 +448,9 @@ int for_each_object_in_pack(struct packed_git *p,
>  int for_each_packed_object(each_packed_object_fn, void *,
>  			   enum for_each_object_flags flags);
>  
> +#define for_each_pack(repo, pack) 		\
> +		for (pack = get_all_packs(repo);\
> +		     pack;			\
> +		     pack = pack->next)

I generally avoid #define'ing a control loop pseudo-syntax unless it makes the resulting code hide overly ugly implementation detail.

for_each_string_list() is there to hide the fact that items are stored in an embedded array whose name is .items and size is .nr that is sufficiently ugnly to expose, but iterating over packs does not look so bad.

If you MUST have this as a pseudo-syntax macro, we need
 - to match for_each_string_list_item(), have iterating variable
   'pack' as the first parameter, and the scope of what's iterated
   'repo' as the second.
 - to make sure the syntax works correctly even if a parameter is
   *not* a simple identifier (I think the above is OK, but there may
   be cases that it does not work well).

Regarding the latter, the way 'item' is incremented at the end of iteration in for_each_string_list_item() is subtle and correct.

#define for_each_string_list_item(item,list)            \
	for (item = (list)->items;                      \
	     item && item < (list)->items + (list)->nr; \
	     ++item)

You would break it if you changed pre-increment to post-increment for a user like this:

	struct string_list *list;
	struct string_list_item *i, **p;
	p = &i;
	for_each_string_list_item(*p, list) {
		...
	}

because ++*p is ++(*p), while *p++ is (*p)++, and we do want the former (i.e. increment the memory cell pointed at by pointer p).

Personally, I would prefer not to introduce this macro if I were working on this topic.

Show 15 quoted lines
>  #endif /* OBJECT_STORE_H */
> diff --git a/packfile.c b/packfile.c
> index 99dd1a7d09..95afcc1187 100644
> --- a/packfile.c
> +++ b/packfile.c
> @@ -2095,8 +2095,7 @@ int for_each_packed_object(each_packed_object_fn cb, void *data,
>  	int r = 0;
>  	int pack_errors = 0;
>  
> -	prepare_packed_git(the_repository);
> -	for (p = get_all_packs(the_repository); p; p = p->next) {
> +	for_each_pack(the_repository, p) {
>  		if ((flags & FOR_EACH_OBJECT_LOCAL_ONLY) && !p->pack_local)
>  			continue;
>  		if ((flags & FOR_EACH_OBJECT_PROMISOR_ONLY) &&
Emily Shaffer· Feb 25, 2020, 23:58 UTC · re: Junio C Hamano · lore

Re: [PATCH v8 13/15] bugreport: add packed object summary

On Thu, Feb 20, 2020 at 02:04:52PM -0800, Junio C Hamano wrote:
Show 82 quoted lines
> Emily Shaffer <emilyshaffer@google.com> writes:
> 
> > +static void get_packed_object_summary(struct strbuf *obj_info, int nongit)
> > +{
> > +	struct packed_git *pack = NULL;
> > +	int pack_count = 0;
> > +	int object_count = 0;
> > +
> > +	if (nongit) {
> > +		strbuf_addstr(obj_info,
> > +			"not run from a git repository - no objects to show\n");
> > +		return;
> > +	}
> > +
> > +	for_each_pack(the_repository, pack) {
> > +		pack_count++;
> > +		/*
> > +		 * To accurately count how many objects are packed, look inside
> > +		 * the packfile's index.
> > +		 */
> > +		open_pack_index(pack);
> > +		object_count += pack->num_objects;
> > +	}
> > +
> > +	strbuf_addf(obj_info, "%d total packs (%d objects)\n", pack_count,
> > +		    object_count);
> > +
> > +}
> 
> Makes sense.
> 
> > @@ -447,4 +448,9 @@ int for_each_object_in_pack(struct packed_git *p,
> >  int for_each_packed_object(each_packed_object_fn, void *,
> >  			   enum for_each_object_flags flags);
> >  
> > +#define for_each_pack(repo, pack) 		\
> > +		for (pack = get_all_packs(repo);\
> > +		     pack;			\
> > +		     pack = pack->next)
> 
> I generally avoid #define'ing a control loop pseudo-syntax unless it
> makes the resulting code hide overly ugly implementation detail.
> 
> for_each_string_list() is there to hide the fact that items are
> stored in an embedded array whose name is .items and size is .nr
> that is sufficiently ugnly to expose, but iterating over packs
> does not look so bad.
> 
> If you MUST have this as a pseudo-syntax macro, we need
> 
>  - to match for_each_string_list_item(), have iterating variable
>    'pack' as the first parameter, and the scope of what's iterated
>    'repo' as the second.
> 
>  - to make sure the syntax works correctly even if a parameter is
>    *not* a simple identifier (I think the above is OK, but there may
>    be cases that it does not work well).
> 
> Regarding the latter, the way 'item' is incremented at the end of
> iteration in for_each_string_list_item() is subtle and correct.
> 
> #define for_each_string_list_item(item,list)            \
> 	for (item = (list)->items;                      \
> 	     item && item < (list)->items + (list)->nr; \
> 	     ++item)
> 
> You would break it if you changed pre-increment to post-increment
> for a user like this:
> 
> 	struct string_list *list;
> 	struct string_list_item *i, **p;
> 	p = &i;
> 
> 	for_each_string_list_item(*p, list) {
> 		...
> 	}
> 
> because ++*p is ++(*p), while *p++ is (*p)++, and we do want the
> former (i.e. increment the memory cell pointed at by pointer p).
> 
> Personally, I would prefer not to introduce this macro if I were
> working on this topic.

Ah, I thought this is the kind of thing you meant here[1]. But I agree with what you point out about the shortcomings of this kind of macro. The implementation details are not so ugly; I'll drop it.

 - Emily
[1] https://lore.kernel.org/git/xmqq8sli89eu.fsf@gitster-ct.c.googlers.com
Show 16 quoted lines
> 
> >  #endif /* OBJECT_STORE_H */
> > diff --git a/packfile.c b/packfile.c
> > index 99dd1a7d09..95afcc1187 100644
> > --- a/packfile.c
> > +++ b/packfile.c
> > @@ -2095,8 +2095,7 @@ int for_each_packed_object(each_packed_object_fn cb, void *data,
> >  	int r = 0;
> >  	int pack_errors = 0;
> >  
> > -	prepare_packed_git(the_repository);
> > -	for (p = get_all_packs(the_repository); p; p = p->next) {
> > +	for_each_pack(the_repository, p) {
> >  		if ((flags & FOR_EACH_OBJECT_LOCAL_ONLY) && !p->pack_local)
> >  			continue;
> >  		if ((flags & FOR_EACH_OBJECT_PROMISOR_ONLY) &&
Emily Shaffer· Feb 20, 2020, 01:58 UTC · re: Emily Shaffer · lore

[PATCH v8 14/15] bugreport: list contents of $OBJDIR/info

Miscellaneous information used about the object store can end up in .git/objects/info; this can help us understand what may be going on with the object store when the user is reporting a bug. Otherwise, it could be difficult to track down what is going wrong with an object which isn't kept locally to .git/objects/ or .git/objects/pack. Having some understanding of where the user's objects may be kept can save us some hops during the bug reporting process.

Signed-off-by: Emily Shaffer <emilyshaffer@google.com>
---
 Documentation/git-bugreport.txt |  1 +
 bugreport.c                     | 54 +++++++++++++++++++++++++++++++++
 2 files changed, 55 insertions(+)
Show changes to 2 files +55 −0

Documentation/git-bugreport.txt, bugreport.c

diff --git a/Documentation/git-bugreport.txt b/Documentation/git-bugreport.txt
index eb41f0677f..a7ef3360d2 100644
--- a/Documentation/git-bugreport.txt
+++ b/Documentation/git-bugreport.txt
@@ -34,6 +34,7 @@ The following information is captured automatically:
  - A list of enabled hooks
  - The number of loose objects in the repository
  - The number of packs and packed objects in the repository
+ - A list of the contents of .git/objects/info (or equivalent)
 
 This tool is invoked via the typical Git setup process, which means that in some
 cases, it might not be able to launch - for example, if a relevant config file
diff --git a/bugreport.c b/bugreport.c
index 71191f1331..1d61e0f642 100644
--- a/bugreport.c
+++ b/bugreport.c
@@ -204,6 +204,57 @@ static void get_packed_object_summary(struct strbuf *obj_info, int nongit)
 
 }
 
+static void list_contents_of_dir_recursively(struct strbuf *contents,
+					     struct strbuf *dirpath)
+{
+	struct dirent *d;
+	DIR *dir;
+	size_t path_len;
+
+	dir = opendir(dirpath->buf);
+	if (!dir)
+		return;
+
+	strbuf_complete(dirpath, '/');
+	path_len = dirpath->len;
+
+	while ((d = readdir(dir))) {
+		if (!strcmp(d->d_name, ".") || !strcmp(d->d_name, ".."))
+			continue;
+
+		strbuf_addbuf(contents, dirpath);
+		strbuf_addstr(contents, d->d_name);
+		strbuf_complete_line(contents);
+
+		if (d->d_type == DT_DIR) {
+			strbuf_addstr(dirpath, d->d_name);
+			list_contents_of_dir_recursively(contents, dirpath);
+		}
+		strbuf_setlen(dirpath, path_len);
+	}
+
+	closedir(dir);
+}
+
+static void get_object_info_summary(struct strbuf *obj_info, int nongit)
+{
+	struct strbuf dirpath = STRBUF_INIT;
+
+	if (nongit) {
+		strbuf_addstr(obj_info,
+			"not run from a git repository - object info unavailable\n");
+		return;
+	}
+
+	strbuf_addstr(&dirpath, get_object_directory());
+	strbuf_complete(&dirpath, '/');
+	strbuf_addstr(&dirpath, "info/");
+
+	list_contents_of_dir_recursively(obj_info, &dirpath);
+
+	strbuf_release(&dirpath);
+}
+
 static const char * const bugreport_usage[] = {
 	N_("git bugreport [-o|--output-directory <file>] [-s|--suffix <format>]"),
 	NULL
@@ -301,6 +352,9 @@ int cmd_main(int argc, const char **argv)
 	get_header(&buffer, "Packed Object Summary");
 	get_packed_object_summary(&buffer, nongit_ok);
 
+	get_header(&buffer, "Object Info Summary");
+	get_object_info_summary(&buffer, nongit_ok);
+
 	report = fopen_for_writing(report_path.buf);
 
 	if (report == NULL) {
-- 
2.25.0.265.gbab2e86ba0-goog
Junio C Hamano· Feb 20, 2020, 22:18 UTC · re: Emily Shaffer · lore

Re: [PATCH v8 14/15] bugreport: list contents of $OBJDIR/info

Emily Shaffer <emilyshaffer@google.com> writes:
Show 10 quoted lines
> +static void list_contents_of_dir_recursively(struct strbuf *contents,
> +					     struct strbuf *dirpath)
> +{
> +	struct dirent *d;
> +	DIR *dir;
> +	size_t path_len;
> +
> +	dir = opendir(dirpath->buf);
> +	if (!dir)
> +		return;
No error detected?
Show 16 quoted lines
> +	strbuf_complete(dirpath, '/');
> +	path_len = dirpath->len;
> +
> +	while ((d = readdir(dir))) {
> +		if (!strcmp(d->d_name, ".") || !strcmp(d->d_name, ".."))
> +			continue;
> +
> +		strbuf_addbuf(contents, dirpath);
> +		strbuf_addstr(contents, d->d_name);
> +		strbuf_complete_line(contents);
> +
> +		if (d->d_type == DT_DIR) {
> +			strbuf_addstr(dirpath, d->d_name);
> +			list_contents_of_dir_recursively(contents, dirpath);
> +		}
> +		strbuf_setlen(dirpath, path_len);
Shouldn't we be sorting the output?
> +	}
> +
> +	closedir(dir);
> +}

Hmph, it is somewhat sad that we have to reinvent a degraded copy of "ls -aR" like this.

Show 13 quoted lines
> +static void get_object_info_summary(struct strbuf *obj_info, int nongit)
> +{
> +	struct strbuf dirpath = STRBUF_INIT;
> +
> +	if (nongit) {
> +		strbuf_addstr(obj_info,
> +			"not run from a git repository - object info unavailable\n");
> +		return;
> +	}
> +
> +	strbuf_addstr(&dirpath, get_object_directory());
> +	strbuf_complete(&dirpath, '/');
> +	strbuf_addstr(&dirpath, "info/");

Would it help to use git_path() for this, perhaps like git_path("objects/info/")?

By the way, do we store anything worth knowing in $GIT_DIR/info too? Perhaps the per-repo attributes and excludes files whose presence may hint at another question to ask when a user reports unexpected behaviour from .gitignore?

Show 17 quoted lines
> +	list_contents_of_dir_recursively(obj_info, &dirpath);
> +	strbuf_release(&dirpath);
> +}
> +
>  static const char * const bugreport_usage[] = {
>  	N_("git bugreport [-o|--output-directory <file>] [-s|--suffix <format>]"),
>  	NULL
> @@ -301,6 +352,9 @@ int cmd_main(int argc, const char **argv)
>  	get_header(&buffer, "Packed Object Summary");
>  	get_packed_object_summary(&buffer, nongit_ok);
>  
> +	get_header(&buffer, "Object Info Summary");
> +	get_object_info_summary(&buffer, nongit_ok);
> +
>  	report = fopen_for_writing(report_path.buf);
>  
>  	if (report == NULL) {
Emily Shaffer· Feb 20, 2020, 01:58 UTC · re: Emily Shaffer · lore

[PATCH v8 15/15] bugreport: summarize contents of alternates file

In some cases, it could be that the user is having a problem with an object which isn't present in their normal object directory. We can get a hint that that might be the case by examining the list of alternates where their object may be stored instead. Since paths to alternates may be sensitive, we'll instead count how many alternates have been specified and note how many of them exist or are broken.

While object-cache.h describes a function "foreach_alt_odb()", this function does not provide information on broken alternates, which are skipped over in "link_alt_odb_entry()". Since the goal is to identify missing alternates, we can gather the contents of .git/objects/info/alternates manually.

Signed-off-by: Emily Shaffer <emilyshaffer@google.com>
---
 Documentation/git-bugreport.txt |  1 +
 bugreport.c                     | 45 +++++++++++++++++++++++++++++++++
 2 files changed, 46 insertions(+)
Show changes to 2 files +46 −0

Documentation/git-bugreport.txt, bugreport.c

diff --git a/Documentation/git-bugreport.txt b/Documentation/git-bugreport.txt
index a7ef3360d2..1f60fb9456 100644
--- a/Documentation/git-bugreport.txt
+++ b/Documentation/git-bugreport.txt
@@ -35,6 +35,7 @@ The following information is captured automatically:
  - The number of loose objects in the repository
  - The number of packs and packed objects in the repository
  - A list of the contents of .git/objects/info (or equivalent)
+ - The number of valid and invalid alternates
 
 This tool is invoked via the typical Git setup process, which means that in some
 cases, it might not be able to launch - for example, if a relevant config file
diff --git a/bugreport.c b/bugreport.c
index 1d61e0f642..1640a71086 100644
--- a/bugreport.c
+++ b/bugreport.c
@@ -255,6 +255,48 @@ static void get_object_info_summary(struct strbuf *obj_info, int nongit)
 	strbuf_release(&dirpath);
 }
 
+static void get_alternates_summary(struct strbuf *alternates_info, int nongit)
+{
+	struct strbuf alternates_path = STRBUF_INIT;
+	struct strbuf alternate = STRBUF_INIT;
+	FILE *file;
+	size_t exists = 0, broken = 0;
+
+	if (nongit) {
+		strbuf_addstr(alternates_info,
+			"not run from a git repository - alternates unavailable\n");
+		return;
+	}
+
+	strbuf_addstr(&alternates_path, get_object_directory());
+	strbuf_complete(&alternates_path, '/');
+	strbuf_addstr(&alternates_path, "info/alternates");
+
+	file = fopen(alternates_path.buf, "r");
+	if (!file) {
+		strbuf_addstr(alternates_info, "No alternates file found.\n");
+		strbuf_release(&alternates_path);
+		return;
+	}
+
+	while (strbuf_getline(&alternate, file) != EOF) {
+		if (!access(alternate.buf, F_OK))
+			exists++;
+		else
+			broken++;
+	}
+
+	strbuf_addf(alternates_info,
+		    "%zd alternates found (%zd working, %zd broken)\n",
+		    exists + broken,
+		    exists,
+		    broken);
+
+	fclose(file);
+	strbuf_release(&alternate);
+	strbuf_release(&alternates_path);
+}
+
 static const char * const bugreport_usage[] = {
 	N_("git bugreport [-o|--output-directory <file>] [-s|--suffix <format>]"),
 	NULL
@@ -355,6 +397,9 @@ int cmd_main(int argc, const char **argv)
 	get_header(&buffer, "Object Info Summary");
 	get_object_info_summary(&buffer, nongit_ok);
 
+	get_header(&buffer, "Alternates");
+	get_alternates_summary(&buffer, nongit_ok);
+
 	report = fopen_for_writing(report_path.buf);
 
 	if (report == NULL) {
-- 
2.25.0.265.gbab2e86ba0-goog
Johannes Schindelin· Feb 20, 2020, 14:08 UTC · re: Emily Shaffer · lore

Re: [PATCH v8 15/15] bugreport: summarize contents of alternates file

Hi Emily,
On Wed, 19 Feb 2020, Emily Shaffer wrote:
Show 12 quoted lines
> In some cases, it could be that the user is having a problem with an
> object which isn't present in their normal object directory. We can get
> a hint that that might be the case by examining the list of alternates
> where their object may be stored instead. Since paths to alternates may
> be sensitive, we'll instead count how many alternates have been
> specified and note how many of them exist or are broken.
>
> While object-cache.h describes a function "foreach_alt_odb()", this
> function does not provide information on broken alternates, which are
> skipped over in "link_alt_odb_entry()". Since the goal is to identify
> missing alternates, we can gather the contents of
> .git/objects/info/alternates manually.
Makes sense.
Show 12 quoted lines
> diff --git a/bugreport.c b/bugreport.c
> index 1d61e0f642..1640a71086 100644
> --- a/bugreport.c
> +++ b/bugreport.c
> @@ -255,6 +255,48 @@ static void get_object_info_summary(struct strbuf *obj_info, int nongit)
>  	strbuf_release(&dirpath);
>  }
>
> +static void get_alternates_summary(struct strbuf *alternates_info, int nongit)
> +{
> +	struct strbuf alternates_path = STRBUF_INIT;
> +	struct strbuf alternate = STRBUF_INIT;

I am not sure that those variables and the parameter need to repeat "alternate", I find it rather distracting. If it were me, I would rename the parameter to `info`, the first strbuf to `path` and the second to `line`. This function is so specific to read the alternates file that it is quite obvious what their roles are.

Show 22 quoted lines
> +	FILE *file;
> +	size_t exists = 0, broken = 0;
> +
> +	if (nongit) {
> +		strbuf_addstr(alternates_info,
> +			"not run from a git repository - alternates unavailable\n");
> +		return;
> +	}
> +
> +	strbuf_addstr(&alternates_path, get_object_directory());
> +	strbuf_complete(&alternates_path, '/');
> +	strbuf_addstr(&alternates_path, "info/alternates");
> +
> +	file = fopen(alternates_path.buf, "r");
> +	if (!file) {
> +		strbuf_addstr(alternates_info, "No alternates file found.\n");
> +		strbuf_release(&alternates_path);
> +		return;
> +	}
> +
> +	while (strbuf_getline(&alternate, file) != EOF) {
> +		if (!access(alternate.buf, F_OK))

Should we make sure that the alternate is actually valid objects directory here? Like, look whether it is a directory, not a file or a (possibly dangling) symbolic link. This seems to be the only check `alt_odb_usable()` performs, so that should probably be good enough here, too.

Show 7 quoted lines
> +			exists++;
> +		else
> +			broken++;
> +	}
> +
> +	strbuf_addf(alternates_info,
> +		    "%zd alternates found (%zd working, %zd broken)\n",

Sadly, `%zd` is not portable. Therefore, `pu` (and `es/bugreport`) do not even _build_ on Windows. I need this to make it work:

-- snip --
Show changes to bugreport.c +5 −5
diff --git a/bugreport.c b/bugreport.c
index 3770aa73fae..5033668e22f 100644
--- a/bugreport.c
+++ b/bugreport.c
@@ -287,10 +287,11 @@ static void get_alternates_summary(struct strbuf *alternates_info, int nongit)
 	}

 	strbuf_addf(alternates_info,
-		    "%zd alternates found (%zd working, %zd broken)\n",
-		    exists + broken,
-		    exists,
-		    broken);
+		    "%"PRIuMAX" alternates found "
+		    "(%"PRIuMAX" working, %"PRIuMAX" broken)\n",
+		    (uintmax_t)(exists + broken),
+		    (uintmax_t)exists,
+		    (uintmax_t)broken);

 	fclose(file);
 	strbuf_release(&alternate);
-- snap --

Could you incorporate that into the next iteration, please?

Thanks,
Dscho

> +		    exists + broken,
> +		    exists,
> +		    broken);
> +
> +	fclose(file);
> +	strbuf_release(&alternate);
> +	strbuf_release(&alternates_path);
> +}
> +
>  static const char * const bugreport_usage[] = {
>  	N_("git bugreport [-o|--output-directory <file>] [-s|--suffix <format>]"),
>  	NULL
> @@ -355,6 +397,9 @@ int cmd_main(int argc, const char **argv)
>  	get_header(&buffer, "Object Info Summary");
>  	get_object_info_summary(&buffer, nongit_ok);
>
> +	get_header(&buffer, "Alternates");
> +	get_alternates_summary(&buffer, nongit_ok);
> +
>  	report = fopen_for_writing(report_path.buf);
>
>  	if (report == NULL) {
> --
> 2.25.0.265.gbab2e86ba0-goog
>
>
Junio C Hamano· Feb 20, 2020, 22:22 UTC · re: Emily Shaffer · lore

Re: [PATCH v8 15/15] bugreport: summarize contents of alternates file

Emily Shaffer <emilyshaffer@google.com> writes:
Show 16 quoted lines
> +static void get_alternates_summary(struct strbuf *alternates_info, int nongit)
> +{
> +	struct strbuf alternates_path = STRBUF_INIT;
> +	struct strbuf alternate = STRBUF_INIT;
> +	FILE *file;
> +	size_t exists = 0, broken = 0;
> +
> +	if (nongit) {
> +		strbuf_addstr(alternates_info,
> +			"not run from a git repository - alternates unavailable\n");
> +		return;
> +	}
> +
> +	strbuf_addstr(&alternates_path, get_object_directory());
> +	strbuf_complete(&alternates_path, '/');
> +	strbuf_addstr(&alternates_path, "info/alternates");
git_path()?
Show 10 quoted lines
> +	file = fopen(alternates_path.buf, "r");
> +	if (!file) {
> +		strbuf_addstr(alternates_info, "No alternates file found.\n");
> +		strbuf_release(&alternates_path);
> +		return;
> +	}
> +
> +	while (strbuf_getline(&alternate, file) != EOF) {
> +		if (!access(alternate.buf, F_OK))
> +			exists++;
F_OK reported as "exists" makes quite a lot of sense.
> +		else
> +			broken++;
So, shouldn't this rather be "missing"?
Show 7 quoted lines
> +	}
> +
> +	strbuf_addf(alternates_info,
> +		    "%zd alternates found (%zd working, %zd broken)\n",
> +		    exists + broken,
> +		    exists,
> +		    broken);

I don't see the point of using size_t for this. Just use int for both, like you did for object count in the step that counds loose and packed objects.

Show 18 quoted lines
> +	fclose(file);
> +	strbuf_release(&alternate);
> +	strbuf_release(&alternates_path);
> +}
> +
>  static const char * const bugreport_usage[] = {
>  	N_("git bugreport [-o|--output-directory <file>] [-s|--suffix <format>]"),
>  	NULL
> @@ -355,6 +397,9 @@ int cmd_main(int argc, const char **argv)
>  	get_header(&buffer, "Object Info Summary");
>  	get_object_info_summary(&buffer, nongit_ok);
>  
> +	get_header(&buffer, "Alternates");
> +	get_alternates_summary(&buffer, nongit_ok);
> +
>  	report = fopen_for_writing(report_path.buf);
>  
>  	if (report == NULL) {
Emily Shaffer· Mar 2, 2020, 23:03 UTC · re: Emily Shaffer · lore

[PATCH v9 0/5] add git-bugreport tool

I did run this set through the Azure Pipelines CI [2] and hope that means it's platform-safe; if that's not the case, please let me know your concerns.

For the relevant patches, I made the following changes since v8:
 - More portable strftime format
 - Use open() instead of fopen_for_writing() in order to specify O_CREAT
   | O_EXCL | O_WRONLY.
 - Fix a use-after-free.
 - Add i18n/l10n macro all over the place; per [3] let's translate the
   whole contents of the report, because it's easy to force to a
   different language and we may not be the only ones reading reports
 - Use a lot less strbuf_complete_line() - when we're making library
   calls, we have control over the format, so we do know whether it ends
   in \n or not; let's not waste the time checking it.
 - Minor nit on uname header phrasing
 - Reword the structure of compat/compiler.h to separate libc and
   compiler.
 - Add MSVC reporting in compat/compiler.h (thanks Dscho).
Thanks all.
 - Emily

[1]: https://lore.kernel.org/git/20200225235558.GG212281@google.com [2]: https://github.com/gitgitgadget/git/pull/566 [3]: https://lore.kernel.org/git/xmqqimjukzzv.fsf@gitster-ct.c.googlers.com

Emily Shaffer (5):
  help: move list_config_help to builtin/help
    Note that this patch is still required for this series because the
    help library (for version/build info) is unusable without it.
  bugreport: add tool to generate debugging info
  bugreport: gather git version and build info
  bugreport: add uname info
  bugreport: add compiler info
 .gitignore                      |   2 +
 Documentation/git-bugreport.txt |  52 ++++++++++++
 Makefile                        |  18 +++-
 bugreport.c                     | 142 ++++++++++++++++++++++++++++++++
 builtin/help.c                  |  86 +++++++++++++++++++
 command-list.txt                |   1 +
 compat/compiler.h               |  38 +++++++++
 generate-cmdlist.sh             |  19 -----
 generate-configlist.sh          |  21 +++++
 help.c                          | 131 +++++++----------------------
 help.h                          |   2 +-
 strbuf.c                        |   4 +
 strbuf.h                        |   1 +
 t/t0091-bugreport.sh            |  61 ++++++++++++++
 14 files changed, 452 insertions(+), 126 deletions(-)
 create mode 100644 Documentation/git-bugreport.txt
 create mode 100644 bugreport.c
 create mode 100644 compat/compiler.h
 create mode 100755 generate-configlist.sh
 create mode 100755 t/t0091-bugreport.sh
-- 
2.25.0.265.gbab2e86ba0-goog
Emily Shaffer· Mar 2, 2020, 23:03 UTC · re: Emily Shaffer · lore

[PATCH v9 1/5] help: move list_config_help to builtin/help

Starting in 3ac68a93fd2, help.o began to depend on builtin/branch.o, builtin/clean.o, and builtin/config.o. This meant that help.o was unusable outside of the context of the main Git executable.

To make help.o usable by other commands again, move list_config_help() into builtin/help.c (where it makes sense to assume other builtin libraries are present).

When command-list.h is included but a member is not used, we start to hear a compiler warning. Since the config list is generated in a fairly different way than the command list, and since commands and config options are semantically different, move the config list into its own header and move the generator into its own script and build rule.

Signed-off-by: Emily Shaffer <emilyshaffer@google.com>
---
 .gitignore             |  1 +
 Makefile               | 13 +++++--
 builtin/help.c         | 86 ++++++++++++++++++++++++++++++++++++++++++
 generate-cmdlist.sh    | 19 ----------
 generate-configlist.sh | 21 +++++++++++
 help.c                 | 85 -----------------------------------------
 help.h                 |  1 -
 7 files changed, 118 insertions(+), 108 deletions(-)
 create mode 100755 generate-configlist.sh
Show changes to 7 files +118 −108

.gitignore, Makefile, builtin/help.c, generate-cmdlist.sh, generate-configlist.sh, help.c, help.h

diff --git a/.gitignore b/.gitignore
index aebe7c0908..ea97de83f3 100644
--- a/.gitignore
+++ b/.gitignore
@@ -189,6 +189,7 @@
 /gitweb/gitweb.cgi
 /gitweb/static/gitweb.js
 /gitweb/static/gitweb.min.*
+/config-list.h
 /command-list.h
 *.tar.gz
 *.dsc
diff --git a/Makefile b/Makefile
index 6134104ae6..c552312d3f 100644
--- a/Makefile
+++ b/Makefile
@@ -815,6 +815,7 @@ LIB_FILE = libgit.a
 XDIFF_LIB = xdiff/lib.a
 VCSSVN_LIB = vcs-svn/lib.a
 
+GENERATED_H += config-list.h
 GENERATED_H += command-list.h
 
 LIB_H := $(sort $(patsubst ./%,%,$(shell git ls-files '*.h' ':!t/' ':!Documentation/' 2>/dev/null || \
@@ -2132,7 +2133,7 @@ git$X: git.o GIT-LDFLAGS $(BUILTIN_OBJS) $(GITLIBS)
 
 help.sp help.s help.o: command-list.h
 
-builtin/help.sp builtin/help.s builtin/help.o: command-list.h GIT-PREFIX
+builtin/help.sp builtin/help.s builtin/help.o: config-list.h GIT-PREFIX
 builtin/help.sp builtin/help.s builtin/help.o: EXTRA_CPPFLAGS = \
 	'-DGIT_HTML_PATH="$(htmldir_relative_SQ)"' \
 	'-DGIT_MAN_PATH="$(mandir_relative_SQ)"' \
@@ -2152,6 +2153,12 @@ $(BUILT_INS): git$X
 	ln -s $< $@ 2>/dev/null || \
 	cp $< $@
 
+config-list.h: generate-configlist.sh
+
+config-list.h:
+	$(QUIET_GEN)$(SHELL_PATH) ./generate-configlist.sh \
+		>$@+ && mv $@+ $@
+
 command-list.h: generate-cmdlist.sh command-list.txt
 
 command-list.h: $(wildcard Documentation/git*.txt) Documentation/*config.txt Documentation/config/*.txt
@@ -2785,7 +2792,7 @@ $(SP_OBJ): %.sp: %.c GIT-CFLAGS FORCE
 .PHONY: sparse $(SP_OBJ)
 sparse: $(SP_OBJ)
 
-EXCEPT_HDRS := command-list.h unicode-width.h compat/% xdiff/%
+EXCEPT_HDRS := command-list.h config-list.h unicode-width.h compat/% xdiff/%
 ifndef GCRYPT_SHA256
 	EXCEPT_HDRS += sha256/gcrypt.h
 endif
@@ -2807,7 +2814,7 @@ hdr-check: $(HCO)
 style:
 	git clang-format --style file --diff --extensions c,h
 
-check: command-list.h
+check: config-list.h command-list.h
 	@if sparse; \
 	then \
 		echo >&2 "Use 'make sparse' instead"; \
diff --git a/builtin/help.c b/builtin/help.c
index e5590d7787..1c5f2b9255 100644
--- a/builtin/help.c
+++ b/builtin/help.c
@@ -8,6 +8,7 @@
 #include "parse-options.h"
 #include "run-command.h"
 #include "column.h"
+#include "config-list.h"
 #include "help.h"
 #include "alias.h"
 
@@ -62,6 +63,91 @@ static const char * const builtin_help_usage[] = {
 	NULL
 };
 
+struct slot_expansion {
+	const char *prefix;
+	const char *placeholder;
+	void (*fn)(struct string_list *list, const char *prefix);
+	int found;
+};
+
+static void list_config_help(int for_human)
+{
+	struct slot_expansion slot_expansions[] = {
+		{ "advice", "*", list_config_advices },
+		{ "color.branch", "<slot>", list_config_color_branch_slots },
+		{ "color.decorate", "<slot>", list_config_color_decorate_slots },
+		{ "color.diff", "<slot>", list_config_color_diff_slots },
+		{ "color.grep", "<slot>", list_config_color_grep_slots },
+		{ "color.interactive", "<slot>", list_config_color_interactive_slots },
+		{ "color.remote", "<slot>", list_config_color_sideband_slots },
+		{ "color.status", "<slot>", list_config_color_status_slots },
+		{ "fsck", "<msg-id>", list_config_fsck_msg_ids },
+		{ "receive.fsck", "<msg-id>", list_config_fsck_msg_ids },
+		{ NULL, NULL, NULL }
+	};
+	const char **p;
+	struct slot_expansion *e;
+	struct string_list keys = STRING_LIST_INIT_DUP;
+	int i;
+
+	for (p = config_name_list; *p; p++) {
+		const char *var = *p;
+		struct strbuf sb = STRBUF_INIT;
+
+		for (e = slot_expansions; e->prefix; e++) {
+
+			strbuf_reset(&sb);
+			strbuf_addf(&sb, "%s.%s", e->prefix, e->placeholder);
+			if (!strcasecmp(var, sb.buf)) {
+				e->fn(&keys, e->prefix);
+				e->found++;
+				break;
+			}
+		}
+		strbuf_release(&sb);
+		if (!e->prefix)
+			string_list_append(&keys, var);
+	}
+
+	for (e = slot_expansions; e->prefix; e++)
+		if (!e->found)
+			BUG("slot_expansion %s.%s is not used",
+			    e->prefix, e->placeholder);
+
+	string_list_sort(&keys);
+	for (i = 0; i < keys.nr; i++) {
+		const char *var = keys.items[i].string;
+		const char *wildcard, *tag, *cut;
+
+		if (for_human) {
+			puts(var);
+			continue;
+		}
+
+		wildcard = strchr(var, '*');
+		tag = strchr(var, '<');
+
+		if (!wildcard && !tag) {
+			puts(var);
+			continue;
+		}
+
+		if (wildcard && !tag)
+			cut = wildcard;
+		else if (!wildcard && tag)
+			cut = tag;
+		else
+			cut = wildcard < tag ? wildcard : tag;
+
+		/*
+		 * We may produce duplicates, but that's up to
+		 * git-completion.bash to handle
+		 */
+		printf("%.*s\n", (int)(cut - var), var);
+	}
+	string_list_clear(&keys, 0);
+}
+
 static enum help_format parse_help_format(const char *format)
 {
 	if (!strcmp(format, "man"))
diff --git a/generate-cmdlist.sh b/generate-cmdlist.sh
index 71158f7d8b..45fecf8bdf 100755
--- a/generate-cmdlist.sh
+++ b/generate-cmdlist.sh
@@ -76,23 +76,6 @@ print_command_list () {
 	echo "};"
 }
 
-print_config_list () {
-	cat <<EOF
-static const char *config_name_list[] = {
-EOF
-	grep -h '^[a-zA-Z].*\..*::$' Documentation/*config.txt Documentation/config/*.txt |
-	sed '/deprecated/d; s/::$//; s/,  */\n/g' |
-	sort |
-	while read line
-	do
-		echo "	\"$line\","
-	done
-	cat <<EOF
-	NULL,
-};
-EOF
-}
-
 exclude_programs=
 while test "--exclude-program" = "$1"
 do
@@ -113,5 +96,3 @@ echo
 define_category_names "$1"
 echo
 print_command_list "$1"
-echo
-print_config_list
diff --git a/generate-configlist.sh b/generate-configlist.sh
new file mode 100755
index 0000000000..8692fe5cf4
--- /dev/null
+++ b/generate-configlist.sh
@@ -0,0 +1,21 @@
+#!/bin/sh
+
+echo "/* Automatically generated by generate-configlist.sh */"
+echo
+
+print_config_list () {
+	cat <<EOF
+static const char *config_name_list[] = {
+EOF
+	grep -h '^[a-zA-Z].*\..*::$' Documentation/*config.txt Documentation/config/*.txt |
+	sed '/deprecated/d; s/::$//; s/,  */\n/g' |
+	sort |
+	sed 's/^.*$/	"&",/'
+	cat <<EOF
+	NULL,
+};
+EOF
+}
+
+echo
+print_config_list
diff --git a/help.c b/help.c
index cf67624a94..a21487db77 100644
--- a/help.c
+++ b/help.c
@@ -407,91 +407,6 @@ void list_common_guides_help(void)
 	putchar('\n');
 }
 
-struct slot_expansion {
-	const char *prefix;
-	const char *placeholder;
-	void (*fn)(struct string_list *list, const char *prefix);
-	int found;
-};
-
-void list_config_help(int for_human)
-{
-	struct slot_expansion slot_expansions[] = {
-		{ "advice", "*", list_config_advices },
-		{ "color.branch", "<slot>", list_config_color_branch_slots },
-		{ "color.decorate", "<slot>", list_config_color_decorate_slots },
-		{ "color.diff", "<slot>", list_config_color_diff_slots },
-		{ "color.grep", "<slot>", list_config_color_grep_slots },
-		{ "color.interactive", "<slot>", list_config_color_interactive_slots },
-		{ "color.remote", "<slot>", list_config_color_sideband_slots },
-		{ "color.status", "<slot>", list_config_color_status_slots },
-		{ "fsck", "<msg-id>", list_config_fsck_msg_ids },
-		{ "receive.fsck", "<msg-id>", list_config_fsck_msg_ids },
-		{ NULL, NULL, NULL }
-	};
-	const char **p;
-	struct slot_expansion *e;
-	struct string_list keys = STRING_LIST_INIT_DUP;
-	int i;
-
-	for (p = config_name_list; *p; p++) {
-		const char *var = *p;
-		struct strbuf sb = STRBUF_INIT;
-
-		for (e = slot_expansions; e->prefix; e++) {
-
-			strbuf_reset(&sb);
-			strbuf_addf(&sb, "%s.%s", e->prefix, e->placeholder);
-			if (!strcasecmp(var, sb.buf)) {
-				e->fn(&keys, e->prefix);
-				e->found++;
-				break;
-			}
-		}
-		strbuf_release(&sb);
-		if (!e->prefix)
-			string_list_append(&keys, var);
-	}
-
-	for (e = slot_expansions; e->prefix; e++)
-		if (!e->found)
-			BUG("slot_expansion %s.%s is not used",
-			    e->prefix, e->placeholder);
-
-	string_list_sort(&keys);
-	for (i = 0; i < keys.nr; i++) {
-		const char *var = keys.items[i].string;
-		const char *wildcard, *tag, *cut;
-
-		if (for_human) {
-			puts(var);
-			continue;
-		}
-
-		wildcard = strchr(var, '*');
-		tag = strchr(var, '<');
-
-		if (!wildcard && !tag) {
-			puts(var);
-			continue;
-		}
-
-		if (wildcard && !tag)
-			cut = wildcard;
-		else if (!wildcard && tag)
-			cut = tag;
-		else
-			cut = wildcard < tag ? wildcard : tag;
-
-		/*
-		 * We may produce duplicates, but that's up to
-		 * git-completion.bash to handle
-		 */
-		printf("%.*s\n", (int)(cut - var), var);
-	}
-	string_list_clear(&keys, 0);
-}
-
 static int get_alias(const char *var, const char *value, void *data)
 {
 	struct string_list *list = data;
diff --git a/help.h b/help.h
index 7a455beeb7..9071894e8c 100644
--- a/help.h
+++ b/help.h
@@ -22,7 +22,6 @@ static inline void mput_char(char c, unsigned int num)
 void list_common_cmds_help(void);
 void list_all_cmds_help(void);
 void list_common_guides_help(void);
-void list_config_help(int for_human);
 
 void list_all_main_cmds(struct string_list *list);
 void list_all_other_cmds(struct string_list *list);
-- 
2.25.0.265.gbab2e86ba0-goog
Emily Shaffer· Mar 2, 2020, 23:03 UTC · re: Emily Shaffer · lore

[PATCH v9 2/5] bugreport: add tool to generate debugging info

Teach Git how to prompt the user for a good bug report: reproduction steps, expected behavior, and actual behavior. Later, Git can learn how to collect some diagnostic information from the repository.

If users can send us a well-written bug report which contains diagnostic information we would otherwise need to ask the user for, we can reduce the number of question-and-answer round trips between the reporter and the Git contributor.

Users may also wish to send a report like this to their local "Git expert" if they have put their repository into a state they are confused by.

Signed-off-by: Emily Shaffer <emilyshaffer@google.com>
---
 .gitignore                      |   1 +
 Documentation/git-bugreport.txt |  46 ++++++++++++++
 Makefile                        |   5 ++
 bugreport.c                     | 105 ++++++++++++++++++++++++++++++++
 command-list.txt                |   1 +
 strbuf.c                        |   4 ++
 strbuf.h                        |   1 +
 t/t0091-bugreport.sh            |  61 +++++++++++++++++++
 8 files changed, 224 insertions(+)
 create mode 100644 Documentation/git-bugreport.txt
 create mode 100644 bugreport.c
 create mode 100755 t/t0091-bugreport.sh
Show changes to 8 files +224 −0

.gitignore, Documentation/git-bugreport.txt, Makefile, bugreport.c, command-list.txt, strbuf.c, strbuf.h, t/t0091-bugreport.sh

diff --git a/.gitignore b/.gitignore
index ea97de83f3..d89bf9e11e 100644
--- a/.gitignore
+++ b/.gitignore
@@ -25,6 +25,7 @@
 /git-bisect--helper
 /git-blame
 /git-branch
+/git-bugreport
 /git-bundle
 /git-cat-file
 /git-check-attr
diff --git a/Documentation/git-bugreport.txt b/Documentation/git-bugreport.txt
new file mode 100644
index 0000000000..1f9fde5cde
--- /dev/null
+++ b/Documentation/git-bugreport.txt
@@ -0,0 +1,46 @@
+git-bugreport(1)
+================
+
+NAME
+----
+git-bugreport - Collect information for user to file a bug report
+
+SYNOPSIS
+--------
+[verse]
+'git bugreport' [(-o | --output-directory) <path>] [(-s | --suffix) <format>]
+
+DESCRIPTION
+-----------
+Captures information about the user's machine, Git client, and repository state,
+as well as a form requesting information about the behavior the user observed,
+into a single text file which the user can then share, for example to the Git
+mailing list, in order to report an observed bug.
+
+The following information is requested from the user:
+
+ - Reproduction steps
+ - Expected behavior
+ - Actual behavior
+
+This tool is invoked via the typical Git setup process, which means that in some
+cases, it might not be able to launch - for example, if a relevant config file
+is unreadable. In this kind of scenario, it may be helpful to manually gather
+the kind of information listed above when manually asking for help.
+
+OPTIONS
+-------
+-o <path>::
+--output-directory <path>::
+	Place the resulting bug report file in `<path>` instead of the root of
+	the Git repository.
+
+-s <format>::
+--suffix <format>::
+	Specify an alternate suffix for the bugreport name, to create a file
+	named 'git-bugreport-<formatted suffix>'. This should take the form of a
+	link:strftime[3] format string; the current local time will be used.
+
+GIT
+---
+Part of the linkgit:git[1] suite
diff --git a/Makefile b/Makefile
index c552312d3f..9e6705061d 100644
--- a/Makefile
+++ b/Makefile
@@ -681,6 +681,7 @@ EXTRA_PROGRAMS =
 # ... and all the rest that could be moved out of bindir to gitexecdir
 PROGRAMS += $(EXTRA_PROGRAMS)
 
+PROGRAM_OBJS += bugreport.o
 PROGRAM_OBJS += credential-store.o
 PROGRAM_OBJS += daemon.o
 PROGRAM_OBJS += fast-import.o
@@ -2461,6 +2462,10 @@ endif
 git-%$X: %.o GIT-LDFLAGS $(GITLIBS)
 	$(QUIET_LINK)$(CC) $(ALL_CFLAGS) -o $@ $(ALL_LDFLAGS) $(filter %.o,$^) $(LIBS)
 
+git-bugreport$X: bugreport.o GIT-LDFLAGS $(GITLIBS)
+	$(QUIET_LINK)$(CC) $(ALL_CFLAGS) -o $@ $(ALL_LDFLAGS) $(filter %.o,$^) \
+		$(LIBS)
+
 git-imap-send$X: imap-send.o $(IMAP_SEND_BUILDDEPS) GIT-LDFLAGS $(GITLIBS)
 	$(QUIET_LINK)$(CC) $(ALL_CFLAGS) -o $@ $(ALL_LDFLAGS) $(filter %.o,$^) \
 		$(IMAP_SEND_LDFLAGS) $(LIBS)
diff --git a/bugreport.c b/bugreport.c
new file mode 100644
index 0000000000..f473d606f2
--- /dev/null
+++ b/bugreport.c
@@ -0,0 +1,105 @@
+#include "builtin.h"
+#include "parse-options.h"
+#include "stdio.h"
+#include "strbuf.h"
+#include "time.h"
+
+static const char * const bugreport_usage[] = {
+	N_("git bugreport [-o|--output-directory <file>] [-s|--suffix <format>]"),
+	NULL
+};
+
+static int get_bug_template(struct strbuf *template)
+{
+	const char template_text[] = N_(
+"Thank you for filling out a Git bug report!\n"
+"Please answer the following questions to help us understand your issue.\n"
+"\n"
+"What did you do before the bug happened? (Steps to reproduce your issue)\n"
+"\n"
+"What did you expect to happen? (Expected behavior)\n"
+"\n"
+"What happened instead? (Actual behavior)\n"
+"\n"
+"What's different between what you expected and what actually happened?\n"
+"\n"
+"Anything else you want to add:\n"
+"\n"
+"Please review the rest of the bug report below.\n"
+"You can delete any lines you don't wish to share.\n");
+
+	strbuf_addstr(template, _(template_text));
+	return 0;
+}
+
+int cmd_main(int argc, const char **argv)
+{
+	struct strbuf buffer = STRBUF_INIT;
+	struct strbuf report_path = STRBUF_INIT;
+	int report = -1;
+	time_t now = time(NULL);
+	char *option_output = NULL;
+	char *option_suffix = "%F-%H%M";
+	int nongit_ok = 0;
+	const char *prefix = NULL;
+	const char *user_relative_path = NULL;
+
+	const struct option bugreport_options[] = {
+		OPT_STRING('o', "output-directory", &option_output, N_("path"),
+			   N_("specify a destination for the bugreport file")),
+		OPT_STRING('s', "suffix", &option_suffix, N_("format"),
+			   N_("specify a strftime format suffix for the filename")),
+		OPT_END()
+	};
+
+	prefix = setup_git_directory_gently(&nongit_ok);
+
+	argc = parse_options(argc, argv, prefix, bugreport_options,
+			     bugreport_usage, 0);
+
+	/* Prepare the path to put the result */
+	strbuf_addstr(&report_path,
+		      prefix_filename(prefix,
+				      option_output ? option_output : ""));
+	strbuf_complete(&report_path, '/');
+
+	strbuf_addstr(&report_path, "git-bugreport-");
+	strbuf_addftime(&report_path, option_suffix, localtime(&now), 0, 0);
+	strbuf_addstr(&report_path, ".txt");
+
+	switch (safe_create_leading_directories(report_path.buf)) {
+	case SCLD_OK:
+	case SCLD_EXISTS:
+		break;
+	default:
+		die(_("could not create leading directories for '%s'"),
+		    report_path.buf);
+	}
+
+	/* Prepare the report contents */
+	get_bug_template(&buffer);
+
+	/* 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) {
+		UNLEAK(report_path);
+		die(_("couldn't create a new file at '%s'"), report_path.buf);
+	}
+
+	strbuf_write_fd(&buffer, report);
+	close(report);
+
+	/*
+	 * We want to print the path relative to the user, but we still need the
+	 * path relative to us to give to the editor.
+	 */
+	if (!(prefix && skip_prefix(report_path.buf, prefix, &user_relative_path)))
+		user_relative_path = report_path.buf;
+	fprintf(stderr, _("Created new report at '%s'.\n"),
+		user_relative_path);
+
+	UNLEAK(buffer);
+	UNLEAK(report_path);
+	return !!launch_editor(report_path.buf, NULL, NULL);
+}
diff --git a/command-list.txt b/command-list.txt
index 2087894655..185e5e3f05 100644
--- a/command-list.txt
+++ b/command-list.txt
@@ -54,6 +54,7 @@ git-archive                             mainporcelain
 git-bisect                              mainporcelain           info
 git-blame                               ancillaryinterrogators          complete
 git-branch                              mainporcelain           history
+git-bugreport                           ancillaryinterrogators
 git-bundle                              mainporcelain
 git-cat-file                            plumbinginterrogators
 git-check-attr                          purehelpers
diff --git a/strbuf.c b/strbuf.c
index f19da55b07..f1d66c7848 100644
--- a/strbuf.c
+++ b/strbuf.c
@@ -539,6 +539,10 @@ ssize_t strbuf_write(struct strbuf *sb, FILE *f)
 	return sb->len ? fwrite(sb->buf, 1, sb->len, f) : 0;
 }
 
+ssize_t strbuf_write_fd(struct strbuf *sb, int fd)
+{
+	return sb->len ? write(fd, sb->buf, sb->len) : 0;
+}
 
 #define STRBUF_MAXLINK (2*PATH_MAX)
 
diff --git a/strbuf.h b/strbuf.h
index aae7ac3a82..bbf6204de7 100644
--- a/strbuf.h
+++ b/strbuf.h
@@ -462,6 +462,7 @@ int strbuf_readlink(struct strbuf *sb, const char *path, size_t hint);
  * NUL bytes.
  */
 ssize_t strbuf_write(struct strbuf *sb, FILE *stream);
+ssize_t strbuf_write_fd(struct strbuf *sb, int fd);
 
 /**
  * Read a line from a FILE *, overwriting the existing contents of
diff --git a/t/t0091-bugreport.sh b/t/t0091-bugreport.sh
new file mode 100755
index 0000000000..65f664fdac
--- /dev/null
+++ b/t/t0091-bugreport.sh
@@ -0,0 +1,61 @@
+#!/bin/sh
+
+test_description='git bugreport'
+
+. ./test-lib.sh
+
+# Headers "[System Info]" will be followed by a non-empty line if we put some
+# information there; we can make sure all our headers were followed by some
+# information to check if the command was successful.
+HEADER_PATTERN="^\[.*\]$"
+
+check_all_headers_populated () {
+	while read -r line
+	do
+		if test "$(grep "$HEADER_PATTERN" "$line")"
+		then
+			echo "$line"
+			read -r nextline
+			if test -z "$nextline"; then
+				return 1;
+			fi
+		fi
+	done
+}
+
+test_expect_success 'creates a report with content in the right places' '
+	git bugreport -s check-headers &&
+	check_all_headers_populated <git-bugreport-check-headers.txt &&
+	test_when_finished rm git-bugreport-check-headers.txt
+'
+
+test_expect_success 'dies if file with same name as report already exists' '
+	>>git-bugreport-duplicate.txt &&
+	test_must_fail git bugreport --suffix duplicate &&
+	test_when_finished rm git-bugreport-duplicate.txt
+'
+
+test_expect_success '--output-directory puts the report in the provided dir' '
+	git bugreport -o foo/ &&
+	test_path_is_file foo/git-bugreport-* &&
+	test_when_finished rm -fr foo/
+'
+
+test_expect_success 'incorrect arguments abort with usage' '
+	test_must_fail git bugreport --false 2>output &&
+	test_i18ngrep usage output &&
+	test_path_is_missing git-bugreport-*
+'
+
+test_expect_success 'runs outside of a git dir' '
+	nongit git bugreport &&
+	test_when_finished rm non-repo/git-bugreport-*
+'
+
+test_expect_success 'can create leading directories outside of a git dir' '
+	nongit git bugreport -o foo/bar/baz &&
+	test_when_finished rm -fr foo/bar/baz
+'
+
+
+test_done
-- 
2.25.0.265.gbab2e86ba0-goog
Johannes Schindelin· Mar 3, 2020, 14:18 UTC · re: Emily Shaffer · lore

Re: [PATCH v9 2/5] bugreport: add tool to generate debugging info

Hi Emily,
On Mon, 2 Mar 2020, Emily Shaffer wrote:
> +	char *option_suffix = "%F-%H%M";

Unfortunately, this still is not an `strftime` format we can use on Windows. I still needed to fix that in the previously-mentioned manner to fix the test run on Windows.

Thanks, Dscho

Johannes Schindelin· Mar 4, 2020, 21:35 UTC · re: Emily Shaffer · lore

Re: [PATCH v9 2/5] bugreport: add tool to generate debugging info

Hi,
On Mon, 2 Mar 2020, Emily Shaffer wrote:
Show 12 quoted lines
>  .gitignore                      |   1 +
>  Documentation/git-bugreport.txt |  46 ++++++++++++++
>  Makefile                        |   5 ++
>  bugreport.c                     | 105 ++++++++++++++++++++++++++++++++
>  command-list.txt                |   1 +
>  strbuf.c                        |   4 ++
>  strbuf.h                        |   1 +
>  t/t0091-bugreport.sh            |  61 +++++++++++++++++++
>  8 files changed, 224 insertions(+)
>  create mode 100644 Documentation/git-bugreport.txt
>  create mode 100644 bugreport.c
>  create mode 100755 t/t0091-bugreport.sh

Hmm. I am still _quite_ convinced that this would be much better as a built-in. Remember, non-built-ins come with a footprint, and I do not necessarily think that you will want to spend 3MB on a `git-bugreport` executable when you could have it for a couple dozen kilobytes inside `git` instead.

Ciao, Dscho

Show 309 quoted lines
>
> diff --git a/.gitignore b/.gitignore
> index ea97de83f3..d89bf9e11e 100644
> --- a/.gitignore
> +++ b/.gitignore
> @@ -25,6 +25,7 @@
>  /git-bisect--helper
>  /git-blame
>  /git-branch
> +/git-bugreport
>  /git-bundle
>  /git-cat-file
>  /git-check-attr
> diff --git a/Documentation/git-bugreport.txt b/Documentation/git-bugreport.txt
> new file mode 100644
> index 0000000000..1f9fde5cde
> --- /dev/null
> +++ b/Documentation/git-bugreport.txt
> @@ -0,0 +1,46 @@
> +git-bugreport(1)
> +================
> +
> +NAME
> +----
> +git-bugreport - Collect information for user to file a bug report
> +
> +SYNOPSIS
> +--------
> +[verse]
> +'git bugreport' [(-o | --output-directory) <path>] [(-s | --suffix) <format>]
> +
> +DESCRIPTION
> +-----------
> +Captures information about the user's machine, Git client, and repository state,
> +as well as a form requesting information about the behavior the user observed,
> +into a single text file which the user can then share, for example to the Git
> +mailing list, in order to report an observed bug.
> +
> +The following information is requested from the user:
> +
> + - Reproduction steps
> + - Expected behavior
> + - Actual behavior
> +
> +This tool is invoked via the typical Git setup process, which means that in some
> +cases, it might not be able to launch - for example, if a relevant config file
> +is unreadable. In this kind of scenario, it may be helpful to manually gather
> +the kind of information listed above when manually asking for help.
> +
> +OPTIONS
> +-------
> +-o <path>::
> +--output-directory <path>::
> +	Place the resulting bug report file in `<path>` instead of the root of
> +	the Git repository.
> +
> +-s <format>::
> +--suffix <format>::
> +	Specify an alternate suffix for the bugreport name, to create a file
> +	named 'git-bugreport-<formatted suffix>'. This should take the form of a
> +	link:strftime[3] format string; the current local time will be used.
> +
> +GIT
> +---
> +Part of the linkgit:git[1] suite
> diff --git a/Makefile b/Makefile
> index c552312d3f..9e6705061d 100644
> --- a/Makefile
> +++ b/Makefile
> @@ -681,6 +681,7 @@ EXTRA_PROGRAMS =
>  # ... and all the rest that could be moved out of bindir to gitexecdir
>  PROGRAMS += $(EXTRA_PROGRAMS)
>
> +PROGRAM_OBJS += bugreport.o
>  PROGRAM_OBJS += credential-store.o
>  PROGRAM_OBJS += daemon.o
>  PROGRAM_OBJS += fast-import.o
> @@ -2461,6 +2462,10 @@ endif
>  git-%$X: %.o GIT-LDFLAGS $(GITLIBS)
>  	$(QUIET_LINK)$(CC) $(ALL_CFLAGS) -o $@ $(ALL_LDFLAGS) $(filter %.o,$^) $(LIBS)
>
> +git-bugreport$X: bugreport.o GIT-LDFLAGS $(GITLIBS)
> +	$(QUIET_LINK)$(CC) $(ALL_CFLAGS) -o $@ $(ALL_LDFLAGS) $(filter %.o,$^) \
> +		$(LIBS)
> +
>  git-imap-send$X: imap-send.o $(IMAP_SEND_BUILDDEPS) GIT-LDFLAGS $(GITLIBS)
>  	$(QUIET_LINK)$(CC) $(ALL_CFLAGS) -o $@ $(ALL_LDFLAGS) $(filter %.o,$^) \
>  		$(IMAP_SEND_LDFLAGS) $(LIBS)
> diff --git a/bugreport.c b/bugreport.c
> new file mode 100644
> index 0000000000..f473d606f2
> --- /dev/null
> +++ b/bugreport.c
> @@ -0,0 +1,105 @@
> +#include "builtin.h"
> +#include "parse-options.h"
> +#include "stdio.h"
> +#include "strbuf.h"
> +#include "time.h"
> +
> +static const char * const bugreport_usage[] = {
> +	N_("git bugreport [-o|--output-directory <file>] [-s|--suffix <format>]"),
> +	NULL
> +};
> +
> +static int get_bug_template(struct strbuf *template)
> +{
> +	const char template_text[] = N_(
> +"Thank you for filling out a Git bug report!\n"
> +"Please answer the following questions to help us understand your issue.\n"
> +"\n"
> +"What did you do before the bug happened? (Steps to reproduce your issue)\n"
> +"\n"
> +"What did you expect to happen? (Expected behavior)\n"
> +"\n"
> +"What happened instead? (Actual behavior)\n"
> +"\n"
> +"What's different between what you expected and what actually happened?\n"
> +"\n"
> +"Anything else you want to add:\n"
> +"\n"
> +"Please review the rest of the bug report below.\n"
> +"You can delete any lines you don't wish to share.\n");
> +
> +	strbuf_addstr(template, _(template_text));
> +	return 0;
> +}
> +
> +int cmd_main(int argc, const char **argv)
> +{
> +	struct strbuf buffer = STRBUF_INIT;
> +	struct strbuf report_path = STRBUF_INIT;
> +	int report = -1;
> +	time_t now = time(NULL);
> +	char *option_output = NULL;
> +	char *option_suffix = "%F-%H%M";
> +	int nongit_ok = 0;
> +	const char *prefix = NULL;
> +	const char *user_relative_path = NULL;
> +
> +	const struct option bugreport_options[] = {
> +		OPT_STRING('o', "output-directory", &option_output, N_("path"),
> +			   N_("specify a destination for the bugreport file")),
> +		OPT_STRING('s', "suffix", &option_suffix, N_("format"),
> +			   N_("specify a strftime format suffix for the filename")),
> +		OPT_END()
> +	};
> +
> +	prefix = setup_git_directory_gently(&nongit_ok);
> +
> +	argc = parse_options(argc, argv, prefix, bugreport_options,
> +			     bugreport_usage, 0);
> +
> +	/* Prepare the path to put the result */
> +	strbuf_addstr(&report_path,
> +		      prefix_filename(prefix,
> +				      option_output ? option_output : ""));
> +	strbuf_complete(&report_path, '/');
> +
> +	strbuf_addstr(&report_path, "git-bugreport-");
> +	strbuf_addftime(&report_path, option_suffix, localtime(&now), 0, 0);
> +	strbuf_addstr(&report_path, ".txt");
> +
> +	switch (safe_create_leading_directories(report_path.buf)) {
> +	case SCLD_OK:
> +	case SCLD_EXISTS:
> +		break;
> +	default:
> +		die(_("could not create leading directories for '%s'"),
> +		    report_path.buf);
> +	}
> +
> +	/* Prepare the report contents */
> +	get_bug_template(&buffer);
> +
> +	/* 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) {
> +		UNLEAK(report_path);
> +		die(_("couldn't create a new file at '%s'"), report_path.buf);
> +	}
> +
> +	strbuf_write_fd(&buffer, report);
> +	close(report);
> +
> +	/*
> +	 * We want to print the path relative to the user, but we still need the
> +	 * path relative to us to give to the editor.
> +	 */
> +	if (!(prefix && skip_prefix(report_path.buf, prefix, &user_relative_path)))
> +		user_relative_path = report_path.buf;
> +	fprintf(stderr, _("Created new report at '%s'.\n"),
> +		user_relative_path);
> +
> +	UNLEAK(buffer);
> +	UNLEAK(report_path);
> +	return !!launch_editor(report_path.buf, NULL, NULL);
> +}
> diff --git a/command-list.txt b/command-list.txt
> index 2087894655..185e5e3f05 100644
> --- a/command-list.txt
> +++ b/command-list.txt
> @@ -54,6 +54,7 @@ git-archive                             mainporcelain
>  git-bisect                              mainporcelain           info
>  git-blame                               ancillaryinterrogators          complete
>  git-branch                              mainporcelain           history
> +git-bugreport                           ancillaryinterrogators
>  git-bundle                              mainporcelain
>  git-cat-file                            plumbinginterrogators
>  git-check-attr                          purehelpers
> diff --git a/strbuf.c b/strbuf.c
> index f19da55b07..f1d66c7848 100644
> --- a/strbuf.c
> +++ b/strbuf.c
> @@ -539,6 +539,10 @@ ssize_t strbuf_write(struct strbuf *sb, FILE *f)
>  	return sb->len ? fwrite(sb->buf, 1, sb->len, f) : 0;
>  }
>
> +ssize_t strbuf_write_fd(struct strbuf *sb, int fd)
> +{
> +	return sb->len ? write(fd, sb->buf, sb->len) : 0;
> +}
>
>  #define STRBUF_MAXLINK (2*PATH_MAX)
>
> diff --git a/strbuf.h b/strbuf.h
> index aae7ac3a82..bbf6204de7 100644
> --- a/strbuf.h
> +++ b/strbuf.h
> @@ -462,6 +462,7 @@ int strbuf_readlink(struct strbuf *sb, const char *path, size_t hint);
>   * NUL bytes.
>   */
>  ssize_t strbuf_write(struct strbuf *sb, FILE *stream);
> +ssize_t strbuf_write_fd(struct strbuf *sb, int fd);
>
>  /**
>   * Read a line from a FILE *, overwriting the existing contents of
> diff --git a/t/t0091-bugreport.sh b/t/t0091-bugreport.sh
> new file mode 100755
> index 0000000000..65f664fdac
> --- /dev/null
> +++ b/t/t0091-bugreport.sh
> @@ -0,0 +1,61 @@
> +#!/bin/sh
> +
> +test_description='git bugreport'
> +
> +. ./test-lib.sh
> +
> +# Headers "[System Info]" will be followed by a non-empty line if we put some
> +# information there; we can make sure all our headers were followed by some
> +# information to check if the command was successful.
> +HEADER_PATTERN="^\[.*\]$"
> +
> +check_all_headers_populated () {
> +	while read -r line
> +	do
> +		if test "$(grep "$HEADER_PATTERN" "$line")"
> +		then
> +			echo "$line"
> +			read -r nextline
> +			if test -z "$nextline"; then
> +				return 1;
> +			fi
> +		fi
> +	done
> +}
> +
> +test_expect_success 'creates a report with content in the right places' '
> +	git bugreport -s check-headers &&
> +	check_all_headers_populated <git-bugreport-check-headers.txt &&
> +	test_when_finished rm git-bugreport-check-headers.txt
> +'
> +
> +test_expect_success 'dies if file with same name as report already exists' '
> +	>>git-bugreport-duplicate.txt &&
> +	test_must_fail git bugreport --suffix duplicate &&
> +	test_when_finished rm git-bugreport-duplicate.txt
> +'
> +
> +test_expect_success '--output-directory puts the report in the provided dir' '
> +	git bugreport -o foo/ &&
> +	test_path_is_file foo/git-bugreport-* &&
> +	test_when_finished rm -fr foo/
> +'
> +
> +test_expect_success 'incorrect arguments abort with usage' '
> +	test_must_fail git bugreport --false 2>output &&
> +	test_i18ngrep usage output &&
> +	test_path_is_missing git-bugreport-*
> +'
> +
> +test_expect_success 'runs outside of a git dir' '
> +	nongit git bugreport &&
> +	test_when_finished rm non-repo/git-bugreport-*
> +'
> +
> +test_expect_success 'can create leading directories outside of a git dir' '
> +	nongit git bugreport -o foo/bar/baz &&
> +	test_when_finished rm -fr foo/bar/baz
> +'
> +
> +
> +test_done
> --
> 2.25.0.265.gbab2e86ba0-goog
>
>
Jeff Hostetler· Mar 5, 2020, 23:34 UTC · re: Johannes Schindelin · lore

Re: [PATCH v9 2/5] bugreport: add tool to generate debugging info

On 3/4/2020 4:35 PM, Johannes Schindelin wrote:
Show 25 quoted lines
> Hi,
> 
> On Mon, 2 Mar 2020, Emily Shaffer wrote:
> 
>>   .gitignore                      |   1 +
>>   Documentation/git-bugreport.txt |  46 ++++++++++++++
>>   Makefile                        |   5 ++
>>   bugreport.c                     | 105 ++++++++++++++++++++++++++++++++
>>   command-list.txt                |   1 +
>>   strbuf.c                        |   4 ++
>>   strbuf.h                        |   1 +
>>   t/t0091-bugreport.sh            |  61 +++++++++++++++++++
>>   8 files changed, 224 insertions(+)
>>   create mode 100644 Documentation/git-bugreport.txt
>>   create mode 100644 bugreport.c
>>   create mode 100755 t/t0091-bugreport.sh
> 
> Hmm. I am still _quite_ convinced that this would be much better as a
> built-in. Remember, non-built-ins come with a footprint, and I do not
> necessarily think that you will want to spend 3MB on a `git-bugreport`
> executable when you could have it for a couple dozen kilobytes inside
> `git` instead.
> 
> Ciao,
> Dscho

Having this command be a stand-alone exe rather than a builtin allows it to have a different linkage. For example, you could include the libcurl and other libraries that are only linked into the transports. And then report version numbers for them if you wanted.

Jeff
Johannes Schindelin· Mar 6, 2020, 13:57 UTC · re: Jeff Hostetler · lore

Re: [PATCH v9 2/5] bugreport: add tool to generate debugging info

Hi Jeff,
On Thu, 5 Mar 2020, Jeff Hostetler wrote:
Show 30 quoted lines
> On 3/4/2020 4:35 PM, Johannes Schindelin wrote:
> >
> > On Mon, 2 Mar 2020, Emily Shaffer wrote:
> >
> > >   .gitignore                      |   1 +
> > >   Documentation/git-bugreport.txt |  46 ++++++++++++++
> > >   Makefile                        |   5 ++
> > >   bugreport.c                     | 105 ++++++++++++++++++++++++++++++++
> > >   command-list.txt                |   1 +
> > >   strbuf.c                        |   4 ++
> > >   strbuf.h                        |   1 +
> > >   t/t0091-bugreport.sh            |  61 +++++++++++++++++++
> > >   8 files changed, 224 insertions(+)
> > >   create mode 100644 Documentation/git-bugreport.txt
> > >   create mode 100644 bugreport.c
> > >   create mode 100755 t/t0091-bugreport.sh
> >
> > Hmm. I am still _quite_ convinced that this would be much better as a
> > built-in. Remember, non-built-ins come with a footprint, and I do not
> > necessarily think that you will want to spend 3MB on a `git-bugreport`
> > executable when you could have it for a couple dozen kilobytes inside
> > `git` instead.
> >
> > Ciao,
> > Dscho
>
> Having this command be a stand-alone exe rather than a builtin allows
> it to have a different linkage.  For example, you could include the
> libcurl and other libraries that are only linked into the transports.
> And then report version numbers for them if you wanted.

While that is true, I would argue that this is quite likely using the _wrong_ information if the user has a different `git-remote-https` in their `PATH`. In other words, that information could _mislead_ the recipient of the bug report.

Now, other people might argue that the different linkage lets `git-bugreport` maybe work where `git` would fail to load a required dynamic library. But again, I would counter that this is a false assumption: since `git-bugreport` relies on `libgit.a`, it essentially _has_ to have the same linkage as `git`, or a superset thereof.

So: No, I really think this is going the wrong direction.

If we want `bugreport` to be a first-class citizen, we should treat it as such. That entails making it a built-in. That entails teaching `git-remote-https` (and potentially other non-builtins) to sprout that option to enquire other information that should be included in the generated part of the bug report.

Ciao, Dscho

Junio C Hamano· Mar 6, 2020, 18:25 UTC · re: Johannes Schindelin · lore

Re: [PATCH v9 2/5] bugreport: add tool to generate debugging info

Johannes Schindelin <Johannes.Schindelin@gmx.de> writes:
> If we want `bugreport` to be a first-class citizen, we should
> treat it as such.  That entails making it a built-in.

The question is, for "bugreport", if it is better to be standalone or to be built-in, and I do not think 'first-class' has anything to do with the question. The transport based on curl-library are separate binaries but they are of course first-class citizens.

Pushing and fetching will happen a lot less often than local operations like "add", "commit", "show", and not paying start-up latencies to load code and link libraries that are not necessary for local operations in built-in, while paying the cost of having to duplicate the memory and disk footprint necessary for libgit.a stuff by making the transport binaries separate from the built-ins, was conscious implementation decision we made earlier to prioritize the reduction of overhead of subcommands for local operation. Yes, the decision de-prioritizes the transport, but that does not mean they are not first-class citizens. It just means that the start-up latency for them (e.g. linking with libcurl) is not huge burden for the overall time cost for the network transfer, and it is necessary cost for them to perform what they need to do anyway, while it is something subcommands for local operations should not have to pay.

> That entails teaching
> `git-remote-https` (and potentially other non-builtins) to sprout that
> option to enquire other information that should be included in the
> generated part of the bug report.
I think later rounds of "git bugreports" already did so.

As I mentioned in a separate message to JeffH, this is a good thing to do, whether "git bugreport" is a built-in or a standalone.

Junio C Hamano· Mar 6, 2020, 18:08 UTC · re: Jeff Hostetler · lore

Re: [PATCH v9 2/5] bugreport: add tool to generate debugging info

Jeff Hostetler <git@jeffhostetler.com> writes:
> Having this command be a stand-alone exe rather than a builtin allows
> it to have a different linkage.  For example, you could include the
> libcurl and other libraries that are only linked into the transports.
> And then report version numbers for them if you wanted.

I actually do not think that is a good rationale. Unless your version of "git bugreport" links into the same binary as the "transports", it still is possible that the version of cURL (for example) "git bugreport" can learn internally from may not have anything to do with the version of the library used by the transports.

Of course, making "bugreport" a built-in, i.e. the same binary as the non-transport part of Git, is not a solution for that issue, either. As Dscho suggested and recent rounds of "git bugreport" implements, teaching the transport binaries an option to report relevant pieces of information regarding the libraries they use, and making "git bugreport" ask them, is a very good solution for that.

What makes it possible by making "git bugreport" stand-alone is for it to link with libraries that the remainder of Git, including the transports that link with libcurl, has no business linking with (a library to obtain system details for diagnostic purposes, for example). Early versions of "git bugreport" may not link with anything special, but making sure it starts and stays standalone leaves it easier to do so _without_ having to worry about splitting the code that started as a built-in out to make it independent later.

Jeff Hostetler· Mar 6, 2020, 18:58 UTC · re: Junio C Hamano · lore

Re: [PATCH v9 2/5] bugreport: add tool to generate debugging info

On 3/6/2020 1:08 PM, Junio C Hamano wrote:
Show 31 quoted lines
> Jeff Hostetler <git@jeffhostetler.com> writes:
> 
>> Having this command be a stand-alone exe rather than a builtin allows
>> it to have a different linkage.  For example, you could include the
>> libcurl and other libraries that are only linked into the transports.
>> And then report version numbers for them if you wanted.
> 
> I actually do not think that is a good rationale.  Unless your
> version of "git bugreport" links into the same binary as the
> "transports", it still is possible that the version of cURL (for
> example) "git bugreport" can learn internally from may not have
> anything to do with the version of the library used by the
> transports.
> 
> Of course, making "bugreport" a built-in, i.e. the same binary as
> the non-transport part of Git, is not a solution for that issue,
> either.  As Dscho suggested and recent rounds of "git bugreport"
> implements, teaching the transport binaries an option to report
> relevant pieces of information regarding the libraries they use, and
> making "git bugreport" ask them, is a very good solution for that.
> 
> What makes it possible by making "git bugreport" stand-alone is for
> it to link with libraries that the remainder of Git, including the
> transports that link with libcurl, has no business linking with (a
> library to obtain system details for diagnostic purposes, for
> example).  Early versions of "git bugreport" may not link with
> anything special, but making sure it starts and stays standalone
> leaves it easier to do so _without_ having to worry about splitting
> the code that started as a built-in out to make it independent later.
> 
> 

Yeah, that makes sense. Thanks Jeff

Johannes Schindelin· Mar 8, 2020, 22:24 UTC · re: Junio C Hamano · lore

Re: [PATCH v9 2/5] bugreport: add tool to generate debugging info

Hi Junio,
On Fri, 6 Mar 2020, Junio C Hamano wrote:
Show 5 quoted lines
> What makes it possible by making "git bugreport" stand-alone is for
> it to link with libraries that the remainder of Git, including the
> transports that link with libcurl, has no business linking with (a
> library to obtain system details for diagnostic purposes, for
> example).

That would, however, make `git-bugreport` more fragile than `git`, i.e. the former might fail to launch under more circumstances than the latter.

Not a good idea for a tool meant to help reporting bugs, to be more fragile to even _start_ than `git`.

A tool that is intended to help users come up with bug reports, despite the fact that users are totally unfamiliar with the implementation details of Git and hence unable to judge competently what information to include or to omit, needs to be _robust_.

You do not want to end up, for example, calling a stale `git-bugreport` from an earlier `make install` (or from a different installation altogether). That would give the recipient not only bogus information, it would be outright misleading.

And that's what I meant by "a stand-alone `git-bugreport` would not be a 1st-class citizen".

I would see it as a serious design issue if this command is anything but a built-in.

Ciao, Dscho

Junio C Hamano· Mar 9, 2020, 14:59 UTC · re: Johannes Schindelin · lore

Re: [PATCH v9 2/5] bugreport: add tool to generate debugging info

Johannes Schindelin <Johannes.Schindelin@gmx.de> writes:
Show 12 quoted lines
> Hi Junio,
>
> On Fri, 6 Mar 2020, Junio C Hamano wrote:
>
>> What makes it possible by making "git bugreport" stand-alone is for
>> it to link with libraries that the remainder of Git, including the
>> transports that link with libcurl, has no business linking with (a
>> library to obtain system details for diagnostic purposes, for
>> example).
>
> That would, however, make `git-bugreport` more fragile than `git`, i.e.
> the former might fail to launch under more circumstances than the latter.
That's a bug.  You can go fix it when it happens.
Johannes Schindelin· Mar 9, 2020, 19:17 UTC · re: Junio C Hamano · lore

Re: [PATCH v9 2/5] bugreport: add tool to generate debugging info

Hi Junio,
On Mon, 9 Mar 2020, Junio C Hamano wrote:
Show 14 quoted lines
> Johannes Schindelin <Johannes.Schindelin@gmx.de> writes:
>
> > On Fri, 6 Mar 2020, Junio C Hamano wrote:
> >
> >> What makes it possible by making "git bugreport" stand-alone is for
> >> it to link with libraries that the remainder of Git, including the
> >> transports that link with libcurl, has no business linking with (a
> >> library to obtain system details for diagnostic purposes, for
> >> example).
> >
> > That would, however, make `git-bugreport` more fragile than `git`, i.e.
> > the former might fail to launch under more circumstances than the latter.
>
> That's a bug.  You can go fix it when it happens.

Heh... yeah, that would be a bug, and the user would not be able to report it via `git bugreport`...

Which is the whole point of my complaint.

Isn't it obvious that we should not have an independent `git-bugreport` by now? With a stand-alone `git-bugreport`, we might

- fail to load the .so files under more circumstances than `git` would
  (since we link to `libgit.a`, we cannot have a subset of dependencies,
  only a superset, or the same),
- launch a stale `git-bugreport` from a completely different Git,
- make users angry for wasting 3MB of their diskspace for `git-bugreport`
  when only a dozen kilobyte would suffice.

On the other hand, if we make `git-bugreport` a built-in, I cannot see any downsides.

For me, therefore, having it as a built-in is a clear win. What am I missing?

Ciao, Dscho

Junio C Hamano· Mar 9, 2020, 19:47 UTC · re: Johannes Schindelin · lore

Re: [PATCH v9 2/5] bugreport: add tool to generate debugging info

Johannes Schindelin <Johannes.Schindelin@gmx.de> writes:
Show 5 quoted lines
> On the other hand, if we make `git-bugreport` a built-in, I cannot see any
> downsides.
>
> For me, therefore, having it as a built-in is a clear win. What am I
> missing?

The right sense of relative importance between efficiently running the rest of Git by not bloting the main binary and making sure not to ship Git that does not run unless "git bugreport" runs (which makes sure that "bugreport" runs) is what you are missing, I suspect.

Another thing is that you are giving "git bugreport" too much weight and too little credit to inexperienced users, by assuming that we will never hear from them when "bugreport" is incapable to run for them. They will report, with or without "git bugreport", and the more important thing you seem to be missing is that after the initial contact it would become an interactive process---there is no reason to prioritize to ensure that the initial contact has everything that is needed to diagnose any issue without further interaction. "With my build, even 'bugreport' dumps core." is perfectly good place to start.

Besides, wouldn't the ones on platforms, on which "git bugreport" may have trouble running, i.e. the ones on minority and exotic platforms, tend to be self sufficient and capable (both diagnosing the issue for themselves, and reaching out to us as appropriate) ones in practice (e.g. I have NonStop folks in mind)?

Johannes Schindelin· Mar 10, 2020, 11:42 UTC · re: Junio C Hamano · lore

Re: [PATCH v9 2/5] bugreport: add tool to generate debugging info

Hi Junio,
On Mon, 9 Mar 2020, Junio C Hamano wrote:
Show 13 quoted lines
> Johannes Schindelin <Johannes.Schindelin@gmx.de> writes:
>
> > On the other hand, if we make `git-bugreport` a built-in, I cannot see any
> > downsides.
> >
> > For me, therefore, having it as a built-in is a clear win. What am I
> > missing?
>
> The right sense of relative importance between efficiently running
> the rest of Git by not bloting the main binary and making sure not
> to ship Git that does not run unless "git bugreport" runs (which
> makes sure that "bugreport" runs) is what you are missing, I
> suspect.
By that reasoning, `git bugreport` should not be included in core Git.
Show 16 quoted lines
> Another thing is that you are giving "git bugreport" too much weight
> and too little credit to inexperienced users, by assuming that we
> will never hear from them when "bugreport" is incapable to run for
> them.  They will report, with or without "git bugreport", and the
> more important thing you seem to be missing is that after the
> initial contact it would become an interactive process---there is
> no reason to prioritize to ensure that the initial contact has
> everything that is needed to diagnose any issue without further
> interaction.  "With my build, even 'bugreport' dumps core." is
> perfectly good place to start.
>
> Besides, wouldn't the ones on platforms, on which "git bugreport"
> may have trouble running, i.e. the ones on minority and exotic
> platforms, tend to be self sufficient and capable (both diagnosing
> the issue for themselves, and reaching out to us as appropriate)
> ones in practice (e.g. I have NonStop folks in mind)?

Yes, I can agree that inexperienced users will not give up and keep up the conversation until they see their problems fixed.

I can also agree that inexperienced users will report bugs even if it is not made super easy for them to do so.

I can agree to that _iff_ I ignore my entire experience maintaining Git for Windows, that is.

Sarcasm aside, I think that you underestimate the importance of a good bug reporting tool like `git bugreport`, and I suspect that Emily does not.

Ciao, Dscho

Junio C Hamano· Mar 10, 2020, 18:37 UTC · re: Johannes Schindelin · lore

Re: [PATCH v9 2/5] bugreport: add tool to generate debugging info

Johannes Schindelin <Johannes.Schindelin@gmx.de> writes:
Show 7 quoted lines
>> The right sense of relative importance between efficiently running
>> the rest of Git by not bloting the main binary and making sure not
>> to ship Git that does not run unless "git bugreport" runs (which
>> makes sure that "bugreport" runs) is what you are missing, I
>> suspect.
>
> By that reasoning, `git bugreport` should not be included in core Git.

The world does not have to be black-or-white. "git bugreport" that covers mainstream platforms in widely-used configurations may be only an 80% solution, but that is better than nothing at all.

Show 19 quoted lines
>> Another thing is that you are giving "git bugreport" too much weight
>> and too little credit to inexperienced users, by assuming that we
>> will never hear from them when "bugreport" is incapable to run for
>> them.  They will report, with or without "git bugreport", and the
>> more important thing you seem to be missing is that after the
>> initial contact it would become an interactive process---there is
>> no reason to prioritize to ensure that the initial contact has
>> everything that is needed to diagnose any issue without further
>> interaction.  "With my build, even 'bugreport' dumps core." is
>> perfectly good place to start.
>>
>> Besides, wouldn't the ones on platforms, on which "git bugreport"
>> may have trouble running, i.e. the ones on minority and exotic
>> platforms, tend to be self sufficient and capable (both diagnosing
>> the issue for themselves, and reaching out to us as appropriate)
>> ones in practice (e.g. I have NonStop folks in mind)?
>
> Yes, I can agree that inexperienced users will not give up and keep
> up the conversation until they see their problems fixed.

Inexperienced users won't be on minority platforms for which we do not have enough resource to get "git bugreport" to run adequetly in the first place. Even if those on minority platforms whose userbase are all technically incapable ones, if they do not help us help them, what can "git bugreport" can do, and more importantly, how would it make a difference between "bugreport" being a built-in vs a standalone?

At this point, I'd have to say that your quibbling does not deserve a serious response and it would be better use of my time to disengage from this thread.

Johannes Schindelin· Mar 10, 2020, 22:08 UTC · re: Junio C Hamano · lore

Re: [PATCH v9 2/5] bugreport: add tool to generate debugging info

Hi Junio,
On Tue, 10 Mar 2020, Junio C Hamano wrote:
> At this point, I'd have to say that your quibbling does not deserve
> a serious response and it would be better use of my time to
> disengage from this thread.

I thought we were discussing whether it makes sense to leave `git-bugreport` as a stand-alone executable, or rather make it a built-in.

If my attempts to convince you that it would be better as a built-in strike you as "quibbling", then I should probably pull out from trying to review and help with this here patch series. I really thought I was helping. My apologies for annoying you instead.

Ciao, Dscho

Emily Shaffer· Mar 19, 2020, 21:39 UTC · re: Johannes Schindelin · lore

Re: [PATCH v9 2/5] bugreport: add tool to generate debugging info

On Wed, Mar 04, 2020 at 10:35:04PM +0100, Johannes Schindelin wrote:
Show 22 quoted lines
> Hi,
> 
> On Mon, 2 Mar 2020, Emily Shaffer wrote:
> 
> >  .gitignore                      |   1 +
> >  Documentation/git-bugreport.txt |  46 ++++++++++++++
> >  Makefile                        |   5 ++
> >  bugreport.c                     | 105 ++++++++++++++++++++++++++++++++
> >  command-list.txt                |   1 +
> >  strbuf.c                        |   4 ++
> >  strbuf.h                        |   1 +
> >  t/t0091-bugreport.sh            |  61 +++++++++++++++++++
> >  8 files changed, 224 insertions(+)
> >  create mode 100644 Documentation/git-bugreport.txt
> >  create mode 100644 bugreport.c
> >  create mode 100755 t/t0091-bugreport.sh
> 
> Hmm. I am still _quite_ convinced that this would be much better as a
> built-in. Remember, non-built-ins come with a footprint, and I do not
> necessarily think that you will want to spend 3MB on a `git-bugreport`
> executable when you could have it for a couple dozen kilobytes inside
> `git` instead.

This is the kind of stuff I really wanted to get straightened out by sending the smaller changeset, so I'm glad to be having this conversation (again, and hopefully for the last time). I read the replies to this mail, which I'm truncating as I think many of them are distracting rather than discussion-worthy, and have tried to summarize:

Builtin:
+ Don't have to call out-of-process to identify 'git version --build-options'
+ Better assurance that we aren't shipping a broken bugreport alongside a new
  version
- Binary bloat, possible startup time hit
? Libraries will behave identically to where the user is seeing issues
  (This point is a possible pro but also a possible con; see similar point in
  standalone list)
Standalone:
+ Could investigate libraries who aren't behaving the way they should.
  (This seems like it'd be better addressed by regression tests, and if we're so
  sure that git-bugreport is working with the info at hand correctly, why don't
  we just write the git binary that way too?)
+ Avoid binary bloat in the main executable.
- Have to ship a big standalone binary instead.
- To get accurate version/build info, need to query the Git executable in a new
  process
Of course if I missed capturing something, please add/correct. Some of
these concerns are quantifiable - binary size and overhead, for example
- so I'm planning on doing some experiments in the coming days. I plan
put together the handful of patches in the latest version of the topic
in both standalone and builtin mode, and then gather the following info:
 - Binary size of 'git'
 - Binary size of 'git-bugreport' when applicable
 - Time for "make" following clean
 - Time for 'git status' on an identical real-world repo (I'll use ours,
   without touching the repo state e.g. changing branch or fetching in
   between)
 - Time to editor for 'git bugreport' with the same setup as previous
 - Peak memory footprint during 'git status'

And of course, if there's more to compare that I can quantify, please let me know that too. I expect I'll be ready to run the experiments by Monday (taking some time off tomorrow) so there's time for me to hear about other concerns.

I'll hold off on sharing my own preference until after we've got some benchmarking to look at, so I can understand the whole picture.

 - Emily
Junio C Hamano· Mar 20, 2020, 00:28 UTC · re: Emily Shaffer · lore

Re: [PATCH v9 2/5] bugreport: add tool to generate debugging info

Emily Shaffer <emilyshaffer@google.com> writes:
Show 8 quoted lines
> Builtin:
> + Don't have to call out-of-process to identify 'git version --build-options'
> + Better assurance that we aren't shipping a broken bugreport alongside a new
>   version
> - Binary bloat, possible startup time hit
> ? Libraries will behave identically to where the user is seeing issues
>   (This point is a possible pro but also a possible con; see similar point in
>   standalone list)
 - Makes it hard to pull in libraries that "bugreport" alone will
   want to use in the future without negatively impacting the rest
   of Git.
>  - Time to editor for 'git bugreport' with the same setup as previous

This is something we absolutely should totally ignore. Even if the bulitin version takes 1 sec to spawn an editor while a standalone one took only 0.1 sec, if other criteria you listed that are more important favours the builtin solution, we should pick it.

In any case, I think we've wasted enough time on this. Let's see a minimum working version that won't break/affect the rest of Git and ship it standalone.

Thanks.
Johannes Schindelin· Mar 20, 2020, 15:35 UTC · re: Junio C Hamano · lore

Re: [PATCH v9 2/5] bugreport: add tool to generate debugging info

On Thu, 19 Mar 2020, Junio C Hamano wrote:
Show 14 quoted lines
> Emily Shaffer <emilyshaffer@google.com> writes:
>
> > Builtin:
> > + Don't have to call out-of-process to identify 'git version --build-options'
> > + Better assurance that we aren't shipping a broken bugreport alongside a new
> >   version
> > - Binary bloat, possible startup time hit
> > ? Libraries will behave identically to where the user is seeing issues
> >   (This point is a possible pro but also a possible con; see similar point in
> >   standalone list)
>
>  - Makes it hard to pull in libraries that "bugreport" alone will
>    want to use in the future without negatively impacting the rest
>    of Git.

And of course we should never do that, lest `git bugreport` won't even load because of it while `git` would.

So even in the purely speculative scenario that we _wanted_ to add more libraries (which we don't, why should we?), we wouldn't actually do it.

Show 10 quoted lines
> >  - Time to editor for 'git bugreport' with the same setup as previous
>
> This is something we absolutely should totally ignore.  Even if the
> bulitin version takes 1 sec to spawn an editor while a standalone
> one took only 0.1 sec, if other criteria you listed that are more
> important favours the builtin solution, we should pick it.
>
> In any case, I think we've wasted enough time on this.  Let's see a
> minimum working version that won't break/affect the rest of Git and
> ship it standalone.

I still disagree with that, but it seems that no amount of arguments will convince Junio, and he's dead set on the standalone version.

Emily Shaffer· Mar 23, 2020, 18:52 UTC · re: Johannes Schindelin · lore

Re: [PATCH v9 2/5] bugreport: add tool to generate debugging info

On Fri, Mar 20, 2020 at 04:35:45PM +0100, Johannes Schindelin wrote:
Show 8 quoted lines
> On Thu, 19 Mar 2020, Junio C Hamano wrote:
> 
> > In any case, I think we've wasted enough time on this.  Let's see a
> > minimum working version that won't break/affect the rest of Git and
> > ship it standalone.
> 
> I still disagree with that, but it seems that no amount of arguments will
> convince Junio, and he's dead set on the standalone version.

In this case, I'll leave the build settings alone and focus on other comments on this patch. Will try to work on it today.

 - Emily
Johannes Schindelin· Mar 20, 2020, 15:42 UTC · re: Emily Shaffer · lore

Re: [PATCH v9 2/5] bugreport: add tool to generate debugging info

Hi Emily,
On Thu, 19 Mar 2020, Emily Shaffer wrote:
Show 43 quoted lines
> On Wed, Mar 04, 2020 at 10:35:04PM +0100, Johannes Schindelin wrote:
>
> > On Mon, 2 Mar 2020, Emily Shaffer wrote:
> >
> > >  .gitignore                      |   1 +
> > >  Documentation/git-bugreport.txt |  46 ++++++++++++++
> > >  Makefile                        |   5 ++
> > >  bugreport.c                     | 105 ++++++++++++++++++++++++++++++++
> > >  command-list.txt                |   1 +
> > >  strbuf.c                        |   4 ++
> > >  strbuf.h                        |   1 +
> > >  t/t0091-bugreport.sh            |  61 +++++++++++++++++++
> > >  8 files changed, 224 insertions(+)
> > >  create mode 100644 Documentation/git-bugreport.txt
> > >  create mode 100644 bugreport.c
> > >  create mode 100755 t/t0091-bugreport.sh
> >
> > Hmm. I am still _quite_ convinced that this would be much better as a
> > built-in. Remember, non-built-ins come with a footprint, and I do not
> > necessarily think that you will want to spend 3MB on a `git-bugreport`
> > executable when you could have it for a couple dozen kilobytes inside
> > `git` instead.
>
> This is the kind of stuff I really wanted to get straightened out by
> sending the smaller changeset, so I'm glad to be having this
> conversation (again, and hopefully for the last time). I read the
> replies to this mail, which I'm truncating as I think many of them are
> distracting rather than discussion-worthy, and have tried to summarize:
>
> Builtin:
> + Don't have to call out-of-process to identify 'git version --build-options'
> + Better assurance that we aren't shipping a broken bugreport alongside a new
>   version
> - Binary bloat, possible startup time hit
> ? Libraries will behave identically to where the user is seeing issues
>   (This point is a possible pro but also a possible con; see similar point in
>   standalone list)
>
> Standalone:
> + Could investigate libraries who aren't behaving the way they should.
>   (This seems like it'd be better addressed by regression tests, and if we're so
>   sure that git-bugreport is working with the info at hand correctly, why don't
>   we just write the git binary that way too?)

No, you're linking with libgit.a, you will have _at least_ the same set of dependencies as `git`. I made that point before.

> + Avoid binary bloat in the main executable.
What? What bloat? Have you measured this?
> - Have to ship a big standalone binary instead.
> - To get accurate version/build info, need to query the Git executable in a new
>   process

Worse. You might pick up inconsistent info from unrelated Git versions, and would be none the wiser. I made that point before.

For example, if you call `git bugreport` in a Git version that does not even include `git-bugreport`, you could pick up a `git-bugreport` from a _different_ Git version. This is a very real scenario on Windows, where we have many applications that ship with their own minimal version of Git for Windows.

Show 14 quoted lines
> Of course if I missed capturing something, please add/correct. Some of
> these concerns are quantifiable - binary size and overhead, for example
> - so I'm planning on doing some experiments in the coming days. I plan
> put together the handful of patches in the latest version of the topic
> in both standalone and builtin mode, and then gather the following info:
>
>  - Binary size of 'git'
>  - Binary size of 'git-bugreport' when applicable
>  - Time for "make" following clean
>  - Time for 'git status' on an identical real-world repo (I'll use ours,
>    without touching the repo state e.g. changing branch or fetching in
>    between)
>  - Time to editor for 'git bugreport' with the same setup as previous
>  - Peak memory footprint during 'git status'

Something that you cannot quantify, of course, is the robustness. Which in my mind is more important than all of the above, and of course you would only be able to guarantee that with a built-in version.

Show 7 quoted lines
> And of course, if there's more to compare that I can quantify, please
> let me know that too. I expect I'll be ready to run the experiments by
> Monday (taking some time off tomorrow) so there's time for me to hear
> about other concerns.
>
> I'll hold off on sharing my own preference until after we've got some
> benchmarking to look at, so I can understand the whole picture.

Why? Why not strong-arm your preference? Junio and I are not shy doing the same, and those are _your_ patches. Junio is clearly not interested in the command at all, but you are clearly interested in it [*1*]. You should have more than just the final say over this.

Ciao, Dscho

Footnote *1*: I am *obviously* interested in this because it might potentially make my life as Git for Windows' maintainer a lot easier. If it is robust enough that I don't get bug reports about `git-bugreport` itself.

Emily Shaffer· Mar 23, 2020, 18:50 UTC · re: Johannes Schindelin · lore

Re: [PATCH v9 2/5] bugreport: add tool to generate debugging info

On Fri, Mar 20, 2020 at 04:42:36PM +0100, Johannes Schindelin wrote:
Show 10 quoted lines
> Hi Emily,
> 
> On Thu, 19 Mar 2020, Emily Shaffer wrote:
> > I'll hold off on sharing my own preference until after we've got some
> > benchmarking to look at, so I can understand the whole picture.
> 
> Why? Why not strong-arm your preference? Junio and I are not shy doing the
> same, and those are _your_ patches. Junio is clearly not interested in the
> command at all, but you are clearly interested in it [*1*]. You should
> have more than just the final say over this.

We are different people, and we approach problems and disagreements differently. I am almost never the type to strong-arm my preference; I'd rather listen to other arguments and look at data, which is why I proposed the experiments I mentioned here. As for you and Junio not being shy, as you put it, I found most of the discussion offputting, and the tone used absolutely contributed to me finding other things to work on instead of coming back to this minefield sooner.

 - Emily
Junio C Hamano· Mar 20, 2020, 17:43 UTC · re: Emily Shaffer · lore

Re: [PATCH v9 2/5] bugreport: add tool to generate debugging info

Emily Shaffer <emilyshaffer@google.com> writes:
> This is the kind of stuff I really wanted to get straightened out by
> sending the smaller changeset, so I'm glad to be having this
> conversation (again, and hopefully for the last time).

I actually have a suspicion that "git bugreport" that is spawned via "git" wrapper is a bad idea (in other words, /usr/bin/git-bug that is totally standalone may be better).

The thing is, anything launched by "git" as its subcommand (be it standalone or builtin) sees an environment already modified by "git", so inspecting say "$PATH" from "git bugreport" (be it standalone or builtin) does not show what the end-user, who may be having trouble, actually has. The mangling of $PATH alone happens to be simple and (we may think) we can easily reverse without losing bits, but there would probably other differences that we think is so subtle and insignificant, right now in this discussion without having actual end-user who is having trouble in front of us, that having "git" layer in between may hide from us.

Having "git-bug" a totally separate tool, that does not even go through git.c::cmd_main(), would also allow (and force) us to treat "git" just like any system component on the end-users' system whose versions and configurations may affect the use of "git" by the end user. The tool, instead of relying on git_version_string[] that is determined at the compile time, would ask "git version" just like the end-users would when asked by us "what version of git do you run?" It also means that "git-bug" can be updated at different cadence and the mismatch of versions between it and "git" does not matter at all.

Having said all that, after suggesting to make the tool even more distant from the remainder of the binary, quite honestly, I do not even want to see us wasting any more time on builtin/standalone at this point, and instead would like to see reports from the end-users produced by a lets-start-small version of the tool and measure how having the tool actually helps.

Thanks.
Johannes Schindelin· Mar 20, 2020, 22:38 UTC · re: Junio C Hamano · lore

Re: [PATCH v9 2/5] bugreport: add tool to generate debugging info

Hi Junio,
On Fri, 20 Mar 2020, Junio C Hamano wrote:
Show 9 quoted lines
> Emily Shaffer <emilyshaffer@google.com> writes:
>
> > This is the kind of stuff I really wanted to get straightened out by
> > sending the smaller changeset, so I'm glad to be having this
> > conversation (again, and hopefully for the last time).
>
> I actually have a suspicion that "git bugreport" that is spawned via
> "git" wrapper is a bad idea (in other words, /usr/bin/git-bug that
> is totally standalone may be better).

The obvious downside of `/usr/bin/git-bug`, of course, is that it has no way to provide accurate data regarding, say, the cURL version in use.

That's a pretty severe downside if you are truly interested in helping bug reporters and bug receivers.

Ciao, Dscho

Show 32 quoted lines
>
> The thing is, anything launched by "git" as its subcommand (be it
> standalone or builtin) sees an environment already modified by
> "git", so inspecting say "$PATH" from "git bugreport" (be it
> standalone or builtin) does not show what the end-user, who may be
> having trouble, actually has.  The mangling of $PATH alone happens
> to be simple and (we may think) we can easily reverse without losing
> bits, but there would probably other differences that we think is so
> subtle and insignificant, right now in this discussion without
> having actual end-user who is having trouble in front of us, that
> having "git" layer in between may hide from us.
>
> Having "git-bug" a totally separate tool, that does not even go
> through git.c::cmd_main(), would also allow (and force) us to treat
> "git" just like any system component on the end-users' system whose
> versions and configurations may affect the use of "git" by the end
> user.  The tool, instead of relying on git_version_string[] that is
> determined at the compile time, would ask "git version" just like
> the end-users would when asked by us "what version of git do you
> run?"  It also means that "git-bug" can be updated at different
> cadence and the mismatch of versions between it and "git" does not
> matter at all.
>
> Having said all that, after suggesting to make the tool even more
> distant from the remainder of the binary, quite honestly, I do not
> even want to see us wasting any more time on builtin/standalone at
> this point, and instead would like to see reports from the end-users
> produced by a lets-start-small version of the tool and measure how
> having the tool actually helps.
>
> Thanks.
>
Junio C Hamano· Mar 20, 2020, 22:47 UTC · re: Johannes Schindelin · lore

Re: [PATCH v9 2/5] bugreport: add tool to generate debugging info

Johannes Schindelin <Johannes.Schindelin@gmx.de> writes:
Show 6 quoted lines
>> I actually have a suspicion that "git bugreport" that is spawned via
>> "git" wrapper is a bad idea (in other words, /usr/bin/git-bug that
>> is totally standalone may be better).
>
> The obvious downside of `/usr/bin/git-bug`, of course, is that it has no
> way to provide accurate data regarding, say, the cURL version in use.
Sorry, but I do not see what's new in your argument this time.

I thought we've already established that the best solution for the "accurate data regarding, say, the cURL version in use" is to use your earlier idea, i.e. give an interface to git-remote-curl so that "git bugreport" can ask it such details, because "git bugreport" that is known by git.c::cmd_main(), whether it is builtin or standalone, is *NOT* linked to the transport anyway.

And the same interface can be used by an independent "git-bug", or even by the end user who is sitting at a terminal when asked by git developers "what version of curl library does your build link with?".

Johannes Schindelin· Mar 21, 2020, 10:53 UTC · re: Junio C Hamano · lore

Re: [PATCH v9 2/5] bugreport: add tool to generate debugging info

Hi Junio,
On Fri, 20 Mar 2020, Junio C Hamano wrote:
Show 22 quoted lines
> Johannes Schindelin <Johannes.Schindelin@gmx.de> writes:
>
> >> I actually have a suspicion that "git bugreport" that is spawned via
> >> "git" wrapper is a bad idea (in other words, /usr/bin/git-bug that
> >> is totally standalone may be better).
> >
> > The obvious downside of `/usr/bin/git-bug`, of course, is that it has no
> > way to provide accurate data regarding, say, the cURL version in use.
>
> Sorry, but I do not see what's new in your argument this time.
>
> I thought we've already established that the best solution for the
> "accurate data regarding, say, the cURL version in use" is to use
> your earlier idea, i.e. give an interface to git-remote-curl so that
> "git bugreport" can ask it such details, because "git bugreport"
> that is known by git.c::cmd_main(), whether it is builtin or
> standalone, is *NOT* linked to the transport anyway.
>
> And the same interface can be used by an independent "git-bug", or
> even by the end user who is sitting at a terminal when asked by git
> developers "what version of curl library does your build link
> with?".

You are _asking_ for version mismatch here. If `git-bug` is a totally standalone program, then it cannot rely at all on `git` to give it the information it wants. Forward compatibility becomes another concern.

In other words, all the avoidably incurred complexity will come back to make the entire `git bugreport` not worth all the effort Emily put into it.

Ciao, Dscho

Emily Shaffer· Mar 2, 2020, 23:03 UTC · re: Emily Shaffer · lore

[PATCH v9 3/5] bugreport: gather git version and build info

Knowing which version of Git a user has and how it was built allows us to more precisely pin down the circumstances when a certain issue occurs, so teach bugreport how to tell us the same output as 'git version --build-options'.

It's not ideal to directly call 'git version --build-options' because that output goes to stdout. Instead, wrap the version string in a helper within help.[ch] library, and call that helper from within the bugreport library.

Signed-off-by: Emily Shaffer <emilyshaffer@google.com>
---
 Documentation/git-bugreport.txt |  4 +++
 bugreport.c                     | 19 +++++++++++++-
 help.c                          | 46 ++++++++++++++++++++-------------
 help.h                          |  1 +
 4 files changed, 51 insertions(+), 19 deletions(-)
Show changes to 4 files +51 −19

Documentation/git-bugreport.txt, bugreport.c, help.c, help.h

diff --git a/Documentation/git-bugreport.txt b/Documentation/git-bugreport.txt
index 1f9fde5cde..f44ae8cbe7 100644
--- a/Documentation/git-bugreport.txt
+++ b/Documentation/git-bugreport.txt
@@ -23,6 +23,10 @@ The following information is requested from the user:
  - Expected behavior
  - Actual behavior
 
+The following information is captured automatically:
+
+ - 'git version --build-options'
+
 This tool is invoked via the typical Git setup process, which means that in some
 cases, it might not be able to launch - for example, if a relevant config file
 is unreadable. In this kind of scenario, it may be helpful to manually gather
diff --git a/bugreport.c b/bugreport.c
index f473d606f2..c20437dc6a 100644
--- a/bugreport.c
+++ b/bugreport.c
@@ -1,8 +1,17 @@
-#include "builtin.h"
+#include "cache.h"
 #include "parse-options.h"
 #include "stdio.h"
 #include "strbuf.h"
 #include "time.h"
+#include "help.h"
+
+static void get_system_info(struct strbuf *sys_info)
+{
+	/* get git version from native cmd */
+	strbuf_addstr(sys_info, _("git version:\n"));
+	get_version_info(sys_info, 1);
+	strbuf_complete_line(sys_info);
+}
 
 static const char * const bugreport_usage[] = {
 	N_("git bugreport [-o|--output-directory <file>] [-s|--suffix <format>]"),
@@ -32,6 +41,11 @@ static int get_bug_template(struct strbuf *template)
 	return 0;
 }
 
+static void get_header(struct strbuf *buf, const char *title)
+{
+	strbuf_addf(buf, "\n\n[%s]\n", title);
+}
+
 int cmd_main(int argc, const char **argv)
 {
 	struct strbuf buffer = STRBUF_INIT;
@@ -79,6 +93,9 @@ int cmd_main(int argc, const char **argv)
 	/* Prepare the report contents */
 	get_bug_template(&buffer);
 
+	get_header(&buffer, _("System Info"));
+	get_system_info(&buffer);
+
 	/* fopen doesn't offer us an O_EXCL alternative, except with glibc. */
 	report = open(report_path.buf, O_CREAT | O_EXCL | O_WRONLY, 0666);
 
diff --git a/help.c b/help.c
index a21487db77..1de9c0d589 100644
--- a/help.c
+++ b/help.c
@@ -622,8 +622,32 @@ const char *help_unknown_cmd(const char *cmd)
 	exit(1);
 }
 
+void get_version_info(struct strbuf *buf, int show_build_options)
+{
+	/*
+	 * The format of this string should be kept stable for compatibility
+	 * with external projects that rely on the output of "git version".
+	 *
+	 * Always show the version, even if other options are given.
+	 */
+	strbuf_addf(buf, "git version %s\n", git_version_string);
+
+	if (show_build_options) {
+		strbuf_addf(buf, "cpu: %s\n", GIT_HOST_CPU);
+		if (git_built_from_commit_string[0])
+			strbuf_addf(buf, "built from commit: %s\n",
+			       git_built_from_commit_string);
+		else
+			strbuf_addstr(buf, "no commit associated with this build\n");
+		strbuf_addf(buf, "sizeof-long: %d\n", (int)sizeof(long));
+		strbuf_addf(buf, "sizeof-size_t: %d\n", (int)sizeof(size_t));
+		/* NEEDSWORK: also save and output GIT-BUILD_OPTIONS? */
+	}
+}
+
 int cmd_version(int argc, const char **argv, const char *prefix)
 {
+	struct strbuf buf = STRBUF_INIT;
 	int build_options = 0;
 	const char * const usage[] = {
 		N_("git version [<options>]"),
@@ -637,25 +661,11 @@ int cmd_version(int argc, const char **argv, const char *prefix)
 
 	argc = parse_options(argc, argv, prefix, options, usage, 0);
 
-	/*
-	 * The format of this string should be kept stable for compatibility
-	 * with external projects that rely on the output of "git version".
-	 *
-	 * Always show the version, even if other options are given.
-	 */
-	printf("git version %s\n", git_version_string);
+	get_version_info(&buf, build_options);
+	printf("%s", buf.buf);
+
+	strbuf_release(&buf);
 
-	if (build_options) {
-		printf("cpu: %s\n", GIT_HOST_CPU);
-		if (git_built_from_commit_string[0])
-			printf("built from commit: %s\n",
-			       git_built_from_commit_string);
-		else
-			printf("no commit associated with this build\n");
-		printf("sizeof-long: %d\n", (int)sizeof(long));
-		printf("sizeof-size_t: %d\n", (int)sizeof(size_t));
-		/* NEEDSWORK: also save and output GIT-BUILD_OPTIONS? */
-	}
 	return 0;
 }
 
diff --git a/help.h b/help.h
index 9071894e8c..500521b908 100644
--- a/help.h
+++ b/help.h
@@ -37,6 +37,7 @@ void add_cmdname(struct cmdnames *cmds, const char *name, int len);
 void exclude_cmds(struct cmdnames *cmds, struct cmdnames *excludes);
 int is_in_cmdlist(struct cmdnames *cmds, const char *name);
 void list_commands(unsigned int colopts, struct cmdnames *main_cmds, struct cmdnames *other_cmds);
+void get_version_info(struct strbuf *buf, int show_build_options);
 
 /*
  * call this to die(), when it is suspected that the user mistyped a
-- 
2.25.0.265.gbab2e86ba0-goog
Junio C Hamano· Mar 23, 2020, 21:20 UTC · re: Emily Shaffer · lore

Re: [PATCH v9 3/5] bugreport: gather git version and build info

Emily Shaffer <emilyshaffer@google.com> writes:
> +The following information is captured automatically:
> +
> + - 'git version --build-options'
Good.  
Do make sure to give us the same information as if the end user
typed that command from the command line.  There may be more than
one directory on $PATH that has "git" in it; we want to see the one
that is giving trouble to the end user, not necessarily the one that
came from the same source as running "git bugreport" was compiled
from, so it is a good idea not to rely on the contents of static
git_version_string[] array that came in libgit.a that the bugreport
tool happened to be linked with.
   
It may not be in the scope of this step, but we'd want to see
versions of executables for the python interpreter (2vs3), the
tcl/tk interpreter (i.e. wish), the shell (i.e. bash, dash, etc.).

In addition to them, we would want to see versions of some of our own binaries (i.e. "git", and transports that are separate executable files). It would lead to a confusing diagnositic session if the end-user's PATH has /usr/bin and then $HOME/bin, and the end-user has a newer version of "git" with "bugreport" only in $HOME/bin. The user may think s/he is using the latest self-compiled "git", and "bugreport" might even agree if it trusts anything determined when "bugreport" was compiled, but in reality the version of "git" used largely was coming from "/usr/bin" except for any new subcommands, or something silly like that, and asking the environment just like the end user does is the only way to make sure we are getting the true piture.

Thanks.
Emily Shaffer· Mar 2, 2020, 23:03 UTC · re: Emily Shaffer · lore

[PATCH v9 4/5] bugreport: add uname info

The contents of uname() can give us some insight into what sort of system the user is running on, and help us replicate their setup if need be. The domainname field is not guaranteed to be available, so don't collect it.

Signed-off-by: Emily Shaffer <emilyshaffer@google.com>
---
 Documentation/git-bugreport.txt |  1 +
 bugreport.c                     | 16 +++++++++++++++-
 2 files changed, 16 insertions(+), 1 deletion(-)
Show changes to 2 files +16 −1

Documentation/git-bugreport.txt, bugreport.c

diff --git a/Documentation/git-bugreport.txt b/Documentation/git-bugreport.txt
index f44ae8cbe7..17b0d14e8d 100644
--- a/Documentation/git-bugreport.txt
+++ b/Documentation/git-bugreport.txt
@@ -26,6 +26,7 @@ The following information is requested from the user:
 The following information is captured automatically:
 
  - 'git version --build-options'
+ - uname sysname, release, version, and machine strings
 
 This tool is invoked via the typical Git setup process, which means that in some
 cases, it might not be able to launch - for example, if a relevant config file
diff --git a/bugreport.c b/bugreport.c
index c20437dc6a..857b4f712c 100644
--- a/bugreport.c
+++ b/bugreport.c
@@ -7,10 +7,24 @@
 
 static void get_system_info(struct strbuf *sys_info)
 {
+	struct utsname uname_info;
+
 	/* get git version from native cmd */
 	strbuf_addstr(sys_info, _("git version:\n"));
 	get_version_info(sys_info, 1);
-	strbuf_complete_line(sys_info);
+
+	/* system call for other version info */
+	strbuf_addstr(sys_info, "uname: ");
+	if (uname(&uname_info))
+		strbuf_addf(sys_info, _("uname() failed with error '%s' (%d)\n"),
+			    strerror(errno),
+			    errno);
+	else
+		strbuf_addf(sys_info, "%s %s %s %s\n",
+			    uname_info.sysname,
+			    uname_info.release,
+			    uname_info.version,
+			    uname_info.machine);
 }
 
 static const char * const bugreport_usage[] = {
-- 
2.25.0.265.gbab2e86ba0-goog
Emily Shaffer· Mar 2, 2020, 23:04 UTC · re: Emily Shaffer · lore

[PATCH v9 5/5] bugreport: add compiler info

To help pinpoint the source of a regression, it is useful to know some info about the compiler which the user's Git client was built with. By adding a generic get_compiler_info() in 'compat/' we can choose which relevant information to share per compiler; to get started, let's demonstrate the version of glibc if the user built with 'gcc'.

Signed-off-by: Emily Shaffer <emilyshaffer@google.com>
---
 Documentation/git-bugreport.txt |  1 +
 bugreport.c                     |  6 ++++++
 compat/compiler.h               | 38 +++++++++++++++++++++++++++++++++
 3 files changed, 45 insertions(+)
 create mode 100644 compat/compiler.h
Show changes to 3 files +45 −0

Documentation/git-bugreport.txt, bugreport.c, compat/compiler.h

diff --git a/Documentation/git-bugreport.txt b/Documentation/git-bugreport.txt
index 17b0d14e8d..643d1b2884 100644
--- a/Documentation/git-bugreport.txt
+++ b/Documentation/git-bugreport.txt
@@ -27,6 +27,7 @@ The following information is captured automatically:
 
  - 'git version --build-options'
  - uname sysname, release, version, and machine strings
+ - Compiler-specific info string
 
 This tool is invoked via the typical Git setup process, which means that in some
 cases, it might not be able to launch - for example, if a relevant config file
diff --git a/bugreport.c b/bugreport.c
index 857b4f712c..5073c901cd 100644
--- a/bugreport.c
+++ b/bugreport.c
@@ -4,6 +4,7 @@
 #include "strbuf.h"
 #include "time.h"
 #include "help.h"
+#include "compat/compiler.h"
 
 static void get_system_info(struct strbuf *sys_info)
 {
@@ -25,6 +26,11 @@ static void get_system_info(struct strbuf *sys_info)
 			    uname_info.release,
 			    uname_info.version,
 			    uname_info.machine);
+
+	strbuf_addstr(sys_info, _("compiler info: "));
+	get_compiler_info(sys_info);
+	strbuf_addstr(sys_info, _("libc info: "));
+	get_libc_info(sys_info);
 }
 
 static const char * const bugreport_usage[] = {
diff --git a/compat/compiler.h b/compat/compiler.h
new file mode 100644
index 0000000000..21f098e6a4
--- /dev/null
+++ b/compat/compiler.h
@@ -0,0 +1,38 @@
+#ifndef COMPILER_H
+#define COMPILER_H
+
+#include "git-compat-util.h"
+#include "strbuf.h"
+
+#ifdef __GLIBC__
+#include <gnu/libc-version.h>
+#endif
+
+static inline void get_compiler_info(struct strbuf *info)
+{
+	int len = info->len;
+#ifdef __GNUC__
+	strbuf_addf(info, "gnuc: %d.%d\n", __GNUC__, __GNUC_MINOR__);
+#endif
+
+#ifdef _MSC_VER
+	strbuf_addf(info, "MSVC version: %s\n", _MSC_FULL_VER);
+#endif
+
+	if (len == info->len)
+		strbuf_addf(info, _("no compiler information available\n"));
+}
+
+static inline void get_libc_info(struct strbuf *info)
+{
+	int len = info->len;
+
+#ifdef __GLIBC__
+	strbuf_addf(info, "glibc: %s\n", gnu_get_libc_version());
+#endif
+
+	if (len == info->len)
+		strbuf_addf(info, _("no libc information available\n"));
+}
+
+#endif /* COMPILER_H */
-- 
2.25.0.265.gbab2e86ba0-goog
Danh Doan· Mar 3, 2020, 11:46 UTC · re: Emily Shaffer · lore

Re: [PATCH v9 5/5] bugreport: add compiler info

On 2020-03-02 15:04:00-0800, Emily Shaffer <emilyshaffer@google.com> wrote:
Show 72 quoted lines
> To help pinpoint the source of a regression, it is useful to know some
> info about the compiler which the user's Git client was built with. By
> adding a generic get_compiler_info() in 'compat/' we can choose which
> relevant information to share per compiler; to get started, let's
> demonstrate the version of glibc if the user built with 'gcc'.
> 
> Signed-off-by: Emily Shaffer <emilyshaffer@google.com>
> ---
>  Documentation/git-bugreport.txt |  1 +
>  bugreport.c                     |  6 ++++++
>  compat/compiler.h               | 38 +++++++++++++++++++++++++++++++++
>  3 files changed, 45 insertions(+)
>  create mode 100644 compat/compiler.h
> 
> diff --git a/Documentation/git-bugreport.txt b/Documentation/git-bugreport.txt
> index 17b0d14e8d..643d1b2884 100644
> --- a/Documentation/git-bugreport.txt
> +++ b/Documentation/git-bugreport.txt
> @@ -27,6 +27,7 @@ The following information is captured automatically:
>  
>   - 'git version --build-options'
>   - uname sysname, release, version, and machine strings
> + - Compiler-specific info string
>  
>  This tool is invoked via the typical Git setup process, which means that in some
>  cases, it might not be able to launch - for example, if a relevant config file
> diff --git a/bugreport.c b/bugreport.c
> index 857b4f712c..5073c901cd 100644
> --- a/bugreport.c
> +++ b/bugreport.c
> @@ -4,6 +4,7 @@
>  #include "strbuf.h"
>  #include "time.h"
>  #include "help.h"
> +#include "compat/compiler.h"
>  
>  static void get_system_info(struct strbuf *sys_info)
>  {
> @@ -25,6 +26,11 @@ static void get_system_info(struct strbuf *sys_info)
>  			    uname_info.release,
>  			    uname_info.version,
>  			    uname_info.machine);
> +
> +	strbuf_addstr(sys_info, _("compiler info: "));
> +	get_compiler_info(sys_info);
> +	strbuf_addstr(sys_info, _("libc info: "));
> +	get_libc_info(sys_info);
>  }
>  
>  static const char * const bugreport_usage[] = {
> diff --git a/compat/compiler.h b/compat/compiler.h
> new file mode 100644
> index 0000000000..21f098e6a4
> --- /dev/null
> +++ b/compat/compiler.h
> @@ -0,0 +1,38 @@
> +#ifndef COMPILER_H
> +#define COMPILER_H
> +
> +#include "git-compat-util.h"
> +#include "strbuf.h"
> +
> +#ifdef __GLIBC__
> +#include <gnu/libc-version.h>
> +#endif
> +
> +static inline void get_compiler_info(struct strbuf *info)
> +{
> +	int len = info->len;
> +#ifdef __GNUC__
> +	strbuf_addf(info, "gnuc: %d.%d\n", __GNUC__, __GNUC_MINOR__);
> +#endif

This fixup can be used for clang on Linux, I guess it could be applied for macOS too (since default gcc on macOS is symlinked to clang?)

--------------8<----------------------
Show changes to compat/compiler.h +3 −1
diff --git a/compat/compiler.h b/compat/compiler.h
index 21f098e6a4..055dbb5e1b 100644
--- a/compat/compiler.h
+++ b/compat/compiler.h
@@ -11,7 +11,9 @@
 static inline void get_compiler_info(struct strbuf *info)
 {
 	int len = info->len;
-#ifdef __GNUC__
+#ifdef __clang__
+	strbuf_addf(info, "clang: %s\n", __clang_version__);
+#elif defined(__GNUC__)
 	strbuf_addf(info, "gnuc: %d.%d\n", __GNUC__, __GNUC_MINOR__);
 #endif
 
-------------------->8---------------------

> +
> +#ifdef _MSC_VER
> +	strbuf_addf(info, "MSVC version: %s\n", _MSC_FULL_VER);
> +#endif
> +
> +	if (len == info->len)
> +		strbuf_addf(info, _("no compiler information available\n"));
> +}
> +
> +static inline void get_libc_info(struct strbuf *info)
> +{
> +	int len = info->len;
> +
> +#ifdef __GLIBC__
> +	strbuf_addf(info, "glibc: %s\n", gnu_get_libc_version());
> +#endif
> +
> +	if (len == info->len)
> +		strbuf_addf(info, _("no libc information available\n"));
> +}
> +
> +#endif /* COMPILER_H */
> -- 
> 2.25.0.265.gbab2e86ba0-goog
> 
-- 
Danh
Junio C Hamano· Mar 3, 2020, 14:07 UTC · re: Emily Shaffer · lore

Re: [PATCH v9 5/5] bugreport: add compiler info

Emily Shaffer <emilyshaffer@google.com> writes:
Show 5 quoted lines
> +static inline void get_compiler_info(struct strbuf *info)
> +{
> + ...
> +	if (len == info->len)
> +		strbuf_addf(info, _("no compiler information available\n"));
s/addf/addstr/ to squelch https://travis-ci.org/git/git/jobs/657572439
Show 7 quoted lines
> +}
> +
> +static inline void get_libc_info(struct strbuf *info)
> +{
> + ...
> +	if (len == info->len)
> +		strbuf_addf(info, _("no libc information available\n"));
Ditto.
> +}
> +
> +#endif /* COMPILER_H */
Johannes Schindelin· Mar 4, 2020, 21:39 UTC · re: Emily Shaffer · lore

Re: [PATCH v9 5/5] bugreport: add compiler info

Hi Emily,
On Mon, 2 Mar 2020, Emily Shaffer wrote:
Show 25 quoted lines
> diff --git a/compat/compiler.h b/compat/compiler.h
> new file mode 100644
> index 0000000000..21f098e6a4
> --- /dev/null
> +++ b/compat/compiler.h
> @@ -0,0 +1,38 @@
> +#ifndef COMPILER_H
> +#define COMPILER_H
> +
> +#include "git-compat-util.h"
> +#include "strbuf.h"
> +
> +#ifdef __GLIBC__
> +#include <gnu/libc-version.h>
> +#endif
> +
> +static inline void get_compiler_info(struct strbuf *info)
> +{
> +	int len = info->len;
> +#ifdef __GNUC__
> +	strbuf_addf(info, "gnuc: %d.%d\n", __GNUC__, __GNUC_MINOR__);
> +#endif
> +
> +#ifdef _MSC_VER
> +	strbuf_addf(info, "MSVC version: %s\n", _MSC_FULL_VER);
I need this to fix a crash in the Visual Studio build's test run:
-- snip --
Subject: [PATCH] fixup??? bugreport: add compiler info

As documented at https://docs.microsoft.com/en-us/cpp/preprocessor/predefined-macros?view=vs-2019, `_MSC_FULL_VER` is an integer, not a string. Therefore this fix is needed to prevent a segmentation fault in the test t0091.1.

Signed-off-by: Johannes Schindelin <johannes.schindelin@gmx.de>
---
 compat/compiler.h | 3 ++-
 1 file changed, 2 insertions(+), 1 deletion(-)
Show changes to compat/compiler.h +2 −3
diff --git a/compat/compiler.h b/compat/compiler.h
index ce6a7f6de9a..ac90fa051dd 100644
--- a/compat/compiler.h
+++ b/compat/compiler.h
@@ -16,7 +16,8 @@ static inline void get_compiler_info(struct strbuf *info)
 #endif

 #ifdef _MSC_VER
-	strbuf_addf(info, "MSVC version: %s\n", _MSC_FULL_VER);
+	strbuf_addf(info, "MSVC version: %02d.%02d.%05d\n",
+		    _MSC_VER / 100, _MSC_VER % 100, _MSC_FULL_VER % 100000);
 #endif

 	if (len == info->len)
-- snap --

Could you squash that in, please?

BTW the two issues I reported in the earlier round are still problems.
Could you squash my fixes, please? For your convenience, you can pluck all
four of them right off of
https://github.com/git-for-windows/git/commits/shears/pu

Just replace the `???` by `!` and you can even use `git rebase
--autosquash`.

Ciao,
Dscho


> +#endif
> +
> +	if (len == info->len)
> +		strbuf_addf(info, _("no compiler information available\n"));
> +}
> +
> +static inline void get_libc_info(struct strbuf *info)
> +{
> +	int len = info->len;
> +
> +#ifdef __GLIBC__
> +	strbuf_addf(info, "glibc: %s\n", gnu_get_libc_version());
> +#endif
> +
> +	if (len == info->len)
> +		strbuf_addf(info, _("no libc information available\n"));
> +}
> +
> +#endif /* COMPILER_H */
> --
> 2.25.0.265.gbab2e86ba0-goog
>
>
Emily Shaffer· Mar 23, 2020, 21:27 UTC · re: Johannes Schindelin · lore

Re: [PATCH v9 5/5] bugreport: add compiler info

On Wed, Mar 04, 2020 at 10:39:53PM +0100, Johannes Schindelin wrote:
Show 31 quoted lines
> Hi Emily,
> 
> On Mon, 2 Mar 2020, Emily Shaffer wrote:
> 
> > diff --git a/compat/compiler.h b/compat/compiler.h
> > new file mode 100644
> > index 0000000000..21f098e6a4
> > --- /dev/null
> > +++ b/compat/compiler.h
> > @@ -0,0 +1,38 @@
> > +#ifndef COMPILER_H
> > +#define COMPILER_H
> > +
> > +#include "git-compat-util.h"
> > +#include "strbuf.h"
> > +
> > +#ifdef __GLIBC__
> > +#include <gnu/libc-version.h>
> > +#endif
> > +
> > +static inline void get_compiler_info(struct strbuf *info)
> > +{
> > +	int len = info->len;
> > +#ifdef __GNUC__
> > +	strbuf_addf(info, "gnuc: %d.%d\n", __GNUC__, __GNUC_MINOR__);
> > +#endif
> > +
> > +#ifdef _MSC_VER
> > +	strbuf_addf(info, "MSVC version: %s\n", _MSC_FULL_VER);
> 
> I need this to fix a crash in the Visual Studio build's test run:

Hummm, is that not part of the GGG suite? I saw it pass (and then failed to include the updated patches with v9 with the changes you mentioned below).

Show 36 quoted lines
> 
> -- snip --
> Subject: [PATCH] fixup??? bugreport: add compiler info
> 
> As documented at
> https://docs.microsoft.com/en-us/cpp/preprocessor/predefined-macros?view=vs-2019,
> `_MSC_FULL_VER` is an integer, not a string. Therefore this fix is
> needed to prevent a segmentation fault in the test t0091.1.
> 
> Signed-off-by: Johannes Schindelin <johannes.schindelin@gmx.de>
> ---
>  compat/compiler.h | 3 ++-
>  1 file changed, 2 insertions(+), 1 deletion(-)
> 
> diff --git a/compat/compiler.h b/compat/compiler.h
> index ce6a7f6de9a..ac90fa051dd 100644
> --- a/compat/compiler.h
> +++ b/compat/compiler.h
> @@ -16,7 +16,8 @@ static inline void get_compiler_info(struct strbuf *info)
>  #endif
> 
>  #ifdef _MSC_VER
> -	strbuf_addf(info, "MSVC version: %s\n", _MSC_FULL_VER);
> +	strbuf_addf(info, "MSVC version: %02d.%02d.%05d\n",
> +		    _MSC_VER / 100, _MSC_VER % 100, _MSC_FULL_VER % 100000);
>  #endif
> 
>  	if (len == info->len)
> -- snap --
> 
> Could you squash that in, please?
> 
> BTW the two issues I reported in the earlier round are still problems.
> Could you squash my fixes, please? For your convenience, you can pluck all
> four of them right off of
> https://github.com/git-for-windows/git/commits/shears/pu

Yes, I think these two issues earlier I have locally and thumbfingered running format-patch.

Show 31 quoted lines
> 
> Just replace the `???` by `!` and you can even use `git rebase
> --autosquash`.
> 
> Ciao,
> Dscho
> 
> 
> > +#endif
> > +
> > +	if (len == info->len)
> > +		strbuf_addf(info, _("no compiler information available\n"));
> > +}
> > +
> > +static inline void get_libc_info(struct strbuf *info)
> > +{
> > +	int len = info->len;
> > +
> > +#ifdef __GLIBC__
> > +	strbuf_addf(info, "glibc: %s\n", gnu_get_libc_version());
> > +#endif
> > +
> > +	if (len == info->len)
> > +		strbuf_addf(info, _("no libc information available\n"));
> > +}
> > +
> > +#endif /* COMPILER_H */
> > --
> > 2.25.0.265.gbab2e86ba0-goog
> >
> >

← back to recent threads