1
# Copyright (C) 2007-2012 Canonical Ltd
1
# Copyright (C) 2007-2011 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
58
54
from bzrlib.lock import LogicalLockResult
59
55
from bzrlib.lockable_files import LockableFiles
60
56
from bzrlib.lockdir import LockDir
61
from bzrlib.mutabletree import (
63
needs_tree_write_lock,
57
from bzrlib.mutabletree import needs_tree_write_lock
65
58
from bzrlib.osutils import (
81
70
from bzrlib.workingtree import (
82
71
InventoryWorkingTree,
84
WorkingTreeFormatMetaDir,
88
77
class DirStateWorkingTree(InventoryWorkingTree):
79
_DEFAULT_WORTH_SAVING_LIMIT = 10
90
81
def __init__(self, basedir,
92
83
_control_files=None,
261
252
:return: an integer. -1 means never save.
263
conf = self.get_config_stack()
264
return conf.get('bzr.workingtree.worth_saving_limit')
254
config = self.branch.get_config()
255
val = config.get_user_option('bzr.workingtree.worth_saving_limit')
257
val = self._DEFAULT_WORTH_SAVING_LIMIT
261
except ValueError, e:
262
trace.warning('Invalid config value for'
263
' "bzr.workingtree.worth_saving_limit"'
264
' value %r is not an integer.'
266
val = self._DEFAULT_WORTH_SAVING_LIMIT
266
269
def filter_unversioned_files(self, paths):
267
270
"""Filter out paths that are versioned.
430
433
self._generate_inventory()
431
434
return self._inventory
433
@deprecated_method(deprecated_in((2, 5, 0)))
434
def _get_inventory(self):
435
return self.root_inventory
437
436
inventory = property(_get_inventory,
438
437
doc="Inventory of this Tree")
440
root_inventory = property(_get_root_inventory,
441
"Root inventory of this tree")
444
440
def get_parent_ids(self):
445
441
"""See Tree.get_parent_ids.
492
488
return False # Missing entries are not executable
493
489
return entry[1][0][3] # Executable?
495
def is_executable(self, file_id, path=None):
496
"""Test if a file is executable or not.
491
if not osutils.supports_executable():
492
def is_executable(self, file_id, path=None):
493
"""Test if a file is executable or not.
498
Note: The caller is expected to take a read-lock before calling this.
500
if not self._supports_executable():
495
Note: The caller is expected to take a read-lock before calling this.
501
497
entry = self._get_entry(file_id=file_id, path=path)
502
498
if entry == (None, None):
504
500
return entry[1][0][3]
502
_is_executable_from_path_and_stat = \
503
_is_executable_from_path_and_stat_from_basis
505
def is_executable(self, file_id, path=None):
506
"""Test if a file is executable or not.
508
Note: The caller is expected to take a read-lock before calling this.
506
510
self._must_be_locked()
508
512
path = self.id2path(file_id)
895
899
def path2id(self, path):
896
900
"""Return the id for path in this tree."""
897
if isinstance(path, list):
900
path = osutils.pathjoin(*path)
901
901
path = path.strip('/')
902
902
entry = self._get_entry(path=path)
903
903
if entry == (None, None):
981
981
all_versioned = False
983
983
if not all_versioned:
984
raise errors.PathsNotVersionedError(
985
[p.decode('utf-8') for p in paths])
984
raise errors.PathsNotVersionedError(paths)
986
985
# -- remove redundancy in supplied paths to prevent over-scanning --
987
986
search_paths = osutils.minimum_path_selection(paths)
1037
1036
found_dir_names = set(dir_name_id[:2] for dir_name_id in found)
1038
1037
for dir_name in split_paths:
1039
1038
if dir_name not in found_dir_names:
1040
raise errors.PathsNotVersionedError(
1041
[p.decode('utf-8') for p in paths])
1039
raise errors.PathsNotVersionedError(paths)
1043
1041
for dir_name_id, trees_info in found.iteritems():
1044
1042
for index in search_indexes:
1165
1163
# _make_delta if we can't get the RevisionTree
1168
delta = rev_tree.root_inventory._make_delta(
1169
basis_tree.root_inventory)
1166
delta = rev_tree.inventory._make_delta(basis_tree.inventory)
1170
1167
dirstate.update_basis_by_delta(delta, rev_id)
1172
1169
if not updated:
1369
1366
base_tree = trees[0][1]
1370
1367
state = self.current_dirstate()
1371
1368
# We don't support ghosts yet
1372
state.set_state_from_scratch(base_tree.root_inventory, trees, [])
1369
state.set_state_from_scratch(base_tree.inventory, trees, [])
1375
1372
class ContentFilterAwareSHA1Provider(dirstate.SHA1Provider):
1497
1494
control_files = self._open_control_files(a_bzrdir)
1498
1495
control_files.create_lock()
1499
1496
control_files.lock_write()
1500
transport.put_bytes('format', self.as_string(),
1497
transport.put_bytes('format', self.get_format_string(),
1501
1498
mode=a_bzrdir._get_file_mode())
1502
1499
if from_branch is not None:
1503
1500
branch = from_branch
1563
1560
transform.build_tree(basis, wt, accelerator_tree,
1564
1561
hardlink=hardlink,
1565
1562
delta_from_tree=delta_from_tree)
1566
for hook in MutableTree.hooks['post_build_tree']:
1613
1608
def _get_matchingbzrdir(self):
1614
1609
"""Overrideable method to get a bzrdir for testing."""
1615
1610
# please test against something that will let us do tree references
1616
return controldir.format_registry.make_bzrdir(
1617
'development-subtree')
1611
return bzrdir.format_registry.make_bzrdir(
1612
'dirstate-with-subtree')
1619
1614
_matchingbzrdir = property(__get_matchingbzrdir)
1626
1621
- exists within a metadir controlling .bzr
1627
1622
- includes an explicit version marker for the workingtree control
1628
files, separate from the ControlDir format
1623
files, separate from the BzrDir format
1629
1624
- modifies the hash cache format
1630
1625
- is new in bzr 0.15
1631
1626
- uses a LockDir to guard access to it.
1636
1631
_tree_class = WorkingTree4
1639
def get_format_string(cls):
1633
def get_format_string(self):
1640
1634
"""See WorkingTreeFormat.get_format_string()."""
1641
1635
return "Bazaar Working Tree Format 4 (bzr 0.15)\n"
1654
1648
_tree_class = WorkingTree5
1657
def get_format_string(cls):
1650
def get_format_string(self):
1658
1651
"""See WorkingTreeFormat.get_format_string()."""
1659
1652
return "Bazaar Working Tree Format 5 (bzr 1.11)\n"
1675
1668
_tree_class = WorkingTree6
1678
def get_format_string(cls):
1670
def get_format_string(self):
1679
1671
"""See WorkingTreeFormat.get_format_string()."""
1680
1672
return "Bazaar Working Tree Format 6 (bzr 1.14)\n"
1693
1685
def supports_views(self):
1696
def _get_matchingbzrdir(self):
1697
"""Overrideable method to get a bzrdir for testing."""
1698
# We use 'development-subtree' instead of '2a', because we have a
1699
# few tests that want to test tree references
1700
return bzrdir.format_registry.make_bzrdir('development-subtree')
1703
1689
class DirStateRevisionTree(InventoryTree):
1704
1690
"""A revision tree pulling the inventory from a dirstate.
1787
1773
if path is not None:
1788
1774
path = path.encode('utf8')
1789
1775
parent_index = self._get_parent_index()
1790
return self._dirstate._get_entry(parent_index, fileid_utf8=file_id,
1776
return self._dirstate._get_entry(parent_index, fileid_utf8=file_id, path_utf8=path)
1793
1778
def _generate_inventory(self):
1794
1779
"""Create and set self.inventory from the dirstate object.
1876
1861
# Make sure the file exists
1877
1862
entry = self._get_entry(file_id, path=path)
1878
1863
if entry == (None, None): # do we raise?
1879
raise errors.NoSuchId(self, file_id)
1880
1865
parent_index = self._get_parent_index()
1881
1866
last_changed_revision = entry[1][parent_index][4]
1896
1881
@needs_read_lock
1897
1882
def get_file_revision(self, file_id):
1898
inv, inv_file_id = self._unpack_file_id(file_id)
1899
return inv[inv_file_id].revision
1883
return self.inventory[file_id].revision
1901
1885
def get_file(self, file_id, path=None):
1902
1886
return StringIO(self.get_file_text(file_id))
1904
1888
def get_file_size(self, file_id):
1905
1889
"""See Tree.get_file_size"""
1906
inv, inv_file_id = self._unpack_file_id(file_id)
1907
return inv[inv_file_id].text_size
1890
return self.inventory[file_id].text_size
1909
1892
def get_file_text(self, file_id, path=None):
1911
for _, content_iter in self.iter_files_bytes([(file_id, None)]):
1912
if content is not None:
1913
raise AssertionError('iter_files_bytes returned'
1914
' too many entries')
1915
# For each entry returned by iter_files_bytes, we must consume the
1916
# content_iter before we step the files iterator.
1917
content = ''.join(content_iter)
1919
raise AssertionError('iter_files_bytes did not return'
1920
' the requested data')
1893
_, content = list(self.iter_files_bytes([(file_id, None)]))[0]
1894
return ''.join(content)
1923
1896
def get_reference_revision(self, file_id, path=None):
1924
inv, inv_file_id = self._unpack_file_id(file_id)
1925
return inv[inv_file_id].reference_revision
1897
return self.inventory[file_id].reference_revision
1927
1899
def iter_files_bytes(self, desired_files):
1928
1900
"""See Tree.iter_files_bytes.
1952
1924
"""Return the revision id for this tree."""
1953
1925
return self._revision_id
1955
def _get_root_inventory(self):
1927
def _get_inventory(self):
1956
1928
if self._inventory is not None:
1957
1929
return self._inventory
1958
1930
self._must_be_locked()
1959
1931
self._generate_inventory()
1960
1932
return self._inventory
1962
root_inventory = property(_get_root_inventory,
1963
doc="Inventory of this Tree")
1965
@deprecated_method(deprecated_in((2, 5, 0)))
1966
def _get_inventory(self):
1967
return self.root_inventory
1969
1934
inventory = property(_get_inventory,
1970
1935
doc="Inventory of this Tree")
1990
1955
def path_content_summary(self, path):
1991
1956
"""See Tree.path_content_summary."""
1992
inv, inv_file_id = self._path2inv_file_id(path)
1993
if inv_file_id is None:
1957
id = self.inventory.path2id(path)
1994
1959
return ('missing', None, None, None)
1995
entry = inv[inv_file_id]
1960
entry = self._inventory[id]
1996
1961
kind = entry.kind
1997
1962
if kind == 'file':
1998
1963
return (kind, entry.text_size, entry.executable, entry.text_sha1)
2002
1967
return (kind, None, None, None)
2004
1969
def is_executable(self, file_id, path=None):
2005
inv, inv_file_id = self._unpack_file_id(file_id)
2006
ie = inv[inv_file_id]
1970
ie = self.inventory[file_id]
2007
1971
if ie.kind != "file":
2009
1973
return ie.executable
2014
1978
def list_files(self, include_root=False, from_dir=None, recursive=True):
2015
1979
# We use a standard implementation, because DirStateRevisionTree is
2016
1980
# dealing with one of the parents of the current state
1981
inv = self._get_inventory()
2017
1982
if from_dir is None:
2018
inv = self.root_inventory
2019
1983
from_dir_id = None
2021
inv, from_dir_id = self._path2inv_file_id(from_dir)
1985
from_dir_id = inv.path2id(from_dir)
2022
1986
if from_dir_id is None:
2023
1987
# Directory not versioned
2025
# FIXME: Support nested trees
2026
1989
entries = inv.iter_entries(from_dir=from_dir_id, recursive=recursive)
2027
1990
if inv.root is not None and not include_root and from_dir is None:
2050
2013
def path2id(self, path):
2051
2014
"""Return the id for path in this tree."""
2052
2015
# lookup by path: faster than splitting and walking the ivnentory.
2053
if isinstance(path, list):
2056
path = osutils.pathjoin(*path)
2057
2016
entry = self._get_entry(path=path)
2058
2017
if entry == (None, None):
2082
2041
# So for now, we just build up the parent inventory, and extract
2083
2042
# it the same way RevisionTree does.
2084
2043
_directory = 'directory'
2085
inv = self._get_root_inventory()
2044
inv = self._get_inventory()
2086
2045
top_id = inv.path2id(prefix)
2087
2046
if top_id is None:
2227
2186
path_entries = state._entries_for_path(path)
2228
2187
if not path_entries:
2229
2188
# this specified path is not present at all: error
2230
not_versioned.append(path.decode('utf-8'))
2189
not_versioned.append(path)
2232
2191
found_versioned = False
2233
2192
# for each id at this path
2241
2200
if not found_versioned:
2242
2201
# none of the indexes was not 'absent' at all ids for this
2244
not_versioned.append(path.decode('utf-8'))
2203
not_versioned.append(path)
2245
2204
if len(not_versioned) > 0:
2246
2205
raise errors.PathsNotVersionedError(not_versioned)
2247
2206
# -- remove redundancy in supplied specific_files to prevent over-scanning --
2314
2273
def update_format(self, tree):
2315
2274
"""Change the format marker."""
2316
2275
tree._transport.put_bytes('format',
2317
self.target_format.as_string(),
2276
self.target_format.get_format_string(),
2318
2277
mode=tree.bzrdir._get_file_mode())
2337
2296
def update_format(self, tree):
2338
2297
"""Change the format marker."""
2339
2298
tree._transport.put_bytes('format',
2340
self.target_format.as_string(),
2299
self.target_format.get_format_string(),
2341
2300
mode=tree.bzrdir._get_file_mode())
2366
2325
def update_format(self, tree):
2367
2326
"""Change the format marker."""
2368
2327
tree._transport.put_bytes('format',
2369
self.target_format.as_string(),
2328
self.target_format.get_format_string(),
2370
2329
mode=tree.bzrdir._get_file_mode())