1# Copyright (C) 2010 Chris Jerdonek (cjerdonek@webkit.org) 2# 3# Redistribution and use in source and binary forms, with or without 4# modification, are permitted provided that the following conditions 5# are met: 6# 1. Redistributions of source code must retain the above copyright 7# notice, this list of conditions and the following disclaimer. 8# 2. Redistributions in binary form must reproduce the above copyright 9# notice, this list of conditions and the following disclaimer in the 10# documentation and/or other materials provided with the distribution. 11# 12# THIS SOFTWARE IS PROVIDED BY APPLE INC. AND ITS CONTRIBUTORS ``AS IS'' AND 13# ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED 14# WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE 15# DISCLAIMED. IN NO EVENT SHALL APPLE INC. OR ITS CONTRIBUTORS BE LIABLE FOR 16# ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 17# DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR 18# SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER 19# CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, 20# OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE 21# OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 22 23"""Contains a substitute for Python 2.6's os.path.relpath().""" 24 25import os 26 27 28# This function is a replacement for os.path.relpath(), which is only 29# available in Python 2.6: 30# 31# http://docs.python.org/library/os.path.html#os.path.relpath 32# 33# It should behave essentially the same as os.path.relpath(), except for 34# returning None on paths not contained in abs_start_path. 35def relpath(path, start_path, os_path_abspath=None, sep=None): 36 """Return a path relative to the given start path, or None. 37 38 Returns None if the path is not contained in the directory start_path. 39 40 Args: 41 path: An absolute or relative path to convert to a relative path. 42 start_path: The path relative to which the given path should be 43 converted. 44 os_path_abspath: A replacement function for unit testing. This 45 function should strip trailing slashes just like 46 os.path.abspath(). Defaults to os.path.abspath. 47 sep: Path separator. Defaults to os.path.sep 48 49 """ 50 if os_path_abspath is None: 51 os_path_abspath = os.path.abspath 52 sep = sep or os.sep 53 54 # Since os_path_abspath() calls os.path.normpath()-- 55 # 56 # (see http://docs.python.org/library/os.path.html#os.path.abspath ) 57 # 58 # it also removes trailing slashes and converts forward and backward 59 # slashes to the preferred slash os.sep. 60 start_path = os_path_abspath(start_path) 61 path = os_path_abspath(path) 62 63 if not path.lower().startswith(start_path.lower()): 64 # Then path is outside the directory given by start_path. 65 return None 66 67 rel_path = path[len(start_path):] 68 69 if not rel_path: 70 # Then the paths are the same. 71 pass 72 elif rel_path[0] == sep: 73 # It is probably sufficient to remove just the first character 74 # since os.path.normpath() collapses separators, but we use 75 # lstrip() just to be sure. 76 rel_path = rel_path.lstrip(sep) 77 else: 78 # We are in the case typified by the following example: 79 # 80 # start_path = "/tmp/foo" 81 # path = "/tmp/foobar" 82 # rel_path = "bar" 83 return None 84 85 return rel_path 86