~bzr-pqm/bzr/bzr.dev

« back to all changes in this revision

Viewing changes to bzrlib/branch.py

  • Committer: Martin Pool
  • Date: 2010-01-29 14:09:05 UTC
  • mto: This revision was merged to the branch mainline in revision 4992.
  • Revision ID: mbp@sourcefrog.net-20100129140905-2uiarb6p8di1ywsr
Correction to url

from review: https://code.edge.launchpad.net/~mbp/bzr/doc/+merge/18250

Show diffs side-by-side

added added

removed removed

Lines of Context:
46
46
    )
47
47
""")
48
48
 
49
 
from bzrlib.decorators import needs_read_lock, needs_write_lock
 
49
from bzrlib.decorators import needs_read_lock, needs_write_lock, only_raises
50
50
from bzrlib.hooks import HookPoint, Hooks
51
51
from bzrlib.inter import InterObject
 
52
from bzrlib.lock import _RelockDebugMixin
52
53
from bzrlib import registry
53
54
from bzrlib.symbol_versioning import (
54
55
    deprecated_in,
446
447
        # start_revision_id.
447
448
        if self._merge_sorted_revisions_cache is None:
448
449
            last_revision = self.last_revision()
449
 
            graph = self.repository.get_graph()
450
 
            parent_map = dict(((key, value) for key, value in
451
 
                     graph.iter_ancestry([last_revision]) if value is not None))
452
 
            revision_graph = repository._strip_NULL_ghosts(parent_map)
453
 
            revs = tsort.merge_sort(revision_graph, last_revision, None,
454
 
                generate_revno=True)
455
 
            # Drop the sequence # before caching
456
 
            self._merge_sorted_revisions_cache = [r[1:] for r in revs]
457
 
 
 
450
            last_key = (last_revision,)
 
451
            known_graph = self.repository.revisions.get_known_graph_ancestry(
 
452
                [last_key])
 
453
            self._merge_sorted_revisions_cache = known_graph.merge_sort(
 
454
                last_key)
458
455
        filtered = self._filter_merge_sorted_revisions(
459
456
            self._merge_sorted_revisions_cache, start_revision_id,
460
457
            stop_revision_id, stop_rule)
470
467
        """Iterate over an inclusive range of sorted revisions."""
471
468
        rev_iter = iter(merge_sorted_revisions)
472
469
        if start_revision_id is not None:
473
 
            for rev_id, depth, revno, end_of_merge in rev_iter:
 
470
            for node in rev_iter:
 
471
                rev_id = node.key[-1]
474
472
                if rev_id != start_revision_id:
475
473
                    continue
476
474
                else:
477
475
                    # The decision to include the start or not
478
476
                    # depends on the stop_rule if a stop is provided
479
 
                    rev_iter = chain(
480
 
                        iter([(rev_id, depth, revno, end_of_merge)]),
481
 
                        rev_iter)
 
477
                    # so pop this node back into the iterator
 
478
                    rev_iter = chain(iter([node]), rev_iter)
482
479
                    break
483
480
        if stop_revision_id is None:
484
 
            for rev_id, depth, revno, end_of_merge in rev_iter:
485
 
                yield rev_id, depth, revno, end_of_merge
 
481
            # Yield everything
 
482
            for node in rev_iter:
 
483
                rev_id = node.key[-1]
 
484
                yield (rev_id, node.merge_depth, node.revno,
 
485
                       node.end_of_merge)
486
486
        elif stop_rule == 'exclude':
487
 
            for rev_id, depth, revno, end_of_merge in rev_iter:
 
487
            for node in rev_iter:
 
488
                rev_id = node.key[-1]
488
489
                if rev_id == stop_revision_id:
489
490
                    return
490
 
                yield rev_id, depth, revno, end_of_merge
 
491
                yield (rev_id, node.merge_depth, node.revno,
 
492
                       node.end_of_merge)
491
493
        elif stop_rule == 'include':
492
 
            for rev_id, depth, revno, end_of_merge in rev_iter:
493
 
                yield rev_id, depth, revno, end_of_merge
 
494
            for node in rev_iter:
 
495
                rev_id = node.key[-1]
 
496
                yield (rev_id, node.merge_depth, node.revno,
 
497
                       node.end_of_merge)
494
498
                if rev_id == stop_revision_id:
495
499
                    return
496
500
        elif stop_rule == 'with-merges':
499
503
                left_parent = stop_rev.parent_ids[0]
500
504
            else:
501
505
                left_parent = _mod_revision.NULL_REVISION
502
 
            for rev_id, depth, revno, end_of_merge in rev_iter:
 
506
            # left_parent is the actual revision we want to stop logging at,
 
507
            # since we want to show the merged revisions after the stop_rev too
 
508
            reached_stop_revision_id = False
 
509
            revision_id_whitelist = []
 
510
            for node in rev_iter:
 
511
                rev_id = node.key[-1]
503
512
                if rev_id == left_parent:
 
513
                    # reached the left parent after the stop_revision
504
514
                    return
505
 
                yield rev_id, depth, revno, end_of_merge
 
515
                if (not reached_stop_revision_id or
 
516
                        rev_id in revision_id_whitelist):
 
517
                    yield (rev_id, node.merge_depth, node.revno,
 
518
                       node.end_of_merge)
 
519
                    if reached_stop_revision_id or rev_id == stop_revision_id:
 
520
                        # only do the merged revs of rev_id from now on
 
521
                        rev = self.repository.get_revision(rev_id)
 
522
                        if rev.parent_ids:
 
523
                            reached_stop_revision_id = True
 
524
                            revision_id_whitelist.extend(rev.parent_ids)
506
525
        else:
507
526
            raise ValueError('invalid stop_rule %r' % stop_rule)
508
527
 
1084
1103
        params = ChangeBranchTipParams(
1085
1104
            self, old_revno, new_revno, old_revid, new_revid)
1086
1105
        for hook in hooks:
1087
 
            try:
1088
 
                hook(params)
1089
 
            except errors.TipChangeRejected:
1090
 
                raise
1091
 
            except Exception:
1092
 
                exc_info = sys.exc_info()
1093
 
                hook_name = Branch.hooks.get_hook_name(hook)
1094
 
                raise errors.HookFailed(
1095
 
                    'pre_change_branch_tip', hook_name, exc_info)
 
1106
            hook(params)
1096
1107
 
1097
1108
    @needs_write_lock
1098
1109
    def update(self):
1147
1158
        revision_id: if not None, the revision history in the new branch will
1148
1159
                     be truncated to end with revision_id.
1149
1160
        """
 
1161
        if (repository_policy is not None and
 
1162
            repository_policy.requires_stacking()):
 
1163
            to_bzrdir._format.require_stacking(_skip_repo=True)
1150
1164
        result = to_bzrdir.create_branch()
1151
1165
        result.lock_write()
1152
1166
        try:
1276
1290
        # clone call. Or something. 20090224 RBC/spiv.
1277
1291
        if revision_id is None:
1278
1292
            revision_id = self.last_revision()
1279
 
        try:
1280
 
            dir_to = self.bzrdir.clone_on_transport(to_transport,
1281
 
                revision_id=revision_id, stacked_on=stacked_on,
1282
 
                create_prefix=create_prefix, use_existing_dir=use_existing_dir)
1283
 
        except errors.FileExists:
1284
 
            if not use_existing_dir:
1285
 
                raise
1286
 
        except errors.NoSuchFile:
1287
 
            if not create_prefix:
1288
 
                raise
 
1293
        dir_to = self.bzrdir.clone_on_transport(to_transport,
 
1294
            revision_id=revision_id, stacked_on=stacked_on,
 
1295
            create_prefix=create_prefix, use_existing_dir=use_existing_dir)
1289
1296
        return dir_to.open_branch()
1290
1297
 
1291
1298
    def create_checkout(self, to_location, revision_id=None,
1431
1438
        """Return the format for the branch object in a_bzrdir."""
1432
1439
        try:
1433
1440
            transport = a_bzrdir.get_branch_transport(None)
1434
 
            format_string = transport.get("format").read()
 
1441
            format_string = transport.get_bytes("format")
1435
1442
            return klass._formats[format_string]
1436
1443
        except errors.NoSuchFile:
1437
 
            raise errors.NotBranchError(path=transport.base)
 
1444
            raise errors.NotBranchError(path=transport.base, bzrdir=a_bzrdir)
1438
1445
        except KeyError:
1439
1446
            raise errors.UnknownFormatError(format=format_string, kind='branch')
1440
1447
 
1789
1796
                              _repository=a_bzrdir.find_repository(),
1790
1797
                              ignore_fallbacks=ignore_fallbacks)
1791
1798
        except errors.NoSuchFile:
1792
 
            raise errors.NotBranchError(path=transport.base)
 
1799
            raise errors.NotBranchError(path=transport.base, bzrdir=a_bzrdir)
1793
1800
 
1794
1801
    def __init__(self):
1795
1802
        super(BranchFormatMetadir, self).__init__()
1970
1977
    def get_reference(self, a_bzrdir):
1971
1978
        """See BranchFormat.get_reference()."""
1972
1979
        transport = a_bzrdir.get_branch_transport(None)
1973
 
        return transport.get('location').read()
 
1980
        return transport.get_bytes('location')
1974
1981
 
1975
1982
    def set_reference(self, a_bzrdir, to_branch):
1976
1983
        """See BranchFormat.set_reference()."""
2064
2071
BranchFormat.register_format(__format6)
2065
2072
BranchFormat.register_format(__format7)
2066
2073
BranchFormat.register_format(__format8)
2067
 
BranchFormat.set_default_format(__format6)
 
2074
BranchFormat.set_default_format(__format7)
2068
2075
_legacy_formats = [BzrBranchFormat4(),
2069
2076
    ]
2070
2077
network_format_registry.register(
2071
2078
    _legacy_formats[0].network_name(), _legacy_formats[0].__class__)
2072
2079
 
2073
2080
 
2074
 
class BzrBranch(Branch):
 
2081
class BzrBranch(Branch, _RelockDebugMixin):
2075
2082
    """A branch stored in the actual filesystem.
2076
2083
 
2077
2084
    Note that it's "local" in the context of the filesystem; it doesn't
2123
2130
        return self.control_files.is_locked()
2124
2131
 
2125
2132
    def lock_write(self, token=None):
 
2133
        if not self.is_locked():
 
2134
            self._note_lock('w')
2126
2135
        # All-in-one needs to always unlock/lock.
2127
2136
        repo_control = getattr(self.repository, 'control_files', None)
2128
2137
        if self.control_files == repo_control or not self.is_locked():
 
2138
            self.repository._warn_if_deprecated(self)
2129
2139
            self.repository.lock_write()
2130
2140
            took_lock = True
2131
2141
        else:
2138
2148
            raise
2139
2149
 
2140
2150
    def lock_read(self):
 
2151
        if not self.is_locked():
 
2152
            self._note_lock('r')
2141
2153
        # All-in-one needs to always unlock/lock.
2142
2154
        repo_control = getattr(self.repository, 'control_files', None)
2143
2155
        if self.control_files == repo_control or not self.is_locked():
 
2156
            self.repository._warn_if_deprecated(self)
2144
2157
            self.repository.lock_read()
2145
2158
            took_lock = True
2146
2159
        else:
2152
2165
                self.repository.unlock()
2153
2166
            raise
2154
2167
 
 
2168
    @only_raises(errors.LockNotHeld, errors.LockBroken)
2155
2169
    def unlock(self):
2156
2170
        try:
2157
2171
            self.control_files.unlock()