Ver Fonte

CPack/RPM: Generate source rpm (SRPM) packages on demand

Closes: #15839
Domen Vrankar há 9 anos atrás
pai
commit
d9cec8adca

+ 7 - 0
Help/release/dev/cpack-rpm-srpm-package.rst

@@ -0,0 +1,7 @@
+cpack-rpm-srpm-package
+----------------------
+
+* The :module:`CPackRPM` module learned to generate source rpm
+  (SRPM) packages on demand. See :variable:`CPACK_RPM_PACKAGE_SOURCES`,
+  :variable:`CPACK_RPM_SOURCE_PKG_BUILD_PARAMS` and
+  :variable:`CPACK_RPM_SOURCE_PKG_PACKAGING_INSTALL_PREFIX`.

+ 5 - 0
Modules/CPack.cmake

@@ -502,6 +502,7 @@ if(NOT CPACK_SOURCE_GENERATOR)
     if(CYGWIN)
       option(CPACK_SOURCE_CYGWIN "Enable to build Cygwin source packages" ON)
     else()
+      option(CPACK_SOURCE_RPM  "Enable to build RPM source packages"  OFF)
       option(CPACK_SOURCE_TBZ2 "Enable to build TBZ2 source packages" ON)
       option(CPACK_SOURCE_TGZ  "Enable to build TGZ source packages"  ON)
       option(CPACK_SOURCE_TXZ  "Enable to build TXZ source packages"  ON)
@@ -515,6 +516,7 @@ if(NOT CPACK_SOURCE_GENERATOR)
 
   cpack_optional_append(CPACK_SOURCE_GENERATOR  CPACK_SOURCE_7Z      7Z)
   cpack_optional_append(CPACK_SOURCE_GENERATOR  CPACK_SOURCE_CYGWIN  CygwinSource)
+  cpack_optional_append(CPACK_SOURCE_GENERATOR  CPACK_SOURCE_RPM     RPM)
   cpack_optional_append(CPACK_SOURCE_GENERATOR  CPACK_SOURCE_TBZ2    TBZ2)
   cpack_optional_append(CPACK_SOURCE_GENERATOR  CPACK_SOURCE_TGZ     TGZ)
   cpack_optional_append(CPACK_SOURCE_GENERATOR  CPACK_SOURCE_TXZ     TXZ)
@@ -544,6 +546,7 @@ mark_as_advanced(
   CPACK_BINARY_ZIP
   CPACK_SOURCE_7Z
   CPACK_SOURCE_CYGWIN
+  CPACK_SOURCE_RPM
   CPACK_SOURCE_TBZ2
   CPACK_SOURCE_TGZ
   CPACK_SOURCE_TXZ
@@ -651,6 +654,8 @@ set(CPACK_PACKAGE_FILE_NAME "${CPACK_SOURCE_PACKAGE_FILE_NAME}")
 set(CPACK_IGNORE_FILES "${CPACK_SOURCE_IGNORE_FILES}")
 set(CPACK_STRIP_FILES "${CPACK_SOURCE_STRIP_FILES}")
 
+set(CPACK_RPM_PACKAGE_SOURCES "ON")
+
 cpack_encode_variables()
 configure_file("${cpack_source_input_file}"
   "${CPACK_SOURCE_OUTPUT_CONFIG_FILE}" @ONLY)

+ 202 - 25
Modules/CPackRPM.cmake

@@ -706,6 +706,77 @@
 #   symbolic link(s) is also on a relocatable path, relocating it during
 #   package installation may cause initial symbolic link to point to an
 #   invalid location.
+#
+# Packaging of sources (SRPM)
+# ^^^^^^^^^^^^^^^^^^^^^^^^^^^
+#
+# SRPM packaging is enabled by setting :variable:`CPACK_RPM_PACKAGE_SOURCES`
+# variable while usually using :variable:`CPACK_INSTALLED_DIRECTORIES` variable
+# to provide directory containing CMakeLists.txt and source files.
+#
+# For CMake projects SRPM package would be product by executing:
+#
+# ``cpack -G RPM --config ./CPackSourceConfig.cmake``
+#
+# .. note::
+#
+#  Produced SRPM package is expected to be built with :manual:`cmake(1)` executable
+#  and packaged with :manual:`cpack(1)` executable so CMakeLists.txt has to be
+#  located in root source directory and must be able to generate binary rpm
+#  packages by executing ``cpack -G`` command. The two executables as well as
+#  rpmbuild must also be present when generating binary rpm packages from the
+#  produced SRPM package.
+#
+# Once the SRPM package is generated it can be used to generate binary packages
+# by creating a directory structure for rpm generation and executing rpmbuild
+# tool:
+#
+# ``mkdir -p build_dir/{BUILD,BUILDROOT,RPMS,SOURCES,SPECS,SRPMS}``
+# ``rpmbuild --define "_topdir <path_to_build_dir>" --rebuild <SRPM_file_name>``
+#
+# Generated packages will be located in build_dir/RPMS directory or its sub
+# directories.
+#
+# .. note::
+#
+#  SRPM package internally uses CPack/RPM generator to generate binary packages
+#  so CMakeScripts.txt can decide during the SRPM to binary rpm generation step
+#  what content the package(s) should have as well as how they should be packaged
+#  (monolithic or components). CMake can decide this for e.g. by reading environment
+#  variables set by the package manager before starting the process of generating
+#  binary rpm packages. This way a single SRPM package can be used to produce
+#  different binary rpm packages on different platforms depending on the platform's
+#  packaging rules.
+#
+# Source RPM packaging has it's own set of variables:
+#
+# .. variable:: CPACK_RPM_PACKAGE_SOURCES
+#
+#  Should the content be packaged as a source rpm (default is binary rpm).
+#
+#  * Mandatory : NO
+#  * Default   : OFF
+#
+# .. note::
+#
+#  For cmake projects :variable:`CPACK_RPM_PACKAGE_SOURCES` variable is set
+#  to ``OFF`` in CPackConfig.cmake and ``ON`` in CPackSourceConfig.cmake
+#  generated files.
+#
+# .. variable:: CPACK_RPM_SOURCE_PKG_BUILD_PARAMS
+#
+#  Additional command-line parameters provided to :manual:`cmake(1)` executable.
+#
+#  * Mandatory : NO
+#  * Default   : -
+#
+# .. variable:: CPACK_RPM_SOURCE_PKG_PACKAGING_INSTALL_PREFIX
+#
+#  Packaging install prefix that would be provided in :variable:`CPACK_PACKAGING_INSTALL_PREFIX`
+#  variable for producing binary RPM packages.
+#
+#  * Mandatory : YES
+#  * Default   : "/"
 
 #=============================================================================
 # Copyright 2007-2016 Kitware, Inc.
@@ -1515,18 +1586,27 @@ function(cpack_rpm_generate_package)
      set(CPACK_RPM_COMPRESSION_TYPE_TMP "")
   endif()
 
-  if(CPACK_PACKAGE_RELOCATABLE OR CPACK_RPM_PACKAGE_RELOCATABLE)
-    if(CPACK_RPM_PACKAGE_DEBUG)
-      message("CPackRPM:Debug: Trying to build a relocatable package")
+  if(NOT CPACK_RPM_PACKAGE_SOURCES)
+    if(CPACK_PACKAGE_RELOCATABLE OR CPACK_RPM_PACKAGE_RELOCATABLE)
+      if(CPACK_RPM_PACKAGE_DEBUG)
+        message("CPackRPM:Debug: Trying to build a relocatable package")
+      endif()
+      if(CPACK_SET_DESTDIR AND (NOT CPACK_SET_DESTDIR STREQUAL "I_ON"))
+        message("CPackRPM:Warning: CPACK_SET_DESTDIR is set (=${CPACK_SET_DESTDIR}) while requesting a relocatable package (CPACK_RPM_PACKAGE_RELOCATABLE is set): this is not supported, the package won't be relocatable.")
+        set(CPACK_RPM_PACKAGE_RELOCATABLE FALSE)
+      else()
+        set(CPACK_RPM_PACKAGE_PREFIX ${CPACK_PACKAGING_INSTALL_PREFIX}) # kept for back compatibility (provided external RPM spec files)
+        cpack_rpm_prepare_relocation_paths()
+        set(CPACK_RPM_PACKAGE_RELOCATABLE TRUE)
+      endif()
     endif()
-    if(CPACK_SET_DESTDIR AND (NOT CPACK_SET_DESTDIR STREQUAL "I_ON"))
-      message("CPackRPM:Warning: CPACK_SET_DESTDIR is set (=${CPACK_SET_DESTDIR}) while requesting a relocatable package (CPACK_RPM_PACKAGE_RELOCATABLE is set): this is not supported, the package won't be relocatable.")
-      set(CPACK_RPM_PACKAGE_RELOCATABLE FALSE)
-    else()
-      set(CPACK_RPM_PACKAGE_PREFIX ${CPACK_PACKAGING_INSTALL_PREFIX}) # kept for back compatibility (provided external RPM spec files)
-      cpack_rpm_prepare_relocation_paths()
-      set(CPACK_RPM_PACKAGE_RELOCATABLE TRUE)
+  else()
+    if(CPACK_RPM_PACKAGE_COMPONENT)
+      message(FATAL_ERROR "CPACK_RPM_PACKAGE_SOURCES parameter can not be used"
+        " in combination with CPACK_RPM_PACKAGE_COMPONENT parameter!")
     endif()
+
+    set(CPACK_RPM_PACKAGE_RELOCATABLE FALSE) # disable relocatable option if building source RPM
   endif()
 
   # Check if additional fields for RPM spec header are given
@@ -1870,13 +1950,50 @@ function(cpack_rpm_generate_package)
     endif()
   endif()
 
-  # We should generate a USER spec file template:
-  #  - either because the user asked for it : CPACK_RPM_GENERATE_USER_BINARY_SPECFILE_TEMPLATE
-  #  - or the user did not provide one : NOT CPACK_RPM_USER_BINARY_SPECFILE
-  if(CPACK_RPM_GENERATE_USER_BINARY_SPECFILE_TEMPLATE OR NOT CPACK_RPM_USER_BINARY_SPECFILE)
+  if(CPACK_RPM_PACKAGE_SOURCES) # source rpm
+    set(archive_name_ "${CPACK_RPM_PACKAGE_NAME}-${CPACK_RPM_PACKAGE_VERSION}")
+
+    execute_process(
+        COMMAND ${CMAKE_COMMAND} -E tar "cfvz" "${CPACK_RPM_DIRECTORY}/SOURCES/${archive_name_}.tar.gz" "${CPACK_PACKAGE_FILE_NAME}"
+        WORKING_DIRECTORY ${CPACK_RPM_DIRECTORY}
+      )
+    set(TMP_RPM_SOURCE "Source: ${archive_name_}.tar.gz")
+
+    if(CPACK_RPM_BUILDREQUIRES)
+      set(TMP_RPM_BUILD_REQUIRES "BuildRequires: ${CPACK_RPM_BUILDREQUIRES}")
+    endif()
+
+    # Disable debuginfo packages - srpm generates invalid packages due to
+    # releasing controll to cpack to generate binary packages.
+    # Note however that this doesn't prevent cpack to generate debuginfo
+    # packages when run from srpm with --rebuild.
+    set(TMP_RPM_DISABLE_DEBUGINFO "%define debug_package %{nil}")
+
+    if(NOT CPACK_RPM_SOURCE_PKG_PACKAGING_INSTALL_PREFIX)
+      set(CPACK_RPM_SOURCE_PKG_PACKAGING_INSTALL_PREFIX "/")
+    endif()
+
+    set(TMP_RPM_BUILD
+      "
+%build
+mkdir cpack_rpm_build_dir
+cd cpack_rpm_build_dir
+cmake ${CPACK_RPM_SOURCE_PKG_BUILD_PARAMS} -DCPACK_PACKAGING_INSTALL_PREFIX=${CPACK_RPM_SOURCE_PKG_PACKAGING_INSTALL_PREFIX} ../${CPACK_PACKAGE_FILE_NAME}
+make %{?_smp_mflags}" # %{?_smp_mflags} -> -j option
+      )
+    set(TMP_RPM_INSTALL
+      "
+cd cpack_rpm_build_dir
+cpack -G RPM
+mv *.rpm %_rpmdir"
+      )
+    set(TMP_RPM_PREP "%setup -c")
+
+    set(RPMBUILD_FLAGS "-bs")
+
      file(WRITE ${CPACK_RPM_BINARY_SPECFILE}.in
       "# -*- rpm-spec -*-
-BuildRoot:      \@CPACK_RPM_DIRECTORY\@/\@CPACK_PACKAGE_FILE_NAME\@\@CPACK_RPM_PACKAGE_COMPONENT_PART_PATH\@
+BuildRoot:      %_topdir/\@CPACK_PACKAGE_FILE_NAME\@
 Summary:        \@CPACK_RPM_PACKAGE_SUMMARY\@
 Name:           \@CPACK_RPM_PACKAGE_NAME\@
 Version:        \@CPACK_RPM_PACKAGE_VERSION\@
@@ -1884,6 +2001,64 @@ Release:        \@CPACK_RPM_PACKAGE_RELEASE\@
 License:        \@CPACK_RPM_PACKAGE_LICENSE\@
 Group:          \@CPACK_RPM_PACKAGE_GROUP\@
 Vendor:         \@CPACK_RPM_PACKAGE_VENDOR\@
+
+\@TMP_RPM_SOURCE\@
+\@TMP_RPM_BUILD_REQUIRES\@
+\@TMP_RPM_BUILDARCH\@
+\@TMP_RPM_PREFIXES\@
+
+\@TMP_RPM_DISABLE_DEBUGINFO\@
+
+%define _rpmdir %_topdir/RPMS
+%define _srcrpmdir %_topdir/SRPMS
+\@FILE_NAME_DEFINE\@
+%define _unpackaged_files_terminate_build 0
+\@TMP_RPM_SPEC_INSTALL_POST\@
+\@CPACK_RPM_SPEC_MORE_DEFINE\@
+\@CPACK_RPM_COMPRESSION_TYPE_TMP\@
+
+%description
+\@CPACK_RPM_PACKAGE_DESCRIPTION\@
+
+# This is a shortcutted spec file generated by CMake RPM generator
+# we skip _install step because CPack does that for us.
+# We do only save CPack installed tree in _prepr
+# and then restore it in build.
+%prep
+\@TMP_RPM_PREP\@
+
+\@TMP_RPM_BUILD\@
+
+#p build
+
+%install
+\@TMP_RPM_INSTALL\@
+
+%clean
+
+%changelog
+\@CPACK_RPM_SPEC_CHANGELOG\@
+"
+    )
+  else()  # binary rpm
+
+    # We should generate a USER spec file template:
+    #  - either because the user asked for it : CPACK_RPM_GENERATE_USER_BINARY_SPECFILE_TEMPLATE
+    #  - or the user did not provide one : NOT CPACK_RPM_USER_BINARY_SPECFILE
+    if(CPACK_RPM_GENERATE_USER_BINARY_SPECFILE_TEMPLATE OR NOT CPACK_RPM_USER_BINARY_SPECFILE)
+      set(RPMBUILD_FLAGS "-bb")
+
+      file(WRITE ${CPACK_RPM_BINARY_SPECFILE}.in
+        "# -*- rpm-spec -*-
+BuildRoot:      %_topdir/\@CPACK_PACKAGE_FILE_NAME\@\@CPACK_RPM_PACKAGE_COMPONENT_PART_PATH\@
+Summary:        \@CPACK_RPM_PACKAGE_SUMMARY\@
+Name:           \@CPACK_RPM_PACKAGE_NAME\@
+Version:        \@CPACK_RPM_PACKAGE_VERSION\@
+Release:        \@CPACK_RPM_PACKAGE_RELEASE\@
+License:        \@CPACK_RPM_PACKAGE_LICENSE\@
+Group:          \@CPACK_RPM_PACKAGE_GROUP\@
+Vendor:         \@CPACK_RPM_PACKAGE_VENDOR\@
+
 \@TMP_RPM_URL\@
 \@TMP_RPM_REQUIRES\@
 \@TMP_RPM_REQUIRES_PRE\@
@@ -1901,10 +2076,10 @@ Vendor:         \@CPACK_RPM_PACKAGE_VENDOR\@
 
 \@TMP_RPM_DEBUGINFO\@
 
-%define _rpmdir \@CPACK_RPM_DIRECTORY\@
+%define _rpmdir %_topdir/RPMS
+%define _srcrpmdir %_topdir/SRPMS
 \@FILE_NAME_DEFINE\@
 %define _unpackaged_files_terminate_build 0
-%define _topdir \@CPACK_RPM_DIRECTORY\@
 \@TMP_RPM_SPEC_INSTALL_POST\@
 \@CPACK_RPM_SPEC_MORE_DEFINE\@
 \@CPACK_RPM_COMPRESSION_TYPE_TMP\@
@@ -1917,16 +2092,14 @@ Vendor:         \@CPACK_RPM_PACKAGE_VENDOR\@
 # We do only save CPack installed tree in _prepr
 # and then restore it in build.
 %prep
-mv $RPM_BUILD_ROOT \"\@CPACK_TOPLEVEL_DIRECTORY\@/tmpBBroot\"
-
-#p build
+mv $RPM_BUILD_ROOT %_topdir/tmpBBroot
 
 %install
 if [ -e $RPM_BUILD_ROOT ];
 then
   rm -rf $RPM_BUILD_ROOT
 fi
-mv \"\@CPACK_TOPLEVEL_DIRECTORY\@/tmpBBroot\" $RPM_BUILD_ROOT
+mv %_topdir/tmpBBroot $RPM_BUILD_ROOT
 
 %clean
 
@@ -1951,7 +2124,10 @@ mv \"\@CPACK_TOPLEVEL_DIRECTORY\@/tmpBBroot\" $RPM_BUILD_ROOT
 
 %changelog
 \@CPACK_RPM_SPEC_CHANGELOG\@
-")
+"
+      )
+    endif()
+
     # Stop here if we were asked to only generate a template USER spec file
     # The generated file may then be used as a template by user who wants
     # to customize their own spec file.
@@ -1977,9 +2153,9 @@ mv \"\@CPACK_TOPLEVEL_DIRECTORY\@/tmpBBroot\" $RPM_BUILD_ROOT
   if(RPMBUILD_EXECUTABLE)
     # Now call rpmbuild using the SPECFILE
     execute_process(
-      COMMAND "${RPMBUILD_EXECUTABLE}" -bb
+      COMMAND "${RPMBUILD_EXECUTABLE}" ${RPMBUILD_FLAGS}
               --define "_topdir ${CPACK_RPM_DIRECTORY}"
-              --buildroot "${CPACK_RPM_DIRECTORY}/${CPACK_PACKAGE_FILE_NAME}${CPACK_RPM_PACKAGE_COMPONENT_PART_PATH}"
+              --buildroot "%_topdir/${CPACK_PACKAGE_FILE_NAME}${CPACK_RPM_PACKAGE_COMPONENT_PART_PATH}" # TODO should I remove this variable? or change the path?
               --target "${CPACK_RPM_PACKAGE_ARCHITECTURE}"
               "${CPACK_RPM_BINARY_SPECFILE}"
       WORKING_DIRECTORY "${CPACK_TOPLEVEL_DIRECTORY}/${CPACK_PACKAGE_FILE_NAME}${CPACK_RPM_PACKAGE_COMPONENT_PART_PATH}"
@@ -2006,7 +2182,8 @@ mv \"\@CPACK_TOPLEVEL_DIRECTORY\@/tmpBBroot\" $RPM_BUILD_ROOT
     # Tell file(GLOB_RECURSE) not to follow directory symlinks
     # even if the project does not set this policy to NEW.
     cmake_policy(SET CMP0009 NEW)
-    file(GLOB_RECURSE GENERATED_FILES "${CPACK_RPM_DIRECTORY}/*.rpm")
+    file(GLOB_RECURSE GENERATED_FILES "${CPACK_RPM_DIRECTORY}/RPMS/*.rpm"
+      "${CPACK_RPM_DIRECTORY}/SRPMS/*.rpm")
   cmake_policy(POP)
 
   if(NOT GENERATED_FILES)

+ 66 - 0
Tests/RunCMake/CPack/CPackTestHelpers.cmake

@@ -1,4 +1,70 @@
 cmake_policy(SET CMP0057 NEW)
+function(run_cpack_test_common_for_merge_ TEST_NAME types build source)
+  if(TEST_TYPE IN_LIST types)
+    set(RunCMake_TEST_NO_CLEAN TRUE)
+    set(RunCMake_TEST_BINARY_DIR "${RunCMake_BINARY_DIR}/${TEST_NAME}-build")
+
+     # TODO this should be executed only once per ctest run (not per generator)
+    file(REMOVE_RECURSE "${RunCMake_TEST_BINARY_DIR}")
+    file(MAKE_DIRECTORY "${RunCMake_TEST_BINARY_DIR}")
+
+    if(EXISTS "${RunCMake_SOURCE_DIR}/${TEST_TYPE}/${TEST_NAME}-Prerequirements.cmake")
+      include("${RunCMake_SOURCE_DIR}/${TEST_TYPE}/${TEST_NAME}-Prerequirements.cmake")
+
+      set(FOUND_PREREQUIREMENTS false)
+      get_test_prerequirements("FOUND_PREREQUIREMENTS"
+          "${TEST_CONFIG_DIR}/${type}_config.cmake")
+
+      # skip the test if prerequirements are not met
+      if(NOT FOUND_PREREQUIREMENTS)
+        message(STATUS "${TEST_NAME} - SKIPPED")
+        return()
+      endif()
+    endif()
+
+    # execute cmake
+    set(RunCMake_TEST_OPTIONS "-DGENERATOR_TYPE=${TEST_TYPE}")
+    run_cmake(${TEST_NAME})
+
+    # execute optional build step
+    if(build)
+      run_cmake_command(${TEST_NAME}-Build "${CMAKE_COMMAND}" --build "${RunCMake_TEST_BINARY_DIR}")
+    endif()
+
+    if(source)
+      set(pack_params_ -G ${TEST_TYPE} --config ./CPackSourceConfig.cmake)
+      FILE(APPEND ${RunCMake_TEST_BINARY_DIR}/CPackSourceConfig.cmake
+        "\nset(CPACK_RPM_SOURCE_PKG_BUILD_PARAMS \"-DRunCMake_TEST:STRING=${TEST_NAME}\")")
+    else()
+      unset(pack_params_)
+    endif()
+
+    # execute cpack
+    execute_process(
+      COMMAND ${CMAKE_CPACK_COMMAND} ${pack_params_}
+      WORKING_DIRECTORY "${RunCMake_TEST_BINARY_DIR}"
+      RESULT_VARIABLE "result_"
+      OUTPUT_FILE "${RunCMake_TEST_BINARY_DIR}/test_output.txt"
+      ERROR_FILE "${RunCMake_TEST_BINARY_DIR}/test_error.txt"
+      )
+
+    # verify result
+    run_cmake_command(
+      ${TEST_TYPE}/${TEST_NAME}
+      "${CMAKE_COMMAND}"
+        -DRunCMake_TEST=${TEST_NAME}
+        -DGENERATOR_TYPE=${TEST_TYPE}
+        -DPACKAGING_RESULT=${result_}
+        "-Dsrc_dir=${RunCMake_SOURCE_DIR}"
+        "-Dbin_dir=${RunCMake_TEST_BINARY_DIR}"
+        "-Dconfig_file=${config_file}"
+        -P "${RunCMake_SOURCE_DIR}/VerifyResult.cmake"
+      )
+  endif()
+endfunction()
+function(run_cpack_source_test TEST_NAME types)
+  run_cpack_test_common_for_merge_("${TEST_NAME}" "${types}" false true)
+endfunction()
 
 function(run_cpack_test TEST_NAME types build)
   if(TEST_TYPE IN_LIST types)

+ 5 - 0
Tests/RunCMake/CPack/RPM/SOURCE_PACKAGE-ExpectedFiles.cmake

@@ -0,0 +1,5 @@
+set(whitespaces_ "[\t\n\r ]*")
+
+set(EXPECTED_FILES_COUNT "1")
+set(EXPECTED_FILE_1 "source_package*.src.rpm")
+set(EXPECTED_FILE_CONTENT_1 "^source_package-0.1.1.tar.gz${whitespaces_}source_package.spec$")

+ 63 - 0
Tests/RunCMake/CPack/RPM/SOURCE_PACKAGE-VerifyResult.cmake

@@ -0,0 +1,63 @@
+file(MAKE_DIRECTORY "${CMAKE_CURRENT_BINARY_DIR}/test_rpm")
+file(MAKE_DIRECTORY "${CMAKE_CURRENT_BINARY_DIR}/test_rpm/BUILD")
+file(MAKE_DIRECTORY "${CMAKE_CURRENT_BINARY_DIR}/test_rpm/BUILDROOT")
+file(MAKE_DIRECTORY "${CMAKE_CURRENT_BINARY_DIR}/test_rpm/RPMS")
+file(MAKE_DIRECTORY "${CMAKE_CURRENT_BINARY_DIR}/test_rpm/SOURCES")
+file(MAKE_DIRECTORY "${CMAKE_CURRENT_BINARY_DIR}/test_rpm/SPECS")
+file(MAKE_DIRECTORY "${CMAKE_CURRENT_BINARY_DIR}/test_rpm/SRPMS")
+
+# make sure that we are using the version of cmake and cpack that we are testing
+get_filename_component(cpack_path_ "${CMAKE_CPACK_COMMAND}" DIRECTORY)
+set(ENV{PATH} "${cpack_path_}:$ENV{PATH}")
+
+execute_process(COMMAND ${RPMBUILD_EXECUTABLE} --define "_topdir ${CMAKE_CURRENT_BINARY_DIR}/test_rpm" --rebuild ${FOUND_FILE_1}
+      RESULT_VARIABLE result_
+      ERROR_VARIABLE  error_
+      OUTPUT_QUIET
+  )
+
+set(output_error_message_
+    "\n${RPMBUILD_EXECUTABLE} error: '${error_}';\nresult: '${result_}';\n${output_error_message}")
+
+set(EXPECTED_FILE_CONTENT_ "^/foo${whitespaces_}/foo/test_prog$")
+
+file(GLOB_RECURSE FOUND_FILE_ RELATIVE "${CMAKE_CURRENT_BINARY_DIR}/test_rpm/RPMS" "${CMAKE_CURRENT_BINARY_DIR}/test_rpm/RPMS/*.rpm")
+list(APPEND foundFiles_ "${FOUND_FILE_}")
+list(LENGTH FOUND_FILE_ foundFilesCount_)
+
+if(foundFilesCount_ EQUAL 1)
+  unset(PACKAGE_CONTENT)
+  getPackageContent("${CMAKE_CURRENT_BINARY_DIR}/test_rpm/RPMS/${FOUND_FILE_}" "PACKAGE_CONTENT")
+
+  string(REGEX MATCH "${EXPECTED_FILE_CONTENT_}"
+      expected_content_list "${PACKAGE_CONTENT}")
+
+  if(NOT expected_content_list)
+    message(FATAL_ERROR
+      "Unexpected file content!\n"
+      " Content: '${PACKAGE_CONTENT}'\n\n"
+      " Expected: '${EXPECTED_FILE_CONTENT_}'"
+      "${output_error_message_}")
+  endif()
+else()
+  message(FATAL_ERROR
+    "Found more than one file!"
+    " Found files count '${foundFilesCount_}'."
+    " Files: '${FOUND_FILE_}'"
+    "${output_error_message_}")
+endif()
+
+# check that there were no extra files generated
+foreach(all_files_glob_ IN LISTS ALL_FILES_GLOB)
+  file(GLOB foundAll_ RELATIVE "${CMAKE_CURRENT_BINARY_DIR}/test_rpm/RPMS" "${all_files_glob_}")
+  list(APPEND allFoundFiles_ "${foundAll_}")
+endforeach()
+
+list(LENGTH foundFiles_ foundFilesCount_)
+list(LENGTH allFoundFiles_ allFoundFilesCount_)
+
+if(NOT foundFilesCount_ EQUAL allFoundFilesCount_)
+  message(FATAL_ERROR
+      "Found more files than expected! Found files: '${allFoundFiles_}'"
+      "${output_error_message_}")
+endif()

+ 1 - 0
Tests/RunCMake/CPack/RunCMakeTest.cmake

@@ -5,6 +5,7 @@ include("${RunCMake_SOURCE_DIR}/CPackTestHelpers.cmake")
 
 # args: TEST_NAME "GENERATORS" RUN_CMAKE_BUILD_STEP
 run_cpack_test(MINIMAL "RPM;DEB;TGZ" false)
+run_cpack_source_test(SOURCE_PACKAGE "RPM" true)
 run_cpack_test(PARTIALLY_RELOCATABLE_WARNING "RPM" false)
 run_cpack_test(DEB_EXTRA "DEB" false)
 run_cpack_test(DEPENDENCIES "RPM;DEB" true)

+ 9 - 0
Tests/RunCMake/CPack/SOURCE_PACKAGE.cmake

@@ -0,0 +1,9 @@
+file(WRITE "${CMAKE_CURRENT_BINARY_DIR}/main.cpp"
+    "int main() {return 0;}")
+add_executable(test_prog "${CMAKE_CURRENT_BINARY_DIR}/main.cpp")
+
+install(TARGETS test_prog DESTINATION foo COMPONENT applications)
+
+set(CPACK_RPM_FILE_NAME "RPM-DEFAULT")
+
+set(CPACK_PACKAGE_NAME "source_package")

+ 1 - 1
Tests/RunCMake/CPack/VerifyResult.cmake

@@ -8,7 +8,7 @@ file(READ "${bin_dir}/test_error.txt" error)
 file(READ "${config_file}" config_file_content)
 
 set(output_error_message
-    "\nCPack output: '${output}'\nCPack error: '${error}';\nconfig file: '${config_file_content}'")
+    "\nCPack output: '${output}'\nCPack error: '${error}';\nCPack result: '${PACKAGING_RESULT}';\nconfig file: '${config_file_content}'")
 
 # check that expected generated files exist and contain expected content
 include("${src_dir}/${GENERATOR_TYPE}/${RunCMake_TEST}-ExpectedFiles.cmake")