132
132
self._format = _format
133
133
self.bzrdir = _bzrdir
134
assert isinstance(basedir, basestring), \
135
"base directory %r is not a string" % basedir
136
134
basedir = safe_unicode(basedir)
137
135
mutter("opening working tree %r", basedir)
138
136
self._branch = branch
139
assert isinstance(self.branch, bzrlib.branch.Branch), \
140
"branch %r is not a Branch" % self.branch
141
137
self.basedir = realpath(basedir)
142
138
# if branch is at our basedir and is a format 6 or less
143
139
# assume all other formats have their own control files.
144
assert isinstance(_control_files, LockableFiles), \
145
"_control_files must be a LockableFiles, not %r" % _control_files
146
140
self._control_files = _control_files
141
self._transport = self._control_files._transport
147
142
self._dirty = None
149
144
# during a read or write lock these objects are set, and are
317
312
state._read_dirblocks_if_needed()
318
313
root_key, current_entry = self._get_entry(path='')
319
314
current_id = root_key[2]
320
assert current_entry[0][0] == 'd' # directory
315
if not (current_entry[0][0] == 'd'): # directory
316
raise AssertionError(current_entry)
321
317
inv = Inventory(root_id=current_id)
322
318
# Turn some things into local variables
323
319
minikind_to_kind = dirstate.DirState._minikind_to_kind
356
352
# add this entry to the parent map.
357
353
parent_ies[(dirname + '/' + name).strip('/')] = inv_entry
358
354
elif kind == 'tree-reference':
359
assert self._repo_supports_tree_reference, \
360
"repository of %r " \
361
"doesn't support tree references " \
362
"required by entry %r" \
355
if not self._repo_supports_tree_reference:
356
raise AssertionError(
358
"doesn't support tree references "
359
"required by entry %r"
364
361
inv_entry.reference_revision = link_or_sha1 or None
365
362
elif kind != 'symlink':
366
363
raise AssertionError("unknown kind %r" % kind)
367
364
# These checks cost us around 40ms on a 55k entry tree
368
assert file_id not in inv_byid, ('file_id %s already in'
369
' inventory as %s' % (file_id, inv_byid[file_id]))
370
assert name_unicode not in parent_ie.children
365
if file_id in inv_byid:
366
raise AssertionError('file_id %s already in'
367
' inventory as %s' % (file_id, inv_byid[file_id]))
368
if name_unicode in parent_ie.children:
369
raise AssertionError('name %r already in parent'
371
371
inv_byid[file_id] = inv_entry
372
372
parent_ie.children[name_unicode] = inv_entry
373
373
self._inventory = inv
552
552
Note: The caller is expected to take a read-lock before calling this.
554
554
relpath = self.id2path(file_id)
555
assert relpath != None, \
556
"path for id {%s} is None!" % file_id
556
raise AssertionError(
557
"path for id {%s} is None!" % file_id)
557
558
return self._kind(relpath)
559
560
def _kind(self, relpath):
632
633
if not from_paths:
635
635
state = self.current_dirstate()
637
assert not isinstance(from_paths, basestring)
636
if isinstance(from_paths, basestring):
638
638
to_dir_utf8 = to_dir.encode('utf8')
639
639
to_entry_dirname, to_basename = os.path.split(to_dir_utf8)
640
640
id_index = state._get_id_index()
795
795
if minikind == 'd':
796
796
def update_dirblock(from_dir, to_key, to_dir_utf8):
797
797
"""Recursively update all entries in this dirblock."""
798
assert from_dir != '', "renaming root not supported"
799
raise AssertionError("renaming root not supported")
799
800
from_key = (from_dir, '')
800
801
from_block_idx, present = \
801
802
state._find_block_index_from_key(from_key)
815
816
# Grab a copy since move_one may update the list.
816
817
for entry in from_block[1][:]:
817
assert entry[0][0] == from_dir
818
if not (entry[0][0] == from_dir):
819
raise AssertionError()
818
820
cur_details = entry[1][0]
819
821
to_key = (to_dir_utf8, entry[0][1], entry[0][2])
820
822
from_path_utf8 = osutils.pathjoin(entry[0][0], entry[0][1])
1033
1035
"""Change the last revision in the working tree."""
1034
1036
parents = self.get_parent_ids()
1035
1037
if new_revision in (NULL_REVISION, None):
1036
assert len(parents) < 2, (
1037
"setting the last parent to none with a pending merge is "
1038
if len(parents) >= 2:
1039
raise AssertionError(
1040
"setting the last parent to none with a pending merge is "
1039
1042
self.set_parent_ids([])
1041
1044
self.set_parent_ids([new_revision] + parents[1:],
1082
1085
raise errors.GhostRevisionUnusableHere(parents_list[0][0])
1083
1086
real_trees = []
1089
parent_ids = [rev_id for rev_id, tree in parents_list]
1090
graph = self.branch.repository.get_graph()
1091
heads = graph.heads(parent_ids)
1092
accepted_revisions = set()
1085
1094
# convert absent trees to the null tree, which we convert back to
1086
1095
# missing on access.
1087
1096
for rev_id, tree in parents_list:
1097
if len(accepted_revisions) > 0:
1098
# we always accept the first tree
1099
if rev_id in accepted_revisions or rev_id not in heads:
1100
# We have already included either this tree, or its
1101
# descendent, so we skip it.
1088
1103
_mod_revision.check_not_reserved_id(rev_id)
1089
1104
if tree is not None:
1090
1105
real_trees.append((rev_id, tree))
1092
1107
real_trees.append((rev_id,
1093
1108
self.branch.repository.revision_tree(None)))
1094
1109
ghosts.append(rev_id)
1110
accepted_revisions.add(rev_id)
1095
1111
dirstate.set_parent_trees(real_trees, ghosts=ghosts)
1096
1112
self._make_dirty(reset_inventory=False)
1241
1257
def update_basis_by_delta(self, new_revid, delta):
1242
1258
"""See MutableTree.update_basis_by_delta."""
1243
assert self.last_revision() != new_revid
1259
if self.last_revision() == new_revid:
1260
raise AssertionError()
1244
1261
self.current_dirstate().update_basis_by_delta(delta, new_revid)
1246
1263
@needs_read_lock
1250
1267
@needs_tree_write_lock
1251
1268
def _write_inventory(self, inv):
1252
1269
"""Write inventory as the current inventory."""
1253
assert not self._dirty, ("attempting to write an inventory when the "
1254
"dirstate is dirty will cause data loss")
1271
raise AssertionError("attempting to write an inventory when the "
1272
"dirstate is dirty will lose pending changes")
1255
1273
self.current_dirstate().set_state_from_inventory(inv)
1256
1274
self._make_dirty(reset_inventory=False)
1257
1275
if self._inventory is not None:
1303
1321
control_files = self._open_control_files(a_bzrdir)
1304
1322
control_files.create_lock()
1305
1323
control_files.lock_write()
1306
control_files.put_utf8('format', self.get_format_string())
1324
transport.put_bytes('format', self.get_format_string(),
1325
mode=a_bzrdir._get_file_mode())
1307
1326
if from_branch is not None:
1308
1327
branch = from_branch
1354
1373
if basis_root_id is not None:
1355
1374
wt._set_root_id(basis_root_id)
1376
# delta_from_tree is safe even for DirStateRevisionTrees,
1377
# because wt4.apply_inventory_delta does not mutate the input
1378
# inventory entries.
1357
1379
transform.build_tree(basis, wt, accelerator_tree,
1380
hardlink=hardlink, delta_from_tree=True)
1402
1424
default_revision=_mod_revision.CURRENT_REVISION):
1403
1425
"""See Tree.annotate_iter"""
1404
1426
w = self._get_weave(file_id)
1405
return w.annotate_iter(self.inventory[file_id].revision)
1427
return w.annotate(self.inventory[file_id].revision)
1407
1429
def _get_ancestors(self, default_revision):
1408
1430
return set(self._repository.get_ancestry(self._revision_id,
1468
1490
This is relatively expensive: we have to walk the entire dirstate.
1470
assert self._locked, 'cannot generate inventory of an unlocked '\
1471
'dirstate revision tree'
1492
if not self._locked:
1493
raise AssertionError(
1494
'cannot generate inventory of an unlocked '
1495
'dirstate revision tree')
1472
1496
# separate call for profiling - makes it clear where the costs are.
1473
1497
self._dirstate._read_dirblocks_if_needed()
1474
assert self._revision_id in self._dirstate.get_parent_ids(), \
1475
'parent %s has disappeared from %s' % (
1476
self._revision_id, self._dirstate.get_parent_ids())
1498
if self._revision_id not in self._dirstate.get_parent_ids():
1499
raise AssertionError(
1500
'parent %s has disappeared from %s' % (
1501
self._revision_id, self._dirstate.get_parent_ids()))
1477
1502
parent_index = self._dirstate.get_parent_ids().index(self._revision_id) + 1
1478
1503
# This is identical now to the WorkingTree _generate_inventory except
1479
1504
# for the tree index use.
1480
1505
root_key, current_entry = self._dirstate._get_entry(parent_index, path_utf8='')
1481
1506
current_id = root_key[2]
1482
assert current_entry[parent_index][0] == 'd'
1507
if current_entry[parent_index][0] != 'd':
1508
raise AssertionError()
1483
1509
inv = Inventory(root_id=current_id, revision_id=self._revision_id)
1484
1510
inv.root.revision = current_entry[parent_index][4]
1485
1511
# Turn some things into local variables
1525
1551
raise AssertionError("cannot convert entry %r into an InventoryEntry"
1527
1553
# These checks cost us around 40ms on a 55k entry tree
1528
assert file_id not in inv_byid
1529
assert name_unicode not in parent_ie.children
1554
if file_id in inv_byid:
1555
raise AssertionError('file_id %s already in'
1556
' inventory as %s' % (file_id, inv_byid[file_id]))
1557
if name_unicode in parent_ie.children:
1558
raise AssertionError('name %r already in parent'
1530
1560
inv_byid[file_id] = inv_entry
1531
1561
parent_ie.children[name_unicode] = inv_entry
1532
1562
self._inventory = inv
1552
1582
return parent_details[1]
1555
@symbol_versioning.deprecated_method(symbol_versioning.zero_ninety)
1556
def get_weave(self, file_id):
1557
return self._get_weave(file_id)
1559
1585
def _get_weave(self, file_id):
1560
1586
return self._repository.weave_store.get_weave(file_id,
1561
1587
self._repository.get_transaction())
1566
1592
def get_file_lines(self, file_id):
1567
1593
entry = self._get_entry(file_id=file_id)[1]
1569
1595
raise errors.NoSuchId(tree=self, file_id=file_id)
1570
1596
return self._get_weave(file_id).get_lines(entry[1][4])
1572
1598
def get_file_size(self, file_id):
1599
"""See Tree.get_file_size"""
1573
1600
return self.inventory[file_id].text_size
1575
1602
def get_file_text(self, file_id):
1760
1787
_matching_to_tree_format = WorkingTreeFormat4()
1761
1788
_test_mutable_trees_to_test_trees = make_source_parent_tree
1763
def _iter_changes(self, include_unchanged=False,
1790
def iter_changes(self, include_unchanged=False,
1764
1791
specific_files=None, pb=None, extra_trees=[],
1765
1792
require_versioned=True, want_unversioned=False):
1766
1793
"""Return the changes from source to target.
1768
:return: An iterator that yields tuples. See InterTree._iter_changes
1795
:return: An iterator that yields tuples. See InterTree.iter_changes
1770
1797
:param specific_files: An optional list of file paths to restrict the
1771
1798
comparison to. When mapping filenames to ids, all matches in all
1790
1817
# TODO: handle extra trees in the dirstate.
1791
1818
if (extra_trees or specific_files == []):
1792
1819
# we can't fast-path these cases (yet)
1793
for f in super(InterDirStateTree, self)._iter_changes(
1820
for f in super(InterDirStateTree, self).iter_changes(
1794
1821
include_unchanged, specific_files, pb, extra_trees,
1795
1822
require_versioned, want_unversioned=want_unversioned):
1798
1825
parent_ids = self.target.get_parent_ids()
1799
assert (self.source._revision_id in parent_ids
1800
or self.source._revision_id == NULL_REVISION), \
1801
"revision {%s} is not stored in {%s}, but %s " \
1802
"can only be used for trees stored in the dirstate" \
1803
% (self.source._revision_id, self.target, self._iter_changes)
1826
if not (self.source._revision_id in parent_ids
1827
or self.source._revision_id == NULL_REVISION):
1828
raise AssertionError(
1829
"revision {%s} is not stored in {%s}, but %s "
1830
"can only be used for trees stored in the dirstate"
1831
% (self.source._revision_id, self.target, self.iter_changes))
1804
1832
target_index = 0
1805
1833
if self.source._revision_id == NULL_REVISION:
1806
1834
source_index = None
1807
1835
indices = (target_index,)
1809
assert (self.source._revision_id in parent_ids), \
1810
"Failure: source._revision_id: %s not in target.parent_ids(%s)" % (
1811
self.source._revision_id, parent_ids)
1837
if not (self.source._revision_id in parent_ids):
1838
raise AssertionError(
1839
"Failure: source._revision_id: %s not in target.parent_ids(%s)" % (
1840
self.source._revision_id, parent_ids))
1812
1841
source_index = 1 + parent_ids.index(self.source._revision_id)
1813
1842
indices = (source_index, target_index)
1814
1843
# -- make all specific_files utf8 --
1952
1981
target_details = entry[1][target_index]
1953
1982
target_minikind = target_details[0]
1954
1983
if path_info is not None and target_minikind in 'fdlt':
1955
assert target_index == 0
1984
if not (target_index == 0):
1985
raise AssertionError()
1956
1986
link_or_sha1 = state.update_entry(entry, abspath=path_info[4],
1957
1987
stat_value=path_info[3])
1958
1988
# The entry may have been modified by update_entry
2071
2101
# parent entry will be the same as the source entry.
2072
2102
target_parent_entry = state._get_entry(target_index,
2073
2103
path_utf8=new_dirname)
2074
assert target_parent_entry != (None, None), (
2075
"Could not find target parent in wt: %s\nparent of: %s"
2076
% (new_dirname, entry))
2104
if target_parent_entry == (None, None):
2105
raise AssertionError(
2106
"Could not find target parent in wt: %s\nparent of: %s"
2107
% (new_dirname, entry))
2077
2108
target_parent_id = target_parent_entry[0][2]
2078
2109
if target_parent_id == entry[0][2]:
2079
2110
# This is the root, so the parent is None
2262
2293
if current_dir_info[0][0] == '':
2263
2294
# remove .bzr from iteration
2264
2295
bzr_index = bisect_left(current_dir_info[1], ('.bzr',))
2265
assert current_dir_info[1][bzr_index][0] == '.bzr'
2296
if current_dir_info[1][bzr_index][0] != '.bzr':
2297
raise AssertionError()
2266
2298
del current_dir_info[1][bzr_index]
2267
2299
# walk until both the directory listing and the versioned metadata
2268
2300
# are exhausted.
2520
2552
def update_format(self, tree):
2521
2553
"""Change the format marker."""
2522
tree._control_files.put_utf8('format',
2523
self.target_format.get_format_string())
2554
tree._transport.put_bytes('format',
2555
self.target_format.get_format_string(),
2556
mode=tree.bzrdir._get_file_mode())