diff --git a/modules/ECMSourceVersionControl.cmake b/modules/ECMSourceVersionControl.cmake --- a/modules/ECMSourceVersionControl.cmake +++ b/modules/ECMSourceVersionControl.cmake @@ -2,16 +2,61 @@ # ECMSourceVersionControl # -------------------------- # -# Tries to determine whether the source is under version control (git clone, -# svn checkout, etc). +# This module allows to determine if and through which of the known version +# control systems the source directory is controlled: +# +# * ``ECM_SOURCE_UNDER_VERSION_CONTROL`` is set to ``TRUE`` when indication +# is found that ``CMAKE_SOURCE_DIR`` is under version control, else set to +# ``FALSE``. +# * ``ECM_SOURCE_VERSION_CONTROL_WHICH`` will be set to any of the following +# strings in case ``ECM_SOURCE_UNDER_VERSION_CONTROL`` is ``TRUE``: +# ``git`` in case the source directory is controlled by Git (i.e. it is a +# Git clone), ``svn`` for Subversion, ``hg`` for Mercurial, and ``bzr`` for +# Bazaar. +# +# Above variables will be automatically set once this module is loaded. +# Determining the variables' values is considered a cheap operation as it only +# requires probing the filesystem for the existance of certain directories. +# +# In case Git is used for version control, additional functions are available +# to retrieve more detailed information about the local checkout's state. +# However, as those functions will invoke the ``git`` binary internally which +# then may perform complex operations, those function invocations are to be +# considered 'expensive'. +# +# The following function will invoke Git to retrieve the current revision as +# represented by the first eight hexdecimal characters of the current commit's +# SHA1 identifier. The revision will be stored in . +# +# :: +# +# ecm_source_version_control_probe_revision() +# +# Similar to above function, the following function will invoke Git to retrieve +# the current branch's name (for example, 'master'). The branch's name will be +# stored in . +# +# :: +# +# ecm_source_version_control_probe_branch() +# +# Only if there is an issue, such as being invoked on a source directory that is +# not managed with Git, above functions will print messages (warnings). +# To get a 'friendly' output during the configuration phase and only if the +# source code is actually version controlled via Git, the following function +# will issue an informative message about the Git checkout's revision and +# branch. Internally, it makes use of both functions discussed above. +# +# :: +# +# ecm_source_version_control_status() # -# ``ECM_SOURCE_UNDER_VERSION_CONTROL`` is set when indication is found that -# CMAKE_SOURCE_DIR is under version control. # # Since 5.63 #============================================================================= # Copyright 2019 Harald Sitter +# Copyright 2019 Thomas Fischer # # Redistribution and use in source and binary forms, with or without # modification, are permitted provided that the following conditions @@ -36,11 +81,85 @@ # (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF # THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. -if(EXISTS "${CMAKE_SOURCE_DIR}/.git" OR - EXISTS "${CMAKE_SOURCE_DIR}/.svn" OR - EXISTS "${CMAKE_SOURCE_DIR}/.hg" OR - EXISTS "${CMAKE_SOURCE_DIR}/.bzr") +if(EXISTS "${CMAKE_SOURCE_DIR}/.git") + # Git + set(ECM_SOURCE_UNDER_VERSION_CONTROL TRUE) + set(ECM_SOURCE_VERSION_CONTROL_WHICH "git") +elseif(EXISTS "${CMAKE_SOURCE_DIR}/.svn") + # Subversion + set(ECM_SOURCE_UNDER_VERSION_CONTROL TRUE) + set(ECM_SOURCE_VERSION_CONTROL_WHICH "svn") +elseif(EXISTS "${CMAKE_SOURCE_DIR}/.hg") + # Mercurial + set(ECM_SOURCE_UNDER_VERSION_CONTROL TRUE) + set(ECM_SOURCE_VERSION_CONTROL_WHICH "hg") +elseif(EXISTS "${CMAKE_SOURCE_DIR}/.bzr") + # Bazaar set(ECM_SOURCE_UNDER_VERSION_CONTROL TRUE) + set(ECM_SOURCE_VERSION_CONTROL_WHICH "bzr") else() + unset(ECM_SOURCE_VERSION_CONTROL_WHICH) set(ECM_SOURCE_UNDER_VERSION_CONTROL FALSE) endif() + +function(_ecm_source_version_control_detect_git) + if(NOT _ECM_SOURCE_VERSION_GIT_EXECUTABLE) + find_program(_ECM_SOURCE_VERSION_GIT_EXECUTABLE + NAMES git.bat git # for Windows, 'git.bat' must be found before 'git' + ) + endif() + if(NOT _ECM_SOURCE_VERSION_GIT_EXECUTABLE) + message(WARNING "No Git executable found despite .git directory located in source directory") + endif() +endfunction() + +function(ecm_source_version_control_probe_revision outvar) + if(NOT ${ECM_SOURCE_UNDER_VERSION_CONTROL}) + message("Source directory not managed by a known version control system") + elseif(${ECM_SOURCE_VERSION_CONTROL_WHICH} STREQUAL "git") + # Git + _ecm_source_version_control_detect_git() + if(_ECM_SOURCE_VERSION_GIT_EXECUTABLE) + execute_process( + WORKING_DIRECTORY "${CMAKE_SOURCE_DIR}" + COMMAND "${_ECM_SOURCE_VERSION_GIT_EXECUTABLE}" rev-parse --short HEAD + OUTPUT_VARIABLE ECM_SOURCE_VERSION_CONTROL_REVISION + OUTPUT_STRIP_TRAILING_WHITESPACE + ) + set(${outvar} ${ECM_SOURCE_VERSION_CONTROL_REVISION} PARENT_SCOPE) + endif() + else() + message(WARNING "Source directory not managed by a supported version control system (Git)") + endif() +endfunction() + +function(ecm_source_version_control_probe_branch outvar) + if(NOT ${ECM_SOURCE_UNDER_VERSION_CONTROL}) + message("Source directory not managed by a known version control system") + elseif(${ECM_SOURCE_VERSION_CONTROL_WHICH} STREQUAL "git") + # Git + _ecm_source_version_control_detect_git() + if(_ECM_SOURCE_VERSION_GIT_EXECUTABLE) + execute_process( + WORKING_DIRECTORY "${CMAKE_SOURCE_DIR}" + COMMAND "${_ECM_SOURCE_VERSION_GIT_EXECUTABLE}" rev-parse --abbrev-ref HEAD + OUTPUT_VARIABLE ECM_SOURCE_VERSION_CONTROL_BRANCH + OUTPUT_STRIP_TRAILING_WHITESPACE + ) + set(${outvar} ${ECM_SOURCE_VERSION_CONTROL_BRANCH} PARENT_SCOPE) + endif() + else() + message(WARNING "Source directory not managed by a supported version control system (Git)") + endif() +endfunction() + +function(ecm_source_version_control_status) + if(${ECM_SOURCE_UNDER_VERSION_CONTROL} AND "${ECM_SOURCE_VERSION_CONTROL_WHICH}" STREQUAL "git") + message(STATUS "Source directory '${CMAKE_SOURCE_DIR}' is under version control by Git.") + ecm_source_version_control_probe_revision(ECM_SOURCE_VERSION_CONTROL_REVISION) + ecm_source_version_control_probe_branch(ECM_SOURCE_VERSION_CONTROL_BRANCH) + if(ECM_SOURCE_VERSION_CONTROL_REVISION AND ECM_SOURCE_VERSION_CONTROL_BRANCH) + message(STATUS "The current Git checkout is branch '${ECM_SOURCE_VERSION_CONTROL_BRANCH}' at commit ${ECM_SOURCE_VERSION_CONTROL_REVISION}.") + endif() + endif() +endfunction()