]> git.proxmox.com Git - libgit2.git/blob - src/remote.c
remote: add accessors for the autotag setting
[libgit2.git] / src / remote.c
1 /*
2 * Copyright (C) 2009-2012 the libgit2 contributors
3 *
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.
6 */
7
8 #include "git2/config.h"
9 #include "git2/types.h"
10 #include "git2/oid.h"
11
12 #include "config.h"
13 #include "repository.h"
14 #include "remote.h"
15 #include "fetch.h"
16 #include "refs.h"
17 #include "pkt.h"
18
19 #include <regex.h>
20
21 static int refspec_parse(git_refspec *refspec, const char *str)
22 {
23 char *delim;
24
25 memset(refspec, 0x0, sizeof(git_refspec));
26
27 if (*str == '+') {
28 refspec->force = 1;
29 str++;
30 }
31
32 delim = strchr(str, ':');
33 if (delim == NULL) {
34 giterr_set(GITERR_NET, "Invalid refspec, missing ':'");
35 return -1;
36 }
37
38 refspec->src = git__strndup(str, delim - str);
39 GITERR_CHECK_ALLOC(refspec->src);
40
41 refspec->dst = git__strdup(delim + 1);
42 GITERR_CHECK_ALLOC(refspec->dst);
43
44 return 0;
45 }
46
47 static int parse_remote_refspec(git_config *cfg, git_refspec *refspec, const char *var)
48 {
49 int error;
50 const char *val;
51
52 if ((error = git_config_get_string(&val, cfg, var)) < 0)
53 return error;
54
55 return refspec_parse(refspec, val);
56 }
57
58 static int download_tags_value(git_remote *remote, git_config *cfg)
59 {
60 const char *val;
61 git_buf buf = GIT_BUF_INIT;
62 int error;
63
64 if (remote->download_tags != GIT_REMOTE_DOWNLOAD_TAGS_UNSET)
65 return 0;
66
67 /* This is the default, let's see if we need to change it */
68 remote->download_tags = GIT_REMOTE_DOWNLOAD_TAGS_AUTO;
69 if (git_buf_printf(&buf, "remote.%s.tagopt", remote->name) < 0)
70 return -1;
71
72 error = git_config_get_string(&val, cfg, git_buf_cstr(&buf));
73 git_buf_free(&buf);
74 if (!error && !strcmp(val, "--no-tags"))
75 remote->download_tags = GIT_REMOTE_DOWNLOAD_TAGS_NONE;
76
77 if (error == GIT_ENOTFOUND)
78 error = 0;
79
80 return error;
81 }
82
83 int git_remote_new(git_remote **out, git_repository *repo, const char *name, const char *url, const char *fetch)
84 {
85 git_remote *remote;
86
87 /* name is optional */
88 assert(out && repo && url);
89
90 remote = git__malloc(sizeof(git_remote));
91 GITERR_CHECK_ALLOC(remote);
92
93 memset(remote, 0x0, sizeof(git_remote));
94 remote->repo = repo;
95 remote->check_cert = 1;
96
97 if (git_vector_init(&remote->refs, 32, NULL) < 0)
98 return -1;
99
100 remote->url = git__strdup(url);
101 GITERR_CHECK_ALLOC(remote->url);
102
103 if (name != NULL) {
104 remote->name = git__strdup(name);
105 GITERR_CHECK_ALLOC(remote->name);
106 }
107
108 if (fetch != NULL) {
109 if (refspec_parse(&remote->fetch, fetch) < 0)
110 goto on_error;
111 }
112
113 *out = remote;
114 return 0;
115
116 on_error:
117 git_remote_free(remote);
118 return -1;
119 }
120
121 int git_remote_load(git_remote **out, git_repository *repo, const char *name)
122 {
123 git_remote *remote;
124 git_buf buf = GIT_BUF_INIT;
125 const char *val;
126 int error = 0;
127 git_config *config;
128
129 assert(out && repo && name);
130
131 if (git_repository_config__weakptr(&config, repo) < 0)
132 return -1;
133
134 remote = git__malloc(sizeof(git_remote));
135 GITERR_CHECK_ALLOC(remote);
136
137 memset(remote, 0x0, sizeof(git_remote));
138 remote->check_cert = 1;
139 remote->name = git__strdup(name);
140 GITERR_CHECK_ALLOC(remote->name);
141
142 if (git_vector_init(&remote->refs, 32, NULL) < 0) {
143 error = -1;
144 goto cleanup;
145 }
146
147 if (git_buf_printf(&buf, "remote.%s.url", name) < 0) {
148 error = -1;
149 goto cleanup;
150 }
151
152 if ((error = git_config_get_string(&val, config, git_buf_cstr(&buf))) < 0)
153 goto cleanup;
154
155 remote->repo = repo;
156 remote->url = git__strdup(val);
157 GITERR_CHECK_ALLOC(remote->url);
158
159 git_buf_clear(&buf);
160 if (git_buf_printf(&buf, "remote.%s.pushurl", name) < 0) {
161 error = -1;
162 goto cleanup;
163 }
164
165 error = git_config_get_string(&val, config, git_buf_cstr(&buf));
166 if (error == GIT_ENOTFOUND)
167 error = 0;
168
169 if (error < 0) {
170 error = -1;
171 goto cleanup;
172 }
173
174 if (val) {
175 remote->pushurl = git__strdup(val);
176 GITERR_CHECK_ALLOC(remote->pushurl);
177 }
178
179 git_buf_clear(&buf);
180 if (git_buf_printf(&buf, "remote.%s.fetch", name) < 0) {
181 error = -1;
182 goto cleanup;
183 }
184
185 error = parse_remote_refspec(config, &remote->fetch, git_buf_cstr(&buf));
186 if (error == GIT_ENOTFOUND)
187 error = 0;
188
189 if (error < 0) {
190 error = -1;
191 goto cleanup;
192 }
193
194 git_buf_clear(&buf);
195 if (git_buf_printf(&buf, "remote.%s.push", name) < 0) {
196 error = -1;
197 goto cleanup;
198 }
199
200 error = parse_remote_refspec(config, &remote->push, git_buf_cstr(&buf));
201 if (error == GIT_ENOTFOUND)
202 error = 0;
203
204 if (error < 0) {
205 error = -1;
206 goto cleanup;
207 }
208
209 if (download_tags_value(remote, config) < 0)
210 goto cleanup;
211
212 *out = remote;
213
214 cleanup:
215 git_buf_free(&buf);
216
217 if (error < 0)
218 git_remote_free(remote);
219
220 return error;
221 }
222
223 int git_remote_save(const git_remote *remote)
224 {
225 git_config *config;
226 git_buf buf = GIT_BUF_INIT, value = GIT_BUF_INIT;
227
228 if (git_repository_config__weakptr(&config, remote->repo) < 0)
229 return -1;
230
231 if (git_buf_printf(&buf, "remote.%s.url", remote->name) < 0)
232 return -1;
233
234 if (git_config_set_string(config, git_buf_cstr(&buf), remote->url) < 0) {
235 git_buf_free(&buf);
236 return -1;
237 }
238
239 git_buf_clear(&buf);
240 if (git_buf_printf(&buf, "remote.%s.pushurl", remote->name) < 0)
241 return -1;
242
243 if (remote->pushurl) {
244 if (git_config_set_string(config, git_buf_cstr(&buf), remote->pushurl) < 0) {
245 git_buf_free(&buf);
246 return -1;
247 }
248 } else {
249 int error = git_config_delete(config, git_buf_cstr(&buf));
250 if (error == GIT_ENOTFOUND) {
251 error = 0;
252 }
253 if (error < 0) {
254 git_buf_free(&buf);
255 return -1;
256 }
257 }
258
259 if (remote->fetch.src != NULL && remote->fetch.dst != NULL) {
260 git_buf_clear(&buf);
261 git_buf_clear(&value);
262 git_buf_printf(&buf, "remote.%s.fetch", remote->name);
263 if (remote->fetch.force)
264 git_buf_putc(&value, '+');
265 git_buf_printf(&value, "%s:%s", remote->fetch.src, remote->fetch.dst);
266 if (git_buf_oom(&buf) || git_buf_oom(&value))
267 return -1;
268
269 if (git_config_set_string(config, git_buf_cstr(&buf), git_buf_cstr(&value)) < 0)
270 goto on_error;
271 }
272
273 if (remote->push.src != NULL && remote->push.dst != NULL) {
274 git_buf_clear(&buf);
275 git_buf_clear(&value);
276 git_buf_printf(&buf, "remote.%s.push", remote->name);
277 if (remote->push.force)
278 git_buf_putc(&value, '+');
279 git_buf_printf(&value, "%s:%s", remote->push.src, remote->push.dst);
280 if (git_buf_oom(&buf) || git_buf_oom(&value))
281 return -1;
282
283 if (git_config_set_string(config, git_buf_cstr(&buf), git_buf_cstr(&value)) < 0)
284 goto on_error;
285 }
286
287 git_buf_free(&buf);
288 git_buf_free(&value);
289
290 return 0;
291
292 on_error:
293 git_buf_free(&buf);
294 git_buf_free(&value);
295 return -1;
296 }
297
298 const char *git_remote_name(git_remote *remote)
299 {
300 assert(remote);
301 return remote->name;
302 }
303
304 const char *git_remote_url(git_remote *remote)
305 {
306 assert(remote);
307 return remote->url;
308 }
309
310 int git_remote_set_url(git_remote *remote, const char* url)
311 {
312 assert(remote);
313 assert(url);
314
315 git__free(remote->url);
316 remote->url = git__strdup(url);
317 GITERR_CHECK_ALLOC(remote->url);
318
319 return 0;
320 }
321
322 const char *git_remote_pushurl(git_remote *remote)
323 {
324 assert(remote);
325 return remote->pushurl;
326 }
327
328 int git_remote_set_pushurl(git_remote *remote, const char* url)
329 {
330 assert(remote);
331
332 git__free(remote->pushurl);
333 if (url) {
334 remote->pushurl = git__strdup(url);
335 GITERR_CHECK_ALLOC(remote->pushurl);
336 } else {
337 remote->pushurl = NULL;
338 }
339 return 0;
340 }
341
342 int git_remote_set_fetchspec(git_remote *remote, const char *spec)
343 {
344 git_refspec refspec;
345
346 assert(remote && spec);
347
348 if (refspec_parse(&refspec, spec) < 0)
349 return -1;
350
351 git__free(remote->fetch.src);
352 git__free(remote->fetch.dst);
353 remote->fetch.src = refspec.src;
354 remote->fetch.dst = refspec.dst;
355
356 return 0;
357 }
358
359 const git_refspec *git_remote_fetchspec(git_remote *remote)
360 {
361 assert(remote);
362 return &remote->fetch;
363 }
364
365 int git_remote_set_pushspec(git_remote *remote, const char *spec)
366 {
367 git_refspec refspec;
368
369 assert(remote && spec);
370
371 if (refspec_parse(&refspec, spec) < 0)
372 return -1;
373
374 git__free(remote->push.src);
375 git__free(remote->push.dst);
376 remote->push.src = refspec.src;
377 remote->push.dst = refspec.dst;
378
379 return 0;
380 }
381
382 const git_refspec *git_remote_pushspec(git_remote *remote)
383 {
384 assert(remote);
385 return &remote->push;
386 }
387
388 const char* git_remote__urlfordirection(git_remote *remote, int direction)
389 {
390 assert(remote);
391
392 if (direction == GIT_DIR_FETCH) {
393 return remote->url;
394 }
395
396 if (direction == GIT_DIR_PUSH) {
397 return remote->pushurl ? remote->pushurl : remote->url;
398 }
399
400 return NULL;
401 }
402
403 int git_remote_connect(git_remote *remote, int direction)
404 {
405 git_transport *t;
406 const char *url;
407
408 assert(remote);
409
410 url = git_remote__urlfordirection(remote, direction);
411 if (url == NULL )
412 return -1;
413
414 if (git_transport_new(&t, url) < 0)
415 return -1;
416
417 t->progress_cb = remote->callbacks.progress;
418 t->cb_data = remote->callbacks.data;
419
420 t->check_cert = remote->check_cert;
421 if (t->connect(t, direction) < 0) {
422 goto on_error;
423 }
424
425 remote->transport = t;
426
427 return 0;
428
429 on_error:
430 t->free(t);
431 return -1;
432 }
433
434 int git_remote_ls(git_remote *remote, git_headlist_cb list_cb, void *payload)
435 {
436 git_vector *refs = &remote->transport->refs;
437 unsigned int i;
438 git_pkt *p = NULL;
439
440 assert(remote);
441
442 if (!remote->transport || !remote->transport->connected) {
443 giterr_set(GITERR_NET, "The remote is not connected");
444 return -1;
445 }
446
447 git_vector_foreach(refs, i, p) {
448 git_pkt_ref *pkt = NULL;
449
450 if (p->type != GIT_PKT_REF)
451 continue;
452
453 pkt = (git_pkt_ref *)p;
454
455 if (list_cb(&pkt->head, payload))
456 return GIT_EUSER;
457 }
458
459 return 0;
460 }
461
462 int git_remote_download(git_remote *remote, git_off_t *bytes, git_indexer_stats *stats)
463 {
464 int error;
465
466 assert(remote && bytes && stats);
467
468 if ((error = git_fetch_negotiate(remote)) < 0)
469 return error;
470
471 return git_fetch_download_pack(remote, bytes, stats);
472 }
473
474 int git_remote_update_tips(git_remote *remote)
475 {
476 int error = 0, autotag;
477 unsigned int i = 0;
478 git_buf refname = GIT_BUF_INIT;
479 git_oid old;
480 git_pkt *pkt;
481 git_odb *odb;
482 git_vector *refs;
483 git_remote_head *head;
484 git_reference *ref;
485 struct git_refspec *spec;
486 char *tagstr = "refs/tags/*:refs/tags/*";
487 git_refspec tagspec;
488
489 assert(remote);
490
491 refs = &remote->transport->refs;
492 spec = &remote->fetch;
493
494 if (refs->length == 0)
495 return 0;
496
497 if (git_repository_odb(&odb, remote->repo) < 0)
498 return -1;
499
500 if (git_refspec__parse(&tagspec, tagstr, true) < 0)
501 return -1;
502
503 /* HEAD is only allowed to be the first in the list */
504 pkt = refs->contents[0];
505 head = &((git_pkt_ref *)pkt)->head;
506 if (!strcmp(head->name, GIT_HEAD_FILE)) {
507 if (git_reference_create_oid(&ref, remote->repo, GIT_FETCH_HEAD_FILE, &head->oid, 1) < 0)
508 return -1;
509
510 i = 1;
511 git_reference_free(ref);
512 }
513
514 for (; i < refs->length; ++i) {
515 autotag = 0;
516 git_pkt *pkt = refs->contents[i];
517
518 if (pkt->type == GIT_PKT_REF)
519 head = &((git_pkt_ref *)pkt)->head;
520 else
521 continue;
522
523 /* Ignore malformed ref names (which also saves us from tag^{} */
524 if (!git_reference_is_valid_name(head->name))
525 continue;
526
527 if (git_refspec_src_matches(spec, head->name)) {
528 if (git_refspec_transform_r(&refname, spec, head->name) < 0)
529 goto on_error;
530 } else if (remote->download_tags != GIT_REMOTE_DOWNLOAD_TAGS_NONE) {
531 autotag = 1;
532
533 if (!git_refspec_src_matches(&tagspec, head->name))
534 continue;
535
536 git_buf_clear(&refname);
537 if (git_buf_puts(&refname, head->name) < 0)
538 goto on_error;
539 } else {
540 continue;
541 }
542
543 if (autotag && !git_odb_exists(odb, &head->oid))
544 continue;
545
546 error = git_reference_name_to_oid(&old, remote->repo, refname.ptr);
547 if (error < 0 && error != GIT_ENOTFOUND)
548 goto on_error;
549
550 if (error == GIT_ENOTFOUND)
551 memset(&old, 0, GIT_OID_RAWSZ);
552
553 if (!git_oid_cmp(&old, &head->oid))
554 continue;
555
556 /* In autotag mode, don't overwrite any locally-existing tags */
557 error = git_reference_create_oid(&ref, remote->repo, refname.ptr, &head->oid, !autotag);
558 if (error < 0 && error != GIT_EEXISTS)
559 goto on_error;
560
561 git_reference_free(ref);
562
563 if (remote->callbacks.update_tips != NULL) {
564 if (remote->callbacks.update_tips(refname.ptr, &old, &head->oid, remote->callbacks.data) < 0)
565 goto on_error;
566 }
567 }
568
569 git_refspec__free(&tagspec);
570 git_buf_free(&refname);
571 return 0;
572
573 on_error:
574 git_refspec__free(&tagspec);
575 git_buf_free(&refname);
576 return -1;
577
578 }
579
580 int git_remote_connected(git_remote *remote)
581 {
582 assert(remote);
583 return remote->transport == NULL ? 0 : remote->transport->connected;
584 }
585
586 void git_remote_disconnect(git_remote *remote)
587 {
588 assert(remote);
589
590 if (remote->transport != NULL && remote->transport->connected)
591 remote->transport->close(remote->transport);
592 }
593
594 void git_remote_free(git_remote *remote)
595 {
596 if (remote == NULL)
597 return;
598
599 if (remote->transport != NULL) {
600 git_remote_disconnect(remote);
601
602 remote->transport->free(remote->transport);
603 remote->transport = NULL;
604 }
605
606 git_vector_free(&remote->refs);
607
608 git_refspec__free(&remote->fetch);
609 git_refspec__free(&remote->push);
610 git__free(remote->url);
611 git__free(remote->pushurl);
612 git__free(remote->name);
613 git__free(remote);
614 }
615
616 struct cb_data {
617 git_vector *list;
618 regex_t *preg;
619 };
620
621 static int remote_list_cb(const char *name, const char *value, void *data_)
622 {
623 struct cb_data *data = (struct cb_data *)data_;
624 size_t nmatch = 2;
625 regmatch_t pmatch[2];
626 GIT_UNUSED(value);
627
628 if (!regexec(data->preg, name, nmatch, pmatch, 0)) {
629 char *remote_name = git__strndup(&name[pmatch[1].rm_so], pmatch[1].rm_eo - pmatch[1].rm_so);
630 GITERR_CHECK_ALLOC(remote_name);
631
632 if (git_vector_insert(data->list, remote_name) < 0)
633 return -1;
634 }
635
636 return 0;
637 }
638
639 int git_remote_list(git_strarray *remotes_list, git_repository *repo)
640 {
641 git_config *cfg;
642 git_vector list;
643 regex_t preg;
644 struct cb_data data;
645 int error;
646
647 if (git_repository_config__weakptr(&cfg, repo) < 0)
648 return -1;
649
650 if (git_vector_init(&list, 4, NULL) < 0)
651 return -1;
652
653 if (regcomp(&preg, "^remote\\.(.*)\\.url$", REG_EXTENDED) < 0) {
654 giterr_set(GITERR_OS, "Remote catch regex failed to compile");
655 return -1;
656 }
657
658 data.list = &list;
659 data.preg = &preg;
660 error = git_config_foreach(cfg, remote_list_cb, &data);
661 regfree(&preg);
662 if (error < 0) {
663 size_t i;
664 char *elem;
665 git_vector_foreach(&list, i, elem) {
666 git__free(elem);
667 }
668
669 git_vector_free(&list);
670
671 /* cb error is converted to GIT_EUSER by git_config_foreach */
672 if (error == GIT_EUSER)
673 error = -1;
674
675 return error;
676 }
677
678 remotes_list->strings = (char **)list.contents;
679 remotes_list->count = list.length;
680
681 return 0;
682 }
683
684 int git_remote_add(git_remote **out, git_repository *repo, const char *name, const char *url)
685 {
686 git_buf buf = GIT_BUF_INIT;
687
688 if (git_buf_printf(&buf, "+refs/heads/*:refs/remotes/%s/*", name) < 0)
689 return -1;
690
691 if (git_remote_new(out, repo, name, url, git_buf_cstr(&buf)) < 0)
692 goto on_error;
693
694 git_buf_free(&buf);
695
696 if (git_remote_save(*out) < 0)
697 goto on_error;
698
699 return 0;
700
701 on_error:
702 git_buf_free(&buf);
703 git_remote_free(*out);
704 return -1;
705 }
706
707 void git_remote_check_cert(git_remote *remote, int check)
708 {
709 assert(remote);
710
711 remote->check_cert = check;
712 }
713
714 void git_remote_set_callbacks(git_remote *remote, git_remote_callbacks *callbacks)
715 {
716 assert(remote && callbacks);
717
718 memcpy(&remote->callbacks, callbacks, sizeof(git_remote_callbacks));
719
720 if (remote->transport) {
721 remote->transport->progress_cb = remote->callbacks.progress;
722 remote->transport->cb_data = remote->callbacks.data;
723 }
724 }
725
726 int git_remote_autotag(git_remote *remote)
727 {
728 return remote->download_tags;
729 }
730
731 void git_remote_set_autotag(git_remote *remote, int value)
732 {
733 remote->download_tags = value;
734 }