# Copyright 2024 The Bazel Authors. All rights reserved. # # Licensed under the Apache License, Version 2.0 (the "License"); # you may not use this file except in compliance with the License. # You may obtain a copy of the License at # # http://www.apache.org/licenses/LICENSE-2.0 # # Unless required by applicable law or agreed to in writing, software # distributed under the License is distributed on an "AS IS" BASIS, # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. # See the License for the specific language governing permissions and # limitations under the License. """Skylib module containing path operations on directories.""" load("//lib:paths.bzl", "paths") _NOT_FOUND = """{directory} does not contain an entry named {name}. Instead, it contains the following entries: {children} """ _WRONG_TYPE = "Expected {dir}/{name} to have type {want}, but got {got}" # These correspond to an "enum". FILE = "file" DIRECTORY = "directory" def _check_path_relative(path): if paths.is_absolute(path): fail("Path must be relative. Got {path}".format(path = path)) def _get_direct_child(directory, name, require_type = None): """Gets the direct child of a directory. Args: directory: (DirectoryInfo) The directory to look within. name: (string) The name of the directory/file to look for. require_type: (Optional[DIRECTORY|FILE]) If provided, must return either a the corresponding type. Returns: (File|DirectoryInfo) The content contained within. """ entry = directory.entries.get(name, None) if entry == None: fail(_NOT_FOUND.format( directory = directory.human_readable, name = repr(name), children = "\n".join(directory.entries.keys()), )) if require_type == DIRECTORY and type(entry) == "File": fail(_WRONG_TYPE.format( dir = directory.human_readable, name = name, want = "Directory", got = "File", )) if require_type == FILE and type(entry) != "File": fail(_WRONG_TYPE.format( dir = directory.human_readable, name = name, want = "File", got = "Directory", )) return entry def get_path(directory, path, require_type = None): """Gets a subdirectory or file contained within a directory. Example: `get_path(directory, "a/b", require_type=FILE)` -> the file corresponding to `directory.path + "/a/b"` Args: directory: (DirectoryInfo) The directory to look within. path: (string) The path of the directory to look for within it. require_type: (Optional[DIRECTORY|FILE]) If provided, must return either a the corresponding type. Returns: (File|DirectoryInfo) The directory contained within. """ _check_path_relative(path) chunks = path.split("/") for dirname in chunks[:-1]: directory = _get_direct_child(directory, dirname, require_type = DIRECTORY) return _get_direct_child( directory, chunks[-1], require_type = require_type, )