1# Copyright 2018 The Bazel Authors. All rights reserved. 2# 3# Licensed under the Apache License, Version 2.0 (the "License"); 4# you may not use this file except in compliance with the License. 5# You may obtain a copy of the License at 6# 7# http://www.apache.org/licenses/LICENSE-2.0 8# 9# Unless required by applicable law or agreed to in writing, software 10# distributed under the License is distributed on an "AS IS" BASIS, 11# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 12# See the License for the specific language governing permissions and 13# limitations under the License. 14 15"""Bazel Path APIs for the Android rules.""" 16 17# TODO(djwhang): Get the path separator in a platform agnostic manner. 18_PATH_SEP = "/" 19_TEST_SRCDIR = "${TEST_SRCDIR}" 20 21def _is_absolute(path): 22 # TODO(djwhang): This is not cross platform safe. Windows absolute paths 23 # do not start with "//", rather "C:\". 24 return path.startswith(_PATH_SEP) 25 26def _split(path): 27 return path.split(_PATH_SEP) 28 29def _join(path_segments): 30 return _PATH_SEP.join(path_segments) 31 32def _normalize_path(path, posix = False): 33 return _PATH_SEP.join( 34 _normalize_path_fragments( 35 path.split(_PATH_SEP), 36 posix = posix, 37 ), 38 ) 39 40def _normalize_path_fragments(path_fragments, posix = False): 41 normalized_path_fragments = [] 42 for idx, fragment in enumerate(path_fragments): 43 if not fragment and idx > 0: 44 continue 45 if fragment == ".": 46 continue 47 if fragment == ".." and not posix: 48 if normalized_path_fragments: 49 last = normalized_path_fragments.pop() 50 if last == ".." or last == "": 51 normalized_path_fragments.append(last) 52 else: 53 continue 54 normalized_path_fragments.append(fragment) 55 if len(normalized_path_fragments) == 1 and not normalized_path_fragments[0]: 56 normalized_path_fragments.append("") 57 return normalized_path_fragments 58 59def _relative_path(path1, path2): 60 if not path1 or _is_absolute(path2): 61 return path2 62 63 path1_fragments = _normalize_path_fragments(_split(path1)) 64 path2_fragments = _normalize_path_fragments(_split(path2)) 65 path1_idx = len(path1_fragments) # index move backwards 66 path2_idx = -1 67 for idx, fragment in enumerate(path2_fragments): 68 if fragment == "..": 69 path1_idx -= 1 70 else: 71 path2_idx = idx 72 break 73 74 relative_path_fragments = [] 75 if path1_idx >= 0: 76 relative_path_fragments.extend(path1_fragments[:path1_idx]) 77 if path2_idx >= 0: 78 relative_path_fragments.extend(path2_fragments[path2_idx:]) 79 return _join(_normalize_path_fragments(relative_path_fragments)) 80 81def _make_test_srcdir_path(ctx, *path_fragments): 82 """Creates a filepath relative to TEST_SRCDIR. 83 84 Args: 85 ctx: Starlark context. 86 *path_fragments: Directories/file to join into a single path. 87 Returns: 88 A filepath that's spearated by the host's filepath separator. 89 """ 90 fragments = [_TEST_SRCDIR, ctx.workspace_name] 91 for path_fragment in path_fragments: 92 fragments += _normalize_path_fragments(_split(path_fragment)) 93 return _join(fragments) 94 95path = struct( 96 is_absolute = _is_absolute, 97 join = _join, 98 normalize = _normalize_path, 99 relative = _relative_path, 100 split = _split, 101 make_test_srcdir_path = _make_test_srcdir_path, 102) 103