{"thread":{"id":"46265","subject":"[GSoC] Update: Week 6","startedAt":"2017-06-26T23:09:19Z","lastAt":"2017-07-13T22:44:15Z","messageCount":28,"participants":["Prathamesh Chavan","Christian Couder","Junio C Hamano","Stefan Beller"],"isPatch":false,"patchVersion":null,"patchTotal":null},"messages":[{"id":"323297","messageId":"CAME+mvUrr8EA-6jbCZdpB7dMZ5CN3RyY7yoRoUBoiZw=sH6Ysw@mail.gmail.com","threadId":"46265","inReplyTo":null,"subject":"[GSoC] Update: Week 6","fromName":"Prathamesh Chavan","fromEmail":"pc44800@gmail.com","sentAt":"2017-06-26T23:09:13Z","receivedAt":"2017-06-26T23:09:19Z","isPatch":false,"sender":{"key":"pc44800@gmail.com","avatar":"https://avatars.githubusercontent.com/u/17272661?v=4"},"body":"SUMMARY OF MY PROJECT:\n\nGit submodule subcommands are currently implemented by using shell script\n'git-submodule.sh'. There are several reasons why we'll prefer not to\nuse the shell script. My project intends to convert the subcommands into\nC code, thus making them builtins. This will increase Git's portability\nand hence the efficiency of working with the git-submodule commands.\nLink to the complete proposal: [1]\n\nMentors:\nStefan Beller <sbeller@google.com>\nChristian Couder <christian.couder@gmail.com>\n\nUPDATES:\n\nFollowing are the updates about my ongoing project:\n\n1. sync and status: The patches were discussed with the mentors\n   and after that, are being posted with this patch.\n\n2. deinit: The patch is debugged, and is ready to be\n   discussed. Not much discussion occurred over this patch\n   and hence the patch is same as its previous version.\n   It is also attached with this update.\n\n3. summary: The porting of this submodule subcommand is\n   almost completed. Things like improving the function\n   names, checking for memory leakage, etc are still\n   left to be taken care of. I'm updating the patch's status\n   by sending the patch to the mentors off-list, so that\n   an appropriate version is posted here on the list.\n   Hence, it wasn't attached to the update.\n\n4. foreach: Not much progress was done with this patch\n   in particular as most of the time was used for completing\n   the porting of submodule subcommand 'summary'.\n   Hence its status remains same as mentioned in the\n   previous update, which is reposted below:\n   'As stated in the previous update, the subcommand was\n   ported without resolving the bug, and simply translating the\n   present code, and adding a NEEDSWORK tag to the comment for\n   mentioning the reported bug as well.\n   But as communicating between child_process is still an issue\n   and so there was no simple was to current carry out the\n   porting. And hence, a hack was used instead. But after\n   discussing it, instead using the repository-object patch\n   series will help to resolve these issues in this situation.'\n\nPLAN FOR WEEK-7 (27 June 2017 to 3 July 2017):\n\n1. foreach: Since the required changes weren't made in the last\n   week in regards with this patch, in the next week I aim for\n   fulfilling them first. I'll like to again mention it here:\n   As it was decided that unblock the conversion of\n   this submodule subcommand, the original cmd_foreach was\n   ported without including the BUG-FIX patch here.\n   Hence, for this week I will try to utilize the\n   'repository-object' series by Brandon Williams.\n   Additionally, I'll like to mention that this update\n   still, doesn't depend on the 'repository-object' series,\n   which I'll be trying to change in the next update.\n\n2. summary: As mentioned earlier, since there is still a little\n   work with its porting left, I'll try to finish it and debug\n   the ported code as well.\n\n3. deinit: As there is still scope of improvision and discussion\n   I'll also be focussing on improving this patch.\n\n[1]: https://docs.google.com/document/d/1krxVLooWl--75Pot3dazhfygR3wCUUWZWzTXtK1L-xU/\n\nThanks,\nPrathamesh Chavan\n"},{"id":"323298","messageId":"20170626231108.23640-1-pc44800@gmail.com","threadId":"46265","inReplyTo":"CAME+mvUrr8EA-6jbCZdpB7dMZ5CN3RyY7yoRoUBoiZw=sH6Ysw@mail.gmail.com","subject":"[GSoC][PATCH 1/6 v2] submodule--helper: introduce for_each_submodule_list","fromName":"Prathamesh Chavan","fromEmail":"pc44800@gmail.com","sentAt":"2017-06-26T23:11:03Z","receivedAt":"2017-06-26T23:11:28Z","isPatch":true,"sender":{"key":"pc44800@gmail.com","avatar":"https://avatars.githubusercontent.com/u/17272661?v=4"},"body":"Introduce function for_each_submodule_list for using it\nin the later patches, related to porting submodule\nsubcommands from shell to C.\nThis new function is also used in ported submodule subcommand\ninit.\n\nMentored-by: Christian Couder <christian.couder@gmail.com>\nMentored-by: Stefan Beller <sbeller@google.com>\nSigned-off-by: Prathamesh Chavan <pc44800@gmail.com>\n---\nThis series of patches is based on the 'next' branch. \n\nComplete build report of this patch series is available at:\nhttps://travis-ci.org/pratham-pc/git/builds/\nBranch: patch-series\nBuild #113\n\n builtin/submodule--helper.c | 39 +++++++++++++++++++++++++++++----------\n 1 file changed, 29 insertions(+), 10 deletions(-)\n\ndiff --git a/builtin/submodule--helper.c b/builtin/submodule--helper.c\nindex 1bfc91bca..c4286aac5 100644\n--- a/builtin/submodule--helper.c\n+++ b/builtin/submodule--helper.c\n@@ -14,6 +14,9 @@\n #include \"refs.h\"\n #include \"connect.h\"\n \n+typedef void (*submodule_list_func_t)(const struct cache_entry *list_item,\n+\t\t\t\t      void *cb_data);\n+\n static char *get_default_remote(void)\n {\n \tchar *dest = NULL, *ret;\n@@ -352,17 +355,30 @@ static int module_list(int argc, const char **argv, const char *prefix)\n \treturn 0;\n }\n \n-static void init_submodule(const char *path, const char *prefix, int quiet)\n+static void for_each_submodule_list(const struct module_list list,\n+\t\t\t\t    submodule_list_func_t fn, void *cb_data)\n {\n+\tint i;\n+\tfor (i = 0; i < list.nr; i++)\n+\t\tfn(list.entries[i], cb_data);\n+}\n+\n+struct init_cb {\n+\tconst char *prefix;\n+\tunsigned int quiet: 1;\n+};\n+#define INIT_CB_INIT { NULL, 0 }\n+\n+static void init_submodule(const struct cache_entry *list_item, void *cb_data)\n+{\n+\tstruct init_cb *info = cb_data;\n \tconst struct submodule *sub;\n \tstruct strbuf sb = STRBUF_INIT;\n \tchar *upd = NULL, *url = NULL, *displaypath;\n \n-\t/* Only loads from .gitmodules, no overlay with .git/config */\n-\tgitmodules_config();\n-\tdisplaypath = get_submodule_displaypath(path, prefix);\n+\tdisplaypath = get_submodule_displaypath(list_item->name, info->prefix);\n \n-\tsub = submodule_from_path(null_sha1, path);\n+\tsub = submodule_from_path(null_sha1, list_item->name);\n \n \tif (!sub)\n \t\tdie(_(\"No url found for submodule path '%s' in .gitmodules\"),\n@@ -374,7 +390,7 @@ static void init_submodule(const char *path, const char *prefix, int quiet)\n \t *\n \t * Set active flag for the submodule being initialized\n \t */\n-\tif (!is_submodule_initialized(path)) {\n+\tif (!is_submodule_initialized(list_item->name)) {\n \t\tstrbuf_addf(&sb, \"submodule.%s.active\", sub->name);\n \t\tgit_config_set_gently(sb.buf, \"true\");\n \t}\n@@ -416,7 +432,7 @@ static void init_submodule(const char *path, const char *prefix, int quiet)\n \t\tif (git_config_set_gently(sb.buf, url))\n \t\t\tdie(_(\"Failed to register url for submodule path '%s'\"),\n \t\t\t    displaypath);\n-\t\tif (!quiet)\n+\t\tif (!info->quiet)\n \t\t\tfprintf(stderr,\n \t\t\t\t_(\"Submodule '%s' (%s) registered for path '%s'\\n\"),\n \t\t\t\tsub->name, url, displaypath);\n@@ -445,10 +461,10 @@ static void init_submodule(const char *path, const char *prefix, int quiet)\n \n static int module_init(int argc, const char **argv, const char *prefix)\n {\n+\tstruct init_cb info = INIT_CB_INIT;\n \tstruct pathspec pathspec;\n \tstruct module_list list = MODULE_LIST_INIT;\n \tint quiet = 0;\n-\tint i;\n \n \tstruct option module_init_options[] = {\n \t\tOPT__QUIET(&quiet, N_(\"Suppress output for initializing a submodule\")),\n@@ -473,8 +489,11 @@ static int module_init(int argc, const char **argv, const char *prefix)\n \tif (!argc && git_config_get_value_multi(\"submodule.active\"))\n \t\tmodule_list_active(&list);\n \n-\tfor (i = 0; i < list.nr; i++)\n-\t\tinit_submodule(list.entries[i]->name, prefix, quiet);\n+\tinfo.prefix = prefix;\n+\tinfo.quiet = !!quiet;\n+\n+\tgitmodules_config();\n+\tfor_each_submodule_list(list, init_submodule, &info);\n \n \treturn 0;\n }\n-- \n2.13.0\n\n"},{"id":"323299","messageId":"20170626231108.23640-2-pc44800@gmail.com","threadId":"46265","inReplyTo":"20170626231108.23640-1-pc44800@gmail.com","subject":"[GSoC][PATCH 2/6 v2] submodule: port subcommand foreach from shell to C","fromName":"Prathamesh Chavan","fromEmail":"pc44800@gmail.com","sentAt":"2017-06-26T23:11:04Z","receivedAt":"2017-06-26T23:11:31Z","isPatch":true,"sender":{"key":"pc44800@gmail.com","avatar":"https://avatars.githubusercontent.com/u/17272661?v=4"},"body":"This aims to make git-submodule foreach a builtin. This is the very\nfirst step taken in this direction. Hence, 'foreach' is ported to\nsubmodule--helper, and submodule--helper is called from git-submodule.sh.\nThe code is split up to have one function to obtain all the list of\nsubmodules. This function acts as the front-end of git-submodule foreach\nsubcommand. It calls the function for_each_submodule_list, which basically\nloops through the list and calls function fn, which in this case is\nruncommand_in_submodule. This third function is a calling function that\ntakes care of running the command in that submodule, and recursively\nperform the same when --recursive is flagged.\n\nThe first function module_foreach first parses the options present in\nargv, and then with the help of module_list_compute, generates the list of\nsubmodules present in the current working tree.\n\nThe second function for_each_submodule_list traverses through the\nlist, and calls function fn (which in case of submodule subcommand\nforeach is runcommand_in_submodule) is called for each entry.\n\nThe third function runcommand_in_submodule, generates a submodule struct sub\nfor $name, value and then later prepends name=sub->name; and other\nvalue assignment to the env argv_array structure of a child_process.\nAlso the <command> of submodule-foreach is push to args argv_array\nstructure and finally, using run_command the commands are executed\nusing a shell.\n\nThe third function also takes care of the recursive flag, by creating\na separate child_process structure and prepending \"--super-prefix displaypath\",\nto the args argv_array structure. Other required arguments and the\ninput <command> of submodule-foreach is also appended to this argv_array.\n\nFunction get_initial_wt_prefix_up_path is introduced to take care of\ngenerating the value for path variable(as it was in the shell script)\n\nHelped-by: Brandon Williams <bmwill@google.com>\nMentored-by: Christian Couder <christian.couder@gmail.com>\nMentored-by: Stefan Beller <sbeller@google.com>\nSigned-off-by: Prathamesh Chavan <pc44800@gmail.com>\n---\nThis patch suggestes the current status of the foreach patch.\nWork is still needed on this patch for eleminating the hack\nused in this patch for generating path variable.\n\n builtin/submodule--helper.c | 163 ++++++++++++++++++++++++++++++++++++++++++++\n git-submodule.sh            |  39 +----------\n 2 files changed, 164 insertions(+), 38 deletions(-)\n\ndiff --git a/builtin/submodule--helper.c b/builtin/submodule--helper.c\nindex c4286aac5..5180659fd 100644\n--- a/builtin/submodule--helper.c\n+++ b/builtin/submodule--helper.c\n@@ -517,6 +517,168 @@ static int module_name(int argc, const char **argv, const char *prefix)\n \treturn 0;\n }\n \n+static char *get_initial_wt_prefix_up_path(char *path)\n+{\n+\tstruct strbuf sb = STRBUF_INIT;\n+\tconst char *p = path;\n+\n+\twhile (*p) {\n+\t\tif (skip_prefix(p, \"./\", &p))\n+\t\t\tcontinue;\n+\t\tif (!skip_prefix(p, \"../\", &p))\n+\t\t\tbreak;\n+\t\tstrbuf_addstr(&sb, \"../\");\n+\t}\n+\n+\treturn strbuf_detach(&sb, NULL);\n+}\n+\n+struct cb_foreach {\n+\tint argc;\n+\tconst char **argv;\n+\tconst char *prefix;\n+\tunsigned int quiet: 1;\n+\tunsigned int recursive: 1;\n+};\n+#define CB_FOREACH_INIT { 0, NULL, NULL, 0, 0 }\n+\n+static void runcommand_in_submodule(const struct cache_entry *list_item,\n+\t\t\t\t    void *cb_data)\n+{\n+\tstruct cb_foreach *info = cb_data;\n+\tconst struct submodule *sub;\n+\tstruct child_process cp = CHILD_PROCESS_INIT;\n+\tchar *displaypath;\n+\n+\tdisplaypath = get_submodule_displaypath(list_item->name, info->prefix);\n+\n+\tsub = submodule_from_path(null_sha1, list_item->name);\n+\n+\tif (!sub)\n+\t\tdie(_(\"No url found for submodule path '%s' in .gitmodules\"),\n+\t\t      displaypath);\n+\n+\tif (!is_submodule_populated_gently(list_item->name, NULL))\n+\t\tgoto cleanup;\n+\n+\tprepare_submodule_repo_env(&cp.env_array);\n+\t/* For the purpose of executing <command> in the submodule,\n+\t * separate shell is used for the purpose of running the\n+\t * child process.\n+\t */\n+\tcp.use_shell = 1;\n+\tcp.dir = list_item->name;\n+\n+\tif (info->argc == 1) {\n+\n+\t\t/*\n+\t\t * NEEDSWORK: Here function get_initial_wt_prefix_up_path is\n+\t\t * used as a hack for evaluating the value of the path\n+\t\t * variable. The proper way would have been to store and use\n+\t\t * the prefix of the repository, where first subcommand\n+\t\t * foreach was executed and then evaluate path as\n+\t\t * relative_path(list_item->name, prefix) for each submodule.\n+\t\t */\n+\t\tchar *initial_wt_prefix_up_path = get_initial_wt_prefix_up_path(displaypath);\n+\t\tchar *toplevel = xgetcwd();\n+\t\targv_array_pushf(&cp.env_array, \"name=%s\", sub->name);\n+\t\targv_array_pushf(&cp.env_array, \"sm_path=%s%s\",\n+\t\t\t\t initial_wt_prefix_up_path, list_item->name);\n+\t\targv_array_pushf(&cp.env_array, \"sha1=%s\",\n+\t\t\t\t oid_to_hex(&list_item->oid));\n+\t\targv_array_pushf(&cp.env_array, \"toplevel=%s\", toplevel);\n+\n+\t\t/*\n+\t\t * NEEDSWORK: The value currently assigned to path variable\n+\t\t * is same as that before porting, but it deviates\n+\t\t * from its documented value: \"$path is the name of the\n+\t\t * submodule directory relative to the superproject\", in\n+\t\t * the case when subcommand foreach is called recursively\n+\t\t * from a subdirectory.\n+\t\t * This is beacuse it is currently relative path from cwd\n+\t\t * to the submodule. In the nested case the intermediate\n+\t\t * submodules are elided, such that it is a bogus path.\n+\t\t */\n+\t\targv_array_pushf(&cp.args, \"path=%s%s; %s\",\n+\t\t\t\t initial_wt_prefix_up_path, list_item->name,\n+\t\t\t\t info->argv[0]);\n+\t\tfree(initial_wt_prefix_up_path);\n+\t\tfree(toplevel);\n+\t} else {\n+\t\targv_array_pushv(&cp.args, info->argv);\n+\t}\n+\n+\tif (!info->quiet)\n+\t\tprintf(_(\"Entering '%s'\\n\"), displaypath);\n+\n+\tif (info->argv[0] && run_command(&cp))\n+\t\tdie(_(\"run_command returned non-zero status for %s\\n.\"),\n+\t\t      displaypath);\n+\n+\tif (info->recursive) {\n+\t\tstruct child_process cpr = CHILD_PROCESS_INIT;\n+\n+\t\tcpr.git_cmd = 1;\n+\t\tcpr.dir = list_item->name;\n+\t\tprepare_submodule_repo_env(&cpr.env_array);\n+\n+\t\targv_array_pushl(&cpr.args, \"--super-prefix\", displaypath,\n+\t\t\t\t \"submodule--helper\", \"foreach\", \"--recursive\",\n+\t\t\t\t NULL);\n+\n+\t\tif (info->quiet)\n+\t\t\targv_array_push(&cpr.args, \"--quiet\");\n+\n+\t\targv_array_pushv(&cpr.args, info->argv);\n+\n+\t\tif (run_command(&cpr))\n+\t\t\tdie(_(\"run_command returned non-zero status while\"\n+\t\t\t      \"recursing in the nested submodules of %s\\n.\"),\n+\t\t\t      displaypath);\n+\t}\n+\n+cleanup:\n+\tfree(displaypath);\n+}\n+\n+static int module_foreach(int argc, const char **argv, const char *prefix)\n+{\n+\tstruct cb_foreach info;\n+\tstruct pathspec pathspec;\n+\tstruct module_list list = MODULE_LIST_INIT;\n+\tint quiet = 0;\n+\tint recursive = 0;\n+\n+\tstruct option module_foreach_options[] = {\n+\t\tOPT__QUIET(&quiet, N_(\"Suppress output of entering each submodule command\")),\n+\t\tOPT_BOOL(0, \"recursive\", &recursive,\n+\t\t\t N_(\"Recurse into nested submodules\")),\n+\t\tOPT_END()\n+\t};\n+\n+\tconst char *const git_submodule_helper_usage[] = {\n+\t\tN_(\"git submodule--helper foreach [--quiet] [--recursive] <command>\"),\n+\t\tNULL\n+\t};\n+\n+\targc = parse_options(argc, argv, prefix, module_foreach_options,\n+\t\t\t     git_submodule_helper_usage, PARSE_OPT_KEEP_UNKNOWN);\n+\n+\tif (module_list_compute(0, NULL, prefix, &pathspec, &list) < 0)\n+\t\tBUG(\"module_list_compute should not choke on empty pathspec\");\n+\n+\tinfo.argc = argc;\n+\tinfo.argv = argv;\n+\tinfo.prefix = prefix;\n+\tinfo.quiet = !!quiet;\n+\tinfo.recursive = !!recursive;\n+\n+\tgitmodules_config();\n+\tfor_each_submodule_list(list, runcommand_in_submodule, &info);\n+\n+\treturn 0;\n+}\n+\n static int clone_submodule(const char *path, const char *gitdir, const char *url,\n \t\t\t   const char *depth, struct string_list *reference,\n \t\t\t   int quiet, int progress)\n@@ -1242,6 +1404,7 @@ static struct cmd_struct commands[] = {\n \t{\"relative-path\", resolve_relative_path, 0},\n \t{\"resolve-relative-url\", resolve_relative_url, 0},\n \t{\"resolve-relative-url-test\", resolve_relative_url_test, 0},\n+\t{\"foreach\", module_foreach, SUPPORT_SUPER_PREFIX},\n \t{\"init\", module_init, SUPPORT_SUPER_PREFIX},\n \t{\"remote-branch\", resolve_remote_submodule_branch, 0},\n \t{\"push-check\", push_check, 0},\ndiff --git a/git-submodule.sh b/git-submodule.sh\nindex e131760ee..c88e0ff7e 100755\n--- a/git-submodule.sh\n+++ b/git-submodule.sh\n@@ -323,45 +323,8 @@ cmd_foreach()\n \t\tshift\n \tdone\n \n-\ttoplevel=$(pwd)\n+\tgit ${wt_prefix:+-C \"$wt_prefix\"} ${prefix:+--super-prefix \"$prefix\"} submodule--helper foreach ${GIT_QUIET:+--quiet} ${recursive:+--recursive} \"$@\"\n \n-\t# dup stdin so that it can be restored when running the external\n-\t# command in the subshell (and a recursive call to this function)\n-\texec 3<&0\n-\n-\t{\n-\t\tgit submodule--helper list --prefix \"$wt_prefix\" ||\n-\t\techo \"#unmatched\" $?\n-\t} |\n-\twhile read -r mode sha1 stage sm_path\n-\tdo\n-\t\tdie_if_unmatched \"$mode\" \"$sha1\"\n-\t\tif test -e \"$sm_path\"/.git\n-\t\tthen\n-\t\t\tdisplaypath=$(git submodule--helper relative-path \"$prefix$sm_path\" \"$wt_prefix\")\n-\t\t\tsay \"$(eval_gettext \"Entering '\\$displaypath'\")\"\n-\t\t\tname=$(git submodule--helper name \"$sm_path\")\n-\t\t\t(\n-\t\t\t\tprefix=\"$prefix$sm_path/\"\n-\t\t\t\tsanitize_submodule_env\n-\t\t\t\tcd \"$sm_path\" &&\n-\t\t\t\tsm_path=$(git submodule--helper relative-path \"$sm_path\" \"$wt_prefix\") &&\n-\t\t\t\t# we make $path available to scripts ...\n-\t\t\t\tpath=$sm_path &&\n-\t\t\t\tif test $# -eq 1\n-\t\t\t\tthen\n-\t\t\t\t\teval \"$1\"\n-\t\t\t\telse\n-\t\t\t\t\t\"$@\"\n-\t\t\t\tfi &&\n-\t\t\t\tif test -n \"$recursive\"\n-\t\t\t\tthen\n-\t\t\t\t\tcmd_foreach \"--recursive\" \"$@\"\n-\t\t\t\tfi\n-\t\t\t) <&3 3<&- ||\n-\t\t\tdie \"$(eval_gettext \"Stopping at '\\$displaypath'; script returned non-zero status.\")\"\n-\t\tfi\n-\tdone\n }\n \n #\n-- \n2.13.0\n\n"},{"id":"323300","messageId":"20170626231108.23640-3-pc44800@gmail.com","threadId":"46265","inReplyTo":"20170626231108.23640-1-pc44800@gmail.com","subject":"[GSoC][PATCH 3/6 v2] submodule: port set_name_rev from shell to C","fromName":"Prathamesh Chavan","fromEmail":"pc44800@gmail.com","sentAt":"2017-06-26T23:11:05Z","receivedAt":"2017-06-26T23:11:35Z","isPatch":true,"sender":{"key":"pc44800@gmail.com","avatar":"https://avatars.githubusercontent.com/u/17272661?v=4"},"body":"Since later on we want to port submodule subcommand status, and since\nset_name_rev is part of cmd_status, hence this function is ported. It\nhas been ported to function print_name_rev in C, which calls get_name_rev\nto get the revname, and after formatting it, print_name_rev prints it.\nAnd hence in this way, the command `git submodule--helper print-name-rev\n\"sm_path\" \"sha1\"` sets value of revname in git-submodule.sh\n\nThe function get_name_rev returns the stdout of the git describe\ncommands. Since there are four different git-describe commands used for\ngenerating the name rev, four child_process are introduced, each successive\nchild process running only when previous has no stdout. The order of these\nfour git-describe commands is maintained the same as it was in the function\nset_name_rev() in shell script.\n\nMentored-by: Christian Couder <christian.couder@gmail.com>\nMentored-by: Stefan Beller <sbeller@google.com>\nSigned-off-by: Prathamesh Chavan <pc44800@gmail.com>\n---\n builtin/submodule--helper.c | 69 +++++++++++++++++++++++++++++++++++++++++++++\n git-submodule.sh            | 16 ++---------\n 2 files changed, 71 insertions(+), 14 deletions(-)\n\ndiff --git a/builtin/submodule--helper.c b/builtin/submodule--helper.c\nindex 5180659fd..86112ac92 100644\n--- a/builtin/submodule--helper.c\n+++ b/builtin/submodule--helper.c\n@@ -244,6 +244,74 @@ static char *get_submodule_displaypath(const char *path, const char *prefix)\n \t}\n }\n \n+enum describe_step {\n+\tstep_bare,\n+\tstep_tags,\n+\tstep_contains,\n+\tstep_all_always,\n+\tstep_end\n+};\n+\n+static char *get_name_rev(const char *sub_path, const char* object_id)\n+{\n+\tstruct strbuf sb = STRBUF_INIT;\n+\tenum describe_step cur_step;\n+\n+\tfor (cur_step = step_bare; cur_step < step_end; cur_step++) {\n+\t\tstruct child_process cp = CHILD_PROCESS_INIT;\n+\t\tprepare_submodule_repo_env(&cp.env_array);\n+\t\tcp.dir = sub_path;\n+\t\tcp.git_cmd = 1;\n+\t\tcp.no_stderr = 1;\n+\n+\t\tswitch (cur_step) {\n+\t\t\tcase step_bare:\n+\t\t\t\targv_array_pushl(&cp.args, \"describe\",\n+\t\t\t\t\t\t object_id, NULL);\n+\t\t\t\tbreak;\n+\t\t\tcase step_tags:\t\n+\t\t\t\targv_array_pushl(&cp.args, \"describe\",\n+\t\t\t\t\t\t \"--tags\", object_id, NULL);\n+\t\t\t\tbreak;\n+\t\t\tcase step_contains:\n+\t\t\t\targv_array_pushl(&cp.args, \"describe\",\n+\t\t\t\t\t\t \"--contains\", object_id,\n+\t\t\t\t\t\t NULL);\n+\t\t\t\tbreak;\n+\t\t\tcase step_all_always:\n+\t\t\t\targv_array_pushl(&cp.args, \"describe\",\n+\t\t\t\t\t\t \"--all\", \"--always\",\n+\t\t\t\t\t\t object_id, NULL);\n+\t\t\t\tbreak;\n+\t\t\tdefault:\n+\t\t\t\tBUG(\"unknown describe step '%d'\", cur_step);\n+\t\t}\n+\n+\t\tif (!capture_command(&cp, &sb, 0) && sb.len) {\n+\t\t\tstrbuf_strip_suffix(&sb, \"\\n\");\n+\t\t\treturn strbuf_detach(&sb, NULL);\n+\t\t}\n+\n+\t}\n+\n+\tstrbuf_release(&sb);\n+\treturn NULL;\n+}\n+\n+static int print_name_rev(int argc, const char **argv, const char *prefix)\n+{\n+\tchar *namerev;\n+\tif (argc != 3)\n+\t\tdie(\"print-name-rev only accepts two arguments: <path> <sha1>\");\n+\n+\tnamerev = get_name_rev(argv[1], argv[2]);\n+\tif (namerev && namerev[0])\n+\t\tprintf(\" (%s)\", namerev);\n+\tprintf(\"\\n\");\n+\n+\treturn 0;\n+}\n+\n struct module_list {\n \tconst struct cache_entry **entries;\n \tint alloc, nr;\n@@ -1405,6 +1473,7 @@ static struct cmd_struct commands[] = {\n \t{\"resolve-relative-url\", resolve_relative_url, 0},\n \t{\"resolve-relative-url-test\", resolve_relative_url_test, 0},\n \t{\"foreach\", module_foreach, SUPPORT_SUPER_PREFIX},\n+\t{\"print-name-rev\", print_name_rev, 0},\n \t{\"init\", module_init, SUPPORT_SUPER_PREFIX},\n \t{\"remote-branch\", resolve_remote_submodule_branch, 0},\n \t{\"push-check\", push_check, 0},\ndiff --git a/git-submodule.sh b/git-submodule.sh\nindex c88e0ff7e..b28a6ba8e 100755\n--- a/git-submodule.sh\n+++ b/git-submodule.sh\n@@ -722,18 +722,6 @@ cmd_update()\n \t}\n }\n \n-set_name_rev () {\n-\trevname=$( (\n-\t\tsanitize_submodule_env\n-\t\tcd \"$1\" && {\n-\t\t\tgit describe \"$2\" 2>/dev/null ||\n-\t\t\tgit describe --tags \"$2\" 2>/dev/null ||\n-\t\t\tgit describe --contains \"$2\" 2>/dev/null ||\n-\t\t\tgit describe --all --always \"$2\"\n-\t\t}\n-\t) )\n-\ttest -z \"$revname\" || revname=\" ($revname)\"\n-}\n #\n # Show commit summary for submodules in index or working tree\n #\n@@ -1005,14 +993,14 @@ cmd_status()\n \t\tfi\n \t\tif git diff-files --ignore-submodules=dirty --quiet -- \"$sm_path\"\n \t\tthen\n-\t\t\tset_name_rev \"$sm_path\" \"$sha1\"\n+\t\t\trevname=$(git submodule--helper print-name-rev \"$sm_path\" \"$sha1\")\n \t\t\tsay \" $sha1 $displaypath$revname\"\n \t\telse\n \t\t\tif test -z \"$cached\"\n \t\t\tthen\n \t\t\t\tsha1=$(sanitize_submodule_env; cd \"$sm_path\" && git rev-parse --verify HEAD)\n \t\t\tfi\n-\t\t\tset_name_rev \"$sm_path\" \"$sha1\"\n+\t\t\trevname=$(git submodule--helper print-name-rev \"$sm_path\" \"$sha1\")\n \t\t\tsay \"+$sha1 $displaypath$revname\"\n \t\tfi\n \n-- \n2.13.0\n\n"},{"id":"323301","messageId":"20170626231108.23640-6-pc44800@gmail.com","threadId":"46265","inReplyTo":"20170626231108.23640-1-pc44800@gmail.com","subject":"[GSoC][PATCH 6/6 v2] submodule: port submodule subcommand 'deinit' from shell to C","fromName":"Prathamesh Chavan","fromEmail":"pc44800@gmail.com","sentAt":"2017-06-26T23:11:08Z","receivedAt":"2017-06-26T23:11:48Z","isPatch":true,"sender":{"key":"pc44800@gmail.com","avatar":"https://avatars.githubusercontent.com/u/17272661?v=4"},"body":"The same mechanism is used even for porting this submodule\nsubcommand, as used in the ported subcommands till now.\nThe function cmd_deinit in split up after porting into three\nfunctions: module_deinit, for_each_submodule_list and\ndeinit_submodule.\n\nMentored-by: Christian Couder <christian.couder@gmail.com>\nMentored-by: Stefan Beller <sbeller@google.com>\nSigned-off-by: Prathamesh Chavan <pc44800@gmail.com>\n---\n builtin/submodule--helper.c | 140 ++++++++++++++++++++++++++++++++++++++++++++\n git-submodule.sh            |  55 +----------------\n 2 files changed, 141 insertions(+), 54 deletions(-)\n\ndiff --git a/builtin/submodule--helper.c b/builtin/submodule--helper.c\nindex 4e3322846..17942529b 100644\n--- a/builtin/submodule--helper.c\n+++ b/builtin/submodule--helper.c\n@@ -751,6 +751,145 @@ static int module_status(int argc, const char **argv, const char *prefix)\n \treturn 0;\n }\n \n+struct deinit_cb {\n+\tconst char *prefix;\n+\tunsigned int quiet: 1;\n+\tunsigned int force: 1;\n+\tunsigned int all: 1;\n+};\n+#define DEINIT_CB_INIT { NULL, 0, 0, 0 }\n+\n+static void deinit_submodule(const struct cache_entry *list_item,\n+\t\t\t     void *cb_data)\n+{\n+\tstruct deinit_cb *info = cb_data;\n+\tconst struct submodule *sub;\n+\tchar *displaypath = NULL;\n+\tstruct child_process cp_config = CHILD_PROCESS_INIT;\n+\tstruct strbuf sb_config = STRBUF_INIT;\n+\tchar *sm_path = xstrdup(list_item->name);\n+\tchar *sub_git_dir = xstrfmt(\"%s/.git\", sm_path);\n+\n+\tsub = submodule_from_path(null_sha1, sm_path);\n+\n+\tif (!sub->name)\n+\t\tgoto cleanup;\n+\n+\tdisplaypath = get_submodule_displaypath(sm_path, info->prefix);\n+\n+\t/* remove the submodule work tree (unless the user already did it) */\n+\tif (is_directory(sm_path)) {\n+\t\tstruct child_process cp = CHILD_PROCESS_INIT;\n+\n+\t\t/* protect submodules containing a .git directory */\n+\t\tif (is_git_directory(sub_git_dir))\n+\t\t\tdie(_(\"Submodule work tree '%s' contains a .git \"\n+\t\t\t      \"directory use 'rm -rf' if you really want \"\n+\t\t\t      \"to remove it including all of its history\"),\n+\t\t\t      displaypath);\n+\n+\t\tif (!info->force) {\n+\t\t\tstruct child_process cp_rm = CHILD_PROCESS_INIT;\n+\t\t\tcp_rm.git_cmd = 1;\n+\t\t\targv_array_pushl(&cp_rm.args, \"rm\", \"-qn\", sm_path,\n+\t\t\t\t\t NULL);\n+\n+\t\t\t/* list_item->name is changed by cmd_rm() below */\n+\t\t\tif (run_command(&cp_rm))\n+\t\t\t\tdie(_(\"Submodule work tree '%s' contains local \"\n+\t\t\t\t      \"modifications; use '-f' to discard them\"),\n+\t\t\t\t      displaypath);\n+\t\t}\n+\n+\t\tcp.use_shell = 1;\n+\t\targv_array_pushl(&cp.args, \"rm\", \"-rf\", sm_path, NULL);\n+\t\tif (!run_command(&cp)) {\n+\t\t\tif (!info->quiet)\n+\t\t\t\tprintf(_(\"Cleared directory '%s'\\n\"),\n+\t\t\t\t\t displaypath);\n+\t\t} else {\n+\t\t\tif (!info->quiet)\n+\t\t\t\tprintf(_(\"Could not remove submodule work tree '%s'\\n\"),\n+\t\t\t\t\t displaypath);\n+\t\t}\n+\t}\n+\n+\tif (mkdir(sm_path, 0700))\n+\t\tdie(_(\"could not create empty submodule directory %s\"),\n+\t\t      displaypath);\n+\n+\tcp_config.git_cmd = 1;\n+\targv_array_pushl(&cp_config.args, \"config\", \"--get-regexp\", NULL);\n+\targv_array_pushf(&cp_config.args, \"submodule.%s\\\\.\", sub->name);\n+\n+\t/* remove the .git/config entries (unless the user already did it) */\n+\tif (!capture_command(&cp_config, &sb_config, 0) && sb_config.len) {\n+\t\tchar *sub_key = xstrfmt(\"submodule.%s\", sub->name);\n+\t\t/*\n+\t\t * remove the whole section so we have a clean state when\n+\t\t * the user later decides to init this submodule again\n+\t\t */\n+\t\tgit_config_rename_section_in_file(NULL, sub_key, NULL);\n+\t\tif (!info->quiet)\n+\t\t\tprintf(_(\"Submodule '%s' (%s) unregistered for path '%s'\\n\"),\n+\t\t\t\t sub->name, sub->url, displaypath);\n+\t\tfree(sub_key);\n+\t}\n+\n+cleanup:\n+\tfree(displaypath);\n+\tfree(sub_git_dir);\n+\tfree(sm_path);\n+\tstrbuf_release(&sb_config);\n+}\n+\n+static int module_deinit(int argc, const char **argv, const char *prefix)\n+{\n+\tstruct deinit_cb info = DEINIT_CB_INIT;\n+\tstruct pathspec pathspec;\n+\tstruct module_list list = MODULE_LIST_INIT;\n+\tint quiet = 0;\n+\tint force = 0;\n+\tint all = 0;\n+\n+\tstruct option module_deinit_options[] = {\n+\t\tOPT__QUIET(&quiet, N_(\"Suppress submodule status output\")),\n+\t\tOPT__FORCE(&force, N_(\"Remove submodule working trees even if they contain local changes\")),\n+\t\tOPT_BOOL(0, \"all\", &all, N_(\"Unregister all submodules\")),\n+\t\tOPT_END()\n+\t};\n+\n+\tconst char *const git_submodule_helper_usage[] = {\n+\t\tN_(\"git submodule deinit [--quiet] [-f | --force] [--all | [--] [<path>...]]\"),\n+\t\tNULL\n+\t};\n+\n+\targc = parse_options(argc, argv, prefix, module_deinit_options,\n+\t\t\t     git_submodule_helper_usage, 0);\n+\n+\tif (module_list_compute(argc, argv, prefix, &pathspec, &list) < 0)\n+\t\tBUG(\"module_list_compute should not choke on empty pathspec\");\n+\n+\tinfo.prefix = prefix;\n+\tinfo.quiet = !!quiet;\n+\tinfo.all = !!all;\n+\tinfo.force = !!force;\n+\n+\tif (all && argc) {\n+\t\terror(\"pathspec and --all are incompatible\");\n+\t\tusage_with_options(git_submodule_helper_usage,\n+\t\t\t\t   module_deinit_options);\n+\t}\n+\n+\tif (!argc && !all)\n+\t\tdie(_(\"Use '--all' if you really want to deinitialize all submodules\"));\n+\n+\tgitmodules_config();\n+\tfor_each_submodule_list(list, deinit_submodule, &info);\n+\n+\treturn 0;\n+}\n+\n static int module_name(int argc, const char **argv, const char *prefix)\n {\n \tconst struct submodule *sub;\n@@ -1805,6 +1944,7 @@ static struct cmd_struct commands[] = {\n \t{\"status\", module_status, SUPPORT_SUPER_PREFIX},\n \t{\"print-default-remote\", print_default_remote, 0},\n \t{\"sync\", module_sync, SUPPORT_SUPER_PREFIX},\n+\t{\"deinit\", module_deinit, SUPPORT_SUPER_PREFIX},\n \t{\"remote-branch\", resolve_remote_submodule_branch, 0},\n \t{\"push-check\", push_check, 0},\n \t{\"absorb-git-dirs\", absorb_git_dirs, SUPPORT_SUPER_PREFIX},\ndiff --git a/git-submodule.sh b/git-submodule.sh\nindex 6257d50e9..0d3308d7b 100755\n--- a/git-submodule.sh\n+++ b/git-submodule.sh\n@@ -391,60 +391,7 @@ cmd_deinit()\n \t\tshift\n \tdone\n \n-\tif test -n \"$deinit_all\" && test \"$#\" -ne 0\n-\tthen\n-\t\techo >&2 \"$(eval_gettext \"pathspec and --all are incompatible\")\"\n-\t\tusage\n-\tfi\n-\tif test $# = 0 && test -z \"$deinit_all\"\n-\tthen\n-\t\tdie \"$(eval_gettext \"Use '--all' if you really want to deinitialize all submodules\")\"\n-\tfi\n-\n-\t{\n-\t\tgit submodule--helper list --prefix \"$wt_prefix\" \"$@\" ||\n-\t\techo \"#unmatched\" $?\n-\t} |\n-\twhile read -r mode sha1 stage sm_path\n-\tdo\n-\t\tdie_if_unmatched \"$mode\" \"$sha1\"\n-\t\tname=$(git submodule--helper name \"$sm_path\") || exit\n-\n-\t\tdisplaypath=$(git submodule--helper relative-path \"$sm_path\" \"$wt_prefix\")\n-\n-\t\t# Remove the submodule work tree (unless the user already did it)\n-\t\tif test -d \"$sm_path\"\n-\t\tthen\n-\t\t\t# Protect submodules containing a .git directory\n-\t\t\tif test -d \"$sm_path/.git\"\n-\t\t\tthen\n-\t\t\t\tdie \"$(eval_gettext \"\\\n-Submodule work tree '\\$displaypath' contains a .git directory\n-(use 'rm -rf' if you really want to remove it including all of its history)\")\"\n-\t\t\tfi\n-\n-\t\t\tif test -z \"$force\"\n-\t\t\tthen\n-\t\t\t\tgit rm -qn \"$sm_path\" ||\n-\t\t\t\tdie \"$(eval_gettext \"Submodule work tree '\\$displaypath' contains local modifications; use '-f' to discard them\")\"\n-\t\t\tfi\n-\t\t\trm -rf \"$sm_path\" &&\n-\t\t\tsay \"$(eval_gettext \"Cleared directory '\\$displaypath'\")\" ||\n-\t\t\tsay \"$(eval_gettext \"Could not remove submodule work tree '\\$displaypath'\")\"\n-\t\tfi\n-\n-\t\tmkdir \"$sm_path\" || say \"$(eval_gettext \"Could not create empty submodule directory '\\$displaypath'\")\"\n-\n-\t\t# Remove the .git/config entries (unless the user already did it)\n-\t\tif test -n \"$(git config --get-regexp submodule.\"$name\\.\")\"\n-\t\tthen\n-\t\t\t# Remove the whole section so we have a clean state when\n-\t\t\t# the user later decides to init this submodule again\n-\t\t\turl=$(git config submodule.\"$name\".url)\n-\t\t\tgit config --remove-section submodule.\"$name\" 2>/dev/null &&\n-\t\t\tsay \"$(eval_gettext \"Submodule '\\$name' (\\$url) unregistered for path '\\$displaypath'\")\"\n-\t\tfi\n-\tdone\n+\tgit ${wt_prefix:+-C \"$wt_prefix\"} submodule--helper deinit ${GIT_QUIET:+--quiet} ${prefix:+--prefix \"$prefix\"} ${force:+--force} ${deinit_all:+--all} \"$@\"\n }\n \n is_tip_reachable () (\n-- \n2.13.0\n\n"},{"id":"323302","messageId":"20170626231108.23640-4-pc44800@gmail.com","threadId":"46265","inReplyTo":"20170626231108.23640-1-pc44800@gmail.com","subject":"[GSoC][PATCH 4/6 v2] submodule: port submodule subcommand status","fromName":"Prathamesh Chavan","fromEmail":"pc44800@gmail.com","sentAt":"2017-06-26T23:11:06Z","receivedAt":"2017-06-26T23:11:57Z","isPatch":true,"sender":{"key":"pc44800@gmail.com","avatar":"https://avatars.githubusercontent.com/u/17272661?v=4"},"body":"The mechanism used for porting submodule subcommand 'status'\nis similar to that used for subcommand 'foreach'.\nThe function cmd_status from git-submodule is ported to three\nfunctions in the builtin submodule--helper namely: module_status,\nfor_each_submodule_list and status_submodule.\n\nprint_status is also introduced for handling the output of\nthe subcommand and also to reduce the code size.\n\nMentored-by: Christian Couder <christian.couder@gmail.com>\nMentored-by: Stefan Beller <sbeller@google.com>\nSigned-off-by: Prathamesh Chavan <pc44800@gmail.com>\n---\n builtin/submodule--helper.c | 152 ++++++++++++++++++++++++++++++++++++++++++++\n git-submodule.sh            |  49 +-------------\n 2 files changed, 153 insertions(+), 48 deletions(-)\n\ndiff --git a/builtin/submodule--helper.c b/builtin/submodule--helper.c\nindex 86112ac92..a5de7a0fe 100644\n--- a/builtin/submodule--helper.c\n+++ b/builtin/submodule--helper.c\n@@ -566,6 +566,157 @@ static int module_init(int argc, const char **argv, const char *prefix)\n \treturn 0;\n }\n \n+struct status_cb {\n+\tconst char *prefix;\n+\tunsigned int quiet: 1;\n+\tunsigned int recursive: 1;\n+\tunsigned int cached: 1;\n+};\n+#define STATUS_CB_INIT { NULL, 0, 0, 0 }\n+\n+static void print_status(struct status_cb *info, char state, const char *path,\n+\t\t\t char *sub_sha1, char *displaypath)\n+{\n+\tif (info->quiet)\n+\t\treturn;\n+\n+\tprintf(\"%c%s %s\", state, sub_sha1, displaypath);\n+\n+\tif (state == ' ' || state == '+') {\n+\t\tstruct argv_array name_rev_args = ARGV_ARRAY_INIT;\n+\n+\t\targv_array_pushl(&name_rev_args, \"print-name-rev\",\n+\t\t\t\t path, sub_sha1, NULL);\n+\t\tprint_name_rev(name_rev_args.argc, name_rev_args.argv,\n+\t\t\t       info->prefix);\n+\t} else {\n+\t\tprintf(\"\\n\");\n+\t}\n+}\n+\n+static void status_submodule(const struct cache_entry *list_item, void *cb_data)\n+{\n+\tstruct status_cb *info = cb_data;\n+\tchar *sub_sha1 = xstrdup(oid_to_hex(&list_item->oid));\n+\tchar *displaypath;\n+\tstruct argv_array diff_files_args = ARGV_ARRAY_INIT;\n+\n+\tif (!submodule_from_path(null_sha1, list_item->name))\n+\t\tdie(_(\"no submodule mapping found in .gitmodules for path '%s'\"),\n+\t\t      list_item->name);\n+\n+\tdisplaypath = get_submodule_displaypath(list_item->name, info->prefix);\n+\n+\tif (list_item->ce_flags) {\n+\t\tprint_status(info, 'U', list_item->name,\n+\t\t\t     sha1_to_hex(null_sha1), displaypath);\n+\t\tgoto cleanup;\n+\t}\n+\n+\tif (!is_submodule_initialized(list_item->name)) {\n+\t\tprint_status(info, '-', list_item->name, sub_sha1, displaypath);\n+\t\tgoto cleanup;\n+\t}\n+\n+\targv_array_pushl(&diff_files_args, \"diff-files\",\n+\t\t\t \"--ignore-submodules=dirty\", \"--quiet\", \"--\",\n+\t\t\t list_item->name, NULL);\n+\n+\tif (!cmd_diff_files(diff_files_args.argc, diff_files_args.argv,\n+\t\t\t    info->prefix)) {\n+\t\tprint_status(info, ' ', list_item->name, sub_sha1, displaypath);\n+\t} else {\n+\t\tif (!info->cached) {\n+\t\t\tstruct child_process cp = CHILD_PROCESS_INIT;\n+\t\t\tstruct strbuf sb = STRBUF_INIT;\n+\n+\t\t\tprepare_submodule_repo_env(&cp.env_array);\n+\t\t\tcp.git_cmd = 1;\n+\t\t\tcp.dir = list_item->name;\n+\n+\t\t\targv_array_pushl(&cp.args, \"rev-parse\",\n+\t\t\t\t\t \"--verify\", \"HEAD\", NULL);\n+\n+\t\t\tif (capture_command(&cp, &sb, 0))\n+\t\t\t\tdie(_(\"could not run 'git rev-parse --verify\"\n+\t\t\t\t      \"HEAD' in submodule %s\"),\n+\t\t\t\t      list_item->name);\n+\n+\t\t\tstrbuf_strip_suffix(&sb, \"\\n\");\n+\t\t\tprint_status(info, '+', list_item->name, sb.buf,\n+\t\t\t\t     displaypath);\n+\t\t\tstrbuf_release(&sb);\n+\t\t} else {\n+\t\t\tprint_status(info, '+', list_item->name, sub_sha1,\n+\t\t\t\t     displaypath);\n+\t\t}\n+\t}\n+\n+\tif (info->recursive) {\n+\t\tstruct child_process cpr = CHILD_PROCESS_INIT;\n+\n+\t\tcpr.git_cmd = 1;\n+\t\tcpr.dir = list_item->name;\n+\t\tprepare_submodule_repo_env(&cpr.env_array);\n+\n+\t\targv_array_pushl(&cpr.args, \"--super-prefix\", displaypath,\n+\t\t\t\t \"submodule--helper\", \"status\", \"--recursive\",\n+\t\t\t\t NULL);\n+\n+\t\tif (info->cached)\n+\t\t\targv_array_push(&cpr.args, \"--cached\");\n+\n+\t\tif (info->quiet)\n+\t\t\targv_array_push(&cpr.args, \"--quiet\");\n+\n+\t\tif (run_command(&cpr))\n+\t\t\tdie(_(\"failed to recurse into submodule '%s'\"),\n+\t\t\t      list_item->name);\n+\t}\n+\n+cleanup:\n+\tfree(displaypath);\n+\tfree(sub_sha1);\n+}\n+\n+static int module_status(int argc, const char **argv, const char *prefix)\n+{\n+\tstruct status_cb info = STATUS_CB_INIT;\n+\tstruct pathspec pathspec;\n+\tstruct module_list list = MODULE_LIST_INIT;\n+\tint quiet = 0;\n+\tint cached = 0;\n+\tint recursive = 0;\n+\n+\tstruct option module_status_options[] = {\n+\t\tOPT__QUIET(&quiet, N_(\"Suppress submodule status output\")),\n+\t\tOPT_BOOL(0, \"cached\", &cached, N_(\"Use commit stored in the index instead of the one stored in the submodule HEAD\")),\n+\t\tOPT_BOOL(0, \"recursive\", &recursive, N_(\"Recurse into nested submodules\")),\n+\t\tOPT_END()\n+\t};\n+\n+\tconst char *const git_submodule_helper_usage[] = {\n+\t\tN_(\"git submodule status [--quiet] [--cached] [--recursive] [<path>]\"),\n+\t\tNULL\n+\t};\n+\n+\targc = parse_options(argc, argv, prefix, module_status_options,\n+\t\t\t     git_submodule_helper_usage, 0);\n+\n+\tif (module_list_compute(argc, argv, prefix, &pathspec, &list) < 0)\n+\t\treturn 1;\n+\n+\tinfo.prefix = prefix;\n+\tinfo.quiet = !!quiet;\n+\tinfo.recursive = !!recursive;\n+\tinfo.cached = !!cached;\n+\n+\tgitmodules_config();\n+\tfor_each_submodule_list(list, status_submodule, &info);\n+\n+\treturn 0;\n+}\n+\n static int module_name(int argc, const char **argv, const char *prefix)\n {\n \tconst struct submodule *sub;\n@@ -1475,6 +1626,7 @@ static struct cmd_struct commands[] = {\n \t{\"foreach\", module_foreach, SUPPORT_SUPER_PREFIX},\n \t{\"print-name-rev\", print_name_rev, 0},\n \t{\"init\", module_init, SUPPORT_SUPER_PREFIX},\n+\t{\"status\", module_status, SUPPORT_SUPER_PREFIX},\n \t{\"remote-branch\", resolve_remote_submodule_branch, 0},\n \t{\"push-check\", push_check, 0},\n \t{\"absorb-git-dirs\", absorb_git_dirs, SUPPORT_SUPER_PREFIX},\ndiff --git a/git-submodule.sh b/git-submodule.sh\nindex b28a6ba8e..b19d5fa7b 100755\n--- a/git-submodule.sh\n+++ b/git-submodule.sh\n@@ -968,54 +968,7 @@ cmd_status()\n \t\tshift\n \tdone\n \n-\t{\n-\t\tgit submodule--helper list --prefix \"$wt_prefix\" \"$@\" ||\n-\t\techo \"#unmatched\" $?\n-\t} |\n-\twhile read -r mode sha1 stage sm_path\n-\tdo\n-\t\tdie_if_unmatched \"$mode\" \"$sha1\"\n-\t\tname=$(git submodule--helper name \"$sm_path\") || exit\n-\t\tdisplaypath=$(git submodule--helper relative-path \"$prefix$sm_path\" \"$wt_prefix\")\n-\t\tif test \"$stage\" = U\n-\t\tthen\n-\t\t\tsay \"U$sha1 $displaypath\"\n-\t\t\tcontinue\n-\t\tfi\n-\t\tif ! git submodule--helper is-active \"$sm_path\" ||\n-\t\t{\n-\t\t\t! test -d \"$sm_path\"/.git &&\n-\t\t\t! test -f \"$sm_path\"/.git\n-\t\t}\n-\t\tthen\n-\t\t\tsay \"-$sha1 $displaypath\"\n-\t\t\tcontinue;\n-\t\tfi\n-\t\tif git diff-files --ignore-submodules=dirty --quiet -- \"$sm_path\"\n-\t\tthen\n-\t\t\trevname=$(git submodule--helper print-name-rev \"$sm_path\" \"$sha1\")\n-\t\t\tsay \" $sha1 $displaypath$revname\"\n-\t\telse\n-\t\t\tif test -z \"$cached\"\n-\t\t\tthen\n-\t\t\t\tsha1=$(sanitize_submodule_env; cd \"$sm_path\" && git rev-parse --verify HEAD)\n-\t\t\tfi\n-\t\t\trevname=$(git submodule--helper print-name-rev \"$sm_path\" \"$sha1\")\n-\t\t\tsay \"+$sha1 $displaypath$revname\"\n-\t\tfi\n-\n-\t\tif test -n \"$recursive\"\n-\t\tthen\n-\t\t\t(\n-\t\t\t\tprefix=\"$displaypath/\"\n-\t\t\t\tsanitize_submodule_env\n-\t\t\t\twt_prefix=\n-\t\t\t\tcd \"$sm_path\" &&\n-\t\t\t\teval cmd_status\n-\t\t\t) ||\n-\t\t\tdie \"$(eval_gettext \"Failed to recurse into submodule path '\\$sm_path'\")\"\n-\t\tfi\n-\tdone\n+\tgit ${wt_prefix:+-C \"$wt_prefix\"} ${prefix:+--super-prefix \"$prefix\"} submodule--helper status ${GIT_QUIET:+--quiet} ${cached:+--cached} ${recursive:+--recursive} \"$@\"\n }\n #\n # Sync remote urls for submodules\n-- \n2.13.0\n\n"},{"id":"323303","messageId":"20170626231108.23640-5-pc44800@gmail.com","threadId":"46265","inReplyTo":"20170626231108.23640-1-pc44800@gmail.com","subject":"[GSoC][PATCH 5/6 v2] submodule: port submodule subcommand sync from shell to C","fromName":"Prathamesh Chavan","fromEmail":"pc44800@gmail.com","sentAt":"2017-06-26T23:11:07Z","receivedAt":"2017-06-26T23:11:58Z","isPatch":true,"sender":{"key":"pc44800@gmail.com","avatar":"https://avatars.githubusercontent.com/u/17272661?v=4"},"body":"The mechanism used for porting the submodule subcommand 'sync' is\nsimilar to that of 'foreach', where we split the function cmd_sync\nfrom shell into three functions in C, module_sync,\nfor_each_submodule_list and sync_submodule.\n\nprint_default_remote is introduced as a submodule--helper\nsubcommand for getting the default remote as stdout.\n\nMentored-by: Christian Couder <christian.couder@gmail.com>\nMentored-by: Stefan Beller <sbeller@google.com>\nSigned-off-by: Prathamesh Chavan <pc44800@gmail.com>\n---\n builtin/submodule--helper.c | 178 ++++++++++++++++++++++++++++++++++++++++++++\n git-submodule.sh            |  56 +-------------\n 2 files changed, 179 insertions(+), 55 deletions(-)\n\ndiff --git a/builtin/submodule--helper.c b/builtin/submodule--helper.c\nindex a5de7a0fe..4e3322846 100644\n--- a/builtin/submodule--helper.c\n+++ b/builtin/submodule--helper.c\n@@ -44,6 +44,20 @@ static char *get_default_remote(void)\n \treturn ret;\n }\n \n+static int print_default_remote(int argc, const char **argv, const char *prefix)\n+{\n+\tconst char *remote;\n+\n+\tif (argc != 1)\n+\t\tdie(_(\"submodule--helper print-default-remote takes no arguments\"));\n+\n+\tremote = get_default_remote();\n+\tif (remote)\n+\t\tputs(remote);\n+\n+\treturn 0;\n+}\n+\n static int starts_with_dot_slash(const char *str)\n {\n \treturn str[0] == '.' && is_dir_sep(str[1]);\n@@ -385,6 +399,26 @@ static void module_list_active(struct module_list *list)\n \t*list = active_modules;\n }\n \n+static char *get_up_path(const char *path)\n+{\n+\tint i = count_slashes(path);\n+\tint l = strlen(path);\n+\tstruct strbuf sb = STRBUF_INIT;\n+\n+\twhile (i--)\n+\t\tstrbuf_addstr(&sb, \"../\");\n+\n+\t/*\n+\t *Check if 'path' ends with slash or not\n+\t *for having the same output for dir/sub_dir\n+\t *and dir/sub_dir/\n+\t */\n+\tif (!is_dir_sep(path[l - 1]))\n+\t\tstrbuf_addstr(&sb, \"../\");\n+\n+\treturn strbuf_detach(&sb, NULL);\n+}\n+\n static int module_list(int argc, const char **argv, const char *prefix)\n {\n \tint i;\n@@ -898,6 +932,148 @@ static int module_foreach(int argc, const char **argv, const char *prefix)\n \treturn 0;\n }\n \n+struct sync_cb {\n+\tconst char *prefix;\n+\tunsigned int quiet: 1;\n+\tunsigned int recursive: 1;\n+};\n+#define SYNC_CB_INIT { NULL, 0, 0 }\n+\n+static void sync_submodule(const struct cache_entry *list_item, void *cb_data)\n+{\n+\tstruct sync_cb *info = cb_data;\n+\tconst struct submodule *sub;\n+\tchar *sub_key, *remote_key;\n+\tchar *sub_origin_url, *super_config_url, *displaypath;\n+\tstruct strbuf sb = STRBUF_INIT;\n+\tstruct child_process cp = CHILD_PROCESS_INIT;\n+\n+\tif (!is_submodule_initialized(list_item->name))\n+\t\treturn;\n+\n+\tsub = submodule_from_path(null_sha1, list_item->name);\n+\n+\tif (!sub && !sub->url)\n+\t\tdie(_(\"no url found for submodule path '%s' in .gitmodules\"),\n+\t\t      list_item->name);\n+\n+\tif (starts_with_dot_dot_slash(sub->url) || starts_with_dot_slash(sub->url)) {\n+\t\tchar *remote_url, *up_path;\n+\t\tchar *remote = get_default_remote();\n+\t\tchar *remote_key = xstrfmt(\"remote.%s.url\", remote);\n+\t\tfree(remote);\n+\n+\t\tif (git_config_get_string(remote_key, &remote_url))\n+\t\t\tremote_url = xgetcwd();\n+\t\tup_path = get_up_path(list_item->name);\n+\t\tsub_origin_url = relative_url(remote_url, sub->url, up_path);\n+\t\tsuper_config_url = relative_url(remote_url, sub->url, NULL);\n+\t\tfree(remote_key);\n+\t\tfree(up_path);\n+\t\tfree(remote_url);\n+\t} else {\n+\t\tsub_origin_url = xstrdup(sub->url);\n+\t\tsuper_config_url = xstrdup(sub->url);\n+\t}\n+\n+\tdisplaypath = get_submodule_displaypath(list_item->name, info->prefix);\n+\n+\tif (!info->quiet)\n+\t\tprintf(_(\"Synchronizing submodule url for '%s'\\n\"),\n+\t\t\t displaypath);\n+\n+\tsub_key = xstrfmt(\"submodule.%s.url\", sub->name);\n+\tif (git_config_set_gently(sub_key, super_config_url))\n+\t\tdie(_(\"failed to register url for submodule path '%s'\"),\n+\t\t      displaypath);\n+\n+\tif (!is_submodule_populated_gently(list_item->name, NULL))\n+\t\tgoto cleanup;\n+\n+\tprepare_submodule_repo_env(&cp.env_array);\n+\tcp.git_cmd = 1;\n+\tcp.dir = list_item->name;\n+\targv_array_pushl(&cp.args, \"submodule--helper\",\n+\t\t\t \"print-default-remote\", NULL);\n+\tif (capture_command(&cp, &sb, 0))\n+\t\tdie(_(\"failed to get the default remote for submodule '%s'\"),\n+\t\t      list_item->name);\n+\n+\tstrbuf_strip_suffix(&sb, \"\\n\");\n+\tremote_key = xstrfmt(\"remote.%s.url\", sb.buf);\n+\tstrbuf_release(&sb);\n+\n+\tchild_process_init(&cp);\n+\tprepare_submodule_repo_env(&cp.env_array);\n+\tcp.git_cmd = 1;\n+\tcp.dir = list_item->name;\n+\targv_array_pushl(&cp.args, \"config\", remote_key, sub_origin_url, NULL);\n+\tif (run_command(&cp))\n+\t\tdie(_(\"failed to update remote for submodule '%s'\"),\n+\t\t      list_item->name);\n+\n+\tif (info->recursive) {\n+\t\tstruct child_process cpr = CHILD_PROCESS_INIT;\n+\n+\t\tcpr.git_cmd = 1;\n+\t\tcpr.dir = list_item->name;\n+\t\tprepare_submodule_repo_env(&cpr.env_array);\n+\n+\t\targv_array_pushl(&cpr.args, \"--super-prefix\", displaypath,\n+\t\t\t\t \"submodule--helper\", \"sync\", \"--recursive\",\n+\t\t\t\t NULL);\n+\n+\t\tif (info->quiet)\n+\t\t\targv_array_push(&cpr.args, \"--quiet\");\n+\n+\t\tif (run_command(&cpr))\n+\t\t\tdie(_(\"failed to recurse into submodule '%s'\"),\n+\t\t\t      list_item->name);\n+\t}\n+\n+cleanup:\n+\tfree(sub_key);\n+\tfree(super_config_url);\n+\tfree(displaypath);\n+\tfree(sub_origin_url);\n+}\n+\n+static int module_sync(int argc, const char **argv, const char *prefix)\n+{\n+\tstruct sync_cb info = SYNC_CB_INIT;\n+\tstruct pathspec pathspec;\n+\tstruct module_list list = MODULE_LIST_INIT;\n+\tint quiet = 0;\n+\tint recursive = 0;\n+\n+\tstruct option module_sync_options[] = {\n+\t\tOPT__QUIET(&quiet, N_(\"Suppress output of synchronizing submodule url\")),\n+\t\tOPT_BOOL(0, \"recursive\", &recursive,\n+\t\t\tN_(\"Recurse into nested submodules\")),\n+\t\tOPT_END()\n+\t};\n+\n+\tconst char *const git_submodule_helper_usage[] = {\n+\t\tN_(\"git submodule--helper sync [--quiet] [--recursive] [<path>]\"),\n+\t\tNULL\n+\t};\n+\n+\targc = parse_options(argc, argv, prefix, module_sync_options,\n+\t\t\t     git_submodule_helper_usage, 0);\n+\n+\tif (module_list_compute(argc, argv, prefix, &pathspec, &list) < 0)\n+\t\treturn 1;\n+\n+\tinfo.prefix = prefix;\n+\tinfo.quiet = !!quiet;\n+\tinfo.recursive = !!recursive;\n+\n+\tgitmodules_config();\n+\tfor_each_submodule_list(list, sync_submodule, &info);\n+\n+\treturn 0;\n+}\n+\n static int clone_submodule(const char *path, const char *gitdir, const char *url,\n \t\t\t   const char *depth, struct string_list *reference,\n \t\t\t   int quiet, int progress)\n@@ -1627,6 +1803,8 @@ static struct cmd_struct commands[] = {\n \t{\"print-name-rev\", print_name_rev, 0},\n \t{\"init\", module_init, SUPPORT_SUPER_PREFIX},\n \t{\"status\", module_status, SUPPORT_SUPER_PREFIX},\n+\t{\"print-default-remote\", print_default_remote, 0},\n+\t{\"sync\", module_sync, SUPPORT_SUPER_PREFIX},\n \t{\"remote-branch\", resolve_remote_submodule_branch, 0},\n \t{\"push-check\", push_check, 0},\n \t{\"absorb-git-dirs\", absorb_git_dirs, SUPPORT_SUPER_PREFIX},\ndiff --git a/git-submodule.sh b/git-submodule.sh\nindex b19d5fa7b..6257d50e9 100755\n--- a/git-submodule.sh\n+++ b/git-submodule.sh\n@@ -1000,63 +1000,9 @@ cmd_sync()\n \t\t\t;;\n \t\tesac\n \tdone\n-\tcd_to_toplevel\n-\t{\n-\t\tgit submodule--helper list --prefix \"$wt_prefix\" \"$@\" ||\n-\t\techo \"#unmatched\" $?\n-\t} |\n-\twhile read -r mode sha1 stage sm_path\n-\tdo\n-\t\tdie_if_unmatched \"$mode\" \"$sha1\"\n-\n-\t\t# skip inactive submodules\n-\t\tif ! git submodule--helper is-active \"$sm_path\"\n-\t\tthen\n-\t\t\tcontinue\n-\t\tfi\n-\n-\t\tname=$(git submodule--helper name \"$sm_path\")\n-\t\turl=$(git config -f .gitmodules --get submodule.\"$name\".url)\n-\n-\t\t# Possibly a url relative to parent\n-\t\tcase \"$url\" in\n-\t\t./*|../*)\n-\t\t\t# rewrite foo/bar as ../.. to find path from\n-\t\t\t# submodule work tree to superproject work tree\n-\t\t\tup_path=\"$(printf '%s\\n' \"$sm_path\" | sed \"s/[^/][^/]*/../g\")\" &&\n-\t\t\t# guarantee a trailing /\n-\t\t\tup_path=${up_path%/}/ &&\n-\t\t\t# path from submodule work tree to submodule origin repo\n-\t\t\tsub_origin_url=$(git submodule--helper resolve-relative-url \"$url\" \"$up_path\") &&\n-\t\t\t# path from superproject work tree to submodule origin repo\n-\t\t\tsuper_config_url=$(git submodule--helper resolve-relative-url \"$url\") || exit\n-\t\t\t;;\n-\t\t*)\n-\t\t\tsub_origin_url=\"$url\"\n-\t\t\tsuper_config_url=\"$url\"\n-\t\t\t;;\n-\t\tesac\n \n-\t\tdisplaypath=$(git submodule--helper relative-path \"$prefix$sm_path\" \"$wt_prefix\")\n-\t\tsay \"$(eval_gettext \"Synchronizing submodule url for '\\$displaypath'\")\"\n-\t\tgit config submodule.\"$name\".url \"$super_config_url\"\n+\tgit ${wt_prefix:+-C \"$wt_prefix\"} ${prefix:+--super-prefix \"$prefix\"} submodule--helper sync ${GIT_QUIET:+--quiet} ${recursive:+--recursive} \"$@\"\n \n-\t\tif test -e \"$sm_path\"/.git\n-\t\tthen\n-\t\t(\n-\t\t\tsanitize_submodule_env\n-\t\t\tcd \"$sm_path\"\n-\t\t\tremote=$(get_default_remote)\n-\t\t\tgit config remote.\"$remote\".url \"$sub_origin_url\"\n-\n-\t\t\tif test -n \"$recursive\"\n-\t\t\tthen\n-\t\t\t\tprefix=\"$prefix$sm_path/\"\n-\t\t\t\teval cmd_sync\n-\t\t\tfi\n-\t\t)\n-\t\tfi\n-\tdone\n }\n \n cmd_absorbgitdirs()\n-- \n2.13.0\n\n"},{"id":"323315","messageId":"CAP8UFD3WY4KptxphBnNVvOfh8XQYrn5jabzBegx5K07+9PnDtQ@mail.gmail.com","threadId":"46265","inReplyTo":"20170626231108.23640-2-pc44800@gmail.com","subject":"Re: [GSoC][PATCH 2/6 v2] submodule: port subcommand foreach from shell to C","fromName":"Christian Couder","fromEmail":"christian.couder@gmail.com","sentAt":"2017-06-27T06:06:35Z","receivedAt":"2017-06-27T06:07:05Z","isPatch":true,"sender":{"key":"christian.couder@gmail.com","avatar":"https://avatars.githubusercontent.com/u/208954?v=4"},"body":"On Tue, Jun 27, 2017 at 1:11 AM, Prathamesh Chavan <pc44800@gmail.com> wrote:\n> +\n> +       if (!is_submodule_populated_gently(list_item->name, NULL))\n> +               goto cleanup;\n> +\n> +       prepare_submodule_repo_env(&cp.env_array);\n> +       /* For the purpose of executing <command> in the submodule,\n> +        * separate shell is used for the purpose of running the\n> +        * child process.\n> +        */\n\nAs this comment spans over more than one line, it should be like:\n\n/*\n * first line of comment\n * second line of comment\n * more stuff ...\n */\n\nAlso please explain WHY a shell is needed, we can see from the code\nthat we will use a shell.\nSo it should be something like:\n\n/*\n * Use a shell because ...\n * and ...\n */\n\n> +       cp.use_shell = 1;\n> +       cp.dir = list_item->name;\n"},{"id":"323317","messageId":"CAP8UFD3iuSKEuuE2aGv9yW+PkD7_5F4sfLF7VSVAJXYhDUMX1A@mail.gmail.com","threadId":"46265","inReplyTo":"20170626231108.23640-5-pc44800@gmail.com","subject":"Re: [GSoC][PATCH 5/6 v2] submodule: port submodule subcommand sync from shell to C","fromName":"Christian Couder","fromEmail":"christian.couder@gmail.com","sentAt":"2017-06-27T06:37:49Z","receivedAt":"2017-06-27T06:37:55Z","isPatch":true,"sender":{"key":"christian.couder@gmail.com","avatar":"https://avatars.githubusercontent.com/u/208954?v=4"},"body":"On Tue, Jun 27, 2017 at 1:11 AM, Prathamesh Chavan <pc44800@gmail.com> wrote:\n\n> +static char *get_up_path(const char *path)\n> +{\n> +       int i = count_slashes(path);\n> +       int l = strlen(path);\n\nNit: \"l\" is quite similar to \"i\" in many fonts, so maybe use \"len\"\ninstead of \"l\", but see below.\n\n> +       struct strbuf sb = STRBUF_INIT;\n> +\n> +       while (i--)\n> +               strbuf_addstr(&sb, \"../\");\n\nNit: a regular \"for\" loop like the following might be easier to review:\n\nfor (i = count_slashes(path); i; i--)\n        strbuf_addstr(&sb, \"../\");\n\n> +       /*\n> +        *Check if 'path' ends with slash or not\n> +        *for having the same output for dir/sub_dir\n> +        *and dir/sub_dir/\n> +        */\n> +       if (!is_dir_sep(path[l - 1]))\n\nAs \"l\" is used only here, maybe we could get rid of this variable\naltogether with something like:\n\n      if (!is_dir_sep(path[strlen(path) - 1]))\n\n> +               strbuf_addstr(&sb, \"../\");\n> +\n> +       return strbuf_detach(&sb, NULL);\n> +}\n\n> +static void sync_submodule(const struct cache_entry *list_item, void *cb_data)\n> +{\n> +       struct sync_cb *info = cb_data;\n> +       const struct submodule *sub;\n> +       char *sub_key, *remote_key;\n> +       char *sub_origin_url, *super_config_url, *displaypath;\n> +       struct strbuf sb = STRBUF_INIT;\n> +       struct child_process cp = CHILD_PROCESS_INIT;\n> +\n> +       if (!is_submodule_initialized(list_item->name))\n> +               return;\n> +\n> +       sub = submodule_from_path(null_sha1, list_item->name);\n> +\n> +       if (!sub && !sub->url)\n\nI think it should be \"(!sub || !sub->url)\".\n\n> +               die(_(\"no url found for submodule path '%s' in .gitmodules\"),\n> +                     list_item->name);\n"},{"id":"323318","messageId":"CAP8UFD1mdgtHWt0CD32O=jXPkGLBiba-41DUchT4WT7CheH4bA@mail.gmail.com","threadId":"46265","inReplyTo":"20170626231108.23640-6-pc44800@gmail.com","subject":"Re: [GSoC][PATCH 6/6 v2] submodule: port submodule subcommand 'deinit' from shell to C","fromName":"Christian Couder","fromEmail":"christian.couder@gmail.com","sentAt":"2017-06-27T07:18:28Z","receivedAt":"2017-06-27T07:18:44Z","isPatch":true,"sender":{"key":"christian.couder@gmail.com","avatar":"https://avatars.githubusercontent.com/u/208954?v=4"},"body":"On Tue, Jun 27, 2017 at 1:11 AM, Prathamesh Chavan <pc44800@gmail.com> wrote:\n\n> +static void deinit_submodule(const struct cache_entry *list_item,\n> +                            void *cb_data)\n> +{\n> +       struct deinit_cb *info = cb_data;\n> +       const struct submodule *sub;\n> +       char *displaypath = NULL;\n> +       struct child_process cp_config = CHILD_PROCESS_INIT;\n> +       struct strbuf sb_config = STRBUF_INIT;\n> +       char *sm_path = xstrdup(list_item->name);\n> +       char *sub_git_dir = xstrfmt(\"%s/.git\", sm_path);\n> +\n> +       sub = submodule_from_path(null_sha1, sm_path);\n> +\n> +       if (!sub->name)\n\nIn the previous patch \"!sub\" is used before \"!sub->url\", so we might\nwant to check \"!sub\" here too.\n\n> +               goto cleanup;\n> +\n> +       displaypath = get_submodule_displaypath(sm_path, info->prefix);\n> +\n> +       /* remove the submodule work tree (unless the user already did it) */\n> +       if (is_directory(sm_path)) {\n> +               struct child_process cp = CHILD_PROCESS_INIT;\n> +\n> +               /* protect submodules containing a .git directory */\n> +               if (is_git_directory(sub_git_dir))\n> +                       die(_(\"Submodule work tree '%s' contains a .git \"\n> +                             \"directory use 'rm -rf' if you really want \"\n> +                             \"to remove it including all of its history\"),\n> +                             displaypath);\n> +\n> +               if (!info->force) {\n> +                       struct child_process cp_rm = CHILD_PROCESS_INIT;\n> +                       cp_rm.git_cmd = 1;\n> +                       argv_array_pushl(&cp_rm.args, \"rm\", \"-qn\", sm_path,\n> +                                        NULL);\n> +\n> +                       /* list_item->name is changed by cmd_rm() below */\n\nIt looks like cmd_rm() is not used anymore below, so this comment\ncould go and the sm_path variable might not be needed any more.\n\n> +                       if (run_command(&cp_rm))\n> +                               die(_(\"Submodule work tree '%s' contains local \"\n> +                                     \"modifications; use '-f' to discard them\"),\n> +                                     displaypath);\n> +               }\n> +\n> +               cp.use_shell = 1;\n\nDo we really need a shell here?\n\n> +               argv_array_pushl(&cp.args, \"rm\", \"-rf\", sm_path, NULL);\n> +               if (!run_command(&cp)) {\n> +                       if (!info->quiet)\n> +                               printf(_(\"Cleared directory '%s'\\n\"),\n> +                                        displaypath);\n> +               } else {\n> +                       if (!info->quiet)\n> +                               printf(_(\"Could not remove submodule work tree '%s'\\n\"),\n> +                                        displaypath);\n> +               }\n> +       }\n> +\n> +       if (mkdir(sm_path, 0700))\n\nAre you sure about the 0700 mode?\nShouldn't this depend on the shared repository settings?\n\n> +               die(_(\"could not create empty submodule directory %s\"),\n> +                     displaypath);\n"},{"id":"323437","messageId":"xmqq60ffx51d.fsf@gitster.mtv.corp.google.com","threadId":"46265","inReplyTo":"20170626231108.23640-1-pc44800@gmail.com","subject":"Re: [GSoC][PATCH 1/6 v2] submodule--helper: introduce for_each_submodule_list","fromName":"Junio C Hamano","fromEmail":"gitster@pobox.com","sentAt":"2017-06-28T19:53:34Z","receivedAt":"2017-06-28T19:54:01Z","isPatch":true,"sender":{"key":"gitster@pobox.com","avatar":"https://avatars.githubusercontent.com/u/54884?v=4"},"body":"Prathamesh Chavan <pc44800@gmail.com> writes:\n\n> Introduce function for_each_submodule_list for using it\n> in the later patches, related to porting submodule\n> subcommands from shell to C.\n> This new function is also used in ported submodule subcommand\n> init.\n\nThe patch text looks sensible.  It would be easier for \"git log\"\nreaders to understand, if the change is explained like so:\n\n\tIntroduce function for_each_submodule_list() and\n\treplace a loop in module_init() with a call to it.\n\n\tThe new function will also be used in other parts of the\n\tsystem in later patches.\n\nThat way, readers do not have to judge the merit of this change\nbased on a vague promise \"it will help world better with future\npatches\", but can instead judge on its immediate benefit that it\nrefactors a useful bit out of an existing code.\n\n> Mentored-by: Christian Couder <christian.couder@gmail.com>\n> Mentored-by: Stefan Beller <sbeller@google.com>\n> Signed-off-by: Prathamesh Chavan <pc44800@gmail.com>\n> ---\n> This series of patches is based on the 'next' branch. \n\nThe reason not to base on 'master' is...?\n\nThe thing is that a topic built on 'next' cannot be merged down to\n'master' until _all_ other topics in 'next' graduate to 'master',\nwhich may never happen.  If you are depending on one or more topics,\nplease make sure to name them.  Then we can\n\n (1) create a branch from the tip of 'master';\n (2) merge these topics you depend on into that branch; and then\n (3) apply these patches.\n\nThe topic still needs to wait until these other topis graduate, but\nat least you would not be blocked by unrelated topics that way.\n\nYou _might_ be building on 'next' because you want to make sure that\nyour topic works not just with master but also want to make sure\nthat there won't be any unexpected breakage when used with topics in\n'next', even though your topic does not depend on anything in 'next'\nin particular.  It is a good development discipline to pay attention\nto other topics in flight and I applaud you for it if that is why\nyou based it on 'next'.  But the right way to do it would be to\nbuild your topic on 'master', and then in addition to testing the\ntopic by itself, also make a trial merge of your topic into 'next'\nand test the result as well.\n\nThanks.\n"},{"id":"323475","messageId":"CAME+mvUbkT-QSbnU62nsfT1SEKFi7OQ4OeUQZYfJ3R=xb3cceg@mail.gmail.com","threadId":"46265","inReplyTo":"xmqq60ffx51d.fsf@gitster.mtv.corp.google.com","subject":"Re: [GSoC][PATCH 1/6 v2] submodule--helper: introduce for_each_submodule_list","fromName":"Prathamesh Chavan","fromEmail":"pc44800@gmail.com","sentAt":"2017-06-29T11:47:22Z","receivedAt":"2017-06-29T11:47:28Z","isPatch":true,"sender":{"key":"pc44800@gmail.com","avatar":"https://avatars.githubusercontent.com/u/17272661?v=4"},"body":">> This series of patches is based on the 'next' branch.\n>\n> The reason not to base on 'master' is...?\n>\n\nThe reason it wasn't based on 'master' was that it depended on the commit:\ndir: create function count_slashes(),\nwhich was merged to 'next' a few days back.\n\n> The thing is that a topic built on 'next' cannot be merged down to\n> 'master' until _all_ other topics in 'next' graduate to 'master',\n> which may never happen.  If you are depending on one or more topics,\n> please make sure to name them.  Then we can\n>\n>  (1) create a branch from the tip of 'master';\n>  (2) merge these topics you depend on into that branch; and then\n>  (3) apply these patches.\n>\nI'll soon be updating this patch series and will create the new patch series in\naccordance with the above routine.\n\n> The topic still needs to wait until these other topis graduate, but\n> at least you would not be blocked by unrelated topics that way.\n>\n> You _might_ be building on 'next' because you want to make sure that\n> your topic works not just with master but also want to make sure\n> that there won't be any unexpected breakage when used with topics in\n> 'next', even though your topic does not depend on anything in 'next'\n> in particular.  It is a good development discipline to pay attention\n> to other topics in flight and I applaud you for it if that is why\n> you based it on 'next'.  But the right way to do it would be to\n> build your topic on 'master', and then in addition to testing the\n> topic by itself, also make a trial merge of your topic into 'next'\n> and test the result as well.\n>\nThanks for making me aware about this as well. And will be following this\nbefore sending out the updated patch-series.\n\nThanks,\nPrathamesh Chavan\n"},{"id":"323599","messageId":"20170630194727.29787-5-pc44800@gmail.com","threadId":"46265","inReplyTo":"20170630194727.29787-1-pc44800@gmail.com","subject":"[GSoC][PATCH 5/5 v3] submodule: port submodule subcommand 'sync' from shell to C","fromName":"Prathamesh Chavan","fromEmail":"pc44800@gmail.com","sentAt":"2017-06-30T19:47:27Z","receivedAt":"2017-06-30T19:48:51Z","isPatch":true,"sender":{"key":"pc44800@gmail.com","avatar":"https://avatars.githubusercontent.com/u/17272661?v=4"},"body":"Port the submodule subcommand 'sync' from shell to C using the same\nmechanism as that used for porting submodule subcommand 'status'.\nHence, here the function cmd_sync() is ported from shell to C.\nThis is done by introducing three functions: module_sync(),\nsync_submodule() and print_default_remote().\n\nThe function print_default_remote() is introduced for getting\nthe default remote as stdout.\n\nMentored-by: Christian Couder <christian.couder@gmail.com>\nMentored-by: Stefan Beller <sbeller@google.com>\nSigned-off-by: Prathamesh Chavan <pc44800@gmail.com>\n---\n builtin/submodule--helper.c | 177 ++++++++++++++++++++++++++++++++++++++++++++\n git-submodule.sh            |  56 +-------------\n 2 files changed, 178 insertions(+), 55 deletions(-)\n\ndiff --git a/builtin/submodule--helper.c b/builtin/submodule--helper.c\nindex 575ae0218..d933daadd 100644\n--- a/builtin/submodule--helper.c\n+++ b/builtin/submodule--helper.c\n@@ -44,6 +44,20 @@ static char *get_default_remote(void)\n \treturn ret;\n }\n \n+static int print_default_remote(int argc, const char **argv, const char *prefix)\n+{\n+\tconst char *remote;\n+\n+\tif (argc != 1)\n+\t\tdie(_(\"submodule--helper print-default-remote takes no arguments\"));\n+\n+\tremote = get_default_remote();\n+\tif (remote)\n+\t\tputs(remote);\n+\n+\treturn 0;\n+}\n+\n static int starts_with_dot_slash(const char *str)\n {\n \treturn str[0] == '.' && is_dir_sep(str[1]);\n@@ -385,6 +399,25 @@ static void module_list_active(struct module_list *list)\n \t*list = active_modules;\n }\n \n+static char *get_up_path(const char *path)\n+{\n+\tint i;\n+\tstruct strbuf sb = STRBUF_INIT;\n+\n+\tfor (i = count_slashes(path); i; i--)\n+\t\tstrbuf_addstr(&sb, \"../\");\n+\n+\t/*\n+\t * Check if 'path' ends with slash or not\n+\t * for having the same output for dir/sub_dir\n+\t * and dir/sub_dir/\n+\t */\n+\tif (!is_dir_sep(path[strlen(path) - 1]))\n+\t\tstrbuf_addstr(&sb, \"../\");\n+\n+\treturn strbuf_detach(&sb, NULL);\n+}\n+\n static int module_list(int argc, const char **argv, const char *prefix)\n {\n \tint i;\n@@ -736,6 +769,148 @@ static int module_name(int argc, const char **argv, const char *prefix)\n \treturn 0;\n }\n \n+struct sync_cb {\n+\tconst char *prefix;\n+\tunsigned int quiet: 1;\n+\tunsigned int recursive: 1;\n+};\n+#define SYNC_CB_INIT { NULL, 0, 0 }\n+\n+static void sync_submodule(const struct cache_entry *list_item, void *cb_data)\n+{\n+\tstruct sync_cb *info = cb_data;\n+\tconst struct submodule *sub;\n+\tchar *sub_key, *remote_key;\n+\tchar *sub_origin_url, *super_config_url, *displaypath;\n+\tstruct strbuf sb = STRBUF_INIT;\n+\tstruct child_process cp = CHILD_PROCESS_INIT;\n+\n+\tif (!is_submodule_initialized(list_item->name))\n+\t\treturn;\n+\n+\tsub = submodule_from_path(null_sha1, list_item->name);\n+\n+\tif (!sub || !sub->url)\n+\t\tdie(_(\"no url found for submodule path '%s' in .gitmodules\"),\n+\t\t      list_item->name);\n+\n+\tif (starts_with_dot_dot_slash(sub->url) || starts_with_dot_slash(sub->url)) {\n+\t\tchar *remote_url, *up_path;\n+\t\tchar *remote = get_default_remote();\n+\t\tchar *remote_key = xstrfmt(\"remote.%s.url\", remote);\n+\t\tfree(remote);\n+\n+\t\tif (git_config_get_string(remote_key, &remote_url))\n+\t\t\tremote_url = xgetcwd();\n+\t\tup_path = get_up_path(list_item->name);\n+\t\tsub_origin_url = relative_url(remote_url, sub->url, up_path);\n+\t\tsuper_config_url = relative_url(remote_url, sub->url, NULL);\n+\t\tfree(remote_key);\n+\t\tfree(up_path);\n+\t\tfree(remote_url);\n+\t} else {\n+\t\tsub_origin_url = xstrdup(sub->url);\n+\t\tsuper_config_url = xstrdup(sub->url);\n+\t}\n+\n+\tdisplaypath = get_submodule_displaypath(list_item->name, info->prefix);\n+\n+\tif (!info->quiet)\n+\t\tprintf(_(\"Synchronizing submodule url for '%s'\\n\"),\n+\t\t\t displaypath);\n+\n+\tsub_key = xstrfmt(\"submodule.%s.url\", sub->name);\n+\tif (git_config_set_gently(sub_key, super_config_url))\n+\t\tdie(_(\"failed to register url for submodule path '%s'\"),\n+\t\t      displaypath);\n+\n+\tif (!is_submodule_populated_gently(list_item->name, NULL))\n+\t\tgoto cleanup;\n+\n+\tprepare_submodule_repo_env(&cp.env_array);\n+\tcp.git_cmd = 1;\n+\tcp.dir = list_item->name;\n+\targv_array_pushl(&cp.args, \"submodule--helper\",\n+\t\t\t \"print-default-remote\", NULL);\n+\tif (capture_command(&cp, &sb, 0))\n+\t\tdie(_(\"failed to get the default remote for submodule '%s'\"),\n+\t\t      list_item->name);\n+\n+\tstrbuf_strip_suffix(&sb, \"\\n\");\n+\tremote_key = xstrfmt(\"remote.%s.url\", sb.buf);\n+\tstrbuf_release(&sb);\n+\n+\tchild_process_init(&cp);\n+\tprepare_submodule_repo_env(&cp.env_array);\n+\tcp.git_cmd = 1;\n+\tcp.dir = list_item->name;\n+\targv_array_pushl(&cp.args, \"config\", remote_key, sub_origin_url, NULL);\n+\tif (run_command(&cp))\n+\t\tdie(_(\"failed to update remote for submodule '%s'\"),\n+\t\t      list_item->name);\n+\n+\tif (info->recursive) {\n+\t\tstruct child_process cpr = CHILD_PROCESS_INIT;\n+\n+\t\tcpr.git_cmd = 1;\n+\t\tcpr.dir = list_item->name;\n+\t\tprepare_submodule_repo_env(&cpr.env_array);\n+\n+\t\targv_array_pushl(&cpr.args, \"--super-prefix\", displaypath,\n+\t\t\t\t \"submodule--helper\", \"sync\", \"--recursive\",\n+\t\t\t\t NULL);\n+\n+\t\tif (info->quiet)\n+\t\t\targv_array_push(&cpr.args, \"--quiet\");\n+\n+\t\tif (run_command(&cpr))\n+\t\t\tdie(_(\"failed to recurse into submodule '%s'\"),\n+\t\t\t      list_item->name);\n+\t}\n+\n+cleanup:\n+\tfree(sub_key);\n+\tfree(super_config_url);\n+\tfree(displaypath);\n+\tfree(sub_origin_url);\n+}\n+\n+static int module_sync(int argc, const char **argv, const char *prefix)\n+{\n+\tstruct sync_cb info = SYNC_CB_INIT;\n+\tstruct pathspec pathspec;\n+\tstruct module_list list = MODULE_LIST_INIT;\n+\tint quiet = 0;\n+\tint recursive = 0;\n+\n+\tstruct option module_sync_options[] = {\n+\t\tOPT__QUIET(&quiet, N_(\"Suppress output of synchronizing submodule url\")),\n+\t\tOPT_BOOL(0, \"recursive\", &recursive,\n+\t\t\tN_(\"Recurse into nested submodules\")),\n+\t\tOPT_END()\n+\t};\n+\n+\tconst char *const git_submodule_helper_usage[] = {\n+\t\tN_(\"git submodule--helper sync [--quiet] [--recursive] [<path>]\"),\n+\t\tNULL\n+\t};\n+\n+\targc = parse_options(argc, argv, prefix, module_sync_options,\n+\t\t\t     git_submodule_helper_usage, 0);\n+\n+\tif (module_list_compute(argc, argv, prefix, &pathspec, &list) < 0)\n+\t\treturn 1;\n+\n+\tinfo.prefix = prefix;\n+\tinfo.quiet = !!quiet;\n+\tinfo.recursive = !!recursive;\n+\n+\tgitmodules_config();\n+\tfor_each_submodule_list(list, sync_submodule, &info);\n+\n+\treturn 0;\n+}\n+\n static int clone_submodule(const char *path, const char *gitdir, const char *url,\n \t\t\t   const char *depth, struct string_list *reference,\n \t\t\t   int quiet, int progress)\n@@ -1464,6 +1639,8 @@ static struct cmd_struct commands[] = {\n \t{\"print-name-rev\", print_name_rev, 0},\n \t{\"init\", module_init, SUPPORT_SUPER_PREFIX},\n \t{\"status\", module_status, SUPPORT_SUPER_PREFIX},\n+\t{\"print-default-remote\", print_default_remote, 0},\n+\t{\"sync\", module_sync, SUPPORT_SUPER_PREFIX},\n \t{\"remote-branch\", resolve_remote_submodule_branch, 0},\n \t{\"push-check\", push_check, 0},\n \t{\"absorb-git-dirs\", absorb_git_dirs, SUPPORT_SUPER_PREFIX},\ndiff --git a/git-submodule.sh b/git-submodule.sh\nindex 51b057d82..6bfc5e17d 100755\n--- a/git-submodule.sh\n+++ b/git-submodule.sh\n@@ -1037,63 +1037,9 @@ cmd_sync()\n \t\t\t;;\n \t\tesac\n \tdone\n-\tcd_to_toplevel\n-\t{\n-\t\tgit submodule--helper list --prefix \"$wt_prefix\" \"$@\" ||\n-\t\techo \"#unmatched\" $?\n-\t} |\n-\twhile read -r mode sha1 stage sm_path\n-\tdo\n-\t\tdie_if_unmatched \"$mode\" \"$sha1\"\n-\n-\t\t# skip inactive submodules\n-\t\tif ! git submodule--helper is-active \"$sm_path\"\n-\t\tthen\n-\t\t\tcontinue\n-\t\tfi\n-\n-\t\tname=$(git submodule--helper name \"$sm_path\")\n-\t\turl=$(git config -f .gitmodules --get submodule.\"$name\".url)\n-\n-\t\t# Possibly a url relative to parent\n-\t\tcase \"$url\" in\n-\t\t./*|../*)\n-\t\t\t# rewrite foo/bar as ../.. to find path from\n-\t\t\t# submodule work tree to superproject work tree\n-\t\t\tup_path=\"$(printf '%s\\n' \"$sm_path\" | sed \"s/[^/][^/]*/../g\")\" &&\n-\t\t\t# guarantee a trailing /\n-\t\t\tup_path=${up_path%/}/ &&\n-\t\t\t# path from submodule work tree to submodule origin repo\n-\t\t\tsub_origin_url=$(git submodule--helper resolve-relative-url \"$url\" \"$up_path\") &&\n-\t\t\t# path from superproject work tree to submodule origin repo\n-\t\t\tsuper_config_url=$(git submodule--helper resolve-relative-url \"$url\") || exit\n-\t\t\t;;\n-\t\t*)\n-\t\t\tsub_origin_url=\"$url\"\n-\t\t\tsuper_config_url=\"$url\"\n-\t\t\t;;\n-\t\tesac\n \n-\t\tdisplaypath=$(git submodule--helper relative-path \"$prefix$sm_path\" \"$wt_prefix\")\n-\t\tsay \"$(eval_gettext \"Synchronizing submodule url for '\\$displaypath'\")\"\n-\t\tgit config submodule.\"$name\".url \"$super_config_url\"\n-\n-\t\tif test -e \"$sm_path\"/.git\n-\t\tthen\n-\t\t(\n-\t\t\tsanitize_submodule_env\n-\t\t\tcd \"$sm_path\"\n-\t\t\tremote=$(get_default_remote)\n-\t\t\tgit config remote.\"$remote\".url \"$sub_origin_url\"\n+\tgit ${wt_prefix:+-C \"$wt_prefix\"} ${prefix:+--super-prefix \"$prefix\"} submodule--helper sync ${GIT_QUIET:+--quiet} ${recursive:+--recursive} \"$@\"\n \n-\t\t\tif test -n \"$recursive\"\n-\t\t\tthen\n-\t\t\t\tprefix=\"$prefix$sm_path/\"\n-\t\t\t\teval cmd_sync\n-\t\t\tfi\n-\t\t)\n-\t\tfi\n-\tdone\n }\n \n cmd_absorbgitdirs()\n-- \n2.13.0\n\n"},{"id":"323600","messageId":"20170630194727.29787-2-pc44800@gmail.com","threadId":"46265","inReplyTo":"20170630194727.29787-1-pc44800@gmail.com","subject":"[GSoC][PATCH 2/5 v3] submodule--helper: introduce for_each_submodule_list()","fromName":"Prathamesh Chavan","fromEmail":"pc44800@gmail.com","sentAt":"2017-06-30T19:47:24Z","receivedAt":"2017-06-30T19:48:53Z","isPatch":true,"sender":{"key":"pc44800@gmail.com","avatar":"https://avatars.githubusercontent.com/u/17272661?v=4"},"body":"Introduce function for_each_submodule_list() and\nreplace a loop in module_init() with a call to it.\n\nThe new function will also be used in other parts of the\nsystem in later patches.\n\nMentored-by: Christian Couder <christian.couder@gmail.com>\nMentored-by: Stefan Beller <sbeller@google.com>\nSigned-off-by: Prathamesh Chavan <pc44800@gmail.com>\n---\n builtin/submodule--helper.c | 39 +++++++++++++++++++++++++++++----------\n 1 file changed, 29 insertions(+), 10 deletions(-)\n\ndiff --git a/builtin/submodule--helper.c b/builtin/submodule--helper.c\nindex 1bfc91bca..c4286aac5 100644\n--- a/builtin/submodule--helper.c\n+++ b/builtin/submodule--helper.c\n@@ -14,6 +14,9 @@\n #include \"refs.h\"\n #include \"connect.h\"\n \n+typedef void (*submodule_list_func_t)(const struct cache_entry *list_item,\n+\t\t\t\t      void *cb_data);\n+\n static char *get_default_remote(void)\n {\n \tchar *dest = NULL, *ret;\n@@ -352,17 +355,30 @@ static int module_list(int argc, const char **argv, const char *prefix)\n \treturn 0;\n }\n \n-static void init_submodule(const char *path, const char *prefix, int quiet)\n+static void for_each_submodule_list(const struct module_list list,\n+\t\t\t\t    submodule_list_func_t fn, void *cb_data)\n {\n+\tint i;\n+\tfor (i = 0; i < list.nr; i++)\n+\t\tfn(list.entries[i], cb_data);\n+}\n+\n+struct init_cb {\n+\tconst char *prefix;\n+\tunsigned int quiet: 1;\n+};\n+#define INIT_CB_INIT { NULL, 0 }\n+\n+static void init_submodule(const struct cache_entry *list_item, void *cb_data)\n+{\n+\tstruct init_cb *info = cb_data;\n \tconst struct submodule *sub;\n \tstruct strbuf sb = STRBUF_INIT;\n \tchar *upd = NULL, *url = NULL, *displaypath;\n \n-\t/* Only loads from .gitmodules, no overlay with .git/config */\n-\tgitmodules_config();\n-\tdisplaypath = get_submodule_displaypath(path, prefix);\n+\tdisplaypath = get_submodule_displaypath(list_item->name, info->prefix);\n \n-\tsub = submodule_from_path(null_sha1, path);\n+\tsub = submodule_from_path(null_sha1, list_item->name);\n \n \tif (!sub)\n \t\tdie(_(\"No url found for submodule path '%s' in .gitmodules\"),\n@@ -374,7 +390,7 @@ static void init_submodule(const char *path, const char *prefix, int quiet)\n \t *\n \t * Set active flag for the submodule being initialized\n \t */\n-\tif (!is_submodule_initialized(path)) {\n+\tif (!is_submodule_initialized(list_item->name)) {\n \t\tstrbuf_addf(&sb, \"submodule.%s.active\", sub->name);\n \t\tgit_config_set_gently(sb.buf, \"true\");\n \t}\n@@ -416,7 +432,7 @@ static void init_submodule(const char *path, const char *prefix, int quiet)\n \t\tif (git_config_set_gently(sb.buf, url))\n \t\t\tdie(_(\"Failed to register url for submodule path '%s'\"),\n \t\t\t    displaypath);\n-\t\tif (!quiet)\n+\t\tif (!info->quiet)\n \t\t\tfprintf(stderr,\n \t\t\t\t_(\"Submodule '%s' (%s) registered for path '%s'\\n\"),\n \t\t\t\tsub->name, url, displaypath);\n@@ -445,10 +461,10 @@ static void init_submodule(const char *path, const char *prefix, int quiet)\n \n static int module_init(int argc, const char **argv, const char *prefix)\n {\n+\tstruct init_cb info = INIT_CB_INIT;\n \tstruct pathspec pathspec;\n \tstruct module_list list = MODULE_LIST_INIT;\n \tint quiet = 0;\n-\tint i;\n \n \tstruct option module_init_options[] = {\n \t\tOPT__QUIET(&quiet, N_(\"Suppress output for initializing a submodule\")),\n@@ -473,8 +489,11 @@ static int module_init(int argc, const char **argv, const char *prefix)\n \tif (!argc && git_config_get_value_multi(\"submodule.active\"))\n \t\tmodule_list_active(&list);\n \n-\tfor (i = 0; i < list.nr; i++)\n-\t\tinit_submodule(list.entries[i]->name, prefix, quiet);\n+\tinfo.prefix = prefix;\n+\tinfo.quiet = !!quiet;\n+\n+\tgitmodules_config();\n+\tfor_each_submodule_list(list, init_submodule, &info);\n \n \treturn 0;\n }\n-- \n2.13.0\n\n"},{"id":"323601","messageId":"20170630194727.29787-4-pc44800@gmail.com","threadId":"46265","inReplyTo":"20170630194727.29787-1-pc44800@gmail.com","subject":"[GSoC][PATCH 4/5 v3] submodule: port submodule subcommand 'status' from shell to C","fromName":"Prathamesh Chavan","fromEmail":"pc44800@gmail.com","sentAt":"2017-06-30T19:47:26Z","receivedAt":"2017-06-30T19:49:23Z","isPatch":true,"sender":{"key":"pc44800@gmail.com","avatar":"https://avatars.githubusercontent.com/u/17272661?v=4"},"body":"This aims to make git-submodule 'status' a built-in. Hence, the function\ncmd_status() is ported from shell to C. This is done by introducing\nthree functions: module_status(), submodule_status() and print_status().\n\nThe function module_status() acts as the front-end of the subcommand.\nIt parses subcommand's options and then calls the function\nmodule_list_compute() for computing the list of submodules. Then\nthis functions calls for_each_submodule_list() looping through the\nlist obtained.\n\nThen for_each_submodule_list() calls submodule_status() for each of the\nsubmodule in its list. The function submodule_status() is responsible\nfor generating the status each submodule it is called for, and\nthen calls print_status().\n\nFinally, the function print_status() handles the printing of submodule's\nstatus.\n\nMentored-by: Christian Couder <christian.couder@gmail.com>\nMentored-by: Stefan Beller <sbeller@google.com>\nSigned-off-by: Prathamesh Chavan <pc44800@gmail.com>\n---\n builtin/submodule--helper.c | 152 ++++++++++++++++++++++++++++++++++++++++++++\n git-submodule.sh            |  49 +-------------\n 2 files changed, 153 insertions(+), 48 deletions(-)\n\ndiff --git a/builtin/submodule--helper.c b/builtin/submodule--helper.c\nindex 4103e40e4..575ae0218 100644\n--- a/builtin/submodule--helper.c\n+++ b/builtin/submodule--helper.c\n@@ -566,6 +566,157 @@ static int module_init(int argc, const char **argv, const char *prefix)\n \treturn 0;\n }\n \n+struct status_cb {\n+\tconst char *prefix;\n+\tunsigned int quiet: 1;\n+\tunsigned int recursive: 1;\n+\tunsigned int cached: 1;\n+};\n+#define STATUS_CB_INIT { NULL, 0, 0, 0 }\n+\n+static void print_status(struct status_cb *info, char state, const char *path,\n+\t\t\t char *sub_sha1, char *displaypath)\n+{\n+\tif (info->quiet)\n+\t\treturn;\n+\n+\tprintf(\"%c%s %s\", state, sub_sha1, displaypath);\n+\n+\tif (state == ' ' || state == '+') {\n+\t\tstruct argv_array name_rev_args = ARGV_ARRAY_INIT;\n+\n+\t\targv_array_pushl(&name_rev_args, \"print-name-rev\",\n+\t\t\t\t path, sub_sha1, NULL);\n+\t\tprint_name_rev(name_rev_args.argc, name_rev_args.argv,\n+\t\t\t       info->prefix);\n+\t} else {\n+\t\tprintf(\"\\n\");\n+\t}\n+}\n+\n+static void status_submodule(const struct cache_entry *list_item, void *cb_data)\n+{\n+\tstruct status_cb *info = cb_data;\n+\tchar *sub_sha1 = xstrdup(oid_to_hex(&list_item->oid));\n+\tchar *displaypath;\n+\tstruct argv_array diff_files_args = ARGV_ARRAY_INIT;\n+\n+\tif (!submodule_from_path(null_sha1, list_item->name))\n+\t\tdie(_(\"no submodule mapping found in .gitmodules for path '%s'\"),\n+\t\t      list_item->name);\n+\n+\tdisplaypath = get_submodule_displaypath(list_item->name, info->prefix);\n+\n+\tif (list_item->ce_flags) {\n+\t\tprint_status(info, 'U', list_item->name,\n+\t\t\t     sha1_to_hex(null_sha1), displaypath);\n+\t\tgoto cleanup;\n+\t}\n+\n+\tif (!is_submodule_initialized(list_item->name)) {\n+\t\tprint_status(info, '-', list_item->name, sub_sha1, displaypath);\n+\t\tgoto cleanup;\n+\t}\n+\n+\targv_array_pushl(&diff_files_args, \"diff-files\",\n+\t\t\t \"--ignore-submodules=dirty\", \"--quiet\", \"--\",\n+\t\t\t list_item->name, NULL);\n+\n+\tif (!cmd_diff_files(diff_files_args.argc, diff_files_args.argv,\n+\t\t\t    info->prefix)) {\n+\t\tprint_status(info, ' ', list_item->name, sub_sha1, displaypath);\n+\t} else {\n+\t\tif (!info->cached) {\n+\t\t\tstruct child_process cp = CHILD_PROCESS_INIT;\n+\t\t\tstruct strbuf sb = STRBUF_INIT;\n+\n+\t\t\tprepare_submodule_repo_env(&cp.env_array);\n+\t\t\tcp.git_cmd = 1;\n+\t\t\tcp.dir = list_item->name;\n+\n+\t\t\targv_array_pushl(&cp.args, \"rev-parse\",\n+\t\t\t\t\t \"--verify\", \"HEAD\", NULL);\n+\n+\t\t\tif (capture_command(&cp, &sb, 0))\n+\t\t\t\tdie(_(\"could not run 'git rev-parse --verify\"\n+\t\t\t\t      \"HEAD' in submodule %s\"),\n+\t\t\t\t      list_item->name);\n+\n+\t\t\tstrbuf_strip_suffix(&sb, \"\\n\");\n+\t\t\tprint_status(info, '+', list_item->name, sb.buf,\n+\t\t\t\t     displaypath);\n+\t\t\tstrbuf_release(&sb);\n+\t\t} else {\n+\t\t\tprint_status(info, '+', list_item->name, sub_sha1,\n+\t\t\t\t     displaypath);\n+\t\t}\n+\t}\n+\n+\tif (info->recursive) {\n+\t\tstruct child_process cpr = CHILD_PROCESS_INIT;\n+\n+\t\tcpr.git_cmd = 1;\n+\t\tcpr.dir = list_item->name;\n+\t\tprepare_submodule_repo_env(&cpr.env_array);\n+\n+\t\targv_array_pushl(&cpr.args, \"--super-prefix\", displaypath,\n+\t\t\t\t \"submodule--helper\", \"status\", \"--recursive\",\n+\t\t\t\t NULL);\n+\n+\t\tif (info->cached)\n+\t\t\targv_array_push(&cpr.args, \"--cached\");\n+\n+\t\tif (info->quiet)\n+\t\t\targv_array_push(&cpr.args, \"--quiet\");\n+\n+\t\tif (run_command(&cpr))\n+\t\t\tdie(_(\"failed to recurse into submodule '%s'\"),\n+\t\t\t      list_item->name);\n+\t}\n+\n+cleanup:\n+\tfree(displaypath);\n+\tfree(sub_sha1);\n+}\n+\n+static int module_status(int argc, const char **argv, const char *prefix)\n+{\n+\tstruct status_cb info = STATUS_CB_INIT;\n+\tstruct pathspec pathspec;\n+\tstruct module_list list = MODULE_LIST_INIT;\n+\tint quiet = 0;\n+\tint cached = 0;\n+\tint recursive = 0;\n+\n+\tstruct option module_status_options[] = {\n+\t\tOPT__QUIET(&quiet, N_(\"Suppress submodule status output\")),\n+\t\tOPT_BOOL(0, \"cached\", &cached, N_(\"Use commit stored in the index instead of the one stored in the submodule HEAD\")),\n+\t\tOPT_BOOL(0, \"recursive\", &recursive, N_(\"Recurse into nested submodules\")),\n+\t\tOPT_END()\n+\t};\n+\n+\tconst char *const git_submodule_helper_usage[] = {\n+\t\tN_(\"git submodule status [--quiet] [--cached] [--recursive] [<path>]\"),\n+\t\tNULL\n+\t};\n+\n+\targc = parse_options(argc, argv, prefix, module_status_options,\n+\t\t\t     git_submodule_helper_usage, 0);\n+\n+\tif (module_list_compute(argc, argv, prefix, &pathspec, &list) < 0)\n+\t\treturn 1;\n+\n+\tinfo.prefix = prefix;\n+\tinfo.quiet = !!quiet;\n+\tinfo.recursive = !!recursive;\n+\tinfo.cached = !!cached;\n+\n+\tgitmodules_config();\n+\tfor_each_submodule_list(list, status_submodule, &info);\n+\n+\treturn 0;\n+}\n+\n static int module_name(int argc, const char **argv, const char *prefix)\n {\n \tconst struct submodule *sub;\n@@ -1312,6 +1463,7 @@ static struct cmd_struct commands[] = {\n \t{\"resolve-relative-url-test\", resolve_relative_url_test, 0},\n \t{\"print-name-rev\", print_name_rev, 0},\n \t{\"init\", module_init, SUPPORT_SUPER_PREFIX},\n+\t{\"status\", module_status, SUPPORT_SUPER_PREFIX},\n \t{\"remote-branch\", resolve_remote_submodule_branch, 0},\n \t{\"push-check\", push_check, 0},\n \t{\"absorb-git-dirs\", absorb_git_dirs, SUPPORT_SUPER_PREFIX},\ndiff --git a/git-submodule.sh b/git-submodule.sh\nindex e988167e0..51b057d82 100755\n--- a/git-submodule.sh\n+++ b/git-submodule.sh\n@@ -1005,54 +1005,7 @@ cmd_status()\n \t\tshift\n \tdone\n \n-\t{\n-\t\tgit submodule--helper list --prefix \"$wt_prefix\" \"$@\" ||\n-\t\techo \"#unmatched\" $?\n-\t} |\n-\twhile read -r mode sha1 stage sm_path\n-\tdo\n-\t\tdie_if_unmatched \"$mode\" \"$sha1\"\n-\t\tname=$(git submodule--helper name \"$sm_path\") || exit\n-\t\tdisplaypath=$(git submodule--helper relative-path \"$prefix$sm_path\" \"$wt_prefix\")\n-\t\tif test \"$stage\" = U\n-\t\tthen\n-\t\t\tsay \"U$sha1 $displaypath\"\n-\t\t\tcontinue\n-\t\tfi\n-\t\tif ! git submodule--helper is-active \"$sm_path\" ||\n-\t\t{\n-\t\t\t! test -d \"$sm_path\"/.git &&\n-\t\t\t! test -f \"$sm_path\"/.git\n-\t\t}\n-\t\tthen\n-\t\t\tsay \"-$sha1 $displaypath\"\n-\t\t\tcontinue;\n-\t\tfi\n-\t\tif git diff-files --ignore-submodules=dirty --quiet -- \"$sm_path\"\n-\t\tthen\n-\t\t\trevname=$(git submodule--helper print-name-rev \"$sm_path\" \"$sha1\")\n-\t\t\tsay \" $sha1 $displaypath$revname\"\n-\t\telse\n-\t\t\tif test -z \"$cached\"\n-\t\t\tthen\n-\t\t\t\tsha1=$(sanitize_submodule_env; cd \"$sm_path\" && git rev-parse --verify HEAD)\n-\t\t\tfi\n-\t\t\trevname=$(git submodule--helper print-name-rev \"$sm_path\" \"$sha1\")\n-\t\t\tsay \"+$sha1 $displaypath$revname\"\n-\t\tfi\n-\n-\t\tif test -n \"$recursive\"\n-\t\tthen\n-\t\t\t(\n-\t\t\t\tprefix=\"$displaypath/\"\n-\t\t\t\tsanitize_submodule_env\n-\t\t\t\twt_prefix=\n-\t\t\t\tcd \"$sm_path\" &&\n-\t\t\t\teval cmd_status\n-\t\t\t) ||\n-\t\t\tdie \"$(eval_gettext \"Failed to recurse into submodule path '\\$sm_path'\")\"\n-\t\tfi\n-\tdone\n+\tgit ${wt_prefix:+-C \"$wt_prefix\"} ${prefix:+--super-prefix \"$prefix\"} submodule--helper status ${GIT_QUIET:+--quiet} ${cached:+--cached} ${recursive:+--recursive} \"$@\"\n }\n #\n # Sync remote urls for submodules\n-- \n2.13.0\n\n"},{"id":"323602","messageId":"20170630194727.29787-3-pc44800@gmail.com","threadId":"46265","inReplyTo":"20170630194727.29787-1-pc44800@gmail.com","subject":"[GSoC][PATCH 3/5 v3] submodule: port set_name_rev() from shell to C","fromName":"Prathamesh Chavan","fromEmail":"pc44800@gmail.com","sentAt":"2017-06-30T19:47:25Z","receivedAt":"2017-06-30T19:49:48Z","isPatch":true,"sender":{"key":"pc44800@gmail.com","avatar":"https://avatars.githubusercontent.com/u/17272661?v=4"},"body":"Function set_name_rev() is ported from git-submodule to the\nsubmodule--helper builtin. The function get_name_rev() generates the\nvalue of the revision name as required, and the function\nprint_name_rev() handles the formating and printing of the obtained\nrevision name.\n\nMentored-by: Christian Couder <christian.couder@gmail.com>\nMentored-by: Stefan Beller <sbeller@google.com>\nSigned-off-by: Prathamesh Chavan <pc44800@gmail.com>\n---\n builtin/submodule--helper.c | 69 +++++++++++++++++++++++++++++++++++++++++++++\n git-submodule.sh            | 16 ++---------\n 2 files changed, 71 insertions(+), 14 deletions(-)\n\ndiff --git a/builtin/submodule--helper.c b/builtin/submodule--helper.c\nindex c4286aac5..4103e40e4 100644\n--- a/builtin/submodule--helper.c\n+++ b/builtin/submodule--helper.c\n@@ -244,6 +244,74 @@ static char *get_submodule_displaypath(const char *path, const char *prefix)\n \t}\n }\n \n+enum describe_step {\n+\tstep_bare,\n+\tstep_tags,\n+\tstep_contains,\n+\tstep_all_always,\n+\tstep_end\n+};\n+\n+static char *get_name_rev(const char *sub_path, const char* object_id)\n+{\n+\tstruct strbuf sb = STRBUF_INIT;\n+\tenum describe_step cur_step;\n+\n+\tfor (cur_step = step_bare; cur_step < step_end; cur_step++) {\n+\t\tstruct child_process cp = CHILD_PROCESS_INIT;\n+\t\tprepare_submodule_repo_env(&cp.env_array);\n+\t\tcp.dir = sub_path;\n+\t\tcp.git_cmd = 1;\n+\t\tcp.no_stderr = 1;\n+\n+\t\tswitch (cur_step) {\n+\t\t\tcase step_bare:\n+\t\t\t\targv_array_pushl(&cp.args, \"describe\",\n+\t\t\t\t\t\t object_id, NULL);\n+\t\t\t\tbreak;\n+\t\t\tcase step_tags:\t\n+\t\t\t\targv_array_pushl(&cp.args, \"describe\",\n+\t\t\t\t\t\t \"--tags\", object_id, NULL);\n+\t\t\t\tbreak;\n+\t\t\tcase step_contains:\n+\t\t\t\targv_array_pushl(&cp.args, \"describe\",\n+\t\t\t\t\t\t \"--contains\", object_id,\n+\t\t\t\t\t\t NULL);\n+\t\t\t\tbreak;\n+\t\t\tcase step_all_always:\n+\t\t\t\targv_array_pushl(&cp.args, \"describe\",\n+\t\t\t\t\t\t \"--all\", \"--always\",\n+\t\t\t\t\t\t object_id, NULL);\n+\t\t\t\tbreak;\n+\t\t\tdefault:\n+\t\t\t\tBUG(\"unknown describe step '%d'\", cur_step);\n+\t\t}\n+\n+\t\tif (!capture_command(&cp, &sb, 0) && sb.len) {\n+\t\t\tstrbuf_strip_suffix(&sb, \"\\n\");\n+\t\t\treturn strbuf_detach(&sb, NULL);\n+\t\t}\n+\n+\t}\n+\n+\tstrbuf_release(&sb);\n+\treturn NULL;\n+}\n+\n+static int print_name_rev(int argc, const char **argv, const char *prefix)\n+{\n+\tchar *namerev;\n+\tif (argc != 3)\n+\t\tdie(\"print-name-rev only accepts two arguments: <path> <sha1>\");\n+\n+\tnamerev = get_name_rev(argv[1], argv[2]);\n+\tif (namerev && namerev[0])\n+\t\tprintf(\" (%s)\", namerev);\n+\tprintf(\"\\n\");\n+\n+\treturn 0;\n+}\n+\n struct module_list {\n \tconst struct cache_entry **entries;\n \tint alloc, nr;\n@@ -1242,6 +1310,7 @@ static struct cmd_struct commands[] = {\n \t{\"relative-path\", resolve_relative_path, 0},\n \t{\"resolve-relative-url\", resolve_relative_url, 0},\n \t{\"resolve-relative-url-test\", resolve_relative_url_test, 0},\n+\t{\"print-name-rev\", print_name_rev, 0},\n \t{\"init\", module_init, SUPPORT_SUPER_PREFIX},\n \t{\"remote-branch\", resolve_remote_submodule_branch, 0},\n \t{\"push-check\", push_check, 0},\ndiff --git a/git-submodule.sh b/git-submodule.sh\nindex e131760ee..e988167e0 100755\n--- a/git-submodule.sh\n+++ b/git-submodule.sh\n@@ -759,18 +759,6 @@ cmd_update()\n \t}\n }\n \n-set_name_rev () {\n-\trevname=$( (\n-\t\tsanitize_submodule_env\n-\t\tcd \"$1\" && {\n-\t\t\tgit describe \"$2\" 2>/dev/null ||\n-\t\t\tgit describe --tags \"$2\" 2>/dev/null ||\n-\t\t\tgit describe --contains \"$2\" 2>/dev/null ||\n-\t\t\tgit describe --all --always \"$2\"\n-\t\t}\n-\t) )\n-\ttest -z \"$revname\" || revname=\" ($revname)\"\n-}\n #\n # Show commit summary for submodules in index or working tree\n #\n@@ -1042,14 +1030,14 @@ cmd_status()\n \t\tfi\n \t\tif git diff-files --ignore-submodules=dirty --quiet -- \"$sm_path\"\n \t\tthen\n-\t\t\tset_name_rev \"$sm_path\" \"$sha1\"\n+\t\t\trevname=$(git submodule--helper print-name-rev \"$sm_path\" \"$sha1\")\n \t\t\tsay \" $sha1 $displaypath$revname\"\n \t\telse\n \t\t\tif test -z \"$cached\"\n \t\t\tthen\n \t\t\t\tsha1=$(sanitize_submodule_env; cd \"$sm_path\" && git rev-parse --verify HEAD)\n \t\t\tfi\n-\t\t\tset_name_rev \"$sm_path\" \"$sha1\"\n+\t\t\trevname=$(git submodule--helper print-name-rev \"$sm_path\" \"$sha1\")\n \t\t\tsay \"+$sha1 $displaypath$revname\"\n \t\tfi\n \n-- \n2.13.0\n\n"},{"id":"323603","messageId":"20170630194727.29787-1-pc44800@gmail.com","threadId":"46265","inReplyTo":"CAME+mvUrr8EA-6jbCZdpB7dMZ5CN3RyY7yoRoUBoiZw=sH6Ysw@mail.gmail.com","subject":"[GSoC][PATCH 1/5 v3] submodule--helper: introduce get_submodule_displaypath()","fromName":"Prathamesh Chavan","fromEmail":"pc44800@gmail.com","sentAt":"2017-06-30T19:47:23Z","receivedAt":"2017-06-30T19:50:28Z","isPatch":true,"sender":{"key":"pc44800@gmail.com","avatar":"https://avatars.githubusercontent.com/u/17272661?v=4"},"body":"Introduce function get_submodule_displaypath() to replace the code\noccurring in submodule_init() for generating displaypath of the\nsubmodule with a call to it.\n\nThis new function will also be used in other parts of the system\nin later patches.\n\nMentored-by: Christian Couder <christian.couder@gmail.com>\nMentored-by: Stefan Beller <sbeller@google.com>\nSigned-off-by: Prathamesh Chavan <pc44800@gmail.com>\n---\nThe patch series is updated, and is based on 'master' branch.\n\nThis patch series contains updates patches about\nIntroduction of the function: get_submodule_displaypath()\n(This patch wasn't posted in the last update by mistake)\nIntroduction of the function: for_each_submodule()\nPort shell function set_name_rev() to C\nPort submodule subcommand 'status' from shell to C\nPort submodule subcommand 'sync' from shell to C\n\nComplete build report of this patch-series is available at:\nhttps://travis-ci.org/pratham-pc/git/builds\nBranch: patch-series-1\nBuild #114\n\nAlso, the above series was also build by basing it on the 'next'\nbranch for the purpose of testing the code.\nSince the function is_submodule_initialized changed to\nis_submodule_active, this change was required to be added in the\nabove patches while basing it on next.\nAfter doing the required changes,\nComplete build report of the above is available at:\nhttps://travis-ci.org/pratham-pc/git/builds\nBranch: patch-series-1-next\nBuild #116\n\nI have held back the following patch since some work is still\nrequired to be done:\nPort submodule subcommand 'foreach' from shell to C\nPort submodule subcommand 'deinit' from shell to C\nPort submodule subcommand 'summary' from shell to C\nI hope to complete this and post these patches later with the\nweekly updates.\n\n builtin/submodule--helper.c | 33 ++++++++++++++++++++++-----------\n 1 file changed, 22 insertions(+), 11 deletions(-)\n\ndiff --git a/builtin/submodule--helper.c b/builtin/submodule--helper.c\nindex 8517032b3..1bfc91bca 100644\n--- a/builtin/submodule--helper.c\n+++ b/builtin/submodule--helper.c\n@@ -220,6 +220,27 @@ static int resolve_relative_url_test(int argc, const char **argv, const char *pr\n \treturn 0;\n }\n \n+static char *get_submodule_displaypath(const char *path, const char *prefix)\n+{\n+\tconst char *super_prefix = get_super_prefix();\n+\n+\tif (prefix && super_prefix) {\n+\t\tBUG(\"cannot have prefix '%s' and superprefix '%s'\",\n+\t\t    prefix, super_prefix);\n+\t} else if (prefix) {\n+\t\tstruct strbuf sb = STRBUF_INIT;\n+\t\tchar *displaypath = xstrdup(relative_path(path, prefix, &sb));\n+\t\tstrbuf_release(&sb);\n+\t\treturn displaypath;\n+\t} else if (super_prefix) {\n+\t\tint len = strlen(super_prefix);\n+\t\tconst char *format = is_dir_sep(super_prefix[len - 1]) ? \"%s%s\" : \"%s/%s\";\n+\t\treturn xstrfmt(format, super_prefix, path);\n+\t} else {\n+\t\treturn xstrdup(path);\n+\t}\n+}\n+\n struct module_list {\n \tconst struct cache_entry **entries;\n \tint alloc, nr;\n@@ -339,16 +360,7 @@ static void init_submodule(const char *path, const char *prefix, int quiet)\n \n \t/* Only loads from .gitmodules, no overlay with .git/config */\n \tgitmodules_config();\n-\n-\tif (prefix && get_super_prefix())\n-\t\tdie(\"BUG: cannot have prefix and superprefix\");\n-\telse if (prefix)\n-\t\tdisplaypath = xstrdup(relative_path(path, prefix, &sb));\n-\telse if (get_super_prefix()) {\n-\t\tstrbuf_addf(&sb, \"%s%s\", get_super_prefix(), path);\n-\t\tdisplaypath = strbuf_detach(&sb, NULL);\n-\t} else\n-\t\tdisplaypath = xstrdup(path);\n+\tdisplaypath = get_submodule_displaypath(path, prefix);\n \n \tsub = submodule_from_path(null_sha1, path);\n \n@@ -363,7 +375,6 @@ static void init_submodule(const char *path, const char *prefix, int quiet)\n \t * Set active flag for the submodule being initialized\n \t */\n \tif (!is_submodule_initialized(path)) {\n-\t\tstrbuf_reset(&sb);\n \t\tstrbuf_addf(&sb, \"submodule.%s.active\", sub->name);\n \t\tgit_config_set_gently(sb.buf, \"true\");\n \t}\n-- \n2.13.0\n\n"},{"id":"323605","messageId":"CAGZ79kbiKd1GB8Gsyo8ABG1RBzhpXYrsySxcC6XRZv88Xx94Qw@mail.gmail.com","threadId":"46265","inReplyTo":"20170630194727.29787-5-pc44800@gmail.com","subject":"Re: [GSoC][PATCH 5/5 v3] submodule: port submodule subcommand 'sync' from shell to C","fromName":"Stefan Beller","fromEmail":"sbeller@google.com","sentAt":"2017-06-30T20:11:19Z","receivedAt":"2017-06-30T20:11:25Z","isPatch":true,"sender":{"key":"stefanbeller@gmail.com","avatar":"https://avatars.githubusercontent.com/u/455868?v=4"},"body":"On Fri, Jun 30, 2017 at 12:47 PM, Prathamesh Chavan <pc44800@gmail.com> wrote:\n> Port the submodule subcommand 'sync' from shell to C using the same\n> mechanism as that used for porting submodule subcommand 'status'.\n> Hence, here the function cmd_sync() is ported from shell to C.\n> This is done by introducing three functions: module_sync(),\n> sync_submodule() and print_default_remote().\n>\n> The function print_default_remote() is introduced for getting\n> the default remote as stdout.\n>\n> Mentored-by: Christian Couder <christian.couder@gmail.com>\n> Mentored-by: Stefan Beller <sbeller@google.com>\n> Signed-off-by: Prathamesh Chavan <pc44800@gmail.com>\n> ---\n\nAll these patches are also\nReviewed-by: Stefan Beller <sbeller@google.com>\n\nThanks for upstreaming the early parts.\n\nThanks,\nStefan\n"},{"id":"323651","messageId":"xmqqfuehp0e4.fsf@gitster.mtv.corp.google.com","threadId":"46265","inReplyTo":"20170630194727.29787-1-pc44800@gmail.com","subject":"Re: [GSoC][PATCH 1/5 v3] submodule--helper: introduce get_submodule_displaypath()","fromName":"Junio C Hamano","fromEmail":"gitster@pobox.com","sentAt":"2017-06-30T22:37:55Z","receivedAt":"2017-06-30T22:38:12Z","isPatch":true,"sender":{"key":"gitster@pobox.com","avatar":"https://avatars.githubusercontent.com/u/54884?v=4"},"body":"Prathamesh Chavan <pc44800@gmail.com> writes:\n\n> Introduce function get_submodule_displaypath() to replace the code\n> occurring in submodule_init() for generating displaypath of the\n> submodule with a call to it.\n>\n> This new function will also be used in other parts of the system\n> in later patches.\n>\n> Mentored-by: Christian Couder <christian.couder@gmail.com>\n> Mentored-by: Stefan Beller <sbeller@google.com>\n> Signed-off-by: Prathamesh Chavan <pc44800@gmail.com>\n> ---\n> The patch series is updated, and is based on 'master' branch.\n>\n> This patch series contains updates patches about\n> Introduction of the function: get_submodule_displaypath()\n> (This patch wasn't posted in the last update by mistake)\n\nI was wondering what that thing was while reading the previous\nround.  Good that it now appears in this round of the series ;-)\n\nThanks.\n\n\n"},{"id":"323653","messageId":"xmqqbmp5ozv0.fsf@gitster.mtv.corp.google.com","threadId":"46265","inReplyTo":"20170630194727.29787-3-pc44800@gmail.com","subject":"Re: [GSoC][PATCH 3/5 v3] submodule: port set_name_rev() from shell to C","fromName":"Junio C Hamano","fromEmail":"gitster@pobox.com","sentAt":"2017-06-30T22:49:23Z","receivedAt":"2017-06-30T22:49:30Z","isPatch":true,"sender":{"key":"gitster@pobox.com","avatar":"https://avatars.githubusercontent.com/u/54884?v=4"},"body":"Prathamesh Chavan <pc44800@gmail.com> writes:\n\n> Function set_name_rev() is ported from git-submodule to the\n> submodule--helper builtin. The function get_name_rev() generates the\n> value of the revision name as required, and the function\n> print_name_rev() handles the formating and printing of the obtained\n> revision name.\n>\n> Mentored-by: Christian Couder <christian.couder@gmail.com>\n> Mentored-by: Stefan Beller <sbeller@google.com>\n> Signed-off-by: Prathamesh Chavan <pc44800@gmail.com>\n> ---\n>  builtin/submodule--helper.c | 69 +++++++++++++++++++++++++++++++++++++++++++++\n>  git-submodule.sh            | 16 ++---------\n>  2 files changed, 71 insertions(+), 14 deletions(-)\n>\n> diff --git a/builtin/submodule--helper.c b/builtin/submodule--helper.c\n> index c4286aac5..4103e40e4 100644\n> --- a/builtin/submodule--helper.c\n> +++ b/builtin/submodule--helper.c\n> @@ -244,6 +244,74 @@ static char *get_submodule_displaypath(const char *path, const char *prefix)\n>  \t}\n>  }\n>  \n> +enum describe_step {\n> +\tstep_bare,\n> +\tstep_tags,\n> +\tstep_contains,\n> +\tstep_all_always,\n> +\tstep_end\n> +};\n\nHmph.\n\nThe only difference between the steps being what subcommand is run,\na better implementation might be to do\n\n\tstatic const char *describe_bare[] = {\n\t\tNULL\n\t};\n\n\t...\n\n\tstatic const char **describe_argv[] = {\n\t\tdescribe_bare, describe_tags, describe_contains, \n                describe_all_always, NULL\n\t};\n\n\tconst char ***d;\n\n\tfor (d = describe_argv; *d; d++) {\n\t\targv_array_pushl(&cp.args, \"describe\");\n\t\targv_array_pushv(&cp.args, *d);\n\t\t... do the thing ...\n\t}\n\nbut unfortunately C is a bit klunky to do so; we cannot easily make\nthe contents of describe_argv[] as anonymous arrays.  An otherwise\nuseless enum stil bothers me, but I do not think of anything better\noffhand.\n\n> +\n> +static char *get_name_rev(const char *sub_path, const char* object_id)\n> +{\n> +\tstruct strbuf sb = STRBUF_INIT;\n> +\tenum describe_step cur_step;\n> +\n> +\tfor (cur_step = step_bare; cur_step < step_end; cur_step++) {\n> +\t\tstruct child_process cp = CHILD_PROCESS_INIT;\n> +\t\tprepare_submodule_repo_env(&cp.env_array);\n> +\t\tcp.dir = sub_path;\n> +\t\tcp.git_cmd = 1;\n> +\t\tcp.no_stderr = 1;\n> +\n> +\t\tswitch (cur_step) {\n> +\t\t\tcase step_bare:\n> +\t\t\t\targv_array_pushl(&cp.args, \"describe\",\n> +\t\t\t\t\t\t object_id, NULL);\n> +\t\t\t\tbreak;\n> +\t\t\tcase step_tags:\t\n> +\t\t\t\targv_array_pushl(&cp.args, \"describe\",\n> +\t\t\t\t\t\t \"--tags\", object_id, NULL);\n> +\t\t\t\tbreak;\n> +\t\t\tcase step_contains:\n> +\t\t\t\targv_array_pushl(&cp.args, \"describe\",\n> +\t\t\t\t\t\t \"--contains\", object_id,\n> +\t\t\t\t\t\t NULL);\n> +\t\t\t\tbreak;\n> +\t\t\tcase step_all_always:\n> +\t\t\t\targv_array_pushl(&cp.args, \"describe\",\n> +\t\t\t\t\t\t \"--all\", \"--always\",\n> +\t\t\t\t\t\t object_id, NULL);\n> +\t\t\t\tbreak;\n> +\t\t\tdefault:\n> +\t\t\t\tBUG(\"unknown describe step '%d'\", cur_step);\n> +\t\t}\n\nDedent the body of switch() by one level, i.e.\n\n\tswitch (var) {\n\tcase val1:\n\t\tdo_this();\n\t\tbreak;\n\tcase val2:\n\t\tdo_that();\n\t\t...\n\t}\n\nOtherwise looking good.\n\n> @@ -1042,14 +1030,14 @@ cmd_status()\n>  \t\tfi\n>  \t\tif git diff-files --ignore-submodules=dirty --quiet -- \"$sm_path\"\n>  \t\tthen\n> -\t\t\tset_name_rev \"$sm_path\" \"$sha1\"\n> +\t\t\trevname=$(git submodule--helper print-name-rev \"$sm_path\" \"$sha1\")\n>  \t\t\tsay \" $sha1 $displaypath$revname\"\n>  \t\telse\n>  \t\t\tif test -z \"$cached\"\n>  \t\t\tthen\n>  \t\t\t\tsha1=$(sanitize_submodule_env; cd \"$sm_path\" && git rev-parse --verify HEAD)\n>  \t\t\tfi\n> -\t\t\tset_name_rev \"$sm_path\" \"$sha1\"\n> +\t\t\trevname=$(git submodule--helper print-name-rev \"$sm_path\" \"$sha1\")\n>  \t\t\tsay \"+$sha1 $displaypath$revname\"\n>  \t\tfi\n"},{"id":"323654","messageId":"xmqq60fdoyyt.fsf@gitster.mtv.corp.google.com","threadId":"46265","inReplyTo":"20170630194727.29787-4-pc44800@gmail.com","subject":"Re: [GSoC][PATCH 4/5 v3] submodule: port submodule subcommand 'status' from shell to C","fromName":"Junio C Hamano","fromEmail":"gitster@pobox.com","sentAt":"2017-06-30T23:08:42Z","receivedAt":"2017-06-30T23:08:50Z","isPatch":true,"sender":{"key":"gitster@pobox.com","avatar":"https://avatars.githubusercontent.com/u/54884?v=4"},"body":"Prathamesh Chavan <pc44800@gmail.com> writes:\n\n> +\targv_array_pushl(&diff_files_args, \"diff-files\",\n> +\t\t\t \"--ignore-submodules=dirty\", \"--quiet\", \"--\",\n> +\t\t\t list_item->name, NULL);\n> +\n> +\tif (!cmd_diff_files(diff_files_args.argc, diff_files_args.argv,\n> +\t\t\t    info->prefix)) {\n\nEssentially we'd only want to run ce_match_stat() on list_item and\nthe current on-filesystem submodule.  We not just know which path we\nare interested in, but we already have the cache entry for it, so it\nfeels quite wasteful to go over the_index.cache[] once again to find\nthe cache entry that matches list_item->name.  Yes, that is how the\nscripted Porcelain did it, but it feels way overkill now we have\nready access to the lower level machinery.\n\nHaving said all that, I think it is a good idea to stick to a\nfaithful conversion in this series.  I just think a NEEDSWORK\ncomment may be a good idea to indicate future optimization\nopportunities.\n\nA similar optimization is already happening in this patch, actually.\nInstead of doing a stat of \"$sm_path/.git\" and checking test -d/-f,\nthe code just calls is_submodule_initialized().  Which is good ;-)\n\n> +\t} else {\n> +\t\tif (!info->cached) {\n> +\t\t\tstruct child_process cp = CHILD_PROCESS_INIT;\n> +\t\t\tstruct strbuf sb = STRBUF_INIT;\n> +\n> +\t\t\tprepare_submodule_repo_env(&cp.env_array);\n> +\t\t\tcp.git_cmd = 1;\n> +\t\t\tcp.dir = list_item->name;\n> +\n> +\t\t\targv_array_pushl(&cp.args, \"rev-parse\",\n> +\t\t\t\t\t \"--verify\", \"HEAD\", NULL);\n> +\n> +\t\t\tif (capture_command(&cp, &sb, 0))\n> +\t\t\t\tdie(_(\"could not run 'git rev-parse --verify\"\n> +\t\t\t\t      \"HEAD' in submodule %s\"),\n> +\t\t\t\t      list_item->name);\n> +\n> +\t\t\tstrbuf_strip_suffix(&sb, \"\\n\");\n\nLikewise.  This is merely resolving a ref inside a submodule;\ncalling something like head_ref_submodule() may be sufficient\nas an optimization and at least deserves to be mentioned in a\nNEEDSWORK comment.\n\n> +\t\t\tprint_status(info, '+', list_item->name, sb.buf,\n> +\t\t\t\t     displaypath);\n> +\t\t\tstrbuf_release(&sb);\n> +\t\t} else {\n> +\t\t\tprint_status(info, '+', list_item->name, sub_sha1,\n> +\t\t\t\t     displaypath);\n> +\t\t}\n> +\t}\n"},{"id":"323655","messageId":"xmqq1sq1oygj.fsf@gitster.mtv.corp.google.com","threadId":"46265","inReplyTo":"20170630194727.29787-5-pc44800@gmail.com","subject":"Re: [GSoC][PATCH 5/5 v3] submodule: port submodule subcommand 'sync' from shell to C","fromName":"Junio C Hamano","fromEmail":"gitster@pobox.com","sentAt":"2017-06-30T23:19:40Z","receivedAt":"2017-06-30T23:19:55Z","isPatch":true,"sender":{"key":"gitster@pobox.com","avatar":"https://avatars.githubusercontent.com/u/54884?v=4"},"body":"Prathamesh Chavan <pc44800@gmail.com> writes:\n\n> +static void sync_submodule(const struct cache_entry *list_item, void *cb_data)\n> +{\n> +\tstruct sync_cb *info = cb_data;\n> +\tconst struct submodule *sub;\n> +\tchar *sub_key, *remote_key;\n> +\tchar *sub_origin_url, *super_config_url, *displaypath;\n> +\tstruct strbuf sb = STRBUF_INIT;\n> +\tstruct child_process cp = CHILD_PROCESS_INIT;\n> +\n> +\tif (!is_submodule_initialized(list_item->name))\n> +\t\treturn;\n> +\n> +\tsub = submodule_from_path(null_sha1, list_item->name);\n> +\n> +\tif (!sub || !sub->url)\n> +\t\tdie(_(\"no url found for submodule path '%s' in .gitmodules\"),\n> +\t\t      list_item->name);\n> +\n> +\tif (starts_with_dot_dot_slash(sub->url) || starts_with_dot_slash(sub->url)) {\n> +\t\tchar *remote_url, *up_path;\n> +\t\tchar *remote = get_default_remote();\n> +\t\tchar *remote_key = xstrfmt(\"remote.%s.url\", remote);\n> +\t\tfree(remote);\n> +\n\nHave a blank line between the decls and the first statement\n(i.e. before \"free(remote)\").  The blank line after \"free(remote)\"\nmay or may not be there.\n\n> +\t\tif (git_config_get_string(remote_key, &remote_url))\n> +\t\t\tremote_url = xgetcwd();\n> +...\n> +\n> +\tprepare_submodule_repo_env(&cp.env_array);\n> +\tcp.git_cmd = 1;\n> +\tcp.dir = list_item->name;\n> +\targv_array_pushl(&cp.args, \"submodule--helper\",\n> +\t\t\t \"print-default-remote\", NULL);\n> +\tif (capture_command(&cp, &sb, 0))\n> +\t\tdie(_(\"failed to get the default remote for submodule '%s'\"),\n> +\t\t      list_item->name);\n\nOK.  Perhaps in a distant future when the repository object\nabstraction is ready, we can do this within the main process, but\nfor now, due to the presence of cp.dir, this is the best we can do.\n\n> +\tstrbuf_strip_suffix(&sb, \"\\n\");\n> +\tremote_key = xstrfmt(\"remote.%s.url\", sb.buf);\n> +\tstrbuf_release(&sb);\n> +\n> +\tchild_process_init(&cp);\n> +\tprepare_submodule_repo_env(&cp.env_array);\n> +\tcp.git_cmd = 1;\n> +\tcp.dir = list_item->name;\n> +\targv_array_pushl(&cp.args, \"config\", remote_key, sub_origin_url, NULL);\n> +\tif (run_command(&cp))\n> +\t\tdie(_(\"failed to update remote for submodule '%s'\"),\n> +\t\t      list_item->name);\n\nLikewise.\n\nLooks like a fairly faithful conversion to me.\n\nThanks.\n"},{"id":"324431","messageId":"20170713200538.25806-1-pc44800@gmail.com","threadId":"46265","inReplyTo":"20170630194727.29787-1-pc44800@gmail.com","subject":"[GSoC][PATCH 1/5 v4] submodule--helper: introduce get_submodule_displaypath()","fromName":"Prathamesh Chavan","fromEmail":"pc44800@gmail.com","sentAt":"2017-07-13T20:05:34Z","receivedAt":"2017-07-13T20:05:57Z","isPatch":true,"sender":{"key":"pc44800@gmail.com","avatar":"https://avatars.githubusercontent.com/u/17272661?v=4"},"body":"Introduce function get_submodule_displaypath() to replace the code\noccurring in submodule_init() for generating displaypath of the\nsubmodule with a call to it.\n\nThis new function will also be used in other parts of the system\nin later patches.\n\nMentored-by: Christian Couder <christian.couder@gmail.com>\nMentored-by: Stefan Beller <sbeller@google.com>\nSigned-off-by: Prathamesh Chavan <pc44800@gmail.com>\n---\n builtin/submodule--helper.c | 33 ++++++++++++++++++++++-----------\n 1 file changed, 22 insertions(+), 11 deletions(-)\n\ndiff --git a/builtin/submodule--helper.c b/builtin/submodule--helper.c\nindex 6abdad329..7af4de09b 100644\n--- a/builtin/submodule--helper.c\n+++ b/builtin/submodule--helper.c\n@@ -220,6 +220,27 @@ static int resolve_relative_url_test(int argc, const char **argv, const char *pr\n \treturn 0;\n }\n \n+static char *get_submodule_displaypath(const char *path, const char *prefix)\n+{\n+\tconst char *super_prefix = get_super_prefix();\n+\n+\tif (prefix && super_prefix) {\n+\t\tBUG(\"cannot have prefix '%s' and superprefix '%s'\",\n+\t\t    prefix, super_prefix);\n+\t} else if (prefix) {\n+\t\tstruct strbuf sb = STRBUF_INIT;\n+\t\tchar *displaypath = xstrdup(relative_path(path, prefix, &sb));\n+\t\tstrbuf_release(&sb);\n+\t\treturn displaypath;\n+\t} else if (super_prefix) {\n+\t\tint len = strlen(super_prefix);\n+\t\tconst char *format = is_dir_sep(super_prefix[len - 1]) ? \"%s%s\" : \"%s/%s\";\n+\t\treturn xstrfmt(format, super_prefix, path);\n+\t} else {\n+\t\treturn xstrdup(path);\n+\t}\n+}\n+\n struct module_list {\n \tconst struct cache_entry **entries;\n \tint alloc, nr;\n@@ -339,16 +360,7 @@ static void init_submodule(const char *path, const char *prefix, int quiet)\n \n \t/* Only loads from .gitmodules, no overlay with .git/config */\n \tgitmodules_config();\n-\n-\tif (prefix && get_super_prefix())\n-\t\tdie(\"BUG: cannot have prefix and superprefix\");\n-\telse if (prefix)\n-\t\tdisplaypath = xstrdup(relative_path(path, prefix, &sb));\n-\telse if (get_super_prefix()) {\n-\t\tstrbuf_addf(&sb, \"%s%s\", get_super_prefix(), path);\n-\t\tdisplaypath = strbuf_detach(&sb, NULL);\n-\t} else\n-\t\tdisplaypath = xstrdup(path);\n+\tdisplaypath = get_submodule_displaypath(path, prefix);\n \n \tsub = submodule_from_path(null_sha1, path);\n \n@@ -363,7 +375,6 @@ static void init_submodule(const char *path, const char *prefix, int quiet)\n \t * Set active flag for the submodule being initialized\n \t */\n \tif (!is_submodule_active(the_repository, path)) {\n-\t\tstrbuf_reset(&sb);\n \t\tstrbuf_addf(&sb, \"submodule.%s.active\", sub->name);\n \t\tgit_config_set_gently(sb.buf, \"true\");\n \t}\n-- \n2.13.0\n\n"},{"id":"324432","messageId":"20170713200538.25806-2-pc44800@gmail.com","threadId":"46265","inReplyTo":"20170713200538.25806-1-pc44800@gmail.com","subject":"[GSoC][PATCH 2/5 v4] submodule--helper: introduce for_each_submodule_list()","fromName":"Prathamesh Chavan","fromEmail":"pc44800@gmail.com","sentAt":"2017-07-13T20:05:35Z","receivedAt":"2017-07-13T20:06:11Z","isPatch":true,"sender":{"key":"pc44800@gmail.com","avatar":"https://avatars.githubusercontent.com/u/17272661?v=4"},"body":"Introduce function for_each_submodule_list() and\nreplace a loop in module_init() with a call to it.\n\nThe new function will also be used in other parts of the\nsystem in later patches.\n\nMentored-by: Christian Couder <christian.couder@gmail.com>\nMentored-by: Stefan Beller <sbeller@google.com>\nSigned-off-by: Prathamesh Chavan <pc44800@gmail.com>\n---\n builtin/submodule--helper.c | 39 +++++++++++++++++++++++++++++----------\n 1 file changed, 29 insertions(+), 10 deletions(-)\n\ndiff --git a/builtin/submodule--helper.c b/builtin/submodule--helper.c\nindex 7af4de09b..e41572f7a 100644\n--- a/builtin/submodule--helper.c\n+++ b/builtin/submodule--helper.c\n@@ -14,6 +14,9 @@\n #include \"refs.h\"\n #include \"connect.h\"\n \n+typedef void (*submodule_list_func_t)(const struct cache_entry *list_item,\n+\t\t\t\t      void *cb_data);\n+\n static char *get_default_remote(void)\n {\n \tchar *dest = NULL, *ret;\n@@ -352,17 +355,30 @@ static int module_list(int argc, const char **argv, const char *prefix)\n \treturn 0;\n }\n \n-static void init_submodule(const char *path, const char *prefix, int quiet)\n+static void for_each_submodule_list(const struct module_list list,\n+\t\t\t\t    submodule_list_func_t fn, void *cb_data)\n {\n+\tint i;\n+\tfor (i = 0; i < list.nr; i++)\n+\t\tfn(list.entries[i], cb_data);\n+}\n+\n+struct init_cb {\n+\tconst char *prefix;\n+\tunsigned int quiet: 1;\n+};\n+#define INIT_CB_INIT { NULL, 0 }\n+\n+static void init_submodule(const struct cache_entry *list_item, void *cb_data)\n+{\n+\tstruct init_cb *info = cb_data;\n \tconst struct submodule *sub;\n \tstruct strbuf sb = STRBUF_INIT;\n \tchar *upd = NULL, *url = NULL, *displaypath;\n \n-\t/* Only loads from .gitmodules, no overlay with .git/config */\n-\tgitmodules_config();\n-\tdisplaypath = get_submodule_displaypath(path, prefix);\n+\tdisplaypath = get_submodule_displaypath(list_item->name, info->prefix);\n \n-\tsub = submodule_from_path(null_sha1, path);\n+\tsub = submodule_from_path(null_sha1, list_item->name);\n \n \tif (!sub)\n \t\tdie(_(\"No url found for submodule path '%s' in .gitmodules\"),\n@@ -374,7 +390,7 @@ static void init_submodule(const char *path, const char *prefix, int quiet)\n \t *\n \t * Set active flag for the submodule being initialized\n \t */\n-\tif (!is_submodule_active(the_repository, path)) {\n+\tif (!is_submodule_active(the_repository, list_item->name)) {\n \t\tstrbuf_addf(&sb, \"submodule.%s.active\", sub->name);\n \t\tgit_config_set_gently(sb.buf, \"true\");\n \t}\n@@ -416,7 +432,7 @@ static void init_submodule(const char *path, const char *prefix, int quiet)\n \t\tif (git_config_set_gently(sb.buf, url))\n \t\t\tdie(_(\"Failed to register url for submodule path '%s'\"),\n \t\t\t    displaypath);\n-\t\tif (!quiet)\n+\t\tif (!info->quiet)\n \t\t\tfprintf(stderr,\n \t\t\t\t_(\"Submodule '%s' (%s) registered for path '%s'\\n\"),\n \t\t\t\tsub->name, url, displaypath);\n@@ -445,10 +461,10 @@ static void init_submodule(const char *path, const char *prefix, int quiet)\n \n static int module_init(int argc, const char **argv, const char *prefix)\n {\n+\tstruct init_cb info = INIT_CB_INIT;\n \tstruct pathspec pathspec;\n \tstruct module_list list = MODULE_LIST_INIT;\n \tint quiet = 0;\n-\tint i;\n \n \tstruct option module_init_options[] = {\n \t\tOPT__QUIET(&quiet, N_(\"Suppress output for initializing a submodule\")),\n@@ -473,8 +489,11 @@ static int module_init(int argc, const char **argv, const char *prefix)\n \tif (!argc && git_config_get_value_multi(\"submodule.active\"))\n \t\tmodule_list_active(&list);\n \n-\tfor (i = 0; i < list.nr; i++)\n-\t\tinit_submodule(list.entries[i]->name, prefix, quiet);\n+\tinfo.prefix = prefix;\n+\tinfo.quiet = !!quiet;\n+\n+\tgitmodules_config();\n+\tfor_each_submodule_list(list, init_submodule, &info);\n \n \treturn 0;\n }\n-- \n2.13.0\n\n"},{"id":"324433","messageId":"20170713200538.25806-3-pc44800@gmail.com","threadId":"46265","inReplyTo":"20170713200538.25806-1-pc44800@gmail.com","subject":"[GSoC][PATCH 3/5 v4] submodule: port set_name_rev() from shell to C","fromName":"Prathamesh Chavan","fromEmail":"pc44800@gmail.com","sentAt":"2017-07-13T20:05:36Z","receivedAt":"2017-07-13T20:06:12Z","isPatch":true,"sender":{"key":"pc44800@gmail.com","avatar":"https://avatars.githubusercontent.com/u/17272661?v=4"},"body":"Function set_name_rev() is ported from git-submodule to the\nsubmodule--helper builtin. The function get_name_rev() generates the\nvalue of the revision name as required, and the function\nprint_name_rev() handles the formating and printing of the obtained\nrevision name.\n\nMentored-by: Christian Couder <christian.couder@gmail.com>\nMentored-by: Stefan Beller <sbeller@google.com>\nSigned-off-by: Prathamesh Chavan <pc44800@gmail.com>\n---\n builtin/submodule--helper.c | 63 +++++++++++++++++++++++++++++++++++++++++++++\n git-submodule.sh            | 16 ++----------\n 2 files changed, 65 insertions(+), 14 deletions(-)\n\ndiff --git a/builtin/submodule--helper.c b/builtin/submodule--helper.c\nindex e41572f7a..80f744407 100644\n--- a/builtin/submodule--helper.c\n+++ b/builtin/submodule--helper.c\n@@ -244,6 +244,68 @@ static char *get_submodule_displaypath(const char *path, const char *prefix)\n \t}\n }\n \n+static char *get_name_rev(const char *sub_path, const char* object_id)\n+{\n+\tstruct strbuf sb = STRBUF_INIT;\n+\tconst char ***d;\n+\n+\tstatic const char *describe_bare[] = {\n+\t\tNULL\n+\t};\n+\n+\tstatic const char *describe_tags[] = {\n+\t\t\"--tags\", NULL\n+\t};\n+\n+\tstatic const char *describe_contains[] = {\n+\t\t\"--contains\", NULL\n+\t};\n+\n+\tstatic const char *describe_all_always[] = {\n+\t\t\"--all\", \"--always\", NULL\n+\t};\n+\n+\tstatic const char **describe_argv[] = {\n+\t\tdescribe_bare, describe_tags, describe_contains,\n+\t\tdescribe_all_always, NULL\n+\t};\n+\n+\tfor (d = describe_argv; *d; d++) {\n+\t\tstruct child_process cp = CHILD_PROCESS_INIT;\n+\t\tprepare_submodule_repo_env(&cp.env_array);\n+\t\tcp.dir = sub_path;\n+\t\tcp.git_cmd = 1;\n+\t\tcp.no_stderr = 1;\n+\n+\t\targv_array_push(&cp.args, \"describe\");\n+\t\targv_array_pushv(&cp.args, *d);\n+\t\targv_array_push(&cp.args, object_id);\n+\n+\t\tif (!capture_command(&cp, &sb, 0) && sb.len) {\n+\t\t\tstrbuf_strip_suffix(&sb, \"\\n\");\n+\t\t\treturn strbuf_detach(&sb, NULL);\n+\t\t}\n+\n+\t}\n+\n+\tstrbuf_release(&sb);\n+\treturn NULL;\n+}\n+\n+static int print_name_rev(int argc, const char **argv, const char *prefix)\n+{\n+\tchar *namerev;\n+\tif (argc != 3)\n+\t\tdie(\"print-name-rev only accepts two arguments: <path> <sha1>\");\n+\n+\tnamerev = get_name_rev(argv[1], argv[2]);\n+\tif (namerev && namerev[0])\n+\t\tprintf(\" (%s)\", namerev);\n+\tprintf(\"\\n\");\n+\n+\treturn 0;\n+}\n+\n struct module_list {\n \tconst struct cache_entry **entries;\n \tint alloc, nr;\n@@ -1242,6 +1304,7 @@ static struct cmd_struct commands[] = {\n \t{\"relative-path\", resolve_relative_path, 0},\n \t{\"resolve-relative-url\", resolve_relative_url, 0},\n \t{\"resolve-relative-url-test\", resolve_relative_url_test, 0},\n+\t{\"print-name-rev\", print_name_rev, 0},\n \t{\"init\", module_init, SUPPORT_SUPER_PREFIX},\n \t{\"remote-branch\", resolve_remote_submodule_branch, 0},\n \t{\"push-check\", push_check, 0},\ndiff --git a/git-submodule.sh b/git-submodule.sh\nindex e131760ee..e988167e0 100755\n--- a/git-submodule.sh\n+++ b/git-submodule.sh\n@@ -759,18 +759,6 @@ cmd_update()\n \t}\n }\n \n-set_name_rev () {\n-\trevname=$( (\n-\t\tsanitize_submodule_env\n-\t\tcd \"$1\" && {\n-\t\t\tgit describe \"$2\" 2>/dev/null ||\n-\t\t\tgit describe --tags \"$2\" 2>/dev/null ||\n-\t\t\tgit describe --contains \"$2\" 2>/dev/null ||\n-\t\t\tgit describe --all --always \"$2\"\n-\t\t}\n-\t) )\n-\ttest -z \"$revname\" || revname=\" ($revname)\"\n-}\n #\n # Show commit summary for submodules in index or working tree\n #\n@@ -1042,14 +1030,14 @@ cmd_status()\n \t\tfi\n \t\tif git diff-files --ignore-submodules=dirty --quiet -- \"$sm_path\"\n \t\tthen\n-\t\t\tset_name_rev \"$sm_path\" \"$sha1\"\n+\t\t\trevname=$(git submodule--helper print-name-rev \"$sm_path\" \"$sha1\")\n \t\t\tsay \" $sha1 $displaypath$revname\"\n \t\telse\n \t\t\tif test -z \"$cached\"\n \t\t\tthen\n \t\t\t\tsha1=$(sanitize_submodule_env; cd \"$sm_path\" && git rev-parse --verify HEAD)\n \t\t\tfi\n-\t\t\tset_name_rev \"$sm_path\" \"$sha1\"\n+\t\t\trevname=$(git submodule--helper print-name-rev \"$sm_path\" \"$sha1\")\n \t\t\tsay \"+$sha1 $displaypath$revname\"\n \t\tfi\n \n-- \n2.13.0\n\n"},{"id":"324434","messageId":"20170713200538.25806-4-pc44800@gmail.com","threadId":"46265","inReplyTo":"20170713200538.25806-1-pc44800@gmail.com","subject":"[GSoC][PATCH 4/5 v4] submodule: port submodule subcommand 'status' from shell to C","fromName":"Prathamesh Chavan","fromEmail":"pc44800@gmail.com","sentAt":"2017-07-13T20:05:37Z","receivedAt":"2017-07-13T20:06:15Z","isPatch":true,"sender":{"key":"pc44800@gmail.com","avatar":"https://avatars.githubusercontent.com/u/17272661?v=4"},"body":"This aims to make git-submodule 'status' a built-in. Hence, the function\ncmd_status() is ported from shell to C. This is done by introducing\nthree functions: module_status(), submodule_status() and print_status().\n\nThe function module_status() acts as the front-end of the subcommand.\nIt parses subcommand's options and then calls the function\nmodule_list_compute() for computing the list of submodules. Then\nthis functions calls for_each_submodule_list() looping through the\nlist obtained.\n\nThen for_each_submodule_list() calls submodule_status() for each of the\nsubmodule in its list. The function submodule_status() is responsible\nfor generating the status each submodule it is called for, and\nthen calls print_status().\n\nFinally, the function print_status() handles the printing of submodule's\nstatus.\n\nMentored-by: Christian Couder <christian.couder@gmail.com>\nMentored-by: Stefan Beller <sbeller@google.com>\nSigned-off-by: Prathamesh Chavan <pc44800@gmail.com>\n---\nIn this new version of patch:\n\nInstead of using cmd_diff_files(), the process is optimized\nby using ce_match_stat().\n\nAlso, the child_process running the command 'rev-parse --verify HEAD'\nis removed for optimization reasons, and instead head_ref_submodule()\nis used with callback function handle_submodule_head_ref().\n\nThe series differs from the complete weekly-update series as these patches\nhave been reviewed with mentors as well as on mailing list more no. of\ntimes then the rest patches from the complete series, and hence\nIMO, are ready for getting included. If not so, I would like to have\nsuggestions for improvising it.\n\nThe patches pass the complete test suite.\n\n builtin/submodule--helper.c | 146 ++++++++++++++++++++++++++++++++++++++++++++\n git-submodule.sh            |  49 +--------------\n 2 files changed, 147 insertions(+), 48 deletions(-)\n\ndiff --git a/builtin/submodule--helper.c b/builtin/submodule--helper.c\nindex 80f744407..9c1630495 100644\n--- a/builtin/submodule--helper.c\n+++ b/builtin/submodule--helper.c\n@@ -560,6 +560,151 @@ static int module_init(int argc, const char **argv, const char *prefix)\n \treturn 0;\n }\n \n+struct status_cb {\n+\tconst char *prefix;\n+\tunsigned int quiet: 1;\n+\tunsigned int recursive: 1;\n+\tunsigned int cached: 1;\n+};\n+#define STATUS_CB_INIT { NULL, 0, 0, 0 }\n+\n+static void print_status(struct status_cb *info, char state, const char *path,\n+\t\t\t char *sub_sha1, char *displaypath)\n+{\n+\tif (info->quiet)\n+\t\treturn;\n+\n+\tprintf(\"%c%s %s\", state, sub_sha1, displaypath);\n+\n+\tif (state == ' ' || state == '+') {\n+\t\tstruct argv_array name_rev_args = ARGV_ARRAY_INIT;\n+\n+\t\targv_array_pushl(&name_rev_args, \"print-name-rev\",\n+\t\t\t\t path, sub_sha1, NULL);\n+\t\tprint_name_rev(name_rev_args.argc, name_rev_args.argv,\n+\t\t\t       info->prefix);\n+\t} else {\n+\t\tprintf(\"\\n\");\n+\t}\n+}\n+\n+static int handle_submodule_head_ref(const char *refname,\n+\t\t\t\t     const struct object_id *oid, int flags,\n+\t\t\t\t     void *cb_data)\n+{\n+\tstruct strbuf *output = cb_data;\n+\tif (oid)\n+\t\tstrbuf_addstr(output, oid_to_hex(oid));\n+\treturn 0;\n+}\n+\n+static void status_submodule(const struct cache_entry *list_item, void *cb_data)\n+{\n+\tstruct status_cb *info = cb_data;\n+\tchar *sub_sha1 = xstrdup(oid_to_hex(&list_item->oid));\n+\tchar *displaypath;\n+\tstruct stat st;\n+\n+\tif (!submodule_from_path(null_sha1, list_item->name))\n+\t\tdie(_(\"no submodule mapping found in .gitmodules for path '%s'\"),\n+\t\t      list_item->name);\n+\n+\tdisplaypath = get_submodule_displaypath(list_item->name, info->prefix);\n+\n+\tif (list_item->ce_flags) {\n+\t\tprint_status(info, 'U', list_item->name,\n+\t\t\t     sha1_to_hex(null_sha1), displaypath);\n+\t\tgoto cleanup;\n+\t}\n+\n+\tif (!is_submodule_active(the_repository, list_item->name)) {\n+\t\tprint_status(info, '-', list_item->name, sub_sha1, displaypath);\n+\t\tgoto cleanup;\n+\t}\n+\n+\tif (!lstat(list_item->name, &st) && !ce_match_stat(list_item, &st, 0)) {\n+\t\tprint_status(info, ' ', list_item->name, sub_sha1, displaypath);\n+\t} else {\n+\t\tif (!info->cached) {\n+\t\t\tstruct strbuf sb = STRBUF_INIT;\n+\t\t\tif (head_ref_submodule(list_item->name,\n+\t\t\t\t\t       handle_submodule_head_ref, &sb))\n+\t\t\t\tdie(_(\"could not resolve HEAD ref inside the\"\n+\t\t\t\t      \"submodule '%s'\"), list_item->name);\n+\t\t\tprint_status(info, '+', list_item->name, sb.buf,\n+\t\t\t\t     displaypath);\n+\t\t\tstrbuf_release(&sb);\n+\t\t} else {\n+\t\t\tprint_status(info, '+', list_item->name, sub_sha1,\n+\t\t\t\t     displaypath);\n+\t\t}\n+\t}\n+\n+\tif (info->recursive) {\n+\t\tstruct child_process cpr = CHILD_PROCESS_INIT;\n+\n+\t\tcpr.git_cmd = 1;\n+\t\tcpr.dir = list_item->name;\n+\t\tprepare_submodule_repo_env(&cpr.env_array);\n+\n+\t\targv_array_pushl(&cpr.args, \"--super-prefix\", displaypath,\n+\t\t\t\t \"submodule--helper\", \"status\", \"--recursive\",\n+\t\t\t\t NULL);\n+\n+\t\tif (info->cached)\n+\t\t\targv_array_push(&cpr.args, \"--cached\");\n+\n+\t\tif (info->quiet)\n+\t\t\targv_array_push(&cpr.args, \"--quiet\");\n+\n+\t\tif (run_command(&cpr))\n+\t\t\tdie(_(\"failed to recurse into submodule '%s'\"),\n+\t\t\t      list_item->name);\n+\t}\n+\n+cleanup:\n+\tfree(displaypath);\n+\tfree(sub_sha1);\n+}\n+\n+static int module_status(int argc, const char **argv, const char *prefix)\n+{\n+\tstruct status_cb info = STATUS_CB_INIT;\n+\tstruct pathspec pathspec;\n+\tstruct module_list list = MODULE_LIST_INIT;\n+\tint quiet = 0;\n+\tint cached = 0;\n+\tint recursive = 0;\n+\n+\tstruct option module_status_options[] = {\n+\t\tOPT__QUIET(&quiet, N_(\"Suppress submodule status output\")),\n+\t\tOPT_BOOL(0, \"cached\", &cached, N_(\"Use commit stored in the index instead of the one stored in the submodule HEAD\")),\n+\t\tOPT_BOOL(0, \"recursive\", &recursive, N_(\"Recurse into nested submodules\")),\n+\t\tOPT_END()\n+\t};\n+\n+\tconst char *const git_submodule_helper_usage[] = {\n+\t\tN_(\"git submodule status [--quiet] [--cached] [--recursive] [<path>]\"),\n+\t\tNULL\n+\t};\n+\n+\targc = parse_options(argc, argv, prefix, module_status_options,\n+\t\t\t     git_submodule_helper_usage, 0);\n+\n+\tif (module_list_compute(argc, argv, prefix, &pathspec, &list) < 0)\n+\t\treturn 1;\n+\n+\tinfo.prefix = prefix;\n+\tinfo.quiet = !!quiet;\n+\tinfo.recursive = !!recursive;\n+\tinfo.cached = !!cached;\n+\n+\tgitmodules_config();\n+\tfor_each_submodule_list(list, status_submodule, &info);\n+\n+\treturn 0;\n+}\n+\n static int module_name(int argc, const char **argv, const char *prefix)\n {\n \tconst struct submodule *sub;\n@@ -1306,6 +1451,7 @@ static struct cmd_struct commands[] = {\n \t{\"resolve-relative-url-test\", resolve_relative_url_test, 0},\n \t{\"print-name-rev\", print_name_rev, 0},\n \t{\"init\", module_init, SUPPORT_SUPER_PREFIX},\n+\t{\"status\", module_status, SUPPORT_SUPER_PREFIX},\n \t{\"remote-branch\", resolve_remote_submodule_branch, 0},\n \t{\"push-check\", push_check, 0},\n \t{\"absorb-git-dirs\", absorb_git_dirs, SUPPORT_SUPER_PREFIX},\ndiff --git a/git-submodule.sh b/git-submodule.sh\nindex e988167e0..51b057d82 100755\n--- a/git-submodule.sh\n+++ b/git-submodule.sh\n@@ -1005,54 +1005,7 @@ cmd_status()\n \t\tshift\n \tdone\n \n-\t{\n-\t\tgit submodule--helper list --prefix \"$wt_prefix\" \"$@\" ||\n-\t\techo \"#unmatched\" $?\n-\t} |\n-\twhile read -r mode sha1 stage sm_path\n-\tdo\n-\t\tdie_if_unmatched \"$mode\" \"$sha1\"\n-\t\tname=$(git submodule--helper name \"$sm_path\") || exit\n-\t\tdisplaypath=$(git submodule--helper relative-path \"$prefix$sm_path\" \"$wt_prefix\")\n-\t\tif test \"$stage\" = U\n-\t\tthen\n-\t\t\tsay \"U$sha1 $displaypath\"\n-\t\t\tcontinue\n-\t\tfi\n-\t\tif ! git submodule--helper is-active \"$sm_path\" ||\n-\t\t{\n-\t\t\t! test -d \"$sm_path\"/.git &&\n-\t\t\t! test -f \"$sm_path\"/.git\n-\t\t}\n-\t\tthen\n-\t\t\tsay \"-$sha1 $displaypath\"\n-\t\t\tcontinue;\n-\t\tfi\n-\t\tif git diff-files --ignore-submodules=dirty --quiet -- \"$sm_path\"\n-\t\tthen\n-\t\t\trevname=$(git submodule--helper print-name-rev \"$sm_path\" \"$sha1\")\n-\t\t\tsay \" $sha1 $displaypath$revname\"\n-\t\telse\n-\t\t\tif test -z \"$cached\"\n-\t\t\tthen\n-\t\t\t\tsha1=$(sanitize_submodule_env; cd \"$sm_path\" && git rev-parse --verify HEAD)\n-\t\t\tfi\n-\t\t\trevname=$(git submodule--helper print-name-rev \"$sm_path\" \"$sha1\")\n-\t\t\tsay \"+$sha1 $displaypath$revname\"\n-\t\tfi\n-\n-\t\tif test -n \"$recursive\"\n-\t\tthen\n-\t\t\t(\n-\t\t\t\tprefix=\"$displaypath/\"\n-\t\t\t\tsanitize_submodule_env\n-\t\t\t\twt_prefix=\n-\t\t\t\tcd \"$sm_path\" &&\n-\t\t\t\teval cmd_status\n-\t\t\t) ||\n-\t\t\tdie \"$(eval_gettext \"Failed to recurse into submodule path '\\$sm_path'\")\"\n-\t\tfi\n-\tdone\n+\tgit ${wt_prefix:+-C \"$wt_prefix\"} ${prefix:+--super-prefix \"$prefix\"} submodule--helper status ${GIT_QUIET:+--quiet} ${cached:+--cached} ${recursive:+--recursive} \"$@\"\n }\n #\n # Sync remote urls for submodules\n-- \n2.13.0\n\n"},{"id":"324435","messageId":"20170713200538.25806-5-pc44800@gmail.com","threadId":"46265","inReplyTo":"20170713200538.25806-1-pc44800@gmail.com","subject":"[GSoC][PATCH 5/5 v4] submodule: port submodule subcommand 'sync' from shell to C","fromName":"Prathamesh Chavan","fromEmail":"pc44800@gmail.com","sentAt":"2017-07-13T20:05:38Z","receivedAt":"2017-07-13T20:06:17Z","isPatch":true,"sender":{"key":"pc44800@gmail.com","avatar":"https://avatars.githubusercontent.com/u/17272661?v=4"},"body":"Port the submodule subcommand 'sync' from shell to C using the same\nmechanism as that used for porting submodule subcommand 'status'.\nHence, here the function cmd_sync() is ported from shell to C.\nThis is done by introducing three functions: module_sync(),\nsync_submodule() and print_default_remote().\n\nThe function print_default_remote() is introduced for getting\nthe default remote as stdout.\n\nMentored-by: Christian Couder <christian.couder@gmail.com>\nMentored-by: Stefan Beller <sbeller@google.com>\nSigned-off-by: Prathamesh Chavan <pc44800@gmail.com>\n---\n builtin/submodule--helper.c | 179 ++++++++++++++++++++++++++++++++++++++++++++\n git-submodule.sh            |  56 +-------------\n 2 files changed, 180 insertions(+), 55 deletions(-)\n\ndiff --git a/builtin/submodule--helper.c b/builtin/submodule--helper.c\nindex 9c1630495..da91c489b 100644\n--- a/builtin/submodule--helper.c\n+++ b/builtin/submodule--helper.c\n@@ -44,6 +44,20 @@ static char *get_default_remote(void)\n \treturn ret;\n }\n \n+static int print_default_remote(int argc, const char **argv, const char *prefix)\n+{\n+\tconst char *remote;\n+\n+\tif (argc != 1)\n+\t\tdie(_(\"submodule--helper print-default-remote takes no arguments\"));\n+\n+\tremote = get_default_remote();\n+\tif (remote)\n+\t\tputs(remote);\n+\n+\treturn 0;\n+}\n+\n static int starts_with_dot_slash(const char *str)\n {\n \treturn str[0] == '.' && is_dir_sep(str[1]);\n@@ -379,6 +393,25 @@ static void module_list_active(struct module_list *list)\n \t*list = active_modules;\n }\n \n+static char *get_up_path(const char *path)\n+{\n+\tint i;\n+\tstruct strbuf sb = STRBUF_INIT;\n+\n+\tfor (i = count_slashes(path); i; i--)\n+\t\tstrbuf_addstr(&sb, \"../\");\n+\n+\t/*\n+\t * Check if 'path' ends with slash or not\n+\t * for having the same output for dir/sub_dir\n+\t * and dir/sub_dir/\n+\t */\n+\tif (!is_dir_sep(path[strlen(path) - 1]))\n+\t\tstrbuf_addstr(&sb, \"../\");\n+\n+\treturn strbuf_detach(&sb, NULL);\n+}\n+\n static int module_list(int argc, const char **argv, const char *prefix)\n {\n \tint i;\n@@ -724,6 +757,150 @@ static int module_name(int argc, const char **argv, const char *prefix)\n \treturn 0;\n }\n \n+struct sync_cb {\n+\tconst char *prefix;\n+\tunsigned int quiet: 1;\n+\tunsigned int recursive: 1;\n+};\n+#define SYNC_CB_INIT { NULL, 0, 0 }\n+\n+static void sync_submodule(const struct cache_entry *list_item, void *cb_data)\n+{\n+\tstruct sync_cb *info = cb_data;\n+\tconst struct submodule *sub;\n+\tchar *sub_key, *remote_key;\n+\tchar *sub_origin_url, *super_config_url, *displaypath;\n+\tstruct strbuf sb = STRBUF_INIT;\n+\tstruct child_process cp = CHILD_PROCESS_INIT;\n+\n+\tif (!is_submodule_active(the_repository, list_item->name))\n+\t\treturn;\n+\n+\tsub = submodule_from_path(null_sha1, list_item->name);\n+\n+\tif (!sub || !sub->url)\n+\t\tdie(_(\"no url found for submodule path '%s' in .gitmodules\"),\n+\t\t      list_item->name);\n+\n+\tif (starts_with_dot_dot_slash(sub->url) || starts_with_dot_slash(sub->url)) {\n+\t\tchar *remote_url, *up_path;\n+\t\tchar *remote = get_default_remote();\n+\t\tchar *remote_key = xstrfmt(\"remote.%s.url\", remote);\n+\n+\t\tif (git_config_get_string(remote_key, &remote_url))\n+\t\t\tremote_url = xgetcwd();\n+\n+\t\tup_path = get_up_path(list_item->name);\n+\t\tsub_origin_url = relative_url(remote_url, sub->url, up_path);\n+\t\tsuper_config_url = relative_url(remote_url, sub->url, NULL);\n+\n+\t\tfree(remote);\n+\t\tfree(remote_key);\n+\t\tfree(up_path);\n+\t\tfree(remote_url);\n+\t} else {\n+\t\tsub_origin_url = xstrdup(sub->url);\n+\t\tsuper_config_url = xstrdup(sub->url);\n+\t}\n+\n+\tdisplaypath = get_submodule_displaypath(list_item->name, info->prefix);\n+\n+\tif (!info->quiet)\n+\t\tprintf(_(\"Synchronizing submodule url for '%s'\\n\"),\n+\t\t\t displaypath);\n+\n+\tsub_key = xstrfmt(\"submodule.%s.url\", sub->name);\n+\tif (git_config_set_gently(sub_key, super_config_url))\n+\t\tdie(_(\"failed to register url for submodule path '%s'\"),\n+\t\t      displaypath);\n+\n+\tif (!is_submodule_populated_gently(list_item->name, NULL))\n+\t\tgoto cleanup;\n+\n+\tprepare_submodule_repo_env(&cp.env_array);\n+\tcp.git_cmd = 1;\n+\tcp.dir = list_item->name;\n+\targv_array_pushl(&cp.args, \"submodule--helper\",\n+\t\t\t \"print-default-remote\", NULL);\n+\tif (capture_command(&cp, &sb, 0))\n+\t\tdie(_(\"failed to get the default remote for submodule '%s'\"),\n+\t\t      list_item->name);\n+\n+\tstrbuf_strip_suffix(&sb, \"\\n\");\n+\tremote_key = xstrfmt(\"remote.%s.url\", sb.buf);\n+\tstrbuf_release(&sb);\n+\n+\tchild_process_init(&cp);\n+\tprepare_submodule_repo_env(&cp.env_array);\n+\tcp.git_cmd = 1;\n+\tcp.dir = list_item->name;\n+\targv_array_pushl(&cp.args, \"config\", remote_key, sub_origin_url, NULL);\n+\tif (run_command(&cp))\n+\t\tdie(_(\"failed to update remote for submodule '%s'\"),\n+\t\t      list_item->name);\n+\n+\tif (info->recursive) {\n+\t\tstruct child_process cpr = CHILD_PROCESS_INIT;\n+\n+\t\tcpr.git_cmd = 1;\n+\t\tcpr.dir = list_item->name;\n+\t\tprepare_submodule_repo_env(&cpr.env_array);\n+\n+\t\targv_array_pushl(&cpr.args, \"--super-prefix\", displaypath,\n+\t\t\t\t \"submodule--helper\", \"sync\", \"--recursive\",\n+\t\t\t\t NULL);\n+\n+\t\tif (info->quiet)\n+\t\t\targv_array_push(&cpr.args, \"--quiet\");\n+\n+\t\tif (run_command(&cpr))\n+\t\t\tdie(_(\"failed to recurse into submodule '%s'\"),\n+\t\t\t      list_item->name);\n+\t}\n+\n+cleanup:\n+\tfree(sub_key);\n+\tfree(super_config_url);\n+\tfree(displaypath);\n+\tfree(sub_origin_url);\n+}\n+\n+static int module_sync(int argc, const char **argv, const char *prefix)\n+{\n+\tstruct sync_cb info = SYNC_CB_INIT;\n+\tstruct pathspec pathspec;\n+\tstruct module_list list = MODULE_LIST_INIT;\n+\tint quiet = 0;\n+\tint recursive = 0;\n+\n+\tstruct option module_sync_options[] = {\n+\t\tOPT__QUIET(&quiet, N_(\"Suppress output of synchronizing submodule url\")),\n+\t\tOPT_BOOL(0, \"recursive\", &recursive,\n+\t\t\tN_(\"Recurse into nested submodules\")),\n+\t\tOPT_END()\n+\t};\n+\n+\tconst char *const git_submodule_helper_usage[] = {\n+\t\tN_(\"git submodule--helper sync [--quiet] [--recursive] [<path>]\"),\n+\t\tNULL\n+\t};\n+\n+\targc = parse_options(argc, argv, prefix, module_sync_options,\n+\t\t\t     git_submodule_helper_usage, 0);\n+\n+\tif (module_list_compute(argc, argv, prefix, &pathspec, &list) < 0)\n+\t\treturn 1;\n+\n+\tinfo.prefix = prefix;\n+\tinfo.quiet = !!quiet;\n+\tinfo.recursive = !!recursive;\n+\n+\tgitmodules_config();\n+\tfor_each_submodule_list(list, sync_submodule, &info);\n+\n+\treturn 0;\n+}\n+\n static int clone_submodule(const char *path, const char *gitdir, const char *url,\n \t\t\t   const char *depth, struct string_list *reference,\n \t\t\t   int quiet, int progress)\n@@ -1452,6 +1629,8 @@ static struct cmd_struct commands[] = {\n \t{\"print-name-rev\", print_name_rev, 0},\n \t{\"init\", module_init, SUPPORT_SUPER_PREFIX},\n \t{\"status\", module_status, SUPPORT_SUPER_PREFIX},\n+\t{\"print-default-remote\", print_default_remote, 0},\n+\t{\"sync\", module_sync, SUPPORT_SUPER_PREFIX},\n \t{\"remote-branch\", resolve_remote_submodule_branch, 0},\n \t{\"push-check\", push_check, 0},\n \t{\"absorb-git-dirs\", absorb_git_dirs, SUPPORT_SUPER_PREFIX},\ndiff --git a/git-submodule.sh b/git-submodule.sh\nindex 51b057d82..6bfc5e17d 100755\n--- a/git-submodule.sh\n+++ b/git-submodule.sh\n@@ -1037,63 +1037,9 @@ cmd_sync()\n \t\t\t;;\n \t\tesac\n \tdone\n-\tcd_to_toplevel\n-\t{\n-\t\tgit submodule--helper list --prefix \"$wt_prefix\" \"$@\" ||\n-\t\techo \"#unmatched\" $?\n-\t} |\n-\twhile read -r mode sha1 stage sm_path\n-\tdo\n-\t\tdie_if_unmatched \"$mode\" \"$sha1\"\n-\n-\t\t# skip inactive submodules\n-\t\tif ! git submodule--helper is-active \"$sm_path\"\n-\t\tthen\n-\t\t\tcontinue\n-\t\tfi\n-\n-\t\tname=$(git submodule--helper name \"$sm_path\")\n-\t\turl=$(git config -f .gitmodules --get submodule.\"$name\".url)\n-\n-\t\t# Possibly a url relative to parent\n-\t\tcase \"$url\" in\n-\t\t./*|../*)\n-\t\t\t# rewrite foo/bar as ../.. to find path from\n-\t\t\t# submodule work tree to superproject work tree\n-\t\t\tup_path=\"$(printf '%s\\n' \"$sm_path\" | sed \"s/[^/][^/]*/../g\")\" &&\n-\t\t\t# guarantee a trailing /\n-\t\t\tup_path=${up_path%/}/ &&\n-\t\t\t# path from submodule work tree to submodule origin repo\n-\t\t\tsub_origin_url=$(git submodule--helper resolve-relative-url \"$url\" \"$up_path\") &&\n-\t\t\t# path from superproject work tree to submodule origin repo\n-\t\t\tsuper_config_url=$(git submodule--helper resolve-relative-url \"$url\") || exit\n-\t\t\t;;\n-\t\t*)\n-\t\t\tsub_origin_url=\"$url\"\n-\t\t\tsuper_config_url=\"$url\"\n-\t\t\t;;\n-\t\tesac\n \n-\t\tdisplaypath=$(git submodule--helper relative-path \"$prefix$sm_path\" \"$wt_prefix\")\n-\t\tsay \"$(eval_gettext \"Synchronizing submodule url for '\\$displaypath'\")\"\n-\t\tgit config submodule.\"$name\".url \"$super_config_url\"\n-\n-\t\tif test -e \"$sm_path\"/.git\n-\t\tthen\n-\t\t(\n-\t\t\tsanitize_submodule_env\n-\t\t\tcd \"$sm_path\"\n-\t\t\tremote=$(get_default_remote)\n-\t\t\tgit config remote.\"$remote\".url \"$sub_origin_url\"\n+\tgit ${wt_prefix:+-C \"$wt_prefix\"} ${prefix:+--super-prefix \"$prefix\"} submodule--helper sync ${GIT_QUIET:+--quiet} ${recursive:+--recursive} \"$@\"\n \n-\t\t\tif test -n \"$recursive\"\n-\t\t\tthen\n-\t\t\t\tprefix=\"$prefix$sm_path/\"\n-\t\t\t\teval cmd_sync\n-\t\t\tfi\n-\t\t)\n-\t\tfi\n-\tdone\n }\n \n cmd_absorbgitdirs()\n-- \n2.13.0\n\n"},{"id":"324460","messageId":"CAGZ79kb18z5zc9iu3Vv5aVZWJmoZzmwbMVpy89VC-t-ei2M+bw@mail.gmail.com","threadId":"46265","inReplyTo":"20170713200538.25806-4-pc44800@gmail.com","subject":"Re: [GSoC][PATCH 4/5 v4] submodule: port submodule subcommand 'status' from shell to C","fromName":"Stefan Beller","fromEmail":"sbeller@google.com","sentAt":"2017-07-13T22:44:09Z","receivedAt":"2017-07-13T22:44:15Z","isPatch":true,"sender":{"key":"stefanbeller@gmail.com","avatar":"https://avatars.githubusercontent.com/u/455868?v=4"},"body":"On Thu, Jul 13, 2017 at 1:05 PM, Prathamesh Chavan <pc44800@gmail.com> wrote:\n> This aims to make git-submodule 'status' a built-in. Hence, the function\n> cmd_status() is ported from shell to C. This is done by introducing\n> three functions: module_status(), submodule_status() and print_status().\n>\n> The function module_status() acts as the front-end of the subcommand.\n> It parses subcommand's options and then calls the function\n> module_list_compute() for computing the list of submodules. Then\n> this functions calls for_each_submodule_list() looping through the\n> list obtained.\n>\n> Then for_each_submodule_list() calls submodule_status() for each of the\n> submodule in its list. The function submodule_status() is responsible\n> for generating the status each submodule it is called for, and\n> then calls print_status().\n>\n> Finally, the function print_status() handles the printing of submodule's\n> status.\n>\n> Mentored-by: Christian Couder <christian.couder@gmail.com>\n> Mentored-by: Stefan Beller <sbeller@google.com>\n> Signed-off-by: Prathamesh Chavan <pc44800@gmail.com>\n> ---\n> In this new version of patch:\n>\n> Instead of using cmd_diff_files(), the process is optimized\n> by using ce_match_stat().\n\nApart from this I have reviewed the patch and found it a faithful\nconversion.\n\nI am not an expert in the diff area  and wonder how\nthe cmd_diff_files functionality is achieved with just a stat call\nand then comparing it to  ce_match_stat. 'Using \"dirty\" ignores\nall changes to the work tree of submodules, only changes to the\ncommits stored in the superproject are shown.' So I'd have\nexpected ce->oid to be compared (is there an index entry differing,\ni.e. more than one stage?)\n\n\n> Also, the child_process running the command 'rev-parse --verify HEAD'\n> is removed for optimization reasons, and instead head_ref_submodule()\n> is used with callback function handle_submodule_head_ref().\n\nCool.\n"}]}