diff --git a/src/common/options/CMakeLists.txt b/src/common/options/CMakeLists.txt index 86de2e7972c803..b432d866fa0c8e 100644 --- a/src/common/options/CMakeLists.txt +++ b/src/common/options/CMakeLists.txt @@ -1,5 +1,6 @@ set(common_options_srcs build_options.cc) set(legacy_options_headers) +set(options_yamls) # to mimic the behavior of file(CONFIGURE ...) file(GENERATE OUTPUT configure_file.cmake @@ -26,6 +27,8 @@ function(add_options name) set(yaml_file ${CMAKE_CURRENT_BINARY_DIR}/${name}.yaml) file_configure("${yaml_in_file}" "${yaml_file}" @ONLY) + string(APPEND options_yamls " ${yaml_file}") + set(options_yamls ${options_yamls} PARENT_SCOPE) set(cc_file "${name}_options.cc") set(h_file "${PROJECT_BINARY_DIR}/include/${name}_legacy_options.h") add_custom_command(PRE_BUILD @@ -100,5 +103,6 @@ add_options(rgw) add_library(common-options-objs OBJECT ${common_options_srcs}) -add_custom_target(legacy-option-headers - DEPENDS ${legacy_options_headers}) + +add_ceph_test(validate-options + ${Python3_EXECUTABLE} ${CMAKE_CURRENT_SOURCE_DIR}/validate-options.py ${options_yamls}) diff --git a/src/common/options/validate-options.py b/src/common/options/validate-options.py new file mode 100755 index 00000000000000..5bc5d4d4673632 --- /dev/null +++ b/src/common/options/validate-options.py @@ -0,0 +1,49 @@ +#!/usr/bin/env python3 + +import argparse +import fileinput +import sys +import yaml +from typing import Any, Dict + + +class ValidationError(Exception): + pass + + +OptionType = Dict[str, Any] + + +def validate_see_also(opt: OptionType, opts: Dict[str, OptionType]) -> None: + see_also = opt.get('see_also') + if see_also is None: + return + for ref in see_also: + if ref not in opts: + msg = f'see_also contains "{ref}". But it is not found.' + raise ValidationError(msg) + + +def main() -> None: + parser = argparse.ArgumentParser( + formatter_class=argparse.ArgumentDefaultsHelpFormatter) + parser.add_argument('yamls', nargs='*') + opts = parser.parse_args() + options = {} + for yaml_file in opts.yamls: + with open(yaml_file) as f: + yml = yaml.load(f, yaml.SafeLoader) + options.update({opt['name']: opt for opt in yml['options']}) + for name, opt in options.items(): + try: + validate_see_also(opt, options) + except ValidationError as e: + raise Exception(f'failed to validate "{name}": {e}') + + +if __name__ == '__main__': + try: + main() + except Exception as e: + print(e, file=sys.stderr) + sys.exit(1)