# 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")), "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))