ls-files: use repository object
Convert ls-files to use a repository struct and recurse submodules inprocess. Signed-off-by: Brandon Williams <bmwill@google.com> Signed-off-by: Junio C Hamano <gitster@pobox.com>
Brandon Williams committed
Jun 22, 2017 at 11:43 UTC
188dce131fa95d85ddc024a1bc7d2b7fc5da4424
3 files changed
+118
-115
builtin/ls-files.c
+78
-114
@@ -5,7 +5,9 @@
5
*
6
* Copyright (C) Linus Torvalds, 2005
7
*/
8
+#define NO_THE_INDEX_COMPATIBILITY_MACROS
9
#include "cache.h"
10
+#include "repository.h"
11
#include "config.h"
12
#include "quote.h"
13
#include "dir.h"
@@ -32,10 +34,8 @@ static int line_terminator = '\n';
34
static int debug_mode;
35
static int show_eol;
36
static int recurse_submodules;
35
-static struct argv_array submodule_options = ARGV_ARRAY_INIT;
37
38
static const char *prefix;
38
-static const char *super_prefix;
39
static int max_prefix_len;
40
static int prefix_len;
41
static struct pathspec pathspec;
@@ -73,25 +73,12 @@ static void write_eolinfo(const struct index_state *istate,
73
74
static void write_name(const char *name)
75
{
76
- /*
77
- * Prepend the super_prefix to name to construct the full_name to be
78
- * written.
79
- */
80
- struct strbuf full_name = STRBUF_INIT;
81
- if (super_prefix) {
82
- strbuf_addstr(&full_name, super_prefix);
83
- strbuf_addstr(&full_name, name);
84
- name = full_name.buf;
85
- }
86
-
76
/*
77
* With "--full-name", prefix_len=0; this caller needs to pass
78
* an empty string in that case (a NULL is good for "").
79
*/
80
write_name_quoted_relative(name, prefix_len ? prefix : NULL,
81
stdout, line_terminator);
93
-
94
- strbuf_release(&full_name);
82
}
83
84
static const char *get_tag(const struct cache_entry *ce, const char *tag)
@@ -210,83 +197,38 @@ static void show_killed_files(const struct index_state *istate,
197
}
198
}
199
213
-/*
214
- * Compile an argv_array with all of the options supported by --recurse_submodules
215
- */
216
-static void compile_submodule_options(const char **argv,
217
- const struct dir_struct *dir,
218
- int show_tag)
219
-{
220
- if (line_terminator == '\0')
221
- argv_array_push(&submodule_options, "-z");
222
- if (show_tag)
223
- argv_array_push(&submodule_options, "-t");
224
- if (show_valid_bit)
225
- argv_array_push(&submodule_options, "-v");
226
- if (show_cached)
227
- argv_array_push(&submodule_options, "--cached");
228
- if (show_eol)
229
- argv_array_push(&submodule_options, "--eol");
230
- if (debug_mode)
231
- argv_array_push(&submodule_options, "--debug");
232
-
233
- /* Add Pathspecs */
234
- argv_array_push(&submodule_options, "--");
235
- for (; *argv; argv++)
236
- argv_array_push(&submodule_options, *argv);
237
-}
200
+static void show_files(struct repository *repo, struct dir_struct *dir);
201
239
-/**
240
- * Recursively call ls-files on a submodule
241
- */
242
-static void show_gitlink(const struct cache_entry *ce)
202
+static void show_submodule(struct repository *superproject,
203
+ struct dir_struct *dir, const char *path)
204
{
244
- struct child_process cp = CHILD_PROCESS_INIT;
245
- int status;
246
- char *dir;
247
-
248
- prepare_submodule_repo_env(&cp.env_array);
249
- argv_array_push(&cp.env_array, GIT_DIR_ENVIRONMENT);
250
-
251
- if (prefix_len)
252
- argv_array_pushf(&cp.env_array, "%s=%s",
253
- GIT_TOPLEVEL_PREFIX_ENVIRONMENT,
254
- prefix);
255
- argv_array_pushf(&cp.args, "--super-prefix=%s%s/",
256
- super_prefix ? super_prefix : "",
257
- ce->name);
258
- argv_array_push(&cp.args, "ls-files");
259
- argv_array_push(&cp.args, "--recurse-submodules");
260
-
261
- /* add supported options */
262
- argv_array_pushv(&cp.args, submodule_options.argv);
263
-
264
- cp.git_cmd = 1;
265
- dir = mkpathdup("%s/%s", get_git_work_tree(), ce->name);
266
- cp.dir = dir;
267
- status = run_command(&cp);
268
- free(dir);
269
- if (status)
270
- exit(status);
205
+ struct repository submodule;
206
+
207
+ if (repo_submodule_init(&submodule, superproject, path))
208
+ return;
209
+
210
+ if (repo_read_index(&submodule) < 0)
211
+ die("index file corrupt");
212
+
213
+ repo_read_gitmodules(&submodule);
214
+
215
+ show_files(&submodule, dir);
216
+
217
+ repo_clear(&submodule);
218
}
219
273
-static void show_ce_entry(const struct index_state *istate,
274
- const char *tag, const struct cache_entry *ce)
220
+static void show_ce(struct repository *repo, struct dir_struct *dir,
221
+ const struct cache_entry *ce, const char *fullname,
222
+ const char *tag)
223
{
276
- struct strbuf name = STRBUF_INIT;
277
- int len = max_prefix_len;
278
- if (super_prefix)
279
- strbuf_addstr(&name, super_prefix);
280
- strbuf_addstr(&name, ce->name);
281
-
282
- if (len > ce_namelen(ce))
224
+ if (max_prefix_len > strlen(fullname))
225
die("git ls-files: internal error - cache entry not superset of prefix");
226
227
if (recurse_submodules && S_ISGITLINK(ce->ce_mode) &&
286
- submodule_path_match(&pathspec, name.buf, ps_matched)) {
287
- show_gitlink(ce);
288
- } else if (match_pathspec(&pathspec, name.buf, name.len,
289
- len, ps_matched,
228
+ is_submodule_active(repo, ce->name)) {
229
+ show_submodule(repo, dir, ce->name);
230
+ } else if (match_pathspec(&pathspec, fullname, strlen(fullname),
231
+ max_prefix_len, ps_matched,
232
S_ISDIR(ce->ce_mode) ||
233
S_ISGITLINK(ce->ce_mode))) {
234
tag = get_tag(ce, tag);
@@ -300,12 +242,10 @@ static void show_ce_entry(const struct index_state *istate,
242
find_unique_abbrev(ce->oid.hash, abbrev),
243
ce_stage(ce));
244
}
303
- write_eolinfo(istate, ce, ce->name);
304
- write_name(ce->name);
245
+ write_eolinfo(repo->index, ce, fullname);
246
+ write_name(fullname);
247
print_debug(ce);
248
}
307
-
308
- strbuf_release(&name);
249
}
250
251
static void show_ru_info(const struct index_state *istate)
@@ -338,59 +278,79 @@ static void show_ru_info(const struct index_state *istate)
278
}
279
280
static int ce_excluded(struct dir_struct *dir, struct index_state *istate,
341
- const struct cache_entry *ce)
281
+ const char *fullname, const struct cache_entry *ce)
282
{
283
int dtype = ce_to_dtype(ce);
344
- return is_excluded(dir, istate, ce->name, &dtype);
284
+ return is_excluded(dir, istate, fullname, &dtype);
285
+}
286
+
287
+static void construct_fullname(struct strbuf *out, const struct repository *repo,
288
+ const struct cache_entry *ce)
289
+{
290
+ strbuf_reset(out);
291
+ if (repo->submodule_prefix)
292
+ strbuf_addstr(out, repo->submodule_prefix);
293
+ strbuf_addstr(out, ce->name);
294
}
295
347
-static void show_files(struct index_state *istate, struct dir_struct *dir)
296
+static void show_files(struct repository *repo, struct dir_struct *dir)
297
{
298
int i;
299
+ struct strbuf fullname = STRBUF_INIT;
300
301
/* For cached/deleted files we don't need to even do the readdir */
302
if (show_others || show_killed) {
303
if (!show_others)
304
dir->flags |= DIR_COLLECT_KILLED_ONLY;
355
- fill_directory(dir, istate, &pathspec);
305
+ fill_directory(dir, repo->index, &pathspec);
306
if (show_others)
357
- show_other_files(istate, dir);
307
+ show_other_files(repo->index, dir);
308
if (show_killed)
359
- show_killed_files(istate, dir);
309
+ show_killed_files(repo->index, dir);
310
}
311
if (show_cached || show_stage) {
362
- for (i = 0; i < istate->cache_nr; i++) {
363
- const struct cache_entry *ce = istate->cache[i];
312
+ for (i = 0; i < repo->index->cache_nr; i++) {
313
+ const struct cache_entry *ce = repo->index->cache[i];
314
+
315
+ construct_fullname(&fullname, repo, ce);
316
+
317
if ((dir->flags & DIR_SHOW_IGNORED) &&
365
- !ce_excluded(dir, istate, ce))
318
+ !ce_excluded(dir, repo->index, fullname.buf, ce))
319
continue;
320
if (show_unmerged && !ce_stage(ce))
321
continue;
322
if (ce->ce_flags & CE_UPDATE)
323
continue;
371
- show_ce_entry(istate, ce_stage(ce) ? tag_unmerged :
372
- (ce_skip_worktree(ce) ? tag_skip_worktree : tag_cached), ce);
324
+ show_ce(repo, dir, ce, fullname.buf,
325
+ ce_stage(ce) ? tag_unmerged :
326
+ (ce_skip_worktree(ce) ? tag_skip_worktree :
327
+ tag_cached));
328
}
329
}
330
if (show_deleted || show_modified) {
376
- for (i = 0; i < istate->cache_nr; i++) {
377
- const struct cache_entry *ce = istate->cache[i];
331
+ for (i = 0; i < repo->index->cache_nr; i++) {
332
+ const struct cache_entry *ce = repo->index->cache[i];
333
struct stat st;
334
int err;
335
+
336
+ construct_fullname(&fullname, repo, ce);
337
+
338
if ((dir->flags & DIR_SHOW_IGNORED) &&
381
- !ce_excluded(dir, istate, ce))
339
+ !ce_excluded(dir, repo->index, fullname.buf, ce))
340
continue;
341
if (ce->ce_flags & CE_UPDATE)
342
continue;
343
if (ce_skip_worktree(ce))
344
continue;
387
- err = lstat(ce->name, &st);
345
+ err = lstat(fullname.buf, &st);
346
if (show_deleted && err)
389
- show_ce_entry(istate, tag_removed, ce);
390
- if (show_modified && ie_modified(istate, ce, &st, 0))
391
- show_ce_entry(istate, tag_modified, ce);
347
+ show_ce(repo, dir, ce, fullname.buf, tag_removed);
348
+ if (show_modified && ie_modified(repo->index, ce, &st, 0))
349
+ show_ce(repo, dir, ce, fullname.buf, tag_modified);
350
}
351
}
352
+
353
+ strbuf_release(&fullname);
354
}
355
356
/*
@@ -615,10 +575,9 @@ int cmd_ls_files(int argc, const char **argv, const char *cmd_prefix)
575
prefix = cmd_prefix;
576
if (prefix)
577
prefix_len = strlen(prefix);
618
- super_prefix = get_super_prefix();
578
git_config(git_default_config, NULL);
579
621
- if (read_cache() < 0)
580
+ if (repo_read_index(the_repository) < 0)
581
die("index file corrupt");
582
583
argc = parse_options(argc, argv, prefix, builtin_ls_files_options,
@@ -652,7 +611,7 @@ int cmd_ls_files(int argc, const char **argv, const char *cmd_prefix)
611
setup_work_tree();
612
613
if (recurse_submodules)
655
- compile_submodule_options(argv, &dir, show_tag);
614
+ repo_read_gitmodules(the_repository);
615
616
if (recurse_submodules &&
617
(show_stage || show_deleted || show_others || show_unmerged ||
@@ -670,7 +629,10 @@ int cmd_ls_files(int argc, const char **argv, const char *cmd_prefix)
629
/*
630
* Find common prefix for all pathspec's
631
* This is used as a performance optimization which unfortunately cannot
673
- * be done when recursing into submodules
632
+ * be done when recursing into submodules because when a pathspec is
633
+ * given which spans repository boundaries you can't simply remove the
634
+ * submodule entry because the pathspec may match something inside the
635
+ * submodule.
636
*/
637
if (recurse_submodules)
638
max_prefix = NULL;
@@ -678,7 +640,7 @@ int cmd_ls_files(int argc, const char **argv, const char *cmd_prefix)
640
max_prefix = common_prefix(&pathspec);
641
max_prefix_len = get_common_prefix_len(max_prefix);
642
681
- prune_index(&the_index, max_prefix, max_prefix_len);
643
+ prune_index(the_repository->index, max_prefix, max_prefix_len);
644
645
/* Treat unmatching pathspec elements as errors */
646
if (pathspec.nr && error_unmatch)
@@ -699,11 +661,13 @@ int cmd_ls_files(int argc, const char **argv, const char *cmd_prefix)
661
*/
662
if (show_stage || show_unmerged)
663
die("ls-files --with-tree is incompatible with -s or -u");
702
- overlay_tree_on_index(&the_index, with_tree, max_prefix);
664
+ overlay_tree_on_index(the_repository->index, with_tree, max_prefix);
665
}
704
- show_files(&the_index, &dir);
666
+
667
+ show_files(the_repository, &dir);
668
+
669
if (show_resolve_undo)
706
- show_ru_info(&the_index);
670
+ show_ru_info(the_repository->index);
671
672
if (ps_matched) {
673
int bad;
git.c
+1
-1
@@ -400,7 +400,7 @@ static struct cmd_struct commands[] = {
400
{ "init-db", cmd_init_db },
401
{ "interpret-trailers", cmd_interpret_trailers, RUN_SETUP_GENTLY },
402
{ "log", cmd_log, RUN_SETUP },
403
- { "ls-files", cmd_ls_files, RUN_SETUP | SUPPORT_SUPER_PREFIX },
403
+ { "ls-files", cmd_ls_files, RUN_SETUP },
404
{ "ls-remote", cmd_ls_remote, RUN_SETUP_GENTLY },
405
{ "ls-tree", cmd_ls_tree, RUN_SETUP },
406
{ "mailinfo", cmd_mailinfo, RUN_SETUP_GENTLY },
t/t3007-ls-files-recurse-submodules.sh
+39
@@ -135,6 +135,45 @@ test_expect_success '--recurse-submodules and pathspecs setup' '
135
test_cmp expect actual
136
'
137
138
+test_expect_success 'inactive submodule' '
139
+ test_when_finished "git config --bool submodule.submodule.active true" &&
140
+ test_when_finished "git -C submodule config --bool submodule.subsub.active true" &&
141
+ git config --bool submodule.submodule.active "false" &&
142
+
143
+ cat >expect <<-\EOF &&
144
+ .gitmodules
145
+ a
146
+ b/b
147
+ h.txt
148
+ sib/file
149
+ sub/file
150
+ submodule
151
+ EOF
152
+
153
+ git ls-files --recurse-submodules >actual &&
154
+ test_cmp expect actual &&
155
+
156
+ git config --bool submodule.submodule.active "true" &&
157
+ git -C submodule config --bool submodule.subsub.active "false" &&
158
+
159
+ cat >expect <<-\EOF &&
160
+ .gitmodules
161
+ a
162
+ b/b
163
+ h.txt
164
+ sib/file
165
+ sub/file
166
+ submodule/.gitmodules
167
+ submodule/c
168
+ submodule/f.TXT
169
+ submodule/g.txt
170
+ submodule/subsub
171
+ EOF
172
+
173
+ git ls-files --recurse-submodules >actual &&
174
+ test_cmp expect actual
175
+'
176
+
177
test_expect_success '--recurse-submodules and pathspecs' '
178
cat >expect <<-\EOF &&
179
h.txt