Skip to content

Commit dd094c2

Browse files
committed
Merge branch 'es/bugreport'
The "bugreport" tool. * es/bugreport: bugreport: drop extraneous includes bugreport: add compiler info bugreport: add uname info bugreport: gather git version and build info bugreport: add tool to generate debugging info help: move list_config_help to builtin/help
2 parents 6d6b412 + 8f0e984 commit dd094c2

File tree

16 files changed

+458
-131
lines changed

16 files changed

+458
-131
lines changed

.gitignore

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -25,6 +25,7 @@
2525
/git-bisect--helper
2626
/git-blame
2727
/git-branch
28+
/git-bugreport
2829
/git-bundle
2930
/git-cat-file
3031
/git-check-attr
@@ -188,6 +189,7 @@
188189
/gitweb/gitweb.cgi
189190
/gitweb/static/gitweb.js
190191
/gitweb/static/gitweb.min.*
192+
/config-list.h
191193
/command-list.h
192194
*.tar.gz
193195
*.dsc

Documentation/git-bugreport.txt

Lines changed: 52 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,52 @@
1+
git-bugreport(1)
2+
================
3+
4+
NAME
5+
----
6+
git-bugreport - Collect information for user to file a bug report
7+
8+
SYNOPSIS
9+
--------
10+
[verse]
11+
'git bugreport' [(-o | --output-directory) <path>] [(-s | --suffix) <format>]
12+
13+
DESCRIPTION
14+
-----------
15+
Captures information about the user's machine, Git client, and repository state,
16+
as well as a form requesting information about the behavior the user observed,
17+
into a single text file which the user can then share, for example to the Git
18+
mailing list, in order to report an observed bug.
19+
20+
The following information is requested from the user:
21+
22+
- Reproduction steps
23+
- Expected behavior
24+
- Actual behavior
25+
26+
The following information is captured automatically:
27+
28+
- 'git version --build-options'
29+
- uname sysname, release, version, and machine strings
30+
- Compiler-specific info string
31+
32+
This tool is invoked via the typical Git setup process, which means that in some
33+
cases, it might not be able to launch - for example, if a relevant config file
34+
is unreadable. In this kind of scenario, it may be helpful to manually gather
35+
the kind of information listed above when manually asking for help.
36+
37+
OPTIONS
38+
-------
39+
-o <path>::
40+
--output-directory <path>::
41+
Place the resulting bug report file in `<path>` instead of the root of
42+
the Git repository.
43+
44+
-s <format>::
45+
--suffix <format>::
46+
Specify an alternate suffix for the bugreport name, to create a file
47+
named 'git-bugreport-<formatted suffix>'. This should take the form of a
48+
link:strftime[3] format string; the current local time will be used.
49+
50+
GIT
51+
---
52+
Part of the linkgit:git[1] suite

Makefile

Lines changed: 15 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -674,6 +674,7 @@ EXTRA_PROGRAMS =
674674
# ... and all the rest that could be moved out of bindir to gitexecdir
675675
PROGRAMS += $(EXTRA_PROGRAMS)
676676

677+
PROGRAM_OBJS += bugreport.o
677678
PROGRAM_OBJS += credential-store.o
678679
PROGRAM_OBJS += daemon.o
679680
PROGRAM_OBJS += fast-import.o
@@ -810,6 +811,7 @@ LIB_FILE = libgit.a
810811
XDIFF_LIB = xdiff/lib.a
811812
VCSSVN_LIB = vcs-svn/lib.a
812813

814+
GENERATED_H += config-list.h
813815
GENERATED_H += command-list.h
814816

815817
LIB_H := $(sort $(patsubst ./%,%,$(shell git ls-files '*.h' ':!t/' ':!Documentation/' 2>/dev/null || \
@@ -2137,7 +2139,7 @@ git$X: git.o GIT-LDFLAGS $(BUILTIN_OBJS) $(GITLIBS)
21372139

21382140
help.sp help.s help.o: command-list.h
21392141

2140-
builtin/help.sp builtin/help.s builtin/help.o: command-list.h GIT-PREFIX
2142+
builtin/help.sp builtin/help.s builtin/help.o: config-list.h GIT-PREFIX
21412143
builtin/help.sp builtin/help.s builtin/help.o: EXTRA_CPPFLAGS = \
21422144
'-DGIT_HTML_PATH="$(htmldir_relative_SQ)"' \
21432145
'-DGIT_MAN_PATH="$(mandir_relative_SQ)"' \
@@ -2157,6 +2159,12 @@ $(BUILT_INS): git$X
21572159
ln -s $< $@ 2>/dev/null || \
21582160
cp $< $@
21592161

2162+
config-list.h: generate-configlist.sh
2163+
2164+
config-list.h:
2165+
$(QUIET_GEN)$(SHELL_PATH) ./generate-configlist.sh \
2166+
>$@+ && mv $@+ $@
2167+
21602168
command-list.h: generate-cmdlist.sh command-list.txt
21612169

21622170
command-list.h: $(wildcard Documentation/git*.txt) Documentation/*config.txt Documentation/config/*.txt
@@ -2459,6 +2467,10 @@ endif
24592467
git-%$X: %.o GIT-LDFLAGS $(GITLIBS)
24602468
$(QUIET_LINK)$(CC) $(ALL_CFLAGS) -o $@ $(ALL_LDFLAGS) $(filter %.o,$^) $(LIBS)
24612469

2470+
git-bugreport$X: bugreport.o GIT-LDFLAGS $(GITLIBS)
2471+
$(QUIET_LINK)$(CC) $(ALL_CFLAGS) -o $@ $(ALL_LDFLAGS) $(filter %.o,$^) \
2472+
$(LIBS)
2473+
24622474
git-imap-send$X: imap-send.o $(IMAP_SEND_BUILDDEPS) GIT-LDFLAGS $(GITLIBS)
24632475
$(QUIET_LINK)$(CC) $(ALL_CFLAGS) -o $@ $(ALL_LDFLAGS) $(filter %.o,$^) \
24642476
$(IMAP_SEND_LDFLAGS) $(LIBS)
@@ -2790,7 +2802,7 @@ $(SP_OBJ): %.sp: %.c GIT-CFLAGS FORCE
27902802
.PHONY: sparse $(SP_OBJ)
27912803
sparse: $(SP_OBJ)
27922804

2793-
EXCEPT_HDRS := command-list.h unicode-width.h compat/% xdiff/%
2805+
EXCEPT_HDRS := command-list.h config-list.h unicode-width.h compat/% xdiff/%
27942806
ifndef GCRYPT_SHA256
27952807
EXCEPT_HDRS += sha256/gcrypt.h
27962808
endif
@@ -2812,7 +2824,7 @@ hdr-check: $(HCO)
28122824
style:
28132825
git clang-format --style file --diff --extensions c,h
28142826

2815-
check: command-list.h
2827+
check: config-list.h command-list.h
28162828
@if sparse; \
28172829
then \
28182830
echo >&2 "Use 'make sparse' instead"; \

bugreport.c

Lines changed: 140 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,140 @@
1+
#include "cache.h"
2+
#include "parse-options.h"
3+
#include "strbuf.h"
4+
#include "help.h"
5+
#include "compat/compiler.h"
6+
7+
static void get_system_info(struct strbuf *sys_info)
8+
{
9+
struct utsname uname_info;
10+
11+
/* get git version from native cmd */
12+
strbuf_addstr(sys_info, _("git version:\n"));
13+
get_version_info(sys_info, 1);
14+
15+
/* system call for other version info */
16+
strbuf_addstr(sys_info, "uname: ");
17+
if (uname(&uname_info))
18+
strbuf_addf(sys_info, _("uname() failed with error '%s' (%d)\n"),
19+
strerror(errno),
20+
errno);
21+
else
22+
strbuf_addf(sys_info, "%s %s %s %s\n",
23+
uname_info.sysname,
24+
uname_info.release,
25+
uname_info.version,
26+
uname_info.machine);
27+
28+
strbuf_addstr(sys_info, _("compiler info: "));
29+
get_compiler_info(sys_info);
30+
strbuf_addstr(sys_info, _("libc info: "));
31+
get_libc_info(sys_info);
32+
}
33+
34+
static const char * const bugreport_usage[] = {
35+
N_("git bugreport [-o|--output-directory <file>] [-s|--suffix <format>]"),
36+
NULL
37+
};
38+
39+
static int get_bug_template(struct strbuf *template)
40+
{
41+
const char template_text[] = N_(
42+
"Thank you for filling out a Git bug report!\n"
43+
"Please answer the following questions to help us understand your issue.\n"
44+
"\n"
45+
"What did you do before the bug happened? (Steps to reproduce your issue)\n"
46+
"\n"
47+
"What did you expect to happen? (Expected behavior)\n"
48+
"\n"
49+
"What happened instead? (Actual behavior)\n"
50+
"\n"
51+
"What's different between what you expected and what actually happened?\n"
52+
"\n"
53+
"Anything else you want to add:\n"
54+
"\n"
55+
"Please review the rest of the bug report below.\n"
56+
"You can delete any lines you don't wish to share.\n");
57+
58+
strbuf_addstr(template, _(template_text));
59+
return 0;
60+
}
61+
62+
static void get_header(struct strbuf *buf, const char *title)
63+
{
64+
strbuf_addf(buf, "\n\n[%s]\n", title);
65+
}
66+
67+
int cmd_main(int argc, const char **argv)
68+
{
69+
struct strbuf buffer = STRBUF_INIT;
70+
struct strbuf report_path = STRBUF_INIT;
71+
int report = -1;
72+
time_t now = time(NULL);
73+
char *option_output = NULL;
74+
char *option_suffix = "%Y-%m-%d-%H%M";
75+
int nongit_ok = 0;
76+
const char *prefix = NULL;
77+
const char *user_relative_path = NULL;
78+
79+
const struct option bugreport_options[] = {
80+
OPT_STRING('o', "output-directory", &option_output, N_("path"),
81+
N_("specify a destination for the bugreport file")),
82+
OPT_STRING('s', "suffix", &option_suffix, N_("format"),
83+
N_("specify a strftime format suffix for the filename")),
84+
OPT_END()
85+
};
86+
87+
prefix = setup_git_directory_gently(&nongit_ok);
88+
89+
argc = parse_options(argc, argv, prefix, bugreport_options,
90+
bugreport_usage, 0);
91+
92+
/* Prepare the path to put the result */
93+
strbuf_addstr(&report_path,
94+
prefix_filename(prefix,
95+
option_output ? option_output : ""));
96+
strbuf_complete(&report_path, '/');
97+
98+
strbuf_addstr(&report_path, "git-bugreport-");
99+
strbuf_addftime(&report_path, option_suffix, localtime(&now), 0, 0);
100+
strbuf_addstr(&report_path, ".txt");
101+
102+
switch (safe_create_leading_directories(report_path.buf)) {
103+
case SCLD_OK:
104+
case SCLD_EXISTS:
105+
break;
106+
default:
107+
die(_("could not create leading directories for '%s'"),
108+
report_path.buf);
109+
}
110+
111+
/* Prepare the report contents */
112+
get_bug_template(&buffer);
113+
114+
get_header(&buffer, _("System Info"));
115+
get_system_info(&buffer);
116+
117+
/* fopen doesn't offer us an O_EXCL alternative, except with glibc. */
118+
report = open(report_path.buf, O_CREAT | O_EXCL | O_WRONLY, 0666);
119+
120+
if (report < 0) {
121+
UNLEAK(report_path);
122+
die(_("couldn't create a new file at '%s'"), report_path.buf);
123+
}
124+
125+
strbuf_write_fd(&buffer, report);
126+
close(report);
127+
128+
/*
129+
* We want to print the path relative to the user, but we still need the
130+
* path relative to us to give to the editor.
131+
*/
132+
if (!(prefix && skip_prefix(report_path.buf, prefix, &user_relative_path)))
133+
user_relative_path = report_path.buf;
134+
fprintf(stderr, _("Created new report at '%s'.\n"),
135+
user_relative_path);
136+
137+
UNLEAK(buffer);
138+
UNLEAK(report_path);
139+
return !!launch_editor(report_path.buf, NULL, NULL);
140+
}

builtin/help.c

Lines changed: 86 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -8,6 +8,7 @@
88
#include "parse-options.h"
99
#include "run-command.h"
1010
#include "column.h"
11+
#include "config-list.h"
1112
#include "help.h"
1213
#include "alias.h"
1314

@@ -62,6 +63,91 @@ static const char * const builtin_help_usage[] = {
6263
NULL
6364
};
6465

66+
struct slot_expansion {
67+
const char *prefix;
68+
const char *placeholder;
69+
void (*fn)(struct string_list *list, const char *prefix);
70+
int found;
71+
};
72+
73+
static void list_config_help(int for_human)
74+
{
75+
struct slot_expansion slot_expansions[] = {
76+
{ "advice", "*", list_config_advices },
77+
{ "color.branch", "<slot>", list_config_color_branch_slots },
78+
{ "color.decorate", "<slot>", list_config_color_decorate_slots },
79+
{ "color.diff", "<slot>", list_config_color_diff_slots },
80+
{ "color.grep", "<slot>", list_config_color_grep_slots },
81+
{ "color.interactive", "<slot>", list_config_color_interactive_slots },
82+
{ "color.remote", "<slot>", list_config_color_sideband_slots },
83+
{ "color.status", "<slot>", list_config_color_status_slots },
84+
{ "fsck", "<msg-id>", list_config_fsck_msg_ids },
85+
{ "receive.fsck", "<msg-id>", list_config_fsck_msg_ids },
86+
{ NULL, NULL, NULL }
87+
};
88+
const char **p;
89+
struct slot_expansion *e;
90+
struct string_list keys = STRING_LIST_INIT_DUP;
91+
int i;
92+
93+
for (p = config_name_list; *p; p++) {
94+
const char *var = *p;
95+
struct strbuf sb = STRBUF_INIT;
96+
97+
for (e = slot_expansions; e->prefix; e++) {
98+
99+
strbuf_reset(&sb);
100+
strbuf_addf(&sb, "%s.%s", e->prefix, e->placeholder);
101+
if (!strcasecmp(var, sb.buf)) {
102+
e->fn(&keys, e->prefix);
103+
e->found++;
104+
break;
105+
}
106+
}
107+
strbuf_release(&sb);
108+
if (!e->prefix)
109+
string_list_append(&keys, var);
110+
}
111+
112+
for (e = slot_expansions; e->prefix; e++)
113+
if (!e->found)
114+
BUG("slot_expansion %s.%s is not used",
115+
e->prefix, e->placeholder);
116+
117+
string_list_sort(&keys);
118+
for (i = 0; i < keys.nr; i++) {
119+
const char *var = keys.items[i].string;
120+
const char *wildcard, *tag, *cut;
121+
122+
if (for_human) {
123+
puts(var);
124+
continue;
125+
}
126+
127+
wildcard = strchr(var, '*');
128+
tag = strchr(var, '<');
129+
130+
if (!wildcard && !tag) {
131+
puts(var);
132+
continue;
133+
}
134+
135+
if (wildcard && !tag)
136+
cut = wildcard;
137+
else if (!wildcard && tag)
138+
cut = tag;
139+
else
140+
cut = wildcard < tag ? wildcard : tag;
141+
142+
/*
143+
* We may produce duplicates, but that's up to
144+
* git-completion.bash to handle
145+
*/
146+
printf("%.*s\n", (int)(cut - var), var);
147+
}
148+
string_list_clear(&keys, 0);
149+
}
150+
65151
static enum help_format parse_help_format(const char *format)
66152
{
67153
if (!strcmp(format, "man"))

command-list.txt

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -54,6 +54,7 @@ git-archive mainporcelain
5454
git-bisect mainporcelain info
5555
git-blame ancillaryinterrogators complete
5656
git-branch mainporcelain history
57+
git-bugreport ancillaryinterrogators
5758
git-bundle mainporcelain
5859
git-cat-file plumbinginterrogators
5960
git-check-attr purehelpers

0 commit comments

Comments
 (0)