~bzr-pqm/bzr/bzr.dev

« back to all changes in this revision

Viewing changes to bzrlib/weave.py

  • Committer: John Arbash Meinel
  • Date: 2009-02-23 15:29:35 UTC
  • mfrom: (3943.7.7 bzr.code_style_cleanup)
  • mto: This revision was merged to the branch mainline in revision 4033.
  • Revision ID: john@arbash-meinel.com-20090223152935-oel9m92mwcc6nb4h
Merge the removal of all trailing whitespace, and resolve conflicts.

Show diffs side-by-side

added added

removed removed

Lines of Context:
61
61
# where the basis and destination are unchanged.
62
62
 
63
63
# FIXME: Sometimes we will be given a parents list for a revision
64
 
# that includes some redundant parents (i.e. already a parent of 
65
 
# something in the list.)  We should eliminate them.  This can 
 
64
# that includes some redundant parents (i.e. already a parent of
 
65
# something in the list.)  We should eliminate them.  This can
66
66
# be done fairly efficiently because the sequence numbers constrain
67
67
# the possible relationships.
68
68
 
131
131
 
132
132
class Weave(VersionedFile):
133
133
    """weave - versioned text file storage.
134
 
    
 
134
 
135
135
    A Weave manages versions of line-based text files, keeping track
136
136
    of the originating version for each line.
137
137
 
183
183
 
184
184
    * It doesn't seem very useful to have an active insertion
185
185
      inside an inactive insertion, but it might happen.
186
 
      
 
186
 
187
187
    * Therefore, all instructions are always"considered"; that
188
188
      is passed onto and off the stack.  An outer inactive block
189
189
      doesn't disable an inner block.
259
259
 
260
260
    def copy(self):
261
261
        """Return a deep copy of self.
262
 
        
 
262
 
263
263
        The copy can be modified without affecting the original weave."""
264
264
        other = Weave()
265
265
        other._weave = self._weave[:]
275
275
            return False
276
276
        return self._parents == other._parents \
277
277
               and self._weave == other._weave \
278
 
               and self._sha1s == other._sha1s 
279
 
    
 
278
               and self._sha1s == other._sha1s
 
279
 
280
280
    def __ne__(self, other):
281
281
        return not self.__eq__(other)
282
282
 
349
349
    def insert_record_stream(self, stream):
350
350
        """Insert a record stream into this versioned file.
351
351
 
352
 
        :param stream: A stream of records to insert. 
 
352
        :param stream: A stream of records to insert.
353
353
        :return: None
354
354
        :seealso VersionedFile.get_record_stream:
355
355
        """
398
398
 
399
399
    def _add(self, version_id, lines, parents, sha1=None, nostore_sha=None):
400
400
        """Add a single text on top of the weave.
401
 
  
 
401
 
402
402
        Returns the index number of the newly added version.
403
403
 
404
404
        version_id
407
407
 
408
408
        parents
409
409
            List or set of direct parent version numbers.
410
 
            
 
410
 
411
411
        lines
412
412
            Sequence of lines to be added in the new version.
413
413
 
435
435
        self._names.append(version_id)
436
436
        self._name_map[version_id] = new_version
437
437
 
438
 
            
 
438
 
439
439
        if not parents:
440
440
            # special case; adding with no parents revision; can do
441
441
            # this more quickly by just appending unconditionally.
452
452
            if sha1 == self._sha1s[pv]:
453
453
                # special case: same as the single parent
454
454
                return new_version
455
 
            
 
455
 
456
456
 
457
457
        ancestors = self._inclusions(parents)
458
458
 
507
507
                # i2; we want to insert after this region to make sure
508
508
                # we don't destroy ourselves
509
509
                i = i2 + offset
510
 
                self._weave[i:i] = ([('{', new_version)] 
511
 
                                    + lines[j1:j2] 
 
510
                self._weave[i:i] = ([('{', new_version)]
 
511
                                    + lines[j1:j2]
512
512
                                    + [('}', None)])
513
513
                offset += 2 + (j2 - j1)
514
514
        return new_version
541
541
            if not isinstance(l, basestring):
542
542
                raise ValueError("text line should be a string or unicode, not %s"
543
543
                                 % type(l))
544
 
        
 
544
 
545
545
 
546
546
 
547
547
    def _check_versions(self, indexes):
555
555
    def _compatible_parents(self, my_parents, other_parents):
556
556
        """During join check that other_parents are joinable with my_parents.
557
557
 
558
 
        Joinable is defined as 'is a subset of' - supersets may require 
 
558
        Joinable is defined as 'is a subset of' - supersets may require
559
559
        regeneration of diffs, but subsets do not.
560
560
        """
561
561
        return len(other_parents.difference(my_parents)) == 0
586
586
 
587
587
    def _walk_internal(self, version_ids=None):
588
588
        """Helper method for weave actions."""
589
 
        
 
589
 
590
590
        istack = []
591
591
        dset = set()
592
592
 
673
673
        for i in versions:
674
674
            if not isinstance(i, int):
675
675
                raise ValueError(i)
676
 
            
 
676
 
677
677
        included = self._inclusions(versions)
678
678
 
679
679
        istack = []
688
688
 
689
689
        WFE = WeaveFormatError
690
690
 
691
 
        # wow. 
 
691
        # wow.
692
692
        #  449       0   4474.6820   2356.5590   bzrlib.weave:556(_extract)
693
693
        #  +285282   0   1676.8040   1676.8040   +<isinstance>
694
694
        # 1.6 seconds in 'isinstance'.
700
700
        # we're still spending ~1/4 of the method in isinstance though.
701
701
        # so lets hard code the acceptable string classes we expect:
702
702
        #  449       0   1202.9420    786.2930   bzrlib.weave:556(_extract)
703
 
        # +71352     0    377.5560    377.5560   +<method 'append' of 'list' 
 
703
        # +71352     0    377.5560    377.5560   +<method 'append' of 'list'
704
704
        #                                          objects>
705
705
        # yay, down to ~1/4 the initial extract time, and our inline time
706
706
        # has shrunk again, with isinstance no longer dominating.
707
707
        # tweaking the stack inclusion test to use a set gives:
708
708
        #  449       0   1122.8030    713.0080   bzrlib.weave:556(_extract)
709
 
        # +71352     0    354.9980    354.9980   +<method 'append' of 'list' 
 
709
        # +71352     0    354.9980    354.9980   +<method 'append' of 'list'
710
710
        #                                          objects>
711
711
        # - a 5% win, or possibly just noise. However with large istacks that
712
712
        # 'in' test could dominate, so I'm leaving this change in place -
713
713
        # when its fast enough to consider profiling big datasets we can review.
714
714
 
715
 
              
716
 
             
 
715
 
 
716
 
717
717
 
718
718
        for l in self._weave:
719
719
            if l.__class__ == tuple:
748
748
 
749
749
    def _maybe_lookup(self, name_or_index):
750
750
        """Convert possible symbolic name to index, or pass through indexes.
751
 
        
 
751
 
752
752
        NOT FOR PUBLIC USE.
753
753
        """
754
754
        if isinstance(name_or_index, (int, long)):
764
764
        measured_sha1 = sha_strings(result)
765
765
        if measured_sha1 != expected_sha1:
766
766
            raise errors.WeaveInvalidChecksum(
767
 
                    'file %s, revision %s, expected: %s, measured %s' 
 
767
                    'file %s, revision %s, expected: %s, measured %s'
768
768
                    % (self._weave_name, version_id,
769
769
                       expected_sha1, measured_sha1))
770
770
        return result
812
812
 
813
813
            if set(new_inc) != set(self.get_ancestry(name)):
814
814
                raise AssertionError(
815
 
                    'failed %s != %s' 
 
815
                    'failed %s != %s'
816
816
                    % (set(new_inc), set(self.get_ancestry(name))))
817
817
            inclusions[name] = new_inc
818
818
 
856
856
            parent_name = other._names[parent_idx]
857
857
            if parent_name not in self._name_map:
858
858
                # should not be possible
859
 
                raise WeaveError("missing parent {%s} of {%s} in %r" 
 
859
                raise WeaveError("missing parent {%s} of {%s} in %r"
860
860
                                 % (parent_name, other._name_map[other_idx], self))
861
861
            new_parents.append(self._name_map[parent_name])
862
862
        return new_parents
869
869
         * the same text
870
870
         * the same direct parents (by name, not index, and disregarding
871
871
           order)
872
 
        
 
872
 
873
873
        If present & correct return True;
874
 
        if not present in self return False; 
 
874
        if not present in self return False;
875
875
        if inconsistent raise error."""
876
876
        this_idx = self._name_map.get(name, -1)
877
877
        if this_idx != -1:
910
910
    """A WeaveFile represents a Weave on disk and writes on change."""
911
911
 
912
912
    WEAVE_SUFFIX = '.weave'
913
 
    
 
913
 
914
914
    def __init__(self, name, transport, filemode=None, create=False, access_mode='w', get_scope=None):
915
915
        """Create a WeaveFile.
916
 
        
 
916
 
917
917
        :param create: If not True, only open an existing knit.
918
918
        """
919
919
        super(WeaveFile, self).__init__(name, access_mode, get_scope=get_scope,
980
980
def _reweave(wa, wb, pb=None, msg=None):
981
981
    """Combine two weaves and return the result.
982
982
 
983
 
    This works even if a revision R has different parents in 
 
983
    This works even if a revision R has different parents in
984
984
    wa and wb.  In the resulting weave all the parents are given.
985
985
 
986
 
    This is done by just building up a new weave, maintaining ordering 
 
986
    This is done by just building up a new weave, maintaining ordering
987
987
    of the versions in the two inputs.  More efficient approaches
988
 
    might be possible but it should only be necessary to do 
989
 
    this operation rarely, when a new previously ghost version is 
 
988
    might be possible but it should only be necessary to do
 
989
    this operation rarely, when a new previously ghost version is
990
990
    inserted.
991
991
 
992
992
    :param pb: An optional progress bar, indicating how far done we are
1028
1028
 
1029
1029
def _reweave_parent_graphs(wa, wb):
1030
1030
    """Return combined parent ancestry for two weaves.
1031
 
    
 
1031
 
1032
1032
    Returned as a list of (version_name, set(parent_names))"""
1033
1033
    combined = {}
1034
1034
    for weave in [wa, wb]:
1099
1099
        Display origin of each line.
1100
1100
    weave merge WEAVEFILE VERSION1 VERSION2 > OUT
1101
1101
        Auto-merge two versions and display conflicts.
1102
 
    weave diff WEAVEFILE VERSION1 VERSION2 
 
1102
    weave diff WEAVEFILE VERSION1 VERSION2
1103
1103
        Show differences between two versions.
1104
1104
 
1105
1105
example:
1122
1122
 
1123
1123
    % weave merge foo.weave 1 2 > foo.txt   (merge them)
1124
1124
    % vi foo.txt                            (resolve conflicts)
1125
 
    % weave add foo.weave merged 1 2 < foo.txt     (commit merged version)     
1126
 
    
 
1125
    % weave add foo.weave merged 1 2 < foo.txt     (commit merged version)
 
1126
 
1127
1127
"""
1128
 
    
 
1128
 
1129
1129
 
1130
1130
 
1131
1131
def main(argv):
1154
1154
 
1155
1155
    def readit():
1156
1156
        return read_weave(file(argv[2], 'rb'))
1157
 
    
 
1157
 
1158
1158
    if cmd == 'help':
1159
1159
        usage()
1160
1160
    elif cmd == 'add':
1175
1175
    elif cmd == 'get': # get one version
1176
1176
        w = readit()
1177
1177
        sys.stdout.writelines(w.get_iter(int(argv[3])))
1178
 
        
 
1178
 
1179
1179
    elif cmd == 'diff':
1180
1180
        w = readit()
1181
1181
        fn = argv[2]
1186
1186
                                '%s version %d' % (fn, v1),
1187
1187
                                '%s version %d' % (fn, v2))
1188
1188
        sys.stdout.writelines(diff_gen)
1189
 
            
 
1189
 
1190
1190
    elif cmd == 'annotate':
1191
1191
        w = readit()
1192
1192
        # newline is added to all lines regardless; too hard to get
1199
1199
            else:
1200
1200
                print '%5d | %s' % (origin, text)
1201
1201
                lasto = origin
1202
 
                
 
1202
 
1203
1203
    elif cmd == 'toc':
1204
1204
        weave_toc(readit())
1205
1205
 
1206
1206
    elif cmd == 'stats':
1207
1207
        weave_stats(argv[2], ProgressBar())
1208
 
        
 
1208
 
1209
1209
    elif cmd == 'check':
1210
1210
        w = readit()
1211
1211
        pb = ProgressBar()
1234
1234
        sys.stdout.writelines(w.weave_merge(p))
1235
1235
    else:
1236
1236
        raise ValueError('unknown command %r' % cmd)
1237
 
    
 
1237
 
1238
1238
 
1239
1239
if __name__ == '__main__':
1240
1240
    import sys