1
# Copyright (C) 2005, 2006, 2007, 2008 Canonical Ltd
1
# Copyright (C) 2007-2010 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
42
35
from bzrlib import (
45
conflicts as _mod_conflicts,
55
43
revision as _mod_revision,
65
49
import bzrlib.branch
66
from bzrlib.transport import get_transport
70
from bzrlib import symbol_versioning
71
53
from bzrlib.decorators import needs_read_lock, needs_write_lock
72
54
from bzrlib.filters import filtered_input_file, internal_size_sha_file_byname
73
from bzrlib.inventory import InventoryEntry, Inventory, ROOT_ID, entry_factory
74
import bzrlib.mutabletree
55
from bzrlib.inventory import Inventory, ROOT_ID, entry_factory
56
from bzrlib.lock import LogicalLockResult
75
57
from bzrlib.mutabletree import needs_tree_write_lock
76
58
from bzrlib.osutils import (
86
from bzrlib.trace import mutter, note
65
from bzrlib.trace import mutter
87
66
from bzrlib.transport.local import LocalTransport
88
67
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,
97
68
from bzrlib.tree import Tree
98
69
from bzrlib.workingtree import WorkingTree, WorkingTree3, WorkingTreeFormat3
464
435
return osutils.lexists(pathjoin(
465
436
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
468
444
def id2path(self, file_id):
469
445
"Convert a file-id to a path."
592
568
return _mod_revision.NULL_REVISION
594
570
def lock_read(self):
595
"""See Branch.lock_read, and WorkingTree.unlock."""
571
"""See Branch.lock_read, and WorkingTree.unlock.
573
:return: A bzrlib.lock.LogicalLockResult.
596
575
self.branch.lock_read()
598
577
self._control_files.lock_read()
632
612
self.branch.unlock()
614
return LogicalLockResult(self.unlock)
635
616
def lock_tree_write(self):
636
"""See MutableTree.lock_tree_write, and WorkingTree.unlock."""
617
"""See MutableTree.lock_tree_write, and WorkingTree.unlock.
619
:return: A bzrlib.lock.LogicalLockResult.
637
621
self.branch.lock_read()
638
self._lock_self_write()
622
return self._lock_self_write()
640
624
def lock_write(self):
641
"""See MutableTree.lock_write, and WorkingTree.unlock."""
625
"""See MutableTree.lock_write, and WorkingTree.unlock.
627
:return: A bzrlib.lock.LogicalLockResult.
642
629
self.branch.lock_write()
643
self._lock_self_write()
630
return self._lock_self_write()
645
632
@needs_tree_write_lock
646
633
def move(self, from_paths, to_dir, after=False):
716
703
from_entry = self._get_entry(path=from_rel)
717
704
if from_entry == (None, None):
718
705
raise errors.BzrMoveFailedError(from_rel,to_dir,
719
errors.NotVersionedError(path=str(from_rel)))
706
errors.NotVersionedError(path=from_rel))
721
708
from_id = from_entry[0][2]
722
709
to_rel = pathjoin(to_dir, from_tail)
1051
1038
def set_last_revision(self, new_revision):
1052
1039
"""Change the last revision in the working tree."""
1053
1040
parents = self.get_parent_ids()
1054
if new_revision in (NULL_REVISION, None):
1041
if new_revision in (_mod_revision.NULL_REVISION, None):
1055
1042
if len(parents) >= 2:
1056
1043
raise AssertionError(
1057
1044
"setting the last parent to none with a pending merge is "
1224
1211
# just forget the whole block.
1225
1212
entry_index = 0
1226
1213
while entry_index < len(block[1]):
1227
# Mark this file id as having been removed
1228
1214
entry = block[1][entry_index]
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)):
1215
if entry[1][0][0] in 'ar':
1216
# don't remove absent or renamed entries
1233
1217
entry_index += 1
1219
# Mark this file id as having been removed
1220
ids_to_unversion.discard(entry[0][2])
1221
if not state._make_absent(entry):
1222
# The block has not shrunk.
1234
1224
# go to the next block. (At the moment we dont delete empty
1236
1226
block_index += 1
1257
1247
# have to change the legacy inventory too.
1258
1248
if self._inventory is not None:
1259
1249
for file_id in file_ids:
1260
self._inventory.remove_recursive_id(file_id)
1250
if self._inventory.has_id(file_id):
1251
self._inventory.remove_recursive_id(file_id)
1262
1253
@needs_tree_write_lock
1263
1254
def rename_one(self, from_rel, to_rel, after=False):
1288
1279
if self._dirty:
1289
1280
raise AssertionError("attempting to write an inventory when the "
1290
1281
"dirstate is dirty will lose pending changes")
1291
self.current_dirstate().set_state_from_inventory(inv)
1292
self._make_dirty(reset_inventory=False)
1293
if self._inventory is not None:
1282
had_inventory = self._inventory is not None
1283
# Setting self._inventory = None forces the dirstate to regenerate the
1284
# working inventory. We do this because self.inventory may be inv, or
1285
# may have been modified, and either case would prevent a clean delta
1287
self._inventory = None
1289
delta = inv._make_delta(self.inventory)
1291
self.apply_inventory_delta(delta)
1294
1293
self._inventory = inv
1321
1320
return statvalue, sha1
1323
class ContentFilteringDirStateWorkingTree(DirStateWorkingTree):
1324
"""Dirstate working tree that supports content filtering.
1326
The dirstate holds the hash and size of the canonical form of the file,
1327
and most methods must return that.
1330
def _file_content_summary(self, path, stat_result):
1331
# This is to support the somewhat obsolete path_content_summary method
1332
# with content filtering: see
1333
# <https://bugs.launchpad.net/bzr/+bug/415508>.
1335
# If the dirstate cache is up to date and knows the hash and size,
1337
# Otherwise if there are no content filters, return the on-disk size
1338
# and leave the hash blank.
1339
# Otherwise, read and filter the on-disk file and use its size and
1342
# The dirstate doesn't store the size of the canonical form so we
1343
# can't trust it for content-filtered trees. We just return None.
1344
dirstate_sha1 = self._dirstate.sha1_from_stat(path, stat_result)
1345
executable = self._is_executable_from_path_and_stat(path, stat_result)
1346
return ('file', None, executable, dirstate_sha1)
1324
1349
class WorkingTree4(DirStateWorkingTree):
1325
1350
"""This is the Format 4 working tree.
1361
1386
class DirStateWorkingTreeFormat(WorkingTreeFormat3):
1362
1388
def initialize(self, a_bzrdir, revision_id=None, from_branch=None,
1363
1389
accelerator_tree=None, hardlink=False):
1364
1390
"""See WorkingTreeFormat.initialize().
1403
1429
wt.lock_tree_write()
1405
1431
self._init_custom_control_files(wt)
1406
if revision_id in (None, NULL_REVISION):
1432
if revision_id in (None, _mod_revision.NULL_REVISION):
1407
1433
if branch.repository.supports_rich_root():
1408
1434
wt._set_root_id(generate_ids.gen_root_id())
1421
1447
if basis is None:
1422
1448
basis = branch.repository.revision_tree(revision_id)
1423
if revision_id == NULL_REVISION:
1449
if revision_id == _mod_revision.NULL_REVISION:
1424
1450
parents_list = []
1426
1452
parents_list = [(revision_id, basis)]
1434
1460
if basis_root_id is not None:
1435
1461
wt._set_root_id(basis_root_id)
1463
if wt.supports_content_filtering():
1464
# The original tree may not have the same content filters
1465
# applied so we can't safely build the inventory delta from
1467
delta_from_tree = False
1469
delta_from_tree = True
1437
1470
# delta_from_tree is safe even for DirStateRevisionTrees,
1438
1471
# because wt4.apply_inventory_delta does not mutate the input
1439
1472
# inventory entries.
1440
1473
transform.build_tree(basis, wt, accelerator_tree,
1441
hardlink=hardlink, delta_from_tree=True)
1475
delta_from_tree=delta_from_tree)
1554
1588
class DirStateRevisionTree(Tree):
1555
"""A revision tree pulling the inventory from a dirstate."""
1589
"""A revision tree pulling the inventory from a dirstate.
1591
Note that this is one of the historical (ie revision) trees cached in the
1592
dirstate for easy access, not the workingtree.
1557
1595
def __init__(self, dirstate, revision_id, repository):
1558
1596
self._dirstate = dirstate
1731
1769
parent_index = self._get_parent_index()
1732
1770
last_changed_revision = entry[1][parent_index][4]
1733
return self._repository.get_revision(last_changed_revision).timestamp
1772
rev = self._repository.get_revision(last_changed_revision)
1773
except errors.NoSuchRevision:
1774
raise errors.FileTimestampUnavailable(self.id2path(file_id))
1775
return rev.timestamp
1735
1777
def get_file_sha1(self, file_id, path=None, stat_value=None):
1736
1778
entry = self._get_entry(file_id=file_id, path=path)
1803
1845
entry = self._get_entry(file_id=file_id)[1]
1804
1846
if entry is None:
1805
1847
raise errors.NoSuchId(tree=self, file_id=file_id)
1806
return dirstate.DirState._minikind_to_kind[entry[1][0]]
1848
parent_index = self._get_parent_index()
1849
return dirstate.DirState._minikind_to_kind[entry[parent_index][0]]
1808
1851
def stored_kind(self, file_id):
1809
1852
"""See Tree.stored_kind"""
1830
1873
return ie.executable
1832
def list_files(self, include_root=False):
1875
def is_locked(self):
1878
def list_files(self, include_root=False, from_dir=None, recursive=True):
1833
1879
# We use a standard implementation, because DirStateRevisionTree is
1834
1880
# dealing with one of the parents of the current state
1835
1881
inv = self._get_inventory()
1836
entries = inv.iter_entries()
1837
if self.inventory.root is not None and not include_root:
1882
if from_dir is None:
1885
from_dir_id = inv.path2id(from_dir)
1886
if from_dir_id is None:
1887
# Directory not versioned
1889
entries = inv.iter_entries(from_dir=from_dir_id, recursive=recursive)
1890
if inv.root is not None and not include_root and from_dir is None:
1839
1892
for path, entry in entries:
1840
1893
yield path, 'V', entry.kind, entry.file_id, entry
1842
1895
def lock_read(self):
1843
"""Lock the tree for a set of operations."""
1896
"""Lock the tree for a set of operations.
1898
:return: A bzrlib.lock.LogicalLockResult.
1844
1900
if not self._locked:
1845
1901
self._repository.lock_read()
1846
1902
if self._dirstate._lock_token is None:
1847
1903
self._dirstate.lock_read()
1848
1904
self._dirstate_locked = True
1849
1905
self._locked += 1
1906
return LogicalLockResult(self.unlock)
1851
1908
def _must_be_locked(self):
1852
1909
if not self._locked:
1945
def make_source_parent_tree_compiled_dirstate(klass, test_case, source, target):
2002
def make_source_parent_tree_compiled_dirstate(klass, test_case, source,
1946
2004
from bzrlib.tests.test__dirstate_helpers import \
1947
CompiledDirstateHelpersFeature
1948
if not CompiledDirstateHelpersFeature.available():
1949
from bzrlib.tests import UnavailableFeature
1950
raise UnavailableFeature(CompiledDirstateHelpersFeature)
1951
from bzrlib._dirstate_helpers_c import ProcessEntryC
2005
compiled_dirstate_helpers_feature
2006
test_case.requireFeature(compiled_dirstate_helpers_feature)
2007
from bzrlib._dirstate_helpers_pyx import ProcessEntryC
1952
2008
result = klass.make_source_parent_tree(source, target)
1953
2009
result[1]._iter_changes = ProcessEntryC
1984
2040
output. An unversioned file is defined as one with (False, False)
1985
2041
for the versioned pair.
1987
# NB: show_status depends on being able to pass in non-versioned files
1988
# and report them as unknown
1989
2043
# TODO: handle extra trees in the dirstate.
1990
2044
if (extra_trees or specific_files == []):
1991
2045
# we can't fast-path these cases (yet)
1994
2048
require_versioned, want_unversioned=want_unversioned)
1995
2049
parent_ids = self.target.get_parent_ids()
1996
2050
if not (self.source._revision_id in parent_ids
1997
or self.source._revision_id == NULL_REVISION):
2051
or self.source._revision_id == _mod_revision.NULL_REVISION):
1998
2052
raise AssertionError(
1999
2053
"revision {%s} is not stored in {%s}, but %s "
2000
2054
"can only be used for trees stored in the dirstate"
2001
2055
% (self.source._revision_id, self.target, self.iter_changes))
2002
2056
target_index = 0
2003
if self.source._revision_id == NULL_REVISION:
2057
if self.source._revision_id == _mod_revision.NULL_REVISION:
2004
2058
source_index = None
2005
2059
indices = (target_index,)
2022
2076
specific_files = set([''])
2023
2077
# -- specific_files is now a utf8 path set --
2024
search_specific_files = set()
2025
2079
# -- get the state object and prepare it.
2026
2080
state = self.target.current_dirstate()
2027
2081
state._read_dirblocks_if_needed()
2028
2082
if require_versioned:
2029
2083
# -- check all supplied paths are versioned in a search tree. --
2030
all_versioned = True
2031
2085
for path in specific_files:
2032
2086
path_entries = state._entries_for_path(path)
2033
2087
if not path_entries:
2034
2088
# this specified path is not present at all: error
2035
all_versioned = False
2089
not_versioned.append(path)
2037
2091
found_versioned = False
2038
2092
# for each id at this path
2039
2093
for entry in path_entries:
2046
2100
if not found_versioned:
2047
2101
# none of the indexes was not 'absent' at all ids for this
2049
all_versioned = False
2051
if not all_versioned:
2052
raise errors.PathsNotVersionedError(specific_files)
2103
not_versioned.append(path)
2104
if len(not_versioned) > 0:
2105
raise errors.PathsNotVersionedError(not_versioned)
2053
2106
# -- remove redundancy in supplied specific_files to prevent over-scanning --
2054
for path in specific_files:
2055
other_specific_files = specific_files.difference(set([path]))
2056
if not osutils.is_inside_any(other_specific_files, path):
2057
# this is a top level path, we must check it.
2058
search_specific_files.add(path)
2107
search_specific_files = osutils.minimum_path_selection(specific_files)
2060
2109
use_filesystem_for_exec = (sys.platform != 'win32')
2061
2110
iter_changes = self.target._iter_changes(include_unchanged,
2073
2122
(revisiontree.RevisionTree, DirStateRevisionTree)):
2075
2124
# the source revid must be in the target dirstate
2076
if not (source._revision_id == NULL_REVISION or
2125
if not (source._revision_id == _mod_revision.NULL_REVISION or
2077
2126
source._revision_id in target.get_parent_ids()):
2078
2127
# TODO: what about ghosts? it may well need to
2079
2128
# check for them explicitly.