/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: Marco Pantaleoni
  • Date: 2010-03-25 18:02:45 UTC
  • mto: This revision was merged to the branch mainline in revision 5174.
  • Revision ID: panta@elasticworld.org-20100325180245-1lt7v5stt13m92tr
Documented behaviour of 'post_branch_init' for lightweight checkouts.

Added blackbox tests for the three hooks.

Show diffs side-by-side

added added

removed removed

Lines of Context:
63
63
BZR_BRANCH_FORMAT_6 = "Bazaar Branch Format 6 (bzr 0.15)\n"
64
64
 
65
65
 
66
 
class Branch(bzrdir.ControlComponent):
 
66
# TODO: Maybe include checks for common corruption of newlines, etc?
 
67
 
 
68
# TODO: Some operations like log might retrieve the same revisions
 
69
# repeatedly to calculate deltas.  We could perhaps have a weakref
 
70
# cache in memory to make this faster.  In general anything can be
 
71
# cached in memory between lock and unlock operations. .. nb thats
 
72
# what the transaction identity map provides
 
73
 
 
74
 
 
75
######################################################################
 
76
# branch objects
 
77
 
 
78
class Branch(object):
67
79
    """Branch holding a history of revisions.
68
80
 
69
 
    :ivar base:
70
 
        Base directory/url of the branch; using control_url and
71
 
        control_transport is more standardized.
 
81
    base
 
82
        Base directory/url of the branch.
72
83
 
73
84
    hooks: An instance of BranchHooks.
74
85
    """
76
87
    # - RBC 20060112
77
88
    base = None
78
89
 
79
 
    @property
80
 
    def control_transport(self):
81
 
        return self._transport
82
 
 
83
 
    @property
84
 
    def user_transport(self):
85
 
        return self.bzrdir.user_transport
86
 
 
87
90
    def __init__(self, *ignored, **ignored_too):
88
91
        self.tags = self._format.make_tags(self)
89
92
        self._revision_history_cache = None
104
107
        """Activate the branch/repository from url as a fallback repository."""
105
108
        repo = self._get_fallback_repository(url)
106
109
        if repo.has_same_location(self.repository):
107
 
            raise errors.UnstackableLocationError(self.user_url, url)
 
110
            raise errors.UnstackableLocationError(self.base, url)
108
111
        self.repository.add_fallback_repository(repo)
109
112
 
110
113
    def break_lock(self):
417
420
            * 'include' - the stop revision is the last item in the result
418
421
            * 'with-merges' - include the stop revision and all of its
419
422
              merged revisions in the result
420
 
            * 'with-merges-without-common-ancestry' - filter out revisions 
421
 
              that are in both ancestries
422
423
        :param direction: either 'reverse' or 'forward':
423
424
            * reverse means return the start_revision_id first, i.e.
424
425
              start at the most recent revision and go backwards in history
446
447
        # start_revision_id.
447
448
        if self._merge_sorted_revisions_cache is None:
448
449
            last_revision = self.last_revision()
449
 
            known_graph = self.repository.get_known_graph_ancestry(
450
 
                [last_revision])
 
450
            last_key = (last_revision,)
 
451
            known_graph = self.repository.revisions.get_known_graph_ancestry(
 
452
                [last_key])
451
453
            self._merge_sorted_revisions_cache = known_graph.merge_sort(
452
 
                last_revision)
 
454
                last_key)
453
455
        filtered = self._filter_merge_sorted_revisions(
454
456
            self._merge_sorted_revisions_cache, start_revision_id,
455
457
            stop_revision_id, stop_rule)
456
 
        # Make sure we don't return revisions that are not part of the
457
 
        # start_revision_id ancestry.
458
 
        filtered = self._filter_start_non_ancestors(filtered)
459
458
        if direction == 'reverse':
460
459
            return filtered
461
460
        if direction == 'forward':
498
497
                       node.end_of_merge)
499
498
                if rev_id == stop_revision_id:
500
499
                    return
501
 
        elif stop_rule == 'with-merges-without-common-ancestry':
502
 
            # We want to exclude all revisions that are already part of the
503
 
            # stop_revision_id ancestry.
504
 
            graph = self.repository.get_graph()
505
 
            ancestors = graph.find_unique_ancestors(start_revision_id,
506
 
                                                    [stop_revision_id])
507
 
            for node in rev_iter:
508
 
                rev_id = node.key[-1]
509
 
                if rev_id not in ancestors:
510
 
                    continue
511
 
                yield (rev_id, node.merge_depth, node.revno,
512
 
                       node.end_of_merge)
513
500
        elif stop_rule == 'with-merges':
514
501
            stop_rev = self.repository.get_revision(stop_revision_id)
515
502
            if stop_rev.parent_ids:
538
525
        else:
539
526
            raise ValueError('invalid stop_rule %r' % stop_rule)
540
527
 
541
 
    def _filter_start_non_ancestors(self, rev_iter):
542
 
        # If we started from a dotted revno, we want to consider it as a tip
543
 
        # and don't want to yield revisions that are not part of its
544
 
        # ancestry. Given the order guaranteed by the merge sort, we will see
545
 
        # uninteresting descendants of the first parent of our tip before the
546
 
        # tip itself.
547
 
        first = rev_iter.next()
548
 
        (rev_id, merge_depth, revno, end_of_merge) = first
549
 
        yield first
550
 
        if not merge_depth:
551
 
            # We start at a mainline revision so by definition, all others
552
 
            # revisions in rev_iter are ancestors
553
 
            for node in rev_iter:
554
 
                yield node
555
 
 
556
 
        clean = False
557
 
        whitelist = set()
558
 
        pmap = self.repository.get_parent_map([rev_id])
559
 
        parents = pmap.get(rev_id, [])
560
 
        if parents:
561
 
            whitelist.update(parents)
562
 
        else:
563
 
            # If there is no parents, there is nothing of interest left
564
 
 
565
 
            # FIXME: It's hard to test this scenario here as this code is never
566
 
            # called in that case. -- vila 20100322
567
 
            return
568
 
 
569
 
        for (rev_id, merge_depth, revno, end_of_merge) in rev_iter:
570
 
            if not clean:
571
 
                if rev_id in whitelist:
572
 
                    pmap = self.repository.get_parent_map([rev_id])
573
 
                    parents = pmap.get(rev_id, [])
574
 
                    whitelist.remove(rev_id)
575
 
                    whitelist.update(parents)
576
 
                    if merge_depth == 0:
577
 
                        # We've reached the mainline, there is nothing left to
578
 
                        # filter
579
 
                        clean = True
580
 
                else:
581
 
                    # A revision that is not part of the ancestry of our
582
 
                    # starting revision.
583
 
                    continue
584
 
            yield (rev_id, merge_depth, revno, end_of_merge)
585
 
 
586
528
    def leave_lock_in_place(self):
587
529
        """Tell this branch object not to release the physical lock when this
588
530
        object is unlocked.
605
547
        :param other: The branch to bind to
606
548
        :type other: Branch
607
549
        """
608
 
        raise errors.UpgradeRequired(self.user_url)
 
550
        raise errors.UpgradeRequired(self.base)
609
551
 
610
552
    def set_append_revisions_only(self, enabled):
611
553
        if not self._format.supports_set_append_revisions_only():
612
 
            raise errors.UpgradeRequired(self.user_url)
 
554
            raise errors.UpgradeRequired(self.base)
613
555
        if enabled:
614
556
            value = 'True'
615
557
        else:
663
605
    def get_old_bound_location(self):
664
606
        """Return the URL of the branch we used to be bound to
665
607
        """
666
 
        raise errors.UpgradeRequired(self.user_url)
 
608
        raise errors.UpgradeRequired(self.base)
667
609
 
668
610
    def get_commit_builder(self, parents, config=None, timestamp=None,
669
611
                           timezone=None, committer=None, revprops=None,
747
689
            stacking.
748
690
        """
749
691
        if not self._format.supports_stacking():
750
 
            raise errors.UnstackableBranchFormat(self._format, self.user_url)
 
692
            raise errors.UnstackableBranchFormat(self._format, self.base)
751
693
        # XXX: Changing from one fallback repository to another does not check
752
694
        # that all the data you need is present in the new fallback.
753
695
        # Possibly it should.
904
846
 
905
847
    def unbind(self):
906
848
        """Older format branches cannot bind or unbind."""
907
 
        raise errors.UpgradeRequired(self.user_url)
 
849
        raise errors.UpgradeRequired(self.base)
908
850
 
909
851
    def last_revision(self):
910
852
        """Return last revision id, or NULL_REVISION."""
1070
1012
        try:
1071
1013
            return urlutils.join(self.base[:-1], parent)
1072
1014
        except errors.InvalidURLJoin, e:
1073
 
            raise errors.InaccessibleParent(parent, self.user_url)
 
1015
            raise errors.InaccessibleParent(parent, self.base)
1074
1016
 
1075
1017
    def _get_parent_location(self):
1076
1018
        raise NotImplementedError(self._get_parent_location)
1575
1517
            elsewhere)
1576
1518
        :return: a branch in this format
1577
1519
        """
1578
 
        mutter('creating branch %r in %s', self, a_bzrdir.user_url)
 
1520
        mutter('creating branch %r in %s', self, a_bzrdir.transport.base)
1579
1521
        branch_transport = a_bzrdir.get_branch_transport(self, name=name)
1580
1522
        lock_map = {
1581
1523
            'metadir': ('lock', lockdir.LockDir),
1968
1910
            if format.__class__ != self.__class__:
1969
1911
                raise AssertionError("wrong format %r found for %r" %
1970
1912
                    (format, self))
1971
 
        transport = a_bzrdir.get_branch_transport(None, name=name)
1972
1913
        try:
 
1914
            transport = a_bzrdir.get_branch_transport(None, name=name)
1973
1915
            control_files = lockable_files.LockableFiles(transport, 'lock',
1974
1916
                                                         lockdir.LockDir)
1975
1917
            return self._branch_class()(_format=self,
2173
2115
            # this format does not implement branch itself, thus the implicit
2174
2116
            # creation contract must see it as uninitializable
2175
2117
            raise errors.UninitializableFormat(self)
2176
 
        mutter('creating branch reference in %s', a_bzrdir.user_url)
 
2118
        mutter('creating branch reference in %s', a_bzrdir.transport.base)
2177
2119
        branch_transport = a_bzrdir.get_branch_transport(self, name=name)
2178
2120
        branch_transport.put_bytes('location',
2179
 
            target_branch.bzrdir.user_url)
 
2121
            target_branch.bzrdir.root_transport.base)
2180
2122
        branch_transport.put_bytes('format', self.get_format_string())
2181
2123
        branch = self.open(
2182
2124
            a_bzrdir, name, _found=True,
2304
2246
 
2305
2247
    def __str__(self):
2306
2248
        if self.name is None:
2307
 
            return '%s(%s)' % (self.__class__.__name__, self.user_url)
 
2249
            return '%s(%r)' % (self.__class__.__name__, self.base)
2308
2250
        else:
2309
 
            return '%s(%s,%s)' % (self.__class__.__name__, self.user_url,
2310
 
                self.name)
 
2251
            return '%s(%r,%r)' % (self.__class__.__name__, self.base, self.name)
2311
2252
 
2312
2253
    __repr__ = __str__
2313
2254
 
2528
2469
        return result
2529
2470
 
2530
2471
    def get_stacked_on_url(self):
2531
 
        raise errors.UnstackableBranchFormat(self._format, self.user_url)
 
2472
        raise errors.UnstackableBranchFormat(self._format, self.base)
2532
2473
 
2533
2474
    def set_push_location(self, location):
2534
2475
        """See Branch.set_push_location."""
2724
2665
        if _mod_revision.is_null(last_revision):
2725
2666
            return
2726
2667
        if last_revision not in self._lefthand_history(revision_id):
2727
 
            raise errors.AppendRevisionsOnlyViolation(self.user_url)
 
2668
            raise errors.AppendRevisionsOnlyViolation(self.base)
2728
2669
 
2729
2670
    def _gen_revision_history(self):
2730
2671
        """Generate the revision history from last revision
2830
2771
        if branch_location is None:
2831
2772
            return Branch.reference_parent(self, file_id, path,
2832
2773
                                           possible_transports)
2833
 
        branch_location = urlutils.join(self.user_url, branch_location)
 
2774
        branch_location = urlutils.join(self.base, branch_location)
2834
2775
        return Branch.open(branch_location,
2835
2776
                           possible_transports=possible_transports)
2836
2777
 
2882
2823
        return stacked_url
2883
2824
 
2884
2825
    def _get_append_revisions_only(self):
2885
 
        return self.get_config(
2886
 
            ).get_user_option_as_bool('append_revisions_only')
 
2826
        value = self.get_config().get_user_option('append_revisions_only')
 
2827
        return value == 'True'
2887
2828
 
2888
2829
    @needs_write_lock
2889
2830
    def generate_revision_history(self, revision_id, last_rev=None,
2951
2892
    """
2952
2893
 
2953
2894
    def get_stacked_on_url(self):
2954
 
        raise errors.UnstackableBranchFormat(self._format, self.user_url)
 
2895
        raise errors.UnstackableBranchFormat(self._format, self.base)
2955
2896
 
2956
2897
 
2957
2898
######################################################################
3044
2985
        :param verbose: Requests more detailed display of what was checked,
3045
2986
            if any.
3046
2987
        """
3047
 
        note('checked branch %s format %s', self.branch.user_url,
 
2988
        note('checked branch %s format %s', self.branch.base,
3048
2989
            self.branch._format)
3049
2990
        for error in self.errors:
3050
2991
            note('found error:%s', error)
3379
3320
        if local and not bound_location:
3380
3321
            raise errors.LocalRequiresBoundBranch()
3381
3322
        master_branch = None
3382
 
        if not local and bound_location and self.source.user_url != bound_location:
 
3323
        if not local and bound_location and self.source.base != bound_location:
3383
3324
            # not pulling from master, so we need to update master.
3384
3325
            master_branch = self.target.get_master_branch(possible_transports)
3385
3326
            master_branch.lock_write()