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.
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]
401
def all_file_ids(self):
402
"""See Tree.iter_all_file_ids"""
403
raise NotImplementedError(self.all_file_ids)
405
382
def __repr__(self):
406
383
return "<%s of %s>" % (self.__class__.__name__,
407
384
getattr(self, 'basedir', None))
522
499
raise NotImplementedError(self.get_root_id)
525
def clone(self, to_bzrdir, revision_id=None):
502
def clone(self, to_controldir, revision_id=None):
526
503
"""Duplicate this working tree into to_bzr, including all state.
528
505
Specifically modified files are kept as modified, but
529
506
ignored and unknown files are discarded.
531
If you want to make a new line of development, see bzrdir.sprout()
508
If you want to make a new line of development, see ControlDir.sprout()
534
511
If not None, the cloned tree will have its last revision set to
550
527
# TODO now merge from tree.last_revision to revision (to preserve
551
528
# user local changes)
552
529
merge.transform_tree(tree, self)
553
tree.set_parent_ids([revision_id])
530
if revision_id == _mod_revision.NULL_REVISION:
533
new_parents = [revision_id]
534
tree.set_parent_ids(new_parents)
555
536
def id2abspath(self, file_id):
556
537
return self.abspath(self.id2path(file_id))
770
747
@needs_tree_write_lock
771
748
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)
749
"""Set the merge modified hashes."""
750
raise NotImplementedError(self.set_merge_modified)
778
752
def _sha_from_stat(self, path, stat_result):
779
753
"""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
762
@needs_write_lock # because merge pulls data into the branch.
795
763
def merge_from_branch(self, branch, to_revision=None, from_revision=None,
796
764
merge_type=None, force=False):
1036
1004
show_base=show_base)
1037
1005
basis_root_id = basis_tree.get_root_id()
1038
1006
new_root_id = new_basis_tree.get_root_id()
1039
if basis_root_id != new_root_id:
1007
if new_root_id is not None and basis_root_id != new_root_id:
1040
1008
self.set_root_id(new_root_id)
1042
1010
basis_tree.unlock()
1043
1011
# TODO - dedup parents list with things merged by pull ?
1044
1012
# reuse the revisiontree we merged against to set the new
1046
parent_trees = [(self.branch.last_revision(), new_basis_tree)]
1015
if self.branch.last_revision() != _mod_revision.NULL_REVISION:
1016
parent_trees.append(
1017
(self.branch.last_revision(), new_basis_tree))
1047
1018
# we have to pull the merge trees out again, because
1048
1019
# merge_inner has set the ids. - this corner is not yet
1049
1020
# layered well enough to prevent double handling.
1188
1155
: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()
1157
raise NotImplementedError(self.lock_read)
1200
1159
def lock_tree_write(self):
1201
1160
"""See MutableTree.lock_tree_write, and WorkingTree.unlock.
1203
1162
: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()
1164
raise NotImplementedError(self.lock_tree_write)
1215
1166
def lock_write(self):
1216
1167
"""See MutableTree.lock_write, and WorkingTree.unlock.
1218
1169
: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()
1171
raise NotImplementedError(self.lock_write)
1230
1173
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)
1174
raise NotImplementedError(self.get_physical_lock_status)
1237
1176
def set_last_revision(self, new_revision):
1238
1177
"""Change the last revision in the working tree."""
1580
1519
last_rev = parent_trees[0][0]
1581
1520
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
1522
def set_conflicts(self, arg):
1598
1523
raise errors.UnsupportedOperation(self.set_conflicts, self)
1828
1753
:param branch: A branch to override probing for the branch.
1830
1755
super(InventoryWorkingTree, self).__init__(basedir=basedir,
1831
branch=branch, _control_files=_control_files, _internal=_internal,
1832
_format=_format, _bzrdir=_bzrdir)
1756
branch=branch, _transport=_control_files._transport,
1757
_internal=_internal, _format=_format, _bzrdir=_bzrdir)
1759
self._control_files = _control_files
1760
self._detect_case_handling()
1834
1762
if _inventory is None:
1835
1763
# This will be acquired on lock_read() or lock_write()
1855
1783
self._inventory = inv
1856
1784
self._inventory_is_modified = dirty
1786
def _detect_case_handling(self):
1787
wt_trans = self.bzrdir.get_workingtree_transport(None)
1789
wt_trans.stat(self._format.case_sensitive_filename)
1790
except errors.NoSuchFile:
1791
self.case_sensitive = True
1793
self.case_sensitive = False
1795
self._setup_directory_is_tree_reference()
1858
1797
def _serialize(self, inventory, out_file):
1859
1798
xml5.serializer_v5.write_inventory(self._inventory, out_file,
1862
1801
def _deserialize(selt, in_file):
1863
1802
return xml5.serializer_v5.read_inventory(in_file)
1804
def break_lock(self):
1805
"""Break a lock if one is present from another instance.
1807
Uses the ui factory to ask for confirmation if the lock may be from
1810
This will probe the repository for its lock as well.
1812
self._control_files.break_lock()
1813
self.branch.break_lock()
1815
def is_locked(self):
1816
return self._control_files.is_locked()
1818
def _must_be_locked(self):
1819
if not self.is_locked():
1820
raise errors.ObjectNotLocked(self)
1822
def lock_read(self):
1823
"""Lock the tree for reading.
1825
This also locks the branch, and can be unlocked via self.unlock().
1827
:return: A bzrlib.lock.LogicalLockResult.
1829
if not self.is_locked():
1831
self.branch.lock_read()
1833
self._control_files.lock_read()
1834
return LogicalLockResult(self.unlock)
1836
self.branch.unlock()
1839
def lock_tree_write(self):
1840
"""See MutableTree.lock_tree_write, and WorkingTree.unlock.
1842
:return: A bzrlib.lock.LogicalLockResult.
1844
if not self.is_locked():
1846
self.branch.lock_read()
1848
self._control_files.lock_write()
1849
return LogicalLockResult(self.unlock)
1851
self.branch.unlock()
1854
def lock_write(self):
1855
"""See MutableTree.lock_write, and WorkingTree.unlock.
1857
:return: A bzrlib.lock.LogicalLockResult.
1859
if not self.is_locked():
1861
self.branch.lock_write()
1863
self._control_files.lock_write()
1864
return LogicalLockResult(self.unlock)
1866
self.branch.unlock()
1869
def get_physical_lock_status(self):
1870
return self._control_files.get_physical_lock_status()
1865
1872
@needs_tree_write_lock
1866
1873
def _write_inventory(self, inv):
1867
1874
"""Write inventory as the current inventory."""
2067
2070
def has_id(self, file_id):
2068
2071
# files that have been deleted are excluded
2069
inv = self.inventory
2070
if not inv.has_id(file_id):
2072
inv, inv_file_id = self._unpack_file_id(file_id)
2073
if not inv.has_id(inv_file_id):
2072
path = inv.id2path(file_id)
2075
path = inv.id2path(inv_file_id)
2073
2076
return osutils.lexists(self.abspath(path))
2075
2078
def has_or_had_id(self, file_id):
2076
2079
if file_id == self.inventory.root.file_id:
2078
return self.inventory.has_id(file_id)
2081
inv, inv_file_id = self._unpack_file_id(file_id)
2082
return inv.has_id(inv_file_id)
2080
@symbol_versioning.deprecated_method(symbol_versioning.deprecated_in((2, 4, 0)))
2084
def all_file_ids(self):
2082
2085
"""Iterate through file_ids for this tree.
2084
2087
file_ids are in a WorkingTree if they are in the working inventory
2085
2088
and the working file exists.
2087
inv = self._inventory
2088
for path, ie in inv.iter_entries():
2089
if osutils.lexists(self.abspath(path)):
2091
for path, ie in self.iter_entries_by_dir():
2092
2095
@needs_tree_write_lock
2093
2096
def set_last_revision(self, new_revision):
2164
2167
mode=self.bzrdir._get_file_mode())
2165
2168
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
2170
def get_file_mtime(self, file_id, path=None):
2174
2171
"""See Tree.get_file_mtime."""
2176
path = self.inventory.id2path(file_id)
2177
return os.lstat(self.abspath(path)).st_mtime
2173
path = self.id2path(file_id)
2175
return os.lstat(self.abspath(path)).st_mtime
2177
if e.errno == errno.ENOENT:
2178
raise errors.FileTimestampUnavailable(path)
2179
2181
def _is_executable_from_path_and_stat_from_basis(self, path, stat_result):
2180
file_id = self.path2id(path)
2182
inv, file_id = self._path2inv_file_id(path)
2181
2183
if file_id is None:
2182
2184
# For unversioned files on win32, we just assume they are not
2185
return self._inventory[file_id].executable
2187
return inv[file_id].executable
2187
2189
def _is_executable_from_path_and_stat_from_stat(self, path, stat_result):
2188
2190
mode = stat_result.st_mode
2189
2191
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):
2193
def is_executable(self, file_id, path=None):
2194
if not self._supports_executable():
2195
inv, inv_file_id = self._unpack_file_id(file_id)
2196
return inv[inv_file_id].executable
2200
2199
path = self.id2path(file_id)
2201
2200
mode = os.lstat(self.abspath(path)).st_mode
2202
2201
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
2203
def _is_executable_from_path_and_stat(self, path, stat_result):
2204
if not self._supports_executable():
2205
return self._is_executable_from_path_and_stat_from_basis(path, stat_result)
2207
return self._is_executable_from_path_and_stat_from_stat(path, stat_result)
2207
2209
@needs_tree_write_lock
2208
2210
def _add(self, files, ids, kinds):
2258
2260
parent_tree = self.branch.repository.revision_tree(parent_id)
2259
2261
parent_tree.lock_read()
2261
if not parent_tree.has_id(file_id):
2264
kind = parent_tree.kind(file_id)
2265
except errors.NoSuchId:
2263
ie = parent_tree.inventory[file_id]
2264
if ie.kind != 'file':
2265
2268
# Note: this is slightly unnecessary, because symlinks and
2266
2269
# directories have a "text" which is the empty text, and we
2267
2270
# know that won't mess up annotations. But it seems cleaner
2269
parent_text_key = (file_id, ie.revision)
2273
file_id, parent_tree.get_file_revision(file_id))
2270
2274
if parent_text_key not in maybe_file_parent_keys:
2271
2275
maybe_file_parent_keys.append(parent_text_key)
2287
2291
for key, line in annotator.annotate_flat(this_key)]
2288
2292
return annotations
2294
def _put_rio(self, filename, stanzas, header):
2295
self._must_be_locked()
2296
my_file = _mod_rio.rio_file(stanzas, header)
2297
self._transport.put_file(filename, my_file,
2298
mode=self.bzrdir._get_file_mode())
2300
@needs_tree_write_lock
2301
def set_merge_modified(self, modified_hashes):
2303
for file_id, hash in modified_hashes.iteritems():
2304
yield _mod_rio.Stanza(file_id=file_id.decode('utf8'),
2306
self._put_rio('merge-hashes', iter_stanzas(), MERGE_MODIFIED_HEADER_1)
2290
2308
@needs_read_lock
2291
2309
def merge_modified(self):
2292
2310
"""Return a dictionary of files modified by a merge.
2312
2330
for s in _mod_rio.RioReader(hashfile):
2313
2331
# RioReader reads in Unicode, so convert file_ids back to utf8
2314
2332
file_id = osutils.safe_file_id(s.get("file_id"), warn=False)
2315
if not self.inventory.has_id(file_id):
2333
if not self.has_id(file_id):
2317
2335
text_hash = s.get("hash")
2318
2336
if text_hash == self.get_file_sha1(file_id):
2397
2415
tree_transport = self.bzrdir.root_transport.clone(sub_path)
2398
2416
if tree_transport.base != branch_transport.base:
2399
2417
tree_bzrdir = format.initialize_on_transport(tree_transport)
2400
branch.BranchReferenceFormat().initialize(tree_bzrdir,
2401
target_branch=new_branch)
2418
tree_bzrdir.set_branch_reference(new_branch)
2403
2420
tree_bzrdir = branch_bzrdir
2404
2421
wt = tree_bzrdir.create_workingtree(_mod_revision.NULL_REVISION)
2429
2446
if not self.is_locked():
2430
2447
raise errors.ObjectNotLocked(self)
2432
inv = self.inventory
2433
2449
if from_dir is None and include_root is True:
2434
yield ('', 'V', 'directory', inv.root.file_id, inv.root)
2450
yield ('', 'V', 'directory', self.get_root_id(), self.inventory.root)
2435
2451
# Convert these into local objects to save lookup times
2436
2452
pathjoin = osutils.pathjoin
2437
2453
file_kind = self._kind
2445
2461
# directory file_id, relative path, absolute path, reverse sorted children
2446
2462
if from_dir is not None:
2447
from_dir_id = inv.path2id(from_dir)
2463
inv, from_dir_id = self._path2inv_file_id(from_dir)
2448
2464
if from_dir_id is None:
2449
2465
# Directory not versioned
2451
2467
from_dir_abspath = pathjoin(self.basedir, from_dir)
2469
inv = self.inventory
2453
2470
from_dir_id = inv.root.file_id
2454
2471
from_dir_abspath = self.basedir
2455
2472
children = os.listdir(from_dir_abspath)
2592
2608
if not self.has_filename(to_dir):
2593
2609
raise errors.BzrMoveFailedError('',to_dir,
2594
2610
errors.NotInWorkingDirectory(to_dir))
2595
to_dir_id = inv.path2id(to_dir)
2611
to_inv, to_dir_id = self._path2inv_file_id(to_dir)
2596
2612
if to_dir_id is None:
2597
2613
raise errors.BzrMoveFailedError('',to_dir,
2598
2614
errors.NotVersionedError(path=to_dir))
2600
to_dir_ie = inv[to_dir_id]
2616
to_dir_ie = to_inv[to_dir_id]
2601
2617
if to_dir_ie.kind != 'directory':
2602
2618
raise errors.BzrMoveFailedError('',to_dir,
2603
2619
errors.NotADirectory(to_abs))
2605
2621
# create rename entries and tuples
2606
2622
for from_rel in from_paths:
2607
2623
from_tail = splitpath(from_rel)[-1]
2608
from_id = inv.path2id(from_rel)
2624
from_inv, from_id = self._path2inv_file_id(from_rel)
2609
2625
if from_id is None:
2610
2626
raise errors.BzrMoveFailedError(from_rel,to_dir,
2611
2627
errors.NotVersionedError(path=from_rel))
2613
from_entry = inv[from_id]
2629
from_entry = from_inv[from_id]
2614
2630
from_parent_id = from_entry.parent_id
2615
2631
to_rel = pathjoin(to_dir, from_tail)
2616
2632
rename_entry = InventoryWorkingTree._RenameEntry(
2662
2679
Everything else results in an error.
2664
inv = self.inventory
2665
2681
rename_entries = []
2667
2683
# create rename entries and tuples
2668
2684
from_tail = splitpath(from_rel)[-1]
2669
from_id = inv.path2id(from_rel)
2685
from_inv, from_id = self._path2inv_file_id(from_rel)
2670
2686
if from_id is None:
2671
2687
# if file is missing in the inventory maybe it's in the basis_tree
2672
2688
basis_tree = self.branch.basis_tree()
2676
2692
errors.NotVersionedError(path=from_rel))
2677
2693
# put entry back in the inventory so we can rename it
2678
2694
from_entry = basis_tree.inventory[from_id].copy()
2695
from_inv.add(from_entry)
2681
from_entry = inv[from_id]
2697
from_inv, from_inv_id = self._unpack_file_id(from_id)
2698
from_entry = from_inv[from_inv_id]
2682
2699
from_parent_id = from_entry.parent_id
2683
2700
to_dir, to_tail = os.path.split(to_rel)
2684
to_dir_id = inv.path2id(to_dir)
2701
to_inv, to_dir_id = self._path2inv_file_id(to_dir)
2685
2702
rename_entry = InventoryWorkingTree._RenameEntry(from_rel=from_rel,
2686
2703
from_id=from_id,
2687
2704
from_tail=from_tail,
2709
2726
from_id, from_rel, to_rel, to_dir, to_dir_id)
2711
2728
self._move(rename_entries)
2712
self._write_inventory(inv)
2729
self._write_inventory(to_inv)
2714
2731
class _RenameEntry(object):
2715
2732
def __init__(self, from_rel, from_id, from_tail, from_parent_id,
2782
2799
# something is wrong, so lets determine what exactly
2783
2800
if not self.has_filename(from_rel) and \
2784
2801
not self.has_filename(to_rel):
2785
raise errors.BzrRenameFailedError(from_rel,to_rel,
2786
errors.PathsDoNotExist(paths=(str(from_rel),
2802
raise errors.BzrRenameFailedError(from_rel, to_rel,
2803
errors.PathsDoNotExist(paths=(from_rel, to_rel)))
2789
2805
raise errors.RenameFailedFilesExist(from_rel, to_rel)
2790
2806
rename_entry.only_change_inv = only_change_inv
2955
2969
if dir[2] == _directory:
2956
2970
pending.append(dir)
2973
def update_feature_flags(self, updated_flags):
2974
"""Update the feature flags for this branch.
2976
:param updated_flags: Dictionary mapping feature names to necessities
2977
A necessity can be None to indicate the feature should be removed
2979
self._format._update_feature_flags(updated_flags)
2980
self.control_transport.put_bytes('format', self._format.as_string())
2959
2983
class WorkingTreeFormatRegistry(controldir.ControlComponentFormatRegistry):
2960
2984
"""Registry for working tree formats."""
3017
3041
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
format_string = bzrdir.extract_format_string(format_string)
3034
return format_registry.get(format_string)
3036
raise errors.UnknownFormatError(format=format_string,
3037
kind="working tree")
3039
def initialize(self, a_bzrdir, revision_id=None, from_branch=None,
3043
def initialize(self, controldir, revision_id=None, from_branch=None,
3040
3044
accelerator_tree=None, hardlink=False):
3041
"""Initialize a new working tree in a_bzrdir.
3045
"""Initialize a new working tree in controldir.
3043
:param a_bzrdir: BzrDir to initialize the working tree in.
3047
:param controldir: ControlDir to initialize the working tree in.
3044
3048
:param revision_id: allows creating a working tree at a different
3045
3049
revision than the branch is at.
3046
3050
:param from_branch: Branch to checkout
3066
3070
"""Return the current default format."""
3067
3071
return format_registry.get_default()
3069
def get_format_string(self):
3070
"""Return the ASCII format string that identifies this format."""
3071
raise NotImplementedError(self.get_format_string)
3073
3073
def get_format_description(self):
3074
3074
"""Return the short description for this format."""
3075
3075
raise NotImplementedError(self.get_format_description)
3127
3127
def unregister_format(klass, format):
3128
3128
format_registry.remove(format)
3130
def get_controldir_for_branch(self):
3131
"""Get the control directory format for creating branches.
3133
This is to support testing of working tree formats that can not exist
3134
in the same control directory as a branch.
3136
return self._matchingbzrdir
3139
class WorkingTreeFormatMetaDir(bzrdir.BzrFormat, WorkingTreeFormat):
3140
"""Base class for working trees that live in bzr meta directories."""
3143
WorkingTreeFormat.__init__(self)
3144
bzrdir.BzrFormat.__init__(self)
3147
def find_format_string(klass, controldir):
3148
"""Return format name for the working tree object in controldir."""
3150
transport = controldir.get_workingtree_transport(None)
3151
return transport.get_bytes("format")
3152
except errors.NoSuchFile:
3153
raise errors.NoWorkingTree(base=transport.base)
3156
def find_format(klass, controldir):
3157
"""Return the format for the working tree object in controldir."""
3158
format_string = klass.find_format_string(controldir)
3159
return klass._find_format(format_registry, 'working tree',
3162
def check_support_status(self, allow_unsupported, recommend_upgrade=True,
3164
WorkingTreeFormat.check_support_status(self,
3165
allow_unsupported=allow_unsupported, recommend_upgrade=recommend_upgrade,
3167
bzrdir.BzrFormat.check_support_status(self, allow_unsupported=allow_unsupported,
3168
recommend_upgrade=recommend_upgrade, basedir=basedir)
3131
3171
format_registry.register_lazy("Bazaar Working Tree Format 4 (bzr 0.15)\n",
3132
3172
"bzrlib.workingtree_4", "WorkingTreeFormat4")