/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/workingtree.py

  • Committer: Robert Collins
  • Date: 2010-05-06 11:08:10 UTC
  • mto: This revision was merged to the branch mainline in revision 5223.
  • Revision ID: robertc@robertcollins.net-20100506110810-h3j07fh5gmw54s25
Cleaner matcher matching revised unlocking protocol.

Show diffs side-by-side

added added

removed removed

Lines of Context:
1
 
# Copyright (C) 2005-2011 Canonical Ltd
 
1
# Copyright (C) 2005-2010 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
49
49
    branch,
50
50
    bzrdir,
51
51
    conflicts as _mod_conflicts,
52
 
    controldir,
53
52
    errors,
54
53
    generate_ids,
55
54
    globbing,
62
61
    revisiontree,
63
62
    trace,
64
63
    transform,
65
 
    transport,
66
64
    ui,
67
65
    views,
68
66
    xml5,
69
67
    xml7,
70
68
    )
 
69
import bzrlib.branch
 
70
from bzrlib.transport import get_transport
71
71
from bzrlib.workingtree_4 import (
72
72
    WorkingTreeFormat4,
73
73
    WorkingTreeFormat5,
77
77
 
78
78
from bzrlib import symbol_versioning
79
79
from bzrlib.decorators import needs_read_lock, needs_write_lock
80
 
from bzrlib.lock import LogicalLockResult
81
80
from bzrlib.lockable_files import LockableFiles
82
81
from bzrlib.lockdir import LockDir
83
82
import bzrlib.mutabletree
169
168
 
170
169
 
171
170
class WorkingTree(bzrlib.mutabletree.MutableTree,
172
 
    controldir.ControlComponent):
 
171
    bzrdir.ControlComponent):
173
172
    """Working copy tree.
174
173
 
175
174
    The inventory is held in the `Branch` working-inventory, and the
177
176
 
178
177
    It is possible for a `WorkingTree` to have a filename which is
179
178
    not listed in the Inventory and vice versa.
180
 
 
181
 
    :ivar basedir: The root of the tree on disk. This is a unicode path object
182
 
        (as opposed to a URL).
183
179
    """
184
180
 
185
181
    # override this to set the strategy for storing views
209
205
        else:
210
206
            self._branch = self.bzrdir.open_branch()
211
207
        self.basedir = realpath(basedir)
212
 
        self._control_files = _control_files
 
208
        # if branch is at our basedir and is a format 6 or less
 
209
        if isinstance(self._format, WorkingTreeFormat2):
 
210
            # share control object
 
211
            self._control_files = self.branch.control_files
 
212
        else:
 
213
            # assume all other formats have their own control files.
 
214
            self._control_files = _control_files
213
215
        self._transport = self._control_files._transport
214
216
        # update the whole cache up front and write to disk if anything changed;
215
217
        # in the future we might want to do this more selectively
256
258
    def _detect_case_handling(self):
257
259
        wt_trans = self.bzrdir.get_workingtree_transport(None)
258
260
        try:
259
 
            wt_trans.stat(self._format.case_sensitive_filename)
 
261
            wt_trans.stat("FoRMaT")
260
262
        except errors.NoSuchFile:
261
263
            self.case_sensitive = True
262
264
        else:
344
346
        if path is None:
345
347
            path = osutils.getcwd()
346
348
        control, relpath = bzrdir.BzrDir.open_containing(path)
 
349
 
347
350
        return control.open_workingtree(), relpath
348
351
 
349
352
    @staticmethod
350
 
    def open_containing_paths(file_list, default_directory=None,
351
 
                              canonicalize=True, apply_view=True):
352
 
        """Open the WorkingTree that contains a set of paths.
353
 
 
354
 
        Fail if the paths given are not all in a single tree.
355
 
 
356
 
        This is used for the many command-line interfaces that take a list of
357
 
        any number of files and that require they all be in the same tree.
358
 
        """
359
 
        if default_directory is None:
360
 
            default_directory = u'.'
361
 
        # recommended replacement for builtins.internal_tree_files
362
 
        if file_list is None or len(file_list) == 0:
363
 
            tree = WorkingTree.open_containing(default_directory)[0]
364
 
            # XXX: doesn't really belong here, and seems to have the strange
365
 
            # side effect of making it return a bunch of files, not the whole
366
 
            # tree -- mbp 20100716
367
 
            if tree.supports_views() and apply_view:
368
 
                view_files = tree.views.lookup_view()
369
 
                if view_files:
370
 
                    file_list = view_files
371
 
                    view_str = views.view_display_str(view_files)
372
 
                    note("Ignoring files outside view. View is %s" % view_str)
373
 
            return tree, file_list
374
 
        if default_directory == u'.':
375
 
            seed = file_list[0]
376
 
        else:
377
 
            seed = default_directory
378
 
            file_list = [osutils.pathjoin(default_directory, f)
379
 
                         for f in file_list]
380
 
        tree = WorkingTree.open_containing(seed)[0]
381
 
        return tree, tree.safe_relpath_files(file_list, canonicalize,
382
 
                                             apply_view=apply_view)
383
 
 
384
 
    def safe_relpath_files(self, file_list, canonicalize=True, apply_view=True):
385
 
        """Convert file_list into a list of relpaths in tree.
386
 
 
387
 
        :param self: A tree to operate on.
388
 
        :param file_list: A list of user provided paths or None.
389
 
        :param apply_view: if True and a view is set, apply it or check that
390
 
            specified files are within it
391
 
        :return: A list of relative paths.
392
 
        :raises errors.PathNotChild: When a provided path is in a different self
393
 
            than self.
394
 
        """
395
 
        if file_list is None:
396
 
            return None
397
 
        if self.supports_views() and apply_view:
398
 
            view_files = self.views.lookup_view()
399
 
        else:
400
 
            view_files = []
401
 
        new_list = []
402
 
        # self.relpath exists as a "thunk" to osutils, but canonical_relpath
403
 
        # doesn't - fix that up here before we enter the loop.
404
 
        if canonicalize:
405
 
            fixer = lambda p: osutils.canonical_relpath(self.basedir, p)
406
 
        else:
407
 
            fixer = self.relpath
408
 
        for filename in file_list:
409
 
            relpath = fixer(osutils.dereference_path(filename))
410
 
            if view_files and not osutils.is_inside_any(view_files, relpath):
411
 
                raise errors.FileOutsideView(filename, view_files)
412
 
            new_list.append(relpath)
413
 
        return new_list
414
 
 
415
 
    @staticmethod
416
353
    def open_downlevel(path=None):
417
354
        """Open an unsupported working tree.
418
355
 
431
368
                return True, None
432
369
            else:
433
370
                return True, tree
434
 
        t = transport.get_transport(location)
435
 
        iterator = bzrdir.BzrDir.find_bzrdirs(t, evaluate=evaluate,
 
371
        transport = get_transport(location)
 
372
        iterator = bzrdir.BzrDir.find_bzrdirs(transport, evaluate=evaluate,
436
373
                                              list_current=list_current)
437
 
        return [tr for tr in iterator if tr is not None]
 
374
        return [t for t in iterator if t is not None]
438
375
 
439
376
    # should be deprecated - this is slow and in any case treating them as a
440
377
    # container is (we now know) bad style -- mbp 20070302
525
462
        return (file_obj, stat_value)
526
463
 
527
464
    def get_file_text(self, file_id, path=None, filtered=True):
528
 
        my_file = self.get_file(file_id, path=path, filtered=filtered)
529
 
        try:
530
 
            return my_file.read()
531
 
        finally:
532
 
            my_file.close()
 
465
        return self.get_file(file_id, path=path, filtered=filtered).read()
533
466
 
534
467
    def get_file_byname(self, filename, filtered=True):
535
468
        path = self.abspath(filename)
589
522
 
590
523
        # Now we have the parents of this content
591
524
        annotator = self.branch.repository.texts.get_annotator()
592
 
        text = self.get_file_text(file_id)
 
525
        text = self.get_file(file_id).read()
593
526
        this_key =(file_id, default_revision)
594
527
        annotator.add_special_text(this_key, file_parent_keys, text)
595
528
        annotations = [(key[-1], line)
1269
1202
                # absolute path
1270
1203
                fap = from_dir_abspath + '/' + f
1271
1204
 
1272
 
                dir_ie = inv[from_dir_id]
1273
 
                if dir_ie.kind == 'directory':
1274
 
                    f_ie = dir_ie.children.get(f)
1275
 
                else:
1276
 
                    f_ie = None
 
1205
                f_ie = inv.get_child(from_dir_id, f)
1277
1206
                if f_ie:
1278
1207
                    c = 'V'
1279
1208
                elif self.is_ignored(fp[1:]):
1280
1209
                    c = 'I'
1281
1210
                else:
1282
 
                    # we may not have found this file, because of a unicode
1283
 
                    # issue, or because the directory was actually a symlink.
 
1211
                    # we may not have found this file, because of a unicode issue
1284
1212
                    f_norm, can_access = osutils.normalized_filename(f)
1285
1213
                    if f == f_norm or not can_access:
1286
1214
                        # No change, so treat this file normally
1329
1257
                stack.pop()
1330
1258
 
1331
1259
    @needs_tree_write_lock
1332
 
    def move(self, from_paths, to_dir=None, after=False):
 
1260
    def move(self, from_paths, to_dir=None, after=False, **kwargs):
1333
1261
        """Rename files.
1334
1262
 
1335
1263
        to_dir must exist in the inventory.
1369
1297
 
1370
1298
        # check for deprecated use of signature
1371
1299
        if to_dir is None:
1372
 
            raise TypeError('You must supply a target directory')
 
1300
            to_dir = kwargs.get('to_name', None)
 
1301
            if to_dir is None:
 
1302
                raise TypeError('You must supply a target directory')
 
1303
            else:
 
1304
                symbol_versioning.warn('The parameter to_name was deprecated'
 
1305
                                       ' in version 0.13. Use to_dir instead',
 
1306
                                       DeprecationWarning)
 
1307
 
1373
1308
        # check destination directory
1374
1309
        if isinstance(from_paths, basestring):
1375
1310
            raise ValueError()
1384
1319
        to_dir_id = inv.path2id(to_dir)
1385
1320
        if to_dir_id is None:
1386
1321
            raise errors.BzrMoveFailedError('',to_dir,
1387
 
                errors.NotVersionedError(path=to_dir))
 
1322
                errors.NotVersionedError(path=str(to_dir)))
1388
1323
 
1389
1324
        to_dir_ie = inv[to_dir_id]
1390
1325
        if to_dir_ie.kind != 'directory':
1397
1332
            from_id = inv.path2id(from_rel)
1398
1333
            if from_id is None:
1399
1334
                raise errors.BzrMoveFailedError(from_rel,to_dir,
1400
 
                    errors.NotVersionedError(path=from_rel))
 
1335
                    errors.NotVersionedError(path=str(from_rel)))
1401
1336
 
1402
1337
            from_entry = inv[from_id]
1403
1338
            from_parent_id = from_entry.parent_id
1445
1380
            # check the inventory for source and destination
1446
1381
            if from_id is None:
1447
1382
                raise errors.BzrMoveFailedError(from_rel,to_rel,
1448
 
                    errors.NotVersionedError(path=from_rel))
 
1383
                    errors.NotVersionedError(path=str(from_rel)))
1449
1384
            if to_id is not None:
1450
1385
                raise errors.BzrMoveFailedError(from_rel,to_rel,
1451
 
                    errors.AlreadyVersionedError(path=to_rel))
 
1386
                    errors.AlreadyVersionedError(path=str(to_rel)))
1452
1387
 
1453
1388
            # try to determine the mode for rename (only change inv or change
1454
1389
            # inv and file system)
1455
1390
            if after:
1456
1391
                if not self.has_filename(to_rel):
1457
1392
                    raise errors.BzrMoveFailedError(from_id,to_rel,
1458
 
                        errors.NoSuchFile(path=to_rel,
 
1393
                        errors.NoSuchFile(path=str(to_rel),
1459
1394
                        extra="New file has not been created yet"))
1460
1395
                only_change_inv = True
1461
1396
            elif not self.has_filename(from_rel) and self.has_filename(to_rel):
1563
1498
            from_id = basis_tree.path2id(from_rel)
1564
1499
            if from_id is None:
1565
1500
                raise errors.BzrRenameFailedError(from_rel,to_rel,
1566
 
                    errors.NotVersionedError(path=from_rel))
 
1501
                    errors.NotVersionedError(path=str(from_rel)))
1567
1502
            # put entry back in the inventory so we can rename it
1568
1503
            from_entry = basis_tree.inventory[from_id].copy()
1569
1504
            inv.add(from_entry)
1587
1522
        # versioned
1588
1523
        if to_dir_id is None:
1589
1524
            raise errors.BzrMoveFailedError(from_rel,to_rel,
1590
 
                errors.NotVersionedError(path=to_dir))
 
1525
                errors.NotVersionedError(path=str(to_dir)))
1591
1526
 
1592
1527
        # all checks done. now we can continue with our actual work
1593
1528
        mutter('rename_one:\n'
1665
1600
 
1666
1601
    @needs_write_lock
1667
1602
    def pull(self, source, overwrite=False, stop_revision=None,
1668
 
             change_reporter=None, possible_transports=None, local=False,
1669
 
             show_base=False):
 
1603
             change_reporter=None, possible_transports=None, local=False):
1670
1604
        source.lock_read()
1671
1605
        try:
1672
1606
            old_revision_info = self.branch.last_revision_info()
1686
1620
                                basis_tree,
1687
1621
                                this_tree=self,
1688
1622
                                pb=None,
1689
 
                                change_reporter=change_reporter,
1690
 
                                show_base=show_base)
 
1623
                                change_reporter=change_reporter)
1691
1624
                    basis_root_id = basis_tree.get_root_id()
1692
1625
                    new_root_id = new_basis_tree.get_root_id()
1693
1626
                    if basis_root_id != new_root_id:
1865
1798
            raise errors.ObjectNotLocked(self)
1866
1799
 
1867
1800
    def lock_read(self):
1868
 
        """Lock the tree for reading.
1869
 
 
1870
 
        This also locks the branch, and can be unlocked via self.unlock().
1871
 
 
1872
 
        :return: A bzrlib.lock.LogicalLockResult.
1873
 
        """
 
1801
        """See Branch.lock_read, and WorkingTree.unlock."""
1874
1802
        if not self.is_locked():
1875
1803
            self._reset_data()
1876
1804
        self.branch.lock_read()
1877
1805
        try:
1878
 
            self._control_files.lock_read()
1879
 
            return LogicalLockResult(self.unlock)
 
1806
            return self._control_files.lock_read()
1880
1807
        except:
1881
1808
            self.branch.unlock()
1882
1809
            raise
1883
1810
 
1884
1811
    def lock_tree_write(self):
1885
 
        """See MutableTree.lock_tree_write, and WorkingTree.unlock.
1886
 
 
1887
 
        :return: A bzrlib.lock.LogicalLockResult.
1888
 
        """
 
1812
        """See MutableTree.lock_tree_write, and WorkingTree.unlock."""
1889
1813
        if not self.is_locked():
1890
1814
            self._reset_data()
1891
1815
        self.branch.lock_read()
1892
1816
        try:
1893
 
            self._control_files.lock_write()
1894
 
            return LogicalLockResult(self.unlock)
 
1817
            return self._control_files.lock_write()
1895
1818
        except:
1896
1819
            self.branch.unlock()
1897
1820
            raise
1898
1821
 
1899
1822
    def lock_write(self):
1900
 
        """See MutableTree.lock_write, and WorkingTree.unlock.
1901
 
 
1902
 
        :return: A bzrlib.lock.LogicalLockResult.
1903
 
        """
 
1823
        """See MutableTree.lock_write, and WorkingTree.unlock."""
1904
1824
        if not self.is_locked():
1905
1825
            self._reset_data()
1906
1826
        self.branch.lock_write()
1907
1827
        try:
1908
 
            self._control_files.lock_write()
1909
 
            return LogicalLockResult(self.unlock)
 
1828
            return self._control_files.lock_write()
1910
1829
        except:
1911
1830
            self.branch.unlock()
1912
1831
            raise
2029
1948
 
2030
1949
        inv_delta = []
2031
1950
 
2032
 
        all_files = set() # specified and nested files 
 
1951
        new_files=set()
2033
1952
        unknown_nested_files=set()
2034
1953
        if to_file is None:
2035
1954
            to_file = sys.stdout
2036
1955
 
2037
 
        files_to_backup = []
2038
 
 
2039
1956
        def recurse_directory_to_add_files(directory):
2040
1957
            # Recurse directory and add all files
2041
1958
            # so we can check if they have changed.
2042
 
            for parent_info, file_infos in self.walkdirs(directory):
 
1959
            for parent_info, file_infos in\
 
1960
                self.walkdirs(directory):
2043
1961
                for relpath, basename, kind, lstat, fileid, kind in file_infos:
2044
1962
                    # Is it versioned or ignored?
2045
 
                    if self.path2id(relpath):
 
1963
                    if self.path2id(relpath) or self.is_ignored(relpath):
2046
1964
                        # Add nested content for deletion.
2047
 
                        all_files.add(relpath)
 
1965
                        new_files.add(relpath)
2048
1966
                    else:
2049
 
                        # Files which are not versioned
 
1967
                        # Files which are not versioned and not ignored
2050
1968
                        # should be treated as unknown.
2051
 
                        files_to_backup.append(relpath)
 
1969
                        unknown_nested_files.add((relpath, None, kind))
2052
1970
 
2053
1971
        for filename in files:
2054
1972
            # Get file name into canonical form.
2055
1973
            abspath = self.abspath(filename)
2056
1974
            filename = self.relpath(abspath)
2057
1975
            if len(filename) > 0:
2058
 
                all_files.add(filename)
 
1976
                new_files.add(filename)
2059
1977
                recurse_directory_to_add_files(filename)
2060
1978
 
2061
 
        files = list(all_files)
 
1979
        files = list(new_files)
2062
1980
 
2063
1981
        if len(files) == 0:
2064
1982
            return # nothing to do
2068
1986
 
2069
1987
        # Bail out if we are going to delete files we shouldn't
2070
1988
        if not keep_files and not force:
2071
 
            for (file_id, path, content_change, versioned, parent_id, name,
2072
 
                 kind, executable) in self.iter_changes(self.basis_tree(),
2073
 
                     include_unchanged=True, require_versioned=False,
2074
 
                     want_unversioned=True, specific_files=files):
2075
 
                if versioned[0] == False:
2076
 
                    # The record is unknown or newly added
2077
 
                    files_to_backup.append(path[1])
2078
 
                elif (content_change and (kind[1] is not None) and
2079
 
                        osutils.is_inside_any(files, path[1])):
2080
 
                    # Versioned and changed, but not deleted, and still
2081
 
                    # in one of the dirs to be deleted.
2082
 
                    files_to_backup.append(path[1])
 
1989
            has_changed_files = len(unknown_nested_files) > 0
 
1990
            if not has_changed_files:
 
1991
                for (file_id, path, content_change, versioned, parent_id, name,
 
1992
                     kind, executable) in self.iter_changes(self.basis_tree(),
 
1993
                         include_unchanged=True, require_versioned=False,
 
1994
                         want_unversioned=True, specific_files=files):
 
1995
                    if versioned == (False, False):
 
1996
                        # The record is unknown ...
 
1997
                        if not self.is_ignored(path[1]):
 
1998
                            # ... but not ignored
 
1999
                            has_changed_files = True
 
2000
                            break
 
2001
                    elif content_change and (kind[1] is not None):
 
2002
                        # Versioned and changed, but not deleted
 
2003
                        has_changed_files = True
 
2004
                        break
2083
2005
 
2084
 
        def backup(file_to_backup):
2085
 
            backup_name = self.bzrdir._available_backup_name(file_to_backup)
2086
 
            osutils.rename(abs_path, self.abspath(backup_name))
2087
 
            return "removed %s (but kept a copy: %s)" % (file_to_backup,
2088
 
                                                         backup_name)
 
2006
            if has_changed_files:
 
2007
                # Make delta show ALL applicable changes in error message.
 
2008
                tree_delta = self.changes_from(self.basis_tree(),
 
2009
                    require_versioned=False, want_unversioned=True,
 
2010
                    specific_files=files)
 
2011
                for unknown_file in unknown_nested_files:
 
2012
                    if unknown_file not in tree_delta.unversioned:
 
2013
                        tree_delta.unversioned.extend((unknown_file,))
 
2014
                raise errors.BzrRemoveChangedFilesError(tree_delta)
2089
2015
 
2090
2016
        # Build inv_delta and delete files where applicable,
2091
2017
        # do this before any modifications to inventory.
2115
2041
                        len(os.listdir(abs_path)) > 0):
2116
2042
                        if force:
2117
2043
                            osutils.rmtree(abs_path)
2118
 
                            message = "deleted %s" % (f,)
2119
2044
                        else:
2120
 
                            message = backup(f)
 
2045
                            message = "%s is not an empty directory "\
 
2046
                                "and won't be deleted." % (f,)
2121
2047
                    else:
2122
 
                        if f in files_to_backup:
2123
 
                            message = backup(f)
2124
 
                        else:
2125
 
                            osutils.delete_any(abs_path)
2126
 
                            message = "deleted %s" % (f,)
 
2048
                        osutils.delete_any(abs_path)
 
2049
                        message = "deleted %s" % (f,)
2127
2050
                elif message is not None:
2128
2051
                    # Only care if we haven't done anything yet.
2129
2052
                    message = "%s does not exist." % (f,)
2266
2189
    _marker = object()
2267
2190
 
2268
2191
    def update(self, change_reporter=None, possible_transports=None,
2269
 
               revision=None, old_tip=_marker, show_base=False):
 
2192
               revision=None, old_tip=_marker):
2270
2193
        """Update a working tree along its branch.
2271
2194
 
2272
2195
        This will update the branch if its bound too, which means we have
2309
2232
            else:
2310
2233
                if old_tip is self._marker:
2311
2234
                    old_tip = None
2312
 
            return self._update_tree(old_tip, change_reporter, revision, show_base)
 
2235
            return self._update_tree(old_tip, change_reporter, revision)
2313
2236
        finally:
2314
2237
            self.unlock()
2315
2238
 
2316
2239
    @needs_tree_write_lock
2317
 
    def _update_tree(self, old_tip=None, change_reporter=None, revision=None,
2318
 
                     show_base=False):
 
2240
    def _update_tree(self, old_tip=None, change_reporter=None, revision=None):
2319
2241
        """Update a tree to the master branch.
2320
2242
 
2321
2243
        :param old_tip: if supplied, the previous tip revision the branch,
2348
2270
            other_tree = self.branch.repository.revision_tree(old_tip)
2349
2271
            nb_conflicts = merge.merge_inner(self.branch, other_tree,
2350
2272
                                             base_tree, this_tree=self,
2351
 
                                             change_reporter=change_reporter,
2352
 
                                             show_base=show_base)
 
2273
                                             change_reporter=change_reporter)
2353
2274
            if nb_conflicts:
2354
2275
                self.add_parent_tree((old_tip, other_tree))
2355
2276
                trace.note('Rerun update after fixing the conflicts.')
2379
2300
 
2380
2301
            nb_conflicts = merge.merge_inner(self.branch, to_tree, base_tree,
2381
2302
                                             this_tree=self,
2382
 
                                             change_reporter=change_reporter,
2383
 
                                             show_base=show_base)
 
2303
                                             change_reporter=change_reporter)
2384
2304
            self.set_last_revision(revision)
2385
2305
            # TODO - dedup parents list with things merged by pull ?
2386
2306
            # reuse the tree we've updated to to set the basis:
2675
2595
        """
2676
2596
        return
2677
2597
 
2678
 
    @needs_read_lock
2679
 
    def check_state(self):
2680
 
        """Check that the working state is/isn't valid."""
2681
 
        check_refs = self._get_check_refs()
2682
 
        refs = {}
2683
 
        for ref in check_refs:
2684
 
            kind, value = ref
2685
 
            if kind == 'trees':
2686
 
                refs[ref] = self.branch.repository.revision_tree(value)
2687
 
        self._check(refs)
2688
 
 
2689
 
    @needs_tree_write_lock
2690
 
    def reset_state(self, revision_ids=None):
2691
 
        """Reset the state of the working tree.
2692
 
 
2693
 
        This does a hard-reset to a last-known-good state. This is a way to
2694
 
        fix if something got corrupted (like the .bzr/checkout/dirstate file)
2695
 
        """
2696
 
        if revision_ids is None:
2697
 
            revision_ids = self.get_parent_ids()
2698
 
        if not revision_ids:
2699
 
            rt = self.branch.repository.revision_tree(
2700
 
                _mod_revision.NULL_REVISION)
2701
 
        else:
2702
 
            rt = self.branch.repository.revision_tree(revision_ids[0])
2703
 
        self._write_inventory(rt.inventory)
2704
 
        self.set_parent_ids(revision_ids)
2705
 
 
2706
2598
    def _get_rules_searcher(self, default_searcher):
2707
2599
        """See Tree._get_rules_searcher."""
2708
2600
        if self._rules_searcher is None:
2744
2636
 
2745
2637
        In Format2 WorkingTrees we have a single lock for the branch and tree
2746
2638
        so lock_tree_write() degrades to lock_write().
2747
 
 
2748
 
        :return: An object with an unlock method which will release the lock
2749
 
            obtained.
2750
2639
        """
2751
2640
        self.branch.lock_write()
2752
2641
        try:
2753
 
            self._control_files.lock_write()
2754
 
            return self
 
2642
            return self._control_files.lock_write()
2755
2643
        except:
2756
2644
            self.branch.unlock()
2757
2645
            raise
2882
2770
    _formats = {}
2883
2771
    """The known formats."""
2884
2772
 
2885
 
    _extra_formats = []
2886
 
    """Extra formats that can not be used in a metadir."""
2887
 
 
2888
2773
    requires_rich_root = False
2889
2774
 
2890
2775
    upgrade_recommended = False
2891
2776
 
2892
 
    requires_normalized_unicode_filenames = False
2893
 
 
2894
 
    case_sensitive_filename = "FoRMaT"
2895
 
 
2896
2777
    @classmethod
2897
2778
    def find_format(klass, a_bzrdir):
2898
2779
        """Return the format for the working tree object in a_bzrdir."""
2947
2828
        klass._formats[format.get_format_string()] = format
2948
2829
 
2949
2830
    @classmethod
2950
 
    def register_extra_format(klass, format):
2951
 
        klass._extra_formats.append(format)
2952
 
 
2953
 
    @classmethod
2954
 
    def unregister_extra_format(klass, format):
2955
 
        klass._extra_formats.remove(format)
2956
 
 
2957
 
    @classmethod
2958
 
    def get_formats(klass):
2959
 
        return klass._formats.values() + klass._extra_formats
2960
 
 
2961
 
    @classmethod
2962
2831
    def set_default_format(klass, format):
2963
2832
        klass._default_format = format
2964
2833
 
2975
2844
 
2976
2845
    upgrade_recommended = True
2977
2846
 
2978
 
    requires_normalized_unicode_filenames = True
2979
 
 
2980
 
    case_sensitive_filename = "Branch-FoRMaT"
2981
 
 
2982
2847
    def get_format_description(self):
2983
2848
        """See WorkingTreeFormat.get_format_description()."""
2984
2849
        return "Working tree format 2"
3019
2884
                         inv,
3020
2885
                         _internal=True,
3021
2886
                         _format=self,
3022
 
                         _bzrdir=a_bzrdir,
3023
 
                         _control_files=branch.control_files)
 
2887
                         _bzrdir=a_bzrdir)
3024
2888
        basis_tree = branch.repository.revision_tree(revision_id)
3025
2889
        if basis_tree.inventory.root is not None:
3026
2890
            wt.set_root_id(basis_tree.get_root_id())
3051
2915
        wt = WorkingTree2(a_bzrdir.root_transport.local_abspath('.'),
3052
2916
                           _internal=True,
3053
2917
                           _format=self,
3054
 
                           _bzrdir=a_bzrdir,
3055
 
                           _control_files=a_bzrdir.open_branch().control_files)
 
2918
                           _bzrdir=a_bzrdir)
3056
2919
        return wt
3057
2920
 
3058
2921
class WorkingTreeFormat3(WorkingTreeFormat):
3192
3055
WorkingTreeFormat.register_format(WorkingTreeFormat4())
3193
3056
WorkingTreeFormat.register_format(WorkingTreeFormat3())
3194
3057
WorkingTreeFormat.set_default_format(__default_format)
3195
 
# Register extra formats which have no format string are not discoverable
3196
 
# and not independently creatable. They are implicitly created as part of
3197
 
# e.g. older Bazaar formats or foreign formats.
3198
 
WorkingTreeFormat.register_extra_format(WorkingTreeFormat2())
 
3058
# formats which have no format string are not discoverable
 
3059
# and not independently creatable, so are not registered.
 
3060
_legacy_formats = [WorkingTreeFormat2(),
 
3061
                   ]