52f1821c6b4c871c86699add1cc88956424173ea
   1#include "cache.h"
   2#include "repository.h"
   3#include "config.h"
   4#include "submodule-config.h"
   5
   6/* The main repository */
   7static struct repository the_repo = {
   8        NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, &the_index, 0, 0
   9};
  10struct repository *the_repository = &the_repo;
  11
  12static char *git_path_from_env(const char *envvar, const char *git_dir,
  13                               const char *path, int fromenv)
  14{
  15        if (fromenv) {
  16                const char *value = getenv(envvar);
  17                if (value)
  18                        return xstrdup(value);
  19        }
  20
  21        return xstrfmt("%s/%s", git_dir, path);
  22}
  23
  24static int find_common_dir(struct strbuf *sb, const char *gitdir, int fromenv)
  25{
  26        if (fromenv) {
  27                const char *value = getenv(GIT_COMMON_DIR_ENVIRONMENT);
  28                if (value) {
  29                        strbuf_addstr(sb, value);
  30                        return 1;
  31                }
  32        }
  33
  34        return get_common_dir_noenv(sb, gitdir);
  35}
  36
  37static void repo_setup_env(struct repository *repo)
  38{
  39        struct strbuf sb = STRBUF_INIT;
  40
  41        repo->different_commondir = find_common_dir(&sb, repo->gitdir,
  42                                                    !repo->ignore_env);
  43        free(repo->commondir);
  44        repo->commondir = strbuf_detach(&sb, NULL);
  45        free(repo->objectdir);
  46        repo->objectdir = git_path_from_env(DB_ENVIRONMENT, repo->commondir,
  47                                            "objects", !repo->ignore_env);
  48        free(repo->graft_file);
  49        repo->graft_file = git_path_from_env(GRAFT_ENVIRONMENT, repo->commondir,
  50                                             "info/grafts", !repo->ignore_env);
  51        free(repo->index_file);
  52        repo->index_file = git_path_from_env(INDEX_ENVIRONMENT, repo->gitdir,
  53                                             "index", !repo->ignore_env);
  54}
  55
  56void repo_set_gitdir(struct repository *repo, const char *path)
  57{
  58        const char *gitfile = read_gitfile(path);
  59
  60        /*
  61         * NEEDSWORK: Eventually we want to be able to free gitdir and the rest
  62         * of the environment before reinitializing it again, but we have some
  63         * crazy code paths where we try to set gitdir with the current gitdir
  64         * and we don't want to free gitdir before copying the passed in value.
  65         */
  66        repo->gitdir = xstrdup(gitfile ? gitfile : path);
  67
  68        repo_setup_env(repo);
  69}
  70
  71/*
  72 * Attempt to resolve and set the provided 'gitdir' for repository 'repo'.
  73 * Return 0 upon success and a non-zero value upon failure.
  74 */
  75static int repo_init_gitdir(struct repository *repo, const char *gitdir)
  76{
  77        int ret = 0;
  78        int error = 0;
  79        char *abspath = NULL;
  80        const char *resolved_gitdir;
  81
  82        abspath = real_pathdup(gitdir, 0);
  83        if (!abspath) {
  84                ret = -1;
  85                goto out;
  86        }
  87
  88        /* 'gitdir' must reference the gitdir directly */
  89        resolved_gitdir = resolve_gitdir_gently(abspath, &error);
  90        if (!resolved_gitdir) {
  91                ret = -1;
  92                goto out;
  93        }
  94
  95        repo_set_gitdir(repo, resolved_gitdir);
  96
  97out:
  98        free(abspath);
  99        return ret;
 100}
 101
 102void repo_set_worktree(struct repository *repo, const char *path)
 103{
 104        repo->worktree = real_pathdup(path, 1);
 105}
 106
 107static int read_and_verify_repository_format(struct repository_format *format,
 108                                             const char *commondir)
 109{
 110        int ret = 0;
 111        struct strbuf sb = STRBUF_INIT;
 112
 113        strbuf_addf(&sb, "%s/config", commondir);
 114        read_repository_format(format, sb.buf);
 115        strbuf_reset(&sb);
 116
 117        if (verify_repository_format(format, &sb) < 0) {
 118                warning("%s", sb.buf);
 119                ret = -1;
 120        }
 121
 122        strbuf_release(&sb);
 123        return ret;
 124}
 125
 126/*
 127 * Initialize 'repo' based on the provided 'gitdir'.
 128 * Return 0 upon success and a non-zero value upon failure.
 129 */
 130int repo_init(struct repository *repo, const char *gitdir, const char *worktree)
 131{
 132        struct repository_format format;
 133        memset(repo, 0, sizeof(*repo));
 134
 135        repo->ignore_env = 1;
 136
 137        if (repo_init_gitdir(repo, gitdir))
 138                goto error;
 139
 140        if (read_and_verify_repository_format(&format, repo->commondir))
 141                goto error;
 142
 143        if (worktree)
 144                repo_set_worktree(repo, worktree);
 145
 146        return 0;
 147
 148error:
 149        repo_clear(repo);
 150        return -1;
 151}
 152
 153/*
 154 * Initialize 'submodule' as the submodule given by 'path' in parent repository
 155 * 'superproject'.
 156 * Return 0 upon success and a non-zero value upon failure.
 157 */
 158int repo_submodule_init(struct repository *submodule,
 159                        struct repository *superproject,
 160                        const char *path)
 161{
 162        const struct submodule *sub;
 163        struct strbuf gitdir = STRBUF_INIT;
 164        struct strbuf worktree = STRBUF_INIT;
 165        int ret = 0;
 166
 167        sub = submodule_from_cache(superproject, &null_oid, path);
 168        if (!sub) {
 169                ret = -1;
 170                goto out;
 171        }
 172
 173        strbuf_repo_worktree_path(&gitdir, superproject, "%s/.git", path);
 174        strbuf_repo_worktree_path(&worktree, superproject, "%s", path);
 175
 176        if (repo_init(submodule, gitdir.buf, worktree.buf)) {
 177                /*
 178                 * If initilization fails then it may be due to the submodule
 179                 * not being populated in the superproject's worktree.  Instead
 180                 * we can try to initilize the submodule by finding it's gitdir
 181                 * in the superproject's 'modules' directory.  In this case the
 182                 * submodule would not have a worktree.
 183                 */
 184                strbuf_reset(&gitdir);
 185                strbuf_repo_git_path(&gitdir, superproject,
 186                                     "modules/%s", sub->name);
 187
 188                if (repo_init(submodule, gitdir.buf, NULL)) {
 189                        ret = -1;
 190                        goto out;
 191                }
 192        }
 193
 194        submodule->submodule_prefix = xstrfmt("%s%s/",
 195                                              superproject->submodule_prefix ?
 196                                              superproject->submodule_prefix :
 197                                              "", path);
 198
 199out:
 200        strbuf_release(&gitdir);
 201        strbuf_release(&worktree);
 202        return ret;
 203}
 204
 205void repo_clear(struct repository *repo)
 206{
 207        free(repo->gitdir);
 208        repo->gitdir = NULL;
 209        free(repo->commondir);
 210        repo->commondir = NULL;
 211        free(repo->objectdir);
 212        repo->objectdir = NULL;
 213        free(repo->graft_file);
 214        repo->graft_file = NULL;
 215        free(repo->index_file);
 216        repo->index_file = NULL;
 217        free(repo->worktree);
 218        repo->worktree = NULL;
 219        free(repo->submodule_prefix);
 220        repo->submodule_prefix = NULL;
 221
 222        if (repo->config) {
 223                git_configset_clear(repo->config);
 224                free(repo->config);
 225                repo->config = NULL;
 226        }
 227
 228        if (repo->submodule_cache) {
 229                submodule_cache_free(repo->submodule_cache);
 230                repo->submodule_cache = NULL;
 231        }
 232
 233        if (repo->index) {
 234                discard_index(repo->index);
 235                free(repo->index);
 236                repo->index = NULL;
 237        }
 238}
 239
 240int repo_read_index(struct repository *repo)
 241{
 242        if (!repo->index)
 243                repo->index = xcalloc(1, sizeof(*repo->index));
 244
 245        return read_index_from(repo->index, repo->index_file);
 246}