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
73
from bzrlib.inventory import InventoryEntry, Inventory, ROOT_ID, entry_factory
74
import bzrlib.mutabletree
56
75
from bzrlib.mutabletree import needs_tree_write_lock
57
76
from bzrlib.osutils import (
64
from bzrlib.trace import mutter
86
from bzrlib.trace import mutter, note
65
87
from bzrlib.transport.local import LocalTransport
66
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,
67
97
from bzrlib.tree import Tree
68
98
from bzrlib.workingtree import WorkingTree, WorkingTree3, WorkingTreeFormat3
321
351
parent_ies[(dirname + '/' + name).strip('/')] = inv_entry
322
352
elif kind == 'tree-reference':
323
353
if not self._repo_supports_tree_reference:
324
raise errors.UnsupportedOperation(
325
self._generate_inventory,
326
self.branch.repository)
354
raise AssertionError(
356
"doesn't support tree references "
357
"required by entry %r"
327
359
inv_entry.reference_revision = link_or_sha1 or None
328
360
elif kind != 'symlink':
329
361
raise AssertionError("unknown kind %r" % kind)
434
466
return osutils.lexists(pathjoin(
435
467
self.basedir, row[0].decode('utf8'), row[1].decode('utf8')))
437
def has_or_had_id(self, file_id):
438
state = self.current_dirstate()
439
row, parents = self._get_entry(file_id=file_id)
440
return row is not None
443
470
def id2path(self, file_id):
444
471
"Convert a file-id to a path."
567
594
return _mod_revision.NULL_REVISION
569
596
def lock_read(self):
570
"""See Branch.lock_read, and WorkingTree.unlock.
572
:return: An object with an unlock method which will release the lock
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()
616
637
def lock_tree_write(self):
617
"""See MutableTree.lock_tree_write, and WorkingTree.unlock.
619
:return: An object with an unlock method which will release the lock
638
"""See MutableTree.lock_tree_write, and WorkingTree.unlock."""
622
639
self.branch.lock_read()
623
return self._lock_self_write()
640
self._lock_self_write()
625
642
def lock_write(self):
626
"""See MutableTree.lock_write, and WorkingTree.unlock.
628
:return: An object with an unlock method which will release the lock
643
"""See MutableTree.lock_write, and WorkingTree.unlock."""
631
644
self.branch.lock_write()
632
return self._lock_self_write()
645
self._lock_self_write()
634
647
@needs_tree_write_lock
635
648
def move(self, from_paths, to_dir, after=False):
705
718
from_entry = self._get_entry(path=from_rel)
706
719
if from_entry == (None, None):
707
720
raise errors.BzrMoveFailedError(from_rel,to_dir,
708
errors.NotVersionedError(path=from_rel))
721
errors.NotVersionedError(path=str(from_rel)))
710
723
from_id = from_entry[0][2]
711
724
to_rel = pathjoin(to_dir, from_tail)
1040
1053
def set_last_revision(self, new_revision):
1041
1054
"""Change the last revision in the working tree."""
1042
1055
parents = self.get_parent_ids()
1043
if new_revision in (_mod_revision.NULL_REVISION, None):
1056
if new_revision in (NULL_REVISION, None):
1044
1057
if len(parents) >= 2:
1045
1058
raise AssertionError(
1046
1059
"setting the last parent to none with a pending merge is "
1213
1226
# just forget the whole block.
1214
1227
entry_index = 0
1215
1228
while entry_index < len(block[1]):
1229
# Mark this file id as having been removed
1216
1230
entry = block[1][entry_index]
1217
if entry[1][0][0] in 'ar':
1218
# 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)):
1219
1235
entry_index += 1
1221
# Mark this file id as having been removed
1222
ids_to_unversion.discard(entry[0][2])
1223
if not state._make_absent(entry):
1224
# The block has not shrunk.
1226
1236
# go to the next block. (At the moment we dont delete empty
1228
1238
block_index += 1
1280
1290
if self._dirty:
1281
1291
raise AssertionError("attempting to write an inventory when the "
1282
1292
"dirstate is dirty will lose pending changes")
1283
had_inventory = self._inventory is not None
1284
# Setting self._inventory = None forces the dirstate to regenerate the
1285
# working inventory. We do this because self.inventory may be inv, or
1286
# may have been modified, and either case would prevent a clean delta
1288
self._inventory = None
1290
delta = inv._make_delta(self.inventory)
1292
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:
1294
1296
self._inventory = inv
1301
1303
self.tree = tree
1303
1305
def sha1(self, abspath):
1304
"""See dirstate.SHA1Provider.sha1()."""
1305
filters = self.tree._content_filter_stack(
1306
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))
1307
1308
return internal_size_sha_file_byname(abspath, filters)[1]
1309
1310
def stat_and_sha1(self, abspath):
1310
"""See dirstate.SHA1Provider.stat_and_sha1()."""
1311
filters = self.tree._content_filter_stack(
1312
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))
1313
1313
file_obj = file(abspath, 'rb', 65000)
1315
1315
statvalue = os.fstat(file_obj.fileno())
1321
1321
return statvalue, sha1
1324
class ContentFilteringDirStateWorkingTree(DirStateWorkingTree):
1325
"""Dirstate working tree that supports content filtering.
1327
The dirstate holds the hash and size of the canonical form of the file,
1328
and most methods must return that.
1331
def _file_content_summary(self, path, stat_result):
1332
# This is to support the somewhat obsolete path_content_summary method
1333
# with content filtering: see
1334
# <https://bugs.edge.launchpad.net/bzr/+bug/415508>.
1336
# If the dirstate cache is up to date and knows the hash and size,
1338
# Otherwise if there are no content filters, return the on-disk size
1339
# and leave the hash blank.
1340
# Otherwise, read and filter the on-disk file and use its size and
1343
# The dirstate doesn't store the size of the canonical form so we
1344
# can't trust it for content-filtered trees. We just return None.
1345
dirstate_sha1 = self._dirstate.sha1_from_stat(path, stat_result)
1346
executable = self._is_executable_from_path_and_stat(path, stat_result)
1347
return ('file', None, executable, dirstate_sha1)
1350
1324
class WorkingTree4(DirStateWorkingTree):
1351
1325
"""This is the Format 4 working tree.
1363
class WorkingTree5(ContentFilteringDirStateWorkingTree):
1337
class WorkingTree5(DirStateWorkingTree):
1364
1338
"""This is the Format 5 working tree.
1366
1340
This differs from WorkingTree4 by:
1367
1341
- Supporting content filtering.
1369
This is new in bzr 1.11.
1373
class WorkingTree6(ContentFilteringDirStateWorkingTree):
1374
"""This is the Format 6 working tree.
1376
This differs from WorkingTree5 by:
1377
1342
- Supporting a current view that may mask the set of files in a tree
1378
1343
impacted by most user operations.
1380
This is new in bzr 1.14.
1345
This is new in bzr 1.11.
1383
1348
def _make_views(self):
1387
1352
class DirStateWorkingTreeFormat(WorkingTreeFormat3):
1389
1353
def initialize(self, a_bzrdir, revision_id=None, from_branch=None,
1390
1354
accelerator_tree=None, hardlink=False):
1391
1355
"""See WorkingTreeFormat.initialize().
1430
1394
wt.lock_tree_write()
1432
1396
self._init_custom_control_files(wt)
1433
if revision_id in (None, _mod_revision.NULL_REVISION):
1397
if revision_id in (None, NULL_REVISION):
1434
1398
if branch.repository.supports_rich_root():
1435
1399
wt._set_root_id(generate_ids.gen_root_id())
1448
1412
if basis is None:
1449
1413
basis = branch.repository.revision_tree(revision_id)
1450
if revision_id == _mod_revision.NULL_REVISION:
1414
if revision_id == NULL_REVISION:
1451
1415
parents_list = []
1453
1417
parents_list = [(revision_id, basis)]
1461
1425
if basis_root_id is not None:
1462
1426
wt._set_root_id(basis_root_id)
1464
if wt.supports_content_filtering():
1465
# The original tree may not have the same content filters
1466
# applied so we can't safely build the inventory delta from
1468
delta_from_tree = False
1470
delta_from_tree = True
1471
1428
# delta_from_tree is safe even for DirStateRevisionTrees,
1472
1429
# because wt4.apply_inventory_delta does not mutate the input
1473
1430
# inventory entries.
1474
1431
transform.build_tree(basis, wt, accelerator_tree,
1476
delta_from_tree=delta_from_tree)
1432
hardlink=hardlink, delta_from_tree=True)
1503
1459
_control_files=control_files)
1505
1461
def __get_matchingbzrdir(self):
1506
return self._get_matchingbzrdir()
1508
def _get_matchingbzrdir(self):
1509
"""Overrideable method to get a bzrdir for testing."""
1510
1462
# please test against something that will let us do tree references
1511
1463
return bzrdir.format_registry.make_bzrdir(
1512
1464
'dirstate-with-subtree')
1555
1507
"""See WorkingTreeFormat.get_format_description()."""
1556
1508
return "Working tree format 5"
1558
def supports_content_filtering(self):
1562
class WorkingTreeFormat6(DirStateWorkingTreeFormat):
1563
"""WorkingTree format supporting views.
1566
upgrade_recommended = False
1568
_tree_class = WorkingTree6
1570
def get_format_string(self):
1571
"""See WorkingTreeFormat.get_format_string()."""
1572
return "Bazaar Working Tree Format 6 (bzr 1.14)\n"
1574
def get_format_description(self):
1575
"""See WorkingTreeFormat.get_format_description()."""
1576
return "Working tree format 6"
1578
1510
def _init_custom_control_files(self, wt):
1579
1511
"""Subclasses with custom control files should override this method."""
1580
1512
wt._transport.put_bytes('views', '', mode=wt.bzrdir._get_file_mode())
1589
1521
class DirStateRevisionTree(Tree):
1590
"""A revision tree pulling the inventory from a dirstate.
1592
Note that this is one of the historical (ie revision) trees cached in the
1593
dirstate for easy access, not the workingtree.
1522
"""A revision tree pulling the inventory from a dirstate."""
1596
1524
def __init__(self, dirstate, revision_id, repository):
1597
1525
self._dirstate = dirstate
1770
1698
parent_index = self._get_parent_index()
1771
1699
last_changed_revision = entry[1][parent_index][4]
1773
rev = self._repository.get_revision(last_changed_revision)
1774
except errors.NoSuchRevision:
1775
raise errors.FileTimestampUnavailable(self.id2path(file_id))
1776
return rev.timestamp
1700
return self._repository.get_revision(last_changed_revision).timestamp
1778
1702
def get_file_sha1(self, file_id, path=None, stat_value=None):
1779
1703
entry = self._get_entry(file_id=file_id, path=path)
1791
1715
return self.inventory[file_id].text_size
1793
1717
def get_file_text(self, file_id, path=None):
1794
_, content = list(self.iter_files_bytes([(file_id, None)]))[0]
1795
return ''.join(content)
1718
return list(self.iter_files_bytes([(file_id, None)]))[0][1]
1797
1720
def get_reference_revision(self, file_id, path=None):
1798
1721
return self.inventory[file_id].reference_revision
1817
1740
if entry[1][parent_index][0] != 'l':
1820
target = entry[1][parent_index][1]
1821
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]
1824
1748
def get_revision_id(self):
1825
1749
"""Return the revision id for this tree."""
1846
1770
entry = self._get_entry(file_id=file_id)[1]
1847
1771
if entry is None:
1848
1772
raise errors.NoSuchId(tree=self, file_id=file_id)
1849
parent_index = self._get_parent_index()
1850
return dirstate.DirState._minikind_to_kind[entry[parent_index][0]]
1773
return dirstate.DirState._minikind_to_kind[entry[1][0]]
1852
1775
def stored_kind(self, file_id):
1853
1776
"""See Tree.stored_kind"""
1874
1797
return ie.executable
1876
def is_locked(self):
1879
def list_files(self, include_root=False, from_dir=None, recursive=True):
1799
def list_files(self, include_root=False):
1880
1800
# We use a standard implementation, because DirStateRevisionTree is
1881
1801
# dealing with one of the parents of the current state
1882
1802
inv = self._get_inventory()
1883
if from_dir is None:
1886
from_dir_id = inv.path2id(from_dir)
1887
if from_dir_id is None:
1888
# Directory not versioned
1890
entries = inv.iter_entries(from_dir=from_dir_id, recursive=recursive)
1891
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:
1893
1806
for path, entry in entries:
1894
1807
yield path, 'V', entry.kind, entry.file_id, entry
1896
1809
def lock_read(self):
1897
"""Lock the tree for a set of operations.
1899
:return: An object with an unlock method which will release the lock
1810
"""Lock the tree for a set of operations."""
1902
1811
if not self._locked:
1903
1812
self._repository.lock_read()
1904
1813
if self._dirstate._lock_token is None:
1905
1814
self._dirstate.lock_read()
1906
1815
self._dirstate_locked = True
1907
1816
self._locked += 1
1910
1818
def _must_be_locked(self):
1911
1819
if not self._locked:
2004
def make_source_parent_tree_compiled_dirstate(klass, test_case, source,
1912
def make_source_parent_tree_compiled_dirstate(klass, test_case, source, target):
2006
1913
from bzrlib.tests.test__dirstate_helpers import \
2007
compiled_dirstate_helpers_feature
2008
test_case.requireFeature(compiled_dirstate_helpers_feature)
2009
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
2010
1919
result = klass.make_source_parent_tree(source, target)
2011
1920
result[1]._iter_changes = ProcessEntryC
2042
1951
output. An unversioned file is defined as one with (False, False)
2043
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
2045
1956
# TODO: handle extra trees in the dirstate.
2046
1957
if (extra_trees or specific_files == []):
2047
1958
# we can't fast-path these cases (yet)
2050
1961
require_versioned, want_unversioned=want_unversioned)
2051
1962
parent_ids = self.target.get_parent_ids()
2052
1963
if not (self.source._revision_id in parent_ids
2053
or self.source._revision_id == _mod_revision.NULL_REVISION):
1964
or self.source._revision_id == NULL_REVISION):
2054
1965
raise AssertionError(
2055
1966
"revision {%s} is not stored in {%s}, but %s "
2056
1967
"can only be used for trees stored in the dirstate"
2057
1968
% (self.source._revision_id, self.target, self.iter_changes))
2058
1969
target_index = 0
2059
if self.source._revision_id == _mod_revision.NULL_REVISION:
1970
if self.source._revision_id == NULL_REVISION:
2060
1971
source_index = None
2061
1972
indices = (target_index,)
2078
1989
specific_files = set([''])
2079
1990
# -- specific_files is now a utf8 path set --
1991
search_specific_files = set()
2081
1992
# -- get the state object and prepare it.
2082
1993
state = self.target.current_dirstate()
2083
1994
state._read_dirblocks_if_needed()
2084
1995
if require_versioned:
2085
1996
# -- check all supplied paths are versioned in a search tree. --
1997
all_versioned = True
2087
1998
for path in specific_files:
2088
1999
path_entries = state._entries_for_path(path)
2089
2000
if not path_entries:
2090
2001
# this specified path is not present at all: error
2091
not_versioned.append(path)
2002
all_versioned = False
2093
2004
found_versioned = False
2094
2005
# for each id at this path
2095
2006
for entry in path_entries:
2102
2013
if not found_versioned:
2103
2014
# none of the indexes was not 'absent' at all ids for this
2105
not_versioned.append(path)
2106
if len(not_versioned) > 0:
2107
raise errors.PathsNotVersionedError(not_versioned)
2016
all_versioned = False
2018
if not all_versioned:
2019
raise errors.PathsNotVersionedError(specific_files)
2108
2020
# -- remove redundancy in supplied specific_files to prevent over-scanning --
2109
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)
2111
2027
use_filesystem_for_exec = (sys.platform != 'win32')
2112
2028
iter_changes = self.target._iter_changes(include_unchanged,
2124
2040
(revisiontree.RevisionTree, DirStateRevisionTree)):
2126
2042
# the source revid must be in the target dirstate
2127
if not (source._revision_id == _mod_revision.NULL_REVISION or
2043
if not (source._revision_id == NULL_REVISION or
2128
2044
source._revision_id in target.get_parent_ids()):
2129
2045
# TODO: what about ghosts? it may well need to
2130
2046
# check for them explicitly.
2191
2107
# tree during upgrade.
2192
2108
tree._control_files.lock_write()
2194
self.update_format(tree)
2196
tree._control_files.unlock()
2198
def update_format(self, tree):
2199
"""Change the format marker."""
2200
tree._transport.put_bytes('format',
2201
self.target_format.get_format_string(),
2202
mode=tree.bzrdir._get_file_mode())
2205
class Converter4or5to6(object):
2206
"""Perform an in-place upgrade of format 4 or 5 to format 6 trees."""
2209
self.target_format = WorkingTreeFormat6()
2211
def convert(self, tree):
2212
# lock the control files not the tree, so that we don't get tree
2213
# on-unlock behaviours, and so that no-one else diddles with the
2214
# tree during upgrade.
2215
tree._control_files.lock_write()
2217
2110
self.init_custom_control_files(tree)
2218
2111
self.update_format(tree)