1
# Copyright (C) 2005, 2006, 2007, 2008, 2009 Canonical Ltd
1
# Copyright (C) 2005, 2006, 2007, 2008 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
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
1300
1321
return statvalue, sha1
1303
class ContentFilteringDirStateWorkingTree(DirStateWorkingTree):
1304
"""Dirstate working tree that supports content filtering.
1306
The dirstate holds the hash and size of the canonical form of the file,
1307
and most methods must return that.
1310
def _file_content_summary(self, path, stat_result):
1311
# This is to support the somewhat obsolete path_content_summary method
1312
# with content filtering: see
1313
# <https://bugs.edge.launchpad.net/bzr/+bug/415508>.
1315
# If the dirstate cache is up to date and knows the hash and size,
1317
# Otherwise if there are no content filters, return the on-disk size
1318
# and leave the hash blank.
1319
# Otherwise, read and filter the on-disk file and use its size and
1322
# The dirstate doesn't store the size of the canonical form so we
1323
# can't trust it for content-filtered trees. We just return None.
1324
dirstate_sha1 = self._dirstate.sha1_from_stat(path, stat_result)
1325
executable = self._is_executable_from_path_and_stat(path, stat_result)
1326
return ('file', None, executable, dirstate_sha1)
1329
1324
class WorkingTree4(DirStateWorkingTree):
1330
1325
"""This is the Format 4 working tree.
1408
1403
wt.lock_tree_write()
1410
1405
self._init_custom_control_files(wt)
1411
if revision_id in (None, _mod_revision.NULL_REVISION):
1406
if revision_id in (None, NULL_REVISION):
1412
1407
if branch.repository.supports_rich_root():
1413
1408
wt._set_root_id(generate_ids.gen_root_id())
1426
1421
if basis is None:
1427
1422
basis = branch.repository.revision_tree(revision_id)
1428
if revision_id == _mod_revision.NULL_REVISION:
1423
if revision_id == NULL_REVISION:
1429
1424
parents_list = []
1431
1426
parents_list = [(revision_id, basis)]
1439
1434
if basis_root_id is not None:
1440
1435
wt._set_root_id(basis_root_id)
1442
# If content filtering is supported, do not use the accelerator
1443
# tree - the cost of transforming the content both ways and
1444
# checking for changed content can outweight the gains it gives.
1445
# Note: do NOT move this logic up higher - using the basis from
1446
# the accelerator tree is still desirable because that can save
1447
# a minute or more of processing on large trees!
1448
# The original tree may not have the same content filters
1449
# applied so we can't safely build the inventory delta from
1451
if wt.supports_content_filtering():
1453
# see https://bugs.edge.launchpad.net/bzr/+bug/408193
1454
trace.warning("hardlinking working copy files is not currently "
1455
"supported in %r" % (wt,))
1456
accelerator_tree = None
1457
delta_from_tree = False
1459
delta_from_tree = True
1460
1437
# delta_from_tree is safe even for DirStateRevisionTrees,
1461
1438
# because wt4.apply_inventory_delta does not mutate the input
1462
1439
# inventory entries.
1463
1440
transform.build_tree(basis, wt, accelerator_tree,
1465
delta_from_tree=delta_from_tree)
1441
hardlink=hardlink, delta_from_tree=True)
1578
1554
class DirStateRevisionTree(Tree):
1579
"""A revision tree pulling the inventory from a dirstate.
1581
Note that this is one of the historical (ie revision) trees cached in the
1582
dirstate for easy access, not the workingtree.
1555
"""A revision tree pulling the inventory from a dirstate."""
1585
1557
def __init__(self, dirstate, revision_id, repository):
1586
1558
self._dirstate = dirstate
1858
1830
return ie.executable
1860
def list_files(self, include_root=False, from_dir=None, recursive=True):
1832
def list_files(self, include_root=False):
1861
1833
# We use a standard implementation, because DirStateRevisionTree is
1862
1834
# dealing with one of the parents of the current state
1863
1835
inv = self._get_inventory()
1864
if from_dir is None:
1867
from_dir_id = inv.path2id(from_dir)
1868
if from_dir_id is None:
1869
# Directory not versioned
1871
entries = inv.iter_entries(from_dir=from_dir_id, recursive=recursive)
1872
if inv.root is not None and not include_root and from_dir is None:
1836
entries = inv.iter_entries()
1837
if self.inventory.root is not None and not include_root:
1874
1839
for path, entry in entries:
1875
1840
yield path, 'V', entry.kind, entry.file_id, entry
1983
1948
if not CompiledDirstateHelpersFeature.available():
1984
1949
from bzrlib.tests import UnavailableFeature
1985
1950
raise UnavailableFeature(CompiledDirstateHelpersFeature)
1986
from bzrlib._dirstate_helpers_pyx import ProcessEntryC
1951
from bzrlib._dirstate_helpers_c import ProcessEntryC
1987
1952
result = klass.make_source_parent_tree(source, target)
1988
1953
result[1]._iter_changes = ProcessEntryC
2029
1994
require_versioned, want_unversioned=want_unversioned)
2030
1995
parent_ids = self.target.get_parent_ids()
2031
1996
if not (self.source._revision_id in parent_ids
2032
or self.source._revision_id == _mod_revision.NULL_REVISION):
1997
or self.source._revision_id == NULL_REVISION):
2033
1998
raise AssertionError(
2034
1999
"revision {%s} is not stored in {%s}, but %s "
2035
2000
"can only be used for trees stored in the dirstate"
2036
2001
% (self.source._revision_id, self.target, self.iter_changes))
2037
2002
target_index = 0
2038
if self.source._revision_id == _mod_revision.NULL_REVISION:
2003
if self.source._revision_id == NULL_REVISION:
2039
2004
source_index = None
2040
2005
indices = (target_index,)
2057
2022
specific_files = set([''])
2058
2023
# -- specific_files is now a utf8 path set --
2024
search_specific_files = set()
2060
2025
# -- get the state object and prepare it.
2061
2026
state = self.target.current_dirstate()
2062
2027
state._read_dirblocks_if_needed()
2063
2028
if require_versioned:
2064
2029
# -- check all supplied paths are versioned in a search tree. --
2030
all_versioned = True
2066
2031
for path in specific_files:
2067
2032
path_entries = state._entries_for_path(path)
2068
2033
if not path_entries:
2069
2034
# this specified path is not present at all: error
2070
not_versioned.append(path)
2035
all_versioned = False
2072
2037
found_versioned = False
2073
2038
# for each id at this path
2074
2039
for entry in path_entries:
2081
2046
if not found_versioned:
2082
2047
# none of the indexes was not 'absent' at all ids for this
2084
not_versioned.append(path)
2085
if len(not_versioned) > 0:
2086
raise errors.PathsNotVersionedError(not_versioned)
2049
all_versioned = False
2051
if not all_versioned:
2052
raise errors.PathsNotVersionedError(specific_files)
2087
2053
# -- remove redundancy in supplied specific_files to prevent over-scanning --
2088
search_specific_files = osutils.minimum_path_selection(specific_files)
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)
2090
2060
use_filesystem_for_exec = (sys.platform != 'win32')
2091
2061
iter_changes = self.target._iter_changes(include_unchanged,
2103
2073
(revisiontree.RevisionTree, DirStateRevisionTree)):
2105
2075
# the source revid must be in the target dirstate
2106
if not (source._revision_id == _mod_revision.NULL_REVISION or
2076
if not (source._revision_id == NULL_REVISION or
2107
2077
source._revision_id in target.get_parent_ids()):
2108
2078
# TODO: what about ghosts? it may well need to
2109
2079
# check for them explicitly.