diff options
Diffstat (limited to 'ref-filter.c')
-rw-r--r-- | ref-filter.c | 272 |
1 files changed, 176 insertions, 96 deletions
diff --git a/ref-filter.c b/ref-filter.c index 01c1a82..0bccfce 100644 --- a/ref-filter.c +++ b/ref-filter.c @@ -3,6 +3,8 @@ #include "parse-options.h" #include "refs.h" #include "wildmatch.h" +#include "object-store.h" +#include "repository.h" #include "commit.h" #include "remote.h" #include "color.h" @@ -16,6 +18,7 @@ #include "trailer.h" #include "wt-status.h" #include "commit-slab.h" +#include "commit-graph.h" static struct ref_msg { const char *gone; @@ -40,6 +43,7 @@ void setup_ref_filter_porcelain_msg(void) typedef enum { FIELD_STR, FIELD_ULONG, FIELD_TIME } cmp_type; typedef enum { COMPARE_EQUAL, COMPARE_UNEQUAL, COMPARE_NONE } cmp_status; +typedef enum { SOURCE_NONE = 0, SOURCE_OBJ, SOURCE_OTHER } info_source; struct align { align_type position; @@ -59,6 +63,17 @@ struct refname_atom { int lstrip, rstrip; }; +static struct expand_data { + struct object_id oid; + enum object_type type; + unsigned long size; + off_t disk_size; + struct object_id delta_base_oid; + void *content; + + struct object_info info; +} oi, oi_deref; + /* * An atom is a valid field atom listed below, possibly prefixed with * a "*" to denote deref_tag(). @@ -72,6 +87,7 @@ struct refname_atom { static struct used_atom { const char *name; cmp_type type; + info_source source; union { char color[COLOR_MAXLEN]; struct align align; @@ -199,6 +215,30 @@ static int remote_ref_atom_parser(const struct ref_format *format, struct used_a return 0; } +static int objecttype_atom_parser(const struct ref_format *format, struct used_atom *atom, + const char *arg, struct strbuf *err) +{ + if (arg) + return strbuf_addf_ret(err, -1, _("%%(objecttype) does not take arguments")); + if (*atom->name == '*') + oi_deref.info.typep = &oi_deref.type; + else + oi.info.typep = &oi.type; + return 0; +} + +static int objectsize_atom_parser(const struct ref_format *format, struct used_atom *atom, + const char *arg, struct strbuf *err) +{ + if (arg) + return strbuf_addf_ret(err, -1, _("%%(objectsize) does not take arguments")); + if (*atom->name == '*') + oi_deref.info.sizep = &oi_deref.size; + else + oi.info.sizep = &oi.size; + return 0; +} + static int body_atom_parser(const struct ref_format *format, struct used_atom *atom, const char *arg, struct strbuf *err) { @@ -379,49 +419,50 @@ static int head_atom_parser(const struct ref_format *format, struct used_atom *a static struct { const char *name; + info_source source; cmp_type cmp_type; int (*parser)(const struct ref_format *format, struct used_atom *atom, const char *arg, struct strbuf *err); } valid_atom[] = { - { "refname" , FIELD_STR, refname_atom_parser }, - { "objecttype" }, - { "objectsize", FIELD_ULONG }, - { "objectname", FIELD_STR, objectname_atom_parser }, - { "tree" }, - { "parent" }, - { "numparent", FIELD_ULONG }, - { "object" }, - { "type" }, - { "tag" }, - { "author" }, - { "authorname" }, - { "authoremail" }, - { "authordate", FIELD_TIME }, - { "committer" }, - { "committername" }, - { "committeremail" }, - { "committerdate", FIELD_TIME }, - { "tagger" }, - { "taggername" }, - { "taggeremail" }, - { "taggerdate", FIELD_TIME }, - { "creator" }, - { "creatordate", FIELD_TIME }, - { "subject", FIELD_STR, subject_atom_parser }, - { "body", FIELD_STR, body_atom_parser }, - { "trailers", FIELD_STR, trailers_atom_parser }, - { "contents", FIELD_STR, contents_atom_parser }, - { "upstream", FIELD_STR, remote_ref_atom_parser }, - { "push", FIELD_STR, remote_ref_atom_parser }, - { "symref", FIELD_STR, refname_atom_parser }, - { "flag" }, - { "HEAD", FIELD_STR, head_atom_parser }, - { "color", FIELD_STR, color_atom_parser }, - { "align", FIELD_STR, align_atom_parser }, - { "end" }, - { "if", FIELD_STR, if_atom_parser }, - { "then" }, - { "else" }, + { "refname", SOURCE_NONE, FIELD_STR, refname_atom_parser }, + { "objecttype", SOURCE_OTHER, FIELD_STR, objecttype_atom_parser }, + { "objectsize", SOURCE_OTHER, FIELD_ULONG, objectsize_atom_parser }, + { "objectname", SOURCE_OTHER, FIELD_STR, objectname_atom_parser }, + { "tree", SOURCE_OBJ }, + { "parent", SOURCE_OBJ }, + { "numparent", SOURCE_OBJ, FIELD_ULONG }, + { "object", SOURCE_OBJ }, + { "type", SOURCE_OBJ }, + { "tag", SOURCE_OBJ }, + { "author", SOURCE_OBJ }, + { "authorname", SOURCE_OBJ }, + { "authoremail", SOURCE_OBJ }, + { "authordate", SOURCE_OBJ, FIELD_TIME }, + { "committer", SOURCE_OBJ }, + { "committername", SOURCE_OBJ }, + { "committeremail", SOURCE_OBJ }, + { "committerdate", SOURCE_OBJ, FIELD_TIME }, + { "tagger", SOURCE_OBJ }, + { "taggername", SOURCE_OBJ }, + { "taggeremail", SOURCE_OBJ }, + { "taggerdate", SOURCE_OBJ, FIELD_TIME }, + { "creator", SOURCE_OBJ }, + { "creatordate", SOURCE_OBJ, FIELD_TIME }, + { "subject", SOURCE_OBJ, FIELD_STR, subject_atom_parser }, + { "body", SOURCE_OBJ, FIELD_STR, body_atom_parser }, + { "trailers", SOURCE_OBJ, FIELD_STR, trailers_atom_parser }, + { "contents", SOURCE_OBJ, FIELD_STR, contents_atom_parser }, + { "upstream", SOURCE_NONE, FIELD_STR, remote_ref_atom_parser }, + { "push", SOURCE_NONE, FIELD_STR, remote_ref_atom_parser }, + { "symref", SOURCE_NONE, FIELD_STR, refname_atom_parser }, + { "flag", SOURCE_NONE }, + { "HEAD", SOURCE_NONE, FIELD_STR, head_atom_parser }, + { "color", SOURCE_NONE, FIELD_STR, color_atom_parser }, + { "align", SOURCE_NONE, FIELD_STR, align_atom_parser }, + { "end", SOURCE_NONE }, + { "if", SOURCE_NONE, FIELD_STR, if_atom_parser }, + { "then", SOURCE_NONE }, + { "else", SOURCE_NONE }, }; #define REF_FORMATTING_STATE_INIT { 0, NULL } @@ -497,6 +538,13 @@ static int parse_ref_filter_atom(const struct ref_format *format, REALLOC_ARRAY(used_atom, used_atom_cnt); used_atom[at].name = xmemdupz(atom, ep - atom); used_atom[at].type = valid_atom[i].cmp_type; + used_atom[at].source = valid_atom[i].source; + if (used_atom[at].source == SOURCE_OBJ) { + if (*atom == '*') + oi_deref.info.contentp = &oi_deref.content; + else + oi.info.contentp = &oi.content; + } if (arg) { arg = used_atom[at].name + (arg - atom) + 1; if (!*arg) { @@ -792,24 +840,6 @@ int verify_ref_format(struct ref_format *format) return 0; } -/* - * Given an object name, read the object data and size, and return a - * "struct object". If the object data we are returning is also borrowed - * by the "struct object" representation, set *eaten as well---it is a - * signal from parse_object_buffer to us not to free the buffer. - */ -static void *get_obj(const struct object_id *oid, struct object **obj, unsigned long *sz, int *eaten) -{ - enum object_type type; - void *buf = read_object_file(oid, &type, sz); - - if (buf) - *obj = parse_object_buffer(oid, type, *sz, buf, eaten); - else - *obj = NULL; - return buf; -} - static int grab_objectname(const char *name, const struct object_id *oid, struct atom_value *v, struct used_atom *atom) { @@ -830,7 +860,7 @@ static int grab_objectname(const char *name, const struct object_id *oid, } /* See grab_values */ -static void grab_common_values(struct atom_value *val, int deref, struct object *obj, void *buf, unsigned long sz) +static void grab_common_values(struct atom_value *val, int deref, struct expand_data *oi) { int i; @@ -842,13 +872,13 @@ static void grab_common_values(struct atom_value *val, int deref, struct object if (deref) name++; if (!strcmp(name, "objecttype")) - v->s = type_name(obj->type); + v->s = type_name(oi->type); else if (!strcmp(name, "objectsize")) { - v->value = sz; - v->s = xstrfmt("%lu", sz); + v->value = oi->size; + v->s = xstrfmt("%lu", oi->size); } else if (deref) - grab_objectname(name, &obj->oid, v, &used_atom[i]); + grab_objectname(name, &oi->oid, v, &used_atom[i]); } } @@ -1207,7 +1237,6 @@ static void fill_missing_values(struct atom_value *val) */ static void grab_values(struct atom_value *val, int deref, struct object *obj, void *buf, unsigned long sz) { - grab_common_values(val, deref, obj, buf, sz); switch (obj->type) { case OBJ_TAG: grab_tag_values(val, deref, obj, buf, sz); @@ -1431,24 +1460,36 @@ static const char *get_refname(struct used_atom *atom, struct ref_array_item *re return show_ref(&atom->u.refname, ref->refname); } -static int get_object(struct ref_array_item *ref, const struct object_id *oid, - int deref, struct object **obj, struct strbuf *err) +static int get_object(struct ref_array_item *ref, int deref, struct object **obj, + struct expand_data *oi, struct strbuf *err) { - int eaten; - int ret = 0; - unsigned long size; - void *buf = get_obj(oid, obj, &size, &eaten); - if (!buf) - ret = strbuf_addf_ret(err, -1, _("missing object %s for %s"), - oid_to_hex(oid), ref->refname); - else if (!*obj) - ret = strbuf_addf_ret(err, -1, _("parse_object_buffer failed on %s for %s"), - oid_to_hex(oid), ref->refname); - else - grab_values(ref->value, deref, *obj, buf, size); + /* parse_object_buffer() will set eaten to 0 if free() will be needed */ + int eaten = 1; + if (oi->info.contentp) { + /* We need to know that to use parse_object_buffer properly */ + oi->info.sizep = &oi->size; + oi->info.typep = &oi->type; + } + if (oid_object_info_extended(the_repository, &oi->oid, &oi->info, + OBJECT_INFO_LOOKUP_REPLACE)) + return strbuf_addf_ret(err, -1, _("missing object %s for %s"), + oid_to_hex(&oi->oid), ref->refname); + + if (oi->info.contentp) { + *obj = parse_object_buffer(the_repository, &oi->oid, oi->type, oi->size, oi->content, &eaten); + if (!obj) { + if (!eaten) + free(oi->content); + return strbuf_addf_ret(err, -1, _("parse_object_buffer failed on %s for %s"), + oid_to_hex(&oi->oid), ref->refname); + } + grab_values(ref->value, deref, *obj, oi->content, oi->size); + } + + grab_common_values(ref->value, deref, oi); if (!eaten) - free(buf); - return ret; + free(oi->content); + return 0; } /* @@ -1458,7 +1499,7 @@ static int populate_value(struct ref_array_item *ref, struct strbuf *err) { struct object *obj; int i; - const struct object_id *tagged; + struct object_info empty = OBJECT_INFO_INIT; ref->value = xcalloc(used_atom_cnt, sizeof(struct atom_value)); @@ -1492,6 +1533,7 @@ static int populate_value(struct ref_array_item *ref, struct strbuf *err) refname = get_symref(atom, ref); else if (starts_with(name, "upstream")) { const char *branch_name; + v->s = ""; /* only local branches may have an upstream */ if (!skip_prefix(ref->refname, "refs/heads/", &branch_name)) @@ -1504,6 +1546,7 @@ static int populate_value(struct ref_array_item *ref, struct strbuf *err) continue; } else if (atom->u.remote_ref.push) { const char *branch_name; + v->s = ""; if (!skip_prefix(ref->refname, "refs/heads/", &branch_name)) continue; @@ -1544,22 +1587,26 @@ static int populate_value(struct ref_array_item *ref, struct strbuf *err) continue; } else if (starts_with(name, "align")) { v->handler = align_atom_handler; + v->s = ""; continue; } else if (!strcmp(name, "end")) { v->handler = end_atom_handler; + v->s = ""; continue; } else if (starts_with(name, "if")) { const char *s; - + v->s = ""; if (skip_prefix(name, "if:", &s)) v->s = xstrdup(s); v->handler = if_atom_handler; continue; } else if (!strcmp(name, "then")) { v->handler = then_atom_handler; + v->s = ""; continue; } else if (!strcmp(name, "else")) { v->handler = else_atom_handler; + v->s = ""; continue; } else continue; @@ -1572,13 +1619,20 @@ static int populate_value(struct ref_array_item *ref, struct strbuf *err) for (i = 0; i < used_atom_cnt; i++) { struct atom_value *v = &ref->value[i]; - if (v->s == NULL) - break; + if (v->s == NULL && used_atom[i].source == SOURCE_NONE) + return strbuf_addf_ret(err, -1, _("missing object %s for %s"), + oid_to_hex(&ref->objectname), ref->refname); } - if (used_atom_cnt <= i) + + if (need_tagged) + oi.info.contentp = &oi.content; + if (!memcmp(&oi.info, &empty, sizeof(empty)) && + !memcmp(&oi_deref.info, &empty, sizeof(empty))) return 0; - if (get_object(ref, &ref->objectname, 0, &obj, err)) + + oi.oid = ref->objectname; + if (get_object(ref, 0, &obj, &oi, err)) return -1; /* @@ -1592,7 +1646,7 @@ static int populate_value(struct ref_array_item *ref, struct strbuf *err) * If it is a tag object, see if we use a value that derefs * the object, and if we do grab the object it refers to. */ - tagged = &((struct tag *)obj)->tagged->oid; + oi_deref.oid = ((struct tag *)obj)->tagged->oid; /* * NEEDSWORK: This derefs tag only once, which @@ -1600,7 +1654,7 @@ static int populate_value(struct ref_array_item *ref, struct strbuf *err) * is not consistent with what deref_tag() does * which peels the onion to the core. */ - return get_object(ref, tagged, 1, &obj, err); + return get_object(ref, 1, &obj, &oi_deref, err); } /* @@ -1662,12 +1716,13 @@ static int in_commit_list(const struct commit_list *want, struct commit *c) } /* - * Test whether the candidate or one of its parents is contained in the list. + * Test whether the candidate is contained in the list. * Do not recurse to find out, though, but return -1 if inconclusive. */ static enum contains_result contains_test(struct commit *candidate, const struct commit_list *want, - struct contains_cache *cache) + struct contains_cache *cache, + uint32_t cutoff) { enum contains_result *cached = contains_cache_at(cache, candidate); @@ -1683,6 +1738,10 @@ static enum contains_result contains_test(struct commit *candidate, /* Otherwise, we don't know; prepare to recurse */ parse_commit_or_die(candidate); + + if (candidate->generation < cutoff) + return CONTAINS_NO; + return CONTAINS_UNKNOWN; } @@ -1698,8 +1757,18 @@ static enum contains_result contains_tag_algo(struct commit *candidate, struct contains_cache *cache) { struct contains_stack contains_stack = { 0, 0, NULL }; - enum contains_result result = contains_test(candidate, want, cache); + enum contains_result result; + uint32_t cutoff = GENERATION_NUMBER_INFINITY; + const struct commit_list *p; + + for (p = want; p; p = p->next) { + struct commit *c = p->item; + load_commit_graph_info(the_repository, c); + if (c->generation < cutoff) + cutoff = c->generation; + } + result = contains_test(candidate, want, cache, cutoff); if (result != CONTAINS_UNKNOWN) return result; @@ -1717,7 +1786,7 @@ static enum contains_result contains_tag_algo(struct commit *candidate, * If we just popped the stack, parents->item has been marked, * therefore contains_test will return a meaningful yes/no. */ - else switch (contains_test(parents->item, want, cache)) { + else switch (contains_test(parents->item, want, cache, cutoff)) { case CONTAINS_YES: *contains_cache_at(cache, commit) = CONTAINS_YES; contains_stack.nr--; @@ -1731,7 +1800,7 @@ static enum contains_result contains_tag_algo(struct commit *candidate, } } free(contains_stack.contains_stack); - return contains_test(candidate, want, cache); + return contains_test(candidate, want, cache, cutoff); } static int commit_contains(struct ref_filter *filter, struct commit *commit, @@ -1797,7 +1866,7 @@ static int match_name_as_path(const struct ref_filter *filter, const char *refna refname[plen] == '/' || p[plen-1] == '/')) return 1; - if (!wildmatch(p, refname, WM_PATHNAME)) + if (!wildmatch(p, refname, flags)) return 1; } return 0; @@ -1852,6 +1921,15 @@ static int for_each_fullref_in_pattern(struct ref_filter *filter, return for_each_fullref_in("", cb, cb_data, broken); } + if (filter->ignore_case) { + /* + * we can't handle case-insensitive comparisons, + * so just return everything and let the caller + * sort it out. + */ + return for_each_fullref_in("", cb, cb_data, broken); + } + if (!filter->name_patterns[0]) { /* no patterns; we have to look at everything */ return for_each_fullref_in("", cb, cb_data, broken); @@ -1897,7 +1975,7 @@ static const struct object_id *match_points_at(struct oid_array *points_at, if (oid_array_lookup(points_at, oid) >= 0) return oid; - obj = parse_object(oid); + obj = parse_object(the_repository, oid); if (!obj) die(_("malformed object at '%s'"), refname); if (obj->type == OBJ_TAG) @@ -2007,7 +2085,8 @@ static int ref_filter_handler(const char *refname, const struct object_id *oid, * non-commits early. The actual filtering is done later. */ if (filter->merge_commit || filter->with_commit || filter->no_commit || filter->verbose) { - commit = lookup_commit_reference_gently(oid, 1); + commit = lookup_commit_reference_gently(the_repository, oid, + 1); if (!commit) return 0; /* We perform the filtering for the '--contains' option... */ @@ -2364,7 +2443,8 @@ int parse_opt_merge_filter(const struct option *opt, const char *arg, int unset) if (get_oid(arg, &oid)) die(_("malformed object name %s"), arg); - rf->merge_commit = lookup_commit_reference_gently(&oid, 0); + rf->merge_commit = lookup_commit_reference_gently(the_repository, + &oid, 0); if (!rf->merge_commit) return opterror(opt, "must point to a commit", 0); |