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
56
from bzrlib.lock import LogicalLockResult
73
from bzrlib.inventory import InventoryEntry, Inventory, ROOT_ID, entry_factory
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."
568
592
return _mod_revision.NULL_REVISION
570
594
def lock_read(self):
571
"""See Branch.lock_read, and WorkingTree.unlock.
573
:return: A bzrlib.lock.LogicalLockResult.
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()
614
return LogicalLockResult(self.unlock)
616
635
def lock_tree_write(self):
617
"""See MutableTree.lock_tree_write, and WorkingTree.unlock.
619
:return: A bzrlib.lock.LogicalLockResult.
636
"""See MutableTree.lock_tree_write, and WorkingTree.unlock."""
621
637
self.branch.lock_read()
622
return self._lock_self_write()
638
self._lock_self_write()
624
640
def lock_write(self):
625
"""See MutableTree.lock_write, and WorkingTree.unlock.
627
:return: A bzrlib.lock.LogicalLockResult.
641
"""See MutableTree.lock_write, and WorkingTree.unlock."""
629
642
self.branch.lock_write()
630
return self._lock_self_write()
643
self._lock_self_write()
632
645
@needs_tree_write_lock
633
646
def move(self, from_paths, to_dir, after=False):
1038
1051
def set_last_revision(self, new_revision):
1039
1052
"""Change the last revision in the working tree."""
1040
1053
parents = self.get_parent_ids()
1041
if new_revision in (_mod_revision.NULL_REVISION, None):
1054
if new_revision in (NULL_REVISION, None):
1042
1055
if len(parents) >= 2:
1043
1056
raise AssertionError(
1044
1057
"setting the last parent to none with a pending merge is "
1211
1224
# just forget the whole block.
1212
1225
entry_index = 0
1213
1226
while entry_index < len(block[1]):
1227
# Mark this file id as having been removed
1214
1228
entry = block[1][entry_index]
1215
if entry[1][0][0] in 'ar':
1216
# 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)):
1217
1233
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.
1224
1234
# go to the next block. (At the moment we dont delete empty
1226
1236
block_index += 1
1278
1288
if self._dirty:
1279
1289
raise AssertionError("attempting to write an inventory when the "
1280
1290
"dirstate is dirty will lose pending changes")
1281
had_inventory = self._inventory is not None
1282
# Setting self._inventory = None forces the dirstate to regenerate the
1283
# working inventory. We do this because self.inventory may be inv, or
1284
# may have been modified, and either case would prevent a clean delta
1286
self._inventory = None
1288
delta = inv._make_delta(self.inventory)
1290
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:
1292
1294
self._inventory = inv
1319
1321
return statvalue, sha1
1322
class ContentFilteringDirStateWorkingTree(DirStateWorkingTree):
1323
"""Dirstate working tree that supports content filtering.
1325
The dirstate holds the hash and size of the canonical form of the file,
1326
and most methods must return that.
1329
def _file_content_summary(self, path, stat_result):
1330
# This is to support the somewhat obsolete path_content_summary method
1331
# with content filtering: see
1332
# <https://bugs.edge.launchpad.net/bzr/+bug/415508>.
1334
# If the dirstate cache is up to date and knows the hash and size,
1336
# Otherwise if there are no content filters, return the on-disk size
1337
# and leave the hash blank.
1338
# Otherwise, read and filter the on-disk file and use its size and
1341
# The dirstate doesn't store the size of the canonical form so we
1342
# can't trust it for content-filtered trees. We just return None.
1343
dirstate_sha1 = self._dirstate.sha1_from_stat(path, stat_result)
1344
executable = self._is_executable_from_path_and_stat(path, stat_result)
1345
return ('file', None, executable, dirstate_sha1)
1348
1324
class WorkingTree4(DirStateWorkingTree):
1349
1325
"""This is the Format 4 working tree.
1385
1361
class DirStateWorkingTreeFormat(WorkingTreeFormat3):
1387
1362
def initialize(self, a_bzrdir, revision_id=None, from_branch=None,
1388
1363
accelerator_tree=None, hardlink=False):
1389
1364
"""See WorkingTreeFormat.initialize().
1428
1403
wt.lock_tree_write()
1430
1405
self._init_custom_control_files(wt)
1431
if revision_id in (None, _mod_revision.NULL_REVISION):
1406
if revision_id in (None, NULL_REVISION):
1432
1407
if branch.repository.supports_rich_root():
1433
1408
wt._set_root_id(generate_ids.gen_root_id())
1446
1421
if basis is None:
1447
1422
basis = branch.repository.revision_tree(revision_id)
1448
if revision_id == _mod_revision.NULL_REVISION:
1423
if revision_id == NULL_REVISION:
1449
1424
parents_list = []
1451
1426
parents_list = [(revision_id, basis)]
1459
1434
if basis_root_id is not None:
1460
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!
1443
# The original tree may not have the same content filters
1444
# applied so we can't safely build the inventory delta from
1462
1446
if wt.supports_content_filtering():
1463
# The original tree may not have the same content filters
1464
# applied so we can't safely build the inventory delta from
1447
accelerator_tree = None
1466
1448
delta_from_tree = False
1468
1450
delta_from_tree = True
1587
1569
class DirStateRevisionTree(Tree):
1588
"""A revision tree pulling the inventory from a dirstate.
1590
Note that this is one of the historical (ie revision) trees cached in the
1591
dirstate for easy access, not the workingtree.
1570
"""A revision tree pulling the inventory from a dirstate."""
1594
1572
def __init__(self, dirstate, revision_id, repository):
1595
1573
self._dirstate = dirstate
1768
1746
parent_index = self._get_parent_index()
1769
1747
last_changed_revision = entry[1][parent_index][4]
1771
rev = self._repository.get_revision(last_changed_revision)
1772
except errors.NoSuchRevision:
1773
raise errors.FileTimestampUnavailable(self.id2path(file_id))
1774
return rev.timestamp
1748
return self._repository.get_revision(last_changed_revision).timestamp
1776
1750
def get_file_sha1(self, file_id, path=None, stat_value=None):
1777
1751
entry = self._get_entry(file_id=file_id, path=path)
1844
1818
entry = self._get_entry(file_id=file_id)[1]
1845
1819
if entry is None:
1846
1820
raise errors.NoSuchId(tree=self, file_id=file_id)
1847
parent_index = self._get_parent_index()
1848
return dirstate.DirState._minikind_to_kind[entry[parent_index][0]]
1821
return dirstate.DirState._minikind_to_kind[entry[1][0]]
1850
1823
def stored_kind(self, file_id):
1851
1824
"""See Tree.stored_kind"""
1872
1845
return ie.executable
1874
def is_locked(self):
1877
1847
def list_files(self, include_root=False, from_dir=None, recursive=True):
1878
1848
# We use a standard implementation, because DirStateRevisionTree is
1879
1849
# dealing with one of the parents of the current state
1892
1862
yield path, 'V', entry.kind, entry.file_id, entry
1894
1864
def lock_read(self):
1895
"""Lock the tree for a set of operations.
1897
:return: A bzrlib.lock.LogicalLockResult.
1865
"""Lock the tree for a set of operations."""
1899
1866
if not self._locked:
1900
1867
self._repository.lock_read()
1901
1868
if self._dirstate._lock_token is None:
1902
1869
self._dirstate.lock_read()
1903
1870
self._dirstate_locked = True
1904
1871
self._locked += 1
1905
return LogicalLockResult(self.unlock)
1907
1873
def _must_be_locked(self):
1908
1874
if not self._locked:
2001
def make_source_parent_tree_compiled_dirstate(klass, test_case, source,
1967
def make_source_parent_tree_compiled_dirstate(klass, test_case, source, target):
2003
1968
from bzrlib.tests.test__dirstate_helpers import \
2004
compiled_dirstate_helpers_feature
2005
test_case.requireFeature(compiled_dirstate_helpers_feature)
1969
CompiledDirstateHelpersFeature
1970
if not CompiledDirstateHelpersFeature.available():
1971
from bzrlib.tests import UnavailableFeature
1972
raise UnavailableFeature(CompiledDirstateHelpersFeature)
2006
1973
from bzrlib._dirstate_helpers_pyx import ProcessEntryC
2007
1974
result = klass.make_source_parent_tree(source, target)
2008
1975
result[1]._iter_changes = ProcessEntryC
2039
2006
output. An unversioned file is defined as one with (False, False)
2040
2007
for the versioned pair.
2009
# NB: show_status depends on being able to pass in non-versioned files
2010
# and report them as unknown
2042
2011
# TODO: handle extra trees in the dirstate.
2043
2012
if (extra_trees or specific_files == []):
2044
2013
# we can't fast-path these cases (yet)
2047
2016
require_versioned, want_unversioned=want_unversioned)
2048
2017
parent_ids = self.target.get_parent_ids()
2049
2018
if not (self.source._revision_id in parent_ids
2050
or self.source._revision_id == _mod_revision.NULL_REVISION):
2019
or self.source._revision_id == NULL_REVISION):
2051
2020
raise AssertionError(
2052
2021
"revision {%s} is not stored in {%s}, but %s "
2053
2022
"can only be used for trees stored in the dirstate"
2054
2023
% (self.source._revision_id, self.target, self.iter_changes))
2055
2024
target_index = 0
2056
if self.source._revision_id == _mod_revision.NULL_REVISION:
2025
if self.source._revision_id == NULL_REVISION:
2057
2026
source_index = None
2058
2027
indices = (target_index,)
2121
2090
(revisiontree.RevisionTree, DirStateRevisionTree)):
2123
2092
# the source revid must be in the target dirstate
2124
if not (source._revision_id == _mod_revision.NULL_REVISION or
2093
if not (source._revision_id == NULL_REVISION or
2125
2094
source._revision_id in target.get_parent_ids()):
2126
2095
# TODO: what about ghosts? it may well need to
2127
2096
# check for them explicitly.