~bzr-pqm/bzr/bzr.dev

« back to all changes in this revision

Viewing changes to bzrlib/knit.py

  • Committer: Canonical.com Patch Queue Manager
  • Date: 2007-08-31 02:05:10 UTC
  • mfrom: (2670.3.8 vf-data-stream)
  • Revision ID: pqm@pqm.ubuntu.com-20070831020510-emrlta5dk6ta95zp
(Andrew Bennetts) Add get_data_stream, insert_data_stream and get_format_signature to KnitVersionedFile.

Show diffs side-by-side

added added

removed removed

Lines of Context:
95
95
    KnitError,
96
96
    InvalidRevisionId,
97
97
    KnitCorrupt,
 
98
    KnitDataStreamIncompatible,
98
99
    KnitHeaderError,
99
100
    RevisionNotPresent,
100
101
    RevisionAlreadyPresent,
562
563
                                (None, current_values[2], current_values[3]),
563
564
                                new_parents)
564
565
 
 
566
    def get_data_stream(self, required_versions):
 
567
        """Get a data stream for the specified versions.
 
568
 
 
569
        Versions may be returned in any order, not necessarily the order
 
570
        specified.
 
571
 
 
572
        :param required_versions: The exact set of versions to be extracted.
 
573
            Unlike some other knit methods, this is not used to generate a
 
574
            transitive closure, rather it is used precisely as given.
 
575
        
 
576
        :returns: format_signature, list of (version, options, length, parents),
 
577
            reader_callable.
 
578
        """
 
579
        required_versions = set([osutils.safe_revision_id(v) for v in
 
580
            required_versions])
 
581
        # we don't care about inclusions, the caller cares.
 
582
        # but we need to setup a list of records to visit.
 
583
        for version_id in required_versions:
 
584
            if not self.has_version(version_id):
 
585
                raise RevisionNotPresent(version_id, self.filename)
 
586
        # Pick the desired versions out of the index in oldest-to-newest order
 
587
        version_list = []
 
588
        for version_id in self.versions():
 
589
            if version_id in required_versions:
 
590
                version_list.append(version_id)
 
591
 
 
592
        # create the list of version information for the result
 
593
        copy_queue_records = []
 
594
        copy_set = set()
 
595
        result_version_list = []
 
596
        for version_id in version_list:
 
597
            options = self._index.get_options(version_id)
 
598
            parents = self._index.get_parents_with_ghosts(version_id)
 
599
            index_memo = self._index.get_position(version_id)
 
600
            copy_queue_records.append((version_id, index_memo))
 
601
            none, data_pos, data_size = index_memo
 
602
            copy_set.add(version_id)
 
603
            # version, options, length, parents
 
604
            result_version_list.append((version_id, options, data_size,
 
605
                parents))
 
606
 
 
607
        # Read the compressed record data.
 
608
        # XXX:
 
609
        # From here down to the return should really be logic in the returned
 
610
        # callable -- in a class that adapts read_records_iter_raw to read
 
611
        # requests.
 
612
        raw_datum = []
 
613
        for (version_id, raw_data), \
 
614
            (version_id2, options, _, parents) in \
 
615
            izip(self._data.read_records_iter_raw(copy_queue_records),
 
616
                 result_version_list):
 
617
            assert version_id == version_id2, 'logic error, inconsistent results'
 
618
            raw_datum.append(raw_data)
 
619
        pseudo_file = StringIO(''.join(raw_datum))
 
620
        def read(length):
 
621
            if length is None:
 
622
                return pseudo_file.read()
 
623
            else:
 
624
                return pseudo_file.read(length)
 
625
        return (self.get_format_signature(), result_version_list, read)
 
626
 
565
627
    def _extract_blocks(self, version_id, source, target):
566
628
        if self._index.get_method(version_id) != 'line-delta':
567
629
            return None
596
658
        else:
597
659
            delta = self.factory.parse_line_delta(data, version_id)
598
660
            return parent, sha1, noeol, delta
 
661
 
 
662
    def get_format_signature(self):
 
663
        """See VersionedFile.get_format_signature()."""
 
664
        if self.factory.annotated:
 
665
            annotated_part = "annotated"
 
666
        else:
 
667
            annotated_part = "plain"
 
668
        return "knit-%s" % (annotated_part,)
599
669
        
600
670
    def get_graph_with_ghosts(self):
601
671
        """See VersionedFile.get_graph_with_ghosts()."""
632
702
                        return True
633
703
        return False
634
704
 
 
705
    def insert_data_stream(self, (format, data_list, reader_callable)):
 
706
        """Insert knit records from a data stream into this knit.
 
707
 
 
708
        If a version in the stream is already present in this knit, it will not
 
709
        be inserted a second time.  It will be checked for consistency with the
 
710
        stored version however, and may cause a KnitCorrupt error to be raised
 
711
        if the data in the stream disagrees with the already stored data.
 
712
        
 
713
        :seealso: get_data_stream
 
714
        """
 
715
        if format != self.get_format_signature():
 
716
            trace.mutter('incompatible format signature inserting to %r', self)
 
717
            raise KnitDataStreamIncompatible(
 
718
                format, self.get_format_signature())
 
719
 
 
720
        for version_id, options, length, parents in data_list:
 
721
            if self.has_version(version_id):
 
722
                # First check: the list of parents.
 
723
                my_parents = self.get_parents_with_ghosts(version_id)
 
724
                if my_parents != parents:
 
725
                    # XXX: KnitCorrupt is not quite the right exception here.
 
726
                    raise KnitCorrupt(
 
727
                        self.filename,
 
728
                        'parents list %r from data stream does not match '
 
729
                        'already recorded parents %r for %s'
 
730
                        % (parents, my_parents, version_id))
 
731
 
 
732
                # Also check the SHA-1 of the fulltext this content will
 
733
                # produce.
 
734
                raw_data = reader_callable(length)
 
735
                my_fulltext_sha1 = self.get_sha1(version_id)
 
736
                df, rec = self._data._parse_record_header(version_id, raw_data)
 
737
                stream_fulltext_sha1 = rec[3]
 
738
                if my_fulltext_sha1 != stream_fulltext_sha1:
 
739
                    # Actually, we don't know if it's this knit that's corrupt,
 
740
                    # or the data stream we're trying to insert.
 
741
                    raise KnitCorrupt(
 
742
                        self.filename, 'sha-1 does not match %s' % version_id)
 
743
            else:
 
744
                self._add_raw_records(
 
745
                    [(version_id, options, parents, length)],
 
746
                    reader_callable(length))
 
747
 
635
748
    def versions(self):
636
749
        """See VersionedFile.versions."""
637
750
        if 'evil' in debug.debug_flags: