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.
25
25
from bzrlib import (
26
26
conflicts as _mod_conflicts,
29
31
revision as _mod_revision,
33
35
from bzrlib.decorators import needs_read_lock
34
from bzrlib.errors import BzrError, BzrCheckError
36
from bzrlib.errors import BzrError, BzrCheckError, NoSuchId
35
37
from bzrlib import errors
36
38
from bzrlib.inventory import Inventory, InventoryFile
37
39
from bzrlib.inter import InterObject
38
40
from bzrlib.osutils import fingerprint_file
39
41
import bzrlib.revision
42
from bzrlib.symbol_versioning import deprecated_function, deprecated_in
40
43
from bzrlib.trace import mutter, note
59
62
Trees can be compared, etc, regardless of whether they are working
60
63
trees or versioned trees.
63
66
def changes_from(self, other, want_unchanged=False, specific_files=None,
64
67
extra_trees=None, require_versioned=False, include_root=False,
65
68
want_unversioned=False):
79
82
a PathsNotVersionedError will be thrown.
80
83
:param want_unversioned: Scan for unversioned paths.
82
The comparison will be performed by an InterTree object looked up on
85
The comparison will be performed by an InterTree object looked up on
85
88
# Martin observes that Tree.changes_from returns a TreeDelta and this
94
97
want_unversioned=want_unversioned,
97
@symbol_versioning.deprecated_method(symbol_versioning.one_three)
98
def _iter_changes(self, *args, **kwargs):
99
return self.iter_changes(*args, **kwargs)
101
100
def iter_changes(self, from_tree, include_unchanged=False,
102
101
specific_files=None, pb=None, extra_trees=None,
103
102
require_versioned=True, want_unversioned=False):
104
103
intertree = InterTree.get(from_tree, self)
105
104
return intertree.iter_changes(include_unchanged, specific_files, pb,
106
105
extra_trees, require_versioned, want_unversioned=want_unversioned)
108
107
def conflicts(self):
109
108
"""Get a list of the conflicts in the tree.
119
118
def get_parent_ids(self):
120
"""Get the parent ids for this tree.
119
"""Get the parent ids for this tree.
122
121
:return: a list of parent ids. [] is returned to indicate
123
122
a tree with no parents.
124
123
:raises: BzrError if the parents are not known.
126
125
raise NotImplementedError(self.get_parent_ids)
128
127
def has_filename(self, filename):
129
128
"""True if the tree has given filename."""
130
129
raise NotImplementedError(self.has_filename)
132
131
def has_id(self, file_id):
133
132
return self.inventory.has_id(file_id)
135
__contains__ = has_id
134
def __contains__(self, file_id):
135
return self.has_id(file_id)
137
137
def has_or_had_id(self, file_id):
138
138
if file_id == self.inventory.root.file_id:
202
202
specific_file_ids=specific_file_ids)
204
204
def iter_references(self):
205
for path, entry in self.iter_entries_by_dir():
206
if entry.kind == 'tree-reference':
207
yield path, entry.file_id
205
if self.supports_tree_reference():
206
for path, entry in self.iter_entries_by_dir():
207
if entry.kind == 'tree-reference':
208
yield path, entry.file_id
209
210
def kind(self, file_id):
210
211
raise NotImplementedError("Tree subclass %s must implement kind"
221
222
def path_content_summary(self, path):
222
223
"""Get a summary of the information about path.
224
225
:param path: A relative path within the tree.
225
226
:return: A tuple containing kind, size, exec, sha1-or-link.
226
227
Kind is always present (see tree.kind()).
254
255
def _get_inventory(self):
255
256
return self._inventory
257
258
def get_file(self, file_id, path=None):
258
259
"""Return a file object for the file file_id in the tree.
260
261
If both file_id and path are defined, it is implementation defined as
261
262
to which one is used.
263
264
raise NotImplementedError(self.get_file)
266
def get_file_with_stat(self, file_id, path=None):
267
"""Get a file handle and stat object for file_id.
269
The default implementation returns (self.get_file, None) for backwards
272
:param file_id: The file id to read.
273
:param path: The path of the file, if it is known.
274
:return: A tuple (file_handle, stat_value_or_None). If the tree has
275
no stat facility, or need for a stat cache feedback during commit,
276
it may return None for the second element of the tuple.
278
return (self.get_file(file_id, path), None)
280
def get_file_text(self, file_id, path=None):
281
"""Return the byte content of a file.
283
:param file_id: The file_id of the file.
284
:param path: The path of the file.
285
If both file_id and path are supplied, an implementation may use
288
my_file = self.get_file(file_id, path)
290
return my_file.read()
294
def get_file_lines(self, file_id, path=None):
295
"""Return the content of a file, as lines.
297
:param file_id: The file_id of the file.
298
:param path: The path of the file.
299
If both file_id and path are supplied, an implementation may use
302
return osutils.split_lines(self.get_file_text(file_id, path))
265
304
def get_file_mtime(self, file_id, path=None):
266
305
"""Return the modification time for a file.
320
359
raise NotImplementedError(self.get_symlink_target)
361
def get_canonical_inventory_paths(self, paths):
362
"""Like get_canonical_inventory_path() but works on multiple items.
364
:param paths: A sequence of paths relative to the root of the tree.
365
:return: A list of paths, with each item the corresponding input path
366
adjusted to account for existing elements that match case
369
return list(self._yield_canonical_inventory_paths(paths))
371
def get_canonical_inventory_path(self, path):
372
"""Returns the first inventory item that case-insensitively matches path.
374
If a path matches exactly, it is returned. If no path matches exactly
375
but more than one path matches case-insensitively, it is implementation
376
defined which is returned.
378
If no path matches case-insensitively, the input path is returned, but
379
with as many path entries that do exist changed to their canonical
382
If you need to resolve many names from the same tree, you should
383
use get_canonical_inventory_paths() to avoid O(N) behaviour.
385
:param path: A paths relative to the root of the tree.
386
:return: The input path adjusted to account for existing elements
387
that match case insensitively.
389
return self._yield_canonical_inventory_paths([path]).next()
391
def _yield_canonical_inventory_paths(self, paths):
393
# First, if the path as specified exists exactly, just use it.
394
if self.path2id(path) is not None:
398
cur_id = self.get_root_id()
400
bit_iter = iter(path.split("/"))
403
for child in self.iter_children(cur_id):
405
child_base = os.path.basename(self.id2path(child))
406
if child_base.lower() == lelt:
408
cur_path = osutils.pathjoin(cur_path, child_base)
411
# before a change is committed we can see this error...
414
# got to the end of this directory and no entries matched.
415
# Return what matched so far, plus the rest as specified.
416
cur_path = osutils.pathjoin(cur_path, elt, *list(bit_iter))
322
421
def get_root_id(self):
323
422
"""Return the file_id for the root of this tree."""
324
423
raise NotImplementedError(self.get_root_id)
415
514
def _check_retrieved(self, ie, f):
416
515
if not __debug__:
418
517
fp = fingerprint_file(f)
421
520
if ie.text_size is not None:
422
521
if ie.text_size != fp['size']:
423
522
raise BzrError("mismatched size for file %r in %r" % (ie.file_id, self._store),
439
538
def paths2ids(self, paths, trees=[], require_versioned=True):
440
539
"""Return all the ids that can be reached by walking from paths.
442
541
Each path is looked up in this tree and any extras provided in
443
542
trees, and this is repeated recursively: the children in an extra tree
444
543
of a directory that has been renamed under a provided path in this tree
456
555
return find_ids_across_trees(paths, [self] + list(trees), require_versioned)
458
@symbol_versioning.deprecated_method(symbol_versioning.one_six)
459
def print_file(self, file_id):
460
"""Print file with id `file_id` to stdout."""
462
sys.stdout.write(self.get_file_text(file_id))
557
def iter_children(self, file_id):
558
entry = self.iter_entries_by_dir([file_id]).next()[1]
559
for child in getattr(entry, 'children', {}).itervalues():
464
562
def lock_read(self):
470
568
The intention of this method is to allow access to possibly cached
471
569
tree data. Implementors of this method should raise NoSuchRevision if
472
the tree is not locally available, even if they could obtain the
473
tree via a repository or some other means. Callers are responsible
570
the tree is not locally available, even if they could obtain the
571
tree via a repository or some other means. Callers are responsible
474
572
for finding the ultimate source for a revision tree.
476
574
:param revision_id: The revision_id of the requested tree.
495
593
:return: set of paths.
497
595
# NB: we specifically *don't* call self.has_filename, because for
498
# WorkingTrees that can indicate files that exist on disk but that
596
# WorkingTrees that can indicate files that exist on disk but that
499
597
# are not versioned.
500
598
pred = self.inventory.has_filename
501
599
return set((p for p in paths if not pred(p)))
506
604
This yields all the data about the contents of a directory at a time.
507
605
After each directory has been yielded, if the caller has mutated the
508
606
list to exclude some directories, they are then not descended into.
510
608
The data yielded is of the form:
511
609
((directory-relpath, directory-path-from-root, directory-fileid),
512
[(relpath, basename, kind, lstat, path_from_tree_root, file_id,
610
[(relpath, basename, kind, lstat, path_from_tree_root, file_id,
513
611
versioned_kind), ...]),
514
612
- directory-relpath is the containing dirs relpath from prefix
515
613
- directory-path-from-root is the containing dirs path from /
522
620
- lstat is the stat data *if* the file was statted.
523
621
- path_from_tree_root is the path from the root of the tree.
524
622
- file_id is the file_id if the entry is versioned.
525
- versioned_kind is the kind of the file as last recorded in the
623
- versioned_kind is the kind of the file as last recorded in the
526
624
versioning system. If 'unknown' the file is not versioned.
527
625
One of 'kind' and 'versioned_kind' must not be 'unknown'.
534
632
raise NotImplementedError(self.walkdirs)
634
def supports_content_filtering(self):
637
def _content_filter_stack(self, path=None, file_id=None):
638
"""The stack of content filters for a path if filtering is supported.
640
Readers will be applied in first-to-last order.
641
Writers will be applied in last-to-first order.
642
Either the path or the file-id needs to be provided.
644
:param path: path relative to the root of the tree
646
:param file_id: file_id or None if unknown
647
:return: the list of filters - [] if there are none
649
filter_pref_names = filters._get_registered_names()
650
if len(filter_pref_names) == 0:
653
path = self.id2path(file_id)
654
prefs = self.iter_search_rules([path], filter_pref_names).next()
655
stk = filters._get_filter_stack_for(prefs)
656
if 'filters' in debug.debug_flags:
657
note("*** %s content-filter: %s => %r" % (path,prefs,stk))
660
def _content_filter_stack_provider(self):
661
"""A function that returns a stack of ContentFilters.
663
The function takes a path (relative to the top of the tree) and a
664
file-id as parameters.
666
:return: None if content filtering is not supported by this tree.
668
if self.supports_content_filtering():
669
return lambda path, file_id: \
670
self._content_filter_stack(path, file_id)
536
674
def iter_search_rules(self, path_names, pref_names=None,
537
_default_searcher=rules._per_user_searcher):
675
_default_searcher=None):
538
676
"""Find the preferences for filenames in a tree.
540
678
:param path_names: an iterable of paths to find attributes for.
544
682
:return: an iterator of tuple sequences, one per path-name.
545
683
See _RulesSearcher.get_items for details on the tuple sequence.
685
if _default_searcher is None:
686
_default_searcher = rules._per_user_searcher
547
687
searcher = self._get_rules_searcher(_default_searcher)
548
688
if searcher is not None:
549
689
if pref_names is not None:
563
class EmptyTree(Tree):
566
self._inventory = Inventory(root_id=None)
567
symbol_versioning.warn('EmptyTree is deprecated as of bzr 0.9 please'
568
' use repository.revision_tree instead.',
569
DeprecationWarning, stacklevel=2)
571
def get_parent_ids(self):
574
def get_symlink_target(self, file_id):
577
def has_filename(self, filename):
580
def kind(self, file_id):
583
def list_files(self, include_root=False):
586
def __contains__(self, file_id):
587
return (file_id in self._inventory)
589
def get_file_sha1(self, file_id, path=None, stat_value=None):
593
703
######################################################################
652
762
new_name = new_inv.id2path(file_id)
653
763
if old_name != new_name:
654
764
yield (old_name, new_name)
657
767
def find_ids_across_trees(filenames, trees, require_versioned=True):
658
768
"""Find the ids corresponding to specified filenames.
660
770
All matches in all trees will be used, and all children of matched
661
771
directories will be used.
677
787
def _find_ids_across_trees(filenames, trees, require_versioned):
678
788
"""Find the ids corresponding to specified filenames.
680
790
All matches in all trees will be used, but subdirectories are not scanned.
682
792
:param filenames: The filenames to find file_ids for
704
814
def _find_children_across_trees(specified_ids, trees):
705
815
"""Return a set including specified ids and their children.
707
817
All matches in all trees will be used.
709
819
:param trees: The trees to find file_ids within
710
:return: a set containing all specified ids and their children
820
:return: a set containing all specified ids and their children
712
822
interesting_ids = set(specified_ids)
713
823
pending = interesting_ids
719
829
for tree in trees:
720
830
if not tree.has_id(file_id):
722
entry = tree.inventory[file_id]
723
for child in getattr(entry, 'children', {}).itervalues():
724
if child.file_id not in interesting_ids:
725
new_pending.add(child.file_id)
832
for child_id in tree.iter_children(file_id):
833
if child_id not in interesting_ids:
834
new_pending.add(child_id)
726
835
interesting_ids.update(new_pending)
727
836
pending = new_pending
728
837
return interesting_ids
832
940
all_unversioned = deque()
834
from_entries_by_dir = list(self.source.inventory.iter_entries_by_dir(
942
from_entries_by_dir = list(self.source.iter_entries_by_dir(
835
943
specific_file_ids=specific_file_ids))
836
944
from_data = dict((e.file_id, (p, e)) for p, e in from_entries_by_dir)
837
to_entries_by_dir = list(self.target.inventory.iter_entries_by_dir(
945
to_entries_by_dir = list(self.target.iter_entries_by_dir(
838
946
specific_file_ids=specific_file_ids))
839
947
num_entries = len(from_entries_by_dir) + len(to_entries_by_dir)
841
# the unversioned path lookup only occurs on real trees - where there
949
# the unversioned path lookup only occurs on real trees - where there
842
950
# can be extras. So the fake_entry is solely used to look up
843
951
# executable it values when execute is not supported.
844
952
fake_entry = InventoryFile('unused', 'unused', 'unused')
878
986
if kind[0] != kind[1]:
879
987
changed_content = True
880
988
elif from_kind == 'file':
881
from_size = self.source._file_size(from_entry, from_stat)
882
to_size = self.target._file_size(to_entry, to_stat)
883
if from_size != to_size:
884
changed_content = True
885
elif (self.source.get_file_sha1(file_id, from_path, from_stat) !=
989
if (self.source.get_file_sha1(file_id, from_path, from_stat) !=
886
990
self.target.get_file_sha1(file_id, to_path, to_stat)):
887
991
changed_content = True
888
992
elif from_kind == 'symlink':
889
993
if (self.source.get_symlink_target(file_id) !=
890
994
self.target.get_symlink_target(file_id)):
891
995
changed_content = True
996
# XXX: Yes, the indentation below is wrong. But fixing it broke
997
# test_merge.TestMergerEntriesLCAOnDisk.
998
# test_nested_tree_subtree_renamed_and_modified. We'll wait for
999
# the fix from bzr.dev -- vila 2009026
892
1000
elif from_kind == 'tree-reference':
893
1001
if (self.source.get_reference_revision(file_id, from_path)
894
1002
!= self.target.get_reference_revision(file_id, to_path)):
895
changed_content = True
1003
changed_content = True
896
1004
parent = (from_parent, to_entry.parent_id)
897
1005
name = (from_name, to_entry.name)
898
1006
executable = (from_executable, to_executable)
899
1007
if pb is not None:
900
1008
pb.update('comparing files', entry_count, num_entries)
901
1009
if (changed_content is not False or versioned[0] != versioned[1]
902
or parent[0] != parent[1] or name[0] != name[1] or
1010
or parent[0] != parent[1] or name[0] != name[1] or
903
1011
executable[0] != executable[1] or include_unchanged):
904
1012
yield (file_id, (from_path, to_path), changed_content,
905
1013
versioned, parent, name, kind, executable)
1075
1183
def _walk_master_tree(self):
1076
1184
"""First pass, walk all trees in lock-step.
1078
1186
When we are done, all nodes in the master_tree will have been
1079
1187
processed. _other_walkers, _other_entries, and _others_extra will be
1080
1188
set on 'self' for future processing.