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
35
42
from bzrlib import (
45
conflicts as _mod_conflicts,
43
55
revision as _mod_revision,
49
65
import bzrlib.branch
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
72
from bzrlib.filters import filtered_input_file, internal_size_sha_file_byname
55
from bzrlib.inventory import Inventory, ROOT_ID, entry_factory
73
from bzrlib.inventory import InventoryEntry, Inventory, ROOT_ID, entry_factory
56
74
import bzrlib.mutabletree
57
75
from bzrlib.mutabletree import needs_tree_write_lock
58
76
from bzrlib.osutils import (
65
from bzrlib.trace import mutter
86
from bzrlib.trace import mutter, note
66
87
from bzrlib.transport.local import LocalTransport
67
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,
68
97
from bzrlib.tree import Tree
69
98
from bzrlib.workingtree import WorkingTree, WorkingTree3, WorkingTreeFormat3
435
464
return osutils.lexists(pathjoin(
436
465
self.basedir, row[0].decode('utf8'), row[1].decode('utf8')))
438
def has_or_had_id(self, file_id):
439
state = self.current_dirstate()
440
row, parents = self._get_entry(file_id=file_id)
441
return row is not None
444
468
def id2path(self, file_id):
445
469
"Convert a file-id to a path."
692
716
from_entry = self._get_entry(path=from_rel)
693
717
if from_entry == (None, None):
694
718
raise errors.BzrMoveFailedError(from_rel,to_dir,
695
errors.NotVersionedError(path=from_rel))
719
errors.NotVersionedError(path=str(from_rel)))
697
721
from_id = from_entry[0][2]
698
722
to_rel = pathjoin(to_dir, from_tail)
1027
1051
def set_last_revision(self, new_revision):
1028
1052
"""Change the last revision in the working tree."""
1029
1053
parents = self.get_parent_ids()
1030
if new_revision in (_mod_revision.NULL_REVISION, None):
1054
if new_revision in (NULL_REVISION, None):
1031
1055
if len(parents) >= 2:
1032
1056
raise AssertionError(
1033
1057
"setting the last parent to none with a pending merge is "
1200
1224
# just forget the whole block.
1201
1225
entry_index = 0
1202
1226
while entry_index < len(block[1]):
1227
# Mark this file id as having been removed
1203
1228
entry = block[1][entry_index]
1204
if entry[1][0][0] in 'ar':
1205
# don't remove absent or renamed entries
1229
ids_to_unversion.discard(entry[0][2])
1230
if (entry[1][0][0] in 'ar' # don't remove absent or renamed
1232
or not state._make_absent(entry)):
1206
1233
entry_index += 1
1208
# Mark this file id as having been removed
1209
ids_to_unversion.discard(entry[0][2])
1210
if not state._make_absent(entry):
1211
# The block has not shrunk.
1213
1234
# go to the next block. (At the moment we dont delete empty
1215
1236
block_index += 1
1267
1288
if self._dirty:
1268
1289
raise AssertionError("attempting to write an inventory when the "
1269
1290
"dirstate is dirty will lose pending changes")
1270
had_inventory = self._inventory is not None
1271
# Setting self._inventory = None forces the dirstate to regenerate the
1272
# working inventory. We do this because self.inventory may be inv, or
1273
# may have been modified, and either case would prevent a clean delta
1275
self._inventory = None
1277
delta = inv._make_delta(self.inventory)
1279
self.apply_inventory_delta(delta)
1291
self.current_dirstate().set_state_from_inventory(inv)
1292
self._make_dirty(reset_inventory=False)
1293
if self._inventory is not None:
1281
1294
self._inventory = inv
1308
1321
return statvalue, sha1
1311
class ContentFilteringDirStateWorkingTree(DirStateWorkingTree):
1312
"""Dirstate working tree that supports content filtering.
1314
The dirstate holds the hash and size of the canonical form of the file,
1315
and most methods must return that.
1318
def _file_content_summary(self, path, stat_result):
1319
# This is to support the somewhat obsolete path_content_summary method
1320
# with content filtering: see
1321
# <https://bugs.edge.launchpad.net/bzr/+bug/415508>.
1323
# If the dirstate cache is up to date and knows the hash and size,
1325
# Otherwise if there are no content filters, return the on-disk size
1326
# and leave the hash blank.
1327
# Otherwise, read and filter the on-disk file and use its size and
1330
# The dirstate doesn't store the size of the canonical form so we
1331
# can't trust it for content-filtered trees. We just return None.
1332
dirstate_sha1 = self._dirstate.sha1_from_stat(path, stat_result)
1333
executable = self._is_executable_from_path_and_stat(path, stat_result)
1334
return ('file', None, executable, dirstate_sha1)
1337
1324
class WorkingTree4(DirStateWorkingTree):
1338
1325
"""This is the Format 4 working tree.
1416
1403
wt.lock_tree_write()
1418
1405
self._init_custom_control_files(wt)
1419
if revision_id in (None, _mod_revision.NULL_REVISION):
1406
if revision_id in (None, NULL_REVISION):
1420
1407
if branch.repository.supports_rich_root():
1421
1408
wt._set_root_id(generate_ids.gen_root_id())
1434
1421
if basis is None:
1435
1422
basis = branch.repository.revision_tree(revision_id)
1436
if revision_id == _mod_revision.NULL_REVISION:
1423
if revision_id == NULL_REVISION:
1437
1424
parents_list = []
1439
1426
parents_list = [(revision_id, basis)]
1447
1434
if basis_root_id is not None:
1448
1435
wt._set_root_id(basis_root_id)
1437
# If content filtering is supported, do not use the accelerator
1438
# tree - the cost of transforming the content both ways and
1439
# checking for changed content can outweight the gains it gives.
1440
# Note: do NOT move this logic up higher - using the basis from
1441
# the accelerator tree is still desirable because that can save
1442
# a minute or more of processing on large trees!
1450
1443
if wt.supports_content_filtering():
1451
# The original tree may not have the same content filters
1452
# applied so we can't safely build the inventory delta from
1454
delta_from_tree = False
1456
delta_from_tree = True
1444
accelerator_tree = None
1457
1445
# delta_from_tree is safe even for DirStateRevisionTrees,
1458
1446
# because wt4.apply_inventory_delta does not mutate the input
1459
1447
# inventory entries.
1460
1448
transform.build_tree(basis, wt, accelerator_tree,
1462
delta_from_tree=delta_from_tree)
1449
hardlink=hardlink, delta_from_tree=True)
1575
1562
class DirStateRevisionTree(Tree):
1576
"""A revision tree pulling the inventory from a dirstate.
1578
Note that this is one of the historical (ie revision) trees cached in the
1579
dirstate for easy access, not the workingtree.
1563
"""A revision tree pulling the inventory from a dirstate."""
1582
1565
def __init__(self, dirstate, revision_id, repository):
1583
1566
self._dirstate = dirstate
1756
1739
parent_index = self._get_parent_index()
1757
1740
last_changed_revision = entry[1][parent_index][4]
1759
rev = self._repository.get_revision(last_changed_revision)
1760
except errors.NoSuchRevision:
1761
raise errors.FileTimestampUnavailable(self.id2path(file_id))
1762
return rev.timestamp
1741
return self._repository.get_revision(last_changed_revision).timestamp
1764
1743
def get_file_sha1(self, file_id, path=None, stat_value=None):
1765
1744
entry = self._get_entry(file_id=file_id, path=path)
1859
1838
return ie.executable
1861
def list_files(self, include_root=False, from_dir=None, recursive=True):
1840
def list_files(self, include_root=False):
1862
1841
# We use a standard implementation, because DirStateRevisionTree is
1863
1842
# dealing with one of the parents of the current state
1864
1843
inv = self._get_inventory()
1865
if from_dir is None:
1868
from_dir_id = inv.path2id(from_dir)
1869
if from_dir_id is None:
1870
# Directory not versioned
1872
entries = inv.iter_entries(from_dir=from_dir_id, recursive=recursive)
1873
if inv.root is not None and not include_root and from_dir is None:
1844
entries = inv.iter_entries()
1845
if self.inventory.root is not None and not include_root:
1875
1847
for path, entry in entries:
1876
1848
yield path, 'V', entry.kind, entry.file_id, entry
1981
def make_source_parent_tree_compiled_dirstate(klass, test_case, source,
1953
def make_source_parent_tree_compiled_dirstate(klass, test_case, source, target):
1983
1954
from bzrlib.tests.test__dirstate_helpers import \
1984
compiled_dirstate_helpers_feature
1985
test_case.requireFeature(compiled_dirstate_helpers_feature)
1986
from bzrlib._dirstate_helpers_pyx import ProcessEntryC
1955
CompiledDirstateHelpersFeature
1956
if not CompiledDirstateHelpersFeature.available():
1957
from bzrlib.tests import UnavailableFeature
1958
raise UnavailableFeature(CompiledDirstateHelpersFeature)
1959
from bzrlib._dirstate_helpers_c import ProcessEntryC
1987
1960
result = klass.make_source_parent_tree(source, target)
1988
1961
result[1]._iter_changes = ProcessEntryC
2019
1992
output. An unversioned file is defined as one with (False, False)
2020
1993
for the versioned pair.
1995
# NB: show_status depends on being able to pass in non-versioned files
1996
# and report them as unknown
2022
1997
# TODO: handle extra trees in the dirstate.
2023
1998
if (extra_trees or specific_files == []):
2024
1999
# we can't fast-path these cases (yet)
2027
2002
require_versioned, want_unversioned=want_unversioned)
2028
2003
parent_ids = self.target.get_parent_ids()
2029
2004
if not (self.source._revision_id in parent_ids
2030
or self.source._revision_id == _mod_revision.NULL_REVISION):
2005
or self.source._revision_id == NULL_REVISION):
2031
2006
raise AssertionError(
2032
2007
"revision {%s} is not stored in {%s}, but %s "
2033
2008
"can only be used for trees stored in the dirstate"
2034
2009
% (self.source._revision_id, self.target, self.iter_changes))
2035
2010
target_index = 0
2036
if self.source._revision_id == _mod_revision.NULL_REVISION:
2011
if self.source._revision_id == NULL_REVISION:
2037
2012
source_index = None
2038
2013
indices = (target_index,)
2060
2035
state._read_dirblocks_if_needed()
2061
2036
if require_versioned:
2062
2037
# -- check all supplied paths are versioned in a search tree. --
2038
all_versioned = True
2064
2039
for path in specific_files:
2065
2040
path_entries = state._entries_for_path(path)
2066
2041
if not path_entries:
2067
2042
# this specified path is not present at all: error
2068
not_versioned.append(path)
2043
all_versioned = False
2070
2045
found_versioned = False
2071
2046
# for each id at this path
2072
2047
for entry in path_entries:
2079
2054
if not found_versioned:
2080
2055
# none of the indexes was not 'absent' at all ids for this
2082
not_versioned.append(path)
2083
if len(not_versioned) > 0:
2084
raise errors.PathsNotVersionedError(not_versioned)
2057
all_versioned = False
2059
if not all_versioned:
2060
raise errors.PathsNotVersionedError(specific_files)
2085
2061
# -- remove redundancy in supplied specific_files to prevent over-scanning --
2086
2062
search_specific_files = osutils.minimum_path_selection(specific_files)
2101
2077
(revisiontree.RevisionTree, DirStateRevisionTree)):
2103
2079
# the source revid must be in the target dirstate
2104
if not (source._revision_id == _mod_revision.NULL_REVISION or
2080
if not (source._revision_id == NULL_REVISION or
2105
2081
source._revision_id in target.get_parent_ids()):
2106
2082
# TODO: what about ghosts? it may well need to
2107
2083
# check for them explicitly.