diff --git a/docs/module/ECMConfiguredInstall.rst b/docs/module/ECMConfiguredInstall.rst new file mode 100644 --- /dev/null +++ b/docs/module/ECMConfiguredInstall.rst @@ -0,0 +1 @@ +.. ecm-module:: ../../modules/ECMConfiguredInstall.cmake diff --git a/modules/ECMConfiguredInstall.cmake b/modules/ECMConfiguredInstall.cmake new file mode 100644 --- /dev/null +++ b/modules/ECMConfiguredInstall.cmake @@ -0,0 +1,89 @@ +#.rst: +# ECMConfiguredInstall +# -------------------- +# +# Take a list of files, runs configure_file and installs the resultant configured file in the given location. +# +# Any suffix of ".in" in the passed file names wil be stripped from the file name at the installed location. +# :: +# ecm_install_configured_files( +# TEMPLATES [ [...]] +# DESTINATION +# [COPYONLY] +# [ESCAPE_QUOTES] +# [@ONLY] +# [COMPONENT ]) +# +# Example usage: +# +# .. code-block:: cmake +# +# ecm_install_configured_files(TEMPLATES foo.txt.in DESTINATION ${KDE_INSTALL_DATADIR} @ONLY) +# +# This wil install the file as foo.txt with any cmake variable replacements made into the data directory. +# +# Since 5.70.0. + +# Copyright 2020 David Edmundson +# +# Redistribution and use in source and binary forms, with or without +# modification, are permitted provided that the following conditions +# are met: +# +# 1. Redistributions of source code must retain the copyright +# notice, this list of conditions and the following disclaimer. +# 2. Redistributions in binary form must reproduce the copyright +# notice, this list of conditions and the following disclaimer in the +# documentation and/or other materials provided with the distribution. +# 3. The name of the author may not be used to endorse or promote products +# derived from this software without specific prior written permission. +# +# THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR +# IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES +# OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. +# IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, +# INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT +# NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, +# DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY +# THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +# (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF +# THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + +function(ecm_install_configured_files) + set(options COPYONLY ESCAPE_QUOTES @ONLY) + set(oneValueArgs DESTINATION COMPONENT) + set(multiValueArgs TEMPLATES) + + cmake_parse_arguments(ARGS "${options}" "${oneValueArgs}" + "${multiValueArgs}" ${ARGN}) + + foreach(_template ${ARGS_TEMPLATES}) + # convert absolute paths + get_filename_component(_name ${_template} NAME) + + string(REGEX REPLACE "\\.in$" "" _name ${_name}) + + set(_out_file ${CMAKE_CURRENT_BINARY_DIR}/${_name}) + + set(_configure_args) + if (ARGS_COPY_ONLY) + list(APPEND _configure_args COPY_ONLY) + endif() + if (ARGS_ESCAPE_QUOTES) + list(APPEND _configure_args ESCAPE_QUOTES) + endif() + if (ARGS_@ONLY) + list(APPEND _configure_args @ONLY) + endif() + + configure_file(${_template} ${_out_file} ${_configure_args}) + + if (DEFINED ARGS_COMPONENT) + set(_component COMPONENT ${ARGS_COMPONENT}) + else() + set(_component) + endif() + + install(FILES ${_out_file} DESTINATION ${ARGS_DESTINATION} ${_component}) + endforeach() +endfunction() diff --git a/tests/CMakeLists.txt b/tests/CMakeLists.txt --- a/tests/CMakeLists.txt +++ b/tests/CMakeLists.txt @@ -222,3 +222,13 @@ if (TARGET Qt5::Quick) add_test_macro(ECMQMLModules dummy) endif() + +set(ECMConfiguredInstallTest_EXTRA_OPTIONS + --build-target install + --build-options + "-DCMAKE_INSTALL_PREFIX:PATH=${CMAKE_CURRENT_BINARY_DIR}/ECMConfiguredInstallTest/InstallDirectory" +) +add_test_macro(ECMConfiguredInstallTest + ${CMAKE_COMMAND} -P "${CMAKE_CURRENT_BINARY_DIR}/ECMConfiguredInstallTest/check_tree.cmake" +) + diff --git a/tests/ECMConfiguredInstallTest/CMakeLists.txt b/tests/ECMConfiguredInstallTest/CMakeLists.txt new file mode 100644 --- /dev/null +++ b/tests/ECMConfiguredInstallTest/CMakeLists.txt @@ -0,0 +1,21 @@ +project(ECMConfiguredInstallTest) +cmake_minimum_required(VERSION 3.5) +set(CMAKE_MODULE_PATH ${CMAKE_CURRENT_SOURCE_DIR}/../../modules) + +# make sure the test install dir is clean +file(REMOVE_RECURSE "${CMAKE_INSTALL_PREFIX}") +include(ECMConfiguredInstall) + +# run test + +set(FOO myFoo) +set(BAR myBar) + +ecm_install_configured_files(TEMPLATES configured.txt DESTINATION ${CMAKE_INSTALL_PREFIX}/test) + +ecm_install_configured_files(TEMPLATES configured_atOnly.txt.in DESTINATION ${CMAKE_INSTALL_PREFIX}/test @ONLY ESCAPE_QUOTES) + +ecm_install_configured_files(TEMPLATES multi1.txt.in ${CMAKE_CURRENT_SOURCE_DIR}/multi2.txt.in DESTINATION ${CMAKE_INSTALL_PREFIX}/test) + +# this will be run by CTest +configure_file(check_tree.cmake.in "${CMAKE_CURRENT_BINARY_DIR}/check_tree.cmake" @ONLY) diff --git a/tests/ECMConfiguredInstallTest/check_tree.cmake.in b/tests/ECMConfiguredInstallTest/check_tree.cmake.in new file mode 100644 --- /dev/null +++ b/tests/ECMConfiguredInstallTest/check_tree.cmake.in @@ -0,0 +1,20 @@ +set(EXPECTED "@CMAKE_CURRENT_SOURCE_DIR@/expected") +set(ACTUAL "@CMAKE_INSTALL_PREFIX@") + +# Compares files in two directories, emits a fatal error if the top level files are different +# Takes a directory of expected files, and a directory of output files +function(compare_dirs expected output ) + file(GLOB files "${expected}/*") + foreach(file ${files}) + get_filename_component(name ${file} NAME) + + execute_process(COMMAND ${CMAKE_COMMAND} -E compare_files ${file} "${output}/${name}" + RESULT_VARIABLE test_result + ) + If (NOT test_result EQUAL 0) + message(FATAL_ERROR "Test failed: ${file} doesn't match ${output}/${name}!") + endif() + endforeach() +endfunction() + +compare_dirs(${EXPECTED} ${ACTUAL}/test ) diff --git a/tests/ECMConfiguredInstallTest/configured.txt b/tests/ECMConfiguredInstallTest/configured.txt new file mode 100644 --- /dev/null +++ b/tests/ECMConfiguredInstallTest/configured.txt @@ -0,0 +1,3 @@ +[General] +Foo=@FOO@ +Bar=${BAR} diff --git a/tests/ECMConfiguredInstallTest/configured_atOnly.txt.in b/tests/ECMConfiguredInstallTest/configured_atOnly.txt.in new file mode 100644 --- /dev/null +++ b/tests/ECMConfiguredInstallTest/configured_atOnly.txt.in @@ -0,0 +1,3 @@ +[General] +Foo=@FOO@ +Bar=${BAR} diff --git a/tests/ECMConfiguredInstallTest/expected/configured.txt b/tests/ECMConfiguredInstallTest/expected/configured.txt new file mode 100644 --- /dev/null +++ b/tests/ECMConfiguredInstallTest/expected/configured.txt @@ -0,0 +1,3 @@ +[General] +Foo=myFoo +Bar=myBar diff --git a/tests/ECMConfiguredInstallTest/expected/configured_atOnly.txt b/tests/ECMConfiguredInstallTest/expected/configured_atOnly.txt new file mode 100644 --- /dev/null +++ b/tests/ECMConfiguredInstallTest/expected/configured_atOnly.txt @@ -0,0 +1,3 @@ +[General] +Foo=myFoo +Bar=${BAR} diff --git a/tests/ECMConfiguredInstallTest/expected/multi1.txt b/tests/ECMConfiguredInstallTest/expected/multi1.txt new file mode 100644 --- /dev/null +++ b/tests/ECMConfiguredInstallTest/expected/multi1.txt @@ -0,0 +1,2 @@ +TestMulti1 +Foo=myFoo diff --git a/tests/ECMConfiguredInstallTest/expected/multi2.txt b/tests/ECMConfiguredInstallTest/expected/multi2.txt new file mode 100644 --- /dev/null +++ b/tests/ECMConfiguredInstallTest/expected/multi2.txt @@ -0,0 +1,2 @@ +TestMulti2 +Foo=myFoo diff --git a/tests/ECMConfiguredInstallTest/multi1.txt.in b/tests/ECMConfiguredInstallTest/multi1.txt.in new file mode 100644 --- /dev/null +++ b/tests/ECMConfiguredInstallTest/multi1.txt.in @@ -0,0 +1,2 @@ +TestMulti1 +Foo=@FOO@ diff --git a/tests/ECMConfiguredInstallTest/multi2.txt.in b/tests/ECMConfiguredInstallTest/multi2.txt.in new file mode 100644 --- /dev/null +++ b/tests/ECMConfiguredInstallTest/multi2.txt.in @@ -0,0 +1,2 @@ +TestMulti2 +Foo=@FOO@