diff options
-rw-r--r-- | gnu/local.mk | 1 | ||||
-rw-r--r-- | gnu/packages/patches/git-header-cmd.patch | 287 | ||||
-rw-r--r-- | gnu/packages/version-control.scm | 3 |
3 files changed, 290 insertions, 1 deletions
diff --git a/gnu/local.mk b/gnu/local.mk index b4f5453dda..4976b5c740 100644 --- a/gnu/local.mk +++ b/gnu/local.mk @@ -1211,6 +1211,7 @@ dist_patch_DATA = \ %D%/packages/patches/genimage-mke2fs-test.patch \ %D%/packages/patches/geoclue-config.patch \ %D%/packages/patches/gettext-libunicode-update.patch \ + %D%/packages/patches/git-header-cmd.patch \ %D%/packages/patches/ghc-8.0-fall-back-to-madv_dontneed.patch \ %D%/packages/patches/ghc-9.2-glibc-2.33-link-order.patch \ %D%/packages/patches/ghc-9.2-grep-warnings.patch \ diff --git a/gnu/packages/patches/git-header-cmd.patch b/gnu/packages/patches/git-header-cmd.patch new file mode 100644 index 0000000000..a8964ab174 --- /dev/null +++ b/gnu/packages/patches/git-header-cmd.patch @@ -0,0 +1,287 @@ +Add a '--header-cmd' to git send-email. + +Upstream status can be tracked at: +https://lore.kernel.org/git/20230423122744.4865-1-maxim.cournoyer@gmail.com/T/#t + +diff --git a/Documentation/config/sendemail.txt b/Documentation/config/sendemail.txt +index 51da7088a8..92a9ebe98c 100644 +--- a/Documentation/config/sendemail.txt ++++ b/Documentation/config/sendemail.txt +@@ -61,6 +61,7 @@ sendemail.ccCmd:: + sendemail.chainReplyTo:: + sendemail.envelopeSender:: + sendemail.from:: ++sendemail.headerCmd:: + sendemail.signedoffbycc:: + sendemail.smtpPass:: + sendemail.suppresscc:: +diff --git a/Documentation/git-send-email.txt b/Documentation/git-send-email.txt +index b0f438ec99..4d2ae061f9 100644 +--- a/Documentation/git-send-email.txt ++++ b/Documentation/git-send-email.txt +@@ -320,6 +320,17 @@ Automating + Output of this command must be single email address per line. + Default is the value of `sendemail.ccCmd` configuration value. + ++--header-cmd=<command>:: ++ Specify a command that is executed once per outgoing message ++ and output RFC 2822 style header lines to be inserted into ++ them. When the `sendemail.headerCmd` configuration variable is ++ set, its value is always used. When --header-cmd is provided ++ at the command line, its value takes precedence over the ++ `sendemail.headerCmd` configuration variable. ++ ++--no-header-cmd:: ++ Disable any header command in use. ++ + --[no-]chain-reply-to:: + If this is set, each email will be sent as a reply to the previous + email sent. If disabled with "--no-chain-reply-to", all emails after +diff --git a/git-send-email.perl b/git-send-email.perl +index 66c9171109..22a64e608f 100755 +--- a/git-send-email.perl ++++ b/git-send-email.perl +@@ -87,8 +87,10 @@ sub usage { + + Automating: + --identity <str> * Use the sendemail.<id> options. +- --to-cmd <str> * Email To: via `<str> \$patch_path` +- --cc-cmd <str> * Email Cc: via `<str> \$patch_path` ++ --to-cmd <str> * Email To: via `<str> \$patch_path`. ++ --cc-cmd <str> * Email Cc: via `<str> \$patch_path`. ++ --header-cmd <str> * Add headers via `<str> \$patch_path`. ++ --no-header-cmd * Disable any header command in use. + --suppress-cc <str> * author, self, sob, cc, cccmd, body, bodycc, misc-by, all. + --[no-]cc-cover * Email Cc: addresses in the cover letter. + --[no-]to-cover * Email To: addresses in the cover letter. +@@ -202,7 +204,7 @@ sub format_2822_time { + $author,$sender,$smtp_authpass,$annotate,$compose,$time); + # Things we either get from config, *or* are overridden on the + # command-line. +-my ($no_cc, $no_to, $no_bcc, $no_identity); ++my ($no_cc, $no_to, $no_bcc, $no_identity, $no_header_cmd); + my (@config_to, @getopt_to); + my (@config_cc, @getopt_cc); + my (@config_bcc, @getopt_bcc); +@@ -269,7 +271,7 @@ sub do_edit { + # Variables with corresponding config settings + my ($suppress_from, $signed_off_by_cc); + my ($cover_cc, $cover_to); +-my ($to_cmd, $cc_cmd); ++my ($to_cmd, $cc_cmd, $header_cmd); + my ($smtp_server, $smtp_server_port, @smtp_server_options); + my ($smtp_authuser, $smtp_encryption, $smtp_ssl_cert_path); + my ($batch_size, $relogin_delay); +@@ -318,6 +320,7 @@ sub do_edit { + "tocmd" => \$to_cmd, + "cc" => \@config_cc, + "cccmd" => \$cc_cmd, ++ "headercmd" => \$header_cmd, + "aliasfiletype" => \$aliasfiletype, + "bcc" => \@config_bcc, + "suppresscc" => \@suppress_cc, +@@ -519,6 +522,8 @@ sub config_regexp { + "compose" => \$compose, + "quiet" => \$quiet, + "cc-cmd=s" => \$cc_cmd, ++ "header-cmd=s" => \$header_cmd, ++ "no-header-cmd" => \$no_header_cmd, + "suppress-from!" => \$suppress_from, + "no-suppress-from" => sub {$suppress_from = 0}, + "suppress-cc=s" => \@suppress_cc, +@@ -1780,16 +1785,16 @@ sub process_file { + $subject = $initial_subject; + $message = ""; + $message_num++; +- # First unfold multiline header fields ++ # Retrieve and unfold header fields. ++ my @header_lines = (); + while(<$fh>) { + last if /^\s*$/; +- if (/^\s+\S/ and @header) { +- chomp($header[$#header]); +- s/^\s+/ /; +- $header[$#header] .= $_; +- } else { +- push(@header, $_); +- } ++ push(@header_lines, $_); ++ } ++ @header = unfold_headers(@header_lines); ++ # Add computed headers, if applicable. ++ unless ($no_header_cmd || ! $header_cmd) { ++ push @header, invoke_header_cmd($header_cmd, $t); + } + # Now parse the header + foreach(@header) { +@@ -2021,15 +2026,63 @@ sub process_file { + } + } + ++# Execute a command and return its output lines as an array. Blank ++# lines which do not appear at the end of the output are reported as ++# errors. ++sub execute_cmd { ++ my ($prefix, $cmd, $file) = @_; ++ my @lines = (); ++ my $seen_blank_line = 0; ++ open my $fh, "-|", "$cmd \Q$file\E" ++ or die sprintf(__("(%s) Could not execute '%s'"), $prefix, $cmd); ++ while (my $line = <$fh>) { ++ die sprintf(__("(%s) Malformed output from '%s'"), $prefix, $cmd) ++ if $seen_blank_line; ++ if ($line =~ /^$/) { ++ $seen_blank_line = $line =~ /^$/; ++ next; ++ } ++ push @lines, $line; ++ } ++ close $fh ++ or die sprintf(__("(%s) failed to close pipe to '%s'"), $prefix, $cmd); ++ return @lines; ++} ++ ++# Process headers lines, unfolding multiline headers as defined by RFC ++# 2822. ++sub unfold_headers { ++ my @headers; ++ foreach(@_) { ++ last if /^\s*$/; ++ if (/^\s+\S/ and @headers) { ++ chomp($headers[$#headers]); ++ s/^\s+/ /; ++ $headers[$#headers] .= $_; ++ } else { ++ push(@headers, $_); ++ } ++ } ++ return @headers; ++} ++ ++# Invoke the provided CMD with FILE as an argument, which should ++# output RFC 2822 email headers. Fold multiline headers and return the ++# headers as an array. ++sub invoke_header_cmd { ++ my ($cmd, $file) = @_; ++ my @lines = execute_cmd("header-cmd", $header_cmd, $file); ++ return unfold_headers(@lines); ++} ++ + # Execute a command (e.g. $to_cmd) to get a list of email addresses + # and return a results array + sub recipients_cmd { + my ($prefix, $what, $cmd, $file) = @_; +- ++ my @lines = (); + my @addresses = (); +- open my $fh, "-|", "$cmd \Q$file\E" +- or die sprintf(__("(%s) Could not execute '%s'"), $prefix, $cmd); +- while (my $address = <$fh>) { ++ @lines = execute_cmd($prefix, $cmd, $file); ++ for my $address (@lines) { + $address =~ s/^\s*//g; + $address =~ s/\s*$//g; + $address = sanitize_address($address); +@@ -2038,8 +2091,6 @@ sub recipients_cmd { + printf(__("(%s) Adding %s: %s from: '%s'\n"), + $prefix, $what, $address, $cmd) unless $quiet; + } +- close $fh +- or die sprintf(__("(%s) failed to close pipe to '%s'"), $prefix, $cmd); + return @addresses; + } + +diff --git a/t/t9001-send-email.sh b/t/t9001-send-email.sh +index 6520346246..6519eea1ed 100755 +--- a/t/t9001-send-email.sh ++++ b/t/t9001-send-email.sh +@@ -374,13 +374,16 @@ test_expect_success $PREREQ,!AUTOIDENT 'broken implicit ident aborts send-email' + ) + ' + +-test_expect_success $PREREQ 'setup tocmd and cccmd scripts' ' ++test_expect_success $PREREQ 'setup cmd scripts' ' + write_script tocmd-sed <<-\EOF && + sed -n -e "s/^tocmd--//p" "$1" + EOF +- write_script cccmd-sed <<-\EOF ++ write_script cccmd-sed <<-\EOF && + sed -n -e "s/^cccmd--//p" "$1" + EOF ++ write_script headercmd-sed <<-\EOF ++ sed -n -e "s/^headercmd--//p" "$1" ++ EOF + ' + + test_expect_success $PREREQ 'tocmd works' ' +@@ -410,6 +413,70 @@ test_expect_success $PREREQ 'cccmd works' ' + grep "^ cccmd@example.com" msgtxt1 + ' + ++test_expect_success $PREREQ 'headercmd works' ' ++ clean_fake_sendmail && ++ cp $patches headercmd.patch && ++ echo "headercmd--X-Debbugs-CC: dummy@example.com" >>headercmd.patch && ++ git send-email \ ++ --from="Example <nobody@example.com>" \ ++ --to=nobody@example.com \ ++ --header-cmd=./headercmd-sed \ ++ --smtp-server="$(pwd)/fake.sendmail" \ ++ headercmd.patch \ ++ && ++ grep "^X-Debbugs-CC: dummy@example.com" msgtxt1 ++' ++ ++test_expect_success $PREREQ '--no-header-cmd works' ' ++ clean_fake_sendmail && ++ cp $patches headercmd.patch && ++ echo "headercmd--X-Debbugs-CC: dummy@example.com" >>headercmd.patch && ++ git send-email \ ++ --from="Example <nobody@example.com>" \ ++ --to=nobody@example.com \ ++ --header-cmd=./headercmd-sed \ ++ --no-header-cmd \ ++ --smtp-server="$(pwd)/fake.sendmail" \ ++ headercmd.patch \ ++ && ++ ! grep "^X-Debbugs-CC: dummy@example.com" msgtxt1 ++' ++ ++test_expect_success $PREREQ 'multiline fields are correctly unfolded' ' ++ clean_fake_sendmail && ++ cp $patches headercmd.patch && ++ write_script headercmd-multiline <<-\EOF && ++ echo "X-Debbugs-CC: someone@example.com ++FoldedField: This is a tale ++ best told using ++ multiple lines." ++ EOF ++ git send-email \ ++ --from="Example <nobody@example.com>" \ ++ --to=nobody@example.com \ ++ --header-cmd=./headercmd-multiline \ ++ --smtp-server="$(pwd)/fake.sendmail" \ ++ headercmd.patch && ++ grep "^FoldedField: This is a tale best told using multiple lines.$" msgtxt1 ++' ++ ++# Blank lines in the middle of the output of a command are invalid. ++test_expect_success $PREREQ 'malform output reported on blank lines in command output' ' ++ clean_fake_sendmail && ++ cp $patches headercmd.patch && ++ write_script headercmd-malformed-output <<-\EOF && ++ echo "X-Debbugs-CC: someone@example.com ++ ++SomeOtherField: someone-else@example.com" ++ EOF ++ ! git send-email \ ++ --from="Example <nobody@example.com>" \ ++ --to=nobody@example.com \ ++ --header-cmd=./headercmd-malformed-output \ ++ --smtp-server="$(pwd)/fake.sendmail" \ ++ headercmd.patch ++' ++ + test_expect_success $PREREQ 'reject long lines' ' + z8=zzzzzzzz && + z64=$z8$z8$z8$z8$z8$z8$z8$z8 && diff --git a/gnu/packages/version-control.scm b/gnu/packages/version-control.scm index c2ec490383..4fbf3b4d05 100644 --- a/gnu/packages/version-control.scm +++ b/gnu/packages/version-control.scm @@ -234,7 +234,8 @@ Python 3.3 and later, rather than on Python 2.") version ".tar.xz")) (sha256 (base32 - "1mpjvhyw8mv2q941xny4d0gw3mb6b4bqaqbh73jd8b1v6zqpaps7")))) + "1mpjvhyw8mv2q941xny4d0gw3mb6b4bqaqbh73jd8b1v6zqpaps7")) + (patches (search-patches "git-header-cmd.patch")))) (build-system gnu-build-system) (native-inputs `(("native-perl" ,perl) |