Skip to content

Commit 090511b

Browse files
derrickstoleegitster
authored andcommitted
maintenance: add --task option
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. Keep in mind that the 'enabled' member of the maintenance_task struct is a placeholder for a future 'maintenance.<task>.enabled' config option. Thus, we use the 'enabled' member to specify which tasks are run when the user does not specify any --task=<task> arguments. The 'enabled' member should be ignored if --task=<task> appears. Signed-off-by: Derrick Stolee <[email protected]> Signed-off-by: Junio C Hamano <[email protected]>
1 parent 663b2b1 commit 090511b

File tree

3 files changed

+98
-4
lines changed

3 files changed

+98
-4
lines changed

Documentation/git-maintenance.txt

Lines changed: 8 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -30,7 +30,9 @@ SUBCOMMANDS
3030
-----------
3131

3232
run::
33-
Run one or more maintenance tasks.
33+
Run one or more maintenance tasks. If one or more `--task=<task>`
34+
options are specified, then those tasks are run in the provided
35+
order. Otherwise, only the `gc` task is run.
3436

3537
TASKS
3638
-----
@@ -63,6 +65,11 @@ OPTIONS
6365
--quiet::
6466
Do not report progress or other information over `stderr`.
6567

68+
--task=<task>::
69+
If this option is specified one or more times, then only run the
70+
specified tasks in the specified order. See the 'TASKS' section
71+
for the list of accepted `<task>` values.
72+
6673
GIT
6774
---
6875
Part of the linkgit:git[1] suite

builtin/gc.c

Lines changed: 63 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -701,7 +701,7 @@ int cmd_gc(int argc, const char **argv, const char *prefix)
701701
}
702702

703703
static const char * const builtin_maintenance_run_usage[] = {
704-
N_("git maintenance run [--auto] [--[no-]quiet]"),
704+
N_("git maintenance run [--auto] [--[no-]quiet] [--task=<task>]"),
705705
NULL
706706
};
707707

@@ -759,6 +759,9 @@ struct maintenance_task {
759759
const char *name;
760760
maintenance_task_fn *fn;
761761
unsigned enabled:1;
762+
763+
/* -1 if not selected. */
764+
int selected_order;
762765
};
763766

764767
enum maintenance_task_label {
@@ -781,13 +784,32 @@ static struct maintenance_task tasks[] = {
781784
},
782785
};
783786

787+
static int compare_tasks_by_selection(const void *a_, const void *b_)
788+
{
789+
const struct maintenance_task *a, *b;
790+
791+
a = (const struct maintenance_task *)&a_;
792+
b = (const struct maintenance_task *)&b_;
793+
794+
return b->selected_order - a->selected_order;
795+
}
796+
784797
static int maintenance_run_tasks(struct maintenance_run_opts *opts)
785798
{
786-
int i;
799+
int i, found_selected = 0;
787800
int result = 0;
788801

802+
for (i = 0; !found_selected && i < TASK__COUNT; i++)
803+
found_selected = tasks[i].selected_order >= 0;
804+
805+
if (found_selected)
806+
QSORT(tasks, TASK__COUNT, compare_tasks_by_selection);
807+
789808
for (i = 0; i < TASK__COUNT; i++) {
790-
if (!tasks[i].enabled)
809+
if (found_selected && tasks[i].selected_order < 0)
810+
continue;
811+
812+
if (!found_selected && !tasks[i].enabled)
791813
continue;
792814

793815
if (tasks[i].fn(opts)) {
@@ -799,20 +821,58 @@ static int maintenance_run_tasks(struct maintenance_run_opts *opts)
799821
return result;
800822
}
801823

824+
static int task_option_parse(const struct option *opt,
825+
const char *arg, int unset)
826+
{
827+
int i, num_selected = 0;
828+
struct maintenance_task *task = NULL;
829+
830+
BUG_ON_OPT_NEG(unset);
831+
832+
for (i = 0; i < TASK__COUNT; i++) {
833+
if (tasks[i].selected_order >= 0)
834+
num_selected++;
835+
if (!strcasecmp(tasks[i].name, arg)) {
836+
task = &tasks[i];
837+
}
838+
}
839+
840+
if (!task) {
841+
error(_("'%s' is not a valid task"), arg);
842+
return 1;
843+
}
844+
845+
if (task->selected_order >= 0) {
846+
error(_("task '%s' cannot be selected multiple times"), arg);
847+
return 1;
848+
}
849+
850+
task->selected_order = num_selected + 1;
851+
852+
return 0;
853+
}
854+
802855
static int maintenance_run(int argc, const char **argv, const char *prefix)
803856
{
857+
int i;
804858
struct maintenance_run_opts opts;
805859
struct option builtin_maintenance_run_options[] = {
806860
OPT_BOOL(0, "auto", &opts.auto_flag,
807861
N_("run tasks based on the state of the repository")),
808862
OPT_BOOL(0, "quiet", &opts.quiet,
809863
N_("do not report progress or other information over stderr")),
864+
OPT_CALLBACK_F(0, "task", NULL, N_("task"),
865+
N_("run a specific task"),
866+
PARSE_OPT_NONEG, task_option_parse),
810867
OPT_END()
811868
};
812869
memset(&opts, 0, sizeof(opts));
813870

814871
opts.quiet = !isatty(2);
815872

873+
for (i = 0; i < TASK__COUNT; i++)
874+
tasks[i].selected_order = -1;
875+
816876
argc = parse_options(argc, argv, prefix,
817877
builtin_maintenance_run_options,
818878
builtin_maintenance_run_usage,

t/t7900-maintenance.sh

Lines changed: 27 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -27,4 +27,31 @@ test_expect_success 'run [--auto|--quiet]' '
2727
test_subcommand git gc --no-quiet <run-no-quiet.txt
2828
'
2929

30+
test_expect_success 'run --task=<task>' '
31+
GIT_TRACE2_EVENT="$(pwd)/run-commit-graph.txt" \
32+
git maintenance run --task=commit-graph 2>/dev/null &&
33+
GIT_TRACE2_EVENT="$(pwd)/run-gc.txt" \
34+
git maintenance run --task=gc 2>/dev/null &&
35+
GIT_TRACE2_EVENT="$(pwd)/run-commit-graph.txt" \
36+
git maintenance run --task=commit-graph 2>/dev/null &&
37+
GIT_TRACE2_EVENT="$(pwd)/run-both.txt" \
38+
git maintenance run --task=commit-graph --task=gc 2>/dev/null &&
39+
test_subcommand ! git gc --quiet <run-commit-graph.txt &&
40+
test_subcommand git gc --quiet <run-gc.txt &&
41+
test_subcommand git gc --quiet <run-both.txt &&
42+
test_subcommand git commit-graph write --split --reachable --no-progress <run-commit-graph.txt &&
43+
test_subcommand ! git commit-graph write --split --reachable --no-progress <run-gc.txt &&
44+
test_subcommand git commit-graph write --split --reachable --no-progress <run-both.txt
45+
'
46+
47+
test_expect_success 'run --task=bogus' '
48+
test_must_fail git maintenance run --task=bogus 2>err &&
49+
test_i18ngrep "is not a valid task" err
50+
'
51+
52+
test_expect_success 'run --task duplicate' '
53+
test_must_fail git maintenance run --task=gc --task=gc 2>err &&
54+
test_i18ngrep "cannot be selected multiple times" err
55+
'
56+
3057
test_done

0 commit comments

Comments
 (0)