~bzr-pqm/bzr/bzr.dev

« back to all changes in this revision

Viewing changes to bzrlib/branch.py

  • Committer: Jelmer Vernooij
  • Date: 2012-02-21 12:51:25 UTC
  • mfrom: (6468.3.1 bzr)
  • mto: This revision was merged to the branch mainline in revision 6519.
  • Revision ID: jelmer@samba.org-20120221125125-7cpkwjmvf3aj2d9x
MergeĀ lp:~jelmer/bzr/use-tree-iter-children

Show diffs side-by-side

added added

removed removed

Lines of Context:
766
766
        """Print `file` to stdout."""
767
767
        raise NotImplementedError(self.print_file)
768
768
 
 
769
    @deprecated_method(deprecated_in((2, 4, 0)))
 
770
    def set_revision_history(self, rev_history):
 
771
        """See Branch.set_revision_history."""
 
772
        self._set_revision_history(rev_history)
 
773
 
 
774
    @needs_write_lock
 
775
    def _set_revision_history(self, rev_history):
 
776
        if len(rev_history) == 0:
 
777
            revid = _mod_revision.NULL_REVISION
 
778
        else:
 
779
            revid = rev_history[-1]
 
780
        if rev_history != self._lefthand_history(revid):
 
781
            raise errors.NotLefthandHistory(rev_history)
 
782
        self.set_last_revision_info(len(rev_history), revid)
 
783
        self._cache_revision_history(rev_history)
 
784
        for hook in Branch.hooks['set_rh']:
 
785
            hook(self, rev_history)
 
786
 
769
787
    @needs_write_lock
770
788
    def set_last_revision_info(self, revno, revision_id):
771
789
        """Set the last revision of this branch.
968
986
        This means the next call to revision_history will need to call
969
987
        _gen_revision_history.
970
988
 
971
 
        This API is semi-public; it is only for use by subclasses, all other
972
 
        code should consider it to be private.
 
989
        This API is semi-public; it only for use by subclasses, all other code
 
990
        should consider it to be private.
973
991
        """
974
992
        self._revision_history_cache = None
975
993
        self._revision_id_to_revno_cache = None
995
1013
        """
996
1014
        raise NotImplementedError(self._gen_revision_history)
997
1015
 
 
1016
    @deprecated_method(deprecated_in((2, 5, 0)))
 
1017
    @needs_read_lock
 
1018
    def revision_history(self):
 
1019
        """Return sequence of revision ids on this branch.
 
1020
 
 
1021
        This method will cache the revision history for as long as it is safe to
 
1022
        do so.
 
1023
        """
 
1024
        return self._revision_history()
 
1025
 
998
1026
    def _revision_history(self):
999
1027
        if 'evil' in debug.debug_flags:
1000
1028
            mutter_callsite(3, "revision_history scales with history.")
1034
1062
    def _read_last_revision_info(self):
1035
1063
        raise NotImplementedError(self._read_last_revision_info)
1036
1064
 
 
1065
    @deprecated_method(deprecated_in((2, 4, 0)))
 
1066
    def import_last_revision_info(self, source_repo, revno, revid):
 
1067
        """Set the last revision info, importing from another repo if necessary.
 
1068
 
 
1069
        :param source_repo: Source repository to optionally fetch from
 
1070
        :param revno: Revision number of the new tip
 
1071
        :param revid: Revision id of the new tip
 
1072
        """
 
1073
        if not self.repository.has_same_location(source_repo):
 
1074
            self.repository.fetch(source_repo, revision_id=revid)
 
1075
        self.set_last_revision_info(revno, revid)
 
1076
 
1037
1077
    def import_last_revision_info_and_tags(self, source, revno, revid,
1038
1078
                                           lossy=False):
1039
1079
        """Set the last revision info, importing from another repo if necessary.
1577
1617
    def __ne__(self, other):
1578
1618
        return not (self == other)
1579
1619
 
 
1620
    @classmethod
 
1621
    @deprecated_method(deprecated_in((2, 4, 0)))
 
1622
    def get_default_format(klass):
 
1623
        """Return the current default format."""
 
1624
        return format_registry.get_default()
 
1625
 
 
1626
    @classmethod
 
1627
    @deprecated_method(deprecated_in((2, 4, 0)))
 
1628
    def get_formats(klass):
 
1629
        """Get all the known formats.
 
1630
 
 
1631
        Warning: This triggers a load of all lazy registered formats: do not
 
1632
        use except when that is desireed.
 
1633
        """
 
1634
        return format_registry._get_all()
 
1635
 
1580
1636
    def get_reference(self, controldir, name=None):
1581
1637
        """Get the target reference of the branch in controldir.
1582
1638
 
1670
1726
        """
1671
1727
        raise NotImplementedError(self.open)
1672
1728
 
 
1729
    @classmethod
 
1730
    @deprecated_method(deprecated_in((2, 4, 0)))
 
1731
    def register_format(klass, format):
 
1732
        """Register a metadir format.
 
1733
 
 
1734
        See MetaDirBranchFormatFactory for the ability to register a format
 
1735
        without loading the code the format needs until it is actually used.
 
1736
        """
 
1737
        format_registry.register(format)
 
1738
 
 
1739
    @classmethod
 
1740
    @deprecated_method(deprecated_in((2, 4, 0)))
 
1741
    def set_default_format(klass, format):
 
1742
        format_registry.set_default(format)
 
1743
 
1673
1744
    def supports_set_append_revisions_only(self):
1674
1745
        """True if this format supports set_append_revisions_only."""
1675
1746
        return False
1682
1753
        """True if this format supports leaving locks in place."""
1683
1754
        return False # by default
1684
1755
 
 
1756
    @classmethod
 
1757
    @deprecated_method(deprecated_in((2, 4, 0)))
 
1758
    def unregister_format(klass, format):
 
1759
        format_registry.remove(format)
 
1760
 
1685
1761
    def __str__(self):
1686
1762
        return self.get_format_description().rstrip()
1687
1763
 
1729
1805
class BranchHooks(Hooks):
1730
1806
    """A dictionary mapping hook name to a list of callables for branch hooks.
1731
1807
 
1732
 
    e.g. ['post_push'] Is the list of items to be called when the
1733
 
    push function is invoked.
 
1808
    e.g. ['set_rh'] Is the list of items to be called when the
 
1809
    set_revision_history function is invoked.
1734
1810
    """
1735
1811
 
1736
1812
    def __init__(self):
1740
1816
        notified.
1741
1817
        """
1742
1818
        Hooks.__init__(self, "bzrlib.branch", "Branch.hooks")
 
1819
        self.add_hook('set_rh',
 
1820
            "Invoked whenever the revision history has been set via "
 
1821
            "set_revision_history. The api signature is (branch, "
 
1822
            "revision_history), and the branch will be write-locked. "
 
1823
            "The set_rh hook can be expensive for bzr to trigger, a better "
 
1824
            "hook to use is Branch.post_change_branch_tip.", (0, 15))
1743
1825
        self.add_hook('open',
1744
1826
            "Called with the Branch object that has been opened after a "
1745
1827
            "branch is opened.", (1, 8))
1963
2045
 
1964
2046
    def _initialize_helper(self, a_bzrdir, utf8_files, name=None,
1965
2047
                           repository=None):
1966
 
        """Initialize a branch in a control dir, with specified files
 
2048
        """Initialize a branch in a bzrdir, with specified files
1967
2049
 
1968
2050
        :param a_bzrdir: The bzrdir to initialize the branch in
1969
2051
        :param utf8_files: The files to create as a list of
2039
2121
            recommend_upgrade=recommend_upgrade, basedir=basedir)
2040
2122
 
2041
2123
 
 
2124
class BzrBranchFormat5(BranchFormatMetadir):
 
2125
    """Bzr branch format 5.
 
2126
 
 
2127
    This format has:
 
2128
     - a revision-history file.
 
2129
     - a format string
 
2130
     - a lock dir guarding the branch itself
 
2131
     - all of this stored in a branch/ subdirectory
 
2132
     - works with shared repositories.
 
2133
 
 
2134
    This format is new in bzr 0.8.
 
2135
    """
 
2136
 
 
2137
    def _branch_class(self):
 
2138
        return BzrBranch5
 
2139
 
 
2140
    @classmethod
 
2141
    def get_format_string(cls):
 
2142
        """See BranchFormat.get_format_string()."""
 
2143
        return "Bazaar-NG branch format 5\n"
 
2144
 
 
2145
    def get_format_description(self):
 
2146
        """See BranchFormat.get_format_description()."""
 
2147
        return "Branch format 5"
 
2148
 
 
2149
    def initialize(self, a_bzrdir, name=None, repository=None,
 
2150
                   append_revisions_only=None):
 
2151
        """Create a branch of this format in a_bzrdir."""
 
2152
        if append_revisions_only:
 
2153
            raise errors.UpgradeRequired(a_bzrdir.user_url)
 
2154
        utf8_files = [('revision-history', ''),
 
2155
                      ('branch-name', ''),
 
2156
                      ]
 
2157
        return self._initialize_helper(a_bzrdir, utf8_files, name, repository)
 
2158
 
 
2159
    def supports_tags(self):
 
2160
        return False
 
2161
 
 
2162
 
2042
2163
class BzrBranchFormat6(BranchFormatMetadir):
2043
2164
    """Branch format with last-revision and tags.
2044
2165
 
2293
2414
 
2294
2415
# formats which have no format string are not discoverable
2295
2416
# and not independently creatable, so are not registered.
 
2417
__format5 = BzrBranchFormat5()
2296
2418
__format6 = BzrBranchFormat6()
2297
2419
__format7 = BzrBranchFormat7()
2298
2420
__format8 = BzrBranchFormat8()
2299
 
format_registry.register_lazy(
2300
 
    "Bazaar-NG branch format 5\n", "bzrlib.branchfmt.fullhistory", "BzrBranchFormat5")
 
2421
format_registry.register(__format5)
2301
2422
format_registry.register(BranchReferenceFormat())
2302
2423
format_registry.register(__format6)
2303
2424
format_registry.register(__format7)
2398
2519
        """
2399
2520
        if not self.is_locked():
2400
2521
            self._note_lock('w')
 
2522
        # All-in-one needs to always unlock/lock.
 
2523
        repo_control = getattr(self.repository, 'control_files', None)
 
2524
        if self.control_files == repo_control or not self.is_locked():
2401
2525
            self.repository._warn_if_deprecated(self)
2402
2526
            self.repository.lock_write()
2403
2527
            took_lock = True
2418
2542
        """
2419
2543
        if not self.is_locked():
2420
2544
            self._note_lock('r')
 
2545
        # All-in-one needs to always unlock/lock.
 
2546
        repo_control = getattr(self.repository, 'control_files', None)
 
2547
        if self.control_files == repo_control or not self.is_locked():
2421
2548
            self.repository._warn_if_deprecated(self)
2422
2549
            self.repository.lock_read()
2423
2550
            took_lock = True
2433
2560
 
2434
2561
    @only_raises(errors.LockNotHeld, errors.LockBroken)
2435
2562
    def unlock(self):
2436
 
        if self.control_files._lock_count == 1 and self.conf_store is not None:
 
2563
        if self.conf_store is not None:
2437
2564
            self.conf_store.save_changes()
2438
2565
        try:
2439
2566
            self.control_files.unlock()
2440
2567
        finally:
 
2568
            # All-in-one needs to always unlock/lock.
 
2569
            repo_control = getattr(self.repository, 'control_files', None)
 
2570
            if (self.control_files == repo_control or
 
2571
                not self.control_files.is_locked()):
 
2572
                self.repository.unlock()
2441
2573
            if not self.control_files.is_locked():
2442
 
                self.repository.unlock()
2443
2574
                # we just released the lock
2444
2575
                self._clear_cached_state()
2445
2576
 
2623
2754
        self.control_transport.put_bytes('format', self._format.as_string())
2624
2755
 
2625
2756
 
 
2757
class FullHistoryBzrBranch(BzrBranch):
 
2758
    """Bzr branch which contains the full revision history."""
 
2759
 
 
2760
    @needs_write_lock
 
2761
    def set_last_revision_info(self, revno, revision_id):
 
2762
        if not revision_id or not isinstance(revision_id, basestring):
 
2763
            raise errors.InvalidRevisionId(revision_id=revision_id, branch=self)
 
2764
        revision_id = _mod_revision.ensure_null(revision_id)
 
2765
        # this old format stores the full history, but this api doesn't
 
2766
        # provide it, so we must generate, and might as well check it's
 
2767
        # correct
 
2768
        history = self._lefthand_history(revision_id)
 
2769
        if len(history) != revno:
 
2770
            raise AssertionError('%d != %d' % (len(history), revno))
 
2771
        self._set_revision_history(history)
 
2772
 
 
2773
    def _read_last_revision_info(self):
 
2774
        rh = self._revision_history()
 
2775
        revno = len(rh)
 
2776
        if revno:
 
2777
            return (revno, rh[-1])
 
2778
        else:
 
2779
            return (0, _mod_revision.NULL_REVISION)
 
2780
 
 
2781
    @deprecated_method(deprecated_in((2, 4, 0)))
 
2782
    @needs_write_lock
 
2783
    def set_revision_history(self, rev_history):
 
2784
        """See Branch.set_revision_history."""
 
2785
        self._set_revision_history(rev_history)
 
2786
 
 
2787
    def _set_revision_history(self, rev_history):
 
2788
        if 'evil' in debug.debug_flags:
 
2789
            mutter_callsite(3, "set_revision_history scales with history.")
 
2790
        check_not_reserved_id = _mod_revision.check_not_reserved_id
 
2791
        for rev_id in rev_history:
 
2792
            check_not_reserved_id(rev_id)
 
2793
        if Branch.hooks['post_change_branch_tip']:
 
2794
            # Don't calculate the last_revision_info() if there are no hooks
 
2795
            # that will use it.
 
2796
            old_revno, old_revid = self.last_revision_info()
 
2797
        if len(rev_history) == 0:
 
2798
            revid = _mod_revision.NULL_REVISION
 
2799
        else:
 
2800
            revid = rev_history[-1]
 
2801
        self._run_pre_change_branch_tip_hooks(len(rev_history), revid)
 
2802
        self._write_revision_history(rev_history)
 
2803
        self._clear_cached_state()
 
2804
        self._cache_revision_history(rev_history)
 
2805
        for hook in Branch.hooks['set_rh']:
 
2806
            hook(self, rev_history)
 
2807
        if Branch.hooks['post_change_branch_tip']:
 
2808
            self._run_post_change_branch_tip_hooks(old_revno, old_revid)
 
2809
 
 
2810
    def _write_revision_history(self, history):
 
2811
        """Factored out of set_revision_history.
 
2812
 
 
2813
        This performs the actual writing to disk.
 
2814
        It is intended to be called by set_revision_history."""
 
2815
        self._transport.put_bytes(
 
2816
            'revision-history', '\n'.join(history),
 
2817
            mode=self.bzrdir._get_file_mode())
 
2818
 
 
2819
    def _gen_revision_history(self):
 
2820
        history = self._transport.get_bytes('revision-history').split('\n')
 
2821
        if history[-1:] == ['']:
 
2822
            # There shouldn't be a trailing newline, but just in case.
 
2823
            history.pop()
 
2824
        return history
 
2825
 
 
2826
    def _synchronize_history(self, destination, revision_id):
 
2827
        if not isinstance(destination, FullHistoryBzrBranch):
 
2828
            super(BzrBranch, self)._synchronize_history(
 
2829
                destination, revision_id)
 
2830
            return
 
2831
        if revision_id == _mod_revision.NULL_REVISION:
 
2832
            new_history = []
 
2833
        else:
 
2834
            new_history = self._revision_history()
 
2835
        if revision_id is not None and new_history != []:
 
2836
            try:
 
2837
                new_history = new_history[:new_history.index(revision_id) + 1]
 
2838
            except ValueError:
 
2839
                rev = self.repository.get_revision(revision_id)
 
2840
                new_history = rev.get_history(self.repository)[1:]
 
2841
        destination._set_revision_history(new_history)
 
2842
 
 
2843
    @needs_write_lock
 
2844
    def generate_revision_history(self, revision_id, last_rev=None,
 
2845
        other_branch=None):
 
2846
        """Create a new revision history that will finish with revision_id.
 
2847
 
 
2848
        :param revision_id: the new tip to use.
 
2849
        :param last_rev: The previous last_revision. If not None, then this
 
2850
            must be a ancestory of revision_id, or DivergedBranches is raised.
 
2851
        :param other_branch: The other branch that DivergedBranches should
 
2852
            raise with respect to.
 
2853
        """
 
2854
        self._set_revision_history(self._lefthand_history(revision_id,
 
2855
            last_rev, other_branch))
 
2856
 
 
2857
 
 
2858
class BzrBranch5(FullHistoryBzrBranch):
 
2859
    """A format 5 branch. This supports new features over plain branches.
 
2860
 
 
2861
    It has support for a master_branch which is the data for bound branches.
 
2862
    """
 
2863
 
 
2864
 
2626
2865
class BzrBranch8(BzrBranch):
2627
2866
    """A branch that stores tree-reference locations."""
2628
2867
 
2908
3147
    :ivar tag_updates: A dict with new tags, see BasicTags.merge_to
2909
3148
    """
2910
3149
 
 
3150
    @deprecated_method(deprecated_in((2, 3, 0)))
 
3151
    def __int__(self):
 
3152
        """Return the relative change in revno.
 
3153
 
 
3154
        :deprecated: Use `new_revno` and `old_revno` instead.
 
3155
        """
 
3156
        return self.new_revno - self.old_revno
 
3157
 
2911
3158
    def report(self, to_file):
2912
3159
        tag_conflicts = getattr(self, "tag_conflicts", None)
2913
3160
        tag_updates = getattr(self, "tag_updates", None)
2943
3190
        target, otherwise it will be None.
2944
3191
    """
2945
3192
 
 
3193
    @deprecated_method(deprecated_in((2, 3, 0)))
 
3194
    def __int__(self):
 
3195
        """Return the relative change in revno.
 
3196
 
 
3197
        :deprecated: Use `new_revno` and `old_revno` instead.
 
3198
        """
 
3199
        return self.new_revno - self.old_revno
 
3200
 
2946
3201
    def report(self, to_file):
2947
3202
        # TODO: This function gets passed a to_file, but then
2948
3203
        # ignores it and calls note() instead. This is also
3104
3359
        raise NotImplementedError(self.fetch)
3105
3360
 
3106
3361
 
3107
 
def _fix_overwrite_type(overwrite):
3108
 
    if isinstance(overwrite, bool):
3109
 
        if overwrite:
3110
 
            return ["history", "tags"]
3111
 
        else:
3112
 
            return []
3113
 
    return overwrite
3114
 
 
3115
 
 
3116
3362
class GenericInterBranch(InterBranch):
3117
3363
    """InterBranch implementation that uses public Branch functions."""
3118
3364
 
3283
3529
        result.target_branch = self.target
3284
3530
        result.old_revno, result.old_revid = self.target.last_revision_info()
3285
3531
        self.source.update_references(self.target)
3286
 
        overwrite = _fix_overwrite_type(overwrite)
3287
3532
        if result.old_revid != stop_revision:
3288
3533
            # We assume that during 'push' this repository is closer than
3289
3534
            # the target.
3290
3535
            graph = self.source.repository.get_graph(self.target.repository)
3291
 
            self._update_revisions(stop_revision,
3292
 
                overwrite=("history" in overwrite),
3293
 
                graph=graph)
 
3536
            self._update_revisions(stop_revision, overwrite=overwrite,
 
3537
                    graph=graph)
3294
3538
        if self.source._push_should_merge_tags():
3295
3539
            result.tag_updates, result.tag_conflicts = (
3296
 
                self.source.tags.merge_to(
3297
 
                self.target.tags, "tags" in overwrite))
 
3540
                self.source.tags.merge_to(self.target.tags, overwrite))
3298
3541
        result.new_revno, result.new_revid = self.target.last_revision_info()
3299
3542
        return result
3300
3543
 
3378
3621
            # -- JRV20090506
3379
3622
            result.old_revno, result.old_revid = \
3380
3623
                self.target.last_revision_info()
3381
 
            overwrite = _fix_overwrite_type(overwrite)
3382
 
            self._update_revisions(stop_revision,
3383
 
                overwrite=("history" in overwrite),
 
3624
            self._update_revisions(stop_revision, overwrite=overwrite,
3384
3625
                graph=graph)
3385
3626
            # TODO: The old revid should be specified when merging tags, 
3386
3627
            # so a tags implementation that versions tags can only 
3387
3628
            # pull in the most recent changes. -- JRV20090506
3388
3629
            result.tag_updates, result.tag_conflicts = (
3389
 
                self.source.tags.merge_to(self.target.tags,
3390
 
                    "tags" in overwrite,
 
3630
                self.source.tags.merge_to(self.target.tags, overwrite,
3391
3631
                    ignore_master=not merge_tags_to_master))
3392
3632
            result.new_revno, result.new_revid = self.target.last_revision_info()
3393
3633
            if _hook_master: