Skip to content

Commit f00ddc9

Browse files
committed
Merge branch 'vd/scalar-generalize-diagnose'
The "diagnose" feature to create a zip archive for diagnostic material has been lifted from "scalar" and made into a feature of "git bugreport". * vd/scalar-generalize-diagnose: scalar: update technical doc roadmap scalar-diagnose: use 'git diagnose --mode=all' builtin/bugreport.c: create '--diagnose' option builtin/diagnose.c: add '--mode' option builtin/diagnose.c: create 'git diagnose' builtin diagnose.c: add option to configure archive contents scalar-diagnose: move functionality to common location scalar-diagnose: move 'get_disk_info()' to 'compat/' scalar-diagnose: add directory to archiver more gently scalar-diagnose: avoid 32-bit overflow of size_t scalar-diagnose: use "$GIT_UNZIP" in test
2 parents a103ad6 + 43370b1 commit f00ddc9

File tree

17 files changed

+637
-278
lines changed

17 files changed

+637
-278
lines changed

.gitignore

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -53,6 +53,7 @@
5353
/git-cvsimport
5454
/git-cvsserver
5555
/git-daemon
56+
/git-diagnose
5657
/git-diff
5758
/git-diff-files
5859
/git-diff-index

Documentation/git-bugreport.txt

Lines changed: 18 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -9,6 +9,7 @@ SYNOPSIS
99
--------
1010
[verse]
1111
'git bugreport' [(-o | --output-directory) <path>] [(-s | --suffix) <format>]
12+
[--diagnose[=<mode>]]
1213

1314
DESCRIPTION
1415
-----------
@@ -31,6 +32,10 @@ The following information is captured automatically:
3132
- A list of enabled hooks
3233
- $SHELL
3334

35+
Additional information may be gathered into a separate zip archive using the
36+
`--diagnose` option, and can be attached alongside the bugreport document to
37+
provide additional context to readers.
38+
3439
This tool is invoked via the typical Git setup process, which means that in some
3540
cases, it might not be able to launch - for example, if a relevant config file
3641
is unreadable. In this kind of scenario, it may be helpful to manually gather
@@ -49,6 +54,19 @@ OPTIONS
4954
named 'git-bugreport-<formatted suffix>'. This should take the form of a
5055
strftime(3) format string; the current local time will be used.
5156

57+
--no-diagnose::
58+
--diagnose[=<mode>]::
59+
Create a zip archive of supplemental information about the user's
60+
machine, Git client, and repository state. The archive is written to the
61+
same output directory as the bug report and is named
62+
'git-diagnostics-<formatted suffix>'.
63+
+
64+
Without `mode` specified, the diagnostic archive will contain the default set of
65+
statistics reported by `git diagnose`. An optional `mode` value may be specified
66+
to change which information is included in the archive. See
67+
linkgit:git-diagnose[1] for the list of valid values for `mode` and details
68+
about their usage.
69+
5270
GIT
5371
---
5472
Part of the linkgit:git[1] suite

Documentation/git-diagnose.txt

Lines changed: 65 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,65 @@
1+
git-diagnose(1)
2+
================
3+
4+
NAME
5+
----
6+
git-diagnose - Generate a zip archive of diagnostic information
7+
8+
SYNOPSIS
9+
--------
10+
[verse]
11+
'git diagnose' [(-o | --output-directory) <path>] [(-s | --suffix) <format>]
12+
[--mode=<mode>]
13+
14+
DESCRIPTION
15+
-----------
16+
Collects detailed information about the user's machine, Git client, and
17+
repository state and packages that information into a zip archive. The
18+
generated archive can then, for example, be shared with the Git mailing list to
19+
help debug an issue or serve as a reference for independent debugging.
20+
21+
By default, the following information is captured in the archive:
22+
23+
* 'git version --build-options'
24+
* The path to the repository root
25+
* The available disk space on the filesystem
26+
* The name and size of each packfile, including those in alternate object
27+
stores
28+
* The total count of loose objects, as well as counts broken down by
29+
`.git/objects` subdirectory
30+
31+
Additional information can be collected by selecting a different diagnostic mode
32+
using the `--mode` option.
33+
34+
This tool differs from linkgit:git-bugreport[1] in that it collects much more
35+
detailed information with a greater focus on reporting the size and data shape
36+
of repository contents.
37+
38+
OPTIONS
39+
-------
40+
-o <path>::
41+
--output-directory <path>::
42+
Place the resulting diagnostics archive in `<path>` instead of the
43+
current directory.
44+
45+
-s <format>::
46+
--suffix <format>::
47+
Specify an alternate suffix for the diagnostics archive name, to create
48+
a file named 'git-diagnostics-<formatted suffix>'. This should take the
49+
form of a strftime(3) format string; the current local time will be
50+
used.
51+
52+
--mode=(stats|all)::
53+
Specify the type of diagnostics that should be collected. The default behavior
54+
of 'git diagnose' is equivalent to `--mode=stats`.
55+
+
56+
The `--mode=all` option collects everything included in `--mode=stats`, as well
57+
as copies of `.git`, `.git/hooks`, `.git/info`, `.git/logs`, and
58+
`.git/objects/info` directories. This additional information may be sensitive,
59+
as it can be used to reconstruct the full contents of the diagnosed repository.
60+
Users should exercise caution when sharing an archive generated with
61+
`--mode=all`.
62+
63+
GIT
64+
---
65+
Part of the linkgit:git[1] suite

Documentation/technical/scalar.txt

Lines changed: 3 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -84,19 +84,16 @@ series have been accepted:
8484

8585
- `scalar-diagnose`: The `scalar` command is taught the `diagnose` subcommand.
8686

87+
- `scalar-generalize-diagnose`: Move the functionality of `scalar diagnose`
88+
into `git diagnose` and `git bugreport --diagnose`.
89+
8790
Roughly speaking (and subject to change), the following series are needed to
8891
"finish" this initial version of Scalar:
8992

9093
- Finish Scalar features: Enable the built-in FSMonitor in Scalar enlistments
9194
and implement `scalar help`. At the end of this series, Scalar should be
9295
feature-complete from the perspective of a user.
9396

94-
- Generalize features not specific to Scalar: In the spirit of making Scalar
95-
configure only what is needed for large repo performance, move common
96-
utilities into other parts of Git. Some of this will be internal-only, but one
97-
major change will be generalizing `scalar diagnose` for use with any Git
98-
repository.
99-
10097
- Move Scalar to toplevel: Move Scalar out of `contrib/` and into the root of
10198
`git`, including updates to build and install it with the rest of Git. This
10299
change will incorporate Scalar into the Git CI and test framework, as well as

Makefile

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -933,6 +933,7 @@ LIB_OBJS += ctype.o
933933
LIB_OBJS += date.o
934934
LIB_OBJS += decorate.o
935935
LIB_OBJS += delta-islands.o
936+
LIB_OBJS += diagnose.o
936937
LIB_OBJS += diff-delta.o
937938
LIB_OBJS += diff-merges.o
938939
LIB_OBJS += diff-lib.o
@@ -1153,6 +1154,7 @@ BUILTIN_OBJS += builtin/credential-cache.o
11531154
BUILTIN_OBJS += builtin/credential-store.o
11541155
BUILTIN_OBJS += builtin/credential.o
11551156
BUILTIN_OBJS += builtin/describe.o
1157+
BUILTIN_OBJS += builtin/diagnose.o
11561158
BUILTIN_OBJS += builtin/diff-files.o
11571159
BUILTIN_OBJS += builtin/diff-index.o
11581160
BUILTIN_OBJS += builtin/diff-tree.o

builtin.h

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -144,6 +144,7 @@ int cmd_credential_cache(int argc, const char **argv, const char *prefix);
144144
int cmd_credential_cache_daemon(int argc, const char **argv, const char *prefix);
145145
int cmd_credential_store(int argc, const char **argv, const char *prefix);
146146
int cmd_describe(int argc, const char **argv, const char *prefix);
147+
int cmd_diagnose(int argc, const char **argv, const char *prefix);
147148
int cmd_diff_files(int argc, const char **argv, const char *prefix);
148149
int cmd_diff_index(int argc, const char **argv, const char *prefix);
149150
int cmd_diff(int argc, const char **argv, const char *prefix);

builtin/bugreport.c

Lines changed: 24 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -5,6 +5,7 @@
55
#include "compat/compiler.h"
66
#include "hook.h"
77
#include "hook-list.h"
8+
#include "diagnose.h"
89

910

1011
static void get_system_info(struct strbuf *sys_info)
@@ -59,7 +60,7 @@ static void get_populated_hooks(struct strbuf *hook_info, int nongit)
5960
}
6061

6162
static const char * const bugreport_usage[] = {
62-
N_("git bugreport [-o|--output-directory <file>] [-s|--suffix <format>]"),
63+
N_("git bugreport [-o|--output-directory <file>] [-s|--suffix <format>] [--diagnose[=<mode>]"),
6364
NULL
6465
};
6566

@@ -98,16 +99,21 @@ int cmd_bugreport(int argc, const char **argv, const char *prefix)
9899
int report = -1;
99100
time_t now = time(NULL);
100101
struct tm tm;
102+
enum diagnose_mode diagnose = DIAGNOSE_NONE;
101103
char *option_output = NULL;
102104
char *option_suffix = "%Y-%m-%d-%H%M";
103105
const char *user_relative_path = NULL;
104106
char *prefixed_filename;
107+
size_t output_path_len;
105108

106109
const struct option bugreport_options[] = {
110+
OPT_CALLBACK_F(0, "diagnose", &diagnose, N_("mode"),
111+
N_("create an additional zip archive of detailed diagnostics (default 'stats')"),
112+
PARSE_OPT_OPTARG, option_parse_diagnose),
107113
OPT_STRING('o', "output-directory", &option_output, N_("path"),
108-
N_("specify a destination for the bugreport file")),
114+
N_("specify a destination for the bugreport file(s)")),
109115
OPT_STRING('s', "suffix", &option_suffix, N_("format"),
110-
N_("specify a strftime format suffix for the filename")),
116+
N_("specify a strftime format suffix for the filename(s)")),
111117
OPT_END()
112118
};
113119

@@ -119,6 +125,7 @@ int cmd_bugreport(int argc, const char **argv, const char *prefix)
119125
option_output ? option_output : "");
120126
strbuf_addstr(&report_path, prefixed_filename);
121127
strbuf_complete(&report_path, '/');
128+
output_path_len = report_path.len;
122129

123130
strbuf_addstr(&report_path, "git-bugreport-");
124131
strbuf_addftime(&report_path, option_suffix, localtime_r(&now, &tm), 0, 0);
@@ -133,6 +140,20 @@ int cmd_bugreport(int argc, const char **argv, const char *prefix)
133140
report_path.buf);
134141
}
135142

143+
/* Prepare diagnostics, if requested */
144+
if (diagnose != DIAGNOSE_NONE) {
145+
struct strbuf zip_path = STRBUF_INIT;
146+
strbuf_add(&zip_path, report_path.buf, output_path_len);
147+
strbuf_addstr(&zip_path, "git-diagnostics-");
148+
strbuf_addftime(&zip_path, option_suffix, localtime_r(&now, &tm), 0, 0);
149+
strbuf_addstr(&zip_path, ".zip");
150+
151+
if (create_diagnostics_archive(&zip_path, diagnose))
152+
die_errno(_("unable to create diagnostics archive %s"), zip_path.buf);
153+
154+
strbuf_release(&zip_path);
155+
}
156+
136157
/* Prepare the report contents */
137158
get_bug_template(&buffer);
138159

builtin/diagnose.c

Lines changed: 61 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,61 @@
1+
#include "builtin.h"
2+
#include "parse-options.h"
3+
#include "diagnose.h"
4+
5+
static const char * const diagnose_usage[] = {
6+
N_("git diagnose [-o|--output-directory <path>] [-s|--suffix <format>] [--mode=<mode>]"),
7+
NULL
8+
};
9+
10+
int cmd_diagnose(int argc, const char **argv, const char *prefix)
11+
{
12+
struct strbuf zip_path = STRBUF_INIT;
13+
time_t now = time(NULL);
14+
struct tm tm;
15+
enum diagnose_mode mode = DIAGNOSE_STATS;
16+
char *option_output = NULL;
17+
char *option_suffix = "%Y-%m-%d-%H%M";
18+
char *prefixed_filename;
19+
20+
const struct option diagnose_options[] = {
21+
OPT_STRING('o', "output-directory", &option_output, N_("path"),
22+
N_("specify a destination for the diagnostics archive")),
23+
OPT_STRING('s', "suffix", &option_suffix, N_("format"),
24+
N_("specify a strftime format suffix for the filename")),
25+
OPT_CALLBACK_F(0, "mode", &mode, N_("(stats|all)"),
26+
N_("specify the content of the diagnostic archive"),
27+
PARSE_OPT_NONEG, option_parse_diagnose),
28+
OPT_END()
29+
};
30+
31+
argc = parse_options(argc, argv, prefix, diagnose_options,
32+
diagnose_usage, 0);
33+
34+
/* Prepare the path to put the result */
35+
prefixed_filename = prefix_filename(prefix,
36+
option_output ? option_output : "");
37+
strbuf_addstr(&zip_path, prefixed_filename);
38+
strbuf_complete(&zip_path, '/');
39+
40+
strbuf_addstr(&zip_path, "git-diagnostics-");
41+
strbuf_addftime(&zip_path, option_suffix, localtime_r(&now, &tm), 0, 0);
42+
strbuf_addstr(&zip_path, ".zip");
43+
44+
switch (safe_create_leading_directories(zip_path.buf)) {
45+
case SCLD_OK:
46+
case SCLD_EXISTS:
47+
break;
48+
default:
49+
die_errno(_("could not create leading directories for '%s'"),
50+
zip_path.buf);
51+
}
52+
53+
/* Prepare diagnostics */
54+
if (create_diagnostics_archive(&zip_path, mode))
55+
die_errno(_("unable to create diagnostics archive %s"),
56+
zip_path.buf);
57+
58+
free(prefixed_filename);
59+
strbuf_release(&zip_path);
60+
return 0;
61+
}

compat/disk.h

Lines changed: 56 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,56 @@
1+
#ifndef COMPAT_DISK_H
2+
#define COMPAT_DISK_H
3+
4+
#include "git-compat-util.h"
5+
6+
static int get_disk_info(struct strbuf *out)
7+
{
8+
struct strbuf buf = STRBUF_INIT;
9+
int res = 0;
10+
11+
#ifdef GIT_WINDOWS_NATIVE
12+
char volume_name[MAX_PATH], fs_name[MAX_PATH];
13+
DWORD serial_number, component_length, flags;
14+
ULARGE_INTEGER avail2caller, total, avail;
15+
16+
strbuf_realpath(&buf, ".", 1);
17+
if (!GetDiskFreeSpaceExA(buf.buf, &avail2caller, &total, &avail)) {
18+
error(_("could not determine free disk size for '%s'"),
19+
buf.buf);
20+
res = -1;
21+
goto cleanup;
22+
}
23+
24+
strbuf_setlen(&buf, offset_1st_component(buf.buf));
25+
if (!GetVolumeInformationA(buf.buf, volume_name, sizeof(volume_name),
26+
&serial_number, &component_length, &flags,
27+
fs_name, sizeof(fs_name))) {
28+
error(_("could not get info for '%s'"), buf.buf);
29+
res = -1;
30+
goto cleanup;
31+
}
32+
strbuf_addf(out, "Available space on '%s': ", buf.buf);
33+
strbuf_humanise_bytes(out, avail2caller.QuadPart);
34+
strbuf_addch(out, '\n');
35+
#else
36+
struct statvfs stat;
37+
38+
strbuf_realpath(&buf, ".", 1);
39+
if (statvfs(buf.buf, &stat) < 0) {
40+
error_errno(_("could not determine free disk size for '%s'"),
41+
buf.buf);
42+
res = -1;
43+
goto cleanup;
44+
}
45+
46+
strbuf_addf(out, "Available space on '%s': ", buf.buf);
47+
strbuf_humanise_bytes(out, (off_t)stat.f_bsize * (off_t)stat.f_bavail);
48+
strbuf_addf(out, " (mount flags 0x%lx)\n", stat.f_flag);
49+
#endif
50+
51+
cleanup:
52+
strbuf_release(&buf);
53+
return res;
54+
}
55+
56+
#endif /* COMPAT_DISK_H */

0 commit comments

Comments
 (0)