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
1382
1403
wt.lock_tree_write()
1384
1405
self._init_custom_control_files(wt)
1385
if revision_id in (None, _mod_revision.NULL_REVISION):
1406
if revision_id in (None, NULL_REVISION):
1386
1407
if branch.repository.supports_rich_root():
1387
1408
wt._set_root_id(generate_ids.gen_root_id())
1400
1421
if basis is None:
1401
1422
basis = branch.repository.revision_tree(revision_id)
1402
if revision_id == _mod_revision.NULL_REVISION:
1423
if revision_id == NULL_REVISION:
1403
1424
parents_list = []
1405
1426
parents_list = [(revision_id, basis)]
1413
1434
if basis_root_id is not None:
1414
1435
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
if wt.supports_content_filtering():
1427
# see https://bugs.edge.launchpad.net/bzr/+bug/408193
1428
trace.warning("hardlinking working copy files is not currently "
1429
"supported in %r" % (wt,))
1430
accelerator_tree = None
1431
delta_from_tree = False
1433
delta_from_tree = True
1434
1437
# delta_from_tree is safe even for DirStateRevisionTrees,
1435
1438
# because wt4.apply_inventory_delta does not mutate the input
1436
1439
# inventory entries.
1437
1440
transform.build_tree(basis, wt, accelerator_tree,
1439
delta_from_tree=delta_from_tree)
1441
hardlink=hardlink, delta_from_tree=True)
1828
1830
return ie.executable
1830
def list_files(self, include_root=False, from_dir=None, recursive=True):
1832
def list_files(self, include_root=False):
1831
1833
# We use a standard implementation, because DirStateRevisionTree is
1832
1834
# dealing with one of the parents of the current state
1833
1835
inv = self._get_inventory()
1834
if from_dir is None:
1837
from_dir_id = inv.path2id(from_dir)
1838
if from_dir_id is None:
1839
# Directory not versioned
1841
entries = inv.iter_entries(from_dir=from_dir_id, recursive=recursive)
1842
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:
1844
1839
for path, entry in entries:
1845
1840
yield path, 'V', entry.kind, entry.file_id, entry
1953
1948
if not CompiledDirstateHelpersFeature.available():
1954
1949
from bzrlib.tests import UnavailableFeature
1955
1950
raise UnavailableFeature(CompiledDirstateHelpersFeature)
1956
from bzrlib._dirstate_helpers_pyx import ProcessEntryC
1951
from bzrlib._dirstate_helpers_c import ProcessEntryC
1957
1952
result = klass.make_source_parent_tree(source, target)
1958
1953
result[1]._iter_changes = ProcessEntryC
1999
1994
require_versioned, want_unversioned=want_unversioned)
2000
1995
parent_ids = self.target.get_parent_ids()
2001
1996
if not (self.source._revision_id in parent_ids
2002
or self.source._revision_id == _mod_revision.NULL_REVISION):
1997
or self.source._revision_id == NULL_REVISION):
2003
1998
raise AssertionError(
2004
1999
"revision {%s} is not stored in {%s}, but %s "
2005
2000
"can only be used for trees stored in the dirstate"
2006
2001
% (self.source._revision_id, self.target, self.iter_changes))
2007
2002
target_index = 0
2008
if self.source._revision_id == _mod_revision.NULL_REVISION:
2003
if self.source._revision_id == NULL_REVISION:
2009
2004
source_index = None
2010
2005
indices = (target_index,)
2027
2022
specific_files = set([''])
2028
2023
# -- specific_files is now a utf8 path set --
2024
search_specific_files = set()
2030
2025
# -- get the state object and prepare it.
2031
2026
state = self.target.current_dirstate()
2032
2027
state._read_dirblocks_if_needed()
2033
2028
if require_versioned:
2034
2029
# -- check all supplied paths are versioned in a search tree. --
2030
all_versioned = True
2036
2031
for path in specific_files:
2037
2032
path_entries = state._entries_for_path(path)
2038
2033
if not path_entries:
2039
2034
# this specified path is not present at all: error
2040
not_versioned.append(path)
2035
all_versioned = False
2042
2037
found_versioned = False
2043
2038
# for each id at this path
2044
2039
for entry in path_entries:
2051
2046
if not found_versioned:
2052
2047
# none of the indexes was not 'absent' at all ids for this
2054
not_versioned.append(path)
2055
if len(not_versioned) > 0:
2056
raise errors.PathsNotVersionedError(not_versioned)
2049
all_versioned = False
2051
if not all_versioned:
2052
raise errors.PathsNotVersionedError(specific_files)
2057
2053
# -- remove redundancy in supplied specific_files to prevent over-scanning --
2058
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)
2060
2060
use_filesystem_for_exec = (sys.platform != 'win32')
2061
2061
iter_changes = self.target._iter_changes(include_unchanged,
2073
2073
(revisiontree.RevisionTree, DirStateRevisionTree)):
2075
2075
# the source revid must be in the target dirstate
2076
if not (source._revision_id == _mod_revision.NULL_REVISION or
2076
if not (source._revision_id == NULL_REVISION or
2077
2077
source._revision_id in target.get_parent_ids()):
2078
2078
# TODO: what about ghosts? it may well need to
2079
2079
# check for them explicitly.