/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: Jelmer Vernooij
  • Date: 2011-02-25 15:24:22 UTC
  • mto: This revision was merged to the branch mainline in revision 5690.
  • Revision ID: jelmer@samba.org-20110225152422-d1pjdfnzsw5ufe2x
Fix tests on Debian GNU/kFreeBSD by treating it like other FreeBSD-kernel-based systems.

Show diffs side-by-side

added added

removed removed

Lines of Context:
1
 
# Copyright (C) 2005-2010 Canonical Ltd
 
1
# Copyright (C) 2005-2011 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,
52
53
    errors,
53
54
    generate_ids,
54
55
    globbing,
57
58
    ignores,
58
59
    inventory,
59
60
    merge,
 
61
    registry,
60
62
    revision as _mod_revision,
61
63
    revisiontree,
62
64
    trace,
63
65
    transform,
 
66
    transport,
64
67
    ui,
65
68
    views,
66
69
    xml5,
67
70
    xml7,
68
71
    )
69
 
import bzrlib.branch
70
 
from bzrlib.transport import get_transport
71
72
from bzrlib.workingtree_4 import (
72
73
    WorkingTreeFormat4,
73
74
    WorkingTreeFormat5,
77
78
 
78
79
from bzrlib import symbol_versioning
79
80
from bzrlib.decorators import needs_read_lock, needs_write_lock
 
81
from bzrlib.lock import LogicalLockResult
80
82
from bzrlib.lockable_files import LockableFiles
81
83
from bzrlib.lockdir import LockDir
82
84
import bzrlib.mutabletree
168
170
 
169
171
 
170
172
class WorkingTree(bzrlib.mutabletree.MutableTree,
171
 
    bzrdir.ControlComponent):
 
173
    controldir.ControlComponent):
172
174
    """Working copy tree.
173
175
 
174
176
    The inventory is held in the `Branch` working-inventory, and the
176
178
 
177
179
    It is possible for a `WorkingTree` to have a filename which is
178
180
    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).
179
184
    """
180
185
 
181
186
    # override this to set the strategy for storing views
205
210
        else:
206
211
            self._branch = self.bzrdir.open_branch()
207
212
        self.basedir = realpath(basedir)
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
        self._control_files = _control_files
215
214
        self._transport = self._control_files._transport
216
215
        # update the whole cache up front and write to disk if anything changed;
217
216
        # in the future we might want to do this more selectively
258
257
    def _detect_case_handling(self):
259
258
        wt_trans = self.bzrdir.get_workingtree_transport(None)
260
259
        try:
261
 
            wt_trans.stat("FoRMaT")
 
260
            wt_trans.stat(self._format.case_sensitive_filename)
262
261
        except errors.NoSuchFile:
263
262
            self.case_sensitive = True
264
263
        else:
346
345
        if path is None:
347
346
            path = osutils.getcwd()
348
347
        control, relpath = bzrdir.BzrDir.open_containing(path)
349
 
 
350
348
        return control.open_workingtree(), relpath
351
349
 
352
350
    @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
353
417
    def open_downlevel(path=None):
354
418
        """Open an unsupported working tree.
355
419
 
368
432
                return True, None
369
433
            else:
370
434
                return True, tree
371
 
        transport = get_transport(location)
372
 
        iterator = bzrdir.BzrDir.find_bzrdirs(transport, evaluate=evaluate,
 
435
        t = transport.get_transport(location)
 
436
        iterator = bzrdir.BzrDir.find_bzrdirs(t, evaluate=evaluate,
373
437
                                              list_current=list_current)
374
 
        return [t for t in iterator if t is not None]
 
438
        return [tr for tr in iterator if tr is not None]
375
439
 
376
440
    # should be deprecated - this is slow and in any case treating them as a
377
441
    # container is (we now know) bad style -- mbp 20070302
462
526
        return (file_obj, stat_value)
463
527
 
464
528
    def get_file_text(self, file_id, path=None, filtered=True):
465
 
        return self.get_file(file_id, path=path, filtered=filtered).read()
 
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()
466
534
 
467
535
    def get_file_byname(self, filename, filtered=True):
468
536
        path = self.abspath(filename)
522
590
 
523
591
        # Now we have the parents of this content
524
592
        annotator = self.branch.repository.texts.get_annotator()
525
 
        text = self.get_file(file_id).read()
 
593
        text = self.get_file_text(file_id)
526
594
        this_key =(file_id, default_revision)
527
595
        annotator.add_special_text(this_key, file_parent_keys, text)
528
596
        annotations = [(key[-1], line)
1202
1270
                # absolute path
1203
1271
                fap = from_dir_abspath + '/' + f
1204
1272
 
1205
 
                f_ie = inv.get_child(from_dir_id, f)
 
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
1206
1278
                if f_ie:
1207
1279
                    c = 'V'
1208
1280
                elif self.is_ignored(fp[1:]):
1209
1281
                    c = 'I'
1210
1282
                else:
1211
 
                    # we may not have found this file, because of a unicode issue
 
1283
                    # we may not have found this file, because of a unicode
 
1284
                    # issue, or because the directory was actually a symlink.
1212
1285
                    f_norm, can_access = osutils.normalized_filename(f)
1213
1286
                    if f == f_norm or not can_access:
1214
1287
                        # No change, so treat this file normally
1257
1330
                stack.pop()
1258
1331
 
1259
1332
    @needs_tree_write_lock
1260
 
    def move(self, from_paths, to_dir=None, after=False, **kwargs):
 
1333
    def move(self, from_paths, to_dir=None, after=False):
1261
1334
        """Rename files.
1262
1335
 
1263
1336
        to_dir must exist in the inventory.
1297
1370
 
1298
1371
        # check for deprecated use of signature
1299
1372
        if to_dir is None:
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
            raise TypeError('You must supply a target directory')
1308
1374
        # check destination directory
1309
1375
        if isinstance(from_paths, basestring):
1310
1376
            raise ValueError()
1319
1385
        to_dir_id = inv.path2id(to_dir)
1320
1386
        if to_dir_id is None:
1321
1387
            raise errors.BzrMoveFailedError('',to_dir,
1322
 
                errors.NotVersionedError(path=str(to_dir)))
 
1388
                errors.NotVersionedError(path=to_dir))
1323
1389
 
1324
1390
        to_dir_ie = inv[to_dir_id]
1325
1391
        if to_dir_ie.kind != 'directory':
1332
1398
            from_id = inv.path2id(from_rel)
1333
1399
            if from_id is None:
1334
1400
                raise errors.BzrMoveFailedError(from_rel,to_dir,
1335
 
                    errors.NotVersionedError(path=str(from_rel)))
 
1401
                    errors.NotVersionedError(path=from_rel))
1336
1402
 
1337
1403
            from_entry = inv[from_id]
1338
1404
            from_parent_id = from_entry.parent_id
1380
1446
            # check the inventory for source and destination
1381
1447
            if from_id is None:
1382
1448
                raise errors.BzrMoveFailedError(from_rel,to_rel,
1383
 
                    errors.NotVersionedError(path=str(from_rel)))
 
1449
                    errors.NotVersionedError(path=from_rel))
1384
1450
            if to_id is not None:
1385
1451
                raise errors.BzrMoveFailedError(from_rel,to_rel,
1386
 
                    errors.AlreadyVersionedError(path=str(to_rel)))
 
1452
                    errors.AlreadyVersionedError(path=to_rel))
1387
1453
 
1388
1454
            # try to determine the mode for rename (only change inv or change
1389
1455
            # inv and file system)
1390
1456
            if after:
1391
1457
                if not self.has_filename(to_rel):
1392
1458
                    raise errors.BzrMoveFailedError(from_id,to_rel,
1393
 
                        errors.NoSuchFile(path=str(to_rel),
 
1459
                        errors.NoSuchFile(path=to_rel,
1394
1460
                        extra="New file has not been created yet"))
1395
1461
                only_change_inv = True
1396
1462
            elif not self.has_filename(from_rel) and self.has_filename(to_rel):
1498
1564
            from_id = basis_tree.path2id(from_rel)
1499
1565
            if from_id is None:
1500
1566
                raise errors.BzrRenameFailedError(from_rel,to_rel,
1501
 
                    errors.NotVersionedError(path=str(from_rel)))
 
1567
                    errors.NotVersionedError(path=from_rel))
1502
1568
            # put entry back in the inventory so we can rename it
1503
1569
            from_entry = basis_tree.inventory[from_id].copy()
1504
1570
            inv.add(from_entry)
1522
1588
        # versioned
1523
1589
        if to_dir_id is None:
1524
1590
            raise errors.BzrMoveFailedError(from_rel,to_rel,
1525
 
                errors.NotVersionedError(path=str(to_dir)))
 
1591
                errors.NotVersionedError(path=to_dir))
1526
1592
 
1527
1593
        # all checks done. now we can continue with our actual work
1528
1594
        mutter('rename_one:\n'
1600
1666
 
1601
1667
    @needs_write_lock
1602
1668
    def pull(self, source, overwrite=False, stop_revision=None,
1603
 
             change_reporter=None, possible_transports=None, local=False):
 
1669
             change_reporter=None, possible_transports=None, local=False,
 
1670
             show_base=False):
1604
1671
        source.lock_read()
1605
1672
        try:
1606
1673
            old_revision_info = self.branch.last_revision_info()
1620
1687
                                basis_tree,
1621
1688
                                this_tree=self,
1622
1689
                                pb=None,
1623
 
                                change_reporter=change_reporter)
 
1690
                                change_reporter=change_reporter,
 
1691
                                show_base=show_base)
1624
1692
                    basis_root_id = basis_tree.get_root_id()
1625
1693
                    new_root_id = new_basis_tree.get_root_id()
1626
1694
                    if basis_root_id != new_root_id:
1798
1866
            raise errors.ObjectNotLocked(self)
1799
1867
 
1800
1868
    def lock_read(self):
1801
 
        """See Branch.lock_read, and WorkingTree.unlock."""
 
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
        """
1802
1875
        if not self.is_locked():
1803
1876
            self._reset_data()
1804
1877
        self.branch.lock_read()
1805
1878
        try:
1806
 
            return self._control_files.lock_read()
 
1879
            self._control_files.lock_read()
 
1880
            return LogicalLockResult(self.unlock)
1807
1881
        except:
1808
1882
            self.branch.unlock()
1809
1883
            raise
1810
1884
 
1811
1885
    def lock_tree_write(self):
1812
 
        """See MutableTree.lock_tree_write, and WorkingTree.unlock."""
 
1886
        """See MutableTree.lock_tree_write, and WorkingTree.unlock.
 
1887
 
 
1888
        :return: A bzrlib.lock.LogicalLockResult.
 
1889
        """
1813
1890
        if not self.is_locked():
1814
1891
            self._reset_data()
1815
1892
        self.branch.lock_read()
1816
1893
        try:
1817
 
            return self._control_files.lock_write()
 
1894
            self._control_files.lock_write()
 
1895
            return LogicalLockResult(self.unlock)
1818
1896
        except:
1819
1897
            self.branch.unlock()
1820
1898
            raise
1821
1899
 
1822
1900
    def lock_write(self):
1823
 
        """See MutableTree.lock_write, and WorkingTree.unlock."""
 
1901
        """See MutableTree.lock_write, and WorkingTree.unlock.
 
1902
 
 
1903
        :return: A bzrlib.lock.LogicalLockResult.
 
1904
        """
1824
1905
        if not self.is_locked():
1825
1906
            self._reset_data()
1826
1907
        self.branch.lock_write()
1827
1908
        try:
1828
 
            return self._control_files.lock_write()
 
1909
            self._control_files.lock_write()
 
1910
            return LogicalLockResult(self.unlock)
1829
1911
        except:
1830
1912
            self.branch.unlock()
1831
1913
            raise
1948
2030
 
1949
2031
        inv_delta = []
1950
2032
 
1951
 
        new_files=set()
 
2033
        all_files = set() # specified and nested files 
1952
2034
        unknown_nested_files=set()
1953
2035
        if to_file is None:
1954
2036
            to_file = sys.stdout
1955
2037
 
 
2038
        files_to_backup = []
 
2039
 
1956
2040
        def recurse_directory_to_add_files(directory):
1957
2041
            # Recurse directory and add all files
1958
2042
            # so we can check if they have changed.
1959
 
            for parent_info, file_infos in\
1960
 
                self.walkdirs(directory):
 
2043
            for parent_info, file_infos in self.walkdirs(directory):
1961
2044
                for relpath, basename, kind, lstat, fileid, kind in file_infos:
1962
2045
                    # Is it versioned or ignored?
1963
 
                    if self.path2id(relpath) or self.is_ignored(relpath):
 
2046
                    if self.path2id(relpath):
1964
2047
                        # Add nested content for deletion.
1965
 
                        new_files.add(relpath)
 
2048
                        all_files.add(relpath)
1966
2049
                    else:
1967
 
                        # Files which are not versioned and not ignored
 
2050
                        # Files which are not versioned
1968
2051
                        # should be treated as unknown.
1969
 
                        unknown_nested_files.add((relpath, None, kind))
 
2052
                        files_to_backup.append(relpath)
1970
2053
 
1971
2054
        for filename in files:
1972
2055
            # Get file name into canonical form.
1973
2056
            abspath = self.abspath(filename)
1974
2057
            filename = self.relpath(abspath)
1975
2058
            if len(filename) > 0:
1976
 
                new_files.add(filename)
 
2059
                all_files.add(filename)
1977
2060
                recurse_directory_to_add_files(filename)
1978
2061
 
1979
 
        files = list(new_files)
 
2062
        files = list(all_files)
1980
2063
 
1981
2064
        if len(files) == 0:
1982
2065
            return # nothing to do
1986
2069
 
1987
2070
        # Bail out if we are going to delete files we shouldn't
1988
2071
        if not keep_files and not force:
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
 
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])
2005
2084
 
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)
 
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)
2015
2090
 
2016
2091
        # Build inv_delta and delete files where applicable,
2017
2092
        # do this before any modifications to inventory.
2041
2116
                        len(os.listdir(abs_path)) > 0):
2042
2117
                        if force:
2043
2118
                            osutils.rmtree(abs_path)
 
2119
                            message = "deleted %s" % (f,)
2044
2120
                        else:
2045
 
                            message = "%s is not an empty directory "\
2046
 
                                "and won't be deleted." % (f,)
 
2121
                            message = backup(f)
2047
2122
                    else:
2048
 
                        osutils.delete_any(abs_path)
2049
 
                        message = "deleted %s" % (f,)
 
2123
                        if f in files_to_backup:
 
2124
                            message = backup(f)
 
2125
                        else:
 
2126
                            osutils.delete_any(abs_path)
 
2127
                            message = "deleted %s" % (f,)
2050
2128
                elif message is not None:
2051
2129
                    # Only care if we haven't done anything yet.
2052
2130
                    message = "%s does not exist." % (f,)
2189
2267
    _marker = object()
2190
2268
 
2191
2269
    def update(self, change_reporter=None, possible_transports=None,
2192
 
               revision=None, old_tip=_marker):
 
2270
               revision=None, old_tip=_marker, show_base=False):
2193
2271
        """Update a working tree along its branch.
2194
2272
 
2195
2273
        This will update the branch if its bound too, which means we have
2232
2310
            else:
2233
2311
                if old_tip is self._marker:
2234
2312
                    old_tip = None
2235
 
            return self._update_tree(old_tip, change_reporter, revision)
 
2313
            return self._update_tree(old_tip, change_reporter, revision, show_base)
2236
2314
        finally:
2237
2315
            self.unlock()
2238
2316
 
2239
2317
    @needs_tree_write_lock
2240
 
    def _update_tree(self, old_tip=None, change_reporter=None, revision=None):
 
2318
    def _update_tree(self, old_tip=None, change_reporter=None, revision=None,
 
2319
                     show_base=False):
2241
2320
        """Update a tree to the master branch.
2242
2321
 
2243
2322
        :param old_tip: if supplied, the previous tip revision the branch,
2270
2349
            other_tree = self.branch.repository.revision_tree(old_tip)
2271
2350
            nb_conflicts = merge.merge_inner(self.branch, other_tree,
2272
2351
                                             base_tree, this_tree=self,
2273
 
                                             change_reporter=change_reporter)
 
2352
                                             change_reporter=change_reporter,
 
2353
                                             show_base=show_base)
2274
2354
            if nb_conflicts:
2275
2355
                self.add_parent_tree((old_tip, other_tree))
2276
2356
                trace.note('Rerun update after fixing the conflicts.')
2300
2380
 
2301
2381
            nb_conflicts = merge.merge_inner(self.branch, to_tree, base_tree,
2302
2382
                                             this_tree=self,
2303
 
                                             change_reporter=change_reporter)
 
2383
                                             change_reporter=change_reporter,
 
2384
                                             show_base=show_base)
2304
2385
            self.set_last_revision(revision)
2305
2386
            # TODO - dedup parents list with things merged by pull ?
2306
2387
            # reuse the tree we've updated to to set the basis:
2595
2676
        """
2596
2677
        return
2597
2678
 
 
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
 
2598
2707
    def _get_rules_searcher(self, default_searcher):
2599
2708
        """See Tree._get_rules_searcher."""
2600
2709
        if self._rules_searcher is None:
2636
2745
 
2637
2746
        In Format2 WorkingTrees we have a single lock for the branch and tree
2638
2747
        so lock_tree_write() degrades to lock_write().
 
2748
 
 
2749
        :return: An object with an unlock method which will release the lock
 
2750
            obtained.
2639
2751
        """
2640
2752
        self.branch.lock_write()
2641
2753
        try:
2642
 
            return self._control_files.lock_write()
 
2754
            self._control_files.lock_write()
 
2755
            return self
2643
2756
        except:
2644
2757
            self.branch.unlock()
2645
2758
            raise
2746
2859
            return path[:-len(suffix)]
2747
2860
 
2748
2861
 
2749
 
class WorkingTreeFormat(object):
 
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):
2750
2881
    """An encapsulation of the initialization and open routines for a format.
2751
2882
 
2752
2883
    Formats provide three things:
2764
2895
    object will be created every time regardless.
2765
2896
    """
2766
2897
 
2767
 
    _default_format = None
2768
 
    """The default format used for new trees."""
2769
 
 
2770
 
    _formats = {}
2771
 
    """The known formats."""
2772
 
 
2773
2898
    requires_rich_root = False
2774
2899
 
2775
2900
    upgrade_recommended = False
2776
2901
 
 
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
 
2777
2909
    @classmethod
2778
2910
    def find_format(klass, a_bzrdir):
2779
2911
        """Return the format for the working tree object in a_bzrdir."""
2780
2912
        try:
2781
2913
            transport = a_bzrdir.get_workingtree_transport(None)
2782
2914
            format_string = transport.get_bytes("format")
2783
 
            return klass._formats[format_string]
 
2915
            return format_registry.get(format_string)
2784
2916
        except errors.NoSuchFile:
2785
2917
            raise errors.NoWorkingTree(base=transport.base)
2786
2918
        except KeyError:
2787
2919
            raise errors.UnknownFormatError(format=format_string,
2788
2920
                                            kind="working tree")
2789
2921
 
 
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
 
2790
2939
    def __eq__(self, other):
2791
2940
        return self.__class__ is other.__class__
2792
2941
 
2794
2943
        return not (self == other)
2795
2944
 
2796
2945
    @classmethod
 
2946
    @symbol_versioning.deprecated_method(
 
2947
        symbol_versioning.deprecated_in((2, 4, 0)))
2797
2948
    def get_default_format(klass):
2798
2949
        """Return the current default format."""
2799
 
        return klass._default_format
 
2950
        return format_registry.get_default()
2800
2951
 
2801
2952
    def get_format_string(self):
2802
2953
        """Return the ASCII format string that identifies this format."""
2824
2975
        return False
2825
2976
 
2826
2977
    @classmethod
 
2978
    @symbol_versioning.deprecated_method(
 
2979
        symbol_versioning.deprecated_in((2, 4, 0)))
2827
2980
    def register_format(klass, format):
2828
 
        klass._formats[format.get_format_string()] = format
2829
 
 
2830
 
    @classmethod
 
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)))
2831
3004
    def set_default_format(klass, format):
2832
 
        klass._default_format = format
 
3005
        format_registry.set_default(format)
2833
3006
 
2834
3007
    @classmethod
 
3008
    @symbol_versioning.deprecated_method(
 
3009
        symbol_versioning.deprecated_in((2, 4, 0)))
2835
3010
    def unregister_format(klass, format):
2836
 
        del klass._formats[format.get_format_string()]
 
3011
        format_registry.remove(format)
2837
3012
 
2838
3013
 
2839
3014
class WorkingTreeFormat2(WorkingTreeFormat):
2844
3019
 
2845
3020
    upgrade_recommended = True
2846
3021
 
 
3022
    requires_normalized_unicode_filenames = True
 
3023
 
 
3024
    case_sensitive_filename = "Branch-FoRMaT"
 
3025
 
 
3026
    missing_parent_conflicts = False
 
3027
 
2847
3028
    def get_format_description(self):
2848
3029
        """See WorkingTreeFormat.get_format_description()."""
2849
3030
        return "Working tree format 2"
2884
3065
                         inv,
2885
3066
                         _internal=True,
2886
3067
                         _format=self,
2887
 
                         _bzrdir=a_bzrdir)
 
3068
                         _bzrdir=a_bzrdir,
 
3069
                         _control_files=branch.control_files)
2888
3070
        basis_tree = branch.repository.revision_tree(revision_id)
2889
3071
        if basis_tree.inventory.root is not None:
2890
3072
            wt.set_root_id(basis_tree.get_root_id())
2915
3097
        wt = WorkingTree2(a_bzrdir.root_transport.local_abspath('.'),
2916
3098
                           _internal=True,
2917
3099
                           _format=self,
2918
 
                           _bzrdir=a_bzrdir)
 
3100
                           _bzrdir=a_bzrdir,
 
3101
                           _control_files=a_bzrdir.open_branch().control_files)
2919
3102
        return wt
2920
3103
 
2921
3104
class WorkingTreeFormat3(WorkingTreeFormat):
2932
3115
 
2933
3116
    upgrade_recommended = True
2934
3117
 
 
3118
    missing_parent_conflicts = True
 
3119
 
2935
3120
    def get_format_string(self):
2936
3121
        """See WorkingTreeFormat.get_format_string()."""
2937
3122
        return "Bazaar-NG Working Tree format 3"
3050
3235
 
3051
3236
 
3052
3237
__default_format = WorkingTreeFormat6()
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
 
                   ]
 
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())