From: Derrick Stolee <dstolee@xxxxxxxxxxxxx> A user may want to only run certain maintenance tasks in a certain order. Add the --task=<task> option, which allows a user to specify an ordered list of tasks to run. These cannot be run multiple times, however. Here is where our array of maintenance_task pointers becomes critical. We can sort the array of pointers based on the task order, but we do not want to move the struct data itself in order to preserve the hashmap references. We use the hashmap to match the --task=<task> arguments into the task struct data. Signed-off-by: Derrick Stolee <dstolee@xxxxxxxxxxxxx> --- Documentation/git-maintenance.txt | 4 ++ builtin/gc.c | 64 ++++++++++++++++++++++++++++++- t/t7900-maintenance.sh | 23 +++++++++++ 3 files changed, 89 insertions(+), 2 deletions(-) diff --git a/Documentation/git-maintenance.txt b/Documentation/git-maintenance.txt index 35b0be7d40..9204762e21 100644 --- a/Documentation/git-maintenance.txt +++ b/Documentation/git-maintenance.txt @@ -73,6 +73,10 @@ OPTIONS --quiet:: Do not report progress or other information over `stderr`. +--task=<task>:: + If this option is specified one or more times, then only run the + specified tasks in the specified order. + GIT --- Part of the linkgit:git[1] suite diff --git a/builtin/gc.c b/builtin/gc.c index 2cd17398ec..c58dea6fa5 100644 --- a/builtin/gc.c +++ b/builtin/gc.c @@ -710,6 +710,7 @@ static const char * const builtin_maintenance_usage[] = { static struct maintenance_opts { int auto_flag; int quiet; + int tasks_selected; } opts; static int run_write_commit_graph(void) @@ -804,20 +805,38 @@ typedef int maintenance_task_fn(void); struct maintenance_task { const char *name; maintenance_task_fn *fn; - unsigned enabled:1; + int task_order; + unsigned enabled:1, + selected:1; }; static struct maintenance_task *tasks[MAX_NUM_TASKS]; static int num_tasks; +static int compare_tasks_by_selection(const void *a_, const void *b_) +{ + const struct maintenance_task *a, *b; + a = (const struct maintenance_task *)a_; + b = (const struct maintenance_task *)b_; + + return b->task_order - a->task_order; +} + static int maintenance_run(void) { int i; int result = 0; + if (opts.tasks_selected) + QSORT(tasks, num_tasks, compare_tasks_by_selection); + for (i = 0; !result && i < num_tasks; i++) { - if (!tasks[i]->enabled) + if (opts.tasks_selected && !tasks[i]->selected) + continue; + + if (!opts.tasks_selected && !tasks[i]->enabled) continue; + result = tasks[i]->fn(); } @@ -842,6 +861,44 @@ static void initialize_tasks(void) num_tasks++; } +static int task_option_parse(const struct option *opt, + const char *arg, int unset) +{ + int i; + struct maintenance_task *task = NULL; + + BUG_ON_OPT_NEG(unset); + + if (!arg || !strlen(arg)) { + error(_("--task requires a value")); + return 1; + } + + opts.tasks_selected++; + + for (i = 0; i < MAX_NUM_TASKS; i++) { + if (tasks[i] && !strcasecmp(tasks[i]->name, arg)) { + task = tasks[i]; + break; + } + } + + if (!task) { + error(_("'%s' is not a valid task"), arg); + return 1; + } + + if (task->selected) { + error(_("task '%s' cannot be selected multiple times"), arg); + return 1; + } + + task->selected = 1; + task->task_order = opts.tasks_selected; + + return 0; +} + int cmd_maintenance(int argc, const char **argv, const char *prefix) { static struct option builtin_maintenance_options[] = { @@ -849,6 +906,9 @@ int cmd_maintenance(int argc, const char **argv, const char *prefix) N_("run tasks based on the state of the repository")), OPT_BOOL(0, "quiet", &opts.quiet, N_("do not report progress or other information over stderr")), + OPT_CALLBACK_F(0, "task", NULL, N_("task"), + N_("run a specific task"), + PARSE_OPT_NONEG, task_option_parse), OPT_END() }; diff --git a/t/t7900-maintenance.sh b/t/t7900-maintenance.sh index 216ac0b19e..c09a9eb90b 100755 --- a/t/t7900-maintenance.sh +++ b/t/t7900-maintenance.sh @@ -21,4 +21,27 @@ test_expect_success 'run [--auto|--quiet]' ' grep ",\"gc\",\"--quiet\"" run-quiet.txt ' +test_expect_success 'run --task=<task>' ' + GIT_TRACE2_EVENT="$(pwd)/run-commit-graph.txt" git maintenance run --task=commit-graph && + GIT_TRACE2_EVENT="$(pwd)/run-gc.txt" git maintenance run --task=gc && + GIT_TRACE2_EVENT="$(pwd)/run-commit-graph.txt" git maintenance run --task=commit-graph && + GIT_TRACE2_EVENT="$(pwd)/run-both.txt" git maintenance run --task=commit-graph --task=gc && + ! grep ",\"gc\"" run-commit-graph.txt && + grep ",\"gc\"" run-gc.txt && + grep ",\"gc\"" run-both.txt && + grep ",\"commit-graph\",\"write\"" run-commit-graph.txt && + ! grep ",\"commit-graph\",\"write\"" run-gc.txt && + grep ",\"commit-graph\",\"write\"" run-both.txt +' + +test_expect_success 'run --task=bogus' ' + test_must_fail git maintenance run --task=bogus 2>err && + test_i18ngrep "is not a valid task" err +' + +test_expect_success 'run --task duplicate' ' + test_must_fail git maintenance run --task=gc --task=gc 2>err && + test_i18ngrep "cannot be selected multiple times" err +' + test_done -- gitgitgadget