xref: /aosp_15_r20/external/bazel-skylib/rules/directory/private/paths.bzl (revision bcb5dc7965af6ee42bf2f21341a2ec00233a8c8a)
1*bcb5dc79SHONG Yifan# Copyright 2024 The Bazel Authors. All rights reserved.
2*bcb5dc79SHONG Yifan#
3*bcb5dc79SHONG Yifan# Licensed under the Apache License, Version 2.0 (the "License");
4*bcb5dc79SHONG Yifan# you may not use this file except in compliance with the License.
5*bcb5dc79SHONG Yifan# You may obtain a copy of the License at
6*bcb5dc79SHONG Yifan#
7*bcb5dc79SHONG Yifan#    http://www.apache.org/licenses/LICENSE-2.0
8*bcb5dc79SHONG Yifan#
9*bcb5dc79SHONG Yifan# Unless required by applicable law or agreed to in writing, software
10*bcb5dc79SHONG Yifan# distributed under the License is distributed on an "AS IS" BASIS,
11*bcb5dc79SHONG Yifan# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12*bcb5dc79SHONG Yifan# See the License for the specific language governing permissions and
13*bcb5dc79SHONG Yifan# limitations under the License.
14*bcb5dc79SHONG Yifan
15*bcb5dc79SHONG Yifan"""Skylib module containing path operations on directories."""
16*bcb5dc79SHONG Yifan
17*bcb5dc79SHONG Yifanload("//lib:paths.bzl", "paths")
18*bcb5dc79SHONG Yifan
19*bcb5dc79SHONG Yifan_NOT_FOUND = """{directory} does not contain an entry named {name}.
20*bcb5dc79SHONG YifanInstead, it contains the following entries:
21*bcb5dc79SHONG Yifan{children}
22*bcb5dc79SHONG Yifan
23*bcb5dc79SHONG Yifan"""
24*bcb5dc79SHONG Yifan_WRONG_TYPE = "Expected {dir}/{name} to have type {want}, but got {got}"
25*bcb5dc79SHONG Yifan
26*bcb5dc79SHONG Yifan# These correspond to an "enum".
27*bcb5dc79SHONG YifanFILE = "file"
28*bcb5dc79SHONG YifanDIRECTORY = "directory"
29*bcb5dc79SHONG Yifan
30*bcb5dc79SHONG Yifandef _check_path_relative(path):
31*bcb5dc79SHONG Yifan    if paths.is_absolute(path):
32*bcb5dc79SHONG Yifan        fail("Path must be relative. Got {path}".format(path = path))
33*bcb5dc79SHONG Yifan
34*bcb5dc79SHONG Yifandef _get_direct_child(directory, name, require_type = None):
35*bcb5dc79SHONG Yifan    """Gets the direct child of a directory.
36*bcb5dc79SHONG Yifan
37*bcb5dc79SHONG Yifan    Args:
38*bcb5dc79SHONG Yifan        directory: (DirectoryInfo) The directory to look within.
39*bcb5dc79SHONG Yifan        name: (string) The name of the directory/file to look for.
40*bcb5dc79SHONG Yifan        require_type: (Optional[DIRECTORY|FILE]) If provided, must return
41*bcb5dc79SHONG Yifan          either a the corresponding type.
42*bcb5dc79SHONG Yifan
43*bcb5dc79SHONG Yifan    Returns:
44*bcb5dc79SHONG Yifan        (File|DirectoryInfo) The content contained within.
45*bcb5dc79SHONG Yifan    """
46*bcb5dc79SHONG Yifan    entry = directory.entries.get(name, None)
47*bcb5dc79SHONG Yifan    if entry == None:
48*bcb5dc79SHONG Yifan        fail(_NOT_FOUND.format(
49*bcb5dc79SHONG Yifan            directory = directory.human_readable,
50*bcb5dc79SHONG Yifan            name = repr(name),
51*bcb5dc79SHONG Yifan            children = "\n".join(directory.entries.keys()),
52*bcb5dc79SHONG Yifan        ))
53*bcb5dc79SHONG Yifan    if require_type == DIRECTORY and type(entry) == "File":
54*bcb5dc79SHONG Yifan        fail(_WRONG_TYPE.format(
55*bcb5dc79SHONG Yifan            dir = directory.human_readable,
56*bcb5dc79SHONG Yifan            name = name,
57*bcb5dc79SHONG Yifan            want = "Directory",
58*bcb5dc79SHONG Yifan            got = "File",
59*bcb5dc79SHONG Yifan        ))
60*bcb5dc79SHONG Yifan
61*bcb5dc79SHONG Yifan    if require_type == FILE and type(entry) != "File":
62*bcb5dc79SHONG Yifan        fail(_WRONG_TYPE.format(
63*bcb5dc79SHONG Yifan            dir = directory.human_readable,
64*bcb5dc79SHONG Yifan            name = name,
65*bcb5dc79SHONG Yifan            want = "File",
66*bcb5dc79SHONG Yifan            got = "Directory",
67*bcb5dc79SHONG Yifan        ))
68*bcb5dc79SHONG Yifan    return entry
69*bcb5dc79SHONG Yifan
70*bcb5dc79SHONG Yifandef get_path(directory, path, require_type = None):
71*bcb5dc79SHONG Yifan    """Gets a subdirectory or file contained within a directory.
72*bcb5dc79SHONG Yifan
73*bcb5dc79SHONG Yifan    Example: `get_path(directory, "a/b", require_type=FILE)`
74*bcb5dc79SHONG Yifan      -> the file  corresponding to `directory.path + "/a/b"`
75*bcb5dc79SHONG Yifan
76*bcb5dc79SHONG Yifan    Args:
77*bcb5dc79SHONG Yifan        directory: (DirectoryInfo) The directory to look within.
78*bcb5dc79SHONG Yifan        path: (string) The path of the directory to look for within it.
79*bcb5dc79SHONG Yifan        require_type: (Optional[DIRECTORY|FILE]) If provided, must return
80*bcb5dc79SHONG Yifan          either a the corresponding type.
81*bcb5dc79SHONG Yifan
82*bcb5dc79SHONG Yifan    Returns:
83*bcb5dc79SHONG Yifan        (File|DirectoryInfo) The directory contained within.
84*bcb5dc79SHONG Yifan    """
85*bcb5dc79SHONG Yifan    _check_path_relative(path)
86*bcb5dc79SHONG Yifan
87*bcb5dc79SHONG Yifan    chunks = path.split("/")
88*bcb5dc79SHONG Yifan    for dirname in chunks[:-1]:
89*bcb5dc79SHONG Yifan        directory = _get_direct_child(directory, dirname, require_type = DIRECTORY)
90*bcb5dc79SHONG Yifan    return _get_direct_child(
91*bcb5dc79SHONG Yifan        directory,
92*bcb5dc79SHONG Yifan        chunks[-1],
93*bcb5dc79SHONG Yifan        require_type = require_type,
94*bcb5dc79SHONG Yifan    )
95