# ----------------------------------------------------------------------------
# Code to difference two text files and output the result as HTML
#
# Programmer: Jeremy Meredith
# Date: June 9, 2003
#
# Note: The core logic was taken from Sean Ahern's xcompare tool
# (then turned into python and refactored.....)
#
# Modifications:
# Brad Whitlock, Thu Mar 18 16:26:26 PST 2004
# Added exception handling code so it does not crash if baselines are
# missing.
#
# ----------------------------------------------------------------------------
import os, string, cgi
class TextFile:
def __init__(self, fn, msg):
self.fileName = fn
self.opened = 0
try:
self.filedes = open(self.fileName, "rt")
self.opened = 1
except IOError:
print "%s %s." % (msg, self.fileName)
def close(self):
if(self.opened == 1):
self.filedes.close()
def readline(self):
retval = ""
if(self.opened == 1):
try:
retval = self.filedes.readline()
except IOError:
retval = ""
return retval
class TextList:
def __init__(self, list):
self.list = list
self.idx = 0
def close(self):
self.idx = 0
self.list = None
def readline(self):
retval = ""
if self.idx < len(self.list):
retval = self.list[self.idx]
self.idx += 1
return retval
class Differencer:
INSERT="#00ff88"
DELETE="#ff8888"
CHANGE="#ffff00"
NOCOLOR=""
oneSidedColor=1
def __init__(self, f1, f2):
self.fn1 = f1
self.fn2 = f2
def InitIO(self, filename, testname):
if type(self.fn1) == type([]):
self.in1 = TextList(self.fn1)
else:
self.in1 = TextFile(self.fn1, "Warning: No baseline text file: ")
if type(self.fn2) == type([]):
self.in2 = TextList(self.fn2)
else:
self.in2 = TextFile(self.fn2, "Warning: No current text file: ")
self.nextleft = self.in1.readline()
self.nextright = self.in2.readline()
self.out = open(filename, "wt")
self.out.write("
Results for test case %s\n"%testname)
self.out.write("\n")
self.out.write("Results for test case %s
\n" % testname)
self.out.write("\n")
self.out.write("Legend |
\n")
self.out.write("%d Lines Added |
\n"%(self.INSERT,self.nAdded))
self.out.write("%d Lines Deleted |
\n"%(self.DELETE,self.nDeleted))
self.out.write("%d Lines Changed |
\n"%(self.CHANGE,self.nChanged))
self.out.write("
\n")
self.out.write("%d modifications, totalling %d lines\n"%(self.nModifications,self.nModifiedLines))
self.out.write("
\n")
self.out.write("\n")
self.out.write("\n")
self.out.write("\n")
self.out.write("\n")
self.out.write("\n")
self.out.write("\n")
self.out.write(" %s | \n" % " Line ")
self.out.write(" %s | \n" % "Baseline")
self.out.write(" %s | \n" % " Line ")
self.out.write(" %s | \n" % "Current")
self.out.write("
\n")
self.out.write("\n")
self.out.write("\n")
def FiniIO(self):
self.out.write("\n")
self.out.write("
\n")
self.out.close()
self.in1.close()
self.in2.close()
def ParseDiff(self):
self.commands=[]
f = os.popen("/usr/bin/diff -f '%s' '%s' 2>/dev/null"%(self.fn1,self.fn2))
op = f.read(1)
while op != '':
arguments = string.split(f.readline())
line = int(arguments[0])
arg = 1
if len(arguments) > 1: arg = int(arguments[1]) + 1 - line
if (op != 'd'):
length = 0;
buff = string.strip(f.readline())
while buff == "" or buff[0] != '.':
length = length + 1
buff = string.strip(f.readline())
else:
length = arg
if op != 'a': line=line-1
self.commands.append((op,line,arg,length))
op = f.read(1)
f.close()
def GetNextLeft(self):
astr=cgi.escape(string.rstrip(self.nextleft))
self.nextleft = self.in1.readline()
self.leftline = self.leftline+1
if astr=="":
return " "
else:
return astr
def GetNextRight(self):
astr=cgi.escape(string.rstrip(self.nextright))
self.nextright = self.in2.readline()
self.rightline = self.rightline+1
if astr=="":
return " "
else:
return astr
def WriteLineNumber(self, num=""):
self.out.write(" %d: | \n"%num)
def WriteLineText(self, color, text):
if color == "":
self.out.write(" %s | \n"%text)
else:
self.out.write(" %s | \n"%(color,text))
def WriteLeft(self,cl):
l = self.GetNextLeft()
self.WriteLineNumber(self.leftline)
self.WriteLineText(cl, l)
def WriteRight(self,cr):
r = self.GetNextRight()
self.WriteLineNumber(self.rightline)
self.WriteLineText(cr, r)
def WriteBlank(self,color):
self.out.write(" | \n")
if color == "" or self.oneSidedColor:
self.out.write(" | \n")
else:
self.out.write(" | \n"%color)
def InsertLine(self,cl, cr):
self.out.write("")
self.WriteLeft(cl)
self.WriteRight(cr)
self.out.write("
\n")
def InsertLeft(self,cl):
self.out.write("")
self.WriteLeft(cl)
self.WriteBlank(cl)
self.out.write("
\n")
def InsertRight(self,cr):
self.out.write("")
self.WriteBlank(cr)
self.WriteRight(cr)
self.out.write("
\n")
def EOFReached(self):
return (self.nextleft == "" or self.nextright == "")
def Difference(self, filename, testname):
commands = self.ParseDiff()
self.nModifiedLines = 0
self.nChanged = 0
self.nAdded = 0
self.nDeleted = 0
for (op,line,arg,length) in self.commands:
if (op == 'a'): self.nAdded = self.nAdded + length
if (op == 'd'): self.nDeleted = self.nDeleted + arg
if (op == 'c'): self.nChanged = self.nChanged + arg
self.nModifications = len(self.commands)
self.nModifiedLines = self.nAdded + self.nChanged + self.nDeleted
self.leftline=0
self.rightline=0
curdiff=0
self.InitIO(filename, testname)
while (not self.EOFReached()):
if (curdiff < len(self.commands)):
(op,line,arg,length) = self.commands[curdiff]
if (curdiff < len(self.commands) and line == self.leftline):
#print "op=%c line=%d arg=%d len=%d"%(op,line,arg,length)
if (op == 'd'):
for i in range(arg):
self.InsertLeft(self.DELETE)
elif (op == 'a'):
for i in range(length):
self.InsertRight(self.INSERT)
elif (op == 'c'):
for i in range(min(arg,length)):
self.InsertLine(self.CHANGE,self.CHANGE)
if length>arg:
for i in range(arg,length):
self.InsertRight(self.CHANGE)
else:
for i in range(length,arg):
self.InsertLeft(self.CHANGE)
curdiff=curdiff+1
else:
self.InsertLine(self.NOCOLOR, self.NOCOLOR)
while (self.nextleft != ""):
self.InsertLeft(self.DELETE)
while (self.nextright != ""):
self.InsertRight(self.INSERT)
self.FiniIO()
return (self.nModifications, self.nModifiedLines)