mercurial/cffi/mpatch.py
author Martin von Zweigbergk <martinvonz@google.com>
Sun, 21 Jul 2019 07:59:16 -0700
changeset 42669 36c692eb28d3
parent 33572 857876ebaed4
child 43076 2372284d9457
permissions -rw-r--r--
transaction: leave unfinished without crashing when not properly released I think the transaction.__del__ is there just as a last resort in case we (or an extension) forgot to release the transaction. When that happens, the repo can (or will on Python 3?) get deleted before the transaction. This leads to a crash in test-devel-warnings.t on Python 3 because we tried to access repo.dirstate, where repo was retried from a weak reference. There's not much we can do here, but let's at least avoid the crash. The user will have run `hg recover` afterwards regardless. Differential Revision: https://phab.mercurial-scm.org/D6664

# mpatch.py - CFFI implementation of mpatch.c
#
# Copyright 2016 Maciej Fijalkowski <fijall@gmail.com>
#
# This software may be used and distributed according to the terms of the
# GNU General Public License version 2 or any later version.

from __future__ import absolute_import

from ..pure.mpatch import *
from ..pure.mpatch import mpatchError  # silence pyflakes
from . import _mpatch

ffi = _mpatch.ffi
lib = _mpatch.lib

@ffi.def_extern()
def cffi_get_next_item(arg, pos):
    all, bins = ffi.from_handle(arg)
    container = ffi.new("struct mpatch_flist*[1]")
    to_pass = ffi.new("char[]", str(bins[pos]))
    all.append(to_pass)
    r = lib.mpatch_decode(to_pass, len(to_pass) - 1, container)
    if r < 0:
        return ffi.NULL
    return container[0]

def patches(text, bins):
    lgt = len(bins)
    all = []
    if not lgt:
        return text
    arg = (all, bins)
    patch = lib.mpatch_fold(ffi.new_handle(arg),
                            lib.cffi_get_next_item, 0, lgt)
    if not patch:
        raise mpatchError("cannot decode chunk")
    outlen = lib.mpatch_calcsize(len(text), patch)
    if outlen < 0:
        lib.mpatch_lfree(patch)
        raise mpatchError("inconsistency detected")
    buf = ffi.new("char[]", outlen)
    if lib.mpatch_apply(buf, text, len(text), patch) < 0:
        lib.mpatch_lfree(patch)
        raise mpatchError("error applying patches")
    res = ffi.buffer(buf, outlen)[:]
    lib.mpatch_lfree(patch)
    return res