Enhance git-send-email to recognize executable scripts passed to --to, --cc, or --bcc. When a recipient argument is an executable file, run it in a subshell and use its output as the recipient list.
This allows users to automate recipient selection using scripts like get_maintainer.pl in the Linux kernel. The script is called with the corresponding flag (--to, --cc, or --bcc) and all remaining command-line arguments (typically the patches being sent).
Modify execute_cmd() to support multiple arguments safely using quotemeta. Add test cases to verify the new functionality and ensure arguments are correctly passed to the scripts.
Co-developed-by: Gemini CLI <gemini-cli@google.com> Signed-off-by: Jim Cromie <jim.cromie@gmail.com> --- git-send-email.perl | 11 +++++++++-- t/t9001-send-email.sh | 42 ++++++++++++++++++++++++++++++++++++++++++ 2 files changed, 51 insertions(+), 2 deletions(-)
Show changes to 2 files +51 −2
git-send-email.perl, t/t9001-send-email.sh
diff --git a/git-send-email.perl b/git-send-email.perl index bb8ddd1eef..2d54d98304 100755 --- a/git-send-email.perl +++ b/git-send-email.perl @@ -579,8 +579,11 @@ sub config_regexp { # Munge any "either config or getopt, not both" variables my @initial_to = @getopt_to ? @getopt_to : ($no_to ? () : @config_to); +@initial_to = map { (-x $_) ? execute_cmd("to-script", $_, "--to", @ARGV) : $_ } @initial_to; my @initial_cc = @getopt_cc ? @getopt_cc : ($no_cc ? () : @config_cc); +@initial_cc = map { (-x $_) ? execute_cmd("cc-script", $_, "--cc", @ARGV) : $_ } @initial_cc; my @initial_bcc = @getopt_bcc ? @getopt_bcc : ($no_bcc ? () : @config_bcc); +@initial_bcc = map { (-x $_) ? execute_cmd("bcc-script", $_, "--bcc", @ARGV) : $_ } @initial_bcc; usage() if $help; my %all_options = (%options, %dump_aliases_options, %identity_options); @@ -2222,10 +2225,14 @@ sub initialize_modified_loop_vars { # lines which do not appear at the end of the output are reported as # errors. sub execute_cmd { - my ($prefix, $cmd, $file) = @_; + my ($prefix, $cmd, @args) = @_; my @lines = (); my $seen_blank_line = 0; - open my $fh, "-|", "$cmd \Q$file\E" + my $full_cmd = $cmd; + for my $arg (@args) { + $full_cmd .= " " . quotemeta($arg); + } + open my $fh, "-|", $full_cmd or die sprintf(__("(%s) Could not execute '%s'"), $prefix, $cmd); while (my $line = <$fh>) { die sprintf(__("(%s) Malformed output from '%s'"), $prefix, $cmd) diff --git a/t/t9001-send-email.sh b/t/t9001-send-email.sh index 24f6c76aee..fed75c7669 100755 --- a/t/t9001-send-email.sh +++ b/t/t9001-send-email.sh @@ -2842,4 +2842,46 @@ test_expect_success $PREREQ '--compose handles to headers' ' test_cmp expect msgtxt2.to ' +test_expect_success $PREREQ '--cc=$script' ' + git init repo && + ( + cd repo && + test_commit commit && + patches=$(git format-patch -1 HEAD) && + write_script cc-script <<-\EOT && + echo "cc-script@example.com" + EOT + PERL5LIB="$GIT_BUILD_DIR/perl" "$GIT_BUILD_DIR/git-send-email.perl" \ + --from="Example <from@example.com>" \ + --to=nobody@example.com \ + --cc=./cc-script \ + --smtp-server="$(pwd)/../fake.sendmail" \ + --confirm=never \ + --dry-run \ + $patches >stdout 2>&1 && + grep "^Cc: cc-script@example\.com" stdout + ) +' + +test_expect_success $PREREQ '--cc=$script with arguments' ' + git init repo-args && + ( + cd repo-args && + test_commit commit && + patches=$(git format-patch -1 HEAD) && + write_script cc-script-args <<-\EOT && + echo "script-args-$2@example.com" + EOT + PERL5LIB="$GIT_BUILD_DIR/perl" "$GIT_BUILD_DIR/git-send-email.perl" \ + --from="Example <from@example.com>" \ + --to=nobody@example.com \ + --cc=./cc-script-args \ + --smtp-server="$(pwd)/../fake.sendmail" \ + --confirm=never \ + --dry-run \ + $patches >stdout 2>&1 && + grep "^Cc: script-args-0001-commit\.patch@example\.com" stdout + ) +' + test_done
-- 2.53.0