/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/branch.py

  • Committer: Robert Collins
  • Date: 2010-05-06 11:08:10 UTC
  • mto: This revision was merged to the branch mainline in revision 5223.
  • Revision ID: robertc@robertcollins.net-20100506110810-h3j07fh5gmw54s25
Cleaner matcher matching revised unlocking protocol.

Show diffs side-by-side

added added

removed removed

Lines of Context:
29
29
        errors,
30
30
        lockdir,
31
31
        lockable_files,
32
 
        remote,
33
32
        repository,
34
33
        revision as _mod_revision,
35
34
        rio,
50
49
from bzrlib.decorators import needs_read_lock, needs_write_lock, only_raises
51
50
from bzrlib.hooks import HookPoint, Hooks
52
51
from bzrlib.inter import InterObject
53
 
from bzrlib.lock import _RelockDebugMixin, LogicalLockResult
 
52
from bzrlib.lock import _RelockDebugMixin
54
53
from bzrlib import registry
55
54
from bzrlib.symbol_versioning import (
56
55
    deprecated_in,
198
197
        return self.supports_tags() and self.tags.get_tag_dict()
199
198
 
200
199
    def get_config(self):
201
 
        """Get a bzrlib.config.BranchConfig for this Branch.
202
 
 
203
 
        This can then be used to get and set configuration options for the
204
 
        branch.
205
 
 
206
 
        :return: A bzrlib.config.BranchConfig.
207
 
        """
208
200
        return BranchConfig(self)
209
201
 
210
202
    def _get_config(self):
291
283
        new_history.reverse()
292
284
        return new_history
293
285
 
294
 
    def lock_write(self, token=None):
295
 
        """Lock the branch for write operations.
296
 
 
297
 
        :param token: A token to permit reacquiring a previously held and
298
 
            preserved lock.
299
 
        :return: A BranchWriteLockResult.
300
 
        """
 
286
    def lock_write(self):
301
287
        raise NotImplementedError(self.lock_write)
302
288
 
303
289
    def lock_read(self):
304
 
        """Lock the branch for read operations.
305
 
 
306
 
        :return: A bzrlib.lock.LogicalLockResult.
307
 
        """
308
290
        raise NotImplementedError(self.lock_read)
309
291
 
310
292
    def unlock(self):
969
951
                raise errors.NoSuchRevision(self, stop_revision)
970
952
        return other_history[self_len:stop_revision]
971
953
 
 
954
    @needs_write_lock
972
955
    def update_revisions(self, other, stop_revision=None, overwrite=False,
973
956
                         graph=None):
974
957
        """Pull in new perfect-fit revisions.
1023
1006
            self._extend_partial_history(distance_from_last)
1024
1007
        return self._partial_revision_history_cache[distance_from_last]
1025
1008
 
 
1009
    @needs_write_lock
1026
1010
    def pull(self, source, overwrite=False, stop_revision=None,
1027
1011
             possible_transports=None, *args, **kwargs):
1028
1012
        """Mirror source into this branch.
1271
1255
                revno = 1
1272
1256
        destination.set_last_revision_info(revno, revision_id)
1273
1257
 
 
1258
    @needs_read_lock
1274
1259
    def copy_content_into(self, destination, revision_id=None):
1275
1260
        """Copy the content of self into destination.
1276
1261
 
1277
1262
        revision_id: if not None, the revision history in the new branch will
1278
1263
                     be truncated to end with revision_id.
1279
1264
        """
1280
 
        return InterBranch.get(self, destination).copy_content_into(
1281
 
            revision_id=revision_id)
 
1265
        self.update_references(destination)
 
1266
        self._synchronize_history(destination, revision_id)
 
1267
        try:
 
1268
            parent = self.get_parent()
 
1269
        except errors.InaccessibleParent, e:
 
1270
            mutter('parent was not accessible to copy: %s', e)
 
1271
        else:
 
1272
            if parent:
 
1273
                destination.set_parent(parent)
 
1274
        if self._push_should_merge_tags():
 
1275
            self.tags.merge_to(destination.tags)
1282
1276
 
1283
1277
    def update_references(self, target):
1284
1278
        if not getattr(self._format, 'supports_reference_locations', False):
1352
1346
        """
1353
1347
        # XXX: Fix the bzrdir API to allow getting the branch back from the
1354
1348
        # clone call. Or something. 20090224 RBC/spiv.
1355
 
        # XXX: Should this perhaps clone colocated branches as well, 
1356
 
        # rather than just the default branch? 20100319 JRV
1357
1349
        if revision_id is None:
1358
1350
            revision_id = self.last_revision()
1359
1351
        dir_to = self.bzrdir.clone_on_transport(to_transport,
1518
1510
        try:
1519
1511
            transport = a_bzrdir.get_branch_transport(None, name=name)
1520
1512
            format_string = transport.get_bytes("format")
1521
 
            format = klass._formats[format_string]
1522
 
            if isinstance(format, MetaDirBranchFormatFactory):
1523
 
                return format()
1524
 
            return format
 
1513
            return klass._formats[format_string]
1525
1514
        except errors.NoSuchFile:
1526
1515
            raise errors.NotBranchError(path=transport.base, bzrdir=a_bzrdir)
1527
1516
        except KeyError:
1532
1521
        """Return the current default format."""
1533
1522
        return klass._default_format
1534
1523
 
1535
 
    @classmethod
1536
 
    def get_formats(klass):
1537
 
        """Get all the known formats.
1538
 
 
1539
 
        Warning: This triggers a load of all lazy registered formats: do not
1540
 
        use except when that is desireed.
1541
 
        """
1542
 
        result = []
1543
 
        for fmt in klass._formats.values():
1544
 
            if isinstance(fmt, MetaDirBranchFormatFactory):
1545
 
                fmt = fmt()
1546
 
            result.append(fmt)
1547
 
        return result
1548
 
 
1549
 
    def get_reference(self, a_bzrdir, name=None):
 
1524
    def get_reference(self, a_bzrdir):
1550
1525
        """Get the target reference of the branch in a_bzrdir.
1551
1526
 
1552
1527
        format probing must have been completed before calling
1554
1529
        in a_bzrdir is correct.
1555
1530
 
1556
1531
        :param a_bzrdir: The bzrdir to get the branch data from.
1557
 
        :param name: Name of the colocated branch to fetch
1558
1532
        :return: None if the branch is not a reference branch.
1559
1533
        """
1560
1534
        return None
1561
1535
 
1562
1536
    @classmethod
1563
 
    def set_reference(self, a_bzrdir, name, to_branch):
 
1537
    def set_reference(self, a_bzrdir, to_branch):
1564
1538
        """Set the target reference of the branch in a_bzrdir.
1565
1539
 
1566
1540
        format probing must have been completed before calling
1568
1542
        in a_bzrdir is correct.
1569
1543
 
1570
1544
        :param a_bzrdir: The bzrdir to set the branch reference for.
1571
 
        :param name: Name of colocated branch to set, None for default
1572
1545
        :param to_branch: branch that the checkout is to reference
1573
1546
        """
1574
1547
        raise NotImplementedError(self.set_reference)
1688
1661
 
1689
1662
    @classmethod
1690
1663
    def register_format(klass, format):
1691
 
        """Register a metadir format.
1692
 
        
1693
 
        See MetaDirBranchFormatFactory for the ability to register a format
1694
 
        without loading the code the format needs until it is actually used.
1695
 
        """
 
1664
        """Register a metadir format."""
1696
1665
        klass._formats[format.get_format_string()] = format
1697
1666
        # Metadir formats have a network name of their format string, and get
1698
 
        # registered as factories.
1699
 
        if isinstance(format, MetaDirBranchFormatFactory):
1700
 
            network_format_registry.register(format.get_format_string(), format)
1701
 
        else:
1702
 
            network_format_registry.register(format.get_format_string(),
1703
 
                format.__class__)
 
1667
        # registered as class factories.
 
1668
        network_format_registry.register(format.get_format_string(), format.__class__)
1704
1669
 
1705
1670
    @classmethod
1706
1671
    def set_default_format(klass, format):
1726
1691
        return False  # by default
1727
1692
 
1728
1693
 
1729
 
class MetaDirBranchFormatFactory(registry._LazyObjectGetter):
1730
 
    """A factory for a BranchFormat object, permitting simple lazy registration.
1731
 
    
1732
 
    While none of the built in BranchFormats are lazy registered yet,
1733
 
    bzrlib.tests.test_branch.TestMetaDirBranchFormatFactory demonstrates how to
1734
 
    use it, and the bzr-loom plugin uses it as well (see
1735
 
    bzrlib.plugins.loom.formats).
1736
 
    """
1737
 
 
1738
 
    def __init__(self, format_string, module_name, member_name):
1739
 
        """Create a MetaDirBranchFormatFactory.
1740
 
 
1741
 
        :param format_string: The format string the format has.
1742
 
        :param module_name: Module to load the format class from.
1743
 
        :param member_name: Attribute name within the module for the format class.
1744
 
        """
1745
 
        registry._LazyObjectGetter.__init__(self, module_name, member_name)
1746
 
        self._format_string = format_string
1747
 
        
1748
 
    def get_format_string(self):
1749
 
        """See BranchFormat.get_format_string."""
1750
 
        return self._format_string
1751
 
 
1752
 
    def __call__(self):
1753
 
        """Used for network_format_registry support."""
1754
 
        return self.get_obj()()
1755
 
 
1756
 
 
1757
1694
class BranchHooks(Hooks):
1758
1695
    """A dictionary mapping hook name to a list of callables for branch hooks.
1759
1696
 
2220
2157
        """See BranchFormat.get_format_description()."""
2221
2158
        return "Checkout reference format 1"
2222
2159
 
2223
 
    def get_reference(self, a_bzrdir, name=None):
 
2160
    def get_reference(self, a_bzrdir):
2224
2161
        """See BranchFormat.get_reference()."""
2225
 
        transport = a_bzrdir.get_branch_transport(None, name=name)
 
2162
        transport = a_bzrdir.get_branch_transport(None)
2226
2163
        return transport.get_bytes('location')
2227
2164
 
2228
 
    def set_reference(self, a_bzrdir, name, to_branch):
 
2165
    def set_reference(self, a_bzrdir, to_branch):
2229
2166
        """See BranchFormat.set_reference()."""
2230
 
        transport = a_bzrdir.get_branch_transport(None, name=name)
 
2167
        transport = a_bzrdir.get_branch_transport(None)
2231
2168
        location = transport.put_bytes('location', to_branch.base)
2232
2169
 
2233
2170
    def initialize(self, a_bzrdir, name=None, target_branch=None):
2284
2221
                raise AssertionError("wrong format %r found for %r" %
2285
2222
                    (format, self))
2286
2223
        if location is None:
2287
 
            location = self.get_reference(a_bzrdir, name)
 
2224
            location = self.get_reference(a_bzrdir)
2288
2225
        real_bzrdir = bzrdir.BzrDir.open(
2289
2226
            location, possible_transports=possible_transports)
2290
2227
        result = real_bzrdir.open_branch(name=name, 
2328
2265
    _legacy_formats[0].network_name(), _legacy_formats[0].__class__)
2329
2266
 
2330
2267
 
2331
 
class BranchWriteLockResult(LogicalLockResult):
2332
 
    """The result of write locking a branch.
2333
 
 
2334
 
    :ivar branch_token: The token obtained from the underlying branch lock, or
2335
 
        None.
2336
 
    :ivar unlock: A callable which will unlock the lock.
2337
 
    """
2338
 
 
2339
 
    def __init__(self, unlock, branch_token):
2340
 
        LogicalLockResult.__init__(self, unlock)
2341
 
        self.branch_token = branch_token
2342
 
 
2343
 
    def __repr__(self):
2344
 
        return "BranchWriteLockResult(%s, %s)" % (self.branch_token,
2345
 
            self.unlock)
2346
 
 
2347
 
 
2348
2268
class BzrBranch(Branch, _RelockDebugMixin):
2349
2269
    """A branch stored in the actual filesystem.
2350
2270
 
2404
2324
        return self.control_files.is_locked()
2405
2325
 
2406
2326
    def lock_write(self, token=None):
2407
 
        """Lock the branch for write operations.
2408
 
 
2409
 
        :param token: A token to permit reacquiring a previously held and
2410
 
            preserved lock.
2411
 
        :return: A BranchWriteLockResult.
2412
 
        """
2413
2327
        if not self.is_locked():
2414
2328
            self._note_lock('w')
2415
2329
        # All-in-one needs to always unlock/lock.
2421
2335
        else:
2422
2336
            took_lock = False
2423
2337
        try:
2424
 
            return BranchWriteLockResult(self.unlock,
2425
 
                self.control_files.lock_write(token=token))
 
2338
            return self.control_files.lock_write(token=token)
2426
2339
        except:
2427
2340
            if took_lock:
2428
2341
                self.repository.unlock()
2429
2342
            raise
2430
2343
 
2431
2344
    def lock_read(self):
2432
 
        """Lock the branch for read operations.
2433
 
 
2434
 
        :return: A bzrlib.lock.LogicalLockResult.
2435
 
        """
2436
2345
        if not self.is_locked():
2437
2346
            self._note_lock('r')
2438
2347
        # All-in-one needs to always unlock/lock.
2445
2354
            took_lock = False
2446
2355
        try:
2447
2356
            self.control_files.lock_read()
2448
 
            return LogicalLockResult(self.unlock)
2449
2357
        except:
2450
2358
            if took_lock:
2451
2359
                self.repository.unlock()
3237
3145
    _optimisers = []
3238
3146
    """The available optimised InterBranch types."""
3239
3147
 
3240
 
    @classmethod
3241
 
    def _get_branch_formats_to_test(klass):
3242
 
        """Return an iterable of format tuples for testing.
3243
 
        
3244
 
        :return: An iterable of (from_format, to_format) to use when testing
3245
 
            this InterBranch class. Each InterBranch class should define this
3246
 
            method itself.
3247
 
        """
3248
 
        raise NotImplementedError(klass._get_branch_formats_to_test)
 
3148
    @staticmethod
 
3149
    def _get_branch_formats_to_test():
 
3150
        """Return a tuple with the Branch formats to use when testing."""
 
3151
        raise NotImplementedError(InterBranch._get_branch_formats_to_test)
3249
3152
 
3250
 
    @needs_write_lock
3251
3153
    def pull(self, overwrite=False, stop_revision=None,
3252
3154
             possible_transports=None, local=False):
3253
3155
        """Mirror source into target branch.
3258
3160
        """
3259
3161
        raise NotImplementedError(self.pull)
3260
3162
 
3261
 
    @needs_write_lock
3262
3163
    def update_revisions(self, stop_revision=None, overwrite=False,
3263
3164
                         graph=None):
3264
3165
        """Pull in new perfect-fit revisions.
3272
3173
        """
3273
3174
        raise NotImplementedError(self.update_revisions)
3274
3175
 
3275
 
    @needs_write_lock
3276
3176
    def push(self, overwrite=False, stop_revision=None,
3277
3177
             _override_hook_source_branch=None):
3278
3178
        """Mirror the source branch into the target branch.
3283
3183
 
3284
3184
 
3285
3185
class GenericInterBranch(InterBranch):
3286
 
    """InterBranch implementation that uses public Branch functions."""
3287
 
 
3288
 
    @classmethod
3289
 
    def is_compatible(klass, source, target):
3290
 
        # GenericBranch uses the public API, so always compatible
3291
 
        return True
3292
 
 
3293
 
    @classmethod
3294
 
    def _get_branch_formats_to_test(klass):
3295
 
        return [(BranchFormat._default_format, BranchFormat._default_format)]
3296
 
 
3297
 
    @classmethod
3298
 
    def unwrap_format(klass, format):
3299
 
        if isinstance(format, remote.RemoteBranchFormat):
3300
 
            format._ensure_real()
3301
 
            return format._custom_format
3302
 
        return format                                                                                                  
3303
 
 
3304
 
    @needs_write_lock
3305
 
    def copy_content_into(self, revision_id=None):
3306
 
        """Copy the content of source into target
3307
 
 
3308
 
        revision_id: if not None, the revision history in the new branch will
3309
 
                     be truncated to end with revision_id.
3310
 
        """
3311
 
        self.source.update_references(self.target)
3312
 
        self.source._synchronize_history(self.target, revision_id)
3313
 
        try:
3314
 
            parent = self.source.get_parent()
3315
 
        except errors.InaccessibleParent, e:
3316
 
            mutter('parent was not accessible to copy: %s', e)
3317
 
        else:
3318
 
            if parent:
3319
 
                self.target.set_parent(parent)
3320
 
        if self.source._push_should_merge_tags():
3321
 
            self.source.tags.merge_to(self.target.tags)
3322
 
 
3323
 
    @needs_write_lock
 
3186
    """InterBranch implementation that uses public Branch functions.
 
3187
    """
 
3188
 
 
3189
    @staticmethod
 
3190
    def _get_branch_formats_to_test():
 
3191
        return BranchFormat._default_format, BranchFormat._default_format
 
3192
 
3324
3193
    def update_revisions(self, stop_revision=None, overwrite=False,
3325
3194
        graph=None):
3326
3195
        """See InterBranch.update_revisions()."""
3327
 
        other_revno, other_last_revision = self.source.last_revision_info()
3328
 
        stop_revno = None # unknown
3329
 
        if stop_revision is None:
3330
 
            stop_revision = other_last_revision
3331
 
            if _mod_revision.is_null(stop_revision):
3332
 
                # if there are no commits, we're done.
3333
 
                return
3334
 
            stop_revno = other_revno
3335
 
 
3336
 
        # what's the current last revision, before we fetch [and change it
3337
 
        # possibly]
3338
 
        last_rev = _mod_revision.ensure_null(self.target.last_revision())
3339
 
        # we fetch here so that we don't process data twice in the common
3340
 
        # case of having something to pull, and so that the check for
3341
 
        # already merged can operate on the just fetched graph, which will
3342
 
        # be cached in memory.
3343
 
        self.target.fetch(self.source, stop_revision)
3344
 
        # Check to see if one is an ancestor of the other
3345
 
        if not overwrite:
3346
 
            if graph is None:
3347
 
                graph = self.target.repository.get_graph()
3348
 
            if self.target._check_if_descendant_or_diverged(
3349
 
                    stop_revision, last_rev, graph, self.source):
3350
 
                # stop_revision is a descendant of last_rev, but we aren't
3351
 
                # overwriting, so we're done.
3352
 
                return
3353
 
        if stop_revno is None:
3354
 
            if graph is None:
3355
 
                graph = self.target.repository.get_graph()
3356
 
            this_revno, this_last_revision = \
3357
 
                    self.target.last_revision_info()
3358
 
            stop_revno = graph.find_distance_to_null(stop_revision,
3359
 
                            [(other_last_revision, other_revno),
3360
 
                             (this_last_revision, this_revno)])
3361
 
        self.target.set_last_revision_info(stop_revno, stop_revision)
3362
 
 
3363
 
    @needs_write_lock
 
3196
        self.source.lock_read()
 
3197
        try:
 
3198
            other_revno, other_last_revision = self.source.last_revision_info()
 
3199
            stop_revno = None # unknown
 
3200
            if stop_revision is None:
 
3201
                stop_revision = other_last_revision
 
3202
                if _mod_revision.is_null(stop_revision):
 
3203
                    # if there are no commits, we're done.
 
3204
                    return
 
3205
                stop_revno = other_revno
 
3206
 
 
3207
            # what's the current last revision, before we fetch [and change it
 
3208
            # possibly]
 
3209
            last_rev = _mod_revision.ensure_null(self.target.last_revision())
 
3210
            # we fetch here so that we don't process data twice in the common
 
3211
            # case of having something to pull, and so that the check for
 
3212
            # already merged can operate on the just fetched graph, which will
 
3213
            # be cached in memory.
 
3214
            self.target.fetch(self.source, stop_revision)
 
3215
            # Check to see if one is an ancestor of the other
 
3216
            if not overwrite:
 
3217
                if graph is None:
 
3218
                    graph = self.target.repository.get_graph()
 
3219
                if self.target._check_if_descendant_or_diverged(
 
3220
                        stop_revision, last_rev, graph, self.source):
 
3221
                    # stop_revision is a descendant of last_rev, but we aren't
 
3222
                    # overwriting, so we're done.
 
3223
                    return
 
3224
            if stop_revno is None:
 
3225
                if graph is None:
 
3226
                    graph = self.target.repository.get_graph()
 
3227
                this_revno, this_last_revision = \
 
3228
                        self.target.last_revision_info()
 
3229
                stop_revno = graph.find_distance_to_null(stop_revision,
 
3230
                                [(other_last_revision, other_revno),
 
3231
                                 (this_last_revision, this_revno)])
 
3232
            self.target.set_last_revision_info(stop_revno, stop_revision)
 
3233
        finally:
 
3234
            self.source.unlock()
 
3235
 
3364
3236
    def pull(self, overwrite=False, stop_revision=None,
3365
 
             possible_transports=None, run_hooks=True,
 
3237
             possible_transports=None, _hook_master=None, run_hooks=True,
3366
3238
             _override_hook_target=None, local=False):
3367
 
        """Pull from source into self, updating my master if any.
 
3239
        """See Branch.pull.
3368
3240
 
 
3241
        :param _hook_master: Private parameter - set the branch to
 
3242
            be supplied as the master to pull hooks.
3369
3243
        :param run_hooks: Private parameter - if false, this branch
3370
3244
            is being called because it's the master of the primary branch,
3371
3245
            so it should not run its hooks.
 
3246
        :param _override_hook_target: Private parameter - set the branch to be
 
3247
            supplied as the target_branch to pull hooks.
 
3248
        :param local: Only update the local branch, and not the bound branch.
3372
3249
        """
3373
 
        bound_location = self.target.get_bound_location()
3374
 
        if local and not bound_location:
 
3250
        # This type of branch can't be bound.
 
3251
        if local:
3375
3252
            raise errors.LocalRequiresBoundBranch()
3376
 
        master_branch = None
3377
 
        if not local and bound_location and self.source.user_url != bound_location:
3378
 
            # not pulling from master, so we need to update master.
3379
 
            master_branch = self.target.get_master_branch(possible_transports)
3380
 
            master_branch.lock_write()
 
3253
        result = PullResult()
 
3254
        result.source_branch = self.source
 
3255
        if _override_hook_target is None:
 
3256
            result.target_branch = self.target
 
3257
        else:
 
3258
            result.target_branch = _override_hook_target
 
3259
        self.source.lock_read()
3381
3260
        try:
3382
 
            if master_branch:
3383
 
                # pull from source into master.
3384
 
                master_branch.pull(self.source, overwrite, stop_revision,
3385
 
                    run_hooks=False)
3386
 
            return self._pull(overwrite,
3387
 
                stop_revision, _hook_master=master_branch,
3388
 
                run_hooks=run_hooks,
3389
 
                _override_hook_target=_override_hook_target)
 
3261
            # We assume that during 'pull' the target repository is closer than
 
3262
            # the source one.
 
3263
            self.source.update_references(self.target)
 
3264
            graph = self.target.repository.get_graph(self.source.repository)
 
3265
            # TODO: Branch formats should have a flag that indicates 
 
3266
            # that revno's are expensive, and pull() should honor that flag.
 
3267
            # -- JRV20090506
 
3268
            result.old_revno, result.old_revid = \
 
3269
                self.target.last_revision_info()
 
3270
            self.target.update_revisions(self.source, stop_revision,
 
3271
                overwrite=overwrite, graph=graph)
 
3272
            # TODO: The old revid should be specified when merging tags, 
 
3273
            # so a tags implementation that versions tags can only 
 
3274
            # pull in the most recent changes. -- JRV20090506
 
3275
            result.tag_conflicts = self.source.tags.merge_to(self.target.tags,
 
3276
                overwrite)
 
3277
            result.new_revno, result.new_revid = self.target.last_revision_info()
 
3278
            if _hook_master:
 
3279
                result.master_branch = _hook_master
 
3280
                result.local_branch = result.target_branch
 
3281
            else:
 
3282
                result.master_branch = result.target_branch
 
3283
                result.local_branch = None
 
3284
            if run_hooks:
 
3285
                for hook in Branch.hooks['post_pull']:
 
3286
                    hook(result)
3390
3287
        finally:
3391
 
            if master_branch:
3392
 
                master_branch.unlock()
 
3288
            self.source.unlock()
 
3289
        return result
3393
3290
 
3394
3291
    def push(self, overwrite=False, stop_revision=None,
3395
3292
             _override_hook_source_branch=None):
3457
3354
            _run_hooks()
3458
3355
            return result
3459
3356
 
3460
 
    def _pull(self, overwrite=False, stop_revision=None,
3461
 
             possible_transports=None, _hook_master=None, run_hooks=True,
 
3357
    @classmethod
 
3358
    def is_compatible(self, source, target):
 
3359
        # GenericBranch uses the public API, so always compatible
 
3360
        return True
 
3361
 
 
3362
 
 
3363
class InterToBranch5(GenericInterBranch):
 
3364
 
 
3365
    @staticmethod
 
3366
    def _get_branch_formats_to_test():
 
3367
        return BranchFormat._default_format, BzrBranchFormat5()
 
3368
 
 
3369
    def pull(self, overwrite=False, stop_revision=None,
 
3370
             possible_transports=None, run_hooks=True,
3462
3371
             _override_hook_target=None, local=False):
3463
 
        """See Branch.pull.
3464
 
 
3465
 
        This function is the core worker, used by GenericInterBranch.pull to
3466
 
        avoid duplication when pulling source->master and source->local.
3467
 
 
3468
 
        :param _hook_master: Private parameter - set the branch to
3469
 
            be supplied as the master to pull hooks.
 
3372
        """Pull from source into self, updating my master if any.
 
3373
 
3470
3374
        :param run_hooks: Private parameter - if false, this branch
3471
3375
            is being called because it's the master of the primary branch,
3472
3376
            so it should not run its hooks.
3473
 
        :param _override_hook_target: Private parameter - set the branch to be
3474
 
            supplied as the target_branch to pull hooks.
3475
 
        :param local: Only update the local branch, and not the bound branch.
3476
3377
        """
3477
 
        # This type of branch can't be bound.
3478
 
        if local:
 
3378
        bound_location = self.target.get_bound_location()
 
3379
        if local and not bound_location:
3479
3380
            raise errors.LocalRequiresBoundBranch()
3480
 
        result = PullResult()
3481
 
        result.source_branch = self.source
3482
 
        if _override_hook_target is None:
3483
 
            result.target_branch = self.target
3484
 
        else:
3485
 
            result.target_branch = _override_hook_target
3486
 
        self.source.lock_read()
 
3381
        master_branch = None
 
3382
        if not local and bound_location and self.source.user_url != bound_location:
 
3383
            # not pulling from master, so we need to update master.
 
3384
            master_branch = self.target.get_master_branch(possible_transports)
 
3385
            master_branch.lock_write()
3487
3386
        try:
3488
 
            # We assume that during 'pull' the target repository is closer than
3489
 
            # the source one.
3490
 
            self.source.update_references(self.target)
3491
 
            graph = self.target.repository.get_graph(self.source.repository)
3492
 
            # TODO: Branch formats should have a flag that indicates 
3493
 
            # that revno's are expensive, and pull() should honor that flag.
3494
 
            # -- JRV20090506
3495
 
            result.old_revno, result.old_revid = \
3496
 
                self.target.last_revision_info()
3497
 
            self.target.update_revisions(self.source, stop_revision,
3498
 
                overwrite=overwrite, graph=graph)
3499
 
            # TODO: The old revid should be specified when merging tags, 
3500
 
            # so a tags implementation that versions tags can only 
3501
 
            # pull in the most recent changes. -- JRV20090506
3502
 
            result.tag_conflicts = self.source.tags.merge_to(self.target.tags,
3503
 
                overwrite)
3504
 
            result.new_revno, result.new_revid = self.target.last_revision_info()
3505
 
            if _hook_master:
3506
 
                result.master_branch = _hook_master
3507
 
                result.local_branch = result.target_branch
3508
 
            else:
3509
 
                result.master_branch = result.target_branch
3510
 
                result.local_branch = None
3511
 
            if run_hooks:
3512
 
                for hook in Branch.hooks['post_pull']:
3513
 
                    hook(result)
 
3387
            if master_branch:
 
3388
                # pull from source into master.
 
3389
                master_branch.pull(self.source, overwrite, stop_revision,
 
3390
                    run_hooks=False)
 
3391
            return super(InterToBranch5, self).pull(overwrite,
 
3392
                stop_revision, _hook_master=master_branch,
 
3393
                run_hooks=run_hooks,
 
3394
                _override_hook_target=_override_hook_target)
3514
3395
        finally:
3515
 
            self.source.unlock()
3516
 
        return result
 
3396
            if master_branch:
 
3397
                master_branch.unlock()
3517
3398
 
3518
3399
 
3519
3400
InterBranch.register_optimiser(GenericInterBranch)
 
3401
InterBranch.register_optimiser(InterToBranch5)