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