96 lines
4.8 KiB
CMake
96 lines
4.8 KiB
CMake
# Verify the complete inventory before installation and again at the destination.
|
|
include("${CMAKE_CURRENT_LIST_DIR}/WriteWindowsRuntimeManifest.cmake")
|
|
|
|
function(docview_verify_windows_worker executable output_files)
|
|
docview_runtime_file_info("${executable}" EXE worker_name worker_size)
|
|
get_filename_component(worker_directory "${executable}" DIRECTORY)
|
|
set(manifest "${executable}.runtime.json")
|
|
if(NOT EXISTS "${manifest}" OR IS_SYMLINK "${manifest}" OR IS_DIRECTORY "${manifest}")
|
|
message(FATAL_ERROR "Build the worker runtime manifest before installing: ${manifest}")
|
|
endif()
|
|
file(SIZE "${manifest}" manifest_size)
|
|
if(manifest_size LESS 1 OR manifest_size GREATER 131072)
|
|
message(FATAL_ERROR "Worker runtime manifest exceeds its size limit or is empty")
|
|
endif()
|
|
file(READ "${manifest}" inventory)
|
|
string(JSON root_type TYPE "${inventory}")
|
|
string(JSON fields LENGTH "${inventory}")
|
|
string(JSON version_type TYPE "${inventory}" schemaVersion)
|
|
string(JSON executable_type TYPE "${inventory}" executable)
|
|
string(JSON files_type TYPE "${inventory}" files)
|
|
string(JSON version GET "${inventory}" schemaVersion)
|
|
string(JSON declared_executable GET "${inventory}" executable)
|
|
string(JSON count LENGTH "${inventory}" files)
|
|
if(NOT root_type STREQUAL "OBJECT" OR NOT fields EQUAL 3 OR
|
|
NOT version_type STREQUAL "NUMBER" OR NOT version STREQUAL "1" OR
|
|
NOT executable_type STREQUAL "STRING" OR NOT declared_executable STREQUAL worker_name OR
|
|
NOT files_type STREQUAL "ARRAY" OR count LESS 1 OR count GREATER 128)
|
|
message(FATAL_ERROR "Invalid worker runtime inventory schema")
|
|
endif()
|
|
math(EXPR last "${count} - 1")
|
|
set(files)
|
|
set(names)
|
|
set(total 0)
|
|
set(found_executable FALSE)
|
|
foreach(index RANGE 0 ${last})
|
|
string(JSON entry_type TYPE "${inventory}" files ${index})
|
|
string(JSON fields LENGTH "${inventory}" files ${index})
|
|
string(JSON name_type TYPE "${inventory}" files ${index} path)
|
|
string(JSON hash_type TYPE "${inventory}" files ${index} sha256)
|
|
string(JSON size_type TYPE "${inventory}" files ${index} size)
|
|
string(JSON name GET "${inventory}" files ${index} path)
|
|
string(JSON expected_hash GET "${inventory}" files ${index} sha256)
|
|
string(JSON expected_size GET "${inventory}" files ${index} size)
|
|
string(LENGTH "${expected_hash}" hash_length)
|
|
if(NOT entry_type STREQUAL "OBJECT" OR NOT fields EQUAL 3 OR
|
|
NOT name_type STREQUAL "STRING" OR NOT hash_type STREQUAL "STRING" OR
|
|
NOT size_type STREQUAL "NUMBER" OR NOT expected_size MATCHES "^[1-9][0-9]*$" OR
|
|
NOT hash_length EQUAL 64 OR NOT expected_hash MATCHES "^[0-9a-f]+$")
|
|
message(FATAL_ERROR "Invalid worker runtime file record")
|
|
endif()
|
|
if(name STREQUAL worker_name)
|
|
set(kind EXE)
|
|
set(found_executable TRUE)
|
|
else()
|
|
set(kind DLL)
|
|
endif()
|
|
get_filename_component(basename "${name}" NAME)
|
|
if(NOT name STREQUAL basename)
|
|
message(FATAL_ERROR "Runtime manifest contains a non-basename path")
|
|
endif()
|
|
set(path "${worker_directory}/${name}")
|
|
docview_runtime_file_info("${path}" "${kind}" checked_name size)
|
|
string(TOLOWER "${name}" folded)
|
|
if(folded IN_LIST names)
|
|
message(FATAL_ERROR "Runtime manifest has a duplicate name")
|
|
endif()
|
|
list(APPEND names "${folded}")
|
|
math(EXPR total "${total} + ${size}")
|
|
if(NOT size EQUAL expected_size OR total GREATER 536870912)
|
|
message(FATAL_ERROR "Runtime file size no longer matches its build inventory: ${name}")
|
|
endif()
|
|
file(SHA256 "${path}" actual_hash)
|
|
if(NOT actual_hash STREQUAL expected_hash)
|
|
message(FATAL_ERROR "Runtime file no longer matches its build inventory: ${name}")
|
|
endif()
|
|
list(APPEND files "${path}")
|
|
endforeach()
|
|
if(NOT found_executable)
|
|
message(FATAL_ERROR "Runtime manifest is missing its worker executable")
|
|
endif()
|
|
set(${output_files} "${files}" PARENT_SCOPE)
|
|
endfunction()
|
|
|
|
docview_verify_windows_worker("${WORKER_EXECUTABLE}" verified_files)
|
|
if(NOT WORKER_VERIFY_ONLY)
|
|
if(NOT IS_ABSOLUTE "${WORKER_INSTALL_DIRECTORY}")
|
|
message(FATAL_ERROR "An absolute worker installation directory is required")
|
|
endif()
|
|
# file(INSTALL) applies DESTDIR itself. Its input must retain the unstaged
|
|
# install prefix; native tools and the verification below need the real path.
|
|
file(INSTALL DESTINATION "${WORKER_INSTALL_DIRECTORY}" TYPE FILE
|
|
FILES ${verified_files} "${WORKER_EXECUTABLE}.runtime.json")
|
|
get_filename_component(worker_name "${WORKER_EXECUTABLE}" NAME)
|
|
docview_verify_windows_worker("$ENV{DESTDIR}${WORKER_INSTALL_DIRECTORY}/${worker_name}" installed_files)
|
|
endif()
|