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 |  * Copyright (C) Linus Torvalds, 2005 | ||||||
|  */ |  */ | ||||||
|  | #define NO_THE_INDEX_COMPATIBILITY_MACROS | ||||||
| #include "cache.h" | #include "cache.h" | ||||||
|  | #include "repository.h" | ||||||
| #include "config.h" | #include "config.h" | ||||||
| #include "quote.h" | #include "quote.h" | ||||||
| #include "dir.h" | #include "dir.h" | ||||||
|  | @ -32,10 +34,8 @@ static int line_terminator = '\n'; | ||||||
| static int debug_mode; | static int debug_mode; | ||||||
| static int show_eol; | static int show_eol; | ||||||
| static int recurse_submodules; | static int recurse_submodules; | ||||||
| static struct argv_array submodule_options = ARGV_ARRAY_INIT; |  | ||||||
|  |  | ||||||
| static const char *prefix; | static const char *prefix; | ||||||
| static const char *super_prefix; |  | ||||||
| static int max_prefix_len; | static int max_prefix_len; | ||||||
| static int prefix_len; | static int prefix_len; | ||||||
| static struct pathspec pathspec; | static struct pathspec pathspec; | ||||||
|  | @ -73,25 +73,12 @@ static void write_eolinfo(const struct index_state *istate, | ||||||
|  |  | ||||||
| static void write_name(const char *name) | 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 | 	 * With "--full-name", prefix_len=0; this caller needs to pass | ||||||
| 	 * an empty string in that case (a NULL is good for ""). | 	 * an empty string in that case (a NULL is good for ""). | ||||||
| 	 */ | 	 */ | ||||||
| 	write_name_quoted_relative(name, prefix_len ? prefix : NULL, | 	write_name_quoted_relative(name, prefix_len ? prefix : NULL, | ||||||
| 				   stdout, line_terminator); | 				   stdout, line_terminator); | ||||||
|  |  | ||||||
| 	strbuf_release(&full_name); |  | ||||||
| } | } | ||||||
|  |  | ||||||
| static const char *get_tag(const struct cache_entry *ce, const char *tag) | 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, | ||||||
| 	} | 	} | ||||||
| } | } | ||||||
|  |  | ||||||
| /* | static void show_files(struct repository *repo, struct dir_struct *dir); | ||||||
|  * 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"); |  | ||||||
|  |  | ||||||
| 	/* Add Pathspecs */ | static void show_submodule(struct repository *superproject, | ||||||
| 	argv_array_push(&submodule_options, "--"); | 			   struct dir_struct *dir, const char *path) | ||||||
| 	for (; *argv; argv++) | { | ||||||
| 		argv_array_push(&submodule_options, *argv); | 	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); | ||||||
| } | } | ||||||
|  |  | ||||||
| /** | static void show_ce(struct repository *repo, struct dir_struct *dir, | ||||||
|  * Recursively call ls-files on a submodule | 		    const struct cache_entry *ce, const char *fullname, | ||||||
|  */ | 		    const char *tag) | ||||||
| static void show_gitlink(const struct cache_entry *ce) |  | ||||||
| { | { | ||||||
| 	struct child_process cp = CHILD_PROCESS_INIT; | 	if (max_prefix_len > strlen(fullname)) | ||||||
| 	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)) |  | ||||||
| 		die("git ls-files: internal error - cache entry not superset of prefix"); | 		die("git ls-files: internal error - cache entry not superset of prefix"); | ||||||
|  |  | ||||||
| 	if (recurse_submodules && S_ISGITLINK(ce->ce_mode) && | 	if (recurse_submodules && S_ISGITLINK(ce->ce_mode) && | ||||||
| 	    submodule_path_match(&pathspec, name.buf, ps_matched)) { | 	    is_submodule_active(repo, ce->name)) { | ||||||
| 		show_gitlink(ce); | 		show_submodule(repo, dir, ce->name); | ||||||
| 	} else if (match_pathspec(&pathspec, name.buf, name.len, | 	} else if (match_pathspec(&pathspec, fullname, strlen(fullname), | ||||||
| 				  len, ps_matched, | 				  max_prefix_len, ps_matched, | ||||||
| 				  S_ISDIR(ce->ce_mode) || | 				  S_ISDIR(ce->ce_mode) || | ||||||
| 				  S_ISGITLINK(ce->ce_mode))) { | 				  S_ISGITLINK(ce->ce_mode))) { | ||||||
| 		tag = get_tag(ce, tag); | 		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), | 			       find_unique_abbrev(ce->oid.hash, abbrev), | ||||||
| 			       ce_stage(ce)); | 			       ce_stage(ce)); | ||||||
| 		} | 		} | ||||||
| 		write_eolinfo(istate, ce, ce->name); | 		write_eolinfo(repo->index, ce, fullname); | ||||||
| 		write_name(ce->name); | 		write_name(fullname); | ||||||
| 		print_debug(ce); | 		print_debug(ce); | ||||||
| 	} | 	} | ||||||
|  |  | ||||||
| 	strbuf_release(&name); |  | ||||||
| } | } | ||||||
|  |  | ||||||
| static void show_ru_info(const struct index_state *istate) | 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, | 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); | 	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; | 	int i; | ||||||
|  | 	struct strbuf fullname = STRBUF_INIT; | ||||||
|  |  | ||||||
| 	/* For cached/deleted files we don't need to even do the readdir */ | 	/* For cached/deleted files we don't need to even do the readdir */ | ||||||
| 	if (show_others || show_killed) { | 	if (show_others || show_killed) { | ||||||
| 		if (!show_others) | 		if (!show_others) | ||||||
| 			dir->flags |= DIR_COLLECT_KILLED_ONLY; | 			dir->flags |= DIR_COLLECT_KILLED_ONLY; | ||||||
| 		fill_directory(dir, istate, &pathspec); | 		fill_directory(dir, repo->index, &pathspec); | ||||||
| 		if (show_others) | 		if (show_others) | ||||||
| 			show_other_files(istate, dir); | 			show_other_files(repo->index, dir); | ||||||
| 		if (show_killed) | 		if (show_killed) | ||||||
| 			show_killed_files(istate, dir); | 			show_killed_files(repo->index, dir); | ||||||
| 	} | 	} | ||||||
| 	if (show_cached || show_stage) { | 	if (show_cached || show_stage) { | ||||||
| 		for (i = 0; i < istate->cache_nr; i++) { | 		for (i = 0; i < repo->index->cache_nr; i++) { | ||||||
| 			const struct cache_entry *ce = istate->cache[i]; | 			const struct cache_entry *ce = repo->index->cache[i]; | ||||||
|  |  | ||||||
|  | 			construct_fullname(&fullname, repo, ce); | ||||||
|  |  | ||||||
| 			if ((dir->flags & DIR_SHOW_IGNORED) && | 			if ((dir->flags & DIR_SHOW_IGNORED) && | ||||||
| 			    !ce_excluded(dir, istate, ce)) | 			    !ce_excluded(dir, repo->index, fullname.buf, ce)) | ||||||
| 				continue; | 				continue; | ||||||
| 			if (show_unmerged && !ce_stage(ce)) | 			if (show_unmerged && !ce_stage(ce)) | ||||||
| 				continue; | 				continue; | ||||||
| 			if (ce->ce_flags & CE_UPDATE) | 			if (ce->ce_flags & CE_UPDATE) | ||||||
| 				continue; | 				continue; | ||||||
| 			show_ce_entry(istate, ce_stage(ce) ? tag_unmerged : | 			show_ce(repo, dir, ce, fullname.buf, | ||||||
| 				(ce_skip_worktree(ce) ? tag_skip_worktree : tag_cached), ce); | 				ce_stage(ce) ? tag_unmerged : | ||||||
|  | 				(ce_skip_worktree(ce) ? tag_skip_worktree : | ||||||
|  | 				 tag_cached)); | ||||||
| 		} | 		} | ||||||
| 	} | 	} | ||||||
| 	if (show_deleted || show_modified) { | 	if (show_deleted || show_modified) { | ||||||
| 		for (i = 0; i < istate->cache_nr; i++) { | 		for (i = 0; i < repo->index->cache_nr; i++) { | ||||||
| 			const struct cache_entry *ce = istate->cache[i]; | 			const struct cache_entry *ce = repo->index->cache[i]; | ||||||
| 			struct stat st; | 			struct stat st; | ||||||
| 			int err; | 			int err; | ||||||
|  |  | ||||||
|  | 			construct_fullname(&fullname, repo, ce); | ||||||
|  |  | ||||||
| 			if ((dir->flags & DIR_SHOW_IGNORED) && | 			if ((dir->flags & DIR_SHOW_IGNORED) && | ||||||
| 			    !ce_excluded(dir, istate, ce)) | 			    !ce_excluded(dir, repo->index, fullname.buf, ce)) | ||||||
| 				continue; | 				continue; | ||||||
| 			if (ce->ce_flags & CE_UPDATE) | 			if (ce->ce_flags & CE_UPDATE) | ||||||
| 				continue; | 				continue; | ||||||
| 			if (ce_skip_worktree(ce)) | 			if (ce_skip_worktree(ce)) | ||||||
| 				continue; | 				continue; | ||||||
| 			err = lstat(ce->name, &st); | 			err = lstat(fullname.buf, &st); | ||||||
| 			if (show_deleted && err) | 			if (show_deleted && err) | ||||||
| 				show_ce_entry(istate, tag_removed, ce); | 				show_ce(repo, dir, ce, fullname.buf, tag_removed); | ||||||
| 			if (show_modified && ie_modified(istate, ce, &st, 0)) | 			if (show_modified && ie_modified(repo->index, ce, &st, 0)) | ||||||
| 				show_ce_entry(istate, tag_modified, ce); | 				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; | 	prefix = cmd_prefix; | ||||||
| 	if (prefix) | 	if (prefix) | ||||||
| 		prefix_len = strlen(prefix); | 		prefix_len = strlen(prefix); | ||||||
| 	super_prefix = get_super_prefix(); |  | ||||||
| 	git_config(git_default_config, NULL); | 	git_config(git_default_config, NULL); | ||||||
|  |  | ||||||
| 	if (read_cache() < 0) | 	if (repo_read_index(the_repository) < 0) | ||||||
| 		die("index file corrupt"); | 		die("index file corrupt"); | ||||||
|  |  | ||||||
| 	argc = parse_options(argc, argv, prefix, builtin_ls_files_options, | 	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(); | 		setup_work_tree(); | ||||||
|  |  | ||||||
| 	if (recurse_submodules) | 	if (recurse_submodules) | ||||||
| 		compile_submodule_options(argv, &dir, show_tag); | 		repo_read_gitmodules(the_repository); | ||||||
|  |  | ||||||
| 	if (recurse_submodules && | 	if (recurse_submodules && | ||||||
| 	    (show_stage || show_deleted || show_others || show_unmerged || | 	    (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 | 	 * Find common prefix for all pathspec's | ||||||
| 	 * This is used as a performance optimization which unfortunately cannot | 	 * 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) | 	if (recurse_submodules) | ||||||
| 		max_prefix = NULL; | 		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 = common_prefix(&pathspec); | ||||||
| 	max_prefix_len = get_common_prefix_len(max_prefix); | 	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 */ | 	/* Treat unmatching pathspec elements as errors */ | ||||||
| 	if (pathspec.nr && error_unmatch) | 	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) | 		if (show_stage || show_unmerged) | ||||||
| 			die("ls-files --with-tree is incompatible with -s or -u"); | 			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) | 	if (show_resolve_undo) | ||||||
| 		show_ru_info(&the_index); | 		show_ru_info(the_repository->index); | ||||||
|  |  | ||||||
| 	if (ps_matched) { | 	if (ps_matched) { | ||||||
| 		int bad; | 		int bad; | ||||||
|  |  | ||||||
							
								
								
									
										2
									
								
								git.c
								
								
								
								
							
							
						
						
									
										2
									
								
								git.c
								
								
								
								
							|  | @ -400,7 +400,7 @@ static struct cmd_struct commands[] = { | ||||||
| 	{ "init-db", cmd_init_db }, | 	{ "init-db", cmd_init_db }, | ||||||
| 	{ "interpret-trailers", cmd_interpret_trailers, RUN_SETUP_GENTLY }, | 	{ "interpret-trailers", cmd_interpret_trailers, RUN_SETUP_GENTLY }, | ||||||
| 	{ "log", cmd_log, RUN_SETUP }, | 	{ "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-remote", cmd_ls_remote, RUN_SETUP_GENTLY }, | ||||||
| 	{ "ls-tree", cmd_ls_tree, RUN_SETUP }, | 	{ "ls-tree", cmd_ls_tree, RUN_SETUP }, | ||||||
| 	{ "mailinfo", cmd_mailinfo, RUN_SETUP_GENTLY }, | 	{ "mailinfo", cmd_mailinfo, RUN_SETUP_GENTLY }, | ||||||
|  |  | ||||||
|  | @ -135,6 +135,45 @@ test_expect_success '--recurse-submodules and pathspecs setup' ' | ||||||
| 	test_cmp expect actual | 	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' ' | test_expect_success '--recurse-submodules and pathspecs' ' | ||||||
| 	cat >expect <<-\EOF && | 	cat >expect <<-\EOF && | ||||||
| 	h.txt | 	h.txt | ||||||
|  |  | ||||||
		Loading…
	
		Reference in New Issue
	
	 Brandon Williams
						Brandon Williams