Merge lp:~vila/bzr/deprecation-warning-preference into lp:bzr

Proposed by Vincent Ladeuil
Status: Merged
Approved by: John A Meinel
Approved revision: no longer in the source branch.
Merged at revision: not available
Proposed branch: lp:~vila/bzr/deprecation-warning-preference
Merge into: lp:bzr
Diff against target: 404 lines (+189/-39)
9 files modified
NEWS (+9/-0)
bzrlib/branch.py (+2/-0)
bzrlib/config.py (+26/-1)
bzrlib/help_topics/en/configuration.txt (+12/-0)
bzrlib/remote.py (+5/-0)
bzrlib/repofmt/pack_repo.py (+2/-8)
bzrlib/repository.py (+16/-9)
bzrlib/tests/blackbox/test_exceptions.py (+66/-11)
bzrlib/tests/test_config.py (+51/-10)
To merge this branch: bzr merge lp:~vila/bzr/deprecation-warning-preference
Reviewer Review Type Date Requested Status
John A Meinel Approve
Review via email: mp+16233@code.launchpad.net
To post a comment you must log in.
Revision history for this message
Vincent Ladeuil (vila) wrote :

This patch supersedes https://code.edge.launchpad.net/~ted/bzr/deprecation-warning-preference/+merge/15455

It's a patch pilot attempt to land a work started by fullermd far too long ago and re-started by ted more recently.

I tried to capture most of the comments by Ian, Martin and John without spending too much time on it (but still...).

This patch adds:
- specifying a suppress_warnings variable in any configuration file,
- explicitly requiring a config variable as a list,
- a suppres_warning() method to config files,
- checks for format_deprecation at lock time on branch objects (which can then provide
  their config to the repo before locking it),
- checks for format_deprecation at lock on repo objects but relying on bazaar.conf only
  in that case.

I may file a bug or three for the remaining points so please comment if you disagree
with some decision made here but mention if you agree with postponing it (good) or you
think it's required to land (bad :).
The idea was to implement something that we could tweak further
but that will not require some upgrade dance in the future (so mainly: keep the same
variable name, don't force setting it in bazaar.conf so the default behaviour for
new branches is still to raise the warning).

These remaining points are:
- the actual implementation use a single global variable for the whole code base,
  forget about being warned for the second repo accessed (or the 20th for bzrlib users),
  that should be implemented as a repo attribute instead,
- working trees can raise format deprecation warnings too, they should use the new
  facility (I don't think we want to proliferate warning variables gratuitously)
- hpss remote repositories doesn't raise the warning locally (AFAICS but feel free
  to prove me wrong),
- no distinction is made between read and write access (I'm not sure I understand
  the need here),
- there is no config file for repositories were such an option can be specified.

My intent here is to provide a base for future work without addressing some existing problems (some of which have been revealed while writing this patch).

I didn't address John idea about filtering by format as I think we plan to
reduce the number of formats and push people to use the default ones.
The rationale is that: 1) you care or you don't care about being warned, 2) you can set
the option in various ways, the finest grain being the branch. I think that's
good enough.

Revision history for this message
John A Meinel (jameinel) wrote :

-----BEGIN PGP SIGNED MESSAGE-----
Hash: SHA1

Vincent Ladeuil wrote:
> Vincent Ladeuil has proposed merging lp:~vila/bzr/deprecation-warning-preference into lp:bzr.
>
> Requested reviews:
> bzr-core (bzr-core)
>
>

...

>
> I didn't address John idea about filtering by format as I think we plan to
> reduce the number of formats and push people to use the default ones.
> The rationale is that: 1) you care or you don't care about being warned, 2) you can set
> the option in various ways, the finest grain being the branch. I think that's
> good enough.
>
>
>

Well, *I* may not care about using --1.9, but I don't want to be using
- --weave anymore. Not to say other people are in that boat.

v- Is the extra 's' for extra suppression ?

+* The ``suppresss_warnings`` configuration option has been introduced and
+ accept the ``format_deprecation`` value to disable the corresponding
+ warning for repositories. It can be set to in either ``bazaar.conf``,
+ ``locations.conf`` or ``branch.conf``.
+ (Ted Gould, Matthew Fuller, Vincent Ladeuil)

You can use

config.LocationConfig(repo.bzrdir.root_transport.base) if you wanted to
support per-repo configuration.

Otherwise:

 review: approve
 merge: approve

John
=:->
-----BEGIN PGP SIGNATURE-----
Version: GnuPG v1.4.9 (Cygwin)
Comment: Using GnuPG with Mozilla - http://enigmail.mozdev.org/

iEYEARECAAYFAkspC1gACgkQJdeBCYSNAAMPagCgj07xNFxCF94NE0Lv+YtQXagO
+9UAnRLpaeeM3hjUd6OovoZJm2CAcbCF
=Y17e
-----END PGP SIGNATURE-----

review: Approve
Revision history for this message
Martin Pool (mbp) wrote :

Skimmed, looks good, thanks!

--
Martin <http://launchpad.net/~mbp/>

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

>>>>> "jam" == John A Meinel <email address hidden> writes:

<snip/>

    jam> Well, *I* may not care about using --1.9, but I don't
    jam> want to be using --weave anymore. Not to say other
    jam> people are in that boat.

What I meant (and forgot to add when writing the cover letter) is
that it's highly likely that people are coherent and use the same
format inside project boundaries so giving a path-based control
over the warning should be pretty close in ease of use to a
format-based control.

But the later is harder to implement and likely harder to use
(and my main point was that we don't want people to get involved
into all of your existing formats if we can avoid it :-)

    jam> v- Is the extra 's' for extra suppression ?

Exactly, I think I made that typo at least 50 times so be
grateful that I left only one as I'm grateful you caught it :D

    jam> +* The ``suppresss_warnings`` configuration option has been introduced and
    jam> + accept the ``format_deprecation`` value to disable the corresponding
    jam> + warning for repositories. It can be set to in either ``bazaar.conf``,
    jam> + ``locations.conf`` or ``branch.conf``.
    jam> + (Ted Gould, Matthew Fuller, Vincent Ladeuil)

    jam> You can use

    jam> config.LocationConfig(repo.bzrdir.root_transport.base) if you wanted to
    jam> support per-repo configuration.

I almost implemented it. I almost mentioned it in the cover letter.

But I had a bad feeling about it, it smells like a workaround. I
don't want to create yet another config file but at the same time
I have a feeling that it may address some other needs.

This needs discussion anyway so I didn't feel bad enough to
implement config.LocationConfig(repo.bzrdir.root_transport.base).

    jam> Otherwise:

    jam> review: approve
    jam> merge: approve

Thanks, you didn't comment on the remaining points so I've filed
bug #497694, comments there welcome.

    Vincent

Preview Diff

[H/L] Next/Prev Comment, [J/K] Next/Prev File, [N/P] Next/Prev Hunk
1=== modified file 'NEWS'
2--- NEWS 2009-12-15 19:59:00 +0000
3+++ NEWS 2009-12-16 10:09:27 +0000
4@@ -95,6 +95,7 @@
5 * ``bzr commit`` now has a ``--commit-time`` option.
6 (Alexander Sack, #459276)
7
8+<<<<<<< TREE
9 * ``-Dhpss`` now increases logging done when run on the bzr server,
10 similarly to how it works on the client. (John Arbash Meinel)
11
12@@ -108,6 +109,14 @@
13 lengths.
14 (Vincent Ladeuil)
15
16+=======
17+* The ``suppresss_warnings`` configuration option has been introduced and
18+ accept the ``format_deprecation`` value to disable the corresponding
19+ warning for repositories. It can be set to in either ``bazaar.conf``,
20+ ``locations.conf`` or ``branch.conf``.
21+ (Ted Gould, Matthew Fuller, Vincent Ladeuil)
22+
23+>>>>>>> MERGE-SOURCE
24 Bug Fixes
25 *********
26
27
28=== modified file 'bzrlib/branch.py'
29--- bzrlib/branch.py 2009-12-04 22:13:52 +0000
30+++ bzrlib/branch.py 2009-12-16 10:09:27 +0000
31@@ -2143,6 +2143,7 @@
32 # All-in-one needs to always unlock/lock.
33 repo_control = getattr(self.repository, 'control_files', None)
34 if self.control_files == repo_control or not self.is_locked():
35+ self.repository._warn_if_deprecated(self)
36 self.repository.lock_write()
37 took_lock = True
38 else:
39@@ -2160,6 +2161,7 @@
40 # All-in-one needs to always unlock/lock.
41 repo_control = getattr(self.repository, 'control_files', None)
42 if self.control_files == repo_control or not self.is_locked():
43+ self.repository._warn_if_deprecated(self)
44 self.repository.lock_read()
45 took_lock = True
46 else:
47
48=== modified file 'bzrlib/config.py'
49--- bzrlib/config.py 2009-12-02 22:04:04 +0000
50+++ bzrlib/config.py 2009-12-16 10:09:27 +0000
51@@ -190,11 +190,23 @@
52 """Get a generic option as a boolean - no special process, no default.
53
54 :return None if the option doesn't exist or its value can't be
55- interpreted as a boolean. Returns True or False ortherwise.
56+ interpreted as a boolean. Returns True or False otherwise.
57 """
58 s = self._get_user_option(option_name)
59 return ui.bool_from_string(s)
60
61+ def get_user_option_as_list(self, option_name):
62+ """Get a generic option as a list - no special process, no default.
63+
64+ :return None if the option doesn't exist. Returns the value as a list
65+ otherwise.
66+ """
67+ l = self._get_user_option(option_name)
68+ if isinstance(l, (str, unicode)):
69+ # A single value, most probably the user forgot the final ','
70+ l = [l]
71+ return l
72+
73 def gpg_signing_command(self):
74 """What program should be used to sign signatures?"""
75 result = self._gpg_signing_command()
76@@ -313,6 +325,19 @@
77 path = 'bzr'
78 return path
79
80+ def suppress_warning(self, warning):
81+ """Should the warning be suppressed or emitted.
82+
83+ :param warning: The name of the warning being tested.
84+
85+ :returns: True if the warning should be suppressed, False otherwise.
86+ """
87+ warnings = self.get_user_option_as_list('suppress_warnings')
88+ if warnings is None or warning not in warnings:
89+ return False
90+ else:
91+ return True
92+
93
94 class IniBasedConfig(Config):
95 """A configuration policy that draws from ini files."""
96
97=== modified file 'bzrlib/help_topics/en/configuration.txt'
98--- bzrlib/help_topics/en/configuration.txt 2009-10-02 09:11:43 +0000
99+++ bzrlib/help_topics/en/configuration.txt 2009-12-16 10:09:27 +0000
100@@ -428,6 +428,18 @@
101 A publically-accessible version of this branch (implying that this version is
102 not publically-accessible). Used (and set) by ``bzr send``.
103
104+suppress_warnings
105+~~~~~~~~~~~~~~~~~
106+
107+A list of strings, each string represent a warning that can be emitted by
108+bzr. Mentioning a warning in this list tells bzr to not emit it.
109+
110+Valid values:
111+
112+* ``format_deprecation``:
113+ whether the format deprecation warning is shown on repositories that are
114+ using deprecated formats.
115+
116
117 Branch type specific options
118 ----------------------------
119
120=== modified file 'bzrlib/remote.py'
121--- bzrlib/remote.py 2009-11-11 06:50:40 +0000
122+++ bzrlib/remote.py 2009-12-16 10:09:27 +0000
123@@ -951,6 +951,11 @@
124 def is_write_locked(self):
125 return self._lock_mode == 'w'
126
127+ def _warn_if_deprecated(self, branch=None):
128+ # If we have a real repository, the check will be done there, if we
129+ # don't the check will be done remotely.
130+ pass
131+
132 def lock_read(self):
133 # wrong eventually - want a local lock cache context
134 if not self._lock_mode:
135
136=== modified file 'bzrlib/repofmt/pack_repo.py'
137--- bzrlib/repofmt/pack_repo.py 2009-10-29 05:54:49 +0000
138+++ bzrlib/repofmt/pack_repo.py 2009-12-16 10:09:27 +0000
139@@ -2234,16 +2234,10 @@
140 self._reconcile_fixes_text_parents = True
141 self._reconcile_backsup_inventory = False
142
143- def _warn_if_deprecated(self):
144+ def _warn_if_deprecated(self, branch=None):
145 # This class isn't deprecated, but one sub-format is
146 if isinstance(self._format, RepositoryFormatKnitPack5RichRootBroken):
147- from bzrlib import repository
148- if repository._deprecation_warning_done:
149- return
150- repository._deprecation_warning_done = True
151- warning("Format %s for %s is deprecated - please use"
152- " 'bzr upgrade --1.6.1-rich-root'"
153- % (self._format, self.bzrdir.transport.base))
154+ super(KnitPackRepository, self)._warn_if_deprecated(branch)
155
156 def _abort_write_group(self):
157 self.revisions._index._key_dependencies.clear()
158
159=== modified file 'bzrlib/repository.py'
160--- bzrlib/repository.py 2009-12-03 05:31:03 +0000
161+++ bzrlib/repository.py 2009-12-16 10:09:27 +0000
162@@ -24,6 +24,7 @@
163 bzrdir,
164 check,
165 chk_map,
166+ config,
167 debug,
168 errors,
169 fetch as _mod_fetch,
170@@ -1304,11 +1305,6 @@
171 self._reconcile_does_inventory_gc = True
172 self._reconcile_fixes_text_parents = False
173 self._reconcile_backsup_inventory = True
174- # not right yet - should be more semantically clear ?
175- #
176- # TODO: make sure to construct the right store classes, etc, depending
177- # on whether escaping is required.
178- self._warn_if_deprecated()
179 self._write_group = None
180 # Additional places to query for data.
181 self._fallback_repositories = []
182@@ -1389,6 +1385,7 @@
183 locked = self.is_locked()
184 result = self.control_files.lock_write(token=token)
185 if not locked:
186+ self._warn_if_deprecated()
187 self._note_lock('w')
188 for repo in self._fallback_repositories:
189 # Writes don't affect fallback repos
190@@ -1400,6 +1397,7 @@
191 locked = self.is_locked()
192 self.control_files.lock_read()
193 if not locked:
194+ self._warn_if_deprecated()
195 self._note_lock('r')
196 for repo in self._fallback_repositories:
197 repo.lock_read()
198@@ -2782,13 +2780,22 @@
199 result.check(callback_refs)
200 return result
201
202- def _warn_if_deprecated(self):
203+ def _warn_if_deprecated(self, branch=None):
204 global _deprecation_warning_done
205 if _deprecation_warning_done:
206 return
207- _deprecation_warning_done = True
208- warning("Format %s for %s is deprecated - please use 'bzr upgrade' to get better performance"
209- % (self._format, self.bzrdir.transport.base))
210+ try:
211+ if branch is None:
212+ conf = config.GlobalConfig()
213+ else:
214+ conf = branch.get_config()
215+ if conf.suppress_warning('format_deprecation'):
216+ return
217+ warning("Format %s for %s is deprecated -"
218+ " please use 'bzr upgrade' to get better performance"
219+ % (self._format, self.bzrdir.transport.base))
220+ finally:
221+ _deprecation_warning_done = True
222
223 def supports_rich_root(self):
224 return self._format.rich_root_data
225
226=== modified file 'bzrlib/tests/blackbox/test_exceptions.py'
227--- bzrlib/tests/blackbox/test_exceptions.py 2009-08-20 06:25:02 +0000
228+++ bzrlib/tests/blackbox/test_exceptions.py 2009-12-16 10:09:27 +0000
229@@ -22,8 +22,11 @@
230
231 from bzrlib import (
232 bzrdir,
233+ config,
234 errors,
235+ osutils,
236 repository,
237+ tests,
238 trace,
239 )
240
241@@ -45,18 +48,70 @@
242 self.assertContainsRe(err, r'Bazaar has encountered an internal error')
243
244
245-class TestDeprecationWarning(TestCaseInTempDir):
246+class TestDeprecationWarning(tests.TestCaseWithTransport):
247+ """The deprecation warning is controlled via a global variable:
248+ repository._deprecation_warning_done. As such, it can be emitted only once
249+ during a bzr invocation, no matter how many repositories are involved.
250+
251+ It would be better if it was a repo attribute instead but that's far more
252+ work than I want to do right now -- vila 20091215.
253+ """
254+
255+ def setUp(self):
256+ super(TestDeprecationWarning, self).setUp()
257+ self.disable_deprecation_warning()
258+
259+ def enable_deprecation_warning(self, repo=None):
260+ """repo is not used yet since _deprecation_warning_done is a global"""
261+ repository._deprecation_warning_done = False
262+
263+ def disable_deprecation_warning(self, repo=None):
264+ """repo is not used yet since _deprecation_warning_done is a global"""
265+ repository._deprecation_warning_done = True
266+
267+ def make_obsolete_repo(self, path):
268+ # We don't want the deprecation raising during the repo creation
269+ tree = self.make_branch_and_tree(path, format=bzrdir.BzrDirFormat5())
270+ return tree
271+
272+ def check_warning(self, present):
273+ if present:
274+ check = self.assertContainsRe
275+ else:
276+ check = self.assertNotContainsRe
277+ check(self._get_log(keep_log_file=True), 'WARNING.*bzr upgrade')
278
279 def test_repository_deprecation_warning(self):
280 """Old formats give a warning"""
281- # the warning's normally off for testing but we reenable it
282- repository._deprecation_warning_done = False
283- try:
284- os.mkdir('foo')
285- bzrdir.BzrDirFormat5().initialize('foo')
286- out, err = self.run_bzr("status foo")
287- self.assertContainsRe(self._get_log(keep_log_file=True),
288- "bzr upgrade")
289- finally:
290- repository._deprecation_warning_done = True
291+ self.make_obsolete_repo('foo')
292+ self.enable_deprecation_warning()
293+ out, err = self.run_bzr('status', working_dir='foo')
294+ self.check_warning(True)
295+
296+ def test_repository_deprecation_warning_suppressed_global(self):
297+ """Old formats give a warning"""
298+ conf = config.GlobalConfig()
299+ conf.set_user_option('suppress_warnings', 'format_deprecation')
300+ self.make_obsolete_repo('foo')
301+ self.enable_deprecation_warning()
302+ out, err = self.run_bzr('status', working_dir='foo')
303+ self.check_warning(False)
304+
305+ def test_repository_deprecation_warning_suppressed_locations(self):
306+ """Old formats give a warning"""
307+ self.make_obsolete_repo('foo')
308+ conf = config.LocationConfig(osutils.pathjoin(self.test_dir, 'foo'))
309+ conf.set_user_option('suppress_warnings', 'format_deprecation')
310+ self.enable_deprecation_warning()
311+ out, err = self.run_bzr('status', working_dir='foo')
312+ self.check_warning(False)
313+
314+ def test_repository_deprecation_warning_suppressed_branch(self):
315+ """Old formats give a warning"""
316+ tree = self.make_obsolete_repo('foo')
317+ conf = tree.branch.get_config()
318+ conf.set_user_option('suppress_warnings', 'format_deprecation')
319+ self.enable_deprecation_warning()
320+ out, err = self.run_bzr('status', working_dir='foo')
321+ self.check_warning(False)
322
323
324=== modified file 'bzrlib/tests/test_config.py'
325--- bzrlib/tests/test_config.py 2009-10-31 01:43:48 +0000
326+++ bzrlib/tests/test_config.py 2009-12-16 10:09:27 +0000
327@@ -369,6 +369,14 @@
328
329 class TestIniConfig(tests.TestCase):
330
331+ def make_config_parser(self, s):
332+ conf = config.IniBasedConfig(None)
333+ parser = conf._get_parser(file=StringIO(s.encode('utf-8')))
334+ return conf, parser
335+
336+
337+class TestIniConfigBuilding(TestIniConfig):
338+
339 def test_contructs(self):
340 my_config = config.IniBasedConfig("nothing")
341
342@@ -385,20 +393,53 @@
343 parser = my_config._get_parser(file=config_file)
344 self.failUnless(my_config._get_parser() is parser)
345
346+
347+class TestGetUserOptionAs(TestIniConfig):
348+
349 def test_get_user_option_as_bool(self):
350- config_file = StringIO("""
351+ conf, parser = self.make_config_parser("""
352 a_true_bool = true
353 a_false_bool = 0
354 an_invalid_bool = maybe
355-a_list = hmm, who knows ? # This interpreted as a list !
356-""".encode('utf-8'))
357- my_config = config.IniBasedConfig(None)
358- parser = my_config._get_parser(file=config_file)
359- get_option = my_config.get_user_option_as_bool
360- self.assertEqual(True, get_option('a_true_bool'))
361- self.assertEqual(False, get_option('a_false_bool'))
362- self.assertIs(None, get_option('an_invalid_bool'))
363- self.assertIs(None, get_option('not_defined_in_this_config'))
364+a_list = hmm, who knows ? # This is interpreted as a list !
365+""")
366+ get_bool = conf.get_user_option_as_bool
367+ self.assertEqual(True, get_bool('a_true_bool'))
368+ self.assertEqual(False, get_bool('a_false_bool'))
369+ self.assertIs(None, get_bool('an_invalid_bool'))
370+ self.assertIs(None, get_bool('not_defined_in_this_config'))
371+
372+
373+ def test_get_user_option_as_list(self):
374+ conf, parser = self.make_config_parser("""
375+a_list = a,b,c
376+length_1 = 1,
377+one_item = x
378+""")
379+ get_list = conf.get_user_option_as_list
380+ self.assertEqual(['a', 'b', 'c'], get_list('a_list'))
381+ self.assertEqual(['1'], get_list('length_1'))
382+ self.assertEqual('x', conf.get_user_option('one_item'))
383+ # automatically cast to list
384+ self.assertEqual(['x'], get_list('one_item'))
385+
386+
387+class TestSupressWarning(TestIniConfig):
388+
389+ def make_warnings_config(self, s):
390+ conf, parser = self.make_config_parser(s)
391+ return conf.suppress_warning
392+
393+ def test_suppress_warning_unknown(self):
394+ suppress_warning = self.make_warnings_config('')
395+ self.assertEqual(False, suppress_warning('unknown_warning'))
396+
397+ def test_suppress_warning_known(self):
398+ suppress_warning = self.make_warnings_config('suppress_warnings=a,b')
399+ self.assertEqual(False, suppress_warning('c'))
400+ self.assertEqual(True, suppress_warning('a'))
401+ self.assertEqual(True, suppress_warning('b'))
402+
403
404 class TestGetConfig(tests.TestCase):
405