1
# Copyright (C) 2007-2010 Canonical Ltd
1
# Copyright (C) 2005, 2006, 2007, 2008, 2009 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
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
74
import bzrlib.mutabletree
56
75
from bzrlib.mutabletree import needs_tree_write_lock
57
76
from bzrlib.osutils import (
64
from bzrlib.trace import mutter
86
from bzrlib.trace import mutter, note
65
87
from bzrlib.transport.local import LocalTransport
66
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,
67
97
from bzrlib.tree import Tree
68
98
from bzrlib.workingtree import WorkingTree, WorkingTree3, WorkingTreeFormat3
434
464
return osutils.lexists(pathjoin(
435
465
self.basedir, row[0].decode('utf8'), row[1].decode('utf8')))
437
def has_or_had_id(self, file_id):
438
state = self.current_dirstate()
439
row, parents = self._get_entry(file_id=file_id)
440
return row is not None
443
468
def id2path(self, file_id):
444
469
"Convert a file-id to a path."
567
592
return _mod_revision.NULL_REVISION
569
594
def lock_read(self):
570
"""See Branch.lock_read, and WorkingTree.unlock.
572
:return: An object with an unlock method which will release the lock
595
"""See Branch.lock_read, and WorkingTree.unlock."""
575
596
self.branch.lock_read()
577
598
self._control_files.lock_read()
612
632
self.branch.unlock()
616
635
def lock_tree_write(self):
617
"""See MutableTree.lock_tree_write, and WorkingTree.unlock.
619
:return: An object with an unlock method which will release the lock
636
"""See MutableTree.lock_tree_write, and WorkingTree.unlock."""
622
637
self.branch.lock_read()
623
return self._lock_self_write()
638
self._lock_self_write()
625
640
def lock_write(self):
626
"""See MutableTree.lock_write, and WorkingTree.unlock.
628
:return: An object with an unlock method which will release the lock
641
"""See MutableTree.lock_write, and WorkingTree.unlock."""
631
642
self.branch.lock_write()
632
return self._lock_self_write()
643
self._lock_self_write()
634
645
@needs_tree_write_lock
635
646
def move(self, from_paths, to_dir, after=False):
705
716
from_entry = self._get_entry(path=from_rel)
706
717
if from_entry == (None, None):
707
718
raise errors.BzrMoveFailedError(from_rel,to_dir,
708
errors.NotVersionedError(path=from_rel))
719
errors.NotVersionedError(path=str(from_rel)))
710
721
from_id = from_entry[0][2]
711
722
to_rel = pathjoin(to_dir, from_tail)
1040
1051
def set_last_revision(self, new_revision):
1041
1052
"""Change the last revision in the working tree."""
1042
1053
parents = self.get_parent_ids()
1043
if new_revision in (_mod_revision.NULL_REVISION, None):
1054
if new_revision in (NULL_REVISION, None):
1044
1055
if len(parents) >= 2:
1045
1056
raise AssertionError(
1046
1057
"setting the last parent to none with a pending merge is "
1213
1224
# just forget the whole block.
1214
1225
entry_index = 0
1215
1226
while entry_index < len(block[1]):
1227
# Mark this file id as having been removed
1216
1228
entry = block[1][entry_index]
1217
if entry[1][0][0] in 'ar':
1218
# 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)):
1219
1233
entry_index += 1
1221
# Mark this file id as having been removed
1222
ids_to_unversion.discard(entry[0][2])
1223
if not state._make_absent(entry):
1224
# The block has not shrunk.
1226
1234
# go to the next block. (At the moment we dont delete empty
1228
1236
block_index += 1
1280
1288
if self._dirty:
1281
1289
raise AssertionError("attempting to write an inventory when the "
1282
1290
"dirstate is dirty will lose pending changes")
1283
had_inventory = self._inventory is not None
1284
# Setting self._inventory = None forces the dirstate to regenerate the
1285
# working inventory. We do this because self.inventory may be inv, or
1286
# may have been modified, and either case would prevent a clean delta
1288
self._inventory = None
1290
delta = inv._make_delta(self.inventory)
1292
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:
1294
1294
self._inventory = inv
1321
1321
return statvalue, sha1
1324
class ContentFilteringDirStateWorkingTree(DirStateWorkingTree):
1325
"""Dirstate working tree that supports content filtering.
1327
The dirstate holds the hash and size of the canonical form of the file,
1328
and most methods must return that.
1331
def _file_content_summary(self, path, stat_result):
1332
# This is to support the somewhat obsolete path_content_summary method
1333
# with content filtering: see
1334
# <https://bugs.edge.launchpad.net/bzr/+bug/415508>.
1336
# If the dirstate cache is up to date and knows the hash and size,
1338
# Otherwise if there are no content filters, return the on-disk size
1339
# and leave the hash blank.
1340
# Otherwise, read and filter the on-disk file and use its size and
1343
# The dirstate doesn't store the size of the canonical form so we
1344
# can't trust it for content-filtered trees. We just return None.
1345
dirstate_sha1 = self._dirstate.sha1_from_stat(path, stat_result)
1346
executable = self._is_executable_from_path_and_stat(path, stat_result)
1347
return ('file', None, executable, dirstate_sha1)
1350
1324
class WorkingTree4(DirStateWorkingTree):
1351
1325
"""This is the Format 4 working tree.
1387
1361
class DirStateWorkingTreeFormat(WorkingTreeFormat3):
1389
1362
def initialize(self, a_bzrdir, revision_id=None, from_branch=None,
1390
1363
accelerator_tree=None, hardlink=False):
1391
1364
"""See WorkingTreeFormat.initialize().
1430
1403
wt.lock_tree_write()
1432
1405
self._init_custom_control_files(wt)
1433
if revision_id in (None, _mod_revision.NULL_REVISION):
1406
if revision_id in (None, NULL_REVISION):
1434
1407
if branch.repository.supports_rich_root():
1435
1408
wt._set_root_id(generate_ids.gen_root_id())
1448
1421
if basis is None:
1449
1422
basis = branch.repository.revision_tree(revision_id)
1450
if revision_id == _mod_revision.NULL_REVISION:
1423
if revision_id == NULL_REVISION:
1451
1424
parents_list = []
1453
1426
parents_list = [(revision_id, basis)]
1461
1434
if basis_root_id is not None:
1462
1435
wt._set_root_id(basis_root_id)
1464
if wt.supports_content_filtering():
1465
# The original tree may not have the same content filters
1466
# applied so we can't safely build the inventory delta from
1468
delta_from_tree = False
1470
delta_from_tree = True
1471
1437
# delta_from_tree is safe even for DirStateRevisionTrees,
1472
1438
# because wt4.apply_inventory_delta does not mutate the input
1473
1439
# inventory entries.
1474
1440
transform.build_tree(basis, wt, accelerator_tree,
1476
delta_from_tree=delta_from_tree)
1441
hardlink=hardlink, delta_from_tree=True)
1589
1554
class DirStateRevisionTree(Tree):
1590
"""A revision tree pulling the inventory from a dirstate.
1592
Note that this is one of the historical (ie revision) trees cached in the
1593
dirstate for easy access, not the workingtree.
1555
"""A revision tree pulling the inventory from a dirstate."""
1596
1557
def __init__(self, dirstate, revision_id, repository):
1597
1558
self._dirstate = dirstate
1770
1731
parent_index = self._get_parent_index()
1771
1732
last_changed_revision = entry[1][parent_index][4]
1773
rev = self._repository.get_revision(last_changed_revision)
1774
except errors.NoSuchRevision:
1775
raise errors.FileTimestampUnavailable(self.id2path(file_id))
1776
return rev.timestamp
1733
return self._repository.get_revision(last_changed_revision).timestamp
1778
1735
def get_file_sha1(self, file_id, path=None, stat_value=None):
1779
1736
entry = self._get_entry(file_id=file_id, path=path)
1846
1803
entry = self._get_entry(file_id=file_id)[1]
1847
1804
if entry is None:
1848
1805
raise errors.NoSuchId(tree=self, file_id=file_id)
1849
parent_index = self._get_parent_index()
1850
return dirstate.DirState._minikind_to_kind[entry[parent_index][0]]
1806
return dirstate.DirState._minikind_to_kind[entry[1][0]]
1852
1808
def stored_kind(self, file_id):
1853
1809
"""See Tree.stored_kind"""
1874
1830
return ie.executable
1876
def is_locked(self):
1879
1832
def list_files(self, include_root=False, from_dir=None, recursive=True):
1880
1833
# We use a standard implementation, because DirStateRevisionTree is
1881
1834
# dealing with one of the parents of the current state
1894
1847
yield path, 'V', entry.kind, entry.file_id, entry
1896
1849
def lock_read(self):
1897
"""Lock the tree for a set of operations.
1899
:return: An object with an unlock method which will release the lock
1850
"""Lock the tree for a set of operations."""
1902
1851
if not self._locked:
1903
1852
self._repository.lock_read()
1904
1853
if self._dirstate._lock_token is None:
1905
1854
self._dirstate.lock_read()
1906
1855
self._dirstate_locked = True
1907
1856
self._locked += 1
1910
1858
def _must_be_locked(self):
1911
1859
if not self._locked:
2004
def make_source_parent_tree_compiled_dirstate(klass, test_case, source,
1952
def make_source_parent_tree_compiled_dirstate(klass, test_case, source, target):
2006
1953
from bzrlib.tests.test__dirstate_helpers import \
2007
compiled_dirstate_helpers_feature
2008
test_case.requireFeature(compiled_dirstate_helpers_feature)
2009
from bzrlib._dirstate_helpers_pyx import ProcessEntryC
1954
CompiledDirstateHelpersFeature
1955
if not CompiledDirstateHelpersFeature.available():
1956
from bzrlib.tests import UnavailableFeature
1957
raise UnavailableFeature(CompiledDirstateHelpersFeature)
1958
from bzrlib._dirstate_helpers_c import ProcessEntryC
2010
1959
result = klass.make_source_parent_tree(source, target)
2011
1960
result[1]._iter_changes = ProcessEntryC
2042
1991
output. An unversioned file is defined as one with (False, False)
2043
1992
for the versioned pair.
1994
# NB: show_status depends on being able to pass in non-versioned files
1995
# and report them as unknown
2045
1996
# TODO: handle extra trees in the dirstate.
2046
1997
if (extra_trees or specific_files == []):
2047
1998
# we can't fast-path these cases (yet)
2050
2001
require_versioned, want_unversioned=want_unversioned)
2051
2002
parent_ids = self.target.get_parent_ids()
2052
2003
if not (self.source._revision_id in parent_ids
2053
or self.source._revision_id == _mod_revision.NULL_REVISION):
2004
or self.source._revision_id == NULL_REVISION):
2054
2005
raise AssertionError(
2055
2006
"revision {%s} is not stored in {%s}, but %s "
2056
2007
"can only be used for trees stored in the dirstate"
2057
2008
% (self.source._revision_id, self.target, self.iter_changes))
2058
2009
target_index = 0
2059
if self.source._revision_id == _mod_revision.NULL_REVISION:
2010
if self.source._revision_id == NULL_REVISION:
2060
2011
source_index = None
2061
2012
indices = (target_index,)
2083
2034
state._read_dirblocks_if_needed()
2084
2035
if require_versioned:
2085
2036
# -- check all supplied paths are versioned in a search tree. --
2037
all_versioned = True
2087
2038
for path in specific_files:
2088
2039
path_entries = state._entries_for_path(path)
2089
2040
if not path_entries:
2090
2041
# this specified path is not present at all: error
2091
not_versioned.append(path)
2042
all_versioned = False
2093
2044
found_versioned = False
2094
2045
# for each id at this path
2095
2046
for entry in path_entries:
2102
2053
if not found_versioned:
2103
2054
# none of the indexes was not 'absent' at all ids for this
2105
not_versioned.append(path)
2106
if len(not_versioned) > 0:
2107
raise errors.PathsNotVersionedError(not_versioned)
2056
all_versioned = False
2058
if not all_versioned:
2059
raise errors.PathsNotVersionedError(specific_files)
2108
2060
# -- remove redundancy in supplied specific_files to prevent over-scanning --
2109
2061
search_specific_files = osutils.minimum_path_selection(specific_files)
2124
2076
(revisiontree.RevisionTree, DirStateRevisionTree)):
2126
2078
# the source revid must be in the target dirstate
2127
if not (source._revision_id == _mod_revision.NULL_REVISION or
2079
if not (source._revision_id == NULL_REVISION or
2128
2080
source._revision_id in target.get_parent_ids()):
2129
2081
# TODO: what about ghosts? it may well need to
2130
2082
# check for them explicitly.