ref-filter: add support for %(contents:lines=X)

In 'tag.c' we can print N lines from the annotation of the tag using
the '-n<num>' option. Copy code from 'tag.c' to 'ref-filter' and
modify it to support appending of N lines from the annotation of tags
to the given strbuf.

Implement %(contents:lines=X) where X lines of the given object are
obtained.

While we're at it, remove unused "contents:<suboption>" atoms from
the `valid_atom` array.

Add documentation and test for the same.

Mentored-by: Christian Couder <christian.couder@gmail.com>
Mentored-by: Matthieu Moy <matthieu.moy@grenoble-inp.fr>
Signed-off-by: Karthik Nayak <karthik.188@gmail.com>
Signed-off-by: Junio C Hamano <gitster@pobox.com>
This commit is contained in:
Karthik Nayak 2015-09-11 20:34:16 +05:30 коммит произвёл Junio C Hamano
Родитель 5b4f28510f
Коммит 1bb38e5a6a
5 изменённых файлов: 103 добавлений и 6 удалений

Просмотреть файл

@ -150,7 +150,8 @@ The complete message in a commit and tag object is `contents`.
Its first line is `contents:subject`, where subject is the concatenation Its first line is `contents:subject`, where subject is the concatenation
of all lines of the commit message up to the first blank line. The next of all lines of the commit message up to the first blank line. The next
line is 'contents:body', where body is all of the lines after the first line is 'contents:body', where body is all of the lines after the first
blank line. Finally, the optional GPG signature is `contents:signature`. blank line. The optional GPG signature is `contents:signature`. The
first `N` lines of the message is obtained using `contents:lines=N`.
For sorting purposes, fields with numeric values sort in numeric For sorting purposes, fields with numeric values sort in numeric
order (`objectsize`, `authordate`, `committerdate`, `taggerdate`). order (`objectsize`, `authordate`, `committerdate`, `taggerdate`).

Просмотреть файл

@ -185,6 +185,10 @@ static enum contains_result contains(struct commit *candidate,
return contains_test(candidate, want); return contains_test(candidate, want);
} }
/*
* Currently modified and used in ref-filter as append_lines(), will
* eventually be removed as we port tag.c to use ref-filter APIs.
*/
static void show_tag_lines(const struct object_id *oid, int lines) static void show_tag_lines(const struct object_id *oid, int lines)
{ {
int i; int i;

Просмотреть файл

@ -45,9 +45,6 @@ static struct {
{ "subject" }, { "subject" },
{ "body" }, { "body" },
{ "contents" }, { "contents" },
{ "contents:subject" },
{ "contents:body" },
{ "contents:signature" },
{ "upstream" }, { "upstream" },
{ "push" }, { "push" },
{ "symref" }, { "symref" },
@ -65,6 +62,11 @@ struct align {
unsigned int width; unsigned int width;
}; };
struct contents {
unsigned int lines;
struct object_id oid;
};
struct ref_formatting_stack { struct ref_formatting_stack {
struct ref_formatting_stack *prev; struct ref_formatting_stack *prev;
struct strbuf output; struct strbuf output;
@ -81,6 +83,7 @@ struct atom_value {
const char *s; const char *s;
union { union {
struct align align; struct align align;
struct contents contents;
} u; } u;
void (*handler)(struct atom_value *atomv, struct ref_formatting_state *state); void (*handler)(struct atom_value *atomv, struct ref_formatting_state *state);
unsigned long ul; /* used for sorting when not FIELD_STR */ unsigned long ul; /* used for sorting when not FIELD_STR */
@ -643,6 +646,30 @@ static void find_subpos(const char *buf, unsigned long sz,
*nonsiglen = *sig - buf; *nonsiglen = *sig - buf;
} }
/*
* If 'lines' is greater than 0, append that many lines from the given
* 'buf' of length 'size' to the given strbuf.
*/
static void append_lines(struct strbuf *out, const char *buf, unsigned long size, int lines)
{
int i;
const char *sp, *eol;
size_t len;
sp = buf;
for (i = 0; i < lines && sp < buf + size; i++) {
if (i)
strbuf_addstr(out, "\n ");
eol = memchr(sp, '\n', size - (sp - buf));
len = eol ? eol - sp : size - (sp - buf);
strbuf_add(out, sp, len);
if (!eol)
break;
sp = eol + 1;
}
}
/* See grab_values */ /* See grab_values */
static void grab_sub_body_contents(struct atom_value *val, int deref, struct object *obj, void *buf, unsigned long sz) static void grab_sub_body_contents(struct atom_value *val, int deref, struct object *obj, void *buf, unsigned long sz)
{ {
@ -653,6 +680,7 @@ static void grab_sub_body_contents(struct atom_value *val, int deref, struct obj
for (i = 0; i < used_atom_cnt; i++) { for (i = 0; i < used_atom_cnt; i++) {
const char *name = used_atom[i]; const char *name = used_atom[i];
struct atom_value *v = &val[i]; struct atom_value *v = &val[i];
const char *valp = NULL;
if (!!deref != (*name == '*')) if (!!deref != (*name == '*'))
continue; continue;
if (deref) if (deref)
@ -662,7 +690,8 @@ static void grab_sub_body_contents(struct atom_value *val, int deref, struct obj
strcmp(name, "contents") && strcmp(name, "contents") &&
strcmp(name, "contents:subject") && strcmp(name, "contents:subject") &&
strcmp(name, "contents:body") && strcmp(name, "contents:body") &&
strcmp(name, "contents:signature")) strcmp(name, "contents:signature") &&
!starts_with(name, "contents:lines="))
continue; continue;
if (!subpos) if (!subpos)
find_subpos(buf, sz, find_subpos(buf, sz,
@ -682,6 +711,16 @@ static void grab_sub_body_contents(struct atom_value *val, int deref, struct obj
v->s = xmemdupz(sigpos, siglen); v->s = xmemdupz(sigpos, siglen);
else if (!strcmp(name, "contents")) else if (!strcmp(name, "contents"))
v->s = xstrdup(subpos); v->s = xstrdup(subpos);
else if (skip_prefix(name, "contents:lines=", &valp)) {
struct strbuf s = STRBUF_INIT;
const char *contents_end = bodylen + bodypos - siglen;
if (strtoul_ui(valp, 10, &v->u.contents.lines))
die(_("positive value expected contents:lines=%s"), valp);
/* Size is the length of the message after removing the signature */
append_lines(&s, subpos, contents_end - subpos, v->u.contents.lines);
v->s = strbuf_detach(&s, NULL);
}
} }
} }

Просмотреть файл

@ -59,7 +59,8 @@ struct ref_filter {
struct commit *merge_commit; struct commit *merge_commit;
unsigned int with_commit_tag_algo : 1; unsigned int with_commit_tag_algo : 1;
unsigned int kind; unsigned int kind,
lines;
}; };
struct ref_filter_cbdata { struct ref_filter_cbdata {

Просмотреть файл

@ -167,4 +167,56 @@ test_expect_success 'nested alignment with quote formatting' "
test_cmp expect actual test_cmp expect actual
" "
test_expect_success 'check `%(contents:lines=1)`' '
cat >expect <<-\EOF &&
master |three
side |four
odd/spot |three
double-tag |Annonated doubly
four |four
one |one
signed-tag |A signed tag message
three |three
two |two
EOF
git for-each-ref --format="%(refname:short) |%(contents:lines=1)" >actual &&
test_cmp expect actual
'
test_expect_success 'check `%(contents:lines=0)`' '
cat >expect <<-\EOF &&
master |
side |
odd/spot |
double-tag |
four |
one |
signed-tag |
three |
two |
EOF
git for-each-ref --format="%(refname:short) |%(contents:lines=0)" >actual &&
test_cmp expect actual
'
test_expect_success 'check `%(contents:lines=99999)`' '
cat >expect <<-\EOF &&
master |three
side |four
odd/spot |three
double-tag |Annonated doubly
four |four
one |one
signed-tag |A signed tag message
three |three
two |two
EOF
git for-each-ref --format="%(refname:short) |%(contents:lines=99999)" >actual &&
test_cmp expect actual
'
test_expect_success '`%(contents:lines=-1)` should fail' '
test_must_fail git for-each-ref --format="%(refname:short) |%(contents:lines=-1)"
'
test_done test_done