@@ -439,6 +439,149 @@ static void for_each_listed_submodule(const struct module_list *list,
439439 fn (list -> entries [i ], cb_data );
440440}
441441
442+ struct cb_foreach {
443+ int argc ;
444+ const char * * argv ;
445+ const char * prefix ;
446+ int quiet ;
447+ int recursive ;
448+ };
449+ #define CB_FOREACH_INIT { 0 }
450+
451+ static void runcommand_in_submodule_cb (const struct cache_entry * list_item ,
452+ void * cb_data )
453+ {
454+ struct cb_foreach * info = cb_data ;
455+ const char * path = list_item -> name ;
456+ const struct object_id * ce_oid = & list_item -> oid ;
457+
458+ const struct submodule * sub ;
459+ struct child_process cp = CHILD_PROCESS_INIT ;
460+ char * displaypath ;
461+
462+ displaypath = get_submodule_displaypath (path , info -> prefix );
463+
464+ sub = submodule_from_path (the_repository , & null_oid , path );
465+
466+ if (!sub )
467+ die (_ ("No url found for submodule path '%s' in .gitmodules" ),
468+ displaypath );
469+
470+ if (!is_submodule_populated_gently (path , NULL ))
471+ goto cleanup ;
472+
473+ prepare_submodule_repo_env (& cp .env_array );
474+
475+ /*
476+ * For the purpose of executing <command> in the submodule,
477+ * separate shell is used for the purpose of running the
478+ * child process.
479+ */
480+ cp .use_shell = 1 ;
481+ cp .dir = path ;
482+
483+ /*
484+ * NEEDSWORK: the command currently has access to the variables $name,
485+ * $sm_path, $displaypath, $sha1 and $toplevel only when the command
486+ * contains a single argument. This is done for maintaining a faithful
487+ * translation from shell script.
488+ */
489+ if (info -> argc == 1 ) {
490+ char * toplevel = xgetcwd ();
491+ struct strbuf sb = STRBUF_INIT ;
492+
493+ argv_array_pushf (& cp .env_array , "name=%s" , sub -> name );
494+ argv_array_pushf (& cp .env_array , "sm_path=%s" , path );
495+ argv_array_pushf (& cp .env_array , "displaypath=%s" , displaypath );
496+ argv_array_pushf (& cp .env_array , "sha1=%s" ,
497+ oid_to_hex (ce_oid ));
498+ argv_array_pushf (& cp .env_array , "toplevel=%s" , toplevel );
499+
500+ /*
501+ * Since the path variable was accessible from the script
502+ * before porting, it is also made available after porting.
503+ * The environment variable "PATH" has a very special purpose
504+ * on windows. And since environment variables are
505+ * case-insensitive in windows, it interferes with the
506+ * existing PATH variable. Hence, to avoid that, we expose
507+ * path via the args argv_array and not via env_array.
508+ */
509+ sq_quote_buf (& sb , path );
510+ argv_array_pushf (& cp .args , "path=%s; %s" ,
511+ sb .buf , info -> argv [0 ]);
512+ strbuf_release (& sb );
513+ free (toplevel );
514+ } else {
515+ argv_array_pushv (& cp .args , info -> argv );
516+ }
517+
518+ if (!info -> quiet )
519+ printf (_ ("Entering '%s'\n" ), displaypath );
520+
521+ if (info -> argv [0 ] && run_command (& cp ))
522+ die (_ ("run_command returned non-zero status for %s\n." ),
523+ displaypath );
524+
525+ if (info -> recursive ) {
526+ struct child_process cpr = CHILD_PROCESS_INIT ;
527+
528+ cpr .git_cmd = 1 ;
529+ cpr .dir = path ;
530+ prepare_submodule_repo_env (& cpr .env_array );
531+
532+ argv_array_pushl (& cpr .args , "--super-prefix" , NULL );
533+ argv_array_pushf (& cpr .args , "%s/" , displaypath );
534+ argv_array_pushl (& cpr .args , "submodule--helper" , "foreach" , "--recursive" ,
535+ NULL );
536+
537+ if (info -> quiet )
538+ argv_array_push (& cpr .args , "--quiet" );
539+
540+ argv_array_pushv (& cpr .args , info -> argv );
541+
542+ if (run_command (& cpr ))
543+ die (_ ("run_command returned non-zero status while"
544+ "recursing in the nested submodules of %s\n." ),
545+ displaypath );
546+ }
547+
548+ cleanup :
549+ free (displaypath );
550+ }
551+
552+ static int module_foreach (int argc , const char * * argv , const char * prefix )
553+ {
554+ struct cb_foreach info = CB_FOREACH_INIT ;
555+ struct pathspec pathspec ;
556+ struct module_list list = MODULE_LIST_INIT ;
557+
558+ struct option module_foreach_options [] = {
559+ OPT__QUIET (& info .quiet , N_ ("Suppress output of entering each submodule command" )),
560+ OPT_BOOL (0 , "recursive" , & info .recursive ,
561+ N_ ("Recurse into nested submodules" )),
562+ OPT_END ()
563+ };
564+
565+ const char * const git_submodule_helper_usage [] = {
566+ N_ ("git submodule--helper foreach [--quiet] [--recursive] <command>" ),
567+ NULL
568+ };
569+
570+ argc = parse_options (argc , argv , prefix , module_foreach_options ,
571+ git_submodule_helper_usage , PARSE_OPT_KEEP_UNKNOWN );
572+
573+ if (module_list_compute (0 , NULL , prefix , & pathspec , & list ) < 0 )
574+ return 1 ;
575+
576+ info .argc = argc ;
577+ info .argv = argv ;
578+ info .prefix = prefix ;
579+
580+ for_each_listed_submodule (& list , runcommand_in_submodule_cb , & info );
581+
582+ return 0 ;
583+ }
584+
442585struct init_cb {
443586 const char * prefix ;
444587 unsigned int flags ;
@@ -1841,6 +1984,7 @@ static struct cmd_struct commands[] = {
18411984 {"relative-path" , resolve_relative_path , 0 },
18421985 {"resolve-relative-url" , resolve_relative_url , 0 },
18431986 {"resolve-relative-url-test" , resolve_relative_url_test , 0 },
1987+ {"foreach" , module_foreach , SUPPORT_SUPER_PREFIX },
18441988 {"init" , module_init , SUPPORT_SUPER_PREFIX },
18451989 {"status" , module_status , SUPPORT_SUPER_PREFIX },
18461990 {"print-default-remote" , print_default_remote , 0 },
0 commit comments