]> git.proxmox.com Git - libgit2.git/blame - src/remote.c
Remove unneccessary string transformation
[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
8#include "git2/remote.h"
9#include "git2/config.h"
10#include "git2/types.h"
11
12#include "config.h"
13#include "repository.h"
14#include "remote.h"
e1d88030 15#include "fetch.h"
441f57c2 16#include "refs.h"
9c82357b 17
8171998f
CMN
18#include <regex.h>
19
9c82357b
CMN
20static int refspec_parse(git_refspec *refspec, const char *str)
21{
22 char *delim;
23
24 memset(refspec, 0x0, sizeof(git_refspec));
25
26 if (*str == '+') {
27 refspec->force = 1;
28 str++;
29 }
30
31 delim = strchr(str, ':');
4376f7f6
CMN
32 if (delim == NULL) {
33 giterr_set(GITERR_NET, "Invalid refspec, missing ':'");
34 return -1;
35 }
9c82357b
CMN
36
37 refspec->src = git__strndup(str, delim - str);
4376f7f6 38 GITERR_CHECK_ALLOC(refspec->src);
9c82357b
CMN
39
40 refspec->dst = git__strdup(delim + 1);
4376f7f6 41 GITERR_CHECK_ALLOC(refspec->dst);
9c82357b 42
4376f7f6 43 return 0;
9c82357b
CMN
44}
45
46static int parse_remote_refspec(git_config *cfg, git_refspec *refspec, const char *var)
47{
9c82357b 48 int error;
4376f7f6 49 const char *val;
9c82357b 50
29e948de 51 if ((error = git_config_get_string(&val, cfg, var)) < 0)
9c82357b
CMN
52 return error;
53
2dc31040 54 return refspec_parse(refspec, val);
9c82357b
CMN
55}
56
baaa8a44 57int git_remote_new(git_remote **out, git_repository *repo, const char *name, const char *url, const char *fetch)
778e1c73
CMN
58{
59 git_remote *remote;
60
4bef3565
VM
61 /* name is optional */
62 assert(out && repo && url);
617bfdf4 63
778e1c73 64 remote = git__malloc(sizeof(git_remote));
4376f7f6 65 GITERR_CHECK_ALLOC(remote);
778e1c73
CMN
66
67 memset(remote, 0x0, sizeof(git_remote));
68 remote->repo = repo;
250b95b2 69 remote->check_cert = 1;
617bfdf4 70
4376f7f6
CMN
71 if (git_vector_init(&remote->refs, 32, NULL) < 0)
72 return -1;
d88d4311 73
778e1c73 74 remote->url = git__strdup(url);
4376f7f6 75 GITERR_CHECK_ALLOC(remote->url);
778e1c73 76
617bfdf4
CMN
77 if (name != NULL) {
78 remote->name = git__strdup(name);
4376f7f6 79 GITERR_CHECK_ALLOC(remote->name);
617bfdf4
CMN
80 }
81
baaa8a44
CMN
82 if (fetch != NULL) {
83 if (refspec_parse(&remote->fetch, fetch) < 0)
84 goto on_error;
85 }
86
778e1c73 87 *out = remote;
4376f7f6 88 return 0;
baaa8a44
CMN
89
90on_error:
91 git_remote_free(remote);
92 return -1;
778e1c73
CMN
93}
94
9462c471 95int git_remote_load(git_remote **out, git_repository *repo, const char *name)
9c82357b
CMN
96{
97 git_remote *remote;
f0f3a18a 98 git_buf buf = GIT_BUF_INIT;
9c82357b 99 const char *val;
4376f7f6 100 int error = 0;
9462c471 101 git_config *config;
9c82357b 102
9462c471
VM
103 assert(out && repo && name);
104
4376f7f6
CMN
105 if (git_repository_config__weakptr(&config, repo) < 0)
106 return -1;
4bef3565 107
9c82357b 108 remote = git__malloc(sizeof(git_remote));
4376f7f6 109 GITERR_CHECK_ALLOC(remote);
9c82357b
CMN
110
111 memset(remote, 0x0, sizeof(git_remote));
250b95b2 112 remote->check_cert = 1;
9c82357b 113 remote->name = git__strdup(name);
4376f7f6 114 GITERR_CHECK_ALLOC(remote->name);
9c82357b 115
2fb9d6de 116 if (git_vector_init(&remote->refs, 32, NULL) < 0) {
117 error = -1;
118 goto cleanup;
119 }
d88d4311 120
2fb9d6de 121 if (git_buf_printf(&buf, "remote.%s.url", name) < 0) {
122 error = -1;
123 goto cleanup;
124 }
9c82357b 125
29e948de 126 if ((error = git_config_get_string(&val, config, git_buf_cstr(&buf))) < 0)
9c82357b 127 goto cleanup;
9c82357b 128
9462c471 129 remote->repo = repo;
9c82357b 130 remote->url = git__strdup(val);
4376f7f6 131 GITERR_CHECK_ALLOC(remote->url);
9c82357b 132
f0f3a18a 133 git_buf_clear(&buf);
2fb9d6de 134 if (git_buf_printf(&buf, "remote.%s.fetch", name) < 0) {
135 error = -1;
136 goto cleanup;
137 }
9c82357b 138
f0f3a18a 139 error = parse_remote_refspec(config, &remote->fetch, git_buf_cstr(&buf));
904b67e6 140 if (error == GIT_ENOTFOUND)
4376f7f6 141 error = 0;
9554cd51 142
4376f7f6
CMN
143 if (error < 0) {
144 error = -1;
9c82357b 145 goto cleanup;
2dc31040 146 }
9c82357b 147
f0f3a18a 148 git_buf_clear(&buf);
2fb9d6de 149 if (git_buf_printf(&buf, "remote.%s.push", name) < 0) {
150 error = -1;
151 goto cleanup;
152 }
9c82357b 153
f0f3a18a 154 error = parse_remote_refspec(config, &remote->push, git_buf_cstr(&buf));
904b67e6 155 if (error == GIT_ENOTFOUND)
4376f7f6 156 error = 0;
9c82357b 157
4376f7f6
CMN
158 if (error < 0) {
159 error = -1;
9c82357b 160 goto cleanup;
4376f7f6 161 }
9c82357b
CMN
162
163 *out = remote;
164
165cleanup:
f0f3a18a 166 git_buf_free(&buf);
9462c471 167
4376f7f6 168 if (error < 0)
9c82357b
CMN
169 git_remote_free(remote);
170
171 return error;
172}
173
89e5ed98
CMN
174int git_remote_save(const git_remote *remote)
175{
89e5ed98
CMN
176 git_config *config;
177 git_buf buf = GIT_BUF_INIT, value = GIT_BUF_INIT;
178
4376f7f6
CMN
179 if (git_repository_config__weakptr(&config, remote->repo) < 0)
180 return -1;
89e5ed98 181
cb020f0d 182 if (git_buf_printf(&buf, "remote.%s.url", remote->name) < 0)
4376f7f6 183 return -1;
89e5ed98 184
4376f7f6
CMN
185 if (git_config_set_string(config, git_buf_cstr(&buf), remote->url) < 0) {
186 git_buf_free(&buf);
187 return -1;
188 }
89e5ed98 189
9c94a356 190 if (remote->fetch.src != NULL && remote->fetch.dst != NULL) {
89e5ed98
CMN
191 git_buf_clear(&buf);
192 git_buf_clear(&value);
4376f7f6 193 git_buf_printf(&buf, "remote.%s.fetch", remote->name);
d05e2c64 194 if (remote->fetch.force)
195 git_buf_putc(&value, '+');
89e5ed98
CMN
196 git_buf_printf(&value, "%s:%s", remote->fetch.src, remote->fetch.dst);
197 if (git_buf_oom(&buf) || git_buf_oom(&value))
4376f7f6 198 return -1;
89e5ed98 199
4376f7f6
CMN
200 if (git_config_set_string(config, git_buf_cstr(&buf), git_buf_cstr(&value)) < 0)
201 goto on_error;
89e5ed98
CMN
202 }
203
9c94a356 204 if (remote->push.src != NULL && remote->push.dst != NULL) {
89e5ed98
CMN
205 git_buf_clear(&buf);
206 git_buf_clear(&value);
4376f7f6 207 git_buf_printf(&buf, "remote.%s.push", remote->name);
d05e2c64 208 if (remote->push.force)
209 git_buf_putc(&value, '+');
89e5ed98
CMN
210 git_buf_printf(&value, "%s:%s", remote->push.src, remote->push.dst);
211 if (git_buf_oom(&buf) || git_buf_oom(&value))
4376f7f6 212 return -1;
89e5ed98 213
4376f7f6
CMN
214 if (git_config_set_string(config, git_buf_cstr(&buf), git_buf_cstr(&value)) < 0)
215 goto on_error;
89e5ed98
CMN
216 }
217
89e5ed98
CMN
218 git_buf_free(&buf);
219 git_buf_free(&value);
4376f7f6
CMN
220
221 return 0;
222
223on_error:
224 git_buf_free(&buf);
225 git_buf_free(&value);
226 return -1;
89e5ed98
CMN
227}
228
4bef3565 229const char *git_remote_name(git_remote *remote)
9c82357b 230{
4bef3565 231 assert(remote);
9c82357b
CMN
232 return remote->name;
233}
234
4bef3565 235const char *git_remote_url(git_remote *remote)
9c82357b 236{
4bef3565 237 assert(remote);
9c82357b
CMN
238 return remote->url;
239}
240
bcb8c007
CMN
241int git_remote_set_fetchspec(git_remote *remote, const char *spec)
242{
bcb8c007
CMN
243 git_refspec refspec;
244
245 assert(remote && spec);
246
4376f7f6
CMN
247 if (refspec_parse(&refspec, spec) < 0)
248 return -1;
bcb8c007
CMN
249
250 git__free(remote->fetch.src);
251 git__free(remote->fetch.dst);
252 remote->fetch.src = refspec.src;
253 remote->fetch.dst = refspec.dst;
254
4376f7f6 255 return 0;
bcb8c007
CMN
256}
257
4bef3565 258const git_refspec *git_remote_fetchspec(git_remote *remote)
9c82357b 259{
4bef3565 260 assert(remote);
9c82357b
CMN
261 return &remote->fetch;
262}
263
bcb8c007
CMN
264int git_remote_set_pushspec(git_remote *remote, const char *spec)
265{
bcb8c007
CMN
266 git_refspec refspec;
267
268 assert(remote && spec);
269
4376f7f6
CMN
270 if (refspec_parse(&refspec, spec) < 0)
271 return -1;
bcb8c007
CMN
272
273 git__free(remote->push.src);
274 git__free(remote->push.dst);
275 remote->push.src = refspec.src;
276 remote->push.dst = refspec.dst;
277
4376f7f6 278 return 0;
bcb8c007
CMN
279}
280
4bef3565 281const git_refspec *git_remote_pushspec(git_remote *remote)
9c82357b 282{
4bef3565 283 assert(remote);
9c82357b
CMN
284 return &remote->push;
285}
286
0ac2726f 287int git_remote_connect(git_remote *remote, int direction)
9ba49bb5 288{
9ba49bb5
CMN
289 git_transport *t;
290
4bef3565
VM
291 assert(remote);
292
4376f7f6
CMN
293 if (git_transport_new(&t, remote->url) < 0)
294 return -1;
9ba49bb5 295
250b95b2 296 t->check_cert = remote->check_cert;
4376f7f6
CMN
297 if (t->connect(t, direction) < 0) {
298 goto on_error;
9ba49bb5
CMN
299 }
300
301 remote->transport = t;
302
4376f7f6 303 return 0;
9ba49bb5 304
4376f7f6
CMN
305on_error:
306 t->free(t);
307 return -1;
9ba49bb5
CMN
308}
309
d88d4311 310int git_remote_ls(git_remote *remote, git_headlist_cb list_cb, void *payload)
9ba49bb5 311{
d88d4311
VM
312 assert(remote);
313
4376f7f6
CMN
314 if (!remote->transport || !remote->transport->connected) {
315 giterr_set(GITERR_NET, "The remote is not connected");
316 return -1;
317 }
d88d4311
VM
318
319 return remote->transport->ls(remote->transport, list_cb, payload);
9ba49bb5
CMN
320}
321
7a520f5d 322int git_remote_download(git_remote *remote, git_off_t *bytes, git_indexer_stats *stats)
48a65a07 323{
95057b85
CMN
324 int error;
325
7a520f5d 326 assert(remote && bytes && stats);
4bef3565 327
95057b85 328 if ((error = git_fetch_negotiate(remote)) < 0)
4376f7f6 329 return error;
95057b85 330
7a520f5d 331 return git_fetch_download_pack(remote, bytes, stats);
48a65a07
CMN
332}
333
f184836b 334int git_remote_update_tips(git_remote *remote, int (*cb)(const char *refname, const git_oid *a, const git_oid *b))
441f57c2 335{
4376f7f6 336 int error = 0;
517bda19 337 unsigned int i = 0;
97769280 338 git_buf refname = GIT_BUF_INIT;
f184836b 339 git_oid old;
3f035860 340 git_vector *refs;
441f57c2
CMN
341 git_remote_head *head;
342 git_reference *ref;
3f035860 343 struct git_refspec *spec;
441f57c2 344
4bef3565
VM
345 assert(remote);
346
3f035860
VM
347 refs = &remote->refs;
348 spec = &remote->fetch;
349
d88d4311 350 if (refs->length == 0)
e172cf08 351 return 0;
517bda19
CMN
352
353 /* HEAD is only allowed to be the first in the list */
d88d4311 354 head = refs->contents[0];
517bda19 355 if (!strcmp(head->name, GIT_HEAD_FILE)) {
4376f7f6
CMN
356 if (git_reference_create_oid(&ref, remote->repo, GIT_FETCH_HEAD_FILE, &head->oid, 1) < 0)
357 return -1;
585a2eb7 358
4376f7f6 359 i = 1;
585a2eb7 360 git_reference_free(ref);
517bda19
CMN
361 }
362
d88d4311
VM
363 for (; i < refs->length; ++i) {
364 head = refs->contents[i];
517bda19 365
4376f7f6 366 if (git_refspec_transform_r(&refname, spec, head->name) < 0)
f184836b
CMN
367 goto on_error;
368
369 error = git_reference_name_to_oid(&old, remote->repo, refname.ptr);
904b67e6 370 if (error < 0 && error != GIT_ENOTFOUND)
f184836b
CMN
371 goto on_error;
372
904b67e6 373 if (error == GIT_ENOTFOUND)
f184836b
CMN
374 memset(&old, 0, GIT_OID_RAWSZ);
375
376 if (!git_oid_cmp(&old, &head->oid))
377 continue;
441f57c2 378
4376f7f6 379 if (git_reference_create_oid(&ref, remote->repo, refname.ptr, &head->oid, 1) < 0)
944d250f 380 goto on_error;
39157563
CMN
381
382 git_reference_free(ref);
f184836b
CMN
383
384 if (cb != NULL) {
385 if (cb(refname.ptr, &old, &head->oid) < 0)
386 goto on_error;
387 }
441f57c2
CMN
388 }
389
97769280 390 git_buf_free(&refname);
f184836b
CMN
391 return 0;
392
393on_error:
394 git_buf_free(&refname);
395 return -1;
97769280 396
441f57c2
CMN
397}
398
6ac3b707
CMN
399int git_remote_connected(git_remote *remote)
400{
4bef3565 401 assert(remote);
6ac3b707
CMN
402 return remote->transport == NULL ? 0 : remote->transport->connected;
403}
404
4cf01e9a
CMN
405void git_remote_disconnect(git_remote *remote)
406{
4bef3565
VM
407 assert(remote);
408
42ea35c0 409 if (remote->transport != NULL && remote->transport->connected)
4cf01e9a 410 remote->transport->close(remote->transport);
4cf01e9a
CMN
411}
412
9c82357b
CMN
413void git_remote_free(git_remote *remote)
414{
2aae2188
CMN
415 if (remote == NULL)
416 return;
417
42ea35c0
MS
418 if (remote->transport != NULL) {
419 git_remote_disconnect(remote);
420
421 remote->transport->free(remote->transport);
422 remote->transport = NULL;
423 }
424
425 git_vector_free(&remote->refs);
426
3286c408
VM
427 git__free(remote->fetch.src);
428 git__free(remote->fetch.dst);
429 git__free(remote->push.src);
430 git__free(remote->push.dst);
431 git__free(remote->url);
432 git__free(remote->name);
3286c408 433 git__free(remote);
9c82357b 434}
8171998f
CMN
435
436struct cb_data {
437 git_vector *list;
438 regex_t *preg;
439};
440
854eccbb 441static int remote_list_cb(const char *name, const char *value, void *data_)
8171998f
CMN
442{
443 struct cb_data *data = (struct cb_data *)data_;
444 size_t nmatch = 2;
445 regmatch_t pmatch[2];
854eccbb 446 GIT_UNUSED(value);
8171998f
CMN
447
448 if (!regexec(data->preg, name, nmatch, pmatch, 0)) {
449 char *remote_name = git__strndup(&name[pmatch[1].rm_so], pmatch[1].rm_eo - pmatch[1].rm_so);
4376f7f6 450 GITERR_CHECK_ALLOC(remote_name);
8171998f 451
4376f7f6
CMN
452 if (git_vector_insert(data->list, remote_name) < 0)
453 return -1;
8171998f
CMN
454 }
455
4376f7f6 456 return 0;
8171998f
CMN
457}
458
459int git_remote_list(git_strarray *remotes_list, git_repository *repo)
460{
461 git_config *cfg;
462 git_vector list;
463 regex_t preg;
464 struct cb_data data;
465 int error;
466
4376f7f6
CMN
467 if (git_repository_config__weakptr(&cfg, repo) < 0)
468 return -1;
8171998f 469
4376f7f6
CMN
470 if (git_vector_init(&list, 4, NULL) < 0)
471 return -1;
8171998f 472
4376f7f6
CMN
473 if (regcomp(&preg, "^remote\\.(.*)\\.url$", REG_EXTENDED) < 0) {
474 giterr_set(GITERR_OS, "Remote catch regex failed to compile");
475 return -1;
476 }
8171998f
CMN
477
478 data.list = &list;
479 data.preg = &preg;
480 error = git_config_foreach(cfg, remote_list_cb, &data);
481 regfree(&preg);
4376f7f6 482 if (error < 0) {
8171998f
CMN
483 size_t i;
484 char *elem;
485 git_vector_foreach(&list, i, elem) {
2bc8fa02 486 git__free(elem);
8171998f
CMN
487 }
488
489 git_vector_free(&list);
490 return error;
491 }
492
493 remotes_list->strings = (char **)list.contents;
494 remotes_list->count = list.length;
495
4376f7f6 496 return 0;
8171998f 497}
a209a025
CMN
498
499int git_remote_add(git_remote **out, git_repository *repo, const char *name, const char *url)
500{
501 git_buf buf = GIT_BUF_INIT;
a209a025 502
d27bf665 503 if (git_buf_printf(&buf, "+refs/heads/*:refs/remotes/%s/*", name) < 0)
baaa8a44 504 return -1;
a209a025 505
baaa8a44 506 if (git_remote_new(out, repo, name, url, git_buf_cstr(&buf)) < 0)
a209a025
CMN
507 goto on_error;
508
509 git_buf_free(&buf);
510
511 if (git_remote_save(*out) < 0)
baaa8a44 512 goto on_error;
a209a025
CMN
513
514 return 0;
515
516on_error:
517 git_buf_free(&buf);
518 git_remote_free(*out);
519 return -1;
520}
250b95b2
CMN
521
522void git_remote_check_cert(git_remote *remote, int check)
523{
524 assert(remote);
525
526 remote->check_cert = check;
527}