2 #include "parse-options.h"
5 #include "compat/compiler.h"
6 #include "run-command.h"
9 static void get_system_info(struct strbuf
*sys_info
)
11 struct utsname uname_info
;
14 /* get git version from native cmd */
15 strbuf_addstr(sys_info
, _("git version:\n"));
16 get_version_info(sys_info
, 1);
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"),
25 strbuf_addf(sys_info
, "%s %s %s %s\n",
31 strbuf_addstr(sys_info
, _("compiler info: "));
32 get_compiler_info(sys_info
);
34 strbuf_addstr(sys_info
, _("libc info: "));
35 get_libc_info(sys_info
);
37 shell
= getenv("SHELL");
38 strbuf_addf(sys_info
, "$SHELL (typically, interactive shell): %s\n",
39 shell
? shell
: "<unset>");
42 static void get_populated_hooks(struct strbuf
*hook_info
, int nongit
)
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
51 static const char *hook
[] = {
79 strbuf_addstr(hook_info
,
80 _("not run from a git repository - no hooks to show\n"));
84 for (i
= 0; i
< ARRAY_SIZE(hook
); i
++)
85 if (find_hook(hook
[i
]))
86 strbuf_addf(hook_info
, "%s\n", hook
[i
]);
89 static const char * const bugreport_usage
[] = {
90 N_("git bugreport [-o|--output-directory <file>] [-s|--suffix <format>]"),
94 static int get_bug_template(struct strbuf
*template)
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"
100 "What did you do before the bug happened? (Steps to reproduce your issue)\n"
102 "What did you expect to happen? (Expected behavior)\n"
104 "What happened instead? (Actual behavior)\n"
106 "What's different between what you expected and what actually happened?\n"
108 "Anything else you want to add:\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");
113 strbuf_addstr(template, _(template_text
));
117 static void get_header(struct strbuf
*buf
, const char *title
)
119 strbuf_addf(buf
, "\n\n[%s]\n", title
);
122 int cmd_bugreport(int argc
, const char **argv
, const char *prefix
)
124 struct strbuf buffer
= STRBUF_INIT
;
125 struct strbuf report_path
= STRBUF_INIT
;
127 time_t now
= time(NULL
);
129 char *option_output
= NULL
;
130 char *option_suffix
= "%Y-%m-%d-%H%M";
131 const char *user_relative_path
= NULL
;
132 char *prefixed_filename
;
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")),
142 argc
= parse_options(argc
, argv
, prefix
, bugreport_options
,
145 /* Prepare the path to put the result */
146 prefixed_filename
= prefix_filename(prefix
,
147 option_output
? option_output
: "");
148 strbuf_addstr(&report_path
, prefixed_filename
);
149 strbuf_complete(&report_path
, '/');
151 strbuf_addstr(&report_path
, "git-bugreport-");
152 strbuf_addftime(&report_path
, option_suffix
, localtime_r(&now
, &tm
), 0, 0);
153 strbuf_addstr(&report_path
, ".txt");
155 switch (safe_create_leading_directories(report_path
.buf
)) {
160 die(_("could not create leading directories for '%s'"),
164 /* Prepare the report contents */
165 get_bug_template(&buffer
);
167 get_header(&buffer
, _("System Info"));
168 get_system_info(&buffer
);
170 get_header(&buffer
, _("Enabled Hooks"));
171 get_populated_hooks(&buffer
, !startup_info
->have_repository
);
173 /* fopen doesn't offer us an O_EXCL alternative, except with glibc. */
174 report
= xopen(report_path
.buf
, O_CREAT
| O_EXCL
| O_WRONLY
, 0666);
176 if (write_in_full(report
, buffer
.buf
, buffer
.len
) < 0)
177 die_errno(_("unable to write to %s"), report_path
.buf
);
182 * We want to print the path relative to the user, but we still need the
183 * path relative to us to give to the editor.
185 if (!(prefix
&& skip_prefix(report_path
.buf
, prefix
, &user_relative_path
)))
186 user_relative_path
= report_path
.buf
;
187 fprintf(stderr
, _("Created new report at '%s'.\n"),
190 free(prefixed_filename
);
193 return !!launch_editor(report_path
.buf
, NULL
, NULL
);