Merge branch 'nd/parseopt-completion'
[gitweb.git] / repository.c
index cf440405a81e6f39e0d2fd459fabe0e8fee5dc2e..4ffbe9bc94edc18314cb49c945038e2f20a40922 100644 (file)
@@ -1,8 +1,12 @@
 #include "cache.h"
 #include "repository.h"
+#include "config.h"
+#include "submodule-config.h"
 
 /* The main repository */
-static struct repository the_repo;
+static struct repository the_repo = {
+       NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, &the_index, &hash_algos[GIT_HASH_SHA1], 0, 0
+};
 struct repository *the_repository = &the_repo;
 
 static char *git_path_from_env(const char *envvar, const char *git_dir,
@@ -36,11 +40,15 @@ static void repo_setup_env(struct repository *repo)
 
        repo->different_commondir = find_common_dir(&sb, repo->gitdir,
                                                    !repo->ignore_env);
+       free(repo->commondir);
        repo->commondir = strbuf_detach(&sb, NULL);
+       free(repo->objectdir);
        repo->objectdir = git_path_from_env(DB_ENVIRONMENT, repo->commondir,
                                            "objects", !repo->ignore_env);
+       free(repo->graft_file);
        repo->graft_file = git_path_from_env(GRAFT_ENVIRONMENT, repo->commondir,
                                             "info/grafts", !repo->ignore_env);
+       free(repo->index_file);
        repo->index_file = git_path_from_env(INDEX_ENVIRONMENT, repo->gitdir,
                                             "index", !repo->ignore_env);
 }
@@ -48,16 +56,17 @@ static void repo_setup_env(struct repository *repo)
 void repo_set_gitdir(struct repository *repo, const char *path)
 {
        const char *gitfile = read_gitfile(path);
+       char *old_gitdir = repo->gitdir;
 
-       /*
-        * NEEDSWORK: Eventually we want to be able to free gitdir and the rest
-        * of the environment before reinitializing it again, but we have some
-        * crazy code paths where we try to set gitdir with the current gitdir
-        * and we don't want to free gitdir before copying the passed in value.
-        */
        repo->gitdir = xstrdup(gitfile ? gitfile : path);
-
        repo_setup_env(repo);
+
+       free(old_gitdir);
+}
+
+void repo_set_hash_algo(struct repository *repo, int hash_algo)
+{
+       repo->hash_algo = &hash_algos[hash_algo];
 }
 
 /*
@@ -132,6 +141,8 @@ int repo_init(struct repository *repo, const char *gitdir, const char *worktree)
        if (read_and_verify_repository_format(&format, repo->commondir))
                goto error;
 
+       repo_set_hash_algo(repo, format.hash_algo);
+
        if (worktree)
                repo_set_worktree(repo, worktree);
 
@@ -142,18 +153,88 @@ int repo_init(struct repository *repo, const char *gitdir, const char *worktree)
        return -1;
 }
 
+/*
+ * Initialize 'submodule' as the submodule given by 'path' in parent repository
+ * 'superproject'.
+ * Return 0 upon success and a non-zero value upon failure.
+ */
+int repo_submodule_init(struct repository *submodule,
+                       struct repository *superproject,
+                       const char *path)
+{
+       const struct submodule *sub;
+       struct strbuf gitdir = STRBUF_INIT;
+       struct strbuf worktree = STRBUF_INIT;
+       int ret = 0;
+
+       sub = submodule_from_cache(superproject, &null_oid, path);
+       if (!sub) {
+               ret = -1;
+               goto out;
+       }
+
+       strbuf_repo_worktree_path(&gitdir, superproject, "%s/.git", path);
+       strbuf_repo_worktree_path(&worktree, superproject, "%s", path);
+
+       if (repo_init(submodule, gitdir.buf, worktree.buf)) {
+               /*
+                * If initilization fails then it may be due to the submodule
+                * not being populated in the superproject's worktree.  Instead
+                * we can try to initilize the submodule by finding it's gitdir
+                * in the superproject's 'modules' directory.  In this case the
+                * submodule would not have a worktree.
+                */
+               strbuf_reset(&gitdir);
+               strbuf_repo_git_path(&gitdir, superproject,
+                                    "modules/%s", sub->name);
+
+               if (repo_init(submodule, gitdir.buf, NULL)) {
+                       ret = -1;
+                       goto out;
+               }
+       }
+
+       submodule->submodule_prefix = xstrfmt("%s%s/",
+                                             superproject->submodule_prefix ?
+                                             superproject->submodule_prefix :
+                                             "", path);
+
+out:
+       strbuf_release(&gitdir);
+       strbuf_release(&worktree);
+       return ret;
+}
+
 void repo_clear(struct repository *repo)
 {
-       free(repo->gitdir);
-       repo->gitdir = NULL;
-       free(repo->commondir);
-       repo->commondir = NULL;
-       free(repo->objectdir);
-       repo->objectdir = NULL;
-       free(repo->graft_file);
-       repo->graft_file = NULL;
-       free(repo->index_file);
-       repo->index_file = NULL;
-       free(repo->worktree);
-       repo->worktree = NULL;
+       FREE_AND_NULL(repo->gitdir);
+       FREE_AND_NULL(repo->commondir);
+       FREE_AND_NULL(repo->objectdir);
+       FREE_AND_NULL(repo->graft_file);
+       FREE_AND_NULL(repo->index_file);
+       FREE_AND_NULL(repo->worktree);
+       FREE_AND_NULL(repo->submodule_prefix);
+
+       if (repo->config) {
+               git_configset_clear(repo->config);
+               FREE_AND_NULL(repo->config);
+       }
+
+       if (repo->submodule_cache) {
+               submodule_cache_free(repo->submodule_cache);
+               repo->submodule_cache = NULL;
+       }
+
+       if (repo->index) {
+               discard_index(repo->index);
+               FREE_AND_NULL(repo->index);
+       }
+}
+
+int repo_read_index(struct repository *repo)
+{
+       if (!repo->index)
+               repo->index = xcalloc(1, sizeof(*repo->index));
+
+       return read_index_from(repo->index, repo->index_file, repo->gitdir);
 }