# CTest instructions to make a continuous build on a computer (Linux / Windows / MacOSX)
# Schedule a task running this script with ctest and launch it using the following command:
# "ctest -DCAMITK_CONTINUOUS_INTEGRATION -DCTEST_BINARY_DIRECTORY -S continuous.cmake -V"
# CAMITK_CONTINUOUS_INTEGRATION = COMPILER-ARCH-BUILDTYPE is the build name, providing build options
# CTEST_BINARY_DIRECTORY = path to the build directory where to compile the generated code of this test.

# What this script does ?
# * INFORMATION STEP
#       Configure SITE and BUILD information to be correctly display on dashboard
#       Loads information from the CTestConfig.cmake file.
# * UPDATE STEP
#       use GIT to udpdate source code to the latest revision.
# * CONFIGURE STEP
#       configure the whole CamiTK project.
# * BUILD STEP 
#       build updated subprojects of CamiTK.
# NOTE : Reports are send tagged for each subproject
# For each step a report is sent to the dashboard. This allows any developer to be informed (mailing list) of any problem, even BEFORE the script ends !

# Need to be defined, for the build to run.
if(NOT DEFINED CTEST_SOURCE_DIRECTORY)
    message(FATAL_ERROR "No source directory: please provide the path to the source directory with the CTEST_SOURCE_DIRECTORY argument")
endif()
if(NOT DEFINED CTEST_BINARY_DIRECTORY)
    message(FATAL_ERROR "No build directory: please provide the path to the build directory with the CTEST_BINARY_DIRECTORY argument")
endif()

# Script configuration, depending of the build, computer running the script
# Update to feat each computer which runs this script

# Get VM compilation information given by ctest call command
if(CAMITK_CONTINUOUS_INTEGRATION)
    string(REGEX REPLACE "^(.*)-.*-.*" "\\1" COMPILER "${CAMITK_CONTINUOUS_INTEGRATION}")
    string(REGEX REPLACE "^.*-(.*)-.*" "\\1" ARCH "${CAMITK_CONTINUOUS_INTEGRATION}")
    string(REGEX REPLACE "^.*-.*-(.*)" "\\1" BUILDTYPE "${CAMITK_CONTINUOUS_INTEGRATION}")
else()
    message(FATAL_ERROR "No CAMITK_CONTINUOUS_INTEGRATION argument: please provide a continuous integration setting with the CAMITK_CONTINUOUS_INTEGRATION argument. It should be equals to COMPILER-ARCH-BUILDTYPE.")
endif()

# Compose with those variables the CTest required ones.
site_name(CTEST_SITE)

if(UNIX)
    set(CTEST_CMAKE_GENERATOR  "Unix Makefiles" )
elseif(WIN32)
    if(COMPILER MATCHES "MinGW" OR "MINGW")
        set(CTEST_CMAKE_GENERATOR  "MinGW Makefiles" )
    elseif(COMPILER MATCHES "MSVC2019") # only 64 bit supports
        set(CTEST_CMAKE_GENERATOR "Visual Studio 16 2019")
    elseif(COMPILER MATCHES "MSVC2022") # only 64 bit supports
        set(CTEST_CMAKE_GENERATOR "Visual Studio 17 2022")
    elseif(COMPILER MATCHES "Ninja")
        set(CTEST_CMAKE_GENERATOR "Ninja")
    else()
        message(FATAL_ERROR "CTEST COMPILER ERROR : No proper or supported compiler found, please check ctest command syntax or update this script.")
    endif()
endif()

if(BUILDTYPE)
    set(CTEST_BUILD_CONFIGURATION ${BUILDTYPE})
    set(CTEST_CONFIGURATION_TYPE ${BUILDTYPE})
else()
    message(FATAL_ERROR "No build type: please provide a valid build type: Debug or Release.")
endif()

# get the git hash
find_package(Git QUIET)
if(GIT_FOUND)
    include("${CTEST_SOURCE_DIRECTORY}/sdk/cmake/modules/macros/GetGitInfo.cmake")
else()
    message(FATAL_ERROR "Git command not found: please install git.")
endif()

set(CTEST_GIT_COMMAND ${GIT_EXECUTABLE})
set(CTEST_UPDATE_COMMAND ${GIT_EXECUTABLE})

# Coverage depends on gcov/lcov and bash, only available on Linux
IF (WIN32)
    set(COVERAGE_OPTION "FALSE")
ELSE()
    set(COVERAGE_OPTION "TRUE")
ENDIF()

# CMake configuration (put here all the configure flags)
set(CTEST_CONFIGURE_COMMAND "${CMAKE_COMMAND} -Wno-dev -G \"${CTEST_CMAKE_GENERATOR}\"")
set(CTEST_CONFIGURE_COMMAND "${CTEST_CONFIGURE_COMMAND} -DCMAKE_BUILD_TYPE:STRING=${CTEST_BUILD_CONFIGURATION} -DCTEST_USE_LAUNCHERS=1")
if(COMPILER MATCHES "MSVC2010" AND ARCH MATCHES "64bits") # Do not compile MML and PhysicalModel until libxml2 MSVC2010 x64 bug remains.
    set(CTEST_CONFIGURE_COMMAND "${CTEST_CONFIGURE_COMMAND} -DACTION_MML=FALSE -DCOMPONENT_MML=FALSE -DCOMPONENT_PHYSICALMODEL=FALSE")
endif()

set(CTEST_TEST_TIMEOUT 1500)
set(CTEST_CONFIGURE_COMMAND "${CTEST_CONFIGURE_COMMAND} -DCEP_IMAGING=TRUE -DCEP_MODELING=TRUE -DCEP_TUTORIALS=TRUE -DCAMITK_TEST_COVERAGE=${COVERAGE_OPTION} ${CTEST_SOURCE_DIRECTORY}")

# to get CDash server configuration :
include("${CTEST_SOURCE_DIRECTORY}/CTestConfig.cmake")

# Continuous build parameters
# Update them regarding your project's compilation time
set(CONTINUOUS_BUILD_DURATION 43200) # Duration time of the main loop of the continuous build in seconds, here 12 hours.
set(CONTINUOUS_BUILD_SLEEP 600) # Step to perform each build <=> maximum time for the script to sleep between 2 builds (10 minutes for now).

#Empty local installation directory
if(WIN32)
    # %APPDATA%\MySoft\Star Runner.ini
    set(CAMITK_USER_BASE_DIR_WINDOWS $ENV{APPDATA})
    file(TO_CMAKE_PATH "${CAMITK_USER_BASE_DIR_WINDOWS}" CAMITK_USER_BASE_DIR)
else()
    # (UNIX OR APPLE)
    # $HOME/.config/MySoft/Star Runner.ini 
    set(CAMITK_USER_BASE_DIR "$ENV{HOME}/.config")
endif()
set(CAMITK_USER_DIR "${CAMITK_USER_BASE_DIR}/CamiTK")
file(REMOVE_RECURSE ${CAMITK_USER_DIR})


# Clean binary directory each beginning of the day
ctest_empty_binary_directory(${CTEST_BINARY_DIRECTORY})

# Main loop
# During 10 hours from starting this script, CTest will continuously build every 10 min.
while (${CTEST_ELAPSED_TIME} LESS ${CONTINUOUS_BUILD_DURATION})
        # Get start time of the build
        set(START_TIME ${CTEST_ELAPSED_TIME})
        
        # set the build name using the compiler and commit hash of the origin/develop branch
        # CTEST_BUILD_NAME needs to be set before ctest_start, which in turns is called before ctest_update
        # therefore the current git hash should be fetch fro origin/develop
        get_git_info(${CTEST_SOURCE_DIRECTORY})
        set(CTEST_BUILD_NAME ${CAMITK_CONTINUOUS_INTEGRATION}-${CAMITK_ORIGIN_DEVELOP_GIT_ABBREVIATED_HASH})
        
        # Start CTest in Continuous mode
        ctest_start(Continuous)
        
        # Update source code and get update command result
        ctest_update(SOURCE ${CTEST_SOURCE_DIRECTORY} RETURN_VALUE count)
        
        if (count GREATER 0) # We have updated source code, thus configure and build modified files

            # show update reports if there is a change in the source code
            ctest_submit(PARTS Update Notes)
            
            # Configure the whole camitk project and send configure report on the server 
            ctest_configure()
            ctest_submit(PARTS Configure)
            
            # Get subprojects listing (automatically created at configuration step)
            include("${CTEST_BINARY_DIRECTORY}/Subprojects.cmake")
            
            # Update CDash configuration to the server
            # Project.xml file is automatically generated. If someone added an extension to CamiTK, CDash will automatically be updated according to it.
            # To do this, send this file to the server
            ctest_submit(FILES "${CTEST_BINARY_DIRECTORY}/Project.xml") 
            
            # Build each subprojects
            foreach(subproject ${CAMITK_TARGETS})

                    # tag sub project, tag are used to sort projects according to tests
                    set_property(GLOBAL PROPERTY SubProject ${subproject})
                    set_property(GLOBAL PROPERTY Label ${subproject})

                    # build each sub project
                    set(CTEST_BUILD_TARGET ${subproject})
                    ctest_build()
                    ctest_submit(PARTS Build)
            endforeach()

            # now that everything is build, run all the tests
            foreach(subproject ${CAMITK_TARGETS})
                    # Run tests
                    ctest_test(BUILD "${CTEST_BINARY_DIRECTORY}" INCLUDE_LABEL "${subproject}")
                    ctest_submit(PARTS Test)
            endforeach(subproject)
            
            
            # Compute test coverage
            message(STATUS "- Running test coverage...")
            set(CTEST_BUILD_TARGET camitk-ce-test-coverage)
            ctest_build()

            if(NOT DEFINED CTEST_COVERAGE_COMMAND)
                find_program(CTEST_COVERAGE_COMMAND NAMES gcov)
                if(CTEST_COVERAGE_COMMAND)
                    message(STATUS "- ctest configured with gcov: ${CTEST_COVERAGE_COMMAND}")
                else()
                    message(STATUS "- ctest not configured with gcov (gcov binary not found)")
                endif()
            endif()

            ctest_coverage()
            ctest_submit(PARTS Coverage)
                    
            # Install locally this build version of CamiTK
            set(CTEST_BUILD_TARGET camitk-ce-local-install)
            ctest_build()
            ctest_submit(PARTS Install)
            
            # Empty local installation directory
            file(REMOVE_RECURSE ${CAMITK_USER_DIR})            
        endif ()

        message(STATUS "Waiting for GIT change")
        
        # Wait maximum the CONTINUOUS_BUILD_SLEEP time (in seconds) to loop again and launch next build
        ctest_sleep(${START_TIME} ${CONTINUOUS_BUILD_SLEEP} ${CTEST_ELAPSED_TIME})
endwhile()
