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