diff options
Diffstat (limited to 'Source/CPack/cmCPackGenerator.cxx')
-rw-r--r-- | Source/CPack/cmCPackGenerator.cxx | 1551 |
1 files changed, 1551 insertions, 0 deletions
diff --git a/Source/CPack/cmCPackGenerator.cxx b/Source/CPack/cmCPackGenerator.cxx new file mode 100644 index 0000000..127bcf9 --- /dev/null +++ b/Source/CPack/cmCPackGenerator.cxx @@ -0,0 +1,1551 @@ +/* Distributed under the OSI-approved BSD 3-Clause License. See accompanying + file Copyright.txt or https://cmake.org/licensing for details. */ +#include "cmCPackGenerator.h" + +#include "cmsys/FStream.hxx" +#include "cmsys/Glob.hxx" +#include "cmsys/RegularExpression.hxx" +#include <algorithm> +#include <cstring> +#include <memory> // IWYU pragma: keep +#include <utility> + +#include "cmCPackComponentGroup.h" +#include "cmCPackLog.h" +#include "cmCryptoHash.h" +#include "cmDuration.h" +#include "cmFSPermissions.h" +#include "cmGeneratedFileStream.h" +#include "cmGlobalGenerator.h" +#include "cmMakefile.h" +#include "cmState.h" +#include "cmStateSnapshot.h" +#include "cmVersion.h" +#include "cmWorkingDirectory.h" +#include "cmXMLSafe.h" +#include "cmake.h" + +#if defined(__HAIKU__) +# include <FindDirectory.h> +# include <StorageDefs.h> +#endif + +cmCPackGenerator::cmCPackGenerator() +{ + this->GeneratorVerbose = cmSystemTools::OUTPUT_NONE; + this->MakefileMap = nullptr; + this->Logger = nullptr; + this->componentPackageMethod = ONE_PACKAGE_PER_GROUP; +} + +cmCPackGenerator::~cmCPackGenerator() +{ + this->MakefileMap = nullptr; +} + +void cmCPackGenerator::DisplayVerboseOutput(const std::string& msg, + float progress) +{ + (void)progress; + cmCPackLogger(cmCPackLog::LOG_VERBOSE, "" << msg << std::endl); +} + +int cmCPackGenerator::PrepareNames() +{ + cmCPackLogger(cmCPackLog::LOG_DEBUG, "Create temp directory." << std::endl); + + // checks CPACK_SET_DESTDIR support + if (IsOn("CPACK_SET_DESTDIR")) { + if (SETDESTDIR_UNSUPPORTED == SupportsSetDestdir()) { + cmCPackLogger(cmCPackLog::LOG_ERROR, + "CPACK_SET_DESTDIR is set to ON but the '" + << Name << "' generator does NOT support it." + << std::endl); + return 0; + } + if (SETDESTDIR_SHOULD_NOT_BE_USED == SupportsSetDestdir()) { + cmCPackLogger(cmCPackLog::LOG_WARNING, + "CPACK_SET_DESTDIR is set to ON but it is " + << "usually a bad idea to do that with '" << Name + << "' generator. Use at your own risk." << std::endl); + } + } + + std::string tempDirectory = this->GetOption("CPACK_PACKAGE_DIRECTORY"); + tempDirectory += "/_CPack_Packages/"; + const char* toplevelTag = this->GetOption("CPACK_TOPLEVEL_TAG"); + if (toplevelTag) { + tempDirectory += toplevelTag; + tempDirectory += "/"; + } + tempDirectory += this->GetOption("CPACK_GENERATOR"); + std::string topDirectory = tempDirectory; + const char* pfname = this->GetOption("CPACK_PACKAGE_FILE_NAME"); + if (!pfname) { + cmCPackLogger(cmCPackLog::LOG_ERROR, + "CPACK_PACKAGE_FILE_NAME not specified" << std::endl); + return 0; + } + std::string outName = pfname; + tempDirectory += "/" + outName; + if (!this->GetOutputExtension()) { + cmCPackLogger(cmCPackLog::LOG_ERROR, + "No output extension specified" << std::endl); + return 0; + } + outName += this->GetOutputExtension(); + const char* pdir = this->GetOption("CPACK_PACKAGE_DIRECTORY"); + if (!pdir) { + cmCPackLogger(cmCPackLog::LOG_ERROR, + "CPACK_PACKAGE_DIRECTORY not specified" << std::endl); + return 0; + } + + std::string destFile = pdir; + this->SetOptionIfNotSet("CPACK_OUTPUT_FILE_PREFIX", destFile.c_str()); + destFile += "/" + outName; + std::string outFile = topDirectory + "/" + outName; + this->SetOptionIfNotSet("CPACK_TOPLEVEL_DIRECTORY", topDirectory.c_str()); + this->SetOptionIfNotSet("CPACK_TEMPORARY_DIRECTORY", tempDirectory.c_str()); + this->SetOptionIfNotSet("CPACK_OUTPUT_FILE_NAME", outName.c_str()); + this->SetOptionIfNotSet("CPACK_OUTPUT_FILE_PATH", destFile.c_str()); + this->SetOptionIfNotSet("CPACK_TEMPORARY_PACKAGE_FILE_NAME", + outFile.c_str()); + this->SetOptionIfNotSet("CPACK_INSTALL_DIRECTORY", this->GetInstallPath()); + this->SetOptionIfNotSet( + "CPACK_NATIVE_INSTALL_DIRECTORY", + cmsys::SystemTools::ConvertToOutputPath(this->GetInstallPath()).c_str()); + this->SetOptionIfNotSet("CPACK_TEMPORARY_INSTALL_DIRECTORY", + tempDirectory.c_str()); + + cmCPackLogger(cmCPackLog::LOG_DEBUG, + "Look for: CPACK_PACKAGE_DESCRIPTION_FILE" << std::endl); + const char* descFileName = this->GetOption("CPACK_PACKAGE_DESCRIPTION_FILE"); + if (descFileName) { + cmCPackLogger(cmCPackLog::LOG_DEBUG, + "Look for: " << descFileName << std::endl); + if (!cmSystemTools::FileExists(descFileName)) { + cmCPackLogger(cmCPackLog::LOG_ERROR, + "Cannot find description file name: [" + << descFileName << "]" << std::endl); + return 0; + } + cmsys::ifstream ifs(descFileName); + if (!ifs) { + cmCPackLogger(cmCPackLog::LOG_ERROR, + "Cannot open description file name: " << descFileName + << std::endl); + return 0; + } + std::ostringstream ostr; + std::string line; + + cmCPackLogger(cmCPackLog::LOG_VERBOSE, + "Read description file: " << descFileName << std::endl); + while (ifs && cmSystemTools::GetLineFromStream(ifs, line)) { + ostr << cmXMLSafe(line) << std::endl; + } + this->SetOptionIfNotSet("CPACK_PACKAGE_DESCRIPTION", ostr.str().c_str()); + } + if (!this->GetOption("CPACK_PACKAGE_DESCRIPTION")) { + cmCPackLogger( + cmCPackLog::LOG_ERROR, + "Project description not specified. Please specify " + "CPACK_PACKAGE_DESCRIPTION or CPACK_PACKAGE_DESCRIPTION_FILE." + << std::endl); + return 0; + } + const char* algoSignature = this->GetOption("CPACK_PACKAGE_CHECKSUM"); + if (algoSignature) { + if (!cmCryptoHash::New(algoSignature)) { + cmCPackLogger(cmCPackLog::LOG_ERROR, + "Cannot recognize algorithm: " << algoSignature + << std::endl); + return 0; + } + } + + this->SetOptionIfNotSet("CPACK_REMOVE_TOPLEVEL_DIRECTORY", "1"); + + return 1; +} + +int cmCPackGenerator::InstallProject() +{ + cmCPackLogger(cmCPackLog::LOG_OUTPUT, "Install projects" << std::endl); + this->CleanTemporaryDirectory(); + + std::string bareTempInstallDirectory = + this->GetOption("CPACK_TEMPORARY_INSTALL_DIRECTORY"); + std::string tempInstallDirectoryStr = bareTempInstallDirectory; + bool setDestDir = cmSystemTools::IsOn(this->GetOption("CPACK_SET_DESTDIR")) | + cmSystemTools::IsInternallyOn(this->GetOption("CPACK_SET_DESTDIR")); + if (!setDestDir) { + tempInstallDirectoryStr += this->GetPackagingInstallPrefix(); + } + + const char* tempInstallDirectory = tempInstallDirectoryStr.c_str(); + int res = 1; + if (!cmsys::SystemTools::MakeDirectory(bareTempInstallDirectory)) { + cmCPackLogger(cmCPackLog::LOG_ERROR, + "Problem creating temporary directory: " + << (tempInstallDirectory ? tempInstallDirectory : "(NULL)") + << std::endl); + return 0; + } + + if (setDestDir) { + std::string destDir = "DESTDIR="; + destDir += tempInstallDirectory; + cmSystemTools::PutEnv(destDir); + } else { + // Make sure there is no destdir + cmSystemTools::PutEnv("DESTDIR="); + } + + // prepare default created directory permissions + mode_t default_dir_mode_v = 0; + mode_t* default_dir_mode = nullptr; + const char* default_dir_install_permissions = + this->GetOption("CPACK_INSTALL_DEFAULT_DIRECTORY_PERMISSIONS"); + if (default_dir_install_permissions && *default_dir_install_permissions) { + std::vector<std::string> items; + cmSystemTools::ExpandListArgument(default_dir_install_permissions, items); + for (const auto& arg : items) { + if (!cmFSPermissions::stringToModeT(arg, default_dir_mode_v)) { + cmCPackLogger(cmCPackLog::LOG_ERROR, + "Invalid permission value '" + << arg + << "'." + " CPACK_INSTALL_DEFAULT_DIRECTORY_PERMISSIONS " + "value is invalid." + << std::endl); + return 0; + } + } + + default_dir_mode = &default_dir_mode_v; + } + + // If the CPackConfig file sets CPACK_INSTALL_COMMANDS then run them + // as listed + if (!this->InstallProjectViaInstallCommands(setDestDir, + tempInstallDirectory)) { + return 0; + } + + // If the CPackConfig file sets CPACK_INSTALL_SCRIPT then run them + // as listed + if (!this->InstallProjectViaInstallScript(setDestDir, + tempInstallDirectory)) { + return 0; + } + + // If the CPackConfig file sets CPACK_INSTALLED_DIRECTORIES + // then glob it and copy it to CPACK_TEMPORARY_DIRECTORY + // This is used in Source packaging + if (!this->InstallProjectViaInstalledDirectories( + setDestDir, tempInstallDirectory, default_dir_mode)) { + return 0; + } + + // If the project is a CMAKE project then run pre-install + // and then read the cmake_install script to run it + if (!this->InstallProjectViaInstallCMakeProjects( + setDestDir, bareTempInstallDirectory, default_dir_mode)) { + return 0; + } + + if (setDestDir) { + cmSystemTools::PutEnv("DESTDIR="); + } + + return res; +} + +int cmCPackGenerator::InstallProjectViaInstallCommands( + bool setDestDir, const std::string& tempInstallDirectory) +{ + (void)setDestDir; + const char* installCommands = this->GetOption("CPACK_INSTALL_COMMANDS"); + if (installCommands && *installCommands) { + std::string tempInstallDirectoryEnv = "CMAKE_INSTALL_PREFIX="; + tempInstallDirectoryEnv += tempInstallDirectory; + cmSystemTools::PutEnv(tempInstallDirectoryEnv); + std::vector<std::string> installCommandsVector; + cmSystemTools::ExpandListArgument(installCommands, installCommandsVector); + for (std::string const& ic : installCommandsVector) { + cmCPackLogger(cmCPackLog::LOG_VERBOSE, "Execute: " << ic << std::endl); + std::string output; + int retVal = 1; + bool resB = cmSystemTools::RunSingleCommand( + ic, &output, &output, &retVal, nullptr, this->GeneratorVerbose, + cmDuration::zero()); + if (!resB || retVal) { + std::string tmpFile = this->GetOption("CPACK_TOPLEVEL_DIRECTORY"); + tmpFile += "/InstallOutput.log"; + cmGeneratedFileStream ofs(tmpFile); + ofs << "# Run command: " << ic << std::endl + << "# Output:" << std::endl + << output << std::endl; + cmCPackLogger(cmCPackLog::LOG_ERROR, + "Problem running install command: " + << ic << std::endl + << "Please check " << tmpFile << " for errors" + << std::endl); + return 0; + } + } + } + return 1; +} + +int cmCPackGenerator::InstallProjectViaInstalledDirectories( + bool setDestDir, const std::string& tempInstallDirectory, + const mode_t* default_dir_mode) +{ + (void)setDestDir; + (void)tempInstallDirectory; + std::vector<cmsys::RegularExpression> ignoreFilesRegex; + const char* cpackIgnoreFiles = this->GetOption("CPACK_IGNORE_FILES"); + if (cpackIgnoreFiles) { + std::vector<std::string> ignoreFilesRegexString; + cmSystemTools::ExpandListArgument(cpackIgnoreFiles, + ignoreFilesRegexString); + for (std::string const& ifr : ignoreFilesRegexString) { + cmCPackLogger(cmCPackLog::LOG_VERBOSE, + "Create ignore files regex for: " << ifr << std::endl); + ignoreFilesRegex.emplace_back(ifr); + } + } + const char* installDirectories = + this->GetOption("CPACK_INSTALLED_DIRECTORIES"); + if (installDirectories && *installDirectories) { + std::vector<std::string> installDirectoriesVector; + cmSystemTools::ExpandListArgument(installDirectories, + installDirectoriesVector); + if (installDirectoriesVector.size() % 2 != 0) { + cmCPackLogger( + cmCPackLog::LOG_ERROR, + "CPACK_INSTALLED_DIRECTORIES should contain pairs of <directory> and " + "<subdirectory>. The <subdirectory> can be '.' to be installed in " + "the toplevel directory of installation." + << std::endl); + return 0; + } + std::vector<std::string>::iterator it; + const std::string& tempDir = tempInstallDirectory; + for (it = installDirectoriesVector.begin(); + it != installDirectoriesVector.end(); ++it) { + std::vector<std::pair<std::string, std::string>> symlinkedFiles; + cmCPackLogger(cmCPackLog::LOG_DEBUG, "Find files" << std::endl); + cmsys::Glob gl; + std::string top = *it; + it++; + std::string subdir = *it; + std::string findExpr = top; + findExpr += "/*"; + cmCPackLogger(cmCPackLog::LOG_OUTPUT, + "- Install directory: " << top << std::endl); + gl.RecurseOn(); + gl.SetRecurseListDirs(true); + if (!gl.FindFiles(findExpr)) { + cmCPackLogger(cmCPackLog::LOG_ERROR, + "Cannot find any files in the installed directory" + << std::endl); + return 0; + } + files = gl.GetFiles(); + for (std::string const& gf : files) { + bool skip = false; + std::string inFile = gf; + if (cmSystemTools::FileIsDirectory(gf)) { + inFile += '/'; + } + for (cmsys::RegularExpression& reg : ignoreFilesRegex) { + if (reg.find(inFile)) { + cmCPackLogger(cmCPackLog::LOG_VERBOSE, + "Ignore file: " << inFile << std::endl); + skip = true; + } + } + if (skip) { + continue; + } + std::string filePath = tempDir; + filePath += "/" + subdir + "/" + cmSystemTools::RelativePath(top, gf); + cmCPackLogger(cmCPackLog::LOG_DEBUG, + "Copy file: " << inFile << " -> " << filePath + << std::endl); + /* If the file is a symlink we will have to re-create it */ + if (cmSystemTools::FileIsSymlink(inFile)) { + std::string targetFile; + std::string inFileRelative = + cmSystemTools::RelativePath(top, inFile); + cmSystemTools::ReadSymlink(inFile, targetFile); + symlinkedFiles.emplace_back(std::move(targetFile), + std::move(inFileRelative)); + } + /* If it is not a symlink then do a plain copy */ + else if (!(cmSystemTools::CopyFileIfDifferent(inFile, filePath) && + cmSystemTools::CopyFileTime(inFile, filePath))) { + cmCPackLogger(cmCPackLog::LOG_ERROR, + "Problem copying file: " << inFile << " -> " + << filePath << std::endl); + return 0; + } + } + /* rebuild symlinks in the installed tree */ + if (!symlinkedFiles.empty()) { + std::string curDir = cmSystemTools::GetCurrentWorkingDirectory(); + std::string goToDir = tempDir; + goToDir += "/" + subdir; + cmCPackLogger(cmCPackLog::LOG_DEBUG, + "Change dir to: " << goToDir << std::endl); + cmWorkingDirectory workdir(goToDir); + if (workdir.Failed()) { + cmCPackLogger(cmCPackLog::LOG_ERROR, + "Failed to change working directory to " + << goToDir << " : " + << std::strerror(workdir.GetLastResult()) + << std::endl); + return 0; + } + for (auto const& symlinked : symlinkedFiles) { + cmCPackLogger(cmCPackLog::LOG_DEBUG, + "Will create a symlink: " << symlinked.second << "--> " + << symlinked.first + << std::endl); + // make sure directory exists for symlink + std::string destDir = + cmSystemTools::GetFilenamePath(symlinked.second); + if (!destDir.empty() && + !cmSystemTools::MakeDirectory(destDir, default_dir_mode)) { + cmCPackLogger(cmCPackLog::LOG_ERROR, + "Cannot create dir: " + << destDir << "\nTrying to create symlink: " + << symlinked.second << "--> " << symlinked.first + << std::endl); + } + if (!cmSystemTools::CreateSymlink(symlinked.first, + symlinked.second)) { + cmCPackLogger(cmCPackLog::LOG_ERROR, + "Cannot create symlink: " + << symlinked.second << "--> " << symlinked.first + << std::endl); + return 0; + } + } + cmCPackLogger(cmCPackLog::LOG_DEBUG, + "Going back to: " << curDir << std::endl); + } + } + } + return 1; +} + +int cmCPackGenerator::InstallProjectViaInstallScript( + bool setDestDir, const std::string& tempInstallDirectory) +{ + const char* cmakeScripts = this->GetOption("CPACK_INSTALL_SCRIPT"); + if (cmakeScripts && *cmakeScripts) { + cmCPackLogger(cmCPackLog::LOG_OUTPUT, + "- Install scripts: " << cmakeScripts << std::endl); + std::vector<std::string> cmakeScriptsVector; + cmSystemTools::ExpandListArgument(cmakeScripts, cmakeScriptsVector); + for (std::string const& installScript : cmakeScriptsVector) { + + cmCPackLogger(cmCPackLog::LOG_OUTPUT, + "- Install script: " << installScript << std::endl); + + if (setDestDir) { + // For DESTDIR based packaging, use the *project* CMAKE_INSTALL_PREFIX + // underneath the tempInstallDirectory. The value of the project's + // CMAKE_INSTALL_PREFIX is sent in here as the value of the + // CPACK_INSTALL_PREFIX variable. + + std::string dir; + if (this->GetOption("CPACK_INSTALL_PREFIX")) { + dir += this->GetOption("CPACK_INSTALL_PREFIX"); + } + this->SetOption("CMAKE_INSTALL_PREFIX", dir.c_str()); + cmCPackLogger( + cmCPackLog::LOG_DEBUG, + "- Using DESTDIR + CPACK_INSTALL_PREFIX... (this->SetOption)" + << std::endl); + cmCPackLogger(cmCPackLog::LOG_DEBUG, + "- Setting CMAKE_INSTALL_PREFIX to '" << dir << "'" + << std::endl); + } else { + this->SetOption("CMAKE_INSTALL_PREFIX", tempInstallDirectory.c_str()); + + cmCPackLogger(cmCPackLog::LOG_DEBUG, + "- Using non-DESTDIR install... (this->SetOption)" + << std::endl); + cmCPackLogger(cmCPackLog::LOG_DEBUG, + "- Setting CMAKE_INSTALL_PREFIX to '" + << tempInstallDirectory << "'" << std::endl); + } + + this->SetOptionIfNotSet("CMAKE_CURRENT_BINARY_DIR", + tempInstallDirectory.c_str()); + this->SetOptionIfNotSet("CMAKE_CURRENT_SOURCE_DIR", + tempInstallDirectory.c_str()); + bool res = this->MakefileMap->ReadListFile(installScript); + if (cmSystemTools::GetErrorOccuredFlag() || !res) { + return 0; + } + } + } + return 1; +} + +int cmCPackGenerator::InstallProjectViaInstallCMakeProjects( + bool setDestDir, const std::string& baseTempInstallDirectory, + const mode_t* default_dir_mode) +{ + const char* cmakeProjects = this->GetOption("CPACK_INSTALL_CMAKE_PROJECTS"); + const char* cmakeGenerator = this->GetOption("CPACK_CMAKE_GENERATOR"); + std::string absoluteDestFiles; + if (cmakeProjects && *cmakeProjects) { + if (!cmakeGenerator) { + cmCPackLogger(cmCPackLog::LOG_ERROR, + "CPACK_INSTALL_CMAKE_PROJECTS is specified, but " + "CPACK_CMAKE_GENERATOR is not. CPACK_CMAKE_GENERATOR " + "is required to install the project." + << std::endl); + return 0; + } + std::vector<std::string> cmakeProjectsVector; + cmSystemTools::ExpandListArgument(cmakeProjects, cmakeProjectsVector); + std::vector<std::string>::iterator it; + for (it = cmakeProjectsVector.begin(); it != cmakeProjectsVector.end(); + ++it) { + if (it + 1 == cmakeProjectsVector.end() || + it + 2 == cmakeProjectsVector.end() || + it + 3 == cmakeProjectsVector.end()) { + cmCPackLogger( + cmCPackLog::LOG_ERROR, + "Not enough items on list: CPACK_INSTALL_CMAKE_PROJECTS. " + "CPACK_INSTALL_CMAKE_PROJECTS should hold quadruplet of install " + "directory, install project name, install component, and install " + "subdirectory." + << std::endl); + return 0; + } + std::string installDirectory = *it; + ++it; + std::string installProjectName = *it; + ++it; + cmCPackInstallCMakeProject project; + + project.Directory = installDirectory; + project.ProjectName = installProjectName; + project.Component = *it; + ++it; + project.SubDirectory = *it; + + std::vector<std::string> componentsVector; + + bool componentInstall = false; + /* + * We do a component install iff + * - the CPack generator support component + * - the user did not request Monolithic install + * (this works at CPack time too) + */ + if (this->SupportsComponentInstallation() && + !(this->IsOn("CPACK_MONOLITHIC_INSTALL"))) { + // Determine the installation types for this project (if provided). + std::string installTypesVar = "CPACK_" + + cmSystemTools::UpperCase(project.Component) + "_INSTALL_TYPES"; + const char* installTypes = this->GetOption(installTypesVar); + if (installTypes && *installTypes) { + std::vector<std::string> installTypesVector; + cmSystemTools::ExpandListArgument(installTypes, installTypesVector); + for (std::string const& installType : installTypesVector) { + project.InstallationTypes.push_back( + this->GetInstallationType(project.ProjectName, installType)); + } + } + + // Determine the set of components that will be used in this project + std::string componentsVar = + "CPACK_COMPONENTS_" + cmSystemTools::UpperCase(project.Component); + const char* components = this->GetOption(componentsVar); + if (components && *components) { + cmSystemTools::ExpandListArgument(components, componentsVector); + for (std::string const& comp : componentsVector) { + project.Components.push_back( + this->GetComponent(project.ProjectName, comp)); + } + componentInstall = true; + } + } + if (componentsVector.empty()) { + componentsVector.push_back(project.Component); + } + + const char* buildConfigCstr = this->GetOption("CPACK_BUILD_CONFIG"); + std::string buildConfig = buildConfigCstr ? buildConfigCstr : ""; + cmGlobalGenerator* globalGenerator = + this->MakefileMap->GetCMakeInstance()->CreateGlobalGenerator( + cmakeGenerator); + if (!globalGenerator) { + cmCPackLogger(cmCPackLog::LOG_ERROR, + "Specified package generator not found. " + "CPACK_CMAKE_GENERATOR value is invalid." + << std::endl); + return 0; + } + // set the global flag for unix style paths on cmSystemTools as + // soon as the generator is set. This allows gmake to be used + // on windows. + cmSystemTools::SetForceUnixPaths(globalGenerator->GetForceUnixPaths()); + + if (!this->RunPreinstallTarget(project.ProjectName, project.Directory, + globalGenerator, buildConfig)) { + return 0; + } + + delete globalGenerator; + + cmCPackLogger(cmCPackLog::LOG_OUTPUT, + "- Install project: " << project.ProjectName << std::endl); + + // Run the installation for each component + for (std::string const& component : componentsVector) { + if (!this->InstallCMakeProject( + setDestDir, project.Directory, baseTempInstallDirectory, + default_dir_mode, component, componentInstall, + project.SubDirectory, buildConfig, absoluteDestFiles)) { + return 0; + } + } + + this->CMakeProjects.push_back(project); + } + } + this->SetOption("CPACK_ABSOLUTE_DESTINATION_FILES", + absoluteDestFiles.c_str()); + return 1; +} + +int cmCPackGenerator::RunPreinstallTarget( + const std::string& installProjectName, const std::string& installDirectory, + cmGlobalGenerator* globalGenerator, const std::string& buildConfig) +{ + // Does this generator require pre-install? + if (const char* preinstall = globalGenerator->GetPreinstallTargetName()) { + std::string buildCommand = globalGenerator->GenerateCMakeBuildCommand( + preinstall, buildConfig, "", false); + cmCPackLogger(cmCPackLog::LOG_DEBUG, + "- Install command: " << buildCommand << std::endl); + cmCPackLogger(cmCPackLog::LOG_OUTPUT, + "- Run preinstall target for: " << installProjectName + << std::endl); + std::string output; + int retVal = 1; + bool resB = cmSystemTools::RunSingleCommand( + buildCommand, &output, &output, &retVal, installDirectory.c_str(), + this->GeneratorVerbose, cmDuration::zero()); + if (!resB || retVal) { + std::string tmpFile = this->GetOption("CPACK_TOPLEVEL_DIRECTORY"); + tmpFile += "/PreinstallOutput.log"; + cmGeneratedFileStream ofs(tmpFile); + ofs << "# Run command: " << buildCommand << std::endl + << "# Directory: " << installDirectory << std::endl + << "# Output:" << std::endl + << output << std::endl; + cmCPackLogger(cmCPackLog::LOG_ERROR, + "Problem running install command: " + << buildCommand << std::endl + << "Please check " << tmpFile << " for errors" + << std::endl); + return 0; + } + } + + return 1; +} + +int cmCPackGenerator::InstallCMakeProject( + bool setDestDir, const std::string& installDirectory, + const std::string& baseTempInstallDirectory, const mode_t* default_dir_mode, + const std::string& component, bool componentInstall, + const std::string& installSubDirectory, const std::string& buildConfig, + std::string& absoluteDestFiles) +{ + std::string tempInstallDirectory = baseTempInstallDirectory; + std::string installFile = installDirectory + "/cmake_install.cmake"; + + if (componentInstall) { + cmCPackLogger(cmCPackLog::LOG_OUTPUT, + "- Install component: " << component << std::endl); + } + + cmake cm(cmake::RoleScript, cmState::CPack); + cm.SetHomeDirectory(""); + cm.SetHomeOutputDirectory(""); + cm.GetCurrentSnapshot().SetDefaultDefinitions(); + cm.AddCMakePaths(); + cm.SetProgressCallback([this](const std::string& msg, float prog) { + this->DisplayVerboseOutput(msg, prog); + }); + cm.SetTrace(this->Trace); + cm.SetTraceExpand(this->TraceExpand); + cmGlobalGenerator gg(&cm); + cmMakefile mf(&gg, cm.GetCurrentSnapshot()); + if (!installSubDirectory.empty() && installSubDirectory != "/" && + installSubDirectory != ".") { + tempInstallDirectory += installSubDirectory; + } + if (componentInstall) { + tempInstallDirectory += "/"; + // 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(component); + if (this->IsOn("CPACK_COMPONENT_INCLUDE_TOPLEVEL_DIRECTORY")) { + tempInstallDirectory += "/"; + tempInstallDirectory += this->GetOption("CPACK_PACKAGE_FILE_NAME"); + } + } + + const char* default_dir_inst_permissions = + this->GetOption("CPACK_INSTALL_DEFAULT_DIRECTORY_PERMISSIONS"); + if (default_dir_inst_permissions && *default_dir_inst_permissions) { + mf.AddDefinition("CMAKE_INSTALL_DEFAULT_DIRECTORY_PERMISSIONS", + default_dir_inst_permissions); + } + + if (!setDestDir) { + tempInstallDirectory += this->GetPackagingInstallPrefix(); + } + + if (setDestDir) { + // For DESTDIR based packaging, use the *project* + // CMAKE_INSTALL_PREFIX underneath the tempInstallDirectory. The + // value of the project's CMAKE_INSTALL_PREFIX is sent in here as + // the value of the CPACK_INSTALL_PREFIX variable. + // + // If DESTDIR has been 'internally set ON' this means that + // the underlying CPack specific generator did ask for that + // In this case we may override CPACK_INSTALL_PREFIX with + // CPACK_PACKAGING_INSTALL_PREFIX + // I know this is tricky and awkward but it's the price for + // CPACK_SET_DESTDIR backward compatibility. + if (cmSystemTools::IsInternallyOn(this->GetOption("CPACK_SET_DESTDIR"))) { + this->SetOption("CPACK_INSTALL_PREFIX", + this->GetOption("CPACK_PACKAGING_INSTALL_PREFIX")); + } + std::string dir; + if (this->GetOption("CPACK_INSTALL_PREFIX")) { + dir += this->GetOption("CPACK_INSTALL_PREFIX"); + } + mf.AddDefinition("CMAKE_INSTALL_PREFIX", dir.c_str()); + + cmCPackLogger( + cmCPackLog::LOG_DEBUG, + "- Using DESTDIR + CPACK_INSTALL_PREFIX... (mf.AddDefinition)" + << std::endl); + cmCPackLogger(cmCPackLog::LOG_DEBUG, + "- Setting CMAKE_INSTALL_PREFIX to '" << dir << "'" + << std::endl); + + // Make sure that DESTDIR + CPACK_INSTALL_PREFIX directory + // exists: + // + if (cmSystemTools::StringStartsWith(dir.c_str(), "/")) { + dir = tempInstallDirectory + dir; + } else { + dir = tempInstallDirectory + "/" + dir; + } + /* + * We must re-set DESTDIR for each component + * We must not add the CPACK_INSTALL_PREFIX part because + * it will be added using the override of CMAKE_INSTALL_PREFIX + * The main reason for this awkward trick is that + * are using DESTDIR for 2 different reasons: + * - Because it was asked by the CPack Generator or the user + * using CPACK_SET_DESTDIR + * - Because it was already used for component install + * in order to put things in subdirs... + */ + cmSystemTools::PutEnv(std::string("DESTDIR=") + tempInstallDirectory); + cmCPackLogger(cmCPackLog::LOG_DEBUG, + "- Creating directory: '" << dir << "'" << std::endl); + + if (!cmsys::SystemTools::MakeDirectory(dir, default_dir_mode)) { + cmCPackLogger(cmCPackLog::LOG_ERROR, + "Problem creating temporary directory: " << dir + << std::endl); + return 0; + } + } else { + mf.AddDefinition("CMAKE_INSTALL_PREFIX", tempInstallDirectory.c_str()); + + if (!cmsys::SystemTools::MakeDirectory(tempInstallDirectory, + default_dir_mode)) { + cmCPackLogger(cmCPackLog::LOG_ERROR, + "Problem creating temporary directory: " + << tempInstallDirectory << std::endl); + return 0; + } + + cmCPackLogger(cmCPackLog::LOG_DEBUG, + "- Using non-DESTDIR install... (mf.AddDefinition)" + << std::endl); + cmCPackLogger(cmCPackLog::LOG_DEBUG, + "- Setting CMAKE_INSTALL_PREFIX to '" << tempInstallDirectory + << "'" << std::endl); + } + + if (!buildConfig.empty()) { + mf.AddDefinition("BUILD_TYPE", buildConfig.c_str()); + } + std::string installComponentLowerCase = cmSystemTools::LowerCase(component); + if (installComponentLowerCase != "all") { + mf.AddDefinition("CMAKE_INSTALL_COMPONENT", component.c_str()); + } + + // strip on TRUE, ON, 1, one or several file names, but not on + // FALSE, OFF, 0 and an empty string + if (!cmSystemTools::IsOff(this->GetOption("CPACK_STRIP_FILES"))) { + mf.AddDefinition("CMAKE_INSTALL_DO_STRIP", "1"); + } + // Remember the list of files before installation + // of the current component (if we are in component install) + std::string const& InstallPrefix = tempInstallDirectory; + std::vector<std::string> filesBefore; + std::string findExpr = tempInstallDirectory; + if (componentInstall) { + cmsys::Glob glB; + findExpr += "/*"; + glB.RecurseOn(); + glB.SetRecurseListDirs(true); + glB.FindFiles(findExpr); + filesBefore = glB.GetFiles(); + std::sort(filesBefore.begin(), filesBefore.end()); + } + + // If CPack was asked to warn on ABSOLUTE INSTALL DESTINATION + // then forward request to cmake_install.cmake script + if (this->IsOn("CPACK_WARN_ON_ABSOLUTE_INSTALL_DESTINATION")) { + mf.AddDefinition("CMAKE_WARN_ON_ABSOLUTE_INSTALL_DESTINATION", "1"); + } + // If current CPack generator does support + // ABSOLUTE INSTALL DESTINATION or CPack has been asked for + // then ask cmake_install.cmake script to error out + // as soon as it occurs (before installing file) + if (!SupportsAbsoluteDestination() || + this->IsOn("CPACK_ERROR_ON_ABSOLUTE_INSTALL_DESTINATION")) { + mf.AddDefinition("CMAKE_ERROR_ON_ABSOLUTE_INSTALL_DESTINATION", "1"); + } + // do installation + bool res = mf.ReadListFile(installFile); + // forward definition of CMAKE_ABSOLUTE_DESTINATION_FILES + // to CPack (may be used by generators like CPack RPM or DEB) + // in order to transparently handle ABSOLUTE PATH + if (mf.GetDefinition("CMAKE_ABSOLUTE_DESTINATION_FILES")) { + mf.AddDefinition("CPACK_ABSOLUTE_DESTINATION_FILES", + mf.GetDefinition("CMAKE_ABSOLUTE_DESTINATION_FILES")); + } + + // Now rebuild the list of files after installation + // of the current component (if we are in component install) + if (componentInstall) { + cmsys::Glob glA; + glA.RecurseOn(); + glA.SetRecurseListDirs(true); + glA.SetRecurseThroughSymlinks(false); + glA.FindFiles(findExpr); + std::vector<std::string> filesAfter = glA.GetFiles(); + std::sort(filesAfter.begin(), filesAfter.end()); + std::vector<std::string>::iterator diff; + std::vector<std::string> result(filesAfter.size()); + diff = std::set_difference(filesAfter.begin(), filesAfter.end(), + filesBefore.begin(), filesBefore.end(), + result.begin()); + + std::vector<std::string>::iterator fit; + std::string localFileName; + // Populate the File field of each component + for (fit = result.begin(); fit != diff; ++fit) { + localFileName = cmSystemTools::RelativePath(InstallPrefix, *fit); + localFileName = + localFileName.substr(localFileName.find_first_not_of('/')); + Components[component].Files.push_back(localFileName); + cmCPackLogger(cmCPackLog::LOG_DEBUG, + "Adding file <" << localFileName << "> to component <" + << component << ">" << std::endl); + } + } + + if (nullptr != mf.GetDefinition("CPACK_ABSOLUTE_DESTINATION_FILES")) { + if (!absoluteDestFiles.empty()) { + absoluteDestFiles += ";"; + } + absoluteDestFiles += mf.GetDefinition("CPACK_ABSOLUTE_DESTINATION_FILES"); + cmCPackLogger(cmCPackLog::LOG_DEBUG, + "Got some ABSOLUTE DESTINATION FILES: " << absoluteDestFiles + << std::endl); + // define component specific var + if (componentInstall) { + std::string absoluteDestFileComponent = + std::string("CPACK_ABSOLUTE_DESTINATION_FILES") + "_" + + GetComponentInstallDirNameSuffix(component); + if (nullptr != this->GetOption(absoluteDestFileComponent)) { + std::string absoluteDestFilesListComponent = + this->GetOption(absoluteDestFileComponent); + absoluteDestFilesListComponent += ";"; + absoluteDestFilesListComponent += + mf.GetDefinition("CPACK_ABSOLUTE_DESTINATION_FILES"); + this->SetOption(absoluteDestFileComponent, + absoluteDestFilesListComponent.c_str()); + } else { + this->SetOption(absoluteDestFileComponent, + mf.GetDefinition("CPACK_ABSOLUTE_DESTINATION_FILES")); + } + } + } + if (cmSystemTools::GetErrorOccuredFlag() || !res) { + return 0; + } + return 1; +} + +bool cmCPackGenerator::ReadListFile(const char* moduleName) +{ + bool retval; + std::string fullPath = this->MakefileMap->GetModulesFile(moduleName); + retval = this->MakefileMap->ReadListFile(fullPath); + // include FATAL_ERROR and ERROR in the return status + retval = retval && (!cmSystemTools::GetErrorOccuredFlag()); + return retval; +} + +void cmCPackGenerator::SetOptionIfNotSet(const std::string& op, + const char* value) +{ + const char* def = this->MakefileMap->GetDefinition(op); + if (def && *def) { + return; + } + this->SetOption(op, value); +} + +void cmCPackGenerator::SetOption(const std::string& op, const char* value) +{ + if (!value) { + this->MakefileMap->RemoveDefinition(op); + return; + } + cmCPackLogger(cmCPackLog::LOG_DEBUG, + this->GetNameOfClass() << "::SetOption(" << op << ", " << value + << ")" << std::endl); + this->MakefileMap->AddDefinition(op, value); +} + +int cmCPackGenerator::DoPackage() +{ + cmCPackLogger(cmCPackLog::LOG_OUTPUT, + "Create package using " << this->Name << std::endl); + + // Prepare CPack internal name and check + // values for many CPACK_xxx vars + if (!this->PrepareNames()) { + return 0; + } + + // Digest Component grouping specification + if (!this->PrepareGroupingKind()) { + return 0; + } + + if (cmSystemTools::IsOn( + this->GetOption("CPACK_REMOVE_TOPLEVEL_DIRECTORY"))) { + const char* toplevelDirectory = + this->GetOption("CPACK_TOPLEVEL_DIRECTORY"); + if (cmSystemTools::FileExists(toplevelDirectory)) { + cmCPackLogger(cmCPackLog::LOG_VERBOSE, + "Remove toplevel directory: " << toplevelDirectory + << std::endl); + if (!cmSystemTools::RepeatedRemoveDirectory(toplevelDirectory)) { + cmCPackLogger(cmCPackLog::LOG_ERROR, + "Problem removing toplevel directory: " + << toplevelDirectory << std::endl); + return 0; + } + } + } + cmCPackLogger(cmCPackLog::LOG_DEBUG, + "About to install project " << std::endl); + + if (!this->InstallProject()) { + return 0; + } + cmCPackLogger(cmCPackLog::LOG_DEBUG, "Done install project " << std::endl); + + const char* tempPackageFileName = + this->GetOption("CPACK_TEMPORARY_PACKAGE_FILE_NAME"); + const char* tempDirectory = this->GetOption("CPACK_TEMPORARY_DIRECTORY"); + + cmCPackLogger(cmCPackLog::LOG_DEBUG, "Find files" << std::endl); + cmsys::Glob gl; + std::string findExpr = tempDirectory; + findExpr += "/*"; + gl.RecurseOn(); + gl.SetRecurseListDirs(true); + gl.SetRecurseThroughSymlinks(false); + if (!gl.FindFiles(findExpr)) { + cmCPackLogger(cmCPackLog::LOG_ERROR, + "Cannot find any files in the packaging tree" << std::endl); + return 0; + } + + cmCPackLogger(cmCPackLog::LOG_OUTPUT, "Create package" << std::endl); + cmCPackLogger(cmCPackLog::LOG_VERBOSE, + "Package files to: " + << (tempPackageFileName ? tempPackageFileName : "(NULL)") + << std::endl); + if (cmSystemTools::FileExists(tempPackageFileName)) { + cmCPackLogger(cmCPackLog::LOG_VERBOSE, + "Remove old package file" << std::endl); + cmSystemTools::RemoveFile(tempPackageFileName); + } + if (cmSystemTools::IsOn( + this->GetOption("CPACK_INCLUDE_TOPLEVEL_DIRECTORY"))) { + tempDirectory = this->GetOption("CPACK_TOPLEVEL_DIRECTORY"); + } + + // The files to be installed + files = gl.GetFiles(); + + packageFileNames.clear(); + /* Put at least one file name into the list of + * wanted packageFileNames. The specific generator + * may update this during PackageFiles. + * (either putting several names or updating the provided one) + */ + packageFileNames.emplace_back(tempPackageFileName ? tempPackageFileName + : ""); + toplevel = tempDirectory; + { // scope that enables package generators to run internal scripts with + // latest CMake policies enabled + cmMakefile::ScopePushPop pp{ this->MakefileMap }; + this->MakefileMap->SetPolicyVersion(cmVersion::GetCMakeVersion(), + std::string()); + + if (!this->PackageFiles() || cmSystemTools::GetErrorOccuredFlag()) { + cmCPackLogger(cmCPackLog::LOG_ERROR, + "Problem compressing the directory" << std::endl); + return 0; + } + } + + /* Prepare checksum algorithm*/ + const char* algo = this->GetOption("CPACK_PACKAGE_CHECKSUM"); + std::unique_ptr<cmCryptoHash> crypto = cmCryptoHash::New(algo ? algo : ""); + + /* + * Copy the generated packages to final destination + * - there may be several of them + * - the initially provided name may have changed + * (because the specific generator did 'normalize' it) + */ + cmCPackLogger(cmCPackLog::LOG_VERBOSE, + "Copying final package(s) [" << packageFileNames.size() + << "]:" << std::endl); + /* now copy package one by one */ + for (std::string const& pkgFileName : packageFileNames) { + std::string tmpPF(this->GetOption("CPACK_OUTPUT_FILE_PREFIX")); + std::string filename(cmSystemTools::GetFilenameName(pkgFileName)); + tempPackageFileName = pkgFileName.c_str(); + tmpPF += "/" + filename; + const char* packageFileName = tmpPF.c_str(); + cmCPackLogger(cmCPackLog::LOG_DEBUG, + "Copy final package(s): " + << (tempPackageFileName ? tempPackageFileName : "(NULL)") + << " to " << (packageFileName ? packageFileName : "(NULL)") + << std::endl); + if (!cmSystemTools::CopyFileIfDifferent(pkgFileName, tmpPF)) { + cmCPackLogger( + cmCPackLog::LOG_ERROR, + "Problem copying the package: " + << (tempPackageFileName ? tempPackageFileName : "(NULL)") << " to " + << (packageFileName ? packageFileName : "(NULL)") << std::endl); + return 0; + } + cmCPackLogger(cmCPackLog::LOG_OUTPUT, + "- package: " << packageFileName << " generated." + << std::endl); + + /* Generate checksum file */ + if (crypto) { + std::string hashFile(this->GetOption("CPACK_OUTPUT_FILE_PREFIX")); + hashFile += "/" + filename; + hashFile += "." + cmSystemTools::LowerCase(algo); + cmsys::ofstream outF(hashFile.c_str()); + if (!outF) { + cmCPackLogger(cmCPackLog::LOG_ERROR, + "Cannot create checksum file: " << hashFile + << std::endl); + return 0; + } + outF << crypto->HashFile(packageFileName) << " " << filename << "\n"; + cmCPackLogger(cmCPackLog::LOG_OUTPUT, + "- checksum file: " << hashFile << " generated." + << std::endl); + } + } + + return 1; +} + +int cmCPackGenerator::Initialize(const std::string& name, cmMakefile* mf) +{ + this->MakefileMap = mf; + this->Name = name; + // set the running generator name + this->SetOption("CPACK_GENERATOR", this->Name.c_str()); + // Load the project specific config file + const char* config = this->GetOption("CPACK_PROJECT_CONFIG_FILE"); + if (config) { + mf->ReadListFile(config); + } + int result = this->InitializeInternal(); + if (cmSystemTools::GetErrorOccuredFlag()) { + return 0; + } + + // If a generator subclass did not already set this option in its + // InitializeInternal implementation, and the project did not already set + // it, the default value should be: + this->SetOptionIfNotSet("CPACK_PACKAGING_INSTALL_PREFIX", "/"); + + return result; +} + +int cmCPackGenerator::InitializeInternal() +{ + return 1; +} + +bool cmCPackGenerator::IsSet(const std::string& name) const +{ + return this->MakefileMap->IsSet(name); +} + +bool cmCPackGenerator::IsOn(const std::string& name) const +{ + return cmSystemTools::IsOn(GetOption(name)); +} + +bool cmCPackGenerator::IsSetToOff(const std::string& op) const +{ + const char* ret = this->MakefileMap->GetDefinition(op); + if (ret && *ret) { + return cmSystemTools::IsOff(ret); + } + return false; +} + +bool cmCPackGenerator::IsSetToEmpty(const std::string& op) const +{ + const char* ret = this->MakefileMap->GetDefinition(op); + if (ret) { + return !*ret; + } + return false; +} + +const char* cmCPackGenerator::GetOption(const std::string& op) const +{ + const char* ret = this->MakefileMap->GetDefinition(op); + if (!ret) { + cmCPackLogger(cmCPackLog::LOG_DEBUG, + "Warning, GetOption return NULL for: " << op << std::endl); + } + return ret; +} + +std::vector<std::string> cmCPackGenerator::GetOptions() const +{ + return this->MakefileMap->GetDefinitions(); +} + +int cmCPackGenerator::PackageFiles() +{ + return 0; +} + +const char* cmCPackGenerator::GetInstallPath() +{ + if (!this->InstallPath.empty()) { + return this->InstallPath.c_str(); + } +#if defined(_WIN32) && !defined(__CYGWIN__) + std::string prgfiles; + std::string sysDrive; + if (cmsys::SystemTools::GetEnv("ProgramFiles", prgfiles)) { + this->InstallPath = prgfiles; + } else if (cmsys::SystemTools::GetEnv("SystemDrive", sysDrive)) { + this->InstallPath = sysDrive; + this->InstallPath += "/Program Files"; + } else { + this->InstallPath = "c:/Program Files"; + } + this->InstallPath += "/"; + this->InstallPath += this->GetOption("CPACK_PACKAGE_NAME"); + this->InstallPath += "-"; + this->InstallPath += this->GetOption("CPACK_PACKAGE_VERSION"); +#elif defined(__HAIKU__) + char dir[B_PATH_NAME_LENGTH]; + if (find_directory(B_SYSTEM_DIRECTORY, -1, false, dir, sizeof(dir)) == + B_OK) { + this->InstallPath = dir; + } else { + this->InstallPath = "/boot/system"; + } +#else + this->InstallPath = "/usr/local/"; +#endif + return this->InstallPath.c_str(); +} + +const char* cmCPackGenerator::GetPackagingInstallPrefix() +{ + cmCPackLogger(cmCPackLog::LOG_DEBUG, + "GetPackagingInstallPrefix: '" + << this->GetOption("CPACK_PACKAGING_INSTALL_PREFIX") << "'" + << std::endl); + + return this->GetOption("CPACK_PACKAGING_INSTALL_PREFIX"); +} + +std::string cmCPackGenerator::FindTemplate(const char* name) +{ + cmCPackLogger(cmCPackLog::LOG_DEBUG, + "Look for template: " << (name ? name : "(NULL)") + << std::endl); + std::string ffile = this->MakefileMap->GetModulesFile(name); + cmCPackLogger(cmCPackLog::LOG_DEBUG, + "Found template: " << ffile << std::endl); + return ffile; +} + +bool cmCPackGenerator::ConfigureString(const std::string& inString, + std::string& outString) +{ + this->MakefileMap->ConfigureString(inString, outString, true, false); + return true; +} + +bool cmCPackGenerator::ConfigureFile(const std::string& inName, + const std::string& outName, + bool copyOnly /* = false */) +{ + return this->MakefileMap->ConfigureFile(inName, outName, copyOnly, true, + false) == 1; +} + +int cmCPackGenerator::CleanTemporaryDirectory() +{ + std::string tempInstallDirectory = + this->GetOption("CPACK_TEMPORARY_INSTALL_DIRECTORY"); + if (cmsys::SystemTools::FileExists(tempInstallDirectory)) { + cmCPackLogger(cmCPackLog::LOG_OUTPUT, + "- Clean temporary : " << tempInstallDirectory << std::endl); + if (!cmSystemTools::RepeatedRemoveDirectory(tempInstallDirectory)) { + cmCPackLogger(cmCPackLog::LOG_ERROR, + "Problem removing temporary directory: " + << tempInstallDirectory << std::endl); + return 0; + } + } + return 1; +} + +cmInstalledFile const* cmCPackGenerator::GetInstalledFile( + std::string const& name) const +{ + cmake const* cm = this->MakefileMap->GetCMakeInstance(); + return cm->GetInstalledFile(name); +} + +int cmCPackGenerator::PrepareGroupingKind() +{ + // find a component package method specified by the user + ComponentPackageMethod method = UNKNOWN_COMPONENT_PACKAGE_METHOD; + + if (this->GetOption("CPACK_COMPONENTS_ALL_IN_ONE_PACKAGE")) { + method = ONE_PACKAGE; + } + + if (this->GetOption("CPACK_COMPONENTS_IGNORE_GROUPS")) { + method = ONE_PACKAGE_PER_COMPONENT; + } + + if (this->GetOption("CPACK_COMPONENTS_ONE_PACKAGE_PER_GROUP")) { + method = ONE_PACKAGE_PER_GROUP; + } + + std::string groupingType; + + // Second way to specify grouping + if (nullptr != this->GetOption("CPACK_COMPONENTS_GROUPING")) { + groupingType = this->GetOption("CPACK_COMPONENTS_GROUPING"); + } + + if (!groupingType.empty()) { + cmCPackLogger(cmCPackLog::LOG_VERBOSE, + "[" << this->Name << "]" + << " requested component grouping = " << groupingType + << std::endl); + if (groupingType == "ALL_COMPONENTS_IN_ONE") { + method = ONE_PACKAGE; + } else if (groupingType == "IGNORE") { + method = ONE_PACKAGE_PER_COMPONENT; + } else if (groupingType == "ONE_PER_GROUP") { + method = ONE_PACKAGE_PER_GROUP; + } else { + cmCPackLogger( + cmCPackLog::LOG_WARNING, + "[" << this->Name << "]" + << " requested component grouping type <" << groupingType + << "> UNKNOWN not in (ALL_COMPONENTS_IN_ONE,IGNORE,ONE_PER_GROUP)" + << std::endl); + } + } + + // Some components were defined but NO group + // fallback to default if not group based + if (method == ONE_PACKAGE_PER_GROUP && this->ComponentGroups.empty() && + !this->Components.empty()) { + if (componentPackageMethod == ONE_PACKAGE) { + method = ONE_PACKAGE; + } else { + method = ONE_PACKAGE_PER_COMPONENT; + } + cmCPackLogger( + cmCPackLog::LOG_WARNING, + "[" << this->Name << "]" + << " One package per component group requested, " + << "but NO component groups exist: Ignoring component group." + << std::endl); + } + + // if user specified packaging method, override the default packaging method + if (method != UNKNOWN_COMPONENT_PACKAGE_METHOD) { + componentPackageMethod = method; + } + + const char* method_names[] = { "ALL_COMPONENTS_IN_ONE", "IGNORE_GROUPS", + "ONE_PER_GROUP" }; + + cmCPackLogger(cmCPackLog::LOG_VERBOSE, + "[" << this->Name << "]" + << " requested component grouping = " + << method_names[componentPackageMethod] << std::endl); + + return 1; +} + +std::string cmCPackGenerator::GetComponentInstallDirNameSuffix( + const std::string& componentName) +{ + return componentName; +} +std::string cmCPackGenerator::GetComponentPackageFileName( + const std::string& initialPackageFileName, + const std::string& groupOrComponentName, bool isGroupName) +{ + + /* + * the default behavior is to use the + * component [group] name as a suffix + */ + std::string suffix = "-" + groupOrComponentName; + /* check if we should use DISPLAY name */ + std::string dispNameVar = "CPACK_" + Name + "_USE_DISPLAY_NAME_IN_FILENAME"; + if (IsOn(dispNameVar)) { + /* the component Group case */ + if (isGroupName) { + std::string groupDispVar = "CPACK_COMPONENT_GROUP_" + + cmSystemTools::UpperCase(groupOrComponentName) + "_DISPLAY_NAME"; + const char* groupDispName = GetOption(groupDispVar); + if (groupDispName) { + suffix = "-" + std::string(groupDispName); + } + } + /* the [single] component case */ + else { + std::string dispVar = "CPACK_COMPONENT_" + + cmSystemTools::UpperCase(groupOrComponentName) + "_DISPLAY_NAME"; + const char* dispName = GetOption(dispVar); + if (dispName) { + suffix = "-" + std::string(dispName); + } + } + } + return initialPackageFileName + suffix; +} + +enum cmCPackGenerator::CPackSetDestdirSupport +cmCPackGenerator::SupportsSetDestdir() const +{ + return cmCPackGenerator::SETDESTDIR_SUPPORTED; +} + +bool cmCPackGenerator::SupportsAbsoluteDestination() const +{ + return true; +} + +bool cmCPackGenerator::SupportsComponentInstallation() const +{ + return false; +} + +bool cmCPackGenerator::WantsComponentInstallation() const +{ + return (!IsOn("CPACK_MONOLITHIC_INSTALL") && + SupportsComponentInstallation() + // check that we have at least one group or component + && (!this->ComponentGroups.empty() || !this->Components.empty())); +} + +cmCPackInstallationType* cmCPackGenerator::GetInstallationType( + const std::string& projectName, const std::string& name) +{ + (void)projectName; + bool hasInstallationType = this->InstallationTypes.count(name) != 0; + cmCPackInstallationType* installType = &this->InstallationTypes[name]; + if (!hasInstallationType) { + // Define the installation type + std::string macroPrefix = + "CPACK_INSTALL_TYPE_" + cmsys::SystemTools::UpperCase(name); + installType->Name = name; + + const char* displayName = this->GetOption(macroPrefix + "_DISPLAY_NAME"); + if (displayName && *displayName) { + installType->DisplayName = displayName; + } else { + installType->DisplayName = installType->Name; + } + + installType->Index = static_cast<unsigned>(this->InstallationTypes.size()); + } + return installType; +} + +cmCPackComponent* cmCPackGenerator::GetComponent( + const std::string& projectName, const std::string& name) +{ + bool hasComponent = this->Components.count(name) != 0; + cmCPackComponent* component = &this->Components[name]; + if (!hasComponent) { + // Define the component + std::string macroPrefix = + "CPACK_COMPONENT_" + cmsys::SystemTools::UpperCase(name); + component->Name = name; + const char* displayName = this->GetOption(macroPrefix + "_DISPLAY_NAME"); + if (displayName && *displayName) { + component->DisplayName = displayName; + } else { + component->DisplayName = component->Name; + } + component->IsHidden = this->IsOn(macroPrefix + "_HIDDEN"); + component->IsRequired = this->IsOn(macroPrefix + "_REQUIRED"); + component->IsDisabledByDefault = this->IsOn(macroPrefix + "_DISABLED"); + component->IsDownloaded = this->IsOn(macroPrefix + "_DOWNLOADED") || + cmSystemTools::IsOn(this->GetOption("CPACK_DOWNLOAD_ALL")); + + const char* archiveFile = this->GetOption(macroPrefix + "_ARCHIVE_FILE"); + if (archiveFile && *archiveFile) { + component->ArchiveFile = archiveFile; + } + + const char* plist = this->GetOption(macroPrefix + "_PLIST"); + if (plist && *plist) { + component->Plist = plist; + } + + const char* groupName = this->GetOption(macroPrefix + "_GROUP"); + if (groupName && *groupName) { + component->Group = GetComponentGroup(projectName, groupName); + component->Group->Components.push_back(component); + } else { + component->Group = nullptr; + } + + const char* description = this->GetOption(macroPrefix + "_DESCRIPTION"); + if (description && *description) { + component->Description = description; + } + + // Determine the installation types. + const char* installTypes = this->GetOption(macroPrefix + "_INSTALL_TYPES"); + if (installTypes && *installTypes) { + std::vector<std::string> installTypesVector; + cmSystemTools::ExpandListArgument(installTypes, installTypesVector); + for (std::string const& installType : installTypesVector) { + component->InstallationTypes.push_back( + this->GetInstallationType(projectName, installType)); + } + } + + // Determine the component dependencies. + const char* depends = this->GetOption(macroPrefix + "_DEPENDS"); + if (depends && *depends) { + std::vector<std::string> dependsVector; + cmSystemTools::ExpandListArgument(depends, dependsVector); + for (std::string const& depend : dependsVector) { + cmCPackComponent* child = GetComponent(projectName, depend); + component->Dependencies.push_back(child); + child->ReverseDependencies.push_back(component); + } + } + } + return component; +} + +cmCPackComponentGroup* cmCPackGenerator::GetComponentGroup( + const std::string& projectName, const std::string& name) +{ + (void)projectName; + std::string macroPrefix = + "CPACK_COMPONENT_GROUP_" + cmsys::SystemTools::UpperCase(name); + bool hasGroup = this->ComponentGroups.count(name) != 0; + cmCPackComponentGroup* group = &this->ComponentGroups[name]; + if (!hasGroup) { + // Define the group + group->Name = name; + const char* displayName = this->GetOption(macroPrefix + "_DISPLAY_NAME"); + if (displayName && *displayName) { + group->DisplayName = displayName; + } else { + group->DisplayName = group->Name; + } + + const char* description = this->GetOption(macroPrefix + "_DESCRIPTION"); + if (description && *description) { + group->Description = description; + } + group->IsBold = this->IsOn(macroPrefix + "_BOLD_TITLE"); + group->IsExpandedByDefault = this->IsOn(macroPrefix + "_EXPANDED"); + const char* parentGroupName = + this->GetOption(macroPrefix + "_PARENT_GROUP"); + if (parentGroupName && *parentGroupName) { + group->ParentGroup = GetComponentGroup(projectName, parentGroupName); + group->ParentGroup->Subgroups.push_back(group); + } else { + group->ParentGroup = nullptr; + } + } + return group; +} |