revision: improve commit_rewrite_person()

The function, commit_rewrite_person(), is designed to find and replace an ident string in the header part, and the way it avoids a random occurrence of "author A U Thor <author@example.com" in the text is by insisting "author" to appear at the beginning of line by passing "\nauthor " as "what". The implementation also doesn't make any effort to limit itself to the commit header by locating the blank line that appears after the header part and stopping the search there. Also, the interface forces the caller to make multiple calls if it wants to rewrite idents on multiple headers. It shouldn't be the case. To support the existing caller better, update commit_rewrite_person() to: - Make a single pass in the input buffer to locate headers named "author" and "committer" and replace idents on them. - Stop at the end of the header, ensuring that nothing in the body of the commit object is modified. The return type of the function commit_rewrite_person() has also been changed from int to void. This has been done because the caller of the function doesn't do anything with the return value of the function. By simplifying the interface of the commit_rewrite_person(), we also intend to expose it as a public function. We will also be renaming the function in a future commit to a different name which clearly tells that the function replaces idents in the header of the commit buffer. Mentored-by: Christian Couder <christian.couder@gmail.com> Mentored-by: John Cai <johncai86@gmail.com> Helped-by: Đoàn Trần Công Danh <congdanhqx@gmail.com> Helped-by: Johannes Schindelin <Johannes.Schindelin@gmx.de> Signed-off-by: Siddharth Asthana <siddharthasthana31@gmail.com> Signed-off-by: Junio C Hamano <gitster@pobox.com>

Siddharth Asthana committed Jul 19, 2022 at 01:20 UTC e9c1b0e38cbaf626034c3741cc68f7d706aee451
1 file changed +47 -17
revision.c
+47 -17
@@ -3755,25 +3755,18 @@ int rewrite_parents(struct rev_info *revs, struct commit *commit,
3755 return 0;
3756 }
3757
3758 -static int commit_rewrite_person(struct strbuf *buf, const char *what, struct string_list *mailmap)
3758 +/*
3759 + * Returns the difference between the new and old length of the ident line.
3760 + */
3761 +static ssize_t rewrite_ident_line(const char *person, size_t len,
3762 + struct strbuf *buf,
3763 + struct string_list *mailmap)
3764 {
3760 - char *person, *endp;
3761 - size_t len, namelen, maillen;
3765 + size_t namelen, maillen;
3766 const char *name;
3767 const char *mail;
3768 struct ident_split ident;
3769
3766 - person = strstr(buf->buf, what);
3767 - if (!person)
3768 - return 0;
3769 -
3770 - person += strlen(what);
3771 - endp = strchr(person, '\n');
3772 - if (!endp)
3773 - return 0;
3774 -
3775 - len = endp - person;
3776 -
3770 if (split_ident_line(&ident, person, len))
3771 return 0;
3772
@@ -3784,6 +3777,7 @@ static int commit_rewrite_person(struct strbuf *buf, const char *what, struct st
3777
3778 if (map_user(mailmap, &mail, &maillen, &name, &namelen)) {
3779 struct strbuf namemail = STRBUF_INIT;
3780 + size_t newlen;
3781
3782 strbuf_addf(&namemail, "%.*s <%.*s>",
3783 (int)namelen, name, (int)maillen, mail);
@@ -3791,15 +3785,50 @@ static int commit_rewrite_person(struct strbuf *buf, const char *what, struct st
3785 strbuf_splice(buf, ident.name_begin - buf->buf,
3786 ident.mail_end - ident.name_begin + 1,
3787 namemail.buf, namemail.len);
3788 + newlen = namemail.len;
3789
3790 strbuf_release(&namemail);
3791
3797 - return 1;
3792 + return newlen - (ident.mail_end - ident.name_begin);
3793 }
3794
3795 return 0;
3796 }
3797
3798 +static void commit_rewrite_person(struct strbuf *buf, const char **header,
3799 + struct string_list *mailmap)
3800 +{
3801 + size_t buf_offset = 0;
3802 +
3803 + if (!mailmap)
3804 + return;
3805 +
3806 + for (;;) {
3807 + const char *person, *line;
3808 + size_t i;
3809 + int found_header = 0;
3810 +
3811 + line = buf->buf + buf_offset;
3812 + if (!*line || *line == '\n')
3813 + return; /* End of headers */
3814 +
3815 + for (i = 0; header[i]; i++)
3816 + if (skip_prefix(line, header[i], &person)) {
3817 + const char *endp = strchrnul(person, '\n');
3818 + found_header = 1;
3819 + buf_offset += endp - line;
3820 + buf_offset += rewrite_ident_line(person, endp - person, buf, mailmap);
3821 + break;
3822 + }
3823 +
3824 + if (!found_header) {
3825 + buf_offset = strchrnul(line, '\n') - buf->buf;
3826 + if (buf->buf[buf_offset] == '\n')
3827 + buf_offset++;
3828 + }
3829 + }
3830 +}
3831 +
3832 static int commit_match(struct commit *commit, struct rev_info *opt)
3833 {
3834 int retval;
@@ -3832,11 +3861,12 @@ static int commit_match(struct commit *commit, struct rev_info *opt)
3861 strbuf_addstr(&buf, message);
3862
3863 if (opt->grep_filter.header_list && opt->mailmap) {
3864 + const char *commit_headers[] = { "author ", "committer ", NULL };
3865 +
3866 if (!buf.len)
3867 strbuf_addstr(&buf, message);
3868
3838 - commit_rewrite_person(&buf, "\nauthor ", opt->mailmap);
3839 - commit_rewrite_person(&buf, "\ncommitter ", opt->mailmap);
3869 + commit_rewrite_person(&buf, commit_headers, opt->mailmap);
3870 }
3871
3872 /* Append "fake" message parts as needed */