]> git.ipfire.org Git - thirdparty/git.git/blame - builtin/bugreport.c
object-file.h: move declarations for object-file.c functions from cache.h
[thirdparty/git.git] / builtin / bugreport.c
CommitLineData
d7a5649c 1#include "builtin.h"
0b027f6c 2#include "abspath.h"
f394e093 3#include "gettext.h"
238b439d 4#include "parse-options.h"
238b439d 5#include "strbuf.h"
617d5719 6#include "help.h"
69bcbbce 7#include "compat/compiler.h"
5e3aba33 8#include "hook.h"
cfe853e6 9#include "hook-list.h"
aac0e8ff 10#include "diagnose.h"
87bed179 11#include "object-file.h"
e38da487 12#include "setup.h"
d5ebb50d 13#include "wrapper.h"
617d5719
ES
14
15static void get_system_info(struct strbuf *sys_info)
16{
1411914a 17 struct utsname uname_info;
4a4804ed 18 char *shell = NULL;
1411914a 19
617d5719
ES
20 /* get git version from native cmd */
21 strbuf_addstr(sys_info, _("git version:\n"));
22 get_version_info(sys_info, 1);
1411914a
ES
23
24 /* system call for other version info */
25 strbuf_addstr(sys_info, "uname: ");
26 if (uname(&uname_info))
27 strbuf_addf(sys_info, _("uname() failed with error '%s' (%d)\n"),
28 strerror(errno),
29 errno);
30 else
31 strbuf_addf(sys_info, "%s %s %s %s\n",
32 uname_info.sysname,
33 uname_info.release,
34 uname_info.version,
35 uname_info.machine);
69bcbbce
ES
36
37 strbuf_addstr(sys_info, _("compiler info: "));
38 get_compiler_info(sys_info);
4a4804ed 39
69bcbbce
ES
40 strbuf_addstr(sys_info, _("libc info: "));
41 get_libc_info(sys_info);
4a4804ed
ES
42
43 shell = getenv("SHELL");
44 strbuf_addf(sys_info, "$SHELL (typically, interactive shell): %s\n",
45 shell ? shell : "<unset>");
617d5719 46}
238b439d 47
788a7760
ES
48static void get_populated_hooks(struct strbuf *hook_info, int nongit)
49{
cfe853e6 50 const char **p;
788a7760
ES
51
52 if (nongit) {
53 strbuf_addstr(hook_info,
54 _("not run from a git repository - no hooks to show\n"));
55 return;
56 }
57
cfe853e6
ÆAB
58 for (p = hook_name_list; *p; p++) {
59 const char *hook = *p;
60
61 if (hook_exists(hook))
62 strbuf_addf(hook_info, "%s\n", hook);
63 }
788a7760
ES
64}
65
238b439d 66static const char * const bugreport_usage[] = {
f6a8ef07 67 N_("git bugreport [(-o | --output-directory) <path>] [(-s | --suffix) <format>]\n"
8bc6f924 68 " [--diagnose[=<mode>]]"),
238b439d
ES
69 NULL
70};
71
72static int get_bug_template(struct strbuf *template)
73{
74 const char template_text[] = N_(
75"Thank you for filling out a Git bug report!\n"
76"Please answer the following questions to help us understand your issue.\n"
77"\n"
78"What did you do before the bug happened? (Steps to reproduce your issue)\n"
79"\n"
80"What did you expect to happen? (Expected behavior)\n"
81"\n"
82"What happened instead? (Actual behavior)\n"
83"\n"
84"What's different between what you expected and what actually happened?\n"
85"\n"
86"Anything else you want to add:\n"
87"\n"
88"Please review the rest of the bug report below.\n"
89"You can delete any lines you don't wish to share.\n");
90
91 strbuf_addstr(template, _(template_text));
92 return 0;
93}
94
617d5719
ES
95static void get_header(struct strbuf *buf, const char *title)
96{
97 strbuf_addf(buf, "\n\n[%s]\n", title);
98}
99
d7a5649c 100int cmd_bugreport(int argc, const char **argv, const char *prefix)
238b439d
ES
101{
102 struct strbuf buffer = STRBUF_INIT;
103 struct strbuf report_path = STRBUF_INIT;
104 int report = -1;
105 time_t now = time(NULL);
4f6460df 106 struct tm tm;
aac0e8ff 107 enum diagnose_mode diagnose = DIAGNOSE_NONE;
238b439d
ES
108 char *option_output = NULL;
109 char *option_suffix = "%Y-%m-%d-%H%M";
238b439d 110 const char *user_relative_path = NULL;
4fa26873 111 char *prefixed_filename;
aac0e8ff 112 size_t output_path_len;
ac95f5d3 113 int ret;
238b439d
ES
114
115 const struct option bugreport_options[] = {
aac0e8ff
VD
116 OPT_CALLBACK_F(0, "diagnose", &diagnose, N_("mode"),
117 N_("create an additional zip archive of detailed diagnostics (default 'stats')"),
118 PARSE_OPT_OPTARG, option_parse_diagnose),
238b439d 119 OPT_STRING('o', "output-directory", &option_output, N_("path"),
aac0e8ff 120 N_("specify a destination for the bugreport file(s)")),
238b439d 121 OPT_STRING('s', "suffix", &option_suffix, N_("format"),
aac0e8ff 122 N_("specify a strftime format suffix for the filename(s)")),
238b439d
ES
123 OPT_END()
124 };
125
238b439d
ES
126 argc = parse_options(argc, argv, prefix, bugreport_options,
127 bugreport_usage, 0);
128
129 /* Prepare the path to put the result */
4fa26873
AH
130 prefixed_filename = prefix_filename(prefix,
131 option_output ? option_output : "");
132 strbuf_addstr(&report_path, prefixed_filename);
238b439d 133 strbuf_complete(&report_path, '/');
aac0e8ff 134 output_path_len = report_path.len;
238b439d
ES
135
136 strbuf_addstr(&report_path, "git-bugreport-");
4f6460df 137 strbuf_addftime(&report_path, option_suffix, localtime_r(&now, &tm), 0, 0);
238b439d
ES
138 strbuf_addstr(&report_path, ".txt");
139
140 switch (safe_create_leading_directories(report_path.buf)) {
141 case SCLD_OK:
142 case SCLD_EXISTS:
143 break;
144 default:
145 die(_("could not create leading directories for '%s'"),
146 report_path.buf);
147 }
148
aac0e8ff
VD
149 /* Prepare diagnostics, if requested */
150 if (diagnose != DIAGNOSE_NONE) {
151 struct strbuf zip_path = STRBUF_INIT;
152 strbuf_add(&zip_path, report_path.buf, output_path_len);
153 strbuf_addstr(&zip_path, "git-diagnostics-");
154 strbuf_addftime(&zip_path, option_suffix, localtime_r(&now, &tm), 0, 0);
155 strbuf_addstr(&zip_path, ".zip");
156
157 if (create_diagnostics_archive(&zip_path, diagnose))
158 die_errno(_("unable to create diagnostics archive %s"), zip_path.buf);
159
160 strbuf_release(&zip_path);
161 }
162
238b439d
ES
163 /* Prepare the report contents */
164 get_bug_template(&buffer);
165
617d5719
ES
166 get_header(&buffer, _("System Info"));
167 get_system_info(&buffer);
168
788a7760 169 get_header(&buffer, _("Enabled Hooks"));
d7a5649c 170 get_populated_hooks(&buffer, !startup_info->have_repository);
788a7760 171
238b439d 172 /* fopen doesn't offer us an O_EXCL alternative, except with glibc. */
66e905b7 173 report = xopen(report_path.buf, O_CREAT | O_EXCL | O_WRONLY, 0666);
238b439d 174
f64b6a1f
RB
175 if (write_in_full(report, buffer.buf, buffer.len) < 0)
176 die_errno(_("unable to write to %s"), report_path.buf);
177
238b439d
ES
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
4fa26873 189 free(prefixed_filename);
ac95f5d3
ÆAB
190 strbuf_release(&buffer);
191
192 ret = !!launch_editor(report_path.buf, NULL, NULL);
193 strbuf_release(&report_path);
194 return ret;
238b439d 195}