~bzr-pqm/bzr/bzr.dev

« back to all changes in this revision

Viewing changes to bzrlib/tree.py

  • Committer: Mark Hammond
  • Date: 2008-12-21 07:30:12 UTC
  • mto: (3932.3.1 cicp-1.11)
  • mto: This revision was merged to the branch mainline in revision 3937.
  • Revision ID: mhammond@skippinet.com.au-20081221073012-bwj4g5iox1kd1vki
get_canonical_path renamed to get_canonical_inventory_path() and corresponding get_canonical_inventory_paths() method added. 
Reimplemented using generators to help future optimization of using a cache.

Show diffs side-by-side

added added

removed removed

Lines of Context:
31
31
    symbol_versioning,
32
32
    )
33
33
from bzrlib.decorators import needs_read_lock
34
 
from bzrlib.errors import BzrError, BzrCheckError
 
34
from bzrlib.errors import BzrError, BzrCheckError, NoSuchId
35
35
from bzrlib import errors
36
36
from bzrlib.inventory import Inventory, InventoryFile
37
37
from bzrlib.inter import InterObject
345
345
        """
346
346
        raise NotImplementedError(self.get_symlink_target)
347
347
 
348
 
    def get_canonical_path(self, path):
349
 
        """Returns the first path that case-insensitively matches the input.
 
348
    def get_canonical_inventory_paths(self, paths):
 
349
        """Returns a list with each item the first path that
 
350
        case-insensitively matches the specified input paths.
350
351
 
351
352
        If a path matches exactly, it is returned. If no path matches exactly
352
353
        but more than one path matches case-insensitively, it is implementation
355
356
        If no path matches case-insensitively, the input path is returned, but
356
357
        with as many path entries that do exist changed to their canonical form.
357
358
 
358
 
        NOTE: There is a risk that this will cause O(N) behaviour if called
359
 
        for every path in a working tree. However, it is expected this should
360
 
        only be used on path specified by the users. A cache with lifetime
361
 
        controlled by the caller would probably resolve this if it becomes a
362
 
        problem.
363
 
 
364
 
        :param path: A path, relative to the root of the tree.
365
 
        :return: The input path adjusted to account for existing elements that
366
 
        match case insensitively.
367
 
        """
368
 
        # First, if the path as specified exists exactly, just use it.
369
 
        if self.path2id(path) is not None:
370
 
            return path
371
 
        # go walkin...
372
 
        cur_id = self.get_root_id()
373
 
        cur_path = ''
374
 
        bit_iter = iter(path.split("/"))
375
 
        for elt in bit_iter:
376
 
            lelt = elt.lower()
377
 
            for child in self.iter_children(cur_id):
378
 
                child_base = os.path.basename(self.id2path(child))
379
 
                if child_base.lower() == lelt:
380
 
                    cur_id = child
381
 
                    cur_path = osutils.pathjoin(cur_path, child_base)
 
359
        :param paths: A sequence of paths relative to the root of the tree.
 
360
        :return: A list of paths, with each item the corresponding input path
 
361
        adjusted to account for existing elements that match case
 
362
        insensitively.
 
363
        """
 
364
        return list(self._yield_canonical_inventory_paths(paths))
 
365
 
 
366
    def get_canonical_inventory_path(self, path):
 
367
        """A convenience version of get_canonical_inventory_path which
 
368
        takes a single path.
 
369
 
 
370
        If you need to resolve many names from the same tree, you should
 
371
        use get_canonical_inventory_paths() to avoid O(N) behaviour.
 
372
        """
 
373
        return self._yield_canonical_inventory_paths([path]).next()
 
374
 
 
375
    def _yield_canonical_inventory_paths(self, paths):
 
376
        for path in paths:
 
377
            # First, if the path as specified exists exactly, just use it.
 
378
            if self.path2id(path) is not None:
 
379
                yield path
 
380
                continue
 
381
            # go walkin...
 
382
            cur_id = self.get_root_id()
 
383
            cur_path = ''
 
384
            bit_iter = iter(path.split("/"))
 
385
            for elt in bit_iter:
 
386
                lelt = elt.lower()
 
387
                for child in self.iter_children(cur_id):
 
388
                    try:
 
389
                        child_base = os.path.basename(self.id2path(child))
 
390
                        if child_base.lower() == lelt:
 
391
                            cur_id = child
 
392
                            cur_path = osutils.pathjoin(cur_path, child_base)
 
393
                            break
 
394
                    except NoSuchId:
 
395
                        # before a change is committed we can see this error...
 
396
                        continue
 
397
                else:
 
398
                    # got to the end of this directory and no entries matched.
 
399
                    # Return what matched so far, plus the rest as specified.
 
400
                    cur_path = osutils.pathjoin(cur_path, elt, *list(bit_iter))
382
401
                    break
383
 
            else:
384
 
                # got to the end of this directory and no entries matched.
385
 
                # Return what matched so far, plus the rest as specified.
386
 
                cur_path = osutils.pathjoin(cur_path, elt, *list(bit_iter))
387
 
                break
388
 
        return cur_path
 
402
            yield cur_path
 
403
        # all done.
389
404
 
390
405
    def get_root_id(self):
391
406
        """Return the file_id for the root of this tree."""