python/mozbuild/mozpack/path.py

Fri, 16 Jan 2015 18:13:44 +0100

author
Michael Schloh von Bennewitz <michael@schloh.com>
date
Fri, 16 Jan 2015 18:13:44 +0100
branch
TOR_BUG_9701
changeset 14
925c144e1f1f
permissions
-rw-r--r--

Integrate suggestion from review to improve consistency with existing code.

     1 # This Source Code Form is subject to the terms of the Mozilla Public
     2 # License, v. 2.0. If a copy of the MPL was not distributed with this
     3 # file, You can obtain one at http://mozilla.org/MPL/2.0/.
     5 import posixpath
     6 import os
     7 import re
     9 '''
    10 Like os.path, with a reduced set of functions, and with normalized path
    11 separators (always use forward slashes).
    12 Also contains a few additional utilities not found in os.path.
    13 '''
    16 def normsep(path):
    17     '''
    18     Normalize path separators, by using forward slashes instead of whatever
    19     os.sep is.
    20     '''
    21     if os.sep != '/':
    22         path = path.replace(os.sep, '/')
    23     return path
    26 def relpath(path, start):
    27     rel = normsep(os.path.relpath(path, start))
    28     return '' if rel == '.' else rel
    31 def abspath(path):
    32     return normsep(os.path.abspath(path))
    35 def join(*paths):
    36     return normsep(os.path.join(*paths))
    39 def normpath(path):
    40     return posixpath.normpath(normsep(path))
    43 def dirname(path):
    44     return posixpath.dirname(normsep(path))
    47 def commonprefix(paths):
    48     return posixpath.commonprefix([normsep(path) for path in paths])
    51 def basename(path):
    52     return os.path.basename(path)
    55 def splitext(path):
    56     return posixpath.splitext(normsep(path))
    59 def split(path):
    60     '''
    61     Return the normalized path as a list of its components.
    62         split('foo/bar/baz') returns ['foo', 'bar', 'baz']
    63     '''
    64     return normsep(path).split('/')
    67 def basedir(path, bases):
    68     '''
    69     Given a list of directories (bases), return which one contains the given
    70     path. If several matches are found, the deepest base directory is returned.
    71         basedir('foo/bar/baz', ['foo', 'baz', 'foo/bar']) returns 'foo/bar'
    72         ('foo' and 'foo/bar' both match, but 'foo/bar' is the deepest match)
    73     '''
    74     path = normsep(path)
    75     bases = [normsep(b) for b in bases]
    76     if path in bases:
    77         return path
    78     for b in sorted(bases, reverse=True):
    79         if b == '' or path.startswith(b + '/'):
    80             return b
    83 re_cache = {}
    85 def match(path, pattern):
    86     '''
    87     Return whether the given path matches the given pattern.
    88     An asterisk can be used to match any string, including the null string, in
    89     one part of the path:
    90         'foo' matches '*', 'f*' or 'fo*o'
    91     However, an asterisk matching a subdirectory may not match the null string:
    92         'foo/bar' does *not* match 'foo/*/bar'
    93     If the pattern matches one of the ancestor directories of the path, the
    94     patch is considered matching:
    95         'foo/bar' matches 'foo'
    96     Two adjacent asterisks can be used to match files and zero or more
    97     directories and subdirectories.
    98         'foo/bar' matches 'foo/**/bar', or '**/bar'
    99     '''
   100     if not pattern:
   101         return True
   102     if not pattern in re_cache:
   103         pattern = re.escape(pattern)
   104         pattern = re.sub(r'(^|\\\/)\\\*\\\*\\\/', r'\1(?:.+/)?', pattern)
   105         pattern = re.sub(r'(^|\\\/)\\\*\\\*$', r'(?:\1.+)?', pattern)
   106         pattern = pattern.replace(r'\*', '[^/]*') + '(?:/.*)?$'
   107         re_cache[pattern] = re.compile(pattern)
   108     return re_cache[pattern].match(path) is not None
   111 def rebase(oldbase, base, relativepath):
   112     '''
   113     Return relativepath relative to base instead of oldbase.
   114     '''
   115     if base == oldbase:
   116         return relativepath
   117     if len(base) < len(oldbase):
   118         assert basedir(oldbase, [base]) == base
   119         relbase = relpath(oldbase, base)
   120         result = join(relbase, relativepath)
   121     else:
   122         assert basedir(base, [oldbase]) == oldbase
   123         relbase = relpath(base, oldbase)
   124         result = relpath(relativepath, relbase)
   125     result = normpath(result)
   126     if relativepath.endswith('/') and not result.endswith('/'):
   127         result += '/'
   128     return result

mercurial