Mercurial > public > mercurial-scm > hg
comparison mercurial/bundle2.py @ 31889:a02e773008f5
bundle2: move 'seek' and 'tell' methods off the unpackermixin class
These methods are unrelated to unpacking. They are used internally by the
'unbundlepart' class only. So me move them there as private methods.
In the same go, we clarify their internal role in the their docstring.
author | Pierre-Yves David <pierre-yves.david@ens-lyon.org> |
---|---|
date | Sun, 09 Apr 2017 19:09:07 +0200 |
parents | cd7aaf344d83 |
children | ad41739c6b2b |
comparison
equal
deleted
inserted
replaced
31888:1c398f7f4aa4 | 31889:a02e773008f5 |
---|---|
615 class unpackermixin(object): | 615 class unpackermixin(object): |
616 """A mixin to extract bytes and struct data from a stream""" | 616 """A mixin to extract bytes and struct data from a stream""" |
617 | 617 |
618 def __init__(self, fp): | 618 def __init__(self, fp): |
619 self._fp = fp | 619 self._fp = fp |
620 self._seekable = (util.safehasattr(fp, 'seek') and | |
621 util.safehasattr(fp, 'tell')) | |
622 | 620 |
623 def _unpack(self, format): | 621 def _unpack(self, format): |
624 """unpack this struct format from the stream | 622 """unpack this struct format from the stream |
625 | 623 |
626 This method is meant for internal usage by the bundle2 protocol only. | 624 This method is meant for internal usage by the bundle2 protocol only. |
638 They directly manipulate the low level stream including bundle2 level | 636 They directly manipulate the low level stream including bundle2 level |
639 instruction. | 637 instruction. |
640 | 638 |
641 Do not use it to implement higher-level logic or methods.""" | 639 Do not use it to implement higher-level logic or methods.""" |
642 return changegroup.readexactly(self._fp, size) | 640 return changegroup.readexactly(self._fp, size) |
643 | |
644 def seek(self, offset, whence=0): | |
645 """move the underlying file pointer""" | |
646 if self._seekable: | |
647 return self._fp.seek(offset, whence) | |
648 else: | |
649 raise NotImplementedError(_('File pointer is not seekable')) | |
650 | |
651 def tell(self): | |
652 """return the file offset, or None if file is not seekable""" | |
653 if self._seekable: | |
654 try: | |
655 return self._fp.tell() | |
656 except IOError as e: | |
657 if e.errno == errno.ESPIPE: | |
658 self._seekable = False | |
659 else: | |
660 raise | |
661 return None | |
662 | 641 |
663 def getunbundler(ui, fp, magicstring=None): | 642 def getunbundler(ui, fp, magicstring=None): |
664 """return a valid unbundler object for a given magicstring""" | 643 """return a valid unbundler object for a given magicstring""" |
665 if magicstring is None: | 644 if magicstring is None: |
666 magicstring = changegroup.readexactly(fp, 4) | 645 magicstring = changegroup.readexactly(fp, 4) |
1109 class unbundlepart(unpackermixin): | 1088 class unbundlepart(unpackermixin): |
1110 """a bundle part read from a bundle""" | 1089 """a bundle part read from a bundle""" |
1111 | 1090 |
1112 def __init__(self, ui, header, fp): | 1091 def __init__(self, ui, header, fp): |
1113 super(unbundlepart, self).__init__(fp) | 1092 super(unbundlepart, self).__init__(fp) |
1093 self._seekable = (util.safehasattr(fp, 'seek') and | |
1094 util.safehasattr(fp, 'tell')) | |
1114 self.ui = ui | 1095 self.ui = ui |
1115 # unbundle state attr | 1096 # unbundle state attr |
1116 self._headerdata = header | 1097 self._headerdata = header |
1117 self._headeroffset = 0 | 1098 self._headeroffset = 0 |
1118 self._initialized = False | 1099 self._initialized = False |
1156 | 1137 |
1157 def _payloadchunks(self, chunknum=0): | 1138 def _payloadchunks(self, chunknum=0): |
1158 '''seek to specified chunk and start yielding data''' | 1139 '''seek to specified chunk and start yielding data''' |
1159 if len(self._chunkindex) == 0: | 1140 if len(self._chunkindex) == 0: |
1160 assert chunknum == 0, 'Must start with chunk 0' | 1141 assert chunknum == 0, 'Must start with chunk 0' |
1161 self._chunkindex.append((0, super(unbundlepart, self).tell())) | 1142 self._chunkindex.append((0, self._tellfp())) |
1162 else: | 1143 else: |
1163 assert chunknum < len(self._chunkindex), \ | 1144 assert chunknum < len(self._chunkindex), \ |
1164 'Unknown chunk %d' % chunknum | 1145 'Unknown chunk %d' % chunknum |
1165 super(unbundlepart, self).seek(self._chunkindex[chunknum][1]) | 1146 self._seekfp(self._chunkindex[chunknum][1]) |
1166 | 1147 |
1167 pos = self._chunkindex[chunknum][0] | 1148 pos = self._chunkindex[chunknum][0] |
1168 payloadsize = self._unpack(_fpayloadsize)[0] | 1149 payloadsize = self._unpack(_fpayloadsize)[0] |
1169 indebug(self.ui, 'payload chunk size: %i' % payloadsize) | 1150 indebug(self.ui, 'payload chunk size: %i' % payloadsize) |
1170 while payloadsize: | 1151 while payloadsize: |
1178 else: | 1159 else: |
1179 result = self._readexact(payloadsize) | 1160 result = self._readexact(payloadsize) |
1180 chunknum += 1 | 1161 chunknum += 1 |
1181 pos += payloadsize | 1162 pos += payloadsize |
1182 if chunknum == len(self._chunkindex): | 1163 if chunknum == len(self._chunkindex): |
1183 self._chunkindex.append((pos, | 1164 self._chunkindex.append((pos, self._tellfp())) |
1184 super(unbundlepart, self).tell())) | |
1185 yield result | 1165 yield result |
1186 payloadsize = self._unpack(_fpayloadsize)[0] | 1166 payloadsize = self._unpack(_fpayloadsize)[0] |
1187 indebug(self.ui, 'payload chunk size: %i' % payloadsize) | 1167 indebug(self.ui, 'payload chunk size: %i' % payloadsize) |
1188 | 1168 |
1189 def _findchunk(self, pos): | 1169 def _findchunk(self, pos): |
1271 self._payloadstream = util.chunkbuffer(self._payloadchunks(chunk)) | 1251 self._payloadstream = util.chunkbuffer(self._payloadchunks(chunk)) |
1272 adjust = self.read(internaloffset) | 1252 adjust = self.read(internaloffset) |
1273 if len(adjust) != internaloffset: | 1253 if len(adjust) != internaloffset: |
1274 raise error.Abort(_('Seek failed\n')) | 1254 raise error.Abort(_('Seek failed\n')) |
1275 self._pos = newpos | 1255 self._pos = newpos |
1256 | |
1257 def _seekfp(self, offset, whence=0): | |
1258 """move the underlying file pointer | |
1259 | |
1260 This method is meant for internal usage by the bundle2 protocol only. | |
1261 They directly manipulate the low level stream including bundle2 level | |
1262 instruction. | |
1263 | |
1264 Do not use it to implement higher-level logic or methods.""" | |
1265 if self._seekable: | |
1266 return self._fp.seek(offset, whence) | |
1267 else: | |
1268 raise NotImplementedError(_('File pointer is not seekable')) | |
1269 | |
1270 def _tellfp(self): | |
1271 """return the file offset, or None if file is not seekable | |
1272 | |
1273 This method is meant for internal usage by the bundle2 protocol only. | |
1274 They directly manipulate the low level stream including bundle2 level | |
1275 instruction. | |
1276 | |
1277 Do not use it to implement higher-level logic or methods.""" | |
1278 if self._seekable: | |
1279 try: | |
1280 return self._fp.tell() | |
1281 except IOError as e: | |
1282 if e.errno == errno.ESPIPE: | |
1283 self._seekable = False | |
1284 else: | |
1285 raise | |
1286 return None | |
1276 | 1287 |
1277 # These are only the static capabilities. | 1288 # These are only the static capabilities. |
1278 # Check the 'getrepocaps' function for the rest. | 1289 # Check the 'getrepocaps' function for the rest. |
1279 capabilities = {'HG20': (), | 1290 capabilities = {'HG20': (), |
1280 'error': ('abort', 'unsupportedcontent', 'pushraced', | 1291 'error': ('abort', 'unsupportedcontent', 'pushraced', |