blob: 3466b3f3c89020ae87baeafd82505a9cbbe80ff6 [file] [edit]
# 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.")