Merge branch 'es/bugreport'
The "bugreport" tool. * es/bugreport: bugreport: drop extraneous includes bugreport: add compiler info bugreport: add uname info bugreport: gather git version and build info bugreport: add tool to generate debugging info help: move list_config_help to builtin/help
This commit is contained in:
commit
dd094c2b75
2
.gitignore
vendored
2
.gitignore
vendored
@ -25,6 +25,7 @@
|
||||
/git-bisect--helper
|
||||
/git-blame
|
||||
/git-branch
|
||||
/git-bugreport
|
||||
/git-bundle
|
||||
/git-cat-file
|
||||
/git-check-attr
|
||||
@ -188,6 +189,7 @@
|
||||
/gitweb/gitweb.cgi
|
||||
/gitweb/static/gitweb.js
|
||||
/gitweb/static/gitweb.min.*
|
||||
/config-list.h
|
||||
/command-list.h
|
||||
*.tar.gz
|
||||
*.dsc
|
||||
|
52
Documentation/git-bugreport.txt
Normal file
52
Documentation/git-bugreport.txt
Normal file
@ -0,0 +1,52 @@
|
||||
git-bugreport(1)
|
||||
================
|
||||
|
||||
NAME
|
||||
----
|
||||
git-bugreport - Collect information for user to file a bug report
|
||||
|
||||
SYNOPSIS
|
||||
--------
|
||||
[verse]
|
||||
'git bugreport' [(-o | --output-directory) <path>] [(-s | --suffix) <format>]
|
||||
|
||||
DESCRIPTION
|
||||
-----------
|
||||
Captures information about the user's machine, Git client, and repository state,
|
||||
as well as a form requesting information about the behavior the user observed,
|
||||
into a single text file which the user can then share, for example to the Git
|
||||
mailing list, in order to report an observed bug.
|
||||
|
||||
The following information is requested from the user:
|
||||
|
||||
- Reproduction steps
|
||||
- Expected behavior
|
||||
- Actual behavior
|
||||
|
||||
The following information is captured automatically:
|
||||
|
||||
- 'git version --build-options'
|
||||
- uname sysname, release, version, and machine strings
|
||||
- Compiler-specific info string
|
||||
|
||||
This tool is invoked via the typical Git setup process, which means that in some
|
||||
cases, it might not be able to launch - for example, if a relevant config file
|
||||
is unreadable. In this kind of scenario, it may be helpful to manually gather
|
||||
the kind of information listed above when manually asking for help.
|
||||
|
||||
OPTIONS
|
||||
-------
|
||||
-o <path>::
|
||||
--output-directory <path>::
|
||||
Place the resulting bug report file in `<path>` instead of the root of
|
||||
the Git repository.
|
||||
|
||||
-s <format>::
|
||||
--suffix <format>::
|
||||
Specify an alternate suffix for the bugreport name, to create a file
|
||||
named 'git-bugreport-<formatted suffix>'. This should take the form of a
|
||||
link:strftime[3] format string; the current local time will be used.
|
||||
|
||||
GIT
|
||||
---
|
||||
Part of the linkgit:git[1] suite
|
18
Makefile
18
Makefile
@ -674,6 +674,7 @@ EXTRA_PROGRAMS =
|
||||
# ... and all the rest that could be moved out of bindir to gitexecdir
|
||||
PROGRAMS += $(EXTRA_PROGRAMS)
|
||||
|
||||
PROGRAM_OBJS += bugreport.o
|
||||
PROGRAM_OBJS += credential-store.o
|
||||
PROGRAM_OBJS += daemon.o
|
||||
PROGRAM_OBJS += fast-import.o
|
||||
@ -810,6 +811,7 @@ LIB_FILE = libgit.a
|
||||
XDIFF_LIB = xdiff/lib.a
|
||||
VCSSVN_LIB = vcs-svn/lib.a
|
||||
|
||||
GENERATED_H += config-list.h
|
||||
GENERATED_H += command-list.h
|
||||
|
||||
LIB_H := $(sort $(patsubst ./%,%,$(shell git ls-files '*.h' ':!t/' ':!Documentation/' 2>/dev/null || \
|
||||
@ -2137,7 +2139,7 @@ git$X: git.o GIT-LDFLAGS $(BUILTIN_OBJS) $(GITLIBS)
|
||||
|
||||
help.sp help.s help.o: command-list.h
|
||||
|
||||
builtin/help.sp builtin/help.s builtin/help.o: command-list.h GIT-PREFIX
|
||||
builtin/help.sp builtin/help.s builtin/help.o: config-list.h GIT-PREFIX
|
||||
builtin/help.sp builtin/help.s builtin/help.o: EXTRA_CPPFLAGS = \
|
||||
'-DGIT_HTML_PATH="$(htmldir_relative_SQ)"' \
|
||||
'-DGIT_MAN_PATH="$(mandir_relative_SQ)"' \
|
||||
@ -2157,6 +2159,12 @@ $(BUILT_INS): git$X
|
||||
ln -s $< $@ 2>/dev/null || \
|
||||
cp $< $@
|
||||
|
||||
config-list.h: generate-configlist.sh
|
||||
|
||||
config-list.h:
|
||||
$(QUIET_GEN)$(SHELL_PATH) ./generate-configlist.sh \
|
||||
>$@+ && mv $@+ $@
|
||||
|
||||
command-list.h: generate-cmdlist.sh command-list.txt
|
||||
|
||||
command-list.h: $(wildcard Documentation/git*.txt) Documentation/*config.txt Documentation/config/*.txt
|
||||
@ -2459,6 +2467,10 @@ endif
|
||||
git-%$X: %.o GIT-LDFLAGS $(GITLIBS)
|
||||
$(QUIET_LINK)$(CC) $(ALL_CFLAGS) -o $@ $(ALL_LDFLAGS) $(filter %.o,$^) $(LIBS)
|
||||
|
||||
git-bugreport$X: bugreport.o GIT-LDFLAGS $(GITLIBS)
|
||||
$(QUIET_LINK)$(CC) $(ALL_CFLAGS) -o $@ $(ALL_LDFLAGS) $(filter %.o,$^) \
|
||||
$(LIBS)
|
||||
|
||||
git-imap-send$X: imap-send.o $(IMAP_SEND_BUILDDEPS) GIT-LDFLAGS $(GITLIBS)
|
||||
$(QUIET_LINK)$(CC) $(ALL_CFLAGS) -o $@ $(ALL_LDFLAGS) $(filter %.o,$^) \
|
||||
$(IMAP_SEND_LDFLAGS) $(LIBS)
|
||||
@ -2790,7 +2802,7 @@ $(SP_OBJ): %.sp: %.c GIT-CFLAGS FORCE
|
||||
.PHONY: sparse $(SP_OBJ)
|
||||
sparse: $(SP_OBJ)
|
||||
|
||||
EXCEPT_HDRS := command-list.h unicode-width.h compat/% xdiff/%
|
||||
EXCEPT_HDRS := command-list.h config-list.h unicode-width.h compat/% xdiff/%
|
||||
ifndef GCRYPT_SHA256
|
||||
EXCEPT_HDRS += sha256/gcrypt.h
|
||||
endif
|
||||
@ -2812,7 +2824,7 @@ hdr-check: $(HCO)
|
||||
style:
|
||||
git clang-format --style file --diff --extensions c,h
|
||||
|
||||
check: command-list.h
|
||||
check: config-list.h command-list.h
|
||||
@if sparse; \
|
||||
then \
|
||||
echo >&2 "Use 'make sparse' instead"; \
|
||||
|
140
bugreport.c
Normal file
140
bugreport.c
Normal file
@ -0,0 +1,140 @@
|
||||
#include "cache.h"
|
||||
#include "parse-options.h"
|
||||
#include "strbuf.h"
|
||||
#include "help.h"
|
||||
#include "compat/compiler.h"
|
||||
|
||||
static void get_system_info(struct strbuf *sys_info)
|
||||
{
|
||||
struct utsname uname_info;
|
||||
|
||||
/* get git version from native cmd */
|
||||
strbuf_addstr(sys_info, _("git version:\n"));
|
||||
get_version_info(sys_info, 1);
|
||||
|
||||
/* system call for other version info */
|
||||
strbuf_addstr(sys_info, "uname: ");
|
||||
if (uname(&uname_info))
|
||||
strbuf_addf(sys_info, _("uname() failed with error '%s' (%d)\n"),
|
||||
strerror(errno),
|
||||
errno);
|
||||
else
|
||||
strbuf_addf(sys_info, "%s %s %s %s\n",
|
||||
uname_info.sysname,
|
||||
uname_info.release,
|
||||
uname_info.version,
|
||||
uname_info.machine);
|
||||
|
||||
strbuf_addstr(sys_info, _("compiler info: "));
|
||||
get_compiler_info(sys_info);
|
||||
strbuf_addstr(sys_info, _("libc info: "));
|
||||
get_libc_info(sys_info);
|
||||
}
|
||||
|
||||
static const char * const bugreport_usage[] = {
|
||||
N_("git bugreport [-o|--output-directory <file>] [-s|--suffix <format>]"),
|
||||
NULL
|
||||
};
|
||||
|
||||
static int get_bug_template(struct strbuf *template)
|
||||
{
|
||||
const char template_text[] = N_(
|
||||
"Thank you for filling out a Git bug report!\n"
|
||||
"Please answer the following questions to help us understand your issue.\n"
|
||||
"\n"
|
||||
"What did you do before the bug happened? (Steps to reproduce your issue)\n"
|
||||
"\n"
|
||||
"What did you expect to happen? (Expected behavior)\n"
|
||||
"\n"
|
||||
"What happened instead? (Actual behavior)\n"
|
||||
"\n"
|
||||
"What's different between what you expected and what actually happened?\n"
|
||||
"\n"
|
||||
"Anything else you want to add:\n"
|
||||
"\n"
|
||||
"Please review the rest of the bug report below.\n"
|
||||
"You can delete any lines you don't wish to share.\n");
|
||||
|
||||
strbuf_addstr(template, _(template_text));
|
||||
return 0;
|
||||
}
|
||||
|
||||
static void get_header(struct strbuf *buf, const char *title)
|
||||
{
|
||||
strbuf_addf(buf, "\n\n[%s]\n", title);
|
||||
}
|
||||
|
||||
int cmd_main(int argc, const char **argv)
|
||||
{
|
||||
struct strbuf buffer = STRBUF_INIT;
|
||||
struct strbuf report_path = STRBUF_INIT;
|
||||
int report = -1;
|
||||
time_t now = time(NULL);
|
||||
char *option_output = NULL;
|
||||
char *option_suffix = "%Y-%m-%d-%H%M";
|
||||
int nongit_ok = 0;
|
||||
const char *prefix = NULL;
|
||||
const char *user_relative_path = NULL;
|
||||
|
||||
const struct option bugreport_options[] = {
|
||||
OPT_STRING('o', "output-directory", &option_output, N_("path"),
|
||||
N_("specify a destination for the bugreport file")),
|
||||
OPT_STRING('s', "suffix", &option_suffix, N_("format"),
|
||||
N_("specify a strftime format suffix for the filename")),
|
||||
OPT_END()
|
||||
};
|
||||
|
||||
prefix = setup_git_directory_gently(&nongit_ok);
|
||||
|
||||
argc = parse_options(argc, argv, prefix, bugreport_options,
|
||||
bugreport_usage, 0);
|
||||
|
||||
/* Prepare the path to put the result */
|
||||
strbuf_addstr(&report_path,
|
||||
prefix_filename(prefix,
|
||||
option_output ? option_output : ""));
|
||||
strbuf_complete(&report_path, '/');
|
||||
|
||||
strbuf_addstr(&report_path, "git-bugreport-");
|
||||
strbuf_addftime(&report_path, option_suffix, localtime(&now), 0, 0);
|
||||
strbuf_addstr(&report_path, ".txt");
|
||||
|
||||
switch (safe_create_leading_directories(report_path.buf)) {
|
||||
case SCLD_OK:
|
||||
case SCLD_EXISTS:
|
||||
break;
|
||||
default:
|
||||
die(_("could not create leading directories for '%s'"),
|
||||
report_path.buf);
|
||||
}
|
||||
|
||||
/* Prepare the report contents */
|
||||
get_bug_template(&buffer);
|
||||
|
||||
get_header(&buffer, _("System Info"));
|
||||
get_system_info(&buffer);
|
||||
|
||||
/* fopen doesn't offer us an O_EXCL alternative, except with glibc. */
|
||||
report = open(report_path.buf, O_CREAT | O_EXCL | O_WRONLY, 0666);
|
||||
|
||||
if (report < 0) {
|
||||
UNLEAK(report_path);
|
||||
die(_("couldn't create a new file at '%s'"), report_path.buf);
|
||||
}
|
||||
|
||||
strbuf_write_fd(&buffer, report);
|
||||
close(report);
|
||||
|
||||
/*
|
||||
* We want to print the path relative to the user, but we still need the
|
||||
* path relative to us to give to the editor.
|
||||
*/
|
||||
if (!(prefix && skip_prefix(report_path.buf, prefix, &user_relative_path)))
|
||||
user_relative_path = report_path.buf;
|
||||
fprintf(stderr, _("Created new report at '%s'.\n"),
|
||||
user_relative_path);
|
||||
|
||||
UNLEAK(buffer);
|
||||
UNLEAK(report_path);
|
||||
return !!launch_editor(report_path.buf, NULL, NULL);
|
||||
}
|
@ -8,6 +8,7 @@
|
||||
#include "parse-options.h"
|
||||
#include "run-command.h"
|
||||
#include "column.h"
|
||||
#include "config-list.h"
|
||||
#include "help.h"
|
||||
#include "alias.h"
|
||||
|
||||
@ -62,6 +63,91 @@ static const char * const builtin_help_usage[] = {
|
||||
NULL
|
||||
};
|
||||
|
||||
struct slot_expansion {
|
||||
const char *prefix;
|
||||
const char *placeholder;
|
||||
void (*fn)(struct string_list *list, const char *prefix);
|
||||
int found;
|
||||
};
|
||||
|
||||
static void list_config_help(int for_human)
|
||||
{
|
||||
struct slot_expansion slot_expansions[] = {
|
||||
{ "advice", "*", list_config_advices },
|
||||
{ "color.branch", "<slot>", list_config_color_branch_slots },
|
||||
{ "color.decorate", "<slot>", list_config_color_decorate_slots },
|
||||
{ "color.diff", "<slot>", list_config_color_diff_slots },
|
||||
{ "color.grep", "<slot>", list_config_color_grep_slots },
|
||||
{ "color.interactive", "<slot>", list_config_color_interactive_slots },
|
||||
{ "color.remote", "<slot>", list_config_color_sideband_slots },
|
||||
{ "color.status", "<slot>", list_config_color_status_slots },
|
||||
{ "fsck", "<msg-id>", list_config_fsck_msg_ids },
|
||||
{ "receive.fsck", "<msg-id>", list_config_fsck_msg_ids },
|
||||
{ NULL, NULL, NULL }
|
||||
};
|
||||
const char **p;
|
||||
struct slot_expansion *e;
|
||||
struct string_list keys = STRING_LIST_INIT_DUP;
|
||||
int i;
|
||||
|
||||
for (p = config_name_list; *p; p++) {
|
||||
const char *var = *p;
|
||||
struct strbuf sb = STRBUF_INIT;
|
||||
|
||||
for (e = slot_expansions; e->prefix; e++) {
|
||||
|
||||
strbuf_reset(&sb);
|
||||
strbuf_addf(&sb, "%s.%s", e->prefix, e->placeholder);
|
||||
if (!strcasecmp(var, sb.buf)) {
|
||||
e->fn(&keys, e->prefix);
|
||||
e->found++;
|
||||
break;
|
||||
}
|
||||
}
|
||||
strbuf_release(&sb);
|
||||
if (!e->prefix)
|
||||
string_list_append(&keys, var);
|
||||
}
|
||||
|
||||
for (e = slot_expansions; e->prefix; e++)
|
||||
if (!e->found)
|
||||
BUG("slot_expansion %s.%s is not used",
|
||||
e->prefix, e->placeholder);
|
||||
|
||||
string_list_sort(&keys);
|
||||
for (i = 0; i < keys.nr; i++) {
|
||||
const char *var = keys.items[i].string;
|
||||
const char *wildcard, *tag, *cut;
|
||||
|
||||
if (for_human) {
|
||||
puts(var);
|
||||
continue;
|
||||
}
|
||||
|
||||
wildcard = strchr(var, '*');
|
||||
tag = strchr(var, '<');
|
||||
|
||||
if (!wildcard && !tag) {
|
||||
puts(var);
|
||||
continue;
|
||||
}
|
||||
|
||||
if (wildcard && !tag)
|
||||
cut = wildcard;
|
||||
else if (!wildcard && tag)
|
||||
cut = tag;
|
||||
else
|
||||
cut = wildcard < tag ? wildcard : tag;
|
||||
|
||||
/*
|
||||
* We may produce duplicates, but that's up to
|
||||
* git-completion.bash to handle
|
||||
*/
|
||||
printf("%.*s\n", (int)(cut - var), var);
|
||||
}
|
||||
string_list_clear(&keys, 0);
|
||||
}
|
||||
|
||||
static enum help_format parse_help_format(const char *format)
|
||||
{
|
||||
if (!strcmp(format, "man"))
|
||||
|
@ -54,6 +54,7 @@ git-archive mainporcelain
|
||||
git-bisect mainporcelain info
|
||||
git-blame ancillaryinterrogators complete
|
||||
git-branch mainporcelain history
|
||||
git-bugreport ancillaryinterrogators
|
||||
git-bundle mainporcelain
|
||||
git-cat-file plumbinginterrogators
|
||||
git-check-attr purehelpers
|
||||
|
41
compat/compiler.h
Normal file
41
compat/compiler.h
Normal file
@ -0,0 +1,41 @@
|
||||
#ifndef COMPILER_H
|
||||
#define COMPILER_H
|
||||
|
||||
#include "git-compat-util.h"
|
||||
#include "strbuf.h"
|
||||
|
||||
#ifdef __GLIBC__
|
||||
#include <gnu/libc-version.h>
|
||||
#endif
|
||||
|
||||
static inline void get_compiler_info(struct strbuf *info)
|
||||
{
|
||||
int len = info->len;
|
||||
#ifdef __clang__
|
||||
strbuf_addf(info, "clang: %s\n", __clang_version__);
|
||||
#elif defined(__GNUC__)
|
||||
strbuf_addf(info, "gnuc: %d.%d\n", __GNUC__, __GNUC_MINOR__);
|
||||
#endif
|
||||
|
||||
#ifdef _MSC_VER
|
||||
strbuf_addf(info, "MSVC version: %02d.%02d.%05d\n",
|
||||
_MSC_VER / 100, _MSC_VER % 100, _MSC_FULL_VER % 100000);
|
||||
#endif
|
||||
|
||||
if (len == info->len)
|
||||
strbuf_addstr(info, _("no compiler information available\n"));
|
||||
}
|
||||
|
||||
static inline void get_libc_info(struct strbuf *info)
|
||||
{
|
||||
int len = info->len;
|
||||
|
||||
#ifdef __GLIBC__
|
||||
strbuf_addf(info, "glibc: %s\n", gnu_get_libc_version());
|
||||
#endif
|
||||
|
||||
if (len == info->len)
|
||||
strbuf_addstr(info, _("no libc information available\n"));
|
||||
}
|
||||
|
||||
#endif /* COMPILER_H */
|
@ -92,8 +92,8 @@ The Steps of Build Git with VS2008
|
||||
the git operations.
|
||||
|
||||
3. Inside Git's directory run the command:
|
||||
make command-list.h
|
||||
to generate the command-list.h file needed to compile git.
|
||||
make command-list.h config-list.h
|
||||
to generate the header file needed to compile git.
|
||||
|
||||
4. Then either build Git with the GNU Make Makefile in the Git projects
|
||||
root
|
||||
|
@ -731,9 +731,9 @@ vcxproj:
|
||||
echo '</Project>') >git-remote-http/LinkOrCopyRemoteHttp.targets
|
||||
git add -f git/LinkOrCopyBuiltins.targets git-remote-http/LinkOrCopyRemoteHttp.targets
|
||||
|
||||
# Add command-list.h
|
||||
$(MAKE) MSVC=1 SKIP_VCPKG=1 prefix=/mingw64 command-list.h
|
||||
git add -f command-list.h
|
||||
# Add command-list.h and config-list.h
|
||||
$(MAKE) MSVC=1 SKIP_VCPKG=1 prefix=/mingw64 config-list.h command-list.h
|
||||
git add -f config-list.h command-list.h
|
||||
|
||||
# Add scripts
|
||||
rm -f perl/perl.mak
|
||||
|
@ -76,23 +76,6 @@ print_command_list () {
|
||||
echo "};"
|
||||
}
|
||||
|
||||
print_config_list () {
|
||||
cat <<EOF
|
||||
static const char *config_name_list[] = {
|
||||
EOF
|
||||
grep -h '^[a-zA-Z].*\..*::$' Documentation/*config.txt Documentation/config/*.txt |
|
||||
sed '/deprecated/d; s/::$//; s/, */\n/g' |
|
||||
sort |
|
||||
while read line
|
||||
do
|
||||
echo " \"$line\","
|
||||
done
|
||||
cat <<EOF
|
||||
NULL,
|
||||
};
|
||||
EOF
|
||||
}
|
||||
|
||||
exclude_programs=
|
||||
while test "--exclude-program" = "$1"
|
||||
do
|
||||
@ -113,5 +96,3 @@ echo
|
||||
define_category_names "$1"
|
||||
echo
|
||||
print_command_list "$1"
|
||||
echo
|
||||
print_config_list
|
||||
|
21
generate-configlist.sh
Executable file
21
generate-configlist.sh
Executable file
@ -0,0 +1,21 @@
|
||||
#!/bin/sh
|
||||
|
||||
echo "/* Automatically generated by generate-configlist.sh */"
|
||||
echo
|
||||
|
||||
print_config_list () {
|
||||
cat <<EOF
|
||||
static const char *config_name_list[] = {
|
||||
EOF
|
||||
grep -h '^[a-zA-Z].*\..*::$' Documentation/*config.txt Documentation/config/*.txt |
|
||||
sed '/deprecated/d; s/::$//; s/, */\n/g' |
|
||||
sort |
|
||||
sed 's/^.*$/ "&",/'
|
||||
cat <<EOF
|
||||
NULL,
|
||||
};
|
||||
EOF
|
||||
}
|
||||
|
||||
echo
|
||||
print_config_list
|
131
help.c
131
help.c
@ -407,91 +407,6 @@ void list_common_guides_help(void)
|
||||
putchar('\n');
|
||||
}
|
||||
|
||||
struct slot_expansion {
|
||||
const char *prefix;
|
||||
const char *placeholder;
|
||||
void (*fn)(struct string_list *list, const char *prefix);
|
||||
int found;
|
||||
};
|
||||
|
||||
void list_config_help(int for_human)
|
||||
{
|
||||
struct slot_expansion slot_expansions[] = {
|
||||
{ "advice", "*", list_config_advices },
|
||||
{ "color.branch", "<slot>", list_config_color_branch_slots },
|
||||
{ "color.decorate", "<slot>", list_config_color_decorate_slots },
|
||||
{ "color.diff", "<slot>", list_config_color_diff_slots },
|
||||
{ "color.grep", "<slot>", list_config_color_grep_slots },
|
||||
{ "color.interactive", "<slot>", list_config_color_interactive_slots },
|
||||
{ "color.remote", "<slot>", list_config_color_sideband_slots },
|
||||
{ "color.status", "<slot>", list_config_color_status_slots },
|
||||
{ "fsck", "<msg-id>", list_config_fsck_msg_ids },
|
||||
{ "receive.fsck", "<msg-id>", list_config_fsck_msg_ids },
|
||||
{ NULL, NULL, NULL }
|
||||
};
|
||||
const char **p;
|
||||
struct slot_expansion *e;
|
||||
struct string_list keys = STRING_LIST_INIT_DUP;
|
||||
int i;
|
||||
|
||||
for (p = config_name_list; *p; p++) {
|
||||
const char *var = *p;
|
||||
struct strbuf sb = STRBUF_INIT;
|
||||
|
||||
for (e = slot_expansions; e->prefix; e++) {
|
||||
|
||||
strbuf_reset(&sb);
|
||||
strbuf_addf(&sb, "%s.%s", e->prefix, e->placeholder);
|
||||
if (!strcasecmp(var, sb.buf)) {
|
||||
e->fn(&keys, e->prefix);
|
||||
e->found++;
|
||||
break;
|
||||
}
|
||||
}
|
||||
strbuf_release(&sb);
|
||||
if (!e->prefix)
|
||||
string_list_append(&keys, var);
|
||||
}
|
||||
|
||||
for (e = slot_expansions; e->prefix; e++)
|
||||
if (!e->found)
|
||||
BUG("slot_expansion %s.%s is not used",
|
||||
e->prefix, e->placeholder);
|
||||
|
||||
string_list_sort(&keys);
|
||||
for (i = 0; i < keys.nr; i++) {
|
||||
const char *var = keys.items[i].string;
|
||||
const char *wildcard, *tag, *cut;
|
||||
|
||||
if (for_human) {
|
||||
puts(var);
|
||||
continue;
|
||||
}
|
||||
|
||||
wildcard = strchr(var, '*');
|
||||
tag = strchr(var, '<');
|
||||
|
||||
if (!wildcard && !tag) {
|
||||
puts(var);
|
||||
continue;
|
||||
}
|
||||
|
||||
if (wildcard && !tag)
|
||||
cut = wildcard;
|
||||
else if (!wildcard && tag)
|
||||
cut = tag;
|
||||
else
|
||||
cut = wildcard < tag ? wildcard : tag;
|
||||
|
||||
/*
|
||||
* We may produce duplicates, but that's up to
|
||||
* git-completion.bash to handle
|
||||
*/
|
||||
printf("%.*s\n", (int)(cut - var), var);
|
||||
}
|
||||
string_list_clear(&keys, 0);
|
||||
}
|
||||
|
||||
static int get_alias(const char *var, const char *value, void *data)
|
||||
{
|
||||
struct string_list *list = data;
|
||||
@ -707,8 +622,32 @@ const char *help_unknown_cmd(const char *cmd)
|
||||
exit(1);
|
||||
}
|
||||
|
||||
void get_version_info(struct strbuf *buf, int show_build_options)
|
||||
{
|
||||
/*
|
||||
* The format of this string should be kept stable for compatibility
|
||||
* with external projects that rely on the output of "git version".
|
||||
*
|
||||
* Always show the version, even if other options are given.
|
||||
*/
|
||||
strbuf_addf(buf, "git version %s\n", git_version_string);
|
||||
|
||||
if (show_build_options) {
|
||||
strbuf_addf(buf, "cpu: %s\n", GIT_HOST_CPU);
|
||||
if (git_built_from_commit_string[0])
|
||||
strbuf_addf(buf, "built from commit: %s\n",
|
||||
git_built_from_commit_string);
|
||||
else
|
||||
strbuf_addstr(buf, "no commit associated with this build\n");
|
||||
strbuf_addf(buf, "sizeof-long: %d\n", (int)sizeof(long));
|
||||
strbuf_addf(buf, "sizeof-size_t: %d\n", (int)sizeof(size_t));
|
||||
/* NEEDSWORK: also save and output GIT-BUILD_OPTIONS? */
|
||||
}
|
||||
}
|
||||
|
||||
int cmd_version(int argc, const char **argv, const char *prefix)
|
||||
{
|
||||
struct strbuf buf = STRBUF_INIT;
|
||||
int build_options = 0;
|
||||
const char * const usage[] = {
|
||||
N_("git version [<options>]"),
|
||||
@ -722,25 +661,11 @@ int cmd_version(int argc, const char **argv, const char *prefix)
|
||||
|
||||
argc = parse_options(argc, argv, prefix, options, usage, 0);
|
||||
|
||||
/*
|
||||
* The format of this string should be kept stable for compatibility
|
||||
* with external projects that rely on the output of "git version".
|
||||
*
|
||||
* Always show the version, even if other options are given.
|
||||
*/
|
||||
printf("git version %s\n", git_version_string);
|
||||
get_version_info(&buf, build_options);
|
||||
printf("%s", buf.buf);
|
||||
|
||||
strbuf_release(&buf);
|
||||
|
||||
if (build_options) {
|
||||
printf("cpu: %s\n", GIT_HOST_CPU);
|
||||
if (git_built_from_commit_string[0])
|
||||
printf("built from commit: %s\n",
|
||||
git_built_from_commit_string);
|
||||
else
|
||||
printf("no commit associated with this build\n");
|
||||
printf("sizeof-long: %d\n", (int)sizeof(long));
|
||||
printf("sizeof-size_t: %d\n", (int)sizeof(size_t));
|
||||
/* NEEDSWORK: also save and output GIT-BUILD_OPTIONS? */
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
2
help.h
2
help.h
@ -22,7 +22,6 @@ static inline void mput_char(char c, unsigned int num)
|
||||
void list_common_cmds_help(void);
|
||||
void list_all_cmds_help(void);
|
||||
void list_common_guides_help(void);
|
||||
void list_config_help(int for_human);
|
||||
|
||||
void list_all_main_cmds(struct string_list *list);
|
||||
void list_all_other_cmds(struct string_list *list);
|
||||
@ -38,6 +37,7 @@ void add_cmdname(struct cmdnames *cmds, const char *name, int len);
|
||||
void exclude_cmds(struct cmdnames *cmds, struct cmdnames *excludes);
|
||||
int is_in_cmdlist(struct cmdnames *cmds, const char *name);
|
||||
void list_commands(unsigned int colopts, struct cmdnames *main_cmds, struct cmdnames *other_cmds);
|
||||
void get_version_info(struct strbuf *buf, int show_build_options);
|
||||
|
||||
/*
|
||||
* call this to die(), when it is suspected that the user mistyped a
|
||||
|
4
strbuf.c
4
strbuf.c
@ -554,6 +554,10 @@ ssize_t strbuf_write(struct strbuf *sb, FILE *f)
|
||||
return sb->len ? fwrite(sb->buf, 1, sb->len, f) : 0;
|
||||
}
|
||||
|
||||
ssize_t strbuf_write_fd(struct strbuf *sb, int fd)
|
||||
{
|
||||
return sb->len ? write(fd, sb->buf, sb->len) : 0;
|
||||
}
|
||||
|
||||
#define STRBUF_MAXLINK (2*PATH_MAX)
|
||||
|
||||
|
1
strbuf.h
1
strbuf.h
@ -468,6 +468,7 @@ int strbuf_readlink(struct strbuf *sb, const char *path, size_t hint);
|
||||
* NUL bytes.
|
||||
*/
|
||||
ssize_t strbuf_write(struct strbuf *sb, FILE *stream);
|
||||
ssize_t strbuf_write_fd(struct strbuf *sb, int fd);
|
||||
|
||||
/**
|
||||
* Read a line from a FILE *, overwriting the existing contents of
|
||||
|
61
t/t0091-bugreport.sh
Executable file
61
t/t0091-bugreport.sh
Executable file
@ -0,0 +1,61 @@
|
||||
#!/bin/sh
|
||||
|
||||
test_description='git bugreport'
|
||||
|
||||
. ./test-lib.sh
|
||||
|
||||
# Headers "[System Info]" will be followed by a non-empty line if we put some
|
||||
# information there; we can make sure all our headers were followed by some
|
||||
# information to check if the command was successful.
|
||||
HEADER_PATTERN="^\[.*\]$"
|
||||
|
||||
check_all_headers_populated () {
|
||||
while read -r line
|
||||
do
|
||||
if test "$(grep "$HEADER_PATTERN" "$line")"
|
||||
then
|
||||
echo "$line"
|
||||
read -r nextline
|
||||
if test -z "$nextline"; then
|
||||
return 1;
|
||||
fi
|
||||
fi
|
||||
done
|
||||
}
|
||||
|
||||
test_expect_success 'creates a report with content in the right places' '
|
||||
test_when_finished rm git-bugreport-check-headers.txt &&
|
||||
git bugreport -s check-headers &&
|
||||
check_all_headers_populated <git-bugreport-check-headers.txt
|
||||
'
|
||||
|
||||
test_expect_success 'dies if file with same name as report already exists' '
|
||||
test_when_finished rm git-bugreport-duplicate.txt &&
|
||||
>>git-bugreport-duplicate.txt &&
|
||||
test_must_fail git bugreport --suffix duplicate
|
||||
'
|
||||
|
||||
test_expect_success '--output-directory puts the report in the provided dir' '
|
||||
test_when_finished rm -fr foo/ &&
|
||||
git bugreport -o foo/ &&
|
||||
test_path_is_file foo/git-bugreport-*
|
||||
'
|
||||
|
||||
test_expect_success 'incorrect arguments abort with usage' '
|
||||
test_must_fail git bugreport --false 2>output &&
|
||||
test_i18ngrep usage output &&
|
||||
test_path_is_missing git-bugreport-*
|
||||
'
|
||||
|
||||
test_expect_success 'runs outside of a git dir' '
|
||||
test_when_finished rm non-repo/git-bugreport-* &&
|
||||
nongit git bugreport
|
||||
'
|
||||
|
||||
test_expect_success 'can create leading directories outside of a git dir' '
|
||||
test_when_finished rm -fr foo/bar/baz &&
|
||||
nongit git bugreport -o foo/bar/baz
|
||||
'
|
||||
|
||||
|
||||
test_done
|
Loading…
Reference in New Issue
Block a user