summaryrefslogtreecommitdiff
path: root/t
diff options
context:
space:
mode:
authorDerrick Stolee <dstolee@microsoft.com>2020-09-11 17:49:18 (GMT)
committerJunio C Hamano <gitster@pobox.com>2020-09-25 17:59:44 (GMT)
commit2fec604f8df51fcf47551723e68a3447915b9eb9 (patch)
tree7373599d9ca099967136d0082cf572a4e23d62a2 /t
parent0c18b700810ab2e2a4fac0d5b54a817141198a27 (diff)
downloadgit-2fec604f8df51fcf47551723e68a3447915b9eb9.zip
git-2fec604f8df51fcf47551723e68a3447915b9eb9.tar.gz
git-2fec604f8df51fcf47551723e68a3447915b9eb9.tar.bz2
maintenance: add start/stop subcommands
Add new subcommands to 'git maintenance' that start or stop background maintenance using 'cron', when available. This integration is as simple as I could make it, barring some implementation complications. The schedule is laid out as follows: 0 1-23 * * * $cmd maintenance run --schedule=hourly 0 0 * * 1-6 $cmd maintenance run --schedule=daily 0 0 * * 0 $cmd maintenance run --schedule=weekly where $cmd is a properly-qualified 'git for-each-repo' execution: $cmd=$path/git --exec-path=$path for-each-repo --config=maintenance.repo where $path points to the location of the Git executable running 'git maintenance start'. This is critical for systems with multiple versions of Git. Specifically, macOS has a system version at '/usr/bin/git' while the version that users can install resides at '/usr/local/bin/git' (symlinked to '/usr/local/libexec/git-core/git'). This will also use your locally-built version if you build and run this in your development environment without installing first. This conditional schedule avoids having cron launch multiple 'git for-each-repo' commands in parallel. Such parallel commands would likely lead to the 'hourly' and 'daily' tasks competing over the object database lock. This could lead to to some tasks never being run! Since the --schedule=<frequency> argument will run all tasks with _at least_ the given frequency, the daily runs will also run the hourly tasks. Similarly, the weekly runs will also run the daily and hourly tasks. The GIT_TEST_CRONTAB environment variable is not intended for users to edit, but instead as a way to mock the 'crontab [-l]' command. This variable is set in test-lib.sh to avoid a future test from accidentally running anything with the cron integration from modifying the user's schedule. We use GIT_TEST_CRONTAB='test-tool crontab <file>' in our tests to check how the schedule is modified in 'git maintenance (start|stop)' commands. Signed-off-by: Derrick Stolee <dstolee@microsoft.com> Signed-off-by: Junio C Hamano <gitster@pobox.com>
Diffstat (limited to 't')
-rw-r--r--t/helper/test-crontab.c35
-rw-r--r--t/helper/test-tool.c1
-rw-r--r--t/helper/test-tool.h1
-rwxr-xr-xt/t7900-maintenance.sh28
-rw-r--r--t/test-lib.sh6
5 files changed, 71 insertions, 0 deletions
diff --git a/t/helper/test-crontab.c b/t/helper/test-crontab.c
new file mode 100644
index 0000000..e7c0137
--- /dev/null
+++ b/t/helper/test-crontab.c
@@ -0,0 +1,35 @@
+#include "test-tool.h"
+#include "cache.h"
+
+/*
+ * Usage: test-tool cron <file> [-l]
+ *
+ * If -l is specified, then write the contents of <file> to stdout.
+ * Otherwise, write from stdin into <file>.
+ */
+int cmd__crontab(int argc, const char **argv)
+{
+ int a;
+ FILE *from, *to;
+
+ if (argc == 3 && !strcmp(argv[2], "-l")) {
+ from = fopen(argv[1], "r");
+ if (!from)
+ return 0;
+ to = stdout;
+ } else if (argc == 2) {
+ from = stdin;
+ to = fopen(argv[1], "w");
+ } else
+ return error("unknown arguments");
+
+ while ((a = fgetc(from)) != EOF)
+ fputc(a, to);
+
+ if (argc == 3)
+ fclose(from);
+ else
+ fclose(to);
+
+ return 0;
+}
diff --git a/t/helper/test-tool.c b/t/helper/test-tool.c
index 590b2ef..432b49d 100644
--- a/t/helper/test-tool.c
+++ b/t/helper/test-tool.c
@@ -18,6 +18,7 @@ static struct test_cmd cmds[] = {
{ "bloom", cmd__bloom },
{ "chmtime", cmd__chmtime },
{ "config", cmd__config },
+ { "crontab", cmd__crontab },
{ "ctype", cmd__ctype },
{ "date", cmd__date },
{ "delta", cmd__delta },
diff --git a/t/helper/test-tool.h b/t/helper/test-tool.h
index ddc8e99..7c3281e 100644
--- a/t/helper/test-tool.h
+++ b/t/helper/test-tool.h
@@ -8,6 +8,7 @@ int cmd__advise_if_enabled(int argc, const char **argv);
int cmd__bloom(int argc, const char **argv);
int cmd__chmtime(int argc, const char **argv);
int cmd__config(int argc, const char **argv);
+int cmd__crontab(int argc, const char **argv);
int cmd__ctype(int argc, const char **argv);
int cmd__date(int argc, const char **argv);
int cmd__delta(int argc, const char **argv);
diff --git a/t/t7900-maintenance.sh b/t/t7900-maintenance.sh
index 8f383d0..7715e40 100755
--- a/t/t7900-maintenance.sh
+++ b/t/t7900-maintenance.sh
@@ -315,4 +315,32 @@ test_expect_success 'register and unregister' '
test_cmp before actual
'
+test_expect_success 'start from empty cron table' '
+ GIT_TEST_CRONTAB="test-tool crontab cron.txt" git maintenance start &&
+
+ # start registers the repo
+ git config --get --global maintenance.repo "$(pwd)" &&
+
+ grep "for-each-repo --config=maintenance.repo maintenance run --schedule=daily" cron.txt &&
+ grep "for-each-repo --config=maintenance.repo maintenance run --schedule=hourly" cron.txt &&
+ grep "for-each-repo --config=maintenance.repo maintenance run --schedule=weekly" cron.txt
+'
+
+test_expect_success 'stop from existing schedule' '
+ GIT_TEST_CRONTAB="test-tool crontab cron.txt" git maintenance stop &&
+
+ # stop does not unregister the repo
+ git config --get --global maintenance.repo "$(pwd)" &&
+
+ # Operation is idempotent
+ GIT_TEST_CRONTAB="test-tool crontab cron.txt" git maintenance stop &&
+ test_must_be_empty cron.txt
+'
+
+test_expect_success 'start preserves existing schedule' '
+ echo "Important information!" >cron.txt &&
+ GIT_TEST_CRONTAB="test-tool crontab cron.txt" git maintenance start &&
+ grep "Important information!" cron.txt
+'
+
test_done
diff --git a/t/test-lib.sh b/t/test-lib.sh
index ef31f40..4a60d1e 100644
--- a/t/test-lib.sh
+++ b/t/test-lib.sh
@@ -1702,3 +1702,9 @@ test_lazy_prereq SHA1 '
test_lazy_prereq REBASE_P '
test -z "$GIT_TEST_SKIP_REBASE_P"
'
+
+# Ensure that no test accidentally triggers a Git command
+# that runs 'crontab', affecting a user's cron schedule.
+# Tests that verify the cron integration must set this locally
+# to avoid errors.
+GIT_TEST_CRONTAB="exit 1"