~bzr-pqm/bzr/bzr.dev

« back to all changes in this revision

Viewing changes to bzrlib/weave.py

  • Committer: Robert Collins
  • Date: 2006-04-18 22:41:16 UTC
  • mto: (1711.1.1 integration)
  • mto: This revision was merged to the branch mainline in revision 1671.
  • Revision ID: robertc@robertcollins.net-20060418224116-9b723440fa56e404
 * 'Metadir' is now the default disk format. This improves behaviour in
   SFTP using circumstances and allows binding and rebinding and easier
   use of repositories. (Robert Collins, Aaron Bentley).

Show diffs side-by-side

added added

removed removed

Lines of Context:
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 accommodate
 
30
# rather than being split up in some other way.  We could accomodate
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
73
74
import os
74
75
import sha
75
76
import time
76
 
import warnings
77
77
 
78
78
from bzrlib.trace import mutter
79
79
from bzrlib.errors import (WeaveError, WeaveFormatError, WeaveParentMismatch,
84
84
        )
85
85
import bzrlib.errors as errors
86
86
from bzrlib.osutils import sha_strings
87
 
import bzrlib.patiencediff
88
 
from bzrlib.symbol_versioning import (deprecated_method,
89
 
        deprecated_function,
90
 
        zero_eight,
91
 
        )
 
87
from bzrlib.symbol_versioning import *
92
88
from bzrlib.tsort import topo_sort
93
89
from bzrlib.versionedfile import VersionedFile, InterVersionedFile
94
90
from bzrlib.weavefile import _read_weave_v5, write_weave_v5
184
180
    """
185
181
 
186
182
    __slots__ = ['_weave', '_parents', '_sha1s', '_names', '_name_map',
187
 
                 '_weave_name', '_matcher']
 
183
                 '_weave_name']
188
184
    
189
 
    def __init__(self, weave_name=None, access_mode='w', matcher=None):
 
185
    def __init__(self, weave_name=None, access_mode='w'):
190
186
        super(Weave, self).__init__(access_mode)
191
187
        self._weave = []
192
188
        self._parents = []
194
190
        self._names = []
195
191
        self._name_map = {}
196
192
        self._weave_name = weave_name
197
 
        if matcher is None:
198
 
            self._matcher = bzrlib.patiencediff.PatienceSequenceMatcher
199
 
        else:
200
 
            self._matcher = matcher
201
193
 
202
194
    def __repr__(self):
203
195
        return "Weave(%r)" % self._weave_name
235
227
 
236
228
    @deprecated_method(zero_eight)
237
229
    def lookup(self, name):
238
 
        """Backwards compatibility thunk:
 
230
        """Backwards compatability thunk:
239
231
 
240
232
        Return name, as name is valid in the api now, and spew deprecation
241
233
        warnings everywhere.
471
463
        """
472
464
 
473
465
        assert isinstance(version_id, basestring)
474
 
        self._check_lines_not_unicode(lines)
475
 
        self._check_lines_are_lines(lines)
476
466
        if not sha1:
477
467
            sha1 = sha_strings(lines)
478
468
        if version_id in self._name_map:
526
516
        if lines == basis_lines:
527
517
            return new_version            
528
518
 
529
 
        # add a sentinel, because we can also match against the final line
 
519
        # add a sentinal, because we can also match against the final line
530
520
        basis_lineno.append(len(self._weave))
531
521
 
532
522
        # XXX: which line of the weave should we really consider
536
526
        #print 'basis_lines:', basis_lines
537
527
        #print 'new_lines:  ', lines
538
528
 
539
 
        s = self._matcher(None, basis_lines, lines)
 
529
        s = SequenceMatcher(None, basis_lines, lines)
540
530
 
541
531
        # offset gives the number of lines that have been inserted
542
532
        # into the weave up to the current point; if the original edit instruction
639
629
 
640
630
    def annotate(self, version_id):
641
631
        if isinstance(version_id, int):
642
 
            warnings.warn('Weave.annotate(int) is deprecated. Please use version names'
 
632
            warn('Weave.annotate(int) is deprecated. Please use version names'
643
633
                 ' in all circumstances as of 0.8',
644
634
                 DeprecationWarning,
645
635
                 stacklevel=2
720
710
            raise WeaveFormatError("unclosed deletion blocks at end of weave: %s"
721
711
                                   % dset)
722
712
 
723
 
    def plan_merge(self, ver_a, ver_b):
724
 
        """Return pseudo-annotation indicating how the two versions merge.
725
 
 
726
 
        This is computed between versions a and b and their common
727
 
        base.
728
 
 
729
 
        Weave lines present in none of them are skipped entirely.
730
 
        """
731
 
        inc_a = set(self.get_ancestry([ver_a]))
732
 
        inc_b = set(self.get_ancestry([ver_b]))
733
 
        inc_c = inc_a & inc_b
734
 
 
735
 
        for lineno, insert, deleteset, line in\
736
 
            self.walk([ver_a, ver_b]):
737
 
            if deleteset & inc_c:
738
 
                # killed in parent; can't be in either a or b
739
 
                # not relevant to our work
740
 
                yield 'killed-base', line
741
 
            elif insert in inc_c:
742
 
                # was inserted in base
743
 
                killed_a = bool(deleteset & inc_a)
744
 
                killed_b = bool(deleteset & inc_b)
745
 
                if killed_a and killed_b:
746
 
                    yield 'killed-both', line
747
 
                elif killed_a:
748
 
                    yield 'killed-a', line
749
 
                elif killed_b:
750
 
                    yield 'killed-b', line
751
 
                else:
752
 
                    yield 'unchanged', line
753
 
            elif insert in inc_a:
754
 
                if deleteset & inc_a:
755
 
                    yield 'ghost-a', line
756
 
                else:
757
 
                    # new in A; not in B
758
 
                    yield 'new-a', line
759
 
            elif insert in inc_b:
760
 
                if deleteset & inc_b:
761
 
                    yield 'ghost-b', line
762
 
                else:
763
 
                    yield 'new-b', line
764
 
            else:
765
 
                # not in either revision
766
 
                yield 'irrelevant', line
767
 
 
768
 
        yield 'unchanged', ''           # terminator
769
 
 
770
713
    def _extract(self, versions):
771
714
        """Yield annotation of lines in included set.
772
715
 
896
839
                       expected_sha1, measured_sha1))
897
840
        return result
898
841
 
899
 
    def get_sha1(self, version_id):
900
 
        """See VersionedFile.get_sha1()."""
901
 
        return self._sha1s[self._lookup(version_id)]
 
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)]
902
848
 
903
849
    @deprecated_method(zero_eight)
904
850
    def numversions(self):
985
931
        if not other.versions():
986
932
            return          # nothing to update, easy
987
933
 
988
 
        if not version_ids:
989
 
            # versions is never none, InterWeave checks this.
990
 
            return 0
 
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()
991
940
 
992
941
        # two loops so that we do not change ourselves before verifying it
993
942
        # will be ok
1073
1022
 
1074
1023
    @deprecated_method(zero_eight)
1075
1024
    def reweave(self, other, pb=None, msg=None):
1076
 
        """reweave has been superseded by plain use of join."""
 
1025
        """reweave has been superceded by plain use of join."""
1077
1026
        return self.join(other, pb, msg)
1078
1027
 
1079
1028
    def _reweave(self, other, pb, msg):
1243
1192
    from bzrlib.weavefile import read_weave
1244
1193
 
1245
1194
    wf = file(weave_file, 'rb')
1246
 
    w = read_weave(wf)
 
1195
    w = read_weave(wf, WeaveVersionedFile)
1247
1196
    # FIXME: doesn't work on pipes
1248
1197
    weave_size = wf.tell()
1249
1198
 
1364
1313
        sys.stdout.writelines(w.get_iter(int(argv[3])))
1365
1314
        
1366
1315
    elif cmd == 'diff':
 
1316
        from difflib import unified_diff
1367
1317
        w = readit()
1368
1318
        fn = argv[2]
1369
1319
        v1, v2 = map(int, argv[3:5])
1370
1320
        lines1 = w.get(v1)
1371
1321
        lines2 = w.get(v2)
1372
 
        diff_gen = bzrlib.patiencediff.unified_diff(lines1, lines2,
 
1322
        diff_gen = unified_diff(lines1, lines2,
1373
1323
                                '%s version %d' % (fn, v1),
1374
1324
                                '%s version %d' % (fn, v2))
1375
1325
        sys.stdout.writelines(diff_gen)
1423
1373
        raise ValueError('unknown command %r' % cmd)
1424
1374
    
1425
1375
 
 
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
 
1426
1405
if __name__ == '__main__':
1427
1406
    import sys
1428
 
    sys.exit(main(sys.argv))
 
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))
1429
1417
 
1430
1418
 
1431
1419
class InterWeave(InterVersionedFile):
1432
1420
    """Optimised code paths for weave to weave operations."""
1433
1421
    
1434
 
    _matching_file_from_factory = staticmethod(WeaveFile)
1435
 
    _matching_file_to_factory = staticmethod(WeaveFile)
 
1422
    _matching_file_factory = staticmethod(WeaveFile)
1436
1423
    
1437
1424
    @staticmethod
1438
1425
    def is_compatible(source, target):
1445
1432
 
1446
1433
    def join(self, pb=None, msg=None, version_ids=None, ignore_missing=False):
1447
1434
        """See InterVersionedFile.join."""
1448
 
        version_ids = self._get_source_version_ids(version_ids, ignore_missing)
1449
 
        if self.target.versions() == [] and version_ids is None:
 
1435
        if self.target.versions() == []:
 
1436
            # optimised copy
1450
1437
            self.target._copy_weave_content(self.source)
1451
1438
            return
1452
1439
        try: