CPack/RPM different package names

Packagers may now set their own rpm package
file names or request that rpmbuild tool
chooses one for them. It also supports handing
of situations where one spec file may produce
multiple rpm packages.
This commit is contained in:
Domen Vrankar 2016-05-15 03:01:34 +02:00
parent b952336902
commit 44ee2d717a
9 changed files with 143 additions and 35 deletions

View File

@ -0,0 +1,9 @@
cpack-rpm-different-package-names
---------------------------------
* The :module:`CPackRPM` module learned how to set user defined package file
names, how to specify that rpmbuild should decide on file name format as
well as handling of multiple rpm packages generated by a single user defined
spec file.
See :variable:`CPACK_RPM_PACKAGE_NAME` and
:variable:`CPACK_RPM_<component>_PACKAGE_NAME`.

View File

@ -54,6 +54,30 @@
# * Mandatory : YES # * Mandatory : YES
# * Default : CPACK_PACKAGE_NAME # * Default : CPACK_PACKAGE_NAME
# #
# .. variable:: CPACK_RPM_FILE_NAME
# CPACK_RPM_<component>_FILE_NAME
#
# Package file name.
#
# * Mandatory : YES
# * Default : ``<CPACK_PACKAGE_FILE_NAME>[-<component>].rpm`` with spaces
# replaced by '-'
#
# This may be set to ``RPM-DEFAULT`` to allow rpmbuild tool to generate package
# file name by itself.
# Alternatively provided package file name must end with ".rpm" suffix.
#
# .. note::
#
# By using user provided spec file, rpm macro extensions such as for
# generating debuginfo packages or by simply using multiple components more
# than one rpm file may be generated, either from a single spec file or from
# multiple spec files (each component execution produces it's own spec file).
# In such cases duplicate file names may occur as a result of this variable
# setting or spec file content structure. Duplicate files get overwritten
# and it is up to the packager to set the variables in a manner that will
# prevent such errors.
#
# .. variable:: CPACK_RPM_PACKAGE_VERSION # .. variable:: CPACK_RPM_PACKAGE_VERSION
# #
# The RPM package version. # The RPM package version.
@ -1534,8 +1558,6 @@ function(cpack_rpm_generate_package)
file(MAKE_DIRECTORY ${CPACK_RPM_ROOTDIR}/SPECS) file(MAKE_DIRECTORY ${CPACK_RPM_ROOTDIR}/SPECS)
file(MAKE_DIRECTORY ${CPACK_RPM_ROOTDIR}/SRPMS) file(MAKE_DIRECTORY ${CPACK_RPM_ROOTDIR}/SRPMS)
#set(CPACK_RPM_FILE_NAME "${CPACK_RPM_PACKAGE_NAME}-${CPACK_RPM_PACKAGE_VERSION}-${CPACK_RPM_PACKAGE_RELEASE}-${CPACK_RPM_PACKAGE_ARCHITECTURE}.rpm")
set(CPACK_RPM_FILE_NAME "${CPACK_OUTPUT_FILE_NAME}")
# it seems rpmbuild can't handle spaces in the path # it seems rpmbuild can't handle spaces in the path
# neither escaping (as below) nor putting quotes around the path seem to help # neither escaping (as below) nor putting quotes around the path seem to help
#string(REGEX REPLACE " " "\\\\ " CPACK_RPM_DIRECTORY "${CPACK_TOPLEVEL_DIRECTORY}") #string(REGEX REPLACE " " "\\\\ " CPACK_RPM_DIRECTORY "${CPACK_TOPLEVEL_DIRECTORY}")
@ -1716,6 +1738,28 @@ function(cpack_rpm_generate_package)
"CPACK_RPM_${CPACK_RPM_PACKAGE_COMPONENT_UPPER}_USER_BINARY_SPECFILE") "CPACK_RPM_${CPACK_RPM_PACKAGE_COMPONENT_UPPER}_USER_BINARY_SPECFILE")
endif() endif()
cpack_rpm_variable_fallback("CPACK_RPM_FILE_NAME"
"CPACK_RPM_${CPACK_RPM_PACKAGE_COMPONENT_UPPER}_FILE_NAME"
"CPACK_RPM_FILE_NAME")
if(NOT CPACK_RPM_FILE_NAME STREQUAL "RPM-DEFAULT")
if(CPACK_RPM_FILE_NAME)
cmake_policy(PUSH)
cmake_policy(SET CMP0010 NEW)
if(NOT CPACK_RPM_FILE_NAME MATCHES ".*\\.rpm")
cmake_policy(POP)
message(FATAL_ERROR "'${CPACK_RPM_FILE_NAME}' is not a valid RPM package file name as it must end with '.rpm'!")
endif()
cmake_policy(POP)
else()
# old file name format for back compatibility
set(CPACK_RPM_FILE_NAME "${CPACK_OUTPUT_FILE_NAME}")
endif()
# else example:
#set(CPACK_RPM_FILE_NAME "${CPACK_RPM_PACKAGE_NAME}-${CPACK_RPM_PACKAGE_VERSION}-${CPACK_RPM_PACKAGE_RELEASE}-${CPACK_RPM_PACKAGE_ARCHITECTURE}.rpm")
set(FILE_NAME_DEFINE "%define _rpmfilename ${CPACK_RPM_FILE_NAME}")
endif()
# We should generate a USER spec file template: # We should generate a USER spec file template:
# - either because the user asked for it : CPACK_RPM_GENERATE_USER_BINARY_SPECFILE_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 # - or the user did not provide one : NOT CPACK_RPM_USER_BINARY_SPECFILE
@ -1746,7 +1790,7 @@ Vendor: \@CPACK_RPM_PACKAGE_VENDOR\@
\@TMP_RPM_PREFIXES\@ \@TMP_RPM_PREFIXES\@
%define _rpmdir \@CPACK_RPM_DIRECTORY\@ %define _rpmdir \@CPACK_RPM_DIRECTORY\@
%define _rpmfilename \@CPACK_RPM_FILE_NAME\@ \@FILE_NAME_DEFINE\@
%define _unpackaged_files_terminate_build 0 %define _unpackaged_files_terminate_build 0
%define _topdir \@CPACK_RPM_DIRECTORY\@ %define _topdir \@CPACK_RPM_DIRECTORY\@
\@TMP_RPM_SPEC_INSTALL_POST\@ \@TMP_RPM_SPEC_INSTALL_POST\@
@ -1844,6 +1888,24 @@ mv \"\@CPACK_TOPLEVEL_DIRECTORY\@/tmpBBroot\" $RPM_BUILD_ROOT
message(FATAL_ERROR "RPM packaging through alien not done (yet)") message(FATAL_ERROR "RPM packaging through alien not done (yet)")
endif() endif()
endif() endif()
# find generated rpm files and take their names
cmake_policy(PUSH)
# 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")
cmake_policy(POP)
if(NOT GENERATED_FILES)
message(FATAL_ERROR "RPM package was not generated! ${CPACK_RPM_DIRECTORY}")
endif()
set(GEN_CPACK_OUTPUT_FILES "${GENERATED_FILES}" PARENT_SCOPE)
if(CPACK_RPM_PACKAGE_DEBUG)
message("CPackRPM:Debug: GEN_CPACK_OUTPUT_FILES = ${GENERATED_FILES}")
endif()
endfunction() endfunction()
cpack_rpm_generate_package() cpack_rpm_generate_package()

View File

@ -47,6 +47,22 @@ int cmCPackRPMGenerator::InitializeInternal()
return this->Superclass::InitializeInternal(); return this->Superclass::InitializeInternal();
} }
void cmCPackRPMGenerator::AddGeneratedPackageNames()
{
// add the generated packages to package file names list
std::string fileNames(this->GetOption("GEN_CPACK_OUTPUT_FILES"));
const char sep = ';';
std::string::size_type pos1 = 0;
std::string::size_type pos2 = fileNames.find(sep, pos1+1);
while(pos2 != std::string::npos)
{
packageFileNames.push_back(fileNames.substr(pos1, pos2-pos1));
pos1 = pos2+1;
pos2 = fileNames.find(sep, pos1+1);
}
packageFileNames.push_back(fileNames.substr(pos1, pos2-pos1));
}
int cmCPackRPMGenerator::PackageOnePack(std::string initialToplevel, int cmCPackRPMGenerator::PackageOnePack(std::string initialToplevel,
std::string packageName) std::string packageName)
{ {
@ -85,8 +101,7 @@ int cmCPackRPMGenerator::PackageOnePack(std::string initialToplevel,
"Error while execution CPackRPM.cmake" << std::endl); "Error while execution CPackRPM.cmake" << std::endl);
retval = 0; retval = 0;
} }
// add the generated package to package file names list
packageFileNames.push_back(packageFileName);
return retval; return retval;
} }
@ -139,20 +154,24 @@ int cmCPackRPMGenerator::PackageComponents(bool ignoreGroup)
retval &= PackageOnePack(initialTopLevel,compIt->first); retval &= PackageOnePack(initialTopLevel,compIt->first);
} }
} }
if(retval)
{
AddGeneratedPackageNames();
}
return retval; return retval;
} }
int cmCPackRPMGenerator::PackageComponentsAllInOne() int cmCPackRPMGenerator::PackageComponentsAllInOne(
const std::string& compInstDirName)
{ {
int retval = 1; int retval = 1;
std::string compInstDirName;
/* Reset package file name list it will be populated during the /* Reset package file name list it will be populated during the
* component packaging run*/ * component packaging run*/
packageFileNames.clear(); packageFileNames.clear();
std::string initialTopLevel(this->GetOption("CPACK_TEMPORARY_DIRECTORY")); std::string initialTopLevel(this->GetOption("CPACK_TEMPORARY_DIRECTORY"));
compInstDirName = "ALL_COMPONENTS_IN_ONE";
cmCPackLogger(cmCPackLog::LOG_VERBOSE, cmCPackLogger(cmCPackLog::LOG_VERBOSE,
"Packaging all groups in one package..." "Packaging all groups in one package..."
"(CPACK_COMPONENTS_ALL_[GROUPS_]IN_ONE_PACKAGE is set)" "(CPACK_COMPONENTS_ALL_[GROUPS_]IN_ONE_PACKAGE is set)"
@ -178,27 +197,32 @@ int cmCPackRPMGenerator::PackageComponentsAllInOne()
/* replace the TEMPORARY package file name */ /* replace the TEMPORARY package file name */
this->SetOption("CPACK_TEMPORARY_PACKAGE_FILE_NAME", this->SetOption("CPACK_TEMPORARY_PACKAGE_FILE_NAME",
packageFileName.c_str()); packageFileName.c_str());
// Tell CPackRPM.cmake the path where the component is.
std::string component_path = "/"; if(!compInstDirName.empty())
component_path += compInstDirName; {
this->SetOption("CPACK_RPM_PACKAGE_COMPONENT_PART_PATH", // Tell CPackRPM.cmake the path where the component is.
component_path.c_str()); std::string component_path = "/";
if (!this->ReadListFile("CPackRPM.cmake")) component_path += compInstDirName;
this->SetOption("CPACK_RPM_PACKAGE_COMPONENT_PART_PATH",
component_path.c_str());
}
if (this->ReadListFile("CPackRPM.cmake"))
{
AddGeneratedPackageNames();
}
else
{ {
cmCPackLogger(cmCPackLog::LOG_ERROR, cmCPackLogger(cmCPackLog::LOG_ERROR,
"Error while execution CPackRPM.cmake" << std::endl); "Error while execution CPackRPM.cmake" << std::endl);
retval = 0; retval = 0;
} }
// add the generated package to package file names list
packageFileNames.push_back(packageFileName);
return retval; return retval;
} }
int cmCPackRPMGenerator::PackageFiles() int cmCPackRPMGenerator::PackageFiles()
{ {
int retval = 1;
cmCPackLogger(cmCPackLog::LOG_DEBUG, "Toplevel: " cmCPackLogger(cmCPackLog::LOG_DEBUG, "Toplevel: "
<< toplevel << std::endl); << toplevel << std::endl);
@ -209,7 +233,7 @@ int cmCPackRPMGenerator::PackageFiles()
// then the package file is unique and should be open here. // then the package file is unique and should be open here.
if (componentPackageMethod == ONE_PACKAGE) if (componentPackageMethod == ONE_PACKAGE)
{ {
return PackageComponentsAllInOne(); return PackageComponentsAllInOne("ALL_COMPONENTS_IN_ONE");
} }
// CASE 2 : COMPONENT CLASSICAL package(s) (i.e. not all-in-one) // CASE 2 : COMPONENT CLASSICAL package(s) (i.e. not all-in-one)
// There will be 1 package for each component group // There will be 1 package for each component group
@ -224,20 +248,8 @@ int cmCPackRPMGenerator::PackageFiles()
// CASE 3 : NON COMPONENT package. // CASE 3 : NON COMPONENT package.
else else
{ {
if (!this->ReadListFile("CPackRPM.cmake")) return PackageComponentsAllInOne("");
{
cmCPackLogger(cmCPackLog::LOG_ERROR,
"Error while execution CPackRPM.cmake" << std::endl);
retval = 0;
}
} }
if (!this->IsSet("RPMBUILD_EXECUTABLE"))
{
cmCPackLogger(cmCPackLog::LOG_ERROR, "Cannot find rpmbuild" << std::endl);
retval = 0;
}
return retval;
} }
bool cmCPackRPMGenerator::SupportsComponentInstallation() const bool cmCPackRPMGenerator::SupportsComponentInstallation() const

View File

@ -65,12 +65,13 @@ protected:
* Special case of component install where all * Special case of component install where all
* components will be put in a single installer. * components will be put in a single installer.
*/ */
int PackageComponentsAllInOne(); int PackageComponentsAllInOne(const std::string& compInstDirName);
virtual const char* GetOutputExtension() { return ".rpm"; } virtual const char* GetOutputExtension() { return ".rpm"; }
virtual bool SupportsComponentInstallation() const; virtual bool SupportsComponentInstallation() const;
virtual std::string GetComponentInstallDirNameSuffix( virtual std::string GetComponentInstallDirNameSuffix(
const std::string& componentName); const std::string& componentName);
void AddGeneratedPackageNames();
}; };
#endif #endif

View File

@ -118,7 +118,7 @@ if(expected_file_mask)
message(STATUS "expected_file_mask='${expected_file_mask}'") message(STATUS "expected_file_mask='${expected_file_mask}'")
if(NOT expected_file) if(NOT expected_file)
message(FATAL_ERROR "error: expected_file=${expected_file} does not exist: CPackComponentsForAll test fails. (CPack_output=${CPack_output}, CPack_error=${CPack_error}") message(FATAL_ERROR "error: expected_file does not exist: CPackComponentsForAll test fails. (CPack_output=${CPack_output}, CPack_error=${CPack_error}")
endif() endif()
list(LENGTH expected_file actual_count) list(LENGTH expected_file actual_count)

View File

@ -0,0 +1,9 @@
set(whitespaces_ "[\t\n\r ]*")
set(EXPECTED_FILES_COUNT "3")
set(EXPECTED_FILE_1 "custom_names-pkg_1*.rpm")
set(EXPECTED_FILE_CONTENT_1 "^/usr/foo${whitespaces_}/usr/foo/CMakeLists.txt$")
set(EXPECTED_FILE_2 "second*.rpm")
set(EXPECTED_FILE_CONTENT_2 "^/usr/foo${whitespaces_}/usr/foo/CMakeLists.txt$")
set(EXPECTED_FILE_3 "pkg_3_abc.rpm")
set(EXPECTED_FILE_CONTENT_3 "^/usr/foo${whitespaces_}/usr/foo/CMakeLists.txt$")

View File

@ -0,0 +1,3 @@
^CPackRPM: Will use GENERATED spec file: .*/Tests/RunCMake/RPM/CPack/RPM_CUSTOM_NAMES-build/_CPack_Packages/.*/RPM/SPECS/custom_names-pkg_1.spec
CPackRPM: Will use GENERATED spec file: .*/Tests/RunCMake/RPM/CPack/RPM_CUSTOM_NAMES-build/_CPack_Packages/.*/RPM/SPECS/second.spec
CPackRPM: Will use GENERATED spec file: .*/Tests/RunCMake/RPM/CPack/RPM_CUSTOM_NAMES-build/_CPack_Packages/.*/RPM/SPECS/custom_names-pkg_3.spec$

View File

@ -0,0 +1,11 @@
set(CPACK_RPM_COMPONENT_INSTALL "ON")
set(CPACK_RPM_FILE_NAME "RPM-DEFAULT")
set(CPACK_RPM_PKG_2_PACKAGE_NAME "second")
set(CPACK_RPM_PKG_3_FILE_NAME "pkg_3_abc.rpm")
install(FILES CMakeLists.txt DESTINATION foo COMPONENT pkg_1)
install(FILES CMakeLists.txt DESTINATION foo COMPONENT pkg_2)
install(FILES CMakeLists.txt DESTINATION foo COMPONENT pkg_3)
set(CPACK_PACKAGE_NAME "custom_names")

View File

@ -10,5 +10,6 @@ run_cpack_test(DEB_EXTRA "DEB" false)
run_cpack_test(DEPENDENCIES "RPM;DEB" true) run_cpack_test(DEPENDENCIES "RPM;DEB" true)
run_cpack_test(EMPTY_DIR "RPM;DEB;TGZ" true) run_cpack_test(EMPTY_DIR "RPM;DEB;TGZ" true)
run_cpack_test(COMPONENTS_EMPTY_DIR "RPM;DEB;TGZ" true) run_cpack_test(COMPONENTS_EMPTY_DIR "RPM;DEB;TGZ" true)
run_cpack_test(RPM_CUSTOM_NAMES "RPM" true)
run_cpack_test(PER_COMPONENT_FIELDS "RPM;DEB" false) run_cpack_test(PER_COMPONENT_FIELDS "RPM;DEB" false)
run_cpack_test(INSTALL_SCRIPTS "RPM" false) run_cpack_test(INSTALL_SCRIPTS "RPM" false)