~bzr-pqm/bzr/bzr.dev

« back to all changes in this revision

Viewing changes to bzrlib/branch.py

Merge bzr.dev.

Show diffs side-by-side

added added

removed removed

Lines of Context:
845
845
            raise errors.NoSuchRevision(self, revno)
846
846
        return history[revno - 1]
847
847
 
 
848
    @needs_write_lock
848
849
    def pull(self, source, overwrite=False, stop_revision=None,
849
 
             possible_transports=None, _override_hook_target=None):
 
850
             possible_transports=None, *args, **kwargs):
850
851
        """Mirror source into this branch.
851
852
 
852
853
        This branch is considered to be 'local', having low latency.
853
854
 
854
855
        :returns: PullResult instance
855
856
        """
856
 
        raise NotImplementedError(self.pull)
 
857
        return InterBranch.get(source, self).pull(overwrite=overwrite,
 
858
            stop_revision=stop_revision,
 
859
            possible_transports=possible_transports, *args, **kwargs)
857
860
 
858
 
    def push(self, target, overwrite=False, stop_revision=None):
 
861
    def push(self, target, overwrite=False, stop_revision=None, *args,
 
862
        **kwargs):
859
863
        """Mirror this branch into target.
860
864
 
861
865
        This branch is considered to be 'local', having low latency.
862
866
        """
863
 
        raise NotImplementedError(self.push)
 
867
        return InterBranch.get(self, target).push(overwrite, stop_revision,
 
868
            *args, **kwargs)
864
869
 
865
870
    def basis_tree(self):
866
871
        """Return `Tree` object for last revision."""
2175
2180
        """See Branch.basis_tree."""
2176
2181
        return self.repository.revision_tree(self.last_revision())
2177
2182
 
2178
 
    @needs_write_lock
2179
 
    def pull(self, source, overwrite=False, stop_revision=None,
2180
 
             _hook_master=None, run_hooks=True, possible_transports=None,
2181
 
             _override_hook_target=None):
2182
 
        """See Branch.pull.
2183
 
 
2184
 
        :param _hook_master: Private parameter - set the branch to
2185
 
            be supplied as the master to pull hooks.
2186
 
        :param run_hooks: Private parameter - if false, this branch
2187
 
            is being called because it's the master of the primary branch,
2188
 
            so it should not run its hooks.
2189
 
        :param _override_hook_target: Private parameter - set the branch to be
2190
 
            supplied as the target_branch to pull hooks.
2191
 
        """
2192
 
        result = PullResult()
2193
 
        result.source_branch = source
2194
 
        if _override_hook_target is None:
2195
 
            result.target_branch = self
2196
 
        else:
2197
 
            result.target_branch = _override_hook_target
2198
 
        source.lock_read()
2199
 
        try:
2200
 
            # We assume that during 'pull' the local repository is closer than
2201
 
            # the remote one.
2202
 
            source.update_references(self)
2203
 
            graph = self.repository.get_graph(source.repository)
2204
 
            result.old_revno, result.old_revid = self.last_revision_info()
2205
 
            self.update_revisions(source, stop_revision, overwrite=overwrite,
2206
 
                                  graph=graph)
2207
 
            result.tag_conflicts = source.tags.merge_to(self.tags, overwrite)
2208
 
            result.new_revno, result.new_revid = self.last_revision_info()
2209
 
            if _hook_master:
2210
 
                result.master_branch = _hook_master
2211
 
                result.local_branch = result.target_branch
2212
 
            else:
2213
 
                result.master_branch = result.target_branch
2214
 
                result.local_branch = None
2215
 
            if run_hooks:
2216
 
                for hook in Branch.hooks['post_pull']:
2217
 
                    hook(result)
2218
 
        finally:
2219
 
            source.unlock()
2220
 
        return result
2221
 
 
2222
2183
    def _get_parent_location(self):
2223
2184
        _locs = ['parent', 'pull', 'x-pull']
2224
2185
        for l in _locs:
2228
2189
                pass
2229
2190
        return None
2230
2191
 
2231
 
    @needs_read_lock
2232
 
    def push(self, target, overwrite=False, stop_revision=None,
2233
 
             _override_hook_source_branch=None):
2234
 
        """See Branch.push.
2235
 
 
2236
 
        This is the basic concrete implementation of push()
2237
 
 
2238
 
        :param _override_hook_source_branch: If specified, run
2239
 
        the hooks passing this Branch as the source, rather than self.
2240
 
        This is for use of RemoteBranch, where push is delegated to the
2241
 
        underlying vfs-based Branch.
2242
 
        """
2243
 
        # TODO: Public option to disable running hooks - should be trivial but
2244
 
        # needs tests.
2245
 
        return _run_with_write_locked_target(
2246
 
            target, self._push_with_bound_branches, target, overwrite,
2247
 
            stop_revision,
2248
 
            _override_hook_source_branch=_override_hook_source_branch)
2249
 
 
2250
 
    def _push_with_bound_branches(self, target, overwrite,
2251
 
            stop_revision,
2252
 
            _override_hook_source_branch=None):
2253
 
        """Push from self into target, and into target's master if any.
2254
 
 
2255
 
        This is on the base BzrBranch class even though it doesn't support
2256
 
        bound branches because the *target* might be bound.
2257
 
        """
2258
 
        def _run_hooks():
2259
 
            if _override_hook_source_branch:
2260
 
                result.source_branch = _override_hook_source_branch
2261
 
            for hook in Branch.hooks['post_push']:
2262
 
                hook(result)
2263
 
 
2264
 
        bound_location = target.get_bound_location()
2265
 
        if bound_location and target.base != bound_location:
2266
 
            # there is a master branch.
2267
 
            #
2268
 
            # XXX: Why the second check?  Is it even supported for a branch to
2269
 
            # be bound to itself? -- mbp 20070507
2270
 
            master_branch = target.get_master_branch()
2271
 
            master_branch.lock_write()
2272
 
            try:
2273
 
                # push into the master from this branch.
2274
 
                self._basic_push(master_branch, overwrite, stop_revision)
2275
 
                # and push into the target branch from this. Note that we push from
2276
 
                # this branch again, because its considered the highest bandwidth
2277
 
                # repository.
2278
 
                result = self._basic_push(target, overwrite, stop_revision)
2279
 
                result.master_branch = master_branch
2280
 
                result.local_branch = target
2281
 
                _run_hooks()
2282
 
                return result
2283
 
            finally:
2284
 
                master_branch.unlock()
2285
 
        else:
2286
 
            # no master branch
2287
 
            result = self._basic_push(target, overwrite, stop_revision)
2288
 
            # TODO: Why set master_branch and local_branch if there's no
2289
 
            # binding?  Maybe cleaner to just leave them unset? -- mbp
2290
 
            # 20070504
2291
 
            result.master_branch = target
2292
 
            result.local_branch = None
2293
 
            _run_hooks()
2294
 
            return result
2295
 
 
2296
2192
    def _basic_push(self, target, overwrite, stop_revision):
2297
2193
        """Basic implementation of push without bound branches or hooks.
2298
2194
 
2299
 
        Must be called with self read locked and target write locked.
 
2195
        Must be called with source read locked and target write locked.
2300
2196
        """
2301
2197
        result = BranchPushResult()
2302
2198
        result.source_branch = self
2307
2203
            # We assume that during 'push' this repository is closer than
2308
2204
            # the target.
2309
2205
            graph = self.repository.get_graph(target.repository)
2310
 
            target.update_revisions(self, stop_revision, overwrite=overwrite,
2311
 
                                    graph=graph)
 
2206
            target.update_revisions(self, stop_revision,
 
2207
                overwrite=overwrite, graph=graph)
2312
2208
        if self._push_should_merge_tags():
2313
 
            result.tag_conflicts = self.tags.merge_to(target.tags, overwrite)
 
2209
            result.tag_conflicts = self.tags.merge_to(target.tags,
 
2210
                overwrite)
2314
2211
        result.new_revno, result.new_revid = target.last_revision_info()
2315
2212
        return result
2316
2213
 
2337
2234
    It has support for a master_branch which is the data for bound branches.
2338
2235
    """
2339
2236
 
2340
 
    @needs_write_lock
2341
 
    def pull(self, source, overwrite=False, stop_revision=None,
2342
 
             run_hooks=True, possible_transports=None,
2343
 
             _override_hook_target=None):
2344
 
        """Pull from source into self, updating my master if any.
2345
 
 
2346
 
        :param run_hooks: Private parameter - if false, this branch
2347
 
            is being called because it's the master of the primary branch,
2348
 
            so it should not run its hooks.
2349
 
        """
2350
 
        bound_location = self.get_bound_location()
2351
 
        master_branch = None
2352
 
        if bound_location and source.base != bound_location:
2353
 
            # not pulling from master, so we need to update master.
2354
 
            master_branch = self.get_master_branch(possible_transports)
2355
 
            master_branch.lock_write()
2356
 
        try:
2357
 
            if master_branch:
2358
 
                # pull from source into master.
2359
 
                master_branch.pull(source, overwrite, stop_revision,
2360
 
                    run_hooks=False)
2361
 
            return super(BzrBranch5, self).pull(source, overwrite,
2362
 
                stop_revision, _hook_master=master_branch,
2363
 
                run_hooks=run_hooks,
2364
 
                _override_hook_target=_override_hook_target)
2365
 
        finally:
2366
 
            if master_branch:
2367
 
                master_branch.unlock()
2368
 
 
2369
2237
    def get_bound_location(self):
2370
2238
        try:
2371
2239
            return self._transport.get_bytes('bound')[:-1]
3003
2871
        """Return a tuple with the Branch formats to use when testing."""
3004
2872
        raise NotImplementedError(self._get_branch_formats_to_test)
3005
2873
 
 
2874
    def pull(self, overwrite=False, stop_revision=None,
 
2875
             possible_transports=None, local=False):
 
2876
        """Mirror source into target branch.
 
2877
 
 
2878
        The target branch is considered to be 'local', having low latency.
 
2879
 
 
2880
        :returns: PullResult instance
 
2881
        """
 
2882
        raise NotImplementedError(self.pull)
 
2883
 
3006
2884
    def update_revisions(self, stop_revision=None, overwrite=False,
3007
2885
                         graph=None):
3008
2886
        """Pull in new perfect-fit revisions.
3016
2894
        """
3017
2895
        raise NotImplementedError(self.update_revisions)
3018
2896
 
 
2897
    def push(self, overwrite=False, stop_revision=None,
 
2898
             _override_hook_source_branch=None):
 
2899
        """Mirror the source branch into the target branch.
 
2900
 
 
2901
        The source branch is considered to be 'local', having low latency.
 
2902
        """
 
2903
        raise NotImplementedError(self.push)
 
2904
 
3019
2905
 
3020
2906
class GenericInterBranch(InterBranch):
3021
2907
    """InterBranch implementation that uses public Branch functions.
3068
2954
        finally:
3069
2955
            self.source.unlock()
3070
2956
 
 
2957
    def pull(self, overwrite=False, stop_revision=None,
 
2958
             possible_transports=None, _hook_master=None, run_hooks=True,
 
2959
             _override_hook_target=None, local=False):
 
2960
        """See Branch.pull.
 
2961
 
 
2962
        :param _hook_master: Private parameter - set the branch to
 
2963
            be supplied as the master to pull hooks.
 
2964
        :param run_hooks: Private parameter - if false, this branch
 
2965
            is being called because it's the master of the primary branch,
 
2966
            so it should not run its hooks.
 
2967
        :param _override_hook_target: Private parameter - set the branch to be
 
2968
            supplied as the target_branch to pull hooks.
 
2969
        :param local: Only update the local branch, and not the bound branch.
 
2970
        """
 
2971
        # This type of branch can't be bound.
 
2972
        if local:
 
2973
            raise errors.LocalRequiresBoundBranch()
 
2974
        result = PullResult()
 
2975
        result.source_branch = self.source
 
2976
        if _override_hook_target is None:
 
2977
            result.target_branch = self.target
 
2978
        else:
 
2979
            result.target_branch = _override_hook_target
 
2980
        self.source.lock_read()
 
2981
        try:
 
2982
            # We assume that during 'pull' the target repository is closer than
 
2983
            # the source one.
 
2984
            self.source.update_references(self.target)
 
2985
            graph = self.target.repository.get_graph(self.source.repository)
 
2986
            # TODO: Branch formats should have a flag that indicates 
 
2987
            # that revno's are expensive, and pull() should honor that flag.
 
2988
            # -- JRV20090506
 
2989
            result.old_revno, result.old_revid = \
 
2990
                self.target.last_revision_info()
 
2991
            self.target.update_revisions(self.source, stop_revision,
 
2992
                overwrite=overwrite, graph=graph)
 
2993
            # TODO: The old revid should be specified when merging tags, 
 
2994
            # so a tags implementation that versions tags can only 
 
2995
            # pull in the most recent changes. -- JRV20090506
 
2996
            result.tag_conflicts = self.source.tags.merge_to(self.target.tags,
 
2997
                overwrite)
 
2998
            result.new_revno, result.new_revid = self.target.last_revision_info()
 
2999
            if _hook_master:
 
3000
                result.master_branch = _hook_master
 
3001
                result.local_branch = result.target_branch
 
3002
            else:
 
3003
                result.master_branch = result.target_branch
 
3004
                result.local_branch = None
 
3005
            if run_hooks:
 
3006
                for hook in Branch.hooks['post_pull']:
 
3007
                    hook(result)
 
3008
        finally:
 
3009
            self.source.unlock()
 
3010
        return result
 
3011
 
 
3012
    def push(self, overwrite=False, stop_revision=None,
 
3013
             _override_hook_source_branch=None):
 
3014
        """See InterBranch.push.
 
3015
 
 
3016
        This is the basic concrete implementation of push()
 
3017
 
 
3018
        :param _override_hook_source_branch: If specified, run
 
3019
        the hooks passing this Branch as the source, rather than self.
 
3020
        This is for use of RemoteBranch, where push is delegated to the
 
3021
        underlying vfs-based Branch.
 
3022
        """
 
3023
        # TODO: Public option to disable running hooks - should be trivial but
 
3024
        # needs tests.
 
3025
        self.source.lock_read()
 
3026
        try:
 
3027
            return _run_with_write_locked_target(
 
3028
                self.target, self._push_with_bound_branches, overwrite,
 
3029
                stop_revision,
 
3030
                _override_hook_source_branch=_override_hook_source_branch)
 
3031
        finally:
 
3032
            self.source.unlock()
 
3033
        return result
 
3034
 
 
3035
    def _push_with_bound_branches(self, overwrite, stop_revision,
 
3036
            _override_hook_source_branch=None):
 
3037
        """Push from source into target, and into target's master if any.
 
3038
        """
 
3039
        def _run_hooks():
 
3040
            if _override_hook_source_branch:
 
3041
                result.source_branch = _override_hook_source_branch
 
3042
            for hook in Branch.hooks['post_push']:
 
3043
                hook(result)
 
3044
 
 
3045
        bound_location = self.target.get_bound_location()
 
3046
        if bound_location and self.target.base != bound_location:
 
3047
            # there is a master branch.
 
3048
            #
 
3049
            # XXX: Why the second check?  Is it even supported for a branch to
 
3050
            # be bound to itself? -- mbp 20070507
 
3051
            master_branch = self.target.get_master_branch()
 
3052
            master_branch.lock_write()
 
3053
            try:
 
3054
                # push into the master from the source branch.
 
3055
                self.source._basic_push(master_branch, overwrite, stop_revision)
 
3056
                # and push into the target branch from the source. Note that we
 
3057
                # push from the source branch again, because its considered the
 
3058
                # highest bandwidth repository.
 
3059
                result = self.source._basic_push(self.target, overwrite,
 
3060
                    stop_revision)
 
3061
                result.master_branch = master_branch
 
3062
                result.local_branch = self.target
 
3063
                _run_hooks()
 
3064
                return result
 
3065
            finally:
 
3066
                master_branch.unlock()
 
3067
        else:
 
3068
            # no master branch
 
3069
            result = self.source._basic_push(self.target, overwrite,
 
3070
                stop_revision)
 
3071
            # TODO: Why set master_branch and local_branch if there's no
 
3072
            # binding?  Maybe cleaner to just leave them unset? -- mbp
 
3073
            # 20070504
 
3074
            result.master_branch = self.target
 
3075
            result.local_branch = None
 
3076
            _run_hooks()
 
3077
            return result
 
3078
 
3071
3079
    @classmethod
3072
3080
    def is_compatible(self, source, target):
3073
3081
        # GenericBranch uses the public API, so always compatible
3074
3082
        return True
3075
3083
 
3076
3084
 
 
3085
class InterToBranch5(GenericInterBranch):
 
3086
 
 
3087
    @staticmethod
 
3088
    def _get_branch_formats_to_test():
 
3089
        return BranchFormat._default_format, BzrBranchFormat5()
 
3090
 
 
3091
    def pull(self, overwrite=False, stop_revision=None,
 
3092
             possible_transports=None, run_hooks=True,
 
3093
             _override_hook_target=None, local=False):
 
3094
        """Pull from source into self, updating my master if any.
 
3095
 
 
3096
        :param run_hooks: Private parameter - if false, this branch
 
3097
            is being called because it's the master of the primary branch,
 
3098
            so it should not run its hooks.
 
3099
        """
 
3100
        bound_location = self.target.get_bound_location()
 
3101
        if local and not bound_location:
 
3102
            raise errors.LocalRequiresBoundBranch()
 
3103
        master_branch = None
 
3104
        if not local and bound_location and self.source.base != bound_location:
 
3105
            # not pulling from master, so we need to update master.
 
3106
            master_branch = self.target.get_master_branch(possible_transports)
 
3107
            master_branch.lock_write()
 
3108
        try:
 
3109
            if master_branch:
 
3110
                # pull from source into master.
 
3111
                master_branch.pull(self.source, overwrite, stop_revision,
 
3112
                    run_hooks=False)
 
3113
            return super(InterToBranch5, self).pull(overwrite,
 
3114
                stop_revision, _hook_master=master_branch,
 
3115
                run_hooks=run_hooks,
 
3116
                _override_hook_target=_override_hook_target)
 
3117
        finally:
 
3118
            if master_branch:
 
3119
                master_branch.unlock()
 
3120
 
 
3121
 
3077
3122
InterBranch.register_optimiser(GenericInterBranch)
 
3123
InterBranch.register_optimiser(InterToBranch5)