Skip to content

Commit c758384

Browse files
committed
Merge branch 'hv/ref-filter-misc' into jch
The "--format=" option to the "for-each-ref" command and friends learned a few more tricks, e.g. the ":short" suffix that applies to "objectname" now also can be used for "parent", "tree", etc. * hv/ref-filter-misc: ref-filter: add `sanitize` option for 'subject' atom pretty: refactor `format_sanitized_subject()` ref-filter: add `short` modifier to 'parent' atom ref-filter: add `short` modifier to 'tree' atom ref-filter: rename `objectname` related functions and fields ref-filter: modify error messages in `grab_objectname()` ref-filter: refactor `grab_objectname()` ref-filter: support different email formats
2 parents 8f7620b + 905f0a4 commit c758384

File tree

5 files changed

+161
-65
lines changed

5 files changed

+161
-65
lines changed

Documentation/git-for-each-ref.txt

Lines changed: 9 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -222,6 +222,8 @@ worktreepath::
222222
In addition to the above, for commit and tag objects, the header
223223
field names (`tree`, `parent`, `object`, `type`, and `tag`) can
224224
be used to specify the value in the header field.
225+
Fields `tree` and `parent` can also be used with modifier `:short` and
226+
`:short=<length>` just like `objectname`.
225227

226228
For commit and tag objects, the special `creatordate` and `creator`
227229
fields will correspond to the appropriate date or name-email-date tuple
@@ -230,7 +232,10 @@ These are intended for working on a mix of annotated and lightweight tags.
230232

231233
Fields that have name-email-date tuple as its value (`author`,
232234
`committer`, and `tagger`) can be suffixed with `name`, `email`,
233-
and `date` to extract the named component.
235+
and `date` to extract the named component. For email fields (`authoremail`,
236+
`committeremail` and `taggeremail`), `:trim` can be appended to get the email
237+
without angle brackets, and `:localpart` to get the part before the `@` symbol
238+
out of the trimmed email.
234239

235240
The message in a commit or a tag object is `contents`, from which
236241
`contents:<part>` can be used to extract various parts out of:
@@ -242,6 +247,9 @@ contents:subject::
242247
The first paragraph of the message, which typically is a
243248
single line, is taken as the "subject" of the commit or the
244249
tag message.
250+
Instead of `contents:subject`, field `subject` can also be used to
251+
obtain same results. `:sanitize` can be appended to `subject` for
252+
subject line suitable for filename.
245253

246254
contents:body::
247255
The remainder of the commit or the tag message that follows

pretty.c

Lines changed: 11 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -839,21 +839,22 @@ static int istitlechar(char c)
839839
(c >= '0' && c <= '9') || c == '.' || c == '_';
840840
}
841841

842-
static void format_sanitized_subject(struct strbuf *sb, const char *msg)
842+
void format_sanitized_subject(struct strbuf *sb, const char *msg, size_t len)
843843
{
844844
size_t trimlen;
845845
size_t start_len = sb->len;
846846
int space = 2;
847+
int i;
847848

848-
for (; *msg && *msg != '\n'; msg++) {
849-
if (istitlechar(*msg)) {
849+
for (i = 0; i < len; i++) {
850+
if (istitlechar(msg[i])) {
850851
if (space == 1)
851852
strbuf_addch(sb, '-');
852853
space = 0;
853-
strbuf_addch(sb, *msg);
854-
if (*msg == '.')
855-
while (*(msg+1) == '.')
856-
msg++;
854+
strbuf_addch(sb, msg[i]);
855+
if (msg[i] == '.')
856+
while (msg[i+1] == '.')
857+
i++;
857858
} else
858859
space |= 1;
859860
}
@@ -1155,7 +1156,7 @@ static size_t format_commit_one(struct strbuf *sb, /* in UTF-8 */
11551156
const struct commit *commit = c->commit;
11561157
const char *msg = c->message;
11571158
struct commit_list *p;
1158-
const char *arg;
1159+
const char *arg, *eol;
11591160
size_t res;
11601161
char **slot;
11611162

@@ -1405,7 +1406,8 @@ static size_t format_commit_one(struct strbuf *sb, /* in UTF-8 */
14051406
format_subject(sb, msg + c->subject_off, " ");
14061407
return 1;
14071408
case 'f': /* sanitized subject */
1408-
format_sanitized_subject(sb, msg + c->subject_off);
1409+
eol = strchrnul(msg + c->subject_off, '\n');
1410+
format_sanitized_subject(sb, msg + c->subject_off, eol - (msg + c->subject_off));
14091411
return 1;
14101412
case 'b': /* body */
14111413
strbuf_addstr(sb, msg + c->body_off);

pretty.h

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -139,4 +139,7 @@ const char *format_subject(struct strbuf *sb, const char *msg,
139139
/* Check if "cmit_fmt" will produce an empty output. */
140140
int commit_format_is_empty(enum cmit_fmt);
141141

142+
/* Make subject of commit message suitable for filename */
143+
void format_sanitized_subject(struct strbuf *sb, const char *msg, size_t len);
144+
142145
#endif /* PRETTY_H */

ref-filter.c

Lines changed: 103 additions & 55 deletions
Original file line numberDiff line numberDiff line change
@@ -127,8 +127,8 @@ static struct used_atom {
127127
unsigned int nobracket : 1, push : 1, push_remote : 1;
128128
} remote_ref;
129129
struct {
130-
enum { C_BARE, C_BODY, C_BODY_DEP, C_LENGTH,
131-
C_LINES, C_SIG, C_SUB, C_TRAILERS } option;
130+
enum { C_BARE, C_BODY, C_BODY_DEP, C_LENGTH, C_LINES,
131+
C_SIG, C_SUB, C_SUB_SANITIZE, C_TRAILERS } option;
132132
struct process_trailer_options trailer_opts;
133133
unsigned int nlines;
134134
} contents;
@@ -139,7 +139,10 @@ static struct used_atom {
139139
struct {
140140
enum { O_FULL, O_LENGTH, O_SHORT } option;
141141
unsigned int length;
142-
} objectname;
142+
} oid;
143+
struct email_option {
144+
enum { EO_RAW, EO_TRIM, EO_LOCALPART } option;
145+
} email_option;
143146
struct refname_atom refname;
144147
char *head;
145148
} u;
@@ -298,9 +301,12 @@ static int body_atom_parser(const struct ref_format *format, struct used_atom *a
298301
static int subject_atom_parser(const struct ref_format *format, struct used_atom *atom,
299302
const char *arg, struct strbuf *err)
300303
{
301-
if (arg)
302-
return strbuf_addf_ret(err, -1, _("%%(subject) does not take arguments"));
303-
atom->u.contents.option = C_SUB;
304+
if (!arg)
305+
atom->u.contents.option = C_SUB;
306+
else if (!strcmp(arg, "sanitize"))
307+
atom->u.contents.option = C_SUB_SANITIZE;
308+
else
309+
return strbuf_addf_ret(err, -1, _("unrecognized %%(subject) argument: %s"), arg);
304310
return 0;
305311
}
306312

@@ -360,22 +366,36 @@ static int contents_atom_parser(const struct ref_format *format, struct used_ato
360366
return 0;
361367
}
362368

363-
static int objectname_atom_parser(const struct ref_format *format, struct used_atom *atom,
364-
const char *arg, struct strbuf *err)
369+
static int oid_atom_parser(const struct ref_format *format, struct used_atom *atom,
370+
const char *arg, struct strbuf *err)
365371
{
366372
if (!arg)
367-
atom->u.objectname.option = O_FULL;
373+
atom->u.oid.option = O_FULL;
368374
else if (!strcmp(arg, "short"))
369-
atom->u.objectname.option = O_SHORT;
375+
atom->u.oid.option = O_SHORT;
370376
else if (skip_prefix(arg, "short=", &arg)) {
371-
atom->u.objectname.option = O_LENGTH;
372-
if (strtoul_ui(arg, 10, &atom->u.objectname.length) ||
373-
atom->u.objectname.length == 0)
374-
return strbuf_addf_ret(err, -1, _("positive value expected objectname:short=%s"), arg);
375-
if (atom->u.objectname.length < MINIMUM_ABBREV)
376-
atom->u.objectname.length = MINIMUM_ABBREV;
377+
atom->u.oid.option = O_LENGTH;
378+
if (strtoul_ui(arg, 10, &atom->u.oid.length) ||
379+
atom->u.oid.length == 0)
380+
return strbuf_addf_ret(err, -1, _("positive value expected '%s' in %%(%s)"), arg, atom->name);
381+
if (atom->u.oid.length < MINIMUM_ABBREV)
382+
atom->u.oid.length = MINIMUM_ABBREV;
377383
} else
378-
return strbuf_addf_ret(err, -1, _("unrecognized %%(objectname) argument: %s"), arg);
384+
return strbuf_addf_ret(err, -1, _("unrecognized argument '%s' in %%(%s)"), arg, atom->name);
385+
return 0;
386+
}
387+
388+
static int person_email_atom_parser(const struct ref_format *format, struct used_atom *atom,
389+
const char *arg, struct strbuf *err)
390+
{
391+
if (!arg)
392+
atom->u.email_option.option = EO_RAW;
393+
else if (!strcmp(arg, "trim"))
394+
atom->u.email_option.option = EO_TRIM;
395+
else if (!strcmp(arg, "localpart"))
396+
atom->u.email_option.option = EO_LOCALPART;
397+
else
398+
return strbuf_addf_ret(err, -1, _("unrecognized email option: %s"), arg);
379399
return 0;
380400
}
381401

@@ -480,25 +500,25 @@ static struct {
480500
{ "refname", SOURCE_NONE, FIELD_STR, refname_atom_parser },
481501
{ "objecttype", SOURCE_OTHER, FIELD_STR, objecttype_atom_parser },
482502
{ "objectsize", SOURCE_OTHER, FIELD_ULONG, objectsize_atom_parser },
483-
{ "objectname", SOURCE_OTHER, FIELD_STR, objectname_atom_parser },
503+
{ "objectname", SOURCE_OTHER, FIELD_STR, oid_atom_parser },
484504
{ "deltabase", SOURCE_OTHER, FIELD_STR, deltabase_atom_parser },
485-
{ "tree", SOURCE_OBJ },
486-
{ "parent", SOURCE_OBJ },
505+
{ "tree", SOURCE_OBJ, FIELD_STR, oid_atom_parser },
506+
{ "parent", SOURCE_OBJ, FIELD_STR, oid_atom_parser },
487507
{ "numparent", SOURCE_OBJ, FIELD_ULONG },
488508
{ "object", SOURCE_OBJ },
489509
{ "type", SOURCE_OBJ },
490510
{ "tag", SOURCE_OBJ },
491511
{ "author", SOURCE_OBJ },
492512
{ "authorname", SOURCE_OBJ },
493-
{ "authoremail", SOURCE_OBJ },
513+
{ "authoremail", SOURCE_OBJ, FIELD_STR, person_email_atom_parser },
494514
{ "authordate", SOURCE_OBJ, FIELD_TIME },
495515
{ "committer", SOURCE_OBJ },
496516
{ "committername", SOURCE_OBJ },
497-
{ "committeremail", SOURCE_OBJ },
517+
{ "committeremail", SOURCE_OBJ, FIELD_STR, person_email_atom_parser },
498518
{ "committerdate", SOURCE_OBJ, FIELD_TIME },
499519
{ "tagger", SOURCE_OBJ },
500520
{ "taggername", SOURCE_OBJ },
501-
{ "taggeremail", SOURCE_OBJ },
521+
{ "taggeremail", SOURCE_OBJ, FIELD_STR, person_email_atom_parser },
502522
{ "taggerdate", SOURCE_OBJ, FIELD_TIME },
503523
{ "creator", SOURCE_OBJ },
504524
{ "creatordate", SOURCE_OBJ, FIELD_TIME },
@@ -903,21 +923,27 @@ int verify_ref_format(struct ref_format *format)
903923
return 0;
904924
}
905925

906-
static int grab_objectname(const char *name, const struct object_id *oid,
907-
struct atom_value *v, struct used_atom *atom)
926+
static const char *do_grab_oid(const char *field, const struct object_id *oid,
927+
struct used_atom *atom)
908928
{
909-
if (starts_with(name, "objectname")) {
910-
if (atom->u.objectname.option == O_SHORT) {
911-
v->s = xstrdup(find_unique_abbrev(oid, DEFAULT_ABBREV));
912-
return 1;
913-
} else if (atom->u.objectname.option == O_FULL) {
914-
v->s = xstrdup(oid_to_hex(oid));
915-
return 1;
916-
} else if (atom->u.objectname.option == O_LENGTH) {
917-
v->s = xstrdup(find_unique_abbrev(oid, atom->u.objectname.length));
918-
return 1;
919-
} else
920-
BUG("unknown %%(objectname) option");
929+
switch (atom->u.oid.option) {
930+
case O_FULL:
931+
return oid_to_hex(oid);
932+
case O_LENGTH:
933+
return find_unique_abbrev(oid, atom->u.oid.length);
934+
case O_SHORT:
935+
return find_unique_abbrev(oid, DEFAULT_ABBREV);
936+
default:
937+
BUG("unknown %%(%s) option", field);
938+
}
939+
}
940+
941+
static int grab_oid(const char *name, const char *field, const struct object_id *oid,
942+
struct atom_value *v, struct used_atom *atom)
943+
{
944+
if (starts_with(name, field)) {
945+
v->s = xstrdup(do_grab_oid(field, oid, atom));
946+
return 1;
921947
}
922948
return 0;
923949
}
@@ -945,7 +971,7 @@ static void grab_common_values(struct atom_value *val, int deref, struct expand_
945971
} else if (!strcmp(name, "deltabase"))
946972
v->s = xstrdup(oid_to_hex(&oi->delta_base_oid));
947973
else if (deref)
948-
grab_objectname(name, &oi->oid, v, &used_atom[i]);
974+
grab_oid(name, "objectname", &oi->oid, v, &used_atom[i]);
949975
}
950976
}
951977

@@ -984,21 +1010,20 @@ static void grab_commit_values(struct atom_value *val, int deref, struct object
9841010
continue;
9851011
if (deref)
9861012
name++;
987-
if (!strcmp(name, "tree")) {
988-
v->s = xstrdup(oid_to_hex(get_commit_tree_oid(commit)));
989-
}
990-
else if (!strcmp(name, "numparent")) {
1013+
if (grab_oid(name, "tree", get_commit_tree_oid(commit), v, &used_atom[i]))
1014+
continue;
1015+
if (!strcmp(name, "numparent")) {
9911016
v->value = commit_list_count(commit->parents);
9921017
v->s = xstrfmt("%lu", (unsigned long)v->value);
9931018
}
994-
else if (!strcmp(name, "parent")) {
1019+
else if (starts_with(name, "parent")) {
9951020
struct commit_list *parents;
9961021
struct strbuf s = STRBUF_INIT;
9971022
for (parents = commit->parents; parents; parents = parents->next) {
998-
struct commit *parent = parents->item;
1023+
struct object_id *oid = &parents->item->object.oid;
9991024
if (parents != commit->parents)
10001025
strbuf_addch(&s, ' ');
1001-
strbuf_addstr(&s, oid_to_hex(&parent->object.oid));
1026+
strbuf_addstr(&s, do_grab_oid("parent", oid, &used_atom[i]));
10021027
}
10031028
v->s = strbuf_detach(&s, NULL);
10041029
}
@@ -1039,16 +1064,35 @@ static const char *copy_name(const char *buf)
10391064
return xstrdup("");
10401065
}
10411066

1042-
static const char *copy_email(const char *buf)
1067+
static const char *copy_email(const char *buf, struct used_atom *atom)
10431068
{
10441069
const char *email = strchr(buf, '<');
10451070
const char *eoemail;
10461071
if (!email)
10471072
return xstrdup("");
1048-
eoemail = strchr(email, '>');
1073+
switch (atom->u.email_option.option) {
1074+
case EO_RAW:
1075+
eoemail = strchr(email, '>');
1076+
if (eoemail)
1077+
eoemail++;
1078+
break;
1079+
case EO_TRIM:
1080+
email++;
1081+
eoemail = strchr(email, '>');
1082+
break;
1083+
case EO_LOCALPART:
1084+
email++;
1085+
eoemail = strchr(email, '@');
1086+
if (!eoemail)
1087+
eoemail = strchr(email, '>');
1088+
break;
1089+
default:
1090+
BUG("unknown email option");
1091+
}
1092+
10491093
if (!eoemail)
10501094
return xstrdup("");
1051-
return xmemdupz(email, eoemail + 1 - email);
1095+
return xmemdupz(email, eoemail - email);
10521096
}
10531097

10541098
static char *copy_subject(const char *buf, unsigned long len)
@@ -1118,7 +1162,7 @@ static void grab_person(const char *who, struct atom_value *val, int deref, void
11181162
continue;
11191163
if (name[wholen] != 0 &&
11201164
strcmp(name + wholen, "name") &&
1121-
strcmp(name + wholen, "email") &&
1165+
!starts_with(name + wholen, "email") &&
11221166
!starts_with(name + wholen, "date"))
11231167
continue;
11241168
if (!wholine)
@@ -1129,8 +1173,8 @@ static void grab_person(const char *who, struct atom_value *val, int deref, void
11291173
v->s = copy_line(wholine);
11301174
else if (!strcmp(name + wholen, "name"))
11311175
v->s = copy_name(wholine);
1132-
else if (!strcmp(name + wholen, "email"))
1133-
v->s = copy_email(wholine);
1176+
else if (starts_with(name + wholen, "email"))
1177+
v->s = copy_email(wholine, &used_atom[i]);
11341178
else if (starts_with(name + wholen, "date"))
11351179
grab_date(wholine, v, name);
11361180
}
@@ -1243,8 +1287,8 @@ static void grab_sub_body_contents(struct atom_value *val, int deref, void *buf)
12431287
continue;
12441288
if (deref)
12451289
name++;
1246-
if (strcmp(name, "subject") &&
1247-
strcmp(name, "body") &&
1290+
if (strcmp(name, "body") &&
1291+
!starts_with(name, "subject") &&
12481292
!starts_with(name, "trailers") &&
12491293
!starts_with(name, "contents"))
12501294
continue;
@@ -1256,7 +1300,11 @@ static void grab_sub_body_contents(struct atom_value *val, int deref, void *buf)
12561300

12571301
if (atom->u.contents.option == C_SUB)
12581302
v->s = copy_subject(subpos, sublen);
1259-
else if (atom->u.contents.option == C_BODY_DEP)
1303+
else if (atom->u.contents.option == C_SUB_SANITIZE) {
1304+
struct strbuf sb = STRBUF_INIT;
1305+
format_sanitized_subject(&sb, subpos, sublen);
1306+
v->s = strbuf_detach(&sb, NULL);
1307+
} else if (atom->u.contents.option == C_BODY_DEP)
12601308
v->s = xmemdupz(bodypos, bodylen);
12611309
else if (atom->u.contents.option == C_LENGTH)
12621310
v->s = xstrfmt("%"PRIuMAX, (uintmax_t)strlen(subpos));
@@ -1706,7 +1754,7 @@ static int populate_value(struct ref_array_item *ref, struct strbuf *err)
17061754
v->s = xstrdup(buf + 1);
17071755
}
17081756
continue;
1709-
} else if (!deref && grab_objectname(name, &ref->objectname, v, atom)) {
1757+
} else if (!deref && grab_oid(name, "objectname", &ref->objectname, v, atom)) {
17101758
continue;
17111759
} else if (!strcmp(name, "HEAD")) {
17121760
if (atom->u.head && !strcmp(ref->refname, atom->u.head))

0 commit comments

Comments
 (0)