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