73
from bzrlib import symbol_versioning
72
# Explicitly import bzrlib.bzrdir so that the BzrProber
73
# is guaranteed to be registered.
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
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
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())
210
# is this scan needed ? it makes things kinda slow.
217
self._detect_case_handling()
200
self._transport = _transport
218
201
self._rules_searcher = None
219
202
self.views = self._make_views()
239
222
return self.bzrdir.is_control_filename(filename)
241
def _detect_case_handling(self):
242
wt_trans = self.bzrdir.get_workingtree_transport(None)
244
wt_trans.stat(self._format.case_sensitive_filename)
245
except errors.NoSuchFile:
246
self.case_sensitive = True
248
self.case_sensitive = False
250
self._setup_directory_is_tree_reference()
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.
232
def has_versioned_directories(self):
233
"""See `Tree.has_versioned_directories`."""
234
return self._format.supports_versioned_directories
236
def _supports_executable(self):
237
if sys.platform == 'win32':
239
# FIXME: Ideally this should check the file system
260
242
def break_lock(self):
261
243
"""Break a lock if one is present from another instance.
280
261
def supports_views(self):
281
262
return self.views.supports_views()
264
def get_config_stack(self):
265
"""Retrieve the config stack for this tree.
267
:return: A ``bzrlib.config.Stack``
269
# For the moment, just provide the branch config stack.
270
return self.branch.get_config_stack()
284
273
def open(path=None, _unsupported=False):
285
274
"""Open an existing working tree at path.
395
384
return True, tree
396
385
t = transport.get_transport(location)
397
iterator = bzrdir.BzrDir.find_bzrdirs(t, evaluate=evaluate,
386
iterator = controldir.ControlDir.find_bzrdirs(t, evaluate=evaluate,
398
387
list_current=list_current)
399
388
return [tr for tr in iterator if tr is not None]
401
def all_file_ids(self):
402
"""See Tree.iter_all_file_ids"""
403
raise NotImplementedError(self.all_file_ids)
405
390
def __repr__(self):
406
391
return "<%s of %s>" % (self.__class__.__name__,
407
392
getattr(self, 'basedir', None))
522
507
raise NotImplementedError(self.get_root_id)
525
def clone(self, to_bzrdir, revision_id=None):
510
def clone(self, to_controldir, revision_id=None):
526
511
"""Duplicate this working tree into to_bzr, including all state.
528
513
Specifically modified files are kept as modified, but
529
514
ignored and unknown files are discarded.
531
If you want to make a new line of development, see bzrdir.sprout()
516
If you want to make a new line of development, see ControlDir.sprout()
534
519
If not None, the cloned tree will have its last revision set to
550
535
# TODO now merge from tree.last_revision to revision (to preserve
551
536
# user local changes)
552
537
merge.transform_tree(tree, self)
553
tree.set_parent_ids([revision_id])
538
if revision_id == _mod_revision.NULL_REVISION:
541
new_parents = [revision_id]
542
tree.set_parent_ids(new_parents)
555
544
def id2abspath(self, file_id):
556
545
return self.abspath(self.id2path(file_id))
770
755
@needs_tree_write_lock
771
756
def set_merge_modified(self, modified_hashes):
773
for file_id, hash in modified_hashes.iteritems():
774
yield _mod_rio.Stanza(file_id=file_id.decode('utf8'),
776
self._put_rio('merge-hashes', iter_stanzas(), MERGE_MODIFIED_HEADER_1)
757
"""Set the merge modified hashes."""
758
raise NotImplementedError(self.set_merge_modified)
778
760
def _sha_from_stat(self, path, stat_result):
779
761
"""Get a sha digest from the tree's stat cache.
788
def _put_rio(self, filename, stanzas, header):
789
self._must_be_locked()
790
my_file = _mod_rio.rio_file(stanzas, header)
791
self._transport.put_file(filename, my_file,
792
mode=self.bzrdir._get_file_mode())
794
770
@needs_write_lock # because merge pulls data into the branch.
795
771
def merge_from_branch(self, branch, to_revision=None, from_revision=None,
796
772
merge_type=None, force=False):
1036
1012
show_base=show_base)
1037
1013
basis_root_id = basis_tree.get_root_id()
1038
1014
new_root_id = new_basis_tree.get_root_id()
1039
if basis_root_id != new_root_id:
1015
if new_root_id is not None and basis_root_id != new_root_id:
1040
1016
self.set_root_id(new_root_id)
1042
1018
basis_tree.unlock()
1043
1019
# TODO - dedup parents list with things merged by pull ?
1044
1020
# reuse the revisiontree we merged against to set the new
1046
parent_trees = [(self.branch.last_revision(), new_basis_tree)]
1023
if self.branch.last_revision() != _mod_revision.NULL_REVISION:
1024
parent_trees.append(
1025
(self.branch.last_revision(), new_basis_tree))
1047
1026
# we have to pull the merge trees out again, because
1048
1027
# merge_inner has set the ids. - this corner is not yet
1049
1028
# layered well enough to prevent double handling.
1188
1163
:return: A bzrlib.lock.LogicalLockResult.
1190
if not self.is_locked():
1192
self.branch.lock_read()
1194
self._control_files.lock_read()
1195
return LogicalLockResult(self.unlock)
1197
self.branch.unlock()
1165
raise NotImplementedError(self.lock_read)
1200
1167
def lock_tree_write(self):
1201
1168
"""See MutableTree.lock_tree_write, and WorkingTree.unlock.
1203
1170
:return: A bzrlib.lock.LogicalLockResult.
1205
if not self.is_locked():
1207
self.branch.lock_read()
1209
self._control_files.lock_write()
1210
return LogicalLockResult(self.unlock)
1212
self.branch.unlock()
1172
raise NotImplementedError(self.lock_tree_write)
1215
1174
def lock_write(self):
1216
1175
"""See MutableTree.lock_write, and WorkingTree.unlock.
1218
1177
:return: A bzrlib.lock.LogicalLockResult.
1220
if not self.is_locked():
1222
self.branch.lock_write()
1224
self._control_files.lock_write()
1225
return LogicalLockResult(self.unlock)
1227
self.branch.unlock()
1179
raise NotImplementedError(self.lock_write)
1230
1181
def get_physical_lock_status(self):
1231
return self._control_files.get_physical_lock_status()
1233
def _reset_data(self):
1234
"""Reset transient data that cannot be revalidated."""
1235
raise NotImplementedError(self._reset_data)
1182
raise NotImplementedError(self.get_physical_lock_status)
1237
1184
def set_last_revision(self, new_revision):
1238
1185
"""Change the last revision in the working tree."""
1580
1527
last_rev = parent_trees[0][0]
1581
1528
return nb_conflicts
1583
def _write_hashcache_if_dirty(self):
1584
"""Write out the hashcache if it is dirty."""
1585
if self._hashcache.needs_write:
1587
self._hashcache.write()
1589
if e.errno not in (errno.EPERM, errno.EACCES):
1591
# TODO: jam 20061219 Should this be a warning? A single line
1592
# warning might be sufficient to let the user know what
1594
mutter('Could not write hashcache for %s\nError: %s',
1595
self._hashcache.cache_file_name(), e)
1597
1530
def set_conflicts(self, arg):
1598
1531
raise errors.UnsupportedOperation(self.set_conflicts, self)
1828
1761
:param branch: A branch to override probing for the branch.
1830
1763
super(InventoryWorkingTree, self).__init__(basedir=basedir,
1831
branch=branch, _control_files=_control_files, _internal=_internal,
1832
_format=_format, _bzrdir=_bzrdir)
1764
branch=branch, _transport=_control_files._transport,
1765
_internal=_internal, _format=_format, _bzrdir=_bzrdir)
1767
self._control_files = _control_files
1768
self._detect_case_handling()
1834
1770
if _inventory is None:
1835
1771
# This will be acquired on lock_read() or lock_write()
1855
1791
self._inventory = inv
1856
1792
self._inventory_is_modified = dirty
1794
def _detect_case_handling(self):
1795
wt_trans = self.bzrdir.get_workingtree_transport(None)
1797
wt_trans.stat(self._format.case_sensitive_filename)
1798
except errors.NoSuchFile:
1799
self.case_sensitive = True
1801
self.case_sensitive = False
1803
self._setup_directory_is_tree_reference()
1858
1805
def _serialize(self, inventory, out_file):
1859
1806
xml5.serializer_v5.write_inventory(self._inventory, out_file,
1862
1809
def _deserialize(selt, in_file):
1863
1810
return xml5.serializer_v5.read_inventory(in_file)
1812
def break_lock(self):
1813
"""Break a lock if one is present from another instance.
1815
Uses the ui factory to ask for confirmation if the lock may be from
1818
This will probe the repository for its lock as well.
1820
self._control_files.break_lock()
1821
self.branch.break_lock()
1823
def is_locked(self):
1824
return self._control_files.is_locked()
1826
def _must_be_locked(self):
1827
if not self.is_locked():
1828
raise errors.ObjectNotLocked(self)
1830
def lock_read(self):
1831
"""Lock the tree for reading.
1833
This also locks the branch, and can be unlocked via self.unlock().
1835
:return: A bzrlib.lock.LogicalLockResult.
1837
if not self.is_locked():
1839
self.branch.lock_read()
1841
self._control_files.lock_read()
1842
return LogicalLockResult(self.unlock)
1844
self.branch.unlock()
1847
def lock_tree_write(self):
1848
"""See MutableTree.lock_tree_write, and WorkingTree.unlock.
1850
:return: A bzrlib.lock.LogicalLockResult.
1852
if not self.is_locked():
1854
self.branch.lock_read()
1856
self._control_files.lock_write()
1857
return LogicalLockResult(self.unlock)
1859
self.branch.unlock()
1862
def lock_write(self):
1863
"""See MutableTree.lock_write, and WorkingTree.unlock.
1865
:return: A bzrlib.lock.LogicalLockResult.
1867
if not self.is_locked():
1869
self.branch.lock_write()
1871
self._control_files.lock_write()
1872
return LogicalLockResult(self.unlock)
1874
self.branch.unlock()
1877
def get_physical_lock_status(self):
1878
return self._control_files.get_physical_lock_status()
1865
1880
@needs_tree_write_lock
1866
1881
def _write_inventory(self, inv):
1867
1882
"""Write inventory as the current inventory."""
2067
2078
def has_id(self, file_id):
2068
2079
# files that have been deleted are excluded
2069
inv = self.inventory
2070
if not inv.has_id(file_id):
2080
inv, inv_file_id = self._unpack_file_id(file_id)
2081
if not inv.has_id(inv_file_id):
2072
path = inv.id2path(file_id)
2083
path = inv.id2path(inv_file_id)
2073
2084
return osutils.lexists(self.abspath(path))
2075
2086
def has_or_had_id(self, file_id):
2076
if file_id == self.inventory.root.file_id:
2087
if file_id == self.get_root_id():
2078
return self.inventory.has_id(file_id)
2089
inv, inv_file_id = self._unpack_file_id(file_id)
2090
return inv.has_id(inv_file_id)
2080
@symbol_versioning.deprecated_method(symbol_versioning.deprecated_in((2, 4, 0)))
2092
def all_file_ids(self):
2082
2093
"""Iterate through file_ids for this tree.
2084
2095
file_ids are in a WorkingTree if they are in the working inventory
2085
2096
and the working file exists.
2087
inv = self._inventory
2088
for path, ie in inv.iter_entries():
2089
if osutils.lexists(self.abspath(path)):
2099
for path, ie in self.iter_entries_by_dir():
2092
2103
@needs_tree_write_lock
2093
2104
def set_last_revision(self, new_revision):
2164
2175
mode=self.bzrdir._get_file_mode())
2165
2176
self._inventory_is_modified = False
2168
def get_file_sha1(self, file_id, path=None, stat_value=None):
2170
path = self._inventory.id2path(file_id)
2171
return self._hashcache.get_sha1(path, stat_value)
2173
2178
def get_file_mtime(self, file_id, path=None):
2174
2179
"""See Tree.get_file_mtime."""
2176
path = self.inventory.id2path(file_id)
2177
return os.lstat(self.abspath(path)).st_mtime
2181
path = self.id2path(file_id)
2183
return os.lstat(self.abspath(path)).st_mtime
2185
if e.errno == errno.ENOENT:
2186
raise errors.FileTimestampUnavailable(path)
2179
2189
def _is_executable_from_path_and_stat_from_basis(self, path, stat_result):
2180
file_id = self.path2id(path)
2190
inv, file_id = self._path2inv_file_id(path)
2181
2191
if file_id is None:
2182
2192
# For unversioned files on win32, we just assume they are not
2185
return self._inventory[file_id].executable
2195
return inv[file_id].executable
2187
2197
def _is_executable_from_path_and_stat_from_stat(self, path, stat_result):
2188
2198
mode = stat_result.st_mode
2189
2199
return bool(stat.S_ISREG(mode) and stat.S_IEXEC & mode)
2191
if not supports_executable():
2192
def is_executable(self, file_id, path=None):
2193
return self._inventory[file_id].executable
2195
_is_executable_from_path_and_stat = \
2196
_is_executable_from_path_and_stat_from_basis
2198
def is_executable(self, file_id, path=None):
2201
def is_executable(self, file_id, path=None):
2202
if not self._supports_executable():
2203
inv, inv_file_id = self._unpack_file_id(file_id)
2204
return inv[inv_file_id].executable
2200
2207
path = self.id2path(file_id)
2201
2208
mode = os.lstat(self.abspath(path)).st_mode
2202
2209
return bool(stat.S_ISREG(mode) and stat.S_IEXEC & mode)
2204
_is_executable_from_path_and_stat = \
2205
_is_executable_from_path_and_stat_from_stat
2211
def _is_executable_from_path_and_stat(self, path, stat_result):
2212
if not self._supports_executable():
2213
return self._is_executable_from_path_and_stat_from_basis(path, stat_result)
2215
return self._is_executable_from_path_and_stat_from_stat(path, stat_result)
2207
2217
@needs_tree_write_lock
2208
2218
def _add(self, files, ids, kinds):
2211
2221
# should probably put it back with the previous ID.
2212
2222
# the read and write working inventory should not occur in this
2213
2223
# function - they should be part of lock_write and unlock.
2214
inv = self.inventory
2224
# FIXME: nested trees
2225
inv = self.root_inventory
2215
2226
for f, file_id, kind in zip(files, ids, kinds):
2216
2227
if file_id is None:
2217
2228
inv.add_path(f, kind=kind)
2258
2269
parent_tree = self.branch.repository.revision_tree(parent_id)
2259
2270
parent_tree.lock_read()
2261
if not parent_tree.has_id(file_id):
2273
kind = parent_tree.kind(file_id)
2274
except errors.NoSuchId:
2263
ie = parent_tree.inventory[file_id]
2264
if ie.kind != 'file':
2265
2277
# Note: this is slightly unnecessary, because symlinks and
2266
2278
# directories have a "text" which is the empty text, and we
2267
2279
# know that won't mess up annotations. But it seems cleaner
2269
parent_text_key = (file_id, ie.revision)
2282
file_id, parent_tree.get_file_revision(file_id))
2270
2283
if parent_text_key not in maybe_file_parent_keys:
2271
2284
maybe_file_parent_keys.append(parent_text_key)
2287
2300
for key, line in annotator.annotate_flat(this_key)]
2288
2301
return annotations
2303
def _put_rio(self, filename, stanzas, header):
2304
self._must_be_locked()
2305
my_file = _mod_rio.rio_file(stanzas, header)
2306
self._transport.put_file(filename, my_file,
2307
mode=self.bzrdir._get_file_mode())
2309
@needs_tree_write_lock
2310
def set_merge_modified(self, modified_hashes):
2312
for file_id, hash in modified_hashes.iteritems():
2313
yield _mod_rio.Stanza(file_id=file_id.decode('utf8'),
2315
self._put_rio('merge-hashes', iter_stanzas(), MERGE_MODIFIED_HEADER_1)
2290
2317
@needs_read_lock
2291
2318
def merge_modified(self):
2292
2319
"""Return a dictionary of files modified by a merge.
2312
2339
for s in _mod_rio.RioReader(hashfile):
2313
2340
# RioReader reads in Unicode, so convert file_ids back to utf8
2314
2341
file_id = osutils.safe_file_id(s.get("file_id"), warn=False)
2315
if not self.inventory.has_id(file_id):
2342
if not self.has_id(file_id):
2317
2344
text_hash = s.get("hash")
2318
2345
if text_hash == self.get_file_sha1(file_id):
2348
2375
other_tree.lock_tree_write()
2350
2377
new_parents = other_tree.get_parent_ids()
2351
other_root = other_tree.inventory.root
2378
other_root = other_tree.root_inventory.root
2352
2379
other_root.parent_id = new_root_parent
2353
2380
other_root.name = osutils.basename(other_tree_path)
2354
self.inventory.add(other_root)
2355
add_children(self.inventory, other_root)
2356
self._write_inventory(self.inventory)
2381
self.root_inventory.add(other_root)
2382
add_children(self.root_inventory, other_root)
2383
self._write_inventory(self.root_inventory)
2357
2384
# normally we don't want to fetch whole repositories, but i think
2358
2385
# here we really do want to consolidate the whole thing.
2359
2386
for parent_id in other_tree.get_parent_ids():
2397
2424
tree_transport = self.bzrdir.root_transport.clone(sub_path)
2398
2425
if tree_transport.base != branch_transport.base:
2399
2426
tree_bzrdir = format.initialize_on_transport(tree_transport)
2400
branch.BranchReferenceFormat().initialize(tree_bzrdir,
2401
target_branch=new_branch)
2427
tree_bzrdir.set_branch_reference(new_branch)
2403
2429
tree_bzrdir = branch_bzrdir
2404
2430
wt = tree_bzrdir.create_workingtree(_mod_revision.NULL_REVISION)
2405
2431
wt.set_parent_ids(self.get_parent_ids())
2406
my_inv = self.inventory
2432
# FIXME: Support nested trees
2433
my_inv = self.root_inventory
2407
2434
child_inv = inventory.Inventory(root_id=None)
2408
2435
new_root = my_inv[file_id]
2409
2436
my_inv.remove_recursive_id(file_id)
2429
2456
if not self.is_locked():
2430
2457
raise errors.ObjectNotLocked(self)
2432
inv = self.inventory
2433
2459
if from_dir is None and include_root is True:
2434
yield ('', 'V', 'directory', inv.root.file_id, inv.root)
2460
yield ('', 'V', 'directory', self.get_root_id(), self.root_inventory.root)
2435
2461
# Convert these into local objects to save lookup times
2436
2462
pathjoin = osutils.pathjoin
2437
2463
file_kind = self._kind
2445
2471
# directory file_id, relative path, absolute path, reverse sorted children
2446
2472
if from_dir is not None:
2447
from_dir_id = inv.path2id(from_dir)
2473
inv, from_dir_id = self._path2inv_file_id(from_dir)
2448
2474
if from_dir_id is None:
2449
2475
# Directory not versioned
2451
2477
from_dir_abspath = pathjoin(self.basedir, from_dir)
2479
inv = self.root_inventory
2453
2480
from_dir_id = inv.root.file_id
2454
2481
from_dir_abspath = self.basedir
2455
2482
children = os.listdir(from_dir_abspath)
2592
2620
if not self.has_filename(to_dir):
2593
2621
raise errors.BzrMoveFailedError('',to_dir,
2594
2622
errors.NotInWorkingDirectory(to_dir))
2595
to_dir_id = inv.path2id(to_dir)
2623
to_inv, to_dir_id = self._path2inv_file_id(to_dir)
2596
2624
if to_dir_id is None:
2597
2625
raise errors.BzrMoveFailedError('',to_dir,
2598
2626
errors.NotVersionedError(path=to_dir))
2600
to_dir_ie = inv[to_dir_id]
2628
to_dir_ie = to_inv[to_dir_id]
2601
2629
if to_dir_ie.kind != 'directory':
2602
2630
raise errors.BzrMoveFailedError('',to_dir,
2603
2631
errors.NotADirectory(to_abs))
2605
2633
# create rename entries and tuples
2606
2634
for from_rel in from_paths:
2607
2635
from_tail = splitpath(from_rel)[-1]
2608
from_id = inv.path2id(from_rel)
2636
from_inv, from_id = self._path2inv_file_id(from_rel)
2609
2637
if from_id is None:
2610
2638
raise errors.BzrMoveFailedError(from_rel,to_dir,
2611
2639
errors.NotVersionedError(path=from_rel))
2613
from_entry = inv[from_id]
2641
from_entry = from_inv[from_id]
2614
2642
from_parent_id = from_entry.parent_id
2615
2643
to_rel = pathjoin(to_dir, from_tail)
2616
2644
rename_entry = InventoryWorkingTree._RenameEntry(
2662
2691
Everything else results in an error.
2664
inv = self.inventory
2665
2693
rename_entries = []
2667
2695
# create rename entries and tuples
2668
2696
from_tail = splitpath(from_rel)[-1]
2669
from_id = inv.path2id(from_rel)
2697
from_inv, from_id = self._path2inv_file_id(from_rel)
2670
2698
if from_id is None:
2671
2699
# if file is missing in the inventory maybe it's in the basis_tree
2672
2700
basis_tree = self.branch.basis_tree()
2675
2703
raise errors.BzrRenameFailedError(from_rel,to_rel,
2676
2704
errors.NotVersionedError(path=from_rel))
2677
2705
# put entry back in the inventory so we can rename it
2678
from_entry = basis_tree.inventory[from_id].copy()
2706
from_entry = basis_tree.root_inventory[from_id].copy()
2707
from_inv.add(from_entry)
2681
from_entry = inv[from_id]
2709
from_inv, from_inv_id = self._unpack_file_id(from_id)
2710
from_entry = from_inv[from_inv_id]
2682
2711
from_parent_id = from_entry.parent_id
2683
2712
to_dir, to_tail = os.path.split(to_rel)
2684
to_dir_id = inv.path2id(to_dir)
2713
to_inv, to_dir_id = self._path2inv_file_id(to_dir)
2685
2714
rename_entry = InventoryWorkingTree._RenameEntry(from_rel=from_rel,
2686
2715
from_id=from_id,
2687
2716
from_tail=from_tail,
2709
2738
from_id, from_rel, to_rel, to_dir, to_dir_id)
2711
2740
self._move(rename_entries)
2712
self._write_inventory(inv)
2741
self._write_inventory(to_inv)
2714
2743
class _RenameEntry(object):
2715
2744
def __init__(self, from_rel, from_id, from_tail, from_parent_id,
2782
2812
# something is wrong, so lets determine what exactly
2783
2813
if not self.has_filename(from_rel) and \
2784
2814
not self.has_filename(to_rel):
2785
raise errors.BzrRenameFailedError(from_rel,to_rel,
2786
errors.PathsDoNotExist(paths=(str(from_rel),
2815
raise errors.BzrRenameFailedError(from_rel, to_rel,
2816
errors.PathsDoNotExist(paths=(from_rel, to_rel)))
2789
2818
raise errors.RenameFailedFilesExist(from_rel, to_rel)
2790
2819
rename_entry.only_change_inv = only_change_inv
2884
2912
This is the same order used by 'osutils.walkdirs'.
2886
2914
## TODO: Work from given directory downwards
2887
for path, dir_entry in self.inventory.directories():
2915
for path, dir_entry in self.iter_entries_by_dir():
2916
if dir_entry.kind != 'directory':
2888
2918
# mutter("search for unknowns in %r", path)
2889
2919
dirabs = self.abspath(path)
2890
2920
if not isdir(dirabs):
2955
2984
if dir[2] == _directory:
2956
2985
pending.append(dir)
2988
def update_feature_flags(self, updated_flags):
2989
"""Update the feature flags for this branch.
2991
:param updated_flags: Dictionary mapping feature names to necessities
2992
A necessity can be None to indicate the feature should be removed
2994
self._format._update_feature_flags(updated_flags)
2995
self.control_transport.put_bytes('format', self._format.as_string())
2959
2998
class WorkingTreeFormatRegistry(controldir.ControlComponentFormatRegistry):
2960
2999
"""Registry for working tree formats."""
3017
3056
supports_versioned_directories = None
3020
def find_format_string(klass, a_bzrdir):
3021
"""Return format name for the working tree object in a_bzrdir."""
3023
transport = a_bzrdir.get_workingtree_transport(None)
3024
return transport.get_bytes("format")
3025
except errors.NoSuchFile:
3026
raise errors.NoWorkingTree(base=transport.base)
3029
def find_format(klass, a_bzrdir):
3030
"""Return the format for the working tree object in a_bzrdir."""
3032
format_string = klass.find_format_string(a_bzrdir)
3033
return format_registry.get(format_string)
3035
raise errors.UnknownFormatError(format=format_string,
3036
kind="working tree")
3038
def initialize(self, a_bzrdir, revision_id=None, from_branch=None,
3058
def initialize(self, controldir, revision_id=None, from_branch=None,
3039
3059
accelerator_tree=None, hardlink=False):
3040
"""Initialize a new working tree in a_bzrdir.
3060
"""Initialize a new working tree in controldir.
3042
:param a_bzrdir: BzrDir to initialize the working tree in.
3062
:param controldir: ControlDir to initialize the working tree in.
3043
3063
:param revision_id: allows creating a working tree at a different
3044
3064
revision than the branch is at.
3045
3065
:param from_branch: Branch to checkout
3065
3085
"""Return the current default format."""
3066
3086
return format_registry.get_default()
3068
def get_format_string(self):
3069
"""Return the ASCII format string that identifies this format."""
3070
raise NotImplementedError(self.get_format_string)
3072
3088
def get_format_description(self):
3073
3089
"""Return the short description for this format."""
3074
3090
raise NotImplementedError(self.get_format_description)
3126
3142
def unregister_format(klass, format):
3127
3143
format_registry.remove(format)
3145
def get_controldir_for_branch(self):
3146
"""Get the control directory format for creating branches.
3148
This is to support testing of working tree formats that can not exist
3149
in the same control directory as a branch.
3151
return self._matchingbzrdir
3154
class WorkingTreeFormatMetaDir(bzrdir.BzrFormat, WorkingTreeFormat):
3155
"""Base class for working trees that live in bzr meta directories."""
3158
WorkingTreeFormat.__init__(self)
3159
bzrdir.BzrFormat.__init__(self)
3162
def find_format_string(klass, controldir):
3163
"""Return format name for the working tree object in controldir."""
3165
transport = controldir.get_workingtree_transport(None)
3166
return transport.get_bytes("format")
3167
except errors.NoSuchFile:
3168
raise errors.NoWorkingTree(base=transport.base)
3171
def find_format(klass, controldir):
3172
"""Return the format for the working tree object in controldir."""
3173
format_string = klass.find_format_string(controldir)
3174
return klass._find_format(format_registry, 'working tree',
3177
def check_support_status(self, allow_unsupported, recommend_upgrade=True,
3179
WorkingTreeFormat.check_support_status(self,
3180
allow_unsupported=allow_unsupported, recommend_upgrade=recommend_upgrade,
3182
bzrdir.BzrFormat.check_support_status(self, allow_unsupported=allow_unsupported,
3183
recommend_upgrade=recommend_upgrade, basedir=basedir)
3130
3186
format_registry.register_lazy("Bazaar Working Tree Format 4 (bzr 0.15)\n",
3131
3187
"bzrlib.workingtree_4", "WorkingTreeFormat4")