]> git.proxmox.com Git - libgit2.git/blame - src/remote.c
Merge pull request #1727 from alindeman/lookup-object-doc-fix
[libgit2.git] / src / remote.c
CommitLineData
9c82357b 1/*
359fc2d2 2 * Copyright (C) the libgit2 contributors. All rights reserved.
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"
1ffd0806 11#include "git2/net.h"
9c82357b
CMN
12
13#include "config.h"
14#include "repository.h"
15#include "remote.h"
e1d88030 16#include "fetch.h"
441f57c2 17#include "refs.h"
b0f6e45d
ET
18#include "refspec.h"
19#include "fetchhead.h"
9c82357b 20
8171998f
CMN
21#include <regex.h>
22
4330ab26 23static int add_refspec(git_remote *remote, const char *string, bool is_fetch)
9c82357b 24{
4330ab26 25 git_refspec *spec;
9c82357b 26
4330ab26
CMN
27 spec = git__calloc(1, sizeof(git_refspec));
28 GITERR_CHECK_ALLOC(spec);
29
1be680c4
CMN
30 if (git_refspec__parse(spec, string, is_fetch) < 0) {
31 git__free(spec);
32 return -1;
33 }
4330ab26
CMN
34
35 spec->push = !is_fetch;
1be680c4
CMN
36 if (git_vector_insert(&remote->refspecs, spec) < 0) {
37 git_refspec__free(spec);
38 git__free(spec);
39 return -1;
40 }
9c82357b 41
4330ab26 42 return 0;
9c82357b
CMN
43}
44
24f2f94e
CMN
45static int download_tags_value(git_remote *remote, git_config *cfg)
46{
47 const char *val;
48 git_buf buf = GIT_BUF_INIT;
49 int error;
50
df50512a 51 /* The 0 value is the default (auto), let's see if we need to change it */
24f2f94e
CMN
52 if (git_buf_printf(&buf, "remote.%s.tagopt", remote->name) < 0)
53 return -1;
54
55 error = git_config_get_string(&val, cfg, git_buf_cstr(&buf));
56 git_buf_free(&buf);
57 if (!error && !strcmp(val, "--no-tags"))
58 remote->download_tags = GIT_REMOTE_DOWNLOAD_TAGS_NONE;
3230a44f
CMN
59 else if (!error && !strcmp(val, "--tags"))
60 remote->download_tags = GIT_REMOTE_DOWNLOAD_TAGS_ALL;
24f2f94e 61
bf6bebe2
RB
62 if (error == GIT_ENOTFOUND) {
63 giterr_clear();
24f2f94e 64 error = 0;
bf6bebe2 65 }
24f2f94e
CMN
66
67 return error;
68}
69
032ba9e4 70static int ensure_remote_name_is_valid(const char *name)
71{
2bca5b67 72 int error = 0;
032ba9e4 73
2bca5b67 74 if (!git_remote_is_valid_name(name)) {
032ba9e4 75 giterr_set(
76 GITERR_CONFIG,
77 "'%s' is not a valid remote name.", name);
78 error = GIT_EINVALIDSPEC;
79 }
80
81 return error;
82}
83
874dcb25 84static int create_internal(git_remote **out, git_repository *repo, const char *name, const char *url, const char *fetch)
778e1c73
CMN
85{
86 git_remote *remote;
44f36f6e
BS
87 git_buf fetchbuf = GIT_BUF_INIT;
88 int error = -1;
778e1c73 89
4bef3565 90 /* name is optional */
874dcb25 91 assert(out && repo && url);
617bfdf4 92
59bccf33 93 remote = git__calloc(1, sizeof(git_remote));
4376f7f6 94 GITERR_CHECK_ALLOC(remote);
778e1c73 95
778e1c73 96 remote->repo = repo;
250b95b2 97 remote->check_cert = 1;
b0f6e45d 98 remote->update_fetchhead = 1;
617bfdf4 99
4376f7f6 100 if (git_vector_init(&remote->refs, 32, NULL) < 0)
44f36f6e 101 goto on_error;
d88d4311 102
778e1c73 103 remote->url = git__strdup(url);
4376f7f6 104 GITERR_CHECK_ALLOC(remote->url);
778e1c73 105
617bfdf4
CMN
106 if (name != NULL) {
107 remote->name = git__strdup(name);
4376f7f6 108 GITERR_CHECK_ALLOC(remote->name);
617bfdf4
CMN
109 }
110
baaa8a44 111 if (fetch != NULL) {
4330ab26 112 if (add_refspec(remote, fetch, true) < 0)
baaa8a44
CMN
113 goto on_error;
114 }
115
215af2cc 116 if (!name)
117 /* A remote without a name doesn't download tags */
c648d4a8 118 remote->download_tags = GIT_REMOTE_DOWNLOAD_TAGS_NONE;
c648d4a8 119
778e1c73 120 *out = remote;
44f36f6e 121 git_buf_free(&fetchbuf);
4376f7f6 122 return 0;
baaa8a44
CMN
123
124on_error:
125 git_remote_free(remote);
44f36f6e
BS
126 git_buf_free(&fetchbuf);
127 return error;
778e1c73
CMN
128}
129
592f466c
BS
130static int ensure_remote_doesnot_exist(git_repository *repo, const char *name)
131{
132 int error;
133 git_remote *remote;
134
135 error = git_remote_load(&remote, repo, name);
136
137 if (error == GIT_ENOTFOUND)
138 return 0;
139
140 if (error < 0)
141 return error;
142
143 git_remote_free(remote);
144
145 giterr_set(
146 GITERR_CONFIG,
147 "Remote '%s' already exists.", name);
148
149 return GIT_EEXISTS;
150}
151
f19304d2 152
874dcb25
BS
153int git_remote_create(git_remote **out, git_repository *repo, const char *name, const char *url)
154{
155 git_buf buf = GIT_BUF_INIT;
c5193e3c 156 git_remote *remote = NULL;
874dcb25
BS
157 int error;
158
159 if ((error = ensure_remote_name_is_valid(name)) < 0)
160 return error;
161
f19304d2 162 if ((error = ensure_remote_doesnot_exist(repo, name)) < 0)
163 return error;
164
874dcb25
BS
165 if (git_buf_printf(&buf, "+refs/heads/*:refs/remotes/%s/*", name) < 0)
166 return -1;
167
c5193e3c 168 if (create_internal(&remote, repo, name, url, git_buf_cstr(&buf)) < 0)
874dcb25
BS
169 goto on_error;
170
171 git_buf_free(&buf);
172
c5193e3c 173 if (git_remote_save(remote) < 0)
874dcb25
BS
174 goto on_error;
175
c5193e3c 176 *out = remote;
177
874dcb25
BS
178 return 0;
179
180on_error:
181 git_buf_free(&buf);
c5193e3c 182 git_remote_free(remote);
874dcb25
BS
183 return -1;
184}
185
0642c143 186int git_remote_create_inmemory(git_remote **out, git_repository *repo, const char *fetch, const char *url)
874dcb25
BS
187{
188 int error;
189 git_remote *remote;
190
79000951 191 if ((error = create_internal(&remote, repo, NULL, url, fetch)) < 0)
874dcb25
BS
192 return error;
193
874dcb25
BS
194 *out = remote;
195 return 0;
196}
197
4330ab26
CMN
198struct refspec_cb_data {
199 git_remote *remote;
200 int fetch;
201};
202
203static int refspec_cb(const git_config_entry *entry, void *payload)
204{
205 const struct refspec_cb_data *data = (struct refspec_cb_data *)payload;
206
207 return add_refspec(data->remote, entry->value, data->fetch);
208}
209
bf6bebe2
RB
210static int get_optional_config(
211 git_config *config, git_buf *buf, git_config_foreach_cb cb, void *payload)
212{
213 int error = 0;
214 const char *key = git_buf_cstr(buf);
215
216 if (git_buf_oom(buf))
217 return -1;
218
219 if (cb != NULL)
220 error = git_config_get_multivar(config, key, NULL, cb, payload);
221 else
222 error = git_config_get_string(payload, config, key);
223
224 if (error == GIT_ENOTFOUND) {
225 giterr_clear();
226 error = 0;
227 }
228
229 if (error < 0)
230 error = -1;
231
232 return error;
233}
234
9462c471 235int git_remote_load(git_remote **out, git_repository *repo, const char *name)
9c82357b
CMN
236{
237 git_remote *remote;
f0f3a18a 238 git_buf buf = GIT_BUF_INIT;
9c82357b 239 const char *val;
4376f7f6 240 int error = 0;
9462c471 241 git_config *config;
4330ab26
CMN
242 struct refspec_cb_data data;
243
9462c471
VM
244 assert(out && repo && name);
245
032ba9e4 246 if ((error = ensure_remote_name_is_valid(name)) < 0)
247 return error;
248
4376f7f6
CMN
249 if (git_repository_config__weakptr(&config, repo) < 0)
250 return -1;
4bef3565 251
9c82357b 252 remote = git__malloc(sizeof(git_remote));
4376f7f6 253 GITERR_CHECK_ALLOC(remote);
9c82357b
CMN
254
255 memset(remote, 0x0, sizeof(git_remote));
250b95b2 256 remote->check_cert = 1;
b0f6e45d 257 remote->update_fetchhead = 1;
9c82357b 258 remote->name = git__strdup(name);
4376f7f6 259 GITERR_CHECK_ALLOC(remote->name);
9c82357b 260
4330ab26 261 if ((git_vector_init(&remote->refs, 32, NULL) < 0) ||
1be680c4 262 (git_vector_init(&remote->refspecs, 2, NULL))) {
2fb9d6de 263 error = -1;
264 goto cleanup;
265 }
d88d4311 266
2fb9d6de 267 if (git_buf_printf(&buf, "remote.%s.url", name) < 0) {
268 error = -1;
269 goto cleanup;
270 }
9c82357b 271
29e948de 272 if ((error = git_config_get_string(&val, config, git_buf_cstr(&buf))) < 0)
9c82357b 273 goto cleanup;
bf6bebe2 274
0da81d2b 275 if (strlen(val) == 0) {
c1cd036e 276 giterr_set(GITERR_INVALID, "Malformed remote '%s' - missing URL", name);
83885891
JSS
277 error = -1;
278 goto cleanup;
279 }
9c82357b 280
9462c471 281 remote->repo = repo;
9c82357b 282 remote->url = git__strdup(val);
4376f7f6 283 GITERR_CHECK_ALLOC(remote->url);
9c82357b 284
bf6bebe2 285 val = NULL;
3ed4b501 286 git_buf_clear(&buf);
bf6bebe2 287 git_buf_printf(&buf, "remote.%s.pushurl", name);
3ed4b501 288
0f938c6b 289 if ((error = get_optional_config(config, &buf, NULL, (void *)&val)) < 0)
3ed4b501 290 goto cleanup;
3ed4b501
SC
291
292 if (val) {
293 remote->pushurl = git__strdup(val);
294 GITERR_CHECK_ALLOC(remote->pushurl);
295 }
296
4330ab26
CMN
297 data.remote = remote;
298 data.fetch = true;
f0f3a18a 299 git_buf_clear(&buf);
bf6bebe2
RB
300 git_buf_printf(&buf, "remote.%s.fetch", name);
301
302 if ((error = get_optional_config(config, &buf, refspec_cb, &data)) < 0)
2fb9d6de 303 goto cleanup;
9c82357b 304
4330ab26 305 data.fetch = false;
bf6bebe2
RB
306 git_buf_clear(&buf);
307 git_buf_printf(&buf, "remote.%s.push", name);
9c82357b 308
bf6bebe2 309 if ((error = get_optional_config(config, &buf, refspec_cb, &data)) < 0)
9c82357b
CMN
310 goto cleanup;
311
24f2f94e
CMN
312 if (download_tags_value(remote, config) < 0)
313 goto cleanup;
314
9c82357b
CMN
315 *out = remote;
316
317cleanup:
f0f3a18a 318 git_buf_free(&buf);
9462c471 319
4376f7f6 320 if (error < 0)
9c82357b
CMN
321 git_remote_free(remote);
322
323 return error;
324}
325
4330ab26 326static int update_config_refspec(const git_remote *remote, git_config *config, int direction)
4fe5520a 327{
4330ab26
CMN
328 git_buf name = GIT_BUF_INIT;
329 int push;
330 const char *dir;
331 size_t i;
bf6bebe2 332 int error = 0;
4fe5520a 333
4330ab26
CMN
334 push = direction == GIT_DIRECTION_PUSH;
335 dir = push ? "push" : "fetch";
4fe5520a 336
4330ab26
CMN
337 if (git_buf_printf(&name, "remote.%s.%s", remote->name, dir) < 0)
338 return -1;
4fe5520a 339
4330ab26 340 /* Clear out the existing config */
bf6bebe2 341 while (!error)
4330ab26 342 error = git_config_delete_entry(config, git_buf_cstr(&name));
4fe5520a 343
4330ab26
CMN
344 if (error != GIT_ENOTFOUND)
345 return error;
346
1be680c4 347 for (i = 0; i < remote->refspecs.length; i++) {
4330ab26 348 git_refspec *spec = git_vector_get(&remote->refspecs, i);
4330ab26
CMN
349
350 if (spec->push != push)
351 continue;
352
bf6bebe2
RB
353 if ((error = git_config_set_multivar(
354 config, git_buf_cstr(&name), "", spec->string)) < 0) {
4330ab26
CMN
355 goto cleanup;
356 }
357 }
358
359 giterr_clear();
360 error = 0;
4fe5520a 361
362cleanup:
363 git_buf_free(&name);
4fe5520a 364
365 return error;
366}
367
89e5ed98
CMN
368int git_remote_save(const git_remote *remote)
369{
218c88a9 370 int error;
89e5ed98 371 git_config *config;
218c88a9 372 const char *tagopt = NULL;
4fe5520a 373 git_buf buf = GIT_BUF_INIT;
89e5ed98 374
e497b16c 375 assert(remote);
376
c07b52df 377 if (!remote->name) {
874dcb25
BS
378 giterr_set(GITERR_INVALID, "Can't save an in-memory remote.");
379 return GIT_EINVALIDSPEC;
a71c27cc
BS
380 }
381
032ba9e4 382 if ((error = ensure_remote_name_is_valid(remote->name)) < 0)
383 return error;
89e5ed98 384
4376f7f6
CMN
385 if (git_repository_config__weakptr(&config, remote->repo) < 0)
386 return -1;
89e5ed98 387
cb020f0d 388 if (git_buf_printf(&buf, "remote.%s.url", remote->name) < 0)
4376f7f6 389 return -1;
89e5ed98 390
4376f7f6
CMN
391 if (git_config_set_string(config, git_buf_cstr(&buf), remote->url) < 0) {
392 git_buf_free(&buf);
393 return -1;
394 }
89e5ed98 395
413d5563
SC
396 git_buf_clear(&buf);
397 if (git_buf_printf(&buf, "remote.%s.pushurl", remote->name) < 0)
398 return -1;
3ed4b501 399
413d5563 400 if (remote->pushurl) {
3ed4b501
SC
401 if (git_config_set_string(config, git_buf_cstr(&buf), remote->pushurl) < 0) {
402 git_buf_free(&buf);
403 return -1;
404 }
413d5563 405 } else {
54b2a37a 406 int error = git_config_delete_entry(config, git_buf_cstr(&buf));
413d5563
SC
407 if (error == GIT_ENOTFOUND) {
408 error = 0;
c48e8700 409 giterr_clear();
413d5563
SC
410 }
411 if (error < 0) {
412 git_buf_free(&buf);
413 return -1;
414 }
3ed4b501
SC
415 }
416
4330ab26
CMN
417 if (update_config_refspec(remote, config, GIT_DIRECTION_FETCH) < 0)
418 goto on_error;
89e5ed98 419
4330ab26
CMN
420 if (update_config_refspec(remote, config, GIT_DIRECTION_PUSH) < 0)
421 goto on_error;
89e5ed98 422
218c88a9
CMN
423 /*
424 * What action to take depends on the old and new values. This
425 * is describes by the table below. tagopt means whether the
426 * is already a value set in the config
427 *
428 * AUTO ALL or NONE
429 * +-----------------------+
430 * tagopt | remove | set |
431 * +---------+-------------|
432 * !tagopt | nothing | set |
433 * +---------+-------------+
434 */
435
436 git_buf_clear(&buf);
437 if (git_buf_printf(&buf, "remote.%s.tagopt", remote->name) < 0)
438 goto on_error;
439
440 error = git_config_get_string(&tagopt, config, git_buf_cstr(&buf));
441 if (error < 0 && error != GIT_ENOTFOUND)
442 goto on_error;
443
444 if (remote->download_tags == GIT_REMOTE_DOWNLOAD_TAGS_ALL) {
445 if (git_config_set_string(config, git_buf_cstr(&buf), "--tags") < 0)
446 goto on_error;
447 } else if (remote->download_tags == GIT_REMOTE_DOWNLOAD_TAGS_NONE) {
448 if (git_config_set_string(config, git_buf_cstr(&buf), "--no-tags") < 0)
449 goto on_error;
450 } else if (tagopt) {
54b2a37a 451 if (git_config_delete_entry(config, git_buf_cstr(&buf)) < 0)
218c88a9
CMN
452 goto on_error;
453 }
454
89e5ed98 455 git_buf_free(&buf);
4376f7f6
CMN
456
457 return 0;
458
459on_error:
460 git_buf_free(&buf);
4376f7f6 461 return -1;
89e5ed98
CMN
462}
463
df705148 464const char *git_remote_name(const git_remote *remote)
9c82357b 465{
4bef3565 466 assert(remote);
9c82357b
CMN
467 return remote->name;
468}
469
df705148 470const char *git_remote_url(const git_remote *remote)
9c82357b 471{
4bef3565 472 assert(remote);
9c82357b
CMN
473 return remote->url;
474}
475
76501590
SC
476int git_remote_set_url(git_remote *remote, const char* url)
477{
478 assert(remote);
479 assert(url);
480
481 git__free(remote->url);
482 remote->url = git__strdup(url);
483 GITERR_CHECK_ALLOC(remote->url);
484
485 return 0;
486}
487
df705148 488const char *git_remote_pushurl(const git_remote *remote)
76501590
SC
489{
490 assert(remote);
491 return remote->pushurl;
492}
493
494int git_remote_set_pushurl(git_remote *remote, const char* url)
495{
496 assert(remote);
497
498 git__free(remote->pushurl);
499 if (url) {
500 remote->pushurl = git__strdup(url);
501 GITERR_CHECK_ALLOC(remote->pushurl);
502 } else {
503 remote->pushurl = NULL;
504 }
505 return 0;
506}
507
eff5b499
SC
508const char* git_remote__urlfordirection(git_remote *remote, int direction)
509{
510 assert(remote);
511
df705148 512 if (direction == GIT_DIRECTION_FETCH) {
eff5b499
SC
513 return remote->url;
514 }
515
df705148 516 if (direction == GIT_DIRECTION_PUSH) {
eff5b499
SC
517 return remote->pushurl ? remote->pushurl : remote->url;
518 }
519
520 return NULL;
521}
522
df705148 523int git_remote_connect(git_remote *remote, git_direction direction)
9ba49bb5 524{
9ba49bb5 525 git_transport *t;
c0c39025 526 const char *url;
41fb1ca0 527 int flags = GIT_TRANSPORTFLAGS_NONE;
9ba49bb5 528
4bef3565
VM
529 assert(remote);
530
41fb1ca0
PK
531 t = remote->transport;
532
c0c39025 533 url = git_remote__urlfordirection(remote, direction);
eff5b499
SC
534 if (url == NULL )
535 return -1;
536
41fb1ca0
PK
537 /* A transport could have been supplied in advance with
538 * git_remote_set_transport */
613d5eb9 539 if (!t && git_transport_new(&t, remote, url) < 0)
4376f7f6 540 return -1;
9ba49bb5 541
41fb1ca0 542 if (t->set_callbacks &&
df705148 543 t->set_callbacks(t, remote->callbacks.progress, NULL, remote->callbacks.payload) < 0)
41fb1ca0 544 goto on_error;
613d5eb9 545
41fb1ca0
PK
546 if (!remote->check_cert)
547 flags |= GIT_TRANSPORTFLAGS_NO_CHECK_CERT;
e03e71da 548
59bccf33 549 if (t->connect(t, url, remote->cred_acquire_cb, remote->cred_acquire_payload, direction, flags) < 0)
4376f7f6 550 goto on_error;
9ba49bb5
CMN
551
552 remote->transport = t;
553
4376f7f6 554 return 0;
9ba49bb5 555
4376f7f6
CMN
556on_error:
557 t->free(t);
613d5eb9
PK
558
559 if (t == remote->transport)
560 remote->transport = NULL;
561
4376f7f6 562 return -1;
9ba49bb5
CMN
563}
564
d88d4311 565int git_remote_ls(git_remote *remote, git_headlist_cb list_cb, void *payload)
9ba49bb5 566{
d88d4311
VM
567 assert(remote);
568
41fb1ca0 569 return remote->transport->ls(remote->transport, list_cb, payload);
9ba49bb5
CMN
570}
571
613d5eb9
PK
572int git_remote__get_http_proxy(git_remote *remote, bool use_ssl, char **proxy_url)
573{
574 git_config *cfg;
575 const char *val;
576
577 assert(remote);
578
a71c27cc 579 if (!proxy_url || !remote->repo)
613d5eb9
PK
580 return -1;
581
582 *proxy_url = NULL;
583
584 if (git_repository_config__weakptr(&cfg, remote->repo) < 0)
585 return -1;
586
587 /* Go through the possible sources for proxy configuration, from most specific
588 * to least specific. */
589
590 /* remote.<name>.proxy config setting */
591 if (remote->name && 0 != *(remote->name)) {
592 git_buf buf = GIT_BUF_INIT;
593
594 if (git_buf_printf(&buf, "remote.%s.proxy", remote->name) < 0)
595 return -1;
596
597 if (!git_config_get_string(&val, cfg, git_buf_cstr(&buf)) &&
598 val && ('\0' != *val)) {
599 git_buf_free(&buf);
600
601 *proxy_url = git__strdup(val);
602 GITERR_CHECK_ALLOC(*proxy_url);
603 return 0;
604 }
605
606 git_buf_free(&buf);
607 }
608
609 /* http.proxy config setting */
610 if (!git_config_get_string(&val, cfg, "http.proxy") &&
611 val && ('\0' != *val)) {
612 *proxy_url = git__strdup(val);
613 GITERR_CHECK_ALLOC(*proxy_url);
614 return 0;
615 }
616
617 /* HTTP_PROXY / HTTPS_PROXY environment variables */
618 val = use_ssl ? getenv("HTTPS_PROXY") : getenv("HTTP_PROXY");
619
620 if (val && ('\0' != *val)) {
621 *proxy_url = git__strdup(val);
622 GITERR_CHECK_ALLOC(*proxy_url);
623 return 0;
624 }
625
626 return 0;
627}
628
d8488457
CMN
629static int store_refs(git_remote_head *head, void *payload)
630{
631 git_vector *refs = (git_vector *)payload;
632
633 return git_vector_insert(refs, head);
634}
635
636static int dwim_refspecs(git_vector *refspecs, git_vector *refs)
637{
638 git_buf buf = GIT_BUF_INIT;
639 git_refspec *spec;
640 size_t i, j, pos;
641 git_remote_head key;
642
643 const char* formatters[] = {
644 GIT_REFS_DIR "%s",
645 GIT_REFS_TAGS_DIR "%s",
646 GIT_REFS_HEADS_DIR "%s",
647 NULL
648 };
649
650 git_vector_foreach(refspecs, i, spec) {
651 if (spec->dwim)
652 continue;
653
654 /* shorthand on the lhs */
655 if (git__prefixcmp(spec->src, GIT_REFS_DIR)) {
656 for (j = 0; formatters[j]; j++) {
657 git_buf_clear(&buf);
658 if (git_buf_printf(&buf, formatters[j], spec->src) < 0)
659 return -1;
660
661 key.name = (char *) git_buf_cstr(&buf);
662 if (!git_vector_search(&pos, refs, &key)) {
663 /* we found something to match the shorthand, set src to that */
664 git__free(spec->src);
665 spec->src = git_buf_detach(&buf);
666 }
667 }
668 }
669
670 if (spec->dst && git__prefixcmp(spec->dst, GIT_REFS_DIR)) {
671 /* if it starts with "remotes" then we just prepend "refs/" */
672 if (!git__prefixcmp(spec->dst, "remotes/")) {
673 git_buf_puts(&buf, GIT_REFS_DIR);
674 } else {
675 git_buf_puts(&buf, GIT_REFS_HEADS_DIR);
676 }
677
678 if (git_buf_puts(&buf, spec->dst) < 0)
679 return -1;
680
681 git__free(spec->dst);
682 spec->dst = git_buf_detach(&buf);
683 }
684
685 spec->dwim = 1;
686 }
687
9c5d4b2e 688 git_buf_free(&buf);
d8488457
CMN
689 return 0;
690}
691
692static int remote_head_cmp(const void *_a, const void *_b)
693{
694 const git_remote_head *a = (git_remote_head *) _a;
695 const git_remote_head *b = (git_remote_head *) _b;
696
697 return git__strcmp_cb(a->name, b->name);
698}
699
216863c4
BS
700int git_remote_download(
701 git_remote *remote,
7d222e13 702 git_transfer_progress_callback progress_cb,
216863c4 703 void *progress_payload)
48a65a07 704{
95057b85 705 int error;
d8488457 706 git_vector refs;
95057b85 707
1e3b8ed5 708 assert(remote);
4bef3565 709
d8488457
CMN
710 if (git_vector_init(&refs, 16, remote_head_cmp) < 0)
711 return -1;
712
713 if (git_remote_ls(remote, store_refs, &refs) < 0) {
714 return -1;
715 }
716
717 error = dwim_refspecs(&remote->refspecs, &refs);
718 git_vector_free(&refs);
719 if (error < 0)
720 return -1;
721
95057b85 722 if ((error = git_fetch_negotiate(remote)) < 0)
4376f7f6 723 return error;
95057b85 724
1e3b8ed5 725 return git_fetch_download_pack(remote, progress_cb, progress_payload);
48a65a07
CMN
726}
727
b0f6e45d
ET
728static int remote_head_for_fetchspec_src(git_remote_head **out, git_vector *update_heads, const char *fetchspec_src)
729{
730 unsigned int i;
731 git_remote_head *remote_ref;
732
733 assert(update_heads && fetchspec_src);
734
735 *out = NULL;
7d4b65f6 736
737 git_vector_foreach(update_heads, i, remote_ref) {
738 if (strcmp(remote_ref->name, fetchspec_src) == 0) {
739 *out = remote_ref;
740 break;
b0f6e45d
ET
741 }
742 }
743
744 return 0;
745}
746
4330ab26 747static int remote_head_for_ref(git_remote_head **out, git_refspec *spec, git_vector *update_heads, git_reference *ref)
b0f6e45d
ET
748{
749 git_reference *resolved_ref = NULL;
750 git_reference *tracking_ref = NULL;
751 git_buf remote_name = GIT_BUF_INIT;
752 int error = 0;
753
4330ab26 754 assert(out && spec && ref);
b0f6e45d
ET
755
756 *out = NULL;
757
758 if ((error = git_reference_resolve(&resolved_ref, ref)) < 0 ||
759 (!git_reference_is_branch(resolved_ref)) ||
a258d8e3 760 (error = git_branch_upstream(&tracking_ref, resolved_ref)) < 0 ||
4330ab26 761 (error = git_refspec_transform_l(&remote_name, spec, git_reference_name(tracking_ref))) < 0) {
b0f6e45d
ET
762 /* Not an error if HEAD is orphaned or no tracking branch */
763 if (error == GIT_ENOTFOUND)
764 error = 0;
765
766 goto cleanup;
767 }
768
769 error = remote_head_for_fetchspec_src(out, update_heads, git_buf_cstr(&remote_name));
770
771cleanup:
772 git_reference_free(tracking_ref);
773 git_reference_free(resolved_ref);
774 git_buf_free(&remote_name);
775 return error;
776}
777
4330ab26 778static int git_remote_write_fetchhead(git_remote *remote, git_refspec *spec, git_vector *update_heads)
b0f6e45d 779{
b0f6e45d
ET
780 git_reference *head_ref = NULL;
781 git_fetchhead_ref *fetchhead_ref;
782 git_remote_head *remote_ref, *merge_remote_ref;
783 git_vector fetchhead_refs;
784 bool include_all_fetchheads;
785 unsigned int i = 0;
786 int error = 0;
787
788 assert(remote);
789
404eadb0
CMN
790 /* no heads, nothing to do */
791 if (update_heads->length == 0)
792 return 0;
793
b0f6e45d
ET
794 if (git_vector_init(&fetchhead_refs, update_heads->length, git_fetchhead_ref_cmp) < 0)
795 return -1;
796
797 /* Iff refspec is * (but not subdir slash star), include tags */
798 include_all_fetchheads = (strcmp(GIT_REFS_HEADS_DIR "*", git_refspec_src(spec)) == 0);
799
800 /* Determine what to merge: if refspec was a wildcard, just use HEAD */
801 if (git_refspec_is_wildcard(spec)) {
802 if ((error = git_reference_lookup(&head_ref, remote->repo, GIT_HEAD_FILE)) < 0 ||
4330ab26 803 (error = remote_head_for_ref(&merge_remote_ref, spec, update_heads, head_ref)) < 0)
b0f6e45d
ET
804 goto cleanup;
805 } else {
806 /* If we're fetching a single refspec, that's the only thing that should be in FETCH_HEAD. */
807 if ((error = remote_head_for_fetchspec_src(&merge_remote_ref, update_heads, git_refspec_src(spec))) < 0)
808 goto cleanup;
809 }
810
811 /* Create the FETCH_HEAD file */
7d4b65f6 812 git_vector_foreach(update_heads, i, remote_ref) {
b0f6e45d
ET
813 int merge_this_fetchhead = (merge_remote_ref == remote_ref);
814
815 if (!include_all_fetchheads &&
816 !git_refspec_src_matches(spec, remote_ref->name) &&
817 !merge_this_fetchhead)
818 continue;
819
820 if (git_fetchhead_ref_create(&fetchhead_ref,
821 &remote_ref->oid,
822 merge_this_fetchhead,
823 remote_ref->name,
824 git_remote_url(remote)) < 0)
825 goto cleanup;
826
827 if (git_vector_insert(&fetchhead_refs, fetchhead_ref) < 0)
828 goto cleanup;
829 }
830
831 git_fetchhead_write(remote->repo, &fetchhead_refs);
832
833cleanup:
834 for (i = 0; i < fetchhead_refs.length; ++i)
835 git_fetchhead_ref_free(fetchhead_refs.contents[i]);
836
837 git_vector_free(&fetchhead_refs);
838 git_reference_free(head_ref);
839
840 return error;
841}
842
4330ab26 843static int update_tips_for_spec(git_remote *remote, git_refspec *spec, git_vector *refs)
441f57c2 844{
a37ddf7e 845 int error = 0, autotag;
517bda19 846 unsigned int i = 0;
97769280 847 git_buf refname = GIT_BUF_INIT;
f184836b 848 git_oid old;
a37ddf7e 849 git_odb *odb;
441f57c2
CMN
850 git_remote_head *head;
851 git_reference *ref;
a37ddf7e 852 git_refspec tagspec;
4330ab26 853 git_vector update_heads;
441f57c2 854
4bef3565
VM
855 assert(remote);
856
acd17006 857 if (git_repository_odb__weakptr(&odb, remote->repo) < 0)
a37ddf7e
CMN
858 return -1;
859
3230a44f 860 if (git_refspec__parse(&tagspec, GIT_REFSPEC_TAGS, true) < 0)
a37ddf7e
CMN
861 return -1;
862
41fb1ca0 863 /* Make a copy of the transport's refs */
4330ab26 864 if (git_vector_init(&update_heads, 16, NULL) < 0)
41fb1ca0 865 return -1;
585a2eb7 866
4330ab26
CMN
867 for (; i < refs->length; ++i) {
868 head = git_vector_get(refs, i);
9063be1f 869 autotag = 0;
517bda19 870
a37ddf7e
CMN
871 /* Ignore malformed ref names (which also saves us from tag^{} */
872 if (!git_reference_is_valid_name(head->name))
873 continue;
874
d8488457 875 if (git_refspec_src_matches(spec, head->name) && spec->dst) {
a37ddf7e
CMN
876 if (git_refspec_transform_r(&refname, spec, head->name) < 0)
877 goto on_error;
878 } else if (remote->download_tags != GIT_REMOTE_DOWNLOAD_TAGS_NONE) {
3230a44f
CMN
879
880 if (remote->download_tags != GIT_REMOTE_DOWNLOAD_TAGS_ALL)
881 autotag = 1;
a37ddf7e
CMN
882
883 if (!git_refspec_src_matches(&tagspec, head->name))
884 continue;
885
886 git_buf_clear(&refname);
887 if (git_buf_puts(&refname, head->name) < 0)
888 goto on_error;
889 } else {
890 continue;
891 }
892
893 if (autotag && !git_odb_exists(odb, &head->oid))
894 continue;
f184836b 895
b0f6e45d
ET
896 if (git_vector_insert(&update_heads, head) < 0)
897 goto on_error;
898
2508cc66 899 error = git_reference_name_to_id(&old, remote->repo, refname.ptr);
904b67e6 900 if (error < 0 && error != GIT_ENOTFOUND)
f184836b
CMN
901 goto on_error;
902
904b67e6 903 if (error == GIT_ENOTFOUND)
f184836b
CMN
904 memset(&old, 0, GIT_OID_RAWSZ);
905
b7f167da 906 if (!git_oid__cmp(&old, &head->oid))
f184836b 907 continue;
441f57c2 908
a37ddf7e 909 /* In autotag mode, don't overwrite any locally-existing tags */
2508cc66 910 error = git_reference_create(&ref, remote->repo, refname.ptr, &head->oid, !autotag);
a37ddf7e 911 if (error < 0 && error != GIT_EEXISTS)
944d250f 912 goto on_error;
39157563
CMN
913
914 git_reference_free(ref);
f184836b 915
b3aaa7a7 916 if (remote->callbacks.update_tips != NULL) {
df705148 917 if (remote->callbacks.update_tips(refname.ptr, &old, &head->oid, remote->callbacks.payload) < 0)
f184836b
CMN
918 goto on_error;
919 }
441f57c2
CMN
920 }
921
b0f6e45d 922 if (git_remote_update_fetchhead(remote) &&
4330ab26 923 (error = git_remote_write_fetchhead(remote, spec, &update_heads)) < 0)
b0f6e45d
ET
924 goto on_error;
925
b0f6e45d 926 git_vector_free(&update_heads);
a37ddf7e 927 git_refspec__free(&tagspec);
97769280 928 git_buf_free(&refname);
f184836b
CMN
929 return 0;
930
931on_error:
b0f6e45d 932 git_vector_free(&update_heads);
a37ddf7e 933 git_refspec__free(&tagspec);
f184836b
CMN
934 git_buf_free(&refname);
935 return -1;
97769280 936
441f57c2
CMN
937}
938
4330ab26
CMN
939int git_remote_update_tips(git_remote *remote)
940{
505b5d0c 941 git_refspec *spec, tagspec;
4330ab26 942 git_vector refs;
505b5d0c 943 int error;
4330ab26
CMN
944 size_t i;
945
505b5d0c
CMN
946
947 if (git_refspec__parse(&tagspec, GIT_REFSPEC_TAGS, true) < 0)
948 return -1;
949
4330ab26
CMN
950 if (git_vector_init(&refs, 16, NULL) < 0)
951 return -1;
952
505b5d0c
CMN
953 if ((error = git_remote_ls(remote, store_refs, &refs)) < 0)
954 goto out;
955
956 if (remote->download_tags == GIT_REMOTE_DOWNLOAD_TAGS_ALL) {
957 error = update_tips_for_spec(remote, &tagspec, &refs);
958 goto out;
959 }
4330ab26
CMN
960
961 git_vector_foreach(&remote->refspecs, i, spec) {
962 if (spec->push)
963 continue;
964
505b5d0c
CMN
965 if ((error = update_tips_for_spec(remote, spec, &refs)) < 0)
966 goto out;
4330ab26
CMN
967 }
968
505b5d0c
CMN
969out:
970 git_refspec__free(&tagspec);
4330ab26 971 git_vector_free(&refs);
505b5d0c 972 return error;
4330ab26
CMN
973}
974
6ac3b707
CMN
975int git_remote_connected(git_remote *remote)
976{
4bef3565 977 assert(remote);
41fb1ca0
PK
978
979 if (!remote->transport || !remote->transport->is_connected)
980 return 0;
981
982 /* Ask the transport if it's connected. */
613d5eb9 983 return remote->transport->is_connected(remote->transport);
6ac3b707
CMN
984}
985
f0d2ddbb
CMN
986void git_remote_stop(git_remote *remote)
987{
613d5eb9
PK
988 assert(remote);
989
990 if (remote->transport && remote->transport->cancel)
41fb1ca0 991 remote->transport->cancel(remote->transport);
f0d2ddbb
CMN
992}
993
4cf01e9a
CMN
994void git_remote_disconnect(git_remote *remote)
995{
4bef3565
VM
996 assert(remote);
997
41fb1ca0
PK
998 if (git_remote_connected(remote))
999 remote->transport->close(remote->transport);
4cf01e9a
CMN
1000}
1001
9c82357b
CMN
1002void git_remote_free(git_remote *remote)
1003{
4330ab26 1004 git_refspec *spec;
4330ab26
CMN
1005 size_t i;
1006
2aae2188
CMN
1007 if (remote == NULL)
1008 return;
1009
42ea35c0
MS
1010 if (remote->transport != NULL) {
1011 git_remote_disconnect(remote);
1012
1013 remote->transport->free(remote->transport);
1014 remote->transport = NULL;
1015 }
1016
1017 git_vector_free(&remote->refs);
1018
4330ab26
CMN
1019 git_vector_foreach(&remote->refspecs, i, spec) {
1020 git_refspec__free(spec);
1021 git__free(spec);
1022 }
1023 git_vector_free(&remote->refspecs);
1024
3286c408 1025 git__free(remote->url);
3ed4b501 1026 git__free(remote->pushurl);
3286c408 1027 git__free(remote->name);
3286c408 1028 git__free(remote);
9c82357b 1029}
8171998f
CMN
1030
1031struct cb_data {
1032 git_vector *list;
1033 regex_t *preg;
1034};
1035
a1abe66a 1036static int remote_list_cb(const git_config_entry *entry, void *data_)
8171998f
CMN
1037{
1038 struct cb_data *data = (struct cb_data *)data_;
1039 size_t nmatch = 2;
1040 regmatch_t pmatch[2];
a1abe66a 1041 const char *name = entry->name;
8171998f
CMN
1042
1043 if (!regexec(data->preg, name, nmatch, pmatch, 0)) {
1044 char *remote_name = git__strndup(&name[pmatch[1].rm_so], pmatch[1].rm_eo - pmatch[1].rm_so);
4376f7f6 1045 GITERR_CHECK_ALLOC(remote_name);
8171998f 1046
4376f7f6
CMN
1047 if (git_vector_insert(data->list, remote_name) < 0)
1048 return -1;
8171998f
CMN
1049 }
1050
4376f7f6 1051 return 0;
8171998f
CMN
1052}
1053
1054int git_remote_list(git_strarray *remotes_list, git_repository *repo)
1055{
1056 git_config *cfg;
1057 git_vector list;
1058 regex_t preg;
1059 struct cb_data data;
1060 int error;
1061
4376f7f6
CMN
1062 if (git_repository_config__weakptr(&cfg, repo) < 0)
1063 return -1;
8171998f 1064
4376f7f6
CMN
1065 if (git_vector_init(&list, 4, NULL) < 0)
1066 return -1;
8171998f 1067
4376f7f6
CMN
1068 if (regcomp(&preg, "^remote\\.(.*)\\.url$", REG_EXTENDED) < 0) {
1069 giterr_set(GITERR_OS, "Remote catch regex failed to compile");
1070 return -1;
1071 }
8171998f
CMN
1072
1073 data.list = &list;
1074 data.preg = &preg;
1075 error = git_config_foreach(cfg, remote_list_cb, &data);
1076 regfree(&preg);
4376f7f6 1077 if (error < 0) {
8171998f
CMN
1078 size_t i;
1079 char *elem;
1080 git_vector_foreach(&list, i, elem) {
2bc8fa02 1081 git__free(elem);
8171998f
CMN
1082 }
1083
1084 git_vector_free(&list);
e4607392
RB
1085
1086 /* cb error is converted to GIT_EUSER by git_config_foreach */
1087 if (error == GIT_EUSER)
1088 error = -1;
1089
8171998f
CMN
1090 return error;
1091 }
1092
1093 remotes_list->strings = (char **)list.contents;
1094 remotes_list->count = list.length;
1095
4376f7f6 1096 return 0;
8171998f 1097}
a209a025 1098
250b95b2
CMN
1099void git_remote_check_cert(git_remote *remote, int check)
1100{
1101 assert(remote);
1102
1103 remote->check_cert = check;
1104}
b3aaa7a7 1105
9267ff58 1106int git_remote_set_callbacks(git_remote *remote, git_remote_callbacks *callbacks)
b3aaa7a7
CMN
1107{
1108 assert(remote && callbacks);
1109
c7231c45 1110 GITERR_CHECK_VERSION(callbacks, GIT_REMOTE_CALLBACKS_VERSION, "git_remote_callbacks");
9267ff58 1111
b3aaa7a7 1112 memcpy(&remote->callbacks, callbacks, sizeof(git_remote_callbacks));
e03e71da 1113
41fb1ca0
PK
1114 if (remote->transport && remote->transport->set_callbacks)
1115 remote->transport->set_callbacks(remote->transport,
1116 remote->callbacks.progress,
1117 NULL,
df705148 1118 remote->callbacks.payload);
9267ff58
BS
1119
1120 return 0;
41fb1ca0
PK
1121}
1122
091361f5
PK
1123void git_remote_set_cred_acquire_cb(
1124 git_remote *remote,
59bccf33
BS
1125 git_cred_acquire_cb cred_acquire_cb,
1126 void *payload)
091361f5
PK
1127{
1128 assert(remote);
1129
1130 remote->cred_acquire_cb = cred_acquire_cb;
59bccf33 1131 remote->cred_acquire_payload = payload;
091361f5
PK
1132}
1133
41fb1ca0
PK
1134int git_remote_set_transport(git_remote *remote, git_transport *transport)
1135{
1136 assert(remote && transport);
1137
c7231c45 1138 GITERR_CHECK_VERSION(transport, GIT_TRANSPORT_VERSION, "git_transport");
10711769 1139
e03e71da 1140 if (remote->transport) {
41fb1ca0
PK
1141 giterr_set(GITERR_NET, "A transport is already bound to this remote");
1142 return -1;
e03e71da 1143 }
41fb1ca0
PK
1144
1145 remote->transport = transport;
1146 return 0;
b3aaa7a7 1147}
f70e466f 1148
67dad09b 1149const git_transfer_progress* git_remote_stats(git_remote *remote)
d57c47dc
BS
1150{
1151 assert(remote);
1152 return &remote->stats;
1153}
1154
f4a62c30 1155git_remote_autotag_option_t git_remote_autotag(git_remote *remote)
f70e466f
CMN
1156{
1157 return remote->download_tags;
1158}
1159
f4a62c30 1160void git_remote_set_autotag(git_remote *remote, git_remote_autotag_option_t value)
f70e466f
CMN
1161{
1162 remote->download_tags = value;
1163}
fcccf304 1164
fcccf304 1165static int rename_remote_config_section(
1166 git_repository *repo,
1167 const char *old_name,
1168 const char *new_name)
1169{
1170 git_buf old_section_name = GIT_BUF_INIT,
1171 new_section_name = GIT_BUF_INIT;
1172 int error = -1;
1173
1174 if (git_buf_printf(&old_section_name, "remote.%s", old_name) < 0)
1175 goto cleanup;
1176
1177 if (git_buf_printf(&new_section_name, "remote.%s", new_name) < 0)
1178 goto cleanup;
1179
1180 error = git_config_rename_section(
1181 repo,
1182 git_buf_cstr(&old_section_name),
1183 git_buf_cstr(&new_section_name));
1184
1185cleanup:
1186 git_buf_free(&old_section_name);
1187 git_buf_free(&new_section_name);
1188
1189 return error;
1190}
1191
1192struct update_data
1193{
1194 git_config *config;
1195 const char *old_remote_name;
1196 const char *new_remote_name;
1197};
1198
1199static int update_config_entries_cb(
1200 const git_config_entry *entry,
1201 void *payload)
1202{
1203 struct update_data *data = (struct update_data *)payload;
1204
1205 if (strcmp(entry->value, data->old_remote_name))
1206 return 0;
1207
1208 return git_config_set_string(
1209 data->config,
1210 entry->name,
1211 data->new_remote_name);
1212}
1213
1214static int update_branch_remote_config_entry(
1215 git_repository *repo,
1216 const char *old_name,
1217 const char *new_name)
1218{
1219 git_config *config;
1220 struct update_data data;
1221
1222 if (git_repository_config__weakptr(&config, repo) < 0)
1223 return -1;
1224
1225 data.config = config;
1226 data.old_remote_name = old_name;
1227 data.new_remote_name = new_name;
1228
1229 return git_config_foreach_match(
1230 config,
1231 "branch\\..+\\.remote",
1232 update_config_entries_cb, &data);
1233}
1234
fcccf304 1235static int rename_one_remote_reference(
56960b83 1236 git_reference *reference,
fcccf304 1237 const char *old_remote_name,
1238 const char *new_remote_name)
1239{
6cfbbf7e 1240 int error = -1;
fcccf304 1241 git_buf new_name = GIT_BUF_INIT;
fcccf304 1242
1243 if (git_buf_printf(
1244 &new_name,
1245 GIT_REFS_REMOTES_DIR "%s%s",
1246 new_remote_name,
56960b83 1247 reference->name + strlen(GIT_REFS_REMOTES_DIR) + strlen(old_remote_name)) < 0)
fcccf304 1248 return -1;
1249
4e6e2ff2 1250 error = git_reference_rename(NULL, reference, git_buf_cstr(&new_name), 0);
d00d5464 1251 git_reference_free(reference);
fcccf304 1252
fcccf304 1253 git_buf_free(&new_name);
1254 return error;
1255}
1256
1257static int rename_remote_references(
1258 git_repository *repo,
1259 const char *old_name,
1260 const char *new_name)
1261{
fcccf304 1262 int error = -1;
56960b83 1263 git_reference *ref;
9bd89d96 1264 git_reference_iterator *iter;
fcccf304 1265
9bd89d96 1266 if (git_reference_iterator_new(&iter, repo) < 0)
56960b83 1267 return -1;
fcccf304 1268
56960b83 1269 while ((error = git_reference_next(&ref, iter)) == 0) {
2f77d8f1
RB
1270 if (git__prefixcmp(ref->name, GIT_REFS_REMOTES_DIR)) {
1271 git_reference_free(ref);
9bd89d96 1272 continue;
2f77d8f1 1273 }
9bd89d96 1274
56960b83
VM
1275 if ((error = rename_one_remote_reference(ref, old_name, new_name)) < 0) {
1276 git_reference_iterator_free(iter);
1277 return error;
1278 }
9bd89d96
CMN
1279 }
1280
1281 git_reference_iterator_free(iter);
fcccf304 1282
56960b83
VM
1283 if (error == GIT_ITEROVER)
1284 return 0;
fcccf304 1285
fcccf304 1286 return error;
1287}
1288
1289static int rename_fetch_refspecs(
1290 git_remote *remote,
1291 const char *new_name,
1292 int (*callback)(const char *problematic_refspec, void *payload),
1293 void *payload)
1294{
1295 git_config *config;
4330ab26 1296 git_buf base = GIT_BUF_INIT, var = GIT_BUF_INIT, val = GIT_BUF_INIT;
1be680c4 1297 const git_refspec *spec;
4330ab26 1298 size_t i;
fcccf304 1299 int error = -1;
1300
4330ab26
CMN
1301 if (git_buf_printf(&base, "+refs/heads/*:refs/remotes/%s/*", remote->name) < 0)
1302 goto cleanup;
fcccf304 1303
1be680c4 1304 git_vector_foreach(&remote->refspecs, i, spec) {
4330ab26
CMN
1305 if (spec->push)
1306 continue;
fcccf304 1307
4330ab26
CMN
1308 /* Every refspec is a problem refspec for an in-memory remote */
1309 if (!remote->name) {
1be680c4 1310 if (callback(spec->string, payload) < 0) {
4330ab26
CMN
1311 error = GIT_EUSER;
1312 goto cleanup;
1313 }
fcccf304 1314
4330ab26
CMN
1315 continue;
1316 }
fcccf304 1317
4330ab26 1318 /* Does the dst part of the refspec follow the extected standard format? */
1be680c4
CMN
1319 if (strcmp(git_buf_cstr(&base), spec->string)) {
1320 if (callback(spec->string, payload) < 0) {
4330ab26
CMN
1321 error = GIT_EUSER;
1322 goto cleanup;
1323 }
fcccf304 1324
4330ab26
CMN
1325 continue;
1326 }
fcccf304 1327
4330ab26
CMN
1328 /* If we do want to move it to the new section */
1329 if (git_buf_printf(&val, "+refs/heads/*:refs/remotes/%s/*", new_name) < 0)
fcccf304 1330 goto cleanup;
1331
4330ab26
CMN
1332 if (git_buf_printf(&var, "remote.%s.fetch", new_name) < 0)
1333 goto cleanup;
fcccf304 1334
4330ab26
CMN
1335 if (git_repository_config__weakptr(&config, remote->repo) < 0)
1336 goto cleanup;
fcccf304 1337
4330ab26
CMN
1338 if (git_config_set_string(config, git_buf_cstr(&var), git_buf_cstr(&val)) < 0)
1339 goto cleanup;
1340 }
fcccf304 1341
4330ab26 1342 error = 0;
fcccf304 1343
1344cleanup:
4330ab26
CMN
1345 git_buf_free(&base);
1346 git_buf_free(&var);
1347 git_buf_free(&val);
fcccf304 1348 return error;
1349}
1350
1351int git_remote_rename(
1352 git_remote *remote,
1353 const char *new_name,
df705148 1354 git_remote_rename_problem_cb callback,
fcccf304 1355 void *payload)
1356{
1357 int error;
1358
1359 assert(remote && new_name);
1360
c07b52df 1361 if (!remote->name) {
79000951
BS
1362 giterr_set(GITERR_INVALID, "Can't rename an in-memory remote.");
1363 return GIT_EINVALIDSPEC;
1364 }
1365
fcccf304 1366 if ((error = ensure_remote_name_is_valid(new_name)) < 0)
1367 return error;
1368
a71c27cc
BS
1369 if (remote->repo) {
1370 if ((error = ensure_remote_doesnot_exist(remote->repo, new_name)) < 0)
fcccf304 1371 return error;
1372
a71c27cc
BS
1373 if (!remote->name) {
1374 if ((error = rename_fetch_refspecs(
1375 remote,
1376 new_name,
1377 callback,
1378 payload)) < 0)
1379 return error;
fcccf304 1380
a71c27cc 1381 remote->name = git__strdup(new_name);
fcccf304 1382
c07b52df 1383 if (!remote->name) return 0;
a71c27cc
BS
1384 return git_remote_save(remote);
1385 }
fcccf304 1386
a71c27cc
BS
1387 if ((error = rename_remote_config_section(
1388 remote->repo,
1389 remote->name,
1390 new_name)) < 0)
1391 return error;
fcccf304 1392
a71c27cc
BS
1393 if ((error = update_branch_remote_config_entry(
1394 remote->repo,
1395 remote->name,
1396 new_name)) < 0)
1397 return error;
fcccf304 1398
a71c27cc
BS
1399 if ((error = rename_remote_references(
1400 remote->repo,
1401 remote->name,
1402 new_name)) < 0)
1403 return error;
1404
1405 if ((error = rename_fetch_refspecs(
1406 remote,
1407 new_name,
1408 callback,
1409 payload)) < 0)
1410 return error;
1411 }
fcccf304 1412
1413 git__free(remote->name);
1414 remote->name = git__strdup(new_name);
1415
1416 return 0;
1417}
b0f6e45d
ET
1418
1419int git_remote_update_fetchhead(git_remote *remote)
1420{
1421 return remote->update_fetchhead;
1422}
1423
1424void git_remote_set_update_fetchhead(git_remote *remote, int value)
1425{
1426 remote->update_fetchhead = value;
1427}
2bca5b67 1428
1429int git_remote_is_valid_name(
1430 const char *remote_name)
1431{
1432 git_buf buf = GIT_BUF_INIT;
1433 git_refspec refspec;
1434 int error = -1;
1435
1436 if (!remote_name || *remote_name == '\0')
1437 return 0;
1438
1439 git_buf_printf(&buf, "refs/heads/test:refs/remotes/%s/test", remote_name);
1440 error = git_refspec__parse(&refspec, git_buf_cstr(&buf), true);
1441
1442 git_buf_free(&buf);
1443 git_refspec__free(&refspec);
1444
1445 giterr_clear();
1446 return error == 0;
1447}
4330ab26
CMN
1448
1449git_refspec *git_remote__matching_refspec(git_remote *remote, const char *refname)
1450{
1451 git_refspec *spec;
1452 size_t i;
1453
1454 git_vector_foreach(&remote->refspecs, i, spec) {
1455 if (spec->push)
1456 continue;
1457
1458 if (git_refspec_src_matches(spec, refname))
1459 return spec;
1460 }
1461
1462 return NULL;
1463}
1464
1465git_refspec *git_remote__matching_dst_refspec(git_remote *remote, const char *refname)
1466{
1467 git_refspec *spec;
1468 size_t i;
1469
1470 git_vector_foreach(&remote->refspecs, i, spec) {
1471 if (spec->push)
1472 continue;
1473
1474 if (git_refspec_dst_matches(spec, refname))
1475 return spec;
1476 }
1477
1478 return NULL;
1479}
1480
1481void git_remote_clear_refspecs(git_remote *remote)
1482{
1483 git_refspec *spec;
4330ab26
CMN
1484 size_t i;
1485
1486 git_vector_foreach(&remote->refspecs, i, spec) {
1487 git_refspec__free(spec);
1be680c4 1488 git__free(spec);
4330ab26
CMN
1489 }
1490 git_vector_clear(&remote->refspecs);
4330ab26
CMN
1491}
1492
bc6374ea 1493int git_remote_add_fetch(git_remote *remote, const char *refspec)
4330ab26
CMN
1494{
1495 return add_refspec(remote, refspec, true);
1496}
1497
bc6374ea 1498int git_remote_add_push(git_remote *remote, const char *refspec)
4330ab26
CMN
1499{
1500 return add_refspec(remote, refspec, false);
1501}
bc6374ea
CMN
1502
1503static int copy_refspecs(git_strarray *array, git_remote *remote, int push)
1504{
1505 size_t i;
1506 git_vector refspecs;
1507 git_refspec *spec;
1508 char *dup;
1509
1510 if (git_vector_init(&refspecs, remote->refspecs.length, NULL) < 0)
1511 return -1;
1512
1513 git_vector_foreach(&remote->refspecs, i, spec) {
1514 if (spec->push != push)
1515 continue;
1516
1be680c4 1517 if ((dup = git__strdup(spec->string)) == NULL)
bc6374ea 1518 goto on_error;
bc6374ea
CMN
1519
1520 if (git_vector_insert(&refspecs, dup) < 0) {
1521 git__free(dup);
1522 goto on_error;
1523 }
1524 }
1525
1526 array->strings = (char **)refspecs.contents;
1527 array->count = refspecs.length;
1528
1529 return 0;
1530
1531on_error:
1532 git_vector_foreach(&refspecs, i, dup)
1533 git__free(dup);
1534 git_vector_free(&refspecs);
1535
1536 return -1;
1537}
1538
1539int git_remote_get_fetch_refspecs(git_strarray *array, git_remote *remote)
1540{
1541 return copy_refspecs(array, remote, false);
1542}
1543
1544int git_remote_get_push_refspecs(git_strarray *array, git_remote *remote)
1545{
1546 return copy_refspecs(array, remote, true);
1547}
1ffd0806
CMN
1548
1549size_t git_remote_refspec_count(git_remote *remote)
1550{
1551 return remote->refspecs.length;
1552}
1553
1554const git_refspec *git_remote_get_refspec(git_remote *remote, size_t n)
1555{
1556 return git_vector_get(&remote->refspecs, n);
1557}
1558
1559int git_remote_remove_refspec(git_remote *remote, size_t n)
1560{
1561 git_refspec *spec;
1562
1563 assert(remote);
1564
1565 spec = git_vector_get(&remote->refspecs, n);
1566 if (spec) {
1567 git_refspec__free(spec);
1568 git__free(spec);
1569 }
1570
1571 return git_vector_remove(&remote->refspecs, n);
1572}