mirror of
https://github.com/git/git.git
synced 2024-12-18 06:14:59 +08:00
bb2c34956a
Move the core functionality of 'scalar diagnose' into a new 'diagnose.[c,h]' library to prepare for new callers in the main Git tree generating diagnostic archives. These callers will be introduced in subsequent patches. While this patch appears large, it is mostly made up of moving code out of 'scalar.c' and into 'diagnose.c'. Specifically, the functions - dir_file_stats_objects() - dir_file_stats() - count_files() - loose_objs_stats() - add_directory_to_archiver() are all copied verbatim from 'scalar.c'. The 'create_diagnostics_archive()' function is a mostly identical (partial) copy of 'cmd_diagnose()', with the primary changes being that 'zip_path' is an input and "Enlistment root" is corrected to "Repository root" in the archiver log. Helped-by: Ævar Arnfjörð Bjarmason <avarab@gmail.com> Signed-off-by: Victoria Dye <vdye@github.com> Signed-off-by: Junio C Hamano <gitster@pobox.com>
217 lines
5.5 KiB
C
217 lines
5.5 KiB
C
#include "cache.h"
|
|
#include "diagnose.h"
|
|
#include "compat/disk.h"
|
|
#include "archive.h"
|
|
#include "dir.h"
|
|
#include "help.h"
|
|
#include "strvec.h"
|
|
#include "object-store.h"
|
|
#include "packfile.h"
|
|
|
|
static void dir_file_stats_objects(const char *full_path, size_t full_path_len,
|
|
const char *file_name, void *data)
|
|
{
|
|
struct strbuf *buf = data;
|
|
struct stat st;
|
|
|
|
if (!stat(full_path, &st))
|
|
strbuf_addf(buf, "%-70s %16" PRIuMAX "\n", file_name,
|
|
(uintmax_t)st.st_size);
|
|
}
|
|
|
|
static int dir_file_stats(struct object_directory *object_dir, void *data)
|
|
{
|
|
struct strbuf *buf = data;
|
|
|
|
strbuf_addf(buf, "Contents of %s:\n", object_dir->path);
|
|
|
|
for_each_file_in_pack_dir(object_dir->path, dir_file_stats_objects,
|
|
data);
|
|
|
|
return 0;
|
|
}
|
|
|
|
static int count_files(char *path)
|
|
{
|
|
DIR *dir = opendir(path);
|
|
struct dirent *e;
|
|
int count = 0;
|
|
|
|
if (!dir)
|
|
return 0;
|
|
|
|
while ((e = readdir(dir)) != NULL)
|
|
if (!is_dot_or_dotdot(e->d_name) && e->d_type == DT_REG)
|
|
count++;
|
|
|
|
closedir(dir);
|
|
return count;
|
|
}
|
|
|
|
static void loose_objs_stats(struct strbuf *buf, const char *path)
|
|
{
|
|
DIR *dir = opendir(path);
|
|
struct dirent *e;
|
|
int count;
|
|
int total = 0;
|
|
unsigned char c;
|
|
struct strbuf count_path = STRBUF_INIT;
|
|
size_t base_path_len;
|
|
|
|
if (!dir)
|
|
return;
|
|
|
|
strbuf_addstr(buf, "Object directory stats for ");
|
|
strbuf_add_absolute_path(buf, path);
|
|
strbuf_addstr(buf, ":\n");
|
|
|
|
strbuf_add_absolute_path(&count_path, path);
|
|
strbuf_addch(&count_path, '/');
|
|
base_path_len = count_path.len;
|
|
|
|
while ((e = readdir(dir)) != NULL)
|
|
if (!is_dot_or_dotdot(e->d_name) &&
|
|
e->d_type == DT_DIR && strlen(e->d_name) == 2 &&
|
|
!hex_to_bytes(&c, e->d_name, 1)) {
|
|
strbuf_setlen(&count_path, base_path_len);
|
|
strbuf_addstr(&count_path, e->d_name);
|
|
total += (count = count_files(count_path.buf));
|
|
strbuf_addf(buf, "%s : %7d files\n", e->d_name, count);
|
|
}
|
|
|
|
strbuf_addf(buf, "Total: %d loose objects", total);
|
|
|
|
strbuf_release(&count_path);
|
|
closedir(dir);
|
|
}
|
|
|
|
static int add_directory_to_archiver(struct strvec *archiver_args,
|
|
const char *path, int recurse)
|
|
{
|
|
int at_root = !*path;
|
|
DIR *dir;
|
|
struct dirent *e;
|
|
struct strbuf buf = STRBUF_INIT;
|
|
size_t len;
|
|
int res = 0;
|
|
|
|
dir = opendir(at_root ? "." : path);
|
|
if (!dir) {
|
|
if (errno == ENOENT) {
|
|
warning(_("could not archive missing directory '%s'"), path);
|
|
return 0;
|
|
}
|
|
return error_errno(_("could not open directory '%s'"), path);
|
|
}
|
|
|
|
if (!at_root)
|
|
strbuf_addf(&buf, "%s/", path);
|
|
len = buf.len;
|
|
strvec_pushf(archiver_args, "--prefix=%s", buf.buf);
|
|
|
|
while (!res && (e = readdir(dir))) {
|
|
if (!strcmp(".", e->d_name) || !strcmp("..", e->d_name))
|
|
continue;
|
|
|
|
strbuf_setlen(&buf, len);
|
|
strbuf_addstr(&buf, e->d_name);
|
|
|
|
if (e->d_type == DT_REG)
|
|
strvec_pushf(archiver_args, "--add-file=%s", buf.buf);
|
|
else if (e->d_type != DT_DIR)
|
|
warning(_("skipping '%s', which is neither file nor "
|
|
"directory"), buf.buf);
|
|
else if (recurse &&
|
|
add_directory_to_archiver(archiver_args,
|
|
buf.buf, recurse) < 0)
|
|
res = -1;
|
|
}
|
|
|
|
closedir(dir);
|
|
strbuf_release(&buf);
|
|
return res;
|
|
}
|
|
|
|
int create_diagnostics_archive(struct strbuf *zip_path)
|
|
{
|
|
struct strvec archiver_args = STRVEC_INIT;
|
|
char **argv_copy = NULL;
|
|
int stdout_fd = -1, archiver_fd = -1;
|
|
struct strbuf buf = STRBUF_INIT;
|
|
int res;
|
|
|
|
stdout_fd = dup(STDOUT_FILENO);
|
|
if (stdout_fd < 0) {
|
|
res = error_errno(_("could not duplicate stdout"));
|
|
goto diagnose_cleanup;
|
|
}
|
|
|
|
archiver_fd = xopen(zip_path->buf, O_CREAT | O_WRONLY | O_TRUNC, 0666);
|
|
if (dup2(archiver_fd, STDOUT_FILENO) < 0) {
|
|
res = error_errno(_("could not redirect output"));
|
|
goto diagnose_cleanup;
|
|
}
|
|
|
|
init_zip_archiver();
|
|
strvec_pushl(&archiver_args, "git-diagnose", "--format=zip", NULL);
|
|
|
|
strbuf_reset(&buf);
|
|
strbuf_addstr(&buf, "Collecting diagnostic info\n\n");
|
|
get_version_info(&buf, 1);
|
|
|
|
strbuf_addf(&buf, "Repository root: %s\n", the_repository->worktree);
|
|
get_disk_info(&buf);
|
|
write_or_die(stdout_fd, buf.buf, buf.len);
|
|
strvec_pushf(&archiver_args,
|
|
"--add-virtual-file=diagnostics.log:%.*s",
|
|
(int)buf.len, buf.buf);
|
|
|
|
strbuf_reset(&buf);
|
|
strbuf_addstr(&buf, "--add-virtual-file=packs-local.txt:");
|
|
dir_file_stats(the_repository->objects->odb, &buf);
|
|
foreach_alt_odb(dir_file_stats, &buf);
|
|
strvec_push(&archiver_args, buf.buf);
|
|
|
|
strbuf_reset(&buf);
|
|
strbuf_addstr(&buf, "--add-virtual-file=objects-local.txt:");
|
|
loose_objs_stats(&buf, ".git/objects");
|
|
strvec_push(&archiver_args, buf.buf);
|
|
|
|
if ((res = add_directory_to_archiver(&archiver_args, ".git", 0)) ||
|
|
(res = add_directory_to_archiver(&archiver_args, ".git/hooks", 0)) ||
|
|
(res = add_directory_to_archiver(&archiver_args, ".git/info", 0)) ||
|
|
(res = add_directory_to_archiver(&archiver_args, ".git/logs", 1)) ||
|
|
(res = add_directory_to_archiver(&archiver_args, ".git/objects/info", 0)))
|
|
goto diagnose_cleanup;
|
|
|
|
strvec_pushl(&archiver_args, "--prefix=",
|
|
oid_to_hex(the_hash_algo->empty_tree), "--", NULL);
|
|
|
|
/* `write_archive()` modifies the `argv` passed to it. Let it. */
|
|
argv_copy = xmemdupz(archiver_args.v,
|
|
sizeof(char *) * archiver_args.nr);
|
|
res = write_archive(archiver_args.nr, (const char **)argv_copy, NULL,
|
|
the_repository, NULL, 0);
|
|
if (res) {
|
|
error(_("failed to write archive"));
|
|
goto diagnose_cleanup;
|
|
}
|
|
|
|
fprintf(stderr, "\n"
|
|
"Diagnostics complete.\n"
|
|
"All of the gathered info is captured in '%s'\n",
|
|
zip_path->buf);
|
|
|
|
diagnose_cleanup:
|
|
if (archiver_fd >= 0) {
|
|
dup2(stdout_fd, STDOUT_FILENO);
|
|
close(stdout_fd);
|
|
close(archiver_fd);
|
|
}
|
|
free(argv_copy);
|
|
strvec_clear(&archiver_args);
|
|
strbuf_release(&buf);
|
|
|
|
return res;
|
|
}
|