Rev 4934: (jam) Add -Dbytes and log how many bytes are transferred for in file:///home/pqm/archives/thelove/bzr/%2Btrunk/

Canonical.com Patch Queue Manager pqm at pqm.ubuntu.com
Tue Jan 5 16:55:14 GMT 2010


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

------------------------------------------------------------
revno: 4934 [merge]
revision-id: pqm at pqm.ubuntu.com-20100105165512-ip2jyuy8f999raxm
parent: pqm at pqm.ubuntu.com-20100105045349-91sjr8vmex9iy8ex
parent: john at arbash-meinel.com-20100105155228-jm4mtt4gobh089xl
committer: Canonical.com Patch Queue Manager <pqm at pqm.ubuntu.com>
branch nick: +trunk
timestamp: Tue 2010-01-05 16:55:12 +0000
message:
  (jam) Add -Dbytes and log how many bytes are transferred for
  	operations.
modified:
  NEWS                           NEWS-20050323055033-4e00b5db738777ff
  bzrlib/commands.py             bzr.py-20050309040720-d10f4714595cf8c3
  bzrlib/help_topics/en/debug-flags.txt debugflags.txt-20090312050229-rdspqbqq4fzbjtpe-1
  bzrlib/tests/per_uifactory/__init__.py __init__.py-20090923045301-o12zypjwsidxn2hy-1
  bzrlib/ui/__init__.py          ui.py-20050824083933-8cf663c763ba53a9
  bzrlib/ui/text.py              text.py-20051130153916-2e438cffc8afc478
=== modified file 'NEWS'
--- a/NEWS	2010-01-05 04:08:35 +0000
+++ b/NEWS	2010-01-05 16:55:12 +0000
@@ -17,16 +17,21 @@
 New Features
 ************
 
+* ``bzr update`` now takes a ``--revision`` argument. This lets you
+  change the revision of the working tree to any revision in the
+  ancestry of the current or master branch. (Matthieu Moy, Mark Hammond,
+  Martin Pool, #45719)
+
+* ``-Dbytes`` can now be used to display the total number of bytes
+  transferred for the current command. This information is always logged
+  to ``.bzr.log`` for later inspection. (John Arbash Meinel)
+
 * The ``suppress_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)
 
-* ``bzr update`` now takes a ``--revision`` argument. This lets you
-  change the revision of the working tree to any revision in the
-  ancestry of the current or master branch. (Matthieu Moy, Mark Hammond,
-  Martin Pool, #45719)
 
 Bug Fixes
 *********

=== modified file 'bzrlib/commands.py'
--- a/bzrlib/commands.py	2009-12-09 05:47:32 +0000
+++ b/bzrlib/commands.py	2009-12-18 17:59:58 +0000
@@ -1103,6 +1103,8 @@
             raise errors.BzrError("argv should be list of unicode strings.")
         argv = new_argv
     ret = run_bzr_catch_errors(argv)
+    bzrlib.ui.ui_factory.log_transport_activity(
+        display=('bytes' in debug.debug_flags))
     trace.mutter("return code %d", ret)
     osutils.report_extension_load_failures()
     return ret

=== modified file 'bzrlib/help_topics/en/debug-flags.txt'
--- a/bzrlib/help_topics/en/debug-flags.txt	2009-12-22 04:07:36 +0000
+++ b/bzrlib/help_topics/en/debug-flags.txt	2010-01-05 04:30:07 +0000
@@ -5,6 +5,7 @@
 prefix) put in the ``debug_flags`` variable in ``bazaar.conf``.
 
 -Dauth            Trace authentication sections used.
+-Dbytes           Print out how many bytes were transferred
 -Ddirstate        Trace dirstate activity (verbose!)
 -Derror           Instead of normal error handling, always print a traceback
                   on error.

=== modified file 'bzrlib/tests/per_uifactory/__init__.py'
--- a/bzrlib/tests/per_uifactory/__init__.py	2009-11-16 01:18:03 +0000
+++ b/bzrlib/tests/per_uifactory/__init__.py	2010-01-05 15:52:28 +0000
@@ -39,6 +39,7 @@
 
 from bzrlib import (
     tests,
+    transport,
     ui,
     )
 
@@ -83,6 +84,24 @@
             raise tests.TestSkipped(str(e))
         output_stream.write('hello!')
 
+    def test_transport_activity(self):
+        # It doesn't matter what the implementation does, we just want to make
+        # sure the interface is there
+        t = transport.get_transport('memory:///')
+        self.factory.report_transport_activity(t, 1000, 'write')
+        self.factory.report_transport_activity(t, 2000, 'read')
+        self.factory.report_transport_activity(t, 4000, None)
+        self.factory.log_transport_activity()
+        self._check_log_transport_activity_noarg()
+        self.factory.log_transport_activity(display=True)
+        self._check_log_transport_activity_display()
+
+    def test_no_transport_activity(self):
+        # No activity to report
+        t = transport.get_transport('memory:///')
+        self.factory.log_transport_activity(display=True)
+        self._check_log_transport_activity_display_no_bytes()
+
 
 class TestTextUIFactory(tests.TestCase, UIFactoryTestMixin):
 
@@ -113,6 +132,62 @@
             self.stderr.getvalue())
         self.assertEquals("", self.stdout.getvalue())
 
+    def _check_log_transport_activity_noarg(self):
+        self.assertEqual('', self.stdout.getvalue())
+        self.assertContainsRe(self.stderr.getvalue(), r'\d+KB\s+\dKB/s |')
+        self.assertNotContainsRe(self.stderr.getvalue(), r'Transferred:')
+
+    def _check_log_transport_activity_display(self):
+        self.assertEqual('', self.stdout.getvalue())
+        # Without a TTY, we shouldn't display anything
+        self.assertEqual('', self.stderr.getvalue())
+
+    def _check_log_transport_activity_display_no_bytes(self):
+        self.assertEqual('', self.stdout.getvalue())
+        # Without a TTY, we shouldn't display anything
+        self.assertEqual('', self.stderr.getvalue())
+
+
+class TestTTYTextUIFactory(TestTextUIFactory):
+
+    def setUp(self):
+        super(TestTTYTextUIFactory, self).setUp()
+
+        class TTYStringIO(object):
+            """Thunk over to StringIO() for everything but 'isatty'"""
+
+            def __init__(self):
+                self.__dict__['_sio'] = StringIO()
+
+            def isatty(self):
+                return True
+
+            def __getattr__(self, name):
+                return getattr(self._sio, name)
+
+            def __setattr__(self, name, value):
+                return setattr(self._sio, name, value)
+                
+        # Remove 'TERM' == 'dumb' which causes us to *not* treat output as a
+        # real terminal, even though isatty returns True
+        self._captureVar('TERM', None)
+        self.stderr = TTYStringIO()
+        self.stdout = TTYStringIO()
+        self.factory = ui.text.TextUIFactory(self.stdin, self.stdout,
+            self.stderr)
+
+    def _check_log_transport_activity_display(self):
+        self.assertEqual('', self.stdout.getvalue())
+        # Displaying the result should write to the progress stream
+        self.assertContainsRe(self.stderr.getvalue(),
+            r'Transferred: 7KiB'
+            r' \(\d+\.\dK/s r:2K w:1K u:4K\)')
+
+    def _check_log_transport_activity_display_no_bytes(self):
+        self.assertEqual('', self.stdout.getvalue())
+        # Without actual bytes transferred, we should report nothing
+        self.assertEqual('', self.stderr.getvalue())
+
 
 class TestSilentUIFactory(tests.TestCase, UIFactoryTestMixin):
     # discards output, therefore tests for output expect nothing
@@ -134,6 +209,15 @@
     def _check_show_warning(self, msg):
         pass
 
+    def _check_log_transport_activity_noarg(self):
+        pass
+
+    def _check_log_transport_activity_display(self):
+        pass
+
+    def _check_log_transport_activity_display_no_bytes(self):
+        pass
+
 
 class TestCannedInputUIFactory(tests.TestCase, UIFactoryTestMixin):
     # discards output, reads input from variables
@@ -154,4 +238,11 @@
     def _check_show_warning(self, msg):
         pass
 
-
+    def _check_log_transport_activity_noarg(self):
+        pass
+
+    def _check_log_transport_activity_display(self):
+        pass
+
+    def _check_log_transport_activity_display_no_bytes(self):
+        pass

=== modified file 'bzrlib/ui/__init__.py'
--- a/bzrlib/ui/__init__.py	2009-12-10 16:54:28 +0000
+++ b/bzrlib/ui/__init__.py	2009-12-18 16:39:21 +0000
@@ -246,6 +246,19 @@
         """
         pass
 
+    def log_transport_activity(self, display=False):
+        """Write out whatever transport activity has been measured.
+
+        Implementations are allowed to do nothing, but it is useful if they can
+        write a line to the log file.
+
+        :param display: If False, only log to disk, if True also try to display
+            a message to the user.
+        :return: None
+        """
+        # Default implementation just does nothing
+        pass
+
     def show_error(self, msg):
         """Show an error message (not an exception) to the user.
         
@@ -345,3 +358,6 @@
 
     def show_transport_activity(self, transport, direction, byte_count):
         pass
+
+    def log_transport_activity(self, display=False):
+        pass

=== modified file 'bzrlib/ui/text.py'
--- a/bzrlib/ui/text.py	2009-12-22 04:07:36 +0000
+++ b/bzrlib/ui/text.py	2010-01-05 04:30:07 +0000
@@ -32,6 +32,7 @@
     progress,
     osutils,
     symbol_versioning,
+    trace,
     )
 
 """)
@@ -203,6 +204,12 @@
         self._progress_view.show_transport_activity(transport,
             direction, byte_count)
 
+    def log_transport_activity(self, display=False):
+        """See UIFactory.log_transport_activity()"""
+        log = getattr(self._progress_view, 'log_transport_activity', None)
+        if log is not None:
+            log(display=display)
+
     def show_error(self, msg):
         self.clear_term()
         self.stderr.write("bzr: error: %s\n" % msg)
@@ -257,6 +264,8 @@
         self._last_task = None
         self._total_byte_count = 0
         self._bytes_since_update = 0
+        self._bytes_by_direction = {'unknown': 0, 'read': 0, 'write': 0}
+        self._first_byte_time = None
         self._fraction = 0
         # force the progress bar to be off, as at the moment it doesn't 
         # correspond reliably to overall command progress
@@ -369,17 +378,25 @@
         This may update a progress bar, spinner, or similar display.
         By default it does nothing.
         """
-        # XXX: Probably there should be a transport activity model, and that
-        # too should be seen by the progress view, rather than being poked in
-        # here.
+        # XXX: there should be a transport activity model, and that too should
+        #      be seen by the progress view, rather than being poked in here.
+        self._total_byte_count += byte_count
+        self._bytes_since_update += byte_count
+        if self._first_byte_time is None:
+            # Note that this isn't great, as technically it should be the time
+            # when the bytes started transferring, not when they completed.
+            # However, we usually start with a small request anyway.
+            self._first_byte_time = time.time()
+        if direction in self._bytes_by_direction:
+            self._bytes_by_direction[direction] += byte_count
+        else:
+            self._bytes_by_direction['unknown'] += byte_count
         if 'no_activity' in debug.debug_flags:
             # Can be used as a workaround if
             # <https://launchpad.net/bugs/321935> reappears and transport
             # activity is cluttering other output.  However, thanks to
             # TextUIOutputStream this shouldn't be a problem any more.
             return
-        self._total_byte_count += byte_count
-        self._bytes_since_update += byte_count
         now = time.time()
         if self._total_byte_count < 2000:
             # a little resistance at first, so it doesn't stay stuck at 0
@@ -399,6 +416,37 @@
             self._last_transport_msg = msg
             self._repaint()
 
+    def _format_bytes_by_direction(self):
+        if self._first_byte_time is None:
+            bps = 0.0
+        else:
+            transfer_time = time.time() - self._first_byte_time
+            if transfer_time < 0.001:
+                transfer_time = 0.001
+            bps = self._total_byte_count / transfer_time
+
+        msg = ('Transferred: %.0fKiB'
+               ' (%.1fK/s r:%.0fK w:%.0fK'
+               % (self._total_byte_count / 1024.,
+                  bps / 1024.,
+                  self._bytes_by_direction['read'] / 1024.,
+                  self._bytes_by_direction['write'] / 1024.,
+                 ))
+        if self._bytes_by_direction['unknown'] > 0:
+            msg += ' u:%.0fK)' % (
+                self._bytes_by_direction['unknown'] / 1024.
+                )
+        else:
+            msg += ')'
+        return msg
+
+    def log_transport_activity(self, display=False):
+        msg = self._format_bytes_by_direction()
+        trace.mutter(msg)
+        if display and self._total_byte_count > 0:
+            self.clear()
+            self._term_file.write(msg + '\n')
+
 
 class TextUIOutputStream(object):
     """Decorates an output stream so that the terminal is cleared before writing.




More information about the bazaar-commits mailing list