scons: Use the textwrap module to wrap warnings/errors neatly.
authorGabe Black <gabe.black@gmail.com>
Thu, 26 Mar 2020 11:04:42 +0000 (04:04 -0700)
committerGabe Black <gabeblack@google.com>
Fri, 27 Mar 2020 08:44:28 +0000 (08:44 +0000)
Otherwise the error and warning messages get chopped off and wrapped by
the terminal wherever they happened to end. That's ugly and hard to
read.

This mechanism attempts to wrap the text using the console width which
it attempts to determine in two ways, first with shutil which should
work in python 3.3 and above, and then with the curses python module. If
neither of those works, it just falls back to 80 columns which is not
ideal but is reasonable.

Change-Id: I961936295505f93f5f36eb6d9cebc5073b5f793b
Reviewed-on: https://gem5-review.googlesource.com/c/public/gem5/+/27128
Reviewed-by: Bobby R. Bruce <bbruce@ucdavis.edu>
Maintainer: Gabe Black <gabeblack@google.com>
Tested-by: kokoro <noreply+kokoro@google.com>
site_scons/gem5_scons/__init__.py

index 16bb753af52fc6d3c86923876f20c68c66edfc03..e7e7a0afca502afcb20d7c0b303620ebecaf4138 100644 (file)
@@ -41,6 +41,7 @@
 from __future__ import print_function
 
 import os
+import textwrap
 
 from gem5_scons.util import get_termcap
 import SCons.Script
@@ -127,9 +128,48 @@ class Transform(object):
             return ', '.join(f)
         return self.format % (com_pfx, fmt(srcs), fmt(tgts))
 
+# The width warning and error messages should be wrapped at.
+text_width = None
+
+# This should work in python 3.3 and above.
+if text_width is None:
+    try:
+        import shutil
+        text_width = shutil.get_terminal_size().columns
+    except:
+        pass
+
+# This should work if the curses python module is installed.
+if text_width is None:
+    try:
+        import curses
+        try:
+            _, text_width = curses.initscr().getmaxyx()
+        finally:
+            curses.endwin()
+    except:
+        pass
+
+# If all else fails, default to 80 columns.
+if text_width is None:
+    text_width = 80
+
 def print_message(prefix, color, message, **kwargs):
+    # Precompute some useful values.
+    prefix_len = len(prefix)
+    wrap_width = text_width - prefix_len
+    padding = ' ' * prefix_len
+
+    # First split on newlines.
     lines = message.split('\n')
-    message = prefix + ('\n' + ' ' * len(prefix)).join(lines)
+    # Then wrap each line to the required width.
+    wrapped_lines = []
+    for line in lines:
+        wrapped_lines.extend(textwrap.wrap(line, wrap_width))
+    # Finally add the prefix and padding on extra lines, and glue it all back
+    # together.
+    message = prefix + ('\n' + padding).join(wrapped_lines)
+    # Print the message in bold in the requested color.
     print(color + termcap.Bold + message + termcap.Normal, **kwargs)
 
 def warning(*args, **kwargs):