bundle2.unbundlepart: implement seek()
authorEric Sumner <ericsumner@fb.com>
Wed, 14 Jan 2015 16:14:19 -0800
changeset 24037 f0b498cfc5c8
parent 24036 c7601086338a
child 24038 10d02cd18604
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.
mercurial/bundle2.py
--- a/mercurial/bundle2.py	Wed Jan 14 15:57:57 2015 -0800
+++ b/mercurial/bundle2.py	Wed Jan 14 16:14:19 2015 -0800
@@ -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': (),