14
14
#include "resolve-undo.h"
15
15
#include "string-list.h"
16
16
#include "pathspec.h"
17
+ #include "run-command.h"
17
18
18
19
static int abbrev ;
19
20
static int show_deleted ;
@@ -28,8 +29,11 @@ static int show_valid_bit;
28
29
static int line_terminator = '\n' ;
29
30
static int debug_mode ;
30
31
static int show_eol ;
32
+ static int recurse_submodules ;
33
+ static struct argv_array submodules_options = ARGV_ARRAY_INIT ;
31
34
32
35
static const char * prefix ;
36
+ static const char * super_prefix ;
33
37
static int max_prefix_len ;
34
38
static int prefix_len ;
35
39
static struct pathspec pathspec ;
@@ -67,12 +71,25 @@ static void write_eolinfo(const struct cache_entry *ce, const char *path)
67
71
68
72
static void write_name (const char * name )
69
73
{
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
+
70
85
/*
71
86
* With "--full-name", prefix_len=0; this caller needs to pass
72
87
* an empty string in that case (a NULL is good for "").
73
88
*/
74
89
write_name_quoted_relative (name , prefix_len ? prefix : NULL ,
75
90
stdout , line_terminator );
91
+
92
+ strbuf_release (& full_name );
76
93
}
77
94
78
95
static void show_dir_entry (const char * tag , struct dir_entry * ent )
@@ -152,55 +169,117 @@ static void show_killed_files(struct dir_struct *dir)
152
169
}
153
170
}
154
171
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
+
155
225
static void show_ce_entry (const char * tag , const struct cache_entry * ce )
156
226
{
227
+ struct strbuf name = STRBUF_INIT ;
157
228
int len = max_prefix_len ;
229
+ if (super_prefix )
230
+ strbuf_addstr (& name , super_prefix );
231
+ strbuf_addstr (& name , ce -> name );
158
232
159
233
if (len >= ce_namelen (ce ))
160
234
die ("git ls-files: internal error - cache entry not superset of prefix" );
161
235
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
+ }
166
259
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 );
180
279
}
181
- tag = alttag ;
182
280
}
183
281
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 );
204
283
}
205
284
206
285
static void show_ru_info (void )
@@ -468,6 +547,8 @@ int cmd_ls_files(int argc, const char **argv, const char *cmd_prefix)
468
547
{ OPTION_SET_INT , 0 , "full-name" , & prefix_len , NULL ,
469
548
N_ ("make the output relative to the project top directory" ),
470
549
PARSE_OPT_NOARG | PARSE_OPT_NONEG , NULL },
550
+ OPT_BOOL (0 , "recurse-submodules" , & recurse_submodules ,
551
+ N_ ("recurse through submodules" )),
471
552
OPT_BOOL (0 , "error-unmatch" , & error_unmatch ,
472
553
N_ ("if any <file> is not in the index, treat this as an error" )),
473
554
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)
484
565
prefix = cmd_prefix ;
485
566
if (prefix )
486
567
prefix_len = strlen (prefix );
568
+ super_prefix = get_super_prefix ();
487
569
git_config (git_default_config , NULL );
488
570
489
571
if (read_cache () < 0 )
@@ -519,13 +601,32 @@ int cmd_ls_files(int argc, const char **argv, const char *cmd_prefix)
519
601
if (require_work_tree && !is_inside_work_tree ())
520
602
setup_work_tree ();
521
603
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
+
522
616
parse_pathspec (& pathspec , 0 ,
523
617
PATHSPEC_PREFER_CWD |
524
618
PATHSPEC_STRIP_SUBMODULE_SLASH_CHEAP ,
525
619
prefix , argv );
526
620
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 );
529
630
max_prefix_len = max_prefix ? strlen (max_prefix ) : 0 ;
530
631
531
632
/* Treat unmatching pathspec elements as errors */
0 commit comments