Skip to content

Commit f5d18f8

Browse files
five-shgitster
authored andcommitted
ref-filter: add new "describe" atom
Duplicate the logic of %(describe) and friends from pretty to ref-filter. In the future, this change helps in unifying both the formats as ref-filter will be able to do everything that pretty is doing and we can have a single interface. The new atom "describe" and its friends are equivalent to the existing pretty formats with the same name. Helped-by: Junio C Hamano <[email protected]> Mentored-by: Christian Couder <[email protected]> Mentored-by: Hariom Verma <[email protected]> Signed-off-by: Kousik Sanagavarapu <[email protected]> Signed-off-by: Junio C Hamano <[email protected]>
1 parent f46094a commit f5d18f8

File tree

3 files changed

+286
-0
lines changed

3 files changed

+286
-0
lines changed

Documentation/git-for-each-ref.txt

Lines changed: 23 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -258,6 +258,29 @@ ahead-behind:<committish>::
258258
commits ahead and behind, respectively, when comparing the output
259259
ref to the `<committish>` specified in the format.
260260

261+
describe[:options]::
262+
A human-readable name, like linkgit:git-describe[1];
263+
empty string for undescribable commits. The `describe` string may
264+
be followed by a colon and one or more comma-separated options.
265+
+
266+
--
267+
tags=<bool-value>;;
268+
Instead of only considering annotated tags, consider
269+
lightweight tags as well; see the corresponding option in
270+
linkgit:git-describe[1] for details.
271+
abbrev=<number>;;
272+
Use at least <number> hexadecimal digits; see the corresponding
273+
option in linkgit:git-describe[1] for details.
274+
match=<pattern>;;
275+
Only consider tags matching the given `glob(7)` pattern,
276+
excluding the "refs/tags/" prefix; see the corresponding option
277+
in linkgit:git-describe[1] for details.
278+
exclude=<pattern>;;
279+
Do not consider tags matching the given `glob(7)` pattern,
280+
excluding the "refs/tags/" prefix; see the corresponding option
281+
in linkgit:git-describe[1] for details.
282+
--
283+
261284
In addition to the above, for commit and tag objects, the header
262285
field names (`tree`, `parent`, `object`, `type`, and `tag`) can
263286
be used to specify the value in the header field.

ref-filter.c

Lines changed: 125 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -5,6 +5,7 @@
55
#include "gpg-interface.h"
66
#include "hex.h"
77
#include "parse-options.h"
8+
#include "run-command.h"
89
#include "refs.h"
910
#include "wildmatch.h"
1011
#include "object-name.h"
@@ -146,6 +147,7 @@ enum atom_type {
146147
ATOM_TAGGERDATE,
147148
ATOM_CREATOR,
148149
ATOM_CREATORDATE,
150+
ATOM_DESCRIBE,
149151
ATOM_SUBJECT,
150152
ATOM_BODY,
151153
ATOM_TRAILERS,
@@ -220,6 +222,7 @@ static struct used_atom {
220222
enum { S_BARE, S_GRADE, S_SIGNER, S_KEY,
221223
S_FINGERPRINT, S_PRI_KEY_FP, S_TRUST_LEVEL } option;
222224
} signature;
225+
const char **describe_args;
223226
struct refname_atom refname;
224227
char *head;
225228
} u;
@@ -600,6 +603,87 @@ static int contents_atom_parser(struct ref_format *format, struct used_atom *ato
600603
return 0;
601604
}
602605

606+
static int describe_atom_option_parser(struct strvec *args, const char **arg,
607+
struct strbuf *err)
608+
{
609+
const char *argval;
610+
size_t arglen = 0;
611+
int optval = 0;
612+
613+
if (match_atom_bool_arg(*arg, "tags", arg, &optval)) {
614+
if (!optval)
615+
strvec_push(args, "--no-tags");
616+
else
617+
strvec_push(args, "--tags");
618+
return 1;
619+
}
620+
621+
if (match_atom_arg_value(*arg, "abbrev", arg, &argval, &arglen)) {
622+
char *endptr;
623+
624+
if (!arglen)
625+
return strbuf_addf_ret(err, -1,
626+
_("argument expected for %s"),
627+
"describe:abbrev");
628+
if (strtol(argval, &endptr, 10) < 0)
629+
return strbuf_addf_ret(err, -1,
630+
_("positive value expected %s=%s"),
631+
"describe:abbrev", argval);
632+
if (endptr - argval != arglen)
633+
return strbuf_addf_ret(err, -1,
634+
_("cannot fully parse %s=%s"),
635+
"describe:abbrev", argval);
636+
637+
strvec_pushf(args, "--abbrev=%.*s", (int)arglen, argval);
638+
return 1;
639+
}
640+
641+
if (match_atom_arg_value(*arg, "match", arg, &argval, &arglen)) {
642+
if (!arglen)
643+
return strbuf_addf_ret(err, -1,
644+
_("value expected %s="),
645+
"describe:match");
646+
647+
strvec_pushf(args, "--match=%.*s", (int)arglen, argval);
648+
return 1;
649+
}
650+
651+
if (match_atom_arg_value(*arg, "exclude", arg, &argval, &arglen)) {
652+
if (!arglen)
653+
return strbuf_addf_ret(err, -1,
654+
_("value expected %s="),
655+
"describe:exclude");
656+
657+
strvec_pushf(args, "--exclude=%.*s", (int)arglen, argval);
658+
return 1;
659+
}
660+
661+
return 0;
662+
}
663+
664+
static int describe_atom_parser(struct ref_format *format UNUSED,
665+
struct used_atom *atom,
666+
const char *arg, struct strbuf *err)
667+
{
668+
struct strvec args = STRVEC_INIT;
669+
670+
for (;;) {
671+
int found = 0;
672+
const char *bad_arg = arg;
673+
674+
if (!arg || !*arg)
675+
break;
676+
677+
found = describe_atom_option_parser(&args, &arg, err);
678+
if (found < 0)
679+
return found;
680+
if (!found)
681+
return err_bad_arg(err, "describe", bad_arg);
682+
}
683+
atom->u.describe_args = strvec_detach(&args);
684+
return 0;
685+
}
686+
603687
static int raw_atom_parser(struct ref_format *format UNUSED,
604688
struct used_atom *atom,
605689
const char *arg, struct strbuf *err)
@@ -802,6 +886,7 @@ static struct {
802886
[ATOM_TAGGERDATE] = { "taggerdate", SOURCE_OBJ, FIELD_TIME },
803887
[ATOM_CREATOR] = { "creator", SOURCE_OBJ },
804888
[ATOM_CREATORDATE] = { "creatordate", SOURCE_OBJ, FIELD_TIME },
889+
[ATOM_DESCRIBE] = { "describe", SOURCE_OBJ, FIELD_STR, describe_atom_parser },
805890
[ATOM_SUBJECT] = { "subject", SOURCE_OBJ, FIELD_STR, subject_atom_parser },
806891
[ATOM_BODY] = { "body", SOURCE_OBJ, FIELD_STR, body_atom_parser },
807892
[ATOM_TRAILERS] = { "trailers", SOURCE_OBJ, FIELD_STR, trailers_atom_parser },
@@ -1708,6 +1793,44 @@ static void append_lines(struct strbuf *out, const char *buf, unsigned long size
17081793
}
17091794
}
17101795

1796+
static void grab_describe_values(struct atom_value *val, int deref,
1797+
struct object *obj)
1798+
{
1799+
struct commit *commit = (struct commit *)obj;
1800+
int i;
1801+
1802+
for (i = 0; i < used_atom_cnt; i++) {
1803+
struct used_atom *atom = &used_atom[i];
1804+
enum atom_type type = atom->atom_type;
1805+
const char *name = atom->name;
1806+
struct atom_value *v = &val[i];
1807+
1808+
struct child_process cmd = CHILD_PROCESS_INIT;
1809+
struct strbuf out = STRBUF_INIT;
1810+
struct strbuf err = STRBUF_INIT;
1811+
1812+
if (type != ATOM_DESCRIBE)
1813+
continue;
1814+
1815+
if (!!deref != (*name == '*'))
1816+
continue;
1817+
1818+
cmd.git_cmd = 1;
1819+
strvec_push(&cmd.args, "describe");
1820+
strvec_pushv(&cmd.args, atom->u.describe_args);
1821+
strvec_push(&cmd.args, oid_to_hex(&commit->object.oid));
1822+
if (pipe_command(&cmd, NULL, 0, &out, 0, &err, 0) < 0) {
1823+
error(_("failed to run 'describe'"));
1824+
v->s = xstrdup("");
1825+
continue;
1826+
}
1827+
strbuf_rtrim(&out);
1828+
v->s = strbuf_detach(&out, NULL);
1829+
1830+
strbuf_release(&err);
1831+
}
1832+
}
1833+
17111834
/* See grab_values */
17121835
static void grab_sub_body_contents(struct atom_value *val, int deref, struct expand_data *data)
17131836
{
@@ -1817,13 +1940,15 @@ static void grab_values(struct atom_value *val, int deref, struct object *obj, s
18171940
grab_tag_values(val, deref, obj);
18181941
grab_sub_body_contents(val, deref, data);
18191942
grab_person("tagger", val, deref, buf);
1943+
grab_describe_values(val, deref, obj);
18201944
break;
18211945
case OBJ_COMMIT:
18221946
grab_commit_values(val, deref, obj);
18231947
grab_sub_body_contents(val, deref, data);
18241948
grab_person("author", val, deref, buf);
18251949
grab_person("committer", val, deref, buf);
18261950
grab_signature(val, deref, obj);
1951+
grab_describe_values(val, deref, obj);
18271952
break;
18281953
case OBJ_TREE:
18291954
/* grab_tree_values(val, deref, obj, buf, sz); */

t/t6300-for-each-ref.sh

Lines changed: 138 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -562,6 +562,144 @@ test_expect_success 'color.ui=always does not override tty check' '
562562
test_cmp expected.bare actual
563563
'
564564

565+
test_expect_success 'setup for describe atom tests' '
566+
git init -b master describe-repo &&
567+
(
568+
cd describe-repo &&
569+
570+
test_commit --no-tag one &&
571+
git tag tagone &&
572+
573+
test_commit --no-tag two &&
574+
git tag -a -m "tag two" tagtwo
575+
)
576+
'
577+
578+
test_expect_success 'describe atom vs git describe' '
579+
(
580+
cd describe-repo &&
581+
582+
git for-each-ref --format="%(objectname)" \
583+
refs/tags/ >obj &&
584+
while read hash
585+
do
586+
if desc=$(git describe $hash)
587+
then
588+
: >expect-contains-good
589+
else
590+
: >expect-contains-bad
591+
fi &&
592+
echo "$hash $desc" || return 1
593+
done <obj >expect &&
594+
test_path_exists expect-contains-good &&
595+
test_path_exists expect-contains-bad &&
596+
597+
git for-each-ref --format="%(objectname) %(describe)" \
598+
refs/tags/ >actual 2>err &&
599+
test_cmp expect actual &&
600+
test_must_be_empty err
601+
)
602+
'
603+
604+
test_expect_success 'describe:tags vs describe --tags' '
605+
(
606+
cd describe-repo &&
607+
git describe --tags >expect &&
608+
git for-each-ref --format="%(describe:tags)" \
609+
refs/heads/master >actual &&
610+
test_cmp expect actual
611+
)
612+
'
613+
614+
test_expect_success 'describe:abbrev=... vs describe --abbrev=...' '
615+
(
616+
cd describe-repo &&
617+
618+
# Case 1: We have commits between HEAD and the most
619+
# recent tag reachable from it
620+
test_commit --no-tag file &&
621+
git describe --abbrev=14 >expect &&
622+
git for-each-ref --format="%(describe:abbrev=14)" \
623+
refs/heads/master >actual &&
624+
test_cmp expect actual &&
625+
626+
# Make sure the hash used is atleast 14 digits long
627+
sed -e "s/^.*-g\([0-9a-f]*\)$/\1/" <actual >hexpart &&
628+
test 15 -le $(wc -c <hexpart) &&
629+
630+
# Case 2: We have a tag at HEAD, describe directly gives
631+
# the name of the tag
632+
git tag -a -m tagged tagname &&
633+
git describe --abbrev=14 >expect &&
634+
git for-each-ref --format="%(describe:abbrev=14)" \
635+
refs/heads/master >actual &&
636+
test_cmp expect actual &&
637+
test tagname = $(cat actual)
638+
)
639+
'
640+
641+
test_expect_success 'describe:match=... vs describe --match ...' '
642+
(
643+
cd describe-repo &&
644+
git tag -a -m "tag foo" tag-foo &&
645+
git describe --match "*-foo" >expect &&
646+
git for-each-ref --format="%(describe:match="*-foo")" \
647+
refs/heads/master >actual &&
648+
test_cmp expect actual
649+
)
650+
'
651+
652+
test_expect_success 'describe:exclude:... vs describe --exclude ...' '
653+
(
654+
cd describe-repo &&
655+
git tag -a -m "tag bar" tag-bar &&
656+
git describe --exclude "*-bar" >expect &&
657+
git for-each-ref --format="%(describe:exclude="*-bar")" \
658+
refs/heads/master >actual &&
659+
test_cmp expect actual
660+
)
661+
'
662+
663+
test_expect_success 'deref with describe atom' '
664+
(
665+
cd describe-repo &&
666+
cat >expect <<-\EOF &&
667+
668+
tagname
669+
tagname
670+
tagname
671+
672+
tagtwo
673+
EOF
674+
git for-each-ref --format="%(*describe)" >actual &&
675+
test_cmp expect actual
676+
)
677+
'
678+
679+
test_expect_success 'err on bad describe atom arg' '
680+
(
681+
cd describe-repo &&
682+
683+
# The bad arg is the only arg passed to describe atom
684+
cat >expect <<-\EOF &&
685+
fatal: unrecognized %(describe) argument: baz
686+
EOF
687+
test_must_fail git for-each-ref --format="%(describe:baz)" \
688+
refs/heads/master 2>actual &&
689+
test_cmp expect actual &&
690+
691+
# The bad arg is in the middle of the option string
692+
# passed to the describe atom
693+
cat >expect <<-\EOF &&
694+
fatal: unrecognized %(describe) argument: qux=1,abbrev=14
695+
EOF
696+
test_must_fail git for-each-ref \
697+
--format="%(describe:tags,qux=1,abbrev=14)" \
698+
ref/heads/master 2>actual &&
699+
test_cmp expect actual
700+
)
701+
'
702+
565703
cat >expected <<\EOF
566704
heads/main
567705
tags/main

0 commit comments

Comments
 (0)