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,6 +29,8 @@ 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 const char * submodule_prefix ;
33
+ static int recurse_submodules ;
31
34
32
35
static const char * prefix ;
33
36
static int max_prefix_len ;
@@ -67,6 +70,21 @@ static void write_eolinfo(const struct cache_entry *ce, const char *path)
67
70
68
71
static void write_name (const char * name )
69
72
{
73
+ /*
74
+ * NEEDSWORK: To make this thread-safe, full_name would have to be owned
75
+ * by the caller.
76
+ *
77
+ * full_name get reused across output lines to minimize the allocation
78
+ * churn.
79
+ */
80
+ static struct strbuf full_name = STRBUF_INIT ;
81
+ if (submodule_prefix && * submodule_prefix ) {
82
+ strbuf_reset (& full_name );
83
+ strbuf_addstr (& full_name , submodule_prefix );
84
+ strbuf_addstr (& full_name , name );
85
+ name = full_name .buf ;
86
+ }
87
+
70
88
/*
71
89
* With "--full-name", prefix_len=0; this caller needs to pass
72
90
* an empty string in that case (a NULL is good for "").
@@ -152,55 +170,106 @@ static void show_killed_files(struct dir_struct *dir)
152
170
}
153
171
}
154
172
173
+ /**
174
+ * Recursively call ls-files on a submodule
175
+ */
176
+ static void show_gitlink (const struct cache_entry * ce )
177
+ {
178
+ struct child_process cp = CHILD_PROCESS_INIT ;
179
+ int status ;
180
+ int i ;
181
+
182
+ argv_array_push (& cp .args , "ls-files" );
183
+ argv_array_push (& cp .args , "--recurse-submodules" );
184
+ argv_array_pushf (& cp .args , "--submodule-prefix=%s%s/" ,
185
+ submodule_prefix ? submodule_prefix : "" ,
186
+ ce -> name );
187
+ /* add options */
188
+ if (show_eol )
189
+ argv_array_push (& cp .args , "--eol" );
190
+ if (show_valid_bit )
191
+ argv_array_push (& cp .args , "-v" );
192
+ if (show_stage )
193
+ argv_array_push (& cp .args , "--stage" );
194
+ if (show_cached )
195
+ argv_array_push (& cp .args , "--cached" );
196
+ if (debug_mode )
197
+ argv_array_push (& cp .args , "--debug" );
198
+
199
+ /*
200
+ * Pass in the original pathspec args. The submodule will be
201
+ * responsible for prepending the 'submodule_prefix' prior to comparing
202
+ * against the pathspec for matches.
203
+ */
204
+ argv_array_push (& cp .args , "--" );
205
+ for (i = 0 ; i < pathspec .nr ; i ++ )
206
+ argv_array_push (& cp .args , pathspec .items [i ].original );
207
+
208
+ cp .git_cmd = 1 ;
209
+ cp .dir = ce -> name ;
210
+ status = run_command (& cp );
211
+ if (status )
212
+ exit (status );
213
+ }
214
+
155
215
static void show_ce_entry (const char * tag , const struct cache_entry * ce )
156
216
{
217
+ struct strbuf name = STRBUF_INIT ;
157
218
int len = max_prefix_len ;
219
+ if (submodule_prefix )
220
+ strbuf_addstr (& name , submodule_prefix );
221
+ strbuf_addstr (& name , ce -> name );
158
222
159
223
if (len >= ce_namelen (ce ))
160
224
die ("git ls-files: internal error - cache entry not superset of prefix" );
161
225
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 ;
226
+ if (recurse_submodules && S_ISGITLINK (ce -> ce_mode ) &&
227
+ submodule_path_match (& pathspec , name .buf , ps_matched )) {
228
+ show_gitlink (ce );
229
+ } else if (match_pathspec (& pathspec , name .buf , name .len ,
230
+ len , ps_matched ,
231
+ S_ISDIR (ce -> ce_mode ) ||
232
+ S_ISGITLINK (ce -> ce_mode ))) {
233
+ if (tag && * tag && show_valid_bit &&
234
+ (ce -> ce_flags & CE_VALID )) {
235
+ static char alttag [4 ];
236
+ memcpy (alttag , tag , 3 );
237
+ if (isalpha (tag [0 ]))
238
+ alttag [0 ] = tolower (tag [0 ]);
239
+ else if (tag [0 ] == '?' )
240
+ alttag [0 ] = '!' ;
241
+ else {
242
+ alttag [0 ] = 'v' ;
243
+ alttag [1 ] = tag [0 ];
244
+ alttag [2 ] = ' ' ;
245
+ alttag [3 ] = 0 ;
246
+ }
247
+ tag = alttag ;
248
+ }
166
249
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 ;
250
+ if (!show_stage ) {
251
+ fputs (tag , stdout );
252
+ } else {
253
+ printf ("%s%06o %s %d\t" ,
254
+ tag ,
255
+ ce -> ce_mode ,
256
+ find_unique_abbrev (ce -> oid .hash , abbrev ),
257
+ ce_stage (ce ));
258
+ }
259
+ write_eolinfo (ce , ce -> name );
260
+ write_name (ce -> name );
261
+ if (debug_mode ) {
262
+ const struct stat_data * sd = & ce -> ce_stat_data ;
263
+
264
+ printf (" ctime: %d:%d\n" , sd -> sd_ctime .sec , sd -> sd_ctime .nsec );
265
+ printf (" mtime: %d:%d\n" , sd -> sd_mtime .sec , sd -> sd_mtime .nsec );
266
+ printf (" dev: %d\tino: %d\n" , sd -> sd_dev , sd -> sd_ino );
267
+ printf (" uid: %d\tgid: %d\n" , sd -> sd_uid , sd -> sd_gid );
268
+ printf (" size: %d\tflags: %x\n" , sd -> sd_size , ce -> ce_flags );
180
269
}
181
- tag = alttag ;
182
270
}
183
271
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
- }
272
+ strbuf_release (& name );
204
273
}
205
274
206
275
static void show_ru_info (void )
@@ -468,6 +537,10 @@ int cmd_ls_files(int argc, const char **argv, const char *cmd_prefix)
468
537
{ OPTION_SET_INT , 0 , "full-name" , & prefix_len , NULL ,
469
538
N_ ("make the output relative to the project top directory" ),
470
539
PARSE_OPT_NOARG | PARSE_OPT_NONEG , NULL },
540
+ OPT_STRING (0 , "submodule-prefix" , & submodule_prefix ,
541
+ N_ ("path" ), N_ ("prepend <path> to each file" )),
542
+ OPT_BOOL (0 , "recurse-submodules" , & recurse_submodules ,
543
+ N_ ("recurse through submodules" )),
471
544
OPT_BOOL (0 , "error-unmatch" , & error_unmatch ,
472
545
N_ ("if any <file> is not in the index, treat this as an error" )),
473
546
OPT_STRING (0 , "with-tree" , & with_tree , N_ ("tree-ish" ),
@@ -519,13 +592,29 @@ int cmd_ls_files(int argc, const char **argv, const char *cmd_prefix)
519
592
if (require_work_tree && !is_inside_work_tree ())
520
593
setup_work_tree ();
521
594
595
+ if (recurse_submodules &&
596
+ (show_deleted || show_others || show_unmerged ||
597
+ show_killed || show_modified || show_resolve_undo ))
598
+ die ("ls-files --recurse-submodules unsupported mode" );
599
+
600
+ if (recurse_submodules && error_unmatch )
601
+ die ("ls-files --recurse-submodules does not support "
602
+ "--error-unmatch" );
603
+
522
604
parse_pathspec (& pathspec , 0 ,
523
605
PATHSPEC_PREFER_CWD |
524
606
PATHSPEC_STRIP_SUBMODULE_SLASH_CHEAP ,
525
607
prefix , argv );
526
608
527
- /* Find common prefix for all pathspec's */
528
- max_prefix = common_prefix (& pathspec );
609
+ /*
610
+ * Find common prefix for all pathspec's
611
+ * This is used as a performance optimization which unfortunately cannot
612
+ * be done when recursing into submodules
613
+ */
614
+ if (recurse_submodules )
615
+ max_prefix = NULL ;
616
+ else
617
+ max_prefix = common_prefix (& pathspec );
529
618
max_prefix_len = max_prefix ? strlen (max_prefix ) : 0 ;
530
619
531
620
/* Treat unmatching pathspec elements as errors */
0 commit comments