/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: Martin Pool
  • Date: 2006-10-06 02:04:17 UTC
  • mfrom: (1908.10.1 bench_usecases.merge2)
  • mto: This revision was merged to the branch mainline in revision 2068.
  • Revision ID: mbp@sourcefrog.net-20061006020417-4949ca86f4417a4d
merge additional fix from cfbolz

Show diffs side-by-side

added added

removed removed

Lines of Context:
1
1
#! /usr/bin/python
2
2
 
3
3
# Copyright (C) 2005 Canonical Ltd
4
 
 
 
4
#
5
5
# This program is free software; you can redistribute it and/or modify
6
6
# it under the terms of the GNU General Public License as published by
7
7
# the Free Software Foundation; either version 2 of the License, or
8
8
# (at your option) any later version.
9
 
 
 
9
#
10
10
# This program is distributed in the hope that it will be useful,
11
11
# but WITHOUT ANY WARRANTY; without even the implied warranty of
12
12
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
13
13
# GNU General Public License for more details.
14
 
 
 
14
#
15
15
# You should have received a copy of the GNU General Public License
16
16
# along with this program; if not, write to the Free Software
17
17
# Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
27
27
# property.
28
28
 
29
29
# TODO: Nothing here so far assumes the lines are really \n newlines,
30
 
# rather than being split up in some other way.  We could accomodate
 
30
# rather than being split up in some other way.  We could accommodate
31
31
# binaries, perhaps by naively splitting on \n or perhaps using
32
32
# something like a rolling checksum.
33
33
 
70
70
 
71
71
from copy import copy
72
72
from cStringIO import StringIO
73
 
from difflib import SequenceMatcher
74
73
import os
75
74
import sha
76
75
import time
 
76
import warnings
77
77
 
 
78
from bzrlib import (
 
79
    progress,
 
80
    )
78
81
from bzrlib.trace import mutter
79
82
from bzrlib.errors import (WeaveError, WeaveFormatError, WeaveParentMismatch,
80
83
        RevisionAlreadyPresent,
84
87
        )
85
88
import bzrlib.errors as errors
86
89
from bzrlib.osutils import sha_strings
87
 
from bzrlib.symbol_versioning import *
 
90
import bzrlib.patiencediff
 
91
from bzrlib.symbol_versioning import (deprecated_method,
 
92
        deprecated_function,
 
93
        zero_eight,
 
94
        )
88
95
from bzrlib.tsort import topo_sort
89
96
from bzrlib.versionedfile import VersionedFile, InterVersionedFile
90
97
from bzrlib.weavefile import _read_weave_v5, write_weave_v5
180
187
    """
181
188
 
182
189
    __slots__ = ['_weave', '_parents', '_sha1s', '_names', '_name_map',
183
 
                 '_weave_name']
 
190
                 '_weave_name', '_matcher']
184
191
    
185
 
    def __init__(self, weave_name=None, access_mode='w'):
 
192
    def __init__(self, weave_name=None, access_mode='w', matcher=None):
186
193
        super(Weave, self).__init__(access_mode)
187
194
        self._weave = []
188
195
        self._parents = []
190
197
        self._names = []
191
198
        self._name_map = {}
192
199
        self._weave_name = weave_name
 
200
        if matcher is None:
 
201
            self._matcher = bzrlib.patiencediff.PatienceSequenceMatcher
 
202
        else:
 
203
            self._matcher = matcher
193
204
 
194
205
    def __repr__(self):
195
206
        return "Weave(%r)" % self._weave_name
227
238
 
228
239
    @deprecated_method(zero_eight)
229
240
    def lookup(self, name):
230
 
        """Backwards compatability thunk:
 
241
        """Backwards compatibility thunk:
231
242
 
232
243
        Return name, as name is valid in the api now, and spew deprecation
233
244
        warnings everywhere.
257
268
 
258
269
    def has_version(self, version_id):
259
270
        """See VersionedFile.has_version."""
260
 
        return self._name_map.has_key(version_id)
 
271
        return (version_id in self._name_map)
261
272
 
262
273
    __contains__ = has_version
263
274
 
463
474
        """
464
475
 
465
476
        assert isinstance(version_id, basestring)
 
477
        self._check_lines_not_unicode(lines)
 
478
        self._check_lines_are_lines(lines)
466
479
        if not sha1:
467
480
            sha1 = sha_strings(lines)
468
481
        if version_id in self._name_map:
516
529
        if lines == basis_lines:
517
530
            return new_version            
518
531
 
519
 
        # add a sentinal, because we can also match against the final line
 
532
        # add a sentinel, because we can also match against the final line
520
533
        basis_lineno.append(len(self._weave))
521
534
 
522
535
        # XXX: which line of the weave should we really consider
526
539
        #print 'basis_lines:', basis_lines
527
540
        #print 'new_lines:  ', lines
528
541
 
529
 
        s = SequenceMatcher(None, basis_lines, lines)
 
542
        s = self._matcher(None, basis_lines, lines)
530
543
 
531
544
        # offset gives the number of lines that have been inserted
532
545
        # into the weave up to the current point; if the original edit instruction
629
642
 
630
643
    def annotate(self, version_id):
631
644
        if isinstance(version_id, int):
632
 
            warn('Weave.annotate(int) is deprecated. Please use version names'
 
645
            warnings.warn('Weave.annotate(int) is deprecated. Please use version names'
633
646
                 ' in all circumstances as of 0.8',
634
647
                 DeprecationWarning,
635
648
                 stacklevel=2
654
667
        """_walk has become visit, a supported api."""
655
668
        return self._walk_internal()
656
669
 
657
 
    def iter_lines_added_or_present_in_versions(self, version_ids=None):
 
670
    def iter_lines_added_or_present_in_versions(self, version_ids=None,
 
671
                                                pb=None):
658
672
        """See VersionedFile.iter_lines_added_or_present_in_versions()."""
659
673
        if version_ids is None:
660
674
            version_ids = self.versions()
710
724
            raise WeaveFormatError("unclosed deletion blocks at end of weave: %s"
711
725
                                   % dset)
712
726
 
 
727
    def plan_merge(self, ver_a, ver_b):
 
728
        """Return pseudo-annotation indicating how the two versions merge.
 
729
 
 
730
        This is computed between versions a and b and their common
 
731
        base.
 
732
 
 
733
        Weave lines present in none of them are skipped entirely.
 
734
        """
 
735
        inc_a = set(self.get_ancestry([ver_a]))
 
736
        inc_b = set(self.get_ancestry([ver_b]))
 
737
        inc_c = inc_a & inc_b
 
738
 
 
739
        for lineno, insert, deleteset, line in\
 
740
            self.walk([ver_a, ver_b]):
 
741
            if deleteset & inc_c:
 
742
                # killed in parent; can't be in either a or b
 
743
                # not relevant to our work
 
744
                yield 'killed-base', line
 
745
            elif insert in inc_c:
 
746
                # was inserted in base
 
747
                killed_a = bool(deleteset & inc_a)
 
748
                killed_b = bool(deleteset & inc_b)
 
749
                if killed_a and killed_b:
 
750
                    yield 'killed-both', line
 
751
                elif killed_a:
 
752
                    yield 'killed-a', line
 
753
                elif killed_b:
 
754
                    yield 'killed-b', line
 
755
                else:
 
756
                    yield 'unchanged', line
 
757
            elif insert in inc_a:
 
758
                if deleteset & inc_a:
 
759
                    yield 'ghost-a', line
 
760
                else:
 
761
                    # new in A; not in B
 
762
                    yield 'new-a', line
 
763
            elif insert in inc_b:
 
764
                if deleteset & inc_b:
 
765
                    yield 'ghost-b', line
 
766
                else:
 
767
                    yield 'new-b', line
 
768
            else:
 
769
                # not in either revision
 
770
                yield 'irrelevant', line
 
771
 
 
772
        yield 'unchanged', ''           # terminator
 
773
 
713
774
    def _extract(self, versions):
714
775
        """Yield annotation of lines in included set.
715
776
 
839
900
                       expected_sha1, measured_sha1))
840
901
        return result
841
902
 
842
 
    def get_sha1(self, name):
843
 
        """Get the stored sha1 sum for the given revision.
844
 
        
845
 
        :param name: The name of the version to lookup
846
 
        """
847
 
        return self._sha1s[self._lookup(name)]
 
903
    def get_sha1(self, version_id):
 
904
        """See VersionedFile.get_sha1()."""
 
905
        return self._sha1s[self._lookup(version_id)]
848
906
 
849
907
    @deprecated_method(zero_eight)
850
908
    def numversions(self):
931
989
        if not other.versions():
932
990
            return          # nothing to update, easy
933
991
 
934
 
        if version_ids:
935
 
            for version_id in version_ids:
936
 
                if not other.has_version(version_id) and not ignore_missing:
937
 
                    raise RevisionNotPresent(version_id, self._weave_name)
938
 
        else:
939
 
            version_ids = other.versions()
 
992
        if not version_ids:
 
993
            # versions is never none, InterWeave checks this.
 
994
            return 0
940
995
 
941
996
        # two loops so that we do not change ourselves before verifying it
942
997
        # will be ok
1022
1077
 
1023
1078
    @deprecated_method(zero_eight)
1024
1079
    def reweave(self, other, pb=None, msg=None):
1025
 
        """reweave has been superceded by plain use of join."""
 
1080
        """reweave has been superseded by plain use of join."""
1026
1081
        return self.join(other, pb, msg)
1027
1082
 
1028
1083
    def _reweave(self, other, pb, msg):
1081
1136
        sio = StringIO()
1082
1137
        write_weave_v5(self, sio)
1083
1138
        sio.seek(0)
1084
 
        transport.put(name + WeaveFile.WEAVE_SUFFIX, sio, self._filemode)
 
1139
        transport.put_file(name + WeaveFile.WEAVE_SUFFIX, sio, self._filemode)
1085
1140
 
1086
1141
    def create_empty(self, name, transport, filemode=None):
1087
1142
        return WeaveFile(name, transport, filemode, create=True)
1092
1147
        sio = StringIO()
1093
1148
        write_weave_v5(self, sio)
1094
1149
        sio.seek(0)
1095
 
        self._transport.put(self._weave_name + WeaveFile.WEAVE_SUFFIX,
1096
 
                            sio,
1097
 
                            self._filemode)
 
1150
        self._transport.put_file(self._weave_name + WeaveFile.WEAVE_SUFFIX,
 
1151
                                 sio,
 
1152
                                 self._filemode)
1098
1153
 
1099
1154
    @staticmethod
1100
1155
    def get_suffixes():
1192
1247
    from bzrlib.weavefile import read_weave
1193
1248
 
1194
1249
    wf = file(weave_file, 'rb')
1195
 
    w = read_weave(wf, WeaveVersionedFile)
 
1250
    w = read_weave(wf)
1196
1251
    # FIXME: doesn't work on pipes
1197
1252
    weave_size = wf.tell()
1198
1253
 
1313
1368
        sys.stdout.writelines(w.get_iter(int(argv[3])))
1314
1369
        
1315
1370
    elif cmd == 'diff':
1316
 
        from difflib import unified_diff
1317
1371
        w = readit()
1318
1372
        fn = argv[2]
1319
1373
        v1, v2 = map(int, argv[3:5])
1320
1374
        lines1 = w.get(v1)
1321
1375
        lines2 = w.get(v2)
1322
 
        diff_gen = unified_diff(lines1, lines2,
 
1376
        diff_gen = bzrlib.patiencediff.unified_diff(lines1, lines2,
1323
1377
                                '%s version %d' % (fn, v1),
1324
1378
                                '%s version %d' % (fn, v2))
1325
1379
        sys.stdout.writelines(diff_gen)
1373
1427
        raise ValueError('unknown command %r' % cmd)
1374
1428
    
1375
1429
 
1376
 
 
1377
 
def profile_main(argv):
1378
 
    import tempfile, hotshot, hotshot.stats
1379
 
 
1380
 
    prof_f = tempfile.NamedTemporaryFile()
1381
 
 
1382
 
    prof = hotshot.Profile(prof_f.name)
1383
 
 
1384
 
    ret = prof.runcall(main, argv)
1385
 
    prof.close()
1386
 
 
1387
 
    stats = hotshot.stats.load(prof_f.name)
1388
 
    #stats.strip_dirs()
1389
 
    stats.sort_stats('cumulative')
1390
 
    ## XXX: Might like to write to stderr or the trace file instead but
1391
 
    ## print_stats seems hardcoded to stdout
1392
 
    stats.print_stats(20)
1393
 
            
1394
 
    return ret
1395
 
 
1396
 
 
1397
 
def lsprofile_main(argv): 
1398
 
    from bzrlib.lsprof import profile
1399
 
    ret,stats = profile(main, argv)
1400
 
    stats.sort()
1401
 
    stats.pprint()
1402
 
    return ret
1403
 
 
1404
 
 
1405
1430
if __name__ == '__main__':
1406
1431
    import sys
1407
 
    if '--profile' in sys.argv:
1408
 
        args = sys.argv[:]
1409
 
        args.remove('--profile')
1410
 
        sys.exit(profile_main(args))
1411
 
    elif '--lsprof' in sys.argv:
1412
 
        args = sys.argv[:]
1413
 
        args.remove('--lsprof')
1414
 
        sys.exit(lsprofile_main(args))
1415
 
    else:
1416
 
        sys.exit(main(sys.argv))
 
1432
    sys.exit(main(sys.argv))
1417
1433
 
1418
1434
 
1419
1435
class InterWeave(InterVersionedFile):
1420
1436
    """Optimised code paths for weave to weave operations."""
1421
1437
    
1422
 
    _matching_file_factory = staticmethod(WeaveFile)
 
1438
    _matching_file_from_factory = staticmethod(WeaveFile)
 
1439
    _matching_file_to_factory = staticmethod(WeaveFile)
1423
1440
    
1424
1441
    @staticmethod
1425
1442
    def is_compatible(source, target):
1432
1449
 
1433
1450
    def join(self, pb=None, msg=None, version_ids=None, ignore_missing=False):
1434
1451
        """See InterVersionedFile.join."""
1435
 
        if self.target.versions() == []:
1436
 
            # optimised copy
 
1452
        version_ids = self._get_source_version_ids(version_ids, ignore_missing)
 
1453
        if self.target.versions() == [] and version_ids is None:
1437
1454
            self.target._copy_weave_content(self.source)
1438
1455
            return
1439
1456
        try: