Toolboxcategory cloud |
ViewsPersonal toolsPython annotateFrom Seapine Labs[edit] Annotate Script in PythonPeople sometimes want to see a view of a file which shows who edited each line. This is sometimes called annotate, blame or praise. Below is a (relatively) simple script written in python to produce such a view. You basically type in your command prompt python annotate.py SurroundFile -oMyOutput.txt -ttext to get an annotated view of your file. Your output will look something like Version User Date Code 1 dev1 12/20/2007 //I hope this works 2 dev2 1/1/2007 //That didn't work etc. Save the following code in a file called annotate.py and save it somewhere in your path.
#!/usr/bin/python
import os,sys,getopt
class LineList:
def __init__(self):
self.data = []
self.firstVersion = -1
def InsertLine(self,newStartNum,newNumLines,newVersion):
currentLength = len(self.data)
if currentLength < newStartNum:
self.data.extend([self.firstVersion]*(newStartNum-currentLength))
for i in range(newNumLines):
self.data.insert(newStartNum+i-1,newVersion)
def DeleteLines(self,oldStartNum,oldNumLines):
for i in range(oldNumLines):
if len(self.data) >= (oldStartNum):
del self.data[oldStartNum-1]
def UpdateLine(self,startNum,numLines,newVersion):
currentLength = len(self.data)
if currentLength < (startNum+numLines):
self.data.extend([self.firstVersion]*(startNum+numLines-currentLength))
for i in range(numLines):
self.data[startNum+i-1]=newVersion
def CreateVersionList(self,fileName):
for line in os.popen("sscm diffreport " + fileName + " -n0").readlines():
if line.startswith("Record not found"):
raise Usage("File does not appear to be in Surround")
if line.startswith("---"):
oldVersion = int(line.split("version")[1].split(" in ")[0])
if self.firstVersion == -1:
self.firstVersion = oldVersion
elif line.startswith("+++"):
newVersion = int(line.split("version")[1].split(" in ")[0])
elif line.startswith("@@"):
changeLine = line.split("-")[1].split("+")
lhs = changeLine[0].strip().split(",")
oldStartNum = int(lhs[0])
if len(lhs) == 2:
oldNumLines = int(lhs[1])
else:
oldNumLines = 1
rhs = changeLine[1].strip().rstrip("@").split(",")
newStartNum = int(rhs[0])
if len(rhs) == 2:
newNumLines = int(rhs[1])
else:
newNumLines = 1
if oldNumLines == 0:
self.InsertLine(newStartNum,newNumLines,newVersion)
elif oldNumLines == 1:
if newNumLines == 0:
self.DeleteLines(newStartNum,1)
elif newNumLines == 1:
self.UpdateLine(newStartNum,1,newVersion)
else:
self.UpdateLine(newStartNum,1,newVersion)
self.InsertLine(newStartNum+1,newNumLines-1,newVersion)
else:
if oldStartNum == newStartNum and oldNumLines == newNumLines:
self.UpdateLine(newStartNum,newNumLines,newVersion)
else:
if oldNumLines > newNumLines:
self.UpdateLine(newStartNum,newNumLines,newVersion)
self.DeleteLines(newStartNum+newNumLines,oldNumLines-newNumLines)
else:
self.UpdateLine(newStartNum,oldNumLines,newVersion)
self.InsertLine(newStartNum+oldNumLines,newNumLines-oldNumLines,newVersion)
class HistoryList:
def __init__(self):
self.data = {}
def CreateHistoryList(self,fileName):
foundAction = False
foundWholeLine = False
tempLine = ""
for line in os.popen("sscm history " + fileName).readlines():
if line.startswith("add") or line.startswith("checkin") or line.startswith("promote") or line.startswith("rebase") or line.startswith("attach") or line.startswith("label") or line.startswith("rollback"):
if len(line) > 60:
tempLine = line.strip()
foundWholeLine = True
else:
tempLine = line
elif line.strip().startswith("Comments"):
foundWholeLine = True
else:
tempLine = tempLine.strip() + " " + line.strip()
if foundWholeLine:
items = tempLine.split(" ")
user = ""
version = ""
for col in items[1:]:
if col != "":
if user == "":
user = col
elif version == "":
version = col
else:
date = col
break
foundWholeLine = False
if len(version) > 0 and not (self.data.has_key(int(version))):
self.data[int(version)] = user,date
tempLine = ""
class Usage(Exception):
def __init__(self, msg):
self.msg = msg
def main(argv=None):
if argv is None:
argv = sys.argv
try:
try:
if len(argv) < 2:
raise Usage("usage: annotate FileName [-oOutputFileName] [-thtml-ttext]")
fileName = sys.argv[1]
if not os.path.isfile(fileName):
raise Usage("usage: annotate FileName [-oOutputFileName] [-thtml-ttext]")
cwd = os.getcwd()
os.chdir(os.path.dirname(os.path.realpath(fileName)))
fileName = os.path.basename(fileName)
opts, args = getopt.getopt(argv[2:], "o:t:")
outputName = ""
htmlOutput = False
for o,a in opts:
if o == "-o":
outputName = a
if o == "-t":
if a == "html":
htmlOutput = True
if outputName == "":
if htmlOutput:
outputName = "annotate.html"
else:
outputName = "annotate.txt"
except getopt.error, msg:
raise Usage(msg)
lineVersions = LineList()
lineVersions.CreateVersionList(fileName)
historyData = HistoryList()
historyData.CreateHistoryList(fileName)
f = open(fileName)
os.chdir(cwd)
outFile = open(outputName,"w")
try:
if htmlOutput:
outFile.writelines('<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">\m')
outFile.writelines('<html xmlns="http://www.w3.org/1999/xhtml" ><head><meta content="text/html; charset=UTF-8" http-equiv="content-type"></head><body>')
outFile.writelines('<table cellpadding="0" cellspacing="0" style="border-bottom:solid 1px black;width:100%; border-collapse: collapse;\
font-family: \'Courier New\', Courier, monospace; font-size: small;">')
outFile.writelines('<thead><tr><th style="width:7%"></th><th style="width:7%"></th><th style="width:15%"></th><th style="width:71%"></th></tr></thead>')
else:
outFile.writelines("Version\tUser\tDate\tCode\n")
lineCount=1
totalNum = len(lineVersions.data)
lastVersion = -1
for line in f:
if lineCount<totalNum:
currentVersion = lineVersions.data[lineCount-1]
else:
currentVersion = lineVersions.firstVersion
if htmlOutput:
if lastVersion == currentVersion:
border = "border-left:solid 1px black;border-right:solid 1px black"
versionText = "<td></td><td></td><td></td>"
else:
border = "border-left:solid 1px black;border-right:solid 1px black;border-top:solid 1px black"
lastVersion = currentVersion
versionData = historyData.data[currentVersion]
versionText = "<td>Version " + str(lastVersion) + "</td><td>User " + versionData[0] + "</td><td>Date " + versionData[1] + "</td>"
outFile.writelines("<tr style='white-space:nowrap;text-overflow: ellipsis;" + border + "'>" + versionText + "<td style='" + border + "'>" + line + "</td></tr>")
else:
try:
versionData = historyData.data[currentVersion]
outFile.writelines(str(currentVersion) + "\t" + versionData[0] + "\t" + versionData[1] + "\t" + line.expandtabs())
except KeyError, e:
print "Missing version: " + str(currentVersion)
lineCount += 1
if htmlOutput:
outFile.writelines('</table>')
outFile.writelines('</body></html>')
finally:
f.close()
outFile.close()
except Usage, err:
print >>sys.stderr, err.msg
return 2
if __name__ == "__main__":
sys.exit(main())
|


