/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 from bzr.dev, resolving the worst of the semantic conflicts, but there's
still a little bit of breakage.

Show diffs side-by-side

added added

removed removed

Lines of Context:
40
40
        )
41
41
from bzrlib.config import BranchConfig, TreeConfig
42
42
from bzrlib.lockable_files import LockableFiles, TransportLock
 
43
from bzrlib.tag import (
 
44
    BasicTags,
 
45
    DisabledTags,
 
46
    )
43
47
""")
44
48
 
45
49
from bzrlib.decorators import needs_read_lock, needs_write_lock
61
65
 
62
66
BZR_BRANCH_FORMAT_4 = "Bazaar-NG branch, format 0.0.4\n"
63
67
BZR_BRANCH_FORMAT_5 = "Bazaar-NG branch, format 5\n"
64
 
BZR_BRANCH_FORMAT_6 = "Bazaar-NG branch, format 6\n"
 
68
BZR_BRANCH_FORMAT_6 = "Bazaar Branch Format 6 (bzr 0.15)\n"
65
69
 
66
70
 
67
71
# TODO: Maybe include checks for common corruption of newlines, etc?
88
92
    # - RBC 20060112
89
93
    base = None
90
94
 
 
95
    # override this to set the strategy for storing tags
 
96
    def _make_tags(self):
 
97
        return DisabledTags(self)
 
98
 
91
99
    def __init__(self, *ignored, **ignored_too):
92
 
        raise NotImplementedError('The Branch class is abstract')
 
100
        self.tags = self._make_tags()
93
101
 
94
102
    def break_lock(self):
95
103
        """Break a lock if one is present from another instance.
415
423
        """Mirror source into this branch.
416
424
 
417
425
        This branch is considered to be 'local', having low latency.
 
426
 
 
427
        :returns: PullResult instance
418
428
        """
419
429
        raise NotImplementedError(self.pull)
420
430
 
461
471
        """
462
472
        raise NotImplementedError(self.get_parent)
463
473
 
 
474
    def _set_config_location(self, name, url, config=None,
 
475
                             make_relative=False):
 
476
        if config is None:
 
477
            config = self.get_config()
 
478
        if url is None:
 
479
            url = ''
 
480
        elif make_relative:
 
481
            url = urlutils.relative_url(self.base, url)
 
482
        config.set_user_option(name, url)
 
483
 
 
484
    def _get_config_location(self, name, config=None):
 
485
        if config is None:
 
486
            config = self.get_config()
 
487
        location = config.get_user_option(name)
 
488
        if location == '':
 
489
            location = None
 
490
        return location
 
491
 
464
492
    def get_submit_branch(self):
465
493
        """Return the submit location of the branch.
466
494
 
479
507
        """
480
508
        self.get_config().set_user_option('submit_branch', location)
481
509
 
 
510
    def get_public_branch(self):
 
511
        """Return the public location of the branch.
 
512
 
 
513
        This is is used by merge directives.
 
514
        """
 
515
        return self._get_config_location('public_branch')
 
516
 
 
517
    def set_public_branch(self, location):
 
518
        """Return the submit location of the branch.
 
519
 
 
520
        This is the default location for bundle.  The usual
 
521
        pattern is that the user can override it by specifying a
 
522
        location.
 
523
        """
 
524
        self._set_config_location('public_branch', location)
 
525
 
482
526
    def get_push_location(self):
483
527
        """Return the None or the location to push this branch to."""
484
528
        push_loc = self.get_config().get_user_option('push_location')
664
708
        elif isinstance(self.bzrdir, RemoteBzrDir):
665
709
            format = bzrdir.BzrDirMetaFormat1()
666
710
        else:
667
 
            format = self.repository.bzrdir.cloning_metadir()
 
711
            format = self.repository.bzrdir.checkout_metadir()
668
712
            format.branch_format = self._format
669
713
        return format
670
714
 
684
728
        except errors.FileExists:
685
729
            pass
686
730
        if lightweight:
687
 
            checkout = bzrdir.BzrDirMetaFormat1().initialize_on_transport(t)
 
731
            format = self._get_checkout_format()
 
732
            checkout = format.initialize_on_transport(t)
688
733
            BranchReferenceFormat().initialize(checkout, self)
689
734
        else:
690
735
            format = self._get_checkout_format()
695
740
            # pull up to the specified revision_id to set the initial 
696
741
            # branch tip correctly, and seed it with history.
697
742
            checkout_branch.pull(self, stop_revision=revision_id)
698
 
        return checkout.create_workingtree(revision_id)
 
743
        tree = checkout.create_workingtree(revision_id)
 
744
        basis_tree = tree.basis_tree()
 
745
        basis_tree.lock_read()
 
746
        try:
 
747
            for path, file_id in basis_tree.iter_references():
 
748
                reference_parent = self.reference_parent(file_id, path)
 
749
                reference_parent.create_checkout(tree.abspath(path),
 
750
                    basis_tree.get_reference_revision(file_id, path),
 
751
                    lightweight)
 
752
        finally:
 
753
            basis_tree.unlock()
 
754
        return tree
 
755
 
 
756
    def reference_parent(self, file_id, path):
 
757
        """Return the parent branch for a tree-reference file_id
 
758
        :param file_id: The file_id of the tree reference
 
759
        :param path: The path of the file_id in the tree
 
760
        :return: A branch associated with the file_id
 
761
        """
 
762
        # FIXME should provide multiple branches, based on config
 
763
        return Branch.open(self.bzrdir.root_transport.clone(path).base)
 
764
 
 
765
    def supports_tags(self):
 
766
        return self._format.supports_tags()
699
767
 
700
768
 
701
769
class BranchFormat(object):
828
896
    def __str__(self):
829
897
        return self.get_format_string().rstrip()
830
898
 
 
899
    def supports_tags(self):
 
900
        """True if this format supports tags stored in the branch"""
 
901
        return False  # by default
 
902
 
 
903
    # XXX: Probably doesn't really belong here -- mbp 20070212
 
904
    def _initialize_control_files(self, a_bzrdir, utf8_files, lock_filename,
 
905
            lock_class):
 
906
        branch_transport = a_bzrdir.get_branch_transport(self)
 
907
        control_files = lockable_files.LockableFiles(branch_transport,
 
908
            lock_filename, lock_class)
 
909
        control_files.create_lock()
 
910
        control_files.lock_write()
 
911
        try:
 
912
            for filename, content in utf8_files:
 
913
                control_files.put_utf8(filename, content)
 
914
        finally:
 
915
            control_files.unlock()
 
916
 
831
917
 
832
918
class BranchHooks(dict):
833
919
    """A dictionary mapping hook name to a list of callables for branch hooks.
851
937
        self['set_rh'] = []
852
938
        # invoked after a push operation completes.
853
939
        # the api signature is
 
940
        # (push_result)
 
941
        # containing the members
854
942
        # (source, local, master, old_revno, old_revid, new_revno, new_revid)
855
943
        # where local is the local branch or None, master is the target 
856
944
        # master branch, and the rest should be self explanatory. The source
859
947
        self['post_push'] = []
860
948
        # invoked after a pull operation completes.
861
949
        # the api signature is
 
950
        # (pull_result)
 
951
        # containing the members
862
952
        # (source, local, master, old_revno, old_revid, new_revno, new_revid)
863
953
        # where local is the local branch or None, master is the target 
864
954
        # master branch, and the rest should be self explanatory. The source
990
1080
        except NoSuchFile:
991
1081
            raise NotBranchError(path=transport.base)
992
1082
 
993
 
    def __str__(self):
994
 
        return "Bazaar-NG Metadir branch format 5"
995
 
 
996
1083
 
997
1084
class BzrBranchFormat6(BzrBranchFormat5):
998
1085
    """Branch format with last-revision
1006
1093
 
1007
1094
    def get_format_string(self):
1008
1095
        """See BranchFormat.get_format_string()."""
1009
 
        return "Bazaar-NG branch format 6\n"
 
1096
        return "Bazaar Branch Format 6 (bzr 0.15)\n"
1010
1097
 
1011
1098
    def get_format_description(self):
1012
1099
        """See BranchFormat.get_format_description()."""
1016
1103
        """Create a branch of this format in a_bzrdir."""
1017
1104
        utf8_files = [('last-revision', '0 null:\n'),
1018
1105
                      ('branch-name', ''),
1019
 
                      ('branch.conf', '')
 
1106
                      ('branch.conf', ''),
 
1107
                      ('tags', ''),
1020
1108
                      ]
1021
1109
        return self._initialize_helper(a_bzrdir, utf8_files)
1022
1110
 
1037
1125
                          a_bzrdir=a_bzrdir,
1038
1126
                          _repository=a_bzrdir.find_repository())
1039
1127
 
 
1128
    def supports_tags(self):
 
1129
        return True
 
1130
 
1040
1131
 
1041
1132
class BranchReferenceFormat(BranchFormat):
1042
1133
    """Bzr branch reference format.
1148
1239
            upgrade/recovery type use; it's not guaranteed that
1149
1240
            all operations will work on old format branches.
1150
1241
        """
 
1242
        Branch.__init__(self)
1151
1243
        if a_bzrdir is None:
1152
1244
            self.bzrdir = bzrdir.BzrDir.open(transport.base)
1153
1245
        else:
1154
1246
            self.bzrdir = a_bzrdir
1155
 
        self._transport = self.bzrdir.transport.clone('..')
1156
 
        self._base = self._transport.base
 
1247
        # self._transport used to point to the directory containing the
 
1248
        # control directory, but was not used - now it's just the transport
 
1249
        # for the branch control files.  mbp 20070212
 
1250
        self._base = self.bzrdir.transport.clone('..').base
1157
1251
        self._format = _format
1158
1252
        if _control_files is None:
1159
1253
            raise ValueError('BzrBranch _control_files is None')
1160
1254
        self.control_files = _control_files
 
1255
        self._transport = _control_files._transport
1161
1256
        if deprecated_passed(init):
1162
1257
            warn("BzrBranch.__init__(..., init=XXX): The init parameter is "
1163
1258
                 "deprecated as of bzr 0.8. Please use Branch.create().",
1192
1287
    __repr__ = __str__
1193
1288
 
1194
1289
    def _get_base(self):
 
1290
        """Returns the directory containing the control directory."""
1195
1291
        return self._base
1196
1292
 
1197
1293
    base = property(_get_base, doc="The URL for the root of this branch.")
1346
1442
        self.set_revision_history(history)
1347
1443
 
1348
1444
    def _gen_revision_history(self):
1349
 
        get_cached_utf8 = cache_utf8.get_cached_utf8
1350
 
        history = [get_cached_utf8(l.rstrip('\r\n')) for l in
1351
 
                self.control_files.get('revision-history').readlines()]
 
1445
        history = self.control_files.get('revision-history').read().split('\n')
 
1446
        if history[-1:] == ['']:
 
1447
            # There shouldn't be a trailing newline, but just in case.
 
1448
            history.pop()
1352
1449
        return history
1353
1450
 
1354
1451
    @needs_read_lock
1452
1549
        :param _run_hooks: Private parameter - allow disabling of
1453
1550
            hooks, used when pushing to a master branch.
1454
1551
        """
 
1552
        result = PullResult()
 
1553
        result.source_branch = source
 
1554
        result.target_branch = self
1455
1555
        source.lock_read()
1456
1556
        try:
1457
 
            old_count, old_tip = self.last_revision_info()
 
1557
            result.old_revno, result.old_revid = self.last_revision_info()
1458
1558
            try:
1459
1559
                self.update_revisions(source, stop_revision)
1460
1560
            except DivergedBranches:
1461
1561
                if not overwrite:
1462
1562
                    raise
1463
1563
            if overwrite:
1464
 
                self.set_revision_history(source.revision_history())
1465
 
            new_count, new_tip = self.last_revision_info()
 
1564
                if stop_revision is None:
 
1565
                    stop_revision = source.last_revision()
 
1566
                self.generate_revision_history(stop_revision)
 
1567
            result.tag_conflicts = source.tags.merge_to(self.tags)
 
1568
            result.new_revno, result.new_revid = self.last_revision_info()
 
1569
            if _hook_master:
 
1570
                result.master_branch = _hook_master
 
1571
                result.local_branch = self
 
1572
            else:
 
1573
                result.master_branch = self
 
1574
                result.local_branch = None
1466
1575
            if _run_hooks:
1467
 
                if _hook_master:
1468
 
                    _hook_local = self
1469
 
                else:
1470
 
                    _hook_master = self
1471
 
                    _hook_local = None
1472
1576
                for hook in Branch.hooks['post_pull']:
1473
 
                    hook(source, _hook_local, _hook_master, old_count, old_tip,
1474
 
                        new_count, new_tip)
1475
 
            return new_count - old_count
 
1577
                    hook(result)
1476
1578
        finally:
1477
1579
            source.unlock()
 
1580
        return result
1478
1581
 
1479
1582
    def _get_parent_location(self):
1480
1583
        _locs = ['parent', 'pull', 'x-pull']
1495
1598
        :param _run_hooks: Private parameter - allow disabling of
1496
1599
            hooks, used when pushing to a master branch.
1497
1600
        """
 
1601
        result = PushResult()
 
1602
        result.source_branch = self
 
1603
        result.target_branch = target
1498
1604
        target.lock_write()
1499
1605
        try:
1500
 
            old_count, old_tip = target.last_revision_info()
 
1606
            result.old_revno, result.old_revid = target.last_revision_info()
1501
1607
            try:
1502
1608
                target.update_revisions(self, stop_revision)
1503
1609
            except DivergedBranches:
1505
1611
                    raise
1506
1612
            if overwrite:
1507
1613
                target.set_revision_history(self.revision_history())
1508
 
            new_count, new_tip = target.last_revision_info()
 
1614
            result.tag_conflicts = self.tags.merge_to(target.tags)
 
1615
            result.new_revno, result.new_revid = target.last_revision_info()
 
1616
            if _hook_master:
 
1617
                result.master_branch = _hook_master
 
1618
                result.local_branch = target
 
1619
            else:
 
1620
                result.master_branch = target
 
1621
                result.local_branch = None
1509
1622
            if _run_hooks:
1510
 
                if _hook_master:
1511
 
                    _hook_local = target
1512
 
                else:
1513
 
                    _hook_master = target
1514
 
                    _hook_local = None
1515
1623
                for hook in Branch.hooks['post_push']:
1516
 
                    hook(self, _hook_local, _hook_master, old_count, old_tip,
1517
 
                        new_count, new_tip)
1518
 
            return new_count - old_count
 
1624
                    hook(result)
1519
1625
        finally:
1520
1626
            target.unlock()
 
1627
        return result
1521
1628
 
1522
1629
    def get_parent(self):
1523
1630
        """See Branch.get_parent."""
1744
1851
        return None
1745
1852
 
1746
1853
 
 
1854
class BzrBranchExperimental(BzrBranch5):
 
1855
    """Bzr experimental branch format
 
1856
 
 
1857
    This format has:
 
1858
     - a revision-history file.
 
1859
     - a format string
 
1860
     - a lock dir guarding the branch itself
 
1861
     - all of this stored in a branch/ subdirectory
 
1862
     - works with shared repositories.
 
1863
     - a tag dictionary in the branch
 
1864
 
 
1865
    This format is new in bzr 0.15, but shouldn't be used for real data, 
 
1866
    only for testing.
 
1867
 
 
1868
    This class acts as it's own BranchFormat.
 
1869
    """
 
1870
 
 
1871
    _matchingbzrdir = bzrdir.BzrDirMetaFormat1()
 
1872
 
 
1873
    @classmethod
 
1874
    def get_format_string(cls):
 
1875
        """See BranchFormat.get_format_string()."""
 
1876
        return "Bazaar-NG branch format experimental\n"
 
1877
 
 
1878
    @classmethod
 
1879
    def get_format_description(cls):
 
1880
        """See BranchFormat.get_format_description()."""
 
1881
        return "Experimental branch format"
 
1882
 
 
1883
    @classmethod
 
1884
    def _initialize_control_files(cls, a_bzrdir, utf8_files, lock_filename,
 
1885
            lock_class):
 
1886
        branch_transport = a_bzrdir.get_branch_transport(cls)
 
1887
        control_files = lockable_files.LockableFiles(branch_transport,
 
1888
            lock_filename, lock_class)
 
1889
        control_files.create_lock()
 
1890
        control_files.lock_write()
 
1891
        try:
 
1892
            for filename, content in utf8_files:
 
1893
                control_files.put_utf8(filename, content)
 
1894
        finally:
 
1895
            control_files.unlock()
 
1896
        
 
1897
    @classmethod
 
1898
    def initialize(cls, a_bzrdir):
 
1899
        """Create a branch of this format in a_bzrdir."""
 
1900
        utf8_files = [('format', cls.get_format_string()),
 
1901
                      ('revision-history', ''),
 
1902
                      ('branch-name', ''),
 
1903
                      ('tags', ''),
 
1904
                      ]
 
1905
        cls._initialize_control_files(a_bzrdir, utf8_files,
 
1906
            'lock', lockdir.LockDir)
 
1907
        return cls.open(a_bzrdir, _found=True)
 
1908
 
 
1909
    @classmethod
 
1910
    def open(cls, a_bzrdir, _found=False):
 
1911
        """Return the branch object for a_bzrdir
 
1912
 
 
1913
        _found is a private parameter, do not use it. It is used to indicate
 
1914
               if format probing has already be done.
 
1915
        """
 
1916
        if not _found:
 
1917
            format = BranchFormat.find_format(a_bzrdir)
 
1918
            assert format.__class__ == cls
 
1919
        transport = a_bzrdir.get_branch_transport(None)
 
1920
        control_files = lockable_files.LockableFiles(transport, 'lock',
 
1921
                                                     lockdir.LockDir)
 
1922
        return cls(_format=cls,
 
1923
            _control_files=control_files,
 
1924
            a_bzrdir=a_bzrdir,
 
1925
            _repository=a_bzrdir.find_repository())
 
1926
 
 
1927
    @classmethod
 
1928
    def is_supported(cls):
 
1929
        return True
 
1930
 
 
1931
    def _make_tags(self):
 
1932
        return BasicTags(self)
 
1933
 
 
1934
    @classmethod
 
1935
    def supports_tags(cls):
 
1936
        return True
 
1937
 
 
1938
 
 
1939
BranchFormat.register_format(BzrBranchExperimental)
 
1940
 
 
1941
 
1747
1942
class BzrBranch6(BzrBranch5):
1748
1943
 
1749
1944
    @needs_read_lock
1836
2031
        self.set_last_revision_info(prev_revno + len(revision_ids),
1837
2032
                                    revision_ids[-1])
1838
2033
 
1839
 
    def _set_config_location(self, name, url, config=None,
1840
 
                             make_relative=False):
1841
 
        if config is None:
1842
 
            config = self.get_config()
1843
 
        if url is None:
1844
 
            url = ''
1845
 
        elif make_relative:
1846
 
            url = urlutils.relative_url(self.base, url)
1847
 
        config.set_user_option(name, url)
1848
 
 
1849
 
 
1850
 
    def _get_config_location(self, name, config=None):
1851
 
        if config is None:
1852
 
            config = self.get_config()
1853
 
        location = config.get_user_option(name)
1854
 
        if location == '':
1855
 
            location = None
1856
 
        return location
1857
 
 
1858
2034
    @needs_write_lock
1859
2035
    def _set_parent_location(self, url):
1860
2036
        """Set the parent branch"""
1932
2108
            revno = self.revision_id_to_revno(revision_id)
1933
2109
        destination.set_last_revision_info(revno, revision_id)
1934
2110
 
 
2111
    def _make_tags(self):
 
2112
        return BasicTags(self)
 
2113
 
1935
2114
 
1936
2115
class BranchTestProviderAdapter(object):
1937
2116
    """A tool to generate a suite testing multiple branch formats at once.
1960
2139
            new_test.bzrdir_format = bzrdir_format
1961
2140
            new_test.branch_format = branch_format
1962
2141
            def make_new_test_id():
1963
 
                new_id = "%s(%s)" % (new_test.id(), branch_format.__class__.__name__)
 
2142
                # the format can be either a class or an instance
 
2143
                name = getattr(branch_format, '__name__',
 
2144
                        branch_format.__class__.__name__)
 
2145
                new_id = "%s(%s)" % (new_test.id(), name)
1964
2146
                return lambda: new_id
1965
2147
            new_test.id = make_new_test_id()
1966
2148
            result.addTest(new_test)
1967
2149
        return result
1968
2150
 
1969
2151
 
 
2152
######################################################################
 
2153
# results of operations
 
2154
 
 
2155
 
 
2156
class _Result(object):
 
2157
 
 
2158
    def _show_tag_conficts(self, to_file):
 
2159
        if not getattr(self, 'tag_conflicts', None):
 
2160
            return
 
2161
        to_file.write('Conflicting tags:\n')
 
2162
        for name, value1, value2 in self.tag_conflicts:
 
2163
            to_file.write('    %s\n' % (name, ))
 
2164
 
 
2165
 
 
2166
class PullResult(_Result):
 
2167
    """Result of a Branch.pull operation.
 
2168
 
 
2169
    :ivar old_revno: Revision number before pull.
 
2170
    :ivar new_revno: Revision number after pull.
 
2171
    :ivar old_revid: Tip revision id before pull.
 
2172
    :ivar new_revid: Tip revision id after pull.
 
2173
    :ivar source_branch: Source (local) branch object.
 
2174
    :ivar master_branch: Master branch of the target, or None.
 
2175
    :ivar target_branch: Target/destination branch object.
 
2176
    """
 
2177
 
 
2178
    def __int__(self):
 
2179
        # DEPRECATED: pull used to return the change in revno
 
2180
        return self.new_revno - self.old_revno
 
2181
 
 
2182
    def report(self, to_file):
 
2183
        if self.old_revid == self.new_revid:
 
2184
            to_file.write('No revisions to pull.\n')
 
2185
        else:
 
2186
            to_file.write('Now on revision %d.\n' % self.new_revno)
 
2187
        self._show_tag_conficts(to_file)
 
2188
 
 
2189
 
 
2190
class PushResult(_Result):
 
2191
    """Result of a Branch.push operation.
 
2192
 
 
2193
    :ivar old_revno: Revision number before push.
 
2194
    :ivar new_revno: Revision number after push.
 
2195
    :ivar old_revid: Tip revision id before push.
 
2196
    :ivar new_revid: Tip revision id after push.
 
2197
    :ivar source_branch: Source branch object.
 
2198
    :ivar master_branch: Master branch of the target, or None.
 
2199
    :ivar target_branch: Target/destination branch object.
 
2200
    """
 
2201
 
 
2202
    def __int__(self):
 
2203
        # DEPRECATED: push used to return the change in revno
 
2204
        return self.new_revno - self.old_revno
 
2205
 
 
2206
    def report(self, to_file):
 
2207
        """Write a human-readable description of the result."""
 
2208
        if self.old_revid == self.new_revid:
 
2209
            to_file.write('No new revisions to push.\n')
 
2210
        else:
 
2211
            to_file.write('Pushed up to revision %d.\n' % self.new_revno)
 
2212
        self._show_tag_conficts(to_file)
 
2213
 
 
2214
 
1970
2215
class BranchCheckResult(object):
1971
2216
    """Results of checking branch consistency.
1972
2217
 
1987
2232
             self.branch._format)
1988
2233
 
1989
2234
 
1990
 
######################################################################
1991
 
# predicates
1992
 
 
1993
 
 
1994
 
@deprecated_function(zero_eight)
1995
 
def is_control_file(*args, **kwargs):
1996
 
    """See bzrlib.workingtree.is_control_file."""
1997
 
    from bzrlib import workingtree
1998
 
    return workingtree.is_control_file(*args, **kwargs)
1999
 
 
2000
 
 
2001
2235
class Converter5to6(object):
2002
2236
    """Perform an in-place upgrade of format 5 to format 6"""
2003
2237
 
2012
2246
        new_branch.set_bound_location(branch.get_bound_location())
2013
2247
        new_branch.set_push_location(branch.get_push_location())
2014
2248
 
 
2249
        # New branch has no tags by default
 
2250
        new_branch.tags._set_tag_dict({})
 
2251
 
2015
2252
        # Copying done; now update target format
2016
2253
        new_branch.control_files.put_utf8('format',
2017
2254
            format.get_format_string())