/brz/remove-bazaar

To get this branch, use:
bzr branch http://gegoxaren.bato24.eu/bzr/brz/remove-bazaar

« back to all changes in this revision

Viewing changes to bzrlib/weave.py

  • Committer: Robert Collins
  • Date: 2006-03-03 02:09:49 UTC
  • mto: (1594.2.4 integration)
  • mto: This revision was merged to the branch mainline in revision 1596.
  • Revision ID: robertc@robertcollins.net-20060303020949-0ddc6f33d0a43943
Smoke test for RevisionStore factories creating revision stores.

Show diffs side-by-side

added added

removed removed

Lines of Context:
66
66
# be done fairly efficiently because the sequence numbers constrain
67
67
# the possible relationships.
68
68
 
69
 
# FIXME: the conflict markers should be *7* characters
70
69
 
71
 
from copy import copy
72
70
from cStringIO import StringIO
73
71
from difflib import SequenceMatcher
74
72
import os
182
180
    __slots__ = ['_weave', '_parents', '_sha1s', '_names', '_name_map',
183
181
                 '_weave_name']
184
182
    
185
 
    def __init__(self, weave_name=None, access_mode='w'):
186
 
        super(Weave, self).__init__(access_mode)
 
183
    def __init__(self, weave_name=None):
187
184
        self._weave = []
188
185
        self._parents = []
189
186
        self._sha1s = []
261
258
 
262
259
    __contains__ = has_version
263
260
 
264
 
    def get_delta(self, version_id):
265
 
        """See VersionedFile.get_delta."""
266
 
        return self.get_deltas([version_id])[version_id]
267
 
 
268
 
    def get_deltas(self, version_ids):
269
 
        """See VersionedFile.get_deltas."""
270
 
        version_ids = self.get_ancestry(version_ids)
271
 
        for version_id in version_ids:
272
 
            if not self.has_version(version_id):
273
 
                raise RevisionNotPresent(version_id, self)
274
 
        # try extracting all versions; parallel extraction is used
275
 
        nv = self.num_versions()
276
 
        sha1s = {}
277
 
        deltas = {}
278
 
        texts = {}
279
 
        inclusions = {}
280
 
        noeols = {}
281
 
        last_parent_lines = {}
282
 
        parents = {}
283
 
        parent_inclusions = {}
284
 
        parent_linenums = {}
285
 
        parent_noeols = {}
286
 
        current_hunks = {}
287
 
        diff_hunks = {}
288
 
        # its simplest to generate a full set of prepared variables.
289
 
        for i in range(nv):
290
 
            name = self._names[i]
291
 
            sha1s[name] = self.get_sha1(name)
292
 
            parents_list = self.get_parents(name)
293
 
            try:
294
 
                parent = parents_list[0]
295
 
                parents[name] = parent
296
 
                parent_inclusions[name] = inclusions[parent]
297
 
            except IndexError:
298
 
                parents[name] = None
299
 
                parent_inclusions[name] = set()
300
 
            # we want to emit start, finish, replacement_length, replacement_lines tuples.
301
 
            diff_hunks[name] = []
302
 
            current_hunks[name] = [0, 0, 0, []] # #start, finish, repl_length, repl_tuples
303
 
            parent_linenums[name] = 0
304
 
            noeols[name] = False
305
 
            parent_noeols[name] = False
306
 
            last_parent_lines[name] = None
307
 
            new_inc = set([name])
308
 
            for p in self._parents[i]:
309
 
                new_inc.update(inclusions[self._idx_to_name(p)])
310
 
            # debug only, known good so far.
311
 
            #assert set(new_inc) == set(self.get_ancestry(name)), \
312
 
            #    'failed %s != %s' % (set(new_inc), set(self.get_ancestry(name)))
313
 
            inclusions[name] = new_inc
314
 
 
315
 
        nlines = len(self._weave)
316
 
 
317
 
        for lineno, inserted, deletes, line in self._walk_internal():
318
 
            # a line is active in a version if:
319
 
            # insert is in the versions inclusions
320
 
            # and
321
 
            # deleteset & the versions inclusions is an empty set.
322
 
            # so - if we have a included by mapping - version is included by
323
 
            # children, we get a list of children to examine for deletes affect
324
 
            # ing them, which is less than the entire set of children.
325
 
            for version_id in version_ids:  
326
 
                # The active inclusion must be an ancestor,
327
 
                # and no ancestors must have deleted this line,
328
 
                # because we don't support resurrection.
329
 
                parent_inclusion = parent_inclusions[version_id]
330
 
                inclusion = inclusions[version_id]
331
 
                parent_active = inserted in parent_inclusion and not (deletes & parent_inclusion)
332
 
                version_active = inserted in inclusion and not (deletes & inclusion)
333
 
                if not parent_active and not version_active:
334
 
                    # unrelated line of ancestry
335
 
                    continue
336
 
                elif parent_active and version_active:
337
 
                    # shared line
338
 
                    parent_linenum = parent_linenums[version_id]
339
 
                    if current_hunks[version_id] != [parent_linenum, parent_linenum, 0, []]:
340
 
                        diff_hunks[version_id].append(tuple(current_hunks[version_id]))
341
 
                    parent_linenum += 1
342
 
                    current_hunks[version_id] = [parent_linenum, parent_linenum, 0, []]
343
 
                    parent_linenums[version_id] = parent_linenum
344
 
                    try:
345
 
                        if line[-1] != '\n':
346
 
                            noeols[version_id] = True
347
 
                    except IndexError:
348
 
                        pass
349
 
                elif parent_active and not version_active:
350
 
                    # deleted line
351
 
                    current_hunks[version_id][1] += 1
352
 
                    parent_linenums[version_id] += 1
353
 
                    last_parent_lines[version_id] = line
354
 
                elif not parent_active and version_active:
355
 
                    # replacement line
356
 
                    # noeol only occurs at the end of a file because we 
357
 
                    # diff linewise. We want to show noeol changes as a
358
 
                    # empty diff unless the actual eol-less content changed.
359
 
                    theline = line
360
 
                    try:
361
 
                        if last_parent_lines[version_id][-1] != '\n':
362
 
                            parent_noeols[version_id] = True
363
 
                    except (TypeError, IndexError):
364
 
                        pass
365
 
                    try:
366
 
                        if theline[-1] != '\n':
367
 
                            noeols[version_id] = True
368
 
                    except IndexError:
369
 
                        pass
370
 
                    new_line = False
371
 
                    parent_should_go = False
372
 
 
373
 
                    if parent_noeols[version_id] == noeols[version_id]:
374
 
                        # no noeol toggle, so trust the weaves statement
375
 
                        # that this line is changed.
376
 
                        new_line = True
377
 
                        if parent_noeols[version_id]:
378
 
                            theline = theline + '\n'
379
 
                    elif parent_noeols[version_id]:
380
 
                        # parent has no eol, we do:
381
 
                        # our line is new, report as such..
382
 
                        new_line = True
383
 
                    elif noeols[version_id]:
384
 
                        # append a eol so that it looks like
385
 
                        # a normalised delta
386
 
                        theline = theline + '\n'
387
 
                        if parents[version_id] is not None:
388
 
                        #if last_parent_lines[version_id] is not None:
389
 
                            parent_should_go = True
390
 
                        if last_parent_lines[version_id] != theline:
391
 
                            # but changed anyway
392
 
                            new_line = True
393
 
                            #parent_should_go = False
394
 
                    if new_line:
395
 
                        current_hunks[version_id][2] += 1
396
 
                        current_hunks[version_id][3].append((inserted, theline))
397
 
                    if parent_should_go:
398
 
                        # last hunk last parent line is not eaten
399
 
                        current_hunks[version_id][1] -= 1
400
 
                    if current_hunks[version_id][1] < 0:
401
 
                        current_hunks[version_id][1] = 0
402
 
                        # import pdb;pdb.set_trace()
403
 
                    # assert current_hunks[version_id][1] >= 0
404
 
 
405
 
        # flush last hunk
406
 
        for i in range(nv):
407
 
            version = self._idx_to_name(i)
408
 
            if current_hunks[version] != [0, 0, 0, []]:
409
 
                diff_hunks[version].append(tuple(current_hunks[version]))
410
 
        result = {}
411
 
        for version_id in version_ids:
412
 
            result[version_id] = (
413
 
                                  parents[version_id],
414
 
                                  sha1s[version_id],
415
 
                                  noeols[version_id],
416
 
                                  diff_hunks[version_id],
417
 
                                  )
418
 
        return result
419
 
 
420
261
    def get_parents(self, version_id):
421
262
        """See VersionedFile.get_parent."""
422
263
        return map(self._idx_to_name, self._parents[self._lookup(version_id)])
437
278
        """Please use Weave.clone_text now."""
438
279
        return self.clone_text(new_rev_id, old_rev_id, parents)
439
280
 
440
 
    def _add_lines(self, version_id, parents, lines, parent_texts):
 
281
    def add_lines(self, version_id, parents, lines):
441
282
        """See VersionedFile.add_lines."""
442
283
        return self._add(version_id, lines, map(self._lookup, parents))
443
284
 
474
315
 
475
316
        # if we abort after here the (in-memory) weave will be corrupt because only
476
317
        # some fields are updated
477
 
        # XXX: FIXME implement a succeed-or-fail of the rest of this routine.
478
 
        #      - Robert Collins 20060226
479
318
        self._parents.append(parents[:])
480
319
        self._sha1s.append(sha1)
481
320
        self._names.append(version_id)
565
404
                offset += 2 + (j2 - j1)
566
405
        return new_version
567
406
 
568
 
    def _clone_text(self, new_version_id, old_version_id, parents):
 
407
    def clone_text(self, new_version_id, old_version_id, parents):
569
408
        """See VersionedFile.clone_text."""
570
409
        old_lines = self.get_text(old_version_id)
571
410
        self.add_lines(new_version_id, parents, old_lines)
572
411
 
573
412
    def _inclusions(self, versions):
574
413
        """Return set of all ancestors of given version(s)."""
575
 
        if not len(versions):
576
 
            return []
577
414
        i = set(versions)
578
415
        for v in xrange(max(versions), 0, -1):
579
416
            if v in i:
619
456
            except IndexError:
620
457
                raise IndexError("invalid version number %r" % i)
621
458
 
622
 
    def _compatible_parents(self, my_parents, other_parents):
623
 
        """During join check that other_parents are joinable with my_parents.
624
 
 
625
 
        Joinable is defined as 'is a subset of' - supersets may require 
626
 
        regeneration of diffs, but subsets do not.
627
 
        """
628
 
        return len(other_parents.difference(my_parents)) == 0
629
 
 
630
459
    def annotate(self, version_id):
631
460
        if isinstance(version_id, int):
632
461
            warn('Weave.annotate(int) is deprecated. Please use version names'
651
480
 
652
481
    @deprecated_method(zero_eight)
653
482
    def _walk(self):
654
 
        """_walk has become visit, a supported api."""
655
 
        return self._walk_internal()
656
 
 
657
 
    def iter_lines_added_or_present_in_versions(self, version_ids=None):
658
 
        """See VersionedFile.iter_lines_added_or_present_in_versions()."""
659
 
        if version_ids is None:
660
 
            version_ids = self.versions()
661
 
        version_ids = set(version_ids)
662
 
        for lineno, inserted, deletes, line in self._walk_internal(version_ids):
663
 
            # if inserted not in version_ids then it was inserted before the
664
 
            # versions we care about, but because weaves cannot represent ghosts
665
 
            # properly, we do not filter down to that
666
 
            # if inserted not in version_ids: continue
667
 
            if line[-1] != '\n':
668
 
                yield line + '\n'
669
 
            else:
670
 
                yield line
671
 
 
672
 
    #@deprecated_method(zero_eight)
 
483
        """_walk has become walk, a supported api."""
 
484
        return self.walk()
 
485
 
673
486
    def walk(self, version_ids=None):
674
487
        """See VersionedFile.walk."""
675
 
        return self._walk_internal(version_ids)
676
 
 
677
 
    def _walk_internal(self, version_ids=None):
678
 
        """Helper method for weave actions."""
679
488
        
680
489
        istack = []
681
490
        dset = set()
683
492
        lineno = 0         # line of weave, 0-based
684
493
 
685
494
        for l in self._weave:
686
 
            if l.__class__ == tuple:
 
495
            if isinstance(l, tuple):
687
496
                c, v = l
688
497
                isactive = None
689
498
                if c == '{':
690
 
                    istack.append(self._names[v])
 
499
                    istack.append(self._idx_to_name(v))
691
500
                elif c == '}':
692
501
                    istack.pop()
693
502
                elif c == '[':
694
 
                    assert self._names[v] not in dset
695
 
                    dset.add(self._names[v])
 
503
                    assert self._idx_to_name(v) not in dset
 
504
                    dset.add(self._idx_to_name(v))
696
505
                elif c == ']':
697
 
                    dset.remove(self._names[v])
 
506
                    dset.remove(self._idx_to_name(v))
698
507
                else:
699
508
                    raise WeaveFormatError('unexpected instruction %r' % v)
700
509
            else:
701
 
                assert l.__class__ in (str, unicode)
 
510
                assert isinstance(l, basestring)
702
511
                assert istack
703
 
                yield lineno, istack[-1], frozenset(dset), l
 
512
                yield lineno, istack[-1], dset.copy(), l
704
513
            lineno += 1
705
514
 
706
515
        if istack:
726
535
        included = self._inclusions(versions)
727
536
 
728
537
        istack = []
729
 
        iset = set()
730
538
        dset = set()
731
539
 
732
540
        lineno = 0         # line of weave, 0-based
737
545
 
738
546
        WFE = WeaveFormatError
739
547
 
740
 
        # wow. 
741
 
        #  449       0   4474.6820   2356.5590   bzrlib.weave:556(_extract)
742
 
        #  +285282   0   1676.8040   1676.8040   +<isinstance>
743
 
        # 1.6 seconds in 'isinstance'.
744
 
        # changing the first isinstance:
745
 
        #  449       0   2814.2660   1577.1760   bzrlib.weave:556(_extract)
746
 
        #  +140414   0    762.8050    762.8050   +<isinstance>
747
 
        # note that the inline time actually dropped (less function calls)
748
 
        # and total processing time was halved.
749
 
        # we're still spending ~1/4 of the method in isinstance though.
750
 
        # so lets hard code the acceptable string classes we expect:
751
 
        #  449       0   1202.9420    786.2930   bzrlib.weave:556(_extract)
752
 
        # +71352     0    377.5560    377.5560   +<method 'append' of 'list' 
753
 
        #                                          objects>
754
 
        # yay, down to ~1/4 the initial extract time, and our inline time
755
 
        # has shrunk again, with isinstance no longer dominating.
756
 
        # tweaking the stack inclusion test to use a set gives:
757
 
        #  449       0   1122.8030    713.0080   bzrlib.weave:556(_extract)
758
 
        # +71352     0    354.9980    354.9980   +<method 'append' of 'list' 
759
 
        #                                          objects>
760
 
        # - a 5% win, or possibly just noise. However with large istacks that
761
 
        # 'in' test could dominate, so I'm leaving this change in place -
762
 
        # when its fast enough to consider profiling big datasets we can review.
763
 
 
764
 
              
765
 
             
766
 
 
767
548
        for l in self._weave:
768
 
            if l.__class__ == tuple:
 
549
            if isinstance(l, tuple):
769
550
                c, v = l
770
551
                isactive = None
771
552
                if c == '{':
772
 
                    assert v not in iset
 
553
                    assert v not in istack
773
554
                    istack.append(v)
774
 
                    iset.add(v)
775
555
                elif c == '}':
776
 
                    iset.remove(istack.pop())
 
556
                    istack.pop()
777
557
                elif c == '[':
778
558
                    if v in included:
779
559
                        assert v not in dset
784
564
                        assert v in dset
785
565
                        dset.remove(v)
786
566
            else:
787
 
                assert l.__class__ in (str, unicode)
 
567
                assert isinstance(l, basestring)
788
568
                if isactive is None:
789
569
                    isactive = (not dset) and istack and (istack[-1] in included)
790
570
                if isactive:
804
584
        
805
585
        Please use get_lines now.
806
586
        """
807
 
        return iter(self.get_lines(self._maybe_lookup(name_or_index)))
 
587
        return self._get_iter(self._maybe_lookup(name_or_index))
808
588
 
809
589
    @deprecated_method(zero_eight)
810
590
    def maybe_lookup(self, name_or_index):
821
601
        else:
822
602
            return self._lookup(name_or_index)
823
603
 
 
604
    def _get_iter(self, version_id):
 
605
        """Yield lines for the specified version."""
 
606
        incls = [self._maybe_lookup(version_id)]
 
607
        if len(incls) == 1:
 
608
            index = incls[0]
 
609
            cur_sha = sha.new()
 
610
        else:
 
611
            # We don't have sha1 sums for multiple entries
 
612
            cur_sha = None
 
613
        for origin, lineno, line in self._extract(incls):
 
614
            if cur_sha:
 
615
                cur_sha.update(line)
 
616
            yield line
 
617
        if cur_sha:
 
618
            expected_sha1 = self._sha1s[index]
 
619
            measured_sha1 = cur_sha.hexdigest() 
 
620
            if measured_sha1 != expected_sha1:
 
621
                raise errors.WeaveInvalidChecksum(
 
622
                        'file %s, revision %s, expected: %s, measured %s' 
 
623
                        % (self._weave_name, self._names[index],
 
624
                           expected_sha1, measured_sha1))
 
625
 
824
626
    @deprecated_method(zero_eight)
825
627
    def get(self, version_id):
826
628
        """Please use either Weave.get_text or Weave.get_lines as desired."""
828
630
 
829
631
    def get_lines(self, version_id):
830
632
        """See VersionedFile.get_lines()."""
831
 
        int_index = self._maybe_lookup(version_id)
832
 
        result = [line for (origin, lineno, line) in self._extract([int_index])]
833
 
        expected_sha1 = self._sha1s[int_index]
834
 
        measured_sha1 = sha_strings(result)
835
 
        if measured_sha1 != expected_sha1:
836
 
            raise errors.WeaveInvalidChecksum(
837
 
                    'file %s, revision %s, expected: %s, measured %s' 
838
 
                    % (self._weave_name, version_id,
839
 
                       expected_sha1, measured_sha1))
840
 
        return result
 
633
        return list(self._get_iter(version_id))
841
634
 
842
635
    def get_sha1(self, name):
843
636
        """Get the stored sha1 sum for the given revision.
864
657
 
865
658
    def check(self, progress_bar=None):
866
659
        # TODO evaluate performance hit of using string sets in this routine.
867
 
        # TODO: check no circular inclusions
868
 
        # TODO: create a nested progress bar
 
660
        # check no circular inclusions
869
661
        for version in range(self.num_versions()):
870
662
            inclusions = list(self._parents[version])
871
663
            if inclusions:
901
693
            update_text = 'checking %s' % (short_name,)
902
694
            update_text = update_text[:25]
903
695
 
904
 
        for lineno, insert, deleteset, line in self._walk_internal():
 
696
        for lineno, insert, deleteset, line in self.walk():
905
697
            if progress_bar:
906
698
                progress_bar.update(update_text, lineno, nlines)
907
699
 
926
718
        # no lines outside of insertion blocks, that deletions are
927
719
        # properly paired, etc.
928
720
 
929
 
    def _join(self, other, pb, msg, version_ids, ignore_missing):
 
721
    def _join(self, other, pb, msg, version_ids):
930
722
        """Worker routine for join()."""
931
723
        if not other.versions():
932
724
            return          # nothing to update, easy
933
725
 
934
726
        if version_ids:
935
727
            for version_id in version_ids:
936
 
                if not other.has_version(version_id) and not ignore_missing:
 
728
                if not self.has_version(version_id):
937
729
                    raise RevisionNotPresent(version_id, self._weave_name)
938
 
        else:
939
 
            version_ids = other.versions()
 
730
        assert version_ids == None
940
731
 
941
732
        # two loops so that we do not change ourselves before verifying it
942
733
        # will be ok
943
734
        # work through in index order to make sure we get all dependencies
944
735
        names_to_join = []
945
736
        processed = 0
946
 
        # get the selected versions only that are in other.versions.
947
 
        version_ids = set(other.versions()).intersection(set(version_ids))
948
 
        # pull in the referenced graph.
949
 
        version_ids = other.get_ancestry(version_ids)
950
 
        pending_graph = [(version, other.get_parents(version)) for
951
 
                         version in version_ids]
952
 
        for name in topo_sort(pending_graph):
953
 
            other_idx = other._name_map[name]
954
 
            # returns True if we have it, False if we need it.
955
 
            if not self._check_version_consistent(other, other_idx, name):
956
 
                names_to_join.append((other_idx, name))
 
737
        for other_idx, name in enumerate(other._names):
 
738
            self._check_version_consistent(other, other_idx, name)
 
739
            sha1 = other._sha1s[other_idx]
 
740
 
957
741
            processed += 1
958
742
 
 
743
            if name in self._name_map:
 
744
                idx = self._lookup(name)
 
745
                n1 = set(map(other._idx_to_name, other._parents[other_idx]))
 
746
                n2 = set(map(self._idx_to_name, self._parents[idx]))
 
747
                if sha1 ==  self._sha1s[idx] and n1 == n2:
 
748
                        continue
 
749
 
 
750
            names_to_join.append((other_idx, name))
959
751
 
960
752
        if pb and not msg:
961
753
            msg = 'weave join'
985
777
        new_parents = []
986
778
        for parent_idx in other._parents[other_idx]:
987
779
            parent_name = other._names[parent_idx]
988
 
            if parent_name not in self._name_map:
 
780
            if parent_name not in self._names:
989
781
                # should not be possible
990
782
                raise WeaveError("missing parent {%s} of {%s} in %r" 
991
783
                                 % (parent_name, other._name_map[other_idx], self))
1012
804
            other_parents = other._parents[other_idx]
1013
805
            n1 = set([self._names[i] for i in self_parents])
1014
806
            n2 = set([other._names[i] for i in other_parents])
1015
 
            if not self._compatible_parents(n1, n2):
 
807
            if n1 != n2:
1016
808
                raise WeaveParentMismatch("inconsistent parents "
1017
809
                    "for version {%s}: %s vs %s" % (name, n1, n2))
1018
810
            else:
1033
825
        :param msg: An optional message for the progress
1034
826
        """
1035
827
        new_weave = _reweave(self, other, pb=pb, msg=msg)
1036
 
        self._copy_weave_content(new_weave)
1037
 
 
1038
 
    def _copy_weave_content(self, otherweave):
1039
 
        """adsorb the content from otherweave."""
1040
828
        for attr in self.__slots__:
1041
829
            if attr != '_weave_name':
1042
 
                setattr(self, attr, copy(getattr(otherweave, attr)))
 
830
                setattr(self, attr, getattr(new_weave, attr))
1043
831
 
1044
832
 
1045
833
class WeaveFile(Weave):
1047
835
 
1048
836
    WEAVE_SUFFIX = '.weave'
1049
837
    
1050
 
    def __init__(self, name, transport, filemode=None, create=False, access_mode='w'):
1051
 
        """Create a WeaveFile.
1052
 
        
1053
 
        :param create: If not True, only open an existing knit.
1054
 
        """
1055
 
        super(WeaveFile, self).__init__(name, access_mode)
 
838
    def __init__(self, name, transport, mode=None):
 
839
        super(WeaveFile, self).__init__(name)
1056
840
        self._transport = transport
1057
 
        self._filemode = filemode
 
841
        self._mode = mode
1058
842
        try:
1059
843
            _read_weave_v5(self._transport.get(name + WeaveFile.WEAVE_SUFFIX), self)
1060
844
        except errors.NoSuchFile:
1061
 
            if not create:
1062
 
                raise
1063
845
            # new file, save it
1064
846
            self._save()
1065
847
 
1066
 
    def _add_lines(self, version_id, parents, lines, parent_texts):
 
848
    def add_lines(self, version_id, parents, lines):
1067
849
        """Add a version and save the weave."""
1068
 
        result = super(WeaveFile, self)._add_lines(version_id, parents, lines,
1069
 
                                                   parent_texts)
 
850
        super(WeaveFile, self).add_lines(version_id, parents, lines)
1070
851
        self._save()
1071
 
        return result
1072
 
 
1073
 
    def _clone_text(self, new_version_id, old_version_id, parents):
1074
 
        """See VersionedFile.clone_text."""
1075
 
        super(WeaveFile, self)._clone_text(new_version_id, old_version_id, parents)
1076
 
        self._save
1077
852
 
1078
853
    def copy_to(self, name, transport):
1079
854
        """See VersionedFile.copy_to()."""
1081
856
        sio = StringIO()
1082
857
        write_weave_v5(self, sio)
1083
858
        sio.seek(0)
1084
 
        transport.put(name + WeaveFile.WEAVE_SUFFIX, sio, self._filemode)
 
859
        transport.put(name + WeaveFile.WEAVE_SUFFIX, sio, self._mode)
1085
860
 
1086
 
    def create_empty(self, name, transport, filemode=None):
1087
 
        return WeaveFile(name, transport, filemode, create=True)
 
861
    def create_empty(self, name, transport, mode=None):
 
862
        return WeaveFile(name, transport, mode)
1088
863
 
1089
864
    def _save(self):
1090
865
        """Save the weave."""
1091
 
        self._check_write_ok()
1092
866
        sio = StringIO()
1093
867
        write_weave_v5(self, sio)
1094
868
        sio.seek(0)
1095
869
        self._transport.put(self._weave_name + WeaveFile.WEAVE_SUFFIX,
1096
870
                            sio,
1097
 
                            self._filemode)
 
871
                            self._mode)
1098
872
 
1099
873
    @staticmethod
1100
874
    def get_suffixes():
1101
875
        """See VersionedFile.get_suffixes()."""
1102
876
        return [WeaveFile.WEAVE_SUFFIX]
1103
877
 
1104
 
    def join(self, other, pb=None, msg=None, version_ids=None,
1105
 
             ignore_missing=False):
 
878
    def join(self, other, pb=None, msg=None, version_ids=None):
1106
879
        """Join other into self and save."""
1107
 
        super(WeaveFile, self).join(other, pb, msg, version_ids, ignore_missing)
 
880
        super(WeaveFile, self).join(other, pb, msg, version_ids)
1108
881
        self._save()
1109
882
 
1110
883
 
1359
1132
        print ' '.join(map(str, w._parents[int(argv[3])]))
1360
1133
 
1361
1134
    elif cmd == 'plan-merge':
1362
 
        # replaced by 'bzr weave-plan-merge'
1363
1135
        w = readit()
1364
1136
        for state, line in w.plan_merge(int(argv[3]), int(argv[4])):
1365
1137
            if line:
1366
1138
                print '%14s | %s' % (state, line),
 
1139
 
1367
1140
    elif cmd == 'merge':
1368
 
        # replaced by 'bzr weave-merge-text'
1369
1141
        w = readit()
1370
1142
        p = w.plan_merge(int(argv[3]), int(argv[4]))
1371
1143
        sys.stdout.writelines(w.weave_merge(p))
 
1144
            
1372
1145
    else:
1373
1146
        raise ValueError('unknown command %r' % cmd)
1374
1147
    
1375
1148
 
1376
1149
 
1377
 
def profile_main(argv):
 
1150
def profile_main(argv): 
1378
1151
    import tempfile, hotshot, hotshot.stats
1379
1152
 
1380
1153
    prof_f = tempfile.NamedTemporaryFile()
1430
1203
        except AttributeError:
1431
1204
            return False
1432
1205
 
1433
 
    def join(self, pb=None, msg=None, version_ids=None, ignore_missing=False):
 
1206
    def join(self, pb=None, msg=None, version_ids=None):
1434
1207
        """See InterVersionedFile.join."""
1435
 
        if self.target.versions() == []:
1436
 
            # optimised copy
1437
 
            self.target._copy_weave_content(self.source)
1438
 
            return
1439
1208
        try:
1440
 
            self.target._join(self.source, pb, msg, version_ids, ignore_missing)
 
1209
            self.target._join(self.source, pb, msg, version_ids)
1441
1210
        except errors.WeaveParentMismatch:
1442
1211
            self.target._reweave(self.source, pb, msg)
1443
1212