Merge branch 'pk/subsub-fetch-fix-take-2' into maint
[git] / builtin / gc.c
1 /*
2  * git gc builtin command
3  *
4  * Cleanup unreachable files and optimize the repository.
5  *
6  * Copyright (c) 2007 James Bowes
7  *
8  * Based on git-gc.sh, which is
9  *
10  * Copyright (c) 2006 Shawn O. Pearce
11  */
12
13 #include "builtin.h"
14 #include "repository.h"
15 #include "config.h"
16 #include "tempfile.h"
17 #include "lockfile.h"
18 #include "parse-options.h"
19 #include "run-command.h"
20 #include "sigchain.h"
21 #include "strvec.h"
22 #include "commit.h"
23 #include "commit-graph.h"
24 #include "packfile.h"
25 #include "object-store.h"
26 #include "pack.h"
27 #include "pack-objects.h"
28 #include "blob.h"
29 #include "tree.h"
30 #include "promisor-remote.h"
31 #include "refs.h"
32 #include "remote.h"
33 #include "object-store.h"
34 #include "exec-cmd.h"
35
36 #define FAILED_RUN "failed to run %s"
37
38 static const char * const builtin_gc_usage[] = {
39         N_("git gc [<options>]"),
40         NULL
41 };
42
43 static int pack_refs = 1;
44 static int prune_reflogs = 1;
45 static int aggressive_depth = 50;
46 static int aggressive_window = 250;
47 static int gc_auto_threshold = 6700;
48 static int gc_auto_pack_limit = 50;
49 static int detach_auto = 1;
50 static timestamp_t gc_log_expire_time;
51 static const char *gc_log_expire = "1.day.ago";
52 static const char *prune_expire = "2.weeks.ago";
53 static const char *prune_worktrees_expire = "3.months.ago";
54 static unsigned long big_pack_threshold;
55 static unsigned long max_delta_cache_size = DEFAULT_DELTA_CACHE_SIZE;
56
57 static struct strvec pack_refs_cmd = STRVEC_INIT;
58 static struct strvec reflog = STRVEC_INIT;
59 static struct strvec repack = STRVEC_INIT;
60 static struct strvec prune = STRVEC_INIT;
61 static struct strvec prune_worktrees = STRVEC_INIT;
62 static struct strvec rerere = STRVEC_INIT;
63
64 static struct tempfile *pidfile;
65 static struct lock_file log_lock;
66
67 static struct string_list pack_garbage = STRING_LIST_INIT_DUP;
68
69 static void clean_pack_garbage(void)
70 {
71         int i;
72         for (i = 0; i < pack_garbage.nr; i++)
73                 unlink_or_warn(pack_garbage.items[i].string);
74         string_list_clear(&pack_garbage, 0);
75 }
76
77 static void report_pack_garbage(unsigned seen_bits, const char *path)
78 {
79         if (seen_bits == PACKDIR_FILE_IDX)
80                 string_list_append(&pack_garbage, path);
81 }
82
83 static void process_log_file(void)
84 {
85         struct stat st;
86         if (fstat(get_lock_file_fd(&log_lock), &st)) {
87                 /*
88                  * Perhaps there was an i/o error or another
89                  * unlikely situation.  Try to make a note of
90                  * this in gc.log along with any existing
91                  * messages.
92                  */
93                 int saved_errno = errno;
94                 fprintf(stderr, _("Failed to fstat %s: %s"),
95                         get_tempfile_path(log_lock.tempfile),
96                         strerror(saved_errno));
97                 fflush(stderr);
98                 commit_lock_file(&log_lock);
99                 errno = saved_errno;
100         } else if (st.st_size) {
101                 /* There was some error recorded in the lock file */
102                 commit_lock_file(&log_lock);
103         } else {
104                 /* No error, clean up any old gc.log */
105                 unlink(git_path("gc.log"));
106                 rollback_lock_file(&log_lock);
107         }
108 }
109
110 static void process_log_file_at_exit(void)
111 {
112         fflush(stderr);
113         process_log_file();
114 }
115
116 static void process_log_file_on_signal(int signo)
117 {
118         process_log_file();
119         sigchain_pop(signo);
120         raise(signo);
121 }
122
123 static int gc_config_is_timestamp_never(const char *var)
124 {
125         const char *value;
126         timestamp_t expire;
127
128         if (!git_config_get_value(var, &value) && value) {
129                 if (parse_expiry_date(value, &expire))
130                         die(_("failed to parse '%s' value '%s'"), var, value);
131                 return expire == 0;
132         }
133         return 0;
134 }
135
136 static void gc_config(void)
137 {
138         const char *value;
139
140         if (!git_config_get_value("gc.packrefs", &value)) {
141                 if (value && !strcmp(value, "notbare"))
142                         pack_refs = -1;
143                 else
144                         pack_refs = git_config_bool("gc.packrefs", value);
145         }
146
147         if (gc_config_is_timestamp_never("gc.reflogexpire") &&
148             gc_config_is_timestamp_never("gc.reflogexpireunreachable"))
149                 prune_reflogs = 0;
150
151         git_config_get_int("gc.aggressivewindow", &aggressive_window);
152         git_config_get_int("gc.aggressivedepth", &aggressive_depth);
153         git_config_get_int("gc.auto", &gc_auto_threshold);
154         git_config_get_int("gc.autopacklimit", &gc_auto_pack_limit);
155         git_config_get_bool("gc.autodetach", &detach_auto);
156         git_config_get_expiry("gc.pruneexpire", &prune_expire);
157         git_config_get_expiry("gc.worktreepruneexpire", &prune_worktrees_expire);
158         git_config_get_expiry("gc.logexpiry", &gc_log_expire);
159
160         git_config_get_ulong("gc.bigpackthreshold", &big_pack_threshold);
161         git_config_get_ulong("pack.deltacachesize", &max_delta_cache_size);
162
163         git_config(git_default_config, NULL);
164 }
165
166 static int too_many_loose_objects(void)
167 {
168         /*
169          * Quickly check if a "gc" is needed, by estimating how
170          * many loose objects there are.  Because SHA-1 is evenly
171          * distributed, we can check only one and get a reasonable
172          * estimate.
173          */
174         DIR *dir;
175         struct dirent *ent;
176         int auto_threshold;
177         int num_loose = 0;
178         int needed = 0;
179         const unsigned hexsz_loose = the_hash_algo->hexsz - 2;
180
181         dir = opendir(git_path("objects/17"));
182         if (!dir)
183                 return 0;
184
185         auto_threshold = DIV_ROUND_UP(gc_auto_threshold, 256);
186         while ((ent = readdir(dir)) != NULL) {
187                 if (strspn(ent->d_name, "0123456789abcdef") != hexsz_loose ||
188                     ent->d_name[hexsz_loose] != '\0')
189                         continue;
190                 if (++num_loose > auto_threshold) {
191                         needed = 1;
192                         break;
193                 }
194         }
195         closedir(dir);
196         return needed;
197 }
198
199 static struct packed_git *find_base_packs(struct string_list *packs,
200                                           unsigned long limit)
201 {
202         struct packed_git *p, *base = NULL;
203
204         for (p = get_all_packs(the_repository); p; p = p->next) {
205                 if (!p->pack_local)
206                         continue;
207                 if (limit) {
208                         if (p->pack_size >= limit)
209                                 string_list_append(packs, p->pack_name);
210                 } else if (!base || base->pack_size < p->pack_size) {
211                         base = p;
212                 }
213         }
214
215         if (base)
216                 string_list_append(packs, base->pack_name);
217
218         return base;
219 }
220
221 static int too_many_packs(void)
222 {
223         struct packed_git *p;
224         int cnt;
225
226         if (gc_auto_pack_limit <= 0)
227                 return 0;
228
229         for (cnt = 0, p = get_all_packs(the_repository); p; p = p->next) {
230                 if (!p->pack_local)
231                         continue;
232                 if (p->pack_keep)
233                         continue;
234                 /*
235                  * Perhaps check the size of the pack and count only
236                  * very small ones here?
237                  */
238                 cnt++;
239         }
240         return gc_auto_pack_limit < cnt;
241 }
242
243 static uint64_t total_ram(void)
244 {
245 #if defined(HAVE_SYSINFO)
246         struct sysinfo si;
247
248         if (!sysinfo(&si))
249                 return si.totalram;
250 #elif defined(HAVE_BSD_SYSCTL) && (defined(HW_MEMSIZE) || defined(HW_PHYSMEM))
251         int64_t physical_memory;
252         int mib[2];
253         size_t length;
254
255         mib[0] = CTL_HW;
256 # if defined(HW_MEMSIZE)
257         mib[1] = HW_MEMSIZE;
258 # else
259         mib[1] = HW_PHYSMEM;
260 # endif
261         length = sizeof(int64_t);
262         if (!sysctl(mib, 2, &physical_memory, &length, NULL, 0))
263                 return physical_memory;
264 #elif defined(GIT_WINDOWS_NATIVE)
265         MEMORYSTATUSEX memInfo;
266
267         memInfo.dwLength = sizeof(MEMORYSTATUSEX);
268         if (GlobalMemoryStatusEx(&memInfo))
269                 return memInfo.ullTotalPhys;
270 #endif
271         return 0;
272 }
273
274 static uint64_t estimate_repack_memory(struct packed_git *pack)
275 {
276         unsigned long nr_objects = approximate_object_count();
277         size_t os_cache, heap;
278
279         if (!pack || !nr_objects)
280                 return 0;
281
282         /*
283          * First we have to scan through at least one pack.
284          * Assume enough room in OS file cache to keep the entire pack
285          * or we may accidentally evict data of other processes from
286          * the cache.
287          */
288         os_cache = pack->pack_size + pack->index_size;
289         /* then pack-objects needs lots more for book keeping */
290         heap = sizeof(struct object_entry) * nr_objects;
291         /*
292          * internal rev-list --all --objects takes up some memory too,
293          * let's say half of it is for blobs
294          */
295         heap += sizeof(struct blob) * nr_objects / 2;
296         /*
297          * and the other half is for trees (commits and tags are
298          * usually insignificant)
299          */
300         heap += sizeof(struct tree) * nr_objects / 2;
301         /* and then obj_hash[], underestimated in fact */
302         heap += sizeof(struct object *) * nr_objects;
303         /* revindex is used also */
304         heap += sizeof(struct revindex_entry) * nr_objects;
305         /*
306          * read_sha1_file() (either at delta calculation phase, or
307          * writing phase) also fills up the delta base cache
308          */
309         heap += delta_base_cache_limit;
310         /* and of course pack-objects has its own delta cache */
311         heap += max_delta_cache_size;
312
313         return os_cache + heap;
314 }
315
316 static int keep_one_pack(struct string_list_item *item, void *data)
317 {
318         strvec_pushf(&repack, "--keep-pack=%s", basename(item->string));
319         return 0;
320 }
321
322 static void add_repack_all_option(struct string_list *keep_pack)
323 {
324         if (prune_expire && !strcmp(prune_expire, "now"))
325                 strvec_push(&repack, "-a");
326         else {
327                 strvec_push(&repack, "-A");
328                 if (prune_expire)
329                         strvec_pushf(&repack, "--unpack-unreachable=%s", prune_expire);
330         }
331
332         if (keep_pack)
333                 for_each_string_list(keep_pack, keep_one_pack, NULL);
334 }
335
336 static void add_repack_incremental_option(void)
337 {
338         strvec_push(&repack, "--no-write-bitmap-index");
339 }
340
341 static int need_to_gc(void)
342 {
343         /*
344          * Setting gc.auto to 0 or negative can disable the
345          * automatic gc.
346          */
347         if (gc_auto_threshold <= 0)
348                 return 0;
349
350         /*
351          * If there are too many loose objects, but not too many
352          * packs, we run "repack -d -l".  If there are too many packs,
353          * we run "repack -A -d -l".  Otherwise we tell the caller
354          * there is no need.
355          */
356         if (too_many_packs()) {
357                 struct string_list keep_pack = STRING_LIST_INIT_NODUP;
358
359                 if (big_pack_threshold) {
360                         find_base_packs(&keep_pack, big_pack_threshold);
361                         if (keep_pack.nr >= gc_auto_pack_limit) {
362                                 big_pack_threshold = 0;
363                                 string_list_clear(&keep_pack, 0);
364                                 find_base_packs(&keep_pack, 0);
365                         }
366                 } else {
367                         struct packed_git *p = find_base_packs(&keep_pack, 0);
368                         uint64_t mem_have, mem_want;
369
370                         mem_have = total_ram();
371                         mem_want = estimate_repack_memory(p);
372
373                         /*
374                          * Only allow 1/2 of memory for pack-objects, leave
375                          * the rest for the OS and other processes in the
376                          * system.
377                          */
378                         if (!mem_have || mem_want < mem_have / 2)
379                                 string_list_clear(&keep_pack, 0);
380                 }
381
382                 add_repack_all_option(&keep_pack);
383                 string_list_clear(&keep_pack, 0);
384         } else if (too_many_loose_objects())
385                 add_repack_incremental_option();
386         else
387                 return 0;
388
389         if (run_hook_le(NULL, "pre-auto-gc", NULL))
390                 return 0;
391         return 1;
392 }
393
394 /* return NULL on success, else hostname running the gc */
395 static const char *lock_repo_for_gc(int force, pid_t* ret_pid)
396 {
397         struct lock_file lock = LOCK_INIT;
398         char my_host[HOST_NAME_MAX + 1];
399         struct strbuf sb = STRBUF_INIT;
400         struct stat st;
401         uintmax_t pid;
402         FILE *fp;
403         int fd;
404         char *pidfile_path;
405
406         if (is_tempfile_active(pidfile))
407                 /* already locked */
408                 return NULL;
409
410         if (xgethostname(my_host, sizeof(my_host)))
411                 xsnprintf(my_host, sizeof(my_host), "unknown");
412
413         pidfile_path = git_pathdup("gc.pid");
414         fd = hold_lock_file_for_update(&lock, pidfile_path,
415                                        LOCK_DIE_ON_ERROR);
416         if (!force) {
417                 static char locking_host[HOST_NAME_MAX + 1];
418                 static char *scan_fmt;
419                 int should_exit;
420
421                 if (!scan_fmt)
422                         scan_fmt = xstrfmt("%s %%%ds", "%"SCNuMAX, HOST_NAME_MAX);
423                 fp = fopen(pidfile_path, "r");
424                 memset(locking_host, 0, sizeof(locking_host));
425                 should_exit =
426                         fp != NULL &&
427                         !fstat(fileno(fp), &st) &&
428                         /*
429                          * 12 hour limit is very generous as gc should
430                          * never take that long. On the other hand we
431                          * don't really need a strict limit here,
432                          * running gc --auto one day late is not a big
433                          * problem. --force can be used in manual gc
434                          * after the user verifies that no gc is
435                          * running.
436                          */
437                         time(NULL) - st.st_mtime <= 12 * 3600 &&
438                         fscanf(fp, scan_fmt, &pid, locking_host) == 2 &&
439                         /* be gentle to concurrent "gc" on remote hosts */
440                         (strcmp(locking_host, my_host) || !kill(pid, 0) || errno == EPERM);
441                 if (fp != NULL)
442                         fclose(fp);
443                 if (should_exit) {
444                         if (fd >= 0)
445                                 rollback_lock_file(&lock);
446                         *ret_pid = pid;
447                         free(pidfile_path);
448                         return locking_host;
449                 }
450         }
451
452         strbuf_addf(&sb, "%"PRIuMAX" %s",
453                     (uintmax_t) getpid(), my_host);
454         write_in_full(fd, sb.buf, sb.len);
455         strbuf_release(&sb);
456         commit_lock_file(&lock);
457         pidfile = register_tempfile(pidfile_path);
458         free(pidfile_path);
459         return NULL;
460 }
461
462 /*
463  * Returns 0 if there was no previous error and gc can proceed, 1 if
464  * gc should not proceed due to an error in the last run. Prints a
465  * message and returns -1 if an error occurred while reading gc.log
466  */
467 static int report_last_gc_error(void)
468 {
469         struct strbuf sb = STRBUF_INIT;
470         int ret = 0;
471         ssize_t len;
472         struct stat st;
473         char *gc_log_path = git_pathdup("gc.log");
474
475         if (stat(gc_log_path, &st)) {
476                 if (errno == ENOENT)
477                         goto done;
478
479                 ret = error_errno(_("cannot stat '%s'"), gc_log_path);
480                 goto done;
481         }
482
483         if (st.st_mtime < gc_log_expire_time)
484                 goto done;
485
486         len = strbuf_read_file(&sb, gc_log_path, 0);
487         if (len < 0)
488                 ret = error_errno(_("cannot read '%s'"), gc_log_path);
489         else if (len > 0) {
490                 /*
491                  * A previous gc failed.  Report the error, and don't
492                  * bother with an automatic gc run since it is likely
493                  * to fail in the same way.
494                  */
495                 warning(_("The last gc run reported the following. "
496                                "Please correct the root cause\n"
497                                "and remove %s.\n"
498                                "Automatic cleanup will not be performed "
499                                "until the file is removed.\n\n"
500                                "%s"),
501                             gc_log_path, sb.buf);
502                 ret = 1;
503         }
504         strbuf_release(&sb);
505 done:
506         free(gc_log_path);
507         return ret;
508 }
509
510 static void gc_before_repack(void)
511 {
512         /*
513          * We may be called twice, as both the pre- and
514          * post-daemonized phases will call us, but running these
515          * commands more than once is pointless and wasteful.
516          */
517         static int done = 0;
518         if (done++)
519                 return;
520
521         if (pack_refs && run_command_v_opt(pack_refs_cmd.v, RUN_GIT_CMD))
522                 die(FAILED_RUN, pack_refs_cmd.v[0]);
523
524         if (prune_reflogs && run_command_v_opt(reflog.v, RUN_GIT_CMD))
525                 die(FAILED_RUN, reflog.v[0]);
526 }
527
528 int cmd_gc(int argc, const char **argv, const char *prefix)
529 {
530         int aggressive = 0;
531         int auto_gc = 0;
532         int quiet = 0;
533         int force = 0;
534         const char *name;
535         pid_t pid;
536         int daemonized = 0;
537         int keep_largest_pack = -1;
538         timestamp_t dummy;
539
540         struct option builtin_gc_options[] = {
541                 OPT__QUIET(&quiet, N_("suppress progress reporting")),
542                 { OPTION_STRING, 0, "prune", &prune_expire, N_("date"),
543                         N_("prune unreferenced objects"),
544                         PARSE_OPT_OPTARG, NULL, (intptr_t)prune_expire },
545                 OPT_BOOL(0, "aggressive", &aggressive, N_("be more thorough (increased runtime)")),
546                 OPT_BOOL_F(0, "auto", &auto_gc, N_("enable auto-gc mode"),
547                            PARSE_OPT_NOCOMPLETE),
548                 OPT_BOOL_F(0, "force", &force,
549                            N_("force running gc even if there may be another gc running"),
550                            PARSE_OPT_NOCOMPLETE),
551                 OPT_BOOL(0, "keep-largest-pack", &keep_largest_pack,
552                          N_("repack all other packs except the largest pack")),
553                 OPT_END()
554         };
555
556         if (argc == 2 && !strcmp(argv[1], "-h"))
557                 usage_with_options(builtin_gc_usage, builtin_gc_options);
558
559         strvec_pushl(&pack_refs_cmd, "pack-refs", "--all", "--prune", NULL);
560         strvec_pushl(&reflog, "reflog", "expire", "--all", NULL);
561         strvec_pushl(&repack, "repack", "-d", "-l", NULL);
562         strvec_pushl(&prune, "prune", "--expire", NULL);
563         strvec_pushl(&prune_worktrees, "worktree", "prune", "--expire", NULL);
564         strvec_pushl(&rerere, "rerere", "gc", NULL);
565
566         /* default expiry time, overwritten in gc_config */
567         gc_config();
568         if (parse_expiry_date(gc_log_expire, &gc_log_expire_time))
569                 die(_("failed to parse gc.logexpiry value %s"), gc_log_expire);
570
571         if (pack_refs < 0)
572                 pack_refs = !is_bare_repository();
573
574         argc = parse_options(argc, argv, prefix, builtin_gc_options,
575                              builtin_gc_usage, 0);
576         if (argc > 0)
577                 usage_with_options(builtin_gc_usage, builtin_gc_options);
578
579         if (prune_expire && parse_expiry_date(prune_expire, &dummy))
580                 die(_("failed to parse prune expiry value %s"), prune_expire);
581
582         if (aggressive) {
583                 strvec_push(&repack, "-f");
584                 if (aggressive_depth > 0)
585                         strvec_pushf(&repack, "--depth=%d", aggressive_depth);
586                 if (aggressive_window > 0)
587                         strvec_pushf(&repack, "--window=%d", aggressive_window);
588         }
589         if (quiet)
590                 strvec_push(&repack, "-q");
591
592         if (auto_gc) {
593                 /*
594                  * Auto-gc should be least intrusive as possible.
595                  */
596                 if (!need_to_gc())
597                         return 0;
598                 if (!quiet) {
599                         if (detach_auto)
600                                 fprintf(stderr, _("Auto packing the repository in background for optimum performance.\n"));
601                         else
602                                 fprintf(stderr, _("Auto packing the repository for optimum performance.\n"));
603                         fprintf(stderr, _("See \"git help gc\" for manual housekeeping.\n"));
604                 }
605                 if (detach_auto) {
606                         int ret = report_last_gc_error();
607                         if (ret < 0)
608                                 /* an I/O error occurred, already reported */
609                                 exit(128);
610                         if (ret == 1)
611                                 /* Last gc --auto failed. Skip this one. */
612                                 return 0;
613
614                         if (lock_repo_for_gc(force, &pid))
615                                 return 0;
616                         gc_before_repack(); /* dies on failure */
617                         delete_tempfile(&pidfile);
618
619                         /*
620                          * failure to daemonize is ok, we'll continue
621                          * in foreground
622                          */
623                         daemonized = !daemonize();
624                 }
625         } else {
626                 struct string_list keep_pack = STRING_LIST_INIT_NODUP;
627
628                 if (keep_largest_pack != -1) {
629                         if (keep_largest_pack)
630                                 find_base_packs(&keep_pack, 0);
631                 } else if (big_pack_threshold) {
632                         find_base_packs(&keep_pack, big_pack_threshold);
633                 }
634
635                 add_repack_all_option(&keep_pack);
636                 string_list_clear(&keep_pack, 0);
637         }
638
639         name = lock_repo_for_gc(force, &pid);
640         if (name) {
641                 if (auto_gc)
642                         return 0; /* be quiet on --auto */
643                 die(_("gc is already running on machine '%s' pid %"PRIuMAX" (use --force if not)"),
644                     name, (uintmax_t)pid);
645         }
646
647         if (daemonized) {
648                 hold_lock_file_for_update(&log_lock,
649                                           git_path("gc.log"),
650                                           LOCK_DIE_ON_ERROR);
651                 dup2(get_lock_file_fd(&log_lock), 2);
652                 sigchain_push_common(process_log_file_on_signal);
653                 atexit(process_log_file_at_exit);
654         }
655
656         gc_before_repack();
657
658         if (!repository_format_precious_objects) {
659                 close_object_store(the_repository->objects);
660                 if (run_command_v_opt(repack.v, RUN_GIT_CMD))
661                         die(FAILED_RUN, repack.v[0]);
662
663                 if (prune_expire) {
664                         strvec_push(&prune, prune_expire);
665                         if (quiet)
666                                 strvec_push(&prune, "--no-progress");
667                         if (has_promisor_remote())
668                                 strvec_push(&prune,
669                                             "--exclude-promisor-objects");
670                         if (run_command_v_opt(prune.v, RUN_GIT_CMD))
671                                 die(FAILED_RUN, prune.v[0]);
672                 }
673         }
674
675         if (prune_worktrees_expire) {
676                 strvec_push(&prune_worktrees, prune_worktrees_expire);
677                 if (run_command_v_opt(prune_worktrees.v, RUN_GIT_CMD))
678                         die(FAILED_RUN, prune_worktrees.v[0]);
679         }
680
681         if (run_command_v_opt(rerere.v, RUN_GIT_CMD))
682                 die(FAILED_RUN, rerere.v[0]);
683
684         report_garbage = report_pack_garbage;
685         reprepare_packed_git(the_repository);
686         if (pack_garbage.nr > 0) {
687                 close_object_store(the_repository->objects);
688                 clean_pack_garbage();
689         }
690
691         prepare_repo_settings(the_repository);
692         if (the_repository->settings.gc_write_commit_graph == 1)
693                 write_commit_graph_reachable(the_repository->objects->odb,
694                                              !quiet && !daemonized ? COMMIT_GRAPH_WRITE_PROGRESS : 0,
695                                              NULL);
696
697         if (auto_gc && too_many_loose_objects())
698                 warning(_("There are too many unreachable loose objects; "
699                         "run 'git prune' to remove them."));
700
701         if (!daemonized)
702                 unlink(git_path("gc.log"));
703
704         return 0;
705 }
706
707 static const char *const builtin_maintenance_run_usage[] = {
708         N_("git maintenance run [--auto] [--[no-]quiet] [--task=<task>] [--schedule]"),
709         NULL
710 };
711
712 enum schedule_priority {
713         SCHEDULE_NONE = 0,
714         SCHEDULE_WEEKLY = 1,
715         SCHEDULE_DAILY = 2,
716         SCHEDULE_HOURLY = 3,
717 };
718
719 static enum schedule_priority parse_schedule(const char *value)
720 {
721         if (!value)
722                 return SCHEDULE_NONE;
723         if (!strcasecmp(value, "hourly"))
724                 return SCHEDULE_HOURLY;
725         if (!strcasecmp(value, "daily"))
726                 return SCHEDULE_DAILY;
727         if (!strcasecmp(value, "weekly"))
728                 return SCHEDULE_WEEKLY;
729         return SCHEDULE_NONE;
730 }
731
732 static int maintenance_opt_schedule(const struct option *opt, const char *arg,
733                                     int unset)
734 {
735         enum schedule_priority *priority = opt->value;
736
737         if (unset)
738                 die(_("--no-schedule is not allowed"));
739
740         *priority = parse_schedule(arg);
741
742         if (!*priority)
743                 die(_("unrecognized --schedule argument '%s'"), arg);
744
745         return 0;
746 }
747
748 struct maintenance_run_opts {
749         int auto_flag;
750         int quiet;
751         enum schedule_priority schedule;
752 };
753
754 /* Remember to update object flag allocation in object.h */
755 #define SEEN            (1u<<0)
756
757 struct cg_auto_data {
758         int num_not_in_graph;
759         int limit;
760 };
761
762 static int dfs_on_ref(const char *refname,
763                       const struct object_id *oid, int flags,
764                       void *cb_data)
765 {
766         struct cg_auto_data *data = (struct cg_auto_data *)cb_data;
767         int result = 0;
768         struct object_id peeled;
769         struct commit_list *stack = NULL;
770         struct commit *commit;
771
772         if (!peel_ref(refname, &peeled))
773                 oid = &peeled;
774         if (oid_object_info(the_repository, oid, NULL) != OBJ_COMMIT)
775                 return 0;
776
777         commit = lookup_commit(the_repository, oid);
778         if (!commit)
779                 return 0;
780         if (parse_commit(commit) ||
781             commit_graph_position(commit) != COMMIT_NOT_FROM_GRAPH)
782                 return 0;
783
784         data->num_not_in_graph++;
785
786         if (data->num_not_in_graph >= data->limit)
787                 return 1;
788
789         commit_list_append(commit, &stack);
790
791         while (!result && stack) {
792                 struct commit_list *parent;
793
794                 commit = pop_commit(&stack);
795
796                 for (parent = commit->parents; parent; parent = parent->next) {
797                         if (parse_commit(parent->item) ||
798                             commit_graph_position(parent->item) != COMMIT_NOT_FROM_GRAPH ||
799                             parent->item->object.flags & SEEN)
800                                 continue;
801
802                         parent->item->object.flags |= SEEN;
803                         data->num_not_in_graph++;
804
805                         if (data->num_not_in_graph >= data->limit) {
806                                 result = 1;
807                                 break;
808                         }
809
810                         commit_list_append(parent->item, &stack);
811                 }
812         }
813
814         free_commit_list(stack);
815         return result;
816 }
817
818 static int should_write_commit_graph(void)
819 {
820         int result;
821         struct cg_auto_data data;
822
823         data.num_not_in_graph = 0;
824         data.limit = 100;
825         git_config_get_int("maintenance.commit-graph.auto",
826                            &data.limit);
827
828         if (!data.limit)
829                 return 0;
830         if (data.limit < 0)
831                 return 1;
832
833         result = for_each_ref(dfs_on_ref, &data);
834
835         repo_clear_commit_marks(the_repository, SEEN);
836
837         return result;
838 }
839
840 static int run_write_commit_graph(struct maintenance_run_opts *opts)
841 {
842         struct child_process child = CHILD_PROCESS_INIT;
843
844         child.git_cmd = 1;
845         strvec_pushl(&child.args, "commit-graph", "write",
846                      "--split", "--reachable", NULL);
847
848         if (opts->quiet)
849                 strvec_push(&child.args, "--no-progress");
850
851         return !!run_command(&child);
852 }
853
854 static int maintenance_task_commit_graph(struct maintenance_run_opts *opts)
855 {
856         prepare_repo_settings(the_repository);
857         if (!the_repository->settings.core_commit_graph)
858                 return 0;
859
860         close_object_store(the_repository->objects);
861         if (run_write_commit_graph(opts)) {
862                 error(_("failed to write commit-graph"));
863                 return 1;
864         }
865
866         return 0;
867 }
868
869 static int fetch_remote(const char *remote, struct maintenance_run_opts *opts)
870 {
871         struct child_process child = CHILD_PROCESS_INIT;
872
873         child.git_cmd = 1;
874         strvec_pushl(&child.args, "fetch", remote, "--prune", "--no-tags",
875                      "--no-write-fetch-head", "--recurse-submodules=no",
876                      "--refmap=", NULL);
877
878         if (opts->quiet)
879                 strvec_push(&child.args, "--quiet");
880
881         strvec_pushf(&child.args, "+refs/heads/*:refs/prefetch/%s/*", remote);
882
883         return !!run_command(&child);
884 }
885
886 static int append_remote(struct remote *remote, void *cbdata)
887 {
888         struct string_list *remotes = (struct string_list *)cbdata;
889
890         string_list_append(remotes, remote->name);
891         return 0;
892 }
893
894 static int maintenance_task_prefetch(struct maintenance_run_opts *opts)
895 {
896         int result = 0;
897         struct string_list_item *item;
898         struct string_list remotes = STRING_LIST_INIT_DUP;
899
900         if (for_each_remote(append_remote, &remotes)) {
901                 error(_("failed to fill remotes"));
902                 result = 1;
903                 goto cleanup;
904         }
905
906         for_each_string_list_item(item, &remotes)
907                 result |= fetch_remote(item->string, opts);
908
909 cleanup:
910         string_list_clear(&remotes, 0);
911         return result;
912 }
913
914 static int maintenance_task_gc(struct maintenance_run_opts *opts)
915 {
916         struct child_process child = CHILD_PROCESS_INIT;
917
918         child.git_cmd = 1;
919         strvec_push(&child.args, "gc");
920
921         if (opts->auto_flag)
922                 strvec_push(&child.args, "--auto");
923         if (opts->quiet)
924                 strvec_push(&child.args, "--quiet");
925         else
926                 strvec_push(&child.args, "--no-quiet");
927
928         close_object_store(the_repository->objects);
929         return run_command(&child);
930 }
931
932 static int prune_packed(struct maintenance_run_opts *opts)
933 {
934         struct child_process child = CHILD_PROCESS_INIT;
935
936         child.git_cmd = 1;
937         strvec_push(&child.args, "prune-packed");
938
939         if (opts->quiet)
940                 strvec_push(&child.args, "--quiet");
941
942         return !!run_command(&child);
943 }
944
945 struct write_loose_object_data {
946         FILE *in;
947         int count;
948         int batch_size;
949 };
950
951 static int loose_object_auto_limit = 100;
952
953 static int loose_object_count(const struct object_id *oid,
954                                const char *path,
955                                void *data)
956 {
957         int *count = (int*)data;
958         if (++(*count) >= loose_object_auto_limit)
959                 return 1;
960         return 0;
961 }
962
963 static int loose_object_auto_condition(void)
964 {
965         int count = 0;
966
967         git_config_get_int("maintenance.loose-objects.auto",
968                            &loose_object_auto_limit);
969
970         if (!loose_object_auto_limit)
971                 return 0;
972         if (loose_object_auto_limit < 0)
973                 return 1;
974
975         return for_each_loose_file_in_objdir(the_repository->objects->odb->path,
976                                              loose_object_count,
977                                              NULL, NULL, &count);
978 }
979
980 static int bail_on_loose(const struct object_id *oid,
981                          const char *path,
982                          void *data)
983 {
984         return 1;
985 }
986
987 static int write_loose_object_to_stdin(const struct object_id *oid,
988                                        const char *path,
989                                        void *data)
990 {
991         struct write_loose_object_data *d = (struct write_loose_object_data *)data;
992
993         fprintf(d->in, "%s\n", oid_to_hex(oid));
994
995         return ++(d->count) > d->batch_size;
996 }
997
998 static int pack_loose(struct maintenance_run_opts *opts)
999 {
1000         struct repository *r = the_repository;
1001         int result = 0;
1002         struct write_loose_object_data data;
1003         struct child_process pack_proc = CHILD_PROCESS_INIT;
1004
1005         /*
1006          * Do not start pack-objects process
1007          * if there are no loose objects.
1008          */
1009         if (!for_each_loose_file_in_objdir(r->objects->odb->path,
1010                                            bail_on_loose,
1011                                            NULL, NULL, NULL))
1012                 return 0;
1013
1014         pack_proc.git_cmd = 1;
1015
1016         strvec_push(&pack_proc.args, "pack-objects");
1017         if (opts->quiet)
1018                 strvec_push(&pack_proc.args, "--quiet");
1019         strvec_pushf(&pack_proc.args, "%s/pack/loose", r->objects->odb->path);
1020
1021         pack_proc.in = -1;
1022
1023         if (start_command(&pack_proc)) {
1024                 error(_("failed to start 'git pack-objects' process"));
1025                 return 1;
1026         }
1027
1028         data.in = xfdopen(pack_proc.in, "w");
1029         data.count = 0;
1030         data.batch_size = 50000;
1031
1032         for_each_loose_file_in_objdir(r->objects->odb->path,
1033                                       write_loose_object_to_stdin,
1034                                       NULL,
1035                                       NULL,
1036                                       &data);
1037
1038         fclose(data.in);
1039
1040         if (finish_command(&pack_proc)) {
1041                 error(_("failed to finish 'git pack-objects' process"));
1042                 result = 1;
1043         }
1044
1045         return result;
1046 }
1047
1048 static int maintenance_task_loose_objects(struct maintenance_run_opts *opts)
1049 {
1050         return prune_packed(opts) || pack_loose(opts);
1051 }
1052
1053 static int incremental_repack_auto_condition(void)
1054 {
1055         struct packed_git *p;
1056         int enabled;
1057         int incremental_repack_auto_limit = 10;
1058         int count = 0;
1059
1060         if (git_config_get_bool("core.multiPackIndex", &enabled) ||
1061             !enabled)
1062                 return 0;
1063
1064         git_config_get_int("maintenance.incremental-repack.auto",
1065                            &incremental_repack_auto_limit);
1066
1067         if (!incremental_repack_auto_limit)
1068                 return 0;
1069         if (incremental_repack_auto_limit < 0)
1070                 return 1;
1071
1072         for (p = get_packed_git(the_repository);
1073              count < incremental_repack_auto_limit && p;
1074              p = p->next) {
1075                 if (!p->multi_pack_index)
1076                         count++;
1077         }
1078
1079         return count >= incremental_repack_auto_limit;
1080 }
1081
1082 static int multi_pack_index_write(struct maintenance_run_opts *opts)
1083 {
1084         struct child_process child = CHILD_PROCESS_INIT;
1085
1086         child.git_cmd = 1;
1087         strvec_pushl(&child.args, "multi-pack-index", "write", NULL);
1088
1089         if (opts->quiet)
1090                 strvec_push(&child.args, "--no-progress");
1091
1092         if (run_command(&child))
1093                 return error(_("failed to write multi-pack-index"));
1094
1095         return 0;
1096 }
1097
1098 static int multi_pack_index_expire(struct maintenance_run_opts *opts)
1099 {
1100         struct child_process child = CHILD_PROCESS_INIT;
1101
1102         child.git_cmd = 1;
1103         strvec_pushl(&child.args, "multi-pack-index", "expire", NULL);
1104
1105         if (opts->quiet)
1106                 strvec_push(&child.args, "--no-progress");
1107
1108         close_object_store(the_repository->objects);
1109
1110         if (run_command(&child))
1111                 return error(_("'git multi-pack-index expire' failed"));
1112
1113         return 0;
1114 }
1115
1116 #define TWO_GIGABYTES (INT32_MAX)
1117
1118 static off_t get_auto_pack_size(void)
1119 {
1120         /*
1121          * The "auto" value is special: we optimize for
1122          * one large pack-file (i.e. from a clone) and
1123          * expect the rest to be small and they can be
1124          * repacked quickly.
1125          *
1126          * The strategy we select here is to select a
1127          * size that is one more than the second largest
1128          * pack-file. This ensures that we will repack
1129          * at least two packs if there are three or more
1130          * packs.
1131          */
1132         off_t max_size = 0;
1133         off_t second_largest_size = 0;
1134         off_t result_size;
1135         struct packed_git *p;
1136         struct repository *r = the_repository;
1137
1138         reprepare_packed_git(r);
1139         for (p = get_all_packs(r); p; p = p->next) {
1140                 if (p->pack_size > max_size) {
1141                         second_largest_size = max_size;
1142                         max_size = p->pack_size;
1143                 } else if (p->pack_size > second_largest_size)
1144                         second_largest_size = p->pack_size;
1145         }
1146
1147         result_size = second_largest_size + 1;
1148
1149         /* But limit ourselves to a batch size of 2g */
1150         if (result_size > TWO_GIGABYTES)
1151                 result_size = TWO_GIGABYTES;
1152
1153         return result_size;
1154 }
1155
1156 static int multi_pack_index_repack(struct maintenance_run_opts *opts)
1157 {
1158         struct child_process child = CHILD_PROCESS_INIT;
1159
1160         child.git_cmd = 1;
1161         strvec_pushl(&child.args, "multi-pack-index", "repack", NULL);
1162
1163         if (opts->quiet)
1164                 strvec_push(&child.args, "--no-progress");
1165
1166         strvec_pushf(&child.args, "--batch-size=%"PRIuMAX,
1167                                   (uintmax_t)get_auto_pack_size());
1168
1169         close_object_store(the_repository->objects);
1170
1171         if (run_command(&child))
1172                 return error(_("'git multi-pack-index repack' failed"));
1173
1174         return 0;
1175 }
1176
1177 static int maintenance_task_incremental_repack(struct maintenance_run_opts *opts)
1178 {
1179         prepare_repo_settings(the_repository);
1180         if (!the_repository->settings.core_multi_pack_index) {
1181                 warning(_("skipping incremental-repack task because core.multiPackIndex is disabled"));
1182                 return 0;
1183         }
1184
1185         if (multi_pack_index_write(opts))
1186                 return 1;
1187         if (multi_pack_index_expire(opts))
1188                 return 1;
1189         if (multi_pack_index_repack(opts))
1190                 return 1;
1191         return 0;
1192 }
1193
1194 typedef int maintenance_task_fn(struct maintenance_run_opts *opts);
1195
1196 /*
1197  * An auto condition function returns 1 if the task should run
1198  * and 0 if the task should NOT run. See needs_to_gc() for an
1199  * example.
1200  */
1201 typedef int maintenance_auto_fn(void);
1202
1203 struct maintenance_task {
1204         const char *name;
1205         maintenance_task_fn *fn;
1206         maintenance_auto_fn *auto_condition;
1207         unsigned enabled:1;
1208
1209         enum schedule_priority schedule;
1210
1211         /* -1 if not selected. */
1212         int selected_order;
1213 };
1214
1215 enum maintenance_task_label {
1216         TASK_PREFETCH,
1217         TASK_LOOSE_OBJECTS,
1218         TASK_INCREMENTAL_REPACK,
1219         TASK_GC,
1220         TASK_COMMIT_GRAPH,
1221
1222         /* Leave as final value */
1223         TASK__COUNT
1224 };
1225
1226 static struct maintenance_task tasks[] = {
1227         [TASK_PREFETCH] = {
1228                 "prefetch",
1229                 maintenance_task_prefetch,
1230         },
1231         [TASK_LOOSE_OBJECTS] = {
1232                 "loose-objects",
1233                 maintenance_task_loose_objects,
1234                 loose_object_auto_condition,
1235         },
1236         [TASK_INCREMENTAL_REPACK] = {
1237                 "incremental-repack",
1238                 maintenance_task_incremental_repack,
1239                 incremental_repack_auto_condition,
1240         },
1241         [TASK_GC] = {
1242                 "gc",
1243                 maintenance_task_gc,
1244                 need_to_gc,
1245                 1,
1246         },
1247         [TASK_COMMIT_GRAPH] = {
1248                 "commit-graph",
1249                 maintenance_task_commit_graph,
1250                 should_write_commit_graph,
1251         },
1252 };
1253
1254 static int compare_tasks_by_selection(const void *a_, const void *b_)
1255 {
1256         const struct maintenance_task *a = a_;
1257         const struct maintenance_task *b = b_;
1258
1259         return b->selected_order - a->selected_order;
1260 }
1261
1262 static int maintenance_run_tasks(struct maintenance_run_opts *opts)
1263 {
1264         int i, found_selected = 0;
1265         int result = 0;
1266         struct lock_file lk;
1267         struct repository *r = the_repository;
1268         char *lock_path = xstrfmt("%s/maintenance", r->objects->odb->path);
1269
1270         if (hold_lock_file_for_update(&lk, lock_path, LOCK_NO_DEREF) < 0) {
1271                 /*
1272                  * Another maintenance command is running.
1273                  *
1274                  * If --auto was provided, then it is likely due to a
1275                  * recursive process stack. Do not report an error in
1276                  * that case.
1277                  */
1278                 if (!opts->auto_flag && !opts->quiet)
1279                         warning(_("lock file '%s' exists, skipping maintenance"),
1280                                 lock_path);
1281                 free(lock_path);
1282                 return 0;
1283         }
1284         free(lock_path);
1285
1286         for (i = 0; !found_selected && i < TASK__COUNT; i++)
1287                 found_selected = tasks[i].selected_order >= 0;
1288
1289         if (found_selected)
1290                 QSORT(tasks, TASK__COUNT, compare_tasks_by_selection);
1291
1292         for (i = 0; i < TASK__COUNT; i++) {
1293                 if (found_selected && tasks[i].selected_order < 0)
1294                         continue;
1295
1296                 if (!found_selected && !tasks[i].enabled)
1297                         continue;
1298
1299                 if (opts->auto_flag &&
1300                     (!tasks[i].auto_condition ||
1301                      !tasks[i].auto_condition()))
1302                         continue;
1303
1304                 if (opts->schedule && tasks[i].schedule < opts->schedule)
1305                         continue;
1306
1307                 trace2_region_enter("maintenance", tasks[i].name, r);
1308                 if (tasks[i].fn(opts)) {
1309                         error(_("task '%s' failed"), tasks[i].name);
1310                         result = 1;
1311                 }
1312                 trace2_region_leave("maintenance", tasks[i].name, r);
1313         }
1314
1315         rollback_lock_file(&lk);
1316         return result;
1317 }
1318
1319 static void initialize_maintenance_strategy(void)
1320 {
1321         char *config_str;
1322
1323         if (git_config_get_string("maintenance.strategy", &config_str))
1324                 return;
1325
1326         if (!strcasecmp(config_str, "incremental")) {
1327                 tasks[TASK_GC].schedule = SCHEDULE_NONE;
1328                 tasks[TASK_COMMIT_GRAPH].enabled = 1;
1329                 tasks[TASK_COMMIT_GRAPH].schedule = SCHEDULE_HOURLY;
1330                 tasks[TASK_PREFETCH].enabled = 1;
1331                 tasks[TASK_PREFETCH].schedule = SCHEDULE_HOURLY;
1332                 tasks[TASK_INCREMENTAL_REPACK].enabled = 1;
1333                 tasks[TASK_INCREMENTAL_REPACK].schedule = SCHEDULE_DAILY;
1334                 tasks[TASK_LOOSE_OBJECTS].enabled = 1;
1335                 tasks[TASK_LOOSE_OBJECTS].schedule = SCHEDULE_DAILY;
1336         }
1337 }
1338
1339 static void initialize_task_config(int schedule)
1340 {
1341         int i;
1342         struct strbuf config_name = STRBUF_INIT;
1343         gc_config();
1344
1345         if (schedule)
1346                 initialize_maintenance_strategy();
1347
1348         for (i = 0; i < TASK__COUNT; i++) {
1349                 int config_value;
1350                 char *config_str;
1351
1352                 strbuf_reset(&config_name);
1353                 strbuf_addf(&config_name, "maintenance.%s.enabled",
1354                             tasks[i].name);
1355
1356                 if (!git_config_get_bool(config_name.buf, &config_value))
1357                         tasks[i].enabled = config_value;
1358
1359                 strbuf_reset(&config_name);
1360                 strbuf_addf(&config_name, "maintenance.%s.schedule",
1361                             tasks[i].name);
1362
1363                 if (!git_config_get_string(config_name.buf, &config_str)) {
1364                         tasks[i].schedule = parse_schedule(config_str);
1365                         free(config_str);
1366                 }
1367         }
1368
1369         strbuf_release(&config_name);
1370 }
1371
1372 static int task_option_parse(const struct option *opt,
1373                              const char *arg, int unset)
1374 {
1375         int i, num_selected = 0;
1376         struct maintenance_task *task = NULL;
1377
1378         BUG_ON_OPT_NEG(unset);
1379
1380         for (i = 0; i < TASK__COUNT; i++) {
1381                 if (tasks[i].selected_order >= 0)
1382                         num_selected++;
1383                 if (!strcasecmp(tasks[i].name, arg)) {
1384                         task = &tasks[i];
1385                 }
1386         }
1387
1388         if (!task) {
1389                 error(_("'%s' is not a valid task"), arg);
1390                 return 1;
1391         }
1392
1393         if (task->selected_order >= 0) {
1394                 error(_("task '%s' cannot be selected multiple times"), arg);
1395                 return 1;
1396         }
1397
1398         task->selected_order = num_selected + 1;
1399
1400         return 0;
1401 }
1402
1403 static int maintenance_run(int argc, const char **argv, const char *prefix)
1404 {
1405         int i;
1406         struct maintenance_run_opts opts;
1407         struct option builtin_maintenance_run_options[] = {
1408                 OPT_BOOL(0, "auto", &opts.auto_flag,
1409                          N_("run tasks based on the state of the repository")),
1410                 OPT_CALLBACK(0, "schedule", &opts.schedule, N_("frequency"),
1411                              N_("run tasks based on frequency"),
1412                              maintenance_opt_schedule),
1413                 OPT_BOOL(0, "quiet", &opts.quiet,
1414                          N_("do not report progress or other information over stderr")),
1415                 OPT_CALLBACK_F(0, "task", NULL, N_("task"),
1416                         N_("run a specific task"),
1417                         PARSE_OPT_NONEG, task_option_parse),
1418                 OPT_END()
1419         };
1420         memset(&opts, 0, sizeof(opts));
1421
1422         opts.quiet = !isatty(2);
1423
1424         for (i = 0; i < TASK__COUNT; i++)
1425                 tasks[i].selected_order = -1;
1426
1427         argc = parse_options(argc, argv, prefix,
1428                              builtin_maintenance_run_options,
1429                              builtin_maintenance_run_usage,
1430                              PARSE_OPT_STOP_AT_NON_OPTION);
1431
1432         if (opts.auto_flag && opts.schedule)
1433                 die(_("use at most one of --auto and --schedule=<frequency>"));
1434
1435         initialize_task_config(opts.schedule);
1436
1437         if (argc != 0)
1438                 usage_with_options(builtin_maintenance_run_usage,
1439                                    builtin_maintenance_run_options);
1440         return maintenance_run_tasks(&opts);
1441 }
1442
1443 static int maintenance_register(void)
1444 {
1445         char *config_value;
1446         struct child_process config_set = CHILD_PROCESS_INIT;
1447         struct child_process config_get = CHILD_PROCESS_INIT;
1448
1449         /* Disable foreground maintenance */
1450         git_config_set("maintenance.auto", "false");
1451
1452         /* Set maintenance strategy, if unset */
1453         if (!git_config_get_string("maintenance.strategy", &config_value))
1454                 free(config_value);
1455         else
1456                 git_config_set("maintenance.strategy", "incremental");
1457
1458         config_get.git_cmd = 1;
1459         strvec_pushl(&config_get.args, "config", "--global", "--get",
1460                      "--fixed-value", "maintenance.repo",
1461                      the_repository->worktree ? the_repository->worktree
1462                                               : the_repository->gitdir,
1463                          NULL);
1464         config_get.out = -1;
1465
1466         if (start_command(&config_get))
1467                 return error(_("failed to run 'git config'"));
1468
1469         /* We already have this value in our config! */
1470         if (!finish_command(&config_get))
1471                 return 0;
1472
1473         config_set.git_cmd = 1;
1474         strvec_pushl(&config_set.args, "config", "--add", "--global", "maintenance.repo",
1475                      the_repository->worktree ? the_repository->worktree
1476                                               : the_repository->gitdir,
1477                      NULL);
1478
1479         return run_command(&config_set);
1480 }
1481
1482 static int maintenance_unregister(void)
1483 {
1484         struct child_process config_unset = CHILD_PROCESS_INIT;
1485
1486         config_unset.git_cmd = 1;
1487         strvec_pushl(&config_unset.args, "config", "--global", "--unset",
1488                      "--fixed-value", "maintenance.repo",
1489                      the_repository->worktree ? the_repository->worktree
1490                                               : the_repository->gitdir,
1491                      NULL);
1492
1493         return run_command(&config_unset);
1494 }
1495
1496 #define BEGIN_LINE "# BEGIN GIT MAINTENANCE SCHEDULE"
1497 #define END_LINE "# END GIT MAINTENANCE SCHEDULE"
1498
1499 static int update_background_schedule(int run_maintenance)
1500 {
1501         int result = 0;
1502         int in_old_region = 0;
1503         struct child_process crontab_list = CHILD_PROCESS_INIT;
1504         struct child_process crontab_edit = CHILD_PROCESS_INIT;
1505         FILE *cron_list, *cron_in;
1506         const char *crontab_name;
1507         struct strbuf line = STRBUF_INIT;
1508         struct lock_file lk;
1509         char *lock_path = xstrfmt("%s/schedule", the_repository->objects->odb->path);
1510
1511         if (hold_lock_file_for_update(&lk, lock_path, LOCK_NO_DEREF) < 0)
1512                 return error(_("another process is scheduling background maintenance"));
1513
1514         crontab_name = getenv("GIT_TEST_CRONTAB");
1515         if (!crontab_name)
1516                 crontab_name = "crontab";
1517
1518         strvec_split(&crontab_list.args, crontab_name);
1519         strvec_push(&crontab_list.args, "-l");
1520         crontab_list.in = -1;
1521         crontab_list.out = dup(lk.tempfile->fd);
1522         crontab_list.git_cmd = 0;
1523
1524         if (start_command(&crontab_list)) {
1525                 result = error(_("failed to run 'crontab -l'; your system might not support 'cron'"));
1526                 goto cleanup;
1527         }
1528
1529         /* Ignore exit code, as an empty crontab will return error. */
1530         finish_command(&crontab_list);
1531
1532         /*
1533          * Read from the .lock file, filtering out the old
1534          * schedule while appending the new schedule.
1535          */
1536         cron_list = fdopen(lk.tempfile->fd, "r");
1537         rewind(cron_list);
1538
1539         strvec_split(&crontab_edit.args, crontab_name);
1540         crontab_edit.in = -1;
1541         crontab_edit.git_cmd = 0;
1542
1543         if (start_command(&crontab_edit)) {
1544                 result = error(_("failed to run 'crontab'; your system might not support 'cron'"));
1545                 goto cleanup;
1546         }
1547
1548         cron_in = fdopen(crontab_edit.in, "w");
1549         if (!cron_in) {
1550                 result = error(_("failed to open stdin of 'crontab'"));
1551                 goto done_editing;
1552         }
1553
1554         while (!strbuf_getline_lf(&line, cron_list)) {
1555                 if (!in_old_region && !strcmp(line.buf, BEGIN_LINE))
1556                         in_old_region = 1;
1557                 else if (in_old_region && !strcmp(line.buf, END_LINE))
1558                         in_old_region = 0;
1559                 else if (!in_old_region)
1560                         fprintf(cron_in, "%s\n", line.buf);
1561         }
1562
1563         if (run_maintenance) {
1564                 struct strbuf line_format = STRBUF_INIT;
1565                 const char *exec_path = git_exec_path();
1566
1567                 fprintf(cron_in, "%s\n", BEGIN_LINE);
1568                 fprintf(cron_in,
1569                         "# The following schedule was created by Git\n");
1570                 fprintf(cron_in, "# Any edits made in this region might be\n");
1571                 fprintf(cron_in,
1572                         "# replaced in the future by a Git command.\n\n");
1573
1574                 strbuf_addf(&line_format,
1575                             "%%s %%s * * %%s \"%s/git\" --exec-path=\"%s\" for-each-repo --config=maintenance.repo maintenance run --schedule=%%s\n",
1576                             exec_path, exec_path);
1577                 fprintf(cron_in, line_format.buf, "0", "1-23", "*", "hourly");
1578                 fprintf(cron_in, line_format.buf, "0", "0", "1-6", "daily");
1579                 fprintf(cron_in, line_format.buf, "0", "0", "0", "weekly");
1580                 strbuf_release(&line_format);
1581
1582                 fprintf(cron_in, "\n%s\n", END_LINE);
1583         }
1584
1585         fflush(cron_in);
1586         fclose(cron_in);
1587         close(crontab_edit.in);
1588
1589 done_editing:
1590         if (finish_command(&crontab_edit)) {
1591                 result = error(_("'crontab' died"));
1592                 goto cleanup;
1593         }
1594         fclose(cron_list);
1595
1596 cleanup:
1597         rollback_lock_file(&lk);
1598         return result;
1599 }
1600
1601 static int maintenance_start(void)
1602 {
1603         if (maintenance_register())
1604                 warning(_("failed to add repo to global config"));
1605
1606         return update_background_schedule(1);
1607 }
1608
1609 static int maintenance_stop(void)
1610 {
1611         return update_background_schedule(0);
1612 }
1613
1614 static const char builtin_maintenance_usage[] = N_("git maintenance <subcommand> [<options>]");
1615
1616 int cmd_maintenance(int argc, const char **argv, const char *prefix)
1617 {
1618         if (argc < 2 ||
1619             (argc == 2 && !strcmp(argv[1], "-h")))
1620                 usage(builtin_maintenance_usage);
1621
1622         if (!strcmp(argv[1], "run"))
1623                 return maintenance_run(argc - 1, argv + 1, prefix);
1624         if (!strcmp(argv[1], "start"))
1625                 return maintenance_start();
1626         if (!strcmp(argv[1], "stop"))
1627                 return maintenance_stop();
1628         if (!strcmp(argv[1], "register"))
1629                 return maintenance_register();
1630         if (!strcmp(argv[1], "unregister"))
1631                 return maintenance_unregister();
1632
1633         die(_("invalid subcommand: %s"), argv[1]);
1634 }