summaryrefslogtreecommitdiff
path: root/list-objects.c
diff options
context:
space:
mode:
Diffstat (limited to 'list-objects.c')
-rw-r--r--list-objects.c148
1 files changed, 102 insertions, 46 deletions
diff --git a/list-objects.c b/list-objects.c
index c41cc80db5..e19589baa0 100644
--- a/list-objects.c
+++ b/list-objects.c
@@ -18,8 +18,7 @@ struct traversal_context {
show_object_fn show_object;
show_commit_fn show_commit;
void *show_data;
- filter_object_fn filter_fn;
- void *filter_data;
+ struct filter *filter;
};
static void process_blob(struct traversal_context *ctx,
@@ -29,7 +28,7 @@ static void process_blob(struct traversal_context *ctx,
{
struct object *obj = &blob->object;
size_t pathlen;
- enum list_objects_filter_result r = LOFR_MARK_SEEN | LOFR_DO_SHOW;
+ enum list_objects_filter_result r;
if (!ctx->revs->blob_objects)
return;
@@ -54,10 +53,10 @@ static void process_blob(struct traversal_context *ctx,
pathlen = path->len;
strbuf_addstr(path, name);
- if ((obj->flags & NOT_USER_GIVEN) && ctx->filter_fn)
- r = ctx->filter_fn(LOFS_BLOB, obj,
- path->buf, &path->buf[pathlen],
- ctx->filter_data);
+ r = list_objects_filter__filter_object(ctx->revs->repo,
+ LOFS_BLOB, obj,
+ path->buf, &path->buf[pathlen],
+ ctx->filter);
if (r & LOFR_MARK_SEEN)
obj->flags |= SEEN;
if (r & LOFR_DO_SHOW)
@@ -113,7 +112,8 @@ static void process_tree_contents(struct traversal_context *ctx,
while (tree_entry(&desc, &entry)) {
if (match != all_entries_interesting) {
- match = tree_entry_interesting(&entry, base, 0,
+ match = tree_entry_interesting(ctx->revs->repo->index,
+ &entry, base, 0,
&ctx->revs->diffopt.pathspec);
if (match == all_entries_not_interesting)
break;
@@ -122,15 +122,25 @@ static void process_tree_contents(struct traversal_context *ctx,
}
if (S_ISDIR(entry.mode)) {
- struct tree *t = lookup_tree(the_repository, entry.oid);
+ struct tree *t = lookup_tree(ctx->revs->repo, &entry.oid);
+ if (!t) {
+ die(_("entry '%s' in tree %s has tree mode, "
+ "but is not a tree"),
+ entry.path, oid_to_hex(&tree->object.oid));
+ }
t->object.flags |= NOT_USER_GIVEN;
process_tree(ctx, t, base, entry.path);
}
else if (S_ISGITLINK(entry.mode))
- process_gitlink(ctx, entry.oid->hash,
+ process_gitlink(ctx, entry.oid.hash,
base, entry.path);
else {
- struct blob *b = lookup_blob(the_repository, entry.oid);
+ struct blob *b = lookup_blob(ctx->revs->repo, &entry.oid);
+ if (!b) {
+ die(_("entry '%s' in tree %s has blob mode, "
+ "but is not a blob"),
+ entry.path, oid_to_hex(&tree->object.oid));
+ }
b->object.flags |= NOT_USER_GIVEN;
process_blob(ctx, b, base, entry.path);
}
@@ -145,7 +155,7 @@ static void process_tree(struct traversal_context *ctx,
struct object *obj = &tree->object;
struct rev_info *revs = ctx->revs;
int baselen = base->len;
- enum list_objects_filter_result r = LOFR_MARK_SEEN | LOFR_DO_SHOW;
+ enum list_objects_filter_result r;
int failed_parse;
if (!revs->tree_objects)
@@ -174,10 +184,10 @@ static void process_tree(struct traversal_context *ctx,
}
strbuf_addstr(base, name);
- if ((obj->flags & NOT_USER_GIVEN) && ctx->filter_fn)
- r = ctx->filter_fn(LOFS_BEGIN_TREE, obj,
- base->buf, &base->buf[baselen],
- ctx->filter_data);
+ r = list_objects_filter__filter_object(ctx->revs->repo,
+ LOFS_BEGIN_TREE, obj,
+ base->buf, &base->buf[baselen],
+ ctx->filter);
if (r & LOFR_MARK_SEEN)
obj->flags |= SEEN;
if (r & LOFR_DO_SHOW)
@@ -190,15 +200,14 @@ static void process_tree(struct traversal_context *ctx,
else if (!failed_parse)
process_tree_contents(ctx, tree, base);
- if ((obj->flags & NOT_USER_GIVEN) && ctx->filter_fn) {
- r = ctx->filter_fn(LOFS_END_TREE, obj,
- base->buf, &base->buf[baselen],
- ctx->filter_data);
- if (r & LOFR_MARK_SEEN)
- obj->flags |= SEEN;
- if (r & LOFR_DO_SHOW)
- ctx->show_object(obj, base->buf, ctx->show_data);
- }
+ r = list_objects_filter__filter_object(ctx->revs->repo,
+ LOFS_END_TREE, obj,
+ base->buf, &base->buf[baselen],
+ ctx->filter);
+ if (r & LOFR_MARK_SEEN)
+ obj->flags |= SEEN;
+ if (r & LOFR_DO_SHOW)
+ ctx->show_object(obj, base->buf, ctx->show_data);
strbuf_setlen(base, baselen);
free_tree_buffer(tree);
@@ -222,25 +231,73 @@ static void mark_edge_parents_uninteresting(struct commit *commit,
}
}
-void mark_edges_uninteresting(struct rev_info *revs, show_edge_fn show_edge)
+static void add_edge_parents(struct commit *commit,
+ struct rev_info *revs,
+ show_edge_fn show_edge,
+ struct oidset *set)
+{
+ struct commit_list *parents;
+
+ for (parents = commit->parents; parents; parents = parents->next) {
+ struct commit *parent = parents->item;
+ struct tree *tree = get_commit_tree(parent);
+
+ if (!tree)
+ continue;
+
+ oidset_insert(set, &tree->object.oid);
+
+ if (!(parent->object.flags & UNINTERESTING))
+ continue;
+ tree->object.flags |= UNINTERESTING;
+
+ if (revs->edge_hint && !(parent->object.flags & SHOWN)) {
+ parent->object.flags |= SHOWN;
+ show_edge(parent);
+ }
+ }
+}
+
+void mark_edges_uninteresting(struct rev_info *revs,
+ show_edge_fn show_edge,
+ int sparse)
{
struct commit_list *list;
int i;
- for (list = revs->commits; list; list = list->next) {
- struct commit *commit = list->item;
+ if (sparse) {
+ struct oidset set;
+ oidset_init(&set, 16);
- if (commit->object.flags & UNINTERESTING) {
- mark_tree_uninteresting(revs->repo,
- get_commit_tree(commit));
- if (revs->edge_hint_aggressive && !(commit->object.flags & SHOWN)) {
- commit->object.flags |= SHOWN;
- show_edge(commit);
+ for (list = revs->commits; list; list = list->next) {
+ struct commit *commit = list->item;
+ struct tree *tree = get_commit_tree(commit);
+
+ if (commit->object.flags & UNINTERESTING)
+ tree->object.flags |= UNINTERESTING;
+
+ oidset_insert(&set, &tree->object.oid);
+ add_edge_parents(commit, revs, show_edge, &set);
+ }
+
+ mark_trees_uninteresting_sparse(revs->repo, &set);
+ oidset_clear(&set);
+ } else {
+ for (list = revs->commits; list; list = list->next) {
+ struct commit *commit = list->item;
+ if (commit->object.flags & UNINTERESTING) {
+ mark_tree_uninteresting(revs->repo,
+ get_commit_tree(commit));
+ if (revs->edge_hint_aggressive && !(commit->object.flags & SHOWN)) {
+ commit->object.flags |= SHOWN;
+ show_edge(commit);
+ }
+ continue;
}
- continue;
+ mark_edge_parents_uninteresting(commit, revs, show_edge);
}
- mark_edge_parents_uninteresting(commit, revs, show_edge);
}
+
if (revs->edge_hint_aggressive) {
for (i = 0; i < revs->cmdline.nr; i++) {
struct object *obj = revs->cmdline.rev[i].item;
@@ -308,10 +365,15 @@ static void do_traverse(struct traversal_context *ctx)
* an uninteresting boundary commit may not have its tree
* parsed yet, but we are not going to show them anyway
*/
- if (get_commit_tree(commit)) {
+ if (!ctx->revs->tree_objects)
+ ; /* do not bother loading tree */
+ else if (get_commit_tree(commit)) {
struct tree *tree = get_commit_tree(commit);
tree->object.flags |= NOT_USER_GIVEN;
add_pending_tree(ctx->revs, tree);
+ } else if (commit->object.parsed) {
+ die(_("unable to load root tree for commit %s"),
+ oid_to_hex(&commit->object.oid));
}
ctx->show_commit(commit, ctx->show_data);
@@ -337,8 +399,7 @@ void traverse_commit_list(struct rev_info *revs,
ctx.show_commit = show_commit;
ctx.show_object = show_object;
ctx.show_data = show_data;
- ctx.filter_fn = NULL;
- ctx.filter_data = NULL;
+ ctx.filter = NULL;
do_traverse(&ctx);
}
@@ -351,17 +412,12 @@ void traverse_commit_list_filtered(
struct oidset *omitted)
{
struct traversal_context ctx;
- filter_free_fn filter_free_fn = NULL;
ctx.revs = revs;
ctx.show_object = show_object;
ctx.show_commit = show_commit;
ctx.show_data = show_data;
- ctx.filter_fn = NULL;
-
- ctx.filter_data = list_objects_filter__init(omitted, filter_options,
- &ctx.filter_fn, &filter_free_fn);
+ ctx.filter = list_objects_filter__init(omitted, filter_options);
do_traverse(&ctx);
- if (ctx.filter_data && filter_free_fn)
- filter_free_fn(ctx.filter_data);
+ list_objects_filter__free(ctx.filter);
}