gc: save log from daemonized gc --auto and print it next time
[gitweb.git] / builtin / gc.c
index 005adbebea80a83a8d0dbb1de744cb50bf689de6..47fc1a6547f1aea81c7c86f62349791a7306a844 100644 (file)
@@ -41,6 +41,7 @@ static struct argv_array prune = ARGV_ARRAY_INIT;
 static struct argv_array rerere = ARGV_ARRAY_INIT;
 
 static char *pidfile;
+static struct lock_file log_lock;
 
 static void remove_pidfile(void)
 {
@@ -55,6 +56,28 @@ static void remove_pidfile_on_signal(int signo)
        raise(signo);
 }
 
+static void process_log_file(void)
+{
+       struct stat st;
+       if (!fstat(log_lock.fd, &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;
@@ -248,6 +271,24 @@ static const char *lock_repo_for_gc(int force, pid_t* ret_pid)
        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))
@@ -269,6 +310,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")),
@@ -324,13 +366,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();
@@ -343,6 +388,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(log_lock.fd, 2);
+               sigchain_push_common(process_log_file_on_signal);
+               atexit(process_log_file_at_exit);
+       }
+
        if (gc_before_repack())
                return -1;