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