~bzr-pqm/bzr/bzr.dev

« back to all changes in this revision

Viewing changes to bzrlib/bzrdir.py

  • Committer: Robert Collins
  • Date: 2006-09-25 00:03:15 UTC
  • mto: This revision was merged to the branch mainline in revision 2038.
  • Revision ID: robertc@robertcollins.net-20060925000315-d096352885e1b2ec
(Robert Collins) bzr 0.11rc1 has branch, bump bzr.dev version to 0.12

Show diffs side-by-side

added added

removed removed

Lines of Context:
1
1
# Copyright (C) 2005, 2006 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
5
5
# the Free Software Foundation; either version 2 of the License, or
6
6
# (at your option) any later version.
7
 
 
 
7
#
8
8
# This program is distributed in the hope that it will be useful,
9
9
# but WITHOUT ANY WARRANTY; without even the implied warranty of
10
10
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
11
11
# GNU General Public License for more details.
12
 
 
 
12
#
13
13
# You should have received a copy of the GNU General Public License
14
14
# along with this program; if not, write to the Free Software
15
15
# Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
22
22
 
23
23
# TODO: remove unittest dependency; put that stuff inside the test suite
24
24
 
 
25
# TODO: The Format probe_transport seems a bit redundant with just trying to
 
26
# open the bzrdir. -- mbp
 
27
#
 
28
# TODO: Can we move specific formats into separate modules to make this file
 
29
# smaller?
 
30
 
25
31
from copy import deepcopy
26
32
from cStringIO import StringIO
27
33
import os
39
45
                            sha_strings,
40
46
                            sha_string,
41
47
                            )
 
48
import bzrlib.revision
42
49
from bzrlib.store.revision.text import TextRevisionStore
43
50
from bzrlib.store.text import TextStore
44
51
from bzrlib.store.versioned import WeaveStore
86
93
        """Return true if this bzrdir is one whose format we can convert from."""
87
94
        return True
88
95
 
 
96
    def check_conversion_target(self, target_format):
 
97
        target_repo_format = target_format.repository_format
 
98
        source_repo_format = self._format.repository_format
 
99
        source_repo_format.check_conversion_target(target_repo_format)
 
100
 
89
101
    @staticmethod
90
102
    def _check_supported(format, allow_unsupported):
91
103
        """Check whether format is a supported format.
292
304
        This will use the current default BzrDirFormat, and use whatever 
293
305
        repository format that that uses for bzrdirformat.create_repository.
294
306
 
295
 
        ;param shared: Create a shared repository rather than a standalone
 
307
        :param shared: Create a shared repository rather than a standalone
296
308
                       repository.
297
309
        The Repository object is returned.
298
310
 
313
325
        repository format that that uses for bzrdirformat.create_workingtree,
314
326
        create_branch and create_repository.
315
327
 
316
 
        The WorkingTree object is returned.
 
328
        :return: The WorkingTree object.
317
329
        """
318
330
        t = get_transport(safe_unicode(base))
319
331
        if not isinstance(t, LocalTransport):
460
472
        _unsupported is a private parameter to the BzrDir class.
461
473
        """
462
474
        t = get_transport(base)
463
 
        mutter("trying to open %r with transport %r", base, t)
464
 
        format = BzrDirFormat.find_format(t)
 
475
        return BzrDir.open_from_transport(t, _unsupported=_unsupported)
 
476
 
 
477
    @staticmethod
 
478
    def open_from_transport(transport, _unsupported=False):
 
479
        """Open a bzrdir within a particular directory.
 
480
 
 
481
        :param transport: Transport containing the bzrdir.
 
482
        :param _unsupported: private.
 
483
        """
 
484
        format = BzrDirFormat.find_format(transport)
465
485
        BzrDir._check_supported(format, _unsupported)
466
 
        return format.open(t, _found=True)
 
486
        return format.open(transport, _found=True)
467
487
 
468
488
    def open_branch(self, unsupported=False):
469
489
        """Open the branch object at this BzrDir if one is present.
503
523
        url = a_transport.base
504
524
        while True:
505
525
            try:
506
 
                format = BzrDirFormat.find_format(a_transport)
507
 
                BzrDir._check_supported(format, False)
508
 
                return format.open(a_transport), urlutils.unescape(a_transport.relpath(url))
 
526
                result = BzrDir.open_from_transport(a_transport)
 
527
                return result, urlutils.unescape(a_transport.relpath(url))
509
528
            except errors.NotBranchError, e:
510
 
                ## mutter('not a branch in: %r %s', a_transport.base, e)
511
529
                pass
512
530
            new_t = a_transport.clone('..')
513
531
            if new_t.base == a_transport.base:
563
581
        except errors.NoWorkingTree:
564
582
            return False
565
583
 
 
584
    def cloning_metadir(self, basis=None):
 
585
        """Produce a metadir suitable for cloning with"""
 
586
        def related_repository(bzrdir):
 
587
            try:
 
588
                branch = bzrdir.open_branch()
 
589
                return branch.repository
 
590
            except errors.NotBranchError:
 
591
                source_branch = None
 
592
                return bzrdir.open_repository()
 
593
        result_format = self._format.__class__()
 
594
        try:
 
595
            try:
 
596
                source_repository = related_repository(self)
 
597
            except errors.NoRepositoryPresent:
 
598
                if basis is None:
 
599
                    raise
 
600
                source_repository = related_repository(self)
 
601
            result_format.repository_format = source_repository._format
 
602
        except errors.NoRepositoryPresent:
 
603
            pass
 
604
        return result_format
 
605
 
566
606
    def sprout(self, url, revision_id=None, basis=None, force_new_repo=False):
567
607
        """Create a copy of this bzrdir prepared for use as a new line of
568
608
        development.
578
618
            itself to download less data.
579
619
        """
580
620
        self._make_tail(url)
581
 
        result = self._format.initialize(url)
 
621
        cloning_format = self.cloning_metadir(basis)
 
622
        result = cloning_format.initialize(url)
582
623
        basis_repo, basis_branch, basis_tree = self._get_basis_components(basis)
583
624
        try:
584
625
            source_branch = self.open_branch()
615
656
                # XXX FIXME RBC 20060214 need tests for this when the basis
616
657
                # is incomplete
617
658
                result_repo.fetch(basis_repo, revision_id=revision_id)
618
 
            result_repo.fetch(source_repository, revision_id=revision_id)
 
659
            if source_repository is not None:
 
660
                result_repo.fetch(source_repository, revision_id=revision_id)
619
661
        if source_branch is not None:
620
662
            source_branch.sprout(result, revision_id=revision_id)
621
663
        else:
685
727
        # done on this format anyway. So - acceptable wart.
686
728
        result = self.open_workingtree()
687
729
        if revision_id is not None:
688
 
            result.set_last_revision(revision_id)
 
730
            if revision_id == bzrlib.revision.NULL_REVISION:
 
731
                result.set_parent_ids([])
 
732
            else:
 
733
                result.set_parent_ids([revision_id])
689
734
        return result
690
735
 
691
736
    def get_branch_transport(self, branch_format):
733
778
        self._check_supported(format, unsupported)
734
779
        return format.open(self, _found=True)
735
780
 
736
 
    def sprout(self, url, revision_id=None, basis=None):
 
781
    def sprout(self, url, revision_id=None, basis=None, force_new_repo=False):
737
782
        """See BzrDir.sprout()."""
738
783
        from bzrlib.workingtree import WorkingTreeFormat2
739
784
        self._make_tail(url)
1052
1097
        """
1053
1098
        return True
1054
1099
 
 
1100
    def same_model(self, target_format):
 
1101
        return (self.repository_format.rich_root_data == 
 
1102
            target_format.rich_root_data)
 
1103
 
1055
1104
    @classmethod
1056
1105
    def known_formats(klass):
1057
1106
        """Return all the known formats.
1173
1222
    def __return_repository_format(self):
1174
1223
        """Circular import protection."""
1175
1224
        from bzrlib.repository import RepositoryFormat4
1176
 
        return RepositoryFormat4(self)
 
1225
        return RepositoryFormat4()
1177
1226
    repository_format = property(__return_repository_format)
1178
1227
 
1179
1228
 
1217
1266
        result = (super(BzrDirFormat5, self).initialize_on_transport(transport))
1218
1267
        RepositoryFormat5().initialize(result, _internal=True)
1219
1268
        if not _cloning:
1220
 
            BzrBranchFormat4().initialize(result)
1221
 
            WorkingTreeFormat2().initialize(result)
 
1269
            branch = BzrBranchFormat4().initialize(result)
 
1270
            try:
 
1271
                WorkingTreeFormat2().initialize(result)
 
1272
            except errors.NotLocalUrl:
 
1273
                # Even though we can't access the working tree, we need to
 
1274
                # create its control files.
 
1275
                WorkingTreeFormat2().stub_initialize_remote(branch.control_files)
1222
1276
        return result
1223
1277
 
1224
1278
    def _open(self, transport):
1228
1282
    def __return_repository_format(self):
1229
1283
        """Circular import protection."""
1230
1284
        from bzrlib.repository import RepositoryFormat5
1231
 
        return RepositoryFormat5(self)
 
1285
        return RepositoryFormat5()
1232
1286
    repository_format = property(__return_repository_format)
1233
1287
 
1234
1288
 
1271
1325
        result = super(BzrDirFormat6, self).initialize_on_transport(transport)
1272
1326
        RepositoryFormat6().initialize(result, _internal=True)
1273
1327
        if not _cloning:
1274
 
            BzrBranchFormat4().initialize(result)
 
1328
            branch = BzrBranchFormat4().initialize(result)
1275
1329
            try:
1276
1330
                WorkingTreeFormat2().initialize(result)
1277
1331
            except errors.NotLocalUrl:
1278
 
                # emulate pre-check behaviour for working tree and silently 
1279
 
                # fail.
1280
 
                pass
 
1332
                # Even though we can't access the working tree, we need to
 
1333
                # create its control files.
 
1334
                WorkingTreeFormat2().stub_initialize_remote(branch.control_files)
1281
1335
        return result
1282
1336
 
1283
1337
    def _open(self, transport):
1287
1341
    def __return_repository_format(self):
1288
1342
        """Circular import protection."""
1289
1343
        from bzrlib.repository import RepositoryFormat6
1290
 
        return RepositoryFormat6(self)
 
1344
        return RepositoryFormat6()
1291
1345
    repository_format = property(__return_repository_format)
1292
1346
 
1293
1347
 
1469
1523
        inv = serializer_v4.read_inventory(self.branch.control_files.get('inventory'))
1470
1524
        new_inv_xml = bzrlib.xml5.serializer_v5.write_inventory_to_string(inv)
1471
1525
        # FIXME inventory is a working tree change.
1472
 
        self.branch.control_files.put('inventory', new_inv_xml)
 
1526
        self.branch.control_files.put('inventory', StringIO(new_inv_xml))
1473
1527
 
1474
1528
    def _write_all_weaves(self):
1475
1529
        controlweaves = WeaveStore(self.bzrdir.transport, prefixed=False)
1532
1586
        assert rev_id not in self.converted_revs
1533
1587
        old_inv_xml = self.branch.repository.inventory_store.get(rev_id).read()
1534
1588
        inv = serializer_v4.read_inventory_from_string(old_inv_xml)
 
1589
        inv.revision_id = rev_id
1535
1590
        rev = self.revisions[rev_id]
1536
1591
        if rev.inventory_sha1:
1537
1592
            assert rev.inventory_sha1 == sha_string(old_inv_xml), \
1557
1612
    def _store_new_weave(self, rev, inv, present_parents):
1558
1613
        # the XML is now updated with text versions
1559
1614
        if __debug__:
1560
 
            for file_id in inv:
1561
 
                ie = inv[file_id]
1562
 
                if ie.kind == 'root_directory':
1563
 
                    continue
1564
 
                assert hasattr(ie, 'revision'), \
 
1615
            entries = inv.iter_entries()
 
1616
            entries.next()
 
1617
            for path, ie in entries:
 
1618
                assert getattr(ie, 'revision', None) is not None, \
1565
1619
                    'no revision on {%s} in {%s}' % \
1566
1620
                    (file_id, rev.revision_id)
1567
1621
        new_inv_xml = bzrlib.xml5.serializer_v5.write_inventory_to_string(inv)
1579
1633
        mutter('converting texts of revision {%s}',
1580
1634
               rev_id)
1581
1635
        parent_invs = map(self._load_updated_inventory, present_parents)
1582
 
        for file_id in inv:
1583
 
            ie = inv[file_id]
 
1636
        entries = inv.iter_entries()
 
1637
        entries.next()
 
1638
        for path, ie in entries:
1584
1639
            self._convert_file_version(rev, ie, parent_invs)
1585
1640
 
1586
1641
    def _convert_file_version(self, rev, ie, parent_invs):
1589
1644
        The file needs to be added into the weave if it is a merge
1590
1645
        of >=2 parents or if it's changed from its parent.
1591
1646
        """
1592
 
        if ie.kind == 'root_directory':
1593
 
            return
1594
1647
        file_id = ie.file_id
1595
1648
        rev_id = rev.revision_id
1596
1649
        w = self.text_weaves.get(file_id)
1745
1798
        for entry in branch_files:
1746
1799
            self.move_entry('branch', entry)
1747
1800
 
1748
 
        self.step('Upgrading working tree')
1749
 
        self.bzrdir.transport.mkdir('checkout', mode=self.dir_mode)
1750
 
        self.make_lock('checkout')
1751
 
        self.put_format('checkout', bzrlib.workingtree.WorkingTreeFormat3())
1752
 
        self.bzrdir.transport.delete_multi(self.garbage_inventories, self.pb)
1753
1801
        checkout_files = [('pending-merges', True),
1754
1802
                          ('inventory', True),
1755
1803
                          ('stat-cache', False)]
1756
 
        for entry in checkout_files:
1757
 
            self.move_entry('checkout', entry)
1758
 
        if last_revision is not None:
1759
 
            self.bzrdir._control_files.put_utf8('checkout/last-revision',
1760
 
                                                last_revision)
1761
 
        self.bzrdir._control_files.put_utf8('branch-format', BzrDirMetaFormat1().get_format_string())
 
1804
        # If a mandatory checkout file is not present, the branch does not have
 
1805
        # a functional checkout. Do not create a checkout in the converted
 
1806
        # branch.
 
1807
        for name, mandatory in checkout_files:
 
1808
            if mandatory and name not in bzrcontents:
 
1809
                has_checkout = False
 
1810
                break
 
1811
        else:
 
1812
            has_checkout = True
 
1813
        if not has_checkout:
 
1814
            self.pb.note('No working tree.')
 
1815
            # If some checkout files are there, we may as well get rid of them.
 
1816
            for name, mandatory in checkout_files:
 
1817
                if name in bzrcontents:
 
1818
                    self.bzrdir.transport.delete(name)
 
1819
        else:
 
1820
            self.step('Upgrading working tree')
 
1821
            self.bzrdir.transport.mkdir('checkout', mode=self.dir_mode)
 
1822
            self.make_lock('checkout')
 
1823
            self.put_format(
 
1824
                'checkout', bzrlib.workingtree.WorkingTreeFormat3())
 
1825
            self.bzrdir.transport.delete_multi(
 
1826
                self.garbage_inventories, self.pb)
 
1827
            for entry in checkout_files:
 
1828
                self.move_entry('checkout', entry)
 
1829
            if last_revision is not None:
 
1830
                self.bzrdir._control_files.put_utf8(
 
1831
                    'checkout/last-revision', last_revision)
 
1832
        self.bzrdir._control_files.put_utf8(
 
1833
            'branch-format', BzrDirMetaFormat1().get_format_string())
1762
1834
        return BzrDir.open(self.bzrdir.root_transport.base)
1763
1835
 
1764
1836
    def make_lock(self, name):