1414#include "resolve-undo.h"
1515#include "string-list.h"
1616#include "pathspec.h"
17+ #include "run-command.h"
1718
1819static int abbrev ;
1920static int show_deleted ;
@@ -28,8 +29,11 @@ static int show_valid_bit;
2829static int line_terminator = '\n' ;
2930static int debug_mode ;
3031static int show_eol ;
32+ static int recurse_submodules ;
33+ static struct argv_array submodules_options = ARGV_ARRAY_INIT ;
3134
3235static const char * prefix ;
36+ static const char * super_prefix ;
3337static int max_prefix_len ;
3438static int prefix_len ;
3539static struct pathspec pathspec ;
@@ -67,12 +71,25 @@ static void write_eolinfo(const struct cache_entry *ce, const char *path)
6771
6872static void write_name (const char * name )
6973{
74+ /*
75+ * Prepend the super_prefix to name to construct the full_name to be
76+ * written.
77+ */
78+ struct strbuf full_name = STRBUF_INIT ;
79+ if (super_prefix ) {
80+ strbuf_addstr (& full_name , super_prefix );
81+ strbuf_addstr (& full_name , name );
82+ name = full_name .buf ;
83+ }
84+
7085 /*
7186 * With "--full-name", prefix_len=0; this caller needs to pass
7287 * an empty string in that case (a NULL is good for "").
7388 */
7489 write_name_quoted_relative (name , prefix_len ? prefix : NULL ,
7590 stdout , line_terminator );
91+
92+ strbuf_release (& full_name );
7693}
7794
7895static void show_dir_entry (const char * tag , struct dir_entry * ent )
@@ -152,55 +169,117 @@ static void show_killed_files(struct dir_struct *dir)
152169 }
153170}
154171
172+ /*
173+ * Compile an argv_array with all of the options supported by --recurse_submodules
174+ */
175+ static void compile_submodule_options (const struct dir_struct * dir , int show_tag )
176+ {
177+ if (line_terminator == '\0' )
178+ argv_array_push (& submodules_options , "-z" );
179+ if (show_tag )
180+ argv_array_push (& submodules_options , "-t" );
181+ if (show_valid_bit )
182+ argv_array_push (& submodules_options , "-v" );
183+ if (show_cached )
184+ argv_array_push (& submodules_options , "--cached" );
185+ if (show_eol )
186+ argv_array_push (& submodules_options , "--eol" );
187+ if (debug_mode )
188+ argv_array_push (& submodules_options , "--debug" );
189+ }
190+
191+ /**
192+ * Recursively call ls-files on a submodule
193+ */
194+ static void show_gitlink (const struct cache_entry * ce )
195+ {
196+ struct child_process cp = CHILD_PROCESS_INIT ;
197+ int status ;
198+ int i ;
199+
200+ argv_array_pushf (& cp .args , "--super-prefix=%s%s/" ,
201+ super_prefix ? super_prefix : "" ,
202+ ce -> name );
203+ argv_array_push (& cp .args , "ls-files" );
204+ argv_array_push (& cp .args , "--recurse-submodules" );
205+
206+ /* add supported options */
207+ argv_array_pushv (& cp .args , submodules_options .argv );
208+
209+ /*
210+ * Pass in the original pathspec args. The submodule will be
211+ * responsible for prepending the 'submodule_prefix' prior to comparing
212+ * against the pathspec for matches.
213+ */
214+ argv_array_push (& cp .args , "--" );
215+ for (i = 0 ; i < pathspec .nr ; i ++ )
216+ argv_array_push (& cp .args , pathspec .items [i ].original );
217+
218+ cp .git_cmd = 1 ;
219+ cp .dir = ce -> name ;
220+ status = run_command (& cp );
221+ if (status )
222+ exit (status );
223+ }
224+
155225static void show_ce_entry (const char * tag , const struct cache_entry * ce )
156226{
227+ struct strbuf name = STRBUF_INIT ;
157228 int len = max_prefix_len ;
229+ if (super_prefix )
230+ strbuf_addstr (& name , super_prefix );
231+ strbuf_addstr (& name , ce -> name );
158232
159233 if (len >= ce_namelen (ce ))
160234 die ("git ls-files: internal error - cache entry not superset of prefix" );
161235
162- if (!match_pathspec (& pathspec , ce -> name , ce_namelen (ce ),
163- len , ps_matched ,
164- S_ISDIR (ce -> ce_mode ) || S_ISGITLINK (ce -> ce_mode )))
165- return ;
236+ if (recurse_submodules && S_ISGITLINK (ce -> ce_mode ) &&
237+ submodule_path_match (& pathspec , name .buf , ps_matched )) {
238+ show_gitlink (ce );
239+ } else if (match_pathspec (& pathspec , name .buf , name .len ,
240+ len , ps_matched ,
241+ S_ISDIR (ce -> ce_mode ) ||
242+ S_ISGITLINK (ce -> ce_mode ))) {
243+ if (tag && * tag && show_valid_bit &&
244+ (ce -> ce_flags & CE_VALID )) {
245+ static char alttag [4 ];
246+ memcpy (alttag , tag , 3 );
247+ if (isalpha (tag [0 ]))
248+ alttag [0 ] = tolower (tag [0 ]);
249+ else if (tag [0 ] == '?' )
250+ alttag [0 ] = '!' ;
251+ else {
252+ alttag [0 ] = 'v' ;
253+ alttag [1 ] = tag [0 ];
254+ alttag [2 ] = ' ' ;
255+ alttag [3 ] = 0 ;
256+ }
257+ tag = alttag ;
258+ }
166259
167- if (tag && * tag && show_valid_bit &&
168- (ce -> ce_flags & CE_VALID )) {
169- static char alttag [4 ];
170- memcpy (alttag , tag , 3 );
171- if (isalpha (tag [0 ]))
172- alttag [0 ] = tolower (tag [0 ]);
173- else if (tag [0 ] == '?' )
174- alttag [0 ] = '!' ;
175- else {
176- alttag [0 ] = 'v' ;
177- alttag [1 ] = tag [0 ];
178- alttag [2 ] = ' ' ;
179- alttag [3 ] = 0 ;
260+ if (!show_stage ) {
261+ fputs (tag , stdout );
262+ } else {
263+ printf ("%s%06o %s %d\t" ,
264+ tag ,
265+ ce -> ce_mode ,
266+ find_unique_abbrev (ce -> oid .hash , abbrev ),
267+ ce_stage (ce ));
268+ }
269+ write_eolinfo (ce , ce -> name );
270+ write_name (ce -> name );
271+ if (debug_mode ) {
272+ const struct stat_data * sd = & ce -> ce_stat_data ;
273+
274+ printf (" ctime: %d:%d\n" , sd -> sd_ctime .sec , sd -> sd_ctime .nsec );
275+ printf (" mtime: %d:%d\n" , sd -> sd_mtime .sec , sd -> sd_mtime .nsec );
276+ printf (" dev: %d\tino: %d\n" , sd -> sd_dev , sd -> sd_ino );
277+ printf (" uid: %d\tgid: %d\n" , sd -> sd_uid , sd -> sd_gid );
278+ printf (" size: %d\tflags: %x\n" , sd -> sd_size , ce -> ce_flags );
180279 }
181- tag = alttag ;
182280 }
183281
184- if (!show_stage ) {
185- fputs (tag , stdout );
186- } else {
187- printf ("%s%06o %s %d\t" ,
188- tag ,
189- ce -> ce_mode ,
190- find_unique_abbrev (ce -> oid .hash ,abbrev ),
191- ce_stage (ce ));
192- }
193- write_eolinfo (ce , ce -> name );
194- write_name (ce -> name );
195- if (debug_mode ) {
196- const struct stat_data * sd = & ce -> ce_stat_data ;
197-
198- printf (" ctime: %d:%d\n" , sd -> sd_ctime .sec , sd -> sd_ctime .nsec );
199- printf (" mtime: %d:%d\n" , sd -> sd_mtime .sec , sd -> sd_mtime .nsec );
200- printf (" dev: %d\tino: %d\n" , sd -> sd_dev , sd -> sd_ino );
201- printf (" uid: %d\tgid: %d\n" , sd -> sd_uid , sd -> sd_gid );
202- printf (" size: %d\tflags: %x\n" , sd -> sd_size , ce -> ce_flags );
203- }
282+ strbuf_release (& name );
204283}
205284
206285static void show_ru_info (void )
@@ -468,6 +547,8 @@ int cmd_ls_files(int argc, const char **argv, const char *cmd_prefix)
468547 { OPTION_SET_INT , 0 , "full-name" , & prefix_len , NULL ,
469548 N_ ("make the output relative to the project top directory" ),
470549 PARSE_OPT_NOARG | PARSE_OPT_NONEG , NULL },
550+ OPT_BOOL (0 , "recurse-submodules" , & recurse_submodules ,
551+ N_ ("recurse through submodules" )),
471552 OPT_BOOL (0 , "error-unmatch" , & error_unmatch ,
472553 N_ ("if any <file> is not in the index, treat this as an error" )),
473554 OPT_STRING (0 , "with-tree" , & with_tree , N_ ("tree-ish" ),
@@ -484,6 +565,7 @@ int cmd_ls_files(int argc, const char **argv, const char *cmd_prefix)
484565 prefix = cmd_prefix ;
485566 if (prefix )
486567 prefix_len = strlen (prefix );
568+ super_prefix = get_super_prefix ();
487569 git_config (git_default_config , NULL );
488570
489571 if (read_cache () < 0 )
@@ -519,13 +601,32 @@ int cmd_ls_files(int argc, const char **argv, const char *cmd_prefix)
519601 if (require_work_tree && !is_inside_work_tree ())
520602 setup_work_tree ();
521603
604+ if (recurse_submodules )
605+ compile_submodule_options (& dir , show_tag );
606+
607+ if (recurse_submodules &&
608+ (show_stage || show_deleted || show_others || show_unmerged ||
609+ show_killed || show_modified || show_resolve_undo || with_tree ))
610+ die ("ls-files --recurse-submodules unsupported mode" );
611+
612+ if (recurse_submodules && error_unmatch )
613+ die ("ls-files --recurse-submodules does not support "
614+ "--error-unmatch" );
615+
522616 parse_pathspec (& pathspec , 0 ,
523617 PATHSPEC_PREFER_CWD |
524618 PATHSPEC_STRIP_SUBMODULE_SLASH_CHEAP ,
525619 prefix , argv );
526620
527- /* Find common prefix for all pathspec's */
528- max_prefix = common_prefix (& pathspec );
621+ /*
622+ * Find common prefix for all pathspec's
623+ * This is used as a performance optimization which unfortunately cannot
624+ * be done when recursing into submodules
625+ */
626+ if (recurse_submodules )
627+ max_prefix = NULL ;
628+ else
629+ max_prefix = common_prefix (& pathspec );
529630 max_prefix_len = max_prefix ? strlen (max_prefix ) : 0 ;
530631
531632 /* Treat unmatching pathspec elements as errors */
0 commit comments