Rev 4753: terminal_width can now returns None. in file:///home/vila/src/bzr/bugs/353370-notty-no-term-width/

Vincent Ladeuil v.ladeuil+lp at free.fr
Wed Dec 2 15:24:34 GMT 2009


At file:///home/vila/src/bzr/bugs/353370-notty-no-term-width/

------------------------------------------------------------
revno: 4753
revision-id: v.ladeuil+lp at free.fr-20091202152434-mvopr2s1p1j8nm93
parent: v.ladeuil+lp at free.fr-20091023125716-93f2al97p0e2kayj
committer: Vincent Ladeuil <v.ladeuil+lp at free.fr>
branch nick: 353370-notty-no-term-width
timestamp: Wed 2009-12-02 16:24:34 +0100
message:
  terminal_width can now returns None.
  
  * bzrlib/win32utils.py:
  (get_console_size): Fix typo in comment.
  
  * bzrlib/ui/text.py:
  (TextProgressView._show_line): Handle the no terminal present case.
  
  * bzrlib/tests/test_osutils.py:
  (TestTerminalWidth): Update tests.
  
  * bzrlib/tests/blackbox/test_too_much.py:
  Fix some imports.
  (OldTests.test_bzr): Handle the no terminal present case.
  
  * bzrlib/tests/__init__.py:
  (VerboseTestResult.report_test_start): Handle the no terminal
  present case.
  
  * bzrlib/status.py:
  (show_pending_merges): Handle the no terminal present case.
  (show_pending_merges.show_log_message): Factor out some
  code. Handle the no terminal present case.
  
  * bzrlib/osutils.py:
  (terminal_width): Return None if no precise value can be found.
  
  * bzrlib/log.py:
  (LineLogFormatter.__init__): Handle the no terminal present case.
  (LineLogFormatter.truncate): Accept None as max_len meaning no
  truncation.
  (LineLogFormatter.log_string): 
  
  * bzrlib/help.py:
  (_help_commands_to_text): Handle the no terminal present case.
-------------- next part --------------
=== modified file 'NEWS'
--- a/NEWS	2009-10-23 10:41:15 +0000
+++ b/NEWS	2009-12-02 15:24:34 +0000
@@ -22,12 +22,11 @@
 Bug Fixes
 *********
 
-* ``osutils.terminal_width()`` obeys the COLUMNS envrionment
-  variable and then default to a reasonable value 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.
-  (Joke de Buhr, Vincent Ladeuil, #353370, #62539)
+* ``osutils.terminal_width()`` obeys the COLUMNS envrionment 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.
+ (Joke de Buhr, Vincent Ladeuil, #353370, #62539)
 
 Improvements
 ************

=== modified file 'bzrlib/help.py'
--- a/bzrlib/help.py	2009-06-19 09:06:56 +0000
+++ b/bzrlib/help.py	2009-12-02 15:24:34 +0000
@@ -78,7 +78,11 @@
     shown_commands = [(n, o) for n, o in commands if o.hidden == hidden]
     max_name = max(len(n) for n, o in shown_commands)
     indent = ' ' * (max_name + 1)
-    width = osutils.terminal_width() - 1
+    width = osutils.terminal_width()
+    if width is None:
+        width = osutils.default_terminal_width
+    # we need one extra space for terminals that wrap on last char
+    width = width - 1
 
     for cmd_name, cmd_object in sorted(shown_commands):
         plugin_name = cmd_object.plugin_name()

=== modified file 'bzrlib/log.py'
--- a/bzrlib/log.py	2009-06-10 03:56:49 +0000
+++ b/bzrlib/log.py	2009-12-02 15:24:34 +0000
@@ -1543,12 +1543,16 @@
 
     def __init__(self, *args, **kwargs):
         super(LineLogFormatter, self).__init__(*args, **kwargs)
-        self._max_chars = terminal_width() - 1
+        width = terminal_width()
+        if width is not None:
+            # we need one extra space for terminals that wrap on last char
+            width = width - 1
+        self._max_chars = width
 
     def truncate(self, str, max_len):
-        if len(str) <= max_len:
+        if max_len is None or len(str) <= max_len:
             return str
-        return str[:max_len-3]+'...'
+        return str[:max_len-3] + '...'
 
     def date_string(self, rev):
         return format_date(rev.timestamp, rev.timezone or 0,

=== modified file 'bzrlib/osutils.py'
--- a/bzrlib/osutils.py	2009-10-23 10:41:15 +0000
+++ b/bzrlib/osutils.py	2009-12-02 15:24:34 +0000
@@ -1294,12 +1294,19 @@
     normalized_filename = _inaccessible_normalized_filename
 
 
-default_tty_width = 80
-"""The default terminal width for ttys."""
-default_non_tty_width = 256
-"""The default terminal width for non-ttys."""
+default_terminal_width = 80
+"""The default terminal width for ttys.
+
+This is defined so that higher levels can share a common fallback value when
+terminal_width() returns None.
+"""
+
+
 def terminal_width():
-    """Return estimated terminal width."""
+    """Return terminal width.
+
+    None is returned if the width can't established precisely.
+    """
 
     # If the env var is set, take it, user is always right
     try:
@@ -1309,18 +1316,11 @@
 
     isatty = getattr(sys.stdout, 'isatty', None)
     if  isatty is None or not isatty():
-        # If it's not a tty, there is no way to acquire a value
-        # automatically. Yet, bzrlib expect a reasonable value here since it's
-        # used for both truncating lines or filling them. As such we need to
-        # use a reasonable default.  When the output is redirected, the pagers
-        # can then handle that themselves (or set COLUMNS if needed). A cleaner
-        # implementation would be to fix the callers to not try to format at
-        # all in these circumstances, but not formmatting when filling lines
-        # does not always make sense.
-        return default_non_tty_width
+        # Don't guess, setting COLUMNS is the recommended way to override.
+        return None
 
     if sys.platform == 'win32':
-        return win32utils.get_console_size(default_tty_width)[0]
+        return win32utils.get_console_size(defaultx=None)[0]
 
     try:
         import struct, fcntl, termios
@@ -1328,10 +1328,10 @@
         x = fcntl.ioctl(1, termios.TIOCGWINSZ, s)
         width = struct.unpack('HHHH', x)[1]
     except (IOError, AttributeError):
-        width = -1
+        return None
 
     if width <= 0:
-        width = default_tty_width
+        return None
 
     return width
 

=== modified file 'bzrlib/status.py'
--- a/bzrlib/status.py	2009-08-06 05:07:12 +0000
+++ b/bzrlib/status.py	2009-12-02 15:24:34 +0000
@@ -197,8 +197,10 @@
     if len(parents) < 2:
         return
 
-    # we need one extra space for terminals that wrap on last char
-    term_width = osutils.terminal_width() - 1
+    term_width = osutils.terminal_width()
+    if term_width is not None:
+        # we need one extra space for terminals that wrap on last char
+        term_width = term_width - 1
     if short:
         first_prefix = 'P   '
         sub_prefix = 'P.   '
@@ -206,6 +208,14 @@
         first_prefix = '  '
         sub_prefix = '    '
 
+    def show_log_message(rev, prefix):
+        if term_width is None:
+            width = term_width
+        else:
+            width = term_width - len(prefix)
+        log_message = log_formatter.log_string(None, rev, width, prefix=prefix)
+        to_file.write(log_message + '\n')
+
     pending = parents[1:]
     branch = new.branch
     last_revision = parents[0]
@@ -213,7 +223,8 @@
         if verbose:
             to_file.write('pending merges:\n')
         else:
-            to_file.write('pending merge tips: (use -v to see all merge revisions)\n')
+            to_file.write('pending merge tips:'
+                          ' (use -v to see all merge revisions)\n')
     graph = branch.repository.get_graph()
     other_revisions = [last_revision]
     log_formatter = log.LineLogFormatter(to_file)
@@ -227,9 +238,7 @@
             continue
 
         # Log the merge, as it gets a slightly different formatting
-        log_message = log_formatter.log_string(None, rev,
-                        term_width - len(first_prefix))
-        to_file.write(first_prefix + log_message + '\n')
+        show_log_message(rev, first_prefix)
         if not verbose:
             continue
 
@@ -267,10 +276,7 @@
             if rev is None:
                 to_file.write(sub_prefix + '(ghost) ' + sub_merge + '\n')
                 continue
-            log_message = log_formatter.log_string(None,
-                            revisions[sub_merge],
-                            term_width - len(sub_prefix))
-            to_file.write(sub_prefix + log_message + '\n')
+            show_log_message(revisions[sub_merge], sub_prefix)
 
 
 def _filter_nonexistent(orig_paths, old_tree, new_tree):

=== modified file 'bzrlib/tests/__init__.py'
--- a/bzrlib/tests/__init__.py	2009-10-14 08:51:44 +0000
+++ b/bzrlib/tests/__init__.py	2009-12-02 15:24:34 +0000
@@ -562,11 +562,15 @@
     def report_test_start(self, test):
         self.count += 1
         name = self._shortened_test_description(test)
-        # width needs space for 6 char status, plus 1 for slash, plus an
-        # 11-char time string, plus a trailing blank
-        # when NUMBERED_DIRS: plus 5 chars on test number, plus 1 char on space
-        self.stream.write(self._ellipsize_to_right(name,
-                          osutils.terminal_width()-18))
+        width = osutils.terminal_width()
+        if width is not None:
+            # width needs space for 6 char status, plus 1 for slash, plus an
+            # 11-char time string, plus a trailing blank
+            # when NUMBERED_DIRS: plus 5 chars on test number, plus 1 char on
+            # space
+            self.stream.write(self._ellipsize_to_right(name, width-18))
+        else:
+            self.stream.write(name)
         self.stream.flush()
 
     def _error_summary(self, err):

=== modified file 'bzrlib/tests/blackbox/test_too_much.py'
--- a/bzrlib/tests/blackbox/test_too_much.py	2009-09-17 11:54:41 +0000
+++ b/bzrlib/tests/blackbox/test_too_much.py	2009-12-02 15:24:34 +0000
@@ -44,11 +44,6 @@
     )
 from bzrlib.branch import Branch
 from bzrlib.errors import BzrCommandError
-from bzrlib.osutils import (
-    has_symlinks,
-    pathjoin,
-    terminal_width,
-    )
 from bzrlib.tests.http_utils import TestCaseWithWebserver
 from bzrlib.tests.test_sftp_transport import TestCaseWithSFTPServer
 from bzrlib.tests.blackbox import ExternalBase
@@ -87,7 +82,7 @@
         os.rmdir('revertdir')
         self.run_bzr('revert')
 
-        if has_symlinks():
+        if osutils.has_symlinks():
             os.symlink('/unlikely/to/exist', 'symlink')
             self.run_bzr('add symlink')
             self.run_bzr('commit -m f')
@@ -374,7 +369,7 @@
         self.run_bzr('init')
 
         self.assertIsSameRealPath(self.run_bzr('root')[0].rstrip(),
-                                  pathjoin(self.test_dir, 'branch1'))
+                                  osutils.pathjoin(self.test_dir, 'branch1'))
 
         progress("status of new file")
 
@@ -443,9 +438,10 @@
 
         log_out = self.run_bzr('log --line')[0]
         # determine the widest line we want
-        max_width = terminal_width() - 1
-        for line in log_out.splitlines():
-            self.assert_(len(line) <= max_width, len(line))
+        max_width = osutils.terminal_width()
+        if max_width is not None:
+            for line in log_out.splitlines():
+                self.assert_(len(line) <= max_width - 1, len(line))
         self.assert_("this is my new commit and" not in log_out)
         self.assert_("this is my new commit" in log_out)
 
@@ -462,7 +458,7 @@
 
         self.run_bzr('info')
 
-        if has_symlinks():
+        if osutils.has_symlinks():
             progress("symlinks")
             mkdir('symlinks')
             chdir('symlinks')

=== modified file 'bzrlib/tests/test_osutils.py'
--- a/bzrlib/tests/test_osutils.py	2009-10-23 12:57:16 +0000
+++ b/bzrlib/tests/test_osutils.py	2009-12-02 15:24:34 +0000
@@ -1886,8 +1886,7 @@
 class TestTerminalWidth(tests.TestCase):
 
     def test_default_values(self):
-        self.assertEquals(80, osutils.default_tty_width)
-        self.assertEquals(256, osutils.default_non_tty_width)
+        self.assertEquals(80, osutils.default_terminal_width)
 
     def test_defaults_to_COLUMNS(self):
         # COLUMNS is set by the test framework
@@ -1907,7 +1906,7 @@
                 return True
 
         sys.stdout = I_am_a_tty()
-        self.assertEquals(osutils.default_tty_width, osutils.terminal_width())
+        self.assertEquals(None, osutils.terminal_width())
 
     def test_non_tty_default_without_columns(self):
         del os.environ['COLUMNS']
@@ -1916,8 +1915,7 @@
             sys.stdout = orig_stdout
         self.addCleanup(restore)
         sys.stdout = None
-        self.assertEquals(osutils.default_non_tty_width,
-                          osutils.terminal_width())
+        self.assertEquals(None, osutils.terminal_width())
 
     def test_TIOCGWINSZ(self):
         # bug 63539 is about a termios without TIOCGWINSZ attribute
@@ -1931,5 +1929,7 @@
             if exist:
                 termios.TIOCGWINSZ = orig
         self.addCleanup(restore)
+
         del termios.TIOCGWINSZ
-        self.assertEquals(osutils.default_tty_width, osutils.terminal_width())
+        del os.environ['COLUMNS']
+        self.assertEquals(None, osutils.terminal_width())

=== modified file 'bzrlib/ui/text.py'
--- a/bzrlib/ui/text.py	2009-09-23 06:29:46 +0000
+++ b/bzrlib/ui/text.py	2009-12-02 15:24:34 +0000
@@ -234,8 +234,10 @@
 
     def _show_line(self, s):
         # sys.stderr.write("progress %r\n" % s)
-        n = self._width - 1
-        self._term_file.write('\r%-*.*s\r' % (n, n, s))
+        if self._width is not None:
+            n = self._width - 1
+            s = '%-*.*s' % (n, n, s)
+        self._term_file.write('\r' + s + '\r')
 
     def clear(self):
         if self._have_output:

=== modified file 'bzrlib/win32utils.py'
--- a/bzrlib/win32utils.py	2009-07-08 14:37:25 +0000
+++ b/bzrlib/win32utils.py	2009-12-02 15:24:34 +0000
@@ -178,7 +178,7 @@
         return (defaultx, defaulty)
 
     # To avoid problem with redirecting output via pipe
-    # need to use stderr instead of stdout
+    # we need to use stderr instead of stdout
     h = ctypes.windll.kernel32.GetStdHandle(WIN32_STDERR_HANDLE)
     csbi = ctypes.create_string_buffer(22)
     res = ctypes.windll.kernel32.GetConsoleScreenBufferInfo(h, csbi)



More information about the bazaar-commits mailing list