| """Utilities to read and write CVS admin files (esp. CVS/Entries)""" |
| |
| import string |
| import os |
| import time |
| |
| |
| class Entry: |
| |
| """Class representing one (parsed) line from CVS/Entries""" |
| |
| def __init__(self, line): |
| words = string.splitfields(line, '/') |
| self.file = words[1] |
| self.rev = words[2] |
| dates = words[3] # ctime, mtime |
| if len(dates) != 49 or dates[:7] == 'Initial': |
| self.ctime = None |
| self.mtime = None |
| self.new = dates[:7] == 'Initial' |
| else: |
| self.ctime = unctime(dates[:24]) |
| self.mtime = unctime(dates[25:]) |
| self.new = 0 |
| self.extra = words[4] |
| self.sum = None |
| |
| def unparse(self): |
| if self.new: |
| dates = "Initial %s" % self.file |
| else: |
| dates = gmctime(self.ctime) + ' ' + gmctime(self.mtime) |
| return "/%s/%s/%s/%s/\n" % ( |
| self.file, |
| self.rev, |
| dates, |
| self.extra) |
| |
| def setsum(self, sum): |
| self.sum = sum |
| |
| def getsum(self): |
| return self.sum |
| |
| def sethexsum(self, hexsum): |
| self.setsum(unhexify(hexsum)) |
| |
| def gethexsum(self): |
| if self.sum: |
| return hexify(self.sum) |
| else: |
| return None |
| |
| def dump(self): |
| keys = self.__dict__.keys() |
| keys.sort() |
| for key in keys: |
| print "%-15s: %s" % (key, `self.__dict__[key]`) |
| print '-'*45 |
| |
| |
| class CVS: |
| |
| """Class representing the contents of CVS/Entries (and CVS/Sums)""" |
| |
| def __init__(self): |
| self.readentries() |
| |
| def readentries(self): |
| self.entries = {} |
| f = self.cvsopen("Entries") |
| while 1: |
| line = f.readline() |
| if not line: break |
| e = Entry(line) |
| self.entries[e.file] = e |
| f.close() |
| |
| def readsums(self): |
| try: |
| f = self.cvsopen("Sums") |
| except IOError: |
| return |
| while 1: |
| line = f.readline() |
| if not line: break |
| words = string.split(line) |
| [file, rev, hexsum] = words |
| if not self.entries.has_key(file): |
| continue |
| e = self.entries[file] |
| if e.rev == rev: |
| e.sethexsum(hexsum) |
| f.close() |
| |
| def writeentries(self): |
| f = self.cvsopen("Entries", 'w') |
| for file in self.keys(): |
| f.write(self.entries[file].unparse()) |
| f.close() |
| |
| def writesums(self): |
| if self.cvsexists("Sums"): |
| f = self.cvsopen("Sums", 'w') |
| else: |
| f = None |
| for file in self.keys(): |
| e = self.entries[file] |
| hexsum = e.gethexsum() |
| if hexsum: |
| if not f: |
| f = self.cvsopen("Sums", 'w') |
| f.write("%s %s %s\n" % (file, e.rev, hexsum)) |
| if f: |
| f.close() |
| |
| def keys(self): |
| keys = self.entries.keys() |
| keys.sort() |
| return keys |
| |
| def cvsexists(self, file): |
| file = os.path.join("CVS", file) |
| return os.path.exists(file) |
| |
| def cvsopen(self, file, mode = 'r'): |
| file = os.path.join("CVS", file) |
| if 'r' not in mode: |
| self.backup(file) |
| return open(file, mode) |
| |
| def backup(self, file): |
| if os.path.isfile(file): |
| bfile = file + '~' |
| os.rename(file, bfile) |
| |
| |
| hexify_format = '%02x' * 16 |
| def hexify(sum): |
| "Return a hex representation of a 16-byte string (e.g. an MD5 digest)" |
| return hexify_format % tuple(map(ord, sum)) |
| |
| def unhexify(hexsum): |
| "Return the original from a hexified string" |
| sum = '' |
| for i in range(0, len(hexsum), 2): |
| sum = sum + chr(string.atoi(hexsum[i:i+2], 16)) |
| return sum |
| |
| |
| unctime_monthmap = {} |
| def unctime(date): |
| if not unctime_monthmap: |
| months = ['Jan', 'Feb', 'Mar', 'Apr', 'May', 'Jun', |
| 'Jul', 'Aug', 'Sep', 'Oct', 'Nov', 'Dec'] |
| i = 0 |
| for m in months: |
| i = i+1 |
| unctime_monthmap[m] = i |
| words = string.split(date) # Day Mon DD HH:MM:SS YEAR |
| year = string.atoi(words[4]) |
| month = unctime_monthmap[words[1]] |
| day = string.atoi(words[2]) |
| [hh, mm, ss] = map(string.atoi, string.splitfields(words[3], ':')) |
| ss = ss - time.timezone |
| return time.mktime((year, month, day, hh, mm, ss, 0, 0, 0)) |
| |
| def gmctime(t): |
| return time.asctime(time.gmtime(t)) |
| |
| def test_unctime(): |
| now = int(time.time()) |
| t = time.gmtime(now) |
| at = time.asctime(t) |
| print 'GMT', now, at |
| print 'timezone', time.timezone |
| print 'local', time.ctime(now) |
| u = unctime(at) |
| print 'unctime()', u |
| gu = time.gmtime(u) |
| print '->', gu |
| print time.asctime(gu) |
| |
| def test(): |
| x = CVS() |
| keys = x.entries.keys() |
| keys.sort() |
| for file in keys: |
| e = x.entries[file] |
| print file, e.rev, gmctime(e.ctime), gmctime(e.mtime), e.extra, |
| print e.gethexsum() |
| |
| |
| if __name__ == "__main__": |
| test() |