]> git.ipfire.org Git - thirdparty/git.git/blobdiff - submodule.c
submodule: migrate get_next_submodule to use repository structs
[thirdparty/git.git] / submodule.c
index 6415cc55807c7ed9ee4cbcaa57f41a5804b6e854..77ace5e784a73623abe59ae95f03729de27f412d 100644 (file)
@@ -25,7 +25,6 @@
 #include "commit-reach.h"
 
 static int config_update_recurse_submodules = RECURSE_SUBMODULES_OFF;
-static struct string_list changed_submodule_names = STRING_LIST_INIT_DUP;
 static int initialized_fetch_ref_tips;
 static struct oid_array ref_tips_before_fetch;
 static struct oid_array ref_tips_after_fetch;
@@ -1136,11 +1135,11 @@ void check_for_new_submodule_commits(struct object_id *oid)
        oid_array_append(&ref_tips_after_fetch, oid);
 }
 
-static void calculate_changed_submodule_paths(struct repository *r)
+static void calculate_changed_submodule_paths(struct repository *r,
+               struct string_list *changed_submodule_names)
 {
        struct argv_array argv = ARGV_ARRAY_INIT;
-       struct string_list changed_submodules = STRING_LIST_INIT_DUP;
-       const struct string_list_item *name;
+       struct string_list_item *name;
 
        /* No need to check if there are no submodules configured */
        if (!submodule_from_path(r, NULL, NULL))
@@ -1157,9 +1156,9 @@ static void calculate_changed_submodule_paths(struct repository *r)
         * Collect all submodules (whether checked out or not) for which new
         * commits have been recorded upstream in "changed_submodule_names".
         */
-       collect_changed_submodules(r, &changed_submodules, &argv);
+       collect_changed_submodules(r, changed_submodule_names, &argv);
 
-       for_each_string_list_item(name, &changed_submodules) {
+       for_each_string_list_item(name, changed_submodule_names) {
                struct oid_array *commits = name->util;
                const struct submodule *submodule;
                const char *path = NULL;
@@ -1173,11 +1172,14 @@ static void calculate_changed_submodule_paths(struct repository *r)
                if (!path)
                        continue;
 
-               if (!submodule_has_commits(r, path, commits))
-                       string_list_append(&changed_submodule_names, name->string);
+               if (submodule_has_commits(r, path, commits)) {
+                       oid_array_clear(commits);
+                       *name->string = '\0';
+               }
        }
 
-       free_submodules_oids(&changed_submodules);
+       string_list_remove_empty_items(changed_submodule_names, 1);
+
        argv_array_clear(&argv);
        oid_array_clear(&ref_tips_before_fetch);
        oid_array_clear(&ref_tips_after_fetch);
@@ -1221,8 +1223,10 @@ struct submodule_parallel_fetch {
        int default_option;
        int quiet;
        int result;
+
+       struct string_list changed_submodule_names;
 };
-#define SPF_INIT {0, ARGV_ARRAY_INIT, NULL, NULL, 0, 0, 0, 0}
+#define SPF_INIT {0, ARGV_ARRAY_INIT, NULL, NULL, 0, 0, 0, 0, STRING_LIST_INIT_DUP }
 
 static int get_fetch_recurse_config(const struct submodule *submodule,
                                    struct submodule_parallel_fetch *spf)
@@ -1249,6 +1253,30 @@ static int get_fetch_recurse_config(const struct submodule *submodule,
        return spf->default_option;
 }
 
+static struct repository *get_submodule_repo_for(struct repository *r,
+                                                const struct submodule *sub)
+{
+       struct repository *ret = xmalloc(sizeof(*ret));
+
+       if (repo_submodule_init(ret, r, sub)) {
+               /*
+                * No entry in .gitmodules? Technically not a submodule,
+                * but historically we supported repositories that happen to be
+                * in-place where a gitlink is. Keep supporting them.
+                */
+               struct strbuf gitdir = STRBUF_INIT;
+               strbuf_repo_worktree_path(&gitdir, r, "%s/.git", sub->path);
+               if (repo_init(ret, gitdir.buf, NULL)) {
+                       strbuf_release(&gitdir);
+                       free(ret);
+                       return NULL;
+               }
+               strbuf_release(&gitdir);
+       }
+
+       return ret;
+}
+
 static int get_next_submodule(struct child_process *cp,
                              struct strbuf *err, void *data, void **task_cb)
 {
@@ -1256,12 +1284,11 @@ static int get_next_submodule(struct child_process *cp,
        struct submodule_parallel_fetch *spf = data;
 
        for (; spf->count < spf->r->index->cache_nr; spf->count++) {
-               struct strbuf submodule_path = STRBUF_INIT;
-               struct strbuf submodule_git_dir = STRBUF_INIT;
                struct strbuf submodule_prefix = STRBUF_INIT;
                const struct cache_entry *ce = spf->r->index->cache[spf->count];
-               const char *git_dir, *default_argv;
+               const char *default_argv;
                const struct submodule *submodule;
+               struct repository *repo;
                struct submodule default_submodule = SUBMODULE_INIT;
 
                if (!S_ISGITLINK(ce->ce_mode))
@@ -1271,7 +1298,8 @@ static int get_next_submodule(struct child_process *cp,
                if (!submodule) {
                        const char *name = default_name_or_path(ce->name);
                        if (name) {
-                               default_submodule.path = default_submodule.name = name;
+                               default_submodule.path = name;
+                               default_submodule.name = name;
                                submodule = &default_submodule;
                        }
                }
@@ -1281,8 +1309,10 @@ static int get_next_submodule(struct child_process *cp,
                default:
                case RECURSE_SUBMODULES_DEFAULT:
                case RECURSE_SUBMODULES_ON_DEMAND:
-                       if (!submodule || !unsorted_string_list_lookup(&changed_submodule_names,
-                                                        submodule->name))
+                       if (!submodule ||
+                           !string_list_lookup(
+                                       &spf->changed_submodule_names,
+                                       submodule->name))
                                continue;
                        default_argv = "on-demand";
                        break;
@@ -1293,15 +1323,11 @@ static int get_next_submodule(struct child_process *cp,
                        continue;
                }
 
-               strbuf_repo_worktree_path(&submodule_path, spf->r, "%s", ce->name);
-               strbuf_addf(&submodule_git_dir, "%s/.git", submodule_path.buf);
                strbuf_addf(&submodule_prefix, "%s%s/", spf->prefix, ce->name);
-               git_dir = read_gitfile(submodule_git_dir.buf);
-               if (!git_dir)
-                       git_dir = submodule_git_dir.buf;
-               if (is_directory(git_dir)) {
+               repo = get_submodule_repo_for(spf->r, submodule);
+               if (repo) {
                        child_process_init(cp);
-                       cp->dir = strbuf_detach(&submodule_path, NULL);
+                       cp->dir = xstrdup(repo->worktree);
                        prepare_submodule_repo_env(&cp->env_array);
                        cp->git_cmd = 1;
                        if (!spf->quiet)
@@ -1312,10 +1338,23 @@ static int get_next_submodule(struct child_process *cp,
                        argv_array_push(&cp->args, default_argv);
                        argv_array_push(&cp->args, "--submodule-prefix");
                        argv_array_push(&cp->args, submodule_prefix.buf);
+
+                       repo_clear(repo);
+                       free(repo);
                        ret = 1;
+               } else {
+                       /*
+                        * An empty directory is normal,
+                        * the submodule is not initialized
+                        */
+                       if (S_ISGITLINK(ce->ce_mode) &&
+                           !is_empty_dir(ce->name)) {
+                               spf->result = 1;
+                               strbuf_addf(err,
+                                           _("Could not access submodule '%s'"),
+                                           ce->name);
+                       }
                }
-               strbuf_release(&submodule_path);
-               strbuf_release(&submodule_git_dir);
                strbuf_release(&submodule_prefix);
                if (ret) {
                        spf->count++;
@@ -1373,7 +1412,8 @@ int fetch_populated_submodules(struct repository *r,
        argv_array_push(&spf.args, "--recurse-submodules-default");
        /* default value, "--submodule-prefix" and its value are added later */
 
-       calculate_changed_submodule_paths(r);
+       calculate_changed_submodule_paths(r, &spf.changed_submodule_names);
+       string_list_sort(&spf.changed_submodule_names);
        run_processes_parallel(max_parallel_jobs,
                               get_next_submodule,
                               fetch_start_failure,
@@ -1382,7 +1422,7 @@ int fetch_populated_submodules(struct repository *r,
 
        argv_array_clear(&spf.args);
 out:
-       string_list_clear(&changed_submodule_names, 1);
+       free_submodules_oids(&spf.changed_submodule_names);
        return spf.result;
 }