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>
This commit is contained in:
parent
96dc883b3c
commit
188dce131f
@ -5,7 +5,9 @@
|
|||||||
*
|
*
|
||||||
* Copyright (C) Linus Torvalds, 2005
|
* Copyright (C) Linus Torvalds, 2005
|
||||||
*/
|
*/
|
||||||
|
#define NO_THE_INDEX_COMPATIBILITY_MACROS
|
||||||
#include "cache.h"
|
#include "cache.h"
|
||||||
|
#include "repository.h"
|
||||||
#include "config.h"
|
#include "config.h"
|
||||||
#include "quote.h"
|
#include "quote.h"
|
||||||
#include "dir.h"
|
#include "dir.h"
|
||||||
@ -32,10 +34,8 @@ static int line_terminator = '\n';
|
|||||||
static int debug_mode;
|
static int debug_mode;
|
||||||
static int show_eol;
|
static int show_eol;
|
||||||
static int recurse_submodules;
|
static int recurse_submodules;
|
||||||
static struct argv_array submodule_options = ARGV_ARRAY_INIT;
|
|
||||||
|
|
||||||
static const char *prefix;
|
static const char *prefix;
|
||||||
static const char *super_prefix;
|
|
||||||
static int max_prefix_len;
|
static int max_prefix_len;
|
||||||
static int prefix_len;
|
static int prefix_len;
|
||||||
static struct pathspec pathspec;
|
static struct pathspec pathspec;
|
||||||
@ -73,25 +73,12 @@ static void write_eolinfo(const struct index_state *istate,
|
|||||||
|
|
||||||
static void write_name(const char *name)
|
static void write_name(const char *name)
|
||||||
{
|
{
|
||||||
/*
|
|
||||||
* Prepend the super_prefix to name to construct the full_name to be
|
|
||||||
* written.
|
|
||||||
*/
|
|
||||||
struct strbuf full_name = STRBUF_INIT;
|
|
||||||
if (super_prefix) {
|
|
||||||
strbuf_addstr(&full_name, super_prefix);
|
|
||||||
strbuf_addstr(&full_name, name);
|
|
||||||
name = full_name.buf;
|
|
||||||
}
|
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* With "--full-name", prefix_len=0; this caller needs to pass
|
* With "--full-name", prefix_len=0; this caller needs to pass
|
||||||
* an empty string in that case (a NULL is good for "").
|
* an empty string in that case (a NULL is good for "").
|
||||||
*/
|
*/
|
||||||
write_name_quoted_relative(name, prefix_len ? prefix : NULL,
|
write_name_quoted_relative(name, prefix_len ? prefix : NULL,
|
||||||
stdout, line_terminator);
|
stdout, line_terminator);
|
||||||
|
|
||||||
strbuf_release(&full_name);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
static const char *get_tag(const struct cache_entry *ce, const char *tag)
|
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,
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/*
|
static void show_files(struct repository *repo, struct dir_struct *dir);
|
||||||
* Compile an argv_array with all of the options supported by --recurse_submodules
|
|
||||||
*/
|
|
||||||
static void compile_submodule_options(const char **argv,
|
|
||||||
const struct dir_struct *dir,
|
|
||||||
int show_tag)
|
|
||||||
{
|
|
||||||
if (line_terminator == '\0')
|
|
||||||
argv_array_push(&submodule_options, "-z");
|
|
||||||
if (show_tag)
|
|
||||||
argv_array_push(&submodule_options, "-t");
|
|
||||||
if (show_valid_bit)
|
|
||||||
argv_array_push(&submodule_options, "-v");
|
|
||||||
if (show_cached)
|
|
||||||
argv_array_push(&submodule_options, "--cached");
|
|
||||||
if (show_eol)
|
|
||||||
argv_array_push(&submodule_options, "--eol");
|
|
||||||
if (debug_mode)
|
|
||||||
argv_array_push(&submodule_options, "--debug");
|
|
||||||
|
|
||||||
/* Add Pathspecs */
|
static void show_submodule(struct repository *superproject,
|
||||||
argv_array_push(&submodule_options, "--");
|
struct dir_struct *dir, const char *path)
|
||||||
for (; *argv; argv++)
|
{
|
||||||
argv_array_push(&submodule_options, *argv);
|
struct repository submodule;
|
||||||
|
|
||||||
|
if (repo_submodule_init(&submodule, superproject, path))
|
||||||
|
return;
|
||||||
|
|
||||||
|
if (repo_read_index(&submodule) < 0)
|
||||||
|
die("index file corrupt");
|
||||||
|
|
||||||
|
repo_read_gitmodules(&submodule);
|
||||||
|
|
||||||
|
show_files(&submodule, dir);
|
||||||
|
|
||||||
|
repo_clear(&submodule);
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
static void show_ce(struct repository *repo, struct dir_struct *dir,
|
||||||
* Recursively call ls-files on a submodule
|
const struct cache_entry *ce, const char *fullname,
|
||||||
*/
|
const char *tag)
|
||||||
static void show_gitlink(const struct cache_entry *ce)
|
|
||||||
{
|
{
|
||||||
struct child_process cp = CHILD_PROCESS_INIT;
|
if (max_prefix_len > strlen(fullname))
|
||||||
int status;
|
|
||||||
char *dir;
|
|
||||||
|
|
||||||
prepare_submodule_repo_env(&cp.env_array);
|
|
||||||
argv_array_push(&cp.env_array, GIT_DIR_ENVIRONMENT);
|
|
||||||
|
|
||||||
if (prefix_len)
|
|
||||||
argv_array_pushf(&cp.env_array, "%s=%s",
|
|
||||||
GIT_TOPLEVEL_PREFIX_ENVIRONMENT,
|
|
||||||
prefix);
|
|
||||||
argv_array_pushf(&cp.args, "--super-prefix=%s%s/",
|
|
||||||
super_prefix ? super_prefix : "",
|
|
||||||
ce->name);
|
|
||||||
argv_array_push(&cp.args, "ls-files");
|
|
||||||
argv_array_push(&cp.args, "--recurse-submodules");
|
|
||||||
|
|
||||||
/* add supported options */
|
|
||||||
argv_array_pushv(&cp.args, submodule_options.argv);
|
|
||||||
|
|
||||||
cp.git_cmd = 1;
|
|
||||||
dir = mkpathdup("%s/%s", get_git_work_tree(), ce->name);
|
|
||||||
cp.dir = dir;
|
|
||||||
status = run_command(&cp);
|
|
||||||
free(dir);
|
|
||||||
if (status)
|
|
||||||
exit(status);
|
|
||||||
}
|
|
||||||
|
|
||||||
static void show_ce_entry(const struct index_state *istate,
|
|
||||||
const char *tag, const struct cache_entry *ce)
|
|
||||||
{
|
|
||||||
struct strbuf name = STRBUF_INIT;
|
|
||||||
int len = max_prefix_len;
|
|
||||||
if (super_prefix)
|
|
||||||
strbuf_addstr(&name, super_prefix);
|
|
||||||
strbuf_addstr(&name, ce->name);
|
|
||||||
|
|
||||||
if (len > ce_namelen(ce))
|
|
||||||
die("git ls-files: internal error - cache entry not superset of prefix");
|
die("git ls-files: internal error - cache entry not superset of prefix");
|
||||||
|
|
||||||
if (recurse_submodules && S_ISGITLINK(ce->ce_mode) &&
|
if (recurse_submodules && S_ISGITLINK(ce->ce_mode) &&
|
||||||
submodule_path_match(&pathspec, name.buf, ps_matched)) {
|
is_submodule_active(repo, ce->name)) {
|
||||||
show_gitlink(ce);
|
show_submodule(repo, dir, ce->name);
|
||||||
} else if (match_pathspec(&pathspec, name.buf, name.len,
|
} else if (match_pathspec(&pathspec, fullname, strlen(fullname),
|
||||||
len, ps_matched,
|
max_prefix_len, ps_matched,
|
||||||
S_ISDIR(ce->ce_mode) ||
|
S_ISDIR(ce->ce_mode) ||
|
||||||
S_ISGITLINK(ce->ce_mode))) {
|
S_ISGITLINK(ce->ce_mode))) {
|
||||||
tag = get_tag(ce, tag);
|
tag = get_tag(ce, tag);
|
||||||
@ -300,12 +242,10 @@ static void show_ce_entry(const struct index_state *istate,
|
|||||||
find_unique_abbrev(ce->oid.hash, abbrev),
|
find_unique_abbrev(ce->oid.hash, abbrev),
|
||||||
ce_stage(ce));
|
ce_stage(ce));
|
||||||
}
|
}
|
||||||
write_eolinfo(istate, ce, ce->name);
|
write_eolinfo(repo->index, ce, fullname);
|
||||||
write_name(ce->name);
|
write_name(fullname);
|
||||||
print_debug(ce);
|
print_debug(ce);
|
||||||
}
|
}
|
||||||
|
|
||||||
strbuf_release(&name);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
static void show_ru_info(const struct index_state *istate)
|
static void show_ru_info(const struct index_state *istate)
|
||||||
@ -338,59 +278,79 @@ static void show_ru_info(const struct index_state *istate)
|
|||||||
}
|
}
|
||||||
|
|
||||||
static int ce_excluded(struct dir_struct *dir, struct index_state *istate,
|
static int ce_excluded(struct dir_struct *dir, struct index_state *istate,
|
||||||
const struct cache_entry *ce)
|
const char *fullname, const struct cache_entry *ce)
|
||||||
{
|
{
|
||||||
int dtype = ce_to_dtype(ce);
|
int dtype = ce_to_dtype(ce);
|
||||||
return is_excluded(dir, istate, ce->name, &dtype);
|
return is_excluded(dir, istate, fullname, &dtype);
|
||||||
}
|
}
|
||||||
|
|
||||||
static void show_files(struct index_state *istate, struct dir_struct *dir)
|
static void construct_fullname(struct strbuf *out, const struct repository *repo,
|
||||||
|
const struct cache_entry *ce)
|
||||||
|
{
|
||||||
|
strbuf_reset(out);
|
||||||
|
if (repo->submodule_prefix)
|
||||||
|
strbuf_addstr(out, repo->submodule_prefix);
|
||||||
|
strbuf_addstr(out, ce->name);
|
||||||
|
}
|
||||||
|
|
||||||
|
static void show_files(struct repository *repo, struct dir_struct *dir)
|
||||||
{
|
{
|
||||||
int i;
|
int i;
|
||||||
|
struct strbuf fullname = STRBUF_INIT;
|
||||||
|
|
||||||
/* For cached/deleted files we don't need to even do the readdir */
|
/* For cached/deleted files we don't need to even do the readdir */
|
||||||
if (show_others || show_killed) {
|
if (show_others || show_killed) {
|
||||||
if (!show_others)
|
if (!show_others)
|
||||||
dir->flags |= DIR_COLLECT_KILLED_ONLY;
|
dir->flags |= DIR_COLLECT_KILLED_ONLY;
|
||||||
fill_directory(dir, istate, &pathspec);
|
fill_directory(dir, repo->index, &pathspec);
|
||||||
if (show_others)
|
if (show_others)
|
||||||
show_other_files(istate, dir);
|
show_other_files(repo->index, dir);
|
||||||
if (show_killed)
|
if (show_killed)
|
||||||
show_killed_files(istate, dir);
|
show_killed_files(repo->index, dir);
|
||||||
}
|
}
|
||||||
if (show_cached || show_stage) {
|
if (show_cached || show_stage) {
|
||||||
for (i = 0; i < istate->cache_nr; i++) {
|
for (i = 0; i < repo->index->cache_nr; i++) {
|
||||||
const struct cache_entry *ce = istate->cache[i];
|
const struct cache_entry *ce = repo->index->cache[i];
|
||||||
|
|
||||||
|
construct_fullname(&fullname, repo, ce);
|
||||||
|
|
||||||
if ((dir->flags & DIR_SHOW_IGNORED) &&
|
if ((dir->flags & DIR_SHOW_IGNORED) &&
|
||||||
!ce_excluded(dir, istate, ce))
|
!ce_excluded(dir, repo->index, fullname.buf, ce))
|
||||||
continue;
|
continue;
|
||||||
if (show_unmerged && !ce_stage(ce))
|
if (show_unmerged && !ce_stage(ce))
|
||||||
continue;
|
continue;
|
||||||
if (ce->ce_flags & CE_UPDATE)
|
if (ce->ce_flags & CE_UPDATE)
|
||||||
continue;
|
continue;
|
||||||
show_ce_entry(istate, ce_stage(ce) ? tag_unmerged :
|
show_ce(repo, dir, ce, fullname.buf,
|
||||||
(ce_skip_worktree(ce) ? tag_skip_worktree : tag_cached), ce);
|
ce_stage(ce) ? tag_unmerged :
|
||||||
|
(ce_skip_worktree(ce) ? tag_skip_worktree :
|
||||||
|
tag_cached));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
if (show_deleted || show_modified) {
|
if (show_deleted || show_modified) {
|
||||||
for (i = 0; i < istate->cache_nr; i++) {
|
for (i = 0; i < repo->index->cache_nr; i++) {
|
||||||
const struct cache_entry *ce = istate->cache[i];
|
const struct cache_entry *ce = repo->index->cache[i];
|
||||||
struct stat st;
|
struct stat st;
|
||||||
int err;
|
int err;
|
||||||
|
|
||||||
|
construct_fullname(&fullname, repo, ce);
|
||||||
|
|
||||||
if ((dir->flags & DIR_SHOW_IGNORED) &&
|
if ((dir->flags & DIR_SHOW_IGNORED) &&
|
||||||
!ce_excluded(dir, istate, ce))
|
!ce_excluded(dir, repo->index, fullname.buf, ce))
|
||||||
continue;
|
continue;
|
||||||
if (ce->ce_flags & CE_UPDATE)
|
if (ce->ce_flags & CE_UPDATE)
|
||||||
continue;
|
continue;
|
||||||
if (ce_skip_worktree(ce))
|
if (ce_skip_worktree(ce))
|
||||||
continue;
|
continue;
|
||||||
err = lstat(ce->name, &st);
|
err = lstat(fullname.buf, &st);
|
||||||
if (show_deleted && err)
|
if (show_deleted && err)
|
||||||
show_ce_entry(istate, tag_removed, ce);
|
show_ce(repo, dir, ce, fullname.buf, tag_removed);
|
||||||
if (show_modified && ie_modified(istate, ce, &st, 0))
|
if (show_modified && ie_modified(repo->index, ce, &st, 0))
|
||||||
show_ce_entry(istate, tag_modified, ce);
|
show_ce(repo, dir, ce, fullname.buf, tag_modified);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
strbuf_release(&fullname);
|
||||||
}
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
@ -615,10 +575,9 @@ int cmd_ls_files(int argc, const char **argv, const char *cmd_prefix)
|
|||||||
prefix = cmd_prefix;
|
prefix = cmd_prefix;
|
||||||
if (prefix)
|
if (prefix)
|
||||||
prefix_len = strlen(prefix);
|
prefix_len = strlen(prefix);
|
||||||
super_prefix = get_super_prefix();
|
|
||||||
git_config(git_default_config, NULL);
|
git_config(git_default_config, NULL);
|
||||||
|
|
||||||
if (read_cache() < 0)
|
if (repo_read_index(the_repository) < 0)
|
||||||
die("index file corrupt");
|
die("index file corrupt");
|
||||||
|
|
||||||
argc = parse_options(argc, argv, prefix, builtin_ls_files_options,
|
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)
|
|||||||
setup_work_tree();
|
setup_work_tree();
|
||||||
|
|
||||||
if (recurse_submodules)
|
if (recurse_submodules)
|
||||||
compile_submodule_options(argv, &dir, show_tag);
|
repo_read_gitmodules(the_repository);
|
||||||
|
|
||||||
if (recurse_submodules &&
|
if (recurse_submodules &&
|
||||||
(show_stage || show_deleted || show_others || show_unmerged ||
|
(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)
|
|||||||
/*
|
/*
|
||||||
* Find common prefix for all pathspec's
|
* Find common prefix for all pathspec's
|
||||||
* This is used as a performance optimization which unfortunately cannot
|
* This is used as a performance optimization which unfortunately cannot
|
||||||
* be done when recursing into submodules
|
* be done when recursing into submodules because when a pathspec is
|
||||||
|
* given which spans repository boundaries you can't simply remove the
|
||||||
|
* submodule entry because the pathspec may match something inside the
|
||||||
|
* submodule.
|
||||||
*/
|
*/
|
||||||
if (recurse_submodules)
|
if (recurse_submodules)
|
||||||
max_prefix = NULL;
|
max_prefix = NULL;
|
||||||
@ -678,7 +640,7 @@ int cmd_ls_files(int argc, const char **argv, const char *cmd_prefix)
|
|||||||
max_prefix = common_prefix(&pathspec);
|
max_prefix = common_prefix(&pathspec);
|
||||||
max_prefix_len = get_common_prefix_len(max_prefix);
|
max_prefix_len = get_common_prefix_len(max_prefix);
|
||||||
|
|
||||||
prune_index(&the_index, max_prefix, max_prefix_len);
|
prune_index(the_repository->index, max_prefix, max_prefix_len);
|
||||||
|
|
||||||
/* Treat unmatching pathspec elements as errors */
|
/* Treat unmatching pathspec elements as errors */
|
||||||
if (pathspec.nr && error_unmatch)
|
if (pathspec.nr && error_unmatch)
|
||||||
@ -699,11 +661,13 @@ int cmd_ls_files(int argc, const char **argv, const char *cmd_prefix)
|
|||||||
*/
|
*/
|
||||||
if (show_stage || show_unmerged)
|
if (show_stage || show_unmerged)
|
||||||
die("ls-files --with-tree is incompatible with -s or -u");
|
die("ls-files --with-tree is incompatible with -s or -u");
|
||||||
overlay_tree_on_index(&the_index, with_tree, max_prefix);
|
overlay_tree_on_index(the_repository->index, with_tree, max_prefix);
|
||||||
}
|
}
|
||||||
show_files(&the_index, &dir);
|
|
||||||
|
show_files(the_repository, &dir);
|
||||||
|
|
||||||
if (show_resolve_undo)
|
if (show_resolve_undo)
|
||||||
show_ru_info(&the_index);
|
show_ru_info(the_repository->index);
|
||||||
|
|
||||||
if (ps_matched) {
|
if (ps_matched) {
|
||||||
int bad;
|
int bad;
|
||||||
|
2
git.c
2
git.c
@ -400,7 +400,7 @@ static struct cmd_struct commands[] = {
|
|||||||
{ "init-db", cmd_init_db },
|
{ "init-db", cmd_init_db },
|
||||||
{ "interpret-trailers", cmd_interpret_trailers, RUN_SETUP_GENTLY },
|
{ "interpret-trailers", cmd_interpret_trailers, RUN_SETUP_GENTLY },
|
||||||
{ "log", cmd_log, RUN_SETUP },
|
{ "log", cmd_log, RUN_SETUP },
|
||||||
{ "ls-files", cmd_ls_files, RUN_SETUP | SUPPORT_SUPER_PREFIX },
|
{ "ls-files", cmd_ls_files, RUN_SETUP },
|
||||||
{ "ls-remote", cmd_ls_remote, RUN_SETUP_GENTLY },
|
{ "ls-remote", cmd_ls_remote, RUN_SETUP_GENTLY },
|
||||||
{ "ls-tree", cmd_ls_tree, RUN_SETUP },
|
{ "ls-tree", cmd_ls_tree, RUN_SETUP },
|
||||||
{ "mailinfo", cmd_mailinfo, RUN_SETUP_GENTLY },
|
{ "mailinfo", cmd_mailinfo, RUN_SETUP_GENTLY },
|
||||||
|
@ -135,6 +135,45 @@ test_expect_success '--recurse-submodules and pathspecs setup' '
|
|||||||
test_cmp expect actual
|
test_cmp expect actual
|
||||||
'
|
'
|
||||||
|
|
||||||
|
test_expect_success 'inactive submodule' '
|
||||||
|
test_when_finished "git config --bool submodule.submodule.active true" &&
|
||||||
|
test_when_finished "git -C submodule config --bool submodule.subsub.active true" &&
|
||||||
|
git config --bool submodule.submodule.active "false" &&
|
||||||
|
|
||||||
|
cat >expect <<-\EOF &&
|
||||||
|
.gitmodules
|
||||||
|
a
|
||||||
|
b/b
|
||||||
|
h.txt
|
||||||
|
sib/file
|
||||||
|
sub/file
|
||||||
|
submodule
|
||||||
|
EOF
|
||||||
|
|
||||||
|
git ls-files --recurse-submodules >actual &&
|
||||||
|
test_cmp expect actual &&
|
||||||
|
|
||||||
|
git config --bool submodule.submodule.active "true" &&
|
||||||
|
git -C submodule config --bool submodule.subsub.active "false" &&
|
||||||
|
|
||||||
|
cat >expect <<-\EOF &&
|
||||||
|
.gitmodules
|
||||||
|
a
|
||||||
|
b/b
|
||||||
|
h.txt
|
||||||
|
sib/file
|
||||||
|
sub/file
|
||||||
|
submodule/.gitmodules
|
||||||
|
submodule/c
|
||||||
|
submodule/f.TXT
|
||||||
|
submodule/g.txt
|
||||||
|
submodule/subsub
|
||||||
|
EOF
|
||||||
|
|
||||||
|
git ls-files --recurse-submodules >actual &&
|
||||||
|
test_cmp expect actual
|
||||||
|
'
|
||||||
|
|
||||||
test_expect_success '--recurse-submodules and pathspecs' '
|
test_expect_success '--recurse-submodules and pathspecs' '
|
||||||
cat >expect <<-\EOF &&
|
cat >expect <<-\EOF &&
|
||||||
h.txt
|
h.txt
|
||||||
|
Loading…
Reference in New Issue
Block a user