blob: 3e0a25543f317fd71dee963558063e9f2aab71ca [file] [log] [blame]
#
#
# Licensed to the Apache Software Foundation (ASF) under one
# or more contributor license agreements. See the NOTICE file
# distributed with this work for additional information
# regarding copyright ownership. The ASF licenses this file
# to you under the Apache License, Version 2.0 (the
# "License"); you may not use this file except in compliance
# with the License. You may obtain a copy of the License at
#
# http://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing,
# software distributed under the License is distributed on an
# "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
# KIND, either express or implied. See the License for the
# specific language governing permissions and limitations
# under the License.
#
#
# Python parser for Subversion skels
import string, re
def parse(s):
if s[0] != '(' and s[-1] != ')':
raise ValueError("Improperly bounded skel: '%s'" % s)
wholeskel = s
s = s[1:-1].lstrip()
prev_accums = []
accum = []
while True:
if len(s) == 0:
return accum
if s[0] in string.digits:
split_tuple = s.split(' ',1)
count = int(split_tuple[0])
if len(split_tuple) > 1:
s = split_tuple[1]
else:
s = ""
accum.append(s[:count])
s = s[count:].lstrip()
continue
if s[0] in string.ascii_letters:
i = 0
while (s[i] not in ' ()'):
i += 1
if i == len(s):
break
accum.append(s[:i])
s = s[i:].lstrip()
continue
if s[0] == '(':
new_accum = []
accum.append(new_accum)
prev_accums.append(accum)
accum = new_accum
s = s[1:].lstrip()
continue
if s[0] == ')':
accum = prev_accums.pop()
s = s[1:].lstrip()
continue
if s[0] == ' ':
s = str.lstrip(' ')
continue
raise ValueError("Unexpected contents in skel: '%s'\n'%s'" % (s, wholeskel))
_ok_implicit = re.compile(r'^[A-Za-z]([^\(\) \r\n\t\f]*)$')
def unparse(struc):
accum = []
for ent in struc:
if isinstance(ent, str):
if len(ent) > 0 and _ok_implicit.match(ent[0]):
accum.append(ent)
else:
accum.append(str(len(ent)))
accum.append(ent)
else:
accum.append(unparse(ent))
return "("+" ".join(accum)+")"
class Rev:
def __init__(self, skelstring="(revision null)"):
sk = parse(skelstring)
if len(sk) == 2 and sk[0] == "revision" and isinstance(sk[1], str):
self.txn = sk[1]
else:
raise ValueError("Invalid revision skel: %s" % skelstring)
def unparse(self):
return unparse( ("revision", self.txn) )
class Change:
def __init__(self, skelstring="(change null null null 0 0 )"):
sk = parse(skelstring)
if len(sk) == 6 and sk[0] == "change" and type(sk[1]) == type(sk[2]) \
== type(sk[3]) == type(sk[4]) == type(sk[5]) == str:
self.path = sk[1]
self.node = sk[2]
self.kind = sk[3]
self.textmod = sk[4]
self.propmod = sk[5]
else:
raise ValueError("Invalid change skel: %s" % skelstring)
def unparse(self):
return unparse( ("change", self.path, self.node, self.kind,
self.textmod and "1" or "", self.propmod and "1" or "") )
class Copy:
def __init__(self, skelstring="(copy null null null)"):
sk = parse(skelstring)
if len(sk) == 4 and sk[0] in ("copy", "soft-copy") and type(sk[1]) \
== type(sk[2]) == type(sk[3]) == str:
self.kind = sk[0]
self.srcpath = sk[1]
self.srctxn = sk[2]
self.destnode = sk[3]
else:
raise ValueError("Invalid copy skel: %s" % skelstring)
def unparse(self):
return unparse( (self.kind, self.srcpath, self.srctxn, self.destnode) )
class Node:
def __init__(self,skelstring="((file null null 1 0) null null)"):
sk = parse(skelstring)
if (len(sk) == 3 or (len(sk) == 4 and isinstance(sk[3], str))) \
and isinstance(sk[0], list) and isinstance(sk[1], str) \
and isinstance(sk[2], str) and sk[0][0] in ("file", "dir") \
and type(sk[0][1]) == type(sk[0][2]) == type(sk[0][3]) == str:
self.kind = sk[0][0]
self.createpath = sk[0][1]
self.prednode = sk[0][2]
self.predcount = int(sk[0][3])
self.proprep = sk[1]
self.datarep = sk[2]
if len(sk) > 3:
self.editrep = sk[3]
else:
self.editrep = None
else:
raise ValueError("Invalid node skel: %s" % skelstring)
def unparse(self):
structure = [ (self.kind, self.createpath, self.prednode,
str(self.predcount)), self.proprep, self.datarep ]
if self.editrep:
structure.append(self.editrep)
return unparse( structure )
class Txn:
def __init__(self,skelstring="(transaction null null () ())"):
sk = parse(skelstring)
if len(sk) == 5 and sk[0] in ("transaction", "committed", "dead") \
and type(sk[1]) == type(sk[2]) == str \
and type(sk[3]) == type(sk[4]) == list and len(sk[3]) % 2 == 0:
self.kind = sk[0]
self.rootnode = sk[1]
if self.kind == "committed":
self.rev = sk[2]
else:
self.basenode = sk[2]
self.proplist = sk[3]
self.copies = sk[4]
else:
raise ValueError("Invalid transaction skel: %s" % skelstring)
def unparse(self):
if self.kind == "committed":
base_item = self.rev
else:
base_item = self.basenode
return unparse( (self.kind, self.rootnode, base_item, self.proplist,
self.copies) )
class SvnDiffWindow:
def __init__(self, skelstructure):
self.offset = skelstructure[0]
self.svndiffver = skelstructure[1][0][1]
self.str = skelstructure[1][0][2]
self.size = skelstructure[1][1]
self.vs_rep = skelstructure[1][2]
def _unparse_structure(self):
return ([ self.offset, [ [ 'svndiff', self.svndiffver, self.str ],
self.size, self.vs_rep ] ])
class Rep:
def __init__(self, skelstring="((fulltext 0 (md5 16 \0\0\0\0\0\0\0\0" \
"\0\0\0\0\0\0\0\0)) null)"):
sk = parse(skelstring)
if isinstance(sk[0], list) and len(sk[0]) == 3 \
and isinstance(sk[0][1], str) \
and isinstance(sk[0][2], list) and len(sk[0][2]) == 2 \
and type(sk[0][2][0]) == type(sk[0][2][1]) == str:
self.kind = sk[0][0]
self.txn = sk[0][1]
self.cksumtype = sk[0][2][0]
self.cksum = sk[0][2][1]
if len(sk) == 2 and sk[0][0] == "fulltext":
self.str = sk[1]
elif len(sk) >= 2 and sk[0][0] == "delta":
self.windows = list(map(SvnDiffWindow, sk[1:]))
else:
raise ValueError("Invalid representation skel: %s" % repr(skelstring))
def unparse(self):
structure = [ [self.kind, self.txn, [self.cksumtype, self.cksum] ] ]
if self.kind == "fulltext":
structure.append(self.str)
elif self.kind == "delta":
for w in self.windows:
structure.append(w._unparse_structure())
return unparse( structure )