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