|
37 | 37 | #include "range-diff.h" |
38 | 38 |
|
39 | 39 | #define MAIL_DEFAULT_WRAP 72 |
| 40 | +#define COVER_FROM_AUTO_MAX_SUBJECT_LEN 100 |
40 | 41 |
|
41 | 42 | /* Set a default date-time format for git log ("log.date" config variable) */ |
42 | 43 | static const char *default_date_mode = NULL; |
@@ -765,23 +766,51 @@ static void add_header(const char *value) |
765 | 766 | item->string[len] = '\0'; |
766 | 767 | } |
767 | 768 |
|
768 | | -#define THREAD_SHALLOW 1 |
769 | | -#define THREAD_DEEP 2 |
770 | | -static int thread; |
| 769 | +enum cover_setting { |
| 770 | + COVER_UNSET, |
| 771 | + COVER_OFF, |
| 772 | + COVER_ON, |
| 773 | + COVER_AUTO |
| 774 | +}; |
| 775 | + |
| 776 | +enum thread_level { |
| 777 | + THREAD_UNSET, |
| 778 | + THREAD_SHALLOW, |
| 779 | + THREAD_DEEP |
| 780 | +}; |
| 781 | + |
| 782 | +enum cover_from_description { |
| 783 | + COVER_FROM_NONE, |
| 784 | + COVER_FROM_MESSAGE, |
| 785 | + COVER_FROM_SUBJECT, |
| 786 | + COVER_FROM_AUTO |
| 787 | +}; |
| 788 | + |
| 789 | +static enum thread_level thread; |
771 | 790 | static int do_signoff; |
772 | 791 | static int base_auto; |
773 | 792 | static char *from; |
774 | 793 | static const char *signature = git_version_string; |
775 | 794 | static const char *signature_file; |
776 | | -static int config_cover_letter; |
| 795 | +static enum cover_setting config_cover_letter; |
777 | 796 | static const char *config_output_directory; |
| 797 | +static enum cover_from_description cover_from_description_mode = COVER_FROM_MESSAGE; |
778 | 798 |
|
779 | | -enum { |
780 | | - COVER_UNSET, |
781 | | - COVER_OFF, |
782 | | - COVER_ON, |
783 | | - COVER_AUTO |
784 | | -}; |
| 799 | +static enum cover_from_description parse_cover_from_description(const char *arg) |
| 800 | +{ |
| 801 | + if (!arg || !strcmp(arg, "default")) |
| 802 | + return COVER_FROM_MESSAGE; |
| 803 | + else if (!strcmp(arg, "none")) |
| 804 | + return COVER_FROM_NONE; |
| 805 | + else if (!strcmp(arg, "message")) |
| 806 | + return COVER_FROM_MESSAGE; |
| 807 | + else if (!strcmp(arg, "subject")) |
| 808 | + return COVER_FROM_SUBJECT; |
| 809 | + else if (!strcmp(arg, "auto")) |
| 810 | + return COVER_FROM_AUTO; |
| 811 | + else |
| 812 | + die(_("%s: invalid cover from description mode"), arg); |
| 813 | +} |
785 | 814 |
|
786 | 815 | static int git_format_config(const char *var, const char *value, void *cb) |
787 | 816 | { |
@@ -836,7 +865,7 @@ static int git_format_config(const char *var, const char *value, void *cb) |
836 | 865 | thread = THREAD_SHALLOW; |
837 | 866 | return 0; |
838 | 867 | } |
839 | | - thread = git_config_bool(var, value) && THREAD_SHALLOW; |
| 868 | + thread = git_config_bool(var, value) ? THREAD_SHALLOW : THREAD_UNSET; |
840 | 869 | return 0; |
841 | 870 | } |
842 | 871 | if (!strcmp(var, "format.signoff")) { |
@@ -888,6 +917,10 @@ static int git_format_config(const char *var, const char *value, void *cb) |
888 | 917 | } |
889 | 918 | return 0; |
890 | 919 | } |
| 920 | + if (!strcmp(var, "format.coverfromdescription")) { |
| 921 | + cover_from_description_mode = parse_cover_from_description(value); |
| 922 | + return 0; |
| 923 | + } |
891 | 924 |
|
892 | 925 | return git_log_config(var, value, cb); |
893 | 926 | } |
@@ -994,20 +1027,6 @@ static void print_signature(FILE *file) |
994 | 1027 | putc('\n', file); |
995 | 1028 | } |
996 | 1029 |
|
997 | | -static void add_branch_description(struct strbuf *buf, const char *branch_name) |
998 | | -{ |
999 | | - struct strbuf desc = STRBUF_INIT; |
1000 | | - if (!branch_name || !*branch_name) |
1001 | | - return; |
1002 | | - read_branch_desc(&desc, branch_name); |
1003 | | - if (desc.len) { |
1004 | | - strbuf_addch(buf, '\n'); |
1005 | | - strbuf_addbuf(buf, &desc); |
1006 | | - strbuf_addch(buf, '\n'); |
1007 | | - } |
1008 | | - strbuf_release(&desc); |
1009 | | -} |
1010 | | - |
1011 | 1030 | static char *find_branch_name(struct rev_info *rev) |
1012 | 1031 | { |
1013 | 1032 | int i, positive = -1; |
@@ -1054,15 +1073,51 @@ static void show_diffstat(struct rev_info *rev, |
1054 | 1073 | fprintf(rev->diffopt.file, "\n"); |
1055 | 1074 | } |
1056 | 1075 |
|
| 1076 | +static void prepare_cover_text(struct pretty_print_context *pp, |
| 1077 | + const char *branch_name, |
| 1078 | + struct strbuf *sb, |
| 1079 | + const char *encoding, |
| 1080 | + int need_8bit_cte) |
| 1081 | +{ |
| 1082 | + const char *subject = "*** SUBJECT HERE ***"; |
| 1083 | + const char *body = "*** BLURB HERE ***"; |
| 1084 | + struct strbuf description_sb = STRBUF_INIT; |
| 1085 | + struct strbuf subject_sb = STRBUF_INIT; |
| 1086 | + |
| 1087 | + if (cover_from_description_mode == COVER_FROM_NONE) |
| 1088 | + goto do_pp; |
| 1089 | + |
| 1090 | + if (branch_name && *branch_name) |
| 1091 | + read_branch_desc(&description_sb, branch_name); |
| 1092 | + if (!description_sb.len) |
| 1093 | + goto do_pp; |
| 1094 | + |
| 1095 | + if (cover_from_description_mode == COVER_FROM_SUBJECT || |
| 1096 | + cover_from_description_mode == COVER_FROM_AUTO) |
| 1097 | + body = format_subject(&subject_sb, description_sb.buf, " "); |
| 1098 | + |
| 1099 | + if (cover_from_description_mode == COVER_FROM_MESSAGE || |
| 1100 | + (cover_from_description_mode == COVER_FROM_AUTO && |
| 1101 | + subject_sb.len > COVER_FROM_AUTO_MAX_SUBJECT_LEN)) |
| 1102 | + body = description_sb.buf; |
| 1103 | + else |
| 1104 | + subject = subject_sb.buf; |
| 1105 | + |
| 1106 | +do_pp: |
| 1107 | + pp_title_line(pp, &subject, sb, encoding, need_8bit_cte); |
| 1108 | + pp_remainder(pp, &body, sb, 0); |
| 1109 | + |
| 1110 | + strbuf_release(&description_sb); |
| 1111 | + strbuf_release(&subject_sb); |
| 1112 | +} |
| 1113 | + |
1057 | 1114 | static void make_cover_letter(struct rev_info *rev, int use_stdout, |
1058 | 1115 | struct commit *origin, |
1059 | 1116 | int nr, struct commit **list, |
1060 | 1117 | const char *branch_name, |
1061 | 1118 | int quiet) |
1062 | 1119 | { |
1063 | 1120 | const char *committer; |
1064 | | - const char *body = "*** SUBJECT HERE ***\n\n*** BLURB HERE ***\n"; |
1065 | | - const char *msg; |
1066 | 1121 | struct shortlog log; |
1067 | 1122 | struct strbuf sb = STRBUF_INIT; |
1068 | 1123 | int i; |
@@ -1092,15 +1147,12 @@ static void make_cover_letter(struct rev_info *rev, int use_stdout, |
1092 | 1147 | if (!branch_name) |
1093 | 1148 | branch_name = find_branch_name(rev); |
1094 | 1149 |
|
1095 | | - msg = body; |
1096 | 1150 | pp.fmt = CMIT_FMT_EMAIL; |
1097 | 1151 | pp.date_mode.type = DATE_RFC2822; |
1098 | 1152 | pp.rev = rev; |
1099 | 1153 | pp.print_email_subject = 1; |
1100 | 1154 | pp_user_info(&pp, NULL, &sb, committer, encoding); |
1101 | | - pp_title_line(&pp, &msg, &sb, encoding, need_8bit_cte); |
1102 | | - pp_remainder(&pp, &msg, &sb, 0); |
1103 | | - add_branch_description(&sb, branch_name); |
| 1155 | + prepare_cover_text(&pp, branch_name, &sb, encoding, need_8bit_cte); |
1104 | 1156 | fprintf(rev->diffopt.file, "%s\n", sb.buf); |
1105 | 1157 |
|
1106 | 1158 | strbuf_release(&sb); |
@@ -1249,9 +1301,9 @@ static int output_directory_callback(const struct option *opt, const char *arg, |
1249 | 1301 |
|
1250 | 1302 | static int thread_callback(const struct option *opt, const char *arg, int unset) |
1251 | 1303 | { |
1252 | | - int *thread = (int *)opt->value; |
| 1304 | + enum thread_level *thread = (enum thread_level *)opt->value; |
1253 | 1305 | if (unset) |
1254 | | - *thread = 0; |
| 1306 | + *thread = THREAD_UNSET; |
1255 | 1307 | else if (!arg || !strcmp(arg, "shallow")) |
1256 | 1308 | *thread = THREAD_SHALLOW; |
1257 | 1309 | else if (!strcmp(arg, "deep")) |
@@ -1542,6 +1594,7 @@ int cmd_format_patch(int argc, const char **argv, const char *prefix) |
1542 | 1594 | int use_patch_format = 0; |
1543 | 1595 | int quiet = 0; |
1544 | 1596 | int reroll_count = -1; |
| 1597 | + char *cover_from_description_arg = NULL; |
1545 | 1598 | char *branch_name = NULL; |
1546 | 1599 | char *base_commit = NULL; |
1547 | 1600 | struct base_tree_info bases; |
@@ -1578,6 +1631,9 @@ int cmd_format_patch(int argc, const char **argv, const char *prefix) |
1578 | 1631 | { OPTION_CALLBACK, 0, "rfc", &rev, NULL, |
1579 | 1632 | N_("Use [RFC PATCH] instead of [PATCH]"), |
1580 | 1633 | PARSE_OPT_NOARG | PARSE_OPT_NONEG, rfc_callback }, |
| 1634 | + OPT_STRING(0, "cover-from-description", &cover_from_description_arg, |
| 1635 | + N_("cover-from-description-mode"), |
| 1636 | + N_("generate parts of a cover letter based on a branch's description")), |
1581 | 1637 | { OPTION_CALLBACK, 0, "subject-prefix", &rev, N_("prefix"), |
1582 | 1638 | N_("Use [<prefix>] instead of [PATCH]"), |
1583 | 1639 | PARSE_OPT_NONEG, subject_prefix_callback }, |
@@ -1669,6 +1725,9 @@ int cmd_format_patch(int argc, const char **argv, const char *prefix) |
1669 | 1725 | PARSE_OPT_KEEP_ARGV0 | PARSE_OPT_KEEP_UNKNOWN | |
1670 | 1726 | PARSE_OPT_KEEP_DASHDASH); |
1671 | 1727 |
|
| 1728 | + if (cover_from_description_arg) |
| 1729 | + cover_from_description_mode = parse_cover_from_description(cover_from_description_arg); |
| 1730 | + |
1672 | 1731 | if (0 < reroll_count) { |
1673 | 1732 | struct strbuf sprefix = STRBUF_INIT; |
1674 | 1733 | strbuf_addf(&sprefix, "%s v%d", |
|
0 commit comments