/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

merge bzr.dev r4042

Show diffs side-by-side

added added

removed removed

Lines of Context:
45
45
 
46
46
from bzrlib.decorators import needs_read_lock, needs_write_lock
47
47
from bzrlib.hooks import Hooks
 
48
from bzrlib import registry
48
49
from bzrlib.symbol_versioning import (
49
50
    deprecated_in,
50
51
    deprecated_method,
89
90
        self.tags = self._make_tags()
90
91
        self._revision_history_cache = None
91
92
        self._revision_id_to_revno_cache = None
 
93
        self._partial_revision_id_to_revno_cache = {}
92
94
        self._last_revision_info_cache = None
 
95
        self._merge_sorted_revisions_cache = None
93
96
        self._open_hook()
94
97
        hooks = Branch.hooks['open']
95
98
        for hook in hooks:
132
135
    @staticmethod
133
136
    def open_containing(url, possible_transports=None):
134
137
        """Open an existing branch which contains url.
135
 
        
 
138
 
136
139
        This probes for a branch at url, and searches upwards from there.
137
140
 
138
141
        Basically we keep looking up until we find the control directory or
139
142
        run into the root.  If there isn't one, raises NotBranchError.
140
 
        If there is one and it is either an unrecognised format or an unsupported 
 
143
        If there is one and it is either an unrecognised format or an unsupported
141
144
        format, UnknownFormatError or UnsupportedFormatError are raised.
142
145
        If there is one, it is returned, along with the unused portion of url.
143
146
        """
145
148
                                                         possible_transports)
146
149
        return control.open_branch(), relpath
147
150
 
 
151
    def _push_should_merge_tags(self):
 
152
        """Should _basic_push merge this branch's tags into the target?
 
153
 
 
154
        The default implementation returns False if this branch has no tags,
 
155
        and True the rest of the time.  Subclasses may override this.
 
156
        """
 
157
        return self.tags.supports_tags() and self.tags.get_tag_dict()
 
158
 
148
159
    def get_config(self):
149
160
        return BranchConfig(self)
150
161
 
172
183
    def is_locked(self):
173
184
        raise NotImplementedError(self.is_locked)
174
185
 
 
186
    def _lefthand_history(self, revision_id, last_rev=None,
 
187
                          other_branch=None):
 
188
        if 'evil' in debug.debug_flags:
 
189
            mutter_callsite(4, "_lefthand_history scales with history.")
 
190
        # stop_revision must be a descendant of last_revision
 
191
        graph = self.repository.get_graph()
 
192
        if last_rev is not None:
 
193
            if not graph.is_ancestor(last_rev, revision_id):
 
194
                # our previous tip is not merged into stop_revision
 
195
                raise errors.DivergedBranches(self, other_branch)
 
196
        # make a new revision history from the graph
 
197
        parents_map = graph.get_parent_map([revision_id])
 
198
        if revision_id not in parents_map:
 
199
            raise errors.NoSuchRevision(self, revision_id)
 
200
        current_rev_id = revision_id
 
201
        new_history = []
 
202
        check_not_reserved_id = _mod_revision.check_not_reserved_id
 
203
        # Do not include ghosts or graph origin in revision_history
 
204
        while (current_rev_id in parents_map and
 
205
               len(parents_map[current_rev_id]) > 0):
 
206
            check_not_reserved_id(current_rev_id)
 
207
            new_history.append(current_rev_id)
 
208
            current_rev_id = parents_map[current_rev_id][0]
 
209
            parents_map = graph.get_parent_map([current_rev_id])
 
210
        new_history.reverse()
 
211
        return new_history
 
212
 
175
213
    def lock_write(self):
176
214
        raise NotImplementedError(self.lock_write)
177
215
 
189
227
        raise NotImplementedError(self.get_physical_lock_status)
190
228
 
191
229
    @needs_read_lock
 
230
    def dotted_revno_to_revision_id(self, revno, _cache_reverse=False):
 
231
        """Return the revision_id for a dotted revno.
 
232
 
 
233
        :param revno: a tuple like (1,) or (1,1,2)
 
234
        :param _cache_reverse: a private parameter enabling storage
 
235
           of the reverse mapping in a top level cache. (This should
 
236
           only be done in selective circumstances as we want to
 
237
           avoid having the mapping cached multiple times.)
 
238
        :return: the revision_id
 
239
        :raises errors.NoSuchRevision: if the revno doesn't exist
 
240
        """
 
241
        rev_id = self._do_dotted_revno_to_revision_id(revno)
 
242
        if _cache_reverse:
 
243
            self._partial_revision_id_to_revno_cache[rev_id] = revno
 
244
        return rev_id
 
245
 
 
246
    def _do_dotted_revno_to_revision_id(self, revno):
 
247
        """Worker function for dotted_revno_to_revision_id.
 
248
 
 
249
        Subclasses should override this if they wish to
 
250
        provide a more efficient implementation.
 
251
        """
 
252
        if len(revno) == 1:
 
253
            return self.get_rev_id(revno[0])
 
254
        revision_id_to_revno = self.get_revision_id_to_revno_map()
 
255
        revision_ids = [revision_id for revision_id, this_revno
 
256
                        in revision_id_to_revno.iteritems()
 
257
                        if revno == this_revno]
 
258
        if len(revision_ids) == 1:
 
259
            return revision_ids[0]
 
260
        else:
 
261
            revno_str = '.'.join(map(str, revno))
 
262
            raise errors.NoSuchRevision(self, revno_str)
 
263
 
 
264
    @needs_read_lock
 
265
    def revision_id_to_dotted_revno(self, revision_id):
 
266
        """Given a revision id, return its dotted revno.
 
267
 
 
268
        :return: a tuple like (1,) or (400,1,3).
 
269
        """
 
270
        return self._do_revision_id_to_dotted_revno(revision_id)
 
271
 
 
272
    def _do_revision_id_to_dotted_revno(self, revision_id):
 
273
        """Worker function for revision_id_to_revno."""
 
274
        # Try the caches if they are loaded
 
275
        result = self._partial_revision_id_to_revno_cache.get(revision_id)
 
276
        if result is not None:
 
277
            return result
 
278
        if self._revision_id_to_revno_cache:
 
279
            result = self._revision_id_to_revno_cache.get(revision_id)
 
280
            if result is None:
 
281
                raise errors.NoSuchRevision(self, revision_id)
 
282
        # Try the mainline as it's optimised
 
283
        try:
 
284
            revno = self.revision_id_to_revno(revision_id)
 
285
            return (revno,)
 
286
        except errors.NoSuchRevision:
 
287
            # We need to load and use the full revno map after all
 
288
            result = self.get_revision_id_to_revno_map().get(revision_id)
 
289
            if result is None:
 
290
                raise errors.NoSuchRevision(self, revision_id)
 
291
        return result
 
292
 
 
293
    @needs_read_lock
192
294
    def get_revision_id_to_revno_map(self):
193
295
        """Return the revision_id => dotted revno map.
194
296
 
218
320
 
219
321
        :return: A dictionary mapping revision_id => dotted revno.
220
322
        """
221
 
        last_revision = self.last_revision()
222
 
        revision_graph = repository._old_get_graph(self.repository,
223
 
            last_revision)
224
 
        merge_sorted_revisions = tsort.merge_sort(
225
 
            revision_graph,
226
 
            last_revision,
227
 
            None,
228
 
            generate_revno=True)
229
323
        revision_id_to_revno = dict((rev_id, revno)
230
 
                                    for seq_num, rev_id, depth, revno, end_of_merge
231
 
                                     in merge_sorted_revisions)
 
324
            for rev_id, depth, revno, end_of_merge
 
325
             in self.iter_merge_sorted_revisions())
232
326
        return revision_id_to_revno
233
327
 
 
328
    @needs_read_lock
 
329
    def iter_merge_sorted_revisions(self, start_revision_id=None,
 
330
            stop_revision_id=None, stop_rule='exclude', direction='reverse'):
 
331
        """Walk the revisions for a branch in merge sorted order.
 
332
 
 
333
        Merge sorted order is the output from a merge-aware,
 
334
        topological sort, i.e. all parents come before their
 
335
        children going forward; the opposite for reverse.
 
336
 
 
337
        :param start_revision_id: the revision_id to begin walking from.
 
338
            If None, the branch tip is used.
 
339
        :param stop_revision_id: the revision_id to terminate the walk
 
340
            after. If None, the rest of history is included.
 
341
        :param stop_rule: if stop_revision_id is not None, the precise rule
 
342
            to use for termination:
 
343
            * 'exclude' - leave the stop revision out of the result (default)
 
344
            * 'include' - the stop revision is the last item in the result
 
345
            * 'with-merges' - include the stop revision and all of its
 
346
              merged revisions in the result
 
347
        :param direction: either 'reverse' or 'forward':
 
348
            * reverse means return the start_revision_id first, i.e.
 
349
              start at the most recent revision and go backwards in history
 
350
            * forward returns tuples in the opposite order to reverse.
 
351
              Note in particular that forward does *not* do any intelligent
 
352
              ordering w.r.t. depth as some clients of this API may like.
 
353
              (If required, that ought to be done at higher layers.)
 
354
 
 
355
        :return: an iterator over (revision_id, depth, revno, end_of_merge)
 
356
            tuples where:
 
357
 
 
358
            * revision_id: the unique id of the revision
 
359
            * depth: How many levels of merging deep this node has been
 
360
              found.
 
361
            * revno_sequence: This field provides a sequence of
 
362
              revision numbers for all revisions. The format is:
 
363
              (REVNO, BRANCHNUM, BRANCHREVNO). BRANCHNUM is the number of the
 
364
              branch that the revno is on. From left to right the REVNO numbers
 
365
              are the sequence numbers within that branch of the revision.
 
366
            * end_of_merge: When True the next node (earlier in history) is
 
367
              part of a different merge.
 
368
        """
 
369
        # Note: depth and revno values are in the context of the branch so
 
370
        # we need the full graph to get stable numbers, regardless of the
 
371
        # start_revision_id.
 
372
        if self._merge_sorted_revisions_cache is None:
 
373
            last_revision = self.last_revision()
 
374
            graph = self.repository.get_graph()
 
375
            parent_map = dict(((key, value) for key, value in
 
376
                     graph.iter_ancestry([last_revision]) if value is not None))
 
377
            revision_graph = repository._strip_NULL_ghosts(parent_map)
 
378
            revs = tsort.merge_sort(revision_graph, last_revision, None,
 
379
                generate_revno=True)
 
380
            # Drop the sequence # before caching
 
381
            self._merge_sorted_revisions_cache = [r[1:] for r in revs]
 
382
 
 
383
        filtered = self._filter_merge_sorted_revisions(
 
384
            self._merge_sorted_revisions_cache, start_revision_id,
 
385
            stop_revision_id, stop_rule)
 
386
        if direction == 'reverse':
 
387
            return filtered
 
388
        if direction == 'forward':
 
389
            return reversed(list(filtered))
 
390
        else:
 
391
            raise ValueError('invalid direction %r' % direction)
 
392
 
 
393
    def _filter_merge_sorted_revisions(self, merge_sorted_revisions,
 
394
        start_revision_id, stop_revision_id, stop_rule):
 
395
        """Iterate over an inclusive range of sorted revisions."""
 
396
        rev_iter = iter(merge_sorted_revisions)
 
397
        if start_revision_id is not None:
 
398
            for rev_id, depth, revno, end_of_merge in rev_iter:
 
399
                if rev_id != start_revision_id:
 
400
                    continue
 
401
                else:
 
402
                    # The decision to include the start or not
 
403
                    # depends on the stop_rule if a stop is provided
 
404
                    rev_iter = chain(
 
405
                        iter([(rev_id, depth, revno, end_of_merge)]),
 
406
                        rev_iter)
 
407
                    break
 
408
        if stop_revision_id is None:
 
409
            for rev_id, depth, revno, end_of_merge in rev_iter:
 
410
                yield rev_id, depth, revno, end_of_merge
 
411
        elif stop_rule == 'exclude':
 
412
            for rev_id, depth, revno, end_of_merge in rev_iter:
 
413
                if rev_id == stop_revision_id:
 
414
                    return
 
415
                yield rev_id, depth, revno, end_of_merge
 
416
        elif stop_rule == 'include':
 
417
            for rev_id, depth, revno, end_of_merge in rev_iter:
 
418
                yield rev_id, depth, revno, end_of_merge
 
419
                if rev_id == stop_revision_id:
 
420
                    return
 
421
        elif stop_rule == 'with-merges':
 
422
            stop_rev = self.repository.get_revision(stop_revision_id)
 
423
            if stop_rev.parent_ids:
 
424
                left_parent = stop_rev.parent_ids[0]
 
425
            else:
 
426
                left_parent = _mod_revision.NULL_REVISION
 
427
            for rev_id, depth, revno, end_of_merge in rev_iter:
 
428
                if rev_id == left_parent:
 
429
                    return
 
430
                yield rev_id, depth, revno, end_of_merge
 
431
        else:
 
432
            raise ValueError('invalid stop_rule %r' % stop_rule)
 
433
 
234
434
    def leave_lock_in_place(self):
235
435
        """Tell this branch object not to release the physical lock when this
236
436
        object is unlocked.
237
 
        
 
437
 
238
438
        If lock_write doesn't return a token, then this method is not supported.
239
439
        """
240
440
        self.control_files.leave_in_place()
296
496
        branch.
297
497
        """
298
498
        return None
299
 
    
 
499
 
300
500
    def get_old_bound_location(self):
301
501
        """Return the URL of the branch we used to be bound to
302
502
        """
303
503
        raise errors.UpgradeRequired(self.base)
304
504
 
305
 
    def get_commit_builder(self, parents, config=None, timestamp=None, 
306
 
                           timezone=None, committer=None, revprops=None, 
 
505
    def get_commit_builder(self, parents, config=None, timestamp=None,
 
506
                           timezone=None, committer=None, revprops=None,
307
507
                           revision_id=None):
308
508
        """Obtain a CommitBuilder for this branch.
309
 
        
 
509
 
310
510
        :param parents: Revision ids of the parents of the new revision.
311
511
        :param config: Optional configuration to use.
312
512
        :param timestamp: Optional timestamp recorded for commit.
318
518
 
319
519
        if config is None:
320
520
            config = self.get_config()
321
 
        
 
521
 
322
522
        return self.repository.get_commit_builder(self, parents, config,
323
523
            timestamp, timezone, committer, revprops, revision_id)
324
524
 
325
525
    def get_master_branch(self, possible_transports=None):
326
526
        """Return the branch we are bound to.
327
 
        
 
527
 
328
528
        :return: Either a Branch, or None
329
529
        """
330
530
        return None
397
597
        self._revision_history_cache = None
398
598
        self._revision_id_to_revno_cache = None
399
599
        self._last_revision_info_cache = None
 
600
        self._merge_sorted_revisions_cache = None
400
601
 
401
602
    def _gen_revision_history(self):
402
603
        """Return sequence of revision hashes on to this branch.
403
 
        
 
604
 
404
605
        Unlike revision_history, this method always regenerates or rereads the
405
606
        revision history, i.e. it does not cache the result, so repeated calls
406
607
        may be expensive.
407
608
 
408
609
        Concrete subclasses should override this instead of revision_history so
409
610
        that subclasses do not need to deal with caching logic.
410
 
        
 
611
 
411
612
        This API is semi-public; it only for use by subclasses, all other code
412
613
        should consider it to be private.
413
614
        """
416
617
    @needs_read_lock
417
618
    def revision_history(self):
418
619
        """Return sequence of revision ids on this branch.
419
 
        
 
620
 
420
621
        This method will cache the revision history for as long as it is safe to
421
622
        do so.
422
623
        """
470
671
    @deprecated_method(deprecated_in((1, 6, 0)))
471
672
    def missing_revisions(self, other, stop_revision=None):
472
673
        """Return a list of new revisions that would perfectly fit.
473
 
        
 
674
 
474
675
        If self and other have not diverged, return a list of the revisions
475
676
        present in other, but missing from self.
476
677
        """
518
719
            # possibly]
519
720
            last_rev = _mod_revision.ensure_null(self.last_revision())
520
721
            # we fetch here so that we don't process data twice in the common
521
 
            # case of having something to pull, and so that the check for 
 
722
            # case of having something to pull, and so that the check for
522
723
            # already merged can operate on the just fetched graph, which will
523
724
            # be cached in memory.
524
725
            self.fetch(other, stop_revision)
586
787
    def get_parent(self):
587
788
        """Return the parent location of the branch.
588
789
 
589
 
        This is the default location for push/pull/missing.  The usual
 
790
        This is the default location for pull/missing.  The usual
590
791
        pattern is that the user can override it by specifying a
591
792
        location.
592
793
        """
654
855
        """Set a new push location for this branch."""
655
856
        raise NotImplementedError(self.set_push_location)
656
857
 
 
858
    def _run_post_change_branch_tip_hooks(self, old_revno, old_revid):
 
859
        """Run the post_change_branch_tip hooks."""
 
860
        hooks = Branch.hooks['post_change_branch_tip']
 
861
        if not hooks:
 
862
            return
 
863
        new_revno, new_revid = self.last_revision_info()
 
864
        params = ChangeBranchTipParams(
 
865
            self, old_revno, new_revno, old_revid, new_revid)
 
866
        for hook in hooks:
 
867
            hook(params)
 
868
 
 
869
    def _run_pre_change_branch_tip_hooks(self, new_revno, new_revid):
 
870
        """Run the pre_change_branch_tip hooks."""
 
871
        hooks = Branch.hooks['pre_change_branch_tip']
 
872
        if not hooks:
 
873
            return
 
874
        old_revno, old_revid = self.last_revision_info()
 
875
        params = ChangeBranchTipParams(
 
876
            self, old_revno, new_revno, old_revid, new_revid)
 
877
        for hook in hooks:
 
878
            try:
 
879
                hook(params)
 
880
            except errors.TipChangeRejected:
 
881
                raise
 
882
            except Exception:
 
883
                exc_info = sys.exc_info()
 
884
                hook_name = Branch.hooks.get_hook_name(hook)
 
885
                raise errors.HookFailed(
 
886
                    'pre_change_branch_tip', hook_name, exc_info)
 
887
 
657
888
    def set_parent(self, url):
658
889
        raise NotImplementedError(self.set_parent)
659
890
 
660
891
    @needs_write_lock
661
892
    def update(self):
662
 
        """Synchronise this branch with the master branch if any. 
 
893
        """Synchronise this branch with the master branch if any.
663
894
 
664
895
        :return: None or the last_revision pivoted out during the update.
665
896
        """
672
903
        """
673
904
        if revno != 0:
674
905
            self.check_real_revno(revno)
675
 
            
 
906
 
676
907
    def check_real_revno(self, revno):
677
908
        """\
678
909
        Check whether a revno corresponds to a real revision.
684
915
    @needs_read_lock
685
916
    def clone(self, to_bzrdir, revision_id=None):
686
917
        """Clone this branch into to_bzrdir preserving all semantic values.
687
 
        
 
918
 
688
919
        revision_id: if not None, the revision history in the new branch will
689
920
                     be truncated to end with revision_id.
690
921
        """
734
965
            revno = len(list(self.repository.iter_reverse_revision_history(
735
966
                                                                revision_id)))
736
967
        destination.set_last_revision_info(revno, revision_id)
737
 
    
 
968
 
738
969
    @needs_read_lock
739
970
    def copy_content_into(self, destination, revision_id=None):
740
971
        """Copy the content of self into destination.
750
981
        else:
751
982
            if parent:
752
983
                destination.set_parent(parent)
753
 
        self.tags.merge_to(destination.tags)
 
984
        if self._push_should_merge_tags():
 
985
            self.tags.merge_to(destination.tags)
754
986
 
755
987
    @needs_read_lock
756
988
    def check(self):
757
989
        """Check consistency of the branch.
758
990
 
759
991
        In particular this checks that revisions given in the revision-history
760
 
        do actually match up in the revision graph, and that they're all 
 
992
        do actually match up in the revision graph, and that they're all
761
993
        present in the repository.
762
 
        
 
994
 
763
995
        Callers will typically also want to check the repository.
764
996
 
765
997
        :return: A BranchCheckResult.
808
1040
                        lightweight=False, accelerator_tree=None,
809
1041
                        hardlink=False):
810
1042
        """Create a checkout of a branch.
811
 
        
 
1043
 
812
1044
        :param to_location: The url to produce the checkout at
813
1045
        :param revision_id: The revision to check out
814
1046
        :param lightweight: If True, produce a lightweight checkout, otherwise,
833
1065
                to_location, force_new_tree=False, format=format)
834
1066
            checkout = checkout_branch.bzrdir
835
1067
            checkout_branch.bind(self)
836
 
            # pull up to the specified revision_id to set the initial 
 
1068
            # pull up to the specified revision_id to set the initial
837
1069
            # branch tip correctly, and seed it with history.
838
1070
            checkout_branch.pull(self, stop_revision=revision_id)
839
1071
            from_branch=None
878
1110
        """Ensure that revision_b is a descendant of revision_a.
879
1111
 
880
1112
        This is a helper function for update_revisions.
881
 
        
 
1113
 
882
1114
        :raises: DivergedBranches if revision_b has diverged from revision_a.
883
1115
        :returns: True if revision_b is a descendant of revision_a.
884
1116
        """
894
1126
 
895
1127
    def _revision_relations(self, revision_a, revision_b, graph):
896
1128
        """Determine the relationship between two revisions.
897
 
        
 
1129
 
898
1130
        :returns: One of: 'a_descends_from_b', 'b_descends_from_a', 'diverged'
899
1131
        """
900
1132
        heads = graph.heads([revision_a, revision_b])
917
1149
     * a format string,
918
1150
     * an open routine.
919
1151
 
920
 
    Formats are placed in an dict by their format string for reference 
 
1152
    Formats are placed in an dict by their format string for reference
921
1153
    during branch opening. Its not required that these be instances, they
922
 
    can be classes themselves with class methods - it simply depends on 
 
1154
    can be classes themselves with class methods - it simply depends on
923
1155
    whether state is needed for a given format or not.
924
1156
 
925
1157
    Once a format is deprecated, just deprecate the initialize and open
926
 
    methods on the format class. Do not deprecate the object, as the 
 
1158
    methods on the format class. Do not deprecate the object, as the
927
1159
    object will be created every time regardless.
928
1160
    """
929
1161
 
1031
1263
        """Is this format supported?
1032
1264
 
1033
1265
        Supported formats can be initialized and opened.
1034
 
        Unsupported formats may not support initialization or committing or 
 
1266
        Unsupported formats may not support initialization or committing or
1035
1267
        some other features depending on the reason for not being supported.
1036
1268
        """
1037
1269
        return True
1038
1270
 
 
1271
    def network_name(self):
 
1272
        """A simple byte string uniquely identifying this format for RPC calls.
 
1273
 
 
1274
        MetaDir branch formats use their disk format string to identify the
 
1275
        repository over the wire. All in one formats such as bzr < 0.8, and
 
1276
        foreign formats like svn/git and hg should use some marker which is
 
1277
        unique and immutable.
 
1278
        """
 
1279
        raise NotImplementedError(self.network_name)
 
1280
 
1039
1281
    def open(self, a_bzrdir, _found=False):
1040
1282
        """Return the branch object for a_bzrdir
1041
1283
 
1046
1288
 
1047
1289
    @classmethod
1048
1290
    def register_format(klass, format):
 
1291
        """Register a metadir format."""
1049
1292
        klass._formats[format.get_format_string()] = format
 
1293
        # Metadir formats have a network name of their format string.
 
1294
        network_format_registry.register(format.get_format_string(), format)
1050
1295
 
1051
1296
    @classmethod
1052
1297
    def set_default_format(klass, format):
1061
1306
        del klass._formats[format.get_format_string()]
1062
1307
 
1063
1308
    def __str__(self):
1064
 
        return self.get_format_string().rstrip()
 
1309
        return self.get_format_description().rstrip()
1065
1310
 
1066
1311
    def supports_tags(self):
1067
1312
        """True if this format supports tags stored in the branch"""
1070
1315
 
1071
1316
class BranchHooks(Hooks):
1072
1317
    """A dictionary mapping hook name to a list of callables for branch hooks.
1073
 
    
 
1318
 
1074
1319
    e.g. ['set_rh'] Is the list of items to be called when the
1075
1320
    set_revision_history function is invoked.
1076
1321
    """
1095
1340
        # (push_result)
1096
1341
        # containing the members
1097
1342
        # (source, local, master, old_revno, old_revid, new_revno, new_revid)
1098
 
        # where local is the local target branch or None, master is the target 
 
1343
        # where local is the local target branch or None, master is the target
1099
1344
        # master branch, and the rest should be self explanatory. The source
1100
1345
        # is read locked and the target branches write locked. Source will
1101
1346
        # be the local low-latency branch.
1105
1350
        # (pull_result)
1106
1351
        # containing the members
1107
1352
        # (source, local, master, old_revno, old_revid, new_revno, new_revid)
1108
 
        # where local is the local branch or None, master is the target 
 
1353
        # where local is the local branch or None, master is the target
1109
1354
        # master branch, and the rest should be self explanatory. The source
1110
1355
        # is read locked and the target branches write locked. The local
1111
1356
        # branch is the low-latency branch.
1121
1366
        # CommitBuilder.revision_tree() and hooks MUST NOT modify this tree
1122
1367
        self['pre_commit'] = []
1123
1368
        # invoked after a commit operation completes.
1124
 
        # the api signature is 
 
1369
        # the api signature is
1125
1370
        # (local, master, old_revno, old_revid, new_revno, new_revid)
1126
1371
        # old_revid is NULL_REVISION for the first commit to a branch.
1127
1372
        self['post_commit'] = []
1188
1433
 
1189
1434
    def __eq__(self, other):
1190
1435
        return self.__dict__ == other.__dict__
1191
 
    
 
1436
 
1192
1437
    def __repr__(self):
1193
1438
        return "<%s of %s from (%s, %s) to (%s, %s)>" % (
1194
 
            self.__class__.__name__, self.branch, 
 
1439
            self.__class__.__name__, self.branch,
1195
1440
            self.old_revno, self.old_revid, self.new_revno, self.new_revid)
1196
1441
 
1197
1442
 
1219
1464
        super(BzrBranchFormat4, self).__init__()
1220
1465
        self._matchingbzrdir = bzrdir.BzrDirFormat6()
1221
1466
 
 
1467
    def network_name(self):
 
1468
        """The network name for this format is the control dirs disk label."""
 
1469
        return self._matchingbzrdir.get_format_string()
 
1470
 
1222
1471
    def open(self, a_bzrdir, _found=False):
1223
1472
        """Return the branch object for a_bzrdir
1224
1473
 
1244
1493
        """What class to instantiate on open calls."""
1245
1494
        raise NotImplementedError(self._branch_class)
1246
1495
 
 
1496
    def network_name(self):
 
1497
        """A simple byte string uniquely identifying this format for RPC calls.
 
1498
 
 
1499
        Metadir branch formats use their format string.
 
1500
        """
 
1501
        return self.get_format_string()
 
1502
 
1247
1503
    def open(self, a_bzrdir, _found=False):
1248
1504
        """Return the branch object for a_bzrdir.
1249
1505
 
1298
1554
    def get_format_description(self):
1299
1555
        """See BranchFormat.get_format_description()."""
1300
1556
        return "Branch format 5"
1301
 
        
 
1557
 
1302
1558
    def initialize(self, a_bzrdir):
1303
1559
        """Create a branch of this format in a_bzrdir."""
1304
1560
        utf8_files = [('revision-history', ''),
1466
1722
        return result
1467
1723
 
1468
1724
 
 
1725
network_format_registry = registry.FormatRegistry()
 
1726
"""Registry of formats indexed by their network name.
 
1727
 
 
1728
The network name for a repository format is an identifier that can be used when
 
1729
referring to formats with smart server operations. See
 
1730
BranchFormat.network_name() for more detail.
 
1731
"""
 
1732
 
 
1733
 
1469
1734
# formats which have no format string are not discoverable
1470
1735
# and not independently creatable, so are not registered.
1471
1736
__format5 = BzrBranchFormat5()
1477
1742
BranchFormat.register_format(__format7)
1478
1743
BranchFormat.set_default_format(__format6)
1479
1744
_legacy_formats = [BzrBranchFormat4(),
1480
 
                   ]
 
1745
    ]
 
1746
network_format_registry.register(
 
1747
    _legacy_formats[0].network_name(), _legacy_formats[0])
 
1748
 
1481
1749
 
1482
1750
class BzrBranch(Branch):
1483
1751
    """A branch stored in the actual filesystem.
1486
1754
    really matter if it's on an nfs/smb/afs/coda/... share, as long as
1487
1755
    it's writable, and can be accessed via the normal filesystem API.
1488
1756
 
1489
 
    :ivar _transport: Transport for file operations on this branch's 
 
1757
    :ivar _transport: Transport for file operations on this branch's
1490
1758
        control files, typically pointing to the .bzr/branch directory.
1491
1759
    :ivar repository: Repository for this branch.
1492
 
    :ivar base: The url of the base directory for this branch; the one 
 
1760
    :ivar base: The url of the base directory for this branch; the one
1493
1761
        containing the .bzr directory.
1494
1762
    """
1495
 
    
 
1763
 
1496
1764
    def __init__(self, _format=None,
1497
1765
                 _control_files=None, a_bzrdir=None, _repository=None):
1498
1766
        """Create new branch object at a particular location."""
1552
1820
        if not self.control_files.is_locked():
1553
1821
            # we just released the lock
1554
1822
            self._clear_cached_state()
1555
 
        
 
1823
 
1556
1824
    def peek_lock_mode(self):
1557
1825
        if self.control_files._lock_count == 0:
1558
1826
            return None
1614
1882
        :param revision_id: The revision-id to truncate history at.  May
1615
1883
          be None to copy complete history.
1616
1884
        """
 
1885
        if not isinstance(destination._format, BzrBranchFormat5):
 
1886
            super(BzrBranch, self)._synchronize_history(
 
1887
                destination, revision_id)
 
1888
            return
1617
1889
        if revision_id == _mod_revision.NULL_REVISION:
1618
1890
            new_history = []
1619
1891
        else:
1626
1898
                new_history = rev.get_history(self.repository)[1:]
1627
1899
        destination.set_revision_history(new_history)
1628
1900
 
1629
 
    def _run_pre_change_branch_tip_hooks(self, new_revno, new_revid):
1630
 
        """Run the pre_change_branch_tip hooks."""
1631
 
        hooks = Branch.hooks['pre_change_branch_tip']
1632
 
        if not hooks:
1633
 
            return
1634
 
        old_revno, old_revid = self.last_revision_info()
1635
 
        params = ChangeBranchTipParams(
1636
 
            self, old_revno, new_revno, old_revid, new_revid)
1637
 
        for hook in hooks:
1638
 
            try:
1639
 
                hook(params)
1640
 
            except errors.TipChangeRejected:
1641
 
                raise
1642
 
            except Exception:
1643
 
                exc_info = sys.exc_info()
1644
 
                hook_name = Branch.hooks.get_hook_name(hook)
1645
 
                raise errors.HookFailed(
1646
 
                    'pre_change_branch_tip', hook_name, exc_info)
1647
 
 
1648
 
    def _run_post_change_branch_tip_hooks(self, old_revno, old_revid):
1649
 
        """Run the post_change_branch_tip hooks."""
1650
 
        hooks = Branch.hooks['post_change_branch_tip']
1651
 
        if not hooks:
1652
 
            return
1653
 
        new_revno, new_revid = self.last_revision_info()
1654
 
        params = ChangeBranchTipParams(
1655
 
            self, old_revno, new_revno, old_revid, new_revid)
1656
 
        for hook in hooks:
1657
 
            hook(params)
1658
 
 
1659
1901
    @needs_write_lock
1660
1902
    def set_last_revision_info(self, revno, revision_id):
1661
1903
        """Set the last revision of this branch.
1664
1906
        for this revision id.
1665
1907
 
1666
1908
        It may be possible to set the branch last revision to an id not
1667
 
        present in the repository.  However, branches can also be 
 
1909
        present in the repository.  However, branches can also be
1668
1910
        configured to check constraints on history, in which case this may not
1669
1911
        be permitted.
1670
1912
        """
1684
1926
            history.pop()
1685
1927
        return history
1686
1928
 
1687
 
    def _lefthand_history(self, revision_id, last_rev=None,
1688
 
                          other_branch=None):
1689
 
        if 'evil' in debug.debug_flags:
1690
 
            mutter_callsite(4, "_lefthand_history scales with history.")
1691
 
        # stop_revision must be a descendant of last_revision
1692
 
        graph = self.repository.get_graph()
1693
 
        if last_rev is not None:
1694
 
            if not graph.is_ancestor(last_rev, revision_id):
1695
 
                # our previous tip is not merged into stop_revision
1696
 
                raise errors.DivergedBranches(self, other_branch)
1697
 
        # make a new revision history from the graph
1698
 
        parents_map = graph.get_parent_map([revision_id])
1699
 
        if revision_id not in parents_map:
1700
 
            raise errors.NoSuchRevision(self, revision_id)
1701
 
        current_rev_id = revision_id
1702
 
        new_history = []
1703
 
        check_not_reserved_id = _mod_revision.check_not_reserved_id
1704
 
        # Do not include ghosts or graph origin in revision_history
1705
 
        while (current_rev_id in parents_map and
1706
 
               len(parents_map[current_rev_id]) > 0):
1707
 
            check_not_reserved_id(current_rev_id)
1708
 
            new_history.append(current_rev_id)
1709
 
            current_rev_id = parents_map[current_rev_id][0]
1710
 
            parents_map = graph.get_parent_map([current_rev_id])
1711
 
        new_history.reverse()
1712
 
        return new_history
1713
 
 
1714
1929
    @needs_write_lock
1715
1930
    def generate_revision_history(self, revision_id, last_rev=None,
1716
1931
        other_branch=None):
1735
1950
             _override_hook_target=None):
1736
1951
        """See Branch.pull.
1737
1952
 
1738
 
        :param _hook_master: Private parameter - set the branch to 
 
1953
        :param _hook_master: Private parameter - set the branch to
1739
1954
            be supplied as the master to pull hooks.
1740
1955
        :param run_hooks: Private parameter - if false, this branch
1741
1956
            is being called because it's the master of the primary branch,
1789
2004
        This is the basic concrete implementation of push()
1790
2005
 
1791
2006
        :param _override_hook_source_branch: If specified, run
1792
 
        the hooks passing this Branch as the source, rather than self.  
 
2007
        the hooks passing this Branch as the source, rather than self.
1793
2008
        This is for use of RemoteBranch, where push is delegated to the
1794
 
        underlying vfs-based Branch. 
 
2009
        underlying vfs-based Branch.
1795
2010
        """
1796
2011
        # TODO: Public option to disable running hooks - should be trivial but
1797
2012
        # needs tests.
1804
2019
            stop_revision,
1805
2020
            _override_hook_source_branch=None):
1806
2021
        """Push from self into target, and into target's master if any.
1807
 
        
1808
 
        This is on the base BzrBranch class even though it doesn't support 
 
2022
 
 
2023
        This is on the base BzrBranch class even though it doesn't support
1809
2024
        bound branches because the *target* might be bound.
1810
2025
        """
1811
2026
        def _run_hooks():
1866
2081
        result.new_revno, result.new_revid = target.last_revision_info()
1867
2082
        return result
1868
2083
 
1869
 
    def _push_should_merge_tags(self):
1870
 
        """Should _basic_push merge this branch's tags into the target?
1871
 
        
1872
 
        The default implementation returns False if this branch has no tags,
1873
 
        and True the rest of the time.  Subclasses may override this.
1874
 
        """
1875
 
        return self.tags.supports_tags() and self.tags.get_tag_dict()
1876
 
 
1877
2084
    def get_parent(self):
1878
2085
        """See Branch.get_parent."""
1879
2086
        parent = self._get_parent_location()
1937
2144
             run_hooks=True, possible_transports=None,
1938
2145
             _override_hook_target=None):
1939
2146
        """Pull from source into self, updating my master if any.
1940
 
        
 
2147
 
1941
2148
        :param run_hooks: Private parameter - if false, this branch
1942
2149
            is being called because it's the master of the primary branch,
1943
2150
            so it should not run its hooks.
1970
2177
    @needs_read_lock
1971
2178
    def get_master_branch(self, possible_transports=None):
1972
2179
        """Return the branch we are bound to.
1973
 
        
 
2180
 
1974
2181
        :return: Either a Branch, or None
1975
2182
 
1976
2183
        This could memoise the branch, but if thats done
2012
2219
        check for divergence to raise an error when the branches are not
2013
2220
        either the same, or one a prefix of the other. That behaviour may not
2014
2221
        be useful, so that check may be removed in future.
2015
 
        
 
2222
 
2016
2223
        :param other: The branch to bind to
2017
2224
        :type other: Branch
2018
2225
        """
2037
2244
 
2038
2245
    @needs_write_lock
2039
2246
    def update(self, possible_transports=None):
2040
 
        """Synchronise this branch with the master branch if any. 
 
2247
        """Synchronise this branch with the master branch if any.
2041
2248
 
2042
2249
        :return: None or the last_revision that was pivoted out during the
2043
2250
                 update.
2059
2266
    def _get_fallback_repository(self, url):
2060
2267
        """Get the repository we fallback to at url."""
2061
2268
        url = urlutils.join(self.base, url)
2062
 
        return bzrdir.BzrDir.open(url).open_branch().repository
 
2269
        a_bzrdir = bzrdir.BzrDir.open(url,
 
2270
                                      possible_transports=[self._transport])
 
2271
        return a_bzrdir.open_branch().repository
2063
2272
 
2064
2273
    def _activate_fallback_location(self, url):
2065
2274
        """Activate the branch/repository from url as a fallback repository."""
2132
2341
 
2133
2342
    def _synchronize_history(self, destination, revision_id):
2134
2343
        """Synchronize last revision and revision history between branches.
2135
 
        
 
2344
 
2136
2345
        :see: Branch._synchronize_history
2137
2346
        """
2138
2347
        # XXX: The base Branch has a fast implementation of this method based
2435
2644
 
2436
2645
    def report_results(self, verbose):
2437
2646
        """Report the check results via trace.note.
2438
 
        
 
2647
 
2439
2648
        :param verbose: Requests more detailed display of what was checked,
2440
2649
            if any.
2441
2650
        """
2501
2710
            return callable(*args, **kwargs)
2502
2711
        finally:
2503
2712
            target.unlock()
2504
 
    
 
2713
 
2505
2714
    """
2506
2715
    # This is very similar to bzrlib.decorators.needs_write_lock.  Perhaps they
2507
2716
    # should share code?