29
29
from bzrlib.lazy_import import lazy_import
30
30
lazy_import(globals(), """
31
from bisect import bisect_left
33
from copy import deepcopy
34
42
from bzrlib import (
38
45
conflicts as _mod_conflicts,
42
filters as _mod_filters,
45
55
revision as _mod_revision,
66
from bzrlib.transport import get_transport
70
from bzrlib import symbol_versioning
53
71
from bzrlib.decorators import needs_read_lock, needs_write_lock
54
from bzrlib.inventory import Inventory, ROOT_ID, entry_factory
55
from bzrlib.lock import LogicalLockResult
56
from bzrlib.lockable_files import LockableFiles
57
from bzrlib.lockdir import LockDir
72
from bzrlib.filters import filtered_input_file, internal_size_sha_file_byname
73
from bzrlib.inventory import InventoryEntry, Inventory, ROOT_ID, entry_factory
74
import bzrlib.mutabletree
58
75
from bzrlib.mutabletree import needs_tree_write_lock
59
76
from bzrlib.osutils import (
86
from bzrlib.trace import mutter, note
66
87
from bzrlib.transport.local import LocalTransport
67
from bzrlib.tree import (
71
from bzrlib.workingtree import (
78
class DirStateWorkingTree(InventoryWorkingTree):
88
from bzrlib.tree import InterTree
89
from bzrlib.progress import DummyProgress, ProgressPhase
90
from bzrlib.revision import NULL_REVISION, CURRENT_REVISION
91
from bzrlib.rio import RioReader, rio_file, Stanza
92
from bzrlib.symbol_versioning import (deprecated_passed,
97
from bzrlib.tree import Tree
98
from bzrlib.workingtree import WorkingTree, WorkingTree3, WorkingTreeFormat3
101
class DirStateWorkingTree(WorkingTree3):
80
102
def __init__(self, basedir,
82
104
_control_files=None,
132
154
state.add(f, file_id, kind, None, '')
133
155
self._make_dirty(reset_inventory=True)
135
def _get_check_refs(self):
136
"""Return the references needed to perform a check of this tree."""
137
return [('trees', self.last_revision())]
139
157
def _make_dirty(self, reset_inventory):
140
158
"""Make the tree state dirty.
194
212
def _comparison_data(self, entry, path):
195
213
kind, executable, stat_value = \
196
WorkingTree._comparison_data(self, entry, path)
214
WorkingTree3._comparison_data(self, entry, path)
197
215
# it looks like a plain directory, but it's really a reference -- see
199
217
if (self._repo_supports_tree_reference and kind == 'directory'
205
223
def commit(self, message=None, revprops=None, *args, **kwargs):
206
224
# mark the tree as dirty post commit - commit
207
225
# can change the current versioned list by doing deletes.
208
result = WorkingTree.commit(self, message, revprops, *args, **kwargs)
226
result = WorkingTree3.commit(self, message, revprops, *args, **kwargs)
209
227
self._make_dirty(reset_inventory=True)
248
def _worth_saving_limit(self):
249
"""How many hash changes are ok before we must save the dirstate.
251
:return: an integer. -1 means never save.
253
# FIXME: We want a WorkingTreeStack here -- vila 20110812
254
conf = config.BranchStack(self.branch)
255
return conf.get('bzr.workingtree.worth_saving_limit')
257
266
def filter_unversioned_files(self, paths):
258
267
"""Filter out paths that are versioned.
342
351
parent_ies[(dirname + '/' + name).strip('/')] = inv_entry
343
352
elif kind == 'tree-reference':
344
353
if not self._repo_supports_tree_reference:
345
raise errors.UnsupportedOperation(
346
self._generate_inventory,
347
self.branch.repository)
354
raise AssertionError(
356
"doesn't support tree references "
357
"required by entry %r"
348
359
inv_entry.reference_revision = link_or_sha1 or None
349
360
elif kind != 'symlink':
350
361
raise AssertionError("unknown kind %r" % kind)
455
466
return osutils.lexists(pathjoin(
456
467
self.basedir, row[0].decode('utf8'), row[1].decode('utf8')))
458
def has_or_had_id(self, file_id):
459
state = self.current_dirstate()
460
row, parents = self._get_entry(file_id=file_id)
461
return row is not None
464
470
def id2path(self, file_id):
465
471
"Convert a file-id to a path."
632
634
self.branch.unlock()
634
return LogicalLockResult(self.unlock)
636
637
def lock_tree_write(self):
637
"""See MutableTree.lock_tree_write, and WorkingTree.unlock.
639
:return: A bzrlib.lock.LogicalLockResult.
638
"""See MutableTree.lock_tree_write, and WorkingTree.unlock."""
641
639
self.branch.lock_read()
642
return self._lock_self_write()
640
self._lock_self_write()
644
642
def lock_write(self):
645
"""See MutableTree.lock_write, and WorkingTree.unlock.
647
:return: A bzrlib.lock.LogicalLockResult.
643
"""See MutableTree.lock_write, and WorkingTree.unlock."""
649
644
self.branch.lock_write()
650
return self._lock_self_write()
645
self._lock_self_write()
652
647
@needs_tree_write_lock
653
648
def move(self, from_paths, to_dir, after=False):
723
718
from_entry = self._get_entry(path=from_rel)
724
719
if from_entry == (None, None):
725
720
raise errors.BzrMoveFailedError(from_rel,to_dir,
726
errors.NotVersionedError(path=from_rel))
721
errors.NotVersionedError(path=str(from_rel)))
728
723
from_id = from_entry[0][2]
729
724
to_rel = pathjoin(to_dir, from_tail)
1058
1053
def set_last_revision(self, new_revision):
1059
1054
"""Change the last revision in the working tree."""
1060
1055
parents = self.get_parent_ids()
1061
if new_revision in (_mod_revision.NULL_REVISION, None):
1056
if new_revision in (NULL_REVISION, None):
1062
1057
if len(parents) >= 2:
1063
1058
raise AssertionError(
1064
1059
"setting the last parent to none with a pending merge is "
1133
1128
_mod_revision.NULL_REVISION)))
1134
1129
ghosts.append(rev_id)
1135
1130
accepted_revisions.add(rev_id)
1137
if (len(real_trees) == 1
1139
and self.branch.repository._format.fast_deltas
1140
and isinstance(real_trees[0][1],
1141
revisiontree.InventoryRevisionTree)
1142
and self.get_parent_ids()):
1143
rev_id, rev_tree = real_trees[0]
1144
basis_id = self.get_parent_ids()[0]
1145
# There are times when basis_tree won't be in
1146
# self.branch.repository, (switch, for example)
1148
basis_tree = self.branch.repository.revision_tree(basis_id)
1149
except errors.NoSuchRevision:
1150
# Fall back to the set_parent_trees(), since we can't use
1151
# _make_delta if we can't get the RevisionTree
1154
delta = rev_tree.inventory._make_delta(basis_tree.inventory)
1155
dirstate.update_basis_by_delta(delta, rev_id)
1158
dirstate.set_parent_trees(real_trees, ghosts=ghosts)
1131
dirstate.set_parent_trees(real_trees, ghosts=ghosts)
1159
1132
self._make_dirty(reset_inventory=False)
1161
1134
def _set_root_id(self, file_id):
1253
1226
# just forget the whole block.
1254
1227
entry_index = 0
1255
1228
while entry_index < len(block[1]):
1229
# Mark this file id as having been removed
1256
1230
entry = block[1][entry_index]
1257
if entry[1][0][0] in 'ar':
1258
# don't remove absent or renamed entries
1231
ids_to_unversion.discard(entry[0][2])
1232
if (entry[1][0][0] in 'ar' # don't remove absent or renamed
1234
or not state._make_absent(entry)):
1259
1235
entry_index += 1
1261
# Mark this file id as having been removed
1262
ids_to_unversion.discard(entry[0][2])
1263
if not state._make_absent(entry):
1264
# The block has not shrunk.
1266
1236
# go to the next block. (At the moment we dont delete empty
1268
1238
block_index += 1
1289
1259
# have to change the legacy inventory too.
1290
1260
if self._inventory is not None:
1291
1261
for file_id in file_ids:
1292
if self._inventory.has_id(file_id):
1293
self._inventory.remove_recursive_id(file_id)
1262
self._inventory.remove_recursive_id(file_id)
1295
1264
@needs_tree_write_lock
1296
1265
def rename_one(self, from_rel, to_rel, after=False):
1297
1266
"""See WorkingTree.rename_one"""
1299
super(DirStateWorkingTree, self).rename_one(from_rel, to_rel, after)
1268
WorkingTree.rename_one(self, from_rel, to_rel, after)
1301
1270
@needs_tree_write_lock
1302
1271
def apply_inventory_delta(self, changes):
1321
1290
if self._dirty:
1322
1291
raise AssertionError("attempting to write an inventory when the "
1323
1292
"dirstate is dirty will lose pending changes")
1324
had_inventory = self._inventory is not None
1325
# Setting self._inventory = None forces the dirstate to regenerate the
1326
# working inventory. We do this because self.inventory may be inv, or
1327
# may have been modified, and either case would prevent a clean delta
1329
self._inventory = None
1331
delta = inv._make_delta(self.inventory)
1333
self.apply_inventory_delta(delta)
1293
self.current_dirstate().set_state_from_inventory(inv)
1294
self._make_dirty(reset_inventory=False)
1295
if self._inventory is not None:
1335
1296
self._inventory = inv
1338
@needs_tree_write_lock
1339
def reset_state(self, revision_ids=None):
1340
"""Reset the state of the working tree.
1342
This does a hard-reset to a last-known-good state. This is a way to
1343
fix if something got corrupted (like the .bzr/checkout/dirstate file)
1345
if revision_ids is None:
1346
revision_ids = self.get_parent_ids()
1347
if not revision_ids:
1348
base_tree = self.branch.repository.revision_tree(
1349
_mod_revision.NULL_REVISION)
1352
trees = zip(revision_ids,
1353
self.branch.repository.revision_trees(revision_ids))
1354
base_tree = trees[0][1]
1355
state = self.current_dirstate()
1356
# We don't support ghosts yet
1357
state.set_state_from_scratch(base_tree.inventory, trees, [])
1360
1300
class ContentFilterAwareSHA1Provider(dirstate.SHA1Provider):
1363
1303
self.tree = tree
1365
1305
def sha1(self, abspath):
1366
"""See dirstate.SHA1Provider.sha1()."""
1367
filters = self.tree._content_filter_stack(
1368
self.tree.relpath(osutils.safe_unicode(abspath)))
1369
return _mod_filters.internal_size_sha_file_byname(abspath, filters)[1]
1306
"""Return the sha1 of a file given its absolute path."""
1307
filters = self.tree._content_filter_stack(self.tree.relpath(abspath))
1308
return internal_size_sha_file_byname(abspath, filters)[1]
1371
1310
def stat_and_sha1(self, abspath):
1372
"""See dirstate.SHA1Provider.stat_and_sha1()."""
1373
filters = self.tree._content_filter_stack(
1374
self.tree.relpath(osutils.safe_unicode(abspath)))
1311
"""Return the stat and sha1 of a file given its absolute path."""
1312
filters = self.tree._content_filter_stack(self.tree.relpath(abspath))
1375
1313
file_obj = file(abspath, 'rb', 65000)
1377
1315
statvalue = os.fstat(file_obj.fileno())
1379
file_obj = _mod_filters.filtered_input_file(file_obj, filters)
1317
file_obj = filtered_input_file(file_obj, filters)
1380
1318
sha1 = osutils.size_sha_file(file_obj)[1]
1382
1320
file_obj.close()
1383
1321
return statvalue, sha1
1386
class ContentFilteringDirStateWorkingTree(DirStateWorkingTree):
1387
"""Dirstate working tree that supports content filtering.
1389
The dirstate holds the hash and size of the canonical form of the file,
1390
and most methods must return that.
1393
def _file_content_summary(self, path, stat_result):
1394
# This is to support the somewhat obsolete path_content_summary method
1395
# with content filtering: see
1396
# <https://bugs.launchpad.net/bzr/+bug/415508>.
1398
# If the dirstate cache is up to date and knows the hash and size,
1400
# Otherwise if there are no content filters, return the on-disk size
1401
# and leave the hash blank.
1402
# Otherwise, read and filter the on-disk file and use its size and
1405
# The dirstate doesn't store the size of the canonical form so we
1406
# can't trust it for content-filtered trees. We just return None.
1407
dirstate_sha1 = self._dirstate.sha1_from_stat(path, stat_result)
1408
executable = self._is_executable_from_path_and_stat(path, stat_result)
1409
return ('file', None, executable, dirstate_sha1)
1412
1324
class WorkingTree4(DirStateWorkingTree):
1413
1325
"""This is the Format 4 working tree.
1415
This differs from WorkingTree by:
1327
This differs from WorkingTree3 by:
1416
1328
- Having a consolidated internal dirstate, stored in a
1417
1329
randomly-accessible sorted file on disk.
1418
1330
- Not having a regular inventory attribute. One can be synthesized
1425
class WorkingTree5(ContentFilteringDirStateWorkingTree):
1337
class WorkingTree5(DirStateWorkingTree):
1426
1338
"""This is the Format 5 working tree.
1428
1340
This differs from WorkingTree4 by:
1429
1341
- Supporting content filtering.
1431
This is new in bzr 1.11.
1435
class WorkingTree6(ContentFilteringDirStateWorkingTree):
1436
"""This is the Format 6 working tree.
1438
This differs from WorkingTree5 by:
1439
1342
- Supporting a current view that may mask the set of files in a tree
1440
1343
impacted by most user operations.
1442
This is new in bzr 1.14.
1345
This is new in bzr 1.11.
1445
1348
def _make_views(self):
1446
1349
return views.PathBasedViews(self)
1449
class DirStateWorkingTreeFormat(WorkingTreeFormat):
1451
missing_parent_conflicts = True
1453
supports_versioned_directories = True
1455
_lock_class = LockDir
1456
_lock_file_name = 'lock'
1458
def _open_control_files(self, a_bzrdir):
1459
transport = a_bzrdir.get_workingtree_transport(None)
1460
return LockableFiles(transport, self._lock_file_name,
1352
class DirStateWorkingTreeFormat(WorkingTreeFormat3):
1463
1353
def initialize(self, a_bzrdir, revision_id=None, from_branch=None,
1464
1354
accelerator_tree=None, hardlink=False):
1465
1355
"""See WorkingTreeFormat.initialize().
1467
1357
:param revision_id: allows creating a working tree at a different
1468
revision than the branch is at.
1358
revision than the branch is at.
1469
1359
:param accelerator_tree: A tree which can be used for retrieving file
1470
1360
contents more quickly than the revision tree, i.e. a workingtree.
1471
1361
The revision tree will be used for cases where accelerator_tree's
1535
1425
if basis_root_id is not None:
1536
1426
wt._set_root_id(basis_root_id)
1538
if wt.supports_content_filtering():
1539
# The original tree may not have the same content filters
1540
# applied so we can't safely build the inventory delta from
1542
delta_from_tree = False
1544
delta_from_tree = True
1545
1428
# delta_from_tree is safe even for DirStateRevisionTrees,
1546
1429
# because wt4.apply_inventory_delta does not mutate the input
1547
1430
# inventory entries.
1548
1431
transform.build_tree(basis, wt, accelerator_tree,
1550
delta_from_tree=delta_from_tree)
1432
hardlink=hardlink, delta_from_tree=True)
1564
1446
:param wt: the WorkingTree object
1567
def open(self, a_bzrdir, _found=False):
1568
"""Return the WorkingTree object for a_bzrdir
1570
_found is a private parameter, do not use it. It is used to indicate
1571
if format probing has already been done.
1574
# we are being called directly and must probe.
1575
raise NotImplementedError
1576
if not isinstance(a_bzrdir.transport, LocalTransport):
1577
raise errors.NotLocalUrl(a_bzrdir.transport.base)
1578
wt = self._open(a_bzrdir, self._open_control_files(a_bzrdir))
1581
1449
def _open(self, a_bzrdir, control_files):
1582
1450
"""Open the tree itself.
1643
1507
"""See WorkingTreeFormat.get_format_description()."""
1644
1508
return "Working tree format 5"
1646
def supports_content_filtering(self):
1650
class WorkingTreeFormat6(DirStateWorkingTreeFormat):
1651
"""WorkingTree format supporting views.
1654
upgrade_recommended = False
1656
_tree_class = WorkingTree6
1658
def get_format_string(self):
1659
"""See WorkingTreeFormat.get_format_string()."""
1660
return "Bazaar Working Tree Format 6 (bzr 1.14)\n"
1662
def get_format_description(self):
1663
"""See WorkingTreeFormat.get_format_description()."""
1664
return "Working tree format 6"
1666
1510
def _init_custom_control_files(self, wt):
1667
1511
"""Subclasses with custom control files should override this method."""
1668
1512
wt._transport.put_bytes('views', '', mode=wt.bzrdir._get_file_mode())
1677
class DirStateRevisionTree(InventoryTree):
1678
"""A revision tree pulling the inventory from a dirstate.
1680
Note that this is one of the historical (ie revision) trees cached in the
1681
dirstate for easy access, not the workingtree.
1521
class DirStateRevisionTree(Tree):
1522
"""A revision tree pulling the inventory from a dirstate."""
1684
1524
def __init__(self, dirstate, revision_id, repository):
1685
1525
self._dirstate = dirstate
1699
1539
def annotate_iter(self, file_id,
1700
1540
default_revision=_mod_revision.CURRENT_REVISION):
1701
1541
"""See Tree.annotate_iter"""
1702
text_key = (file_id, self.get_file_revision(file_id))
1542
text_key = (file_id, self.inventory[file_id].revision)
1703
1543
annotations = self._repository.texts.annotate(text_key)
1704
1544
return [(key[-1], line) for (key, line) in annotations]
1546
def _get_ancestors(self, default_revision):
1547
return set(self._repository.get_ancestry(self._revision_id,
1706
1549
def _comparison_data(self, entry, path):
1707
1550
"""See Tree._comparison_data."""
1708
1551
if entry is None:
1853
1698
parent_index = self._get_parent_index()
1854
1699
last_changed_revision = entry[1][parent_index][4]
1856
rev = self._repository.get_revision(last_changed_revision)
1857
except errors.NoSuchRevision:
1858
raise errors.FileTimestampUnavailable(self.id2path(file_id))
1859
return rev.timestamp
1700
return self._repository.get_revision(last_changed_revision).timestamp
1861
1702
def get_file_sha1(self, file_id, path=None, stat_value=None):
1862
1703
entry = self._get_entry(file_id=file_id, path=path)
1899
1736
return self._repository.iter_files_bytes(repo_desired_files)
1901
def get_symlink_target(self, file_id, path=None):
1738
def get_symlink_target(self, file_id):
1902
1739
entry = self._get_entry(file_id=file_id)
1903
1740
parent_index = self._get_parent_index()
1904
1741
if entry[1][parent_index][0] != 'l':
1907
target = entry[1][parent_index][1]
1908
target = target.decode('utf8')
1744
# At present, none of the tree implementations supports non-ascii
1745
# symlink targets. So we will just assume that the dirstate path is
1747
return entry[1][parent_index][1]
1911
1749
def get_revision_id(self):
1912
1750
"""Return the revision id for this tree."""
1933
1771
entry = self._get_entry(file_id=file_id)[1]
1934
1772
if entry is None:
1935
1773
raise errors.NoSuchId(tree=self, file_id=file_id)
1936
parent_index = self._get_parent_index()
1937
return dirstate.DirState._minikind_to_kind[entry[parent_index][0]]
1774
return dirstate.DirState._minikind_to_kind[entry[1][0]]
1939
1776
def stored_kind(self, file_id):
1940
1777
"""See Tree.stored_kind"""
1957
1794
def is_executable(self, file_id, path=None):
1958
1795
ie = self.inventory[file_id]
1959
1796
if ie.kind != "file":
1961
1798
return ie.executable
1963
def is_locked(self):
1966
def list_files(self, include_root=False, from_dir=None, recursive=True):
1800
def list_files(self, include_root=False):
1967
1801
# We use a standard implementation, because DirStateRevisionTree is
1968
1802
# dealing with one of the parents of the current state
1969
1803
inv = self._get_inventory()
1970
if from_dir is None:
1973
from_dir_id = inv.path2id(from_dir)
1974
if from_dir_id is None:
1975
# Directory not versioned
1977
entries = inv.iter_entries(from_dir=from_dir_id, recursive=recursive)
1978
if inv.root is not None and not include_root and from_dir is None:
1804
entries = inv.iter_entries()
1805
if self.inventory.root is not None and not include_root:
1980
1807
for path, entry in entries:
1981
1808
yield path, 'V', entry.kind, entry.file_id, entry
1983
1810
def lock_read(self):
1984
"""Lock the tree for a set of operations.
1986
:return: A bzrlib.lock.LogicalLockResult.
1811
"""Lock the tree for a set of operations."""
1988
1812
if not self._locked:
1989
1813
self._repository.lock_read()
1990
1814
if self._dirstate._lock_token is None:
1991
1815
self._dirstate.lock_read()
1992
1816
self._dirstate_locked = True
1993
1817
self._locked += 1
1994
return LogicalLockResult(self.unlock)
1996
1819
def _must_be_locked(self):
1997
1820
if not self._locked:
2076
1899
def make_source_parent_tree(source, target):
2077
1900
"""Change the source tree into a parent of the target."""
2078
1901
revid = source.commit('record tree')
2079
target.branch.fetch(source.branch, revid)
1902
target.branch.repository.fetch(source.branch.repository, revid)
2080
1903
target.set_parent_ids([revid])
2081
1904
return target.basis_tree(), target
2090
def make_source_parent_tree_compiled_dirstate(klass, test_case, source,
1913
def make_source_parent_tree_compiled_dirstate(klass, test_case, source, target):
2092
1914
from bzrlib.tests.test__dirstate_helpers import \
2093
compiled_dirstate_helpers_feature
2094
test_case.requireFeature(compiled_dirstate_helpers_feature)
2095
from bzrlib._dirstate_helpers_pyx import ProcessEntryC
1915
CompiledDirstateHelpersFeature
1916
if not CompiledDirstateHelpersFeature.available():
1917
from bzrlib.tests import UnavailableFeature
1918
raise UnavailableFeature(CompiledDirstateHelpersFeature)
1919
from bzrlib._dirstate_helpers_c import ProcessEntryC
2096
1920
result = klass.make_source_parent_tree(source, target)
2097
1921
result[1]._iter_changes = ProcessEntryC
2136
1962
require_versioned, want_unversioned=want_unversioned)
2137
1963
parent_ids = self.target.get_parent_ids()
2138
1964
if not (self.source._revision_id in parent_ids
2139
or self.source._revision_id == _mod_revision.NULL_REVISION):
1965
or self.source._revision_id == NULL_REVISION):
2140
1966
raise AssertionError(
2141
1967
"revision {%s} is not stored in {%s}, but %s "
2142
1968
"can only be used for trees stored in the dirstate"
2143
1969
% (self.source._revision_id, self.target, self.iter_changes))
2144
1970
target_index = 0
2145
if self.source._revision_id == _mod_revision.NULL_REVISION:
1971
if self.source._revision_id == NULL_REVISION:
2146
1972
source_index = None
2147
1973
indices = (target_index,)
2164
1990
specific_files = set([''])
2165
1991
# -- specific_files is now a utf8 path set --
1992
search_specific_files = set()
2167
1993
# -- get the state object and prepare it.
2168
1994
state = self.target.current_dirstate()
2169
1995
state._read_dirblocks_if_needed()
2170
1996
if require_versioned:
2171
1997
# -- check all supplied paths are versioned in a search tree. --
1998
all_versioned = True
2173
1999
for path in specific_files:
2174
2000
path_entries = state._entries_for_path(path)
2175
2001
if not path_entries:
2176
2002
# this specified path is not present at all: error
2177
not_versioned.append(path)
2003
all_versioned = False
2179
2005
found_versioned = False
2180
2006
# for each id at this path
2181
2007
for entry in path_entries:
2188
2014
if not found_versioned:
2189
2015
# none of the indexes was not 'absent' at all ids for this
2191
not_versioned.append(path)
2192
if len(not_versioned) > 0:
2193
raise errors.PathsNotVersionedError(not_versioned)
2017
all_versioned = False
2019
if not all_versioned:
2020
raise errors.PathsNotVersionedError(specific_files)
2194
2021
# -- remove redundancy in supplied specific_files to prevent over-scanning --
2195
search_specific_files = osutils.minimum_path_selection(specific_files)
2022
for path in specific_files:
2023
other_specific_files = specific_files.difference(set([path]))
2024
if not osutils.is_inside_any(other_specific_files, path):
2025
# this is a top level path, we must check it.
2026
search_specific_files.add(path)
2197
2028
use_filesystem_for_exec = (sys.platform != 'win32')
2198
2029
iter_changes = self.target._iter_changes(include_unchanged,
2210
2041
(revisiontree.RevisionTree, DirStateRevisionTree)):
2212
2043
# the source revid must be in the target dirstate
2213
if not (source._revision_id == _mod_revision.NULL_REVISION or
2044
if not (source._revision_id == NULL_REVISION or
2214
2045
source._revision_id in target.get_parent_ids()):
2215
2046
# TODO: what about ghosts? it may well need to
2216
2047
# check for them explicitly.
2277
2108
# tree during upgrade.
2278
2109
tree._control_files.lock_write()
2280
self.update_format(tree)
2282
tree._control_files.unlock()
2284
def update_format(self, tree):
2285
"""Change the format marker."""
2286
tree._transport.put_bytes('format',
2287
self.target_format.get_format_string(),
2288
mode=tree.bzrdir._get_file_mode())
2291
class Converter4or5to6(object):
2292
"""Perform an in-place upgrade of format 4 or 5 to format 6 trees."""
2295
self.target_format = WorkingTreeFormat6()
2297
def convert(self, tree):
2298
# lock the control files not the tree, so that we don't get tree
2299
# on-unlock behaviours, and so that no-one else diddles with the
2300
# tree during upgrade.
2301
tree._control_files.lock_write()
2303
2111
self.init_custom_control_files(tree)
2304
2112
self.update_format(tree)