]> git.proxmox.com Git - libgit2.git/blame - src/remote.c
Merge pull request #672 from scottjg/more-mingw32-fixes
[libgit2.git] / src / remote.c
CommitLineData
9c82357b 1/*
5e0de328 2 * Copyright (C) 2009-2012 the libgit2 contributors
9c82357b 3 *
bb742ede
VM
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.
9c82357b
CMN
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"
e1d88030 15#include "fetch.h"
441f57c2 16#include "refs.h"
9c82357b 17
8171998f
CMN
18#include <regex.h>
19
9c82357b
CMN
20static int refspec_parse(git_refspec *refspec, const char *str)
21{
22 char *delim;
23
24 memset(refspec, 0x0, sizeof(git_refspec));
25
26 if (*str == '+') {
27 refspec->force = 1;
28 str++;
29 }
30
31 delim = strchr(str, ':');
4376f7f6
CMN
32 if (delim == NULL) {
33 giterr_set(GITERR_NET, "Invalid refspec, missing ':'");
34 return -1;
35 }
9c82357b
CMN
36
37 refspec->src = git__strndup(str, delim - str);
4376f7f6 38 GITERR_CHECK_ALLOC(refspec->src);
9c82357b
CMN
39
40 refspec->dst = git__strdup(delim + 1);
4376f7f6 41 GITERR_CHECK_ALLOC(refspec->dst);
9c82357b 42
4376f7f6 43 return 0;
9c82357b
CMN
44}
45
46static int parse_remote_refspec(git_config *cfg, git_refspec *refspec, const char *var)
47{
9c82357b 48 int error;
4376f7f6 49 const char *val;
9c82357b 50
4376f7f6 51 if ((error = git_config_get_string(cfg, var, &val)) < 0)
9c82357b
CMN
52 return error;
53
2dc31040 54 return refspec_parse(refspec, val);
9c82357b
CMN
55}
56
617bfdf4 57int git_remote_new(git_remote **out, git_repository *repo, const char *url, const char *name)
778e1c73
CMN
58{
59 git_remote *remote;
60
4bef3565
VM
61 /* name is optional */
62 assert(out && repo && url);
617bfdf4 63
778e1c73 64 remote = git__malloc(sizeof(git_remote));
4376f7f6 65 GITERR_CHECK_ALLOC(remote);
778e1c73
CMN
66
67 memset(remote, 0x0, sizeof(git_remote));
68 remote->repo = repo;
617bfdf4 69
4376f7f6
CMN
70 if (git_vector_init(&remote->refs, 32, NULL) < 0)
71 return -1;
d88d4311 72
778e1c73 73 remote->url = git__strdup(url);
4376f7f6 74 GITERR_CHECK_ALLOC(remote->url);
778e1c73 75
617bfdf4
CMN
76 if (name != NULL) {
77 remote->name = git__strdup(name);
4376f7f6 78 GITERR_CHECK_ALLOC(remote->name);
617bfdf4
CMN
79 }
80
778e1c73 81 *out = remote;
4376f7f6 82 return 0;
778e1c73
CMN
83}
84
9462c471 85int git_remote_load(git_remote **out, git_repository *repo, const char *name)
9c82357b
CMN
86{
87 git_remote *remote;
f0f3a18a 88 git_buf buf = GIT_BUF_INIT;
9c82357b 89 const char *val;
4376f7f6 90 int error = 0;
9462c471 91 git_config *config;
9c82357b 92
9462c471
VM
93 assert(out && repo && name);
94
4376f7f6
CMN
95 if (git_repository_config__weakptr(&config, repo) < 0)
96 return -1;
4bef3565 97
9c82357b 98 remote = git__malloc(sizeof(git_remote));
4376f7f6 99 GITERR_CHECK_ALLOC(remote);
9c82357b
CMN
100
101 memset(remote, 0x0, sizeof(git_remote));
102 remote->name = git__strdup(name);
4376f7f6 103 GITERR_CHECK_ALLOC(remote->name);
9c82357b 104
4376f7f6
CMN
105 if (git_vector_init(&remote->refs, 32, NULL) < 0)
106 return -1;
d88d4311 107
4376f7f6
CMN
108 if (git_buf_printf(&buf, "remote.%s.url", name) < 0)
109 return -1;
9c82357b 110
4376f7f6
CMN
111 if (git_config_get_string(config, git_buf_cstr(&buf), &val) < 0) {
112 error = -1;
9c82357b
CMN
113 goto cleanup;
114 }
115
9462c471 116 remote->repo = repo;
9c82357b 117 remote->url = git__strdup(val);
4376f7f6 118 GITERR_CHECK_ALLOC(remote->url);
9c82357b 119
f0f3a18a 120 git_buf_clear(&buf);
4376f7f6
CMN
121 if (git_buf_printf(&buf, "remote.%s.fetch", name) < 0)
122 return -1;
9c82357b 123
f0f3a18a 124 error = parse_remote_refspec(config, &remote->fetch, git_buf_cstr(&buf));
9554cd51 125 if (error == GIT_ENOTFOUND)
4376f7f6 126 error = 0;
9554cd51 127
4376f7f6
CMN
128 if (error < 0) {
129 error = -1;
9c82357b 130 goto cleanup;
2dc31040 131 }
9c82357b 132
f0f3a18a 133 git_buf_clear(&buf);
4376f7f6
CMN
134 if (git_buf_printf(&buf, "remote.%s.push", name) < 0)
135 return -1;
9c82357b 136
f0f3a18a 137 error = parse_remote_refspec(config, &remote->push, git_buf_cstr(&buf));
2dc31040 138 if (error == GIT_ENOTFOUND)
4376f7f6 139 error = 0;
9c82357b 140
4376f7f6
CMN
141 if (error < 0) {
142 error = -1;
9c82357b 143 goto cleanup;
4376f7f6 144 }
9c82357b
CMN
145
146 *out = remote;
147
148cleanup:
f0f3a18a 149 git_buf_free(&buf);
9462c471 150
4376f7f6 151 if (error < 0)
9c82357b
CMN
152 git_remote_free(remote);
153
154 return error;
155}
156
89e5ed98
CMN
157int git_remote_save(const git_remote *remote)
158{
89e5ed98
CMN
159 git_config *config;
160 git_buf buf = GIT_BUF_INIT, value = GIT_BUF_INIT;
161
4376f7f6
CMN
162 if (git_repository_config__weakptr(&config, remote->repo) < 0)
163 return -1;
89e5ed98 164
4376f7f6
CMN
165 if (git_buf_printf(&buf, "remote.%s.%s", remote->name, "url") < 0)
166 return -1;
89e5ed98 167
4376f7f6
CMN
168 if (git_config_set_string(config, git_buf_cstr(&buf), remote->url) < 0) {
169 git_buf_free(&buf);
170 return -1;
171 }
89e5ed98 172
9c94a356 173 if (remote->fetch.src != NULL && remote->fetch.dst != NULL) {
89e5ed98
CMN
174 git_buf_clear(&buf);
175 git_buf_clear(&value);
4376f7f6 176 git_buf_printf(&buf, "remote.%s.fetch", remote->name);
89e5ed98
CMN
177 git_buf_printf(&value, "%s:%s", remote->fetch.src, remote->fetch.dst);
178 if (git_buf_oom(&buf) || git_buf_oom(&value))
4376f7f6 179 return -1;
89e5ed98 180
4376f7f6
CMN
181 if (git_config_set_string(config, git_buf_cstr(&buf), git_buf_cstr(&value)) < 0)
182 goto on_error;
89e5ed98
CMN
183 }
184
9c94a356 185 if (remote->push.src != NULL && remote->push.dst != NULL) {
89e5ed98
CMN
186 git_buf_clear(&buf);
187 git_buf_clear(&value);
4376f7f6 188 git_buf_printf(&buf, "remote.%s.push", remote->name);
89e5ed98
CMN
189 git_buf_printf(&value, "%s:%s", remote->push.src, remote->push.dst);
190 if (git_buf_oom(&buf) || git_buf_oom(&value))
4376f7f6 191 return -1;
89e5ed98 192
4376f7f6
CMN
193 if (git_config_set_string(config, git_buf_cstr(&buf), git_buf_cstr(&value)) < 0)
194 goto on_error;
89e5ed98
CMN
195 }
196
89e5ed98
CMN
197 git_buf_free(&buf);
198 git_buf_free(&value);
4376f7f6
CMN
199
200 return 0;
201
202on_error:
203 git_buf_free(&buf);
204 git_buf_free(&value);
205 return -1;
89e5ed98
CMN
206}
207
4bef3565 208const char *git_remote_name(git_remote *remote)
9c82357b 209{
4bef3565 210 assert(remote);
9c82357b
CMN
211 return remote->name;
212}
213
4bef3565 214const char *git_remote_url(git_remote *remote)
9c82357b 215{
4bef3565 216 assert(remote);
9c82357b
CMN
217 return remote->url;
218}
219
bcb8c007
CMN
220int git_remote_set_fetchspec(git_remote *remote, const char *spec)
221{
bcb8c007
CMN
222 git_refspec refspec;
223
224 assert(remote && spec);
225
4376f7f6
CMN
226 if (refspec_parse(&refspec, spec) < 0)
227 return -1;
bcb8c007
CMN
228
229 git__free(remote->fetch.src);
230 git__free(remote->fetch.dst);
231 remote->fetch.src = refspec.src;
232 remote->fetch.dst = refspec.dst;
233
4376f7f6 234 return 0;
bcb8c007
CMN
235}
236
4bef3565 237const git_refspec *git_remote_fetchspec(git_remote *remote)
9c82357b 238{
4bef3565 239 assert(remote);
9c82357b
CMN
240 return &remote->fetch;
241}
242
bcb8c007
CMN
243int git_remote_set_pushspec(git_remote *remote, const char *spec)
244{
bcb8c007
CMN
245 git_refspec refspec;
246
247 assert(remote && spec);
248
4376f7f6
CMN
249 if (refspec_parse(&refspec, spec) < 0)
250 return -1;
bcb8c007
CMN
251
252 git__free(remote->push.src);
253 git__free(remote->push.dst);
254 remote->push.src = refspec.src;
255 remote->push.dst = refspec.dst;
256
4376f7f6 257 return 0;
bcb8c007
CMN
258}
259
4bef3565 260const git_refspec *git_remote_pushspec(git_remote *remote)
9c82357b 261{
4bef3565 262 assert(remote);
9c82357b
CMN
263 return &remote->push;
264}
265
0ac2726f 266int git_remote_connect(git_remote *remote, int direction)
9ba49bb5 267{
9ba49bb5
CMN
268 git_transport *t;
269
4bef3565
VM
270 assert(remote);
271
4376f7f6
CMN
272 if (git_transport_new(&t, remote->url) < 0)
273 return -1;
9ba49bb5 274
4376f7f6
CMN
275 if (t->connect(t, direction) < 0) {
276 goto on_error;
9ba49bb5
CMN
277 }
278
279 remote->transport = t;
280
4376f7f6 281 return 0;
9ba49bb5 282
4376f7f6
CMN
283on_error:
284 t->free(t);
285 return -1;
9ba49bb5
CMN
286}
287
d88d4311 288int git_remote_ls(git_remote *remote, git_headlist_cb list_cb, void *payload)
9ba49bb5 289{
d88d4311
VM
290 assert(remote);
291
4376f7f6
CMN
292 if (!remote->transport || !remote->transport->connected) {
293 giterr_set(GITERR_NET, "The remote is not connected");
294 return -1;
295 }
d88d4311
VM
296
297 return remote->transport->ls(remote->transport, list_cb, payload);
9ba49bb5
CMN
298}
299
7a520f5d 300int git_remote_download(git_remote *remote, git_off_t *bytes, git_indexer_stats *stats)
48a65a07 301{
95057b85
CMN
302 int error;
303
7a520f5d 304 assert(remote && bytes && stats);
4bef3565 305
95057b85 306 if ((error = git_fetch_negotiate(remote)) < 0)
4376f7f6 307 return error;
95057b85 308
7a520f5d 309 return git_fetch_download_pack(remote, bytes, stats);
48a65a07
CMN
310}
311
f184836b 312int git_remote_update_tips(git_remote *remote, int (*cb)(const char *refname, const git_oid *a, const git_oid *b))
441f57c2 313{
4376f7f6 314 int error = 0;
517bda19 315 unsigned int i = 0;
97769280 316 git_buf refname = GIT_BUF_INIT;
f184836b 317 git_oid old;
d88d4311 318 git_vector *refs = &remote->refs;
441f57c2
CMN
319 git_remote_head *head;
320 git_reference *ref;
321 struct git_refspec *spec = &remote->fetch;
322
4bef3565
VM
323 assert(remote);
324
d88d4311 325 if (refs->length == 0)
517bda19
CMN
326 return GIT_SUCCESS;
327
328 /* HEAD is only allowed to be the first in the list */
d88d4311 329 head = refs->contents[0];
517bda19 330 if (!strcmp(head->name, GIT_HEAD_FILE)) {
4376f7f6
CMN
331 if (git_reference_create_oid(&ref, remote->repo, GIT_FETCH_HEAD_FILE, &head->oid, 1) < 0)
332 return -1;
585a2eb7 333
4376f7f6 334 i = 1;
585a2eb7 335 git_reference_free(ref);
517bda19
CMN
336 }
337
d88d4311
VM
338 for (; i < refs->length; ++i) {
339 head = refs->contents[i];
517bda19 340
4376f7f6 341 if (git_refspec_transform_r(&refname, spec, head->name) < 0)
f184836b
CMN
342 goto on_error;
343
344 error = git_reference_name_to_oid(&old, remote->repo, refname.ptr);
345 if (error < 0 && error != GIT_ENOTFOUND)
346 goto on_error;
347
348 if (error == GIT_ENOTFOUND)
349 memset(&old, 0, GIT_OID_RAWSZ);
350
351 if (!git_oid_cmp(&old, &head->oid))
352 continue;
441f57c2 353
4376f7f6 354 if (git_reference_create_oid(&ref, remote->repo, refname.ptr, &head->oid, 1) < 0)
97769280 355 break;
39157563
CMN
356
357 git_reference_free(ref);
f184836b
CMN
358
359 if (cb != NULL) {
360 if (cb(refname.ptr, &old, &head->oid) < 0)
361 goto on_error;
362 }
441f57c2
CMN
363 }
364
97769280 365 git_buf_free(&refname);
f184836b
CMN
366 return 0;
367
368on_error:
369 git_buf_free(&refname);
370 return -1;
97769280 371
441f57c2
CMN
372}
373
6ac3b707
CMN
374int git_remote_connected(git_remote *remote)
375{
4bef3565 376 assert(remote);
6ac3b707
CMN
377 return remote->transport == NULL ? 0 : remote->transport->connected;
378}
379
4cf01e9a
CMN
380void git_remote_disconnect(git_remote *remote)
381{
4bef3565
VM
382 assert(remote);
383
42ea35c0 384 if (remote->transport != NULL && remote->transport->connected)
4cf01e9a 385 remote->transport->close(remote->transport);
4cf01e9a
CMN
386}
387
9c82357b
CMN
388void git_remote_free(git_remote *remote)
389{
2aae2188
CMN
390 if (remote == NULL)
391 return;
392
42ea35c0
MS
393 if (remote->transport != NULL) {
394 git_remote_disconnect(remote);
395
396 remote->transport->free(remote->transport);
397 remote->transport = NULL;
398 }
399
400 git_vector_free(&remote->refs);
401
3286c408
VM
402 git__free(remote->fetch.src);
403 git__free(remote->fetch.dst);
404 git__free(remote->push.src);
405 git__free(remote->push.dst);
406 git__free(remote->url);
407 git__free(remote->name);
3286c408 408 git__free(remote);
9c82357b 409}
8171998f
CMN
410
411struct cb_data {
412 git_vector *list;
413 regex_t *preg;
414};
415
854eccbb 416static int remote_list_cb(const char *name, const char *value, void *data_)
8171998f
CMN
417{
418 struct cb_data *data = (struct cb_data *)data_;
419 size_t nmatch = 2;
420 regmatch_t pmatch[2];
854eccbb 421 GIT_UNUSED(value);
8171998f
CMN
422
423 if (!regexec(data->preg, name, nmatch, pmatch, 0)) {
424 char *remote_name = git__strndup(&name[pmatch[1].rm_so], pmatch[1].rm_eo - pmatch[1].rm_so);
4376f7f6 425 GITERR_CHECK_ALLOC(remote_name);
8171998f 426
4376f7f6
CMN
427 if (git_vector_insert(data->list, remote_name) < 0)
428 return -1;
8171998f
CMN
429 }
430
4376f7f6 431 return 0;
8171998f
CMN
432}
433
434int git_remote_list(git_strarray *remotes_list, git_repository *repo)
435{
436 git_config *cfg;
437 git_vector list;
438 regex_t preg;
439 struct cb_data data;
440 int error;
441
4376f7f6
CMN
442 if (git_repository_config__weakptr(&cfg, repo) < 0)
443 return -1;
8171998f 444
4376f7f6
CMN
445 if (git_vector_init(&list, 4, NULL) < 0)
446 return -1;
8171998f 447
4376f7f6
CMN
448 if (regcomp(&preg, "^remote\\.(.*)\\.url$", REG_EXTENDED) < 0) {
449 giterr_set(GITERR_OS, "Remote catch regex failed to compile");
450 return -1;
451 }
8171998f
CMN
452
453 data.list = &list;
454 data.preg = &preg;
455 error = git_config_foreach(cfg, remote_list_cb, &data);
456 regfree(&preg);
4376f7f6 457 if (error < 0) {
8171998f
CMN
458 size_t i;
459 char *elem;
460 git_vector_foreach(&list, i, elem) {
2bc8fa02 461 git__free(elem);
8171998f
CMN
462 }
463
464 git_vector_free(&list);
465 return error;
466 }
467
468 remotes_list->strings = (char **)list.contents;
469 remotes_list->count = list.length;
470
4376f7f6 471 return 0;
8171998f 472}