git/list[1] front-page[2] threads[3] people[4] search[5] about
 

[PATCH RFC 4/6] send-email: --compose takes optional argument to existing file

From
Michael Witten <mfwitten@gmail.com>
Date
Apr 7, 2009, 21:25 UTC
Message-ID
<1239139522-24118-4-git-send-email-mfwitten@gmail.com>
In-Reply-To
<1239139522-24118-3-git-send-email-mfwitten@gmail.com>

Now, a user may specify an existing (in-progress) file to use as the introductory/summary email.

The file is opened for any additional editing as usual.
Signed-off-by: Michael Witten <mfwitten@gmail.com>
---
 Documentation/git-send-email.txt |    7 ++-
 git-send-email.perl              |  112 ++++++++++++++++++++++----------------
 2 files changed, 71 insertions(+), 48 deletions(-)
diff --git a/Documentation/git-send-email.txt b/Documentation/git-send-email.txt
index 4b656ca..bc9ff13 100644
--- a/Documentation/git-send-email.txt
+++ b/Documentation/git-send-email.txt
@@ -57,8 +57,11 @@ The --cc option must be repeated for each user you want on the cc list.
 	or one for all of them at once.
 
 --compose::
-	Use $GIT_EDITOR, core.editor, $VISUAL, or $EDITOR to edit an
-	introductory message for the patch series.
+	Use $GIT_EDITOR, core.editor, $VISUAL, or $EDITOR, or vi to edit an
+	introductory message for the patch series. An existing file may be
+	specified as the basis for the introductory email; it will be opened
+	for editing directly. Otherwise, a new temporary file is created with
+	some default contents.
 +
 When '--compose' is used, git send-email will use the From, Subject, and
 In-Reply-To headers specified in the message. If the body of the message
diff --git a/git-send-email.perl b/git-send-email.perl
index 098c620..481bf36 100755
--- a/git-send-email.perl
+++ b/git-send-email.perl
@@ -53,7 +53,7 @@ git send-email [options] <file | directory | rev-list options >
     --subject               <str>  * Email "Subject:"
     --in-reply-to           <str>  * Email "In-Reply-To:"
     --annotate                     * Review each patch that will be sent in an editor.
-    --compose                      * Open an editor for introduction.
+    --compose           opt <str>  * Open an editor for introduction.
 
   Sending:
     --delay                 <int>  * Delay (seconds) between sending emails.
@@ -62,7 +62,7 @@ git send-email [options] <file | directory | rev-list options >
                                      is optional. Default 'localhost'.
     --smtp-server-port      <int>  * Outgoing SMTP server port.
     --smtp-user             <str>  * Username for SMTP-AUTH.
-    --smtp-pass             <str>  * Password for SMTP-AUTH; not necessary.
+    --smtp-pass         opt <str>  * Password for SMTP-AUTH; not necessary.
     --smtp-encryption       <str>  * tls or ssl; anything else disables.
     --smtp-ssl                     * Deprecated. Use '--smtp-encryption ssl'.
 
@@ -159,7 +159,7 @@ if ($@) {
 # Behavior modification variables
 my ($quiet, $dry_run) = (0, 0);
 my $format_patch;
-my $compose_filename;
+my ($compose_filename, $compose_final_filename, $compose_final_is_not_empty);
 
 # Handle interactive edition of files.
 my $multiedit;
@@ -224,13 +224,12 @@ sub signal_handler {
 	system "stty echo";
 
 	# tmp files from --compose
-	if (defined $compose_filename) {
-		if (-e $compose_filename) {
-			print "'$compose_filename' contains an intermediate version of the email you were composing.\n";
-		}
-		if (-e ($compose_filename . ".final")) {
-			print "'$compose_filename.final' contains the composed email.\n"
-		}
+	if (defined $compose_filename and -f $compose_filename) {
+		print "'$compose_filename' contains an intermediate version of the email you were composing.\n";
+	}
+
+	if (defined $compose_final_filename and -f $compose_final_filename) {
+		print "'$compose_final_filename' contains the composed email.\n"
 	}
 
 	exit;
@@ -258,7 +257,7 @@ my $rc = GetOptions("sender|from=s" => \$sender,
 		    "smtp-encryption=s" => \$smtp_encryption,
 		    "identity=s" => \$identity,
 		    "annotate" => \$annotate,
-		    "compose" => \$compose,
+		    "compose:s" => \$compose,
 		    "quiet" => \$quiet,
 		    "cc-cmd=s" => \$cc_cmd,
 		    "suppress-from!" => \$suppress_from,
@@ -517,21 +516,36 @@ sub get_patch_subject($) {
 	die "'Subject:' line expected in '$patch'";
 }
 
-if ($compose) {
-	# Note that this does not need to be secure, but we will make a small
-	# effort to have it be unique
-	$compose_filename = ($repo ?
-		tempfile(".gitsendemail.msg.XXXXXX", DIR => $repo->repo_path()) :
-		tempfile(".gitsendemail.msg.XXXXXX", DIR => "."))[1];
-	open(C,">",$compose_filename)
-		or die "Failed to open for writing $compose_filename: $!";
+if (defined $compose) {
+
+	my ($tmp_file, $tmp_filename) = tempfile(".gitsendemail.msg.XXXXXX", DIR => ($repo ? $repo->repo_path() : "."));
 
+	my $compose_file;
+	my $compose_final_file;
+
+	if ($compose ne '') {
+
+		$compose_filename = $compose;
+
+		$compose_final_filename = $tmp_filename;
+		$compose_final_file     = $tmp_file
+
+	} else {
 
-	my $tpl_sender = $sender || $repoauthor || $repocommitter || '';
-	my $tpl_subject = $initial_subject || '';
-	my $tpl_reply_to = $initial_reply_to || '';
+		$compose_filename = $tmp_filename;
+		$compose_file     = $tmp_file;
 
-	print C <<EOT;
+		$compose_final_filename = "$compose_filename.final";
+		open $compose_final_file, ">", $compose_final_filename
+			or die "Failed to open '$compose_final_filename' for writing: $!";
+
+		# Help the user out with some instruction and initial headers:
+
+		my $tpl_sender = $sender || $repoauthor || $repocommitter || '';
+		my $tpl_subject = $initial_subject || '';
+		my $tpl_reply_to = $initial_reply_to || '';
+
+		print $compose_file <<EOT;
 From $tpl_sender # This line is ignored.
 GIT: Lines beginning in "GIT:" will be removed.
 GIT: Consider including an overall diffstat or table of contents
@@ -543,10 +557,10 @@ Subject: $tpl_subject
 In-Reply-To: $tpl_reply_to
 
 EOT
-	for my $f (@files) {
-		print C "GIT: ", get_patch_subject($f), "\n";
+		for my $f (@files) {
+			print $compose_file "GIT: ", get_patch_subject($f), "\n";
+		}
 	}
-	close(C);
 
 	my $editor = $ENV{GIT_EDITOR} || Git::config(@repo, "core.editor") || $ENV{VISUAL} || $ENV{EDITOR} || "vi";
 
@@ -556,23 +570,28 @@ EOT
 		do_edit($compose_filename);
 	}
 
-	open(C2,">",$compose_filename . ".final")
-		or die "Failed to open $compose_filename.final : " . $!;
+	# Now transform the user-edited introduction into something
+	# suitable for sending via email; the user's editor may have
+	# unlinked the original file and replaced it with an entirely
+	# new one. If this be the case, then it wouldn't do just to
+	# seek to the beginning and start reading, because then only
+	# the original content would be retrieved. Consequently, the
+	# file must be reopened to be safe (note, the original
+	# filehandle is closed automatically).
 
-	open(C,"<",$compose_filename)
-		or die "Failed to open $compose_filename : " . $!;
+	open $compose_file, "<", $compose_filename
+		or die "Failed to open '$compose_filename' for reading: $!";
 
 	my $need_8bit_cte = file_has_nonascii($compose_filename);
 	my $in_body = 0;
-	my $summary_empty = 1;
-	while(<C>) {
+	while(<$compose_file>) {
 		next if m/^GIT:/;
-		if ($in_body) {
-			$summary_empty = 0 unless (/^\n$/);
+		if ($in_body && not /^\n$/) {
+			 $compose_final_is_not_empty = 1;
 		} elsif (/^\n$/) {
 			$in_body = 1;
 			if ($need_8bit_cte) {
-				print C2 "MIME-Version: 1.0\n",
+				print $compose_final_file "MIME-Version: 1.0\n",
 					 "Content-Type: text/plain; ",
 					   "charset=utf-8\n",
 					 "Content-Transfer-Encoding: 8bit\n";
@@ -597,15 +616,12 @@ EOT
 			print "To/Cc/Bcc fields are not interpreted yet, they have been ignored\n";
 			next;
 		}
-		print C2 $_;
-	}
-	close(C);
-	close(C2);
 
-	if ($summary_empty) {
-		print "Summary email is empty, skipping it\n";
-		$compose = -1;
+		print $compose_final_file $_;
 	}
+
+	print "Summary email is empty, skipping it\n" unless ($compose_final_is_not_empty);
+
 } elsif ($annotate) {
 	do_edit(@files);
 }
@@ -685,9 +701,7 @@ if (!defined $smtp_server) {
 	$smtp_server ||= 'localhost'; # could be 127.0.0.1, too... *shrug*
 }
 
-if ($compose && $compose > 0) {
-	@files = ($compose_filename . ".final", @files);
-}
+unshift(@files, $compose_final_filename) if ($compose_final_is_not_empty);
 
 # Variables we set as part of the loop over files
 our ($message_id, %mail, $subject, $reply_to, $references, $message,
@@ -1153,7 +1167,13 @@ for (my $index = 0; $index < @files; $index++) {
 cleanup_compose_files();
 
 sub cleanup_compose_files() {
-	unlink($compose_filename, $compose_filename . ".final") if $compose;
+	if (defined $compose) {
+		unlink(
+			$compose_final_filename,
+			# Don't delete user-supplied file.
+			$compose ? () : $compose_filename
+		);
+	}
 }
 
 $smtp->quit if $smtp;
-- 
1.6.2.2.448.g61445.dirty
Previous: Michael WittenNext: Michael Witten
Message 4 of 30 in “send-email: Add --delay for separating emails”
  1. 1/6 send-email: Add --delay for separating emailsMichael Witten, Apr 7, 2009
  2. 2/6 send-email: --smtp-server-port should take an integerMichael Witten, Apr 7, 2009
  3. 3/6 send-email: Handle "GIT:" rather than "GIT: " during --composeMichael Witten, Apr 7, 2009
  4. 4/6 send-email: --compose takes optional argument to existing fileMichael Witten, Apr 7, 2009
  5. 5/6 send-email: Cleanup the usage text a bitMichael Witten, Apr 7, 2009
  6. 6/6 send-email: Remove horrible mix of tabs and spacesMichael Witten, Apr 7, 2009
  7. demerphqApr 7, 2009
  8. Michael WittenApr 7, 2009
  9. demerphqApr 7, 2009
  10. demerphqApr 7, 2009
  11. Jeff KingApr 7, 2009
  12. Andreas EricssonApr 7, 2009
  13. Tomas CarneckyApr 7, 2009
  14. Jeff KingApr 8, 2009
  15. Junio C HamanoApr 11, 2009
  16. Junio C HamanoApr 11, 2009
  17. Junio C HamanoApr 11, 2009
  18. Michael WittenApr 11, 2009
  19. Junio C HamanoApr 12, 2009
  20. Michael WittenApr 12, 2009
  21. Junio C HamanoApr 7, 2009
  22. Junio C HamanoApr 11, 2009
  23. Wesley J. LandakerApr 11, 2009
  24. Michael WittenApr 11, 2009
  25. Jeff KingApr 7, 2009
  26. 1/6 Re: send-email: Add --delay for separating emailsNicolas Sebrecht, Apr 7, 2009
  27. Andreas EricssonApr 7, 2009
  28. Jeff KingApr 8, 2009
  29. Jeff KingApr 8, 2009
  30. Junio C HamanoApr 7, 2009

Read the whole thread, see it on lore, or plain text.

$ cat FOOTERMessages come from the public archive at lore.kernel.org/git, fetched every hour. The front page is chosen and written each morning by an AI editor and can be wrong; the threads themselves are the record. About and API. For agents: an MCP server at https://gitlist.dev/mcp, and any thread, story or person page as Markdown by adding .md to its URL (or sending Accept: text/markdown). Details in /llms.txt.