submodule: port submodule subcommand 'foreach' from shell to C
This aims to make git-submodule foreach a builtin. 'foreach' is ported to the submodule--helper, and submodule--helper is called from git-submodule.sh. Helped-by: Brandon Williams <bmwill@google.com> Mentored-by: Christian Couder <christian.couder@gmail.com> Mentored-by: Stefan Beller <sbeller@google.com> Signed-off-by: Prathamesh Chavan <pc44800@gmail.com> Signed-off-by: Stefan Beller <sbeller@google.com> Signed-off-by: Junio C Hamano <gitster@pobox.com>maint
							parent
							
								
									b6f7ac8fd5
								
							
						
					
					
						commit
						fc1b9243cd
					
				|  | @ -439,6 +439,149 @@ static void for_each_listed_submodule(const struct module_list *list, | |||
| 		fn(list->entries[i], cb_data); | ||||
| } | ||||
|  | ||||
| struct cb_foreach { | ||||
| 	int argc; | ||||
| 	const char **argv; | ||||
| 	const char *prefix; | ||||
| 	int quiet; | ||||
| 	int recursive; | ||||
| }; | ||||
| #define CB_FOREACH_INIT { 0 } | ||||
|  | ||||
| static void runcommand_in_submodule_cb(const struct cache_entry *list_item, | ||||
| 				       void *cb_data) | ||||
| { | ||||
| 	struct cb_foreach *info = cb_data; | ||||
| 	const char *path = list_item->name; | ||||
| 	const struct object_id *ce_oid = &list_item->oid; | ||||
|  | ||||
| 	const struct submodule *sub; | ||||
| 	struct child_process cp = CHILD_PROCESS_INIT; | ||||
| 	char *displaypath; | ||||
|  | ||||
| 	displaypath = get_submodule_displaypath(path, info->prefix); | ||||
|  | ||||
| 	sub = submodule_from_path(the_repository, &null_oid, path); | ||||
|  | ||||
| 	if (!sub) | ||||
| 		die(_("No url found for submodule path '%s' in .gitmodules"), | ||||
| 			displaypath); | ||||
|  | ||||
| 	if (!is_submodule_populated_gently(path, NULL)) | ||||
| 		goto cleanup; | ||||
|  | ||||
| 	prepare_submodule_repo_env(&cp.env_array); | ||||
|  | ||||
| 	/* | ||||
| 	 * For the purpose of executing <command> in the submodule, | ||||
| 	 * separate shell is used for the purpose of running the | ||||
| 	 * child process. | ||||
| 	 */ | ||||
| 	cp.use_shell = 1; | ||||
| 	cp.dir = path; | ||||
|  | ||||
| 	/* | ||||
| 	 * NEEDSWORK: the command currently has access to the variables $name, | ||||
| 	 * $sm_path, $displaypath, $sha1 and $toplevel only when the command | ||||
| 	 * contains a single argument. This is done for maintaining a faithful | ||||
| 	 * translation from shell script. | ||||
| 	 */ | ||||
| 	if (info->argc == 1) { | ||||
| 		char *toplevel = xgetcwd(); | ||||
| 		struct strbuf sb = STRBUF_INIT; | ||||
|  | ||||
| 		argv_array_pushf(&cp.env_array, "name=%s", sub->name); | ||||
| 		argv_array_pushf(&cp.env_array, "sm_path=%s", path); | ||||
| 		argv_array_pushf(&cp.env_array, "displaypath=%s", displaypath); | ||||
| 		argv_array_pushf(&cp.env_array, "sha1=%s", | ||||
| 				oid_to_hex(ce_oid)); | ||||
| 		argv_array_pushf(&cp.env_array, "toplevel=%s", toplevel); | ||||
|  | ||||
| 		/* | ||||
| 		 * Since the path variable was accessible from the script | ||||
| 		 * before porting, it is also made available after porting. | ||||
| 		 * The environment variable "PATH" has a very special purpose | ||||
| 		 * on windows. And since environment variables are | ||||
| 		 * case-insensitive in windows, it interferes with the | ||||
| 		 * existing PATH variable. Hence, to avoid that, we expose | ||||
| 		 * path via the args argv_array and not via env_array. | ||||
| 		 */ | ||||
| 		sq_quote_buf(&sb, path); | ||||
| 		argv_array_pushf(&cp.args, "path=%s; %s", | ||||
| 				 sb.buf, info->argv[0]); | ||||
| 		strbuf_release(&sb); | ||||
| 		free(toplevel); | ||||
| 	} else { | ||||
| 		argv_array_pushv(&cp.args, info->argv); | ||||
| 	} | ||||
|  | ||||
| 	if (!info->quiet) | ||||
| 		printf(_("Entering '%s'\n"), displaypath); | ||||
|  | ||||
| 	if (info->argv[0] && run_command(&cp)) | ||||
| 		die(_("run_command returned non-zero status for %s\n."), | ||||
| 			displaypath); | ||||
|  | ||||
| 	if (info->recursive) { | ||||
| 		struct child_process cpr = CHILD_PROCESS_INIT; | ||||
|  | ||||
| 		cpr.git_cmd = 1; | ||||
| 		cpr.dir = path; | ||||
| 		prepare_submodule_repo_env(&cpr.env_array); | ||||
|  | ||||
| 		argv_array_pushl(&cpr.args, "--super-prefix", NULL); | ||||
| 		argv_array_pushf(&cpr.args, "%s/", displaypath); | ||||
| 		argv_array_pushl(&cpr.args, "submodule--helper", "foreach", "--recursive", | ||||
| 				NULL); | ||||
|  | ||||
| 		if (info->quiet) | ||||
| 			argv_array_push(&cpr.args, "--quiet"); | ||||
|  | ||||
| 		argv_array_pushv(&cpr.args, info->argv); | ||||
|  | ||||
| 		if (run_command(&cpr)) | ||||
| 			die(_("run_command returned non-zero status while" | ||||
| 				"recursing in the nested submodules of %s\n."), | ||||
| 				displaypath); | ||||
| 	} | ||||
|  | ||||
| cleanup: | ||||
| 	free(displaypath); | ||||
| } | ||||
|  | ||||
| static int module_foreach(int argc, const char **argv, const char *prefix) | ||||
| { | ||||
| 	struct cb_foreach info = CB_FOREACH_INIT; | ||||
| 	struct pathspec pathspec; | ||||
| 	struct module_list list = MODULE_LIST_INIT; | ||||
|  | ||||
| 	struct option module_foreach_options[] = { | ||||
| 		OPT__QUIET(&info.quiet, N_("Suppress output of entering each submodule command")), | ||||
| 		OPT_BOOL(0, "recursive", &info.recursive, | ||||
| 			 N_("Recurse into nested submodules")), | ||||
| 		OPT_END() | ||||
| 	}; | ||||
|  | ||||
| 	const char *const git_submodule_helper_usage[] = { | ||||
| 		N_("git submodule--helper foreach [--quiet] [--recursive] <command>"), | ||||
| 		NULL | ||||
| 	}; | ||||
|  | ||||
| 	argc = parse_options(argc, argv, prefix, module_foreach_options, | ||||
| 			     git_submodule_helper_usage, PARSE_OPT_KEEP_UNKNOWN); | ||||
|  | ||||
| 	if (module_list_compute(0, NULL, prefix, &pathspec, &list) < 0) | ||||
| 		return 1; | ||||
|  | ||||
| 	info.argc = argc; | ||||
| 	info.argv = argv; | ||||
| 	info.prefix = prefix; | ||||
|  | ||||
| 	for_each_listed_submodule(&list, runcommand_in_submodule_cb, &info); | ||||
|  | ||||
| 	return 0; | ||||
| } | ||||
|  | ||||
| struct init_cb { | ||||
| 	const char *prefix; | ||||
| 	unsigned int flags; | ||||
|  | @ -1841,6 +1984,7 @@ static struct cmd_struct commands[] = { | |||
| 	{"relative-path", resolve_relative_path, 0}, | ||||
| 	{"resolve-relative-url", resolve_relative_url, 0}, | ||||
| 	{"resolve-relative-url-test", resolve_relative_url_test, 0}, | ||||
| 	{"foreach", module_foreach, SUPPORT_SUPER_PREFIX}, | ||||
| 	{"init", module_init, SUPPORT_SUPER_PREFIX}, | ||||
| 	{"status", module_status, SUPPORT_SUPER_PREFIX}, | ||||
| 	{"print-default-remote", print_default_remote, 0}, | ||||
|  |  | |||
|  | @ -323,44 +323,7 @@ cmd_foreach() | |||
| 		shift | ||||
| 	done | ||||
|  | ||||
| 	toplevel=$(pwd) | ||||
|  | ||||
| 	# dup stdin so that it can be restored when running the external | ||||
| 	# command in the subshell (and a recursive call to this function) | ||||
| 	exec 3<&0 | ||||
|  | ||||
| 	{ | ||||
| 		git submodule--helper list --prefix "$wt_prefix" || | ||||
| 		echo "#unmatched" $? | ||||
| 	} | | ||||
| 	while read -r mode sha1 stage sm_path | ||||
| 	do | ||||
| 		die_if_unmatched "$mode" "$sha1" | ||||
| 		if test -e "$sm_path"/.git | ||||
| 		then | ||||
| 			displaypath=$(git submodule--helper relative-path "$prefix$sm_path" "$wt_prefix") | ||||
| 			say "$(eval_gettext "Entering '\$displaypath'")" | ||||
| 			name=$(git submodule--helper name "$sm_path") | ||||
| 			( | ||||
| 				prefix="$prefix$sm_path/" | ||||
| 				sanitize_submodule_env | ||||
| 				cd "$sm_path" && | ||||
| 				# we make $path available to scripts ... | ||||
| 				path=$sm_path && | ||||
| 				if test $# -eq 1 | ||||
| 				then | ||||
| 					eval "$1" | ||||
| 				else | ||||
| 					"$@" | ||||
| 				fi && | ||||
| 				if test -n "$recursive" | ||||
| 				then | ||||
| 					cmd_foreach "--recursive" "$@" | ||||
| 				fi | ||||
| 			) <&3 3<&- || | ||||
| 			die "$(eval_gettext "Stopping at '\$displaypath'; script returned non-zero status.")" | ||||
| 		fi | ||||
| 	done | ||||
| 	git ${wt_prefix:+-C "$wt_prefix"} ${prefix:+--super-prefix "$prefix"} submodule--helper foreach ${GIT_QUIET:+--quiet} ${recursive:+--recursive} "$@" | ||||
| } | ||||
|  | ||||
| # | ||||
|  |  | |||
		Loading…
	
		Reference in New Issue
	
	 Prathamesh Chavan
						Prathamesh Chavan