2685
1814
return ShelfManager(self, self._transport)
2688
class WorkingTree2(WorkingTree):
2689
"""This is the Format 2 working tree.
2691
This was the first weave based working tree.
2692
- uses os locks for locking.
2693
- uses the branch last-revision.
1817
class InventoryWorkingTree(WorkingTree,
1818
bzrlib.mutabletree.MutableInventoryTree):
1819
"""Base class for working trees that are inventory-oriented.
1821
The inventory is held in the `Branch` working-inventory, and the
1822
files are in a directory on disk.
1824
It is possible for a `WorkingTree` to have a filename which is
1825
not listed in the Inventory and vice versa.
2696
def __init__(self, *args, **kwargs):
2697
super(WorkingTree2, self).__init__(*args, **kwargs)
2698
# WorkingTree2 has more of a constraint that self._inventory must
2699
# exist. Because this is an older format, we don't mind the overhead
2700
# caused by the extra computation here.
2702
# Newer WorkingTree's should only have self._inventory set when they
2704
if self._inventory is None:
2705
self.read_working_inventory()
2707
def _get_check_refs(self):
2708
"""Return the references needed to perform a check of this tree."""
2709
return [('trees', self.last_revision())]
2711
def lock_tree_write(self):
2712
"""See WorkingTree.lock_tree_write().
2714
In Format2 WorkingTrees we have a single lock for the branch and tree
2715
so lock_tree_write() degrades to lock_write().
2717
:return: An object with an unlock method which will release the lock
2720
self.branch.lock_write()
2722
self._control_files.lock_write()
2725
self.branch.unlock()
2729
# do non-implementation specific cleanup
2732
# we share control files:
2733
if self._control_files._lock_count == 3:
2734
# _inventory_is_modified is always False during a read lock.
2735
if self._inventory_is_modified:
2737
self._write_hashcache_if_dirty()
2739
# reverse order of locking.
2741
return self._control_files.unlock()
1828
def __init__(self, basedir='.',
1829
branch=DEPRECATED_PARAMETER,
1831
_control_files=None,
1835
"""Construct a InventoryWorkingTree instance. This is not a public API.
1837
:param branch: A branch to override probing for the branch.
1839
super(InventoryWorkingTree, self).__init__(basedir=basedir,
1840
branch=branch, _control_files=_control_files, _internal=_internal,
1841
_format=_format, _bzrdir=_bzrdir)
1843
if _inventory is None:
1844
# This will be acquired on lock_read() or lock_write()
1845
self._inventory_is_modified = False
1846
self._inventory = None
1848
# the caller of __init__ has provided an inventory,
1849
# we assume they know what they are doing - as its only
1850
# the Format factory and creation methods that are
1851
# permitted to do this.
1852
self._set_inventory(_inventory, dirty=False)
1854
def _set_inventory(self, inv, dirty):
1855
"""Set the internal cached inventory.
1857
:param inv: The inventory to set.
1858
:param dirty: A boolean indicating whether the inventory is the same
1859
logical inventory as whats on disk. If True the inventory is not
1860
the same and should be written to disk or data will be lost, if
1861
False then the inventory is the same as that on disk and any
1862
serialisation would be unneeded overhead.
1864
self._inventory = inv
1865
self._inventory_is_modified = dirty
1867
def _serialize(self, inventory, out_file):
1868
xml5.serializer_v5.write_inventory(self._inventory, out_file,
1871
def _deserialize(selt, in_file):
1872
return xml5.serializer_v5.read_inventory(in_file)
1874
@needs_tree_write_lock
1875
def _write_inventory(self, inv):
1876
"""Write inventory as the current inventory."""
1877
self._set_inventory(inv, dirty=True)
1880
# XXX: This method should be deprecated in favour of taking in a proper
1881
# new Inventory object.
1882
@needs_tree_write_lock
1883
def set_inventory(self, new_inventory_list):
1884
from bzrlib.inventory import (Inventory,
1888
inv = Inventory(self.get_root_id())
1889
for path, file_id, parent, kind in new_inventory_list:
1890
name = os.path.basename(path)
1893
# fixme, there should be a factory function inv,add_??
1894
if kind == 'directory':
1895
inv.add(InventoryDirectory(file_id, name, parent))
1896
elif kind == 'file':
1897
inv.add(InventoryFile(file_id, name, parent))
1898
elif kind == 'symlink':
1899
inv.add(InventoryLink(file_id, name, parent))
1901
raise errors.BzrError("unknown kind %r" % kind)
1902
self._write_inventory(inv)
1904
def _write_basis_inventory(self, xml):
1905
"""Write the basis inventory XML to the basis-inventory file"""
1906
path = self._basis_inventory_name()
1908
self._transport.put_file(path, sio,
1909
mode=self.bzrdir._get_file_mode())
1911
def _reset_data(self):
1912
"""Reset transient data that cannot be revalidated."""
1913
self._inventory_is_modified = False
1914
f = self._transport.get('inventory')
1916
result = self._deserialize(f)
2743
self.branch.unlock()
2746
class WorkingTree3(WorkingTree):
2747
"""This is the Format 3 working tree.
2749
This differs from the base WorkingTree by:
2750
- having its own file lock
2751
- having its own last-revision property.
2753
This is new in bzr 0.8
2757
def _last_revision(self):
2758
"""See Mutable.last_revision."""
1919
self._set_inventory(result, dirty=False)
1921
def _set_root_id(self, file_id):
1922
"""Set the root id for this tree, in a format specific manner.
1924
:param file_id: The file id to assign to the root. It must not be
1925
present in the current inventory or an error will occur. It must
1926
not be None, but rather a valid file id.
1928
inv = self._inventory
1929
orig_root_id = inv.root.file_id
1930
# TODO: it might be nice to exit early if there was nothing
1931
# to do, saving us from trigger a sync on unlock.
1932
self._inventory_is_modified = True
1933
# we preserve the root inventory entry object, but
1934
# unlinkit from the byid index
1935
del inv._byid[inv.root.file_id]
1936
inv.root.file_id = file_id
1937
# and link it into the index with the new changed id.
1938
inv._byid[inv.root.file_id] = inv.root
1939
# and finally update all children to reference the new id.
1940
# XXX: this should be safe to just look at the root.children
1941
# list, not the WHOLE INVENTORY.
1944
if entry.parent_id == orig_root_id:
1945
entry.parent_id = inv.root.file_id
1947
def all_file_ids(self):
1948
"""See Tree.iter_all_file_ids"""
1949
return set(self.inventory)
1951
@needs_tree_write_lock
1952
def set_parent_trees(self, parents_list, allow_leftmost_as_ghost=False):
1953
"""See MutableTree.set_parent_trees."""
1954
parent_ids = [rev for (rev, tree) in parents_list]
1955
for revision_id in parent_ids:
1956
_mod_revision.check_not_reserved_id(revision_id)
1958
self._check_parents_for_ghosts(parent_ids,
1959
allow_leftmost_as_ghost=allow_leftmost_as_ghost)
1961
parent_ids = self._filter_parent_ids_by_ancestry(parent_ids)
1963
if len(parent_ids) == 0:
1964
leftmost_parent_id = _mod_revision.NULL_REVISION
1965
leftmost_parent_tree = None
1967
leftmost_parent_id, leftmost_parent_tree = parents_list[0]
1969
if self._change_last_revision(leftmost_parent_id):
1970
if leftmost_parent_tree is None:
1971
# If we don't have a tree, fall back to reading the
1972
# parent tree from the repository.
1973
self._cache_basis_inventory(leftmost_parent_id)
1975
inv = leftmost_parent_tree.inventory
1976
xml = self._create_basis_xml_from_inventory(
1977
leftmost_parent_id, inv)
1978
self._write_basis_inventory(xml)
1979
self._set_merges_from_parent_ids(parent_ids)
1981
def _cache_basis_inventory(self, new_revision):
1982
"""Cache new_revision as the basis inventory."""
1983
# TODO: this should allow the ready-to-use inventory to be passed in,
1984
# as commit already has that ready-to-use [while the format is the
2760
return self._transport.get_bytes('last-revision')
2761
except errors.NoSuchFile:
2762
return _mod_revision.NULL_REVISION
2764
def _change_last_revision(self, revision_id):
2765
"""See WorkingTree._change_last_revision."""
2766
if revision_id is None or revision_id == _mod_revision.NULL_REVISION:
2768
self._transport.delete('last-revision')
2769
except errors.NoSuchFile:
2773
self._transport.put_bytes('last-revision', revision_id,
2774
mode=self.bzrdir._get_file_mode())
2777
def _get_check_refs(self):
2778
"""Return the references needed to perform a check of this tree."""
2779
return [('trees', self.last_revision())]
1987
# this double handles the inventory - unpack and repack -
1988
# but is easier to understand. We can/should put a conditional
1989
# in here based on whether the inventory is in the latest format
1990
# - perhaps we should repack all inventories on a repository
1992
# the fast path is to copy the raw xml from the repository. If the
1993
# xml contains 'revision_id="', then we assume the right
1994
# revision_id is set. We must check for this full string, because a
1995
# root node id can legitimately look like 'revision_id' but cannot
1997
xml = self.branch.repository._get_inventory_xml(new_revision)
1998
firstline = xml.split('\n', 1)[0]
1999
if (not 'revision_id="' in firstline or
2000
'format="7"' not in firstline):
2001
inv = self.branch.repository._serializer.read_inventory_from_string(
2003
xml = self._create_basis_xml_from_inventory(new_revision, inv)
2004
self._write_basis_inventory(xml)
2005
except (errors.NoSuchRevision, errors.RevisionNotPresent):
2008
def _basis_inventory_name(self):
2009
return 'basis-inventory-cache'
2011
def _create_basis_xml_from_inventory(self, revision_id, inventory):
2012
"""Create the text that will be saved in basis-inventory"""
2013
inventory.revision_id = revision_id
2014
return xml7.serializer_v7.write_inventory_to_string(inventory)
2781
2016
@needs_tree_write_lock
2782
2017
def set_conflicts(self, conflicts):
2802
2037
raise errors.ConflictFormatError()
2803
2038
except StopIteration:
2804
2039
raise errors.ConflictFormatError()
2805
return _mod_conflicts.ConflictList.from_stanzas(RioReader(confile))
2040
reader = _mod_rio.RioReader(confile)
2041
return _mod_conflicts.ConflictList.from_stanzas(reader)
2807
2043
confile.close()
2810
# do non-implementation specific cleanup
2812
if self._control_files._lock_count == 1:
2813
# _inventory_is_modified is always False during a read lock.
2814
if self._inventory_is_modified:
2816
self._write_hashcache_if_dirty()
2817
# reverse order of locking.
2819
return self._control_files.unlock()
2821
self.branch.unlock()
2824
def get_conflicted_stem(path):
2825
for suffix in _mod_conflicts.CONFLICT_SUFFIXES:
2826
if path.endswith(suffix):
2827
return path[:-len(suffix)]
2830
class WorkingTreeFormat(object):
2045
def read_basis_inventory(self):
2046
"""Read the cached basis inventory."""
2047
path = self._basis_inventory_name()
2048
return self._transport.get_bytes(path)
2051
def read_working_inventory(self):
2052
"""Read the working inventory.
2054
:raises errors.InventoryModified: read_working_inventory will fail
2055
when the current in memory inventory has been modified.
2057
# conceptually this should be an implementation detail of the tree.
2058
# XXX: Deprecate this.
2059
# ElementTree does its own conversion from UTF-8, so open in
2061
if self._inventory_is_modified:
2062
raise errors.InventoryModified(self)
2063
f = self._transport.get('inventory')
2065
result = self._deserialize(f)
2068
self._set_inventory(result, dirty=False)
2072
def get_root_id(self):
2073
"""Return the id of this trees root"""
2074
return self._inventory.root.file_id
2076
def has_id(self, file_id):
2077
# files that have been deleted are excluded
2078
inv = self.inventory
2079
if not inv.has_id(file_id):
2081
path = inv.id2path(file_id)
2082
return osutils.lexists(self.abspath(path))
2084
def has_or_had_id(self, file_id):
2085
if file_id == self.inventory.root.file_id:
2087
return self.inventory.has_id(file_id)
2089
__contains__ = has_id
2091
@symbol_versioning.deprecated_method(symbol_versioning.deprecated_in((2, 4, 0)))
2093
"""Iterate through file_ids for this tree.
2095
file_ids are in a WorkingTree if they are in the working inventory
2096
and the working file exists.
2098
inv = self._inventory
2099
for path, ie in inv.iter_entries():
2100
if osutils.lexists(self.abspath(path)):
2103
@needs_tree_write_lock
2104
def set_last_revision(self, new_revision):
2105
"""Change the last revision in the working tree."""
2106
if self._change_last_revision(new_revision):
2107
self._cache_basis_inventory(new_revision)
2109
def _get_check_refs(self):
2110
"""Return the references needed to perform a check of this tree.
2112
The default implementation returns no refs, and is only suitable for
2113
trees that have no local caching and can commit on ghosts at any time.
2115
:seealso: bzrlib.check for details about check_refs.
2120
def _check(self, references):
2121
"""Check the tree for consistency.
2123
:param references: A dict with keys matching the items returned by
2124
self._get_check_refs(), and values from looking those keys up in
2127
tree_basis = self.basis_tree()
2128
tree_basis.lock_read()
2130
repo_basis = references[('trees', self.last_revision())]
2131
if len(list(repo_basis.iter_changes(tree_basis))) > 0:
2132
raise errors.BzrCheckError(
2133
"Mismatched basis inventory content.")
2139
def check_state(self):
2140
"""Check that the working state is/isn't valid."""
2141
check_refs = self._get_check_refs()
2143
for ref in check_refs:
2146
refs[ref] = self.branch.repository.revision_tree(value)
2149
@needs_tree_write_lock
2150
def reset_state(self, revision_ids=None):
2151
"""Reset the state of the working tree.
2153
This does a hard-reset to a last-known-good state. This is a way to
2154
fix if something got corrupted (like the .bzr/checkout/dirstate file)
2156
if revision_ids is None:
2157
revision_ids = self.get_parent_ids()
2158
if not revision_ids:
2159
rt = self.branch.repository.revision_tree(
2160
_mod_revision.NULL_REVISION)
2162
rt = self.branch.repository.revision_tree(revision_ids[0])
2163
self._write_inventory(rt.inventory)
2164
self.set_parent_ids(revision_ids)
2167
"""Write the in memory inventory to disk."""
2168
# TODO: Maybe this should only write on dirty ?
2169
if self._control_files._lock_mode != 'w':
2170
raise errors.NotWriteLocked(self)
2172
self._serialize(self._inventory, sio)
2174
self._transport.put_file('inventory', sio,
2175
mode=self.bzrdir._get_file_mode())
2176
self._inventory_is_modified = False
2179
def get_file_sha1(self, file_id, path=None, stat_value=None):
2181
path = self._inventory.id2path(file_id)
2182
return self._hashcache.get_sha1(path, stat_value)
2184
def get_file_mtime(self, file_id, path=None):
2185
"""See Tree.get_file_mtime."""
2187
path = self.inventory.id2path(file_id)
2188
return os.lstat(self.abspath(path)).st_mtime
2190
def _is_executable_from_path_and_stat_from_basis(self, path, stat_result):
2191
file_id = self.path2id(path)
2193
# For unversioned files on win32, we just assume they are not
2196
return self._inventory[file_id].executable
2198
def _is_executable_from_path_and_stat_from_stat(self, path, stat_result):
2199
mode = stat_result.st_mode
2200
return bool(stat.S_ISREG(mode) and stat.S_IEXEC & mode)
2202
if not supports_executable():
2203
def is_executable(self, file_id, path=None):
2204
return self._inventory[file_id].executable
2206
_is_executable_from_path_and_stat = \
2207
_is_executable_from_path_and_stat_from_basis
2209
def is_executable(self, file_id, path=None):
2211
path = self.id2path(file_id)
2212
mode = os.lstat(self.abspath(path)).st_mode
2213
return bool(stat.S_ISREG(mode) and stat.S_IEXEC & mode)
2215
_is_executable_from_path_and_stat = \
2216
_is_executable_from_path_and_stat_from_stat
2218
@needs_tree_write_lock
2219
def _add(self, files, ids, kinds):
2220
"""See MutableTree._add."""
2221
# TODO: Re-adding a file that is removed in the working copy
2222
# should probably put it back with the previous ID.
2223
# the read and write working inventory should not occur in this
2224
# function - they should be part of lock_write and unlock.
2225
inv = self.inventory
2226
for f, file_id, kind in zip(files, ids, kinds):
2228
inv.add_path(f, kind=kind)
2230
inv.add_path(f, kind=kind, file_id=file_id)
2231
self._inventory_is_modified = True
2233
def revision_tree(self, revision_id):
2234
"""See WorkingTree.revision_id."""
2235
if revision_id == self.last_revision():
2237
xml = self.read_basis_inventory()
2238
except errors.NoSuchFile:
2242
inv = xml7.serializer_v7.read_inventory_from_string(xml)
2243
# dont use the repository revision_tree api because we want
2244
# to supply the inventory.
2245
if inv.revision_id == revision_id:
2246
return revisiontree.InventoryRevisionTree(
2247
self.branch.repository, inv, revision_id)
2248
except errors.BadInventoryFormat:
2250
# raise if there was no inventory, or if we read the wrong inventory.
2251
raise errors.NoSuchRevisionInTree(self, revision_id)
2254
def annotate_iter(self, file_id, default_revision=CURRENT_REVISION):
2255
"""See Tree.annotate_iter
2257
This implementation will use the basis tree implementation if possible.
2258
Lines not in the basis are attributed to CURRENT_REVISION
2260
If there are pending merges, lines added by those merges will be
2261
incorrectly attributed to CURRENT_REVISION (but after committing, the
2262
attribution will be correct).
2264
maybe_file_parent_keys = []
2265
for parent_id in self.get_parent_ids():
2267
parent_tree = self.revision_tree(parent_id)
2268
except errors.NoSuchRevisionInTree:
2269
parent_tree = self.branch.repository.revision_tree(parent_id)
2270
parent_tree.lock_read()
2272
if file_id not in parent_tree:
2274
ie = parent_tree.inventory[file_id]
2275
if ie.kind != 'file':
2276
# Note: this is slightly unnecessary, because symlinks and
2277
# directories have a "text" which is the empty text, and we
2278
# know that won't mess up annotations. But it seems cleaner
2280
parent_text_key = (file_id, ie.revision)
2281
if parent_text_key not in maybe_file_parent_keys:
2282
maybe_file_parent_keys.append(parent_text_key)
2284
parent_tree.unlock()
2285
graph = _mod_graph.Graph(self.branch.repository.texts)
2286
heads = graph.heads(maybe_file_parent_keys)
2287
file_parent_keys = []
2288
for key in maybe_file_parent_keys:
2290
file_parent_keys.append(key)
2292
# Now we have the parents of this content
2293
annotator = self.branch.repository.texts.get_annotator()
2294
text = self.get_file_text(file_id)
2295
this_key =(file_id, default_revision)
2296
annotator.add_special_text(this_key, file_parent_keys, text)
2297
annotations = [(key[-1], line)
2298
for key, line in annotator.annotate_flat(this_key)]
2302
def merge_modified(self):
2303
"""Return a dictionary of files modified by a merge.
2305
The list is initialized by WorkingTree.set_merge_modified, which is
2306
typically called after we make some automatic updates to the tree
2309
This returns a map of file_id->sha1, containing only files which are
2310
still in the working inventory and have that text hash.
2313
hashfile = self._transport.get('merge-hashes')
2314
except errors.NoSuchFile:
2319
if hashfile.next() != MERGE_MODIFIED_HEADER_1 + '\n':
2320
raise errors.MergeModifiedFormatError()
2321
except StopIteration:
2322
raise errors.MergeModifiedFormatError()
2323
for s in _mod_rio.RioReader(hashfile):
2324
# RioReader reads in Unicode, so convert file_ids back to utf8
2325
file_id = osutils.safe_file_id(s.get("file_id"), warn=False)
2326
if file_id not in self.inventory:
2328
text_hash = s.get("hash")
2329
if text_hash == self.get_file_sha1(file_id):
2330
merge_hashes[file_id] = text_hash
2336
def subsume(self, other_tree):
2337
def add_children(inventory, entry):
2338
for child_entry in entry.children.values():
2339
inventory._byid[child_entry.file_id] = child_entry
2340
if child_entry.kind == 'directory':
2341
add_children(inventory, child_entry)
2342
if other_tree.get_root_id() == self.get_root_id():
2343
raise errors.BadSubsumeSource(self, other_tree,
2344
'Trees have the same root')
2346
other_tree_path = self.relpath(other_tree.basedir)
2347
except errors.PathNotChild:
2348
raise errors.BadSubsumeSource(self, other_tree,
2349
'Tree is not contained by the other')
2350
new_root_parent = self.path2id(osutils.dirname(other_tree_path))
2351
if new_root_parent is None:
2352
raise errors.BadSubsumeSource(self, other_tree,
2353
'Parent directory is not versioned.')
2354
# We need to ensure that the result of a fetch will have a
2355
# versionedfile for the other_tree root, and only fetching into
2356
# RepositoryKnit2 guarantees that.
2357
if not self.branch.repository.supports_rich_root():
2358
raise errors.SubsumeTargetNeedsUpgrade(other_tree)
2359
other_tree.lock_tree_write()
2361
new_parents = other_tree.get_parent_ids()
2362
other_root = other_tree.inventory.root
2363
other_root.parent_id = new_root_parent
2364
other_root.name = osutils.basename(other_tree_path)
2365
self.inventory.add(other_root)
2366
add_children(self.inventory, other_root)
2367
self._write_inventory(self.inventory)
2368
# normally we don't want to fetch whole repositories, but i think
2369
# here we really do want to consolidate the whole thing.
2370
for parent_id in other_tree.get_parent_ids():
2371
self.branch.fetch(other_tree.branch, parent_id)
2372
self.add_parent_tree_id(parent_id)
2375
other_tree.bzrdir.retire_bzrdir()
2377
@needs_tree_write_lock
2378
def extract(self, file_id, format=None):
2379
"""Extract a subtree from this tree.
2381
A new branch will be created, relative to the path for this tree.
2385
segments = osutils.splitpath(path)
2386
transport = self.branch.bzrdir.root_transport
2387
for name in segments:
2388
transport = transport.clone(name)
2389
transport.ensure_base()
2392
sub_path = self.id2path(file_id)
2393
branch_transport = mkdirs(sub_path)
2395
format = self.bzrdir.cloning_metadir()
2396
branch_transport.ensure_base()
2397
branch_bzrdir = format.initialize_on_transport(branch_transport)
2399
repo = branch_bzrdir.find_repository()
2400
except errors.NoRepositoryPresent:
2401
repo = branch_bzrdir.create_repository()
2402
if not repo.supports_rich_root():
2403
raise errors.RootNotRich()
2404
new_branch = branch_bzrdir.create_branch()
2405
new_branch.pull(self.branch)
2406
for parent_id in self.get_parent_ids():
2407
new_branch.fetch(self.branch, parent_id)
2408
tree_transport = self.bzrdir.root_transport.clone(sub_path)
2409
if tree_transport.base != branch_transport.base:
2410
tree_bzrdir = format.initialize_on_transport(tree_transport)
2411
branch.BranchReferenceFormat().initialize(tree_bzrdir,
2412
target_branch=new_branch)
2414
tree_bzrdir = branch_bzrdir
2415
wt = tree_bzrdir.create_workingtree(_mod_revision.NULL_REVISION)
2416
wt.set_parent_ids(self.get_parent_ids())
2417
my_inv = self.inventory
2418
child_inv = inventory.Inventory(root_id=None)
2419
new_root = my_inv[file_id]
2420
my_inv.remove_recursive_id(file_id)
2421
new_root.parent_id = None
2422
child_inv.add(new_root)
2423
self._write_inventory(my_inv)
2424
wt._write_inventory(child_inv)
2427
def list_files(self, include_root=False, from_dir=None, recursive=True):
2428
"""List all files as (path, class, kind, id, entry).
2430
Lists, but does not descend into unversioned directories.
2431
This does not include files that have been deleted in this
2432
tree. Skips the control directory.
2434
:param include_root: if True, return an entry for the root
2435
:param from_dir: start from this directory or None for the root
2436
:param recursive: whether to recurse into subdirectories or not
2438
# list_files is an iterator, so @needs_read_lock doesn't work properly
2439
# with it. So callers should be careful to always read_lock the tree.
2440
if not self.is_locked():
2441
raise errors.ObjectNotLocked(self)
2443
inv = self.inventory
2444
if from_dir is None and include_root is True:
2445
yield ('', 'V', 'directory', inv.root.file_id, inv.root)
2446
# Convert these into local objects to save lookup times
2447
pathjoin = osutils.pathjoin
2448
file_kind = self._kind
2450
# transport.base ends in a slash, we want the piece
2451
# between the last two slashes
2452
transport_base_dir = self.bzrdir.transport.base.rsplit('/', 2)[1]
2454
fk_entries = {'directory':TreeDirectory, 'file':TreeFile, 'symlink':TreeLink}
2456
# directory file_id, relative path, absolute path, reverse sorted children
2457
if from_dir is not None:
2458
from_dir_id = inv.path2id(from_dir)
2459
if from_dir_id is None:
2460
# Directory not versioned
2462
from_dir_abspath = pathjoin(self.basedir, from_dir)
2464
from_dir_id = inv.root.file_id
2465
from_dir_abspath = self.basedir
2466
children = os.listdir(from_dir_abspath)
2468
# jam 20060527 The kernel sized tree seems equivalent whether we
2469
# use a deque and popleft to keep them sorted, or if we use a plain
2470
# list and just reverse() them.
2471
children = collections.deque(children)
2472
stack = [(from_dir_id, u'', from_dir_abspath, children)]
2474
from_dir_id, from_dir_relpath, from_dir_abspath, children = stack[-1]
2477
f = children.popleft()
2478
## TODO: If we find a subdirectory with its own .bzr
2479
## directory, then that is a separate tree and we
2480
## should exclude it.
2482
# the bzrdir for this tree
2483
if transport_base_dir == f:
2486
# we know that from_dir_relpath and from_dir_abspath never end in a slash
2487
# and 'f' doesn't begin with one, we can do a string op, rather
2488
# than the checks of pathjoin(), all relative paths will have an extra slash
2490
fp = from_dir_relpath + '/' + f
2493
fap = from_dir_abspath + '/' + f
2495
dir_ie = inv[from_dir_id]
2496
if dir_ie.kind == 'directory':
2497
f_ie = dir_ie.children.get(f)
2502
elif self.is_ignored(fp[1:]):
2505
# we may not have found this file, because of a unicode
2506
# issue, or because the directory was actually a symlink.
2507
f_norm, can_access = osutils.normalized_filename(f)
2508
if f == f_norm or not can_access:
2509
# No change, so treat this file normally
2512
# this file can be accessed by a normalized path
2513
# check again if it is versioned
2514
# these lines are repeated here for performance
2516
fp = from_dir_relpath + '/' + f
2517
fap = from_dir_abspath + '/' + f
2518
f_ie = inv.get_child(from_dir_id, f)
2521
elif self.is_ignored(fp[1:]):
2528
# make a last minute entry
2530
yield fp[1:], c, fk, f_ie.file_id, f_ie
2533
yield fp[1:], c, fk, None, fk_entries[fk]()
2535
yield fp[1:], c, fk, None, TreeEntry()
2538
if fk != 'directory':
2541
# But do this child first if recursing down
2543
new_children = os.listdir(fap)
2545
new_children = collections.deque(new_children)
2546
stack.append((f_ie.file_id, fp, fap, new_children))
2547
# Break out of inner loop,
2548
# so that we start outer loop with child
2551
# if we finished all children, pop it off the stack
2554
@needs_tree_write_lock
2555
def move(self, from_paths, to_dir=None, after=False):
2558
to_dir must exist in the inventory.
2560
If to_dir exists and is a directory, the files are moved into
2561
it, keeping their old names.
2563
Note that to_dir is only the last component of the new name;
2564
this doesn't change the directory.
2566
For each entry in from_paths the move mode will be determined
2569
The first mode moves the file in the filesystem and updates the
2570
inventory. The second mode only updates the inventory without
2571
touching the file on the filesystem.
2573
move uses the second mode if 'after == True' and the target is not
2574
versioned but present in the working tree.
2576
move uses the second mode if 'after == False' and the source is
2577
versioned but no longer in the working tree, and the target is not
2578
versioned but present in the working tree.
2580
move uses the first mode if 'after == False' and the source is
2581
versioned and present in the working tree, and the target is not
2582
versioned and not present in the working tree.
2584
Everything else results in an error.
2586
This returns a list of (from_path, to_path) pairs for each
2587
entry that is moved.
2592
# check for deprecated use of signature
2594
raise TypeError('You must supply a target directory')
2595
# check destination directory
2596
if isinstance(from_paths, basestring):
2598
inv = self.inventory
2599
to_abs = self.abspath(to_dir)
2600
if not isdir(to_abs):
2601
raise errors.BzrMoveFailedError('',to_dir,
2602
errors.NotADirectory(to_abs))
2603
if not self.has_filename(to_dir):
2604
raise errors.BzrMoveFailedError('',to_dir,
2605
errors.NotInWorkingDirectory(to_dir))
2606
to_dir_id = inv.path2id(to_dir)
2607
if to_dir_id is None:
2608
raise errors.BzrMoveFailedError('',to_dir,
2609
errors.NotVersionedError(path=to_dir))
2611
to_dir_ie = inv[to_dir_id]
2612
if to_dir_ie.kind != 'directory':
2613
raise errors.BzrMoveFailedError('',to_dir,
2614
errors.NotADirectory(to_abs))
2616
# create rename entries and tuples
2617
for from_rel in from_paths:
2618
from_tail = splitpath(from_rel)[-1]
2619
from_id = inv.path2id(from_rel)
2621
raise errors.BzrMoveFailedError(from_rel,to_dir,
2622
errors.NotVersionedError(path=from_rel))
2624
from_entry = inv[from_id]
2625
from_parent_id = from_entry.parent_id
2626
to_rel = pathjoin(to_dir, from_tail)
2627
rename_entry = InventoryWorkingTree._RenameEntry(
2630
from_tail=from_tail,
2631
from_parent_id=from_parent_id,
2632
to_rel=to_rel, to_tail=from_tail,
2633
to_parent_id=to_dir_id)
2634
rename_entries.append(rename_entry)
2635
rename_tuples.append((from_rel, to_rel))
2637
# determine which move mode to use. checks also for movability
2638
rename_entries = self._determine_mv_mode(rename_entries, after)
2640
original_modified = self._inventory_is_modified
2643
self._inventory_is_modified = True
2644
self._move(rename_entries)
2646
# restore the inventory on error
2647
self._inventory_is_modified = original_modified
2649
self._write_inventory(inv)
2650
return rename_tuples
2652
@needs_tree_write_lock
2653
def rename_one(self, from_rel, to_rel, after=False):
2656
This can change the directory or the filename or both.
2658
rename_one has several 'modes' to work. First, it can rename a physical
2659
file and change the file_id. That is the normal mode. Second, it can
2660
only change the file_id without touching any physical file.
2662
rename_one uses the second mode if 'after == True' and 'to_rel' is not
2663
versioned but present in the working tree.
2665
rename_one uses the second mode if 'after == False' and 'from_rel' is
2666
versioned but no longer in the working tree, and 'to_rel' is not
2667
versioned but present in the working tree.
2669
rename_one uses the first mode if 'after == False' and 'from_rel' is
2670
versioned and present in the working tree, and 'to_rel' is not
2671
versioned and not present in the working tree.
2673
Everything else results in an error.
2675
inv = self.inventory
2678
# create rename entries and tuples
2679
from_tail = splitpath(from_rel)[-1]
2680
from_id = inv.path2id(from_rel)
2682
# if file is missing in the inventory maybe it's in the basis_tree
2683
basis_tree = self.branch.basis_tree()
2684
from_id = basis_tree.path2id(from_rel)
2686
raise errors.BzrRenameFailedError(from_rel,to_rel,
2687
errors.NotVersionedError(path=from_rel))
2688
# put entry back in the inventory so we can rename it
2689
from_entry = basis_tree.inventory[from_id].copy()
2692
from_entry = inv[from_id]
2693
from_parent_id = from_entry.parent_id
2694
to_dir, to_tail = os.path.split(to_rel)
2695
to_dir_id = inv.path2id(to_dir)
2696
rename_entry = InventoryWorkingTree._RenameEntry(from_rel=from_rel,
2698
from_tail=from_tail,
2699
from_parent_id=from_parent_id,
2700
to_rel=to_rel, to_tail=to_tail,
2701
to_parent_id=to_dir_id)
2702
rename_entries.append(rename_entry)
2704
# determine which move mode to use. checks also for movability
2705
rename_entries = self._determine_mv_mode(rename_entries, after)
2707
# check if the target changed directory and if the target directory is
2709
if to_dir_id is None:
2710
raise errors.BzrMoveFailedError(from_rel,to_rel,
2711
errors.NotVersionedError(path=to_dir))
2713
# all checks done. now we can continue with our actual work
2714
mutter('rename_one:\n'
2719
' to_dir_id {%s}\n',
2720
from_id, from_rel, to_rel, to_dir, to_dir_id)
2722
self._move(rename_entries)
2723
self._write_inventory(inv)
2725
class _RenameEntry(object):
2726
def __init__(self, from_rel, from_id, from_tail, from_parent_id,
2727
to_rel, to_tail, to_parent_id, only_change_inv=False):
2728
self.from_rel = from_rel
2729
self.from_id = from_id
2730
self.from_tail = from_tail
2731
self.from_parent_id = from_parent_id
2732
self.to_rel = to_rel
2733
self.to_tail = to_tail
2734
self.to_parent_id = to_parent_id
2735
self.only_change_inv = only_change_inv
2737
def _determine_mv_mode(self, rename_entries, after=False):
2738
"""Determines for each from-to pair if both inventory and working tree
2739
or only the inventory has to be changed.
2741
Also does basic plausability tests.
2743
inv = self.inventory
2745
for rename_entry in rename_entries:
2746
# store to local variables for easier reference
2747
from_rel = rename_entry.from_rel
2748
from_id = rename_entry.from_id
2749
to_rel = rename_entry.to_rel
2750
to_id = inv.path2id(to_rel)
2751
only_change_inv = False
2753
# check the inventory for source and destination
2755
raise errors.BzrMoveFailedError(from_rel,to_rel,
2756
errors.NotVersionedError(path=from_rel))
2757
if to_id is not None:
2758
raise errors.BzrMoveFailedError(from_rel,to_rel,
2759
errors.AlreadyVersionedError(path=to_rel))
2761
# try to determine the mode for rename (only change inv or change
2762
# inv and file system)
2764
if not self.has_filename(to_rel):
2765
raise errors.BzrMoveFailedError(from_id,to_rel,
2766
errors.NoSuchFile(path=to_rel,
2767
extra="New file has not been created yet"))
2768
only_change_inv = True
2769
elif not self.has_filename(from_rel) and self.has_filename(to_rel):
2770
only_change_inv = True
2771
elif self.has_filename(from_rel) and not self.has_filename(to_rel):
2772
only_change_inv = False
2773
elif (not self.case_sensitive
2774
and from_rel.lower() == to_rel.lower()
2775
and self.has_filename(from_rel)):
2776
only_change_inv = False
2778
# something is wrong, so lets determine what exactly
2779
if not self.has_filename(from_rel) and \
2780
not self.has_filename(to_rel):
2781
raise errors.BzrRenameFailedError(from_rel,to_rel,
2782
errors.PathsDoNotExist(paths=(str(from_rel),
2785
raise errors.RenameFailedFilesExist(from_rel, to_rel)
2786
rename_entry.only_change_inv = only_change_inv
2787
return rename_entries
2789
def _move(self, rename_entries):
2790
"""Moves a list of files.
2792
Depending on the value of the flag 'only_change_inv', the
2793
file will be moved on the file system or not.
2795
inv = self.inventory
2798
for entry in rename_entries:
2800
self._move_entry(entry)
2802
self._rollback_move(moved)
2806
def _rollback_move(self, moved):
2807
"""Try to rollback a previous move in case of an filesystem error."""
2808
inv = self.inventory
2811
self._move_entry(WorkingTree._RenameEntry(
2812
entry.to_rel, entry.from_id,
2813
entry.to_tail, entry.to_parent_id, entry.from_rel,
2814
entry.from_tail, entry.from_parent_id,
2815
entry.only_change_inv))
2816
except errors.BzrMoveFailedError, e:
2817
raise errors.BzrMoveFailedError( '', '', "Rollback failed."
2818
" The working tree is in an inconsistent state."
2819
" Please consider doing a 'bzr revert'."
2820
" Error message is: %s" % e)
2822
def _move_entry(self, entry):
2823
inv = self.inventory
2824
from_rel_abs = self.abspath(entry.from_rel)
2825
to_rel_abs = self.abspath(entry.to_rel)
2826
if from_rel_abs == to_rel_abs:
2827
raise errors.BzrMoveFailedError(entry.from_rel, entry.to_rel,
2828
"Source and target are identical.")
2830
if not entry.only_change_inv:
2832
osutils.rename(from_rel_abs, to_rel_abs)
2834
raise errors.BzrMoveFailedError(entry.from_rel,
2836
inv.rename(entry.from_id, entry.to_parent_id, entry.to_tail)
2838
@needs_tree_write_lock
2839
def unversion(self, file_ids):
2840
"""Remove the file ids in file_ids from the current versioned set.
2842
When a file_id is unversioned, all of its children are automatically
2845
:param file_ids: The file ids to stop versioning.
2846
:raises: NoSuchId if any fileid is not currently versioned.
2848
for file_id in file_ids:
2849
if file_id not in self._inventory:
2850
raise errors.NoSuchId(self, file_id)
2851
for file_id in file_ids:
2852
if self._inventory.has_id(file_id):
2853
self._inventory.remove_recursive_id(file_id)
2855
# in the future this should just set a dirty bit to wait for the
2856
# final unlock. However, until all methods of workingtree start
2857
# with the current in -memory inventory rather than triggering
2858
# a read, it is more complex - we need to teach read_inventory
2859
# to know when to read, and when to not read first... and possibly
2860
# to save first when the in memory one may be corrupted.
2861
# so for now, we just only write it if it is indeed dirty.
2863
self._write_inventory(self._inventory)
2865
def stored_kind(self, file_id):
2866
"""See Tree.stored_kind"""
2867
return self.inventory[file_id].kind
2870
"""Yield all unversioned files in this WorkingTree.
2872
If there are any unversioned directories then only the directory is
2873
returned, not all its children. But if there are unversioned files
2874
under a versioned subdirectory, they are returned.
2876
Currently returned depth-first, sorted by name within directories.
2877
This is the same order used by 'osutils.walkdirs'.
2879
## TODO: Work from given directory downwards
2880
for path, dir_entry in self.inventory.directories():
2881
# mutter("search for unknowns in %r", path)
2882
dirabs = self.abspath(path)
2883
if not isdir(dirabs):
2884
# e.g. directory deleted
2888
for subf in os.listdir(dirabs):
2889
if self.bzrdir.is_control_filename(subf):
2891
if subf not in dir_entry.children:
2894
can_access) = osutils.normalized_filename(subf)
2895
except UnicodeDecodeError:
2896
path_os_enc = path.encode(osutils._fs_enc)
2897
relpath = path_os_enc + '/' + subf
2898
raise errors.BadFilenameEncoding(relpath,
2900
if subf_norm != subf and can_access:
2901
if subf_norm not in dir_entry.children:
2902
fl.append(subf_norm)
2908
subp = pathjoin(path, subf)
2911
def _walkdirs(self, prefix=""):
2912
"""Walk the directories of this tree.
2914
:prefix: is used as the directrory to start with.
2915
returns a generator which yields items in the form:
2916
((curren_directory_path, fileid),
2917
[(file1_path, file1_name, file1_kind, None, file1_id,
2920
_directory = 'directory'
2921
# get the root in the inventory
2922
inv = self.inventory
2923
top_id = inv.path2id(prefix)
2927
pending = [(prefix, '', _directory, None, top_id, None)]
2930
currentdir = pending.pop()
2931
# 0 - relpath, 1- basename, 2- kind, 3- stat, 4-id, 5-kind
2932
top_id = currentdir[4]
2934
relroot = currentdir[0] + '/'
2937
# FIXME: stash the node in pending
2939
if entry.kind == 'directory':
2940
for name, child in entry.sorted_children():
2941
dirblock.append((relroot + name, name, child.kind, None,
2942
child.file_id, child.kind
2944
yield (currentdir[0], entry.file_id), dirblock
2945
# push the user specified dirs from dirblock
2946
for dir in reversed(dirblock):
2947
if dir[2] == _directory:
2951
class WorkingTreeFormatRegistry(controldir.ControlComponentFormatRegistry):
2952
"""Registry for working tree formats."""
2954
def __init__(self, other_registry=None):
2955
super(WorkingTreeFormatRegistry, self).__init__(other_registry)
2956
self._default_format = None
2957
self._default_format_key = None
2959
def get_default(self):
2960
"""Return the current default format."""
2961
if (self._default_format_key is not None and
2962
self._default_format is None):
2963
self._default_format = self.get(self._default_format_key)
2964
return self._default_format
2966
def set_default(self, format):
2967
"""Set the default format."""
2968
self._default_format = format
2969
self._default_format_key = None
2971
def set_default_key(self, format_string):
2972
"""Set the default format by its format string."""
2973
self._default_format_key = format_string
2974
self._default_format = None
2977
format_registry = WorkingTreeFormatRegistry()
2980
class WorkingTreeFormat(controldir.ControlComponentFormat):
2831
2981
"""An encapsulation of the initialization and open routines for a format.
2833
2983
Formats provide three things:
3084
@symbol_versioning.deprecated_method(
3085
symbol_versioning.deprecated_in((2, 4, 0)))
2908
3086
def register_format(klass, format):
2909
klass._formats[format.get_format_string()] = format
3087
format_registry.register(format)
3090
@symbol_versioning.deprecated_method(
3091
symbol_versioning.deprecated_in((2, 4, 0)))
3092
def register_extra_format(klass, format):
3093
format_registry.register_extra(format)
3096
@symbol_versioning.deprecated_method(
3097
symbol_versioning.deprecated_in((2, 4, 0)))
3098
def unregister_extra_format(klass, format):
3099
format_registry.unregister_extra(format)
3102
@symbol_versioning.deprecated_method(
3103
symbol_versioning.deprecated_in((2, 4, 0)))
3104
def get_formats(klass):
3105
return format_registry._get_all()
3108
@symbol_versioning.deprecated_method(
3109
symbol_versioning.deprecated_in((2, 4, 0)))
2912
3110
def set_default_format(klass, format):
2913
klass._default_format = format
3111
format_registry.set_default(format)
3114
@symbol_versioning.deprecated_method(
3115
symbol_versioning.deprecated_in((2, 4, 0)))
2916
3116
def unregister_format(klass, format):
2917
del klass._formats[format.get_format_string()]
2920
class WorkingTreeFormat2(WorkingTreeFormat):
2921
"""The second working tree format.
2923
This format modified the hash cache from the format 1 hash cache.
2926
upgrade_recommended = True
2928
def get_format_description(self):
2929
"""See WorkingTreeFormat.get_format_description()."""
2930
return "Working tree format 2"
2932
def _stub_initialize_on_transport(self, transport, file_mode):
2933
"""Workaround: create control files for a remote working tree.
2935
This ensures that it can later be updated and dealt with locally,
2936
since BzrDirFormat6 and BzrDirFormat5 cannot represent dirs with
2937
no working tree. (See bug #43064).
2940
inv = inventory.Inventory()
2941
xml5.serializer_v5.write_inventory(inv, sio, working=True)
2943
transport.put_file('inventory', sio, file_mode)
2944
transport.put_bytes('pending-merges', '', file_mode)
2946
def initialize(self, a_bzrdir, revision_id=None, from_branch=None,
2947
accelerator_tree=None, hardlink=False):
2948
"""See WorkingTreeFormat.initialize()."""
2949
if not isinstance(a_bzrdir.transport, LocalTransport):
2950
raise errors.NotLocalUrl(a_bzrdir.transport.base)
2951
if from_branch is not None:
2952
branch = from_branch
2954
branch = a_bzrdir.open_branch()
2955
if revision_id is None:
2956
revision_id = _mod_revision.ensure_null(branch.last_revision())
2959
branch.generate_revision_history(revision_id)
2962
inv = inventory.Inventory()
2963
wt = WorkingTree2(a_bzrdir.root_transport.local_abspath('.'),
2969
basis_tree = branch.repository.revision_tree(revision_id)
2970
if basis_tree.inventory.root is not None:
2971
wt.set_root_id(basis_tree.get_root_id())
2972
# set the parent list and cache the basis tree.
2973
if _mod_revision.is_null(revision_id):
2976
parent_trees = [(revision_id, basis_tree)]
2977
wt.set_parent_trees(parent_trees)
2978
transform.build_tree(basis_tree, wt)
2982
super(WorkingTreeFormat2, self).__init__()
2983
self._matchingbzrdir = bzrdir.BzrDirFormat6()
2985
def open(self, a_bzrdir, _found=False):
2986
"""Return the WorkingTree object for a_bzrdir
2988
_found is a private parameter, do not use it. It is used to indicate
2989
if format probing has already been done.
2992
# we are being called directly and must probe.
2993
raise NotImplementedError
2994
if not isinstance(a_bzrdir.transport, LocalTransport):
2995
raise errors.NotLocalUrl(a_bzrdir.transport.base)
2996
wt = WorkingTree2(a_bzrdir.root_transport.local_abspath('.'),
3002
class WorkingTreeFormat3(WorkingTreeFormat):
3003
"""The second working tree format updated to record a format marker.
3006
- exists within a metadir controlling .bzr
3007
- includes an explicit version marker for the workingtree control
3008
files, separate from the BzrDir format
3009
- modifies the hash cache format
3011
- uses a LockDir to guard access for writes.
3014
upgrade_recommended = True
3016
def get_format_string(self):
3017
"""See WorkingTreeFormat.get_format_string()."""
3018
return "Bazaar-NG Working Tree format 3"
3020
def get_format_description(self):
3021
"""See WorkingTreeFormat.get_format_description()."""
3022
return "Working tree format 3"
3024
_lock_file_name = 'lock'
3025
_lock_class = LockDir
3027
_tree_class = WorkingTree3
3029
def __get_matchingbzrdir(self):
3030
return bzrdir.BzrDirMetaFormat1()
3032
_matchingbzrdir = property(__get_matchingbzrdir)
3034
def _open_control_files(self, a_bzrdir):
3035
transport = a_bzrdir.get_workingtree_transport(None)
3036
return LockableFiles(transport, self._lock_file_name,
3039
def initialize(self, a_bzrdir, revision_id=None, from_branch=None,
3040
accelerator_tree=None, hardlink=False):
3041
"""See WorkingTreeFormat.initialize().
3043
:param revision_id: if supplied, create a working tree at a different
3044
revision than the branch is at.
3045
:param accelerator_tree: A tree which can be used for retrieving file
3046
contents more quickly than the revision tree, i.e. a workingtree.
3047
The revision tree will be used for cases where accelerator_tree's
3048
content is different.
3049
:param hardlink: If true, hard-link files from accelerator_tree,
3052
if not isinstance(a_bzrdir.transport, LocalTransport):
3053
raise errors.NotLocalUrl(a_bzrdir.transport.base)
3054
transport = a_bzrdir.get_workingtree_transport(self)
3055
control_files = self._open_control_files(a_bzrdir)
3056
control_files.create_lock()
3057
control_files.lock_write()
3058
transport.put_bytes('format', self.get_format_string(),
3059
mode=a_bzrdir._get_file_mode())
3060
if from_branch is not None:
3061
branch = from_branch
3063
branch = a_bzrdir.open_branch()
3064
if revision_id is None:
3065
revision_id = _mod_revision.ensure_null(branch.last_revision())
3066
# WorkingTree3 can handle an inventory which has a unique root id.
3067
# as of bzr 0.12. However, bzr 0.11 and earlier fail to handle
3068
# those trees. And because there isn't a format bump inbetween, we
3069
# are maintaining compatibility with older clients.
3070
# inv = Inventory(root_id=gen_root_id())
3071
inv = self._initial_inventory()
3072
wt = self._tree_class(a_bzrdir.root_transport.local_abspath('.'),
3078
_control_files=control_files)
3079
wt.lock_tree_write()
3081
basis_tree = branch.repository.revision_tree(revision_id)
3082
# only set an explicit root id if there is one to set.
3083
if basis_tree.inventory.root is not None:
3084
wt.set_root_id(basis_tree.get_root_id())
3085
if revision_id == _mod_revision.NULL_REVISION:
3086
wt.set_parent_trees([])
3088
wt.set_parent_trees([(revision_id, basis_tree)])
3089
transform.build_tree(basis_tree, wt)
3091
# Unlock in this order so that the unlock-triggers-flush in
3092
# WorkingTree is given a chance to fire.
3093
control_files.unlock()
3097
def _initial_inventory(self):
3098
return inventory.Inventory()
3101
super(WorkingTreeFormat3, self).__init__()
3103
def open(self, a_bzrdir, _found=False):
3104
"""Return the WorkingTree object for a_bzrdir
3106
_found is a private parameter, do not use it. It is used to indicate
3107
if format probing has already been done.
3110
# we are being called directly and must probe.
3111
raise NotImplementedError
3112
if not isinstance(a_bzrdir.transport, LocalTransport):
3113
raise errors.NotLocalUrl(a_bzrdir.transport.base)
3114
wt = self._open(a_bzrdir, self._open_control_files(a_bzrdir))
3117
def _open(self, a_bzrdir, control_files):
3118
"""Open the tree itself.
3120
:param a_bzrdir: the dir for the tree.
3121
:param control_files: the control files for the tree.
3123
return self._tree_class(a_bzrdir.root_transport.local_abspath('.'),
3127
_control_files=control_files)
3130
return self.get_format_string()
3133
__default_format = WorkingTreeFormat6()
3134
WorkingTreeFormat.register_format(__default_format)
3135
WorkingTreeFormat.register_format(WorkingTreeFormat5())
3136
WorkingTreeFormat.register_format(WorkingTreeFormat4())
3137
WorkingTreeFormat.register_format(WorkingTreeFormat3())
3138
WorkingTreeFormat.set_default_format(__default_format)
3139
# formats which have no format string are not discoverable
3140
# and not independently creatable, so are not registered.
3141
_legacy_formats = [WorkingTreeFormat2(),
3117
format_registry.remove(format)
3120
format_registry.register_lazy("Bazaar Working Tree Format 4 (bzr 0.15)\n",
3121
"bzrlib.workingtree_4", "WorkingTreeFormat4")
3122
format_registry.register_lazy("Bazaar Working Tree Format 5 (bzr 1.11)\n",
3123
"bzrlib.workingtree_4", "WorkingTreeFormat5")
3124
format_registry.register_lazy("Bazaar Working Tree Format 6 (bzr 1.14)\n",
3125
"bzrlib.workingtree_4", "WorkingTreeFormat6")
3126
format_registry.register_lazy("Bazaar-NG Working Tree format 3",
3127
"bzrlib.workingtree_3", "WorkingTreeFormat3")
3128
format_registry.set_default_key("Bazaar Working Tree Format 6 (bzr 1.14)\n")