Skip to content

Commit

Permalink
common/options: validate see-also
Browse files Browse the repository at this point in the history
y2c.py is like a compiler which translates .yaml to .cc and .h files,
it does not have access to all .yaml files. to validate the dangling
see-also issue, we need to do this with a "linker".

in this change, validate-options.py is introduced to check if any of
option name included by the see-also property is valid.

Fixes: https://tracker.ceph.com/issues/51483
Signed-off-by: Kefu Chai <kchai@redhat.com>
  • Loading branch information
tchaikov committed Aug 23, 2021
1 parent b7cace0 commit fc1a4e8
Show file tree
Hide file tree
Showing 2 changed files with 55 additions and 2 deletions.
8 changes: 6 additions & 2 deletions src/common/options/CMakeLists.txt
Original file line number Diff line number Diff line change
@@ -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
Expand All @@ -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
Expand Down Expand Up @@ -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})
49 changes: 49 additions & 0 deletions src/common/options/validate-options.py
Original file line number Diff line number Diff line change
@@ -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)

0 comments on commit fc1a4e8

Please sign in to comment.