bundle2.unpackermixin: control for underlying file descriptor
authorEric Sumner <ericsumner@fb.com>
Wed, 14 Jan 2015 14:24:16 -0800
changeset 24026 3daef83a1873
parent 24025 bbb011f4eb32
child 24027 f2a631c7387a
bundle2.unpackermixin: control for underlying file descriptor This patch adds seek(), tell(), and close() implementations for unpackermixin which forward to the file descriptor's implementation if possible. A future patch will use this to make bundle2.unbundlepart seekable, which will in turn make it usable as a file descriptor for bundlerepo.
mercurial/bundle2.py
--- a/mercurial/bundle2.py	Fri Jan 16 15:34:03 2015 -0800
+++ b/mercurial/bundle2.py	Wed Jan 14 14:24:16 2015 -0800
@@ -145,6 +145,7 @@
 preserve.
 """
 
+import errno
 import sys
 import util
 import struct
@@ -484,6 +485,8 @@
 
     def __init__(self, fp):
         self._fp = fp
+        self._seekable = (util.safehasattr(fp, 'seek') and
+                          util.safehasattr(fp, 'tell'))
 
     def _unpack(self, format):
         """unpack this struct format from the stream"""
@@ -494,6 +497,29 @@
         """read exactly <size> bytes from the stream"""
         return changegroup.readexactly(self._fp, size)
 
+    def seek(self, offset, whence):
+        """move the underlying file pointer"""
+        if self._seekable:
+            return self._fp.seek(offset, whence)
+        else:
+            raise NotImplementedError(_('File pointer is not seekable'))
+
+    def tell(self):
+        """return the file offset, or None if file is not seekable"""
+        if self._seekable:
+            try:
+                return self._fp.tell()
+            except IOError, e:
+                if e.errno == errno.ESPIPE:
+                    self._seekable = False
+                else:
+                    raise
+        return None
+
+    def close(self):
+        """close underlying file"""
+        if util.safehasattr(self._fp, 'close'):
+            return self._fp.close()
 
 class unbundle20(unpackermixin):
     """interpret a bundle2 stream