diff --git a/cmake/VersionScript.cmake b/cmake/VersionScript.cmake index 929bbbe..7cde15d 100644 --- a/cmake/VersionScript.cmake +++ b/cmake/VersionScript.cmake @@ -1,5 +1,5 @@ -# Copyright (C) 2011-2016 Daniel Scharrer +# Copyright (C) 2011-2020 Daniel Scharrer # # This software is provided 'as-is', without any express or implied # warranty. In no event will the author(s) be held liable for any damages @@ -26,102 +26,29 @@ if((NOT DEFINED INPUT) OR (NOT DEFINED OUTPUT) OR (NOT DEFINED VERSION_SOURCES) message(SEND_ERROR "Invalid arguments.") endif() +include("${CMAKE_CURRENT_LIST_DIR}/VersionString.cmake") + # configure_file doesn't handle newlines correctly - pre-escape variables -function(escape_var VAR) +macro(_version_escape var string) # Escape the escape character and quotes - string(REGEX REPLACE "([\\\\\"])" "\\\\\\1" escaped "${${VAR}}") + string(REGEX REPLACE "([\\\\\"])" "\\\\\\1" ${var} "${string}") # Pull newlines out of string - string(REGEX REPLACE "\n" "\\\\n\"\n\t\"" escaped "${escaped}") - set(${VAR} "${escaped}" PARENT_SCOPE) -endfunction(escape_var) + string(REGEX REPLACE "\n" "\\\\n\"\n\t\"" ${var} "${${var}}") +endmacro() set(var "") foreach(arg IN LISTS VERSION_SOURCES) - if(var STREQUAL "") set(var ${arg}) else() - - file(READ "${arg}" ${var}) - string(STRIP "${${var}}" ${var}) - string(REGEX REPLACE "\r\n" "\n" ${var} "${${var}}") - string(REGEX REPLACE "\r" "\n" ${var} "${${var}}") - - # Split the version file into lines. - string(REGEX MATCHALL "[^\r\n]+" lines "${${var}}") - set(${var}_COUNT 0) - foreach(line IN LISTS lines) - - set(${var}_${${var}_COUNT} "${line}") - escape_var(${var}_${${var}_COUNT}) - - # Find the first and last spaces - string(STRIP "${line}" line) - string(LENGTH "${line}" line_length) - set(first_space -1) - set(last_space ${line_length}) - foreach(i RANGE ${line_length}) - if(i LESS line_length) - string(SUBSTRING "${line}" ${i} 1 line_char) - if(line_char STREQUAL " ") - set(last_space ${i}) - if(first_space EQUAL -1) - set(first_space ${i}) - endif() - endif() - endif() - endforeach() - - if(first_space GREATER -1) - - # Get everything before the first space - string(SUBSTRING "${line}" 0 ${first_space} line_name) - string(STRIP "${line_name}" ${var}_${${var}_COUNT}_SHORTNAME) - escape_var(${var}_${${var}_COUNT}_SHORTNAME) - - # Get everything after the first space - math(EXPR num_length "${line_length} - ${first_space}") - string(SUBSTRING "${line}" ${first_space} ${num_length} line_num) - string(STRIP "${line_num}" ${var}_${${var}_COUNT}_STRING) - escape_var(${var}_${${var}_COUNT}_STRING) - - endif() - - if(line MATCHES " ([0-9]\\.[^ ]* \\+ )?[^ ]*$") - string(REGEX REPLACE " (([0-9]\\.[^ ]* \\+ )?[^ ]*)$" "" - ${var}_${${var}_COUNT}_NAME "${line}") - string(LENGTH ${${var}_${${var}_COUNT}_NAME} begin) - math(EXPR begin "${begin} + 1") - math(EXPR length "${line_length} - ${begin}") - string(SUBSTRING "${line}" "${begin}" "${length}" ${var}_${${var}_COUNT}_NUMBER) - - else() - set(${var}_${${var}_COUNT}_NAME "${line}") - set(${var}_${${var}_COUNT}_NUMBER) - endif() - escape_var(${var}_${${var}_COUNT}_NAME) - escape_var(${var}_${${var}_COUNT}_NUMBER) - - math(EXPR ${var}_COUNT "${${var}_COUNT} + 1") - endforeach() - - string(REGEX REPLACE "\n\n.*$" "" ${var}_HEAD "${${var}}") - string(STRIP "${${var}_HEAD}" ${var}_HEAD) - string(REGEX MATCH "\n\n.*" ${var}_TAIL "${${var}}") - string(STRIP "${${var}_TAIL}" ${var}_TAIL) - - escape_var(${var}) - escape_var(${var}_HEAD) - escape_var(${var}_TAIL) - + parse_version_file(${var} "${arg}" ON) set(var "") endif() - endforeach() # Check for a git directory and fill in the git commit hash if one exists. unset(GIT_COMMIT) -if(EXISTS "${GIT_DIR}") +if(NOT GIT_DIR STREQUAL "") unset(git_head) diff --git a/cmake/VersionString.cmake b/cmake/VersionString.cmake index 40cd1ca..fe8b31f 100644 --- a/cmake/VersionString.cmake +++ b/cmake/VersionString.cmake @@ -1,5 +1,5 @@ -# Copyright (C) 2011-2016 Daniel Scharrer +# Copyright (C) 2011-2020 Daniel Scharrer # # This software is provided 'as-is', without any express or implied # warranty. In no event will the author(s) be held liable for any damages @@ -17,8 +17,7 @@ # misrepresented as being the original software. # 3. This notice may not be removed or altered from any source distribution. -get_filename_component(VERSION_STRING_DIR "${CMAKE_CURRENT_LIST_FILE}" PATH) -set(VERSION_STRING_SCRIPT "${VERSION_STRING_DIR}/VersionScript.cmake") +set(VERSION_STRING_SCRIPT "${CMAKE_CURRENT_LIST_DIR}/VersionScript.cmake") # Create a rule to generate a version string at compile time. # @@ -33,11 +32,20 @@ set(VERSION_STRING_SCRIPT "${VERSION_STRING_DIR}/VersionScript.cmake") # for each variable ${var} # - ${var}: The contents of the associated file # - ${var}_COUNT: Number of lines in the associated file -# - ${var}_${i}: The ${i}-th line of the associated file -# - ${var}_${i}_SHORTNAME: The first component of the ${i}-th line of the associated file -# - ${var}_${i}_STRING: Everything except the first component of the ${i}-th line of the associated file -# - ${var}_${i}_NAME: Everything except the last component of the ${i}-th line of the associated file -# - ${var}_${i}_NUMBER: The last component of the ${i}-th line of the associated file +# - For each line ${i}: +# - ${var}_${i}: The ${i}-th line of the associated file +# - ${var}_${i}_PREFIX: The first component in the line +# - ${var}_${i}_LINE: Everything except the first component of the line +# - ${var}_${i}_NAME: Everything except the last component of the line +# - ${var}_${i}_STRING: The last component (excluding optional suffix) of the line +# - ${var}_${i}_SUFFIX: Suffix (seperated by " + ") of the line +# - ${var}_${i}_MAJOR: First version component in ${var}_${i}_STRING +# - ${var}_${i}_MINOR: Second version component in ${var}_${i}_STRING +# - ${var}_${i}_PATCH: Third version component in ${var}_${i}_STRING +# - ${var}_${i}_BUILD: Fourth version component in ${var}_${i}_STRING +# - ${var}_${i}_NUMBER: Reassembled verion components +# - ${var}_${i}_PRERELEASE: If the version indicates a prerelease build +# - ${var}_${i}_PRIVATE: If the version indicates a private build # - ${var}_HEAD: The first paragraph of the associated file # - ${var}_TAIL: The remaining paragraphs of the associated file # @@ -92,6 +100,8 @@ function(version_file SRC DST VERSION_SOURCES GIT_DIR) if(EXISTS "${abs_git_dir}/logs/HEAD") list(APPEND dependencies "${abs_git_dir}/logs/HEAD") endif() + else() + set(abs_git_dir "") endif() add_custom_command( @@ -106,6 +116,8 @@ function(version_file SRC DST VERSION_SOURCES GIT_DIR) "-DGIT_COMMAND=${GIT_COMMAND}" ${defines} -P "${VERSION_STRING_SCRIPT}" + COMMAND + ${CMAKE_COMMAND} -E touch "${abs_dst}" MAIN_DEPENDENCY "${abs_src}" DEPENDS @@ -114,4 +126,198 @@ function(version_file SRC DST VERSION_SOURCES GIT_DIR) VERBATIM ) -endfunction(version_file) +endfunction() + +macro(_version_escape var string) + set(${var} "${string}") +endmacro() + +macro(_define_version_var_nostrip suffix contents) + _version_escape(${var}_${suffix} "${${contents}}") + list(APPEND variables ${var}_${suffix}) +endmacro() + +macro(_define_version_var suffix contents) + string(STRIP "${${contents}}" tmp) + _define_version_var_nostrip(${suffix} tmp) +endmacro() + +macro(_define_version_line_var_nostrip suffix contents) + _define_version_var_nostrip(${i}_${suffix} ${contents}) + if(line_name) + set(${line_name}_${suffix} "${${var}_${i}_${suffix}}") + list(APPEND variables ${line_name}_${suffix}) + endif() +endmacro() + +macro(_define_version_line_var suffix contents) + string(STRIP "${${contents}}" tmp) + _define_version_line_var_nostrip(${suffix} tmp) +endmacro() + +function(parse_version_file names file) + + list(GET names 0 var) + + list(LENGTH names names_count) + + set(variables) + + file(READ "${file}" contents) + string(STRIP "${contents}" contents) + string(REGEX REPLACE "\r\n" "\n" contents "${contents}") + string(REGEX REPLACE "\r" "\n" contents "${contents}") + _version_escape(${var} "${contents}") + list(APPEND variables ${var}) + + # Split the version file into lines. + string(REGEX MATCHALL "[^\r\n]+" lines "${contents}") + set(i 0) + foreach(line IN LISTS lines) + + if(i LESS names_count) + list(GET names ${i} line_name) + else() + set(line_name) + endif() + + _define_version_var(${i} line) + + if(line MATCHES "^([^ ]*) (.*)$") + set(prefix "${CMAKE_MATCH_1}") + set(notprefix "${CMAKE_MATCH_2}") + _define_version_line_var(PREFIX prefix) + _define_version_line_var(LINE notprefix) + else() + _define_version_line_var(PREFIX line) + endif() + + if(line MATCHES "^(.*[^+] )?([^ ]+)( \\+ [^ ]+)?$") + + set(name "${CMAKE_MATCH_1}") + set(string "${CMAKE_MATCH_2}") + set(suffix "${CMAKE_MATCH_3}") + + _define_version_line_var(NAME name) + _define_version_line_var(STRING string) + _define_version_line_var_nostrip(SUFFIX suffix) + + if(i GREATER 0 AND line_name) + set(${line_name} "${${var}_${i}_STRING}") + list(APPEND variables ${line_name}) + endif() + + if(string MATCHES "^([0-9]+)(\\.([0-9]+)(\\.([0-9]+)(\\.([0-9]+))?)?)?(.*)?$") + + set(major "${CMAKE_MATCH_1}") + set(minor "${CMAKE_MATCH_3}") + set(patch "${CMAKE_MATCH_5}") + set(build "${CMAKE_MATCH_7}") + set(release "${CMAKE_MATCH_8}") + + set(error 0) + set(newpatch) + set(newbuild) + set(prerelease 0) + set(private 0) + if(release MATCHES "^\\-dev\\-([2-9][0-9][0-9][0-9]+)\\-([0-9][0-9])\\-([0-9][0-9])$") + set(prerelease 1) + set(newpatch "${CMAKE_MATCH_1}") + set(newbuild "${CMAKE_MATCH_2}${CMAKE_MATCH_3}") + elseif(release MATCHES "^\\-rc([0-9]+)$") + set(prerelease 1) + set(newpatch "9999") + set(newbuild "${CMAKE_MATCH_1}") + elseif(release MATCHES "^\\-r([0-9]+)$") + if(build STREQUAL "") + set(build "${CMAKE_MATCH_1}") + else() + set(error 1) + endif() + elseif(release OR suffix) + set(prerelease 1) + set(private 1) + set(newpatch 9999) + set(newbuild 9999) + endif() + + foreach(component IN ITEMS major minor patch build newpatch newbuild) + string(REGEX REPLACE "^0+" "" ${component} "${${component}}") + if(NOT ${component}) + set(${component} 0) + endif() + endforeach() + + if(newpatch) + set(prerelease 1) + if(build) + set(error 1) + else() + if(patch) + if(newpatch EQUAL 9999) + math(EXPR patch "${patch} - 1") + if(newbuild EQUAL 9999) + set(build 9999) + else() + math(EXPR build "${newbuild} + 1000") + endif() + else() + set(error 1) + endif() + else() + if(minor) + math(EXPR minor "${minor} - 1") + else() + if(major) + math(EXPR major "${major} - 1") + else() + set(error 1) + endif() + set(minor 9999) + endif() + set(patch "${newpatch}") + set(build "${newbuild}") + endif() + endif() + endif() + + set(number "${major}") + if(minor OR patch OR build) + set(number "${number}.${minor}") + if(patch OR build) + set(number "${number}.${patch}") + if(build) + set(number "${number}.${build}") + endif() + endif() + endif() + + _define_version_line_var(MAJOR major) + _define_version_line_var(MINOR minor) + _define_version_line_var(PATCH patch) + _define_version_line_var(BUILD build) + _define_version_line_var(PRERELEASE prerelease) + _define_version_line_var(PRIVATE private) + _define_version_line_var(NUMBER number) + _define_version_line_var(ERROR error) + + endif() + + endif() + + math(EXPR i "${i} + 1") + endforeach() + + set(${var}_COUNT ${i} PARENT_SCOPE) + + string(REGEX REPLACE "\n\n.*$" "" head "${contents}") + _define_version_var(HEAD head) + + string(REGEX MATCH "\n\n.*" tail "${contents}") + _define_version_var(TAIL tail) + + foreach(var IN LISTS variables) + set(${var} "${${var}}" PARENT_SCOPE) + endforeach() + +endfunction() diff --git a/doc/innoextract.1.in b/doc/innoextract.1.in index 682052a..996dabb 100644 --- a/doc/innoextract.1.in +++ b/doc/innoextract.1.in @@ -1,6 +1,6 @@ .\" Manpage for innoextract. .\" Contact daniel@constexpr.org to correct errors or typos. -.TH innoextract 1 "@CHANGELOG_0_NUMBER@" "@VERSION_0_NUMBER@@GIT_SUFFIX_7@" +.TH innoextract 1 "@CHANGELOG_0_STRING@" "@VERSION_0_STRING@@VERSION_SUFFIX@@GIT_SUFFIX_7@" .SH NAME innoextract - tool to extract installers created by Inno Setup .SH SYNOPSIS diff --git a/src/release.cpp.in b/src/release.cpp.in index ea9d61d..41c27ae 100644 --- a/src/release.cpp.in +++ b/src/release.cpp.in @@ -38,12 +38,12 @@ const char innoextract_name[] = "${VERSION_0_NAME}"; -const char innoextract_version[] = "${VERSION_0_NUMBER}${GIT_SUFFIX_7}"; +const char innoextract_version[] = "${VERSION_0_STRING}${VERSION_SUFFIX}${GIT_SUFFIX_7}"; const char innosetup_versions[] = "${VERSION_2}"; const char innoextract_bugs[] = "${VERSION_4}"; -const char innoextract_copyright[] = "${LICENSE_0_STRING}"; +const char innoextract_copyright[] = "${LICENSE_0_LINE}"; const char innoextract_license[] = "${LICENSE_TAIL}";