|
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