Line Flow Count Block(s) Source
1 - /*
2 - * Copyright (C) the libgit2 contributors. All rights reserved.
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 "remote.h"
9 -
10 - #include "git2/config.h"
11 - #include "git2/types.h"
12 - #include "git2/oid.h"
13 - #include "git2/net.h"
14 -
15 - #include "config.h"
16 - #include "repository.h"
17 - #include "fetch.h"
18 - #include "refs.h"
19 - #include "refspec.h"
20 - #include "fetchhead.h"
21 - #include "push.h"
22 -
23 - #define CONFIG_URL_FMT "remote.%s.url"
24 - #define CONFIG_PUSHURL_FMT "remote.%s.pushurl"
25 - #define CONFIG_FETCH_FMT "remote.%s.fetch"
26 - #define CONFIG_PUSH_FMT "remote.%s.push"
27 - #define CONFIG_TAGOPT_FMT "remote.%s.tagopt"
28 -
29 - static int dwim_refspecs(git_vector *out, git_vector *refspecs, git_vector *refs);
30 - static int lookup_remote_prune_config(git_remote *remote, git_config *config, const char *name);
31 - char *apply_insteadof(git_config *config, const char *url, int direction);
32 -
33 399 2 static int add_refspec_to(git_vector *vector, const char *string, bool is_fetch)
34 - {
35 - git_refspec *spec;
36 -
37 399 2 spec = git__calloc(1, sizeof(git_refspec));
38 399 3,4 GIT_ERROR_CHECK_ALLOC(spec);
39 -
40 399 5,6 if (git_refspec__parse(spec, string, is_fetch) < 0) {
41 ##### 7 git__free(spec);
42 ##### 8 return -1;
43 - }
44 -
45 399 9 spec->push = !is_fetch;
46 399 9,10 if (git_vector_insert(vector, spec) < 0) {
47 ##### 11 git_refspec__dispose(spec);
48 ##### 12 git__free(spec);
49 ##### 13 return -1;
50 - }
51 -
52 399 14 return 0;
53 - }
54 -
55 380 2 static int add_refspec(git_remote *remote, const char *string, bool is_fetch)
56 - {
57 380 2 return add_refspec_to(&remote->refspecs, string, is_fetch);
58 - }
59 -
60 165 2 static int download_tags_value(git_remote *remote, git_config *cfg)
61 - {
62 - git_config_entry *ce;
63 165 2 git_buf buf = GIT_BUF_INIT;
64 - int error;
65 -
66 165 2,3 if (git_buf_printf(&buf, "remote.%s.tagopt", remote->name) < 0)
67 ##### 4 return -1;
68 -
69 165 5,6 error = git_config__lookup_entry(&ce, cfg, git_buf_cstr(&buf), false);
70 165 7 git_buf_dispose(&buf);
71 -
72 165 8-10 if (!error && ce && ce->value) {
73 ##### 11 if (!strcmp(ce->value, "--no-tags"))
74 ##### 12 remote->download_tags = GIT_REMOTE_DOWNLOAD_TAGS_NONE;
75 ##### 13 else if (!strcmp(ce->value, "--tags"))
76 ##### 14 remote->download_tags = GIT_REMOTE_DOWNLOAD_TAGS_ALL;
77 - }
78 -
79 165 15 git_config_entry_free(ce);
80 165 16 return error;
81 - }
82 -
83 870 2 static int ensure_remote_name_is_valid(const char *name)
84 - {
85 870 2 int error = 0;
86 -
87 870 2,3 if (!git_remote_is_valid_name(name)) {
88 17 4-7 git_error_set(
89 - GIT_ERROR_CONFIG,
90 - "'%s' is not a valid remote name.", name ? name : "(null)");
91 17 8 error = GIT_EINVALIDSPEC;
92 - }
93 -
94 870 9 return error;
95 - }
96 -
97 163 2 static int write_add_refspec(git_repository *repo, const char *name, const char *refspec, bool fetch)
98 - {
99 - git_config *cfg;
100 163 2 git_buf var = GIT_BUF_INIT;
101 - git_refspec spec;
102 - const char *fmt;
103 - int error;
104 -
105 163 2,3 if ((error = git_repository_config__weakptr(&cfg, repo)) < 0)
106 ##### 4 return error;
107 -
108 163 5-7 fmt = fetch ? CONFIG_FETCH_FMT : CONFIG_PUSH_FMT;
109 -
110 163 8,9 if ((error = ensure_remote_name_is_valid(name)) < 0)
111 ##### 10 return error;
112 -
113 163 11,12 if ((error = git_refspec__parse(&spec, refspec, fetch)) < 0) {
114 1 13,14 if (git_error_last()->klass != GIT_ERROR_NOMEMORY)
115 1 15 error = GIT_EINVALIDSPEC;
116 -
117 1 16 return error;
118 - }
119 -
120 162 17 git_refspec__dispose(&spec);
121 -
122 162 18,19 if ((error = git_buf_printf(&var, fmt, name)) < 0)
123 ##### 20 return error;
124 -
125 - /*
126 - * "$^" is a unmatcheable regexp: it will not match anything at all, so
127 - * all values will be considered new and we will not replace any
128 - * present value.
129 - */
130 162 21,22 if ((error = git_config_set_multivar(cfg, var.ptr, "$^", refspec)) < 0) {
131 ##### 23 goto cleanup;
132 - }
133 -
134 - cleanup:
135 162 24 git_buf_dispose(&var);
136 162 25 return 0;
137 - }
138 -
139 341 2 static int canonicalize_url(git_buf *out, const char *in)
140 - {
141 341 2,3 if (in == NULL || strlen(in) == 0) {
142 4 4 git_error_set(GIT_ERROR_INVALID, "cannot set empty URL");
143 4 5 return GIT_EINVALIDSPEC;
144 - }
145 -
146 - #ifdef GIT_WIN32
147 - /* Given a UNC path like \\server\path, we need to convert this
148 - * to //server/path for compatibility with core git.
149 - */
150 - if (in[0] == '\\' && in[1] == '\\' &&
151 - (git__isalpha(in[2]) || git__isdigit(in[2]))) {
152 - const char *c;
153 - for (c = in; *c; c++)
154 - git_buf_putc(out, *c == '\\' ? '/' : *c);
155 -
156 - return git_buf_oom(out) ? -1 : 0;
157 - }
158 - #endif
159 -
160 337 6 return git_buf_puts(out, in);
161 - }
162 -
163 164 2 static int default_fetchspec_for_name(git_buf *buf, const char *name)
164 - {
165 164 2,3 if (git_buf_printf(buf, "+refs/heads/*:refs/remotes/%s/*", name) < 0)
166 ##### 4 return -1;
167 -
168 164 5 return 0;
169 - }
170 -
171 172 2 static int ensure_remote_doesnot_exist(git_repository *repo, const char *name)
172 - {
173 - int error;
174 - git_remote *remote;
175 -
176 172 2 error = git_remote_lookup(&remote, repo, name);
177 -
178 172 3 if (error == GIT_ENOTFOUND)
179 168 4 return 0;
180 -
181 4 5 if (error < 0)
182 ##### 6 return error;
183 -
184 4 7 git_remote_free(remote);
185 -
186 4 8 git_error_set(GIT_ERROR_CONFIG, "remote '%s' already exists", name);
187 -
188 4 9 return GIT_EEXISTS;
189 - }
190 -
191 ##### 2 int git_remote_create_options_init(git_remote_create_options *opts, unsigned int version)
192 - {
193 ##### 2-4 GIT_INIT_STRUCTURE_FROM_TEMPLATE(
194 - opts, version, git_remote_create_options, GIT_REMOTE_CREATE_OPTIONS_INIT);
195 ##### 5 return 0;
196 - }
197 -
198 - #ifndef GIT_DEPRECATE_HARD
199 ##### 2 int git_remote_create_init_options(git_remote_create_options *opts, unsigned int version)
200 - {
201 ##### 2 return git_remote_create_options_init(opts, version);
202 - }
203 - #endif
204 -
205 199 2 int git_remote_create_with_opts(git_remote **out, const char *url, const git_remote_create_options *opts)
206 - {
207 199 2 git_remote *remote = NULL;
208 199 2 git_config *config_ro = NULL, *config_rw;
209 199 2 git_buf canonical_url = GIT_BUF_INIT;
210 199 2 git_buf var = GIT_BUF_INIT;
211 199 2 git_buf specbuf = GIT_BUF_INIT;
212 199 2 const git_remote_create_options dummy_opts = GIT_REMOTE_CREATE_OPTIONS_INIT;
213 199 2 int error = -1;
214 -
215 199 2-4 assert(out && url);
216 -
217 199 5 if (!opts) {
218 7 6 opts = &dummy_opts;
219 - }
220 -
221 199 7-9 GIT_ERROR_CHECK_VERSION(opts, GIT_REMOTE_CREATE_OPTIONS_VERSION, "git_remote_create_options");
222 -
223 199 10 if (opts->name != NULL) {
224 165 11,12 if ((error = ensure_remote_name_is_valid(opts->name)) < 0)
225 6 13 return error;
226 -
227 159 14-16 if (opts->repository &&
228 159 15 (error = ensure_remote_doesnot_exist(opts->repository, opts->name)) < 0)
229 2 17 return error;
230 - }
231 -
232 191 18 if (opts->repository) {
233 183 19,20 if ((error = git_repository_config_snapshot(&config_ro, opts->repository)) < 0)
234 ##### 21 goto on_error;
235 - }
236 -
237 191 22 remote = git__calloc(1, sizeof(git_remote));
238 191 23,24 GIT_ERROR_CHECK_ALLOC(remote);
239 -
240 191 25 remote->repo = opts->repository;
241 -
242 191 25-28 if ((error = git_vector_init(&remote->refs, 8, NULL)) < 0 ||
243 - (error = canonicalize_url(&canonical_url, url)) < 0)
244 - goto on_error;
245 -
246 188 29,30 if (opts->repository && !(opts->flags & GIT_REMOTE_CREATE_SKIP_INSTEADOF)) {
247 180 31,32 remote->url = apply_insteadof(config_ro, canonical_url.ptr, GIT_DIRECTION_FETCH);
248 - } else {
249 8 33,34 remote->url = git__strdup(canonical_url.ptr);
250 - }
251 188 35,36 GIT_ERROR_CHECK_ALLOC(remote->url);
252 -
253 188 37 if (opts->name != NULL) {
254 156 38 remote->name = git__strdup(opts->name);
255 156 39,40 GIT_ERROR_CHECK_ALLOC(remote->name);
256 -
257 156 41-43 if (opts->repository &&
258 156 42,44,45 ((error = git_buf_printf(&var, CONFIG_URL_FMT, opts->name)) < 0 ||
259 156 44,46,47 (error = git_repository_config__weakptr(&config_rw, opts->repository)) < 0 ||
260 156 46 (error = git_config_set_string(config_rw, var.ptr, canonical_url.ptr)) < 0))
261 - goto on_error;
262 - }
263 -
264 188 48,49 if (opts->fetchspec != NULL ||
265 180 49,50 (opts->name && !(opts->flags & GIT_REMOTE_CREATE_SKIP_DEFAULT_FETCHSPEC))) {
266 152 51 const char *fetch = NULL;
267 152 51 if (opts->fetchspec) {
268 8 52 fetch = opts->fetchspec;
269 - } else {
270 144 53,54 if ((error = default_fetchspec_for_name(&specbuf, opts->name)) < 0)
271 ##### 55 goto on_error;
272 -
273 144 56 fetch = git_buf_cstr(&specbuf);
274 - }
275 -
276 152 57,58 if ((error = add_refspec(remote, fetch, true)) < 0)
277 ##### 59 goto on_error;
278 -
279 - /* only write for named remotes with a repository */
280 152 60-63 if (opts->repository && opts->name &&
281 152 62,64,65 ((error = write_add_refspec(opts->repository, opts->name, fetch, true)) < 0 ||
282 152 64 (error = lookup_remote_prune_config(remote, config_ro, opts->name)) < 0))
283 - goto on_error;
284 -
285 - /* Move the data over to where the matching functions can find them */
286 152 66,67 if ((error = dwim_refspecs(&remote->active_refspecs, &remote->refspecs, &remote->refs)) < 0)
287 ##### 68 goto on_error;
288 - }
289 -
290 - /* A remote without a name doesn't download tags */
291 188 69 if (!opts->name)
292 32 70 remote->download_tags = GIT_REMOTE_DOWNLOAD_TAGS_NONE;
293 - else
294 156 71 remote->download_tags = GIT_REMOTE_DOWNLOAD_TAGS_AUTO;
295 -
296 -
297 188 72 git_buf_dispose(&var);
298 -
299 188 73 *out = remote;
300 188 73 error = 0;
301 -
302 - on_error:
303 191 74 if (error)
304 3 75 git_remote_free(remote);
305 -
306 191 76 git_config_free(config_ro);
307 191 77 git_buf_dispose(&specbuf);
308 191 78 git_buf_dispose(&canonical_url);
309 191 79 git_buf_dispose(&var);
310 191 80 return error;
311 - }
312 -
313 152 2 int git_remote_create(git_remote **out, git_repository *repo, const char *name, const char *url)
314 - {
315 152 2 git_buf buf = GIT_BUF_INIT;
316 - int error;
317 152 2 git_remote_create_options opts = GIT_REMOTE_CREATE_OPTIONS_INIT;
318 -
319 - /* Those 2 tests are duplicated here because of backward-compatibility */
320 152 2,3 if ((error = ensure_remote_name_is_valid(name)) < 0)
321 7 4 return error;
322 -
323 145 5,6 if (canonicalize_url(&buf, url) < 0)
324 1 7 return GIT_ERROR;
325 -
326 144 8 git_buf_clear(&buf);
327 -
328 144 9 opts.repository = repo;
329 144 9 opts.name = name;
330 -
331 144 9 error = git_remote_create_with_opts(out, url, &opts);
332 -
333 144 10 git_buf_dispose(&buf);
334 -
335 144 11 return error;
336 - }
337 -
338 12 2 int git_remote_create_with_fetchspec(git_remote **out, git_repository *repo, const char *name, const char *url, const char *fetch)
339 - {
340 - int error;
341 12 2 git_remote_create_options opts = GIT_REMOTE_CREATE_OPTIONS_INIT;
342 -
343 12 2,3 if ((error = ensure_remote_name_is_valid(name)) < 0)
344 2 4 return error;
345 -
346 10 5 opts.repository = repo;
347 10 5 opts.name = name;
348 10 5 opts.fetchspec = fetch;
349 10 5 opts.flags = GIT_REMOTE_CREATE_SKIP_DEFAULT_FETCHSPEC;
350 -
351 10 5 return git_remote_create_with_opts(out, url, &opts);
352 - }
353 -
354 24 2 int git_remote_create_anonymous(git_remote **out, git_repository *repo, const char *url)
355 - {
356 24 2 git_remote_create_options opts = GIT_REMOTE_CREATE_OPTIONS_INIT;
357 -
358 24 2 opts.repository = repo;
359 -
360 24 2 return git_remote_create_with_opts(out, url, &opts);
361 - }
362 -
363 6 2 int git_remote_create_detached(git_remote **out, const char *url)
364 - {
365 6 2 return git_remote_create_with_opts(out, url, NULL);
366 - }
367 -
368 65 2 int git_remote_dup(git_remote **dest, git_remote *source)
369 - {
370 - size_t i;
371 65 2 int error = 0;
372 - git_refspec *spec;
373 65 2 git_remote *remote = git__calloc(1, sizeof(git_remote));
374 65 3,4 GIT_ERROR_CHECK_ALLOC(remote);
375 -
376 65 5 if (source->name != NULL) {
377 65 6 remote->name = git__strdup(source->name);
378 65 7,8 GIT_ERROR_CHECK_ALLOC(remote->name);
379 - }
380 -
381 65 9 if (source->url != NULL) {
382 65 10 remote->url = git__strdup(source->url);
383 65 11,12 GIT_ERROR_CHECK_ALLOC(remote->url);
384 - }
385 -
386 65 13 if (source->pushurl != NULL) {
387 ##### 14 remote->pushurl = git__strdup(source->pushurl);
388 ##### 15,16 GIT_ERROR_CHECK_ALLOC(remote->pushurl);
389 - }
390 -
391 65 17 remote->repo = source->repo;
392 65 17 remote->download_tags = source->download_tags;
393 65 17 remote->prune_refs = source->prune_refs;
394 -
395 65 17,18,20 if (git_vector_init(&remote->refs, 32, NULL) < 0 ||
396 65 19,22 git_vector_init(&remote->refspecs, 2, NULL) < 0 ||
397 65 21 git_vector_init(&remote->active_refspecs, 2, NULL) < 0) {
398 ##### 23 error = -1;
399 ##### 23 goto cleanup;
400 - }
401 -
402 130 24,28-30 git_vector_foreach(&source->refspecs, i, spec) {
403 65 25,26 if ((error = add_refspec(remote, spec->string, !spec->push)) < 0)
404 ##### 27 goto cleanup;
405 - }
406 -
407 65 31 *dest = remote;
408 -
409 - cleanup:
410 -
411 65 32 if (error < 0)
412 ##### 33 git__free(remote);
413 -
414 65 34 return error;
415 - }
416 -
417 - struct refspec_cb_data {
418 - git_remote *remote;
419 - int fetch;
420 - };
421 -
422 163 2 static int refspec_cb(const git_config_entry *entry, void *payload)
423 - {
424 163 2 struct refspec_cb_data *data = (struct refspec_cb_data *)payload;
425 163 2 return add_refspec(data->remote, entry->value, data->fetch);
426 - }
427 -
428 1038 2 static int get_optional_config(
429 - bool *found, git_config *config, git_buf *buf,
430 - git_config_foreach_cb cb, void *payload)
431 - {
432 1038 2 int error = 0;
433 1038 2 const char *key = git_buf_cstr(buf);
434 -
435 1038 3,4 if (git_buf_oom(buf))
436 ##### 5 return -1;
437 -
438 1038 6 if (cb != NULL)
439 330 7 error = git_config_get_multivar_foreach(config, key, NULL, cb, payload);
440 - else
441 708 8 error = git_config_get_string(payload, config, key);
442 -
443 1038 9 if (found)
444 708 10 *found = !error;
445 -
446 1038 11 if (error == GIT_ENOTFOUND) {
447 704 12 git_error_clear();
448 704 13 error = 0;
449 - }
450 -
451 1038 14 return error;
452 - }
453 -
454 355 2 int git_remote_lookup(git_remote **out, git_repository *repo, const char *name)
455 - {
456 355 2 git_remote *remote = NULL;
457 355 2 git_buf buf = GIT_BUF_INIT;
458 - const char *val;
459 355 2 int error = 0;
460 - git_config *config;
461 355 2 struct refspec_cb_data data = { NULL };
462 355 2 bool optional_setting_found = false, found;
463 -
464 355 2-5 assert(out && repo && name);
465 -
466 355 6,7 if ((error = ensure_remote_name_is_valid(name)) < 0)
467 1 8 return error;
468 -
469 354 9,10 if ((error = git_repository_config_snapshot(&config, repo)) < 0)
470 ##### 11 return error;
471 -
472 354 12 remote = git__calloc(1, sizeof(git_remote));
473 354 13,14 GIT_ERROR_CHECK_ALLOC(remote);
474 -
475 354 15 remote->name = git__strdup(name);
476 354 16,17 GIT_ERROR_CHECK_ALLOC(remote->name);
477 -
478 354 18,19,21 if (git_vector_init(&remote->refs, 32, NULL) < 0 ||
479 354 20,23 git_vector_init(&remote->refspecs, 2, NULL) < 0 ||
480 354 22,25 git_vector_init(&remote->passive_refspecs, 2, NULL) < 0 ||
481 354 24 git_vector_init(&remote->active_refspecs, 2, NULL) < 0) {
482 ##### 26 error = -1;
483 ##### 26 goto cleanup;
484 - }
485 -
486 354 27,28 if ((error = git_buf_printf(&buf, "remote.%s.url", name)) < 0)
487 ##### 29 goto cleanup;
488 -
489 354 30,31 if ((error = get_optional_config(&found, config, &buf, NULL, (void *)&val)) < 0)
490 ##### 32 goto cleanup;
491 -
492 354 33 optional_setting_found |= found;
493 -
494 354 33 remote->repo = repo;
495 354 33 remote->download_tags = GIT_REMOTE_DOWNLOAD_TAGS_AUTO;
496 -
497 354 33,34 if (found && strlen(val) > 0) {
498 159 35 remote->url = apply_insteadof(config, val, GIT_DIRECTION_FETCH);
499 159 36,37 GIT_ERROR_CHECK_ALLOC(remote->url);
500 - }
501 -
502 354 38 val = NULL;
503 354 38 git_buf_clear(&buf);
504 354 39 git_buf_printf(&buf, "remote.%s.pushurl", name);
505 -
506 354 40,41 if ((error = get_optional_config(&found, config, &buf, NULL, (void *)&val)) < 0)
507 ##### 42 goto cleanup;
508 -
509 354 43 optional_setting_found |= found;
510 -
511 354 43 if (!optional_setting_found) {
512 189 44 error = GIT_ENOTFOUND;
513 189 44 git_error_set(GIT_ERROR_CONFIG, "remote '%s' does not exist", name);
514 189 45 goto cleanup;
515 - }
516 -
517 165 46,47 if (found && strlen(val) > 0) {
518 12 48 remote->pushurl = apply_insteadof(config, val, GIT_DIRECTION_PUSH);
519 12 49,50 GIT_ERROR_CHECK_ALLOC(remote->pushurl);
520 - }
521 -
522 165 51 data.remote = remote;
523 165 51 data.fetch = true;
524 -
525 165 51 git_buf_clear(&buf);
526 165 52 git_buf_printf(&buf, "remote.%s.fetch", name);
527 -
528 165 53,54 if ((error = get_optional_config(NULL, config, &buf, refspec_cb, &data)) < 0)
529 ##### 55 goto cleanup;
530 -
531 165 56 data.fetch = false;
532 165 56 git_buf_clear(&buf);
533 165 57 git_buf_printf(&buf, "remote.%s.push", name);
534 -
535 165 58,59 if ((error = get_optional_config(NULL, config, &buf, refspec_cb, &data)) < 0)
536 ##### 60 goto cleanup;
537 -
538 165 61,62 if ((error = download_tags_value(remote, config)) < 0)
539 ##### 63 goto cleanup;
540 -
541 165 64,65 if ((error = lookup_remote_prune_config(remote, config, name)) < 0)
542 ##### 66 goto cleanup;
543 -
544 - /* Move the data over to where the matching functions can find them */
545 165 67,68 if ((error = dwim_refspecs(&remote->active_refspecs, &remote->refspecs, &remote->refs)) < 0)
546 ##### 69 goto cleanup;
547 -
548 165 70 *out = remote;
549 -
550 - cleanup:
551 354 71 git_config_free(config);
552 354 72 git_buf_dispose(&buf);
553 -
554 354 73 if (error < 0)
555 189 74 git_remote_free(remote);
556 -
557 354 75 return error;
558 - }
559 -
560 317 2 static int lookup_remote_prune_config(git_remote *remote, git_config *config, const char *name)
561 - {
562 317 2 git_buf buf = GIT_BUF_INIT;
563 317 2 int error = 0;
564 -
565 317 2 git_buf_printf(&buf, "remote.%s.prune", name);
566 -
567 317 3-5 if ((error = git_config_get_bool(&remote->prune_refs, config, git_buf_cstr(&buf))) < 0) {
568 311 6 if (error == GIT_ENOTFOUND) {
569 311 7 git_error_clear();
570 -
571 311 8,9 if ((error = git_config_get_bool(&remote->prune_refs, config, "fetch.prune")) < 0) {
572 310 10 if (error == GIT_ENOTFOUND) {
573 310 11 git_error_clear();
574 310 12 error = 0;
575 - }
576 - }
577 - }
578 - }
579 -
580 317 13 git_buf_dispose(&buf);
581 317 14 return error;
582 - }
583 -
584 88 2 const char *git_remote_name(const git_remote *remote)
585 - {
586 88 2,3 assert(remote);
587 88 4 return remote->name;
588 - }
589 -
590 68 2 git_repository *git_remote_owner(const git_remote *remote)
591 - {
592 68 2,3 assert(remote);
593 68 4 return remote->repo;
594 - }
595 -
596 879 2 const char *git_remote_url(const git_remote *remote)
597 - {
598 879 2,3 assert(remote);
599 879 4 return remote->url;
600 - }
601 -
602 6 2 static int set_url(git_repository *repo, const char *remote, const char *pattern, const char *url)
603 - {
604 - git_config *cfg;
605 6 2 git_buf buf = GIT_BUF_INIT, canonical_url = GIT_BUF_INIT;
606 - int error;
607 -
608 6 2-4 assert(repo && remote);
609 -
610 6 5,6 if ((error = ensure_remote_name_is_valid(remote)) < 0)
611 ##### 7 return error;
612 -
613 6 8,9 if ((error = git_repository_config__weakptr(&cfg, repo)) < 0)
614 ##### 10 return error;
615 -
616 6 11,12 if ((error = git_buf_printf(&buf, pattern, remote)) < 0)
617 ##### 13 return error;
618 -
619 6 14 if (url) {
620 5 15,16 if ((error = canonicalize_url(&canonical_url, url)) < 0)
621 ##### 17 goto cleanup;
622 -
623 5 18 error = git_config_set_string(cfg, buf.ptr, url);
624 - } else {
625 1 19 error = git_config_delete_entry(cfg, buf.ptr);
626 - }
627 -
628 - cleanup:
629 6 20 git_buf_dispose(&canonical_url);
630 6 21 git_buf_dispose(&buf);
631 -
632 6 22 return error;
633 - }
634 -
635 4 2 int git_remote_set_url(git_repository *repo, const char *remote, const char *url)
636 - {
637 4 2 return set_url(repo, remote, CONFIG_URL_FMT, url);
638 - }
639 -
640 12 2 const char *git_remote_pushurl(const git_remote *remote)
641 - {
642 12 2,3 assert(remote);
643 12 4 return remote->pushurl;
644 - }
645 -
646 2 2 int git_remote_set_pushurl(git_repository *repo, const char *remote, const char* url)
647 - {
648 2 2 return set_url(repo, remote, CONFIG_PUSHURL_FMT, url);
649 - }
650 -
651 187 2 static int resolve_url(git_buf *resolved_url, const char *url, int direction, const git_remote_callbacks *callbacks)
652 - {
653 - int status;
654 -
655 187 2,3 if (callbacks && callbacks->resolve_url) {
656 4 4 git_buf_clear(resolved_url);
657 4 5 status = callbacks->resolve_url(resolved_url, url, direction, callbacks->payload);
658 4 6 if (status != GIT_PASSTHROUGH) {
659 2 7 git_error_set_after_callback_function(status, "git_resolve_url_cb");
660 2 8 git_buf_sanitize(resolved_url);
661 2 9 return status;
662 - }
663 - }
664 -
665 185 10 return git_buf_sets(resolved_url, url);
666 - }
667 -
668 189 2 int git_remote__urlfordirection(git_buf *url_out, struct git_remote *remote, int direction, const git_remote_callbacks *callbacks)
669 - {
670 189 2 const char *url = NULL;
671 -
672 189 2,3 assert(remote);
673 189 4-6 assert(direction == GIT_DIRECTION_FETCH || direction == GIT_DIRECTION_PUSH);
674 -
675 189 7 if (direction == GIT_DIRECTION_FETCH) {
676 176 8 url = remote->url;
677 13 9 } else if (direction == GIT_DIRECTION_PUSH) {
678 13 10-13 url = remote->pushurl ? remote->pushurl : remote->url;
679 - }
680 -
681 189 14 if (!url) {
682 2 15-21 git_error_set(GIT_ERROR_INVALID,
683 - "malformed remote '%s' - missing %s URL",
684 2 18 remote->name ? remote->name : "(anonymous)",
685 - direction == GIT_DIRECTION_FETCH ? "fetch" : "push");
686 2 22 return GIT_EINVALID;
687 - }
688 187 23 return resolve_url(url_out, url, direction, callbacks);
689 - }
690 -
691 170 2 static int remote_transport_set_callbacks(git_transport *t, const git_remote_callbacks *cbs)
692 - {
693 170 2,3 if (!t->set_callbacks || !cbs)
694 53 4 return 0;
695 -
696 117 5 return t->set_callbacks(t, cbs->sideband_progress, NULL,
697 - cbs->certificate_check, cbs->payload);
698 - }
699 -
700 174 2 static int set_transport_custom_headers(git_transport *t, const git_strarray *custom_headers)
701 - {
702 174 2 if (!t->set_custom_headers)
703 101 3 return 0;
704 -
705 73 4 return t->set_custom_headers(t, custom_headers);
706 - }
707 -
708 181 2 int git_remote__connect(git_remote *remote, git_direction direction, const git_remote_callbacks *callbacks, const git_remote_connection_opts *conn)
709 - {
710 - git_transport *t;
711 181 2 git_buf url = GIT_BUF_INIT;
712 181 2 int flags = GIT_TRANSPORTFLAGS_NONE;
713 - int error;
714 181 2 void *payload = NULL;
715 181 2 git_credential_acquire_cb credentials = NULL;
716 181 2 git_transport_cb transport = NULL;
717 -
718 181 2,3 assert(remote);
719 -
720 181 4 if (callbacks) {
721 126 5-7 GIT_ERROR_CHECK_VERSION(callbacks, GIT_REMOTE_CALLBACKS_VERSION, "git_remote_callbacks");
722 126 8 credentials = callbacks->credentials;
723 126 8 transport = callbacks->transport;
724 126 8 payload = callbacks->payload;
725 - }
726 -
727 181 9 if (conn->proxy)
728 125 10-12 GIT_ERROR_CHECK_VERSION(conn->proxy, GIT_PROXY_OPTIONS_VERSION, "git_proxy_options");
729 -
730 181 13 t = remote->transport;
731 -
732 181 13,14 if ((error = git_remote__urlfordirection(&url, remote, direction, callbacks)) < 0)
733 2 15 goto on_error;
734 -
735 - /* If we don't have a transport object yet, and the caller specified a
736 - * custom transport factory, use that */
737 179 16-19 if (!t && transport &&
738 - (error = transport(&t, remote, payload)) < 0)
739 ##### 20 goto on_error;
740 -
741 - /* If we still don't have a transport, then use the global
742 - * transport registrations which map URI schemes to transport factories */
743 179 21-23 if (!t && (error = git_transport_new(&t, remote, url.ptr)) < 0)
744 5 24 goto on_error;
745 -
746 174 25,26 if ((error = set_transport_custom_headers(t, conn->custom_headers)) != 0)
747 4 27 goto on_error;
748 -
749 170 28-31 if ((error = remote_transport_set_callbacks(t, callbacks)) < 0 ||
750 170 30 (error = t->connect(t, url.ptr, credentials, payload, conn->proxy, direction, flags)) != 0)
751 - goto on_error;
752 -
753 156 32 remote->transport = t;
754 -
755 156 32 git_buf_dispose(&url);
756 -
757 156 33 return 0;
758 -
759 - on_error:
760 25 34 if (t)
761 18 35 t->free(t);
762 -
763 25 36 git_buf_dispose(&url);
764 -
765 25 37 if (t == remote->transport)
766 7 38 remote->transport = NULL;
767 -
768 25 39 return error;
769 - }
770 -
771 40 2 int git_remote_connect(git_remote *remote, git_direction direction, const git_remote_callbacks *callbacks, const git_proxy_options *proxy, const git_strarray *custom_headers)
772 - {
773 - git_remote_connection_opts conn;
774 -
775 40 2 conn.proxy = proxy;
776 40 2 conn.custom_headers = custom_headers;
777 -
778 40 2 return git_remote__connect(remote, direction, callbacks, &conn);
779 - }
780 -
781 510 2 int git_remote_ls(const git_remote_head ***out, size_t *size, git_remote *remote)
782 - {
783 510 2,3 assert(remote);
784 -
785 510 4 if (!remote->transport) {
786 1 5 git_error_set(GIT_ERROR_NET, "this remote has never connected");
787 1 6 return -1;
788 - }
789 -
790 509 7 return remote->transport->ls(out, size, remote->transport);
791 - }
792 -
793 6 2 int git_remote__get_http_proxy(git_remote *remote, bool use_ssl, char **proxy_url)
794 - {
795 - git_config *cfg;
796 6 2 git_config_entry *ce = NULL;
797 6 2 git_buf val = GIT_BUF_INIT;
798 - int error;
799 -
800 6 2,3 assert(remote);
801 -
802 6 4,5 if (!proxy_url || !remote->repo)
803 ##### 6 return -1;
804 -
805 6 7 *proxy_url = NULL;
806 -
807 6 7,8 if ((error = git_repository_config__weakptr(&cfg, remote->repo)) < 0)
808 ##### 9 return error;
809 -
810 - /* Go through the possible sources for proxy configuration, from most specific
811 - * to least specific. */
812 -
813 - /* remote.<name>.proxy config setting */
814 6 10,11 if (remote->name && remote->name[0]) {
815 6 12 git_buf buf = GIT_BUF_INIT;
816 -
817 6 12,13 if ((error = git_buf_printf(&buf, "remote.%s.proxy", remote->name)) < 0)
818 ##### 14,25 return error;
819 -
820 6 15,16 error = git_config__lookup_entry(&ce, cfg, git_buf_cstr(&buf), false);
821 6 17 git_buf_dispose(&buf);
822 -
823 6 18 if (error < 0)
824 ##### 19 return error;
825 -
826 6 20,21 if (ce && ce->value) {
827 ##### 22 *proxy_url = git__strdup(ce->value);
828 6 23,24 goto found;
829 - }
830 - }
831 -
832 - /* http.proxy config setting */
833 6 26,27 if ((error = git_config__lookup_entry(&ce, cfg, "http.proxy", false)) < 0)
834 ##### 28 return error;
835 -
836 6 29,30 if (ce && ce->value) {
837 ##### 31 *proxy_url = git__strdup(ce->value);
838 ##### 32 goto found;
839 - }
840 -
841 - /* http_proxy / https_proxy environment variables */
842 6 33-36 error = git__getenv(&val, use_ssl ? "https_proxy" : "http_proxy");
843 -
844 - /* try uppercase environment variables */
845 6 37 if (error == GIT_ENOTFOUND)
846 6 38-41 error = git__getenv(&val, use_ssl ? "HTTPS_PROXY" : "HTTP_PROXY");
847 -
848 6 42 if (error < 0) {
849 6 43 if (error == GIT_ENOTFOUND) {
850 6 44 git_error_clear();
851 6 45 error = 0;
852 - }
853 -
854 6 46 return error;
855 - }
856 -
857 ##### 47,48 *proxy_url = git_buf_detach(&val);
858 -
859 - found:
860 ##### 49,50 GIT_ERROR_CHECK_ALLOC(*proxy_url);
861 ##### 51 git_config_entry_free(ce);
862 -
863 ##### 52 return 0;
864 - }
865 -
866 - /* DWIM `refspecs` based on `refs` and append the output to `out` */
867 570 2 static int dwim_refspecs(git_vector *out, git_vector *refspecs, git_vector *refs)
868 - {
869 - size_t i;
870 - git_refspec *spec;
871 -
872 1132 2,6-8 git_vector_foreach(refspecs, i, spec) {
873 562 3,4 if (git_refspec__dwim_one(out, spec, refs) < 0)
874 ##### 5 return -1;
875 - }
876 -
877 570 9 return 0;
878 - }
879 -
880 2205 2 static void free_refspecs(git_vector *vec)
881 - {
882 - size_t i;
883 - git_refspec *spec;
884 -
885 3168 2,5-7 git_vector_foreach(vec, i, spec) {
886 963 3 git_refspec__dispose(spec);
887 963 4 git__free(spec);
888 - }
889 -
890 2205 8 git_vector_clear(vec);
891 2205 9 }
892 -
893 729 2 static int remote_head_cmp(const void *_a, const void *_b)
894 - {
895 729 2 const git_remote_head *a = (git_remote_head *) _a;
896 729 2 const git_remote_head *b = (git_remote_head *) _b;
897 -
898 729 2 return git__strcmp_cb(a->name, b->name);
899 - }
900 -
901 247 2 static int ls_to_vector(git_vector *out, git_remote *remote)
902 - {
903 - git_remote_head **heads;
904 - size_t heads_len, i;
905 -
906 247 2,3 if (git_remote_ls((const git_remote_head ***)&heads, &heads_len, remote) < 0)
907 ##### 4 return -1;
908 -
909 247 5,6 if (git_vector_init(out, heads_len, remote_head_cmp) < 0)
910 ##### 7 return -1;
911 -
912 4981 8,12,13 for (i = 0; i < heads_len; i++) {
913 4734 9,10 if (git_vector_insert(out, heads[i]) < 0)
914 ##### 11 return -1;
915 - }
916 -
917 247 14 return 0;
918 - }
919 -
920 123 2 int git_remote_download(git_remote *remote, const git_strarray *refspecs, const git_fetch_options *opts)
921 - {
922 123 2 int error = -1;
923 - size_t i;
924 123 2 git_vector *to_active, specs = GIT_VECTOR_INIT, refs = GIT_VECTOR_INIT;
925 123 2 const git_remote_callbacks *cbs = NULL;
926 123 2 const git_strarray *custom_headers = NULL;
927 123 2 const git_proxy_options *proxy = NULL;
928 -
929 123 2,3 assert(remote);
930 -
931 123 4 if (!remote->repo) {
932 1 5 git_error_set(GIT_ERROR_INVALID, "cannot download detached remote");
933 1 6 return -1;
934 - }
935 -
936 122 7 if (opts) {
937 102 8-10 GIT_ERROR_CHECK_VERSION(&opts->callbacks, GIT_REMOTE_CALLBACKS_VERSION, "git_remote_callbacks");
938 102 11 cbs = &opts->callbacks;
939 102 11 custom_headers = &opts->custom_headers;
940 102 11-13 GIT_ERROR_CHECK_VERSION(&opts->proxy_opts, GIT_PROXY_OPTIONS_VERSION, "git_proxy_options");
941 102 14 proxy = &opts->proxy_opts;
942 - }
943 -
944 122 15-18 if (!git_remote_connected(remote) &&
945 - (error = git_remote_connect(remote, GIT_DIRECTION_FETCH, cbs, proxy, custom_headers)) < 0)
946 ##### 19 goto on_error;
947 -
948 122 20,21 if (ls_to_vector(&refs, remote) < 0)
949 ##### 22 return -1;
950 -
951 122 23,24 if ((git_vector_init(&specs, 0, NULL)) < 0)
952 ##### 25 goto on_error;
953 -
954 122 26 remote->passed_refspecs = 0;
955 122 26,27 if (!refspecs || !refspecs->count) {
956 106 28 to_active = &remote->refspecs;
957 - } else {
958 35 29,33,34 for (i = 0; i < refspecs->count; i++) {
959 19 30,31 if ((error = add_refspec_to(&specs, refspecs->strings[i], true)) < 0)
960 ##### 32 goto on_error;
961 - }
962 -
963 16 35 to_active = &specs;
964 16 35 remote->passed_refspecs = 1;
965 - }
966 -
967 122 36 free_refspecs(&remote->passive_refspecs);
968 122 37,38 if ((error = dwim_refspecs(&remote->passive_refspecs, &remote->refspecs, &refs)) < 0)
969 ##### 39 goto on_error;
970 -
971 122 40 free_refspecs(&remote->active_refspecs);
972 122 41 error = dwim_refspecs(&remote->active_refspecs, to_active, &refs);
973 -
974 122 42 git_vector_free(&refs);
975 122 43 free_refspecs(&specs);
976 122 44 git_vector_free(&specs);
977 -
978 122 45 if (error < 0)
979 ##### 46 return error;
980 -
981 122 47 if (remote->push) {
982 ##### 48 git_push_free(remote->push);
983 ##### 49 remote->push = NULL;
984 - }
985 -
986 122 50,51 if ((error = git_fetch_negotiate(remote, opts)) < 0)
987 ##### 52 return error;
988 -
989 122 53 return git_fetch_download_pack(remote, cbs);
990 -
991 - on_error:
992 ##### 54 git_vector_free(&refs);
993 ##### 55 free_refspecs(&specs);
994 ##### 56 git_vector_free(&specs);
995 ##### 57 return error;
996 - }
997 -
998 141 2 int git_remote_fetch(
999 - git_remote *remote,
1000 - const git_strarray *refspecs,
1001 - const git_fetch_options *opts,
1002 - const char *reflog_message)
1003 - {
1004 141 2 int error, update_fetchhead = 1;
1005 141 2 git_remote_autotag_option_t tagopt = remote->download_tags;
1006 141 2 bool prune = false;
1007 141 2 git_buf reflog_msg_buf = GIT_BUF_INIT;
1008 141 2 const git_remote_callbacks *cbs = NULL;
1009 141 2 git_remote_connection_opts conn = GIT_REMOTE_CONNECTION_OPTIONS_INIT;
1010 -
1011 141 2 if (opts) {
1012 123 3-5 GIT_ERROR_CHECK_VERSION(&opts->callbacks, GIT_REMOTE_CALLBACKS_VERSION, "git_remote_callbacks");
1013 123 6 cbs = &opts->callbacks;
1014 123 6 conn.custom_headers = &opts->custom_headers;
1015 123 6 update_fetchhead = opts->update_fetchhead;
1016 123 6 tagopt = opts->download_tags;
1017 123 6-8 GIT_ERROR_CHECK_VERSION(&opts->proxy_opts, GIT_PROXY_OPTIONS_VERSION, "git_proxy_options");
1018 123 9 conn.proxy = &opts->proxy_opts;
1019 - }
1020 -
1021 - /* Connect and download everything */
1022 141 10,11 if ((error = git_remote__connect(remote, GIT_DIRECTION_FETCH, cbs, &conn)) != 0)
1023 23 12 return error;
1024 -
1025 118 13 error = git_remote_download(remote, refspecs, opts);
1026 -
1027 - /* We don't need to be connected anymore */
1028 118 14 git_remote_disconnect(remote);
1029 -
1030 - /* If the download failed, return the error */
1031 118 15 if (error != 0)
1032 2 16 return error;
1033 -
1034 - /* Default reflog message */
1035 116 17 if (reflog_message)
1036 67 18 git_buf_sets(&reflog_msg_buf, reflog_message);
1037 - else {
1038 49 19-22 git_buf_printf(&reflog_msg_buf, "fetch %s",
1039 49 19 remote->name ? remote->name : remote->url);
1040 - }
1041 -
1042 - /* Create "remote/foo" branches for all remote branches */
1043 116 23,24 error = git_remote_update_tips(remote, cbs, update_fetchhead, tagopt, git_buf_cstr(&reflog_msg_buf));
1044 116 25 git_buf_dispose(&reflog_msg_buf);
1045 116 26 if (error < 0)
1046 ##### 27 return error;
1047 -
1048 116 28,29 if (opts && opts->prune == GIT_FETCH_PRUNE)
1049 ##### 30 prune = true;
1050 116 31-33 else if (opts && opts->prune == GIT_FETCH_PRUNE_UNSPECIFIED && remote->prune_refs)
1051 5 34 prune = true;
1052 111 35,36 else if (opts && opts->prune == GIT_FETCH_NO_PRUNE)
1053 ##### 37 prune = false;
1054 - else
1055 111 38 prune = remote->prune_refs;
1056 -
1057 116 39 if (prune)
1058 5 40 error = git_remote_prune(remote, cbs);
1059 -
1060 116 41 return error;
1061 - }
1062 -
1063 27 2 static int remote_head_for_fetchspec_src(git_remote_head **out, git_vector *update_heads, const char *fetchspec_src)
1064 - {
1065 - unsigned int i;
1066 - git_remote_head *remote_ref;
1067 -
1068 27 2-4 assert(update_heads && fetchspec_src);
1069 -
1070 27 5 *out = NULL;
1071 -
1072 41 5,8-10 git_vector_foreach(update_heads, i, remote_ref) {
1073 38 6 if (strcmp(remote_ref->name, fetchspec_src) == 0) {
1074 24 7 *out = remote_ref;
1075 24 7 break;
1076 - }
1077 - }
1078 -
1079 27 11 return 0;
1080 - }
1081 -
1082 58 2 static int ref_to_update(int *update, git_buf *remote_name, git_remote *remote, git_refspec *spec, const char *ref_name)
1083 - {
1084 58 2 int error = 0;
1085 - git_repository *repo;
1086 58 2 git_buf upstream_remote = GIT_BUF_INIT;
1087 58 2 git_buf upstream_name = GIT_BUF_INIT;
1088 -
1089 58 2 repo = git_remote_owner(remote);
1090 -
1091 58 3,4,6 if ((!git_reference__is_branch(ref_name)) ||
1092 58 5,8 !git_remote_name(remote) ||
1093 57 7,11 (error = git_branch_upstream_remote(&upstream_remote, repo, ref_name) < 0) ||
1094 6 9,10,12,13 git__strcmp(git_remote_name(remote), git_buf_cstr(&upstream_remote)) ||
1095 5 16 (error = git_branch_upstream_name(&upstream_name, repo, ref_name)) < 0 ||
1096 5 14,15,17,18 !git_refspec_dst_matches(spec, git_buf_cstr(&upstream_name)) ||
1097 5 17 (error = git_refspec_rtransform(remote_name, spec, upstream_name.ptr)) < 0) {
1098 - /* Not an error if there is no upstream */
1099 53 19 if (error == GIT_ENOTFOUND) {
1100 ##### 20 git_error_clear();
1101 ##### 21 error = 0;
1102 - }
1103 -
1104 53 22 *update = 0;
1105 - } else {
1106 5 23 *update = 1;
1107 - }
1108 -
1109 58 24 git_buf_dispose(&upstream_remote);
1110 58 25 git_buf_dispose(&upstream_name);
1111 58 26 return error;
1112 - }
1113 -
1114 58 2 static int remote_head_for_ref(git_remote_head **out, git_remote *remote, git_refspec *spec, git_vector *update_heads, git_reference *ref)
1115 - {
1116 58 2 git_reference *resolved_ref = NULL;
1117 58 2 git_buf remote_name = GIT_BUF_INIT;
1118 58 2 git_config *config = NULL;
1119 - const char *ref_name;
1120 58 2 int error = 0, update;
1121 -
1122 58 2-5 assert(out && spec && ref);
1123 -
1124 58 6 *out = NULL;
1125 -
1126 58 6 error = git_reference_resolve(&resolved_ref, ref);
1127 -
1128 - /* If we're in an unborn branch, let's pretend nothing happened */
1129 58 7-9 if (error == GIT_ENOTFOUND && git_reference_type(ref) == GIT_REFERENCE_SYMBOLIC) {
1130 47 10 ref_name = git_reference_symbolic_target(ref);
1131 47 11 error = 0;
1132 - } else {
1133 11 12 ref_name = git_reference_name(resolved_ref);
1134 - }
1135 -
1136 58 13,14 if ((error = ref_to_update(&update, &remote_name, remote, spec, ref_name)) < 0)
1137 ##### 15 goto cleanup;
1138 -
1139 58 16 if (update)
1140 5 17,18 error = remote_head_for_fetchspec_src(out, update_heads, git_buf_cstr(&remote_name));
1141 -
1142 - cleanup:
1143 58 19 git_buf_dispose(&remote_name);
1144 58 20 git_reference_free(resolved_ref);
1145 58 21 git_config_free(config);
1146 58 22 return error;
1147 - }
1148 -
1149 86 2 static int git_remote_write_fetchhead(git_remote *remote, git_refspec *spec, git_vector *update_heads)
1150 - {
1151 86 2 git_reference *head_ref = NULL;
1152 - git_fetchhead_ref *fetchhead_ref;
1153 - git_remote_head *remote_ref, *merge_remote_ref;
1154 - git_vector fetchhead_refs;
1155 - bool include_all_fetchheads;
1156 86 2 unsigned int i = 0;
1157 86 2 int error = 0;
1158 -
1159 86 2,3 assert(remote);
1160 -
1161 - /* no heads, nothing to do */
1162 86 4 if (update_heads->length == 0)
1163 6 5 return 0;
1164 -
1165 80 6,7 if (git_vector_init(&fetchhead_refs, update_heads->length, git_fetchhead_ref_cmp) < 0)
1166 ##### 8 return -1;
1167 -
1168 - /* Iff refspec is * (but not subdir slash star), include tags */
1169 80 9 include_all_fetchheads = (strcmp(GIT_REFS_HEADS_DIR "*", git_refspec_src(spec)) == 0);
1170 -
1171 - /* Determine what to merge: if refspec was a wildcard, just use HEAD */
1172 80 10,11 if (git_refspec_is_wildcard(spec)) {
1173 58 12-15 if ((error = git_reference_lookup(&head_ref, remote->repo, GIT_HEAD_FILE)) < 0 ||
1174 58 14 (error = remote_head_for_ref(&merge_remote_ref, remote, spec, update_heads, head_ref)) < 0)
1175 - goto cleanup;
1176 - } else {
1177 - /* If we're fetching a single refspec, that's the only thing that should be in FETCH_HEAD. */
1178 22 16-18 if ((error = remote_head_for_fetchspec_src(&merge_remote_ref, update_heads, git_refspec_src(spec))) < 0)
1179 ##### 19 goto cleanup;
1180 - }
1181 -
1182 - /* Create the FETCH_HEAD file */
1183 835 20,33-35 git_vector_foreach(update_heads, i, remote_ref) {
1184 755 21 int merge_this_fetchhead = (merge_remote_ref == remote_ref);
1185 -
1186 755 21,23 if (!include_all_fetchheads &&
1187 73 22,24 !git_refspec_src_matches(spec, remote_ref->name) &&
1188 - !merge_this_fetchhead)
1189 21 25 continue;
1190 -
1191 734 26-28 if (git_fetchhead_ref_create(&fetchhead_ref,
1192 - &remote_ref->oid,
1193 - merge_this_fetchhead,
1194 734 27 remote_ref->name,
1195 - git_remote_url(remote)) < 0)
1196 ##### 29 goto cleanup;
1197 -
1198 734 30,31 if (git_vector_insert(&fetchhead_refs, fetchhead_ref) < 0)
1199 ##### 32 goto cleanup;
1200 - }
1201 -
1202 80 36 git_fetchhead_write(remote->repo, &fetchhead_refs);
1203 -
1204 - cleanup:
1205 814 37,39,40 for (i = 0; i < fetchhead_refs.length; ++i)
1206 734 38 git_fetchhead_ref_free(fetchhead_refs.contents[i]);
1207 -
1208 80 41 git_vector_free(&fetchhead_refs);
1209 80 42 git_reference_free(head_ref);
1210 -
1211 80 43 return error;
1212 - }
1213 -
1214 - /**
1215 - * Generate a list of candidates for pruning by getting a list of
1216 - * references which match the rhs of an active refspec.
1217 - */
1218 8 2 static int prune_candidates(git_vector *candidates, git_remote *remote)
1219 - {
1220 8 2 git_strarray arr = { 0 };
1221 - size_t i;
1222 - int error;
1223 -
1224 8 2,3 if ((error = git_reference_list(&arr, remote->repo)) < 0)
1225 ##### 4 return error;
1226 -
1227 163 5,15,16 for (i = 0; i < arr.count; i++) {
1228 155 6 const char *refname = arr.strings[i];
1229 - char *refname_dup;
1230 -
1231 155 6,7 if (!git_remote__matching_dst_refspec(remote, refname))
1232 57 8 continue;
1233 -
1234 98 9 refname_dup = git__strdup(refname);
1235 98 10,11 GIT_ERROR_CHECK_ALLOC(refname_dup);
1236 -
1237 98 12,13 if ((error = git_vector_insert(candidates, refname_dup)) < 0)
1238 ##### 14 goto out;
1239 - }
1240 -
1241 - out:
1242 8 17 git_strarray_dispose(&arr);
1243 8 18 return error;
1244 - }
1245 -
1246 633 2 static int find_head(const void *_a, const void *_b)
1247 - {
1248 633 2 git_remote_head *a = (git_remote_head *) _a;
1249 633 2 git_remote_head *b = (git_remote_head *) _b;
1250 -
1251 633 2 return strcmp(a->name, b->name);
1252 - }
1253 -
1254 8 2 int git_remote_prune(git_remote *remote, const git_remote_callbacks *callbacks)
1255 - {
1256 - size_t i, j;
1257 8 2 git_vector remote_refs = GIT_VECTOR_INIT;
1258 8 2 git_vector candidates = GIT_VECTOR_INIT;
1259 - const git_refspec *spec;
1260 - const char *refname;
1261 - int error;
1262 8 2 git_oid zero_id = {{ 0 }};
1263 -
1264 8 2 if (callbacks)
1265 8 3-5 GIT_ERROR_CHECK_VERSION(callbacks, GIT_REMOTE_CALLBACKS_VERSION, "git_remote_callbacks");
1266 -
1267 8 6,7 if ((error = ls_to_vector(&remote_refs, remote)) < 0)
1268 ##### 8 goto cleanup;
1269 -
1270 8 9 git_vector_set_cmp(&remote_refs, find_head);
1271 -
1272 8 10,11 if ((error = prune_candidates(&candidates, remote)) < 0)
1273 ##### 12 goto cleanup;
1274 -
1275 - /*
1276 - * Remove those entries from the candidate list for which we
1277 - * can find a remote reference in at least one refspec.
1278 - */
1279 106 13,38-40 git_vector_foreach(&candidates, i, refname) {
1280 117 14,34,36,37 git_vector_foreach(&remote->active_refspecs, j, spec) {
1281 112 15 git_buf buf = GIT_BUF_INIT;
1282 - size_t pos;
1283 - char *src_name;
1284 112 15 git_remote_head key = {0};
1285 -
1286 112 15,16 if (!git_refspec_dst_matches(spec, refname))
1287 19 17,34 continue;
1288 -
1289 100 18,19 if ((error = git_refspec_rtransform(&buf, spec, refname)) < 0)
1290 ##### 20,35 goto cleanup;
1291 -
1292 100 21 key.name = (char *) git_buf_cstr(&buf);
1293 100 22 error = git_vector_bsearch(&pos, &remote_refs, &key);
1294 100 23 git_buf_dispose(&buf);
1295 -
1296 100 24,25 if (error < 0 && error != GIT_ENOTFOUND)
1297 ##### 26 goto cleanup;
1298 -
1299 100 27 if (error == GIT_ENOTFOUND)
1300 7 28 continue;
1301 -
1302 - /* if we did find a source, remove it from the candiates */
1303 93 29,30 if ((error = git_vector_set((void **) &src_name, &candidates, i, NULL)) < 0)
1304 ##### 31 goto cleanup;
1305 -
1306 93 32 git__free(src_name);
1307 93 33 break;
1308 - }
1309 - }
1310 -
1311 - /*
1312 - * For those candidates still left in the list, we need to
1313 - * remove them. We do not remove symrefs, as those are for
1314 - * stuff like origin/HEAD which will never match, but we do
1315 - * not want to remove them.
1316 - */
1317 106 41,67-69 git_vector_foreach(&candidates, i, refname) {
1318 - git_reference *ref;
1319 - git_oid id;
1320 -
1321 98 42 if (refname == NULL)
1322 93 43,65 continue;
1323 -
1324 5 44 error = git_reference_lookup(&ref, remote->repo, refname);
1325 - /* as we want it gone, let's not consider this an error */
1326 5 45 if (error == GIT_ENOTFOUND)
1327 ##### 46 continue;
1328 -
1329 5 47 if (error < 0)
1330 ##### 48,66 goto cleanup;
1331 -
1332 5 49,50 if (git_reference_type(ref) == GIT_REFERENCE_SYMBOLIC) {
1333 ##### 51 git_reference_free(ref);
1334 ##### 52 continue;
1335 - }
1336 -
1337 5 53,54 git_oid_cpy(&id, git_reference_target(ref));
1338 5 55 error = git_reference_delete(ref);
1339 5 56 git_reference_free(ref);
1340 5 57 if (error < 0)
1341 ##### 58 goto cleanup;
1342 -
1343 5 59,60 if (callbacks && callbacks->update_tips)
1344 ##### 61 error = callbacks->update_tips(refname, &id, &zero_id, callbacks->payload);
1345 -
1346 5 62 if (error < 0)
1347 5 63,64 goto cleanup;
1348 - }
1349 -
1350 - cleanup:
1351 8 70 git_vector_free(&remote_refs);
1352 8 71 git_vector_free_deep(&candidates);
1353 8 72 return error;
1354 - }
1355 -
1356 164 2 static int update_tips_for_spec(
1357 - git_remote *remote,
1358 - const git_remote_callbacks *callbacks,
1359 - int update_fetchhead,
1360 - git_remote_autotag_option_t tagopt,
1361 - git_refspec *spec,
1362 - git_vector *refs,
1363 - const char *log_message)
1364 - {
1365 164 2 int error = 0, autotag;
1366 164 2 unsigned int i = 0;
1367 164 2 git_buf refname = GIT_BUF_INIT;
1368 - git_oid old;
1369 - git_odb *odb;
1370 - git_remote_head *head;
1371 - git_reference *ref;
1372 - git_refspec tagspec;
1373 - git_vector update_heads;
1374 -
1375 164 2,3 assert(remote);
1376 -
1377 164 4,5 if (git_repository_odb__weakptr(&odb, remote->repo) < 0)
1378 ##### 6 return -1;
1379 -
1380 164 7,8 if (git_refspec__parse(&tagspec, GIT_REFSPEC_TAGS, true) < 0)
1381 ##### 9 return -1;
1382 -
1383 - /* Make a copy of the transport's refs */
1384 164 10,11 if (git_vector_init(&update_heads, 16, NULL) < 0)
1385 ##### 12 return -1;
1386 -
1387 3179 13,73,74 for (; i < refs->length; ++i) {
1388 3015 14 head = git_vector_get(refs, i);
1389 3015 15 autotag = 0;
1390 3015 15 git_buf_clear(&refname);
1391 -
1392 - /* Ignore malformed ref names (which also saves us from tag^{} */
1393 3015 16,17 if (!git_reference_is_valid_name(head->name))
1394 567 18 continue;
1395 -
1396 - /* If we have a tag, see if the auto-follow rules say to update it */
1397 2448 19,20 if (git_refspec_src_matches(&tagspec, head->name)) {
1398 833 21 if (tagopt != GIT_REMOTE_DOWNLOAD_TAGS_NONE) {
1399 -
1400 744 22 if (tagopt == GIT_REMOTE_DOWNLOAD_TAGS_AUTO)
1401 388 23 autotag = 1;
1402 -
1403 744 24 git_buf_clear(&refname);
1404 744 25,26 if (git_buf_puts(&refname, head->name) < 0)
1405 ##### 27 goto on_error;
1406 - }
1407 - }
1408 -
1409 - /* If we didn't want to auto-follow the tag, check if the refspec matches */
1410 2448 28-30 if (!autotag && git_refspec_src_matches(spec, head->name)) {
1411 912 31 if (spec->dst) {
1412 903 32,33 if (git_refspec_transform(&refname, spec, head->name) < 0)
1413 ##### 34 goto on_error;
1414 - } else {
1415 - /*
1416 - * no rhs mans store it in FETCH_HEAD, even if we don't
1417 - update anything else.
1418 - */
1419 9 35,36 if ((error = git_vector_insert(&update_heads, head)) < 0)
1420 ##### 37 goto on_error;
1421 -
1422 9 38 continue;
1423 - }
1424 - }
1425 -
1426 - /* If we still don't have a refname, we don't want it */
1427 2439 39,40 if (git_buf_len(&refname) == 0) {
1428 981 41 continue;
1429 - }
1430 -
1431 - /* In autotag mode, only create tags for objects already in db */
1432 1458 42-44 if (autotag && !git_odb_exists(odb, &head->oid))
1433 5 45 continue;
1434 -
1435 1453 46-48 if (!autotag && git_vector_insert(&update_heads, head) < 0)
1436 ##### 49 goto on_error;
1437 -
1438 1453 50 error = git_reference_name_to_id(&old, remote->repo, refname.ptr);
1439 1453 51,52 if (error < 0 && error != GIT_ENOTFOUND)
1440 ##### 53 goto on_error;
1441 -
1442 1453 54 if (error == GIT_ENOTFOUND) {
1443 1014 55 memset(&old, 0, GIT_OID_RAWSZ);
1444 -
1445 1014 55-57 if (autotag && git_vector_insert(&update_heads, head) < 0)
1446 ##### 58 goto on_error;
1447 - }
1448 -
1449 1453 59,60 if (!git_oid__cmp(&old, &head->oid))
1450 438 61 continue;
1451 -
1452 - /* In autotag mode, don't overwrite any locally-existing tags */
1453 1015 62 error = git_reference_create(&ref, remote->repo, refname.ptr, &head->oid, !autotag,
1454 - log_message);
1455 -
1456 1015 63 if (error == GIT_EEXISTS)
1457 ##### 64 continue;
1458 -
1459 1015 65 if (error < 0)
1460 ##### 66 goto on_error;
1461 -
1462 1015 67 git_reference_free(ref);
1463 -
1464 1015 68,69 if (callbacks && callbacks->update_tips != NULL) {
1465 69 70,71 if (callbacks->update_tips(refname.ptr, &old, &head->oid, callbacks->payload) < 0)
1466 ##### 72 goto on_error;
1467 - }
1468 - }
1469 -
1470 164 75-77 if (update_fetchhead &&
1471 - (error = git_remote_write_fetchhead(remote, spec, &update_heads)) < 0)
1472 ##### 78 goto on_error;
1473 -
1474 164 79 git_vector_free(&update_heads);
1475 164 80 git_refspec__dispose(&tagspec);
1476 164 81 git_buf_dispose(&refname);
1477 164 82 return 0;
1478 -
1479 - on_error:
1480 ##### 83 git_vector_free(&update_heads);
1481 ##### 84 git_refspec__dispose(&tagspec);
1482 ##### 85 git_buf_dispose(&refname);
1483 ##### 86 return -1;
1484 -
1485 - }
1486 -
1487 - /**
1488 - * Iteration over the three vectors, with a pause whenever we find a match
1489 - *
1490 - * On each stop, we store the iteration stat in the inout i,j,k
1491 - * parameters, and return the currently matching passive refspec as
1492 - * well as the head which we matched.
1493 - */
1494 23 2 static int next_head(const git_remote *remote, git_vector *refs,
1495 - git_refspec **out_spec, git_remote_head **out_head,
1496 - size_t *out_i, size_t *out_j, size_t *out_k)
1497 - {
1498 - const git_vector *active, *passive;
1499 - git_remote_head *head;
1500 - git_refspec *spec, *passive_spec;
1501 - size_t i, j, k;
1502 -
1503 23 2 active = &remote->active_refspecs;
1504 23 2 passive = &remote->passive_refspecs;
1505 -
1506 23 2 i = *out_i;
1507 23 2 j = *out_j;
1508 23 2 k = *out_k;
1509 -
1510 407 2,23,24 for (; i < refs->length; i++) {
1511 391 3 head = git_vector_get(refs, i);
1512 -
1513 391 4,5 if (!git_reference_is_valid_name(head->name))
1514 76 6 continue;
1515 -
1516 692 7,20,21 for (; j < active->length; j++) {
1517 384 8 spec = git_vector_get(active, j);
1518 -
1519 384 9,10 if (!git_refspec_src_matches(spec, head->name))
1520 331 11 continue;
1521 -
1522 60 12,16,18 for (; k < passive->length; k++) {
1523 14 13 passive_spec = git_vector_get(passive, k);
1524 -
1525 14 14,15 if (!git_refspec_src_matches(passive_spec, head->name))
1526 7 16 continue;
1527 -
1528 7 17 *out_spec = passive_spec;
1529 7 17 *out_head = head;
1530 7 17 *out_i = i;
1531 7 17 *out_j = j;
1532 7 17 *out_k = k + 1;
1533 7 17 return 0;
1534 -
1535 - }
1536 46 19 k = 0;
1537 - }
1538 308 22 j = 0;
1539 - }
1540 -
1541 16 25 return GIT_ITEROVER;
1542 - }
1543 -
1544 16 2 static int opportunistic_updates(const git_remote *remote, const git_remote_callbacks *callbacks,
1545 - git_vector *refs, const char *msg)
1546 - {
1547 - size_t i, j, k;
1548 - git_refspec *spec;
1549 - git_remote_head *head;
1550 - git_reference *ref;
1551 16 2 git_buf refname = GIT_BUF_INIT;
1552 16 2 int error = 0;
1553 -
1554 16 2 i = j = k = 0;
1555 -
1556 23 2,27,28 while ((error = next_head(remote, refs, &spec, &head, &i, &j, &k)) == 0) {
1557 7 3 git_oid old = {{ 0 }};
1558 - /*
1559 - * If we got here, there is a refspec which was used
1560 - * for fetching which matches the source of one of the
1561 - * passive refspecs, so we should update that
1562 - * remote-tracking branch, but not add it to
1563 - * FETCH_HEAD
1564 - */
1565 -
1566 7 3 git_buf_clear(&refname);
1567 7 4,5 if ((error = git_refspec_transform(&refname, spec, head->name)) < 0)
1568 ##### 6,26 goto cleanup;
1569 -
1570 7 7 error = git_reference_name_to_id(&old, remote->repo, refname.ptr);
1571 7 8,9 if (error < 0 && error != GIT_ENOTFOUND)
1572 ##### 10 goto cleanup;
1573 -
1574 7 11,12 if (!git_oid_cmp(&old, &head->oid))
1575 4 13 continue;
1576 -
1577 - /* If we did find a current reference, make sure we haven't lost a race */
1578 3 14 if (error)
1579 3 15 error = git_reference_create(&ref, remote->repo, refname.ptr, &head->oid, true, msg);
1580 - else
1581 ##### 16 error = git_reference_create_matching(&ref, remote->repo, refname.ptr, &head->oid, true, &old, msg);
1582 3 17 git_reference_free(ref);
1583 3 18 if (error < 0)
1584 ##### 19 goto cleanup;
1585 -
1586 3 20,21 if (callbacks && callbacks->update_tips != NULL) {
1587 ##### 22,23 if (callbacks->update_tips(refname.ptr, &old, &head->oid, callbacks->payload) < 0)
1588 3 24,25 goto cleanup;
1589 - }
1590 - }
1591 -
1592 16 29 if (error == GIT_ITEROVER)
1593 16 30 error = 0;
1594 -
1595 - cleanup:
1596 16 31 git_buf_dispose(&refname);
1597 16 32 return error;
1598 - }
1599 -
1600 117 2 static int truncate_fetch_head(const char *gitdir)
1601 - {
1602 117 2 git_buf path = GIT_BUF_INIT;
1603 - int error;
1604 -
1605 117 2,3 if ((error = git_buf_joinpath(&path, gitdir, GIT_FETCH_HEAD_FILE)) < 0)
1606 ##### 4 return error;
1607 -
1608 117 5 error = git_futils_truncate(path.ptr, GIT_REFS_FILE_MODE);
1609 117 6 git_buf_dispose(&path);
1610 -
1611 117 7 return error;
1612 - }
1613 -
1614 122 2 int git_remote_update_tips(
1615 - git_remote *remote,
1616 - const git_remote_callbacks *callbacks,
1617 - int update_fetchhead,
1618 - git_remote_autotag_option_t download_tags,
1619 - const char *reflog_message)
1620 - {
1621 - git_refspec *spec, tagspec;
1622 122 2 git_vector refs = GIT_VECTOR_INIT;
1623 - git_remote_autotag_option_t tagopt;
1624 - int error;
1625 - size_t i;
1626 -
1627 - /* push has its own logic hidden away in the push object */
1628 122 2 if (remote->push) {
1629 5 3 return git_push_update_tips(remote->push, callbacks);
1630 - }
1631 -
1632 117 4,5 if (git_refspec__parse(&tagspec, GIT_REFSPEC_TAGS, true) < 0)
1633 ##### 6 return -1;
1634 -
1635 -
1636 117 7,8 if ((error = ls_to_vector(&refs, remote)) < 0)
1637 ##### 9 goto out;
1638 -
1639 117 10 if (download_tags == GIT_REMOTE_DOWNLOAD_TAGS_UNSPECIFIED)
1640 44 11 tagopt = remote->download_tags;
1641 - else
1642 73 12 tagopt = download_tags;
1643 -
1644 117 13-15 if ((error = truncate_fetch_head(git_repository_path(remote->repo))) < 0)
1645 ##### 16 goto out;
1646 -
1647 117 17 if (tagopt == GIT_REMOTE_DOWNLOAD_TAGS_ALL) {
1648 40 18,19 if ((error = update_tips_for_spec(remote, callbacks, update_fetchhead, tagopt, &tagspec, &refs, reflog_message)) < 0)
1649 ##### 20 goto out;
1650 - }
1651 -
1652 241 21,27-29 git_vector_foreach(&remote->active_refspecs, i, spec) {
1653 124 22 if (spec->push)
1654 ##### 23 continue;
1655 -
1656 124 24,25 if ((error = update_tips_for_spec(remote, callbacks, update_fetchhead, tagopt, spec, &refs, reflog_message)) < 0)
1657 ##### 26 goto out;
1658 - }
1659 -
1660 - /* only try to do opportunisitic updates if the refpec lists differ */
1661 117 30 if (remote->passed_refspecs)
1662 16 31 error = opportunistic_updates(remote, callbacks, &refs, reflog_message);
1663 -
1664 - out:
1665 117 32 git_vector_free(&refs);
1666 117 33 git_refspec__dispose(&tagspec);
1667 117 34 return error;
1668 - }
1669 -
1670 419 2 int git_remote_connected(const git_remote *remote)
1671 - {
1672 419 2,3 assert(remote);
1673 -
1674 419 4,5 if (!remote->transport || !remote->transport->is_connected)
1675 ##### 6 return 0;
1676 -
1677 - /* Ask the transport if it's connected. */
1678 419 7 return remote->transport->is_connected(remote->transport);
1679 - }
1680 -
1681 ##### 2 int git_remote_stop(git_remote *remote)
1682 - {
1683 ##### 2,3 assert(remote);
1684 -
1685 ##### 4,5 if (remote->transport && remote->transport->cancel)
1686 ##### 6 remote->transport->cancel(remote->transport);
1687 -
1688 ##### 7 return 0;
1689 - }
1690 -
1691 276 2 int git_remote_disconnect(git_remote *remote)
1692 - {
1693 276 2,3 assert(remote);
1694 -
1695 276 4,5 if (git_remote_connected(remote))
1696 148 6 remote->transport->close(remote->transport);
1697 -
1698 276 7 return 0;
1699 - }
1700 -
1701 662 2 void git_remote_free(git_remote *remote)
1702 - {
1703 662 2 if (remote == NULL)
1704 662 3,20 return;
1705 -
1706 610 4 if (remote->transport != NULL) {
1707 144 5 git_remote_disconnect(remote);
1708 -
1709 144 6 remote->transport->free(remote->transport);
1710 144 7 remote->transport = NULL;
1711 - }
1712 -
1713 610 8 git_vector_free(&remote->refs);
1714 -
1715 610 9 free_refspecs(&remote->refspecs);
1716 610 10 git_vector_free(&remote->refspecs);
1717 -
1718 610 11 free_refspecs(&remote->active_refspecs);
1719 610 12 git_vector_free(&remote->active_refspecs);
1720 -
1721 610 13 free_refspecs(&remote->passive_refspecs);
1722 610 14 git_vector_free(&remote->passive_refspecs);
1723 -
1724 610 15 git_push_free(remote->push);
1725 610 16 git__free(remote->url);
1726 610 17 git__free(remote->pushurl);
1727 610 18 git__free(remote->name);
1728 610 19 git__free(remote);
1729 - }
1730 -
1731 61 2 static int remote_list_cb(const git_config_entry *entry, void *payload)
1732 - {
1733 61 2 git_vector *list = payload;
1734 61 2 const char *name = entry->name + strlen("remote.");
1735 61 2 size_t namelen = strlen(name);
1736 - char *remote_name;
1737 -
1738 - /* we know name matches "remote.<stuff>.(push)?url" */
1739 -
1740 61 2 if (!strcmp(&name[namelen - 4], ".url"))
1741 44 3 remote_name = git__strndup(name, namelen - 4); /* strip ".url" */
1742 - else
1743 17 4 remote_name = git__strndup(name, namelen - 8); /* strip ".pushurl" */
1744 61 5,6 GIT_ERROR_CHECK_ALLOC(remote_name);
1745 -
1746 61 7 return git_vector_insert(list, remote_name);
1747 - }
1748 -
1749 23 2 int git_remote_list(git_strarray *remotes_list, git_repository *repo)
1750 - {
1751 - int error;
1752 - git_config *cfg;
1753 23 2 git_vector list = GIT_VECTOR_INIT;
1754 -
1755 23 2,3 if ((error = git_repository_config__weakptr(&cfg, repo)) < 0)
1756 ##### 4 return error;
1757 -
1758 23 5,6 if ((error = git_vector_init(&list, 4, git__strcmp_cb)) < 0)
1759 ##### 7 return error;
1760 -
1761 23 8 error = git_config_foreach_match(
1762 - cfg, "^remote\\..*\\.(push)?url$", remote_list_cb, &list);
1763 -
1764 23 9 if (error < 0) {
1765 ##### 10 git_vector_free_deep(&list);
1766 ##### 11 return error;
1767 - }
1768 -
1769 23 12 git_vector_uniq(&list, git__free);
1770 -
1771 23 14 remotes_list->strings =
1772 23 13 (char **)git_vector_detach(&remotes_list->count, NULL, &list);
1773 -
1774 23 14 return 0;
1775 - }
1776 -
1777 ##### 2 const git_indexer_progress *git_remote_stats(git_remote *remote)
1778 - {
1779 ##### 2,3 assert(remote);
1780 ##### 4 return &remote->stats;
1781 - }
1782 -
1783 2 2 git_remote_autotag_option_t git_remote_autotag(const git_remote *remote)
1784 - {
1785 2 2 return remote->download_tags;
1786 - }
1787 -
1788 3 2 int git_remote_set_autotag(git_repository *repo, const char *remote, git_remote_autotag_option_t value)
1789 - {
1790 3 2 git_buf var = GIT_BUF_INIT;
1791 - git_config *config;
1792 - int error;
1793 -
1794 3 2-4 assert(repo && remote);
1795 -
1796 3 5,6 if ((error = ensure_remote_name_is_valid(remote)) < 0)
1797 ##### 7 return error;
1798 -
1799 3 8,9 if ((error = git_repository_config__weakptr(&config, repo)) < 0)
1800 ##### 10 return error;
1801 -
1802 3 11,12 if ((error = git_buf_printf(&var, CONFIG_TAGOPT_FMT, remote)))
1803 ##### 13 return error;
1804 -
1805 3 14 switch (value) {
1806 - case GIT_REMOTE_DOWNLOAD_TAGS_NONE:
1807 1 15 error = git_config_set_string(config, var.ptr, "--no-tags");
1808 1 16 break;
1809 - case GIT_REMOTE_DOWNLOAD_TAGS_ALL:
1810 1 17 error = git_config_set_string(config, var.ptr, "--tags");
1811 1 18 break;
1812 - case GIT_REMOTE_DOWNLOAD_TAGS_AUTO:
1813 1 19 error = git_config_delete_entry(config, var.ptr);
1814 1 20 if (error == GIT_ENOTFOUND)
1815 ##### 21 error = 0;
1816 1 22 break;
1817 - default:
1818 ##### 23 git_error_set(GIT_ERROR_INVALID, "invalid value for the tagopt setting");
1819 ##### 24 error = -1;
1820 - }
1821 -
1822 3 25 git_buf_dispose(&var);
1823 3 26 return error;
1824 - }
1825 -
1826 4 2 int git_remote_prune_refs(const git_remote *remote)
1827 - {
1828 4 2 return remote->prune_refs;
1829 - }
1830 -
1831 15 2 static int rename_remote_config_section(
1832 - git_repository *repo,
1833 - const char *old_name,
1834 - const char *new_name)
1835 - {
1836 15 2 git_buf old_section_name = GIT_BUF_INIT,
1837 15 2 new_section_name = GIT_BUF_INIT;
1838 15 2 int error = -1;
1839 -
1840 15 2,3 if (git_buf_printf(&old_section_name, "remote.%s", old_name) < 0)
1841 ##### 4 goto cleanup;
1842 -
1843 15 5,7 if (new_name &&
1844 11 6 (git_buf_printf(&new_section_name, "remote.%s", new_name) < 0))
1845 ##### 8 goto cleanup;
1846 -
1847 15 9-13 error = git_config_rename_section(
1848 - repo,
1849 - git_buf_cstr(&old_section_name),
1850 - new_name ? git_buf_cstr(&new_section_name) : NULL);
1851 -
1852 - cleanup:
1853 15 14 git_buf_dispose(&old_section_name);
1854 15 15 git_buf_dispose(&new_section_name);
1855 -
1856 15 16 return error;
1857 - }
1858 -
1859 - struct update_data {
1860 - git_config *config;
1861 - const char *old_remote_name;
1862 - const char *new_remote_name;
1863 - };
1864 -
1865 61 2 static int update_config_entries_cb(
1866 - const git_config_entry *entry,
1867 - void *payload)
1868 - {
1869 61 2 struct update_data *data = (struct update_data *)payload;
1870 -
1871 61 2 if (strcmp(entry->value, data->old_remote_name))
1872 40 3 return 0;
1873 -
1874 21 4 return git_config_set_string(
1875 - data->config, entry->name, data->new_remote_name);
1876 - }
1877 -
1878 11 2 static int update_branch_remote_config_entry(
1879 - git_repository *repo,
1880 - const char *old_name,
1881 - const char *new_name)
1882 - {
1883 - int error;
1884 11 2 struct update_data data = { NULL };
1885 -
1886 11 2,3 if ((error = git_repository_config__weakptr(&data.config, repo)) < 0)
1887 ##### 4 return error;
1888 -
1889 11 5 data.old_remote_name = old_name;
1890 11 5 data.new_remote_name = new_name;
1891 -
1892 11 5 return git_config_foreach_match(
1893 11 5 data.config, "branch\\..+\\.remote", update_config_entries_cb, &data);
1894 - }
1895 -
1896 14 2 static int rename_one_remote_reference(
1897 - git_reference *reference_in,
1898 - const char *old_remote_name,
1899 - const char *new_remote_name)
1900 - {
1901 - int error;
1902 14 2 git_reference *ref = NULL, *dummy = NULL;
1903 14 2 git_buf namespace = GIT_BUF_INIT, old_namespace = GIT_BUF_INIT;
1904 14 2 git_buf new_name = GIT_BUF_INIT;
1905 14 2 git_buf log_message = GIT_BUF_INIT;
1906 - size_t pfx_len;
1907 - const char *target;
1908 -
1909 14 2,3 if ((error = git_buf_printf(&namespace, GIT_REFS_REMOTES_DIR "%s/", new_remote_name)) < 0)
1910 ##### 4 return error;
1911 -
1912 14 5 pfx_len = strlen(GIT_REFS_REMOTES_DIR) + strlen(old_remote_name) + 1;
1913 14 5 git_buf_puts(&new_name, namespace.ptr);
1914 14 6-8 if ((error = git_buf_puts(&new_name, git_reference_name(reference_in) + pfx_len)) < 0)
1915 ##### 9 goto cleanup;
1916 -
1917 14 10,11 if ((error = git_buf_printf(&log_message,
1918 - "renamed remote %s to %s",
1919 - old_remote_name, new_remote_name)) < 0)
1920 ##### 12 goto cleanup;
1921 -
1922 14 13-16 if ((error = git_reference_rename(&ref, reference_in, git_buf_cstr(&new_name), 1,
1923 - git_buf_cstr(&log_message))) < 0)
1924 ##### 17 goto cleanup;
1925 -
1926 14 18,19 if (git_reference_type(ref) != GIT_REFERENCE_SYMBOLIC)
1927 12 20 goto cleanup;
1928 -
1929 - /* Handle refs like origin/HEAD -> origin/master */
1930 2 21 target = git_reference_symbolic_target(ref);
1931 2 22,23 if ((error = git_buf_printf(&old_namespace, GIT_REFS_REMOTES_DIR "%s/", old_remote_name)) < 0)
1932 ##### 24 goto cleanup;
1933 -
1934 2 25,26 if (git__prefixcmp(target, old_namespace.ptr))
1935 ##### 27 goto cleanup;
1936 -
1937 2 28 git_buf_clear(&new_name);
1938 2 29 git_buf_puts(&new_name, namespace.ptr);
1939 2 30,31 if ((error = git_buf_puts(&new_name, target + pfx_len)) < 0)
1940 ##### 32 goto cleanup;
1941 -
1942 2 33-35 error = git_reference_symbolic_set_target(&dummy, ref, git_buf_cstr(&new_name),
1943 - git_buf_cstr(&log_message));
1944 -
1945 2 36 git_reference_free(dummy);
1946 -
1947 - cleanup:
1948 14 37 git_reference_free(reference_in);
1949 14 38 git_reference_free(ref);
1950 14 39 git_buf_dispose(&namespace);
1951 14 40 git_buf_dispose(&old_namespace);
1952 14 41 git_buf_dispose(&new_name);
1953 14 42 git_buf_dispose(&log_message);
1954 14 43 return error;
1955 - }
1956 -
1957 11 2 static int rename_remote_references(
1958 - git_repository *repo,
1959 - const char *old_name,
1960 - const char *new_name)
1961 - {
1962 - int error;
1963 11 2 git_buf buf = GIT_BUF_INIT;
1964 - git_reference *ref;
1965 - git_reference_iterator *iter;
1966 -
1967 11 2,3 if ((error = git_buf_printf(&buf, GIT_REFS_REMOTES_DIR "%s/*", old_name)) < 0)
1968 ##### 4 return error;
1969 -
1970 11 5,6 error = git_reference_iterator_glob_new(&iter, repo, git_buf_cstr(&buf));
1971 11 7 git_buf_dispose(&buf);
1972 -
1973 11 8 if (error < 0)
1974 ##### 9 return error;
1975 -
1976 25 10,14,15 while ((error = git_reference_next(&ref, iter)) == 0) {
1977 14 11,12 if ((error = rename_one_remote_reference(ref, old_name, new_name)) < 0)
1978 ##### 13 break;
1979 - }
1980 -
1981 11 16 git_reference_iterator_free(iter);
1982 -
1983 11 17 return (error == GIT_ITEROVER) ? 0 : error;
1984 - }
1985 -
1986 11 2 static int rename_fetch_refspecs(git_vector *problems, git_remote *remote, const char *new_name)
1987 - {
1988 - git_config *config;
1989 11 2 git_buf base = GIT_BUF_INIT, var = GIT_BUF_INIT, val = GIT_BUF_INIT;
1990 - const git_refspec *spec;
1991 - size_t i;
1992 11 2 int error = 0;
1993 -
1994 11 2,3 if ((error = git_repository_config__weakptr(&config, remote->repo)) < 0)
1995 ##### 4 return error;
1996 -
1997 11 5,6 if ((error = git_vector_init(problems, 1, NULL)) < 0)
1998 ##### 7 return error;
1999 -
2000 11 8,9 if ((error = default_fetchspec_for_name(&base, remote->name)) < 0)
2001 ##### 10 return error;
2002 -
2003 21 11,35-37 git_vector_foreach(&remote->refspecs, i, spec) {
2004 10 12 if (spec->push)
2005 ##### 13 continue;
2006 -
2007 - /* Does the dst part of the refspec follow the expected format? */
2008 10 14,15 if (strcmp(git_buf_cstr(&base), spec->string)) {
2009 - char *dup;
2010 -
2011 1 16 dup = git__strdup(spec->string);
2012 1 17,18 GIT_ERROR_CHECK_ALLOC(dup);
2013 -
2014 1 19,20 if ((error = git_vector_insert(problems, dup)) < 0)
2015 ##### 21 break;
2016 -
2017 1 22 continue;
2018 - }
2019 -
2020 - /* If we do want to move it to the new section */
2021 -
2022 9 23 git_buf_clear(&val);
2023 9 24 git_buf_clear(&var);
2024 -
2025 9 25,26,28 if (default_fetchspec_for_name(&val, new_name) < 0 ||
2026 9 27 git_buf_printf(&var, "remote.%s.fetch", new_name) < 0)
2027 - {
2028 ##### 29 error = -1;
2029 ##### 29 break;
2030 - }
2031 -
2032 9 30-33 if ((error = git_config_set_string(
2033 - config, git_buf_cstr(&var), git_buf_cstr(&val))) < 0)
2034 ##### 34 break;
2035 - }
2036 -
2037 11 38 git_buf_dispose(&base);
2038 11 39 git_buf_dispose(&var);
2039 11 40 git_buf_dispose(&val);
2040 -
2041 11 41 if (error < 0) {
2042 - char *str;
2043 ##### 42,44-46 git_vector_foreach(problems, i, str)
2044 ##### 43 git__free(str);
2045 -
2046 ##### 47 git_vector_free(problems);
2047 - }
2048 -
2049 11 48 return error;
2050 - }
2051 -
2052 15 2 int git_remote_rename(git_strarray *out, git_repository *repo, const char *name, const char *new_name)
2053 - {
2054 - int error;
2055 15 2 git_vector problem_refspecs = GIT_VECTOR_INIT;
2056 15 2 git_remote *remote = NULL;
2057 -
2058 15 2-6 assert(out && repo && name && new_name);
2059 -
2060 15 7,8 if ((error = git_remote_lookup(&remote, repo, name)) < 0)
2061 1 9 return error;
2062 -
2063 14 10,11 if ((error = ensure_remote_name_is_valid(new_name)) < 0)
2064 1 12 goto cleanup;
2065 -
2066 13 13,14 if ((error = ensure_remote_doesnot_exist(repo, new_name)) < 0)
2067 2 15 goto cleanup;
2068 -
2069 11 16,17 if ((error = rename_remote_config_section(repo, name, new_name)) < 0)
2070 ##### 18 goto cleanup;
2071 -
2072 11 19,20 if ((error = update_branch_remote_config_entry(repo, name, new_name)) < 0)
2073 ##### 21 goto cleanup;
2074 -
2075 11 22,23 if ((error = rename_remote_references(repo, name, new_name)) < 0)
2076 ##### 24 goto cleanup;
2077 -
2078 11 25,26 if ((error = rename_fetch_refspecs(&problem_refspecs, remote, new_name)) < 0)
2079 ##### 27 goto cleanup;
2080 -
2081 11 28 out->count = problem_refspecs.length;
2082 11 28 out->strings = (char **) problem_refspecs.contents;
2083 -
2084 - cleanup:
2085 14 29 if (error < 0)
2086 3 30 git_vector_free(&problem_refspecs);
2087 -
2088 14 31 git_remote_free(remote);
2089 14 32 return error;
2090 - }
2091 -
2092 878 2 int git_remote_is_valid_name(
2093 - const char *remote_name)
2094 - {
2095 878 2 git_buf buf = GIT_BUF_INIT;
2096 - git_refspec refspec;
2097 878 2 int error = -1;
2098 -
2099 878 2,3 if (!remote_name || *remote_name == '\0')
2100 5 4 return 0;
2101 -
2102 873 5 git_buf_printf(&buf, "refs/heads/test:refs/remotes/%s/test", remote_name);
2103 873 6,7 error = git_refspec__parse(&refspec, git_buf_cstr(&buf), true);
2104 -
2105 873 8 git_buf_dispose(&buf);
2106 873 9 git_refspec__dispose(&refspec);
2107 -
2108 873 10 git_error_clear();
2109 873 11 return error == 0;
2110 - }
2111 -
2112 1750 2 git_refspec *git_remote__matching_refspec(git_remote *remote, const char *refname)
2113 - {
2114 - git_refspec *spec;
2115 - size_t i;
2116 -
2117 2785 2,8-10 git_vector_foreach(&remote->active_refspecs, i, spec) {
2118 1873 3 if (spec->push)
2119 1 4 continue;
2120 -
2121 1872 5,6 if (git_refspec_src_matches(spec, refname))
2122 838 7 return spec;
2123 - }
2124 -
2125 912 11 return NULL;
2126 - }
2127 -
2128 188 2 git_refspec *git_remote__matching_dst_refspec(git_remote *remote, const char *refname)
2129 - {
2130 - git_refspec *spec;
2131 - size_t i;
2132 -
2133 287 2,8-10 git_vector_foreach(&remote->active_refspecs, i, spec) {
2134 215 3 if (spec->push)
2135 1 4 continue;
2136 -
2137 214 5,6 if (git_refspec_dst_matches(spec, refname))
2138 116 7 return spec;
2139 - }
2140 -
2141 72 11 return NULL;
2142 - }
2143 -
2144 6 2 int git_remote_add_fetch(git_repository *repo, const char *remote, const char *refspec)
2145 - {
2146 6 2 return write_add_refspec(repo, remote, refspec, true);
2147 - }
2148 -
2149 5 2 int git_remote_add_push(git_repository *repo, const char *remote, const char *refspec)
2150 - {
2151 5 2 return write_add_refspec(repo, remote, refspec, false);
2152 - }
2153 -
2154 15 2 static int copy_refspecs(git_strarray *array, const git_remote *remote, unsigned int push)
2155 - {
2156 - size_t i;
2157 - git_vector refspecs;
2158 - git_refspec *spec;
2159 - char *dup;
2160 -
2161 15 2,3 if (git_vector_init(&refspecs, remote->refspecs.length, NULL) < 0)
2162 ##### 4 return -1;
2163 -
2164 33 5,14-16 git_vector_foreach(&remote->refspecs, i, spec) {
2165 18 6 if (spec->push != push)
2166 7 7 continue;
2167 -
2168 11 8,9 if ((dup = git__strdup(spec->string)) == NULL)
2169 ##### 10 goto on_error;
2170 -
2171 11 11,12 if (git_vector_insert(&refspecs, dup) < 0) {
2172 ##### 13 git__free(dup);
2173 ##### 18 goto on_error;
2174 - }
2175 - }
2176 -
2177 15 17 array->strings = (char **)refspecs.contents;
2178 15 17 array->count = refspecs.length;
2179 -
2180 15 17 return 0;
2181 -
2182 - on_error:
2183 ##### 19 git_vector_free_deep(&refspecs);
2184 -
2185 ##### 20 return -1;
2186 - }
2187 -
2188 13 2 int git_remote_get_fetch_refspecs(git_strarray *array, const git_remote *remote)
2189 - {
2190 13 2 return copy_refspecs(array, remote, false);
2191 - }
2192 -
2193 2 2 int git_remote_get_push_refspecs(git_strarray *array, const git_remote *remote)
2194 - {
2195 2 2 return copy_refspecs(array, remote, true);
2196 - }
2197 -
2198 8 2 size_t git_remote_refspec_count(const git_remote *remote)
2199 - {
2200 8 2 return remote->refspecs.length;
2201 - }
2202 -
2203 30 2 const git_refspec *git_remote_get_refspec(const git_remote *remote, size_t n)
2204 - {
2205 30 2 return git_vector_get(&remote->refspecs, n);
2206 - }
2207 -
2208 1 2 int git_remote_init_callbacks(git_remote_callbacks *opts, unsigned int version)
2209 - {
2210 1 2-4 GIT_INIT_STRUCTURE_FROM_TEMPLATE(
2211 - opts, version, git_remote_callbacks, GIT_REMOTE_CALLBACKS_INIT);
2212 1 5 return 0;
2213 - }
2214 -
2215 - /* asserts a branch.<foo>.remote format */
2216 8 2 static const char *name_offset(size_t *len_out, const char *name)
2217 - {
2218 - size_t prefix_len;
2219 - const char *dot;
2220 -
2221 8 2 prefix_len = strlen("remote.");
2222 8 2 dot = strchr(name + prefix_len, '.');
2223 -
2224 8 2,3 assert(dot);
2225 -
2226 8 4 *len_out = dot - name - prefix_len;
2227 8 4 return name + prefix_len;
2228 - }
2229 -
2230 5 2 static int remove_branch_config_related_entries(
2231 - git_repository *repo,
2232 - const char *remote_name)
2233 - {
2234 - int error;
2235 - git_config *config;
2236 - git_config_entry *entry;
2237 - git_config_iterator *iter;
2238 5 2 git_buf buf = GIT_BUF_INIT;
2239 -
2240 5 2,3 if ((error = git_repository_config__weakptr(&config, repo)) < 0)
2241 ##### 4 return error;
2242 -
2243 5 5,6 if ((error = git_config_iterator_glob_new(&iter, config, "branch\\..+\\.remote")) < 0)
2244 ##### 7 return error;
2245 -
2246 - /* find any branches with us as upstream and remove that config */
2247 29 8,34,35 while ((error = git_config_next(&entry, iter)) == 0) {
2248 - const char *branch;
2249 - size_t branch_len;
2250 -
2251 24 9 if (strcmp(remote_name, entry->value))
2252 16 10 continue;
2253 -
2254 8 11 branch = name_offset(&branch_len, entry->name);
2255 -
2256 8 12 git_buf_clear(&buf);
2257 8 13,14 if (git_buf_printf(&buf, "branch.%.*s.merge", (int)branch_len, branch) < 0)
2258 ##### 15,33 break;
2259 -
2260 8 16-18 if ((error = git_config_delete_entry(config, git_buf_cstr(&buf))) < 0) {
2261 ##### 19 if (error != GIT_ENOTFOUND)
2262 ##### 20 break;
2263 ##### 21 git_error_clear();
2264 - }
2265 -
2266 8 22 git_buf_clear(&buf);
2267 8 23,24 if (git_buf_printf(&buf, "branch.%.*s.remote", (int)branch_len, branch) < 0)
2268 ##### 25 break;
2269 -
2270 8 26-28 if ((error = git_config_delete_entry(config, git_buf_cstr(&buf))) < 0) {
2271 ##### 29 if (error != GIT_ENOTFOUND)
2272 ##### 30 break;
2273 8 31,32 git_error_clear();
2274 - }
2275 - }
2276 -
2277 5 36 if (error == GIT_ITEROVER)
2278 5 37 error = 0;
2279 -
2280 5 38 git_buf_dispose(&buf);
2281 5 39 git_config_iterator_free(iter);
2282 5 40 return error;
2283 - }
2284 -
2285 4 2 static int remove_refs(git_repository *repo, const git_refspec *spec)
2286 - {
2287 4 2 git_reference_iterator *iter = NULL;
2288 - git_vector refs;
2289 - const char *name;
2290 - char *dup;
2291 - int error;
2292 - size_t i;
2293 -
2294 4 2,3 if ((error = git_vector_init(&refs, 8, NULL)) < 0)
2295 ##### 4 return error;
2296 -
2297 4 5,6 if ((error = git_reference_iterator_new(&iter, repo)) < 0)
2298 ##### 7 goto cleanup;
2299 -
2300 92 8,18,19 while ((error = git_reference_next_name(&name, iter)) == 0) {
2301 88 9,10 if (!git_refspec_dst_matches(spec, name))
2302 84 11 continue;
2303 -
2304 4 12 dup = git__strdup(name);
2305 4 13 if (!dup) {
2306 ##### 14 error = -1;
2307 ##### 14 goto cleanup;
2308 - }
2309 -
2310 4 15,16 if ((error = git_vector_insert(&refs, dup)) < 0)
2311 ##### 17 goto cleanup;
2312 - }
2313 4 20 if (error == GIT_ITEROVER)
2314 4 21 error = 0;
2315 4 22 if (error < 0)
2316 ##### 23 goto cleanup;
2317 -
2318 8 24,28-30 git_vector_foreach(&refs, i, name) {
2319 4 25,26 if ((error = git_reference_remove(repo, name)) < 0)
2320 ##### 27 break;
2321 - }
2322 -
2323 - cleanup:
2324 4 31 git_reference_iterator_free(iter);
2325 8 32,34-36 git_vector_foreach(&refs, i, dup) {
2326 4 33 git__free(dup);
2327 - }
2328 4 37 git_vector_free(&refs);
2329 4 38 return error;
2330 - }
2331 -
2332 5 2 static int remove_remote_tracking(git_repository *repo, const char *remote_name)
2333 - {
2334 - git_remote *remote;
2335 - int error;
2336 - size_t i, count;
2337 -
2338 - /* we want to use what's on the config, regardless of changes to the instance in memory */
2339 5 2,3 if ((error = git_remote_lookup(&remote, repo, remote_name)) < 0)
2340 1 4 return error;
2341 -
2342 4 5 count = git_remote_refspec_count(remote);
2343 8 6,13,14 for (i = 0; i < count; i++) {
2344 4 7 const git_refspec *refspec = git_remote_get_refspec(remote, i);
2345 -
2346 - /* shouldn't ever actually happen */
2347 4 8 if (refspec == NULL)
2348 ##### 9 continue;
2349 -
2350 4 10,11 if ((error = remove_refs(repo, refspec)) < 0)
2351 ##### 12 break;
2352 - }
2353 -
2354 4 15 git_remote_free(remote);
2355 4 16 return error;
2356 - }
2357 -
2358 5 2 int git_remote_delete(git_repository *repo, const char *name)
2359 - {
2360 - int error;
2361 -
2362 5 2-4 assert(repo && name);
2363 -
2364 5 5-8 if ((error = remove_branch_config_related_entries(repo, name)) < 0 ||
2365 4 9,10 (error = remove_remote_tracking(repo, name)) < 0 ||
2366 - (error = rename_remote_config_section(repo, name, NULL)) < 0)
2367 1 11 return error;
2368 -
2369 4 12 return 0;
2370 - }
2371 -
2372 60 2 int git_remote_default_branch(git_buf *out, git_remote *remote)
2373 - {
2374 - const git_remote_head **heads;
2375 60 2 const git_remote_head *guess = NULL;
2376 - const git_oid *head_id;
2377 - size_t heads_len, i;
2378 - int error;
2379 -
2380 60 2,3 assert(out);
2381 -
2382 60 4,5 if ((error = git_remote_ls(&heads, &heads_len, remote)) < 0)
2383 ##### 6 return error;
2384 -
2385 60 7 if (heads_len == 0)
2386 1 8 return GIT_ENOTFOUND;
2387 -
2388 59 9 if (strcmp(heads[0]->name, GIT_HEAD_FILE))
2389 ##### 10 return GIT_ENOTFOUND;
2390 -
2391 59 11 git_buf_sanitize(out);
2392 - /* the first one must be HEAD so if that has the symref info, we're done */
2393 59 12 if (heads[0]->symref_target)
2394 55 13 return git_buf_puts(out, heads[0]->symref_target);
2395 -
2396 - /*
2397 - * If there's no symref information, we have to look over them
2398 - * and guess. We return the first match unless the master
2399 - * branch is a candidate. Then we return the master branch.
2400 - */
2401 4 14 head_id = &heads[0]->oid;
2402 -
2403 112 14,25,26 for (i = 1; i < heads_len; i++) {
2404 108 15,16 if (git_oid_cmp(head_id, &heads[i]->oid))
2405 98 17 continue;
2406 -
2407 10 18,19 if (git__prefixcmp(heads[i]->name, GIT_REFS_HEADS_DIR))
2408 8 20 continue;
2409 -
2410 2 21 if (!guess) {
2411 1 22 guess = heads[i];
2412 1 22 continue;
2413 - }
2414 -
2415 1 23 if (!git__strcmp(GIT_REFS_HEADS_MASTER_FILE, heads[i]->name)) {
2416 ##### 24 guess = heads[i];
2417 ##### 24 break;
2418 - }
2419 - }
2420 -
2421 4 27 if (!guess)
2422 3 28 return GIT_ENOTFOUND;
2423 -
2424 1 29 return git_buf_puts(out, guess->name);
2425 - }
2426 -
2427 10 2 int git_remote_upload(git_remote *remote, const git_strarray *refspecs, const git_push_options *opts)
2428 - {
2429 - size_t i;
2430 - int error;
2431 - git_push *push;
2432 - git_refspec *spec;
2433 10 2 const git_remote_callbacks *cbs = NULL;
2434 10 2 git_remote_connection_opts conn = GIT_REMOTE_CONNECTION_OPTIONS_INIT;
2435 -
2436 10 2,3 assert(remote);
2437 -
2438 10 4 if (!remote->repo) {
2439 1 5 git_error_set(GIT_ERROR_INVALID, "cannot download detached remote");
2440 1 6 return -1;
2441 - }
2442 -
2443 9 7 if (opts) {
2444 2 8 cbs = &opts->callbacks;
2445 2 8 conn.custom_headers = &opts->custom_headers;
2446 2 8 conn.proxy = &opts->proxy_opts;
2447 - }
2448 -
2449 9 9-12 if (!git_remote_connected(remote) &&
2450 - (error = git_remote__connect(remote, GIT_DIRECTION_PUSH, cbs, &conn)) < 0)
2451 ##### 13 goto cleanup;
2452 -
2453 9 14 free_refspecs(&remote->active_refspecs);
2454 9 15,16 if ((error = dwim_refspecs(&remote->active_refspecs, &remote->refspecs, &remote->refs)) < 0)
2455 ##### 17 goto cleanup;
2456 -
2457 9 18 if (remote->push) {
2458 1 19 git_push_free(remote->push);
2459 1 20 remote->push = NULL;
2460 - }
2461 -
2462 9 21,22 if ((error = git_push_new(&remote->push, remote)) < 0)
2463 ##### 23 return error;
2464 -
2465 9 24 push = remote->push;
2466 -
2467 9 24-26 if (opts && (error = git_push_set_options(push, opts)) < 0)
2468 ##### 27 goto cleanup;
2469 -
2470 9 28,29,36 if (refspecs && refspecs->count > 0) {
2471 18 30,34,35 for (i = 0; i < refspecs->count; i++) {
2472 9 31,32 if ((error = git_push_add_refspec(push, refspecs->strings[i])) < 0)
2473 ##### 33 goto cleanup;
2474 - }
2475 - } else {
2476 ##### 37,43-45 git_vector_foreach(&remote->refspecs, i, spec) {
2477 ##### 38 if (!spec->push)
2478 ##### 39 continue;
2479 ##### 40,41 if ((error = git_push_add_refspec(push, spec->string)) < 0)
2480 ##### 42 goto cleanup;
2481 - }
2482 - }
2483 -
2484 9 46,47 if ((error = git_push_finish(push, cbs)) < 0)
2485 2 48 goto cleanup;
2486 -
2487 7 49-52 if (cbs && cbs->push_update_reference &&
2488 ##### 51 (error = git_push_status_foreach(push, cbs->push_update_reference, cbs->payload)) < 0)
2489 ##### 53 goto cleanup;
2490 -
2491 - cleanup:
2492 9 54 return error;
2493 - }
2494 -
2495 6 2 int git_remote_push(git_remote *remote, const git_strarray *refspecs, const git_push_options *opts)
2496 - {
2497 - int error;
2498 6 2 const git_remote_callbacks *cbs = NULL;
2499 6 2 const git_strarray *custom_headers = NULL;
2500 6 2 const git_proxy_options *proxy = NULL;
2501 -
2502 6 2,3 assert(remote);
2503 -
2504 6 4 if (!remote->repo) {
2505 1 5 git_error_set(GIT_ERROR_INVALID, "cannot download detached remote");
2506 1 6 return -1;
2507 - }
2508 -
2509 5 7 if (opts) {
2510 2 8-10 GIT_ERROR_CHECK_VERSION(&opts->callbacks, GIT_REMOTE_CALLBACKS_VERSION, "git_remote_callbacks");
2511 2 11 cbs = &opts->callbacks;
2512 2 11 custom_headers = &opts->custom_headers;
2513 2 11-13 GIT_ERROR_CHECK_VERSION(&opts->proxy_opts, GIT_PROXY_OPTIONS_VERSION, "git_proxy_options");
2514 2 14 proxy = &opts->proxy_opts;
2515 - }
2516 -
2517 5 15,16 assert(remote);
2518 -
2519 5 17,18 if ((error = git_remote_connect(remote, GIT_DIRECTION_PUSH, cbs, proxy, custom_headers)) < 0)
2520 ##### 19 return error;
2521 -
2522 5 20,21 if ((error = git_remote_upload(remote, refspecs, opts)) < 0)
2523 ##### 22 return error;
2524 -
2525 5 23 error = git_remote_update_tips(remote, cbs, 0, 0, NULL);
2526 -
2527 5 24 git_remote_disconnect(remote);
2528 5 25 return error;
2529 - }
2530 -
2531 - #define PREFIX "url"
2532 - #define SUFFIX_FETCH "insteadof"
2533 - #define SUFFIX_PUSH "pushinsteadof"
2534 -
2535 351 2 char *apply_insteadof(git_config *config, const char *url, int direction)
2536 - {
2537 - size_t match_length, prefix_length, suffix_length;
2538 351 2 char *replacement = NULL;
2539 - const char *regexp;
2540 -
2541 351 2 git_buf result = GIT_BUF_INIT;
2542 - git_config_entry *entry;
2543 - git_config_iterator *iter;
2544 -
2545 351 2,3 assert(config);
2546 351 4,5 assert(url);
2547 351 6-8 assert(direction == GIT_DIRECTION_FETCH || direction == GIT_DIRECTION_PUSH);
2548 -
2549 - /* Add 1 to prefix/suffix length due to the additional escaped dot */
2550 351 9 prefix_length = strlen(PREFIX) + 1;
2551 351 9 if (direction == GIT_DIRECTION_FETCH) {
2552 339 10 regexp = PREFIX "\\..*\\." SUFFIX_FETCH;
2553 339 10 suffix_length = strlen(SUFFIX_FETCH) + 1;
2554 - } else {
2555 12 11 regexp = PREFIX "\\..*\\." SUFFIX_PUSH;
2556 12 11 suffix_length = strlen(SUFFIX_PUSH) + 1;
2557 - }
2558 -
2559 351 12,13 if (git_config_iterator_glob_new(&iter, config, regexp) < 0)
2560 ##### 14 return NULL;
2561 -
2562 351 15 match_length = 0;
2563 423 15,23,24 while (git_config_next(&entry, iter) == 0) {
2564 - size_t n, replacement_length;
2565 -
2566 - /* Check if entry value is a prefix of URL */
2567 72 16,17 if (git__prefixcmp(url, entry->value))
2568 52 18 continue;
2569 - /* Check if entry value is longer than previous
2570 - * prefixes */
2571 20 19 if ((n = strlen(entry->value)) <= match_length)
2572 ##### 20 continue;
2573 -
2574 20 21 git__free(replacement);
2575 20 22 match_length = n;
2576 -
2577 - /* Cut off prefix and suffix of the value */
2578 20 22 replacement_length =
2579 20 22 strlen(entry->name) - (prefix_length + suffix_length);
2580 20 22 replacement = git__strndup(entry->name + prefix_length,
2581 - replacement_length);
2582 - }
2583 -
2584 351 25 git_config_iterator_free(iter);
2585 -
2586 351 26 if (match_length == 0)
2587 338 27 return git__strdup(url);
2588 -
2589 13 28 git_buf_printf(&result, "%s%s", replacement, url + match_length);
2590 -
2591 13 29 git__free(replacement);
2592 -
2593 13 30 return result.ptr;
2594 - }