ls-files: use repository object
Convert ls-files to use a repository struct and recurse submodules inprocess. Signed-off-by: Brandon Williams <bmwill@google.com> Signed-off-by: Junio C Hamano <gitster@pobox.com>maint
							parent
							
								
									96dc883b3c
								
							
						
					
					
						commit
						188dce131f
					
				|  | @ -5,7 +5,9 @@ | |||
|  * | ||||
|  * Copyright (C) Linus Torvalds, 2005 | ||||
|  */ | ||||
| #define NO_THE_INDEX_COMPATIBILITY_MACROS | ||||
| #include "cache.h" | ||||
| #include "repository.h" | ||||
| #include "config.h" | ||||
| #include "quote.h" | ||||
| #include "dir.h" | ||||
|  | @ -32,10 +34,8 @@ static int line_terminator = '\n'; | |||
| static int debug_mode; | ||||
| static int show_eol; | ||||
| static int recurse_submodules; | ||||
| static struct argv_array submodule_options = ARGV_ARRAY_INIT; | ||||
|  | ||||
| static const char *prefix; | ||||
| static const char *super_prefix; | ||||
| static int max_prefix_len; | ||||
| static int prefix_len; | ||||
| static struct pathspec pathspec; | ||||
|  | @ -73,25 +73,12 @@ static void write_eolinfo(const struct index_state *istate, | |||
|  | ||||
| static void write_name(const char *name) | ||||
| { | ||||
| 	/* | ||||
| 	 * Prepend the super_prefix to name to construct the full_name to be | ||||
| 	 * written. | ||||
| 	 */ | ||||
| 	struct strbuf full_name = STRBUF_INIT; | ||||
| 	if (super_prefix) { | ||||
| 		strbuf_addstr(&full_name, super_prefix); | ||||
| 		strbuf_addstr(&full_name, name); | ||||
| 		name = full_name.buf; | ||||
| 	} | ||||
|  | ||||
| 	/* | ||||
| 	 * With "--full-name", prefix_len=0; this caller needs to pass | ||||
| 	 * an empty string in that case (a NULL is good for ""). | ||||
| 	 */ | ||||
| 	write_name_quoted_relative(name, prefix_len ? prefix : NULL, | ||||
| 				   stdout, line_terminator); | ||||
|  | ||||
| 	strbuf_release(&full_name); | ||||
| } | ||||
|  | ||||
| static const char *get_tag(const struct cache_entry *ce, const char *tag) | ||||
|  | @ -210,83 +197,38 @@ static void show_killed_files(const struct index_state *istate, | |||
| 	} | ||||
| } | ||||
|  | ||||
| /* | ||||
|  * Compile an argv_array with all of the options supported by --recurse_submodules | ||||
|  */ | ||||
| static void compile_submodule_options(const char **argv, | ||||
| 				      const struct dir_struct *dir, | ||||
| 				      int show_tag) | ||||
| { | ||||
| 	if (line_terminator == '\0') | ||||
| 		argv_array_push(&submodule_options, "-z"); | ||||
| 	if (show_tag) | ||||
| 		argv_array_push(&submodule_options, "-t"); | ||||
| 	if (show_valid_bit) | ||||
| 		argv_array_push(&submodule_options, "-v"); | ||||
| 	if (show_cached) | ||||
| 		argv_array_push(&submodule_options, "--cached"); | ||||
| 	if (show_eol) | ||||
| 		argv_array_push(&submodule_options, "--eol"); | ||||
| 	if (debug_mode) | ||||
| 		argv_array_push(&submodule_options, "--debug"); | ||||
| static void show_files(struct repository *repo, struct dir_struct *dir); | ||||
|  | ||||
| 	/* Add Pathspecs */ | ||||
| 	argv_array_push(&submodule_options, "--"); | ||||
| 	for (; *argv; argv++) | ||||
| 		argv_array_push(&submodule_options, *argv); | ||||
| static void show_submodule(struct repository *superproject, | ||||
| 			   struct dir_struct *dir, const char *path) | ||||
| { | ||||
| 	struct repository submodule; | ||||
|  | ||||
| 	if (repo_submodule_init(&submodule, superproject, path)) | ||||
| 		return; | ||||
|  | ||||
| 	if (repo_read_index(&submodule) < 0) | ||||
| 		die("index file corrupt"); | ||||
|  | ||||
| 	repo_read_gitmodules(&submodule); | ||||
|  | ||||
| 	show_files(&submodule, dir); | ||||
|  | ||||
| 	repo_clear(&submodule); | ||||
| } | ||||
|  | ||||
| /** | ||||
|  * Recursively call ls-files on a submodule | ||||
|  */ | ||||
| static void show_gitlink(const struct cache_entry *ce) | ||||
| static void show_ce(struct repository *repo, struct dir_struct *dir, | ||||
| 		    const struct cache_entry *ce, const char *fullname, | ||||
| 		    const char *tag) | ||||
| { | ||||
| 	struct child_process cp = CHILD_PROCESS_INIT; | ||||
| 	int status; | ||||
| 	char *dir; | ||||
|  | ||||
| 	prepare_submodule_repo_env(&cp.env_array); | ||||
| 	argv_array_push(&cp.env_array, GIT_DIR_ENVIRONMENT); | ||||
|  | ||||
| 	if (prefix_len) | ||||
| 		argv_array_pushf(&cp.env_array, "%s=%s", | ||||
| 				 GIT_TOPLEVEL_PREFIX_ENVIRONMENT, | ||||
| 				 prefix); | ||||
| 	argv_array_pushf(&cp.args, "--super-prefix=%s%s/", | ||||
| 			 super_prefix ? super_prefix : "", | ||||
| 			 ce->name); | ||||
| 	argv_array_push(&cp.args, "ls-files"); | ||||
| 	argv_array_push(&cp.args, "--recurse-submodules"); | ||||
|  | ||||
| 	/* add supported options */ | ||||
| 	argv_array_pushv(&cp.args, submodule_options.argv); | ||||
|  | ||||
| 	cp.git_cmd = 1; | ||||
| 	dir = mkpathdup("%s/%s", get_git_work_tree(), ce->name); | ||||
| 	cp.dir = dir; | ||||
| 	status = run_command(&cp); | ||||
| 	free(dir); | ||||
| 	if (status) | ||||
| 		exit(status); | ||||
| } | ||||
|  | ||||
| static void show_ce_entry(const struct index_state *istate, | ||||
| 			  const char *tag, const struct cache_entry *ce) | ||||
| { | ||||
| 	struct strbuf name = STRBUF_INIT; | ||||
| 	int len = max_prefix_len; | ||||
| 	if (super_prefix) | ||||
| 		strbuf_addstr(&name, super_prefix); | ||||
| 	strbuf_addstr(&name, ce->name); | ||||
|  | ||||
| 	if (len > ce_namelen(ce)) | ||||
| 	if (max_prefix_len > strlen(fullname)) | ||||
| 		die("git ls-files: internal error - cache entry not superset of prefix"); | ||||
|  | ||||
| 	if (recurse_submodules && S_ISGITLINK(ce->ce_mode) && | ||||
| 	    submodule_path_match(&pathspec, name.buf, ps_matched)) { | ||||
| 		show_gitlink(ce); | ||||
| 	} else if (match_pathspec(&pathspec, name.buf, name.len, | ||||
| 				  len, ps_matched, | ||||
| 	    is_submodule_active(repo, ce->name)) { | ||||
| 		show_submodule(repo, dir, ce->name); | ||||
| 	} else if (match_pathspec(&pathspec, fullname, strlen(fullname), | ||||
| 				  max_prefix_len, ps_matched, | ||||
| 				  S_ISDIR(ce->ce_mode) || | ||||
| 				  S_ISGITLINK(ce->ce_mode))) { | ||||
| 		tag = get_tag(ce, tag); | ||||
|  | @ -300,12 +242,10 @@ static void show_ce_entry(const struct index_state *istate, | |||
| 			       find_unique_abbrev(ce->oid.hash, abbrev), | ||||
| 			       ce_stage(ce)); | ||||
| 		} | ||||
| 		write_eolinfo(istate, ce, ce->name); | ||||
| 		write_name(ce->name); | ||||
| 		write_eolinfo(repo->index, ce, fullname); | ||||
| 		write_name(fullname); | ||||
| 		print_debug(ce); | ||||
| 	} | ||||
|  | ||||
| 	strbuf_release(&name); | ||||
| } | ||||
|  | ||||
| static void show_ru_info(const struct index_state *istate) | ||||
|  | @ -338,59 +278,79 @@ static void show_ru_info(const struct index_state *istate) | |||
| } | ||||
|  | ||||
| static int ce_excluded(struct dir_struct *dir, struct index_state *istate, | ||||
| 		       const struct cache_entry *ce) | ||||
| 		       const char *fullname, const struct cache_entry *ce) | ||||
| { | ||||
| 	int dtype = ce_to_dtype(ce); | ||||
| 	return is_excluded(dir, istate, ce->name, &dtype); | ||||
| 	return is_excluded(dir, istate, fullname, &dtype); | ||||
| } | ||||
|  | ||||
| static void show_files(struct index_state *istate, struct dir_struct *dir) | ||||
| static void construct_fullname(struct strbuf *out, const struct repository *repo, | ||||
| 			       const struct cache_entry *ce) | ||||
| { | ||||
| 	strbuf_reset(out); | ||||
| 	if (repo->submodule_prefix) | ||||
| 		strbuf_addstr(out, repo->submodule_prefix); | ||||
| 	strbuf_addstr(out, ce->name); | ||||
| } | ||||
|  | ||||
| static void show_files(struct repository *repo, struct dir_struct *dir) | ||||
| { | ||||
| 	int i; | ||||
| 	struct strbuf fullname = STRBUF_INIT; | ||||
|  | ||||
| 	/* For cached/deleted files we don't need to even do the readdir */ | ||||
| 	if (show_others || show_killed) { | ||||
| 		if (!show_others) | ||||
| 			dir->flags |= DIR_COLLECT_KILLED_ONLY; | ||||
| 		fill_directory(dir, istate, &pathspec); | ||||
| 		fill_directory(dir, repo->index, &pathspec); | ||||
| 		if (show_others) | ||||
| 			show_other_files(istate, dir); | ||||
| 			show_other_files(repo->index, dir); | ||||
| 		if (show_killed) | ||||
| 			show_killed_files(istate, dir); | ||||
| 			show_killed_files(repo->index, dir); | ||||
| 	} | ||||
| 	if (show_cached || show_stage) { | ||||
| 		for (i = 0; i < istate->cache_nr; i++) { | ||||
| 			const struct cache_entry *ce = istate->cache[i]; | ||||
| 		for (i = 0; i < repo->index->cache_nr; i++) { | ||||
| 			const struct cache_entry *ce = repo->index->cache[i]; | ||||
|  | ||||
| 			construct_fullname(&fullname, repo, ce); | ||||
|  | ||||
| 			if ((dir->flags & DIR_SHOW_IGNORED) && | ||||
| 			    !ce_excluded(dir, istate, ce)) | ||||
| 			    !ce_excluded(dir, repo->index, fullname.buf, ce)) | ||||
| 				continue; | ||||
| 			if (show_unmerged && !ce_stage(ce)) | ||||
| 				continue; | ||||
| 			if (ce->ce_flags & CE_UPDATE) | ||||
| 				continue; | ||||
| 			show_ce_entry(istate, ce_stage(ce) ? tag_unmerged : | ||||
| 				(ce_skip_worktree(ce) ? tag_skip_worktree : tag_cached), ce); | ||||
| 			show_ce(repo, dir, ce, fullname.buf, | ||||
| 				ce_stage(ce) ? tag_unmerged : | ||||
| 				(ce_skip_worktree(ce) ? tag_skip_worktree : | ||||
| 				 tag_cached)); | ||||
| 		} | ||||
| 	} | ||||
| 	if (show_deleted || show_modified) { | ||||
| 		for (i = 0; i < istate->cache_nr; i++) { | ||||
| 			const struct cache_entry *ce = istate->cache[i]; | ||||
| 		for (i = 0; i < repo->index->cache_nr; i++) { | ||||
| 			const struct cache_entry *ce = repo->index->cache[i]; | ||||
| 			struct stat st; | ||||
| 			int err; | ||||
|  | ||||
| 			construct_fullname(&fullname, repo, ce); | ||||
|  | ||||
| 			if ((dir->flags & DIR_SHOW_IGNORED) && | ||||
| 			    !ce_excluded(dir, istate, ce)) | ||||
| 			    !ce_excluded(dir, repo->index, fullname.buf, ce)) | ||||
| 				continue; | ||||
| 			if (ce->ce_flags & CE_UPDATE) | ||||
| 				continue; | ||||
| 			if (ce_skip_worktree(ce)) | ||||
| 				continue; | ||||
| 			err = lstat(ce->name, &st); | ||||
| 			err = lstat(fullname.buf, &st); | ||||
| 			if (show_deleted && err) | ||||
| 				show_ce_entry(istate, tag_removed, ce); | ||||
| 			if (show_modified && ie_modified(istate, ce, &st, 0)) | ||||
| 				show_ce_entry(istate, tag_modified, ce); | ||||
| 				show_ce(repo, dir, ce, fullname.buf, tag_removed); | ||||
| 			if (show_modified && ie_modified(repo->index, ce, &st, 0)) | ||||
| 				show_ce(repo, dir, ce, fullname.buf, tag_modified); | ||||
| 		} | ||||
| 	} | ||||
|  | ||||
| 	strbuf_release(&fullname); | ||||
| } | ||||
|  | ||||
| /* | ||||
|  | @ -615,10 +575,9 @@ int cmd_ls_files(int argc, const char **argv, const char *cmd_prefix) | |||
| 	prefix = cmd_prefix; | ||||
| 	if (prefix) | ||||
| 		prefix_len = strlen(prefix); | ||||
| 	super_prefix = get_super_prefix(); | ||||
| 	git_config(git_default_config, NULL); | ||||
|  | ||||
| 	if (read_cache() < 0) | ||||
| 	if (repo_read_index(the_repository) < 0) | ||||
| 		die("index file corrupt"); | ||||
|  | ||||
| 	argc = parse_options(argc, argv, prefix, builtin_ls_files_options, | ||||
|  | @ -652,7 +611,7 @@ int cmd_ls_files(int argc, const char **argv, const char *cmd_prefix) | |||
| 		setup_work_tree(); | ||||
|  | ||||
| 	if (recurse_submodules) | ||||
| 		compile_submodule_options(argv, &dir, show_tag); | ||||
| 		repo_read_gitmodules(the_repository); | ||||
|  | ||||
| 	if (recurse_submodules && | ||||
| 	    (show_stage || show_deleted || show_others || show_unmerged || | ||||
|  | @ -670,7 +629,10 @@ int cmd_ls_files(int argc, const char **argv, const char *cmd_prefix) | |||
| 	/* | ||||
| 	 * Find common prefix for all pathspec's | ||||
| 	 * This is used as a performance optimization which unfortunately cannot | ||||
| 	 * be done when recursing into submodules | ||||
| 	 * be done when recursing into submodules because when a pathspec is | ||||
| 	 * given which spans repository boundaries you can't simply remove the | ||||
| 	 * submodule entry because the pathspec may match something inside the | ||||
| 	 * submodule. | ||||
| 	 */ | ||||
| 	if (recurse_submodules) | ||||
| 		max_prefix = NULL; | ||||
|  | @ -678,7 +640,7 @@ int cmd_ls_files(int argc, const char **argv, const char *cmd_prefix) | |||
| 		max_prefix = common_prefix(&pathspec); | ||||
| 	max_prefix_len = get_common_prefix_len(max_prefix); | ||||
|  | ||||
| 	prune_index(&the_index, max_prefix, max_prefix_len); | ||||
| 	prune_index(the_repository->index, max_prefix, max_prefix_len); | ||||
|  | ||||
| 	/* Treat unmatching pathspec elements as errors */ | ||||
| 	if (pathspec.nr && error_unmatch) | ||||
|  | @ -699,11 +661,13 @@ int cmd_ls_files(int argc, const char **argv, const char *cmd_prefix) | |||
| 		 */ | ||||
| 		if (show_stage || show_unmerged) | ||||
| 			die("ls-files --with-tree is incompatible with -s or -u"); | ||||
| 		overlay_tree_on_index(&the_index, with_tree, max_prefix); | ||||
| 		overlay_tree_on_index(the_repository->index, with_tree, max_prefix); | ||||
| 	} | ||||
| 	show_files(&the_index, &dir); | ||||
|  | ||||
| 	show_files(the_repository, &dir); | ||||
|  | ||||
| 	if (show_resolve_undo) | ||||
| 		show_ru_info(&the_index); | ||||
| 		show_ru_info(the_repository->index); | ||||
|  | ||||
| 	if (ps_matched) { | ||||
| 		int bad; | ||||
|  |  | |||
							
								
								
									
										2
									
								
								git.c
								
								
								
								
							
							
						
						
									
										2
									
								
								git.c
								
								
								
								
							|  | @ -400,7 +400,7 @@ static struct cmd_struct commands[] = { | |||
| 	{ "init-db", cmd_init_db }, | ||||
| 	{ "interpret-trailers", cmd_interpret_trailers, RUN_SETUP_GENTLY }, | ||||
| 	{ "log", cmd_log, RUN_SETUP }, | ||||
| 	{ "ls-files", cmd_ls_files, RUN_SETUP | SUPPORT_SUPER_PREFIX }, | ||||
| 	{ "ls-files", cmd_ls_files, RUN_SETUP }, | ||||
| 	{ "ls-remote", cmd_ls_remote, RUN_SETUP_GENTLY }, | ||||
| 	{ "ls-tree", cmd_ls_tree, RUN_SETUP }, | ||||
| 	{ "mailinfo", cmd_mailinfo, RUN_SETUP_GENTLY }, | ||||
|  |  | |||
|  | @ -135,6 +135,45 @@ test_expect_success '--recurse-submodules and pathspecs setup' ' | |||
| 	test_cmp expect actual | ||||
| ' | ||||
|  | ||||
| test_expect_success 'inactive submodule' ' | ||||
| 	test_when_finished "git config --bool submodule.submodule.active true" && | ||||
| 	test_when_finished "git -C submodule config --bool submodule.subsub.active true" && | ||||
| 	git config --bool submodule.submodule.active "false" && | ||||
|  | ||||
| 	cat >expect <<-\EOF && | ||||
| 	.gitmodules | ||||
| 	a | ||||
| 	b/b | ||||
| 	h.txt | ||||
| 	sib/file | ||||
| 	sub/file | ||||
| 	submodule | ||||
| 	EOF | ||||
|  | ||||
| 	git ls-files --recurse-submodules >actual && | ||||
| 	test_cmp expect actual && | ||||
|  | ||||
| 	git config --bool submodule.submodule.active "true" && | ||||
| 	git -C submodule config --bool submodule.subsub.active "false" && | ||||
|  | ||||
| 	cat >expect <<-\EOF && | ||||
| 	.gitmodules | ||||
| 	a | ||||
| 	b/b | ||||
| 	h.txt | ||||
| 	sib/file | ||||
| 	sub/file | ||||
| 	submodule/.gitmodules | ||||
| 	submodule/c | ||||
| 	submodule/f.TXT | ||||
| 	submodule/g.txt | ||||
| 	submodule/subsub | ||||
| 	EOF | ||||
|  | ||||
| 	git ls-files --recurse-submodules >actual && | ||||
| 	test_cmp expect actual | ||||
| ' | ||||
|  | ||||
| test_expect_success '--recurse-submodules and pathspecs' ' | ||||
| 	cat >expect <<-\EOF && | ||||
| 	h.txt | ||||
|  |  | |||
		Loading…
	
		Reference in New Issue
	
	 Brandon Williams
						Brandon Williams