[PATCH 10/21] maintenance: add --task option

[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]

 



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                      | 62 ++++++++++++++++++++++++++++++-
 t/t7900-maintenance.sh            | 23 ++++++++++++
 3 files changed, 87 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 a6b080627f..8f2143862c 100644
--- a/builtin/gc.c
+++ b/builtin/gc.c
@@ -715,6 +715,7 @@ static const char * const builtin_maintenance_usage[] = {
 struct maintenance_opts {
 	int auto_flag;
 	int quiet;
+	int tasks_selected;
 } opts;
 
 static int run_write_commit_graph(struct repository *r)
@@ -812,7 +813,9 @@ struct maintenance_task {
 	struct hashmap_entry ent;
 	const char *name;
 	maintenance_task_fn *fn;
-	unsigned enabled:1;
+	int task_order;
+	unsigned enabled:1,
+		 selected:1;
 };
 
 static int task_entry_cmp(const void *unused_cmp_data,
@@ -833,14 +836,30 @@ struct maintenance_task *tasks[MAX_NUM_TASKS];
 int num_tasks;
 struct hashmap task_map;
 
+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(struct repository *r)
 {
 	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(r);
 	}
 
@@ -873,6 +892,42 @@ static void initialize_tasks(void)
 	}
 }
 
+static int task_option_parse(const struct option *opt,
+			     const char *arg, int unset)
+{
+	struct maintenance_task *task;
+	struct maintenance_task key;
+
+	BUG_ON_OPT_NEG(unset);
+
+	if (!arg || !strlen(arg)) {
+		error(_("--task requires a value"));
+		return 1;
+	}
+
+	opts.tasks_selected++;
+
+	key.name = arg;
+	hashmap_entry_init(&key.ent, strihash(key.name));
+
+	task = hashmap_get_entry(&task_map, &key, ent, NULL);
+
+	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)
 {
 	struct repository *r = the_repository;
@@ -882,6 +937,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




[Index of Archives]     [Linux Kernel Development]     [Gcc Help]     [IETF Annouce]     [DCCP]     [Netdev]     [Networking]     [Security]     [V4L]     [Bugtraq]     [Yosemite]     [MIPS Linux]     [ARM Linux]     [Linux Security]     [Linux RAID]     [Linux SCSI]     [Fedora Users]

  Powered by Linux