blob: 25f860a0d973caca44593cb28919e47afb13089d [file] [log] [blame]
Jeff Kingd7a56492020-08-13 10:59:36 -04001#include "builtin.h"
Elijah Newren0b027f62023-03-21 06:25:58 +00002#include "abspath.h"
Elijah Newren4e120822023-04-11 00:41:57 -07003#include "editor.h"
Elijah Newrenf394e092023-03-21 06:25:54 +00004#include "gettext.h"
Emily Shaffer238b4392020-04-16 14:18:04 -07005#include "parse-options.h"
Emily Shaffer238b4392020-04-16 14:18:04 -07006#include "strbuf.h"
Emily Shaffer617d5712020-04-16 14:18:05 -07007#include "help.h"
Emily Shaffer69bcbbc2020-04-16 14:18:07 -07008#include "compat/compiler.h"
Ævar Arnfjörð Bjarmason5e3aba32021-09-26 21:03:26 +02009#include "hook.h"
Ævar Arnfjörð Bjarmasoncfe853e2021-09-26 21:03:29 +020010#include "hook-list.h"
Victoria Dyeaac0e8f2022-08-12 20:10:17 +000011#include "diagnose.h"
Elijah Newren87bed172023-04-11 00:41:53 -070012#include "object-file.h"
Elijah Newrene38da482023-03-21 06:26:05 +000013#include "setup.h"
Emily Shaffer617d5712020-04-16 14:18:05 -070014
15static void get_system_info(struct strbuf *sys_info)
16{
Emily Shaffer14119142020-04-16 14:18:06 -070017 struct utsname uname_info;
Emily Shaffer4a4804e2020-05-12 16:42:13 -070018 char *shell = NULL;
Emily Shaffer14119142020-04-16 14:18:06 -070019
Emily Shaffer617d5712020-04-16 14:18:05 -070020 /* get git version from native cmd */
21 strbuf_addstr(sys_info, _("git version:\n"));
22 get_version_info(sys_info, 1);
Emily Shaffer14119142020-04-16 14:18:06 -070023
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);
Emily Shaffer69bcbbc2020-04-16 14:18:07 -070036
37 strbuf_addstr(sys_info, _("compiler info: "));
38 get_compiler_info(sys_info);
Emily Shaffer4a4804e2020-05-12 16:42:13 -070039
Emily Shaffer69bcbbc2020-04-16 14:18:07 -070040 strbuf_addstr(sys_info, _("libc info: "));
41 get_libc_info(sys_info);
Emily Shaffer4a4804e2020-05-12 16:42:13 -070042
43 shell = getenv("SHELL");
44 strbuf_addf(sys_info, "$SHELL (typically, interactive shell): %s\n",
45 shell ? shell : "<unset>");
Emily Shaffer617d5712020-04-16 14:18:05 -070046}
Emily Shaffer238b4392020-04-16 14:18:04 -070047
Emily Shaffer788a7762020-05-07 17:53:57 -070048static void get_populated_hooks(struct strbuf *hook_info, int nongit)
49{
Ævar Arnfjörð Bjarmasoncfe853e2021-09-26 21:03:29 +020050 const char **p;
Emily Shaffer788a7762020-05-07 17:53:57 -070051
52 if (nongit) {
53 strbuf_addstr(hook_info,
54 _("not run from a git repository - no hooks to show\n"));
55 return;
56 }
57
Ævar Arnfjörð Bjarmasoncfe853e2021-09-26 21:03:29 +020058 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 }
Emily Shaffer788a7762020-05-07 17:53:57 -070064}
65
Emily Shaffer238b4392020-04-16 14:18:04 -070066static const char * const bugreport_usage[] = {
Jiamu Sunb3b57c62024-03-14 04:00:16 +000067 N_("git bugreport [(-o | --output-directory) <path>]\n"
68 " [(-s | --suffix) <format> | --no-suffix]\n"
Ævar Arnfjörð Bjarmason8bc6f922022-10-13 17:39:05 +020069 " [--diagnose[=<mode>]]"),
Emily Shaffer238b4392020-04-16 14:18:04 -070070 NULL
71};
72
73static int get_bug_template(struct strbuf *template)
74{
75 const char template_text[] = N_(
76"Thank you for filling out a Git bug report!\n"
77"Please answer the following questions to help us understand your issue.\n"
78"\n"
79"What did you do before the bug happened? (Steps to reproduce your issue)\n"
80"\n"
81"What did you expect to happen? (Expected behavior)\n"
82"\n"
83"What happened instead? (Actual behavior)\n"
84"\n"
85"What's different between what you expected and what actually happened?\n"
86"\n"
87"Anything else you want to add:\n"
88"\n"
89"Please review the rest of the bug report below.\n"
90"You can delete any lines you don't wish to share.\n");
91
92 strbuf_addstr(template, _(template_text));
93 return 0;
94}
95
Emily Shaffer617d5712020-04-16 14:18:05 -070096static void get_header(struct strbuf *buf, const char *title)
97{
98 strbuf_addf(buf, "\n\n[%s]\n", title);
99}
100
Jeff Kingd7a56492020-08-13 10:59:36 -0400101int cmd_bugreport(int argc, const char **argv, const char *prefix)
Emily Shaffer238b4392020-04-16 14:18:04 -0700102{
103 struct strbuf buffer = STRBUF_INIT;
104 struct strbuf report_path = STRBUF_INIT;
105 int report = -1;
106 time_t now = time(NULL);
Taylor Blau4f6460d2020-11-30 19:30:06 -0500107 struct tm tm;
Victoria Dyeaac0e8f2022-08-12 20:10:17 +0000108 enum diagnose_mode diagnose = DIAGNOSE_NONE;
Emily Shaffer238b4392020-04-16 14:18:04 -0700109 char *option_output = NULL;
110 char *option_suffix = "%Y-%m-%d-%H%M";
Emily Shaffer238b4392020-04-16 14:18:04 -0700111 const char *user_relative_path = NULL;
Andrzej Hunt4fa26872021-04-25 14:16:13 +0000112 char *prefixed_filename;
Victoria Dyeaac0e8f2022-08-12 20:10:17 +0000113 size_t output_path_len;
Ævar Arnfjörð Bjarmasonac95f5d2022-11-08 19:17:51 +0100114 int ret;
Emily Shaffer238b4392020-04-16 14:18:04 -0700115
116 const struct option bugreport_options[] = {
Victoria Dyeaac0e8f2022-08-12 20:10:17 +0000117 OPT_CALLBACK_F(0, "diagnose", &diagnose, N_("mode"),
118 N_("create an additional zip archive of detailed diagnostics (default 'stats')"),
119 PARSE_OPT_OPTARG, option_parse_diagnose),
Emily Shaffer238b4392020-04-16 14:18:04 -0700120 OPT_STRING('o', "output-directory", &option_output, N_("path"),
Victoria Dyeaac0e8f2022-08-12 20:10:17 +0000121 N_("specify a destination for the bugreport file(s)")),
Emily Shaffer238b4392020-04-16 14:18:04 -0700122 OPT_STRING('s', "suffix", &option_suffix, N_("format"),
Victoria Dyeaac0e8f2022-08-12 20:10:17 +0000123 N_("specify a strftime format suffix for the filename(s)")),
Emily Shaffer238b4392020-04-16 14:18:04 -0700124 OPT_END()
125 };
126
Emily Shaffer238b4392020-04-16 14:18:04 -0700127 argc = parse_options(argc, argv, prefix, bugreport_options,
128 bugreport_usage, 0);
129
Emily Shaffer681c0a22023-10-26 11:22:31 -0700130 if (argc) {
131 error(_("unknown argument `%s'"), argv[0]);
132 usage(bugreport_usage[0]);
133 }
134
Emily Shaffer238b4392020-04-16 14:18:04 -0700135 /* Prepare the path to put the result */
Andrzej Hunt4fa26872021-04-25 14:16:13 +0000136 prefixed_filename = prefix_filename(prefix,
137 option_output ? option_output : "");
138 strbuf_addstr(&report_path, prefixed_filename);
Emily Shaffer238b4392020-04-16 14:18:04 -0700139 strbuf_complete(&report_path, '/');
Victoria Dyeaac0e8f2022-08-12 20:10:17 +0000140 output_path_len = report_path.len;
Emily Shaffer238b4392020-04-16 14:18:04 -0700141
Jiamu Sunb3b57c62024-03-14 04:00:16 +0000142 strbuf_addstr(&report_path, "git-bugreport");
143 if (option_suffix) {
144 strbuf_addch(&report_path, '-');
145 strbuf_addftime(&report_path, option_suffix, localtime_r(&now, &tm), 0, 0);
146 }
Emily Shaffer238b4392020-04-16 14:18:04 -0700147 strbuf_addstr(&report_path, ".txt");
148
149 switch (safe_create_leading_directories(report_path.buf)) {
150 case SCLD_OK:
151 case SCLD_EXISTS:
152 break;
153 default:
154 die(_("could not create leading directories for '%s'"),
155 report_path.buf);
156 }
157
Victoria Dyeaac0e8f2022-08-12 20:10:17 +0000158 /* Prepare diagnostics, if requested */
159 if (diagnose != DIAGNOSE_NONE) {
160 struct strbuf zip_path = STRBUF_INIT;
161 strbuf_add(&zip_path, report_path.buf, output_path_len);
162 strbuf_addstr(&zip_path, "git-diagnostics-");
163 strbuf_addftime(&zip_path, option_suffix, localtime_r(&now, &tm), 0, 0);
164 strbuf_addstr(&zip_path, ".zip");
165
166 if (create_diagnostics_archive(&zip_path, diagnose))
167 die_errno(_("unable to create diagnostics archive %s"), zip_path.buf);
168
169 strbuf_release(&zip_path);
170 }
171
Emily Shaffer238b4392020-04-16 14:18:04 -0700172 /* Prepare the report contents */
173 get_bug_template(&buffer);
174
Emily Shaffer617d5712020-04-16 14:18:05 -0700175 get_header(&buffer, _("System Info"));
176 get_system_info(&buffer);
177
Emily Shaffer788a7762020-05-07 17:53:57 -0700178 get_header(&buffer, _("Enabled Hooks"));
Jeff Kingd7a56492020-08-13 10:59:36 -0400179 get_populated_hooks(&buffer, !startup_info->have_repository);
Emily Shaffer788a7762020-05-07 17:53:57 -0700180
Emily Shaffer238b4392020-04-16 14:18:04 -0700181 /* fopen doesn't offer us an O_EXCL alternative, except with glibc. */
René Scharfe66e905b2021-08-25 22:16:46 +0200182 report = xopen(report_path.buf, O_CREAT | O_EXCL | O_WRONLY, 0666);
Emily Shaffer238b4392020-04-16 14:18:04 -0700183
Randall S. Beckerf64b6a12020-06-19 16:23:19 -0400184 if (write_in_full(report, buffer.buf, buffer.len) < 0)
185 die_errno(_("unable to write to %s"), report_path.buf);
186
Emily Shaffer238b4392020-04-16 14:18:04 -0700187 close(report);
188
189 /*
190 * We want to print the path relative to the user, but we still need the
191 * path relative to us to give to the editor.
192 */
193 if (!(prefix && skip_prefix(report_path.buf, prefix, &user_relative_path)))
194 user_relative_path = report_path.buf;
195 fprintf(stderr, _("Created new report at '%s'.\n"),
196 user_relative_path);
197
Andrzej Hunt4fa26872021-04-25 14:16:13 +0000198 free(prefixed_filename);
Ævar Arnfjörð Bjarmasonac95f5d2022-11-08 19:17:51 +0100199 strbuf_release(&buffer);
200
201 ret = !!launch_editor(report_path.buf, NULL, NULL);
202 strbuf_release(&report_path);
203 return ret;
Emily Shaffer238b4392020-04-16 14:18:04 -0700204}