Skip to content

Commit 49e19e1

Browse files
committed
Merge branch 'es/bugreport' into pu
The "bugreport" tool. Ready for 'next' to be improved/enhanced on top? As the scope of the topic got trimmed, hopefully these early parts can be polished quickly enough to be merged down. * es/bugreport: 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 71da7dc + fa77442 commit 49e19e1

File tree

14 files changed

+455
-126
lines changed

14 files changed

+455
-126
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
@@ -811,6 +812,7 @@ XDIFF_LIB = xdiff/lib.a
811812
VCSSVN_LIB = vcs-svn/lib.a
812813
REFTABLE_LIB = reftable/libreftable.a
813814

815+
GENERATED_H += config-list.h
814816
GENERATED_H += command-list.h
815817

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

21402142
help.sp help.s help.o: command-list.h
21412143

2142-
builtin/help.sp builtin/help.s builtin/help.o: command-list.h GIT-PREFIX
2144+
builtin/help.sp builtin/help.s builtin/help.o: config-list.h GIT-PREFIX
21432145
builtin/help.sp builtin/help.s builtin/help.o: EXTRA_CPPFLAGS = \
21442146
'-DGIT_HTML_PATH="$(htmldir_relative_SQ)"' \
21452147
'-DGIT_MAN_PATH="$(mandir_relative_SQ)"' \
@@ -2159,6 +2161,12 @@ $(BUILT_INS): git$X
21592161
ln -s $< $@ 2>/dev/null || \
21602162
cp $< $@
21612163

2164+
config-list.h: generate-configlist.sh
2165+
2166+
config-list.h:
2167+
$(QUIET_GEN)$(SHELL_PATH) ./generate-configlist.sh \
2168+
>$@+ && mv $@+ $@
2169+
21622170
command-list.h: generate-cmdlist.sh command-list.txt
21632171

21642172
command-list.h: $(wildcard Documentation/git*.txt) Documentation/*config.txt Documentation/config/*.txt
@@ -2478,6 +2486,10 @@ endif
24782486
git-%$X: %.o GIT-LDFLAGS $(GITLIBS)
24792487
$(QUIET_LINK)$(CC) $(ALL_CFLAGS) -o $@ $(ALL_LDFLAGS) $(filter %.o,$^) $(LIBS)
24802488

2489+
git-bugreport$X: bugreport.o GIT-LDFLAGS $(GITLIBS)
2490+
$(QUIET_LINK)$(CC) $(ALL_CFLAGS) -o $@ $(ALL_LDFLAGS) $(filter %.o,$^) \
2491+
$(LIBS)
2492+
24812493
git-imap-send$X: imap-send.o $(IMAP_SEND_BUILDDEPS) GIT-LDFLAGS $(GITLIBS)
24822494
$(QUIET_LINK)$(CC) $(ALL_CFLAGS) -o $@ $(ALL_LDFLAGS) $(filter %.o,$^) \
24832495
$(IMAP_SEND_LDFLAGS) $(LIBS)
@@ -2812,7 +2824,7 @@ $(SP_OBJ): %.sp: %.c GIT-CFLAGS FORCE
28122824
.PHONY: sparse $(SP_OBJ)
28132825
sparse: $(SP_OBJ)
28142826

2815-
EXCEPT_HDRS := command-list.h unicode-width.h compat/% xdiff/%
2827+
EXCEPT_HDRS := command-list.h config-list.h unicode-width.h compat/% xdiff/%
28162828
ifndef GCRYPT_SHA256
28172829
EXCEPT_HDRS += sha256/gcrypt.h
28182830
endif
@@ -2834,7 +2846,7 @@ hdr-check: $(HCO)
28342846
style:
28352847
git clang-format --style file --diff --extensions c,h
28362848

2837-
check: command-list.h
2849+
check: config-list.h command-list.h
28382850
@if sparse; \
28392851
then \
28402852
echo >&2 "Use 'make sparse' instead"; \

bugreport.c

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

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)