1
# Copyright (C) 2005, 2006, 2007, 2008, 2009 Canonical Ltd
1
# Copyright (C) 2007-2011 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
52
from bzrlib.decorators import needs_read_lock, needs_write_lock
54
from bzrlib.filters import filtered_input_file, internal_size_sha_file_byname
55
53
from bzrlib.inventory import Inventory, ROOT_ID, entry_factory
56
import bzrlib.mutabletree
54
from bzrlib.lock import LogicalLockResult
55
from bzrlib.lockable_files import LockableFiles
56
from bzrlib.lockdir import LockDir
57
57
from bzrlib.mutabletree import needs_tree_write_lock
58
58
from bzrlib.osutils import (
65
from bzrlib.trace import mutter
66
65
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):
66
from bzrlib.tree import (
70
from bzrlib.workingtree import (
77
class DirStateWorkingTree(InventoryWorkingTree):
79
_DEFAULT_WORTH_SAVING_LIMIT = 10
73
81
def __init__(self, basedir,
75
83
_control_files=None,
85
93
self._format = _format
86
94
self.bzrdir = _bzrdir
87
95
basedir = safe_unicode(basedir)
88
mutter("opening working tree %r", basedir)
96
trace.mutter("opening working tree %r", basedir)
89
97
self._branch = branch
90
98
self.basedir = realpath(basedir)
91
99
# if branch is at our basedir and is a format 6 or less
125
133
state.add(f, file_id, kind, None, '')
126
134
self._make_dirty(reset_inventory=True)
136
def _get_check_refs(self):
137
"""Return the references needed to perform a check of this tree."""
138
return [('trees', self.last_revision())]
128
140
def _make_dirty(self, reset_inventory):
129
141
"""Make the tree state dirty.
183
195
def _comparison_data(self, entry, path):
184
196
kind, executable, stat_value = \
185
WorkingTree3._comparison_data(self, entry, path)
197
WorkingTree._comparison_data(self, entry, path)
186
198
# it looks like a plain directory, but it's really a reference -- see
188
200
if (self._repo_supports_tree_reference and kind == 'directory'
194
206
def commit(self, message=None, revprops=None, *args, **kwargs):
195
207
# mark the tree as dirty post commit - commit
196
208
# can change the current versioned list by doing deletes.
197
result = WorkingTree3.commit(self, message, revprops, *args, **kwargs)
209
result = WorkingTree.commit(self, message, revprops, *args, **kwargs)
198
210
self._make_dirty(reset_inventory=True)
219
231
local_path = self.bzrdir.get_workingtree_transport(None
220
232
).local_abspath('dirstate')
221
233
self._dirstate = dirstate.DirState.on_file(local_path,
222
self._sha1_provider())
234
self._sha1_provider(), self._worth_saving_limit())
223
235
return self._dirstate
225
237
def _sha1_provider(self):
249
def _worth_saving_limit(self):
250
"""How many hash changes are ok before we must save the dirstate.
252
:return: an integer. -1 means never save.
254
config = self.branch.get_config()
255
val = config.get_user_option('bzr.workingtree.worth_saving_limit')
257
val = self._DEFAULT_WORTH_SAVING_LIMIT
261
except ValueError, e:
262
trace.warning('Invalid config value for'
263
' "bzr.workingtree.worth_saving_limit"'
264
' value %r is not an integer.'
266
val = self._DEFAULT_WORTH_SAVING_LIMIT
237
269
def filter_unversioned_files(self, paths):
238
270
"""Filter out paths that are versioned.
568
600
return _mod_revision.NULL_REVISION
570
602
def lock_read(self):
571
"""See Branch.lock_read, and WorkingTree.unlock."""
603
"""See Branch.lock_read, and WorkingTree.unlock.
605
:return: A bzrlib.lock.LogicalLockResult.
572
607
self.branch.lock_read()
574
609
self._control_files.lock_read()
608
644
self.branch.unlock()
646
return LogicalLockResult(self.unlock)
611
648
def lock_tree_write(self):
612
"""See MutableTree.lock_tree_write, and WorkingTree.unlock."""
649
"""See MutableTree.lock_tree_write, and WorkingTree.unlock.
651
:return: A bzrlib.lock.LogicalLockResult.
613
653
self.branch.lock_read()
614
self._lock_self_write()
654
return self._lock_self_write()
616
656
def lock_write(self):
617
"""See MutableTree.lock_write, and WorkingTree.unlock."""
657
"""See MutableTree.lock_write, and WorkingTree.unlock.
659
:return: A bzrlib.lock.LogicalLockResult.
618
661
self.branch.lock_write()
619
self._lock_self_write()
662
return self._lock_self_write()
621
664
@needs_tree_write_lock
622
665
def move(self, from_paths, to_dir, after=False):
1102
1145
_mod_revision.NULL_REVISION)))
1103
1146
ghosts.append(rev_id)
1104
1147
accepted_revisions.add(rev_id)
1105
dirstate.set_parent_trees(real_trees, ghosts=ghosts)
1149
if (len(real_trees) == 1
1151
and self.branch.repository._format.fast_deltas
1152
and isinstance(real_trees[0][1],
1153
revisiontree.InventoryRevisionTree)
1154
and self.get_parent_ids()):
1155
rev_id, rev_tree = real_trees[0]
1156
basis_id = self.get_parent_ids()[0]
1157
# There are times when basis_tree won't be in
1158
# self.branch.repository, (switch, for example)
1160
basis_tree = self.branch.repository.revision_tree(basis_id)
1161
except errors.NoSuchRevision:
1162
# Fall back to the set_parent_trees(), since we can't use
1163
# _make_delta if we can't get the RevisionTree
1166
delta = rev_tree.inventory._make_delta(basis_tree.inventory)
1167
dirstate.update_basis_by_delta(delta, rev_id)
1170
dirstate.set_parent_trees(real_trees, ghosts=ghosts)
1106
1171
self._make_dirty(reset_inventory=False)
1108
1173
def _set_root_id(self, file_id):
1129
1194
def unlock(self):
1130
1195
"""Unlock in format 4 trees needs to write the entire dirstate."""
1131
# do non-implementation specific cleanup
1134
1196
if self._control_files._lock_count == 1:
1197
# do non-implementation specific cleanup
1135
1200
# eventually we should do signature checking during read locks for
1136
1201
# dirstate updates.
1137
1202
if self._control_files._lock_mode == 'w':
1236
1301
# have to change the legacy inventory too.
1237
1302
if self._inventory is not None:
1238
1303
for file_id in file_ids:
1239
self._inventory.remove_recursive_id(file_id)
1304
if self._inventory.has_id(file_id):
1305
self._inventory.remove_recursive_id(file_id)
1241
1307
@needs_tree_write_lock
1242
1308
def rename_one(self, from_rel, to_rel, after=False):
1243
1309
"""See WorkingTree.rename_one"""
1245
WorkingTree.rename_one(self, from_rel, to_rel, after)
1311
super(DirStateWorkingTree, self).rename_one(from_rel, to_rel, after)
1247
1313
@needs_tree_write_lock
1248
1314
def apply_inventory_delta(self, changes):
1267
1333
if self._dirty:
1268
1334
raise AssertionError("attempting to write an inventory when the "
1269
1335
"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:
1336
had_inventory = self._inventory is not None
1337
# Setting self._inventory = None forces the dirstate to regenerate the
1338
# working inventory. We do this because self.inventory may be inv, or
1339
# may have been modified, and either case would prevent a clean delta
1341
self._inventory = None
1343
delta = inv._make_delta(self.inventory)
1345
self.apply_inventory_delta(delta)
1273
1347
self._inventory = inv
1350
@needs_tree_write_lock
1351
def reset_state(self, revision_ids=None):
1352
"""Reset the state of the working tree.
1354
This does a hard-reset to a last-known-good state. This is a way to
1355
fix if something got corrupted (like the .bzr/checkout/dirstate file)
1357
if revision_ids is None:
1358
revision_ids = self.get_parent_ids()
1359
if not revision_ids:
1360
base_tree = self.branch.repository.revision_tree(
1361
_mod_revision.NULL_REVISION)
1364
trees = zip(revision_ids,
1365
self.branch.repository.revision_trees(revision_ids))
1366
base_tree = trees[0][1]
1367
state = self.current_dirstate()
1368
# We don't support ghosts yet
1369
state.set_state_from_scratch(base_tree.inventory, trees, [])
1277
1372
class ContentFilterAwareSHA1Provider(dirstate.SHA1Provider):
1283
1378
"""See dirstate.SHA1Provider.sha1()."""
1284
1379
filters = self.tree._content_filter_stack(
1285
1380
self.tree.relpath(osutils.safe_unicode(abspath)))
1286
return internal_size_sha_file_byname(abspath, filters)[1]
1381
return _mod_filters.internal_size_sha_file_byname(abspath, filters)[1]
1288
1383
def stat_and_sha1(self, abspath):
1289
1384
"""See dirstate.SHA1Provider.stat_and_sha1()."""
1294
1389
statvalue = os.fstat(file_obj.fileno())
1296
file_obj = filtered_input_file(file_obj, filters)
1391
file_obj = _mod_filters.filtered_input_file(file_obj, filters)
1297
1392
sha1 = osutils.size_sha_file(file_obj)[1]
1299
1394
file_obj.close()
1300
1395
return statvalue, sha1
1398
class ContentFilteringDirStateWorkingTree(DirStateWorkingTree):
1399
"""Dirstate working tree that supports content filtering.
1401
The dirstate holds the hash and size of the canonical form of the file,
1402
and most methods must return that.
1405
def _file_content_summary(self, path, stat_result):
1406
# This is to support the somewhat obsolete path_content_summary method
1407
# with content filtering: see
1408
# <https://bugs.launchpad.net/bzr/+bug/415508>.
1410
# If the dirstate cache is up to date and knows the hash and size,
1412
# Otherwise if there are no content filters, return the on-disk size
1413
# and leave the hash blank.
1414
# Otherwise, read and filter the on-disk file and use its size and
1417
# The dirstate doesn't store the size of the canonical form so we
1418
# can't trust it for content-filtered trees. We just return None.
1419
dirstate_sha1 = self._dirstate.sha1_from_stat(path, stat_result)
1420
executable = self._is_executable_from_path_and_stat(path, stat_result)
1421
return ('file', None, executable, dirstate_sha1)
1303
1424
class WorkingTree4(DirStateWorkingTree):
1304
1425
"""This is the Format 4 working tree.
1306
This differs from WorkingTree3 by:
1427
This differs from WorkingTree by:
1307
1428
- Having a consolidated internal dirstate, stored in a
1308
1429
randomly-accessible sorted file on disk.
1309
1430
- Not having a regular inventory attribute. One can be synthesized
1337
1458
return views.PathBasedViews(self)
1340
class DirStateWorkingTreeFormat(WorkingTreeFormat3):
1461
class DirStateWorkingTreeFormat(WorkingTreeFormat):
1463
missing_parent_conflicts = True
1465
supports_versioned_directories = True
1467
_lock_class = LockDir
1468
_lock_file_name = 'lock'
1470
def _open_control_files(self, a_bzrdir):
1471
transport = a_bzrdir.get_workingtree_transport(None)
1472
return LockableFiles(transport, self._lock_file_name,
1341
1475
def initialize(self, a_bzrdir, revision_id=None, from_branch=None,
1342
1476
accelerator_tree=None, hardlink=False):
1343
1477
"""See WorkingTreeFormat.initialize().
1345
1479
:param revision_id: allows creating a working tree at a different
1346
revision than the branch is at.
1480
revision than the branch is at.
1347
1481
:param accelerator_tree: A tree which can be used for retrieving file
1348
1482
contents more quickly than the revision tree, i.e. a workingtree.
1349
1483
The revision tree will be used for cases where accelerator_tree's
1413
1547
if basis_root_id is not None:
1414
1548
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
1550
if wt.supports_content_filtering():
1426
accelerator_tree = None
1551
# The original tree may not have the same content filters
1552
# applied so we can't safely build the inventory delta from
1427
1554
delta_from_tree = False
1429
1556
delta_from_tree = True
1449
1576
:param wt: the WorkingTree object
1579
def open(self, a_bzrdir, _found=False):
1580
"""Return the WorkingTree object for a_bzrdir
1582
_found is a private parameter, do not use it. It is used to indicate
1583
if format probing has already been done.
1586
# we are being called directly and must probe.
1587
raise NotImplementedError
1588
if not isinstance(a_bzrdir.transport, LocalTransport):
1589
raise errors.NotLocalUrl(a_bzrdir.transport.base)
1590
wt = self._open(a_bzrdir, self._open_control_files(a_bzrdir))
1452
1593
def _open(self, a_bzrdir, control_files):
1453
1594
"""Open the tree itself.
1548
class DirStateRevisionTree(Tree):
1549
"""A revision tree pulling the inventory from a dirstate."""
1689
class DirStateRevisionTree(InventoryTree):
1690
"""A revision tree pulling the inventory from a dirstate.
1692
Note that this is one of the historical (ie revision) trees cached in the
1693
dirstate for easy access, not the workingtree.
1551
1696
def __init__(self, dirstate, revision_id, repository):
1552
1697
self._dirstate = dirstate
1566
1711
def annotate_iter(self, file_id,
1567
1712
default_revision=_mod_revision.CURRENT_REVISION):
1568
1713
"""See Tree.annotate_iter"""
1569
text_key = (file_id, self.inventory[file_id].revision)
1714
text_key = (file_id, self.get_file_revision(file_id))
1570
1715
annotations = self._repository.texts.annotate(text_key)
1571
1716
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
1718
def _comparison_data(self, entry, path):
1577
1719
"""See Tree._comparison_data."""
1578
1720
if entry is None:
1694
1836
elif kind == 'directory':
1695
1837
parent_ies[(dirname + '/' + name).strip('/')] = inv_entry
1696
1838
elif kind == 'symlink':
1697
inv_entry.executable = False
1698
inv_entry.text_size = None
1699
1839
inv_entry.symlink_target = utf8_decode(fingerprint)[0]
1700
1840
elif kind == 'tree-reference':
1701
1841
inv_entry.reference_revision = fingerprint or None
1725
1865
parent_index = self._get_parent_index()
1726
1866
last_changed_revision = entry[1][parent_index][4]
1727
return self._repository.get_revision(last_changed_revision).timestamp
1868
rev = self._repository.get_revision(last_changed_revision)
1869
except errors.NoSuchRevision:
1870
raise errors.FileTimestampUnavailable(self.id2path(file_id))
1871
return rev.timestamp
1729
1873
def get_file_sha1(self, file_id, path=None, stat_value=None):
1730
1874
entry = self._get_entry(file_id=file_id, path=path)
1734
1878
return parent_details[1]
1882
def get_file_revision(self, file_id):
1883
return self.inventory[file_id].revision
1737
1885
def get_file(self, file_id, path=None):
1738
1886
return StringIO(self.get_file_text(file_id))
1763
1911
return self._repository.iter_files_bytes(repo_desired_files)
1765
def get_symlink_target(self, file_id):
1913
def get_symlink_target(self, file_id, path=None):
1766
1914
entry = self._get_entry(file_id=file_id)
1767
1915
parent_index = self._get_parent_index()
1768
1916
if entry[1][parent_index][0] != 'l':
1797
1945
entry = self._get_entry(file_id=file_id)[1]
1798
1946
if entry is None:
1799
1947
raise errors.NoSuchId(tree=self, file_id=file_id)
1800
return dirstate.DirState._minikind_to_kind[entry[1][0]]
1948
parent_index = self._get_parent_index()
1949
return dirstate.DirState._minikind_to_kind[entry[parent_index][0]]
1802
1951
def stored_kind(self, file_id):
1803
1952
"""See Tree.stored_kind"""
1820
1969
def is_executable(self, file_id, path=None):
1821
1970
ie = self.inventory[file_id]
1822
1971
if ie.kind != "file":
1824
1973
return ie.executable
1975
def is_locked(self):
1826
1978
def list_files(self, include_root=False, from_dir=None, recursive=True):
1827
1979
# We use a standard implementation, because DirStateRevisionTree is
1828
1980
# dealing with one of the parents of the current state
1841
1993
yield path, 'V', entry.kind, entry.file_id, entry
1843
1995
def lock_read(self):
1844
"""Lock the tree for a set of operations."""
1996
"""Lock the tree for a set of operations.
1998
:return: A bzrlib.lock.LogicalLockResult.
1845
2000
if not self._locked:
1846
2001
self._repository.lock_read()
1847
2002
if self._dirstate._lock_token is None:
1848
2003
self._dirstate.lock_read()
1849
2004
self._dirstate_locked = True
1850
2005
self._locked += 1
2006
return LogicalLockResult(self.unlock)
1852
2008
def _must_be_locked(self):
1853
2009
if not self._locked:
1932
2088
def make_source_parent_tree(source, target):
1933
2089
"""Change the source tree into a parent of the target."""
1934
2090
revid = source.commit('record tree')
1935
target.branch.repository.fetch(source.branch.repository, revid)
2091
target.branch.fetch(source.branch, revid)
1936
2092
target.set_parent_ids([revid])
1937
2093
return target.basis_tree(), target
1946
def make_source_parent_tree_compiled_dirstate(klass, test_case, source, target):
2102
def make_source_parent_tree_compiled_dirstate(klass, test_case, source,
1947
2104
from bzrlib.tests.test__dirstate_helpers import \
1948
CompiledDirstateHelpersFeature
1949
if not CompiledDirstateHelpersFeature.available():
1950
from bzrlib.tests import UnavailableFeature
1951
raise UnavailableFeature(CompiledDirstateHelpersFeature)
2105
compiled_dirstate_helpers_feature
2106
test_case.requireFeature(compiled_dirstate_helpers_feature)
1952
2107
from bzrlib._dirstate_helpers_pyx import ProcessEntryC
1953
2108
result = klass.make_source_parent_tree(source, target)
1954
2109
result[1]._iter_changes = ProcessEntryC
1985
2140
output. An unversioned file is defined as one with (False, False)
1986
2141
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
2143
# TODO: handle extra trees in the dirstate.
1991
2144
if (extra_trees or specific_files == []):
1992
2145
# we can't fast-path these cases (yet)