diff options
Diffstat (limited to 'builtin/gc.c')
-rw-r--r-- | builtin/gc.c | 142 |
1 files changed, 91 insertions, 51 deletions
diff --git a/builtin/gc.c b/builtin/gc.c index ef7226d7bc..9a48eb535f 100644 --- a/builtin/gc.c +++ b/builtin/gc.c @@ -873,55 +873,40 @@ static int maintenance_task_commit_graph(struct maintenance_run_opts *opts) return 0; } -static int fetch_remote(const char *remote, struct maintenance_run_opts *opts) +static int fetch_remote(struct remote *remote, void *cbdata) { + struct maintenance_run_opts *opts = cbdata; struct child_process child = CHILD_PROCESS_INIT; + if (remote->skip_default_update) + return 0; + child.git_cmd = 1; - strvec_pushl(&child.args, "fetch", remote, "--prune", "--no-tags", + strvec_pushl(&child.args, "fetch", remote->name, + "--prefetch", "--prune", "--no-tags", "--no-write-fetch-head", "--recurse-submodules=no", - "--refmap=", NULL); + NULL); if (opts->quiet) strvec_push(&child.args, "--quiet"); - strvec_pushf(&child.args, "+refs/heads/*:refs/prefetch/%s/*", remote); - return !!run_command(&child); } -static int append_remote(struct remote *remote, void *cbdata) -{ - struct string_list *remotes = (struct string_list *)cbdata; - - string_list_append(remotes, remote->name); - return 0; -} - static int maintenance_task_prefetch(struct maintenance_run_opts *opts) { - int result = 0; - struct string_list_item *item; - struct string_list remotes = STRING_LIST_INIT_DUP; - git_config_set_multivar_gently("log.excludedecoration", "refs/prefetch/", "refs/prefetch/", CONFIG_FLAGS_FIXED_VALUE | CONFIG_FLAGS_MULTI_REPLACE); - if (for_each_remote(append_remote, &remotes)) { - error(_("failed to fill remotes")); - result = 1; - goto cleanup; + if (for_each_remote(fetch_remote, opts)) { + error(_("failed to prefetch remotes")); + return 1; } - for_each_string_list_item(item, &remotes) - result |= fetch_remote(item->string, opts); - -cleanup: - string_list_clear(&remotes, 0); - return result; + return 0; } static int maintenance_task_gc(struct maintenance_run_opts *opts) @@ -1557,7 +1542,7 @@ static char *launchctl_service_filename(const char *name) struct strbuf filename = STRBUF_INIT; strbuf_addf(&filename, "~/Library/LaunchAgents/%s.plist", name); - expanded = expand_user_path(filename.buf, 1); + expanded = interpolate_path(filename.buf, 1); if (!expanded) die(_("failed to expand path '%s'"), filename.buf); @@ -1615,18 +1600,40 @@ static int launchctl_remove_plists(const char *cmd) launchctl_remove_plist(SCHEDULE_WEEKLY, cmd); } +static int launchctl_list_contains_plist(const char *name, const char *cmd) +{ + int result; + struct child_process child = CHILD_PROCESS_INIT; + char *uid = launchctl_get_uid(); + + strvec_split(&child.args, cmd); + strvec_pushl(&child.args, "list", name, NULL); + + child.no_stderr = 1; + child.no_stdout = 1; + + if (start_command(&child)) + die(_("failed to start launchctl")); + + result = finish_command(&child); + + free(uid); + + /* Returns failure if 'name' doesn't exist. */ + return !result; +} + static int launchctl_schedule_plist(const char *exec_path, enum schedule_priority schedule, const char *cmd) { - FILE *plist; - int i; + int i, fd; const char *preamble, *repeat; const char *frequency = get_frequency(schedule); char *name = launchctl_service_name(frequency); char *filename = launchctl_service_filename(name); - - if (safe_create_leading_directories(filename)) - die(_("failed to create directories for '%s'"), filename); - plist = xfopen(filename, "w"); + struct lock_file lk = LOCK_INIT; + static unsigned long lock_file_timeout_ms = ULONG_MAX; + struct strbuf plist = STRBUF_INIT, plist2 = STRBUF_INIT; + struct stat st; preamble = "<?xml version=\"1.0\"?>\n" "<!DOCTYPE plist PUBLIC \"-//Apple//DTD PLIST 1.0//EN\" \"http://www.apple.com/DTDs/PropertyList-1.0.dtd\">\n" @@ -1645,7 +1652,7 @@ static int launchctl_schedule_plist(const char *exec_path, enum schedule_priorit "</array>\n" "<key>StartCalendarInterval</key>\n" "<array>\n"; - fprintf(plist, preamble, name, exec_path, exec_path, frequency); + strbuf_addf(&plist, preamble, name, exec_path, exec_path, frequency); switch (schedule) { case SCHEDULE_HOURLY: @@ -1654,7 +1661,7 @@ static int launchctl_schedule_plist(const char *exec_path, enum schedule_priorit "<key>Minute</key><integer>0</integer>\n" "</dict>\n"; for (i = 1; i <= 23; i++) - fprintf(plist, repeat, i); + strbuf_addf(&plist, repeat, i); break; case SCHEDULE_DAILY: @@ -1664,32 +1671,59 @@ static int launchctl_schedule_plist(const char *exec_path, enum schedule_priorit "<key>Minute</key><integer>0</integer>\n" "</dict>\n"; for (i = 1; i <= 6; i++) - fprintf(plist, repeat, i); + strbuf_addf(&plist, repeat, i); break; case SCHEDULE_WEEKLY: - fprintf(plist, - "<dict>\n" - "<key>Day</key><integer>0</integer>\n" - "<key>Hour</key><integer>0</integer>\n" - "<key>Minute</key><integer>0</integer>\n" - "</dict>\n"); + strbuf_addstr(&plist, + "<dict>\n" + "<key>Day</key><integer>0</integer>\n" + "<key>Hour</key><integer>0</integer>\n" + "<key>Minute</key><integer>0</integer>\n" + "</dict>\n"); break; default: /* unreachable */ break; } - fprintf(plist, "</array>\n</dict>\n</plist>\n"); - fclose(plist); + strbuf_addstr(&plist, "</array>\n</dict>\n</plist>\n"); + + if (safe_create_leading_directories(filename)) + die(_("failed to create directories for '%s'"), filename); + + if ((long)lock_file_timeout_ms < 0 && + git_config_get_ulong("gc.launchctlplistlocktimeoutms", + &lock_file_timeout_ms)) + lock_file_timeout_ms = 150; + + fd = hold_lock_file_for_update_timeout(&lk, filename, LOCK_DIE_ON_ERROR, + lock_file_timeout_ms); - /* bootout might fail if not already running, so ignore */ - launchctl_boot_plist(0, filename, cmd); - if (launchctl_boot_plist(1, filename, cmd)) - die(_("failed to bootstrap service %s"), filename); + /* + * Does this file already exist? With the intended contents? Is it + * registered already? Then it does not need to be re-registered. + */ + if (!stat(filename, &st) && st.st_size == plist.len && + strbuf_read_file(&plist2, filename, plist.len) == plist.len && + !strbuf_cmp(&plist, &plist2) && + launchctl_list_contains_plist(name, cmd)) + rollback_lock_file(&lk); + else { + if (write_in_full(fd, plist.buf, plist.len) < 0 || + commit_lock_file(&lk)) + die_errno(_("could not write '%s'"), filename); + + /* bootout might fail if not already running, so ignore */ + launchctl_boot_plist(0, filename, cmd); + if (launchctl_boot_plist(1, filename, cmd)) + die(_("failed to bootstrap service %s"), filename); + } free(filename); free(name); + strbuf_release(&plist); + strbuf_release(&plist2); return 0; } @@ -1924,6 +1958,7 @@ static int crontab_update_schedule(int run_maintenance, int fd, const char *cmd) else if (!in_old_region) fprintf(cron_in, "%s\n", line.buf); } + strbuf_release(&line); if (run_maintenance) { struct strbuf line_format = STRBUF_INIT; @@ -1986,8 +2021,10 @@ static int update_background_schedule(int enable) cmd = sep + 1; } - if (hold_lock_file_for_update(&lk, lock_path, LOCK_NO_DEREF) < 0) - return error(_("another process is scheduling background maintenance")); + if (hold_lock_file_for_update(&lk, lock_path, LOCK_NO_DEREF) < 0) { + result = error(_("another process is scheduling background maintenance")); + goto cleanup; + } if (!strcmp(scheduler, "launchctl")) result = launchctl_update_schedule(enable, get_lock_file_fd(&lk), cmd); @@ -1999,6 +2036,9 @@ static int update_background_schedule(int enable) die("unknown background scheduler: %s", scheduler); rollback_lock_file(&lk); + +cleanup: + free(lock_path); free(testing); return result; } |