/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 and resolve conflicts.

Show diffs side-by-side

added added

removed removed

Lines of Context:
1
 
# Copyright (C) 2005, 2006, 2007 Canonical Ltd
 
1
# Copyright (C) 2005, 2006, 2007, 2008 Canonical Ltd
2
2
#
3
3
# This program is free software; you can redistribute it and/or modify
4
4
# it under the terms of the GNU General Public License as published by
41
41
 
42
42
from bzrlib.decorators import needs_read_lock, needs_write_lock
43
43
from bzrlib.hooks import Hooks
44
 
from bzrlib.symbol_versioning import (deprecated_method,
45
 
                                      zero_sixteen,
46
 
                                      )
 
44
from bzrlib.symbol_versioning import (
 
45
    deprecated_in,
 
46
    deprecated_method,
 
47
    )
47
48
from bzrlib.trace import mutter, mutter_callsite, note, is_quiet
48
49
 
49
50
 
221
222
        """
222
223
        self.control_files.dont_leave_in_place()
223
224
 
 
225
    @deprecated_method(deprecated_in((0, 16, 0)))
224
226
    def abspath(self, name):
225
227
        """Return absolute filename for something in the branch
226
228
        
317
319
        The delta is relative to its mainline predecessor, or the
318
320
        empty tree for revision 1.
319
321
        """
320
 
        assert isinstance(revno, int)
321
322
        rh = self.revision_history()
322
323
        if not (1 <= revno <= len(rh)):
323
324
            raise errors.InvalidRevisionNumber(revno)
324
325
        return self.repository.get_revision_delta(rh[revno-1])
325
326
 
326
 
    @deprecated_method(zero_sixteen)
327
 
    def get_root_id(self):
328
 
        """Return the id of this branches root
329
 
 
330
 
        Deprecated: branches don't have root ids-- trees do.
331
 
        Use basis_tree().get_root_id() instead.
332
 
        """
333
 
        raise NotImplementedError(self.get_root_id)
334
 
 
335
327
    def print_file(self, file, revision_id):
336
328
        """Print `file` to stdout."""
337
329
        raise NotImplementedError(self.print_file)
451
443
        if stop_revision is None:
452
444
            stop_revision = other_len
453
445
        else:
454
 
            assert isinstance(stop_revision, int)
455
446
            if stop_revision > other_len:
456
447
                raise errors.NoSuchRevision(self, stop_revision)
457
448
        return other_history[self_len:stop_revision]
458
449
 
459
 
    def update_revisions(self, other, stop_revision=None):
 
450
    def update_revisions(self, other, stop_revision=None, overwrite=False,
 
451
                         graph=None):
460
452
        """Pull in new perfect-fit revisions.
461
453
 
462
454
        :param other: Another Branch to pull from
463
455
        :param stop_revision: Updated until the given revision
 
456
        :param overwrite: Always set the branch pointer, rather than checking
 
457
            to see if it is a proper descendant.
 
458
        :param graph: A Graph object that can be used to query history
 
459
            information. This can be None.
464
460
        :return: None
465
461
        """
466
462
        raise NotImplementedError(self.update_revisions)
704
700
        :return: A BranchCheckResult.
705
701
        """
706
702
        mainline_parent_id = None
707
 
        for revision_id in self.revision_history():
 
703
        last_revno, last_revision_id = self.last_revision_info()
 
704
        real_rev_history = list(self.repository.iter_reverse_revision_history(
 
705
                                last_revision_id))
 
706
        real_rev_history.reverse()
 
707
        if len(real_rev_history) != last_revno:
 
708
            raise errors.BzrCheckError('revno does not match len(mainline)'
 
709
                ' %s != %s' % (last_revno, len(real_rev_history)))
 
710
        # TODO: We should probably also check that real_rev_history actually
 
711
        #       matches self.revision_history()
 
712
        for revision_id in real_rev_history:
708
713
            try:
709
714
                revision = self.repository.get_revision(revision_id)
710
715
            except errors.NoSuchRevision, e:
783
788
            basis_tree.unlock()
784
789
        return tree
785
790
 
 
791
    @needs_write_lock
 
792
    def reconcile(self, thorough=True):
 
793
        """Make sure the data stored in this branch is consistent."""
 
794
        from bzrlib.reconcile import BranchReconciler
 
795
        reconciler = BranchReconciler(self, thorough=thorough)
 
796
        reconciler.reconcile()
 
797
        return reconciler
 
798
 
786
799
    def reference_parent(self, file_id, path):
787
800
        """Return the parent branch for a tree-reference file_id
788
801
        :param file_id: The file_id of the tree reference
900
913
        control_files.create_lock()
901
914
        control_files.lock_write()
902
915
        if set_format:
903
 
            control_files.put_utf8('format', self.get_format_string())
 
916
            utf8_files += [('format', self.get_format_string())]
904
917
        try:
905
 
            for file, content in utf8_files:
906
 
                control_files.put_utf8(file, content)
 
918
            for (filename, content) in utf8_files:
 
919
                branch_transport.put_bytes(
 
920
                    filename, content,
 
921
                    mode=control_files._file_mode)
907
922
        finally:
908
923
            control_files.unlock()
909
924
        return self.open(a_bzrdir, _found=True)
939
954
 
940
955
    @classmethod
941
956
    def unregister_format(klass, format):
942
 
        assert klass._formats[format.get_format_string()] is format
943
957
        del klass._formats[format.get_format_string()]
944
958
 
945
959
    def __str__(self):
949
963
        """True if this format supports tags stored in the branch"""
950
964
        return False  # by default
951
965
 
952
 
    # XXX: Probably doesn't really belong here -- mbp 20070212
953
 
    def _initialize_control_files(self, a_bzrdir, utf8_files, lock_filename,
954
 
            lock_class):
955
 
        branch_transport = a_bzrdir.get_branch_transport(self)
956
 
        control_files = lockable_files.LockableFiles(branch_transport,
957
 
            lock_filename, lock_class)
958
 
        control_files.create_lock()
959
 
        control_files.lock_write()
960
 
        try:
961
 
            for filename, content in utf8_files:
962
 
                control_files.put_utf8(filename, content)
963
 
        finally:
964
 
            control_files.unlock()
965
 
 
966
966
 
967
967
class BranchHooks(Hooks):
968
968
    """A dictionary mapping hook name to a list of callables for branch hooks.
1149
1149
        """
1150
1150
        if not _found:
1151
1151
            format = BranchFormat.find_format(a_bzrdir)
1152
 
            assert format.__class__ == self.__class__
 
1152
            if format.__class__ != self.__class__:
 
1153
                raise AssertionError("wrong format %r found for %r" %
 
1154
                    (format, self))
1153
1155
        try:
1154
1156
            transport = a_bzrdir.get_branch_transport(None)
1155
1157
            control_files = lockable_files.LockableFiles(transport, 'lock',
1197
1199
        """
1198
1200
        if not _found:
1199
1201
            format = BranchFormat.find_format(a_bzrdir)
1200
 
            assert format.__class__ == self.__class__
 
1202
            if format.__class__ != self.__class__:
 
1203
                raise AssertionError("wrong format %r found for %r" %
 
1204
                    (format, self))
1201
1205
        transport = a_bzrdir.get_branch_transport(None)
1202
1206
        control_files = lockable_files.LockableFiles(transport, 'lock',
1203
1207
                                                     lockdir.LockDir)
1277
1281
        """
1278
1282
        if not _found:
1279
1283
            format = BranchFormat.find_format(a_bzrdir)
1280
 
            assert format.__class__ == self.__class__
 
1284
            if format.__class__ != self.__class__:
 
1285
                raise AssertionError("wrong format %r found for %r" %
 
1286
                    (format, self))
1281
1287
        if location is None:
1282
1288
            location = self.get_reference(a_bzrdir)
1283
1289
        real_bzrdir = bzrdir.BzrDir.open(
1312
1318
    Note that it's "local" in the context of the filesystem; it doesn't
1313
1319
    really matter if it's on an nfs/smb/afs/coda/... share, as long as
1314
1320
    it's writable, and can be accessed via the normal filesystem API.
 
1321
 
 
1322
    :ivar _transport: Transport for file operations on this branch's 
 
1323
        control files, typically pointing to the .bzr/branch directory.
 
1324
    :ivar repository: Repository for this branch.
 
1325
    :ivar base: The url of the base directory for this branch; the one 
 
1326
        containing the .bzr directory.
1315
1327
    """
1316
1328
    
1317
1329
    def __init__(self, _format=None,
1322
1334
            raise ValueError('a_bzrdir must be supplied')
1323
1335
        else:
1324
1336
            self.bzrdir = a_bzrdir
1325
 
        # self._transport used to point to the directory containing the
1326
 
        # control directory, but was not used - now it's just the transport
1327
 
        # for the branch control files.  mbp 20070212
1328
1337
        self._base = self.bzrdir.transport.clone('..').base
 
1338
        # XXX: We should be able to just do
 
1339
        #   self.base = self.bzrdir.root_transport.base
 
1340
        # but this does not quite work yet -- mbp 20080522
1329
1341
        self._format = _format
1330
1342
        if _control_files is None:
1331
1343
            raise ValueError('BzrBranch _control_files is None')
1344
1356
 
1345
1357
    base = property(_get_base, doc="The URL for the root of this branch.")
1346
1358
 
 
1359
    @deprecated_method(deprecated_in((0, 16, 0)))
1347
1360
    def abspath(self, name):
1348
1361
        """See Branch.abspath."""
1349
 
        return self.control_files._transport.abspath(name)
1350
 
 
1351
 
 
1352
 
    @deprecated_method(zero_sixteen)
1353
 
    @needs_read_lock
1354
 
    def get_root_id(self):
1355
 
        """See Branch.get_root_id."""
1356
 
        tree = self.repository.revision_tree(self.last_revision())
1357
 
        return tree.get_root_id()
 
1362
        return self._transport.abspath(name)
1358
1363
 
1359
1364
    def is_locked(self):
1360
1365
        return self.control_files.is_locked()
1405
1410
 
1406
1411
        This performs the actual writing to disk.
1407
1412
        It is intended to be called by BzrBranch5.set_revision_history."""
1408
 
        self.control_files.put_bytes(
1409
 
            'revision-history', '\n'.join(history))
 
1413
        self._transport.put_bytes(
 
1414
            'revision-history', '\n'.join(history),
 
1415
            mode=self.control_files._file_mode)
1410
1416
 
1411
1417
    @needs_write_lock
1412
1418
    def set_revision_history(self, rev_history):
1444
1450
        """
1445
1451
        revision_id = _mod_revision.ensure_null(revision_id)
1446
1452
        old_revno, old_revid = self.last_revision_info()
 
1453
        # this old format stores the full history, but this api doesn't
 
1454
        # provide it, so we must generate, and might as well check it's
 
1455
        # correct
1447
1456
        history = self._lefthand_history(revision_id)
1448
 
        assert len(history) == revno, '%d != %d' % (len(history), revno)
 
1457
        if len(history) != revno:
 
1458
            raise AssertionError('%d != %d' % (len(history), revno))
1449
1459
        self.set_revision_history(history)
1450
1460
        self._run_post_change_branch_tip_hooks(old_revno, old_revid)
1451
1461
 
1452
1462
    def _gen_revision_history(self):
1453
 
        history = self.control_files.get('revision-history').read().split('\n')
 
1463
        history = self._transport.get_bytes('revision-history').split('\n')
1454
1464
        if history[-1:] == ['']:
1455
1465
            # There shouldn't be a trailing newline, but just in case.
1456
1466
            history.pop()
1496
1506
            last_rev, other_branch))
1497
1507
 
1498
1508
    @needs_write_lock
1499
 
    def update_revisions(self, other, stop_revision=None, overwrite=False):
 
1509
    def update_revisions(self, other, stop_revision=None, overwrite=False,
 
1510
                         graph=None):
1500
1511
        """See Branch.update_revisions."""
1501
1512
        other.lock_read()
1502
1513
        try:
1503
 
            other_last_revno, other_last_revision = other.last_revision_info()
 
1514
            other_revno, other_last_revision = other.last_revision_info()
 
1515
            stop_revno = None # unknown
1504
1516
            if stop_revision is None:
1505
1517
                stop_revision = other_last_revision
1506
1518
                if _mod_revision.is_null(stop_revision):
1507
1519
                    # if there are no commits, we're done.
1508
1520
                    return
1509
 
            # whats the current last revision, before we fetch [and change it
 
1521
                stop_revno = other_revno
 
1522
 
 
1523
            # what's the current last revision, before we fetch [and change it
1510
1524
            # possibly]
1511
1525
            last_rev = _mod_revision.ensure_null(self.last_revision())
1512
1526
            # we fetch here so that we don't process data twice in the common
1516
1530
            self.fetch(other, stop_revision)
1517
1531
            # Check to see if one is an ancestor of the other
1518
1532
            if not overwrite:
1519
 
                heads = self.repository.get_graph().heads([stop_revision,
1520
 
                                                           last_rev])
 
1533
                if graph is None:
 
1534
                    graph = self.repository.get_graph()
 
1535
                heads = graph.heads([stop_revision, last_rev])
1521
1536
                if heads == set([last_rev]):
1522
1537
                    # The current revision is a decendent of the target,
1523
1538
                    # nothing to do
1525
1540
                elif heads == set([stop_revision, last_rev]):
1526
1541
                    # These branches have diverged
1527
1542
                    raise errors.DivergedBranches(self, other)
1528
 
                assert heads == set([stop_revision])
1529
 
            if other_last_revision == stop_revision:
1530
 
                self.set_last_revision_info(other_last_revno,
1531
 
                                            other_last_revision)
1532
 
            else:
1533
 
                # TODO: jam 2007-11-29 Is there a way to determine the
1534
 
                #       revno without searching all of history??
1535
 
                if overwrite:
1536
 
                    self.generate_revision_history(stop_revision)
1537
 
                else:
1538
 
                    self.generate_revision_history(stop_revision,
1539
 
                        last_rev=last_rev, other_branch=other)
 
1543
                elif heads != set([stop_revision]):
 
1544
                    raise AssertionError("invalid heads: %r" % heads)
 
1545
            if stop_revno is None:
 
1546
                if graph is None:
 
1547
                    graph = self.repository.get_graph()
 
1548
                this_revno, this_last_revision = self.last_revision_info()
 
1549
                stop_revno = graph.find_distance_to_null(stop_revision,
 
1550
                                [(other_last_revision, other_revno),
 
1551
                                 (this_last_revision, this_revno)])
 
1552
            self.set_last_revision_info(stop_revno, stop_revision)
1540
1553
        finally:
1541
1554
            other.unlock()
1542
1555
 
1560
1573
        result.target_branch = self
1561
1574
        source.lock_read()
1562
1575
        try:
 
1576
            # We assume that during 'pull' the local repository is closer than
 
1577
            # the remote one.
 
1578
            graph = self.repository.get_graph(source.repository)
1563
1579
            result.old_revno, result.old_revid = self.last_revision_info()
1564
 
            self.update_revisions(source, stop_revision, overwrite=overwrite)
 
1580
            self.update_revisions(source, stop_revision, overwrite=overwrite,
 
1581
                                  graph=graph)
1565
1582
            result.tag_conflicts = source.tags.merge_to(self.tags, overwrite)
1566
1583
            result.new_revno, result.new_revid = self.last_revision_info()
1567
1584
            if _hook_master:
1581
1598
        _locs = ['parent', 'pull', 'x-pull']
1582
1599
        for l in _locs:
1583
1600
            try:
1584
 
                return self.control_files.get(l).read().strip('\n')
 
1601
                return self._transport.get_bytes(l).strip('\n')
1585
1602
            except errors.NoSuchFile:
1586
1603
                pass
1587
1604
        return None
1664
1681
        result.source_branch = self
1665
1682
        result.target_branch = target
1666
1683
        result.old_revno, result.old_revid = target.last_revision_info()
1667
 
        try:
1668
 
            target.update_revisions(self, stop_revision)
1669
 
        except errors.DivergedBranches:
1670
 
            if not overwrite:
1671
 
                raise
1672
 
        if overwrite:
1673
 
            target.set_revision_history(self.revision_history())
 
1684
 
 
1685
        # We assume that during 'push' this repository is closer than
 
1686
        # the target.
 
1687
        graph = self.repository.get_graph(target.repository)
 
1688
        target.update_revisions(self, stop_revision, overwrite=overwrite,
 
1689
                                graph=graph)
1674
1690
        result.tag_conflicts = self.tags.merge_to(target.tags, overwrite)
1675
1691
        result.new_revno, result.new_revid = target.last_revision_info()
1676
1692
        return result
1677
1693
 
1678
1694
    def get_parent(self):
1679
1695
        """See Branch.get_parent."""
1680
 
 
1681
 
        assert self.base[-1] == '/'
1682
1696
        parent = self._get_parent_location()
1683
1697
        if parent is None:
1684
1698
            return parent
1703
1717
        # TODO: Maybe delete old location files?
1704
1718
        # URLs should never be unicode, even on the local fs,
1705
1719
        # FIXUP this and get_parent in a future branch format bump:
1706
 
        # read and rewrite the file, and have the new format code read
1707
 
        # using .get not .get_utf8. RBC 20060125
 
1720
        # read and rewrite the file. RBC 20060125
1708
1721
        if url is not None:
1709
1722
            if isinstance(url, unicode):
1710
 
                try: 
 
1723
                try:
1711
1724
                    url = url.encode('ascii')
1712
1725
                except UnicodeEncodeError:
1713
1726
                    raise errors.InvalidURL(url,
1718
1731
 
1719
1732
    def _set_parent_location(self, url):
1720
1733
        if url is None:
1721
 
            self.control_files._transport.delete('parent')
 
1734
            self._transport.delete('parent')
1722
1735
        else:
1723
 
            assert isinstance(url, str)
1724
 
            self.control_files.put_bytes('parent', url + '\n')
 
1736
            self._transport.put_bytes('parent', url + '\n',
 
1737
                mode=self.control_files._file_mode)
1725
1738
 
1726
1739
 
1727
1740
class BzrBranch5(BzrBranch):
1769
1782
 
1770
1783
    def get_bound_location(self):
1771
1784
        try:
1772
 
            return self.control_files.get_utf8('bound').read()[:-1]
 
1785
            return self._transport.get_bytes('bound')[:-1]
1773
1786
        except errors.NoSuchFile:
1774
1787
            return None
1775
1788
 
1801
1814
        :param location: URL to the target branch
1802
1815
        """
1803
1816
        if location:
1804
 
            self.control_files.put_utf8('bound', location+'\n')
 
1817
            self._transport.put_bytes('bound', location+'\n',
 
1818
                mode=self.bzrdir._get_file_mode())
1805
1819
        else:
1806
1820
            try:
1807
 
                self.control_files._transport.delete('bound')
 
1821
                self._transport.delete('bound')
1808
1822
            except errors.NoSuchFile:
1809
1823
                return False
1810
1824
            return True
1881
1895
        return self._last_revision_info_cache
1882
1896
 
1883
1897
    def _last_revision_info(self):
1884
 
        revision_string = self.control_files.get('last-revision').read()
 
1898
        revision_string = self._transport.get_bytes('last-revision')
1885
1899
        revno, revision_id = revision_string.rstrip('\n').split(' ', 1)
1886
1900
        revision_id = cache_utf8.get_cached_utf8(revision_id)
1887
1901
        revno = int(revno)
1896
1910
        Intended to be called by set_last_revision_info and
1897
1911
        _write_revision_history.
1898
1912
        """
1899
 
        assert revision_id is not None, "Use NULL_REVISION, not None"
 
1913
        revision_id = _mod_revision.ensure_null(revision_id)
1900
1914
        out_string = '%d %s\n' % (revno, revision_id)
1901
 
        self.control_files.put_bytes('last-revision', out_string)
 
1915
        self._transport.put_bytes('last-revision', out_string,
 
1916
            mode=self.control_files._file_mode)
1902
1917
 
1903
1918
    @needs_write_lock
1904
1919
    def set_last_revision_info(self, revno, revision_id):
1945
1960
            iterator = repo.iter_reverse_revision_history(start_revision)
1946
1961
            #skip the last revision in the list
1947
1962
            next_revision = iterator.next()
1948
 
            assert next_revision == start_revision
1949
1963
        for revision_id in iterator:
1950
1964
            self._partial_revision_history_cache.append(revision_id)
1951
1965
            if (stop_index is not None and
2081
2095
            raise errors.NoSuchRevision(self, revno)
2082
2096
 
2083
2097
        if history is not None:
2084
 
            assert len(history) == last_revno, 'revno/history mismatch'
2085
2098
            return history[revno - 1]
2086
2099
 
2087
2100
        index = last_revno - revno
2209
2222
        new_branch.tags._set_tag_dict({})
2210
2223
 
2211
2224
        # Copying done; now update target format
2212
 
        new_branch.control_files.put_utf8('format',
2213
 
            format.get_format_string())
 
2225
        new_branch._transport.put_bytes('format',
 
2226
            format.get_format_string(),
 
2227
            mode=new_branch.control_files._file_mode)
2214
2228
 
2215
2229
        # Clean up old files
2216
 
        new_branch.control_files._transport.delete('revision-history')
 
2230
        new_branch._transport.delete('revision-history')
2217
2231
        try:
2218
2232
            branch.set_parent(None)
2219
2233
        except errors.NoSuchFile: