Skip to content
Merged
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
159 changes: 93 additions & 66 deletions roottest/scripts/custom_diff.py
Original file line number Diff line number Diff line change
@@ -1,61 +1,85 @@
""" Clever (with filters) compare command using difflib.py providing diffs in four formats:

* ndiff: lists every line and highlights interline changes.
* context: highlights clusters of changes in a before/after format.
* unified: highlights clusters of changes in an inline format.
* html: generates side by side comparison with change highlights.

"""
import sys, os, time, difflib, optparse, re
"""Clever (with filters) compare command using difflib.py providing diffs in four formats:

* ndiff: lists every line and highlights interline changes.
* context: highlights clusters of changes in a before/after format.
* unified: highlights clusters of changes in an inline format.
* html: generates side by side comparison with change highlights.

"""
import difflib
import optparse
import os
import re
import sys
import time


#---------------------------------------------------------------------------------------------------------------------------
#---Filter and substitutions------------------------------------------------------------------------------------------------
class LineFilter:
"""A line filter to suppress lines in the diff.
self.skip_regexes contains patterns to skip entirely.
self.substitutions contains patterns to replace with the given strings.
These patterns only need to be compiled once for all the incoming lines.
"""

def __init__(self):
# Skip these lines
self.skip_regexes = [
re.compile(pattern)
for pattern in [
r"^Processing ", # Interpreted macros
r"^Info in <\w+::ACLiC>: creating shared library", # Compiled macros
r"^In file included from input_line", # Wrapper input line
r"^[:space:]*$", # Lines which are empty apart from spaces
]
]

# Replace these patterns in all lines
self.substitutions = [
(re.compile(r"[ ]@0x[a-fA-F0-9]+"), ""), # Remove pointers from output
(re.compile(r"std::__[0-9]+::"), "std::"), # Canonicalise standard namespaces
(
re.compile(r"^(\S*/|)([^:/]+)[-:0-9]*(?=: error:)"),
r"\2",
), # Trim file paths and line numbers from lines with ": error:"
(re.compile(r"(input_line_|ROOT_prompt_)[0-9]+"), r"\1--"), # Canonicalise input_line_123, ROOT_prompt_345
]

def filter(self, lines, ignoreWhiteSpace=False):
outlines = []
for line in lines:
if sys.platform == "win32":
if "Creating library " in line:
continue
if "_ACLiC_dict" in line:
continue
if "Warning in <TInterpreter::ReadRootmapFile>:" in line:
continue
if "Warning in <TClassTable::Add>:" in line:
continue
if "Error: Removing " in line:
continue
if " -nologo -TP -c -nologo -I" in line:
continue
if "rootcling -v1 -f " in line:
continue
if "No precompiled header available" in line:
continue

# ---Skip all lines matching predefined expressions---------------------------
if any(pattern.match(line) is not None for pattern in self.skip_regexes):
continue

def filter(lines, ignoreWhiteSpace = False):
outlines = []
for line in lines:
if sys.platform == 'win32':
if 'Creating library ' in line:
continue
if '_ACLiC_dict' in line:
continue
if 'Warning in <TInterpreter::ReadRootmapFile>:' in line:
continue
if 'Warning in <TClassTable::Add>:' in line:
continue
if 'Error: Removing ' in line:
continue
if ' -nologo -TP -c -nologo -I' in line:
continue
if 'rootcling -v1 -f ' in line:
continue
if 'No precompiled header available' in line:
continue
#if line in ['\n', '\r\n']:
# continue
#---Processing line from interpreter (root.exe)------------------------------
if re.match(r'^Processing ', line):
continue
#---ACLiC info---------------------------------------------------------------
if re.match(r'^Info in <\w+::ACLiC>: creating shared library', line):
continue
#---Compilation error--------------------------------------------------------
elif re.search(r': error:', line):
nline = re.sub(r'\S+/', '', line)
nline = re.sub(r'(:|_)[0-9]+(?=:)', ':--', nline)
#---Wrapper input line-------------------------------------------------------
elif re.match(r'^In file included from input_line', line):
continue
else:
nline = line
#---Remove Addresses in cling/cint-------------------------------------------
nline = re.sub(r'[ ]@0x[a-fA-F0-9]+', '', nline)
#---Remove versioning in std-------------------------------------------------
nline = re.sub(r'std::__[0-9]::', 'std::', nline)
#---Remove white spaces------------------------------------------------------
if (ignoreWhiteSpace):
nline = re.sub(r'[ ]', '', nline)
outlines.append(nline)
return outlines
# ---Apply predefined replacements--------------------------------------------
for pattern, replacement in self.substitutions:
line = pattern.sub(replacement, line)

# ---Remove white spaces------------------------------------------------------
if ignoreWhiteSpace:
line = re.sub(r"[ ]", "", line)
outlines.append(line)
return outlines

#-----------------------------------------------------------------------------------------------------------------------------
def main():
Expand All @@ -67,16 +91,16 @@ def main():
parser.add_option("-n", action="store_true", default=False, help='Produce a ndiff format diff')
parser.add_option("-l", "--lines", type="int", default=3, help='Set number of context lines (default 3)')
(options, args) = parser.parse_args()

if len(args) == 0:
parser.print_help()
sys.exit(1)
if len(args) != 2:
parser.error("need to specify both a fromfile and tofile")

n = options.lines
fromfile, tofile = args

fromdate = time.ctime(os.stat(fromfile).st_mtime)
todate = time.ctime(os.stat(tofile).st_mtime)
if sys.platform == 'win32':
Expand All @@ -86,17 +110,18 @@ def main():
fromlines = open(fromfile, 'r' if sys.version_info >= (3, 4) else 'U').readlines()
tolines = open(tofile, 'r' if sys.version_info >= (3, 4) else 'U').readlines()

nows_fromlines = filter(fromlines, True)
nows_tolines = filter(tolines, True)
lineFilter = LineFilter()
nows_fromlines = lineFilter.filter(fromlines, True)
nows_tolines = lineFilter.filter(tolines, True)

check = difflib.context_diff(nows_fromlines, nows_tolines)
try:
first = next(check)
_ = next(check)
except StopIteration:
sys.exit(0)

fromlines = filter(fromlines, False)
tolines = filter(tolines, False)
fromlines = lineFilter.filter(fromlines, False)
tolines = lineFilter.filter(tolines, False)

if options.u:
diff = difflib.unified_diff(fromlines, tolines, fromfile, tofile, fromdate, todate, n=n)
Expand All @@ -106,12 +131,14 @@ def main():
diff = difflib.HtmlDiff().make_file(fromlines,tolines,fromfile,tofile,context=options.c,numlines=n)
else:
diff = difflib.context_diff(fromlines, tolines, fromfile, tofile, fromdate, todate, n=n)

difflines = [line for line in diff]
sys.stdout.writelines(difflines)

if difflines : sys.exit(1)
else : sys.exit(0)
if difflines:
sys.exit(1)
else:
sys.exit(0)

if __name__ == '__main__':
main()
Expand Down
Loading