sha1_file: teach sha1_object_info_extended more flags
[gitweb.git] / submodule.c
index c9e764b5193adb22fad644b74a4f84cb0645ed55..1b8a3b575db6c85a42e9c9e285617113ecac4a84 100644 (file)
@@ -16,6 +16,7 @@
 #include "quote.h"
 #include "remote.h"
 #include "worktree.h"
+#include "parse-options.h"
 
 static int config_fetch_recurse_submodules = RECURSE_SUBMODULES_ON_DEMAND;
 static int config_update_recurse_submodules = RECURSE_SUBMODULES_OFF;
@@ -153,7 +154,8 @@ void set_diffopt_flags_from_submodule_config(struct diff_options *diffopt,
        }
 }
 
-int submodule_config(const char *var, const char *value, void *cb)
+/* For loading from the .gitmodules file. */
+static int git_modules_config(const char *var, const char *value, void *cb)
 {
        if (!strcmp(var, "submodule.fetchjobs")) {
                parallel_jobs = git_config_int(var, value);
@@ -169,6 +171,30 @@ int submodule_config(const char *var, const char *value, void *cb)
        return 0;
 }
 
+/* Loads all submodule settings from the config. */
+int submodule_config(const char *var, const char *value, void *cb)
+{
+       if (!strcmp(var, "submodule.recurse")) {
+               int v = git_config_bool(var, value) ?
+                       RECURSE_SUBMODULES_ON : RECURSE_SUBMODULES_OFF;
+               config_update_recurse_submodules = v;
+               return 0;
+       } else {
+               return git_modules_config(var, value, cb);
+       }
+}
+
+/* Cheap function that only determines if we're interested in submodules at all */
+int git_default_submodule_config(const char *var, const char *value, void *cb)
+{
+       if (!strcmp(var, "submodule.recurse")) {
+               int v = git_config_bool(var, value) ?
+                       RECURSE_SUBMODULES_ON : RECURSE_SUBMODULES_OFF;
+               config_update_recurse_submodules = v;
+       }
+       return 0;
+}
+
 int option_parse_recurse_submodules_worktree_updater(const struct option *opt,
                                                     const char *arg, int unset)
 {
@@ -222,7 +248,8 @@ void gitmodules_config(void)
                }
 
                if (!gitmodules_is_unmerged)
-                       git_config_from_file(submodule_config, gitmodules_path.buf, NULL);
+                       git_config_from_file(git_modules_config,
+                               gitmodules_path.buf, NULL);
                strbuf_release(&gitmodules_path);
        }
 }
@@ -233,7 +260,7 @@ void gitmodules_config_sha1(const unsigned char *commit_sha1)
        unsigned char sha1[20];
 
        if (gitmodule_sha1_from_commit(commit_sha1, sha1, &rev)) {
-               git_config_from_blob_sha1(submodule_config, rev.buf,
+               git_config_from_blob_sha1(git_modules_config, rev.buf,
                                          sha1, NULL);
        }
        strbuf_release(&rev);
@@ -308,6 +335,69 @@ int is_submodule_populated_gently(const char *path, int *return_error_code)
        return ret;
 }
 
+/*
+ * Dies if the provided 'prefix' corresponds to an unpopulated submodule
+ */
+void die_in_unpopulated_submodule(const struct index_state *istate,
+                                 const char *prefix)
+{
+       int i, prefixlen;
+
+       if (!prefix)
+               return;
+
+       prefixlen = strlen(prefix);
+
+       for (i = 0; i < istate->cache_nr; i++) {
+               struct cache_entry *ce = istate->cache[i];
+               int ce_len = ce_namelen(ce);
+
+               if (!S_ISGITLINK(ce->ce_mode))
+                       continue;
+               if (prefixlen <= ce_len)
+                       continue;
+               if (strncmp(ce->name, prefix, ce_len))
+                       continue;
+               if (prefix[ce_len] != '/')
+                       continue;
+
+               die(_("in unpopulated submodule '%s'"), ce->name);
+       }
+}
+
+/*
+ * Dies if any paths in the provided pathspec descends into a submodule
+ */
+void die_path_inside_submodule(const struct index_state *istate,
+                              const struct pathspec *ps)
+{
+       int i, j;
+
+       for (i = 0; i < istate->cache_nr; i++) {
+               struct cache_entry *ce = istate->cache[i];
+               int ce_len = ce_namelen(ce);
+
+               if (!S_ISGITLINK(ce->ce_mode))
+                       continue;
+
+               for (j = 0; j < ps->nr ; j++) {
+                       const struct pathspec_item *item = &ps->items[j];
+
+                       if (item->len <= ce_len)
+                               continue;
+                       if (item->match[ce_len] != '/')
+                               continue;
+                       if (strncmp(ce->name, item->match, ce_len))
+                               continue;
+                       if (item->len == ce_len + 1)
+                               continue;
+
+                       die(_("Pathspec '%s' is in submodule '%.*s'"),
+                           item->original, ce_len, ce->name);
+               }
+       }
+}
+
 int parse_submodule_update_strategy(const char *value,
                struct submodule_update_strategy *dst)
 {
@@ -473,8 +563,8 @@ static void show_submodule_header(FILE *f, const char *path,
         * Attempt to lookup the commit references, and determine if this is
         * a fast forward or fast backwards update.
         */
-       *left = lookup_commit_reference(one->hash);
-       *right = lookup_commit_reference(two->hash);
+       *left = lookup_commit_reference(one);
+       *right = lookup_commit_reference(two);
 
        /*
         * Warn about missing commits in the submodule project, but only if
@@ -580,7 +670,8 @@ void show_submodule_inline_diff(FILE *f, const char *path,
        cp.no_stdin = 1;
 
        /* TODO: other options may need to be passed here. */
-       argv_array_push(&cp.args, "diff");
+       argv_array_pushl(&cp.args, "diff", "--submodule=diff", NULL);
+
        argv_array_pushf(&cp.args, "--line-prefix=%s", line_prefix);
        if (DIFF_OPT_TST(o, REVERSE_DIFF)) {
                argv_array_pushf(&cp.args, "--src-prefix=%s%s/",
@@ -743,7 +834,7 @@ static int check_has_commit(const struct object_id *oid, void *data)
 {
        int *has_commit = data;
 
-       if (!lookup_commit_reference(oid->hash))
+       if (!lookup_commit_reference(oid))
                *has_commit = 0;
 
        return 0;
@@ -1377,7 +1468,7 @@ static int submodule_has_dirty_index(const struct submodule *sub)
 {
        struct child_process cp = CHILD_PROCESS_INIT;
 
-       prepare_submodule_repo_env_no_git_dir(&cp.env_array);
+       prepare_submodule_repo_env(&cp.env_array);
 
        cp.git_cmd = 1;
        argv_array_pushl(&cp.args, "diff-index", "--quiet",
@@ -1394,7 +1485,7 @@ static int submodule_has_dirty_index(const struct submodule *sub)
 static void submodule_reset_index(const char *path)
 {
        struct child_process cp = CHILD_PROCESS_INIT;
-       prepare_submodule_repo_env_no_git_dir(&cp.env_array);
+       prepare_submodule_repo_env(&cp.env_array);
 
        cp.git_cmd = 1;
        cp.no_stdin = 1;
@@ -1475,7 +1566,7 @@ int submodule_move_head(const char *path,
                }
        }
 
-       prepare_submodule_repo_env_no_git_dir(&cp.env_array);
+       prepare_submodule_repo_env(&cp.env_array);
 
        cp.git_cmd = 1;
        cp.no_stdin = 1;
@@ -1483,7 +1574,7 @@ int submodule_move_head(const char *path,
 
        argv_array_pushf(&cp.args, "--super-prefix=%s%s/",
                        get_super_prefix_or_empty(), path);
-       argv_array_pushl(&cp.args, "read-tree", NULL);
+       argv_array_pushl(&cp.args, "read-tree", "--recurse-submodules", NULL);
 
        if (flags & SUBMODULE_MOVE_HEAD_DRY_RUN)
                argv_array_push(&cp.args, "-n");
@@ -1505,15 +1596,16 @@ int submodule_move_head(const char *path,
 
        if (!(flags & SUBMODULE_MOVE_HEAD_DRY_RUN)) {
                if (new) {
-                       struct child_process cp1 = CHILD_PROCESS_INIT;
+                       child_process_init(&cp);
                        /* also set the HEAD accordingly */
-                       cp1.git_cmd = 1;
-                       cp1.no_stdin = 1;
-                       cp1.dir = path;
+                       cp.git_cmd = 1;
+                       cp.no_stdin = 1;
+                       cp.dir = path;
 
-                       argv_array_pushl(&cp1.args, "update-ref", "HEAD", new, NULL);
+                       prepare_submodule_repo_env(&cp.env_array);
+                       argv_array_pushl(&cp.args, "update-ref", "HEAD", new, NULL);
 
-                       if (run_command(&cp1)) {
+                       if (run_command(&cp)) {
                                ret = -1;
                                goto out;
                        }
@@ -1603,9 +1695,9 @@ static void print_commit(struct commit *commit)
 #define MERGE_WARNING(path, msg) \
        warning("Failed to merge submodule %s (%s)", path, msg);
 
-int merge_submodule(unsigned char result[20], const char *path,
-                   const unsigned char base[20], const unsigned char a[20],
-                   const unsigned char b[20], int search)
+int merge_submodule(struct object_id *result, const char *path,
+                   const struct object_id *base, const struct object_id *a,
+                   const struct object_id *b, int search)
 {
        struct commit *commit_base, *commit_a, *commit_b;
        int parent_count;
@@ -1614,14 +1706,14 @@ int merge_submodule(unsigned char result[20], const char *path,
        int i;
 
        /* store a in result in case we fail */
-       hashcpy(result, a);
+       oidcpy(result, a);
 
        /* we can not handle deletion conflicts */
-       if (is_null_sha1(base))
+       if (is_null_oid(base))
                return 0;
-       if (is_null_sha1(a))
+       if (is_null_oid(a))
                return 0;
-       if (is_null_sha1(b))
+       if (is_null_oid(b))
                return 0;
 
        if (add_submodule_odb(path)) {
@@ -1645,11 +1737,11 @@ int merge_submodule(unsigned char result[20], const char *path,
 
        /* Case #1: a is contained in b or vice versa */
        if (in_merge_bases(commit_a, commit_b)) {
-               hashcpy(result, b);
+               oidcpy(result, b);
                return 1;
        }
        if (in_merge_bases(commit_b, commit_a)) {
-               hashcpy(result, a);
+               oidcpy(result, a);
                return 1;
        }