cf440405a81e6f39e0d2fd459fabe0e8fee5dc2e
   1#include "cache.h"
   2#include "repository.h"
   3
   4/* The main repository */
   5static struct repository the_repo;
   6struct repository *the_repository = &the_repo;
   7
   8static char *git_path_from_env(const char *envvar, const char *git_dir,
   9                               const char *path, int fromenv)
  10{
  11        if (fromenv) {
  12                const char *value = getenv(envvar);
  13                if (value)
  14                        return xstrdup(value);
  15        }
  16
  17        return xstrfmt("%s/%s", git_dir, path);
  18}
  19
  20static int find_common_dir(struct strbuf *sb, const char *gitdir, int fromenv)
  21{
  22        if (fromenv) {
  23                const char *value = getenv(GIT_COMMON_DIR_ENVIRONMENT);
  24                if (value) {
  25                        strbuf_addstr(sb, value);
  26                        return 1;
  27                }
  28        }
  29
  30        return get_common_dir_noenv(sb, gitdir);
  31}
  32
  33static void repo_setup_env(struct repository *repo)
  34{
  35        struct strbuf sb = STRBUF_INIT;
  36
  37        repo->different_commondir = find_common_dir(&sb, repo->gitdir,
  38                                                    !repo->ignore_env);
  39        repo->commondir = strbuf_detach(&sb, NULL);
  40        repo->objectdir = git_path_from_env(DB_ENVIRONMENT, repo->commondir,
  41                                            "objects", !repo->ignore_env);
  42        repo->graft_file = git_path_from_env(GRAFT_ENVIRONMENT, repo->commondir,
  43                                             "info/grafts", !repo->ignore_env);
  44        repo->index_file = git_path_from_env(INDEX_ENVIRONMENT, repo->gitdir,
  45                                             "index", !repo->ignore_env);
  46}
  47
  48void repo_set_gitdir(struct repository *repo, const char *path)
  49{
  50        const char *gitfile = read_gitfile(path);
  51
  52        /*
  53         * NEEDSWORK: Eventually we want to be able to free gitdir and the rest
  54         * of the environment before reinitializing it again, but we have some
  55         * crazy code paths where we try to set gitdir with the current gitdir
  56         * and we don't want to free gitdir before copying the passed in value.
  57         */
  58        repo->gitdir = xstrdup(gitfile ? gitfile : path);
  59
  60        repo_setup_env(repo);
  61}
  62
  63/*
  64 * Attempt to resolve and set the provided 'gitdir' for repository 'repo'.
  65 * Return 0 upon success and a non-zero value upon failure.
  66 */
  67static int repo_init_gitdir(struct repository *repo, const char *gitdir)
  68{
  69        int ret = 0;
  70        int error = 0;
  71        char *abspath = NULL;
  72        const char *resolved_gitdir;
  73
  74        abspath = real_pathdup(gitdir, 0);
  75        if (!abspath) {
  76                ret = -1;
  77                goto out;
  78        }
  79
  80        /* 'gitdir' must reference the gitdir directly */
  81        resolved_gitdir = resolve_gitdir_gently(abspath, &error);
  82        if (!resolved_gitdir) {
  83                ret = -1;
  84                goto out;
  85        }
  86
  87        repo_set_gitdir(repo, resolved_gitdir);
  88
  89out:
  90        free(abspath);
  91        return ret;
  92}
  93
  94void repo_set_worktree(struct repository *repo, const char *path)
  95{
  96        repo->worktree = real_pathdup(path, 1);
  97}
  98
  99static int read_and_verify_repository_format(struct repository_format *format,
 100                                             const char *commondir)
 101{
 102        int ret = 0;
 103        struct strbuf sb = STRBUF_INIT;
 104
 105        strbuf_addf(&sb, "%s/config", commondir);
 106        read_repository_format(format, sb.buf);
 107        strbuf_reset(&sb);
 108
 109        if (verify_repository_format(format, &sb) < 0) {
 110                warning("%s", sb.buf);
 111                ret = -1;
 112        }
 113
 114        strbuf_release(&sb);
 115        return ret;
 116}
 117
 118/*
 119 * Initialize 'repo' based on the provided 'gitdir'.
 120 * Return 0 upon success and a non-zero value upon failure.
 121 */
 122int repo_init(struct repository *repo, const char *gitdir, const char *worktree)
 123{
 124        struct repository_format format;
 125        memset(repo, 0, sizeof(*repo));
 126
 127        repo->ignore_env = 1;
 128
 129        if (repo_init_gitdir(repo, gitdir))
 130                goto error;
 131
 132        if (read_and_verify_repository_format(&format, repo->commondir))
 133                goto error;
 134
 135        if (worktree)
 136                repo_set_worktree(repo, worktree);
 137
 138        return 0;
 139
 140error:
 141        repo_clear(repo);
 142        return -1;
 143}
 144
 145void repo_clear(struct repository *repo)
 146{
 147        free(repo->gitdir);
 148        repo->gitdir = NULL;
 149        free(repo->commondir);
 150        repo->commondir = NULL;
 151        free(repo->objectdir);
 152        repo->objectdir = NULL;
 153        free(repo->graft_file);
 154        repo->graft_file = NULL;
 155        free(repo->index_file);
 156        repo->index_file = NULL;
 157        free(repo->worktree);
 158        repo->worktree = NULL;
 159}