mercurial/pure/mpatch.py
author Jun Wu <quark@fb.com>
Mon, 04 Apr 2016 02:36:05 +0100
changeset 28769 222f482930c8
parent 28589 c4c7be9f0554
child 28782 f736f98e16ca
permissions -rw-r--r--
chg: make connect debug message less repetitive Before this patch, "connect to" debug message is printed repeatedly because a previous patch changed how the chg client decides the server is ready to be connected. This patch revises the places we print connect debug messages so they are less repetitive without losing useful information.
Ignore whitespace changes - Everywhere: Within whitespace: At end of lines:
7699
fac054f84600 pure Python implementation of mpatch.c
Martin Geisler <mg@daimi.au.dk>
parents:
diff changeset
     1
# mpatch.py - Python implementation of mpatch.c
fac054f84600 pure Python implementation of mpatch.c
Martin Geisler <mg@daimi.au.dk>
parents:
diff changeset
     2
#
fac054f84600 pure Python implementation of mpatch.c
Martin Geisler <mg@daimi.au.dk>
parents:
diff changeset
     3
# Copyright 2009 Matt Mackall <mpm@selenic.com> and others
fac054f84600 pure Python implementation of mpatch.c
Martin Geisler <mg@daimi.au.dk>
parents:
diff changeset
     4
#
8225
46293a0c7e9f updated license to be explicit about GPL version 2
Martin Geisler <mg@lazybytes.net>
parents: 7775
diff changeset
     5
# This software may be used and distributed according to the terms of the
10263
25e572394f5c Update license to GPLv2+
Matt Mackall <mpm@selenic.com>
parents: 8225
diff changeset
     6
# GNU General Public License version 2 or any later version.
7699
fac054f84600 pure Python implementation of mpatch.c
Martin Geisler <mg@daimi.au.dk>
parents:
diff changeset
     7
27337
9a17576103a4 mpatch: use absolute_import
Gregory Szorc <gregory.szorc@gmail.com>
parents: 16683
diff changeset
     8
from __future__ import absolute_import
9a17576103a4 mpatch: use absolute_import
Gregory Szorc <gregory.szorc@gmail.com>
parents: 16683
diff changeset
     9
9a17576103a4 mpatch: use absolute_import
Gregory Szorc <gregory.szorc@gmail.com>
parents: 16683
diff changeset
    10
import cStringIO
7775
5280c39778b6 pure/mpatch: use StringIO instead of mmap (issue1493)
Martin Geisler <mg@daimi.au.dk>
parents: 7699
diff changeset
    11
import struct
27337
9a17576103a4 mpatch: use absolute_import
Gregory Szorc <gregory.szorc@gmail.com>
parents: 16683
diff changeset
    12
9a17576103a4 mpatch: use absolute_import
Gregory Szorc <gregory.szorc@gmail.com>
parents: 16683
diff changeset
    13
StringIO = cStringIO.StringIO
7699
fac054f84600 pure Python implementation of mpatch.c
Martin Geisler <mg@daimi.au.dk>
parents:
diff changeset
    14
fac054f84600 pure Python implementation of mpatch.c
Martin Geisler <mg@daimi.au.dk>
parents:
diff changeset
    15
# This attempts to apply a series of patches in time proportional to
fac054f84600 pure Python implementation of mpatch.c
Martin Geisler <mg@daimi.au.dk>
parents:
diff changeset
    16
# the total size of the patches, rather than patches * len(text). This
fac054f84600 pure Python implementation of mpatch.c
Martin Geisler <mg@daimi.au.dk>
parents:
diff changeset
    17
# means rather than shuffling strings around, we shuffle around
fac054f84600 pure Python implementation of mpatch.c
Martin Geisler <mg@daimi.au.dk>
parents:
diff changeset
    18
# pointers to fragments with fragment lists.
fac054f84600 pure Python implementation of mpatch.c
Martin Geisler <mg@daimi.au.dk>
parents:
diff changeset
    19
#
fac054f84600 pure Python implementation of mpatch.c
Martin Geisler <mg@daimi.au.dk>
parents:
diff changeset
    20
# When the fragment lists get too long, we collapse them. To do this
fac054f84600 pure Python implementation of mpatch.c
Martin Geisler <mg@daimi.au.dk>
parents:
diff changeset
    21
# efficiently, we do all our operations inside a buffer created by
fac054f84600 pure Python implementation of mpatch.c
Martin Geisler <mg@daimi.au.dk>
parents:
diff changeset
    22
# mmap and simply use memmove. This avoids creating a bunch of large
fac054f84600 pure Python implementation of mpatch.c
Martin Geisler <mg@daimi.au.dk>
parents:
diff changeset
    23
# temporary string buffers.
fac054f84600 pure Python implementation of mpatch.c
Martin Geisler <mg@daimi.au.dk>
parents:
diff changeset
    24
28587
76d7cab13f04 mpatch: move pull() method to top level
Augie Fackler <augie@google.com>
parents: 27337
diff changeset
    25
def _pull(dst, src, l): # pull l bytes from src
76d7cab13f04 mpatch: move pull() method to top level
Augie Fackler <augie@google.com>
parents: 27337
diff changeset
    26
    while l:
76d7cab13f04 mpatch: move pull() method to top level
Augie Fackler <augie@google.com>
parents: 27337
diff changeset
    27
        f = src.pop()
76d7cab13f04 mpatch: move pull() method to top level
Augie Fackler <augie@google.com>
parents: 27337
diff changeset
    28
        if f[0] > l: # do we need to split?
76d7cab13f04 mpatch: move pull() method to top level
Augie Fackler <augie@google.com>
parents: 27337
diff changeset
    29
            src.append((f[0] - l, f[1] + l))
76d7cab13f04 mpatch: move pull() method to top level
Augie Fackler <augie@google.com>
parents: 27337
diff changeset
    30
            dst.append((l, f[1]))
76d7cab13f04 mpatch: move pull() method to top level
Augie Fackler <augie@google.com>
parents: 27337
diff changeset
    31
            return
76d7cab13f04 mpatch: move pull() method to top level
Augie Fackler <augie@google.com>
parents: 27337
diff changeset
    32
        dst.append(f)
76d7cab13f04 mpatch: move pull() method to top level
Augie Fackler <augie@google.com>
parents: 27337
diff changeset
    33
        l -= f[0]
76d7cab13f04 mpatch: move pull() method to top level
Augie Fackler <augie@google.com>
parents: 27337
diff changeset
    34
28588
6546afde350e mpatch: un-nest the move() method
Augie Fackler <augie@google.com>
parents: 28587
diff changeset
    35
def _move(m, dest, src, count):
6546afde350e mpatch: un-nest the move() method
Augie Fackler <augie@google.com>
parents: 28587
diff changeset
    36
    """move count bytes from src to dest
6546afde350e mpatch: un-nest the move() method
Augie Fackler <augie@google.com>
parents: 28587
diff changeset
    37
6546afde350e mpatch: un-nest the move() method
Augie Fackler <augie@google.com>
parents: 28587
diff changeset
    38
    The file pointer is left at the end of dest.
6546afde350e mpatch: un-nest the move() method
Augie Fackler <augie@google.com>
parents: 28587
diff changeset
    39
    """
6546afde350e mpatch: un-nest the move() method
Augie Fackler <augie@google.com>
parents: 28587
diff changeset
    40
    m.seek(src)
6546afde350e mpatch: un-nest the move() method
Augie Fackler <augie@google.com>
parents: 28587
diff changeset
    41
    buf = m.read(count)
6546afde350e mpatch: un-nest the move() method
Augie Fackler <augie@google.com>
parents: 28587
diff changeset
    42
    m.seek(dest)
6546afde350e mpatch: un-nest the move() method
Augie Fackler <augie@google.com>
parents: 28587
diff changeset
    43
    m.write(buf)
6546afde350e mpatch: un-nest the move() method
Augie Fackler <augie@google.com>
parents: 28587
diff changeset
    44
28589
c4c7be9f0554 mpatch: move collect() to module level
Augie Fackler <augie@google.com>
parents: 28588
diff changeset
    45
def _collect(m, buf, list):
c4c7be9f0554 mpatch: move collect() to module level
Augie Fackler <augie@google.com>
parents: 28588
diff changeset
    46
    start = buf
c4c7be9f0554 mpatch: move collect() to module level
Augie Fackler <augie@google.com>
parents: 28588
diff changeset
    47
    for l, p in reversed(list):
c4c7be9f0554 mpatch: move collect() to module level
Augie Fackler <augie@google.com>
parents: 28588
diff changeset
    48
        _move(m, buf, p, l)
c4c7be9f0554 mpatch: move collect() to module level
Augie Fackler <augie@google.com>
parents: 28588
diff changeset
    49
        buf += l
c4c7be9f0554 mpatch: move collect() to module level
Augie Fackler <augie@google.com>
parents: 28588
diff changeset
    50
    return (buf - start, start)
c4c7be9f0554 mpatch: move collect() to module level
Augie Fackler <augie@google.com>
parents: 28588
diff changeset
    51
7699
fac054f84600 pure Python implementation of mpatch.c
Martin Geisler <mg@daimi.au.dk>
parents:
diff changeset
    52
def patches(a, bins):
10282
08a0f04b56bd many, many trivial check-code fixups
Matt Mackall <mpm@selenic.com>
parents: 10263
diff changeset
    53
    if not bins:
08a0f04b56bd many, many trivial check-code fixups
Matt Mackall <mpm@selenic.com>
parents: 10263
diff changeset
    54
        return a
7699
fac054f84600 pure Python implementation of mpatch.c
Martin Geisler <mg@daimi.au.dk>
parents:
diff changeset
    55
fac054f84600 pure Python implementation of mpatch.c
Martin Geisler <mg@daimi.au.dk>
parents:
diff changeset
    56
    plens = [len(x) for x in bins]
fac054f84600 pure Python implementation of mpatch.c
Martin Geisler <mg@daimi.au.dk>
parents:
diff changeset
    57
    pl = sum(plens)
fac054f84600 pure Python implementation of mpatch.c
Martin Geisler <mg@daimi.au.dk>
parents:
diff changeset
    58
    bl = len(a) + pl
fac054f84600 pure Python implementation of mpatch.c
Martin Geisler <mg@daimi.au.dk>
parents:
diff changeset
    59
    tl = bl + bl + pl # enough for the patches and two working texts
fac054f84600 pure Python implementation of mpatch.c
Martin Geisler <mg@daimi.au.dk>
parents:
diff changeset
    60
    b1, b2 = 0, bl
fac054f84600 pure Python implementation of mpatch.c
Martin Geisler <mg@daimi.au.dk>
parents:
diff changeset
    61
10282
08a0f04b56bd many, many trivial check-code fixups
Matt Mackall <mpm@selenic.com>
parents: 10263
diff changeset
    62
    if not tl:
08a0f04b56bd many, many trivial check-code fixups
Matt Mackall <mpm@selenic.com>
parents: 10263
diff changeset
    63
        return a
7699
fac054f84600 pure Python implementation of mpatch.c
Martin Geisler <mg@daimi.au.dk>
parents:
diff changeset
    64
7775
5280c39778b6 pure/mpatch: use StringIO instead of mmap (issue1493)
Martin Geisler <mg@daimi.au.dk>
parents: 7699
diff changeset
    65
    m = StringIO()
7699
fac054f84600 pure Python implementation of mpatch.c
Martin Geisler <mg@daimi.au.dk>
parents:
diff changeset
    66
fac054f84600 pure Python implementation of mpatch.c
Martin Geisler <mg@daimi.au.dk>
parents:
diff changeset
    67
    # load our original text
fac054f84600 pure Python implementation of mpatch.c
Martin Geisler <mg@daimi.au.dk>
parents:
diff changeset
    68
    m.write(a)
fac054f84600 pure Python implementation of mpatch.c
Martin Geisler <mg@daimi.au.dk>
parents:
diff changeset
    69
    frags = [(len(a), b1)]
fac054f84600 pure Python implementation of mpatch.c
Martin Geisler <mg@daimi.au.dk>
parents:
diff changeset
    70
fac054f84600 pure Python implementation of mpatch.c
Martin Geisler <mg@daimi.au.dk>
parents:
diff changeset
    71
    # copy all the patches into our segment so we can memmove from them
fac054f84600 pure Python implementation of mpatch.c
Martin Geisler <mg@daimi.au.dk>
parents:
diff changeset
    72
    pos = b2 + bl
fac054f84600 pure Python implementation of mpatch.c
Martin Geisler <mg@daimi.au.dk>
parents:
diff changeset
    73
    m.seek(pos)
fac054f84600 pure Python implementation of mpatch.c
Martin Geisler <mg@daimi.au.dk>
parents:
diff changeset
    74
    for p in bins: m.write(p)
fac054f84600 pure Python implementation of mpatch.c
Martin Geisler <mg@daimi.au.dk>
parents:
diff changeset
    75
fac054f84600 pure Python implementation of mpatch.c
Martin Geisler <mg@daimi.au.dk>
parents:
diff changeset
    76
    for plen in plens:
fac054f84600 pure Python implementation of mpatch.c
Martin Geisler <mg@daimi.au.dk>
parents:
diff changeset
    77
        # if our list gets too long, execute it
fac054f84600 pure Python implementation of mpatch.c
Martin Geisler <mg@daimi.au.dk>
parents:
diff changeset
    78
        if len(frags) > 128:
fac054f84600 pure Python implementation of mpatch.c
Martin Geisler <mg@daimi.au.dk>
parents:
diff changeset
    79
            b2, b1 = b1, b2
28589
c4c7be9f0554 mpatch: move collect() to module level
Augie Fackler <augie@google.com>
parents: 28588
diff changeset
    80
            frags = [_collect(m, b1, frags)]
7699
fac054f84600 pure Python implementation of mpatch.c
Martin Geisler <mg@daimi.au.dk>
parents:
diff changeset
    81
fac054f84600 pure Python implementation of mpatch.c
Martin Geisler <mg@daimi.au.dk>
parents:
diff changeset
    82
        new = []
fac054f84600 pure Python implementation of mpatch.c
Martin Geisler <mg@daimi.au.dk>
parents:
diff changeset
    83
        end = pos + plen
fac054f84600 pure Python implementation of mpatch.c
Martin Geisler <mg@daimi.au.dk>
parents:
diff changeset
    84
        last = 0
fac054f84600 pure Python implementation of mpatch.c
Martin Geisler <mg@daimi.au.dk>
parents:
diff changeset
    85
        while pos < end:
7775
5280c39778b6 pure/mpatch: use StringIO instead of mmap (issue1493)
Martin Geisler <mg@daimi.au.dk>
parents: 7699
diff changeset
    86
            m.seek(pos)
5280c39778b6 pure/mpatch: use StringIO instead of mmap (issue1493)
Martin Geisler <mg@daimi.au.dk>
parents: 7699
diff changeset
    87
            p1, p2, l = struct.unpack(">lll", m.read(12))
28587
76d7cab13f04 mpatch: move pull() method to top level
Augie Fackler <augie@google.com>
parents: 27337
diff changeset
    88
            _pull(new, frags, p1 - last) # what didn't change
76d7cab13f04 mpatch: move pull() method to top level
Augie Fackler <augie@google.com>
parents: 27337
diff changeset
    89
            _pull([], frags, p2 - p1)    # what got deleted
16683
525fdb738975 cleanup: eradicate long lines
Brodie Rao <brodie@sf.io>
parents: 14065
diff changeset
    90
            new.append((l, pos + 12))   # what got added
7699
fac054f84600 pure Python implementation of mpatch.c
Martin Geisler <mg@daimi.au.dk>
parents:
diff changeset
    91
            pos += l + 12
fac054f84600 pure Python implementation of mpatch.c
Martin Geisler <mg@daimi.au.dk>
parents:
diff changeset
    92
            last = p2
16683
525fdb738975 cleanup: eradicate long lines
Brodie Rao <brodie@sf.io>
parents: 14065
diff changeset
    93
        frags.extend(reversed(new))     # what was left at the end
7699
fac054f84600 pure Python implementation of mpatch.c
Martin Geisler <mg@daimi.au.dk>
parents:
diff changeset
    94
28589
c4c7be9f0554 mpatch: move collect() to module level
Augie Fackler <augie@google.com>
parents: 28588
diff changeset
    95
    t = _collect(m, b2, frags)
7699
fac054f84600 pure Python implementation of mpatch.c
Martin Geisler <mg@daimi.au.dk>
parents:
diff changeset
    96
7775
5280c39778b6 pure/mpatch: use StringIO instead of mmap (issue1493)
Martin Geisler <mg@daimi.au.dk>
parents: 7699
diff changeset
    97
    m.seek(t[1])
5280c39778b6 pure/mpatch: use StringIO instead of mmap (issue1493)
Martin Geisler <mg@daimi.au.dk>
parents: 7699
diff changeset
    98
    return m.read(t[0])
7699
fac054f84600 pure Python implementation of mpatch.c
Martin Geisler <mg@daimi.au.dk>
parents:
diff changeset
    99
fac054f84600 pure Python implementation of mpatch.c
Martin Geisler <mg@daimi.au.dk>
parents:
diff changeset
   100
def patchedsize(orig, delta):
fac054f84600 pure Python implementation of mpatch.c
Martin Geisler <mg@daimi.au.dk>
parents:
diff changeset
   101
    outlen, last, bin = 0, 0, 0
fac054f84600 pure Python implementation of mpatch.c
Martin Geisler <mg@daimi.au.dk>
parents:
diff changeset
   102
    binend = len(delta)
fac054f84600 pure Python implementation of mpatch.c
Martin Geisler <mg@daimi.au.dk>
parents:
diff changeset
   103
    data = 12
fac054f84600 pure Python implementation of mpatch.c
Martin Geisler <mg@daimi.au.dk>
parents:
diff changeset
   104
fac054f84600 pure Python implementation of mpatch.c
Martin Geisler <mg@daimi.au.dk>
parents:
diff changeset
   105
    while data <= binend:
fac054f84600 pure Python implementation of mpatch.c
Martin Geisler <mg@daimi.au.dk>
parents:
diff changeset
   106
        decode = delta[bin:bin + 12]
fac054f84600 pure Python implementation of mpatch.c
Martin Geisler <mg@daimi.au.dk>
parents:
diff changeset
   107
        start, end, length = struct.unpack(">lll", decode)
fac054f84600 pure Python implementation of mpatch.c
Martin Geisler <mg@daimi.au.dk>
parents:
diff changeset
   108
        if start > end:
fac054f84600 pure Python implementation of mpatch.c
Martin Geisler <mg@daimi.au.dk>
parents:
diff changeset
   109
            break
fac054f84600 pure Python implementation of mpatch.c
Martin Geisler <mg@daimi.au.dk>
parents:
diff changeset
   110
        bin = data + length
fac054f84600 pure Python implementation of mpatch.c
Martin Geisler <mg@daimi.au.dk>
parents:
diff changeset
   111
        data = bin + 12
fac054f84600 pure Python implementation of mpatch.c
Martin Geisler <mg@daimi.au.dk>
parents:
diff changeset
   112
        outlen += start - last
fac054f84600 pure Python implementation of mpatch.c
Martin Geisler <mg@daimi.au.dk>
parents:
diff changeset
   113
        last = end
fac054f84600 pure Python implementation of mpatch.c
Martin Geisler <mg@daimi.au.dk>
parents:
diff changeset
   114
        outlen += length
fac054f84600 pure Python implementation of mpatch.c
Martin Geisler <mg@daimi.au.dk>
parents:
diff changeset
   115
fac054f84600 pure Python implementation of mpatch.c
Martin Geisler <mg@daimi.au.dk>
parents:
diff changeset
   116
    if bin != binend:
11122
2114e44b08f6 clean up remaining generic exceptions
Matt Mackall <mpm@selenic.com>
parents: 10282
diff changeset
   117
        raise ValueError("patch cannot be decoded")
7699
fac054f84600 pure Python implementation of mpatch.c
Martin Geisler <mg@daimi.au.dk>
parents:
diff changeset
   118
fac054f84600 pure Python implementation of mpatch.c
Martin Geisler <mg@daimi.au.dk>
parents:
diff changeset
   119
    outlen += orig - last
fac054f84600 pure Python implementation of mpatch.c
Martin Geisler <mg@daimi.au.dk>
parents:
diff changeset
   120
    return outlen