Rev 4882: Fix minor issues and make test passing on windows for terminal_width() in http://bazaar.launchpad.net/~vila/bzr/integration

Vincent Ladeuil v.ladeuil+lp at free.fr
Wed Dec 9 17:22:10 GMT 2009


At http://bazaar.launchpad.net/~vila/bzr/integration

------------------------------------------------------------
revno: 4882 [merge]
revision-id: v.ladeuil+lp at free.fr-20091209172154-cefhveeazvlbpy4r
parent: pqm at pqm.ubuntu.com-20091209083802-i7thqoq5irt2r4ya
parent: v.ladeuil+lp at free.fr-20091209150900-pbytmi9fh4fa3vbf
committer: Vincent Ladeuil <v.ladeuil+lp at free.fr>
branch nick: integration
timestamp: Wed 2009-12-09 18:21:54 +0100
message:
  Fix minor issues and make test passing on windows for terminal_width()
modified:
  NEWS                           NEWS-20050323055033-4e00b5db738777ff
  bzrlib/osutils.py              osutils.py-20050309040759-eeaff12fbf77ac86
  bzrlib/tests/test_osutils.py   test_osutils.py-20051201224856-e48ee24c12182989
-------------- next part --------------
=== modified file 'NEWS'
--- a/NEWS	2009-12-09 05:47:32 +0000
+++ b/NEWS	2009-12-09 17:21:54 +0000
@@ -64,11 +64,13 @@
 * Lots of bugfixes for the test suite on Windows. We should once again
   have a test suite with no failures on Windows. (John Arbash Meinel)
 
-* ``osutils.terminal_width()`` obeys the BZR_COLUMNS envrionment
+* ``osutils.terminal_width()`` obeys the BZR_COLUMNS environment
   variable but returns None if the terminal is not a tty (when output is
   redirected for example). Also fixes its usage under OSes that doesn't
-  provide termios.TIOCGWINSZ.  
+  provide termios.TIOCGWINSZ. Make sure the corresponding tests runs on
+  windows too.
   (Joke de Buhr, Vincent Ladeuil, #353370, #62539)
+  (John Arbash Meinel, Vincent Ladeuil, #492561)
 
 * Terminate ssh subprocesses when no references to them remain, fixing
   subprocess and file descriptor leaks.  (Andrew Bennetts, #426662)

=== modified file 'bzrlib/osutils.py'
--- a/bzrlib/osutils.py	2009-12-04 10:09:11 +0000
+++ b/bzrlib/osutils.py	2009-12-09 14:18:48 +0000
@@ -1342,6 +1342,23 @@
     """Return terminal width.
 
     None is returned if the width can't established precisely.
+
+    The rules are:
+    - if BZR_COLUMNS is set, returns its value
+    - if there is no controlling terminal, returns None
+    - if COLUMNS is set, returns its value,
+
+    From there, we need to query the OS to get the size of the controlling
+    terminal.
+
+    Unices:
+    - get termios.TIOCGWINSZ
+    - if an error occurs or a negative value is obtained, returns None
+
+    Windows:
+    
+    - win32utils.get_console_size() decides,
+    - returns None on error (provided default value)
     """
 
     # If BZR_COLUMNS is set, take it, user is always right
@@ -1355,26 +1372,50 @@
         # Don't guess, setting BZR_COLUMNS is the recommended way to override.
         return None
 
-    if sys.platform == 'win32':
-        return win32utils.get_console_size(defaultx=None)[0]
-
+    # If COLUMNS is set, take it, the terminal knows better (even inside a
+    # given terminal, the application can decide to set COLUMNS to a lower
+    # value (splitted screen) or a bigger value (scroll bars))
+    try:
+        return int(os.environ['COLUMNS'])
+    except (KeyError, ValueError):
+        pass
+
+    width, height = _terminal_size(None, None)
+    if width <= 0:
+        # Consider invalid values as meaning no width
+        return None
+
+    return width
+
+
+def _win32_terminal_size(width, height):
+    width, height = win32utils.get_console_size(defaultx=width, defaulty=height)
+    return width, height
+
+
+def _ioctl_terminal_size(width, height):
     try:
         import struct, fcntl, termios
         s = struct.pack('HHHH', 0, 0, 0, 0)
         x = fcntl.ioctl(1, termios.TIOCGWINSZ, s)
-        width = struct.unpack('HHHH', x)[1]
+        height, width = struct.unpack('HHHH', x)[0:2]
     except (IOError, AttributeError):
-        # If COLUMNS is set, take it
-        try:
-            return int(os.environ['COLUMNS'])
-        except (KeyError, ValueError):
-            return None
-
-    if width <= 0:
-        # Consider invalid values as meaning no width
-        return None
-
-    return width
+        pass
+    return width, height
+
+_terminal_size = None
+"""Returns the terminal size as (width, height).
+
+:param width: Default value for width.
+:param height: Default value for height.
+
+This is defined specifically for each OS and query the size of the controlling
+terminal. If any error occurs, the provided default values should be returned.
+"""
+if sys.platform == 'win32':
+    _terminal_size = _win32_terminal_size
+else:
+    _terminal_size = _ioctl_terminal_size
 
 
 def supports_executable():

=== modified file 'bzrlib/tests/test_osutils.py'
--- a/bzrlib/tests/test_osutils.py	2009-12-08 21:46:07 +0000
+++ b/bzrlib/tests/test_osutils.py	2009-12-09 15:09:00 +0000
@@ -1928,39 +1928,63 @@
 
 class TestTerminalWidth(tests.TestCase):
 
+    def replace_stdout(self, new):
+        orig_stdout = sys.stdout
+        def restore():
+            sys.stdout = orig_stdout
+        self.addCleanup(restore)
+        sys.stdout = new
+
+    def replace__terminal_size(self, new):
+        orig__terminal_size = osutils._terminal_size
+        def restore():
+            osutils._terminal_size = orig__terminal_size
+        self.addCleanup(restore)
+        osutils._terminal_size = new
+
+    def set_fake_tty(self):
+
+        class I_am_a_tty(object):
+            def isatty(self):
+                return True
+
+        self.replace_stdout(I_am_a_tty())
+
     def test_default_values(self):
-        self.assertEquals(80, osutils.default_terminal_width)
+        self.assertEqual(80, osutils.default_terminal_width)
 
     def test_defaults_to_BZR_COLUMNS(self):
         # BZR_COLUMNS is set by the test framework
-        self.assertEquals('80', os.environ['BZR_COLUMNS'])
+        self.assertNotEqual('12', os.environ['BZR_COLUMNS'])
         os.environ['BZR_COLUMNS'] = '12'
-        self.assertEquals(12, osutils.terminal_width())
+        self.assertEqual(12, osutils.terminal_width())
+
+    def test_falls_back_to_COLUMNS(self):
+        del os.environ['BZR_COLUMNS']
+        self.assertNotEqual('42', os.environ['COLUMNS'])
+        self.set_fake_tty()
+        os.environ['COLUMNS'] = '42'
+        self.assertEqual(42, osutils.terminal_width())
 
     def test_tty_default_without_columns(self):
         del os.environ['BZR_COLUMNS']
         del os.environ['COLUMNS']
-        orig_stdout = sys.stdout
-        def restore():
-            sys.stdout = orig_stdout
-        self.addCleanup(restore)
-
-        class I_am_a_tty(object):
-            def isatty(self):
-                return True
-
-        sys.stdout = I_am_a_tty()
-        self.assertEquals(None, osutils.terminal_width())
+
+        def terminal_size(w, h):
+            return 42, 42
+
+        self.set_fake_tty()
+        # We need to override the osutils definition as it depends on the
+        # running environment that we can't control (PQM running without a
+        # controlling terminal is one example).
+        self.replace__terminal_size(terminal_size)
+        self.assertEqual(42, osutils.terminal_width())
 
     def test_non_tty_default_without_columns(self):
         del os.environ['BZR_COLUMNS']
         del os.environ['COLUMNS']
-        orig_stdout = sys.stdout
-        def restore():
-            sys.stdout = orig_stdout
-        self.addCleanup(restore)
-        sys.stdout = None
-        self.assertEquals(None, osutils.terminal_width())
+        self.replace_stdout(None)
+        self.assertEqual(None, osutils.terminal_width())
 
     def test_no_TIOCGWINSZ(self):
         self.requireFeature(TermIOSFeature)
@@ -1978,4 +2002,5 @@
             del termios.TIOCGWINSZ
         del os.environ['BZR_COLUMNS']
         del os.environ['COLUMNS']
-        self.assertIs(None, osutils.terminal_width())
+        # Whatever the result is, if we don't raise an exception, it's ok.
+        osutils.terminal_width()



More information about the bazaar-commits mailing list