9411c4baee2f49e7ce561bc3e142e4bffd521733
   1#include "cache.h"
   2#include "repository.h"
   3#include "object-store.h"
   4#include "config.h"
   5#include "object.h"
   6#include "lockfile.h"
   7#include "submodule-config.h"
   8
   9/* The main repository */
  10static struct repository the_repo;
  11struct repository *the_repository;
  12
  13void initialize_the_repository(void)
  14{
  15        the_repository = &the_repo;
  16
  17        the_repo.index = &the_index;
  18        the_repo.objects = raw_object_store_new();
  19        the_repo.parsed_objects = parsed_object_pool_new();
  20
  21        repo_set_hash_algo(&the_repo, GIT_HASH_SHA1);
  22}
  23
  24static void expand_base_dir(char **out, const char *in,
  25                            const char *base_dir, const char *def_in)
  26{
  27        free(*out);
  28        if (in)
  29                *out = xstrdup(in);
  30        else
  31                *out = xstrfmt("%s/%s", base_dir, def_in);
  32}
  33
  34static void repo_set_commondir(struct repository *repo,
  35                               const char *commondir)
  36{
  37        struct strbuf sb = STRBUF_INIT;
  38
  39        free(repo->commondir);
  40
  41        if (commondir) {
  42                repo->different_commondir = 1;
  43                repo->commondir = xstrdup(commondir);
  44                return;
  45        }
  46
  47        repo->different_commondir = get_common_dir_noenv(&sb, repo->gitdir);
  48        repo->commondir = strbuf_detach(&sb, NULL);
  49}
  50
  51void repo_set_gitdir(struct repository *repo,
  52                     const char *root,
  53                     const struct set_gitdir_args *o)
  54{
  55        const char *gitfile = read_gitfile(root);
  56        /*
  57         * repo->gitdir is saved because the caller could pass "root"
  58         * that also points to repo->gitdir. We want to keep it alive
  59         * until after xstrdup(root). Then we can free it.
  60         */
  61        char *old_gitdir = repo->gitdir;
  62
  63        repo->gitdir = xstrdup(gitfile ? gitfile : root);
  64        free(old_gitdir);
  65
  66        repo_set_commondir(repo, o->commondir);
  67
  68        if (!repo->objects->odb) {
  69                repo->objects->odb = xcalloc(1, sizeof(*repo->objects->odb));
  70                repo->objects->odb_tail = &repo->objects->odb->next;
  71        }
  72        expand_base_dir(&repo->objects->odb->path, o->object_dir,
  73                        repo->commondir, "objects");
  74
  75        free(repo->objects->alternate_db);
  76        repo->objects->alternate_db = xstrdup_or_null(o->alternate_db);
  77        expand_base_dir(&repo->graft_file, o->graft_file,
  78                        repo->commondir, "info/grafts");
  79        expand_base_dir(&repo->index_file, o->index_file,
  80                        repo->gitdir, "index");
  81}
  82
  83void repo_set_hash_algo(struct repository *repo, int hash_algo)
  84{
  85        repo->hash_algo = &hash_algos[hash_algo];
  86}
  87
  88/*
  89 * Attempt to resolve and set the provided 'gitdir' for repository 'repo'.
  90 * Return 0 upon success and a non-zero value upon failure.
  91 */
  92static int repo_init_gitdir(struct repository *repo, const char *gitdir)
  93{
  94        int ret = 0;
  95        int error = 0;
  96        char *abspath = NULL;
  97        const char *resolved_gitdir;
  98        struct set_gitdir_args args = { NULL };
  99
 100        abspath = real_pathdup(gitdir, 0);
 101        if (!abspath) {
 102                ret = -1;
 103                goto out;
 104        }
 105
 106        /* 'gitdir' must reference the gitdir directly */
 107        resolved_gitdir = resolve_gitdir_gently(abspath, &error);
 108        if (!resolved_gitdir) {
 109                ret = -1;
 110                goto out;
 111        }
 112
 113        repo_set_gitdir(repo, resolved_gitdir, &args);
 114
 115out:
 116        free(abspath);
 117        return ret;
 118}
 119
 120void repo_set_worktree(struct repository *repo, const char *path)
 121{
 122        repo->worktree = real_pathdup(path, 1);
 123}
 124
 125static int read_and_verify_repository_format(struct repository_format *format,
 126                                             const char *commondir)
 127{
 128        int ret = 0;
 129        struct strbuf sb = STRBUF_INIT;
 130
 131        strbuf_addf(&sb, "%s/config", commondir);
 132        read_repository_format(format, sb.buf);
 133        strbuf_reset(&sb);
 134
 135        if (verify_repository_format(format, &sb) < 0) {
 136                warning("%s", sb.buf);
 137                ret = -1;
 138        }
 139
 140        strbuf_release(&sb);
 141        return ret;
 142}
 143
 144/*
 145 * Initialize 'repo' based on the provided 'gitdir'.
 146 * Return 0 upon success and a non-zero value upon failure.
 147 */
 148int repo_init(struct repository *repo,
 149              const char *gitdir,
 150              const char *worktree)
 151{
 152        struct repository_format format;
 153        memset(repo, 0, sizeof(*repo));
 154
 155        repo->objects = raw_object_store_new();
 156        repo->parsed_objects = parsed_object_pool_new();
 157
 158        if (repo_init_gitdir(repo, gitdir))
 159                goto error;
 160
 161        if (read_and_verify_repository_format(&format, repo->commondir))
 162                goto error;
 163
 164        repo_set_hash_algo(repo, format.hash_algo);
 165
 166        if (worktree)
 167                repo_set_worktree(repo, worktree);
 168
 169        return 0;
 170
 171error:
 172        repo_clear(repo);
 173        return -1;
 174}
 175
 176/*
 177 * Initialize 'submodule' as the submodule given by 'path' in parent repository
 178 * 'superproject'.
 179 * Return 0 upon success and a non-zero value upon failure.
 180 */
 181int repo_submodule_init(struct repository *submodule,
 182                        struct repository *superproject,
 183                        const char *path)
 184{
 185        const struct submodule *sub;
 186        struct strbuf gitdir = STRBUF_INIT;
 187        struct strbuf worktree = STRBUF_INIT;
 188        int ret = 0;
 189
 190        sub = submodule_from_path(superproject, &null_oid, path);
 191        if (!sub) {
 192                ret = -1;
 193                goto out;
 194        }
 195
 196        strbuf_repo_worktree_path(&gitdir, superproject, "%s/.git", path);
 197        strbuf_repo_worktree_path(&worktree, superproject, "%s", path);
 198
 199        if (repo_init(submodule, gitdir.buf, worktree.buf)) {
 200                /*
 201                 * If initilization fails then it may be due to the submodule
 202                 * not being populated in the superproject's worktree.  Instead
 203                 * we can try to initilize the submodule by finding it's gitdir
 204                 * in the superproject's 'modules' directory.  In this case the
 205                 * submodule would not have a worktree.
 206                 */
 207                strbuf_reset(&gitdir);
 208                strbuf_repo_git_path(&gitdir, superproject,
 209                                     "modules/%s", sub->name);
 210
 211                if (repo_init(submodule, gitdir.buf, NULL)) {
 212                        ret = -1;
 213                        goto out;
 214                }
 215        }
 216
 217        submodule->submodule_prefix = xstrfmt("%s%s/",
 218                                              superproject->submodule_prefix ?
 219                                              superproject->submodule_prefix :
 220                                              "", path);
 221
 222out:
 223        strbuf_release(&gitdir);
 224        strbuf_release(&worktree);
 225        return ret;
 226}
 227
 228void repo_clear(struct repository *repo)
 229{
 230        FREE_AND_NULL(repo->gitdir);
 231        FREE_AND_NULL(repo->commondir);
 232        FREE_AND_NULL(repo->graft_file);
 233        FREE_AND_NULL(repo->index_file);
 234        FREE_AND_NULL(repo->worktree);
 235        FREE_AND_NULL(repo->submodule_prefix);
 236
 237        raw_object_store_clear(repo->objects);
 238        FREE_AND_NULL(repo->objects);
 239
 240        parsed_object_pool_clear(repo->parsed_objects);
 241        FREE_AND_NULL(repo->parsed_objects);
 242
 243        if (repo->config) {
 244                git_configset_clear(repo->config);
 245                FREE_AND_NULL(repo->config);
 246        }
 247
 248        if (repo->submodule_cache) {
 249                submodule_cache_free(repo->submodule_cache);
 250                repo->submodule_cache = NULL;
 251        }
 252
 253        if (repo->index) {
 254                discard_index(repo->index);
 255                if (repo->index != &the_index)
 256                        FREE_AND_NULL(repo->index);
 257        }
 258}
 259
 260int repo_read_index(struct repository *repo)
 261{
 262        if (!repo->index)
 263                repo->index = xcalloc(1, sizeof(*repo->index));
 264
 265        return read_index_from(repo->index, repo->index_file, repo->gitdir);
 266}
 267
 268int repo_hold_locked_index(struct repository *repo,
 269                           struct lock_file *lf,
 270                           int flags)
 271{
 272        if (!repo->index_file)
 273                BUG("the repo hasn't been setup");
 274        return hold_lock_file_for_update(lf, repo->index_file, flags);
 275}