~bzr-pqm/bzr/bzr.dev

« back to all changes in this revision

Viewing changes to bzrlib/branch.py

  • Committer: Aaron Bentley
  • Date: 2007-02-06 14:52:16 UTC
  • mfrom: (2266 +trunk)
  • mto: This revision was merged to the branch mainline in revision 2268.
  • Revision ID: abentley@panoramicfeedback.com-20070206145216-fcpi8o3ufvuzwbp9
Merge bzr.dev

Show diffs side-by-side

added added

removed removed

Lines of Context:
15
15
# Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
16
16
 
17
17
 
 
18
from cStringIO import StringIO
 
19
 
 
20
from bzrlib.lazy_import import lazy_import
 
21
lazy_import(globals(), """
18
22
from copy import deepcopy
19
 
from cStringIO import StringIO
20
23
from unittest import TestSuite
21
24
from warnings import warn
22
25
 
24
27
from bzrlib import (
25
28
        bzrdir,
26
29
        cache_utf8,
 
30
        config as _mod_config,
27
31
        errors,
28
32
        lockdir,
 
33
        lockable_files,
29
34
        osutils,
30
 
        revision,
 
35
        revision as _mod_revision,
31
36
        transport,
32
37
        tree,
33
38
        ui,
34
39
        urlutils,
35
40
        )
36
 
from bzrlib.config import TreeConfig
 
41
from bzrlib.config import BranchConfig, TreeConfig
 
42
from bzrlib.lockable_files import LockableFiles, TransportLock
 
43
""")
 
44
 
37
45
from bzrlib.decorators import needs_read_lock, needs_write_lock
38
 
import bzrlib.errors as errors
39
 
from bzrlib.errors import (BzrError, BzrCheckError, DivergedBranches, 
40
 
                           HistoryMissing, InvalidRevisionId, 
41
 
                           InvalidRevisionNumber, LockError, NoSuchFile, 
 
46
from bzrlib.errors import (BzrError, BzrCheckError, DivergedBranches,
 
47
                           HistoryMissing, InvalidRevisionId,
 
48
                           InvalidRevisionNumber, LockError, NoSuchFile,
42
49
                           NoSuchRevision, NoWorkingTree, NotVersionedError,
43
 
                           NotBranchError, UninitializableFormat, 
44
 
                           UnlistableStore, UnlistableBranch, 
 
50
                           NotBranchError, UninitializableFormat,
 
51
                           UnlistableStore, UnlistableBranch,
45
52
                           )
46
 
from bzrlib.lockable_files import LockableFiles, TransportLock
47
53
from bzrlib.symbol_versioning import (deprecated_function,
48
54
                                      deprecated_method,
49
55
                                      DEPRECATED_PARAMETER,
75
81
 
76
82
    base
77
83
        Base directory/url of the branch.
 
84
 
 
85
    hooks: An instance of BranchHooks.
78
86
    """
79
87
    # this is really an instance variable - FIXME move it there
80
88
    # - RBC 20060112
148
156
        pass
149
157
 
150
158
    def get_config(self):
151
 
        return bzrlib.config.BranchConfig(self)
 
159
        return BranchConfig(self)
152
160
 
153
161
    def _get_nick(self):
154
162
        return self.get_config().get_nickname()
217
225
        try:
218
226
            if last_revision is None:
219
227
                pb.update('get source history')
220
 
                from_history = from_branch.revision_history()
221
 
                if from_history:
222
 
                    last_revision = from_history[-1]
223
 
                else:
224
 
                    # no history in the source branch
225
 
                    last_revision = revision.NULL_REVISION
 
228
                last_revision = from_branch.last_revision_info()[1]
226
229
            return self.repository.fetch(from_branch.repository,
227
230
                                         revision_id=last_revision,
228
231
                                         pb=nested_pb)
316
319
        else:
317
320
            return None
318
321
 
 
322
    def last_revision_info(self):
 
323
        """Return information about the last revision.
 
324
 
 
325
        :return: A tuple (revno, last_revision_id).
 
326
        """
 
327
        rh = self.revision_history()
 
328
        revno = len(rh)
 
329
        if revno:
 
330
            return (revno, rh[-1])
 
331
        else:
 
332
            return (0, _mod_revision.NULL_REVISION)
 
333
 
319
334
    def missing_revisions(self, other, stop_revision=None):
320
335
        """Return a list of new revisions that would perfectly fit.
321
336
        
369
384
        return history[revno - 1]
370
385
 
371
386
    def pull(self, source, overwrite=False, stop_revision=None):
 
387
        """Mirror source into this branch.
 
388
 
 
389
        This branch is considered to be 'local', having low latency.
 
390
        """
372
391
        raise NotImplementedError(self.pull)
373
392
 
 
393
    def push(self, target, overwrite=False, stop_revision=None):
 
394
        """Mirror this branch into target.
 
395
 
 
396
        This branch is considered to be 'local', having low latency.
 
397
        """
 
398
        raise NotImplementedError(self.push)
 
399
 
374
400
    def basis_tree(self):
375
401
        """Return `Tree` object for last revision."""
376
402
        return self.repository.revision_tree(self.last_revision())
593
619
            format = self.repository.bzrdir.cloning_metadir()
594
620
        return format
595
621
 
596
 
    def create_checkout(self, to_location, revision_id=None, 
 
622
    def create_checkout(self, to_location, revision_id=None,
597
623
                        lightweight=False):
598
624
        """Create a checkout of a branch.
599
625
        
670
696
 
671
697
    def get_format_description(self):
672
698
        """Return the short format description for this format."""
673
 
        raise NotImplementedError(self.get_format_string)
 
699
        raise NotImplementedError(self.get_format_description)
674
700
 
675
701
    def initialize(self, a_bzrdir):
676
702
        """Create a branch of this format in a_bzrdir."""
710
736
        return self.get_format_string().rstrip()
711
737
 
712
738
 
 
739
class BranchHooks(dict):
 
740
    """A dictionary mapping hook name to a list of callables for branch hooks.
 
741
    
 
742
    e.g. ['set_rh'] Is the list of items to be called when the
 
743
    set_revision_history function is invoked.
 
744
    """
 
745
 
 
746
    def __init__(self):
 
747
        """Create the default hooks.
 
748
 
 
749
        These are all empty initially, because by default nothing should get
 
750
        notified.
 
751
        """
 
752
        dict.__init__(self)
 
753
        # invoked whenever the revision history has been set
 
754
        # with set_revision_history. The api signature is
 
755
        # (branch, revision_history), and the branch will
 
756
        # be write-locked. Introduced in 0.15.
 
757
        self['set_rh'] = []
 
758
 
 
759
    def install_hook(self, hook_name, a_callable):
 
760
        """Install a_callable in to the hook hook_name.
 
761
 
 
762
        :param hook_name: A hook name. See the __init__ method of BranchHooks
 
763
            for the complete list of hooks.
 
764
        :param a_callable: The callable to be invoked when the hook triggers.
 
765
            The exact signature will depend on the hook - see the __init__ 
 
766
            method of BranchHooks for details on each hook.
 
767
        """
 
768
        try:
 
769
            self[hook_name].append(a_callable)
 
770
        except KeyError:
 
771
            raise errors.UnknownHook('branch', hook_name)
 
772
 
 
773
 
 
774
# install the default hooks into the Branch class.
 
775
Branch.hooks = BranchHooks()
 
776
 
 
777
 
713
778
class BzrBranchFormat4(BranchFormat):
714
779
    """Bzr branch format 4.
715
780
 
729
794
        utf8_files = [('revision-history', ''),
730
795
                      ('branch-name', ''),
731
796
                      ]
732
 
        control_files = LockableFiles(branch_transport, 'branch-lock',
733
 
                                      TransportLock)
 
797
        control_files = lockable_files.LockableFiles(branch_transport,
 
798
                             'branch-lock', lockable_files.TransportLock)
734
799
        control_files.create_lock()
735
800
        control_files.lock_write()
736
801
        try:
790
855
        utf8_files = [('revision-history', ''),
791
856
                      ('branch-name', ''),
792
857
                      ]
793
 
        control_files = LockableFiles(branch_transport, 'lock', lockdir.LockDir)
 
858
        control_files = lockable_files.LockableFiles(branch_transport, 'lock',
 
859
                                                     lockdir.LockDir)
794
860
        control_files.create_lock()
795
861
        control_files.lock_write()
796
862
        control_files.put_utf8('format', self.get_format_string())
815
881
            format = BranchFormat.find_format(a_bzrdir)
816
882
            assert format.__class__ == self.__class__
817
883
        transport = a_bzrdir.get_branch_transport(None)
818
 
        control_files = LockableFiles(transport, 'lock', lockdir.LockDir)
 
884
        control_files = lockable_files.LockableFiles(transport, 'lock',
 
885
                                                     lockdir.LockDir)
819
886
        return BzrBranch5(_format=self,
820
887
                          _control_files=control_files,
821
888
                          a_bzrdir=a_bzrdir,
1069
1136
    def append_revision(self, *revision_ids):
1070
1137
        """See Branch.append_revision."""
1071
1138
        for revision_id in revision_ids:
 
1139
            _mod_revision.check_not_reserved_id(revision_id)
1072
1140
            mutter("add {%s} to revision-history" % revision_id)
1073
1141
        rev_history = self.revision_history()
1074
1142
        rev_history.extend(revision_ids)
1092
1160
            # this call is disabled because revision_history is 
1093
1161
            # not really an object yet, and the transaction is for objects.
1094
1162
            # transaction.register_clean(history)
 
1163
        for hook in Branch.hooks['set_rh']:
 
1164
            hook(self, rev_history)
1095
1165
 
1096
1166
    @needs_read_lock
1097
1167
    def revision_history(self):
1129
1199
        # make a new revision history from the graph
1130
1200
        current_rev_id = revision_id
1131
1201
        new_history = []
1132
 
        while current_rev_id not in (None, revision.NULL_REVISION):
 
1202
        while current_rev_id not in (None, _mod_revision.NULL_REVISION):
1133
1203
            new_history.append(current_rev_id)
1134
1204
            current_rev_id_parents = stop_graph[current_rev_id]
1135
1205
            try:
1183
1253
        """See Branch.pull."""
1184
1254
        source.lock_read()
1185
1255
        try:
1186
 
            old_count = len(self.revision_history())
 
1256
            old_count = self.last_revision_info()[0]
1187
1257
            try:
1188
1258
                self.update_revisions(source, stop_revision)
1189
1259
            except DivergedBranches:
1191
1261
                    raise
1192
1262
            if overwrite:
1193
1263
                self.set_revision_history(source.revision_history())
1194
 
            new_count = len(self.revision_history())
 
1264
            new_count = self.last_revision_info()[0]
1195
1265
            return new_count - old_count
1196
1266
        finally:
1197
1267
            source.unlock()
1198
1268
 
 
1269
    @needs_read_lock
 
1270
    def push(self, target, overwrite=False, stop_revision=None):
 
1271
        """See Branch.push."""
 
1272
        target.lock_write()
 
1273
        try:
 
1274
            old_count = len(target.revision_history())
 
1275
            try:
 
1276
                target.update_revisions(self, stop_revision)
 
1277
            except DivergedBranches:
 
1278
                if not overwrite:
 
1279
                    raise
 
1280
            if overwrite:
 
1281
                target.set_revision_history(self.revision_history())
 
1282
            new_count = len(target.revision_history())
 
1283
            return new_count - old_count
 
1284
        finally:
 
1285
            target.unlock()
 
1286
 
1199
1287
    def get_parent(self):
1200
1288
        """See Branch.get_parent."""
1201
1289
 
1223
1311
 
1224
1312
    def set_push_location(self, location):
1225
1313
        """See Branch.set_push_location."""
1226
 
        self.get_config().set_user_option('push_location', location, 
1227
 
                                          local=True)
 
1314
        self.get_config().set_user_option(
 
1315
            'push_location', location,
 
1316
            store=_mod_config.STORE_LOCATION_NORECURSE)
1228
1317
 
1229
1318
    @needs_write_lock
1230
1319
    def set_parent(self, url):
1273
1362
        
1274
1363
    @needs_write_lock
1275
1364
    def pull(self, source, overwrite=False, stop_revision=None):
1276
 
        """Updates branch.pull to be bound branch aware."""
 
1365
        """Extends branch.pull to be bound branch aware."""
1277
1366
        bound_location = self.get_bound_location()
1278
1367
        if source.base != bound_location:
1279
1368
            # not pulling from master, so we need to update master.
1283
1372
                source = master_branch
1284
1373
        return super(BzrBranch5, self).pull(source, overwrite, stop_revision)
1285
1374
 
 
1375
    @needs_write_lock
 
1376
    def push(self, target, overwrite=False, stop_revision=None):
 
1377
        """Updates branch.push to be bound branch aware."""
 
1378
        bound_location = target.get_bound_location()
 
1379
        if target.base != bound_location:
 
1380
            # not pushing to master, so we need to update master.
 
1381
            master_branch = target.get_master_branch()
 
1382
            if master_branch:
 
1383
                # push into the master from this branch.
 
1384
                super(BzrBranch5, self).push(master_branch, overwrite,
 
1385
                    stop_revision)
 
1386
        # and push into the target branch from this. Note that we push from
 
1387
        # this branch again, because its considered the highest bandwidth
 
1388
        # repository.
 
1389
        return super(BzrBranch5, self).push(target, overwrite, stop_revision)
 
1390
 
1286
1391
    def get_bound_location(self):
1287
1392
        try:
1288
1393
            return self.control_files.get_utf8('bound').read()[:-1]
1445
1550
@deprecated_function(zero_eight)
1446
1551
def is_control_file(*args, **kwargs):
1447
1552
    """See bzrlib.workingtree.is_control_file."""
1448
 
    return bzrlib.workingtree.is_control_file(*args, **kwargs)
 
1553
    from bzrlib import workingtree
 
1554
    return workingtree.is_control_file(*args, **kwargs)