stg mail: Refactor __send_message and friends
[stgit] / stgit / commands / mail.py
index 72d0133..91e89ff 100644 (file)
@@ -28,7 +28,7 @@ from stgit.lib import git as gitlib
 
 help = 'Send a patch or series of patches by e-mail'
 kind = 'patch'
-usage = [' [options] [<patch1>] [<patch2>] [<patch3>..<patch4>]']
+usage = [' [options] [--] [<patch1>] [<patch2>] [<patch3>..<patch4>]']
 description = r"""
 Send a patch or a range of patches by e-mail using the SMTP server
 specified by the 'stgit.smtpserver' configuration option, or the
@@ -154,9 +154,14 @@ def __get_sender():
         try:
             sender = str(git.user())
         except git.GitException:
-            sender = str(git.author())
+            try:
+                sender = str(git.author())
+            except git.GitException:
+                pass
     if not sender:
-        raise CmdException, 'unknown sender details'
+        raise CmdException, ('Unknown sender name and e-mail; you should'
+                             ' for example set git config user.name and'
+                             ' user.email')
     sender = email.Utils.parseaddr(sender)
 
     return email.Utils.formataddr(address_or_alias(sender))
@@ -185,10 +190,20 @@ def __send_message_sendmail(sendmail, msg):
     cmd = sendmail.split()
     Run(*cmd).raw_input(msg).discard_output()
 
-def __send_message_smtp(smtpserver, from_addr, to_addr_list, msg,
-                        smtpuser, smtppassword, use_tls):
+def __send_message_smtp(smtpserver, from_addr, to_addr_list, msg, options):
     """Send the message using the given SMTP server
     """
+    smtppassword = options.smtp_password or config.get('stgit.smtppassword')
+    smtpuser = options.smtp_user or config.get('stgit.smtpuser')
+    smtpusetls = options.smtp_tls or config.get('stgit.smtptls') == 'yes'
+
+    if (smtppassword and not smtpuser):
+        raise CmdException('SMTP password supplied, username needed')
+    if (smtpusetls and not smtpuser):
+        raise CmdException('SMTP over TLS requested, username needed')
+    if (smtpuser and not smtppassword):
+        smtppassword = getpass.getpass("Please enter SMTP password: ")
+
     try:
         s = smtplib.SMTP(smtpserver)
     except Exception, err:
@@ -198,7 +213,7 @@ def __send_message_smtp(smtpserver, from_addr, to_addr_list, msg,
     try:
         if smtpuser and smtppassword:
             s.ehlo()
-            if use_tls:
+            if smtpusetls:
                 if not hasattr(socket, 'ssl'):
                     raise CmdException,  "cannot use TLS - no SSL support in Python"
                 s.starttls()
@@ -213,19 +228,17 @@ def __send_message_smtp(smtpserver, from_addr, to_addr_list, msg,
 
     s.quit()
 
-def __send_message(smtpserver, from_addr, to_addr_list, msg,
-                   sleep, smtpuser, smtppassword, use_tls):
+def __send_message(from_addr, to_addr_list, msg, options):
     """Message sending dispatcher.
     """
+    smtpserver = options.smtp_server or config.get('stgit.smtpserver')
+
     if smtpserver.startswith('/'):
         # Use the sendmail tool
         __send_message_sendmail(smtpserver, msg)
     else:
         # Use the SMTP server (we have host and port information)
-        __send_message_smtp(smtpserver, from_addr, to_addr_list, msg,
-                            smtpuser, smtppassword, use_tls)
-    # give recipients a chance of receiving patches in the correct order
-    time.sleep(sleep)
+        __send_message_smtp(smtpserver, from_addr, to_addr_list, msg, options)
 
 def __build_address_headers(msg, options, extra_cc = []):
     """Build the address headers and check existing headers in the
@@ -283,8 +296,17 @@ def __get_signers_list(msg):
     acked-by lines in the message.
     """
     addr_list = []
-
-    r = re.compile('^(signed-off-by|acked-by|cc):\s+(.+)$', re.I)
+    tags = '%s|%s|%s|%s|%s|%s|%s' % (
+            'signed-off-by',
+            'acked-by',
+            'cc',
+            'reviewed-by',
+            'reported-by',
+            'tested-by',
+            'reported-and-tested-by')
+    regex = '^(%s):\s+(.+)$' % tags
+
+    r = re.compile(regex, re.I)
     for line in msg.split('\n'):
         m = r.match(line)
         if m:
@@ -387,10 +409,11 @@ def __build_cover(tmpl, patches, msg_id, options):
                  'totalnr':      total_nr_str,
                  'number':       number_str,
                  'shortlog':     stack.shortlog(crt_series.get_patch(p)
-                                                for p in patches),
+                                                for p in reversed(patches)),
                  'diffstat':     gitlib.diffstat(git.diff(
                      rev1 = git_id(crt_series, '%s^' % patches[0]),
-                     rev2 = git_id(crt_series, '%s' % patches[-1])))}
+                     rev2 = git_id(crt_series, '%s' % patches[-1]),
+                     diff_flags = options.diff_flags))}
 
     try:
         msg_string = tmpl % tmpl_dict
@@ -530,8 +553,6 @@ def func(parser, options, args):
     """Send the patches by e-mail using the patchmail.tmpl file as
     a template
     """
-    smtpserver = options.smtp_server or config.get('stgit.smtpserver')
-
     applied = crt_series.get_applied()
 
     if options.all:
@@ -542,23 +563,15 @@ def func(parser, options, args):
     else:
         raise CmdException, 'Incorrect options. Unknown patches to send'
 
+    # early test for sender identity
+    __get_sender()
+
     out.start('Checking the validity of the patches')
     for p in patches:
         if crt_series.empty_patch(p):
             raise CmdException, 'Cannot send empty patch "%s"' % p
     out.done()
 
-    smtppassword = options.smtp_password or config.get('stgit.smtppassword')
-    smtpuser = options.smtp_user or config.get('stgit.smtpuser')
-    smtpusetls = options.smtp_tls or config.get('stgit.smtptls') == 'yes'
-
-    if (smtppassword and not smtpuser):
-        raise CmdException, 'SMTP password supplied, username needed'
-    if (smtpusetls and not smtpuser):
-        raise CmdException, 'SMTP over TLS requested, username needed'
-    if (smtpuser and not smtppassword):
-        smtppassword = getpass.getpass("Please enter SMTP password: ")
-
     total_nr = len(patches)
     if total_nr == 0:
         raise CmdException, 'No patches to send'
@@ -600,8 +613,8 @@ def func(parser, options, args):
             out.stdout_raw(msg_string + '\n')
         else:
             out.start('Sending the cover message')
-            __send_message(smtpserver, from_addr, to_addr_list, msg_string,
-                           sleep, smtpuser, smtppassword, smtpusetls)
+            __send_message(from_addr, to_addr_list, msg_string, options)
+            time.sleep(sleep)
             out.done()
 
     # send the patches
@@ -615,7 +628,7 @@ def func(parser, options, args):
         if not tmpl:
             raise CmdException, 'No e-mail template file found'
 
-    for (p, patch_nr) in zip(patches, range(1, len(patches) + 1)):
+    for (p, patch_nr) in zip(patches, range(1, total_nr + 1)):
         msg_id = email.Utils.make_msgid('stgit')
         msg = __build_message(tmpl, p, patch_nr, total_nr, msg_id, ref_id,
                               options)
@@ -631,6 +644,9 @@ def func(parser, options, args):
             out.stdout_raw(msg_string + '\n')
         else:
             out.start('Sending patch "%s"' % p)
-            __send_message(smtpserver, from_addr, to_addr_list, msg_string,
-                           sleep, smtpuser, smtppassword, smtpusetls)
+            __send_message(from_addr, to_addr_list, msg_string, options)
+            # give recipients a chance of receiving related patches in the
+            # correct order.
+            if patch_nr < total_nr:
+                time.sleep(sleep)
             out.done()