pretty: support "mboxrd" output format

This output format prevents format-patch output from breaking
readers if somebody copy+pasted an mbox into a commit message.

Unlike the traditional "mboxo" format, "mboxrd" is designed to
be fully-reversible.  "mboxrd" also gracefully degrades to
showing extra ">" in existing "mboxo" readers.

This degradation is preferable to breaking message splitting
completely, a problem I've seen in "mboxcl" due to having
multiple, non-existent, or inaccurate Content-Length headers.

"mboxcl2" is a non-starter since it's inherits the problems
of "mboxcl" while being completely incompatible with existing
tooling based around mailsplit.

ref: http://homepage.ntlworld.com/jonathan.deboynepollard/FGA/mail-mbox-formats.html

Signed-off-by: Eric Wong <e@80x24.org>
Signed-off-by: Junio C Hamano <gitster@pobox.com>
This commit is contained in:
Eric Wong
2016-06-05 04:46:39 +00:00
committed by Junio C Hamano
parent 6326f19925
commit 9f23e04061
5 changed files with 75 additions and 11 deletions

View File

@ -92,6 +92,7 @@ static void setup_commit_formats(void)
{ "medium", CMIT_FMT_MEDIUM, 0, 8 },
{ "short", CMIT_FMT_SHORT, 0, 0 },
{ "email", CMIT_FMT_EMAIL, 0, 0 },
{ "mboxrd", CMIT_FMT_MBOXRD, 0, 0 },
{ "fuller", CMIT_FMT_FULLER, 0, 8 },
{ "full", CMIT_FMT_FULL, 0, 8 },
{ "oneline", CMIT_FMT_ONELINE, 1, 0 }
@ -444,7 +445,7 @@ void pp_user_info(struct pretty_print_context *pp,
if (pp->mailmap)
map_user(pp->mailmap, &mailbuf, &maillen, &namebuf, &namelen);
if (pp->fmt == CMIT_FMT_EMAIL) {
if (cmit_fmt_is_mail(pp->fmt)) {
if (pp->from_ident && ident_cmp(pp->from_ident, &ident)) {
struct strbuf buf = STRBUF_INIT;
@ -494,6 +495,7 @@ void pp_user_info(struct pretty_print_context *pp,
show_ident_date(&ident, &pp->date_mode));
break;
case CMIT_FMT_EMAIL:
case CMIT_FMT_MBOXRD:
strbuf_addf(sb, "Date: %s\n",
show_ident_date(&ident, DATE_MODE(RFC2822)));
break;
@ -535,7 +537,7 @@ static void add_merge_info(const struct pretty_print_context *pp,
{
struct commit_list *parent = commit->parents;
if ((pp->fmt == CMIT_FMT_ONELINE) || (pp->fmt == CMIT_FMT_EMAIL) ||
if ((pp->fmt == CMIT_FMT_ONELINE) || (cmit_fmt_is_mail(pp->fmt)) ||
!parent || !parent->next)
return;
@ -1614,7 +1616,7 @@ void pp_title_line(struct pretty_print_context *pp,
if (pp->after_subject) {
strbuf_addstr(sb, pp->after_subject);
}
if (pp->fmt == CMIT_FMT_EMAIL) {
if (cmit_fmt_is_mail(pp->fmt)) {
strbuf_addch(sb, '\n');
}
@ -1697,6 +1699,16 @@ static void pp_handle_indent(struct pretty_print_context *pp,
strbuf_add(sb, line, linelen);
}
static int is_mboxrd_from(const char *line, int len)
{
/*
* a line matching /^From $/ here would only have len == 4
* at this point because is_empty_line would've trimmed all
* trailing space
*/
return len > 4 && starts_with(line + strspn(line, ">"), "From ");
}
void pp_remainder(struct pretty_print_context *pp,
const char **msg_p,
struct strbuf *sb,
@ -1725,8 +1737,13 @@ void pp_remainder(struct pretty_print_context *pp,
else if (pp->expand_tabs_in_log)
strbuf_add_tabexpand(sb, pp->expand_tabs_in_log,
line, linelen);
else
else {
if (pp->fmt == CMIT_FMT_MBOXRD &&
is_mboxrd_from(line, linelen))
strbuf_addch(sb, '>');
strbuf_add(sb, line, linelen);
}
strbuf_addch(sb, '\n');
}
}
@ -1750,14 +1767,14 @@ void pretty_print_commit(struct pretty_print_context *pp,
encoding = get_log_output_encoding();
msg = reencoded = logmsg_reencode(commit, NULL, encoding);
if (pp->fmt == CMIT_FMT_ONELINE || pp->fmt == CMIT_FMT_EMAIL)
if (pp->fmt == CMIT_FMT_ONELINE || cmit_fmt_is_mail(pp->fmt))
indent = 0;
/*
* We need to check and emit Content-type: to mark it
* as 8-bit if we haven't done so.
*/
if (pp->fmt == CMIT_FMT_EMAIL && need_8bit_cte == 0) {
if (cmit_fmt_is_mail(pp->fmt) && need_8bit_cte == 0) {
int i, ch, in_body;
for (in_body = i = 0; (ch = msg[i]); i++) {
@ -1785,7 +1802,7 @@ void pretty_print_commit(struct pretty_print_context *pp,
msg = skip_empty_lines(msg);
/* These formats treat the title line specially. */
if (pp->fmt == CMIT_FMT_ONELINE || pp->fmt == CMIT_FMT_EMAIL)
if (pp->fmt == CMIT_FMT_ONELINE || cmit_fmt_is_mail(pp->fmt))
pp_title_line(pp, &msg, sb, encoding, need_8bit_cte);
beginning_of_body = sb->len;
@ -1802,7 +1819,7 @@ void pretty_print_commit(struct pretty_print_context *pp,
* format. Make sure we did not strip the blank line
* between the header and the body.
*/
if (pp->fmt == CMIT_FMT_EMAIL && sb->len <= beginning_of_body)
if (cmit_fmt_is_mail(pp->fmt) && sb->len <= beginning_of_body)
strbuf_addch(sb, '\n');
unuse_commit_buffer(commit, reencoded);