1
# Copyright (C) 2007-2010 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
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
322
351
parent_ies[(dirname + '/' + name).strip('/')] = inv_entry
323
352
elif kind == 'tree-reference':
324
353
if not self._repo_supports_tree_reference:
325
raise errors.UnsupportedOperation(
326
self._generate_inventory,
327
self.branch.repository)
354
raise AssertionError(
356
"doesn't support tree references "
357
"required by entry %r"
328
359
inv_entry.reference_revision = link_or_sha1 or None
329
360
elif kind != 'symlink':
330
361
raise AssertionError("unknown kind %r" % kind)
435
466
return osutils.lexists(pathjoin(
436
467
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
470
def id2path(self, file_id):
445
471
"Convert a file-id to a path."
568
594
return _mod_revision.NULL_REVISION
570
596
def lock_read(self):
571
"""See Branch.lock_read, and WorkingTree.unlock.
573
:return: A bzrlib.lock.LogicalLockResult.
597
"""See Branch.lock_read, and WorkingTree.unlock."""
575
598
self.branch.lock_read()
577
600
self._control_files.lock_read()
612
634
self.branch.unlock()
614
return LogicalLockResult(self.unlock)
616
637
def lock_tree_write(self):
617
"""See MutableTree.lock_tree_write, and WorkingTree.unlock.
619
:return: A bzrlib.lock.LogicalLockResult.
638
"""See MutableTree.lock_tree_write, and WorkingTree.unlock."""
621
639
self.branch.lock_read()
622
return self._lock_self_write()
640
self._lock_self_write()
624
642
def lock_write(self):
625
"""See MutableTree.lock_write, and WorkingTree.unlock.
627
:return: A bzrlib.lock.LogicalLockResult.
643
"""See MutableTree.lock_write, and WorkingTree.unlock."""
629
644
self.branch.lock_write()
630
return self._lock_self_write()
645
self._lock_self_write()
632
647
@needs_tree_write_lock
633
648
def move(self, from_paths, to_dir, after=False):
703
718
from_entry = self._get_entry(path=from_rel)
704
719
if from_entry == (None, None):
705
720
raise errors.BzrMoveFailedError(from_rel,to_dir,
706
errors.NotVersionedError(path=from_rel))
721
errors.NotVersionedError(path=str(from_rel)))
708
723
from_id = from_entry[0][2]
709
724
to_rel = pathjoin(to_dir, from_tail)
1038
1053
def set_last_revision(self, new_revision):
1039
1054
"""Change the last revision in the working tree."""
1040
1055
parents = self.get_parent_ids()
1041
if new_revision in (_mod_revision.NULL_REVISION, None):
1056
if new_revision in (NULL_REVISION, None):
1042
1057
if len(parents) >= 2:
1043
1058
raise AssertionError(
1044
1059
"setting the last parent to none with a pending merge is "
1211
1226
# just forget the whole block.
1212
1227
entry_index = 0
1213
1228
while entry_index < len(block[1]):
1229
# Mark this file id as having been removed
1214
1230
entry = block[1][entry_index]
1215
if entry[1][0][0] in 'ar':
1216
# don't remove absent or renamed entries
1231
ids_to_unversion.discard(entry[0][2])
1232
if (entry[1][0][0] in 'ar' # don't remove absent or renamed
1234
or not state._make_absent(entry)):
1217
1235
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
1236
# go to the next block. (At the moment we dont delete empty
1226
1238
block_index += 1
1278
1290
if self._dirty:
1279
1291
raise AssertionError("attempting to write an inventory when the "
1280
1292
"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)
1293
self.current_dirstate().set_state_from_inventory(inv)
1294
self._make_dirty(reset_inventory=False)
1295
if self._inventory is not None:
1292
1296
self._inventory = inv
1299
1303
self.tree = tree
1301
1305
def sha1(self, abspath):
1302
"""See dirstate.SHA1Provider.sha1()."""
1303
filters = self.tree._content_filter_stack(
1304
self.tree.relpath(osutils.safe_unicode(abspath)))
1306
"""Return the sha1 of a file given its absolute path."""
1307
filters = self.tree._content_filter_stack(self.tree.relpath(abspath))
1305
1308
return internal_size_sha_file_byname(abspath, filters)[1]
1307
1310
def stat_and_sha1(self, abspath):
1308
"""See dirstate.SHA1Provider.stat_and_sha1()."""
1309
filters = self.tree._content_filter_stack(
1310
self.tree.relpath(osutils.safe_unicode(abspath)))
1311
"""Return the stat and sha1 of a file given its absolute path."""
1312
filters = self.tree._content_filter_stack(self.tree.relpath(abspath))
1311
1313
file_obj = file(abspath, 'rb', 65000)
1313
1315
statvalue = os.fstat(file_obj.fileno())
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.
1361
class WorkingTree5(ContentFilteringDirStateWorkingTree):
1337
class WorkingTree5(DirStateWorkingTree):
1362
1338
"""This is the Format 5 working tree.
1364
1340
This differs from WorkingTree4 by:
1365
1341
- Supporting content filtering.
1367
This is new in bzr 1.11.
1371
class WorkingTree6(ContentFilteringDirStateWorkingTree):
1372
"""This is the Format 6 working tree.
1374
This differs from WorkingTree5 by:
1375
1342
- Supporting a current view that may mask the set of files in a tree
1376
1343
impacted by most user operations.
1378
This is new in bzr 1.14.
1345
This is new in bzr 1.11.
1381
1348
def _make_views(self):
1385
1352
class DirStateWorkingTreeFormat(WorkingTreeFormat3):
1387
1353
def initialize(self, a_bzrdir, revision_id=None, from_branch=None,
1388
1354
accelerator_tree=None, hardlink=False):
1389
1355
"""See WorkingTreeFormat.initialize().
1428
1394
wt.lock_tree_write()
1430
1396
self._init_custom_control_files(wt)
1431
if revision_id in (None, _mod_revision.NULL_REVISION):
1397
if revision_id in (None, NULL_REVISION):
1432
1398
if branch.repository.supports_rich_root():
1433
1399
wt._set_root_id(generate_ids.gen_root_id())
1446
1412
if basis is None:
1447
1413
basis = branch.repository.revision_tree(revision_id)
1448
if revision_id == _mod_revision.NULL_REVISION:
1414
if revision_id == NULL_REVISION:
1449
1415
parents_list = []
1451
1417
parents_list = [(revision_id, basis)]
1459
1425
if basis_root_id is not None:
1460
1426
wt._set_root_id(basis_root_id)
1462
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
1466
delta_from_tree = False
1468
delta_from_tree = True
1469
1428
# delta_from_tree is safe even for DirStateRevisionTrees,
1470
1429
# because wt4.apply_inventory_delta does not mutate the input
1471
1430
# inventory entries.
1472
1431
transform.build_tree(basis, wt, accelerator_tree,
1474
delta_from_tree=delta_from_tree)
1432
hardlink=hardlink, delta_from_tree=True)
1501
1459
_control_files=control_files)
1503
1461
def __get_matchingbzrdir(self):
1504
return self._get_matchingbzrdir()
1506
def _get_matchingbzrdir(self):
1507
"""Overrideable method to get a bzrdir for testing."""
1508
1462
# please test against something that will let us do tree references
1509
1463
return bzrdir.format_registry.make_bzrdir(
1510
1464
'dirstate-with-subtree')
1553
1507
"""See WorkingTreeFormat.get_format_description()."""
1554
1508
return "Working tree format 5"
1556
def supports_content_filtering(self):
1560
class WorkingTreeFormat6(DirStateWorkingTreeFormat):
1561
"""WorkingTree format supporting views.
1564
upgrade_recommended = False
1566
_tree_class = WorkingTree6
1568
def get_format_string(self):
1569
"""See WorkingTreeFormat.get_format_string()."""
1570
return "Bazaar Working Tree Format 6 (bzr 1.14)\n"
1572
def get_format_description(self):
1573
"""See WorkingTreeFormat.get_format_description()."""
1574
return "Working tree format 6"
1576
1510
def _init_custom_control_files(self, wt):
1577
1511
"""Subclasses with custom control files should override this method."""
1578
1512
wt._transport.put_bytes('views', '', mode=wt.bzrdir._get_file_mode())
1587
1521
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.
1522
"""A revision tree pulling the inventory from a dirstate."""
1594
1524
def __init__(self, dirstate, revision_id, repository):
1595
1525
self._dirstate = dirstate
1768
1698
parent_index = self._get_parent_index()
1769
1699
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
1700
return self._repository.get_revision(last_changed_revision).timestamp
1776
1702
def get_file_sha1(self, file_id, path=None, stat_value=None):
1777
1703
entry = self._get_entry(file_id=file_id, path=path)
1789
1715
return self.inventory[file_id].text_size
1791
1717
def get_file_text(self, file_id, path=None):
1792
_, content = list(self.iter_files_bytes([(file_id, None)]))[0]
1793
return ''.join(content)
1718
return list(self.iter_files_bytes([(file_id, None)]))[0][1]
1795
1720
def get_reference_revision(self, file_id, path=None):
1796
1721
return self.inventory[file_id].reference_revision
1815
1740
if entry[1][parent_index][0] != 'l':
1818
target = entry[1][parent_index][1]
1819
target = target.decode('utf8')
1743
# At present, none of the tree implementations supports non-ascii
1744
# symlink targets. So we will just assume that the dirstate path is
1746
return entry[1][parent_index][1]
1822
1748
def get_revision_id(self):
1823
1749
"""Return the revision id for this tree."""
1844
1770
entry = self._get_entry(file_id=file_id)[1]
1845
1771
if entry is None:
1846
1772
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]]
1773
return dirstate.DirState._minikind_to_kind[entry[1][0]]
1850
1775
def stored_kind(self, file_id):
1851
1776
"""See Tree.stored_kind"""
1872
1797
return ie.executable
1874
def is_locked(self):
1877
def list_files(self, include_root=False, from_dir=None, recursive=True):
1799
def list_files(self, include_root=False):
1878
1800
# We use a standard implementation, because DirStateRevisionTree is
1879
1801
# dealing with one of the parents of the current state
1880
1802
inv = self._get_inventory()
1881
if from_dir is None:
1884
from_dir_id = inv.path2id(from_dir)
1885
if from_dir_id is None:
1886
# Directory not versioned
1888
entries = inv.iter_entries(from_dir=from_dir_id, recursive=recursive)
1889
if inv.root is not None and not include_root and from_dir is None:
1803
entries = inv.iter_entries()
1804
if self.inventory.root is not None and not include_root:
1891
1806
for path, entry in entries:
1892
1807
yield path, 'V', entry.kind, entry.file_id, entry
1894
1809
def lock_read(self):
1895
"""Lock the tree for a set of operations.
1897
:return: A bzrlib.lock.LogicalLockResult.
1810
"""Lock the tree for a set of operations."""
1899
1811
if not self._locked:
1900
1812
self._repository.lock_read()
1901
1813
if self._dirstate._lock_token is None:
1902
1814
self._dirstate.lock_read()
1903
1815
self._dirstate_locked = True
1904
1816
self._locked += 1
1905
return LogicalLockResult(self.unlock)
1907
1818
def _must_be_locked(self):
1908
1819
if not self._locked:
2001
def make_source_parent_tree_compiled_dirstate(klass, test_case, source,
1912
def make_source_parent_tree_compiled_dirstate(klass, test_case, source, target):
2003
1913
from bzrlib.tests.test__dirstate_helpers import \
2004
compiled_dirstate_helpers_feature
2005
test_case.requireFeature(compiled_dirstate_helpers_feature)
2006
from bzrlib._dirstate_helpers_pyx import ProcessEntryC
1914
CompiledDirstateHelpersFeature
1915
if not CompiledDirstateHelpersFeature.available():
1916
from bzrlib.tests import UnavailableFeature
1917
raise UnavailableFeature(CompiledDirstateHelpersFeature)
1918
from bzrlib._dirstate_helpers_c import ProcessEntryC
2007
1919
result = klass.make_source_parent_tree(source, target)
2008
1920
result[1]._iter_changes = ProcessEntryC
2039
1951
output. An unversioned file is defined as one with (False, False)
2040
1952
for the versioned pair.
1954
# NB: show_status depends on being able to pass in non-versioned files
1955
# and report them as unknown
2042
1956
# TODO: handle extra trees in the dirstate.
2043
1957
if (extra_trees or specific_files == []):
2044
1958
# we can't fast-path these cases (yet)
2047
1961
require_versioned, want_unversioned=want_unversioned)
2048
1962
parent_ids = self.target.get_parent_ids()
2049
1963
if not (self.source._revision_id in parent_ids
2050
or self.source._revision_id == _mod_revision.NULL_REVISION):
1964
or self.source._revision_id == NULL_REVISION):
2051
1965
raise AssertionError(
2052
1966
"revision {%s} is not stored in {%s}, but %s "
2053
1967
"can only be used for trees stored in the dirstate"
2054
1968
% (self.source._revision_id, self.target, self.iter_changes))
2055
1969
target_index = 0
2056
if self.source._revision_id == _mod_revision.NULL_REVISION:
1970
if self.source._revision_id == NULL_REVISION:
2057
1971
source_index = None
2058
1972
indices = (target_index,)
2075
1989
specific_files = set([''])
2076
1990
# -- specific_files is now a utf8 path set --
1991
search_specific_files = set()
2078
1992
# -- get the state object and prepare it.
2079
1993
state = self.target.current_dirstate()
2080
1994
state._read_dirblocks_if_needed()
2081
1995
if require_versioned:
2082
1996
# -- check all supplied paths are versioned in a search tree. --
1997
all_versioned = True
2084
1998
for path in specific_files:
2085
1999
path_entries = state._entries_for_path(path)
2086
2000
if not path_entries:
2087
2001
# this specified path is not present at all: error
2088
not_versioned.append(path)
2002
all_versioned = False
2090
2004
found_versioned = False
2091
2005
# for each id at this path
2092
2006
for entry in path_entries:
2099
2013
if not found_versioned:
2100
2014
# none of the indexes was not 'absent' at all ids for this
2102
not_versioned.append(path)
2103
if len(not_versioned) > 0:
2104
raise errors.PathsNotVersionedError(not_versioned)
2016
all_versioned = False
2018
if not all_versioned:
2019
raise errors.PathsNotVersionedError(specific_files)
2105
2020
# -- remove redundancy in supplied specific_files to prevent over-scanning --
2106
search_specific_files = osutils.minimum_path_selection(specific_files)
2021
for path in specific_files:
2022
other_specific_files = specific_files.difference(set([path]))
2023
if not osutils.is_inside_any(other_specific_files, path):
2024
# this is a top level path, we must check it.
2025
search_specific_files.add(path)
2108
2027
use_filesystem_for_exec = (sys.platform != 'win32')
2109
2028
iter_changes = self.target._iter_changes(include_unchanged,
2121
2040
(revisiontree.RevisionTree, DirStateRevisionTree)):
2123
2042
# the source revid must be in the target dirstate
2124
if not (source._revision_id == _mod_revision.NULL_REVISION or
2043
if not (source._revision_id == NULL_REVISION or
2125
2044
source._revision_id in target.get_parent_ids()):
2126
2045
# TODO: what about ghosts? it may well need to
2127
2046
# check for them explicitly.
2188
2107
# tree during upgrade.
2189
2108
tree._control_files.lock_write()
2191
self.update_format(tree)
2193
tree._control_files.unlock()
2195
def update_format(self, tree):
2196
"""Change the format marker."""
2197
tree._transport.put_bytes('format',
2198
self.target_format.get_format_string(),
2199
mode=tree.bzrdir._get_file_mode())
2202
class Converter4or5to6(object):
2203
"""Perform an in-place upgrade of format 4 or 5 to format 6 trees."""
2206
self.target_format = WorkingTreeFormat6()
2208
def convert(self, tree):
2209
# lock the control files not the tree, so that we don't get tree
2210
# on-unlock behaviours, and so that no-one else diddles with the
2211
# tree during upgrade.
2212
tree._control_files.lock_write()
2214
2110
self.init_custom_control_files(tree)
2215
2111
self.update_format(tree)