]> git.ipfire.org Git - thirdparty/git.git/blame - bugreport.c
Merge branch 'sn/midx-repack-with-config'
[thirdparty/git.git] / bugreport.c
CommitLineData
617d5719 1#include "cache.h"
238b439d 2#include "parse-options.h"
238b439d 3#include "strbuf.h"
617d5719 4#include "help.h"
69bcbbce 5#include "compat/compiler.h"
788a7760
ES
6#include "run-command.h"
7
617d5719
ES
8
9static void get_system_info(struct strbuf *sys_info)
10{
1411914a
ES
11 struct utsname uname_info;
12
617d5719
ES
13 /* get git version from native cmd */
14 strbuf_addstr(sys_info, _("git version:\n"));
15 get_version_info(sys_info, 1);
1411914a
ES
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);
69bcbbce
ES
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);
617d5719 34}
238b439d 35
788a7760
ES
36static void get_populated_hooks(struct strbuf *hook_info, int nongit)
37{
38 /*
39 * NEEDSWORK: Doesn't look like there is a list of all possible hooks;
40 * so below is a transcription of `git help hooks`. Later, this should
41 * be replaced with some programmatically generated list (generated from
42 * doc or else taken from some library which tells us about all the
43 * hooks)
44 */
45 static const char *hook[] = {
46 "applypatch-msg",
47 "pre-applypatch",
48 "post-applypatch",
49 "pre-commit",
50 "pre-merge-commit",
51 "prepare-commit-msg",
52 "commit-msg",
53 "post-commit",
54 "pre-rebase",
55 "post-checkout",
56 "post-merge",
57 "pre-push",
58 "pre-receive",
59 "update",
60 "post-receive",
61 "post-update",
62 "push-to-checkout",
63 "pre-auto-gc",
64 "post-rewrite",
65 "sendemail-validate",
66 "fsmonitor-watchman",
67 "p4-pre-submit",
68 "post-index-change",
69 };
70 int i;
71
72 if (nongit) {
73 strbuf_addstr(hook_info,
74 _("not run from a git repository - no hooks to show\n"));
75 return;
76 }
77
78 for (i = 0; i < ARRAY_SIZE(hook); i++)
79 if (find_hook(hook[i]))
80 strbuf_addf(hook_info, "%s\n", hook[i]);
81}
82
238b439d
ES
83static const char * const bugreport_usage[] = {
84 N_("git bugreport [-o|--output-directory <file>] [-s|--suffix <format>]"),
85 NULL
86};
87
88static int get_bug_template(struct strbuf *template)
89{
90 const char template_text[] = N_(
91"Thank you for filling out a Git bug report!\n"
92"Please answer the following questions to help us understand your issue.\n"
93"\n"
94"What did you do before the bug happened? (Steps to reproduce your issue)\n"
95"\n"
96"What did you expect to happen? (Expected behavior)\n"
97"\n"
98"What happened instead? (Actual behavior)\n"
99"\n"
100"What's different between what you expected and what actually happened?\n"
101"\n"
102"Anything else you want to add:\n"
103"\n"
104"Please review the rest of the bug report below.\n"
105"You can delete any lines you don't wish to share.\n");
106
107 strbuf_addstr(template, _(template_text));
108 return 0;
109}
110
617d5719
ES
111static void get_header(struct strbuf *buf, const char *title)
112{
113 strbuf_addf(buf, "\n\n[%s]\n", title);
114}
115
238b439d
ES
116int cmd_main(int argc, const char **argv)
117{
118 struct strbuf buffer = STRBUF_INIT;
119 struct strbuf report_path = STRBUF_INIT;
120 int report = -1;
121 time_t now = time(NULL);
122 char *option_output = NULL;
123 char *option_suffix = "%Y-%m-%d-%H%M";
124 int nongit_ok = 0;
125 const char *prefix = NULL;
126 const char *user_relative_path = NULL;
127
128 const struct option bugreport_options[] = {
129 OPT_STRING('o', "output-directory", &option_output, N_("path"),
130 N_("specify a destination for the bugreport file")),
131 OPT_STRING('s', "suffix", &option_suffix, N_("format"),
132 N_("specify a strftime format suffix for the filename")),
133 OPT_END()
134 };
135
136 prefix = setup_git_directory_gently(&nongit_ok);
137
138 argc = parse_options(argc, argv, prefix, bugreport_options,
139 bugreport_usage, 0);
140
141 /* Prepare the path to put the result */
142 strbuf_addstr(&report_path,
143 prefix_filename(prefix,
144 option_output ? option_output : ""));
145 strbuf_complete(&report_path, '/');
146
147 strbuf_addstr(&report_path, "git-bugreport-");
148 strbuf_addftime(&report_path, option_suffix, localtime(&now), 0, 0);
149 strbuf_addstr(&report_path, ".txt");
150
151 switch (safe_create_leading_directories(report_path.buf)) {
152 case SCLD_OK:
153 case SCLD_EXISTS:
154 break;
155 default:
156 die(_("could not create leading directories for '%s'"),
157 report_path.buf);
158 }
159
160 /* Prepare the report contents */
161 get_bug_template(&buffer);
162
617d5719
ES
163 get_header(&buffer, _("System Info"));
164 get_system_info(&buffer);
165
788a7760
ES
166 get_header(&buffer, _("Enabled Hooks"));
167 get_populated_hooks(&buffer, nongit_ok);
168
238b439d
ES
169 /* fopen doesn't offer us an O_EXCL alternative, except with glibc. */
170 report = open(report_path.buf, O_CREAT | O_EXCL | O_WRONLY, 0666);
171
172 if (report < 0) {
173 UNLEAK(report_path);
174 die(_("couldn't create a new file at '%s'"), report_path.buf);
175 }
176
177 strbuf_write_fd(&buffer, report);
178 close(report);
179
180 /*
181 * We want to print the path relative to the user, but we still need the
182 * path relative to us to give to the editor.
183 */
184 if (!(prefix && skip_prefix(report_path.buf, prefix, &user_relative_path)))
185 user_relative_path = report_path.buf;
186 fprintf(stderr, _("Created new report at '%s'.\n"),
187 user_relative_path);
188
189 UNLEAK(buffer);
190 UNLEAK(report_path);
191 return !!launch_editor(report_path.buf, NULL, NULL);
192}