]>
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 | ||
9c82357b CMN |
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, ':'); | |
4376f7f6 CMN |
33 | if (delim == NULL) { |
34 | giterr_set(GITERR_NET, "Invalid refspec, missing ':'"); | |
35 | return -1; | |
36 | } | |
9c82357b CMN |
37 | |
38 | refspec->src = git__strndup(str, delim - str); | |
4376f7f6 | 39 | GITERR_CHECK_ALLOC(refspec->src); |
9c82357b CMN |
40 | |
41 | refspec->dst = git__strdup(delim + 1); | |
4376f7f6 | 42 | GITERR_CHECK_ALLOC(refspec->dst); |
9c82357b | 43 | |
4376f7f6 | 44 | return 0; |
9c82357b CMN |
45 | } |
46 | ||
47 | static int parse_remote_refspec(git_config *cfg, git_refspec *refspec, const char *var) | |
48 | { | |
9c82357b | 49 | int error; |
4376f7f6 | 50 | const char *val; |
9c82357b | 51 | |
29e948de | 52 | if ((error = git_config_get_string(&val, cfg, var)) < 0) |
9c82357b CMN |
53 | return error; |
54 | ||
2dc31040 | 55 | return refspec_parse(refspec, val); |
9c82357b CMN |
56 | } |
57 | ||
24f2f94e CMN |
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 | ||
baaa8a44 | 83 | int git_remote_new(git_remote **out, git_repository *repo, const char *name, const char *url, const char *fetch) |
778e1c73 CMN |
84 | { |
85 | git_remote *remote; | |
86 | ||
4bef3565 VM |
87 | /* name is optional */ |
88 | assert(out && repo && url); | |
617bfdf4 | 89 | |
778e1c73 | 90 | remote = git__malloc(sizeof(git_remote)); |
4376f7f6 | 91 | GITERR_CHECK_ALLOC(remote); |
778e1c73 CMN |
92 | |
93 | memset(remote, 0x0, sizeof(git_remote)); | |
94 | remote->repo = repo; | |
250b95b2 | 95 | remote->check_cert = 1; |
617bfdf4 | 96 | |
4376f7f6 CMN |
97 | if (git_vector_init(&remote->refs, 32, NULL) < 0) |
98 | return -1; | |
d88d4311 | 99 | |
778e1c73 | 100 | remote->url = git__strdup(url); |
4376f7f6 | 101 | GITERR_CHECK_ALLOC(remote->url); |
778e1c73 | 102 | |
617bfdf4 CMN |
103 | if (name != NULL) { |
104 | remote->name = git__strdup(name); | |
4376f7f6 | 105 | GITERR_CHECK_ALLOC(remote->name); |
617bfdf4 CMN |
106 | } |
107 | ||
baaa8a44 CMN |
108 | if (fetch != NULL) { |
109 | if (refspec_parse(&remote->fetch, fetch) < 0) | |
110 | goto on_error; | |
111 | } | |
112 | ||
778e1c73 | 113 | *out = remote; |
4376f7f6 | 114 | return 0; |
baaa8a44 CMN |
115 | |
116 | on_error: | |
117 | git_remote_free(remote); | |
118 | return -1; | |
778e1c73 CMN |
119 | } |
120 | ||
9462c471 | 121 | int git_remote_load(git_remote **out, git_repository *repo, const char *name) |
9c82357b CMN |
122 | { |
123 | git_remote *remote; | |
f0f3a18a | 124 | git_buf buf = GIT_BUF_INIT; |
9c82357b | 125 | const char *val; |
4376f7f6 | 126 | int error = 0; |
9462c471 | 127 | git_config *config; |
9c82357b | 128 | |
9462c471 VM |
129 | assert(out && repo && name); |
130 | ||
4376f7f6 CMN |
131 | if (git_repository_config__weakptr(&config, repo) < 0) |
132 | return -1; | |
4bef3565 | 133 | |
9c82357b | 134 | remote = git__malloc(sizeof(git_remote)); |
4376f7f6 | 135 | GITERR_CHECK_ALLOC(remote); |
9c82357b CMN |
136 | |
137 | memset(remote, 0x0, sizeof(git_remote)); | |
250b95b2 | 138 | remote->check_cert = 1; |
9c82357b | 139 | remote->name = git__strdup(name); |
4376f7f6 | 140 | GITERR_CHECK_ALLOC(remote->name); |
9c82357b | 141 | |
2fb9d6de | 142 | if (git_vector_init(&remote->refs, 32, NULL) < 0) { |
143 | error = -1; | |
144 | goto cleanup; | |
145 | } | |
d88d4311 | 146 | |
2fb9d6de | 147 | if (git_buf_printf(&buf, "remote.%s.url", name) < 0) { |
148 | error = -1; | |
149 | goto cleanup; | |
150 | } | |
9c82357b | 151 | |
29e948de | 152 | if ((error = git_config_get_string(&val, config, git_buf_cstr(&buf))) < 0) |
9c82357b | 153 | goto cleanup; |
9c82357b | 154 | |
9462c471 | 155 | remote->repo = repo; |
9c82357b | 156 | remote->url = git__strdup(val); |
4376f7f6 | 157 | GITERR_CHECK_ALLOC(remote->url); |
9c82357b | 158 | |
3ed4b501 SC |
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 | ||
f0f3a18a | 179 | git_buf_clear(&buf); |
2fb9d6de | 180 | if (git_buf_printf(&buf, "remote.%s.fetch", name) < 0) { |
181 | error = -1; | |
182 | goto cleanup; | |
183 | } | |
9c82357b | 184 | |
f0f3a18a | 185 | error = parse_remote_refspec(config, &remote->fetch, git_buf_cstr(&buf)); |
904b67e6 | 186 | if (error == GIT_ENOTFOUND) |
4376f7f6 | 187 | error = 0; |
9554cd51 | 188 | |
4376f7f6 CMN |
189 | if (error < 0) { |
190 | error = -1; | |
9c82357b | 191 | goto cleanup; |
2dc31040 | 192 | } |
9c82357b | 193 | |
f0f3a18a | 194 | git_buf_clear(&buf); |
2fb9d6de | 195 | if (git_buf_printf(&buf, "remote.%s.push", name) < 0) { |
196 | error = -1; | |
197 | goto cleanup; | |
198 | } | |
9c82357b | 199 | |
f0f3a18a | 200 | error = parse_remote_refspec(config, &remote->push, git_buf_cstr(&buf)); |
904b67e6 | 201 | if (error == GIT_ENOTFOUND) |
4376f7f6 | 202 | error = 0; |
9c82357b | 203 | |
4376f7f6 CMN |
204 | if (error < 0) { |
205 | error = -1; | |
9c82357b | 206 | goto cleanup; |
4376f7f6 | 207 | } |
9c82357b | 208 | |
24f2f94e CMN |
209 | if (download_tags_value(remote, config) < 0) |
210 | goto cleanup; | |
211 | ||
9c82357b CMN |
212 | *out = remote; |
213 | ||
214 | cleanup: | |
f0f3a18a | 215 | git_buf_free(&buf); |
9462c471 | 216 | |
4376f7f6 | 217 | if (error < 0) |
9c82357b CMN |
218 | git_remote_free(remote); |
219 | ||
220 | return error; | |
221 | } | |
222 | ||
89e5ed98 CMN |
223 | int git_remote_save(const git_remote *remote) |
224 | { | |
89e5ed98 CMN |
225 | git_config *config; |
226 | git_buf buf = GIT_BUF_INIT, value = GIT_BUF_INIT; | |
227 | ||
4376f7f6 CMN |
228 | if (git_repository_config__weakptr(&config, remote->repo) < 0) |
229 | return -1; | |
89e5ed98 | 230 | |
cb020f0d | 231 | if (git_buf_printf(&buf, "remote.%s.url", remote->name) < 0) |
4376f7f6 | 232 | return -1; |
89e5ed98 | 233 | |
4376f7f6 CMN |
234 | if (git_config_set_string(config, git_buf_cstr(&buf), remote->url) < 0) { |
235 | git_buf_free(&buf); | |
236 | return -1; | |
237 | } | |
89e5ed98 | 238 | |
413d5563 SC |
239 | git_buf_clear(&buf); |
240 | if (git_buf_printf(&buf, "remote.%s.pushurl", remote->name) < 0) | |
241 | return -1; | |
3ed4b501 | 242 | |
413d5563 | 243 | if (remote->pushurl) { |
3ed4b501 SC |
244 | if (git_config_set_string(config, git_buf_cstr(&buf), remote->pushurl) < 0) { |
245 | git_buf_free(&buf); | |
246 | return -1; | |
247 | } | |
413d5563 SC |
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 | } | |
3ed4b501 SC |
257 | } |
258 | ||
9c94a356 | 259 | if (remote->fetch.src != NULL && remote->fetch.dst != NULL) { |
89e5ed98 CMN |
260 | git_buf_clear(&buf); |
261 | git_buf_clear(&value); | |
4376f7f6 | 262 | git_buf_printf(&buf, "remote.%s.fetch", remote->name); |
d05e2c64 | 263 | if (remote->fetch.force) |
264 | git_buf_putc(&value, '+'); | |
89e5ed98 CMN |
265 | git_buf_printf(&value, "%s:%s", remote->fetch.src, remote->fetch.dst); |
266 | if (git_buf_oom(&buf) || git_buf_oom(&value)) | |
4376f7f6 | 267 | return -1; |
89e5ed98 | 268 | |
4376f7f6 CMN |
269 | if (git_config_set_string(config, git_buf_cstr(&buf), git_buf_cstr(&value)) < 0) |
270 | goto on_error; | |
89e5ed98 CMN |
271 | } |
272 | ||
9c94a356 | 273 | if (remote->push.src != NULL && remote->push.dst != NULL) { |
89e5ed98 CMN |
274 | git_buf_clear(&buf); |
275 | git_buf_clear(&value); | |
4376f7f6 | 276 | git_buf_printf(&buf, "remote.%s.push", remote->name); |
d05e2c64 | 277 | if (remote->push.force) |
278 | git_buf_putc(&value, '+'); | |
89e5ed98 CMN |
279 | git_buf_printf(&value, "%s:%s", remote->push.src, remote->push.dst); |
280 | if (git_buf_oom(&buf) || git_buf_oom(&value)) | |
4376f7f6 | 281 | return -1; |
89e5ed98 | 282 | |
4376f7f6 CMN |
283 | if (git_config_set_string(config, git_buf_cstr(&buf), git_buf_cstr(&value)) < 0) |
284 | goto on_error; | |
89e5ed98 CMN |
285 | } |
286 | ||
89e5ed98 CMN |
287 | git_buf_free(&buf); |
288 | git_buf_free(&value); | |
4376f7f6 CMN |
289 | |
290 | return 0; | |
291 | ||
292 | on_error: | |
293 | git_buf_free(&buf); | |
294 | git_buf_free(&value); | |
295 | return -1; | |
89e5ed98 CMN |
296 | } |
297 | ||
4bef3565 | 298 | const char *git_remote_name(git_remote *remote) |
9c82357b | 299 | { |
4bef3565 | 300 | assert(remote); |
9c82357b CMN |
301 | return remote->name; |
302 | } | |
303 | ||
4bef3565 | 304 | const char *git_remote_url(git_remote *remote) |
9c82357b | 305 | { |
4bef3565 | 306 | assert(remote); |
9c82357b CMN |
307 | return remote->url; |
308 | } | |
309 | ||
76501590 SC |
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 | ||
bcb8c007 CMN |
342 | int git_remote_set_fetchspec(git_remote *remote, const char *spec) |
343 | { | |
bcb8c007 CMN |
344 | git_refspec refspec; |
345 | ||
346 | assert(remote && spec); | |
347 | ||
4376f7f6 CMN |
348 | if (refspec_parse(&refspec, spec) < 0) |
349 | return -1; | |
bcb8c007 CMN |
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 | ||
4376f7f6 | 356 | return 0; |
bcb8c007 CMN |
357 | } |
358 | ||
4bef3565 | 359 | const git_refspec *git_remote_fetchspec(git_remote *remote) |
9c82357b | 360 | { |
4bef3565 | 361 | assert(remote); |
9c82357b CMN |
362 | return &remote->fetch; |
363 | } | |
364 | ||
bcb8c007 CMN |
365 | int git_remote_set_pushspec(git_remote *remote, const char *spec) |
366 | { | |
bcb8c007 CMN |
367 | git_refspec refspec; |
368 | ||
369 | assert(remote && spec); | |
370 | ||
4376f7f6 CMN |
371 | if (refspec_parse(&refspec, spec) < 0) |
372 | return -1; | |
bcb8c007 CMN |
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 | ||
4376f7f6 | 379 | return 0; |
bcb8c007 CMN |
380 | } |
381 | ||
4bef3565 | 382 | const git_refspec *git_remote_pushspec(git_remote *remote) |
9c82357b | 383 | { |
4bef3565 | 384 | assert(remote); |
9c82357b CMN |
385 | return &remote->push; |
386 | } | |
387 | ||
eff5b499 SC |
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 | ||
0ac2726f | 403 | int git_remote_connect(git_remote *remote, int direction) |
9ba49bb5 | 404 | { |
9ba49bb5 | 405 | git_transport *t; |
c0c39025 | 406 | const char *url; |
9ba49bb5 | 407 | |
4bef3565 VM |
408 | assert(remote); |
409 | ||
c0c39025 | 410 | url = git_remote__urlfordirection(remote, direction); |
eff5b499 SC |
411 | if (url == NULL ) |
412 | return -1; | |
413 | ||
414 | if (git_transport_new(&t, url) < 0) | |
4376f7f6 | 415 | return -1; |
9ba49bb5 | 416 | |
e03e71da CMN |
417 | t->progress_cb = remote->callbacks.progress; |
418 | t->cb_data = remote->callbacks.data; | |
419 | ||
250b95b2 | 420 | t->check_cert = remote->check_cert; |
4376f7f6 CMN |
421 | if (t->connect(t, direction) < 0) { |
422 | goto on_error; | |
9ba49bb5 CMN |
423 | } |
424 | ||
425 | remote->transport = t; | |
426 | ||
4376f7f6 | 427 | return 0; |
9ba49bb5 | 428 | |
4376f7f6 CMN |
429 | on_error: |
430 | t->free(t); | |
431 | return -1; | |
9ba49bb5 CMN |
432 | } |
433 | ||
d88d4311 | 434 | int git_remote_ls(git_remote *remote, git_headlist_cb list_cb, void *payload) |
9ba49bb5 | 435 | { |
ad4b5beb CMN |
436 | git_vector *refs = &remote->transport->refs; |
437 | unsigned int i; | |
438 | git_pkt *p = NULL; | |
439 | ||
d88d4311 VM |
440 | assert(remote); |
441 | ||
4376f7f6 CMN |
442 | if (!remote->transport || !remote->transport->connected) { |
443 | giterr_set(GITERR_NET, "The remote is not connected"); | |
444 | return -1; | |
445 | } | |
d88d4311 | 446 | |
ad4b5beb CMN |
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 | ||
e4607392 | 455 | if (list_cb(&pkt->head, payload)) |
d8d28e2e | 456 | return GIT_EUSER; |
ad4b5beb CMN |
457 | } |
458 | ||
459 | return 0; | |
9ba49bb5 CMN |
460 | } |
461 | ||
7a520f5d | 462 | int git_remote_download(git_remote *remote, git_off_t *bytes, git_indexer_stats *stats) |
48a65a07 | 463 | { |
95057b85 CMN |
464 | int error; |
465 | ||
7a520f5d | 466 | assert(remote && bytes && stats); |
4bef3565 | 467 | |
95057b85 | 468 | if ((error = git_fetch_negotiate(remote)) < 0) |
4376f7f6 | 469 | return error; |
95057b85 | 470 | |
7a520f5d | 471 | return git_fetch_download_pack(remote, bytes, stats); |
48a65a07 CMN |
472 | } |
473 | ||
b3aaa7a7 | 474 | int git_remote_update_tips(git_remote *remote) |
441f57c2 | 475 | { |
a37ddf7e | 476 | int error = 0, autotag; |
517bda19 | 477 | unsigned int i = 0; |
97769280 | 478 | git_buf refname = GIT_BUF_INIT; |
f184836b | 479 | git_oid old; |
a37ddf7e CMN |
480 | git_pkt *pkt; |
481 | git_odb *odb; | |
3f035860 | 482 | git_vector *refs; |
441f57c2 CMN |
483 | git_remote_head *head; |
484 | git_reference *ref; | |
3f035860 | 485 | struct git_refspec *spec; |
a37ddf7e CMN |
486 | char *tagstr = "refs/tags/*:refs/tags/*"; |
487 | git_refspec tagspec; | |
441f57c2 | 488 | |
4bef3565 VM |
489 | assert(remote); |
490 | ||
a37ddf7e | 491 | refs = &remote->transport->refs; |
3f035860 VM |
492 | spec = &remote->fetch; |
493 | ||
d88d4311 | 494 | if (refs->length == 0) |
e172cf08 | 495 | return 0; |
517bda19 | 496 | |
a37ddf7e CMN |
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 | ||
517bda19 | 503 | /* HEAD is only allowed to be the first in the list */ |
a37ddf7e CMN |
504 | pkt = refs->contents[0]; |
505 | head = &((git_pkt_ref *)pkt)->head; | |
517bda19 | 506 | if (!strcmp(head->name, GIT_HEAD_FILE)) { |
4376f7f6 CMN |
507 | if (git_reference_create_oid(&ref, remote->repo, GIT_FETCH_HEAD_FILE, &head->oid, 1) < 0) |
508 | return -1; | |
585a2eb7 | 509 | |
4376f7f6 | 510 | i = 1; |
585a2eb7 | 511 | git_reference_free(ref); |
517bda19 CMN |
512 | } |
513 | ||
d88d4311 | 514 | for (; i < refs->length; ++i) { |
a37ddf7e CMN |
515 | autotag = 0; |
516 | git_pkt *pkt = refs->contents[i]; | |
517bda19 | 517 | |
a37ddf7e CMN |
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; | |
f184836b CMN |
545 | |
546 | error = git_reference_name_to_oid(&old, remote->repo, refname.ptr); | |
904b67e6 | 547 | if (error < 0 && error != GIT_ENOTFOUND) |
f184836b CMN |
548 | goto on_error; |
549 | ||
904b67e6 | 550 | if (error == GIT_ENOTFOUND) |
f184836b CMN |
551 | memset(&old, 0, GIT_OID_RAWSZ); |
552 | ||
553 | if (!git_oid_cmp(&old, &head->oid)) | |
554 | continue; | |
441f57c2 | 555 | |
a37ddf7e CMN |
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) | |
944d250f | 559 | goto on_error; |
39157563 CMN |
560 | |
561 | git_reference_free(ref); | |
f184836b | 562 | |
b3aaa7a7 CMN |
563 | if (remote->callbacks.update_tips != NULL) { |
564 | if (remote->callbacks.update_tips(refname.ptr, &old, &head->oid, remote->callbacks.data) < 0) | |
f184836b CMN |
565 | goto on_error; |
566 | } | |
441f57c2 CMN |
567 | } |
568 | ||
a37ddf7e | 569 | git_refspec__free(&tagspec); |
97769280 | 570 | git_buf_free(&refname); |
f184836b CMN |
571 | return 0; |
572 | ||
573 | on_error: | |
a37ddf7e | 574 | git_refspec__free(&tagspec); |
f184836b CMN |
575 | git_buf_free(&refname); |
576 | return -1; | |
97769280 | 577 | |
441f57c2 CMN |
578 | } |
579 | ||
6ac3b707 CMN |
580 | int git_remote_connected(git_remote *remote) |
581 | { | |
4bef3565 | 582 | assert(remote); |
6ac3b707 CMN |
583 | return remote->transport == NULL ? 0 : remote->transport->connected; |
584 | } | |
585 | ||
4cf01e9a CMN |
586 | void git_remote_disconnect(git_remote *remote) |
587 | { | |
4bef3565 VM |
588 | assert(remote); |
589 | ||
42ea35c0 | 590 | if (remote->transport != NULL && remote->transport->connected) |
4cf01e9a | 591 | remote->transport->close(remote->transport); |
4cf01e9a CMN |
592 | } |
593 | ||
9c82357b CMN |
594 | void git_remote_free(git_remote *remote) |
595 | { | |
2aae2188 CMN |
596 | if (remote == NULL) |
597 | return; | |
598 | ||
42ea35c0 MS |
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 | ||
3665ba8e CMN |
608 | git_refspec__free(&remote->fetch); |
609 | git_refspec__free(&remote->push); | |
3286c408 | 610 | git__free(remote->url); |
3ed4b501 | 611 | git__free(remote->pushurl); |
3286c408 | 612 | git__free(remote->name); |
3286c408 | 613 | git__free(remote); |
9c82357b | 614 | } |
8171998f CMN |
615 | |
616 | struct cb_data { | |
617 | git_vector *list; | |
618 | regex_t *preg; | |
619 | }; | |
620 | ||
854eccbb | 621 | static int remote_list_cb(const char *name, const char *value, void *data_) |
8171998f CMN |
622 | { |
623 | struct cb_data *data = (struct cb_data *)data_; | |
624 | size_t nmatch = 2; | |
625 | regmatch_t pmatch[2]; | |
854eccbb | 626 | GIT_UNUSED(value); |
8171998f CMN |
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); | |
4376f7f6 | 630 | GITERR_CHECK_ALLOC(remote_name); |
8171998f | 631 | |
4376f7f6 CMN |
632 | if (git_vector_insert(data->list, remote_name) < 0) |
633 | return -1; | |
8171998f CMN |
634 | } |
635 | ||
4376f7f6 | 636 | return 0; |
8171998f CMN |
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 | ||
4376f7f6 CMN |
647 | if (git_repository_config__weakptr(&cfg, repo) < 0) |
648 | return -1; | |
8171998f | 649 | |
4376f7f6 CMN |
650 | if (git_vector_init(&list, 4, NULL) < 0) |
651 | return -1; | |
8171998f | 652 | |
4376f7f6 CMN |
653 | if (regcomp(&preg, "^remote\\.(.*)\\.url$", REG_EXTENDED) < 0) { |
654 | giterr_set(GITERR_OS, "Remote catch regex failed to compile"); | |
655 | return -1; | |
656 | } | |
8171998f CMN |
657 | |
658 | data.list = &list; | |
659 | data.preg = &preg; | |
660 | error = git_config_foreach(cfg, remote_list_cb, &data); | |
661 | regfree(&preg); | |
4376f7f6 | 662 | if (error < 0) { |
8171998f CMN |
663 | size_t i; |
664 | char *elem; | |
665 | git_vector_foreach(&list, i, elem) { | |
2bc8fa02 | 666 | git__free(elem); |
8171998f CMN |
667 | } |
668 | ||
669 | git_vector_free(&list); | |
e4607392 RB |
670 | |
671 | /* cb error is converted to GIT_EUSER by git_config_foreach */ | |
672 | if (error == GIT_EUSER) | |
673 | error = -1; | |
674 | ||
8171998f CMN |
675 | return error; |
676 | } | |
677 | ||
678 | remotes_list->strings = (char **)list.contents; | |
679 | remotes_list->count = list.length; | |
680 | ||
4376f7f6 | 681 | return 0; |
8171998f | 682 | } |
a209a025 CMN |
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; | |
a209a025 | 687 | |
d27bf665 | 688 | if (git_buf_printf(&buf, "+refs/heads/*:refs/remotes/%s/*", name) < 0) |
baaa8a44 | 689 | return -1; |
a209a025 | 690 | |
baaa8a44 | 691 | if (git_remote_new(out, repo, name, url, git_buf_cstr(&buf)) < 0) |
a209a025 CMN |
692 | goto on_error; |
693 | ||
694 | git_buf_free(&buf); | |
695 | ||
696 | if (git_remote_save(*out) < 0) | |
baaa8a44 | 697 | goto on_error; |
a209a025 CMN |
698 | |
699 | return 0; | |
700 | ||
701 | on_error: | |
702 | git_buf_free(&buf); | |
703 | git_remote_free(*out); | |
704 | return -1; | |
705 | } | |
250b95b2 CMN |
706 | |
707 | void git_remote_check_cert(git_remote *remote, int check) | |
708 | { | |
709 | assert(remote); | |
710 | ||
711 | remote->check_cert = check; | |
712 | } | |
b3aaa7a7 CMN |
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)); | |
e03e71da CMN |
719 | |
720 | if (remote->transport) { | |
721 | remote->transport->progress_cb = remote->callbacks.progress; | |
722 | remote->transport->cb_data = remote->callbacks.data; | |
723 | } | |
b3aaa7a7 | 724 | } |
f70e466f CMN |
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 | } |