]> git.cworth.org Git - apitrace/blobdiff - scripts/tracediff.py
Merge branch 'gui-thumbnails'
[apitrace] / scripts / tracediff.py
index 7237da095e5b7a172e1aae9890b7f99fecd4c86b..b3933a9d59ee1b11a5e6b0b9b81327345d9aa4ca 100755 (executable)
 
 import platform
 import optparse
-import os
+import os.path
 import shutil
 import subprocess
 import sys
 import tempfile
 
 
-def stripdump(trace, fifo):
-    dump = subprocess.Popen(
-        args = [
+class Dumper:
+
+    def __init__(self, trace, calls):
+        self.output = tempfile.NamedTemporaryFile()
+
+        dump_args = [
             options.apitrace,
             'dump',
             '--color=never',
+            '--call-nos=no',
             '--arg-names=no',
-            '--calls=' + options.calls,
+            '--calls=' + calls,
             trace
-        ],
-        stdout = subprocess.PIPE,
-        universal_newlines = True,
-    )
+        ]
 
-    sed = subprocess.Popen(
-        args = [
-            'sed',
-            '-e', r's/\r$//g',
-            '-e', r's/^[0-9]\+ //',
-            '-e', r's/hdc = \w\+/hdc/g',
-        ],
-        stdin = dump.stdout,
-        stdout = open(fifo, 'wt'),
-        universal_newlines = True,
-    )
+        self.dump = subprocess.Popen(
+            args = dump_args,
+            stdout = self.output,
+            universal_newlines = True,
+        )
+
+
+if platform.system() == 'Windows':
+    start_delete = ''
+    end_delete   = ''
+    start_insert = ''
+    end_insert   = ''
+else:
+    start_delete = '\33[9m\33[31m'
+    end_delete   = '\33[0m'
+    start_insert = '\33[32m'
+    end_insert   = '\33[0m'
 
 
-def diff(traces):
-    fifodir = tempfile.mkdtemp()
-    try:
-        fifos = []
-        for i in range(len(traces)):
-            trace = traces[i]
-            fifo = os.path.join(fifodir, str(i))
-            stripdump(trace, fifo)
-            fifos.append(fifo)
+def diff(ref_trace, src_trace):
 
-        # TODO use difflib instead
-        sdiff = subprocess.Popen(
-            args = [
+    ref_dumper = Dumper(ref_trace, options.ref_calls)
+    src_dumper = Dumper(src_trace, options.src_calls)
+
+    # TODO use difflib instead
+    if options.diff == 'diff':
+        diff_args = [
+                'diff',
+                '--speed-large-files',
+                '--old-line-format=' + start_delete + '%l' + end_delete + '\n',
+                '--new-line-format=' + start_insert + '%l' + end_insert + '\n',
+            ]
+    elif options.diff == 'sdiff':
+        diff_args = [
                 'sdiff',
                 '--width=%u' % options.width,
                 '--speed-large-files',
-            ] + fifos,
-            stdout = subprocess.PIPE,
-            universal_newlines = True,
-        )
-
+            ]
+    elif options.diff == 'wdiff':
+        diff_args = [
+                'wdiff',
+                #'--terminal',
+                '--avoid-wraps',
+                '--start-delete=' + start_delete,
+                '--end-delete=' + end_delete,
+                '--start-insert=' + start_insert,
+                '--end-insert=' + end_insert,
+            ]
+    else:
+        assert False
+    diff_args += [ref_dumper.output.name, src_dumper.output.name]
+
+    ref_dumper.dump.wait()
+    src_dumper.dump.wait()
+
+    less = None
+    if sys.stdout.isatty():
         less = subprocess.Popen(
             args = ['less', '-FRXn'],
-            stdin = sdiff.stdout
+            stdin = subprocess.PIPE
         )
 
+        diff_stdout = less.stdin
+    else:
+        diff_stdout = None
+
+    diff = subprocess.Popen(
+        args = diff_args,
+        stdout = diff_stdout,
+        universal_newlines = True,
+    )
+
+    diff.wait()
+
+    if less is not None:
         less.wait()
 
-    finally:
-        shutil.rmtree(fifodir)
+
+def which(executable):
+    '''Search for the executable on the PATH.'''
+
+    if platform.system() == 'Windows':
+        exts = ['.exe']
+    else:
+        exts = ['']
+    dirs = os.environ['PATH'].split(os.path.pathsep)
+    for dir in dirs:
+        path = os.path.join(dir, executable)
+        for ext in exts:
+            if os.path.exists(path + ext):
+                return True
+    return False
 
 
 def columns():
@@ -103,6 +153,7 @@ def main():
     '''Main program.
     '''
 
+    # Determine default options
     default_width = columns()
 
     # Parse command line options
@@ -113,10 +164,23 @@ def main():
         '-a', '--apitrace', metavar='PROGRAM',
         type='string', dest='apitrace', default='apitrace',
         help='apitrace command [default: %default]')
+    optparser.add_option(
+        '-d', '--diff',
+        type="choice", choices=('diff', 'sdiff', 'wdiff'),
+        dest="diff", default=None,
+        help="diff program: wdiff, sdiff, or diff [default: auto]")
     optparser.add_option(
         '-c', '--calls', metavar='CALLSET',
         type="string", dest="calls", default='1-10000',
         help="calls to compare [default: %default]")
+    optparser.add_option(
+        '--ref-calls', metavar='CALLSET',
+        type="string", dest="ref_calls", default=None,
+        help="calls to compare from reference trace")
+    optparser.add_option(
+        '--src-calls', metavar='CALLSET',
+        type="string", dest="src_calls", default=None,
+        help="calls to compare from source trace")
     optparser.add_option(
         '-w', '--width', metavar='NUM',
         type="string", dest="width", default=default_width,
@@ -127,7 +191,23 @@ def main():
     if len(args) != 2:
         optparser.error("incorrect number of arguments")
 
-    diff(args)
+    if options.diff is None:
+        if which('wdiff'):
+            options.diff = 'wdiff'
+        else:
+            sys.stderr.write('warning: wdiff not found\n')
+            if which('sdiff'):
+                options.diff = 'sdiff'
+            else:
+                sys.stderr.write('warning: sdiff not found\n')
+                options.diff = 'diff'
+
+    if options.ref_calls is None:
+        options.ref_calls = options.calls
+    if options.src_calls is None:
+        options.src_calls = options.calls
+
+    diff(*args)
 
 
 if __name__ == '__main__':