174 _parttypeforbidden = re.compile('[^a-zA-Z0-9_:-]') |
174 _parttypeforbidden = re.compile('[^a-zA-Z0-9_:-]') |
175 |
175 |
176 def outdebug(ui, message): |
176 def outdebug(ui, message): |
177 """debug regarding output stream (bundling)""" |
177 """debug regarding output stream (bundling)""" |
178 ui.debug('bundle2-output: %s\n' % message) |
178 ui.debug('bundle2-output: %s\n' % message) |
|
179 |
|
180 def indebug(ui, message): |
|
181 """debug on input stream (unbundling)""" |
|
182 ui.debug(message) |
179 |
183 |
180 def validateparttype(parttype): |
184 def validateparttype(parttype): |
181 """raise ValueError if a parttype contains invalid character""" |
185 """raise ValueError if a parttype contains invalid character""" |
182 if _parttypeforbidden.search(parttype): |
186 if _parttypeforbidden.search(parttype): |
183 raise ValueError(parttype) |
187 raise ValueError(parttype) |
344 try: |
348 try: |
345 try: |
349 try: |
346 handler = parthandlermapping.get(part.type) |
350 handler = parthandlermapping.get(part.type) |
347 if handler is None: |
351 if handler is None: |
348 raise error.UnsupportedPartError(parttype=part.type) |
352 raise error.UnsupportedPartError(parttype=part.type) |
349 op.ui.debug('found a handler for part %r\n' % part.type) |
353 indebug(op.ui, 'found a handler for part %r\n' % part.type) |
350 unknownparams = part.mandatorykeys - handler.params |
354 unknownparams = part.mandatorykeys - handler.params |
351 if unknownparams: |
355 if unknownparams: |
352 unknownparams = list(unknownparams) |
356 unknownparams = list(unknownparams) |
353 unknownparams.sort() |
357 unknownparams.sort() |
354 raise error.UnsupportedPartError(parttype=part.type, |
358 raise error.UnsupportedPartError(parttype=part.type, |
355 params=unknownparams) |
359 params=unknownparams) |
356 except error.UnsupportedPartError, exc: |
360 except error.UnsupportedPartError, exc: |
357 if part.mandatory: # mandatory parts |
361 if part.mandatory: # mandatory parts |
358 raise |
362 raise |
359 op.ui.debug('ignoring unsupported advisory part %s\n' % exc) |
363 indebug(op.ui, 'ignoring unsupported advisory part %s\n' % exc) |
360 return # skip to part processing |
364 return # skip to part processing |
361 |
365 |
362 # handler is called outside the above try block so that we don't |
366 # handler is called outside the above try block so that we don't |
363 # risk catching KeyErrors from anything other than the |
367 # risk catching KeyErrors from anything other than the |
364 # parthandlermapping lookup (any KeyError raised by handler() |
368 # parthandlermapping lookup (any KeyError raised by handler() |
557 raise util.Abort(_('not a Mercurial bundle')) |
561 raise util.Abort(_('not a Mercurial bundle')) |
558 unbundlerclass = formatmap.get(version) |
562 unbundlerclass = formatmap.get(version) |
559 if unbundlerclass is None: |
563 if unbundlerclass is None: |
560 raise util.Abort(_('unknown bundle version %s') % version) |
564 raise util.Abort(_('unknown bundle version %s') % version) |
561 unbundler = unbundlerclass(ui, fp) |
565 unbundler = unbundlerclass(ui, fp) |
562 ui.debug('start processing of %s stream\n' % header) |
566 indebug(ui, 'start processing of %s stream\n' % header) |
563 return unbundler |
567 return unbundler |
564 |
568 |
565 class unbundle20(unpackermixin): |
569 class unbundle20(unpackermixin): |
566 """interpret a bundle2 stream |
570 """interpret a bundle2 stream |
567 |
571 |
574 super(unbundle20, self).__init__(fp) |
578 super(unbundle20, self).__init__(fp) |
575 |
579 |
576 @util.propertycache |
580 @util.propertycache |
577 def params(self): |
581 def params(self): |
578 """dictionary of stream level parameters""" |
582 """dictionary of stream level parameters""" |
579 self.ui.debug('reading bundle2 stream parameters\n') |
583 indebug(self.ui, 'reading bundle2 stream parameters\n') |
580 params = {} |
584 params = {} |
581 paramssize = self._unpack(_fstreamparamsize)[0] |
585 paramssize = self._unpack(_fstreamparamsize)[0] |
582 if paramssize < 0: |
586 if paramssize < 0: |
583 raise error.BundleValueError('negative bundle param size: %i' |
587 raise error.BundleValueError('negative bundle param size: %i' |
584 % paramssize) |
588 % paramssize) |
607 if name[0] not in string.letters: |
611 if name[0] not in string.letters: |
608 raise ValueError('non letter first character: %r' % name) |
612 raise ValueError('non letter first character: %r' % name) |
609 # Some logic will be later added here to try to process the option for |
613 # Some logic will be later added here to try to process the option for |
610 # a dict of known parameter. |
614 # a dict of known parameter. |
611 if name[0].islower(): |
615 if name[0].islower(): |
612 self.ui.debug("ignoring unknown parameter %r\n" % name) |
616 indebug(self.ui, "ignoring unknown parameter %r\n" % name) |
613 else: |
617 else: |
614 raise error.UnsupportedPartError(params=(name,)) |
618 raise error.UnsupportedPartError(params=(name,)) |
615 |
619 |
616 |
620 |
617 def iterparts(self): |
621 def iterparts(self): |
618 """yield all parts contained in the stream""" |
622 """yield all parts contained in the stream""" |
619 # make sure param have been loaded |
623 # make sure param have been loaded |
620 self.params |
624 self.params |
621 self.ui.debug('start extraction of bundle2 parts\n') |
625 indebug(self.ui, 'start extraction of bundle2 parts\n') |
622 headerblock = self._readpartheader() |
626 headerblock = self._readpartheader() |
623 while headerblock is not None: |
627 while headerblock is not None: |
624 part = unbundlepart(self.ui, headerblock, self._fp) |
628 part = unbundlepart(self.ui, headerblock, self._fp) |
625 yield part |
629 yield part |
626 part.seek(0, 2) |
630 part.seek(0, 2) |
627 headerblock = self._readpartheader() |
631 headerblock = self._readpartheader() |
628 self.ui.debug('end of bundle2 stream\n') |
632 indebug(self.ui, 'end of bundle2 stream\n') |
629 |
633 |
630 def _readpartheader(self): |
634 def _readpartheader(self): |
631 """reads a part header size and return the bytes blob |
635 """reads a part header size and return the bytes blob |
632 |
636 |
633 returns None if empty""" |
637 returns None if empty""" |
634 headersize = self._unpack(_fpartheadersize)[0] |
638 headersize = self._unpack(_fpartheadersize)[0] |
635 if headersize < 0: |
639 if headersize < 0: |
636 raise error.BundleValueError('negative part header size: %i' |
640 raise error.BundleValueError('negative part header size: %i' |
637 % headersize) |
641 % headersize) |
638 self.ui.debug('part header size: %i\n' % headersize) |
642 indebug(self.ui, 'part header size: %i\n' % headersize) |
639 if headersize: |
643 if headersize: |
640 return self._readexact(headersize) |
644 return self._readexact(headersize) |
641 return None |
645 return None |
642 |
646 |
643 def compressed(self): |
647 def compressed(self): |
819 returns None if empty""" |
823 returns None if empty""" |
820 headersize = self._unpack(_fpartheadersize)[0] |
824 headersize = self._unpack(_fpartheadersize)[0] |
821 if headersize < 0: |
825 if headersize < 0: |
822 raise error.BundleValueError('negative part header size: %i' |
826 raise error.BundleValueError('negative part header size: %i' |
823 % headersize) |
827 % headersize) |
824 self.ui.debug('part header size: %i\n' % headersize) |
828 indebug(self.ui, 'part header size: %i\n' % headersize) |
825 if headersize: |
829 if headersize: |
826 return self._readexact(headersize) |
830 return self._readexact(headersize) |
827 return None |
831 return None |
828 |
832 |
829 def __call__(self): |
833 def __call__(self): |
830 self.ui.debug('bundle2 stream interruption, looking for a part.\n') |
834 indebug(self.ui, 'bundle2 stream interruption, looking for a part.\n') |
831 headerblock = self._readpartheader() |
835 headerblock = self._readpartheader() |
832 if headerblock is None: |
836 if headerblock is None: |
833 self.ui.debug('no part found during interruption.\n') |
837 indebug(self.ui, 'no part found during interruption.\n') |
834 return |
838 return |
835 part = unbundlepart(self.ui, headerblock, self._fp) |
839 part = unbundlepart(self.ui, headerblock, self._fp) |
836 op = interruptoperation(self.ui) |
840 op = interruptoperation(self.ui) |
837 _processpart(op, part) |
841 _processpart(op, part) |
838 |
842 |
912 'Unknown chunk %d' % chunknum |
916 'Unknown chunk %d' % chunknum |
913 super(unbundlepart, self).seek(self._chunkindex[chunknum][1]) |
917 super(unbundlepart, self).seek(self._chunkindex[chunknum][1]) |
914 |
918 |
915 pos = self._chunkindex[chunknum][0] |
919 pos = self._chunkindex[chunknum][0] |
916 payloadsize = self._unpack(_fpayloadsize)[0] |
920 payloadsize = self._unpack(_fpayloadsize)[0] |
917 self.ui.debug('payload chunk size: %i\n' % payloadsize) |
921 indebug(self.ui, 'payload chunk size: %i\n' % payloadsize) |
918 while payloadsize: |
922 while payloadsize: |
919 if payloadsize == flaginterrupt: |
923 if payloadsize == flaginterrupt: |
920 # interruption detection, the handler will now read a |
924 # interruption detection, the handler will now read a |
921 # single part and process it. |
925 # single part and process it. |
922 interrupthandler(self.ui, self._fp)() |
926 interrupthandler(self.ui, self._fp)() |
930 if chunknum == len(self._chunkindex): |
934 if chunknum == len(self._chunkindex): |
931 self._chunkindex.append((pos, |
935 self._chunkindex.append((pos, |
932 super(unbundlepart, self).tell())) |
936 super(unbundlepart, self).tell())) |
933 yield result |
937 yield result |
934 payloadsize = self._unpack(_fpayloadsize)[0] |
938 payloadsize = self._unpack(_fpayloadsize)[0] |
935 self.ui.debug('payload chunk size: %i\n' % payloadsize) |
939 indebug(self.ui, 'payload chunk size: %i\n' % payloadsize) |
936 |
940 |
937 def _findchunk(self, pos): |
941 def _findchunk(self, pos): |
938 '''for a given payload position, return a chunk number and offset''' |
942 '''for a given payload position, return a chunk number and offset''' |
939 for chunk, (ppos, fpos) in enumerate(self._chunkindex): |
943 for chunk, (ppos, fpos) in enumerate(self._chunkindex): |
940 if ppos == pos: |
944 if ppos == pos: |
945 |
949 |
946 def _readheader(self): |
950 def _readheader(self): |
947 """read the header and setup the object""" |
951 """read the header and setup the object""" |
948 typesize = self._unpackheader(_fparttypesize)[0] |
952 typesize = self._unpackheader(_fparttypesize)[0] |
949 self.type = self._fromheader(typesize) |
953 self.type = self._fromheader(typesize) |
950 self.ui.debug('part type: "%s"\n' % self.type) |
954 indebug(self.ui, 'part type: "%s"\n' % self.type) |
951 self.id = self._unpackheader(_fpartid)[0] |
955 self.id = self._unpackheader(_fpartid)[0] |
952 self.ui.debug('part id: "%s"\n' % self.id) |
956 indebug(self.ui, 'part id: "%s"\n' % self.id) |
953 # extract mandatory bit from type |
957 # extract mandatory bit from type |
954 self.mandatory = (self.type != self.type.lower()) |
958 self.mandatory = (self.type != self.type.lower()) |
955 self.type = self.type.lower() |
959 self.type = self.type.lower() |
956 ## reading parameters |
960 ## reading parameters |
957 # param count |
961 # param count |
958 mancount, advcount = self._unpackheader(_fpartparamcount) |
962 mancount, advcount = self._unpackheader(_fpartparamcount) |
959 self.ui.debug('part parameters: %i\n' % (mancount + advcount)) |
963 indebug(self.ui, 'part parameters: %i\n' % (mancount + advcount)) |
960 # param size |
964 # param size |
961 fparamsizes = _makefpartparamsizes(mancount + advcount) |
965 fparamsizes = _makefpartparamsizes(mancount + advcount) |
962 paramsizes = self._unpackheader(fparamsizes) |
966 paramsizes = self._unpackheader(fparamsizes) |
963 # make it a list of couple again |
967 # make it a list of couple again |
964 paramsizes = zip(paramsizes[::2], paramsizes[1::2]) |
968 paramsizes = zip(paramsizes[::2], paramsizes[1::2]) |