~bzr-pqm/bzr/bzr.dev

« back to all changes in this revision

Viewing changes to bzrlib/knit.py

  • Committer: John Arbash Meinel
  • Date: 2006-06-18 02:21:57 UTC
  • mfrom: (1787 +trunk)
  • mto: This revision was merged to the branch mainline in revision 1794.
  • Revision ID: john@arbash-meinel.com-20060618022157-6e33aa9b67c25e4f
[merge] bzr.dev 1787

Show diffs side-by-side

added added

removed removed

Lines of Context:
2
2
# Written by Martin Pool.
3
3
# Modified by Johan Rydberg <jrydberg@gnu.org>
4
4
# Modified by Robert Collins <robert.collins@canonical.com>
5
 
# Modified by Aaron Bentley <aaron.bentley@utoronto.ca>
6
5
#
7
6
# This program is free software; you can redistribute it and/or modify
8
7
# it under the terms of the GNU General Public License as published by
68
67
from cStringIO import StringIO
69
68
import difflib
70
69
from itertools import izip, chain
71
 
import operator
72
70
import os
73
71
import sys
74
72
 
77
75
from bzrlib.errors import FileExists, NoSuchFile, KnitError, \
78
76
        InvalidRevisionId, KnitCorrupt, KnitHeaderError, \
79
77
        RevisionNotPresent, RevisionAlreadyPresent
80
 
from bzrlib.tuned_gzip import GzipFile
 
78
from bzrlib.tuned_gzip import *
81
79
from bzrlib.trace import mutter
82
80
from bzrlib.osutils import contains_whitespace, contains_linebreaks, \
83
81
     sha_strings
267
265
    stored and retrieved.
268
266
    """
269
267
 
270
 
    def __init__(self, relpath, transport, file_mode=None, access_mode=None, 
271
 
                 factory=None, basis_knit=None, delta=True, create=False):
 
268
    def __init__(self, relpath, transport, file_mode=None, access_mode=None, factory=None,
 
269
                 basis_knit=None, delta=True, create=False):
272
270
        """Construct a knit at location specified by relpath.
273
271
        
274
272
        :param create: If not True, only open an existing knit.
512
510
            diff_hunks.append((op[1], op[2], op[4]-op[3], new_content._lines[op[3]:op[4]]))
513
511
        return diff_hunks
514
512
 
515
 
    def _get_component_versions(self, version_id):
516
 
        basis = self.basis_knit
517
 
        needed_versions = []
518
 
        basis_versions = []
519
 
        cursor = version_id
520
 
 
521
 
        while 1:
522
 
            picked_knit = self
523
 
            if basis and basis._index.has_version(cursor):
524
 
                picked_knit = basis
525
 
                basis_versions.append(cursor)
526
 
            method = picked_knit._index.get_method(cursor)
527
 
            needed_versions.append((method, cursor))
528
 
            if method == 'fulltext':
529
 
                break
530
 
            cursor = picked_knit.get_parents(cursor)[0]
531
 
        return needed_versions, basis_versions
532
 
 
533
 
    def _get_component_positions(self, version_id):
534
 
        needed_versions, basis_versions = \
535
 
            self._get_component_versions(version_id)
536
 
        assert len(basis_versions) == 0
537
 
        positions = []
538
 
        for method, comp_id in needed_versions:
539
 
            data_pos, data_size = self._index.get_position(comp_id)
540
 
            positions.append((method, comp_id, data_pos, data_size))
541
 
        return positions
542
 
 
543
513
    def _get_components(self, version_id):
544
514
        """Return a list of (version_id, method, data) tuples that
545
515
        makes up version specified by version_id of the knit.
563
533
        # basis_revisions is a list of versions that needs to be
564
534
        # fetched but exists in the basis knit.
565
535
 
566
 
        needed_versions, basis_versions = \
567
 
            self._get_component_versions(version_id)
 
536
        basis = self.basis_knit
 
537
        needed_versions = []
 
538
        basis_versions = []
 
539
        cursor = version_id
 
540
 
 
541
        while 1:
 
542
            picked_knit = self
 
543
            if basis and basis._index.has_version(cursor):
 
544
                picked_knit = basis
 
545
                basis_versions.append(cursor)
 
546
            method = picked_knit._index.get_method(cursor)
 
547
            needed_versions.append((method, cursor))
 
548
            if method == 'fulltext':
 
549
                break
 
550
            cursor = picked_knit.get_parents(cursor)[0]
568
551
 
569
552
        components = {}
570
553
        if basis_versions:
571
 
            assert False, "I am broken"
572
 
            basis = self.basis_knit
573
554
            records = []
574
555
            for comp_id in basis_versions:
575
556
                data_pos, data_size = basis._index.get_data_position(comp_id)
576
 
                records.append((comp_id, data_pos, data_size))
 
557
                records.append((piece_id, data_pos, data_size))
577
558
            components.update(basis._data.read_records(records))
578
559
 
579
560
        records = []
622
603
 
623
604
        # digest here is the digest from the last applied component.
624
605
        if sha_strings(content.text()) != digest:
 
606
            import pdb;pdb.set_trace()
625
607
            raise KnitCorrupt(self.filename, 'sha-1 does not match %s' % version_id)
626
608
 
627
609
        return content
735
717
 
736
718
    def _clone_text(self, new_version_id, old_version_id, parents):
737
719
        """See VersionedFile.clone_text()."""
738
 
        # FIXME RBC 20060228 make fast by only inserting an index with null 
739
 
        # delta.
 
720
        # FIXME RBC 20060228 make fast by only inserting an index with null delta.
740
721
        self.add_lines(new_version_id, parents, self.get_lines(old_version_id))
741
722
 
742
723
    def get_lines(self, version_id):
743
724
        """See VersionedFile.get_lines()."""
744
 
        return self.get_line_list([version_id])[0]
745
 
 
746
 
    def _get_version_components(self, position_map):
747
 
        records = []
748
 
        for version_id, positions in position_map.iteritems():
749
 
            for method, comp_id, position, size in positions:
750
 
                records.append((comp_id, position, size))
751
 
        record_map = self._data.read_records(records)
752
 
 
753
 
        component_map = {}
754
 
        for version_id, positions in position_map.iteritems():
755
 
            components = []
756
 
            for method, comp_id, position, size in positions:
757
 
                data, digest = record_map[comp_id]
758
 
                components.append((comp_id, method, data, digest))
759
 
            component_map[version_id] = components
760
 
        return component_map
761
 
 
762
 
    def get_text(self, version_id):
763
 
        """See VersionedFile.get_text"""
764
 
        return self.get_texts([version_id])[0]
765
 
 
766
 
    def get_texts(self, version_ids):
767
 
        return [''.join(l) for l in self.get_line_list(version_ids)]
768
 
 
769
 
    def get_line_list(self, version_ids):
770
 
        """Return the texts of listed versions as a list of strings."""
771
 
        position_map = {}
772
 
        for version_id in version_ids:
773
 
            if not self.has_version(version_id):
774
 
                raise RevisionNotPresent(version_id, self.filename)
775
 
            position_map[version_id] = \
776
 
                self._get_component_positions(version_id)
777
 
 
778
 
        version_components = self._get_version_components(position_map).items()
779
 
 
780
 
        text_map = {}
781
 
        for version_id, components in version_components:
782
 
            content = None
783
 
            for component_id, method, data, digest in reversed(components):
784
 
                version_idx = self._index.lookup(component_id)
785
 
                if method == 'fulltext':
786
 
                    assert content is None
787
 
                    content = self.factory.parse_fulltext(data, version_idx)
788
 
                elif method == 'line-delta':
789
 
                    delta = self.factory.parse_line_delta(data, version_idx)
790
 
                    content._lines = self._apply_delta(content._lines, delta)
791
 
 
792
 
            if 'no-eol' in self._index.get_options(version_id):
793
 
                line = content._lines[-1][1].rstrip('\n')
794
 
                content._lines[-1] = (content._lines[-1][0], line)
795
 
 
796
 
            # digest here is the digest from the last applied component.
797
 
            if sha_strings(content.text()) != digest:
798
 
                raise KnitCorrupt(self.filename, 
799
 
                                  'sha-1 does not match %s' % version_id)
800
 
 
801
 
            text_map[version_id] = content.text()
802
 
        return [text_map[v] for v in version_ids]
 
725
        return self._get_content(version_id).text()
803
726
 
804
727
    def iter_lines_added_or_present_in_versions(self, version_ids=None):
805
728
        """See VersionedFile.iter_lines_added_or_present_in_versions()."""
1069
992
        # position in _history is the 'official' index for a revision
1070
993
        # but the values may have come from a newer entry.
1071
994
        # so - wc -l of a knit index is != the number of unique names
1072
 
        # in the knit.
 
995
        # in the weave.
1073
996
        self._history = []
1074
997
        pb = bzrlib.ui.ui_factory.nested_progress_bar()
1075
998
        try:
1450
1373
                needed_records.append((version_id, pos, size))
1451
1374
 
1452
1375
        if len(needed_records):
1453
 
            needed_records.sort(key=operator.itemgetter(1))
1454
1376
            # We take it that the transport optimizes the fetching as good
1455
1377
            # as possible (ie, reads continuous ranges.)
1456
1378
            response = self._transport.readv(self._filename,
1457
1379
                [(pos, size) for version_id, pos, size in needed_records])
1458
1380
 
1459
 
            for (record_id, pos, size), (pos, data) in \
1460
 
                izip(iter(needed_records), response):
 
1381
            for (record_id, pos, size), (pos, data) in izip(iter(needed_records), response):
1461
1382
                content, digest = self._parse_record(record_id, data)
1462
1383
                self._records[record_id] = (digest, content)
1463
1384