remote.c 62.3 KB
Newer Older
Carlos Martín Nieto committed
1
/*
Edward Thomson committed
2
 * Copyright (C) the libgit2 contributors. All rights reserved.
Carlos Martín Nieto committed
3
 *
Vicent Marti committed
4 5
 * This file is part of libgit2, distributed under the GNU GPL v2 with
 * a Linking Exception. For full terms see the included COPYING file.
Carlos Martín Nieto committed
6 7
 */

8 9
#include "remote.h"

Carlos Martín Nieto committed
10 11
#include "git2/config.h"
#include "git2/types.h"
12
#include "git2/oid.h"
13
#include "git2/net.h"
Carlos Martín Nieto committed
14 15 16

#include "config.h"
#include "repository.h"
17
#include "fetch.h"
18
#include "refs.h"
19 20
#include "refspec.h"
#include "fetchhead.h"
21
#include "push.h"
Carlos Martín Nieto committed
22

23 24 25
#define CONFIG_URL_FMT "remote.%s.url"
#define CONFIG_PUSHURL_FMT "remote.%s.pushurl"
#define CONFIG_FETCH_FMT "remote.%s.fetch"
26
#define CONFIG_PUSH_FMT "remote.%s.push"
27
#define CONFIG_TAGOPT_FMT "remote.%s.tagopt"
28

29
static int dwim_refspecs(git_vector *out, git_vector *refspecs, git_vector *refs);
30
static int lookup_remote_prune_config(git_remote *remote, git_config *config, const char *name);
31
char *apply_insteadof(git_config *config, const char *url, int direction);
32

33
static int add_refspec_to(git_vector *vector, const char *string, bool is_fetch)
Carlos Martín Nieto committed
34
{
35
	git_refspec *spec;
Carlos Martín Nieto committed
36

37
	spec = git__calloc(1, sizeof(git_refspec));
38
	GIT_ERROR_CHECK_ALLOC(spec);
39

40 41 42 43
	if (git_refspec__parse(spec, string, is_fetch) < 0) {
		git__free(spec);
		return -1;
	}
44 45

	spec->push = !is_fetch;
46
	if (git_vector_insert(vector, spec) < 0) {
47
		git_refspec__dispose(spec);
48 49 50
		git__free(spec);
		return -1;
	}
Carlos Martín Nieto committed
51

52
	return 0;
Carlos Martín Nieto committed
53 54
}

55 56 57 58 59
static int add_refspec(git_remote *remote, const char *string, bool is_fetch)
{
	return add_refspec_to(&remote->refspecs, string, is_fetch);
}

60 61
static int download_tags_value(git_remote *remote, git_config *cfg)
{
62
	git_config_entry *ce;
63 64 65 66 67 68
	git_buf buf = GIT_BUF_INIT;
	int error;

	if (git_buf_printf(&buf, "remote.%s.tagopt", remote->name) < 0)
		return -1;

69
	error = git_config__lookup_entry(&ce, cfg, git_buf_cstr(&buf), false);
70
	git_buf_dispose(&buf);
71

72 73 74 75 76
	if (!error && ce && ce->value) {
		if (!strcmp(ce->value, "--no-tags"))
			remote->download_tags = GIT_REMOTE_DOWNLOAD_TAGS_NONE;
		else if (!strcmp(ce->value, "--tags"))
			remote->download_tags = GIT_REMOTE_DOWNLOAD_TAGS_ALL;
77
	}
78

79
	git_config_entry_free(ce);
80 81 82
	return error;
}

83 84
static int ensure_remote_name_is_valid(const char *name)
{
85
	int error = 0;
86

87
	if (!git_remote_is_valid_name(name)) {
88 89
		git_error_set(
			GIT_ERROR_CONFIG,
90
			"'%s' is not a valid remote name.", name ? name : "(null)");
91 92 93 94 95 96
		error = GIT_EINVALIDSPEC;
	}

	return error;
}

97 98 99 100
static int write_add_refspec(git_repository *repo, const char *name, const char *refspec, bool fetch)
{
	git_config *cfg;
	git_buf var = GIT_BUF_INIT;
101
	git_refspec spec;
102 103 104 105 106 107 108 109 110 111 112
	const char *fmt;
	int error;

	if ((error = git_repository_config__weakptr(&cfg, repo)) < 0)
	    return error;

	fmt = fetch ? CONFIG_FETCH_FMT : CONFIG_PUSH_FMT;

	if ((error = ensure_remote_name_is_valid(name)) < 0)
		return error;

113
	if ((error = git_refspec__parse(&spec, refspec, fetch)) < 0) {
114
		if (git_error_last()->klass != GIT_ERROR_NOMEMORY)
115 116 117 118 119
			error = GIT_EINVALIDSPEC;

		return error;
	}

120
	git_refspec__dispose(&spec);
121

122 123 124 125 126 127 128 129 130 131 132 133 134
	if ((error = git_buf_printf(&var, fmt, name)) < 0)
		return error;

	/*
	 * "$^" is a unmatcheable regexp: it will not match anything at all, so
	 * all values will be considered new and we will not replace any
	 * present value.
	 */
	if ((error = git_config_set_multivar(cfg, var.ptr, "$^", refspec)) < 0) {
		goto cleanup;
	}

cleanup:
135
	git_buf_dispose(&var);
136 137 138
	return 0;
}

139 140
static int canonicalize_url(git_buf *out, const char *in)
{
141
	if (in == NULL || strlen(in) == 0) {
142
		git_error_set(GIT_ERROR_INVALID, "cannot set empty URL");
143 144
		return GIT_EINVALIDSPEC;
	}
145

146
#ifdef GIT_WIN32
147 148 149 150 151
	/* Given a UNC path like \\server\path, we need to convert this
	 * to //server/path for compatibility with core git.
	 */
	if (in[0] == '\\' && in[1] == '\\' &&
		(git__isalpha(in[2]) || git__isdigit(in[2]))) {
152
		const char *c;
153 154 155 156 157 158 159 160 161 162
		for (c = in; *c; c++)
			git_buf_putc(out, *c == '\\' ? '/' : *c);

		return git_buf_oom(out) ? -1 : 0;
	}
#endif

	return git_buf_puts(out, in);
}

163 164 165 166 167 168 169 170
static int default_fetchspec_for_name(git_buf *buf, const char *name)
{
	if (git_buf_printf(buf, "+refs/heads/*:refs/remotes/%s/*", name) < 0)
		return -1;

	return 0;
}

171 172 173 174 175 176 177 178 179 180 181 182 183 184 185
static int ensure_remote_doesnot_exist(git_repository *repo, const char *name)
{
	int error;
	git_remote *remote;

	error = git_remote_lookup(&remote, repo, name);

	if (error == GIT_ENOTFOUND)
		return 0;

	if (error < 0)
		return error;

	git_remote_free(remote);

186
	git_error_set(GIT_ERROR_CONFIG, "remote '%s' already exists", name);
187 188 189 190

	return GIT_EEXISTS;
}

191
int git_remote_create_options_init(git_remote_create_options *opts, unsigned int version)
192
{
193 194 195 196 197
	GIT_INIT_STRUCTURE_FROM_TEMPLATE(
		opts, version, git_remote_create_options, GIT_REMOTE_CREATE_OPTIONS_INIT);
	return 0;
}

198 199 200 201 202
int git_remote_create_init_options(git_remote_create_options *opts, unsigned int version)
{
	return git_remote_create_options_init(opts, version);
}

203
int git_remote_create_with_opts(git_remote **out, const char *url, const git_remote_create_options *opts)
204 205
{
	git_remote *remote = NULL;
206
	git_config *config_ro = NULL, *config_rw;
207 208
	git_buf canonical_url = GIT_BUF_INIT;
	git_buf var = GIT_BUF_INIT;
209
	git_buf specbuf = GIT_BUF_INIT;
210
	const git_remote_create_options dummy_opts = GIT_REMOTE_CREATE_OPTIONS_INIT;
211
	int error = -1;
212

213
	assert(out && url);
214

215 216 217 218
	if (!opts) {
		opts = &dummy_opts;
	}

219
	GIT_ERROR_CHECK_VERSION(opts, GIT_REMOTE_CREATE_OPTIONS_VERSION, "git_remote_create_options");
220 221 222 223 224 225 226 227 228 229 230 231 232 233

	if (opts->name != NULL) {
		if ((error = ensure_remote_name_is_valid(opts->name)) < 0)
			return error;

		if (opts->repository &&
		    (error = ensure_remote_doesnot_exist(opts->repository, opts->name)) < 0)
			return error;
	}

	if (opts->repository) {
		if ((error = git_repository_config_snapshot(&config_ro, opts->repository)) < 0)
			goto on_error;
	}
234

235
	remote = git__calloc(1, sizeof(git_remote));
236
	GIT_ERROR_CHECK_ALLOC(remote);
237

238
	remote->repo = opts->repository;
239

240
	if ((error = git_vector_init(&remote->refs, 8, NULL)) < 0 ||
241
		(error = canonicalize_url(&canonical_url, url)) < 0)
242
		goto on_error;
243

244
	if (opts->repository && !(opts->flags & GIT_REMOTE_CREATE_SKIP_INSTEADOF)) {
245 246 247 248
		remote->url = apply_insteadof(config_ro, canonical_url.ptr, GIT_DIRECTION_FETCH);
	} else {
		remote->url = git__strdup(canonical_url.ptr);
	}
249
	GIT_ERROR_CHECK_ALLOC(remote->url);
250

251 252
	if (opts->name != NULL) {
		remote->name = git__strdup(opts->name);
253
		GIT_ERROR_CHECK_ALLOC(remote->name);
254

255 256 257 258
		if (opts->repository &&
		    ((error = git_buf_printf(&var, CONFIG_URL_FMT, opts->name)) < 0 ||
		    (error = git_repository_config__weakptr(&config_rw, opts->repository)) < 0 ||
		    (error = git_config_set_string(config_rw, var.ptr, canonical_url.ptr)) < 0))
259
			goto on_error;
260 261
	}

262 263 264 265 266 267 268 269 270 271 272 273 274
	if (opts->fetchspec != NULL ||
	    (opts->name && !(opts->flags & GIT_REMOTE_CREATE_SKIP_DEFAULT_FETCHSPEC))) {
		const char *fetch = NULL;
		if (opts->fetchspec) {
			fetch = opts->fetchspec;
		} else {
			if ((error = default_fetchspec_for_name(&specbuf, opts->name)) < 0)
				goto on_error;

			fetch = git_buf_cstr(&specbuf);
		}

		if ((error = add_refspec(remote, fetch, true)) < 0)
275 276
			goto on_error;

277
		/* only write for named remotes with a repository */
278
		if (opts->repository && opts->name &&
279
		    ((error = write_add_refspec(opts->repository, opts->name, fetch, true)) < 0 ||
280
		    (error = lookup_remote_prune_config(remote, config_ro, opts->name)) < 0))
281 282
			goto on_error;

283
		/* Move the data over to where the matching functions can find them */
Leo Yang committed
284
		if ((error = dwim_refspecs(&remote->active_refspecs, &remote->refspecs, &remote->refs)) < 0)
285
			goto on_error;
286 287
	}

288
	/* A remote without a name doesn't download tags */
289
	if (!opts->name)
290
		remote->download_tags = GIT_REMOTE_DOWNLOAD_TAGS_NONE;
291 292 293
	else
		remote->download_tags = GIT_REMOTE_DOWNLOAD_TAGS_AUTO;

294

295
	git_buf_dispose(&var);
296

297
	*out = remote;
Edward Thomson committed
298
	error = 0;
299 300

on_error:
Edward Thomson committed
301 302 303
	if (error)
		git_remote_free(remote);

304
	git_config_free(config_ro);
305
	git_buf_dispose(&specbuf);
306 307
	git_buf_dispose(&canonical_url);
	git_buf_dispose(&var);
308
	return error;
309 310
}

311 312 313 314
int git_remote_create(git_remote **out, git_repository *repo, const char *name, const char *url)
{
	git_buf buf = GIT_BUF_INIT;
	int error;
315
	git_remote_create_options opts = GIT_REMOTE_CREATE_OPTIONS_INIT;
316

317 318 319 320 321 322 323 324 325 326 327 328
	/* Those 2 tests are duplicated here because of backward-compatibility */
	if ((error = ensure_remote_name_is_valid(name)) < 0)
		return error;

	if (canonicalize_url(&buf, url) < 0)
		return GIT_ERROR;

	git_buf_clear(&buf);

	opts.repository = repo;
	opts.name = name;

329
	error = git_remote_create_with_opts(out, url, &opts);
330

331
	git_buf_dispose(&buf);
332

333
	return error;
334 335
}

336 337 338
int git_remote_create_with_fetchspec(git_remote **out, git_repository *repo, const char *name, const char *url, const char *fetch)
{
	int error;
339
	git_remote_create_options opts = GIT_REMOTE_CREATE_OPTIONS_INIT;
340 341 342 343

	if ((error = ensure_remote_name_is_valid(name)) < 0)
		return error;

344 345 346
	opts.repository = repo;
	opts.name = name;
	opts.fetchspec = fetch;
347
	opts.flags = GIT_REMOTE_CREATE_SKIP_DEFAULT_FETCHSPEC;
348

349
	return git_remote_create_with_opts(out, url, &opts);
350 351
}

352
int git_remote_create_anonymous(git_remote **out, git_repository *repo, const char *url)
353
{
354 355 356 357
	git_remote_create_options opts = GIT_REMOTE_CREATE_OPTIONS_INIT;

	opts.repository = repo;

358
	return git_remote_create_with_opts(out, url, &opts);
359 360
}

361 362
int git_remote_create_detached(git_remote **out, const char *url)
{
363
	return git_remote_create_with_opts(out, url, NULL);
364 365
}

366
int git_remote_dup(git_remote **dest, git_remote *source)
Arthur Schreiber committed
367
{
368
	size_t i;
369
	int error = 0;
370
	git_refspec *spec;
Arthur Schreiber committed
371
	git_remote *remote = git__calloc(1, sizeof(git_remote));
372
	GIT_ERROR_CHECK_ALLOC(remote);
Arthur Schreiber committed
373 374 375

	if (source->name != NULL) {
		remote->name = git__strdup(source->name);
376
		GIT_ERROR_CHECK_ALLOC(remote->name);
Arthur Schreiber committed
377 378 379 380
	}

	if (source->url != NULL) {
		remote->url = git__strdup(source->url);
381
		GIT_ERROR_CHECK_ALLOC(remote->url);
Arthur Schreiber committed
382 383 384 385
	}

	if (source->pushurl != NULL) {
		remote->pushurl = git__strdup(source->pushurl);
386
		GIT_ERROR_CHECK_ALLOC(remote->pushurl);
Arthur Schreiber committed
387 388 389 390
	}

	remote->repo = source->repo;
	remote->download_tags = source->download_tags;
391
	remote->prune_refs = source->prune_refs;
Arthur Schreiber committed
392

393 394 395 396 397
	if (git_vector_init(&remote->refs, 32, NULL) < 0 ||
	    git_vector_init(&remote->refspecs, 2, NULL) < 0 ||
	    git_vector_init(&remote->active_refspecs, 2, NULL) < 0) {
		error = -1;
		goto cleanup;
Arthur Schreiber committed
398 399
	}

400 401 402 403
	git_vector_foreach(&source->refspecs, i, spec) {
		if ((error = add_refspec(remote, spec->string, !spec->push)) < 0)
			goto cleanup;
	}
404

Arthur Schreiber committed
405 406
	*dest = remote;

407 408 409 410 411 412
cleanup:

	if (error < 0)
		git__free(remote);

	return error;
Arthur Schreiber committed
413 414
}

415 416 417 418 419 420 421
struct refspec_cb_data {
	git_remote *remote;
	int fetch;
};

static int refspec_cb(const git_config_entry *entry, void *payload)
{
422
	struct refspec_cb_data *data = (struct refspec_cb_data *)payload;
423
	return add_refspec(data->remote, entry->value, data->fetch);
424 425
}

426
static int get_optional_config(
427 428
	bool *found, git_config *config, git_buf *buf,
	git_config_foreach_cb cb, void *payload)
429 430 431 432 433 434 435 436
{
	int error = 0;
	const char *key = git_buf_cstr(buf);

	if (git_buf_oom(buf))
		return -1;

	if (cb != NULL)
437
		error = git_config_get_multivar_foreach(config, key, NULL, cb, payload);
438 439 440
	else
		error = git_config_get_string(payload, config, key);

441 442 443
	if (found)
		*found = !error;

444
	if (error == GIT_ENOTFOUND) {
445
		git_error_clear();
446 447 448 449 450 451
		error = 0;
	}

	return error;
}

452
int git_remote_lookup(git_remote **out, git_repository *repo, const char *name)
Carlos Martín Nieto committed
453
{
454
	git_remote *remote = NULL;
455
	git_buf buf = GIT_BUF_INIT;
Carlos Martín Nieto committed
456
	const char *val;
457
	int error = 0;
458
	git_config *config;
459
	struct refspec_cb_data data = { NULL };
460
	bool optional_setting_found = false, found;
461

462 463
	assert(out && repo && name);

464 465 466
	if ((error = ensure_remote_name_is_valid(name)) < 0)
		return error;

467
	if ((error = git_repository_config_snapshot(&config, repo)) < 0)
468
		return error;
469

470
	remote = git__calloc(1, sizeof(git_remote));
471
	GIT_ERROR_CHECK_ALLOC(remote);
Carlos Martín Nieto committed
472 473

	remote->name = git__strdup(name);
474
	GIT_ERROR_CHECK_ALLOC(remote->name);
Carlos Martín Nieto committed
475

476 477
	if (git_vector_init(&remote->refs, 32, NULL) < 0 ||
	    git_vector_init(&remote->refspecs, 2, NULL) < 0 ||
478
	    git_vector_init(&remote->passive_refspecs, 2, NULL) < 0 ||
479
	    git_vector_init(&remote->active_refspecs, 2, NULL) < 0) {
480 481 482
		error = -1;
		goto cleanup;
	}
483

484
	if ((error = git_buf_printf(&buf, "remote.%s.url", name)) < 0)
485
		goto cleanup;
Carlos Martín Nieto committed
486

487
	if ((error = get_optional_config(&found, config, &buf, NULL, (void *)&val)) < 0)
Carlos Martín Nieto committed
488
		goto cleanup;
489

490 491
	optional_setting_found |= found;

492
	remote->repo = repo;
493
	remote->download_tags = GIT_REMOTE_DOWNLOAD_TAGS_AUTO;
494 495

	if (found && strlen(val) > 0) {
496
		remote->url = apply_insteadof(config, val, GIT_DIRECTION_FETCH);
497
		GIT_ERROR_CHECK_ALLOC(remote->url);
498
	}
Carlos Martín Nieto committed
499

500
	val = NULL;
501
	git_buf_clear(&buf);
502
	git_buf_printf(&buf, "remote.%s.pushurl", name);
503

504
	if ((error = get_optional_config(&found, config, &buf, NULL, (void *)&val)) < 0)
505 506
		goto cleanup;

507 508 509 510
	optional_setting_found |= found;

	if (!optional_setting_found) {
		error = GIT_ENOTFOUND;
511
		git_error_set(GIT_ERROR_CONFIG, "remote '%s' does not exist", name);
512
		goto cleanup;
513
	}
514

515
	if (found && strlen(val) > 0) {
516
		remote->pushurl = apply_insteadof(config, val, GIT_DIRECTION_PUSH);
517
		GIT_ERROR_CHECK_ALLOC(remote->pushurl);
518 519
	}

520 521
	data.remote = remote;
	data.fetch = true;
522

523
	git_buf_clear(&buf);
524 525
	git_buf_printf(&buf, "remote.%s.fetch", name);

526
	if ((error = get_optional_config(NULL, config, &buf, refspec_cb, &data)) < 0)
527
		goto cleanup;
Carlos Martín Nieto committed
528

529
	data.fetch = false;
530 531
	git_buf_clear(&buf);
	git_buf_printf(&buf, "remote.%s.push", name);
Carlos Martín Nieto committed
532

533
	if ((error = get_optional_config(NULL, config, &buf, refspec_cb, &data)) < 0)
Carlos Martín Nieto committed
534 535
		goto cleanup;

536
	if ((error = download_tags_value(remote, config)) < 0)
537 538
		goto cleanup;

539 540 541 542
	if ((error = lookup_remote_prune_config(remote, config, name)) < 0)
		goto cleanup;

	/* Move the data over to where the matching functions can find them */
Leo Yang committed
543
	if ((error = dwim_refspecs(&remote->active_refspecs, &remote->refspecs, &remote->refs)) < 0)
544 545 546 547 548 549
		goto cleanup;

	*out = remote;

cleanup:
	git_config_free(config);
550
	git_buf_dispose(&buf);
551 552 553 554 555 556 557 558 559 560 561 562

	if (error < 0)
		git_remote_free(remote);

	return error;
}

static int lookup_remote_prune_config(git_remote *remote, git_config *config, const char *name)
{
	git_buf buf = GIT_BUF_INIT;
	int error = 0;

563 564 565 566
	git_buf_printf(&buf, "remote.%s.prune", name);

	if ((error = git_config_get_bool(&remote->prune_refs, config, git_buf_cstr(&buf))) < 0) {
		if (error == GIT_ENOTFOUND) {
567
			git_error_clear();
568 569 570

			if ((error = git_config_get_bool(&remote->prune_refs, config, "fetch.prune")) < 0) {
				if (error == GIT_ENOTFOUND) {
571
					git_error_clear();
David Calavera committed
572
					error = 0;
573 574 575 576 577
				}
			}
		}
	}

578
	git_buf_dispose(&buf);
Carlos Martín Nieto committed
579 580 581
	return error;
}

Ben Straub committed
582
const char *git_remote_name(const git_remote *remote)
Carlos Martín Nieto committed
583
{
584
	assert(remote);
Carlos Martín Nieto committed
585 586 587
	return remote->name;
}

Etienne Samson committed
588 589 590 591 592 593
git_repository *git_remote_owner(const git_remote *remote)
{
	assert(remote);
	return remote->repo;
}

Ben Straub committed
594
const char *git_remote_url(const git_remote *remote)
Carlos Martín Nieto committed
595
{
596
	assert(remote);
Carlos Martín Nieto committed
597 598 599
	return remote->url;
}

600
static int set_url(git_repository *repo, const char *remote, const char *pattern, const char *url)
601
{
602 603 604
	git_config *cfg;
	git_buf buf = GIT_BUF_INIT, canonical_url = GIT_BUF_INIT;
	int error;
605

606
	assert(repo && remote);
607

608 609 610 611 612 613 614 615 616 617 618 619 620 621 622 623 624 625 626
	if ((error = ensure_remote_name_is_valid(remote)) < 0)
		return error;

	if ((error = git_repository_config__weakptr(&cfg, repo)) < 0)
		return error;

	if ((error = git_buf_printf(&buf, pattern, remote)) < 0)
		return error;

	if (url) {
		if ((error = canonicalize_url(&canonical_url, url)) < 0)
			goto cleanup;

		error = git_config_set_string(cfg, buf.ptr, url);
	} else {
		error = git_config_delete_entry(cfg, buf.ptr);
	}

cleanup:
627 628
	git_buf_dispose(&canonical_url);
	git_buf_dispose(&buf);
629 630 631 632 633 634 635

	return error;
}

int git_remote_set_url(git_repository *repo, const char *remote, const char *url)
{
	return set_url(repo, remote, CONFIG_URL_FMT, url);
636 637
}

Ben Straub committed
638
const char *git_remote_pushurl(const git_remote *remote)
639 640 641 642 643
{
	assert(remote);
	return remote->pushurl;
}

644
int git_remote_set_pushurl(git_repository *repo, const char *remote, const char* url)
645
{
646
	return set_url(repo, remote, CONFIG_PUSHURL_FMT, url);
647 648
}

649
static int resolve_url(git_buf *resolved_url, const char *url, int direction, const git_remote_callbacks *callbacks)
650
{
651 652 653 654 655 656 657 658 659 660 661
	int status;

	if (callbacks && callbacks->resolve_url) {
		git_buf_clear(resolved_url);
		status = callbacks->resolve_url(resolved_url, url, direction, callbacks->payload);
		if (status != GIT_PASSTHROUGH) {
			git_error_set_after_callback_function(status, "git_resolve_url_cb");
			git_buf_sanitize(resolved_url);
			return status;
		}
	}
662

663 664 665 666 667 668 669 670
	return git_buf_sets(resolved_url, url);
}

int git_remote__urlfordirection(git_buf *url_out, struct git_remote *remote, int direction, const git_remote_callbacks *callbacks)
{
	const char *url = NULL;

	assert(remote);
671 672
	assert(direction == GIT_DIRECTION_FETCH || direction == GIT_DIRECTION_PUSH);

Ben Straub committed
673
	if (direction == GIT_DIRECTION_FETCH) {
674 675 676
		url = remote->url;
	} else if (direction == GIT_DIRECTION_PUSH) {
		url = remote->pushurl ? remote->pushurl : remote->url;
677 678
	}

679 680 681 682 683 684
	if (!url) {
		git_error_set(GIT_ERROR_INVALID,
			"malformed remote '%s' - missing %s URL",
			remote->name ? remote->name : "(anonymous)",
			direction == GIT_DIRECTION_FETCH ? "fetch" : "push");
		return GIT_EINVALID;
685
	}
686
	return resolve_url(url_out, url, direction, callbacks);
687 688
}

689 690 691 692 693 694 695 696 697
int set_transport_callbacks(git_transport *t, const git_remote_callbacks *cbs)
{
	if (!t->set_callbacks || !cbs)
		return 0;

	return t->set_callbacks(t, cbs->sideband_progress, NULL,
				cbs->certificate_check, cbs->payload);
}

Matt Burke committed
698
static int set_transport_custom_headers(git_transport *t, const git_strarray *custom_headers)
699
{
700
	if (!t->set_custom_headers)
701 702 703 704 705
		return 0;

	return t->set_custom_headers(t, custom_headers);
}

706
int git_remote__connect(git_remote *remote, git_direction direction, const git_remote_callbacks *callbacks, const git_remote_connection_opts *conn)
707 708
{
	git_transport *t;
709
	git_buf url = GIT_BUF_INIT;
710
	int flags = GIT_TRANSPORTFLAGS_NONE;
711
	int error;
712
	void *payload = NULL;
713 714
	git_cred_acquire_cb credentials = NULL;
	git_transport_cb transport = NULL;
715

716 717
	assert(remote);

718
	if (callbacks) {
719
		GIT_ERROR_CHECK_VERSION(callbacks, GIT_REMOTE_CALLBACKS_VERSION, "git_remote_callbacks");
720
		credentials = callbacks->credentials;
721
		transport   = callbacks->transport;
722 723 724
		payload     = callbacks->payload;
	}

725
	if (conn->proxy)
726
		GIT_ERROR_CHECK_VERSION(conn->proxy, GIT_PROXY_OPTIONS_VERSION, "git_proxy_options");
727

728 729
	t = remote->transport;

730 731
	if ((error = git_remote__urlfordirection(&url, remote, direction, callbacks)) < 0)
		goto on_error;
732

733 734
	/* If we don't have a transport object yet, and the caller specified a
	 * custom transport factory, use that */
735 736
	if (!t && transport &&
		(error = transport(&t, remote, payload)) < 0)
737
		goto on_error;
738 739 740

	/* If we still don't have a transport, then use the global
	 * transport registrations which map URI schemes to transport factories */
741 742
	if (!t && (error = git_transport_new(&t, remote, url.ptr)) < 0)
		goto on_error;
743

744
	if ((error = set_transport_custom_headers(t, conn->custom_headers)) != 0)
745 746
		goto on_error;

747
	if ((error = set_transport_callbacks(t, callbacks)) < 0 ||
748
	    (error = t->connect(t, url.ptr, credentials, payload, conn->proxy, direction, flags)) != 0)
749
		goto on_error;
750 751 752

	remote->transport = t;

753 754
	git_buf_dispose(&url);

755
	return 0;
756

757
on_error:
758 759 760 761
	if (t)
		t->free(t);

	git_buf_dispose(&url);
762 763 764 765

	if (t == remote->transport)
		remote->transport = NULL;

766
	return error;
767 768
}

769 770 771 772 773 774 775 776 777 778
int git_remote_connect(git_remote *remote, git_direction direction, const git_remote_callbacks *callbacks, const git_proxy_options *proxy, const git_strarray *custom_headers)
{
	git_remote_connection_opts conn;

	conn.proxy = proxy;
	conn.custom_headers = custom_headers;

	return git_remote__connect(remote, direction, callbacks, &conn);
}

779
int git_remote_ls(const git_remote_head ***out, size_t *size, git_remote *remote)
780
{
781 782
	assert(remote);

783
	if (!remote->transport) {
784
		git_error_set(GIT_ERROR_NET, "this remote has never connected");
785 786 787
		return -1;
	}

788
	return remote->transport->ls(out, size, remote->transport);
789 790
}

791 792 793
int git_remote__get_http_proxy(git_remote *remote, bool use_ssl, char **proxy_url)
{
	git_config *cfg;
794
	git_config_entry *ce = NULL;
795
	git_buf val = GIT_BUF_INIT;
796
	int error;
797 798 799

	assert(remote);

800
	if (!proxy_url || !remote->repo)
801 802 803 804
		return -1;

	*proxy_url = NULL;

805 806
	if ((error = git_repository_config__weakptr(&cfg, remote->repo)) < 0)
		return error;
807 808 809 810 811

	/* Go through the possible sources for proxy configuration, from most specific
	 * to least specific. */

	/* remote.<name>.proxy config setting */
812
	if (remote->name && remote->name[0]) {
813 814
		git_buf buf = GIT_BUF_INIT;

815 816
		if ((error = git_buf_printf(&buf, "remote.%s.proxy", remote->name)) < 0)
			return error;
817

818
		error = git_config__lookup_entry(&ce, cfg, git_buf_cstr(&buf), false);
819
		git_buf_dispose(&buf);
820

821
		if (error < 0)
822
			return error;
823

824
		if (ce && ce->value) {
825
			*proxy_url = git__strdup(ce->value);
826 827
			goto found;
		}
828 829 830
	}

	/* http.proxy config setting */
831
	if ((error = git_config__lookup_entry(&ce, cfg, "http.proxy", false)) < 0)
832
		return error;
833

834
	if (ce && ce->value) {
835
		*proxy_url = git__strdup(ce->value);
836 837
		goto found;
	}
838

839 840
	/* http_proxy / https_proxy environment variables */
	error = git__getenv(&val, use_ssl ? "https_proxy" : "http_proxy");
841

842 843
	/* try uppercase environment variables */
	if (error == GIT_ENOTFOUND)
844
		error = git__getenv(&val, use_ssl ? "HTTPS_PROXY" : "HTTP_PROXY");
845 846

	if (error < 0) {
847
		if (error == GIT_ENOTFOUND) {
848
			git_error_clear();
849 850 851 852
			error = 0;
		}

		return error;
853
	}
854 855 856 857

	*proxy_url = git_buf_detach(&val);

found:
858
	GIT_ERROR_CHECK_ALLOC(*proxy_url);
859
	git_config_entry_free(ce);
860 861 862 863

	return 0;
}

864 865
/* DWIM `refspecs` based on `refs` and append the output to `out` */
static int dwim_refspecs(git_vector *out, git_vector *refspecs, git_vector *refs)
866
{
867
	size_t i;
868 869 870
	git_refspec *spec;

	git_vector_foreach(refspecs, i, spec) {
871 872 873
		if (git_refspec__dwim_one(out, spec, refs) < 0)
			return -1;
	}
874

875 876
	return 0;
}
877

878 879 880 881
static void free_refspecs(git_vector *vec)
{
	size_t i;
	git_refspec *spec;
882

883
	git_vector_foreach(vec, i, spec) {
884
		git_refspec__dispose(spec);
885
		git__free(spec);
886 887
	}

888
	git_vector_clear(vec);
889 890 891 892 893 894 895 896 897 898
}

static int remote_head_cmp(const void *_a, const void *_b)
{
	const git_remote_head *a = (git_remote_head *) _a;
	const git_remote_head *b = (git_remote_head *) _b;

	return git__strcmp_cb(a->name, b->name);
}

899 900 901 902 903 904 905 906 907 908 909 910 911 912 913 914 915 916 917
static int ls_to_vector(git_vector *out, git_remote *remote)
{
	git_remote_head **heads;
	size_t heads_len, i;

	if (git_remote_ls((const git_remote_head ***)&heads, &heads_len, remote) < 0)
		return -1;

	if (git_vector_init(out, heads_len, remote_head_cmp) < 0)
		return -1;

	for (i = 0; i < heads_len; i++) {
		if (git_vector_insert(out, heads[i]) < 0)
			return -1;
	}

	return 0;
}

918
int git_remote_download(git_remote *remote, const git_strarray *refspecs, const git_fetch_options *opts)
919
{
920
	int error = -1;
921
	size_t i;
922
	git_vector *to_active, specs = GIT_VECTOR_INIT, refs = GIT_VECTOR_INIT;
923
	const git_remote_callbacks *cbs = NULL;
924
	const git_strarray *custom_headers = NULL;
925
	const git_proxy_options *proxy = NULL;
926

927
	assert(remote);
928

929
	if (!remote->repo) {
930
		git_error_set(GIT_ERROR_INVALID, "cannot download detached remote");
931 932 933
		return -1;
	}

934
	if (opts) {
935
		GIT_ERROR_CHECK_VERSION(&opts->callbacks, GIT_REMOTE_CALLBACKS_VERSION, "git_remote_callbacks");
936
		cbs = &opts->callbacks;
937
		custom_headers = &opts->custom_headers;
938
		GIT_ERROR_CHECK_VERSION(&opts->proxy_opts, GIT_PROXY_OPTIONS_VERSION, "git_proxy_options");
939
		proxy = &opts->proxy_opts;
940 941 942
	}

	if (!git_remote_connected(remote) &&
943
	    (error = git_remote_connect(remote, GIT_DIRECTION_FETCH, cbs, proxy, custom_headers)) < 0)
944 945
		goto on_error;

946
	if (ls_to_vector(&refs, remote) < 0)
947 948
		return -1;

949 950 951
	if ((git_vector_init(&specs, 0, NULL)) < 0)
		goto on_error;

952
	remote->passed_refspecs = 0;
953
	if (!refspecs || !refspecs->count) {
954 955 956 957 958 959 960 961
		to_active = &remote->refspecs;
	} else {
		for (i = 0; i < refspecs->count; i++) {
			if ((error = add_refspec_to(&specs, refspecs->strings[i], true)) < 0)
				goto on_error;
		}

		to_active = &specs;
962
		remote->passed_refspecs = 1;
963 964
	}

965 966 967
	free_refspecs(&remote->passive_refspecs);
	if ((error = dwim_refspecs(&remote->passive_refspecs, &remote->refspecs, &refs)) < 0)
		goto on_error;
968

969
	free_refspecs(&remote->active_refspecs);
970
	error = dwim_refspecs(&remote->active_refspecs, to_active, &refs);
971

972
	git_vector_free(&refs);
973 974
	free_refspecs(&specs);
	git_vector_free(&specs);
975 976

	if (error < 0)
977
		return error;
978

979 980 981 982 983
	if (remote->push) {
		git_push_free(remote->push);
		remote->push = NULL;
	}

984
	if ((error = git_fetch_negotiate(remote, opts)) < 0)
985
		return error;
986

987
	return git_fetch_download_pack(remote, cbs);
988 989 990 991 992 993

on_error:
	git_vector_free(&refs);
	free_refspecs(&specs);
	git_vector_free(&specs);
	return error;
994 995
}

996 997
int git_remote_fetch(
		git_remote *remote,
998
		const git_strarray *refspecs,
999
		const git_fetch_options *opts,
1000
		const char *reflog_message)
1001
{
1002
	int error, update_fetchhead = 1;
1003
	git_remote_autotag_option_t tagopt = remote->download_tags;
1004
	bool prune = false;
1005
	git_buf reflog_msg_buf = GIT_BUF_INIT;
1006
	const git_remote_callbacks *cbs = NULL;
1007
	git_remote_connection_opts conn = GIT_REMOTE_CONNECTION_OPTIONS_INIT;
1008 1009

	if (opts) {
1010
		GIT_ERROR_CHECK_VERSION(&opts->callbacks, GIT_REMOTE_CALLBACKS_VERSION, "git_remote_callbacks");
1011
		cbs = &opts->callbacks;
1012
		conn.custom_headers = &opts->custom_headers;
1013
		update_fetchhead = opts->update_fetchhead;
1014
		tagopt = opts->download_tags;
1015
		GIT_ERROR_CHECK_VERSION(&opts->proxy_opts, GIT_PROXY_OPTIONS_VERSION, "git_proxy_options");
1016
		conn.proxy = &opts->proxy_opts;
1017
	}
1018 1019

	/* Connect and download everything */
1020
	if ((error = git_remote__connect(remote, GIT_DIRECTION_FETCH, cbs, &conn)) != 0)
1021 1022
		return error;

1023
	error = git_remote_download(remote, refspecs, opts);
1024 1025 1026 1027

	/* We don't need to be connected anymore */
	git_remote_disconnect(remote);

1028 1029 1030 1031
	/* If the download failed, return the error */
	if (error != 0)
		return error;

1032 1033 1034 1035 1036 1037 1038 1039
	/* Default reflog message */
	if (reflog_message)
		git_buf_sets(&reflog_msg_buf, reflog_message);
	else {
		git_buf_printf(&reflog_msg_buf, "fetch %s",
				remote->name ? remote->name : remote->url);
	}

1040
	/* Create "remote/foo" branches for all remote branches */
1041
	error = git_remote_update_tips(remote, cbs, update_fetchhead, tagopt, git_buf_cstr(&reflog_msg_buf));
1042
	git_buf_dispose(&reflog_msg_buf);
1043 1044 1045
	if (error < 0)
		return error;

1046 1047
	if (opts && opts->prune == GIT_FETCH_PRUNE)
		prune = true;
1048
	else if (opts && opts->prune == GIT_FETCH_PRUNE_UNSPECIFIED && remote->prune_refs)
1049 1050 1051 1052 1053 1054 1055
		prune = true;
	else if (opts && opts->prune == GIT_FETCH_NO_PRUNE)
		prune = false;
	else
		prune = remote->prune_refs;

	if (prune)
1056
		error = git_remote_prune(remote, cbs);
1057

1058
	return error;
1059 1060
}

1061 1062 1063 1064 1065 1066 1067 1068
static int remote_head_for_fetchspec_src(git_remote_head **out, git_vector *update_heads, const char *fetchspec_src)
{
	unsigned int i;
	git_remote_head *remote_ref;

	assert(update_heads && fetchspec_src);

	*out = NULL;
nulltoken committed
1069 1070 1071 1072 1073

	git_vector_foreach(update_heads, i, remote_ref) {
		if (strcmp(remote_ref->name, fetchspec_src) == 0) {
			*out = remote_ref;
			break;
1074 1075 1076 1077 1078 1079
		}
	}

	return 0;
}

1080 1081 1082 1083 1084 1085 1086 1087 1088 1089 1090 1091 1092 1093 1094 1095 1096 1097
static int ref_to_update(int *update, git_buf *remote_name, git_remote *remote, git_refspec *spec, const char *ref_name)
{
	int error = 0;
	git_repository *repo;
	git_buf upstream_remote = GIT_BUF_INIT;
	git_buf upstream_name = GIT_BUF_INIT;

	repo = git_remote_owner(remote);

	if ((!git_reference__is_branch(ref_name)) ||
	    !git_remote_name(remote) ||
	    (error = git_branch_upstream_remote(&upstream_remote, repo, ref_name) < 0) ||
	    git__strcmp(git_remote_name(remote), git_buf_cstr(&upstream_remote)) ||
	    (error = git_branch_upstream_name(&upstream_name, repo, ref_name)) < 0 ||
	    !git_refspec_dst_matches(spec, git_buf_cstr(&upstream_name)) ||
	    (error = git_refspec_rtransform(remote_name, spec, upstream_name.ptr)) < 0) {
		/* Not an error if there is no upstream */
		if (error == GIT_ENOTFOUND) {
1098
			git_error_clear();
1099 1100 1101 1102 1103 1104 1105 1106
			error = 0;
		}

		*update = 0;
	} else {
		*update = 1;
	}

1107 1108
	git_buf_dispose(&upstream_remote);
	git_buf_dispose(&upstream_name);
1109 1110 1111
	return error;
}

1112
static int remote_head_for_ref(git_remote_head **out, git_remote *remote, git_refspec *spec, git_vector *update_heads, git_reference *ref)
1113 1114 1115
{
	git_reference *resolved_ref = NULL;
	git_buf remote_name = GIT_BUF_INIT;
1116
	git_config *config = NULL;
1117
	const char *ref_name;
1118
	int error = 0, update;
1119

1120
	assert(out && spec && ref);
1121 1122 1123

	*out = NULL;

1124 1125 1126
	error = git_reference_resolve(&resolved_ref, ref);

	/* If we're in an unborn branch, let's pretend nothing happened */
1127
	if (error == GIT_ENOTFOUND && git_reference_type(ref) == GIT_REFERENCE_SYMBOLIC) {
1128 1129 1130 1131 1132 1133
		ref_name = git_reference_symbolic_target(ref);
		error = 0;
	} else {
		ref_name = git_reference_name(resolved_ref);
	}

1134
	if ((error = ref_to_update(&update, &remote_name, remote, spec, ref_name)) < 0)
1135 1136
		goto cleanup;

1137 1138
	if (update)
		error = remote_head_for_fetchspec_src(out, update_heads, git_buf_cstr(&remote_name));
1139 1140

cleanup:
1141
	git_buf_dispose(&remote_name);
1142
	git_reference_free(resolved_ref);
1143
	git_config_free(config);
1144 1145 1146
	return error;
}

1147
static int git_remote_write_fetchhead(git_remote *remote, git_refspec *spec, git_vector *update_heads)
1148 1149 1150 1151 1152 1153 1154 1155 1156 1157 1158
{
	git_reference *head_ref = NULL;
	git_fetchhead_ref *fetchhead_ref;
	git_remote_head *remote_ref, *merge_remote_ref;
	git_vector fetchhead_refs;
	bool include_all_fetchheads;
	unsigned int i = 0;
	int error = 0;

	assert(remote);

1159 1160 1161 1162
	/* no heads, nothing to do */
	if (update_heads->length == 0)
		return 0;

1163 1164 1165 1166 1167 1168 1169 1170 1171
	if (git_vector_init(&fetchhead_refs, update_heads->length, git_fetchhead_ref_cmp) < 0)
		return -1;

	/* Iff refspec is * (but not subdir slash star), include tags */
	include_all_fetchheads = (strcmp(GIT_REFS_HEADS_DIR "*", git_refspec_src(spec)) == 0);

	/* Determine what to merge: if refspec was a wildcard, just use HEAD */
	if (git_refspec_is_wildcard(spec)) {
		if ((error = git_reference_lookup(&head_ref, remote->repo, GIT_HEAD_FILE)) < 0 ||
1172
			(error = remote_head_for_ref(&merge_remote_ref, remote, spec, update_heads, head_ref)) < 0)
1173 1174 1175 1176 1177 1178 1179 1180
				goto cleanup;
	} else {
		/* If we're fetching a single refspec, that's the only thing that should be in FETCH_HEAD. */
		if ((error = remote_head_for_fetchspec_src(&merge_remote_ref, update_heads, git_refspec_src(spec))) < 0)
			goto cleanup;
	}

	/* Create the FETCH_HEAD file */
nulltoken committed
1181
	git_vector_foreach(update_heads, i, remote_ref) {
1182 1183 1184 1185 1186 1187 1188 1189 1190 1191 1192 1193 1194 1195 1196 1197 1198 1199 1200 1201 1202 1203 1204 1205 1206 1207 1208 1209 1210 1211
		int merge_this_fetchhead = (merge_remote_ref == remote_ref);

		if (!include_all_fetchheads &&
			!git_refspec_src_matches(spec, remote_ref->name) &&
			!merge_this_fetchhead)
			continue;

		if (git_fetchhead_ref_create(&fetchhead_ref,
			&remote_ref->oid,
			merge_this_fetchhead,
			remote_ref->name,
			git_remote_url(remote)) < 0)
			goto cleanup;

		if (git_vector_insert(&fetchhead_refs, fetchhead_ref) < 0)
			goto cleanup;
	}

	git_fetchhead_write(remote->repo, &fetchhead_refs);

cleanup:
	for (i = 0; i < fetchhead_refs.length; ++i)
		git_fetchhead_ref_free(fetchhead_refs.contents[i]);

	git_vector_free(&fetchhead_refs);
	git_reference_free(head_ref);

	return error;
}

1212 1213 1214 1215 1216
/**
 * Generate a list of candidates for pruning by getting a list of
 * references which match the rhs of an active refspec.
 */
static int prune_candidates(git_vector *candidates, git_remote *remote)
1217 1218
{
	git_strarray arr = { 0 };
1219
	size_t i;
1220 1221 1222 1223 1224
	int error;

	if ((error = git_reference_list(&arr, remote->repo)) < 0)
		return error;

1225 1226 1227 1228 1229 1230 1231 1232
	for (i = 0; i < arr.count; i++) {
		const char *refname = arr.strings[i];
		char *refname_dup;

		if (!git_remote__matching_dst_refspec(remote, refname))
			continue;

		refname_dup = git__strdup(refname);
1233
		GIT_ERROR_CHECK_ALLOC(refname_dup);
1234 1235 1236 1237 1238 1239 1240 1241 1242 1243 1244 1245 1246 1247 1248 1249 1250 1251

		if ((error = git_vector_insert(candidates, refname_dup)) < 0)
			goto out;
	}

out:
	git_strarray_free(&arr);
	return error;
}

static int find_head(const void *_a, const void *_b)
{
	git_remote_head *a = (git_remote_head *) _a;
	git_remote_head *b = (git_remote_head *) _b;

	return strcmp(a->name, b->name);
}

1252
int git_remote_prune(git_remote *remote, const git_remote_callbacks *callbacks)
1253 1254 1255 1256 1257 1258 1259 1260 1261
{
	size_t i, j;
	git_vector remote_refs = GIT_VECTOR_INIT;
	git_vector candidates = GIT_VECTOR_INIT;
	const git_refspec *spec;
	const char *refname;
	int error;
	git_oid zero_id = {{ 0 }};

1262
	if (callbacks)
1263
		GIT_ERROR_CHECK_VERSION(callbacks, GIT_REMOTE_CALLBACKS_VERSION, "git_remote_callbacks");
1264

1265 1266 1267
	if ((error = ls_to_vector(&remote_refs, remote)) < 0)
		goto cleanup;

1268
	git_vector_set_cmp(&remote_refs, find_head);
1269

1270 1271
	if ((error = prune_candidates(&candidates, remote)) < 0)
		goto cleanup;
1272

1273 1274 1275 1276 1277 1278 1279 1280 1281 1282 1283 1284
	/*
	 * Remove those entries from the candidate list for which we
	 * can find a remote reference in at least one refspec.
	 */
	git_vector_foreach(&candidates, i, refname) {
		git_vector_foreach(&remote->active_refspecs, j, spec) {
			git_buf buf = GIT_BUF_INIT;
			size_t pos;
			char *src_name;
			git_remote_head key = {0};

			if (!git_refspec_dst_matches(spec, refname))
1285 1286
				continue;

1287 1288
			if ((error = git_refspec_rtransform(&buf, spec, refname)) < 0)
				goto cleanup;
1289

1290
			key.name = (char *) git_buf_cstr(&buf);
1291
			error = git_vector_bsearch(&pos, &remote_refs, &key);
1292
			git_buf_dispose(&buf);
1293

1294 1295
			if (error < 0 && error != GIT_ENOTFOUND)
				goto cleanup;
1296

1297
			if (error == GIT_ENOTFOUND)
1298 1299
				continue;

1300 1301 1302 1303 1304 1305
			/* if we did find a source, remove it from the candiates */
			if ((error = git_vector_set((void **) &src_name, &candidates, i, NULL)) < 0)
				goto cleanup;

			git__free(src_name);
			break;
1306 1307 1308
		}
	}

1309 1310 1311 1312 1313 1314 1315 1316 1317 1318 1319 1320 1321 1322 1323 1324 1325 1326 1327 1328 1329
	/*
	 * For those candidates still left in the list, we need to
	 * remove them. We do not remove symrefs, as those are for
	 * stuff like origin/HEAD which will never match, but we do
	 * not want to remove them.
	 */
	git_vector_foreach(&candidates, i, refname) {
		git_reference *ref;
		git_oid id;

		if (refname == NULL)
			continue;

		error = git_reference_lookup(&ref, remote->repo, refname);
		/* as we want it gone, let's not consider this an error */
		if (error == GIT_ENOTFOUND)
			continue;

		if (error < 0)
			goto cleanup;

1330
		if (git_reference_type(ref) == GIT_REFERENCE_SYMBOLIC) {
1331 1332 1333 1334 1335 1336 1337 1338 1339 1340
			git_reference_free(ref);
			continue;
		}

		git_oid_cpy(&id, git_reference_target(ref));
		error = git_reference_delete(ref);
		git_reference_free(ref);
		if (error < 0)
			goto cleanup;

1341 1342
		if (callbacks && callbacks->update_tips)
			error = callbacks->update_tips(refname, &id, &zero_id, callbacks->payload);
1343 1344 1345 1346 1347

		if (error < 0)
			goto cleanup;
	}

1348 1349
cleanup:
	git_vector_free(&remote_refs);
1350
	git_vector_free_deep(&candidates);
1351 1352 1353
	return error;
}

1354 1355
static int update_tips_for_spec(
		git_remote *remote,
1356
		const git_remote_callbacks *callbacks,
1357
		int update_fetchhead,
1358
		git_remote_autotag_option_t tagopt,
1359 1360 1361
		git_refspec *spec,
		git_vector *refs,
		const char *log_message)
1362
{
1363
	int error = 0, autotag;
1364
	unsigned int i = 0;
1365
	git_buf refname = GIT_BUF_INIT;
1366
	git_oid old;
1367
	git_odb *odb;
1368 1369
	git_remote_head *head;
	git_reference *ref;
1370
	git_refspec tagspec;
1371
	git_vector update_heads;
1372

1373 1374
	assert(remote);

1375
	if (git_repository_odb__weakptr(&odb, remote->repo) < 0)
1376 1377
		return -1;

1378
	if (git_refspec__parse(&tagspec, GIT_REFSPEC_TAGS, true) < 0)
1379 1380
		return -1;

1381
	/* Make a copy of the transport's refs */
1382
	if (git_vector_init(&update_heads, 16, NULL) < 0)
1383
		return -1;
1384

1385 1386
	for (; i < refs->length; ++i) {
		head = git_vector_get(refs, i);
1387
		autotag = 0;
1388
		git_buf_clear(&refname);
1389

1390 1391 1392 1393
		/* Ignore malformed ref names (which also saves us from tag^{} */
		if (!git_reference_is_valid_name(head->name))
			continue;

1394
		/* If we have a tag, see if the auto-follow rules say to update it */
1395
		if (git_refspec_src_matches(&tagspec, head->name)) {
1396
			if (tagopt != GIT_REMOTE_DOWNLOAD_TAGS_NONE) {
1397

1398
				if (tagopt == GIT_REMOTE_DOWNLOAD_TAGS_AUTO)
1399
					autotag = 1;
1400

1401 1402 1403 1404
				git_buf_clear(&refname);
				if (git_buf_puts(&refname, head->name) < 0)
					goto on_error;
			}
1405 1406 1407 1408
		}

		/* If we didn't want to auto-follow the tag, check if the refspec matches */
		if (!autotag && git_refspec_src_matches(spec, head->name)) {
1409 1410 1411 1412 1413 1414 1415 1416 1417 1418 1419 1420 1421
			if (spec->dst) {
				if (git_refspec_transform(&refname, spec, head->name) < 0)
					goto on_error;
			} else {
				/*
				 * no rhs mans store it in FETCH_HEAD, even if we don't
				 update anything else.
				 */
				if ((error = git_vector_insert(&update_heads, head)) < 0)
					goto on_error;

				continue;
			}
1422 1423 1424 1425
		}

		/* If we still don't have a refname, we don't want it */
		if (git_buf_len(&refname) == 0) {
1426 1427 1428
			continue;
		}

1429
		/* In autotag mode, only create tags for objects already in db */
1430 1431
		if (autotag && !git_odb_exists(odb, &head->oid))
			continue;
1432

1433
		if (!autotag && git_vector_insert(&update_heads, head) < 0)
1434 1435
			goto on_error;

1436
		error = git_reference_name_to_id(&old, remote->repo, refname.ptr);
1437
		if (error < 0 && error != GIT_ENOTFOUND)
1438 1439
			goto on_error;

1440
		if (error == GIT_ENOTFOUND) {
1441 1442
			memset(&old, 0, GIT_OID_RAWSZ);

1443 1444 1445 1446
			if (autotag && git_vector_insert(&update_heads, head) < 0)
				goto on_error;
		}

1447
		if (!git_oid__cmp(&old, &head->oid))
1448
			continue;
1449

1450
		/* In autotag mode, don't overwrite any locally-existing tags */
1451
		error = git_reference_create(&ref, remote->repo, refname.ptr, &head->oid, !autotag,
1452
				log_message);
1453 1454 1455 1456 1457

		if (error == GIT_EEXISTS)
			continue;

		if (error < 0)
1458
			goto on_error;
1459 1460

		git_reference_free(ref);
1461

1462 1463
		if (callbacks && callbacks->update_tips != NULL) {
			if (callbacks->update_tips(refname.ptr, &old, &head->oid, callbacks->payload) < 0)
1464 1465
				goto on_error;
		}
1466 1467
	}

1468
	if (update_fetchhead &&
1469
	    (error = git_remote_write_fetchhead(remote, spec, &update_heads)) < 0)
1470 1471 1472
		goto on_error;

	git_vector_free(&update_heads);
1473
	git_refspec__dispose(&tagspec);
1474
	git_buf_dispose(&refname);
1475 1476 1477
	return 0;

on_error:
1478
	git_vector_free(&update_heads);
1479
	git_refspec__dispose(&tagspec);
1480
	git_buf_dispose(&refname);
1481
	return -1;
1482

1483 1484
}

1485 1486 1487 1488 1489 1490 1491 1492 1493 1494 1495 1496 1497 1498 1499 1500 1501 1502 1503 1504 1505 1506 1507 1508 1509 1510 1511 1512 1513 1514 1515 1516 1517 1518 1519 1520 1521 1522 1523 1524 1525 1526 1527 1528 1529 1530 1531 1532 1533 1534 1535 1536 1537 1538 1539 1540 1541
/**
 * Iteration over the three vectors, with a pause whenever we find a match
 *
 * On each stop, we store the iteration stat in the inout i,j,k
 * parameters, and return the currently matching passive refspec as
 * well as the head which we matched.
 */
static int next_head(const git_remote *remote, git_vector *refs,
		     git_refspec **out_spec, git_remote_head **out_head,
		     size_t *out_i, size_t *out_j, size_t *out_k)
{
	const git_vector *active, *passive;
	git_remote_head *head;
	git_refspec *spec, *passive_spec;
	size_t i, j, k;

	active = &remote->active_refspecs;
	passive = &remote->passive_refspecs;

	i = *out_i;
	j = *out_j;
	k = *out_k;

	for (; i < refs->length; i++) {
		head = git_vector_get(refs, i);

		if (!git_reference_is_valid_name(head->name))
			continue;

		for (; j < active->length; j++) {
			spec = git_vector_get(active, j);

			if (!git_refspec_src_matches(spec, head->name))
				continue;

			for (; k < passive->length; k++) {
				passive_spec = git_vector_get(passive, k);

				if (!git_refspec_src_matches(passive_spec, head->name))
				    continue;

				*out_spec = passive_spec;
				*out_head = head;
				*out_i = i;
				*out_j = j;
				*out_k = k + 1;
				return 0;

			}
			k = 0;
		}
		j = 0;
	}

	return GIT_ITEROVER;
}

1542 1543
static int opportunistic_updates(const git_remote *remote, const git_remote_callbacks *callbacks,
				 git_vector *refs, const char *msg)
1544 1545 1546 1547 1548 1549
{
	size_t i, j, k;
	git_refspec *spec;
	git_remote_head *head;
	git_reference *ref;
	git_buf refname = GIT_BUF_INIT;
1550
	int error = 0;
1551 1552 1553 1554

	i = j = k = 0;

	while ((error = next_head(remote, refs, &spec, &head, &i, &j, &k)) == 0) {
1555
		git_oid old = {{ 0 }};
1556 1557 1558 1559 1560 1561 1562 1563
		/*
		 * If we got here, there is a refspec which was used
		 * for fetching which matches the source of one of the
		 * passive refspecs, so we should update that
		 * remote-tracking branch, but not add it to
		 * FETCH_HEAD
		 */

1564
		git_buf_clear(&refname);
1565
		if ((error = git_refspec_transform(&refname, spec, head->name)) < 0)
1566
			goto cleanup;
1567

1568 1569 1570 1571 1572 1573
		error = git_reference_name_to_id(&old, remote->repo, refname.ptr);
		if (error < 0 && error != GIT_ENOTFOUND)
			goto cleanup;

		if (!git_oid_cmp(&old, &head->oid))
			continue;
1574

1575 1576 1577 1578 1579 1580
		/* If we did find a current reference, make sure we haven't lost a race */
		if (error)
			error = git_reference_create(&ref, remote->repo, refname.ptr, &head->oid, true, msg);
		else
			error = git_reference_create_matching(&ref, remote->repo, refname.ptr, &head->oid, true, &old, msg);
		git_reference_free(ref);
1581
		if (error < 0)
1582 1583 1584 1585 1586 1587
			goto cleanup;

		if (callbacks && callbacks->update_tips != NULL) {
			if (callbacks->update_tips(refname.ptr, &old, &head->oid, callbacks->payload) < 0)
				goto cleanup;
		}
1588 1589
	}

1590 1591 1592 1593
	if (error == GIT_ITEROVER)
		error = 0;

cleanup:
1594
	git_buf_dispose(&refname);
1595
	return error;
1596 1597
}

1598 1599 1600 1601 1602 1603 1604 1605 1606
static int truncate_fetch_head(const char *gitdir)
{
	git_buf path = GIT_BUF_INIT;
	int error;

	if ((error = git_buf_joinpath(&path, gitdir, GIT_FETCH_HEAD_FILE)) < 0)
		return error;

	error = git_futils_truncate(path.ptr, GIT_REFS_FILE_MODE);
1607
	git_buf_dispose(&path);
1608 1609 1610 1611

	return error;
}

1612 1613
int git_remote_update_tips(
		git_remote *remote,
1614
		const git_remote_callbacks *callbacks,
1615
		int update_fetchhead,
1616
		git_remote_autotag_option_t download_tags,
1617
		const char *reflog_message)
1618
{
1619
	git_refspec *spec, tagspec;
1620
	git_vector refs = GIT_VECTOR_INIT;
1621
	git_remote_autotag_option_t tagopt;
1622
	int error;
1623 1624
	size_t i;

1625 1626
	/* push has its own logic hidden away in the push object */
	if (remote->push) {
1627
		return git_push_update_tips(remote->push, callbacks);
1628 1629
	}

1630 1631 1632
	if (git_refspec__parse(&tagspec, GIT_REFSPEC_TAGS, true) < 0)
		return -1;

1633 1634

	if ((error = ls_to_vector(&refs, remote)) < 0)
1635 1636
		goto out;

1637
	if (download_tags == GIT_REMOTE_DOWNLOAD_TAGS_UNSPECIFIED)
1638 1639 1640 1641
		tagopt = remote->download_tags;
	else
		tagopt = download_tags;

1642 1643 1644
	if ((error = truncate_fetch_head(git_repository_path(remote->repo))) < 0)
		goto out;

1645 1646
	if (tagopt == GIT_REMOTE_DOWNLOAD_TAGS_ALL) {
		if ((error = update_tips_for_spec(remote, callbacks, update_fetchhead, tagopt, &tagspec, &refs, reflog_message)) < 0)
1647
			goto out;
1648
	}
1649

1650
	git_vector_foreach(&remote->active_refspecs, i, spec) {
1651 1652 1653
		if (spec->push)
			continue;

1654
		if ((error = update_tips_for_spec(remote, callbacks, update_fetchhead, tagopt, spec, &refs, reflog_message)) < 0)
1655
			goto out;
1656 1657
	}

1658 1659
	/* only try to do opportunisitic updates if the refpec lists differ */
	if (remote->passed_refspecs)
1660
		error = opportunistic_updates(remote, callbacks, &refs, reflog_message);
1661

1662
out:
1663
	git_vector_free(&refs);
1664
	git_refspec__dispose(&tagspec);
1665
	return error;
1666 1667
}

1668
int git_remote_connected(const git_remote *remote)
1669
{
1670
	assert(remote);
1671 1672 1673 1674 1675

	if (!remote->transport || !remote->transport->is_connected)
		return 0;

	/* Ask the transport if it's connected. */
1676
	return remote->transport->is_connected(remote->transport);
1677 1678
}

1679 1680
void git_remote_stop(git_remote *remote)
{
1681 1682 1683
	assert(remote);

	if (remote->transport && remote->transport->cancel)
1684
		remote->transport->cancel(remote->transport);
1685 1686
}

1687 1688
void git_remote_disconnect(git_remote *remote)
{
1689 1690
	assert(remote);

1691 1692
	if (git_remote_connected(remote))
		remote->transport->close(remote->transport);
1693 1694
}

Carlos Martín Nieto committed
1695 1696
void git_remote_free(git_remote *remote)
{
1697 1698 1699
	if (remote == NULL)
		return;

1700 1701 1702 1703 1704 1705 1706 1707 1708
	if (remote->transport != NULL) {
		git_remote_disconnect(remote);

		remote->transport->free(remote->transport);
		remote->transport = NULL;
	}

	git_vector_free(&remote->refs);

1709
	free_refspecs(&remote->refspecs);
1710 1711
	git_vector_free(&remote->refspecs);

1712 1713 1714
	free_refspecs(&remote->active_refspecs);
	git_vector_free(&remote->active_refspecs);

1715 1716 1717
	free_refspecs(&remote->passive_refspecs);
	git_vector_free(&remote->passive_refspecs);

1718
	git_push_free(remote->push);
1719
	git__free(remote->url);
1720
	git__free(remote->pushurl);
1721 1722
	git__free(remote->name);
	git__free(remote);
Carlos Martín Nieto committed
1723
}
1724

1725
static int remote_list_cb(const git_config_entry *entry, void *payload)
1726
{
1727
	git_vector *list = payload;
1728 1729 1730
	const char *name = entry->name + strlen("remote.");
	size_t namelen = strlen(name);
	char *remote_name;
1731

1732
	/* we know name matches "remote.<stuff>.(push)?url" */
1733

1734 1735 1736 1737
	if (!strcmp(&name[namelen - 4], ".url"))
		remote_name = git__strndup(name, namelen - 4); /* strip ".url" */
	else
		remote_name = git__strndup(name, namelen - 8); /* strip ".pushurl" */
1738
	GIT_ERROR_CHECK_ALLOC(remote_name);
1739

1740
	return git_vector_insert(list, remote_name);
1741 1742 1743 1744 1745
}

int git_remote_list(git_strarray *remotes_list, git_repository *repo)
{
	int error;
1746
	git_config *cfg;
1747
	git_vector list = GIT_VECTOR_INIT;
1748

1749 1750
	if ((error = git_repository_config__weakptr(&cfg, repo)) < 0)
		return error;
1751

1752
	if ((error = git_vector_init(&list, 4, git__strcmp_cb)) < 0)
1753
		return error;
1754

1755
	error = git_config_foreach_match(
1756
		cfg, "^remote\\..*\\.(push)?url$", remote_list_cb, &list);
1757

1758
	if (error < 0) {
1759
		git_vector_free_deep(&list);
1760 1761 1762
		return error;
	}

1763
	git_vector_uniq(&list, git__free);
1764

1765 1766
	remotes_list->strings =
		(char **)git_vector_detach(&remotes_list->count, NULL, &list);
1767

1768
	return 0;
1769
}
1770

1771
const git_indexer_progress *git_remote_stats(git_remote *remote)
1772 1773 1774 1775 1776
{
	assert(remote);
	return &remote->stats;
}

1777
git_remote_autotag_option_t git_remote_autotag(const git_remote *remote)
1778 1779 1780 1781
{
	return remote->download_tags;
}

1782
int git_remote_set_autotag(git_repository *repo, const char *remote, git_remote_autotag_option_t value)
1783
{
1784 1785 1786 1787 1788 1789 1790 1791 1792 1793 1794 1795 1796 1797 1798 1799 1800 1801 1802 1803 1804 1805 1806 1807 1808 1809 1810 1811
	git_buf var = GIT_BUF_INIT;
	git_config *config;
	int error;

	assert(repo && remote);

	if ((error = ensure_remote_name_is_valid(remote)) < 0)
		return error;

	if ((error = git_repository_config__weakptr(&config, repo)) < 0)
		return error;

	if ((error = git_buf_printf(&var, CONFIG_TAGOPT_FMT, remote)))
		return error;

	switch (value) {
	case GIT_REMOTE_DOWNLOAD_TAGS_NONE:
		error = git_config_set_string(config, var.ptr, "--no-tags");
		break;
	case GIT_REMOTE_DOWNLOAD_TAGS_ALL:
		error = git_config_set_string(config, var.ptr, "--tags");
		break;
	case GIT_REMOTE_DOWNLOAD_TAGS_AUTO:
		error = git_config_delete_entry(config, var.ptr);
		if (error == GIT_ENOTFOUND)
			error = 0;
		break;
	default:
1812
		git_error_set(GIT_ERROR_INVALID, "invalid value for the tagopt setting");
1813 1814 1815
		error = -1;
	}

1816
	git_buf_dispose(&var);
1817
	return error;
1818
}
1819

1820 1821 1822 1823 1824
int git_remote_prune_refs(const git_remote *remote)
{
	return remote->prune_refs;
}

1825 1826 1827 1828 1829 1830 1831 1832 1833 1834 1835 1836
static int rename_remote_config_section(
	git_repository *repo,
	const char *old_name,
	const char *new_name)
{
	git_buf old_section_name = GIT_BUF_INIT,
		new_section_name = GIT_BUF_INIT;
	int error = -1;

	if (git_buf_printf(&old_section_name, "remote.%s", old_name) < 0)
		goto cleanup;

1837 1838 1839
	if (new_name &&
		(git_buf_printf(&new_section_name, "remote.%s", new_name) < 0))
			goto cleanup;
1840 1841 1842 1843

	error = git_config_rename_section(
		repo,
		git_buf_cstr(&old_section_name),
1844
		new_name ? git_buf_cstr(&new_section_name) : NULL);
1845 1846

cleanup:
1847 1848
	git_buf_dispose(&old_section_name);
	git_buf_dispose(&new_section_name);
1849 1850 1851 1852

	return error;
}

1853
struct update_data {
1854 1855 1856 1857 1858 1859 1860 1861 1862 1863 1864 1865 1866 1867
	git_config *config;
	const char *old_remote_name;
	const char *new_remote_name;
};

static int update_config_entries_cb(
	const git_config_entry *entry,
	void *payload)
{
	struct update_data *data = (struct update_data *)payload;

	if (strcmp(entry->value, data->old_remote_name))
		return 0;

1868 1869
	return git_config_set_string(
		data->config, entry->name, data->new_remote_name);
1870 1871 1872 1873 1874 1875 1876
}

static int update_branch_remote_config_entry(
	git_repository *repo,
	const char *old_name,
	const char *new_name)
{
1877 1878
	int error;
	struct update_data data = { NULL };
1879

1880 1881
	if ((error = git_repository_config__weakptr(&data.config, repo)) < 0)
		return error;
1882 1883 1884 1885

	data.old_remote_name = old_name;
	data.new_remote_name = new_name;

1886
	return git_config_foreach_match(
1887
		data.config, "branch\\..+\\.remote", update_config_entries_cb, &data);
1888 1889 1890
}

static int rename_one_remote_reference(
1891
	git_reference *reference_in,
1892 1893 1894
	const char *old_remote_name,
	const char *new_remote_name)
{
1895
	int error;
1896 1897
	git_reference *ref = NULL, *dummy = NULL;
	git_buf namespace = GIT_BUF_INIT, old_namespace = GIT_BUF_INIT;
1898
	git_buf new_name = GIT_BUF_INIT;
1899
	git_buf log_message = GIT_BUF_INIT;
1900 1901
	size_t pfx_len;
	const char *target;
1902

1903 1904 1905 1906 1907 1908
	if ((error = git_buf_printf(&namespace, GIT_REFS_REMOTES_DIR "%s/", new_remote_name)) < 0)
		return error;

	pfx_len = strlen(GIT_REFS_REMOTES_DIR) + strlen(old_remote_name) + 1;
	git_buf_puts(&new_name, namespace.ptr);
	if ((error = git_buf_puts(&new_name, git_reference_name(reference_in) + pfx_len)) < 0)
1909
		goto cleanup;
1910

1911 1912 1913 1914
	if ((error = git_buf_printf(&log_message,
					"renamed remote %s to %s",
					old_remote_name, new_remote_name)) < 0)
		goto cleanup;
1915

1916
	if ((error = git_reference_rename(&ref, reference_in, git_buf_cstr(&new_name), 1,
1917
					  git_buf_cstr(&log_message))) < 0)
1918 1919
		goto cleanup;

1920
	if (git_reference_type(ref) != GIT_REFERENCE_SYMBOLIC)
1921 1922 1923 1924 1925 1926 1927 1928 1929 1930 1931 1932 1933 1934 1935 1936
		goto cleanup;

	/* Handle refs like origin/HEAD -> origin/master */
	target = git_reference_symbolic_target(ref);
	if ((error = git_buf_printf(&old_namespace, GIT_REFS_REMOTES_DIR "%s/", old_remote_name)) < 0)
		goto cleanup;

	if (git__prefixcmp(target, old_namespace.ptr))
		goto cleanup;

	git_buf_clear(&new_name);
	git_buf_puts(&new_name, namespace.ptr);
	if ((error = git_buf_puts(&new_name, target + pfx_len)) < 0)
		goto cleanup;

	error = git_reference_symbolic_set_target(&dummy, ref, git_buf_cstr(&new_name),
1937
						  git_buf_cstr(&log_message));
1938 1939

	git_reference_free(dummy);
1940 1941

cleanup:
1942 1943
	git_reference_free(reference_in);
	git_reference_free(ref);
1944 1945 1946 1947
	git_buf_dispose(&namespace);
	git_buf_dispose(&old_namespace);
	git_buf_dispose(&new_name);
	git_buf_dispose(&log_message);
1948 1949 1950 1951 1952 1953 1954 1955
	return error;
}

static int rename_remote_references(
	git_repository *repo,
	const char *old_name,
	const char *new_name)
{
1956
	int error;
1957
	git_buf buf = GIT_BUF_INIT;
Vicent Marti committed
1958
	git_reference *ref;
1959
	git_reference_iterator *iter;
1960

1961
	if ((error = git_buf_printf(&buf, GIT_REFS_REMOTES_DIR "%s/*", old_name)) < 0)
1962
		return error;
1963

1964
	error = git_reference_iterator_glob_new(&iter, repo, git_buf_cstr(&buf));
1965
	git_buf_dispose(&buf);
1966

1967 1968 1969 1970
	if (error < 0)
		return error;

	while ((error = git_reference_next(&ref, iter)) == 0) {
1971 1972
		if ((error = rename_one_remote_reference(ref, old_name, new_name)) < 0)
			break;
1973 1974 1975
	}

	git_reference_iterator_free(iter);
1976

1977
	return (error == GIT_ITEROVER) ? 0 : error;
1978 1979
}

1980
static int rename_fetch_refspecs(git_vector *problems, git_remote *remote, const char *new_name)
1981 1982
{
	git_config *config;
1983
	git_buf base = GIT_BUF_INIT, var = GIT_BUF_INIT, val = GIT_BUF_INIT;
1984
	const git_refspec *spec;
1985
	size_t i;
1986
	int error = 0;
1987

1988
	if ((error = git_repository_config__weakptr(&config, remote->repo)) < 0)
1989 1990
		return error;

1991 1992 1993
	if ((error = git_vector_init(problems, 1, NULL)) < 0)
		return error;

1994
	if ((error = default_fetchspec_for_name(&base, remote->name)) < 0)
1995
		return error;
1996

1997
	git_vector_foreach(&remote->refspecs, i, spec) {
1998 1999
		if (spec->push)
			continue;
2000

2001
		/* Does the dst part of the refspec follow the expected format? */
2002
		if (strcmp(git_buf_cstr(&base), spec->string)) {
2003
			char *dup;
2004

2005
			dup = git__strdup(spec->string);
2006
			GIT_ERROR_CHECK_ALLOC(dup);
2007 2008

			if ((error = git_vector_insert(problems, dup)) < 0)
2009
				break;
2010

2011 2012
			continue;
		}
2013

2014
		/* If we do want to move it to the new section */
2015

2016 2017
		git_buf_clear(&val);
		git_buf_clear(&var);
2018

2019
		if (default_fetchspec_for_name(&val, new_name) < 0 ||
2020 2021 2022
			git_buf_printf(&var, "remote.%s.fetch", new_name) < 0)
		{
			error = -1;
2023
			break;
2024
		}
2025

2026 2027
		if ((error = git_config_set_string(
				config, git_buf_cstr(&var), git_buf_cstr(&val))) < 0)
2028
			break;
2029
	}
2030

2031 2032 2033
	git_buf_dispose(&base);
	git_buf_dispose(&var);
	git_buf_dispose(&val);
2034 2035 2036 2037 2038 2039 2040 2041 2042

	if (error < 0) {
		char *str;
		git_vector_foreach(problems, i, str)
			git__free(str);

		git_vector_free(problems);
	}

2043 2044 2045
	return error;
}

2046
int git_remote_rename(git_strarray *out, git_repository *repo, const char *name, const char *new_name)
2047 2048
{
	int error;
2049
	git_vector problem_refspecs = GIT_VECTOR_INIT;
2050
	git_remote *remote = NULL;
2051

2052
	assert(out && repo && name && new_name);
2053

2054
	if ((error = git_remote_lookup(&remote, repo, name)) < 0)
2055
		return error;
2056

2057
	if ((error = ensure_remote_name_is_valid(new_name)) < 0)
2058
		goto cleanup;
2059

2060 2061
	if ((error = ensure_remote_doesnot_exist(repo, new_name)) < 0)
		goto cleanup;
2062

2063 2064
	if ((error = rename_remote_config_section(repo, name, new_name)) < 0)
		goto cleanup;
2065

2066 2067
	if ((error = update_branch_remote_config_entry(repo, name, new_name)) < 0)
		goto cleanup;
2068

2069 2070
	if ((error = rename_remote_references(repo, name, new_name)) < 0)
		goto cleanup;
2071

2072
	if ((error = rename_fetch_refspecs(&problem_refspecs, remote, new_name)) < 0)
2073
		goto cleanup;
2074

2075 2076 2077
	out->count = problem_refspecs.length;
	out->strings = (char **) problem_refspecs.contents;

2078 2079 2080
cleanup:
	if (error < 0)
		git_vector_free(&problem_refspecs);
2081

2082 2083
	git_remote_free(remote);
	return error;
2084
}
2085

2086 2087 2088 2089 2090 2091 2092 2093 2094 2095 2096 2097 2098
int git_remote_is_valid_name(
	const char *remote_name)
{
	git_buf buf = GIT_BUF_INIT;
	git_refspec refspec;
	int error = -1;

	if (!remote_name || *remote_name == '\0')
		return 0;

	git_buf_printf(&buf, "refs/heads/test:refs/remotes/%s/test", remote_name);
	error = git_refspec__parse(&refspec, git_buf_cstr(&buf), true);

2099
	git_buf_dispose(&buf);
2100
	git_refspec__dispose(&refspec);
2101

2102
	git_error_clear();
2103 2104
	return error == 0;
}
2105 2106 2107 2108 2109 2110

git_refspec *git_remote__matching_refspec(git_remote *remote, const char *refname)
{
	git_refspec *spec;
	size_t i;

2111
	git_vector_foreach(&remote->active_refspecs, i, spec) {
2112 2113 2114 2115 2116 2117 2118 2119 2120 2121 2122 2123 2124 2125 2126
		if (spec->push)
			continue;

		if (git_refspec_src_matches(spec, refname))
			return spec;
	}

	return NULL;
}

git_refspec *git_remote__matching_dst_refspec(git_remote *remote, const char *refname)
{
	git_refspec *spec;
	size_t i;

2127
	git_vector_foreach(&remote->active_refspecs, i, spec) {
2128 2129 2130 2131 2132 2133 2134 2135 2136 2137
		if (spec->push)
			continue;

		if (git_refspec_dst_matches(spec, refname))
			return spec;
	}

	return NULL;
}

2138
int git_remote_add_fetch(git_repository *repo, const char *remote, const char *refspec)
2139
{
2140
	return write_add_refspec(repo, remote, refspec, true);
2141 2142
}

2143
int git_remote_add_push(git_repository *repo, const char *remote, const char *refspec)
2144
{
2145
	return write_add_refspec(repo, remote, refspec, false);
2146 2147
}

2148
static int copy_refspecs(git_strarray *array, const git_remote *remote, unsigned int push)
2149 2150 2151 2152 2153 2154 2155 2156 2157 2158 2159 2160 2161
{
	size_t i;
	git_vector refspecs;
	git_refspec *spec;
	char *dup;

	if (git_vector_init(&refspecs, remote->refspecs.length, NULL) < 0)
		return -1;

	git_vector_foreach(&remote->refspecs, i, spec) {
		if (spec->push != push)
			continue;

2162
		if ((dup = git__strdup(spec->string)) == NULL)
2163 2164 2165 2166 2167 2168 2169 2170 2171 2172 2173 2174 2175 2176
			goto on_error;

		if (git_vector_insert(&refspecs, dup) < 0) {
			git__free(dup);
			goto on_error;
		}
	}

	array->strings = (char **)refspecs.contents;
	array->count = refspecs.length;

	return 0;

on_error:
2177
	git_vector_free_deep(&refspecs);
2178 2179 2180 2181

	return -1;
}

2182
int git_remote_get_fetch_refspecs(git_strarray *array, const git_remote *remote)
2183 2184 2185 2186
{
	return copy_refspecs(array, remote, false);
}

2187
int git_remote_get_push_refspecs(git_strarray *array, const git_remote *remote)
2188 2189 2190
{
	return copy_refspecs(array, remote, true);
}
2191

2192
size_t git_remote_refspec_count(const git_remote *remote)
2193 2194 2195 2196
{
	return remote->refspecs.length;
}

2197
const git_refspec *git_remote_get_refspec(const git_remote *remote, size_t n)
2198 2199 2200
{
	return git_vector_get(&remote->refspecs, n);
}
2201

2202
int git_remote_init_callbacks(git_remote_callbacks *opts, unsigned int version)
2203
{
2204 2205 2206
	GIT_INIT_STRUCTURE_FROM_TEMPLATE(
		opts, version, git_remote_callbacks, GIT_REMOTE_CALLBACKS_INIT);
	return 0;
2207
}
2208

2209 2210
/* asserts a branch.<foo>.remote format */
static const char *name_offset(size_t *len_out, const char *name)
2211
{
2212 2213
	size_t prefix_len;
	const char *dot;
2214

2215 2216
	prefix_len = strlen("remote.");
	dot = strchr(name + prefix_len, '.');
2217

2218
	assert(dot);
2219

2220 2221
	*len_out = dot - name - prefix_len;
	return name + prefix_len;
2222 2223 2224 2225 2226 2227 2228 2229
}

static int remove_branch_config_related_entries(
	git_repository *repo,
	const char *remote_name)
{
	int error;
	git_config *config;
2230 2231 2232
	git_config_entry *entry;
	git_config_iterator *iter;
	git_buf buf = GIT_BUF_INIT;
2233 2234 2235 2236

	if ((error = git_repository_config__weakptr(&config, repo)) < 0)
		return error;

2237
	if ((error = git_config_iterator_glob_new(&iter, config, "branch\\..+\\.remote")) < 0)
2238 2239
		return error;

2240 2241 2242 2243
	/* find any branches with us as upstream and remove that config */
	while ((error = git_config_next(&entry, iter)) == 0) {
		const char *branch;
		size_t branch_len;
2244

2245 2246
		if (strcmp(remote_name, entry->value))
			continue;
2247

2248
		branch = name_offset(&branch_len, entry->name);
2249

2250 2251 2252 2253
		git_buf_clear(&buf);
		if (git_buf_printf(&buf, "branch.%.*s.merge", (int)branch_len, branch) < 0)
			break;

2254 2255 2256
		if ((error = git_config_delete_entry(config, git_buf_cstr(&buf))) < 0) {
			if (error != GIT_ENOTFOUND)
				break;
2257
			git_error_clear();
2258
		}
2259 2260 2261 2262 2263

		git_buf_clear(&buf);
		if (git_buf_printf(&buf, "branch.%.*s.remote", (int)branch_len, branch) < 0)
			break;

2264 2265 2266
		if ((error = git_config_delete_entry(config, git_buf_cstr(&buf))) < 0) {
			if (error != GIT_ENOTFOUND)
				break;
2267
			git_error_clear();
2268
		}
2269 2270
	}

2271 2272 2273
	if (error == GIT_ITEROVER)
		error = 0;

2274
	git_buf_dispose(&buf);
2275
	git_config_iterator_free(iter);
2276 2277 2278
	return error;
}

2279
static int remove_refs(git_repository *repo, const git_refspec *spec)
2280
{
2281 2282
	git_reference_iterator *iter = NULL;
	git_vector refs;
2283
	const char *name;
2284
	char *dup;
2285
	int error;
2286
	size_t i;
2287

2288
	if ((error = git_vector_init(&refs, 8, NULL)) < 0)
2289 2290
		return error;

2291 2292 2293
	if ((error = git_reference_iterator_new(&iter, repo)) < 0)
		goto cleanup;

2294
	while ((error = git_reference_next_name(&name, iter)) == 0) {
2295 2296 2297 2298 2299 2300 2301 2302
		if (!git_refspec_dst_matches(spec, name))
			continue;

		dup = git__strdup(name);
		if (!dup) {
			error = -1;
			goto cleanup;
		}
2303

2304 2305 2306
		if ((error = git_vector_insert(&refs, dup)) < 0)
			goto cleanup;
	}
2307 2308
	if (error == GIT_ITEROVER)
		error = 0;
2309 2310 2311 2312 2313 2314 2315
	if (error < 0)
		goto cleanup;

	git_vector_foreach(&refs, i, name) {
		if ((error = git_reference_remove(repo, name)) < 0)
			break;
	}
2316

2317 2318 2319 2320 2321 2322
cleanup:
	git_reference_iterator_free(iter);
	git_vector_foreach(&refs, i, dup) {
		git__free(dup);
	}
	git_vector_free(&refs);
2323 2324 2325 2326 2327 2328 2329 2330 2331 2332
	return error;
}

static int remove_remote_tracking(git_repository *repo, const char *remote_name)
{
	git_remote *remote;
	int error;
	size_t i, count;

	/* we want to use what's on the config, regardless of changes to the instance in memory */
2333
	if ((error = git_remote_lookup(&remote, repo, remote_name)) < 0)
2334 2335 2336 2337 2338 2339 2340 2341 2342 2343
		return error;

	count = git_remote_refspec_count(remote);
	for (i = 0; i < count; i++) {
		const git_refspec *refspec = git_remote_get_refspec(remote, i);

		/* shouldn't ever actually happen */
		if (refspec == NULL)
			continue;

2344
		if ((error = remove_refs(repo, refspec)) < 0)
2345 2346 2347 2348 2349 2350 2351
			break;
	}

	git_remote_free(remote);
	return error;
}

2352
int git_remote_delete(git_repository *repo, const char *name)
2353 2354 2355
{
	int error;

2356
	assert(repo && name);
2357

2358 2359 2360
	if ((error = remove_branch_config_related_entries(repo, name)) < 0 ||
	    (error = remove_remote_tracking(repo, name)) < 0 ||
	    (error = rename_remote_config_section(repo, name, NULL)) < 0)
2361 2362
		return error;

2363 2364
	return 0;
}
2365 2366 2367 2368 2369 2370 2371 2372 2373

int git_remote_default_branch(git_buf *out, git_remote *remote)
{
	const git_remote_head **heads;
	const git_remote_head *guess = NULL;
	const git_oid *head_id;
	size_t heads_len, i;
	int error;

2374 2375
	assert(out);

2376 2377 2378 2379 2380 2381
	if ((error = git_remote_ls(&heads, &heads_len, remote)) < 0)
		return error;

	if (heads_len == 0)
		return GIT_ENOTFOUND;

2382 2383 2384
	if (strcmp(heads[0]->name, GIT_HEAD_FILE))
		return GIT_ENOTFOUND;

2385 2386 2387 2388 2389 2390 2391 2392 2393 2394 2395 2396 2397 2398 2399 2400
	git_buf_sanitize(out);
	/* the first one must be HEAD so if that has the symref info, we're done */
	if (heads[0]->symref_target)
		return git_buf_puts(out, heads[0]->symref_target);

	/*
	 * If there's no symref information, we have to look over them
	 * and guess. We return the first match unless the master
	 * branch is a candidate. Then we return the master branch.
	 */
	head_id = &heads[0]->oid;

	for (i = 1; i < heads_len; i++) {
		if (git_oid_cmp(head_id, &heads[i]->oid))
			continue;

2401 2402 2403
		if (git__prefixcmp(heads[i]->name, GIT_REFS_HEADS_DIR))
			continue;

2404 2405 2406 2407 2408 2409 2410 2411 2412 2413 2414 2415 2416 2417 2418 2419
		if (!guess) {
			guess = heads[i];
			continue;
		}

		if (!git__strcmp(GIT_REFS_HEADS_MASTER_FILE, heads[i]->name)) {
			guess = heads[i];
			break;
		}
	}

	if (!guess)
		return GIT_ENOTFOUND;

	return git_buf_puts(out, guess->name);
}
2420

2421
int git_remote_upload(git_remote *remote, const git_strarray *refspecs, const git_push_options *opts)
2422 2423
{
	size_t i;
2424 2425
	int error;
	git_push *push;
2426
	git_refspec *spec;
2427
	const git_remote_callbacks *cbs = NULL;
2428
	git_remote_connection_opts conn = GIT_REMOTE_CONNECTION_OPTIONS_INIT;
2429

2430
	assert(remote);
2431

2432
	if (!remote->repo) {
2433
		git_error_set(GIT_ERROR_INVALID, "cannot download detached remote");
2434 2435 2436
		return -1;
	}

2437
	if (opts) {
2438
		cbs = &opts->callbacks;
2439 2440
		conn.custom_headers = &opts->custom_headers;
		conn.proxy = &opts->proxy_opts;
2441
	}
2442

2443
	if (!git_remote_connected(remote) &&
2444
	    (error = git_remote__connect(remote, GIT_DIRECTION_PUSH, cbs, &conn)) < 0)
2445 2446
		goto cleanup;

2447
	free_refspecs(&remote->active_refspecs);
Leo Yang committed
2448
	if ((error = dwim_refspecs(&remote->active_refspecs, &remote->refspecs, &remote->refs)) < 0)
2449 2450
		goto cleanup;

2451 2452 2453 2454 2455 2456
	if (remote->push) {
		git_push_free(remote->push);
		remote->push = NULL;
	}

	if ((error = git_push_new(&remote->push, remote)) < 0)
2457 2458
		return error;

2459
	push = remote->push;
2460 2461 2462 2463

	if (opts && (error = git_push_set_options(push, opts)) < 0)
		goto cleanup;

2464 2465 2466 2467 2468 2469 2470 2471 2472 2473 2474 2475
	if (refspecs && refspecs->count > 0) {
		for (i = 0; i < refspecs->count; i++) {
			if ((error = git_push_add_refspec(push, refspecs->strings[i])) < 0)
				goto cleanup;
		}
	} else {
		git_vector_foreach(&remote->refspecs, i, spec) {
			if (!spec->push)
				continue;
			if ((error = git_push_add_refspec(push, spec->string)) < 0)
				goto cleanup;
		}
2476 2477
	}

2478
	if ((error = git_push_finish(push, cbs)) < 0)
2479 2480
		goto cleanup;

2481
	if (cbs && cbs->push_update_reference &&
2482
	    (error = git_push_status_foreach(push, cbs->push_update_reference, cbs->payload)) < 0)
2483 2484 2485
		goto cleanup;

cleanup:
2486 2487 2488
	return error;
}

2489
int git_remote_push(git_remote *remote, const git_strarray *refspecs, const git_push_options *opts)
2490 2491
{
	int error;
2492
	const git_remote_callbacks *cbs = NULL;
2493
	const git_strarray *custom_headers = NULL;
2494
	const git_proxy_options *proxy = NULL;
2495

2496 2497 2498
	assert(remote);

	if (!remote->repo) {
2499
		git_error_set(GIT_ERROR_INVALID, "cannot download detached remote");
2500 2501 2502
		return -1;
	}

2503
	if (opts) {
2504
		GIT_ERROR_CHECK_VERSION(&opts->callbacks, GIT_REMOTE_CALLBACKS_VERSION, "git_remote_callbacks");
2505
		cbs = &opts->callbacks;
2506
		custom_headers = &opts->custom_headers;
2507
		GIT_ERROR_CHECK_VERSION(&opts->proxy_opts, GIT_PROXY_OPTIONS_VERSION, "git_proxy_options");
2508
		proxy = &opts->proxy_opts;
2509
	}
2510

2511
	assert(remote);
2512

2513
	if ((error = git_remote_connect(remote, GIT_DIRECTION_PUSH, cbs, proxy, custom_headers)) < 0)
2514 2515 2516 2517 2518
		return error;

	if ((error = git_remote_upload(remote, refspecs, opts)) < 0)
		return error;

2519
	error = git_remote_update_tips(remote, cbs, 0, 0, NULL);
2520

2521 2522 2523
	git_remote_disconnect(remote);
	return error;
}
2524 2525 2526 2527 2528 2529 2530 2531 2532 2533 2534 2535 2536 2537 2538 2539 2540 2541 2542 2543 2544 2545 2546 2547 2548 2549 2550 2551 2552

#define PREFIX "url"
#define SUFFIX_FETCH "insteadof"
#define SUFFIX_PUSH "pushinsteadof"

char *apply_insteadof(git_config *config, const char *url, int direction)
{
	size_t match_length, prefix_length, suffix_length;
	char *replacement = NULL;
	const char *regexp;

	git_buf result = GIT_BUF_INIT;
	git_config_entry *entry;
	git_config_iterator *iter;

	assert(config);
	assert(url);
	assert(direction == GIT_DIRECTION_FETCH || direction == GIT_DIRECTION_PUSH);

	/* Add 1 to prefix/suffix length due to the additional escaped dot */
	prefix_length = strlen(PREFIX) + 1;
	if (direction == GIT_DIRECTION_FETCH) {
		regexp = PREFIX "\\..*\\." SUFFIX_FETCH;
		suffix_length = strlen(SUFFIX_FETCH) + 1;
	} else {
		regexp = PREFIX "\\..*\\." SUFFIX_PUSH;
		suffix_length = strlen(SUFFIX_PUSH) + 1;
	}

2553 2554
	if (git_config_iterator_glob_new(&iter, config, regexp) < 0)
		return NULL;
2555 2556 2557 2558 2559 2560 2561 2562 2563 2564 2565 2566 2567 2568 2569 2570 2571 2572 2573 2574 2575 2576 2577 2578 2579 2580 2581 2582 2583 2584 2585 2586 2587 2588

	match_length = 0;
	while (git_config_next(&entry, iter) == 0) {
		size_t n, replacement_length;

		/* Check if entry value is a prefix of URL */
		if (git__prefixcmp(url, entry->value))
			continue;
		/* Check if entry value is longer than previous
		 * prefixes */
		if ((n = strlen(entry->value)) <= match_length)
			continue;

		git__free(replacement);
		match_length = n;

		/* Cut off prefix and suffix of the value */
		replacement_length =
		    strlen(entry->name) - (prefix_length + suffix_length);
		replacement = git__strndup(entry->name + prefix_length,
				replacement_length);
	}

	git_config_iterator_free(iter);

	if (match_length == 0)
		return git__strdup(url);

	git_buf_printf(&result, "%s%s", replacement, url + match_length);

	git__free(replacement);

	return result.ptr;
}