Guido van Rossum | 5f07b84 | 1995-04-26 22:57:11 +0000 | [diff] [blame^] | 1 | """Utilities to read and write CVS admin files (esp. CVS/Entries)""" |
| 2 | |
| 3 | import string |
| 4 | import os |
| 5 | import time |
| 6 | |
| 7 | |
| 8 | class Entry: |
| 9 | |
| 10 | """Class representing one (parsed) line from CVS/Entries""" |
| 11 | |
| 12 | def __init__(self, line): |
| 13 | words = string.splitfields(line, '/') |
| 14 | self.file = words[1] |
| 15 | self.rev = words[2] |
| 16 | dates = words[3] # ctime, mtime |
| 17 | if dates[:7] == 'Initial': |
| 18 | self.ctime = None |
| 19 | self.mtime = None |
| 20 | self.new = 1 |
| 21 | else: |
| 22 | self.ctime = unctime(dates[:24]) |
| 23 | self.mtime = unctime(dates[25:]) |
| 24 | self.new = 0 |
| 25 | self.extra = words[4] |
| 26 | self.sum = None |
| 27 | |
| 28 | def unparse(self): |
| 29 | if self.new: |
| 30 | dates = "Initial %s" % self.file |
| 31 | else: |
| 32 | dates = gmctime(self.ctime) + ' ' + gmctime(self.mtime) |
| 33 | return "/%s/%s/%s/%s/\n" % ( |
| 34 | self.file, |
| 35 | self.rev, |
| 36 | dates, |
| 37 | self.extra) |
| 38 | |
| 39 | def setsum(self, sum): |
| 40 | self.sum = sum |
| 41 | |
| 42 | def getsum(self): |
| 43 | return self.sum |
| 44 | |
| 45 | def sethexsum(self, hexsum): |
| 46 | self.setsum(unhexify(hexsum)) |
| 47 | |
| 48 | def gethexsum(self): |
| 49 | if self.sum: |
| 50 | return hexify(self.sum) |
| 51 | else: |
| 52 | return None |
| 53 | |
| 54 | |
| 55 | class CVS: |
| 56 | |
| 57 | """Class representing the contents of CVS/Entries (and CVS/Sums)""" |
| 58 | |
| 59 | def __init__(self): |
| 60 | self.readentries() |
| 61 | |
| 62 | def readentries(self): |
| 63 | self.entries = {} |
| 64 | f = self.cvsopen("Entries") |
| 65 | while 1: |
| 66 | line = f.readline() |
| 67 | if not line: break |
| 68 | e = Entry(line) |
| 69 | self.entries[e.file] = e |
| 70 | f.close() |
| 71 | |
| 72 | def readsums(self): |
| 73 | try: |
| 74 | f = self.cvsopen("Sums") |
| 75 | except IOError: |
| 76 | return |
| 77 | while 1: |
| 78 | line = f.readline() |
| 79 | if not line: break |
| 80 | words = string.split(line) |
| 81 | [file, rev, hexsum] = words |
| 82 | e = self.entries[file] |
| 83 | if e.rev == rev: |
| 84 | e.sethexsum(hexsum) |
| 85 | f.close() |
| 86 | |
| 87 | def writeentries(self): |
| 88 | f = self.cvsopen("Entries", 'w') |
| 89 | for file in self.keys(): |
| 90 | f.write(self.entries[file].unparse()) |
| 91 | f.close() |
| 92 | |
| 93 | def writesums(self): |
| 94 | if self.cvsexists("Sums"): |
| 95 | f = self.cvsopen("Sums", 'w') |
| 96 | else: |
| 97 | f = None |
| 98 | for file in self.keys(): |
| 99 | e = self.entries[file] |
| 100 | hexsum = e.gethexsum() |
| 101 | if hexsum: |
| 102 | if not f: |
| 103 | f = self.cvsopen("Sums", 'w') |
| 104 | f.write("%s %s %s\n" % (file, e.rev, hexsum)) |
| 105 | if f: |
| 106 | f.close() |
| 107 | |
| 108 | def keys(self): |
| 109 | keys = self.entries.keys() |
| 110 | keys.sort() |
| 111 | return keys |
| 112 | |
| 113 | def cvsexists(self, file): |
| 114 | file = os.path.join("CVS", file) |
| 115 | return os.path.exists(file) |
| 116 | |
| 117 | def cvsopen(self, file, mode = 'r'): |
| 118 | file = os.path.join("CVS", file) |
| 119 | if 'r' not in mode: |
| 120 | self.backup(file) |
| 121 | return open(file, mode) |
| 122 | |
| 123 | def backup(self, file): |
| 124 | if os.path.isfile(file): |
| 125 | bfile = file + '~' |
| 126 | os.rename(file, bfile) |
| 127 | |
| 128 | |
| 129 | hexify_format = '%02x' * 16 |
| 130 | def hexify(sum): |
| 131 | "Return a hex representation of a 16-byte string (e.g. an MD5 digest)" |
| 132 | return hexify_format % tuple(map(ord, sum)) |
| 133 | |
| 134 | def unhexify(hexsum): |
| 135 | "Return the original from a hexified string" |
| 136 | sum = '' |
| 137 | for i in range(0, len(hexsum), 2): |
| 138 | sum = sum + chr(string.atoi(hexsum[i:i+2], 16)) |
| 139 | return sum |
| 140 | |
| 141 | |
| 142 | unctime_monthmap = {} |
| 143 | def unctime(date): |
| 144 | if not unctime_monthmap: |
| 145 | months = ['Jan', 'Feb', 'Mar', 'Apr', 'May', 'Jun', |
| 146 | 'Jul', 'Aug', 'Sep', 'Oct', 'Nov', 'Dec'] |
| 147 | i = 0 |
| 148 | for m in months: |
| 149 | i = i+1 |
| 150 | unctime_monthmap[m] = i |
| 151 | words = string.split(date) # Day Mon DD HH:MM:SS YEAR |
| 152 | year = string.atoi(words[4]) |
| 153 | month = unctime_monthmap[words[1]] |
| 154 | day = string.atoi(words[2]) |
| 155 | [hh, mm, ss] = map(string.atoi, string.splitfields(words[3], ':')) |
| 156 | ss = ss - time.timezone |
| 157 | return time.mktime((year, month, day, hh, mm, ss, 0, 0, 0)) |
| 158 | |
| 159 | def gmctime(t): |
| 160 | return time.asctime(time.gmtime(t)) |
| 161 | |
| 162 | def test_unctime(): |
| 163 | now = int(time.time()) |
| 164 | t = time.gmtime(now) |
| 165 | at = time.asctime(t) |
| 166 | print 'GMT', now, at |
| 167 | print 'timezone', time.timezone |
| 168 | print 'local', time.ctime(now) |
| 169 | u = unctime(at) |
| 170 | print 'unctime()', u |
| 171 | gu = time.gmtime(u) |
| 172 | print '->', gu |
| 173 | print time.asctime(gu) |
| 174 | |
| 175 | def test(): |
| 176 | x = CVS() |
| 177 | keys = x.entries.keys() |
| 178 | keys.sort() |
| 179 | for file in keys: |
| 180 | e = x.entries[file] |
| 181 | print file, e.rev, gmctime(e.ctime), gmctime(e.mtime), e.extra, |
| 182 | print e.gethexsum() |
| 183 | |
| 184 | |
| 185 | if __name__ == "__main__": |
| 186 | test() |