# ---------------------------------------------------------------------------- # 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("\n") self.out.write("\n"%(self.INSERT,self.nAdded)) self.out.write("\n"%(self.DELETE,self.nDeleted)) self.out.write("\n"%(self.CHANGE,self.nChanged)) self.out.write("
Legend
%d Lines Added
%d Lines Deleted
%d Lines Changed

\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(" \n" % " Line ") self.out.write(" \n" % "Baseline") self.out.write(" \n" % " Line ") self.out.write(" \n" % "Current") self.out.write("\n") self.out.write("\n") self.out.write("\n") def FiniIO(self): self.out.write("\n") self.out.write("
%s%s%s%s
\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)