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