13
13
# You should have received a copy of the GNU General Public License
14
14
# along with this program; if not, write to the Free Software
15
# Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
15
# Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
17
17
"""Tree classes, representing directory at point in time.
21
21
from collections import deque
22
from cStringIO import StringIO
25
24
from bzrlib import (
26
25
conflicts as _mod_conflicts,
29
30
revision as _mod_revision,
33
33
from bzrlib.decorators import needs_read_lock
34
from bzrlib.errors import BzrError, BzrCheckError, NoSuchId
34
from bzrlib.errors import BzrError, NoSuchId
35
35
from bzrlib import errors
36
from bzrlib.inventory import Inventory, InventoryFile
36
from bzrlib.inventory import InventoryFile
37
37
from bzrlib.inter import InterObject
38
38
from bzrlib.osutils import fingerprint_file
39
39
import bzrlib.revision
40
40
from bzrlib.symbol_versioning import deprecated_function, deprecated_in
41
from bzrlib.trace import mutter, note
41
from bzrlib.trace import note
44
44
class Tree(object):
95
95
want_unversioned=want_unversioned,
98
@symbol_versioning.deprecated_method(symbol_versioning.one_three)
99
def _iter_changes(self, *args, **kwargs):
100
return self.iter_changes(*args, **kwargs)
102
98
def iter_changes(self, from_tree, include_unchanged=False,
103
99
specific_files=None, pb=None, extra_trees=None,
104
100
require_versioned=True, want_unversioned=False):
137
133
return self.has_id(file_id)
139
135
def has_or_had_id(self, file_id):
140
if file_id == self.inventory.root.file_id:
142
136
return self.inventory.has_id(file_id)
144
138
def is_ignored(self, filename):
204
198
specific_file_ids=specific_file_ids)
206
200
def iter_references(self):
207
for path, entry in self.iter_entries_by_dir():
208
if entry.kind == 'tree-reference':
209
yield path, entry.file_id
201
if self.supports_tree_reference():
202
for path, entry in self.iter_entries_by_dir():
203
if entry.kind == 'tree-reference':
204
yield path, entry.file_id
211
206
def kind(self, file_id):
212
207
raise NotImplementedError("Tree subclass %s must implement kind"
265
260
raise NotImplementedError(self.get_file)
262
def get_file_with_stat(self, file_id, path=None):
263
"""Get a file handle and stat object for file_id.
265
The default implementation returns (self.get_file, None) for backwards
268
:param file_id: The file id to read.
269
:param path: The path of the file, if it is known.
270
:return: A tuple (file_handle, stat_value_or_None). If the tree has
271
no stat facility, or need for a stat cache feedback during commit,
272
it may return None for the second element of the tuple.
274
return (self.get_file(file_id, path), None)
267
276
def get_file_text(self, file_id, path=None):
268
277
"""Return the byte content of a file.
424
433
raise NotImplementedError(self.annotate_iter)
426
435
def _get_plan_merge_data(self, file_id, other, base):
427
from bzrlib import merge, versionedfile
436
from bzrlib import versionedfile
428
437
vf = versionedfile._PlanMergeVersionedFile(file_id)
429
438
last_revision_a = self._get_file_revision(file_id, vf, 'this:')
430
439
last_revision_b = other._get_file_revision(file_id, vf, 'other:')
546
555
for child in getattr(entry, 'children', {}).itervalues():
547
556
yield child.file_id
549
@symbol_versioning.deprecated_method(symbol_versioning.one_six)
550
def print_file(self, file_id):
551
"""Print file with id `file_id` to stdout."""
553
sys.stdout.write(self.get_file_text(file_id))
555
558
def lock_read(self):
627
630
def supports_content_filtering(self):
633
def _content_filter_stack(self, path=None, file_id=None):
634
"""The stack of content filters for a path if filtering is supported.
636
Readers will be applied in first-to-last order.
637
Writers will be applied in last-to-first order.
638
Either the path or the file-id needs to be provided.
640
:param path: path relative to the root of the tree
642
:param file_id: file_id or None if unknown
643
:return: the list of filters - [] if there are none
645
filter_pref_names = filters._get_registered_names()
646
if len(filter_pref_names) == 0:
649
path = self.id2path(file_id)
650
prefs = self.iter_search_rules([path], filter_pref_names).next()
651
stk = filters._get_filter_stack_for(prefs)
652
if 'filters' in debug.debug_flags:
653
note("*** %s content-filter: %s => %r" % (path,prefs,stk))
656
def _content_filter_stack_provider(self):
657
"""A function that returns a stack of ContentFilters.
659
The function takes a path (relative to the top of the tree) and a
660
file-id as parameters.
662
:return: None if content filtering is not supported by this tree.
664
if self.supports_content_filtering():
665
return lambda path, file_id: \
666
self._content_filter_stack(path, file_id)
630
670
def iter_search_rules(self, path_names, pref_names=None,
631
_default_searcher=rules._per_user_searcher):
671
_default_searcher=None):
632
672
"""Find the preferences for filenames in a tree.
634
674
:param path_names: an iterable of paths to find attributes for.
638
678
:return: an iterator of tuple sequences, one per path-name.
639
679
See _RulesSearcher.get_items for details on the tuple sequence.
681
if _default_searcher is None:
682
_default_searcher = rules._per_user_searcher
641
683
searcher = self._get_rules_searcher(_default_searcher)
642
684
if searcher is not None:
643
685
if pref_names is not None:
941
982
if kind[0] != kind[1]:
942
983
changed_content = True
943
984
elif from_kind == 'file':
944
from_size = self.source._file_size(from_entry, from_stat)
945
to_size = self.target._file_size(to_entry, to_stat)
946
if from_size != to_size:
947
changed_content = True
948
elif (self.source.get_file_sha1(file_id, from_path, from_stat) !=
985
if (self.source.get_file_sha1(file_id, from_path, from_stat) !=
949
986
self.target.get_file_sha1(file_id, to_path, to_stat)):
950
987
changed_content = True
951
988
elif from_kind == 'symlink':
952
989
if (self.source.get_symlink_target(file_id) !=
953
990
self.target.get_symlink_target(file_id)):
954
991
changed_content = True
992
# XXX: Yes, the indentation below is wrong. But fixing it broke
993
# test_merge.TestMergerEntriesLCAOnDisk.
994
# test_nested_tree_subtree_renamed_and_modified. We'll wait for
995
# the fix from bzr.dev -- vila 2009026
955
996
elif from_kind == 'tree-reference':
956
997
if (self.source.get_reference_revision(file_id, from_path)
957
998
!= self.target.get_reference_revision(file_id, to_path)):