Merge lp:~mbp/bzr/deprecation-old into lp:~bzr/bzr/trunk-old

Proposed by Martin Pool
Status: Merged
Merged at revision: not available
Proposed branch: lp:~mbp/bzr/deprecation-old
Merge into: lp:~bzr/bzr/trunk-old
Diff against target: 769 lines
To merge this branch: bzr merge lp:~mbp/bzr/deprecation-old
Reviewer Review Type Date Requested Status
John A Meinel Approve
Review via email: mp+7135@code.launchpad.net
To post a comment you must log in.
Revision history for this message
Martin Pool (mbp) wrote :

This deprecates and deletes old progress bar related code, and the weave.py main method.

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

This seems okay, though I wonder if you deleted too many tests.

Usually when we deprecate something, we keep it under test, and add a "callDeprecated" or "applyDeprecated" wrap around its call. Which ensures that
1) it is still properly deprecated
2) And it still works the way it used to, until it is removed

Deleting the tests of things that were already deprecated is, of course, fine.

Anyway, just take another quick look and see if you really wanted to delete all of TestProgressTypes, and if so, go ahead and merge.

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

2009/6/8 John A Meinel <email address hidden>:
> Review: Approve
> This seems okay, though I wonder if you deleted too many tests.
>
> Usually when we deprecate something, we keep it under test, and add a "callDeprecated" or "applyDeprecated" wrap around its call. Which ensures that
> 1) it is still properly deprecated
> 2) And it still works the way it used to, until it is removed
>
> Deleting the tests of things that were already deprecated is, of course, fine.
>
> Anyway, just take another quick look and see if you really wanted to delete all of TestProgressTypes, and if so, go ahead and merge.

I wondered whether we should delete them too, however, keeping them
and getting them to catch warnings in all the right places was just
more work than seemed worthwhile for code that's going away. It also
makes it more clear where testing is needed for the new code. :)

The specific problem was that although it's easy to test that one
particular deprecated function works, there's no obvious way to say
"and it's ok if it calls other deprecated code in turn." Really we
also shouldn't issue warnings in that case even at run time. Some
fixes are possible but I didn't want to do them here.

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

Preview Diff

[H/L] Next/Prev Comment, [J/K] Next/Prev File, [N/P] Next/Prev Hunk
=== modified file 'NEWS'
--- NEWS 2009-06-05 23:21:51 +0000
+++ NEWS 2009-06-06 02:35:12 +0000
@@ -103,13 +103,19 @@
103103
104* Added osutils.parent_directories(). (Ian Clatworthy)104* Added osutils.parent_directories(). (Ian Clatworthy)
105105
106* ``bzrlib.progress.ProgressBar``, ``ChildProgress``, ``DotsProgressBar``,
107 ``TTYProgressBar`` and ``child_progress`` are now deprecated; use
108 ``ui_factory.nested_progress_bar`` instead. (Martin Pool)
109
106* TreeTransformBase no longer assumes that limbo is provided via disk.110* TreeTransformBase no longer assumes that limbo is provided via disk.
107 DiskTreeTransform now provides disk functionality. (Aaron Bentley)111 DiskTreeTransform now provides disk functionality. (Aaron Bentley)
108112
109
110Internals113Internals
111*********114*********
112115
116* Remove ``weave.py`` script for accessing internals of old weave-format
117 repositories. (Martin Pool)
118
113Testing119Testing
114*******120*******
115121
116122
=== modified file 'bzrlib/progress.py'
--- bzrlib/progress.py 2009-03-23 14:59:43 +0000
+++ bzrlib/progress.py 2009-06-06 02:35:12 +0000
@@ -36,11 +36,13 @@
36 )36 )
37from bzrlib.trace import mutter37from bzrlib.trace import mutter
38from bzrlib.symbol_versioning import (38from bzrlib.symbol_versioning import (
39 deprecated_function,
39 deprecated_in,40 deprecated_in,
40 deprecated_method,41 deprecated_method,
41 )42 )
4243
4344
45# XXX: deprecated; can be removed when the ProgressBar factory is removed
44def _supports_progress(f):46def _supports_progress(f):
45 """Detect if we can use pretty progress bars on the output stream f.47 """Detect if we can use pretty progress bars on the output stream f.
4648
@@ -140,6 +142,7 @@
140 self.ui_factory.clear_term()142 self.ui_factory.clear_term()
141143
142144
145@deprecated_function(deprecated_in((1, 16, 0)))
143def ProgressBar(to_file=None, **kwargs):146def ProgressBar(to_file=None, **kwargs):
144 """Abstract factory"""147 """Abstract factory"""
145 if to_file is None:148 if to_file is None:
@@ -163,75 +166,6 @@
163 return _progress_bar_types[requested_bar_type](to_file=to_file, **kwargs)166 return _progress_bar_types[requested_bar_type](to_file=to_file, **kwargs)
164167
165168
166class ProgressBarStack(object):
167 """A stack of progress bars.
168
169 This class is deprecated: instead, ask the ui factory for a new progress
170 task and finish it when it's done.
171 """
172
173 @deprecated_method(deprecated_in((1, 12, 0)))
174 def __init__(self,
175 to_file=None,
176 show_pct=False,
177 show_spinner=True,
178 show_eta=False,
179 show_bar=True,
180 show_count=True,
181 to_messages_file=None,
182 klass=None):
183 """Setup the stack with the parameters the progress bars should have."""
184 if to_file is None:
185 to_file = sys.stderr
186 if to_messages_file is None:
187 to_messages_file = sys.stdout
188 self._to_file = to_file
189 self._show_pct = show_pct
190 self._show_spinner = show_spinner
191 self._show_eta = show_eta
192 self._show_bar = show_bar
193 self._show_count = show_count
194 self._to_messages_file = to_messages_file
195 self._stack = []
196 self._klass = klass or ProgressBar
197
198 def top(self):
199 if len(self._stack) != 0:
200 return self._stack[-1]
201 else:
202 return None
203
204 def bottom(self):
205 if len(self._stack) != 0:
206 return self._stack[0]
207 else:
208 return None
209
210 def get_nested(self):
211 """Return a nested progress bar."""
212 if len(self._stack) == 0:
213 func = self._klass
214 else:
215 func = self.top().child_progress
216 new_bar = func(to_file=self._to_file,
217 show_pct=self._show_pct,
218 show_spinner=self._show_spinner,
219 show_eta=self._show_eta,
220 show_bar=self._show_bar,
221 show_count=self._show_count,
222 to_messages_file=self._to_messages_file,
223 _stack=self)
224 self._stack.append(new_bar)
225 return new_bar
226
227 def return_pb(self, bar):
228 """Return bar after its been used."""
229 if bar is not self._stack[-1]:
230 warnings.warn("%r is not currently active" % (bar,))
231 else:
232 self._stack.pop()
233
234
235class _BaseProgressBar(object):169class _BaseProgressBar(object):
236170
237 def __init__(self,171 def __init__(self,
@@ -278,6 +212,7 @@
278 self.to_messages_file.write(fmt_string % args)212 self.to_messages_file.write(fmt_string % args)
279 self.to_messages_file.write('\n')213 self.to_messages_file.write('\n')
280214
215 @deprecated_function(deprecated_in((1, 16, 0)))
281 def child_progress(self, **kwargs):216 def child_progress(self, **kwargs):
282 return ChildProgress(**kwargs)217 return ChildProgress(**kwargs)
283218
@@ -309,6 +244,7 @@
309244
310class DotsProgressBar(_BaseProgressBar):245class DotsProgressBar(_BaseProgressBar):
311246
247 @deprecated_function(deprecated_in((1, 16, 0)))
312 def __init__(self, **kwargs):248 def __init__(self, **kwargs):
313 _BaseProgressBar.__init__(self, **kwargs)249 _BaseProgressBar.__init__(self, **kwargs)
314 self.last_msg = None250 self.last_msg = None
@@ -335,8 +271,6 @@
335 self.tick()271 self.tick()
336272
337273
338
339
340class TTYProgressBar(_BaseProgressBar):274class TTYProgressBar(_BaseProgressBar):
341 """Progress bar display object.275 """Progress bar display object.
342276
@@ -359,7 +293,7 @@
359 """293 """
360 SPIN_CHARS = r'/-\|'294 SPIN_CHARS = r'/-\|'
361295
362296 @deprecated_function(deprecated_in((1, 16, 0)))
363 def __init__(self, **kwargs):297 def __init__(self, **kwargs):
364 from bzrlib.osutils import terminal_width298 from bzrlib.osutils import terminal_width
365 _BaseProgressBar.__init__(self, **kwargs)299 _BaseProgressBar.__init__(self, **kwargs)
@@ -519,11 +453,10 @@
519 #self.to_file.flush()453 #self.to_file.flush()
520454
521455
522
523
524class ChildProgress(_BaseProgressBar):456class ChildProgress(_BaseProgressBar):
525 """A progress indicator that pushes its data to the parent"""457 """A progress indicator that pushes its data to the parent"""
526458
459 @deprecated_function(deprecated_in((1, 16, 0)))
527 def __init__(self, _stack, **kwargs):460 def __init__(self, _stack, **kwargs):
528 _BaseProgressBar.__init__(self, _stack=_stack, **kwargs)461 _BaseProgressBar.__init__(self, _stack=_stack, **kwargs)
529 self.parent = _stack.top()462 self.parent = _stack.top()
@@ -565,23 +498,6 @@
565 self.parent.note(*args, **kwargs)498 self.parent.note(*args, **kwargs)
566499
567500
568class InstrumentedProgress(TTYProgressBar):
569 """TTYProgress variant that tracks outcomes"""
570
571 def __init__(self, *args, **kwargs):
572 self.always_throttled = True
573 self.never_throttle = False
574 TTYProgressBar.__init__(self, *args, **kwargs)
575
576 def throttle(self, old_message):
577 if self.never_throttle:
578 result = False
579 else:
580 result = TTYProgressBar.throttle(self, old_message)
581 if result is False:
582 self.always_throttled = False
583
584
585def str_tdelta(delt):501def str_tdelta(delt):
586 if delt is None:502 if delt is None:
587 return "-:--:--"503 return "-:--:--"
588504
=== modified file 'bzrlib/tests/test_progress.py'
--- bzrlib/tests/test_progress.py 2009-03-23 14:59:43 +0000
+++ bzrlib/tests/test_progress.py 2009-06-06 02:35:12 +0000
@@ -18,29 +18,12 @@
18from StringIO import StringIO18from StringIO import StringIO
1919
20from bzrlib import errors20from bzrlib import errors
21from bzrlib.progress import (
22 DummyProgress,
23 ChildProgress,
24 TTYProgressBar,
25 DotsProgressBar,
26 ProgressBarStack,
27 InstrumentedProgress,
28 )
29from bzrlib.tests import TestCase21from bzrlib.tests import TestCase
30from bzrlib.symbol_versioning import (22from bzrlib.symbol_versioning import (
31 deprecated_in,23 deprecated_in,
32 )24 )
3325
3426
35class FakeStack:
36
37 def __init__(self, top):
38 self.__top = top
39
40 def top(self):
41 return self.__top
42
43
44class _TTYStringIO(StringIO):27class _TTYStringIO(StringIO):
45 """A helper class which makes a StringIO look like a terminal"""28 """A helper class which makes a StringIO look like a terminal"""
4629
@@ -53,259 +36,3 @@
5336
54 def isatty(self):37 def isatty(self):
55 return False38 return False
56
57
58class TestProgress(TestCase):
59
60 def setUp(self):
61 TestCase.setUp(self)
62 q = DummyProgress()
63 self.top = ChildProgress(_stack=FakeStack(q))
64
65 def test_propogation(self):
66 self.top.update('foobles', 1, 2)
67 self.assertEqual(self.top.message, 'foobles')
68 self.assertEqual(self.top.current, 1)
69 self.assertEqual(self.top.total, 2)
70 self.assertEqual(self.top.child_fraction, 0)
71 child = ChildProgress(_stack=FakeStack(self.top))
72 child.update('baubles', 2, 4)
73 self.assertEqual(self.top.message, 'foobles')
74 self.assertEqual(self.top.current, 1)
75 self.assertEqual(self.top.total, 2)
76 self.assertEqual(self.top.child_fraction, 0.5)
77 grandchild = ChildProgress(_stack=FakeStack(child))
78 grandchild.update('barbells', 1, 2)
79 self.assertEqual(self.top.child_fraction, 0.625)
80 self.assertEqual(child.child_fraction, 0.5)
81 child.update('baubles', 3, 4)
82 self.assertEqual(child.child_fraction, 0)
83 self.assertEqual(self.top.child_fraction, 0.75)
84 grandchild.update('barbells', 1, 2)
85 self.assertEqual(self.top.child_fraction, 0.875)
86 grandchild.update('barbells', 2, 2)
87 self.assertEqual(self.top.child_fraction, 1)
88 child.update('baubles', 4, 4)
89 self.assertEqual(self.top.child_fraction, 1)
90 #test clamping
91 grandchild.update('barbells', 2, 2)
92 self.assertEqual(self.top.child_fraction, 1)
93
94 def test_implementations(self):
95 for implementation in (TTYProgressBar, DotsProgressBar,
96 DummyProgress):
97 self.check_parent_handling(implementation)
98
99 def check_parent_handling(self, parentclass):
100 top = parentclass(to_file=StringIO())
101 top.update('foobles', 1, 2)
102 child = ChildProgress(_stack=FakeStack(top))
103 child.update('baubles', 4, 4)
104 top.update('lala', 2, 2)
105 child.update('baubles', 4, 4)
106
107 def test_stacking(self):
108 self.check_stack(TTYProgressBar, ChildProgress)
109 self.check_stack(DotsProgressBar, ChildProgress)
110 self.check_stack(DummyProgress, DummyProgress)
111
112 def check_stack(self, parent_class, child_class):
113 stack = self.applyDeprecated(
114 deprecated_in((1, 12, 0)),
115 ProgressBarStack,
116 klass=parent_class, to_file=StringIO())
117 parent = stack.get_nested()
118 try:
119 self.assertIs(parent.__class__, parent_class)
120 child = stack.get_nested()
121 try:
122 self.assertIs(child.__class__, child_class)
123 finally:
124 child.finished()
125 finally:
126 parent.finished()
127
128 def test_throttling(self):
129 pb = InstrumentedProgress(to_file=StringIO())
130 # instantaneous updates should be squelched
131 pb.update('me', 1, 1)
132 self.assertTrue(pb.always_throttled)
133 pb = InstrumentedProgress(to_file=StringIO())
134 # It's like an instant sleep(1)!
135 pb.start_time -= 1
136 # Updates after a second should not be squelched
137 pb.update('me', 1, 1)
138 self.assertFalse(pb.always_throttled)
139
140 def test_clear(self):
141 sio = StringIO()
142 pb = TTYProgressBar(to_file=sio, show_eta=False)
143 pb.width = 20 # Just make it easier to test
144 # This should not output anything
145 pb.clear()
146 # These two should not be displayed because
147 # of throttling
148 pb.update('foo', 1, 3)
149 pb.update('bar', 2, 3)
150 # So pb.clear() has nothing to do
151 pb.clear()
152
153 # Make sure the next update isn't throttled
154 pb.start_time -= 1
155 pb.update('baz', 3, 3)
156 pb.clear()
157
158 self.assertEqual('\r[=========] baz 3/3'
159 '\r \r',
160 sio.getvalue())
161
162 def test_no_eta(self):
163 # An old version of the progress bar would
164 # store every update if show_eta was false
165 # because the eta routine was where it was
166 # cleaned out
167 pb = InstrumentedProgress(to_file=StringIO(), show_eta=False)
168 # Just make sure this first few are throttled
169 pb.start_time += 5
170
171 # These messages are throttled, and don't contribute
172 for count in xrange(100):
173 pb.update('x', count, 300)
174 self.assertEqual(0, len(pb.last_updates))
175
176 # Unthrottle by time
177 pb.start_time -= 10
178
179 # These happen too fast, so only one gets through
180 for count in xrange(100):
181 pb.update('x', count+100, 200)
182 self.assertEqual(1, len(pb.last_updates))
183
184 pb.MIN_PAUSE = 0.0
185
186 # But all of these go through, don't let the
187 # last_update list grow without bound
188 for count in xrange(100):
189 pb.update('x', count+100, 200)
190
191 self.assertEqual(pb._max_last_updates, len(pb.last_updates))
192
193
194class TestProgressTypes(TestCase):
195 """Test that the right ProgressBar gets instantiated at the right time."""
196
197 def get_nested(self, outf, term, env_progress=None):
198 """Setup so that ProgressBar thinks we are in the supplied terminal."""
199 orig_term = os.environ.get('TERM')
200 orig_progress = os.environ.get('BZR_PROGRESS_BAR')
201 os.environ['TERM'] = term
202 if env_progress is not None:
203 os.environ['BZR_PROGRESS_BAR'] = env_progress
204 elif orig_progress is not None:
205 del os.environ['BZR_PROGRESS_BAR']
206
207 def reset():
208 if orig_term is None:
209 del os.environ['TERM']
210 else:
211 os.environ['TERM'] = orig_term
212 # We may have never created BZR_PROGRESS_BAR
213 # So we can't just delete like we can 'TERM' (which is always set)
214 if orig_progress is None:
215 if 'BZR_PROGRESS_BAR' in os.environ:
216 del os.environ['BZR_PROGRESS_BAR']
217 else:
218 os.environ['BZR_PROGRESS_BAR'] = orig_progress
219
220 self.addCleanup(reset)
221
222 stack = self.applyDeprecated(
223 deprecated_in((1, 12, 0)),
224 ProgressBarStack,
225 to_file=outf)
226 pb = stack.get_nested()
227 pb.start_time -= 1 # Make sure it is ready to write
228 pb.width = 20 # And it is of reasonable size
229 return pb
230
231 def test_tty_progress(self):
232 # Make sure the ProgressBarStack thinks it is
233 # writing out to a terminal, and thus uses a TTYProgressBar
234 out = _TTYStringIO()
235 pb = self.get_nested(out, 'xterm')
236 self.assertIsInstance(pb, TTYProgressBar)
237 try:
238 pb.update('foo', 1, 2)
239 pb.update('bar', 2, 2)
240 finally:
241 pb.finished()
242
243 self.assertEqual('\r/ [==== ] foo 1/2'
244 '\r- [=======] bar 2/2'
245 '\r \r',
246 out.getvalue())
247
248 def test_noninteractive_progress(self):
249 out = _NonTTYStringIO()
250 pb = self.get_nested(out, 'xterm')
251 self.assertIsInstance(pb, DummyProgress)
252 try:
253 pb.update('foo', 1, 2)
254 pb.update('bar', 2, 2)
255 finally:
256 pb.finished()
257 self.assertEqual('', out.getvalue())
258
259 def test_dots_progress(self):
260 # make sure we get the right progress bar when not on a terminal
261 out = _NonTTYStringIO()
262 pb = self.get_nested(out, 'xterm', 'dots')
263 self.assertIsInstance(pb, DotsProgressBar)
264 try:
265 pb.update('foo', 1, 2)
266 pb.update('bar', 2, 2)
267 finally:
268 pb.finished()
269 self.assertEqual('foo: .'
270 '\nbar: .'
271 '\n',
272 out.getvalue())
273
274 def test_no_isatty_progress(self):
275 # Make sure ProgressBarStack handles a plain StringIO()
276 import cStringIO
277 out = cStringIO.StringIO()
278 pb = self.get_nested(out, 'xterm')
279 pb.finished()
280 self.assertIsInstance(pb, DummyProgress)
281
282 def test_dumb_progress(self):
283 # using a terminal that can't do cursor movement
284 out = _TTYStringIO()
285 pb = self.get_nested(out, 'dumb')
286 pb.finished()
287 self.assertIsInstance(pb, DummyProgress)
288
289 def test_progress_env_tty(self):
290 # The environ variable BZR_PROGRESS_BAR controls what type of
291 # progress bar we will get, even if it wouldn't usually be that type
292 import cStringIO
293
294 # Usually, this would be a DotsProgressBar
295 out = cStringIO.StringIO()
296 pb = self.get_nested(out, 'dumb', 'tty')
297 pb.finished()
298 # Even though we are not a tty, the env_var will override
299 self.assertIsInstance(pb, TTYProgressBar)
300
301 def test_progress_env_none(self):
302 # Even though we are in a valid tty, no progress
303 out = _TTYStringIO()
304 pb = self.get_nested(out, 'xterm', 'none')
305 pb.finished()
306 self.assertIsInstance(pb, DummyProgress)
307
308 def test_progress_env_invalid(self):
309 out = _TTYStringIO()
310 self.assertRaises(errors.InvalidProgressBarType, self.get_nested,
311 out, 'xterm', 'nonexistant')
31239
=== modified file 'bzrlib/tests/test_ui.py'
--- bzrlib/tests/test_ui.py 2009-05-15 10:14:51 +0000
+++ bzrlib/tests/test_ui.py 2009-06-06 02:35:12 +0000
@@ -25,12 +25,6 @@
2525
26import bzrlib26import bzrlib
27import bzrlib.errors as errors27import bzrlib.errors as errors
28from bzrlib.progress import (
29 DotsProgressBar,
30 ProgressBarStack,
31 ProgressTask,
32 TTYProgressBar,
33 )
34from bzrlib.symbol_versioning import (28from bzrlib.symbol_versioning import (
35 deprecated_in,29 deprecated_in,
36 )30 )
@@ -164,33 +158,6 @@
164 pb2.finished()158 pb2.finished()
165 pb1.finished()159 pb1.finished()
166160
167 def test_progress_stack(self):
168 # test the progress bar stack which the default text factory
169 # uses.
170 stderr = StringIO()
171 stdout = StringIO()
172 # make a stack, which accepts parameters like a pb.
173 stack = self.applyDeprecated(
174 deprecated_in((1, 12, 0)),
175 ProgressBarStack,
176 to_file=stderr, to_messages_file=stdout)
177 # but is not one
178 self.assertFalse(getattr(stack, 'note', False))
179 pb1 = stack.get_nested()
180 pb2 = stack.get_nested()
181 warnings, _ = self.callCatchWarnings(pb1.finished)
182 self.assertEqual(len(warnings), 1)
183 pb2.finished()
184 pb1.finished()
185 # the text ui factory never actually removes the stack once its setup.
186 # we need to be able to nest again correctly from here.
187 pb1 = stack.get_nested()
188 pb2 = stack.get_nested()
189 warnings, _ = self.callCatchWarnings(pb1.finished)
190 self.assertEqual(len(warnings), 1)
191 pb2.finished()
192 pb1.finished()
193
194 def assert_get_bool_acceptance_of_user_input(self, factory):161 def assert_get_bool_acceptance_of_user_input(self, factory):
195 factory.stdin = StringIO("y\nyes with garbage\n"162 factory.stdin = StringIO("y\nyes with garbage\n"
196 "yes\nn\nnot an answer\n"163 "yes\nn\nnot an answer\n"
197164
=== modified file 'bzrlib/weave.py'
--- bzrlib/weave.py 2009-04-08 16:33:19 +0000
+++ bzrlib/weave.py 2009-06-06 02:35:12 +0000
@@ -1,6 +1,4 @@
1#! /usr/bin/python1# Copyright (C) 2005, 2009 Canonical Ltd
2
3# Copyright (C) 2005 Canonical Ltd
4#2#
5# This program is free software; you can redistribute it and/or modify3# This program is free software; you can redistribute it and/or modify
6# it under the terms of the GNU General Public License as published by4# it under the terms of the GNU General Public License as published by
@@ -1025,6 +1023,7 @@
1025 wr._add(name, lines, [wr._lookup(i) for i in combined_parents[name]])1023 wr._add(name, lines, [wr._lookup(i) for i in combined_parents[name]])
1026 return wr1024 return wr
10271025
1026
1028def _reweave_parent_graphs(wa, wb):1027def _reweave_parent_graphs(wa, wb):
1029 """Return combined parent ancestry for two weaves.1028 """Return combined parent ancestry for two weaves.
10301029
@@ -1035,206 +1034,3 @@
1035 p = combined.setdefault(name, set())1034 p = combined.setdefault(name, set())
1036 p.update(map(weave._idx_to_name, weave._parents[idx]))1035 p.update(map(weave._idx_to_name, weave._parents[idx]))
1037 return combined1036 return combined
1038
1039
1040def weave_toc(w):
1041 """Show the weave's table-of-contents"""
1042 print '%6s %50s %10s %10s' % ('ver', 'name', 'sha1', 'parents')
1043 for i in (6, 50, 10, 10):
1044 print '-' * i,
1045 print
1046 for i in range(w.num_versions()):
1047 sha1 = w._sha1s[i]
1048 name = w._names[i]
1049 parent_str = ' '.join(map(str, w._parents[i]))
1050 print '%6d %-50.50s %10.10s %s' % (i, name, sha1, parent_str)
1051
1052
1053
1054def weave_stats(weave_file, pb):
1055 from bzrlib.weavefile import read_weave
1056
1057 wf = file(weave_file, 'rb')
1058 w = read_weave(wf)
1059 # FIXME: doesn't work on pipes
1060 weave_size = wf.tell()
1061
1062 total = 0
1063 vers = len(w)
1064 for i in range(vers):
1065 pb.update('checking sizes', i, vers)
1066 for origin, lineno, line in w._extract([i]):
1067 total += len(line)
1068
1069 pb.clear()
1070
1071 print 'versions %9d' % vers
1072 print 'weave file %9d bytes' % weave_size
1073 print 'total contents %9d bytes' % total
1074 print 'compression ratio %9.2fx' % (float(total) / float(weave_size))
1075 if vers:
1076 avg = total/vers
1077 print 'average size %9d bytes' % avg
1078 print 'relative size %9.2fx' % (float(weave_size) / float(avg))
1079
1080
1081def usage():
1082 print """bzr weave tool
1083
1084Experimental tool for weave algorithm.
1085
1086usage:
1087 weave init WEAVEFILE
1088 Create an empty weave file
1089 weave get WEAVEFILE VERSION
1090 Write out specified version.
1091 weave check WEAVEFILE
1092 Check consistency of all versions.
1093 weave toc WEAVEFILE
1094 Display table of contents.
1095 weave add WEAVEFILE NAME [BASE...] < NEWTEXT
1096 Add NEWTEXT, with specified parent versions.
1097 weave annotate WEAVEFILE VERSION
1098 Display origin of each line.
1099 weave merge WEAVEFILE VERSION1 VERSION2 > OUT
1100 Auto-merge two versions and display conflicts.
1101 weave diff WEAVEFILE VERSION1 VERSION2
1102 Show differences between two versions.
1103
1104example:
1105
1106 % weave init foo.weave
1107 % vi foo.txt
1108 % weave add foo.weave ver0 < foo.txt
1109 added version 0
1110
1111 (create updated version)
1112 % vi foo.txt
1113 % weave get foo.weave 0 | diff -u - foo.txt
1114 % weave add foo.weave ver1 0 < foo.txt
1115 added version 1
1116
1117 % weave get foo.weave 0 > foo.txt (create forked version)
1118 % vi foo.txt
1119 % weave add foo.weave ver2 0 < foo.txt
1120 added version 2
1121
1122 % weave merge foo.weave 1 2 > foo.txt (merge them)
1123 % vi foo.txt (resolve conflicts)
1124 % weave add foo.weave merged 1 2 < foo.txt (commit merged version)
1125
1126"""
1127
1128
1129
1130def main(argv):
1131 import sys
1132 import os
1133 try:
1134 import bzrlib
1135 except ImportError:
1136 # in case we're run directly from the subdirectory
1137 sys.path.append('..')
1138 import bzrlib
1139 from bzrlib.weavefile import write_weave, read_weave
1140 from bzrlib.progress import ProgressBar
1141
1142 try:
1143 import psyco
1144 psyco.full()
1145 except ImportError:
1146 pass
1147
1148 if len(argv) < 2:
1149 usage()
1150 return 0
1151
1152 cmd = argv[1]
1153
1154 def readit():
1155 return read_weave(file(argv[2], 'rb'))
1156
1157 if cmd == 'help':
1158 usage()
1159 elif cmd == 'add':
1160 w = readit()
1161 # at the moment, based on everything in the file
1162 name = argv[3]
1163 parents = map(int, argv[4:])
1164 lines = sys.stdin.readlines()
1165 ver = w.add(name, parents, lines)
1166 write_weave(w, file(argv[2], 'wb'))
1167 print 'added version %r %d' % (name, ver)
1168 elif cmd == 'init':
1169 fn = argv[2]
1170 if os.path.exists(fn):
1171 raise IOError("file exists")
1172 w = Weave()
1173 write_weave(w, file(fn, 'wb'))
1174 elif cmd == 'get': # get one version
1175 w = readit()
1176 sys.stdout.writelines(w.get_iter(int(argv[3])))
1177
1178 elif cmd == 'diff':
1179 w = readit()
1180 fn = argv[2]
1181 v1, v2 = map(int, argv[3:5])
1182 lines1 = w.get(v1)
1183 lines2 = w.get(v2)
1184 diff_gen = bzrlib.patiencediff.unified_diff(lines1, lines2,
1185 '%s version %d' % (fn, v1),
1186 '%s version %d' % (fn, v2))
1187 sys.stdout.writelines(diff_gen)
1188
1189 elif cmd == 'annotate':
1190 w = readit()
1191 # newline is added to all lines regardless; too hard to get
1192 # reasonable formatting otherwise
1193 lasto = None
1194 for origin, text in w.annotate(int(argv[3])):
1195 text = text.rstrip('\r\n')
1196 if origin == lasto:
1197 print ' | %s' % (text)
1198 else:
1199 print '%5d | %s' % (origin, text)
1200 lasto = origin
1201
1202 elif cmd == 'toc':
1203 weave_toc(readit())
1204
1205 elif cmd == 'stats':
1206 weave_stats(argv[2], ProgressBar())
1207
1208 elif cmd == 'check':
1209 w = readit()
1210 pb = ProgressBar()
1211 w.check(pb)
1212 pb.clear()
1213 print '%d versions ok' % w.num_versions()
1214
1215 elif cmd == 'inclusions':
1216 w = readit()
1217 print ' '.join(map(str, w.inclusions([int(argv[3])])))
1218
1219 elif cmd == 'parents':
1220 w = readit()
1221 print ' '.join(map(str, w._parents[int(argv[3])]))
1222
1223 elif cmd == 'plan-merge':
1224 # replaced by 'bzr weave-plan-merge'
1225 w = readit()
1226 for state, line in w.plan_merge(int(argv[3]), int(argv[4])):
1227 if line:
1228 print '%14s | %s' % (state, line),
1229 elif cmd == 'merge':
1230 # replaced by 'bzr weave-merge-text'
1231 w = readit()
1232 p = w.plan_merge(int(argv[3]), int(argv[4]))
1233 sys.stdout.writelines(w.weave_merge(p))
1234 else:
1235 raise ValueError('unknown command %r' % cmd)
1236
1237
1238if __name__ == '__main__':
1239 import sys
1240 sys.exit(main(sys.argv))