]> git.ipfire.org Git - thirdparty/git.git/commitdiff
maintenance: create `launchctl` configuration using a lock file
authorJohannes Schindelin <johannes.schindelin@gmx.de>
Tue, 24 Aug 2021 15:43:59 +0000 (15:43 +0000)
committerJunio C Hamano <gitster@pobox.com>
Tue, 24 Aug 2021 21:16:57 +0000 (14:16 -0700)
When two `git maintenance` processes try to write the `.plist` file, we
need to help them with serializing their efforts.

The 150ms time-out value was determined from thin air.

Signed-off-by: Johannes Schindelin <johannes.schindelin@gmx.de>
Signed-off-by: Junio C Hamano <gitster@pobox.com>
builtin/gc.c

index f05d2f0a1ac9cd5637237d7da987452523a8ced3..06f18a347d0b805bebe706039f7ea851f962014b 100644 (file)
@@ -1602,16 +1602,14 @@ static int launchctl_remove_plists(const char *cmd)
 
 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;
 
        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"
@@ -1630,7 +1628,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:
@@ -1639,7 +1637,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:
@@ -1649,24 +1647,38 @@ 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);
+
+       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);
@@ -1675,6 +1687,7 @@ static int launchctl_schedule_plist(const char *exec_path, enum schedule_priorit
 
        free(filename);
        free(name);
+       strbuf_release(&plist);
        return 0;
 }