[PATCH] patch: add support for git delta hunks

Augie Fackler raf at durin42.com
Wed Nov 27 08:53:29 CST 2013


On Tue, Nov 26, 2013 at 12:17:55PM +0100, Nicolas Vigier wrote:
> # HG changeset patch
> # User Nicolas Vigier <boklm at mars-attacks.org>
> # Date 1385424419 -3600
> # Node ID f8cb3b94a9f68dcca3d9545b14a7ecc21e8ba156
> # Parent  1c46b18b0e1c47fa4cecf21b78c083a54ae9903f
> patch: add support for git delta hunks
>
> When creating patches modifying binary files using "git format-patch",
> git creates 'literal' and 'delta' hunks. Mercurial currently supports
> 'literal' hunks only, which makes it impossible to import patches with
> 'delta' hunks.
>
> This changeset adds support for 'delta' hunks. It is a reimplementation
> of patch-delta.c from git :
> http://git.kernel.org/cgit/git/git.git/tree/patch-delta.c
>
> diff -r 1c46b18b0e1c -r f8cb3b94a9f6 mercurial/patch.py
> --- a/mercurial/patch.py	Fri Nov 22 17:26:58 2013 -0600
> +++ b/mercurial/patch.py	Tue Nov 26 01:06:59 2013 +0100
> @@ -721,8 +721,9 @@
>              if self.remove:
>                  self.backend.unlink(self.fname)
>              else:
> -                self.lines[:] = h.new()
> -                self.offset += len(h.new())
> +                l = h.new(self.lines)
> +                self.lines[:] = l
> +                self.offset += len(l)
>                  self.dirty = True
>              return 0
>
> @@ -1016,9 +1017,10 @@
>          return old, oldstart, new, newstart
>
>  class binhunk(object):
> -    'A binary patch file. Only understands literals so far.'
> +    'A binary patch file.'
>      def __init__(self, lr, fname):
>          self.text = None
> +        self.delta = False
>          self.hunk = ['GIT binary patch\n']
>          self._fname = fname
>          self._read(lr)
> @@ -1026,8 +1028,63 @@
>      def complete(self):
>          return self.text is not None
>
> -    def new(self):
> -        return [self.text]
> +    def new(self, lines):
> +        def deltahead(binchunk):
> +            i = 0
> +            for c in binchunk:
> +                i += 1
> +                if not (ord(c) & 0x80):
> +                    return i
> +            return i
> +        def applydelta(binchunk, data):

I may be missing something, but it look slike this nested function
could be a module-level function and then be a little more readable?

> +            out = ""
> +            s = deltahead(binchunk)
> +            binchunk = binchunk[s:]
> +            s = deltahead(binchunk)
> +            binchunk = binchunk[s:]
> +            i = 0
> +            while i < len(binchunk):
> +                cmd = ord(binchunk[i])
> +                i += 1
> +                if (cmd & 0x80):
> +                    offset = 0
> +                    size = 0
> +                    if (cmd & 0x01):
> +                        offset = ord(binchunk[i])
> +                        i += 1
> +                    if (cmd & 0x02):
> +                        offset |= ord(binchunk[i]) << 8
> +                        i += 1
> +                    if (cmd & 0x04):
> +                        offset |= ord(binchunk[i]) << 16
> +                        i += 1
> +                    if (cmd & 0x08):
> +                        offset |= ord(binchunk[i]) << 24
> +                        i += 1
> +                    if (cmd & 0x10):
> +                        size = ord(binchunk[i])
> +                        i += 1
> +                    if (cmd & 0x20):
> +                        size |= ord(binchunk[i]) << 8
> +                        i += 1
> +                    if (cmd & 0x40):
> +                        size |= ord(binchunk[i]) << 16
> +                        i += 1
> +                    if size == 0:
> +                        size = 0x10000
> +                    offset_end = offset + size
> +                    out += data[offset:offset_end]
> +                elif cmd != 0:
> +                    offset_end = i + cmd
> +                    out += binchunk[i:offset_end]
> +                    i += cmd
> +                else:
> +                    raise PatchError(_('unexpected delta opcode 0'))
> +            return out
> +        if self.delta:
> +            return [applydelta(self.text, ''.join(lines))]
> +        else:
> +            return [self.text]
>
>      def _read(self, lr):
>          def getline(lr, hunk):
> @@ -1035,14 +1092,19 @@
>              hunk.append(l)
>              return l.rstrip('\r\n')
>
> +        size = 0
>          while True:
>              line = getline(lr, self.hunk)
>              if not line:
>                  raise PatchError(_('could not extract "%s" binary data')
>                                   % self._fname)
>              if line.startswith('literal '):
> +                size = int(line[8:].rstrip())
>                  break
> -        size = int(line[8:].rstrip())
> +            if line.startswith('delta '):
> +                size = int(line[6:].rstrip())
> +                self.delta = True
> +                break
>          dec = []
>          line = getline(lr, self.hunk)
>          while len(line) > 1:
> _______________________________________________
> Mercurial-devel mailing list
> Mercurial-devel at selenic.com
> http://selenic.com/mailman/listinfo/mercurial-devel


More information about the Mercurial-devel mailing list