2608
1758
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.
1761
class InventoryWorkingTree(WorkingTree,
1762
bzrlib.mutabletree.MutableInventoryTree):
1763
"""Base class for working trees that are inventory-oriented.
1765
The inventory is held in the `Branch` working-inventory, and the
1766
files are in a directory on disk.
1768
It is possible for a `WorkingTree` to have a filename which is
1769
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()
1772
def __init__(self, basedir='.',
1773
branch=DEPRECATED_PARAMETER,
1775
_control_files=None,
1779
"""Construct a InventoryWorkingTree instance. This is not a public API.
1781
:param branch: A branch to override probing for the branch.
1783
super(InventoryWorkingTree, self).__init__(basedir=basedir,
1784
branch=branch, _control_files=_control_files, _internal=_internal,
1785
_format=_format, _bzrdir=_bzrdir)
1787
self._detect_case_handling()
1789
if _inventory is None:
1790
# This will be acquired on lock_read() or lock_write()
1791
self._inventory_is_modified = False
1792
self._inventory = None
1794
# the caller of __init__ has provided an inventory,
1795
# we assume they know what they are doing - as its only
1796
# the Format factory and creation methods that are
1797
# permitted to do this.
1798
self._set_inventory(_inventory, dirty=False)
1800
def _set_inventory(self, inv, dirty):
1801
"""Set the internal cached inventory.
1803
:param inv: The inventory to set.
1804
:param dirty: A boolean indicating whether the inventory is the same
1805
logical inventory as whats on disk. If True the inventory is not
1806
the same and should be written to disk or data will be lost, if
1807
False then the inventory is the same as that on disk and any
1808
serialisation would be unneeded overhead.
1810
self._inventory = inv
1811
self._inventory_is_modified = dirty
1813
def _detect_case_handling(self):
1814
wt_trans = self.bzrdir.get_workingtree_transport(None)
1816
wt_trans.stat(self._format.case_sensitive_filename)
1817
except errors.NoSuchFile:
1818
self.case_sensitive = True
1820
self.case_sensitive = False
1822
self._setup_directory_is_tree_reference()
1824
def _serialize(self, inventory, out_file):
1825
xml5.serializer_v5.write_inventory(self._inventory, out_file,
1828
def _deserialize(selt, in_file):
1829
return xml5.serializer_v5.read_inventory(in_file)
1831
@needs_tree_write_lock
1832
def _write_inventory(self, inv):
1833
"""Write inventory as the current inventory."""
1834
self._set_inventory(inv, dirty=True)
1837
# XXX: This method should be deprecated in favour of taking in a proper
1838
# new Inventory object.
1839
@needs_tree_write_lock
1840
def set_inventory(self, new_inventory_list):
1841
from bzrlib.inventory import (Inventory,
1845
inv = Inventory(self.get_root_id())
1846
for path, file_id, parent, kind in new_inventory_list:
1847
name = os.path.basename(path)
1850
# fixme, there should be a factory function inv,add_??
1851
if kind == 'directory':
1852
inv.add(InventoryDirectory(file_id, name, parent))
1853
elif kind == 'file':
1854
inv.add(InventoryFile(file_id, name, parent))
1855
elif kind == 'symlink':
1856
inv.add(InventoryLink(file_id, name, parent))
1858
raise errors.BzrError("unknown kind %r" % kind)
1859
self._write_inventory(inv)
1861
def _write_basis_inventory(self, xml):
1862
"""Write the basis inventory XML to the basis-inventory file"""
1863
path = self._basis_inventory_name()
1865
self._transport.put_file(path, sio,
1866
mode=self.bzrdir._get_file_mode())
1868
def _reset_data(self):
1869
"""Reset transient data that cannot be revalidated."""
1870
self._inventory_is_modified = False
1871
f = self._transport.get('inventory')
1873
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."""
1876
self._set_inventory(result, dirty=False)
1878
def _set_root_id(self, file_id):
1879
"""Set the root id for this tree, in a format specific manner.
1881
:param file_id: The file id to assign to the root. It must not be
1882
present in the current inventory or an error will occur. It must
1883
not be None, but rather a valid file id.
1885
inv = self._inventory
1886
orig_root_id = inv.root.file_id
1887
# TODO: it might be nice to exit early if there was nothing
1888
# to do, saving us from trigger a sync on unlock.
1889
self._inventory_is_modified = True
1890
# we preserve the root inventory entry object, but
1891
# unlinkit from the byid index
1892
del inv._byid[inv.root.file_id]
1893
inv.root.file_id = file_id
1894
# and link it into the index with the new changed id.
1895
inv._byid[inv.root.file_id] = inv.root
1896
# and finally update all children to reference the new id.
1897
# XXX: this should be safe to just look at the root.children
1898
# list, not the WHOLE INVENTORY.
1901
if entry.parent_id == orig_root_id:
1902
entry.parent_id = inv.root.file_id
1904
def all_file_ids(self):
1905
"""See Tree.iter_all_file_ids"""
1906
return set(self.inventory)
1908
@needs_tree_write_lock
1909
def set_parent_trees(self, parents_list, allow_leftmost_as_ghost=False):
1910
"""See MutableTree.set_parent_trees."""
1911
parent_ids = [rev for (rev, tree) in parents_list]
1912
for revision_id in parent_ids:
1913
_mod_revision.check_not_reserved_id(revision_id)
1915
self._check_parents_for_ghosts(parent_ids,
1916
allow_leftmost_as_ghost=allow_leftmost_as_ghost)
1918
parent_ids = self._filter_parent_ids_by_ancestry(parent_ids)
1920
if len(parent_ids) == 0:
1921
leftmost_parent_id = _mod_revision.NULL_REVISION
1922
leftmost_parent_tree = None
1924
leftmost_parent_id, leftmost_parent_tree = parents_list[0]
1926
if self._change_last_revision(leftmost_parent_id):
1927
if leftmost_parent_tree is None:
1928
# If we don't have a tree, fall back to reading the
1929
# parent tree from the repository.
1930
self._cache_basis_inventory(leftmost_parent_id)
1932
inv = leftmost_parent_tree.inventory
1933
xml = self._create_basis_xml_from_inventory(
1934
leftmost_parent_id, inv)
1935
self._write_basis_inventory(xml)
1936
self._set_merges_from_parent_ids(parent_ids)
1938
def _cache_basis_inventory(self, new_revision):
1939
"""Cache new_revision as the basis inventory."""
1940
# TODO: this should allow the ready-to-use inventory to be passed in,
1941
# 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())]
1944
# this double handles the inventory - unpack and repack -
1945
# but is easier to understand. We can/should put a conditional
1946
# in here based on whether the inventory is in the latest format
1947
# - perhaps we should repack all inventories on a repository
1949
# the fast path is to copy the raw xml from the repository. If the
1950
# xml contains 'revision_id="', then we assume the right
1951
# revision_id is set. We must check for this full string, because a
1952
# root node id can legitimately look like 'revision_id' but cannot
1954
xml = self.branch.repository._get_inventory_xml(new_revision)
1955
firstline = xml.split('\n', 1)[0]
1956
if (not 'revision_id="' in firstline or
1957
'format="7"' not in firstline):
1958
inv = self.branch.repository._serializer.read_inventory_from_string(
1960
xml = self._create_basis_xml_from_inventory(new_revision, inv)
1961
self._write_basis_inventory(xml)
1962
except (errors.NoSuchRevision, errors.RevisionNotPresent):
1965
def _basis_inventory_name(self):
1966
return 'basis-inventory-cache'
1968
def _create_basis_xml_from_inventory(self, revision_id, inventory):
1969
"""Create the text that will be saved in basis-inventory"""
1970
inventory.revision_id = revision_id
1971
return xml7.serializer_v7.write_inventory_to_string(inventory)
2700
1973
@needs_tree_write_lock
2701
1974
def set_conflicts(self, conflicts):
2721
1994
raise errors.ConflictFormatError()
2722
1995
except StopIteration:
2723
1996
raise errors.ConflictFormatError()
2724
return _mod_conflicts.ConflictList.from_stanzas(RioReader(confile))
1997
reader = _mod_rio.RioReader(confile)
1998
return _mod_conflicts.ConflictList.from_stanzas(reader)
2726
2000
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):
2002
def read_basis_inventory(self):
2003
"""Read the cached basis inventory."""
2004
path = self._basis_inventory_name()
2005
return self._transport.get_bytes(path)
2008
def read_working_inventory(self):
2009
"""Read the working inventory.
2011
:raises errors.InventoryModified: read_working_inventory will fail
2012
when the current in memory inventory has been modified.
2014
# conceptually this should be an implementation detail of the tree.
2015
# XXX: Deprecate this.
2016
# ElementTree does its own conversion from UTF-8, so open in
2018
if self._inventory_is_modified:
2019
raise errors.InventoryModified(self)
2020
f = self._transport.get('inventory')
2022
result = self._deserialize(f)
2025
self._set_inventory(result, dirty=False)
2029
def get_root_id(self):
2030
"""Return the id of this trees root"""
2031
return self._inventory.root.file_id
2033
def has_id(self, file_id):
2034
# files that have been deleted are excluded
2035
inv = self.inventory
2036
if not inv.has_id(file_id):
2038
path = inv.id2path(file_id)
2039
return osutils.lexists(self.abspath(path))
2041
def has_or_had_id(self, file_id):
2042
if file_id == self.inventory.root.file_id:
2044
return self.inventory.has_id(file_id)
2046
@symbol_versioning.deprecated_method(symbol_versioning.deprecated_in((2, 4, 0)))
2048
"""Iterate through file_ids for this tree.
2050
file_ids are in a WorkingTree if they are in the working inventory
2051
and the working file exists.
2053
inv = self._inventory
2054
for path, ie in inv.iter_entries():
2055
if osutils.lexists(self.abspath(path)):
2058
@needs_tree_write_lock
2059
def set_last_revision(self, new_revision):
2060
"""Change the last revision in the working tree."""
2061
if self._change_last_revision(new_revision):
2062
self._cache_basis_inventory(new_revision)
2064
def _get_check_refs(self):
2065
"""Return the references needed to perform a check of this tree.
2067
The default implementation returns no refs, and is only suitable for
2068
trees that have no local caching and can commit on ghosts at any time.
2070
:seealso: bzrlib.check for details about check_refs.
2075
def _check(self, references):
2076
"""Check the tree for consistency.
2078
:param references: A dict with keys matching the items returned by
2079
self._get_check_refs(), and values from looking those keys up in
2082
tree_basis = self.basis_tree()
2083
tree_basis.lock_read()
2085
repo_basis = references[('trees', self.last_revision())]
2086
if len(list(repo_basis.iter_changes(tree_basis))) > 0:
2087
raise errors.BzrCheckError(
2088
"Mismatched basis inventory content.")
2094
def check_state(self):
2095
"""Check that the working state is/isn't valid."""
2096
check_refs = self._get_check_refs()
2098
for ref in check_refs:
2101
refs[ref] = self.branch.repository.revision_tree(value)
2104
@needs_tree_write_lock
2105
def reset_state(self, revision_ids=None):
2106
"""Reset the state of the working tree.
2108
This does a hard-reset to a last-known-good state. This is a way to
2109
fix if something got corrupted (like the .bzr/checkout/dirstate file)
2111
if revision_ids is None:
2112
revision_ids = self.get_parent_ids()
2113
if not revision_ids:
2114
rt = self.branch.repository.revision_tree(
2115
_mod_revision.NULL_REVISION)
2117
rt = self.branch.repository.revision_tree(revision_ids[0])
2118
self._write_inventory(rt.inventory)
2119
self.set_parent_ids(revision_ids)
2122
"""Write the in memory inventory to disk."""
2123
# TODO: Maybe this should only write on dirty ?
2124
if self._control_files._lock_mode != 'w':
2125
raise errors.NotWriteLocked(self)
2127
self._serialize(self._inventory, sio)
2129
self._transport.put_file('inventory', sio,
2130
mode=self.bzrdir._get_file_mode())
2131
self._inventory_is_modified = False
2133
def get_file_mtime(self, file_id, path=None):
2134
"""See Tree.get_file_mtime."""
2136
path = self.inventory.id2path(file_id)
2137
return os.lstat(self.abspath(path)).st_mtime
2139
def _is_executable_from_path_and_stat_from_basis(self, path, stat_result):
2140
file_id = self.path2id(path)
2142
# For unversioned files on win32, we just assume they are not
2145
return self._inventory[file_id].executable
2147
def _is_executable_from_path_and_stat_from_stat(self, path, stat_result):
2148
mode = stat_result.st_mode
2149
return bool(stat.S_ISREG(mode) and stat.S_IEXEC & mode)
2151
if not supports_executable():
2152
def is_executable(self, file_id, path=None):
2153
return self._inventory[file_id].executable
2155
_is_executable_from_path_and_stat = \
2156
_is_executable_from_path_and_stat_from_basis
2158
def is_executable(self, file_id, path=None):
2160
path = self.id2path(file_id)
2161
mode = os.lstat(self.abspath(path)).st_mode
2162
return bool(stat.S_ISREG(mode) and stat.S_IEXEC & mode)
2164
_is_executable_from_path_and_stat = \
2165
_is_executable_from_path_and_stat_from_stat
2167
@needs_tree_write_lock
2168
def _add(self, files, ids, kinds):
2169
"""See MutableTree._add."""
2170
# TODO: Re-adding a file that is removed in the working copy
2171
# should probably put it back with the previous ID.
2172
# the read and write working inventory should not occur in this
2173
# function - they should be part of lock_write and unlock.
2174
inv = self.inventory
2175
for f, file_id, kind in zip(files, ids, kinds):
2177
inv.add_path(f, kind=kind)
2179
inv.add_path(f, kind=kind, file_id=file_id)
2180
self._inventory_is_modified = True
2182
def revision_tree(self, revision_id):
2183
"""See WorkingTree.revision_id."""
2184
if revision_id == self.last_revision():
2186
xml = self.read_basis_inventory()
2187
except errors.NoSuchFile:
2191
inv = xml7.serializer_v7.read_inventory_from_string(xml)
2192
# dont use the repository revision_tree api because we want
2193
# to supply the inventory.
2194
if inv.revision_id == revision_id:
2195
return revisiontree.InventoryRevisionTree(
2196
self.branch.repository, inv, revision_id)
2197
except errors.BadInventoryFormat:
2199
# raise if there was no inventory, or if we read the wrong inventory.
2200
raise errors.NoSuchRevisionInTree(self, revision_id)
2203
def annotate_iter(self, file_id, default_revision=CURRENT_REVISION):
2204
"""See Tree.annotate_iter
2206
This implementation will use the basis tree implementation if possible.
2207
Lines not in the basis are attributed to CURRENT_REVISION
2209
If there are pending merges, lines added by those merges will be
2210
incorrectly attributed to CURRENT_REVISION (but after committing, the
2211
attribution will be correct).
2213
maybe_file_parent_keys = []
2214
for parent_id in self.get_parent_ids():
2216
parent_tree = self.revision_tree(parent_id)
2217
except errors.NoSuchRevisionInTree:
2218
parent_tree = self.branch.repository.revision_tree(parent_id)
2219
parent_tree.lock_read()
2221
if not parent_tree.has_id(file_id):
2223
ie = parent_tree.inventory[file_id]
2224
if ie.kind != 'file':
2225
# Note: this is slightly unnecessary, because symlinks and
2226
# directories have a "text" which is the empty text, and we
2227
# know that won't mess up annotations. But it seems cleaner
2229
parent_text_key = (file_id, ie.revision)
2230
if parent_text_key not in maybe_file_parent_keys:
2231
maybe_file_parent_keys.append(parent_text_key)
2233
parent_tree.unlock()
2234
graph = _mod_graph.Graph(self.branch.repository.texts)
2235
heads = graph.heads(maybe_file_parent_keys)
2236
file_parent_keys = []
2237
for key in maybe_file_parent_keys:
2239
file_parent_keys.append(key)
2241
# Now we have the parents of this content
2242
annotator = self.branch.repository.texts.get_annotator()
2243
text = self.get_file_text(file_id)
2244
this_key =(file_id, default_revision)
2245
annotator.add_special_text(this_key, file_parent_keys, text)
2246
annotations = [(key[-1], line)
2247
for key, line in annotator.annotate_flat(this_key)]
2251
def merge_modified(self):
2252
"""Return a dictionary of files modified by a merge.
2254
The list is initialized by WorkingTree.set_merge_modified, which is
2255
typically called after we make some automatic updates to the tree
2258
This returns a map of file_id->sha1, containing only files which are
2259
still in the working inventory and have that text hash.
2262
hashfile = self._transport.get('merge-hashes')
2263
except errors.NoSuchFile:
2268
if hashfile.next() != MERGE_MODIFIED_HEADER_1 + '\n':
2269
raise errors.MergeModifiedFormatError()
2270
except StopIteration:
2271
raise errors.MergeModifiedFormatError()
2272
for s in _mod_rio.RioReader(hashfile):
2273
# RioReader reads in Unicode, so convert file_ids back to utf8
2274
file_id = osutils.safe_file_id(s.get("file_id"), warn=False)
2275
if not self.inventory.has_id(file_id):
2277
text_hash = s.get("hash")
2278
if text_hash == self.get_file_sha1(file_id):
2279
merge_hashes[file_id] = text_hash
2285
def subsume(self, other_tree):
2286
def add_children(inventory, entry):
2287
for child_entry in entry.children.values():
2288
inventory._byid[child_entry.file_id] = child_entry
2289
if child_entry.kind == 'directory':
2290
add_children(inventory, child_entry)
2291
if other_tree.get_root_id() == self.get_root_id():
2292
raise errors.BadSubsumeSource(self, other_tree,
2293
'Trees have the same root')
2295
other_tree_path = self.relpath(other_tree.basedir)
2296
except errors.PathNotChild:
2297
raise errors.BadSubsumeSource(self, other_tree,
2298
'Tree is not contained by the other')
2299
new_root_parent = self.path2id(osutils.dirname(other_tree_path))
2300
if new_root_parent is None:
2301
raise errors.BadSubsumeSource(self, other_tree,
2302
'Parent directory is not versioned.')
2303
# We need to ensure that the result of a fetch will have a
2304
# versionedfile for the other_tree root, and only fetching into
2305
# RepositoryKnit2 guarantees that.
2306
if not self.branch.repository.supports_rich_root():
2307
raise errors.SubsumeTargetNeedsUpgrade(other_tree)
2308
other_tree.lock_tree_write()
2310
new_parents = other_tree.get_parent_ids()
2311
other_root = other_tree.inventory.root
2312
other_root.parent_id = new_root_parent
2313
other_root.name = osutils.basename(other_tree_path)
2314
self.inventory.add(other_root)
2315
add_children(self.inventory, other_root)
2316
self._write_inventory(self.inventory)
2317
# normally we don't want to fetch whole repositories, but i think
2318
# here we really do want to consolidate the whole thing.
2319
for parent_id in other_tree.get_parent_ids():
2320
self.branch.fetch(other_tree.branch, parent_id)
2321
self.add_parent_tree_id(parent_id)
2324
other_tree.bzrdir.retire_bzrdir()
2326
@needs_tree_write_lock
2327
def extract(self, file_id, format=None):
2328
"""Extract a subtree from this tree.
2330
A new branch will be created, relative to the path for this tree.
2334
segments = osutils.splitpath(path)
2335
transport = self.branch.bzrdir.root_transport
2336
for name in segments:
2337
transport = transport.clone(name)
2338
transport.ensure_base()
2341
sub_path = self.id2path(file_id)
2342
branch_transport = mkdirs(sub_path)
2344
format = self.bzrdir.cloning_metadir()
2345
branch_transport.ensure_base()
2346
branch_bzrdir = format.initialize_on_transport(branch_transport)
2348
repo = branch_bzrdir.find_repository()
2349
except errors.NoRepositoryPresent:
2350
repo = branch_bzrdir.create_repository()
2351
if not repo.supports_rich_root():
2352
raise errors.RootNotRich()
2353
new_branch = branch_bzrdir.create_branch()
2354
new_branch.pull(self.branch)
2355
for parent_id in self.get_parent_ids():
2356
new_branch.fetch(self.branch, parent_id)
2357
tree_transport = self.bzrdir.root_transport.clone(sub_path)
2358
if tree_transport.base != branch_transport.base:
2359
tree_bzrdir = format.initialize_on_transport(tree_transport)
2360
branch.BranchReferenceFormat().initialize(tree_bzrdir,
2361
target_branch=new_branch)
2363
tree_bzrdir = branch_bzrdir
2364
wt = tree_bzrdir.create_workingtree(_mod_revision.NULL_REVISION)
2365
wt.set_parent_ids(self.get_parent_ids())
2366
my_inv = self.inventory
2367
child_inv = inventory.Inventory(root_id=None)
2368
new_root = my_inv[file_id]
2369
my_inv.remove_recursive_id(file_id)
2370
new_root.parent_id = None
2371
child_inv.add(new_root)
2372
self._write_inventory(my_inv)
2373
wt._write_inventory(child_inv)
2376
def list_files(self, include_root=False, from_dir=None, recursive=True):
2377
"""List all files as (path, class, kind, id, entry).
2379
Lists, but does not descend into unversioned directories.
2380
This does not include files that have been deleted in this
2381
tree. Skips the control directory.
2383
:param include_root: if True, return an entry for the root
2384
:param from_dir: start from this directory or None for the root
2385
:param recursive: whether to recurse into subdirectories or not
2387
# list_files is an iterator, so @needs_read_lock doesn't work properly
2388
# with it. So callers should be careful to always read_lock the tree.
2389
if not self.is_locked():
2390
raise errors.ObjectNotLocked(self)
2392
inv = self.inventory
2393
if from_dir is None and include_root is True:
2394
yield ('', 'V', 'directory', inv.root.file_id, inv.root)
2395
# Convert these into local objects to save lookup times
2396
pathjoin = osutils.pathjoin
2397
file_kind = self._kind
2399
# transport.base ends in a slash, we want the piece
2400
# between the last two slashes
2401
transport_base_dir = self.bzrdir.transport.base.rsplit('/', 2)[1]
2403
fk_entries = {'directory':TreeDirectory, 'file':TreeFile, 'symlink':TreeLink}
2405
# directory file_id, relative path, absolute path, reverse sorted children
2406
if from_dir is not None:
2407
from_dir_id = inv.path2id(from_dir)
2408
if from_dir_id is None:
2409
# Directory not versioned
2411
from_dir_abspath = pathjoin(self.basedir, from_dir)
2413
from_dir_id = inv.root.file_id
2414
from_dir_abspath = self.basedir
2415
children = os.listdir(from_dir_abspath)
2417
# jam 20060527 The kernel sized tree seems equivalent whether we
2418
# use a deque and popleft to keep them sorted, or if we use a plain
2419
# list and just reverse() them.
2420
children = collections.deque(children)
2421
stack = [(from_dir_id, u'', from_dir_abspath, children)]
2423
from_dir_id, from_dir_relpath, from_dir_abspath, children = stack[-1]
2426
f = children.popleft()
2427
## TODO: If we find a subdirectory with its own .bzr
2428
## directory, then that is a separate tree and we
2429
## should exclude it.
2431
# the bzrdir for this tree
2432
if transport_base_dir == f:
2435
# we know that from_dir_relpath and from_dir_abspath never end in a slash
2436
# and 'f' doesn't begin with one, we can do a string op, rather
2437
# than the checks of pathjoin(), all relative paths will have an extra slash
2439
fp = from_dir_relpath + '/' + f
2442
fap = from_dir_abspath + '/' + f
2444
dir_ie = inv[from_dir_id]
2445
if dir_ie.kind == 'directory':
2446
f_ie = dir_ie.children.get(f)
2451
elif self.is_ignored(fp[1:]):
2454
# we may not have found this file, because of a unicode
2455
# issue, or because the directory was actually a symlink.
2456
f_norm, can_access = osutils.normalized_filename(f)
2457
if f == f_norm or not can_access:
2458
# No change, so treat this file normally
2461
# this file can be accessed by a normalized path
2462
# check again if it is versioned
2463
# these lines are repeated here for performance
2465
fp = from_dir_relpath + '/' + f
2466
fap = from_dir_abspath + '/' + f
2467
f_ie = inv.get_child(from_dir_id, f)
2470
elif self.is_ignored(fp[1:]):
2477
# make a last minute entry
2479
yield fp[1:], c, fk, f_ie.file_id, f_ie
2482
yield fp[1:], c, fk, None, fk_entries[fk]()
2484
yield fp[1:], c, fk, None, TreeEntry()
2487
if fk != 'directory':
2490
# But do this child first if recursing down
2492
new_children = os.listdir(fap)
2494
new_children = collections.deque(new_children)
2495
stack.append((f_ie.file_id, fp, fap, new_children))
2496
# Break out of inner loop,
2497
# so that we start outer loop with child
2500
# if we finished all children, pop it off the stack
2503
@needs_tree_write_lock
2504
def move(self, from_paths, to_dir=None, after=False):
2507
to_dir must exist in the inventory.
2509
If to_dir exists and is a directory, the files are moved into
2510
it, keeping their old names.
2512
Note that to_dir is only the last component of the new name;
2513
this doesn't change the directory.
2515
For each entry in from_paths the move mode will be determined
2518
The first mode moves the file in the filesystem and updates the
2519
inventory. The second mode only updates the inventory without
2520
touching the file on the filesystem.
2522
move uses the second mode if 'after == True' and the target is
2523
either not versioned or newly added, and present in the working tree.
2525
move uses the second mode if 'after == False' and the source is
2526
versioned but no longer in the working tree, and the target is not
2527
versioned but present in the working tree.
2529
move uses the first mode if 'after == False' and the source is
2530
versioned and present in the working tree, and the target is not
2531
versioned and not present in the working tree.
2533
Everything else results in an error.
2535
This returns a list of (from_path, to_path) pairs for each
2536
entry that is moved.
2541
# check for deprecated use of signature
2543
raise TypeError('You must supply a target directory')
2544
# check destination directory
2545
if isinstance(from_paths, basestring):
2547
inv = self.inventory
2548
to_abs = self.abspath(to_dir)
2549
if not isdir(to_abs):
2550
raise errors.BzrMoveFailedError('',to_dir,
2551
errors.NotADirectory(to_abs))
2552
if not self.has_filename(to_dir):
2553
raise errors.BzrMoveFailedError('',to_dir,
2554
errors.NotInWorkingDirectory(to_dir))
2555
to_dir_id = inv.path2id(to_dir)
2556
if to_dir_id is None:
2557
raise errors.BzrMoveFailedError('',to_dir,
2558
errors.NotVersionedError(path=to_dir))
2560
to_dir_ie = inv[to_dir_id]
2561
if to_dir_ie.kind != 'directory':
2562
raise errors.BzrMoveFailedError('',to_dir,
2563
errors.NotADirectory(to_abs))
2565
# create rename entries and tuples
2566
for from_rel in from_paths:
2567
from_tail = splitpath(from_rel)[-1]
2568
from_id = inv.path2id(from_rel)
2570
raise errors.BzrMoveFailedError(from_rel,to_dir,
2571
errors.NotVersionedError(path=from_rel))
2573
from_entry = inv[from_id]
2574
from_parent_id = from_entry.parent_id
2575
to_rel = pathjoin(to_dir, from_tail)
2576
rename_entry = InventoryWorkingTree._RenameEntry(
2579
from_tail=from_tail,
2580
from_parent_id=from_parent_id,
2581
to_rel=to_rel, to_tail=from_tail,
2582
to_parent_id=to_dir_id)
2583
rename_entries.append(rename_entry)
2584
rename_tuples.append((from_rel, to_rel))
2586
# determine which move mode to use. checks also for movability
2587
rename_entries = self._determine_mv_mode(rename_entries, after)
2589
original_modified = self._inventory_is_modified
2592
self._inventory_is_modified = True
2593
self._move(rename_entries)
2595
# restore the inventory on error
2596
self._inventory_is_modified = original_modified
2598
self._write_inventory(inv)
2599
return rename_tuples
2601
@needs_tree_write_lock
2602
def rename_one(self, from_rel, to_rel, after=False):
2605
This can change the directory or the filename or both.
2607
rename_one has several 'modes' to work. First, it can rename a physical
2608
file and change the file_id. That is the normal mode. Second, it can
2609
only change the file_id without touching any physical file.
2611
rename_one uses the second mode if 'after == True' and 'to_rel' is not
2612
versioned but present in the working tree.
2614
rename_one uses the second mode if 'after == False' and 'from_rel' is
2615
versioned but no longer in the working tree, and 'to_rel' is not
2616
versioned but present in the working tree.
2618
rename_one uses the first mode if 'after == False' and 'from_rel' is
2619
versioned and present in the working tree, and 'to_rel' is not
2620
versioned and not present in the working tree.
2622
Everything else results in an error.
2624
inv = self.inventory
2627
# create rename entries and tuples
2628
from_tail = splitpath(from_rel)[-1]
2629
from_id = inv.path2id(from_rel)
2631
# if file is missing in the inventory maybe it's in the basis_tree
2632
basis_tree = self.branch.basis_tree()
2633
from_id = basis_tree.path2id(from_rel)
2635
raise errors.BzrRenameFailedError(from_rel,to_rel,
2636
errors.NotVersionedError(path=from_rel))
2637
# put entry back in the inventory so we can rename it
2638
from_entry = basis_tree.inventory[from_id].copy()
2641
from_entry = inv[from_id]
2642
from_parent_id = from_entry.parent_id
2643
to_dir, to_tail = os.path.split(to_rel)
2644
to_dir_id = inv.path2id(to_dir)
2645
rename_entry = InventoryWorkingTree._RenameEntry(from_rel=from_rel,
2647
from_tail=from_tail,
2648
from_parent_id=from_parent_id,
2649
to_rel=to_rel, to_tail=to_tail,
2650
to_parent_id=to_dir_id)
2651
rename_entries.append(rename_entry)
2653
# determine which move mode to use. checks also for movability
2654
rename_entries = self._determine_mv_mode(rename_entries, after)
2656
# check if the target changed directory and if the target directory is
2658
if to_dir_id is None:
2659
raise errors.BzrMoveFailedError(from_rel,to_rel,
2660
errors.NotVersionedError(path=to_dir))
2662
# all checks done. now we can continue with our actual work
2663
mutter('rename_one:\n'
2668
' to_dir_id {%s}\n',
2669
from_id, from_rel, to_rel, to_dir, to_dir_id)
2671
self._move(rename_entries)
2672
self._write_inventory(inv)
2674
class _RenameEntry(object):
2675
def __init__(self, from_rel, from_id, from_tail, from_parent_id,
2676
to_rel, to_tail, to_parent_id, only_change_inv=False,
2678
self.from_rel = from_rel
2679
self.from_id = from_id
2680
self.from_tail = from_tail
2681
self.from_parent_id = from_parent_id
2682
self.to_rel = to_rel
2683
self.to_tail = to_tail
2684
self.to_parent_id = to_parent_id
2685
self.change_id = change_id
2686
self.only_change_inv = only_change_inv
2688
def _determine_mv_mode(self, rename_entries, after=False):
2689
"""Determines for each from-to pair if both inventory and working tree
2690
or only the inventory has to be changed.
2692
Also does basic plausability tests.
2694
inv = self.inventory
2696
for rename_entry in rename_entries:
2697
# store to local variables for easier reference
2698
from_rel = rename_entry.from_rel
2699
from_id = rename_entry.from_id
2700
to_rel = rename_entry.to_rel
2701
to_id = inv.path2id(to_rel)
2702
only_change_inv = False
2705
# check the inventory for source and destination
2707
raise errors.BzrMoveFailedError(from_rel,to_rel,
2708
errors.NotVersionedError(path=from_rel))
2709
if to_id is not None:
2711
# allow it with --after but only if dest is newly added
2713
basis = self.basis_tree()
2716
if not basis.has_id(to_id):
2717
rename_entry.change_id = True
2722
raise errors.BzrMoveFailedError(from_rel,to_rel,
2723
errors.AlreadyVersionedError(path=to_rel))
2725
# try to determine the mode for rename (only change inv or change
2726
# inv and file system)
2728
if not self.has_filename(to_rel):
2729
raise errors.BzrMoveFailedError(from_id,to_rel,
2730
errors.NoSuchFile(path=to_rel,
2731
extra="New file has not been created yet"))
2732
only_change_inv = True
2733
elif not self.has_filename(from_rel) and self.has_filename(to_rel):
2734
only_change_inv = True
2735
elif self.has_filename(from_rel) and not self.has_filename(to_rel):
2736
only_change_inv = False
2737
elif (not self.case_sensitive
2738
and from_rel.lower() == to_rel.lower()
2739
and self.has_filename(from_rel)):
2740
only_change_inv = False
2742
# something is wrong, so lets determine what exactly
2743
if not self.has_filename(from_rel) and \
2744
not self.has_filename(to_rel):
2745
raise errors.BzrRenameFailedError(from_rel,to_rel,
2746
errors.PathsDoNotExist(paths=(str(from_rel),
2749
raise errors.RenameFailedFilesExist(from_rel, to_rel)
2750
rename_entry.only_change_inv = only_change_inv
2751
return rename_entries
2753
def _move(self, rename_entries):
2754
"""Moves a list of files.
2756
Depending on the value of the flag 'only_change_inv', the
2757
file will be moved on the file system or not.
2759
inv = self.inventory
2762
for entry in rename_entries:
2764
self._move_entry(entry)
2766
self._rollback_move(moved)
2770
def _rollback_move(self, moved):
2771
"""Try to rollback a previous move in case of an filesystem error."""
2772
inv = self.inventory
2775
self._move_entry(WorkingTree._RenameEntry(
2776
entry.to_rel, entry.from_id,
2777
entry.to_tail, entry.to_parent_id, entry.from_rel,
2778
entry.from_tail, entry.from_parent_id,
2779
entry.only_change_inv))
2780
except errors.BzrMoveFailedError, e:
2781
raise errors.BzrMoveFailedError( '', '', "Rollback failed."
2782
" The working tree is in an inconsistent state."
2783
" Please consider doing a 'bzr revert'."
2784
" Error message is: %s" % e)
2786
def _move_entry(self, entry):
2787
inv = self.inventory
2788
from_rel_abs = self.abspath(entry.from_rel)
2789
to_rel_abs = self.abspath(entry.to_rel)
2790
if from_rel_abs == to_rel_abs:
2791
raise errors.BzrMoveFailedError(entry.from_rel, entry.to_rel,
2792
"Source and target are identical.")
2794
if not entry.only_change_inv:
2796
osutils.rename(from_rel_abs, to_rel_abs)
2798
raise errors.BzrMoveFailedError(entry.from_rel,
2801
to_id = inv.path2id(entry.to_rel)
2802
inv.remove_recursive_id(to_id)
2803
inv.rename(entry.from_id, entry.to_parent_id, entry.to_tail)
2805
@needs_tree_write_lock
2806
def unversion(self, file_ids):
2807
"""Remove the file ids in file_ids from the current versioned set.
2809
When a file_id is unversioned, all of its children are automatically
2812
:param file_ids: The file ids to stop versioning.
2813
:raises: NoSuchId if any fileid is not currently versioned.
2815
for file_id in file_ids:
2816
if not self._inventory.has_id(file_id):
2817
raise errors.NoSuchId(self, file_id)
2818
for file_id in file_ids:
2819
if self._inventory.has_id(file_id):
2820
self._inventory.remove_recursive_id(file_id)
2822
# in the future this should just set a dirty bit to wait for the
2823
# final unlock. However, until all methods of workingtree start
2824
# with the current in -memory inventory rather than triggering
2825
# a read, it is more complex - we need to teach read_inventory
2826
# to know when to read, and when to not read first... and possibly
2827
# to save first when the in memory one may be corrupted.
2828
# so for now, we just only write it if it is indeed dirty.
2830
self._write_inventory(self._inventory)
2832
def stored_kind(self, file_id):
2833
"""See Tree.stored_kind"""
2834
return self.inventory[file_id].kind
2837
"""Yield all unversioned files in this WorkingTree.
2839
If there are any unversioned directories then only the directory is
2840
returned, not all its children. But if there are unversioned files
2841
under a versioned subdirectory, they are returned.
2843
Currently returned depth-first, sorted by name within directories.
2844
This is the same order used by 'osutils.walkdirs'.
2846
## TODO: Work from given directory downwards
2847
for path, dir_entry in self.inventory.directories():
2848
# mutter("search for unknowns in %r", path)
2849
dirabs = self.abspath(path)
2850
if not isdir(dirabs):
2851
# e.g. directory deleted
2855
for subf in os.listdir(dirabs):
2856
if self.bzrdir.is_control_filename(subf):
2858
if subf not in dir_entry.children:
2861
can_access) = osutils.normalized_filename(subf)
2862
except UnicodeDecodeError:
2863
path_os_enc = path.encode(osutils._fs_enc)
2864
relpath = path_os_enc + '/' + subf
2865
raise errors.BadFilenameEncoding(relpath,
2867
if subf_norm != subf and can_access:
2868
if subf_norm not in dir_entry.children:
2869
fl.append(subf_norm)
2875
subp = pathjoin(path, subf)
2878
def _walkdirs(self, prefix=""):
2879
"""Walk the directories of this tree.
2881
:param prefix: is used as the directrory to start with.
2882
:returns: a generator which yields items in the form::
2884
((curren_directory_path, fileid),
2885
[(file1_path, file1_name, file1_kind, None, file1_id,
2888
_directory = 'directory'
2889
# get the root in the inventory
2890
inv = self.inventory
2891
top_id = inv.path2id(prefix)
2895
pending = [(prefix, '', _directory, None, top_id, None)]
2898
currentdir = pending.pop()
2899
# 0 - relpath, 1- basename, 2- kind, 3- stat, 4-id, 5-kind
2900
top_id = currentdir[4]
2902
relroot = currentdir[0] + '/'
2905
# FIXME: stash the node in pending
2907
if entry.kind == 'directory':
2908
for name, child in entry.sorted_children():
2909
dirblock.append((relroot + name, name, child.kind, None,
2910
child.file_id, child.kind
2912
yield (currentdir[0], entry.file_id), dirblock
2913
# push the user specified dirs from dirblock
2914
for dir in reversed(dirblock):
2915
if dir[2] == _directory:
2919
class WorkingTreeFormatRegistry(controldir.ControlComponentFormatRegistry):
2920
"""Registry for working tree formats."""
2922
def __init__(self, other_registry=None):
2923
super(WorkingTreeFormatRegistry, self).__init__(other_registry)
2924
self._default_format = None
2925
self._default_format_key = None
2927
def get_default(self):
2928
"""Return the current default format."""
2929
if (self._default_format_key is not None and
2930
self._default_format is None):
2931
self._default_format = self.get(self._default_format_key)
2932
return self._default_format
2934
def set_default(self, format):
2935
"""Set the default format."""
2936
self._default_format = format
2937
self._default_format_key = None
2939
def set_default_key(self, format_string):
2940
"""Set the default format by its format string."""
2941
self._default_format_key = format_string
2942
self._default_format = None
2945
format_registry = WorkingTreeFormatRegistry()
2948
class WorkingTreeFormat(controldir.ControlComponentFormat):
2750
2949
"""An encapsulation of the initialization and open routines for a format.
2752
2951
Formats provide three things:
3054
@symbol_versioning.deprecated_method(
3055
symbol_versioning.deprecated_in((2, 4, 0)))
2827
3056
def register_format(klass, format):
2828
klass._formats[format.get_format_string()] = format
3057
format_registry.register(format)
3060
@symbol_versioning.deprecated_method(
3061
symbol_versioning.deprecated_in((2, 4, 0)))
3062
def register_extra_format(klass, format):
3063
format_registry.register_extra(format)
3066
@symbol_versioning.deprecated_method(
3067
symbol_versioning.deprecated_in((2, 4, 0)))
3068
def unregister_extra_format(klass, format):
3069
format_registry.unregister_extra(format)
3072
@symbol_versioning.deprecated_method(
3073
symbol_versioning.deprecated_in((2, 4, 0)))
3074
def get_formats(klass):
3075
return format_registry._get_all()
3078
@symbol_versioning.deprecated_method(
3079
symbol_versioning.deprecated_in((2, 4, 0)))
2831
3080
def set_default_format(klass, format):
2832
klass._default_format = format
3081
format_registry.set_default(format)
3084
@symbol_versioning.deprecated_method(
3085
symbol_versioning.deprecated_in((2, 4, 0)))
2835
3086
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(),
3087
format_registry.remove(format)
3090
format_registry.register_lazy("Bazaar Working Tree Format 4 (bzr 0.15)\n",
3091
"bzrlib.workingtree_4", "WorkingTreeFormat4")
3092
format_registry.register_lazy("Bazaar Working Tree Format 5 (bzr 1.11)\n",
3093
"bzrlib.workingtree_4", "WorkingTreeFormat5")
3094
format_registry.register_lazy("Bazaar Working Tree Format 6 (bzr 1.14)\n",
3095
"bzrlib.workingtree_4", "WorkingTreeFormat6")
3096
format_registry.register_lazy("Bazaar-NG Working Tree format 3",
3097
"bzrlib.workingtree_3", "WorkingTreeFormat3")
3098
format_registry.set_default_key("Bazaar Working Tree Format 6 (bzr 1.14)\n")