2608
1753
return ShelfManager(self, self._transport)
2611
class WorkingTree2(WorkingTree):
2612
"""This is the Format 2 working tree.
2614
This was the first weave based working tree.
2615
- uses os locks for locking.
2616
- uses the branch last-revision.
1756
class InventoryWorkingTree(WorkingTree,
1757
bzrlib.mutabletree.MutableInventoryTree):
1758
"""Base class for working trees that are inventory-oriented.
1760
The inventory is held in the `Branch` working-inventory, and the
1761
files are in a directory on disk.
1763
It is possible for a `WorkingTree` to have a filename which is
1764
not listed in the Inventory and vice versa.
2619
def __init__(self, *args, **kwargs):
2620
super(WorkingTree2, self).__init__(*args, **kwargs)
2621
# WorkingTree2 has more of a constraint that self._inventory must
2622
# exist. Because this is an older format, we don't mind the overhead
2623
# caused by the extra computation here.
2625
# Newer WorkingTree's should only have self._inventory set when they
2627
if self._inventory is None:
2628
self.read_working_inventory()
2630
def _get_check_refs(self):
2631
"""Return the references needed to perform a check of this tree."""
2632
return [('trees', self.last_revision())]
2634
def lock_tree_write(self):
2635
"""See WorkingTree.lock_tree_write().
2637
In Format2 WorkingTrees we have a single lock for the branch and tree
2638
so lock_tree_write() degrades to lock_write().
2640
self.branch.lock_write()
2642
return self._control_files.lock_write()
2644
self.branch.unlock()
2648
# do non-implementation specific cleanup
2651
# we share control files:
2652
if self._control_files._lock_count == 3:
2653
# _inventory_is_modified is always False during a read lock.
2654
if self._inventory_is_modified:
2656
self._write_hashcache_if_dirty()
2658
# reverse order of locking.
2660
return self._control_files.unlock()
1767
def __init__(self, basedir='.',
1768
branch=DEPRECATED_PARAMETER,
1770
_control_files=None,
1774
"""Construct a InventoryWorkingTree instance. This is not a public API.
1776
:param branch: A branch to override probing for the branch.
1778
super(InventoryWorkingTree, self).__init__(basedir=basedir,
1779
branch=branch, _control_files=_control_files, _internal=_internal,
1780
_format=_format, _bzrdir=_bzrdir)
1782
self._detect_case_handling()
1784
if _inventory is None:
1785
# This will be acquired on lock_read() or lock_write()
1786
self._inventory_is_modified = False
1787
self._inventory = None
1789
# the caller of __init__ has provided an inventory,
1790
# we assume they know what they are doing - as its only
1791
# the Format factory and creation methods that are
1792
# permitted to do this.
1793
self._set_inventory(_inventory, dirty=False)
1795
def _set_inventory(self, inv, dirty):
1796
"""Set the internal cached inventory.
1798
:param inv: The inventory to set.
1799
:param dirty: A boolean indicating whether the inventory is the same
1800
logical inventory as whats on disk. If True the inventory is not
1801
the same and should be written to disk or data will be lost, if
1802
False then the inventory is the same as that on disk and any
1803
serialisation would be unneeded overhead.
1805
self._inventory = inv
1806
self._inventory_is_modified = dirty
1808
def _detect_case_handling(self):
1809
wt_trans = self.bzrdir.get_workingtree_transport(None)
1811
wt_trans.stat(self._format.case_sensitive_filename)
1812
except errors.NoSuchFile:
1813
self.case_sensitive = True
1815
self.case_sensitive = False
1817
self._setup_directory_is_tree_reference()
1819
def _serialize(self, inventory, out_file):
1820
xml5.serializer_v5.write_inventory(self._inventory, out_file,
1823
def _deserialize(selt, in_file):
1824
return xml5.serializer_v5.read_inventory(in_file)
1826
@needs_tree_write_lock
1827
def _write_inventory(self, inv):
1828
"""Write inventory as the current inventory."""
1829
self._set_inventory(inv, dirty=True)
1832
# XXX: This method should be deprecated in favour of taking in a proper
1833
# new Inventory object.
1834
@needs_tree_write_lock
1835
def set_inventory(self, new_inventory_list):
1836
from bzrlib.inventory import (Inventory,
1840
inv = Inventory(self.get_root_id())
1841
for path, file_id, parent, kind in new_inventory_list:
1842
name = os.path.basename(path)
1845
# fixme, there should be a factory function inv,add_??
1846
if kind == 'directory':
1847
inv.add(InventoryDirectory(file_id, name, parent))
1848
elif kind == 'file':
1849
inv.add(InventoryFile(file_id, name, parent))
1850
elif kind == 'symlink':
1851
inv.add(InventoryLink(file_id, name, parent))
1853
raise errors.BzrError("unknown kind %r" % kind)
1854
self._write_inventory(inv)
1856
def _write_basis_inventory(self, xml):
1857
"""Write the basis inventory XML to the basis-inventory file"""
1858
path = self._basis_inventory_name()
1860
self._transport.put_file(path, sio,
1861
mode=self.bzrdir._get_file_mode())
1863
def _reset_data(self):
1864
"""Reset transient data that cannot be revalidated."""
1865
self._inventory_is_modified = False
1866
f = self._transport.get('inventory')
1868
result = self._deserialize(f)
2662
self.branch.unlock()
2665
class WorkingTree3(WorkingTree):
2666
"""This is the Format 3 working tree.
2668
This differs from the base WorkingTree by:
2669
- having its own file lock
2670
- having its own last-revision property.
2672
This is new in bzr 0.8
2676
def _last_revision(self):
2677
"""See Mutable.last_revision."""
1871
self._set_inventory(result, dirty=False)
1873
def _set_root_id(self, file_id):
1874
"""Set the root id for this tree, in a format specific manner.
1876
:param file_id: The file id to assign to the root. It must not be
1877
present in the current inventory or an error will occur. It must
1878
not be None, but rather a valid file id.
1880
inv = self._inventory
1881
orig_root_id = inv.root.file_id
1882
# TODO: it might be nice to exit early if there was nothing
1883
# to do, saving us from trigger a sync on unlock.
1884
self._inventory_is_modified = True
1885
# we preserve the root inventory entry object, but
1886
# unlinkit from the byid index
1887
del inv._byid[inv.root.file_id]
1888
inv.root.file_id = file_id
1889
# and link it into the index with the new changed id.
1890
inv._byid[inv.root.file_id] = inv.root
1891
# and finally update all children to reference the new id.
1892
# XXX: this should be safe to just look at the root.children
1893
# list, not the WHOLE INVENTORY.
1896
if entry.parent_id == orig_root_id:
1897
entry.parent_id = inv.root.file_id
1899
def all_file_ids(self):
1900
"""See Tree.iter_all_file_ids"""
1901
return set(self.inventory)
1903
@needs_tree_write_lock
1904
def set_parent_trees(self, parents_list, allow_leftmost_as_ghost=False):
1905
"""See MutableTree.set_parent_trees."""
1906
parent_ids = [rev for (rev, tree) in parents_list]
1907
for revision_id in parent_ids:
1908
_mod_revision.check_not_reserved_id(revision_id)
1910
self._check_parents_for_ghosts(parent_ids,
1911
allow_leftmost_as_ghost=allow_leftmost_as_ghost)
1913
parent_ids = self._filter_parent_ids_by_ancestry(parent_ids)
1915
if len(parent_ids) == 0:
1916
leftmost_parent_id = _mod_revision.NULL_REVISION
1917
leftmost_parent_tree = None
1919
leftmost_parent_id, leftmost_parent_tree = parents_list[0]
1921
if self._change_last_revision(leftmost_parent_id):
1922
if leftmost_parent_tree is None:
1923
# If we don't have a tree, fall back to reading the
1924
# parent tree from the repository.
1925
self._cache_basis_inventory(leftmost_parent_id)
1927
inv = leftmost_parent_tree.inventory
1928
xml = self._create_basis_xml_from_inventory(
1929
leftmost_parent_id, inv)
1930
self._write_basis_inventory(xml)
1931
self._set_merges_from_parent_ids(parent_ids)
1933
def _cache_basis_inventory(self, new_revision):
1934
"""Cache new_revision as the basis inventory."""
1935
# TODO: this should allow the ready-to-use inventory to be passed in,
1936
# as commit already has that ready-to-use [while the format is the
2679
return self._transport.get_bytes('last-revision')
2680
except errors.NoSuchFile:
2681
return _mod_revision.NULL_REVISION
2683
def _change_last_revision(self, revision_id):
2684
"""See WorkingTree._change_last_revision."""
2685
if revision_id is None or revision_id == _mod_revision.NULL_REVISION:
2687
self._transport.delete('last-revision')
2688
except errors.NoSuchFile:
2692
self._transport.put_bytes('last-revision', revision_id,
2693
mode=self.bzrdir._get_file_mode())
2696
def _get_check_refs(self):
2697
"""Return the references needed to perform a check of this tree."""
2698
return [('trees', self.last_revision())]
1939
# this double handles the inventory - unpack and repack -
1940
# but is easier to understand. We can/should put a conditional
1941
# in here based on whether the inventory is in the latest format
1942
# - perhaps we should repack all inventories on a repository
1944
# the fast path is to copy the raw xml from the repository. If the
1945
# xml contains 'revision_id="', then we assume the right
1946
# revision_id is set. We must check for this full string, because a
1947
# root node id can legitimately look like 'revision_id' but cannot
1949
xml = self.branch.repository._get_inventory_xml(new_revision)
1950
firstline = xml.split('\n', 1)[0]
1951
if (not 'revision_id="' in firstline or
1952
'format="7"' not in firstline):
1953
inv = self.branch.repository._serializer.read_inventory_from_string(
1955
xml = self._create_basis_xml_from_inventory(new_revision, inv)
1956
self._write_basis_inventory(xml)
1957
except (errors.NoSuchRevision, errors.RevisionNotPresent):
1960
def _basis_inventory_name(self):
1961
return 'basis-inventory-cache'
1963
def _create_basis_xml_from_inventory(self, revision_id, inventory):
1964
"""Create the text that will be saved in basis-inventory"""
1965
inventory.revision_id = revision_id
1966
return xml7.serializer_v7.write_inventory_to_string(inventory)
2700
1968
@needs_tree_write_lock
2701
1969
def set_conflicts(self, conflicts):
2721
1989
raise errors.ConflictFormatError()
2722
1990
except StopIteration:
2723
1991
raise errors.ConflictFormatError()
2724
return _mod_conflicts.ConflictList.from_stanzas(RioReader(confile))
1992
reader = _mod_rio.RioReader(confile)
1993
return _mod_conflicts.ConflictList.from_stanzas(reader)
2726
1995
confile.close()
2729
# do non-implementation specific cleanup
2731
if self._control_files._lock_count == 1:
2732
# _inventory_is_modified is always False during a read lock.
2733
if self._inventory_is_modified:
2735
self._write_hashcache_if_dirty()
2736
# reverse order of locking.
2738
return self._control_files.unlock()
2740
self.branch.unlock()
2743
def get_conflicted_stem(path):
2744
for suffix in _mod_conflicts.CONFLICT_SUFFIXES:
2745
if path.endswith(suffix):
2746
return path[:-len(suffix)]
2749
class WorkingTreeFormat(object):
1997
def read_basis_inventory(self):
1998
"""Read the cached basis inventory."""
1999
path = self._basis_inventory_name()
2000
return self._transport.get_bytes(path)
2003
def read_working_inventory(self):
2004
"""Read the working inventory.
2006
:raises errors.InventoryModified: read_working_inventory will fail
2007
when the current in memory inventory has been modified.
2009
# conceptually this should be an implementation detail of the tree.
2010
# XXX: Deprecate this.
2011
# ElementTree does its own conversion from UTF-8, so open in
2013
if self._inventory_is_modified:
2014
raise errors.InventoryModified(self)
2015
f = self._transport.get('inventory')
2017
result = self._deserialize(f)
2020
self._set_inventory(result, dirty=False)
2024
def get_root_id(self):
2025
"""Return the id of this trees root"""
2026
return self._inventory.root.file_id
2028
def has_id(self, file_id):
2029
# files that have been deleted are excluded
2030
inv = self.inventory
2031
if not inv.has_id(file_id):
2033
path = inv.id2path(file_id)
2034
return osutils.lexists(self.abspath(path))
2036
def has_or_had_id(self, file_id):
2037
if file_id == self.inventory.root.file_id:
2039
return self.inventory.has_id(file_id)
2041
@symbol_versioning.deprecated_method(symbol_versioning.deprecated_in((2, 4, 0)))
2043
"""Iterate through file_ids for this tree.
2045
file_ids are in a WorkingTree if they are in the working inventory
2046
and the working file exists.
2048
inv = self._inventory
2049
for path, ie in inv.iter_entries():
2050
if osutils.lexists(self.abspath(path)):
2053
@needs_tree_write_lock
2054
def set_last_revision(self, new_revision):
2055
"""Change the last revision in the working tree."""
2056
if self._change_last_revision(new_revision):
2057
self._cache_basis_inventory(new_revision)
2059
def _get_check_refs(self):
2060
"""Return the references needed to perform a check of this tree.
2062
The default implementation returns no refs, and is only suitable for
2063
trees that have no local caching and can commit on ghosts at any time.
2065
:seealso: bzrlib.check for details about check_refs.
2070
def _check(self, references):
2071
"""Check the tree for consistency.
2073
:param references: A dict with keys matching the items returned by
2074
self._get_check_refs(), and values from looking those keys up in
2077
tree_basis = self.basis_tree()
2078
tree_basis.lock_read()
2080
repo_basis = references[('trees', self.last_revision())]
2081
if len(list(repo_basis.iter_changes(tree_basis))) > 0:
2082
raise errors.BzrCheckError(
2083
"Mismatched basis inventory content.")
2089
def check_state(self):
2090
"""Check that the working state is/isn't valid."""
2091
check_refs = self._get_check_refs()
2093
for ref in check_refs:
2096
refs[ref] = self.branch.repository.revision_tree(value)
2099
@needs_tree_write_lock
2100
def reset_state(self, revision_ids=None):
2101
"""Reset the state of the working tree.
2103
This does a hard-reset to a last-known-good state. This is a way to
2104
fix if something got corrupted (like the .bzr/checkout/dirstate file)
2106
if revision_ids is None:
2107
revision_ids = self.get_parent_ids()
2108
if not revision_ids:
2109
rt = self.branch.repository.revision_tree(
2110
_mod_revision.NULL_REVISION)
2112
rt = self.branch.repository.revision_tree(revision_ids[0])
2113
self._write_inventory(rt.inventory)
2114
self.set_parent_ids(revision_ids)
2117
"""Write the in memory inventory to disk."""
2118
# TODO: Maybe this should only write on dirty ?
2119
if self._control_files._lock_mode != 'w':
2120
raise errors.NotWriteLocked(self)
2122
self._serialize(self._inventory, sio)
2124
self._transport.put_file('inventory', sio,
2125
mode=self.bzrdir._get_file_mode())
2126
self._inventory_is_modified = False
2128
def get_file_mtime(self, file_id, path=None):
2129
"""See Tree.get_file_mtime."""
2131
path = self.inventory.id2path(file_id)
2132
return os.lstat(self.abspath(path)).st_mtime
2134
def _is_executable_from_path_and_stat_from_basis(self, path, stat_result):
2135
file_id = self.path2id(path)
2137
# For unversioned files on win32, we just assume they are not
2140
return self._inventory[file_id].executable
2142
def _is_executable_from_path_and_stat_from_stat(self, path, stat_result):
2143
mode = stat_result.st_mode
2144
return bool(stat.S_ISREG(mode) and stat.S_IEXEC & mode)
2146
if not supports_executable():
2147
def is_executable(self, file_id, path=None):
2148
return self._inventory[file_id].executable
2150
_is_executable_from_path_and_stat = \
2151
_is_executable_from_path_and_stat_from_basis
2153
def is_executable(self, file_id, path=None):
2155
path = self.id2path(file_id)
2156
mode = os.lstat(self.abspath(path)).st_mode
2157
return bool(stat.S_ISREG(mode) and stat.S_IEXEC & mode)
2159
_is_executable_from_path_and_stat = \
2160
_is_executable_from_path_and_stat_from_stat
2162
@needs_tree_write_lock
2163
def _add(self, files, ids, kinds):
2164
"""See MutableTree._add."""
2165
# TODO: Re-adding a file that is removed in the working copy
2166
# should probably put it back with the previous ID.
2167
# the read and write working inventory should not occur in this
2168
# function - they should be part of lock_write and unlock.
2169
inv = self.inventory
2170
for f, file_id, kind in zip(files, ids, kinds):
2172
inv.add_path(f, kind=kind)
2174
inv.add_path(f, kind=kind, file_id=file_id)
2175
self._inventory_is_modified = True
2177
def revision_tree(self, revision_id):
2178
"""See WorkingTree.revision_id."""
2179
if revision_id == self.last_revision():
2181
xml = self.read_basis_inventory()
2182
except errors.NoSuchFile:
2186
inv = xml7.serializer_v7.read_inventory_from_string(xml)
2187
# dont use the repository revision_tree api because we want
2188
# to supply the inventory.
2189
if inv.revision_id == revision_id:
2190
return revisiontree.InventoryRevisionTree(
2191
self.branch.repository, inv, revision_id)
2192
except errors.BadInventoryFormat:
2194
# raise if there was no inventory, or if we read the wrong inventory.
2195
raise errors.NoSuchRevisionInTree(self, revision_id)
2198
def annotate_iter(self, file_id, default_revision=CURRENT_REVISION):
2199
"""See Tree.annotate_iter
2201
This implementation will use the basis tree implementation if possible.
2202
Lines not in the basis are attributed to CURRENT_REVISION
2204
If there are pending merges, lines added by those merges will be
2205
incorrectly attributed to CURRENT_REVISION (but after committing, the
2206
attribution will be correct).
2208
maybe_file_parent_keys = []
2209
for parent_id in self.get_parent_ids():
2211
parent_tree = self.revision_tree(parent_id)
2212
except errors.NoSuchRevisionInTree:
2213
parent_tree = self.branch.repository.revision_tree(parent_id)
2214
parent_tree.lock_read()
2216
if not parent_tree.has_id(file_id):
2218
ie = parent_tree.inventory[file_id]
2219
if ie.kind != 'file':
2220
# Note: this is slightly unnecessary, because symlinks and
2221
# directories have a "text" which is the empty text, and we
2222
# know that won't mess up annotations. But it seems cleaner
2224
parent_text_key = (file_id, ie.revision)
2225
if parent_text_key not in maybe_file_parent_keys:
2226
maybe_file_parent_keys.append(parent_text_key)
2228
parent_tree.unlock()
2229
graph = _mod_graph.Graph(self.branch.repository.texts)
2230
heads = graph.heads(maybe_file_parent_keys)
2231
file_parent_keys = []
2232
for key in maybe_file_parent_keys:
2234
file_parent_keys.append(key)
2236
# Now we have the parents of this content
2237
annotator = self.branch.repository.texts.get_annotator()
2238
text = self.get_file_text(file_id)
2239
this_key =(file_id, default_revision)
2240
annotator.add_special_text(this_key, file_parent_keys, text)
2241
annotations = [(key[-1], line)
2242
for key, line in annotator.annotate_flat(this_key)]
2246
def merge_modified(self):
2247
"""Return a dictionary of files modified by a merge.
2249
The list is initialized by WorkingTree.set_merge_modified, which is
2250
typically called after we make some automatic updates to the tree
2253
This returns a map of file_id->sha1, containing only files which are
2254
still in the working inventory and have that text hash.
2257
hashfile = self._transport.get('merge-hashes')
2258
except errors.NoSuchFile:
2263
if hashfile.next() != MERGE_MODIFIED_HEADER_1 + '\n':
2264
raise errors.MergeModifiedFormatError()
2265
except StopIteration:
2266
raise errors.MergeModifiedFormatError()
2267
for s in _mod_rio.RioReader(hashfile):
2268
# RioReader reads in Unicode, so convert file_ids back to utf8
2269
file_id = osutils.safe_file_id(s.get("file_id"), warn=False)
2270
if not self.inventory.has_id(file_id):
2272
text_hash = s.get("hash")
2273
if text_hash == self.get_file_sha1(file_id):
2274
merge_hashes[file_id] = text_hash
2280
def subsume(self, other_tree):
2281
def add_children(inventory, entry):
2282
for child_entry in entry.children.values():
2283
inventory._byid[child_entry.file_id] = child_entry
2284
if child_entry.kind == 'directory':
2285
add_children(inventory, child_entry)
2286
if other_tree.get_root_id() == self.get_root_id():
2287
raise errors.BadSubsumeSource(self, other_tree,
2288
'Trees have the same root')
2290
other_tree_path = self.relpath(other_tree.basedir)
2291
except errors.PathNotChild:
2292
raise errors.BadSubsumeSource(self, other_tree,
2293
'Tree is not contained by the other')
2294
new_root_parent = self.path2id(osutils.dirname(other_tree_path))
2295
if new_root_parent is None:
2296
raise errors.BadSubsumeSource(self, other_tree,
2297
'Parent directory is not versioned.')
2298
# We need to ensure that the result of a fetch will have a
2299
# versionedfile for the other_tree root, and only fetching into
2300
# RepositoryKnit2 guarantees that.
2301
if not self.branch.repository.supports_rich_root():
2302
raise errors.SubsumeTargetNeedsUpgrade(other_tree)
2303
other_tree.lock_tree_write()
2305
new_parents = other_tree.get_parent_ids()
2306
other_root = other_tree.inventory.root
2307
other_root.parent_id = new_root_parent
2308
other_root.name = osutils.basename(other_tree_path)
2309
self.inventory.add(other_root)
2310
add_children(self.inventory, other_root)
2311
self._write_inventory(self.inventory)
2312
# normally we don't want to fetch whole repositories, but i think
2313
# here we really do want to consolidate the whole thing.
2314
for parent_id in other_tree.get_parent_ids():
2315
self.branch.fetch(other_tree.branch, parent_id)
2316
self.add_parent_tree_id(parent_id)
2319
other_tree.bzrdir.retire_bzrdir()
2321
@needs_tree_write_lock
2322
def extract(self, file_id, format=None):
2323
"""Extract a subtree from this tree.
2325
A new branch will be created, relative to the path for this tree.
2329
segments = osutils.splitpath(path)
2330
transport = self.branch.bzrdir.root_transport
2331
for name in segments:
2332
transport = transport.clone(name)
2333
transport.ensure_base()
2336
sub_path = self.id2path(file_id)
2337
branch_transport = mkdirs(sub_path)
2339
format = self.bzrdir.cloning_metadir()
2340
branch_transport.ensure_base()
2341
branch_bzrdir = format.initialize_on_transport(branch_transport)
2343
repo = branch_bzrdir.find_repository()
2344
except errors.NoRepositoryPresent:
2345
repo = branch_bzrdir.create_repository()
2346
if not repo.supports_rich_root():
2347
raise errors.RootNotRich()
2348
new_branch = branch_bzrdir.create_branch()
2349
new_branch.pull(self.branch)
2350
for parent_id in self.get_parent_ids():
2351
new_branch.fetch(self.branch, parent_id)
2352
tree_transport = self.bzrdir.root_transport.clone(sub_path)
2353
if tree_transport.base != branch_transport.base:
2354
tree_bzrdir = format.initialize_on_transport(tree_transport)
2355
branch.BranchReferenceFormat().initialize(tree_bzrdir,
2356
target_branch=new_branch)
2358
tree_bzrdir = branch_bzrdir
2359
wt = tree_bzrdir.create_workingtree(_mod_revision.NULL_REVISION)
2360
wt.set_parent_ids(self.get_parent_ids())
2361
my_inv = self.inventory
2362
child_inv = inventory.Inventory(root_id=None)
2363
new_root = my_inv[file_id]
2364
my_inv.remove_recursive_id(file_id)
2365
new_root.parent_id = None
2366
child_inv.add(new_root)
2367
self._write_inventory(my_inv)
2368
wt._write_inventory(child_inv)
2371
def list_files(self, include_root=False, from_dir=None, recursive=True):
2372
"""List all files as (path, class, kind, id, entry).
2374
Lists, but does not descend into unversioned directories.
2375
This does not include files that have been deleted in this
2376
tree. Skips the control directory.
2378
:param include_root: if True, return an entry for the root
2379
:param from_dir: start from this directory or None for the root
2380
:param recursive: whether to recurse into subdirectories or not
2382
# list_files is an iterator, so @needs_read_lock doesn't work properly
2383
# with it. So callers should be careful to always read_lock the tree.
2384
if not self.is_locked():
2385
raise errors.ObjectNotLocked(self)
2387
inv = self.inventory
2388
if from_dir is None and include_root is True:
2389
yield ('', 'V', 'directory', inv.root.file_id, inv.root)
2390
# Convert these into local objects to save lookup times
2391
pathjoin = osutils.pathjoin
2392
file_kind = self._kind
2394
# transport.base ends in a slash, we want the piece
2395
# between the last two slashes
2396
transport_base_dir = self.bzrdir.transport.base.rsplit('/', 2)[1]
2398
fk_entries = {'directory':TreeDirectory, 'file':TreeFile, 'symlink':TreeLink}
2400
# directory file_id, relative path, absolute path, reverse sorted children
2401
if from_dir is not None:
2402
from_dir_id = inv.path2id(from_dir)
2403
if from_dir_id is None:
2404
# Directory not versioned
2406
from_dir_abspath = pathjoin(self.basedir, from_dir)
2408
from_dir_id = inv.root.file_id
2409
from_dir_abspath = self.basedir
2410
children = os.listdir(from_dir_abspath)
2412
# jam 20060527 The kernel sized tree seems equivalent whether we
2413
# use a deque and popleft to keep them sorted, or if we use a plain
2414
# list and just reverse() them.
2415
children = collections.deque(children)
2416
stack = [(from_dir_id, u'', from_dir_abspath, children)]
2418
from_dir_id, from_dir_relpath, from_dir_abspath, children = stack[-1]
2421
f = children.popleft()
2422
## TODO: If we find a subdirectory with its own .bzr
2423
## directory, then that is a separate tree and we
2424
## should exclude it.
2426
# the bzrdir for this tree
2427
if transport_base_dir == f:
2430
# we know that from_dir_relpath and from_dir_abspath never end in a slash
2431
# and 'f' doesn't begin with one, we can do a string op, rather
2432
# than the checks of pathjoin(), all relative paths will have an extra slash
2434
fp = from_dir_relpath + '/' + f
2437
fap = from_dir_abspath + '/' + f
2439
dir_ie = inv[from_dir_id]
2440
if dir_ie.kind == 'directory':
2441
f_ie = dir_ie.children.get(f)
2446
elif self.is_ignored(fp[1:]):
2449
# we may not have found this file, because of a unicode
2450
# issue, or because the directory was actually a symlink.
2451
f_norm, can_access = osutils.normalized_filename(f)
2452
if f == f_norm or not can_access:
2453
# No change, so treat this file normally
2456
# this file can be accessed by a normalized path
2457
# check again if it is versioned
2458
# these lines are repeated here for performance
2460
fp = from_dir_relpath + '/' + f
2461
fap = from_dir_abspath + '/' + f
2462
f_ie = inv.get_child(from_dir_id, f)
2465
elif self.is_ignored(fp[1:]):
2472
# make a last minute entry
2474
yield fp[1:], c, fk, f_ie.file_id, f_ie
2477
yield fp[1:], c, fk, None, fk_entries[fk]()
2479
yield fp[1:], c, fk, None, TreeEntry()
2482
if fk != 'directory':
2485
# But do this child first if recursing down
2487
new_children = os.listdir(fap)
2489
new_children = collections.deque(new_children)
2490
stack.append((f_ie.file_id, fp, fap, new_children))
2491
# Break out of inner loop,
2492
# so that we start outer loop with child
2495
# if we finished all children, pop it off the stack
2498
@needs_tree_write_lock
2499
def move(self, from_paths, to_dir=None, after=False):
2502
to_dir must exist in the inventory.
2504
If to_dir exists and is a directory, the files are moved into
2505
it, keeping their old names.
2507
Note that to_dir is only the last component of the new name;
2508
this doesn't change the directory.
2510
For each entry in from_paths the move mode will be determined
2513
The first mode moves the file in the filesystem and updates the
2514
inventory. The second mode only updates the inventory without
2515
touching the file on the filesystem.
2517
move uses the second mode if 'after == True' and the target is
2518
either not versioned or newly added, and present in the working tree.
2520
move uses the second mode if 'after == False' and the source is
2521
versioned but no longer in the working tree, and the target is not
2522
versioned but present in the working tree.
2524
move uses the first mode if 'after == False' and the source is
2525
versioned and present in the working tree, and the target is not
2526
versioned and not present in the working tree.
2528
Everything else results in an error.
2530
This returns a list of (from_path, to_path) pairs for each
2531
entry that is moved.
2536
# check for deprecated use of signature
2538
raise TypeError('You must supply a target directory')
2539
# check destination directory
2540
if isinstance(from_paths, basestring):
2542
inv = self.inventory
2543
to_abs = self.abspath(to_dir)
2544
if not isdir(to_abs):
2545
raise errors.BzrMoveFailedError('',to_dir,
2546
errors.NotADirectory(to_abs))
2547
if not self.has_filename(to_dir):
2548
raise errors.BzrMoveFailedError('',to_dir,
2549
errors.NotInWorkingDirectory(to_dir))
2550
to_dir_id = inv.path2id(to_dir)
2551
if to_dir_id is None:
2552
raise errors.BzrMoveFailedError('',to_dir,
2553
errors.NotVersionedError(path=to_dir))
2555
to_dir_ie = inv[to_dir_id]
2556
if to_dir_ie.kind != 'directory':
2557
raise errors.BzrMoveFailedError('',to_dir,
2558
errors.NotADirectory(to_abs))
2560
# create rename entries and tuples
2561
for from_rel in from_paths:
2562
from_tail = splitpath(from_rel)[-1]
2563
from_id = inv.path2id(from_rel)
2565
raise errors.BzrMoveFailedError(from_rel,to_dir,
2566
errors.NotVersionedError(path=from_rel))
2568
from_entry = inv[from_id]
2569
from_parent_id = from_entry.parent_id
2570
to_rel = pathjoin(to_dir, from_tail)
2571
rename_entry = InventoryWorkingTree._RenameEntry(
2574
from_tail=from_tail,
2575
from_parent_id=from_parent_id,
2576
to_rel=to_rel, to_tail=from_tail,
2577
to_parent_id=to_dir_id)
2578
rename_entries.append(rename_entry)
2579
rename_tuples.append((from_rel, to_rel))
2581
# determine which move mode to use. checks also for movability
2582
rename_entries = self._determine_mv_mode(rename_entries, after)
2584
original_modified = self._inventory_is_modified
2587
self._inventory_is_modified = True
2588
self._move(rename_entries)
2590
# restore the inventory on error
2591
self._inventory_is_modified = original_modified
2593
self._write_inventory(inv)
2594
return rename_tuples
2596
@needs_tree_write_lock
2597
def rename_one(self, from_rel, to_rel, after=False):
2600
This can change the directory or the filename or both.
2602
rename_one has several 'modes' to work. First, it can rename a physical
2603
file and change the file_id. That is the normal mode. Second, it can
2604
only change the file_id without touching any physical file.
2606
rename_one uses the second mode if 'after == True' and 'to_rel' is not
2607
versioned but present in the working tree.
2609
rename_one uses the second mode if 'after == False' and 'from_rel' is
2610
versioned but no longer in the working tree, and 'to_rel' is not
2611
versioned but present in the working tree.
2613
rename_one uses the first mode if 'after == False' and 'from_rel' is
2614
versioned and present in the working tree, and 'to_rel' is not
2615
versioned and not present in the working tree.
2617
Everything else results in an error.
2619
inv = self.inventory
2622
# create rename entries and tuples
2623
from_tail = splitpath(from_rel)[-1]
2624
from_id = inv.path2id(from_rel)
2626
# if file is missing in the inventory maybe it's in the basis_tree
2627
basis_tree = self.branch.basis_tree()
2628
from_id = basis_tree.path2id(from_rel)
2630
raise errors.BzrRenameFailedError(from_rel,to_rel,
2631
errors.NotVersionedError(path=from_rel))
2632
# put entry back in the inventory so we can rename it
2633
from_entry = basis_tree.inventory[from_id].copy()
2636
from_entry = inv[from_id]
2637
from_parent_id = from_entry.parent_id
2638
to_dir, to_tail = os.path.split(to_rel)
2639
to_dir_id = inv.path2id(to_dir)
2640
rename_entry = InventoryWorkingTree._RenameEntry(from_rel=from_rel,
2642
from_tail=from_tail,
2643
from_parent_id=from_parent_id,
2644
to_rel=to_rel, to_tail=to_tail,
2645
to_parent_id=to_dir_id)
2646
rename_entries.append(rename_entry)
2648
# determine which move mode to use. checks also for movability
2649
rename_entries = self._determine_mv_mode(rename_entries, after)
2651
# check if the target changed directory and if the target directory is
2653
if to_dir_id is None:
2654
raise errors.BzrMoveFailedError(from_rel,to_rel,
2655
errors.NotVersionedError(path=to_dir))
2657
# all checks done. now we can continue with our actual work
2658
mutter('rename_one:\n'
2663
' to_dir_id {%s}\n',
2664
from_id, from_rel, to_rel, to_dir, to_dir_id)
2666
self._move(rename_entries)
2667
self._write_inventory(inv)
2669
class _RenameEntry(object):
2670
def __init__(self, from_rel, from_id, from_tail, from_parent_id,
2671
to_rel, to_tail, to_parent_id, only_change_inv=False,
2673
self.from_rel = from_rel
2674
self.from_id = from_id
2675
self.from_tail = from_tail
2676
self.from_parent_id = from_parent_id
2677
self.to_rel = to_rel
2678
self.to_tail = to_tail
2679
self.to_parent_id = to_parent_id
2680
self.change_id = change_id
2681
self.only_change_inv = only_change_inv
2683
def _determine_mv_mode(self, rename_entries, after=False):
2684
"""Determines for each from-to pair if both inventory and working tree
2685
or only the inventory has to be changed.
2687
Also does basic plausability tests.
2689
inv = self.inventory
2691
for rename_entry in rename_entries:
2692
# store to local variables for easier reference
2693
from_rel = rename_entry.from_rel
2694
from_id = rename_entry.from_id
2695
to_rel = rename_entry.to_rel
2696
to_id = inv.path2id(to_rel)
2697
only_change_inv = False
2700
# check the inventory for source and destination
2702
raise errors.BzrMoveFailedError(from_rel,to_rel,
2703
errors.NotVersionedError(path=from_rel))
2704
if to_id is not None:
2706
# allow it with --after but only if dest is newly added
2708
basis = self.basis_tree()
2711
if not basis.has_id(to_id):
2712
rename_entry.change_id = True
2717
raise errors.BzrMoveFailedError(from_rel,to_rel,
2718
errors.AlreadyVersionedError(path=to_rel))
2720
# try to determine the mode for rename (only change inv or change
2721
# inv and file system)
2723
if not self.has_filename(to_rel):
2724
raise errors.BzrMoveFailedError(from_id,to_rel,
2725
errors.NoSuchFile(path=to_rel,
2726
extra="New file has not been created yet"))
2727
only_change_inv = True
2728
elif not self.has_filename(from_rel) and self.has_filename(to_rel):
2729
only_change_inv = True
2730
elif self.has_filename(from_rel) and not self.has_filename(to_rel):
2731
only_change_inv = False
2732
elif (not self.case_sensitive
2733
and from_rel.lower() == to_rel.lower()
2734
and self.has_filename(from_rel)):
2735
only_change_inv = False
2737
# something is wrong, so lets determine what exactly
2738
if not self.has_filename(from_rel) and \
2739
not self.has_filename(to_rel):
2740
raise errors.BzrRenameFailedError(from_rel,to_rel,
2741
errors.PathsDoNotExist(paths=(str(from_rel),
2744
raise errors.RenameFailedFilesExist(from_rel, to_rel)
2745
rename_entry.only_change_inv = only_change_inv
2746
return rename_entries
2748
def _move(self, rename_entries):
2749
"""Moves a list of files.
2751
Depending on the value of the flag 'only_change_inv', the
2752
file will be moved on the file system or not.
2754
inv = self.inventory
2757
for entry in rename_entries:
2759
self._move_entry(entry)
2761
self._rollback_move(moved)
2765
def _rollback_move(self, moved):
2766
"""Try to rollback a previous move in case of an filesystem error."""
2767
inv = self.inventory
2770
self._move_entry(WorkingTree._RenameEntry(
2771
entry.to_rel, entry.from_id,
2772
entry.to_tail, entry.to_parent_id, entry.from_rel,
2773
entry.from_tail, entry.from_parent_id,
2774
entry.only_change_inv))
2775
except errors.BzrMoveFailedError, e:
2776
raise errors.BzrMoveFailedError( '', '', "Rollback failed."
2777
" The working tree is in an inconsistent state."
2778
" Please consider doing a 'bzr revert'."
2779
" Error message is: %s" % e)
2781
def _move_entry(self, entry):
2782
inv = self.inventory
2783
from_rel_abs = self.abspath(entry.from_rel)
2784
to_rel_abs = self.abspath(entry.to_rel)
2785
if from_rel_abs == to_rel_abs:
2786
raise errors.BzrMoveFailedError(entry.from_rel, entry.to_rel,
2787
"Source and target are identical.")
2789
if not entry.only_change_inv:
2791
osutils.rename(from_rel_abs, to_rel_abs)
2793
raise errors.BzrMoveFailedError(entry.from_rel,
2796
to_id = inv.path2id(entry.to_rel)
2797
inv.remove_recursive_id(to_id)
2798
inv.rename(entry.from_id, entry.to_parent_id, entry.to_tail)
2800
@needs_tree_write_lock
2801
def unversion(self, file_ids):
2802
"""Remove the file ids in file_ids from the current versioned set.
2804
When a file_id is unversioned, all of its children are automatically
2807
:param file_ids: The file ids to stop versioning.
2808
:raises: NoSuchId if any fileid is not currently versioned.
2810
for file_id in file_ids:
2811
if not self._inventory.has_id(file_id):
2812
raise errors.NoSuchId(self, file_id)
2813
for file_id in file_ids:
2814
if self._inventory.has_id(file_id):
2815
self._inventory.remove_recursive_id(file_id)
2817
# in the future this should just set a dirty bit to wait for the
2818
# final unlock. However, until all methods of workingtree start
2819
# with the current in -memory inventory rather than triggering
2820
# a read, it is more complex - we need to teach read_inventory
2821
# to know when to read, and when to not read first... and possibly
2822
# to save first when the in memory one may be corrupted.
2823
# so for now, we just only write it if it is indeed dirty.
2825
self._write_inventory(self._inventory)
2827
def stored_kind(self, file_id):
2828
"""See Tree.stored_kind"""
2829
return self.inventory[file_id].kind
2832
"""Yield all unversioned files in this WorkingTree.
2834
If there are any unversioned directories then only the directory is
2835
returned, not all its children. But if there are unversioned files
2836
under a versioned subdirectory, they are returned.
2838
Currently returned depth-first, sorted by name within directories.
2839
This is the same order used by 'osutils.walkdirs'.
2841
## TODO: Work from given directory downwards
2842
for path, dir_entry in self.inventory.directories():
2843
# mutter("search for unknowns in %r", path)
2844
dirabs = self.abspath(path)
2845
if not isdir(dirabs):
2846
# e.g. directory deleted
2850
for subf in os.listdir(dirabs):
2851
if self.bzrdir.is_control_filename(subf):
2853
if subf not in dir_entry.children:
2856
can_access) = osutils.normalized_filename(subf)
2857
except UnicodeDecodeError:
2858
path_os_enc = path.encode(osutils._fs_enc)
2859
relpath = path_os_enc + '/' + subf
2860
raise errors.BadFilenameEncoding(relpath,
2862
if subf_norm != subf and can_access:
2863
if subf_norm not in dir_entry.children:
2864
fl.append(subf_norm)
2870
subp = pathjoin(path, subf)
2873
def _walkdirs(self, prefix=""):
2874
"""Walk the directories of this tree.
2876
:param prefix: is used as the directrory to start with.
2877
:returns: a generator which yields items in the form::
2879
((curren_directory_path, fileid),
2880
[(file1_path, file1_name, file1_kind, None, file1_id,
2883
_directory = 'directory'
2884
# get the root in the inventory
2885
inv = self.inventory
2886
top_id = inv.path2id(prefix)
2890
pending = [(prefix, '', _directory, None, top_id, None)]
2893
currentdir = pending.pop()
2894
# 0 - relpath, 1- basename, 2- kind, 3- stat, 4-id, 5-kind
2895
top_id = currentdir[4]
2897
relroot = currentdir[0] + '/'
2900
# FIXME: stash the node in pending
2902
if entry.kind == 'directory':
2903
for name, child in entry.sorted_children():
2904
dirblock.append((relroot + name, name, child.kind, None,
2905
child.file_id, child.kind
2907
yield (currentdir[0], entry.file_id), dirblock
2908
# push the user specified dirs from dirblock
2909
for dir in reversed(dirblock):
2910
if dir[2] == _directory:
2914
class WorkingTreeFormatRegistry(controldir.ControlComponentFormatRegistry):
2915
"""Registry for working tree formats."""
2917
def __init__(self, other_registry=None):
2918
super(WorkingTreeFormatRegistry, self).__init__(other_registry)
2919
self._default_format = None
2920
self._default_format_key = None
2922
def get_default(self):
2923
"""Return the current default format."""
2924
if (self._default_format_key is not None and
2925
self._default_format is None):
2926
self._default_format = self.get(self._default_format_key)
2927
return self._default_format
2929
def set_default(self, format):
2930
"""Set the default format."""
2931
self._default_format = format
2932
self._default_format_key = None
2934
def set_default_key(self, format_string):
2935
"""Set the default format by its format string."""
2936
self._default_format_key = format_string
2937
self._default_format = None
2940
format_registry = WorkingTreeFormatRegistry()
2943
class WorkingTreeFormat(controldir.ControlComponentFormat):
2750
2944
"""An encapsulation of the initialization and open routines for a format.
2752
2946
Formats provide three things:
3049
@symbol_versioning.deprecated_method(
3050
symbol_versioning.deprecated_in((2, 4, 0)))
2827
3051
def register_format(klass, format):
2828
klass._formats[format.get_format_string()] = format
3052
format_registry.register(format)
3055
@symbol_versioning.deprecated_method(
3056
symbol_versioning.deprecated_in((2, 4, 0)))
3057
def register_extra_format(klass, format):
3058
format_registry.register_extra(format)
3061
@symbol_versioning.deprecated_method(
3062
symbol_versioning.deprecated_in((2, 4, 0)))
3063
def unregister_extra_format(klass, format):
3064
format_registry.unregister_extra(format)
3067
@symbol_versioning.deprecated_method(
3068
symbol_versioning.deprecated_in((2, 4, 0)))
3069
def get_formats(klass):
3070
return format_registry._get_all()
3073
@symbol_versioning.deprecated_method(
3074
symbol_versioning.deprecated_in((2, 4, 0)))
2831
3075
def set_default_format(klass, format):
2832
klass._default_format = format
3076
format_registry.set_default(format)
3079
@symbol_versioning.deprecated_method(
3080
symbol_versioning.deprecated_in((2, 4, 0)))
2835
3081
def unregister_format(klass, format):
2836
del klass._formats[format.get_format_string()]
2839
class WorkingTreeFormat2(WorkingTreeFormat):
2840
"""The second working tree format.
2842
This format modified the hash cache from the format 1 hash cache.
2845
upgrade_recommended = True
2847
def get_format_description(self):
2848
"""See WorkingTreeFormat.get_format_description()."""
2849
return "Working tree format 2"
2851
def _stub_initialize_on_transport(self, transport, file_mode):
2852
"""Workaround: create control files for a remote working tree.
2854
This ensures that it can later be updated and dealt with locally,
2855
since BzrDirFormat6 and BzrDirFormat5 cannot represent dirs with
2856
no working tree. (See bug #43064).
2859
inv = inventory.Inventory()
2860
xml5.serializer_v5.write_inventory(inv, sio, working=True)
2862
transport.put_file('inventory', sio, file_mode)
2863
transport.put_bytes('pending-merges', '', file_mode)
2865
def initialize(self, a_bzrdir, revision_id=None, from_branch=None,
2866
accelerator_tree=None, hardlink=False):
2867
"""See WorkingTreeFormat.initialize()."""
2868
if not isinstance(a_bzrdir.transport, LocalTransport):
2869
raise errors.NotLocalUrl(a_bzrdir.transport.base)
2870
if from_branch is not None:
2871
branch = from_branch
2873
branch = a_bzrdir.open_branch()
2874
if revision_id is None:
2875
revision_id = _mod_revision.ensure_null(branch.last_revision())
2878
branch.generate_revision_history(revision_id)
2881
inv = inventory.Inventory()
2882
wt = WorkingTree2(a_bzrdir.root_transport.local_abspath('.'),
2888
basis_tree = branch.repository.revision_tree(revision_id)
2889
if basis_tree.inventory.root is not None:
2890
wt.set_root_id(basis_tree.get_root_id())
2891
# set the parent list and cache the basis tree.
2892
if _mod_revision.is_null(revision_id):
2895
parent_trees = [(revision_id, basis_tree)]
2896
wt.set_parent_trees(parent_trees)
2897
transform.build_tree(basis_tree, wt)
2901
super(WorkingTreeFormat2, self).__init__()
2902
self._matchingbzrdir = bzrdir.BzrDirFormat6()
2904
def open(self, a_bzrdir, _found=False):
2905
"""Return the WorkingTree object for a_bzrdir
2907
_found is a private parameter, do not use it. It is used to indicate
2908
if format probing has already been done.
2911
# we are being called directly and must probe.
2912
raise NotImplementedError
2913
if not isinstance(a_bzrdir.transport, LocalTransport):
2914
raise errors.NotLocalUrl(a_bzrdir.transport.base)
2915
wt = WorkingTree2(a_bzrdir.root_transport.local_abspath('.'),
2921
class WorkingTreeFormat3(WorkingTreeFormat):
2922
"""The second working tree format updated to record a format marker.
2925
- exists within a metadir controlling .bzr
2926
- includes an explicit version marker for the workingtree control
2927
files, separate from the BzrDir format
2928
- modifies the hash cache format
2930
- uses a LockDir to guard access for writes.
2933
upgrade_recommended = True
2935
def get_format_string(self):
2936
"""See WorkingTreeFormat.get_format_string()."""
2937
return "Bazaar-NG Working Tree format 3"
2939
def get_format_description(self):
2940
"""See WorkingTreeFormat.get_format_description()."""
2941
return "Working tree format 3"
2943
_lock_file_name = 'lock'
2944
_lock_class = LockDir
2946
_tree_class = WorkingTree3
2948
def __get_matchingbzrdir(self):
2949
return bzrdir.BzrDirMetaFormat1()
2951
_matchingbzrdir = property(__get_matchingbzrdir)
2953
def _open_control_files(self, a_bzrdir):
2954
transport = a_bzrdir.get_workingtree_transport(None)
2955
return LockableFiles(transport, self._lock_file_name,
2958
def initialize(self, a_bzrdir, revision_id=None, from_branch=None,
2959
accelerator_tree=None, hardlink=False):
2960
"""See WorkingTreeFormat.initialize().
2962
:param revision_id: if supplied, create a working tree at a different
2963
revision than the branch is at.
2964
:param accelerator_tree: A tree which can be used for retrieving file
2965
contents more quickly than the revision tree, i.e. a workingtree.
2966
The revision tree will be used for cases where accelerator_tree's
2967
content is different.
2968
:param hardlink: If true, hard-link files from accelerator_tree,
2971
if not isinstance(a_bzrdir.transport, LocalTransport):
2972
raise errors.NotLocalUrl(a_bzrdir.transport.base)
2973
transport = a_bzrdir.get_workingtree_transport(self)
2974
control_files = self._open_control_files(a_bzrdir)
2975
control_files.create_lock()
2976
control_files.lock_write()
2977
transport.put_bytes('format', self.get_format_string(),
2978
mode=a_bzrdir._get_file_mode())
2979
if from_branch is not None:
2980
branch = from_branch
2982
branch = a_bzrdir.open_branch()
2983
if revision_id is None:
2984
revision_id = _mod_revision.ensure_null(branch.last_revision())
2985
# WorkingTree3 can handle an inventory which has a unique root id.
2986
# as of bzr 0.12. However, bzr 0.11 and earlier fail to handle
2987
# those trees. And because there isn't a format bump inbetween, we
2988
# are maintaining compatibility with older clients.
2989
# inv = Inventory(root_id=gen_root_id())
2990
inv = self._initial_inventory()
2991
wt = self._tree_class(a_bzrdir.root_transport.local_abspath('.'),
2997
_control_files=control_files)
2998
wt.lock_tree_write()
3000
basis_tree = branch.repository.revision_tree(revision_id)
3001
# only set an explicit root id if there is one to set.
3002
if basis_tree.inventory.root is not None:
3003
wt.set_root_id(basis_tree.get_root_id())
3004
if revision_id == _mod_revision.NULL_REVISION:
3005
wt.set_parent_trees([])
3007
wt.set_parent_trees([(revision_id, basis_tree)])
3008
transform.build_tree(basis_tree, wt)
3010
# Unlock in this order so that the unlock-triggers-flush in
3011
# WorkingTree is given a chance to fire.
3012
control_files.unlock()
3016
def _initial_inventory(self):
3017
return inventory.Inventory()
3020
super(WorkingTreeFormat3, self).__init__()
3022
def open(self, a_bzrdir, _found=False):
3023
"""Return the WorkingTree object for a_bzrdir
3025
_found is a private parameter, do not use it. It is used to indicate
3026
if format probing has already been done.
3029
# we are being called directly and must probe.
3030
raise NotImplementedError
3031
if not isinstance(a_bzrdir.transport, LocalTransport):
3032
raise errors.NotLocalUrl(a_bzrdir.transport.base)
3033
wt = self._open(a_bzrdir, self._open_control_files(a_bzrdir))
3036
def _open(self, a_bzrdir, control_files):
3037
"""Open the tree itself.
3039
:param a_bzrdir: the dir for the tree.
3040
:param control_files: the control files for the tree.
3042
return self._tree_class(a_bzrdir.root_transport.local_abspath('.'),
3046
_control_files=control_files)
3049
return self.get_format_string()
3052
__default_format = WorkingTreeFormat6()
3053
WorkingTreeFormat.register_format(__default_format)
3054
WorkingTreeFormat.register_format(WorkingTreeFormat5())
3055
WorkingTreeFormat.register_format(WorkingTreeFormat4())
3056
WorkingTreeFormat.register_format(WorkingTreeFormat3())
3057
WorkingTreeFormat.set_default_format(__default_format)
3058
# formats which have no format string are not discoverable
3059
# and not independently creatable, so are not registered.
3060
_legacy_formats = [WorkingTreeFormat2(),
3082
format_registry.remove(format)
3085
format_registry.register_lazy("Bazaar Working Tree Format 4 (bzr 0.15)\n",
3086
"bzrlib.workingtree_4", "WorkingTreeFormat4")
3087
format_registry.register_lazy("Bazaar Working Tree Format 5 (bzr 1.11)\n",
3088
"bzrlib.workingtree_4", "WorkingTreeFormat5")
3089
format_registry.register_lazy("Bazaar Working Tree Format 6 (bzr 1.14)\n",
3090
"bzrlib.workingtree_4", "WorkingTreeFormat6")
3091
format_registry.register_lazy("Bazaar-NG Working Tree format 3",
3092
"bzrlib.workingtree_3", "WorkingTreeFormat3")
3093
format_registry.set_default_key("Bazaar Working Tree Format 6 (bzr 1.14)\n")