From ae6c098f158dd306462024c5cb137b8f7f65cfbd Mon Sep 17 00:00:00 2001 From: Steven Drake Date: Wed, 17 Feb 2010 12:39:34 +1300 Subject: [PATCH 1/4] Add 'git format-patch --to=' option and 'format.to' configuration variable. Has the same functionality as the '--cc' option and 'format.cc' configuration variable but for the "To:" email header. Half of the code to support this was already there. With email the To: header usually more important than the Cc: header. [jc: tests are by Stephen Boyd] Signed-off-by: Steven Drake Signed-off-by: Stephen Boyd Signed-off-by: Junio C Hamano --- Documentation/git-format-patch.txt | 11 ++++++++--- builtin-log.c | 16 ++++++++++++++++ t/t4014-format-patch.sh | 14 ++++++++++++++ 3 files changed, 38 insertions(+), 3 deletions(-) diff --git a/Documentation/git-format-patch.txt b/Documentation/git-format-patch.txt index 9674f9de67..835fb7135b 100644 --- a/Documentation/git-format-patch.txt +++ b/Documentation/git-format-patch.txt @@ -18,7 +18,7 @@ SYNOPSIS [--in-reply-to=Message-Id] [--suffix=.] [--ignore-if-in-upstream] [--subject-prefix=Subject-Prefix] - [--cc=] + [--to=] [--cc=] [--cover-letter] [] [ | ] @@ -162,6 +162,10 @@ will want to ensure that threading is disabled for `git send-email`. allows for useful naming of a patch series, and can be combined with the `--numbered` option. +--to=:: + Add a `To:` header to the email headers. This is in addition + to any configured headers, and may be used multiple times. + --cc=:: Add a `Cc:` header to the email headers. This is in addition to any configured headers, and may be used multiple times. @@ -202,8 +206,8 @@ CONFIGURATION ------------- You can specify extra mail header lines to be added to each message, defaults for the subject prefix and file suffix, number patches when -outputting more than one patch, add "Cc:" headers, configure attachments, -and sign off patches with configuration variables. +outputting more than one patch, add "To" or "Cc:" headers, configure +attachments, and sign off patches with configuration variables. ------------ [format] @@ -211,6 +215,7 @@ and sign off patches with configuration variables. subjectprefix = CHANGE suffix = .txt numbered = auto + to = cc = attach [ = mime-boundary-string ] signoff = true diff --git a/builtin-log.c b/builtin-log.c index 8d16832f7e..5d23a67993 100644 --- a/builtin-log.c +++ b/builtin-log.c @@ -504,6 +504,13 @@ static int git_format_config(const char *var, const char *value, void *cb) } if (!strcmp(var, "format.suffix")) return git_config_string(&fmt_patch_suffix, var, value); + if (!strcmp(var, "format.to")) { + if (!value) + return config_error_nonbool(var); + ALLOC_GROW(extra_to, extra_to_nr + 1, extra_to_alloc); + extra_to[extra_to_nr++] = xstrdup(value); + return 0; + } if (!strcmp(var, "format.cc")) { if (!value) return config_error_nonbool(var); @@ -875,6 +882,13 @@ static int header_callback(const struct option *opt, const char *arg, int unset) return 0; } +static int to_callback(const struct option *opt, const char *arg, int unset) +{ + ALLOC_GROW(extra_to, extra_to_nr + 1, extra_to_alloc); + extra_to[extra_to_nr++] = xstrdup(arg); + return 0; +} + static int cc_callback(const struct option *opt, const char *arg, int unset) { ALLOC_GROW(extra_cc, extra_cc_nr + 1, extra_cc_alloc); @@ -939,6 +953,8 @@ int cmd_format_patch(int argc, const char **argv, const char *prefix) { OPTION_CALLBACK, 0, "add-header", NULL, "header", "add email header", PARSE_OPT_NONEG, header_callback }, + { OPTION_CALLBACK, 0, "to", NULL, "email", "add To: header", + PARSE_OPT_NONEG, to_callback }, { OPTION_CALLBACK, 0, "cc", NULL, "email", "add Cc: header", PARSE_OPT_NONEG, cc_callback }, OPT_STRING(0, "in-reply-to", &in_reply_to, "message-id", diff --git a/t/t4014-format-patch.sh b/t/t4014-format-patch.sh index f2a2aaa2b9..830ddb0cbe 100755 --- a/t/t4014-format-patch.sh +++ b/t/t4014-format-patch.sh @@ -143,6 +143,20 @@ test_expect_success 'configuration headers and command line headers' ' grep "^ *S. E. Cipient \$" patch7 ' +test_expect_success 'command line To: header' ' + + git config --unset-all format.headers && + git format-patch --to="R. E. Cipient " --stdout master..side | sed -e "/^\$/q" >patch8 && + grep "^To: R. E. Cipient \$" patch8 +' + +test_expect_success 'configuration To: header' ' + + git config format.to "R. E. Cipient " && + git format-patch --stdout master..side | sed -e "/^\$/q" >patch9 && + grep "^To: R. E. Cipient \$" patch9 +' + test_expect_success 'multiple files' ' rm -rf patches/ && From ca9e0a1b8738959f5bd5a17ec81fa3bd1a326c9d Mon Sep 17 00:00:00 2001 From: Stephen Boyd Date: Sun, 7 Mar 2010 14:46:46 -0800 Subject: [PATCH 2/4] format-patch: use a string_list for headers In the next patch we'll need to clear the header lists if the user specifies --no-add-headers or --no-to or --no-cc. This actually cuts down on the code a bit too. Signed-off-by: Stephen Boyd Signed-off-by: Junio C Hamano --- builtin-log.c | 73 ++++++++++++++++++++++++--------------------------- 1 file changed, 34 insertions(+), 39 deletions(-) diff --git a/builtin-log.c b/builtin-log.c index 5d23a67993..207dd1fa90 100644 --- a/builtin-log.c +++ b/builtin-log.c @@ -458,35 +458,28 @@ static int auto_number = 1; static char *default_attach = NULL; -static char **extra_hdr; -static int extra_hdr_nr; -static int extra_hdr_alloc; - -static char **extra_to; -static int extra_to_nr; -static int extra_to_alloc; - -static char **extra_cc; -static int extra_cc_nr; -static int extra_cc_alloc; +static struct string_list extra_hdr; +static struct string_list extra_to; +static struct string_list extra_cc; static void add_header(const char *value) { + struct string_list_item *item; int len = strlen(value); while (len && value[len - 1] == '\n') len--; + if (!strncasecmp(value, "to: ", 4)) { - ALLOC_GROW(extra_to, extra_to_nr + 1, extra_to_alloc); - extra_to[extra_to_nr++] = xstrndup(value + 4, len - 4); - return; + item = string_list_append(value + 4, &extra_to); + len -= 4; + } else if (!strncasecmp(value, "cc: ", 4)) { + item = string_list_append(value + 4, &extra_cc); + len -= 4; + } else { + item = string_list_append(value, &extra_hdr); } - if (!strncasecmp(value, "cc: ", 4)) { - ALLOC_GROW(extra_cc, extra_cc_nr + 1, extra_cc_alloc); - extra_cc[extra_cc_nr++] = xstrndup(value + 4, len - 4); - return; - } - ALLOC_GROW(extra_hdr, extra_hdr_nr + 1, extra_hdr_alloc); - extra_hdr[extra_hdr_nr++] = xstrndup(value, len); + + item->string[len] = '\0'; } #define THREAD_SHALLOW 1 @@ -507,15 +500,13 @@ static int git_format_config(const char *var, const char *value, void *cb) if (!strcmp(var, "format.to")) { if (!value) return config_error_nonbool(var); - ALLOC_GROW(extra_to, extra_to_nr + 1, extra_to_alloc); - extra_to[extra_to_nr++] = xstrdup(value); + string_list_append(value, &extra_to); return 0; } if (!strcmp(var, "format.cc")) { if (!value) return config_error_nonbool(var); - ALLOC_GROW(extra_cc, extra_cc_nr + 1, extra_cc_alloc); - extra_cc[extra_cc_nr++] = xstrdup(value); + string_list_append(value, &extra_cc); return 0; } if (!strcmp(var, "diff.color") || !strcmp(var, "color.diff")) { @@ -884,15 +875,13 @@ static int header_callback(const struct option *opt, const char *arg, int unset) static int to_callback(const struct option *opt, const char *arg, int unset) { - ALLOC_GROW(extra_to, extra_to_nr + 1, extra_to_alloc); - extra_to[extra_to_nr++] = xstrdup(arg); + string_list_append(arg, &extra_to); return 0; } static int cc_callback(const struct option *opt, const char *arg, int unset) { - ALLOC_GROW(extra_cc, extra_cc_nr + 1, extra_cc_alloc); - extra_cc[extra_cc_nr++] = xstrdup(arg); + string_list_append(arg, &extra_cc); return 0; } @@ -972,6 +961,9 @@ int cmd_format_patch(int argc, const char **argv, const char *prefix) OPT_END() }; + extra_hdr.strdup_strings = 1; + extra_to.strdup_strings = 1; + extra_cc.strdup_strings = 1; git_config(git_format_config, NULL); init_revisions(&rev, prefix); rev.commit_format = CMIT_FMT_EMAIL; @@ -1008,29 +1000,29 @@ int cmd_format_patch(int argc, const char **argv, const char *prefix) add_signoff = xmemdupz(committer, endpos - committer + 1); } - for (i = 0; i < extra_hdr_nr; i++) { - strbuf_addstr(&buf, extra_hdr[i]); + for (i = 0; i < extra_hdr.nr; i++) { + strbuf_addstr(&buf, extra_hdr.items[i].string); strbuf_addch(&buf, '\n'); } - if (extra_to_nr) + if (extra_to.nr) strbuf_addstr(&buf, "To: "); - for (i = 0; i < extra_to_nr; i++) { + for (i = 0; i < extra_to.nr; i++) { if (i) strbuf_addstr(&buf, " "); - strbuf_addstr(&buf, extra_to[i]); - if (i + 1 < extra_to_nr) + strbuf_addstr(&buf, extra_to.items[i].string); + if (i + 1 < extra_to.nr) strbuf_addch(&buf, ','); strbuf_addch(&buf, '\n'); } - if (extra_cc_nr) + if (extra_cc.nr) strbuf_addstr(&buf, "Cc: "); - for (i = 0; i < extra_cc_nr; i++) { + for (i = 0; i < extra_cc.nr; i++) { if (i) strbuf_addstr(&buf, " "); - strbuf_addstr(&buf, extra_cc[i]); - if (i + 1 < extra_cc_nr) + strbuf_addstr(&buf, extra_cc.items[i].string); + if (i + 1 < extra_cc.nr) strbuf_addch(&buf, ','); strbuf_addch(&buf, '\n'); } @@ -1239,6 +1231,9 @@ int cmd_format_patch(int argc, const char **argv, const char *prefix) fclose(stdout); } free(list); + string_list_clear(&extra_to, 0); + string_list_clear(&extra_cc, 0); + string_list_clear(&extra_hdr, 0); if (ignore_if_in_upstream) free_patch_ids(&ids); return 0; From c42600346bb6c3427df7ea1c5a33d723ec02d731 Mon Sep 17 00:00:00 2001 From: Stephen Boyd Date: Sun, 7 Mar 2010 14:46:47 -0800 Subject: [PATCH 3/4] format-patch: add --no-cc, --no-to, and --no-add-headers These new options allow users to override their config settings for format.cc, format.to and format.headers respectively. These options only make git ignore the config settings and any previous command line options, so you'll still have to add more command line options to add extra headers. For example, $ cat .git/config [format] to = Someone $ git format-patch -1 --no-to --to="Someone Else " would format a patch addressed to "Someone Else" and not "Someone". Signed-off-by: Stephen Boyd Signed-off-by: Junio C Hamano --- builtin-log.c | 25 ++++++++++++++++++------- t/t4014-format-patch.sh | 38 ++++++++++++++++++++++++++++++++++++++ 2 files changed, 56 insertions(+), 7 deletions(-) diff --git a/builtin-log.c b/builtin-log.c index 207dd1fa90..e14c0a2a01 100644 --- a/builtin-log.c +++ b/builtin-log.c @@ -869,19 +869,31 @@ static int inline_callback(const struct option *opt, const char *arg, int unset) static int header_callback(const struct option *opt, const char *arg, int unset) { - add_header(arg); + if (unset) { + string_list_clear(&extra_hdr, 0); + string_list_clear(&extra_to, 0); + string_list_clear(&extra_cc, 0); + } else { + add_header(arg); + } return 0; } static int to_callback(const struct option *opt, const char *arg, int unset) { - string_list_append(arg, &extra_to); + if (unset) + string_list_clear(&extra_to, 0); + else + string_list_append(arg, &extra_to); return 0; } static int cc_callback(const struct option *opt, const char *arg, int unset) { - string_list_append(arg, &extra_cc); + if (unset) + string_list_clear(&extra_cc, 0); + else + string_list_append(arg, &extra_cc); return 0; } @@ -940,12 +952,11 @@ int cmd_format_patch(int argc, const char **argv, const char *prefix) PARSE_OPT_NONEG | PARSE_OPT_NOARG }, OPT_GROUP("Messaging"), { OPTION_CALLBACK, 0, "add-header", NULL, "header", - "add email header", PARSE_OPT_NONEG, - header_callback }, + "add email header", 0, header_callback }, { OPTION_CALLBACK, 0, "to", NULL, "email", "add To: header", - PARSE_OPT_NONEG, to_callback }, + 0, to_callback }, { OPTION_CALLBACK, 0, "cc", NULL, "email", "add Cc: header", - PARSE_OPT_NONEG, cc_callback }, + 0, cc_callback }, OPT_STRING(0, "in-reply-to", &in_reply_to, "message-id", "make first mail a reply to "), { OPTION_CALLBACK, 0, "attach", &rev, "boundary", diff --git a/t/t4014-format-patch.sh b/t/t4014-format-patch.sh index 830ddb0cbe..c7b625642d 100755 --- a/t/t4014-format-patch.sh +++ b/t/t4014-format-patch.sh @@ -157,6 +157,44 @@ test_expect_success 'configuration To: header' ' grep "^To: R. E. Cipient \$" patch9 ' +test_expect_success '--no-to overrides config.to' ' + + git config --replace-all format.to \ + "R. E. Cipient " && + git format-patch --no-to --stdout master..side | + sed -e "/^\$/q" >patch10 && + ! grep "^To: R. E. Cipient \$" patch10 +' + +test_expect_success '--no-to and --to replaces config.to' ' + + git config --replace-all format.to \ + "Someone " && + git format-patch --no-to --to="Someone Else " \ + --stdout master..side | + sed -e "/^\$/q" >patch11 && + ! grep "^To: Someone \$" patch11 && + grep "^To: Someone Else \$" patch11 +' + +test_expect_success '--no-cc overrides config.cc' ' + + git config --replace-all format.cc \ + "C. E. Cipient " && + git format-patch --no-cc --stdout master..side | + sed -e "/^\$/q" >patch12 && + ! grep "^Cc: C. E. Cipient \$" patch12 +' + +test_expect_success '--no-add-headers overrides config.headers' ' + + git config --replace-all format.headers \ + "Header1: B. E. Cipient " && + git format-patch --no-add-headers --stdout master..side | + sed -e "/^\$/q" >patch13 && + ! grep "^Header1: B. E. Cipient \$" patch13 +' + test_expect_success 'multiple files' ' rm -rf patches/ && From f434c083a097bdc43991e4b0282b9aa1a994a60e Mon Sep 17 00:00:00 2001 From: Stephen Boyd Date: Sun, 7 Mar 2010 14:46:48 -0800 Subject: [PATCH 4/4] send-email: add --no-cc, --no-to, and --no-bcc There's no way to override the sendemail.to, sendemail.cc, and sendemail.bcc config settings. Add options allowing the user to tell git to ignore the config settings and take whatever is on the command line. Signed-off-by: Stephen Boyd Signed-off-by: Junio C Hamano --- git-send-email.perl | 14 ++++++--- t/t9001-send-email.sh | 66 +++++++++++++++++++++++++++++++++++++++++++ 2 files changed, 76 insertions(+), 4 deletions(-) diff --git a/git-send-email.perl b/git-send-email.perl index e05455f74c..d612ae8729 100755 --- a/git-send-email.perl +++ b/git-send-email.perl @@ -47,9 +47,9 @@ git send-email [options] Composing: --from * Email From: - --to * Email To: - --cc * Email Cc: - --bcc * Email Bcc: + --[no-]to * Email To: + --[no-]cc * Email Cc: + --[no-]bcc * Email Bcc: --subject * Email "Subject:" --in-reply-to * Email "In-Reply-To:" --annotate * Review each patch that will be sent in an editor. @@ -135,7 +135,7 @@ sub unique_email_list(@); sub cleanup_compose_files(); # Variables we fill in automatically, or via prompting: -my (@to,@cc,@initial_cc,@bcclist,@xh, +my (@to,$no_to,@cc,$no_cc,@initial_cc,@bcclist,$no_bcc,@xh, $initial_reply_to,$initial_subject,@files, $author,$sender,$smtp_authpass,$annotate,$compose,$time); @@ -261,8 +261,11 @@ my $rc = GetOptions("sender|from=s" => \$sender, "in-reply-to=s" => \$initial_reply_to, "subject=s" => \$initial_subject, "to=s" => \@to, + "no-to" => \$no_to, "cc=s" => \@initial_cc, + "no-cc" => \$no_cc, "bcc=s" => \@bcclist, + "no-bcc" => \$no_bcc, "chain-reply-to!" => \$chain_reply_to, "smtp-server=s" => \$smtp_server, "smtp-server-port=s" => \$smtp_server_port, @@ -305,6 +308,9 @@ sub read_config { foreach my $setting (keys %config_settings) { my $target = $config_settings{$setting}; + next if $setting eq "to" and defined $no_to; + next if $setting eq "cc" and defined $no_cc; + next if $setting eq "bcc" and defined $no_bcc; if (ref($target) eq "ARRAY") { unless (@$target) { my @values = Git::config(@repo, "$prefix.$setting"); diff --git a/t/t9001-send-email.sh b/t/t9001-send-email.sh index c09f375288..640b3d2bb4 100755 --- a/t/t9001-send-email.sh +++ b/t/t9001-send-email.sh @@ -852,4 +852,70 @@ test_expect_success 'no warning with sendemail.chainreplyto = true' ' ! grep "no-chain-reply-to" errors ' +test_expect_success 'sendemail.to works' ' + git config --replace-all sendemail.to "Somebody " && + git send-email \ + --dry-run \ + --from="Example " \ + $patches $patches >stdout && + grep "To: Somebody " stdout +' + +test_expect_success '--no-to overrides sendemail.to' ' + git send-email \ + --dry-run \ + --from="Example " \ + --no-to \ + --to=nobody@example.com \ + $patches $patches >stdout && + grep "To: nobody@example.com" stdout && + ! grep "To: Somebody " stdout +' + +test_expect_success 'sendemail.cc works' ' + git config --replace-all sendemail.cc "Somebody " && + git send-email \ + --dry-run \ + --from="Example " \ + --to=nobody@example.com \ + $patches $patches >stdout && + grep "Cc: Somebody " stdout +' + +test_expect_success '--no-cc overrides sendemail.cc' ' + git send-email \ + --dry-run \ + --from="Example " \ + --no-cc \ + --cc=bodies@example.com \ + --to=nobody@example.com \ + $patches $patches >stdout && + grep "Cc: bodies@example.com" stdout && + ! grep "Cc: Somebody " stdout +' + +test_expect_success 'sendemail.bcc works' ' + git config --replace-all sendemail.bcc "Other " && + git send-email \ + --dry-run \ + --from="Example " \ + --to=nobody@example.com \ + --smtp-server relay.example.com \ + $patches $patches >stdout && + grep "RCPT TO:" stdout +' + +test_expect_success '--no-bcc overrides sendemail.bcc' ' + git send-email \ + --dry-run \ + --from="Example " \ + --no-bcc \ + --bcc=bodies@example.com \ + --to=nobody@example.com \ + --smtp-server relay.example.com \ + $patches $patches >stdout && + grep "RCPT TO:" stdout && + ! grep "RCPT TO:" stdout +' + test_done