mercurial/bundle2.py
changeset 24026 3daef83a1873
parent 23916 a3f7c781786b
child 24034 9881a1437799
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