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