1
# Copyright (C) 2005, 2006, 2007, 2008, 2009 Canonical Ltd
1
# Copyright (C) 2007-2012 Canonical Ltd
3
3
# This program is free software; you can redistribute it and/or modify
4
4
# it under the terms of the GNU General Public License as published by
53
56
from bzrlib.decorators import needs_read_lock, needs_write_lock
54
from bzrlib.filters import filtered_input_file, internal_size_sha_file_byname
55
57
from bzrlib.inventory import Inventory, ROOT_ID, entry_factory
56
import bzrlib.mutabletree
57
from bzrlib.mutabletree import needs_tree_write_lock
58
from bzrlib.lock import LogicalLockResult
59
from bzrlib.lockable_files import LockableFiles
60
from bzrlib.lockdir import LockDir
61
from bzrlib.mutabletree import (
63
needs_tree_write_lock,
58
65
from bzrlib.osutils import (
65
from bzrlib.trace import mutter
72
from bzrlib.symbol_versioning import (
66
76
from bzrlib.transport.local import LocalTransport
67
from bzrlib.tree import InterTree
68
from bzrlib.tree import Tree
69
from bzrlib.workingtree import WorkingTree, WorkingTree3, WorkingTreeFormat3
72
class DirStateWorkingTree(WorkingTree3):
77
from bzrlib.tree import (
81
from bzrlib.workingtree import (
84
WorkingTreeFormatMetaDir,
88
class DirStateWorkingTree(InventoryWorkingTree):
73
90
def __init__(self, basedir,
75
92
_control_files=None,
85
102
self._format = _format
86
103
self.bzrdir = _bzrdir
87
104
basedir = safe_unicode(basedir)
88
mutter("opening working tree %r", basedir)
105
trace.mutter("opening working tree %r", basedir)
89
106
self._branch = branch
90
107
self.basedir = realpath(basedir)
91
108
# if branch is at our basedir and is a format 6 or less
125
142
state.add(f, file_id, kind, None, '')
126
143
self._make_dirty(reset_inventory=True)
145
def _get_check_refs(self):
146
"""Return the references needed to perform a check of this tree."""
147
return [('trees', self.last_revision())]
128
149
def _make_dirty(self, reset_inventory):
129
150
"""Make the tree state dirty.
183
204
def _comparison_data(self, entry, path):
184
205
kind, executable, stat_value = \
185
WorkingTree3._comparison_data(self, entry, path)
206
WorkingTree._comparison_data(self, entry, path)
186
207
# it looks like a plain directory, but it's really a reference -- see
188
209
if (self._repo_supports_tree_reference and kind == 'directory'
194
215
def commit(self, message=None, revprops=None, *args, **kwargs):
195
216
# mark the tree as dirty post commit - commit
196
217
# can change the current versioned list by doing deletes.
197
result = WorkingTree3.commit(self, message, revprops, *args, **kwargs)
218
result = WorkingTree.commit(self, message, revprops, *args, **kwargs)
198
219
self._make_dirty(reset_inventory=True)
219
240
local_path = self.bzrdir.get_workingtree_transport(None
220
241
).local_abspath('dirstate')
221
242
self._dirstate = dirstate.DirState.on_file(local_path,
222
self._sha1_provider())
243
self._sha1_provider(), self._worth_saving_limit())
223
244
return self._dirstate
225
246
def _sha1_provider(self):
258
def _worth_saving_limit(self):
259
"""How many hash changes are ok before we must save the dirstate.
261
:return: an integer. -1 means never save.
263
conf = self.get_config_stack()
264
return conf.get('bzr.workingtree.worth_saving_limit')
237
266
def filter_unversioned_files(self, paths):
238
267
"""Filter out paths that are versioned.
401
430
self._generate_inventory()
402
431
return self._inventory
433
@deprecated_method(deprecated_in((2, 5, 0)))
434
def _get_inventory(self):
435
return self.root_inventory
404
437
inventory = property(_get_inventory,
405
438
doc="Inventory of this Tree")
440
root_inventory = property(_get_root_inventory,
441
"Root inventory of this tree")
408
444
def get_parent_ids(self):
409
445
"""See Tree.get_parent_ids.
456
492
return False # Missing entries are not executable
457
493
return entry[1][0][3] # Executable?
459
if not osutils.supports_executable():
460
def is_executable(self, file_id, path=None):
461
"""Test if a file is executable or not.
495
def is_executable(self, file_id, path=None):
496
"""Test if a file is executable or not.
463
Note: The caller is expected to take a read-lock before calling this.
498
Note: The caller is expected to take a read-lock before calling this.
500
if not self._supports_executable():
465
501
entry = self._get_entry(file_id=file_id, path=path)
466
502
if entry == (None, None):
468
504
return entry[1][0][3]
470
_is_executable_from_path_and_stat = \
471
_is_executable_from_path_and_stat_from_basis
473
def is_executable(self, file_id, path=None):
474
"""Test if a file is executable or not.
476
Note: The caller is expected to take a read-lock before calling this.
478
506
self._must_be_locked()
480
508
path = self.id2path(file_id)
481
mode = os.lstat(self.abspath(path)).st_mode
509
mode = osutils.lstat(self.abspath(path)).st_mode
482
510
return bool(stat.S_ISREG(mode) and stat.S_IEXEC & mode)
484
512
def all_file_ids(self):
568
596
return _mod_revision.NULL_REVISION
570
598
def lock_read(self):
571
"""See Branch.lock_read, and WorkingTree.unlock."""
599
"""See Branch.lock_read, and WorkingTree.unlock.
601
:return: A bzrlib.lock.LogicalLockResult.
572
603
self.branch.lock_read()
574
605
self._control_files.lock_read()
608
640
self.branch.unlock()
642
return LogicalLockResult(self.unlock)
611
644
def lock_tree_write(self):
612
"""See MutableTree.lock_tree_write, and WorkingTree.unlock."""
645
"""See MutableTree.lock_tree_write, and WorkingTree.unlock.
647
:return: A bzrlib.lock.LogicalLockResult.
613
649
self.branch.lock_read()
614
self._lock_self_write()
650
return self._lock_self_write()
616
652
def lock_write(self):
617
"""See MutableTree.lock_write, and WorkingTree.unlock."""
653
"""See MutableTree.lock_write, and WorkingTree.unlock.
655
:return: A bzrlib.lock.LogicalLockResult.
618
657
self.branch.lock_write()
619
self._lock_self_write()
658
return self._lock_self_write()
621
660
@needs_tree_write_lock
622
661
def move(self, from_paths, to_dir, after=False):
856
895
def path2id(self, path):
857
896
"""Return the id for path in this tree."""
897
if isinstance(path, list):
900
path = osutils.pathjoin(*path)
858
901
path = path.strip('/')
859
902
entry = self._get_entry(path=path)
860
903
if entry == (None, None):
938
981
all_versioned = False
940
983
if not all_versioned:
941
raise errors.PathsNotVersionedError(paths)
984
raise errors.PathsNotVersionedError(
985
[p.decode('utf-8') for p in paths])
942
986
# -- remove redundancy in supplied paths to prevent over-scanning --
943
987
search_paths = osutils.minimum_path_selection(paths)
993
1037
found_dir_names = set(dir_name_id[:2] for dir_name_id in found)
994
1038
for dir_name in split_paths:
995
1039
if dir_name not in found_dir_names:
996
raise errors.PathsNotVersionedError(paths)
1040
raise errors.PathsNotVersionedError(
1041
[p.decode('utf-8') for p in paths])
998
1043
for dir_name_id, trees_info in found.iteritems():
999
1044
for index in search_indexes:
1102
1147
_mod_revision.NULL_REVISION)))
1103
1148
ghosts.append(rev_id)
1104
1149
accepted_revisions.add(rev_id)
1105
dirstate.set_parent_trees(real_trees, ghosts=ghosts)
1151
if (len(real_trees) == 1
1153
and self.branch.repository._format.fast_deltas
1154
and isinstance(real_trees[0][1],
1155
revisiontree.InventoryRevisionTree)
1156
and self.get_parent_ids()):
1157
rev_id, rev_tree = real_trees[0]
1158
basis_id = self.get_parent_ids()[0]
1159
# There are times when basis_tree won't be in
1160
# self.branch.repository, (switch, for example)
1162
basis_tree = self.branch.repository.revision_tree(basis_id)
1163
except errors.NoSuchRevision:
1164
# Fall back to the set_parent_trees(), since we can't use
1165
# _make_delta if we can't get the RevisionTree
1168
delta = rev_tree.root_inventory._make_delta(
1169
basis_tree.root_inventory)
1170
dirstate.update_basis_by_delta(delta, rev_id)
1173
dirstate.set_parent_trees(real_trees, ghosts=ghosts)
1106
1174
self._make_dirty(reset_inventory=False)
1108
1176
def _set_root_id(self, file_id):
1129
1197
def unlock(self):
1130
1198
"""Unlock in format 4 trees needs to write the entire dirstate."""
1131
# do non-implementation specific cleanup
1134
1199
if self._control_files._lock_count == 1:
1200
# do non-implementation specific cleanup
1135
1203
# eventually we should do signature checking during read locks for
1136
1204
# dirstate updates.
1137
1205
if self._control_files._lock_mode == 'w':
1236
1304
# have to change the legacy inventory too.
1237
1305
if self._inventory is not None:
1238
1306
for file_id in file_ids:
1239
self._inventory.remove_recursive_id(file_id)
1307
if self._inventory.has_id(file_id):
1308
self._inventory.remove_recursive_id(file_id)
1241
1310
@needs_tree_write_lock
1242
1311
def rename_one(self, from_rel, to_rel, after=False):
1243
1312
"""See WorkingTree.rename_one"""
1245
WorkingTree.rename_one(self, from_rel, to_rel, after)
1314
super(DirStateWorkingTree, self).rename_one(from_rel, to_rel, after)
1247
1316
@needs_tree_write_lock
1248
1317
def apply_inventory_delta(self, changes):
1267
1336
if self._dirty:
1268
1337
raise AssertionError("attempting to write an inventory when the "
1269
1338
"dirstate is dirty will lose pending changes")
1270
self.current_dirstate().set_state_from_inventory(inv)
1271
self._make_dirty(reset_inventory=False)
1272
if self._inventory is not None:
1339
had_inventory = self._inventory is not None
1340
# Setting self._inventory = None forces the dirstate to regenerate the
1341
# working inventory. We do this because self.inventory may be inv, or
1342
# may have been modified, and either case would prevent a clean delta
1344
self._inventory = None
1346
delta = inv._make_delta(self.root_inventory)
1348
self.apply_inventory_delta(delta)
1273
1350
self._inventory = inv
1353
@needs_tree_write_lock
1354
def reset_state(self, revision_ids=None):
1355
"""Reset the state of the working tree.
1357
This does a hard-reset to a last-known-good state. This is a way to
1358
fix if something got corrupted (like the .bzr/checkout/dirstate file)
1360
if revision_ids is None:
1361
revision_ids = self.get_parent_ids()
1362
if not revision_ids:
1363
base_tree = self.branch.repository.revision_tree(
1364
_mod_revision.NULL_REVISION)
1367
trees = zip(revision_ids,
1368
self.branch.repository.revision_trees(revision_ids))
1369
base_tree = trees[0][1]
1370
state = self.current_dirstate()
1371
# We don't support ghosts yet
1372
state.set_state_from_scratch(base_tree.root_inventory, trees, [])
1277
1375
class ContentFilterAwareSHA1Provider(dirstate.SHA1Provider):
1283
1381
"""See dirstate.SHA1Provider.sha1()."""
1284
1382
filters = self.tree._content_filter_stack(
1285
1383
self.tree.relpath(osutils.safe_unicode(abspath)))
1286
return internal_size_sha_file_byname(abspath, filters)[1]
1384
return _mod_filters.internal_size_sha_file_byname(abspath, filters)[1]
1288
1386
def stat_and_sha1(self, abspath):
1289
1387
"""See dirstate.SHA1Provider.stat_and_sha1()."""
1294
1392
statvalue = os.fstat(file_obj.fileno())
1296
file_obj = filtered_input_file(file_obj, filters)
1394
file_obj = _mod_filters.filtered_input_file(file_obj, filters)
1297
1395
sha1 = osutils.size_sha_file(file_obj)[1]
1299
1397
file_obj.close()
1300
1398
return statvalue, sha1
1401
class ContentFilteringDirStateWorkingTree(DirStateWorkingTree):
1402
"""Dirstate working tree that supports content filtering.
1404
The dirstate holds the hash and size of the canonical form of the file,
1405
and most methods must return that.
1408
def _file_content_summary(self, path, stat_result):
1409
# This is to support the somewhat obsolete path_content_summary method
1410
# with content filtering: see
1411
# <https://bugs.launchpad.net/bzr/+bug/415508>.
1413
# If the dirstate cache is up to date and knows the hash and size,
1415
# Otherwise if there are no content filters, return the on-disk size
1416
# and leave the hash blank.
1417
# Otherwise, read and filter the on-disk file and use its size and
1420
# The dirstate doesn't store the size of the canonical form so we
1421
# can't trust it for content-filtered trees. We just return None.
1422
dirstate_sha1 = self._dirstate.sha1_from_stat(path, stat_result)
1423
executable = self._is_executable_from_path_and_stat(path, stat_result)
1424
return ('file', None, executable, dirstate_sha1)
1303
1427
class WorkingTree4(DirStateWorkingTree):
1304
1428
"""This is the Format 4 working tree.
1306
This differs from WorkingTree3 by:
1430
This differs from WorkingTree by:
1307
1431
- Having a consolidated internal dirstate, stored in a
1308
1432
randomly-accessible sorted file on disk.
1309
1433
- Not having a regular inventory attribute. One can be synthesized
1337
1461
return views.PathBasedViews(self)
1340
class DirStateWorkingTreeFormat(WorkingTreeFormat3):
1464
class DirStateWorkingTreeFormat(WorkingTreeFormatMetaDir):
1466
missing_parent_conflicts = True
1468
supports_versioned_directories = True
1470
_lock_class = LockDir
1471
_lock_file_name = 'lock'
1473
def _open_control_files(self, a_bzrdir):
1474
transport = a_bzrdir.get_workingtree_transport(None)
1475
return LockableFiles(transport, self._lock_file_name,
1341
1478
def initialize(self, a_bzrdir, revision_id=None, from_branch=None,
1342
1479
accelerator_tree=None, hardlink=False):
1343
1480
"""See WorkingTreeFormat.initialize().
1345
1482
:param revision_id: allows creating a working tree at a different
1346
revision than the branch is at.
1483
revision than the branch is at.
1347
1484
:param accelerator_tree: A tree which can be used for retrieving file
1348
1485
contents more quickly than the revision tree, i.e. a workingtree.
1349
1486
The revision tree will be used for cases where accelerator_tree's
1360
1497
control_files = self._open_control_files(a_bzrdir)
1361
1498
control_files.create_lock()
1362
1499
control_files.lock_write()
1363
transport.put_bytes('format', self.get_format_string(),
1500
transport.put_bytes('format', self.as_string(),
1364
1501
mode=a_bzrdir._get_file_mode())
1365
1502
if from_branch is not None:
1366
1503
branch = from_branch
1413
1550
if basis_root_id is not None:
1414
1551
wt._set_root_id(basis_root_id)
1416
# If content filtering is supported, do not use the accelerator
1417
# tree - the cost of transforming the content both ways and
1418
# checking for changed content can outweight the gains it gives.
1419
# Note: do NOT move this logic up higher - using the basis from
1420
# the accelerator tree is still desirable because that can save
1421
# a minute or more of processing on large trees!
1422
# The original tree may not have the same content filters
1423
# applied so we can't safely build the inventory delta from
1425
1553
if wt.supports_content_filtering():
1426
accelerator_tree = None
1554
# The original tree may not have the same content filters
1555
# applied so we can't safely build the inventory delta from
1427
1557
delta_from_tree = False
1429
1559
delta_from_tree = True
1433
1563
transform.build_tree(basis, wt, accelerator_tree,
1434
1564
hardlink=hardlink,
1435
1565
delta_from_tree=delta_from_tree)
1566
for hook in MutableTree.hooks['post_build_tree']:
1449
1581
:param wt: the WorkingTree object
1584
def open(self, a_bzrdir, _found=False):
1585
"""Return the WorkingTree object for a_bzrdir
1587
_found is a private parameter, do not use it. It is used to indicate
1588
if format probing has already been done.
1591
# we are being called directly and must probe.
1592
raise NotImplementedError
1593
if not isinstance(a_bzrdir.transport, LocalTransport):
1594
raise errors.NotLocalUrl(a_bzrdir.transport.base)
1595
wt = self._open(a_bzrdir, self._open_control_files(a_bzrdir))
1452
1598
def _open(self, a_bzrdir, control_files):
1453
1599
"""Open the tree itself.
1467
1613
def _get_matchingbzrdir(self):
1468
1614
"""Overrideable method to get a bzrdir for testing."""
1469
1615
# please test against something that will let us do tree references
1470
return bzrdir.format_registry.make_bzrdir(
1471
'dirstate-with-subtree')
1616
return controldir.format_registry.make_bzrdir(
1617
'development-subtree')
1473
1619
_matchingbzrdir = property(__get_matchingbzrdir)
1480
1626
- exists within a metadir controlling .bzr
1481
1627
- includes an explicit version marker for the workingtree control
1482
files, separate from the BzrDir format
1628
files, separate from the ControlDir format
1483
1629
- modifies the hash cache format
1484
1630
- is new in bzr 0.15
1485
1631
- uses a LockDir to guard access to it.
1490
1636
_tree_class = WorkingTree4
1492
def get_format_string(self):
1639
def get_format_string(cls):
1493
1640
"""See WorkingTreeFormat.get_format_string()."""
1494
1641
return "Bazaar Working Tree Format 4 (bzr 0.15)\n"
1507
1654
_tree_class = WorkingTree5
1509
def get_format_string(self):
1657
def get_format_string(cls):
1510
1658
"""See WorkingTreeFormat.get_format_string()."""
1511
1659
return "Bazaar Working Tree Format 5 (bzr 1.11)\n"
1527
1675
_tree_class = WorkingTree6
1529
def get_format_string(self):
1678
def get_format_string(cls):
1530
1679
"""See WorkingTreeFormat.get_format_string()."""
1531
1680
return "Bazaar Working Tree Format 6 (bzr 1.14)\n"
1544
1693
def supports_views(self):
1548
class DirStateRevisionTree(Tree):
1549
"""A revision tree pulling the inventory from a dirstate."""
1696
def _get_matchingbzrdir(self):
1697
"""Overrideable method to get a bzrdir for testing."""
1698
# We use 'development-subtree' instead of '2a', because we have a
1699
# few tests that want to test tree references
1700
return bzrdir.format_registry.make_bzrdir('development-subtree')
1703
class DirStateRevisionTree(InventoryTree):
1704
"""A revision tree pulling the inventory from a dirstate.
1706
Note that this is one of the historical (ie revision) trees cached in the
1707
dirstate for easy access, not the workingtree.
1551
1710
def __init__(self, dirstate, revision_id, repository):
1552
1711
self._dirstate = dirstate
1566
1725
def annotate_iter(self, file_id,
1567
1726
default_revision=_mod_revision.CURRENT_REVISION):
1568
1727
"""See Tree.annotate_iter"""
1569
text_key = (file_id, self.inventory[file_id].revision)
1728
text_key = (file_id, self.get_file_revision(file_id))
1570
1729
annotations = self._repository.texts.annotate(text_key)
1571
1730
return [(key[-1], line) for (key, line) in annotations]
1573
def _get_ancestors(self, default_revision):
1574
return set(self._repository.get_ancestry(self._revision_id,
1576
1732
def _comparison_data(self, entry, path):
1577
1733
"""See Tree._comparison_data."""
1578
1734
if entry is None:
1631
1787
if path is not None:
1632
1788
path = path.encode('utf8')
1633
1789
parent_index = self._get_parent_index()
1634
return self._dirstate._get_entry(parent_index, fileid_utf8=file_id, path_utf8=path)
1790
return self._dirstate._get_entry(parent_index, fileid_utf8=file_id,
1636
1793
def _generate_inventory(self):
1637
1794
"""Create and set self.inventory from the dirstate object.
1694
1851
elif kind == 'directory':
1695
1852
parent_ies[(dirname + '/' + name).strip('/')] = inv_entry
1696
1853
elif kind == 'symlink':
1697
inv_entry.executable = False
1698
inv_entry.text_size = None
1699
1854
inv_entry.symlink_target = utf8_decode(fingerprint)[0]
1700
1855
elif kind == 'tree-reference':
1701
1856
inv_entry.reference_revision = fingerprint or None
1721
1876
# Make sure the file exists
1722
1877
entry = self._get_entry(file_id, path=path)
1723
1878
if entry == (None, None): # do we raise?
1879
raise errors.NoSuchId(self, file_id)
1725
1880
parent_index = self._get_parent_index()
1726
1881
last_changed_revision = entry[1][parent_index][4]
1727
return self._repository.get_revision(last_changed_revision).timestamp
1883
rev = self._repository.get_revision(last_changed_revision)
1884
except errors.NoSuchRevision:
1885
raise errors.FileTimestampUnavailable(self.id2path(file_id))
1886
return rev.timestamp
1729
1888
def get_file_sha1(self, file_id, path=None, stat_value=None):
1730
1889
entry = self._get_entry(file_id=file_id, path=path)
1734
1893
return parent_details[1]
1897
def get_file_revision(self, file_id):
1898
inv, inv_file_id = self._unpack_file_id(file_id)
1899
return inv[inv_file_id].revision
1737
1901
def get_file(self, file_id, path=None):
1738
1902
return StringIO(self.get_file_text(file_id))
1740
1904
def get_file_size(self, file_id):
1741
1905
"""See Tree.get_file_size"""
1742
return self.inventory[file_id].text_size
1906
inv, inv_file_id = self._unpack_file_id(file_id)
1907
return inv[inv_file_id].text_size
1744
1909
def get_file_text(self, file_id, path=None):
1745
_, content = list(self.iter_files_bytes([(file_id, None)]))[0]
1746
return ''.join(content)
1911
for _, content_iter in self.iter_files_bytes([(file_id, None)]):
1912
if content is not None:
1913
raise AssertionError('iter_files_bytes returned'
1914
' too many entries')
1915
# For each entry returned by iter_files_bytes, we must consume the
1916
# content_iter before we step the files iterator.
1917
content = ''.join(content_iter)
1919
raise AssertionError('iter_files_bytes did not return'
1920
' the requested data')
1748
1923
def get_reference_revision(self, file_id, path=None):
1749
return self.inventory[file_id].reference_revision
1924
inv, inv_file_id = self._unpack_file_id(file_id)
1925
return inv[inv_file_id].reference_revision
1751
1927
def iter_files_bytes(self, desired_files):
1752
1928
"""See Tree.iter_files_bytes.
1763
1939
return self._repository.iter_files_bytes(repo_desired_files)
1765
def get_symlink_target(self, file_id):
1941
def get_symlink_target(self, file_id, path=None):
1766
1942
entry = self._get_entry(file_id=file_id)
1767
1943
parent_index = self._get_parent_index()
1768
1944
if entry[1][parent_index][0] != 'l':
1776
1952
"""Return the revision id for this tree."""
1777
1953
return self._revision_id
1779
def _get_inventory(self):
1955
def _get_root_inventory(self):
1780
1956
if self._inventory is not None:
1781
1957
return self._inventory
1782
1958
self._must_be_locked()
1783
1959
self._generate_inventory()
1784
1960
return self._inventory
1962
root_inventory = property(_get_root_inventory,
1963
doc="Inventory of this Tree")
1965
@deprecated_method(deprecated_in((2, 5, 0)))
1966
def _get_inventory(self):
1967
return self.root_inventory
1786
1969
inventory = property(_get_inventory,
1787
1970
doc="Inventory of this Tree")
1797
1980
entry = self._get_entry(file_id=file_id)[1]
1798
1981
if entry is None:
1799
1982
raise errors.NoSuchId(tree=self, file_id=file_id)
1800
return dirstate.DirState._minikind_to_kind[entry[1][0]]
1983
parent_index = self._get_parent_index()
1984
return dirstate.DirState._minikind_to_kind[entry[parent_index][0]]
1802
1986
def stored_kind(self, file_id):
1803
1987
"""See Tree.stored_kind"""
1806
1990
def path_content_summary(self, path):
1807
1991
"""See Tree.path_content_summary."""
1808
id = self.inventory.path2id(path)
1992
inv, inv_file_id = self._path2inv_file_id(path)
1993
if inv_file_id is None:
1810
1994
return ('missing', None, None, None)
1811
entry = self._inventory[id]
1995
entry = inv[inv_file_id]
1812
1996
kind = entry.kind
1813
1997
if kind == 'file':
1814
1998
return (kind, entry.text_size, entry.executable, entry.text_sha1)
1818
2002
return (kind, None, None, None)
1820
2004
def is_executable(self, file_id, path=None):
1821
ie = self.inventory[file_id]
2005
inv, inv_file_id = self._unpack_file_id(file_id)
2006
ie = inv[inv_file_id]
1822
2007
if ie.kind != "file":
1824
2009
return ie.executable
2011
def is_locked(self):
1826
2014
def list_files(self, include_root=False, from_dir=None, recursive=True):
1827
2015
# We use a standard implementation, because DirStateRevisionTree is
1828
2016
# dealing with one of the parents of the current state
1829
inv = self._get_inventory()
1830
2017
if from_dir is None:
2018
inv = self.root_inventory
1831
2019
from_dir_id = None
1833
from_dir_id = inv.path2id(from_dir)
2021
inv, from_dir_id = self._path2inv_file_id(from_dir)
1834
2022
if from_dir_id is None:
1835
2023
# Directory not versioned
2025
# FIXME: Support nested trees
1837
2026
entries = inv.iter_entries(from_dir=from_dir_id, recursive=recursive)
1838
2027
if inv.root is not None and not include_root and from_dir is None:
1841
2030
yield path, 'V', entry.kind, entry.file_id, entry
1843
2032
def lock_read(self):
1844
"""Lock the tree for a set of operations."""
2033
"""Lock the tree for a set of operations.
2035
:return: A bzrlib.lock.LogicalLockResult.
1845
2037
if not self._locked:
1846
2038
self._repository.lock_read()
1847
2039
if self._dirstate._lock_token is None:
1848
2040
self._dirstate.lock_read()
1849
2041
self._dirstate_locked = True
1850
2042
self._locked += 1
2043
return LogicalLockResult(self.unlock)
1852
2045
def _must_be_locked(self):
1853
2046
if not self._locked:
1857
2050
def path2id(self, path):
1858
2051
"""Return the id for path in this tree."""
1859
2052
# lookup by path: faster than splitting and walking the ivnentory.
2053
if isinstance(path, list):
2056
path = osutils.pathjoin(*path)
1860
2057
entry = self._get_entry(path=path)
1861
2058
if entry == (None, None):
1885
2082
# So for now, we just build up the parent inventory, and extract
1886
2083
# it the same way RevisionTree does.
1887
2084
_directory = 'directory'
1888
inv = self._get_inventory()
2085
inv = self._get_root_inventory()
1889
2086
top_id = inv.path2id(prefix)
1890
2087
if top_id is None:
1932
2129
def make_source_parent_tree(source, target):
1933
2130
"""Change the source tree into a parent of the target."""
1934
2131
revid = source.commit('record tree')
1935
target.branch.repository.fetch(source.branch.repository, revid)
2132
target.branch.fetch(source.branch, revid)
1936
2133
target.set_parent_ids([revid])
1937
2134
return target.basis_tree(), target
1946
def make_source_parent_tree_compiled_dirstate(klass, test_case, source, target):
2143
def make_source_parent_tree_compiled_dirstate(klass, test_case, source,
1947
2145
from bzrlib.tests.test__dirstate_helpers import \
1948
CompiledDirstateHelpersFeature
1949
if not CompiledDirstateHelpersFeature.available():
1950
from bzrlib.tests import UnavailableFeature
1951
raise UnavailableFeature(CompiledDirstateHelpersFeature)
2146
compiled_dirstate_helpers_feature
2147
test_case.requireFeature(compiled_dirstate_helpers_feature)
1952
2148
from bzrlib._dirstate_helpers_pyx import ProcessEntryC
1953
2149
result = klass.make_source_parent_tree(source, target)
1954
2150
result[1]._iter_changes = ProcessEntryC
1985
2181
output. An unversioned file is defined as one with (False, False)
1986
2182
for the versioned pair.
1988
# NB: show_status depends on being able to pass in non-versioned files
1989
# and report them as unknown
1990
2184
# TODO: handle extra trees in the dirstate.
1991
2185
if (extra_trees or specific_files == []):
1992
2186
# we can't fast-path these cases (yet)
2033
2227
path_entries = state._entries_for_path(path)
2034
2228
if not path_entries:
2035
2229
# this specified path is not present at all: error
2036
not_versioned.append(path)
2230
not_versioned.append(path.decode('utf-8'))
2038
2232
found_versioned = False
2039
2233
# for each id at this path
2047
2241
if not found_versioned:
2048
2242
# none of the indexes was not 'absent' at all ids for this
2050
not_versioned.append(path)
2244
not_versioned.append(path.decode('utf-8'))
2051
2245
if len(not_versioned) > 0:
2052
2246
raise errors.PathsNotVersionedError(not_versioned)
2053
2247
# -- remove redundancy in supplied specific_files to prevent over-scanning --
2120
2314
def update_format(self, tree):
2121
2315
"""Change the format marker."""
2122
2316
tree._transport.put_bytes('format',
2123
self.target_format.get_format_string(),
2317
self.target_format.as_string(),
2124
2318
mode=tree.bzrdir._get_file_mode())
2143
2337
def update_format(self, tree):
2144
2338
"""Change the format marker."""
2145
2339
tree._transport.put_bytes('format',
2146
self.target_format.get_format_string(),
2340
self.target_format.as_string(),
2147
2341
mode=tree.bzrdir._get_file_mode())
2172
2366
def update_format(self, tree):
2173
2367
"""Change the format marker."""
2174
2368
tree._transport.put_bytes('format',
2175
self.target_format.get_format_string(),
2369
self.target_format.as_string(),
2176
2370
mode=tree.bzrdir._get_file_mode())