Use oid_object_info_extended() to get object info instead of read_object_file(). It will help to handle some requests faster (e.g., we do not need to parse whole object if we need to know %(objectsize)). It could also help us to add new atoms such as %(objectsize:disk) and %(deltabase). Signed-off-by: Olga Telezhnaia <olyatelezhnaya@xxxxxxxxx> --- ref-filter.c | 123 ++++++++++++++++++++++++++++++++++++++++++----------------- 1 file changed, 89 insertions(+), 34 deletions(-) diff --git a/ref-filter.c b/ref-filter.c index f04169f0ea0e3..112955f006648 100644 --- a/ref-filter.c +++ b/ref-filter.c @@ -61,6 +61,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(). @@ -202,6 +213,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) { @@ -388,8 +423,8 @@ static struct { const char *arg, struct strbuf *err); } valid_atom[] = { { "refname", SOURCE_NONE, FIELD_STR, refname_atom_parser }, - { "objecttype", SOURCE_OTHER }, - { "objectsize", SOURCE_OTHER, FIELD_ULONG }, + { "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 }, @@ -502,6 +537,12 @@ static int parse_ref_filter_atom(const struct ref_format *format, 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) { @@ -817,7 +858,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; @@ -829,13 +870,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]); } } @@ -1194,7 +1235,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); @@ -1418,28 +1458,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; - enum object_type type; - void *buf = read_object_file(oid, &type, &size); - if (!buf) - ret = strbuf_addf_ret(err, -1, _("missing object %s for %s"), - oid_to_hex(oid), ref->refname); - else { - *obj = parse_object_buffer(oid, type, size, buf, &eaten); - 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(&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; } /* @@ -1449,7 +1497,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)); @@ -1569,13 +1617,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; /* @@ -1589,7 +1644,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 @@ -1597,7 +1652,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); } /* -- https://github.com/git/git/pull/520