xref: /aosp_15_r20/external/pigweed/pw_build/glob_dirs.bzl (revision 61c4878ac05f98d0ceed94b57d316916de578985)
1# Copyright 2024 The Pigweed Authors
2#
3# Licensed under the Apache License, Version 2.0 (the "License"); you may not
4# use this file except in compliance with the License. You may obtain a copy of
5# the License at
6#
7#     https://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, WITHOUT
11# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
12# License for the specific language governing permissions and limitations under
13# the License.
14"""Helpers that use wildcards to match one or more directories."""
15
16def match_dir_internal(include, exclude = [], allow_empty = True, _fail_callback = fail):
17    """The actual implementation of match_dir with more testability.
18
19    DO NOT USE THIS DIRECTLY!!! Use `match_dir()`!
20
21    Args:
22      include: A list of wildcard patterns to match against.
23      exclude: A list of wildcard patterns to exclude.
24      allow_empty: Whether or not to permit returning `None`.
25      _fail_callback: Callback to call when an error is encountered.
26
27    Returns:
28      Path to a single directory that matches the specified constraints.
29    """
30    matches = glob_dirs(
31        include,
32        exclude,
33        allow_empty = allow_empty,
34    )
35    if not allow_empty and not matches:
36        return _fail_callback(
37            ("glob pattern {} didn't match anything, but allow_empty is set " +
38             "to False").format(include),
39        )
40    if len(matches) > 1:
41        return _fail_callback(
42            ("glob pattern {} matches multiple directories when only one " +
43             "was requested: {}").format(include, matches),
44        )
45    return matches[0] if matches else None
46
47def match_dir(include, exclude = [], allow_empty = True):
48    """Identifies a single directory using a wildcard pattern.
49
50    This helper follows the same semantics as Bazel's native glob() function,
51    but only matches a single directory. If more than one match is found, this
52    will fail.
53
54    Args:
55      include: A list of wildcard patterns to match against.
56      exclude: A list of wildcard patterns to exclude.
57      allow_empty: Whether or not to permit returning `None`.
58
59    Returns:
60      Path to a single directory that matches the specified constraints, or
61      `None` if no match is found and `allow_empty` is `True`.
62    """
63    return match_dir_internal(
64        include,
65        exclude = exclude,
66        allow_empty = allow_empty,
67    )
68
69def glob_dirs(include, exclude = [], allow_empty = True):
70    """Matches the provided glob pattern to identify a list of directories.
71
72    This helper follows the same semantics as Bazel's native glob() function,
73    but only matches directories.
74
75    Args:
76      include: A list of wildcard patterns to match against.
77      exclude: A list of wildcard patterns to exclude.
78      allow_empty: Whether or not to permit an empty list of matches.
79
80    Returns:
81      List of directory paths that match the specified constraints.
82    """
83    without_dirs = native.glob(
84        include,
85        exclude,
86        exclude_directories = 1,
87        allow_empty = True,
88    )
89    with_dirs = native.glob(
90        include,
91        exclude,
92        exclude_directories = 0,
93        allow_empty = allow_empty,
94    )
95    results = {p: None for p in with_dirs}
96    for p in without_dirs:
97        results.pop(p)
98
99    return list(results.keys())
100