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

8 9
#include "submodule.h"

10
#include "git2/config.h"
11
#include "git2/sys/config.h"
12 13 14
#include "git2/types.h"
#include "git2/index.h"
#include "buffer.h"
15
#include "buf_text.h"
16 17
#include "vector.h"
#include "posix.h"
18
#include "config_backend.h"
19 20
#include "config.h"
#include "repository.h"
Russell Belfer committed
21 22
#include "tree.h"
#include "iterator.h"
23 24
#include "path.h"
#include "index.h"
25
#include "worktree.h"
Russell Belfer committed
26 27

#define GIT_MODULES_FILE ".gitmodules"
28

29 30 31
static git_cvar_map _sm_update_map[] = {
	{GIT_CVAR_STRING, "checkout", GIT_SUBMODULE_UPDATE_CHECKOUT},
	{GIT_CVAR_STRING, "rebase", GIT_SUBMODULE_UPDATE_REBASE},
Russell Belfer committed
32 33
	{GIT_CVAR_STRING, "merge", GIT_SUBMODULE_UPDATE_MERGE},
	{GIT_CVAR_STRING, "none", GIT_SUBMODULE_UPDATE_NONE},
34 35
	{GIT_CVAR_FALSE, NULL, GIT_SUBMODULE_UPDATE_NONE},
	{GIT_CVAR_TRUE, NULL, GIT_SUBMODULE_UPDATE_CHECKOUT},
36 37
};

38
static git_cvar_map _sm_ignore_map[] = {
Russell Belfer committed
39
	{GIT_CVAR_STRING, "none", GIT_SUBMODULE_IGNORE_NONE},
40
	{GIT_CVAR_STRING, "untracked", GIT_SUBMODULE_IGNORE_UNTRACKED},
Russell Belfer committed
41 42
	{GIT_CVAR_STRING, "dirty", GIT_SUBMODULE_IGNORE_DIRTY},
	{GIT_CVAR_STRING, "all", GIT_SUBMODULE_IGNORE_ALL},
43 44
	{GIT_CVAR_FALSE, NULL, GIT_SUBMODULE_IGNORE_NONE},
	{GIT_CVAR_TRUE, NULL, GIT_SUBMODULE_IGNORE_ALL},
45 46
};

47 48 49 50 51 52
static git_cvar_map _sm_recurse_map[] = {
	{GIT_CVAR_STRING, "on-demand", GIT_SUBMODULE_RECURSE_ONDEMAND},
	{GIT_CVAR_FALSE, NULL, GIT_SUBMODULE_RECURSE_NO},
	{GIT_CVAR_TRUE, NULL, GIT_SUBMODULE_RECURSE_YES},
};

53 54 55 56 57 58 59 60 61 62
enum {
	CACHE_OK = 0,
	CACHE_REFRESH = 1,
	CACHE_FLUSH = 2
};
enum {
	GITMODULES_EXISTING = 0,
	GITMODULES_CREATE = 1,
};

63
static kh_inline khint_t str_hash_no_trailing_slash(const char *s)
64
{
65
	khint_t h;
66

67
	for (h = 0; *s; ++s)
68
		if (s[1] != '\0' || *s != '/')
69
			h = (h << 5) - h + *s;
70

71
	return h;
72 73
}

74
static kh_inline int str_equal_no_trailing_slash(const char *a, const char *b)
75
{
76 77
	size_t alen = a ? strlen(a) : 0;
	size_t blen = b ? strlen(b) : 0;
78

79
	if (alen > 0 && a[alen - 1] == '/')
80
		alen--;
81
	if (blen > 0 && b[blen - 1] == '/')
82 83
		blen--;

84 85
	return (alen == 0 && blen == 0) ||
		(alen == blen && strncmp(a, b, alen) == 0);
86 87
}

Russell Belfer committed
88 89
__KHASH_IMPL(
	str, static kh_inline, const char *, void *, 1,
90
	str_hash_no_trailing_slash, str_equal_no_trailing_slash)
Russell Belfer committed
91

92 93
static int submodule_alloc(git_submodule **out, git_repository *repo, const char *name);
static git_config_backend *open_gitmodules(git_repository *repo, int gitmod);
94
static int gitmodules_snapshot(git_config **snap, git_repository *repo);
95 96
static int get_url_base(git_buf *url, git_repository *repo);
static int lookup_head_remote_key(git_buf *remote_key, git_repository *repo);
97
static int lookup_default_remote(git_remote **remote, git_repository *repo);
98 99
static int submodule_load_each(const git_config_entry *entry, void *payload);
static int submodule_read_config(git_submodule *sm, git_config *cfg);
100
static int submodule_load_from_wd_lite(git_submodule *);
101 102
static void submodule_get_index_status(unsigned int *, git_submodule *);
static void submodule_get_wd_status(unsigned int *, git_submodule *, git_repository *, git_submodule_ignore_t);
103 104
static void submodule_update_from_index_entry(git_submodule *sm, const git_index_entry *ie);
static void submodule_update_from_head_data(git_submodule *sm, mode_t mode, const git_oid *id);
Russell Belfer committed
105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121

static int submodule_cmp(const void *a, const void *b)
{
	return strcmp(((git_submodule *)a)->name, ((git_submodule *)b)->name);
}

static int submodule_config_key_trunc_puts(git_buf *key, const char *suffix)
{
	ssize_t idx = git_buf_rfind(key, '.');
	git_buf_truncate(key, (size_t)(idx + 1));
	return git_buf_puts(key, suffix);
}

/*
 * PUBLIC APIS
 */

122 123 124 125 126 127
static void submodule_set_lookup_error(int error, const char *name)
{
	if (!error)
		return;

	giterr_set(GITERR_SUBMODULE, (error == GIT_ENOTFOUND) ?
128 129
		"no submodule named '%s'" :
		"submodule '%s' has not been added yet", name);
130 131
}

132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151
typedef struct {
	const char *path;
	char *name;
} fbp_data;

static int find_by_path(const git_config_entry *entry, void *payload)
{
	fbp_data *data = payload;

	if (!strcmp(entry->value, data->path)) {
		const char *fdot, *ldot;
		fdot = strchr(entry->name, '.');
		ldot = strrchr(entry->name, '.');
		data->name = git__strndup(fdot + 1, ldot - fdot - 1);
		GITERR_CHECK_ALLOC(data->name);
	}

	return 0;
}

152 153 154 155
/*
 * Checks to see if the submodule shares its name with a file or directory that
 * already exists on the index. If so, the submodule cannot be added.
 */
156
static int is_path_occupied(bool *occupied, git_repository *repo, const char *path)
157 158
{
	int error = 0;
159 160
	git_index *index;
	git_buf dir = GIT_BUF_INIT;
161
	*occupied = false;
162 163

	if ((error = git_repository_index__weakptr(&index, repo)) < 0)
164
		goto out;
165

166 167 168 169 170 171
	if ((error = git_index_find(NULL, index, path)) != GIT_ENOTFOUND) {
		if (!error) {
			giterr_set(GITERR_SUBMODULE,
				"File '%s' already exists in the index", path);
			*occupied = true;
		}
172
		goto out;
173 174
	}

175 176 177 178 179
	if ((error = git_buf_sets(&dir, path)) < 0)
		goto out;

	if ((error = git_path_to_dir(&dir)) < 0)
		goto out;
180

181 182 183 184 185 186 187
	if ((error = git_index_find_prefix(NULL, index, dir.ptr)) != GIT_ENOTFOUND) {
		if (!error) {
			giterr_set(GITERR_SUBMODULE,
				"Directory '%s' already exists in the index", path);
			*occupied = true;
		}
		goto out;
188
	}
189

190
	error = 0;
191

192
out:
193
	git_buf_dispose(&dir);
194
	return error;
195 196
}

197
/**
198
 * Release the name map returned by 'load_submodule_names'.
199
 */
200 201
static void free_submodule_names(git_strmap *names)
{
202 203
	const char *key;
	char *value;
204

205 206
	if (names == NULL)
		return;
207

208 209 210
	git_strmap_foreach(names, key, value, {
		git__free((char *) key);
		git__free(value);
211 212
	});
	git_strmap_free(names);
213

214 215 216 217 218 219 220 221
	return;
}

/**
 * Map submodule paths to names.
 * TODO: for some use-cases, this might need case-folding on a
 * case-insensitive filesystem
 */
222
static int load_submodule_names(git_strmap **out, git_repository *repo, git_config *cfg)
223 224
{
	const char *key = "submodule\\..*\\.path";
225
	git_config_iterator *iter = NULL;
226
	git_config_entry *entry;
227
	git_buf buf = GIT_BUF_INIT;
228
	git_strmap *names;
229
	int rval, isvalid;
230
	int error = 0;
231

232 233 234 235 236
	*out = NULL;

	if ((error = git_strmap_alloc(&names)) < 0)
		goto out;

237
	if ((error = git_config_iterator_glob_new(&iter, cfg, key)) < 0)
238
		goto out;
239

240
	while (git_config_next(&entry, iter) == 0) {
241 242 243 244
		const char *fdot, *ldot;
		fdot = strchr(entry->name, '.');
		ldot = strrchr(entry->name, '.');

245
		if (git_strmap_exists(names, entry->value)) {
246 247 248 249 250 251
			giterr_set(GITERR_SUBMODULE,
				   "duplicated submodule path '%s'", entry->value);
			error = -1;
			goto out;
		}

252
		git_buf_clear(&buf);
253
		git_buf_put(&buf, fdot + 1, ldot - fdot - 1);
254
		isvalid = git_submodule_name_is_valid(repo, buf.ptr, 0);
255 256 257 258
		if (isvalid < 0) {
			error = isvalid;
			goto out;
		}
259
		if (!isvalid)
260 261
			continue;

262
		git_strmap_insert(names, git__strdup(entry->value), git_buf_detach(&buf), &rval);
263
		if (rval < 0) {
264
			giterr_set(GITERR_NOMEMORY, "error inserting submodule into hash table");
265 266
			error = -1;
			goto out;
267
		}
268
	}
269 270
	if (error == GIT_ITEROVER)
		error = 0;
271

272 273 274
	*out = names;
	names = NULL;

275
out:
276
	free_submodule_names(names);
277
	git_buf_dispose(&buf);
278
	git_config_iterator_free(iter);
279
	return error;
280 281
}

282
int git_submodule_lookup(
283 284 285 286 287
	git_submodule **out, /* NULL if user only wants to test existence */
	git_repository *repo,
	const char *name)    /* trailing slash is allowed */
{
	int error;
288
	unsigned int location;
289
	git_submodule *sm;
290 291 292

	assert(repo && name);

293 294 295 296 297
	if (repo->is_bare) {
		giterr_set(GITERR_SUBMODULE, "cannot get submodules without a working tree");
		return -1;
	}

298 299 300 301 302 303 304 305 306 307 308
	if (repo->submodule_cache != NULL) {
		khiter_t pos = git_strmap_lookup_index(repo->submodule_cache, name);
		if (git_strmap_valid_index(repo->submodule_cache, pos)) {
			if (out) {
				*out = git_strmap_value_at(repo->submodule_cache, pos);
				GIT_REFCOUNT_INC(*out);
			}
			return 0;
		}
	}

309 310
	if ((error = submodule_alloc(&sm, repo, name)) < 0)
		return error;
Russell Belfer committed
311

312 313
	if ((error = git_submodule_reload(sm, false)) < 0) {
		git_submodule_free(sm);
Russell Belfer committed
314
		return error;
315
	}
Russell Belfer committed
316

317 318 319 320 321
	if ((error = git_submodule_location(&location, sm)) < 0) {
		git_submodule_free(sm);
		return error;
	}

322
	/* If it's not configured or we're looking by path  */
323 324
	if (location == 0 || location == GIT_SUBMODULE_STATUS_IN_WD) {
		git_config_backend *mods;
325
		const char *pattern = "submodule\\..*\\.path";
326 327 328 329 330 331 332 333
		git_buf path = GIT_BUF_INIT;
		fbp_data data = { NULL, NULL };

		git_buf_puts(&path, name);
		while (path.ptr[path.size-1] == '/') {
			path.ptr[--path.size] = '\0';
		}
		data.path = path.ptr;
334

335 336 337
		mods = open_gitmodules(repo, GITMODULES_EXISTING);

		if (mods)
338
			error = git_config_backend_foreach_match(mods, pattern, find_by_path, &data);
339

340
		git_config_backend_free(mods);
341 342 343

		if (error < 0) {
			git_submodule_free(sm);
344
			git_buf_dispose(&path);
345
			return error;
346
		}
347 348 349 350

		if (data.name) {
			git__free(sm->name);
			sm->name = data.name;
351
			sm->path = git_buf_detach(&path);
352 353 354 355 356 357 358

			/* Try to load again with the right name */
			if ((error = git_submodule_reload(sm, false)) < 0) {
				git_submodule_free(sm);
				return error;
			}
		}
359

360
		git_buf_dispose(&path);
361 362
	}

363 364 365 366 367 368 369
	if ((error = git_submodule_location(&location, sm)) < 0) {
		git_submodule_free(sm);
		return error;
	}

	/* If we still haven't found it, do the WD check */
	if (location == 0 || location == GIT_SUBMODULE_STATUS_IN_WD) {
370 371
		git_submodule_free(sm);
		error = GIT_ENOTFOUND;
Russell Belfer committed
372

373
		/* If it's not configured, we still check if there's a repo at the path */
Russell Belfer committed
374 375
		if (git_repository_workdir(repo)) {
			git_buf path = GIT_BUF_INIT;
376
			if (git_buf_join3(&path,
377
					  '/', git_repository_workdir(repo), name, DOT_GIT) < 0)
Russell Belfer committed
378 379
				return -1;

380
			if (git_path_exists(path.ptr))
Russell Belfer committed
381 382
				error = GIT_EEXISTS;

383
			git_buf_dispose(&path);
Russell Belfer committed
384 385
		}

386
		submodule_set_lookup_error(error, name);
387
		return error;
Russell Belfer committed
388 389
	}

390 391 392 393 394 395
	if (out)
		*out = sm;
	else
		git_submodule_free(sm);

	return 0;
Russell Belfer committed
396
}
397

398
int git_submodule_name_is_valid(git_repository *repo, const char *name, int flags)
399
{
400 401 402
	git_buf buf = GIT_BUF_INIT;
	int error, isvalid;

403 404 405
	if (flags == 0)
		flags = GIT_PATH_REJECT_FILESYSTEM_DEFAULTS;

406
	/* Avoid allocating a new string if we can avoid it */
407
	if (strchr(name, '\\') != NULL) {
408 409 410 411 412 413
		if ((error = git_path_normalize_slashes(&buf, name)) < 0)
			return error;
	} else {
		git_buf_attach_notowned(&buf, name, strlen(name));
	}

414
	isvalid =  git_path_isvalid(repo, buf.ptr, 0, flags);
415
	git_buf_dispose(&buf);
416 417

	return isvalid;
418 419
}

420 421 422 423 424
static void submodule_free_dup(void *sm)
{
	git_submodule_free(sm);
}

425 426 427 428 429 430 431 432 433 434 435 436 437 438 439 440
static int submodule_get_or_create(git_submodule **out, git_repository *repo, git_strmap *map, const char *name)
{
	int error = 0;
	khiter_t pos;
	git_submodule *sm = NULL;

	pos = git_strmap_lookup_index(map, name);
	if (git_strmap_valid_index(map, pos)) {
		sm = git_strmap_value_at(map, pos);
		goto done;
	}

	/* if the submodule doesn't exist yet in the map, create it */
	if ((error = submodule_alloc(&sm, repo, name)) < 0)
		return error;

441
	pos = git_strmap_put(map, sm->name, &error);
442 443 444 445 446 447 448 449 450 451 452 453 454 455 456
	/* nobody can beat us to adding it */
	assert(error != 0);
	if (error < 0) {
		git_submodule_free(sm);
		return error;
	}

	git_strmap_set_value_at(map, pos, sm);

done:
	GIT_REFCOUNT_INC(sm);
	*out = sm;
	return 0;
}

457
static int submodules_from_index(git_strmap *map, git_index *idx, git_config *cfg)
458
{
David Turner committed
459
	int error;
460
	git_iterator *i = NULL;
David Turner committed
461
	const git_index_entry *entry;
462
	git_strmap *names;
463

464
	if ((error = load_submodule_names(&names, git_index_owner(idx), cfg)))
465
		goto done;
466

David Turner committed
467
	if ((error = git_iterator_for_index(&i, git_index_owner(idx), idx, NULL)) < 0)
468
		goto done;
469

David Turner committed
470 471 472 473 474 475 476 477 478 479 480 481
	while (!(error = git_iterator_advance(&entry, i))) {
		khiter_t pos = git_strmap_lookup_index(map, entry->path);
		git_submodule *sm;

		if (git_strmap_valid_index(map, pos)) {
			sm = git_strmap_value_at(map, pos);

			if (S_ISGITLINK(entry->mode))
				submodule_update_from_index_entry(sm, entry);
			else
				sm->flags |= GIT_SUBMODULE_STATUS__INDEX_NOT_SUBMODULE;
		} else if (S_ISGITLINK(entry->mode)) {
482 483 484 485 486 487 488 489 490
			khiter_t name_pos;
			const char *name;

			name_pos = git_strmap_lookup_index(names, entry->path);
			if (git_strmap_valid_index(names, name_pos)) {
				name = git_strmap_value_at(names, name_pos);
			} else {
				name = entry->path;
			}
491

492
			if (!submodule_get_or_create(&sm, git_index_owner(idx), map, name)) {
David Turner committed
493 494 495 496 497
				submodule_update_from_index_entry(sm, entry);
				git_submodule_free(sm);
			}
		}
	}
498

David Turner committed
499 500
	if (error == GIT_ITEROVER)
		error = 0;
501

502
done:
David Turner committed
503
	git_iterator_free(i);
504
	free_submodule_names(names);
505

David Turner committed
506
	return error;
507 508
}

509
static int submodules_from_head(git_strmap *map, git_tree *head, git_config *cfg)
510
{
David Turner committed
511
	int error;
512
	git_iterator *i = NULL;
David Turner committed
513
	const git_index_entry *entry;
514 515 516
	git_strmap *names;

	if ((error = load_submodule_names(&names, git_tree_owner(head), cfg)))
517
		goto done;
518

David Turner committed
519
	if ((error = git_iterator_for_tree(&i, head, NULL)) < 0)
520
		goto done;
521

David Turner committed
522 523 524 525 526 527 528 529 530 531 532 533
	while (!(error = git_iterator_advance(&entry, i))) {
		khiter_t pos = git_strmap_lookup_index(map, entry->path);
		git_submodule *sm;

		if (git_strmap_valid_index(map, pos)) {
			sm = git_strmap_value_at(map, pos);

			if (S_ISGITLINK(entry->mode))
				submodule_update_from_head_data(sm, entry->mode, &entry->id);
			else
				sm->flags |= GIT_SUBMODULE_STATUS__HEAD_NOT_SUBMODULE;
		} else if (S_ISGITLINK(entry->mode)) {
534 535 536 537 538 539 540 541 542
			khiter_t name_pos;
			const char *name;

			name_pos = git_strmap_lookup_index(names, entry->path);
			if (git_strmap_valid_index(names, name_pos)) {
				name = git_strmap_value_at(names, name_pos);
			} else {
				name = entry->path;
			}
543

544
			if (!submodule_get_or_create(&sm, git_tree_owner(head), map, name)) {
David Turner committed
545 546 547 548 549 550
				submodule_update_from_head_data(
					sm, entry->mode, &entry->id);
				git_submodule_free(sm);
			}
		}
	}
551

David Turner committed
552 553
	if (error == GIT_ITEROVER)
		error = 0;
554

555
done:
David Turner committed
556
	git_iterator_free(i);
557
	free_submodule_names(names);
558

David Turner committed
559
	return error;
560 561 562 563
}

/* If have_sm is true, sm is populated, otherwise map an repo are. */
typedef struct {
564
	git_config *mods;
565 566 567 568
	git_strmap *map;
	git_repository *repo;
} lfc_data;

569
int git_submodule__map(git_repository *repo, git_strmap *map)
570 571 572 573 574 575 576
{
	int error = 0;
	git_index *idx = NULL;
	git_tree *head = NULL;
	const char *wd = NULL;
	git_buf path = GIT_BUF_INIT;
	git_submodule *sm;
577
	git_config *mods = NULL;
578 579 580 581 582 583 584 585 586 587 588 589 590

	assert(repo && map);

	/* get sources that we will need to check */
	if (git_repository_index(&idx, repo) < 0)
		giterr_clear();
	if (git_repository_head_tree(&head, repo) < 0)
		giterr_clear();

	wd = git_repository_workdir(repo);
	if (wd && (error = git_buf_joinpath(&path, wd, GIT_MODULES_FILE)) < 0)
		goto cleanup;

591 592 593 594 595 596
	/* add submodule information from .gitmodules */
	if (wd) {
		lfc_data data = { 0 };
		data.map = map;
		data.repo = repo;

597 598 599
		if ((error = gitmodules_snapshot(&mods, repo)) < 0) {
			if (error == GIT_ENOTFOUND)
				error = 0;
600
			goto cleanup;
601
		}
602 603 604 605 606 607

		data.mods = mods;
		if ((error = git_config_foreach(
			    mods, submodule_load_each, &data)) < 0)
			goto cleanup;
	}
608
	/* add back submodule information from index */
609
	if (mods && idx) {
610
		if ((error = submodules_from_index(map, idx, mods)) < 0)
611 612 613
			goto cleanup;
	}
	/* add submodule information from HEAD */
614
	if (mods && head) {
615
		if ((error = submodules_from_head(map, head, mods)) < 0)
616 617 618
			goto cleanup;
	}
	/* shallow scan submodules in work tree as needed */
619
	if (wd) {
620 621 622 623 624 625
		git_strmap_foreach_value(map, sm, {
				submodule_load_from_wd_lite(sm);
			});
	}

cleanup:
626
	git_config_free(mods);
627 628 629
	/* TODO: if we got an error, mark submodule config as invalid? */
	git_index_free(idx);
	git_tree_free(head);
630
	git_buf_dispose(&path);
631 632 633
	return error;
}

Russell Belfer committed
634 635
int git_submodule_foreach(
	git_repository *repo,
636
	git_submodule_cb callback,
Russell Belfer committed
637 638
	void *payload)
{
639 640 641
	git_vector snapshot = GIT_VECTOR_INIT;
	git_strmap *submodules;
	git_submodule *sm;
Russell Belfer committed
642
	int error;
643
	size_t i;
Russell Belfer committed
644

645 646 647 648 649
	if (repo->is_bare) {
		giterr_set(GITERR_SUBMODULE, "cannot get submodules without a working tree");
		return -1;
	}

650
	if ((error = git_strmap_alloc(&submodules)) < 0)
Russell Belfer committed
651 652
		return error;

653
	if ((error = git_submodule__map(repo, submodules)) < 0)
654
		goto done;
655 656

	if (!(error = git_vector_init(
657
			&snapshot, git_strmap_num_entries(submodules), submodule_cmp))) {
658

659
		git_strmap_foreach_value(submodules, sm, {
660
			if ((error = git_vector_insert(&snapshot, sm)) < 0)
Russell Belfer committed
661
				break;
662 663 664 665 666 667 668 669 670 671
			GIT_REFCOUNT_INC(sm);
		});
	}

	if (error < 0)
		goto done;

	git_vector_uniq(&snapshot, submodule_free_dup);

	git_vector_foreach(&snapshot, i, sm) {
672
		if ((error = callback(sm, sm->name, payload)) != 0) {
673
			giterr_set_after_callback(error);
Russell Belfer committed
674
			break;
675
		}
676
	}
Russell Belfer committed
677

678 679 680 681
done:
	git_vector_foreach(&snapshot, i, sm)
		git_submodule_free(sm);
	git_vector_free(&snapshot);
Russell Belfer committed
682

683 684 685 686
	git_strmap_foreach_value(submodules, sm, {
		git_submodule_free(sm);
	});
	git_strmap_free(submodules);
Russell Belfer committed
687

688
	return error;
Russell Belfer committed
689 690
}

691 692 693 694 695 696 697 698 699 700 701 702 703 704 705 706 707 708 709 710 711 712 713 714 715 716 717
static int submodule_repo_init(
	git_repository **out,
	git_repository *parent_repo,
	const char *path,
	const char *url,
	bool use_gitlink)
{
	int error = 0;
	git_buf workdir = GIT_BUF_INIT, repodir = GIT_BUF_INIT;
	git_repository_init_options initopt = GIT_REPOSITORY_INIT_OPTIONS_INIT;
	git_repository *subrepo = NULL;

	error = git_buf_joinpath(&workdir, git_repository_workdir(parent_repo), path);
	if (error < 0)
		goto cleanup;

	initopt.flags = GIT_REPOSITORY_INIT_MKPATH | GIT_REPOSITORY_INIT_NO_REINIT;
	initopt.origin_url = url;

	/* init submodule repository and add origin remote as needed */

	/* New style: sub-repo goes in <repo-dir>/modules/<name>/ with a
	 * gitlink in the sub-repo workdir directory to that repository
	 *
	 * Old style: sub-repo goes directly into repo/<name>/.git/
	 */
	 if (use_gitlink) {
718 719 720 721
		error = git_repository_item_path(&repodir, parent_repo, GIT_REPOSITORY_ITEM_MODULES);
		if (error < 0)
			goto cleanup;
		error = git_buf_joinpath(&repodir, repodir.ptr, path);
722 723 724 725 726 727 728 729 730 731 732 733 734
		if (error < 0)
			goto cleanup;

		initopt.workdir_path = workdir.ptr;
		initopt.flags |=
			GIT_REPOSITORY_INIT_NO_DOTGIT_DIR |
			GIT_REPOSITORY_INIT_RELATIVE_GITLINK;

		error = git_repository_init_ext(&subrepo, repodir.ptr, &initopt);
	} else
		error = git_repository_init_ext(&subrepo, workdir.ptr, &initopt);

cleanup:
735 736
	git_buf_dispose(&workdir);
	git_buf_dispose(&repodir);
737 738 739 740 741 742

	*out = subrepo;

	return error;
}

Russell Belfer committed
743
int git_submodule_add_setup(
744
	git_submodule **out,
Russell Belfer committed
745 746 747 748 749 750
	git_repository *repo,
	const char *url,
	const char *path,
	int use_gitlink)
{
	int error = 0;
Ben Straub committed
751
	git_config_backend *mods = NULL;
752
	git_submodule *sm = NULL;
Russell Belfer committed
753 754
	git_buf name = GIT_BUF_INIT, real_url = GIT_BUF_INIT;
	git_repository *subrepo = NULL;
755
	bool path_occupied;
Russell Belfer committed
756 757 758 759 760

	assert(repo && url && path);

	/* see if there is already an entry for this submodule */

761
	if (git_submodule_lookup(NULL, repo, path) < 0)
Russell Belfer committed
762 763 764
		giterr_clear();
	else {
		giterr_set(GITERR_SUBMODULE,
765
			"attempt to add submodule '%s' that already exists", path);
Russell Belfer committed
766 767 768 769 770 771 772 773 774
		return GIT_EEXISTS;
	}

	/* validate and normalize path */

	if (git__prefixcmp(path, git_repository_workdir(repo)) == 0)
		path += strlen(git_repository_workdir(repo));

	if (git_path_root(path) >= 0) {
775
		giterr_set(GITERR_SUBMODULE, "submodule path must be a relative path");
Russell Belfer committed
776 777 778 779
		error = -1;
		goto cleanup;
	}

780
	if ((error = is_path_occupied(&path_occupied, repo, path)) < 0)
781 782
		goto cleanup;

783 784 785 786 787
	if (path_occupied) {
		error = GIT_EEXISTS;
		goto cleanup;
	}

Russell Belfer committed
788 789
	/* update .gitmodules */

790
	if (!(mods = open_gitmodules(repo, GITMODULES_CREATE))) {
Russell Belfer committed
791
		giterr_set(GITERR_SUBMODULE,
792
			"adding submodules to a bare repository is not supported");
Russell Belfer committed
793 794 795 796
		return -1;
	}

	if ((error = git_buf_printf(&name, "submodule.%s.path", path)) < 0 ||
797
		(error = git_config_backend_set_string(mods, name.ptr, path)) < 0)
Russell Belfer committed
798 799 800
		goto cleanup;

	if ((error = submodule_config_key_trunc_puts(&name, "url")) < 0 ||
801
		(error = git_config_backend_set_string(mods, name.ptr, url)) < 0)
Russell Belfer committed
802 803 804 805 806 807 808 809 810 811
		goto cleanup;

	git_buf_clear(&name);

	/* init submodule repository and add origin remote as needed */

	error = git_buf_joinpath(&name, git_repository_workdir(repo), path);
	if (error < 0)
		goto cleanup;

812 813
	/* if the repo does not already exist, then init a new repo and add it.
	 * Otherwise, just add the existing repo.
Russell Belfer committed
814
	 */
815 816
	if (!(git_path_exists(name.ptr) &&
		git_path_contains(&name, DOT_GIT))) {
817 818 819 820 821 822

		/* resolve the actual URL to use */
		if ((error = git_submodule_resolve_url(&real_url, repo, url)) < 0)
			goto cleanup;

		 if ((error = submodule_repo_init(&subrepo, repo, path, real_url.ptr, use_gitlink)) < 0)
Russell Belfer committed
823 824 825
			goto cleanup;
	}

826
	if ((error = git_submodule_lookup(&sm, repo, path)) < 0)
827
		goto cleanup;
Russell Belfer committed
828

829
	error = git_submodule_init(sm, false);
830

Russell Belfer committed
831
cleanup:
832 833 834 835 836 837
	if (error && sm) {
		git_submodule_free(sm);
		sm = NULL;
	}
	if (out != NULL)
		*out = sm;
Russell Belfer committed
838

839
	git_config_backend_free(mods);
Russell Belfer committed
840
	git_repository_free(subrepo);
841 842
	git_buf_dispose(&real_url);
	git_buf_dispose(&name);
Russell Belfer committed
843 844 845 846

	return error;
}

847 848 849 850 851 852 853
int git_submodule_repo_init(
	git_repository **out,
	const git_submodule *sm,
	int use_gitlink)
{
	int error;
	git_repository *sub_repo = NULL;
854 855 856
	const char *configured_url;
	git_config *cfg = NULL;
	git_buf buf = GIT_BUF_INIT;
857 858 859

	assert(out && sm);

860 861
	/* get the configured remote url of the submodule */
	if ((error = git_buf_printf(&buf, "submodule.%s.url", sm->name)) < 0 ||
862
		(error = git_repository_config_snapshot(&cfg, sm->repo)) < 0 ||
863 864 865
		(error = git_config_get_string(&configured_url, cfg, buf.ptr)) < 0 ||
		(error = submodule_repo_init(&sub_repo, sm->repo, sm->path, configured_url, use_gitlink)) < 0)
		goto done;
866 867 868

	*out = sub_repo;

869 870
done:
	git_config_free(cfg);
871
	git_buf_dispose(&buf);
872 873 874
	return error;
}

Russell Belfer committed
875 876 877 878 879 880 881
int git_submodule_add_finalize(git_submodule *sm)
{
	int error;
	git_index *index;

	assert(sm);

882
	if ((error = git_repository_index__weakptr(&index, sm->repo)) < 0 ||
883
		(error = git_index_add_bypath(index, GIT_MODULES_FILE)) < 0)
Russell Belfer committed
884 885
		return error;

886
	return git_submodule_add_to_index(sm, true);
Russell Belfer committed
887 888
}

889
int git_submodule_add_to_index(git_submodule *sm, int write_index)
Russell Belfer committed
890 891
{
	int error;
892
	git_repository *sm_repo = NULL;
Russell Belfer committed
893 894 895 896 897 898 899 900
	git_index *index;
	git_buf path = GIT_BUF_INIT;
	git_commit *head;
	git_index_entry entry;
	struct stat st;

	assert(sm);

901 902 903
	/* force reload of wd OID by git_submodule_open */
	sm->flags = sm->flags & ~GIT_SUBMODULE_STATUS__WD_OID_VALID;

904
	if ((error = git_repository_index__weakptr(&index, sm->repo)) < 0 ||
Russell Belfer committed
905
		(error = git_buf_joinpath(
906
			&path, git_repository_workdir(sm->repo), sm->path)) < 0 ||
Russell Belfer committed
907 908 909 910 911 912
		(error = git_submodule_open(&sm_repo, sm)) < 0)
		goto cleanup;

	/* read stat information for submodule working directory */
	if (p_stat(path.ptr, &st) < 0) {
		giterr_set(GITERR_SUBMODULE,
913
			"cannot add submodule without working directory");
Russell Belfer committed
914 915 916
		error = -1;
		goto cleanup;
	}
917 918

	memset(&entry, 0, sizeof(entry));
919
	entry.path = sm->path;
920 921
	git_index_entry__init_from_stat(
		&entry, &st, !(git_index_caps(index) & GIT_INDEXCAP_NO_FILEMODE));
Russell Belfer committed
922 923 924 925

	/* calling git_submodule_open will have set sm->wd_oid if possible */
	if ((sm->flags & GIT_SUBMODULE_STATUS__WD_OID_VALID) == 0) {
		giterr_set(GITERR_SUBMODULE,
926
			"cannot add submodule without HEAD to index");
Russell Belfer committed
927 928 929
		error = -1;
		goto cleanup;
	}
930
	git_oid_cpy(&entry.id, &sm->wd_oid);
Russell Belfer committed
931 932 933 934

	if ((error = git_commit_lookup(&head, sm_repo, &sm->wd_oid)) < 0)
		goto cleanup;

935
	entry.ctime.seconds = (int32_t)git_commit_time(head);
Russell Belfer committed
936
	entry.ctime.nanoseconds = 0;
937
	entry.mtime.seconds = (int32_t)git_commit_time(head);
Russell Belfer committed
938 939 940 941
	entry.mtime.nanoseconds = 0;

	git_commit_free(head);

942
	/* add it */
Edward Thomson committed
943
	error = git_index_add(index, &entry);
Russell Belfer committed
944

945 946 947 948 949 950 951 952
	/* write it, if requested */
	if (!error && write_index) {
		error = git_index_write(index);

		if (!error)
			git_oid_cpy(&sm->index_oid, &sm->wd_oid);
	}

Russell Belfer committed
953 954
cleanup:
	git_repository_free(sm_repo);
955
	git_buf_dispose(&path);
Russell Belfer committed
956 957 958
	return error;
}

959 960 961 962
const char *git_submodule_update_to_str(git_submodule_update_t update)
{
	int i;
	for (i = 0; i < (int)ARRAY_SIZE(_sm_update_map); ++i)
963
		if (_sm_update_map[i].map_value == (int)update)
964 965 966 967
			return _sm_update_map[i].str_match;
	return NULL;
}

Russell Belfer committed
968 969 970
git_repository *git_submodule_owner(git_submodule *submodule)
{
	assert(submodule);
971
	return submodule->repo;
Russell Belfer committed
972 973 974 975 976 977 978 979 980 981 982 983 984 985 986 987 988 989 990 991
}

const char *git_submodule_name(git_submodule *submodule)
{
	assert(submodule);
	return submodule->name;
}

const char *git_submodule_path(git_submodule *submodule)
{
	assert(submodule);
	return submodule->path;
}

const char *git_submodule_url(git_submodule *submodule)
{
	assert(submodule);
	return submodule->url;
}

992 993 994
int git_submodule_resolve_url(git_buf *out, git_repository *repo, const char *url)
{
	int error = 0;
995
	git_buf normalized = GIT_BUF_INIT;
996

997 998 999
	assert(out && repo && url);

	git_buf_sanitize(out);
Carlos Martín Nieto committed
1000

1001
	/* We do this in all platforms in case someone on Windows created the .gitmodules */
1002
	if (strchr(url, '\\')) {
1003
		if ((error = git_path_normalize_slashes(&normalized, url)) < 0)
1004 1005 1006 1007 1008
			return error;

		url = normalized.ptr;
	}

1009

1010
	if (git_path_is_relative(url)) {
1011
		if (!(error = get_url_base(out, repo)))
1012 1013 1014 1015
			error = git_path_apply_relative(out, url);
	} else if (strchr(url, ':') != NULL || url[0] == '/') {
		error = git_buf_sets(out, url);
	} else {
1016
		giterr_set(GITERR_SUBMODULE, "invalid format for submodule URL");
1017 1018 1019
		error = -1;
	}

1020
	git_buf_dispose(&normalized);
1021 1022 1023
	return error;
}

1024 1025 1026 1027 1028 1029 1030 1031 1032 1033 1034 1035 1036 1037
static int write_var(git_repository *repo, const char *name, const char *var, const char *val)
{
	git_buf key = GIT_BUF_INIT;
	git_config_backend *mods;
	int error;

	mods = open_gitmodules(repo, GITMODULES_CREATE);
	if (!mods)
		return -1;

	if ((error = git_buf_printf(&key, "submodule.%s.%s", name, var)) < 0)
		goto cleanup;

	if (val)
1038
		error = git_config_backend_set_string(mods, key.ptr, val);
1039
	else
1040
		error = git_config_backend_delete(mods, key.ptr);
1041

1042
	git_buf_dispose(&key);
1043 1044

cleanup:
1045
	git_config_backend_free(mods);
1046 1047 1048
	return error;
}

1049 1050 1051 1052 1053 1054 1055 1056 1057 1058 1059 1060 1061 1062 1063 1064
static int write_mapped_var(git_repository *repo, const char *name, git_cvar_map *maps, size_t nmaps, const char *var, int ival)
{
	git_cvar_t type;
	const char *val;

	if (git_config_lookup_map_enum(&type, &val, maps, nmaps, ival) < 0) {
		giterr_set(GITERR_SUBMODULE, "invalid value for %s", var);
		return -1;
	}

	if (type == GIT_CVAR_TRUE)
		val = "true";

	return write_var(repo, name, var, val);
}

1065 1066 1067 1068 1069 1070
const char *git_submodule_branch(git_submodule *submodule)
{
	assert(submodule);
	return submodule->branch;
}

1071
int git_submodule_set_branch(git_repository *repo, const char *name, const char *branch)
1072 1073
{

1074
	assert(repo && name);
1075

1076
	return write_var(repo, name, "branch", branch);
1077 1078
}

1079
int git_submodule_set_url(git_repository *repo, const char *name, const char *url)
Russell Belfer committed
1080
{
1081
	assert(repo && name && url);
Russell Belfer committed
1082

1083
	return write_var(repo, name, "url", url);
Russell Belfer committed
1084 1085
}

1086
const git_oid *git_submodule_index_id(git_submodule *submodule)
Russell Belfer committed
1087 1088 1089 1090 1091 1092 1093 1094 1095
{
	assert(submodule);

	if (submodule->flags & GIT_SUBMODULE_STATUS__INDEX_OID_VALID)
		return &submodule->index_oid;
	else
		return NULL;
}

1096
const git_oid *git_submodule_head_id(git_submodule *submodule)
Russell Belfer committed
1097 1098 1099 1100 1101 1102 1103 1104 1105
{
	assert(submodule);

	if (submodule->flags & GIT_SUBMODULE_STATUS__HEAD_OID_VALID)
		return &submodule->head_oid;
	else
		return NULL;
}

1106
const git_oid *git_submodule_wd_id(git_submodule *submodule)
Russell Belfer committed
1107 1108 1109
{
	assert(submodule);

1110
	/* load unless we think we have a valid oid */
Russell Belfer committed
1111 1112 1113 1114
	if (!(submodule->flags & GIT_SUBMODULE_STATUS__WD_OID_VALID)) {
		git_repository *subrepo;

		/* calling submodule open grabs the HEAD OID if possible */
1115
		if (!git_submodule_open_bare(&subrepo, submodule))
Russell Belfer committed
1116
			git_repository_free(subrepo);
1117 1118
		else
			giterr_clear();
Russell Belfer committed
1119 1120 1121 1122 1123 1124 1125 1126 1127 1128 1129
	}

	if (submodule->flags & GIT_SUBMODULE_STATUS__WD_OID_VALID)
		return &submodule->wd_oid;
	else
		return NULL;
}

git_submodule_ignore_t git_submodule_ignore(git_submodule *submodule)
{
	assert(submodule);
1130 1131
	return (submodule->ignore < GIT_SUBMODULE_IGNORE_NONE) ?
		GIT_SUBMODULE_IGNORE_NONE : submodule->ignore;
Russell Belfer committed
1132 1133
}

1134 1135
int git_submodule_set_ignore(git_repository *repo, const char *name, git_submodule_ignore_t ignore)
{
1136
	assert(repo && name);
1137

1138
	return write_mapped_var(repo, name, _sm_ignore_map, ARRAY_SIZE(_sm_ignore_map), "ignore", ignore);
1139 1140
}

1141
git_submodule_update_t git_submodule_update_strategy(git_submodule *submodule)
Russell Belfer committed
1142 1143
{
	assert(submodule);
1144 1145
	return (submodule->update < GIT_SUBMODULE_UPDATE_CHECKOUT) ?
		GIT_SUBMODULE_UPDATE_CHECKOUT : submodule->update;
Russell Belfer committed
1146 1147
}

1148
int git_submodule_set_update(git_repository *repo, const char *name, git_submodule_update_t update)
Russell Belfer committed
1149
{
1150
	assert(repo && name);
Russell Belfer committed
1151

1152
	return write_mapped_var(repo, name, _sm_update_map, ARRAY_SIZE(_sm_update_map), "update", update);
Russell Belfer committed
1153 1154
}

1155
git_submodule_recurse_t git_submodule_fetch_recurse_submodules(
1156 1157 1158 1159 1160 1161
	git_submodule *submodule)
{
	assert(submodule);
	return submodule->fetch_recurse;
}

1162
int git_submodule_set_fetch_recurse_submodules(git_repository *repo, const char *name, git_submodule_recurse_t recurse)
1163
{
1164 1165
	assert(repo && name);

1166
	return write_mapped_var(repo, name, _sm_recurse_map, ARRAY_SIZE(_sm_recurse_map), "fetchRecurseSubmodules", recurse);
1167 1168
}

1169 1170 1171 1172 1173 1174 1175 1176 1177 1178 1179 1180 1181 1182 1183 1184 1185 1186 1187 1188 1189 1190 1191 1192 1193
static int submodule_repo_create(
	git_repository **out,
	git_repository *parent_repo,
	const char *path)
{
	int error = 0;
	git_buf workdir = GIT_BUF_INIT, repodir = GIT_BUF_INIT;
	git_repository_init_options initopt = GIT_REPOSITORY_INIT_OPTIONS_INIT;
	git_repository *subrepo = NULL;

	initopt.flags =
		GIT_REPOSITORY_INIT_MKPATH |
		GIT_REPOSITORY_INIT_NO_REINIT |
		GIT_REPOSITORY_INIT_NO_DOTGIT_DIR |
		GIT_REPOSITORY_INIT_RELATIVE_GITLINK;

	/* Workdir: path to sub-repo working directory */
	error = git_buf_joinpath(&workdir, git_repository_workdir(parent_repo), path);
	if (error < 0)
		goto cleanup;

	initopt.workdir_path = workdir.ptr;

	/**
	 * Repodir: path to the sub-repo. sub-repo goes in:
1194
	 * <repo-dir>/modules/<name>/ with a gitlink in the
1195 1196
	 * sub-repo workdir directory to that repository.
	 */
1197 1198 1199 1200
	error = git_repository_item_path(&repodir, parent_repo, GIT_REPOSITORY_ITEM_MODULES);
	if (error < 0)
		goto cleanup;
	error = git_buf_joinpath(&repodir, repodir.ptr, path);
1201 1202 1203 1204 1205 1206
	if (error < 0)
		goto cleanup;

	error = git_repository_init_ext(&subrepo, repodir.ptr, &initopt);

cleanup:
1207 1208
	git_buf_dispose(&workdir);
	git_buf_dispose(&repodir);
1209 1210 1211 1212 1213 1214 1215 1216 1217 1218 1219 1220 1221 1222 1223 1224

	*out = subrepo;

	return error;
}

/**
 * Callback to override sub-repository creation when
 * cloning a sub-repository.
 */
static int git_submodule_update_repo_init_cb(
	git_repository **out,
	const char *path,
	int bare,
	void *payload)
{
1225 1226
	git_submodule *sm;

1227
	GIT_UNUSED(bare);
1228 1229

	sm = payload;
1230 1231 1232 1233

	return submodule_repo_create(out, sm->repo, path);
}

1234 1235 1236 1237 1238 1239 1240
int git_submodule_update_init_options(git_submodule_update_options *opts, unsigned int version)
{
	GIT_INIT_STRUCTURE_FROM_TEMPLATE(
		opts, version, git_submodule_update_options, GIT_SUBMODULE_UPDATE_OPTIONS_INIT);
	return 0;
}

1241 1242 1243 1244 1245 1246 1247 1248 1249 1250 1251 1252 1253 1254 1255 1256 1257 1258 1259 1260 1261
int git_submodule_update(git_submodule *sm, int init, git_submodule_update_options *_update_options)
{
	int error;
	unsigned int submodule_status;
	git_config *config = NULL;
	const char *submodule_url;
	git_repository *sub_repo = NULL;
	git_remote *remote = NULL;
	git_object *target_commit = NULL;
	git_buf buf = GIT_BUF_INIT;
	git_submodule_update_options update_options = GIT_SUBMODULE_UPDATE_OPTIONS_INIT;
	git_clone_options clone_options = GIT_CLONE_OPTIONS_INIT;

	assert(sm);

	if (_update_options)
		memcpy(&update_options, _update_options, sizeof(git_submodule_update_options));

	GITERR_CHECK_VERSION(&update_options, GIT_SUBMODULE_UPDATE_OPTIONS_VERSION, "git_submodule_update_options");

	/* Copy over the remote callbacks */
1262
	memcpy(&clone_options.fetch_opts, &update_options.fetch_opts, sizeof(git_fetch_options));
1263 1264

	/* Get the status of the submodule to determine if it is already initialized  */
1265
	if ((error = git_submodule_status(&submodule_status, sm->repo, sm->name, GIT_SUBMODULE_IGNORE_UNSPECIFIED)) < 0)
1266 1267 1268 1269 1270 1271 1272 1273 1274 1275 1276 1277 1278 1279 1280 1281 1282 1283 1284 1285 1286 1287 1288
		goto done;

	/*
	 * If submodule work dir is not already initialized, check to see
	 * what we need to do (initialize, clone, return error...)
	 */
	if (submodule_status & GIT_SUBMODULE_STATUS_WD_UNINITIALIZED) {
		/*
		 * Work dir is not initialized, check to see if the submodule
		 * info has been copied into .git/config
		 */
		if ((error = git_repository_config_snapshot(&config, sm->repo)) < 0 ||
			(error = git_buf_printf(&buf, "submodule.%s.url", git_submodule_name(sm))) < 0)
			goto done;

		if ((error = git_config_get_string(&submodule_url, config, git_buf_cstr(&buf))) < 0) {
			/*
			 * If the error is not "not found" or if it is "not found" and we are not
			 * initializing the submodule, then return error.
			 */
			if (error != GIT_ENOTFOUND)
				goto done;

1289
			if (!init) {
1290
				giterr_set(GITERR_SUBMODULE, "submodule is not initialized");
1291 1292 1293 1294 1295 1296 1297 1298 1299 1300 1301 1302 1303 1304 1305 1306 1307 1308 1309 1310 1311 1312
				error = GIT_ERROR;
				goto done;
			}

			/* The submodule has not been initialized yet - initialize it now.*/
			if ((error = git_submodule_init(sm, 0)) < 0)
				goto done;

			git_config_free(config);
			config = NULL;

			if ((error = git_repository_config_snapshot(&config, sm->repo)) < 0 ||
				(error = git_config_get_string(&submodule_url, config, git_buf_cstr(&buf))) < 0)
				goto done;
		}

		/** submodule is initialized - now clone it **/
		/* override repo creation */
		clone_options.repository_cb = git_submodule_update_repo_init_cb;
		clone_options.repository_cb_payload = sm;

		/*
1313
		 * Do not perform checkout as part of clone, instead we
1314 1315 1316 1317 1318
		 * will checkout the specific commit manually.
		 */
		clone_options.checkout_opts.checkout_strategy = GIT_CHECKOUT_NONE;

		if ((error = git_clone(&sub_repo, submodule_url, sm->path, &clone_options)) < 0 ||
1319
			(error = git_repository_set_head_detached(sub_repo, git_submodule_index_id(sm))) < 0 ||
1320 1321 1322
			(error = git_checkout_head(sub_repo, &update_options.checkout_opts)) != 0)
			goto done;
	} else {
1323 1324
		const git_oid *oid;

1325 1326 1327 1328 1329
		/**
		 * Work dir is initialized - look up the commit in the parent repository's index,
		 * update the workdir contents of the subrepository, and set the subrepository's
		 * head to the new commit.
		 */
1330 1331 1332
		if ((error = git_submodule_open(&sub_repo, sm)) < 0)
			goto done;

1333 1334 1335 1336 1337 1338
		if ((oid = git_submodule_index_id(sm)) == NULL) {
			giterr_set(GITERR_SUBMODULE, "could not get ID of submodule in index");
			error = -1;
			goto done;
		}

1339
		/* Look up the target commit in the submodule. */
1340
		if ((error = git_object_lookup(&target_commit, sub_repo, oid, GIT_OBJ_COMMIT)) < 0) {
1341 1342 1343 1344 1345 1346 1347 1348 1349
			/* If it isn't found then fetch and try again. */
			if (error != GIT_ENOTFOUND || !update_options.allow_fetch ||
				(error = lookup_default_remote(&remote, sub_repo)) < 0 ||
				(error = git_remote_fetch(remote, NULL, &update_options.fetch_opts, NULL)) < 0 ||
				(error = git_object_lookup(&target_commit, sub_repo, git_submodule_index_id(sm), GIT_OBJ_COMMIT)) < 0)
				goto done;
		}

		if ((error = git_checkout_tree(sub_repo, target_commit, &update_options.checkout_opts)) != 0 ||
1350
			(error = git_repository_set_head_detached(sub_repo, git_submodule_index_id(sm))) < 0)
1351 1352 1353 1354 1355 1356 1357 1358 1359 1360
			goto done;

		/* Invalidate the wd flags as the workdir has been updated. */
		sm->flags = sm->flags &
			~(GIT_SUBMODULE_STATUS_IN_WD |
		  	GIT_SUBMODULE_STATUS__WD_OID_VALID |
		  	GIT_SUBMODULE_STATUS__WD_SCANNED);
	}

done:
1361
	git_buf_dispose(&buf);
1362 1363 1364 1365 1366 1367 1368 1369
	git_config_free(config);
	git_object_free(target_commit);
	git_remote_free(remote);
	git_repository_free(sub_repo);

	return error;
}

1370
int git_submodule_init(git_submodule *sm, int overwrite)
Russell Belfer committed
1371 1372
{
	int error;
1373
	const char *val;
1374
	git_buf key = GIT_BUF_INIT, effective_submodule_url = GIT_BUF_INIT;
1375
	git_config *cfg = NULL;
Russell Belfer committed
1376

1377
	if (!sm->url) {
Russell Belfer committed
1378
		giterr_set(GITERR_SUBMODULE,
1379
			"no URL configured for submodule '%s'", sm->name);
Russell Belfer committed
1380 1381 1382
		return -1;
	}

1383
	if ((error = git_repository_config(&cfg, sm->repo)) < 0)
Russell Belfer committed
1384 1385
		return error;

1386 1387
	/* write "submodule.NAME.url" */

1388
	if ((error = git_submodule_resolve_url(&effective_submodule_url, sm->repo, sm->url)) < 0 ||
1389
		(error = git_buf_printf(&key, "submodule.%s.url", sm->name)) < 0 ||
1390
		(error = git_config__update_entry(
1391
			cfg, key.ptr, effective_submodule_url.ptr, overwrite != 0, false)) < 0)
1392 1393
		goto cleanup;

Russell Belfer committed
1394 1395
	/* write "submodule.NAME.update" if not default */

1396 1397 1398 1399 1400 1401 1402 1403 1404 1405 1406 1407
	val = (sm->update == GIT_SUBMODULE_UPDATE_CHECKOUT) ?
		NULL : git_submodule_update_to_str(sm->update);

	if ((error = git_buf_printf(&key, "submodule.%s.update", sm->name)) < 0 ||
		(error = git_config__update_entry(
			cfg, key.ptr, val, overwrite != 0, false)) < 0)
		goto cleanup;

	/* success */

cleanup:
	git_config_free(cfg);
1408 1409
	git_buf_dispose(&key);
	git_buf_dispose(&effective_submodule_url);
Russell Belfer committed
1410 1411 1412 1413

	return error;
}

1414
int git_submodule_sync(git_submodule *sm)
Russell Belfer committed
1415
{
1416 1417 1418
	int error = 0;
	git_config *cfg = NULL;
	git_buf key = GIT_BUF_INIT;
1419
	git_repository *smrepo = NULL;
1420 1421

	if (!sm->url) {
Russell Belfer committed
1422
		giterr_set(GITERR_SUBMODULE,
1423
			"no URL configured for submodule '%s'", sm->name);
Russell Belfer committed
1424 1425 1426 1427 1428
		return -1;
	}

	/* copy URL over to config only if it already exists */

1429 1430 1431 1432 1433 1434
	if (!(error = git_repository_config__weakptr(&cfg, sm->repo)) &&
		!(error = git_buf_printf(&key, "submodule.%s.url", sm->name)))
		error = git_config__update_entry(cfg, key.ptr, sm->url, true, true);

	/* if submodule exists in the working directory, update remote url */

1435 1436 1437 1438
	if (!error &&
		(sm->flags & GIT_SUBMODULE_STATUS_IN_WD) != 0 &&
		!(error = git_submodule_open(&smrepo, sm)))
	{
1439 1440 1441 1442 1443
		git_buf remote_name = GIT_BUF_INIT;

		if ((error = git_repository_config__weakptr(&cfg, smrepo)) < 0)
			/* return error from reading submodule config */;
		else if ((error = lookup_head_remote_key(&remote_name, smrepo)) < 0) {
1444
			giterr_clear();
1445
			error = git_buf_sets(&key, "remote.origin.url");
1446 1447
		} else {
			error = git_buf_join3(
1448
				&key, '.', "remote", remote_name.ptr, "url");
1449
			git_buf_dispose(&remote_name);
1450 1451
		}

1452 1453
		if (!error)
			error = git_config__update_entry(cfg, key.ptr, sm->url, true, false);
1454 1455 1456 1457

		git_repository_free(smrepo);
	}

1458
	git_buf_dispose(&key);
1459 1460

	return error;
Russell Belfer committed
1461 1462
}

1463 1464
static int git_submodule__open(
	git_repository **subrepo, git_submodule *sm, bool bare)
Russell Belfer committed
1465 1466 1467
{
	int error;
	git_buf path = GIT_BUF_INIT;
1468 1469
	unsigned int flags = GIT_REPOSITORY_OPEN_NO_SEARCH;
	const char *wd;
Russell Belfer committed
1470

1471
	assert(sm && subrepo);
Russell Belfer committed
1472

1473 1474 1475
	if (git_repository__ensure_not_bare(
			sm->repo, "open submodule repository") < 0)
		return GIT_EBAREREPO;
Russell Belfer committed
1476

1477
	wd = git_repository_workdir(sm->repo);
Russell Belfer committed
1478

1479 1480
	if (git_buf_joinpath(&path, wd, sm->path) < 0 ||
		git_buf_joinpath(&path, path.ptr, DOT_GIT) < 0)
Russell Belfer committed
1481 1482
		return -1;

1483 1484 1485 1486
	sm->flags = sm->flags &
		~(GIT_SUBMODULE_STATUS_IN_WD |
		  GIT_SUBMODULE_STATUS__WD_OID_VALID |
		  GIT_SUBMODULE_STATUS__WD_SCANNED);
Russell Belfer committed
1487

1488 1489
	if (bare)
		flags |= GIT_REPOSITORY_OPEN_BARE;
Russell Belfer committed
1490

1491
	error = git_repository_open_ext(subrepo, path.ptr, flags, wd);
1492

1493 1494 1495 1496
	/* if we opened the submodule successfully, grab HEAD OID, etc. */
	if (!error) {
		sm->flags |= GIT_SUBMODULE_STATUS_IN_WD |
			GIT_SUBMODULE_STATUS__WD_SCANNED;
1497

1498 1499 1500 1501 1502 1503 1504 1505 1506
		if (!git_reference_name_to_id(&sm->wd_oid, *subrepo, GIT_HEAD_FILE))
			sm->flags |= GIT_SUBMODULE_STATUS__WD_OID_VALID;
		else
			giterr_clear();
	} else if (git_path_exists(path.ptr)) {
		sm->flags |= GIT_SUBMODULE_STATUS__WD_SCANNED |
			GIT_SUBMODULE_STATUS_IN_WD;
	} else {
		git_buf_rtruncate_at_char(&path, '/'); /* remove "/.git" */
1507

1508 1509 1510
		if (git_path_isdir(path.ptr))
			sm->flags |= GIT_SUBMODULE_STATUS__WD_SCANNED;
	}
1511

1512
	git_buf_dispose(&path);
1513

1514 1515
	return error;
}
1516

1517 1518 1519 1520
int git_submodule_open_bare(git_repository **subrepo, git_submodule *sm)
{
	return git_submodule__open(subrepo, sm, true);
}
Russell Belfer committed
1521

1522 1523 1524
int git_submodule_open(git_repository **subrepo, git_submodule *sm)
{
	return git_submodule__open(subrepo, sm, false);
Russell Belfer committed
1525 1526
}

1527 1528
static void submodule_update_from_index_entry(
	git_submodule *sm, const git_index_entry *ie)
Russell Belfer committed
1529
{
1530
	bool already_found = (sm->flags & GIT_SUBMODULE_STATUS_IN_INDEX) != 0;
Russell Belfer committed
1531

1532 1533 1534 1535 1536 1537 1538
	if (!S_ISGITLINK(ie->mode)) {
		if (!already_found)
			sm->flags |= GIT_SUBMODULE_STATUS__INDEX_NOT_SUBMODULE;
	} else {
		if (already_found)
			sm->flags |= GIT_SUBMODULE_STATUS__INDEX_MULTIPLE_ENTRIES;
		else
1539
			git_oid_cpy(&sm->index_oid, &ie->id);
Russell Belfer committed
1540

1541 1542 1543 1544 1545 1546 1547 1548 1549
		sm->flags |= GIT_SUBMODULE_STATUS_IN_INDEX |
			GIT_SUBMODULE_STATUS__INDEX_OID_VALID;
	}
}

static int submodule_update_index(git_submodule *sm)
{
	git_index *index;
	const git_index_entry *ie;
Russell Belfer committed
1550

1551
	if (git_repository_index__weakptr(&index, sm->repo) < 0)
Russell Belfer committed
1552 1553
		return -1;

1554
	sm->flags = sm->flags &
1555 1556 1557
		~(GIT_SUBMODULE_STATUS_IN_INDEX |
		  GIT_SUBMODULE_STATUS__INDEX_OID_VALID);

1558 1559
	if (!(ie = git_index_get_bypath(index, sm->path, 0)))
		return 0;
Russell Belfer committed
1560

1561 1562 1563 1564 1565 1566 1567 1568 1569 1570 1571 1572 1573 1574 1575
	submodule_update_from_index_entry(sm, ie);

	return 0;
}

static void submodule_update_from_head_data(
	git_submodule *sm, mode_t mode, const git_oid *id)
{
	if (!S_ISGITLINK(mode))
		sm->flags |= GIT_SUBMODULE_STATUS__HEAD_NOT_SUBMODULE;
	else {
		git_oid_cpy(&sm->head_oid, id);

		sm->flags |= GIT_SUBMODULE_STATUS_IN_HEAD |
			GIT_SUBMODULE_STATUS__HEAD_OID_VALID;
Russell Belfer committed
1576
	}
1577
}
Russell Belfer committed
1578

1579 1580 1581
static int submodule_update_head(git_submodule *submodule)
{
	git_tree *head = NULL;
nulltoken committed
1582
	git_tree_entry *te = NULL;
Russell Belfer committed
1583

1584 1585 1586
	submodule->flags = submodule->flags &
		~(GIT_SUBMODULE_STATUS_IN_HEAD |
		  GIT_SUBMODULE_STATUS__HEAD_OID_VALID);
Russell Belfer committed
1587

1588 1589 1590 1591 1592
	/* if we can't look up file in current head, then done */
	if (git_repository_head_tree(&head, submodule->repo) < 0 ||
		git_tree_entry_bypath(&te, head, submodule->path) < 0)
		giterr_clear();
	else
1593
		submodule_update_from_head_data(submodule, te->attr, git_tree_entry_id(te));
Russell Belfer committed
1594

nulltoken committed
1595
	git_tree_entry_free(te);
1596 1597 1598
	git_tree_free(head);
	return 0;
}
1599

1600
int git_submodule_reload(git_submodule *sm, int force)
1601
{
1602
	int error = 0, isvalid;
1603
	git_config *mods;
Russell Belfer committed
1604

1605 1606
	GIT_UNUSED(force);

1607 1608
	assert(sm);

1609 1610
	isvalid = git_submodule_name_is_valid(sm->repo, sm->name, 0);
	if (isvalid <= 0) {
1611
		/* This should come with a warning, but we've no API for that */
1612
		return isvalid;
1613 1614
	}

1615 1616
	if (!git_repository_is_bare(sm->repo)) {
		/* refresh config data */
1617 1618
		if ((error = gitmodules_snapshot(&mods, sm->repo)) < 0 && error != GIT_ENOTFOUND)
			return error;
1619 1620 1621
		if (mods != NULL) {
			error = submodule_read_config(sm, mods);
			git_config_free(mods);
Russell Belfer committed
1622

1623 1624 1625
			if (error < 0)
				return error;
		}
1626

1627 1628 1629 1630 1631
		/* refresh wd data */
		sm->flags &=
			~(GIT_SUBMODULE_STATUS_IN_WD |
			  GIT_SUBMODULE_STATUS__WD_OID_VALID |
			  GIT_SUBMODULE_STATUS__WD_FLAGS);
Russell Belfer committed
1632

1633
		error = submodule_load_from_wd_lite(sm);
1634
	}
1635

1636 1637
	if (error == 0 && (error = submodule_update_index(sm)) == 0)
		error = submodule_update_head(sm);
1638

1639
	return error;
Russell Belfer committed
1640 1641
}

1642 1643
static void submodule_copy_oid_maybe(
	git_oid *tgt, const git_oid *src, bool valid)
Russell Belfer committed
1644
{
1645 1646 1647 1648 1649 1650 1651
	if (tgt) {
		if (valid)
			memcpy(tgt, src, sizeof(*tgt));
		else
			memset(tgt, 0, sizeof(*tgt));
	}
}
1652

1653 1654 1655 1656 1657 1658 1659 1660 1661 1662
int git_submodule__status(
	unsigned int *out_status,
	git_oid *out_head_id,
	git_oid *out_index_id,
	git_oid *out_wd_id,
	git_submodule *sm,
	git_submodule_ignore_t ign)
{
	unsigned int status;
	git_repository *smrepo = NULL;
Russell Belfer committed
1663

1664
	if (ign == GIT_SUBMODULE_IGNORE_UNSPECIFIED)
1665
		ign = sm->ignore;
1666

1667 1668 1669 1670
	/* only return location info if ignore == all */
	if (ign == GIT_SUBMODULE_IGNORE_ALL) {
		*out_status = (sm->flags & GIT_SUBMODULE_STATUS__IN_FLAGS);
		return 0;
1671
	}
Russell Belfer committed
1672

1673 1674 1675 1676 1677 1678
	/* If the user has requested caching submodule state, performing these
	 * expensive operations (especially `submodule_update_head`, which is
	 * bottlenecked on `git_repository_head_tree`) eliminates much of the
	 * advantage.  We will, therefore, interpret the request for caching to
	 * apply here to and skip them.
	 */
1679

1680 1681 1682 1683 1684 1685 1686 1687 1688
	if (sm->repo->submodule_cache == NULL) {
		/* refresh the index OID */
		if (submodule_update_index(sm) < 0)
			return -1;

		/* refresh the HEAD OID */
		if (submodule_update_head(sm) < 0)
			return -1;
	}
Russell Belfer committed
1689

1690 1691 1692 1693 1694 1695 1696 1697 1698 1699 1700 1701 1702 1703 1704 1705 1706 1707 1708 1709 1710 1711 1712 1713 1714 1715 1716 1717 1718 1719
	/* for ignore == dirty, don't scan the working directory */
	if (ign == GIT_SUBMODULE_IGNORE_DIRTY) {
		/* git_submodule_open_bare will load WD OID data */
		if (git_submodule_open_bare(&smrepo, sm) < 0)
			giterr_clear();
		else
			git_repository_free(smrepo);
		smrepo = NULL;
	} else if (git_submodule_open(&smrepo, sm) < 0) {
		giterr_clear();
		smrepo = NULL;
	}

	status = GIT_SUBMODULE_STATUS__CLEAR_INTERNAL(sm->flags);

	submodule_get_index_status(&status, sm);
	submodule_get_wd_status(&status, sm, smrepo, ign);

	git_repository_free(smrepo);

	*out_status = status;

	submodule_copy_oid_maybe(out_head_id, &sm->head_oid,
		(sm->flags & GIT_SUBMODULE_STATUS__HEAD_OID_VALID) != 0);
	submodule_copy_oid_maybe(out_index_id, &sm->index_oid,
		(sm->flags & GIT_SUBMODULE_STATUS__INDEX_OID_VALID) != 0);
	submodule_copy_oid_maybe(out_wd_id, &sm->wd_oid,
		(sm->flags & GIT_SUBMODULE_STATUS__WD_OID_VALID) != 0);

	return 0;
Russell Belfer committed
1720 1721
}

1722
int git_submodule_status(unsigned int *status, git_repository *repo, const char *name, git_submodule_ignore_t ignore)
1723
{
1724 1725 1726 1727 1728 1729 1730 1731
	git_submodule *sm;
	int error;

	assert(status && repo && name);

	if ((error = git_submodule_lookup(&sm, repo, name)) < 0)
		return error;

1732
	error = git_submodule__status(status, NULL, NULL, NULL, sm, ignore);
1733
	git_submodule_free(sm);
1734

1735
	return error;
1736
}
1737

1738 1739 1740 1741 1742 1743
int git_submodule_location(unsigned int *location, git_submodule *sm)
{
	assert(location && sm);

	return git_submodule__status(
		location, NULL, NULL, NULL, sm, GIT_SUBMODULE_IGNORE_ALL);
1744 1745
}

Russell Belfer committed
1746 1747 1748 1749
/*
 * INTERNAL FUNCTIONS
 */

1750
static int submodule_alloc(
1751
	git_submodule **out, git_repository *repo, const char *name)
1752
{
1753
	size_t namelen;
1754
	git_submodule *sm;
1755

1756
	if (!name || !(namelen = strlen(name))) {
1757
		giterr_set(GITERR_SUBMODULE, "invalid submodule name");
1758
		return -1;
1759 1760
	}

1761
	sm = git__calloc(1, sizeof(git_submodule));
1762
	GITERR_CHECK_ALLOC(sm);
1763

1764 1765 1766
	sm->name = sm->path = git__strdup(name);
	if (!sm->name) {
		git__free(sm);
1767
		return -1;
1768
	}
Russell Belfer committed
1769

1770
	GIT_REFCOUNT_INC(sm);
1771 1772
	sm->ignore = sm->ignore_default = GIT_SUBMODULE_IGNORE_NONE;
	sm->update = sm->update_default = GIT_SUBMODULE_UPDATE_CHECKOUT;
1773
	sm->fetch_recurse = sm->fetch_recurse_default = GIT_SUBMODULE_RECURSE_NO;
1774
	sm->repo   = repo;
1775
	sm->branch = NULL;
1776

1777 1778
	*out = sm;
	return 0;
Russell Belfer committed
1779 1780
}

1781
static void submodule_release(git_submodule *sm)
Russell Belfer committed
1782 1783 1784 1785
{
	if (!sm)
		return;

1786
	if (sm->repo) {
1787
		sm->repo = NULL;
1788 1789
	}

1790 1791 1792 1793
	if (sm->path != sm->name)
		git__free(sm->path);
	git__free(sm->name);
	git__free(sm->url);
1794
	git__free(sm->branch);
1795 1796 1797
	git__memzero(sm, sizeof(*sm));
	git__free(sm);
}
Russell Belfer committed
1798

1799 1800 1801 1802 1803
void git_submodule_free(git_submodule *sm)
{
	if (!sm)
		return;
	GIT_REFCOUNT_DEC(sm, submodule_release);
Russell Belfer committed
1804 1805
}

1806 1807 1808
static int submodule_config_error(const char *property, const char *value)
{
	giterr_set(GITERR_INVALID,
1809
		"invalid value for submodule '%s' property: '%s'", property, value);
1810
	return -1;
1811 1812
}

1813 1814 1815 1816 1817 1818 1819 1820 1821 1822 1823 1824 1825 1826 1827 1828 1829 1830 1831 1832 1833 1834 1835 1836 1837 1838 1839 1840
int git_submodule_parse_ignore(git_submodule_ignore_t *out, const char *value)
{
	int val;

	if (git_config_lookup_map_value(
			&val, _sm_ignore_map, ARRAY_SIZE(_sm_ignore_map), value) < 0) {
		*out = GIT_SUBMODULE_IGNORE_NONE;
		return submodule_config_error("ignore", value);
	}

	*out = (git_submodule_ignore_t)val;
	return 0;
}

int git_submodule_parse_update(git_submodule_update_t *out, const char *value)
{
	int val;

	if (git_config_lookup_map_value(
			&val, _sm_update_map, ARRAY_SIZE(_sm_update_map), value) < 0) {
		*out = GIT_SUBMODULE_UPDATE_CHECKOUT;
		return submodule_config_error("update", value);
	}

	*out = (git_submodule_update_t)val;
	return 0;
}

1841 1842 1843 1844 1845 1846 1847 1848 1849 1850 1851 1852 1853 1854
int git_submodule_parse_recurse(git_submodule_recurse_t *out, const char *value)
{
	int val;

	if (git_config_lookup_map_value(
			&val, _sm_recurse_map, ARRAY_SIZE(_sm_recurse_map), value) < 0) {
		*out = GIT_SUBMODULE_RECURSE_YES;
		return submodule_config_error("recurse", value);
	}

	*out = (git_submodule_recurse_t)val;
	return 0;
}

1855
static int get_value(const char **out, git_config *cfg, git_buf *buf, const char *name, const char *field)
1856
{
1857
	int error;
1858

1859
	git_buf_clear(buf);
1860

1861 1862 1863
	if ((error = git_buf_printf(buf, "submodule.%s.%s", name, field)) < 0 ||
	    (error = git_config_get_string(out, cfg, buf->ptr)) < 0)
		return error;
1864

1865 1866
	return error;
}
1867

1868 1869 1870 1871 1872 1873 1874 1875
static bool looks_like_command_line_option(const char *s)
{
	if (s && s[0] == '-')
		return true;

	return false;
}

1876 1877 1878 1879 1880
static int submodule_read_config(git_submodule *sm, git_config *cfg)
{
	git_buf key = GIT_BUF_INIT;
	const char *value;
	int error, in_config = 0;
Russell Belfer committed
1881

1882 1883 1884
	/*
	 * TODO: Look up path in index and if it is present but not a GITLINK
	 * then this should be deleted (at least to match git's behavior)
1885
	 */
1886

1887 1888
	if ((error = get_value(&value, cfg, &key, sm->name, "path")) == 0) {
		in_config = 1;
1889 1890
		/* We would warn here if we had that API */
		if (!looks_like_command_line_option(value)) {
1891 1892
	/*
	 * TODO: if case insensitive filesystem, then the following strcmp
1893 1894
	 * should be strcasecmp
	 */
1895 1896 1897 1898 1899 1900 1901
			if (strcmp(sm->name, value) != 0) {
				if (sm->path != sm->name)
					git__free(sm->path);
				sm->path = git__strdup(value);
				GITERR_CHECK_ALLOC(sm->path);
			}

1902
		}
1903
	} else if (error != GIT_ENOTFOUND) {
1904
		goto cleanup;
1905
	}
1906

1907
	if ((error = get_value(&value, cfg, &key, sm->name, "url")) == 0) {
1908 1909 1910 1911 1912 1913
		/* We would warn here if we had that API */
		if (!looks_like_command_line_option(value)) {
			in_config = 1;
			sm->url = git__strdup(value);
			GITERR_CHECK_ALLOC(sm->url);
		}
1914
	} else if (error != GIT_ENOTFOUND) {
1915
		goto cleanup;
1916 1917
	}

1918 1919 1920 1921 1922
	if ((error = get_value(&value, cfg, &key, sm->name, "branch")) == 0) {
		in_config = 1;
		sm->branch = git__strdup(value);
		GITERR_CHECK_ALLOC(sm->branch);
	} else if (error != GIT_ENOTFOUND) {
1923
		goto cleanup;
1924
	}
1925

1926 1927
	if ((error = get_value(&value, cfg, &key, sm->name, "update")) == 0) {
		in_config = 1;
1928
		if ((error = git_submodule_parse_update(&sm->update, value)) < 0)
1929
			goto cleanup;
1930
		sm->update_default = sm->update;
1931
	} else if (error != GIT_ENOTFOUND) {
1932
		goto cleanup;
1933
	}
1934 1935 1936

	if ((error = get_value(&value, cfg, &key, sm->name, "fetchRecurseSubmodules")) == 0) {
		in_config = 1;
1937
		if ((error = git_submodule_parse_recurse(&sm->fetch_recurse, value)) < 0)
1938
			goto cleanup;
1939
		sm->fetch_recurse_default = sm->fetch_recurse;
1940
	} else if (error != GIT_ENOTFOUND) {
1941
		goto cleanup;
1942
	}
1943 1944 1945

	if ((error = get_value(&value, cfg, &key, sm->name, "ignore")) == 0) {
		in_config = 1;
1946
		if ((error = git_submodule_parse_ignore(&sm->ignore, value)) < 0)
1947
			goto cleanup;
1948
		sm->ignore_default = sm->ignore;
1949
	} else if (error != GIT_ENOTFOUND) {
1950
		goto cleanup;
1951
	}
1952 1953 1954 1955

	if (in_config)
		sm->flags |= GIT_SUBMODULE_STATUS_IN_CONFIG;

1956 1957 1958
	error = 0;

cleanup:
1959
	git_buf_dispose(&key);
1960
	return error;
1961 1962 1963 1964 1965 1966 1967 1968 1969 1970
}

static int submodule_load_each(const git_config_entry *entry, void *payload)
{
	lfc_data *data = payload;
	const char *namestart, *property;
	git_strmap_iter pos;
	git_strmap *map = data->map;
	git_buf name = GIT_BUF_INIT;
	git_submodule *sm;
1971
	int error, isvalid;
1972 1973 1974 1975 1976 1977 1978 1979 1980 1981 1982 1983 1984 1985 1986

	if (git__prefixcmp(entry->name, "submodule.") != 0)
		return 0;

	namestart = entry->name + strlen("submodule.");
	property  = strrchr(namestart, '.');

	if (!property || (property == namestart))
		return 0;

	property++;

	if ((error = git_buf_set(&name, namestart, property - namestart -1)) < 0)
		return error;

1987 1988 1989
	isvalid = git_submodule_name_is_valid(data->repo, name.ptr, 0);
	if (isvalid <= 0) {
		error = isvalid;
1990 1991 1992
		goto done;
	}

1993 1994 1995 1996 1997 1998 1999
	/*
	 * Now that we have the submodule's name, we can use that to
	 * figure out whether it's in the map. If it's not, we create
	 * a new submodule, load the config and insert it. If it's
	 * already inserted, we've already loaded it, so we skip.
	 */
	pos = git_strmap_lookup_index(map, name.ptr);
2000 2001 2002 2003
	if (git_strmap_valid_index(map, pos)) {
		error = 0;
		goto done;
	}
2004 2005 2006 2007 2008 2009 2010 2011 2012

	if ((error = submodule_alloc(&sm, data->repo, name.ptr)) < 0)
		goto done;

	if ((error = submodule_read_config(sm, data->mods)) < 0) {
		git_submodule_free(sm);
		goto done;
	}

2013
	git_strmap_insert(map, sm->name, sm, &error);
2014 2015 2016 2017 2018
	assert(error != 0);
	if (error < 0)
		goto done;

	error = 0;
2019

2020
done:
2021
	git_buf_dispose(&name);
2022
	return error;
2023 2024
}

2025
static int submodule_load_from_wd_lite(git_submodule *sm)
Russell Belfer committed
2026 2027 2028
{
	git_buf path = GIT_BUF_INIT;

2029
	if (git_buf_joinpath(&path, git_repository_workdir(sm->repo), sm->path) < 0)
2030
		return -1;
Russell Belfer committed
2031 2032 2033 2034 2035 2036 2037

	if (git_path_isdir(path.ptr))
		sm->flags |= GIT_SUBMODULE_STATUS__WD_SCANNED;

	if (git_path_contains(&path, DOT_GIT))
		sm->flags |= GIT_SUBMODULE_STATUS_IN_WD;

2038
	git_buf_dispose(&path);
Russell Belfer committed
2039 2040 2041
	return 0;
}

2042
/**
2043
 * Requests a snapshot of $WORK_TREE/.gitmodules.
2044
 *
2045
 * Returns GIT_ENOTFOUND in case no .gitmodules file exist
2046
 */
2047
static int gitmodules_snapshot(git_config **snap, git_repository *repo)
2048 2049
{
	const char *workdir = git_repository_workdir(repo);
2050
	git_config *mods = NULL;
2051
	git_buf path = GIT_BUF_INIT;
2052
	int error;
2053

2054 2055
	if (!workdir)
		return GIT_ENOTFOUND;
2056

2057 2058
	if ((error = git_buf_joinpath(&path, workdir, GIT_MODULES_FILE)) < 0)
		return error;
2059

2060 2061
	if ((error = git_config_open_ondisk(&mods, path.ptr)) < 0)
		goto cleanup;
2062
	git_buf_dispose(&path);
2063 2064 2065 2066 2067

	if ((error = git_config_snapshot(snap, mods)) < 0)
		goto cleanup;

	error = 0;
2068

2069 2070
cleanup:
	if (mods)
2071
		git_config_free(mods);
2072
	git_buf_dispose(&path);
2073

2074
	return error;
2075 2076
}

Ben Straub committed
2077
static git_config_backend *open_gitmodules(
2078
	git_repository *repo,
2079
	int okay_to_create)
Russell Belfer committed
2080
{
2081
	const char *workdir = git_repository_workdir(repo);
Russell Belfer committed
2082
	git_buf path = GIT_BUF_INIT;
Ben Straub committed
2083
	git_config_backend *mods = NULL;
Russell Belfer committed
2084 2085 2086 2087 2088 2089

	if (workdir != NULL) {
		if (git_buf_joinpath(&path, workdir, GIT_MODULES_FILE) != 0)
			return NULL;

		if (okay_to_create || git_path_isfile(path.ptr)) {
2090 2091
			/* git_config_backend_from_file should only fail if OOM */
			if (git_config_backend_from_file(&mods, path.ptr) < 0)
2092
				mods = NULL;
Russell Belfer committed
2093
			/* open should only fail here if the file is malformed */
2094 2095
			else if (git_config_backend_open(mods, GIT_CONFIG_LEVEL_LOCAL, repo) < 0) {
				git_config_backend_free(mods);
Russell Belfer committed
2096 2097
				mods = NULL;
			}
2098 2099 2100
		}
	}

2101
	git_buf_dispose(&path);
2102

Russell Belfer committed
2103 2104 2105
	return mods;
}

Russell Belfer committed
2106 2107
/* Lookup name of remote of the local tracking branch HEAD points to */
static int lookup_head_remote_key(git_buf *remote_name, git_repository *repo)
2108
{
Russell Belfer committed
2109
	int error;
Russell Belfer committed
2110 2111 2112 2113 2114 2115 2116
	git_reference *head = NULL;
	git_buf upstream_name = GIT_BUF_INIT;

	/* lookup and dereference HEAD */
	if ((error = git_repository_head(&head, repo)) < 0)
		return error;

2117 2118 2119 2120 2121 2122 2123 2124 2125 2126 2127 2128
	/**
	 * If head does not refer to a branch, then return
	 * GIT_ENOTFOUND to indicate that we could not find
	 * a remote key for the local tracking branch HEAD points to.
	 **/
	if (!git_reference_is_branch(head)) {
		giterr_set(GITERR_INVALID,
			"HEAD does not refer to a branch.");
		error = GIT_ENOTFOUND;
		goto done;
	}

Russell Belfer committed
2129
	/* lookup remote tracking branch of HEAD */
2130 2131 2132 2133 2134
	if ((error = git_branch_upstream_name(
		&upstream_name,
		repo,
		git_reference_name(head))) < 0)
		goto done;
Russell Belfer committed
2135

2136 2137 2138
	/* lookup remote of remote tracking branch */
	if ((error = git_branch_remote_name(remote_name, repo, upstream_name.ptr)) < 0)
		goto done;
Russell Belfer committed
2139

2140
done:
2141
	git_buf_dispose(&upstream_name);
Russell Belfer committed
2142
	git_reference_free(head);
2143

2144 2145
	return error;
}
2146

Russell Belfer committed
2147 2148
/* Lookup the remote of the local tracking branch HEAD points to */
static int lookup_head_remote(git_remote **remote, git_repository *repo)
2149 2150
{
	int error;
Russell Belfer committed
2151
	git_buf remote_name = GIT_BUF_INIT;
2152

Russell Belfer committed
2153 2154
	/* lookup remote of remote tracking branch name */
	if (!(error = lookup_head_remote_key(&remote_name, repo)))
2155
		error = git_remote_lookup(remote, repo, remote_name.ptr);
2156

2157
	git_buf_dispose(&remote_name);
Russell Belfer committed
2158

2159 2160
	return error;
}
Russell Belfer committed
2161

Russell Belfer committed
2162 2163
/* Lookup remote, either from HEAD or fall back on origin */
static int lookup_default_remote(git_remote **remote, git_repository *repo)
2164
{
Russell Belfer committed
2165
	int error = lookup_head_remote(remote, repo);
Russell Belfer committed
2166

Russell Belfer committed
2167 2168
	/* if that failed, use 'origin' instead */
	if (error == GIT_ENOTFOUND)
2169
		error = git_remote_lookup(remote, repo, "origin");
Russell Belfer committed
2170

Russell Belfer committed
2171 2172 2173
	if (error == GIT_ENOTFOUND)
		giterr_set(
			GITERR_SUBMODULE,
2174
			"cannot get default remote for submodule - no local tracking "
Russell Belfer committed
2175
			"branch for HEAD and origin does not exist");
Russell Belfer committed
2176 2177

	return error;
2178 2179
}

Russell Belfer committed
2180
static int get_url_base(git_buf *url, git_repository *repo)
2181 2182
{
	int error;
2183
	git_worktree *wt = NULL;
Russell Belfer committed
2184
	git_remote *remote = NULL;
2185

2186
	if ((error = lookup_default_remote(&remote, repo)) == 0) {
Russell Belfer committed
2187
		error = git_buf_sets(url, git_remote_url(remote));
2188 2189 2190 2191
		goto out;
	} else if (error != GIT_ENOTFOUND)
		goto out;
	else
Russell Belfer committed
2192
		giterr_clear();
2193 2194 2195 2196 2197 2198 2199

	/* if repository does not have a default remote, use workdir instead */
	if (git_repository_is_worktree(repo)) {
		if ((error = git_worktree_open_from_repository(&wt, repo)) < 0)
			goto out;
		error = git_buf_sets(url, wt->parent_path);
	} else
Russell Belfer committed
2200
		error = git_buf_sets(url, git_repository_workdir(repo));
2201 2202 2203 2204

out:
	git_remote_free(remote);
	git_worktree_free(wt);
2205 2206 2207 2208

	return error;
}

2209
static void submodule_get_index_status(unsigned int *status, git_submodule *sm)
Russell Belfer committed
2210
{
2211 2212
	const git_oid *head_oid  = git_submodule_head_id(sm);
	const git_oid *index_oid = git_submodule_index_id(sm);
Russell Belfer committed
2213

2214 2215
	*status = *status & ~GIT_SUBMODULE_STATUS__INDEX_FLAGS;

2216 2217 2218 2219 2220 2221 2222 2223
	if (!head_oid) {
		if (index_oid)
			*status |= GIT_SUBMODULE_STATUS_INDEX_ADDED;
	}
	else if (!index_oid)
		*status |= GIT_SUBMODULE_STATUS_INDEX_DELETED;
	else if (!git_oid_equal(head_oid, index_oid))
		*status |= GIT_SUBMODULE_STATUS_INDEX_MODIFIED;
Russell Belfer committed
2224 2225
}

2226

2227 2228 2229 2230 2231
static void submodule_get_wd_status(
	unsigned int *status,
	git_submodule *sm,
	git_repository *sm_repo,
	git_submodule_ignore_t ign)
2232
{
2233 2234 2235 2236
	const git_oid *index_oid = git_submodule_index_id(sm);
	const git_oid *wd_oid =
		(sm->flags & GIT_SUBMODULE_STATUS__WD_OID_VALID) ? &sm->wd_oid : NULL;
	git_tree *sm_head = NULL;
2237
	git_index *index = NULL;
2238
	git_diff_options opt = GIT_DIFF_OPTIONS_INIT;
2239
	git_diff *diff;
2240

2241
	*status = *status & ~GIT_SUBMODULE_STATUS__WD_FLAGS;
Russell Belfer committed
2242

2243 2244 2245
	if (!index_oid) {
		if (wd_oid)
			*status |= GIT_SUBMODULE_STATUS_WD_ADDED;
Russell Belfer committed
2246
	}
2247 2248 2249 2250 2251 2252
	else if (!wd_oid) {
		if ((sm->flags & GIT_SUBMODULE_STATUS__WD_SCANNED) != 0 &&
			(sm->flags & GIT_SUBMODULE_STATUS_IN_WD) == 0)
			*status |= GIT_SUBMODULE_STATUS_WD_UNINITIALIZED;
		else
			*status |= GIT_SUBMODULE_STATUS_WD_DELETED;
Russell Belfer committed
2253
	}
2254 2255
	else if (!git_oid_equal(index_oid, wd_oid))
		*status |= GIT_SUBMODULE_STATUS_WD_MODIFIED;
Russell Belfer committed
2256

2257 2258 2259
	/* if we have no repo, then we're done */
	if (!sm_repo)
		return;
2260

2261 2262 2263 2264
	/* the diffs below could be optimized with an early termination
	 * option to the git_diff functions, but for now this is sufficient
	 * (and certainly no worse that what core git does).
	 */
2265

2266 2267
	if (ign == GIT_SUBMODULE_IGNORE_NONE)
		opt.flags |= GIT_DIFF_INCLUDE_UNTRACKED;
Russell Belfer committed
2268

2269 2270
	(void)git_repository_index__weakptr(&index, sm_repo);

2271
	/* if we don't have an unborn head, check diff with index */
2272 2273 2274 2275
	if (git_repository_head_tree(&sm_head, sm_repo) < 0)
		giterr_clear();
	else {
		/* perform head to index diff on submodule */
2276
		if (git_diff_tree_to_index(&diff, sm_repo, sm_head, index, &opt) < 0)
2277 2278
			giterr_clear();
		else {
2279
			if (git_diff_num_deltas(diff) > 0)
2280
				*status |= GIT_SUBMODULE_STATUS_WD_INDEX_MODIFIED;
2281
			git_diff_free(diff);
2282 2283
			diff = NULL;
		}
Russell Belfer committed
2284

2285
		git_tree_free(sm_head);
2286
	}
2287

2288
	/* perform index-to-workdir diff on submodule */
2289
	if (git_diff_index_to_workdir(&diff, sm_repo, index, &opt) < 0)
2290 2291 2292 2293
		giterr_clear();
	else {
		size_t untracked =
			git_diff_num_deltas_of_type(diff, GIT_DELTA_UNTRACKED);
2294

2295 2296
		if (untracked > 0)
			*status |= GIT_SUBMODULE_STATUS_WD_UNTRACKED;
2297

2298 2299
		if (git_diff_num_deltas(diff) != untracked)
			*status |= GIT_SUBMODULE_STATUS_WD_WD_MODIFIED;
Russell Belfer committed
2300

2301
		git_diff_free(diff);
2302
		diff = NULL;
2303
	}
2304
}