Patchwork [4,of,4] bundle2.unbundlepart: implement seek()

login
register
mail settings
Submitter Eric Sumner
Date Feb. 4, 2015, 7:29 p.m.
Message ID <f0bc1ba2a91c628e1f0d.1423078178@waste.org>
Download mbox | patch
Permalink /patch/7671/
State Accepted
Commit f0b498cfc5c839b07ca8832d57ef8f3a473db56a
Headers show

Comments

Eric Sumner - Feb. 4, 2015, 7:29 p.m.
# HG changeset patch
# User Eric Sumner <ericsumner@fb.com>
# Date 1421280859 28800
#      Wed Jan 14 16:14:19 2015 -0800
# Node ID f0bc1ba2a91c628e1f0d4abe7b037e35668a26a1
# Parent  34be4c79b05ea59a75e2e60f25839971c120126f
bundle2.unbundlepart: implement seek()

This implements a seek() method for unbundlepart.  This allows on-disk bundle2
parts to behave enough like files for bundlerepo to handle them.  A future
patch will add support for bundlerepo to read the bundle2 files that are
written when the experimental.strip-bundle2-version config option is used.
Matt Mackall - Feb. 4, 2015, 9:54 p.m.
On Wed, 2015-02-04 at 13:29 -0600, Eric Sumner wrote:
> # HG changeset patch
> # User Eric Sumner <ericsumner@fb.com>
> # Date 1421280859 28800
> #      Wed Jan 14 16:14:19 2015 -0800
> # Node ID f0bc1ba2a91c628e1f0d4abe7b037e35668a26a1
> # Parent  34be4c79b05ea59a75e2e60f25839971c120126f
> bundle2.unbundlepart: implement seek()

These are queued for default, thanks.

Patch

diff --git a/mercurial/bundle2.py b/mercurial/bundle2.py
--- a/mercurial/bundle2.py
+++ b/mercurial/bundle2.py
@@ -886,6 +886,15 @@ 
             payloadsize = self._unpack(_fpayloadsize)[0]
             self.ui.debug('payload chunk size: %i\n' % payloadsize)
 
+    def _findchunk(self, pos):
+        '''for a given payload position, return a chunk number and offset'''
+        for chunk, (ppos, fpos) in enumerate(self._chunkindex):
+            if ppos == pos:
+                return chunk, 0
+            elif ppos > pos:
+                return chunk - 1, pos - self._chunkindex[chunk - 1][0]
+        raise ValueError('Unknown chunk')
+
     def _readheader(self):
         """read the header and setup the object"""
         typesize = self._unpackheader(_fparttypesize)[0]
@@ -937,6 +946,31 @@ 
     def tell(self):
         return self._pos
 
+    def seek(self, offset, whence=0):
+        if whence == 0:
+            newpos = offset
+        elif whence == 1:
+            newpos = self._pos + offset
+        elif whence == 2:
+            if not self.consumed:
+                self.read()
+            newpos = self._chunkindex[-1][0] - offset
+        else:
+            raise ValueError('Unknown whence value: %r' % (whence,))
+
+        if newpos > self._chunkindex[-1][0] and not self.consumed:
+            self.read()
+        if not 0 <= newpos <= self._chunkindex[-1][0]:
+            raise ValueError('Offset out of range')
+
+        if self._pos != newpos:
+            chunk, internaloffset = self._findchunk(newpos)
+            self._payloadstream = util.chunkbuffer(self._payloadchunks(chunk))
+            adjust = self.read(internaloffset)
+            if len(adjust) != internaloffset:
+                raise util.Abort(_('Seek failed\n'))
+            self._pos = newpos
+
 capabilities = {'HG2Y': (),
                 'b2x:listkeys': (),
                 'b2x:pushkey': (),