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