blob: 7ca0fba1b8ed46a86290bd6ed966cb9aa8233de6 [file] [log] [blame]
Emily Shaffer617d5712020-04-16 14:18:05 -07001#include "cache.h"
Emily Shaffer238b4392020-04-16 14:18:04 -07002#include "parse-options.h"
Emily Shaffer238b4392020-04-16 14:18:04 -07003#include "strbuf.h"
Emily Shaffer617d5712020-04-16 14:18:05 -07004#include "help.h"
Emily Shaffer69bcbbc2020-04-16 14:18:07 -07005#include "compat/compiler.h"
Emily Shaffer788a7762020-05-07 17:53:57 -07006#include "run-command.h"
7
Emily Shaffer617d5712020-04-16 14:18:05 -07008
9static void get_system_info(struct strbuf *sys_info)
10{
Emily Shaffer14119142020-04-16 14:18:06 -070011 struct utsname uname_info;
Emily Shaffer4a4804e2020-05-12 16:42:13 -070012 char *shell = NULL;
Emily Shaffer14119142020-04-16 14:18:06 -070013
Emily Shaffer617d5712020-04-16 14:18:05 -070014 /* get git version from native cmd */
15 strbuf_addstr(sys_info, _("git version:\n"));
16 get_version_info(sys_info, 1);
Emily Shaffer14119142020-04-16 14:18:06 -070017
18 /* system call for other version info */
19 strbuf_addstr(sys_info, "uname: ");
20 if (uname(&uname_info))
21 strbuf_addf(sys_info, _("uname() failed with error '%s' (%d)\n"),
22 strerror(errno),
23 errno);
24 else
25 strbuf_addf(sys_info, "%s %s %s %s\n",
26 uname_info.sysname,
27 uname_info.release,
28 uname_info.version,
29 uname_info.machine);
Emily Shaffer69bcbbc2020-04-16 14:18:07 -070030
31 strbuf_addstr(sys_info, _("compiler info: "));
32 get_compiler_info(sys_info);
Emily Shaffer4a4804e2020-05-12 16:42:13 -070033
Emily Shaffer69bcbbc2020-04-16 14:18:07 -070034 strbuf_addstr(sys_info, _("libc info: "));
35 get_libc_info(sys_info);
Emily Shaffer4a4804e2020-05-12 16:42:13 -070036
37 shell = getenv("SHELL");
38 strbuf_addf(sys_info, "$SHELL (typically, interactive shell): %s\n",
39 shell ? shell : "<unset>");
Emily Shaffer617d5712020-04-16 14:18:05 -070040}
Emily Shaffer238b4392020-04-16 14:18:04 -070041
Emily Shaffer788a7762020-05-07 17:53:57 -070042static void get_populated_hooks(struct strbuf *hook_info, int nongit)
43{
44 /*
45 * NEEDSWORK: Doesn't look like there is a list of all possible hooks;
46 * so below is a transcription of `git help hooks`. Later, this should
47 * be replaced with some programmatically generated list (generated from
48 * doc or else taken from some library which tells us about all the
49 * hooks)
50 */
51 static const char *hook[] = {
52 "applypatch-msg",
53 "pre-applypatch",
54 "post-applypatch",
55 "pre-commit",
56 "pre-merge-commit",
57 "prepare-commit-msg",
58 "commit-msg",
59 "post-commit",
60 "pre-rebase",
61 "post-checkout",
62 "post-merge",
63 "pre-push",
64 "pre-receive",
65 "update",
66 "post-receive",
67 "post-update",
68 "push-to-checkout",
69 "pre-auto-gc",
70 "post-rewrite",
71 "sendemail-validate",
72 "fsmonitor-watchman",
73 "p4-pre-submit",
74 "post-index-change",
75 };
76 int i;
77
78 if (nongit) {
79 strbuf_addstr(hook_info,
80 _("not run from a git repository - no hooks to show\n"));
81 return;
82 }
83
84 for (i = 0; i < ARRAY_SIZE(hook); i++)
85 if (find_hook(hook[i]))
86 strbuf_addf(hook_info, "%s\n", hook[i]);
87}
88
Emily Shaffer238b4392020-04-16 14:18:04 -070089static const char * const bugreport_usage[] = {
90 N_("git bugreport [-o|--output-directory <file>] [-s|--suffix <format>]"),
91 NULL
92};
93
94static int get_bug_template(struct strbuf *template)
95{
96 const char template_text[] = N_(
97"Thank you for filling out a Git bug report!\n"
98"Please answer the following questions to help us understand your issue.\n"
99"\n"
100"What did you do before the bug happened? (Steps to reproduce your issue)\n"
101"\n"
102"What did you expect to happen? (Expected behavior)\n"
103"\n"
104"What happened instead? (Actual behavior)\n"
105"\n"
106"What's different between what you expected and what actually happened?\n"
107"\n"
108"Anything else you want to add:\n"
109"\n"
110"Please review the rest of the bug report below.\n"
111"You can delete any lines you don't wish to share.\n");
112
113 strbuf_addstr(template, _(template_text));
114 return 0;
115}
116
Emily Shaffer617d5712020-04-16 14:18:05 -0700117static void get_header(struct strbuf *buf, const char *title)
118{
119 strbuf_addf(buf, "\n\n[%s]\n", title);
120}
121
Emily Shaffer238b4392020-04-16 14:18:04 -0700122int cmd_main(int argc, const char **argv)
123{
124 struct strbuf buffer = STRBUF_INIT;
125 struct strbuf report_path = STRBUF_INIT;
126 int report = -1;
127 time_t now = time(NULL);
128 char *option_output = NULL;
129 char *option_suffix = "%Y-%m-%d-%H%M";
130 int nongit_ok = 0;
131 const char *prefix = NULL;
132 const char *user_relative_path = NULL;
133
134 const struct option bugreport_options[] = {
135 OPT_STRING('o', "output-directory", &option_output, N_("path"),
136 N_("specify a destination for the bugreport file")),
137 OPT_STRING('s', "suffix", &option_suffix, N_("format"),
138 N_("specify a strftime format suffix for the filename")),
139 OPT_END()
140 };
141
142 prefix = setup_git_directory_gently(&nongit_ok);
143
144 argc = parse_options(argc, argv, prefix, bugreport_options,
145 bugreport_usage, 0);
146
147 /* Prepare the path to put the result */
148 strbuf_addstr(&report_path,
149 prefix_filename(prefix,
150 option_output ? option_output : ""));
151 strbuf_complete(&report_path, '/');
152
153 strbuf_addstr(&report_path, "git-bugreport-");
154 strbuf_addftime(&report_path, option_suffix, localtime(&now), 0, 0);
155 strbuf_addstr(&report_path, ".txt");
156
157 switch (safe_create_leading_directories(report_path.buf)) {
158 case SCLD_OK:
159 case SCLD_EXISTS:
160 break;
161 default:
162 die(_("could not create leading directories for '%s'"),
163 report_path.buf);
164 }
165
166 /* Prepare the report contents */
167 get_bug_template(&buffer);
168
Emily Shaffer617d5712020-04-16 14:18:05 -0700169 get_header(&buffer, _("System Info"));
170 get_system_info(&buffer);
171
Emily Shaffer788a7762020-05-07 17:53:57 -0700172 get_header(&buffer, _("Enabled Hooks"));
173 get_populated_hooks(&buffer, nongit_ok);
174
Emily Shaffer238b4392020-04-16 14:18:04 -0700175 /* fopen doesn't offer us an O_EXCL alternative, except with glibc. */
176 report = open(report_path.buf, O_CREAT | O_EXCL | O_WRONLY, 0666);
177
Jeff Kingd5e19612020-08-13 11:55:00 -0400178 if (report < 0)
Emily Shaffer238b4392020-04-16 14:18:04 -0700179 die(_("couldn't create a new file at '%s'"), report_path.buf);
Emily Shaffer238b4392020-04-16 14:18:04 -0700180
Randall S. Beckerf64b6a12020-06-19 16:23:19 -0400181 if (write_in_full(report, buffer.buf, buffer.len) < 0)
182 die_errno(_("unable to write to %s"), report_path.buf);
183
Emily Shaffer238b4392020-04-16 14:18:04 -0700184 close(report);
185
186 /*
187 * We want to print the path relative to the user, but we still need the
188 * path relative to us to give to the editor.
189 */
190 if (!(prefix && skip_prefix(report_path.buf, prefix, &user_relative_path)))
191 user_relative_path = report_path.buf;
192 fprintf(stderr, _("Created new report at '%s'.\n"),
193 user_relative_path);
194
195 UNLEAK(buffer);
196 UNLEAK(report_path);
197 return !!launch_editor(report_path.buf, NULL, NULL);
198}