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