diff options
Diffstat (limited to 'builtin/gc.c')
-rw-r--r-- | builtin/gc.c | 90 |
1 files changed, 66 insertions, 24 deletions
diff --git a/builtin/gc.c b/builtin/gc.c index 5ae95cd466..9ff0204940 100644 --- a/builtin/gc.c +++ b/builtin/gc.c @@ -11,6 +11,7 @@ */ #include "builtin.h" +#include "tempfile.h" #include "lockfile.h" #include "parse-options.h" #include "run-command.h" @@ -21,7 +22,7 @@ #define FAILED_RUN "failed to run %s" static const char * const builtin_gc_usage[] = { - N_("git gc [options]"), + N_("git gc [<options>]"), NULL }; @@ -42,20 +43,8 @@ static struct argv_array prune = ARGV_ARRAY_INIT; static struct argv_array prune_worktrees = ARGV_ARRAY_INIT; static struct argv_array rerere = ARGV_ARRAY_INIT; -static char *pidfile; - -static void remove_pidfile(void) -{ - if (pidfile) - unlink(pidfile); -} - -static void remove_pidfile_on_signal(int signo) -{ - remove_pidfile(); - sigchain_pop(signo); - raise(signo); -} +static struct tempfile pidfile; +static struct lock_file log_lock; static void git_config_date_string(const char *key, const char **output) { @@ -68,6 +57,28 @@ static void git_config_date_string(const char *key, const char **output) } } +static void process_log_file(void) +{ + struct stat st; + if (!fstat(get_lock_file_fd(&log_lock), &st) && st.st_size) + commit_lock_file(&log_lock); + else + rollback_lock_file(&log_lock); +} + +static void process_log_file_at_exit(void) +{ + fflush(stderr); + process_log_file(); +} + +static void process_log_file_on_signal(int signo) +{ + process_log_file(); + sigchain_pop(signo); + raise(signo); +} + static void gc_config(void) { const char *value; @@ -199,20 +210,22 @@ static const char *lock_repo_for_gc(int force, pid_t* ret_pid) uintmax_t pid; FILE *fp; int fd; + char *pidfile_path; - if (pidfile) + if (is_tempfile_active(&pidfile)) /* already locked */ return NULL; if (gethostname(my_host, sizeof(my_host))) strcpy(my_host, "unknown"); - fd = hold_lock_file_for_update(&lock, git_path("gc.pid"), + pidfile_path = git_pathdup("gc.pid"); + fd = hold_lock_file_for_update(&lock, pidfile_path, LOCK_DIE_ON_ERROR); if (!force) { static char locking_host[128]; int should_exit; - fp = fopen(git_path("gc.pid"), "r"); + fp = fopen(pidfile_path, "r"); memset(locking_host, 0, sizeof(locking_host)); should_exit = fp != NULL && @@ -236,6 +249,7 @@ static const char *lock_repo_for_gc(int force, pid_t* ret_pid) if (fd >= 0) rollback_lock_file(&lock); *ret_pid = pid; + free(pidfile_path); return locking_host; } } @@ -245,14 +259,29 @@ static const char *lock_repo_for_gc(int force, pid_t* ret_pid) write_in_full(fd, sb.buf, sb.len); strbuf_release(&sb); commit_lock_file(&lock); - - pidfile = git_pathdup("gc.pid"); - sigchain_push_common(remove_pidfile_on_signal); - atexit(remove_pidfile); - + register_tempfile(&pidfile, pidfile_path); + free(pidfile_path); return NULL; } +static int report_last_gc_error(void) +{ + struct strbuf sb = STRBUF_INIT; + int ret; + + ret = strbuf_read_file(&sb, git_path("gc.log"), 0); + if (ret > 0) + return error(_("The last gc run reported the following. " + "Please correct the root cause\n" + "and remove %s.\n" + "Automatic cleanup will not be performed " + "until the file is removed.\n\n" + "%s"), + git_path("gc.log"), sb.buf); + strbuf_release(&sb); + return 0; +} + static int gc_before_repack(void) { if (pack_refs && run_command_v_opt(pack_refs_cmd.argv, RUN_GIT_CMD)) @@ -274,6 +303,7 @@ int cmd_gc(int argc, const char **argv, const char *prefix) int force = 0; const char *name; pid_t pid; + int daemonized = 0; struct option builtin_gc_options[] = { OPT__QUIET(&quiet, N_("suppress progress reporting")), @@ -330,13 +360,16 @@ int cmd_gc(int argc, const char **argv, const char *prefix) fprintf(stderr, _("See \"git help gc\" for manual housekeeping.\n")); } if (detach_auto) { + if (report_last_gc_error()) + return -1; + if (gc_before_repack()) return -1; /* * failure to daemonize is ok, we'll continue * in foreground */ - daemonize(); + daemonized = !daemonize(); } } else add_repack_all_option(); @@ -349,6 +382,15 @@ int cmd_gc(int argc, const char **argv, const char *prefix) name, (uintmax_t)pid); } + if (daemonized) { + hold_lock_file_for_update(&log_lock, + git_path("gc.log"), + LOCK_DIE_ON_ERROR); + dup2(get_lock_file_fd(&log_lock), 2); + sigchain_push_common(process_log_file_on_signal); + atexit(process_log_file_at_exit); + } + if (gc_before_repack()) return -1; |