diff --git a/CMake/Modules/GetGitRevisionDescription.cmake b/CMake/Modules/GetGitRevisionDescription.cmake new file mode 100644 index 000000000..7d75ff0b2 --- /dev/null +++ b/CMake/Modules/GetGitRevisionDescription.cmake @@ -0,0 +1,168 @@ +# - Returns a version string from Git +# +# These functions force a re-configure on each git commit so that you can +# trust the values of the variables in your build system. +# +# get_git_head_revision( [ ...]) +# +# Returns the refspec and sha hash of the current head revision +# +# git_describe( [ ...]) +# +# Returns the results of git describe on the source tree, and adjusting +# the output so that it tests false if an error occurs. +# +# git_get_exact_tag( [ ...]) +# +# Returns the results of git describe --exact-match on the source tree, +# and adjusting the output so that it tests false if there was no exact +# matching tag. +# +# git_local_changes( ) +# +# Returns either "CLEAN" or "DIRTY" with respect to uncommitted changes. +# Uses the return code of "git diff-index --quiet HEAD --". +# Does not regard untracked files. +# +# Requires CMake 2.6 or newer (uses the 'function' command) +# +# Original Author: +# 2009-2010 Ryan Pavlik +# http://academic.cleardefinition.com +# Iowa State University HCI Graduate Program/VRAC +# +# Copyright Iowa State University 2009-2010. +# Distributed under the Boost Software License, Version 1.0. +# (See accompanying file LICENSE_1_0.txt or copy at +# http://www.boost.org/LICENSE_1_0.txt) + +if(__get_git_revision_description) + return() +endif() +set(__get_git_revision_description YES) + +# We must run the following at "include" time, not at function call time, +# to find the path to this module rather than the path to a calling list file +get_filename_component(_gitdescmoddir ${CMAKE_CURRENT_LIST_FILE} PATH) + +function(get_git_head_revision _source_dir _refspecvar _hashvar) + set(GIT_PARENT_DIR "${_source_dir}") + set(GIT_DIR "${GIT_PARENT_DIR}/.git") + while(NOT EXISTS "${GIT_DIR}") # .git dir not found, search parent directories + set(GIT_PREVIOUS_PARENT "${GIT_PARENT_DIR}") + get_filename_component(GIT_PARENT_DIR ${GIT_PARENT_DIR} PATH) + if(GIT_PARENT_DIR STREQUAL GIT_PREVIOUS_PARENT) + # We have reached the root directory, we are not in git + set(${_refspecvar} "GITDIR-NOTFOUND" PARENT_SCOPE) + set(${_hashvar} "GITDIR-NOTFOUND" PARENT_SCOPE) + return() + endif() + set(GIT_DIR "${GIT_PARENT_DIR}/.git") + endwhile() + # check if this is a submodule + if(NOT IS_DIRECTORY ${GIT_DIR}) + file(READ ${GIT_DIR} submodule) + string(REGEX REPLACE "gitdir: (.*)\n$" "\\1" GIT_DIR_RELATIVE ${submodule}) + get_filename_component(SUBMODULE_DIR ${GIT_DIR} PATH) + get_filename_component(GIT_DIR ${SUBMODULE_DIR}/${GIT_DIR_RELATIVE} ABSOLUTE) + endif() + set(GIT_DATA "${CMAKE_CURRENT_BINARY_DIR}/CMakeFiles/git-data") + if(NOT EXISTS "${GIT_DATA}") + file(MAKE_DIRECTORY "${GIT_DATA}") + endif() + + if(NOT EXISTS "${GIT_DIR}/HEAD") + return() + endif() + set(HEAD_FILE "${GIT_DATA}/HEAD") + configure_file("${GIT_DIR}/HEAD" "${HEAD_FILE}" COPYONLY) + + configure_file("${_gitdescmoddir}/GetGitRevisionDescription.cmake.in" + "${GIT_DATA}/grabRef.cmake" + @ONLY) + include("${GIT_DATA}/grabRef.cmake") + + set(${_refspecvar} "${HEAD_REF}" PARENT_SCOPE) + set(${_hashvar} "${HEAD_HASH}" PARENT_SCOPE) +endfunction() + +function(git_describe _source_dir _var) + if(NOT GIT_FOUND) + find_package(Git QUIET) + endif() + get_git_head_revision(${_source_dir} refspec hash) + if(NOT GIT_FOUND) + set(${_var} "GIT-NOTFOUND" PARENT_SCOPE) + return() + endif() + if(NOT hash) + set(${_var} "HEAD-HASH-NOTFOUND" PARENT_SCOPE) + return() + endif() + + # TODO sanitize + #if((${ARGN}" MATCHES "&&") OR + # (ARGN MATCHES "||") OR + # (ARGN MATCHES "\\;")) + # message("Please report the following error to the project!") + # message(FATAL_ERROR "Looks like someone's doing something nefarious with git_describe! Passed arguments ${ARGN}") + #endif() + + #message(STATUS "Arguments to execute_process: ${ARGN}") + + execute_process(COMMAND + "${GIT_EXECUTABLE}" + describe + ${hash} + ${ARGN} + WORKING_DIRECTORY + "${_source_dir}" + RESULT_VARIABLE + res + OUTPUT_VARIABLE + out + ERROR_QUIET + OUTPUT_STRIP_TRAILING_WHITESPACE) + if(NOT res EQUAL 0) + set(out "${out}-${res}-NOTFOUND") + endif() + + set(${_var} "${out}" PARENT_SCOPE) +endfunction() + +function(git_get_exact_tag _source_dir _var) + git_describe(${_source_dir} out --exact-match ${ARGN}) + set(${_var} "${out}" PARENT_SCOPE) +endfunction() + +function(git_local_changes _source_dir _var) + if(NOT GIT_FOUND) + find_package(Git QUIET) + endif() + get_git_head_revision(${_source_dir} refspec hash) + if(NOT GIT_FOUND) + set(${_var} "GIT-NOTFOUND" PARENT_SCOPE) + return() + endif() + if(NOT hash) + set(${_var} "HEAD-HASH-NOTFOUND" PARENT_SCOPE) + return() + endif() + + execute_process(COMMAND + "${GIT_EXECUTABLE}" + diff-index --quiet HEAD -- + WORKING_DIRECTORY + "${_source_dir}" + RESULT_VARIABLE + res + OUTPUT_VARIABLE + out + ERROR_QUIET + OUTPUT_STRIP_TRAILING_WHITESPACE) + if(res EQUAL 0) + set(${_var} "CLEAN" PARENT_SCOPE) + else() + set(${_var} "DIRTY" PARENT_SCOPE) + endif() +endfunction() diff --git a/CMake/Modules/GetGitRevisionDescription.cmake.in b/CMake/Modules/GetGitRevisionDescription.cmake.in new file mode 100644 index 000000000..6d8b708ef --- /dev/null +++ b/CMake/Modules/GetGitRevisionDescription.cmake.in @@ -0,0 +1,41 @@ +# +# Internal file for GetGitRevisionDescription.cmake +# +# Requires CMake 2.6 or newer (uses the 'function' command) +# +# Original Author: +# 2009-2010 Ryan Pavlik +# http://academic.cleardefinition.com +# Iowa State University HCI Graduate Program/VRAC +# +# Copyright Iowa State University 2009-2010. +# Distributed under the Boost Software License, Version 1.0. +# (See accompanying file LICENSE_1_0.txt or copy at +# http://www.boost.org/LICENSE_1_0.txt) + +set(HEAD_HASH) + +file(READ "@HEAD_FILE@" HEAD_CONTENTS LIMIT 1024) + +string(STRIP "${HEAD_CONTENTS}" HEAD_CONTENTS) +if(HEAD_CONTENTS MATCHES "ref") + # named branch + string(REPLACE "ref: " "" HEAD_REF "${HEAD_CONTENTS}") + if(EXISTS "@GIT_DIR@/${HEAD_REF}") + configure_file("@GIT_DIR@/${HEAD_REF}" "@GIT_DATA@/head-ref" COPYONLY) + else() + configure_file("@GIT_DIR@/packed-refs" "@GIT_DATA@/packed-refs" COPYONLY) + file(READ "@GIT_DATA@/packed-refs" PACKED_REFS) + if(${PACKED_REFS} MATCHES "([0-9a-z]*) ${HEAD_REF}") + set(HEAD_HASH "${CMAKE_MATCH_1}") + endif() + endif() +else() + # detached HEAD + configure_file("@GIT_DIR@/HEAD" "@GIT_DATA@/head-ref" COPYONLY) +endif() + +if(NOT HEAD_HASH) + file(READ "@GIT_DATA@/head-ref" HEAD_HASH LIMIT 1024) + string(STRIP "${HEAD_HASH}" HEAD_HASH) +endif() diff --git a/CMake/getsvn.cmake b/CMake/getsvn.cmake index 754963639..0af52fe28 100644 --- a/CMake/getsvn.cmake +++ b/CMake/getsvn.cmake @@ -1,5 +1,7 @@ -find_package (Subversion) -if (Subversion_FOUND AND EXISTS "${SOURCE_DIR}/.svn") +message (STATUS "Checking for revision information") +if (EXISTS "${SOURCE_DIR}/.svn") + message (STATUS "Checking for Subversion revision information") + find_package (Subversion QUIET REQUIRED) # the FindSubversion.cmake module is part of the standard distribution include (FindSubversion) # extract working copy information for SOURCE_DIR into MY_XXX variables @@ -7,9 +9,9 @@ if (Subversion_FOUND AND EXISTS "${SOURCE_DIR}/.svn") message ("${MY_WC_INFO}") # determine if the working copy has outstanding changes execute_process (COMMAND ${Subversion_SVN_EXECUTABLE} status ${SOURCE_DIR} - OUTPUT_FILE "${OUTPUT_DIR}/svn_status.txt" + OUTPUT_FILE "${BINARY_DIR}/svn_status.txt" OUTPUT_STRIP_TRAILING_WHITESPACE) - file (STRINGS "${OUTPUT_DIR}/svn_status.txt" __svn_changes + file (STRINGS "${BINARY_DIR}/svn_status.txt" __svn_changes REGEX "^[^?].*$" ) if (__svn_changes) @@ -20,11 +22,11 @@ if (Subversion_FOUND AND EXISTS "${SOURCE_DIR}/.svn") endforeach (__svn_change ${__svn_changes}) endif (__svn_changes) message (STATUS "${SOURCE_DIR} contains a .svn and is revision ${MY_WC_LAST_CHANGED_REV}") - # write a file with the SVNVERSION define - file (WRITE "${OUTPUT_DIR}/svnversion.h.txt" "#define SVNVERSION ${MY_WC_LAST_CHANGED_REV}\n") -else (Subversion_FOUND AND EXISTS "${SOURCE_DIR}/.svn") - # try git-svn - if (Subversion_FOUND AND EXISTS "${SOURCE_DIR}/.git") + # write a file with the SCS_VERSION define + file (WRITE "${BINARY_DIR}/scs_version.h.txt" "#define SCS_VERSION r${MY_WC_LAST_CHANGED_REV}\n") +elseif (EXISTS "${SOURCE_DIR}/.git") + if (EXISTS "${SOURCE_DIR}/.git/svn/.metadata") # try git-svn + message (STATUS "Checking for Subversion revision information using git-svn") include (${SOURCE_DIR}/CMake/Modules/FindGitSubversion.cmake) # extract working copy information for SOURCE_DIR into MY_XXX variables GitSubversion_WC_INFO (${SOURCE_DIR} MY) @@ -32,10 +34,10 @@ else (Subversion_FOUND AND EXISTS "${SOURCE_DIR}/.svn") # try and determine if the working copy has outstanding changes execute_process (COMMAND ${GIT_EXECUTABLE} --git-dir=${SOURCE_DIR}/.git --work-tree=${SOURCE_DIR} svn dcommit --dry-run RESULT_VARIABLE __git_svn_status - OUTPUT_FILE "${OUTPUT_DIR}/svn_status.txt" + OUTPUT_FILE "${BINARY_DIR}/svn_status.txt" ERROR_QUIET OUTPUT_STRIP_TRAILING_WHITESPACE) - file (STRINGS "${OUTPUT_DIR}/svn_status.txt" __svn_changes + file (STRINGS "${BINARY_DIR}/svn_status.txt" __svn_changes REGEX "^diff-tree" ) if ((NOT ${__git_svn_status} EQUAL 0) OR __svn_changes) @@ -43,12 +45,31 @@ else (Subversion_FOUND AND EXISTS "${SOURCE_DIR}/.svn") set (MY_WC_LAST_CHANGED_REV "${MY_WC_LAST_CHANGED_REV}-dirty") endif () # write a file with the SVNVERSION define - file (WRITE "${OUTPUT_DIR}/svnversion.h.txt" "#define SVNVERSION r${MY_WC_LAST_CHANGED_REV}\n") - else (Subversion_FOUND AND EXISTS "${SOURCE_DIR}/.svn") - file (WRITE "${OUTPUT_DIR}/svnversion.h.txt" "#define SVNVERSION\n") - endif (Subversion_FOUND AND EXISTS "${SOURCE_DIR}/.git") -endif (Subversion_FOUND AND EXISTS "${SOURCE_DIR}/.svn") + file (WRITE "${BINARY_DIR}/scs_version.h.txt" "#define SCS_VERSION r${MY_WC_LAST_CHANGED_REV}\n") + else () + # + # try git + # + message (STATUS "Checking for gitrevision information") + include (${SOURCE_DIR}/CMake/Modules/GetGitRevisionDescription.cmake) + get_git_head_revision (${SOURCE_DIR} GIT_REFSPEC GIT_SHA1) + git_local_changes (${SOURCE_DIR} GIT_DIRTY) + string (SUBSTRING "${GIT_SHA1}" 0 6 GIT_SHA1) + if ("${GIT_DIRTY}" STREQUAL "DIRTY") + message (WARNING "Source tree based on revision ${GIT_REFSPEC} ${GIT_SHA1} appears to have local changes") + set (GIT_SHA1 "${GIT_SHA1}-dirty") + execute_process (COMMAND ${GIT_EXECUTABLE} --git-dir=${SOURCE_DIR}/.git --work-tree=${SOURCE_DIR} status + ERROR_QUIET + OUTPUT_STRIP_TRAILING_WHITESPACE) + endif () + message (STATUS "refspec: ${GIT_REFSPEC} - SHA1: ${GIT_SHA1}") + file (WRITE "${BINARY_DIR}/scs_version.h.txt" "#define SCS_VERSION ${GIT_SHA1}\n") + else() + message (STATUS "No SCS found") + file (WRITE "${BINARY_DIR}/scs_version.h.txt" "#define SCS_VERSION\n") + endif () +endif () # copy the file to the final header only if the version changes # reduces needless rebuilds -execute_process (COMMAND ${CMAKE_COMMAND} -E copy_if_different "${OUTPUT_DIR}/svnversion.h.txt" "${OUTPUT_DIR}/svnversion.h") +execute_process (COMMAND ${CMAKE_COMMAND} -E copy_if_different "${BINARY_DIR}/scs_version.h.txt" "${OUTPUT_DIR}/scs_version.h") diff --git a/CMakeLists.txt b/CMakeLists.txt index 03b5dca3a..6a7f0b58b 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -1488,9 +1488,13 @@ add_custom_target (uninstall "${CMAKE_COMMAND}" -P "${CMAKE_CURRENT_BINARY_DIR}/cmake_uninstall.cmake") -# creates svnversion.h using cmake script +# creates or updates ${PROJECT_BINARY_DIR}/scs_version.h using cmake script add_custom_target (revisiontag - COMMAND ${CMAKE_COMMAND} -D SOURCE_DIR=${CMAKE_CURRENT_SOURCE_DIR} -D OUTPUT_DIR=${PROJECT_BINARY_DIR} -P ${CMAKE_CURRENT_SOURCE_DIR}/CMake/getsvn.cmake + COMMAND ${CMAKE_COMMAND} + -D SOURCE_DIR=${CMAKE_CURRENT_SOURCE_DIR} + -D BINARY_DIR=${CMAKE_CURRENT_BINARY_DIR} + -D OUTPUT_DIR=${PROJECT_BINARY_DIR} + -P ${CMAKE_CURRENT_SOURCE_DIR}/CMake/getsvn.cmake COMMENT "Generating Subversion revision information" VERBATIM ) diff --git a/Versions.cmake b/Versions.cmake index 890d28652..a34c8d91d 100644 --- a/Versions.cmake +++ b/Versions.cmake @@ -1,6 +1,6 @@ # Version number components set (WSJTX_VERSION_MAJOR 1) -set (WSJTX_VERSION_MINOR 9) +set (WSJTX_VERSION_MINOR 10) set (WSJTX_VERSION_PATCH 0) -#set (WSJTX_RC 1) # release candidate number, comment out or zero for development versions -set (WSJTX_VERSION_IS_RELEASE 1) # set to 1 for final release build +set (WSJTX_RC 1) # release candidate number, comment out or zero for development versions +set (WSJTX_VERSION_IS_RELEASE 0) # set to 1 for final release build diff --git a/revision_utils.cpp b/revision_utils.cpp index 81b12a6ca..8842e3b4c 100644 --- a/revision_utils.cpp +++ b/revision_utils.cpp @@ -5,7 +5,7 @@ #include #include -#include "svnversion.h" +#include "scs_version.h" namespace { @@ -13,51 +13,51 @@ namespace { QString revision; - // try and match a number - QRegularExpression re {R"(^[$:]\w+: (\d+[^$]*)\$$)"}; + // try and match a number (hexadecimal allowed) + QRegularExpression re {R"(^[$:]\w+: (r?[\da-f]+[^$]*)\$$)"}; auto match = re.match (s); if (match.hasMatch ()) { - revision = 'r' + match.captured (1); + revision = match.captured (1); } return revision; } } -QString revision (QString const& svn_rev_string) +QString revision (QString const& scs_rev_string) { QString result; - auto revision_from_svn = revision_extract_number (svn_rev_string); + auto revision_from_scs = revision_extract_number (scs_rev_string); #if defined (CMAKE_BUILD) - QString svn_info {":Rev: " WSJTX_STRINGIZE (SVNVERSION) " $"}; + QString scs_info {":Rev: " WSJTX_STRINGIZE (SCS_VERSION) " $"}; - auto revision_from_svn_info = revision_extract_number (svn_info); - if (!revision_from_svn_info.isEmpty ()) + auto revision_from_scs_info = revision_extract_number (scs_info); + if (!revision_from_scs_info.isEmpty ()) { // we managed to get the revision number from svn info etc. - result = revision_from_svn_info; + result = revision_from_scs_info; } - else if (!revision_from_svn.isEmpty ()) + else if (!revision_from_scs.isEmpty ()) { // fall back to revision passed in if any - result = revision_from_svn; + result = revision_from_scs; } else { // match anything QRegularExpression re {R"(^[$:]\w+: ([^$]*)\$$)"}; - auto match = re.match (svn_info); + auto match = re.match (scs_info); if (match.hasMatch ()) { result = match.captured (1); } } #else - if (!revision_from_svn.isEmpty ()) + if (!revision_from_scs.isEmpty ()) { // not CMake build so all we have is revision passed - result = revision_from_svn; + result = revision_from_scs; } #endif return result.trimmed ();