]> git.proxmox.com Git - libgit2.git/blame - src/remote.c
remote: move the transport ctor to the callbacks
[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"
fe794b2e 21#include "push.h"
9c82357b 22
22261344
CMN
23#define CONFIG_URL_FMT "remote.%s.url"
24#define CONFIG_PUSHURL_FMT "remote.%s.pushurl"
25#define CONFIG_FETCH_FMT "remote.%s.fetch"
26
af613ecd 27static int dwim_refspecs(git_vector *out, git_vector *refspecs, git_vector *refs);
1ef3f0ce 28static int lookup_remote_prune_config(git_remote *remote, git_config *config, const char *name);
af613ecd 29
3f894205 30static int add_refspec_to(git_vector *vector, const char *string, bool is_fetch)
9c82357b 31{
4330ab26 32 git_refspec *spec;
9c82357b 33
4330ab26
CMN
34 spec = git__calloc(1, sizeof(git_refspec));
35 GITERR_CHECK_ALLOC(spec);
36
1be680c4
CMN
37 if (git_refspec__parse(spec, string, is_fetch) < 0) {
38 git__free(spec);
39 return -1;
40 }
4330ab26
CMN
41
42 spec->push = !is_fetch;
3f894205 43 if (git_vector_insert(vector, spec) < 0) {
1be680c4
CMN
44 git_refspec__free(spec);
45 git__free(spec);
46 return -1;
47 }
9c82357b 48
4330ab26 49 return 0;
9c82357b
CMN
50}
51
3f894205
CMN
52static int add_refspec(git_remote *remote, const char *string, bool is_fetch)
53{
54 return add_refspec_to(&remote->refspecs, string, is_fetch);
55}
56
24f2f94e
CMN
57static int download_tags_value(git_remote *remote, git_config *cfg)
58{
9a97f49e 59 git_config_entry *ce;
24f2f94e
CMN
60 git_buf buf = GIT_BUF_INIT;
61 int error;
62
df50512a 63 /* The 0 value is the default (auto), let's see if we need to change it */
24f2f94e
CMN
64 if (git_buf_printf(&buf, "remote.%s.tagopt", remote->name) < 0)
65 return -1;
66
9f77b3f6 67 error = git_config__lookup_entry(&ce, cfg, git_buf_cstr(&buf), false);
24f2f94e 68 git_buf_free(&buf);
24f2f94e 69
9f77b3f6
RB
70 if (!error && ce && ce->value) {
71 if (!strcmp(ce->value, "--no-tags"))
72 remote->download_tags = GIT_REMOTE_DOWNLOAD_TAGS_NONE;
73 else if (!strcmp(ce->value, "--tags"))
74 remote->download_tags = GIT_REMOTE_DOWNLOAD_TAGS_ALL;
bf6bebe2 75 }
24f2f94e 76
9a97f49e 77 git_config_entry_free(ce);
24f2f94e
CMN
78 return error;
79}
80
032ba9e4 81static int ensure_remote_name_is_valid(const char *name)
82{
2bca5b67 83 int error = 0;
032ba9e4 84
2bca5b67 85 if (!git_remote_is_valid_name(name)) {
032ba9e4 86 giterr_set(
87 GITERR_CONFIG,
183aa4f8 88 "'%s' is not a valid remote name.", name ? name : "(null)");
032ba9e4 89 error = GIT_EINVALIDSPEC;
90 }
91
92 return error;
93}
94
41698f22
CMN
95#if 0
96/* We could export this as a helper */
80fc7d6b 97static int get_check_cert(int *out, git_repository *repo)
af6dab7e
PK
98{
99 git_config *cfg;
100 const char *val;
80fc7d6b
ET
101 int error = 0;
102
103 assert(out && repo);
af6dab7e 104
80fc7d6b
ET
105 /* By default, we *DO* want to verify the certificate. */
106 *out = 1;
af6dab7e
PK
107
108 /* Go through the possible sources for SSL verification settings, from
109 * most specific to least specific. */
110
111 /* GIT_SSL_NO_VERIFY environment variable */
8f2a3d62 112 if ((val = getenv("GIT_SSL_NO_VERIFY")) != NULL)
80fc7d6b 113 return git_config_parse_bool(out, val);
af6dab7e
PK
114
115 /* http.sslVerify config setting */
80fc7d6b
ET
116 if ((error = git_repository_config__weakptr(&cfg, repo)) < 0)
117 return error;
af6dab7e 118
9f77b3f6 119 *out = git_config__get_bool_force(cfg, "http.sslverify", 1);
80fc7d6b 120 return 0;
af6dab7e 121}
41698f22 122#endif
af6dab7e 123
12f32d91
ET
124static int canonicalize_url(git_buf *out, const char *in)
125{
5b0c6306 126#ifdef GIT_WIN32
12f32d91
ET
127 const char *c;
128
12f32d91
ET
129 /* Given a UNC path like \\server\path, we need to convert this
130 * to //server/path for compatibility with core git.
131 */
132 if (in[0] == '\\' && in[1] == '\\' &&
133 (git__isalpha(in[2]) || git__isdigit(in[2]))) {
134 for (c = in; *c; c++)
135 git_buf_putc(out, *c == '\\' ? '/' : *c);
136
137 return git_buf_oom(out) ? -1 : 0;
138 }
139#endif
140
141 return git_buf_puts(out, in);
142}
143
874dcb25 144static int create_internal(git_remote **out, git_repository *repo, const char *name, const char *url, const char *fetch)
778e1c73
CMN
145{
146 git_remote *remote;
a8846da7 147 git_config *config = NULL;
22261344
CMN
148 git_buf canonical_url = GIT_BUF_INIT;
149 git_buf var = GIT_BUF_INIT;
44f36f6e 150 int error = -1;
778e1c73 151
4bef3565 152 /* name is optional */
874dcb25 153 assert(out && repo && url);
617bfdf4 154
22261344
CMN
155 if ((error = git_repository_config__weakptr(&config, repo)) < 0)
156 return error;
157
59bccf33 158 remote = git__calloc(1, sizeof(git_remote));
4376f7f6 159 GITERR_CHECK_ALLOC(remote);
778e1c73 160
778e1c73 161 remote->repo = repo;
b0f6e45d 162 remote->update_fetchhead = 1;
617bfdf4 163
12f32d91
ET
164 if (git_vector_init(&remote->refs, 32, NULL) < 0 ||
165 canonicalize_url(&canonical_url, url) < 0)
44f36f6e 166 goto on_error;
d88d4311 167
12f32d91 168 remote->url = git_buf_detach(&canonical_url);
778e1c73 169
617bfdf4
CMN
170 if (name != NULL) {
171 remote->name = git__strdup(name);
4376f7f6 172 GITERR_CHECK_ALLOC(remote->name);
22261344
CMN
173
174 if ((error = git_buf_printf(&var, CONFIG_URL_FMT, name)) < 0)
175 goto on_error;
176
177 if ((error = git_config_set_string(config, var.ptr, remote->url)) < 0)
178 goto on_error;
617bfdf4
CMN
179 }
180
baaa8a44 181 if (fetch != NULL) {
4330ab26 182 if (add_refspec(remote, fetch, true) < 0)
baaa8a44 183 goto on_error;
d3cd7da5 184
1ef3f0ce
DC
185 if ((error = git_repository_config_snapshot(&config, repo)) < 0)
186 goto on_error;
187
69f0032b 188 if ((error = lookup_remote_prune_config(remote, config, name)) < 0)
1ef3f0ce
DC
189 goto on_error;
190
d3cd7da5 191 /* Move the data over to where the matching functions can find them */
69f0032b 192 if ((error = dwim_refspecs(&remote->active_refspecs, &remote->refspecs, &remote->refs)) < 0)
d3cd7da5 193 goto on_error;
baaa8a44
CMN
194 }
195
215af2cc 196 if (!name)
197 /* A remote without a name doesn't download tags */
c648d4a8 198 remote->download_tags = GIT_REMOTE_DOWNLOAD_TAGS_NONE;
c648d4a8 199
22261344
CMN
200 git_buf_free(&var);
201
778e1c73 202 *out = remote;
a8846da7 203 error = 0;
baaa8a44
CMN
204
205on_error:
a8846da7
ET
206 if (error)
207 git_remote_free(remote);
208
1ef3f0ce 209 git_config_free(config);
12f32d91 210 git_buf_free(&canonical_url);
22261344 211 git_buf_free(&var);
44f36f6e 212 return error;
778e1c73
CMN
213}
214
592f466c
BS
215static int ensure_remote_doesnot_exist(git_repository *repo, const char *name)
216{
217 int error;
218 git_remote *remote;
219
209425ce 220 error = git_remote_lookup(&remote, repo, name);
592f466c
BS
221
222 if (error == GIT_ENOTFOUND)
223 return 0;
224
225 if (error < 0)
226 return error;
227
228 git_remote_free(remote);
229
230 giterr_set(
231 GITERR_CONFIG,
232 "Remote '%s' already exists.", name);
233
234 return GIT_EEXISTS;
235}
236
f19304d2 237
874dcb25
BS
238int git_remote_create(git_remote **out, git_repository *repo, const char *name, const char *url)
239{
240 git_buf buf = GIT_BUF_INIT;
241 int error;
242
874dcb25
BS
243 if (git_buf_printf(&buf, "+refs/heads/*:refs/remotes/%s/*", name) < 0)
244 return -1;
245
a68e217f 246 error = git_remote_create_with_fetchspec(out, repo, name, url, git_buf_cstr(&buf));
874dcb25
BS
247 git_buf_free(&buf);
248
a68e217f 249 return error;
874dcb25
BS
250}
251
40b99d05
VG
252int git_remote_create_with_fetchspec(git_remote **out, git_repository *repo, const char *name, const char *url, const char *fetch)
253{
40b99d05
VG
254 git_remote *remote = NULL;
255 int error;
256
257 if ((error = ensure_remote_name_is_valid(name)) < 0)
258 return error;
259
260 if ((error = ensure_remote_doesnot_exist(repo, name)) < 0)
261 return error;
874dcb25 262
0fe522d1 263 if (create_internal(&remote, repo, name, url, fetch) < 0)
874dcb25
BS
264 goto on_error;
265
c5193e3c 266 if (git_remote_save(remote) < 0)
874dcb25
BS
267 goto on_error;
268
c5193e3c 269 *out = remote;
270
874dcb25
BS
271 return 0;
272
273on_error:
c5193e3c 274 git_remote_free(remote);
874dcb25
BS
275 return -1;
276}
277
fd536d29 278int git_remote_create_anonymous(git_remote **out, git_repository *repo, const char *url, const char *fetch)
874dcb25
BS
279{
280 int error;
281 git_remote *remote;
282
79000951 283 if ((error = create_internal(&remote, repo, NULL, url, fetch)) < 0)
874dcb25
BS
284 return error;
285
874dcb25
BS
286 *out = remote;
287 return 0;
288}
289
991b2840 290int git_remote_dup(git_remote **dest, git_remote *source)
40ef47dd 291{
991b2840
AS
292 int error = 0;
293 git_strarray refspecs = { 0 };
40ef47dd
AS
294 git_remote *remote = git__calloc(1, sizeof(git_remote));
295 GITERR_CHECK_ALLOC(remote);
296
40ef47dd
AS
297 if (source->name != NULL) {
298 remote->name = git__strdup(source->name);
299 GITERR_CHECK_ALLOC(remote->name);
300 }
301
302 if (source->url != NULL) {
303 remote->url = git__strdup(source->url);
304 GITERR_CHECK_ALLOC(remote->url);
305 }
306
307 if (source->pushurl != NULL) {
308 remote->pushurl = git__strdup(source->pushurl);
1697cd6f 309 GITERR_CHECK_ALLOC(remote->pushurl);
40ef47dd
AS
310 }
311
312 remote->repo = source->repo;
40ef47dd 313 remote->download_tags = source->download_tags;
40ef47dd 314 remote->update_fetchhead = source->update_fetchhead;
5f473947 315 remote->prune_refs = source->prune_refs;
40ef47dd 316
991b2840
AS
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) {
320 error = -1;
321 goto cleanup;
40ef47dd
AS
322 }
323
991b2840
AS
324 if ((error = git_remote_get_fetch_refspecs(&refspecs, source)) < 0 ||
325 (error = git_remote_set_fetch_refspecs(remote, &refspecs)) < 0)
326 goto cleanup;
327
328 git_strarray_free(&refspecs);
329
330 if ((error = git_remote_get_push_refspecs(&refspecs, source)) < 0 ||
331 (error = git_remote_set_push_refspecs(remote, &refspecs)) < 0)
332 goto cleanup;
333
40ef47dd
AS
334 *dest = remote;
335
991b2840
AS
336cleanup:
337
338 git_strarray_free(&refspecs);
339
340 if (error < 0)
341 git__free(remote);
342
343 return error;
40ef47dd
AS
344}
345
4330ab26
CMN
346struct refspec_cb_data {
347 git_remote *remote;
348 int fetch;
349};
350
351static int refspec_cb(const git_config_entry *entry, void *payload)
352{
96869a4e 353 struct refspec_cb_data *data = (struct refspec_cb_data *)payload;
25e0b157 354 return add_refspec(data->remote, entry->value, data->fetch);
4330ab26
CMN
355}
356
bf6bebe2 357static int get_optional_config(
c9ffa84b 358 bool *found, git_config *config, git_buf *buf,
359 git_config_foreach_cb cb, void *payload)
bf6bebe2
RB
360{
361 int error = 0;
362 const char *key = git_buf_cstr(buf);
363
364 if (git_buf_oom(buf))
365 return -1;
366
367 if (cb != NULL)
4efa3290 368 error = git_config_get_multivar_foreach(config, key, NULL, cb, payload);
bf6bebe2
RB
369 else
370 error = git_config_get_string(payload, config, key);
371
c9ffa84b 372 if (found)
373 *found = !error;
374
bf6bebe2
RB
375 if (error == GIT_ENOTFOUND) {
376 giterr_clear();
377 error = 0;
378 }
379
bf6bebe2
RB
380 return error;
381}
382
209425ce 383int git_remote_lookup(git_remote **out, git_repository *repo, const char *name)
9c82357b
CMN
384{
385 git_remote *remote;
f0f3a18a 386 git_buf buf = GIT_BUF_INIT;
9c82357b 387 const char *val;
4376f7f6 388 int error = 0;
9462c471 389 git_config *config;
96869a4e 390 struct refspec_cb_data data = { NULL };
c9ffa84b 391 bool optional_setting_found = false, found;
4330ab26 392
9462c471
VM
393 assert(out && repo && name);
394
032ba9e4 395 if ((error = ensure_remote_name_is_valid(name)) < 0)
396 return error;
397
ac99d86b 398 if ((error = git_repository_config_snapshot(&config, repo)) < 0)
29c4cb09 399 return error;
4bef3565 400
392702ee 401 remote = git__calloc(1, sizeof(git_remote));
4376f7f6 402 GITERR_CHECK_ALLOC(remote);
9c82357b 403
b0f6e45d 404 remote->update_fetchhead = 1;
9c82357b 405 remote->name = git__strdup(name);
4376f7f6 406 GITERR_CHECK_ALLOC(remote->name);
9c82357b 407
25e0b157
RB
408 if (git_vector_init(&remote->refs, 32, NULL) < 0 ||
409 git_vector_init(&remote->refspecs, 2, NULL) < 0 ||
2cdd5c57 410 git_vector_init(&remote->passive_refspecs, 2, NULL) < 0 ||
25e0b157 411 git_vector_init(&remote->active_refspecs, 2, NULL) < 0) {
2fb9d6de 412 error = -1;
413 goto cleanup;
414 }
d88d4311 415
25e0b157 416 if ((error = git_buf_printf(&buf, "remote.%s.url", name)) < 0)
2fb9d6de 417 goto cleanup;
9c82357b 418
c9ffa84b 419 if ((error = get_optional_config(&found, config, &buf, NULL, (void *)&val)) < 0)
9c82357b 420 goto cleanup;
bf6bebe2 421
c9ffa84b 422 optional_setting_found |= found;
423
9462c471 424 remote->repo = repo;
c9ffa84b 425
426 if (found && strlen(val) > 0) {
427 remote->url = git__strdup(val);
428 GITERR_CHECK_ALLOC(remote->url);
429 }
9c82357b 430
bf6bebe2 431 val = NULL;
3ed4b501 432 git_buf_clear(&buf);
bf6bebe2 433 git_buf_printf(&buf, "remote.%s.pushurl", name);
3ed4b501 434
c9ffa84b 435 if ((error = get_optional_config(&found, config, &buf, NULL, (void *)&val)) < 0)
3ed4b501 436 goto cleanup;
3ed4b501 437
c9ffa84b 438 optional_setting_found |= found;
439
440 if (!optional_setting_found) {
441 error = GIT_ENOTFOUND;
d723dbed 442 giterr_set(GITERR_CONFIG, "Remote '%s' does not exist.", name);
3ed4b501 443 goto cleanup;
c9ffa84b 444 }
3ed4b501 445
c9ffa84b 446 if (found && strlen(val) > 0) {
3ed4b501
SC
447 remote->pushurl = git__strdup(val);
448 GITERR_CHECK_ALLOC(remote->pushurl);
449 }
450
4330ab26
CMN
451 data.remote = remote;
452 data.fetch = true;
96869a4e 453
f0f3a18a 454 git_buf_clear(&buf);
bf6bebe2
RB
455 git_buf_printf(&buf, "remote.%s.fetch", name);
456
c9ffa84b 457 if ((error = get_optional_config(NULL, config, &buf, refspec_cb, &data)) < 0)
2fb9d6de 458 goto cleanup;
9c82357b 459
4330ab26 460 data.fetch = false;
bf6bebe2
RB
461 git_buf_clear(&buf);
462 git_buf_printf(&buf, "remote.%s.push", name);
9c82357b 463
c9ffa84b 464 if ((error = get_optional_config(NULL, config, &buf, refspec_cb, &data)) < 0)
9c82357b
CMN
465 goto cleanup;
466
24f2f94e
CMN
467 if (download_tags_value(remote, config) < 0)
468 goto cleanup;
469
1ef3f0ce
DC
470 if ((error = lookup_remote_prune_config(remote, config, name)) < 0)
471 goto cleanup;
472
473 /* Move the data over to where the matching functions can find them */
69f0032b 474 if ((error = dwim_refspecs(&remote->active_refspecs, &remote->refspecs, &remote->refs)) < 0)
1ef3f0ce
DC
475 goto cleanup;
476
477 *out = remote;
478
479cleanup:
480 git_config_free(config);
481 git_buf_free(&buf);
482
483 if (error < 0)
484 git_remote_free(remote);
485
486 return error;
487}
488
489static int lookup_remote_prune_config(git_remote *remote, git_config *config, const char *name)
490{
491 git_buf buf = GIT_BUF_INIT;
492 int error = 0;
493
5f473947
L
494 git_buf_printf(&buf, "remote.%s.prune", name);
495
496 if ((error = git_config_get_bool(&remote->prune_refs, config, git_buf_cstr(&buf))) < 0) {
497 if (error == GIT_ENOTFOUND) {
498 giterr_clear();
499
500 if ((error = git_config_get_bool(&remote->prune_refs, config, "fetch.prune")) < 0) {
501 if (error == GIT_ENOTFOUND) {
502 giterr_clear();
66b71ea5 503 error = 0;
5f473947
L
504 }
505 }
506 }
507 }
508
f0f3a18a 509 git_buf_free(&buf);
9c82357b
CMN
510 return error;
511}
512
4330ab26 513static int update_config_refspec(const git_remote *remote, git_config *config, int direction)
4fe5520a 514{
4330ab26 515 git_buf name = GIT_BUF_INIT;
66566516 516 unsigned int push;
4330ab26
CMN
517 const char *dir;
518 size_t i;
bf6bebe2 519 int error = 0;
3793fa9b 520 const char *cname;
4fe5520a 521
4330ab26
CMN
522 push = direction == GIT_DIRECTION_PUSH;
523 dir = push ? "push" : "fetch";
4fe5520a 524
4330ab26
CMN
525 if (git_buf_printf(&name, "remote.%s.%s", remote->name, dir) < 0)
526 return -1;
3793fa9b 527 cname = git_buf_cstr(&name);
4fe5520a 528
4330ab26 529 /* Clear out the existing config */
bf6bebe2 530 while (!error)
3793fa9b 531 error = git_config_delete_multivar(config, cname, ".*");
4fe5520a 532
4330ab26
CMN
533 if (error != GIT_ENOTFOUND)
534 return error;
535
1be680c4 536 for (i = 0; i < remote->refspecs.length; i++) {
4330ab26 537 git_refspec *spec = git_vector_get(&remote->refspecs, i);
4330ab26
CMN
538
539 if (spec->push != push)
540 continue;
541
376454d0
DRT
542 // "$^" is a unmatcheable regexp: it will not match anything at all, so
543 // all values will be considered new and we will not replace any
544 // present value.
bf6bebe2 545 if ((error = git_config_set_multivar(
376454d0 546 config, cname, "$^", spec->string)) < 0) {
4330ab26
CMN
547 goto cleanup;
548 }
549 }
550
551 giterr_clear();
552 error = 0;
4fe5520a 553
554cleanup:
555 git_buf_free(&name);
4fe5520a 556
557 return error;
558}
559
89e5ed98
CMN
560int git_remote_save(const git_remote *remote)
561{
218c88a9 562 int error;
8286300a 563 git_config *cfg;
218c88a9 564 const char *tagopt = NULL;
4fe5520a 565 git_buf buf = GIT_BUF_INIT;
9a97f49e 566 git_config_entry *existing = NULL;
89e5ed98 567
e497b16c 568 assert(remote);
569
c07b52df 570 if (!remote->name) {
fd536d29 571 giterr_set(GITERR_INVALID, "Can't save an anonymous remote.");
874dcb25 572 return GIT_EINVALIDSPEC;
a71c27cc
BS
573 }
574
032ba9e4 575 if ((error = ensure_remote_name_is_valid(remote->name)) < 0)
576 return error;
89e5ed98 577
8286300a
RB
578 if ((error = git_repository_config__weakptr(&cfg, remote->repo)) < 0)
579 return error;
89e5ed98 580
8286300a
RB
581 /* after this point, buffer is allocated so end with cleanup */
582
8286300a
RB
583 if ((error = update_config_refspec(remote, cfg, GIT_DIRECTION_FETCH)) < 0)
584 goto cleanup;
89e5ed98 585
8286300a
RB
586 if ((error = update_config_refspec(remote, cfg, GIT_DIRECTION_PUSH)) < 0)
587 goto cleanup;
89e5ed98 588
218c88a9
CMN
589 /*
590 * What action to take depends on the old and new values. This
591 * is describes by the table below. tagopt means whether the
592 * is already a value set in the config
593 *
594 * AUTO ALL or NONE
595 * +-----------------------+
596 * tagopt | remove | set |
597 * +---------+-------------|
598 * !tagopt | nothing | set |
599 * +---------+-------------+
600 */
601
602 git_buf_clear(&buf);
8286300a
RB
603 if ((error = git_buf_printf(&buf, "remote.%s.tagopt", remote->name)) < 0)
604 goto cleanup;
218c88a9 605
8286300a
RB
606 if ((error = git_config__lookup_entry(
607 &existing, cfg, git_buf_cstr(&buf), false)) < 0)
608 goto cleanup;
218c88a9 609
8286300a
RB
610 if (remote->download_tags == GIT_REMOTE_DOWNLOAD_TAGS_ALL)
611 tagopt = "--tags";
612 else if (remote->download_tags == GIT_REMOTE_DOWNLOAD_TAGS_NONE)
613 tagopt = "--no-tags";
614 else if (existing != NULL)
615 tagopt = NULL;
4376f7f6 616
8286300a
RB
617 error = git_config__update_entry(
618 cfg, git_buf_cstr(&buf), tagopt, true, false);
4376f7f6 619
8286300a 620cleanup:
9a97f49e 621 git_config_entry_free(existing);
4376f7f6 622 git_buf_free(&buf);
8286300a 623 return error;
89e5ed98
CMN
624}
625
df705148 626const char *git_remote_name(const git_remote *remote)
9c82357b 627{
4bef3565 628 assert(remote);
9c82357b
CMN
629 return remote->name;
630}
631
85e1eded
ES
632git_repository *git_remote_owner(const git_remote *remote)
633{
634 assert(remote);
635 return remote->repo;
636}
637
df705148 638const char *git_remote_url(const git_remote *remote)
9c82357b 639{
4bef3565 640 assert(remote);
9c82357b
CMN
641 return remote->url;
642}
643
22261344 644static int set_url(git_repository *repo, const char *remote, const char *pattern, const char *url)
76501590 645{
22261344
CMN
646 git_config *cfg;
647 git_buf buf = GIT_BUF_INIT, canonical_url = GIT_BUF_INIT;
648 int error;
76501590 649
22261344 650 assert(repo && remote);
76501590 651
22261344
CMN
652 if ((error = ensure_remote_name_is_valid(remote)) < 0)
653 return error;
654
655 if ((error = git_repository_config__weakptr(&cfg, repo)) < 0)
656 return error;
657
658 if ((error = git_buf_printf(&buf, pattern, remote)) < 0)
659 return error;
660
661 if (url) {
662 if ((error = canonicalize_url(&canonical_url, url)) < 0)
663 goto cleanup;
664
665 error = git_config_set_string(cfg, buf.ptr, url);
666 } else {
667 error = git_config_delete_entry(cfg, buf.ptr);
668 }
669
670cleanup:
671 git_buf_free(&canonical_url);
672 git_buf_free(&buf);
673
674 return error;
675}
676
677int git_remote_set_url(git_repository *repo, const char *remote, const char *url)
678{
679 return set_url(repo, remote, CONFIG_URL_FMT, url);
76501590
SC
680}
681
df705148 682const char *git_remote_pushurl(const git_remote *remote)
76501590
SC
683{
684 assert(remote);
685 return remote->pushurl;
686}
687
22261344 688int git_remote_set_pushurl(git_repository *repo, const char *remote, const char* url)
76501590 689{
22261344 690 return set_url(repo, remote, CONFIG_PUSHURL_FMT, url);
76501590
SC
691}
692
eff5b499
SC
693const char* git_remote__urlfordirection(git_remote *remote, int direction)
694{
695 assert(remote);
696
b83c92dd 697 assert(direction == GIT_DIRECTION_FETCH || direction == GIT_DIRECTION_PUSH);
698
df705148 699 if (direction == GIT_DIRECTION_FETCH) {
eff5b499
SC
700 return remote->url;
701 }
702
df705148 703 if (direction == GIT_DIRECTION_PUSH) {
eff5b499
SC
704 return remote->pushurl ? remote->pushurl : remote->url;
705 }
706
707 return NULL;
708}
709
8f0104ec
CMN
710int set_transport_callbacks(git_transport *t, const git_remote_callbacks *cbs)
711{
712 if (!t->set_callbacks || !cbs)
713 return 0;
714
715 return t->set_callbacks(t, cbs->sideband_progress, NULL,
716 cbs->certificate_check, cbs->payload);
717}
718
719int git_remote_connect(git_remote *remote, git_direction direction, const git_remote_callbacks *callbacks)
9ba49bb5 720{
9ba49bb5 721 git_transport *t;
c0c39025 722 const char *url;
41fb1ca0 723 int flags = GIT_TRANSPORTFLAGS_NONE;
80fc7d6b 724 int error;
8f0104ec 725 void *payload = NULL;
058b753c
CMN
726 git_cred_acquire_cb credentials = NULL;
727 git_transport_cb transport = NULL;
9ba49bb5 728
4bef3565
VM
729 assert(remote);
730
8f0104ec
CMN
731 if (callbacks) {
732 GITERR_CHECK_VERSION(callbacks, GIT_REMOTE_CALLBACKS_VERSION, "git_remote_callbacks");
733 credentials = callbacks->credentials;
058b753c 734 transport = callbacks->transport;
8f0104ec
CMN
735 payload = callbacks->payload;
736 }
737
41fb1ca0
PK
738 t = remote->transport;
739
c0c39025 740 url = git_remote__urlfordirection(remote, direction);
80fc7d6b 741 if (url == NULL) {
44bc0c6a 742 giterr_set(GITERR_INVALID,
743 "Malformed remote '%s' - missing URL", remote->name);
eff5b499 744 return -1;
44bc0c6a 745 }
eff5b499 746
1697cd6f
PK
747 /* If we don't have a transport object yet, and the caller specified a
748 * custom transport factory, use that */
058b753c
CMN
749 if (!t && transport &&
750 (error = transport(&t, remote, payload)) < 0)
1697cd6f
PK
751 return error;
752
753 /* If we still don't have a transport, then use the global
754 * transport registrations which map URI schemes to transport factories */
80fc7d6b
ET
755 if (!t && (error = git_transport_new(&t, remote, url)) < 0)
756 return error;
9ba49bb5 757
8f0104ec
CMN
758 if ((error = set_transport_callbacks(t, callbacks)) < 0 ||
759 (error = t->connect(t, url, credentials, payload, direction, flags)) != 0)
4376f7f6 760 goto on_error;
9ba49bb5
CMN
761
762 remote->transport = t;
763
4376f7f6 764 return 0;
9ba49bb5 765
4376f7f6
CMN
766on_error:
767 t->free(t);
613d5eb9
PK
768
769 if (t == remote->transport)
770 remote->transport = NULL;
771
80fc7d6b 772 return error;
9ba49bb5
CMN
773}
774
359dce72 775int git_remote_ls(const git_remote_head ***out, size_t *size, git_remote *remote)
9ba49bb5 776{
d88d4311
VM
777 assert(remote);
778
dc8adda4 779 if (!remote->transport) {
699dfcc3 780 giterr_set(GITERR_NET, "this remote has never connected");
dc8adda4
JG
781 return -1;
782 }
783
359dce72 784 return remote->transport->ls(out, size, remote->transport);
9ba49bb5
CMN
785}
786
613d5eb9
PK
787int git_remote__get_http_proxy(git_remote *remote, bool use_ssl, char **proxy_url)
788{
789 git_config *cfg;
9a97f49e 790 git_config_entry *ce = NULL;
9f77b3f6 791 const char *val = NULL;
80fc7d6b 792 int error;
613d5eb9
PK
793
794 assert(remote);
795
a71c27cc 796 if (!proxy_url || !remote->repo)
613d5eb9
PK
797 return -1;
798
799 *proxy_url = NULL;
800
80fc7d6b
ET
801 if ((error = git_repository_config__weakptr(&cfg, remote->repo)) < 0)
802 return error;
613d5eb9
PK
803
804 /* Go through the possible sources for proxy configuration, from most specific
805 * to least specific. */
806
807 /* remote.<name>.proxy config setting */
9f77b3f6 808 if (remote->name && remote->name[0]) {
613d5eb9
PK
809 git_buf buf = GIT_BUF_INIT;
810
80fc7d6b
ET
811 if ((error = git_buf_printf(&buf, "remote.%s.proxy", remote->name)) < 0)
812 return error;
613d5eb9 813
9f77b3f6
RB
814 error = git_config__lookup_entry(&ce, cfg, git_buf_cstr(&buf), false);
815 git_buf_free(&buf);
613d5eb9 816
9f77b3f6 817 if (error < 0)
80fc7d6b 818 return error;
613d5eb9 819
9f77b3f6
RB
820 if (ce && ce->value) {
821 val = ce->value;
822 goto found;
823 }
613d5eb9
PK
824 }
825
826 /* http.proxy config setting */
9f77b3f6 827 if ((error = git_config__lookup_entry(&ce, cfg, "http.proxy", false)) < 0)
80fc7d6b 828 return error;
9f77b3f6
RB
829 if (ce && ce->value) {
830 val = ce->value;
831 goto found;
832 }
613d5eb9
PK
833
834 /* HTTP_PROXY / HTTPS_PROXY environment variables */
835 val = use_ssl ? getenv("HTTPS_PROXY") : getenv("HTTP_PROXY");
836
9f77b3f6
RB
837found:
838 if (val && val[0]) {
613d5eb9
PK
839 *proxy_url = git__strdup(val);
840 GITERR_CHECK_ALLOC(*proxy_url);
613d5eb9 841 }
9a97f49e 842 git_config_entry_free(ce);
613d5eb9
PK
843
844 return 0;
845}
846
af613ecd
CMN
847/* DWIM `refspecs` based on `refs` and append the output to `out` */
848static int dwim_refspecs(git_vector *out, git_vector *refspecs, git_vector *refs)
d8488457 849{
af613ecd 850 size_t i;
d8488457 851 git_refspec *spec;
d8488457
CMN
852
853 git_vector_foreach(refspecs, i, spec) {
af613ecd
CMN
854 if (git_refspec__dwim_one(out, spec, refs) < 0)
855 return -1;
856 }
d8488457 857
af613ecd
CMN
858 return 0;
859}
d8488457 860
af613ecd
CMN
861static void free_refspecs(git_vector *vec)
862{
863 size_t i;
864 git_refspec *spec;
d8488457 865
af613ecd
CMN
866 git_vector_foreach(vec, i, spec) {
867 git_refspec__free(spec);
868 git__free(spec);
d8488457
CMN
869 }
870
af613ecd 871 git_vector_clear(vec);
d8488457
CMN
872}
873
874static int remote_head_cmp(const void *_a, const void *_b)
875{
876 const git_remote_head *a = (git_remote_head *) _a;
877 const git_remote_head *b = (git_remote_head *) _b;
878
879 return git__strcmp_cb(a->name, b->name);
880}
881
877cde76
CMN
882static int ls_to_vector(git_vector *out, git_remote *remote)
883{
884 git_remote_head **heads;
885 size_t heads_len, i;
886
887 if (git_remote_ls((const git_remote_head ***)&heads, &heads_len, remote) < 0)
888 return -1;
889
890 if (git_vector_init(out, heads_len, remote_head_cmp) < 0)
891 return -1;
892
893 for (i = 0; i < heads_len; i++) {
894 if (git_vector_insert(out, heads[i]) < 0)
895 return -1;
896 }
897
898 return 0;
899}
900
8f0104ec 901int git_remote_download(git_remote *remote, const git_strarray *refspecs, const git_fetch_options *opts)
48a65a07 902{
eecc1772 903 int error = -1;
3f894205
CMN
904 size_t i;
905 git_vector refs, specs, *to_active;
8f0104ec 906 const git_remote_callbacks *cbs = NULL;
95057b85 907
1e3b8ed5 908 assert(remote);
4bef3565 909
8f0104ec
CMN
910 if (opts) {
911 GITERR_CHECK_VERSION(&opts->callbacks, GIT_REMOTE_CALLBACKS_VERSION, "git_remote_callbacks");
912 cbs = &opts->callbacks;
913 }
914
915 if (!git_remote_connected(remote) &&
916 (error = git_remote_connect(remote, GIT_DIRECTION_FETCH, cbs)) < 0)
917 goto on_error;
918
877cde76 919 if (ls_to_vector(&refs, remote) < 0)
d8488457 920 return -1;
d8488457 921
3f894205
CMN
922 if ((git_vector_init(&specs, 0, NULL)) < 0)
923 goto on_error;
924
c5837cad 925 remote->passed_refspecs = 0;
8e398e4c 926 if (!refspecs || !refspecs->count) {
3f894205
CMN
927 to_active = &remote->refspecs;
928 } else {
929 for (i = 0; i < refspecs->count; i++) {
930 if ((error = add_refspec_to(&specs, refspecs->strings[i], true)) < 0)
931 goto on_error;
932 }
933
934 to_active = &specs;
c5837cad 935 remote->passed_refspecs = 1;
3f894205
CMN
936 }
937
2cdd5c57
CMN
938 free_refspecs(&remote->passive_refspecs);
939 if ((error = dwim_refspecs(&remote->passive_refspecs, &remote->refspecs, &refs)) < 0)
940 goto on_error;
af613ecd 941
2cdd5c57 942 free_refspecs(&remote->active_refspecs);
3f894205 943 error = dwim_refspecs(&remote->active_refspecs, to_active, &refs);
2cdd5c57 944
877cde76 945 git_vector_free(&refs);
3f894205
CMN
946 free_refspecs(&specs);
947 git_vector_free(&specs);
877cde76
CMN
948
949 if (error < 0)
25e0b157 950 return error;
d8488457 951
c070ac64
POL
952 if (remote->push) {
953 git_push_free(remote->push);
954 remote->push = NULL;
955 }
956
95057b85 957 if ((error = git_fetch_negotiate(remote)) < 0)
4376f7f6 958 return error;
95057b85 959
8f0104ec 960 return git_fetch_download_pack(remote, cbs);
3f894205
CMN
961
962on_error:
963 git_vector_free(&refs);
964 free_refspecs(&specs);
965 git_vector_free(&specs);
966 return error;
48a65a07
CMN
967}
968
c3ab1e5a
BS
969int git_remote_fetch(
970 git_remote *remote,
3f894205 971 const git_strarray *refspecs,
8f0104ec 972 const git_fetch_options *opts,
c3ab1e5a 973 const char *reflog_message)
fe3a40a4
CMN
974{
975 int error;
6fb373a0 976 bool prune = false;
db55bb73 977 git_buf reflog_msg_buf = GIT_BUF_INIT;
8f0104ec
CMN
978 const git_remote_callbacks *cbs = NULL;
979
980 if (opts) {
981 GITERR_CHECK_VERSION(&opts->callbacks, GIT_REMOTE_CALLBACKS_VERSION, "git_remote_callbacks");
982 cbs = &opts->callbacks;
983 }
fe3a40a4
CMN
984
985 /* Connect and download everything */
8f0104ec 986 if ((error = git_remote_connect(remote, GIT_DIRECTION_FETCH, cbs)) != 0)
fe3a40a4
CMN
987 return error;
988
8f0104ec 989 error = git_remote_download(remote, refspecs, opts);
fe3a40a4
CMN
990
991 /* We don't need to be connected anymore */
992 git_remote_disconnect(remote);
993
06a8f5c3
BL
994 /* If the download failed, return the error */
995 if (error != 0)
996 return error;
997
db55bb73
BS
998 /* Default reflog message */
999 if (reflog_message)
1000 git_buf_sets(&reflog_msg_buf, reflog_message);
1001 else {
1002 git_buf_printf(&reflog_msg_buf, "fetch %s",
1003 remote->name ? remote->name : remote->url);
1004 }
1005
fe3a40a4 1006 /* Create "remote/foo" branches for all remote branches */
8f0104ec 1007 error = git_remote_update_tips(remote, cbs, git_buf_cstr(&reflog_msg_buf));
db55bb73 1008 git_buf_free(&reflog_msg_buf);
8c13eaed
CMN
1009 if (error < 0)
1010 return error;
1011
6fb373a0
CMN
1012 if (opts && opts->prune == GIT_FETCH_PRUNE)
1013 prune = true;
1014 else if (opts && opts->prune == GIT_FETCH_PRUNE_FALLBACK && remote->prune_refs)
1015 prune = true;
1016 else if (opts && opts->prune == GIT_FETCH_NO_PRUNE)
1017 prune = false;
1018 else
1019 prune = remote->prune_refs;
1020
1021 if (prune)
8f0104ec 1022 error = git_remote_prune(remote, cbs);
8c13eaed 1023
db55bb73 1024 return error;
fe3a40a4
CMN
1025}
1026
b0f6e45d
ET
1027static int remote_head_for_fetchspec_src(git_remote_head **out, git_vector *update_heads, const char *fetchspec_src)
1028{
1029 unsigned int i;
1030 git_remote_head *remote_ref;
1031
1032 assert(update_heads && fetchspec_src);
1033
1034 *out = NULL;
7d4b65f6 1035
1036 git_vector_foreach(update_heads, i, remote_ref) {
1037 if (strcmp(remote_ref->name, fetchspec_src) == 0) {
1038 *out = remote_ref;
1039 break;
b0f6e45d
ET
1040 }
1041 }
1042
1043 return 0;
1044}
1045
2c9b9c8b
CMN
1046static int ref_to_update(int *update, git_buf *remote_name, git_remote *remote, git_refspec *spec, const char *ref_name)
1047{
1048 int error = 0;
1049 git_repository *repo;
1050 git_buf upstream_remote = GIT_BUF_INIT;
1051 git_buf upstream_name = GIT_BUF_INIT;
1052
1053 repo = git_remote_owner(remote);
1054
1055 if ((!git_reference__is_branch(ref_name)) ||
1056 !git_remote_name(remote) ||
1057 (error = git_branch_upstream_remote(&upstream_remote, repo, ref_name) < 0) ||
1058 git__strcmp(git_remote_name(remote), git_buf_cstr(&upstream_remote)) ||
1059 (error = git_branch_upstream_name(&upstream_name, repo, ref_name)) < 0 ||
1060 !git_refspec_dst_matches(spec, git_buf_cstr(&upstream_name)) ||
1061 (error = git_refspec_rtransform(remote_name, spec, upstream_name.ptr)) < 0) {
1062 /* Not an error if there is no upstream */
1063 if (error == GIT_ENOTFOUND) {
1064 giterr_clear();
1065 error = 0;
1066 }
1067
1068 *update = 0;
1069 } else {
1070 *update = 1;
1071 }
1072
1073 git_buf_free(&upstream_remote);
1074 git_buf_free(&upstream_name);
1075 return error;
1076}
1077
f49819aa 1078static int remote_head_for_ref(git_remote_head **out, git_remote *remote, git_refspec *spec, git_vector *update_heads, git_reference *ref)
b0f6e45d
ET
1079{
1080 git_reference *resolved_ref = NULL;
b0f6e45d 1081 git_buf remote_name = GIT_BUF_INIT;
f49819aa 1082 git_config *config = NULL;
e235db02 1083 const char *ref_name;
2c9b9c8b 1084 int error = 0, update;
b0f6e45d 1085
4330ab26 1086 assert(out && spec && ref);
b0f6e45d
ET
1087
1088 *out = NULL;
1089
67d4997a
CMN
1090 error = git_reference_resolve(&resolved_ref, ref);
1091
1092 /* If we're in an unborn branch, let's pretend nothing happened */
1093 if (error == GIT_ENOTFOUND && git_reference_type(ref) == GIT_REF_SYMBOLIC) {
1094 ref_name = git_reference_symbolic_target(ref);
1095 error = 0;
1096 } else {
1097 ref_name = git_reference_name(resolved_ref);
1098 }
1099
2c9b9c8b 1100 if ((error = ref_to_update(&update, &remote_name, remote, spec, ref_name)) < 0)
b0f6e45d 1101 goto cleanup;
b0f6e45d 1102
2c9b9c8b
CMN
1103 if (update)
1104 error = remote_head_for_fetchspec_src(out, update_heads, git_buf_cstr(&remote_name));
b0f6e45d
ET
1105
1106cleanup:
f7fcb18f 1107 git_buf_free(&remote_name);
b0f6e45d 1108 git_reference_free(resolved_ref);
f49819aa 1109 git_config_free(config);
b0f6e45d
ET
1110 return error;
1111}
1112
4330ab26 1113static int git_remote_write_fetchhead(git_remote *remote, git_refspec *spec, git_vector *update_heads)
b0f6e45d 1114{
b0f6e45d
ET
1115 git_reference *head_ref = NULL;
1116 git_fetchhead_ref *fetchhead_ref;
1117 git_remote_head *remote_ref, *merge_remote_ref;
1118 git_vector fetchhead_refs;
1119 bool include_all_fetchheads;
1120 unsigned int i = 0;
1121 int error = 0;
1122
1123 assert(remote);
1124
404eadb0
CMN
1125 /* no heads, nothing to do */
1126 if (update_heads->length == 0)
1127 return 0;
1128
b0f6e45d
ET
1129 if (git_vector_init(&fetchhead_refs, update_heads->length, git_fetchhead_ref_cmp) < 0)
1130 return -1;
1131
1132 /* Iff refspec is * (but not subdir slash star), include tags */
1133 include_all_fetchheads = (strcmp(GIT_REFS_HEADS_DIR "*", git_refspec_src(spec)) == 0);
1134
1135 /* Determine what to merge: if refspec was a wildcard, just use HEAD */
1136 if (git_refspec_is_wildcard(spec)) {
1137 if ((error = git_reference_lookup(&head_ref, remote->repo, GIT_HEAD_FILE)) < 0 ||
f49819aa 1138 (error = remote_head_for_ref(&merge_remote_ref, remote, spec, update_heads, head_ref)) < 0)
b0f6e45d
ET
1139 goto cleanup;
1140 } else {
1141 /* If we're fetching a single refspec, that's the only thing that should be in FETCH_HEAD. */
1142 if ((error = remote_head_for_fetchspec_src(&merge_remote_ref, update_heads, git_refspec_src(spec))) < 0)
1143 goto cleanup;
1144 }
1145
1146 /* Create the FETCH_HEAD file */
7d4b65f6 1147 git_vector_foreach(update_heads, i, remote_ref) {
b0f6e45d
ET
1148 int merge_this_fetchhead = (merge_remote_ref == remote_ref);
1149
1150 if (!include_all_fetchheads &&
1151 !git_refspec_src_matches(spec, remote_ref->name) &&
1152 !merge_this_fetchhead)
1153 continue;
1154
1155 if (git_fetchhead_ref_create(&fetchhead_ref,
1156 &remote_ref->oid,
1157 merge_this_fetchhead,
1158 remote_ref->name,
1159 git_remote_url(remote)) < 0)
1160 goto cleanup;
1161
1162 if (git_vector_insert(&fetchhead_refs, fetchhead_ref) < 0)
1163 goto cleanup;
1164 }
1165
1166 git_fetchhead_write(remote->repo, &fetchhead_refs);
1167
1168cleanup:
1169 for (i = 0; i < fetchhead_refs.length; ++i)
1170 git_fetchhead_ref_free(fetchhead_refs.contents[i]);
1171
1172 git_vector_free(&fetchhead_refs);
1173 git_reference_free(head_ref);
1174
1175 return error;
1176}
1177
59ff8b67
CMN
1178/**
1179 * Generate a list of candidates for pruning by getting a list of
1180 * references which match the rhs of an active refspec.
1181 */
1182static int prune_candidates(git_vector *candidates, git_remote *remote)
5f473947
L
1183{
1184 git_strarray arr = { 0 };
59ff8b67 1185 size_t i;
5f473947
L
1186 int error;
1187
1188 if ((error = git_reference_list(&arr, remote->repo)) < 0)
1189 return error;
1190
59ff8b67
CMN
1191 for (i = 0; i < arr.count; i++) {
1192 const char *refname = arr.strings[i];
1193 char *refname_dup;
1194
1195 if (!git_remote__matching_dst_refspec(remote, refname))
1196 continue;
1197
1198 refname_dup = git__strdup(refname);
1199 GITERR_CHECK_ALLOC(refname_dup);
1200
1201 if ((error = git_vector_insert(candidates, refname_dup)) < 0)
1202 goto out;
1203 }
1204
1205out:
1206 git_strarray_free(&arr);
1207 return error;
1208}
1209
1210static int find_head(const void *_a, const void *_b)
1211{
1212 git_remote_head *a = (git_remote_head *) _a;
1213 git_remote_head *b = (git_remote_head *) _b;
1214
1215 return strcmp(a->name, b->name);
1216}
1217
8f0104ec 1218int git_remote_prune(git_remote *remote, const git_remote_callbacks *callbacks)
59ff8b67
CMN
1219{
1220 size_t i, j;
1221 git_vector remote_refs = GIT_VECTOR_INIT;
1222 git_vector candidates = GIT_VECTOR_INIT;
1223 const git_refspec *spec;
1224 const char *refname;
1225 int error;
1226 git_oid zero_id = {{ 0 }};
1227
8f0104ec
CMN
1228 if (callbacks)
1229 GITERR_CHECK_VERSION(callbacks, GIT_REMOTE_CALLBACKS_VERSION, "git_remote_callbacks");
1230
5f473947
L
1231 if ((error = ls_to_vector(&remote_refs, remote)) < 0)
1232 goto cleanup;
1233
59ff8b67 1234 git_vector_set_cmp(&remote_refs, find_head);
5f473947 1235
59ff8b67
CMN
1236 if ((error = prune_candidates(&candidates, remote)) < 0)
1237 goto cleanup;
5f473947 1238
59ff8b67
CMN
1239 /*
1240 * Remove those entries from the candidate list for which we
1241 * can find a remote reference in at least one refspec.
1242 */
1243 git_vector_foreach(&candidates, i, refname) {
1244 git_vector_foreach(&remote->active_refspecs, j, spec) {
1245 git_buf buf = GIT_BUF_INIT;
1246 size_t pos;
1247 char *src_name;
1248 git_remote_head key = {0};
1249
1250 if (!git_refspec_dst_matches(spec, refname))
5f473947
L
1251 continue;
1252
59ff8b67
CMN
1253 if ((error = git_refspec_rtransform(&buf, spec, refname)) < 0)
1254 goto cleanup;
5f473947 1255
59ff8b67
CMN
1256 key.name = (char *) git_buf_cstr(&buf);
1257 error = git_vector_search(&pos, &remote_refs, &key);
1258 git_buf_free(&buf);
5f473947 1259
59ff8b67
CMN
1260 if (error < 0 && error != GIT_ENOTFOUND)
1261 goto cleanup;
5f473947 1262
59ff8b67 1263 if (error == GIT_ENOTFOUND)
5f473947
L
1264 continue;
1265
59ff8b67
CMN
1266 /* if we did find a source, remove it from the candiates */
1267 if ((error = git_vector_set((void **) &src_name, &candidates, i, NULL)) < 0)
1268 goto cleanup;
1269
1270 git__free(src_name);
1271 break;
5f473947
L
1272 }
1273 }
1274
59ff8b67
CMN
1275 /*
1276 * For those candidates still left in the list, we need to
1277 * remove them. We do not remove symrefs, as those are for
1278 * stuff like origin/HEAD which will never match, but we do
1279 * not want to remove them.
1280 */
1281 git_vector_foreach(&candidates, i, refname) {
1282 git_reference *ref;
1283 git_oid id;
1284
1285 if (refname == NULL)
1286 continue;
1287
1288 error = git_reference_lookup(&ref, remote->repo, refname);
1289 /* as we want it gone, let's not consider this an error */
1290 if (error == GIT_ENOTFOUND)
1291 continue;
1292
1293 if (error < 0)
1294 goto cleanup;
1295
1296 if (git_reference_type(ref) == GIT_REF_SYMBOLIC) {
1297 git_reference_free(ref);
1298 continue;
1299 }
1300
1301 git_oid_cpy(&id, git_reference_target(ref));
1302 error = git_reference_delete(ref);
1303 git_reference_free(ref);
1304 if (error < 0)
1305 goto cleanup;
1306
8f0104ec
CMN
1307 if (callbacks && callbacks->update_tips)
1308 error = callbacks->update_tips(refname, &id, &zero_id, callbacks->payload);
59ff8b67
CMN
1309
1310 if (error < 0)
1311 goto cleanup;
1312 }
1313
5f473947 1314cleanup:
5f473947 1315 git_vector_free(&remote_refs);
59ff8b67 1316 git_vector_free_deep(&candidates);
5f473947
L
1317 return error;
1318}
1319
c3ab1e5a
BS
1320static int update_tips_for_spec(
1321 git_remote *remote,
8f0104ec 1322 const git_remote_callbacks *callbacks,
c3ab1e5a
BS
1323 git_refspec *spec,
1324 git_vector *refs,
c3ab1e5a 1325 const char *log_message)
441f57c2 1326{
a37ddf7e 1327 int error = 0, autotag;
517bda19 1328 unsigned int i = 0;
97769280 1329 git_buf refname = GIT_BUF_INIT;
f184836b 1330 git_oid old;
a37ddf7e 1331 git_odb *odb;
441f57c2
CMN
1332 git_remote_head *head;
1333 git_reference *ref;
a37ddf7e 1334 git_refspec tagspec;
4330ab26 1335 git_vector update_heads;
441f57c2 1336
4bef3565
VM
1337 assert(remote);
1338
acd17006 1339 if (git_repository_odb__weakptr(&odb, remote->repo) < 0)
a37ddf7e
CMN
1340 return -1;
1341
3230a44f 1342 if (git_refspec__parse(&tagspec, GIT_REFSPEC_TAGS, true) < 0)
a37ddf7e
CMN
1343 return -1;
1344
41fb1ca0 1345 /* Make a copy of the transport's refs */
4330ab26 1346 if (git_vector_init(&update_heads, 16, NULL) < 0)
41fb1ca0 1347 return -1;
585a2eb7 1348
4330ab26
CMN
1349 for (; i < refs->length; ++i) {
1350 head = git_vector_get(refs, i);
9063be1f 1351 autotag = 0;
517bda19 1352
a37ddf7e
CMN
1353 /* Ignore malformed ref names (which also saves us from tag^{} */
1354 if (!git_reference_is_valid_name(head->name))
1355 continue;
1356
e284c451
POL
1357 if (git_refspec_src_matches(&tagspec, head->name)) {
1358 if (remote->download_tags != GIT_REMOTE_DOWNLOAD_TAGS_NONE) {
3230a44f 1359
e284c451
POL
1360 if (remote->download_tags == GIT_REMOTE_DOWNLOAD_TAGS_AUTO)
1361 autotag = 1;
a37ddf7e 1362
e284c451
POL
1363 git_buf_clear(&refname);
1364 if (git_buf_puts(&refname, head->name) < 0)
1365 goto on_error;
1366 } else {
a37ddf7e 1367 continue;
e284c451
POL
1368 }
1369 } else if (git_refspec_src_matches(spec, head->name) && spec->dst) {
1370 if (git_refspec_transform(&refname, spec, head->name) < 0)
a37ddf7e
CMN
1371 goto on_error;
1372 } else {
1373 continue;
1374 }
1375
e284c451 1376 /* In autotag mode, only create tags for objects already in db */
a37ddf7e
CMN
1377 if (autotag && !git_odb_exists(odb, &head->oid))
1378 continue;
f184836b 1379
d908351a 1380 if (!autotag && git_vector_insert(&update_heads, head) < 0)
b0f6e45d
ET
1381 goto on_error;
1382
2508cc66 1383 error = git_reference_name_to_id(&old, remote->repo, refname.ptr);
904b67e6 1384 if (error < 0 && error != GIT_ENOTFOUND)
f184836b
CMN
1385 goto on_error;
1386
d908351a 1387 if (error == GIT_ENOTFOUND) {
f184836b
CMN
1388 memset(&old, 0, GIT_OID_RAWSZ);
1389
d908351a
L
1390 if (autotag && git_vector_insert(&update_heads, head) < 0)
1391 goto on_error;
1392 }
1393
b7f167da 1394 if (!git_oid__cmp(&old, &head->oid))
f184836b 1395 continue;
441f57c2 1396
a37ddf7e 1397 /* In autotag mode, don't overwrite any locally-existing tags */
c3ab1e5a 1398 error = git_reference_create(&ref, remote->repo, refname.ptr, &head->oid, !autotag,
659cf202 1399 log_message);
a37ddf7e 1400 if (error < 0 && error != GIT_EEXISTS)
944d250f 1401 goto on_error;
39157563
CMN
1402
1403 git_reference_free(ref);
f184836b 1404
8f0104ec
CMN
1405 if (callbacks && callbacks->update_tips != NULL) {
1406 if (callbacks->update_tips(refname.ptr, &old, &head->oid, callbacks->payload) < 0)
f184836b
CMN
1407 goto on_error;
1408 }
441f57c2
CMN
1409 }
1410
b0f6e45d 1411 if (git_remote_update_fetchhead(remote) &&
4330ab26 1412 (error = git_remote_write_fetchhead(remote, spec, &update_heads)) < 0)
b0f6e45d
ET
1413 goto on_error;
1414
b0f6e45d 1415 git_vector_free(&update_heads);
a37ddf7e 1416 git_refspec__free(&tagspec);
97769280 1417 git_buf_free(&refname);
f184836b
CMN
1418 return 0;
1419
1420on_error:
b0f6e45d 1421 git_vector_free(&update_heads);
a37ddf7e 1422 git_refspec__free(&tagspec);
f184836b
CMN
1423 git_buf_free(&refname);
1424 return -1;
97769280 1425
441f57c2
CMN
1426}
1427
c5837cad
CMN
1428/**
1429 * Iteration over the three vectors, with a pause whenever we find a match
1430 *
1431 * On each stop, we store the iteration stat in the inout i,j,k
1432 * parameters, and return the currently matching passive refspec as
1433 * well as the head which we matched.
1434 */
1435static int next_head(const git_remote *remote, git_vector *refs,
1436 git_refspec **out_spec, git_remote_head **out_head,
1437 size_t *out_i, size_t *out_j, size_t *out_k)
1438{
1439 const git_vector *active, *passive;
1440 git_remote_head *head;
1441 git_refspec *spec, *passive_spec;
1442 size_t i, j, k;
1443
1444 active = &remote->active_refspecs;
1445 passive = &remote->passive_refspecs;
1446
1447 i = *out_i;
1448 j = *out_j;
1449 k = *out_k;
1450
1451 for (; i < refs->length; i++) {
1452 head = git_vector_get(refs, i);
1453
1454 if (!git_reference_is_valid_name(head->name))
1455 continue;
1456
1457 for (; j < active->length; j++) {
1458 spec = git_vector_get(active, j);
1459
1460 if (!git_refspec_src_matches(spec, head->name))
1461 continue;
1462
1463 for (; k < passive->length; k++) {
1464 passive_spec = git_vector_get(passive, k);
1465
1466 if (!git_refspec_src_matches(passive_spec, head->name))
1467 continue;
1468
1469 *out_spec = passive_spec;
1470 *out_head = head;
1471 *out_i = i;
1472 *out_j = j;
1473 *out_k = k + 1;
1474 return 0;
1475
1476 }
1477 k = 0;
1478 }
1479 j = 0;
1480 }
1481
1482 return GIT_ITEROVER;
1483}
1484
659cf202 1485static int opportunistic_updates(const git_remote *remote, git_vector *refs, const char *msg)
c5837cad
CMN
1486{
1487 size_t i, j, k;
1488 git_refspec *spec;
1489 git_remote_head *head;
1490 git_reference *ref;
1491 git_buf refname = GIT_BUF_INIT;
1492 int error;
1493
1494 i = j = k = 0;
1495
1496 while ((error = next_head(remote, refs, &spec, &head, &i, &j, &k)) == 0) {
1497 /*
1498 * If we got here, there is a refspec which was used
1499 * for fetching which matches the source of one of the
1500 * passive refspecs, so we should update that
1501 * remote-tracking branch, but not add it to
1502 * FETCH_HEAD
1503 */
1504
1505 if ((error = git_refspec_transform(&refname, spec, head->name)) < 0)
1506 return error;
1507
659cf202 1508 error = git_reference_create(&ref, remote->repo, refname.ptr, &head->oid, true, msg);
c5837cad 1509 git_buf_free(&refname);
cdd71711 1510 git_reference_free(ref);
c5837cad
CMN
1511
1512 if (error < 0)
1513 return error;
1514 }
1515
1516 return 0;
1517}
1518
c3ab1e5a
BS
1519int git_remote_update_tips(
1520 git_remote *remote,
8f0104ec 1521 const git_remote_callbacks *callbacks,
c3ab1e5a 1522 const char *reflog_message)
4330ab26 1523{
505b5d0c 1524 git_refspec *spec, tagspec;
cdedef40 1525 git_vector refs = GIT_VECTOR_INIT;
505b5d0c 1526 int error;
4330ab26
CMN
1527 size_t i;
1528
fe794b2e
CMN
1529 /* push has its own logic hidden away in the push object */
1530 if (remote->push) {
8f0104ec 1531 return git_push_update_tips(remote->push, callbacks);
fe794b2e
CMN
1532 }
1533
505b5d0c
CMN
1534 if (git_refspec__parse(&tagspec, GIT_REFSPEC_TAGS, true) < 0)
1535 return -1;
1536
877cde76
CMN
1537
1538 if ((error = ls_to_vector(&refs, remote)) < 0)
505b5d0c
CMN
1539 goto out;
1540
1541 if (remote->download_tags == GIT_REMOTE_DOWNLOAD_TAGS_ALL) {
8f0104ec 1542 if ((error = update_tips_for_spec(remote, callbacks, &tagspec, &refs, reflog_message)) < 0)
e284c451 1543 goto out;
505b5d0c 1544 }
4330ab26 1545
af613ecd 1546 git_vector_foreach(&remote->active_refspecs, i, spec) {
4330ab26
CMN
1547 if (spec->push)
1548 continue;
1549
8f0104ec 1550 if ((error = update_tips_for_spec(remote, callbacks, spec, &refs, reflog_message)) < 0)
505b5d0c 1551 goto out;
4330ab26
CMN
1552 }
1553
c5837cad
CMN
1554 /* only try to do opportunisitic updates if the refpec lists differ */
1555 if (remote->passed_refspecs)
659cf202 1556 error = opportunistic_updates(remote, &refs, reflog_message);
c5837cad 1557
505b5d0c 1558out:
877cde76 1559 git_vector_free(&refs);
505b5d0c 1560 git_refspec__free(&tagspec);
505b5d0c 1561 return error;
4330ab26
CMN
1562}
1563
11f6ad5f 1564int git_remote_connected(const git_remote *remote)
6ac3b707 1565{
4bef3565 1566 assert(remote);
41fb1ca0
PK
1567
1568 if (!remote->transport || !remote->transport->is_connected)
1569 return 0;
1570
1571 /* Ask the transport if it's connected. */
613d5eb9 1572 return remote->transport->is_connected(remote->transport);
6ac3b707
CMN
1573}
1574
f0d2ddbb
CMN
1575void git_remote_stop(git_remote *remote)
1576{
613d5eb9
PK
1577 assert(remote);
1578
1579 if (remote->transport && remote->transport->cancel)
41fb1ca0 1580 remote->transport->cancel(remote->transport);
f0d2ddbb
CMN
1581}
1582
4cf01e9a
CMN
1583void git_remote_disconnect(git_remote *remote)
1584{
4bef3565
VM
1585 assert(remote);
1586
41fb1ca0
PK
1587 if (git_remote_connected(remote))
1588 remote->transport->close(remote->transport);
4cf01e9a
CMN
1589}
1590
9c82357b
CMN
1591void git_remote_free(git_remote *remote)
1592{
2aae2188
CMN
1593 if (remote == NULL)
1594 return;
1595
42ea35c0
MS
1596 if (remote->transport != NULL) {
1597 git_remote_disconnect(remote);
1598
1599 remote->transport->free(remote->transport);
1600 remote->transport = NULL;
1601 }
1602
1603 git_vector_free(&remote->refs);
1604
af613ecd 1605 free_refspecs(&remote->refspecs);
4330ab26
CMN
1606 git_vector_free(&remote->refspecs);
1607
af613ecd
CMN
1608 free_refspecs(&remote->active_refspecs);
1609 git_vector_free(&remote->active_refspecs);
1610
2cdd5c57
CMN
1611 free_refspecs(&remote->passive_refspecs);
1612 git_vector_free(&remote->passive_refspecs);
1613
fe794b2e 1614 git_push_free(remote->push);
3286c408 1615 git__free(remote->url);
3ed4b501 1616 git__free(remote->pushurl);
3286c408 1617 git__free(remote->name);
3286c408 1618 git__free(remote);
9c82357b 1619}
8171998f 1620
106c12f1 1621static int remote_list_cb(const git_config_entry *entry, void *payload)
8171998f 1622{
25e0b157 1623 git_vector *list = payload;
106c12f1
RB
1624 const char *name = entry->name + strlen("remote.");
1625 size_t namelen = strlen(name);
1626 char *remote_name;
8171998f 1627
106c12f1 1628 /* we know name matches "remote.<stuff>.(push)?url" */
8171998f 1629
106c12f1
RB
1630 if (!strcmp(&name[namelen - 4], ".url"))
1631 remote_name = git__strndup(name, namelen - 4); /* strip ".url" */
1632 else
1633 remote_name = git__strndup(name, namelen - 8); /* strip ".pushurl" */
25e0b157 1634 GITERR_CHECK_ALLOC(remote_name);
8171998f 1635
25e0b157 1636 return git_vector_insert(list, remote_name);
8171998f
CMN
1637}
1638
1639int git_remote_list(git_strarray *remotes_list, git_repository *repo)
1640{
8171998f 1641 int error;
96869a4e 1642 git_config *cfg;
25e0b157 1643 git_vector list = GIT_VECTOR_INIT;
8171998f 1644
96869a4e
RB
1645 if ((error = git_repository_config__weakptr(&cfg, repo)) < 0)
1646 return error;
8171998f 1647
25e0b157 1648 if ((error = git_vector_init(&list, 4, git__strcmp_cb)) < 0)
96869a4e 1649 return error;
8171998f 1650
106c12f1 1651 error = git_config_foreach_match(
25e0b157 1652 cfg, "^remote\\..*\\.(push)?url$", remote_list_cb, &list);
8171998f 1653
4376f7f6 1654 if (error < 0) {
9cfce273 1655 git_vector_free_deep(&list);
8171998f
CMN
1656 return error;
1657 }
1658
25e0b157 1659 git_vector_uniq(&list, git__free);
aec87f71 1660
25e0b157
RB
1661 remotes_list->strings =
1662 (char **)git_vector_detach(&remotes_list->count, NULL, &list);
8171998f 1663
4376f7f6 1664 return 0;
8171998f 1665}
a209a025 1666
67dad09b 1667const git_transfer_progress* git_remote_stats(git_remote *remote)
d57c47dc
BS
1668{
1669 assert(remote);
1670 return &remote->stats;
1671}
1672
11f6ad5f 1673git_remote_autotag_option_t git_remote_autotag(const git_remote *remote)
f70e466f
CMN
1674{
1675 return remote->download_tags;
1676}
1677
f4a62c30 1678void git_remote_set_autotag(git_remote *remote, git_remote_autotag_option_t value)
f70e466f
CMN
1679{
1680 remote->download_tags = value;
1681}
fcccf304 1682
5f473947
L
1683int git_remote_prune_refs(const git_remote *remote)
1684{
1685 return remote->prune_refs;
1686}
1687
fcccf304 1688static int rename_remote_config_section(
1689 git_repository *repo,
1690 const char *old_name,
1691 const char *new_name)
1692{
1693 git_buf old_section_name = GIT_BUF_INIT,
1694 new_section_name = GIT_BUF_INIT;
1695 int error = -1;
1696
1697 if (git_buf_printf(&old_section_name, "remote.%s", old_name) < 0)
1698 goto cleanup;
1699
40e48ea4 1700 if (new_name &&
1701 (git_buf_printf(&new_section_name, "remote.%s", new_name) < 0))
1702 goto cleanup;
fcccf304 1703
1704 error = git_config_rename_section(
1705 repo,
1706 git_buf_cstr(&old_section_name),
40e48ea4 1707 new_name ? git_buf_cstr(&new_section_name) : NULL);
fcccf304 1708
1709cleanup:
1710 git_buf_free(&old_section_name);
1711 git_buf_free(&new_section_name);
1712
1713 return error;
1714}
1715
96869a4e 1716struct update_data {
fcccf304 1717 git_config *config;
1718 const char *old_remote_name;
1719 const char *new_remote_name;
1720};
1721
1722static int update_config_entries_cb(
1723 const git_config_entry *entry,
1724 void *payload)
1725{
1726 struct update_data *data = (struct update_data *)payload;
1727
1728 if (strcmp(entry->value, data->old_remote_name))
1729 return 0;
1730
25e0b157
RB
1731 return git_config_set_string(
1732 data->config, entry->name, data->new_remote_name);
fcccf304 1733}
1734
1735static int update_branch_remote_config_entry(
1736 git_repository *repo,
1737 const char *old_name,
1738 const char *new_name)
1739{
96869a4e
RB
1740 int error;
1741 struct update_data data = { NULL };
fcccf304 1742
96869a4e
RB
1743 if ((error = git_repository_config__weakptr(&data.config, repo)) < 0)
1744 return error;
fcccf304 1745
fcccf304 1746 data.old_remote_name = old_name;
1747 data.new_remote_name = new_name;
1748
25e0b157 1749 return git_config_foreach_match(
96869a4e 1750 data.config, "branch\\..+\\.remote", update_config_entries_cb, &data);
fcccf304 1751}
1752
fcccf304 1753static int rename_one_remote_reference(
d1544564 1754 git_reference *reference_in,
fcccf304 1755 const char *old_remote_name,
1756 const char *new_remote_name)
1757{
96869a4e 1758 int error;
d1544564
CMN
1759 git_reference *ref = NULL, *dummy = NULL;
1760 git_buf namespace = GIT_BUF_INIT, old_namespace = GIT_BUF_INIT;
fcccf304 1761 git_buf new_name = GIT_BUF_INIT;
ccf6ce5c 1762 git_buf log_message = GIT_BUF_INIT;
d1544564
CMN
1763 size_t pfx_len;
1764 const char *target;
fcccf304 1765
d1544564
CMN
1766 if ((error = git_buf_printf(&namespace, GIT_REFS_REMOTES_DIR "%s/", new_remote_name)) < 0)
1767 return error;
1768
1769 pfx_len = strlen(GIT_REFS_REMOTES_DIR) + strlen(old_remote_name) + 1;
1770 git_buf_puts(&new_name, namespace.ptr);
1771 if ((error = git_buf_puts(&new_name, git_reference_name(reference_in) + pfx_len)) < 0)
ccf6ce5c 1772 goto cleanup;
fcccf304 1773
ccf6ce5c
BS
1774 if ((error = git_buf_printf(&log_message,
1775 "renamed remote %s to %s",
1776 old_remote_name, new_remote_name)) < 0)
1777 goto cleanup;
fcccf304 1778
d1544564 1779 if ((error = git_reference_rename(&ref, reference_in, git_buf_cstr(&new_name), 1,
659cf202 1780 git_buf_cstr(&log_message))) < 0)
d1544564
CMN
1781 goto cleanup;
1782
1783 if (git_reference_type(ref) != GIT_REF_SYMBOLIC)
1784 goto cleanup;
1785
1786 /* Handle refs like origin/HEAD -> origin/master */
1787 target = git_reference_symbolic_target(ref);
1788 if ((error = git_buf_printf(&old_namespace, GIT_REFS_REMOTES_DIR "%s/", old_remote_name)) < 0)
1789 goto cleanup;
1790
1791 if (git__prefixcmp(target, old_namespace.ptr))
1792 goto cleanup;
1793
1794 git_buf_clear(&new_name);
1795 git_buf_puts(&new_name, namespace.ptr);
1796 if ((error = git_buf_puts(&new_name, target + pfx_len)) < 0)
1797 goto cleanup;
1798
1799 error = git_reference_symbolic_set_target(&dummy, ref, git_buf_cstr(&new_name),
659cf202 1800 git_buf_cstr(&log_message));
d1544564
CMN
1801
1802 git_reference_free(dummy);
ccf6ce5c
BS
1803
1804cleanup:
d1544564
CMN
1805 git_reference_free(reference_in);
1806 git_reference_free(ref);
1807 git_buf_free(&namespace);
1808 git_buf_free(&old_namespace);
fcccf304 1809 git_buf_free(&new_name);
ccf6ce5c 1810 git_buf_free(&log_message);
fcccf304 1811 return error;
1812}
1813
1814static int rename_remote_references(
1815 git_repository *repo,
1816 const char *old_name,
1817 const char *new_name)
1818{
96869a4e 1819 int error;
a52ab4b8 1820 git_buf buf = GIT_BUF_INIT;
56960b83 1821 git_reference *ref;
9bd89d96 1822 git_reference_iterator *iter;
fcccf304 1823
a52ab4b8 1824 if ((error = git_buf_printf(&buf, GIT_REFS_REMOTES_DIR "%s/*", old_name)) < 0)
96869a4e 1825 return error;
fcccf304 1826
a52ab4b8
CMN
1827 error = git_reference_iterator_glob_new(&iter, repo, git_buf_cstr(&buf));
1828 git_buf_free(&buf);
9bd89d96 1829
a52ab4b8
CMN
1830 if (error < 0)
1831 return error;
1832
1833 while ((error = git_reference_next(&ref, iter)) == 0) {
96869a4e
RB
1834 if ((error = rename_one_remote_reference(ref, old_name, new_name)) < 0)
1835 break;
9bd89d96
CMN
1836 }
1837
1838 git_reference_iterator_free(iter);
fcccf304 1839
96869a4e 1840 return (error == GIT_ITEROVER) ? 0 : error;
fcccf304 1841}
1842
72bca13e 1843static int rename_fetch_refspecs(git_vector *problems, git_remote *remote, const char *new_name)
fcccf304 1844{
1845 git_config *config;
4330ab26 1846 git_buf base = GIT_BUF_INIT, var = GIT_BUF_INIT, val = GIT_BUF_INIT;
1be680c4 1847 const git_refspec *spec;
4330ab26 1848 size_t i;
25e0b157 1849 int error = 0;
fcccf304 1850
dab89f9b 1851 if ((error = git_repository_config__weakptr(&config, remote->repo)) < 0)
25e0b157
RB
1852 return error;
1853
72bca13e
CMN
1854 if ((error = git_vector_init(problems, 1, NULL)) < 0)
1855 return error;
1856
25e0b157
RB
1857 if ((error = git_buf_printf(
1858 &base, "+refs/heads/*:refs/remotes/%s/*", remote->name)) < 0)
1859 return error;
dab89f9b 1860
1be680c4 1861 git_vector_foreach(&remote->refspecs, i, spec) {
4330ab26
CMN
1862 if (spec->push)
1863 continue;
fcccf304 1864
dab89f9b 1865 /* Does the dst part of the refspec follow the expected format? */
5a49ff9f 1866 if (strcmp(git_buf_cstr(&base), spec->string)) {
72bca13e 1867 char *dup;
fcccf304 1868
72bca13e
CMN
1869 dup = git__strdup(spec->string);
1870 GITERR_CHECK_ALLOC(dup);
1871
1872 if ((error = git_vector_insert(problems, dup)) < 0)
25e0b157 1873 break;
c7b3e1b3 1874
4330ab26
CMN
1875 continue;
1876 }
fcccf304 1877
4330ab26 1878 /* If we do want to move it to the new section */
fcccf304 1879
dab89f9b
RB
1880 git_buf_clear(&val);
1881 git_buf_clear(&var);
fcccf304 1882
dab89f9b
RB
1883 if (git_buf_printf(
1884 &val, "+refs/heads/*:refs/remotes/%s/*", new_name) < 0 ||
1885 git_buf_printf(&var, "remote.%s.fetch", new_name) < 0)
1886 {
1887 error = -1;
25e0b157 1888 break;
dab89f9b 1889 }
fcccf304 1890
dab89f9b
RB
1891 if ((error = git_config_set_string(
1892 config, git_buf_cstr(&var), git_buf_cstr(&val))) < 0)
25e0b157 1893 break;
4330ab26 1894 }
fcccf304 1895
4330ab26
CMN
1896 git_buf_free(&base);
1897 git_buf_free(&var);
1898 git_buf_free(&val);
72bca13e
CMN
1899
1900 if (error < 0) {
1901 char *str;
1902 git_vector_foreach(problems, i, str)
1903 git__free(str);
1904
1905 git_vector_free(problems);
1906 }
1907
fcccf304 1908 return error;
1909}
1910
46c8f7f8 1911int git_remote_rename(git_strarray *out, git_repository *repo, const char *name, const char *new_name)
fcccf304 1912{
1913 int error;
46c8f7f8 1914 git_vector problem_refspecs = GIT_VECTOR_INIT;
64bcf567 1915 git_remote *remote = NULL;
fcccf304 1916
46c8f7f8 1917 assert(out && repo && name && new_name);
fcccf304 1918
209425ce 1919 if ((error = git_remote_lookup(&remote, repo, name)) < 0)
cce27d82 1920 return error;
79000951 1921
fcccf304 1922 if ((error = ensure_remote_name_is_valid(new_name)) < 0)
46c8f7f8 1923 goto cleanup;
fcccf304 1924
46c8f7f8
CMN
1925 if ((error = ensure_remote_doesnot_exist(repo, new_name)) < 0)
1926 goto cleanup;
fcccf304 1927
46c8f7f8
CMN
1928 if ((error = rename_remote_config_section(repo, name, new_name)) < 0)
1929 goto cleanup;
fcccf304 1930
46c8f7f8
CMN
1931 if ((error = update_branch_remote_config_entry(repo, name, new_name)) < 0)
1932 goto cleanup;
fcccf304 1933
46c8f7f8
CMN
1934 if ((error = rename_remote_references(repo, name, new_name)) < 0)
1935 goto cleanup;
fcccf304 1936
72bca13e 1937 if ((error = rename_fetch_refspecs(&problem_refspecs, remote, new_name)) < 0)
46c8f7f8 1938 goto cleanup;
fcccf304 1939
72bca13e
CMN
1940 out->count = problem_refspecs.length;
1941 out->strings = (char **) problem_refspecs.contents;
1942
46c8f7f8
CMN
1943cleanup:
1944 if (error < 0)
1945 git_vector_free(&problem_refspecs);
fcccf304 1946
46c8f7f8
CMN
1947 git_remote_free(remote);
1948 return error;
fcccf304 1949}
b0f6e45d
ET
1950
1951int git_remote_update_fetchhead(git_remote *remote)
1952{
8f2a3d62 1953 return (remote->update_fetchhead != 0);
b0f6e45d
ET
1954}
1955
1956void git_remote_set_update_fetchhead(git_remote *remote, int value)
1957{
8f2a3d62 1958 remote->update_fetchhead = (value != 0);
b0f6e45d 1959}
2bca5b67 1960
1961int git_remote_is_valid_name(
1962 const char *remote_name)
1963{
1964 git_buf buf = GIT_BUF_INIT;
1965 git_refspec refspec;
1966 int error = -1;
1967
1968 if (!remote_name || *remote_name == '\0')
1969 return 0;
1970
1971 git_buf_printf(&buf, "refs/heads/test:refs/remotes/%s/test", remote_name);
1972 error = git_refspec__parse(&refspec, git_buf_cstr(&buf), true);
1973
1974 git_buf_free(&buf);
1975 git_refspec__free(&refspec);
1976
1977 giterr_clear();
1978 return error == 0;
1979}
4330ab26
CMN
1980
1981git_refspec *git_remote__matching_refspec(git_remote *remote, const char *refname)
1982{
1983 git_refspec *spec;
1984 size_t i;
1985
af613ecd 1986 git_vector_foreach(&remote->active_refspecs, i, spec) {
4330ab26
CMN
1987 if (spec->push)
1988 continue;
1989
1990 if (git_refspec_src_matches(spec, refname))
1991 return spec;
1992 }
1993
1994 return NULL;
1995}
1996
1997git_refspec *git_remote__matching_dst_refspec(git_remote *remote, const char *refname)
1998{
1999 git_refspec *spec;
2000 size_t i;
2001
af613ecd 2002 git_vector_foreach(&remote->active_refspecs, i, spec) {
4330ab26
CMN
2003 if (spec->push)
2004 continue;
2005
2006 if (git_refspec_dst_matches(spec, refname))
2007 return spec;
2008 }
2009
2010 return NULL;
2011}
2012
2013void git_remote_clear_refspecs(git_remote *remote)
2014{
2015 git_refspec *spec;
4330ab26
CMN
2016 size_t i;
2017
2018 git_vector_foreach(&remote->refspecs, i, spec) {
2019 git_refspec__free(spec);
1be680c4 2020 git__free(spec);
4330ab26
CMN
2021 }
2022 git_vector_clear(&remote->refspecs);
4330ab26
CMN
2023}
2024
bc6374ea 2025int git_remote_add_fetch(git_remote *remote, const char *refspec)
4330ab26 2026{
c300d84a 2027 return add_refspec(remote, refspec, true);
4330ab26
CMN
2028}
2029
bc6374ea 2030int git_remote_add_push(git_remote *remote, const char *refspec)
4330ab26 2031{
c300d84a 2032 return add_refspec(remote, refspec, false);
266af6d8
CMN
2033}
2034
2035static int set_refspecs(git_remote *remote, git_strarray *array, int push)
2036{
2037 git_vector *vec = &remote->refspecs;
2038 git_refspec *spec;
2039 size_t i;
2040
2041 /* Start by removing any refspecs of the same type */
2042 for (i = 0; i < vec->length; i++) {
2043 spec = git_vector_get(vec, i);
2044 if (spec->push != push)
2045 continue;
2046
2047 git_refspec__free(spec);
2048 git__free(spec);
2049 git_vector_remove(vec, i);
2050 i--;
2051 }
2052
2053 /* And now we add the new ones */
2054
2055 for (i = 0; i < array->count; i++) {
2056 if (add_refspec(remote, array->strings[i], !push) < 0)
2057 return -1;
2058 }
2059
c300d84a 2060 return 0;
266af6d8
CMN
2061}
2062
2063int git_remote_set_fetch_refspecs(git_remote *remote, git_strarray *array)
2064{
2065 return set_refspecs(remote, array, false);
2066}
2067
2068int git_remote_set_push_refspecs(git_remote *remote, git_strarray *array)
2069{
2070 return set_refspecs(remote, array, true);
4330ab26 2071}
bc6374ea 2072
11f6ad5f 2073static int copy_refspecs(git_strarray *array, const git_remote *remote, unsigned int push)
bc6374ea
CMN
2074{
2075 size_t i;
2076 git_vector refspecs;
2077 git_refspec *spec;
2078 char *dup;
2079
2080 if (git_vector_init(&refspecs, remote->refspecs.length, NULL) < 0)
2081 return -1;
2082
2083 git_vector_foreach(&remote->refspecs, i, spec) {
2084 if (spec->push != push)
2085 continue;
2086
1be680c4 2087 if ((dup = git__strdup(spec->string)) == NULL)
bc6374ea 2088 goto on_error;
bc6374ea
CMN
2089
2090 if (git_vector_insert(&refspecs, dup) < 0) {
2091 git__free(dup);
2092 goto on_error;
2093 }
2094 }
2095
2096 array->strings = (char **)refspecs.contents;
2097 array->count = refspecs.length;
2098
2099 return 0;
2100
2101on_error:
9cfce273 2102 git_vector_free_deep(&refspecs);
bc6374ea
CMN
2103
2104 return -1;
2105}
2106
11f6ad5f 2107int git_remote_get_fetch_refspecs(git_strarray *array, const git_remote *remote)
bc6374ea
CMN
2108{
2109 return copy_refspecs(array, remote, false);
2110}
2111
11f6ad5f 2112int git_remote_get_push_refspecs(git_strarray *array, const git_remote *remote)
bc6374ea
CMN
2113{
2114 return copy_refspecs(array, remote, true);
2115}
1ffd0806 2116
11f6ad5f 2117size_t git_remote_refspec_count(const git_remote *remote)
1ffd0806
CMN
2118{
2119 return remote->refspecs.length;
2120}
2121
11f6ad5f 2122const git_refspec *git_remote_get_refspec(const git_remote *remote, size_t n)
1ffd0806
CMN
2123{
2124 return git_vector_get(&remote->refspecs, n);
2125}
b9f81997 2126
bc91347b 2127int git_remote_init_callbacks(git_remote_callbacks *opts, unsigned int version)
b9f81997 2128{
bc91347b
RB
2129 GIT_INIT_STRUCTURE_FROM_TEMPLATE(
2130 opts, version, git_remote_callbacks, GIT_REMOTE_CALLBACKS_INIT);
2131 return 0;
b9f81997 2132}
40e48ea4 2133
5cdac19c
CMN
2134/* asserts a branch.<foo>.remote format */
2135static const char *name_offset(size_t *len_out, const char *name)
40e48ea4 2136{
5cdac19c
CMN
2137 size_t prefix_len;
2138 const char *dot;
40e48ea4 2139
5cdac19c
CMN
2140 prefix_len = strlen("remote.");
2141 dot = strchr(name + prefix_len, '.');
40e48ea4 2142
5cdac19c 2143 assert(dot);
40e48ea4 2144
5cdac19c
CMN
2145 *len_out = dot - name - prefix_len;
2146 return name + prefix_len;
40e48ea4 2147}
2148
2149static int remove_branch_config_related_entries(
2150 git_repository *repo,
2151 const char *remote_name)
2152{
2153 int error;
2154 git_config *config;
5cdac19c
CMN
2155 git_config_entry *entry;
2156 git_config_iterator *iter;
2157 git_buf buf = GIT_BUF_INIT;
40e48ea4 2158
2159 if ((error = git_repository_config__weakptr(&config, repo)) < 0)
2160 return error;
2161
5cdac19c 2162 if ((error = git_config_iterator_glob_new(&iter, config, "branch\\..+\\.remote")) < 0)
40e48ea4 2163 return error;
2164
5cdac19c
CMN
2165 /* find any branches with us as upstream and remove that config */
2166 while ((error = git_config_next(&entry, iter)) == 0) {
2167 const char *branch;
2168 size_t branch_len;
40e48ea4 2169
5cdac19c
CMN
2170 if (strcmp(remote_name, entry->value))
2171 continue;
40e48ea4 2172
5cdac19c 2173 branch = name_offset(&branch_len, entry->name);
40e48ea4 2174
5cdac19c
CMN
2175 git_buf_clear(&buf);
2176 if (git_buf_printf(&buf, "branch.%.*s.merge", (int)branch_len, branch) < 0)
2177 break;
2178
2179 if ((error = git_config_delete_entry(config, git_buf_cstr(&buf))) < 0)
2180 break;
2181
2182 git_buf_clear(&buf);
2183 if (git_buf_printf(&buf, "branch.%.*s.remote", (int)branch_len, branch) < 0)
2184 break;
2185
2186 if ((error = git_config_delete_entry(config, git_buf_cstr(&buf))) < 0)
2187 break;
40e48ea4 2188 }
2189
5cdac19c
CMN
2190 if (error == GIT_ITEROVER)
2191 error = 0;
2192
2193 git_buf_free(&buf);
2194 git_config_iterator_free(iter);
40e48ea4 2195 return error;
2196}
2197
8a9419aa 2198static int remove_refs(git_repository *repo, const git_refspec *spec)
ec8a949a 2199{
8a9419aa
CMN
2200 git_reference_iterator *iter = NULL;
2201 git_vector refs;
ec8a949a 2202 const char *name;
8a9419aa 2203 char *dup;
ec8a949a 2204 int error;
8a9419aa 2205 size_t i;
ec8a949a 2206
8a9419aa 2207 if ((error = git_vector_init(&refs, 8, NULL)) < 0)
ec8a949a
CMN
2208 return error;
2209
8a9419aa
CMN
2210 if ((error = git_reference_iterator_new(&iter, repo)) < 0)
2211 goto cleanup;
2212
ec8a949a 2213 while ((error = git_reference_next_name(&name, iter)) == 0) {
8a9419aa
CMN
2214 if (!git_refspec_dst_matches(spec, name))
2215 continue;
2216
2217 dup = git__strdup(name);
2218 if (!dup) {
2219 error = -1;
2220 goto cleanup;
2221 }
ec8a949a 2222
8a9419aa
CMN
2223 if ((error = git_vector_insert(&refs, dup)) < 0)
2224 goto cleanup;
2225 }
ec8a949a
CMN
2226 if (error == GIT_ITEROVER)
2227 error = 0;
8a9419aa
CMN
2228 if (error < 0)
2229 goto cleanup;
2230
2231 git_vector_foreach(&refs, i, name) {
2232 if ((error = git_reference_remove(repo, name)) < 0)
2233 break;
2234 }
ec8a949a 2235
8a9419aa
CMN
2236cleanup:
2237 git_reference_iterator_free(iter);
2238 git_vector_foreach(&refs, i, dup) {
2239 git__free(dup);
2240 }
2241 git_vector_free(&refs);
ec8a949a
CMN
2242 return error;
2243}
2244
2245static int remove_remote_tracking(git_repository *repo, const char *remote_name)
2246{
2247 git_remote *remote;
2248 int error;
2249 size_t i, count;
2250
2251 /* we want to use what's on the config, regardless of changes to the instance in memory */
209425ce 2252 if ((error = git_remote_lookup(&remote, repo, remote_name)) < 0)
ec8a949a
CMN
2253 return error;
2254
2255 count = git_remote_refspec_count(remote);
2256 for (i = 0; i < count; i++) {
2257 const git_refspec *refspec = git_remote_get_refspec(remote, i);
2258
2259 /* shouldn't ever actually happen */
2260 if (refspec == NULL)
2261 continue;
2262
8a9419aa 2263 if ((error = remove_refs(repo, refspec)) < 0)
ec8a949a
CMN
2264 break;
2265 }
2266
2267 git_remote_free(remote);
2268 return error;
2269}
2270
262eec23 2271int git_remote_delete(git_repository *repo, const char *name)
40e48ea4 2272{
2273 int error;
40e48ea4 2274
262eec23 2275 assert(repo && name);
ec8a949a 2276
262eec23
CMN
2277 if ((error = remove_branch_config_related_entries(repo, name)) < 0 ||
2278 (error = remove_remote_tracking(repo, name)) < 0 ||
2279 (error = rename_remote_config_section(repo, name, NULL)) < 0)
ec8a949a
CMN
2280 return error;
2281
40e48ea4 2282 return 0;
2283}
d22db24f
CMN
2284
2285int git_remote_default_branch(git_buf *out, git_remote *remote)
2286{
2287 const git_remote_head **heads;
2288 const git_remote_head *guess = NULL;
2289 const git_oid *head_id;
2290 size_t heads_len, i;
2291 int error;
2292
dc8adda4
JG
2293 assert(out);
2294
d22db24f
CMN
2295 if ((error = git_remote_ls(&heads, &heads_len, remote)) < 0)
2296 return error;
2297
2298 if (heads_len == 0)
2299 return GIT_ENOTFOUND;
2300
0cdaa376
CMN
2301 if (strcmp(heads[0]->name, GIT_HEAD_FILE))
2302 return GIT_ENOTFOUND;
2303
d22db24f
CMN
2304 git_buf_sanitize(out);
2305 /* the first one must be HEAD so if that has the symref info, we're done */
2306 if (heads[0]->symref_target)
2307 return git_buf_puts(out, heads[0]->symref_target);
2308
2309 /*
2310 * If there's no symref information, we have to look over them
2311 * and guess. We return the first match unless the master
2312 * branch is a candidate. Then we return the master branch.
2313 */
2314 head_id = &heads[0]->oid;
2315
2316 for (i = 1; i < heads_len; i++) {
2317 if (git_oid_cmp(head_id, &heads[i]->oid))
2318 continue;
2319
38952604
CMN
2320 if (git__prefixcmp(heads[i]->name, GIT_REFS_HEADS_DIR))
2321 continue;
2322
d22db24f
CMN
2323 if (!guess) {
2324 guess = heads[i];
2325 continue;
2326 }
2327
2328 if (!git__strcmp(GIT_REFS_HEADS_MASTER_FILE, heads[i]->name)) {
2329 guess = heads[i];
2330 break;
2331 }
2332 }
2333
2334 if (!guess)
2335 return GIT_ENOTFOUND;
2336
2337 return git_buf_puts(out, guess->name);
2338}
3149547b 2339
fe794b2e 2340int git_remote_upload(git_remote *remote, const git_strarray *refspecs, const git_push_options *opts)
3149547b 2341{
3149547b 2342 size_t i;
fe794b2e
CMN
2343 int error;
2344 git_push *push;
64e3e6d4 2345 git_refspec *spec;
8f0104ec 2346 const git_remote_callbacks *cbs = NULL;
3149547b 2347
fe794b2e 2348 assert(remote);
3149547b 2349
8f0104ec
CMN
2350 if (opts)
2351 cbs = &opts->callbacks;
2352
fe794b2e 2353 if (!git_remote_connected(remote) &&
8f0104ec 2354 (error = git_remote_connect(remote, GIT_DIRECTION_PUSH, cbs)) < 0)
fe794b2e
CMN
2355 goto cleanup;
2356
1034f1b5 2357 free_refspecs(&remote->active_refspecs);
69f0032b 2358 if ((error = dwim_refspecs(&remote->active_refspecs, &remote->refspecs, &remote->refs)) < 0)
1034f1b5
POL
2359 goto cleanup;
2360
fe794b2e
CMN
2361 if (remote->push) {
2362 git_push_free(remote->push);
2363 remote->push = NULL;
2364 }
2365
2366 if ((error = git_push_new(&remote->push, remote)) < 0)
3149547b
CMN
2367 return error;
2368
fe794b2e 2369 push = remote->push;
3149547b
CMN
2370
2371 if (opts && (error = git_push_set_options(push, opts)) < 0)
2372 goto cleanup;
2373
64e3e6d4
CMN
2374 if (refspecs && refspecs->count > 0) {
2375 for (i = 0; i < refspecs->count; i++) {
2376 if ((error = git_push_add_refspec(push, refspecs->strings[i])) < 0)
2377 goto cleanup;
2378 }
2379 } else {
2380 git_vector_foreach(&remote->refspecs, i, spec) {
2381 if (!spec->push)
2382 continue;
2383 if ((error = git_push_add_refspec(push, spec->string)) < 0)
2384 goto cleanup;
2385 }
3149547b
CMN
2386 }
2387
8f0104ec 2388 if ((error = git_push_finish(push, cbs)) < 0)
3149547b
CMN
2389 goto cleanup;
2390
8f0104ec 2391 if (cbs && cbs->push_update_reference &&
52ee0e8e 2392 (error = git_push_status_foreach(push, cbs->push_update_reference, cbs->payload)) < 0)
3149547b
CMN
2393 goto cleanup;
2394
3149547b 2395cleanup:
fe794b2e
CMN
2396 return error;
2397}
2398
412a3808 2399int git_remote_push(git_remote *remote, const git_strarray *refspecs, const git_push_options *opts)
fe794b2e
CMN
2400{
2401 int error;
8f0104ec
CMN
2402 const git_remote_callbacks *cbs = NULL;
2403
2404 if (opts) {
2405 GITERR_CHECK_VERSION(&opts->callbacks, GIT_REMOTE_CALLBACKS_VERSION, "git_remote_callbacks");
2406 cbs = &opts->callbacks;
2407 }
fe794b2e
CMN
2408
2409 assert(remote && refspecs);
2410
8f0104ec 2411 if ((error = git_remote_connect(remote, GIT_DIRECTION_PUSH, cbs)) < 0)
fe794b2e
CMN
2412 return error;
2413
2414 if ((error = git_remote_upload(remote, refspecs, opts)) < 0)
2415 return error;
2416
8f0104ec 2417 error = git_remote_update_tips(remote, cbs, NULL);
fe794b2e 2418
3149547b 2419 git_remote_disconnect(remote);
3149547b
CMN
2420 return error;
2421}