git/list[1] front-page[2] threads[3] people[4] search[5] about
 

[PATCH v3 3/3] gc: replace config subprocesses with API calls

From
Derrick Stolee via GitGitGadget <gitgitgadget@gmail.com>
Date
Sep 26, 2022, 18:48 UTC
Message-ID
<260d7bee36e1af2f6a6a8791d293402e97a502e6.1664218087.git.gitgitgadget@gmail.com>
In-Reply-To
<pull.1358.v3.git.1664218087.gitgitgadget@gmail.com>
From: Derrick Stolee <derrickstolee@github.com>

The 'git maintenance [un]register' commands set or unset the multi- valued maintenance.repo config key with the absolute path of the current repository. These are set in the global config file.

Instead of calling a subcommand and creating a new process, create the proper API calls to git_config_set_multivar_in_file_gently(). It requires loading the filename for the global config file (and erroring out if now $HOME value is set). We also need to be careful about using CONFIG_REGEX_NONE when adding the value and using CONFIG_FLAGS_FIXED_VALUE when removing the value. In both cases, we check that the value already exists (this check already existed for 'unregister').

Also, remove the transparent translation of the error code from the config API to the exit code of 'git maintenance'. Instead, use die() to recover from failures at that level. In the case of 'unregister --force', allow the CONFIG_NOTHING_SET error code to be a success. This allows a possible race where another process removes the config value. The end result is that the config value is not set anymore, so we can treat this as a success.

Reported-by: SZEDER Gábor <szeder.dev@gmail.com>
Signed-off-by: Derrick Stolee <derrickstolee@github.com>
---
 builtin/gc.c | 75 ++++++++++++++++++++++++++++++----------------------
 1 file changed, 44 insertions(+), 31 deletions(-)
diff --git a/builtin/gc.c b/builtin/gc.c
index 8d154586272..4c59235950d 100644
--- a/builtin/gc.c
+++ b/builtin/gc.c
@@ -1470,11 +1470,12 @@ static int maintenance_register(int argc, const char **argv, const char *prefix)
 	struct option options[] = {
 		OPT_END(),
 	};
-	int rc;
+	int found = 0;
+	const char *key = "maintenance.repo";
 	char *config_value;
-	struct child_process config_set = CHILD_PROCESS_INIT;
-	struct child_process config_get = CHILD_PROCESS_INIT;
 	char *maintpath = get_maintpath();
+	struct string_list_item *item;
+	const struct string_list *list;
 
 	argc = parse_options(argc, argv, prefix, options,
 			     builtin_maintenance_register_usage, 0);
@@ -1491,31 +1492,35 @@ static int maintenance_register(int argc, const char **argv, const char *prefix)
 	else
 		git_config_set("maintenance.strategy", "incremental");
 
-	config_get.git_cmd = 1;
-	strvec_pushl(&config_get.args, "config", "--global", "--get",
-		     "--fixed-value", "maintenance.repo", maintpath, NULL);
-	config_get.out = -1;
-
-	if (start_command(&config_get)) {
-		rc = error(_("failed to run 'git config'"));
-		goto done;
+	list = git_config_get_value_multi(key);
+	if (list) {
+		for_each_string_list_item(item, list) {
+			if (!strcmp(maintpath, item->string)) {
+				found = 1;
+				break;
+			}
+		}
 	}
 
-	/* We already have this value in our config! */
-	if (!finish_command(&config_get)) {
-		rc = 0;
-		goto done;
+	if (!found) {
+		int rc;
+		char *user_config, *xdg_config;
+		git_global_config(&user_config, &xdg_config);
+		if (!user_config)
+			die(_("$HOME not set"));
+		rc = git_config_set_multivar_in_file_gently(
+			user_config, "maintenance.repo", maintpath,
+			CONFIG_REGEX_NONE, 0);
+		free(user_config);
+		free(xdg_config);
+
+		if (rc)
+			die(_("unable to add '%s' value of '%s'"),
+			    key, maintpath);
 	}
 
-	config_set.git_cmd = 1;
-	strvec_pushl(&config_set.args, "config", "--add", "--global", "maintenance.repo",
-		     maintpath, NULL);
-
-	rc = run_command(&config_set);
-
-done:
 	free(maintpath);
-	return rc;
+	return 0;
 }
 
 static char const * const builtin_maintenance_unregister_usage[] = {
@@ -1533,8 +1538,6 @@ static int maintenance_unregister(int argc, const char **argv, const char *prefi
 		OPT_END(),
 	};
 	const char *key = "maintenance.repo";
-	int rc = 0;
-	struct child_process config_unset = CHILD_PROCESS_INIT;
 	char *maintpath = get_maintpath();
 	int found = 0;
 	struct string_list_item *item;
@@ -1554,17 +1557,27 @@ static int maintenance_unregister(int argc, const char **argv, const char *prefi
 	}
 
 	if (found) {
-		config_unset.git_cmd = 1;
-		strvec_pushl(&config_unset.args, "config", "--global", "--unset",
-			     "--fixed-value", key, maintpath, NULL);
-
-		rc = run_command(&config_unset);
+		int rc;
+		char *user_config, *xdg_config;
+		git_global_config(&user_config, &xdg_config);
+		if (!user_config)
+			die(_("$HOME not set"));
+		rc = git_config_set_multivar_in_file_gently(
+			user_config, key, NULL, maintpath,
+			CONFIG_FLAGS_MULTI_REPLACE | CONFIG_FLAGS_FIXED_VALUE);
+		free(user_config);
+		free(xdg_config);
+
+		if (rc &&
+		    (!force || rc == CONFIG_NOTHING_SET))
+			die(_("unable to unset '%s' value of '%s'"),
+			    key, maintpath);
 	} else if (!force) {
 		die(_("repository '%s' is not registered"), maintpath);
 	}
 
 	free(maintpath);
-	return rc;
+	return 0;
 }
 
 static const char *get_frequency(enum schedule_priority schedule)
-- 
gitgitgadget
Previous: Derrick Stolee via GitGitGadgetNext: Junio C Hamano
Message 25 of 34 in “maintenance: make unregister idempotent”
  1. maintenance: make unregister idempotentDerrick Stolee via GitGitGadget, Sep 20, 2022
  2. Junio C HamanoSep 21, 2022
  3. Derrick StoleeSep 22, 2022
  4. Junio C HamanoSep 22, 2022
  5. Derrick StoleeSep 22, 2022
  6. Junio C HamanoSep 22, 2022
  7. 0/2 scalar: make unregister idempotentDerrick Stolee via GitGitGadget, Sep 22, 2022
  8. 2/2 scalar: make 'unregister' idempotentDerrick Stolee via GitGitGadget, Sep 22, 2022
  9. 1/2 maintenance: add 'unregister --force'Derrick Stolee via GitGitGadget, Sep 22, 2022
  10. SZEDER GáborSep 23, 2022
  11. Derrick StoleeSep 26, 2022
  12. Ævar Arnfjörð BjarmasonSep 26, 2022
  13. Derrick StoleeSep 26, 2022
  14. Junio C HamanoSep 26, 2022
  15. 0/3 scalar: make unregister idempotentDerrick Stolee via GitGitGadget, Sep 26, 2022
  16. 1/3 maintenance: add 'unregister --force'Derrick Stolee via GitGitGadget, Sep 26, 2022
  17. Junio C HamanoSep 26, 2022
  18. Derrick StoleeSep 26, 2022
  19. Junio C HamanoSep 26, 2022
  20. Derrick StoleeSep 27, 2022
  21. Derrick StoleeSep 27, 2022
  22. Ævar Arnfjörð BjarmasonSep 27, 2022
  23. Derrick StoleeSep 27, 2022
  24. 2/3 scalar: make 'unregister' idempotentDerrick Stolee via GitGitGadget, Sep 26, 2022
  25. 3/3 gc: replace config subprocesses with API callsDerrick Stolee via GitGitGadget, Sep 26, 2022
  26. Junio C HamanoSep 26, 2022
  27. 0/4 scalar: make unregister idempotentDerrick Stolee via GitGitGadget, Sep 27, 2022
  28. 1/4 maintenance: add 'unregister --force'Derrick Stolee via GitGitGadget, Sep 27, 2022
  29. 2/4 scalar: make 'unregister' idempotentDerrick Stolee via GitGitGadget, Sep 27, 2022
  30. 3/4 gc: replace config subprocesses with API callsDerrick Stolee via GitGitGadget, Sep 27, 2022
  31. 4/4 string-list: document iterator behavior on NULL inputDerrick Stolee via GitGitGadget, Sep 27, 2022
  32. Junio C HamanoSep 27, 2022
  33. Junio C HamanoSep 27, 2022
  34. Derrick StoleeSep 27, 2022

Read the whole thread, see it on lore, or plain text.

$ cat FOOTERMessages come from the public archive at lore.kernel.org/git, fetched every hour. The front page is chosen and written each morning by an AI editor and can be wrong; the threads themselves are the record. About and API. For agents: an MCP server at https://gitlist.dev/mcp, and any thread, story or person page as Markdown by adding .md to its URL (or sending Accept: text/markdown). Details in /llms.txt.