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