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