On 07/25, Prathamesh Chavan 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.cou...@gmail.com>
> Mentored-by: Stefan Beller <sbel...@google.com>
> Signed-off-by: Prathamesh Chavan <pc44...@gmail.com>
> ---
> In this new version of patch, following changes were made:
> * the code use to die when sub->url was found to be NULL. This was not a
>   correct translation of code. It was corrected by using an empty string
>   instead of sub->url.
> * a process was used in the previous patch for registering the submodule
>   url. This was avoided by the suggested changes on the previous patch.
> * some nits were also corrected.
>  
>  builtin/submodule--helper.c | 183 
> ++++++++++++++++++++++++++++++++++++++++++++
>  git-submodule.sh            |  56 +-------------
>  2 files changed, 184 insertions(+), 55 deletions(-)
> 
> diff --git a/builtin/submodule--helper.c b/builtin/submodule--helper.c
> index b39828174..2d1d3984d 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);

Any reason why puts is used instead of a printf function?

> +
> +     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;
> @@ -729,6 +762,154 @@ 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;
> +     struct strbuf sub_repo_path = STRBUF_INIT;

Not the most important but you could be a lot more efficient here with
your variables.  You could allocate a single strbuf and reuse it for
'sub_key'. 'remote_key', 'sb', and 'sub_repo_path' as it doesn't look
like you need any of those two at the same time.

> +     char *sub_config_path = NULL;
> +
> +     if (!is_submodule_active(the_repository, list_item->name))
> +             return;
> +
> +     sub = submodule_from_path(null_sha1, list_item->name);

Since is_submodule_active also calls into the submodule-config subsystem
to retrieve a submodule this call should never return a NULL ptr...so it
may be safer to return instead of proceeding if 'sub' ends up being null
here.

> +
> +     if (sub && sub->url) {
> +             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);
> +             }
> +     } else {
> +             sub_origin_url = "";
> +             super_config_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);
> +
> +     submodule_to_gitdir(&sub_repo_path, list_item->name);

This function (submodule_to_gitdir) has some poor characteristics in
that it will succeed even if there isn't a configured submodule but
there just happens to be a submodule at the provided path...but it looks
like none of them will affect this as the fist thing this function does
is check if the submodule is active before preceding.

> +     sub_config_path = xstrfmt("%s/config", sub_repo_path.buf);
> +     strbuf_release(&sub_repo_path);
> +
> +     if (git_config_set_in_file_gently(sub_config_path, remote_key, 
> sub_origin_url))
> +             die(_("failed to update remote for submodule '%s'"),
> +                   list_item->name);
> +
> +     if (info->recursive) {
> +             struct child_process cpr = CHILD_PROCESS_INIT;
> +
> +             cpr.git_cmd = 1;
> +             cpr.dir = list_item->name;
> +             prepare_submodule_repo_env(&cpr.env_array);
> +
> +             argv_array_pushl(&cpr.args, "--super-prefix", displaypath,

Same comment as the previous patch here.

> +                              "submodule--helper", "sync", "--recursive",
> +                              NULL);
> +
> +             if (info->quiet)
> +                     argv_array_push(&cpr.args, "--quiet");
> +
> +             if (run_command(&cpr))
> +                     die(_("failed to recurse into submodule '%s'"),
> +                           list_item->name);
> +     }
> +
> +cleanup:
> +     free(sub_key);
> +     free(super_config_url);
> +     free(displaypath);
> +     free(sub_config_path);
> +     free(sub_origin_url);
> +}
> +
> +static int module_sync(int argc, const char **argv, const char *prefix)
> +{
> +     struct sync_cb info = SYNC_CB_INIT;
> +     struct pathspec pathspec;
> +     struct module_list list = MODULE_LIST_INIT;
> +     int quiet = 0;
> +     int recursive = 0;
> +
> +     struct option module_sync_options[] = {
> +             OPT__QUIET(&quiet, N_("Suppress output of synchronizing 
> submodule url")),
> +             OPT_BOOL(0, "recursive", &recursive,
> +                     N_("Recurse into nested submodules")),
> +             OPT_END()
> +     };
> +
> +     const char *const git_submodule_helper_usage[] = {
> +             N_("git submodule--helper sync [--quiet] [--recursive] 
> [<path>]"),
> +             NULL
> +     };
> +
> +     argc = parse_options(argc, argv, prefix, module_sync_options,
> +                          git_submodule_helper_usage, 0);
> +
> +     if (module_list_compute(argc, argv, prefix, &pathspec, &list) < 0)
> +             return 1;
> +
> +     info.prefix = prefix;
> +     info.quiet = !!quiet;
> +     info.recursive = !!recursive;
> +
> +     gitmodules_config();
> +     for_each_submodule_list(list, sync_submodule, &info);
> +
> +     return 0;
> +}
> +
>  static int clone_submodule(const char *path, const char *gitdir, const char 
> *url,
>                          const char *depth, struct string_list *reference,
>                          int quiet, int progress)
> @@ -1457,6 +1638,8 @@ static struct cmd_struct commands[] = {
>       {"print-name-rev", print_name_rev, 0},
>       {"init", module_init, SUPPORT_SUPER_PREFIX},
>       {"status", module_status, SUPPORT_SUPER_PREFIX},
> +     {"print-default-remote", print_default_remote, 0},
> +     {"sync", module_sync, SUPPORT_SUPER_PREFIX},
>       {"remote-branch", resolve_remote_submodule_branch, 0},
>       {"push-check", push_check, 0},
>       {"absorb-git-dirs", absorb_git_dirs, SUPPORT_SUPER_PREFIX},
> diff --git a/git-submodule.sh b/git-submodule.sh
> index 51b057d82..6bfc5e17d 100755
> --- a/git-submodule.sh
> +++ b/git-submodule.sh
> @@ -1037,63 +1037,9 @@ cmd_sync()
>                       ;;
>               esac
>       done
> -     cd_to_toplevel
> -     {
> -             git submodule--helper list --prefix "$wt_prefix" "$@" ||
> -             echo "#unmatched" $?
> -     } |
> -     while read -r mode sha1 stage sm_path
> -     do
> -             die_if_unmatched "$mode" "$sha1"
> -
> -             # skip inactive submodules
> -             if ! git submodule--helper is-active "$sm_path"
> -             then
> -                     continue
> -             fi
> -
> -             name=$(git submodule--helper name "$sm_path")
> -             url=$(git config -f .gitmodules --get submodule."$name".url)
> -
> -             # Possibly a url relative to parent
> -             case "$url" in
> -             ./*|../*)
> -                     # rewrite foo/bar as ../.. to find path from
> -                     # submodule work tree to superproject work tree
> -                     up_path="$(printf '%s\n' "$sm_path" | sed 
> "s/[^/][^/]*/../g")" &&
> -                     # guarantee a trailing /
> -                     up_path=${up_path%/}/ &&
> -                     # path from submodule work tree to submodule origin repo
> -                     sub_origin_url=$(git submodule--helper 
> resolve-relative-url "$url" "$up_path") &&
> -                     # path from superproject work tree to submodule origin 
> repo
> -                     super_config_url=$(git submodule--helper 
> resolve-relative-url "$url") || exit
> -                     ;;
> -             *)
> -                     sub_origin_url="$url"
> -                     super_config_url="$url"
> -                     ;;
> -             esac
>  
> -             displaypath=$(git submodule--helper relative-path 
> "$prefix$sm_path" "$wt_prefix")
> -             say "$(eval_gettext "Synchronizing submodule url for 
> '\$displaypath'")"
> -             git config submodule."$name".url "$super_config_url"
> -
> -             if test -e "$sm_path"/.git
> -             then
> -             (
> -                     sanitize_submodule_env
> -                     cd "$sm_path"
> -                     remote=$(get_default_remote)
> -                     git config remote."$remote".url "$sub_origin_url"
> +     git ${wt_prefix:+-C "$wt_prefix"} ${prefix:+--super-prefix "$prefix"} 
> submodule--helper sync ${GIT_QUIET:+--quiet} ${recursive:+--recursive} "$@"
>  
> -                     if test -n "$recursive"
> -                     then
> -                             prefix="$prefix$sm_path/"
> -                             eval cmd_sync
> -                     fi
> -             )
> -             fi
> -     done
>  }
>  
>  cmd_absorbgitdirs()
> -- 
> 2.13.0
> 

-- 
Brandon Williams

Reply via email to