]> git.ipfire.org Git - thirdparty/git.git/commitdiff
builtin/diagnose.c: create 'git diagnose' builtin
authorVictoria Dye <vdye@github.com>
Fri, 12 Aug 2022 20:10:15 +0000 (20:10 +0000)
committerJunio C Hamano <gitster@pobox.com>
Fri, 12 Aug 2022 20:20:02 +0000 (13:20 -0700)
Create a 'git diagnose' builtin to generate a standalone zip archive of
repository diagnostics.

The "diagnose" functionality was originally implemented for Scalar in
aa5c79a331 (scalar: implement `scalar diagnose`, 2022-05-28). However, the
diagnostics gathered are not specific to Scalar-cloned repositories and
can be useful when diagnosing issues in any Git repository.

Helped-by: Ævar Arnfjörð Bjarmason <avarab@gmail.com>
Helped-by: Derrick Stolee <derrickstolee@github.com>
Signed-off-by: Victoria Dye <vdye@github.com>
Signed-off-by: Junio C Hamano <gitster@pobox.com>
.gitignore
Documentation/git-diagnose.txt [new file with mode: 0644]
Makefile
builtin.h
builtin/diagnose.c [new file with mode: 0644]
git.c
t/t0092-diagnose.sh [new file with mode: 0755]

index 42fd7253b4435e014690ad173125e2a291c2ca5a..80b530bbed2c80814ac74956d329d277d85bba86 100644 (file)
@@ -53,6 +53,7 @@
 /git-cvsimport
 /git-cvsserver
 /git-daemon
+/git-diagnose
 /git-diff
 /git-diff-files
 /git-diff-index
diff --git a/Documentation/git-diagnose.txt b/Documentation/git-diagnose.txt
new file mode 100644 (file)
index 0000000..ce07dd0
--- /dev/null
@@ -0,0 +1,50 @@
+git-diagnose(1)
+================
+
+NAME
+----
+git-diagnose - Generate a zip archive of diagnostic information
+
+SYNOPSIS
+--------
+[verse]
+'git diagnose' [(-o | --output-directory) <path>] [(-s | --suffix) <format>]
+
+DESCRIPTION
+-----------
+Collects detailed information about the user's machine, Git client, and
+repository state and packages that information into a zip archive. The
+generated archive can then, for example, be shared with the Git mailing list to
+help debug an issue or serve as a reference for independent debugging.
+
+The following information is captured in the archive:
+
+  * 'git version --build-options'
+  * The path to the repository root
+  * The available disk space on the filesystem
+  * The name and size of each packfile, including those in alternate object
+    stores
+  * The total count of loose objects, as well as counts broken down by
+    `.git/objects` subdirectory
+
+This tool differs from linkgit:git-bugreport[1] in that it collects much more
+detailed information with a greater focus on reporting the size and data shape
+of repository contents.
+
+OPTIONS
+-------
+-o <path>::
+--output-directory <path>::
+       Place the resulting diagnostics archive in `<path>` instead of the
+       current directory.
+
+-s <format>::
+--suffix <format>::
+       Specify an alternate suffix for the diagnostics archive name, to create
+       a file named 'git-diagnostics-<formatted suffix>'. This should take the
+       form of a strftime(3) format string; the current local time will be
+       used.
+
+GIT
+---
+Part of the linkgit:git[1] suite
index ad27a0bd70c23e6a404c80ad77975844ad2448d0..9ceaf55582a709e8e44f97dc68c453eb51843240 100644 (file)
--- a/Makefile
+++ b/Makefile
@@ -1154,6 +1154,7 @@ BUILTIN_OBJS += builtin/credential-cache.o
 BUILTIN_OBJS += builtin/credential-store.o
 BUILTIN_OBJS += builtin/credential.o
 BUILTIN_OBJS += builtin/describe.o
+BUILTIN_OBJS += builtin/diagnose.o
 BUILTIN_OBJS += builtin/diff-files.o
 BUILTIN_OBJS += builtin/diff-index.o
 BUILTIN_OBJS += builtin/diff-tree.o
index 40e9ecc8485324a40e142d5cbc9345a22e45f333..8901a34d6bf424680b9d13a1bdf332bedb4d8e20 100644 (file)
--- a/builtin.h
+++ b/builtin.h
@@ -144,6 +144,7 @@ int cmd_credential_cache(int argc, const char **argv, const char *prefix);
 int cmd_credential_cache_daemon(int argc, const char **argv, const char *prefix);
 int cmd_credential_store(int argc, const char **argv, const char *prefix);
 int cmd_describe(int argc, const char **argv, const char *prefix);
+int cmd_diagnose(int argc, const char **argv, const char *prefix);
 int cmd_diff_files(int argc, const char **argv, const char *prefix);
 int cmd_diff_index(int argc, const char **argv, const char *prefix);
 int cmd_diff(int argc, const char **argv, const char *prefix);
diff --git a/builtin/diagnose.c b/builtin/diagnose.c
new file mode 100644 (file)
index 0000000..832493b
--- /dev/null
@@ -0,0 +1,57 @@
+#include "builtin.h"
+#include "parse-options.h"
+#include "diagnose.h"
+
+static const char * const diagnose_usage[] = {
+       N_("git diagnose [-o|--output-directory <path>] [-s|--suffix <format>]"),
+       NULL
+};
+
+int cmd_diagnose(int argc, const char **argv, const char *prefix)
+{
+       struct strbuf zip_path = STRBUF_INIT;
+       time_t now = time(NULL);
+       struct tm tm;
+       char *option_output = NULL;
+       char *option_suffix = "%Y-%m-%d-%H%M";
+       char *prefixed_filename;
+
+       const struct option diagnose_options[] = {
+               OPT_STRING('o', "output-directory", &option_output, N_("path"),
+                          N_("specify a destination for the diagnostics archive")),
+               OPT_STRING('s', "suffix", &option_suffix, N_("format"),
+                          N_("specify a strftime format suffix for the filename")),
+               OPT_END()
+       };
+
+       argc = parse_options(argc, argv, prefix, diagnose_options,
+                            diagnose_usage, 0);
+
+       /* Prepare the path to put the result */
+       prefixed_filename = prefix_filename(prefix,
+                                           option_output ? option_output : "");
+       strbuf_addstr(&zip_path, prefixed_filename);
+       strbuf_complete(&zip_path, '/');
+
+       strbuf_addstr(&zip_path, "git-diagnostics-");
+       strbuf_addftime(&zip_path, option_suffix, localtime_r(&now, &tm), 0, 0);
+       strbuf_addstr(&zip_path, ".zip");
+
+       switch (safe_create_leading_directories(zip_path.buf)) {
+       case SCLD_OK:
+       case SCLD_EXISTS:
+               break;
+       default:
+               die_errno(_("could not create leading directories for '%s'"),
+                         zip_path.buf);
+       }
+
+       /* Prepare diagnostics */
+       if (create_diagnostics_archive(&zip_path, DIAGNOSE_STATS))
+               die_errno(_("unable to create diagnostics archive %s"),
+                         zip_path.buf);
+
+       free(prefixed_filename);
+       strbuf_release(&zip_path);
+       return 0;
+}
diff --git a/git.c b/git.c
index e5d62fa5a92e95e1ede041ebf913d841744c31f8..0b9d8ef76776f3a1a011962b33b37d80fd21c4b2 100644 (file)
--- a/git.c
+++ b/git.c
@@ -522,6 +522,7 @@ static struct cmd_struct commands[] = {
        { "credential-cache--daemon", cmd_credential_cache_daemon },
        { "credential-store", cmd_credential_store },
        { "describe", cmd_describe, RUN_SETUP },
+       { "diagnose", cmd_diagnose, RUN_SETUP_GENTLY },
        { "diff", cmd_diff, NO_PARSEOPT },
        { "diff-files", cmd_diff_files, RUN_SETUP | NEED_WORK_TREE | NO_PARSEOPT },
        { "diff-index", cmd_diff_index, RUN_SETUP | NO_PARSEOPT },
diff --git a/t/t0092-diagnose.sh b/t/t0092-diagnose.sh
new file mode 100755 (executable)
index 0000000..b692372
--- /dev/null
@@ -0,0 +1,32 @@
+#!/bin/sh
+
+test_description='git diagnose'
+
+TEST_PASSES_SANITIZE_LEAK=true
+. ./test-lib.sh
+
+test_expect_success UNZIP 'creates diagnostics zip archive' '
+       test_when_finished rm -rf report &&
+
+       git diagnose -o report -s test >out &&
+       grep "Available space" out &&
+
+       zip_path=report/git-diagnostics-test.zip &&
+       test_path_is_file "$zip_path" &&
+
+       # Check zipped archive content
+       "$GIT_UNZIP" -p "$zip_path" diagnostics.log >out &&
+       test_file_not_empty out &&
+
+       "$GIT_UNZIP" -p "$zip_path" packs-local.txt >out &&
+       grep ".git/objects" out &&
+
+       "$GIT_UNZIP" -p "$zip_path" objects-local.txt >out &&
+       grep "^Total: [0-9][0-9]*" out &&
+
+       # Should not include .git directory contents by default
+       ! "$GIT_UNZIP" -l "$zip_path" | grep ".git/"
+       grep "^Total: [0-9][0-9]*" out
+'
+
+test_done