Mesa (main): pytracediff: implement pager ('less') invocation internally

GitLab Mirror gitlab-mirror at kemper.freedesktop.org
Tue Jun 28 12:13:50 UTC 2022


Module: Mesa
Branch: main
Commit: aab5d176b83fe8d5bbf5502c38c4aa0a8558a22f
URL:    http://cgit.freedesktop.org/mesa/mesa/commit/?id=aab5d176b83fe8d5bbf5502c38c4aa0a8558a22f

Author: Matti Hamalainen <ccr at tnsp.org>
Date:   Mon Jun 20 14:20:09 2022 +0300

pytracediff: implement pager ('less') invocation internally

In order to get rid of the ntracediff.sh wrapper script, implement
invocation of 'less' internally, if the stdout is determined to
be a tty. Otherwise just print out normally.

Signed-off-by: Matti Hamalainen <ccr at tnsp.org>
Acked-by: Mike Blumenkrantz <michael.blumenkrantz at gmail.com>
Reviewed-by: Dylan Baker <dylan at pnwbakers.com>
Part-of: <https://gitlab.freedesktop.org/mesa/mesa/-/merge_requests/17135>

---

 src/gallium/tools/trace/pytracediff.py | 236 +++++++++++++++++++--------------
 1 file changed, 135 insertions(+), 101 deletions(-)

diff --git a/src/gallium/tools/trace/pytracediff.py b/src/gallium/tools/trace/pytracediff.py
index 7c79f755806..15ea36f8306 100755
--- a/src/gallium/tools/trace/pytracediff.py
+++ b/src/gallium/tools/trace/pytracediff.py
@@ -26,12 +26,14 @@
 ##########################################################################
 
 from parse import *
+import os
 import sys
 import re
 import signal
 import functools
 import argparse
 import difflib
+import subprocess
 
 assert sys.version_info >= (3, 6), 'Python >= 3.6 required'
 
@@ -54,6 +56,8 @@ PKK_ANSI_ITALIC    = '3m'
 ###
 def pkk_fatal(msg):
     print(f"ERROR: {msg}", file=sys.stderr)
+    if outpipe is not None:
+        outpipe.terminate()
     sys.exit(1)
 
 
@@ -61,8 +65,17 @@ def pkk_info(msg):
     print(msg, file=sys.stderr)
 
 
+def pkk_output(outpipe, msg):
+    if outpipe is not None:
+        print(msg, file=outpipe.stdin)
+    else:
+        print(msg)
+
+
 def pkk_signal_handler(signal, frame):
     print("\nQuitting due to SIGINT / Ctrl+C!")
+    if outpipe is not None:
+        outpipe.terminate()
     sys.exit(1)
 
 
@@ -259,6 +272,16 @@ def pkk_format_line(line, indent, width):
 ### Main program starts
 ###
 if __name__ == "__main__":
+    ### Check if output is a terminal
+    outpipe = None
+    redirect = False
+
+    try:
+        defwidth = os.get_terminal_size().columns
+        redirect = True
+    except OSError:
+        defwidth = 80
+
     signal.signal(signal.SIGINT, pkk_signal_handler)
 
     ### Parse arguments
@@ -307,7 +330,7 @@ if __name__ == "__main__":
 
     optparser.add_argument("-w", "--width",
         dest="output_width",
-        type=functools.partial(pkk_arg_range, vmin=16, vmax=512), default=80,
+        type=functools.partial(pkk_arg_range, vmin=16, vmax=512), default=defwidth,
         metavar="N",
         help="output width (default: %(default)s)")
 
@@ -327,115 +350,126 @@ if __name__ == "__main__":
         print("The files are identical.")
         sys.exit(0)
 
-    ### Output results
-    pkk_info("Outputting diff ...")
-    colwidth = int((options.output_width - 3) / 2)
-    colfmt   = "{}{:"+ str(colwidth) +"s}{} {}{}{} {}{:"+ str(colwidth) +"s}{}"
-
-    printer = PKKPrettyPrinter(options)
-
-    prevtag = ""
-    for tag, start1, end1, start2, end2 in opcodes:
-        if tag == "equal":
-            show_args = False
-            if options.suppress_common:
-                if tag != prevtag:
-                    print("[...]")
-                continue
-
-            sep = "|"
-            ansi1 = ansi2 = ansiend = ""
-            show_args = False
-        elif tag == "insert":
-            sep = "+"
-            ansi1 = ""
-            ansi2 = PKK_ANSI_ESC + PKK_ANSI_GREEN
-            show_args = True
-        elif tag == "delete":
-            sep = "-"
-            ansi1 = PKK_ANSI_ESC + PKK_ANSI_RED
-            ansi2 = ""
-            show_args = True
-        elif tag == "replace":
-            sep = ">"
-            ansi1 = ansi2 = PKK_ANSI_ESC + PKK_ANSI_BOLD
-            show_args = True
-        else:
-            pkk_fatal(f"Internal error, unsupported difflib.SequenceMatcher operation '{tag}'.")
+    ### Redirect output to 'less' if stdout is a tty
+    try:
+        if redirect:
+            outpipe = subprocess.Popen(["less", "-S", "-R"], stdin=subprocess.PIPE, encoding="utf8")
+
+        ### Output results
+        pkk_info("Outputting diff ...")
+        colwidth = int((options.output_width - 3) / 2)
+        colfmt   = "{}{:"+ str(colwidth) +"s}{} {}{}{} {}{:"+ str(colwidth) +"s}{}"
+
+        printer = PKKPrettyPrinter(options)
+
+        prevtag = ""
+        for tag, start1, end1, start2, end2 in opcodes:
+            if tag == "equal":
+                show_args = False
+                if options.suppress_common:
+                    if tag != prevtag:
+                        pkk_output(outpipe, "[...]")
+                    continue
+
+                sep = "|"
+                ansi1 = ansi2 = ansiend = ""
+                show_args = False
+            elif tag == "insert":
+                sep = "+"
+                ansi1 = ""
+                ansi2 = PKK_ANSI_ESC + PKK_ANSI_GREEN
+                show_args = True
+            elif tag == "delete":
+                sep = "-"
+                ansi1 = PKK_ANSI_ESC + PKK_ANSI_RED
+                ansi2 = ""
+                show_args = True
+            elif tag == "replace":
+                sep = ">"
+                ansi1 = ansi2 = PKK_ANSI_ESC + PKK_ANSI_BOLD
+                show_args = True
+            else:
+                pkk_fatal(f"Internal error, unsupported difflib.SequenceMatcher operation '{tag}'.")
 
-        # No ANSI, please
-        if options.plain:
-            ansi1 = ansisep = ansi2 = ansiend = ""
-        else:
-            ansisep = PKK_ANSI_ESC + PKK_ANSI_PURPLE
-            ansiend = PKK_ANSI_ESC + PKK_ANSI_NORMAL
-
-
-        # Print out the block
-        ncall1 = start1
-        ncall2 = start2
-        last1 = last2 = False
-        while True:
-            # Get line data
-            if ncall1 < end1:
-                if not options.ignore_junk or not stack1[ncall1].is_junk:
-                    printer.entry_start(show_args)
-                    stack1[ncall1].visit(printer)
-                    data1 = printer.entry_get()
+            # No ANSI, please
+            if options.plain:
+                ansi1 = ansisep = ansi2 = ansiend = ""
+            else:
+                ansisep = PKK_ANSI_ESC + PKK_ANSI_PURPLE
+                ansiend = PKK_ANSI_ESC + PKK_ANSI_NORMAL
+
+
+            # Print out the block
+            ncall1 = start1
+            ncall2 = start2
+            last1 = last2 = False
+            while True:
+                # Get line data
+                if ncall1 < end1:
+                    if not options.ignore_junk or not stack1[ncall1].is_junk:
+                        printer.entry_start(show_args)
+                        stack1[ncall1].visit(printer)
+                        data1 = printer.entry_get()
+                    else:
+                        data1 = []
+                    ncall1 += 1
                 else:
                     data1 = []
-                ncall1 += 1
-            else:
-                data1 = []
-                last1 = True
-
-            if ncall2 < end2:
-                if not options.ignore_junk or not stack2[ncall2].is_junk:
-                    printer.entry_start(show_args)
-                    stack2[ncall2].visit(printer)
-                    data2 = printer.entry_get()
+                    last1 = True
+
+                if ncall2 < end2:
+                    if not options.ignore_junk or not stack2[ncall2].is_junk:
+                        printer.entry_start(show_args)
+                        stack2[ncall2].visit(printer)
+                        data2 = printer.entry_get()
+                    else:
+                        data2 = []
+                    ncall2 += 1
                 else:
                     data2 = []
-                ncall2 += 1
-            else:
-                data2 = []
-                last2 = True
-
-            # Check if we are at last call of both
-            if last1 and last2:
-                break
-
-            nline = 0
-            while nline < len(data1) or nline < len(data2):
-                # Determine line start indentation
-                if nline > 0:
-                    if options.suppress_variants:
-                        indent = " "*8
+                    last2 = True
+
+                # Check if we are at last call of both
+                if last1 and last2:
+                    break
+
+                nline = 0
+                while nline < len(data1) or nline < len(data2):
+                    # Determine line start indentation
+                    if nline > 0:
+                        if options.suppress_variants:
+                            indent = " "*8
+                        else:
+                            indent = " "*12
                     else:
-                        indent = " "*12
-                else:
-                    indent = ""
+                        indent = ""
+
+                    line1 = pkk_get_line(data1, nline)
+                    line2 = pkk_get_line(data2, nline)
+
+                    # Highlight differing lines if not plain
+                    if not options.plain and line1 != line2:
+                        if tag == "insert" or tag == "delete":
+                            ansi1 = ansi1 + PKK_ANSI_ESC + PKK_ANSI_BOLD
+                        elif tag == "replace":
+                            ansi1 = ansi2 = ansi1 + PKK_ANSI_ESC + PKK_ANSI_YELLOW
 
-                line1 = pkk_get_line(data1, nline)
-                line2 = pkk_get_line(data2, nline)
+                    # Output line
+                    pkk_output(outpipe, colfmt.format(
+                        ansi1, pkk_format_line(line1, indent, colwidth), ansiend,
+                        ansisep, sep, ansiend,
+                        ansi2, pkk_format_line(line2, indent, colwidth), ansiend).
+                        rstrip())
 
-                # Highlight differing lines if not plain
-                if not options.plain and line1 != line2:
-                    if tag == "insert" or tag == "delete":
-                        ansi1 = ansi1 + PKK_ANSI_ESC + PKK_ANSI_BOLD
-                    elif tag == "replace":
-                        ansi1 = ansi2 = ansi1 + PKK_ANSI_ESC + PKK_ANSI_YELLOW
+                    nline += 1
 
-                # Output line
-                print(colfmt.format(
-                    ansi1, pkk_format_line(line1, indent, colwidth), ansiend,
-                    ansisep, sep, ansiend,
-                    ansi2, pkk_format_line(line2, indent, colwidth), ansiend).
-                    rstrip())
+            if tag == "equal" and options.suppress_common:
+                pkk_output(outpipe, "[...]")
 
-                nline += 1
+            prevtag = tag
 
-        if tag == "equal" and options.suppress_common:
-            print("[...]")
+    except Exception as e:
+        pkk_fatal(str(e))
 
-        prevtag = tag
+    if outpipe is not None:
+        outpipe.communicate()



More information about the mesa-commit mailing list