submodule init: initialize active submodules
[gitweb.git] / builtin / submodule--helper.c
index 4beeda5f9f49d6c2e2f552308b50bacf70ebd421..65208faa7fb4cb139326b5f8b984e315faf268d0 100644 (file)
@@ -270,6 +270,29 @@ static int module_list_compute(int argc, const char **argv,
        return result;
 }
 
+static void module_list_active(struct module_list *list)
+{
+       int i;
+       struct module_list active_modules = MODULE_LIST_INIT;
+
+       gitmodules_config();
+
+       for (i = 0; i < list->nr; i++) {
+               const struct cache_entry *ce = list->entries[i];
+
+               if (!is_submodule_initialized(ce->name))
+                       continue;
+
+               ALLOC_GROW(active_modules.entries,
+                          active_modules.nr + 1,
+                          active_modules.alloc);
+               active_modules.entries[active_modules.nr++] = ce;
+       }
+
+       free(list->entries);
+       *list = active_modules;
+}
+
 static int module_list(int argc, const char **argv, const char *prefix)
 {
        int i;
@@ -317,8 +340,12 @@ static void init_submodule(const char *path, const char *prefix, int quiet)
        /* Only loads from .gitmodules, no overlay with .git/config */
        gitmodules_config();
 
-       if (prefix) {
-               strbuf_addf(&sb, "%s%s", prefix, path);
+       if (prefix && get_super_prefix())
+               die("BUG: cannot have prefix and superprefix");
+       else if (prefix)
+               displaypath = xstrdup(relative_path(path, prefix, &sb));
+       else if (get_super_prefix()) {
+               strbuf_addf(&sb, "%s%s", get_super_prefix(), path);
                displaypath = strbuf_detach(&sb, NULL);
        } else
                displaypath = xstrdup(path);
@@ -352,12 +379,10 @@ static void init_submodule(const char *path, const char *prefix, int quiet)
                        strbuf_addf(&remotesb, "remote.%s.url", remote);
                        free(remote);
 
-                       if (git_config_get_string(remotesb.buf, &remoteurl))
-                               /*
-                                * The repository is its own
-                                * authoritative upstream
-                                */
+                       if (git_config_get_string(remotesb.buf, &remoteurl)) {
+                               warning(_("could not lookup configuration '%s'. Assuming this repository is its own authoritative upstream."), remotesb.buf);
                                remoteurl = xgetcwd();
+                       }
                        relurl = relative_url(remoteurl, url, NULL);
                        strbuf_release(&remotesb);
                        free(remoteurl);
@@ -403,9 +428,6 @@ static int module_init(int argc, const char **argv, const char *prefix)
        int i;
 
        struct option module_init_options[] = {
-               OPT_STRING(0, "prefix", &prefix,
-                          N_("path"),
-                          N_("alternative anchor for relative paths")),
                OPT__QUIET(&quiet, N_("Suppress output for initializing a submodule")),
                OPT_END()
        };
@@ -421,6 +443,13 @@ static int module_init(int argc, const char **argv, const char *prefix)
        if (module_list_compute(argc, argv, prefix, &pathspec, &list) < 0)
                return 1;
 
+       /*
+        * If there are no path args and submodule.active is set then,
+        * by default, only initialize 'active' modules.
+        */
+       if (!argc && git_config_get_value_multi("submodule.active"))
+               module_list_active(&list);
+
        for (i = 0; i < list.nr; i++)
                init_submodule(list.entries[i]->name, prefix, quiet);
 
@@ -498,9 +527,9 @@ static int add_possible_reference_from_superproject(
 
        /*
         * If the alternate object store is another repository, try the
-        * standard layout with .git/modules/<name>/objects
+        * standard layout with .git/(modules/<name>)+/objects
         */
-       if (ends_with(alt->path, ".git/objects")) {
+       if (ends_with(alt->path, "/objects")) {
                char *sm_alternate;
                struct strbuf sb = STRBUF_INIT;
                struct strbuf err = STRBUF_INIT;
@@ -583,6 +612,7 @@ static int module_clone(int argc, const char **argv, const char *prefix)
        struct strbuf rel_path = STRBUF_INIT;
        struct strbuf sb = STRBUF_INIT;
        struct string_list reference = STRING_LIST_INIT_NODUP;
+       char *sm_alternate = NULL, *error_strategy = NULL;
 
        struct option module_clone_options[] = {
                OPT_STRING(0, "prefix", &prefix,
@@ -624,7 +654,7 @@ static int module_clone(int argc, const char **argv, const char *prefix)
                                   module_clone_options);
 
        strbuf_addf(&sb, "%s/modules/%s", get_git_dir(), name);
-       sm_gitdir = xstrdup(absolute_path(sb.buf));
+       sm_gitdir = absolute_pathdup(sb.buf);
        strbuf_reset(&sb);
 
        if (!is_absolute_path(path)) {
@@ -672,6 +702,20 @@ static int module_clone(int argc, const char **argv, const char *prefix)
                die(_("could not get submodule directory for '%s'"), path);
        git_config_set_in_file(p, "core.worktree",
                               relative_path(path, sm_gitdir, &rel_path));
+
+       /* setup alternateLocation and alternateErrorStrategy in the cloned submodule if needed */
+       git_config_get_string("submodule.alternateLocation", &sm_alternate);
+       if (sm_alternate)
+               git_config_set_in_file(p, "submodule.alternateLocation",
+                                          sm_alternate);
+       git_config_get_string("submodule.alternateErrorStrategy", &error_strategy);
+       if (error_strategy)
+               git_config_set_in_file(p, "submodule.alternateErrorStrategy",
+                                          error_strategy);
+
+       free(sm_alternate);
+       free(error_strategy);
+
        strbuf_release(&sb);
        strbuf_release(&rel_path);
        free(sm_gitdir);
@@ -745,7 +789,6 @@ static int prepare_to_clone_next_submodule(const struct cache_entry *ce,
        struct strbuf displaypath_sb = STRBUF_INIT;
        struct strbuf sb = STRBUF_INIT;
        const char *displaypath = NULL;
-       char *url = NULL;
        int needs_cloning = 0;
 
        if (ce_stage(ce)) {
@@ -779,15 +822,8 @@ static int prepare_to_clone_next_submodule(const struct cache_entry *ce,
                goto cleanup;
        }
 
-       /*
-        * Looking up the url in .git/config.
-        * We must not fall back to .gitmodules as we only want
-        * to process configured submodules.
-        */
-       strbuf_reset(&sb);
-       strbuf_addf(&sb, "submodule.%s.url", sub->name);
-       git_config_get_string(sb.buf, &url);
-       if (!url) {
+       /* Check if the submodule has been initialized. */
+       if (!is_submodule_initialized(ce->name)) {
                next_submodule_warn_missing(suc, out, displaypath);
                goto cleanup;
        }
@@ -821,7 +857,7 @@ static int prepare_to_clone_next_submodule(const struct cache_entry *ce,
                argv_array_push(&child->args, "--depth=1");
        argv_array_pushl(&child->args, "--path", sub->path, NULL);
        argv_array_pushl(&child->args, "--name", sub->name, NULL);
-       argv_array_pushl(&child->args, "--url", url, NULL);
+       argv_array_pushl(&child->args, "--url", sub->url, NULL);
        if (suc->references.nr) {
                struct string_list_item *item;
                for_each_string_list_item(item, &suc->references)
@@ -831,7 +867,6 @@ static int prepare_to_clone_next_submodule(const struct cache_entry *ce,
                argv_array_push(&child->args, suc->depth);
 
 cleanup:
-       free(url);
        strbuf_reset(&displaypath_sb);
        strbuf_reset(&sb);
 
@@ -1076,21 +1111,73 @@ static int resolve_remote_submodule_branch(int argc, const char **argv,
        return 0;
 }
 
+static int absorb_git_dirs(int argc, const char **argv, const char *prefix)
+{
+       int i;
+       struct pathspec pathspec;
+       struct module_list list = MODULE_LIST_INIT;
+       unsigned flags = ABSORB_GITDIR_RECURSE_SUBMODULES;
+
+       struct option embed_gitdir_options[] = {
+               OPT_STRING(0, "prefix", &prefix,
+                          N_("path"),
+                          N_("path into the working tree")),
+               OPT_BIT(0, "--recursive", &flags, N_("recurse into submodules"),
+                       ABSORB_GITDIR_RECURSE_SUBMODULES),
+               OPT_END()
+       };
+
+       const char *const git_submodule_helper_usage[] = {
+               N_("git submodule--helper embed-git-dir [<path>...]"),
+               NULL
+       };
+
+       argc = parse_options(argc, argv, prefix, embed_gitdir_options,
+                            git_submodule_helper_usage, 0);
+
+       gitmodules_config();
+       git_config(submodule_config, NULL);
+
+       if (module_list_compute(argc, argv, prefix, &pathspec, &list) < 0)
+               return 1;
+
+       for (i = 0; i < list.nr; i++)
+               absorb_git_dir_into_superproject(prefix,
+                               list.entries[i]->name, flags);
+
+       return 0;
+}
+
+static int is_active(int argc, const char **argv, const char *prefix)
+{
+       if (argc != 2)
+               die("submodule--helper is-active takes exactly 1 arguments");
+
+       gitmodules_config();
+
+       return !is_submodule_initialized(argv[1]);
+}
+
+#define SUPPORT_SUPER_PREFIX (1<<0)
+
 struct cmd_struct {
        const char *cmd;
        int (*fn)(int, const char **, const char *);
+       unsigned option;
 };
 
 static struct cmd_struct commands[] = {
-       {"list", module_list},
-       {"name", module_name},
-       {"clone", module_clone},
-       {"update-clone", update_clone},
-       {"relative-path", resolve_relative_path},
-       {"resolve-relative-url", resolve_relative_url},
-       {"resolve-relative-url-test", resolve_relative_url_test},
-       {"init", module_init},
-       {"remote-branch", resolve_remote_submodule_branch}
+       {"list", module_list, 0},
+       {"name", module_name, 0},
+       {"clone", module_clone, 0},
+       {"update-clone", update_clone, 0},
+       {"relative-path", resolve_relative_path, 0},
+       {"resolve-relative-url", resolve_relative_url, 0},
+       {"resolve-relative-url-test", resolve_relative_url_test, 0},
+       {"init", module_init, SUPPORT_SUPER_PREFIX},
+       {"remote-branch", resolve_remote_submodule_branch, 0},
+       {"absorb-git-dirs", absorb_git_dirs, SUPPORT_SUPER_PREFIX},
+       {"is-active", is_active, 0},
 };
 
 int cmd_submodule__helper(int argc, const char **argv, const char *prefix)
@@ -1100,9 +1187,15 @@ int cmd_submodule__helper(int argc, const char **argv, const char *prefix)
                die(_("submodule--helper subcommand must be "
                      "called with a subcommand"));
 
-       for (i = 0; i < ARRAY_SIZE(commands); i++)
-               if (!strcmp(argv[1], commands[i].cmd))
+       for (i = 0; i < ARRAY_SIZE(commands); i++) {
+               if (!strcmp(argv[1], commands[i].cmd)) {
+                       if (get_super_prefix() &&
+                           !(commands[i].option & SUPPORT_SUPER_PREFIX))
+                               die(_("%s doesn't support --super-prefix"),
+                                   commands[i].cmd);
                        return commands[i].fn(argc - 1, argv + 1, prefix);
+               }
+       }
 
        die(_("'%s' is not a valid submodule--helper "
              "subcommand"), argv[1]);