cmake_minimum_required(VERSION 3.19)
###########################################
#### Usage: cmake -DCMD= -P cmake/cmd.cmake
###########################################
function(EXECUTE)
execute_process(COMMAND ${ARGV} COMMAND_ECHO STDOUT COMMAND_ERROR_IS_FATAL ANY)
endfunction(EXECUTE)
function(MESSAGE type)
if(ARGV0 STREQUAL "STDOUT")
execute_process(COMMAND ${CMAKE_COMMAND} -E echo "${ARGN}")
else()
_MESSAGE(${type} "${ARGN}")
endif()
endfunction()
function(HASH)
if(NOT FILES)
message(FATAL_ERROR "You need to specify 'FILES'")
endif()
if(NOT ALGORITHM)
set(ALGORITHM SHA256)
endif()
string(TOLOWER "${ALGORITHM}" HASHFILE_ENDING)
file(GLOB GLOBBED_FILES RELATIVE "${CMAKE_CURRENT_BINARY_DIR}" "${FILES}")
foreach(f ${GLOBBED_FILES})
file(${ALGORITHM} ${f} fHash)
set(OUTPUT "${fHash} ${f}")
message(STDOUT ${OUTPUT})
if(CREATE_FILE)
file(WRITE ${f}.${HASHFILE_ENDING} "${OUTPUT}\n")
endif()
endforeach()
endfunction()
function(CHECK_WIX_WARNING)
list(APPEND EXPECTED_WARNINGS "CNDL1077.*WixShellExecTarget.*INSTALL_ROOT")
list(APPEND EXPECTED_WARNINGS "CNDL1077.*WixShellExecTarget.*ProductName")
list(APPEND EXPECTED_WARNINGS "LGHT1076.*ICE03.*CustomInstallDirDlg.SystemSettingsCheckBox")
list(APPEND EXPECTED_WARNINGS "LGHT1076.*ICE30.*AusweisApp2.*ProxyService")
list(APPEND EXPECTED_WARNINGS "LGHT1076.*ICE30.*AusweisApp2.*ProxyService")
list(APPEND EXPECTED_WARNINGS "LGHT1076.*ICE61.*product.*version")
list(LENGTH EXPECTED_WARNINGS EXPECTED_COUNT)
file(STRINGS "${FILE}" WIX_WARNINGS REGEX "warning")
foreach(m ${WIX_WARNINGS})
unset(KNOWN_WARNING)
foreach(e ${EXPECTED_WARNINGS})
string(REGEX MATCH "${e}" KNOWN_WARNING "${m}")
if(KNOWN_WARNING)
MATH(EXPR WARNING_COUNT "${WARNING_COUNT}+1")
break()
endif()
endforeach()
if(NOT KNOWN_WARNING)
message(STATUS "${m}\n")
MATH(EXPR UNKNOWN_WARNINGS "${UNKNOWN_WARNINGS}+1")
endif()
endforeach()
if(UNKNOWN_WARNINGS)
message(FATAL_ERROR "WiX log: Found ${UNKNOWN_WARNINGS} new warnings")
endif()
if(WARNING_COUNT EQUAL EXPECTED_COUNT)
message(STATUS "WiX log: Expectation met")
return()
endif()
if(WARNING_COUNT GREATER EXPECTED_COUNT)
message(FATAL_ERROR "WiX log: Found unexpected warnings")
else()
message(FATAL_ERROR "WiX log: Missing expected warnings")
endif()
endfunction()
function(DEPLOY_NEXUS)
find_program(MVN_BIN mvn)
if(NOT MVN_BIN)
message(FATAL_ERROR "Cannot find mvn")
endif()
set(SETTINGS_XML "
nexus
\${env.NEXUS_USERNAME}
\${env.NEXUS_PSW}
central
\${env.CENTRAL_USERNAME}
\${env.CENTRAL_PSW}
")
file(WRITE settings.xml "${SETTINGS_XML}")
function(get_file _suffix _out_var)
file(GLOB file RELATIVE ${CMAKE_BINARY_DIR} ${_suffix})
list(LENGTH file list_length)
if(list_length GREATER 1)
message(FATAL_ERROR "Found more than one entry: ${file}")
elseif(asc_length EQUAL 0)
message(FATAL_ERROR "File ${file} not found. Maybe signature is missing?")
endif()
set(${_out_var} ${file} PARENT_SCOPE)
endfunction()
get_file("*.aar" FILE_AAR)
get_file("*.pom" FILE_POM)
get_file("*-sources.jar" FILE_JAR)
file(STRINGS "${FILE_POM}" is_snapshot REGEX ".+-SNAPSHOT")
if(is_snapshot)
set(NEXUS_URL https://repo.govkg.de/repository/ausweisapp-snapshots)
else()
set(NEXUS_URL https://repo.govkg.de/repository/ausweisapp-releases)
endif()
set(MVN_CMD ${MVN_BIN} deploy:3.1.3:deploy-file -Dfile=${FILE_AAR} -DpomFile=${FILE_POM} -Dsources=${FILE_JAR} --settings settings.xml)
EXECUTE(${MVN_CMD} -DrepositoryId=nexus -Durl=${NEXUS_URL})
if(PUBLISH AND NOT is_snapshot)
set(CENTRAL_PARAMS -DrepositoryId=central -Durl=https://s01.oss.sonatype.org/service/local/staging/deploy/maven2)
EXECUTE(${MVN_CMD} ${CENTRAL_PARAMS})
get_file("*.aar.asc" FILE_AAR_ASC)
get_file("*.pom.asc" FILE_POM_ASC)
get_file("*-sources.jar.asc" FILE_SOURCES_ASC)
function(mvn_upload _file _packaging _classifier)
EXECUTE(${MVN_BIN} deploy:3.1.3:deploy-file -Dfile=${_file} -Dpackaging=${_packaging} -Dclassifier=${_classifier} -DpomFile=${FILE_POM} ${CENTRAL_PARAMS} --settings settings.xml)
endfunction()
mvn_upload("${FILE_AAR_ASC}" "aar.asc" "")
mvn_upload("${FILE_POM_ASC}" "pom.asc" "")
mvn_upload("${FILE_SOURCES_ASC}" "jar.asc" "sources")
endif()
file(REMOVE settings.xml)
endfunction()
function(CHECK_FAILURE_CODES)
file(STRINGS "src/global/FailureCode.h" LINES)
foreach(line ${LINES})
if(line MATCHES "enum class Reason")
set(ENUM_FOUND 1)
continue()
endif()
if(ENUM_FOUND)
if(line MATCHES "{")
continue()
endif()
if(line MATCHES "}")
break()
endif()
string(REGEX REPLACE "//.*" "" line ${line})
string(APPEND SINGLE_LINE ${line})
endif()
endforeach()
string(REGEX REPLACE "/\\*[^(\\*/)]*\\*/" "" SINGLE_LINE ${SINGLE_LINE})
string(REGEX MATCHALL "([a-zA-Z0-9_]+)" FAILURE_CODES ${SINGLE_LINE})
file(STRINGS "docs/failurecodes/failurecodes.rst" LINES_RST)
foreach(line_rst ${LINES_RST})
#match this pattern: " - | **Card_Removed**" with spaces or tabs as whitespaces.
string(REGEX MATCH "[ \\t]+-[ \\t]+\\|[ \\t]+\\*\\*([A-Za-z0-9_]+)\\*\\*" MATCH ${line_rst})
if(MATCH)
list(APPEND FAILURE_CODES_RST ${CMAKE_MATCH_1})
endif()
endforeach()
list(LENGTH FAILURE_CODES ENUM_CODE_COUNT)
list(LENGTH FAILURE_CODES_RST RST_CODE_COUNT)
if(NOT ENUM_CODE_COUNT EQUAL RST_CODE_COUNT)
message(FATAL_ERROR
"The failure code count in FailureCode.h (${ENUM_CODE_COUNT}) does not match the count in failurecodes.rst (${RST_CODE_COUNT})!")
endif()
file(GLOB_RECURSE SOURCE_FILES src/*.cpp)
foreach(code ${FAILURE_CODES})
if(NOT code IN_LIST FAILURE_CODES_RST)
message(FATAL_ERROR
"The failure code [${code}] is not part of failurecodes.rst. This hints a missing, duplicated or incorrectly spelled code in failurecodes.rst.")
endif()
set(COUNTER 0)
foreach(file ${SOURCE_FILES})
file(READ ${file} CONTENT)
string(REGEX MATCHALL "FailureCode::Reason::${code}" USAGE ${CONTENT})
list(LENGTH USAGE OCCURRENCES)
math(EXPR COUNTER ${COUNTER}+${OCCURRENCES})
endforeach()
if(NOT COUNTER EQUAL 1)
message(FATAL_ERROR "${code} is not used exactly one time. Found ${COUNTER}")
endif()
endforeach()
endfunction()
function(CHECK_QMLDIR)
file(GLOB_RECURSE QMLDIRS "${CMAKE_CURRENT_BINARY_DIR}/qmldir")
if(QMLDIRS STREQUAL "")
message(FATAL_ERROR "no qmldirs found: ${CMAKE_CURRENT_BINARY_DIR}")
endif()
foreach(file ${QMLDIRS})
get_filename_component(dir "${file}" DIRECTORY)
file(GLOB_RECURSE QMLFILES RELATIVE "${dir}" "${dir}/*.qml")
set(flatten_qmlfiles)
foreach(entry ${QMLFILES})
get_filename_component(name "${entry}" NAME)
list(APPEND flatten_qmlfiles ${name})
endforeach()
file(STRINGS "${file}" content)
# check if qmldir has invalid files
foreach(line ${content})
string(REGEX MATCH "[A-Za-z]+\\.qml$" _unused "${line}")
if(CMAKE_MATCH_0)
list(FIND flatten_qmlfiles ${CMAKE_MATCH_0} found)
if(found EQUAL -1)
string(REPLACE "${CMAKE_CURRENT_BINARY_DIR}/" "" subdir "${file}")
message(STATUS "${CMAKE_MATCH_0} not found in ${subdir}")
set(failed TRUE)
endif()
endif()
endforeach()
# check if qmldir has missing files
foreach(qmlfile ${flatten_qmlfiles})
string(REGEX MATCH "([A-Za-z]+)_[0-9\\.]+\\.qml" _unused "${qmlfile}")
if(CMAKE_MATCH_1)
set(qmlfile "${CMAKE_MATCH_1}.qml")
endif()
file(STRINGS "${file}" content REGEX " ${qmlfile}")
if(content STREQUAL "")
string(REPLACE "${CMAKE_CURRENT_BINARY_DIR}/" "" qmldir "${file}")
message(STATUS "${qmlfile} not found in ${qmldir}")
set(failed TRUE)
endif()
endforeach()
endforeach()
if(failed)
message(FATAL_ERROR "qmldir seems invalid")
endif()
endfunction()
function(CHECK_QMLTYPES)
file(GLOB_RECURSE QMLTYPES "${CMAKE_CURRENT_BINARY_DIR}/*.qmltypes")
if(QMLTYPES STREQUAL "")
message(FATAL_ERROR "no qmltypes found: ${CMAKE_CURRENT_BINARY_DIR}")
endif()
set(failed FALSE)
foreach(file ${QMLTYPES})
file(STRINGS "${file}" filecontent)
set(PARENT_NAME "")
set(ENUM_FOUND FALSE)
set(ENUM_NAME "")
set(ENUM_SCOPED FALSE)
foreach(line ${filecontent})
if(ENUM_FOUND)
if(line MATCHES "}")
if(NOT ENUM_SCOPED AND NOT PARENT_NAME MATCHES "governikus::Enum${ENUM_NAME}")
get_filename_component(file "${file}" NAME)
message(STATUS "${file}: ${ENUM_NAME} of ${PARENT_NAME} is not scoped")
set(failed TRUE)
endif()
set(ENUM_FOUND FALSE)
set(ENUM_NAME "")
set(ENUM_SCOPED FALSE)
elseif(line MATCHES "name: \"([A-Za-z]+)\"")
set(ENUM_NAME ${CMAKE_MATCH_1})
elseif(line MATCHES "isScoped: true")
set(ENUM_SCOPED TRUE)
endif()
elseif(line MATCHES "Enum {")
set(ENUM_FOUND TRUE)
elseif(line MATCHES "name: \"([A-Za-z:]+)\"")
set(PARENT_NAME ${CMAKE_MATCH_1})
endif()
endforeach()
endforeach()
if(failed)
message(FATAL_ERROR "Enum in qmltypes is not scoped")
endif()
endfunction()
if(NOT CMD)
message(FATAL_ERROR "You need to specify 'CMD'")
endif()
if(COMMAND "${CMD}")
cmake_language(CALL ${CMD})
else()
message(FATAL_ERROR "Unknown CMD: ${CMD}")
endif()