/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

Update to bzr.dev.

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 (
 
45
    deprecated_in,
 
46
    deprecated_method,
 
47
    )
44
48
from bzrlib.trace import mutter, mutter_callsite, note, is_quiet
45
49
 
46
50
 
218
222
        """
219
223
        self.control_files.dont_leave_in_place()
220
224
 
 
225
    @deprecated_method(deprecated_in((0, 16, 0)))
221
226
    def abspath(self, name):
222
227
        """Return absolute filename for something in the branch
223
228
        
420
425
        else:
421
426
            return (0, _mod_revision.NULL_REVISION)
422
427
 
 
428
    @deprecated_method(deprecated_in((1, 6, 0)))
423
429
    def missing_revisions(self, other, stop_revision=None):
424
430
        """Return a list of new revisions that would perfectly fit.
425
431
        
442
448
                raise errors.NoSuchRevision(self, stop_revision)
443
449
        return other_history[self_len:stop_revision]
444
450
 
445
 
    def update_revisions(self, other, stop_revision=None):
 
451
    @needs_write_lock
 
452
    def update_revisions(self, other, stop_revision=None, overwrite=False,
 
453
                         graph=None):
446
454
        """Pull in new perfect-fit revisions.
447
455
 
448
456
        :param other: Another Branch to pull from
449
457
        :param stop_revision: Updated until the given revision
 
458
        :param overwrite: Always set the branch pointer, rather than checking
 
459
            to see if it is a proper descendant.
 
460
        :param graph: A Graph object that can be used to query history
 
461
            information. This can be None.
450
462
        :return: None
451
463
        """
452
 
        raise NotImplementedError(self.update_revisions)
 
464
        other.lock_read()
 
465
        try:
 
466
            other_revno, other_last_revision = other.last_revision_info()
 
467
            stop_revno = None # unknown
 
468
            if stop_revision is None:
 
469
                stop_revision = other_last_revision
 
470
                if _mod_revision.is_null(stop_revision):
 
471
                    # if there are no commits, we're done.
 
472
                    return
 
473
                stop_revno = other_revno
 
474
 
 
475
            # what's the current last revision, before we fetch [and change it
 
476
            # possibly]
 
477
            last_rev = _mod_revision.ensure_null(self.last_revision())
 
478
            # we fetch here so that we don't process data twice in the common
 
479
            # case of having something to pull, and so that the check for 
 
480
            # already merged can operate on the just fetched graph, which will
 
481
            # be cached in memory.
 
482
            self.fetch(other, stop_revision)
 
483
            # Check to see if one is an ancestor of the other
 
484
            if not overwrite:
 
485
                if graph is None:
 
486
                    graph = self.repository.get_graph()
 
487
                heads = graph.heads([stop_revision, last_rev])
 
488
                if heads == set([last_rev]):
 
489
                    # The current revision is a decendent of the target,
 
490
                    # nothing to do
 
491
                    return
 
492
                elif heads == set([stop_revision, last_rev]):
 
493
                    # These branches have diverged
 
494
                    raise errors.DivergedBranches(self, other)
 
495
                elif heads != set([stop_revision]):
 
496
                    raise AssertionError("invalid heads: %r" % heads)
 
497
            if stop_revno is None:
 
498
                if graph is None:
 
499
                    graph = self.repository.get_graph()
 
500
                this_revno, this_last_revision = self.last_revision_info()
 
501
                stop_revno = graph.find_distance_to_null(stop_revision,
 
502
                                [(other_last_revision, other_revno),
 
503
                                 (this_last_revision, this_revno)])
 
504
            self.set_last_revision_info(stop_revno, stop_revision)
 
505
        finally:
 
506
            other.unlock()
 
507
 
 
508
 
453
509
 
454
510
    def revision_id_to_revno(self, revision_id):
455
511
        """Given a revision id, return its revno"""
903
959
        control_files.create_lock()
904
960
        control_files.lock_write()
905
961
        if set_format:
906
 
            control_files.put_utf8('format', self.get_format_string())
 
962
            utf8_files += [('format', self.get_format_string())]
907
963
        try:
908
 
            for file, content in utf8_files:
909
 
                control_files.put_utf8(file, content)
 
964
            for (filename, content) in utf8_files:
 
965
                branch_transport.put_bytes(
 
966
                    filename, content,
 
967
                    mode=a_bzrdir._get_file_mode())
910
968
        finally:
911
969
            control_files.unlock()
912
970
        return self.open(a_bzrdir, _found=True)
951
1009
        """True if this format supports tags stored in the branch"""
952
1010
        return False  # by default
953
1011
 
954
 
    # XXX: Probably doesn't really belong here -- mbp 20070212
955
 
    def _initialize_control_files(self, a_bzrdir, utf8_files, lock_filename,
956
 
            lock_class):
957
 
        branch_transport = a_bzrdir.get_branch_transport(self)
958
 
        control_files = lockable_files.LockableFiles(branch_transport,
959
 
            lock_filename, lock_class)
960
 
        control_files.create_lock()
961
 
        control_files.lock_write()
962
 
        try:
963
 
            for filename, content in utf8_files:
964
 
                control_files.put_utf8(filename, content)
965
 
        finally:
966
 
            control_files.unlock()
967
 
 
968
1012
 
969
1013
class BranchHooks(Hooks):
970
1014
    """A dictionary mapping hook name to a list of callables for branch hooks.
1320
1364
    Note that it's "local" in the context of the filesystem; it doesn't
1321
1365
    really matter if it's on an nfs/smb/afs/coda/... share, as long as
1322
1366
    it's writable, and can be accessed via the normal filesystem API.
 
1367
 
 
1368
    :ivar _transport: Transport for file operations on this branch's 
 
1369
        control files, typically pointing to the .bzr/branch directory.
 
1370
    :ivar repository: Repository for this branch.
 
1371
    :ivar base: The url of the base directory for this branch; the one 
 
1372
        containing the .bzr directory.
1323
1373
    """
1324
1374
    
1325
1375
    def __init__(self, _format=None,
1330
1380
            raise ValueError('a_bzrdir must be supplied')
1331
1381
        else:
1332
1382
            self.bzrdir = a_bzrdir
1333
 
        # self._transport used to point to the directory containing the
1334
 
        # control directory, but was not used - now it's just the transport
1335
 
        # for the branch control files.  mbp 20070212
1336
1383
        self._base = self.bzrdir.transport.clone('..').base
 
1384
        # XXX: We should be able to just do
 
1385
        #   self.base = self.bzrdir.root_transport.base
 
1386
        # but this does not quite work yet -- mbp 20080522
1337
1387
        self._format = _format
1338
1388
        if _control_files is None:
1339
1389
            raise ValueError('BzrBranch _control_files is None')
1352
1402
 
1353
1403
    base = property(_get_base, doc="The URL for the root of this branch.")
1354
1404
 
 
1405
    @deprecated_method(deprecated_in((0, 16, 0)))
1355
1406
    def abspath(self, name):
1356
1407
        """See Branch.abspath."""
1357
 
        return self.control_files._transport.abspath(name)
 
1408
        return self._transport.abspath(name)
1358
1409
 
1359
1410
    def is_locked(self):
1360
1411
        return self.control_files.is_locked()
1405
1456
 
1406
1457
        This performs the actual writing to disk.
1407
1458
        It is intended to be called by BzrBranch5.set_revision_history."""
1408
 
        self.control_files.put_bytes(
1409
 
            'revision-history', '\n'.join(history))
 
1459
        self._transport.put_bytes(
 
1460
            'revision-history', '\n'.join(history),
 
1461
            mode=self.bzrdir._get_file_mode())
1410
1462
 
1411
1463
    @needs_write_lock
1412
1464
    def set_revision_history(self, rev_history):
1457
1509
        self._run_post_change_branch_tip_hooks(old_revno, old_revid)
1458
1510
 
1459
1511
    def _gen_revision_history(self):
1460
 
        history = self.control_files.get('revision-history').read().split('\n')
 
1512
        history = self._transport.get_bytes('revision-history').split('\n')
1461
1513
        if history[-1:] == ['']:
1462
1514
            # There shouldn't be a trailing newline, but just in case.
1463
1515
            history.pop()
1504
1556
        self.set_revision_history(self._lefthand_history(revision_id,
1505
1557
            last_rev, other_branch))
1506
1558
 
1507
 
    @needs_write_lock
1508
 
    def update_revisions(self, other, stop_revision=None, overwrite=False):
1509
 
        """See Branch.update_revisions."""
1510
 
        other.lock_read()
1511
 
        try:
1512
 
            other_last_revno, other_last_revision = other.last_revision_info()
1513
 
            if stop_revision is None:
1514
 
                stop_revision = other_last_revision
1515
 
                if _mod_revision.is_null(stop_revision):
1516
 
                    # if there are no commits, we're done.
1517
 
                    return
1518
 
            # whats the current last revision, before we fetch [and change it
1519
 
            # possibly]
1520
 
            last_rev = _mod_revision.ensure_null(self.last_revision())
1521
 
            # we fetch here so that we don't process data twice in the common
1522
 
            # case of having something to pull, and so that the check for 
1523
 
            # already merged can operate on the just fetched graph, which will
1524
 
            # be cached in memory.
1525
 
            self.fetch(other, stop_revision)
1526
 
            # Check to see if one is an ancestor of the other
1527
 
            if not overwrite:
1528
 
                heads = self.repository.get_graph().heads([stop_revision,
1529
 
                                                           last_rev])
1530
 
                if heads == set([last_rev]):
1531
 
                    # The current revision is a decendent of the target,
1532
 
                    # nothing to do
1533
 
                    return
1534
 
                elif heads == set([stop_revision, last_rev]):
1535
 
                    # These branches have diverged
1536
 
                    raise errors.DivergedBranches(self, other)
1537
 
                elif heads != set([stop_revision]):
1538
 
                    raise AssertionError("invalid heads: %r" % heads)
1539
 
            if other_last_revision == stop_revision:
1540
 
                self.set_last_revision_info(other_last_revno,
1541
 
                                            other_last_revision)
1542
 
            else:
1543
 
                # TODO: jam 2007-11-29 Is there a way to determine the
1544
 
                #       revno without searching all of history??
1545
 
                if overwrite:
1546
 
                    self.generate_revision_history(stop_revision)
1547
 
                else:
1548
 
                    self.generate_revision_history(stop_revision,
1549
 
                        last_rev=last_rev, other_branch=other)
1550
 
        finally:
1551
 
            other.unlock()
1552
 
 
1553
1559
    def basis_tree(self):
1554
1560
        """See Branch.basis_tree."""
1555
1561
        return self.repository.revision_tree(self.last_revision())
1570
1576
        result.target_branch = self
1571
1577
        source.lock_read()
1572
1578
        try:
 
1579
            # We assume that during 'pull' the local repository is closer than
 
1580
            # the remote one.
 
1581
            graph = self.repository.get_graph(source.repository)
1573
1582
            result.old_revno, result.old_revid = self.last_revision_info()
1574
 
            self.update_revisions(source, stop_revision, overwrite=overwrite)
 
1583
            self.update_revisions(source, stop_revision, overwrite=overwrite,
 
1584
                                  graph=graph)
1575
1585
            result.tag_conflicts = source.tags.merge_to(self.tags, overwrite)
1576
1586
            result.new_revno, result.new_revid = self.last_revision_info()
1577
1587
            if _hook_master:
1591
1601
        _locs = ['parent', 'pull', 'x-pull']
1592
1602
        for l in _locs:
1593
1603
            try:
1594
 
                return self.control_files.get(l).read().strip('\n')
 
1604
                return self._transport.get_bytes(l).strip('\n')
1595
1605
            except errors.NoSuchFile:
1596
1606
                pass
1597
1607
        return None
1674
1684
        result.source_branch = self
1675
1685
        result.target_branch = target
1676
1686
        result.old_revno, result.old_revid = target.last_revision_info()
1677
 
        try:
1678
 
            target.update_revisions(self, stop_revision)
1679
 
        except errors.DivergedBranches:
1680
 
            if not overwrite:
1681
 
                raise
1682
 
        if overwrite:
1683
 
            target.set_revision_history(self.revision_history())
 
1687
 
 
1688
        # We assume that during 'push' this repository is closer than
 
1689
        # the target.
 
1690
        graph = self.repository.get_graph(target.repository)
 
1691
        target.update_revisions(self, stop_revision, overwrite=overwrite,
 
1692
                                graph=graph)
1684
1693
        result.tag_conflicts = self.tags.merge_to(target.tags, overwrite)
1685
1694
        result.new_revno, result.new_revid = target.last_revision_info()
1686
1695
        return result
1714
1723
        # read and rewrite the file. RBC 20060125
1715
1724
        if url is not None:
1716
1725
            if isinstance(url, unicode):
1717
 
                try: 
 
1726
                try:
1718
1727
                    url = url.encode('ascii')
1719
1728
                except UnicodeEncodeError:
1720
1729
                    raise errors.InvalidURL(url,
1725
1734
 
1726
1735
    def _set_parent_location(self, url):
1727
1736
        if url is None:
1728
 
            self.control_files._transport.delete('parent')
 
1737
            self._transport.delete('parent')
1729
1738
        else:
1730
 
            self.control_files.put_bytes('parent', url + '\n')
 
1739
            self._transport.put_bytes('parent', url + '\n',
 
1740
                mode=self.bzrdir._get_file_mode())
1731
1741
 
1732
1742
 
1733
1743
class BzrBranch5(BzrBranch):
1807
1817
        :param location: URL to the target branch
1808
1818
        """
1809
1819
        if location:
1810
 
            self.control_files.put_utf8('bound', location+'\n')
 
1820
            self._transport.put_bytes('bound', location+'\n',
 
1821
                mode=self.bzrdir._get_file_mode())
1811
1822
        else:
1812
1823
            try:
1813
 
                self.control_files._transport.delete('bound')
 
1824
                self._transport.delete('bound')
1814
1825
            except errors.NoSuchFile:
1815
1826
                return False
1816
1827
            return True
1887
1898
        return self._last_revision_info_cache
1888
1899
 
1889
1900
    def _last_revision_info(self):
1890
 
        revision_string = self.control_files.get('last-revision').read()
 
1901
        revision_string = self._transport.get_bytes('last-revision')
1891
1902
        revno, revision_id = revision_string.rstrip('\n').split(' ', 1)
1892
1903
        revision_id = cache_utf8.get_cached_utf8(revision_id)
1893
1904
        revno = int(revno)
1904
1915
        """
1905
1916
        revision_id = _mod_revision.ensure_null(revision_id)
1906
1917
        out_string = '%d %s\n' % (revno, revision_id)
1907
 
        self.control_files.put_bytes('last-revision', out_string)
 
1918
        self._transport.put_bytes('last-revision', out_string,
 
1919
            mode=self.bzrdir._get_file_mode())
1908
1920
 
1909
1921
    @needs_write_lock
1910
1922
    def set_last_revision_info(self, revno, revision_id):
2133
2145
    :ivar old_revid: Tip revision id before pull.
2134
2146
    :ivar new_revid: Tip revision id after pull.
2135
2147
    :ivar source_branch: Source (local) branch object.
2136
 
    :ivar master_branch: Master branch of the target, or None.
 
2148
    :ivar master_branch: Master branch of the target, or the target if no
 
2149
        Master
 
2150
    :ivar local_branch: target branch if there is a Master, else None
2137
2151
    :ivar target_branch: Target/destination branch object.
 
2152
    :ivar tag_conflicts: A list of tag conflicts, see BasicTags.merge_to
2138
2153
    """
2139
2154
 
2140
2155
    def __int__(self):
2213
2228
        new_branch.tags._set_tag_dict({})
2214
2229
 
2215
2230
        # Copying done; now update target format
2216
 
        new_branch.control_files.put_utf8('format',
2217
 
            format.get_format_string())
 
2231
        new_branch._transport.put_bytes('format',
 
2232
            format.get_format_string(),
 
2233
            mode=new_branch.bzrdir._get_file_mode())
2218
2234
 
2219
2235
        # Clean up old files
2220
 
        new_branch.control_files._transport.delete('revision-history')
 
2236
        new_branch._transport.delete('revision-history')
2221
2237
        try:
2222
2238
            branch.set_parent(None)
2223
2239
        except errors.NoSuchFile: