submodule.c 59.5 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 11
#include "buf.h"
#include "branch.h"
12 13
#include "vector.h"
#include "posix.h"
14
#include "config_backend.h"
15 16
#include "config.h"
#include "repository.h"
Russell Belfer committed
17 18
#include "tree.h"
#include "iterator.h"
19
#include "fs_path.h"
20
#include "str.h"
21
#include "index.h"
22
#include "worktree.h"
23
#include "clone.h"
24
#include "path.h"
Russell Belfer committed
25

26 27 28 29 30
#include "git2/config.h"
#include "git2/sys/config.h"
#include "git2/types.h"
#include "git2/index.h"

Russell Belfer committed
31
#define GIT_MODULES_FILE ".gitmodules"
32

33 34 35 36 37 38 39
static git_configmap _sm_update_map[] = {
	{GIT_CONFIGMAP_STRING, "checkout", GIT_SUBMODULE_UPDATE_CHECKOUT},
	{GIT_CONFIGMAP_STRING, "rebase", GIT_SUBMODULE_UPDATE_REBASE},
	{GIT_CONFIGMAP_STRING, "merge", GIT_SUBMODULE_UPDATE_MERGE},
	{GIT_CONFIGMAP_STRING, "none", GIT_SUBMODULE_UPDATE_NONE},
	{GIT_CONFIGMAP_FALSE, NULL, GIT_SUBMODULE_UPDATE_NONE},
	{GIT_CONFIGMAP_TRUE, NULL, GIT_SUBMODULE_UPDATE_CHECKOUT},
40 41
};

42 43 44 45 46 47 48
static git_configmap _sm_ignore_map[] = {
	{GIT_CONFIGMAP_STRING, "none", GIT_SUBMODULE_IGNORE_NONE},
	{GIT_CONFIGMAP_STRING, "untracked", GIT_SUBMODULE_IGNORE_UNTRACKED},
	{GIT_CONFIGMAP_STRING, "dirty", GIT_SUBMODULE_IGNORE_DIRTY},
	{GIT_CONFIGMAP_STRING, "all", GIT_SUBMODULE_IGNORE_ALL},
	{GIT_CONFIGMAP_FALSE, NULL, GIT_SUBMODULE_IGNORE_NONE},
	{GIT_CONFIGMAP_TRUE, NULL, GIT_SUBMODULE_IGNORE_ALL},
49 50
};

51 52 53 54
static git_configmap _sm_recurse_map[] = {
	{GIT_CONFIGMAP_STRING, "on-demand", GIT_SUBMODULE_RECURSE_ONDEMAND},
	{GIT_CONFIGMAP_FALSE, NULL, GIT_SUBMODULE_RECURSE_NO},
	{GIT_CONFIGMAP_TRUE, NULL, GIT_SUBMODULE_RECURSE_YES},
55 56
};

57 58 59 60 61 62 63
enum {
	CACHE_OK = 0,
	CACHE_REFRESH = 1,
	CACHE_FLUSH = 2
};
enum {
	GITMODULES_EXISTING = 0,
64
	GITMODULES_CREATE = 1
65 66
};

67 68
static int submodule_alloc(git_submodule **out, git_repository *repo, const char *name);
static git_config_backend *open_gitmodules(git_repository *repo, int gitmod);
69
static int gitmodules_snapshot(git_config **snap, git_repository *repo);
70 71
static int get_url_base(git_str *url, git_repository *repo);
static int lookup_head_remote_key(git_str *remote_key, git_repository *repo);
72
static int lookup_default_remote(git_remote **remote, git_repository *repo);
73 74
static int submodule_load_each(const git_config_entry *entry, void *payload);
static int submodule_read_config(git_submodule *sm, git_config *cfg);
75
static int submodule_load_from_wd_lite(git_submodule *);
76 77
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);
78 79
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
80 81 82 83 84 85

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

86
static int submodule_config_key_trunc_puts(git_str *key, const char *suffix)
Russell Belfer committed
87
{
88 89 90
	ssize_t idx = git_str_rfind(key, '.');
	git_str_truncate(key, (size_t)(idx + 1));
	return git_str_puts(key, suffix);
Russell Belfer committed
91 92 93 94 95 96
}

/*
 * PUBLIC APIS
 */

97 98 99 100 101
static void submodule_set_lookup_error(int error, const char *name)
{
	if (!error)
		return;

102
	git_error_set(GIT_ERROR_SUBMODULE, (error == GIT_ENOTFOUND) ?
103 104
		"no submodule named '%s'" :
		"submodule '%s' has not been added yet", name);
105 106
}

107 108 109 110 111 112 113 114 115 116 117 118 119 120
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);
121
		GIT_ERROR_CHECK_ALLOC(data->name);
122 123 124 125 126
	}

	return 0;
}

127 128 129 130
/*
 * 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.
 */
131
static int is_path_occupied(bool *occupied, git_repository *repo, const char *path)
132 133
{
	int error = 0;
134
	git_index *index;
135
	git_str dir = GIT_STR_INIT;
136
	*occupied = false;
137 138

	if ((error = git_repository_index__weakptr(&index, repo)) < 0)
139
		goto out;
140

141 142
	if ((error = git_index_find(NULL, index, path)) != GIT_ENOTFOUND) {
		if (!error) {
143
			git_error_set(GIT_ERROR_SUBMODULE,
144 145 146
				"File '%s' already exists in the index", path);
			*occupied = true;
		}
147
		goto out;
148 149
	}

150
	if ((error = git_str_sets(&dir, path)) < 0)
151 152
		goto out;

153
	if ((error = git_fs_path_to_dir(&dir)) < 0)
154
		goto out;
155

156 157
	if ((error = git_index_find_prefix(NULL, index, dir.ptr)) != GIT_ENOTFOUND) {
		if (!error) {
158
			git_error_set(GIT_ERROR_SUBMODULE,
159 160 161 162
				"Directory '%s' already exists in the index", path);
			*occupied = true;
		}
		goto out;
163
	}
164

165
	error = 0;
166

167
out:
168
	git_str_dispose(&dir);
169
	return error;
170 171
}

172
/**
173
 * Release the name map returned by 'load_submodule_names'.
174
 */
175 176
static void free_submodule_names(git_strmap *names)
{
177 178
	const char *key;
	char *value;
179

180 181
	if (names == NULL)
		return;
182

183 184 185
	git_strmap_foreach(names, key, value, {
		git__free((char *) key);
		git__free(value);
186 187
	});
	git_strmap_free(names);
188

189 190 191 192 193 194 195 196
	return;
}

/**
 * Map submodule paths to names.
 * TODO: for some use-cases, this might need case-folding on a
 * case-insensitive filesystem
 */
197
static int load_submodule_names(git_strmap **out, git_repository *repo, git_config *cfg)
198 199
{
	const char *key = "submodule\\..*\\.path";
200
	git_config_iterator *iter = NULL;
201
	git_config_entry *entry;
202
	git_str buf = GIT_STR_INIT;
203
	git_strmap *names;
204
	int isvalid, error;
205

206 207
	*out = NULL;

208
	if ((error = git_strmap_new(&names)) < 0)
209 210
		goto out;

211
	if ((error = git_config_iterator_glob_new(&iter, cfg, key)) < 0)
212
		goto out;
213

214
	while ((error = git_config_next(&entry, iter)) == 0) {
215 216 217 218
		const char *fdot, *ldot;
		fdot = strchr(entry->name, '.');
		ldot = strrchr(entry->name, '.');

219
		if (git_strmap_exists(names, entry->value)) {
220
			git_error_set(GIT_ERROR_SUBMODULE,
221 222 223 224 225
				   "duplicated submodule path '%s'", entry->value);
			error = -1;
			goto out;
		}

226 227
		git_str_clear(&buf);
		git_str_put(&buf, fdot + 1, ldot - fdot - 1);
228
		isvalid = git_submodule_name_is_valid(repo, buf.ptr, 0);
229 230 231 232
		if (isvalid < 0) {
			error = isvalid;
			goto out;
		}
233
		if (!isvalid)
234 235
			continue;

236
		if ((error = git_strmap_set(names, git__strdup(entry->value), git_str_detach(&buf))) < 0) {
237
			git_error_set(GIT_ERROR_NOMEMORY, "error inserting submodule into hash table");
238 239
			error = -1;
			goto out;
240
		}
241
	}
242 243
	if (error == GIT_ITEROVER)
		error = 0;
244

245 246 247
	*out = names;
	names = NULL;

248
out:
249
	free_submodule_names(names);
250
	git_str_dispose(&buf);
251
	git_config_iterator_free(iter);
252
	return error;
253 254
}

255 256 257 258 259 260 261 262 263 264 265 266 267 268 269 270 271 272 273 274 275 276 277 278 279 280 281 282
int git_submodule_cache_init(git_strmap **out, git_repository *repo)
{
	int error = 0;
	git_strmap *cache = NULL;
	GIT_ASSERT_ARG(out);
	GIT_ASSERT_ARG(repo);
	if ((error = git_strmap_new(&cache)) < 0)
		return error;
	if ((error = git_submodule__map(repo, cache)) < 0) {
		git_submodule_cache_free(cache);
		return error;
	}
	*out = cache;
	return error;
}

int git_submodule_cache_free(git_strmap *cache)
{
	git_submodule *sm = NULL;
	if (cache == NULL)
		return 0;
	git_strmap_foreach_value(cache, sm, {
		git_submodule_free(sm);
	});
	git_strmap_free(cache);
	return 0;
}

283
int git_submodule_lookup(
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 */
{
288 289 290 291 292 293 294 295 296
	return git_submodule__lookup_with_cache(out, repo, name, repo->submodule_cache);
}

int git_submodule__lookup_with_cache(
	git_submodule **out, /* NULL if user only wants to test existence */
	git_repository *repo,
	const char *name,    /* trailing slash is allowed */
	git_strmap *cache)
{
297
	int error;
298
	unsigned int location;
299
	git_submodule *sm;
300

301 302
	GIT_ASSERT_ARG(repo);
	GIT_ASSERT_ARG(name);
303

304
	if (repo->is_bare) {
305
		git_error_set(GIT_ERROR_SUBMODULE, "cannot get submodules without a working tree");
306 307 308
		return -1;
	}

309 310
	if (cache != NULL) {
		if ((sm = git_strmap_get(cache, name)) != NULL) {
311
			if (out) {
312
				*out = sm;
313 314 315 316 317 318
				GIT_REFCOUNT_INC(*out);
			}
			return 0;
		}
	}

319 320
	if ((error = submodule_alloc(&sm, repo, name)) < 0)
		return error;
Russell Belfer committed
321

322 323
	if ((error = git_submodule_reload(sm, false)) < 0) {
		git_submodule_free(sm);
Russell Belfer committed
324
		return error;
325
	}
Russell Belfer committed
326

327 328 329 330 331
	if ((error = git_submodule_location(&location, sm)) < 0) {
		git_submodule_free(sm);
		return error;
	}

332
	/* If it's not configured or we're looking by path  */
333 334
	if (location == 0 || location == GIT_SUBMODULE_STATUS_IN_WD) {
		git_config_backend *mods;
335
		const char *pattern = "submodule\\..*\\.path";
336
		git_str path = GIT_STR_INIT;
337 338
		fbp_data data = { NULL, NULL };

339
		git_str_puts(&path, name);
340 341 342 343
		while (path.ptr[path.size-1] == '/') {
			path.ptr[--path.size] = '\0';
		}
		data.path = path.ptr;
344

345 346 347
		mods = open_gitmodules(repo, GITMODULES_EXISTING);

		if (mods)
348
			error = git_config_backend_foreach_match(mods, pattern, find_by_path, &data);
349

350
		git_config_backend_free(mods);
351 352 353

		if (error < 0) {
			git_submodule_free(sm);
354
			git_str_dispose(&path);
355
			return error;
356
		}
357 358 359 360

		if (data.name) {
			git__free(sm->name);
			sm->name = data.name;
361
			sm->path = git_str_detach(&path);
362 363 364 365 366 367 368

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

370
		git_str_dispose(&path);
371 372
	}

373 374 375 376 377 378 379
	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) {
380 381
		git_submodule_free(sm);
		error = GIT_ENOTFOUND;
Russell Belfer committed
382

383
		/* If it's not configured, we still check if there's a repo at the path */
Russell Belfer committed
384
		if (git_repository_workdir(repo)) {
385 386
			git_str path = GIT_STR_INIT;
			if (git_str_join3(&path, '/',
387 388
			                  git_repository_workdir(repo),
					  name, DOT_GIT) < 0 ||
389
			    git_path_validate_str_length(NULL, &path) < 0)
Russell Belfer committed
390 391
				return -1;

392
			if (git_fs_path_exists(path.ptr))
Russell Belfer committed
393 394
				error = GIT_EEXISTS;

395
			git_str_dispose(&path);
Russell Belfer committed
396 397
		}

398
		submodule_set_lookup_error(error, name);
399
		return error;
Russell Belfer committed
400 401
	}

402 403 404 405 406 407
	if (out)
		*out = sm;
	else
		git_submodule_free(sm);

	return 0;
Russell Belfer committed
408
}
409

410
int git_submodule_name_is_valid(git_repository *repo, const char *name, int flags)
411
{
412
	git_str buf = GIT_STR_INIT;
413 414
	int error, isvalid;

415
	if (flags == 0)
416
		flags = GIT_FS_PATH_REJECT_FILESYSTEM_DEFAULTS;
417

418
	/* Avoid allocating a new string if we can avoid it */
419
	if (strchr(name, '\\') != NULL) {
420
		if ((error = git_fs_path_normalize_slashes(&buf, name)) < 0)
421 422
			return error;
	} else {
423
		git_str_attach_notowned(&buf, name, strlen(name));
424 425
	}

426
	isvalid = git_path_is_valid(repo, buf.ptr, 0, flags);
427
	git_str_dispose(&buf);
428 429

	return isvalid;
430 431
}

432 433 434 435 436
static void submodule_free_dup(void *sm)
{
	git_submodule_free(sm);
}

437 438 439
static int submodule_get_or_create(git_submodule **out, git_repository *repo, git_strmap *map, const char *name)
{
	git_submodule *sm = NULL;
440
	int error;
441

442
	if ((sm = git_strmap_get(map, name)) != NULL)
443 444 445 446 447 448
		goto done;

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

449
	if ((error = git_strmap_set(map, sm->name, sm)) < 0) {
450 451 452 453 454 455 456 457 458 459
		git_submodule_free(sm);
		return error;
	}

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

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

467
	if ((error = load_submodule_names(&names, git_index_owner(idx), cfg)))
468
		goto done;
469

David Turner committed
470
	if ((error = git_iterator_for_index(&i, git_index_owner(idx), idx, NULL)) < 0)
471
		goto done;
472

David Turner committed
473 474 475
	while (!(error = git_iterator_advance(&entry, i))) {
		git_submodule *sm;

476
		if ((sm = git_strmap_get(map, entry->path)) != NULL) {
David Turner committed
477 478 479 480 481
			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
			const char *name;

484
			if ((name = git_strmap_get(names, entry->path)) == NULL)
485
				name = entry->path;
486

487
			if (!submodule_get_or_create(&sm, git_index_owner(idx), map, name)) {
David Turner committed
488 489 490 491 492
				submodule_update_from_index_entry(sm, entry);
				git_submodule_free(sm);
			}
		}
	}
493

David Turner committed
494 495
	if (error == GIT_ITEROVER)
		error = 0;
496

497
done:
David Turner committed
498
	git_iterator_free(i);
499
	free_submodule_names(names);
500

David Turner committed
501
	return error;
502 503
}

504
static int submodules_from_head(git_strmap *map, git_tree *head, git_config *cfg)
505
{
David Turner committed
506
	int error;
507
	git_iterator *i = NULL;
David Turner committed
508
	const git_index_entry *entry;
509 510 511
	git_strmap *names;

	if ((error = load_submodule_names(&names, git_tree_owner(head), cfg)))
512
		goto done;
513

David Turner committed
514
	if ((error = git_iterator_for_tree(&i, head, NULL)) < 0)
515
		goto done;
516

David Turner committed
517 518 519
	while (!(error = git_iterator_advance(&entry, i))) {
		git_submodule *sm;

520
		if ((sm = git_strmap_get(map, entry->path)) != NULL) {
David Turner committed
521 522 523 524 525
			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)) {
526 527
			const char *name;

528
			if ((name = git_strmap_get(names, entry->path)) == NULL)
529
				name = entry->path;
530

531
			if (!submodule_get_or_create(&sm, git_tree_owner(head), map, name)) {
David Turner committed
532 533 534 535 536 537
				submodule_update_from_head_data(
					sm, entry->mode, &entry->id);
				git_submodule_free(sm);
			}
		}
	}
538

David Turner committed
539 540
	if (error == GIT_ITEROVER)
		error = 0;
541

542
done:
David Turner committed
543
	git_iterator_free(i);
544
	free_submodule_names(names);
545

David Turner committed
546
	return error;
547 548 549 550
}

/* If have_sm is true, sm is populated, otherwise map an repo are. */
typedef struct {
551
	git_config *mods;
552 553 554 555
	git_strmap *map;
	git_repository *repo;
} lfc_data;

556
int git_submodule__map(git_repository *repo, git_strmap *map)
557 558 559 560
{
	int error = 0;
	git_index *idx = NULL;
	git_tree *head = NULL;
561
	git_str path = GIT_STR_INIT;
562
	git_submodule *sm;
563
	git_config *mods = NULL;
564
	bool has_workdir;
565

566 567
	GIT_ASSERT_ARG(repo);
	GIT_ASSERT_ARG(map);
568 569 570

	/* get sources that we will need to check */
	if (git_repository_index(&idx, repo) < 0)
571
		git_error_clear();
572
	if (git_repository_head_tree(&head, repo) < 0)
573
		git_error_clear();
574

575 576 577 578
	has_workdir = git_repository_workdir(repo) != NULL;

	if (has_workdir &&
	    (error = git_repository_workdir_path(&path, repo, GIT_MODULES_FILE)) < 0)
579 580
		goto cleanup;

581
	/* add submodule information from .gitmodules */
582
	if (has_workdir) {
583 584 585 586
		lfc_data data = { 0 };
		data.map = map;
		data.repo = repo;

587 588 589
		if ((error = gitmodules_snapshot(&mods, repo)) < 0) {
			if (error == GIT_ENOTFOUND)
				error = 0;
590
			goto cleanup;
591
		}
592 593 594 595 596 597

		data.mods = mods;
		if ((error = git_config_foreach(
			    mods, submodule_load_each, &data)) < 0)
			goto cleanup;
	}
598
	/* add back submodule information from index */
599
	if (mods && idx) {
600
		if ((error = submodules_from_index(map, idx, mods)) < 0)
601 602 603
			goto cleanup;
	}
	/* add submodule information from HEAD */
604
	if (mods && head) {
605
		if ((error = submodules_from_head(map, head, mods)) < 0)
606 607 608
			goto cleanup;
	}
	/* shallow scan submodules in work tree as needed */
609
	if (has_workdir) {
610 611 612 613 614 615
		git_strmap_foreach_value(map, sm, {
				submodule_load_from_wd_lite(sm);
			});
	}

cleanup:
616
	git_config_free(mods);
617 618 619
	/* TODO: if we got an error, mark submodule config as invalid? */
	git_index_free(idx);
	git_tree_free(head);
620
	git_str_dispose(&path);
621 622 623
	return error;
}

Russell Belfer committed
624 625
int git_submodule_foreach(
	git_repository *repo,
626
	git_submodule_cb callback,
Russell Belfer committed
627 628
	void *payload)
{
629 630 631
	git_vector snapshot = GIT_VECTOR_INIT;
	git_strmap *submodules;
	git_submodule *sm;
Russell Belfer committed
632
	int error;
633
	size_t i;
Russell Belfer committed
634

635
	if (repo->is_bare) {
636
		git_error_set(GIT_ERROR_SUBMODULE, "cannot get submodules without a working tree");
637 638 639
		return -1;
	}

640
	if ((error = git_strmap_new(&submodules)) < 0)
Russell Belfer committed
641 642
		return error;

643
	if ((error = git_submodule__map(repo, submodules)) < 0)
644
		goto done;
645 646

	if (!(error = git_vector_init(
647
			&snapshot, git_strmap_size(submodules), submodule_cmp))) {
648

649
		git_strmap_foreach_value(submodules, sm, {
650
			if ((error = git_vector_insert(&snapshot, sm)) < 0)
Russell Belfer committed
651
				break;
652 653 654 655 656 657 658 659 660 661
			GIT_REFCOUNT_INC(sm);
		});
	}

	if (error < 0)
		goto done;

	git_vector_uniq(&snapshot, submodule_free_dup);

	git_vector_foreach(&snapshot, i, sm) {
662
		if ((error = callback(sm, sm->name, payload)) != 0) {
663
			git_error_set_after_callback(error);
Russell Belfer committed
664
			break;
665
		}
666
	}
Russell Belfer committed
667

668 669 670 671
done:
	git_vector_foreach(&snapshot, i, sm)
		git_submodule_free(sm);
	git_vector_free(&snapshot);
Russell Belfer committed
672

673 674 675 676
	git_strmap_foreach_value(submodules, sm, {
		git_submodule_free(sm);
	});
	git_strmap_free(submodules);
Russell Belfer committed
677

678
	return error;
Russell Belfer committed
679 680
}

681 682 683 684 685 686 687 688
static int submodule_repo_init(
	git_repository **out,
	git_repository *parent_repo,
	const char *path,
	const char *url,
	bool use_gitlink)
{
	int error = 0;
689
	git_str workdir = GIT_STR_INIT, repodir = GIT_STR_INIT;
690 691 692
	git_repository_init_options initopt = GIT_REPOSITORY_INIT_OPTIONS_INIT;
	git_repository *subrepo = NULL;

693
	error = git_repository_workdir_path(&workdir, parent_repo, path);
694 695 696 697 698 699 700 701 702 703 704 705 706 707
	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) {
708
		error = git_repository__item_path(&repodir, parent_repo, GIT_REPOSITORY_ITEM_MODULES);
709 710
		if (error < 0)
			goto cleanup;
711
		error = git_str_joinpath(&repodir, repodir.ptr, path);
712 713 714 715 716 717 718 719 720 721 722 723 724
		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:
725 726
	git_str_dispose(&workdir);
	git_str_dispose(&repodir);
727 728 729 730 731 732

	*out = subrepo;

	return error;
}

733 734 735 736 737 738 739 740 741 742 743 744 745 746
static int git_submodule__resolve_url(
	git_str *out,
	git_repository *repo,
	const char *url)
{
	int error = 0;
	git_str normalized = GIT_STR_INIT;

	GIT_ASSERT_ARG(out);
	GIT_ASSERT_ARG(repo);
	GIT_ASSERT_ARG(url);

	/* We do this in all platforms in case someone on Windows created the .gitmodules */
	if (strchr(url, '\\')) {
747
		if ((error = git_fs_path_normalize_slashes(&normalized, url)) < 0)
748 749 750 751 752 753
			return error;

		url = normalized.ptr;
	}


754
	if (git_fs_path_is_relative(url)) {
755
		if (!(error = get_url_base(out, repo)))
756
			error = git_fs_path_apply_relative(out, url);
757 758 759 760 761 762 763 764 765 766 767 768 769 770 771 772 773 774 775
	} else if (strchr(url, ':') != NULL || url[0] == '/') {
		error = git_str_sets(out, url);
	} else {
		git_error_set(GIT_ERROR_SUBMODULE, "invalid format for submodule URL");
		error = -1;
	}

	git_str_dispose(&normalized);
	return error;
}

int git_submodule_resolve_url(
	git_buf *out,
	git_repository *repo,
	const char *url)
{
	GIT_BUF_WRAP_PRIVATE(out, git_submodule__resolve_url, repo, url);
}

Russell Belfer committed
776
int git_submodule_add_setup(
777
	git_submodule **out,
Russell Belfer committed
778 779 780 781 782 783
	git_repository *repo,
	const char *url,
	const char *path,
	int use_gitlink)
{
	int error = 0;
Ben Straub committed
784
	git_config_backend *mods = NULL;
785
	git_submodule *sm = NULL;
786
	git_str name = GIT_STR_INIT, real_url = GIT_STR_INIT;
Russell Belfer committed
787
	git_repository *subrepo = NULL;
788
	bool path_occupied;
Russell Belfer committed
789

790 791 792
	GIT_ASSERT_ARG(repo);
	GIT_ASSERT_ARG(url);
	GIT_ASSERT_ARG(path);
Russell Belfer committed
793 794 795

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

796
	if (git_submodule_lookup(NULL, repo, path) < 0)
797
		git_error_clear();
Russell Belfer committed
798
	else {
799
		git_error_set(GIT_ERROR_SUBMODULE,
800
			"attempt to add submodule '%s' that already exists", path);
Russell Belfer committed
801 802 803 804 805 806 807 808
		return GIT_EEXISTS;
	}

	/* validate and normalize path */

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

809
	if (git_fs_path_root(path) >= 0) {
810
		git_error_set(GIT_ERROR_SUBMODULE, "submodule path must be a relative path");
Russell Belfer committed
811 812 813 814
		error = -1;
		goto cleanup;
	}

815
	if ((error = is_path_occupied(&path_occupied, repo, path)) < 0)
816 817
		goto cleanup;

818 819 820 821 822
	if (path_occupied) {
		error = GIT_EEXISTS;
		goto cleanup;
	}

Russell Belfer committed
823 824
	/* update .gitmodules */

825
	if (!(mods = open_gitmodules(repo, GITMODULES_CREATE))) {
826
		git_error_set(GIT_ERROR_SUBMODULE,
827
			"adding submodules to a bare repository is not supported");
Russell Belfer committed
828 829 830
		return -1;
	}

831
	if ((error = git_str_printf(&name, "submodule.%s.path", path)) < 0 ||
832
		(error = git_config_backend_set_string(mods, name.ptr, path)) < 0)
Russell Belfer committed
833 834 835
		goto cleanup;

	if ((error = submodule_config_key_trunc_puts(&name, "url")) < 0 ||
836
		(error = git_config_backend_set_string(mods, name.ptr, url)) < 0)
Russell Belfer committed
837 838
		goto cleanup;

839
	git_str_clear(&name);
Russell Belfer committed
840 841 842

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

843
	error = git_repository_workdir_path(&name, repo, path);
Russell Belfer committed
844 845 846
	if (error < 0)
		goto cleanup;

847 848
	/* if the repo does not already exist, then init a new repo and add it.
	 * Otherwise, just add the existing repo.
Russell Belfer committed
849
	 */
850 851
	if (!(git_fs_path_exists(name.ptr) &&
		git_fs_path_contains(&name, DOT_GIT))) {
852 853

		/* resolve the actual URL to use */
854
		if ((error = git_submodule__resolve_url(&real_url, repo, url)) < 0)
855 856 857
			goto cleanup;

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

861
	if ((error = git_submodule_lookup(&sm, repo, path)) < 0)
862
		goto cleanup;
Russell Belfer committed
863

864
	error = git_submodule_init(sm, false);
865

Russell Belfer committed
866
cleanup:
867 868 869 870 871 872
	if (error && sm) {
		git_submodule_free(sm);
		sm = NULL;
	}
	if (out != NULL)
		*out = sm;
Russell Belfer committed
873

874
	git_config_backend_free(mods);
Russell Belfer committed
875
	git_repository_free(subrepo);
876 877
	git_str_dispose(&real_url);
	git_str_dispose(&name);
Russell Belfer committed
878 879 880 881

	return error;
}

882 883 884 885 886 887 888
int git_submodule_repo_init(
	git_repository **out,
	const git_submodule *sm,
	int use_gitlink)
{
	int error;
	git_repository *sub_repo = NULL;
889 890
	const char *configured_url;
	git_config *cfg = NULL;
891
	git_str buf = GIT_STR_INIT;
892

893 894
	GIT_ASSERT_ARG(out);
	GIT_ASSERT_ARG(sm);
895

896
	/* get the configured remote url of the submodule */
897
	if ((error = git_str_printf(&buf, "submodule.%s.url", sm->name)) < 0 ||
898
		(error = git_repository_config_snapshot(&cfg, sm->repo)) < 0 ||
899 900 901
		(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;
902 903 904

	*out = sub_repo;

905 906
done:
	git_config_free(cfg);
907
	git_str_dispose(&buf);
908 909 910
	return error;
}

911 912 913 914 915 916 917 918 919 920 921 922 923 924 925 926 927 928 929 930
static int clone_return_origin(git_remote **out, git_repository *repo, const char *name, const char *url, void *payload)
{
	GIT_UNUSED(url);
	GIT_UNUSED(payload);
	return git_remote_lookup(out, repo, name);
}

static int clone_return_repo(git_repository **out, const char *path, int bare, void *payload)
{
	git_submodule *sm = payload;

	GIT_UNUSED(path);
	GIT_UNUSED(bare);
	return git_submodule_open(out, sm);
}

int git_submodule_clone(git_repository **out, git_submodule *submodule, const git_submodule_update_options *given_opts)
{
	int error;
	git_repository *clone;
931
	git_str rel_path = GIT_STR_INIT;
932 933 934
	git_submodule_update_options sub_opts = GIT_SUBMODULE_UPDATE_OPTIONS_INIT;
	git_clone_options opts = GIT_CLONE_OPTIONS_INIT;

935
	GIT_ASSERT_ARG(submodule);
936 937 938 939 940 941 942 943 944 945 946 947 948

	if (given_opts)
		memcpy(&sub_opts, given_opts, sizeof(sub_opts));

	GIT_ERROR_CHECK_VERSION(&sub_opts, GIT_SUBMODULE_UPDATE_OPTIONS_VERSION, "git_submodule_update_options");

	memcpy(&opts.checkout_opts, &sub_opts.checkout_opts, sizeof(sub_opts.checkout_opts));
	memcpy(&opts.fetch_opts, &sub_opts.fetch_opts, sizeof(sub_opts.fetch_opts));
	opts.repository_cb = clone_return_repo;
	opts.repository_cb_payload = submodule;
	opts.remote_cb = clone_return_origin;
	opts.remote_cb_payload = submodule;

949 950 951
	error = git_repository_workdir_path(&rel_path, git_submodule_owner(submodule), git_submodule_path(submodule));
	if (error < 0)
		goto cleanup;
952

953
	error = git_clone__submodule(&clone, git_submodule_url(submodule), git_str_cstr(&rel_path), &opts);
954 955 956 957 958 959 960 961 962
	if (error < 0)
		goto cleanup;

	if (!out)
		git_repository_free(clone);
	else
		*out = clone;

cleanup:
963
	git_str_dispose(&rel_path);
964 965 966 967

	return error;
}

Russell Belfer committed
968 969 970 971 972
int git_submodule_add_finalize(git_submodule *sm)
{
	int error;
	git_index *index;

973
	GIT_ASSERT_ARG(sm);
Russell Belfer committed
974

975
	if ((error = git_repository_index__weakptr(&index, sm->repo)) < 0 ||
976
		(error = git_index_add_bypath(index, GIT_MODULES_FILE)) < 0)
Russell Belfer committed
977 978
		return error;

979
	return git_submodule_add_to_index(sm, true);
Russell Belfer committed
980 981
}

982
int git_submodule_add_to_index(git_submodule *sm, int write_index)
Russell Belfer committed
983 984
{
	int error;
985
	git_repository *sm_repo = NULL;
Russell Belfer committed
986
	git_index *index;
987
	git_str path = GIT_STR_INIT;
Russell Belfer committed
988 989 990 991
	git_commit *head;
	git_index_entry entry;
	struct stat st;

992
	GIT_ASSERT_ARG(sm);
Russell Belfer committed
993

994 995 996
	/* force reload of wd OID by git_submodule_open */
	sm->flags = sm->flags & ~GIT_SUBMODULE_STATUS__WD_OID_VALID;

997
	if ((error = git_repository_index__weakptr(&index, sm->repo)) < 0 ||
998 999
	    (error = git_repository_workdir_path(&path, sm->repo, sm->path)) < 0 ||
	    (error = git_submodule_open(&sm_repo, sm)) < 0)
Russell Belfer committed
1000 1001 1002 1003
		goto cleanup;

	/* read stat information for submodule working directory */
	if (p_stat(path.ptr, &st) < 0) {
1004
		git_error_set(GIT_ERROR_SUBMODULE,
1005
			"cannot add submodule without working directory");
Russell Belfer committed
1006 1007 1008
		error = -1;
		goto cleanup;
	}
1009 1010

	memset(&entry, 0, sizeof(entry));
1011
	entry.path = sm->path;
1012
	git_index_entry__init_from_stat(
1013
		&entry, &st, !(git_index_caps(index) & GIT_INDEX_CAPABILITY_NO_FILEMODE));
Russell Belfer committed
1014 1015 1016

	/* calling git_submodule_open will have set sm->wd_oid if possible */
	if ((sm->flags & GIT_SUBMODULE_STATUS__WD_OID_VALID) == 0) {
1017
		git_error_set(GIT_ERROR_SUBMODULE,
1018
			"cannot add submodule without HEAD to index");
Russell Belfer committed
1019 1020 1021
		error = -1;
		goto cleanup;
	}
1022
	git_oid_cpy(&entry.id, &sm->wd_oid);
Russell Belfer committed
1023 1024 1025 1026

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

1027
	entry.ctime.seconds = (int32_t)git_commit_time(head);
Russell Belfer committed
1028
	entry.ctime.nanoseconds = 0;
1029
	entry.mtime.seconds = (int32_t)git_commit_time(head);
Russell Belfer committed
1030 1031 1032 1033
	entry.mtime.nanoseconds = 0;

	git_commit_free(head);

1034
	/* add it */
Edward Thomson committed
1035
	error = git_index_add(index, &entry);
Russell Belfer committed
1036

1037 1038 1039 1040 1041 1042 1043 1044
	/* 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
1045 1046
cleanup:
	git_repository_free(sm_repo);
1047
	git_str_dispose(&path);
Russell Belfer committed
1048 1049 1050
	return error;
}

1051
static const char *submodule_update_to_str(git_submodule_update_t update)
1052 1053 1054
{
	int i;
	for (i = 0; i < (int)ARRAY_SIZE(_sm_update_map); ++i)
1055
		if (_sm_update_map[i].map_value == (int)update)
1056 1057 1058 1059
			return _sm_update_map[i].str_match;
	return NULL;
}

Russell Belfer committed
1060 1061
git_repository *git_submodule_owner(git_submodule *submodule)
{
1062
	GIT_ASSERT_ARG_WITH_RETVAL(submodule, NULL);
1063
	return submodule->repo;
Russell Belfer committed
1064 1065 1066 1067
}

const char *git_submodule_name(git_submodule *submodule)
{
1068
	GIT_ASSERT_ARG_WITH_RETVAL(submodule, NULL);
Russell Belfer committed
1069 1070 1071 1072 1073
	return submodule->name;
}

const char *git_submodule_path(git_submodule *submodule)
{
1074
	GIT_ASSERT_ARG_WITH_RETVAL(submodule, NULL);
Russell Belfer committed
1075 1076 1077 1078 1079
	return submodule->path;
}

const char *git_submodule_url(git_submodule *submodule)
{
1080
	GIT_ASSERT_ARG_WITH_RETVAL(submodule, NULL);
Russell Belfer committed
1081 1082 1083
	return submodule->url;
}

1084 1085
static int write_var(git_repository *repo, const char *name, const char *var, const char *val)
{
1086
	git_str key = GIT_STR_INIT;
1087 1088 1089 1090 1091 1092 1093
	git_config_backend *mods;
	int error;

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

1094
	if ((error = git_str_printf(&key, "submodule.%s.%s", name, var)) < 0)
1095 1096 1097
		goto cleanup;

	if (val)
1098
		error = git_config_backend_set_string(mods, key.ptr, val);
1099
	else
1100
		error = git_config_backend_delete(mods, key.ptr);
1101

1102
	git_str_dispose(&key);
1103 1104

cleanup:
1105
	git_config_backend_free(mods);
1106 1107 1108
	return error;
}

1109
static int write_mapped_var(git_repository *repo, const char *name, git_configmap *maps, size_t nmaps, const char *var, int ival)
1110
{
1111
	git_configmap_t type;
1112 1113 1114
	const char *val;

	if (git_config_lookup_map_enum(&type, &val, maps, nmaps, ival) < 0) {
1115
		git_error_set(GIT_ERROR_SUBMODULE, "invalid value for %s", var);
1116 1117 1118
		return -1;
	}

1119
	if (type == GIT_CONFIGMAP_TRUE)
1120 1121 1122 1123 1124
		val = "true";

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

1125 1126
const char *git_submodule_branch(git_submodule *submodule)
{
1127
	GIT_ASSERT_ARG_WITH_RETVAL(submodule, NULL);
1128 1129 1130
	return submodule->branch;
}

1131
int git_submodule_set_branch(git_repository *repo, const char *name, const char *branch)
1132
{
1133 1134
	GIT_ASSERT_ARG(repo);
	GIT_ASSERT_ARG(name);
1135

1136
	return write_var(repo, name, "branch", branch);
1137 1138
}

1139
int git_submodule_set_url(git_repository *repo, const char *name, const char *url)
Russell Belfer committed
1140
{
1141 1142 1143
	GIT_ASSERT_ARG(repo);
	GIT_ASSERT_ARG(name);
	GIT_ASSERT_ARG(url);
Russell Belfer committed
1144

1145
	return write_var(repo, name, "url", url);
Russell Belfer committed
1146 1147
}

1148
const git_oid *git_submodule_index_id(git_submodule *submodule)
Russell Belfer committed
1149
{
1150
	GIT_ASSERT_ARG_WITH_RETVAL(submodule, NULL);
Russell Belfer committed
1151 1152 1153 1154 1155 1156 1157

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

1158
const git_oid *git_submodule_head_id(git_submodule *submodule)
Russell Belfer committed
1159
{
1160
	GIT_ASSERT_ARG_WITH_RETVAL(submodule, NULL);
Russell Belfer committed
1161 1162 1163 1164 1165 1166 1167

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

1168
const git_oid *git_submodule_wd_id(git_submodule *submodule)
Russell Belfer committed
1169
{
1170
	GIT_ASSERT_ARG_WITH_RETVAL(submodule, NULL);
Russell Belfer committed
1171

1172
	/* load unless we think we have a valid oid */
Russell Belfer committed
1173 1174 1175 1176
	if (!(submodule->flags & GIT_SUBMODULE_STATUS__WD_OID_VALID)) {
		git_repository *subrepo;

		/* calling submodule open grabs the HEAD OID if possible */
1177
		if (!git_submodule_open_bare(&subrepo, submodule))
Russell Belfer committed
1178
			git_repository_free(subrepo);
1179
		else
1180
			git_error_clear();
Russell Belfer committed
1181 1182 1183 1184 1185 1186 1187 1188 1189 1190
	}

	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)
{
1191 1192
	GIT_ASSERT_ARG_WITH_RETVAL(submodule, GIT_SUBMODULE_IGNORE_UNSPECIFIED);

1193 1194
	return (submodule->ignore < GIT_SUBMODULE_IGNORE_NONE) ?
		GIT_SUBMODULE_IGNORE_NONE : submodule->ignore;
Russell Belfer committed
1195 1196
}

1197 1198
int git_submodule_set_ignore(git_repository *repo, const char *name, git_submodule_ignore_t ignore)
{
1199 1200
	GIT_ASSERT_ARG(repo);
	GIT_ASSERT_ARG(name);
1201

1202
	return write_mapped_var(repo, name, _sm_ignore_map, ARRAY_SIZE(_sm_ignore_map), "ignore", ignore);
1203 1204
}

1205
git_submodule_update_t git_submodule_update_strategy(git_submodule *submodule)
Russell Belfer committed
1206
{
1207 1208
	GIT_ASSERT_ARG_WITH_RETVAL(submodule, GIT_SUBMODULE_UPDATE_NONE);

1209 1210
	return (submodule->update < GIT_SUBMODULE_UPDATE_CHECKOUT) ?
		GIT_SUBMODULE_UPDATE_CHECKOUT : submodule->update;
Russell Belfer committed
1211 1212
}

1213
int git_submodule_set_update(git_repository *repo, const char *name, git_submodule_update_t update)
Russell Belfer committed
1214
{
1215 1216
	GIT_ASSERT_ARG(repo);
	GIT_ASSERT_ARG(name);
Russell Belfer committed
1217

1218
	return write_mapped_var(repo, name, _sm_update_map, ARRAY_SIZE(_sm_update_map), "update", update);
Russell Belfer committed
1219 1220
}

1221
git_submodule_recurse_t git_submodule_fetch_recurse_submodules(
1222 1223
	git_submodule *submodule)
{
1224
	GIT_ASSERT_ARG_WITH_RETVAL(submodule, GIT_SUBMODULE_RECURSE_NO);
1225 1226 1227
	return submodule->fetch_recurse;
}

1228
int git_submodule_set_fetch_recurse_submodules(git_repository *repo, const char *name, git_submodule_recurse_t recurse)
1229
{
1230 1231
	GIT_ASSERT_ARG(repo);
	GIT_ASSERT_ARG(name);
1232

1233
	return write_mapped_var(repo, name, _sm_recurse_map, ARRAY_SIZE(_sm_recurse_map), "fetchRecurseSubmodules", recurse);
1234 1235
}

1236 1237 1238 1239 1240 1241
static int submodule_repo_create(
	git_repository **out,
	git_repository *parent_repo,
	const char *path)
{
	int error = 0;
1242
	git_str workdir = GIT_STR_INIT, repodir = GIT_STR_INIT;
1243 1244 1245 1246 1247 1248 1249 1250 1251 1252
	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 */
1253
	error = git_repository_workdir_path(&workdir, parent_repo, path);
1254 1255 1256 1257 1258 1259 1260
	if (error < 0)
		goto cleanup;

	initopt.workdir_path = workdir.ptr;

	/**
	 * Repodir: path to the sub-repo. sub-repo goes in:
1261
	 * <repo-dir>/modules/<name>/ with a gitlink in the
1262 1263
	 * sub-repo workdir directory to that repository.
	 */
1264
	error = git_repository__item_path(&repodir, parent_repo, GIT_REPOSITORY_ITEM_MODULES);
1265 1266
	if (error < 0)
		goto cleanup;
1267
	error = git_str_joinpath(&repodir, repodir.ptr, path);
1268 1269 1270 1271 1272 1273
	if (error < 0)
		goto cleanup;

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

cleanup:
1274 1275
	git_str_dispose(&workdir);
	git_str_dispose(&repodir);
1276 1277 1278 1279 1280 1281 1282 1283 1284 1285 1286 1287 1288 1289 1290 1291

	*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)
{
1292 1293
	git_submodule *sm;

1294
	GIT_UNUSED(bare);
1295 1296

	sm = payload;
1297 1298 1299 1300

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

1301
int git_submodule_update_options_init(git_submodule_update_options *opts, unsigned int version)
1302 1303 1304 1305 1306 1307
{
	GIT_INIT_STRUCTURE_FROM_TEMPLATE(
		opts, version, git_submodule_update_options, GIT_SUBMODULE_UPDATE_OPTIONS_INIT);
	return 0;
}

1308
#ifndef GIT_DEPRECATE_HARD
1309 1310 1311 1312
int git_submodule_update_init_options(git_submodule_update_options *opts, unsigned int version)
{
	return git_submodule_update_options_init(opts, version);
}
1313
#endif
1314

1315 1316 1317 1318 1319 1320 1321 1322 1323
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;
1324
	git_str buf = GIT_STR_INIT;
1325 1326 1327
	git_submodule_update_options update_options = GIT_SUBMODULE_UPDATE_OPTIONS_INIT;
	git_clone_options clone_options = GIT_CLONE_OPTIONS_INIT;

1328
	GIT_ASSERT_ARG(sm);
1329 1330 1331 1332

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

1333
	GIT_ERROR_CHECK_VERSION(&update_options, GIT_SUBMODULE_UPDATE_OPTIONS_VERSION, "git_submodule_update_options");
1334 1335

	/* Copy over the remote callbacks */
1336
	memcpy(&clone_options.fetch_opts, &update_options.fetch_opts, sizeof(git_fetch_options));
1337 1338

	/* Get the status of the submodule to determine if it is already initialized  */
1339
	if ((error = git_submodule_status(&submodule_status, sm->repo, sm->name, GIT_SUBMODULE_IGNORE_UNSPECIFIED)) < 0)
1340
		goto done;
1341 1342 1343 1344 1345
	
	/* If the submodule is configured but hasn't been added, skip it */
	if (submodule_status == GIT_SUBMODULE_STATUS_IN_CONFIG)
	        goto done;
	
1346 1347 1348 1349 1350 1351 1352 1353 1354 1355
	/*
	 * 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 ||
1356
			(error = git_str_printf(&buf, "submodule.%s.url", git_submodule_name(sm))) < 0)
1357 1358
			goto done;

1359
		if ((error = git_config_get_string(&submodule_url, config, git_str_cstr(&buf))) < 0) {
1360 1361 1362 1363 1364 1365 1366
			/*
			 * 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;

1367
			if (!init) {
1368
				git_error_set(GIT_ERROR_SUBMODULE, "submodule is not initialized");
1369 1370 1371 1372 1373 1374 1375 1376 1377 1378 1379 1380
				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 ||
1381
				(error = git_config_get_string(&submodule_url, config, git_str_cstr(&buf))) < 0)
1382 1383 1384 1385 1386 1387 1388 1389 1390
				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;

		/*
1391
		 * Do not perform checkout as part of clone, instead we
1392 1393 1394 1395
		 * will checkout the specific commit manually.
		 */
		clone_options.checkout_opts.checkout_strategy = GIT_CHECKOUT_NONE;

1396
		if ((error = git_clone__submodule(&sub_repo, submodule_url, sm->path, &clone_options)) < 0 ||
1397
			(error = git_repository_set_head_detached(sub_repo, git_submodule_index_id(sm))) < 0 ||
1398 1399 1400
			(error = git_checkout_head(sub_repo, &update_options.checkout_opts)) != 0)
			goto done;
	} else {
1401 1402
		const git_oid *oid;

1403 1404 1405 1406 1407
		/**
		 * 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.
		 */
1408 1409 1410
		if ((error = git_submodule_open(&sub_repo, sm)) < 0)
			goto done;

1411
		if ((oid = git_submodule_index_id(sm)) == NULL) {
1412
			git_error_set(GIT_ERROR_SUBMODULE, "could not get ID of submodule in index");
1413 1414 1415 1416
			error = -1;
			goto done;
		}

1417
		/* Look up the target commit in the submodule. */
1418
		if ((error = git_object_lookup(&target_commit, sub_repo, oid, GIT_OBJECT_COMMIT)) < 0) {
1419 1420 1421 1422
			/* 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 ||
1423
				(error = git_object_lookup(&target_commit, sub_repo, git_submodule_index_id(sm), GIT_OBJECT_COMMIT)) < 0)
1424 1425 1426 1427
				goto done;
		}

		if ((error = git_checkout_tree(sub_repo, target_commit, &update_options.checkout_opts)) != 0 ||
1428
			(error = git_repository_set_head_detached(sub_repo, git_submodule_index_id(sm))) < 0)
1429 1430 1431 1432 1433 1434 1435 1436 1437 1438
			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:
1439
	git_str_dispose(&buf);
1440 1441 1442 1443 1444 1445 1446 1447
	git_config_free(config);
	git_object_free(target_commit);
	git_remote_free(remote);
	git_repository_free(sub_repo);

	return error;
}

1448
int git_submodule_init(git_submodule *sm, int overwrite)
Russell Belfer committed
1449 1450
{
	int error;
1451
	const char *val;
1452
	git_str key = GIT_STR_INIT, effective_submodule_url = GIT_STR_INIT;
1453
	git_config *cfg = NULL;
Russell Belfer committed
1454

1455
	if (!sm->url) {
1456
		git_error_set(GIT_ERROR_SUBMODULE,
1457
			"no URL configured for submodule '%s'", sm->name);
Russell Belfer committed
1458 1459 1460
		return -1;
	}

1461
	if ((error = git_repository_config(&cfg, sm->repo)) < 0)
Russell Belfer committed
1462 1463
		return error;

1464 1465
	/* write "submodule.NAME.url" */

1466 1467
	if ((error = git_submodule__resolve_url(&effective_submodule_url, sm->repo, sm->url)) < 0 ||
		(error = git_str_printf(&key, "submodule.%s.url", sm->name)) < 0 ||
1468
		(error = git_config__update_entry(
1469
			cfg, key.ptr, effective_submodule_url.ptr, overwrite != 0, false)) < 0)
1470 1471
		goto cleanup;

Russell Belfer committed
1472 1473
	/* write "submodule.NAME.update" if not default */

1474
	val = (sm->update == GIT_SUBMODULE_UPDATE_CHECKOUT) ?
1475
		NULL : submodule_update_to_str(sm->update);
1476

1477
	if ((error = git_str_printf(&key, "submodule.%s.update", sm->name)) < 0 ||
1478 1479 1480 1481 1482 1483 1484 1485
		(error = git_config__update_entry(
			cfg, key.ptr, val, overwrite != 0, false)) < 0)
		goto cleanup;

	/* success */

cleanup:
	git_config_free(cfg);
1486 1487
	git_str_dispose(&key);
	git_str_dispose(&effective_submodule_url);
Russell Belfer committed
1488 1489 1490 1491

	return error;
}

1492
int git_submodule_sync(git_submodule *sm)
Russell Belfer committed
1493
{
1494
	git_str key = GIT_STR_INIT, url = GIT_STR_INIT, remote_name = GIT_STR_INIT;
1495
	git_repository *smrepo = NULL;
1496 1497
	git_config *cfg = NULL;
	int error = 0;
1498 1499

	if (!sm->url) {
1500
		git_error_set(GIT_ERROR_SUBMODULE, "no URL configured for submodule '%s'", sm->name);
Russell Belfer committed
1501 1502 1503 1504
		return -1;
	}

	/* copy URL over to config only if it already exists */
1505
	if ((error = git_repository_config__weakptr(&cfg, sm->repo)) < 0 ||
1506 1507
	    (error = git_str_printf(&key, "submodule.%s.url", sm->name)) < 0 ||
	    (error = git_submodule__resolve_url(&url, sm->repo, sm->url)) < 0 ||
1508 1509
	    (error = git_config__update_entry(cfg, key.ptr, url.ptr, true, true)) < 0)
		goto out;
Russell Belfer committed
1510

1511 1512
	if (!(sm->flags & GIT_SUBMODULE_STATUS_IN_WD))
		goto out;
1513 1514

	/* if submodule exists in the working directory, update remote url */
1515 1516 1517
	if ((error = git_submodule_open(&smrepo, sm)) < 0 ||
	    (error = git_repository_config__weakptr(&cfg, smrepo)) < 0)
		goto out;
1518

1519
	if (lookup_head_remote_key(&remote_name, smrepo) == 0) {
1520
		if ((error = git_str_join3(&key, '.', "remote", remote_name.ptr, "url")) < 0)
1521
			goto out;
1522
	} else if ((error = git_str_sets(&key, "remote.origin.url")) < 0) {
1523
		goto out;
1524 1525
	}

1526 1527
	if ((error = git_config__update_entry(cfg, key.ptr, url.ptr, true, false)) < 0)
		goto out;
1528

1529 1530
out:
	git_repository_free(smrepo);
1531 1532 1533
	git_str_dispose(&remote_name);
	git_str_dispose(&key);
	git_str_dispose(&url);
1534
	return error;
Russell Belfer committed
1535 1536
}

1537 1538
static int git_submodule__open(
	git_repository **subrepo, git_submodule *sm, bool bare)
Russell Belfer committed
1539 1540
{
	int error;
1541
	git_str path = GIT_STR_INIT;
1542 1543
	unsigned int flags = GIT_REPOSITORY_OPEN_NO_SEARCH;
	const char *wd;
Russell Belfer committed
1544

1545 1546
	GIT_ASSERT_ARG(sm);
	GIT_ASSERT_ARG(subrepo);
Russell Belfer committed
1547

1548 1549 1550
	if (git_repository__ensure_not_bare(
			sm->repo, "open submodule repository") < 0)
		return GIT_EBAREREPO;
Russell Belfer committed
1551

1552
	wd = git_repository_workdir(sm->repo);
Russell Belfer committed
1553

1554
	if (git_str_join3(&path, '/', wd, sm->path, DOT_GIT) < 0)
Russell Belfer committed
1555 1556
		return -1;

1557 1558 1559 1560
	sm->flags = sm->flags &
		~(GIT_SUBMODULE_STATUS_IN_WD |
		  GIT_SUBMODULE_STATUS__WD_OID_VALID |
		  GIT_SUBMODULE_STATUS__WD_SCANNED);
Russell Belfer committed
1561

1562 1563
	if (bare)
		flags |= GIT_REPOSITORY_OPEN_BARE;
Russell Belfer committed
1564

1565
	error = git_repository_open_ext(subrepo, path.ptr, flags, wd);
1566

1567 1568 1569 1570
	/* if we opened the submodule successfully, grab HEAD OID, etc. */
	if (!error) {
		sm->flags |= GIT_SUBMODULE_STATUS_IN_WD |
			GIT_SUBMODULE_STATUS__WD_SCANNED;
1571

1572 1573 1574
		if (!git_reference_name_to_id(&sm->wd_oid, *subrepo, GIT_HEAD_FILE))
			sm->flags |= GIT_SUBMODULE_STATUS__WD_OID_VALID;
		else
1575
			git_error_clear();
1576
	} else if (git_fs_path_exists(path.ptr)) {
1577 1578 1579
		sm->flags |= GIT_SUBMODULE_STATUS__WD_SCANNED |
			GIT_SUBMODULE_STATUS_IN_WD;
	} else {
1580
		git_str_rtruncate_at_char(&path, '/'); /* remove "/.git" */
1581

1582
		if (git_fs_path_isdir(path.ptr))
1583 1584
			sm->flags |= GIT_SUBMODULE_STATUS__WD_SCANNED;
	}
1585

1586
	git_str_dispose(&path);
1587

1588 1589
	return error;
}
1590

1591 1592 1593 1594
int git_submodule_open_bare(git_repository **subrepo, git_submodule *sm)
{
	return git_submodule__open(subrepo, sm, true);
}
Russell Belfer committed
1595

1596 1597 1598
int git_submodule_open(git_repository **subrepo, git_submodule *sm)
{
	return git_submodule__open(subrepo, sm, false);
Russell Belfer committed
1599 1600
}

1601 1602
static void submodule_update_from_index_entry(
	git_submodule *sm, const git_index_entry *ie)
Russell Belfer committed
1603
{
1604
	bool already_found = (sm->flags & GIT_SUBMODULE_STATUS_IN_INDEX) != 0;
Russell Belfer committed
1605

1606 1607 1608 1609 1610 1611 1612
	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
1613
			git_oid_cpy(&sm->index_oid, &ie->id);
Russell Belfer committed
1614

1615 1616 1617 1618 1619 1620 1621 1622 1623
		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
1624

1625
	if (git_repository_index__weakptr(&index, sm->repo) < 0)
Russell Belfer committed
1626 1627
		return -1;

1628
	sm->flags = sm->flags &
1629 1630 1631
		~(GIT_SUBMODULE_STATUS_IN_INDEX |
		  GIT_SUBMODULE_STATUS__INDEX_OID_VALID);

1632 1633
	if (!(ie = git_index_get_bypath(index, sm->path, 0)))
		return 0;
Russell Belfer committed
1634

1635 1636 1637 1638 1639 1640 1641 1642 1643 1644 1645 1646 1647 1648 1649
	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
1650
	}
1651
}
Russell Belfer committed
1652

1653 1654 1655
static int submodule_update_head(git_submodule *submodule)
{
	git_tree *head = NULL;
nulltoken committed
1656
	git_tree_entry *te = NULL;
Russell Belfer committed
1657

1658 1659 1660
	submodule->flags = submodule->flags &
		~(GIT_SUBMODULE_STATUS_IN_HEAD |
		  GIT_SUBMODULE_STATUS__HEAD_OID_VALID);
Russell Belfer committed
1661

1662 1663 1664
	/* 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)
1665
		git_error_clear();
1666
	else
1667
		submodule_update_from_head_data(submodule, te->attr, git_tree_entry_id(te));
Russell Belfer committed
1668

nulltoken committed
1669
	git_tree_entry_free(te);
1670 1671 1672
	git_tree_free(head);
	return 0;
}
1673

1674
int git_submodule_reload(git_submodule *sm, int force)
1675
{
1676 1677
	git_config *mods = NULL;
	int error;
Russell Belfer committed
1678

1679 1680
	GIT_UNUSED(force);

1681
	GIT_ASSERT_ARG(sm);
1682

1683
	if ((error = git_submodule_name_is_valid(sm->repo, sm->name, 0)) <= 0)
1684
		/* This should come with a warning, but we've no API for that */
1685
		goto out;
1686

1687 1688
	if (git_repository_is_bare(sm->repo))
		goto out;
Russell Belfer committed
1689

1690 1691 1692
	/* refresh config data */
	if ((error = gitmodules_snapshot(&mods, sm->repo)) < 0 && error != GIT_ENOTFOUND)
		goto out;
1693

1694 1695
	if (mods != NULL && (error = submodule_read_config(sm, mods)) < 0)
		goto out;
Russell Belfer committed
1696

1697 1698 1699 1700 1701
	/* refresh wd data */
	sm->flags &=
		~(GIT_SUBMODULE_STATUS_IN_WD |
		  GIT_SUBMODULE_STATUS__WD_OID_VALID |
		  GIT_SUBMODULE_STATUS__WD_FLAGS);
1702

1703 1704 1705 1706
	if ((error = submodule_load_from_wd_lite(sm)) < 0 ||
	    (error = submodule_update_index(sm)) < 0 ||
	    (error = submodule_update_head(sm)) < 0)
		goto out;
1707

1708 1709
out:
	git_config_free(mods);
1710
	return error;
Russell Belfer committed
1711 1712
}

1713 1714
static void submodule_copy_oid_maybe(
	git_oid *tgt, const git_oid *src, bool valid)
Russell Belfer committed
1715
{
1716 1717 1718 1719 1720 1721 1722
	if (tgt) {
		if (valid)
			memcpy(tgt, src, sizeof(*tgt));
		else
			memset(tgt, 0, sizeof(*tgt));
	}
}
1723

1724 1725 1726 1727 1728 1729 1730 1731 1732 1733
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
1734

1735
	if (ign == GIT_SUBMODULE_IGNORE_UNSPECIFIED)
1736
		ign = sm->ignore;
1737

1738 1739 1740 1741
	/* only return location info if ignore == all */
	if (ign == GIT_SUBMODULE_IGNORE_ALL) {
		*out_status = (sm->flags & GIT_SUBMODULE_STATUS__IN_FLAGS);
		return 0;
1742
	}
Russell Belfer committed
1743

1744 1745 1746 1747 1748 1749
	/* 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.
	 */
1750

1751 1752 1753 1754 1755 1756 1757 1758 1759
	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
1760

1761 1762 1763 1764
	/* 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)
1765
			git_error_clear();
1766 1767 1768 1769
		else
			git_repository_free(smrepo);
		smrepo = NULL;
	} else if (git_submodule_open(&smrepo, sm) < 0) {
1770
		git_error_clear();
1771 1772 1773 1774 1775 1776 1777 1778 1779 1780 1781 1782 1783 1784 1785 1786 1787 1788 1789 1790
		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
1791 1792
}

1793
int git_submodule_status(unsigned int *status, git_repository *repo, const char *name, git_submodule_ignore_t ignore)
1794
{
1795 1796 1797
	git_submodule *sm;
	int error;

1798 1799 1800
	GIT_ASSERT_ARG(status);
	GIT_ASSERT_ARG(repo);
	GIT_ASSERT_ARG(name);
1801 1802 1803 1804

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

1805
	error = git_submodule__status(status, NULL, NULL, NULL, sm, ignore);
1806
	git_submodule_free(sm);
1807

1808
	return error;
1809
}
1810

1811 1812
int git_submodule_location(unsigned int *location, git_submodule *sm)
{
1813 1814
	GIT_ASSERT_ARG(location);
	GIT_ASSERT_ARG(sm);
1815 1816 1817

	return git_submodule__status(
		location, NULL, NULL, NULL, sm, GIT_SUBMODULE_IGNORE_ALL);
1818 1819
}

Russell Belfer committed
1820 1821 1822 1823
/*
 * INTERNAL FUNCTIONS
 */

1824
static int submodule_alloc(
1825
	git_submodule **out, git_repository *repo, const char *name)
1826
{
1827
	size_t namelen;
1828
	git_submodule *sm;
1829

1830
	if (!name || !(namelen = strlen(name))) {
1831
		git_error_set(GIT_ERROR_SUBMODULE, "invalid submodule name");
1832
		return -1;
1833 1834
	}

1835
	sm = git__calloc(1, sizeof(git_submodule));
1836
	GIT_ERROR_CHECK_ALLOC(sm);
1837

1838 1839 1840
	sm->name = sm->path = git__strdup(name);
	if (!sm->name) {
		git__free(sm);
1841
		return -1;
1842
	}
Russell Belfer committed
1843

1844
	GIT_REFCOUNT_INC(sm);
1845 1846
	sm->ignore = sm->ignore_default = GIT_SUBMODULE_IGNORE_NONE;
	sm->update = sm->update_default = GIT_SUBMODULE_UPDATE_CHECKOUT;
1847
	sm->fetch_recurse = sm->fetch_recurse_default = GIT_SUBMODULE_RECURSE_NO;
1848
	sm->repo   = repo;
1849
	sm->branch = NULL;
1850

1851 1852
	*out = sm;
	return 0;
Russell Belfer committed
1853 1854
}

1855
static void submodule_release(git_submodule *sm)
Russell Belfer committed
1856 1857 1858 1859
{
	if (!sm)
		return;

1860
	if (sm->repo) {
1861
		sm->repo = NULL;
1862 1863
	}

1864 1865 1866 1867
	if (sm->path != sm->name)
		git__free(sm->path);
	git__free(sm->name);
	git__free(sm->url);
1868
	git__free(sm->branch);
1869 1870 1871
	git__memzero(sm, sizeof(*sm));
	git__free(sm);
}
Russell Belfer committed
1872

1873
int git_submodule_dup(git_submodule **out, git_submodule *source)
1874
{
1875
	GIT_ASSERT_ARG(out);
1876
	GIT_ASSERT_ARG(source);
1877

1878
	GIT_REFCOUNT_INC(source);
1879 1880 1881

	*out = source;
	return 0;
1882 1883
}

1884 1885 1886 1887 1888
void git_submodule_free(git_submodule *sm)
{
	if (!sm)
		return;
	GIT_REFCOUNT_DEC(sm, submodule_release);
Russell Belfer committed
1889 1890
}

1891 1892
static int submodule_config_error(const char *property, const char *value)
{
1893
	git_error_set(GIT_ERROR_INVALID,
1894
		"invalid value for submodule '%s' property: '%s'", property, value);
1895
	return -1;
1896 1897
}

1898 1899 1900 1901 1902 1903 1904 1905 1906 1907 1908 1909 1910 1911 1912 1913 1914 1915 1916 1917 1918 1919 1920 1921 1922 1923 1924 1925
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;
}

1926
static int submodule_parse_recurse(git_submodule_recurse_t *out, const char *value)
1927 1928 1929 1930 1931 1932 1933 1934 1935 1936 1937 1938 1939
{
	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;
}

1940
static int get_value(const char **out, git_config *cfg, git_str *buf, const char *name, const char *field)
1941
{
1942
	int error;
1943

1944
	git_str_clear(buf);
1945

1946
	if ((error = git_str_printf(buf, "submodule.%s.%s", name, field)) < 0 ||
1947 1948
	    (error = git_config_get_string(out, cfg, buf->ptr)) < 0)
		return error;
1949

1950 1951
	return error;
}
1952

1953 1954 1955 1956 1957 1958 1959 1960
static bool looks_like_command_line_option(const char *s)
{
	if (s && s[0] == '-')
		return true;

	return false;
}

1961 1962
static int submodule_read_config(git_submodule *sm, git_config *cfg)
{
1963
	git_str key = GIT_STR_INIT;
1964 1965
	const char *value;
	int error, in_config = 0;
Russell Belfer committed
1966

1967 1968 1969
	/*
	 * 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)
1970
	 */
1971

1972 1973
	if ((error = get_value(&value, cfg, &key, sm->name, "path")) == 0) {
		in_config = 1;
1974 1975
		/* We would warn here if we had that API */
		if (!looks_like_command_line_option(value)) {
1976 1977
	/*
	 * TODO: if case insensitive filesystem, then the following strcmp
1978 1979
	 * should be strcasecmp
	 */
1980 1981 1982 1983
			if (strcmp(sm->name, value) != 0) {
				if (sm->path != sm->name)
					git__free(sm->path);
				sm->path = git__strdup(value);
1984
				GIT_ERROR_CHECK_ALLOC(sm->path);
1985 1986
			}

1987
		}
1988
	} else if (error != GIT_ENOTFOUND) {
1989
		goto cleanup;
1990
	}
1991

1992
	if ((error = get_value(&value, cfg, &key, sm->name, "url")) == 0) {
1993 1994 1995 1996
		/* We would warn here if we had that API */
		if (!looks_like_command_line_option(value)) {
			in_config = 1;
			sm->url = git__strdup(value);
1997
			GIT_ERROR_CHECK_ALLOC(sm->url);
1998
		}
1999
	} else if (error != GIT_ENOTFOUND) {
2000
		goto cleanup;
2001 2002
	}

2003 2004 2005
	if ((error = get_value(&value, cfg, &key, sm->name, "branch")) == 0) {
		in_config = 1;
		sm->branch = git__strdup(value);
2006
		GIT_ERROR_CHECK_ALLOC(sm->branch);
2007
	} else if (error != GIT_ENOTFOUND) {
2008
		goto cleanup;
2009
	}
2010

2011 2012
	if ((error = get_value(&value, cfg, &key, sm->name, "update")) == 0) {
		in_config = 1;
2013
		if ((error = git_submodule_parse_update(&sm->update, value)) < 0)
2014
			goto cleanup;
2015
		sm->update_default = sm->update;
2016
	} else if (error != GIT_ENOTFOUND) {
2017
		goto cleanup;
2018
	}
2019 2020 2021

	if ((error = get_value(&value, cfg, &key, sm->name, "fetchRecurseSubmodules")) == 0) {
		in_config = 1;
2022
		if ((error = submodule_parse_recurse(&sm->fetch_recurse, value)) < 0)
2023
			goto cleanup;
2024
		sm->fetch_recurse_default = sm->fetch_recurse;
2025
	} else if (error != GIT_ENOTFOUND) {
2026
		goto cleanup;
2027
	}
2028 2029 2030

	if ((error = get_value(&value, cfg, &key, sm->name, "ignore")) == 0) {
		in_config = 1;
2031
		if ((error = git_submodule_parse_ignore(&sm->ignore, value)) < 0)
2032
			goto cleanup;
2033
		sm->ignore_default = sm->ignore;
2034
	} else if (error != GIT_ENOTFOUND) {
2035
		goto cleanup;
2036
	}
2037 2038 2039 2040

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

2041 2042 2043
	error = 0;

cleanup:
2044
	git_str_dispose(&key);
2045
	return error;
2046 2047 2048 2049 2050 2051 2052
}

static int submodule_load_each(const git_config_entry *entry, void *payload)
{
	lfc_data *data = payload;
	const char *namestart, *property;
	git_strmap *map = data->map;
2053
	git_str name = GIT_STR_INIT;
2054
	git_submodule *sm;
2055
	int error, isvalid;
2056 2057 2058 2059 2060 2061 2062 2063 2064 2065 2066 2067

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

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

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

	property++;

2068
	if ((error = git_str_set(&name, namestart, property - namestart -1)) < 0)
2069 2070
		return error;

2071 2072 2073
	isvalid = git_submodule_name_is_valid(data->repo, name.ptr, 0);
	if (isvalid <= 0) {
		error = isvalid;
2074 2075 2076
		goto done;
	}

2077 2078 2079 2080 2081 2082
	/*
	 * 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.
	 */
2083
	if (git_strmap_exists(map, name.ptr)) {
2084 2085 2086
		error = 0;
		goto done;
	}
2087 2088 2089 2090 2091 2092 2093 2094 2095

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

2096
	if ((error = git_strmap_set(map, sm->name, sm)) < 0)
2097 2098 2099
		goto done;

	error = 0;
2100

2101
done:
2102
	git_str_dispose(&name);
2103
	return error;
2104 2105
}

2106
static int submodule_load_from_wd_lite(git_submodule *sm)
Russell Belfer committed
2107
{
2108
	git_str path = GIT_STR_INIT;
Russell Belfer committed
2109

2110
	if (git_repository_workdir_path(&path, sm->repo, sm->path) < 0)
2111
		return -1;
Russell Belfer committed
2112

2113
	if (git_fs_path_isdir(path.ptr))
Russell Belfer committed
2114 2115
		sm->flags |= GIT_SUBMODULE_STATUS__WD_SCANNED;

2116
	if (git_fs_path_contains(&path, DOT_GIT))
Russell Belfer committed
2117 2118
		sm->flags |= GIT_SUBMODULE_STATUS_IN_WD;

2119
	git_str_dispose(&path);
Russell Belfer committed
2120 2121 2122
	return 0;
}

2123
/**
2124
 * Requests a snapshot of $WORK_TREE/.gitmodules.
2125
 *
2126
 * Returns GIT_ENOTFOUND in case no .gitmodules file exist
2127
 */
2128
static int gitmodules_snapshot(git_config **snap, git_repository *repo)
2129
{
2130
	git_config *mods = NULL;
2131
	git_str path = GIT_STR_INIT;
2132
	int error;
2133

2134
	if (git_repository_workdir(repo) == NULL)
2135
		return GIT_ENOTFOUND;
2136

2137
	if ((error = git_repository_workdir_path(&path, repo, GIT_MODULES_FILE)) < 0)
2138
		return error;
2139

2140 2141
	if ((error = git_config_open_ondisk(&mods, path.ptr)) < 0)
		goto cleanup;
2142
	git_str_dispose(&path);
2143 2144 2145 2146 2147

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

	error = 0;
2148

2149 2150
cleanup:
	if (mods)
2151
		git_config_free(mods);
2152
	git_str_dispose(&path);
2153

2154
	return error;
2155 2156
}

Ben Straub committed
2157
static git_config_backend *open_gitmodules(
2158
	git_repository *repo,
2159
	int okay_to_create)
Russell Belfer committed
2160
{
2161
	git_str path = GIT_STR_INIT;
Ben Straub committed
2162
	git_config_backend *mods = NULL;
Russell Belfer committed
2163

2164 2165
	if (git_repository_workdir(repo) != NULL) {
		if (git_repository_workdir_path(&path, repo, GIT_MODULES_FILE) != 0)
Russell Belfer committed
2166 2167
			return NULL;

2168
		if (okay_to_create || git_fs_path_isfile(path.ptr)) {
2169 2170
			/* git_config_backend_from_file should only fail if OOM */
			if (git_config_backend_from_file(&mods, path.ptr) < 0)
2171
				mods = NULL;
Russell Belfer committed
2172
			/* open should only fail here if the file is malformed */
2173 2174
			else if (git_config_backend_open(mods, GIT_CONFIG_LEVEL_LOCAL, repo) < 0) {
				git_config_backend_free(mods);
Russell Belfer committed
2175 2176
				mods = NULL;
			}
2177 2178 2179
		}
	}

2180
	git_str_dispose(&path);
2181

Russell Belfer committed
2182 2183 2184
	return mods;
}

Russell Belfer committed
2185
/* Lookup name of remote of the local tracking branch HEAD points to */
2186
static int lookup_head_remote_key(git_str *remote_name, git_repository *repo)
2187
{
Russell Belfer committed
2188
	int error;
Russell Belfer committed
2189
	git_reference *head = NULL;
2190
	git_str upstream_name = GIT_STR_INIT;
Russell Belfer committed
2191 2192 2193 2194 2195

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

2196 2197 2198 2199 2200 2201
	/**
	 * 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)) {
2202
		git_error_set(GIT_ERROR_INVALID,
2203 2204 2205 2206 2207
			"HEAD does not refer to a branch.");
		error = GIT_ENOTFOUND;
		goto done;
	}

Russell Belfer committed
2208
	/* lookup remote tracking branch of HEAD */
2209
	if ((error = git_branch__upstream_name(
2210 2211 2212 2213
		&upstream_name,
		repo,
		git_reference_name(head))) < 0)
		goto done;
Russell Belfer committed
2214

2215
	/* lookup remote of remote tracking branch */
2216
	if ((error = git_branch__remote_name(remote_name, repo, upstream_name.ptr)) < 0)
2217
		goto done;
Russell Belfer committed
2218

2219
done:
2220
	git_str_dispose(&upstream_name);
Russell Belfer committed
2221
	git_reference_free(head);
2222

2223 2224
	return error;
}
2225

Russell Belfer committed
2226 2227
/* Lookup the remote of the local tracking branch HEAD points to */
static int lookup_head_remote(git_remote **remote, git_repository *repo)
2228 2229
{
	int error;
2230
	git_str remote_name = GIT_STR_INIT;
2231

Russell Belfer committed
2232 2233
	/* lookup remote of remote tracking branch name */
	if (!(error = lookup_head_remote_key(&remote_name, repo)))
2234
		error = git_remote_lookup(remote, repo, remote_name.ptr);
2235

2236
	git_str_dispose(&remote_name);
Russell Belfer committed
2237

2238 2239
	return error;
}
Russell Belfer committed
2240

Russell Belfer committed
2241 2242
/* Lookup remote, either from HEAD or fall back on origin */
static int lookup_default_remote(git_remote **remote, git_repository *repo)
2243
{
Russell Belfer committed
2244
	int error = lookup_head_remote(remote, repo);
Russell Belfer committed
2245

Russell Belfer committed
2246
	/* if that failed, use 'origin' instead */
2247
	if (error == GIT_ENOTFOUND || error == GIT_EUNBORNBRANCH)
2248
		error = git_remote_lookup(remote, repo, "origin");
Russell Belfer committed
2249

Russell Belfer committed
2250
	if (error == GIT_ENOTFOUND)
2251 2252
		git_error_set(
			GIT_ERROR_SUBMODULE,
2253
			"cannot get default remote for submodule - no local tracking "
Russell Belfer committed
2254
			"branch for HEAD and origin does not exist");
Russell Belfer committed
2255 2256

	return error;
2257 2258
}

2259
static int get_url_base(git_str *url, git_repository *repo)
2260 2261
{
	int error;
2262
	git_worktree *wt = NULL;
Russell Belfer committed
2263
	git_remote *remote = NULL;
2264

2265
	if ((error = lookup_default_remote(&remote, repo)) == 0) {
2266
		error = git_str_sets(url, git_remote_url(remote));
2267 2268 2269 2270
		goto out;
	} else if (error != GIT_ENOTFOUND)
		goto out;
	else
2271
		git_error_clear();
2272 2273 2274 2275 2276

	/* 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;
2277
		error = git_str_sets(url, wt->parent_path);
2278
	} else {
2279
		error = git_str_sets(url, git_repository_workdir(repo));
2280
	}
2281 2282 2283 2284

out:
	git_remote_free(remote);
	git_worktree_free(wt);
2285 2286 2287 2288

	return error;
}

2289
static void submodule_get_index_status(unsigned int *status, git_submodule *sm)
Russell Belfer committed
2290
{
2291 2292
	const git_oid *head_oid  = git_submodule_head_id(sm);
	const git_oid *index_oid = git_submodule_index_id(sm);
Russell Belfer committed
2293

2294 2295
	*status = *status & ~GIT_SUBMODULE_STATUS__INDEX_FLAGS;

2296 2297 2298 2299 2300 2301 2302 2303
	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
2304 2305
}

2306

2307 2308 2309 2310 2311
static void submodule_get_wd_status(
	unsigned int *status,
	git_submodule *sm,
	git_repository *sm_repo,
	git_submodule_ignore_t ign)
2312
{
2313 2314 2315 2316
	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;
2317
	git_index *index = NULL;
2318
	git_diff_options opt = GIT_DIFF_OPTIONS_INIT;
2319
	git_diff *diff;
2320

2321
	*status = *status & ~GIT_SUBMODULE_STATUS__WD_FLAGS;
Russell Belfer committed
2322

2323 2324 2325
	if (!index_oid) {
		if (wd_oid)
			*status |= GIT_SUBMODULE_STATUS_WD_ADDED;
Russell Belfer committed
2326
	}
2327 2328 2329 2330 2331 2332
	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
2333
	}
2334 2335
	else if (!git_oid_equal(index_oid, wd_oid))
		*status |= GIT_SUBMODULE_STATUS_WD_MODIFIED;
Russell Belfer committed
2336

2337 2338 2339
	/* if we have no repo, then we're done */
	if (!sm_repo)
		return;
2340

2341 2342 2343 2344
	/* 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).
	 */
2345

2346 2347
	if (ign == GIT_SUBMODULE_IGNORE_NONE)
		opt.flags |= GIT_DIFF_INCLUDE_UNTRACKED;
Russell Belfer committed
2348

2349 2350
	(void)git_repository_index__weakptr(&index, sm_repo);

2351
	/* if we don't have an unborn head, check diff with index */
2352
	if (git_repository_head_tree(&sm_head, sm_repo) < 0)
2353
		git_error_clear();
2354 2355
	else {
		/* perform head to index diff on submodule */
2356
		if (git_diff_tree_to_index(&diff, sm_repo, sm_head, index, &opt) < 0)
2357
			git_error_clear();
2358
		else {
2359
			if (git_diff_num_deltas(diff) > 0)
2360
				*status |= GIT_SUBMODULE_STATUS_WD_INDEX_MODIFIED;
2361
			git_diff_free(diff);
2362 2363
			diff = NULL;
		}
Russell Belfer committed
2364

2365
		git_tree_free(sm_head);
2366
	}
2367

2368
	/* perform index-to-workdir diff on submodule */
2369
	if (git_diff_index_to_workdir(&diff, sm_repo, index, &opt) < 0)
2370
		git_error_clear();
2371 2372 2373
	else {
		size_t untracked =
			git_diff_num_deltas_of_type(diff, GIT_DELTA_UNTRACKED);
2374

2375 2376
		if (untracked > 0)
			*status |= GIT_SUBMODULE_STATUS_WD_UNTRACKED;
2377

2378 2379
		if (git_diff_num_deltas(diff) != untracked)
			*status |= GIT_SUBMODULE_STATUS_WD_WD_MODIFIED;
Russell Belfer committed
2380

2381
		git_diff_free(diff);
2382
		diff = NULL;
2383
	}
2384
}