~bzr-pqm/bzr/bzr.dev

« back to all changes in this revision

Viewing changes to bzrlib/bzrdir.py

  • Committer: wang
  • Date: 2006-10-29 13:41:32 UTC
  • mto: (2104.4.1 wang_65714)
  • mto: This revision was merged to the branch mainline in revision 2109.
  • Revision ID: wang@ubuntu-20061029134132-3d7f4216f20c4aef
Replace python's difflib by patiencediff because the worst case 
performance is cubic for difflib and people commiting large data 
files are often hurt by this. The worst case performance of patience is 
quadratic. Fix bug 65714.

Show diffs side-by-side

added added

removed removed

Lines of Context:
22
22
 
23
23
# TODO: remove unittest dependency; put that stuff inside the test suite
24
24
 
25
 
from copy import deepcopy
 
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
 
26
31
from cStringIO import StringIO
27
32
import os
 
33
 
 
34
from bzrlib.lazy_import import lazy_import
 
35
lazy_import(globals(), """
 
36
from copy import deepcopy
28
37
from stat import S_ISDIR
29
 
from unittest import TestSuite
 
38
import unittest
30
39
 
31
40
import bzrlib
32
 
import bzrlib.errors as errors
33
 
from bzrlib.lockable_files import LockableFiles, TransportLock
34
 
from bzrlib.lockdir import LockDir
 
41
from bzrlib import (
 
42
    errors,
 
43
    lockable_files,
 
44
    lockdir,
 
45
    revision as _mod_revision,
 
46
    urlutils,
 
47
    xml4,
 
48
    xml5,
 
49
    )
35
50
from bzrlib.osutils import (
36
 
                            abspath,
37
 
                            pathjoin,
38
 
                            safe_unicode,
39
 
                            sha_strings,
40
 
                            sha_string,
41
 
                            )
 
51
    safe_unicode,
 
52
    sha_strings,
 
53
    sha_string,
 
54
    )
42
55
from bzrlib.store.revision.text import TextRevisionStore
43
56
from bzrlib.store.text import TextStore
44
57
from bzrlib.store.versioned import WeaveStore
45
 
from bzrlib.trace import mutter
46
58
from bzrlib.transactions import WriteTransaction
47
59
from bzrlib.transport import get_transport
 
60
from bzrlib.weave import Weave
 
61
""")
 
62
 
 
63
from bzrlib.trace import mutter
48
64
from bzrlib.transport.local import LocalTransport
49
 
import bzrlib.urlutils as urlutils
50
 
from bzrlib.weave import Weave
51
 
from bzrlib.xml4 import serializer_v4
52
 
import bzrlib.xml5
53
65
 
54
66
 
55
67
class BzrDir(object):
86
98
        """Return true if this bzrdir is one whose format we can convert from."""
87
99
        return True
88
100
 
 
101
    def check_conversion_target(self, target_format):
 
102
        target_repo_format = target_format.repository_format
 
103
        source_repo_format = self._format.repository_format
 
104
        source_repo_format.check_conversion_target(target_repo_format)
 
105
 
89
106
    @staticmethod
90
107
    def _check_supported(format, allow_unsupported):
91
108
        """Check whether format is a supported format.
176
193
    def _make_tail(self, url):
177
194
        head, tail = urlutils.split(url)
178
195
        if tail and tail != '.':
179
 
            t = bzrlib.transport.get_transport(head)
 
196
            t = get_transport(head)
180
197
            try:
181
198
                t.mkdir(tail)
182
199
            except errors.FileExists:
198
215
                    "not one of %r" % cls)
199
216
        head, tail = urlutils.split(base)
200
217
        if tail and tail != '.':
201
 
            t = bzrlib.transport.get_transport(head)
 
218
            t = get_transport(head)
202
219
            try:
203
220
                t.mkdir(tail)
204
221
            except errors.FileExists:
292
309
        This will use the current default BzrDirFormat, and use whatever 
293
310
        repository format that that uses for bzrdirformat.create_repository.
294
311
 
295
 
        ;param shared: Create a shared repository rather than a standalone
 
312
        :param shared: Create a shared repository rather than a standalone
296
313
                       repository.
297
314
        The Repository object is returned.
298
315
 
313
330
        repository format that that uses for bzrdirformat.create_workingtree,
314
331
        create_branch and create_repository.
315
332
 
316
 
        The WorkingTree object is returned.
 
333
        :return: The WorkingTree object.
317
334
        """
318
335
        t = get_transport(safe_unicode(base))
319
336
        if not isinstance(t, LocalTransport):
329
346
        """
330
347
        raise NotImplementedError(self.create_workingtree)
331
348
 
 
349
    def destroy_workingtree(self):
 
350
        """Destroy the working tree at this BzrDir.
 
351
 
 
352
        Formats that do not support this may raise UnsupportedOperation.
 
353
        """
 
354
        raise NotImplementedError(self.destroy_workingtree)
 
355
 
 
356
    def destroy_workingtree_metadata(self):
 
357
        """Destroy the control files for the working tree at this BzrDir.
 
358
 
 
359
        The contents of working tree files are not affected.
 
360
        Formats that do not support this may raise UnsupportedOperation.
 
361
        """
 
362
        raise NotImplementedError(self.destroy_workingtree_metadata)
 
363
 
332
364
    def find_repository(self):
333
365
        """Find the repository that should be used for a_bzrdir.
334
366
 
460
492
        _unsupported is a private parameter to the BzrDir class.
461
493
        """
462
494
        t = get_transport(base)
463
 
        mutter("trying to open %r with transport %r", base, t)
464
 
        format = BzrDirFormat.find_format(t)
 
495
        return BzrDir.open_from_transport(t, _unsupported=_unsupported)
 
496
 
 
497
    @staticmethod
 
498
    def open_from_transport(transport, _unsupported=False):
 
499
        """Open a bzrdir within a particular directory.
 
500
 
 
501
        :param transport: Transport containing the bzrdir.
 
502
        :param _unsupported: private.
 
503
        """
 
504
        format = BzrDirFormat.find_format(transport)
465
505
        BzrDir._check_supported(format, _unsupported)
466
 
        return format.open(t, _found=True)
 
506
        return format.open(transport, _found=True)
467
507
 
468
508
    def open_branch(self, unsupported=False):
469
509
        """Open the branch object at this BzrDir if one is present.
503
543
        url = a_transport.base
504
544
        while True:
505
545
            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))
 
546
                result = BzrDir.open_from_transport(a_transport)
 
547
                return result, urlutils.unescape(a_transport.relpath(url))
509
548
            except errors.NotBranchError, e:
510
 
                ## mutter('not a branch in: %r %s', a_transport.base, e)
511
549
                pass
512
550
            new_t = a_transport.clone('..')
513
551
            if new_t.base == a_transport.base:
563
601
        except errors.NoWorkingTree:
564
602
            return False
565
603
 
 
604
    def cloning_metadir(self, basis=None):
 
605
        """Produce a metadir suitable for cloning with"""
 
606
        def related_repository(bzrdir):
 
607
            try:
 
608
                branch = bzrdir.open_branch()
 
609
                return branch.repository
 
610
            except errors.NotBranchError:
 
611
                source_branch = None
 
612
                return bzrdir.open_repository()
 
613
        result_format = self._format.__class__()
 
614
        try:
 
615
            try:
 
616
                source_repository = related_repository(self)
 
617
            except errors.NoRepositoryPresent:
 
618
                if basis is None:
 
619
                    raise
 
620
                source_repository = related_repository(self)
 
621
            result_format.repository_format = source_repository._format
 
622
        except errors.NoRepositoryPresent:
 
623
            pass
 
624
        return result_format
 
625
 
566
626
    def sprout(self, url, revision_id=None, basis=None, force_new_repo=False):
567
627
        """Create a copy of this bzrdir prepared for use as a new line of
568
628
        development.
578
638
            itself to download less data.
579
639
        """
580
640
        self._make_tail(url)
581
 
        result = self._format.initialize(url)
 
641
        cloning_format = self.cloning_metadir(basis)
 
642
        result = cloning_format.initialize(url)
582
643
        basis_repo, basis_branch, basis_tree = self._get_basis_components(basis)
583
644
        try:
584
645
            source_branch = self.open_branch()
615
676
                # XXX FIXME RBC 20060214 need tests for this when the basis
616
677
                # is incomplete
617
678
                result_repo.fetch(basis_repo, revision_id=revision_id)
618
 
            result_repo.fetch(source_repository, revision_id=revision_id)
 
679
            if source_repository is not None:
 
680
                result_repo.fetch(source_repository, revision_id=revision_id)
619
681
        if source_branch is not None:
620
682
            source_branch.sprout(result, revision_id=revision_id)
621
683
        else:
623
685
        # TODO: jam 20060426 we probably need a test in here in the
624
686
        #       case that the newly sprouted branch is a remote one
625
687
        if result_repo is None or result_repo.make_working_trees():
626
 
            result.create_workingtree()
 
688
            wt = result.create_workingtree()
 
689
            if wt.inventory.root is None:
 
690
                try:
 
691
                    wt.set_root_id(self.open_workingtree.get_root_id())
 
692
                except errors.NoWorkingTree:
 
693
                    pass
627
694
        return result
628
695
 
629
696
 
633
700
    def __init__(self, _transport, _format):
634
701
        """See BzrDir.__init__."""
635
702
        super(BzrDirPreSplitOut, self).__init__(_transport, _format)
636
 
        assert self._format._lock_class == TransportLock
 
703
        assert self._format._lock_class == lockable_files.TransportLock
637
704
        assert self._format._lock_file_name == 'branch-lock'
638
 
        self._control_files = LockableFiles(self.get_branch_transport(None),
 
705
        self._control_files = lockable_files.LockableFiles(
 
706
                                            self.get_branch_transport(None),
639
707
                                            self._format._lock_file_name,
640
708
                                            self._format._lock_class)
641
709
 
685
753
        # done on this format anyway. So - acceptable wart.
686
754
        result = self.open_workingtree()
687
755
        if revision_id is not None:
688
 
            result.set_last_revision(revision_id)
 
756
            if revision_id == _mod_revision.NULL_REVISION:
 
757
                result.set_parent_ids([])
 
758
            else:
 
759
                result.set_parent_ids([revision_id])
689
760
        return result
690
761
 
 
762
    def destroy_workingtree(self):
 
763
        """See BzrDir.destroy_workingtree."""
 
764
        raise errors.UnsupportedOperation(self.destroy_workingtree, self)
 
765
 
 
766
    def destroy_workingtree_metadata(self):
 
767
        """See BzrDir.destroy_workingtree_metadata."""
 
768
        raise errors.UnsupportedOperation(self.destroy_workingtree_metadata, 
 
769
                                          self)
 
770
 
691
771
    def get_branch_transport(self, branch_format):
692
772
        """See BzrDir.get_branch_transport()."""
693
773
        if branch_format is None:
733
813
        self._check_supported(format, unsupported)
734
814
        return format.open(self, _found=True)
735
815
 
736
 
    def sprout(self, url, revision_id=None, basis=None):
 
816
    def sprout(self, url, revision_id=None, basis=None, force_new_repo=False):
737
817
        """See BzrDir.sprout()."""
738
818
        from bzrlib.workingtree import WorkingTreeFormat2
739
819
        self._make_tail(url)
833
913
        from bzrlib.workingtree import WorkingTreeFormat
834
914
        return WorkingTreeFormat.get_default_format().initialize(self, revision_id)
835
915
 
 
916
    def destroy_workingtree(self):
 
917
        """See BzrDir.destroy_workingtree."""
 
918
        wt = self.open_workingtree()
 
919
        repository = wt.branch.repository
 
920
        empty = repository.revision_tree(bzrlib.revision.NULL_REVISION)
 
921
        wt.revert([], old_tree=empty)
 
922
        self.destroy_workingtree_metadata()
 
923
 
 
924
    def destroy_workingtree_metadata(self):
 
925
        self.transport.delete_tree('checkout')
 
926
 
836
927
    def _get_mkdir_mode(self):
837
928
        """Figure out the mode to use when creating a bzrdir subdir."""
838
 
        temp_control = LockableFiles(self.transport, '', TransportLock)
 
929
        temp_control = lockable_files.LockableFiles(self.transport, '',
 
930
                                     lockable_files.TransportLock)
839
931
        return temp_control._dir_mode
840
932
 
841
933
    def get_branch_transport(self, branch_format):
1017
1109
        """Initialize a new bzrdir in the base directory of a Transport."""
1018
1110
        # Since we don't have a .bzr directory, inherit the
1019
1111
        # mode from the root directory
1020
 
        temp_control = LockableFiles(transport, '', TransportLock)
 
1112
        temp_control = lockable_files.LockableFiles(transport,
 
1113
                            '', lockable_files.TransportLock)
1021
1114
        temp_control._transport.mkdir('.bzr',
1022
1115
                                      # FIXME: RBC 20060121 don't peek under
1023
1116
                                      # the covers
1032
1125
                      ('branch-format', self.get_format_string()),
1033
1126
                      ]
1034
1127
        # NB: no need to escape relative paths that are url safe.
1035
 
        control_files = LockableFiles(control, self._lock_file_name, 
1036
 
                                      self._lock_class)
 
1128
        control_files = lockable_files.LockableFiles(control,
 
1129
                            self._lock_file_name, self._lock_class)
1037
1130
        control_files.create_lock()
1038
1131
        control_files.lock_write()
1039
1132
        try:
1052
1145
        """
1053
1146
        return True
1054
1147
 
 
1148
    def same_model(self, target_format):
 
1149
        return (self.repository_format.rich_root_data == 
 
1150
            target_format.rich_root_data)
 
1151
 
1055
1152
    @classmethod
1056
1153
    def known_formats(klass):
1057
1154
        """Return all the known formats.
1138
1235
    removed in format 5; write support for this format has been removed.
1139
1236
    """
1140
1237
 
1141
 
    _lock_class = TransportLock
 
1238
    _lock_class = lockable_files.TransportLock
1142
1239
 
1143
1240
    def get_format_string(self):
1144
1241
        """See BzrDirFormat.get_format_string()."""
1173
1270
    def __return_repository_format(self):
1174
1271
        """Circular import protection."""
1175
1272
        from bzrlib.repository import RepositoryFormat4
1176
 
        return RepositoryFormat4(self)
 
1273
        return RepositoryFormat4()
1177
1274
    repository_format = property(__return_repository_format)
1178
1275
 
1179
1276
 
1188
1285
       Unhashed stores in the repository.
1189
1286
    """
1190
1287
 
1191
 
    _lock_class = TransportLock
 
1288
    _lock_class = lockable_files.TransportLock
1192
1289
 
1193
1290
    def get_format_string(self):
1194
1291
        """See BzrDirFormat.get_format_string()."""
1217
1314
        result = (super(BzrDirFormat5, self).initialize_on_transport(transport))
1218
1315
        RepositoryFormat5().initialize(result, _internal=True)
1219
1316
        if not _cloning:
1220
 
            BzrBranchFormat4().initialize(result)
1221
 
            WorkingTreeFormat2().initialize(result)
 
1317
            branch = BzrBranchFormat4().initialize(result)
 
1318
            try:
 
1319
                WorkingTreeFormat2().initialize(result)
 
1320
            except errors.NotLocalUrl:
 
1321
                # Even though we can't access the working tree, we need to
 
1322
                # create its control files.
 
1323
                WorkingTreeFormat2().stub_initialize_remote(branch.control_files)
1222
1324
        return result
1223
1325
 
1224
1326
    def _open(self, transport):
1228
1330
    def __return_repository_format(self):
1229
1331
        """Circular import protection."""
1230
1332
        from bzrlib.repository import RepositoryFormat5
1231
 
        return RepositoryFormat5(self)
 
1333
        return RepositoryFormat5()
1232
1334
    repository_format = property(__return_repository_format)
1233
1335
 
1234
1336
 
1242
1344
     - Format 6 repositories [always]
1243
1345
    """
1244
1346
 
1245
 
    _lock_class = TransportLock
 
1347
    _lock_class = lockable_files.TransportLock
1246
1348
 
1247
1349
    def get_format_string(self):
1248
1350
        """See BzrDirFormat.get_format_string()."""
1271
1373
        result = super(BzrDirFormat6, self).initialize_on_transport(transport)
1272
1374
        RepositoryFormat6().initialize(result, _internal=True)
1273
1375
        if not _cloning:
1274
 
            BzrBranchFormat4().initialize(result)
 
1376
            branch = BzrBranchFormat4().initialize(result)
1275
1377
            try:
1276
1378
                WorkingTreeFormat2().initialize(result)
1277
1379
            except errors.NotLocalUrl:
1278
 
                # emulate pre-check behaviour for working tree and silently 
1279
 
                # fail.
1280
 
                pass
 
1380
                # Even though we can't access the working tree, we need to
 
1381
                # create its control files.
 
1382
                WorkingTreeFormat2().stub_initialize_remote(branch.control_files)
1281
1383
        return result
1282
1384
 
1283
1385
    def _open(self, transport):
1287
1389
    def __return_repository_format(self):
1288
1390
        """Circular import protection."""
1289
1391
        from bzrlib.repository import RepositoryFormat6
1290
 
        return RepositoryFormat6(self)
 
1392
        return RepositoryFormat6()
1291
1393
    repository_format = property(__return_repository_format)
1292
1394
 
1293
1395
 
1302
1404
     - Format 7 repositories [optional]
1303
1405
    """
1304
1406
 
1305
 
    _lock_class = LockDir
 
1407
    _lock_class = lockdir.LockDir
1306
1408
 
1307
1409
    def get_converter(self, format=None):
1308
1410
        """See BzrDirFormat.get_converter()."""
1362
1464
        self._formats = formats
1363
1465
    
1364
1466
    def adapt(self, test):
1365
 
        result = TestSuite()
 
1467
        result = unittest.TestSuite()
1366
1468
        for format in self._formats:
1367
1469
            new_test = deepcopy(test)
1368
1470
            new_test.transport_server = self._transport_server
1466
1568
        self.bzrdir.transport.delete_tree('text-store')
1467
1569
 
1468
1570
    def _convert_working_inv(self):
1469
 
        inv = serializer_v4.read_inventory(self.branch.control_files.get('inventory'))
1470
 
        new_inv_xml = bzrlib.xml5.serializer_v5.write_inventory_to_string(inv)
 
1571
        inv = xml4.serializer_v4.read_inventory(
 
1572
                    self.branch.control_files.get('inventory'))
 
1573
        new_inv_xml = xml5.serializer_v5.write_inventory_to_string(inv)
1471
1574
        # FIXME inventory is a working tree change.
1472
 
        self.branch.control_files.put('inventory', new_inv_xml)
 
1575
        self.branch.control_files.put('inventory', StringIO(new_inv_xml))
1473
1576
 
1474
1577
    def _write_all_weaves(self):
1475
1578
        controlweaves = WeaveStore(self.bzrdir.transport, prefixed=False)
1499
1602
                                                      prefixed=False,
1500
1603
                                                      compressed=True))
1501
1604
        try:
1502
 
            transaction = bzrlib.transactions.WriteTransaction()
 
1605
            transaction = WriteTransaction()
1503
1606
            for i, rev_id in enumerate(self.converted_revs):
1504
1607
                self.pb.update('write revision', i, len(self.converted_revs))
1505
1608
                _revision_store.add_revision(self.revisions[rev_id], transaction)
1531
1634
    def _load_old_inventory(self, rev_id):
1532
1635
        assert rev_id not in self.converted_revs
1533
1636
        old_inv_xml = self.branch.repository.inventory_store.get(rev_id).read()
1534
 
        inv = serializer_v4.read_inventory_from_string(old_inv_xml)
 
1637
        inv = xml4.serializer_v4.read_inventory_from_string(old_inv_xml)
 
1638
        inv.revision_id = rev_id
1535
1639
        rev = self.revisions[rev_id]
1536
1640
        if rev.inventory_sha1:
1537
1641
            assert rev.inventory_sha1 == sha_string(old_inv_xml), \
1541
1645
    def _load_updated_inventory(self, rev_id):
1542
1646
        assert rev_id in self.converted_revs
1543
1647
        inv_xml = self.inv_weave.get_text(rev_id)
1544
 
        inv = bzrlib.xml5.serializer_v5.read_inventory_from_string(inv_xml)
 
1648
        inv = xml5.serializer_v5.read_inventory_from_string(inv_xml)
1545
1649
        return inv
1546
1650
 
1547
1651
    def _convert_one_rev(self, rev_id):
1560
1664
            entries = inv.iter_entries()
1561
1665
            entries.next()
1562
1666
            for path, ie in entries:
1563
 
                assert hasattr(ie, 'revision'), \
 
1667
                assert getattr(ie, 'revision', None) is not None, \
1564
1668
                    'no revision on {%s} in {%s}' % \
1565
1669
                    (file_id, rev.revision_id)
1566
 
        new_inv_xml = bzrlib.xml5.serializer_v5.write_inventory_to_string(inv)
 
1670
        new_inv_xml = xml5.serializer_v5.write_inventory_to_string(inv)
1567
1671
        new_inv_sha1 = sha_string(new_inv_xml)
1568
1672
        self.inv_weave.add_lines(rev.revision_id, 
1569
1673
                                 present_parents,
1602
1706
                                                  entry_vf=w)
1603
1707
        for old_revision in previous_entries:
1604
1708
                # if this fails, its a ghost ?
1605
 
                assert old_revision in self.converted_revs 
 
1709
                assert old_revision in self.converted_revs, \
 
1710
                    "Revision {%s} not in converted_revs" % old_revision
1606
1711
        self.snapshot_ie(previous_entries, ie, w, rev_id)
1607
1712
        del ie.text_id
1608
1713
        assert getattr(ie, 'revision', None) is not None
1743
1848
        for entry in branch_files:
1744
1849
            self.move_entry('branch', entry)
1745
1850
 
1746
 
        self.step('Upgrading working tree')
1747
 
        self.bzrdir.transport.mkdir('checkout', mode=self.dir_mode)
1748
 
        self.make_lock('checkout')
1749
 
        self.put_format('checkout', bzrlib.workingtree.WorkingTreeFormat3())
1750
 
        self.bzrdir.transport.delete_multi(self.garbage_inventories, self.pb)
1751
1851
        checkout_files = [('pending-merges', True),
1752
1852
                          ('inventory', True),
1753
1853
                          ('stat-cache', False)]
1754
 
        for entry in checkout_files:
1755
 
            self.move_entry('checkout', entry)
1756
 
        if last_revision is not None:
1757
 
            self.bzrdir._control_files.put_utf8('checkout/last-revision',
1758
 
                                                last_revision)
1759
 
        self.bzrdir._control_files.put_utf8('branch-format', BzrDirMetaFormat1().get_format_string())
 
1854
        # If a mandatory checkout file is not present, the branch does not have
 
1855
        # a functional checkout. Do not create a checkout in the converted
 
1856
        # branch.
 
1857
        for name, mandatory in checkout_files:
 
1858
            if mandatory and name not in bzrcontents:
 
1859
                has_checkout = False
 
1860
                break
 
1861
        else:
 
1862
            has_checkout = True
 
1863
        if not has_checkout:
 
1864
            self.pb.note('No working tree.')
 
1865
            # If some checkout files are there, we may as well get rid of them.
 
1866
            for name, mandatory in checkout_files:
 
1867
                if name in bzrcontents:
 
1868
                    self.bzrdir.transport.delete(name)
 
1869
        else:
 
1870
            self.step('Upgrading working tree')
 
1871
            self.bzrdir.transport.mkdir('checkout', mode=self.dir_mode)
 
1872
            self.make_lock('checkout')
 
1873
            self.put_format(
 
1874
                'checkout', bzrlib.workingtree.WorkingTreeFormat3())
 
1875
            self.bzrdir.transport.delete_multi(
 
1876
                self.garbage_inventories, self.pb)
 
1877
            for entry in checkout_files:
 
1878
                self.move_entry('checkout', entry)
 
1879
            if last_revision is not None:
 
1880
                self.bzrdir._control_files.put_utf8(
 
1881
                    'checkout/last-revision', last_revision)
 
1882
        self.bzrdir._control_files.put_utf8(
 
1883
            'branch-format', BzrDirMetaFormat1().get_format_string())
1760
1884
        return BzrDir.open(self.bzrdir.root_transport.base)
1761
1885
 
1762
1886
    def make_lock(self, name):
1763
1887
        """Make a lock for the new control dir name."""
1764
1888
        self.step('Make %s lock' % name)
1765
 
        ld = LockDir(self.bzrdir.transport, 
1766
 
                     '%s/lock' % name,
1767
 
                     file_modebits=self.file_mode,
1768
 
                     dir_modebits=self.dir_mode)
 
1889
        ld = lockdir.LockDir(self.bzrdir.transport,
 
1890
                             '%s/lock' % name,
 
1891
                             file_modebits=self.file_mode,
 
1892
                             dir_modebits=self.dir_mode)
1769
1893
        ld.create()
1770
1894
 
1771
1895
    def move_entry(self, new_dir, entry):