/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,
58
57
    ignores,
59
58
    inventory,
60
59
    merge,
61
 
    registry,
62
60
    revision as _mod_revision,
63
61
    revisiontree,
64
62
    trace,
65
63
    transform,
66
 
    transport,
67
64
    ui,
68
65
    views,
69
66
    xml5,
70
67
    xml7,
71
68
    )
 
69
import bzrlib.branch
 
70
from bzrlib.transport import get_transport
72
71
from bzrlib.workingtree_4 import (
73
72
    WorkingTreeFormat4,
74
73
    WorkingTreeFormat5,
78
77
 
79
78
from bzrlib import symbol_versioning
80
79
from bzrlib.decorators import needs_read_lock, needs_write_lock
81
 
from bzrlib.lock import LogicalLockResult
82
80
from bzrlib.lockable_files import LockableFiles
83
81
from bzrlib.lockdir import LockDir
84
82
import bzrlib.mutabletree
170
168
 
171
169
 
172
170
class WorkingTree(bzrlib.mutabletree.MutableTree,
173
 
    controldir.ControlComponent):
 
171
    bzrdir.ControlComponent):
174
172
    """Working copy tree.
175
173
 
176
174
    The inventory is held in the `Branch` working-inventory, and the
178
176
 
179
177
    It is possible for a `WorkingTree` to have a filename which is
180
178
    not listed in the Inventory and vice versa.
181
 
 
182
 
    :ivar basedir: The root of the tree on disk. This is a unicode path object
183
 
        (as opposed to a URL).
184
179
    """
185
180
 
186
181
    # override this to set the strategy for storing views
210
205
        else:
211
206
            self._branch = self.bzrdir.open_branch()
212
207
        self.basedir = realpath(basedir)
213
 
        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
214
215
        self._transport = self._control_files._transport
215
216
        # update the whole cache up front and write to disk if anything changed;
216
217
        # in the future we might want to do this more selectively
257
258
    def _detect_case_handling(self):
258
259
        wt_trans = self.bzrdir.get_workingtree_transport(None)
259
260
        try:
260
 
            wt_trans.stat(self._format.case_sensitive_filename)
 
261
            wt_trans.stat("FoRMaT")
261
262
        except errors.NoSuchFile:
262
263
            self.case_sensitive = True
263
264
        else:
345
346
        if path is None:
346
347
            path = osutils.getcwd()
347
348
        control, relpath = bzrdir.BzrDir.open_containing(path)
 
349
 
348
350
        return control.open_workingtree(), relpath
349
351
 
350
352
    @staticmethod
351
 
    def open_containing_paths(file_list, default_directory=None,
352
 
                              canonicalize=True, apply_view=True):
353
 
        """Open the WorkingTree that contains a set of paths.
354
 
 
355
 
        Fail if the paths given are not all in a single tree.
356
 
 
357
 
        This is used for the many command-line interfaces that take a list of
358
 
        any number of files and that require they all be in the same tree.
359
 
        """
360
 
        if default_directory is None:
361
 
            default_directory = u'.'
362
 
        # recommended replacement for builtins.internal_tree_files
363
 
        if file_list is None or len(file_list) == 0:
364
 
            tree = WorkingTree.open_containing(default_directory)[0]
365
 
            # XXX: doesn't really belong here, and seems to have the strange
366
 
            # side effect of making it return a bunch of files, not the whole
367
 
            # tree -- mbp 20100716
368
 
            if tree.supports_views() and apply_view:
369
 
                view_files = tree.views.lookup_view()
370
 
                if view_files:
371
 
                    file_list = view_files
372
 
                    view_str = views.view_display_str(view_files)
373
 
                    note("Ignoring files outside view. View is %s" % view_str)
374
 
            return tree, file_list
375
 
        if default_directory == u'.':
376
 
            seed = file_list[0]
377
 
        else:
378
 
            seed = default_directory
379
 
            file_list = [osutils.pathjoin(default_directory, f)
380
 
                         for f in file_list]
381
 
        tree = WorkingTree.open_containing(seed)[0]
382
 
        return tree, tree.safe_relpath_files(file_list, canonicalize,
383
 
                                             apply_view=apply_view)
384
 
 
385
 
    def safe_relpath_files(self, file_list, canonicalize=True, apply_view=True):
386
 
        """Convert file_list into a list of relpaths in tree.
387
 
 
388
 
        :param self: A tree to operate on.
389
 
        :param file_list: A list of user provided paths or None.
390
 
        :param apply_view: if True and a view is set, apply it or check that
391
 
            specified files are within it
392
 
        :return: A list of relative paths.
393
 
        :raises errors.PathNotChild: When a provided path is in a different self
394
 
            than self.
395
 
        """
396
 
        if file_list is None:
397
 
            return None
398
 
        if self.supports_views() and apply_view:
399
 
            view_files = self.views.lookup_view()
400
 
        else:
401
 
            view_files = []
402
 
        new_list = []
403
 
        # self.relpath exists as a "thunk" to osutils, but canonical_relpath
404
 
        # doesn't - fix that up here before we enter the loop.
405
 
        if canonicalize:
406
 
            fixer = lambda p: osutils.canonical_relpath(self.basedir, p)
407
 
        else:
408
 
            fixer = self.relpath
409
 
        for filename in file_list:
410
 
            relpath = fixer(osutils.dereference_path(filename))
411
 
            if view_files and not osutils.is_inside_any(view_files, relpath):
412
 
                raise errors.FileOutsideView(filename, view_files)
413
 
            new_list.append(relpath)
414
 
        return new_list
415
 
 
416
 
    @staticmethod
417
353
    def open_downlevel(path=None):
418
354
        """Open an unsupported working tree.
419
355
 
432
368
                return True, None
433
369
            else:
434
370
                return True, tree
435
 
        t = transport.get_transport(location)
436
 
        iterator = bzrdir.BzrDir.find_bzrdirs(t, evaluate=evaluate,
 
371
        transport = get_transport(location)
 
372
        iterator = bzrdir.BzrDir.find_bzrdirs(transport, evaluate=evaluate,
437
373
                                              list_current=list_current)
438
 
        return [tr for tr in iterator if tr is not None]
 
374
        return [t for t in iterator if t is not None]
439
375
 
440
376
    # should be deprecated - this is slow and in any case treating them as a
441
377
    # container is (we now know) bad style -- mbp 20070302
526
462
        return (file_obj, stat_value)
527
463
 
528
464
    def get_file_text(self, file_id, path=None, filtered=True):
529
 
        my_file = self.get_file(file_id, path=path, filtered=filtered)
530
 
        try:
531
 
            return my_file.read()
532
 
        finally:
533
 
            my_file.close()
 
465
        return self.get_file(file_id, path=path, filtered=filtered).read()
534
466
 
535
467
    def get_file_byname(self, filename, filtered=True):
536
468
        path = self.abspath(filename)
590
522
 
591
523
        # Now we have the parents of this content
592
524
        annotator = self.branch.repository.texts.get_annotator()
593
 
        text = self.get_file_text(file_id)
 
525
        text = self.get_file(file_id).read()
594
526
        this_key =(file_id, default_revision)
595
527
        annotator.add_special_text(this_key, file_parent_keys, text)
596
528
        annotations = [(key[-1], line)
1270
1202
                # absolute path
1271
1203
                fap = from_dir_abspath + '/' + f
1272
1204
 
1273
 
                dir_ie = inv[from_dir_id]
1274
 
                if dir_ie.kind == 'directory':
1275
 
                    f_ie = dir_ie.children.get(f)
1276
 
                else:
1277
 
                    f_ie = None
 
1205
                f_ie = inv.get_child(from_dir_id, f)
1278
1206
                if f_ie:
1279
1207
                    c = 'V'
1280
1208
                elif self.is_ignored(fp[1:]):
1281
1209
                    c = 'I'
1282
1210
                else:
1283
 
                    # we may not have found this file, because of a unicode
1284
 
                    # issue, or because the directory was actually a symlink.
 
1211
                    # we may not have found this file, because of a unicode issue
1285
1212
                    f_norm, can_access = osutils.normalized_filename(f)
1286
1213
                    if f == f_norm or not can_access:
1287
1214
                        # No change, so treat this file normally
1330
1257
                stack.pop()
1331
1258
 
1332
1259
    @needs_tree_write_lock
1333
 
    def move(self, from_paths, to_dir=None, after=False):
 
1260
    def move(self, from_paths, to_dir=None, after=False, **kwargs):
1334
1261
        """Rename files.
1335
1262
 
1336
1263
        to_dir must exist in the inventory.
1370
1297
 
1371
1298
        # check for deprecated use of signature
1372
1299
        if to_dir is None:
1373
 
            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
 
1374
1308
        # check destination directory
1375
1309
        if isinstance(from_paths, basestring):
1376
1310
            raise ValueError()
1385
1319
        to_dir_id = inv.path2id(to_dir)
1386
1320
        if to_dir_id is None:
1387
1321
            raise errors.BzrMoveFailedError('',to_dir,
1388
 
                errors.NotVersionedError(path=to_dir))
 
1322
                errors.NotVersionedError(path=str(to_dir)))
1389
1323
 
1390
1324
        to_dir_ie = inv[to_dir_id]
1391
1325
        if to_dir_ie.kind != 'directory':
1398
1332
            from_id = inv.path2id(from_rel)
1399
1333
            if from_id is None:
1400
1334
                raise errors.BzrMoveFailedError(from_rel,to_dir,
1401
 
                    errors.NotVersionedError(path=from_rel))
 
1335
                    errors.NotVersionedError(path=str(from_rel)))
1402
1336
 
1403
1337
            from_entry = inv[from_id]
1404
1338
            from_parent_id = from_entry.parent_id
1446
1380
            # check the inventory for source and destination
1447
1381
            if from_id is None:
1448
1382
                raise errors.BzrMoveFailedError(from_rel,to_rel,
1449
 
                    errors.NotVersionedError(path=from_rel))
 
1383
                    errors.NotVersionedError(path=str(from_rel)))
1450
1384
            if to_id is not None:
1451
1385
                raise errors.BzrMoveFailedError(from_rel,to_rel,
1452
 
                    errors.AlreadyVersionedError(path=to_rel))
 
1386
                    errors.AlreadyVersionedError(path=str(to_rel)))
1453
1387
 
1454
1388
            # try to determine the mode for rename (only change inv or change
1455
1389
            # inv and file system)
1456
1390
            if after:
1457
1391
                if not self.has_filename(to_rel):
1458
1392
                    raise errors.BzrMoveFailedError(from_id,to_rel,
1459
 
                        errors.NoSuchFile(path=to_rel,
 
1393
                        errors.NoSuchFile(path=str(to_rel),
1460
1394
                        extra="New file has not been created yet"))
1461
1395
                only_change_inv = True
1462
1396
            elif not self.has_filename(from_rel) and self.has_filename(to_rel):
1564
1498
            from_id = basis_tree.path2id(from_rel)
1565
1499
            if from_id is None:
1566
1500
                raise errors.BzrRenameFailedError(from_rel,to_rel,
1567
 
                    errors.NotVersionedError(path=from_rel))
 
1501
                    errors.NotVersionedError(path=str(from_rel)))
1568
1502
            # put entry back in the inventory so we can rename it
1569
1503
            from_entry = basis_tree.inventory[from_id].copy()
1570
1504
            inv.add(from_entry)
1588
1522
        # versioned
1589
1523
        if to_dir_id is None:
1590
1524
            raise errors.BzrMoveFailedError(from_rel,to_rel,
1591
 
                errors.NotVersionedError(path=to_dir))
 
1525
                errors.NotVersionedError(path=str(to_dir)))
1592
1526
 
1593
1527
        # all checks done. now we can continue with our actual work
1594
1528
        mutter('rename_one:\n'
1666
1600
 
1667
1601
    @needs_write_lock
1668
1602
    def pull(self, source, overwrite=False, stop_revision=None,
1669
 
             change_reporter=None, possible_transports=None, local=False,
1670
 
             show_base=False):
 
1603
             change_reporter=None, possible_transports=None, local=False):
1671
1604
        source.lock_read()
1672
1605
        try:
1673
1606
            old_revision_info = self.branch.last_revision_info()
1687
1620
                                basis_tree,
1688
1621
                                this_tree=self,
1689
1622
                                pb=None,
1690
 
                                change_reporter=change_reporter,
1691
 
                                show_base=show_base)
 
1623
                                change_reporter=change_reporter)
1692
1624
                    basis_root_id = basis_tree.get_root_id()
1693
1625
                    new_root_id = new_basis_tree.get_root_id()
1694
1626
                    if basis_root_id != new_root_id:
1866
1798
            raise errors.ObjectNotLocked(self)
1867
1799
 
1868
1800
    def lock_read(self):
1869
 
        """Lock the tree for reading.
1870
 
 
1871
 
        This also locks the branch, and can be unlocked via self.unlock().
1872
 
 
1873
 
        :return: A bzrlib.lock.LogicalLockResult.
1874
 
        """
 
1801
        """See Branch.lock_read, and WorkingTree.unlock."""
1875
1802
        if not self.is_locked():
1876
1803
            self._reset_data()
1877
1804
        self.branch.lock_read()
1878
1805
        try:
1879
 
            self._control_files.lock_read()
1880
 
            return LogicalLockResult(self.unlock)
 
1806
            return self._control_files.lock_read()
1881
1807
        except:
1882
1808
            self.branch.unlock()
1883
1809
            raise
1884
1810
 
1885
1811
    def lock_tree_write(self):
1886
 
        """See MutableTree.lock_tree_write, and WorkingTree.unlock.
1887
 
 
1888
 
        :return: A bzrlib.lock.LogicalLockResult.
1889
 
        """
 
1812
        """See MutableTree.lock_tree_write, and WorkingTree.unlock."""
1890
1813
        if not self.is_locked():
1891
1814
            self._reset_data()
1892
1815
        self.branch.lock_read()
1893
1816
        try:
1894
 
            self._control_files.lock_write()
1895
 
            return LogicalLockResult(self.unlock)
 
1817
            return self._control_files.lock_write()
1896
1818
        except:
1897
1819
            self.branch.unlock()
1898
1820
            raise
1899
1821
 
1900
1822
    def lock_write(self):
1901
 
        """See MutableTree.lock_write, and WorkingTree.unlock.
1902
 
 
1903
 
        :return: A bzrlib.lock.LogicalLockResult.
1904
 
        """
 
1823
        """See MutableTree.lock_write, and WorkingTree.unlock."""
1905
1824
        if not self.is_locked():
1906
1825
            self._reset_data()
1907
1826
        self.branch.lock_write()
1908
1827
        try:
1909
 
            self._control_files.lock_write()
1910
 
            return LogicalLockResult(self.unlock)
 
1828
            return self._control_files.lock_write()
1911
1829
        except:
1912
1830
            self.branch.unlock()
1913
1831
            raise
2030
1948
 
2031
1949
        inv_delta = []
2032
1950
 
2033
 
        all_files = set() # specified and nested files 
 
1951
        new_files=set()
2034
1952
        unknown_nested_files=set()
2035
1953
        if to_file is None:
2036
1954
            to_file = sys.stdout
2037
1955
 
2038
 
        files_to_backup = []
2039
 
 
2040
1956
        def recurse_directory_to_add_files(directory):
2041
1957
            # Recurse directory and add all files
2042
1958
            # so we can check if they have changed.
2043
 
            for parent_info, file_infos in self.walkdirs(directory):
 
1959
            for parent_info, file_infos in\
 
1960
                self.walkdirs(directory):
2044
1961
                for relpath, basename, kind, lstat, fileid, kind in file_infos:
2045
1962
                    # Is it versioned or ignored?
2046
 
                    if self.path2id(relpath):
 
1963
                    if self.path2id(relpath) or self.is_ignored(relpath):
2047
1964
                        # Add nested content for deletion.
2048
 
                        all_files.add(relpath)
 
1965
                        new_files.add(relpath)
2049
1966
                    else:
2050
 
                        # Files which are not versioned
 
1967
                        # Files which are not versioned and not ignored
2051
1968
                        # should be treated as unknown.
2052
 
                        files_to_backup.append(relpath)
 
1969
                        unknown_nested_files.add((relpath, None, kind))
2053
1970
 
2054
1971
        for filename in files:
2055
1972
            # Get file name into canonical form.
2056
1973
            abspath = self.abspath(filename)
2057
1974
            filename = self.relpath(abspath)
2058
1975
            if len(filename) > 0:
2059
 
                all_files.add(filename)
 
1976
                new_files.add(filename)
2060
1977
                recurse_directory_to_add_files(filename)
2061
1978
 
2062
 
        files = list(all_files)
 
1979
        files = list(new_files)
2063
1980
 
2064
1981
        if len(files) == 0:
2065
1982
            return # nothing to do
2069
1986
 
2070
1987
        # Bail out if we are going to delete files we shouldn't
2071
1988
        if not keep_files and not force:
2072
 
            for (file_id, path, content_change, versioned, parent_id, name,
2073
 
                 kind, executable) in self.iter_changes(self.basis_tree(),
2074
 
                     include_unchanged=True, require_versioned=False,
2075
 
                     want_unversioned=True, specific_files=files):
2076
 
                if versioned[0] == False:
2077
 
                    # The record is unknown or newly added
2078
 
                    files_to_backup.append(path[1])
2079
 
                elif (content_change and (kind[1] is not None) and
2080
 
                        osutils.is_inside_any(files, path[1])):
2081
 
                    # Versioned and changed, but not deleted, and still
2082
 
                    # in one of the dirs to be deleted.
2083
 
                    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
2084
2005
 
2085
 
        def backup(file_to_backup):
2086
 
            backup_name = self.bzrdir._available_backup_name(file_to_backup)
2087
 
            osutils.rename(abs_path, self.abspath(backup_name))
2088
 
            return "removed %s (but kept a copy: %s)" % (file_to_backup,
2089
 
                                                         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)
2090
2015
 
2091
2016
        # Build inv_delta and delete files where applicable,
2092
2017
        # do this before any modifications to inventory.
2116
2041
                        len(os.listdir(abs_path)) > 0):
2117
2042
                        if force:
2118
2043
                            osutils.rmtree(abs_path)
2119
 
                            message = "deleted %s" % (f,)
2120
2044
                        else:
2121
 
                            message = backup(f)
 
2045
                            message = "%s is not an empty directory "\
 
2046
                                "and won't be deleted." % (f,)
2122
2047
                    else:
2123
 
                        if f in files_to_backup:
2124
 
                            message = backup(f)
2125
 
                        else:
2126
 
                            osutils.delete_any(abs_path)
2127
 
                            message = "deleted %s" % (f,)
 
2048
                        osutils.delete_any(abs_path)
 
2049
                        message = "deleted %s" % (f,)
2128
2050
                elif message is not None:
2129
2051
                    # Only care if we haven't done anything yet.
2130
2052
                    message = "%s does not exist." % (f,)
2267
2189
    _marker = object()
2268
2190
 
2269
2191
    def update(self, change_reporter=None, possible_transports=None,
2270
 
               revision=None, old_tip=_marker, show_base=False):
 
2192
               revision=None, old_tip=_marker):
2271
2193
        """Update a working tree along its branch.
2272
2194
 
2273
2195
        This will update the branch if its bound too, which means we have
2310
2232
            else:
2311
2233
                if old_tip is self._marker:
2312
2234
                    old_tip = None
2313
 
            return self._update_tree(old_tip, change_reporter, revision, show_base)
 
2235
            return self._update_tree(old_tip, change_reporter, revision)
2314
2236
        finally:
2315
2237
            self.unlock()
2316
2238
 
2317
2239
    @needs_tree_write_lock
2318
 
    def _update_tree(self, old_tip=None, change_reporter=None, revision=None,
2319
 
                     show_base=False):
 
2240
    def _update_tree(self, old_tip=None, change_reporter=None, revision=None):
2320
2241
        """Update a tree to the master branch.
2321
2242
 
2322
2243
        :param old_tip: if supplied, the previous tip revision the branch,
2349
2270
            other_tree = self.branch.repository.revision_tree(old_tip)
2350
2271
            nb_conflicts = merge.merge_inner(self.branch, other_tree,
2351
2272
                                             base_tree, this_tree=self,
2352
 
                                             change_reporter=change_reporter,
2353
 
                                             show_base=show_base)
 
2273
                                             change_reporter=change_reporter)
2354
2274
            if nb_conflicts:
2355
2275
                self.add_parent_tree((old_tip, other_tree))
2356
2276
                trace.note('Rerun update after fixing the conflicts.')
2380
2300
 
2381
2301
            nb_conflicts = merge.merge_inner(self.branch, to_tree, base_tree,
2382
2302
                                             this_tree=self,
2383
 
                                             change_reporter=change_reporter,
2384
 
                                             show_base=show_base)
 
2303
                                             change_reporter=change_reporter)
2385
2304
            self.set_last_revision(revision)
2386
2305
            # TODO - dedup parents list with things merged by pull ?
2387
2306
            # reuse the tree we've updated to to set the basis:
2676
2595
        """
2677
2596
        return
2678
2597
 
2679
 
    @needs_read_lock
2680
 
    def check_state(self):
2681
 
        """Check that the working state is/isn't valid."""
2682
 
        check_refs = self._get_check_refs()
2683
 
        refs = {}
2684
 
        for ref in check_refs:
2685
 
            kind, value = ref
2686
 
            if kind == 'trees':
2687
 
                refs[ref] = self.branch.repository.revision_tree(value)
2688
 
        self._check(refs)
2689
 
 
2690
 
    @needs_tree_write_lock
2691
 
    def reset_state(self, revision_ids=None):
2692
 
        """Reset the state of the working tree.
2693
 
 
2694
 
        This does a hard-reset to a last-known-good state. This is a way to
2695
 
        fix if something got corrupted (like the .bzr/checkout/dirstate file)
2696
 
        """
2697
 
        if revision_ids is None:
2698
 
            revision_ids = self.get_parent_ids()
2699
 
        if not revision_ids:
2700
 
            rt = self.branch.repository.revision_tree(
2701
 
                _mod_revision.NULL_REVISION)
2702
 
        else:
2703
 
            rt = self.branch.repository.revision_tree(revision_ids[0])
2704
 
        self._write_inventory(rt.inventory)
2705
 
        self.set_parent_ids(revision_ids)
2706
 
 
2707
2598
    def _get_rules_searcher(self, default_searcher):
2708
2599
        """See Tree._get_rules_searcher."""
2709
2600
        if self._rules_searcher is None:
2745
2636
 
2746
2637
        In Format2 WorkingTrees we have a single lock for the branch and tree
2747
2638
        so lock_tree_write() degrades to lock_write().
2748
 
 
2749
 
        :return: An object with an unlock method which will release the lock
2750
 
            obtained.
2751
2639
        """
2752
2640
        self.branch.lock_write()
2753
2641
        try:
2754
 
            self._control_files.lock_write()
2755
 
            return self
 
2642
            return self._control_files.lock_write()
2756
2643
        except:
2757
2644
            self.branch.unlock()
2758
2645
            raise
2859
2746
            return path[:-len(suffix)]
2860
2747
 
2861
2748
 
2862
 
class WorkingTreeFormatRegistry(controldir.ControlComponentFormatRegistry):
2863
 
    """Registry for working tree formats."""
2864
 
 
2865
 
    def __init__(self, other_registry=None):
2866
 
        super(WorkingTreeFormatRegistry, self).__init__(other_registry)
2867
 
        self._default_format = None
2868
 
 
2869
 
    def get_default(self):
2870
 
        """Return the current default format."""
2871
 
        return self._default_format
2872
 
 
2873
 
    def set_default(self, format):
2874
 
        self._default_format = format
2875
 
 
2876
 
 
2877
 
format_registry = WorkingTreeFormatRegistry()
2878
 
 
2879
 
 
2880
 
class WorkingTreeFormat(controldir.ControlComponentFormat):
 
2749
class WorkingTreeFormat(object):
2881
2750
    """An encapsulation of the initialization and open routines for a format.
2882
2751
 
2883
2752
    Formats provide three things:
2895
2764
    object will be created every time regardless.
2896
2765
    """
2897
2766
 
 
2767
    _default_format = None
 
2768
    """The default format used for new trees."""
 
2769
 
 
2770
    _formats = {}
 
2771
    """The known formats."""
 
2772
 
2898
2773
    requires_rich_root = False
2899
2774
 
2900
2775
    upgrade_recommended = False
2901
2776
 
2902
 
    requires_normalized_unicode_filenames = False
2903
 
 
2904
 
    case_sensitive_filename = "FoRMaT"
2905
 
 
2906
 
    missing_parent_conflicts = False
2907
 
    """If this format supports missing parent conflicts."""
2908
 
 
2909
2777
    @classmethod
2910
2778
    def find_format(klass, a_bzrdir):
2911
2779
        """Return the format for the working tree object in a_bzrdir."""
2912
2780
        try:
2913
2781
            transport = a_bzrdir.get_workingtree_transport(None)
2914
2782
            format_string = transport.get_bytes("format")
2915
 
            return format_registry.get(format_string)
 
2783
            return klass._formats[format_string]
2916
2784
        except errors.NoSuchFile:
2917
2785
            raise errors.NoWorkingTree(base=transport.base)
2918
2786
        except KeyError:
2919
2787
            raise errors.UnknownFormatError(format=format_string,
2920
2788
                                            kind="working tree")
2921
2789
 
2922
 
    def initialize(self, a_bzrdir, revision_id=None, from_branch=None,
2923
 
                   accelerator_tree=None, hardlink=False):
2924
 
        """Initialize a new working tree in a_bzrdir.
2925
 
 
2926
 
        :param a_bzrdir: BzrDir to initialize the working tree in.
2927
 
        :param revision_id: allows creating a working tree at a different
2928
 
            revision than the branch is at.
2929
 
        :param from_branch: Branch to checkout
2930
 
        :param accelerator_tree: A tree which can be used for retrieving file
2931
 
            contents more quickly than the revision tree, i.e. a workingtree.
2932
 
            The revision tree will be used for cases where accelerator_tree's
2933
 
            content is different.
2934
 
        :param hardlink: If true, hard-link files from accelerator_tree,
2935
 
            where possible.
2936
 
        """
2937
 
        raise NotImplementedError(self.initialize)
2938
 
 
2939
2790
    def __eq__(self, other):
2940
2791
        return self.__class__ is other.__class__
2941
2792
 
2943
2794
        return not (self == other)
2944
2795
 
2945
2796
    @classmethod
2946
 
    @symbol_versioning.deprecated_method(
2947
 
        symbol_versioning.deprecated_in((2, 4, 0)))
2948
2797
    def get_default_format(klass):
2949
2798
        """Return the current default format."""
2950
 
        return format_registry.get_default()
 
2799
        return klass._default_format
2951
2800
 
2952
2801
    def get_format_string(self):
2953
2802
        """Return the ASCII format string that identifies this format."""
2975
2824
        return False
2976
2825
 
2977
2826
    @classmethod
2978
 
    @symbol_versioning.deprecated_method(
2979
 
        symbol_versioning.deprecated_in((2, 4, 0)))
2980
2827
    def register_format(klass, format):
2981
 
        format_registry.register(format)
2982
 
 
2983
 
    @classmethod
2984
 
    @symbol_versioning.deprecated_method(
2985
 
        symbol_versioning.deprecated_in((2, 4, 0)))
2986
 
    def register_extra_format(klass, format):
2987
 
        format_registry.register_extra(format)
2988
 
 
2989
 
    @classmethod
2990
 
    @symbol_versioning.deprecated_method(
2991
 
        symbol_versioning.deprecated_in((2, 4, 0)))
2992
 
    def unregister_extra_format(klass, format):
2993
 
        format_registry.unregister_extra(format)
2994
 
 
2995
 
    @classmethod
2996
 
    @symbol_versioning.deprecated_method(
2997
 
        symbol_versioning.deprecated_in((2, 4, 0)))
2998
 
    def get_formats(klass):
2999
 
        return format_registry._get_all()
3000
 
 
3001
 
    @classmethod
3002
 
    @symbol_versioning.deprecated_method(
3003
 
        symbol_versioning.deprecated_in((2, 4, 0)))
 
2828
        klass._formats[format.get_format_string()] = format
 
2829
 
 
2830
    @classmethod
3004
2831
    def set_default_format(klass, format):
3005
 
        format_registry.set_default(format)
 
2832
        klass._default_format = format
3006
2833
 
3007
2834
    @classmethod
3008
 
    @symbol_versioning.deprecated_method(
3009
 
        symbol_versioning.deprecated_in((2, 4, 0)))
3010
2835
    def unregister_format(klass, format):
3011
 
        format_registry.remove(format)
 
2836
        del klass._formats[format.get_format_string()]
3012
2837
 
3013
2838
 
3014
2839
class WorkingTreeFormat2(WorkingTreeFormat):
3019
2844
 
3020
2845
    upgrade_recommended = True
3021
2846
 
3022
 
    requires_normalized_unicode_filenames = True
3023
 
 
3024
 
    case_sensitive_filename = "Branch-FoRMaT"
3025
 
 
3026
 
    missing_parent_conflicts = False
3027
 
 
3028
2847
    def get_format_description(self):
3029
2848
        """See WorkingTreeFormat.get_format_description()."""
3030
2849
        return "Working tree format 2"
3065
2884
                         inv,
3066
2885
                         _internal=True,
3067
2886
                         _format=self,
3068
 
                         _bzrdir=a_bzrdir,
3069
 
                         _control_files=branch.control_files)
 
2887
                         _bzrdir=a_bzrdir)
3070
2888
        basis_tree = branch.repository.revision_tree(revision_id)
3071
2889
        if basis_tree.inventory.root is not None:
3072
2890
            wt.set_root_id(basis_tree.get_root_id())
3097
2915
        wt = WorkingTree2(a_bzrdir.root_transport.local_abspath('.'),
3098
2916
                           _internal=True,
3099
2917
                           _format=self,
3100
 
                           _bzrdir=a_bzrdir,
3101
 
                           _control_files=a_bzrdir.open_branch().control_files)
 
2918
                           _bzrdir=a_bzrdir)
3102
2919
        return wt
3103
2920
 
3104
2921
class WorkingTreeFormat3(WorkingTreeFormat):
3115
2932
 
3116
2933
    upgrade_recommended = True
3117
2934
 
3118
 
    missing_parent_conflicts = True
3119
 
 
3120
2935
    def get_format_string(self):
3121
2936
        """See WorkingTreeFormat.get_format_string()."""
3122
2937
        return "Bazaar-NG Working Tree format 3"
3235
3050
 
3236
3051
 
3237
3052
__default_format = WorkingTreeFormat6()
3238
 
format_registry.register_lazy("Bazaar Working Tree Format 4 (bzr 0.15)\n",
3239
 
    "bzrlib.workingtree_4", "WorkingTreeFormat4")
3240
 
format_registry.register_lazy("Bazaar Working Tree Format 5 (bzr 1.11)\n",
3241
 
    "bzrlib.workingtree_4", "WorkingTreeFormat5")
3242
 
format_registry.register_lazy("Bazaar Working Tree Format 6 (bzr 1.14)\n",
3243
 
    "bzrlib.workingtree_4", "WorkingTreeFormat6")
3244
 
format_registry.register(WorkingTreeFormat3())
3245
 
format_registry.set_default(__default_format)
3246
 
# Register extra formats which have no format string are not discoverable
3247
 
# and not independently creatable. They are implicitly created as part of
3248
 
# e.g. older Bazaar formats or foreign formats.
3249
 
format_registry.register_extra(WorkingTreeFormat2())
 
3053
WorkingTreeFormat.register_format(__default_format)
 
3054
WorkingTreeFormat.register_format(WorkingTreeFormat5())
 
3055
WorkingTreeFormat.register_format(WorkingTreeFormat4())
 
3056
WorkingTreeFormat.register_format(WorkingTreeFormat3())
 
3057
WorkingTreeFormat.set_default_format(__default_format)
 
3058
# formats which have no format string are not discoverable
 
3059
# and not independently creatable, so are not registered.
 
3060
_legacy_formats = [WorkingTreeFormat2(),
 
3061
                   ]