""" PatchUtils.py This module defines some functions for patching Python code. """ import string import os def AskYN(prompt): if os.name == 'mac': import EasyDialogs butn = EasyDialogs.AskYesNoCancel(prompt, default=9) if butn == 1: return 'Y' if butn == 0: return 'N' raise 'userCanceled' while 1: ans = raw_input(prompt)[:1] if ans=='y' or ans=='Y': return 'Y' if ans=='n' or ans=='N': return 'N' class Patch: "class Patch: keeps info on one file being patched" def __init__(self, basepath, filename, idtag): "constructor: make a backup of the file, and read the contents into memory." self.path = os.path.join(basepath, filename) self.lines = [] self._MakeBackup() self._Read() idtag = string.strip(idtag) patchnote = "### PATCHED: " patchnotelen = len(patchnote) patches = [] i = 0 while self.lines[i][:patchnotelen] == patchnote: patches.append(string.strip(self.lines[i][patchnotelen:])) i = i+1 if patches: print "Previous patches:", string.join(patches) if idtag in patches: print "Patch '%s' has already been applied." % idtag if len(patches) > 1: print "WARNING: Removing patches will remove ALL previous patches!" if AskYN("Remove previous patches?") == 'Y': self._RestoreFromBackup() # finally, insert patch note self.lines.insert(0, patchnote + idtag + '\n') def _MakeBackup(self): try: # if we already have a backup file, do nothing open(self.path+".bak",'r') return except: pass fin = open(self.path,'r') fout = open(self.path+".bak",'w') fout.writelines(fin.readlines()) def _RestoreFromBackup(self): print "Restoring %s from backup" % self.path self.lines = open(self.path+".bak",'r').readlines() open(self.path,'w').writelines(self.lines) self.qtyLines = len(self.lines) def _Read(self): print "\nReading", self.path self.lines = open(self.path, 'r').readlines() self.qtyLines = len(self.lines) def Write(self): open(self.path, 'w').writelines(self.lines) print "%s lines written to %s" % (len(self.lines), self.path) def _FindLine(self, x, callerName): lineno = None for i in range(self.qtyLines): if string.find(self.lines[i], x) >= 0: if lineno is not None: raise callerName+"_NotUnique", x lineno = i if lineno is None: raise callerName+"_NotFound", x return lineno def InsertAfter(self, x, data): lineno = self._FindLine(x, "InsertAfter") # we've found it; now, insert after this line datalines = string.split(data,'\n') print "Inserting %d line(s) after line %d" % (len(datalines), lineno) for line in datalines: lineno = lineno + 1 self.lines.insert(lineno, line+'\n') self.qtyLines = len(self.lines) def InsertBefore(self, x, data): lineno = self._FindLine(x, "InsertBefore") # we've found it; now, insert before this line datalines = string.split(data,'\n') print "Inserting %d line(s) before line %d" % (len(datalines), lineno) datalines.reverse() for line in datalines: self.lines.insert(lineno, line+'\n') self.qtyLines = len(self.lines) def ReplaceLine(self, x, data): lineno = self._FindLine(x, "ReplaceLine") # we've found it; now, replace this line with the given ones del self.lines[lineno] datalines = string.split(data,'\n') print "Substituting %d line(s) for line %d" % (len(datalines), lineno) for line in datalines: self.lines.insert(lineno, line+'\n') lineno = lineno + 1 self.qtyLines = len(self.lines)