{"thread":{"id":"46490","subject":"[GSoC][PATCH 00/13] Update: Week-11","startedAt":"2017-07-31T20:56:48Z","lastAt":"2017-08-05T18:03:15Z","messageCount":25,"participants":["Prathamesh Chavan","Stefan Beller","Christian Couder"],"isPatch":true,"patchVersion":1,"patchTotal":13},"messages":[{"id":"325321","messageId":"20170731205621.24305-1-pc44800@gmail.com","threadId":"46490","inReplyTo":null,"subject":"[GSoC][PATCH 00/13] Update: Week-11","fromName":"Prathamesh Chavan","fromEmail":"pc44800@gmail.com","sentAt":"2017-07-31T20:56:08Z","receivedAt":"2017-07-31T20:56:48Z","isPatch":true,"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\n* Following patches were updated after the previous reviews:\n  - set_name_rev()\n  submodule subcommands:\n  - status\n  - sync\n  - deinit\n  - summary\n  - foreach\n\n* Reviews from both Christian Couder <christian.couder@gmail.com> and\n  Brandon Williams <bmwill@google.com> helped in improvising these patches\n  and their suggestions were implemented.\n\n* Porting of submodule subcommand add is still underway. Its progess can be\n  viewed at [2].\n\nPLAN FOR WEEK-12 (1 August 2017 to 7 August 2017):\n\n* summary: One of the problems pointed out by Brandon this week was that\n  the function print_submodule_summary() was too big to keep track of\n  all the things that are happening. Hence, I will be splitting the\n  function into smaller functions.\n\n* displaypath: There is some confusion produced with the way the\n  value of displaypath is being generated, using super-prefix. [3]\n  Via having discussion on this, I'll try to resolve the issues\n  regarding it. In the patches following the update, I have addressed\n  this issue as well.\n\n* add: Porting of this subcommand is still underway and will be working\n  on to completely port this subcommand.\n\nA complete build report of these series of patches is available at: [4].\nBuild #145\nBranch: week-11\n\nThe work is push on github and is available at: [5].\n\n[1]: https://docs.google.com/document/d/1krxVLooWl--75Pot3dazhfygR3wCUUWZWzTXtK1    L-xU/\n[2]: https://github.com/pratham-pc/git/commits/sub-add\n[3]: https://public-inbox.org/git/20170724213028.GB92874@google.com/\n[4]: https://travis-ci.org/pratham-pc/git/builds/\n[5]: https://github.com/pratham-pc/git/commits/week-11\n\n  submodule--helper: introduce get_submodule_displaypath()\n  submodule--helper: introduce for_each_submodule_list()\n  submodule: port set_name_rev() from shell to C\n  submodule: port submodule subcommand 'status' from shell to C\n  submodule: port submodule subcommand 'sync' from shell to C\n  submodule: port submodule subcommand 'deinit' from shell to C\n  diff: change scope of the function count_lines()\n  submodule: port submodule subcommand 'summary' from shell to C\n  submodule foreach: correct '$path' in nested submodules from a\n    subdirectory\n  submodule foreach: document '$sm_path' instead of '$path'\n  submodule foreach: clarify the '$toplevel' variable documentation\n  submodule foreach: document variable '$displaypath'\n  submodule: port submodule subcommand 'foreach' from shell to C\n\n Documentation/git-submodule.txt |   15 +-\n builtin/submodule--helper.c     | 1175 ++++++++++++++++++++++++++++++++++++++-\n diff.c                          |    2 +-\n diff.h                          |    1 +\n git-submodule.sh                |  394 +------------\n t/t7407-submodule-foreach.sh    |   38 +-\n 6 files changed, 1207 insertions(+), 418 deletions(-)\n\n-- \n2.13.0\n\n"},{"id":"325322","messageId":"20170731205621.24305-2-pc44800@gmail.com","threadId":"46490","inReplyTo":"20170731205621.24305-1-pc44800@gmail.com","subject":"[GSoC][PATCH 01/13] submodule--helper: introduce get_submodule_displaypath()","fromName":"Prathamesh Chavan","fromEmail":"pc44800@gmail.com","sentAt":"2017-07-31T20:56:09Z","receivedAt":"2017-07-31T20:56:51Z","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":"325323","messageId":"20170731205621.24305-3-pc44800@gmail.com","threadId":"46490","inReplyTo":"20170731205621.24305-1-pc44800@gmail.com","subject":"[GSoC][PATCH 02/13] submodule--helper: introduce for_each_submodule_list()","fromName":"Prathamesh Chavan","fromEmail":"pc44800@gmail.com","sentAt":"2017-07-31T20:56:10Z","receivedAt":"2017-07-31T20:56:55Z","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":"325324","messageId":"20170731205621.24305-4-pc44800@gmail.com","threadId":"46490","inReplyTo":"20170731205621.24305-1-pc44800@gmail.com","subject":"[GSoC][PATCH 03/13] submodule: port set_name_rev() from shell to C","fromName":"Prathamesh Chavan","fromEmail":"pc44800@gmail.com","sentAt":"2017-07-31T20:56:11Z","receivedAt":"2017-07-31T20:56:58Z","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---\nIn this new version, the following changes have been made:\n* The variable namerev from print_name_rev is now freed at the end of the \n  function.\n\n builtin/submodule--helper.c | 64 +++++++++++++++++++++++++++++++++++++++++++++\n git-submodule.sh            | 16 ++----------\n 2 files changed, 66 insertions(+), 14 deletions(-)\n\ndiff --git a/builtin/submodule--helper.c b/builtin/submodule--helper.c\nindex e41572f7a..2cb72d68e 100644\n--- a/builtin/submodule--helper.c\n+++ b/builtin/submodule--helper.c\n@@ -244,6 +244,69 @@ 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+\tfree(namerev);\n+\treturn 0;\n+}\n+\n struct module_list {\n \tconst struct cache_entry **entries;\n \tint alloc, nr;\n@@ -1242,6 +1305,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":"325325","messageId":"20170731205621.24305-5-pc44800@gmail.com","threadId":"46490","inReplyTo":"20170731205621.24305-1-pc44800@gmail.com","subject":"[GSoC][PATCH 04/13] submodule: port submodule subcommand 'status' from shell to C","fromName":"Prathamesh Chavan","fromEmail":"pc44800@gmail.com","sentAt":"2017-07-31T20:56:12Z","receivedAt":"2017-07-31T20:57:01Z","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, the following changes have been made:\n* parameters passed to the function print_status() have been changed.\n  Instead of passing char *sub_sha1, instead the object_id is being passed.\n \n* Also, since the passed parameter displaypath's value isn't changed\n  by the function, it is passed to the funcition as const char *displaypath\n  instead of char *displaypath.\n\n* the output type of the function handle_submodule_head_ref() is changed\n  from strbuf to object_id, as we will use the object_id instead of the\n  hex of sha1 being stored in a struct strbuf.\n\n* diff_files_args is cleared after using it by passing it as args in the\n  function cmd_diff_files.\n\n* In the function status_submodule(), for checking if a submodule has merge\n  conflicts, the patch currently checks if the value of any of the ce_flags\n  is non-zero. Currently, I think the we aren't interested in a partiular flag,\n  but I'm not sure on this.\n\n* Debugging leftovers and suprious new-lines are removed.\n\n* The confusion with displaypath being passed as te super-prefix in many\n  of the ported subcommands may be a result of the fact that the\n  function generating the displaypath: get_submodule_displaypath()\n  uses the super-prefix as simply a path concatenated with the current\n  submodule name to denote our current location.\n  The function get_super_prefix() is declared in cache.h and defined in\n  environment.c, but is majorly used in the builtin/submodule--helper.c\n  and also in unpack-trees.c\n  Also, for generating any submodule's displaypath, it would be important to\n  have \"..\" passed to the submodule, and currently it is possible only via the\n  super-prefix.\n  This is also other instaces where the super-prefix contained \"..\" as well.\n  One of such instance is Test 4 from t7406-submodule-update.sh\n  Hence, maybe documenting the value of displaypath might a solution\n  for the above problem.\n  I'm just stating my views and would like to recieve your opinion on this\n  matter.\n\n builtin/submodule--helper.c | 154 ++++++++++++++++++++++++++++++++++++++++++++\n git-submodule.sh            |  49 +-------------\n 2 files changed, 155 insertions(+), 48 deletions(-)\n\ndiff --git a/builtin/submodule--helper.c b/builtin/submodule--helper.c\nindex 2cb72d68e..a6e6a48cc 100644\n--- a/builtin/submodule--helper.c\n+++ b/builtin/submodule--helper.c\n@@ -561,6 +561,159 @@ 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 const struct object_id *oid, const char *displaypath)\n+{\n+\tif (info->quiet)\n+\t\treturn;\n+\n+\tprintf(\"%c%s %s\", state, oid_to_hex(oid), 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, oid_to_hex(oid), 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 object_id *output = cb_data;\n+\tif (oid)\n+\t\toidcpy(output, oid);\n+\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 *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     &null_oid, 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, &list_item->oid,\n+\t\t\t     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, &list_item->oid,\n+\t\t\t     displaypath);\n+\t} else {\n+\t\tif (!info->cached) {\n+\t\t\tstruct object_id oid;\n+\n+\t\t\tif (head_ref_submodule(list_item->name,\n+\t\t\t\t\t       handle_submodule_head_ref, &oid))\n+\t\t\t\tdie(_(\"could not resolve HEAD ref inside the\"\n+\t\t\t\t      \"submodule '%s'\"), list_item->name);\n+\n+\t\t\tprint_status(info, '+', list_item->name, &oid,\n+\t\t\t\t     displaypath);\n+\t\t} else {\n+\t\t\tprint_status(info, '+', list_item->name,\n+\t\t\t\t     &list_item->oid, 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+\targv_array_clear(&diff_files_args);\n+\tfree(displaypath);\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@@ -1307,6 +1460,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":"325326","messageId":"20170731205621.24305-6-pc44800@gmail.com","threadId":"46490","inReplyTo":"20170731205621.24305-1-pc44800@gmail.com","subject":"[GSoC][PATCH 05/13] submodule: port submodule subcommand 'sync' from shell to C","fromName":"Prathamesh Chavan","fromEmail":"pc44800@gmail.com","sentAt":"2017-07-31T20:56:13Z","receivedAt":"2017-07-31T20:57:06Z","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---\nIn this new version, the following changes have been made:\n* There was no good reason for using puts in the function print_default_remote()\n  Hence, in this patch, we instead use printf to do the same, as it is what\n  is generally used throughout the codebase.\n\n* As suggested, this patch ensures a more efficient use of variables, and\n  removes most of the variables by reusing 'strbuf sb' at places required.\n\n builtin/submodule--helper.c | 182 ++++++++++++++++++++++++++++++++++++++++++++\n git-submodule.sh            |  56 +-------------\n 2 files changed, 183 insertions(+), 55 deletions(-)\n\ndiff --git a/builtin/submodule--helper.c b/builtin/submodule--helper.c\nindex a6e6a48cc..91945337f 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\tprintf(\"%s\\n\", 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@@ -380,6 +394,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@@ -733,6 +766,153 @@ 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 *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+\tchar *sub_config_path = NULL;\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\tif (starts_with_dot_dot_slash(sub->url) || starts_with_dot_slash(sub->url)) {\n+\t\t\tchar *remote_url, *up_path;\n+\t\t\tchar *remote = get_default_remote();\n+\t\t\tstrbuf_addf(&sb, \"remote.%s.url\", remote);\n+\n+\t\t\tif (git_config_get_string(sb.buf, &remote_url))\n+\t\t\t\tremote_url = xgetcwd();\n+\n+\t\t\tup_path = get_up_path(list_item->name);\n+\t\t\tsub_origin_url = relative_url(remote_url, sub->url, up_path);\n+\t\t\tsuper_config_url = relative_url(remote_url, sub->url, NULL);\n+\n+\t\t\tfree(remote);\n+\t\t\tfree(up_path);\n+\t\t\tfree(remote_url);\n+\t\t} else {\n+\t\t\tsub_origin_url = xstrdup(sub->url);\n+\t\t\tsuper_config_url = xstrdup(sub->url);\n+\t\t}\n+\t} else {\n+\t\tsub_origin_url = \"\";\n+\t\tsuper_config_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+\tstrbuf_reset(&sb);\n+\tstrbuf_addf(&sb, \"submodule.%s.url\", sub->name);\n+\tif (git_config_set_gently(sb.buf, 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+\n+\tstrbuf_reset(&sb);\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+\n+\tstrbuf_reset(&sb);\n+\tsubmodule_to_gitdir(&sb, list_item->name);\n+\tstrbuf_addstr(&sb, \"/config\");\n+\n+\tif (git_config_set_in_file_gently(sb.buf, remote_key, sub_origin_url))\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+\tstrbuf_release(&sb);\n+\tfree(super_config_url);\n+\tfree(displaypath);\n+\tfree(sub_config_path);\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@@ -1461,6 +1641,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":"325327","messageId":"20170731205621.24305-7-pc44800@gmail.com","threadId":"46490","inReplyTo":"20170731205621.24305-1-pc44800@gmail.com","subject":"[GSoC][PATCH 06/13] submodule: port submodule subcommand 'deinit' from shell to C","fromName":"Prathamesh Chavan","fromEmail":"pc44800@gmail.com","sentAt":"2017-07-31T20:56:14Z","receivedAt":"2017-07-31T20:57:08Z","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---\nIn this new version, the following changes have been made:\n* In the function deinit_submodule, since the test is_git_directory()\n  adds an additional condition, instead is_directory() is used to check\n  if \"sm_path/.git\" is a directory.\n\n* since it was possible in the previous path that the value st.st_mode passed\n  to the function mkdir contained a garbage value, instead we intrduce a\n  mode_t variable mode, initially containing a default mode value '0777'.\n  This is what the default of mode is set in case, that the value is\n  not set after the lstat call. \n\n builtin/submodule--helper.c | 144 ++++++++++++++++++++++++++++++++++++++++++++\n git-submodule.sh            |  55 +----------------\n 2 files changed, 145 insertions(+), 54 deletions(-)\n\ndiff --git a/builtin/submodule--helper.c b/builtin/submodule--helper.c\nindex 91945337f..f642f9889 100644\n--- a/builtin/submodule--helper.c\n+++ b/builtin/submodule--helper.c\n@@ -913,6 +913,149 @@ static int module_sync(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 *sub_git_dir = xstrfmt(\"%s/.git\", list_item->name);\n+\tmode_t mode = 0777;\n+\n+\tsub = submodule_from_path(null_sha1, list_item->name);\n+\n+\tif (!sub || !sub->name)\n+\t\tgoto cleanup;\n+\n+\tdisplaypath = get_submodule_displaypath(list_item->name, info->prefix);\n+\n+\t/* remove the submodule work tree (unless the user already did it) */\n+\tif (is_directory(list_item->name)) {\n+\t\tstruct stat st;\n+\t\t/* protect submodules containing a .git directory */\n+\t\tif (is_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\",\n+\t\t\t\t\t list_item->name, NULL);\n+\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\tif (!lstat(list_item->name, &st)) {\n+\t\t\tstruct strbuf sb_rm = STRBUF_INIT;\n+\t\t\tconst char *format;\n+\n+\t\t\tstrbuf_addstr(&sb_rm, list_item->name);\n+\n+\t\t\tif (!remove_dir_recursively(&sb_rm, 0))\n+\t\t\t\tformat = _(\"Cleared directory '%s'\\n\");\n+\t\t\telse\n+\t\t\t\tformat = _(\"Could not remove submodule work tree '%s'\\n\");\n+\n+\t\t\tif (!info->quiet)\n+\t\t\t\tprintf(format, displaypath);\n+\n+\t\t\tmode = st.st_mode;\n+\n+\t\t\tstrbuf_release(&sb_rm);\n+\t\t}\n+\t}\n+\n+\tif (mkdir(list_item->name, mode))\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+\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 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@@ -1643,6 +1786,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 6bfc5e17d..73e6f093f 100755\n--- a/git-submodule.sh\n+++ b/git-submodule.sh\n@@ -428,60 +428,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":"325328","messageId":"20170731205621.24305-8-pc44800@gmail.com","threadId":"46490","inReplyTo":"20170731205621.24305-1-pc44800@gmail.com","subject":"[GSoC][PATCH 07/13] diff: change scope of the function count_lines()","fromName":"Prathamesh Chavan","fromEmail":"pc44800@gmail.com","sentAt":"2017-07-31T20:56:15Z","receivedAt":"2017-07-31T20:57:12Z","isPatch":true,"sender":{"key":"pc44800@gmail.com","avatar":"https://avatars.githubusercontent.com/u/17272661?v=4"},"body":"Change the scope of function count_lines for allowing the function\nto be reused in other parts of the code as well.\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 diff.c | 2 +-\n diff.h | 1 +\n 2 files changed, 2 insertions(+), 1 deletion(-)\n\ndiff --git a/diff.c b/diff.c\nindex 85e714f6c..03ed64f93 100644\n--- a/diff.c\n+++ b/diff.c\n@@ -425,7 +425,7 @@ struct emit_callback {\n \tstruct strbuf *header;\n };\n \n-static int count_lines(const char *data, int size)\n+int count_lines(const char *data, int size)\n {\n \tint count, ch, completely_empty = 1, nl_just_seen = 0;\n \tcount = 0;\ndiff --git a/diff.h b/diff.h\nindex 2d442e296..8522514e9 100644\n--- a/diff.h\n+++ b/diff.h\n@@ -273,6 +273,7 @@ extern struct diff_filepair *diff_unmerge(struct diff_options *, const char *pat\n extern int parse_long_opt(const char *opt, const char **argv,\n \t\t\t const char **optarg);\n \n+extern int count_lines(const char *data, int size);\n extern int git_diff_basic_config(const char *var, const char *value, void *cb);\n extern int git_diff_heuristic_config(const char *var, const char *value, void *cb);\n extern void init_diff_ui_defaults(void);\n-- \n2.13.0\n\n"},{"id":"325329","messageId":"20170731205621.24305-9-pc44800@gmail.com","threadId":"46490","inReplyTo":"20170731205621.24305-1-pc44800@gmail.com","subject":"[GSoC][PATCH 08/13] submodule: port submodule subcommand 'summary' from shell to C","fromName":"Prathamesh Chavan","fromEmail":"pc44800@gmail.com","sentAt":"2017-07-31T20:56:16Z","receivedAt":"2017-07-31T20:57:16Z","isPatch":true,"sender":{"key":"pc44800@gmail.com","avatar":"https://avatars.githubusercontent.com/u/17272661?v=4"},"body":"The submodule subcommand 'summary' is ported in the process of\nmaking git-submodule a builtin. The function cmd_summary() from\ngit-submodule.sh is ported to functions module_summary(),\ncompute_summary_module_list(), prepare_submodule_summary() and\nprint_submodule_summary().\n\nThe first function module_summary() parses the options of submodule\nsubcommand and also acts as the front-end of this subcommand.\nAfter parsing them, it calls the compute_summary_module_list()\n\nThe functions compute_summary_module_list() runs the diff_cmd,\nand generates the modules list, as required by the subcommand.\nThe generation of this module list is done by the using the\ncallback function submodule_summary_callback(), and stored in the\nstructure module_cb.\n\nOnce the module list is generated, prepare_submodule_summary()\nfurther goes through the list and filters the list, for\neventually calling the print_submodule_summary() function.\n\nFinally, the print_submodule_summary() takes care of generating\nand printing the summary for each 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---\nIn this new version, the following changes have been made:\n\n* Firstly, about the function compute_summary_module_list().\n  This function is created to generate the list of modules, for which\n  we will generate the summary further. Since the list is actually\n  generated using the git-diff-files or git-diff-index command, but for\n  porting this, we required to create a function similar to the builtin\n  functions of the above commands. But we can't directly call cmd_diff_files() \n  and cmd_diff_index() since we don't have to display the output and instead\n  need to store it. Hence, this function is introduced.\n \n* Also, the module_cb_list *list is not freed since it is a non-heap object.\n  Hence, free() can't be using on the non-heap objects.\n\n* In the function prepare_submodule_summary(), as suggested\n  'git_config_get_string_const' was used instead of instead of '_value'\n\n* Some variables which weren't modified throughout the function-call were\n  passed as const.\n\n* The '!!' trick, which wasn't used in the last patch, is now used in this\n  new version .\n\n* the variables sha1_dst and sha1_src are removed from the function\n  print_submodule_summary(), and instead the p->oid_src and p->oid_dst are\n  used.\n\n* The variable sm_git_dir is freed at the end of the function.\n\n* variable head was no longer used in module_summary() and instead the strbuf\n  was utilized.\n\n builtin/submodule--helper.c | 425 ++++++++++++++++++++++++++++++++++++++++++++\n git-submodule.sh            | 182 +------------------\n 2 files changed, 426 insertions(+), 181 deletions(-)\n\ndiff --git a/builtin/submodule--helper.c b/builtin/submodule--helper.c\nindex f642f9889..94438d6ce 100644\n--- a/builtin/submodule--helper.c\n+++ b/builtin/submodule--helper.c\n@@ -13,6 +13,9 @@\n #include \"remote.h\"\n #include \"refs.h\"\n #include \"connect.h\"\n+#include \"revision.h\"\n+#include \"diffcore.h\"\n+#include \"diff.h\"\n \n typedef void (*submodule_list_func_t)(const struct cache_entry *list_item,\n \t\t\t\t      void *cb_data);\n@@ -766,6 +769,427 @@ static int module_name(int argc, const char **argv, const char *prefix)\n \treturn 0;\n }\n \n+struct module_cb {\n+\tunsigned int mod_src;\n+\tunsigned int mod_dst;\n+\tstruct object_id oid_src;\n+\tstruct object_id oid_dst;\n+\tchar status;\n+\tconst char *sm_path;\n+};\n+#define MODULE_CB_INIT { 0, 0, NULL, NULL, '\\0', NULL }\n+\n+struct module_cb_list {\n+\tstruct module_cb **entries;\n+\tint alloc, nr;\n+};\n+#define MODULE_CB_LIST_INIT { NULL, 0, 0 }\n+\n+struct summary_cb {\n+\tint argc;\n+\tconst char **argv;\n+\tconst char *prefix;\n+\tchar *diff_cmd;\n+\tunsigned int cached: 1;\n+\tunsigned int for_status: 1;\n+\tunsigned int quiet: 1;\n+\tunsigned int files: 1;\n+\tint summary_limits;\n+};\n+#define SUMMARY_CB_INIT { 0, NULL, NULL, NULL, 0, 0, 0, 0, 0 }\n+\n+static int verify_submodule_object_name(const char *sm_path, const char *sha1)\n+{\n+\tstruct child_process cp_rev_parse = CHILD_PROCESS_INIT;\n+\n+\tcp_rev_parse.git_cmd = 1;\n+\tcp_rev_parse.no_stdout = 1;\n+\tcp_rev_parse.dir = sm_path;\n+\tprepare_submodule_repo_env(&cp_rev_parse.env_array);\n+\n+\targv_array_pushl(&cp_rev_parse.args, \"rev-parse\", \"-q\",\n+\t\t\t \"--verify\", NULL);\n+\targv_array_pushf(&cp_rev_parse.args, \"%s^0\", sha1);\n+\n+\tif (run_command(&cp_rev_parse))\n+\t\treturn 1;\n+\n+\treturn 0;\n+}\n+\n+static void print_submodule_summary(struct summary_cb *info,\n+\t\t\t\t    struct module_cb *p)\n+{\n+\tint missing_src = 0;\n+\tint missing_dst = 0;\n+\tchar *displaypath;\n+\tconst char *sha1_abbr_src;\n+\tconst char *sha1_abbr_dst;\n+\tint errmsg = 0;\n+\tint total_commits = -1;\n+\tchar *sm_git_dir = xstrfmt(\"%s/.git\", p->sm_path);\n+\tint is_sm_git_dir = 0;\n+\n+\tif (!info->cached && !oidcmp(&p->oid_dst, &null_oid)) {\n+\t\tif (S_ISGITLINK(p->mod_dst)) {\n+\t\t\tstruct child_process cp_rev_parse = CHILD_PROCESS_INIT;\n+\t\t\tstruct strbuf sb_rev_parse = STRBUF_INIT;\n+\n+\t\t\tcp_rev_parse.git_cmd = 1;\n+\t\t\tcp_rev_parse.no_stderr = 1;\n+\t\t\tcp_rev_parse.dir = p->sm_path;\n+\t\t\tprepare_submodule_repo_env(&cp_rev_parse.env_array);\n+\n+\t\t\targv_array_pushl(&cp_rev_parse.args,\n+\t\t\t\t\t \"rev-parse\", \"HEAD\", NULL);\n+\t\t\tif (!capture_command(&cp_rev_parse, &sb_rev_parse, 0)) {\n+\t\t\t\tstrbuf_strip_suffix(&sb_rev_parse, \"\\n\");\n+\n+\t\t\t\tget_oid_hex(sb_rev_parse.buf, &p->oid_dst);\n+\t\t\t}\n+\t\t\tstrbuf_release(&sb_rev_parse);\n+\t\t} else if (S_ISLNK(p->mod_dst) || S_ISREG(p->mod_dst)) {\n+\t\t\tstruct child_process cp_hash_object = CHILD_PROCESS_INIT;\n+\t\t\tstruct strbuf sb_hash_object = STRBUF_INIT;\n+\n+\t\t\tcp_hash_object.git_cmd = 1;\n+\t\t\targv_array_pushl(&cp_hash_object.args,\n+\t\t\t\t\t \"hash-object\", p->sm_path,\n+\t\t\t\t\t NULL);\n+\t\t\tif (!capture_command(&cp_hash_object,\n+\t\t\t\t\t     &sb_hash_object, 0)) {\n+\t\t\t\tstrbuf_strip_suffix(&sb_hash_object, \"\\n\");\n+\n+\t\t\t\tget_oid_hex(sb_hash_object.buf, &p->oid_dst);\n+\t\t\t}\n+\t\t\tstrbuf_release(&sb_hash_object);\n+\t\t} else {\n+\t\t\tif (p->mod_dst)\n+\t\t\t\tdie(_(\"unexpected mode %d\\n\"), p->mod_dst);\n+\t\t}\n+\t}\n+\n+\tif (is_git_directory(sm_git_dir))\n+\t\tis_sm_git_dir = 1;\n+\n+\tif (is_sm_git_dir && S_ISGITLINK(p->mod_src))\n+\t\tmissing_src = verify_submodule_object_name(p->sm_path,\n+\t\t\t\t\t\t\t   oid_to_hex(&p->oid_src));\n+\n+\tif (is_sm_git_dir && S_ISGITLINK(p->mod_dst))\n+\t\tmissing_dst = verify_submodule_object_name(p->sm_path,\n+\t\t\t\t\t\t\t   oid_to_hex(&p->oid_dst));\n+\n+\tdisplaypath = get_submodule_displaypath(p->sm_path, info->prefix);\n+\n+\tif (!missing_dst && !missing_src) {\n+\t\tif (is_sm_git_dir) {\n+\t\t\tstruct child_process cp_rev_list = CHILD_PROCESS_INIT;\n+\t\t\tstruct strbuf sb_rev_list = STRBUF_INIT;\n+\t\t\tchar *range;\n+\n+\t\t\tif (S_ISGITLINK(p->mod_src) && S_ISGITLINK(p->mod_dst))\n+\t\t\t\trange = xstrfmt(\"%s...%s\", oid_to_hex(&p->oid_src), oid_to_hex(&p->oid_dst));\n+\t\t\telse if (S_ISGITLINK(p->mod_src))\n+\t\t\t\trange = xstrdup(oid_to_hex(&p->oid_src));\n+\t\t\telse\n+\t\t\t\trange = xstrdup(oid_to_hex(&p->oid_dst));\n+\n+\t\t\tcp_rev_list.git_cmd = 1;\n+\t\t\tcp_rev_list.dir = p->sm_path;\n+\t\t\tprepare_submodule_repo_env(&cp_rev_list.env_array);\n+\n+\t\t\targv_array_pushl(&cp_rev_list.args, \"rev-list\",\n+\t\t\t\t\t \"--first-parent\", range, \"--\", NULL);\n+\t\t\tif (!capture_command(&cp_rev_list, &sb_rev_list, 0)) {\n+\t\t\t\tif (sb_rev_list.len)\n+\t\t\t\t\ttotal_commits = count_lines(sb_rev_list.buf,\n+\t\t\t\t\t\t\t\t    sb_rev_list.len);\n+\t\t\t\telse\n+\t\t\t\t\ttotal_commits = 0;\n+\t\t\t}\n+\n+\t\t\tfree(range);\n+\t\t\tstrbuf_release(&sb_rev_list);\n+\t\t}\n+\t} else {\n+\t\terrmsg = 1;\n+\t}\n+\n+\tsha1_abbr_src = find_unique_abbrev(p->oid_src.hash, 7);\n+\tsha1_abbr_dst = find_unique_abbrev(p->oid_dst.hash, 7);\n+\n+\tif (p->status == 'T') {\n+\t\tif (S_ISGITLINK(p->mod_dst))\n+\t\t\tprintf(_(\"* %s %s(blob)->%s(submodule)\"),\n+\t\t\t\t displaypath, sha1_abbr_src,\n+\t\t\t\t sha1_abbr_dst);\n+\t\telse\n+\t\t\tprintf(_(\"* %s %s(submodule)->%s(blob)\"),\n+\t\t\t\t displaypath, sha1_abbr_src,\n+\t\t\t\t sha1_abbr_dst);\n+\t} else {\n+\t\t\tprintf(\"* %s %s...%s\", displaypath, sha1_abbr_src,\n+\t\t\t\t sha1_abbr_dst);\n+\t}\n+\n+\tif (total_commits < 0)\n+\t\tprintf(\":\\n\");\n+\telse\n+\t\tprintf(\" (%d):\\n\", total_commits);\n+\n+\tif (errmsg) {\n+\t\t/*\n+\t\t * Don't give error msg for modification whose dst is not\n+\t\t * submodule, i.e. deleted or changed to blob\n+\t\t */\n+\t\tif (S_ISGITLINK(p->mod_src)) {\n+\t\t\tif (missing_src && missing_dst) {\n+\t\t\t\tprintf(_(\"  Warn: %s doesn't contain commits %s and %s\\n\"),\n+\t\t\t\t displaypath, oid_to_hex(&p->oid_src), oid_to_hex(&p->oid_dst));\n+\t\t\t} else if (missing_src) {\n+\t\t\t\tprintf(_(\"  Warn: %s doesn't contain commit %s\\n\"),\n+\t\t\t\t displaypath, oid_to_hex(&p->oid_src));\n+\t\t\t} else {\n+\t\t\t\tprintf(_(\"  Warn: %s doesn't contain commit %s\\n\"),\n+\t\t\t\t displaypath, oid_to_hex(&p->oid_dst));\n+\t\t\t}\n+\t\t}\n+\t} else if (is_sm_git_dir) {\n+\t\tstruct child_process cp_log = CHILD_PROCESS_INIT;\n+\n+\t\tcp_log.git_cmd = 1;\n+\t\tcp_log.dir = p->sm_path;\n+\t\tprepare_submodule_repo_env(&cp_log.env_array);\n+\t\targv_array_pushl(&cp_log.args, \"log\", NULL);\n+\n+\t\tif (S_ISGITLINK(p->mod_src) && S_ISGITLINK(p->mod_dst)) {\n+\t\t\tif (info->summary_limits > 0)\n+\t\t\t\targv_array_pushf(&cp_log.args, \"-%d\", info->summary_limits);\n+\n+\t\t\targv_array_pushl(&cp_log.args, \"--pretty=  %m %s\",\n+\t\t\t\t\t \"--first-parent\", NULL);\n+\t\t\targv_array_pushf(&cp_log.args, \"%s...%s\", oid_to_hex(&p->oid_src), oid_to_hex(&p->oid_dst));\n+\t\t} else if (S_ISGITLINK(p->mod_dst)) {\n+\t\t\targv_array_pushl(&cp_log.args, \"--pretty=  > %s\",\n+\t\t\t\t\t \"-1\", oid_to_hex(&p->oid_dst), NULL);\n+\t\t} else {\n+\t\t\targv_array_pushl(&cp_log.args, \"--pretty=  < %s\",\n+\t\t\t\t\t \"-1\", oid_to_hex(&p->oid_src), NULL);\n+\t\t}\n+\n+\t\trun_command(&cp_log);\n+\t}\n+\tprintf(\"\\n\");\n+\n+\tfree(displaypath);\n+\tfree(sm_git_dir);\n+}\n+\n+static void prepare_submodule_summary(struct summary_cb *info,\n+\t\t\t\t      struct module_cb_list *list)\n+{\n+\tint i;\n+\tfor (i = 0; i < list->nr; i++) {\n+\t\tstruct module_cb *p = list->entries[i];\n+\t\tstruct child_process cp_rev_parse = CHILD_PROCESS_INIT;\n+\n+\t\tif (p->status == 'D' || p->status == 'T') {\n+\t\t\tprint_submodule_summary(info, p);\n+\t\t\tcontinue;\n+\t\t}\n+\n+\t\tif (info->for_status) {\n+\t\t\tchar *config_key;\n+\t\t\tconst char *ignore_config = \"none\";\n+\t\t\tconst char *value;\n+\t\t\tconst struct submodule *sub = submodule_from_path(null_sha1, p->sm_path);\n+\n+\t\t\tif (sub && p->status != 'A') {\n+\t\t\t\tconfig_key = xstrfmt(\"submodule.%s.ignore\",\n+\t\t\t\t\t\t     sub->name);\n+\t\t\t\tif (!git_config_get_string_const(config_key, &value))\n+\t\t\t\t\tignore_config = value;\n+\t\t\t\telse if (sub->ignore)\n+\t\t\t\t\tignore_config = sub->ignore;\n+\n+\t\t\t\tfree(config_key);\n+\n+\t\t\t\tif (!strcmp(ignore_config, \"all\"))\n+\t\t\t\t\tcontinue;\n+\t\t\t}\n+\t\t}\n+\n+\t\t/* Also show added or modified modules which are checked out */\n+\t\tcp_rev_parse.dir = p->sm_path;\n+\t\tcp_rev_parse.git_cmd = 1;\n+\t\tcp_rev_parse.no_stderr = 1;\n+\t\tcp_rev_parse.no_stdout = 1;\n+\n+\t\targv_array_pushl(&cp_rev_parse.args, \"rev-parse\",\n+\t\t\t\t \"--git-dir\", NULL);\n+\n+\t\tif (!run_command(&cp_rev_parse))\n+\t\t\tprint_submodule_summary(info, p);\n+\t}\n+}\n+\n+static void submodule_summary_callback(struct diff_queue_struct *q,\n+\t\t\t\t       struct diff_options *options,\n+\t\t\t\t       void *data)\n+{\n+\tint i;\n+\tstruct module_cb_list *list = data;\n+\tfor (i = 0; i < q->nr; i++) {\n+\t\tstruct diff_filepair *p = q->queue[i];\n+\t\tstruct module_cb *temp;\n+\n+\t\tif (!S_ISGITLINK(p->one->mode) && !S_ISGITLINK(p->two->mode))\n+\t\t\tcontinue;\n+\t\ttemp = (struct module_cb*)malloc(sizeof(struct module_cb));\n+\t\ttemp->mod_src = p->one->mode;\n+\t\ttemp->mod_dst = p->two->mode;\n+\t\ttemp->oid_src = p->one->oid;\n+\t\ttemp->oid_dst = p->two->oid;\n+\t\ttemp->status = p->status;\n+\t\ttemp->sm_path = xstrdup(p->one->path);\n+\n+\t\tALLOC_GROW(list->entries, list->nr + 1, list->alloc);\n+\t\tlist->entries[list->nr++] = temp;\n+\t}\n+}\n+\n+static int compute_summary_module_list(char *head, struct summary_cb *info)\n+{\n+\tstruct argv_array diff_args = ARGV_ARRAY_INIT;\n+\tstruct rev_info rev;\n+\tstruct module_cb_list list = MODULE_CB_LIST_INIT;\n+\n+\targv_array_push(&diff_args, info->diff_cmd);\n+\tif (info->cached)\n+\t\targv_array_push(&diff_args, \"--cached\");\n+\targv_array_pushl(&diff_args, \"--ignore-submodules=dirty\", \"--raw\",\n+\t\t\t NULL);\n+\tif (head)\n+\t\targv_array_push(&diff_args, head);\n+\targv_array_push(&diff_args, \"--\");\n+\tif (info->argc)\n+\t\targv_array_pushv(&diff_args, info->argv);\n+\n+\tgit_config(git_diff_basic_config, NULL);\n+\tinit_revisions(&rev, info->prefix);\n+\tgitmodules_config();\n+\trev.abbrev = 0;\n+\tprecompose_argv(diff_args.argc, diff_args.argv);\n+\n+\tdiff_args.argc = setup_revisions(diff_args.argc, diff_args.argv,\n+\t\t\t\t\t &rev, NULL);\n+\trev.diffopt.output_format = DIFF_FORMAT_NO_OUTPUT | DIFF_FORMAT_CALLBACK;\n+\trev.diffopt.format_callback = submodule_summary_callback;\n+\trev.diffopt.format_callback_data = &list;\n+\n+\tif (!info->cached) {\n+\t\tif (!strcmp(info->diff_cmd, \"diff-index\"))\n+\t\t\tsetup_work_tree();\n+\t\tif (read_cache_preload(&rev.diffopt.pathspec) < 0) {\n+\t\t\tperror(\"read_cache_preload\");\n+\t\t\treturn -1;\n+\t\t}\n+\t} else if (read_cache() < 0) {\n+\t\tperror(\"read_cache\");\n+\t\treturn -1;\n+\t}\n+\n+\tif (!strcmp(info->diff_cmd, \"diff-index\"))\n+\t\trun_diff_index(&rev, info->cached);\n+\telse\n+\t\trun_diff_files(&rev, 0);\n+\tprepare_submodule_summary(info, &list);\n+\n+\tfree(head);\n+\treturn 0;\n+\n+}\n+\n+static int module_summary(int argc, const char **argv, const char *prefix)\n+{\n+\tstruct summary_cb info = SUMMARY_CB_INIT;\n+\tint cached = 0;\n+\tchar *diff_cmd = \"diff-index\";\n+\tint for_status = 0;\n+\tint quiet = 0;\n+\tint files = 0;\n+\tint summary_limits = -1;\n+\tstruct child_process cp_rev = CHILD_PROCESS_INIT;\n+\tstruct strbuf sb = STRBUF_INIT;\n+\n+\tstruct option module_summary_options[] = {\n+\t\tOPT__QUIET(&quiet, N_(\"Suppress output for initializing a submodule\")),\n+\t\tOPT_BOOL(0, \"cached\", &cached, N_(\"Use the commit stored in the index instead of the submodule HEAD\")),\n+\t\tOPT_BOOL(0, \"files\", &files, N_(\"To compares the commit in the index with that in the submodule HEAD\")),\n+\t\tOPT_BOOL(0, \"for-status\", &for_status, N_(\"Skip submodules with 'all' ignore_config value\")),\n+\t\tOPT_INTEGER('n', \"summary-limits\", &summary_limits, N_(\"Limit the summary size\")),\n+\t\tOPT_END()\n+\t};\n+\n+\tconst char *const git_submodule_helper_usage[] = {\n+\t\tN_(\"git submodule--helper summary [<options>] [--] [<path>]\"),\n+\t\tNULL\n+\t};\n+\n+\targc = parse_options(argc, argv, prefix, module_summary_options,\n+\t\t\t     git_submodule_helper_usage, 0);\n+\n+\tif (!summary_limits)\n+\t\treturn 0;\n+\n+\tcp_rev.git_cmd = 1;\n+\targv_array_pushl(&cp_rev.args, \"rev-parse\", \"-q\", \"--verify\",\n+\t\t\t argc ? argv[0] : \"HEAD\", NULL);\n+\n+\tif (!capture_command(&cp_rev, &sb, 0)) {\n+\t\tstrbuf_strip_suffix(&sb, \"\\n\");\n+\t\tif (argc) {\n+\t\t\targv++;\n+\t\t\targc--;\n+\t\t}\n+\t} else if (!argc || !strcmp(argv[0], \"HEAD\")) {\n+\t\t/* before the first commit: compare with an empty tree */\n+\t\tstruct stat st;\n+\t\tstruct object_id oid;\n+\t\tif (fstat(0, &st) < 0 || index_fd(oid.hash, 0, &st, 2, prefix, 3))\n+\t\t\tdie(\"Unable to add %s to database\", oid.hash);\n+\t\tstrbuf_addstr(&sb, oid_to_hex(&oid));\n+\t\tif (argc) {\n+\t\t\targv++;\n+\t\t\targc--;\n+\t\t}\n+\t} else {\n+\t\tstrbuf_addstr(&sb, \"HEAD\");\n+\t}\n+\n+\tif (files) {\n+\t\tif (cached)\n+\t\t\tdie(_(\"The --cached option cannot be used with the --files option\"));\n+\t\tdiff_cmd = \"diff-files\";\n+\n+\t\tstrbuf_reset(&sb);\n+\t\tsb.buf = NULL;\n+\t}\n+\n+\tinfo.argc = argc;\n+\tinfo.argv = argv;\n+\tinfo.prefix = prefix;\n+\tinfo.cached = !!cached;\n+\tinfo.for_status = !!for_status;\n+\tinfo.quiet = quiet;\n+\tinfo.files = files;\n+\tinfo.summary_limits = summary_limits;\n+\tinfo.diff_cmd = diff_cmd;\n+\n+\treturn compute_summary_module_list(strbuf_detach(&sb, NULL), &info);\n+}\n+\n struct sync_cb {\n \tconst char *prefix;\n \tunsigned int quiet: 1;\n@@ -1787,6 +2211,7 @@ static struct cmd_struct commands[] = {\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{\"summary\", module_summary, 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 73e6f093f..a427ddafd 100755\n--- a/git-submodule.sh\n+++ b/git-submodule.sh\n@@ -51,31 +51,6 @@ die_if_unmatched ()\n \tfi\n }\n \n-#\n-# Print a submodule configuration setting\n-#\n-# $1 = submodule name\n-# $2 = option name\n-# $3 = default value\n-#\n-# Checks in the usual git-config places first (for overrides),\n-# otherwise it falls back on .gitmodules.  This allows you to\n-# distribute project-wide defaults in .gitmodules, while still\n-# customizing individual repositories if necessary.  If the option is\n-# not in .gitmodules either, print a default value.\n-#\n-get_submodule_config () {\n-\tname=\"$1\"\n-\toption=\"$2\"\n-\tdefault=\"$3\"\n-\tvalue=$(git config submodule.\"$name\".\"$option\")\n-\tif test -z \"$value\"\n-\tthen\n-\t\tvalue=$(git config -f .gitmodules submodule.\"$name\".\"$option\")\n-\tfi\n-\tprintf '%s' \"${value:-$default}\"\n-}\n-\n isnumber()\n {\n \tn=$(($1 + 0)) 2>/dev/null && test \"$n\" = \"$1\"\n@@ -755,163 +730,8 @@ cmd_summary() {\n \t\tshift\n \tdone\n \n-\ttest $summary_limit = 0 && return\n-\n-\tif rev=$(git rev-parse -q --verify --default HEAD ${1+\"$1\"})\n-\tthen\n-\t\thead=$rev\n-\t\ttest $# = 0 || shift\n-\telif test -z \"$1\" || test \"$1\" = \"HEAD\"\n-\tthen\n-\t\t# before the first commit: compare with an empty tree\n-\t\thead=$(git hash-object -w -t tree --stdin </dev/null)\n-\t\ttest -z \"$1\" || shift\n-\telse\n-\t\thead=\"HEAD\"\n-\tfi\n-\n-\tif [ -n \"$files\" ]\n-\tthen\n-\t\ttest -n \"$cached\" &&\n-\t\tdie \"$(gettext \"The --cached option cannot be used with the --files option\")\"\n-\t\tdiff_cmd=diff-files\n-\t\thead=\n-\tfi\n-\n-\tcd_to_toplevel\n-\teval \"set $(git rev-parse --sq --prefix \"$wt_prefix\" -- \"$@\")\"\n-\t# Get modified modules cared by user\n-\tmodules=$(git $diff_cmd $cached --ignore-submodules=dirty --raw $head -- \"$@\" |\n-\t\tsane_egrep '^:([0-7]* )?160000' |\n-\t\twhile read -r mod_src mod_dst sha1_src sha1_dst status sm_path\n-\t\tdo\n-\t\t\t# Always show modules deleted or type-changed (blob<->module)\n-\t\t\tif test \"$status\" = D || test \"$status\" = T\n-\t\t\tthen\n-\t\t\t\tprintf '%s\\n' \"$sm_path\"\n-\t\t\t\tcontinue\n-\t\t\tfi\n-\t\t\t# Respect the ignore setting for --for-status.\n-\t\t\tif test -n \"$for_status\"\n-\t\t\tthen\n-\t\t\t\tname=$(git submodule--helper name \"$sm_path\")\n-\t\t\t\tignore_config=$(get_submodule_config \"$name\" ignore none)\n-\t\t\t\ttest $status != A && test $ignore_config = all && continue\n-\t\t\tfi\n-\t\t\t# Also show added or modified modules which are checked out\n-\t\t\tGIT_DIR=\"$sm_path/.git\" git-rev-parse --git-dir >/dev/null 2>&1 &&\n-\t\t\tprintf '%s\\n' \"$sm_path\"\n-\t\tdone\n-\t)\n-\n-\ttest -z \"$modules\" && return\n-\n-\tgit $diff_cmd $cached --ignore-submodules=dirty --raw $head -- $modules |\n-\tsane_egrep '^:([0-7]* )?160000' |\n-\tcut -c2- |\n-\twhile read -r mod_src mod_dst sha1_src sha1_dst status name\n-\tdo\n-\t\tif test -z \"$cached\" &&\n-\t\t\ttest $sha1_dst = 0000000000000000000000000000000000000000\n-\t\tthen\n-\t\t\tcase \"$mod_dst\" in\n-\t\t\t160000)\n-\t\t\t\tsha1_dst=$(GIT_DIR=\"$name/.git\" git rev-parse HEAD)\n-\t\t\t\t;;\n-\t\t\t100644 | 100755 | 120000)\n-\t\t\t\tsha1_dst=$(git hash-object $name)\n-\t\t\t\t;;\n-\t\t\t000000)\n-\t\t\t\t;; # removed\n-\t\t\t*)\n-\t\t\t\t# unexpected type\n-\t\t\t\teval_gettextln \"unexpected mode \\$mod_dst\" >&2\n-\t\t\t\tcontinue ;;\n-\t\t\tesac\n-\t\tfi\n-\t\tmissing_src=\n-\t\tmissing_dst=\n-\n-\t\ttest $mod_src = 160000 &&\n-\t\t! GIT_DIR=\"$name/.git\" git-rev-parse -q --verify $sha1_src^0 >/dev/null &&\n-\t\tmissing_src=t\n-\n-\t\ttest $mod_dst = 160000 &&\n-\t\t! GIT_DIR=\"$name/.git\" git-rev-parse -q --verify $sha1_dst^0 >/dev/null &&\n-\t\tmissing_dst=t\n+\tgit ${wt_prefix:+-C \"$wt_prefix\"} submodule--helper summary ${GIT_QUIET:+--quiet} ${prefix:+--prefix \"$prefix\"} ${for_status:+--for-status} ${files:+--files} ${cached:+--cached} ${summary_limit:+-n $summary_limit} \"$@\"\n \n-\t\tdisplay_name=$(git submodule--helper relative-path \"$name\" \"$wt_prefix\")\n-\n-\t\ttotal_commits=\n-\t\tcase \"$missing_src,$missing_dst\" in\n-\t\tt,)\n-\t\t\terrmsg=\"$(eval_gettext \"  Warn: \\$display_name doesn't contain commit \\$sha1_src\")\"\n-\t\t\t;;\n-\t\t,t)\n-\t\t\terrmsg=\"$(eval_gettext \"  Warn: \\$display_name doesn't contain commit \\$sha1_dst\")\"\n-\t\t\t;;\n-\t\tt,t)\n-\t\t\terrmsg=\"$(eval_gettext \"  Warn: \\$display_name doesn't contain commits \\$sha1_src and \\$sha1_dst\")\"\n-\t\t\t;;\n-\t\t*)\n-\t\t\terrmsg=\n-\t\t\ttotal_commits=$(\n-\t\t\tif test $mod_src = 160000 && test $mod_dst = 160000\n-\t\t\tthen\n-\t\t\t\trange=\"$sha1_src...$sha1_dst\"\n-\t\t\telif test $mod_src = 160000\n-\t\t\tthen\n-\t\t\t\trange=$sha1_src\n-\t\t\telse\n-\t\t\t\trange=$sha1_dst\n-\t\t\tfi\n-\t\t\tGIT_DIR=\"$name/.git\" \\\n-\t\t\tgit rev-list --first-parent $range -- | wc -l\n-\t\t\t)\n-\t\t\ttotal_commits=\" ($(($total_commits + 0)))\"\n-\t\t\t;;\n-\t\tesac\n-\n-\t\tsha1_abbr_src=$(echo $sha1_src | cut -c1-7)\n-\t\tsha1_abbr_dst=$(echo $sha1_dst | cut -c1-7)\n-\t\tif test $status = T\n-\t\tthen\n-\t\t\tblob=\"$(gettext \"blob\")\"\n-\t\t\tsubmodule=\"$(gettext \"submodule\")\"\n-\t\t\tif test $mod_dst = 160000\n-\t\t\tthen\n-\t\t\t\techo \"* $display_name $sha1_abbr_src($blob)->$sha1_abbr_dst($submodule)$total_commits:\"\n-\t\t\telse\n-\t\t\t\techo \"* $display_name $sha1_abbr_src($submodule)->$sha1_abbr_dst($blob)$total_commits:\"\n-\t\t\tfi\n-\t\telse\n-\t\t\techo \"* $display_name $sha1_abbr_src...$sha1_abbr_dst$total_commits:\"\n-\t\tfi\n-\t\tif test -n \"$errmsg\"\n-\t\tthen\n-\t\t\t# Don't give error msg for modification whose dst is not submodule\n-\t\t\t# i.e. deleted or changed to blob\n-\t\t\ttest $mod_dst = 160000 && echo \"$errmsg\"\n-\t\telse\n-\t\t\tif test $mod_src = 160000 && test $mod_dst = 160000\n-\t\t\tthen\n-\t\t\t\tlimit=\n-\t\t\t\ttest $summary_limit -gt 0 && limit=\"-$summary_limit\"\n-\t\t\t\tGIT_DIR=\"$name/.git\" \\\n-\t\t\t\tgit log $limit --pretty='format:  %m %s' \\\n-\t\t\t\t--first-parent $sha1_src...$sha1_dst\n-\t\t\telif test $mod_dst = 160000\n-\t\t\tthen\n-\t\t\t\tGIT_DIR=\"$name/.git\" \\\n-\t\t\t\tgit log --pretty='format:  > %s' -1 $sha1_dst\n-\t\t\telse\n-\t\t\t\tGIT_DIR=\"$name/.git\" \\\n-\t\t\t\tgit log --pretty='format:  < %s' -1 $sha1_src\n-\t\t\tfi\n-\t\t\techo\n-\t\tfi\n-\t\techo\n-\tdone\n }\n #\n # List all submodules, prefixed with:\n-- \n2.13.0\n\n"},{"id":"325330","messageId":"20170731205621.24305-10-pc44800@gmail.com","threadId":"46490","inReplyTo":"20170731205621.24305-1-pc44800@gmail.com","subject":"[GSoC][PATCH 09/13] submodule foreach: correct '$path' in nested submodules from a subdirectory","fromName":"Prathamesh Chavan","fromEmail":"pc44800@gmail.com","sentAt":"2017-07-31T20:56:17Z","receivedAt":"2017-07-31T20:57:18Z","isPatch":true,"sender":{"key":"pc44800@gmail.com","avatar":"https://avatars.githubusercontent.com/u/17272661?v=4"},"body":"When running 'git submodule foreach' from a subdirectory of your\nrepository, nested submodules get a bogus value for $sm_path:\nFor a submodule 'sub' that contains a nested submodule 'nested',\nrunning 'git -C dir submodule foreach echo $path' would report\npath='../nested' for the nested submodule. The first part '../' is\nderived from the logic computing the relative path from $pwd to the\nroot of the superproject. The second part is the submodule path inside\nthe submodule. This value is of little use and is hard to document.\n\nThere are two different possible solutions that have more value:\n(a) The path value is documented as the path from the toplevel of the\n    superproject to the mount point of the submodule.\n    In this case we would want to have path='sub/nested'.\n\n(b) As Ramsay noticed the documented value is wrong. For the non-nested\n    case the path is equal to the relative path from $pwd to the\n    submodules working directory. When following this model,\n    the expected value would be path='../sub/nested'.\n\nThe behavior for (b) was introduced in 091a6eb0fe (submodule: drop the\ntop-level requirement, 2013-06-16) the intent for $path seemed to be\nrelative to $cwd to the submodule worktree, but that did not work for\nnested submodules, as the intermittent submodules were not included in\nthe path.\n\nIf we were to fix the meaning of the $path using (a) such that \"path\"\nis \"the path from the toplevel of the superproject to the mount point\nof the submodule\", we would break any existing submodule user that runs\nforeach from non-root of the superproject as the non-nested submodule\n'../sub' would change its path to 'sub'.\n\nIf we would fix the meaning of the $path using (b), such that \"path\"\nis \"the relative path from $pwd to the submodule\", then we would break\nany user that uses nested submodules (even from the root directory) as\nthe 'nested' would become 'sub/nested'.\n\nBoth groups can be found in the wild.  The author has no data if one group\noutweighs the other by large margin, and offending each one seems equally\nbad at first.  However in the authors imagination it is better to go with\n(a) as running from a sub directory sounds like it is carried out\nby a human rather than by some automation task.  With a human on\nthe keyboard the feedback loop is short and the changed behavior can be\nadapted to quickly unlike some automation that can break silently.\n\nDiscussed-with: Ramsay Jones <ramsay@ramsayjones.plus.com>\nSigned-off-by: Prathamesh Chavan <pc44800@gmail.com>\nSigned-off-by: Stefan Beller <sbeller@google.com>\n---\n git-submodule.sh             |  1 -\n t/t7407-submodule-foreach.sh | 36 ++++++++++++++++++++++++++++++++++--\n 2 files changed, 34 insertions(+), 3 deletions(-)\n\ndiff --git a/git-submodule.sh b/git-submodule.sh\nindex a427ddafd..493a64372 100755\n--- a/git-submodule.sh\n+++ b/git-submodule.sh\n@@ -320,7 +320,6 @@ cmd_foreach()\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\ndiff --git a/t/t7407-submodule-foreach.sh b/t/t7407-submodule-foreach.sh\nindex 6ba5daf42..0663622a4 100755\n--- a/t/t7407-submodule-foreach.sh\n+++ b/t/t7407-submodule-foreach.sh\n@@ -82,9 +82,9 @@ test_expect_success 'test basic \"submodule foreach\" usage' '\n \n cat >expect <<EOF\n Entering '../sub1'\n-$pwd/clone-foo1-../sub1-$sub1sha1\n+$pwd/clone-foo1-sub1-$sub1sha1\n Entering '../sub3'\n-$pwd/clone-foo3-../sub3-$sub3sha1\n+$pwd/clone-foo3-sub3-$sub3sha1\n EOF\n \n test_expect_success 'test \"submodule foreach\" from subdirectory' '\n@@ -196,6 +196,38 @@ test_expect_success 'test messages from \"foreach --recursive\" from subdirectory'\n \t) &&\n \ttest_i18ncmp expect actual\n '\n+sub1sha1=$(cd clone2/sub1 && git rev-parse HEAD)\n+sub2sha1=$(cd clone2/sub2 && git rev-parse HEAD)\n+sub3sha1=$(cd clone2/sub3 && git rev-parse HEAD)\n+nested1sha1=$(cd clone2/nested1 && git rev-parse HEAD)\n+nested2sha1=$(cd clone2/nested1/nested2 && git rev-parse HEAD)\n+nested3sha1=$(cd clone2/nested1/nested2/nested3 && git rev-parse HEAD)\n+submodulesha1=$(cd clone2/nested1/nested2/nested3/submodule && git rev-parse HEAD)\n+\n+cat >expect <<EOF\n+Entering '../nested1'\n+$pwd/clone2-nested1-nested1-$nested1sha1\n+Entering '../nested1/nested2'\n+$pwd/clone2/nested1-nested2-nested2-$nested2sha1\n+Entering '../nested1/nested2/nested3'\n+$pwd/clone2/nested1/nested2-nested3-nested3-$nested3sha1\n+Entering '../nested1/nested2/nested3/submodule'\n+$pwd/clone2/nested1/nested2/nested3-submodule-submodule-$submodulesha1\n+Entering '../sub1'\n+$pwd/clone2-foo1-sub1-$sub1sha1\n+Entering '../sub2'\n+$pwd/clone2-foo2-sub2-$sub2sha1\n+Entering '../sub3'\n+$pwd/clone2-foo3-sub3-$sub3sha1\n+EOF\n+\n+test_expect_success 'test \"submodule foreach --recursive\" from subdirectory' '\n+\t(\n+\t\tcd clone2/untracked &&\n+\t\tgit submodule foreach --recursive \"echo \\$toplevel-\\$name-\\$sm_path-\\$sha1\" >../../actual\n+\t) &&\n+\ttest_i18ncmp expect actual\n+'\n \n cat > expect <<EOF\n nested1-nested1\n-- \n2.13.0\n\n"},{"id":"325331","messageId":"20170731205621.24305-11-pc44800@gmail.com","threadId":"46490","inReplyTo":"20170731205621.24305-1-pc44800@gmail.com","subject":"[GSoC][PATCH 10/13] submodule foreach: document '$sm_path' instead of '$path'","fromName":"Prathamesh Chavan","fromEmail":"pc44800@gmail.com","sentAt":"2017-07-31T20:56:18Z","receivedAt":"2017-07-31T20:57:23Z","isPatch":true,"sender":{"key":"pc44800@gmail.com","avatar":"https://avatars.githubusercontent.com/u/17272661?v=4"},"body":"As using a variable '$path' may be harmful to users due to\ncapitalization issues, see 64394e3ae9 (git-submodule.sh: Don't\nuse $path variable in eval_gettext string, 2012-04-17). Adjust\nthe documentation to advocate for using $sm_path,  which contains\nthe same value. We still make the 'path' variable available and\ndocument it as a deprecated synonym of 'sm_path'.\n\nDiscussed-with: Ramsay Jones <ramsay@ramsayjones.plus.com>\nSigned-off-by: Stefan Beller <sbeller@google.com>\nSigned-off-by: Prathamesh Chavan <pc44800@gmail.com>\n---\nThis patch is same as its previous version.\nAlthough here I'll like to add a point that we aim to slowly drop the support\nof the variable 'path'.\n\n Documentation/git-submodule.txt | 10 ++++++----\n 1 file changed, 6 insertions(+), 4 deletions(-)\n\ndiff --git a/Documentation/git-submodule.txt b/Documentation/git-submodule.txt\nindex ff612001d..a23baef62 100644\n--- a/Documentation/git-submodule.txt\n+++ b/Documentation/git-submodule.txt\n@@ -183,12 +183,14 @@ information too.\n \n foreach [--recursive] <command>::\n \tEvaluates an arbitrary shell command in each checked out submodule.\n-\tThe command has access to the variables $name, $path, $sha1 and\n+\tThe command has access to the variables $name, $sm_path, $sha1 and\n \t$toplevel:\n \t$name is the name of the relevant submodule section in `.gitmodules`,\n-\t$path is the name of the submodule directory relative to the\n-\tsuperproject, $sha1 is the commit as recorded in the superproject,\n-\tand $toplevel is the absolute path to the top-level of the superproject.\n+\t$sm_path is the path of the submodule as recorded in the superproject,\n+\t$sha1 is the commit as recorded in the superproject, and\n+\t$toplevel is the absolute path to the top-level of the superproject.\n+\tNote that to avoid conflicts with '$PATH' on Windows, the '$path'\n+\tvariable is now a deprecated synonym of '$sm_path' variable.\n \tAny submodules defined in the superproject but not checked out are\n \tignored by this command. Unless given `--quiet`, foreach prints the name\n \tof each submodule before evaluating the command.\n-- \n2.13.0\n\n"},{"id":"325332","messageId":"20170731205621.24305-12-pc44800@gmail.com","threadId":"46490","inReplyTo":"20170731205621.24305-1-pc44800@gmail.com","subject":"[GSoC][PATCH 11/13] submodule foreach: clarify the '$toplevel' variable documentation","fromName":"Prathamesh Chavan","fromEmail":"pc44800@gmail.com","sentAt":"2017-07-31T20:56:19Z","receivedAt":"2017-07-31T20:57:26Z","isPatch":true,"sender":{"key":"pc44800@gmail.com","avatar":"https://avatars.githubusercontent.com/u/17272661?v=4"},"body":"It does not contain the topmost superproject as the author assumed,\nbut the direct superproject, such that $toplevel/$sm_path is the\nactual absolute path of the submodule.\n\nDiscussed-with: Ramsay Jones <ramsay@ramsayjones.plus.com>\nSigned-off-by: Stefan Beller <sbeller@google.com>\nSigned-off-by: Prathamesh Chavan <pc44800@gmail.com>\n---\n Documentation/git-submodule.txt | 3 ++-\n 1 file changed, 2 insertions(+), 1 deletion(-)\n\ndiff --git a/Documentation/git-submodule.txt b/Documentation/git-submodule.txt\nindex a23baef62..8e7930ebc 100644\n--- a/Documentation/git-submodule.txt\n+++ b/Documentation/git-submodule.txt\n@@ -188,7 +188,8 @@ foreach [--recursive] <command>::\n \t$name is the name of the relevant submodule section in `.gitmodules`,\n \t$sm_path is the path of the submodule as recorded in the superproject,\n \t$sha1 is the commit as recorded in the superproject, and\n-\t$toplevel is the absolute path to the top-level of the superproject.\n+\t$toplevel is the absolute path to its superproject, such that\n+\t$toplevel/$sm_path is the absolute path of the submodule.\n \tNote that to avoid conflicts with '$PATH' on Windows, the '$path'\n \tvariable is now a deprecated synonym of '$sm_path' variable.\n \tAny submodules defined in the superproject but not checked out are\n-- \n2.13.0\n\n"},{"id":"325333","messageId":"20170731205621.24305-13-pc44800@gmail.com","threadId":"46490","inReplyTo":"20170731205621.24305-1-pc44800@gmail.com","subject":"[GSoC][PATCH 12/13] submodule foreach: document variable '$displaypath'","fromName":"Prathamesh Chavan","fromEmail":"pc44800@gmail.com","sentAt":"2017-07-31T20:56:20Z","receivedAt":"2017-07-31T20:57:28Z","isPatch":true,"sender":{"key":"pc44800@gmail.com","avatar":"https://avatars.githubusercontent.com/u/17272661?v=4"},"body":"It was observed that the variable '$displaypath' was accessible but\nundocumented. Hence, document it.\n\nDiscussed-with: Ramsay Jones <ramsay@ramsayjones.plus.com>\nSigned-off-by: Stefan Beller <sbeller@google.com>\nSigned-off-by: Prathamesh Chavan <pc44800@gmail.com>\n---\nIn this new version, the following changes have been made:\n* Spelling mistake in the commit message was corrected.\n\n Documentation/git-submodule.txt |  6 ++++--\n t/t7407-submodule-foreach.sh    | 22 +++++++++++-----------\n 2 files changed, 15 insertions(+), 13 deletions(-)\n\ndiff --git a/Documentation/git-submodule.txt b/Documentation/git-submodule.txt\nindex 8e7930ebc..0cca702cb 100644\n--- a/Documentation/git-submodule.txt\n+++ b/Documentation/git-submodule.txt\n@@ -183,10 +183,12 @@ information too.\n \n foreach [--recursive] <command>::\n \tEvaluates an arbitrary shell command in each checked out submodule.\n-\tThe command has access to the variables $name, $sm_path, $sha1 and\n-\t$toplevel:\n+\tThe command has access to the variables $name, $sm_path, $displaypath,\n+\t$sha1 and $toplevel:\n \t$name is the name of the relevant submodule section in `.gitmodules`,\n \t$sm_path is the path of the submodule as recorded in the superproject,\n+\t$displaypath contains the relative path from the current working\n+\tdirectory to the submodules root directory,\n \t$sha1 is the commit as recorded in the superproject, and\n \t$toplevel is the absolute path to its superproject, such that\n \t$toplevel/$sm_path is the absolute path of the submodule.\ndiff --git a/t/t7407-submodule-foreach.sh b/t/t7407-submodule-foreach.sh\nindex 0663622a4..6ad57e061 100755\n--- a/t/t7407-submodule-foreach.sh\n+++ b/t/t7407-submodule-foreach.sh\n@@ -82,16 +82,16 @@ test_expect_success 'test basic \"submodule foreach\" usage' '\n \n cat >expect <<EOF\n Entering '../sub1'\n-$pwd/clone-foo1-sub1-$sub1sha1\n+$pwd/clone-foo1-sub1-../sub1-$sub1sha1\n Entering '../sub3'\n-$pwd/clone-foo3-sub3-$sub3sha1\n+$pwd/clone-foo3-sub3-../sub3-$sub3sha1\n EOF\n \n test_expect_success 'test \"submodule foreach\" from subdirectory' '\n \tmkdir clone/sub &&\n \t(\n \t\tcd clone/sub &&\n-\t\tgit submodule foreach \"echo \\$toplevel-\\$name-\\$sm_path-\\$sha1\" >../../actual\n+\t\tgit submodule foreach \"echo \\$toplevel-\\$name-\\$sm_path-\\$displaypath-\\$sha1\" >../../actual\n \t) &&\n \ttest_i18ncmp expect actual\n '\n@@ -206,25 +206,25 @@ submodulesha1=$(cd clone2/nested1/nested2/nested3/submodule && git rev-parse HEA\n \n cat >expect <<EOF\n Entering '../nested1'\n-$pwd/clone2-nested1-nested1-$nested1sha1\n+$pwd/clone2-nested1-nested1-../nested1-$nested1sha1\n Entering '../nested1/nested2'\n-$pwd/clone2/nested1-nested2-nested2-$nested2sha1\n+$pwd/clone2/nested1-nested2-nested2-../nested1/nested2-$nested2sha1\n Entering '../nested1/nested2/nested3'\n-$pwd/clone2/nested1/nested2-nested3-nested3-$nested3sha1\n+$pwd/clone2/nested1/nested2-nested3-nested3-../nested1/nested2/nested3-$nested3sha1\n Entering '../nested1/nested2/nested3/submodule'\n-$pwd/clone2/nested1/nested2/nested3-submodule-submodule-$submodulesha1\n+$pwd/clone2/nested1/nested2/nested3-submodule-submodule-../nested1/nested2/nested3/submodule-$submodulesha1\n Entering '../sub1'\n-$pwd/clone2-foo1-sub1-$sub1sha1\n+$pwd/clone2-foo1-sub1-../sub1-$sub1sha1\n Entering '../sub2'\n-$pwd/clone2-foo2-sub2-$sub2sha1\n+$pwd/clone2-foo2-sub2-../sub2-$sub2sha1\n Entering '../sub3'\n-$pwd/clone2-foo3-sub3-$sub3sha1\n+$pwd/clone2-foo3-sub3-../sub3-$sub3sha1\n EOF\n \n test_expect_success 'test \"submodule foreach --recursive\" from subdirectory' '\n \t(\n \t\tcd clone2/untracked &&\n-\t\tgit submodule foreach --recursive \"echo \\$toplevel-\\$name-\\$sm_path-\\$sha1\" >../../actual\n+\t\tgit submodule foreach --recursive \"echo \\$toplevel-\\$name-\\$sm_path-\\$displaypath-\\$sha1\" >../../actual\n \t) &&\n \ttest_i18ncmp expect actual\n '\n-- \n2.13.0\n\n"},{"id":"325334","messageId":"20170731205621.24305-14-pc44800@gmail.com","threadId":"46490","inReplyTo":"20170731205621.24305-1-pc44800@gmail.com","subject":"[GSoC][PATCH 13/13] submodule: port submodule subcommand 'foreach' from shell to C","fromName":"Prathamesh Chavan","fromEmail":"pc44800@gmail.com","sentAt":"2017-07-31T20:56:21Z","receivedAt":"2017-07-31T20:57:33Z","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\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---\nIn this new version, the following changes have been made:\n* Comment style is improved in the function runcommand_in_submodule()\n\n* Comment in added about why the variable \"path\" was exposed via args\n  argv_array instead of exposing it via the env_array.\n\n* This patch exposes the various variables when argc == 1 only, just\n  for maintaining a faithful porting. You can also find discussion about\n  the same at [1].\n\n[1]: https://public-inbox.org/git/CAME+mvUSGAFbN5j-_hv7QpAS57hq4wgH+yZ7XJMPuyQN1gALaA@mail.gmail.com/\n\n builtin/submodule--helper.c | 136 ++++++++++++++++++++++++++++++++++++++++++++\n git-submodule.sh            |  39 +------------\n 2 files changed, 137 insertions(+), 38 deletions(-)\n\ndiff --git a/builtin/submodule--helper.c b/builtin/submodule--helper.c\nindex 94438d6ce..935f56510 100644\n--- a/builtin/submodule--helper.c\n+++ b/builtin/submodule--helper.c\n@@ -769,6 +769,141 @@ static int module_name(int argc, const char **argv, const char *prefix)\n \treturn 0;\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+\n+\t/*\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+\t\tchar *toplevel = xgetcwd();\n+\n+\t\targv_array_pushf(&cp.env_array, \"name=%s\", sub->name);\n+\t\targv_array_pushf(&cp.env_array, \"sm_path=%s\", list_item->name);\n+\t\targv_array_pushf(&cp.env_array, \"displaypath=%s\", displaypath);\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 * Since the path variable was accessible from the script\n+\t\t * before porting, it is also made available after porting.\n+\t\t * The environment variable \"PATH\" has a very special purpose\n+\t\t * on windows. And since environment variables are\n+\t\t * case-insensitive in windows, it interferes with the\n+\t\t * existing PATH variable. Hence, to avoid that, we expose\n+\t\t * path via the args argv_array and not via env_array.\n+\t\t */\n+\t\targv_array_pushf(&cp.args, \"path=%s; %s\",\n+\t\t\t\t list_item->name, info->argv[0]);\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 struct module_cb {\n \tunsigned int mod_src;\n \tunsigned int mod_dst;\n@@ -2206,6 +2341,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{\"print-name-rev\", print_name_rev, 0},\n+\t{\"foreach\", module_foreach, SUPPORT_SUPER_PREFIX},\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},\ndiff --git a/git-submodule.sh b/git-submodule.sh\nindex 493a64372..e25b2c613 100755\n--- a/git-submodule.sh\n+++ b/git-submodule.sh\n@@ -298,44 +298,7 @@ cmd_foreach()\n \t\tshift\n \tdone\n \n-\ttoplevel=$(pwd)\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\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+\tgit ${wt_prefix:+-C \"$wt_prefix\"} ${prefix:+--super-prefix \"$prefix\"} submodule--helper foreach ${GIT_QUIET:+--quiet} ${recursive:+--recursive} \"$@\"\n }\n \n #\n-- \n2.13.0\n\n"},{"id":"325341","messageId":"CAGZ79kaL48k=tCL-nnzFJBm4Qx2Q9uON=Cv82RhUr4ArG66rDA@mail.gmail.com","threadId":"46490","inReplyTo":"20170731205621.24305-5-pc44800@gmail.com","subject":"Re: [GSoC][PATCH 04/13] submodule: port submodule subcommand 'status' from shell to C","fromName":"Stefan Beller","fromEmail":"sbeller@google.com","sentAt":"2017-07-31T21:12:27Z","receivedAt":"2017-07-31T21:12:34Z","isPatch":true,"sender":{"key":"stefanbeller@gmail.com","avatar":"https://avatars.githubusercontent.com/u/455868?v=4"},"body":"On Mon, Jul 31, 2017 at 1:56 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, the following changes have been made:\n> * parameters passed to the function print_status() have been changed.\n>   Instead of passing char *sub_sha1, instead the object_id is being passed.\n>\n> * Also, since the passed parameter displaypath's value isn't changed\n>   by the function, it is passed to the funcition as const char *displaypath\n>   instead of char *displaypath.\n>\n> * the output type of the function handle_submodule_head_ref() is changed\n>   from strbuf to object_id, as we will use the object_id instead of the\n>   hex of sha1 being stored in a struct strbuf.\n>\n> * diff_files_args is cleared after using it by passing it as args in the\n>   function cmd_diff_files.\n>\n> * In the function status_submodule(), for checking if a submodule has merge\n>   conflicts, the patch currently checks if the value of any of the ce_flags\n>   is non-zero. Currently, I think the we aren't interested in a partiular flag,\n>   but I'm not sure on this.\n>\n> * Debugging leftovers and suprious new-lines are removed.\n>\n> * The confusion with displaypath being passed as te super-prefix in many\n>   of the ported subcommands may be a result of the fact that the\n>   function generating the displaypath: get_submodule_displaypath()\n>   uses the super-prefix as simply a path concatenated with the current\n>   submodule name to denote our current location.\n>   The function get_super_prefix() is declared in cache.h and defined in\n>   environment.c, but is majorly used in the builtin/submodule--helper.c\n>   and also in unpack-trees.c\n>   Also, for generating any submodule's displaypath, it would be important to\n>   have \"..\" passed to the submodule, and currently it is possible only via the\n>   super-prefix.\n>   This is also other instaces where the super-prefix contained \"..\" as well.\n>   One of such instance is Test 4 from t7406-submodule-update.sh\n>   Hence, maybe documenting the value of displaypath might a solution\n>   for the above problem.\n>   I'm just stating my views and would like to recieve your opinion on this\n>   matter.\n\nYes, I agree that the display path is not quite easily understood as it can be\nambiguous.  I am confused by this paragraph:\n* does test 4 from 7406 fail here, or was it just the starting point\n  of the discussion and it all works fine?\n\nI have reviewed the patches up to (and including this) patch and\nso far they look good to me.\n\nThanks,\nStefan\n"},{"id":"325342","messageId":"CAGZ79kaxMKHgLoz-NnFGDs2MbB6i5kbhAGC9FZL8KJ8YYRAvLQ@mail.gmail.com","threadId":"46490","inReplyTo":"20170731205621.24305-6-pc44800@gmail.com","subject":"Re: [GSoC][PATCH 05/13] submodule: port submodule subcommand 'sync' from shell to C","fromName":"Stefan Beller","fromEmail":"sbeller@google.com","sentAt":"2017-07-31T21:19:04Z","receivedAt":"2017-07-31T21:19:10Z","isPatch":true,"sender":{"key":"stefanbeller@gmail.com","avatar":"https://avatars.githubusercontent.com/u/455868?v=4"},"body":"On Mon, Jul 31, 2017 at 1:56 PM, Prathamesh Chavan <pc44800@gmail.com> wrote:\n> In this new version, the following changes have been made:\n> * There was no good reason for using puts in the function print_default_remote()\n>   Hence, in this patch, we instead use printf to do the same, as it is what\n>   is generally used throughout the codebase.\n\nHah! I refrained on suggesting the opposite at the last patch.\nIn older code there are lots of \"puts\", c.f. \"git grep puts\", so I assumed\nit to be a micro optimization, hence I would have suggested it.\nEither way is fine with me.\n"},{"id":"325347","messageId":"CAGZ79kbyyR54me_+wQDZRrikqKTp_a98yozVfr8P85QHfyyy=Q@mail.gmail.com","threadId":"46490","inReplyTo":"20170731205621.24305-7-pc44800@gmail.com","subject":"Re: [GSoC][PATCH 06/13] submodule: port submodule subcommand 'deinit' from shell to C","fromName":"Stefan Beller","fromEmail":"sbeller@google.com","sentAt":"2017-07-31T21:42:06Z","receivedAt":"2017-07-31T21:42:41Z","isPatch":true,"sender":{"key":"stefanbeller@gmail.com","avatar":"https://avatars.githubusercontent.com/u/455868?v=4"},"body":"On Mon, Jul 31, 2017 at 1:56 PM, Prathamesh Chavan <pc44800@gmail.com> wrote:\n> The same mechanism is used even for porting this submodule\n> subcommand, as used in the ported subcommands till now.\n> The function cmd_deinit in split up after porting into three\n> functions: module_deinit(), for_each_submodule_list() and\n> deinit_submodule().\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, the following changes have been made:\n> * In the function deinit_submodule, since the test is_git_directory()\n>   adds an additional condition, instead is_directory() is used to check\n>   if \"sm_path/.git\" is a directory.\n\nThanks for writing these patches.\nI wonder if (some of) these notes are best put into the code\nas a comment such as\n\n    /* NEEDSWORK: convert to is_submodule_active */\n\nsuch that people reading this code later realize that checking\nfor a directory may not be the \"correct\" thing, but a thing which\nwas easy to express using shell.\n\n> +struct deinit_cb {\n> +       const char *prefix;\n> +       unsigned int quiet: 1;\n> +       unsigned int force: 1;\n> +       unsigned int all: 1;\n\nThe value 'all' seems to be unused, i.e. we assign it but never read it?\n\n> +};\n> +#define DEINIT_CB_INIT { NULL, 0, 0, 0 }\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 *sub_git_dir = xstrfmt(\"%s/.git\", list_item->name);\n> +       mode_t mode = 0777;\n> +\n> +       sub = submodule_from_path(null_sha1, list_item->name);\n> +\n> +       if (!sub || !sub->name)\n> +               goto cleanup;\n> +\n> +       displaypath = get_submodule_displaypath(list_item->name, info->prefix);\n> +\n> +       /* remove the submodule work tree (unless the user already did it) */\n> +       if (is_directory(list_item->name)) {\n> +               struct stat st;\n> +               /* protect submodules containing a .git directory */\n\nHere may a good place to put:\n  /* NEEDSWORK: automatically call absorbgitdirs before warning/die. */\n(It was not in the shell version, so feel free to ignore)\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\",\n> +                                        list_item->name, NULL);\n\nA bug that exists in the shell version as well as here:\nWhat if the submodule has the name '--cached', which happens\nto be a valid argument for git-rm?\n\nThe call to git-rm would die claiming that the <file> is missing,\nas the file name was miss-interpreted as another flag.\n\nTo solve this problem we would insert a '--' after the options,\nbefore the file name to state that the last argument is a <file>.\n\nNot sure if we want to fix the bug while we're here or if we rather\nwant to add\n\n    /* NEEDSWORK: add '--' to confirm <file> argument */\n\n> +       if (mkdir(list_item->name, mode))\n> +               die(_(\"could not create empty submodule directory %s\"),\n> +                     displaypath);\n\nIn the shell version we used the shell mkdir, which on failure\nwould print the error to stderr on its own. The added \"|| say\"\nis just to clarify the bigger picture.\n\nmkdir in C doesn't print the actual error (e.g.\nno diskspace, permissions) so we have to do it.\nUse 'die_errno' instead as then the reason will be given as well.\n\n> +       cp_config.git_cmd = 1;\n> +       argv_array_pushl(&cp_config.args, \"config\", \"--get-regexp\", NULL);\n> +       argv_array_pushf(&cp_config.args, \"submodule.%s\\\\.\", sub->name);\n\nIt would be nice if the commit message could give hints as why a literal\ntranslation was chosen here and not e.g. one of the builtin config\ncalls, as that would omit spawning a process.\n"},{"id":"325348","messageId":"CAGZ79kaWn9z47Va=VW4R2Aswws1N5n2u4Kvatn73s0YnV0pVqQ@mail.gmail.com","threadId":"46490","inReplyTo":"20170731205621.24305-9-pc44800@gmail.com","subject":"Re: [GSoC][PATCH 08/13] submodule: port submodule subcommand 'summary' from shell to C","fromName":"Stefan Beller","fromEmail":"sbeller@google.com","sentAt":"2017-07-31T22:15:39Z","receivedAt":"2017-07-31T22:15:47Z","isPatch":true,"sender":{"key":"stefanbeller@gmail.com","avatar":"https://avatars.githubusercontent.com/u/455868?v=4"},"body":"On Mon, Jul 31, 2017 at 1:56 PM, Prathamesh Chavan <pc44800@gmail.com> wrote:\n> The submodule subcommand 'summary' is ported in the process of\n> making git-submodule a builtin. The function cmd_summary() from\n> git-submodule.sh is ported to functions module_summary(),\n> compute_summary_module_list(), prepare_submodule_summary() and\n> print_submodule_summary().\n>\n> The first function module_summary() parses the options of submodule\n> subcommand and also acts as the front-end of this subcommand.\n> After parsing them, it calls the compute_summary_module_list()\n>\n> The functions compute_summary_module_list() runs the diff_cmd,\n> and generates the modules list, as required by the subcommand.\n> The generation of this module list is done by the using the\n> callback function submodule_summary_callback(), and stored in the\n> structure module_cb.\n>\n> Once the module list is generated, prepare_submodule_summary()\n> further goes through the list and filters the list, for\n> eventually calling the print_submodule_summary() function.\n>\n> Finally, the print_submodule_summary() takes care of generating\n> and printing the summary for each submodule.\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, the following changes have been made:\n>\n> * Firstly, about the function compute_summary_module_list().\n>   This function is created to generate the list of modules, for which\n>   we will generate the summary further. Since the list is actually\n>   generated using the git-diff-files or git-diff-index command, but for\n>   porting this, we required to create a function similar to the builtin\n>   functions of the above commands. But we can't directly call cmd_diff_files()\n>   and cmd_diff_index() since we don't have to display the output and instead\n>   need to store it. Hence, this function is introduced.\n>\n> * Also, the module_cb_list *list is not freed since it is a non-heap object.\n>   Hence, free() can't be using on the non-heap objects.\n>\n> * In the function prepare_submodule_summary(), as suggested\n>   'git_config_get_string_const' was used instead of instead of '_value'\n>\n> * Some variables which weren't modified throughout the function-call were\n>   passed as const.\n>\n> * The '!!' trick, which wasn't used in the last patch, is now used in this\n>   new version .\n>\n> * the variables sha1_dst and sha1_src are removed from the function\n>   print_submodule_summary(), and instead the p->oid_src and p->oid_dst are\n>   used.\n>\n> * The variable sm_git_dir is freed at the end of the function.\n>\n> * variable head was no longer used in module_summary() and instead the strbuf\n>   was utilized.\n>\n>  builtin/submodule--helper.c | 425 ++++++++++++++++++++++++++++++++++++++++++++\n>  git-submodule.sh            | 182 +------------------\n>  2 files changed, 426 insertions(+), 181 deletions(-)\n>\n> diff --git a/builtin/submodule--helper.c b/builtin/submodule--helper.c\n> index f642f9889..94438d6ce 100644\n> --- a/builtin/submodule--helper.c\n> +++ b/builtin/submodule--helper.c\n> @@ -13,6 +13,9 @@\n>  #include \"remote.h\"\n>  #include \"refs.h\"\n>  #include \"connect.h\"\n> +#include \"revision.h\"\n> +#include \"diffcore.h\"\n> +#include \"diff.h\"\n>\n>  typedef void (*submodule_list_func_t)(const struct cache_entry *list_item,\n>                                       void *cb_data);\n> @@ -766,6 +769,427 @@ static int module_name(int argc, const char **argv, const char *prefix)\n>         return 0;\n>  }\n>\n> +struct module_cb {\n> +       unsigned int mod_src;\n> +       unsigned int mod_dst;\n> +       struct object_id oid_src;\n> +       struct object_id oid_dst;\n> +       char status;\n> +       const char *sm_path;\n> +};\n> +#define MODULE_CB_INIT { 0, 0, NULL, NULL, '\\0', NULL }\n> +\n> +struct module_cb_list {\n> +       struct module_cb **entries;\n> +       int alloc, nr;\n> +};\n> +#define MODULE_CB_LIST_INIT { NULL, 0, 0 }\n> +\n> +struct summary_cb {\n> +       int argc;\n> +       const char **argv;\n> +       const char *prefix;\n> +       char *diff_cmd;\n> +       unsigned int cached: 1;\n> +       unsigned int for_status: 1;\n> +       unsigned int quiet: 1;\n> +       unsigned int files: 1;\n> +       int summary_limits;\n> +};\n> +#define SUMMARY_CB_INIT { 0, NULL, NULL, NULL, 0, 0, 0, 0, 0 }\n> +\n> +static int verify_submodule_object_name(const char *sm_path, const char *sha1)\n> +{\n> +       struct child_process cp_rev_parse = CHILD_PROCESS_INIT;\n> +\n> +       cp_rev_parse.git_cmd = 1;\n> +       cp_rev_parse.no_stdout = 1;\n> +       cp_rev_parse.dir = sm_path;\n> +       prepare_submodule_repo_env(&cp_rev_parse.env_array);\n> +\n> +       argv_array_pushl(&cp_rev_parse.args, \"rev-parse\", \"-q\",\n> +                        \"--verify\", NULL);\n> +       argv_array_pushf(&cp_rev_parse.args, \"%s^0\", sha1);\n> +\n> +       if (run_command(&cp_rev_parse))\n> +               return 1;\n> +\n> +       return 0;\n> +}\n> +\n> +static void print_submodule_summary(struct summary_cb *info,\n> +                                   struct module_cb *p)\n> +{\n> +       int missing_src = 0;\n> +       int missing_dst = 0;\n> +       char *displaypath;\n> +       const char *sha1_abbr_src;\n> +       const char *sha1_abbr_dst;\n> +       int errmsg = 0;\n> +       int total_commits = -1;\n> +       char *sm_git_dir = xstrfmt(\"%s/.git\", p->sm_path);\n> +       int is_sm_git_dir = 0;\n> +\n> +       if (!info->cached && !oidcmp(&p->oid_dst, &null_oid)) {\n> +               if (S_ISGITLINK(p->mod_dst)) {\n> +                       struct child_process cp_rev_parse = CHILD_PROCESS_INIT;\n> +                       struct strbuf sb_rev_parse = STRBUF_INIT;\n> +\n> +                       cp_rev_parse.git_cmd = 1;\n> +                       cp_rev_parse.no_stderr = 1;\n> +                       cp_rev_parse.dir = p->sm_path;\n> +                       prepare_submodule_repo_env(&cp_rev_parse.env_array);\n> +\n> +                       argv_array_pushl(&cp_rev_parse.args,\n> +                                        \"rev-parse\", \"HEAD\", NULL);\n> +                       if (!capture_command(&cp_rev_parse, &sb_rev_parse, 0)) {\n> +                               strbuf_strip_suffix(&sb_rev_parse, \"\\n\");\n> +\n> +                               get_oid_hex(sb_rev_parse.buf, &p->oid_dst);\n> +                       }\n> +                       strbuf_release(&sb_rev_parse);\n\nI think this could be replaced via\nhead_ref_submodule(sub->path, callback function, &where_to_store)\nor is there some trickery going on, that this also works on\nnon-compliant submodules?\n(Maybe add that as a NEEDSWORK/TODO)\n\n> +static int compute_summary_module_list(char *head, struct summary_cb *info)\n> +{\n> +       struct argv_array diff_args = ARGV_ARRAY_INIT;\n> +       struct rev_info rev;\n> +       struct module_cb_list list = MODULE_CB_LIST_INIT;\n> +\n> +       argv_array_push(&diff_args, info->diff_cmd);\n> +       if (info->cached)\n> +               argv_array_push(&diff_args, \"--cached\");\n> +       argv_array_pushl(&diff_args, \"--ignore-submodules=dirty\", \"--raw\",\n> +                        NULL);\n> +       if (head)\n> +               argv_array_push(&diff_args, head);\n> +       argv_array_push(&diff_args, \"--\");\n> +       if (info->argc)\n> +               argv_array_pushv(&diff_args, info->argv);\n> +\n> +       git_config(git_diff_basic_config, NULL);\n> +       init_revisions(&rev, info->prefix);\n> +       gitmodules_config();\n> +       rev.abbrev = 0;\n\nRecently there was a discussion how to operate the\nrevision machinery best (search for earlier versions of\njs/rebase-i-final if interested), whether we can and want\nto directly set flags such as .abbrev or if we'd rather\nwant to push \"--abbrev=0\" to the diff_args before the --\n\nbisect and archive both assign abbrev directly, so I think\nwe're fine here.\n\n> +       precompose_argv(diff_args.argc, diff_args.argv);\n> +\n> +       diff_args.argc = setup_revisions(diff_args.argc, diff_args.argv,\n> +                                        &rev, NULL);\n> +       rev.diffopt.output_format = DIFF_FORMAT_NO_OUTPUT | DIFF_FORMAT_CALLBACK;\n> +       rev.diffopt.format_callback = submodule_summary_callback;\n> +       rev.diffopt.format_callback_data = &list;\n> +\n> +       if (!info->cached) {\n> +               if (!strcmp(info->diff_cmd, \"diff-index\"))\n\nThis strcmp smells like we're encoding the state not optimally\nin 'info'.  Maybe we can have an enum { DIFF_FILES, DIFF_INDEX }\ninstead of a string (that we assign earlier) and then have to\ncompare to it again.\n\n> +                       setup_work_tree();\n> +               if (read_cache_preload(&rev.diffopt.pathspec) < 0) {\n> +                       perror(\"read_cache_preload\");\n> +                       return -1;\n> +               }\n> +       } else if (read_cache() < 0) {\n> +               perror(\"read_cache\");\n> +               return -1;\n> +       }\n\nThis cascaded decision whether to use\nsetup_work_tree / read_cache_preload / read_cache\nseems quite optimized, hence complicated to read. :)\nI like it, though.\n\n> +\n> +       if (!summary_limits)\n> +               return 0;\n\nGood call for converting \"test $summary_limit = 0 && return\".\nI suspected this may be an overeager optimization (as no\nerror checking is done at all, but that is what it is)\nf2dc06a344 (git-submodule summary: limit summary size,\n2008-03-11) introduced it like this.\n"},{"id":"325350","messageId":"CAGZ79kYow5a-dwggDAvGweajrxYNhmtb+oWKTGKriiHtBj-kbw@mail.gmail.com","threadId":"46490","inReplyTo":"20170731205621.24305-14-pc44800@gmail.com","subject":"Re: [GSoC][PATCH 13/13] submodule: port submodule subcommand 'foreach' from shell to C","fromName":"Stefan Beller","fromEmail":"sbeller@google.com","sentAt":"2017-07-31T22:20:44Z","receivedAt":"2017-07-31T22:21:09Z","isPatch":true,"sender":{"key":"stefanbeller@gmail.com","avatar":"https://avatars.githubusercontent.com/u/455868?v=4"},"body":"On Mon, Jul 31, 2017 at 1:56 PM, Prathamesh Chavan <pc44800@gmail.com> wrote:\n> This aims to make git-submodule foreach a builtin. This is the very\n> first step taken in this direction. Hence, 'foreach' is ported to\n> submodule--helper, and submodule--helper is called from git-submodule.sh.\n> The code is split up to have one function to obtain all the list of\n> submodules. This function acts as the front-end of git-submodule foreach\n> subcommand. It calls the function for_each_submodule_list, which basically\n> loops through the list and calls function fn, which in this case is\n> runcommand_in_submodule. This third function is a calling function that\n> takes care of running the command in that submodule, and recursively\n> perform the same when --recursive is flagged.\n>\n> The first function module_foreach first parses the options present in\n> argv, and then with the help of module_list_compute, generates the list of\n> submodules present in the current working tree.\n>\n> The second function for_each_submodule_list traverses through the\n> list, and calls function fn (which in case of submodule subcommand\n> foreach is runcommand_in_submodule) is called for each entry.\n>\n> The third function runcommand_in_submodule, generates a submodule struct sub\n> for $name, value and then later prepends name=sub->name; and other\n> value assignment to the env argv_array structure of a child_process.\n> Also the <command> of submodule-foreach is push to args argv_array\n> structure and finally, using run_command the commands are executed\n> using a shell.\n>\n> The third function also takes care of the recursive flag, by creating\n> a separate child_process structure and prepending \"--super-prefix displaypath\",\n> to the args argv_array structure. Other required arguments and the\n> input <command> of submodule-foreach is also appended to this argv_array.\n>\n> Helped-by: Brandon Williams <bmwill@google.com>\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, the following changes have been made:\n> * Comment style is improved in the function runcommand_in_submodule()\n>\n> * Comment in added about why the variable \"path\" was exposed via args\n>   argv_array instead of exposing it via the env_array.\n>\n> * This patch exposes the various variables when argc == 1 only, just\n>   for maintaining a faithful porting. You can also find discussion about\n>   the same at [1].\n>\n> [1]: https://public-inbox.org/git/CAME+mvUSGAFbN5j-_hv7QpAS57hq4wgH+yZ7XJMPuyQN1gALaA@mail.gmail.com/\n\nAh right, maybe add a NEEDSWORK or have the commit message explain\nthis behavior.\n"},{"id":"325356","messageId":"CAP8UFD3_zX0=h9tuNA-w+30V4P8zZGyUCEnpciTkwRWpXjjmNg@mail.gmail.com","threadId":"46490","inReplyTo":"20170731205621.24305-9-pc44800@gmail.com","subject":"Re: [GSoC][PATCH 08/13] submodule: port submodule subcommand 'summary' from shell to C","fromName":"Christian Couder","fromEmail":"christian.couder@gmail.com","sentAt":"2017-07-31T23:27:58Z","receivedAt":"2017-07-31T23:28:16Z","isPatch":true,"sender":{"key":"christian.couder@gmail.com","avatar":"https://avatars.githubusercontent.com/u/208954?v=4"},"body":"On Mon, Jul 31, 2017 at 10:56 PM, Prathamesh Chavan <pc44800@gmail.com> wrote:\n\n> * variable head was no longer used in module_summary() and instead the strbuf\n>   was utilized.\n\nGood but there might be a few problems in the way it is used. See below.\n\n> +static int compute_summary_module_list(char *head, struct summary_cb *info)\n> +{\n> +       struct argv_array diff_args = ARGV_ARRAY_INIT;\n> +       struct rev_info rev;\n> +       struct module_cb_list list = MODULE_CB_LIST_INIT;\n> +\n> +       argv_array_push(&diff_args, info->diff_cmd);\n> +       if (info->cached)\n> +               argv_array_push(&diff_args, \"--cached\");\n> +       argv_array_pushl(&diff_args, \"--ignore-submodules=dirty\", \"--raw\",\n> +                        NULL);\n> +       if (head)\n> +               argv_array_push(&diff_args, head);\n> +       argv_array_push(&diff_args, \"--\");\n> +       if (info->argc)\n> +               argv_array_pushv(&diff_args, info->argv);\n> +\n> +       git_config(git_diff_basic_config, NULL);\n> +       init_revisions(&rev, info->prefix);\n> +       gitmodules_config();\n> +       rev.abbrev = 0;\n> +       precompose_argv(diff_args.argc, diff_args.argv);\n> +\n> +       diff_args.argc = setup_revisions(diff_args.argc, diff_args.argv,\n> +                                        &rev, NULL);\n> +       rev.diffopt.output_format = DIFF_FORMAT_NO_OUTPUT | DIFF_FORMAT_CALLBACK;\n> +       rev.diffopt.format_callback = submodule_summary_callback;\n> +       rev.diffopt.format_callback_data = &list;\n> +\n> +       if (!info->cached) {\n> +               if (!strcmp(info->diff_cmd, \"diff-index\"))\n> +                       setup_work_tree();\n> +               if (read_cache_preload(&rev.diffopt.pathspec) < 0) {\n> +                       perror(\"read_cache_preload\");\n> +                       return -1;\n> +               }\n> +       } else if (read_cache() < 0) {\n> +               perror(\"read_cache\");\n> +               return -1;\n> +       }\n> +\n> +       if (!strcmp(info->diff_cmd, \"diff-index\"))\n> +               run_diff_index(&rev, info->cached);\n> +       else\n> +               run_diff_files(&rev, 0);\n> +       prepare_submodule_summary(info, &list);\n> +\n> +       free(head);\n\nIt is a bit strange to have this function free() an argument it is passed.\n\n> +       return 0;\n> +\n\nSpurious new line.\n\n> +}\n> +\n> +static int module_summary(int argc, const char **argv, const char *prefix)\n> +{\n> +       struct summary_cb info = SUMMARY_CB_INIT;\n> +       int cached = 0;\n> +       char *diff_cmd = \"diff-index\";\n> +       int for_status = 0;\n> +       int quiet = 0;\n> +       int files = 0;\n> +       int summary_limits = -1;\n> +       struct child_process cp_rev = CHILD_PROCESS_INIT;\n> +       struct strbuf sb = STRBUF_INIT;\n\n[...]\n\n> +       if (!capture_command(&cp_rev, &sb, 0)) {\n> +               strbuf_strip_suffix(&sb, \"\\n\");\n> +               if (argc) {\n> +                       argv++;\n> +                       argc--;\n> +               }\n> +       } else if (!argc || !strcmp(argv[0], \"HEAD\")) {\n> +               /* before the first commit: compare with an empty tree */\n> +               struct stat st;\n> +               struct object_id oid;\n> +               if (fstat(0, &st) < 0 || index_fd(oid.hash, 0, &st, 2, prefix, 3))\n> +                       die(\"Unable to add %s to database\", oid.hash);\n> +               strbuf_addstr(&sb, oid_to_hex(&oid));\n> +               if (argc) {\n> +                       argv++;\n> +                       argc--;\n> +               }\n> +       } else {\n> +               strbuf_addstr(&sb, \"HEAD\");\n> +       }\n> +\n> +       if (files) {\n> +               if (cached)\n> +                       die(_(\"The --cached option cannot be used with the --files option\"));\n> +               diff_cmd = \"diff-files\";\n> +\n> +               strbuf_reset(&sb);\n\nstrbuf_reset() does not free the memory allocated to sb.buf...\n\n> +               sb.buf = NULL;\n\n...then this makes sure that the memory previously allocated to sb.buf\nwill not be free()d.\n\nMaybe instead of the above 2 lines just: strbuf_release(&sb)\nOr maybe just don't set sb.buf to NULL.\n\n> +       }\n> +\n> +       info.argc = argc;\n> +       info.argv = argv;\n> +       info.prefix = prefix;\n> +       info.cached = !!cached;\n> +       info.for_status = !!for_status;\n> +       info.quiet = quiet;\n> +       info.files = files;\n> +       info.summary_limits = summary_limits;\n> +       info.diff_cmd = diff_cmd;\n> +\n> +       return compute_summary_module_list(strbuf_detach(&sb, NULL), &info);\n\nMaybe you could pass: \"sb.len > 0 ? strbuf_detach(&sb, NULL) : NULL\"\nThis way if sb has previously been released or reset, NULL will be passed.\n\nI would suggest though to just pass sb.buf and to strbuf_release(&sb)\nafter calling compute_summary_module_list() and before returning from\nmodule_summary() instead of having compute_summary_module_list() free\nits first argument.\nIf you do that then compute_summary_module_list() should be changed so\nthat when it is passed \"\" it will behave in the same way as when it is\npassed NULL.\n\n> +}\n"},{"id":"325408","messageId":"CAME+mvXsh53kLJ4se4uKY=SJcvSbHtEZQ6K2CgAPs=1wxUxk1A@mail.gmail.com","threadId":"46490","inReplyTo":"CAGZ79kaL48k=tCL-nnzFJBm4Qx2Q9uON=Cv82RhUr4ArG66rDA@mail.gmail.com","subject":"Re: [GSoC][PATCH 04/13] submodule: port submodule subcommand 'status' from shell to C","fromName":"Prathamesh Chavan","fromEmail":"pc44800@gmail.com","sentAt":"2017-08-01T21:14:57Z","receivedAt":"2017-08-01T21:15:03Z","isPatch":true,"sender":{"key":"pc44800@gmail.com","avatar":"https://avatars.githubusercontent.com/u/17272661?v=4"},"body":"On Tue, Aug 1, 2017 at 2:42 AM, Stefan Beller <sbeller@google.com> wrote:\n> On Mon, Jul 31, 2017 at 1:56 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, the following changes have been made:\n>> * parameters passed to the function print_status() have been changed.\n>>   Instead of passing char *sub_sha1, instead the object_id is being passed.\n>>\n>> * Also, since the passed parameter displaypath's value isn't changed\n>>   by the function, it is passed to the funcition as const char *displaypath\n>>   instead of char *displaypath.\n>>\n>> * the output type of the function handle_submodule_head_ref() is changed\n>>   from strbuf to object_id, as we will use the object_id instead of the\n>>   hex of sha1 being stored in a struct strbuf.\n>>\n>> * diff_files_args is cleared after using it by passing it as args in the\n>>   function cmd_diff_files.\n>>\n>> * In the function status_submodule(), for checking if a submodule has merge\n>>   conflicts, the patch currently checks if the value of any of the ce_flags\n>>   is non-zero. Currently, I think the we aren't interested in a partiular flag,\n>>   but I'm not sure on this.\n>>\n>> * Debugging leftovers and suprious new-lines are removed.\n>>\n>> * The confusion with displaypath being passed as te super-prefix in many\n>>   of the ported subcommands may be a result of the fact that the\n>>   function generating the displaypath: get_submodule_displaypath()\n>>   uses the super-prefix as simply a path concatenated with the current\n>>   submodule name to denote our current location.\n>>   The function get_super_prefix() is declared in cache.h and defined in\n>>   environment.c, but is majorly used in the builtin/submodule--helper.c\n>>   and also in unpack-trees.c\n>>   Also, for generating any submodule's displaypath, it would be important to\n>>   have \"..\" passed to the submodule, and currently it is possible only via the\n>>   super-prefix.\n>>   This is also other instaces where the super-prefix contained \"..\" as well.\n>>   One of such instance is Test 4 from t7406-submodule-update.sh\n>>   Hence, maybe documenting the value of displaypath might a solution\n>>   for the above problem.\n>>   I'm just stating my views and would like to recieve your opinion on this\n>>   matter.\n>\n> Yes, I agree that the display path is not quite easily understood as it can be\n> ambiguous.  I am confused by this paragraph:\n> * does test 4 from 7406 fail here, or was it just the starting point\n>   of the discussion and it all works fine?\n\nSorry for misleading there. In the discussion earlier, Brandon mentioned that\ndisplaypath's value may contain \"..\" as well.\nTo this, I replied pointing out one of the test which checks for the value of\ndisplaypath.\nIn this test, ( Test 4 from t7406-submodule-update.sh), the value of displaypath\nis being calculated via the submodule_init() function present in\nsubmodule--helper.c\nHere, I wanted to point out that, even in the case of this function,\nthe variable\ndisplaypath is evaluated after receiving the value of \"../super/\" as\nthe value returned\nby the function get_super_prefix().\nHence, to correct this confusion about the usage of super-prefix,\n(which as pointed out by Brandon has been traditionally defined\nas the path from the root of the superproject down to the root of\nthe submodule which further means that there should not ever be\nany relative '..'s.), we may either have to get the value of super-prefix's\nDocumentation to accomodate this change, and to accept the way it is\nused in submodule--helper and the current patch series, or else,\nchange the way it is being used in the various function, and used\nanother method for evaluation of displaypath.\n\nThanks,\nPrathamesh Chavan\n"},{"id":"325409","messageId":"CAME+mvUJxiD2TwqvLYr73DfCGw7FRSgY3je6VNwasTFY4vH-kg@mail.gmail.com","threadId":"46490","inReplyTo":"CAGZ79kbyyR54me_+wQDZRrikqKTp_a98yozVfr8P85QHfyyy=Q@mail.gmail.com","subject":"Re: [GSoC][PATCH 06/13] submodule: port submodule subcommand 'deinit' from shell to C","fromName":"Prathamesh Chavan","fromEmail":"pc44800@gmail.com","sentAt":"2017-08-01T21:19:16Z","receivedAt":"2017-08-01T21:19:25Z","isPatch":true,"sender":{"key":"pc44800@gmail.com","avatar":"https://avatars.githubusercontent.com/u/17272661?v=4"},"body":"On Tue, Aug 1, 2017 at 3:12 AM, Stefan Beller <sbeller@google.com> wrote:\n> On Mon, Jul 31, 2017 at 1:56 PM, Prathamesh Chavan <pc44800@gmail.com> wrote:\n>> The same mechanism is used even for porting this submodule\n>> subcommand, as used in the ported subcommands till now.\n>> The function cmd_deinit in split up after porting into three\n>> functions: module_deinit(), for_each_submodule_list() and\n>> deinit_submodule().\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, the following changes have been made:\n>> * In the function deinit_submodule, since the test is_git_directory()\n>>   adds an additional condition, instead is_directory() is used to check\n>>   if \"sm_path/.git\" is a directory.\n>\n> Thanks for writing these patches.\n> I wonder if (some of) these notes are best put into the code\n> as a comment such as\n>\n>     /* NEEDSWORK: convert to is_submodule_active */\n>\n> such that people reading this code later realize that checking\n> for a directory may not be the \"correct\" thing, but a thing which\n> was easy to express using shell.\n>\n>> +struct deinit_cb {\n>> +       const char *prefix;\n>> +       unsigned int quiet: 1;\n>> +       unsigned int force: 1;\n>> +       unsigned int all: 1;\n>\n> The value 'all' seems to be unused, i.e. we assign it but never read it?\n>\n>> +};\n>> +#define DEINIT_CB_INIT { NULL, 0, 0, 0 }\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 *sub_git_dir = xstrfmt(\"%s/.git\", list_item->name);\n>> +       mode_t mode = 0777;\n>> +\n>> +       sub = submodule_from_path(null_sha1, list_item->name);\n>> +\n>> +       if (!sub || !sub->name)\n>> +               goto cleanup;\n>> +\n>> +       displaypath = get_submodule_displaypath(list_item->name, info->prefix);\n>> +\n>> +       /* remove the submodule work tree (unless the user already did it) */\n>> +       if (is_directory(list_item->name)) {\n>> +               struct stat st;\n>> +               /* protect submodules containing a .git directory */\n>\n> Here may a good place to put:\n>   /* NEEDSWORK: automatically call absorbgitdirs before warning/die. */\n> (It was not in the shell version, so feel free to ignore)\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\",\n>> +                                        list_item->name, NULL);\n>\n> A bug that exists in the shell version as well as here:\n> What if the submodule has the name '--cached', which happens\n> to be a valid argument for git-rm?\n>\n> The call to git-rm would die claiming that the <file> is missing,\n> as the file name was miss-interpreted as another flag.\n>\n> To solve this problem we would insert a '--' after the options,\n> before the file name to state that the last argument is a <file>.\n>\n> Not sure if we want to fix the bug while we're here or if we rather\n> want to add\n>\n>     /* NEEDSWORK: add '--' to confirm <file> argument */\n>\nIMO, I would first port the subcommand, and add an additional comment\nfor pointing the bug out. And then later, we may have a bug-fix patch in this\nseries of patch itself for tackling this bug out.\n\nThanks,\nPrathamesh Chavan\n"},{"id":"325638","messageId":"CAME+mvUAspzuzbB4pFiQeOtT7NGRTO25M-k8o8hoysMFLGy_0w@mail.gmail.com","threadId":"46490","inReplyTo":"CAP8UFD3_zX0=h9tuNA-w+30V4P8zZGyUCEnpciTkwRWpXjjmNg@mail.gmail.com","subject":"Re: [GSoC][PATCH 08/13] submodule: port submodule subcommand 'summary' from shell to C","fromName":"Prathamesh Chavan","fromEmail":"pc44800@gmail.com","sentAt":"2017-08-05T10:28:03Z","receivedAt":"2017-08-05T10:28:34Z","isPatch":true,"sender":{"key":"pc44800@gmail.com","avatar":"https://avatars.githubusercontent.com/u/17272661?v=4"},"body":"On Tue, Aug 1, 2017 at 4:57 AM, Christian Couder\n<christian.couder@gmail.com> wrote:\n> On Mon, Jul 31, 2017 at 10:56 PM, Prathamesh Chavan <pc44800@gmail.com> wrote:\n>\n>> * variable head was no longer used in module_summary() and instead the strbuf\n>>   was utilized.\n>\n> Good but there might be a few problems in the way it is used. See below.\n>\n>> +static int compute_summary_module_list(char *head, struct summary_cb *info)\n>> +{\n>> +       struct argv_array diff_args = ARGV_ARRAY_INIT;\n>> +       struct rev_info rev;\n>> +       struct module_cb_list list = MODULE_CB_LIST_INIT;\n>> +\n>> +       argv_array_push(&diff_args, info->diff_cmd);\n>> +       if (info->cached)\n>> +               argv_array_push(&diff_args, \"--cached\");\n>> +       argv_array_pushl(&diff_args, \"--ignore-submodules=dirty\", \"--raw\",\n>> +                        NULL);\n>> +       if (head)\n>> +               argv_array_push(&diff_args, head);\n>> +       argv_array_push(&diff_args, \"--\");\n>> +       if (info->argc)\n>> +               argv_array_pushv(&diff_args, info->argv);\n>> +\n>> +       git_config(git_diff_basic_config, NULL);\n>> +       init_revisions(&rev, info->prefix);\n>> +       gitmodules_config();\n>> +       rev.abbrev = 0;\n>> +       precompose_argv(diff_args.argc, diff_args.argv);\n>> +\n>> +       diff_args.argc = setup_revisions(diff_args.argc, diff_args.argv,\n>> +                                        &rev, NULL);\n>> +       rev.diffopt.output_format = DIFF_FORMAT_NO_OUTPUT | DIFF_FORMAT_CALLBACK;\n>> +       rev.diffopt.format_callback = submodule_summary_callback;\n>> +       rev.diffopt.format_callback_data = &list;\n>> +\n>> +       if (!info->cached) {\n>> +               if (!strcmp(info->diff_cmd, \"diff-index\"))\n>> +                       setup_work_tree();\n>> +               if (read_cache_preload(&rev.diffopt.pathspec) < 0) {\n>> +                       perror(\"read_cache_preload\");\n>> +                       return -1;\n>> +               }\n>> +       } else if (read_cache() < 0) {\n>> +               perror(\"read_cache\");\n>> +               return -1;\n>> +       }\n>> +\n>> +       if (!strcmp(info->diff_cmd, \"diff-index\"))\n>> +               run_diff_index(&rev, info->cached);\n>> +       else\n>> +               run_diff_files(&rev, 0);\n>> +       prepare_submodule_summary(info, &list);\n>> +\n>> +       free(head);\n>\n> It is a bit strange to have this function free() an argument it is passed.\n>\n>> +       return 0;\n>> +\n>\n> Spurious new line.\n>\n>> +}\n>> +\n>> +static int module_summary(int argc, const char **argv, const char *prefix)\n>> +{\n>> +       struct summary_cb info = SUMMARY_CB_INIT;\n>> +       int cached = 0;\n>> +       char *diff_cmd = \"diff-index\";\n>> +       int for_status = 0;\n>> +       int quiet = 0;\n>> +       int files = 0;\n>> +       int summary_limits = -1;\n>> +       struct child_process cp_rev = CHILD_PROCESS_INIT;\n>> +       struct strbuf sb = STRBUF_INIT;\n>\n> [...]\n>\n>> +       if (!capture_command(&cp_rev, &sb, 0)) {\n>> +               strbuf_strip_suffix(&sb, \"\\n\");\n>> +               if (argc) {\n>> +                       argv++;\n>> +                       argc--;\n>> +               }\n>> +       } else if (!argc || !strcmp(argv[0], \"HEAD\")) {\n>> +               /* before the first commit: compare with an empty tree */\n>> +               struct stat st;\n>> +               struct object_id oid;\n>> +               if (fstat(0, &st) < 0 || index_fd(oid.hash, 0, &st, 2, prefix, 3))\n>> +                       die(\"Unable to add %s to database\", oid.hash);\n>> +               strbuf_addstr(&sb, oid_to_hex(&oid));\n>> +               if (argc) {\n>> +                       argv++;\n>> +                       argc--;\n>> +               }\n>> +       } else {\n>> +               strbuf_addstr(&sb, \"HEAD\");\n>> +       }\n>> +\n>> +       if (files) {\n>> +               if (cached)\n>> +                       die(_(\"The --cached option cannot be used with the --files option\"));\n>> +               diff_cmd = \"diff-files\";\n>> +\n>> +               strbuf_reset(&sb);\n>\n> strbuf_reset() does not free the memory allocated to sb.buf...\n>\n>> +               sb.buf = NULL;\n>\n> ...then this makes sure that the memory previously allocated to sb.buf\n> will not be free()d.\n>\n> Maybe instead of the above 2 lines just: strbuf_release(&sb)\n> Or maybe just don't set sb.buf to NULL.\n>\n>> +       }\n>> +\n>> +       info.argc = argc;\n>> +       info.argv = argv;\n>> +       info.prefix = prefix;\n>> +       info.cached = !!cached;\n>> +       info.for_status = !!for_status;\n>> +       info.quiet = quiet;\n>> +       info.files = files;\n>> +       info.summary_limits = summary_limits;\n>> +       info.diff_cmd = diff_cmd;\n>> +\n>> +       return compute_summary_module_list(strbuf_detach(&sb, NULL), &info);\n>\n> Maybe you could pass: \"sb.len > 0 ? strbuf_detach(&sb, NULL) : NULL\"\n> This way if sb has previously been released or reset, NULL will be passed.\n>\n> I would suggest though to just pass sb.buf and to strbuf_release(&sb)\n> after calling compute_summary_module_list() and before returning from\n> module_summary() instead of having compute_summary_module_list() free\n> its first argument.\n> If you do that then compute_summary_module_list() should be changed so\n> that when it is passed \"\" it will behave in the same way as when it is\n> passed NULL.\n>\nWe can avoid it to behave same for \"\" and NULL, by checking if diff_cmd\nis \"cmd_diff_files\", since its value is set NULL by this case.\n\nret = compute_summary_module_list(strcmp(diff_cmd, \"diff-files\") ?\nNULL: sb.buf, &info);\nstrbuf_release(&sb);\n\ninstead of:\nret = compute_summary_module_list(sb.len ? sb.buf : NULL, &info);\nif (sb.len)\nstrbuf_release(&sb);\n\n>> +}\n"},{"id":"325639","messageId":"CAP8UFD2oqdaQqVwuGqqj9OOnm5Pyufpck=rod0UFQEWrROJsXQ@mail.gmail.com","threadId":"46490","inReplyTo":"CAME+mvUAspzuzbB4pFiQeOtT7NGRTO25M-k8o8hoysMFLGy_0w@mail.gmail.com","subject":"Re: [GSoC][PATCH 08/13] submodule: port submodule subcommand 'summary' from shell to C","fromName":"Christian Couder","fromEmail":"christian.couder@gmail.com","sentAt":"2017-08-05T16:55:53Z","receivedAt":"2017-08-05T16:55:58Z","isPatch":true,"sender":{"key":"christian.couder@gmail.com","avatar":"https://avatars.githubusercontent.com/u/208954?v=4"},"body":"On Sat, Aug 5, 2017 at 12:28 PM, Prathamesh Chavan <pc44800@gmail.com> wrote:\n> On Tue, Aug 1, 2017 at 4:57 AM, Christian Couder\n> <christian.couder@gmail.com> wrote:\n>> On Mon, Jul 31, 2017 at 10:56 PM, Prathamesh Chavan <pc44800@gmail.com> wrote:\n>>\n> We can avoid it to behave same for \"\" and NULL, by checking if diff_cmd\n> is \"cmd_diff_files\", since its value is set NULL by this case.\n>\n> ret = compute_summary_module_list(strcmp(diff_cmd, \"diff-files\") ?\n> NULL: sb.buf, &info);\n> strbuf_release(&sb);\n\nIt looks error prone, more fagile and less efficient to me.\n\n> instead of:\n> ret = compute_summary_module_list(sb.len ? sb.buf : NULL, &info);\n> if (sb.len)\n> strbuf_release(&sb);\n\nI think it is ok to call strbuf_release(&sb) many times, so the \"if\n(sb.len)\" check above is not needed.\n"},{"id":"325640","messageId":"CAME+mvXGK2zeCHgayS8=ti75CBY6Vp7Qkq+mgvWStQ+vEyLtPg@mail.gmail.com","threadId":"46490","inReplyTo":"CAP8UFD2oqdaQqVwuGqqj9OOnm5Pyufpck=rod0UFQEWrROJsXQ@mail.gmail.com","subject":"Re: [GSoC][PATCH 08/13] submodule: port submodule subcommand 'summary' from shell to C","fromName":"Prathamesh Chavan","fromEmail":"pc44800@gmail.com","sentAt":"2017-08-05T18:03:09Z","receivedAt":"2017-08-05T18:03:15Z","isPatch":true,"sender":{"key":"pc44800@gmail.com","avatar":"https://avatars.githubusercontent.com/u/17272661?v=4"},"body":"On Sat, Aug 5, 2017 at 10:25 PM, Christian Couder\n<christian.couder@gmail.com> wrote:\n> On Sat, Aug 5, 2017 at 12:28 PM, Prathamesh Chavan <pc44800@gmail.com> wrote:\n>> On Tue, Aug 1, 2017 at 4:57 AM, Christian Couder\n>> <christian.couder@gmail.com> wrote:\n>>> On Mon, Jul 31, 2017 at 10:56 PM, Prathamesh Chavan <pc44800@gmail.com> wrote:\n>>>\n>> We can avoid it to behave same for \"\" and NULL, by checking if diff_cmd\n>> is \"cmd_diff_files\", since its value is set NULL by this case.\n>>\n>> ret = compute_summary_module_list(strcmp(diff_cmd, \"diff-files\") ?\n>> NULL: sb.buf, &info);\n>> strbuf_release(&sb);\n>\n> It looks error prone, more fagile and less efficient to me.\n\nI think by using enum { DIFF_INDEX, DIFF_FILES },\nwe can avoid using strcmp() here, and make it more efficient\nnot only here but also in other parts of the code, since\nall such steps involving strcmp could be removed.\n\nThanks,\nPrathamesh Chavan\n"}]}