Rev 3365: Use mail-user-agent for Emacs mail clients (xma) in file:///home/pqm/archives/thelove/bzr/%2Btrunk/

Canonical.com Patch Queue Manager pqm at pqm.ubuntu.com
Sun Apr 13 20:44:36 BST 2008


At file:///home/pqm/archives/thelove/bzr/%2Btrunk/

------------------------------------------------------------
revno: 3365
revision-id:pqm at pqm.ubuntu.com-20080413194429-a5e4pft9sffa2ycu
parent: pqm at pqm.ubuntu.com-20080412084839-344825k3wbmbzzzf
parent: aaron at aaronbentley.com-20080413174114-kktjwgp1ahjimcn9
committer: Canonical.com Patch Queue Manager <pqm at pqm.ubuntu.com>
branch nick: +trunk
timestamp: Sun 2008-04-13 20:44:29 +0100
message:
  Use mail-user-agent for Emacs mail clients (xma)
modified:
  NEWS                           NEWS-20050323055033-4e00b5db738777ff
  bzrlib/config.py               config.py-20051011043216-070c74f4e9e338e8
  bzrlib/mail_client.py          mail_client.py-20070809192806-vuxt3t19srtpjpdn-1
  bzrlib/tests/test_mail_client.py test_mail_client.py-20070809192806-vuxt3t19srtpjpdn-2
    ------------------------------------------------------------
    revno: 3364.1.2
    revision-id:aaron at aaronbentley.com-20080413174114-kktjwgp1ahjimcn9
    parent: aaron at aaronbentley.com-20080413173834-tzh23thfzx23121c
    committer: Aaron Bentley <aaron at aaronbentley.com>
    branch nick: bzr.ab.integration
    timestamp: Sun 2008-04-13 13:41:14 -0400
    message:
      Update NEWS for 1.5 cycle
    modified:
      NEWS                           NEWS-20050323055033-4e00b5db738777ff
    ------------------------------------------------------------
    revno: 3364.1.1
    revision-id:aaron at aaronbentley.com-20080413173834-tzh23thfzx23121c
    parent: pqm at pqm.ubuntu.com-20080412084839-344825k3wbmbzzzf
    parent: xma at gnu.org-20080413114800-b3tp394elic1793b
    committer: Aaron Bentley <aaron at aaronbentley.com>
    branch nick: bzr.ab.integration
    timestamp: Sun 2008-04-13 13:38:34 -0400
    message:
      Merge Emacs mail-user-agent patch
    modified:
      NEWS                           NEWS-20050323055033-4e00b5db738777ff
      bzrlib/config.py               config.py-20051011043216-070c74f4e9e338e8
      bzrlib/mail_client.py          mail_client.py-20070809192806-vuxt3t19srtpjpdn-1
      bzrlib/tests/test_mail_client.py test_mail_client.py-20070809192806-vuxt3t19srtpjpdn-2
    ------------------------------------------------------------
    revno: 3324.4.1
    revision-id:xma at gnu.org-20080413114800-b3tp394elic1793b
    parent: pqm at pqm.ubuntu.com-20080401091848-6y4f104r061ad8bk
    committer: Xavier Maillard <xma at gnu.org>
    branch nick: xma-emacsclient
    timestamp: Sun 2008-04-13 13:48:00 +0200
    message:
      Replace mail-mode call with compose-mail from GNU Emacs.
      
      This patch is a modified version of the current revno 3323.
      
      It overloads it by:
      
      1. defining a different python class EmacsMail "MUA agnostic".
      
         To use this option, just put these lines into ~/.bazaar/bazaar.conf
          
      [DEFAULT]
      mail_client = emacsclient
      
      2. supporting any mail client of GNU Emacs family (mail-mode,
         message-mode, ...) The right tool will be called according to the
         value of the variable ``mail-user-agent``. So Virtually any Emacs
         mail client will work transparently if registered against
         ``mail-user-agent``.
      
      3. adding a wrapper function around MIME attachment. This allow us not
         to have many different functions/classes to attach a file but one.
      
      4. tests have been updated to follow the changes.
    modified:
      NEWS                           NEWS-20050323055033-4e00b5db738777ff
      bzrlib/config.py               config.py-20051011043216-070c74f4e9e338e8
      bzrlib/mail_client.py          mail_client.py-20070809192806-vuxt3t19srtpjpdn-1
      bzrlib/tests/test_mail_client.py test_mail_client.py-20070809192806-vuxt3t19srtpjpdn-2
=== modified file 'NEWS'
--- a/NEWS	2008-04-12 06:46:35 +0000
+++ b/NEWS	2008-04-13 17:41:14 +0000
@@ -12,6 +12,29 @@
 
   CHANGES:
 
+    * Broader support of GNU Emacs mail clients. Set
+      ``mail_client=emacsclient`` in your bazaar.conf and ``send`` will pop the
+      bundle in a mail buffer according to the value of ``mail-user-agent``
+      variable. (Xavier Maillard)
+
+  FEATURES:
+
+  IMPROVEMENTS:
+
+  BUGFIXES:
+
+  DOCUMENTATION:
+
+  TESTING:
+
+  INTERNALS:
+
+  API BREAKS:
+
+
+bzr 1.4rc1 2008-04-11
+---------------------
+
    * bzr main script cannot be imported (Benjamin Peterson)
 
    * On Linux bzr additionally looks for plugins in arch-independent site
@@ -36,9 +59,6 @@
 
   FEATURES:
 
-    * Added mail-mode GNU Emacs mail package as a mail_client.
-      (Xavier Maillard, Bojan Nikolic)
-
     * Added start_commit hook for mutable trees. (Jelmer Vernooij, #186422)
 
     * ``status`` now accepts ``--no-pending`` to show the status without

=== modified file 'bzrlib/config.py'
--- a/bzrlib/config.py	2008-04-10 13:30:05 +0000
+++ b/bzrlib/config.py	2008-04-13 17:38:34 +0000
@@ -151,6 +151,7 @@
             mail_client_class = {
                 None: mail_client.DefaultMail,
                 # Specific clients
+                'emacsclient': mail_client.EmacsMail,
                 'evolution': mail_client.Evolution,
                 'kmail': mail_client.KMail,
                 'mutt': mail_client.Mutt,
@@ -159,7 +160,6 @@
                 'default': mail_client.DefaultMail,
                 'editor': mail_client.Editor,
                 'mapi': mail_client.MAPIClient,
-                'emacs-mailmode': mail_client.EmacsMailMode,
                 'xdg-email': mail_client.XDGEmail,
             }[selected_client]
         except KeyError:

=== modified file 'bzrlib/mail_client.py'
--- a/bzrlib/mail_client.py	2008-04-01 04:19:06 +0000
+++ b/bzrlib/mail_client.py	2008-04-13 11:48:00 +0000
@@ -306,16 +306,67 @@
         return commandline
 
 
-class EmacsMailMode(ExternalMailClient):
-    """Call emacsclient in mail-mode.
-    
-    This only work for emacs >= 22.1.
+class EmacsMail(ExternalMailClient):
+    """Call emacsclient to have a mail buffer.
+
+    This only work for emacs >= 22.1 due to recent -e/--eval support.
+
+    The good news is that this implementation will work with all mail
+    agents registered against ``mail-user-agent``. So there is no need
+    to instantiate ExternalMailClient for each and every GNU Emacs
+    MUA.
+
+    Users just have to ensure that ``mail-user-agent`` is set according
+    to their tastes.
     """
+
     _client_commands = ['emacsclient']
 
+    def _prepare_send_function(self):
+        """Write our wrapper function into a temporary file.
+
+        This temporary file will be loaded at runtime in
+        _get_compose_commandline function.
+
+        FIXME: this function does not remove the file. That's a wanted
+        behaviour since _get_compose_commandline won't run the send
+        mail function directly but return the eligible command line.
+        Removing our temporary file here would prevent our sendmail
+        function to work.
+
+        A possible workaround could be to load the function here with
+        emacsclient --eval '(load temp)' but this is not robust since
+        emacs could have been stopped between here and the call to
+        mail client.
+        """
+
+        _defun = r"""(defun bzr-add-mime-att (file)
+  "Attach FILe to a mail buffer as a MIME attachment."
+  (let ((agent mail-user-agent))
+    (mail-text)
+    (newline)
+    (if (and file (file-exists-p file))
+        (cond
+         ((eq agent 'sendmail-user-agent)
+          (etach-attach file))
+         ((or (eq agent 'message-user-agent)(eq agent 'gnus-user-agent))
+          (mml-attach-file file "text/x-patch" "BZR merge" "attachment"))
+         (t
+          (message "Unhandled MUA")))
+      (error "File %s does not exist." file))))
+"""
+
+        fd, temp_file = tempfile.mkstemp(prefix="emacs-bzr-send-",
+                                         suffix=".el")
+        try:
+            os.write(fd, _defun)
+        finally:
+            os.close(fd) # Just close the handle but do not remove the file.
+        return temp_file
+
     def _get_compose_commandline(self, to, subject, attach_path):
         commandline = ["--eval"]
-        # Ensure we can at least have an empty mail-mode buffer
+
         _to = "nil"
         _subject = "nil"
 
@@ -323,19 +374,23 @@
             _to = ("\"%s\"" % self._encode_safe(to))
         if subject is not None:
             _subject = ("\"%s\"" % self._encode_safe(subject))
-        mmform = "(mail nil %s %s)" % (_to ,_subject)
-
-        # call mail-mode, move the point to body and insert a new blank line
-        # we *must* force this point movement for the case when To is not passed
-        # with --mail-to. Without this, the patch could be inserted at the wrong place
-        commandline.append(mmform)
-        commandline.append("(mail-text)")
-        commandline.append("(newline)")
-
-        # ... and put a MIME attachment (if any)
+
+        # Funcall the default mail composition function
+        # This will work with any mail mode including default mail-mode
+        # User must tweak mail-user-agent variable to tell what function
+        # will be called inside compose-mail.
+        mail_cmd = "(compose-mail %s %s)" % (_to, _subject)
+        commandline.append(mail_cmd)
+
+        # Try to attach a MIME attachment using our wrapper function
         if attach_path is not None:
-            ifform = "(attach \"%s\")" % self._encode_path(attach_path,'attachment')
-            commandline.append(ifform)
+            # Do not create a file if there is no attachment
+            lmmform = '(load "%s")' % self._prepare_send_function()
+            mmform  = '(bzr-add-mime-att "%s")' % \
+                self._encode_path(attach_path, 'attachment')
+            commandline.append(lmmform)
+            commandline.append(mmform)
+
         return commandline
 
 

=== modified file 'bzrlib/tests/test_mail_client.py'
--- a/bzrlib/tests/test_mail_client.py	2008-04-01 04:19:06 +0000
+++ b/bzrlib/tests/test_mail_client.py	2008-04-13 11:48:00 +0000
@@ -71,27 +71,34 @@
                 'Command-line item %r is unicode!' % item)
 
 
-class TestEmacsMailMode(tests.TestCase):
+class TestEmacsMail(tests.TestCase):
 
     def test_commandline(self):
-        eclient = mail_client.EmacsMailMode(None)
-        commandline = eclient._get_compose_commandline(None, None, 'file%')
-        self.assertEqual(['--eval', '(mail nil nil nil)',
-                          '(mail-text)', '(newline)',
-                          '(attach "file%")'], commandline)
+        eclient = mail_client.EmacsMail(None)
+
+        commandline = eclient._get_compose_commandline(None, 'Hi there!', None)
+        self.assertEqual(['--eval', '(compose-mail nil "Hi there!")'],
+                         commandline)
 
         commandline = eclient._get_compose_commandline('jrandom at example.org',
-                                                     'Hi there!', None)
-        self.assertEqual(['--eval', '(mail nil "jrandom at example.org" "Hi there!")',
-                          '(mail-text)', '(newline)'], commandline)
+                                                       'Hi there!', None)
+        self.assertEqual(['--eval',
+                          '(compose-mail "jrandom at example.org" "Hi there!")'],
+                         commandline)
+
+        # We won't be able to know the temporary file name at this stage
+        # so we can't raise an assertion with assertEqual
+        cmdline = eclient._get_compose_commandline(None, None, 'file%')
+        commandline = ' '.join(cmdline)
+        self.assertContainsRe(commandline, '--eval')
+        self.assertContainsRe(commandline, '(compose-mail nil nil)')
+        self.assertContainsRe(commandline, '(load .*)')
+        self.assertContainsRe(commandline, '(bzr-add-mime-att \"file%\")')
 
     def test_commandline_is_8bit(self):
-        eclient = mail_client.EmacsMailMode(None)
+        eclient = mail_client.EmacsMail(None)
         commandline = eclient._get_compose_commandline(u'jrandom at example.org',
             u'Hi there!', u'file%')
-        self.assertEqual(['--eval', '(mail nil "jrandom at example.org" "Hi there!")',
-                          '(mail-text)', '(newline)',
-                          '(attach "file%")'], commandline)
         for item in commandline:
             self.assertFalse(isinstance(item, unicode),
                 'Command-line item %r is unicode!' % item)




More information about the bazaar-commits mailing list