| # Built-in cache documentation structural-parity lint. | |
| # | |
| # The table ``Source/cmCacheDocumentationTable.cxx`` is hand-maintained; | |
| # its set of entries is the curated list of CMake cache variables for | |
| # which ``cmake-gui`` and ``ccmake`` surface a built-in tooltip when the | |
| # on-disk ``HELPSTRING`` is empty (the common case for variables a user | |
| # sets via ``-D`` without an accompanying docstring). | |
| # | |
| # The sibling table ``Source/cmCachePatternTable.cxx`` carries the | |
| # placeholder-shaped fallbacks (``CMAKE_<LANG>_FLAGS``, | |
| # ``CMAKE_POLICY_DEFAULT_CMP<NNNN>``, ``<PROJECT-NAME>_VERSION``, ...). | |
| # Patterns store their placeholder names with angle brackets; the | |
| # corresponding ``Help/variable/<NAME>.rst`` filenames carry the same | |
| # placeholder tokens with the brackets stripped. | |
| # | |
| # Drift between an entry's wording and its source ``Help/variable/*.rst`` | |
| # manual is handled by reviewer discipline : when an ``.rst`` is reworded, | |
| # the matching table entry is reviewed in the same change. This test | |
| # therefore enforces only the one piece of drift that a human reviewer | |
| # would not naturally catch: that every entry NAME in both tables still | |
| # resolves to an existing ``Help/variable/<NAME>.rst`` file (so the | |
| # tooltip is never silently divorced from a real manual via a typo, a | |
| # rename, or a deletion). | |
| if(NOT DEFINED CMake_SOURCE_DIR OR NOT IS_DIRECTORY "${CMake_SOURCE_DIR}") | |
| message(FATAL_ERROR | |
| "CacheVarHelpCoverage: CMake_SOURCE_DIR was not provided.") | |
| endif() | |
| set(_help_dir "${CMake_SOURCE_DIR}/Help/variable") | |
| set(_table_file "${CMake_SOURCE_DIR}/Source/cmCacheDocumentationTable.cxx") | |
| set(_pattern_file "${CMake_SOURCE_DIR}/Source/cmCachePatternTable.cxx") | |
| if(NOT IS_DIRECTORY "${_help_dir}") | |
| message(FATAL_ERROR | |
| "CacheVarHelpCoverage: ${_help_dir} does not exist.") | |
| endif() | |
| if(NOT EXISTS "${_table_file}") | |
| message(FATAL_ERROR | |
| "CacheVarHelpCoverage: ${_table_file} does not exist.") | |
| endif() | |
| if(NOT EXISTS "${_pattern_file}") | |
| message(FATAL_ERROR | |
| "CacheVarHelpCoverage: ${_pattern_file} does not exist.") | |
| endif() | |
| # Extract entry names from the C++ exact-match table. Each entry begins | |
| # with the fixed pattern ``\n { "NAME",``; see the header comment in | |
| # cmCacheDocumentationTable.cxx for the layout convention. | |
| file(READ "${_table_file}" _table_text) | |
| string(REGEX MATCHALL "\n \\{ \"[^\"]+\"" _hits "${_table_text}") | |
| set(_table_names) | |
| foreach(_hit IN LISTS _hits) | |
| string(REGEX REPLACE "^\n \\{ \"" "" _name "${_hit}") | |
| string(REGEX REPLACE "\"$" "" _name "${_name}") | |
| list(APPEND _table_names "${_name}") | |
| endforeach() | |
| list(SORT _table_names) | |
| # Extract entry patterns from the C++ pattern table. Same row shape as | |
| # above; the pattern strings carry angle-bracketed placeholders like | |
| # ``CMAKE_<LANG>_FLAGS`` or ``<PROJECT-NAME>_VERSION``. Strip the | |
| # angle brackets to derive the matching ``.rst`` basename | |
| # (``CMAKE_LANG_FLAGS.rst`` etc.). | |
| file(READ "${_pattern_file}" _pattern_text) | |
| string(REGEX MATCHALL "\n \\{ \"[^\"]+\"" _phits "${_pattern_text}") | |
| set(_pattern_names) | |
| foreach(_hit IN LISTS _phits) | |
| string(REGEX REPLACE "^\n \\{ \"" "" _name "${_hit}") | |
| string(REGEX REPLACE "\"$" "" _name "${_name}") | |
| list(APPEND _pattern_names "${_name}") | |
| endforeach() | |
| list(SORT _pattern_names) | |
| # Table entries whose NAME does not match an existing | |
| # Help/variable/<NAME>.rst manual. | |
| set(_missing_exact) | |
| foreach(_name IN LISTS _table_names) | |
| if(NOT EXISTS "${_help_dir}/${_name}.rst") | |
| list(APPEND _missing_exact "${_name}") | |
| endif() | |
| endforeach() | |
| # Pattern entries whose NAME (with ``<`` and ``>`` stripped) does not | |
| # match an existing Help/variable/<NAME>.rst manual. | |
| set(_missing_pattern) | |
| foreach(_name IN LISTS _pattern_names) | |
| string(REPLACE "<" "" _basename "${_name}") | |
| string(REPLACE ">" "" _basename "${_basename}") | |
| if(NOT EXISTS "${_help_dir}/${_basename}.rst") | |
| list(APPEND _missing_pattern "${_name}") | |
| endif() | |
| endforeach() | |
| if(_missing_exact OR _missing_pattern) | |
| set(_msg "Built-in cache documentation coverage check failed.") | |
| if(_missing_exact) | |
| list(LENGTH _missing_exact _n) | |
| string(APPEND _msg | |
| "\n\n${_n} entry/entries in Source/cmCacheDocumentationTable.cxx" | |
| "\nhave no matching Help/variable/<NAME>.rst manual:") | |
| foreach(_name IN LISTS _missing_exact) | |
| string(APPEND _msg "\n ${_name}") | |
| endforeach() | |
| endif() | |
| if(_missing_pattern) | |
| list(LENGTH _missing_pattern _n) | |
| string(APPEND _msg | |
| "\n\n${_n} entry/entries in Source/cmCachePatternTable.cxx" | |
| "\nhave no matching Help/variable/<NAME>.rst manual (the " | |
| "placeholder tokens carry through verbatim with ``<``/``>`` " | |
| "stripped):") | |
| foreach(_name IN LISTS _missing_pattern) | |
| string(REPLACE "<" "" _basename "${_name}") | |
| string(REPLACE ">" "" _basename "${_basename}") | |
| string(APPEND _msg "\n ${_name} -> ${_basename}.rst") | |
| endforeach() | |
| endif() | |
| string(APPEND _msg | |
| "\n\nLikely causes and remedies:" | |
| "\n * The entry NAME / Pattern is misspelled -- fix the spelling." | |
| "\n * Help/variable/<NAME>.rst was renamed -- update the entry to" | |
| "\n match the new filename." | |
| "\n * Help/variable/<NAME>.rst was deleted intentionally -- remove" | |
| "\n the corresponding entry from the table.") | |
| message(FATAL_ERROR "${_msg}") | |
| endif() | |
| list(LENGTH _table_names _n_tab) | |
| list(LENGTH _pattern_names _n_pat) | |
| message(STATUS | |
| "Built-in cache documentation coverage OK: " | |
| "${_n_tab} exact entry/entries + ${_n_pat} pattern entry/entries, " | |
| "all matched to Help/variable/*.rst.") |