On Tue, Jul 18, 2017 at 1:49 PM, Prathamesh Chavan <pc44800@xxxxxxxxx> wrote: > Port the submodule subcommand 'sync' from shell to C using the same > mechanism as that used for porting submodule subcommand 'status'. > Hence, here the function cmd_sync() is ported from shell to C. > This is done by introducing three functions: module_sync(), > sync_submodule() and print_default_remote(). > > The function print_default_remote() is introduced for getting > the default remote as stdout. > > Mentored-by: Christian Couder <christian.couder@xxxxxxxxx> > Mentored-by: Stefan Beller <sbeller@xxxxxxxxxx> > Signed-off-by: Prathamesh Chavan <pc44800@xxxxxxxxx> > --- > builtin/submodule--helper.c | 179 ++++++++++++++++++++++++++++++++++++++++++++ > git-submodule.sh | 56 +------------- > 2 files changed, 180 insertions(+), 55 deletions(-) > > diff --git a/builtin/submodule--helper.c b/builtin/submodule--helper.c > index 9c1630495..da91c489b 100644 > --- a/builtin/submodule--helper.c > +++ b/builtin/submodule--helper.c > @@ -44,6 +44,20 @@ static char *get_default_remote(void) > return ret; > } > > +static int print_default_remote(int argc, const char **argv, const char *prefix) > +{ > + const char *remote; > + > + if (argc != 1) > + die(_("submodule--helper print-default-remote takes no arguments")); > + > + remote = get_default_remote(); > + if (remote) > + puts(remote); > + > + return 0; > +} > + > static int starts_with_dot_slash(const char *str) > { > return str[0] == '.' && is_dir_sep(str[1]); > @@ -379,6 +393,25 @@ static void module_list_active(struct module_list *list) > *list = active_modules; > } > > +static char *get_up_path(const char *path) > +{ > + int i; > + struct strbuf sb = STRBUF_INIT; > + > + for (i = count_slashes(path); i; i--) > + strbuf_addstr(&sb, "../"); > + > + /* > + * Check if 'path' ends with slash or not > + * for having the same output for dir/sub_dir > + * and dir/sub_dir/ > + */ > + if (!is_dir_sep(path[strlen(path) - 1])) > + strbuf_addstr(&sb, "../"); > + > + return strbuf_detach(&sb, NULL); > +} > + > static int module_list(int argc, const char **argv, const char *prefix) > { > int i; > @@ -724,6 +757,150 @@ static int module_name(int argc, const char **argv, const char *prefix) > return 0; > } > > +struct sync_cb { > + const char *prefix; > + unsigned int quiet: 1; > + unsigned int recursive: 1; > +}; > +#define SYNC_CB_INIT { NULL, 0, 0 } > + > +static void sync_submodule(const struct cache_entry *list_item, void *cb_data) > +{ > + struct sync_cb *info = cb_data; > + const struct submodule *sub; > + char *sub_key, *remote_key; > + char *sub_origin_url, *super_config_url, *displaypath; > + struct strbuf sb = STRBUF_INIT; > + struct child_process cp = CHILD_PROCESS_INIT; > + > + if (!is_submodule_active(the_repository, list_item->name)) > + return; We can use the_repository here, as we also use child processes to recurse, such that we always operate on the_repository as the superproject. > + > + sub = submodule_from_path(null_sha1, list_item->name); > + > + if (!sub || !sub->url) > + die(_("no url found for submodule path '%s' in .gitmodules"), > + list_item->name); We do not die in the shell script when the url is missing in the .gitmodules file. > + > + if (starts_with_dot_dot_slash(sub->url) || starts_with_dot_slash(sub->url)) { > + char *remote_url, *up_path; > + char *remote = get_default_remote(); > + char *remote_key = xstrfmt("remote.%s.url", remote); > + > + if (git_config_get_string(remote_key, &remote_url)) > + remote_url = xgetcwd(); > + > + up_path = get_up_path(list_item->name); > + sub_origin_url = relative_url(remote_url, sub->url, up_path); > + super_config_url = relative_url(remote_url, sub->url, NULL); > + > + free(remote); > + free(remote_key); > + free(up_path); > + free(remote_url); > + } else { > + sub_origin_url = xstrdup(sub->url); > + super_config_url = xstrdup(sub->url); > + } > + > + displaypath = get_submodule_displaypath(list_item->name, info->prefix); > + > + if (!info->quiet) > + printf(_("Synchronizing submodule url for '%s'\n"), > + displaypath); > + > + sub_key = xstrfmt("submodule.%s.url", sub->name); > + if (git_config_set_gently(sub_key, super_config_url)) > + die(_("failed to register url for submodule path '%s'"), > + displaypath); > + > + if (!is_submodule_populated_gently(list_item->name, NULL)) > + goto cleanup; > + > + prepare_submodule_repo_env(&cp.env_array); > + cp.git_cmd = 1; > + cp.dir = list_item->name; > + argv_array_pushl(&cp.args, "submodule--helper", > + "print-default-remote", NULL); > + if (capture_command(&cp, &sb, 0)) > + die(_("failed to get the default remote for submodule '%s'"), > + list_item->name); > + > + strbuf_strip_suffix(&sb, "\n"); > + remote_key = xstrfmt("remote.%s.url", sb.buf); > + strbuf_release(&sb); > + > + child_process_init(&cp); > + prepare_submodule_repo_env(&cp.env_array); > + cp.git_cmd = 1; > + cp.dir = list_item->name; > + argv_array_pushl(&cp.args, "config", remote_key, sub_origin_url, NULL); > + if (run_command(&cp)) > + die(_("failed to update remote for submodule '%s'"), > + list_item->name); While it is a strict conversion from the shell script, we could also try to do this in-process: 1) we'd find out the submodules git dir using submodule_to_gitdir 2) construct the path the the config file as "%s/.gitconfig" 3) using git_config_set_in_file (which presumably takes file name, key and value) the value can be set