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