~bzr-pqm/bzr/bzr.dev

« back to all changes in this revision

Viewing changes to bzrlib/weave.py

  • Committer: Ian Clatworthy
  • Date: 2007-11-27 21:17:06 UTC
  • mto: (3054.1.1 ianc-integration)
  • mto: This revision was merged to the branch mainline in revision 3055.
  • Revision ID: ian.clatworthy@internode.on.net-20071127211706-871zcqst0yi5tcvl
make fixes suggested by proof-readers

Show diffs side-by-side

added added

removed removed

Lines of Context:
88
88
import bzrlib.errors as errors
89
89
from bzrlib.osutils import sha_strings
90
90
import bzrlib.patiencediff
91
 
from bzrlib.symbol_versioning import (deprecated_method,
92
 
        deprecated_function,
93
 
        zero_eight,
94
 
        )
95
91
from bzrlib.tsort import topo_sort
96
92
from bzrlib.versionedfile import VersionedFile, InterVersionedFile
97
93
from bzrlib.weavefile import _read_weave_v5, write_weave_v5
228
224
    def __ne__(self, other):
229
225
        return not self.__eq__(other)
230
226
 
231
 
    @deprecated_method(zero_eight)
232
 
    def idx_to_name(self, index):
233
 
        """Old public interface, the public interface is all names now."""
234
 
        return index
235
 
 
236
227
    def _idx_to_name(self, version):
237
228
        return self._names[version]
238
229
 
239
 
    @deprecated_method(zero_eight)
240
 
    def lookup(self, name):
241
 
        """Backwards compatibility thunk:
242
 
 
243
 
        Return name, as name is valid in the api now, and spew deprecation
244
 
        warnings everywhere.
245
 
        """
246
 
        return name
247
 
 
248
230
    def _lookup(self, name):
249
231
        """Convert symbolic version name to index."""
 
232
        self.check_not_reserved_id(name)
250
233
        try:
251
234
            return self._name_map[name]
252
235
        except KeyError:
253
236
            raise RevisionNotPresent(name, self._weave_name)
254
237
 
255
 
    @deprecated_method(zero_eight)
256
 
    def iter_names(self):
257
 
        """Deprecated convenience function, please see VersionedFile.names()."""
258
 
        return iter(self.names())
259
 
 
260
 
    @deprecated_method(zero_eight)
261
 
    def names(self):
262
 
        """See Weave.versions for the current api."""
263
 
        return self.versions()
264
 
 
265
238
    def versions(self):
266
239
        """See VersionedFile.versions."""
267
240
        return self._names[:]
272
245
 
273
246
    __contains__ = has_version
274
247
 
275
 
    def get_delta(self, version_id):
276
 
        """See VersionedFile.get_delta."""
277
 
        return self.get_deltas([version_id])[version_id]
278
 
 
279
 
    def get_deltas(self, version_ids):
280
 
        """See VersionedFile.get_deltas."""
281
 
        version_ids = self.get_ancestry(version_ids)
282
 
        for version_id in version_ids:
283
 
            if not self.has_version(version_id):
284
 
                raise RevisionNotPresent(version_id, self)
285
 
        # try extracting all versions; parallel extraction is used
286
 
        nv = self.num_versions()
287
 
        sha1s = {}
288
 
        deltas = {}
289
 
        texts = {}
290
 
        inclusions = {}
291
 
        noeols = {}
292
 
        last_parent_lines = {}
293
 
        parents = {}
294
 
        parent_inclusions = {}
295
 
        parent_linenums = {}
296
 
        parent_noeols = {}
297
 
        current_hunks = {}
298
 
        diff_hunks = {}
299
 
        # its simplest to generate a full set of prepared variables.
300
 
        for i in range(nv):
301
 
            name = self._names[i]
302
 
            sha1s[name] = self.get_sha1(name)
303
 
            parents_list = self.get_parents(name)
304
 
            try:
305
 
                parent = parents_list[0]
306
 
                parents[name] = parent
307
 
                parent_inclusions[name] = inclusions[parent]
308
 
            except IndexError:
309
 
                parents[name] = None
310
 
                parent_inclusions[name] = set()
311
 
            # we want to emit start, finish, replacement_length, replacement_lines tuples.
312
 
            diff_hunks[name] = []
313
 
            current_hunks[name] = [0, 0, 0, []] # #start, finish, repl_length, repl_tuples
314
 
            parent_linenums[name] = 0
315
 
            noeols[name] = False
316
 
            parent_noeols[name] = False
317
 
            last_parent_lines[name] = None
318
 
            new_inc = set([name])
319
 
            for p in self._parents[i]:
320
 
                new_inc.update(inclusions[self._idx_to_name(p)])
321
 
            # debug only, known good so far.
322
 
            #assert set(new_inc) == set(self.get_ancestry(name)), \
323
 
            #    'failed %s != %s' % (set(new_inc), set(self.get_ancestry(name)))
324
 
            inclusions[name] = new_inc
325
 
 
326
 
        nlines = len(self._weave)
327
 
 
328
 
        for lineno, inserted, deletes, line in self._walk_internal():
329
 
            # a line is active in a version if:
330
 
            # insert is in the versions inclusions
331
 
            # and
332
 
            # deleteset & the versions inclusions is an empty set.
333
 
            # so - if we have a included by mapping - version is included by
334
 
            # children, we get a list of children to examine for deletes affect
335
 
            # ing them, which is less than the entire set of children.
336
 
            for version_id in version_ids:  
337
 
                # The active inclusion must be an ancestor,
338
 
                # and no ancestors must have deleted this line,
339
 
                # because we don't support resurrection.
340
 
                parent_inclusion = parent_inclusions[version_id]
341
 
                inclusion = inclusions[version_id]
342
 
                parent_active = inserted in parent_inclusion and not (deletes & parent_inclusion)
343
 
                version_active = inserted in inclusion and not (deletes & inclusion)
344
 
                if not parent_active and not version_active:
345
 
                    # unrelated line of ancestry
346
 
                    continue
347
 
                elif parent_active and version_active:
348
 
                    # shared line
349
 
                    parent_linenum = parent_linenums[version_id]
350
 
                    if current_hunks[version_id] != [parent_linenum, parent_linenum, 0, []]:
351
 
                        diff_hunks[version_id].append(tuple(current_hunks[version_id]))
352
 
                    parent_linenum += 1
353
 
                    current_hunks[version_id] = [parent_linenum, parent_linenum, 0, []]
354
 
                    parent_linenums[version_id] = parent_linenum
355
 
                    try:
356
 
                        if line[-1] != '\n':
357
 
                            noeols[version_id] = True
358
 
                    except IndexError:
359
 
                        pass
360
 
                elif parent_active and not version_active:
361
 
                    # deleted line
362
 
                    current_hunks[version_id][1] += 1
363
 
                    parent_linenums[version_id] += 1
364
 
                    last_parent_lines[version_id] = line
365
 
                elif not parent_active and version_active:
366
 
                    # replacement line
367
 
                    # noeol only occurs at the end of a file because we 
368
 
                    # diff linewise. We want to show noeol changes as a
369
 
                    # empty diff unless the actual eol-less content changed.
370
 
                    theline = line
371
 
                    try:
372
 
                        if last_parent_lines[version_id][-1] != '\n':
373
 
                            parent_noeols[version_id] = True
374
 
                    except (TypeError, IndexError):
375
 
                        pass
376
 
                    try:
377
 
                        if theline[-1] != '\n':
378
 
                            noeols[version_id] = True
379
 
                    except IndexError:
380
 
                        pass
381
 
                    new_line = False
382
 
                    parent_should_go = False
383
 
 
384
 
                    if parent_noeols[version_id] == noeols[version_id]:
385
 
                        # no noeol toggle, so trust the weaves statement
386
 
                        # that this line is changed.
387
 
                        new_line = True
388
 
                        if parent_noeols[version_id]:
389
 
                            theline = theline + '\n'
390
 
                    elif parent_noeols[version_id]:
391
 
                        # parent has no eol, we do:
392
 
                        # our line is new, report as such..
393
 
                        new_line = True
394
 
                    elif noeols[version_id]:
395
 
                        # append a eol so that it looks like
396
 
                        # a normalised delta
397
 
                        theline = theline + '\n'
398
 
                        if parents[version_id] is not None:
399
 
                        #if last_parent_lines[version_id] is not None:
400
 
                            parent_should_go = True
401
 
                        if last_parent_lines[version_id] != theline:
402
 
                            # but changed anyway
403
 
                            new_line = True
404
 
                            #parent_should_go = False
405
 
                    if new_line:
406
 
                        current_hunks[version_id][2] += 1
407
 
                        current_hunks[version_id][3].append((inserted, theline))
408
 
                    if parent_should_go:
409
 
                        # last hunk last parent line is not eaten
410
 
                        current_hunks[version_id][1] -= 1
411
 
                    if current_hunks[version_id][1] < 0:
412
 
                        current_hunks[version_id][1] = 0
413
 
                        # import pdb;pdb.set_trace()
414
 
                    # assert current_hunks[version_id][1] >= 0
415
 
 
416
 
        # flush last hunk
417
 
        for i in range(nv):
418
 
            version = self._idx_to_name(i)
419
 
            if current_hunks[version] != [0, 0, 0, []]:
420
 
                diff_hunks[version].append(tuple(current_hunks[version]))
421
 
        result = {}
422
 
        for version_id in version_ids:
423
 
            result[version_id] = (
424
 
                                  parents[version_id],
425
 
                                  sha1s[version_id],
426
 
                                  noeols[version_id],
427
 
                                  diff_hunks[version_id],
428
 
                                  )
429
 
        return result
430
 
 
431
248
    def get_parents(self, version_id):
432
249
        """See VersionedFile.get_parent."""
433
250
        return map(self._idx_to_name, self._parents[self._lookup(version_id)])
443
260
            raise RevisionAlreadyPresent(name, self._weave_name)
444
261
        return idx
445
262
 
446
 
    @deprecated_method(zero_eight)
447
 
    def add_identical(self, old_rev_id, new_rev_id, parents):
448
 
        """Please use Weave.clone_text now."""
449
 
        return self.clone_text(new_rev_id, old_rev_id, parents)
450
 
 
451
 
    def _add_lines(self, version_id, parents, lines, parent_texts):
 
263
    def _add_lines(self, version_id, parents, lines, parent_texts,
 
264
       left_matching_blocks, nostore_sha, random_id, check_content):
452
265
        """See VersionedFile.add_lines."""
453
 
        return self._add(version_id, lines, map(self._lookup, parents))
454
 
 
455
 
    @deprecated_method(zero_eight)
456
 
    def add(self, name, parents, text, sha1=None):
457
 
        """See VersionedFile.add_lines for the non deprecated api."""
458
 
        return self._add(name, text, map(self._maybe_lookup, parents), sha1)
459
 
 
460
 
    def _add(self, version_id, lines, parents, sha1=None):
 
266
        idx = self._add(version_id, lines, map(self._lookup, parents),
 
267
            nostore_sha=nostore_sha)
 
268
        return sha_strings(lines), sum(map(len, lines)), idx
 
269
 
 
270
    def _add(self, version_id, lines, parents, sha1=None, nostore_sha=None):
461
271
        """Add a single text on top of the weave.
462
272
  
463
273
        Returns the index number of the newly added version.
471
281
            
472
282
        lines
473
283
            Sequence of lines to be added in the new version.
 
284
 
 
285
        :param nostore_sha: See VersionedFile.add_lines.
474
286
        """
475
 
 
476
287
        assert isinstance(version_id, basestring)
477
288
        self._check_lines_not_unicode(lines)
478
289
        self._check_lines_are_lines(lines)
479
290
        if not sha1:
480
291
            sha1 = sha_strings(lines)
 
292
        if sha1 == nostore_sha:
 
293
            raise errors.ExistingContent
481
294
        if version_id in self._name_map:
482
295
            return self._check_repeated_add(version_id, parents, lines, sha1)
483
296
 
527
340
        # another small special case: a merge, producing the same text
528
341
        # as auto-merge
529
342
        if lines == basis_lines:
530
 
            return new_version            
 
343
            return new_version
531
344
 
532
345
        # add a sentinel, because we can also match against the final line
533
346
        basis_lineno.append(len(self._weave))
596
409
        ## except IndexError:
597
410
        ##     raise ValueError("version %d not present in weave" % v)
598
411
 
599
 
    @deprecated_method(zero_eight)
600
 
    def inclusions(self, version_ids):
601
 
        """Deprecated - see VersionedFile.get_ancestry for the replacement."""
602
 
        if not version_ids:
603
 
            return []
604
 
        if isinstance(version_ids[0], int):
605
 
            return [self._idx_to_name(v) for v in self._inclusions(version_ids)]
606
 
        else:
607
 
            return self.get_ancestry(version_ids)
608
 
 
609
 
    def get_ancestry(self, version_ids):
 
412
    def get_ancestry(self, version_ids, topo_sorted=True):
610
413
        """See VersionedFile.get_ancestry."""
611
414
        if isinstance(version_ids, basestring):
612
415
            version_ids = [version_ids]
640
443
        """
641
444
        return len(other_parents.difference(my_parents)) == 0
642
445
 
643
 
    def annotate(self, version_id):
644
 
        if isinstance(version_id, int):
645
 
            warnings.warn('Weave.annotate(int) is deprecated. Please use version names'
646
 
                 ' in all circumstances as of 0.8',
647
 
                 DeprecationWarning,
648
 
                 stacklevel=2
649
 
                 )
650
 
            result = []
651
 
            for origin, lineno, text in self._extract([version_id]):
652
 
                result.append((origin, text))
653
 
            return result
654
 
        else:
655
 
            return super(Weave, self).annotate(version_id)
656
 
    
657
446
    def annotate_iter(self, version_id):
658
447
        """Yield list of (version-id, line) pairs for the specified version.
659
448
 
662
451
        for origin, lineno, text in self._extract(incls):
663
452
            yield self._idx_to_name(origin), text
664
453
 
665
 
    @deprecated_method(zero_eight)
666
 
    def _walk(self):
667
 
        """_walk has become visit, a supported api."""
668
 
        return self._walk_internal()
669
 
 
670
454
    def iter_lines_added_or_present_in_versions(self, version_ids=None,
671
455
                                                pb=None):
672
456
        """See VersionedFile.iter_lines_added_or_present_in_versions()."""
683
467
            else:
684
468
                yield line
685
469
 
686
 
    #@deprecated_method(zero_eight)
687
 
    def walk(self, version_ids=None):
688
 
        """See VersionedFile.walk."""
689
 
        return self._walk_internal(version_ids)
690
 
 
691
470
    def _walk_internal(self, version_ids=None):
692
471
        """Helper method for weave actions."""
693
472
        
736
515
        inc_b = set(self.get_ancestry([ver_b]))
737
516
        inc_c = inc_a & inc_b
738
517
 
739
 
        for lineno, insert, deleteset, line in\
740
 
            self.walk([ver_a, ver_b]):
 
518
        for lineno, insert, deleteset, line in self._walk_internal([ver_a, ver_b]):
741
519
            if deleteset & inc_c:
742
520
                # killed in parent; can't be in either a or b
743
521
                # not relevant to our work
859
637
                                   % dset)
860
638
        return result
861
639
 
862
 
    @deprecated_method(zero_eight)
863
 
    def get_iter(self, name_or_index):
864
 
        """Deprecated, please do not use. Lookups are not not needed.
865
 
        
866
 
        Please use get_lines now.
867
 
        """
868
 
        return iter(self.get_lines(self._maybe_lookup(name_or_index)))
869
 
 
870
 
    @deprecated_method(zero_eight)
871
 
    def maybe_lookup(self, name_or_index):
872
 
        """Deprecated, please do not use. Lookups are not not needed."""
873
 
        return self._maybe_lookup(name_or_index)
874
 
 
875
640
    def _maybe_lookup(self, name_or_index):
876
641
        """Convert possible symbolic name to index, or pass through indexes.
877
642
        
882
647
        else:
883
648
            return self._lookup(name_or_index)
884
649
 
885
 
    @deprecated_method(zero_eight)
886
 
    def get(self, version_id):
887
 
        """Please use either Weave.get_text or Weave.get_lines as desired."""
888
 
        return self.get_lines(version_id)
889
 
 
890
650
    def get_lines(self, version_id):
891
651
        """See VersionedFile.get_lines()."""
892
652
        int_index = self._maybe_lookup(version_id)
904
664
        """See VersionedFile.get_sha1()."""
905
665
        return self._sha1s[self._lookup(version_id)]
906
666
 
907
 
    @deprecated_method(zero_eight)
908
 
    def numversions(self):
909
 
        """How many versions are in this weave?
910
 
 
911
 
        Deprecated in favour of num_versions.
912
 
        """
913
 
        return self.num_versions()
 
667
    def get_sha1s(self, version_ids):
 
668
        """See VersionedFile.get_sha1s()."""
 
669
        return [self._sha1s[self._lookup(v)] for v in version_ids]
914
670
 
915
671
    def num_versions(self):
916
672
        """How many versions are in this weave?"""
1075
831
        else:
1076
832
            return False
1077
833
 
1078
 
    @deprecated_method(zero_eight)
1079
 
    def reweave(self, other, pb=None, msg=None):
1080
 
        """reweave has been superseded by plain use of join."""
1081
 
        return self.join(other, pb, msg)
1082
 
 
1083
834
    def _reweave(self, other, pb, msg):
1084
835
        """Reweave self with other - internal helper for join().
1085
836
 
1118
869
            # new file, save it
1119
870
            self._save()
1120
871
 
1121
 
    def _add_lines(self, version_id, parents, lines, parent_texts):
 
872
    def _add_lines(self, version_id, parents, lines, parent_texts,
 
873
        left_matching_blocks, nostore_sha, random_id, check_content):
1122
874
        """Add a version and save the weave."""
 
875
        self.check_not_reserved_id(version_id)
1123
876
        result = super(WeaveFile, self)._add_lines(version_id, parents, lines,
1124
 
                                                   parent_texts)
 
877
            parent_texts, left_matching_blocks, nostore_sha, random_id,
 
878
            check_content)
1125
879
        self._save()
1126
880
        return result
1127
881
 
1163
917
        self._save()
1164
918
 
1165
919
 
1166
 
@deprecated_function(zero_eight)
1167
 
def reweave(wa, wb, pb=None, msg=None):
1168
 
    """reweaving is deprecation, please just use weave.join()."""
1169
 
    _reweave(wa, wb, pb, msg)
1170
 
 
1171
920
def _reweave(wa, wb, pb=None, msg=None):
1172
921
    """Combine two weaves and return the result.
1173
922
 
1453
1202
        if self.target.versions() == [] and version_ids is None:
1454
1203
            self.target._copy_weave_content(self.source)
1455
1204
            return
1456
 
        try:
1457
 
            self.target._join(self.source, pb, msg, version_ids, ignore_missing)
1458
 
        except errors.WeaveParentMismatch:
1459
 
            self.target._reweave(self.source, pb, msg)
 
1205
        self.target._join(self.source, pb, msg, version_ids, ignore_missing)
1460
1206
 
1461
1207
 
1462
1208
InterVersionedFile.register_optimiser(InterWeave)