H
Holger
I needed a tool for extracting patches from CVS based on the log
messages. I.e. we mark our fixes and features with a "Bugdb XYZ"
And sometimes you need to move a fix/feature to another branch or maybe
you just want to inspect exactly what changes were related to a
specific bugdb issue.
Now I've searched hi and low for this and I now it's out there
somewhere bleeding obvious - can't imagine I'm the first to have this
thought. I just haven't been able to find it...
Well, that was an excellent opportunity to get some python practice, so
below is my first shot at the problem.
Any feedback on what would be "the pythonic way" to do this would be
much appreciated!
Usage:
cd myproject
patchmaker <regxpr>
Ouput is a diff of involved files+revs
Thank you,
/Holger
----------------------------------------------------------------------------------------------------------------------
#!/usr/bin/env python
# Copyright 2006 Holger Lindeberg Bille
import sys, re, os
import popen2
workingfile = re.compile("^Working file: *(.*)$")
revision = re.compile("^revision *(.*)$")
fileend =
re.compile("^===========================================================================")
details = re.compile("^date: *")
entryend = re.compile("^----------------------------")
branches = re.compile("^branches *(.*)*")
class LogEntry:
def __init__(self):
self.rev = 0
self.prevrev = 0
self.text = []
def setName(self, name):
self.name = name
def read(self, file):
done = 0
for line in file:
regx = details.search(line)
if regx:
pass
else:
if entryend.search(line):
break
else:
if fileend.search(line):
done = 1
break
else:
self.text.append(line.strip())
return done
def GuessPrevRev(self):
pass
def filter(self, filter):
found = 0
for line in self.text:
if filter.search(line):
found = 1
break
return found
def calcPrevRev(self):
# todo: get this from CVS instead of guessing
self.rev = "1.1"
self.prevrev = "1.1"
ver = self.name.split(".")
n = int(ver.pop()) - 1
while len(ver) >= 1:
if n >= 1:
ver.append(str(n))
self.prevrev = ".".join(ver)
self.rev = self.name
break
else:
ver.pop() # throw this away
n = int(ver.pop())
def patchDump(self, file):
cmd = "cvs -q diff -u -b -r %s -r %s %s" % (self.prevrev,
self.rev, file)
# print cmd
outp, inp = popen2.popen2(cmd)
for line in outp:
print line,
outp.close()
inp.close()
def dump(self):
print "------------------------------------------"
print "rev = %s" % self.name
for line in self.text:
print line
class FileLog:
def __init__(self):
self.revs = []
def setName(self, name):
self.name = name
def read(self, file):
for line in file:
regx = revision.search(line)
if regx:
rev = LogEntry()
rev.setName(regx.group(1))
done = rev.read(file)
self.revs.append(rev)
if done:
break
def filter(self, filter):
found = 0
newrevs = []
for rev in self.revs:
if rev.filter(filter):
found = 1
newrevs.append(rev)
self.revs = newrevs
return found
def calcPrevRev(self):
for rev in self.revs:
rev.calcPrevRev()
def patchDump(self):
for rev in self.revs:
rev.patchDump(self.name)
def dump(self):
print "File = %s" % self.name
print "No. of revs %d" % len(self.revs)
for rev in self.revs:
rev.dump()
print "==============================================="
class LogDB:
def __init__(self):
self.flogs = []
def read(self):
outp, inp = popen2.popen2('cvs -q log -N')
found = 0
for line in outp:
regx = workingfile.search(line)
if regx:
flog = FileLog()
flog.setName(regx.group(1))
flog.read(outp)
self.flogs.append(flog)
outp.close()
inp.close()
def filter(self, filter):
newflogs = []
for flog in self.flogs:
if flog.filter(filter):
newflogs.append(flog)
self.flogs = newflogs
def calcPrevRev(self):
for flog in self.flogs:
flog.calcPrevRev()
def patchDump(self):
for flog in self.flogs:
flog.patchDump()
def dump(self):
print "Starting dump"
print "==============================================="
for flog in self.flogs:
flog.dump()
if len(sys.argv) != 2:
sys.stderr.write("wrong number of args")
sys.exit()
a = sys.argv[1]
a.encode('latin-1')
#print "arg = %s" % a
db = LogDB()
db.read()
#db.dump()
myfilter = re.compile(a)
db.filter(myfilter)
#db.dump()
db.calcPrevRev()
db.patchDump()
messages. I.e. we mark our fixes and features with a "Bugdb XYZ"
And sometimes you need to move a fix/feature to another branch or maybe
you just want to inspect exactly what changes were related to a
specific bugdb issue.
Now I've searched hi and low for this and I now it's out there
somewhere bleeding obvious - can't imagine I'm the first to have this
thought. I just haven't been able to find it...
Well, that was an excellent opportunity to get some python practice, so
below is my first shot at the problem.
Any feedback on what would be "the pythonic way" to do this would be
much appreciated!
Usage:
cd myproject
patchmaker <regxpr>
Ouput is a diff of involved files+revs
Thank you,
/Holger
----------------------------------------------------------------------------------------------------------------------
#!/usr/bin/env python
# Copyright 2006 Holger Lindeberg Bille
import sys, re, os
import popen2
workingfile = re.compile("^Working file: *(.*)$")
revision = re.compile("^revision *(.*)$")
fileend =
re.compile("^===========================================================================")
details = re.compile("^date: *")
entryend = re.compile("^----------------------------")
branches = re.compile("^branches *(.*)*")
class LogEntry:
def __init__(self):
self.rev = 0
self.prevrev = 0
self.text = []
def setName(self, name):
self.name = name
def read(self, file):
done = 0
for line in file:
regx = details.search(line)
if regx:
pass
else:
if entryend.search(line):
break
else:
if fileend.search(line):
done = 1
break
else:
self.text.append(line.strip())
return done
def GuessPrevRev(self):
pass
def filter(self, filter):
found = 0
for line in self.text:
if filter.search(line):
found = 1
break
return found
def calcPrevRev(self):
# todo: get this from CVS instead of guessing
self.rev = "1.1"
self.prevrev = "1.1"
ver = self.name.split(".")
n = int(ver.pop()) - 1
while len(ver) >= 1:
if n >= 1:
ver.append(str(n))
self.prevrev = ".".join(ver)
self.rev = self.name
break
else:
ver.pop() # throw this away
n = int(ver.pop())
def patchDump(self, file):
cmd = "cvs -q diff -u -b -r %s -r %s %s" % (self.prevrev,
self.rev, file)
# print cmd
outp, inp = popen2.popen2(cmd)
for line in outp:
print line,
outp.close()
inp.close()
def dump(self):
print "------------------------------------------"
print "rev = %s" % self.name
for line in self.text:
print line
class FileLog:
def __init__(self):
self.revs = []
def setName(self, name):
self.name = name
def read(self, file):
for line in file:
regx = revision.search(line)
if regx:
rev = LogEntry()
rev.setName(regx.group(1))
done = rev.read(file)
self.revs.append(rev)
if done:
break
def filter(self, filter):
found = 0
newrevs = []
for rev in self.revs:
if rev.filter(filter):
found = 1
newrevs.append(rev)
self.revs = newrevs
return found
def calcPrevRev(self):
for rev in self.revs:
rev.calcPrevRev()
def patchDump(self):
for rev in self.revs:
rev.patchDump(self.name)
def dump(self):
print "File = %s" % self.name
print "No. of revs %d" % len(self.revs)
for rev in self.revs:
rev.dump()
print "==============================================="
class LogDB:
def __init__(self):
self.flogs = []
def read(self):
outp, inp = popen2.popen2('cvs -q log -N')
found = 0
for line in outp:
regx = workingfile.search(line)
if regx:
flog = FileLog()
flog.setName(regx.group(1))
flog.read(outp)
self.flogs.append(flog)
outp.close()
inp.close()
def filter(self, filter):
newflogs = []
for flog in self.flogs:
if flog.filter(filter):
newflogs.append(flog)
self.flogs = newflogs
def calcPrevRev(self):
for flog in self.flogs:
flog.calcPrevRev()
def patchDump(self):
for flog in self.flogs:
flog.patchDump()
def dump(self):
print "Starting dump"
print "==============================================="
for flog in self.flogs:
flog.dump()
if len(sys.argv) != 2:
sys.stderr.write("wrong number of args")
sys.exit()
a = sys.argv[1]
a.encode('latin-1')
#print "arg = %s" % a
db = LogDB()
db.read()
#db.dump()
myfilter = re.compile(a)
db.filter(myfilter)
#db.dump()
db.calcPrevRev()
db.patchDump()