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