Mercurial > public > mercurial-scm > hg
comparison mercurial/bundle2.py @ 24026:3daef83a1873
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.
author | Eric Sumner <ericsumner@fb.com> |
---|---|
date | Wed, 14 Jan 2015 14:24:16 -0800 |
parents | a3f7c781786b |
children | 9881a1437799 |
comparison
equal
deleted
inserted
replaced
24025:bbb011f4eb32 | 24026:3daef83a1873 |
---|---|
143 channel usable. But none of the part read from an abort are processed. In the | 143 channel usable. But none of the part read from an abort are processed. In the |
144 future, dropping the stream may become an option for channel we do not care to | 144 future, dropping the stream may become an option for channel we do not care to |
145 preserve. | 145 preserve. |
146 """ | 146 """ |
147 | 147 |
148 import errno | |
148 import sys | 149 import sys |
149 import util | 150 import util |
150 import struct | 151 import struct |
151 import urllib | 152 import urllib |
152 import string | 153 import string |
482 class unpackermixin(object): | 483 class unpackermixin(object): |
483 """A mixin to extract bytes and struct data from a stream""" | 484 """A mixin to extract bytes and struct data from a stream""" |
484 | 485 |
485 def __init__(self, fp): | 486 def __init__(self, fp): |
486 self._fp = fp | 487 self._fp = fp |
488 self._seekable = (util.safehasattr(fp, 'seek') and | |
489 util.safehasattr(fp, 'tell')) | |
487 | 490 |
488 def _unpack(self, format): | 491 def _unpack(self, format): |
489 """unpack this struct format from the stream""" | 492 """unpack this struct format from the stream""" |
490 data = self._readexact(struct.calcsize(format)) | 493 data = self._readexact(struct.calcsize(format)) |
491 return _unpack(format, data) | 494 return _unpack(format, data) |
492 | 495 |
493 def _readexact(self, size): | 496 def _readexact(self, size): |
494 """read exactly <size> bytes from the stream""" | 497 """read exactly <size> bytes from the stream""" |
495 return changegroup.readexactly(self._fp, size) | 498 return changegroup.readexactly(self._fp, size) |
496 | 499 |
500 def seek(self, offset, whence): | |
501 """move the underlying file pointer""" | |
502 if self._seekable: | |
503 return self._fp.seek(offset, whence) | |
504 else: | |
505 raise NotImplementedError(_('File pointer is not seekable')) | |
506 | |
507 def tell(self): | |
508 """return the file offset, or None if file is not seekable""" | |
509 if self._seekable: | |
510 try: | |
511 return self._fp.tell() | |
512 except IOError, e: | |
513 if e.errno == errno.ESPIPE: | |
514 self._seekable = False | |
515 else: | |
516 raise | |
517 return None | |
518 | |
519 def close(self): | |
520 """close underlying file""" | |
521 if util.safehasattr(self._fp, 'close'): | |
522 return self._fp.close() | |
497 | 523 |
498 class unbundle20(unpackermixin): | 524 class unbundle20(unpackermixin): |
499 """interpret a bundle2 stream | 525 """interpret a bundle2 stream |
500 | 526 |
501 This class is fed with a binary stream and yields parts through its | 527 This class is fed with a binary stream and yields parts through its |