From 494bb8ada786be70f39807a574bea6a1ef98654d Mon Sep 17 00:00:00 2001 From: Eric NOULARD Date: Sun, 6 Feb 2011 21:23:10 +0100 Subject: [PATCH] CPackRPM honors all the different ways of packaging components RPM cannot easily 'merge' differents directory into a single RPM with shared prefix. So more flexibility has been added to generic CPackGenerator in order to let the specific generator chose the local installation directory for each component. --- Source/CPack/cmCPackArchiveGenerator.cxx | 2 - Source/CPack/cmCPackGenerator.cxx | 36 ++++- Source/CPack/cmCPackGenerator.h | 13 ++ Source/CPack/cmCPackRPMGenerator.cxx | 188 +++++++++++++++++++++-- Source/CPack/cmCPackRPMGenerator.h | 13 ++ 5 files changed, 229 insertions(+), 23 deletions(-) diff --git a/Source/CPack/cmCPackArchiveGenerator.cxx b/Source/CPack/cmCPackArchiveGenerator.cxx index 46be99b6f..febf205fc 100644 --- a/Source/CPack/cmCPackArchiveGenerator.cxx +++ b/Source/CPack/cmCPackArchiveGenerator.cxx @@ -226,8 +226,6 @@ int cmCPackArchiveGenerator::PackageFiles() cmCPackLogger(cmCPackLog::LOG_DEBUG, "Toplevel: " << toplevel << std::endl); - PrepareGroupingKind(); - if (SupportsComponentInstallation()) { // CASE 1 : COMPONENT ALL-IN-ONE package // If ALL GROUPS or ALL COMPONENTS in ONE package has been requested diff --git a/Source/CPack/cmCPackGenerator.cxx b/Source/CPack/cmCPackGenerator.cxx index feda52c06..69d9b8ceb 100644 --- a/Source/CPack/cmCPackGenerator.cxx +++ b/Source/CPack/cmCPackGenerator.cxx @@ -684,7 +684,14 @@ int cmCPackGenerator::InstallProjectViaInstallCMakeProjects( if (componentInstall) { tempInstallDirectory += "/"; - tempInstallDirectory += installComponent; + // Some CPack generators would rather chose + // the local installation directory suffix. + // Some (e.g. RPM) use + // one install directory for each component **GROUP** + // instead of the default + // one install directory for each component. + tempInstallDirectory += + GetComponentInstallDirNameSuffix(installComponent); } if (!setDestDir) @@ -873,6 +880,12 @@ int cmCPackGenerator::DoPackage() return 0; } + // Digest Component grouping specification + if ( !this->PrepareGroupingKind() ) + { + return 0; + } + if ( cmSystemTools::IsOn( this->GetOption("CPACK_REMOVE_TOPLEVEL_DIRECTORY")) ) { @@ -1251,11 +1264,11 @@ int cmCPackGenerator::PrepareGroupingKind() cmCPackLogger(cmCPackLog::LOG_VERBOSE, "[" << this->Name << "]" << " requested component grouping = "<< groupingType <Name << "]" << " requested component grouping type <"<< groupingType - << "> UNKNOWN not in (ALL_GROUP_IN_ONE," - "ALL_COMPONENT_IN_ONE,IGNORE)" < UNKNOWN not in (ALL_GROUPS_IN_ONE," + "ALL_COMPONENTS_IN_ONE,IGNORE)" <Name << "]" + << " requested component grouping = (" + << "ALL_GROUPS_IN_ONE=" << allGroupInOne + << ", ALL_COMPONENTS_IN_ONE=" << allComponentInOne + << ", IGNORE_GROUPS=" << ignoreComponentGroup + << ")" + << std::endl); // Some components were defined but NO group // force ignoreGroups if (this->ComponentGroups.empty() && (!this->Components.empty()) @@ -1288,6 +1309,11 @@ int cmCPackGenerator::PrepareGroupingKind() return 1; } +std::string cmCPackGenerator::GetComponentInstallDirNameSuffix( + const std::string& componentName) { + return componentName; +} + //---------------------------------------------------------------------- bool cmCPackGenerator::SupportsComponentInstallation() const { diff --git a/Source/CPack/cmCPackGenerator.h b/Source/CPack/cmCPackGenerator.h index f44a334ad..d4b1b16ef 100644 --- a/Source/CPack/cmCPackGenerator.h +++ b/Source/CPack/cmCPackGenerator.h @@ -131,6 +131,19 @@ protected: */ virtual int PrepareGroupingKind(); + /** + * Some CPack generators may prefer to have + * CPack install all components belonging to the same + * [component] group to be install in the same directory. + * The default behavior is to install each component in + * a separate directory. + * @param[in] componentName the name of the component to be installed + * @return the name suffix the generator wants for the specified component + * default is "componentName" + */ + virtual std::string GetComponentInstallDirNameSuffix( + const std::string& componentName); + /** * Package the list of files and/or components which * has been prepared by the beginning of DoPackage. diff --git a/Source/CPack/cmCPackRPMGenerator.cxx b/Source/CPack/cmCPackRPMGenerator.cxx index a5db78f40..a5a9753e2 100644 --- a/Source/CPack/cmCPackRPMGenerator.cxx +++ b/Source/CPack/cmCPackRPMGenerator.cxx @@ -35,26 +35,63 @@ int cmCPackRPMGenerator::InitializeInternal() } //---------------------------------------------------------------------- -int cmCPackRPMGenerator::PackageFiles() +int cmCPackRPMGenerator::PackageComponents(bool ignoreGroup) { int retval = 1; - /* Digest Component grouping specification */ - retval = PrepareGroupingKind(); - cmCPackLogger(cmCPackLog::LOG_DEBUG, "Toplevel: " - << toplevel << std::endl); + /* Reset package file name list it will be populated during the + * component packaging run*/ + packageFileNames.clear(); + std::string initialTopLevel(this->GetOption("CPACK_TEMPORARY_DIRECTORY")); - /* Are we in the component packaging case */ - if (SupportsComponentInstallation() & (!this->ComponentGroups.empty())) + // The default behavior is to have one package by component group + // unless CPACK_COMPONENTS_IGNORE_GROUP is specified. + if (!ignoreGroup) + { + std::map::iterator compGIt; + for (compGIt=this->ComponentGroups.begin(); + compGIt!=this->ComponentGroups.end(); ++compGIt) + { + cmCPackLogger(cmCPackLog::LOG_VERBOSE, "Packaging component group: " + << compGIt->first + << std::endl); + // Begin the archive for this group + std::string localToplevel(initialTopLevel); + std::string packageFileName( + cmSystemTools::GetParentDirectory(toplevel.c_str()) + ); + std::string outputFileName( + std::string(this->GetOption("CPACK_PACKAGE_FILE_NAME")) + +"-"+compGIt->first + this->GetOutputExtension() + ); + + localToplevel += "/"+ compGIt->first; + /* replace the TEMP DIRECTORY with the component one */ + this->SetOption("CPACK_TEMPORARY_DIRECTORY",localToplevel.c_str()); + packageFileName += "/"+ outputFileName; + /* replace proposed CPACK_OUTPUT_FILE_NAME */ + this->SetOption("CPACK_OUTPUT_FILE_NAME",outputFileName.c_str()); + /* replace the TEMPORARY package file name */ + this->SetOption("CPACK_TEMPORARY_PACKAGE_FILE_NAME", + packageFileName.c_str()); + // Tell CPackRPM.cmake the name of the component GROUP. + this->SetOption("CPACK_RPM_PACKAGE_COMPONENT",compGIt->first.c_str()); + if (!this->ReadListFile("CPackRPM.cmake")) + { + cmCPackLogger(cmCPackLog::LOG_ERROR, + "Error while execution CPackRPM.cmake" << std::endl); + retval = 0; + } + // add the generated package to package file names list + packageFileNames.push_back(packageFileName); + } + } + // CPACK_COMPONENTS_IGNORE_GROUPS is set + // We build 1 package per component + else { - /* Reset package file name list it will be populated during the - * component packaging run*/ - packageFileNames.clear(); - std::string initialTopLevel(this->GetOption("CPACK_TEMPORARY_DIRECTORY")); - /* One Package per component CASE */ - /* Iterate over components */ std::map::iterator compIt; for (compIt=this->Components.begin(); - compIt!=this->Components.end(); ++compIt ) + compIt!=this->Components.end(); ++compIt ) { std::string localToplevel(initialTopLevel); std::string packageFileName( @@ -82,12 +119,101 @@ int cmCPackRPMGenerator::PackageFiles() "Error while execution CPackRPM.cmake" << std::endl); retval = 0; } - // add the generated package to package file names list packageFileNames.push_back(packageFileName); } } - /* This is the non component case */ + return retval; +} + +//---------------------------------------------------------------------- +int cmCPackRPMGenerator::PackageComponentsAllInOne(bool allComponent) +{ + int retval = 1; + std::string compInstDirName; + /* Reset package file name list it will be populated during the + * component packaging run*/ + packageFileNames.clear(); + std::string initialTopLevel(this->GetOption("CPACK_TEMPORARY_DIRECTORY")); + + // all GROUP in one vs all COMPONENT in one + if (allComponent) + { + compInstDirName = "ALL_COMPONENTS_IN_ONE"; + } + else + { + compInstDirName = "ALL_GROUPS_IN_ONE"; + } + + cmCPackLogger(cmCPackLog::LOG_VERBOSE, + "Packaging all groups in one package..." + "(CPACK_COMPONENTS_ALL_[GROUPS_]IN_ONE_PACKAGE is set)" + << std::endl); + + // The ALL GROUPS in ONE package case + std::string localToplevel(initialTopLevel); + std::string packageFileName( + cmSystemTools::GetParentDirectory(toplevel.c_str()) + ); + std::string outputFileName( + std::string(this->GetOption("CPACK_PACKAGE_FILE_NAME")) + +"-ALL"+ this->GetOutputExtension() + ); + // all GROUP in one vs all COMPONENT in one + localToplevel += "/"+compInstDirName; + + /* replace the TEMP DIRECTORY with the component one */ + this->SetOption("CPACK_TEMPORARY_DIRECTORY",localToplevel.c_str()); + packageFileName += "/"+ outputFileName; + /* replace proposed CPACK_OUTPUT_FILE_NAME */ + this->SetOption("CPACK_OUTPUT_FILE_NAME",outputFileName.c_str()); + /* replace the TEMPORARY package file name */ + this->SetOption("CPACK_TEMPORARY_PACKAGE_FILE_NAME", + packageFileName.c_str()); + // Tell CPackRPM.cmake the name of the component GROUP. + this->SetOption("CPACK_RPM_PACKAGE_COMPONENT",compInstDirName.c_str()); + if (!this->ReadListFile("CPackRPM.cmake")) + { + cmCPackLogger(cmCPackLog::LOG_ERROR, + "Error while execution CPackRPM.cmake" << std::endl); + retval = 0; + } + // add the generated package to package file names list + packageFileNames.push_back(packageFileName); + + return 1; +} + +//---------------------------------------------------------------------- +int cmCPackRPMGenerator::PackageFiles() +{ + int retval = 1; + + cmCPackLogger(cmCPackLog::LOG_DEBUG, "Toplevel: " + << toplevel << std::endl); + + /* Are we in the component packaging case */ + if (SupportsComponentInstallation()) { + // CASE 1 : COMPONENT ALL-IN-ONE package + // If ALL GROUPS or ALL COMPONENTS in ONE package has been requested + // then the package file is unique and should be open here. + if (allComponentInOne || + (allGroupInOne && (!this->ComponentGroups.empty())) + ) + { + return PackageComponentsAllInOne(allComponentInOne); + } + // CASE 2 : COMPONENT CLASSICAL package(s) (i.e. not all-in-one) + // There will be 1 package for each component group + // however one may require to ignore component group and + // in this case you'll get 1 package for each component. + else if ((!this->ComponentGroups.empty()) || (ignoreComponentGroup)) + { + return PackageComponents(ignoreComponentGroup); + } + } + // CASE 3 : NON COMPONENT package. else { if (!this->ReadListFile("CPackRPM.cmake")) @@ -118,3 +244,33 @@ bool cmCPackRPMGenerator::SupportsComponentInstallation() const } } +std::string cmCPackRPMGenerator::GetComponentInstallDirNameSuffix( + const std::string& componentName) + { + if (ignoreComponentGroup) { + return componentName; + } + + if (allComponentInOne) { + return std::string("ALL_COMPONENTS_IN_ONE"); + } + // We have to find the name of the COMPONENT GROUP + // the current COMPONENT belongs to. + std::string groupVar = "CPACK_COMPONENT_" + + cmSystemTools::UpperCase(componentName) + "_GROUP"; + if (NULL != GetOption(groupVar.c_str())) + { + if (allGroupInOne) + { + return std::string("ALL_GROUPS_IN_ONE"); + } + else + { + return std::string(GetOption(groupVar.c_str())); + } + } + else + { + return componentName; + } + } diff --git a/Source/CPack/cmCPackRPMGenerator.h b/Source/CPack/cmCPackRPMGenerator.h index 57d5cca70..7c2e434da 100644 --- a/Source/CPack/cmCPackRPMGenerator.h +++ b/Source/CPack/cmCPackRPMGenerator.h @@ -38,8 +38,21 @@ public: protected: virtual int InitializeInternal(); virtual int PackageFiles(); + /** + * The method used to package files when component + * install is used. This will create one + * archive for each component group. + */ + int PackageComponents(bool ignoreGroup); + /** + * Special case of component install where all + * components will be put in a single installer. + */ + int PackageComponentsAllInOne(bool allComponent); virtual const char* GetOutputExtension() { return ".rpm"; } virtual bool SupportsComponentInstallation() const; + virtual std::string GetComponentInstallDirNameSuffix( + const std::string& componentName); };