repository: introduce the repository object
[git] / repository.c
1 #include "cache.h"
2 #include "repository.h"
3
4 /* The main repository */
5 static struct repository the_repo;
6 struct repository *the_repository = &the_repo;
7
8 static 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
20 static 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
33 static 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
48 void 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  */
67 static 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
89 out:
90         free(abspath);
91         return ret;
92 }
93
94 void repo_set_worktree(struct repository *repo, const char *path)
95 {
96         repo->worktree = real_pathdup(path, 1);
97 }
98
99 static 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  */
122 int 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
140 error:
141         repo_clear(repo);
142         return -1;
143 }
144
145 void 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 }