352
341
raise NotImplementedError(self.get_symlink_target)
354
def get_canonical_inventory_paths(self, paths):
355
"""Like get_canonical_inventory_path() but works on multiple items.
357
:param paths: A sequence of paths relative to the root of the tree.
358
:return: A list of paths, with each item the corresponding input path
359
adjusted to account for existing elements that match case
362
return list(self._yield_canonical_inventory_paths(paths))
364
def get_canonical_inventory_path(self, path):
365
"""Returns the first inventory item that case-insensitively matches path.
367
If a path matches exactly, it is returned. If no path matches exactly
368
but more than one path matches case-insensitively, it is implementation
369
defined which is returned.
371
If no path matches case-insensitively, the input path is returned, but
372
with as many path entries that do exist changed to their canonical
375
If you need to resolve many names from the same tree, you should
376
use get_canonical_inventory_paths() to avoid O(N) behaviour.
378
:param path: A paths relative to the root of the tree.
379
:return: The input path adjusted to account for existing elements
380
that match case insensitively.
382
return self._yield_canonical_inventory_paths([path]).next()
384
def _yield_canonical_inventory_paths(self, paths):
386
# First, if the path as specified exists exactly, just use it.
387
if self.path2id(path) is not None:
391
cur_id = self.get_root_id()
393
bit_iter = iter(path.split("/"))
397
for child in self.iter_children(cur_id):
399
# XXX: it seem like if the child is known to be in the
400
# tree, we shouldn't need to go from its id back to
401
# its path -- mbp 2010-02-11
403
# XXX: it seems like we could be more efficient
404
# by just directly looking up the original name and
405
# only then searching all children; also by not
406
# chopping paths so much. -- mbp 2010-02-11
407
child_base = os.path.basename(self.id2path(child))
408
if (child_base == elt):
409
# if we found an exact match, we can stop now; if
410
# we found an approximate match we need to keep
411
# searching because there might be an exact match
414
new_path = osutils.pathjoin(cur_path, child_base)
416
elif child_base.lower() == lelt:
418
new_path = osutils.pathjoin(cur_path, child_base)
419
except errors.NoSuchId:
420
# before a change is committed we can see this error...
425
# got to the end of this directory and no entries matched.
426
# Return what matched so far, plus the rest as specified.
427
cur_path = osutils.pathjoin(cur_path, elt, *list(bit_iter))
432
344
def get_root_id(self):
433
345
"""Return the file_id for the root of this tree."""
625
class InventoryTree(Tree):
626
"""A tree that relies on an inventory for its metadata.
628
Trees contain an `Inventory` object, and also know how to retrieve
629
file texts mentioned in the inventory, either from a working
630
directory or from a store.
632
It is possible for trees to contain files that are not described
633
in their inventory or vice versa; for this use `filenames()`.
636
def get_canonical_inventory_paths(self, paths):
637
"""Like get_canonical_inventory_path() but works on multiple items.
639
:param paths: A sequence of paths relative to the root of the tree.
640
:return: A list of paths, with each item the corresponding input path
641
adjusted to account for existing elements that match case
644
return list(self._yield_canonical_inventory_paths(paths))
646
def get_canonical_inventory_path(self, path):
647
"""Returns the first inventory item that case-insensitively matches path.
649
If a path matches exactly, it is returned. If no path matches exactly
650
but more than one path matches case-insensitively, it is implementation
651
defined which is returned.
653
If no path matches case-insensitively, the input path is returned, but
654
with as many path entries that do exist changed to their canonical
657
If you need to resolve many names from the same tree, you should
658
use get_canonical_inventory_paths() to avoid O(N) behaviour.
660
:param path: A paths relative to the root of the tree.
661
:return: The input path adjusted to account for existing elements
662
that match case insensitively.
664
return self._yield_canonical_inventory_paths([path]).next()
666
def _yield_canonical_inventory_paths(self, paths):
668
# First, if the path as specified exists exactly, just use it.
669
if self.path2id(path) is not None:
673
cur_id = self.get_root_id()
675
bit_iter = iter(path.split("/"))
679
for child in self.iter_children(cur_id):
681
# XXX: it seem like if the child is known to be in the
682
# tree, we shouldn't need to go from its id back to
683
# its path -- mbp 2010-02-11
685
# XXX: it seems like we could be more efficient
686
# by just directly looking up the original name and
687
# only then searching all children; also by not
688
# chopping paths so much. -- mbp 2010-02-11
689
child_base = os.path.basename(self.id2path(child))
690
if (child_base == elt):
691
# if we found an exact match, we can stop now; if
692
# we found an approximate match we need to keep
693
# searching because there might be an exact match
696
new_path = osutils.pathjoin(cur_path, child_base)
698
elif child_base.lower() == lelt:
700
new_path = osutils.pathjoin(cur_path, child_base)
701
except errors.NoSuchId:
702
# before a change is committed we can see this error...
707
# got to the end of this directory and no entries matched.
708
# Return what matched so far, plus the rest as specified.
709
cur_path = osutils.pathjoin(cur_path, elt, *list(bit_iter))
714
def _get_inventory(self):
715
return self._inventory
717
inventory = property(_get_inventory,
718
doc="Inventory of this Tree")
721
def path2id(self, path):
722
"""Return the id for path in this tree."""
723
return self._inventory.path2id(path)
725
def id2path(self, file_id):
726
"""Return the path for a file id.
730
return self.inventory.id2path(file_id)
732
def has_id(self, file_id):
733
return self.inventory.has_id(file_id)
735
def has_or_had_id(self, file_id):
736
return self.inventory.has_id(file_id)
739
return iter(self.inventory)
741
def filter_unversioned_files(self, paths):
742
"""Filter out paths that are versioned.
744
:return: set of paths.
746
# NB: we specifically *don't* call self.has_filename, because for
747
# WorkingTrees that can indicate files that exist on disk but that
749
pred = self.inventory.has_filename
750
return set((p for p in paths if not pred(p)))
753
def iter_entries_by_dir(self, specific_file_ids=None, yield_parents=False):
754
"""Walk the tree in 'by_dir' order.
756
This will yield each entry in the tree as a (path, entry) tuple.
757
The order that they are yielded is:
759
See Tree.iter_entries_by_dir for details.
761
:param yield_parents: If True, yield the parents from the root leading
762
down to specific_file_ids that have been requested. This has no
763
impact if specific_file_ids is None.
765
return self.inventory.iter_entries_by_dir(
766
specific_file_ids=specific_file_ids, yield_parents=yield_parents)
768
def get_file_by_path(self, path):
769
return self.get_file(self._inventory.path2id(path), path)
720
772
######################################################################