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