Merge branch 'ms/submodule-foreach-fix'
authorJunio C Hamano <gitster@pobox.com>
Tue, 9 Jul 2019 22:25:46 +0000 (15:25 -0700)
committerJunio C Hamano <gitster@pobox.com>
Tue, 9 Jul 2019 22:25:46 +0000 (15:25 -0700)
"git submodule foreach" did not protect command line options passed
to the command to be run in each submodule correctly, when the
"--recursive" option was in use.

* ms/submodule-foreach-fix:
submodule foreach: fix recursion of options

1  2 
builtin/submodule--helper.c
t/t7407-submodule-foreach.sh
index 13da32d3b736f00e2e41aa4729f1f2422c94439e,61a5bfb1f2be0e3e31ffe99987dc3bff4b055ee6..909e77e802d3302c2486aeb1646fe953d81a0a92
@@@ -1,4 -1,3 +1,4 @@@
 +#define USE_THE_INDEX_COMPATIBILITY_MACROS
  #include "builtin.h"
  #include "repository.h"
  #include "cache.h"
@@@ -348,7 -347,7 +348,7 @@@ static int module_list_compute(int argc
                        i++;
        }
  
 -      if (ps_matched && report_path_error(ps_matched, pathspec, prefix))
 +      if (ps_matched && report_path_error(ps_matched, pathspec))
                result = -1;
  
        free(ps_matched);
@@@ -540,6 -539,7 +540,7 @@@ static void runcommand_in_submodule_cb(
                if (info->quiet)
                        argv_array_push(&cpr.args, "--quiet");
  
+               argv_array_push(&cpr.args, "--");
                argv_array_pushv(&cpr.args, info->argv);
  
                if (run_command(&cpr))
@@@ -566,12 -566,12 +567,12 @@@ static int module_foreach(int argc, con
        };
  
        const char *const git_submodule_helper_usage[] = {
 -              N_("git submodule--helper foreach [--quiet] [--recursive] <command>"),
 +              N_("git submodule--helper foreach [--quiet] [--recursive] [--] <command>"),
                NULL
        };
  
        argc = parse_options(argc, argv, prefix, module_foreach_options,
 -                           git_submodule_helper_usage, PARSE_OPT_KEEP_UNKNOWN);
 +                           git_submodule_helper_usage, 0);
  
        if (module_list_compute(0, NULL, prefix, &pathspec, &list) < 0)
                return 1;
@@@ -709,7 -709,7 +710,7 @@@ static int module_init(int argc, const 
        };
  
        const char *const git_submodule_helper_usage[] = {
 -              N_("git submodule--helper init [<path>]"),
 +              N_("git submodule--helper init [<options>] [<path>]"),
                NULL
        };
  
@@@ -1132,8 -1132,6 +1133,8 @@@ static void deinit_submodule(const cha
                if (!(flags & OPT_QUIET))
                        printf(format, displaypath);
  
 +              submodule_unset_core_worktree(sub);
 +
                strbuf_release(&sb_rm);
        }
  
@@@ -1268,20 -1266,19 +1269,20 @@@ struct submodule_alternate_setup 
        SUBMODULE_ALTERNATE_ERROR_IGNORE, NULL }
  
  static int add_possible_reference_from_superproject(
 -              struct alternate_object_database *alt, void *sas_cb)
 +              struct object_directory *odb, void *sas_cb)
  {
        struct submodule_alternate_setup *sas = sas_cb;
 +      size_t len;
  
        /*
         * If the alternate object store is another repository, try the
         * standard layout with .git/(modules/<name>)+/objects
         */
 -      if (ends_with(alt->path, "/objects")) {
 +      if (strip_suffix(odb->path, "/objects", &len)) {
                char *sm_alternate;
                struct strbuf sb = STRBUF_INIT;
                struct strbuf err = STRBUF_INIT;
 -              strbuf_add(&sb, alt->path, strlen(alt->path) - strlen("objects"));
 +              strbuf_add(&sb, odb->path, len);
  
                /*
                 * We need to end the new path with '/' to mark it as a dir,
                 * as the last part of a missing submodule reference would
                 * be taken as a file name.
                 */
 -              strbuf_addf(&sb, "modules/%s/", sas->submodule_name);
 +              strbuf_addf(&sb, "/modules/%s/", sas->submodule_name);
  
                sm_alternate = compute_alternate_path(sb.buf, &err);
                if (sm_alternate) {
                                die(_("submodule '%s' cannot add alternate: %s"),
                                    sas->submodule_name, err.buf);
                        case SUBMODULE_ALTERNATE_ERROR_INFO:
 -                              fprintf(stderr, _("submodule '%s' cannot add alternate: %s"),
 +                              fprintf_ln(stderr, _("submodule '%s' cannot add alternate: %s"),
                                        sas->submodule_name, err.buf);
                        case SUBMODULE_ALTERNATE_ERROR_IGNORE:
                                ; /* nothing */
@@@ -1555,7 -1552,7 +1556,7 @@@ struct submodule_update_clone 
  #define SUBMODULE_UPDATE_CLONE_INIT {0, MODULE_LIST_INIT, 0, \
        SUBMODULE_UPDATE_STRATEGY_INIT, 0, 0, -1, STRING_LIST_INIT_DUP, 0, \
        NULL, NULL, NULL, \
 -      NULL, 0, 0, 0, NULL, 0, 0, 0}
 +      NULL, 0, 0, 0, NULL, 0, 0, 1}
  
  
  static void next_submodule_warn_missing(struct submodule_update_clone *suc,
@@@ -1816,10 -1813,11 +1817,10 @@@ static int update_submodules(struct sub
  {
        int i;
  
 -      run_processes_parallel(suc->max_jobs,
 -                             update_clone_get_next_task,
 -                             update_clone_start_failure,
 -                             update_clone_task_finished,
 -                             suc);
 +      run_processes_parallel_tr2(suc->max_jobs, update_clone_get_next_task,
 +                                 update_clone_start_failure,
 +                                 update_clone_task_finished, suc, "submodule",
 +                                 "parallel/update");
  
        /*
         * We saved the output and put it out all at once now.
@@@ -2048,7 -2046,7 +2049,7 @@@ static int ensure_core_worktree(int arg
        struct repository subrepo;
  
        if (argc != 2)
 -              BUG("submodule--helper connect-gitdir-workingtree <name> <path>");
 +              BUG("submodule--helper ensure-core-worktree <path>");
  
        path = argv[1];
  
        if (!sub)
                BUG("We could get the submodule handle before?");
  
 -      if (repo_submodule_init(&subrepo, the_repository, path))
 +      if (repo_submodule_init(&subrepo, the_repository, sub))
                die(_("could not get a repository handle for submodule '%s'"), path);
  
        if (!repo_config_get_string(&subrepo, "core.worktree", &cw)) {
@@@ -2096,7 -2094,7 +2097,7 @@@ static int absorb_git_dirs(int argc, co
        };
  
        const char *const git_submodule_helper_usage[] = {
 -              N_("git submodule--helper embed-git-dir [<path>...]"),
 +              N_("git submodule--helper absorb-git-dirs [<options>] [<path>...]"),
                NULL
        };
  
                return 1;
  
        for (i = 0; i < list.nr; i++)
 -              absorb_git_dir_into_superproject(prefix,
 -                              list.entries[i]->name, flags);
 +              absorb_git_dir_into_superproject(list.entries[i]->name, flags);
  
        return 0;
  }
@@@ -2146,22 -2145,17 +2147,22 @@@ static int check_name(int argc, const c
  static int module_config(int argc, const char **argv, const char *prefix)
  {
        enum {
 -              CHECK_WRITEABLE = 1
 +              CHECK_WRITEABLE = 1,
 +              DO_UNSET = 2
        } command = 0;
  
        struct option module_config_options[] = {
                OPT_CMDMODE(0, "check-writeable", &command,
                            N_("check if it is safe to write to the .gitmodules file"),
                            CHECK_WRITEABLE),
 +              OPT_CMDMODE(0, "unset", &command,
 +                          N_("unset the config in the .gitmodules file"),
 +                          DO_UNSET),
                OPT_END()
        };
        const char *const git_submodule_helper_usage[] = {
 -              N_("git submodule--helper config name [value]"),
 +              N_("git submodule--helper config <name> [<value>]"),
 +              N_("git submodule--helper config --unset <name>"),
                N_("git submodule--helper config --check-writeable"),
                NULL
        };
                return is_writing_gitmodules_ok() ? 0 : -1;
  
        /* Equivalent to ACTION_GET in builtin/config.c */
 -      if (argc == 2)
 +      if (argc == 2 && command != DO_UNSET)
                return print_config_from_gitmodules(the_repository, argv[1]);
  
        /* Equivalent to ACTION_SET in builtin/config.c */
 -      if (argc == 3) {
 +      if (argc == 3 || (argc == 2 && command == DO_UNSET)) {
 +              const char *value = (argc == 3) ? argv[2] : NULL;
 +
                if (!is_writing_gitmodules_ok())
                        die(_("please make sure that the .gitmodules file is in the working tree"));
  
 -              return config_set_in_gitmodules_file_gently(argv[1], argv[2]);
 +              return config_set_in_gitmodules_file_gently(argv[1], value);
        }
  
        usage_with_options(git_submodule_helper_usage, module_config_options);
index 706ae762e0ec2fd0103f7f6788eff13ec86ebd67,57e4b7f990d60cd5789a31f0ae20738196191c1d..6b2aa917e11871eb403c8c79725b1e1944f8d29f
@@@ -411,14 -411,11 +411,21 @@@ test_expect_success 'multi-argument com
        test_cmp expected actual
  '
  
 +test_expect_success 'option-like arguments passed to foreach commands are not lost' '
 +      (
 +              cd super &&
 +              git submodule foreach "echo be --quiet" > ../expected &&
 +              git submodule foreach echo be --quiet > ../actual
 +      ) &&
 +      grep -sq -e "--quiet" expected &&
 +      test_cmp expected actual
 +'
 +
+ test_expect_success 'option-like arguments passed to foreach recurse correctly' '
+       git -C clone2 submodule foreach --recursive "echo be --an-option" >expect &&
+       git -C clone2 submodule foreach --recursive echo be --an-option >actual &&
+       grep -e "--an-option" expect &&
+       test_cmp expect actual
+ '
  test_done