|
13 | 13 | #include "oid-array.h"
|
14 | 14 | #include "repository.h"
|
15 | 15 | #include "commit.h"
|
| 16 | +#include "mailmap.h" |
| 17 | +#include "ident.h" |
16 | 18 | #include "remote.h"
|
17 | 19 | #include "color.h"
|
18 | 20 | #include "tag.h"
|
@@ -215,8 +217,16 @@ static struct used_atom {
|
215 | 217 | struct {
|
216 | 218 | enum { O_SIZE, O_SIZE_DISK } option;
|
217 | 219 | } objectsize;
|
218 |
| - struct email_option { |
219 |
| - enum { EO_RAW, EO_TRIM, EO_LOCALPART } option; |
| 220 | + struct { |
| 221 | + enum { N_RAW, N_MAILMAP } option; |
| 222 | + } name_option; |
| 223 | + struct { |
| 224 | + enum { |
| 225 | + EO_RAW = 0, |
| 226 | + EO_TRIM = 1<<0, |
| 227 | + EO_LOCALPART = 1<<1, |
| 228 | + EO_MAILMAP = 1<<2, |
| 229 | + } option; |
220 | 230 | } email_option;
|
221 | 231 | struct {
|
222 | 232 | enum { S_BARE, S_GRADE, S_SIGNER, S_KEY,
|
@@ -720,21 +730,55 @@ static int oid_atom_parser(struct ref_format *format UNUSED,
|
720 | 730 | return 0;
|
721 | 731 | }
|
722 | 732 |
|
723 |
| -static int person_email_atom_parser(struct ref_format *format UNUSED, |
724 |
| - struct used_atom *atom, |
725 |
| - const char *arg, struct strbuf *err) |
| 733 | +static int person_name_atom_parser(struct ref_format *format UNUSED, |
| 734 | + struct used_atom *atom, |
| 735 | + const char *arg, struct strbuf *err) |
726 | 736 | {
|
727 | 737 | if (!arg)
|
728 |
| - atom->u.email_option.option = EO_RAW; |
729 |
| - else if (!strcmp(arg, "trim")) |
730 |
| - atom->u.email_option.option = EO_TRIM; |
731 |
| - else if (!strcmp(arg, "localpart")) |
732 |
| - atom->u.email_option.option = EO_LOCALPART; |
| 738 | + atom->u.name_option.option = N_RAW; |
| 739 | + else if (!strcmp(arg, "mailmap")) |
| 740 | + atom->u.name_option.option = N_MAILMAP; |
733 | 741 | else
|
734 | 742 | return err_bad_arg(err, atom->name, arg);
|
735 | 743 | return 0;
|
736 | 744 | }
|
737 | 745 |
|
| 746 | +static int email_atom_option_parser(struct used_atom *atom, |
| 747 | + const char **arg, struct strbuf *err) |
| 748 | +{ |
| 749 | + if (!*arg) |
| 750 | + return EO_RAW; |
| 751 | + if (skip_prefix(*arg, "trim", arg)) |
| 752 | + return EO_TRIM; |
| 753 | + if (skip_prefix(*arg, "localpart", arg)) |
| 754 | + return EO_LOCALPART; |
| 755 | + if (skip_prefix(*arg, "mailmap", arg)) |
| 756 | + return EO_MAILMAP; |
| 757 | + return -1; |
| 758 | +} |
| 759 | + |
| 760 | +static int person_email_atom_parser(struct ref_format *format UNUSED, |
| 761 | + struct used_atom *atom, |
| 762 | + const char *arg, struct strbuf *err) |
| 763 | +{ |
| 764 | + for (;;) { |
| 765 | + int opt = email_atom_option_parser(atom, &arg, err); |
| 766 | + const char *bad_arg = arg; |
| 767 | + |
| 768 | + if (opt < 0) |
| 769 | + return err_bad_arg(err, atom->name, bad_arg); |
| 770 | + atom->u.email_option.option |= opt; |
| 771 | + |
| 772 | + if (!arg || !*arg) |
| 773 | + break; |
| 774 | + if (*arg == ',') |
| 775 | + arg++; |
| 776 | + else |
| 777 | + return err_bad_arg(err, atom->name, bad_arg); |
| 778 | + } |
| 779 | + return 0; |
| 780 | +} |
| 781 | + |
738 | 782 | static int refname_atom_parser(struct ref_format *format UNUSED,
|
739 | 783 | struct used_atom *atom,
|
740 | 784 | const char *arg, struct strbuf *err)
|
@@ -877,15 +921,15 @@ static struct {
|
877 | 921 | [ATOM_TYPE] = { "type", SOURCE_OBJ },
|
878 | 922 | [ATOM_TAG] = { "tag", SOURCE_OBJ },
|
879 | 923 | [ATOM_AUTHOR] = { "author", SOURCE_OBJ },
|
880 |
| - [ATOM_AUTHORNAME] = { "authorname", SOURCE_OBJ }, |
| 924 | + [ATOM_AUTHORNAME] = { "authorname", SOURCE_OBJ, FIELD_STR, person_name_atom_parser }, |
881 | 925 | [ATOM_AUTHOREMAIL] = { "authoremail", SOURCE_OBJ, FIELD_STR, person_email_atom_parser },
|
882 | 926 | [ATOM_AUTHORDATE] = { "authordate", SOURCE_OBJ, FIELD_TIME },
|
883 | 927 | [ATOM_COMMITTER] = { "committer", SOURCE_OBJ },
|
884 |
| - [ATOM_COMMITTERNAME] = { "committername", SOURCE_OBJ }, |
| 928 | + [ATOM_COMMITTERNAME] = { "committername", SOURCE_OBJ, FIELD_STR, person_name_atom_parser }, |
885 | 929 | [ATOM_COMMITTEREMAIL] = { "committeremail", SOURCE_OBJ, FIELD_STR, person_email_atom_parser },
|
886 | 930 | [ATOM_COMMITTERDATE] = { "committerdate", SOURCE_OBJ, FIELD_TIME },
|
887 | 931 | [ATOM_TAGGER] = { "tagger", SOURCE_OBJ },
|
888 |
| - [ATOM_TAGGERNAME] = { "taggername", SOURCE_OBJ }, |
| 932 | + [ATOM_TAGGERNAME] = { "taggername", SOURCE_OBJ, FIELD_STR, person_name_atom_parser }, |
889 | 933 | [ATOM_TAGGEREMAIL] = { "taggeremail", SOURCE_OBJ, FIELD_STR, person_email_atom_parser },
|
890 | 934 | [ATOM_TAGGERDATE] = { "taggerdate", SOURCE_OBJ, FIELD_TIME },
|
891 | 935 | [ATOM_CREATOR] = { "creator", SOURCE_OBJ },
|
@@ -1486,32 +1530,49 @@ static const char *copy_name(const char *buf)
|
1486 | 1530 | return xstrdup("");
|
1487 | 1531 | }
|
1488 | 1532 |
|
| 1533 | +static const char *find_end_of_email(const char *email, int opt) |
| 1534 | +{ |
| 1535 | + const char *eoemail; |
| 1536 | + |
| 1537 | + if (opt & EO_LOCALPART) { |
| 1538 | + eoemail = strchr(email, '@'); |
| 1539 | + if (eoemail) |
| 1540 | + return eoemail; |
| 1541 | + return strchr(email, '>'); |
| 1542 | + } |
| 1543 | + |
| 1544 | + if (opt & EO_TRIM) |
| 1545 | + return strchr(email, '>'); |
| 1546 | + |
| 1547 | + /* |
| 1548 | + * The option here is either the raw email option or the raw |
| 1549 | + * mailmap option (that is EO_RAW or EO_MAILMAP). In such cases, |
| 1550 | + * we directly grab the whole email including the closing |
| 1551 | + * angle brackets. |
| 1552 | + * |
| 1553 | + * If EO_MAILMAP was set with any other option (that is either |
| 1554 | + * EO_TRIM or EO_LOCALPART), we already grab the end of email |
| 1555 | + * above. |
| 1556 | + */ |
| 1557 | + eoemail = strchr(email, '>'); |
| 1558 | + if (eoemail) |
| 1559 | + eoemail++; |
| 1560 | + return eoemail; |
| 1561 | +} |
| 1562 | + |
1489 | 1563 | static const char *copy_email(const char *buf, struct used_atom *atom)
|
1490 | 1564 | {
|
1491 | 1565 | const char *email = strchr(buf, '<');
|
1492 | 1566 | const char *eoemail;
|
| 1567 | + int opt = atom->u.email_option.option; |
| 1568 | + |
1493 | 1569 | if (!email)
|
1494 | 1570 | return xstrdup("");
|
1495 |
| - switch (atom->u.email_option.option) { |
1496 |
| - case EO_RAW: |
1497 |
| - eoemail = strchr(email, '>'); |
1498 |
| - if (eoemail) |
1499 |
| - eoemail++; |
1500 |
| - break; |
1501 |
| - case EO_TRIM: |
1502 |
| - email++; |
1503 |
| - eoemail = strchr(email, '>'); |
1504 |
| - break; |
1505 |
| - case EO_LOCALPART: |
| 1571 | + |
| 1572 | + if (opt & (EO_LOCALPART | EO_TRIM)) |
1506 | 1573 | email++;
|
1507 |
| - eoemail = strchr(email, '@'); |
1508 |
| - if (!eoemail) |
1509 |
| - eoemail = strchr(email, '>'); |
1510 |
| - break; |
1511 |
| - default: |
1512 |
| - BUG("unknown email option"); |
1513 |
| - } |
1514 | 1574 |
|
| 1575 | + eoemail = find_end_of_email(email, opt); |
1515 | 1576 | if (!eoemail)
|
1516 | 1577 | return xstrdup("");
|
1517 | 1578 | return xmemdupz(email, eoemail - email);
|
@@ -1572,39 +1633,60 @@ static void grab_date(const char *buf, struct atom_value *v, const char *atomnam
|
1572 | 1633 | v->value = 0;
|
1573 | 1634 | }
|
1574 | 1635 |
|
| 1636 | +static struct string_list mailmap = STRING_LIST_INIT_NODUP; |
| 1637 | + |
1575 | 1638 | /* See grab_values */
|
1576 | 1639 | static void grab_person(const char *who, struct atom_value *val, int deref, void *buf)
|
1577 | 1640 | {
|
1578 | 1641 | int i;
|
1579 | 1642 | int wholen = strlen(who);
|
1580 | 1643 | const char *wholine = NULL;
|
| 1644 | + const char *headers[] = { "author ", "committer ", |
| 1645 | + "tagger ", NULL }; |
1581 | 1646 |
|
1582 | 1647 | for (i = 0; i < used_atom_cnt; i++) {
|
1583 |
| - const char *name = used_atom[i].name; |
| 1648 | + struct used_atom *atom = &used_atom[i]; |
| 1649 | + const char *name = atom->name; |
1584 | 1650 | struct atom_value *v = &val[i];
|
| 1651 | + struct strbuf mailmap_buf = STRBUF_INIT; |
| 1652 | + |
1585 | 1653 | if (!!deref != (*name == '*'))
|
1586 | 1654 | continue;
|
1587 | 1655 | if (deref)
|
1588 | 1656 | name++;
|
1589 | 1657 | if (strncmp(who, name, wholen))
|
1590 | 1658 | continue;
|
1591 | 1659 | if (name[wholen] != 0 &&
|
1592 |
| - strcmp(name + wholen, "name") && |
| 1660 | + !starts_with(name + wholen, "name") && |
1593 | 1661 | !starts_with(name + wholen, "email") &&
|
1594 | 1662 | !starts_with(name + wholen, "date"))
|
1595 | 1663 | continue;
|
1596 |
| - if (!wholine) |
| 1664 | + |
| 1665 | + if ((starts_with(name + wholen, "name") && |
| 1666 | + (atom->u.name_option.option == N_MAILMAP)) || |
| 1667 | + (starts_with(name + wholen, "email") && |
| 1668 | + (atom->u.email_option.option & EO_MAILMAP))) { |
| 1669 | + if (!mailmap.items) |
| 1670 | + read_mailmap(&mailmap); |
| 1671 | + strbuf_addstr(&mailmap_buf, buf); |
| 1672 | + apply_mailmap_to_header(&mailmap_buf, headers, &mailmap); |
| 1673 | + wholine = find_wholine(who, wholen, mailmap_buf.buf); |
| 1674 | + } else { |
1597 | 1675 | wholine = find_wholine(who, wholen, buf);
|
| 1676 | + } |
| 1677 | + |
1598 | 1678 | if (!wholine)
|
1599 | 1679 | return; /* no point looking for it */
|
1600 | 1680 | if (name[wholen] == 0)
|
1601 | 1681 | v->s = copy_line(wholine);
|
1602 |
| - else if (!strcmp(name + wholen, "name")) |
| 1682 | + else if (starts_with(name + wholen, "name")) |
1603 | 1683 | v->s = copy_name(wholine);
|
1604 | 1684 | else if (starts_with(name + wholen, "email"))
|
1605 | 1685 | v->s = copy_email(wholine, &used_atom[i]);
|
1606 | 1686 | else if (starts_with(name + wholen, "date"))
|
1607 | 1687 | grab_date(wholine, v, name);
|
| 1688 | + |
| 1689 | + strbuf_release(&mailmap_buf); |
1608 | 1690 | }
|
1609 | 1691 |
|
1610 | 1692 | /*
|
|
0 commit comments