• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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