Merge lp:~jelmer/bzr/config-mail-client into lp:bzr

Proposed by Jelmer Vernooij
Status: Merged
Approved by: Vincent Ladeuil
Approved revision: no longer in the source branch.
Merged at revision: 6460
Proposed branch: lp:~jelmer/bzr/config-mail-client
Merge into: lp:bzr
Prerequisite: lp:~jelmer/bzr/config-registry-option
Diff against target: 284 lines (+75/-74)
7 files modified
bzrlib/config.py (+2/-11)
bzrlib/errors.py (+0/-8)
bzrlib/mail_client.py (+7/-5)
bzrlib/send.py (+3/-2)
bzrlib/tests/blackbox/test_send.py (+7/-6)
bzrlib/tests/test_config.py (+53/-42)
doc/en/release-notes/bzr-2.6.txt (+3/-0)
To merge this branch: bzr merge lp:~jelmer/bzr/config-mail-client
Reviewer Review Type Date Requested Status
Vincent Ladeuil Needs Fixing
Review via email: mp+90536@code.launchpad.net

Commit message

Use config stacks for 'mail_client' configuration option.

Description of the change

Convert the ''mail_client'' setting over to using config stacks.

To post a comment you must log in.
Revision history for this message
Vincent Ladeuil (vila) wrote :

This seems to mix to changes:
1 - the one described in the news entry,

2 - an incomplete migration of the mail_client option (which is more complex
    too)

I'm fine landing 1, I think the changes related to 2 should be kept for a
further proposal which can then be completed.

review: Needs Fixing
Revision history for this message
Jelmer Vernooij (jelmer) wrote :

Hi,

Thanks for all the config reviews!

> This seems to mix to changes:
> 1 - the one described in the news entry,
>
> 2 - an incomplete migration of the mail_client option (which is more complex
> too)
>
> I'm fine landing 1, I think the changes related to 2 should be kept for a
> further proposal which can then be completed.
I'm not sure I follow in what way (2) is incomplete, can you expand on that ?

Revision history for this message
Vincent Ladeuil (vila) wrote :

    >> This seems to mix to changes:
    >> 1 - the one described in the news entry,

Meh, typed too fast, I meant 'email' here not 'mail_client'. But even
that is not that easy, see below.

    >>
    >> 2 - an incomplete migration of the mail_client option (which is more complex
    >> too)
    >>
    >> I'm fine landing 1, I think the changes related to 2 should be kept for a
    >> further proposal which can then be completed.
    > I'm not sure I follow in what way (2) is incomplete, can you expand on that ?

My bad, I read a bit fast and missed:

+ mail_client = config_stack.get('mail_client')(config_stack)

\o/

In the old implementation, I disliked the fact that the config object
was responsible for building (and returning !) a specific object as it
meant the API became asymmetric: this object couldn't be passed to
set().

I'm delighted you've addressed that too :)

Unfortunately, while this is precisely where I want us to go, this is
(also) precisely where tests are failing (bb.test_send).

Moreover, switching to a config_stack as the parameter to build mail
clients also breaks compatibility. Hence: more complex.

Revision history for this message
Jelmer Vernooij (jelmer) wrote :

On Mon, Jan 30, 2012 at 07:19:25AM -0000, Vincent Ladeuil wrote:
>
> >>
> >> 2 - an incomplete migration of the mail_client option (which is more complex
> >> too)
> >>
> >> I'm fine landing 1, I think the changes related to 2 should be kept for a
> >> further proposal which can then be completed.
> > I'm not sure I follow in what way (2) is incomplete, can you expand on that ?
> My bad, I read a bit fast and missed:
>
> + mail_client = config_stack.get('mail_client')(config_stack)
>
> \o/
>
> In the old implementation, I disliked the fact that the config object
> was responsible for building (and returning !) a specific object as it
> meant the API became asymmetric: this object couldn't be passed to
> set().
>
> I'm delighted you've addressed that too :)
>
> Unfortunately, while this is precisely where I want us to go, this is
> (also) precisely where tests are failing (bb.test_send).
These should now be fixed - we were missing invalid='error'.

> Moreover, switching to a config_stack as the parameter to build mail
> clients also breaks compatibility. Hence: more complex.
That's why I mentioned it in the API changes section. Do we really
have to worry about external mail client implementations, are there
any out there?

Cheers,

Jelmer

Revision history for this message
Vincent Ladeuil (vila) wrote :

> > Unfortunately, while this is precisely where I want us to go, this is
> > (also) precisely where tests are failing (bb.test_send).
> These should now be fixed - we were missing invalid='error'.

Ha cool, sorry, I didn't dig.

>
> > Moreover, switching to a config_stack as the parameter to build mail
> > clients also breaks compatibility. Hence: more complex.
> That's why I mentioned it in the API changes section. Do we really
> have to worry about external mail client implementations, are there
> any out there?

Probably not that much and they could be fixed easily. But I'm more worried
about users of get_mail_client (which you've deleted).

Greping through all the plugins I have source for, I found hits for
grep_mail_client in bzr-gtk and... that's all ? Wow, will be easy to fix
then :)

May be deprecating and throwing an error from this method would make it
clearer for potential users ?

You still have a failing (and eager) test (<mutter> split ! </mutter) using
get_mail_client by the way.

ERROR: test_config.TestBranchConfigItems.test_get_mail_client

Other than that, I'm glad the invalid='error' was enough and it now seems
more landable.

Let's share the blame if things go wrong, fix the test and land ;)

review: Needs Fixing

Preview Diff

[H/L] Next/Prev Comment, [J/K] Next/Prev File, [N/P] Next/Prev Hunk
1=== modified file 'bzrlib/config.py'
2--- bzrlib/config.py 2012-01-28 17:58:09 +0000
3+++ bzrlib/config.py 2012-02-02 12:15:24 +0000
4@@ -92,7 +92,6 @@
5 lazy_regex,
6 library_state,
7 lockdir,
8- mail_client,
9 mergetools,
10 osutils,
11 symbol_versioning,
12@@ -240,16 +239,6 @@
13 return diff.DiffFromTool.from_string(cmd, old_tree, new_tree,
14 sys.stdout)
15
16- def get_mail_client(self):
17- """Get a mail client to use"""
18- selected_client = self.get_user_option('mail_client')
19- _registry = mail_client.mail_client_registry
20- try:
21- mail_client_class = _registry.get(selected_client)
22- except KeyError:
23- raise errors.UnknownMailClient(selected_client)
24- return mail_client_class(self)
25-
26 def _get_signature_checking(self):
27 """Template method to override signature checking policy."""
28
29@@ -2803,6 +2792,8 @@
30 Standard log formats are ``long``, ``short`` and ``line``. Additional formats
31 may be provided by plugins.
32 '''))
33+option_registry.register_lazy('mail_client', 'bzrlib.mail_client',
34+ 'opt_mail_client')
35 option_registry.register(
36 Option('output_encoding',
37 help= 'Unicode encoding for output'
38
39=== modified file 'bzrlib/errors.py'
40--- bzrlib/errors.py 2012-01-31 18:25:57 +0000
41+++ bzrlib/errors.py 2012-02-02 12:15:24 +0000
42@@ -2768,14 +2768,6 @@
43 _fmt = "No mail-to address (--mail-to) or output (-o) specified."
44
45
46-class UnknownMailClient(BzrError):
47-
48- _fmt = "Unknown mail client: %(mail_client)s"
49-
50- def __init__(self, mail_client):
51- BzrError.__init__(self, mail_client=mail_client)
52-
53-
54 class MailClientNotFound(BzrError):
55
56 _fmt = "Unable to find mail client with the following names:"\
57
58=== modified file 'bzrlib/mail_client.py'
59--- bzrlib/mail_client.py 2011-12-19 10:58:39 +0000
60+++ bzrlib/mail_client.py 2012-02-02 12:15:24 +0000
61@@ -24,6 +24,7 @@
62
63 import bzrlib
64 from bzrlib import (
65+ config as _mod_config,
66 email_message,
67 errors,
68 msgeditor,
69@@ -111,7 +112,7 @@
70 if body == '':
71 raise errors.NoMessageSupplied()
72 email_message.EmailMessage.send(self.config,
73- self.config.username(),
74+ self.config.get('email'),
75 to,
76 subject,
77 body,
78@@ -378,7 +379,7 @@
79 extension, body=None, from_=None):
80 """See ExternalMailClient._compose"""
81 if from_ is None:
82- from_ = self.config.get_user_option('email')
83+ from_ = self.config.get('email')
84 super(Claws, self)._compose(prompt, to, subject, attach_path,
85 mime_subtype, extension, body, from_)
86
87@@ -617,11 +618,11 @@
88 """See MailClient.compose"""
89 try:
90 return self._mail_client().compose(prompt, to, subject,
91- attachment, mimie_subtype,
92+ attachment, mime_subtype,
93 extension, basename, body)
94 except errors.MailClientNotFound:
95 return Editor(self.config).compose(prompt, to, subject,
96- attachment, mimie_subtype, extension, body)
97+ attachment, mime_subtype, extension, body)
98
99 def compose_merge_request(self, to, subject, directive, basename=None,
100 body=None):
101@@ -636,4 +637,5 @@
102 help=DefaultMail.__doc__)
103 mail_client_registry.default_key = 'default'
104
105-
106+opt_mail_client = _mod_config.RegistryOption('mail_client',
107+ mail_client_registry, help='E-mail client to use.', invalid='error')
108
109=== modified file 'bzrlib/send.py'
110--- bzrlib/send.py 2012-01-25 15:53:18 +0000
111+++ bzrlib/send.py 2012-02-02 12:15:24 +0000
112@@ -49,9 +49,10 @@
113 branch.lock_write()
114 try:
115 if output is None:
116+ config_stack = branch.get_config_stack()
117 if mail_to is None:
118- mail_to = branch.get_config_stack().get('submit_to')
119- mail_client = branch.get_config().get_mail_client()
120+ mail_to = config_stack.get('submit_to')
121+ mail_client = config_stack.get('mail_client')(config_stack)
122 if (not getattr(mail_client, 'supports_body', False)
123 and body is not None):
124 raise errors.BzrCommandError(gettext(
125
126=== modified file 'bzrlib/tests/blackbox/test_send.py'
127--- bzrlib/tests/blackbox/test_send.py 2012-01-25 15:53:18 +0000
128+++ bzrlib/tests/blackbox/test_send.py 2012-02-02 12:15:24 +0000
129@@ -193,25 +193,26 @@
130
131 def test_mailto_option(self):
132 b = branch.Branch.open('branch')
133- b.get_config().set_user_option('mail_client', 'editor')
134+ b.get_config_stack().set('mail_client', 'editor')
135 self.run_bzr_error(
136 ('No mail-to address \\(--mail-to\\) or output \\(-o\\) specified',
137 ), 'send -f branch')
138- b.get_config().set_user_option('mail_client', 'bogus')
139+ b.get_config_stack().set('mail_client', 'bogus')
140 self.run_send([])
141- self.run_bzr_error(('Unknown mail client: bogus',),
142+ self.run_bzr_error(('Bad value "bogus" for option "mail_client"',),
143 'send -f branch --mail-to jrandom@example.org')
144 b.get_config_stack().set('submit_to', 'jrandom@example.org')
145- self.run_bzr_error(('Unknown mail client: bogus',),
146+ self.run_bzr_error(('Bad value "bogus" for option "mail_client"',),
147 'send -f branch')
148
149 def test_mailto_child_option(self):
150 """Make sure that child_submit_to is used."""
151 b = branch.Branch.open('branch')
152- b.get_config().set_user_option('mail_client', 'bogus')
153+ b.get_config_stack().set('mail_client', 'bogus')
154 parent = branch.Branch.open('parent')
155 parent.get_config_stack().set('child_submit_to', 'somebody@example.org')
156- self.run_bzr_error(('Unknown mail client: bogus',), 'send -f branch')
157+ self.run_bzr_error(('Bad value "bogus" for option "mail_client"',),
158+ 'send -f branch')
159
160 def test_format(self):
161 md = self.get_MD(['--format=4'])
162
163=== modified file 'bzrlib/tests/test_config.py'
164--- bzrlib/tests/test_config.py 2012-01-27 21:25:21 +0000
165+++ bzrlib/tests/test_config.py 2012-02-02 12:15:24 +0000
166@@ -1904,48 +1904,6 @@
167 location='http://example.com/specific')
168 self.assertEqual(my_config.get_user_option('option'), 'exact')
169
170- def test_get_mail_client(self):
171- config = self.get_branch_config()
172- client = config.get_mail_client()
173- self.assertIsInstance(client, mail_client.DefaultMail)
174-
175- # Specific clients
176- config.set_user_option('mail_client', 'evolution')
177- client = config.get_mail_client()
178- self.assertIsInstance(client, mail_client.Evolution)
179-
180- config.set_user_option('mail_client', 'kmail')
181- client = config.get_mail_client()
182- self.assertIsInstance(client, mail_client.KMail)
183-
184- config.set_user_option('mail_client', 'mutt')
185- client = config.get_mail_client()
186- self.assertIsInstance(client, mail_client.Mutt)
187-
188- config.set_user_option('mail_client', 'thunderbird')
189- client = config.get_mail_client()
190- self.assertIsInstance(client, mail_client.Thunderbird)
191-
192- # Generic options
193- config.set_user_option('mail_client', 'default')
194- client = config.get_mail_client()
195- self.assertIsInstance(client, mail_client.DefaultMail)
196-
197- config.set_user_option('mail_client', 'editor')
198- client = config.get_mail_client()
199- self.assertIsInstance(client, mail_client.Editor)
200-
201- config.set_user_option('mail_client', 'mapi')
202- client = config.get_mail_client()
203- self.assertIsInstance(client, mail_client.MAPIClient)
204-
205- config.set_user_option('mail_client', 'xdg-email')
206- client = config.get_mail_client()
207- self.assertIsInstance(client, mail_client.XDGEmail)
208-
209- config.set_user_option('mail_client', 'firebird')
210- self.assertRaises(errors.UnknownMailClient, config.get_mail_client)
211-
212
213 class TestMailAddressExtraction(tests.TestCase):
214
215@@ -4889,3 +4847,56 @@
216 self.overrideEnv('BZR_EMAIL', None)
217 self.overrideEnv('EMAIL', 'jelmer@samba.org')
218 self.assertEquals('jelmer@debian.org', conf.get('email'))
219+
220+
221+class MailClientOptionTests(tests.TestCase):
222+
223+ def test_default(self):
224+ conf = config.MemoryStack('')
225+ client = conf.get('mail_client')
226+ self.assertIs(client, mail_client.DefaultMail)
227+
228+ def test_evolution(self):
229+ conf = config.MemoryStack('mail_client=evolution')
230+ client = conf.get('mail_client')
231+ self.assertIs(client, mail_client.Evolution)
232+
233+ def test_kmail(self):
234+ conf = config.MemoryStack('mail_client=kmail')
235+ client = conf.get('mail_client')
236+ self.assertIs(client, mail_client.KMail)
237+
238+ def test_mutt(self):
239+ conf = config.MemoryStack('mail_client=mutt')
240+ client = conf.get('mail_client')
241+ self.assertIs(client, mail_client.Mutt)
242+
243+ def test_thunderbird(self):
244+ conf = config.MemoryStack('mail_client=thunderbird')
245+ client = conf.get('mail_client')
246+ self.assertIs(client, mail_client.Thunderbird)
247+
248+ def test_explicit_default(self):
249+ conf = config.MemoryStack('mail_client=default')
250+ client = conf.get('mail_client')
251+ self.assertIs(client, mail_client.DefaultMail)
252+
253+ def test_editor(self):
254+ conf = config.MemoryStack('mail_client=editor')
255+ client = conf.get('mail_client')
256+ self.assertIs(client, mail_client.Editor)
257+
258+ def test_mapi(self):
259+ conf = config.MemoryStack('mail_client=mapi')
260+ client = conf.get('mail_client')
261+ self.assertIs(client, mail_client.MAPIClient)
262+
263+ def test_xdg_email(self):
264+ conf = config.MemoryStack('mail_client=xdg-email')
265+ client = conf.get('mail_client')
266+ self.assertIs(client, mail_client.XDGEmail)
267+
268+ def test_unknown(self):
269+ conf = config.MemoryStack('mail_client=firebird')
270+ self.assertRaises(errors.ConfigOptionValueError, conf.get,
271+ 'mail_client')
272
273=== modified file 'doc/en/release-notes/bzr-2.6.txt'
274--- doc/en/release-notes/bzr-2.6.txt 2012-01-27 21:11:36 +0000
275+++ doc/en/release-notes/bzr-2.6.txt 2012-02-02 12:15:24 +0000
276@@ -52,6 +52,9 @@
277 or tuples of bytestrings.
278 (Jelmer Vernooij)
279
280+* ``mail_client`` now accepts a configuration stack object rather than
281+ an old style Config object. (Jelmer Vernooij)
282+
283 * New configuration option class ``RegistryOption`` which is backed
284 onto a registry. (Jelmer Vernooij)
285