Add a new "add-config" subcommand to `git submodule--helper` with the
goal of converting part of the shell code in git-submodule.sh related to
`git submodule add` into C code. This new subcommand sets the
configuration variables of a newly added submodule, by registering the
url in local git config, as well as the submodule name and path in the
.gitmodules file. It also sets 'submodule.<name>.active' to "true" if
the submodule path has not already been covered by any pathspec
specified in 'submodule.active'.
This is meant to be a faithful conversion from shell to C, although we
add comments to areas that could be improved in future patches, after
the conversion has settled.
Signed-off-by: Atharva Raykar <raykar.ath@gmail.com>
Mentored-by: Christian Couder <christian.couder@gmail.com>
Mentored-by: Shourya Shukla <periperidip@gmail.com>
Based-on-patch-by: Shourya Shukla <periperidip@gmail.com>
Based-on-patch-by: Prathamesh Chavan <pc44800@gmail.com>
Signed-off-by: Junio C Hamano <gitster@pobox.com>
Atharva Raykar committedAug 6, 2021 at 19:34 UTCa452128a36cb73f5366c23eabe93c7edfa227866
3 files changed+135-27
builtin/submodule--helper.c
+129
index a592ecaec1..7c3ed74118 100644--- a/builtin/submodule--helper.c+++ b/builtin/submodule--helper.c@@ -2935,6 +2935,134 @@ static int add_clone(int argc, const char **argv, const char *prefix) return 0; }+static int config_submodule_in_gitmodules(const char *name, const char *var, const char *value)+{+ char *key;+ int ret;++ if (!is_writing_gitmodules_ok())+ die(_("please make sure that the .gitmodules file is in the working tree"));++ key = xstrfmt("submodule.%s.%s", name, var);+ ret = config_set_in_gitmodules_file_gently(key, value);+ free(key);++ return ret;+}++static void configure_added_submodule(struct add_data *add_data)+{+ char *key;+ char *val = NULL;+ struct child_process add_submod = CHILD_PROCESS_INIT;+ struct child_process add_gitmodules = CHILD_PROCESS_INIT;++ key = xstrfmt("submodule.%s.url", add_data->sm_name);+ git_config_set_gently(key, add_data->realrepo);+ free(key);++ add_submod.git_cmd = 1;+ strvec_pushl(&add_submod.args, "add",+ "--no-warn-embedded-repo", NULL);+ if (add_data->force)+ strvec_push(&add_submod.args, "--force");+ strvec_pushl(&add_submod.args, "--", add_data->sm_path, NULL);++ if (run_command(&add_submod))+ die(_("Failed to add submodule '%s'"), add_data->sm_path);++ if (config_submodule_in_gitmodules(add_data->sm_name, "path", add_data->sm_path) ||+ config_submodule_in_gitmodules(add_data->sm_name, "url", add_data->repo))+ die(_("Failed to register submodule '%s'"), add_data->sm_path);++ if (add_data->branch) {+ if (config_submodule_in_gitmodules(add_data->sm_name,+ "branch", add_data->branch))+ die(_("Failed to register submodule '%s'"), add_data->sm_path);+ }++ add_gitmodules.git_cmd = 1;+ strvec_pushl(&add_gitmodules.args,+ "add", "--force", "--", ".gitmodules", NULL);++ if (run_command(&add_gitmodules))+ die(_("Failed to register submodule '%s'"), add_data->sm_path);++ /*+ * NEEDSWORK: In a multi-working-tree world this needs to be+ * set in the per-worktree config.+ */+ /*+ * NEEDSWORK: In the longer run, we need to get rid of this+ * pattern of querying "submodule.active" before calling+ * is_submodule_active(), since that function needs to find+ * out the value of "submodule.active" again anyway.+ */+ if (!git_config_get_string("submodule.active", &val) && val) {+ /*+ * If the submodule being added isn't already covered by the+ * current configured pathspec, set the submodule's active flag+ */+ if (!is_submodule_active(the_repository, add_data->sm_path)) {+ key = xstrfmt("submodule.%s.active", add_data->sm_name);+ git_config_set_gently(key, "true");+ free(key);+ }+ } else {+ key = xstrfmt("submodule.%s.active", add_data->sm_name);+ git_config_set_gently(key, "true");+ free(key);+ }+}++static int add_config(int argc, const char **argv, const char *prefix)+{+ int force = 0;+ struct add_data add_data = ADD_DATA_INIT;++ struct option options[] = {+ OPT_STRING('b', "branch", &add_data.branch,+ N_("branch"),+ N_("branch of repository to store in "+ "the submodule configuration")),+ OPT_STRING(0, "url", &add_data.repo,+ N_("string"),+ N_("url to clone submodule from")),+ OPT_STRING(0, "resolved-url", &add_data.realrepo,+ N_("string"),+ N_("url to clone the submodule from, after it has "+ "been dereferenced relative to parent's url, "+ "in the case where <url> is a relative url")),+ OPT_STRING(0, "path", &add_data.sm_path,+ N_("path"),+ N_("where the new submodule will be cloned to")),+ OPT_STRING(0, "name", &add_data.sm_name,+ N_("string"),+ N_("name of the new submodule")),+ OPT__FORCE(&force, N_("allow adding an otherwise ignored submodule path"),+ PARSE_OPT_NOCOMPLETE),+ OPT_END()+ };++ const char *const usage[] = {+ N_("git submodule--helper add-config "+ "[--force|-f] [--branch|-b <branch>] "+ "--url <url> --resolved-url <resolved-url> "+ "--path <path> --name <name>"),+ NULL+ };++ argc = parse_options(argc, argv, prefix, options, usage, 0);++ if (argc)+ usage_with_options(usage, options);++ add_data.force = !!force;+ configure_added_submodule(&add_data);++ return 0;+}+ #define SUPPORT_SUPER_PREFIX (1<<0) struct cmd_struct {@@ -2948,6 +3076,7 @@ static struct cmd_struct commands[] = { {"name", module_name, 0}, {"clone", module_clone, 0}, {"add-clone", add_clone, 0},+ {"add-config", add_config, 0}, {"update-module-mode", module_update_module_mode, 0}, {"update-clone", update_clone, 0}, {"ensure-core-worktree", ensure_core_worktree, 0},
git-submodule.sh
+1-27
index 053daf3724..f713cb113c 100755--- a/git-submodule.sh+++ b/git-submodule.sh@@ -242,33 +242,7 @@ cmd_add() fi git submodule--helper add-clone ${GIT_QUIET:+--quiet} ${force:+"--force"} ${progress:+"--progress"} ${branch:+--branch "$branch"} --prefix "$wt_prefix" --path "$sm_path" --name "$sm_name" --url "$realrepo" ${reference:+"$reference"} ${dissociate:+"--dissociate"} ${depth:+"$depth"} || exit- git config submodule."$sm_name".url "$realrepo"-- git add --no-warn-embedded-repo $force "$sm_path" ||- die "fatal: $(eval_gettext "Failed to add submodule '\$sm_path'")"-- git submodule--helper config submodule."$sm_name".path "$sm_path" &&- git submodule--helper config submodule."$sm_name".url "$repo" &&- if test -n "$branch"- then- git submodule--helper config submodule."$sm_name".branch "$branch"- fi &&- git add --force .gitmodules ||- die "fatal: $(eval_gettext "Failed to register submodule '\$sm_path'")"-- # NEEDSWORK: In a multi-working-tree world, this needs to be- # set in the per-worktree config.- if git config --get submodule.active >/dev/null- then- # If the submodule being adding isn't already covered by the- # current configured pathspec, set the submodule's active flag- if ! git submodule--helper is-active "$sm_path"- then- git config submodule."$sm_name".active "true"- fi- else- git config submodule."$sm_name".active "true"- fi+ git submodule--helper add-config ${force:+--force} ${branch:+--branch "$branch"} --url "$repo" --resolved-url "$realrepo" --path "$sm_path" --name "$sm_name" } #
submodule.c
+5
index 0b1d9c1dde..8577667773 100644--- a/submodule.c+++ b/submodule.c@@ -237,6 +237,11 @@ int option_parse_recurse_submodules_worktree_updater(const struct option *opt, /* * Determine if a submodule has been initialized at a given 'path' */+/*+ * NEEDSWORK: Emit a warning if submodule.active exists, but is valueless,+ * ie, the config looks like: "[submodule] active\n".+ * Since that is an invalid pathspec, we should inform the user.+ */ int is_submodule_active(struct repository *repo, const char *path) { int ret = 0;