~bzr-pqm/bzr/bzr.dev

« back to all changes in this revision

Viewing changes to bzrlib/branch.py

  • Committer: Benoît Pierre
  • Date: 2011-10-10 20:55:52 UTC
  • mto: This revision was merged to the branch mainline in revision 6215.
  • Revision ID: benoit.pierre@gmail.com-20111010205552-7o6qoaiihy31hhxb
Avoid prompt duplication for shelf_ui tests.

Show diffs side-by-side

added added

removed removed

Lines of Context:
16
16
 
17
17
 
18
18
from cStringIO import StringIO
19
 
import sys
20
19
 
21
20
from bzrlib.lazy_import import lazy_import
22
21
lazy_import(globals(), """
23
 
from itertools import chain
 
22
import itertools
24
23
from bzrlib import (
25
24
        bzrdir,
26
25
        cache_utf8,
36
35
        repository,
37
36
        revision as _mod_revision,
38
37
        rio,
 
38
        tag as _mod_tag,
39
39
        transport,
40
40
        ui,
41
41
        urlutils,
42
42
        )
43
 
from bzrlib.config import BranchConfig, TransportConfig
44
 
from bzrlib.tag import (
45
 
    BasicTags,
46
 
    DisabledTags,
47
 
    )
 
43
from bzrlib.i18n import gettext, ngettext
48
44
""")
49
45
 
50
46
from bzrlib import (
66
62
from bzrlib.trace import mutter, mutter_callsite, note, is_quiet
67
63
 
68
64
 
69
 
BZR_BRANCH_FORMAT_4 = "Bazaar-NG branch, format 0.0.4\n"
70
 
BZR_BRANCH_FORMAT_5 = "Bazaar-NG branch, format 5\n"
71
 
BZR_BRANCH_FORMAT_6 = "Bazaar Branch Format 6 (bzr 0.15)\n"
72
 
 
73
 
 
74
65
class Branch(controldir.ControlComponent):
75
66
    """Branch holding a history of revisions.
76
67
 
222
213
 
223
214
        :return: A bzrlib.config.BranchConfig.
224
215
        """
225
 
        return BranchConfig(self)
 
216
        return _mod_config.BranchConfig(self)
 
217
 
 
218
    def get_config_stack(self):
 
219
        """Get a bzrlib.config.BranchStack for this Branch.
 
220
 
 
221
        This can then be used to get and set configuration options for the
 
222
        branch.
 
223
 
 
224
        :return: A bzrlib.config.BranchStack.
 
225
        """
 
226
        return _mod_config.BranchStack(self)
226
227
 
227
228
    def _get_config(self):
228
229
        """Get the concrete config for just the config in this branch.
520
521
                    # The decision to include the start or not
521
522
                    # depends on the stop_rule if a stop is provided
522
523
                    # so pop this node back into the iterator
523
 
                    rev_iter = chain(iter([node]), rev_iter)
 
524
                    rev_iter = itertools.chain(iter([node]), rev_iter)
524
525
                    break
525
526
        if stop_revision_id is None:
526
527
            # Yield everything
651
652
        """
652
653
        raise errors.UpgradeRequired(self.user_url)
653
654
 
 
655
    def get_append_revisions_only(self):
 
656
        """Whether it is only possible to append revisions to the history.
 
657
        """
 
658
        if not self._format.supports_set_append_revisions_only():
 
659
            return False
 
660
        return self.get_config(
 
661
            ).get_user_option_as_bool('append_revisions_only')
 
662
 
654
663
    def set_append_revisions_only(self, enabled):
655
664
        if not self._format.supports_set_append_revisions_only():
656
665
            raise errors.UpgradeRequired(self.user_url)
724
733
        """
725
734
        return None
726
735
 
 
736
    @deprecated_method(deprecated_in((2, 5, 0)))
727
737
    def get_revision_delta(self, revno):
728
738
        """Return the delta for one revision.
729
739
 
730
740
        The delta is relative to its mainline predecessor, or the
731
741
        empty tree for revision 1.
732
742
        """
733
 
        rh = self.revision_history()
734
 
        if not (1 <= revno <= len(rh)):
 
743
        try:
 
744
            revid = self.get_rev_id(revno)
 
745
        except errors.NoSuchRevision:
735
746
            raise errors.InvalidRevisionNumber(revno)
736
 
        return self.repository.get_revision_delta(rh[revno-1])
 
747
        return self.repository.get_revision_delta(revid)
737
748
 
738
749
    def get_stacked_on_url(self):
739
750
        """Get the URL this branch is stacked against.
785
796
                                  other_branch=None):
786
797
        """See Branch.generate_revision_history"""
787
798
        graph = self.repository.get_graph()
 
799
        (last_revno, last_revid) = self.last_revision_info()
788
800
        known_revision_ids = [
789
 
            self.last_revision_info(),
 
801
            (last_revid, last_revno),
790
802
            (_mod_revision.NULL_REVISION, 0),
791
803
            ]
792
804
        if last_rev is not None:
849
861
        """
850
862
        pb = ui.ui_factory.nested_progress_bar()
851
863
        try:
852
 
            pb.update("Unstacking")
 
864
            pb.update(gettext("Unstacking"))
853
865
            # The basic approach here is to fetch the tip of the branch,
854
866
            # including all available ghosts, from the existing stacked
855
867
            # repository into a new repository object without the fallbacks. 
1293
1305
            if repository_policy is not None:
1294
1306
                repository_policy.configure_branch(result)
1295
1307
            self.copy_content_into(result, revision_id=revision_id)
1296
 
            master_branch = self.get_master_branch()
1297
 
            if master_branch is None:
 
1308
            master_url = self.get_bound_location()
 
1309
            if master_url is None:
1298
1310
                result.set_parent(self.bzrdir.root_transport.base)
1299
1311
            else:
1300
 
                result.set_parent(master_branch.bzrdir.root_transport.base)
 
1312
                result.set_parent(master_url)
1301
1313
        finally:
1302
1314
            result.unlock()
1303
1315
        return result
1381
1393
        # specific check.
1382
1394
        return result
1383
1395
 
1384
 
    def _get_checkout_format(self):
 
1396
    def _get_checkout_format(self, lightweight=False):
1385
1397
        """Return the most suitable metadir for a checkout of this branch.
1386
1398
        Weaves are used if this branch's repository uses weaves.
1387
1399
        """
1433
1445
        """
1434
1446
        t = transport.get_transport(to_location)
1435
1447
        t.ensure_base()
 
1448
        format = self._get_checkout_format(lightweight=lightweight)
1436
1449
        if lightweight:
1437
 
            format = self._get_checkout_format()
1438
1450
            checkout = format.initialize_on_transport(t)
1439
1451
            from_branch = BranchReferenceFormat().initialize(checkout, 
1440
1452
                target_branch=self)
1441
1453
        else:
1442
 
            format = self._get_checkout_format()
1443
1454
            checkout_branch = bzrdir.BzrDir.create_branch_convenience(
1444
1455
                to_location, force_new_tree=False, format=format)
1445
1456
            checkout = checkout_branch.bzrdir
1545
1556
        # For bzr native formats must_fetch is just the tip, and if_present_fetch
1546
1557
        # are the tags.
1547
1558
        must_fetch = set([self.last_revision()])
1548
 
        try:
1549
 
            if_present_fetch = set(self.tags.get_reverse_tag_dict())
1550
 
        except errors.TagsNotSupported:
1551
 
            if_present_fetch = set()
 
1559
        if_present_fetch = set()
 
1560
        c = self.get_config()
 
1561
        include_tags = c.get_user_option_as_bool('branch.fetch_tags',
 
1562
                                                 default=False)
 
1563
        if include_tags:
 
1564
            try:
 
1565
                if_present_fetch = set(self.tags.get_reverse_tag_dict())
 
1566
            except errors.TagsNotSupported:
 
1567
                pass
1552
1568
        must_fetch.discard(_mod_revision.NULL_REVISION)
1553
1569
        if_present_fetch.discard(_mod_revision.NULL_REVISION)
1554
1570
        return must_fetch, if_present_fetch
1572
1588
    object will be created every time regardless.
1573
1589
    """
1574
1590
 
1575
 
    can_set_append_revisions_only = True
1576
 
 
1577
1591
    def __eq__(self, other):
1578
1592
        return self.__class__ is other.__class__
1579
1593
 
1651
1665
        for hook in hooks:
1652
1666
            hook(params)
1653
1667
 
1654
 
    def initialize(self, a_bzrdir, name=None, repository=None):
 
1668
    def initialize(self, a_bzrdir, name=None, repository=None,
 
1669
                   append_revisions_only=None):
1655
1670
        """Create a branch of this format in a_bzrdir.
1656
1671
        
1657
1672
        :param name: Name of the colocated branch to create.
1679
1694
        Note that it is normal for branch to be a RemoteBranch when using tags
1680
1695
        on a RemoteBranch.
1681
1696
        """
1682
 
        return DisabledTags(branch)
 
1697
        return _mod_tag.DisabledTags(branch)
1683
1698
 
1684
1699
    def network_name(self):
1685
1700
        """A simple byte string uniquely identifying this format for RPC calls.
1743
1758
        """True if this format supports tags stored in the branch"""
1744
1759
        return False  # by default
1745
1760
 
 
1761
    def tags_are_versioned(self):
 
1762
        """Whether the tag container for this branch versions tags."""
 
1763
        return False
 
1764
 
 
1765
    def supports_tags_referencing_ghosts(self):
 
1766
        """True if tags can reference ghost revisions."""
 
1767
        return True
 
1768
 
1746
1769
 
1747
1770
class MetaDirBranchFormatFactory(registry._LazyObjectGetter):
1748
1771
    """A factory for a BranchFormat object, permitting simple lazy registration.
1987
2010
        """What class to instantiate on open calls."""
1988
2011
        raise NotImplementedError(self._branch_class)
1989
2012
 
 
2013
    def _get_initial_config(self, append_revisions_only=None):
 
2014
        if append_revisions_only:
 
2015
            return "append_revisions_only = True\n"
 
2016
        else:
 
2017
            # Avoid writing anything if append_revisions_only is disabled,
 
2018
            # as that is the default.
 
2019
            return ""
 
2020
 
1990
2021
    def _initialize_helper(self, a_bzrdir, utf8_files, name=None,
1991
2022
                           repository=None):
1992
2023
        """Initialize a branch in a bzrdir, with specified files
2082
2113
        """See BranchFormat.get_format_description()."""
2083
2114
        return "Branch format 5"
2084
2115
 
2085
 
    def initialize(self, a_bzrdir, name=None, repository=None):
 
2116
    def initialize(self, a_bzrdir, name=None, repository=None,
 
2117
                   append_revisions_only=None):
2086
2118
        """Create a branch of this format in a_bzrdir."""
 
2119
        if append_revisions_only:
 
2120
            raise errors.UpgradeRequired(a_bzrdir.user_url)
2087
2121
        utf8_files = [('revision-history', ''),
2088
2122
                      ('branch-name', ''),
2089
2123
                      ]
2115
2149
        """See BranchFormat.get_format_description()."""
2116
2150
        return "Branch format 6"
2117
2151
 
2118
 
    def initialize(self, a_bzrdir, name=None, repository=None):
 
2152
    def initialize(self, a_bzrdir, name=None, repository=None,
 
2153
                   append_revisions_only=None):
2119
2154
        """Create a branch of this format in a_bzrdir."""
2120
2155
        utf8_files = [('last-revision', '0 null:\n'),
2121
 
                      ('branch.conf', ''),
 
2156
                      ('branch.conf',
 
2157
                          self._get_initial_config(append_revisions_only)),
2122
2158
                      ('tags', ''),
2123
2159
                      ]
2124
2160
        return self._initialize_helper(a_bzrdir, utf8_files, name, repository)
2125
2161
 
2126
2162
    def make_tags(self, branch):
2127
2163
        """See bzrlib.branch.BranchFormat.make_tags()."""
2128
 
        return BasicTags(branch)
 
2164
        return _mod_tag.BasicTags(branch)
2129
2165
 
2130
2166
    def supports_set_append_revisions_only(self):
2131
2167
        return True
2145
2181
        """See BranchFormat.get_format_description()."""
2146
2182
        return "Branch format 8"
2147
2183
 
2148
 
    def initialize(self, a_bzrdir, name=None, repository=None):
 
2184
    def initialize(self, a_bzrdir, name=None, repository=None,
 
2185
                   append_revisions_only=None):
2149
2186
        """Create a branch of this format in a_bzrdir."""
2150
2187
        utf8_files = [('last-revision', '0 null:\n'),
2151
 
                      ('branch.conf', ''),
 
2188
                      ('branch.conf',
 
2189
                          self._get_initial_config(append_revisions_only)),
2152
2190
                      ('tags', ''),
2153
2191
                      ('references', '')
2154
2192
                      ]
2156
2194
 
2157
2195
    def make_tags(self, branch):
2158
2196
        """See bzrlib.branch.BranchFormat.make_tags()."""
2159
 
        return BasicTags(branch)
 
2197
        return _mod_tag.BasicTags(branch)
2160
2198
 
2161
2199
    def supports_set_append_revisions_only(self):
2162
2200
        return True
2176
2214
    This format was introduced in bzr 1.6.
2177
2215
    """
2178
2216
 
2179
 
    def initialize(self, a_bzrdir, name=None, repository=None):
 
2217
    def initialize(self, a_bzrdir, name=None, repository=None,
 
2218
                   append_revisions_only=None):
2180
2219
        """Create a branch of this format in a_bzrdir."""
2181
2220
        utf8_files = [('last-revision', '0 null:\n'),
2182
 
                      ('branch.conf', ''),
 
2221
                      ('branch.conf',
 
2222
                          self._get_initial_config(append_revisions_only)),
2183
2223
                      ('tags', ''),
2184
2224
                      ]
2185
2225
        return self._initialize_helper(a_bzrdir, utf8_files, name, repository)
2203
2243
 
2204
2244
    def make_tags(self, branch):
2205
2245
        """See bzrlib.branch.BranchFormat.make_tags()."""
2206
 
        return BasicTags(branch)
 
2246
        return _mod_tag.BasicTags(branch)
2207
2247
 
2208
2248
    supports_reference_locations = False
2209
2249
 
2238
2278
        location = transport.put_bytes('location', to_branch.base)
2239
2279
 
2240
2280
    def initialize(self, a_bzrdir, name=None, target_branch=None,
2241
 
            repository=None):
 
2281
            repository=None, append_revisions_only=None):
2242
2282
        """Create a branch of this format in a_bzrdir."""
2243
2283
        if target_branch is None:
2244
2284
            # this format does not implement branch itself, thus the implicit
2245
2285
            # creation contract must see it as uninitializable
2246
2286
            raise errors.UninitializableFormat(self)
2247
2287
        mutter('creating branch reference in %s', a_bzrdir.user_url)
 
2288
        if a_bzrdir._format.fixed_components:
 
2289
            raise errors.IncompatibleFormat(self, a_bzrdir._format)
2248
2290
        branch_transport = a_bzrdir.get_branch_transport(self, name=name)
2249
2291
        branch_transport.put_bytes('location',
2250
2292
            target_branch.bzrdir.user_url)
2419
2461
    base = property(_get_base, doc="The URL for the root of this branch.")
2420
2462
 
2421
2463
    def _get_config(self):
2422
 
        return TransportConfig(self._transport, 'branch.conf')
 
2464
        return _mod_config.TransportConfig(self._transport, 'branch.conf')
2423
2465
 
2424
2466
    def is_locked(self):
2425
2467
        return self.control_files.is_locked()
2506
2548
            raise errors.InvalidRevisionId(revision_id=revision_id, branch=self)
2507
2549
        revision_id = _mod_revision.ensure_null(revision_id)
2508
2550
        old_revno, old_revid = self.last_revision_info()
2509
 
        if self._get_append_revisions_only():
 
2551
        if self.get_append_revisions_only():
2510
2552
            self._check_history_violation(revision_id)
2511
2553
        self._run_pre_change_branch_tip_hooks(revno, revision_id)
2512
2554
        self._write_last_revision_info(revno, revision_id)
2951
2993
            raise errors.NotStacked(self)
2952
2994
        return stacked_url
2953
2995
 
2954
 
    def _get_append_revisions_only(self):
2955
 
        return self.get_config(
2956
 
            ).get_user_option_as_bool('append_revisions_only')
2957
 
 
2958
2996
    @needs_read_lock
2959
2997
    def get_rev_id(self, revno, history=None):
2960
2998
        """Find the revision id of the specified revno."""
3046
3084
    :ivar local_branch: target branch if there is a Master, else None
3047
3085
    :ivar target_branch: Target/destination branch object. (write locked)
3048
3086
    :ivar tag_conflicts: A list of tag conflicts, see BasicTags.merge_to
 
3087
    :ivar tag_updates: A dict with new tags, see BasicTags.merge_to
3049
3088
    """
3050
3089
 
3051
3090
    @deprecated_method(deprecated_in((2, 3, 0)))
3057
3096
        return self.new_revno - self.old_revno
3058
3097
 
3059
3098
    def report(self, to_file):
 
3099
        tag_conflicts = getattr(self, "tag_conflicts", None)
 
3100
        tag_updates = getattr(self, "tag_updates", None)
3060
3101
        if not is_quiet():
3061
 
            if self.old_revid == self.new_revid:
3062
 
                to_file.write('No revisions to pull.\n')
3063
 
            else:
 
3102
            if self.old_revid != self.new_revid:
3064
3103
                to_file.write('Now on revision %d.\n' % self.new_revno)
 
3104
            if tag_updates:
 
3105
                to_file.write('%d tag(s) updated.\n' % len(tag_updates))
 
3106
            if self.old_revid == self.new_revid and not tag_updates:
 
3107
                if not tag_conflicts:
 
3108
                    to_file.write('No revisions or tags to pull.\n')
 
3109
                else:
 
3110
                    to_file.write('No revisions to pull.\n')
3065
3111
        self._show_tag_conficts(to_file)
3066
3112
 
3067
3113
 
3093
3139
        return self.new_revno - self.old_revno
3094
3140
 
3095
3141
    def report(self, to_file):
3096
 
        """Write a human-readable description of the result."""
3097
 
        if self.old_revid == self.new_revid:
3098
 
            note('No new revisions to push.')
3099
 
        else:
3100
 
            note('Pushed up to revision %d.' % self.new_revno)
 
3142
        # TODO: This function gets passed a to_file, but then
 
3143
        # ignores it and calls note() instead. This is also
 
3144
        # inconsistent with PullResult(), which writes to stdout.
 
3145
        # -- JRV20110901, bug #838853
 
3146
        tag_conflicts = getattr(self, "tag_conflicts", None)
 
3147
        tag_updates = getattr(self, "tag_updates", None)
 
3148
        if not is_quiet():
 
3149
            if self.old_revid != self.new_revid:
 
3150
                note(gettext('Pushed up to revision %d.') % self.new_revno)
 
3151
            if tag_updates:
 
3152
                note(ngettext('%d tag updated.', '%d tags updated.', len(tag_updates)) % len(tag_updates))
 
3153
            if self.old_revid == self.new_revid and not tag_updates:
 
3154
                if not tag_conflicts:
 
3155
                    note(gettext('No new revisions or tags to push.'))
 
3156
                else:
 
3157
                    note(gettext('No new revisions to push.'))
3101
3158
        self._show_tag_conficts(to_file)
3102
3159
 
3103
3160
 
3117
3174
        :param verbose: Requests more detailed display of what was checked,
3118
3175
            if any.
3119
3176
        """
3120
 
        note('checked branch %s format %s', self.branch.user_url,
3121
 
            self.branch._format)
 
3177
        note(gettext('checked branch {0} format {1}').format(
 
3178
                                self.branch.user_url, self.branch._format))
3122
3179
        for error in self.errors:
3123
 
            note('found error:%s', error)
 
3180
            note(gettext('found error:%s'), error)
3124
3181
 
3125
3182
 
3126
3183
class Converter5to6(object):
3165
3222
 
3166
3223
 
3167
3224
class Converter7to8(object):
3168
 
    """Perform an in-place upgrade of format 6 to format 7"""
 
3225
    """Perform an in-place upgrade of format 7 to format 8"""
3169
3226
 
3170
3227
    def convert(self, branch):
3171
3228
        format = BzrBranchFormat8()
3344
3401
        if local and not bound_location:
3345
3402
            raise errors.LocalRequiresBoundBranch()
3346
3403
        master_branch = None
3347
 
        source_is_master = (self.source.user_url == bound_location)
 
3404
        source_is_master = False
 
3405
        if bound_location:
 
3406
            # bound_location comes from a config file, some care has to be
 
3407
            # taken to relate it to source.user_url
 
3408
            normalized = urlutils.normalize_url(bound_location)
 
3409
            try:
 
3410
                relpath = self.source.user_transport.relpath(normalized)
 
3411
                source_is_master = (relpath == '')
 
3412
            except (errors.PathNotChild, errors.InvalidURL):
 
3413
                source_is_master = False
3348
3414
        if not local and bound_location and not source_is_master:
3349
3415
            # not pulling from master, so we need to update master.
3350
3416
            master_branch = self.target.get_master_branch(possible_transports)
3402
3468
            self._update_revisions(stop_revision, overwrite=overwrite,
3403
3469
                    graph=graph)
3404
3470
        if self.source._push_should_merge_tags():
3405
 
            result.tag_conflicts = self.source.tags.merge_to(self.target.tags,
3406
 
                overwrite)
 
3471
            result.tag_updates, result.tag_conflicts = (
 
3472
                self.source.tags.merge_to(self.target.tags, overwrite))
3407
3473
        result.new_revno, result.new_revid = self.target.last_revision_info()
3408
3474
        return result
3409
3475
 
3492
3558
            # TODO: The old revid should be specified when merging tags, 
3493
3559
            # so a tags implementation that versions tags can only 
3494
3560
            # pull in the most recent changes. -- JRV20090506
3495
 
            result.tag_conflicts = self.source.tags.merge_to(self.target.tags,
3496
 
                overwrite, ignore_master=not merge_tags_to_master)
 
3561
            result.tag_updates, result.tag_conflicts = (
 
3562
                self.source.tags.merge_to(self.target.tags, overwrite,
 
3563
                    ignore_master=not merge_tags_to_master))
3497
3564
            result.new_revno, result.new_revid = self.target.last_revision_info()
3498
3565
            if _hook_master:
3499
3566
                result.master_branch = _hook_master