From da635c3c97fd93af408c795cdf27adf306604ff1 Mon Sep 17 00:00:00 2001 From: Sebastian Silva Date: Fri, 02 Dec 2011 19:53:30 +0000 Subject: pure python mercurial to run on XO1.75 --- diff --git a/websdk/mercurial/base85.py b/websdk/mercurial/base85.py new file mode 100644 index 0000000..930d251 --- /dev/null +++ b/websdk/mercurial/base85.py @@ -0,0 +1,74 @@ +# base85.py: pure python base85 codec +# +# Copyright (C) 2009 Brendan Cully +# +# This software may be used and distributed according to the terms of the +# GNU General Public License version 2 or any later version. + +import struct + +_b85chars = "0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZ" \ + "abcdefghijklmnopqrstuvwxyz!#$%&()*+-;<=>?@^_`{|}~" +_b85chars2 = [(a + b) for a in _b85chars for b in _b85chars] +_b85dec = {} + +def _mkb85dec(): + for i, c in enumerate(_b85chars): + _b85dec[c] = i + +def b85encode(text, pad=False): + """encode text in base85 format""" + l = len(text) + r = l % 4 + if r: + text += '\0' * (4 - r) + longs = len(text) >> 2 + words = struct.unpack('>%dL' % (longs), text) + + out = ''.join(_b85chars[(word // 52200625) % 85] + + _b85chars2[(word // 7225) % 7225] + + _b85chars2[word % 7225] + for word in words) + + if pad: + return out + + # Trim padding + olen = l % 4 + if olen: + olen += 1 + olen += l // 4 * 5 + return out[:olen] + +def b85decode(text): + """decode base85-encoded text""" + if not _b85dec: + _mkb85dec() + + l = len(text) + out = [] + for i in range(0, len(text), 5): + chunk = text[i:i + 5] + acc = 0 + for j, c in enumerate(chunk): + try: + acc = acc * 85 + _b85dec[c] + except KeyError: + raise TypeError('Bad base85 character at byte %d' % (i + j)) + if acc > 4294967295: + raise OverflowError('Base85 overflow in hunk starting at byte %d' % i) + out.append(acc) + + # Pad final chunk if necessary + cl = l % 5 + if cl: + acc *= 85 ** (5 - cl) + if cl > 1: + acc += 0xffffff >> (cl - 2) * 8 + out[-1] = acc + + out = struct.pack('>%dL' % (len(out)), *out) + if cl: + out = out[:-(5 - cl)] + + return out diff --git a/websdk/mercurial/bdiff.py b/websdk/mercurial/bdiff.py new file mode 100644 index 0000000..0e457d3 --- /dev/null +++ b/websdk/mercurial/bdiff.py @@ -0,0 +1,80 @@ +# bdiff.py - Python implementation of bdiff.c +# +# Copyright 2009 Matt Mackall and others +# +# This software may be used and distributed according to the terms of the +# GNU General Public License version 2 or any later version. + +import struct, difflib + +def splitnewlines(text): + '''like str.splitlines, but only split on newlines.''' + lines = [l + '\n' for l in text.split('\n')] + if lines: + if lines[-1] == '\n': + lines.pop() + else: + lines[-1] = lines[-1][:-1] + return lines + +def _normalizeblocks(a, b, blocks): + prev = None + r = [] + for curr in blocks: + if prev is None: + prev = curr + continue + shift = 0 + + a1, b1, l1 = prev + a1end = a1 + l1 + b1end = b1 + l1 + + a2, b2, l2 = curr + a2end = a2 + l2 + b2end = b2 + l2 + if a1end == a2: + while (a1end + shift < a2end and + a[a1end + shift] == b[b1end + shift]): + shift += 1 + elif b1end == b2: + while (b1end + shift < b2end and + a[a1end + shift] == b[b1end + shift]): + shift += 1 + r.append((a1, b1, l1 + shift)) + prev = a2 + shift, b2 + shift, l2 - shift + r.append(prev) + return r + +def bdiff(a, b): + a = str(a).splitlines(True) + b = str(b).splitlines(True) + + if not a: + s = "".join(b) + return s and (struct.pack(">lll", 0, 0, len(s)) + s) + + bin = [] + p = [0] + for i in a: p.append(p[-1] + len(i)) + + d = difflib.SequenceMatcher(None, a, b).get_matching_blocks() + d = _normalizeblocks(a, b, d) + la = 0 + lb = 0 + for am, bm, size in d: + s = "".join(b[lb:bm]) + if am > la or s: + bin.append(struct.pack(">lll", p[la], p[am], len(s)) + s) + la = am + size + lb = bm + size + + return "".join(bin) + +def blocks(a, b): + an = splitnewlines(a) + bn = splitnewlines(b) + d = difflib.SequenceMatcher(None, an, bn).get_matching_blocks() + d = _normalizeblocks(an, bn, d) + return [(i, i + n, j, j + n) for (i, j, n) in d] + diff --git a/websdk/mercurial/diffhelpers.py b/websdk/mercurial/diffhelpers.py new file mode 100644 index 0000000..681fa26 --- /dev/null +++ b/websdk/mercurial/diffhelpers.py @@ -0,0 +1,60 @@ +# diffhelpers.py - pure Python implementation of diffhelpers.c +# +# Copyright 2009 Matt Mackall and others +# +# This software may be used and distributed according to the terms of the +# GNU General Public License version 2 or any later version. + +def addlines(fp, hunk, lena, lenb, a, b): + while True: + todoa = lena - len(a) + todob = lenb - len(b) + num = max(todoa, todob) + if num == 0: + break + for i in xrange(num): + s = fp.readline() + c = s[0] + if s == "\\ No newline at end of file\n": + fix_newline(hunk, a, b) + continue + if c == "\n": + # Some patches may be missing the control char + # on empty lines. Supply a leading space. + s = " \n" + hunk.append(s) + if c == "+": + b.append(s[1:]) + elif c == "-": + a.append(s) + else: + b.append(s[1:]) + a.append(s) + return 0 + +def fix_newline(hunk, a, b): + l = hunk[-1] + # tolerate CRLF in last line + if l.endswith('\r\n'): + hline = l[:-2] + else: + hline = l[:-1] + c = hline[0] + + if c in " +": + b[-1] = hline[1:] + if c in " -": + a[-1] = hline + hunk[-1] = hline + return 0 + + +def testhunk(a, b, bstart): + alen = len(a) + blen = len(b) + if alen > blen - bstart: + return -1 + for i in xrange(alen): + if a[i][1:] != b[i + bstart]: + return -1 + return 0 diff --git a/websdk/mercurial/mpatch.py b/websdk/mercurial/mpatch.py new file mode 100644 index 0000000..760740d --- /dev/null +++ b/websdk/mercurial/mpatch.py @@ -0,0 +1,118 @@ +# mpatch.py - Python implementation of mpatch.c +# +# Copyright 2009 Matt Mackall and others +# +# This software may be used and distributed according to the terms of the +# GNU General Public License version 2 or any later version. + +import struct +try: + from cStringIO import StringIO +except ImportError: + from StringIO import StringIO + +# This attempts to apply a series of patches in time proportional to +# the total size of the patches, rather than patches * len(text). This +# means rather than shuffling strings around, we shuffle around +# pointers to fragments with fragment lists. +# +# When the fragment lists get too long, we collapse them. To do this +# efficiently, we do all our operations inside a buffer created by +# mmap and simply use memmove. This avoids creating a bunch of large +# temporary string buffers. + +def patches(a, bins): + if not bins: + return a + + plens = [len(x) for x in bins] + pl = sum(plens) + bl = len(a) + pl + tl = bl + bl + pl # enough for the patches and two working texts + b1, b2 = 0, bl + + if not tl: + return a + + m = StringIO() + def move(dest, src, count): + """move count bytes from src to dest + + The file pointer is left at the end of dest. + """ + m.seek(src) + buf = m.read(count) + m.seek(dest) + m.write(buf) + + # load our original text + m.write(a) + frags = [(len(a), b1)] + + # copy all the patches into our segment so we can memmove from them + pos = b2 + bl + m.seek(pos) + for p in bins: m.write(p) + + def pull(dst, src, l): # pull l bytes from src + while l: + f = src.pop() + if f[0] > l: # do we need to split? + src.append((f[0] - l, f[1] + l)) + dst.append((l, f[1])) + return + dst.append(f) + l -= f[0] + + def collect(buf, list): + start = buf + for l, p in reversed(list): + move(buf, p, l) + buf += l + return (buf - start, start) + + for plen in plens: + # if our list gets too long, execute it + if len(frags) > 128: + b2, b1 = b1, b2 + frags = [collect(b1, frags)] + + new = [] + end = pos + plen + last = 0 + while pos < end: + m.seek(pos) + p1, p2, l = struct.unpack(">lll", m.read(12)) + pull(new, frags, p1 - last) # what didn't change + pull([], frags, p2 - p1) # what got deleted + new.append((l, pos + 12)) # what got added + pos += l + 12 + last = p2 + frags.extend(reversed(new)) # what was left at the end + + t = collect(b2, frags) + + m.seek(t[1]) + return m.read(t[0]) + +def patchedsize(orig, delta): + outlen, last, bin = 0, 0, 0 + binend = len(delta) + data = 12 + + while data <= binend: + decode = delta[bin:bin + 12] + start, end, length = struct.unpack(">lll", decode) + if start > end: + break + bin = data + length + data = bin + 12 + outlen += start - last + last = end + outlen += length + + if bin != binend: + raise ValueError("patch cannot be decoded") + + outlen += orig - last + return outlen diff --git a/websdk/mercurial/osutil.py b/websdk/mercurial/osutil.py new file mode 100644 index 0000000..28bbbc5 --- /dev/null +++ b/websdk/mercurial/osutil.py @@ -0,0 +1,185 @@ +# osutil.py - pure Python version of osutil.c +# +# Copyright 2009 Matt Mackall and others +# +# This software may be used and distributed according to the terms of the +# GNU General Public License version 2 or any later version. + +import os +import stat as statmod + +def _mode_to_kind(mode): + if statmod.S_ISREG(mode): + return statmod.S_IFREG + if statmod.S_ISDIR(mode): + return statmod.S_IFDIR + if statmod.S_ISLNK(mode): + return statmod.S_IFLNK + if statmod.S_ISBLK(mode): + return statmod.S_IFBLK + if statmod.S_ISCHR(mode): + return statmod.S_IFCHR + if statmod.S_ISFIFO(mode): + return statmod.S_IFIFO + if statmod.S_ISSOCK(mode): + return statmod.S_IFSOCK + return mode + +def listdir(path, stat=False, skip=None): + '''listdir(path, stat=False) -> list_of_tuples + + Return a sorted list containing information about the entries + in the directory. + + If stat is True, each element is a 3-tuple: + + (name, type, stat object) + + Otherwise, each element is a 2-tuple: + + (name, type) + ''' + result = [] + prefix = path + if not prefix.endswith(os.sep): + prefix += os.sep + names = os.listdir(path) + names.sort() + for fn in names: + st = os.lstat(prefix + fn) + if fn == skip and statmod.S_ISDIR(st.st_mode): + return [] + if stat: + result.append((fn, _mode_to_kind(st.st_mode), st)) + else: + result.append((fn, _mode_to_kind(st.st_mode))) + return result + +if os.name != 'nt': + posixfile = open +else: + import ctypes, ctypes.util + + _kernel32 = ctypes.windll.kernel32 + + _DWORD = ctypes.c_ulong + _LPCSTR = _LPSTR = ctypes.c_char_p + _HANDLE = ctypes.c_void_p + + _INVALID_HANDLE_VALUE = _HANDLE(-1).value + + def _crtname(): + try: + # find_msvcrt was introduced in Python 2.6 + return ctypes.util.find_msvcrt() + except AttributeError: + return 'msvcr71.dll' # CPython 2.5 and 2.4 + + _crt = ctypes.PyDLL(_crtname()) + + # CreateFile + _FILE_SHARE_READ = 0x00000001 + _FILE_SHARE_WRITE = 0x00000002 + _FILE_SHARE_DELETE = 0x00000004 + + _CREATE_ALWAYS = 2 + _OPEN_EXISTING = 3 + _OPEN_ALWAYS = 4 + + _GENERIC_READ = 0x80000000 + _GENERIC_WRITE = 0x40000000 + + _FILE_ATTRIBUTE_NORMAL = 0x80 + + # _open_osfhandle + _O_RDONLY = 0x0000 + _O_RDWR = 0x0002 + _O_APPEND = 0x0008 + + _O_TEXT = 0x4000 + _O_BINARY = 0x8000 + + # types of parameters of C functions used (required by pypy) + + _kernel32.CreateFileA.argtypes = [_LPCSTR, _DWORD, _DWORD, ctypes.c_void_p, + _DWORD, _DWORD, _HANDLE] + _kernel32.CreateFileA.restype = _HANDLE + + _crt._open_osfhandle.argtypes = [_HANDLE, ctypes.c_int] + _crt._open_osfhandle.restype = ctypes.c_int + + def _raiseioerror(name): + err = ctypes.WinError() + raise IOError(err.errno, '%s: %s' % (name, err.strerror)) + + class posixfile(object): + '''a file object aiming for POSIX-like semantics + + CPython's open() returns a file that was opened *without* setting the + _FILE_SHARE_DELETE flag, which causes rename and unlink to abort. + This even happens if any hardlinked copy of the file is in open state. + We set _FILE_SHARE_DELETE here, so files opened with posixfile can be + renamed and deleted while they are held open. + Note that if a file opened with posixfile is unlinked, the file + remains but cannot be opened again or be recreated under the same name, + until all reading processes have closed the file.''' + + def __init__(self, name, mode='r', bufsize=-1): + if 'b' in mode: + flags = _O_BINARY + else: + flags = _O_TEXT + + m0 = mode[0] + if m0 == 'r' and not '+' in mode: + flags |= _O_RDONLY + access = _GENERIC_READ + else: + # work around http://support.microsoft.com/kb/899149 and + # set _O_RDWR for 'w' and 'a', even if mode has no '+' + flags |= _O_RDWR + access = _GENERIC_READ | _GENERIC_WRITE + + if m0 == 'r': + creation = _OPEN_EXISTING + elif m0 == 'w': + creation = _CREATE_ALWAYS + elif m0 == 'a': + creation = _OPEN_ALWAYS + flags |= _O_APPEND + else: + raise ValueError("invalid mode: %s" % mode) + + fh = _kernel32.CreateFileA(name, access, + _FILE_SHARE_READ | _FILE_SHARE_WRITE | _FILE_SHARE_DELETE, + None, creation, _FILE_ATTRIBUTE_NORMAL, None) + if fh == _INVALID_HANDLE_VALUE: + _raiseioerror(name) + + # for CPython we must use the same CRT as Python uses, + # or the os.fdopen call below will abort with + # "OSError: [Errno 9] Bad file descriptor" + fd = _crt._open_osfhandle(fh, flags) + if fd == -1: + _kernel32.CloseHandle(fh) + _raiseioerror(name) + + f = os.fdopen(fd, mode, bufsize) + # unfortunately, f.name is '' at this point -- so we store + # the name on this wrapper. We cannot just assign to f.name, + # because that attribute is read-only. + object.__setattr__(self, 'name', name) + object.__setattr__(self, '_file', f) + + def __iter__(self): + return self._file + + def __getattr__(self, name): + return getattr(self._file, name) + + def __setattr__(self, name, value): + '''mimics the read-only attributes of Python file objects + by raising 'TypeError: readonly attribute' if someone tries: + f = posixfile('foo.txt') + f.name = 'bla' ''' + return self._file.__setattr__(name, value) diff --git a/websdk/mercurial/parsers.py b/websdk/mercurial/parsers.py new file mode 100644 index 0000000..c4fe285 --- /dev/null +++ b/websdk/mercurial/parsers.py @@ -0,0 +1,89 @@ +# parsers.py - Python implementation of parsers.c +# +# Copyright 2009 Matt Mackall and others +# +# This software may be used and distributed according to the terms of the +# GNU General Public License version 2 or any later version. + +from mercurial.node import bin, nullid +from mercurial import util +import struct, zlib + +_pack = struct.pack +_unpack = struct.unpack +_compress = zlib.compress +_decompress = zlib.decompress +_sha = util.sha1 + +def parse_manifest(mfdict, fdict, lines): + for l in lines.splitlines(): + f, n = l.split('\0') + if len(n) > 40: + fdict[f] = n[40:] + mfdict[f] = bin(n[:40]) + else: + mfdict[f] = bin(n) + +def parse_index2(data, inline): + def gettype(q): + return int(q & 0xFFFF) + + def offset_type(offset, type): + return long(long(offset) << 16 | type) + + indexformatng = ">Qiiiiii20s12x" + + s = struct.calcsize(indexformatng) + index = [] + cache = None + off = 0 + + l = len(data) - s + append = index.append + if inline: + cache = (0, data) + while off <= l: + e = _unpack(indexformatng, data[off:off + s]) + append(e) + if e[1] < 0: + break + off += e[1] + s + else: + while off <= l: + e = _unpack(indexformatng, data[off:off + s]) + append(e) + off += s + + if off != len(data): + raise ValueError('corrupt index file') + + if index: + e = list(index[0]) + type = gettype(e[0]) + e[0] = offset_type(0, type) + index[0] = tuple(e) + + # add the magic null revision at -1 + index.append((0, 0, 0, -1, -1, -1, -1, nullid)) + + return index, cache + +def parse_dirstate(dmap, copymap, st): + parents = [st[:20], st[20: 40]] + # deref fields so they will be local in loop + format = ">cllll" + e_size = struct.calcsize(format) + pos1 = 40 + l = len(st) + + # the inner loop + while pos1 < l: + pos2 = pos1 + e_size + e = _unpack(">cllll", st[pos1:pos2]) # a literal here is faster + pos1 = pos2 + e[4] + f = st[pos2:pos1] + if '\0' in f: + f, c = f.split('\0') + copymap[f] = c + dmap[f] = e[:4] + return parents -- cgit v0.9.1