]> git.proxmox.com Git - libgit2.git/blob - src/remote.c
Fix the build on Emscripten
[libgit2.git] / src / remote.c
1 /*
2 * Copyright (C) 2009-2011 the libgit2 contributors
3 *
4 * This file is part of libgit2, distributed under the GNU GPL v2 with
5 * a Linking Exception. For full terms see the included COPYING file.
6 */
7
8 #include "git2/remote.h"
9 #include "git2/config.h"
10 #include "git2/types.h"
11
12 #include "config.h"
13 #include "repository.h"
14 #include "remote.h"
15 #include "fetch.h"
16 #include "refs.h"
17
18 static int refspec_parse(git_refspec *refspec, const char *str)
19 {
20 char *delim;
21
22 memset(refspec, 0x0, sizeof(git_refspec));
23
24 if (*str == '+') {
25 refspec->force = 1;
26 str++;
27 }
28
29 delim = strchr(str, ':');
30 if (delim == NULL)
31 return git__throw(GIT_EOBJCORRUPTED, "Failed to parse refspec. No ':'");
32
33 refspec->src = git__strndup(str, delim - str);
34 if (refspec->src == NULL)
35 return GIT_ENOMEM;
36
37 refspec->dst = git__strdup(delim + 1);
38 if (refspec->dst == NULL) {
39 git__free(refspec->src);
40 refspec->src = NULL;
41 return GIT_ENOMEM;
42 }
43
44 return GIT_SUCCESS;
45 }
46
47 static int parse_remote_refspec(git_config *cfg, git_refspec *refspec, const char *var)
48 {
49 const char *val;
50 int error;
51
52 error = git_config_get_string(cfg, var, &val);
53 if (error < GIT_SUCCESS)
54 return error;
55
56 return refspec_parse(refspec, val);
57 }
58
59 int git_remote_new(git_remote **out, git_repository *repo, const char *url, const char *name)
60 {
61 git_remote *remote;
62
63 /* name is optional */
64 assert(out && repo && url);
65
66 remote = git__malloc(sizeof(git_remote));
67 if (remote == NULL)
68 return GIT_ENOMEM;
69
70 memset(remote, 0x0, sizeof(git_remote));
71 remote->repo = repo;
72
73 if (git_vector_init(&remote->refs, 32, NULL) < 0) {
74 git_remote_free(remote);
75 return GIT_ENOMEM;
76 }
77
78 remote->url = git__strdup(url);
79 if (remote->url == NULL) {
80 git_remote_free(remote);
81 return GIT_ENOMEM;
82 }
83
84 if (name != NULL) {
85 remote->name = git__strdup(name);
86 if (remote->name == NULL) {
87 git_remote_free(remote);
88 return GIT_ENOMEM;
89 }
90 }
91
92 *out = remote;
93 return GIT_SUCCESS;
94 }
95
96 int git_remote_load(git_remote **out, git_repository *repo, const char *name)
97 {
98 git_remote *remote;
99 char *buf = NULL;
100 const char *val;
101 int ret, error, buf_len;
102 git_config *config;
103
104 assert(out && repo && name);
105
106 error = git_repository_config__weakptr(&config, repo);
107 if (error < GIT_SUCCESS)
108 return error;
109
110 remote = git__malloc(sizeof(git_remote));
111 if (remote == NULL)
112 return GIT_ENOMEM;
113
114 memset(remote, 0x0, sizeof(git_remote));
115 remote->name = git__strdup(name);
116 if (remote->name == NULL) {
117 error = GIT_ENOMEM;
118 goto cleanup;
119 }
120
121 if (git_vector_init(&remote->refs, 32, NULL) < 0) {
122 error = GIT_ENOMEM;
123 goto cleanup;
124 }
125
126 /* "fetch" is the longest var name we're interested in */
127 buf_len = strlen("remote.") + strlen(".fetch") + strlen(name) + 1;
128 buf = git__malloc(buf_len);
129 if (buf == NULL) {
130 error = GIT_ENOMEM;
131 goto cleanup;
132 }
133
134 ret = p_snprintf(buf, buf_len, "%s.%s.%s", "remote", name, "url");
135 if (ret < 0) {
136 error = git__throw(GIT_EOSERR, "Failed to build config var name");
137 goto cleanup;
138 }
139
140 error = git_config_get_string(config, buf, &val);
141 if (error < GIT_SUCCESS) {
142 error = git__rethrow(error, "Remote's url doesn't exist");
143 goto cleanup;
144 }
145
146 remote->repo = repo;
147 remote->url = git__strdup(val);
148 if (remote->url == NULL) {
149 error = GIT_ENOMEM;
150 goto cleanup;
151 }
152
153 ret = p_snprintf(buf, buf_len, "%s.%s.%s", "remote", name, "fetch");
154 if (ret < 0) {
155 error = git__throw(GIT_EOSERR, "Failed to build config var name");
156 goto cleanup;
157 }
158
159 error = parse_remote_refspec(config, &remote->fetch, buf);
160 if (error < GIT_SUCCESS) {
161 error = git__rethrow(error, "Failed to get fetch refspec");
162 goto cleanup;
163 }
164
165 ret = p_snprintf(buf, buf_len, "%s.%s.%s", "remote", name, "push");
166 if (ret < 0) {
167 error = git__throw(GIT_EOSERR, "Failed to build config var name");
168 goto cleanup;
169 }
170
171 error = parse_remote_refspec(config, &remote->push, buf);
172 /* Not finding push is fine */
173 if (error == GIT_ENOTFOUND)
174 error = GIT_SUCCESS;
175
176 if (error < GIT_SUCCESS)
177 goto cleanup;
178
179 *out = remote;
180
181 cleanup:
182 git__free(buf);
183
184 if (error < GIT_SUCCESS)
185 git_remote_free(remote);
186
187 return error;
188 }
189
190 const char *git_remote_name(git_remote *remote)
191 {
192 assert(remote);
193 return remote->name;
194 }
195
196 const char *git_remote_url(git_remote *remote)
197 {
198 assert(remote);
199 return remote->url;
200 }
201
202 const git_refspec *git_remote_fetchspec(git_remote *remote)
203 {
204 assert(remote);
205 return &remote->fetch;
206 }
207
208 const git_refspec *git_remote_pushspec(git_remote *remote)
209 {
210 assert(remote);
211 return &remote->push;
212 }
213
214 int git_remote_connect(git_remote *remote, int direction)
215 {
216 int error;
217 git_transport *t;
218
219 assert(remote);
220
221 error = git_transport_new(&t, remote->url);
222 if (error < GIT_SUCCESS)
223 return git__rethrow(error, "Failed to create transport");
224
225 error = t->connect(t, direction);
226 if (error < GIT_SUCCESS) {
227 error = git__rethrow(error, "Failed to connect the transport");
228 goto cleanup;
229 }
230
231 remote->transport = t;
232
233 cleanup:
234 if (error < GIT_SUCCESS)
235 t->free(t);
236
237 return error;
238 }
239
240 int git_remote_ls(git_remote *remote, git_headlist_cb list_cb, void *payload)
241 {
242 assert(remote);
243
244 if (!remote->transport || !remote->transport->connected)
245 return git__throw(GIT_ERROR, "The remote is not connected");
246
247 return remote->transport->ls(remote->transport, list_cb, payload);
248 }
249
250 int git_remote_download(char **filename, git_remote *remote)
251 {
252 int error;
253
254 assert(filename && remote);
255
256 if ((error = git_fetch_negotiate(remote)) < 0)
257 return git__rethrow(error, "Error negotiating");
258
259 return git_fetch_download_pack(filename, remote);
260 }
261
262 int git_remote_update_tips(git_remote *remote)
263 {
264 int error = GIT_SUCCESS;
265 unsigned int i = 0;
266 git_buf refname = GIT_BUF_INIT;
267 git_vector *refs = &remote->refs;
268 git_remote_head *head;
269 git_reference *ref;
270 struct git_refspec *spec = &remote->fetch;
271
272 assert(remote);
273
274 if (refs->length == 0)
275 return GIT_SUCCESS;
276
277 /* HEAD is only allowed to be the first in the list */
278 head = refs->contents[0];
279 if (!strcmp(head->name, GIT_HEAD_FILE)) {
280 error = git_reference_create_oid(&ref, remote->repo, GIT_FETCH_HEAD_FILE, &head->oid, 1);
281 i = 1;
282 if (error < GIT_SUCCESS)
283 return git__rethrow(error, "Failed to update FETCH_HEAD");
284
285 git_reference_free(ref);
286 }
287
288 for (; i < refs->length; ++i) {
289 head = refs->contents[i];
290
291 error = git_refspec_transform_r(&refname, spec, head->name);
292 if (error < GIT_SUCCESS)
293 break;
294
295 error = git_reference_create_oid(&ref, remote->repo, refname.ptr, &head->oid, 1);
296 if (error < GIT_SUCCESS)
297 break;
298
299 git_reference_free(ref);
300 }
301
302 git_buf_free(&refname);
303
304 return error;
305 }
306
307 int git_remote_connected(git_remote *remote)
308 {
309 assert(remote);
310 return remote->transport == NULL ? 0 : remote->transport->connected;
311 }
312
313 void git_remote_disconnect(git_remote *remote)
314 {
315 assert(remote);
316
317 if (remote->transport != NULL) {
318 if (remote->transport->connected)
319 remote->transport->close(remote->transport);
320
321 remote->transport->free(remote->transport);
322 remote->transport = NULL;
323 }
324 }
325
326 void git_remote_free(git_remote *remote)
327 {
328 if (remote == NULL)
329 return;
330
331 git__free(remote->fetch.src);
332 git__free(remote->fetch.dst);
333 git__free(remote->push.src);
334 git__free(remote->push.dst);
335 git__free(remote->url);
336 git__free(remote->name);
337 git_vector_free(&remote->refs);
338 git_remote_disconnect(remote);
339 git__free(remote);
340 }