~bzr-pqm/bzr/bzr.dev

« back to all changes in this revision

Viewing changes to bzrlib/workingtree.py

  • Committer: Jelmer Vernooij
  • Date: 2012-02-20 12:19:29 UTC
  • mfrom: (6437.23.11 2.5)
  • mto: (6581.1.1 trunk)
  • mto: This revision was merged to the branch mainline in revision 6582.
  • Revision ID: jelmer@samba.org-20120220121929-7ni2psvjoatm1yp4
Merge bzr/2.5.

Show diffs side-by-side

added added

removed removed

Lines of Context:
29
29
WorkingTree.open(dir).
30
30
"""
31
31
 
 
32
from __future__ import absolute_import
32
33
 
33
34
from cStringIO import StringIO
34
35
import os
46
47
 
47
48
from bzrlib import (
48
49
    branch,
49
 
    bzrdir,
50
50
    conflicts as _mod_conflicts,
51
51
    controldir,
52
52
    errors,
54
54
    generate_ids,
55
55
    globbing,
56
56
    graph as _mod_graph,
57
 
    hashcache,
58
57
    ignores,
59
58
    inventory,
60
59
    merge,
70
69
    )
71
70
""")
72
71
 
73
 
from bzrlib import symbol_versioning
 
72
# Explicitly import bzrlib.bzrdir so that the BzrProber
 
73
# is guaranteed to be registered.
 
74
from bzrlib import (
 
75
    bzrdir,
 
76
    symbol_versioning,
 
77
    )
 
78
 
74
79
from bzrlib.decorators import needs_read_lock, needs_write_lock
 
80
from bzrlib.i18n import gettext
75
81
from bzrlib.lock import LogicalLockResult
76
82
import bzrlib.mutabletree
77
83
from bzrlib.mutabletree import needs_tree_write_lock
84
90
    realpath,
85
91
    safe_unicode,
86
92
    splitpath,
87
 
    supports_executable,
88
93
    )
89
94
from bzrlib.trace import mutter, note
90
95
from bzrlib.revision import CURRENT_REVISION
172
177
 
173
178
    def __init__(self, basedir='.',
174
179
                 branch=DEPRECATED_PARAMETER,
175
 
                 _control_files=None,
176
180
                 _internal=False,
 
181
                 _transport=None,
177
182
                 _format=None,
178
183
                 _bzrdir=None):
179
184
        """Construct a WorkingTree instance. This is not a public API.
192
197
        else:
193
198
            self._branch = self.bzrdir.open_branch()
194
199
        self.basedir = realpath(basedir)
195
 
        self._control_files = _control_files
196
 
        self._transport = self._control_files._transport
197
 
        # update the whole cache up front and write to disk if anything changed;
198
 
        # in the future we might want to do this more selectively
199
 
        # two possible ways offer themselves : in self._unlock, write the cache
200
 
        # if needed, or, when the cache sees a change, append it to the hash
201
 
        # cache file, and have the parser take the most recent entry for a
202
 
        # given path only.
203
 
        wt_trans = self.bzrdir.get_workingtree_transport(None)
204
 
        cache_filename = wt_trans.local_abspath('stat-cache')
205
 
        self._hashcache = hashcache.HashCache(basedir, cache_filename,
206
 
            self.bzrdir._get_file_mode(),
207
 
            self._content_filter_stack_provider())
208
 
        hc = self._hashcache
209
 
        hc.read()
210
 
        # is this scan needed ? it makes things kinda slow.
211
 
        #hc.scan()
212
 
 
213
 
        if hc.needs_write:
214
 
            mutter("write hc")
215
 
            hc.write()
216
 
 
217
 
        self._detect_case_handling()
 
200
        self._transport = _transport
218
201
        self._rules_searcher = None
219
202
        self.views = self._make_views()
220
203
 
238
221
        """
239
222
        return self.bzrdir.is_control_filename(filename)
240
223
 
241
 
    def _detect_case_handling(self):
242
 
        wt_trans = self.bzrdir.get_workingtree_transport(None)
243
 
        try:
244
 
            wt_trans.stat(self._format.case_sensitive_filename)
245
 
        except errors.NoSuchFile:
246
 
            self.case_sensitive = True
247
 
        else:
248
 
            self.case_sensitive = False
249
 
 
250
 
        self._setup_directory_is_tree_reference()
251
 
 
252
224
    branch = property(
253
225
        fget=lambda self: self._branch,
254
226
        doc="""The branch this WorkingTree is connected to.
257
229
            the working tree has been constructed from.
258
230
            """)
259
231
 
 
232
    def has_versioned_directories(self):
 
233
        """See `Tree.has_versioned_directories`."""
 
234
        return self._format.supports_versioned_directories
 
235
 
 
236
    def _supports_executable(self):
 
237
        if sys.platform == 'win32':
 
238
            return False
 
239
        # FIXME: Ideally this should check the file system
 
240
        return True
 
241
 
260
242
    def break_lock(self):
261
243
        """Break a lock if one is present from another instance.
262
244
 
265
247
 
266
248
        This will probe the repository for its lock as well.
267
249
        """
268
 
        self._control_files.break_lock()
269
 
        self.branch.break_lock()
 
250
        raise NotImplementedError(self.break_lock)
270
251
 
271
252
    def requires_rich_root(self):
272
253
        return self._format.requires_rich_root
287
268
        """
288
269
        if path is None:
289
270
            path = osutils.getcwd()
290
 
        control = bzrdir.BzrDir.open(path, _unsupported)
291
 
        return control.open_workingtree(_unsupported)
 
271
        control = controldir.ControlDir.open(path, _unsupported=_unsupported)
 
272
        return control.open_workingtree(unsupported=_unsupported)
292
273
 
293
274
    @staticmethod
294
275
    def open_containing(path=None):
305
286
        """
306
287
        if path is None:
307
288
            path = osutils.getcwd()
308
 
        control, relpath = bzrdir.BzrDir.open_containing(path)
 
289
        control, relpath = controldir.ControlDir.open_containing(path)
309
290
        return control.open_workingtree(), relpath
310
291
 
311
292
    @staticmethod
331
312
                if view_files:
332
313
                    file_list = view_files
333
314
                    view_str = views.view_display_str(view_files)
334
 
                    note("Ignoring files outside view. View is %s" % view_str)
 
315
                    note(gettext("Ignoring files outside view. View is %s") % view_str)
335
316
            return tree, file_list
336
317
        if default_directory == u'.':
337
318
            seed = file_list[0]
394
375
            else:
395
376
                return True, tree
396
377
        t = transport.get_transport(location)
397
 
        iterator = bzrdir.BzrDir.find_bzrdirs(t, evaluate=evaluate,
 
378
        iterator = controldir.ControlDir.find_bzrdirs(t, evaluate=evaluate,
398
379
                                              list_current=list_current)
399
380
        return [tr for tr in iterator if tr is not None]
400
381
 
522
503
        raise NotImplementedError(self.get_root_id)
523
504
 
524
505
    @needs_read_lock
525
 
    def clone(self, to_bzrdir, revision_id=None):
 
506
    def clone(self, to_controldir, revision_id=None):
526
507
        """Duplicate this working tree into to_bzr, including all state.
527
508
 
528
509
        Specifically modified files are kept as modified, but
529
510
        ignored and unknown files are discarded.
530
511
 
531
 
        If you want to make a new line of development, see bzrdir.sprout()
 
512
        If you want to make a new line of development, see ControlDir.sprout()
532
513
 
533
514
        revision
534
515
            If not None, the cloned tree will have its last revision set to
536
517
            and this one merged in.
537
518
        """
538
519
        # assumes the target bzr dir format is compatible.
539
 
        result = to_bzrdir.create_workingtree()
 
520
        result = to_controldir.create_workingtree()
540
521
        self.copy_content_into(result, revision_id)
541
522
        return result
542
523
 
550
531
            # TODO now merge from tree.last_revision to revision (to preserve
551
532
            # user local changes)
552
533
            merge.transform_tree(tree, self)
553
 
            tree.set_parent_ids([revision_id])
 
534
            if revision_id == _mod_revision.NULL_REVISION:
 
535
                new_parents = []
 
536
            else:
 
537
                new_parents = [revision_id]
 
538
            tree.set_parent_ids(new_parents)
554
539
 
555
540
    def id2abspath(self, file_id):
556
541
        return self.abspath(self.id2path(file_id))
765
750
 
766
751
    @needs_tree_write_lock
767
752
    def set_merge_modified(self, modified_hashes):
768
 
        def iter_stanzas():
769
 
            for file_id, hash in modified_hashes.iteritems():
770
 
                yield _mod_rio.Stanza(file_id=file_id.decode('utf8'),
771
 
                    hash=hash)
772
 
        self._put_rio('merge-hashes', iter_stanzas(), MERGE_MODIFIED_HEADER_1)
 
753
        """Set the merge modified hashes."""
 
754
        raise NotImplementedError(self.set_merge_modified)
773
755
 
774
756
    def _sha_from_stat(self, path, stat_result):
775
757
        """Get a sha digest from the tree's stat cache.
781
763
        """
782
764
        return None
783
765
 
784
 
    def _put_rio(self, filename, stanzas, header):
785
 
        self._must_be_locked()
786
 
        my_file = _mod_rio.rio_file(stanzas, header)
787
 
        self._transport.put_file(filename, my_file,
788
 
            mode=self.bzrdir._get_file_mode())
789
 
 
790
766
    @needs_write_lock # because merge pulls data into the branch.
791
767
    def merge_from_branch(self, branch, to_revision=None, from_revision=None,
792
768
                          merge_type=None, force=False):
1032
1008
                                show_base=show_base)
1033
1009
                    basis_root_id = basis_tree.get_root_id()
1034
1010
                    new_root_id = new_basis_tree.get_root_id()
1035
 
                    if basis_root_id != new_root_id:
 
1011
                    if new_root_id is not None and basis_root_id != new_root_id:
1036
1012
                        self.set_root_id(new_root_id)
1037
1013
                finally:
1038
1014
                    basis_tree.unlock()
1039
1015
                # TODO - dedup parents list with things merged by pull ?
1040
1016
                # reuse the revisiontree we merged against to set the new
1041
1017
                # tree data.
1042
 
                parent_trees = [(self.branch.last_revision(), new_basis_tree)]
 
1018
                parent_trees = []
 
1019
                if self.branch.last_revision() != _mod_revision.NULL_REVISION:
 
1020
                    parent_trees.append(
 
1021
                        (self.branch.last_revision(), new_basis_tree))
1043
1022
                # we have to pull the merge trees out again, because
1044
1023
                # merge_inner has set the ids. - this corner is not yet
1045
1024
                # layered well enough to prevent double handling.
1062
1041
            stream.write(bytes)
1063
1042
        finally:
1064
1043
            stream.close()
1065
 
        # TODO: update the hashcache here ?
1066
1044
 
1067
1045
    def extras(self):
1068
1046
        """Yield all unversioned files in this WorkingTree.
1145
1123
        else:
1146
1124
            mode = stat_value.st_mode
1147
1125
            kind = osutils.file_kind_from_stat_mode(mode)
1148
 
            if not supports_executable():
 
1126
            if not self._supports_executable():
1149
1127
                executable = entry is not None and entry.executable
1150
1128
            else:
1151
1129
                executable = bool(stat.S_ISREG(mode) and stat.S_IEXEC & mode)
1170
1148
        return _mod_revision.ensure_null(self.branch.last_revision())
1171
1149
 
1172
1150
    def is_locked(self):
1173
 
        return self._control_files.is_locked()
1174
 
 
1175
 
    def _must_be_locked(self):
1176
 
        if not self.is_locked():
1177
 
            raise errors.ObjectNotLocked(self)
 
1151
        """Check if this tree is locked."""
 
1152
        raise NotImplementedError(self.is_locked)
1178
1153
 
1179
1154
    def lock_read(self):
1180
1155
        """Lock the tree for reading.
1183
1158
 
1184
1159
        :return: A bzrlib.lock.LogicalLockResult.
1185
1160
        """
1186
 
        if not self.is_locked():
1187
 
            self._reset_data()
1188
 
        self.branch.lock_read()
1189
 
        try:
1190
 
            self._control_files.lock_read()
1191
 
            return LogicalLockResult(self.unlock)
1192
 
        except:
1193
 
            self.branch.unlock()
1194
 
            raise
 
1161
        raise NotImplementedError(self.lock_read)
1195
1162
 
1196
1163
    def lock_tree_write(self):
1197
1164
        """See MutableTree.lock_tree_write, and WorkingTree.unlock.
1198
1165
 
1199
1166
        :return: A bzrlib.lock.LogicalLockResult.
1200
1167
        """
1201
 
        if not self.is_locked():
1202
 
            self._reset_data()
1203
 
        self.branch.lock_read()
1204
 
        try:
1205
 
            self._control_files.lock_write()
1206
 
            return LogicalLockResult(self.unlock)
1207
 
        except:
1208
 
            self.branch.unlock()
1209
 
            raise
 
1168
        raise NotImplementedError(self.lock_tree_write)
1210
1169
 
1211
1170
    def lock_write(self):
1212
1171
        """See MutableTree.lock_write, and WorkingTree.unlock.
1213
1172
 
1214
1173
        :return: A bzrlib.lock.LogicalLockResult.
1215
1174
        """
1216
 
        if not self.is_locked():
1217
 
            self._reset_data()
1218
 
        self.branch.lock_write()
1219
 
        try:
1220
 
            self._control_files.lock_write()
1221
 
            return LogicalLockResult(self.unlock)
1222
 
        except:
1223
 
            self.branch.unlock()
1224
 
            raise
 
1175
        raise NotImplementedError(self.lock_write)
1225
1176
 
1226
1177
    def get_physical_lock_status(self):
1227
 
        return self._control_files.get_physical_lock_status()
1228
 
 
1229
 
    def _reset_data(self):
1230
 
        """Reset transient data that cannot be revalidated."""
1231
 
        raise NotImplementedError(self._reset_data)
 
1178
        raise NotImplementedError(self.get_physical_lock_status)
1232
1179
 
1233
1180
    def set_last_revision(self, new_revision):
1234
1181
        """Change the last revision in the working tree."""
1528
1475
                                             show_base=show_base)
1529
1476
            if nb_conflicts:
1530
1477
                self.add_parent_tree((old_tip, other_tree))
1531
 
                note('Rerun update after fixing the conflicts.')
 
1478
                note(gettext('Rerun update after fixing the conflicts.'))
1532
1479
                return nb_conflicts
1533
1480
 
1534
1481
        if last_rev != _mod_revision.ensure_null(revision):
1576
1523
            last_rev = parent_trees[0][0]
1577
1524
        return nb_conflicts
1578
1525
 
1579
 
    def _write_hashcache_if_dirty(self):
1580
 
        """Write out the hashcache if it is dirty."""
1581
 
        if self._hashcache.needs_write:
1582
 
            try:
1583
 
                self._hashcache.write()
1584
 
            except OSError, e:
1585
 
                if e.errno not in (errno.EPERM, errno.EACCES):
1586
 
                    raise
1587
 
                # TODO: jam 20061219 Should this be a warning? A single line
1588
 
                #       warning might be sufficient to let the user know what
1589
 
                #       is going on.
1590
 
                mutter('Could not write hashcache for %s\nError: %s',
1591
 
                              self._hashcache.cache_file_name(), e)
1592
 
 
1593
1526
    def set_conflicts(self, arg):
1594
1527
        raise errors.UnsupportedOperation(self.set_conflicts, self)
1595
1528
 
1824
1757
        :param branch: A branch to override probing for the branch.
1825
1758
        """
1826
1759
        super(InventoryWorkingTree, self).__init__(basedir=basedir,
1827
 
            branch=branch, _control_files=_control_files, _internal=_internal,
1828
 
            _format=_format, _bzrdir=_bzrdir)
 
1760
            branch=branch, _transport=_control_files._transport,
 
1761
            _internal=_internal, _format=_format, _bzrdir=_bzrdir)
 
1762
 
 
1763
        self._control_files = _control_files
 
1764
        self._detect_case_handling()
1829
1765
 
1830
1766
        if _inventory is None:
1831
1767
            # This will be acquired on lock_read() or lock_write()
1851
1787
        self._inventory = inv
1852
1788
        self._inventory_is_modified = dirty
1853
1789
 
 
1790
    def _detect_case_handling(self):
 
1791
        wt_trans = self.bzrdir.get_workingtree_transport(None)
 
1792
        try:
 
1793
            wt_trans.stat(self._format.case_sensitive_filename)
 
1794
        except errors.NoSuchFile:
 
1795
            self.case_sensitive = True
 
1796
        else:
 
1797
            self.case_sensitive = False
 
1798
 
 
1799
        self._setup_directory_is_tree_reference()
 
1800
 
1854
1801
    def _serialize(self, inventory, out_file):
1855
1802
        xml5.serializer_v5.write_inventory(self._inventory, out_file,
1856
1803
            working=True)
1858
1805
    def _deserialize(selt, in_file):
1859
1806
        return xml5.serializer_v5.read_inventory(in_file)
1860
1807
 
 
1808
    def break_lock(self):
 
1809
        """Break a lock if one is present from another instance.
 
1810
 
 
1811
        Uses the ui factory to ask for confirmation if the lock may be from
 
1812
        an active process.
 
1813
 
 
1814
        This will probe the repository for its lock as well.
 
1815
        """
 
1816
        self._control_files.break_lock()
 
1817
        self.branch.break_lock()
 
1818
 
 
1819
    def is_locked(self):
 
1820
        return self._control_files.is_locked()
 
1821
 
 
1822
    def _must_be_locked(self):
 
1823
        if not self.is_locked():
 
1824
            raise errors.ObjectNotLocked(self)
 
1825
 
 
1826
    def lock_read(self):
 
1827
        """Lock the tree for reading.
 
1828
 
 
1829
        This also locks the branch, and can be unlocked via self.unlock().
 
1830
 
 
1831
        :return: A bzrlib.lock.LogicalLockResult.
 
1832
        """
 
1833
        if not self.is_locked():
 
1834
            self._reset_data()
 
1835
        self.branch.lock_read()
 
1836
        try:
 
1837
            self._control_files.lock_read()
 
1838
            return LogicalLockResult(self.unlock)
 
1839
        except:
 
1840
            self.branch.unlock()
 
1841
            raise
 
1842
 
 
1843
    def lock_tree_write(self):
 
1844
        """See MutableTree.lock_tree_write, and WorkingTree.unlock.
 
1845
 
 
1846
        :return: A bzrlib.lock.LogicalLockResult.
 
1847
        """
 
1848
        if not self.is_locked():
 
1849
            self._reset_data()
 
1850
        self.branch.lock_read()
 
1851
        try:
 
1852
            self._control_files.lock_write()
 
1853
            return LogicalLockResult(self.unlock)
 
1854
        except:
 
1855
            self.branch.unlock()
 
1856
            raise
 
1857
 
 
1858
    def lock_write(self):
 
1859
        """See MutableTree.lock_write, and WorkingTree.unlock.
 
1860
 
 
1861
        :return: A bzrlib.lock.LogicalLockResult.
 
1862
        """
 
1863
        if not self.is_locked():
 
1864
            self._reset_data()
 
1865
        self.branch.lock_write()
 
1866
        try:
 
1867
            self._control_files.lock_write()
 
1868
            return LogicalLockResult(self.unlock)
 
1869
        except:
 
1870
            self.branch.unlock()
 
1871
            raise
 
1872
 
 
1873
    def get_physical_lock_status(self):
 
1874
        return self._control_files.get_physical_lock_status()
 
1875
 
1861
1876
    @needs_tree_write_lock
1862
1877
    def _write_inventory(self, inv):
1863
1878
        """Write inventory as the current inventory."""
2160
2175
            mode=self.bzrdir._get_file_mode())
2161
2176
        self._inventory_is_modified = False
2162
2177
 
2163
 
    @needs_read_lock
2164
 
    def get_file_sha1(self, file_id, path=None, stat_value=None):
2165
 
        if not path:
2166
 
            path = self._inventory.id2path(file_id)
2167
 
        return self._hashcache.get_sha1(path, stat_value)
2168
 
 
2169
2178
    def get_file_mtime(self, file_id, path=None):
2170
2179
        """See Tree.get_file_mtime."""
2171
2180
        if not path:
2172
2181
            path = self.inventory.id2path(file_id)
2173
 
        return os.lstat(self.abspath(path)).st_mtime
 
2182
        try:
 
2183
            return os.lstat(self.abspath(path)).st_mtime
 
2184
        except OSError, e:
 
2185
            if e.errno == errno.ENOENT:
 
2186
                raise errors.FileTimestampUnavailable(path)
 
2187
            raise
2174
2188
 
2175
2189
    def _is_executable_from_path_and_stat_from_basis(self, path, stat_result):
2176
2190
        file_id = self.path2id(path)
2184
2198
        mode = stat_result.st_mode
2185
2199
        return bool(stat.S_ISREG(mode) and stat.S_IEXEC & mode)
2186
2200
 
2187
 
    if not supports_executable():
2188
 
        def is_executable(self, file_id, path=None):
 
2201
    def is_executable(self, file_id, path=None):
 
2202
        if not self._supports_executable():
2189
2203
            return self._inventory[file_id].executable
2190
 
 
2191
 
        _is_executable_from_path_and_stat = \
2192
 
            _is_executable_from_path_and_stat_from_basis
2193
 
    else:
2194
 
        def is_executable(self, file_id, path=None):
 
2204
        else:
2195
2205
            if not path:
2196
2206
                path = self.id2path(file_id)
2197
2207
            mode = os.lstat(self.abspath(path)).st_mode
2198
2208
            return bool(stat.S_ISREG(mode) and stat.S_IEXEC & mode)
2199
2209
 
2200
 
        _is_executable_from_path_and_stat = \
2201
 
            _is_executable_from_path_and_stat_from_stat
 
2210
    def _is_executable_from_path_and_stat(self, path, stat_result):
 
2211
        if not self._supports_executable():
 
2212
            return self._is_executable_from_path_and_stat_from_basis(path, stat_result)
 
2213
        else:
 
2214
            return self._is_executable_from_path_and_stat_from_stat(path, stat_result)
2202
2215
 
2203
2216
    @needs_tree_write_lock
2204
2217
    def _add(self, files, ids, kinds):
2283
2296
                       for key, line in annotator.annotate_flat(this_key)]
2284
2297
        return annotations
2285
2298
 
 
2299
    def _put_rio(self, filename, stanzas, header):
 
2300
        self._must_be_locked()
 
2301
        my_file = _mod_rio.rio_file(stanzas, header)
 
2302
        self._transport.put_file(filename, my_file,
 
2303
            mode=self.bzrdir._get_file_mode())
 
2304
 
 
2305
    @needs_tree_write_lock
 
2306
    def set_merge_modified(self, modified_hashes):
 
2307
        def iter_stanzas():
 
2308
            for file_id, hash in modified_hashes.iteritems():
 
2309
                yield _mod_rio.Stanza(file_id=file_id.decode('utf8'),
 
2310
                    hash=hash)
 
2311
        self._put_rio('merge-hashes', iter_stanzas(), MERGE_MODIFIED_HEADER_1)
 
2312
 
2286
2313
    @needs_read_lock
2287
2314
    def merge_modified(self):
2288
2315
        """Return a dictionary of files modified by a merge.
2393
2420
        tree_transport = self.bzrdir.root_transport.clone(sub_path)
2394
2421
        if tree_transport.base != branch_transport.base:
2395
2422
            tree_bzrdir = format.initialize_on_transport(tree_transport)
2396
 
            branch.BranchReferenceFormat().initialize(tree_bzrdir,
2397
 
                target_branch=new_branch)
 
2423
            tree_bzrdir.set_branch_reference(new_branch)
2398
2424
        else:
2399
2425
            tree_bzrdir = branch_bzrdir
2400
2426
        wt = tree_bzrdir.create_workingtree(_mod_revision.NULL_REVISION)
2778
2804
                # something is wrong, so lets determine what exactly
2779
2805
                if not self.has_filename(from_rel) and \
2780
2806
                   not self.has_filename(to_rel):
2781
 
                    raise errors.BzrRenameFailedError(from_rel,to_rel,
2782
 
                        errors.PathsDoNotExist(paths=(str(from_rel),
2783
 
                        str(to_rel))))
 
2807
                    raise errors.BzrRenameFailedError(from_rel, to_rel,
 
2808
                        errors.PathsDoNotExist(paths=(from_rel, to_rel)))
2784
2809
                else:
2785
2810
                    raise errors.RenameFailedFilesExist(from_rel, to_rel)
2786
2811
            rename_entry.only_change_inv = only_change_inv
2951
2976
                if dir[2] == _directory:
2952
2977
                    pending.append(dir)
2953
2978
 
 
2979
    @needs_write_lock
 
2980
    def update_feature_flags(self, updated_flags):
 
2981
        """Update the feature flags for this branch.
 
2982
 
 
2983
        :param updated_flags: Dictionary mapping feature names to necessities
 
2984
            A necessity can be None to indicate the feature should be removed
 
2985
        """
 
2986
        self._format._update_feature_flags(updated_flags)
 
2987
        self.control_transport.put_bytes('format', self._format.as_string())
 
2988
 
2954
2989
 
2955
2990
class WorkingTreeFormatRegistry(controldir.ControlComponentFormatRegistry):
2956
2991
    """Registry for working tree formats."""
3012
3047
 
3013
3048
    supports_versioned_directories = None
3014
3049
 
3015
 
    @classmethod
3016
 
    def find_format_string(klass, a_bzrdir):
3017
 
        """Return format name for the working tree object in a_bzrdir."""
3018
 
        try:
3019
 
            transport = a_bzrdir.get_workingtree_transport(None)
3020
 
            return transport.get_bytes("format")
3021
 
        except errors.NoSuchFile:
3022
 
            raise errors.NoWorkingTree(base=transport.base)
3023
 
 
3024
 
    @classmethod
3025
 
    def find_format(klass, a_bzrdir):
3026
 
        """Return the format for the working tree object in a_bzrdir."""
3027
 
        try:
3028
 
            format_string = klass.find_format_string(a_bzrdir)
3029
 
            return format_registry.get(format_string)
3030
 
        except KeyError:
3031
 
            raise errors.UnknownFormatError(format=format_string,
3032
 
                                            kind="working tree")
3033
 
 
3034
 
    def initialize(self, a_bzrdir, revision_id=None, from_branch=None,
 
3050
    def initialize(self, controldir, revision_id=None, from_branch=None,
3035
3051
                   accelerator_tree=None, hardlink=False):
3036
 
        """Initialize a new working tree in a_bzrdir.
 
3052
        """Initialize a new working tree in controldir.
3037
3053
 
3038
 
        :param a_bzrdir: BzrDir to initialize the working tree in.
 
3054
        :param controldir: ControlDir to initialize the working tree in.
3039
3055
        :param revision_id: allows creating a working tree at a different
3040
3056
            revision than the branch is at.
3041
3057
        :param from_branch: Branch to checkout
3061
3077
        """Return the current default format."""
3062
3078
        return format_registry.get_default()
3063
3079
 
3064
 
    def get_format_string(self):
3065
 
        """Return the ASCII format string that identifies this format."""
3066
 
        raise NotImplementedError(self.get_format_string)
3067
 
 
3068
3080
    def get_format_description(self):
3069
3081
        """Return the short description for this format."""
3070
3082
        raise NotImplementedError(self.get_format_description)
3122
3134
    def unregister_format(klass, format):
3123
3135
        format_registry.remove(format)
3124
3136
 
 
3137
    def get_controldir_for_branch(self):
 
3138
        """Get the control directory format for creating branches.
 
3139
 
 
3140
        This is to support testing of working tree formats that can not exist
 
3141
        in the same control directory as a branch.
 
3142
        """
 
3143
        return self._matchingbzrdir
 
3144
 
 
3145
 
 
3146
class WorkingTreeFormatMetaDir(bzrdir.BzrFormat, WorkingTreeFormat):
 
3147
    """Base class for working trees that live in bzr meta directories."""
 
3148
 
 
3149
    def __init__(self):
 
3150
        WorkingTreeFormat.__init__(self)
 
3151
        bzrdir.BzrFormat.__init__(self)
 
3152
 
 
3153
    @classmethod
 
3154
    def find_format_string(klass, controldir):
 
3155
        """Return format name for the working tree object in controldir."""
 
3156
        try:
 
3157
            transport = controldir.get_workingtree_transport(None)
 
3158
            return transport.get_bytes("format")
 
3159
        except errors.NoSuchFile:
 
3160
            raise errors.NoWorkingTree(base=transport.base)
 
3161
 
 
3162
    @classmethod
 
3163
    def find_format(klass, controldir):
 
3164
        """Return the format for the working tree object in controldir."""
 
3165
        format_string = klass.find_format_string(controldir)
 
3166
        return klass._find_format(format_registry, 'working tree',
 
3167
                format_string)
 
3168
 
 
3169
    def check_support_status(self, allow_unsupported, recommend_upgrade=True,
 
3170
            basedir=None):
 
3171
        WorkingTreeFormat.check_support_status(self,
 
3172
            allow_unsupported=allow_unsupported, recommend_upgrade=recommend_upgrade,
 
3173
            basedir=basedir)
 
3174
        bzrdir.BzrFormat.check_support_status(self, allow_unsupported=allow_unsupported,
 
3175
            recommend_upgrade=recommend_upgrade, basedir=basedir)
 
3176
 
3125
3177
 
3126
3178
format_registry.register_lazy("Bazaar Working Tree Format 4 (bzr 0.15)\n",
3127
3179
    "bzrlib.workingtree_4", "WorkingTreeFormat4")