@@ -439,6 +439,149 @@ static void for_each_listed_submodule(const struct module_list *list,
439
439
fn (list -> entries [i ], cb_data );
440
440
}
441
441
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
+
442
585
struct init_cb {
443
586
const char * prefix ;
444
587
unsigned int flags ;
@@ -1841,6 +1984,7 @@ static struct cmd_struct commands[] = {
1841
1984
{"relative-path" , resolve_relative_path , 0 },
1842
1985
{"resolve-relative-url" , resolve_relative_url , 0 },
1843
1986
{"resolve-relative-url-test" , resolve_relative_url_test , 0 },
1987
+ {"foreach" , module_foreach , SUPPORT_SUPER_PREFIX },
1844
1988
{"init" , module_init , SUPPORT_SUPER_PREFIX },
1845
1989
{"status" , module_status , SUPPORT_SUPER_PREFIX },
1846
1990
{"print-default-remote" , print_default_remote , 0 },
0 commit comments