remote.c 62.4 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;
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 1132 1133 1134 1135
		ref_name = git_reference_symbolic_target(ref);
		error = 0;
	} else {
		ref_name = git_reference_name(resolved_ref);
	}

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

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

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

1149
static int git_remote_write_fetchhead(git_remote *remote, git_refspec *spec, git_vector *update_heads)
1150 1151 1152 1153 1154 1155 1156 1157 1158 1159 1160
{
	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);

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

1165 1166 1167 1168 1169 1170 1171 1172 1173
	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 ||
1174
			(error = remote_head_for_ref(&merge_remote_ref, remote, spec, update_heads, head_ref)) < 0)
1175 1176 1177 1178 1179 1180 1181 1182
				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
1183
	git_vector_foreach(update_heads, i, remote_ref) {
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 1212 1213
		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;
}

1214 1215 1216 1217 1218
/**
 * 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)
1219 1220
{
	git_strarray arr = { 0 };
1221
	size_t i;
1222 1223 1224 1225 1226
	int error;

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

1227 1228 1229 1230 1231 1232 1233 1234
	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);
1235
		GIT_ERROR_CHECK_ALLOC(refname_dup);
1236 1237 1238 1239 1240 1241

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

out:
1242
	git_strarray_dispose(&arr);
1243 1244 1245 1246 1247 1248 1249 1250 1251 1252 1253
	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);
}

1254
int git_remote_prune(git_remote *remote, const git_remote_callbacks *callbacks)
1255 1256 1257 1258 1259 1260 1261 1262 1263
{
	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 }};

1264
	if (callbacks)
1265
		GIT_ERROR_CHECK_VERSION(callbacks, GIT_REMOTE_CALLBACKS_VERSION, "git_remote_callbacks");
1266

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

1270
	git_vector_set_cmp(&remote_refs, find_head);
1271

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

1275 1276 1277 1278 1279 1280 1281 1282 1283 1284 1285 1286
	/*
	 * 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))
1287 1288
				continue;

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

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

1296 1297
			if (error < 0 && error != GIT_ENOTFOUND)
				goto cleanup;
1298

1299
			if (error == GIT_ENOTFOUND)
1300 1301
				continue;

1302 1303 1304 1305 1306 1307
			/* 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;
1308 1309 1310
		}
	}

1311 1312 1313 1314 1315 1316 1317 1318 1319 1320 1321 1322 1323 1324 1325 1326 1327 1328 1329 1330 1331
	/*
	 * 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;

1332
		if (git_reference_type(ref) == GIT_REFERENCE_SYMBOLIC) {
1333 1334 1335 1336 1337 1338 1339 1340 1341 1342
			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;

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

		if (error < 0)
			goto cleanup;
	}

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

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

1375 1376
	assert(remote);

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

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

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

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

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

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

1400
				if (tagopt == GIT_REMOTE_DOWNLOAD_TAGS_AUTO)
1401
					autotag = 1;
1402

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

		/* If we didn't want to auto-follow the tag, check if the refspec matches */
		if (!autotag && git_refspec_src_matches(spec, head->name)) {
1411 1412 1413 1414 1415 1416 1417 1418 1419 1420 1421 1422 1423
			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;
			}
1424 1425 1426 1427
		}

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

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

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

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

1442
		if (error == GIT_ENOTFOUND) {
1443 1444
			memset(&old, 0, GIT_OID_RAWSZ);

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

1449
		if (!git_oid__cmp(&old, &head->oid))
1450
			continue;
1451

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

		if (error == GIT_EEXISTS)
			continue;

		if (error < 0)
1460
			goto on_error;
1461 1462

		git_reference_free(ref);
1463

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

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

	git_vector_free(&update_heads);
1475
	git_refspec__dispose(&tagspec);
1476
	git_buf_dispose(&refname);
1477 1478 1479
	return 0;

on_error:
1480
	git_vector_free(&update_heads);
1481
	git_refspec__dispose(&tagspec);
1482
	git_buf_dispose(&refname);
1483
	return -1;
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 1542 1543
/**
 * 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;
}

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

	i = j = k = 0;

	while ((error = next_head(remote, refs, &spec, &head, &i, &j, &k)) == 0) {
1557
		git_oid old = {{ 0 }};
1558 1559 1560 1561 1562 1563 1564 1565
		/*
		 * 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
		 */

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

1570 1571 1572 1573 1574 1575
		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;
1576

1577 1578 1579 1580 1581 1582
		/* 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);
1583
		if (error < 0)
1584 1585 1586 1587 1588 1589
			goto cleanup;

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

1592 1593 1594 1595
	if (error == GIT_ITEROVER)
		error = 0;

cleanup:
1596
	git_buf_dispose(&refname);
1597
	return error;
1598 1599
}

1600 1601 1602 1603 1604 1605 1606 1607 1608
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);
1609
	git_buf_dispose(&path);
1610 1611 1612 1613

	return error;
}

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

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

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

1635 1636

	if ((error = ls_to_vector(&refs, remote)) < 0)
1637 1638
		goto out;

1639
	if (download_tags == GIT_REMOTE_DOWNLOAD_TAGS_UNSPECIFIED)
1640 1641 1642 1643
		tagopt = remote->download_tags;
	else
		tagopt = download_tags;

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

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

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

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

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

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

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

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

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

1681
int git_remote_stop(git_remote *remote)
1682
{
1683 1684 1685
	assert(remote);

	if (remote->transport && remote->transport->cancel)
1686
		remote->transport->cancel(remote->transport);
1687 1688

	return 0;
1689 1690
}

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

1695 1696
	if (git_remote_connected(remote))
		remote->transport->close(remote->transport);
1697 1698

	return 0;
1699 1700
}

Carlos Martín Nieto committed
1701 1702
void git_remote_free(git_remote *remote)
{
1703 1704 1705
	if (remote == NULL)
		return;

1706 1707 1708 1709 1710 1711 1712 1713 1714
	if (remote->transport != NULL) {
		git_remote_disconnect(remote);

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

	git_vector_free(&remote->refs);

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

1718 1719 1720
	free_refspecs(&remote->active_refspecs);
	git_vector_free(&remote->active_refspecs);

1721 1722 1723
	free_refspecs(&remote->passive_refspecs);
	git_vector_free(&remote->passive_refspecs);

1724
	git_push_free(remote->push);
1725
	git__free(remote->url);
1726
	git__free(remote->pushurl);
1727 1728
	git__free(remote->name);
	git__free(remote);
Carlos Martín Nieto committed
1729
}
1730

1731
static int remote_list_cb(const git_config_entry *entry, void *payload)
1732
{
1733
	git_vector *list = payload;
1734 1735 1736
	const char *name = entry->name + strlen("remote.");
	size_t namelen = strlen(name);
	char *remote_name;
1737

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

1740 1741 1742 1743
	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" */
1744
	GIT_ERROR_CHECK_ALLOC(remote_name);
1745

1746
	return git_vector_insert(list, remote_name);
1747 1748 1749 1750 1751
}

int git_remote_list(git_strarray *remotes_list, git_repository *repo)
{
	int error;
1752
	git_config *cfg;
1753
	git_vector list = GIT_VECTOR_INIT;
1754

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

1758
	if ((error = git_vector_init(&list, 4, git__strcmp_cb)) < 0)
1759
		return error;
1760

1761
	error = git_config_foreach_match(
1762
		cfg, "^remote\\..*\\.(push)?url$", remote_list_cb, &list);
1763

1764
	if (error < 0) {
1765
		git_vector_free_deep(&list);
1766 1767 1768
		return error;
	}

1769
	git_vector_uniq(&list, git__free);
1770

1771 1772
	remotes_list->strings =
		(char **)git_vector_detach(&remotes_list->count, NULL, &list);
1773

1774
	return 0;
1775
}
1776

1777
const git_indexer_progress *git_remote_stats(git_remote *remote)
1778 1779 1780 1781 1782
{
	assert(remote);
	return &remote->stats;
}

1783
git_remote_autotag_option_t git_remote_autotag(const git_remote *remote)
1784 1785 1786 1787
{
	return remote->download_tags;
}

1788
int git_remote_set_autotag(git_repository *repo, const char *remote, git_remote_autotag_option_t value)
1789
{
1790 1791 1792 1793 1794 1795 1796 1797 1798 1799 1800 1801 1802 1803 1804 1805 1806 1807 1808 1809 1810 1811 1812 1813 1814 1815 1816 1817
	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:
1818
		git_error_set(GIT_ERROR_INVALID, "invalid value for the tagopt setting");
1819 1820 1821
		error = -1;
	}

1822
	git_buf_dispose(&var);
1823
	return error;
1824
}
1825

1826 1827 1828 1829 1830
int git_remote_prune_refs(const git_remote *remote)
{
	return remote->prune_refs;
}

1831 1832 1833 1834 1835 1836 1837 1838 1839 1840 1841 1842
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;

1843 1844 1845
	if (new_name &&
		(git_buf_printf(&new_section_name, "remote.%s", new_name) < 0))
			goto cleanup;
1846 1847 1848 1849

	error = git_config_rename_section(
		repo,
		git_buf_cstr(&old_section_name),
1850
		new_name ? git_buf_cstr(&new_section_name) : NULL);
1851 1852

cleanup:
1853 1854
	git_buf_dispose(&old_section_name);
	git_buf_dispose(&new_section_name);
1855 1856 1857 1858

	return error;
}

1859
struct update_data {
1860 1861 1862 1863 1864 1865 1866 1867 1868 1869 1870 1871 1872 1873
	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;

1874 1875
	return git_config_set_string(
		data->config, entry->name, data->new_remote_name);
1876 1877 1878 1879 1880 1881 1882
}

static int update_branch_remote_config_entry(
	git_repository *repo,
	const char *old_name,
	const char *new_name)
{
1883 1884
	int error;
	struct update_data data = { NULL };
1885

1886 1887
	if ((error = git_repository_config__weakptr(&data.config, repo)) < 0)
		return error;
1888 1889 1890 1891

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

1892
	return git_config_foreach_match(
1893
		data.config, "branch\\..+\\.remote", update_config_entries_cb, &data);
1894 1895 1896
}

static int rename_one_remote_reference(
1897
	git_reference *reference_in,
1898 1899 1900
	const char *old_remote_name,
	const char *new_remote_name)
{
1901
	int error;
1902 1903
	git_reference *ref = NULL, *dummy = NULL;
	git_buf namespace = GIT_BUF_INIT, old_namespace = GIT_BUF_INIT;
1904
	git_buf new_name = GIT_BUF_INIT;
1905
	git_buf log_message = GIT_BUF_INIT;
1906 1907
	size_t pfx_len;
	const char *target;
1908

1909 1910 1911 1912 1913 1914
	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)
1915
		goto cleanup;
1916

1917 1918 1919 1920
	if ((error = git_buf_printf(&log_message,
					"renamed remote %s to %s",
					old_remote_name, new_remote_name)) < 0)
		goto cleanup;
1921

1922
	if ((error = git_reference_rename(&ref, reference_in, git_buf_cstr(&new_name), 1,
1923
					  git_buf_cstr(&log_message))) < 0)
1924 1925
		goto cleanup;

1926
	if (git_reference_type(ref) != GIT_REFERENCE_SYMBOLIC)
1927 1928 1929 1930 1931 1932 1933 1934 1935 1936 1937 1938 1939 1940 1941 1942
		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),
1943
						  git_buf_cstr(&log_message));
1944 1945

	git_reference_free(dummy);
1946 1947

cleanup:
1948 1949
	git_reference_free(reference_in);
	git_reference_free(ref);
1950 1951 1952 1953
	git_buf_dispose(&namespace);
	git_buf_dispose(&old_namespace);
	git_buf_dispose(&new_name);
	git_buf_dispose(&log_message);
1954 1955 1956 1957 1958 1959 1960 1961
	return error;
}

static int rename_remote_references(
	git_repository *repo,
	const char *old_name,
	const char *new_name)
{
1962
	int error;
1963
	git_buf buf = GIT_BUF_INIT;
Vicent Marti committed
1964
	git_reference *ref;
1965
	git_reference_iterator *iter;
1966

1967
	if ((error = git_buf_printf(&buf, GIT_REFS_REMOTES_DIR "%s/*", old_name)) < 0)
1968
		return error;
1969

1970
	error = git_reference_iterator_glob_new(&iter, repo, git_buf_cstr(&buf));
1971
	git_buf_dispose(&buf);
1972

1973 1974 1975 1976
	if (error < 0)
		return error;

	while ((error = git_reference_next(&ref, iter)) == 0) {
1977 1978
		if ((error = rename_one_remote_reference(ref, old_name, new_name)) < 0)
			break;
1979 1980 1981
	}

	git_reference_iterator_free(iter);
1982

1983
	return (error == GIT_ITEROVER) ? 0 : error;
1984 1985
}

1986
static int rename_fetch_refspecs(git_vector *problems, git_remote *remote, const char *new_name)
1987 1988
{
	git_config *config;
1989
	git_buf base = GIT_BUF_INIT, var = GIT_BUF_INIT, val = GIT_BUF_INIT;
1990
	const git_refspec *spec;
1991
	size_t i;
1992
	int error = 0;
1993

1994
	if ((error = git_repository_config__weakptr(&config, remote->repo)) < 0)
1995 1996
		return error;

1997 1998 1999
	if ((error = git_vector_init(problems, 1, NULL)) < 0)
		return error;

2000
	if ((error = default_fetchspec_for_name(&base, remote->name)) < 0)
2001
		return error;
2002

2003
	git_vector_foreach(&remote->refspecs, i, spec) {
2004 2005
		if (spec->push)
			continue;
2006

2007
		/* Does the dst part of the refspec follow the expected format? */
2008
		if (strcmp(git_buf_cstr(&base), spec->string)) {
2009
			char *dup;
2010

2011
			dup = git__strdup(spec->string);
2012
			GIT_ERROR_CHECK_ALLOC(dup);
2013 2014

			if ((error = git_vector_insert(problems, dup)) < 0)
2015
				break;
2016

2017 2018
			continue;
		}
2019

2020
		/* If we do want to move it to the new section */
2021

2022 2023
		git_buf_clear(&val);
		git_buf_clear(&var);
2024

2025
		if (default_fetchspec_for_name(&val, new_name) < 0 ||
2026 2027 2028
			git_buf_printf(&var, "remote.%s.fetch", new_name) < 0)
		{
			error = -1;
2029
			break;
2030
		}
2031

2032 2033
		if ((error = git_config_set_string(
				config, git_buf_cstr(&var), git_buf_cstr(&val))) < 0)
2034
			break;
2035
	}
2036

2037 2038 2039
	git_buf_dispose(&base);
	git_buf_dispose(&var);
	git_buf_dispose(&val);
2040 2041 2042 2043 2044 2045 2046 2047 2048

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

		git_vector_free(problems);
	}

2049 2050 2051
	return error;
}

2052
int git_remote_rename(git_strarray *out, git_repository *repo, const char *name, const char *new_name)
2053 2054
{
	int error;
2055
	git_vector problem_refspecs = GIT_VECTOR_INIT;
2056
	git_remote *remote = NULL;
2057

2058
	assert(out && repo && name && new_name);
2059

2060
	if ((error = git_remote_lookup(&remote, repo, name)) < 0)
2061
		return error;
2062

2063
	if ((error = ensure_remote_name_is_valid(new_name)) < 0)
2064
		goto cleanup;
2065

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

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

2072 2073
	if ((error = update_branch_remote_config_entry(repo, name, new_name)) < 0)
		goto cleanup;
2074

2075 2076
	if ((error = rename_remote_references(repo, name, new_name)) < 0)
		goto cleanup;
2077

2078
	if ((error = rename_fetch_refspecs(&problem_refspecs, remote, new_name)) < 0)
2079
		goto cleanup;
2080

2081 2082 2083
	out->count = problem_refspecs.length;
	out->strings = (char **) problem_refspecs.contents;

2084 2085 2086
cleanup:
	if (error < 0)
		git_vector_free(&problem_refspecs);
2087

2088 2089
	git_remote_free(remote);
	return error;
2090
}
2091

2092 2093 2094 2095 2096 2097 2098 2099 2100 2101 2102 2103 2104
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);

2105
	git_buf_dispose(&buf);
2106
	git_refspec__dispose(&refspec);
2107

2108
	git_error_clear();
2109 2110
	return error == 0;
}
2111 2112 2113 2114 2115 2116

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

2117
	git_vector_foreach(&remote->active_refspecs, i, spec) {
2118 2119 2120 2121 2122 2123 2124 2125 2126 2127 2128 2129 2130 2131 2132
		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;

2133
	git_vector_foreach(&remote->active_refspecs, i, spec) {
2134 2135 2136 2137 2138 2139 2140 2141 2142 2143
		if (spec->push)
			continue;

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

	return NULL;
}

2144
int git_remote_add_fetch(git_repository *repo, const char *remote, const char *refspec)
2145
{
2146
	return write_add_refspec(repo, remote, refspec, true);
2147 2148
}

2149
int git_remote_add_push(git_repository *repo, const char *remote, const char *refspec)
2150
{
2151
	return write_add_refspec(repo, remote, refspec, false);
2152 2153
}

2154
static int copy_refspecs(git_strarray *array, const git_remote *remote, unsigned int push)
2155 2156 2157 2158 2159 2160 2161 2162 2163 2164 2165 2166 2167
{
	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;

2168
		if ((dup = git__strdup(spec->string)) == NULL)
2169 2170 2171 2172 2173 2174 2175 2176 2177 2178 2179 2180 2181 2182
			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:
2183
	git_vector_free_deep(&refspecs);
2184 2185 2186 2187

	return -1;
}

2188
int git_remote_get_fetch_refspecs(git_strarray *array, const git_remote *remote)
2189 2190 2191 2192
{
	return copy_refspecs(array, remote, false);
}

2193
int git_remote_get_push_refspecs(git_strarray *array, const git_remote *remote)
2194 2195 2196
{
	return copy_refspecs(array, remote, true);
}
2197

2198
size_t git_remote_refspec_count(const git_remote *remote)
2199 2200 2201 2202
{
	return remote->refspecs.length;
}

2203
const git_refspec *git_remote_get_refspec(const git_remote *remote, size_t n)
2204 2205 2206
{
	return git_vector_get(&remote->refspecs, n);
}
2207

2208
int git_remote_init_callbacks(git_remote_callbacks *opts, unsigned int version)
2209
{
2210 2211 2212
	GIT_INIT_STRUCTURE_FROM_TEMPLATE(
		opts, version, git_remote_callbacks, GIT_REMOTE_CALLBACKS_INIT);
	return 0;
2213
}
2214

2215 2216
/* asserts a branch.<foo>.remote format */
static const char *name_offset(size_t *len_out, const char *name)
2217
{
2218 2219
	size_t prefix_len;
	const char *dot;
2220

2221 2222
	prefix_len = strlen("remote.");
	dot = strchr(name + prefix_len, '.');
2223

2224
	assert(dot);
2225

2226 2227
	*len_out = dot - name - prefix_len;
	return name + prefix_len;
2228 2229 2230 2231 2232 2233 2234 2235
}

static int remove_branch_config_related_entries(
	git_repository *repo,
	const char *remote_name)
{
	int error;
	git_config *config;
2236 2237 2238
	git_config_entry *entry;
	git_config_iterator *iter;
	git_buf buf = GIT_BUF_INIT;
2239 2240 2241 2242

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

2243
	if ((error = git_config_iterator_glob_new(&iter, config, "branch\\..+\\.remote")) < 0)
2244 2245
		return error;

2246 2247 2248 2249
	/* 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;
2250

2251 2252
		if (strcmp(remote_name, entry->value))
			continue;
2253

2254
		branch = name_offset(&branch_len, entry->name);
2255

2256 2257 2258 2259
		git_buf_clear(&buf);
		if (git_buf_printf(&buf, "branch.%.*s.merge", (int)branch_len, branch) < 0)
			break;

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

		git_buf_clear(&buf);
		if (git_buf_printf(&buf, "branch.%.*s.remote", (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
	if (error == GIT_ITEROVER)
		error = 0;

2280
	git_buf_dispose(&buf);
2281
	git_config_iterator_free(iter);
2282 2283 2284
	return error;
}

2285
static int remove_refs(git_repository *repo, const git_refspec *spec)
2286
{
2287 2288
	git_reference_iterator *iter = NULL;
	git_vector refs;
2289
	const char *name;
2290
	char *dup;
2291
	int error;
2292
	size_t i;
2293

2294
	if ((error = git_vector_init(&refs, 8, NULL)) < 0)
2295 2296
		return error;

2297 2298 2299
	if ((error = git_reference_iterator_new(&iter, repo)) < 0)
		goto cleanup;

2300
	while ((error = git_reference_next_name(&name, iter)) == 0) {
2301 2302 2303 2304 2305 2306 2307 2308
		if (!git_refspec_dst_matches(spec, name))
			continue;

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

2310 2311 2312
		if ((error = git_vector_insert(&refs, dup)) < 0)
			goto cleanup;
	}
2313 2314
	if (error == GIT_ITEROVER)
		error = 0;
2315 2316 2317 2318 2319 2320 2321
	if (error < 0)
		goto cleanup;

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

2323 2324 2325 2326 2327 2328
cleanup:
	git_reference_iterator_free(iter);
	git_vector_foreach(&refs, i, dup) {
		git__free(dup);
	}
	git_vector_free(&refs);
2329 2330 2331 2332 2333 2334 2335 2336 2337 2338
	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 */
2339
	if ((error = git_remote_lookup(&remote, repo, remote_name)) < 0)
2340 2341 2342 2343 2344 2345 2346 2347 2348 2349
		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;

2350
		if ((error = remove_refs(repo, refspec)) < 0)
2351 2352 2353 2354 2355 2356 2357
			break;
	}

	git_remote_free(remote);
	return error;
}

2358
int git_remote_delete(git_repository *repo, const char *name)
2359 2360 2361
{
	int error;

2362
	assert(repo && name);
2363

2364 2365 2366
	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)
2367 2368
		return error;

2369 2370
	return 0;
}
2371 2372 2373 2374 2375 2376 2377 2378 2379

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;

2380 2381
	assert(out);

2382 2383 2384 2385 2386 2387
	if ((error = git_remote_ls(&heads, &heads_len, remote)) < 0)
		return error;

	if (heads_len == 0)
		return GIT_ENOTFOUND;

2388 2389 2390
	if (strcmp(heads[0]->name, GIT_HEAD_FILE))
		return GIT_ENOTFOUND;

2391 2392 2393 2394 2395 2396 2397 2398 2399 2400 2401 2402 2403 2404 2405 2406
	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;

2407 2408 2409
		if (git__prefixcmp(heads[i]->name, GIT_REFS_HEADS_DIR))
			continue;

2410 2411 2412 2413 2414 2415 2416 2417 2418 2419 2420 2421 2422 2423 2424 2425
		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);
}
2426

2427
int git_remote_upload(git_remote *remote, const git_strarray *refspecs, const git_push_options *opts)
2428 2429
{
	size_t i;
2430 2431
	int error;
	git_push *push;
2432
	git_refspec *spec;
2433
	const git_remote_callbacks *cbs = NULL;
2434
	git_remote_connection_opts conn = GIT_REMOTE_CONNECTION_OPTIONS_INIT;
2435

2436
	assert(remote);
2437

2438
	if (!remote->repo) {
2439
		git_error_set(GIT_ERROR_INVALID, "cannot download detached remote");
2440 2441 2442
		return -1;
	}

2443
	if (opts) {
2444
		cbs = &opts->callbacks;
2445 2446
		conn.custom_headers = &opts->custom_headers;
		conn.proxy = &opts->proxy_opts;
2447
	}
2448

2449
	if (!git_remote_connected(remote) &&
2450
	    (error = git_remote__connect(remote, GIT_DIRECTION_PUSH, cbs, &conn)) < 0)
2451 2452
		goto cleanup;

2453
	free_refspecs(&remote->active_refspecs);
Leo Yang committed
2454
	if ((error = dwim_refspecs(&remote->active_refspecs, &remote->refspecs, &remote->refs)) < 0)
2455 2456
		goto cleanup;

2457 2458 2459 2460 2461 2462
	if (remote->push) {
		git_push_free(remote->push);
		remote->push = NULL;
	}

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

2465
	push = remote->push;
2466 2467 2468 2469

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

2470 2471 2472 2473 2474 2475 2476 2477 2478 2479 2480 2481
	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;
		}
2482 2483
	}

2484
	if ((error = git_push_finish(push, cbs)) < 0)
2485 2486
		goto cleanup;

2487
	if (cbs && cbs->push_update_reference &&
2488
	    (error = git_push_status_foreach(push, cbs->push_update_reference, cbs->payload)) < 0)
2489 2490 2491
		goto cleanup;

cleanup:
2492 2493 2494
	return error;
}

2495
int git_remote_push(git_remote *remote, const git_strarray *refspecs, const git_push_options *opts)
2496 2497
{
	int error;
2498
	const git_remote_callbacks *cbs = NULL;
2499
	const git_strarray *custom_headers = NULL;
2500
	const git_proxy_options *proxy = NULL;
2501

2502 2503 2504
	assert(remote);

	if (!remote->repo) {
2505
		git_error_set(GIT_ERROR_INVALID, "cannot download detached remote");
2506 2507 2508
		return -1;
	}

2509
	if (opts) {
2510
		GIT_ERROR_CHECK_VERSION(&opts->callbacks, GIT_REMOTE_CALLBACKS_VERSION, "git_remote_callbacks");
2511
		cbs = &opts->callbacks;
2512
		custom_headers = &opts->custom_headers;
2513
		GIT_ERROR_CHECK_VERSION(&opts->proxy_opts, GIT_PROXY_OPTIONS_VERSION, "git_proxy_options");
2514
		proxy = &opts->proxy_opts;
2515
	}
2516

2517
	assert(remote);
2518

2519
	if ((error = git_remote_connect(remote, GIT_DIRECTION_PUSH, cbs, proxy, custom_headers)) < 0)
2520 2521 2522 2523 2524
		return error;

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

2525
	error = git_remote_update_tips(remote, cbs, 0, 0, NULL);
2526

2527 2528 2529
	git_remote_disconnect(remote);
	return error;
}
2530 2531 2532 2533 2534 2535 2536 2537 2538 2539 2540 2541 2542 2543 2544 2545 2546 2547 2548 2549 2550 2551 2552 2553 2554 2555 2556 2557 2558

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

2559 2560
	if (git_config_iterator_glob_new(&iter, config, regexp) < 0)
		return NULL;
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 2589 2590 2591 2592 2593 2594

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