]> git.proxmox.com Git - libgit2.git/blame - src/remote.c
remote: add accessors for the autotag setting
[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
9c82357b
CMN
8#include "git2/config.h"
9#include "git2/types.h"
c07d9c95 10#include "git2/oid.h"
9c82357b
CMN
11
12#include "config.h"
13#include "repository.h"
14#include "remote.h"
e1d88030 15#include "fetch.h"
441f57c2 16#include "refs.h"
ad4b5beb 17#include "pkt.h"
9c82357b 18
8171998f
CMN
19#include <regex.h>
20
9c82357b
CMN
21static int refspec_parse(git_refspec *refspec, const char *str)
22{
23 char *delim;
24
25 memset(refspec, 0x0, sizeof(git_refspec));
26
27 if (*str == '+') {
28 refspec->force = 1;
29 str++;
30 }
31
32 delim = strchr(str, ':');
4376f7f6
CMN
33 if (delim == NULL) {
34 giterr_set(GITERR_NET, "Invalid refspec, missing ':'");
35 return -1;
36 }
9c82357b
CMN
37
38 refspec->src = git__strndup(str, delim - str);
4376f7f6 39 GITERR_CHECK_ALLOC(refspec->src);
9c82357b
CMN
40
41 refspec->dst = git__strdup(delim + 1);
4376f7f6 42 GITERR_CHECK_ALLOC(refspec->dst);
9c82357b 43
4376f7f6 44 return 0;
9c82357b
CMN
45}
46
47static int parse_remote_refspec(git_config *cfg, git_refspec *refspec, const char *var)
48{
9c82357b 49 int error;
4376f7f6 50 const char *val;
9c82357b 51
29e948de 52 if ((error = git_config_get_string(&val, cfg, var)) < 0)
9c82357b
CMN
53 return error;
54
2dc31040 55 return refspec_parse(refspec, val);
9c82357b
CMN
56}
57
24f2f94e
CMN
58static int download_tags_value(git_remote *remote, git_config *cfg)
59{
60 const char *val;
61 git_buf buf = GIT_BUF_INIT;
62 int error;
63
64 if (remote->download_tags != GIT_REMOTE_DOWNLOAD_TAGS_UNSET)
65 return 0;
66
67 /* This is the default, let's see if we need to change it */
68 remote->download_tags = GIT_REMOTE_DOWNLOAD_TAGS_AUTO;
69 if (git_buf_printf(&buf, "remote.%s.tagopt", remote->name) < 0)
70 return -1;
71
72 error = git_config_get_string(&val, cfg, git_buf_cstr(&buf));
73 git_buf_free(&buf);
74 if (!error && !strcmp(val, "--no-tags"))
75 remote->download_tags = GIT_REMOTE_DOWNLOAD_TAGS_NONE;
76
77 if (error == GIT_ENOTFOUND)
78 error = 0;
79
80 return error;
81}
82
baaa8a44 83int git_remote_new(git_remote **out, git_repository *repo, const char *name, const char *url, const char *fetch)
778e1c73
CMN
84{
85 git_remote *remote;
86
4bef3565
VM
87 /* name is optional */
88 assert(out && repo && url);
617bfdf4 89
778e1c73 90 remote = git__malloc(sizeof(git_remote));
4376f7f6 91 GITERR_CHECK_ALLOC(remote);
778e1c73
CMN
92
93 memset(remote, 0x0, sizeof(git_remote));
94 remote->repo = repo;
250b95b2 95 remote->check_cert = 1;
617bfdf4 96
4376f7f6
CMN
97 if (git_vector_init(&remote->refs, 32, NULL) < 0)
98 return -1;
d88d4311 99
778e1c73 100 remote->url = git__strdup(url);
4376f7f6 101 GITERR_CHECK_ALLOC(remote->url);
778e1c73 102
617bfdf4
CMN
103 if (name != NULL) {
104 remote->name = git__strdup(name);
4376f7f6 105 GITERR_CHECK_ALLOC(remote->name);
617bfdf4
CMN
106 }
107
baaa8a44
CMN
108 if (fetch != NULL) {
109 if (refspec_parse(&remote->fetch, fetch) < 0)
110 goto on_error;
111 }
112
778e1c73 113 *out = remote;
4376f7f6 114 return 0;
baaa8a44
CMN
115
116on_error:
117 git_remote_free(remote);
118 return -1;
778e1c73
CMN
119}
120
9462c471 121int git_remote_load(git_remote **out, git_repository *repo, const char *name)
9c82357b
CMN
122{
123 git_remote *remote;
f0f3a18a 124 git_buf buf = GIT_BUF_INIT;
9c82357b 125 const char *val;
4376f7f6 126 int error = 0;
9462c471 127 git_config *config;
9c82357b 128
9462c471
VM
129 assert(out && repo && name);
130
4376f7f6
CMN
131 if (git_repository_config__weakptr(&config, repo) < 0)
132 return -1;
4bef3565 133
9c82357b 134 remote = git__malloc(sizeof(git_remote));
4376f7f6 135 GITERR_CHECK_ALLOC(remote);
9c82357b
CMN
136
137 memset(remote, 0x0, sizeof(git_remote));
250b95b2 138 remote->check_cert = 1;
9c82357b 139 remote->name = git__strdup(name);
4376f7f6 140 GITERR_CHECK_ALLOC(remote->name);
9c82357b 141
2fb9d6de 142 if (git_vector_init(&remote->refs, 32, NULL) < 0) {
143 error = -1;
144 goto cleanup;
145 }
d88d4311 146
2fb9d6de 147 if (git_buf_printf(&buf, "remote.%s.url", name) < 0) {
148 error = -1;
149 goto cleanup;
150 }
9c82357b 151
29e948de 152 if ((error = git_config_get_string(&val, config, git_buf_cstr(&buf))) < 0)
9c82357b 153 goto cleanup;
9c82357b 154
9462c471 155 remote->repo = repo;
9c82357b 156 remote->url = git__strdup(val);
4376f7f6 157 GITERR_CHECK_ALLOC(remote->url);
9c82357b 158
3ed4b501
SC
159 git_buf_clear(&buf);
160 if (git_buf_printf(&buf, "remote.%s.pushurl", name) < 0) {
161 error = -1;
162 goto cleanup;
163 }
164
165 error = git_config_get_string(&val, config, git_buf_cstr(&buf));
166 if (error == GIT_ENOTFOUND)
167 error = 0;
168
169 if (error < 0) {
170 error = -1;
171 goto cleanup;
172 }
173
174 if (val) {
175 remote->pushurl = git__strdup(val);
176 GITERR_CHECK_ALLOC(remote->pushurl);
177 }
178
f0f3a18a 179 git_buf_clear(&buf);
2fb9d6de 180 if (git_buf_printf(&buf, "remote.%s.fetch", name) < 0) {
181 error = -1;
182 goto cleanup;
183 }
9c82357b 184
f0f3a18a 185 error = parse_remote_refspec(config, &remote->fetch, git_buf_cstr(&buf));
904b67e6 186 if (error == GIT_ENOTFOUND)
4376f7f6 187 error = 0;
9554cd51 188
4376f7f6
CMN
189 if (error < 0) {
190 error = -1;
9c82357b 191 goto cleanup;
2dc31040 192 }
9c82357b 193
f0f3a18a 194 git_buf_clear(&buf);
2fb9d6de 195 if (git_buf_printf(&buf, "remote.%s.push", name) < 0) {
196 error = -1;
197 goto cleanup;
198 }
9c82357b 199
f0f3a18a 200 error = parse_remote_refspec(config, &remote->push, git_buf_cstr(&buf));
904b67e6 201 if (error == GIT_ENOTFOUND)
4376f7f6 202 error = 0;
9c82357b 203
4376f7f6
CMN
204 if (error < 0) {
205 error = -1;
9c82357b 206 goto cleanup;
4376f7f6 207 }
9c82357b 208
24f2f94e
CMN
209 if (download_tags_value(remote, config) < 0)
210 goto cleanup;
211
9c82357b
CMN
212 *out = remote;
213
214cleanup:
f0f3a18a 215 git_buf_free(&buf);
9462c471 216
4376f7f6 217 if (error < 0)
9c82357b
CMN
218 git_remote_free(remote);
219
220 return error;
221}
222
89e5ed98
CMN
223int git_remote_save(const git_remote *remote)
224{
89e5ed98
CMN
225 git_config *config;
226 git_buf buf = GIT_BUF_INIT, value = GIT_BUF_INIT;
227
4376f7f6
CMN
228 if (git_repository_config__weakptr(&config, remote->repo) < 0)
229 return -1;
89e5ed98 230
cb020f0d 231 if (git_buf_printf(&buf, "remote.%s.url", remote->name) < 0)
4376f7f6 232 return -1;
89e5ed98 233
4376f7f6
CMN
234 if (git_config_set_string(config, git_buf_cstr(&buf), remote->url) < 0) {
235 git_buf_free(&buf);
236 return -1;
237 }
89e5ed98 238
413d5563
SC
239 git_buf_clear(&buf);
240 if (git_buf_printf(&buf, "remote.%s.pushurl", remote->name) < 0)
241 return -1;
3ed4b501 242
413d5563 243 if (remote->pushurl) {
3ed4b501
SC
244 if (git_config_set_string(config, git_buf_cstr(&buf), remote->pushurl) < 0) {
245 git_buf_free(&buf);
246 return -1;
247 }
413d5563
SC
248 } else {
249 int error = git_config_delete(config, git_buf_cstr(&buf));
250 if (error == GIT_ENOTFOUND) {
251 error = 0;
252 }
253 if (error < 0) {
254 git_buf_free(&buf);
255 return -1;
256 }
3ed4b501
SC
257 }
258
9c94a356 259 if (remote->fetch.src != NULL && remote->fetch.dst != NULL) {
89e5ed98
CMN
260 git_buf_clear(&buf);
261 git_buf_clear(&value);
4376f7f6 262 git_buf_printf(&buf, "remote.%s.fetch", remote->name);
d05e2c64 263 if (remote->fetch.force)
264 git_buf_putc(&value, '+');
89e5ed98
CMN
265 git_buf_printf(&value, "%s:%s", remote->fetch.src, remote->fetch.dst);
266 if (git_buf_oom(&buf) || git_buf_oom(&value))
4376f7f6 267 return -1;
89e5ed98 268
4376f7f6
CMN
269 if (git_config_set_string(config, git_buf_cstr(&buf), git_buf_cstr(&value)) < 0)
270 goto on_error;
89e5ed98
CMN
271 }
272
9c94a356 273 if (remote->push.src != NULL && remote->push.dst != NULL) {
89e5ed98
CMN
274 git_buf_clear(&buf);
275 git_buf_clear(&value);
4376f7f6 276 git_buf_printf(&buf, "remote.%s.push", remote->name);
d05e2c64 277 if (remote->push.force)
278 git_buf_putc(&value, '+');
89e5ed98
CMN
279 git_buf_printf(&value, "%s:%s", remote->push.src, remote->push.dst);
280 if (git_buf_oom(&buf) || git_buf_oom(&value))
4376f7f6 281 return -1;
89e5ed98 282
4376f7f6
CMN
283 if (git_config_set_string(config, git_buf_cstr(&buf), git_buf_cstr(&value)) < 0)
284 goto on_error;
89e5ed98
CMN
285 }
286
89e5ed98
CMN
287 git_buf_free(&buf);
288 git_buf_free(&value);
4376f7f6
CMN
289
290 return 0;
291
292on_error:
293 git_buf_free(&buf);
294 git_buf_free(&value);
295 return -1;
89e5ed98
CMN
296}
297
4bef3565 298const char *git_remote_name(git_remote *remote)
9c82357b 299{
4bef3565 300 assert(remote);
9c82357b
CMN
301 return remote->name;
302}
303
4bef3565 304const char *git_remote_url(git_remote *remote)
9c82357b 305{
4bef3565 306 assert(remote);
9c82357b
CMN
307 return remote->url;
308}
309
76501590
SC
310int git_remote_set_url(git_remote *remote, const char* url)
311{
312 assert(remote);
313 assert(url);
314
315 git__free(remote->url);
316 remote->url = git__strdup(url);
317 GITERR_CHECK_ALLOC(remote->url);
318
319 return 0;
320}
321
322const char *git_remote_pushurl(git_remote *remote)
323{
324 assert(remote);
325 return remote->pushurl;
326}
327
328int git_remote_set_pushurl(git_remote *remote, const char* url)
329{
330 assert(remote);
331
332 git__free(remote->pushurl);
333 if (url) {
334 remote->pushurl = git__strdup(url);
335 GITERR_CHECK_ALLOC(remote->pushurl);
336 } else {
337 remote->pushurl = NULL;
338 }
339 return 0;
340}
341
bcb8c007
CMN
342int git_remote_set_fetchspec(git_remote *remote, const char *spec)
343{
bcb8c007
CMN
344 git_refspec refspec;
345
346 assert(remote && spec);
347
4376f7f6
CMN
348 if (refspec_parse(&refspec, spec) < 0)
349 return -1;
bcb8c007
CMN
350
351 git__free(remote->fetch.src);
352 git__free(remote->fetch.dst);
353 remote->fetch.src = refspec.src;
354 remote->fetch.dst = refspec.dst;
355
4376f7f6 356 return 0;
bcb8c007
CMN
357}
358
4bef3565 359const git_refspec *git_remote_fetchspec(git_remote *remote)
9c82357b 360{
4bef3565 361 assert(remote);
9c82357b
CMN
362 return &remote->fetch;
363}
364
bcb8c007
CMN
365int git_remote_set_pushspec(git_remote *remote, const char *spec)
366{
bcb8c007
CMN
367 git_refspec refspec;
368
369 assert(remote && spec);
370
4376f7f6
CMN
371 if (refspec_parse(&refspec, spec) < 0)
372 return -1;
bcb8c007
CMN
373
374 git__free(remote->push.src);
375 git__free(remote->push.dst);
376 remote->push.src = refspec.src;
377 remote->push.dst = refspec.dst;
378
4376f7f6 379 return 0;
bcb8c007
CMN
380}
381
4bef3565 382const git_refspec *git_remote_pushspec(git_remote *remote)
9c82357b 383{
4bef3565 384 assert(remote);
9c82357b
CMN
385 return &remote->push;
386}
387
eff5b499
SC
388const char* git_remote__urlfordirection(git_remote *remote, int direction)
389{
390 assert(remote);
391
392 if (direction == GIT_DIR_FETCH) {
393 return remote->url;
394 }
395
396 if (direction == GIT_DIR_PUSH) {
397 return remote->pushurl ? remote->pushurl : remote->url;
398 }
399
400 return NULL;
401}
402
0ac2726f 403int git_remote_connect(git_remote *remote, int direction)
9ba49bb5 404{
9ba49bb5 405 git_transport *t;
c0c39025 406 const char *url;
9ba49bb5 407
4bef3565
VM
408 assert(remote);
409
c0c39025 410 url = git_remote__urlfordirection(remote, direction);
eff5b499
SC
411 if (url == NULL )
412 return -1;
413
414 if (git_transport_new(&t, url) < 0)
4376f7f6 415 return -1;
9ba49bb5 416
e03e71da
CMN
417 t->progress_cb = remote->callbacks.progress;
418 t->cb_data = remote->callbacks.data;
419
250b95b2 420 t->check_cert = remote->check_cert;
4376f7f6
CMN
421 if (t->connect(t, direction) < 0) {
422 goto on_error;
9ba49bb5
CMN
423 }
424
425 remote->transport = t;
426
4376f7f6 427 return 0;
9ba49bb5 428
4376f7f6
CMN
429on_error:
430 t->free(t);
431 return -1;
9ba49bb5
CMN
432}
433
d88d4311 434int git_remote_ls(git_remote *remote, git_headlist_cb list_cb, void *payload)
9ba49bb5 435{
ad4b5beb
CMN
436 git_vector *refs = &remote->transport->refs;
437 unsigned int i;
438 git_pkt *p = NULL;
439
d88d4311
VM
440 assert(remote);
441
4376f7f6
CMN
442 if (!remote->transport || !remote->transport->connected) {
443 giterr_set(GITERR_NET, "The remote is not connected");
444 return -1;
445 }
d88d4311 446
ad4b5beb
CMN
447 git_vector_foreach(refs, i, p) {
448 git_pkt_ref *pkt = NULL;
449
450 if (p->type != GIT_PKT_REF)
451 continue;
452
453 pkt = (git_pkt_ref *)p;
454
e4607392 455 if (list_cb(&pkt->head, payload))
d8d28e2e 456 return GIT_EUSER;
ad4b5beb
CMN
457 }
458
459 return 0;
9ba49bb5
CMN
460}
461
7a520f5d 462int git_remote_download(git_remote *remote, git_off_t *bytes, git_indexer_stats *stats)
48a65a07 463{
95057b85
CMN
464 int error;
465
7a520f5d 466 assert(remote && bytes && stats);
4bef3565 467
95057b85 468 if ((error = git_fetch_negotiate(remote)) < 0)
4376f7f6 469 return error;
95057b85 470
7a520f5d 471 return git_fetch_download_pack(remote, bytes, stats);
48a65a07
CMN
472}
473
b3aaa7a7 474int git_remote_update_tips(git_remote *remote)
441f57c2 475{
a37ddf7e 476 int error = 0, autotag;
517bda19 477 unsigned int i = 0;
97769280 478 git_buf refname = GIT_BUF_INIT;
f184836b 479 git_oid old;
a37ddf7e
CMN
480 git_pkt *pkt;
481 git_odb *odb;
3f035860 482 git_vector *refs;
441f57c2
CMN
483 git_remote_head *head;
484 git_reference *ref;
3f035860 485 struct git_refspec *spec;
a37ddf7e
CMN
486 char *tagstr = "refs/tags/*:refs/tags/*";
487 git_refspec tagspec;
441f57c2 488
4bef3565
VM
489 assert(remote);
490
a37ddf7e 491 refs = &remote->transport->refs;
3f035860
VM
492 spec = &remote->fetch;
493
d88d4311 494 if (refs->length == 0)
e172cf08 495 return 0;
517bda19 496
a37ddf7e
CMN
497 if (git_repository_odb(&odb, remote->repo) < 0)
498 return -1;
499
500 if (git_refspec__parse(&tagspec, tagstr, true) < 0)
501 return -1;
502
517bda19 503 /* HEAD is only allowed to be the first in the list */
a37ddf7e
CMN
504 pkt = refs->contents[0];
505 head = &((git_pkt_ref *)pkt)->head;
517bda19 506 if (!strcmp(head->name, GIT_HEAD_FILE)) {
4376f7f6
CMN
507 if (git_reference_create_oid(&ref, remote->repo, GIT_FETCH_HEAD_FILE, &head->oid, 1) < 0)
508 return -1;
585a2eb7 509
4376f7f6 510 i = 1;
585a2eb7 511 git_reference_free(ref);
517bda19
CMN
512 }
513
d88d4311 514 for (; i < refs->length; ++i) {
a37ddf7e
CMN
515 autotag = 0;
516 git_pkt *pkt = refs->contents[i];
517bda19 517
a37ddf7e
CMN
518 if (pkt->type == GIT_PKT_REF)
519 head = &((git_pkt_ref *)pkt)->head;
520 else
521 continue;
522
523 /* Ignore malformed ref names (which also saves us from tag^{} */
524 if (!git_reference_is_valid_name(head->name))
525 continue;
526
527 if (git_refspec_src_matches(spec, head->name)) {
528 if (git_refspec_transform_r(&refname, spec, head->name) < 0)
529 goto on_error;
530 } else if (remote->download_tags != GIT_REMOTE_DOWNLOAD_TAGS_NONE) {
531 autotag = 1;
532
533 if (!git_refspec_src_matches(&tagspec, head->name))
534 continue;
535
536 git_buf_clear(&refname);
537 if (git_buf_puts(&refname, head->name) < 0)
538 goto on_error;
539 } else {
540 continue;
541 }
542
543 if (autotag && !git_odb_exists(odb, &head->oid))
544 continue;
f184836b
CMN
545
546 error = git_reference_name_to_oid(&old, remote->repo, refname.ptr);
904b67e6 547 if (error < 0 && error != GIT_ENOTFOUND)
f184836b
CMN
548 goto on_error;
549
904b67e6 550 if (error == GIT_ENOTFOUND)
f184836b
CMN
551 memset(&old, 0, GIT_OID_RAWSZ);
552
553 if (!git_oid_cmp(&old, &head->oid))
554 continue;
441f57c2 555
a37ddf7e
CMN
556 /* In autotag mode, don't overwrite any locally-existing tags */
557 error = git_reference_create_oid(&ref, remote->repo, refname.ptr, &head->oid, !autotag);
558 if (error < 0 && error != GIT_EEXISTS)
944d250f 559 goto on_error;
39157563
CMN
560
561 git_reference_free(ref);
f184836b 562
b3aaa7a7
CMN
563 if (remote->callbacks.update_tips != NULL) {
564 if (remote->callbacks.update_tips(refname.ptr, &old, &head->oid, remote->callbacks.data) < 0)
f184836b
CMN
565 goto on_error;
566 }
441f57c2
CMN
567 }
568
a37ddf7e 569 git_refspec__free(&tagspec);
97769280 570 git_buf_free(&refname);
f184836b
CMN
571 return 0;
572
573on_error:
a37ddf7e 574 git_refspec__free(&tagspec);
f184836b
CMN
575 git_buf_free(&refname);
576 return -1;
97769280 577
441f57c2
CMN
578}
579
6ac3b707
CMN
580int git_remote_connected(git_remote *remote)
581{
4bef3565 582 assert(remote);
6ac3b707
CMN
583 return remote->transport == NULL ? 0 : remote->transport->connected;
584}
585
4cf01e9a
CMN
586void git_remote_disconnect(git_remote *remote)
587{
4bef3565
VM
588 assert(remote);
589
42ea35c0 590 if (remote->transport != NULL && remote->transport->connected)
4cf01e9a 591 remote->transport->close(remote->transport);
4cf01e9a
CMN
592}
593
9c82357b
CMN
594void git_remote_free(git_remote *remote)
595{
2aae2188
CMN
596 if (remote == NULL)
597 return;
598
42ea35c0
MS
599 if (remote->transport != NULL) {
600 git_remote_disconnect(remote);
601
602 remote->transport->free(remote->transport);
603 remote->transport = NULL;
604 }
605
606 git_vector_free(&remote->refs);
607
3665ba8e
CMN
608 git_refspec__free(&remote->fetch);
609 git_refspec__free(&remote->push);
3286c408 610 git__free(remote->url);
3ed4b501 611 git__free(remote->pushurl);
3286c408 612 git__free(remote->name);
3286c408 613 git__free(remote);
9c82357b 614}
8171998f
CMN
615
616struct cb_data {
617 git_vector *list;
618 regex_t *preg;
619};
620
854eccbb 621static int remote_list_cb(const char *name, const char *value, void *data_)
8171998f
CMN
622{
623 struct cb_data *data = (struct cb_data *)data_;
624 size_t nmatch = 2;
625 regmatch_t pmatch[2];
854eccbb 626 GIT_UNUSED(value);
8171998f
CMN
627
628 if (!regexec(data->preg, name, nmatch, pmatch, 0)) {
629 char *remote_name = git__strndup(&name[pmatch[1].rm_so], pmatch[1].rm_eo - pmatch[1].rm_so);
4376f7f6 630 GITERR_CHECK_ALLOC(remote_name);
8171998f 631
4376f7f6
CMN
632 if (git_vector_insert(data->list, remote_name) < 0)
633 return -1;
8171998f
CMN
634 }
635
4376f7f6 636 return 0;
8171998f
CMN
637}
638
639int git_remote_list(git_strarray *remotes_list, git_repository *repo)
640{
641 git_config *cfg;
642 git_vector list;
643 regex_t preg;
644 struct cb_data data;
645 int error;
646
4376f7f6
CMN
647 if (git_repository_config__weakptr(&cfg, repo) < 0)
648 return -1;
8171998f 649
4376f7f6
CMN
650 if (git_vector_init(&list, 4, NULL) < 0)
651 return -1;
8171998f 652
4376f7f6
CMN
653 if (regcomp(&preg, "^remote\\.(.*)\\.url$", REG_EXTENDED) < 0) {
654 giterr_set(GITERR_OS, "Remote catch regex failed to compile");
655 return -1;
656 }
8171998f
CMN
657
658 data.list = &list;
659 data.preg = &preg;
660 error = git_config_foreach(cfg, remote_list_cb, &data);
661 regfree(&preg);
4376f7f6 662 if (error < 0) {
8171998f
CMN
663 size_t i;
664 char *elem;
665 git_vector_foreach(&list, i, elem) {
2bc8fa02 666 git__free(elem);
8171998f
CMN
667 }
668
669 git_vector_free(&list);
e4607392
RB
670
671 /* cb error is converted to GIT_EUSER by git_config_foreach */
672 if (error == GIT_EUSER)
673 error = -1;
674
8171998f
CMN
675 return error;
676 }
677
678 remotes_list->strings = (char **)list.contents;
679 remotes_list->count = list.length;
680
4376f7f6 681 return 0;
8171998f 682}
a209a025
CMN
683
684int git_remote_add(git_remote **out, git_repository *repo, const char *name, const char *url)
685{
686 git_buf buf = GIT_BUF_INIT;
a209a025 687
d27bf665 688 if (git_buf_printf(&buf, "+refs/heads/*:refs/remotes/%s/*", name) < 0)
baaa8a44 689 return -1;
a209a025 690
baaa8a44 691 if (git_remote_new(out, repo, name, url, git_buf_cstr(&buf)) < 0)
a209a025
CMN
692 goto on_error;
693
694 git_buf_free(&buf);
695
696 if (git_remote_save(*out) < 0)
baaa8a44 697 goto on_error;
a209a025
CMN
698
699 return 0;
700
701on_error:
702 git_buf_free(&buf);
703 git_remote_free(*out);
704 return -1;
705}
250b95b2
CMN
706
707void git_remote_check_cert(git_remote *remote, int check)
708{
709 assert(remote);
710
711 remote->check_cert = check;
712}
b3aaa7a7
CMN
713
714void git_remote_set_callbacks(git_remote *remote, git_remote_callbacks *callbacks)
715{
716 assert(remote && callbacks);
717
718 memcpy(&remote->callbacks, callbacks, sizeof(git_remote_callbacks));
e03e71da
CMN
719
720 if (remote->transport) {
721 remote->transport->progress_cb = remote->callbacks.progress;
722 remote->transport->cb_data = remote->callbacks.data;
723 }
b3aaa7a7 724}
f70e466f
CMN
725
726int git_remote_autotag(git_remote *remote)
727{
728 return remote->download_tags;
729}
730
731void git_remote_set_autotag(git_remote *remote, int value)
732{
733 remote->download_tags = value;
734}