@@ -83,6 +83,7 @@
/git-init-db
/git-interpret-trailers
/git-instaweb
+/git-job-runner
/git-log
/git-ls-files
/git-ls-remote
new file mode 100644
@@ -0,0 +1,52 @@
+git-job-runner(1)
+=================
+
+NAME
+----
+git-job-runner - run jobs on multiple repos according to a schedlue.
+Intended for background operation.
+
+
+SYNOPSIS
+--------
+[verse]
+'git job-runner [--repo=<path>]'
+
+
+DESCRIPTION
+-----------
+
+Run jobs in a loop with some frequency. Intended for running in the
+background.
+
+The `git run-job <job-name>` command runs a specific maintenance task.
+The `job-runner` command is a long-running process that calls the
+`run-job` command on a set of repositories at some frequency. The
+`job.*` config values customize the frequencies of these jobs.
+
+
+OPTIONS
+-------
+
+--repo=<dir>::
+ If at least one `--repo` option is provided, the runner only
+ attempts running jobs on repositories located at the provided
+ `<dir>` values. This option can be specified multiple times.
+
+
+CONFIGURATION
+-------------
+
+The `git job-runner` command is intended to run as a long-running
+process. The following config options are checked periodically during
+the process and will modify its behavior:
+
+The below documentation is the same as what's found in
+linkgit:git-config[1]:
+
+include::config/job.txt[]
+
+
+GIT
+---
+Part of the linkgit:git[1] suite
@@ -1082,6 +1082,7 @@ BUILTIN_OBJS += builtin/help.o
BUILTIN_OBJS += builtin/index-pack.o
BUILTIN_OBJS += builtin/init-db.o
BUILTIN_OBJS += builtin/interpret-trailers.o
+BUILTIN_OBJS += builtin/job-runner.o
BUILTIN_OBJS += builtin/log.o
BUILTIN_OBJS += builtin/ls-files.o
BUILTIN_OBJS += builtin/ls-remote.o
@@ -176,6 +176,7 @@ int cmd_help(int argc, const char **argv, const char *prefix);
int cmd_index_pack(int argc, const char **argv, const char *prefix);
int cmd_init_db(int argc, const char **argv, const char *prefix);
int cmd_interpret_trailers(int argc, const char **argv, const char *prefix);
+int cmd_job_runner(int argc, const char **argv, const char *prefix);
int cmd_log(int argc, const char **argv, const char *prefix);
int cmd_log_reflog(int argc, const char **argv, const char *prefix);
int cmd_ls_files(int argc, const char **argv, const char *prefix);
new file mode 100644
@@ -0,0 +1,111 @@
+#include "builtin.h"
+#include "config.h"
+#include "parse-options.h"
+#include "run-command.h"
+#include "string-list.h"
+
+static char const * const builtin_job_runner_usage[] = {
+ N_("git job-runner [<options>]"),
+ NULL
+};
+
+static struct string_list arg_repos = STRING_LIST_INIT_DUP;
+
+static int arg_repos_append(const struct option *opt,
+ const char *arg, int unset)
+{
+ string_list_append(&arg_repos, arg);
+ return 0;
+}
+
+static int load_active_repos(struct string_list *repos)
+{
+ if (arg_repos.nr) {
+ struct string_list_item *item;
+ for (item = arg_repos.items;
+ item && item < arg_repos.items + arg_repos.nr;
+ item++)
+ string_list_append(repos, item->string);
+ return 0;
+ }
+
+ return 0;
+}
+
+static int run_job(const char *job, const char *repo)
+{
+ struct argv_array cmd = ARGV_ARRAY_INIT;
+ argv_array_pushl(&cmd, "-C", repo, "run-job", job, NULL);
+ return run_command_v_opt(cmd.argv, RUN_GIT_CMD);
+}
+
+static int run_job_loop_step(struct string_list *list)
+{
+ int result = 0;
+ struct string_list_item *job;
+ struct string_list repos = STRING_LIST_INIT_DUP;
+
+ if ((result = load_active_repos(&repos)))
+ return result;
+
+ for (job = list->items;
+ !result && job && job < list->items + list->nr;
+ job++) {
+ struct string_list_item *repo;
+ for (repo = repos.items;
+ !result && repo && repo < repos.items + repos.nr;
+ repo++)
+ result = run_job(job->string,
+ repo->string);
+ }
+
+ string_list_clear(&repos, 0);
+ return result;
+}
+
+static unsigned int get_loop_interval(void)
+{
+ /* Default: 30 minutes */
+ return 30 * 60;
+}
+
+static int initialize_jobs(struct string_list *list)
+{
+ string_list_append(list, "commit-graph");
+ string_list_append(list, "fetch");
+ string_list_append(list, "loose-objects");
+ string_list_append(list, "pack-files");
+ return 0;
+}
+
+int cmd_job_runner(int argc, const char **argv, const char *prefix)
+{
+ int result;
+ struct string_list job_list = STRING_LIST_INIT_DUP;
+ static struct option builtin_job_runner_options[] = {
+ OPT_CALLBACK_F(0, "repo",
+ NULL,
+ N_("<path>"),
+ N_("run jobs on the repository at <path>"),
+ PARSE_OPT_NONEG, arg_repos_append),
+ OPT_END(),
+ };
+
+ if (argc == 2 && !strcmp(argv[1], "-h"))
+ usage_with_options(builtin_job_runner_usage,
+ builtin_job_runner_options);
+
+ argc = parse_options(argc, argv, prefix,
+ builtin_job_runner_options,
+ builtin_job_runner_usage,
+ 0);
+
+ result = initialize_jobs(&job_list);
+
+ while (!(result = run_job_loop_step(&job_list))) {
+ unsigned int interval = get_loop_interval();
+ sleep(interval);
+ }
+
+ return result;
+}
@@ -110,6 +110,7 @@ git-init mainporcelain init
git-instaweb ancillaryinterrogators complete
git-interpret-trailers purehelpers
gitk mainporcelain
+git-job-runner plumbingmanipulators
git-log mainporcelain info
git-ls-files plumbinginterrogators
git-ls-remote plumbinginterrogators
@@ -517,6 +517,7 @@ static struct cmd_struct commands[] = {
{ "init", cmd_init_db },
{ "init-db", cmd_init_db },
{ "interpret-trailers", cmd_interpret_trailers, RUN_SETUP_GENTLY },
+ { "job-runner", cmd_job_runner, RUN_SETUP_GENTLY },
{ "log", cmd_log, RUN_SETUP },
{ "ls-files", cmd_ls_files, RUN_SETUP },
{ "ls-remote", cmd_ls_remote, RUN_SETUP_GENTLY },