Skip to content

Commit 1342476

Browse files
pratham-pcgitster
authored andcommitted
submodule: port submodule subcommand 'sync' from shell to C
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 four functions: module_sync(), sync_submodule(), sync_submodule_cb() and print_default_remote(). The function print_default_remote() is introduced for getting the default remote as stdout. Mentored-by: Christian Couder <[email protected]> Mentored-by: Stefan Beller <[email protected]> Signed-off-by: Prathamesh Chavan <[email protected]> Signed-off-by: Junio C Hamano <[email protected]>
1 parent 36438dc commit 1342476

File tree

2 files changed

+194
-56
lines changed

2 files changed

+194
-56
lines changed

builtin/submodule--helper.c

Lines changed: 193 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -50,6 +50,20 @@ static char *get_default_remote(void)
5050
return ret;
5151
}
5252

53+
static int print_default_remote(int argc, const char **argv, const char *prefix)
54+
{
55+
const char *remote;
56+
57+
if (argc != 1)
58+
die(_("submodule--helper print-default-remote takes no arguments"));
59+
60+
remote = get_default_remote();
61+
if (remote)
62+
printf("%s\n", remote);
63+
64+
return 0;
65+
}
66+
5367
static int starts_with_dot_slash(const char *str)
5468
{
5569
return str[0] == '.' && is_dir_sep(str[1]);
@@ -358,6 +372,25 @@ static void module_list_active(struct module_list *list)
358372
*list = active_modules;
359373
}
360374

375+
static char *get_up_path(const char *path)
376+
{
377+
int i;
378+
struct strbuf sb = STRBUF_INIT;
379+
380+
for (i = count_slashes(path); i; i--)
381+
strbuf_addstr(&sb, "../");
382+
383+
/*
384+
* Check if 'path' ends with slash or not
385+
* for having the same output for dir/sub_dir
386+
* and dir/sub_dir/
387+
*/
388+
if (!is_dir_sep(path[strlen(path) - 1]))
389+
strbuf_addstr(&sb, "../");
390+
391+
return strbuf_detach(&sb, NULL);
392+
}
393+
361394
static int module_list(int argc, const char **argv, const char *prefix)
362395
{
363396
int i;
@@ -718,6 +751,164 @@ static int module_name(int argc, const char **argv, const char *prefix)
718751
return 0;
719752
}
720753

754+
struct sync_cb {
755+
const char *prefix;
756+
unsigned int flags;
757+
};
758+
759+
#define SYNC_CB_INIT { NULL, 0 }
760+
761+
static void sync_submodule(const char *path, const char *prefix,
762+
unsigned int flags)
763+
{
764+
const struct submodule *sub;
765+
char *remote_key = NULL;
766+
char *sub_origin_url, *super_config_url, *displaypath;
767+
struct strbuf sb = STRBUF_INIT;
768+
struct child_process cp = CHILD_PROCESS_INIT;
769+
char *sub_config_path = NULL;
770+
771+
if (!is_submodule_active(the_repository, path))
772+
return;
773+
774+
sub = submodule_from_path(&null_oid, path);
775+
776+
if (sub && sub->url) {
777+
if (starts_with_dot_dot_slash(sub->url) ||
778+
starts_with_dot_slash(sub->url)) {
779+
char *remote_url, *up_path;
780+
char *remote = get_default_remote();
781+
strbuf_addf(&sb, "remote.%s.url", remote);
782+
783+
if (git_config_get_string(sb.buf, &remote_url))
784+
remote_url = xgetcwd();
785+
786+
up_path = get_up_path(path);
787+
sub_origin_url = relative_url(remote_url, sub->url, up_path);
788+
super_config_url = relative_url(remote_url, sub->url, NULL);
789+
790+
free(remote);
791+
free(up_path);
792+
free(remote_url);
793+
} else {
794+
sub_origin_url = xstrdup(sub->url);
795+
super_config_url = xstrdup(sub->url);
796+
}
797+
} else {
798+
sub_origin_url = xstrdup("");
799+
super_config_url = xstrdup("");
800+
}
801+
802+
displaypath = get_submodule_displaypath(path, prefix);
803+
804+
if (!(flags & OPT_QUIET))
805+
printf(_("Synchronizing submodule url for '%s'\n"),
806+
displaypath);
807+
808+
strbuf_reset(&sb);
809+
strbuf_addf(&sb, "submodule.%s.url", sub->name);
810+
if (git_config_set_gently(sb.buf, super_config_url))
811+
die(_("failed to register url for submodule path '%s'"),
812+
displaypath);
813+
814+
if (!is_submodule_populated_gently(path, NULL))
815+
goto cleanup;
816+
817+
prepare_submodule_repo_env(&cp.env_array);
818+
cp.git_cmd = 1;
819+
cp.dir = path;
820+
argv_array_pushl(&cp.args, "submodule--helper",
821+
"print-default-remote", NULL);
822+
823+
strbuf_reset(&sb);
824+
if (capture_command(&cp, &sb, 0))
825+
die(_("failed to get the default remote for submodule '%s'"),
826+
path);
827+
828+
strbuf_strip_suffix(&sb, "\n");
829+
remote_key = xstrfmt("remote.%s.url", sb.buf);
830+
831+
strbuf_reset(&sb);
832+
submodule_to_gitdir(&sb, path);
833+
strbuf_addstr(&sb, "/config");
834+
835+
if (git_config_set_in_file_gently(sb.buf, remote_key, sub_origin_url))
836+
die(_("failed to update remote for submodule '%s'"),
837+
path);
838+
839+
if (flags & OPT_RECURSIVE) {
840+
struct child_process cpr = CHILD_PROCESS_INIT;
841+
842+
cpr.git_cmd = 1;
843+
cpr.dir = path;
844+
prepare_submodule_repo_env(&cpr.env_array);
845+
846+
argv_array_push(&cpr.args, "--super-prefix");
847+
argv_array_pushf(&cpr.args, "%s/", displaypath);
848+
argv_array_pushl(&cpr.args, "submodule--helper", "sync",
849+
"--recursive", NULL);
850+
851+
if (flags & OPT_QUIET)
852+
argv_array_push(&cpr.args, "--quiet");
853+
854+
if (run_command(&cpr))
855+
die(_("failed to recurse into submodule '%s'"),
856+
path);
857+
}
858+
859+
cleanup:
860+
free(super_config_url);
861+
free(sub_origin_url);
862+
strbuf_release(&sb);
863+
free(remote_key);
864+
free(displaypath);
865+
free(sub_config_path);
866+
}
867+
868+
static void sync_submodule_cb(const struct cache_entry *list_item, void *cb_data)
869+
{
870+
struct sync_cb *info = cb_data;
871+
sync_submodule(list_item->name, info->prefix, info->flags);
872+
873+
}
874+
875+
static int module_sync(int argc, const char **argv, const char *prefix)
876+
{
877+
struct sync_cb info = SYNC_CB_INIT;
878+
struct pathspec pathspec;
879+
struct module_list list = MODULE_LIST_INIT;
880+
int quiet = 0;
881+
int recursive = 0;
882+
883+
struct option module_sync_options[] = {
884+
OPT__QUIET(&quiet, N_("Suppress output of synchronizing submodule url")),
885+
OPT_BOOL(0, "recursive", &recursive,
886+
N_("Recurse into nested submodules")),
887+
OPT_END()
888+
};
889+
890+
const char *const git_submodule_helper_usage[] = {
891+
N_("git submodule--helper sync [--quiet] [--recursive] [<path>]"),
892+
NULL
893+
};
894+
895+
argc = parse_options(argc, argv, prefix, module_sync_options,
896+
git_submodule_helper_usage, 0);
897+
898+
if (module_list_compute(argc, argv, prefix, &pathspec, &list) < 0)
899+
return 1;
900+
901+
info.prefix = prefix;
902+
if (quiet)
903+
info.flags |= OPT_QUIET;
904+
if (recursive)
905+
info.flags |= OPT_RECURSIVE;
906+
907+
for_each_listed_submodule(&list, sync_submodule_cb, &info);
908+
909+
return 0;
910+
}
911+
721912
static int clone_submodule(const char *path, const char *gitdir, const char *url,
722913
const char *depth, struct string_list *reference,
723914
int quiet, int progress)
@@ -1498,6 +1689,8 @@ static struct cmd_struct commands[] = {
14981689
{"resolve-relative-url-test", resolve_relative_url_test, 0},
14991690
{"init", module_init, SUPPORT_SUPER_PREFIX},
15001691
{"status", module_status, SUPPORT_SUPER_PREFIX},
1692+
{"print-default-remote", print_default_remote, 0},
1693+
{"sync", module_sync, SUPPORT_SUPER_PREFIX},
15011694
{"remote-branch", resolve_remote_submodule_branch, 0},
15021695
{"push-check", push_check, 0},
15031696
{"absorb-git-dirs", absorb_git_dirs, SUPPORT_SUPER_PREFIX},

git-submodule.sh

Lines changed: 1 addition & 56 deletions
Original file line numberDiff line numberDiff line change
@@ -1036,63 +1036,8 @@ cmd_sync()
10361036
;;
10371037
esac
10381038
done
1039-
cd_to_toplevel
1040-
{
1041-
git submodule--helper list --prefix "$wt_prefix" "$@" ||
1042-
echo "#unmatched" $?
1043-
} |
1044-
while read -r mode sha1 stage sm_path
1045-
do
1046-
die_if_unmatched "$mode" "$sha1"
10471039

1048-
# skip inactive submodules
1049-
if ! git submodule--helper is-active "$sm_path"
1050-
then
1051-
continue
1052-
fi
1053-
1054-
name=$(git submodule--helper name "$sm_path")
1055-
url=$(git config -f .gitmodules --get submodule."$name".url)
1056-
1057-
# Possibly a url relative to parent
1058-
case "$url" in
1059-
./*|../*)
1060-
# rewrite foo/bar as ../.. to find path from
1061-
# submodule work tree to superproject work tree
1062-
up_path="$(printf '%s\n' "$sm_path" | sed "s/[^/][^/]*/../g")" &&
1063-
# guarantee a trailing /
1064-
up_path=${up_path%/}/ &&
1065-
# path from submodule work tree to submodule origin repo
1066-
sub_origin_url=$(git submodule--helper resolve-relative-url "$url" "$up_path") &&
1067-
# path from superproject work tree to submodule origin repo
1068-
super_config_url=$(git submodule--helper resolve-relative-url "$url") || exit
1069-
;;
1070-
*)
1071-
sub_origin_url="$url"
1072-
super_config_url="$url"
1073-
;;
1074-
esac
1075-
1076-
displaypath=$(git submodule--helper relative-path "$prefix$sm_path" "$wt_prefix")
1077-
say "$(eval_gettext "Synchronizing submodule url for '\$displaypath'")"
1078-
git config submodule."$name".url "$super_config_url"
1079-
1080-
if test -e "$sm_path"/.git
1081-
then
1082-
(
1083-
sanitize_submodule_env
1084-
cd "$sm_path"
1085-
remote=$(get_default_remote)
1086-
git config remote."$remote".url "$sub_origin_url"
1087-
1088-
if test -n "$recursive"
1089-
then
1090-
prefix="$prefix$sm_path/"
1091-
eval cmd_sync
1092-
fi
1093-
)
1094-
fi
1095-
done
1040+
git ${wt_prefix:+-C "$wt_prefix"} ${prefix:+--super-prefix "$prefix"} submodule--helper sync ${GIT_QUIET:+--quiet} ${recursive:+--recursive} "$@"
10961041
}
10971042

10981043
cmd_absorbgitdirs()

0 commit comments

Comments
 (0)