{"thread":{"id":"53075","subject":"[PATCH v10 0/5] add git-bugreport tool","startedAt":"2020-03-23T21:43:51Z","lastAt":"2020-04-07T20:34:26Z","messageCount":32,"participants":["Emily Shaffer","Junio C Hamano","SZEDER Gábor","Danh Doan"],"isPatch":true,"patchVersion":10,"patchTotal":5},"messages":[{"id":"393826","messageId":"20200323214340.182724-1-emilyshaffer@google.com","threadId":"53075","inReplyTo":null,"subject":"[PATCH v10 0/5] add git-bugreport tool","fromName":"Emily Shaffer","fromEmail":"emilyshaffer@google.com","sentAt":"2020-03-23T21:43:35Z","receivedAt":"2020-03-23T21:43:51Z","isPatch":true,"sender":{"key":"nasamuffin@google.com","avatar":"https://avatars.githubusercontent.com/u/1606826?v=4"},"body":"Since v9, a few minor fixes only related to MS and clang compatibility,\nplus a warning about strbuf_addf vs strbuf_addstr. I have made no\nchanges to the build setup for v10, so it's still built as a standalone\nwhich is invoked via the cmd_main helper. There is plenty of time to\nchange the way we build it later if we want, but I generally agree with\nthe sentiment \"let's get something checked in\".\n\nGitGitGadget CI is running at:\nhttps://github.com/gitgitgadget/git/pull/573\n\n - Emily\n\nEmily Shaffer (5):\n  help: move list_config_help to builtin/help\n  bugreport: add tool to generate debugging info\n  bugreport: gather git version and build info\n  bugreport: add uname info\n  bugreport: add compiler info\n\n .gitignore                      |   2 +\n Documentation/git-bugreport.txt |  52 ++++++++++++\n Makefile                        |  18 +++-\n bugreport.c                     | 142 ++++++++++++++++++++++++++++++++\n builtin/help.c                  |  86 +++++++++++++++++++\n command-list.txt                |   1 +\n compat/compiler.h               |  38 +++++++++\n generate-cmdlist.sh             |  19 -----\n generate-configlist.sh          |  21 +++++\n help.c                          | 131 +++++++----------------------\n help.h                          |   2 +-\n strbuf.c                        |   4 +\n strbuf.h                        |   1 +\n t/t0091-bugreport.sh            |  61 ++++++++++++++\n 14 files changed, 452 insertions(+), 126 deletions(-)\n create mode 100644 Documentation/git-bugreport.txt\n create mode 100644 bugreport.c\n create mode 100644 compat/compiler.h\n create mode 100755 generate-configlist.sh\n create mode 100755 t/t0091-bugreport.sh\n\n-- \n2.25.1.696.g5e7596f4ac-goog\n\n"},{"id":"393827","messageId":"20200323214340.182724-2-emilyshaffer@google.com","threadId":"53075","inReplyTo":"20200323214340.182724-1-emilyshaffer@google.com","subject":"[PATCH v10 1/5] help: move list_config_help to builtin/help","fromName":"Emily Shaffer","fromEmail":"emilyshaffer@google.com","sentAt":"2020-03-23T21:43:36Z","receivedAt":"2020-03-23T21:43:54Z","isPatch":true,"sender":{"key":"nasamuffin@google.com","avatar":"https://avatars.githubusercontent.com/u/1606826?v=4"},"body":"Starting in 3ac68a93fd2, help.o began to depend on builtin/branch.o,\nbuiltin/clean.o, and builtin/config.o. This meant that help.o was\nunusable outside of the context of the main Git executable.\n\nTo make help.o usable by other commands again, move list_config_help()\ninto builtin/help.c (where it makes sense to assume other builtin libraries\nare present).\n\nWhen command-list.h is included but a member is not used, we start to\nhear a compiler warning. Since the config list is generated in a fairly\ndifferent way than the command list, and since commands and config\noptions are semantically different, move the config list into its own\nheader and move the generator into its own script and build rule.\n\nSigned-off-by: Emily Shaffer <emilyshaffer@google.com>\n---\n .gitignore             |  1 +\n Makefile               | 13 +++++--\n builtin/help.c         | 86 ++++++++++++++++++++++++++++++++++++++++++\n generate-cmdlist.sh    | 19 ----------\n generate-configlist.sh | 21 +++++++++++\n help.c                 | 85 -----------------------------------------\n help.h                 |  1 -\n 7 files changed, 118 insertions(+), 108 deletions(-)\n create mode 100755 generate-configlist.sh\n\ndiff --git a/.gitignore b/.gitignore\nindex aebe7c0908..ea97de83f3 100644\n--- a/.gitignore\n+++ b/.gitignore\n@@ -189,6 +189,7 @@\n /gitweb/gitweb.cgi\n /gitweb/static/gitweb.js\n /gitweb/static/gitweb.min.*\n+/config-list.h\n /command-list.h\n *.tar.gz\n *.dsc\ndiff --git a/Makefile b/Makefile\nindex 6134104ae6..c552312d3f 100644\n--- a/Makefile\n+++ b/Makefile\n@@ -815,6 +815,7 @@ LIB_FILE = libgit.a\n XDIFF_LIB = xdiff/lib.a\n VCSSVN_LIB = vcs-svn/lib.a\n \n+GENERATED_H += config-list.h\n GENERATED_H += command-list.h\n \n LIB_H := $(sort $(patsubst ./%,%,$(shell git ls-files '*.h' ':!t/' ':!Documentation/' 2>/dev/null || \\\n@@ -2132,7 +2133,7 @@ git$X: git.o GIT-LDFLAGS $(BUILTIN_OBJS) $(GITLIBS)\n \n help.sp help.s help.o: command-list.h\n \n-builtin/help.sp builtin/help.s builtin/help.o: command-list.h GIT-PREFIX\n+builtin/help.sp builtin/help.s builtin/help.o: config-list.h GIT-PREFIX\n builtin/help.sp builtin/help.s builtin/help.o: EXTRA_CPPFLAGS = \\\n \t'-DGIT_HTML_PATH=\"$(htmldir_relative_SQ)\"' \\\n \t'-DGIT_MAN_PATH=\"$(mandir_relative_SQ)\"' \\\n@@ -2152,6 +2153,12 @@ $(BUILT_INS): git$X\n \tln -s $< $@ 2>/dev/null || \\\n \tcp $< $@\n \n+config-list.h: generate-configlist.sh\n+\n+config-list.h:\n+\t$(QUIET_GEN)$(SHELL_PATH) ./generate-configlist.sh \\\n+\t\t>$@+ && mv $@+ $@\n+\n command-list.h: generate-cmdlist.sh command-list.txt\n \n command-list.h: $(wildcard Documentation/git*.txt) Documentation/*config.txt Documentation/config/*.txt\n@@ -2785,7 +2792,7 @@ $(SP_OBJ): %.sp: %.c GIT-CFLAGS FORCE\n .PHONY: sparse $(SP_OBJ)\n sparse: $(SP_OBJ)\n \n-EXCEPT_HDRS := command-list.h unicode-width.h compat/% xdiff/%\n+EXCEPT_HDRS := command-list.h config-list.h unicode-width.h compat/% xdiff/%\n ifndef GCRYPT_SHA256\n \tEXCEPT_HDRS += sha256/gcrypt.h\n endif\n@@ -2807,7 +2814,7 @@ hdr-check: $(HCO)\n style:\n \tgit clang-format --style file --diff --extensions c,h\n \n-check: command-list.h\n+check: config-list.h command-list.h\n \t@if sparse; \\\n \tthen \\\n \t\techo >&2 \"Use 'make sparse' instead\"; \\\ndiff --git a/builtin/help.c b/builtin/help.c\nindex e5590d7787..1c5f2b9255 100644\n--- a/builtin/help.c\n+++ b/builtin/help.c\n@@ -8,6 +8,7 @@\n #include \"parse-options.h\"\n #include \"run-command.h\"\n #include \"column.h\"\n+#include \"config-list.h\"\n #include \"help.h\"\n #include \"alias.h\"\n \n@@ -62,6 +63,91 @@ static const char * const builtin_help_usage[] = {\n \tNULL\n };\n \n+struct slot_expansion {\n+\tconst char *prefix;\n+\tconst char *placeholder;\n+\tvoid (*fn)(struct string_list *list, const char *prefix);\n+\tint found;\n+};\n+\n+static void list_config_help(int for_human)\n+{\n+\tstruct slot_expansion slot_expansions[] = {\n+\t\t{ \"advice\", \"*\", list_config_advices },\n+\t\t{ \"color.branch\", \"<slot>\", list_config_color_branch_slots },\n+\t\t{ \"color.decorate\", \"<slot>\", list_config_color_decorate_slots },\n+\t\t{ \"color.diff\", \"<slot>\", list_config_color_diff_slots },\n+\t\t{ \"color.grep\", \"<slot>\", list_config_color_grep_slots },\n+\t\t{ \"color.interactive\", \"<slot>\", list_config_color_interactive_slots },\n+\t\t{ \"color.remote\", \"<slot>\", list_config_color_sideband_slots },\n+\t\t{ \"color.status\", \"<slot>\", list_config_color_status_slots },\n+\t\t{ \"fsck\", \"<msg-id>\", list_config_fsck_msg_ids },\n+\t\t{ \"receive.fsck\", \"<msg-id>\", list_config_fsck_msg_ids },\n+\t\t{ NULL, NULL, NULL }\n+\t};\n+\tconst char **p;\n+\tstruct slot_expansion *e;\n+\tstruct string_list keys = STRING_LIST_INIT_DUP;\n+\tint i;\n+\n+\tfor (p = config_name_list; *p; p++) {\n+\t\tconst char *var = *p;\n+\t\tstruct strbuf sb = STRBUF_INIT;\n+\n+\t\tfor (e = slot_expansions; e->prefix; e++) {\n+\n+\t\t\tstrbuf_reset(&sb);\n+\t\t\tstrbuf_addf(&sb, \"%s.%s\", e->prefix, e->placeholder);\n+\t\t\tif (!strcasecmp(var, sb.buf)) {\n+\t\t\t\te->fn(&keys, e->prefix);\n+\t\t\t\te->found++;\n+\t\t\t\tbreak;\n+\t\t\t}\n+\t\t}\n+\t\tstrbuf_release(&sb);\n+\t\tif (!e->prefix)\n+\t\t\tstring_list_append(&keys, var);\n+\t}\n+\n+\tfor (e = slot_expansions; e->prefix; e++)\n+\t\tif (!e->found)\n+\t\t\tBUG(\"slot_expansion %s.%s is not used\",\n+\t\t\t    e->prefix, e->placeholder);\n+\n+\tstring_list_sort(&keys);\n+\tfor (i = 0; i < keys.nr; i++) {\n+\t\tconst char *var = keys.items[i].string;\n+\t\tconst char *wildcard, *tag, *cut;\n+\n+\t\tif (for_human) {\n+\t\t\tputs(var);\n+\t\t\tcontinue;\n+\t\t}\n+\n+\t\twildcard = strchr(var, '*');\n+\t\ttag = strchr(var, '<');\n+\n+\t\tif (!wildcard && !tag) {\n+\t\t\tputs(var);\n+\t\t\tcontinue;\n+\t\t}\n+\n+\t\tif (wildcard && !tag)\n+\t\t\tcut = wildcard;\n+\t\telse if (!wildcard && tag)\n+\t\t\tcut = tag;\n+\t\telse\n+\t\t\tcut = wildcard < tag ? wildcard : tag;\n+\n+\t\t/*\n+\t\t * We may produce duplicates, but that's up to\n+\t\t * git-completion.bash to handle\n+\t\t */\n+\t\tprintf(\"%.*s\\n\", (int)(cut - var), var);\n+\t}\n+\tstring_list_clear(&keys, 0);\n+}\n+\n static enum help_format parse_help_format(const char *format)\n {\n \tif (!strcmp(format, \"man\"))\ndiff --git a/generate-cmdlist.sh b/generate-cmdlist.sh\nindex 71158f7d8b..45fecf8bdf 100755\n--- a/generate-cmdlist.sh\n+++ b/generate-cmdlist.sh\n@@ -76,23 +76,6 @@ print_command_list () {\n \techo \"};\"\n }\n \n-print_config_list () {\n-\tcat <<EOF\n-static const char *config_name_list[] = {\n-EOF\n-\tgrep -h '^[a-zA-Z].*\\..*::$' Documentation/*config.txt Documentation/config/*.txt |\n-\tsed '/deprecated/d; s/::$//; s/,  */\\n/g' |\n-\tsort |\n-\twhile read line\n-\tdo\n-\t\techo \"\t\\\"$line\\\",\"\n-\tdone\n-\tcat <<EOF\n-\tNULL,\n-};\n-EOF\n-}\n-\n exclude_programs=\n while test \"--exclude-program\" = \"$1\"\n do\n@@ -113,5 +96,3 @@ echo\n define_category_names \"$1\"\n echo\n print_command_list \"$1\"\n-echo\n-print_config_list\ndiff --git a/generate-configlist.sh b/generate-configlist.sh\nnew file mode 100755\nindex 0000000000..8692fe5cf4\n--- /dev/null\n+++ b/generate-configlist.sh\n@@ -0,0 +1,21 @@\n+#!/bin/sh\n+\n+echo \"/* Automatically generated by generate-configlist.sh */\"\n+echo\n+\n+print_config_list () {\n+\tcat <<EOF\n+static const char *config_name_list[] = {\n+EOF\n+\tgrep -h '^[a-zA-Z].*\\..*::$' Documentation/*config.txt Documentation/config/*.txt |\n+\tsed '/deprecated/d; s/::$//; s/,  */\\n/g' |\n+\tsort |\n+\tsed 's/^.*$/\t\"&\",/'\n+\tcat <<EOF\n+\tNULL,\n+};\n+EOF\n+}\n+\n+echo\n+print_config_list\ndiff --git a/help.c b/help.c\nindex cf67624a94..a21487db77 100644\n--- a/help.c\n+++ b/help.c\n@@ -407,91 +407,6 @@ void list_common_guides_help(void)\n \tputchar('\\n');\n }\n \n-struct slot_expansion {\n-\tconst char *prefix;\n-\tconst char *placeholder;\n-\tvoid (*fn)(struct string_list *list, const char *prefix);\n-\tint found;\n-};\n-\n-void list_config_help(int for_human)\n-{\n-\tstruct slot_expansion slot_expansions[] = {\n-\t\t{ \"advice\", \"*\", list_config_advices },\n-\t\t{ \"color.branch\", \"<slot>\", list_config_color_branch_slots },\n-\t\t{ \"color.decorate\", \"<slot>\", list_config_color_decorate_slots },\n-\t\t{ \"color.diff\", \"<slot>\", list_config_color_diff_slots },\n-\t\t{ \"color.grep\", \"<slot>\", list_config_color_grep_slots },\n-\t\t{ \"color.interactive\", \"<slot>\", list_config_color_interactive_slots },\n-\t\t{ \"color.remote\", \"<slot>\", list_config_color_sideband_slots },\n-\t\t{ \"color.status\", \"<slot>\", list_config_color_status_slots },\n-\t\t{ \"fsck\", \"<msg-id>\", list_config_fsck_msg_ids },\n-\t\t{ \"receive.fsck\", \"<msg-id>\", list_config_fsck_msg_ids },\n-\t\t{ NULL, NULL, NULL }\n-\t};\n-\tconst char **p;\n-\tstruct slot_expansion *e;\n-\tstruct string_list keys = STRING_LIST_INIT_DUP;\n-\tint i;\n-\n-\tfor (p = config_name_list; *p; p++) {\n-\t\tconst char *var = *p;\n-\t\tstruct strbuf sb = STRBUF_INIT;\n-\n-\t\tfor (e = slot_expansions; e->prefix; e++) {\n-\n-\t\t\tstrbuf_reset(&sb);\n-\t\t\tstrbuf_addf(&sb, \"%s.%s\", e->prefix, e->placeholder);\n-\t\t\tif (!strcasecmp(var, sb.buf)) {\n-\t\t\t\te->fn(&keys, e->prefix);\n-\t\t\t\te->found++;\n-\t\t\t\tbreak;\n-\t\t\t}\n-\t\t}\n-\t\tstrbuf_release(&sb);\n-\t\tif (!e->prefix)\n-\t\t\tstring_list_append(&keys, var);\n-\t}\n-\n-\tfor (e = slot_expansions; e->prefix; e++)\n-\t\tif (!e->found)\n-\t\t\tBUG(\"slot_expansion %s.%s is not used\",\n-\t\t\t    e->prefix, e->placeholder);\n-\n-\tstring_list_sort(&keys);\n-\tfor (i = 0; i < keys.nr; i++) {\n-\t\tconst char *var = keys.items[i].string;\n-\t\tconst char *wildcard, *tag, *cut;\n-\n-\t\tif (for_human) {\n-\t\t\tputs(var);\n-\t\t\tcontinue;\n-\t\t}\n-\n-\t\twildcard = strchr(var, '*');\n-\t\ttag = strchr(var, '<');\n-\n-\t\tif (!wildcard && !tag) {\n-\t\t\tputs(var);\n-\t\t\tcontinue;\n-\t\t}\n-\n-\t\tif (wildcard && !tag)\n-\t\t\tcut = wildcard;\n-\t\telse if (!wildcard && tag)\n-\t\t\tcut = tag;\n-\t\telse\n-\t\t\tcut = wildcard < tag ? wildcard : tag;\n-\n-\t\t/*\n-\t\t * We may produce duplicates, but that's up to\n-\t\t * git-completion.bash to handle\n-\t\t */\n-\t\tprintf(\"%.*s\\n\", (int)(cut - var), var);\n-\t}\n-\tstring_list_clear(&keys, 0);\n-}\n-\n static int get_alias(const char *var, const char *value, void *data)\n {\n \tstruct string_list *list = data;\ndiff --git a/help.h b/help.h\nindex 7a455beeb7..9071894e8c 100644\n--- a/help.h\n+++ b/help.h\n@@ -22,7 +22,6 @@ static inline void mput_char(char c, unsigned int num)\n void list_common_cmds_help(void);\n void list_all_cmds_help(void);\n void list_common_guides_help(void);\n-void list_config_help(int for_human);\n \n void list_all_main_cmds(struct string_list *list);\n void list_all_other_cmds(struct string_list *list);\n-- \n2.25.1.696.g5e7596f4ac-goog\n\n"},{"id":"393828","messageId":"20200323214340.182724-3-emilyshaffer@google.com","threadId":"53075","inReplyTo":"20200323214340.182724-1-emilyshaffer@google.com","subject":"[PATCH v10 2/5] bugreport: add tool to generate debugging info","fromName":"Emily Shaffer","fromEmail":"emilyshaffer@google.com","sentAt":"2020-03-23T21:43:37Z","receivedAt":"2020-03-23T21:43:56Z","isPatch":true,"sender":{"key":"nasamuffin@google.com","avatar":"https://avatars.githubusercontent.com/u/1606826?v=4"},"body":"Teach Git how to prompt the user for a good bug report: reproduction\nsteps, expected behavior, and actual behavior. Later, Git can learn how\nto collect some diagnostic information from the repository.\n\nIf users can send us a well-written bug report which contains diagnostic\ninformation we would otherwise need to ask the user for, we can reduce\nthe number of question-and-answer round trips between the reporter and\nthe Git contributor.\n\nUsers may also wish to send a report like this to their local \"Git\nexpert\" if they have put their repository into a state they are confused\nby.\n\nSigned-off-by: Emily Shaffer <emilyshaffer@google.com>\n---\n .gitignore                      |   1 +\n Documentation/git-bugreport.txt |  46 ++++++++++++++\n Makefile                        |   5 ++\n bugreport.c                     | 105 ++++++++++++++++++++++++++++++++\n command-list.txt                |   1 +\n strbuf.c                        |   4 ++\n strbuf.h                        |   1 +\n t/t0091-bugreport.sh            |  61 +++++++++++++++++++\n 8 files changed, 224 insertions(+)\n create mode 100644 Documentation/git-bugreport.txt\n create mode 100644 bugreport.c\n create mode 100755 t/t0091-bugreport.sh\n\ndiff --git a/.gitignore b/.gitignore\nindex ea97de83f3..d89bf9e11e 100644\n--- a/.gitignore\n+++ b/.gitignore\n@@ -25,6 +25,7 @@\n /git-bisect--helper\n /git-blame\n /git-branch\n+/git-bugreport\n /git-bundle\n /git-cat-file\n /git-check-attr\ndiff --git a/Documentation/git-bugreport.txt b/Documentation/git-bugreport.txt\nnew file mode 100644\nindex 0000000000..1f9fde5cde\n--- /dev/null\n+++ b/Documentation/git-bugreport.txt\n@@ -0,0 +1,46 @@\n+git-bugreport(1)\n+================\n+\n+NAME\n+----\n+git-bugreport - Collect information for user to file a bug report\n+\n+SYNOPSIS\n+--------\n+[verse]\n+'git bugreport' [(-o | --output-directory) <path>] [(-s | --suffix) <format>]\n+\n+DESCRIPTION\n+-----------\n+Captures information about the user's machine, Git client, and repository state,\n+as well as a form requesting information about the behavior the user observed,\n+into a single text file which the user can then share, for example to the Git\n+mailing list, in order to report an observed bug.\n+\n+The following information is requested from the user:\n+\n+ - Reproduction steps\n+ - Expected behavior\n+ - Actual behavior\n+\n+This tool is invoked via the typical Git setup process, which means that in some\n+cases, it might not be able to launch - for example, if a relevant config file\n+is unreadable. In this kind of scenario, it may be helpful to manually gather\n+the kind of information listed above when manually asking for help.\n+\n+OPTIONS\n+-------\n+-o <path>::\n+--output-directory <path>::\n+\tPlace the resulting bug report file in `<path>` instead of the root of\n+\tthe Git repository.\n+\n+-s <format>::\n+--suffix <format>::\n+\tSpecify an alternate suffix for the bugreport name, to create a file\n+\tnamed 'git-bugreport-<formatted suffix>'. This should take the form of a\n+\tlink:strftime[3] format string; the current local time will be used.\n+\n+GIT\n+---\n+Part of the linkgit:git[1] suite\ndiff --git a/Makefile b/Makefile\nindex c552312d3f..9e6705061d 100644\n--- a/Makefile\n+++ b/Makefile\n@@ -681,6 +681,7 @@ EXTRA_PROGRAMS =\n # ... and all the rest that could be moved out of bindir to gitexecdir\n PROGRAMS += $(EXTRA_PROGRAMS)\n \n+PROGRAM_OBJS += bugreport.o\n PROGRAM_OBJS += credential-store.o\n PROGRAM_OBJS += daemon.o\n PROGRAM_OBJS += fast-import.o\n@@ -2461,6 +2462,10 @@ endif\n git-%$X: %.o GIT-LDFLAGS $(GITLIBS)\n \t$(QUIET_LINK)$(CC) $(ALL_CFLAGS) -o $@ $(ALL_LDFLAGS) $(filter %.o,$^) $(LIBS)\n \n+git-bugreport$X: bugreport.o GIT-LDFLAGS $(GITLIBS)\n+\t$(QUIET_LINK)$(CC) $(ALL_CFLAGS) -o $@ $(ALL_LDFLAGS) $(filter %.o,$^) \\\n+\t\t$(LIBS)\n+\n git-imap-send$X: imap-send.o $(IMAP_SEND_BUILDDEPS) GIT-LDFLAGS $(GITLIBS)\n \t$(QUIET_LINK)$(CC) $(ALL_CFLAGS) -o $@ $(ALL_LDFLAGS) $(filter %.o,$^) \\\n \t\t$(IMAP_SEND_LDFLAGS) $(LIBS)\ndiff --git a/bugreport.c b/bugreport.c\nnew file mode 100644\nindex 0000000000..f6f53a5e8e\n--- /dev/null\n+++ b/bugreport.c\n@@ -0,0 +1,105 @@\n+#include \"builtin.h\"\n+#include \"parse-options.h\"\n+#include \"stdio.h\"\n+#include \"strbuf.h\"\n+#include \"time.h\"\n+\n+static const char * const bugreport_usage[] = {\n+\tN_(\"git bugreport [-o|--output-directory <file>] [-s|--suffix <format>]\"),\n+\tNULL\n+};\n+\n+static int get_bug_template(struct strbuf *template)\n+{\n+\tconst char template_text[] = N_(\n+\"Thank you for filling out a Git bug report!\\n\"\n+\"Please answer the following questions to help us understand your issue.\\n\"\n+\"\\n\"\n+\"What did you do before the bug happened? (Steps to reproduce your issue)\\n\"\n+\"\\n\"\n+\"What did you expect to happen? (Expected behavior)\\n\"\n+\"\\n\"\n+\"What happened instead? (Actual behavior)\\n\"\n+\"\\n\"\n+\"What's different between what you expected and what actually happened?\\n\"\n+\"\\n\"\n+\"Anything else you want to add:\\n\"\n+\"\\n\"\n+\"Please review the rest of the bug report below.\\n\"\n+\"You can delete any lines you don't wish to share.\\n\");\n+\n+\tstrbuf_addstr(template, _(template_text));\n+\treturn 0;\n+}\n+\n+int cmd_main(int argc, const char **argv)\n+{\n+\tstruct strbuf buffer = STRBUF_INIT;\n+\tstruct strbuf report_path = STRBUF_INIT;\n+\tint report = -1;\n+\ttime_t now = time(NULL);\n+\tchar *option_output = NULL;\n+\tchar *option_suffix = \"%Y-%m-%d-%H%M\";\n+\tint nongit_ok = 0;\n+\tconst char *prefix = NULL;\n+\tconst char *user_relative_path = NULL;\n+\n+\tconst struct option bugreport_options[] = {\n+\t\tOPT_STRING('o', \"output-directory\", &option_output, N_(\"path\"),\n+\t\t\t   N_(\"specify a destination for the bugreport file\")),\n+\t\tOPT_STRING('s', \"suffix\", &option_suffix, N_(\"format\"),\n+\t\t\t   N_(\"specify a strftime format suffix for the filename\")),\n+\t\tOPT_END()\n+\t};\n+\n+\tprefix = setup_git_directory_gently(&nongit_ok);\n+\n+\targc = parse_options(argc, argv, prefix, bugreport_options,\n+\t\t\t     bugreport_usage, 0);\n+\n+\t/* Prepare the path to put the result */\n+\tstrbuf_addstr(&report_path,\n+\t\t      prefix_filename(prefix,\n+\t\t\t\t      option_output ? option_output : \"\"));\n+\tstrbuf_complete(&report_path, '/');\n+\n+\tstrbuf_addstr(&report_path, \"git-bugreport-\");\n+\tstrbuf_addftime(&report_path, option_suffix, localtime(&now), 0, 0);\n+\tstrbuf_addstr(&report_path, \".txt\");\n+\n+\tswitch (safe_create_leading_directories(report_path.buf)) {\n+\tcase SCLD_OK:\n+\tcase SCLD_EXISTS:\n+\t\tbreak;\n+\tdefault:\n+\t\tdie(_(\"could not create leading directories for '%s'\"),\n+\t\t    report_path.buf);\n+\t}\n+\n+\t/* Prepare the report contents */\n+\tget_bug_template(&buffer);\n+\n+\t/* fopen doesn't offer us an O_EXCL alternative, except with glibc. */\n+\treport = open(report_path.buf, O_CREAT | O_EXCL | O_WRONLY, 0666);\n+\n+\tif (report < 0) {\n+\t\tUNLEAK(report_path);\n+\t\tdie(_(\"couldn't create a new file at '%s'\"), report_path.buf);\n+\t}\n+\n+\tstrbuf_write_fd(&buffer, report);\n+\tclose(report);\n+\n+\t/*\n+\t * We want to print the path relative to the user, but we still need the\n+\t * path relative to us to give to the editor.\n+\t */\n+\tif (!(prefix && skip_prefix(report_path.buf, prefix, &user_relative_path)))\n+\t\tuser_relative_path = report_path.buf;\n+\tfprintf(stderr, _(\"Created new report at '%s'.\\n\"),\n+\t\tuser_relative_path);\n+\n+\tUNLEAK(buffer);\n+\tUNLEAK(report_path);\n+\treturn !!launch_editor(report_path.buf, NULL, NULL);\n+}\ndiff --git a/command-list.txt b/command-list.txt\nindex 2087894655..185e5e3f05 100644\n--- a/command-list.txt\n+++ b/command-list.txt\n@@ -54,6 +54,7 @@ git-archive                             mainporcelain\n git-bisect                              mainporcelain           info\n git-blame                               ancillaryinterrogators          complete\n git-branch                              mainporcelain           history\n+git-bugreport                           ancillaryinterrogators\n git-bundle                              mainporcelain\n git-cat-file                            plumbinginterrogators\n git-check-attr                          purehelpers\ndiff --git a/strbuf.c b/strbuf.c\nindex f19da55b07..f1d66c7848 100644\n--- a/strbuf.c\n+++ b/strbuf.c\n@@ -539,6 +539,10 @@ ssize_t strbuf_write(struct strbuf *sb, FILE *f)\n \treturn sb->len ? fwrite(sb->buf, 1, sb->len, f) : 0;\n }\n \n+ssize_t strbuf_write_fd(struct strbuf *sb, int fd)\n+{\n+\treturn sb->len ? write(fd, sb->buf, sb->len) : 0;\n+}\n \n #define STRBUF_MAXLINK (2*PATH_MAX)\n \ndiff --git a/strbuf.h b/strbuf.h\nindex aae7ac3a82..bbf6204de7 100644\n--- a/strbuf.h\n+++ b/strbuf.h\n@@ -462,6 +462,7 @@ int strbuf_readlink(struct strbuf *sb, const char *path, size_t hint);\n  * NUL bytes.\n  */\n ssize_t strbuf_write(struct strbuf *sb, FILE *stream);\n+ssize_t strbuf_write_fd(struct strbuf *sb, int fd);\n \n /**\n  * Read a line from a FILE *, overwriting the existing contents of\ndiff --git a/t/t0091-bugreport.sh b/t/t0091-bugreport.sh\nnew file mode 100755\nindex 0000000000..65f664fdac\n--- /dev/null\n+++ b/t/t0091-bugreport.sh\n@@ -0,0 +1,61 @@\n+#!/bin/sh\n+\n+test_description='git bugreport'\n+\n+. ./test-lib.sh\n+\n+# Headers \"[System Info]\" will be followed by a non-empty line if we put some\n+# information there; we can make sure all our headers were followed by some\n+# information to check if the command was successful.\n+HEADER_PATTERN=\"^\\[.*\\]$\"\n+\n+check_all_headers_populated () {\n+\twhile read -r line\n+\tdo\n+\t\tif test \"$(grep \"$HEADER_PATTERN\" \"$line\")\"\n+\t\tthen\n+\t\t\techo \"$line\"\n+\t\t\tread -r nextline\n+\t\t\tif test -z \"$nextline\"; then\n+\t\t\t\treturn 1;\n+\t\t\tfi\n+\t\tfi\n+\tdone\n+}\n+\n+test_expect_success 'creates a report with content in the right places' '\n+\tgit bugreport -s check-headers &&\n+\tcheck_all_headers_populated <git-bugreport-check-headers.txt &&\n+\ttest_when_finished rm git-bugreport-check-headers.txt\n+'\n+\n+test_expect_success 'dies if file with same name as report already exists' '\n+\t>>git-bugreport-duplicate.txt &&\n+\ttest_must_fail git bugreport --suffix duplicate &&\n+\ttest_when_finished rm git-bugreport-duplicate.txt\n+'\n+\n+test_expect_success '--output-directory puts the report in the provided dir' '\n+\tgit bugreport -o foo/ &&\n+\ttest_path_is_file foo/git-bugreport-* &&\n+\ttest_when_finished rm -fr foo/\n+'\n+\n+test_expect_success 'incorrect arguments abort with usage' '\n+\ttest_must_fail git bugreport --false 2>output &&\n+\ttest_i18ngrep usage output &&\n+\ttest_path_is_missing git-bugreport-*\n+'\n+\n+test_expect_success 'runs outside of a git dir' '\n+\tnongit git bugreport &&\n+\ttest_when_finished rm non-repo/git-bugreport-*\n+'\n+\n+test_expect_success 'can create leading directories outside of a git dir' '\n+\tnongit git bugreport -o foo/bar/baz &&\n+\ttest_when_finished rm -fr foo/bar/baz\n+'\n+\n+\n+test_done\n-- \n2.25.1.696.g5e7596f4ac-goog\n\n"},{"id":"393829","messageId":"20200323214340.182724-4-emilyshaffer@google.com","threadId":"53075","inReplyTo":"20200323214340.182724-1-emilyshaffer@google.com","subject":"[PATCH v10 3/5] bugreport: gather git version and build info","fromName":"Emily Shaffer","fromEmail":"emilyshaffer@google.com","sentAt":"2020-03-23T21:43:38Z","receivedAt":"2020-03-23T21:43:59Z","isPatch":true,"sender":{"key":"nasamuffin@google.com","avatar":"https://avatars.githubusercontent.com/u/1606826?v=4"},"body":"Knowing which version of Git a user has and how it was built allows us\nto more precisely pin down the circumstances when a certain issue\noccurs, so teach bugreport how to tell us the same output as 'git\nversion --build-options'.\n\nIt's not ideal to directly call 'git version --build-options' because\nthat output goes to stdout. Instead, wrap the version string in a helper\nwithin help.[ch] library, and call that helper from within the bugreport\nlibrary.\n\nSigned-off-by: Emily Shaffer <emilyshaffer@google.com>\n---\n Documentation/git-bugreport.txt |  4 +++\n bugreport.c                     | 19 +++++++++++++-\n help.c                          | 46 ++++++++++++++++++++-------------\n help.h                          |  1 +\n 4 files changed, 51 insertions(+), 19 deletions(-)\n\ndiff --git a/Documentation/git-bugreport.txt b/Documentation/git-bugreport.txt\nindex 1f9fde5cde..f44ae8cbe7 100644\n--- a/Documentation/git-bugreport.txt\n+++ b/Documentation/git-bugreport.txt\n@@ -23,6 +23,10 @@ The following information is requested from the user:\n  - Expected behavior\n  - Actual behavior\n \n+The following information is captured automatically:\n+\n+ - 'git version --build-options'\n+\n This tool is invoked via the typical Git setup process, which means that in some\n cases, it might not be able to launch - for example, if a relevant config file\n is unreadable. In this kind of scenario, it may be helpful to manually gather\ndiff --git a/bugreport.c b/bugreport.c\nindex f6f53a5e8e..4cdb58bbaa 100644\n--- a/bugreport.c\n+++ b/bugreport.c\n@@ -1,8 +1,17 @@\n-#include \"builtin.h\"\n+#include \"cache.h\"\n #include \"parse-options.h\"\n #include \"stdio.h\"\n #include \"strbuf.h\"\n #include \"time.h\"\n+#include \"help.h\"\n+\n+static void get_system_info(struct strbuf *sys_info)\n+{\n+\t/* get git version from native cmd */\n+\tstrbuf_addstr(sys_info, _(\"git version:\\n\"));\n+\tget_version_info(sys_info, 1);\n+\tstrbuf_complete_line(sys_info);\n+}\n \n static const char * const bugreport_usage[] = {\n \tN_(\"git bugreport [-o|--output-directory <file>] [-s|--suffix <format>]\"),\n@@ -32,6 +41,11 @@ static int get_bug_template(struct strbuf *template)\n \treturn 0;\n }\n \n+static void get_header(struct strbuf *buf, const char *title)\n+{\n+\tstrbuf_addf(buf, \"\\n\\n[%s]\\n\", title);\n+}\n+\n int cmd_main(int argc, const char **argv)\n {\n \tstruct strbuf buffer = STRBUF_INIT;\n@@ -79,6 +93,9 @@ int cmd_main(int argc, const char **argv)\n \t/* Prepare the report contents */\n \tget_bug_template(&buffer);\n \n+\tget_header(&buffer, _(\"System Info\"));\n+\tget_system_info(&buffer);\n+\n \t/* fopen doesn't offer us an O_EXCL alternative, except with glibc. */\n \treport = open(report_path.buf, O_CREAT | O_EXCL | O_WRONLY, 0666);\n \ndiff --git a/help.c b/help.c\nindex a21487db77..1de9c0d589 100644\n--- a/help.c\n+++ b/help.c\n@@ -622,8 +622,32 @@ const char *help_unknown_cmd(const char *cmd)\n \texit(1);\n }\n \n+void get_version_info(struct strbuf *buf, int show_build_options)\n+{\n+\t/*\n+\t * The format of this string should be kept stable for compatibility\n+\t * with external projects that rely on the output of \"git version\".\n+\t *\n+\t * Always show the version, even if other options are given.\n+\t */\n+\tstrbuf_addf(buf, \"git version %s\\n\", git_version_string);\n+\n+\tif (show_build_options) {\n+\t\tstrbuf_addf(buf, \"cpu: %s\\n\", GIT_HOST_CPU);\n+\t\tif (git_built_from_commit_string[0])\n+\t\t\tstrbuf_addf(buf, \"built from commit: %s\\n\",\n+\t\t\t       git_built_from_commit_string);\n+\t\telse\n+\t\t\tstrbuf_addstr(buf, \"no commit associated with this build\\n\");\n+\t\tstrbuf_addf(buf, \"sizeof-long: %d\\n\", (int)sizeof(long));\n+\t\tstrbuf_addf(buf, \"sizeof-size_t: %d\\n\", (int)sizeof(size_t));\n+\t\t/* NEEDSWORK: also save and output GIT-BUILD_OPTIONS? */\n+\t}\n+}\n+\n int cmd_version(int argc, const char **argv, const char *prefix)\n {\n+\tstruct strbuf buf = STRBUF_INIT;\n \tint build_options = 0;\n \tconst char * const usage[] = {\n \t\tN_(\"git version [<options>]\"),\n@@ -637,25 +661,11 @@ int cmd_version(int argc, const char **argv, const char *prefix)\n \n \targc = parse_options(argc, argv, prefix, options, usage, 0);\n \n-\t/*\n-\t * The format of this string should be kept stable for compatibility\n-\t * with external projects that rely on the output of \"git version\".\n-\t *\n-\t * Always show the version, even if other options are given.\n-\t */\n-\tprintf(\"git version %s\\n\", git_version_string);\n+\tget_version_info(&buf, build_options);\n+\tprintf(\"%s\", buf.buf);\n+\n+\tstrbuf_release(&buf);\n \n-\tif (build_options) {\n-\t\tprintf(\"cpu: %s\\n\", GIT_HOST_CPU);\n-\t\tif (git_built_from_commit_string[0])\n-\t\t\tprintf(\"built from commit: %s\\n\",\n-\t\t\t       git_built_from_commit_string);\n-\t\telse\n-\t\t\tprintf(\"no commit associated with this build\\n\");\n-\t\tprintf(\"sizeof-long: %d\\n\", (int)sizeof(long));\n-\t\tprintf(\"sizeof-size_t: %d\\n\", (int)sizeof(size_t));\n-\t\t/* NEEDSWORK: also save and output GIT-BUILD_OPTIONS? */\n-\t}\n \treturn 0;\n }\n \ndiff --git a/help.h b/help.h\nindex 9071894e8c..500521b908 100644\n--- a/help.h\n+++ b/help.h\n@@ -37,6 +37,7 @@ void add_cmdname(struct cmdnames *cmds, const char *name, int len);\n void exclude_cmds(struct cmdnames *cmds, struct cmdnames *excludes);\n int is_in_cmdlist(struct cmdnames *cmds, const char *name);\n void list_commands(unsigned int colopts, struct cmdnames *main_cmds, struct cmdnames *other_cmds);\n+void get_version_info(struct strbuf *buf, int show_build_options);\n \n /*\n  * call this to die(), when it is suspected that the user mistyped a\n-- \n2.25.1.696.g5e7596f4ac-goog\n\n"},{"id":"393830","messageId":"20200323214340.182724-5-emilyshaffer@google.com","threadId":"53075","inReplyTo":"20200323214340.182724-1-emilyshaffer@google.com","subject":"[PATCH v10 4/5] bugreport: add uname info","fromName":"Emily Shaffer","fromEmail":"emilyshaffer@google.com","sentAt":"2020-03-23T21:43:39Z","receivedAt":"2020-03-23T21:44:00Z","isPatch":true,"sender":{"key":"nasamuffin@google.com","avatar":"https://avatars.githubusercontent.com/u/1606826?v=4"},"body":"The contents of uname() can give us some insight into what sort of\nsystem the user is running on, and help us replicate their setup if need\nbe. The domainname field is not guaranteed to be available, so don't\ncollect it.\n\nSigned-off-by: Emily Shaffer <emilyshaffer@google.com>\n---\n Documentation/git-bugreport.txt |  1 +\n bugreport.c                     | 16 +++++++++++++++-\n 2 files changed, 16 insertions(+), 1 deletion(-)\n\ndiff --git a/Documentation/git-bugreport.txt b/Documentation/git-bugreport.txt\nindex f44ae8cbe7..17b0d14e8d 100644\n--- a/Documentation/git-bugreport.txt\n+++ b/Documentation/git-bugreport.txt\n@@ -26,6 +26,7 @@ The following information is requested from the user:\n The following information is captured automatically:\n \n  - 'git version --build-options'\n+ - uname sysname, release, version, and machine strings\n \n This tool is invoked via the typical Git setup process, which means that in some\n cases, it might not be able to launch - for example, if a relevant config file\ndiff --git a/bugreport.c b/bugreport.c\nindex 4cdb58bbaa..1a3172bcec 100644\n--- a/bugreport.c\n+++ b/bugreport.c\n@@ -7,10 +7,24 @@\n \n static void get_system_info(struct strbuf *sys_info)\n {\n+\tstruct utsname uname_info;\n+\n \t/* get git version from native cmd */\n \tstrbuf_addstr(sys_info, _(\"git version:\\n\"));\n \tget_version_info(sys_info, 1);\n-\tstrbuf_complete_line(sys_info);\n+\n+\t/* system call for other version info */\n+\tstrbuf_addstr(sys_info, \"uname: \");\n+\tif (uname(&uname_info))\n+\t\tstrbuf_addf(sys_info, _(\"uname() failed with error '%s' (%d)\\n\"),\n+\t\t\t    strerror(errno),\n+\t\t\t    errno);\n+\telse\n+\t\tstrbuf_addf(sys_info, \"%s %s %s %s\\n\",\n+\t\t\t    uname_info.sysname,\n+\t\t\t    uname_info.release,\n+\t\t\t    uname_info.version,\n+\t\t\t    uname_info.machine);\n }\n \n static const char * const bugreport_usage[] = {\n-- \n2.25.1.696.g5e7596f4ac-goog\n\n"},{"id":"393831","messageId":"20200323214340.182724-6-emilyshaffer@google.com","threadId":"53075","inReplyTo":"20200323214340.182724-1-emilyshaffer@google.com","subject":"[PATCH v10 5/5] bugreport: add compiler info","fromName":"Emily Shaffer","fromEmail":"emilyshaffer@google.com","sentAt":"2020-03-23T21:43:40Z","receivedAt":"2020-03-23T21:44:03Z","isPatch":true,"sender":{"key":"nasamuffin@google.com","avatar":"https://avatars.githubusercontent.com/u/1606826?v=4"},"body":"To help pinpoint the source of a regression, it is useful to know some\ninfo about the compiler which the user's Git client was built with. By\nadding a generic get_compiler_info() in 'compat/' we can choose which\nrelevant information to share per compiler; to get started, let's\ndemonstrate the version of glibc if the user built with 'gcc'.\n\nSigned-off-by: Emily Shaffer <emilyshaffer@google.com>\n---\n Documentation/git-bugreport.txt |  1 +\n bugreport.c                     |  6 ++++++\n compat/compiler.h               | 38 +++++++++++++++++++++++++++++++++\n 3 files changed, 45 insertions(+)\n create mode 100644 compat/compiler.h\n\ndiff --git a/Documentation/git-bugreport.txt b/Documentation/git-bugreport.txt\nindex 17b0d14e8d..643d1b2884 100644\n--- a/Documentation/git-bugreport.txt\n+++ b/Documentation/git-bugreport.txt\n@@ -27,6 +27,7 @@ The following information is captured automatically:\n \n  - 'git version --build-options'\n  - uname sysname, release, version, and machine strings\n+ - Compiler-specific info string\n \n This tool is invoked via the typical Git setup process, which means that in some\n cases, it might not be able to launch - for example, if a relevant config file\ndiff --git a/bugreport.c b/bugreport.c\nindex 1a3172bcec..089b939a87 100644\n--- a/bugreport.c\n+++ b/bugreport.c\n@@ -4,6 +4,7 @@\n #include \"strbuf.h\"\n #include \"time.h\"\n #include \"help.h\"\n+#include \"compat/compiler.h\"\n \n static void get_system_info(struct strbuf *sys_info)\n {\n@@ -25,6 +26,11 @@ static void get_system_info(struct strbuf *sys_info)\n \t\t\t    uname_info.release,\n \t\t\t    uname_info.version,\n \t\t\t    uname_info.machine);\n+\n+\tstrbuf_addstr(sys_info, _(\"compiler info: \"));\n+\tget_compiler_info(sys_info);\n+\tstrbuf_addstr(sys_info, _(\"libc info: \"));\n+\tget_libc_info(sys_info);\n }\n \n static const char * const bugreport_usage[] = {\ndiff --git a/compat/compiler.h b/compat/compiler.h\nnew file mode 100644\nindex 0000000000..ce6a7f6de9\n--- /dev/null\n+++ b/compat/compiler.h\n@@ -0,0 +1,38 @@\n+#ifndef COMPILER_H\n+#define COMPILER_H\n+\n+#include \"git-compat-util.h\"\n+#include \"strbuf.h\"\n+\n+#ifdef __GLIBC__\n+#include <gnu/libc-version.h>\n+#endif\n+\n+static inline void get_compiler_info(struct strbuf *info)\n+{\n+\tint len = info->len;\n+#ifdef __GNUC__\n+\tstrbuf_addf(info, \"gnuc: %d.%d\\n\", __GNUC__, __GNUC_MINOR__);\n+#endif\n+\n+#ifdef _MSC_VER\n+\tstrbuf_addf(info, \"MSVC version: %s\\n\", _MSC_FULL_VER);\n+#endif\n+\n+\tif (len == info->len)\n+\t\tstrbuf_addstr(info, _(\"no compiler information available\\n\"));\n+}\n+\n+static inline void get_libc_info(struct strbuf *info)\n+{\n+\tint len = info->len;\n+\n+#ifdef __GLIBC__\n+\tstrbuf_addf(info, \"glibc: %s\\n\", gnu_get_libc_version());\n+#endif\n+\n+\tif (len == info->len)\n+\t\tstrbuf_addstr(info, _(\"no libc information available\\n\"));\n+}\n+\n+#endif /* COMPILER_H */\n-- \n2.25.1.696.g5e7596f4ac-goog\n\n"},{"id":"393836","messageId":"xmqqlfnq3bwc.fsf@gitster.c.googlers.com","threadId":"53075","inReplyTo":"20200323214340.182724-6-emilyshaffer@google.com","subject":"Re: [PATCH v10 5/5] bugreport: add compiler info","fromName":"Junio C Hamano","fromEmail":"gitster@pobox.com","sentAt":"2020-03-23T23:10:59Z","receivedAt":"2020-03-23T23:11:03Z","isPatch":true,"sender":{"key":"gitster@pobox.com","avatar":"https://avatars.githubusercontent.com/u/54884?v=4"},"body":"Emily Shaffer <emilyshaffer@google.com> writes:\n\n> +#ifdef _MSC_VER\n> +\tstrbuf_addf(info, \"MSVC version: %s\\n\", _MSC_FULL_VER);\n> +#endif\n\nThis part is a bit different from what Dscho suggested to be\nsquashed (and I have had on top of v9 series).\n\nBelow is a diff between (v9 + SQUASH???) and v10.  I think the\nchange in the strftime format is a strict improvement.\n\nThanks.\n\n bugreport.c       | 2 +-\n compat/compiler.h | 3 +--\n 2 files changed, 2 insertions(+), 3 deletions(-)\n\ndiff --git a/bugreport.c b/bugreport.c\nindex 5073c901cd..089b939a87 100644\n--- a/bugreport.c\n+++ b/bugreport.c\n@@ -73,7 +73,7 @@ int cmd_main(int argc, const char **argv)\n \tint report = -1;\n \ttime_t now = time(NULL);\n \tchar *option_output = NULL;\n-\tchar *option_suffix = \"%F-%H%M\";\n+\tchar *option_suffix = \"%Y-%m-%d-%H%M\";\n \tint nongit_ok = 0;\n \tconst char *prefix = NULL;\n \tconst char *user_relative_path = NULL;\ndiff --git a/compat/compiler.h b/compat/compiler.h\nindex ac90fa051d..ce6a7f6de9 100644\n--- a/compat/compiler.h\n+++ b/compat/compiler.h\n@@ -16,8 +16,7 @@ static inline void get_compiler_info(struct strbuf *info)\n #endif\n \n #ifdef _MSC_VER\n-\tstrbuf_addf(info, \"MSVC version: %02d.%02d.%05d\\n\",\n-\t\t    _MSC_VER / 100, _MSC_VER % 100, _MSC_FULL_VER % 100000);\n+\tstrbuf_addf(info, \"MSVC version: %s\\n\", _MSC_FULL_VER);\n #endif\n \n \tif (len == info->len)\n"},{"id":"394016","messageId":"20200325211024.GC53368@google.com","threadId":"53075","inReplyTo":"xmqqlfnq3bwc.fsf@gitster.c.googlers.com","subject":"Re: [PATCH v10 5/5] bugreport: add compiler info","fromName":"Emily Shaffer","fromEmail":"emilyshaffer@google.com","sentAt":"2020-03-25T21:10:24Z","receivedAt":"2020-03-25T21:10:34Z","isPatch":true,"sender":{"key":"nasamuffin@google.com","avatar":"https://avatars.githubusercontent.com/u/1606826?v=4"},"body":"On Mon, Mar 23, 2020 at 04:10:59PM -0700, Junio C Hamano wrote:\n> Emily Shaffer <emilyshaffer@google.com> writes:\n> \n> > +#ifdef _MSC_VER\n> > +\tstrbuf_addf(info, \"MSVC version: %s\\n\", _MSC_FULL_VER);\n> > +#endif\n> \n> This part is a bit different from what Dscho suggested to be\n> squashed (and I have had on top of v9 series).\n> \n> Below is a diff between (v9 + SQUASH???) and v10.  I think the\n> change in the strftime format is a strict improvement.\n\nHmph. This is different than what I have in local. Please ignore this\nentire v10, I've made a mistake in my tooling. I'm sorry about the\nnoise and for not checking over my patches better before mailing.\n\n - Emily\n"},{"id":"394020","messageId":"20200325212500.135046-1-emilyshaffer@google.com","threadId":"53075","inReplyTo":"20200323214340.182724-1-emilyshaffer@google.com","subject":"[PATCH v11 0/5] add git-bugreport tool","fromName":"Emily Shaffer","fromEmail":"emilyshaffer@google.com","sentAt":"2020-03-25T21:24:55Z","receivedAt":"2020-03-25T21:25:15Z","isPatch":true,"sender":{"key":"nasamuffin@google.com","avatar":"https://avatars.githubusercontent.com/u/1606826?v=4"},"body":"Please ignore v10; it seemed that I had a ref .git/bugreport as well as\na ref .git/refs/heads/bugreport and the former was pointing somewhere\nstale, so v10 was identical at least to v9 if not also to v8. :|\n\nThis hopefully really does include the MSVC changes as well as the clang\nchanges and addstr noise fixes. I'm really sorry for the noise.\n\n - Emily\n\nEmily Shaffer (5):\n  help: move list_config_help to builtin/help\n  bugreport: add tool to generate debugging info\n  bugreport: gather git version and build info\n  bugreport: add uname info\n  bugreport: add compiler info\n\n .gitignore                      |   2 +\n Documentation/git-bugreport.txt |  52 ++++++++++++\n Makefile                        |  18 +++-\n bugreport.c                     | 142 ++++++++++++++++++++++++++++++++\n builtin/help.c                  |  86 +++++++++++++++++++\n command-list.txt                |   1 +\n compat/compiler.h               |  41 +++++++++\n generate-cmdlist.sh             |  19 -----\n generate-configlist.sh          |  21 +++++\n help.c                          | 131 +++++++----------------------\n help.h                          |   2 +-\n strbuf.c                        |   4 +\n strbuf.h                        |   1 +\n t/t0091-bugreport.sh            |  61 ++++++++++++++\n 14 files changed, 455 insertions(+), 126 deletions(-)\n create mode 100644 Documentation/git-bugreport.txt\n create mode 100644 bugreport.c\n create mode 100644 compat/compiler.h\n create mode 100755 generate-configlist.sh\n create mode 100755 t/t0091-bugreport.sh\n\n-- \n2.25.1.696.g5e7596f4ac-goog\n\n"},{"id":"394021","messageId":"20200325212500.135046-2-emilyshaffer@google.com","threadId":"53075","inReplyTo":"20200325212500.135046-1-emilyshaffer@google.com","subject":"[PATCH v11 1/5] help: move list_config_help to builtin/help","fromName":"Emily Shaffer","fromEmail":"emilyshaffer@google.com","sentAt":"2020-03-25T21:24:56Z","receivedAt":"2020-03-25T21:25:19Z","isPatch":true,"sender":{"key":"nasamuffin@google.com","avatar":"https://avatars.githubusercontent.com/u/1606826?v=4"},"body":"Starting in 3ac68a93fd2, help.o began to depend on builtin/branch.o,\nbuiltin/clean.o, and builtin/config.o. This meant that help.o was\nunusable outside of the context of the main Git executable.\n\nTo make help.o usable by other commands again, move list_config_help()\ninto builtin/help.c (where it makes sense to assume other builtin libraries\nare present).\n\nWhen command-list.h is included but a member is not used, we start to\nhear a compiler warning. Since the config list is generated in a fairly\ndifferent way than the command list, and since commands and config\noptions are semantically different, move the config list into its own\nheader and move the generator into its own script and build rule.\n\nSigned-off-by: Emily Shaffer <emilyshaffer@google.com>\n---\n .gitignore             |  1 +\n Makefile               | 13 +++++--\n builtin/help.c         | 86 ++++++++++++++++++++++++++++++++++++++++++\n generate-cmdlist.sh    | 19 ----------\n generate-configlist.sh | 21 +++++++++++\n help.c                 | 85 -----------------------------------------\n help.h                 |  1 -\n 7 files changed, 118 insertions(+), 108 deletions(-)\n create mode 100755 generate-configlist.sh\n\ndiff --git a/.gitignore b/.gitignore\nindex aebe7c0908..ea97de83f3 100644\n--- a/.gitignore\n+++ b/.gitignore\n@@ -189,6 +189,7 @@\n /gitweb/gitweb.cgi\n /gitweb/static/gitweb.js\n /gitweb/static/gitweb.min.*\n+/config-list.h\n /command-list.h\n *.tar.gz\n *.dsc\ndiff --git a/Makefile b/Makefile\nindex 6134104ae6..c552312d3f 100644\n--- a/Makefile\n+++ b/Makefile\n@@ -815,6 +815,7 @@ LIB_FILE = libgit.a\n XDIFF_LIB = xdiff/lib.a\n VCSSVN_LIB = vcs-svn/lib.a\n \n+GENERATED_H += config-list.h\n GENERATED_H += command-list.h\n \n LIB_H := $(sort $(patsubst ./%,%,$(shell git ls-files '*.h' ':!t/' ':!Documentation/' 2>/dev/null || \\\n@@ -2132,7 +2133,7 @@ git$X: git.o GIT-LDFLAGS $(BUILTIN_OBJS) $(GITLIBS)\n \n help.sp help.s help.o: command-list.h\n \n-builtin/help.sp builtin/help.s builtin/help.o: command-list.h GIT-PREFIX\n+builtin/help.sp builtin/help.s builtin/help.o: config-list.h GIT-PREFIX\n builtin/help.sp builtin/help.s builtin/help.o: EXTRA_CPPFLAGS = \\\n \t'-DGIT_HTML_PATH=\"$(htmldir_relative_SQ)\"' \\\n \t'-DGIT_MAN_PATH=\"$(mandir_relative_SQ)\"' \\\n@@ -2152,6 +2153,12 @@ $(BUILT_INS): git$X\n \tln -s $< $@ 2>/dev/null || \\\n \tcp $< $@\n \n+config-list.h: generate-configlist.sh\n+\n+config-list.h:\n+\t$(QUIET_GEN)$(SHELL_PATH) ./generate-configlist.sh \\\n+\t\t>$@+ && mv $@+ $@\n+\n command-list.h: generate-cmdlist.sh command-list.txt\n \n command-list.h: $(wildcard Documentation/git*.txt) Documentation/*config.txt Documentation/config/*.txt\n@@ -2785,7 +2792,7 @@ $(SP_OBJ): %.sp: %.c GIT-CFLAGS FORCE\n .PHONY: sparse $(SP_OBJ)\n sparse: $(SP_OBJ)\n \n-EXCEPT_HDRS := command-list.h unicode-width.h compat/% xdiff/%\n+EXCEPT_HDRS := command-list.h config-list.h unicode-width.h compat/% xdiff/%\n ifndef GCRYPT_SHA256\n \tEXCEPT_HDRS += sha256/gcrypt.h\n endif\n@@ -2807,7 +2814,7 @@ hdr-check: $(HCO)\n style:\n \tgit clang-format --style file --diff --extensions c,h\n \n-check: command-list.h\n+check: config-list.h command-list.h\n \t@if sparse; \\\n \tthen \\\n \t\techo >&2 \"Use 'make sparse' instead\"; \\\ndiff --git a/builtin/help.c b/builtin/help.c\nindex e5590d7787..1c5f2b9255 100644\n--- a/builtin/help.c\n+++ b/builtin/help.c\n@@ -8,6 +8,7 @@\n #include \"parse-options.h\"\n #include \"run-command.h\"\n #include \"column.h\"\n+#include \"config-list.h\"\n #include \"help.h\"\n #include \"alias.h\"\n \n@@ -62,6 +63,91 @@ static const char * const builtin_help_usage[] = {\n \tNULL\n };\n \n+struct slot_expansion {\n+\tconst char *prefix;\n+\tconst char *placeholder;\n+\tvoid (*fn)(struct string_list *list, const char *prefix);\n+\tint found;\n+};\n+\n+static void list_config_help(int for_human)\n+{\n+\tstruct slot_expansion slot_expansions[] = {\n+\t\t{ \"advice\", \"*\", list_config_advices },\n+\t\t{ \"color.branch\", \"<slot>\", list_config_color_branch_slots },\n+\t\t{ \"color.decorate\", \"<slot>\", list_config_color_decorate_slots },\n+\t\t{ \"color.diff\", \"<slot>\", list_config_color_diff_slots },\n+\t\t{ \"color.grep\", \"<slot>\", list_config_color_grep_slots },\n+\t\t{ \"color.interactive\", \"<slot>\", list_config_color_interactive_slots },\n+\t\t{ \"color.remote\", \"<slot>\", list_config_color_sideband_slots },\n+\t\t{ \"color.status\", \"<slot>\", list_config_color_status_slots },\n+\t\t{ \"fsck\", \"<msg-id>\", list_config_fsck_msg_ids },\n+\t\t{ \"receive.fsck\", \"<msg-id>\", list_config_fsck_msg_ids },\n+\t\t{ NULL, NULL, NULL }\n+\t};\n+\tconst char **p;\n+\tstruct slot_expansion *e;\n+\tstruct string_list keys = STRING_LIST_INIT_DUP;\n+\tint i;\n+\n+\tfor (p = config_name_list; *p; p++) {\n+\t\tconst char *var = *p;\n+\t\tstruct strbuf sb = STRBUF_INIT;\n+\n+\t\tfor (e = slot_expansions; e->prefix; e++) {\n+\n+\t\t\tstrbuf_reset(&sb);\n+\t\t\tstrbuf_addf(&sb, \"%s.%s\", e->prefix, e->placeholder);\n+\t\t\tif (!strcasecmp(var, sb.buf)) {\n+\t\t\t\te->fn(&keys, e->prefix);\n+\t\t\t\te->found++;\n+\t\t\t\tbreak;\n+\t\t\t}\n+\t\t}\n+\t\tstrbuf_release(&sb);\n+\t\tif (!e->prefix)\n+\t\t\tstring_list_append(&keys, var);\n+\t}\n+\n+\tfor (e = slot_expansions; e->prefix; e++)\n+\t\tif (!e->found)\n+\t\t\tBUG(\"slot_expansion %s.%s is not used\",\n+\t\t\t    e->prefix, e->placeholder);\n+\n+\tstring_list_sort(&keys);\n+\tfor (i = 0; i < keys.nr; i++) {\n+\t\tconst char *var = keys.items[i].string;\n+\t\tconst char *wildcard, *tag, *cut;\n+\n+\t\tif (for_human) {\n+\t\t\tputs(var);\n+\t\t\tcontinue;\n+\t\t}\n+\n+\t\twildcard = strchr(var, '*');\n+\t\ttag = strchr(var, '<');\n+\n+\t\tif (!wildcard && !tag) {\n+\t\t\tputs(var);\n+\t\t\tcontinue;\n+\t\t}\n+\n+\t\tif (wildcard && !tag)\n+\t\t\tcut = wildcard;\n+\t\telse if (!wildcard && tag)\n+\t\t\tcut = tag;\n+\t\telse\n+\t\t\tcut = wildcard < tag ? wildcard : tag;\n+\n+\t\t/*\n+\t\t * We may produce duplicates, but that's up to\n+\t\t * git-completion.bash to handle\n+\t\t */\n+\t\tprintf(\"%.*s\\n\", (int)(cut - var), var);\n+\t}\n+\tstring_list_clear(&keys, 0);\n+}\n+\n static enum help_format parse_help_format(const char *format)\n {\n \tif (!strcmp(format, \"man\"))\ndiff --git a/generate-cmdlist.sh b/generate-cmdlist.sh\nindex 71158f7d8b..45fecf8bdf 100755\n--- a/generate-cmdlist.sh\n+++ b/generate-cmdlist.sh\n@@ -76,23 +76,6 @@ print_command_list () {\n \techo \"};\"\n }\n \n-print_config_list () {\n-\tcat <<EOF\n-static const char *config_name_list[] = {\n-EOF\n-\tgrep -h '^[a-zA-Z].*\\..*::$' Documentation/*config.txt Documentation/config/*.txt |\n-\tsed '/deprecated/d; s/::$//; s/,  */\\n/g' |\n-\tsort |\n-\twhile read line\n-\tdo\n-\t\techo \"\t\\\"$line\\\",\"\n-\tdone\n-\tcat <<EOF\n-\tNULL,\n-};\n-EOF\n-}\n-\n exclude_programs=\n while test \"--exclude-program\" = \"$1\"\n do\n@@ -113,5 +96,3 @@ echo\n define_category_names \"$1\"\n echo\n print_command_list \"$1\"\n-echo\n-print_config_list\ndiff --git a/generate-configlist.sh b/generate-configlist.sh\nnew file mode 100755\nindex 0000000000..8692fe5cf4\n--- /dev/null\n+++ b/generate-configlist.sh\n@@ -0,0 +1,21 @@\n+#!/bin/sh\n+\n+echo \"/* Automatically generated by generate-configlist.sh */\"\n+echo\n+\n+print_config_list () {\n+\tcat <<EOF\n+static const char *config_name_list[] = {\n+EOF\n+\tgrep -h '^[a-zA-Z].*\\..*::$' Documentation/*config.txt Documentation/config/*.txt |\n+\tsed '/deprecated/d; s/::$//; s/,  */\\n/g' |\n+\tsort |\n+\tsed 's/^.*$/\t\"&\",/'\n+\tcat <<EOF\n+\tNULL,\n+};\n+EOF\n+}\n+\n+echo\n+print_config_list\ndiff --git a/help.c b/help.c\nindex cf67624a94..a21487db77 100644\n--- a/help.c\n+++ b/help.c\n@@ -407,91 +407,6 @@ void list_common_guides_help(void)\n \tputchar('\\n');\n }\n \n-struct slot_expansion {\n-\tconst char *prefix;\n-\tconst char *placeholder;\n-\tvoid (*fn)(struct string_list *list, const char *prefix);\n-\tint found;\n-};\n-\n-void list_config_help(int for_human)\n-{\n-\tstruct slot_expansion slot_expansions[] = {\n-\t\t{ \"advice\", \"*\", list_config_advices },\n-\t\t{ \"color.branch\", \"<slot>\", list_config_color_branch_slots },\n-\t\t{ \"color.decorate\", \"<slot>\", list_config_color_decorate_slots },\n-\t\t{ \"color.diff\", \"<slot>\", list_config_color_diff_slots },\n-\t\t{ \"color.grep\", \"<slot>\", list_config_color_grep_slots },\n-\t\t{ \"color.interactive\", \"<slot>\", list_config_color_interactive_slots },\n-\t\t{ \"color.remote\", \"<slot>\", list_config_color_sideband_slots },\n-\t\t{ \"color.status\", \"<slot>\", list_config_color_status_slots },\n-\t\t{ \"fsck\", \"<msg-id>\", list_config_fsck_msg_ids },\n-\t\t{ \"receive.fsck\", \"<msg-id>\", list_config_fsck_msg_ids },\n-\t\t{ NULL, NULL, NULL }\n-\t};\n-\tconst char **p;\n-\tstruct slot_expansion *e;\n-\tstruct string_list keys = STRING_LIST_INIT_DUP;\n-\tint i;\n-\n-\tfor (p = config_name_list; *p; p++) {\n-\t\tconst char *var = *p;\n-\t\tstruct strbuf sb = STRBUF_INIT;\n-\n-\t\tfor (e = slot_expansions; e->prefix; e++) {\n-\n-\t\t\tstrbuf_reset(&sb);\n-\t\t\tstrbuf_addf(&sb, \"%s.%s\", e->prefix, e->placeholder);\n-\t\t\tif (!strcasecmp(var, sb.buf)) {\n-\t\t\t\te->fn(&keys, e->prefix);\n-\t\t\t\te->found++;\n-\t\t\t\tbreak;\n-\t\t\t}\n-\t\t}\n-\t\tstrbuf_release(&sb);\n-\t\tif (!e->prefix)\n-\t\t\tstring_list_append(&keys, var);\n-\t}\n-\n-\tfor (e = slot_expansions; e->prefix; e++)\n-\t\tif (!e->found)\n-\t\t\tBUG(\"slot_expansion %s.%s is not used\",\n-\t\t\t    e->prefix, e->placeholder);\n-\n-\tstring_list_sort(&keys);\n-\tfor (i = 0; i < keys.nr; i++) {\n-\t\tconst char *var = keys.items[i].string;\n-\t\tconst char *wildcard, *tag, *cut;\n-\n-\t\tif (for_human) {\n-\t\t\tputs(var);\n-\t\t\tcontinue;\n-\t\t}\n-\n-\t\twildcard = strchr(var, '*');\n-\t\ttag = strchr(var, '<');\n-\n-\t\tif (!wildcard && !tag) {\n-\t\t\tputs(var);\n-\t\t\tcontinue;\n-\t\t}\n-\n-\t\tif (wildcard && !tag)\n-\t\t\tcut = wildcard;\n-\t\telse if (!wildcard && tag)\n-\t\t\tcut = tag;\n-\t\telse\n-\t\t\tcut = wildcard < tag ? wildcard : tag;\n-\n-\t\t/*\n-\t\t * We may produce duplicates, but that's up to\n-\t\t * git-completion.bash to handle\n-\t\t */\n-\t\tprintf(\"%.*s\\n\", (int)(cut - var), var);\n-\t}\n-\tstring_list_clear(&keys, 0);\n-}\n-\n static int get_alias(const char *var, const char *value, void *data)\n {\n \tstruct string_list *list = data;\ndiff --git a/help.h b/help.h\nindex 7a455beeb7..9071894e8c 100644\n--- a/help.h\n+++ b/help.h\n@@ -22,7 +22,6 @@ static inline void mput_char(char c, unsigned int num)\n void list_common_cmds_help(void);\n void list_all_cmds_help(void);\n void list_common_guides_help(void);\n-void list_config_help(int for_human);\n \n void list_all_main_cmds(struct string_list *list);\n void list_all_other_cmds(struct string_list *list);\n-- \n2.25.1.696.g5e7596f4ac-goog\n\n"},{"id":"394022","messageId":"20200325212500.135046-3-emilyshaffer@google.com","threadId":"53075","inReplyTo":"20200325212500.135046-1-emilyshaffer@google.com","subject":"[PATCH v11 2/5] bugreport: add tool to generate debugging info","fromName":"Emily Shaffer","fromEmail":"emilyshaffer@google.com","sentAt":"2020-03-25T21:24:57Z","receivedAt":"2020-03-25T21:25:20Z","isPatch":true,"sender":{"key":"nasamuffin@google.com","avatar":"https://avatars.githubusercontent.com/u/1606826?v=4"},"body":"Teach Git how to prompt the user for a good bug report: reproduction\nsteps, expected behavior, and actual behavior. Later, Git can learn how\nto collect some diagnostic information from the repository.\n\nIf users can send us a well-written bug report which contains diagnostic\ninformation we would otherwise need to ask the user for, we can reduce\nthe number of question-and-answer round trips between the reporter and\nthe Git contributor.\n\nUsers may also wish to send a report like this to their local \"Git\nexpert\" if they have put their repository into a state they are confused\nby.\n\nSigned-off-by: Emily Shaffer <emilyshaffer@google.com>\n---\n .gitignore                      |   1 +\n Documentation/git-bugreport.txt |  46 ++++++++++++++\n Makefile                        |   5 ++\n bugreport.c                     | 105 ++++++++++++++++++++++++++++++++\n command-list.txt                |   1 +\n strbuf.c                        |   4 ++\n strbuf.h                        |   1 +\n t/t0091-bugreport.sh            |  61 +++++++++++++++++++\n 8 files changed, 224 insertions(+)\n create mode 100644 Documentation/git-bugreport.txt\n create mode 100644 bugreport.c\n create mode 100755 t/t0091-bugreport.sh\n\ndiff --git a/.gitignore b/.gitignore\nindex ea97de83f3..d89bf9e11e 100644\n--- a/.gitignore\n+++ b/.gitignore\n@@ -25,6 +25,7 @@\n /git-bisect--helper\n /git-blame\n /git-branch\n+/git-bugreport\n /git-bundle\n /git-cat-file\n /git-check-attr\ndiff --git a/Documentation/git-bugreport.txt b/Documentation/git-bugreport.txt\nnew file mode 100644\nindex 0000000000..1f9fde5cde\n--- /dev/null\n+++ b/Documentation/git-bugreport.txt\n@@ -0,0 +1,46 @@\n+git-bugreport(1)\n+================\n+\n+NAME\n+----\n+git-bugreport - Collect information for user to file a bug report\n+\n+SYNOPSIS\n+--------\n+[verse]\n+'git bugreport' [(-o | --output-directory) <path>] [(-s | --suffix) <format>]\n+\n+DESCRIPTION\n+-----------\n+Captures information about the user's machine, Git client, and repository state,\n+as well as a form requesting information about the behavior the user observed,\n+into a single text file which the user can then share, for example to the Git\n+mailing list, in order to report an observed bug.\n+\n+The following information is requested from the user:\n+\n+ - Reproduction steps\n+ - Expected behavior\n+ - Actual behavior\n+\n+This tool is invoked via the typical Git setup process, which means that in some\n+cases, it might not be able to launch - for example, if a relevant config file\n+is unreadable. In this kind of scenario, it may be helpful to manually gather\n+the kind of information listed above when manually asking for help.\n+\n+OPTIONS\n+-------\n+-o <path>::\n+--output-directory <path>::\n+\tPlace the resulting bug report file in `<path>` instead of the root of\n+\tthe Git repository.\n+\n+-s <format>::\n+--suffix <format>::\n+\tSpecify an alternate suffix for the bugreport name, to create a file\n+\tnamed 'git-bugreport-<formatted suffix>'. This should take the form of a\n+\tlink:strftime[3] format string; the current local time will be used.\n+\n+GIT\n+---\n+Part of the linkgit:git[1] suite\ndiff --git a/Makefile b/Makefile\nindex c552312d3f..9e6705061d 100644\n--- a/Makefile\n+++ b/Makefile\n@@ -681,6 +681,7 @@ EXTRA_PROGRAMS =\n # ... and all the rest that could be moved out of bindir to gitexecdir\n PROGRAMS += $(EXTRA_PROGRAMS)\n \n+PROGRAM_OBJS += bugreport.o\n PROGRAM_OBJS += credential-store.o\n PROGRAM_OBJS += daemon.o\n PROGRAM_OBJS += fast-import.o\n@@ -2461,6 +2462,10 @@ endif\n git-%$X: %.o GIT-LDFLAGS $(GITLIBS)\n \t$(QUIET_LINK)$(CC) $(ALL_CFLAGS) -o $@ $(ALL_LDFLAGS) $(filter %.o,$^) $(LIBS)\n \n+git-bugreport$X: bugreport.o GIT-LDFLAGS $(GITLIBS)\n+\t$(QUIET_LINK)$(CC) $(ALL_CFLAGS) -o $@ $(ALL_LDFLAGS) $(filter %.o,$^) \\\n+\t\t$(LIBS)\n+\n git-imap-send$X: imap-send.o $(IMAP_SEND_BUILDDEPS) GIT-LDFLAGS $(GITLIBS)\n \t$(QUIET_LINK)$(CC) $(ALL_CFLAGS) -o $@ $(ALL_LDFLAGS) $(filter %.o,$^) \\\n \t\t$(IMAP_SEND_LDFLAGS) $(LIBS)\ndiff --git a/bugreport.c b/bugreport.c\nnew file mode 100644\nindex 0000000000..f6f53a5e8e\n--- /dev/null\n+++ b/bugreport.c\n@@ -0,0 +1,105 @@\n+#include \"builtin.h\"\n+#include \"parse-options.h\"\n+#include \"stdio.h\"\n+#include \"strbuf.h\"\n+#include \"time.h\"\n+\n+static const char * const bugreport_usage[] = {\n+\tN_(\"git bugreport [-o|--output-directory <file>] [-s|--suffix <format>]\"),\n+\tNULL\n+};\n+\n+static int get_bug_template(struct strbuf *template)\n+{\n+\tconst char template_text[] = N_(\n+\"Thank you for filling out a Git bug report!\\n\"\n+\"Please answer the following questions to help us understand your issue.\\n\"\n+\"\\n\"\n+\"What did you do before the bug happened? (Steps to reproduce your issue)\\n\"\n+\"\\n\"\n+\"What did you expect to happen? (Expected behavior)\\n\"\n+\"\\n\"\n+\"What happened instead? (Actual behavior)\\n\"\n+\"\\n\"\n+\"What's different between what you expected and what actually happened?\\n\"\n+\"\\n\"\n+\"Anything else you want to add:\\n\"\n+\"\\n\"\n+\"Please review the rest of the bug report below.\\n\"\n+\"You can delete any lines you don't wish to share.\\n\");\n+\n+\tstrbuf_addstr(template, _(template_text));\n+\treturn 0;\n+}\n+\n+int cmd_main(int argc, const char **argv)\n+{\n+\tstruct strbuf buffer = STRBUF_INIT;\n+\tstruct strbuf report_path = STRBUF_INIT;\n+\tint report = -1;\n+\ttime_t now = time(NULL);\n+\tchar *option_output = NULL;\n+\tchar *option_suffix = \"%Y-%m-%d-%H%M\";\n+\tint nongit_ok = 0;\n+\tconst char *prefix = NULL;\n+\tconst char *user_relative_path = NULL;\n+\n+\tconst struct option bugreport_options[] = {\n+\t\tOPT_STRING('o', \"output-directory\", &option_output, N_(\"path\"),\n+\t\t\t   N_(\"specify a destination for the bugreport file\")),\n+\t\tOPT_STRING('s', \"suffix\", &option_suffix, N_(\"format\"),\n+\t\t\t   N_(\"specify a strftime format suffix for the filename\")),\n+\t\tOPT_END()\n+\t};\n+\n+\tprefix = setup_git_directory_gently(&nongit_ok);\n+\n+\targc = parse_options(argc, argv, prefix, bugreport_options,\n+\t\t\t     bugreport_usage, 0);\n+\n+\t/* Prepare the path to put the result */\n+\tstrbuf_addstr(&report_path,\n+\t\t      prefix_filename(prefix,\n+\t\t\t\t      option_output ? option_output : \"\"));\n+\tstrbuf_complete(&report_path, '/');\n+\n+\tstrbuf_addstr(&report_path, \"git-bugreport-\");\n+\tstrbuf_addftime(&report_path, option_suffix, localtime(&now), 0, 0);\n+\tstrbuf_addstr(&report_path, \".txt\");\n+\n+\tswitch (safe_create_leading_directories(report_path.buf)) {\n+\tcase SCLD_OK:\n+\tcase SCLD_EXISTS:\n+\t\tbreak;\n+\tdefault:\n+\t\tdie(_(\"could not create leading directories for '%s'\"),\n+\t\t    report_path.buf);\n+\t}\n+\n+\t/* Prepare the report contents */\n+\tget_bug_template(&buffer);\n+\n+\t/* fopen doesn't offer us an O_EXCL alternative, except with glibc. */\n+\treport = open(report_path.buf, O_CREAT | O_EXCL | O_WRONLY, 0666);\n+\n+\tif (report < 0) {\n+\t\tUNLEAK(report_path);\n+\t\tdie(_(\"couldn't create a new file at '%s'\"), report_path.buf);\n+\t}\n+\n+\tstrbuf_write_fd(&buffer, report);\n+\tclose(report);\n+\n+\t/*\n+\t * We want to print the path relative to the user, but we still need the\n+\t * path relative to us to give to the editor.\n+\t */\n+\tif (!(prefix && skip_prefix(report_path.buf, prefix, &user_relative_path)))\n+\t\tuser_relative_path = report_path.buf;\n+\tfprintf(stderr, _(\"Created new report at '%s'.\\n\"),\n+\t\tuser_relative_path);\n+\n+\tUNLEAK(buffer);\n+\tUNLEAK(report_path);\n+\treturn !!launch_editor(report_path.buf, NULL, NULL);\n+}\ndiff --git a/command-list.txt b/command-list.txt\nindex 2087894655..185e5e3f05 100644\n--- a/command-list.txt\n+++ b/command-list.txt\n@@ -54,6 +54,7 @@ git-archive                             mainporcelain\n git-bisect                              mainporcelain           info\n git-blame                               ancillaryinterrogators          complete\n git-branch                              mainporcelain           history\n+git-bugreport                           ancillaryinterrogators\n git-bundle                              mainporcelain\n git-cat-file                            plumbinginterrogators\n git-check-attr                          purehelpers\ndiff --git a/strbuf.c b/strbuf.c\nindex f19da55b07..f1d66c7848 100644\n--- a/strbuf.c\n+++ b/strbuf.c\n@@ -539,6 +539,10 @@ ssize_t strbuf_write(struct strbuf *sb, FILE *f)\n \treturn sb->len ? fwrite(sb->buf, 1, sb->len, f) : 0;\n }\n \n+ssize_t strbuf_write_fd(struct strbuf *sb, int fd)\n+{\n+\treturn sb->len ? write(fd, sb->buf, sb->len) : 0;\n+}\n \n #define STRBUF_MAXLINK (2*PATH_MAX)\n \ndiff --git a/strbuf.h b/strbuf.h\nindex aae7ac3a82..bbf6204de7 100644\n--- a/strbuf.h\n+++ b/strbuf.h\n@@ -462,6 +462,7 @@ int strbuf_readlink(struct strbuf *sb, const char *path, size_t hint);\n  * NUL bytes.\n  */\n ssize_t strbuf_write(struct strbuf *sb, FILE *stream);\n+ssize_t strbuf_write_fd(struct strbuf *sb, int fd);\n \n /**\n  * Read a line from a FILE *, overwriting the existing contents of\ndiff --git a/t/t0091-bugreport.sh b/t/t0091-bugreport.sh\nnew file mode 100755\nindex 0000000000..65f664fdac\n--- /dev/null\n+++ b/t/t0091-bugreport.sh\n@@ -0,0 +1,61 @@\n+#!/bin/sh\n+\n+test_description='git bugreport'\n+\n+. ./test-lib.sh\n+\n+# Headers \"[System Info]\" will be followed by a non-empty line if we put some\n+# information there; we can make sure all our headers were followed by some\n+# information to check if the command was successful.\n+HEADER_PATTERN=\"^\\[.*\\]$\"\n+\n+check_all_headers_populated () {\n+\twhile read -r line\n+\tdo\n+\t\tif test \"$(grep \"$HEADER_PATTERN\" \"$line\")\"\n+\t\tthen\n+\t\t\techo \"$line\"\n+\t\t\tread -r nextline\n+\t\t\tif test -z \"$nextline\"; then\n+\t\t\t\treturn 1;\n+\t\t\tfi\n+\t\tfi\n+\tdone\n+}\n+\n+test_expect_success 'creates a report with content in the right places' '\n+\tgit bugreport -s check-headers &&\n+\tcheck_all_headers_populated <git-bugreport-check-headers.txt &&\n+\ttest_when_finished rm git-bugreport-check-headers.txt\n+'\n+\n+test_expect_success 'dies if file with same name as report already exists' '\n+\t>>git-bugreport-duplicate.txt &&\n+\ttest_must_fail git bugreport --suffix duplicate &&\n+\ttest_when_finished rm git-bugreport-duplicate.txt\n+'\n+\n+test_expect_success '--output-directory puts the report in the provided dir' '\n+\tgit bugreport -o foo/ &&\n+\ttest_path_is_file foo/git-bugreport-* &&\n+\ttest_when_finished rm -fr foo/\n+'\n+\n+test_expect_success 'incorrect arguments abort with usage' '\n+\ttest_must_fail git bugreport --false 2>output &&\n+\ttest_i18ngrep usage output &&\n+\ttest_path_is_missing git-bugreport-*\n+'\n+\n+test_expect_success 'runs outside of a git dir' '\n+\tnongit git bugreport &&\n+\ttest_when_finished rm non-repo/git-bugreport-*\n+'\n+\n+test_expect_success 'can create leading directories outside of a git dir' '\n+\tnongit git bugreport -o foo/bar/baz &&\n+\ttest_when_finished rm -fr foo/bar/baz\n+'\n+\n+\n+test_done\n-- \n2.25.1.696.g5e7596f4ac-goog\n\n"},{"id":"394023","messageId":"20200325212500.135046-4-emilyshaffer@google.com","threadId":"53075","inReplyTo":"20200325212500.135046-1-emilyshaffer@google.com","subject":"[PATCH v11 3/5] bugreport: gather git version and build info","fromName":"Emily Shaffer","fromEmail":"emilyshaffer@google.com","sentAt":"2020-03-25T21:24:58Z","receivedAt":"2020-03-25T21:25:23Z","isPatch":true,"sender":{"key":"nasamuffin@google.com","avatar":"https://avatars.githubusercontent.com/u/1606826?v=4"},"body":"Knowing which version of Git a user has and how it was built allows us\nto more precisely pin down the circumstances when a certain issue\noccurs, so teach bugreport how to tell us the same output as 'git\nversion --build-options'.\n\nIt's not ideal to directly call 'git version --build-options' because\nthat output goes to stdout. Instead, wrap the version string in a helper\nwithin help.[ch] library, and call that helper from within the bugreport\nlibrary.\n\nSigned-off-by: Emily Shaffer <emilyshaffer@google.com>\n---\n Documentation/git-bugreport.txt |  4 +++\n bugreport.c                     | 19 +++++++++++++-\n help.c                          | 46 ++++++++++++++++++++-------------\n help.h                          |  1 +\n 4 files changed, 51 insertions(+), 19 deletions(-)\n\ndiff --git a/Documentation/git-bugreport.txt b/Documentation/git-bugreport.txt\nindex 1f9fde5cde..f44ae8cbe7 100644\n--- a/Documentation/git-bugreport.txt\n+++ b/Documentation/git-bugreport.txt\n@@ -23,6 +23,10 @@ The following information is requested from the user:\n  - Expected behavior\n  - Actual behavior\n \n+The following information is captured automatically:\n+\n+ - 'git version --build-options'\n+\n This tool is invoked via the typical Git setup process, which means that in some\n cases, it might not be able to launch - for example, if a relevant config file\n is unreadable. In this kind of scenario, it may be helpful to manually gather\ndiff --git a/bugreport.c b/bugreport.c\nindex f6f53a5e8e..4cdb58bbaa 100644\n--- a/bugreport.c\n+++ b/bugreport.c\n@@ -1,8 +1,17 @@\n-#include \"builtin.h\"\n+#include \"cache.h\"\n #include \"parse-options.h\"\n #include \"stdio.h\"\n #include \"strbuf.h\"\n #include \"time.h\"\n+#include \"help.h\"\n+\n+static void get_system_info(struct strbuf *sys_info)\n+{\n+\t/* get git version from native cmd */\n+\tstrbuf_addstr(sys_info, _(\"git version:\\n\"));\n+\tget_version_info(sys_info, 1);\n+\tstrbuf_complete_line(sys_info);\n+}\n \n static const char * const bugreport_usage[] = {\n \tN_(\"git bugreport [-o|--output-directory <file>] [-s|--suffix <format>]\"),\n@@ -32,6 +41,11 @@ static int get_bug_template(struct strbuf *template)\n \treturn 0;\n }\n \n+static void get_header(struct strbuf *buf, const char *title)\n+{\n+\tstrbuf_addf(buf, \"\\n\\n[%s]\\n\", title);\n+}\n+\n int cmd_main(int argc, const char **argv)\n {\n \tstruct strbuf buffer = STRBUF_INIT;\n@@ -79,6 +93,9 @@ int cmd_main(int argc, const char **argv)\n \t/* Prepare the report contents */\n \tget_bug_template(&buffer);\n \n+\tget_header(&buffer, _(\"System Info\"));\n+\tget_system_info(&buffer);\n+\n \t/* fopen doesn't offer us an O_EXCL alternative, except with glibc. */\n \treport = open(report_path.buf, O_CREAT | O_EXCL | O_WRONLY, 0666);\n \ndiff --git a/help.c b/help.c\nindex a21487db77..1de9c0d589 100644\n--- a/help.c\n+++ b/help.c\n@@ -622,8 +622,32 @@ const char *help_unknown_cmd(const char *cmd)\n \texit(1);\n }\n \n+void get_version_info(struct strbuf *buf, int show_build_options)\n+{\n+\t/*\n+\t * The format of this string should be kept stable for compatibility\n+\t * with external projects that rely on the output of \"git version\".\n+\t *\n+\t * Always show the version, even if other options are given.\n+\t */\n+\tstrbuf_addf(buf, \"git version %s\\n\", git_version_string);\n+\n+\tif (show_build_options) {\n+\t\tstrbuf_addf(buf, \"cpu: %s\\n\", GIT_HOST_CPU);\n+\t\tif (git_built_from_commit_string[0])\n+\t\t\tstrbuf_addf(buf, \"built from commit: %s\\n\",\n+\t\t\t       git_built_from_commit_string);\n+\t\telse\n+\t\t\tstrbuf_addstr(buf, \"no commit associated with this build\\n\");\n+\t\tstrbuf_addf(buf, \"sizeof-long: %d\\n\", (int)sizeof(long));\n+\t\tstrbuf_addf(buf, \"sizeof-size_t: %d\\n\", (int)sizeof(size_t));\n+\t\t/* NEEDSWORK: also save and output GIT-BUILD_OPTIONS? */\n+\t}\n+}\n+\n int cmd_version(int argc, const char **argv, const char *prefix)\n {\n+\tstruct strbuf buf = STRBUF_INIT;\n \tint build_options = 0;\n \tconst char * const usage[] = {\n \t\tN_(\"git version [<options>]\"),\n@@ -637,25 +661,11 @@ int cmd_version(int argc, const char **argv, const char *prefix)\n \n \targc = parse_options(argc, argv, prefix, options, usage, 0);\n \n-\t/*\n-\t * The format of this string should be kept stable for compatibility\n-\t * with external projects that rely on the output of \"git version\".\n-\t *\n-\t * Always show the version, even if other options are given.\n-\t */\n-\tprintf(\"git version %s\\n\", git_version_string);\n+\tget_version_info(&buf, build_options);\n+\tprintf(\"%s\", buf.buf);\n+\n+\tstrbuf_release(&buf);\n \n-\tif (build_options) {\n-\t\tprintf(\"cpu: %s\\n\", GIT_HOST_CPU);\n-\t\tif (git_built_from_commit_string[0])\n-\t\t\tprintf(\"built from commit: %s\\n\",\n-\t\t\t       git_built_from_commit_string);\n-\t\telse\n-\t\t\tprintf(\"no commit associated with this build\\n\");\n-\t\tprintf(\"sizeof-long: %d\\n\", (int)sizeof(long));\n-\t\tprintf(\"sizeof-size_t: %d\\n\", (int)sizeof(size_t));\n-\t\t/* NEEDSWORK: also save and output GIT-BUILD_OPTIONS? */\n-\t}\n \treturn 0;\n }\n \ndiff --git a/help.h b/help.h\nindex 9071894e8c..500521b908 100644\n--- a/help.h\n+++ b/help.h\n@@ -37,6 +37,7 @@ void add_cmdname(struct cmdnames *cmds, const char *name, int len);\n void exclude_cmds(struct cmdnames *cmds, struct cmdnames *excludes);\n int is_in_cmdlist(struct cmdnames *cmds, const char *name);\n void list_commands(unsigned int colopts, struct cmdnames *main_cmds, struct cmdnames *other_cmds);\n+void get_version_info(struct strbuf *buf, int show_build_options);\n \n /*\n  * call this to die(), when it is suspected that the user mistyped a\n-- \n2.25.1.696.g5e7596f4ac-goog\n\n"},{"id":"394024","messageId":"20200325212500.135046-5-emilyshaffer@google.com","threadId":"53075","inReplyTo":"20200325212500.135046-1-emilyshaffer@google.com","subject":"[PATCH v11 4/5] bugreport: add uname info","fromName":"Emily Shaffer","fromEmail":"emilyshaffer@google.com","sentAt":"2020-03-25T21:24:59Z","receivedAt":"2020-03-25T21:25:26Z","isPatch":true,"sender":{"key":"nasamuffin@google.com","avatar":"https://avatars.githubusercontent.com/u/1606826?v=4"},"body":"The contents of uname() can give us some insight into what sort of\nsystem the user is running on, and help us replicate their setup if need\nbe. The domainname field is not guaranteed to be available, so don't\ncollect it.\n\nSigned-off-by: Emily Shaffer <emilyshaffer@google.com>\n---\n Documentation/git-bugreport.txt |  1 +\n bugreport.c                     | 16 +++++++++++++++-\n 2 files changed, 16 insertions(+), 1 deletion(-)\n\ndiff --git a/Documentation/git-bugreport.txt b/Documentation/git-bugreport.txt\nindex f44ae8cbe7..17b0d14e8d 100644\n--- a/Documentation/git-bugreport.txt\n+++ b/Documentation/git-bugreport.txt\n@@ -26,6 +26,7 @@ The following information is requested from the user:\n The following information is captured automatically:\n \n  - 'git version --build-options'\n+ - uname sysname, release, version, and machine strings\n \n This tool is invoked via the typical Git setup process, which means that in some\n cases, it might not be able to launch - for example, if a relevant config file\ndiff --git a/bugreport.c b/bugreport.c\nindex 4cdb58bbaa..1a3172bcec 100644\n--- a/bugreport.c\n+++ b/bugreport.c\n@@ -7,10 +7,24 @@\n \n static void get_system_info(struct strbuf *sys_info)\n {\n+\tstruct utsname uname_info;\n+\n \t/* get git version from native cmd */\n \tstrbuf_addstr(sys_info, _(\"git version:\\n\"));\n \tget_version_info(sys_info, 1);\n-\tstrbuf_complete_line(sys_info);\n+\n+\t/* system call for other version info */\n+\tstrbuf_addstr(sys_info, \"uname: \");\n+\tif (uname(&uname_info))\n+\t\tstrbuf_addf(sys_info, _(\"uname() failed with error '%s' (%d)\\n\"),\n+\t\t\t    strerror(errno),\n+\t\t\t    errno);\n+\telse\n+\t\tstrbuf_addf(sys_info, \"%s %s %s %s\\n\",\n+\t\t\t    uname_info.sysname,\n+\t\t\t    uname_info.release,\n+\t\t\t    uname_info.version,\n+\t\t\t    uname_info.machine);\n }\n \n static const char * const bugreport_usage[] = {\n-- \n2.25.1.696.g5e7596f4ac-goog\n\n"},{"id":"394025","messageId":"20200325212500.135046-6-emilyshaffer@google.com","threadId":"53075","inReplyTo":"20200325212500.135046-1-emilyshaffer@google.com","subject":"[PATCH v11 5/5] bugreport: add compiler info","fromName":"Emily Shaffer","fromEmail":"emilyshaffer@google.com","sentAt":"2020-03-25T21:25:00Z","receivedAt":"2020-03-25T21:25:27Z","isPatch":true,"sender":{"key":"nasamuffin@google.com","avatar":"https://avatars.githubusercontent.com/u/1606826?v=4"},"body":"To help pinpoint the source of a regression, it is useful to know some\ninfo about the compiler which the user's Git client was built with. By\nadding a generic get_compiler_info() in 'compat/' we can choose which\nrelevant information to share per compiler; to get started, let's\ndemonstrate the version of glibc if the user built with 'gcc'.\n\nSigned-off-by: Emily Shaffer <emilyshaffer@google.com>\nHelped-by: Danh Doan <congdanhqx@gmail.com>\nHelped-by: Johannes Schindelin <Johannes.Schindelin@gmx.de>\n---\n Documentation/git-bugreport.txt |  1 +\n bugreport.c                     |  6 +++++\n compat/compiler.h               | 41 +++++++++++++++++++++++++++++++++\n 3 files changed, 48 insertions(+)\n create mode 100644 compat/compiler.h\n\ndiff --git a/Documentation/git-bugreport.txt b/Documentation/git-bugreport.txt\nindex 17b0d14e8d..643d1b2884 100644\n--- a/Documentation/git-bugreport.txt\n+++ b/Documentation/git-bugreport.txt\n@@ -27,6 +27,7 @@ The following information is captured automatically:\n \n  - 'git version --build-options'\n  - uname sysname, release, version, and machine strings\n+ - Compiler-specific info string\n \n This tool is invoked via the typical Git setup process, which means that in some\n cases, it might not be able to launch - for example, if a relevant config file\ndiff --git a/bugreport.c b/bugreport.c\nindex 1a3172bcec..089b939a87 100644\n--- a/bugreport.c\n+++ b/bugreport.c\n@@ -4,6 +4,7 @@\n #include \"strbuf.h\"\n #include \"time.h\"\n #include \"help.h\"\n+#include \"compat/compiler.h\"\n \n static void get_system_info(struct strbuf *sys_info)\n {\n@@ -25,6 +26,11 @@ static void get_system_info(struct strbuf *sys_info)\n \t\t\t    uname_info.release,\n \t\t\t    uname_info.version,\n \t\t\t    uname_info.machine);\n+\n+\tstrbuf_addstr(sys_info, _(\"compiler info: \"));\n+\tget_compiler_info(sys_info);\n+\tstrbuf_addstr(sys_info, _(\"libc info: \"));\n+\tget_libc_info(sys_info);\n }\n \n static const char * const bugreport_usage[] = {\ndiff --git a/compat/compiler.h b/compat/compiler.h\nnew file mode 100644\nindex 0000000000..10dbb65937\n--- /dev/null\n+++ b/compat/compiler.h\n@@ -0,0 +1,41 @@\n+#ifndef COMPILER_H\n+#define COMPILER_H\n+\n+#include \"git-compat-util.h\"\n+#include \"strbuf.h\"\n+\n+#ifdef __GLIBC__\n+#include <gnu/libc-version.h>\n+#endif\n+\n+static inline void get_compiler_info(struct strbuf *info)\n+{\n+\tint len = info->len;\n+#ifdef __clang__\n+\tstrbuf_addf(info, \"clang: %s\\n\", __clang_version__);\n+#elif defined(__GNUC__)\n+\tstrbuf_addf(info, \"gnuc: %d.%d\\n\", __GNUC__, __GNUC_MINOR__);\n+#endif\n+\n+#ifdef _MSC_VER\n+\tstrbuf_addf(info, \"MSVC version: %02d.%02d.%05d\\n\",\n+\t\t    _MSC_VER / 100, _MSC_VER % 100, _MSC_FULL_VER % 100000);\n+#endif\n+\n+\tif (len == info->len)\n+\t\tstrbuf_addstr(info, _(\"no compiler information available\\n\"));\n+}\n+\n+static inline void get_libc_info(struct strbuf *info)\n+{\n+\tint len = info->len;\n+\n+#ifdef __GLIBC__\n+\tstrbuf_addf(info, \"glibc: %s\\n\", gnu_get_libc_version());\n+#endif\n+\n+\tif (len == info->len)\n+\t\tstrbuf_addstr(info, _(\"no libc information available\\n\"));\n+}\n+\n+#endif /* COMPILER_H */\n-- \n2.25.1.696.g5e7596f4ac-goog\n\n"},{"id":"394518","messageId":"20200401201743.GF2224@szeder.dev","threadId":"53075","inReplyTo":"20200325212500.135046-3-emilyshaffer@google.com","subject":"Re: [PATCH v11 2/5] bugreport: add tool to generate debugging info","fromName":"SZEDER Gábor","fromEmail":"szeder.dev@gmail.com","sentAt":"2020-04-01T20:17:43Z","receivedAt":"2020-04-01T20:17:49Z","isPatch":true,"sender":{"key":"szeder.dev@gmail.com","avatar":"https://avatars.githubusercontent.com/u/116324?v=4"},"body":"On Wed, Mar 25, 2020 at 02:24:57PM -0700, Emily Shaffer wrote:\n> diff --git a/t/t0091-bugreport.sh b/t/t0091-bugreport.sh\n> new file mode 100755\n> index 0000000000..65f664fdac\n> --- /dev/null\n> +++ b/t/t0091-bugreport.sh\n> @@ -0,0 +1,61 @@\n> +#!/bin/sh\n> +\n> +test_description='git bugreport'\n> +\n> +. ./test-lib.sh\n> +\n> +# Headers \"[System Info]\" will be followed by a non-empty line if we put some\n> +# information there; we can make sure all our headers were followed by some\n> +# information to check if the command was successful.\n> +HEADER_PATTERN=\"^\\[.*\\]$\"\n> +\n> +check_all_headers_populated () {\n> +\twhile read -r line\n> +\tdo\n> +\t\tif test \"$(grep \"$HEADER_PATTERN\" \"$line\")\"\n> +\t\tthen\n> +\t\t\techo \"$line\"\n> +\t\t\tread -r nextline\n> +\t\t\tif test -z \"$nextline\"; then\n> +\t\t\t\treturn 1;\n> +\t\t\tfi\n> +\t\tfi\n> +\tdone\n> +}\n> +\n> +test_expect_success 'creates a report with content in the right places' '\n> +\tgit bugreport -s check-headers &&\n> +\tcheck_all_headers_populated <git-bugreport-check-headers.txt &&\n> +\ttest_when_finished rm git-bugreport-check-headers.txt\n\n'test_when_finished' should be at the beginning of the test, otherwise\nit will have no effect if a command before it were to fail.\n\n> +'\n> +\n> +test_expect_success 'dies if file with same name as report already exists' '\n> +\t>>git-bugreport-duplicate.txt &&\n> +\ttest_must_fail git bugreport --suffix duplicate &&\n> +\ttest_when_finished rm git-bugreport-duplicate.txt\n> +'\n> +\n> +test_expect_success '--output-directory puts the report in the provided dir' '\n> +\tgit bugreport -o foo/ &&\n> +\ttest_path_is_file foo/git-bugreport-* &&\n> +\ttest_when_finished rm -fr foo/\n> +'\n> +\n> +test_expect_success 'incorrect arguments abort with usage' '\n> +\ttest_must_fail git bugreport --false 2>output &&\n> +\ttest_i18ngrep usage output &&\n> +\ttest_path_is_missing git-bugreport-*\n> +'\n> +\n> +test_expect_success 'runs outside of a git dir' '\n> +\tnongit git bugreport &&\n> +\ttest_when_finished rm non-repo/git-bugreport-*\n> +'\n> +\n> +test_expect_success 'can create leading directories outside of a git dir' '\n> +\tnongit git bugreport -o foo/bar/baz &&\n> +\ttest_when_finished rm -fr foo/bar/baz\n> +'\n> +\n> +\n> +test_done\n> -- \n> 2.25.1.696.g5e7596f4ac-goog\n> \n"},{"id":"394885","messageId":"20200406224526.256074-1-emilyshaffer@google.com","threadId":"53075","inReplyTo":"20200325212500.135046-1-emilyshaffer@google.com","subject":"[PATCH v12 0/5] bugreport: add tool to generate debugging info","fromName":"Emily Shaffer","fromEmail":"emilyshaffer@google.com","sentAt":"2020-04-06T22:45:21Z","receivedAt":"2020-04-06T22:45:36Z","isPatch":true,"sender":{"key":"nasamuffin@google.com","avatar":"https://avatars.githubusercontent.com/u/1606826?v=4"},"body":"Since v11, reordered tests per SZEDER's comment so that the\ntest_when_finished lines come first in each test.\n\nEmily Shaffer (5):\n  help: move list_config_help to builtin/help\n  bugreport: add tool to generate debugging info\n  bugreport: gather git version and build info\n  bugreport: add uname info\n  bugreport: add compiler info\n\n .gitignore                      |   2 +\n Documentation/git-bugreport.txt |  52 ++++++++++++\n Makefile                        |  18 +++-\n bugreport.c                     | 142 ++++++++++++++++++++++++++++++++\n builtin/help.c                  |  86 +++++++++++++++++++\n command-list.txt                |   1 +\n compat/compiler.h               |  41 +++++++++\n generate-cmdlist.sh             |  19 -----\n generate-configlist.sh          |  21 +++++\n help.c                          | 131 +++++++----------------------\n help.h                          |   2 +-\n strbuf.c                        |   4 +\n strbuf.h                        |   1 +\n t/t0091-bugreport.sh            |  61 ++++++++++++++\n 14 files changed, 455 insertions(+), 126 deletions(-)\n create mode 100644 Documentation/git-bugreport.txt\n create mode 100644 bugreport.c\n create mode 100644 compat/compiler.h\n create mode 100755 generate-configlist.sh\n create mode 100755 t/t0091-bugreport.sh\n\n-- \n2.26.0.292.g33ef6b2f38-goog\n\n"},{"id":"394886","messageId":"20200406224526.256074-2-emilyshaffer@google.com","threadId":"53075","inReplyTo":"20200406224526.256074-1-emilyshaffer@google.com","subject":"[PATCH v12 1/5] help: move list_config_help to builtin/help","fromName":"Emily Shaffer","fromEmail":"emilyshaffer@google.com","sentAt":"2020-04-06T22:45:22Z","receivedAt":"2020-04-06T22:45:40Z","isPatch":true,"sender":{"key":"nasamuffin@google.com","avatar":"https://avatars.githubusercontent.com/u/1606826?v=4"},"body":"Starting in 3ac68a93fd2, help.o began to depend on builtin/branch.o,\nbuiltin/clean.o, and builtin/config.o. This meant that help.o was\nunusable outside of the context of the main Git executable.\n\nTo make help.o usable by other commands again, move list_config_help()\ninto builtin/help.c (where it makes sense to assume other builtin libraries\nare present).\n\nWhen command-list.h is included but a member is not used, we start to\nhear a compiler warning. Since the config list is generated in a fairly\ndifferent way than the command list, and since commands and config\noptions are semantically different, move the config list into its own\nheader and move the generator into its own script and build rule.\n\nSigned-off-by: Emily Shaffer <emilyshaffer@google.com>\n---\n .gitignore             |  1 +\n Makefile               | 13 +++++--\n builtin/help.c         | 86 ++++++++++++++++++++++++++++++++++++++++++\n generate-cmdlist.sh    | 19 ----------\n generate-configlist.sh | 21 +++++++++++\n help.c                 | 85 -----------------------------------------\n help.h                 |  1 -\n 7 files changed, 118 insertions(+), 108 deletions(-)\n create mode 100755 generate-configlist.sh\n\ndiff --git a/.gitignore b/.gitignore\nindex 188bd1c3de..61bf5142a9 100644\n--- a/.gitignore\n+++ b/.gitignore\n@@ -188,6 +188,7 @@\n /gitweb/gitweb.cgi\n /gitweb/static/gitweb.js\n /gitweb/static/gitweb.min.*\n+/config-list.h\n /command-list.h\n *.tar.gz\n *.dsc\ndiff --git a/Makefile b/Makefile\nindex ef1ff2228f..d4aff7f9b5 100644\n--- a/Makefile\n+++ b/Makefile\n@@ -815,6 +815,7 @@ LIB_FILE = libgit.a\n XDIFF_LIB = xdiff/lib.a\n VCSSVN_LIB = vcs-svn/lib.a\n \n+GENERATED_H += config-list.h\n GENERATED_H += command-list.h\n \n LIB_H := $(sort $(patsubst ./%,%,$(shell git ls-files '*.h' ':!t/' ':!Documentation/' 2>/dev/null || \\\n@@ -2133,7 +2134,7 @@ git$X: git.o GIT-LDFLAGS $(BUILTIN_OBJS) $(GITLIBS)\n \n help.sp help.s help.o: command-list.h\n \n-builtin/help.sp builtin/help.s builtin/help.o: command-list.h GIT-PREFIX\n+builtin/help.sp builtin/help.s builtin/help.o: config-list.h GIT-PREFIX\n builtin/help.sp builtin/help.s builtin/help.o: EXTRA_CPPFLAGS = \\\n \t'-DGIT_HTML_PATH=\"$(htmldir_relative_SQ)\"' \\\n \t'-DGIT_MAN_PATH=\"$(mandir_relative_SQ)\"' \\\n@@ -2153,6 +2154,12 @@ $(BUILT_INS): git$X\n \tln -s $< $@ 2>/dev/null || \\\n \tcp $< $@\n \n+config-list.h: generate-configlist.sh\n+\n+config-list.h:\n+\t$(QUIET_GEN)$(SHELL_PATH) ./generate-configlist.sh \\\n+\t\t>$@+ && mv $@+ $@\n+\n command-list.h: generate-cmdlist.sh command-list.txt\n \n command-list.h: $(wildcard Documentation/git*.txt) Documentation/*config.txt Documentation/config/*.txt\n@@ -2786,7 +2793,7 @@ $(SP_OBJ): %.sp: %.c GIT-CFLAGS FORCE\n .PHONY: sparse $(SP_OBJ)\n sparse: $(SP_OBJ)\n \n-EXCEPT_HDRS := command-list.h unicode-width.h compat/% xdiff/%\n+EXCEPT_HDRS := command-list.h config-list.h unicode-width.h compat/% xdiff/%\n ifndef GCRYPT_SHA256\n \tEXCEPT_HDRS += sha256/gcrypt.h\n endif\n@@ -2808,7 +2815,7 @@ hdr-check: $(HCO)\n style:\n \tgit clang-format --style file --diff --extensions c,h\n \n-check: command-list.h\n+check: config-list.h command-list.h\n \t@if sparse; \\\n \tthen \\\n \t\techo >&2 \"Use 'make sparse' instead\"; \\\ndiff --git a/builtin/help.c b/builtin/help.c\nindex e5590d7787..1c5f2b9255 100644\n--- a/builtin/help.c\n+++ b/builtin/help.c\n@@ -8,6 +8,7 @@\n #include \"parse-options.h\"\n #include \"run-command.h\"\n #include \"column.h\"\n+#include \"config-list.h\"\n #include \"help.h\"\n #include \"alias.h\"\n \n@@ -62,6 +63,91 @@ static const char * const builtin_help_usage[] = {\n \tNULL\n };\n \n+struct slot_expansion {\n+\tconst char *prefix;\n+\tconst char *placeholder;\n+\tvoid (*fn)(struct string_list *list, const char *prefix);\n+\tint found;\n+};\n+\n+static void list_config_help(int for_human)\n+{\n+\tstruct slot_expansion slot_expansions[] = {\n+\t\t{ \"advice\", \"*\", list_config_advices },\n+\t\t{ \"color.branch\", \"<slot>\", list_config_color_branch_slots },\n+\t\t{ \"color.decorate\", \"<slot>\", list_config_color_decorate_slots },\n+\t\t{ \"color.diff\", \"<slot>\", list_config_color_diff_slots },\n+\t\t{ \"color.grep\", \"<slot>\", list_config_color_grep_slots },\n+\t\t{ \"color.interactive\", \"<slot>\", list_config_color_interactive_slots },\n+\t\t{ \"color.remote\", \"<slot>\", list_config_color_sideband_slots },\n+\t\t{ \"color.status\", \"<slot>\", list_config_color_status_slots },\n+\t\t{ \"fsck\", \"<msg-id>\", list_config_fsck_msg_ids },\n+\t\t{ \"receive.fsck\", \"<msg-id>\", list_config_fsck_msg_ids },\n+\t\t{ NULL, NULL, NULL }\n+\t};\n+\tconst char **p;\n+\tstruct slot_expansion *e;\n+\tstruct string_list keys = STRING_LIST_INIT_DUP;\n+\tint i;\n+\n+\tfor (p = config_name_list; *p; p++) {\n+\t\tconst char *var = *p;\n+\t\tstruct strbuf sb = STRBUF_INIT;\n+\n+\t\tfor (e = slot_expansions; e->prefix; e++) {\n+\n+\t\t\tstrbuf_reset(&sb);\n+\t\t\tstrbuf_addf(&sb, \"%s.%s\", e->prefix, e->placeholder);\n+\t\t\tif (!strcasecmp(var, sb.buf)) {\n+\t\t\t\te->fn(&keys, e->prefix);\n+\t\t\t\te->found++;\n+\t\t\t\tbreak;\n+\t\t\t}\n+\t\t}\n+\t\tstrbuf_release(&sb);\n+\t\tif (!e->prefix)\n+\t\t\tstring_list_append(&keys, var);\n+\t}\n+\n+\tfor (e = slot_expansions; e->prefix; e++)\n+\t\tif (!e->found)\n+\t\t\tBUG(\"slot_expansion %s.%s is not used\",\n+\t\t\t    e->prefix, e->placeholder);\n+\n+\tstring_list_sort(&keys);\n+\tfor (i = 0; i < keys.nr; i++) {\n+\t\tconst char *var = keys.items[i].string;\n+\t\tconst char *wildcard, *tag, *cut;\n+\n+\t\tif (for_human) {\n+\t\t\tputs(var);\n+\t\t\tcontinue;\n+\t\t}\n+\n+\t\twildcard = strchr(var, '*');\n+\t\ttag = strchr(var, '<');\n+\n+\t\tif (!wildcard && !tag) {\n+\t\t\tputs(var);\n+\t\t\tcontinue;\n+\t\t}\n+\n+\t\tif (wildcard && !tag)\n+\t\t\tcut = wildcard;\n+\t\telse if (!wildcard && tag)\n+\t\t\tcut = tag;\n+\t\telse\n+\t\t\tcut = wildcard < tag ? wildcard : tag;\n+\n+\t\t/*\n+\t\t * We may produce duplicates, but that's up to\n+\t\t * git-completion.bash to handle\n+\t\t */\n+\t\tprintf(\"%.*s\\n\", (int)(cut - var), var);\n+\t}\n+\tstring_list_clear(&keys, 0);\n+}\n+\n static enum help_format parse_help_format(const char *format)\n {\n \tif (!strcmp(format, \"man\"))\ndiff --git a/generate-cmdlist.sh b/generate-cmdlist.sh\nindex 71158f7d8b..45fecf8bdf 100755\n--- a/generate-cmdlist.sh\n+++ b/generate-cmdlist.sh\n@@ -76,23 +76,6 @@ print_command_list () {\n \techo \"};\"\n }\n \n-print_config_list () {\n-\tcat <<EOF\n-static const char *config_name_list[] = {\n-EOF\n-\tgrep -h '^[a-zA-Z].*\\..*::$' Documentation/*config.txt Documentation/config/*.txt |\n-\tsed '/deprecated/d; s/::$//; s/,  */\\n/g' |\n-\tsort |\n-\twhile read line\n-\tdo\n-\t\techo \"\t\\\"$line\\\",\"\n-\tdone\n-\tcat <<EOF\n-\tNULL,\n-};\n-EOF\n-}\n-\n exclude_programs=\n while test \"--exclude-program\" = \"$1\"\n do\n@@ -113,5 +96,3 @@ echo\n define_category_names \"$1\"\n echo\n print_command_list \"$1\"\n-echo\n-print_config_list\ndiff --git a/generate-configlist.sh b/generate-configlist.sh\nnew file mode 100755\nindex 0000000000..8692fe5cf4\n--- /dev/null\n+++ b/generate-configlist.sh\n@@ -0,0 +1,21 @@\n+#!/bin/sh\n+\n+echo \"/* Automatically generated by generate-configlist.sh */\"\n+echo\n+\n+print_config_list () {\n+\tcat <<EOF\n+static const char *config_name_list[] = {\n+EOF\n+\tgrep -h '^[a-zA-Z].*\\..*::$' Documentation/*config.txt Documentation/config/*.txt |\n+\tsed '/deprecated/d; s/::$//; s/,  */\\n/g' |\n+\tsort |\n+\tsed 's/^.*$/\t\"&\",/'\n+\tcat <<EOF\n+\tNULL,\n+};\n+EOF\n+}\n+\n+echo\n+print_config_list\ndiff --git a/help.c b/help.c\nindex cf67624a94..a21487db77 100644\n--- a/help.c\n+++ b/help.c\n@@ -407,91 +407,6 @@ void list_common_guides_help(void)\n \tputchar('\\n');\n }\n \n-struct slot_expansion {\n-\tconst char *prefix;\n-\tconst char *placeholder;\n-\tvoid (*fn)(struct string_list *list, const char *prefix);\n-\tint found;\n-};\n-\n-void list_config_help(int for_human)\n-{\n-\tstruct slot_expansion slot_expansions[] = {\n-\t\t{ \"advice\", \"*\", list_config_advices },\n-\t\t{ \"color.branch\", \"<slot>\", list_config_color_branch_slots },\n-\t\t{ \"color.decorate\", \"<slot>\", list_config_color_decorate_slots },\n-\t\t{ \"color.diff\", \"<slot>\", list_config_color_diff_slots },\n-\t\t{ \"color.grep\", \"<slot>\", list_config_color_grep_slots },\n-\t\t{ \"color.interactive\", \"<slot>\", list_config_color_interactive_slots },\n-\t\t{ \"color.remote\", \"<slot>\", list_config_color_sideband_slots },\n-\t\t{ \"color.status\", \"<slot>\", list_config_color_status_slots },\n-\t\t{ \"fsck\", \"<msg-id>\", list_config_fsck_msg_ids },\n-\t\t{ \"receive.fsck\", \"<msg-id>\", list_config_fsck_msg_ids },\n-\t\t{ NULL, NULL, NULL }\n-\t};\n-\tconst char **p;\n-\tstruct slot_expansion *e;\n-\tstruct string_list keys = STRING_LIST_INIT_DUP;\n-\tint i;\n-\n-\tfor (p = config_name_list; *p; p++) {\n-\t\tconst char *var = *p;\n-\t\tstruct strbuf sb = STRBUF_INIT;\n-\n-\t\tfor (e = slot_expansions; e->prefix; e++) {\n-\n-\t\t\tstrbuf_reset(&sb);\n-\t\t\tstrbuf_addf(&sb, \"%s.%s\", e->prefix, e->placeholder);\n-\t\t\tif (!strcasecmp(var, sb.buf)) {\n-\t\t\t\te->fn(&keys, e->prefix);\n-\t\t\t\te->found++;\n-\t\t\t\tbreak;\n-\t\t\t}\n-\t\t}\n-\t\tstrbuf_release(&sb);\n-\t\tif (!e->prefix)\n-\t\t\tstring_list_append(&keys, var);\n-\t}\n-\n-\tfor (e = slot_expansions; e->prefix; e++)\n-\t\tif (!e->found)\n-\t\t\tBUG(\"slot_expansion %s.%s is not used\",\n-\t\t\t    e->prefix, e->placeholder);\n-\n-\tstring_list_sort(&keys);\n-\tfor (i = 0; i < keys.nr; i++) {\n-\t\tconst char *var = keys.items[i].string;\n-\t\tconst char *wildcard, *tag, *cut;\n-\n-\t\tif (for_human) {\n-\t\t\tputs(var);\n-\t\t\tcontinue;\n-\t\t}\n-\n-\t\twildcard = strchr(var, '*');\n-\t\ttag = strchr(var, '<');\n-\n-\t\tif (!wildcard && !tag) {\n-\t\t\tputs(var);\n-\t\t\tcontinue;\n-\t\t}\n-\n-\t\tif (wildcard && !tag)\n-\t\t\tcut = wildcard;\n-\t\telse if (!wildcard && tag)\n-\t\t\tcut = tag;\n-\t\telse\n-\t\t\tcut = wildcard < tag ? wildcard : tag;\n-\n-\t\t/*\n-\t\t * We may produce duplicates, but that's up to\n-\t\t * git-completion.bash to handle\n-\t\t */\n-\t\tprintf(\"%.*s\\n\", (int)(cut - var), var);\n-\t}\n-\tstring_list_clear(&keys, 0);\n-}\n-\n static int get_alias(const char *var, const char *value, void *data)\n {\n \tstruct string_list *list = data;\ndiff --git a/help.h b/help.h\nindex 7a455beeb7..9071894e8c 100644\n--- a/help.h\n+++ b/help.h\n@@ -22,7 +22,6 @@ static inline void mput_char(char c, unsigned int num)\n void list_common_cmds_help(void);\n void list_all_cmds_help(void);\n void list_common_guides_help(void);\n-void list_config_help(int for_human);\n \n void list_all_main_cmds(struct string_list *list);\n void list_all_other_cmds(struct string_list *list);\n-- \n2.26.0.292.g33ef6b2f38-goog\n\n"},{"id":"394887","messageId":"20200406224526.256074-3-emilyshaffer@google.com","threadId":"53075","inReplyTo":"20200406224526.256074-1-emilyshaffer@google.com","subject":"[PATCH v12 2/5] bugreport: add tool to generate debugging info","fromName":"Emily Shaffer","fromEmail":"emilyshaffer@google.com","sentAt":"2020-04-06T22:45:23Z","receivedAt":"2020-04-06T22:45:41Z","isPatch":true,"sender":{"key":"nasamuffin@google.com","avatar":"https://avatars.githubusercontent.com/u/1606826?v=4"},"body":"Teach Git how to prompt the user for a good bug report: reproduction\nsteps, expected behavior, and actual behavior. Later, Git can learn how\nto collect some diagnostic information from the repository.\n\nIf users can send us a well-written bug report which contains diagnostic\ninformation we would otherwise need to ask the user for, we can reduce\nthe number of question-and-answer round trips between the reporter and\nthe Git contributor.\n\nUsers may also wish to send a report like this to their local \"Git\nexpert\" if they have put their repository into a state they are confused\nby.\n\nSigned-off-by: Emily Shaffer <emilyshaffer@google.com>\n---\n .gitignore                      |   1 +\n Documentation/git-bugreport.txt |  46 ++++++++++++++\n Makefile                        |   5 ++\n bugreport.c                     | 105 ++++++++++++++++++++++++++++++++\n command-list.txt                |   1 +\n strbuf.c                        |   4 ++\n strbuf.h                        |   1 +\n t/t0091-bugreport.sh            |  61 +++++++++++++++++++\n 8 files changed, 224 insertions(+)\n create mode 100644 Documentation/git-bugreport.txt\n create mode 100644 bugreport.c\n create mode 100755 t/t0091-bugreport.sh\n\ndiff --git a/.gitignore b/.gitignore\nindex 61bf5142a9..ee509a2ad2 100644\n--- a/.gitignore\n+++ b/.gitignore\n@@ -25,6 +25,7 @@\n /git-bisect--helper\n /git-blame\n /git-branch\n+/git-bugreport\n /git-bundle\n /git-cat-file\n /git-check-attr\ndiff --git a/Documentation/git-bugreport.txt b/Documentation/git-bugreport.txt\nnew file mode 100644\nindex 0000000000..1f9fde5cde\n--- /dev/null\n+++ b/Documentation/git-bugreport.txt\n@@ -0,0 +1,46 @@\n+git-bugreport(1)\n+================\n+\n+NAME\n+----\n+git-bugreport - Collect information for user to file a bug report\n+\n+SYNOPSIS\n+--------\n+[verse]\n+'git bugreport' [(-o | --output-directory) <path>] [(-s | --suffix) <format>]\n+\n+DESCRIPTION\n+-----------\n+Captures information about the user's machine, Git client, and repository state,\n+as well as a form requesting information about the behavior the user observed,\n+into a single text file which the user can then share, for example to the Git\n+mailing list, in order to report an observed bug.\n+\n+The following information is requested from the user:\n+\n+ - Reproduction steps\n+ - Expected behavior\n+ - Actual behavior\n+\n+This tool is invoked via the typical Git setup process, which means that in some\n+cases, it might not be able to launch - for example, if a relevant config file\n+is unreadable. In this kind of scenario, it may be helpful to manually gather\n+the kind of information listed above when manually asking for help.\n+\n+OPTIONS\n+-------\n+-o <path>::\n+--output-directory <path>::\n+\tPlace the resulting bug report file in `<path>` instead of the root of\n+\tthe Git repository.\n+\n+-s <format>::\n+--suffix <format>::\n+\tSpecify an alternate suffix for the bugreport name, to create a file\n+\tnamed 'git-bugreport-<formatted suffix>'. This should take the form of a\n+\tlink:strftime[3] format string; the current local time will be used.\n+\n+GIT\n+---\n+Part of the linkgit:git[1] suite\ndiff --git a/Makefile b/Makefile\nindex d4aff7f9b5..b0a9073788 100644\n--- a/Makefile\n+++ b/Makefile\n@@ -680,6 +680,7 @@ EXTRA_PROGRAMS =\n # ... and all the rest that could be moved out of bindir to gitexecdir\n PROGRAMS += $(EXTRA_PROGRAMS)\n \n+PROGRAM_OBJS += bugreport.o\n PROGRAM_OBJS += credential-store.o\n PROGRAM_OBJS += daemon.o\n PROGRAM_OBJS += fast-import.o\n@@ -2462,6 +2463,10 @@ endif\n git-%$X: %.o GIT-LDFLAGS $(GITLIBS)\n \t$(QUIET_LINK)$(CC) $(ALL_CFLAGS) -o $@ $(ALL_LDFLAGS) $(filter %.o,$^) $(LIBS)\n \n+git-bugreport$X: bugreport.o GIT-LDFLAGS $(GITLIBS)\n+\t$(QUIET_LINK)$(CC) $(ALL_CFLAGS) -o $@ $(ALL_LDFLAGS) $(filter %.o,$^) \\\n+\t\t$(LIBS)\n+\n git-imap-send$X: imap-send.o $(IMAP_SEND_BUILDDEPS) GIT-LDFLAGS $(GITLIBS)\n \t$(QUIET_LINK)$(CC) $(ALL_CFLAGS) -o $@ $(ALL_LDFLAGS) $(filter %.o,$^) \\\n \t\t$(IMAP_SEND_LDFLAGS) $(LIBS)\ndiff --git a/bugreport.c b/bugreport.c\nnew file mode 100644\nindex 0000000000..f6f53a5e8e\n--- /dev/null\n+++ b/bugreport.c\n@@ -0,0 +1,105 @@\n+#include \"builtin.h\"\n+#include \"parse-options.h\"\n+#include \"stdio.h\"\n+#include \"strbuf.h\"\n+#include \"time.h\"\n+\n+static const char * const bugreport_usage[] = {\n+\tN_(\"git bugreport [-o|--output-directory <file>] [-s|--suffix <format>]\"),\n+\tNULL\n+};\n+\n+static int get_bug_template(struct strbuf *template)\n+{\n+\tconst char template_text[] = N_(\n+\"Thank you for filling out a Git bug report!\\n\"\n+\"Please answer the following questions to help us understand your issue.\\n\"\n+\"\\n\"\n+\"What did you do before the bug happened? (Steps to reproduce your issue)\\n\"\n+\"\\n\"\n+\"What did you expect to happen? (Expected behavior)\\n\"\n+\"\\n\"\n+\"What happened instead? (Actual behavior)\\n\"\n+\"\\n\"\n+\"What's different between what you expected and what actually happened?\\n\"\n+\"\\n\"\n+\"Anything else you want to add:\\n\"\n+\"\\n\"\n+\"Please review the rest of the bug report below.\\n\"\n+\"You can delete any lines you don't wish to share.\\n\");\n+\n+\tstrbuf_addstr(template, _(template_text));\n+\treturn 0;\n+}\n+\n+int cmd_main(int argc, const char **argv)\n+{\n+\tstruct strbuf buffer = STRBUF_INIT;\n+\tstruct strbuf report_path = STRBUF_INIT;\n+\tint report = -1;\n+\ttime_t now = time(NULL);\n+\tchar *option_output = NULL;\n+\tchar *option_suffix = \"%Y-%m-%d-%H%M\";\n+\tint nongit_ok = 0;\n+\tconst char *prefix = NULL;\n+\tconst char *user_relative_path = NULL;\n+\n+\tconst struct option bugreport_options[] = {\n+\t\tOPT_STRING('o', \"output-directory\", &option_output, N_(\"path\"),\n+\t\t\t   N_(\"specify a destination for the bugreport file\")),\n+\t\tOPT_STRING('s', \"suffix\", &option_suffix, N_(\"format\"),\n+\t\t\t   N_(\"specify a strftime format suffix for the filename\")),\n+\t\tOPT_END()\n+\t};\n+\n+\tprefix = setup_git_directory_gently(&nongit_ok);\n+\n+\targc = parse_options(argc, argv, prefix, bugreport_options,\n+\t\t\t     bugreport_usage, 0);\n+\n+\t/* Prepare the path to put the result */\n+\tstrbuf_addstr(&report_path,\n+\t\t      prefix_filename(prefix,\n+\t\t\t\t      option_output ? option_output : \"\"));\n+\tstrbuf_complete(&report_path, '/');\n+\n+\tstrbuf_addstr(&report_path, \"git-bugreport-\");\n+\tstrbuf_addftime(&report_path, option_suffix, localtime(&now), 0, 0);\n+\tstrbuf_addstr(&report_path, \".txt\");\n+\n+\tswitch (safe_create_leading_directories(report_path.buf)) {\n+\tcase SCLD_OK:\n+\tcase SCLD_EXISTS:\n+\t\tbreak;\n+\tdefault:\n+\t\tdie(_(\"could not create leading directories for '%s'\"),\n+\t\t    report_path.buf);\n+\t}\n+\n+\t/* Prepare the report contents */\n+\tget_bug_template(&buffer);\n+\n+\t/* fopen doesn't offer us an O_EXCL alternative, except with glibc. */\n+\treport = open(report_path.buf, O_CREAT | O_EXCL | O_WRONLY, 0666);\n+\n+\tif (report < 0) {\n+\t\tUNLEAK(report_path);\n+\t\tdie(_(\"couldn't create a new file at '%s'\"), report_path.buf);\n+\t}\n+\n+\tstrbuf_write_fd(&buffer, report);\n+\tclose(report);\n+\n+\t/*\n+\t * We want to print the path relative to the user, but we still need the\n+\t * path relative to us to give to the editor.\n+\t */\n+\tif (!(prefix && skip_prefix(report_path.buf, prefix, &user_relative_path)))\n+\t\tuser_relative_path = report_path.buf;\n+\tfprintf(stderr, _(\"Created new report at '%s'.\\n\"),\n+\t\tuser_relative_path);\n+\n+\tUNLEAK(buffer);\n+\tUNLEAK(report_path);\n+\treturn !!launch_editor(report_path.buf, NULL, NULL);\n+}\ndiff --git a/command-list.txt b/command-list.txt\nindex 2087894655..185e5e3f05 100644\n--- a/command-list.txt\n+++ b/command-list.txt\n@@ -54,6 +54,7 @@ git-archive                             mainporcelain\n git-bisect                              mainporcelain           info\n git-blame                               ancillaryinterrogators          complete\n git-branch                              mainporcelain           history\n+git-bugreport                           ancillaryinterrogators\n git-bundle                              mainporcelain\n git-cat-file                            plumbinginterrogators\n git-check-attr                          purehelpers\ndiff --git a/strbuf.c b/strbuf.c\nindex bb0065ccaf..3bfcaababb 100644\n--- a/strbuf.c\n+++ b/strbuf.c\n@@ -554,6 +554,10 @@ ssize_t strbuf_write(struct strbuf *sb, FILE *f)\n \treturn sb->len ? fwrite(sb->buf, 1, sb->len, f) : 0;\n }\n \n+ssize_t strbuf_write_fd(struct strbuf *sb, int fd)\n+{\n+\treturn sb->len ? write(fd, sb->buf, sb->len) : 0;\n+}\n \n #define STRBUF_MAXLINK (2*PATH_MAX)\n \ndiff --git a/strbuf.h b/strbuf.h\nindex ce8e49c0b2..801a3694ec 100644\n--- a/strbuf.h\n+++ b/strbuf.h\n@@ -468,6 +468,7 @@ int strbuf_readlink(struct strbuf *sb, const char *path, size_t hint);\n  * NUL bytes.\n  */\n ssize_t strbuf_write(struct strbuf *sb, FILE *stream);\n+ssize_t strbuf_write_fd(struct strbuf *sb, int fd);\n \n /**\n  * Read a line from a FILE *, overwriting the existing contents of\ndiff --git a/t/t0091-bugreport.sh b/t/t0091-bugreport.sh\nnew file mode 100755\nindex 0000000000..2e73658a5c\n--- /dev/null\n+++ b/t/t0091-bugreport.sh\n@@ -0,0 +1,61 @@\n+#!/bin/sh\n+\n+test_description='git bugreport'\n+\n+. ./test-lib.sh\n+\n+# Headers \"[System Info]\" will be followed by a non-empty line if we put some\n+# information there; we can make sure all our headers were followed by some\n+# information to check if the command was successful.\n+HEADER_PATTERN=\"^\\[.*\\]$\"\n+\n+check_all_headers_populated () {\n+\twhile read -r line\n+\tdo\n+\t\tif test \"$(grep \"$HEADER_PATTERN\" \"$line\")\"\n+\t\tthen\n+\t\t\techo \"$line\"\n+\t\t\tread -r nextline\n+\t\t\tif test -z \"$nextline\"; then\n+\t\t\t\treturn 1;\n+\t\t\tfi\n+\t\tfi\n+\tdone\n+}\n+\n+test_expect_success 'creates a report with content in the right places' '\n+\ttest_when_finished rm git-bugreport-check-headers.txt &&\n+\tgit bugreport -s check-headers &&\n+\tcheck_all_headers_populated <git-bugreport-check-headers.txt\n+'\n+\n+test_expect_success 'dies if file with same name as report already exists' '\n+\ttest_when_finished rm git-bugreport-duplicate.txt &&\n+\t>>git-bugreport-duplicate.txt &&\n+\ttest_must_fail git bugreport --suffix duplicate\n+'\n+\n+test_expect_success '--output-directory puts the report in the provided dir' '\n+\ttest_when_finished rm -fr foo/ &&\n+\tgit bugreport -o foo/ &&\n+\ttest_path_is_file foo/git-bugreport-*\n+'\n+\n+test_expect_success 'incorrect arguments abort with usage' '\n+\ttest_must_fail git bugreport --false 2>output &&\n+\ttest_i18ngrep usage output &&\n+\ttest_path_is_missing git-bugreport-*\n+'\n+\n+test_expect_success 'runs outside of a git dir' '\n+\ttest_when_finished rm non-repo/git-bugreport-* &&\n+\tnongit git bugreport\n+'\n+\n+test_expect_success 'can create leading directories outside of a git dir' '\n+\ttest_when_finished rm -fr foo/bar/baz &&\n+\tnongit git bugreport -o foo/bar/baz\n+'\n+\n+\n+test_done\n-- \n2.26.0.292.g33ef6b2f38-goog\n\n"},{"id":"394888","messageId":"20200406224526.256074-4-emilyshaffer@google.com","threadId":"53075","inReplyTo":"20200406224526.256074-1-emilyshaffer@google.com","subject":"[PATCH v12 3/5] bugreport: gather git version and build info","fromName":"Emily Shaffer","fromEmail":"emilyshaffer@google.com","sentAt":"2020-04-06T22:45:24Z","receivedAt":"2020-04-06T22:45:45Z","isPatch":true,"sender":{"key":"nasamuffin@google.com","avatar":"https://avatars.githubusercontent.com/u/1606826?v=4"},"body":"Knowing which version of Git a user has and how it was built allows us\nto more precisely pin down the circumstances when a certain issue\noccurs, so teach bugreport how to tell us the same output as 'git\nversion --build-options'.\n\nIt's not ideal to directly call 'git version --build-options' because\nthat output goes to stdout. Instead, wrap the version string in a helper\nwithin help.[ch] library, and call that helper from within the bugreport\nlibrary.\n\nSigned-off-by: Emily Shaffer <emilyshaffer@google.com>\n---\n Documentation/git-bugreport.txt |  4 +++\n bugreport.c                     | 19 +++++++++++++-\n help.c                          | 46 ++++++++++++++++++++-------------\n help.h                          |  1 +\n 4 files changed, 51 insertions(+), 19 deletions(-)\n\ndiff --git a/Documentation/git-bugreport.txt b/Documentation/git-bugreport.txt\nindex 1f9fde5cde..f44ae8cbe7 100644\n--- a/Documentation/git-bugreport.txt\n+++ b/Documentation/git-bugreport.txt\n@@ -23,6 +23,10 @@ The following information is requested from the user:\n  - Expected behavior\n  - Actual behavior\n \n+The following information is captured automatically:\n+\n+ - 'git version --build-options'\n+\n This tool is invoked via the typical Git setup process, which means that in some\n cases, it might not be able to launch - for example, if a relevant config file\n is unreadable. In this kind of scenario, it may be helpful to manually gather\ndiff --git a/bugreport.c b/bugreport.c\nindex f6f53a5e8e..4cdb58bbaa 100644\n--- a/bugreport.c\n+++ b/bugreport.c\n@@ -1,8 +1,17 @@\n-#include \"builtin.h\"\n+#include \"cache.h\"\n #include \"parse-options.h\"\n #include \"stdio.h\"\n #include \"strbuf.h\"\n #include \"time.h\"\n+#include \"help.h\"\n+\n+static void get_system_info(struct strbuf *sys_info)\n+{\n+\t/* get git version from native cmd */\n+\tstrbuf_addstr(sys_info, _(\"git version:\\n\"));\n+\tget_version_info(sys_info, 1);\n+\tstrbuf_complete_line(sys_info);\n+}\n \n static const char * const bugreport_usage[] = {\n \tN_(\"git bugreport [-o|--output-directory <file>] [-s|--suffix <format>]\"),\n@@ -32,6 +41,11 @@ static int get_bug_template(struct strbuf *template)\n \treturn 0;\n }\n \n+static void get_header(struct strbuf *buf, const char *title)\n+{\n+\tstrbuf_addf(buf, \"\\n\\n[%s]\\n\", title);\n+}\n+\n int cmd_main(int argc, const char **argv)\n {\n \tstruct strbuf buffer = STRBUF_INIT;\n@@ -79,6 +93,9 @@ int cmd_main(int argc, const char **argv)\n \t/* Prepare the report contents */\n \tget_bug_template(&buffer);\n \n+\tget_header(&buffer, _(\"System Info\"));\n+\tget_system_info(&buffer);\n+\n \t/* fopen doesn't offer us an O_EXCL alternative, except with glibc. */\n \treport = open(report_path.buf, O_CREAT | O_EXCL | O_WRONLY, 0666);\n \ndiff --git a/help.c b/help.c\nindex a21487db77..1de9c0d589 100644\n--- a/help.c\n+++ b/help.c\n@@ -622,8 +622,32 @@ const char *help_unknown_cmd(const char *cmd)\n \texit(1);\n }\n \n+void get_version_info(struct strbuf *buf, int show_build_options)\n+{\n+\t/*\n+\t * The format of this string should be kept stable for compatibility\n+\t * with external projects that rely on the output of \"git version\".\n+\t *\n+\t * Always show the version, even if other options are given.\n+\t */\n+\tstrbuf_addf(buf, \"git version %s\\n\", git_version_string);\n+\n+\tif (show_build_options) {\n+\t\tstrbuf_addf(buf, \"cpu: %s\\n\", GIT_HOST_CPU);\n+\t\tif (git_built_from_commit_string[0])\n+\t\t\tstrbuf_addf(buf, \"built from commit: %s\\n\",\n+\t\t\t       git_built_from_commit_string);\n+\t\telse\n+\t\t\tstrbuf_addstr(buf, \"no commit associated with this build\\n\");\n+\t\tstrbuf_addf(buf, \"sizeof-long: %d\\n\", (int)sizeof(long));\n+\t\tstrbuf_addf(buf, \"sizeof-size_t: %d\\n\", (int)sizeof(size_t));\n+\t\t/* NEEDSWORK: also save and output GIT-BUILD_OPTIONS? */\n+\t}\n+}\n+\n int cmd_version(int argc, const char **argv, const char *prefix)\n {\n+\tstruct strbuf buf = STRBUF_INIT;\n \tint build_options = 0;\n \tconst char * const usage[] = {\n \t\tN_(\"git version [<options>]\"),\n@@ -637,25 +661,11 @@ int cmd_version(int argc, const char **argv, const char *prefix)\n \n \targc = parse_options(argc, argv, prefix, options, usage, 0);\n \n-\t/*\n-\t * The format of this string should be kept stable for compatibility\n-\t * with external projects that rely on the output of \"git version\".\n-\t *\n-\t * Always show the version, even if other options are given.\n-\t */\n-\tprintf(\"git version %s\\n\", git_version_string);\n+\tget_version_info(&buf, build_options);\n+\tprintf(\"%s\", buf.buf);\n+\n+\tstrbuf_release(&buf);\n \n-\tif (build_options) {\n-\t\tprintf(\"cpu: %s\\n\", GIT_HOST_CPU);\n-\t\tif (git_built_from_commit_string[0])\n-\t\t\tprintf(\"built from commit: %s\\n\",\n-\t\t\t       git_built_from_commit_string);\n-\t\telse\n-\t\t\tprintf(\"no commit associated with this build\\n\");\n-\t\tprintf(\"sizeof-long: %d\\n\", (int)sizeof(long));\n-\t\tprintf(\"sizeof-size_t: %d\\n\", (int)sizeof(size_t));\n-\t\t/* NEEDSWORK: also save and output GIT-BUILD_OPTIONS? */\n-\t}\n \treturn 0;\n }\n \ndiff --git a/help.h b/help.h\nindex 9071894e8c..500521b908 100644\n--- a/help.h\n+++ b/help.h\n@@ -37,6 +37,7 @@ void add_cmdname(struct cmdnames *cmds, const char *name, int len);\n void exclude_cmds(struct cmdnames *cmds, struct cmdnames *excludes);\n int is_in_cmdlist(struct cmdnames *cmds, const char *name);\n void list_commands(unsigned int colopts, struct cmdnames *main_cmds, struct cmdnames *other_cmds);\n+void get_version_info(struct strbuf *buf, int show_build_options);\n \n /*\n  * call this to die(), when it is suspected that the user mistyped a\n-- \n2.26.0.292.g33ef6b2f38-goog\n\n"},{"id":"394889","messageId":"20200406224526.256074-5-emilyshaffer@google.com","threadId":"53075","inReplyTo":"20200406224526.256074-1-emilyshaffer@google.com","subject":"[PATCH v12 4/5] bugreport: add uname info","fromName":"Emily Shaffer","fromEmail":"emilyshaffer@google.com","sentAt":"2020-04-06T22:45:25Z","receivedAt":"2020-04-06T22:45:46Z","isPatch":true,"sender":{"key":"nasamuffin@google.com","avatar":"https://avatars.githubusercontent.com/u/1606826?v=4"},"body":"The contents of uname() can give us some insight into what sort of\nsystem the user is running on, and help us replicate their setup if need\nbe. The domainname field is not guaranteed to be available, so don't\ncollect it.\n\nSigned-off-by: Emily Shaffer <emilyshaffer@google.com>\n---\n Documentation/git-bugreport.txt |  1 +\n bugreport.c                     | 16 +++++++++++++++-\n 2 files changed, 16 insertions(+), 1 deletion(-)\n\ndiff --git a/Documentation/git-bugreport.txt b/Documentation/git-bugreport.txt\nindex f44ae8cbe7..17b0d14e8d 100644\n--- a/Documentation/git-bugreport.txt\n+++ b/Documentation/git-bugreport.txt\n@@ -26,6 +26,7 @@ The following information is requested from the user:\n The following information is captured automatically:\n \n  - 'git version --build-options'\n+ - uname sysname, release, version, and machine strings\n \n This tool is invoked via the typical Git setup process, which means that in some\n cases, it might not be able to launch - for example, if a relevant config file\ndiff --git a/bugreport.c b/bugreport.c\nindex 4cdb58bbaa..1a3172bcec 100644\n--- a/bugreport.c\n+++ b/bugreport.c\n@@ -7,10 +7,24 @@\n \n static void get_system_info(struct strbuf *sys_info)\n {\n+\tstruct utsname uname_info;\n+\n \t/* get git version from native cmd */\n \tstrbuf_addstr(sys_info, _(\"git version:\\n\"));\n \tget_version_info(sys_info, 1);\n-\tstrbuf_complete_line(sys_info);\n+\n+\t/* system call for other version info */\n+\tstrbuf_addstr(sys_info, \"uname: \");\n+\tif (uname(&uname_info))\n+\t\tstrbuf_addf(sys_info, _(\"uname() failed with error '%s' (%d)\\n\"),\n+\t\t\t    strerror(errno),\n+\t\t\t    errno);\n+\telse\n+\t\tstrbuf_addf(sys_info, \"%s %s %s %s\\n\",\n+\t\t\t    uname_info.sysname,\n+\t\t\t    uname_info.release,\n+\t\t\t    uname_info.version,\n+\t\t\t    uname_info.machine);\n }\n \n static const char * const bugreport_usage[] = {\n-- \n2.26.0.292.g33ef6b2f38-goog\n\n"},{"id":"394890","messageId":"20200406224526.256074-6-emilyshaffer@google.com","threadId":"53075","inReplyTo":"20200406224526.256074-1-emilyshaffer@google.com","subject":"[PATCH v12 5/5] bugreport: add compiler info","fromName":"Emily Shaffer","fromEmail":"emilyshaffer@google.com","sentAt":"2020-04-06T22:45:26Z","receivedAt":"2020-04-06T22:45:49Z","isPatch":true,"sender":{"key":"nasamuffin@google.com","avatar":"https://avatars.githubusercontent.com/u/1606826?v=4"},"body":"To help pinpoint the source of a regression, it is useful to know some\ninfo about the compiler which the user's Git client was built with. By\nadding a generic get_compiler_info() in 'compat/' we can choose which\nrelevant information to share per compiler; to get started, let's\ndemonstrate the version of glibc if the user built with 'gcc'.\n\nSigned-off-by: Emily Shaffer <emilyshaffer@google.com>\nHelped-by: Danh Doan <congdanhqx@gmail.com>\nHelped-by: Johannes Schindelin <Johannes.Schindelin@gmx.de>\n---\n Documentation/git-bugreport.txt |  1 +\n bugreport.c                     |  6 +++++\n compat/compiler.h               | 41 +++++++++++++++++++++++++++++++++\n 3 files changed, 48 insertions(+)\n create mode 100644 compat/compiler.h\n\ndiff --git a/Documentation/git-bugreport.txt b/Documentation/git-bugreport.txt\nindex 17b0d14e8d..643d1b2884 100644\n--- a/Documentation/git-bugreport.txt\n+++ b/Documentation/git-bugreport.txt\n@@ -27,6 +27,7 @@ The following information is captured automatically:\n \n  - 'git version --build-options'\n  - uname sysname, release, version, and machine strings\n+ - Compiler-specific info string\n \n This tool is invoked via the typical Git setup process, which means that in some\n cases, it might not be able to launch - for example, if a relevant config file\ndiff --git a/bugreport.c b/bugreport.c\nindex 1a3172bcec..089b939a87 100644\n--- a/bugreport.c\n+++ b/bugreport.c\n@@ -4,6 +4,7 @@\n #include \"strbuf.h\"\n #include \"time.h\"\n #include \"help.h\"\n+#include \"compat/compiler.h\"\n \n static void get_system_info(struct strbuf *sys_info)\n {\n@@ -25,6 +26,11 @@ static void get_system_info(struct strbuf *sys_info)\n \t\t\t    uname_info.release,\n \t\t\t    uname_info.version,\n \t\t\t    uname_info.machine);\n+\n+\tstrbuf_addstr(sys_info, _(\"compiler info: \"));\n+\tget_compiler_info(sys_info);\n+\tstrbuf_addstr(sys_info, _(\"libc info: \"));\n+\tget_libc_info(sys_info);\n }\n \n static const char * const bugreport_usage[] = {\ndiff --git a/compat/compiler.h b/compat/compiler.h\nnew file mode 100644\nindex 0000000000..10dbb65937\n--- /dev/null\n+++ b/compat/compiler.h\n@@ -0,0 +1,41 @@\n+#ifndef COMPILER_H\n+#define COMPILER_H\n+\n+#include \"git-compat-util.h\"\n+#include \"strbuf.h\"\n+\n+#ifdef __GLIBC__\n+#include <gnu/libc-version.h>\n+#endif\n+\n+static inline void get_compiler_info(struct strbuf *info)\n+{\n+\tint len = info->len;\n+#ifdef __clang__\n+\tstrbuf_addf(info, \"clang: %s\\n\", __clang_version__);\n+#elif defined(__GNUC__)\n+\tstrbuf_addf(info, \"gnuc: %d.%d\\n\", __GNUC__, __GNUC_MINOR__);\n+#endif\n+\n+#ifdef _MSC_VER\n+\tstrbuf_addf(info, \"MSVC version: %02d.%02d.%05d\\n\",\n+\t\t    _MSC_VER / 100, _MSC_VER % 100, _MSC_FULL_VER % 100000);\n+#endif\n+\n+\tif (len == info->len)\n+\t\tstrbuf_addstr(info, _(\"no compiler information available\\n\"));\n+}\n+\n+static inline void get_libc_info(struct strbuf *info)\n+{\n+\tint len = info->len;\n+\n+#ifdef __GLIBC__\n+\tstrbuf_addf(info, \"glibc: %s\\n\", gnu_get_libc_version());\n+#endif\n+\n+\tif (len == info->len)\n+\t\tstrbuf_addstr(info, _(\"no libc information available\\n\"));\n+}\n+\n+#endif /* COMPILER_H */\n-- \n2.26.0.292.g33ef6b2f38-goog\n\n"},{"id":"394891","messageId":"xmqqimicusfv.fsf@gitster.c.googlers.com","threadId":"53075","inReplyTo":"20200406224526.256074-2-emilyshaffer@google.com","subject":"Re: [PATCH v12 1/5] help: move list_config_help to builtin/help","fromName":"Junio C Hamano","fromEmail":"gitster@pobox.com","sentAt":"2020-04-06T23:04:36Z","receivedAt":"2020-04-06T23:04:39Z","isPatch":true,"sender":{"key":"gitster@pobox.com","avatar":"https://avatars.githubusercontent.com/u/54884?v=4"},"body":"Emily Shaffer <emilyshaffer@google.com> writes:\n\n> Starting in 3ac68a93fd2, help.o began to depend on builtin/branch.o,\n> builtin/clean.o, and builtin/config.o. This meant that help.o was\n> unusable outside of the context of the main Git executable.\n\nQuite straight-forward.  Thanks for the clean-up.\n"},{"id":"394892","messageId":"xmqqeet0urts.fsf@gitster.c.googlers.com","threadId":"53075","inReplyTo":"20200406224526.256074-4-emilyshaffer@google.com","subject":"Re: [PATCH v12 3/5] bugreport: gather git version and build info","fromName":"Junio C Hamano","fromEmail":"gitster@pobox.com","sentAt":"2020-04-06T23:17:51Z","receivedAt":"2020-04-06T23:17:56Z","isPatch":true,"sender":{"key":"gitster@pobox.com","avatar":"https://avatars.githubusercontent.com/u/54884?v=4"},"body":"Emily Shaffer <emilyshaffer@google.com> writes:\n\n> It's not ideal to directly call 'git version --build-options' because\n> that output goes to stdout. Instead, wrap the version string in a helper\n> within help.[ch] library, and call that helper from within the bugreport\n> library.\n\nThis means that \"git-bugreport\" that can be a different binary from\nsay \"git-remote-curl\" (or \"git-version\" for that matter) would still\nreport whatever version string that was compiled into \"bugreport\".\n\nReporting the version of \"bugreport\" is *not* useless, and what this\nstep adds to the report is good.  \n\nBut the version number of \"bugreport\" may not have much to do with\nthe binary the end user is having trouble with, so we'd also want\nthe version of the main part of \"git\", and other standalone \"git\"\nsubprograms like \"git-remote-curl\", reported separately, probably\ntogether with $PATH, $GIT_EXEC_PATH and what appears in the\ndirectories listed on these environment variables.\n\nIf \"git version --build-options\" writes to its standard output\nstream, that is a good thing, as it makes it easy to spawn and read\nwhat it says via the run_command() API, and there is one less thing\nto worry about (it would be a bit more cumbersome if the output goes\nto the standard error stream).\n\nAs \"git-remote-curl\" would also be a separate binary, we'd have to\nuse the same technique to report version number (and perhaps curl's\nlibrary version and its configuration?), perhaps by teaching the\nsubcommand a new option to dump such details to its standard output.\n\nUsing the same technique to report the version about the \"git\"\nitself would be consistent thing to do, as a preparation for future\nsteps that reports the details about \"git-remote-curl\".\n\nThanks.\n"},{"id":"394893","messageId":"xmqqa73ourp7.fsf@gitster.c.googlers.com","threadId":"53075","inReplyTo":"20200406224526.256074-5-emilyshaffer@google.com","subject":"Re: [PATCH v12 4/5] bugreport: add uname info","fromName":"Junio C Hamano","fromEmail":"gitster@pobox.com","sentAt":"2020-04-06T23:20:36Z","receivedAt":"2020-04-06T23:20:44Z","isPatch":true,"sender":{"key":"gitster@pobox.com","avatar":"https://avatars.githubusercontent.com/u/54884?v=4"},"body":"Emily Shaffer <emilyshaffer@google.com> writes:\n\n> The contents of uname() can give us some insight into what sort of\n> system the user is running on, and help us replicate their setup if need\n> be. The domainname field is not guaranteed to be available, so don't\n> collect it.\n\nUnlike \"what's the verison of 'git'?\" and \"with what versions of\nwhich libraries does the 'git' the user is having trouble with links\nwith?\" I mentioned earlier in my review of [3/5], what this step\ndeals with, i.e. \"what are these properties of the running system?\",\nis perfectly good to report from \"git bugreport\" itself.\n\nLooking good.\n\nThanks.\n\n\n>\n> Signed-off-by: Emily Shaffer <emilyshaffer@google.com>\n> ---\n>  Documentation/git-bugreport.txt |  1 +\n>  bugreport.c                     | 16 +++++++++++++++-\n>  2 files changed, 16 insertions(+), 1 deletion(-)\n>\n> diff --git a/Documentation/git-bugreport.txt b/Documentation/git-bugreport.txt\n> index f44ae8cbe7..17b0d14e8d 100644\n> --- a/Documentation/git-bugreport.txt\n> +++ b/Documentation/git-bugreport.txt\n> @@ -26,6 +26,7 @@ The following information is requested from the user:\n>  The following information is captured automatically:\n>  \n>   - 'git version --build-options'\n> + - uname sysname, release, version, and machine strings\n>  \n>  This tool is invoked via the typical Git setup process, which means that in some\n>  cases, it might not be able to launch - for example, if a relevant config file\n> diff --git a/bugreport.c b/bugreport.c\n> index 4cdb58bbaa..1a3172bcec 100644\n> --- a/bugreport.c\n> +++ b/bugreport.c\n> @@ -7,10 +7,24 @@\n>  \n>  static void get_system_info(struct strbuf *sys_info)\n>  {\n> +\tstruct utsname uname_info;\n> +\n>  \t/* get git version from native cmd */\n>  \tstrbuf_addstr(sys_info, _(\"git version:\\n\"));\n>  \tget_version_info(sys_info, 1);\n> -\tstrbuf_complete_line(sys_info);\n> +\n> +\t/* system call for other version info */\n> +\tstrbuf_addstr(sys_info, \"uname: \");\n> +\tif (uname(&uname_info))\n> +\t\tstrbuf_addf(sys_info, _(\"uname() failed with error '%s' (%d)\\n\"),\n> +\t\t\t    strerror(errno),\n> +\t\t\t    errno);\n> +\telse\n> +\t\tstrbuf_addf(sys_info, \"%s %s %s %s\\n\",\n> +\t\t\t    uname_info.sysname,\n> +\t\t\t    uname_info.release,\n> +\t\t\t    uname_info.version,\n> +\t\t\t    uname_info.machine);\n>  }\n>  \n>  static const char * const bugreport_usage[] = {\n"},{"id":"394894","messageId":"xmqq5zecur7l.fsf@gitster.c.googlers.com","threadId":"53075","inReplyTo":"20200406224526.256074-6-emilyshaffer@google.com","subject":"Re: [PATCH v12 5/5] bugreport: add compiler info","fromName":"Junio C Hamano","fromEmail":"gitster@pobox.com","sentAt":"2020-04-06T23:31:10Z","receivedAt":"2020-04-06T23:31:14Z","isPatch":true,"sender":{"key":"gitster@pobox.com","avatar":"https://avatars.githubusercontent.com/u/54884?v=4"},"body":"Emily Shaffer <emilyshaffer@google.com> writes:\n\n> To help pinpoint the source of a regression, it is useful to know some\n> info about the compiler which the user's Git client was built with. By\n> adding a generic get_compiler_info() in 'compat/' we can choose which\n> relevant information to share per compiler; to get started, let's\n> demonstrate the version of glibc if the user built with 'gcc'.\n\nThis one is not about \"what system are we running on\", but more\nabout \"how were the various pieces of Git binaries the user has\ntrouble running built?\".  While it may be useful to learn how \"git\nbugreport\" was compiled, the same question about the other binaries\nof Git (e.g. \"git\" itself, or \"git ls-files\" that is builtin) may\nhave different answers.  It should be fairly trivial to teach the\n\"git\" binaries (i.e. \"git\" itself plus builtins, and standalone\nsubcommands like \"git-remote-curl\" and \"git-bugreport\") to report\nhow they were built (e.g. with what library and compiler) by calling\nthe helpers you added in [3/5] and [5/5] and once that is done, it\nwould be straight-forward to teach \"git bugreport\" to collect\nproperties of them by invoking them and reading their output via the\nrun_command() interface, as I mentioned in my review on [3/5]\nearlire.\n\nThanks.\n\n"},{"id":"394896","messageId":"20200406234738.GA2568@danh.dev","threadId":"53075","inReplyTo":"20200406224526.256074-6-emilyshaffer@google.com","subject":"Re: [PATCH v12 5/5] bugreport: add compiler info","fromName":"Danh Doan","fromEmail":"congdanhqx@gmail.com","sentAt":"2020-04-06T23:47:38Z","receivedAt":"2020-04-06T23:47:43Z","isPatch":true,"sender":{"key":"congdanhqx@gmail.com","avatar":"https://avatars.githubusercontent.com/u/42673067?v=4"},"body":"On 2020-04-06 15:45:26-0700, Emily Shaffer <emilyshaffer@google.com> wrote:\n> Helped-by: Danh Doan <congdanhqx@gmail.com>\n\nIf you ever send another version of this series, my Git identity is:\n\nĐoàn Trần Công Danh <congdanhqx@gmail.com>\n\nThanks,\n\n-- \nDanh\n"},{"id":"394963","messageId":"xmqqpncjtjsh.fsf@gitster.c.googlers.com","threadId":"53075","inReplyTo":"20200406234738.GA2568@danh.dev","subject":"Re: [PATCH v12 5/5] bugreport: add compiler info","fromName":"Junio C Hamano","fromEmail":"gitster@pobox.com","sentAt":"2020-04-07T15:09:02Z","receivedAt":"2020-04-07T15:09:08Z","isPatch":true,"sender":{"key":"gitster@pobox.com","avatar":"https://avatars.githubusercontent.com/u/54884?v=4"},"body":"Danh Doan <congdanhqx@gmail.com> writes:\n\n> On 2020-04-06 15:45:26-0700, Emily Shaffer <emilyshaffer@google.com> wrote:\n>> Helped-by: Danh Doan <congdanhqx@gmail.com>\n>\n> If you ever send another version of this series, my Git identity is:\n>\n> Đoàn Trần Công Danh <congdanhqx@gmail.com>\n>\n> Thanks,\n\nThanks.\n\n"},{"id":"394968","messageId":"xmqqlfn7tj3d.fsf@gitster.c.googlers.com","threadId":"53075","inReplyTo":"20200406224526.256074-1-emilyshaffer@google.com","subject":"Re: [PATCH v12 0/5] bugreport: add tool to generate debugging info","fromName":"Junio C Hamano","fromEmail":"gitster@pobox.com","sentAt":"2020-04-07T15:24:06Z","receivedAt":"2020-04-07T15:24:11Z","isPatch":true,"sender":{"key":"gitster@pobox.com","avatar":"https://avatars.githubusercontent.com/u/54884?v=4"},"body":"Emily Shaffer <emilyshaffer@google.com> writes:\n\n> Since v11, reordered tests per SZEDER's comment so that the\n> test_when_finished lines come first in each test.\n>\n> Emily Shaffer (5):\n>   help: move list_config_help to builtin/help\n>   bugreport: add tool to generate debugging info\n>   bugreport: gather git version and build info\n>   bugreport: add uname info\n>   bugreport: add compiler info\n\nOverall it was a pleasnt read.\n\nJust to avoid misunderstanding, those comments in which I envisioned\na way to report versions and attributes on different parts of \"git\"\n(and I expect we'd be reporting versions and add-ons to tools like\n'wish' that runs gitk and git-gui, 'perl' and 'python' in a similar\nway---by finding them on the $PATH and asking them who they are) are\nNOT \"without these, the bugreport tool would not be useful\", but \"we\nwill in time need these, so let's keep them in mind\" issues [*1*].\n\nSo, I am hoping that this is ready to move to 'next'.\n\nThanks.\n\n\n[Footnote]\n\n*1* What we saw here in the review showed us a very good starting\npoint to report the version of the source one binary was built from,\nand the compiler and library that binary was built with, and various\nattributes of the system that is running that binary.  Thanks to\nstep [1/5], these helper functions can also be linked to help other\nparts of \"git\" (like the transport) report the first two (some code\nmay further need to be moved so that they can be called from the\nbuilt-ins and standalones).  The system that the binary is running\non would be the same anyway, so there is no need to duplicate that\npart of the report.\n"},{"id":"394992","messageId":"20200407183541.GA137962@google.com","threadId":"53075","inReplyTo":"xmqqpncjtjsh.fsf@gitster.c.googlers.com","subject":"Re: [PATCH v12 5/5] bugreport: add compiler info","fromName":"Emily Shaffer","fromEmail":"emilyshaffer@google.com","sentAt":"2020-04-07T18:35:41Z","receivedAt":"2020-04-07T18:35:49Z","isPatch":true,"sender":{"key":"nasamuffin@google.com","avatar":"https://avatars.githubusercontent.com/u/1606826?v=4"},"body":"On Tue, Apr 07, 2020 at 08:09:02AM -0700, Junio C Hamano wrote:\n> Danh Doan <congdanhqx@gmail.com> writes:\n> \n> > On 2020-04-06 15:45:26-0700, Emily Shaffer <emilyshaffer@google.com> wrote:\n> >> Helped-by: Danh Doan <congdanhqx@gmail.com>\n> >\n> > If you ever send another version of this series, my Git identity is:\n> >\n> > Đoàn Trần Công Danh <congdanhqx@gmail.com>\n> >\n> > Thanks,\n> \n> Thanks.\n> \nThanks Danh - I copied it from the email header, my apologies. Junio,\nsince you replied as well does that mean you updated your copy and I\ndon't need to re-send? (I haven't read the other comments yet, but your\ncomment on the cover letter makes me think you don't want a v13.)\n\n - Emily\n"},{"id":"394994","messageId":"20200407184240.GB137962@google.com","threadId":"53075","inReplyTo":"xmqqeet0urts.fsf@gitster.c.googlers.com","subject":"Re: [PATCH v12 3/5] bugreport: gather git version and build info","fromName":"Emily Shaffer","fromEmail":"emilyshaffer@google.com","sentAt":"2020-04-07T18:42:40Z","receivedAt":"2020-04-07T18:42:49Z","isPatch":true,"sender":{"key":"nasamuffin@google.com","avatar":"https://avatars.githubusercontent.com/u/1606826?v=4"},"body":"On Mon, Apr 06, 2020 at 04:17:51PM -0700, Junio C Hamano wrote:\n> Emily Shaffer <emilyshaffer@google.com> writes:\n> \n> > It's not ideal to directly call 'git version --build-options' because\n> > that output goes to stdout. Instead, wrap the version string in a helper\n> > within help.[ch] library, and call that helper from within the bugreport\n> > library.\n> \n> This means that \"git-bugreport\" that can be a different binary from\n> say \"git-remote-curl\" (or \"git-version\" for that matter) would still\n> report whatever version string that was compiled into \"bugreport\".\n> \n> Reporting the version of \"bugreport\" is *not* useless, and what this\n> step adds to the report is good.  \n> \n> But the version number of \"bugreport\" may not have much to do with\n> the binary the end user is having trouble with, so we'd also want\n> the version of the main part of \"git\", and other standalone \"git\"\n> subprograms like \"git-remote-curl\", reported separately, probably\n> together with $PATH, $GIT_EXEC_PATH and what appears in the\n> directories listed on these environment variables.\n> \n> If \"git version --build-options\" writes to its standard output\n> stream, that is a good thing, as it makes it easy to spawn and read\n> what it says via the run_command() API, and there is one less thing\n> to worry about (it would be a bit more cumbersome if the output goes\n> to the standard error stream).\n> \n> As \"git-remote-curl\" would also be a separate binary, we'd have to\n> use the same technique to report version number (and perhaps curl's\n> library version and its configuration?), perhaps by teaching the\n> subcommand a new option to dump such details to its standard output.\n> \n> Using the same technique to report the version about the \"git\"\n> itself would be consistent thing to do, as a preparation for future\n> steps that reports the details about \"git-remote-curl\".\n\nSure. I will include a run_command() call to \"git version\n--build-options\" (or is it --build-info?) in the same series where I\nre-introduce the call to \"git-remote-curl\", since they will look pretty\nsimilar; around that time I will clean up what \"git-bugreport\" reports\nabout its own version/build info, too.\n\nTo be clear, do you want me to include the output of get_compiler_info()\nin \"git version --build-options\" when I do that change, too?\n\n - Emily\n"},{"id":"395002","messageId":"xmqq4ktvt635.fsf@gitster.c.googlers.com","threadId":"53075","inReplyTo":"20200407184240.GB137962@google.com","subject":"Re: [PATCH v12 3/5] bugreport: gather git version and build info","fromName":"Junio C Hamano","fromEmail":"gitster@pobox.com","sentAt":"2020-04-07T20:05:02Z","receivedAt":"2020-04-07T20:05:08Z","isPatch":true,"sender":{"key":"gitster@pobox.com","avatar":"https://avatars.githubusercontent.com/u/54884?v=4"},"body":"Emily Shaffer <emilyshaffer@google.com> writes:\n\n> To be clear, do you want me to include the output of get_compiler_info()\n> in \"git version --build-options\" when I do that change, too?\n\nIn the endgame, there are two kinds of information we'd want to\ngather and report, I would think.\n\nOnes that can be different per-binary are things like:\n\n - what version of the source code the binary was compiled from\n - with what compiler options\n - using which compiler and\n - linking with what libraries,\n - where in the filesystem is the binary located\n\nThe others are various properties of the system the user is using,\nand having trouble using, Git on:\n\n - how many CPUs do we have,\n - how much free memory,\n - is the repository's filesystem case sensitive,\n - what version of 'wish' is being used.\n\nWe'd want the former to be reported for each binary that matters, so\n\"git version --build-options\" would want to say it, \"git remote-curl\n--build-options\" would want to say it, and being different binaries,\nthey may say different things.\n\nThere is not much point in duplicating the latter that are not\nbinary specific, so it probably makes sense to gather them inside,\nand report them from, \"git bugreport\" itself.\n\nThanks.\n"},{"id":"395006","messageId":"20200407203418.GC137962@google.com","threadId":"53075","inReplyTo":"xmqq4ktvt635.fsf@gitster.c.googlers.com","subject":"Re: [PATCH v12 3/5] bugreport: gather git version and build info","fromName":"Emily Shaffer","fromEmail":"emilyshaffer@google.com","sentAt":"2020-04-07T20:34:18Z","receivedAt":"2020-04-07T20:34:26Z","isPatch":true,"sender":{"key":"nasamuffin@google.com","avatar":"https://avatars.githubusercontent.com/u/1606826?v=4"},"body":"On Tue, Apr 07, 2020 at 01:05:02PM -0700, Junio C Hamano wrote:\n> Emily Shaffer <emilyshaffer@google.com> writes:\n> \n> > To be clear, do you want me to include the output of get_compiler_info()\n> > in \"git version --build-options\" when I do that change, too?\n> \n> In the endgame, there are two kinds of information we'd want to\n> gather and report, I would think.\n> \n> Ones that can be different per-binary are things like:\n> \n>  - what version of the source code the binary was compiled from\n>  - with what compiler options\n>  - using which compiler and\n>  - linking with what libraries,\n>  - where in the filesystem is the binary located\n> \n> The others are various properties of the system the user is using,\n> and having trouble using, Git on:\n> \n>  - how many CPUs do we have,\n>  - how much free memory,\n>  - is the repository's filesystem case sensitive,\n>  - what version of 'wish' is being used.\n> \n> We'd want the former to be reported for each binary that matters, so\n> \"git version --build-options\" would want to say it, \"git remote-curl\n> --build-options\" would want to say it, and being different binaries,\n> they may say different things.\n> \n> There is not much point in duplicating the latter that are not\n> binary specific, so it probably makes sense to gather them inside,\n> and report them from, \"git bugreport\" itself.\n\nSure. Sounds great. Thanks for laying it out, this is very clear.\n\n - Emily\n"}]}