| # Copyright 2019 gRPC authors. |
| # |
| # 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. |
| """Buildgen attribute validation plugin.""" |
| |
| |
| def anything(): |
| return lambda v: None |
| |
| |
| def one_of(values): |
| return lambda v: ( |
| "{0} is not in [{1}]".format(v, values) if v not in values else None |
| ) |
| |
| |
| def subset_of(values): |
| return lambda v: ( |
| "{0} is not subset of [{1}]".format(v, values) |
| if not all(e in values for e in v) |
| else None |
| ) |
| |
| |
| VALID_ATTRIBUTE_KEYS_MAP = { |
| "filegroup": { |
| "deps": anything(), |
| "headers": anything(), |
| "plugin": anything(), |
| "public_headers": anything(), |
| "src": anything(), |
| "uses": anything(), |
| }, |
| "lib": { |
| "asm_src": anything(), |
| "baselib": anything(), |
| "boringssl": one_of((True,)), |
| "build_system": anything(), |
| "build": anything(), |
| "cmake_target": anything(), |
| "defaults": anything(), |
| "deps_linkage": one_of(("static",)), |
| "deps": anything(), |
| "dll": one_of((True, "only")), |
| "filegroups": anything(), |
| "generate_plugin_registry": anything(), |
| "headers": anything(), |
| "language": one_of(("c", "c++", "csharp")), |
| "LDFLAGS": anything(), |
| "platforms": subset_of(("linux", "mac", "posix", "windows")), |
| "public_headers": anything(), |
| "secure": one_of(("check", True, False)), |
| "src": anything(), |
| "vs_proj_dir": anything(), |
| "zlib": one_of((True,)), |
| }, |
| "target": { |
| "args": anything(), |
| "benchmark": anything(), |
| "boringssl": one_of((True,)), |
| "build": anything(), |
| "ci_platforms": anything(), |
| "corpus_dirs": anything(), |
| "cpu_cost": anything(), |
| "defaults": anything(), |
| "deps": anything(), |
| "dict": anything(), |
| "exclude_configs": anything(), |
| "exclude_iomgrs": anything(), |
| "excluded_poll_engines": anything(), |
| "filegroups": anything(), |
| "flaky": one_of((True, False)), |
| "gtest": one_of((True, False)), |
| "headers": anything(), |
| "language": one_of(("c", "c89", "c++", "csharp")), |
| "maxlen": anything(), |
| "platforms": subset_of(("linux", "mac", "posix", "windows")), |
| "plugin_option": anything(), |
| "run": one_of((True, False)), |
| "secure": one_of(("check", True, False)), |
| "src": anything(), |
| "timeout_seconds": anything(), |
| "uses_polling": anything(), |
| "vs_proj_dir": anything(), |
| "zlib": one_of((True,)), |
| }, |
| "external_proto_library": { |
| "destination": anything(), |
| "proto_prefix": anything(), |
| "urls": anything(), |
| "hash": anything(), |
| "strip_prefix": anything(), |
| }, |
| } |
| |
| |
| def check_attributes(entity, kind, errors): |
| attributes = VALID_ATTRIBUTE_KEYS_MAP[kind] |
| name = entity.get("name", anything()) |
| for key, value in list(entity.items()): |
| if key == "name": |
| continue |
| validator = attributes.get(key) |
| if validator: |
| error = validator(value) |
| if error: |
| errors.append( |
| "{0}({1}) has an invalid value for '{2}': {3}".format( |
| name, kind, key, error |
| ) |
| ) |
| else: |
| errors.append( |
| "{0}({1}) has an invalid attribute '{2}'".format( |
| name, kind, key |
| ) |
| ) |
| |
| |
| def mako_plugin(dictionary): |
| """The exported plugin code for check_attr. |
| |
| This validates that filegroups, libs, and target can have only valid |
| attributes. This is mainly for preventing build.yaml from having |
| unnecessary and misleading attributes accidentally. |
| """ |
| |
| errors = [] |
| for filegroup in dictionary.get("filegroups", {}): |
| check_attributes(filegroup, "filegroup", errors) |
| for lib in dictionary.get("libs", {}): |
| check_attributes(lib, "lib", errors) |
| for target in dictionary.get("targets", {}): |
| check_attributes(target, "target", errors) |
| for target in dictionary.get("external_proto_libraries", {}): |
| check_attributes(target, "external_proto_library", errors) |
| if errors: |
| raise Exception("\n".join(errors)) |