]> git.proxmox.com Git - libgit2.git/blame - src/remote.c
Add network transfer callbacks on Windows
[libgit2.git] / src / remote.c
CommitLineData
9c82357b 1/*
5e0de328 2 * Copyright (C) 2009-2012 the libgit2 contributors
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"
9c82357b
CMN
11
12#include "config.h"
13#include "repository.h"
14#include "remote.h"
e1d88030 15#include "fetch.h"
441f57c2 16#include "refs.h"
ad4b5beb 17#include "pkt.h"
9c82357b 18
8171998f
CMN
19#include <regex.h>
20
eb0bd77a 21static int parse_remote_refspec(git_config *cfg, git_refspec *refspec, const char *var, bool is_fetch)
9c82357b 22{
9c82357b 23 int error;
4376f7f6 24 const char *val;
9c82357b 25
29e948de 26 if ((error = git_config_get_string(&val, cfg, var)) < 0)
9c82357b
CMN
27 return error;
28
eb0bd77a 29 return git_refspec__parse(refspec, val, is_fetch);
9c82357b
CMN
30}
31
24f2f94e
CMN
32static int download_tags_value(git_remote *remote, git_config *cfg)
33{
34 const char *val;
35 git_buf buf = GIT_BUF_INIT;
36 int error;
37
38 if (remote->download_tags != GIT_REMOTE_DOWNLOAD_TAGS_UNSET)
39 return 0;
40
41 /* This is the default, let's see if we need to change it */
42 remote->download_tags = GIT_REMOTE_DOWNLOAD_TAGS_AUTO;
43 if (git_buf_printf(&buf, "remote.%s.tagopt", remote->name) < 0)
44 return -1;
45
46 error = git_config_get_string(&val, cfg, git_buf_cstr(&buf));
47 git_buf_free(&buf);
48 if (!error && !strcmp(val, "--no-tags"))
49 remote->download_tags = GIT_REMOTE_DOWNLOAD_TAGS_NONE;
3230a44f
CMN
50 else if (!error && !strcmp(val, "--tags"))
51 remote->download_tags = GIT_REMOTE_DOWNLOAD_TAGS_ALL;
24f2f94e
CMN
52
53 if (error == GIT_ENOTFOUND)
54 error = 0;
55
56 return error;
57}
58
baaa8a44 59int git_remote_new(git_remote **out, git_repository *repo, const char *name, const char *url, const char *fetch)
778e1c73
CMN
60{
61 git_remote *remote;
62
4bef3565
VM
63 /* name is optional */
64 assert(out && repo && url);
617bfdf4 65
778e1c73 66 remote = git__malloc(sizeof(git_remote));
4376f7f6 67 GITERR_CHECK_ALLOC(remote);
778e1c73
CMN
68
69 memset(remote, 0x0, sizeof(git_remote));
70 remote->repo = repo;
250b95b2 71 remote->check_cert = 1;
617bfdf4 72
4376f7f6
CMN
73 if (git_vector_init(&remote->refs, 32, NULL) < 0)
74 return -1;
d88d4311 75
778e1c73 76 remote->url = git__strdup(url);
4376f7f6 77 GITERR_CHECK_ALLOC(remote->url);
778e1c73 78
617bfdf4
CMN
79 if (name != NULL) {
80 remote->name = git__strdup(name);
4376f7f6 81 GITERR_CHECK_ALLOC(remote->name);
617bfdf4
CMN
82 }
83
baaa8a44 84 if (fetch != NULL) {
eb0bd77a 85 if (git_refspec__parse(&remote->fetch, fetch, true) < 0)
baaa8a44
CMN
86 goto on_error;
87 }
88
c648d4a8
CMN
89 /* A remote without a name doesn't download tags */
90 if (!name) {
91 remote->download_tags = GIT_REMOTE_DOWNLOAD_TAGS_NONE;
92 }
93
778e1c73 94 *out = remote;
4376f7f6 95 return 0;
baaa8a44
CMN
96
97on_error:
98 git_remote_free(remote);
99 return -1;
778e1c73
CMN
100}
101
9462c471 102int git_remote_load(git_remote **out, git_repository *repo, const char *name)
9c82357b
CMN
103{
104 git_remote *remote;
f0f3a18a 105 git_buf buf = GIT_BUF_INIT;
9c82357b 106 const char *val;
4376f7f6 107 int error = 0;
9462c471 108 git_config *config;
9c82357b 109
9462c471
VM
110 assert(out && repo && name);
111
4376f7f6
CMN
112 if (git_repository_config__weakptr(&config, repo) < 0)
113 return -1;
4bef3565 114
9c82357b 115 remote = git__malloc(sizeof(git_remote));
4376f7f6 116 GITERR_CHECK_ALLOC(remote);
9c82357b
CMN
117
118 memset(remote, 0x0, sizeof(git_remote));
250b95b2 119 remote->check_cert = 1;
9c82357b 120 remote->name = git__strdup(name);
4376f7f6 121 GITERR_CHECK_ALLOC(remote->name);
9c82357b 122
2fb9d6de 123 if (git_vector_init(&remote->refs, 32, NULL) < 0) {
124 error = -1;
125 goto cleanup;
126 }
d88d4311 127
2fb9d6de 128 if (git_buf_printf(&buf, "remote.%s.url", name) < 0) {
129 error = -1;
130 goto cleanup;
131 }
9c82357b 132
29e948de 133 if ((error = git_config_get_string(&val, config, git_buf_cstr(&buf))) < 0)
9c82357b 134 goto cleanup;
9c82357b 135
9462c471 136 remote->repo = repo;
9c82357b 137 remote->url = git__strdup(val);
4376f7f6 138 GITERR_CHECK_ALLOC(remote->url);
9c82357b 139
3ed4b501
SC
140 git_buf_clear(&buf);
141 if (git_buf_printf(&buf, "remote.%s.pushurl", name) < 0) {
142 error = -1;
143 goto cleanup;
144 }
145
146 error = git_config_get_string(&val, config, git_buf_cstr(&buf));
147 if (error == GIT_ENOTFOUND)
148 error = 0;
149
150 if (error < 0) {
151 error = -1;
152 goto cleanup;
153 }
154
155 if (val) {
156 remote->pushurl = git__strdup(val);
157 GITERR_CHECK_ALLOC(remote->pushurl);
158 }
159
f0f3a18a 160 git_buf_clear(&buf);
2fb9d6de 161 if (git_buf_printf(&buf, "remote.%s.fetch", name) < 0) {
162 error = -1;
163 goto cleanup;
164 }
9c82357b 165
eb0bd77a 166 error = parse_remote_refspec(config, &remote->fetch, git_buf_cstr(&buf), true);
904b67e6 167 if (error == GIT_ENOTFOUND)
4376f7f6 168 error = 0;
9554cd51 169
4376f7f6
CMN
170 if (error < 0) {
171 error = -1;
9c82357b 172 goto cleanup;
2dc31040 173 }
9c82357b 174
f0f3a18a 175 git_buf_clear(&buf);
2fb9d6de 176 if (git_buf_printf(&buf, "remote.%s.push", name) < 0) {
177 error = -1;
178 goto cleanup;
179 }
9c82357b 180
eb0bd77a 181 error = parse_remote_refspec(config, &remote->push, git_buf_cstr(&buf), false);
904b67e6 182 if (error == GIT_ENOTFOUND)
4376f7f6 183 error = 0;
9c82357b 184
4376f7f6
CMN
185 if (error < 0) {
186 error = -1;
9c82357b 187 goto cleanup;
4376f7f6 188 }
9c82357b 189
24f2f94e
CMN
190 if (download_tags_value(remote, config) < 0)
191 goto cleanup;
192
9c82357b
CMN
193 *out = remote;
194
195cleanup:
f0f3a18a 196 git_buf_free(&buf);
9462c471 197
4376f7f6 198 if (error < 0)
9c82357b
CMN
199 git_remote_free(remote);
200
201 return error;
202}
203
e497b16c 204static int ensure_remote_name_is_valid(const char *name)
205{
206 git_buf buf = GIT_BUF_INIT;
207 git_refspec refspec;
208 int error = -1;
209
210 if (!name || *name == '\0')
211 goto cleanup;
212
213 git_buf_printf(&buf, "refs/heads/test:refs/remotes/%s/test", name);
214 error = git_refspec__parse(&refspec, git_buf_cstr(&buf), true);
215
216 git_buf_free(&buf);
217 git_refspec__free(&refspec);
218
219cleanup:
220 if (error)
221 giterr_set(
222 GITERR_CONFIG,
223 "'%s' is not a valid remote name.", name);
224
225 return error;
226}
227
4fe5520a 228static int update_config_refspec(
229 git_config *config,
230 const char *remote_name,
231 const git_refspec *refspec,
232 int git_direction)
233{
234 git_buf name = GIT_BUF_INIT, value = GIT_BUF_INIT;
235 int error = -1;
236
237 if (refspec->src == NULL || refspec->dst == NULL)
238 return 0;
239
fb39b3a5 240 if (git_buf_printf(
4fe5520a 241 &name,
242 "remote.%s.%s",
243 remote_name,
fb39b3a5 244 git_direction == GIT_DIR_FETCH ? "fetch" : "push") < 0)
245 goto cleanup;
4fe5520a 246
fb39b3a5 247 if (git_refspec__serialize(&value, refspec) < 0)
4fe5520a 248 goto cleanup;
249
250 error = git_config_set_string(
251 config,
252 git_buf_cstr(&name),
253 git_buf_cstr(&value));
254
255cleanup:
256 git_buf_free(&name);
257 git_buf_free(&value);
258
259 return error;
260}
261
89e5ed98
CMN
262int git_remote_save(const git_remote *remote)
263{
218c88a9 264 int error;
89e5ed98 265 git_config *config;
218c88a9 266 const char *tagopt = NULL;
4fe5520a 267 git_buf buf = GIT_BUF_INIT;
89e5ed98 268
e497b16c 269 assert(remote);
270
271 if (ensure_remote_name_is_valid(remote->name) < 0)
272 return -1;
89e5ed98 273
4376f7f6
CMN
274 if (git_repository_config__weakptr(&config, remote->repo) < 0)
275 return -1;
89e5ed98 276
cb020f0d 277 if (git_buf_printf(&buf, "remote.%s.url", remote->name) < 0)
4376f7f6 278 return -1;
89e5ed98 279
4376f7f6
CMN
280 if (git_config_set_string(config, git_buf_cstr(&buf), remote->url) < 0) {
281 git_buf_free(&buf);
282 return -1;
283 }
89e5ed98 284
413d5563
SC
285 git_buf_clear(&buf);
286 if (git_buf_printf(&buf, "remote.%s.pushurl", remote->name) < 0)
287 return -1;
3ed4b501 288
413d5563 289 if (remote->pushurl) {
3ed4b501
SC
290 if (git_config_set_string(config, git_buf_cstr(&buf), remote->pushurl) < 0) {
291 git_buf_free(&buf);
292 return -1;
293 }
413d5563
SC
294 } else {
295 int error = git_config_delete(config, git_buf_cstr(&buf));
296 if (error == GIT_ENOTFOUND) {
297 error = 0;
298 }
299 if (error < 0) {
300 git_buf_free(&buf);
301 return -1;
302 }
3ed4b501
SC
303 }
304
4fe5520a 305 if (update_config_refspec(
306 config,
307 remote->name,
308 &remote->fetch,
309 GIT_DIR_FETCH) < 0)
4376f7f6 310 goto on_error;
89e5ed98 311
4fe5520a 312 if (update_config_refspec(
313 config,
314 remote->name,
315 &remote->push,
316 GIT_DIR_PUSH) < 0)
4376f7f6 317 goto on_error;
89e5ed98 318
218c88a9
CMN
319 /*
320 * What action to take depends on the old and new values. This
321 * is describes by the table below. tagopt means whether the
322 * is already a value set in the config
323 *
324 * AUTO ALL or NONE
325 * +-----------------------+
326 * tagopt | remove | set |
327 * +---------+-------------|
328 * !tagopt | nothing | set |
329 * +---------+-------------+
330 */
331
332 git_buf_clear(&buf);
333 if (git_buf_printf(&buf, "remote.%s.tagopt", remote->name) < 0)
334 goto on_error;
335
336 error = git_config_get_string(&tagopt, config, git_buf_cstr(&buf));
337 if (error < 0 && error != GIT_ENOTFOUND)
338 goto on_error;
339
340 if (remote->download_tags == GIT_REMOTE_DOWNLOAD_TAGS_ALL) {
341 if (git_config_set_string(config, git_buf_cstr(&buf), "--tags") < 0)
342 goto on_error;
343 } else if (remote->download_tags == GIT_REMOTE_DOWNLOAD_TAGS_NONE) {
344 if (git_config_set_string(config, git_buf_cstr(&buf), "--no-tags") < 0)
345 goto on_error;
346 } else if (tagopt) {
347 if (git_config_delete(config, git_buf_cstr(&buf)) < 0)
348 goto on_error;
349 }
350
89e5ed98 351 git_buf_free(&buf);
4376f7f6
CMN
352
353 return 0;
354
355on_error:
356 git_buf_free(&buf);
4376f7f6 357 return -1;
89e5ed98
CMN
358}
359
4bef3565 360const char *git_remote_name(git_remote *remote)
9c82357b 361{
4bef3565 362 assert(remote);
9c82357b
CMN
363 return remote->name;
364}
365
4bef3565 366const char *git_remote_url(git_remote *remote)
9c82357b 367{
4bef3565 368 assert(remote);
9c82357b
CMN
369 return remote->url;
370}
371
76501590
SC
372int git_remote_set_url(git_remote *remote, const char* url)
373{
374 assert(remote);
375 assert(url);
376
377 git__free(remote->url);
378 remote->url = git__strdup(url);
379 GITERR_CHECK_ALLOC(remote->url);
380
381 return 0;
382}
383
384const char *git_remote_pushurl(git_remote *remote)
385{
386 assert(remote);
387 return remote->pushurl;
388}
389
390int git_remote_set_pushurl(git_remote *remote, const char* url)
391{
392 assert(remote);
393
394 git__free(remote->pushurl);
395 if (url) {
396 remote->pushurl = git__strdup(url);
397 GITERR_CHECK_ALLOC(remote->pushurl);
398 } else {
399 remote->pushurl = NULL;
400 }
401 return 0;
402}
403
bcb8c007
CMN
404int git_remote_set_fetchspec(git_remote *remote, const char *spec)
405{
bcb8c007
CMN
406 git_refspec refspec;
407
408 assert(remote && spec);
409
eb0bd77a 410 if (git_refspec__parse(&refspec, spec, true) < 0)
4376f7f6 411 return -1;
bcb8c007 412
eb0bd77a 413 git_refspec__free(&remote->fetch);
bcb8c007
CMN
414 remote->fetch.src = refspec.src;
415 remote->fetch.dst = refspec.dst;
416
4376f7f6 417 return 0;
bcb8c007
CMN
418}
419
4bef3565 420const git_refspec *git_remote_fetchspec(git_remote *remote)
9c82357b 421{
4bef3565 422 assert(remote);
9c82357b
CMN
423 return &remote->fetch;
424}
425
bcb8c007
CMN
426int git_remote_set_pushspec(git_remote *remote, const char *spec)
427{
bcb8c007
CMN
428 git_refspec refspec;
429
430 assert(remote && spec);
431
eb0bd77a 432 if (git_refspec__parse(&refspec, spec, false) < 0)
4376f7f6 433 return -1;
bcb8c007 434
eb0bd77a 435 git_refspec__free(&remote->push);
bcb8c007
CMN
436 remote->push.src = refspec.src;
437 remote->push.dst = refspec.dst;
438
4376f7f6 439 return 0;
bcb8c007
CMN
440}
441
4bef3565 442const git_refspec *git_remote_pushspec(git_remote *remote)
9c82357b 443{
4bef3565 444 assert(remote);
9c82357b
CMN
445 return &remote->push;
446}
447
eff5b499
SC
448const char* git_remote__urlfordirection(git_remote *remote, int direction)
449{
450 assert(remote);
451
452 if (direction == GIT_DIR_FETCH) {
453 return remote->url;
454 }
455
456 if (direction == GIT_DIR_PUSH) {
457 return remote->pushurl ? remote->pushurl : remote->url;
458 }
459
460 return NULL;
461}
462
0ac2726f 463int git_remote_connect(git_remote *remote, int direction)
9ba49bb5 464{
9ba49bb5 465 git_transport *t;
c0c39025 466 const char *url;
9ba49bb5 467
4bef3565
VM
468 assert(remote);
469
c0c39025 470 url = git_remote__urlfordirection(remote, direction);
eff5b499
SC
471 if (url == NULL )
472 return -1;
473
474 if (git_transport_new(&t, url) < 0)
4376f7f6 475 return -1;
9ba49bb5 476
e03e71da
CMN
477 t->progress_cb = remote->callbacks.progress;
478 t->cb_data = remote->callbacks.data;
479
250b95b2 480 t->check_cert = remote->check_cert;
4376f7f6
CMN
481 if (t->connect(t, direction) < 0) {
482 goto on_error;
9ba49bb5
CMN
483 }
484
485 remote->transport = t;
486
4376f7f6 487 return 0;
9ba49bb5 488
4376f7f6
CMN
489on_error:
490 t->free(t);
491 return -1;
9ba49bb5
CMN
492}
493
d88d4311 494int git_remote_ls(git_remote *remote, git_headlist_cb list_cb, void *payload)
9ba49bb5 495{
ad4b5beb
CMN
496 git_vector *refs = &remote->transport->refs;
497 unsigned int i;
498 git_pkt *p = NULL;
499
d88d4311
VM
500 assert(remote);
501
4376f7f6
CMN
502 if (!remote->transport || !remote->transport->connected) {
503 giterr_set(GITERR_NET, "The remote is not connected");
504 return -1;
505 }
d88d4311 506
ad4b5beb
CMN
507 git_vector_foreach(refs, i, p) {
508 git_pkt_ref *pkt = NULL;
509
510 if (p->type != GIT_PKT_REF)
511 continue;
512
513 pkt = (git_pkt_ref *)p;
514
e4607392 515 if (list_cb(&pkt->head, payload))
d8d28e2e 516 return GIT_EUSER;
ad4b5beb
CMN
517 }
518
519 return 0;
9ba49bb5
CMN
520}
521
216863c4
BS
522int git_remote_download(
523 git_remote *remote,
7d222e13 524 git_transfer_progress_callback progress_cb,
216863c4 525 void *progress_payload)
48a65a07 526{
95057b85
CMN
527 int error;
528
1e3b8ed5 529 assert(remote);
4bef3565 530
95057b85 531 if ((error = git_fetch_negotiate(remote)) < 0)
4376f7f6 532 return error;
95057b85 533
1e3b8ed5 534 return git_fetch_download_pack(remote, progress_cb, progress_payload);
48a65a07
CMN
535}
536
b3aaa7a7 537int git_remote_update_tips(git_remote *remote)
441f57c2 538{
a37ddf7e 539 int error = 0, autotag;
517bda19 540 unsigned int i = 0;
97769280 541 git_buf refname = GIT_BUF_INIT;
f184836b 542 git_oid old;
a37ddf7e
CMN
543 git_pkt *pkt;
544 git_odb *odb;
3f035860 545 git_vector *refs;
441f57c2
CMN
546 git_remote_head *head;
547 git_reference *ref;
3f035860 548 struct git_refspec *spec;
a37ddf7e 549 git_refspec tagspec;
441f57c2 550
4bef3565
VM
551 assert(remote);
552
a37ddf7e 553 refs = &remote->transport->refs;
3f035860
VM
554 spec = &remote->fetch;
555
d88d4311 556 if (refs->length == 0)
e172cf08 557 return 0;
517bda19 558
acd17006 559 if (git_repository_odb__weakptr(&odb, remote->repo) < 0)
a37ddf7e
CMN
560 return -1;
561
3230a44f 562 if (git_refspec__parse(&tagspec, GIT_REFSPEC_TAGS, true) < 0)
a37ddf7e
CMN
563 return -1;
564
517bda19 565 /* HEAD is only allowed to be the first in the list */
a37ddf7e
CMN
566 pkt = refs->contents[0];
567 head = &((git_pkt_ref *)pkt)->head;
517bda19 568 if (!strcmp(head->name, GIT_HEAD_FILE)) {
4376f7f6
CMN
569 if (git_reference_create_oid(&ref, remote->repo, GIT_FETCH_HEAD_FILE, &head->oid, 1) < 0)
570 return -1;
585a2eb7 571
4376f7f6 572 i = 1;
585a2eb7 573 git_reference_free(ref);
517bda19
CMN
574 }
575
d88d4311 576 for (; i < refs->length; ++i) {
a37ddf7e 577 git_pkt *pkt = refs->contents[i];
9063be1f 578 autotag = 0;
517bda19 579
a37ddf7e
CMN
580 if (pkt->type == GIT_PKT_REF)
581 head = &((git_pkt_ref *)pkt)->head;
582 else
583 continue;
584
585 /* Ignore malformed ref names (which also saves us from tag^{} */
586 if (!git_reference_is_valid_name(head->name))
587 continue;
588
589 if (git_refspec_src_matches(spec, head->name)) {
590 if (git_refspec_transform_r(&refname, spec, head->name) < 0)
591 goto on_error;
592 } else if (remote->download_tags != GIT_REMOTE_DOWNLOAD_TAGS_NONE) {
3230a44f
CMN
593
594 if (remote->download_tags != GIT_REMOTE_DOWNLOAD_TAGS_ALL)
595 autotag = 1;
a37ddf7e
CMN
596
597 if (!git_refspec_src_matches(&tagspec, head->name))
598 continue;
599
600 git_buf_clear(&refname);
601 if (git_buf_puts(&refname, head->name) < 0)
602 goto on_error;
603 } else {
604 continue;
605 }
606
607 if (autotag && !git_odb_exists(odb, &head->oid))
608 continue;
f184836b
CMN
609
610 error = git_reference_name_to_oid(&old, remote->repo, refname.ptr);
904b67e6 611 if (error < 0 && error != GIT_ENOTFOUND)
f184836b
CMN
612 goto on_error;
613
904b67e6 614 if (error == GIT_ENOTFOUND)
f184836b
CMN
615 memset(&old, 0, GIT_OID_RAWSZ);
616
617 if (!git_oid_cmp(&old, &head->oid))
618 continue;
441f57c2 619
a37ddf7e
CMN
620 /* In autotag mode, don't overwrite any locally-existing tags */
621 error = git_reference_create_oid(&ref, remote->repo, refname.ptr, &head->oid, !autotag);
622 if (error < 0 && error != GIT_EEXISTS)
944d250f 623 goto on_error;
39157563
CMN
624
625 git_reference_free(ref);
f184836b 626
b3aaa7a7
CMN
627 if (remote->callbacks.update_tips != NULL) {
628 if (remote->callbacks.update_tips(refname.ptr, &old, &head->oid, remote->callbacks.data) < 0)
f184836b
CMN
629 goto on_error;
630 }
441f57c2
CMN
631 }
632
a37ddf7e 633 git_refspec__free(&tagspec);
97769280 634 git_buf_free(&refname);
f184836b
CMN
635 return 0;
636
637on_error:
a37ddf7e 638 git_refspec__free(&tagspec);
f184836b
CMN
639 git_buf_free(&refname);
640 return -1;
97769280 641
441f57c2
CMN
642}
643
6ac3b707
CMN
644int git_remote_connected(git_remote *remote)
645{
4bef3565 646 assert(remote);
6ac3b707
CMN
647 return remote->transport == NULL ? 0 : remote->transport->connected;
648}
649
f0d2ddbb
CMN
650void git_remote_stop(git_remote *remote)
651{
652 git_atomic_set(&remote->transport->cancel, 1);
653}
654
4cf01e9a
CMN
655void git_remote_disconnect(git_remote *remote)
656{
4bef3565
VM
657 assert(remote);
658
42ea35c0 659 if (remote->transport != NULL && remote->transport->connected)
4cf01e9a 660 remote->transport->close(remote->transport);
4cf01e9a
CMN
661}
662
9c82357b
CMN
663void git_remote_free(git_remote *remote)
664{
2aae2188
CMN
665 if (remote == NULL)
666 return;
667
42ea35c0
MS
668 if (remote->transport != NULL) {
669 git_remote_disconnect(remote);
670
671 remote->transport->free(remote->transport);
672 remote->transport = NULL;
673 }
674
675 git_vector_free(&remote->refs);
676
3665ba8e
CMN
677 git_refspec__free(&remote->fetch);
678 git_refspec__free(&remote->push);
3286c408 679 git__free(remote->url);
3ed4b501 680 git__free(remote->pushurl);
3286c408 681 git__free(remote->name);
3286c408 682 git__free(remote);
9c82357b 683}
8171998f
CMN
684
685struct cb_data {
686 git_vector *list;
687 regex_t *preg;
688};
689
a1abe66a 690static int remote_list_cb(const git_config_entry *entry, void *data_)
8171998f
CMN
691{
692 struct cb_data *data = (struct cb_data *)data_;
693 size_t nmatch = 2;
694 regmatch_t pmatch[2];
a1abe66a 695 const char *name = entry->name;
8171998f
CMN
696
697 if (!regexec(data->preg, name, nmatch, pmatch, 0)) {
698 char *remote_name = git__strndup(&name[pmatch[1].rm_so], pmatch[1].rm_eo - pmatch[1].rm_so);
4376f7f6 699 GITERR_CHECK_ALLOC(remote_name);
8171998f 700
4376f7f6
CMN
701 if (git_vector_insert(data->list, remote_name) < 0)
702 return -1;
8171998f
CMN
703 }
704
4376f7f6 705 return 0;
8171998f
CMN
706}
707
708int git_remote_list(git_strarray *remotes_list, git_repository *repo)
709{
710 git_config *cfg;
711 git_vector list;
712 regex_t preg;
713 struct cb_data data;
714 int error;
715
4376f7f6
CMN
716 if (git_repository_config__weakptr(&cfg, repo) < 0)
717 return -1;
8171998f 718
4376f7f6
CMN
719 if (git_vector_init(&list, 4, NULL) < 0)
720 return -1;
8171998f 721
4376f7f6
CMN
722 if (regcomp(&preg, "^remote\\.(.*)\\.url$", REG_EXTENDED) < 0) {
723 giterr_set(GITERR_OS, "Remote catch regex failed to compile");
724 return -1;
725 }
8171998f
CMN
726
727 data.list = &list;
728 data.preg = &preg;
729 error = git_config_foreach(cfg, remote_list_cb, &data);
730 regfree(&preg);
4376f7f6 731 if (error < 0) {
8171998f
CMN
732 size_t i;
733 char *elem;
734 git_vector_foreach(&list, i, elem) {
2bc8fa02 735 git__free(elem);
8171998f
CMN
736 }
737
738 git_vector_free(&list);
e4607392
RB
739
740 /* cb error is converted to GIT_EUSER by git_config_foreach */
741 if (error == GIT_EUSER)
742 error = -1;
743
8171998f
CMN
744 return error;
745 }
746
747 remotes_list->strings = (char **)list.contents;
748 remotes_list->count = list.length;
749
4376f7f6 750 return 0;
8171998f 751}
a209a025
CMN
752
753int git_remote_add(git_remote **out, git_repository *repo, const char *name, const char *url)
754{
755 git_buf buf = GIT_BUF_INIT;
a209a025 756
d27bf665 757 if (git_buf_printf(&buf, "+refs/heads/*:refs/remotes/%s/*", name) < 0)
baaa8a44 758 return -1;
a209a025 759
baaa8a44 760 if (git_remote_new(out, repo, name, url, git_buf_cstr(&buf)) < 0)
a209a025
CMN
761 goto on_error;
762
763 git_buf_free(&buf);
764
765 if (git_remote_save(*out) < 0)
baaa8a44 766 goto on_error;
a209a025
CMN
767
768 return 0;
769
770on_error:
771 git_buf_free(&buf);
772 git_remote_free(*out);
773 return -1;
774}
250b95b2
CMN
775
776void git_remote_check_cert(git_remote *remote, int check)
777{
778 assert(remote);
779
780 remote->check_cert = check;
781}
b3aaa7a7
CMN
782
783void git_remote_set_callbacks(git_remote *remote, git_remote_callbacks *callbacks)
784{
785 assert(remote && callbacks);
786
787 memcpy(&remote->callbacks, callbacks, sizeof(git_remote_callbacks));
e03e71da
CMN
788
789 if (remote->transport) {
790 remote->transport->progress_cb = remote->callbacks.progress;
791 remote->transport->cb_data = remote->callbacks.data;
792 }
b3aaa7a7 793}
f70e466f 794
67dad09b 795const git_transfer_progress* git_remote_stats(git_remote *remote)
d57c47dc
BS
796{
797 assert(remote);
798 return &remote->stats;
799}
800
f70e466f
CMN
801int git_remote_autotag(git_remote *remote)
802{
803 return remote->download_tags;
804}
805
806void git_remote_set_autotag(git_remote *remote, int value)
807{
808 remote->download_tags = value;
809}
fcccf304 810
811static int ensure_remote_doesnot_exist(git_repository *repo, const char *name)
812{
813 int error;
814 git_remote *remote;
815
816 error = git_remote_load(&remote, repo, name);
817
818 if (error == GIT_ENOTFOUND)
819 return 0;
820
821 if (error < 0)
822 return error;
823
824 git_remote_free(remote);
825
826 giterr_set(
827 GITERR_CONFIG,
828 "Remote '%s' already exists.", name);
829
830 return GIT_EEXISTS;
831}
832
833static int rename_remote_config_section(
834 git_repository *repo,
835 const char *old_name,
836 const char *new_name)
837{
838 git_buf old_section_name = GIT_BUF_INIT,
839 new_section_name = GIT_BUF_INIT;
840 int error = -1;
841
842 if (git_buf_printf(&old_section_name, "remote.%s", old_name) < 0)
843 goto cleanup;
844
845 if (git_buf_printf(&new_section_name, "remote.%s", new_name) < 0)
846 goto cleanup;
847
848 error = git_config_rename_section(
849 repo,
850 git_buf_cstr(&old_section_name),
851 git_buf_cstr(&new_section_name));
852
853cleanup:
854 git_buf_free(&old_section_name);
855 git_buf_free(&new_section_name);
856
857 return error;
858}
859
860struct update_data
861{
862 git_config *config;
863 const char *old_remote_name;
864 const char *new_remote_name;
865};
866
867static int update_config_entries_cb(
868 const git_config_entry *entry,
869 void *payload)
870{
871 struct update_data *data = (struct update_data *)payload;
872
873 if (strcmp(entry->value, data->old_remote_name))
874 return 0;
875
876 return git_config_set_string(
877 data->config,
878 entry->name,
879 data->new_remote_name);
880}
881
882static int update_branch_remote_config_entry(
883 git_repository *repo,
884 const char *old_name,
885 const char *new_name)
886{
887 git_config *config;
888 struct update_data data;
889
890 if (git_repository_config__weakptr(&config, repo) < 0)
891 return -1;
892
893 data.config = config;
894 data.old_remote_name = old_name;
895 data.new_remote_name = new_name;
896
897 return git_config_foreach_match(
898 config,
899 "branch\\..+\\.remote",
900 update_config_entries_cb, &data);
901}
902
903static int rename_cb(const char *ref, void *data)
904{
905 if (git__prefixcmp(ref, GIT_REFS_REMOTES_DIR))
906 return 0;
907
908 return git_vector_insert((git_vector *)data, git__strdup(ref));
909}
910
911static int rename_one_remote_reference(
912 git_repository *repo,
913 const char *reference_name,
914 const char *old_remote_name,
915 const char *new_remote_name)
916{
917 int error;
918 git_buf new_name = GIT_BUF_INIT;
919 git_reference *reference = NULL;
920
921 if (git_buf_printf(
922 &new_name,
923 GIT_REFS_REMOTES_DIR "%s%s",
924 new_remote_name,
925 reference_name + strlen(GIT_REFS_REMOTES_DIR) + strlen(old_remote_name)) < 0)
926 return -1;
927
928 if (git_reference_lookup(&reference, repo, reference_name) < 0)
929 goto cleanup;
930
931 error = git_reference_rename(reference, git_buf_cstr(&new_name), 0);
932
933cleanup:
934 git_reference_free(reference);
935 git_buf_free(&new_name);
936 return error;
937}
938
939static int rename_remote_references(
940 git_repository *repo,
941 const char *old_name,
942 const char *new_name)
943{
944 git_vector refnames;
945 int error = -1;
946 unsigned int i;
947 char *name;
948
949 if (git_vector_init(&refnames, 8, NULL) < 0)
950 goto cleanup;
951
952 if (git_reference_foreach(
953 repo,
954 GIT_REF_LISTALL,
955 rename_cb,
956 &refnames) < 0)
957 goto cleanup;
958
959 git_vector_foreach(&refnames, i, name) {
960 if ((error = rename_one_remote_reference(repo, name, old_name, new_name)) < 0)
961 goto cleanup;
962 }
963
964 error = 0;
965cleanup:
966 git_vector_foreach(&refnames, i, name) {
967 git__free(name);
968 }
969
970 git_vector_free(&refnames);
971 return error;
972}
973
974static int rename_fetch_refspecs(
975 git_remote *remote,
976 const char *new_name,
977 int (*callback)(const char *problematic_refspec, void *payload),
978 void *payload)
979{
980 git_config *config;
981 const git_refspec *fetch_refspec;
982 git_buf dst_prefix = GIT_BUF_INIT, serialized = GIT_BUF_INIT;
983 const char* pos;
984 int error = -1;
985
986 fetch_refspec = git_remote_fetchspec(remote);
987
988 /* Is there a refspec to deal with? */
989 if (fetch_refspec->src == NULL &&
990 fetch_refspec->dst == NULL)
991 return 0;
992
993 if (git_refspec__serialize(&serialized, fetch_refspec) < 0)
994 goto cleanup;
995
996 /* Is it an in-memory remote? */
997 if (remote->name == '\0') {
998 error = (callback(git_buf_cstr(&serialized), payload) < 0) ? GIT_EUSER : 0;
999 goto cleanup;
1000 }
1001
1002 if (git_buf_printf(&dst_prefix, ":refs/remotes/%s/", remote->name) < 0)
1003 goto cleanup;
1004
1005 pos = strstr(git_buf_cstr(&serialized), git_buf_cstr(&dst_prefix));
1006
1007 /* Does the dst part of the refspec follow the extected standard format? */
1008 if (!pos) {
1009 error = (callback(git_buf_cstr(&serialized), payload) < 0) ? GIT_EUSER : 0;
1010 goto cleanup;
1011 }
1012
1013 if (git_buf_splice(
1014 &serialized,
1015 pos - git_buf_cstr(&serialized) + strlen(":refs/remotes/"),
1016 strlen(remote->name), new_name,
1017 strlen(new_name)) < 0)
1018 goto cleanup;
1019
1020 git_refspec__free(&remote->fetch);
1021
1022 if (git_refspec__parse(&remote->fetch, git_buf_cstr(&serialized), true) < 0)
1023 goto cleanup;
1024
1025 if (git_repository_config__weakptr(&config, remote->repo) < 0)
1026 goto cleanup;
1027
1028 error = update_config_refspec(config, new_name, &remote->fetch, GIT_DIR_FETCH);
1029
1030cleanup:
1031 git_buf_free(&serialized);
1032 git_buf_free(&dst_prefix);
1033 return error;
1034}
1035
1036int git_remote_rename(
1037 git_remote *remote,
1038 const char *new_name,
1039 int (*callback)(const char *problematic_refspec, void *payload),
1040 void *payload)
1041{
1042 int error;
1043
1044 assert(remote && new_name);
1045
1046 if ((error = ensure_remote_doesnot_exist(remote->repo, new_name)) < 0)
1047 return error;
1048
1049 if ((error = ensure_remote_name_is_valid(new_name)) < 0)
1050 return error;
1051
1052 if (!remote->name) {
1053 if ((error = rename_fetch_refspecs(
1054 remote,
1055 new_name,
1056 callback,
1057 payload)) < 0)
1058 return error;
1059
1060 remote->name = git__strdup(new_name);
1061
1062 return git_remote_save(remote);
1063 }
1064
1065 if ((error = rename_remote_config_section(
1066 remote->repo,
1067 remote->name,
1068 new_name)) < 0)
1069 return error;
1070
1071 if ((error = update_branch_remote_config_entry(
1072 remote->repo,
1073 remote->name,
1074 new_name)) < 0)
1075 return error;
1076
1077 if ((error = rename_remote_references(
1078 remote->repo,
1079 remote->name,
1080 new_name)) < 0)
1081 return error;
1082
1083 if ((error = rename_fetch_refspecs(
1084 remote,
1085 new_name,
1086 callback,
1087 payload)) < 0)
1088 return error;
1089
1090 git__free(remote->name);
1091 remote->name = git__strdup(new_name);
1092
1093 return 0;
1094}