Follow-up to r29036: Now that the "mergeinfo" transaction file is no
[svn.git] / tools / bdb / skel.py
blobd5b3ea959f138e0c25e9a406e3f1d51a1ae395a0
1 # Python parser for Subversion skels
3 import string, re
4 from types import *
6 def parse(s):
7 if s[0] != '(' and s[-1] != ')':
8 raise ValueError("Improperly bounded skel: '%s'" % s)
9 wholeskel = s
10 s = s[1:-1].lstrip()
11 prev_accums = []
12 accum = []
13 while 1:
14 if len(s) == 0:
15 return accum
16 if s[0] in string.digits:
17 split_tuple = s.split(' ',1)
18 count = int(split_tuple[0])
19 if len(split_tuple) > 1:
20 s = split_tuple[1]
21 else:
22 s = ""
23 accum.append(s[:count])
24 s = s[count:].lstrip()
25 continue
26 if s[0] in string.ascii_letters:
27 i = 0
28 while (s[i] not in ' ()'):
29 i += 1
30 if i == len(s):
31 break
32 accum.append(s[:i])
33 s = s[i:].lstrip()
34 continue
35 if s[0] == '(':
36 new_accum = []
37 accum.append(new_accum)
38 prev_accums.append(accum)
39 accum = new_accum
40 s = s[1:].lstrip()
41 continue
42 if s[0] == ')':
43 accum = prev_accums.pop()
44 s = s[1:].lstrip()
45 continue
46 if s[0] == ' ':
47 s = str.lstrip(' ')
48 continue
49 raise ValueError("Unexpected contents in skel: '%s'\n'%s'" % (s, wholeskel))
52 _ok_implicit = re.compile(r'^[A-Za-z]([^\(\) \r\n\t\f]*)$')
53 def unparse(struc):
54 accum = []
55 for ent in struc:
56 if type(ent) == StringType:
57 if len(ent) > 0 and _ok_implicit.match(ent[0]):
58 accum.append(ent)
59 else:
60 accum.append(str(len(ent)))
61 accum.append(ent)
62 else:
63 accum.append(unparse(ent))
64 return "("+" ".join(accum)+")"
67 class Rev:
68 def __init__(self, skelstring="(revision null)"):
69 sk = parse(skelstring)
70 if len(sk) == 2 and sk[0] == "revision" and type(sk[1]) == StringType:
71 self.txn = sk[1]
72 else:
73 raise ValueError("Invalid revision skel: %s" % skelstring)
75 def unparse(self):
76 return unparse( ("revision", self.txn) )
79 class Change:
80 def __init__(self, skelstring="(change null null null 0 0 )"):
81 sk = parse(skelstring)
82 if len(sk) == 6 and sk[0] == "change" and type(sk[1]) == type(sk[2]) \
83 == type(sk[3]) == type(sk[4]) == type(sk[5]) == StringType:
84 self.path = sk[1]
85 self.node = sk[2]
86 self.kind = sk[3]
87 self.textmod = sk[4]
88 self.propmod = sk[5]
89 else:
90 raise ValueError("Invalid change skel: %s" % skelstring)
92 def unparse(self):
93 return unparse( ("change", self.path, self.node, self.kind,
94 self.textmod and "1" or "", self.propmod and "1" or "") )
97 class Copy:
98 def __init__(self, skelstring="(copy null null null)"):
99 sk = parse(skelstring)
100 if len(sk) == 4 and sk[0] in ("copy", "soft-copy") and type(sk[1]) \
101 == type(sk[2]) == type(sk[3]) == StringType:
102 self.kind = sk[0]
103 self.srcpath = sk[1]
104 self.srctxn = sk[2]
105 self.destnode = sk[3]
106 else:
107 raise ValueError("Invalid copy skel: %s" % skelstring)
109 def unparse(self):
110 return unparse( (self.kind, self.srcpath, self.srctxn, self.destnode) )
113 class Node:
114 def __init__(self,skelstring="((file null null 1 0) null null)"):
115 sk = parse(skelstring)
116 if (len(sk) == 3 or (len(sk) == 4 and type(sk[3]) == StringType)) \
117 and type(sk[0]) == ListType and type(sk[1]) == StringType \
118 and type(sk[2]) == StringType and sk[0][0] in ("file", "dir") \
119 and type(sk[0][1]) == type(sk[0][2]) == type(sk[0][3]) == StringType:
120 self.kind = sk[0][0]
121 self.createpath = sk[0][1]
122 self.prednode = sk[0][2]
123 self.predcount = int(sk[0][3])
124 self.proprep = sk[1]
125 self.datarep = sk[2]
126 if len(sk) > 3:
127 self.editrep = sk[3]
128 else:
129 self.editrep = None
130 else:
131 raise ValueError("Invalid node skel: %s" % skelstring)
133 def unparse(self):
134 structure = [ (self.kind, self.createpath, self.prednode,
135 str(self.predcount)), self.proprep, self.datarep ]
136 if self.editrep:
137 structure.append(self.editrep)
138 return unparse( structure )
141 class Txn:
142 def __init__(self,skelstring="(transaction null null () ())"):
143 sk = parse(skelstring)
144 if len(sk) == 5 and sk[0] in ("transaction", "committed", "dead") \
145 and type(sk[1]) == type(sk[2]) == StringType \
146 and type(sk[3]) == type(sk[4]) == ListType and len(sk[3]) % 2 == 0:
147 self.kind = sk[0]
148 self.rootnode = sk[1]
149 if self.kind == "committed":
150 self.rev = sk[2]
151 else:
152 self.basenode = sk[2]
153 self.proplist = sk[3]
154 self.copies = sk[4]
155 else:
156 raise ValueError("Invalid transaction skel: %s" % skelstring)
158 def unparse(self):
159 if self.kind == "committed":
160 base_item = self.rev
161 else:
162 base_item = self.basenode
163 return unparse( (self.kind, self.rootnode, base_item, self.proplist,
164 self.copies) )
167 class SvnDiffWindow:
168 def __init__(self, skelstructure):
169 self.offset = skelstructure[0]
170 self.svndiffver = skelstructure[1][0][1]
171 self.str = skelstructure[1][0][2]
172 self.size = skelstructure[1][1]
173 self.vs_rep = skelstructure[1][2]
175 def _unparse_structure(self):
176 return ([ self.offset, [ [ 'svndiff', self.svndiffver, self.str ],
177 self.size, self.vs_rep ] ])
180 class Rep:
181 def __init__(self, skelstring="((fulltext 0 (md5 16 \0\0\0\0\0\0\0\0" \
182 "\0\0\0\0\0\0\0\0)) null)"):
183 sk = parse(skelstring)
184 if type(sk[0]) == ListType and len(sk[0]) == 3 \
185 and type(sk[0][1]) == StringType \
186 and type(sk[0][2]) == ListType and len(sk[0][2]) == 2 \
187 and type(sk[0][2][0]) == type(sk[0][2][1]) == StringType:
188 self.kind = sk[0][0]
189 self.txn = sk[0][1]
190 self.cksumtype = sk[0][2][0]
191 self.cksum = sk[0][2][1]
192 if len(sk) == 2 and sk[0][0] == "fulltext":
193 self.str = sk[1]
194 elif len(sk) >= 2 and sk[0][0] == "delta":
195 self.windows = map(SvnDiffWindow, sk[1:])
196 else:
197 raise ValueError("Invalid representation skel: %s" % repr(skelstring))
199 def unparse(self):
200 structure = [ [self.kind, self.txn, [self.cksumtype, self.cksum] ] ]
201 if self.kind == "fulltext":
202 structure.append(self.str)
203 elif self.kind == "delta":
204 for w in self.windows:
205 structure.append(w._unparse_structure())
206 return unparse( structure )