Patchwork bundle2.unpackermixin: control for underlying file descriptor

login
register
mail settings
Submitter Eric Sumner
Date Feb. 4, 2015, 12:30 a.m.
Message ID <6c20248d6cb42cbe4325.1423009824@waste.org>
Download mbox | patch
Permalink /patch/7644/
State Accepted
Commit 3daef83a18733a1f849b2d48878a7c9b410f0f35
Headers show

Comments

Eric Sumner - Feb. 4, 2015, 12:30 a.m.
# HG changeset patch
# User Eric Sumner <ericsumner@fb.com>
# Date 1421274256 28800
#      Wed Jan 14 14:24:16 2015 -0800
# Node ID 6c20248d6cb42cbe43255070666e764e898ce311
# Parent  bc75f8750cde0150357b25919c945ce418f0e503
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.
Matt Mackall - Feb. 4, 2015, 1:07 a.m.
On Tue, 2015-02-03 at 18:30 -0600, Eric Sumner wrote:
> # HG changeset patch
> # User Eric Sumner <ericsumner@fb.com>
> # Date 1421274256 28800
> #      Wed Jan 14 14:24:16 2015 -0800
> # Node ID 6c20248d6cb42cbe43255070666e764e898ce311
> # Parent  bc75f8750cde0150357b25919c945ce418f0e503
> bundle2.unpackermixin: control for underlying file descriptor

Queued for default, thanks.

Patch

diff --git a/mercurial/bundle2.py b/mercurial/bundle2.py
--- a/mercurial/bundle2.py
+++ b/mercurial/bundle2.py
@@ -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