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