remote.c 62.8 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
#ifndef GIT_DEPRECATE_HARD
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
#endif
204

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

215
	assert(out && url);
216

217 218 219 220
	if (!opts) {
		opts = &dummy_opts;
	}

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

	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;
	}
236

237
	remote = git__calloc(1, sizeof(git_remote));
238
	GIT_ERROR_CHECK_ALLOC(remote);
239

240
	remote->repo = opts->repository;
241

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

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

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

257 258 259 260
		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))
261
			goto on_error;
262 263
	}

264 265 266 267 268 269 270 271 272 273 274 275 276
	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)
277 278
			goto on_error;

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

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

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

296

297
	git_buf_dispose(&var);
298

299
	*out = remote;
Edward Thomson committed
300
	error = 0;
301 302

on_error:
Edward Thomson committed
303 304 305
	if (error)
		git_remote_free(remote);

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

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

319 320 321 322 323 324 325 326 327 328 329 330
	/* 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;

331
	error = git_remote_create_with_opts(out, url, &opts);
332

333
	git_buf_dispose(&buf);
334

335
	return error;
336 337
}

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

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

346 347 348
	opts.repository = repo;
	opts.name = name;
	opts.fetchspec = fetch;
349
	opts.flags = GIT_REMOTE_CREATE_SKIP_DEFAULT_FETCHSPEC;
350

351
	return git_remote_create_with_opts(out, url, &opts);
352 353
}

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

	opts.repository = repo;

360
	return git_remote_create_with_opts(out, url, &opts);
361 362
}

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

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

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

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

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

	remote->repo = source->repo;
	remote->download_tags = source->download_tags;
393
	remote->prune_refs = source->prune_refs;
Arthur Schreiber committed
394

395 396 397 398 399
	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
400 401
	}

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

Arthur Schreiber committed
407 408
	*dest = remote;

409 410 411 412 413 414
cleanup:

	if (error < 0)
		git__free(remote);

	return error;
Arthur Schreiber committed
415 416
}

417 418 419 420 421 422 423
struct refspec_cb_data {
	git_remote *remote;
	int fetch;
};

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

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

	if (git_buf_oom(buf))
		return -1;

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

443 444 445
	if (found)
		*found = !error;

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

	return error;
}

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

464 465
	assert(out && repo && name);

466 467 468
	if ((error = ensure_remote_name_is_valid(name)) < 0)
		return error;

469
	if ((error = git_repository_config_snapshot(&config, repo)) < 0)
470
		return error;
471

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

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

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

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

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

492 493
	optional_setting_found |= found;

494
	remote->repo = repo;
495
	remote->download_tags = GIT_REMOTE_DOWNLOAD_TAGS_AUTO;
496 497

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

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

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

509 510 511 512
	optional_setting_found |= found;

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

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

522 523
	data.remote = remote;
	data.fetch = true;
524

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

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

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

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

538
	if ((error = download_tags_value(remote, config)) < 0)
539 540
		goto cleanup;

541 542 543 544
	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
545
	if ((error = dwim_refspecs(&remote->active_refspecs, &remote->refspecs, &remote->refs)) < 0)
546 547 548 549 550 551
		goto cleanup;

	*out = remote;

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

	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;

565 566 567 568
	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) {
569
			git_error_clear();
570 571 572

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

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

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

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

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

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

608
	assert(repo && remote);
609

610 611 612 613 614 615 616 617 618 619 620 621 622 623 624 625 626 627 628
	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:
629 630
	git_buf_dispose(&canonical_url);
	git_buf_dispose(&buf);
631 632 633 634 635 636 637

	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);
638 639
}

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

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

651
static int resolve_url(git_buf *resolved_url, const char *url, int direction, const git_remote_callbacks *callbacks)
652
{
653 654 655 656 657 658 659 660 661 662 663
	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;
		}
	}
664

665 666 667 668 669 670 671 672
	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);
673 674
	assert(direction == GIT_DIRECTION_FETCH || direction == GIT_DIRECTION_PUSH);

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

681 682 683 684 685 686
	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;
687
	}
688
	return resolve_url(url_out, url, direction, callbacks);
689 690
}

691
static int remote_transport_set_callbacks(git_transport *t, const git_remote_callbacks *cbs)
692 693 694 695 696 697 698 699
{
	if (!t->set_callbacks || !cbs)
		return 0;

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

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

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

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

718 719
	assert(remote);

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

727
	if (conn->proxy)
728
		GIT_ERROR_CHECK_VERSION(conn->proxy, GIT_PROXY_OPTIONS_VERSION, "git_proxy_options");
729

730 731
	t = remote->transport;

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

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

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

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

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

	remote->transport = t;

755 756
	git_buf_dispose(&url);

757
	return 0;
758

759
on_error:
760 761 762 763
	if (t)
		t->free(t);

	git_buf_dispose(&url);
764 765 766 767

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

768
	return error;
769 770
}

771 772 773 774 775 776 777 778 779 780
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);
}

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

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

790
	return remote->transport->ls(out, size, remote->transport);
791 792
}

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

	assert(remote);

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

	*proxy_url = NULL;

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

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

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

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

820
		error = git_config__lookup_entry(&ce, cfg, git_buf_cstr(&buf), false);
821
		git_buf_dispose(&buf);
822

823
		if (error < 0)
824
			return error;
825

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

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

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

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

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

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

		return error;
855
	}
856 857 858 859

	*proxy_url = git_buf_detach(&val);

found:
860
	GIT_ERROR_CHECK_ALLOC(*proxy_url);
861
	git_config_entry_free(ce);
862 863 864 865

	return 0;
}

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

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

877 878
	return 0;
}
879

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

885
	git_vector_foreach(vec, i, spec) {
886
		git_refspec__dispose(spec);
887
		git__free(spec);
888 889
	}

890
	git_vector_clear(vec);
891 892 893 894 895 896 897 898 899 900
}

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);
}

901 902 903 904 905 906 907 908 909 910 911 912 913 914 915 916 917 918 919
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;
}

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

929
	assert(remote);
930

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

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

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

948
	if (ls_to_vector(&refs, remote) < 0)
949 950
		return -1;

951 952 953
	if ((git_vector_init(&specs, 0, NULL)) < 0)
		goto on_error;

954
	remote->passed_refspecs = 0;
955
	if (!refspecs || !refspecs->count) {
956 957 958 959 960 961 962 963
		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;
964
		remote->passed_refspecs = 1;
965 966
	}

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

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

974
	git_vector_free(&refs);
975 976
	free_refspecs(&specs);
	git_vector_free(&specs);
977 978

	if (error < 0)
979
		return error;
980

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

986
	if ((error = git_fetch_negotiate(remote, opts)) < 0)
987
		return error;
988

989
	return git_fetch_download_pack(remote, cbs);
990 991 992 993 994 995

on_error:
	git_vector_free(&refs);
	free_refspecs(&specs);
	git_vector_free(&specs);
	return error;
996 997
}

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

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

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

1025
	error = git_remote_download(remote, refspecs, opts);
1026 1027 1028 1029

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

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

1034 1035 1036 1037 1038 1039 1040 1041
	/* 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);
	}

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

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

	if (prune)
1058
		error = git_remote_prune(remote, cbs);
1059

1060
	return error;
1061 1062
}

1063 1064 1065 1066 1067 1068 1069 1070
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
1071 1072 1073 1074 1075

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

	return 0;
}

1082 1083 1084 1085 1086 1087 1088 1089 1090 1091 1092 1093 1094 1095 1096 1097 1098 1099
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) {
1100
			git_error_clear();
1101 1102 1103 1104 1105 1106 1107 1108
			error = 0;
		}

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

1109 1110
	git_buf_dispose(&upstream_remote);
	git_buf_dispose(&upstream_name);
1111 1112 1113
	return error;
}

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

1122
	assert(out && spec && ref);
1123 1124 1125

	*out = NULL;

1126 1127 1128
	error = git_reference_resolve(&resolved_ref, ref);

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

1136 1137 1138 1139 1140 1141 1142 1143 1144 1145
	/*
	 * The ref name may be unresolvable - perhaps it's pointing to
	 * something invalid.  In this case, there is no remote head for
	 * this ref.
	 */
	if (!ref_name) {
		error = 0;
		goto cleanup;
	}

1146
	if ((error = ref_to_update(&update, &remote_name, remote, spec, ref_name)) < 0)
1147 1148
		goto cleanup;

1149 1150
	if (update)
		error = remote_head_for_fetchspec_src(out, update_heads, git_buf_cstr(&remote_name));
1151 1152

cleanup:
1153
	git_buf_dispose(&remote_name);
1154
	git_reference_free(resolved_ref);
1155
	git_config_free(config);
1156 1157 1158
	return error;
}

1159
static int git_remote_write_fetchhead(git_remote *remote, git_refspec *spec, git_vector *update_heads)
1160 1161 1162 1163 1164 1165 1166 1167 1168 1169 1170
{
	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);

1171 1172 1173 1174
	/* no heads, nothing to do */
	if (update_heads->length == 0)
		return 0;

1175 1176 1177 1178 1179 1180 1181 1182 1183
	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 ||
1184
			(error = remote_head_for_ref(&merge_remote_ref, remote, spec, update_heads, head_ref)) < 0)
1185 1186 1187 1188 1189 1190 1191 1192
				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
1193
	git_vector_foreach(update_heads, i, remote_ref) {
1194 1195 1196 1197 1198 1199 1200 1201 1202 1203 1204 1205 1206 1207 1208 1209 1210 1211 1212 1213 1214 1215 1216 1217 1218 1219 1220 1221 1222 1223
		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;
}

1224 1225 1226 1227 1228
/**
 * 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)
1229 1230
{
	git_strarray arr = { 0 };
1231
	size_t i;
1232 1233 1234 1235 1236
	int error;

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

1237 1238 1239 1240 1241 1242 1243 1244
	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);
1245
		GIT_ERROR_CHECK_ALLOC(refname_dup);
1246 1247 1248 1249 1250 1251

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

out:
1252
	git_strarray_dispose(&arr);
1253 1254 1255 1256 1257 1258 1259 1260 1261 1262 1263
	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);
}

1264
int git_remote_prune(git_remote *remote, const git_remote_callbacks *callbacks)
1265 1266 1267 1268 1269 1270 1271 1272 1273
{
	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 }};

1274
	if (callbacks)
1275
		GIT_ERROR_CHECK_VERSION(callbacks, GIT_REMOTE_CALLBACKS_VERSION, "git_remote_callbacks");
1276

1277 1278 1279
	if ((error = ls_to_vector(&remote_refs, remote)) < 0)
		goto cleanup;

1280
	git_vector_set_cmp(&remote_refs, find_head);
1281

1282 1283
	if ((error = prune_candidates(&candidates, remote)) < 0)
		goto cleanup;
1284

1285 1286 1287 1288 1289 1290 1291 1292 1293 1294 1295 1296
	/*
	 * 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))
1297 1298
				continue;

1299 1300
			if ((error = git_refspec_rtransform(&buf, spec, refname)) < 0)
				goto cleanup;
1301

1302
			key.name = (char *) git_buf_cstr(&buf);
1303
			error = git_vector_bsearch(&pos, &remote_refs, &key);
1304
			git_buf_dispose(&buf);
1305

1306 1307
			if (error < 0 && error != GIT_ENOTFOUND)
				goto cleanup;
1308

1309
			if (error == GIT_ENOTFOUND)
1310 1311
				continue;

1312 1313 1314 1315 1316 1317
			/* 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;
1318 1319 1320
		}
	}

1321 1322 1323 1324 1325 1326 1327 1328 1329 1330 1331 1332 1333 1334 1335 1336 1337 1338 1339 1340 1341
	/*
	 * 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;

1342
		if (git_reference_type(ref) == GIT_REFERENCE_SYMBOLIC) {
1343 1344 1345 1346 1347 1348 1349 1350 1351 1352
			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;

1353 1354
		if (callbacks && callbacks->update_tips)
			error = callbacks->update_tips(refname, &id, &zero_id, callbacks->payload);
1355 1356 1357 1358 1359

		if (error < 0)
			goto cleanup;
	}

1360 1361
cleanup:
	git_vector_free(&remote_refs);
1362
	git_vector_free_deep(&candidates);
1363 1364 1365
	return error;
}

1366 1367
static int update_tips_for_spec(
		git_remote *remote,
1368
		const git_remote_callbacks *callbacks,
1369
		int update_fetchhead,
1370
		git_remote_autotag_option_t tagopt,
1371 1372 1373
		git_refspec *spec,
		git_vector *refs,
		const char *log_message)
1374
{
1375
	int error = 0, autotag;
1376
	unsigned int i = 0;
1377
	git_buf refname = GIT_BUF_INIT;
1378
	git_oid old;
1379
	git_odb *odb;
1380 1381
	git_remote_head *head;
	git_reference *ref;
1382
	git_refspec tagspec;
1383
	git_vector update_heads;
1384

1385 1386
	assert(remote);

1387
	if (git_repository_odb__weakptr(&odb, remote->repo) < 0)
1388 1389
		return -1;

1390
	if (git_refspec__parse(&tagspec, GIT_REFSPEC_TAGS, true) < 0)
1391 1392
		return -1;

1393
	/* Make a copy of the transport's refs */
1394
	if (git_vector_init(&update_heads, 16, NULL) < 0)
1395
		return -1;
1396

1397 1398
	for (; i < refs->length; ++i) {
		head = git_vector_get(refs, i);
1399
		autotag = 0;
1400
		git_buf_clear(&refname);
1401

1402 1403 1404 1405
		/* Ignore malformed ref names (which also saves us from tag^{} */
		if (!git_reference_is_valid_name(head->name))
			continue;

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

1410
				if (tagopt == GIT_REMOTE_DOWNLOAD_TAGS_AUTO)
1411
					autotag = 1;
1412

1413 1414 1415 1416
				git_buf_clear(&refname);
				if (git_buf_puts(&refname, head->name) < 0)
					goto on_error;
			}
1417 1418 1419 1420
		}

		/* If we didn't want to auto-follow the tag, check if the refspec matches */
		if (!autotag && git_refspec_src_matches(spec, head->name)) {
1421 1422 1423 1424 1425 1426 1427 1428 1429 1430 1431 1432 1433
			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;
			}
1434 1435 1436 1437
		}

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

1441
		/* In autotag mode, only create tags for objects already in db */
1442 1443
		if (autotag && !git_odb_exists(odb, &head->oid))
			continue;
1444

1445
		if (!autotag && git_vector_insert(&update_heads, head) < 0)
1446 1447
			goto on_error;

1448
		error = git_reference_name_to_id(&old, remote->repo, refname.ptr);
1449
		if (error < 0 && error != GIT_ENOTFOUND)
1450 1451
			goto on_error;

1452
		if (error == GIT_ENOTFOUND) {
1453 1454
			memset(&old, 0, GIT_OID_RAWSZ);

1455 1456 1457 1458
			if (autotag && git_vector_insert(&update_heads, head) < 0)
				goto on_error;
		}

1459
		if (!git_oid__cmp(&old, &head->oid))
1460
			continue;
1461

1462
		/* In autotag mode, don't overwrite any locally-existing tags */
1463
		error = git_reference_create(&ref, remote->repo, refname.ptr, &head->oid, !autotag,
1464
				log_message);
1465 1466 1467 1468 1469

		if (error == GIT_EEXISTS)
			continue;

		if (error < 0)
1470
			goto on_error;
1471 1472

		git_reference_free(ref);
1473

1474 1475
		if (callbacks && callbacks->update_tips != NULL) {
			if (callbacks->update_tips(refname.ptr, &old, &head->oid, callbacks->payload) < 0)
1476 1477
				goto on_error;
		}
1478 1479
	}

1480
	if (update_fetchhead &&
1481
	    (error = git_remote_write_fetchhead(remote, spec, &update_heads)) < 0)
1482 1483 1484
		goto on_error;

	git_vector_free(&update_heads);
1485
	git_refspec__dispose(&tagspec);
1486
	git_buf_dispose(&refname);
1487 1488 1489
	return 0;

on_error:
1490
	git_vector_free(&update_heads);
1491
	git_refspec__dispose(&tagspec);
1492
	git_buf_dispose(&refname);
1493
	return -1;
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 1542 1543 1544 1545 1546 1547 1548 1549 1550 1551 1552 1553
/**
 * 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;
}

1554 1555
static int opportunistic_updates(const git_remote *remote, const git_remote_callbacks *callbacks,
				 git_vector *refs, const char *msg)
1556 1557 1558 1559 1560 1561
{
	size_t i, j, k;
	git_refspec *spec;
	git_remote_head *head;
	git_reference *ref;
	git_buf refname = GIT_BUF_INIT;
1562
	int error = 0;
1563 1564 1565 1566

	i = j = k = 0;

	while ((error = next_head(remote, refs, &spec, &head, &i, &j, &k)) == 0) {
1567
		git_oid old = {{ 0 }};
1568 1569 1570 1571 1572 1573 1574 1575
		/*
		 * 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
		 */

1576
		git_buf_clear(&refname);
1577
		if ((error = git_refspec_transform(&refname, spec, head->name)) < 0)
1578
			goto cleanup;
1579

1580 1581 1582 1583 1584 1585
		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;
1586

1587 1588 1589 1590 1591 1592
		/* 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);
1593
		if (error < 0)
1594 1595 1596 1597 1598 1599
			goto cleanup;

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

1602 1603 1604 1605
	if (error == GIT_ITEROVER)
		error = 0;

cleanup:
1606
	git_buf_dispose(&refname);
1607
	return error;
1608 1609
}

1610 1611 1612 1613 1614 1615 1616 1617 1618
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);
1619
	git_buf_dispose(&path);
1620 1621 1622 1623

	return error;
}

1624 1625
int git_remote_update_tips(
		git_remote *remote,
1626
		const git_remote_callbacks *callbacks,
1627
		int update_fetchhead,
1628
		git_remote_autotag_option_t download_tags,
1629
		const char *reflog_message)
1630
{
1631
	git_refspec *spec, tagspec;
1632
	git_vector refs = GIT_VECTOR_INIT;
1633
	git_remote_autotag_option_t tagopt;
1634
	int error;
1635 1636
	size_t i;

1637 1638
	/* push has its own logic hidden away in the push object */
	if (remote->push) {
1639
		return git_push_update_tips(remote->push, callbacks);
1640 1641
	}

1642 1643 1644
	if (git_refspec__parse(&tagspec, GIT_REFSPEC_TAGS, true) < 0)
		return -1;

1645 1646

	if ((error = ls_to_vector(&refs, remote)) < 0)
1647 1648
		goto out;

1649
	if (download_tags == GIT_REMOTE_DOWNLOAD_TAGS_UNSPECIFIED)
1650 1651 1652 1653
		tagopt = remote->download_tags;
	else
		tagopt = download_tags;

1654 1655 1656
	if ((error = truncate_fetch_head(git_repository_path(remote->repo))) < 0)
		goto out;

1657 1658
	if (tagopt == GIT_REMOTE_DOWNLOAD_TAGS_ALL) {
		if ((error = update_tips_for_spec(remote, callbacks, update_fetchhead, tagopt, &tagspec, &refs, reflog_message)) < 0)
1659
			goto out;
1660
	}
1661

1662
	git_vector_foreach(&remote->active_refspecs, i, spec) {
1663 1664 1665
		if (spec->push)
			continue;

1666
		if ((error = update_tips_for_spec(remote, callbacks, update_fetchhead, tagopt, spec, &refs, reflog_message)) < 0)
1667
			goto out;
1668 1669
	}

1670 1671
	/* only try to do opportunisitic updates if the refpec lists differ */
	if (remote->passed_refspecs)
1672
		error = opportunistic_updates(remote, callbacks, &refs, reflog_message);
1673

1674
out:
1675
	git_vector_free(&refs);
1676
	git_refspec__dispose(&tagspec);
1677
	return error;
1678 1679
}

1680
int git_remote_connected(const git_remote *remote)
1681
{
1682
	assert(remote);
1683 1684 1685 1686 1687

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

	/* Ask the transport if it's connected. */
1688
	return remote->transport->is_connected(remote->transport);
1689 1690
}

1691
int git_remote_stop(git_remote *remote)
1692
{
1693 1694 1695
	assert(remote);

	if (remote->transport && remote->transport->cancel)
1696
		remote->transport->cancel(remote->transport);
1697 1698

	return 0;
1699 1700
}

1701
int git_remote_disconnect(git_remote *remote)
1702
{
1703 1704
	assert(remote);

1705 1706
	if (git_remote_connected(remote))
		remote->transport->close(remote->transport);
1707 1708

	return 0;
1709 1710
}

Carlos Martín Nieto committed
1711 1712
void git_remote_free(git_remote *remote)
{
1713 1714 1715
	if (remote == NULL)
		return;

1716 1717 1718 1719 1720 1721 1722 1723 1724
	if (remote->transport != NULL) {
		git_remote_disconnect(remote);

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

	git_vector_free(&remote->refs);

1725
	free_refspecs(&remote->refspecs);
1726 1727
	git_vector_free(&remote->refspecs);

1728 1729 1730
	free_refspecs(&remote->active_refspecs);
	git_vector_free(&remote->active_refspecs);

1731 1732 1733
	free_refspecs(&remote->passive_refspecs);
	git_vector_free(&remote->passive_refspecs);

1734
	git_push_free(remote->push);
1735
	git__free(remote->url);
1736
	git__free(remote->pushurl);
1737 1738
	git__free(remote->name);
	git__free(remote);
Carlos Martín Nieto committed
1739
}
1740

1741
static int remote_list_cb(const git_config_entry *entry, void *payload)
1742
{
1743
	git_vector *list = payload;
1744 1745 1746
	const char *name = entry->name + strlen("remote.");
	size_t namelen = strlen(name);
	char *remote_name;
1747

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

1750 1751 1752 1753
	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" */
1754
	GIT_ERROR_CHECK_ALLOC(remote_name);
1755

1756
	return git_vector_insert(list, remote_name);
1757 1758 1759 1760 1761
}

int git_remote_list(git_strarray *remotes_list, git_repository *repo)
{
	int error;
1762
	git_config *cfg;
1763
	git_vector list = GIT_VECTOR_INIT;
1764

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

1768
	if ((error = git_vector_init(&list, 4, git__strcmp_cb)) < 0)
1769
		return error;
1770

1771
	error = git_config_foreach_match(
1772
		cfg, "^remote\\..*\\.(push)?url$", remote_list_cb, &list);
1773

1774
	if (error < 0) {
1775
		git_vector_free_deep(&list);
1776 1777 1778
		return error;
	}

1779
	git_vector_uniq(&list, git__free);
1780

1781 1782
	remotes_list->strings =
		(char **)git_vector_detach(&remotes_list->count, NULL, &list);
1783

1784
	return 0;
1785
}
1786

1787
const git_indexer_progress *git_remote_stats(git_remote *remote)
1788 1789 1790 1791 1792
{
	assert(remote);
	return &remote->stats;
}

1793
git_remote_autotag_option_t git_remote_autotag(const git_remote *remote)
1794 1795 1796 1797
{
	return remote->download_tags;
}

1798
int git_remote_set_autotag(git_repository *repo, const char *remote, git_remote_autotag_option_t value)
1799
{
1800 1801 1802 1803 1804 1805 1806 1807 1808 1809 1810 1811 1812 1813 1814 1815 1816 1817 1818 1819 1820 1821 1822 1823 1824 1825 1826 1827
	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:
1828
		git_error_set(GIT_ERROR_INVALID, "invalid value for the tagopt setting");
1829 1830 1831
		error = -1;
	}

1832
	git_buf_dispose(&var);
1833
	return error;
1834
}
1835

1836 1837 1838 1839 1840
int git_remote_prune_refs(const git_remote *remote)
{
	return remote->prune_refs;
}

1841 1842 1843 1844 1845 1846 1847 1848 1849 1850 1851 1852
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;

1853 1854 1855
	if (new_name &&
		(git_buf_printf(&new_section_name, "remote.%s", new_name) < 0))
			goto cleanup;
1856 1857 1858 1859

	error = git_config_rename_section(
		repo,
		git_buf_cstr(&old_section_name),
1860
		new_name ? git_buf_cstr(&new_section_name) : NULL);
1861 1862

cleanup:
1863 1864
	git_buf_dispose(&old_section_name);
	git_buf_dispose(&new_section_name);
1865 1866 1867 1868

	return error;
}

1869
struct update_data {
1870 1871 1872 1873 1874 1875 1876 1877 1878 1879 1880 1881 1882 1883
	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;

1884 1885
	return git_config_set_string(
		data->config, entry->name, data->new_remote_name);
1886 1887 1888 1889 1890 1891 1892
}

static int update_branch_remote_config_entry(
	git_repository *repo,
	const char *old_name,
	const char *new_name)
{
1893 1894
	int error;
	struct update_data data = { NULL };
1895

1896 1897
	if ((error = git_repository_config__weakptr(&data.config, repo)) < 0)
		return error;
1898 1899 1900 1901

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

1902
	return git_config_foreach_match(
1903
		data.config, "branch\\..+\\.remote", update_config_entries_cb, &data);
1904 1905 1906
}

static int rename_one_remote_reference(
1907
	git_reference *reference_in,
1908 1909 1910
	const char *old_remote_name,
	const char *new_remote_name)
{
1911
	int error;
1912 1913
	git_reference *ref = NULL, *dummy = NULL;
	git_buf namespace = GIT_BUF_INIT, old_namespace = GIT_BUF_INIT;
1914
	git_buf new_name = GIT_BUF_INIT;
1915
	git_buf log_message = GIT_BUF_INIT;
1916 1917
	size_t pfx_len;
	const char *target;
1918

1919 1920 1921 1922 1923 1924
	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)
1925
		goto cleanup;
1926

1927 1928 1929 1930
	if ((error = git_buf_printf(&log_message,
					"renamed remote %s to %s",
					old_remote_name, new_remote_name)) < 0)
		goto cleanup;
1931

1932
	if ((error = git_reference_rename(&ref, reference_in, git_buf_cstr(&new_name), 1,
1933
					  git_buf_cstr(&log_message))) < 0)
1934 1935
		goto cleanup;

1936
	if (git_reference_type(ref) != GIT_REFERENCE_SYMBOLIC)
1937 1938 1939 1940 1941 1942 1943 1944 1945 1946 1947 1948 1949 1950 1951 1952
		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),
1953
						  git_buf_cstr(&log_message));
1954 1955

	git_reference_free(dummy);
1956 1957

cleanup:
1958 1959
	git_reference_free(reference_in);
	git_reference_free(ref);
1960 1961 1962 1963
	git_buf_dispose(&namespace);
	git_buf_dispose(&old_namespace);
	git_buf_dispose(&new_name);
	git_buf_dispose(&log_message);
1964 1965 1966 1967 1968 1969 1970 1971
	return error;
}

static int rename_remote_references(
	git_repository *repo,
	const char *old_name,
	const char *new_name)
{
1972
	int error;
1973
	git_buf buf = GIT_BUF_INIT;
Vicent Marti committed
1974
	git_reference *ref;
1975
	git_reference_iterator *iter;
1976

1977
	if ((error = git_buf_printf(&buf, GIT_REFS_REMOTES_DIR "%s/*", old_name)) < 0)
1978
		return error;
1979

1980
	error = git_reference_iterator_glob_new(&iter, repo, git_buf_cstr(&buf));
1981
	git_buf_dispose(&buf);
1982

1983 1984 1985 1986
	if (error < 0)
		return error;

	while ((error = git_reference_next(&ref, iter)) == 0) {
1987 1988
		if ((error = rename_one_remote_reference(ref, old_name, new_name)) < 0)
			break;
1989 1990 1991
	}

	git_reference_iterator_free(iter);
1992

1993
	return (error == GIT_ITEROVER) ? 0 : error;
1994 1995
}

1996
static int rename_fetch_refspecs(git_vector *problems, git_remote *remote, const char *new_name)
1997 1998
{
	git_config *config;
1999
	git_buf base = GIT_BUF_INIT, var = GIT_BUF_INIT, val = GIT_BUF_INIT;
2000
	const git_refspec *spec;
2001
	size_t i;
2002
	int error = 0;
2003

2004
	if ((error = git_repository_config__weakptr(&config, remote->repo)) < 0)
2005 2006
		return error;

2007 2008 2009
	if ((error = git_vector_init(problems, 1, NULL)) < 0)
		return error;

2010
	if ((error = default_fetchspec_for_name(&base, remote->name)) < 0)
2011
		return error;
2012

2013
	git_vector_foreach(&remote->refspecs, i, spec) {
2014 2015
		if (spec->push)
			continue;
2016

2017
		/* Does the dst part of the refspec follow the expected format? */
2018
		if (strcmp(git_buf_cstr(&base), spec->string)) {
2019
			char *dup;
2020

2021
			dup = git__strdup(spec->string);
2022
			GIT_ERROR_CHECK_ALLOC(dup);
2023 2024

			if ((error = git_vector_insert(problems, dup)) < 0)
2025
				break;
2026

2027 2028
			continue;
		}
2029

2030
		/* If we do want to move it to the new section */
2031

2032 2033
		git_buf_clear(&val);
		git_buf_clear(&var);
2034

2035
		if (default_fetchspec_for_name(&val, new_name) < 0 ||
2036 2037 2038
			git_buf_printf(&var, "remote.%s.fetch", new_name) < 0)
		{
			error = -1;
2039
			break;
2040
		}
2041

2042 2043
		if ((error = git_config_set_string(
				config, git_buf_cstr(&var), git_buf_cstr(&val))) < 0)
2044
			break;
2045
	}
2046

2047 2048 2049
	git_buf_dispose(&base);
	git_buf_dispose(&var);
	git_buf_dispose(&val);
2050 2051 2052 2053 2054 2055 2056 2057 2058

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

		git_vector_free(problems);
	}

2059 2060 2061
	return error;
}

2062
int git_remote_rename(git_strarray *out, git_repository *repo, const char *name, const char *new_name)
2063 2064
{
	int error;
2065
	git_vector problem_refspecs = GIT_VECTOR_INIT;
2066
	git_remote *remote = NULL;
2067

2068
	assert(out && repo && name && new_name);
2069

2070
	if ((error = git_remote_lookup(&remote, repo, name)) < 0)
2071
		return error;
2072

2073
	if ((error = ensure_remote_name_is_valid(new_name)) < 0)
2074
		goto cleanup;
2075

2076 2077
	if ((error = ensure_remote_doesnot_exist(repo, new_name)) < 0)
		goto cleanup;
2078

2079 2080
	if ((error = rename_remote_config_section(repo, name, new_name)) < 0)
		goto cleanup;
2081

2082 2083
	if ((error = update_branch_remote_config_entry(repo, name, new_name)) < 0)
		goto cleanup;
2084

2085 2086
	if ((error = rename_remote_references(repo, name, new_name)) < 0)
		goto cleanup;
2087

2088
	if ((error = rename_fetch_refspecs(&problem_refspecs, remote, new_name)) < 0)
2089
		goto cleanup;
2090

2091 2092 2093
	out->count = problem_refspecs.length;
	out->strings = (char **) problem_refspecs.contents;

2094 2095 2096
cleanup:
	if (error < 0)
		git_vector_free(&problem_refspecs);
2097

2098 2099
	git_remote_free(remote);
	return error;
2100
}
2101

2102 2103 2104 2105 2106 2107 2108 2109 2110 2111 2112 2113 2114
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);

2115
	git_buf_dispose(&buf);
2116
	git_refspec__dispose(&refspec);
2117

2118
	git_error_clear();
2119 2120
	return error == 0;
}
2121 2122 2123 2124 2125 2126

git_refspec *git_remote__matching_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 2138 2139 2140 2141 2142
		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;

2143
	git_vector_foreach(&remote->active_refspecs, i, spec) {
2144 2145 2146 2147 2148 2149 2150 2151 2152 2153
		if (spec->push)
			continue;

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

	return NULL;
}

2154
int git_remote_add_fetch(git_repository *repo, const char *remote, const char *refspec)
2155
{
2156
	return write_add_refspec(repo, remote, refspec, true);
2157 2158
}

2159
int git_remote_add_push(git_repository *repo, const char *remote, const char *refspec)
2160
{
2161
	return write_add_refspec(repo, remote, refspec, false);
2162 2163
}

2164
static int copy_refspecs(git_strarray *array, const git_remote *remote, unsigned int push)
2165 2166 2167 2168 2169 2170 2171 2172 2173 2174 2175 2176 2177
{
	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;

2178
		if ((dup = git__strdup(spec->string)) == NULL)
2179 2180 2181 2182 2183 2184 2185 2186 2187 2188 2189 2190 2191 2192
			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:
2193
	git_vector_free_deep(&refspecs);
2194 2195 2196 2197

	return -1;
}

2198
int git_remote_get_fetch_refspecs(git_strarray *array, const git_remote *remote)
2199 2200 2201 2202
{
	return copy_refspecs(array, remote, false);
}

2203
int git_remote_get_push_refspecs(git_strarray *array, const git_remote *remote)
2204 2205 2206
{
	return copy_refspecs(array, remote, true);
}
2207

2208
size_t git_remote_refspec_count(const git_remote *remote)
2209 2210 2211 2212
{
	return remote->refspecs.length;
}

2213
const git_refspec *git_remote_get_refspec(const git_remote *remote, size_t n)
2214 2215 2216
{
	return git_vector_get(&remote->refspecs, n);
}
2217

2218
int git_remote_init_callbacks(git_remote_callbacks *opts, unsigned int version)
2219
{
2220 2221 2222
	GIT_INIT_STRUCTURE_FROM_TEMPLATE(
		opts, version, git_remote_callbacks, GIT_REMOTE_CALLBACKS_INIT);
	return 0;
2223
}
2224

2225 2226
/* asserts a branch.<foo>.remote format */
static const char *name_offset(size_t *len_out, const char *name)
2227
{
2228 2229
	size_t prefix_len;
	const char *dot;
2230

2231 2232
	prefix_len = strlen("remote.");
	dot = strchr(name + prefix_len, '.');
2233

2234
	assert(dot);
2235

2236 2237
	*len_out = dot - name - prefix_len;
	return name + prefix_len;
2238 2239 2240 2241 2242 2243 2244 2245
}

static int remove_branch_config_related_entries(
	git_repository *repo,
	const char *remote_name)
{
	int error;
	git_config *config;
2246 2247 2248
	git_config_entry *entry;
	git_config_iterator *iter;
	git_buf buf = GIT_BUF_INIT;
2249 2250 2251 2252

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

2253
	if ((error = git_config_iterator_glob_new(&iter, config, "branch\\..+\\.remote")) < 0)
2254 2255
		return error;

2256 2257 2258 2259
	/* 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;
2260

2261 2262
		if (strcmp(remote_name, entry->value))
			continue;
2263

2264
		branch = name_offset(&branch_len, entry->name);
2265

2266 2267 2268 2269
		git_buf_clear(&buf);
		if (git_buf_printf(&buf, "branch.%.*s.merge", (int)branch_len, branch) < 0)
			break;

2270 2271 2272
		if ((error = git_config_delete_entry(config, git_buf_cstr(&buf))) < 0) {
			if (error != GIT_ENOTFOUND)
				break;
2273
			git_error_clear();
2274
		}
2275 2276 2277 2278 2279

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

2280 2281 2282
		if ((error = git_config_delete_entry(config, git_buf_cstr(&buf))) < 0) {
			if (error != GIT_ENOTFOUND)
				break;
2283
			git_error_clear();
2284
		}
2285 2286
	}

2287 2288 2289
	if (error == GIT_ITEROVER)
		error = 0;

2290
	git_buf_dispose(&buf);
2291
	git_config_iterator_free(iter);
2292 2293 2294
	return error;
}

2295
static int remove_refs(git_repository *repo, const git_refspec *spec)
2296
{
2297 2298
	git_reference_iterator *iter = NULL;
	git_vector refs;
2299
	const char *name;
2300
	char *dup;
2301
	int error;
2302
	size_t i;
2303

2304
	if ((error = git_vector_init(&refs, 8, NULL)) < 0)
2305 2306
		return error;

2307 2308 2309
	if ((error = git_reference_iterator_new(&iter, repo)) < 0)
		goto cleanup;

2310
	while ((error = git_reference_next_name(&name, iter)) == 0) {
2311 2312 2313 2314 2315 2316 2317 2318
		if (!git_refspec_dst_matches(spec, name))
			continue;

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

2320 2321 2322
		if ((error = git_vector_insert(&refs, dup)) < 0)
			goto cleanup;
	}
2323 2324
	if (error == GIT_ITEROVER)
		error = 0;
2325 2326 2327 2328 2329 2330 2331
	if (error < 0)
		goto cleanup;

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

2333 2334 2335 2336 2337 2338
cleanup:
	git_reference_iterator_free(iter);
	git_vector_foreach(&refs, i, dup) {
		git__free(dup);
	}
	git_vector_free(&refs);
2339 2340 2341 2342 2343 2344 2345 2346 2347 2348
	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 */
2349
	if ((error = git_remote_lookup(&remote, repo, remote_name)) < 0)
2350 2351 2352 2353 2354 2355 2356 2357 2358 2359
		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;

2360
		if ((error = remove_refs(repo, refspec)) < 0)
2361 2362 2363 2364 2365 2366 2367
			break;
	}

	git_remote_free(remote);
	return error;
}

2368
int git_remote_delete(git_repository *repo, const char *name)
2369 2370 2371
{
	int error;

2372
	assert(repo && name);
2373

2374 2375 2376
	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)
2377 2378
		return error;

2379 2380
	return 0;
}
2381 2382 2383 2384 2385 2386 2387

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;
2388
	git_buf local_default = GIT_BUF_INIT;
2389 2390
	int error;

2391 2392
	assert(out);

2393
	if ((error = git_remote_ls(&heads, &heads_len, remote)) < 0)
2394
		goto done;
2395

2396 2397 2398 2399
	if (heads_len == 0 || strcmp(heads[0]->name, GIT_HEAD_FILE)) {
		error = GIT_ENOTFOUND;
		goto done;
	}
2400

2401
	git_buf_sanitize(out);
2402

2403
	/* the first one must be HEAD so if that has the symref info, we're done */
2404 2405 2406 2407
	if (heads[0]->symref_target) {
		error = git_buf_puts(out, heads[0]->symref_target);
		goto done;
	}
2408 2409 2410

	/*
	 * If there's no symref information, we have to look over them
2411 2412
	 * and guess. We return the first match unless the default
	 * branch is a candidate. Then we return the default branch.
2413
	 */
2414 2415 2416 2417

	if ((error = git_repository_initialbranch(&local_default, remote->repo)) < 0)
		goto done;

2418 2419 2420 2421 2422 2423
	head_id = &heads[0]->oid;

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

2424 2425 2426
		if (git__prefixcmp(heads[i]->name, GIT_REFS_HEADS_DIR))
			continue;

2427 2428 2429 2430 2431
		if (!guess) {
			guess = heads[i];
			continue;
		}

2432
		if (!git__strcmp(local_default.ptr, heads[i]->name)) {
2433 2434 2435 2436 2437
			guess = heads[i];
			break;
		}
	}

2438 2439 2440 2441 2442 2443
	if (!guess) {
		error = GIT_ENOTFOUND;
		goto done;
	}

	error = git_buf_puts(out, guess->name);
2444

2445 2446 2447
done:
	git_buf_dispose(&local_default);
	return error;
2448
}
2449

2450
int git_remote_upload(git_remote *remote, const git_strarray *refspecs, const git_push_options *opts)
2451 2452
{
	size_t i;
2453 2454
	int error;
	git_push *push;
2455
	git_refspec *spec;
2456
	const git_remote_callbacks *cbs = NULL;
2457
	git_remote_connection_opts conn = GIT_REMOTE_CONNECTION_OPTIONS_INIT;
2458

2459
	assert(remote);
2460

2461
	if (!remote->repo) {
2462
		git_error_set(GIT_ERROR_INVALID, "cannot download detached remote");
2463 2464 2465
		return -1;
	}

2466
	if (opts) {
2467
		cbs = &opts->callbacks;
2468 2469
		conn.custom_headers = &opts->custom_headers;
		conn.proxy = &opts->proxy_opts;
2470
	}
2471

2472
	if (!git_remote_connected(remote) &&
2473
	    (error = git_remote__connect(remote, GIT_DIRECTION_PUSH, cbs, &conn)) < 0)
2474 2475
		goto cleanup;

2476
	free_refspecs(&remote->active_refspecs);
Leo Yang committed
2477
	if ((error = dwim_refspecs(&remote->active_refspecs, &remote->refspecs, &remote->refs)) < 0)
2478 2479
		goto cleanup;

2480 2481 2482 2483 2484 2485
	if (remote->push) {
		git_push_free(remote->push);
		remote->push = NULL;
	}

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

2488
	push = remote->push;
2489 2490 2491 2492

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

2493 2494 2495 2496 2497 2498 2499 2500 2501 2502 2503 2504
	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;
		}
2505 2506
	}

2507
	if ((error = git_push_finish(push, cbs)) < 0)
2508 2509
		goto cleanup;

2510
	if (cbs && cbs->push_update_reference &&
2511
	    (error = git_push_status_foreach(push, cbs->push_update_reference, cbs->payload)) < 0)
2512 2513 2514
		goto cleanup;

cleanup:
2515 2516 2517
	return error;
}

2518
int git_remote_push(git_remote *remote, const git_strarray *refspecs, const git_push_options *opts)
2519 2520
{
	int error;
2521
	const git_remote_callbacks *cbs = NULL;
2522
	const git_strarray *custom_headers = NULL;
2523
	const git_proxy_options *proxy = NULL;
2524

2525 2526 2527
	assert(remote);

	if (!remote->repo) {
2528
		git_error_set(GIT_ERROR_INVALID, "cannot download detached remote");
2529 2530 2531
		return -1;
	}

2532
	if (opts) {
2533
		GIT_ERROR_CHECK_VERSION(&opts->callbacks, GIT_REMOTE_CALLBACKS_VERSION, "git_remote_callbacks");
2534
		cbs = &opts->callbacks;
2535
		custom_headers = &opts->custom_headers;
2536
		GIT_ERROR_CHECK_VERSION(&opts->proxy_opts, GIT_PROXY_OPTIONS_VERSION, "git_proxy_options");
2537
		proxy = &opts->proxy_opts;
2538
	}
2539

2540
	assert(remote);
2541

2542
	if ((error = git_remote_connect(remote, GIT_DIRECTION_PUSH, cbs, proxy, custom_headers)) < 0)
2543 2544 2545 2546 2547
		return error;

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

2548
	error = git_remote_update_tips(remote, cbs, 0, 0, NULL);
2549

2550 2551 2552
	git_remote_disconnect(remote);
	return error;
}
2553 2554 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

#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;
	}

2582 2583
	if (git_config_iterator_glob_new(&iter, config, regexp) < 0)
		return NULL;
2584 2585 2586 2587 2588 2589 2590 2591 2592 2593 2594 2595 2596 2597 2598 2599 2600 2601 2602 2603 2604 2605 2606 2607 2608 2609 2610 2611 2612 2613 2614 2615 2616 2617

	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;
}