diff --git a/CMake/MITKDashboardScript.download.cmake b/CMake/MITKDashboardScript.download.cmake index 7d8d298127..ce4796c377 100644 --- a/CMake/MITKDashboardScript.download.cmake +++ b/CMake/MITKDashboardScript.download.cmake @@ -1,464 +1,508 @@ #[===========================================================================[ Helper functions ]===========================================================================] -#[[ Call vswhere tool to query properties of the installed Visual Studio +#[[ Call the vswhere tool to query properties of installed Visual Studio versions. - Use OUTPUT_VARIABLE to specify the variable that is used to store the - output of vswhere. All other arguments are passed to vswhere. + Use OUTPUT_VARIABLE to specify the variable for storing the output + of vswhere. All other arguments are passed to vswhere. The OUTPUT_VARIABLE is not touched if vswhere was not found or returned an error. ]] function(vswhere) cmake_parse_arguments(VSWHERE "" OUTPUT_VARIABLE "" ${ARGN}) if(NOT VSWHERE_OUTPUT_VARIABLE) return() endif() set(program_files_x86 "ProgramFiles(x86)") set(vswhere_executable "$ENV{${program_files_x86}}\\Microsoft Visual Studio\\Installer\\vswhere.exe") if(EXISTS ${vswhere_executable}) execute_process(COMMAND ${vswhere_executable} ${VSWHERE_UNPARSED_ARGUMENTS} RESULT_VARIABLE exit_code OUTPUT_VARIABLE output OUTPUT_STRIP_TRAILING_WHITESPACE) if(exit_code EQUAL 0 AND output) set(${VSWHERE_OUTPUT_VARIABLE} ${output} PARENT_SCOPE) endif() endif() endfunction() #[[ Extract the product line and major version from CTEST_CMAKE_GENERATOR if it starts with "Visual Studio xx yyyy", where xx is the major version and yyyy the product line. - Use PRODUCT_LINE and MAJOR_VERSION to specify the variables that are - used to store the results. ]] + Use PRODUCT_LINE and MAJOR_VERSION to specify the variables for storing + the results. ]] function(parse_visual_studio_generator) cmake_parse_arguments(VS "" "PRODUCT_LINE;MAJOR_VERSION" "" ${ARGN}) if(CTEST_CMAKE_GENERATOR MATCHES "^Visual Studio ([0-9]+) ([0-9]+)") if(VS_MAJOR_VERSION) set(${VS_MAJOR_VERSION} ${CMAKE_MATCH_1} PARENT_SCOPE) endif() if(VS_PRODUCT_LINE) set(${VS_PRODUCT_LINE} ${CMAKE_MATCH_2} PARENT_SCOPE) endif() endif() endfunction() function(get_os) cmake_parse_arguments(OS "" "NAME;VERSION" "" ${ARGN}) if(APPLE) if(OS_NAME) set(${OS_NAME} macOS PARENT_SCOPE) endif() if(OS_VERSION) execute_process(COMMAND sw_vers -productVersion RESULT_VARIABLE exit_code OUTPUT_VARIABLE version OUTPUT_STRIP_TRAILING_WHITESPACE) if(exit_code EQUAL 0 AND version) set(${OS_VERSION} ${version} PARENT_SCOPE) endif() endif() elseif(UNIX AND EXISTS /etc/os-release) # Linux with systemd file(READ /etc/os-release os_release) if(OS_NAME AND os_release MATCHES "NAME=\\\"?([^\\\"\\n]+)") set(${OS_NAME} ${CMAKE_MATCH_1} PARENT_SCOPE) endif() if(OS_VERSION AND os_release MATCHES "VERSION_ID=\\\"?([^\\\"\\n]+)") set(${OS_VERSION} ${CMAKE_MATCH_1} PARENT_SCOPE) endif() elseif(WIN32) if(OS_NAME) set(${OS_NAME} Windows PARENT_SCOPE) endif() if(OS_VERSION) execute_process(COMMAND wmic os get Version -value RESULT_VARIABLE exit_code OUTPUT_VARIABLE version OUTPUT_STRIP_TRAILING_WHITESPACE) if(exit_code EQUAL 0 AND version) if(version MATCHES "Version=([0-9]+)\\.([0-9]+)") set(${OS_VERSION} ${CMAKE_MATCH_1} PARENT_SCOPE) if(CMAKE_MATCH_2) set(${OS_VERSION} "${OS_VERSION}.${CMAKE_MATCH_2}" PARENT_SCOPE) endif() endif() + else() + set(${OS_VERSION} "" PARENT_SCOPE) endif() endif() endif() endfunction() -#[[ Try to make up a descriptive build name (CTEST_BUILD_NAME) out of the - operating system and the compiler. ]] +#[[ Try to make up a descriptive build name (CTEST_BUILD_NAME) based on the + operating system and compiler. ]] function(set_default_build_name) unset(build_name) # Step 1/2: Determine operating system get_os(NAME os_name VERSION os_version) if(os_name AND os_version) set(build_name "${os_name} ${os_version}") else() # Fallback: use CMake variables that describe the system set(build_name ${CMAKE_SYSTEM_NAME}) if(CMAKE_SYSTEM_VERSION) # Not set in script mode. Give it a try, though. set(build_name "${build_name} ${CMAKE_SYSTEM_VERSION}") endif() endif() # Step 2/2: Determine compiler if(APPLE) # TODO elseif(UNIX) # TODO else() parse_visual_studio_generator(PRODUCT_LINE product_line MAJOR_VERSION version) if(product_line) set(build_name "${build_name} Visual Studio ${product_line}") vswhere(-version ${version} -property catalog_productDisplayVersion OUTPUT_VARIABLE exact_version) if(exact_version) set(build_name "${build_name} v${exact_version}") endif() endif() endif() set(CTEST_BUILD_NAME ${build_name} PARENT_SCOPE) endfunction() function(parse_mitk_extension) cmake_parse_arguments(EXTENSION "" "SOURCE_DIR;GIT_REPOSITORY;GIT_TAG" "" ${ARGN}) if(EXTENSION_UNPARSED_ARGUMENTS MATCHES "([^|]+)\\|([^|]+)\\|(.+)") if(EXTENSION_SOURCE_DIR) set(${EXTENSION_SOURCE_DIR} ${CMAKE_MATCH_1} PARENT_SCOPE) endif() if(EXTENSION_GIT_REPOSITORY) set(${EXTENSION_GIT_REPOSITORY} ${CMAKE_MATCH_2} PARENT_SCOPE) endif() if(EXTENSION_GIT_TAG) set(${EXTENSION_GIT_TAG} ${CMAKE_MATCH_3} PARENT_SCOPE) endif() endif() endfunction() #[[ Print colored text if terminal supports ANSI escape codes. Formatting is done with nested or interleaved HTML-style elements. Supported elements are , , , and . ]] function(print) set(text "${ARGV0}") if(UNIX OR (WIN32 AND "$ENV{MSYSTEM}" MATCHES "^MINGW")) set(stack "white") # Manage stack to handle nested/interleaved elements while(1) # Iterate over text and replace all tags with ANSI escape codes if(text MATCHES "<(/?)([a-z]+)>") # Find next element tag set(token "<${CMAKE_MATCH_1}${CMAKE_MATCH_2}>") if(NOT CMAKE_MATCH_1) # Start tag list(INSERT stack 0 "${CMAKE_MATCH_2}") # Push front else() # End tag list(FIND stack "${CMAKE_MATCH_2}" index) if(NOT index EQUAL -1) list(REMOVE_AT stack ${index}) # Pop first matching tag endif() endif() # Find same tag again but this time with position and length string(FIND "${text}" "${token}" position) string(LENGTH "${token}" length) # Slice text to eventually replace only the current tag string(SUBSTRING "${text}" 0 ${position} left) math(EXPR position "${position} + ${length}") string(SUBSTRING "${text}" ${position} -1 right) list(FIND stack "bold" bold) if(bold EQUAL -1) # Text is not bold, color at first index set(bold 0) set(index 0) elseif(bold EQUAL 0) # Text is bold, color at second index set(bold 1) set(index 1) else() # Text is bold, color at first index set(bold 1) set(index 0) endif() list(GET stack ${index} color) if(color STREQUAL "red") set(color_code 31) elseif(color STREQUAL "green") set(color_code 32) elseif(color STREQUAL "yellow") set(color_code 33) else() # "white" set(color_code 37) endif() string(ASCII 27 esc) set(text "${left}${esc}[${bold};${color_code}m${right}") else() break() endif() endwhile() - else() + else() # No ANSI escape code support, get rid of tags string(REGEX REPLACE "<(/?)([a-z]+)>" "" text "${text}") endif() message("${text}") endfunction() +function(git) + cmake_parse_arguments(GIT "" "OUTPUT_VARIABLE;WORKING_DIRECTORY;EXIT_CODE" "" ${ARGN}) + + execute_process(COMMAND ${CTEST_GIT_COMMAND} ${GIT_UNPARSED_ARGUMENTS} + WORKING_DIRECTORY "${GIT_WORKING_DIRECTORY}" + RESULT_VARIABLE exit_code + OUTPUT_VARIABLE output + OUTPUT_STRIP_TRAILING_WHITESPACE) + + if(GIT_OUTPUT_VARIABLE) + set(${GIT_OUTPUT_VARIABLE} ${output} PARENT_SCOPE) + endif() + + if(GIT_EXIT_CODE) + set(${GIT_EXIT_CODE} ${exit_code} PARENT_SCOPE) + endif() +endfunction() + +function(git_log) + cmake_parse_arguments(LOG "" "AUTHOR;COMMIT_HASH;COMMITTER;SUBJECT;WORKING_DIRECTORY" "" ${ARGN}) + set(git_args WORKING_DIRECTORY "${LOG_WORKING_DIRECTORY}" log -1) + + if(LOG_AUTHOR) + git(${git_args} --pretty=%an OUTPUT_VARIABLE author) + if(author) + set(${LOG_AUTHOR} ${author} PARENT_SCOPE) + endif() + endif() + if(LOG_COMMIT_HASH) + git(${git_args} --pretty=%h OUTPUT_VARIABLE commit_hash) + if(commit_hash) + set(${LOG_COMMIT_HASH} ${commit_hash} PARENT_SCOPE) + endif() + endif() + if(LOG_COMMITTER) + git(${git_args} --pretty=%cn OUTPUT_VARIABLE committer) + if(committer) + set(${LOG_COMMITTER} ${committer} PARENT_SCOPE) + endif() + endif() + if(LOG_SUBJECT) + git(${git_args} --pretty=%s OUTPUT_VARIABLE subject) + if(subject) + set(${LOG_SUBJECT} ${subject} PARENT_SCOPE) + endif() + endif() +endfunction() + #[===========================================================================[ Actual script ]===========================================================================] find_program(CTEST_GIT_COMMAND git) +#[[ Assemble Git commands twofold: As strings in specific CTest variables that + are picked up automatically by ctest_start() and ctest_update() and as + lists as expected by execute_process() to manually execute Git. ]] + set(CTEST_CHECKOUT_COMMAND "\"${CTEST_GIT_COMMAND}\" clone") -set(checkout_command "${CTEST_GIT_COMMAND}" clone --quiet) +set(checkout_command clone --quiet) if(GIT_SHALLOW_CLONE) set(CTEST_CHECKOUT_COMMAND "${CTEST_CHECKOUT_COMMAND} --depth 1") list(APPEND checkout_command --depth 1) endif() set(CTEST_CHECKOUT_COMMAND "${CTEST_CHECKOUT_COMMAND} --branch ${MITK_TAG} ${MITK_REPOSITORY} MITK") set(CTEST_UPDATE_OPTIONS "--quiet") set(update_options --quiet) if(GIT_SHALLOW_CLONE) set(CTEST_UPDATE_OPTIONS "${CTEST_UPDATE_OPTIONS} --depth=1") list(APPEND update_options --depth=1) endif() set(CTEST_UPDATE_OPTIONS "${CTEST_UPDATE_OPTIONS} origin ${MITK_TAG}") list(APPEND update_options origin) set(CTEST_SOURCE_DIRECTORY "${CMAKE_CURRENT_LIST_DIR}/src/MITK") set(CTEST_BINARY_DIRECTORY "${CMAKE_CURRENT_LIST_DIR}/build") site_name(CTEST_SITE) if(NOT CTEST_BUILD_NAME) set_default_build_name() endif() print("The Medical Imaging Interaction Toolkit (MITK)") set(indent " ") message("${indent}Site: ${CTEST_SITE}") message("${indent}Dashboard model: ${CTEST_DASHBOARD_MODEL}") if(MITK_EXTENSIONS) unset(extensions) foreach(extension ${MITK_EXTENSIONS}) if(extensions) set(extensions "${extensions}, ") endif() parse_mitk_extension(${extension} SOURCE_DIR extension_dir) set(extensions "${extensions}${extension_dir}") endforeach() message("${indent}Extensions: ${extensions}") endif() print("MITK repository") if(NOT EXISTS "${CTEST_SOURCE_DIRECTORY}") message("${indent}Clone repository: ${MITK_REPOSITORY}") message("${indent}Git branch/tag/commit: ${MITK_TAG}") ctest_start(${CTEST_DASHBOARD_MODEL}) else() unset(CTEST_CHECKOUT_COMMAND) # Do not clone if source directory already exists message("${indent}Update repository: ${CTEST_SOURCE_DIRECTORY}") message("${indent}Git branch/tag/commit: ${MITK_TAG}") - execute_process(COMMAND "${CTEST_GIT_COMMAND}" rev-parse --short=7 HEAD - WORKING_DIRECTORY "${CTEST_SOURCE_DIRECTORY}" - OUTPUT_VARIABLE old_revision - OUTPUT_STRIP_TRAILING_WHITESPACE) - message("${indent}Old revision: ${old_revision}") + git_log(COMMIT_HASH old_revision COMMITTER committer SUBJECT subject WORKING_DIRECTORY "${CTEST_SOURCE_DIRECTORY}") + message("${indent}Old revision: ${old_revision} (committed by ${committer})\n${indent}${indent}${subject}") ctest_start(${CTEST_DASHBOARD_MODEL}) - execute_process(COMMAND "${CTEST_GIT_COMMAND}" rev-parse --short=7 HEAD - WORKING_DIRECTORY "${CTEST_SOURCE_DIRECTORY}" - OUTPUT_VARIABLE new_revision - OUTPUT_STRIP_TRAILING_WHITESPACE) - message("${indent}New revision: ${new_revision}") + git_log(COMMIT_HASH new_revision WORKING_DIRECTORY "${CTEST_SOURCE_DIRECTORY}") + if(new_revision STREQUAL old_revision) + message("${indent}New revision: up to date") + else() + git_log(COMMITTER committer SUBJECT subject WORKING_DIRECTORY "${CTEST_SOURCE_DIRECTORY}") + message("${indent}New revision: ${new_revision} (committed by ${committer})\n${indent}${indent}${subject}") + endif() ctest_update(RETURN_VALUE num_files_updated) if(num_files_updated EQUAL -1) return() # Nothing to submit, error message already printed endif() endif() unset(MITK_EXTENSION_DIRS) set(up_to_date TRUE) foreach(extension ${MITK_EXTENSIONS}) parse_mitk_extension(${extension} SOURCE_DIR extension_dir GIT_REPOSITORY extension_repo GIT_TAG extension_tag) print("${extension_dir} repository") set(absolute_extension_dir "${CMAKE_CURRENT_LIST_DIR}/src/${extension_dir}") list(APPEND MITK_EXTENSION_DIRS "${absolute_extension_dir}") if(EXISTS "${absolute_extension_dir}") - execute_process(COMMAND "${CTEST_GIT_COMMAND}" rev-parse --short=7 HEAD - WORKING_DIRECTORY "${absolute_extension_dir}" - OUTPUT_VARIABLE old_revision - OUTPUT_STRIP_TRAILING_WHITESPACE) - + git_log(COMMIT_HASH old_revision COMMITTER committer SUBJECT subject WORKING_DIRECTORY "${absolute_extension_dir}") message("${indent}Update repository: ${absolute_extension_dir}") message("${indent}Git branch/tag/commit: ${extension_tag}") - message("${indent}Old revision: ${old_revision}") + message("${indent}Old revision: ${old_revision} (committed by ${committer})\n${indent}${indent}${subject}") - execute_process(COMMAND "${CTEST_GIT_COMMAND}" fetch ${update_options} ${extension_tag} - WORKING_DIRECTORY "${absolute_extension_dir}") - - execute_process(COMMAND "${CTEST_GIT_COMMAND}" diff --quiet HEAD FETCH_HEAD - WORKING_DIRECTORY "${absolute_extension_dir}" - RESULT_VARIABLE exit_code) + git(fetch ${update_options} ${extension_tag} WORKING_DIRECTORY "${absolute_extension_dir}") + git(diff --quiet HEAD FETCH_HEAD WORKING_DIRECTORY "${absolute_extension_dir}" EXIT_CODE exit_code) if(NOT exit_code EQUAL 0) - execute_process(COMMAND "${CTEST_GIT_COMMAND}" reset --hard FETCH_HEAD - WORKING_DIRECTORY "${absolute_extension_dir}") - + git(reset --hard FETCH_HEAD WORKING_DIRECTORY "${absolute_extension_dir}") set(up_to_date FALSE) endif() - execute_process(COMMAND "${CTEST_GIT_COMMAND}" rev-parse --short=7 HEAD - WORKING_DIRECTORY "${absolute_extension_dir}" - OUTPUT_VARIABLE new_revision - OUTPUT_STRIP_TRAILING_WHITESPACE) - - message("${indent}New revision: ${new_revision}") + git_log(COMMIT_HASH new_revision WORKING_DIRECTORY "${absolute_extension_dir}") + if(new_revision STREQUAL old_revision) + message("${indent}New revision: up to date") + else() + git_log(COMMITTER committer SUBJECT subject WORKING_DIRECTORY "${absolute_extension_dir}") + message("${indent}New revision: ${new_revision} (committed by ${committer})\n${indent}${indent}${subject}") + endif() else() message("${indent}Clone repository: ${extension_repo}") message("${indent}Git branch/tag/commit: ${extension_tag}") - execute_process(COMMAND ${checkout_command} --branch ${extension_tag} ${extension_repo} "src/${extension_dir}" + git(${checkout_command} --branch ${extension_tag} ${extension_repo} "src/${extension_dir}" WORKING_DIRECTORY "${CMAKE_CURRENT_LIST_DIR}") set(up_to_date FALSE) endif() endforeach() # ctest_submit(PARTS Update) set(cmake_options -D SUPERBUILD_EXCLUDE_MITKBUILD_TARGET:BOOL=TRUE -D MITK_CTEST_SCRIPT_MODE:STRING=${CTEST_DASHBOARD_MODEL} -D MITK_BUILD_CONFIGURATION:STRING=${MITK_BUILD_CONFIGURATION} ) if(MITK_EXTENSION_DIRS) string (REPLACE ";" "\\\;" MITK_EXTENSION_DIRS "${MITK_EXTENSION_DIRS}") list(APPEND cmake_options -D MITK_EXTENSION_DIRS:STRING=${MITK_EXTENSION_DIRS}) endif() print("MITK SuperBuild - ${MITK_BUILD_CONFIGURATION} configuration") ctest_configure( OPTIONS "${cmake_options}" RETURN_VALUE config_return_value) # ctest_submit(PARTS Configure) if(NOT config_return_value EQUAL 0) # ctest_submit(PARTS Done) return() endif() include("${CTEST_BINARY_DIRECTORY}/SuperBuildTargets.cmake") if(SUPERBUILD_TARGETS) list(LENGTH SUPERBUILD_TARGETS n) set(i 1) set(build_options "") foreach(target ${SUPERBUILD_TARGETS}) print("MITK SuperBuild - [${i}/${n}] Build ${target}") ctest_build(TARGET ${target} NUMBER_ERRORS num_build_errors NUMBER_WARNINGS num_build_warnings RETURN_VALUE build_return_value ${build_options}) # ctest_submit(PARTS Build) if(num_build_warnings GREATER 0) print("${indent}${num_build_warnings} warning(s)") endif() if(NOT (build_return_value EQUAL 0 AND num_build_errors EQUAL 0)) # ctest_submit(PARTS Done) print("${indent}${num_build_errors} error(s)") return() else() print("${indent}${target} was built successfully") endif() if(NOT build_options) set(build_options APPEND) endif() math(EXPR i "${i} + 1") endforeach() else() # ctest_submit(PARTS Done) message(FATAL_ERROR "SUPERBUILD_TARGETS variable not set in SuperBuildTargets.cmake") endif() # ctest_submit(PARTS Done) return() #[[ ctest_build(TARGET MITK-Data NUMBER_ERRORS NUMBER_OF_BUILD_ERRORS RETURN_VALUE BUILD_RETURN_VALUE) ctest_submit(PARTS Build) if(BUILD_RETURN_VALUE EQUAL 0 AND NUMBER_OF_BUILD_ERRORS EQUAL 0) ctest_build(TARGET MITK-Configure APPEND NUMBER_ERRORS NUMBER_OF_BUILD_ERRORS RETURN_VALUE BUILD_RETURN_VALUE) ctest_submit(PARTS Build) if(BUILD_RETURN_VALUE EQUAL 0 AND NUMBER_OF_BUILD_ERRORS EQUAL 0) ctest_build(BUILD "${CTEST_BINARY_DIRECTORY}/MITK-build" APPEND NUMBER_ERRORS NUMBER_OF_BUILD_ERRORS RETURN_VALUE BUILD_RETURN_VALUE) ctest_submit(PARTS Build) if(BUILD_RETURN_VALUE EQUAL 0 AND NUMBER_OF_BUILD_ERRORS EQUAL 0) ctest_test(BUILD "${CTEST_BINARY_DIRECTORY}/MITK-build" EXCLUDE "(ProjectTemplate|Package)") ctest_submit(PARTS Test Done) else() ctest_submit(PARTS Done) # Error in Build Step (MITK) endif() else() ctest_submit(PARTS Done) # Error in Build step (Superbuild) endif() else() ctest_submit(PARTS Done) # Error in MITK-Data build step (Superbuild) endif() else() ctest_submit(PARTS Done) # Error in Configure step (Superbuild) endif() endif() ]]