Skip to content

Commit 188dce1

Browse files
bmwillgitster
authored andcommitted
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>
1 parent 96dc883 commit 188dce1

File tree

3 files changed

+118
-115
lines changed

3 files changed

+118
-115
lines changed

builtin/ls-files.c

Lines changed: 78 additions & 114 deletions
Original file line numberDiff line numberDiff line change
@@ -5,7 +5,9 @@
55
*
66
* Copyright (C) Linus Torvalds, 2005
77
*/
8+
#define NO_THE_INDEX_COMPATIBILITY_MACROS
89
#include "cache.h"
10+
#include "repository.h"
911
#include "config.h"
1012
#include "quote.h"
1113
#include "dir.h"
@@ -32,10 +34,8 @@ static int line_terminator = '\n';
3234
static int debug_mode;
3335
static int show_eol;
3436
static int recurse_submodules;
35-
static struct argv_array submodule_options = ARGV_ARRAY_INIT;
3637

3738
static const char *prefix;
38-
static const char *super_prefix;
3939
static int max_prefix_len;
4040
static int prefix_len;
4141
static struct pathspec pathspec;
@@ -73,25 +73,12 @@ static void write_eolinfo(const struct index_state *istate,
7373

7474
static void write_name(const char *name)
7575
{
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-
8776
/*
8877
* With "--full-name", prefix_len=0; this caller needs to pass
8978
* an empty string in that case (a NULL is good for "").
9079
*/
9180
write_name_quoted_relative(name, prefix_len ? prefix : NULL,
9281
stdout, line_terminator);
93-
94-
strbuf_release(&full_name);
9582
}
9683

9784
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,
210197
}
211198
}
212199

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);
238201

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)
243204
{
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);
271218
}
272219

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)
275223
{
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))
283225
die("git ls-files: internal error - cache entry not superset of prefix");
284226

285227
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,
290232
S_ISDIR(ce->ce_mode) ||
291233
S_ISGITLINK(ce->ce_mode))) {
292234
tag = get_tag(ce, tag);
@@ -300,12 +242,10 @@ static void show_ce_entry(const struct index_state *istate,
300242
find_unique_abbrev(ce->oid.hash, abbrev),
301243
ce_stage(ce));
302244
}
303-
write_eolinfo(istate, ce, ce->name);
304-
write_name(ce->name);
245+
write_eolinfo(repo->index, ce, fullname);
246+
write_name(fullname);
305247
print_debug(ce);
306248
}
307-
308-
strbuf_release(&name);
309249
}
310250

311251
static void show_ru_info(const struct index_state *istate)
@@ -338,59 +278,79 @@ static void show_ru_info(const struct index_state *istate)
338278
}
339279

340280
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)
342282
{
343283
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);
345294
}
346295

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)
348297
{
349298
int i;
299+
struct strbuf fullname = STRBUF_INIT;
350300

351301
/* For cached/deleted files we don't need to even do the readdir */
352302
if (show_others || show_killed) {
353303
if (!show_others)
354304
dir->flags |= DIR_COLLECT_KILLED_ONLY;
355-
fill_directory(dir, istate, &pathspec);
305+
fill_directory(dir, repo->index, &pathspec);
356306
if (show_others)
357-
show_other_files(istate, dir);
307+
show_other_files(repo->index, dir);
358308
if (show_killed)
359-
show_killed_files(istate, dir);
309+
show_killed_files(repo->index, dir);
360310
}
361311
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+
364317
if ((dir->flags & DIR_SHOW_IGNORED) &&
365-
!ce_excluded(dir, istate, ce))
318+
!ce_excluded(dir, repo->index, fullname.buf, ce))
366319
continue;
367320
if (show_unmerged && !ce_stage(ce))
368321
continue;
369322
if (ce->ce_flags & CE_UPDATE)
370323
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));
373328
}
374329
}
375330
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];
378333
struct stat st;
379334
int err;
335+
336+
construct_fullname(&fullname, repo, ce);
337+
380338
if ((dir->flags & DIR_SHOW_IGNORED) &&
381-
!ce_excluded(dir, istate, ce))
339+
!ce_excluded(dir, repo->index, fullname.buf, ce))
382340
continue;
383341
if (ce->ce_flags & CE_UPDATE)
384342
continue;
385343
if (ce_skip_worktree(ce))
386344
continue;
387-
err = lstat(ce->name, &st);
345+
err = lstat(fullname.buf, &st);
388346
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);
392350
}
393351
}
352+
353+
strbuf_release(&fullname);
394354
}
395355

396356
/*
@@ -615,10 +575,9 @@ int cmd_ls_files(int argc, const char **argv, const char *cmd_prefix)
615575
prefix = cmd_prefix;
616576
if (prefix)
617577
prefix_len = strlen(prefix);
618-
super_prefix = get_super_prefix();
619578
git_config(git_default_config, NULL);
620579

621-
if (read_cache() < 0)
580+
if (repo_read_index(the_repository) < 0)
622581
die("index file corrupt");
623582

624583
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)
652611
setup_work_tree();
653612

654613
if (recurse_submodules)
655-
compile_submodule_options(argv, &dir, show_tag);
614+
repo_read_gitmodules(the_repository);
656615

657616
if (recurse_submodules &&
658617
(show_stage || show_deleted || show_others || show_unmerged ||
@@ -670,15 +629,18 @@ int cmd_ls_files(int argc, const char **argv, const char *cmd_prefix)
670629
/*
671630
* Find common prefix for all pathspec's
672631
* 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.
674636
*/
675637
if (recurse_submodules)
676638
max_prefix = NULL;
677639
else
678640
max_prefix = common_prefix(&pathspec);
679641
max_prefix_len = get_common_prefix_len(max_prefix);
680642

681-
prune_index(&the_index, max_prefix, max_prefix_len);
643+
prune_index(the_repository->index, max_prefix, max_prefix_len);
682644

683645
/* Treat unmatching pathspec elements as errors */
684646
if (pathspec.nr && error_unmatch)
@@ -699,11 +661,13 @@ int cmd_ls_files(int argc, const char **argv, const char *cmd_prefix)
699661
*/
700662
if (show_stage || show_unmerged)
701663
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);
703665
}
704-
show_files(&the_index, &dir);
666+
667+
show_files(the_repository, &dir);
668+
705669
if (show_resolve_undo)
706-
show_ru_info(&the_index);
670+
show_ru_info(the_repository->index);
707671

708672
if (ps_matched) {
709673
int bad;

git.c

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -400,7 +400,7 @@ static struct cmd_struct commands[] = {
400400
{ "init-db", cmd_init_db },
401401
{ "interpret-trailers", cmd_interpret_trailers, RUN_SETUP_GENTLY },
402402
{ "log", cmd_log, RUN_SETUP },
403-
{ "ls-files", cmd_ls_files, RUN_SETUP | SUPPORT_SUPER_PREFIX },
403+
{ "ls-files", cmd_ls_files, RUN_SETUP },
404404
{ "ls-remote", cmd_ls_remote, RUN_SETUP_GENTLY },
405405
{ "ls-tree", cmd_ls_tree, RUN_SETUP },
406406
{ "mailinfo", cmd_mailinfo, RUN_SETUP_GENTLY },

t/t3007-ls-files-recurse-submodules.sh

Lines changed: 39 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -135,6 +135,45 @@ test_expect_success '--recurse-submodules and pathspecs setup' '
135135
test_cmp expect actual
136136
'
137137

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+
138177
test_expect_success '--recurse-submodules and pathspecs' '
139178
cat >expect <<-\EOF &&
140179
h.txt

0 commit comments

Comments
 (0)