summaryrefslogtreecommitdiffstats
path: root/Source/CPack
diff options
context:
space:
mode:
Diffstat (limited to 'Source/CPack')
-rw-r--r--Source/CPack/IFW/cmCPackIFWGenerator.cxx582
-rw-r--r--Source/CPack/IFW/cmCPackIFWGenerator.h167
-rw-r--r--Source/CPack/IFW/cmCPackIFWInstaller.cxx349
-rw-r--r--Source/CPack/IFW/cmCPackIFWInstaller.h118
-rw-r--r--Source/CPack/IFW/cmCPackIFWPackage.cxx484
-rw-r--r--Source/CPack/IFW/cmCPackIFWPackage.h149
-rw-r--r--Source/CPack/IFW/cmCPackIFWRepository.cxx342
-rw-r--r--Source/CPack/IFW/cmCPackIFWRepository.h105
-rw-r--r--Source/CPack/OSXLauncherScript.scptbin0 -> 3102 bytes
-rw-r--r--Source/CPack/OSXScriptLauncher.cxx130
-rw-r--r--Source/CPack/WiX/cmCPackWIXGenerator.cxx1134
-rw-r--r--Source/CPack/WiX/cmCPackWIXGenerator.h167
-rw-r--r--Source/CPack/WiX/cmWIXAccessControlList.cxx136
-rw-r--r--Source/CPack/WiX/cmWIXAccessControlList.h44
-rw-r--r--Source/CPack/WiX/cmWIXDirectoriesSourceWriter.cxx88
-rw-r--r--Source/CPack/WiX/cmWIXDirectoriesSourceWriter.h44
-rw-r--r--Source/CPack/WiX/cmWIXFeaturesSourceWriter.cxx101
-rw-r--r--Source/CPack/WiX/cmWIXFeaturesSourceWriter.h38
-rw-r--r--Source/CPack/WiX/cmWIXFilesSourceWriter.cxx170
-rw-r--r--Source/CPack/WiX/cmWIXFilesSourceWriter.h52
-rw-r--r--Source/CPack/WiX/cmWIXPatch.cxx105
-rw-r--r--Source/CPack/WiX/cmWIXPatch.h47
-rw-r--r--Source/CPack/WiX/cmWIXPatchParser.cxx156
-rw-r--r--Source/CPack/WiX/cmWIXPatchParser.h100
-rw-r--r--Source/CPack/WiX/cmWIXRichTextFormatWriter.cxx196
-rw-r--r--Source/CPack/WiX/cmWIXRichTextFormatWriter.h54
-rw-r--r--Source/CPack/WiX/cmWIXShortcut.cxx115
-rw-r--r--Source/CPack/WiX/cmWIXShortcut.h70
-rw-r--r--Source/CPack/WiX/cmWIXSourceWriter.cxx216
-rw-r--r--Source/CPack/WiX/cmWIXSourceWriter.h75
-rw-r--r--Source/CPack/bills-comments.txt68
-rw-r--r--Source/CPack/cmCPack7zGenerator.cxx22
-rw-r--r--Source/CPack/cmCPack7zGenerator.h36
-rw-r--r--Source/CPack/cmCPackArchiveGenerator.cxx273
-rw-r--r--Source/CPack/cmCPackArchiveGenerator.h75
-rw-r--r--Source/CPack/cmCPackBundleGenerator.cxx292
-rw-r--r--Source/CPack/cmCPackBundleGenerator.h42
-rw-r--r--Source/CPack/cmCPackComponentGroup.cxx43
-rw-r--r--Source/CPack/cmCPackComponentGroup.h149
-rw-r--r--Source/CPack/cmCPackConfigure.h.in11
-rw-r--r--Source/CPack/cmCPackCygwinBinaryGenerator.cxx84
-rw-r--r--Source/CPack/cmCPackCygwinBinaryGenerator.h39
-rw-r--r--Source/CPack/cmCPackCygwinSourceGenerator.cxx167
-rw-r--r--Source/CPack/cmCPackCygwinSourceGenerator.h41
-rw-r--r--Source/CPack/cmCPackDebGenerator.cxx952
-rw-r--r--Source/CPack/cmCPackDebGenerator.h76
-rw-r--r--Source/CPack/cmCPackDragNDropGenerator.cxx898
-rw-r--r--Source/CPack/cmCPackDragNDropGenerator.h60
-rw-r--r--Source/CPack/cmCPackGenerator.cxx1433
-rw-r--r--Source/CPack/cmCPackGenerator.h331
-rw-r--r--Source/CPack/cmCPackGeneratorFactory.cxx183
-rw-r--r--Source/CPack/cmCPackGeneratorFactory.h61
-rw-r--r--Source/CPack/cmCPackLog.cxx190
-rw-r--r--Source/CPack/cmCPackLog.h158
-rw-r--r--Source/CPack/cmCPackNSISGenerator.cxx918
-rw-r--r--Source/CPack/cmCPackNSISGenerator.h85
-rw-r--r--Source/CPack/cmCPackOSXX11Generator.cxx291
-rw-r--r--Source/CPack/cmCPackOSXX11Generator.h48
-rw-r--r--Source/CPack/cmCPackPKGGenerator.cxx367
-rw-r--r--Source/CPack/cmCPackPKGGenerator.h96
-rw-r--r--Source/CPack/cmCPackPackageMakerGenerator.cxx584
-rw-r--r--Source/CPack/cmCPackPackageMakerGenerator.h60
-rw-r--r--Source/CPack/cmCPackProductBuildGenerator.cxx231
-rw-r--r--Source/CPack/cmCPackProductBuildGenerator.h58
-rw-r--r--Source/CPack/cmCPackRPMGenerator.cxx253
-rw-r--r--Source/CPack/cmCPackRPMGenerator.h78
-rw-r--r--Source/CPack/cmCPackSTGZGenerator.cxx125
-rw-r--r--Source/CPack/cmCPackSTGZGenerator.h40
-rw-r--r--Source/CPack/cmCPackTGZGenerator.cxx22
-rw-r--r--Source/CPack/cmCPackTGZGenerator.h36
-rw-r--r--Source/CPack/cmCPackTXZGenerator.cxx22
-rw-r--r--Source/CPack/cmCPackTXZGenerator.h36
-rw-r--r--Source/CPack/cmCPackTarBZip2Generator.cxx22
-rw-r--r--Source/CPack/cmCPackTarBZip2Generator.h35
-rw-r--r--Source/CPack/cmCPackTarCompressGenerator.cxx22
-rw-r--r--Source/CPack/cmCPackTarCompressGenerator.h35
-rw-r--r--Source/CPack/cmCPackZIPGenerator.cxx22
-rw-r--r--Source/CPack/cmCPackZIPGenerator.h36
-rw-r--r--Source/CPack/cpack.cxx429
-rw-r--r--Source/CPack/cygwin.readme69
80 files changed, 15238 insertions, 0 deletions
diff --git a/Source/CPack/IFW/cmCPackIFWGenerator.cxx b/Source/CPack/IFW/cmCPackIFWGenerator.cxx
new file mode 100644
index 0000000..4a5eb90
--- /dev/null
+++ b/Source/CPack/IFW/cmCPackIFWGenerator.cxx
@@ -0,0 +1,582 @@
+/*============================================================================
+ CMake - Cross Platform Makefile Generator
+ Copyright 2000-2009 Kitware, Inc., Insight Software Consortium
+
+ Distributed under the OSI-approved BSD License (the "License");
+ see accompanying file Copyright.txt for details.
+
+ This software is distributed WITHOUT ANY WARRANTY; without even the
+ implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
+ See the License for more information.
+============================================================================*/
+
+#include "cmCPackIFWGenerator.h"
+
+#include <CPack/cmCPackComponentGroup.h>
+#include <CPack/cmCPackLog.h>
+
+#include <cmsys/Directory.hxx>
+#include <cmsys/Glob.hxx>
+#include <cmsys/RegularExpression.hxx>
+#include <cmsys/SystemTools.hxx>
+
+#include <cmGeneratedFileStream.h>
+#include <cmGlobalGenerator.h>
+#include <cmMakefile.h>
+#include <cmSystemTools.h>
+#include <cmTimestamp.h>
+#include <cmVersionConfig.h>
+#include <cmXMLWriter.h>
+
+cmCPackIFWGenerator::cmCPackIFWGenerator()
+{
+}
+
+cmCPackIFWGenerator::~cmCPackIFWGenerator()
+{
+}
+
+bool cmCPackIFWGenerator::IsVersionLess(const char* version)
+{
+ return cmSystemTools::VersionCompare(cmSystemTools::OP_LESS,
+ FrameworkVersion.data(), version);
+}
+
+bool cmCPackIFWGenerator::IsVersionGreater(const char* version)
+{
+ return cmSystemTools::VersionCompare(cmSystemTools::OP_GREATER,
+ FrameworkVersion.data(), version);
+}
+
+bool cmCPackIFWGenerator::IsVersionEqual(const char* version)
+{
+ return cmSystemTools::VersionCompare(cmSystemTools::OP_EQUAL,
+ FrameworkVersion.data(), version);
+}
+
+int cmCPackIFWGenerator::PackageFiles()
+{
+ cmCPackLogger(cmCPackLog::LOG_OUTPUT, "- Configuration" << std::endl);
+
+ // Installer configuragion
+ Installer.GenerateInstallerFile();
+
+ // Packages configuration
+ Installer.GeneratePackageFiles();
+
+ std::string ifwTLD = this->GetOption("CPACK_TOPLEVEL_DIRECTORY");
+ std::string ifwTmpFile = ifwTLD;
+ ifwTmpFile += "/IFWOutput.log";
+
+ // Run repogen
+ if (!Installer.RemoteRepositories.empty()) {
+ std::string ifwCmd = RepoGen;
+
+ if (IsVersionLess("2.0.0")) {
+ ifwCmd += " -c " + this->toplevel + "/config/config.xml";
+ }
+
+ ifwCmd += " -p " + this->toplevel + "/packages";
+
+ if (!PkgsDirsVector.empty()) {
+ for (std::vector<std::string>::iterator it = PkgsDirsVector.begin();
+ it != PkgsDirsVector.end(); ++it) {
+ ifwCmd += " -p " + *it;
+ }
+ }
+
+ if (!OnlineOnly && !DownloadedPackages.empty()) {
+ ifwCmd += " -i ";
+ std::set<cmCPackIFWPackage*>::iterator it = DownloadedPackages.begin();
+ ifwCmd += (*it)->Name;
+ ++it;
+ while (it != DownloadedPackages.end()) {
+ ifwCmd += "," + (*it)->Name;
+ ++it;
+ }
+ }
+ ifwCmd += " " + this->toplevel + "/repository";
+ cmCPackLogger(cmCPackLog::LOG_VERBOSE, "Execute: " << ifwCmd << std::endl);
+ std::string output;
+ int retVal = 1;
+ cmCPackLogger(cmCPackLog::LOG_OUTPUT, "- Generate repository"
+ << std::endl);
+ bool res = cmSystemTools::RunSingleCommand(ifwCmd.c_str(), &output,
+ &output, &retVal, CM_NULLPTR,
+ this->GeneratorVerbose, 0);
+ if (!res || retVal) {
+ cmGeneratedFileStream ofs(ifwTmpFile.c_str());
+ ofs << "# Run command: " << ifwCmd << std::endl
+ << "# Output:" << std::endl
+ << output << std::endl;
+ cmCPackLogger(cmCPackLog::LOG_ERROR, "Problem running IFW command: "
+ << ifwCmd << std::endl
+ << "Please check " << ifwTmpFile << " for errors"
+ << std::endl);
+ return 0;
+ }
+
+ if (!Repository.RepositoryUpdate.empty() &&
+ !Repository.PatchUpdatesXml()) {
+ cmCPackLogger(cmCPackLog::LOG_WARNING, "Problem patch IFW \"Updates\" "
+ << "file: " << this->toplevel + "/repository/Updates.xml"
+ << std::endl);
+ }
+
+ cmCPackLogger(cmCPackLog::LOG_OUTPUT, "- repository: "
+ << this->toplevel << "/repository generated" << std::endl);
+ }
+
+ // Run binary creator
+ {
+ std::string ifwCmd = BinCreator;
+ ifwCmd += " -c " + this->toplevel + "/config/config.xml";
+ ifwCmd += " -p " + this->toplevel + "/packages";
+
+ if (!PkgsDirsVector.empty()) {
+ for (std::vector<std::string>::iterator it = PkgsDirsVector.begin();
+ it != PkgsDirsVector.end(); ++it) {
+ ifwCmd += " -p " + *it;
+ }
+ }
+
+ if (OnlineOnly) {
+ ifwCmd += " --online-only";
+ } else if (!DownloadedPackages.empty() &&
+ !Installer.RemoteRepositories.empty()) {
+ ifwCmd += " -e ";
+ std::set<cmCPackIFWPackage*>::iterator it = DownloadedPackages.begin();
+ ifwCmd += (*it)->Name;
+ ++it;
+ while (it != DownloadedPackages.end()) {
+ ifwCmd += "," + (*it)->Name;
+ ++it;
+ }
+ } else if (!DependentPackages.empty()) {
+ ifwCmd += " -i ";
+ // Binary
+ std::set<cmCPackIFWPackage*>::iterator bit = BinaryPackages.begin();
+ while (bit != BinaryPackages.end()) {
+ ifwCmd += (*bit)->Name + ",";
+ ++bit;
+ }
+ // Depend
+ DependenceMap::iterator it = DependentPackages.begin();
+ ifwCmd += it->second.Name;
+ ++it;
+ while (it != DependentPackages.end()) {
+ ifwCmd += "," + it->second.Name;
+ ++it;
+ }
+ }
+ // TODO: set correct name for multipackages
+ if (!this->packageFileNames.empty()) {
+ ifwCmd += " " + packageFileNames[0];
+ } else {
+ ifwCmd += " installer";
+ }
+ cmCPackLogger(cmCPackLog::LOG_VERBOSE, "Execute: " << ifwCmd << std::endl);
+ std::string output;
+ int retVal = 1;
+ cmCPackLogger(cmCPackLog::LOG_OUTPUT, "- Generate package" << std::endl);
+ bool res = cmSystemTools::RunSingleCommand(ifwCmd.c_str(), &output,
+ &output, &retVal, CM_NULLPTR,
+ this->GeneratorVerbose, 0);
+ if (!res || retVal) {
+ cmGeneratedFileStream ofs(ifwTmpFile.c_str());
+ ofs << "# Run command: " << ifwCmd << std::endl
+ << "# Output:" << std::endl
+ << output << std::endl;
+ cmCPackLogger(cmCPackLog::LOG_ERROR, "Problem running IFW command: "
+ << ifwCmd << std::endl
+ << "Please check " << ifwTmpFile << " for errors"
+ << std::endl);
+ return 0;
+ }
+ }
+
+ return 1;
+}
+
+const char* cmCPackIFWGenerator::GetPackagingInstallPrefix()
+{
+ const char* defPrefix = cmCPackGenerator::GetPackagingInstallPrefix();
+
+ std::string tmpPref = defPrefix ? defPrefix : "";
+
+ if (this->Components.empty()) {
+ tmpPref += "packages/" + GetRootPackageName() + "/data";
+ }
+
+ this->SetOption("CPACK_IFW_PACKAGING_INSTALL_PREFIX", tmpPref.c_str());
+
+ return this->GetOption("CPACK_IFW_PACKAGING_INSTALL_PREFIX");
+}
+
+const char* cmCPackIFWGenerator::GetOutputExtension()
+{
+ return ExecutableSuffix.c_str();
+}
+
+int cmCPackIFWGenerator::InitializeInternal()
+{
+ // Search Qt Installer Framework tools
+
+ const std::string BinCreatorOpt = "CPACK_IFW_BINARYCREATOR_EXECUTABLE";
+ const std::string RepoGenOpt = "CPACK_IFW_REPOGEN_EXECUTABLE";
+ const std::string FrameworkVersionOpt = "CPACK_IFW_FRAMEWORK_VERSION";
+
+ if (!this->IsSet(BinCreatorOpt) || !this->IsSet(RepoGenOpt) ||
+ !this->IsSet(FrameworkVersionOpt)) {
+ this->ReadListFile("CPackIFW.cmake");
+ }
+
+ // Look 'binarycreator' executable (needs)
+
+ const char* BinCreatorStr = this->GetOption(BinCreatorOpt);
+ if (!BinCreatorStr || cmSystemTools::IsNOTFOUND(BinCreatorStr)) {
+ BinCreator = "";
+ } else {
+ BinCreator = BinCreatorStr;
+ }
+
+ if (BinCreator.empty()) {
+ cmCPackLogger(cmCPackLog::LOG_ERROR,
+ "Cannot find QtIFW compiler \"binarycreator\": "
+ "likely it is not installed, or not in your PATH"
+ << std::endl);
+ return 0;
+ }
+
+ // Look 'repogen' executable (optional)
+
+ const char* RepoGenStr = this->GetOption(RepoGenOpt);
+ if (!RepoGenStr || cmSystemTools::IsNOTFOUND(RepoGenStr)) {
+ RepoGen = "";
+ } else {
+ RepoGen = RepoGenStr;
+ }
+
+ // Framework version
+ if (const char* FrameworkVersionSrt = this->GetOption(FrameworkVersionOpt)) {
+ FrameworkVersion = FrameworkVersionSrt;
+ } else {
+ FrameworkVersion = "1.9.9";
+ }
+
+ // Variables that Change Behavior
+
+ // Resolve duplicate names
+ ResolveDuplicateNames = this->IsOn("CPACK_IFW_RESOLVE_DUPLICATE_NAMES");
+
+ // Additional packages dirs
+ PkgsDirsVector.clear();
+ if (const char* dirs = this->GetOption("CPACK_IFW_PACKAGES_DIRECTORIES")) {
+ cmSystemTools::ExpandListArgument(dirs, PkgsDirsVector);
+ }
+
+ // Installer
+ Installer.Generator = this;
+ Installer.ConfigureFromOptions();
+
+ // Repository
+ Repository.Generator = this;
+ Repository.Name = "Unspecified";
+ if (const char* site = this->GetOption("CPACK_DOWNLOAD_SITE")) {
+ Repository.Url = site;
+ Installer.RemoteRepositories.push_back(&Repository);
+ }
+
+ // Repositories
+ if (const char* RepoAllStr = this->GetOption("CPACK_IFW_REPOSITORIES_ALL")) {
+ std::vector<std::string> RepoAllVector;
+ cmSystemTools::ExpandListArgument(RepoAllStr, RepoAllVector);
+ for (std::vector<std::string>::iterator rit = RepoAllVector.begin();
+ rit != RepoAllVector.end(); ++rit) {
+ GetRepository(*rit);
+ }
+ }
+
+ if (const char* ifwDownloadAll = this->GetOption("CPACK_IFW_DOWNLOAD_ALL")) {
+ OnlineOnly = cmSystemTools::IsOn(ifwDownloadAll);
+ } else if (const char* cpackDownloadAll =
+ this->GetOption("CPACK_DOWNLOAD_ALL")) {
+ OnlineOnly = cmSystemTools::IsOn(cpackDownloadAll);
+ } else {
+ OnlineOnly = false;
+ }
+
+ if (!Installer.RemoteRepositories.empty() && RepoGen.empty()) {
+ cmCPackLogger(cmCPackLog::LOG_ERROR,
+ "Cannot find QtIFW repository generator \"repogen\": "
+ "likely it is not installed, or not in your PATH"
+ << std::endl);
+ return 0;
+ }
+
+ // Executable suffix
+ if (const char* optExeSuffix = this->GetOption("CMAKE_EXECUTABLE_SUFFIX")) {
+ ExecutableSuffix = optExeSuffix;
+ if (ExecutableSuffix.empty()) {
+ std::string sysName(this->GetOption("CMAKE_SYSTEM_NAME"));
+ if (sysName == "Linux") {
+ ExecutableSuffix = ".run";
+ }
+ }
+ } else {
+ ExecutableSuffix = cmCPackGenerator::GetOutputExtension();
+ }
+
+ return this->Superclass::InitializeInternal();
+}
+
+std::string cmCPackIFWGenerator::GetComponentInstallDirNameSuffix(
+ const std::string& componentName)
+{
+ const std::string prefix = "packages/";
+ const std::string suffix = "/data";
+
+ if (componentPackageMethod == ONE_PACKAGE) {
+ return std::string(prefix + GetRootPackageName() + suffix);
+ }
+
+ return prefix + GetComponentPackageName(&Components[componentName]) + suffix;
+}
+
+cmCPackComponent* cmCPackIFWGenerator::GetComponent(
+ const std::string& projectName, const std::string& componentName)
+{
+ ComponentsMap::iterator cit = Components.find(componentName);
+ if (cit != Components.end()) {
+ return &(cit->second);
+ }
+
+ cmCPackComponent* component =
+ cmCPackGenerator::GetComponent(projectName, componentName);
+ if (!component) {
+ return component;
+ }
+
+ std::string name = GetComponentPackageName(component);
+ PackagesMap::iterator pit = Packages.find(name);
+ if (pit != Packages.end()) {
+ return component;
+ }
+
+ cmCPackIFWPackage* package = &Packages[name];
+ package->Name = name;
+ package->Generator = this;
+ if (package->ConfigureFromComponent(component)) {
+ package->Installer = &Installer;
+ Installer.Packages.insert(
+ std::pair<std::string, cmCPackIFWPackage*>(name, package));
+ ComponentPackages.insert(
+ std::pair<cmCPackComponent*, cmCPackIFWPackage*>(component, package));
+ if (component->IsDownloaded) {
+ DownloadedPackages.insert(package);
+ } else {
+ BinaryPackages.insert(package);
+ }
+ } else {
+ Packages.erase(name);
+ cmCPackLogger(cmCPackLog::LOG_ERROR, "Cannot configure package \""
+ << name << "\" for component \"" << component->Name << "\""
+ << std::endl);
+ }
+
+ return component;
+}
+
+cmCPackComponentGroup* cmCPackIFWGenerator::GetComponentGroup(
+ const std::string& projectName, const std::string& groupName)
+{
+ cmCPackComponentGroup* group =
+ cmCPackGenerator::GetComponentGroup(projectName, groupName);
+ if (!group) {
+ return group;
+ }
+
+ std::string name = GetGroupPackageName(group);
+ PackagesMap::iterator pit = Packages.find(name);
+ if (pit != Packages.end()) {
+ return group;
+ }
+
+ cmCPackIFWPackage* package = &Packages[name];
+ package->Name = name;
+ package->Generator = this;
+ if (package->ConfigureFromGroup(group)) {
+ package->Installer = &Installer;
+ Installer.Packages.insert(
+ std::pair<std::string, cmCPackIFWPackage*>(name, package));
+ GroupPackages.insert(
+ std::pair<cmCPackComponentGroup*, cmCPackIFWPackage*>(group, package));
+ BinaryPackages.insert(package);
+ } else {
+ Packages.erase(name);
+ cmCPackLogger(cmCPackLog::LOG_ERROR, "Cannot configure package \""
+ << name << "\" for component group \"" << group->Name
+ << "\"" << std::endl);
+ }
+ return group;
+}
+
+enum cmCPackGenerator::CPackSetDestdirSupport
+cmCPackIFWGenerator::SupportsSetDestdir() const
+{
+ return cmCPackGenerator::SETDESTDIR_SHOULD_NOT_BE_USED;
+}
+
+bool cmCPackIFWGenerator::SupportsAbsoluteDestination() const
+{
+ return false;
+}
+
+bool cmCPackIFWGenerator::SupportsComponentInstallation() const
+{
+ return true;
+}
+
+bool cmCPackIFWGenerator::IsOnePackage() const
+{
+ return componentPackageMethod == ONE_PACKAGE;
+}
+
+std::string cmCPackIFWGenerator::GetRootPackageName()
+{
+ // Default value
+ std::string name = "root";
+ if (const char* optIFW_PACKAGE_GROUP =
+ this->GetOption("CPACK_IFW_PACKAGE_GROUP")) {
+ // Configure from root group
+ cmCPackIFWPackage package;
+ package.Generator = this;
+ package.ConfigureFromGroup(optIFW_PACKAGE_GROUP);
+ name = package.Name;
+ } else if (const char* optIFW_PACKAGE_NAME =
+ this->GetOption("CPACK_IFW_PACKAGE_NAME")) {
+ // Configure from root package name
+ name = optIFW_PACKAGE_NAME;
+ } else if (const char* optPACKAGE_NAME =
+ this->GetOption("CPACK_PACKAGE_NAME")) {
+ // Configure from package name
+ name = optPACKAGE_NAME;
+ }
+ return name;
+}
+
+std::string cmCPackIFWGenerator::GetGroupPackageName(
+ cmCPackComponentGroup* group) const
+{
+ std::string name;
+ if (!group) {
+ return name;
+ }
+ if (cmCPackIFWPackage* package = GetGroupPackage(group)) {
+ return package->Name;
+ }
+ const char* option =
+ GetOption("CPACK_IFW_COMPONENT_GROUP_" +
+ cmsys::SystemTools::UpperCase(group->Name) + "_NAME");
+ name = option ? option : group->Name;
+ if (group->ParentGroup) {
+ cmCPackIFWPackage* package = GetGroupPackage(group->ParentGroup);
+ bool dot = !ResolveDuplicateNames;
+ if (dot && name.substr(0, package->Name.size()) == package->Name) {
+ dot = false;
+ }
+ if (dot) {
+ name = package->Name + "." + name;
+ }
+ }
+ return name;
+}
+
+std::string cmCPackIFWGenerator::GetComponentPackageName(
+ cmCPackComponent* component) const
+{
+ std::string name;
+ if (!component) {
+ return name;
+ }
+ if (cmCPackIFWPackage* package = GetComponentPackage(component)) {
+ return package->Name;
+ }
+ std::string prefix = "CPACK_IFW_COMPONENT_" +
+ cmsys::SystemTools::UpperCase(component->Name) + "_";
+ const char* option = GetOption(prefix + "NAME");
+ name = option ? option : component->Name;
+ if (component->Group) {
+ cmCPackIFWPackage* package = GetGroupPackage(component->Group);
+ if ((componentPackageMethod == ONE_PACKAGE_PER_GROUP) ||
+ IsOn(prefix + "COMMON")) {
+ return package->Name;
+ }
+ bool dot = !ResolveDuplicateNames;
+ if (dot && name.substr(0, package->Name.size()) == package->Name) {
+ dot = false;
+ }
+ if (dot) {
+ name = package->Name + "." + name;
+ }
+ }
+ return name;
+}
+
+cmCPackIFWPackage* cmCPackIFWGenerator::GetGroupPackage(
+ cmCPackComponentGroup* group) const
+{
+ std::map<cmCPackComponentGroup*, cmCPackIFWPackage*>::const_iterator pit =
+ GroupPackages.find(group);
+ return pit != GroupPackages.end() ? pit->second : CM_NULLPTR;
+}
+
+cmCPackIFWPackage* cmCPackIFWGenerator::GetComponentPackage(
+ cmCPackComponent* component) const
+{
+ std::map<cmCPackComponent*, cmCPackIFWPackage*>::const_iterator pit =
+ ComponentPackages.find(component);
+ return pit != ComponentPackages.end() ? pit->second : CM_NULLPTR;
+}
+
+cmCPackIFWRepository* cmCPackIFWGenerator::GetRepository(
+ const std::string& repositoryName)
+{
+ RepositoriesMap::iterator rit = Repositories.find(repositoryName);
+ if (rit != Repositories.end()) {
+ return &(rit->second);
+ }
+
+ cmCPackIFWRepository* repository = &Repositories[repositoryName];
+ repository->Name = repositoryName;
+ repository->Generator = this;
+ if (repository->ConfigureFromOptions()) {
+ if (repository->Update == cmCPackIFWRepository::None) {
+ Installer.RemoteRepositories.push_back(repository);
+ } else {
+ Repository.RepositoryUpdate.push_back(repository);
+ }
+ } else {
+ Repositories.erase(repositoryName);
+ repository = CM_NULLPTR;
+ cmCPackLogger(cmCPackLog::LOG_WARNING, "Invalid repository \""
+ << repositoryName << "\""
+ << " configuration. Repository will be skipped."
+ << std::endl);
+ }
+ return repository;
+}
+
+void cmCPackIFWGenerator::WriteGeneratedByToStrim(cmXMLWriter& xout)
+{
+ std::ostringstream comment;
+ comment << "Generated by CPack " << CMake_VERSION << " IFW generator "
+ << "for QtIFW ";
+ if (IsVersionLess("2.0")) {
+ comment << "less 2.0";
+ } else {
+ comment << FrameworkVersion;
+ }
+ comment << " tools at " << cmTimestamp().CurrentTime("", true);
+ xout.Comment(comment.str().c_str());
+}
diff --git a/Source/CPack/IFW/cmCPackIFWGenerator.h b/Source/CPack/IFW/cmCPackIFWGenerator.h
new file mode 100644
index 0000000..12f2ca6
--- /dev/null
+++ b/Source/CPack/IFW/cmCPackIFWGenerator.h
@@ -0,0 +1,167 @@
+/*============================================================================
+ CMake - Cross Platform Makefile Generator
+ Copyright 2000-2009 Kitware, Inc., Insight Software Consortium
+
+ Distributed under the OSI-approved BSD License (the "License");
+ see accompanying file Copyright.txt for details.
+
+ This software is distributed WITHOUT ANY WARRANTY; without even the
+ implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
+ See the License for more information.
+============================================================================*/
+
+#ifndef cmCPackIFWGenerator_h
+#define cmCPackIFWGenerator_h
+
+#include <CPack/cmCPackGenerator.h>
+
+#include "cmCPackIFWInstaller.h"
+#include "cmCPackIFWPackage.h"
+#include "cmCPackIFWRepository.h"
+
+class cmXMLWriter;
+
+/** \class cmCPackIFWGenerator
+ * \brief A generator for Qt Installer Framework tools
+ *
+ * http://qt-project.org/doc/qtinstallerframework/index.html
+ */
+class cmCPackIFWGenerator : public cmCPackGenerator
+{
+public:
+ cmCPackTypeMacro(cmCPackIFWGenerator, cmCPackGenerator);
+
+ typedef std::map<std::string, cmCPackIFWPackage> PackagesMap;
+ typedef std::map<std::string, cmCPackIFWRepository> RepositoriesMap;
+ typedef std::map<std::string, cmCPackComponent> ComponentsMap;
+ typedef std::map<std::string, cmCPackComponentGroup> ComponentGoupsMap;
+ typedef std::map<std::string, cmCPackIFWPackage::DependenceStruct>
+ DependenceMap;
+
+ /**
+ * Construct IFW generator
+ */
+ cmCPackIFWGenerator();
+
+ /**
+ * Destruct IFW generator
+ */
+ ~cmCPackIFWGenerator() CM_OVERRIDE;
+
+ /**
+ * Compare \a version with QtIFW framework version
+ */
+ bool IsVersionLess(const char* version);
+
+ /**
+ * Compare \a version with QtIFW framework version
+ */
+ bool IsVersionGreater(const char* version);
+
+ /**
+ * Compare \a version with QtIFW framework version
+ */
+ bool IsVersionEqual(const char* version);
+
+protected:
+ // cmCPackGenerator reimplementation
+
+ /**
+ * @brief Initialize generator
+ * @return 0 on failure
+ */
+ int InitializeInternal() CM_OVERRIDE;
+ int PackageFiles() CM_OVERRIDE;
+ const char* GetPackagingInstallPrefix() CM_OVERRIDE;
+
+ /**
+ * @brief Extension of binary installer
+ * @return Executable suffix or value from default implementation
+ */
+ const char* GetOutputExtension() CM_OVERRIDE;
+
+ std::string GetComponentInstallDirNameSuffix(
+ const std::string& componentName) CM_OVERRIDE;
+
+ /**
+ * @brief Get Component
+ * @param projectName Project name
+ * @param componentName Component name
+ *
+ * This method calls the base implementation.
+ *
+ * @return Pointer to component
+ */
+ cmCPackComponent* GetComponent(const std::string& projectName,
+ const std::string& componentName) CM_OVERRIDE;
+
+ /**
+ * @brief Get group of component
+ * @param projectName Project name
+ * @param groupName Component group name
+ *
+ * This method calls the base implementation.
+ *
+ * @return Pointer to component group
+ */
+ cmCPackComponentGroup* GetComponentGroup(
+ const std::string& projectName, const std::string& groupName) CM_OVERRIDE;
+
+ enum cmCPackGenerator::CPackSetDestdirSupport SupportsSetDestdir() const
+ CM_OVERRIDE;
+ bool SupportsAbsoluteDestination() const CM_OVERRIDE;
+ bool SupportsComponentInstallation() const CM_OVERRIDE;
+
+protected:
+ // Methods
+
+ bool IsOnePackage() const;
+
+ std::string GetRootPackageName();
+
+ std::string GetGroupPackageName(cmCPackComponentGroup* group) const;
+ std::string GetComponentPackageName(cmCPackComponent* component) const;
+
+ cmCPackIFWPackage* GetGroupPackage(cmCPackComponentGroup* group) const;
+ cmCPackIFWPackage* GetComponentPackage(cmCPackComponent* component) const;
+
+ cmCPackIFWRepository* GetRepository(const std::string& repositoryName);
+
+ void WriteGeneratedByToStrim(cmXMLWriter& xout);
+
+protected:
+ // Data
+
+ friend class cmCPackIFWPackage;
+ friend class cmCPackIFWInstaller;
+ friend class cmCPackIFWRepository;
+
+ // Installer
+ cmCPackIFWInstaller Installer;
+ // Repository
+ cmCPackIFWRepository Repository;
+ // Collection of packages
+ PackagesMap Packages;
+ // Collection of repositories
+ RepositoriesMap Repositories;
+ // Collection of binary packages
+ std::set<cmCPackIFWPackage*> BinaryPackages;
+ // Collection of downloaded packages
+ std::set<cmCPackIFWPackage*> DownloadedPackages;
+ // Dependent packages
+ DependenceMap DependentPackages;
+ std::map<cmCPackComponent*, cmCPackIFWPackage*> ComponentPackages;
+ std::map<cmCPackComponentGroup*, cmCPackIFWPackage*> GroupPackages;
+
+private:
+ std::string RepoGen;
+ std::string BinCreator;
+ std::string FrameworkVersion;
+ std::string ExecutableSuffix;
+
+ bool OnlineOnly;
+ bool ResolveDuplicateNames;
+ std::vector<std::string> PkgsDirsVector;
+};
+
+#endif
diff --git a/Source/CPack/IFW/cmCPackIFWInstaller.cxx b/Source/CPack/IFW/cmCPackIFWInstaller.cxx
new file mode 100644
index 0000000..13a3613
--- /dev/null
+++ b/Source/CPack/IFW/cmCPackIFWInstaller.cxx
@@ -0,0 +1,349 @@
+/*============================================================================
+ CMake - Cross Platform Makefile Generator
+ Copyright 2000-2009 Kitware, Inc., Insight Software Consortium
+
+ Distributed under the OSI-approved BSD License (the "License");
+ see accompanying file Copyright.txt for details.
+
+ This software is distributed WITHOUT ANY WARRANTY; without even the
+ implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
+ See the License for more information.
+============================================================================*/
+
+#include "cmCPackIFWInstaller.h"
+
+#include "cmCPackIFWGenerator.h"
+
+#include <CPack/cmCPackLog.h>
+
+#include <cmGeneratedFileStream.h>
+#include <cmXMLWriter.h>
+
+#ifdef cmCPackLogger
+#undef cmCPackLogger
+#endif
+#define cmCPackLogger(logType, msg) \
+ do { \
+ std::ostringstream cmCPackLog_msg; \
+ cmCPackLog_msg << msg; \
+ if (Generator) { \
+ Generator->Logger->Log(logType, __FILE__, __LINE__, \
+ cmCPackLog_msg.str().c_str()); \
+ } \
+ } while (0)
+
+cmCPackIFWInstaller::cmCPackIFWInstaller()
+ : Generator(CM_NULLPTR)
+{
+}
+
+const char* cmCPackIFWInstaller::GetOption(const std::string& op) const
+{
+ return Generator ? Generator->GetOption(op) : CM_NULLPTR;
+}
+
+bool cmCPackIFWInstaller::IsOn(const std::string& op) const
+{
+ return Generator ? Generator->IsOn(op) : false;
+}
+
+bool cmCPackIFWInstaller::IsVersionLess(const char* version)
+{
+ return Generator ? Generator->IsVersionLess(version) : false;
+}
+
+bool cmCPackIFWInstaller::IsVersionGreater(const char* version)
+{
+ return Generator ? Generator->IsVersionGreater(version) : false;
+}
+
+bool cmCPackIFWInstaller::IsVersionEqual(const char* version)
+{
+ return Generator ? Generator->IsVersionEqual(version) : false;
+}
+
+void cmCPackIFWInstaller::ConfigureFromOptions()
+{
+ // Name;
+ if (const char* optIFW_PACKAGE_NAME =
+ this->GetOption("CPACK_IFW_PACKAGE_NAME")) {
+ Name = optIFW_PACKAGE_NAME;
+ } else if (const char* optPACKAGE_NAME =
+ this->GetOption("CPACK_PACKAGE_NAME")) {
+ Name = optPACKAGE_NAME;
+ } else {
+ Name = "Your package";
+ }
+
+ // Title;
+ if (const char* optIFW_PACKAGE_TITLE =
+ GetOption("CPACK_IFW_PACKAGE_TITLE")) {
+ Title = optIFW_PACKAGE_TITLE;
+ } else if (const char* optPACKAGE_DESCRIPTION_SUMMARY =
+ GetOption("CPACK_PACKAGE_DESCRIPTION_SUMMARY")) {
+ Title = optPACKAGE_DESCRIPTION_SUMMARY;
+ } else {
+ Title = "Your package description";
+ }
+
+ // Version;
+ if (const char* option = GetOption("CPACK_PACKAGE_VERSION")) {
+ Version = option;
+ } else {
+ Version = "1.0.0";
+ }
+
+ // Publisher
+ if (const char* optIFW_PACKAGE_PUBLISHER =
+ GetOption("CPACK_IFW_PACKAGE_PUBLISHER")) {
+ Publisher = optIFW_PACKAGE_PUBLISHER;
+ } else if (const char* optPACKAGE_VENDOR =
+ GetOption("CPACK_PACKAGE_VENDOR")) {
+ Publisher = optPACKAGE_VENDOR;
+ }
+
+ // ProductUrl
+ if (const char* option = GetOption("CPACK_IFW_PRODUCT_URL")) {
+ ProductUrl = option;
+ }
+
+ // ApplicationIcon
+ if (const char* option = GetOption("CPACK_IFW_PACKAGE_ICON")) {
+ if (cmSystemTools::FileExists(option)) {
+ InstallerApplicationIcon = option;
+ } else {
+ // TODO: implement warning
+ }
+ }
+
+ // WindowIcon
+ if (const char* option = GetOption("CPACK_IFW_PACKAGE_WINDOW_ICON")) {
+ if (cmSystemTools::FileExists(option)) {
+ InstallerWindowIcon = option;
+ } else {
+ // TODO: implement warning
+ }
+ }
+
+ // Logo
+ if (const char* option = GetOption("CPACK_IFW_PACKAGE_LOGO")) {
+ if (cmSystemTools::FileExists(option)) {
+ Logo = option;
+ } else {
+ // TODO: implement warning
+ }
+ }
+
+ // Start menu
+ if (const char* optIFW_START_MENU_DIR =
+ this->GetOption("CPACK_IFW_PACKAGE_START_MENU_DIRECTORY")) {
+ StartMenuDir = optIFW_START_MENU_DIR;
+ } else {
+ StartMenuDir = Name;
+ }
+
+ // Default target directory for installation
+ if (const char* optIFW_TARGET_DIRECTORY =
+ GetOption("CPACK_IFW_TARGET_DIRECTORY")) {
+ TargetDir = optIFW_TARGET_DIRECTORY;
+ } else if (const char* optPACKAGE_INSTALL_DIRECTORY =
+ GetOption("CPACK_PACKAGE_INSTALL_DIRECTORY")) {
+ TargetDir = "@ApplicationsDir@/";
+ TargetDir += optPACKAGE_INSTALL_DIRECTORY;
+ } else {
+ TargetDir = "@RootDir@/usr/local";
+ }
+
+ // Default target directory for installation with administrator rights
+ if (const char* option = GetOption("CPACK_IFW_ADMIN_TARGET_DIRECTORY")) {
+ AdminTargetDir = option;
+ }
+
+ // Maintenance tool
+ if (const char* optIFW_MAINTENANCE_TOOL =
+ this->GetOption("CPACK_IFW_PACKAGE_MAINTENANCE_TOOL_NAME")) {
+ MaintenanceToolName = optIFW_MAINTENANCE_TOOL;
+ }
+
+ // Maintenance tool ini file
+ if (const char* optIFW_MAINTENANCE_TOOL_INI =
+ this->GetOption("CPACK_IFW_PACKAGE_MAINTENANCE_TOOL_INI_FILE")) {
+ MaintenanceToolIniFile = optIFW_MAINTENANCE_TOOL_INI;
+ }
+
+ // Allow non-ASCII characters
+ if (this->GetOption("CPACK_IFW_PACKAGE_ALLOW_NON_ASCII_CHARACTERS")) {
+ if (IsOn("CPACK_IFW_PACKAGE_ALLOW_NON_ASCII_CHARACTERS")) {
+ AllowNonAsciiCharacters = "true";
+ } else {
+ AllowNonAsciiCharacters = "false";
+ }
+ }
+
+ // Space in path
+ if (this->GetOption("CPACK_IFW_PACKAGE_ALLOW_SPACE_IN_PATH")) {
+ if (IsOn("CPACK_IFW_PACKAGE_ALLOW_SPACE_IN_PATH")) {
+ AllowSpaceInPath = "true";
+ } else {
+ AllowSpaceInPath = "false";
+ }
+ }
+
+ // Control script
+ if (const char* optIFW_CONTROL_SCRIPT =
+ this->GetOption("CPACK_IFW_PACKAGE_CONTROL_SCRIPT")) {
+ ControlScript = optIFW_CONTROL_SCRIPT;
+ }
+}
+
+void cmCPackIFWInstaller::GenerateInstallerFile()
+{
+ // Lazy directory initialization
+ if (Directory.empty() && Generator) {
+ Directory = Generator->toplevel;
+ }
+
+ // Output stream
+ cmGeneratedFileStream fout((Directory + "/config/config.xml").data());
+ cmXMLWriter xout(fout);
+
+ xout.StartDocument();
+
+ WriteGeneratedByToStrim(xout);
+
+ xout.StartElement("Installer");
+
+ xout.Element("Name", Name);
+ xout.Element("Version", Version);
+ xout.Element("Title", Title);
+
+ if (!Publisher.empty()) {
+ xout.Element("Publisher", Publisher);
+ }
+
+ if (!ProductUrl.empty()) {
+ xout.Element("ProductUrl", ProductUrl);
+ }
+
+ // ApplicationIcon
+ if (!InstallerApplicationIcon.empty()) {
+ std::string name =
+ cmSystemTools::GetFilenameName(InstallerApplicationIcon);
+ std::string path = Directory + "/config/" + name;
+ name = cmSystemTools::GetFilenameWithoutExtension(name);
+ cmsys::SystemTools::CopyFileIfDifferent(InstallerApplicationIcon.data(),
+ path.data());
+ xout.Element("InstallerApplicationIcon", name);
+ }
+
+ // WindowIcon
+ if (!InstallerWindowIcon.empty()) {
+ std::string name = cmSystemTools::GetFilenameName(InstallerWindowIcon);
+ std::string path = Directory + "/config/" + name;
+ cmsys::SystemTools::CopyFileIfDifferent(InstallerWindowIcon.data(),
+ path.data());
+ xout.Element("InstallerWindowIcon", name);
+ }
+
+ // Logo
+ if (!Logo.empty()) {
+ std::string name = cmSystemTools::GetFilenameName(Logo);
+ std::string path = Directory + "/config/" + name;
+ cmsys::SystemTools::CopyFileIfDifferent(Logo.data(), path.data());
+ xout.Element("Logo", name);
+ }
+
+ // Start menu
+ if (!IsVersionLess("2.0")) {
+ xout.Element("StartMenuDir", StartMenuDir);
+ }
+
+ // Target dir
+ if (!TargetDir.empty()) {
+ xout.Element("TargetDir", TargetDir);
+ }
+
+ // Admin target dir
+ if (!AdminTargetDir.empty()) {
+ xout.Element("AdminTargetDir", AdminTargetDir);
+ }
+
+ // Remote repositories
+ if (!RemoteRepositories.empty()) {
+ xout.StartElement("RemoteRepositories");
+ for (RepositoriesVector::iterator rit = RemoteRepositories.begin();
+ rit != RemoteRepositories.end(); ++rit) {
+ (*rit)->WriteRepositoryConfig(xout);
+ }
+ xout.EndElement();
+ }
+
+ // Maintenance tool
+ if (!IsVersionLess("2.0") && !MaintenanceToolName.empty()) {
+ xout.Element("MaintenanceToolName", MaintenanceToolName);
+ }
+
+ // Maintenance tool ini file
+ if (!IsVersionLess("2.0") && !MaintenanceToolIniFile.empty()) {
+ xout.Element("MaintenanceToolIniFile", MaintenanceToolIniFile);
+ }
+
+ // Different allows
+ if (IsVersionLess("2.0")) {
+ // CPack IFW default policy
+ xout.Comment("CPack IFW default policy for QtIFW less 2.0");
+ xout.Element("AllowNonAsciiCharacters", "true");
+ xout.Element("AllowSpaceInPath", "true");
+ } else {
+ if (!AllowNonAsciiCharacters.empty()) {
+ xout.Element("AllowNonAsciiCharacters", AllowNonAsciiCharacters);
+ }
+ if (!AllowSpaceInPath.empty()) {
+ xout.Element("AllowSpaceInPath", AllowSpaceInPath);
+ }
+ }
+
+ // Control script (copy to config dir)
+ if (!IsVersionLess("2.0") && !ControlScript.empty()) {
+ std::string name = cmSystemTools::GetFilenameName(ControlScript);
+ std::string path = Directory + "/config/" + name;
+ cmsys::SystemTools::CopyFileIfDifferent(ControlScript.data(), path.data());
+ xout.Element("ControlScript", name);
+ }
+
+ xout.EndElement();
+ xout.EndDocument();
+}
+
+void cmCPackIFWInstaller::GeneratePackageFiles()
+{
+ if (Packages.empty() || Generator->IsOnePackage()) {
+ // Generate default package
+ cmCPackIFWPackage package;
+ package.Generator = Generator;
+ package.Installer = this;
+ // Check package group
+ if (const char* option = GetOption("CPACK_IFW_PACKAGE_GROUP")) {
+ package.ConfigureFromGroup(option);
+ package.ForcedInstallation = "true";
+ } else {
+ package.ConfigureFromOptions();
+ }
+ package.GeneratePackageFile();
+ return;
+ }
+
+ // Generate packages meta information
+ for (PackagesMap::iterator pit = Packages.begin(); pit != Packages.end();
+ ++pit) {
+ cmCPackIFWPackage* package = pit->second;
+ package->GeneratePackageFile();
+ }
+}
+
+void cmCPackIFWInstaller::WriteGeneratedByToStrim(cmXMLWriter& xout)
+{
+ if (Generator) {
+ Generator->WriteGeneratedByToStrim(xout);
+ }
+}
diff --git a/Source/CPack/IFW/cmCPackIFWInstaller.h b/Source/CPack/IFW/cmCPackIFWInstaller.h
new file mode 100644
index 0000000..3170116
--- /dev/null
+++ b/Source/CPack/IFW/cmCPackIFWInstaller.h
@@ -0,0 +1,118 @@
+/*============================================================================
+ CMake - Cross Platform Makefile Generator
+ Copyright 2000-2009 Kitware, Inc., Insight Software Consortium
+
+ Distributed under the OSI-approved BSD License (the "License");
+ see accompanying file Copyright.txt for details.
+
+ This software is distributed WITHOUT ANY WARRANTY; without even the
+ implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
+ See the License for more information.
+============================================================================*/
+
+#ifndef cmCPackIFWInstaller_h
+#define cmCPackIFWInstaller_h
+
+#include <cmStandardIncludes.h>
+
+class cmCPackIFWPackage;
+class cmCPackIFWGenerator;
+class cmCPackIFWRepository;
+class cmXMLWriter;
+
+/** \class cmCPackIFWInstaller
+ * \brief A binary installer to be created CPack IFW generator
+ */
+class cmCPackIFWInstaller
+{
+public:
+ // Types
+
+ typedef std::map<std::string, cmCPackIFWPackage*> PackagesMap;
+ typedef std::vector<cmCPackIFWRepository*> RepositoriesVector;
+
+public:
+ // Constructor
+
+ /**
+ * Construct installer
+ */
+ cmCPackIFWInstaller();
+
+public:
+ // Configuration
+
+ /// Name of the product being installed
+ std::string Name;
+
+ /// Version number of the product being installed
+ std::string Version;
+
+ /// Name of the installer as displayed on the title bar
+ std::string Title;
+
+ /// Publisher of the software (as shown in the Windows Control Panel)
+ std::string Publisher;
+
+ /// URL to a page that contains product information on your web site
+ std::string ProductUrl;
+
+ /// Filename for a custom installer icon
+ std::string InstallerApplicationIcon;
+
+ /// Filename for a custom window icon
+ std::string InstallerWindowIcon;
+
+ /// Filename for a logo
+ std::string Logo;
+
+ /// Name of the default program group in the Windows Start menu
+ std::string StartMenuDir;
+
+ /// Default target directory for installation
+ std::string TargetDir;
+
+ /// Default target directory for installation with administrator rights
+ std::string AdminTargetDir;
+
+ /// Filename of the generated maintenance tool
+ std::string MaintenanceToolName;
+
+ /// Filename for the configuration of the generated maintenance tool
+ std::string MaintenanceToolIniFile;
+
+ /// Set to true if the installation path can contain non-ASCII characters
+ std::string AllowNonAsciiCharacters;
+
+ /// Set to false if the installation path cannot contain space characters
+ std::string AllowSpaceInPath;
+
+ /// Filename for a custom installer control script
+ std::string ControlScript;
+
+public:
+ // Internal implementation
+
+ const char* GetOption(const std::string& op) const;
+ bool IsOn(const std::string& op) const;
+
+ bool IsVersionLess(const char* version);
+ bool IsVersionGreater(const char* version);
+ bool IsVersionEqual(const char* version);
+
+ void ConfigureFromOptions();
+
+ void GenerateInstallerFile();
+
+ void GeneratePackageFiles();
+
+ cmCPackIFWGenerator* Generator;
+ PackagesMap Packages;
+ RepositoriesVector RemoteRepositories;
+ std::string Directory;
+
+protected:
+ void WriteGeneratedByToStrim(cmXMLWriter& xout);
+};
+
+#endif // cmCPackIFWInstaller_h
diff --git a/Source/CPack/IFW/cmCPackIFWPackage.cxx b/Source/CPack/IFW/cmCPackIFWPackage.cxx
new file mode 100644
index 0000000..5db06e6
--- /dev/null
+++ b/Source/CPack/IFW/cmCPackIFWPackage.cxx
@@ -0,0 +1,484 @@
+/*============================================================================
+ CMake - Cross Platform Makefile Generator
+ Copyright 2000-2009 Kitware, Inc., Insight Software Consortium
+
+ Distributed under the OSI-approved BSD License (the "License");
+ see accompanying file Copyright.txt for details.
+
+ This software is distributed WITHOUT ANY WARRANTY; without even the
+ implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
+ See the License for more information.
+============================================================================*/
+
+#include "cmCPackIFWPackage.h"
+
+#include "cmCPackIFWGenerator.h"
+
+#include <CPack/cmCPackLog.h>
+
+#include <cmGeneratedFileStream.h>
+#include <cmTimestamp.h>
+#include <cmXMLWriter.h>
+
+//----------------------------------------------------------------- Logger ---
+#ifdef cmCPackLogger
+#undef cmCPackLogger
+#endif
+#define cmCPackLogger(logType, msg) \
+ do { \
+ std::ostringstream cmCPackLog_msg; \
+ cmCPackLog_msg << msg; \
+ if (Generator) { \
+ Generator->Logger->Log(logType, __FILE__, __LINE__, \
+ cmCPackLog_msg.str().c_str()); \
+ } \
+ } while (0)
+
+//---------------------------------------------------------- CompareStruct ---
+cmCPackIFWPackage::CompareStruct::CompareStruct()
+ : Type(CompareNone)
+{
+}
+
+//------------------------------------------------------- DependenceStruct ---
+cmCPackIFWPackage::DependenceStruct::DependenceStruct()
+{
+}
+
+cmCPackIFWPackage::DependenceStruct::DependenceStruct(
+ const std::string& dependence)
+{
+ // Search compare section
+ size_t pos = std::string::npos;
+ if ((pos = dependence.find("<=")) != std::string::npos) {
+ Compare.Type = CompareLessOrEqual;
+ Compare.Value = dependence.substr(pos + 2);
+ } else if ((pos = dependence.find(">=")) != std::string::npos) {
+ Compare.Type = CompareGreaterOrEqual;
+ Compare.Value = dependence.substr(pos + 2);
+ } else if ((pos = dependence.find('<')) != std::string::npos) {
+ Compare.Type = CompareLess;
+ Compare.Value = dependence.substr(pos + 1);
+ } else if ((pos = dependence.find('=')) != std::string::npos) {
+ Compare.Type = CompareEqual;
+ Compare.Value = dependence.substr(pos + 1);
+ } else if ((pos = dependence.find('>')) != std::string::npos) {
+ Compare.Type = CompareGreater;
+ Compare.Value = dependence.substr(pos + 1);
+ }
+ Name = pos == std::string::npos ? dependence : dependence.substr(0, pos);
+}
+
+std::string cmCPackIFWPackage::DependenceStruct::NameWithCompare() const
+{
+ if (Compare.Type == CompareNone) {
+ return Name;
+ }
+
+ std::string result = Name;
+
+ if (Compare.Type == CompareLessOrEqual) {
+ result += "<=";
+ } else if (Compare.Type == CompareGreaterOrEqual) {
+ result += ">=";
+ } else if (Compare.Type == CompareLess) {
+ result += "<";
+ } else if (Compare.Type == CompareEqual) {
+ result += "=";
+ } else if (Compare.Type == CompareGreater) {
+ result += ">";
+ }
+
+ result += Compare.Value;
+
+ return result;
+}
+
+//------------------------------------------------------ cmCPackIFWPackage ---
+cmCPackIFWPackage::cmCPackIFWPackage()
+ : Generator(CM_NULLPTR)
+ , Installer(CM_NULLPTR)
+{
+}
+
+const char* cmCPackIFWPackage::GetOption(const std::string& op) const
+{
+ const char* option = Generator ? Generator->GetOption(op) : CM_NULLPTR;
+ return option && *option ? option : CM_NULLPTR;
+}
+
+bool cmCPackIFWPackage::IsOn(const std::string& op) const
+{
+ return Generator ? Generator->IsOn(op) : false;
+}
+
+bool cmCPackIFWPackage::IsVersionLess(const char* version)
+{
+ return Generator ? Generator->IsVersionLess(version) : false;
+}
+
+bool cmCPackIFWPackage::IsVersionGreater(const char* version)
+{
+ return Generator ? Generator->IsVersionGreater(version) : false;
+}
+
+bool cmCPackIFWPackage::IsVersionEqual(const char* version)
+{
+ return Generator ? Generator->IsVersionEqual(version) : false;
+}
+
+std::string cmCPackIFWPackage::GetComponentName(cmCPackComponent* component)
+{
+ if (!component) {
+ return "";
+ }
+ const char* option =
+ GetOption("CPACK_IFW_COMPONENT_" +
+ cmsys::SystemTools::UpperCase(component->Name) + "_NAME");
+ return option ? option : component->Name;
+}
+
+void cmCPackIFWPackage::DefaultConfiguration()
+{
+ DisplayName = "";
+ Description = "";
+ Version = "";
+ ReleaseDate = "";
+ Script = "";
+ Licenses.clear();
+ SortingPriority = "";
+ Default = "";
+ Essential = "";
+ Virtual = "";
+ ForcedInstallation = "";
+}
+
+// Defaul configuration (all in one package)
+int cmCPackIFWPackage::ConfigureFromOptions()
+{
+ // Restore defaul configuration
+ DefaultConfiguration();
+
+ // Name
+ Name = Generator->GetRootPackageName();
+
+ // Display name
+ if (const char* option = this->GetOption("CPACK_PACKAGE_NAME")) {
+ DisplayName = option;
+ } else {
+ DisplayName = "Your package";
+ }
+
+ // Description
+ if (const char* option =
+ this->GetOption("CPACK_PACKAGE_DESCRIPTION_SUMMARY")) {
+ Description = option;
+ } else {
+ Description = "Your package description";
+ }
+
+ // Version
+ if (const char* option = GetOption("CPACK_PACKAGE_VERSION")) {
+ Version = option;
+ } else {
+ Version = "1.0.0";
+ }
+
+ ForcedInstallation = "true";
+
+ return 1;
+}
+
+int cmCPackIFWPackage::ConfigureFromComponent(cmCPackComponent* component)
+{
+ if (!component) {
+ return 0;
+ }
+
+ // Restore defaul configuration
+ DefaultConfiguration();
+
+ std::string prefix = "CPACK_IFW_COMPONENT_" +
+ cmsys::SystemTools::UpperCase(component->Name) + "_";
+
+ // Display name
+ DisplayName = component->DisplayName;
+
+ // Description
+ Description = component->Description;
+
+ // Version
+ if (const char* optVERSION = GetOption(prefix + "VERSION")) {
+ Version = optVERSION;
+ } else if (const char* optPACKAGE_VERSION =
+ GetOption("CPACK_PACKAGE_VERSION")) {
+ Version = optPACKAGE_VERSION;
+ } else {
+ Version = "1.0.0";
+ }
+
+ // Script
+ if (const char* option = GetOption(prefix + "SCRIPT")) {
+ Script = option;
+ }
+
+ // CMake dependencies
+ if (!component->Dependencies.empty()) {
+ std::vector<cmCPackComponent*>::iterator dit;
+ for (dit = component->Dependencies.begin();
+ dit != component->Dependencies.end(); ++dit) {
+ Dependencies.insert(Generator->ComponentPackages[*dit]);
+ }
+ }
+
+ // QtIFW dependencies
+ if (const char* option = this->GetOption(prefix + "DEPENDS")) {
+ std::vector<std::string> deps;
+ cmSystemTools::ExpandListArgument(option, deps);
+ for (std::vector<std::string>::iterator dit = deps.begin();
+ dit != deps.end(); ++dit) {
+ DependenceStruct dep(*dit);
+ if (!Generator->Packages.count(dep.Name)) {
+ bool hasDep = Generator->DependentPackages.count(dep.Name) > 0;
+ DependenceStruct& depRef = Generator->DependentPackages[dep.Name];
+ if (!hasDep) {
+ depRef = dep;
+ }
+ AlienDependencies.insert(&depRef);
+ }
+ }
+ }
+
+ // Licenses
+ if (const char* option = this->GetOption(prefix + "LICENSES")) {
+ Licenses.clear();
+ cmSystemTools::ExpandListArgument(option, Licenses);
+ if (Licenses.size() % 2 != 0) {
+ cmCPackLogger(
+ cmCPackLog::LOG_WARNING, prefix
+ << "LICENSES"
+ << " should contain pairs of <display_name> and <file_path>."
+ << std::endl);
+ Licenses.clear();
+ }
+ }
+
+ // Priority
+ if (const char* option = this->GetOption(prefix + "PRIORITY")) {
+ SortingPriority = option;
+ }
+
+ // Default
+ Default = component->IsDisabledByDefault ? "false" : "true";
+
+ // Essential
+ if (this->IsOn(prefix + "ESSENTIAL")) {
+ Essential = "true";
+ }
+
+ // Virtual
+ Virtual = component->IsHidden ? "true" : "";
+
+ // ForcedInstallation
+ ForcedInstallation = component->IsRequired ? "true" : "false";
+
+ return 1;
+}
+
+int cmCPackIFWPackage::ConfigureFromGroup(cmCPackComponentGroup* group)
+{
+ if (!group) {
+ return 0;
+ }
+
+ // Restore defaul configuration
+ DefaultConfiguration();
+
+ std::string prefix = "CPACK_IFW_COMPONENT_GROUP_" +
+ cmsys::SystemTools::UpperCase(group->Name) + "_";
+
+ DisplayName = group->DisplayName;
+ Description = group->Description;
+
+ // Version
+ if (const char* optVERSION = GetOption(prefix + "VERSION")) {
+ Version = optVERSION;
+ } else if (const char* optPACKAGE_VERSION =
+ GetOption("CPACK_PACKAGE_VERSION")) {
+ Version = optPACKAGE_VERSION;
+ } else {
+ Version = "1.0.0";
+ }
+
+ // Script
+ if (const char* option = GetOption(prefix + "SCRIPT")) {
+ Script = option;
+ }
+
+ // Licenses
+ if (const char* option = this->GetOption(prefix + "LICENSES")) {
+ Licenses.clear();
+ cmSystemTools::ExpandListArgument(option, Licenses);
+ if (Licenses.size() % 2 != 0) {
+ cmCPackLogger(
+ cmCPackLog::LOG_WARNING, prefix
+ << "LICENSES"
+ << " should contain pairs of <display_name> and <file_path>."
+ << std::endl);
+ Licenses.clear();
+ }
+ }
+
+ // Priority
+ if (const char* option = this->GetOption(prefix + "PRIORITY")) {
+ SortingPriority = option;
+ }
+
+ return 1;
+}
+
+int cmCPackIFWPackage::ConfigureFromGroup(const std::string& groupName)
+{
+ // Group configuration
+
+ cmCPackComponentGroup group;
+ std::string prefix =
+ "CPACK_COMPONENT_GROUP_" + cmsys::SystemTools::UpperCase(groupName) + "_";
+
+ if (const char* option = GetOption(prefix + "DISPLAY_NAME")) {
+ group.DisplayName = option;
+ } else {
+ group.DisplayName = group.Name;
+ }
+
+ if (const char* option = GetOption(prefix + "DESCRIPTION")) {
+ group.Description = option;
+ }
+ group.IsBold = IsOn(prefix + "BOLD_TITLE");
+ group.IsExpandedByDefault = IsOn(prefix + "EXPANDED");
+
+ // Package configuration
+
+ group.Name = groupName;
+
+ if (Generator) {
+ Name = Generator->GetGroupPackageName(&group);
+ } else {
+ Name = group.Name;
+ }
+
+ return ConfigureFromGroup(&group);
+}
+
+void cmCPackIFWPackage::GeneratePackageFile()
+{
+ // Lazy directory initialization
+ if (Directory.empty()) {
+ if (Installer) {
+ Directory = Installer->Directory + "/packages/" + Name;
+ } else if (Generator) {
+ Directory = Generator->toplevel + "/packages/" + Name;
+ }
+ }
+
+ // Output stream
+ cmGeneratedFileStream fout((Directory + "/meta/package.xml").data());
+ cmXMLWriter xout(fout);
+
+ xout.StartDocument();
+
+ WriteGeneratedByToStrim(xout);
+
+ xout.StartElement("Package");
+
+ xout.Element("DisplayName", DisplayName);
+ xout.Element("Description", Description);
+ xout.Element("Name", Name);
+ xout.Element("Version", Version);
+
+ if (!ReleaseDate.empty()) {
+ xout.Element("ReleaseDate", ReleaseDate);
+ } else {
+ xout.Element("ReleaseDate", cmTimestamp().CurrentTime("%Y-%m-%d", true));
+ }
+
+ // Script (copy to meta dir)
+ if (!Script.empty()) {
+ std::string name = cmSystemTools::GetFilenameName(Script);
+ std::string path = Directory + "/meta/" + name;
+ cmsys::SystemTools::CopyFileIfDifferent(Script.data(), path.data());
+ xout.Element("Script", name);
+ }
+
+ // Dependencies
+ std::set<DependenceStruct> compDepSet;
+ for (std::set<DependenceStruct*>::iterator ait = AlienDependencies.begin();
+ ait != AlienDependencies.end(); ++ait) {
+ compDepSet.insert(*(*ait));
+ }
+ for (std::set<cmCPackIFWPackage*>::iterator it = Dependencies.begin();
+ it != Dependencies.end(); ++it) {
+ compDepSet.insert(DependenceStruct((*it)->Name));
+ }
+ // Write dependencies
+ if (!compDepSet.empty()) {
+ std::ostringstream dependencies;
+ std::set<DependenceStruct>::iterator it = compDepSet.begin();
+ dependencies << it->NameWithCompare();
+ ++it;
+ while (it != compDepSet.end()) {
+ dependencies << "," << it->NameWithCompare();
+ ++it;
+ }
+ xout.Element("Dependencies", dependencies.str());
+ }
+
+ // Licenses (copy to meta dir)
+ std::vector<std::string> licenses = Licenses;
+ for (size_t i = 1; i < licenses.size(); i += 2) {
+ std::string name = cmSystemTools::GetFilenameName(licenses[i]);
+ std::string path = Directory + "/meta/" + name;
+ cmsys::SystemTools::CopyFileIfDifferent(licenses[i].data(), path.data());
+ licenses[i] = name;
+ }
+ if (!licenses.empty()) {
+ xout.StartElement("Licenses");
+ for (size_t i = 0; i < licenses.size(); i += 2) {
+ xout.StartElement("License");
+ xout.Attribute("name", licenses[i]);
+ xout.Attribute("file", licenses[i + 1]);
+ xout.EndElement();
+ }
+ xout.EndElement();
+ }
+
+ if (!ForcedInstallation.empty()) {
+ xout.Element("ForcedInstallation", ForcedInstallation);
+ }
+
+ if (!Virtual.empty()) {
+ xout.Element("Virtual", Virtual);
+ } else if (!Default.empty()) {
+ xout.Element("Default", Default);
+ }
+
+ // Essential
+ if (!Essential.empty()) {
+ xout.Element("Essential", Essential);
+ }
+
+ // Priority
+ if (!SortingPriority.empty()) {
+ xout.Element("SortingPriority", SortingPriority);
+ }
+
+ xout.EndElement();
+ xout.EndDocument();
+}
+
+void cmCPackIFWPackage::WriteGeneratedByToStrim(cmXMLWriter& xout)
+{
+ if (Generator) {
+ Generator->WriteGeneratedByToStrim(xout);
+ }
+}
diff --git a/Source/CPack/IFW/cmCPackIFWPackage.h b/Source/CPack/IFW/cmCPackIFWPackage.h
new file mode 100644
index 0000000..55b07ec
--- /dev/null
+++ b/Source/CPack/IFW/cmCPackIFWPackage.h
@@ -0,0 +1,149 @@
+/*============================================================================
+ CMake - Cross Platform Makefile Generator
+ Copyright 2000-2009 Kitware, Inc., Insight Software Consortium
+
+ Distributed under the OSI-approved BSD License (the "License");
+ see accompanying file Copyright.txt for details.
+
+ This software is distributed WITHOUT ANY WARRANTY; without even the
+ implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
+ See the License for more information.
+============================================================================*/
+
+#ifndef cmCPackIFWPackage_h
+#define cmCPackIFWPackage_h
+
+#include <cmStandardIncludes.h>
+
+class cmCPackComponent;
+class cmCPackComponentGroup;
+class cmCPackIFWInstaller;
+class cmCPackIFWGenerator;
+class cmXMLWriter;
+
+/** \class cmCPackIFWPackage
+ * \brief A single component to be installed by CPack IFW generator
+ */
+class cmCPackIFWPackage
+{
+public:
+ // Types
+
+ enum CompareTypes
+ {
+ CompareNone = 0x0,
+ CompareEqual = 0x1,
+ CompareLess = 0x2,
+ CompareLessOrEqual = 0x3,
+ CompareGreater = 0x4,
+ CompareGreaterOrEqual = 0x5
+ };
+
+ struct CompareStruct
+ {
+ CompareStruct();
+
+ unsigned int Type;
+ std::string Value;
+ };
+
+ struct DependenceStruct
+ {
+ DependenceStruct();
+ DependenceStruct(const std::string& dependence);
+
+ std::string Name;
+ CompareStruct Compare;
+
+ std::string NameWithCompare() const;
+
+ bool operator<(const DependenceStruct& other) const
+ {
+ return Name < other.Name;
+ }
+ };
+
+public:
+ // [Con|De]structor
+
+ /**
+ * Construct package
+ */
+ cmCPackIFWPackage();
+
+public:
+ // Configuration
+
+ /// Human-readable name of the component
+ std::string DisplayName;
+
+ /// Human-readable description of the component
+ std::string Description;
+
+ /// Version number of the component
+ std::string Version;
+
+ /// Date when this component version was released
+ std::string ReleaseDate;
+
+ /// Domain-like identification for this component
+ std::string Name;
+
+ /// File name of a script being loaded
+ std::string Script;
+
+ /// List of license agreements to be accepted by the installing user
+ std::vector<std::string> Licenses;
+
+ /// Priority of the component in the tree
+ std::string SortingPriority;
+
+ /// Set to true to preselect the component in the installer
+ std::string Default;
+
+ /// Marks the package as essential to force a restart of the MaintenanceTool
+ std::string Essential;
+
+ /// Set to true to hide the component from the installer
+ std::string Virtual;
+
+ /// Determines that the package must always be installed
+ std::string ForcedInstallation;
+
+public:
+ // Internal implementation
+
+ const char* GetOption(const std::string& op) const;
+ bool IsOn(const std::string& op) const;
+
+ bool IsVersionLess(const char* version);
+ bool IsVersionGreater(const char* version);
+ bool IsVersionEqual(const char* version);
+
+ std::string GetComponentName(cmCPackComponent* component);
+
+ void DefaultConfiguration();
+
+ int ConfigureFromOptions();
+ int ConfigureFromComponent(cmCPackComponent* component);
+ int ConfigureFromGroup(cmCPackComponentGroup* group);
+ int ConfigureFromGroup(const std::string& groupName);
+
+ void GeneratePackageFile();
+
+ // Pointer to generator
+ cmCPackIFWGenerator* Generator;
+ // Pointer to installer
+ cmCPackIFWInstaller* Installer;
+ // Collection of dependencies
+ std::set<cmCPackIFWPackage*> Dependencies;
+ // Collection of unresolved dependencies
+ std::set<DependenceStruct*> AlienDependencies;
+ // Patch to package directory
+ std::string Directory;
+
+protected:
+ void WriteGeneratedByToStrim(cmXMLWriter& xout);
+};
+
+#endif // cmCPackIFWPackage_h
diff --git a/Source/CPack/IFW/cmCPackIFWRepository.cxx b/Source/CPack/IFW/cmCPackIFWRepository.cxx
new file mode 100644
index 0000000..fcb1c77
--- /dev/null
+++ b/Source/CPack/IFW/cmCPackIFWRepository.cxx
@@ -0,0 +1,342 @@
+/*============================================================================
+ CMake - Cross Platform Makefile Generator
+ Copyright 2000-2009 Kitware, Inc., Insight Software Consortium
+
+ Distributed under the OSI-approved BSD License (the "License");
+ see accompanying file Copyright.txt for details.
+
+ This software is distributed WITHOUT ANY WARRANTY; without even the
+ implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
+ See the License for more information.
+============================================================================*/
+
+#include "cmCPackIFWRepository.h"
+
+#include "cmCPackIFWGenerator.h"
+
+#include <CPack/cmCPackLog.h>
+
+#include <cmGeneratedFileStream.h>
+#include <cmXMLParser.h>
+#include <cmXMLWriter.h>
+
+#ifdef cmCPackLogger
+#undef cmCPackLogger
+#endif
+#define cmCPackLogger(logType, msg) \
+ do { \
+ std::ostringstream cmCPackLog_msg; \
+ cmCPackLog_msg << msg; \
+ if (Generator) { \
+ Generator->Logger->Log(logType, __FILE__, __LINE__, \
+ cmCPackLog_msg.str().c_str()); \
+ } \
+ } while (0)
+
+cmCPackIFWRepository::cmCPackIFWRepository()
+ : Update(None)
+ , Generator(CM_NULLPTR)
+{
+}
+
+bool cmCPackIFWRepository::IsValid() const
+{
+ bool valid = true;
+
+ switch (Update) {
+ case None:
+ valid = !Url.empty();
+ break;
+ case Add:
+ valid = !Url.empty();
+ break;
+ case Remove:
+ valid = !Url.empty();
+ break;
+ case Replace:
+ valid = !OldUrl.empty() && !NewUrl.empty();
+ break;
+ }
+
+ return valid;
+}
+
+const char* cmCPackIFWRepository::GetOption(const std::string& op) const
+{
+ return Generator ? Generator->GetOption(op) : CM_NULLPTR;
+}
+
+bool cmCPackIFWRepository::IsOn(const std::string& op) const
+{
+ return Generator ? Generator->IsOn(op) : false;
+}
+
+bool cmCPackIFWRepository::IsVersionLess(const char* version)
+{
+ return Generator ? Generator->IsVersionLess(version) : false;
+}
+
+bool cmCPackIFWRepository::IsVersionGreater(const char* version)
+{
+ return Generator ? Generator->IsVersionGreater(version) : false;
+}
+
+bool cmCPackIFWRepository::IsVersionEqual(const char* version)
+{
+ return Generator ? Generator->IsVersionEqual(version) : false;
+}
+
+bool cmCPackIFWRepository::ConfigureFromOptions()
+{
+ // Name;
+ if (Name.empty()) {
+ return false;
+ }
+
+ std::string prefix =
+ "CPACK_IFW_REPOSITORY_" + cmsys::SystemTools::UpperCase(Name) + "_";
+
+ // Update
+ if (IsOn(prefix + "ADD")) {
+ Update = Add;
+ } else if (IsOn(prefix + "REMOVE")) {
+ Update = Remove;
+ } else if (IsOn(prefix + "REPLACE")) {
+ Update = Replace;
+ } else {
+ Update = None;
+ }
+
+ // Url
+ if (const char* url = GetOption(prefix + "URL")) {
+ Url = url;
+ } else {
+ Url = "";
+ }
+
+ // Old url
+ if (const char* oldUrl = GetOption(prefix + "OLD_URL")) {
+ OldUrl = oldUrl;
+ } else {
+ OldUrl = "";
+ }
+
+ // New url
+ if (const char* newUrl = GetOption(prefix + "NEW_URL")) {
+ NewUrl = newUrl;
+ } else {
+ NewUrl = "";
+ }
+
+ // Enabled
+ if (IsOn(prefix + "DISABLED")) {
+ Enabled = "0";
+ } else {
+ Enabled = "";
+ }
+
+ // Username
+ if (const char* username = GetOption(prefix + "USERNAME")) {
+ Username = username;
+ } else {
+ Username = "";
+ }
+
+ // Password
+ if (const char* password = GetOption(prefix + "PASSWORD")) {
+ Password = password;
+ } else {
+ Password = "";
+ }
+
+ // DisplayName
+ if (const char* displayName = GetOption(prefix + "DISPLAY_NAME")) {
+ DisplayName = displayName;
+ } else {
+ DisplayName = "";
+ }
+
+ return IsValid();
+}
+
+/** \class cmCPackeIFWUpdatesPatcher
+ * \brief Helper class that parses and patch Updates.xml file (QtIFW)
+ */
+class cmCPackeIFWUpdatesPatcher : public cmXMLParser
+{
+public:
+ cmCPackeIFWUpdatesPatcher(cmCPackIFWRepository* r, cmXMLWriter& x)
+ : repository(r)
+ , xout(x)
+ , patched(false)
+ {
+ }
+
+ cmCPackIFWRepository* repository;
+ cmXMLWriter& xout;
+ bool patched;
+
+protected:
+ void StartElement(const std::string& name, const char** atts) CM_OVERRIDE
+ {
+ xout.StartElement(name);
+ StartFragment(atts);
+ }
+
+ void StartFragment(const char** atts)
+ {
+ for (size_t i = 0; atts[i]; i += 2) {
+ const char* key = atts[i];
+ const char* value = atts[i + 1];
+ xout.Attribute(key, value);
+ }
+ }
+
+ void EndElement(const std::string& name) CM_OVERRIDE
+ {
+ if (name == "Updates" && !patched) {
+ repository->WriteRepositoryUpdates(xout);
+ patched = true;
+ }
+ xout.EndElement();
+ if (patched) {
+ return;
+ }
+ if (name == "Checksum") {
+ repository->WriteRepositoryUpdates(xout);
+ patched = true;
+ }
+ }
+
+ void CharacterDataHandler(const char* data, int length) CM_OVERRIDE
+ {
+ std::string content(data, data + length);
+ if (content == "" || content == " " || content == " " ||
+ content == "\n") {
+ return;
+ }
+ xout.Content(content);
+ }
+};
+
+bool cmCPackIFWRepository::PatchUpdatesXml()
+{
+ // Lazy directory initialization
+ if (Directory.empty() && Generator) {
+ Directory = Generator->toplevel;
+ }
+
+ // Filenames
+ std::string updatesXml = Directory + "/repository/Updates.xml";
+ std::string updatesPatchXml = Directory + "/repository/UpdatesPatch.xml";
+
+ // Output stream
+ cmGeneratedFileStream fout(updatesPatchXml.data());
+ cmXMLWriter xout(fout);
+
+ xout.StartDocument();
+
+ WriteGeneratedByToStrim(xout);
+
+ // Patch
+ {
+ cmCPackeIFWUpdatesPatcher patcher(this, xout);
+ patcher.ParseFile(updatesXml.data());
+ }
+
+ xout.EndDocument();
+
+ fout.Close();
+
+ return cmSystemTools::RenameFile(updatesPatchXml.data(), updatesXml.data());
+}
+
+void cmCPackIFWRepository::WriteRepositoryConfig(cmXMLWriter& xout)
+{
+ xout.StartElement("Repository");
+
+ // Url
+ xout.Element("Url", Url);
+ // Enabled
+ if (!Enabled.empty()) {
+ xout.Element("Enabled", Enabled);
+ }
+ // Username
+ if (!Username.empty()) {
+ xout.Element("Username", Username);
+ }
+ // Password
+ if (!Password.empty()) {
+ xout.Element("Password", Password);
+ }
+ // DisplayName
+ if (!DisplayName.empty()) {
+ xout.Element("DisplayName", DisplayName);
+ }
+
+ xout.EndElement();
+}
+
+void cmCPackIFWRepository::WriteRepositoryUpdate(cmXMLWriter& xout)
+{
+ xout.StartElement("Repository");
+
+ switch (Update) {
+ case None:
+ break;
+ case Add:
+ xout.Attribute("action", "add");
+ break;
+ case Remove:
+ xout.Attribute("action", "remove");
+ break;
+ case Replace:
+ xout.Attribute("action", "replace");
+ break;
+ }
+
+ // Url
+ if (Update == Add || Update == Remove) {
+ xout.Attribute("url", Url);
+ } else if (Update == Replace) {
+ xout.Attribute("oldUrl", OldUrl);
+ xout.Attribute("newUrl", NewUrl);
+ }
+ // Enabled
+ if (!Enabled.empty()) {
+ xout.Attribute("enabled", Enabled);
+ }
+ // Username
+ if (!Username.empty()) {
+ xout.Attribute("username", Username);
+ }
+ // Password
+ if (!Password.empty()) {
+ xout.Attribute("password", Password);
+ }
+ // DisplayName
+ if (!DisplayName.empty()) {
+ xout.Attribute("displayname", DisplayName);
+ }
+
+ xout.EndElement();
+}
+
+void cmCPackIFWRepository::WriteRepositoryUpdates(cmXMLWriter& xout)
+{
+ if (!RepositoryUpdate.empty()) {
+ xout.StartElement("RepositoryUpdate");
+ for (RepositoriesVector::iterator rit = RepositoryUpdate.begin();
+ rit != RepositoryUpdate.end(); ++rit) {
+ (*rit)->WriteRepositoryUpdate(xout);
+ }
+ xout.EndElement();
+ }
+}
+
+void cmCPackIFWRepository::WriteGeneratedByToStrim(cmXMLWriter& xout)
+{
+ if (Generator) {
+ Generator->WriteGeneratedByToStrim(xout);
+ }
+}
diff --git a/Source/CPack/IFW/cmCPackIFWRepository.h b/Source/CPack/IFW/cmCPackIFWRepository.h
new file mode 100644
index 0000000..5ffb775
--- /dev/null
+++ b/Source/CPack/IFW/cmCPackIFWRepository.h
@@ -0,0 +1,105 @@
+/*============================================================================
+ CMake - Cross Platform Makefile Generator
+ Copyright 2000-2009 Kitware, Inc., Insight Software Consortium
+
+ Distributed under the OSI-approved BSD License (the "License");
+ see accompanying file Copyright.txt for details.
+
+ This software is distributed WITHOUT ANY WARRANTY; without even the
+ implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
+ See the License for more information.
+============================================================================*/
+
+#ifndef cmCPackIFWRepository_h
+#define cmCPackIFWRepository_h
+
+#include <cmStandardIncludes.h>
+
+class cmCPackIFWGenerator;
+class cmXMLWriter;
+
+/** \class cmCPackIFWRepository
+ * \brief A remote repository to be created CPack IFW generator
+ */
+class cmCPackIFWRepository
+{
+public:
+ // Types
+
+ enum Action
+ {
+ None,
+ Add,
+ Remove,
+ Replace
+ };
+
+ typedef std::vector<cmCPackIFWRepository*> RepositoriesVector;
+
+public:
+ // Constructor
+
+ /**
+ * Construct repository
+ */
+ cmCPackIFWRepository();
+
+public:
+ // Configuration
+
+ /// Internal repository name
+ std::string Name;
+
+ /// Optional update action
+ Action Update;
+
+ /// Is points to a list of available components
+ std::string Url;
+
+ /// Is points to a list that will replaced
+ std::string OldUrl;
+
+ /// Is points to a list that will replace to
+ std::string NewUrl;
+
+ /// With "0" disabling this repository
+ std::string Enabled;
+
+ /// Is used as user on a protected repository
+ std::string Username;
+
+ /// Is password to use on a protected repository
+ std::string Password;
+
+ /// Is optional string to display instead of the URL
+ std::string DisplayName;
+
+public:
+ // Internal implementation
+
+ bool IsValid() const;
+
+ const char* GetOption(const std::string& op) const;
+ bool IsOn(const std::string& op) const;
+
+ bool IsVersionLess(const char* version);
+ bool IsVersionGreater(const char* version);
+ bool IsVersionEqual(const char* version);
+
+ bool ConfigureFromOptions();
+
+ bool PatchUpdatesXml();
+
+ void WriteRepositoryConfig(cmXMLWriter& xout);
+ void WriteRepositoryUpdate(cmXMLWriter& xout);
+ void WriteRepositoryUpdates(cmXMLWriter& xout);
+
+ cmCPackIFWGenerator* Generator;
+ RepositoriesVector RepositoryUpdate;
+ std::string Directory;
+
+protected:
+ void WriteGeneratedByToStrim(cmXMLWriter& xout);
+};
+
+#endif // cmCPackIFWRepository_h
diff --git a/Source/CPack/OSXLauncherScript.scpt b/Source/CPack/OSXLauncherScript.scpt
new file mode 100644
index 0000000..342cf8c
--- /dev/null
+++ b/Source/CPack/OSXLauncherScript.scpt
Binary files differ
diff --git a/Source/CPack/OSXScriptLauncher.cxx b/Source/CPack/OSXScriptLauncher.cxx
new file mode 100644
index 0000000..a233e76
--- /dev/null
+++ b/Source/CPack/OSXScriptLauncher.cxx
@@ -0,0 +1,130 @@
+/*============================================================================
+ CMake - Cross Platform Makefile Generator
+ Copyright 2000-2009 Kitware, Inc., Insight Software Consortium
+
+ Distributed under the OSI-approved BSD License (the "License");
+ see accompanying file Copyright.txt for details.
+
+ This software is distributed WITHOUT ANY WARRANTY; without even the
+ implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
+ See the License for more information.
+============================================================================*/
+#include <cmsys/FStream.hxx>
+#include <cmsys/Process.h>
+#include <cmsys/SystemTools.hxx>
+
+#include <iostream>
+
+#include <CoreFoundation/CoreFoundation.h>
+
+// For the PATH_MAX constant
+#include <sys/syslimits.h>
+
+#define DebugError(x) \
+ ofs << x << std::endl; \
+ std::cout << x << std::endl
+
+int main(int argc, char* argv[])
+{
+ // if ( cmsys::SystemTools::FileExists(
+ std::string cwd = cmsys::SystemTools::GetCurrentWorkingDirectory();
+ cmsys::ofstream ofs("/tmp/output.txt");
+
+ CFStringRef fileName;
+ CFBundleRef appBundle;
+ CFURLRef scriptFileURL;
+ UInt8* path;
+
+ // get CF URL for script
+ if (!(appBundle = CFBundleGetMainBundle())) {
+ DebugError("Cannot get main bundle");
+ return 1;
+ }
+ fileName = CFSTR("RuntimeScript");
+ if (!(scriptFileURL =
+ CFBundleCopyResourceURL(appBundle, fileName, NULL, NULL))) {
+ DebugError("CFBundleCopyResourceURL failed");
+ return 1;
+ }
+
+ // create path string
+ if (!(path = new UInt8[PATH_MAX])) {
+ return 1;
+ }
+
+ // get the file system path of the url as a cstring
+ // in an encoding suitable for posix apis
+ if (CFURLGetFileSystemRepresentation(scriptFileURL, true, path, PATH_MAX) ==
+ false) {
+ DebugError("CFURLGetFileSystemRepresentation failed");
+ return 1;
+ }
+
+ // dispose of the CF variable
+ CFRelease(scriptFileURL);
+
+ std::string fullScriptPath = reinterpret_cast<char*>(path);
+ delete[] path;
+
+ if (!cmsys::SystemTools::FileExists(fullScriptPath.c_str())) {
+ return 1;
+ }
+
+ std::string scriptDirectory =
+ cmsys::SystemTools::GetFilenamePath(fullScriptPath);
+ ofs << fullScriptPath << std::endl;
+ std::vector<const char*> args;
+ args.push_back(fullScriptPath.c_str());
+ int cc;
+ for (cc = 1; cc < argc; ++cc) {
+ args.push_back(argv[cc]);
+ }
+ args.push_back(0);
+
+ cmsysProcess* cp = cmsysProcess_New();
+ cmsysProcess_SetCommand(cp, &*args.begin());
+ cmsysProcess_SetWorkingDirectory(cp, scriptDirectory.c_str());
+ cmsysProcess_SetOption(cp, cmsysProcess_Option_HideWindow, 1);
+ cmsysProcess_SetTimeout(cp, 0);
+ cmsysProcess_Execute(cp);
+
+ std::vector<char> tempOutput;
+ char* data;
+ int length;
+ while (cmsysProcess_WaitForData(cp, &data, &length, 0)) {
+ // Translate NULL characters in the output into valid text.
+ // Visual Studio 7 puts these characters in the output of its
+ // build process.
+ for (int i = 0; i < length; ++i) {
+ if (data[i] == '\0') {
+ data[i] = ' ';
+ }
+ }
+ std::cout.write(data, length);
+ }
+
+ cmsysProcess_WaitForExit(cp, 0);
+
+ bool result = true;
+ if (cmsysProcess_GetState(cp) == cmsysProcess_State_Exited) {
+ if (cmsysProcess_GetExitValue(cp) != 0) {
+ result = false;
+ }
+ } else if (cmsysProcess_GetState(cp) == cmsysProcess_State_Exception) {
+ const char* exception_str = cmsysProcess_GetExceptionString(cp);
+ std::cerr << exception_str << std::endl;
+ result = false;
+ } else if (cmsysProcess_GetState(cp) == cmsysProcess_State_Error) {
+ const char* error_str = cmsysProcess_GetErrorString(cp);
+ std::cerr << error_str << std::endl;
+ result = false;
+ } else if (cmsysProcess_GetState(cp) == cmsysProcess_State_Expired) {
+ const char* error_str = "Process terminated due to timeout\n";
+ std::cerr << error_str << std::endl;
+ result = false;
+ }
+
+ cmsysProcess_Delete(cp);
+
+ return 0;
+}
diff --git a/Source/CPack/WiX/cmCPackWIXGenerator.cxx b/Source/CPack/WiX/cmCPackWIXGenerator.cxx
new file mode 100644
index 0000000..3ecc14d
--- /dev/null
+++ b/Source/CPack/WiX/cmCPackWIXGenerator.cxx
@@ -0,0 +1,1134 @@
+/*============================================================================
+ CMake - Cross Platform Makefile Generator
+ Copyright 2012-2015 Kitware, Inc., Insight Software Consortium
+
+ Distributed under the OSI-approved BSD License (the "License");
+ see accompanying file Copyright.txt for details.
+
+ This software is distributed WITHOUT ANY WARRANTY; without even the
+ implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
+ See the License for more information.
+============================================================================*/
+
+#include "cmCPackWIXGenerator.h"
+
+#include <CPack/cmCPackComponentGroup.h>
+#include <CPack/cmCPackLog.h>
+#include <cmCryptoHash.h>
+#include <cmGeneratedFileStream.h>
+#include <cmInstalledFile.h>
+#include <cmSystemTools.h>
+
+#include "cmWIXDirectoriesSourceWriter.h"
+#include "cmWIXFeaturesSourceWriter.h"
+#include "cmWIXFilesSourceWriter.h"
+#include "cmWIXRichTextFormatWriter.h"
+#include "cmWIXSourceWriter.h"
+
+#include <cmsys/Directory.hxx>
+#include <cmsys/Encoding.hxx>
+#include <cmsys/FStream.hxx>
+#include <cmsys/SystemTools.hxx>
+
+#include <rpc.h> // for GUID generation
+
+cmCPackWIXGenerator::cmCPackWIXGenerator()
+ : Patch(0)
+{
+}
+
+cmCPackWIXGenerator::~cmCPackWIXGenerator()
+{
+ if (this->Patch) {
+ delete this->Patch;
+ }
+}
+
+int cmCPackWIXGenerator::InitializeInternal()
+{
+ componentPackageMethod = ONE_PACKAGE;
+ this->Patch = new cmWIXPatch(this->Logger);
+
+ return this->Superclass::InitializeInternal();
+}
+
+bool cmCPackWIXGenerator::RunWiXCommand(std::string const& command)
+{
+ std::string logFileName = this->CPackTopLevel + "/wix.log";
+
+ cmCPackLogger(cmCPackLog::LOG_DEBUG, "Running WiX command: " << command
+ << std::endl);
+
+ std::string output;
+
+ int returnValue = 0;
+ bool status = cmSystemTools::RunSingleCommand(command.c_str(), &output,
+ &output, &returnValue, 0,
+ cmSystemTools::OUTPUT_NONE);
+
+ cmsys::ofstream logFile(logFileName.c_str(), std::ios::app);
+ logFile << command << std::endl;
+ logFile << output;
+ logFile.close();
+
+ if (!status || returnValue) {
+ cmCPackLogger(cmCPackLog::LOG_ERROR, "Problem running WiX candle. "
+ "Please check '"
+ << logFileName << "' for errors." << std::endl);
+
+ return false;
+ }
+
+ return true;
+}
+
+bool cmCPackWIXGenerator::RunCandleCommand(std::string const& sourceFile,
+ std::string const& objectFile)
+{
+ std::string executable;
+ if (!RequireOption("CPACK_WIX_CANDLE_EXECUTABLE", executable)) {
+ return false;
+ }
+
+ std::ostringstream command;
+ command << QuotePath(executable);
+ command << " -nologo";
+ command << " -arch " << GetArchitecture();
+ command << " -out " << QuotePath(objectFile);
+
+ for (extension_set_t::const_iterator i = CandleExtensions.begin();
+ i != CandleExtensions.end(); ++i) {
+ command << " -ext " << QuotePath(*i);
+ }
+
+ AddCustomFlags("CPACK_WIX_CANDLE_EXTRA_FLAGS", command);
+
+ command << " " << QuotePath(sourceFile);
+
+ return RunWiXCommand(command.str());
+}
+
+bool cmCPackWIXGenerator::RunLightCommand(std::string const& objectFiles)
+{
+ std::string executable;
+ if (!RequireOption("CPACK_WIX_LIGHT_EXECUTABLE", executable)) {
+ return false;
+ }
+
+ std::ostringstream command;
+ command << QuotePath(executable);
+ command << " -nologo";
+ command << " -out " << QuotePath(packageFileNames.at(0));
+
+ for (extension_set_t::const_iterator i = this->LightExtensions.begin();
+ i != this->LightExtensions.end(); ++i) {
+ command << " -ext " << QuotePath(*i);
+ }
+
+ const char* const cultures = GetOption("CPACK_WIX_CULTURES");
+ if (cultures) {
+ command << " -cultures:" << cultures;
+ }
+
+ AddCustomFlags("CPACK_WIX_LIGHT_EXTRA_FLAGS", command);
+
+ command << " " << objectFiles;
+
+ return RunWiXCommand(command.str());
+}
+
+int cmCPackWIXGenerator::PackageFiles()
+{
+ if (!PackageFilesImpl() || cmSystemTools::GetErrorOccuredFlag()) {
+ cmCPackLogger(cmCPackLog::LOG_ERROR, "Fatal WiX Generator Error"
+ << std::endl);
+ return false;
+ }
+
+ return true;
+}
+
+bool cmCPackWIXGenerator::InitializeWiXConfiguration()
+{
+ if (!ReadListFile("CPackWIX.cmake")) {
+ cmCPackLogger(cmCPackLog::LOG_ERROR, "Error while executing CPackWIX.cmake"
+ << std::endl);
+ return false;
+ }
+
+ if (GetOption("CPACK_WIX_PRODUCT_GUID") == 0) {
+ std::string guid = GenerateGUID();
+ SetOption("CPACK_WIX_PRODUCT_GUID", guid.c_str());
+
+ cmCPackLogger(cmCPackLog::LOG_VERBOSE,
+ "CPACK_WIX_PRODUCT_GUID implicitly set to " << guid << " . "
+ << std::endl);
+ }
+
+ if (GetOption("CPACK_WIX_UPGRADE_GUID") == 0) {
+ std::string guid = GenerateGUID();
+ SetOption("CPACK_WIX_UPGRADE_GUID", guid.c_str());
+
+ cmCPackLogger(
+ cmCPackLog::LOG_WARNING, "CPACK_WIX_UPGRADE_GUID implicitly set to "
+ << guid << " . "
+ "Please refer to the documentation on how and why "
+ "you might want to set this explicitly."
+ << std::endl);
+ }
+
+ if (!RequireOption("CPACK_TOPLEVEL_DIRECTORY", this->CPackTopLevel)) {
+ return false;
+ }
+
+ if (GetOption("CPACK_WIX_LICENSE_RTF") == 0) {
+ std::string licenseFilename = this->CPackTopLevel + "/License.rtf";
+ SetOption("CPACK_WIX_LICENSE_RTF", licenseFilename.c_str());
+
+ if (!CreateLicenseFile()) {
+ return false;
+ }
+ }
+
+ if (GetOption("CPACK_PACKAGE_VENDOR") == 0) {
+ std::string defaultVendor = "Humanity";
+ SetOption("CPACK_PACKAGE_VENDOR", defaultVendor.c_str());
+
+ cmCPackLogger(cmCPackLog::LOG_VERBOSE,
+ "CPACK_PACKAGE_VENDOR implicitly set to "
+ << defaultVendor << " . " << std::endl);
+ }
+
+ if (GetOption("CPACK_WIX_UI_REF") == 0) {
+ std::string defaultRef = "WixUI_InstallDir";
+
+ if (!this->Components.empty()) {
+ defaultRef = "WixUI_FeatureTree";
+ }
+
+ SetOption("CPACK_WIX_UI_REF", defaultRef.c_str());
+ }
+
+ const char* packageContact = GetOption("CPACK_PACKAGE_CONTACT");
+ if (packageContact != 0 && GetOption("CPACK_WIX_PROPERTY_ARPCONTACT") == 0) {
+ SetOption("CPACK_WIX_PROPERTY_ARPCONTACT", packageContact);
+ }
+
+ CollectExtensions("CPACK_WIX_EXTENSIONS", this->CandleExtensions);
+ CollectExtensions("CPACK_WIX_CANDLE_EXTENSIONS", this->CandleExtensions);
+
+ this->LightExtensions.insert("WixUIExtension");
+ CollectExtensions("CPACK_WIX_EXTENSIONS", this->LightExtensions);
+ CollectExtensions("CPACK_WIX_LIGHT_EXTENSIONS", this->LightExtensions);
+
+ const char* patchFilePath = GetOption("CPACK_WIX_PATCH_FILE");
+ if (patchFilePath) {
+ std::vector<std::string> patchFilePaths;
+ cmSystemTools::ExpandListArgument(patchFilePath, patchFilePaths);
+
+ for (size_t i = 0; i < patchFilePaths.size(); ++i) {
+ if (!this->Patch->LoadFragments(patchFilePaths[i])) {
+ return false;
+ }
+ }
+ }
+
+ return true;
+}
+
+bool cmCPackWIXGenerator::PackageFilesImpl()
+{
+ if (!InitializeWiXConfiguration()) {
+ return false;
+ }
+
+ CreateWiXVariablesIncludeFile();
+ CreateWiXPropertiesIncludeFile();
+ CreateWiXProductFragmentIncludeFile();
+
+ if (!CreateWiXSourceFiles()) {
+ return false;
+ }
+
+ AppendUserSuppliedExtraSources();
+
+ std::set<std::string> usedBaseNames;
+
+ std::ostringstream objectFiles;
+ for (size_t i = 0; i < this->WixSources.size(); ++i) {
+ std::string const& sourceFilename = this->WixSources[i];
+
+ std::string baseName =
+ cmSystemTools::GetFilenameWithoutLastExtension(sourceFilename);
+
+ unsigned int counter = 0;
+ std::string uniqueBaseName = baseName;
+
+ while (usedBaseNames.find(uniqueBaseName) != usedBaseNames.end()) {
+ std::ostringstream tmp;
+ tmp << baseName << ++counter;
+ uniqueBaseName = tmp.str();
+ }
+
+ usedBaseNames.insert(uniqueBaseName);
+
+ std::string objectFilename =
+ this->CPackTopLevel + "/" + uniqueBaseName + ".wixobj";
+
+ if (!RunCandleCommand(sourceFilename, objectFilename)) {
+ return false;
+ }
+
+ objectFiles << " " << QuotePath(objectFilename);
+ }
+
+ AppendUserSuppliedExtraObjects(objectFiles);
+
+ return RunLightCommand(objectFiles.str());
+}
+
+void cmCPackWIXGenerator::AppendUserSuppliedExtraSources()
+{
+ const char* cpackWixExtraSources = GetOption("CPACK_WIX_EXTRA_SOURCES");
+ if (!cpackWixExtraSources)
+ return;
+
+ cmSystemTools::ExpandListArgument(cpackWixExtraSources, this->WixSources);
+}
+
+void cmCPackWIXGenerator::AppendUserSuppliedExtraObjects(std::ostream& stream)
+{
+ const char* cpackWixExtraObjects = GetOption("CPACK_WIX_EXTRA_OBJECTS");
+ if (!cpackWixExtraObjects)
+ return;
+
+ std::vector<std::string> expandedExtraObjects;
+
+ cmSystemTools::ExpandListArgument(cpackWixExtraObjects,
+ expandedExtraObjects);
+
+ for (size_t i = 0; i < expandedExtraObjects.size(); ++i) {
+ stream << " " << QuotePath(expandedExtraObjects[i]);
+ }
+}
+
+void cmCPackWIXGenerator::CreateWiXVariablesIncludeFile()
+{
+ std::string includeFilename = this->CPackTopLevel + "/cpack_variables.wxi";
+
+ cmWIXSourceWriter includeFile(this->Logger, includeFilename, true);
+
+ CopyDefinition(includeFile, "CPACK_WIX_PRODUCT_GUID");
+ CopyDefinition(includeFile, "CPACK_WIX_UPGRADE_GUID");
+ CopyDefinition(includeFile, "CPACK_PACKAGE_VENDOR");
+ CopyDefinition(includeFile, "CPACK_PACKAGE_NAME");
+ CopyDefinition(includeFile, "CPACK_PACKAGE_VERSION");
+ CopyDefinition(includeFile, "CPACK_WIX_LICENSE_RTF");
+ CopyDefinition(includeFile, "CPACK_WIX_PRODUCT_ICON");
+ CopyDefinition(includeFile, "CPACK_WIX_UI_BANNER");
+ CopyDefinition(includeFile, "CPACK_WIX_UI_DIALOG");
+ SetOptionIfNotSet("CPACK_WIX_PROGRAM_MENU_FOLDER",
+ GetOption("CPACK_PACKAGE_NAME"));
+ CopyDefinition(includeFile, "CPACK_WIX_PROGRAM_MENU_FOLDER");
+ CopyDefinition(includeFile, "CPACK_WIX_UI_REF");
+}
+
+void cmCPackWIXGenerator::CreateWiXPropertiesIncludeFile()
+{
+ std::string includeFilename = this->CPackTopLevel + "/properties.wxi";
+
+ cmWIXSourceWriter includeFile(this->Logger, includeFilename, true);
+
+ std::string prefix = "CPACK_WIX_PROPERTY_";
+ std::vector<std::string> options = GetOptions();
+
+ for (size_t i = 0; i < options.size(); ++i) {
+ std::string const& name = options[i];
+
+ if (name.length() > prefix.length() &&
+ name.substr(0, prefix.length()) == prefix) {
+ std::string id = name.substr(prefix.length());
+ std::string value = GetOption(name.c_str());
+
+ includeFile.BeginElement("Property");
+ includeFile.AddAttribute("Id", id);
+ includeFile.AddAttribute("Value", value);
+ includeFile.EndElement("Property");
+ }
+ }
+
+ if (GetOption("CPACK_WIX_PROPERTY_ARPINSTALLLOCATION") == 0) {
+ includeFile.BeginElement("Property");
+ includeFile.AddAttribute("Id", "INSTALL_ROOT");
+ includeFile.AddAttribute("Secure", "yes");
+
+ includeFile.BeginElement("RegistrySearch");
+ includeFile.AddAttribute("Id", "FindInstallLocation");
+ includeFile.AddAttribute("Root", "HKLM");
+ includeFile.AddAttribute(
+ "Key", "Software\\Microsoft\\Windows\\"
+ "CurrentVersion\\Uninstall\\[WIX_UPGRADE_DETECTED]");
+ includeFile.AddAttribute("Name", "InstallLocation");
+ includeFile.AddAttribute("Type", "raw");
+ includeFile.EndElement("RegistrySearch");
+ includeFile.EndElement("Property");
+
+ includeFile.BeginElement("SetProperty");
+ includeFile.AddAttribute("Id", "ARPINSTALLLOCATION");
+ includeFile.AddAttribute("Value", "[INSTALL_ROOT]");
+ includeFile.AddAttribute("After", "CostFinalize");
+ includeFile.EndElement("SetProperty");
+ }
+}
+
+void cmCPackWIXGenerator::CreateWiXProductFragmentIncludeFile()
+{
+ std::string includeFilename = this->CPackTopLevel + "/product_fragment.wxi";
+
+ cmWIXSourceWriter includeFile(this->Logger, includeFilename, true);
+
+ this->Patch->ApplyFragment("#PRODUCT", includeFile);
+}
+
+void cmCPackWIXGenerator::CopyDefinition(cmWIXSourceWriter& source,
+ std::string const& name)
+{
+ const char* value = GetOption(name.c_str());
+ if (value) {
+ AddDefinition(source, name, value);
+ }
+}
+
+void cmCPackWIXGenerator::AddDefinition(cmWIXSourceWriter& source,
+ std::string const& name,
+ std::string const& value)
+{
+ std::ostringstream tmp;
+ tmp << name << "=\"" << value << '"';
+
+ source.AddProcessingInstruction(
+ "define", cmWIXSourceWriter::CMakeEncodingToUtf8(tmp.str()));
+}
+
+bool cmCPackWIXGenerator::CreateWiXSourceFiles()
+{
+ std::string directoryDefinitionsFilename =
+ this->CPackTopLevel + "/directories.wxs";
+
+ this->WixSources.push_back(directoryDefinitionsFilename);
+
+ cmWIXDirectoriesSourceWriter directoryDefinitions(
+ this->Logger, directoryDefinitionsFilename);
+ directoryDefinitions.BeginElement("Fragment");
+
+ std::string installRoot;
+ if (!RequireOption("CPACK_PACKAGE_INSTALL_DIRECTORY", installRoot)) {
+ return false;
+ }
+
+ directoryDefinitions.BeginElement("Directory");
+ directoryDefinitions.AddAttribute("Id", "TARGETDIR");
+ directoryDefinitions.AddAttribute("Name", "SourceDir");
+
+ size_t installRootSize =
+ directoryDefinitions.BeginInstallationPrefixDirectory(
+ GetProgramFilesFolderId(), installRoot);
+
+ std::string fileDefinitionsFilename = this->CPackTopLevel + "/files.wxs";
+
+ this->WixSources.push_back(fileDefinitionsFilename);
+
+ cmWIXFilesSourceWriter fileDefinitions(this->Logger,
+ fileDefinitionsFilename);
+
+ fileDefinitions.BeginElement("Fragment");
+
+ std::string featureDefinitionsFilename =
+ this->CPackTopLevel + "/features.wxs";
+
+ this->WixSources.push_back(featureDefinitionsFilename);
+
+ cmWIXFeaturesSourceWriter featureDefinitions(this->Logger,
+ featureDefinitionsFilename);
+
+ featureDefinitions.BeginElement("Fragment");
+
+ featureDefinitions.BeginElement("Feature");
+ featureDefinitions.AddAttribute("Id", "ProductFeature");
+ featureDefinitions.AddAttribute("Display", "expand");
+ featureDefinitions.AddAttribute("Absent", "disallow");
+ featureDefinitions.AddAttribute("ConfigurableDirectory", "INSTALL_ROOT");
+
+ std::string cpackPackageName;
+ if (!RequireOption("CPACK_PACKAGE_NAME", cpackPackageName)) {
+ return false;
+ }
+
+ std::string featureTitle = cpackPackageName;
+ if (const char* title = GetOption("CPACK_WIX_ROOT_FEATURE_TITLE")) {
+ featureTitle = title;
+ }
+ featureDefinitions.AddAttribute("Title", featureTitle);
+ if (const char* desc = GetOption("CPACK_WIX_ROOT_FEATURE_DESCRIPTION")) {
+ featureDefinitions.AddAttribute("Description", desc);
+ }
+ featureDefinitions.AddAttribute("Level", "1");
+ this->Patch->ApplyFragment("#PRODUCTFEATURE", featureDefinitions);
+
+ const char* package = GetOption("CPACK_WIX_CMAKE_PACKAGE_REGISTRY");
+ if (package) {
+ featureDefinitions.CreateCMakePackageRegistryEntry(
+ package, GetOption("CPACK_WIX_UPGRADE_GUID"));
+ }
+
+ if (!CreateFeatureHierarchy(featureDefinitions)) {
+ return false;
+ }
+
+ featureDefinitions.EndElement("Feature");
+
+ std::set<cmWIXShortcuts::Type> emittedShortcutTypes;
+
+ cmWIXShortcuts globalShortcuts;
+ if (Components.empty()) {
+ AddComponentsToFeature(toplevel, "ProductFeature", directoryDefinitions,
+ fileDefinitions, featureDefinitions,
+ globalShortcuts);
+
+ globalShortcuts.AddShortcutTypes(emittedShortcutTypes);
+ } else {
+ for (std::map<std::string, cmCPackComponent>::const_iterator i =
+ this->Components.begin();
+ i != this->Components.end(); ++i) {
+ cmCPackComponent const& component = i->second;
+
+ std::string componentPath = toplevel;
+ componentPath += "/";
+ componentPath += component.Name;
+
+ std::string componentFeatureId = "CM_C_" + component.Name;
+
+ cmWIXShortcuts featureShortcuts;
+ AddComponentsToFeature(componentPath, componentFeatureId,
+ directoryDefinitions, fileDefinitions,
+ featureDefinitions, featureShortcuts);
+
+ featureShortcuts.AddShortcutTypes(emittedShortcutTypes);
+
+ if (!CreateShortcuts(component.Name, componentFeatureId,
+ featureShortcuts, false, fileDefinitions,
+ featureDefinitions)) {
+ return false;
+ }
+ }
+ }
+
+ bool emitUninstallShortcut =
+ emittedShortcutTypes.find(cmWIXShortcuts::START_MENU) !=
+ emittedShortcutTypes.end();
+
+ if (!CreateShortcuts(std::string(), "ProductFeature", globalShortcuts,
+ emitUninstallShortcut, fileDefinitions,
+ featureDefinitions)) {
+ return false;
+ }
+
+ featureDefinitions.EndElement("Fragment");
+ fileDefinitions.EndElement("Fragment");
+
+ directoryDefinitions.EndInstallationPrefixDirectory(installRootSize);
+
+ if (emittedShortcutTypes.find(cmWIXShortcuts::START_MENU) !=
+ emittedShortcutTypes.end()) {
+ directoryDefinitions.EmitStartMenuFolder(
+ GetOption("CPACK_WIX_PROGRAM_MENU_FOLDER"));
+ }
+
+ if (emittedShortcutTypes.find(cmWIXShortcuts::DESKTOP) !=
+ emittedShortcutTypes.end()) {
+ directoryDefinitions.EmitDesktopFolder();
+ }
+
+ if (emittedShortcutTypes.find(cmWIXShortcuts::STARTUP) !=
+ emittedShortcutTypes.end()) {
+ directoryDefinitions.EmitStartupFolder();
+ }
+
+ directoryDefinitions.EndElement("Directory");
+ directoryDefinitions.EndElement("Fragment");
+
+ if (!GenerateMainSourceFileFromTemplate()) {
+ return false;
+ }
+
+ return this->Patch->CheckForUnappliedFragments();
+}
+
+std::string cmCPackWIXGenerator::GetProgramFilesFolderId() const
+{
+ if (GetArchitecture() == "x86") {
+ return "ProgramFilesFolder";
+ } else {
+ return "ProgramFiles64Folder";
+ }
+}
+
+bool cmCPackWIXGenerator::GenerateMainSourceFileFromTemplate()
+{
+ std::string wixTemplate = FindTemplate("WIX.template.in");
+ if (GetOption("CPACK_WIX_TEMPLATE") != 0) {
+ wixTemplate = GetOption("CPACK_WIX_TEMPLATE");
+ }
+
+ if (wixTemplate.empty()) {
+ cmCPackLogger(cmCPackLog::LOG_ERROR,
+ "Could not find CPack WiX template file WIX.template.in"
+ << std::endl);
+ return false;
+ }
+
+ std::string mainSourceFilePath = this->CPackTopLevel + "/main.wxs";
+
+ if (!ConfigureFile(wixTemplate.c_str(), mainSourceFilePath.c_str())) {
+ cmCPackLogger(cmCPackLog::LOG_ERROR, "Failed creating '"
+ << mainSourceFilePath << "'' from template." << std::endl);
+
+ return false;
+ }
+
+ this->WixSources.push_back(mainSourceFilePath);
+
+ return true;
+}
+
+bool cmCPackWIXGenerator::CreateFeatureHierarchy(
+ cmWIXFeaturesSourceWriter& featureDefinitions)
+{
+ for (std::map<std::string, cmCPackComponentGroup>::const_iterator i =
+ ComponentGroups.begin();
+ i != ComponentGroups.end(); ++i) {
+ cmCPackComponentGroup const& group = i->second;
+ if (group.ParentGroup == 0) {
+ featureDefinitions.EmitFeatureForComponentGroup(group);
+ }
+ }
+
+ for (std::map<std::string, cmCPackComponent>::const_iterator i =
+ this->Components.begin();
+ i != this->Components.end(); ++i) {
+ cmCPackComponent const& component = i->second;
+
+ if (!component.Group) {
+ featureDefinitions.EmitFeatureForComponent(component);
+ }
+ }
+
+ return true;
+}
+
+bool cmCPackWIXGenerator::AddComponentsToFeature(
+ std::string const& rootPath, std::string const& featureId,
+ cmWIXDirectoriesSourceWriter& directoryDefinitions,
+ cmWIXFilesSourceWriter& fileDefinitions,
+ cmWIXFeaturesSourceWriter& featureDefinitions, cmWIXShortcuts& shortcuts)
+{
+ featureDefinitions.BeginElement("FeatureRef");
+ featureDefinitions.AddAttribute("Id", featureId);
+
+ std::vector<std::string> cpackPackageExecutablesList;
+ const char* cpackPackageExecutables = GetOption("CPACK_PACKAGE_EXECUTABLES");
+ if (cpackPackageExecutables) {
+ cmSystemTools::ExpandListArgument(cpackPackageExecutables,
+ cpackPackageExecutablesList);
+ if (cpackPackageExecutablesList.size() % 2 != 0) {
+ cmCPackLogger(
+ cmCPackLog::LOG_ERROR,
+ "CPACK_PACKAGE_EXECUTABLES should contain pairs of <executable> and "
+ "<text label>."
+ << std::endl);
+ return false;
+ }
+ }
+
+ std::vector<std::string> cpackPackageDesktopLinksList;
+ const char* cpackPackageDesktopLinks =
+ GetOption("CPACK_CREATE_DESKTOP_LINKS");
+ if (cpackPackageDesktopLinks) {
+ cmSystemTools::ExpandListArgument(cpackPackageDesktopLinks,
+ cpackPackageDesktopLinksList);
+ }
+
+ AddDirectoryAndFileDefinitons(rootPath, "INSTALL_ROOT", directoryDefinitions,
+ fileDefinitions, featureDefinitions,
+ cpackPackageExecutablesList,
+ cpackPackageDesktopLinksList, shortcuts);
+
+ featureDefinitions.EndElement("FeatureRef");
+
+ return true;
+}
+
+bool cmCPackWIXGenerator::CreateShortcuts(
+ std::string const& cpackComponentName, std::string const& featureId,
+ cmWIXShortcuts const& shortcuts, bool emitUninstallShortcut,
+ cmWIXFilesSourceWriter& fileDefinitions,
+ cmWIXFeaturesSourceWriter& featureDefinitions)
+{
+ if (!shortcuts.empty(cmWIXShortcuts::START_MENU)) {
+ if (!this->CreateShortcutsOfSpecificType(
+ cmWIXShortcuts::START_MENU, cpackComponentName, featureId, "",
+ shortcuts, emitUninstallShortcut, fileDefinitions,
+ featureDefinitions)) {
+ return false;
+ }
+ }
+
+ if (!shortcuts.empty(cmWIXShortcuts::DESKTOP)) {
+ if (!this->CreateShortcutsOfSpecificType(
+ cmWIXShortcuts::DESKTOP, cpackComponentName, featureId, "DESKTOP",
+ shortcuts, false, fileDefinitions, featureDefinitions)) {
+ return false;
+ }
+ }
+
+ if (!shortcuts.empty(cmWIXShortcuts::STARTUP)) {
+ if (!this->CreateShortcutsOfSpecificType(
+ cmWIXShortcuts::STARTUP, cpackComponentName, featureId, "STARTUP",
+ shortcuts, false, fileDefinitions, featureDefinitions)) {
+ return false;
+ }
+ }
+
+ return true;
+}
+
+bool cmCPackWIXGenerator::CreateShortcutsOfSpecificType(
+ cmWIXShortcuts::Type type, std::string const& cpackComponentName,
+ std::string const& featureId, std::string const& idPrefix,
+ cmWIXShortcuts const& shortcuts, bool emitUninstallShortcut,
+ cmWIXFilesSourceWriter& fileDefinitions,
+ cmWIXFeaturesSourceWriter& featureDefinitions)
+{
+ std::string directoryId;
+ switch (type) {
+ case cmWIXShortcuts::START_MENU:
+ directoryId = "PROGRAM_MENU_FOLDER";
+ break;
+ case cmWIXShortcuts::DESKTOP:
+ directoryId = "DesktopFolder";
+ break;
+ case cmWIXShortcuts::STARTUP:
+ directoryId = "StartupFolder";
+ break;
+ default:
+ return false;
+ }
+
+ featureDefinitions.BeginElement("FeatureRef");
+ featureDefinitions.AddAttribute("Id", featureId);
+
+ std::string cpackVendor;
+ if (!RequireOption("CPACK_PACKAGE_VENDOR", cpackVendor)) {
+ return false;
+ }
+
+ std::string cpackPackageName;
+ if (!RequireOption("CPACK_PACKAGE_NAME", cpackPackageName)) {
+ return false;
+ }
+
+ std::string idSuffix;
+ if (!cpackComponentName.empty()) {
+ idSuffix += "_";
+ idSuffix += cpackComponentName;
+ }
+
+ std::string componentId = "CM_SHORTCUT";
+ if (idPrefix.size()) {
+ componentId += "_" + idPrefix;
+ }
+
+ componentId += idSuffix;
+
+ fileDefinitions.BeginElement("DirectoryRef");
+ fileDefinitions.AddAttribute("Id", directoryId);
+
+ fileDefinitions.BeginElement("Component");
+ fileDefinitions.AddAttribute("Id", componentId);
+ fileDefinitions.AddAttribute("Guid", "*");
+
+ this->Patch->ApplyFragment(componentId, fileDefinitions);
+
+ std::string registryKey =
+ std::string("Software\\") + cpackVendor + "\\" + cpackPackageName;
+
+ shortcuts.EmitShortcuts(type, registryKey, cpackComponentName,
+ fileDefinitions);
+
+ if (type == cmWIXShortcuts::START_MENU) {
+ fileDefinitions.EmitRemoveFolder("CM_REMOVE_PROGRAM_MENU_FOLDER" +
+ idSuffix);
+ }
+
+ if (emitUninstallShortcut) {
+ fileDefinitions.EmitUninstallShortcut(cpackPackageName);
+ }
+
+ fileDefinitions.EndElement("Component");
+ fileDefinitions.EndElement("DirectoryRef");
+
+ featureDefinitions.EmitComponentRef(componentId);
+ featureDefinitions.EndElement("FeatureRef");
+
+ return true;
+}
+
+bool cmCPackWIXGenerator::CreateLicenseFile()
+{
+ std::string licenseSourceFilename;
+ if (!RequireOption("CPACK_RESOURCE_FILE_LICENSE", licenseSourceFilename)) {
+ return false;
+ }
+
+ std::string licenseDestinationFilename;
+ if (!RequireOption("CPACK_WIX_LICENSE_RTF", licenseDestinationFilename)) {
+ return false;
+ }
+
+ std::string extension = GetRightmostExtension(licenseSourceFilename);
+
+ if (extension == ".rtf") {
+ cmSystemTools::CopyAFile(licenseSourceFilename.c_str(),
+ licenseDestinationFilename.c_str());
+ } else if (extension == ".txt") {
+ cmWIXRichTextFormatWriter rtfWriter(licenseDestinationFilename);
+
+ cmsys::ifstream licenseSource(licenseSourceFilename.c_str());
+
+ std::string line;
+ while (std::getline(licenseSource, line)) {
+ rtfWriter.AddText(line);
+ rtfWriter.AddText("\n");
+ }
+ } else {
+ cmCPackLogger(cmCPackLog::LOG_ERROR,
+ "unsupported WiX License file extension '"
+ << extension << "'" << std::endl);
+
+ return false;
+ }
+
+ return true;
+}
+
+void cmCPackWIXGenerator::AddDirectoryAndFileDefinitons(
+ std::string const& topdir, std::string const& directoryId,
+ cmWIXDirectoriesSourceWriter& directoryDefinitions,
+ cmWIXFilesSourceWriter& fileDefinitions,
+ cmWIXFeaturesSourceWriter& featureDefinitions,
+ std::vector<std::string> const& packageExecutables,
+ std::vector<std::string> const& desktopExecutables,
+ cmWIXShortcuts& shortcuts)
+{
+ cmsys::Directory dir;
+ dir.Load(topdir.c_str());
+
+ std::string relativeDirectoryPath =
+ cmSystemTools::RelativePath(toplevel.c_str(), topdir.c_str());
+
+ if (relativeDirectoryPath.empty()) {
+ relativeDirectoryPath = ".";
+ }
+
+ cmInstalledFile const* directoryInstalledFile = this->GetInstalledFile(
+ this->RelativePathWithoutComponentPrefix(relativeDirectoryPath));
+
+ bool emptyDirectory = dir.GetNumberOfFiles() == 2;
+ bool createDirectory = false;
+
+ if (emptyDirectory) {
+ createDirectory = true;
+ }
+
+ if (directoryInstalledFile) {
+ if (directoryInstalledFile->HasProperty("CPACK_WIX_ACL")) {
+ createDirectory = true;
+ }
+ }
+
+ if (createDirectory) {
+ std::string componentId = fileDefinitions.EmitComponentCreateFolder(
+ directoryId, GenerateGUID(), directoryInstalledFile);
+ featureDefinitions.EmitComponentRef(componentId);
+ }
+
+ if (emptyDirectory) {
+ return;
+ }
+
+ for (size_t i = 0; i < dir.GetNumberOfFiles(); ++i) {
+ std::string fileName = dir.GetFile(static_cast<unsigned long>(i));
+
+ if (fileName == "." || fileName == "..") {
+ continue;
+ }
+
+ std::string fullPath = topdir + "/" + fileName;
+
+ std::string relativePath =
+ cmSystemTools::RelativePath(toplevel.c_str(), fullPath.c_str());
+
+ std::string id = PathToId(relativePath);
+
+ if (cmSystemTools::FileIsDirectory(fullPath.c_str())) {
+ std::string subDirectoryId = std::string("CM_D") + id;
+
+ directoryDefinitions.BeginElement("Directory");
+ directoryDefinitions.AddAttribute("Id", subDirectoryId);
+ directoryDefinitions.AddAttribute("Name", fileName);
+
+ AddDirectoryAndFileDefinitons(
+ fullPath, subDirectoryId, directoryDefinitions, fileDefinitions,
+ featureDefinitions, packageExecutables, desktopExecutables, shortcuts);
+
+ this->Patch->ApplyFragment(subDirectoryId, directoryDefinitions);
+ directoryDefinitions.EndElement("Directory");
+ } else {
+ cmInstalledFile const* installedFile = this->GetInstalledFile(
+ this->RelativePathWithoutComponentPrefix(relativePath));
+
+ if (installedFile) {
+ shortcuts.CreateFromProperties(id, directoryId, *installedFile);
+ }
+
+ std::string componentId = fileDefinitions.EmitComponentFile(
+ directoryId, id, fullPath, *(this->Patch), installedFile);
+
+ featureDefinitions.EmitComponentRef(componentId);
+
+ for (size_t j = 0; j < packageExecutables.size(); ++j) {
+ std::string const& executableName = packageExecutables[j++];
+ std::string const& textLabel = packageExecutables[j];
+
+ if (cmSystemTools::LowerCase(fileName) ==
+ cmSystemTools::LowerCase(executableName) + ".exe") {
+ cmWIXShortcut shortcut;
+ shortcut.label = textLabel;
+ shortcut.workingDirectoryId = directoryId;
+ shortcuts.insert(cmWIXShortcuts::START_MENU, id, shortcut);
+
+ if (!desktopExecutables.empty() &&
+ std::find(desktopExecutables.begin(), desktopExecutables.end(),
+ executableName) != desktopExecutables.end()) {
+ shortcuts.insert(cmWIXShortcuts::DESKTOP, id, shortcut);
+ }
+ }
+ }
+ }
+ }
+}
+
+bool cmCPackWIXGenerator::RequireOption(std::string const& name,
+ std::string& value) const
+{
+ const char* tmp = GetOption(name.c_str());
+ if (tmp) {
+ value = tmp;
+
+ return true;
+ } else {
+ cmCPackLogger(cmCPackLog::LOG_ERROR, "Required variable "
+ << name << " not set" << std::endl);
+
+ return false;
+ }
+}
+
+std::string cmCPackWIXGenerator::GetArchitecture() const
+{
+ std::string void_p_size;
+ RequireOption("CPACK_WIX_SIZEOF_VOID_P", void_p_size);
+
+ if (void_p_size == "8") {
+ return "x64";
+ } else {
+ return "x86";
+ }
+}
+
+std::string cmCPackWIXGenerator::GenerateGUID()
+{
+ UUID guid;
+ UuidCreate(&guid);
+
+ unsigned short* tmp = 0;
+ UuidToStringW(&guid, &tmp);
+
+ std::string result =
+ cmsys::Encoding::ToNarrow(reinterpret_cast<wchar_t*>(tmp));
+ RpcStringFreeW(&tmp);
+
+ return cmSystemTools::UpperCase(result);
+}
+
+std::string cmCPackWIXGenerator::QuotePath(std::string const& path)
+{
+ return std::string("\"") + path + '"';
+}
+
+std::string cmCPackWIXGenerator::GetRightmostExtension(
+ std::string const& filename)
+{
+ std::string extension;
+
+ std::string::size_type i = filename.rfind(".");
+ if (i != std::string::npos) {
+ extension = filename.substr(i);
+ }
+
+ return cmSystemTools::LowerCase(extension);
+}
+
+std::string cmCPackWIXGenerator::PathToId(std::string const& path)
+{
+ id_map_t::const_iterator i = PathToIdMap.find(path);
+ if (i != PathToIdMap.end())
+ return i->second;
+
+ std::string id = CreateNewIdForPath(path);
+ return id;
+}
+
+std::string cmCPackWIXGenerator::CreateNewIdForPath(std::string const& path)
+{
+ std::vector<std::string> components;
+ cmSystemTools::SplitPath(path.c_str(), components, false);
+
+ size_t replacementCount = 0;
+
+ std::string identifier;
+ std::string currentComponent;
+
+ for (size_t i = 1; i < components.size(); ++i) {
+ if (i != 1)
+ identifier += '.';
+
+ currentComponent =
+ NormalizeComponentForId(components[i], replacementCount);
+
+ identifier += currentComponent;
+ }
+
+ std::string idPrefix = "P";
+ size_t replacementPercent = replacementCount * 100 / identifier.size();
+ if (replacementPercent > 33 || identifier.size() > 60) {
+ identifier = CreateHashedId(path, currentComponent);
+ idPrefix = "H";
+ }
+
+ std::ostringstream result;
+ result << idPrefix << "_" << identifier;
+
+ size_t ambiguityCount = ++IdAmbiguityCounter[identifier];
+
+ if (ambiguityCount > 999) {
+ cmCPackLogger(cmCPackLog::LOG_ERROR,
+ "Error while trying to generate a unique Id for '"
+ << path << "'" << std::endl);
+
+ return std::string();
+ } else if (ambiguityCount > 1) {
+ result << "_" << ambiguityCount;
+ }
+
+ std::string resultString = result.str();
+
+ PathToIdMap[path] = resultString;
+
+ return resultString;
+}
+
+std::string cmCPackWIXGenerator::CreateHashedId(
+ std::string const& path, std::string const& normalizedFilename)
+{
+ CM_AUTO_PTR<cmCryptoHash> sha1 = cmCryptoHash::New("SHA1");
+ std::string hash = sha1->HashString(path.c_str());
+
+ std::string identifier;
+ identifier += hash.substr(0, 7) + "_";
+
+ const size_t maxFileNameLength = 52;
+ if (normalizedFilename.length() > maxFileNameLength) {
+ identifier += normalizedFilename.substr(0, maxFileNameLength - 3);
+ identifier += "...";
+ } else {
+ identifier += normalizedFilename;
+ }
+
+ return identifier;
+}
+
+std::string cmCPackWIXGenerator::NormalizeComponentForId(
+ std::string const& component, size_t& replacementCount)
+{
+ std::string result;
+ result.resize(component.size());
+
+ for (size_t i = 0; i < component.size(); ++i) {
+ char c = component[i];
+ if (IsLegalIdCharacter(c)) {
+ result[i] = c;
+ } else {
+ result[i] = '_';
+ ++replacementCount;
+ }
+ }
+
+ return result;
+}
+
+bool cmCPackWIXGenerator::IsLegalIdCharacter(char c)
+{
+ return (c >= '0' && c <= '9') || (c >= 'a' && c <= 'z') ||
+ (c >= 'A' && c <= 'Z') || c == '_' || c == '.';
+}
+
+void cmCPackWIXGenerator::CollectExtensions(std::string const& variableName,
+ extension_set_t& extensions)
+{
+ const char* variableContent = GetOption(variableName.c_str());
+ if (!variableContent)
+ return;
+
+ std::vector<std::string> list;
+ cmSystemTools::ExpandListArgument(variableContent, list);
+ extensions.insert(list.begin(), list.end());
+}
+
+void cmCPackWIXGenerator::AddCustomFlags(std::string const& variableName,
+ std::ostream& stream)
+{
+ const char* variableContent = GetOption(variableName.c_str());
+ if (!variableContent)
+ return;
+
+ std::vector<std::string> list;
+ cmSystemTools::ExpandListArgument(variableContent, list);
+
+ for (std::vector<std::string>::const_iterator i = list.begin();
+ i != list.end(); ++i) {
+ stream << " " << QuotePath(*i);
+ }
+}
+
+std::string cmCPackWIXGenerator::RelativePathWithoutComponentPrefix(
+ std::string const& path)
+{
+ if (this->Components.empty()) {
+ return path;
+ }
+
+ std::string::size_type pos = path.find('/');
+
+ return path.substr(pos + 1);
+}
diff --git a/Source/CPack/WiX/cmCPackWIXGenerator.h b/Source/CPack/WiX/cmCPackWIXGenerator.h
new file mode 100644
index 0000000..9d3a522
--- /dev/null
+++ b/Source/CPack/WiX/cmCPackWIXGenerator.h
@@ -0,0 +1,167 @@
+/*============================================================================
+ CMake - Cross Platform Makefile Generator
+ Copyright 2012-2015 Kitware, Inc.
+
+ Distributed under the OSI-approved BSD License (the "License");
+ see accompanying file Copyright.txt for details.
+
+ This software is distributed WITHOUT ANY WARRANTY; without even the
+ implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
+ See the License for more information.
+============================================================================*/
+
+#ifndef cmCPackWIXGenerator_h
+#define cmCPackWIXGenerator_h
+
+#include <CPack/cmCPackGenerator.h>
+
+#include "cmWIXPatch.h"
+#include "cmWIXShortcut.h"
+
+#include <map>
+#include <string>
+
+class cmWIXSourceWriter;
+class cmWIXDirectoriesSourceWriter;
+class cmWIXFilesSourceWriter;
+class cmWIXFeaturesSourceWriter;
+
+/** \class cmCPackWIXGenerator
+ * \brief A generator for WIX files
+ */
+class cmCPackWIXGenerator : public cmCPackGenerator
+{
+public:
+ cmCPackTypeMacro(cmCPackWIXGenerator, cmCPackGenerator);
+
+ cmCPackWIXGenerator();
+ ~cmCPackWIXGenerator();
+
+protected:
+ virtual int InitializeInternal();
+
+ virtual int PackageFiles();
+
+ virtual const char* GetOutputExtension() { return ".msi"; }
+
+ virtual enum CPackSetDestdirSupport SupportsSetDestdir() const
+ {
+ return SETDESTDIR_UNSUPPORTED;
+ }
+
+ virtual bool SupportsAbsoluteDestination() const { return false; }
+
+ virtual bool SupportsComponentInstallation() const { return true; }
+
+private:
+ typedef std::map<std::string, std::string> id_map_t;
+ typedef std::map<std::string, size_t> ambiguity_map_t;
+ typedef std::set<std::string> extension_set_t;
+
+ bool InitializeWiXConfiguration();
+
+ bool PackageFilesImpl();
+
+ void CreateWiXVariablesIncludeFile();
+
+ void CreateWiXPropertiesIncludeFile();
+
+ void CreateWiXProductFragmentIncludeFile();
+
+ void CopyDefinition(cmWIXSourceWriter& source, std::string const& name);
+
+ void AddDefinition(cmWIXSourceWriter& source, std::string const& name,
+ std::string const& value);
+
+ bool CreateWiXSourceFiles();
+
+ std::string GetProgramFilesFolderId() const;
+
+ bool GenerateMainSourceFileFromTemplate();
+
+ bool CreateFeatureHierarchy(cmWIXFeaturesSourceWriter& featureDefinitions);
+
+ bool AddComponentsToFeature(
+ std::string const& rootPath, std::string const& featureId,
+ cmWIXDirectoriesSourceWriter& directoryDefinitions,
+ cmWIXFilesSourceWriter& fileDefinitions,
+ cmWIXFeaturesSourceWriter& featureDefinitions, cmWIXShortcuts& shortcuts);
+
+ bool CreateShortcuts(std::string const& cpackComponentName,
+ std::string const& featureId,
+ cmWIXShortcuts const& shortcuts,
+ bool emitUninstallShortcut,
+ cmWIXFilesSourceWriter& fileDefinitions,
+ cmWIXFeaturesSourceWriter& featureDefinitions);
+
+ bool CreateShortcutsOfSpecificType(
+ cmWIXShortcuts::Type type, std::string const& cpackComponentName,
+ std::string const& featureId, std::string const& idPrefix,
+ cmWIXShortcuts const& shortcuts, bool emitUninstallShortcut,
+ cmWIXFilesSourceWriter& fileDefinitions,
+ cmWIXFeaturesSourceWriter& featureDefinitions);
+
+ void AppendUserSuppliedExtraSources();
+
+ void AppendUserSuppliedExtraObjects(std::ostream& stream);
+
+ bool CreateLicenseFile();
+
+ bool RunWiXCommand(std::string const& command);
+
+ bool RunCandleCommand(std::string const& sourceFile,
+ std::string const& objectFile);
+
+ bool RunLightCommand(std::string const& objectFiles);
+
+ void AddDirectoryAndFileDefinitons(
+ std::string const& topdir, std::string const& directoryId,
+ cmWIXDirectoriesSourceWriter& directoryDefinitions,
+ cmWIXFilesSourceWriter& fileDefinitions,
+ cmWIXFeaturesSourceWriter& featureDefinitions,
+ std::vector<std::string> const& packageExecutables,
+ std::vector<std::string> const& desktopExecutables,
+ cmWIXShortcuts& shortcuts);
+
+ bool RequireOption(std::string const& name, std::string& value) const;
+
+ std::string GetArchitecture() const;
+
+ static std::string GenerateGUID();
+
+ static std::string QuotePath(std::string const& path);
+
+ static std::string GetRightmostExtension(std::string const& filename);
+
+ std::string PathToId(std::string const& path);
+
+ std::string CreateNewIdForPath(std::string const& path);
+
+ static std::string CreateHashedId(std::string const& path,
+ std::string const& normalizedFilename);
+
+ std::string NormalizeComponentForId(std::string const& component,
+ size_t& replacementCount);
+
+ static bool IsLegalIdCharacter(char c);
+
+ void CollectExtensions(std::string const& variableName,
+ extension_set_t& extensions);
+
+ void AddCustomFlags(std::string const& variableName, std::ostream& stream);
+
+ std::string RelativePathWithoutComponentPrefix(std::string const& path);
+
+ std::vector<std::string> WixSources;
+ id_map_t PathToIdMap;
+ ambiguity_map_t IdAmbiguityCounter;
+
+ extension_set_t CandleExtensions;
+ extension_set_t LightExtensions;
+
+ std::string CPackTopLevel;
+
+ cmWIXPatch* Patch;
+};
+
+#endif
diff --git a/Source/CPack/WiX/cmWIXAccessControlList.cxx b/Source/CPack/WiX/cmWIXAccessControlList.cxx
new file mode 100644
index 0000000..bbbd92d
--- /dev/null
+++ b/Source/CPack/WiX/cmWIXAccessControlList.cxx
@@ -0,0 +1,136 @@
+/*============================================================================
+ CMake - Cross Platform Makefile Generator
+ Copyright 2014 Kitware, Inc.
+
+ Distributed under the OSI-approved BSD License (the "License");
+ see accompanying file Copyright.txt for details.
+
+ This software is distributed WITHOUT ANY WARRANTY; without even the
+ implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
+ See the License for more information.
+============================================================================*/
+
+#include "cmWIXAccessControlList.h"
+
+#include <CPack/cmCPackGenerator.h>
+
+#include <cmSystemTools.h>
+
+cmWIXAccessControlList::cmWIXAccessControlList(
+ cmCPackLog* logger, cmInstalledFile const& installedFile,
+ cmWIXSourceWriter& sourceWriter)
+ : Logger(logger)
+ , InstalledFile(installedFile)
+ , SourceWriter(sourceWriter)
+{
+}
+
+bool cmWIXAccessControlList::Apply()
+{
+ std::vector<std::string> entries;
+ this->InstalledFile.GetPropertyAsList("CPACK_WIX_ACL", entries);
+
+ for (size_t i = 0; i < entries.size(); ++i) {
+ this->CreatePermissionElement(entries[i]);
+ }
+
+ return true;
+}
+
+void cmWIXAccessControlList::CreatePermissionElement(std::string const& entry)
+{
+ std::string::size_type pos = entry.find('=');
+ if (pos == std::string::npos) {
+ this->ReportError(entry, "Did not find mandatory '='");
+ return;
+ }
+
+ std::string user_and_domain = entry.substr(0, pos);
+ std::string permission_string = entry.substr(pos + 1);
+
+ pos = user_and_domain.find('@');
+ std::string user;
+ std::string domain;
+ if (pos != std::string::npos) {
+ user = user_and_domain.substr(0, pos);
+ domain = user_and_domain.substr(pos + 1);
+ } else {
+ user = user_and_domain;
+ }
+
+ std::vector<std::string> permissions =
+ cmSystemTools::tokenize(permission_string, ",");
+
+ this->SourceWriter.BeginElement("Permission");
+ this->SourceWriter.AddAttribute("User", user);
+ if (!domain.empty()) {
+ this->SourceWriter.AddAttribute("Domain", domain);
+ }
+ for (size_t i = 0; i < permissions.size(); ++i) {
+ this->EmitBooleanAttribute(entry,
+ cmSystemTools::TrimWhitespace(permissions[i]));
+ }
+ this->SourceWriter.EndElement("Permission");
+}
+
+void cmWIXAccessControlList::ReportError(std::string const& entry,
+ std::string const& message)
+{
+ cmCPackLogger(cmCPackLog::LOG_ERROR, "Failed processing ACL entry '"
+ << entry << "': " << message << std::endl);
+}
+
+bool cmWIXAccessControlList::IsBooleanAttribute(std::string const& name)
+{
+ static const char* validAttributes[] = {
+ /* clang-format needs this comment to break after the opening brace */
+ "Append",
+ "ChangePermission",
+ "CreateChild",
+ "CreateFile",
+ "CreateLink",
+ "CreateSubkeys",
+ "Delete",
+ "DeleteChild",
+ "EnumerateSubkeys",
+ "Execute",
+ "FileAllRights",
+ "GenericAll",
+ "GenericExecute",
+ "GenericRead",
+ "GenericWrite",
+ "Notify",
+ "Read",
+ "ReadAttributes",
+ "ReadExtendedAttributes",
+ "ReadPermission",
+ "SpecificRightsAll",
+ "Synchronize",
+ "TakeOwnership",
+ "Traverse",
+ "Write",
+ "WriteAttributes",
+ "WriteExtendedAttributes",
+ 0
+ };
+
+ size_t i = 0;
+ while (validAttributes[i]) {
+ if (name == validAttributes[i++])
+ return true;
+ }
+
+ return false;
+}
+
+void cmWIXAccessControlList::EmitBooleanAttribute(std::string const& entry,
+ std::string const& name)
+{
+ if (!this->IsBooleanAttribute(name)) {
+ std::ostringstream message;
+ message << "Unknown boolean attribute '" << name << "'";
+ this->ReportError(entry, message.str());
+ }
+
+ this->SourceWriter.AddAttribute(name, "yes");
+}
diff --git a/Source/CPack/WiX/cmWIXAccessControlList.h b/Source/CPack/WiX/cmWIXAccessControlList.h
new file mode 100644
index 0000000..a1ac593
--- /dev/null
+++ b/Source/CPack/WiX/cmWIXAccessControlList.h
@@ -0,0 +1,44 @@
+/*============================================================================
+ CMake - Cross Platform Makefile Generator
+ Copyright 2014 Kitware, Inc.
+
+ Distributed under the OSI-approved BSD License (the "License");
+ see accompanying file Copyright.txt for details.
+
+ This software is distributed WITHOUT ANY WARRANTY; without even the
+ implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
+ See the License for more information.
+============================================================================*/
+
+#ifndef cmWIXAccessControlList_h
+#define cmWIXAccessControlList_h
+
+#include "cmWIXSourceWriter.h"
+
+#include <CPack/cmCPackLog.h>
+#include <cmInstalledFile.h>
+
+class cmWIXAccessControlList
+{
+public:
+ cmWIXAccessControlList(cmCPackLog* logger,
+ cmInstalledFile const& installedFile,
+ cmWIXSourceWriter& sourceWriter);
+
+ bool Apply();
+
+private:
+ void CreatePermissionElement(std::string const& entry);
+
+ void ReportError(std::string const& entry, std::string const& message);
+
+ bool IsBooleanAttribute(std::string const& name);
+
+ void EmitBooleanAttribute(std::string const& entry, std::string const& name);
+
+ cmCPackLog* Logger;
+ cmInstalledFile const& InstalledFile;
+ cmWIXSourceWriter& SourceWriter;
+};
+
+#endif
diff --git a/Source/CPack/WiX/cmWIXDirectoriesSourceWriter.cxx b/Source/CPack/WiX/cmWIXDirectoriesSourceWriter.cxx
new file mode 100644
index 0000000..de64059
--- /dev/null
+++ b/Source/CPack/WiX/cmWIXDirectoriesSourceWriter.cxx
@@ -0,0 +1,88 @@
+/*============================================================================
+ CMake - Cross Platform Makefile Generator
+ Copyright 2014 Kitware, Inc.
+
+ Distributed under the OSI-approved BSD License (the "License");
+ see accompanying file Copyright.txt for details.
+
+ This software is distributed WITHOUT ANY WARRANTY; without even the
+ implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
+ See the License for more information.
+============================================================================*/
+
+#include "cmWIXDirectoriesSourceWriter.h"
+
+cmWIXDirectoriesSourceWriter::cmWIXDirectoriesSourceWriter(
+ cmCPackLog* logger, std::string const& filename)
+ : cmWIXSourceWriter(logger, filename)
+{
+}
+
+void cmWIXDirectoriesSourceWriter::EmitStartMenuFolder(
+ std::string const& startMenuFolder)
+{
+ BeginElement("Directory");
+ AddAttribute("Id", "ProgramMenuFolder");
+
+ BeginElement("Directory");
+ AddAttribute("Id", "PROGRAM_MENU_FOLDER");
+ AddAttribute("Name", startMenuFolder);
+ EndElement("Directory");
+
+ EndElement("Directory");
+}
+
+void cmWIXDirectoriesSourceWriter::EmitDesktopFolder()
+{
+ BeginElement("Directory");
+ AddAttribute("Id", "DesktopFolder");
+ AddAttribute("Name", "Desktop");
+ EndElement("Directory");
+}
+
+void cmWIXDirectoriesSourceWriter::EmitStartupFolder()
+{
+ BeginElement("Directory");
+ AddAttribute("Id", "StartupFolder");
+ AddAttribute("Name", "Startup");
+ EndElement("Directory");
+}
+
+size_t cmWIXDirectoriesSourceWriter::BeginInstallationPrefixDirectory(
+ std::string const& programFilesFolderId,
+ std::string const& installRootString)
+{
+ BeginElement("Directory");
+ AddAttribute("Id", programFilesFolderId);
+
+ std::vector<std::string> installRoot;
+
+ cmSystemTools::SplitPath(installRootString.c_str(), installRoot);
+
+ if (!installRoot.empty() && installRoot.back().empty()) {
+ installRoot.pop_back();
+ }
+
+ for (size_t i = 1; i < installRoot.size(); ++i) {
+ BeginElement("Directory");
+
+ if (i == installRoot.size() - 1) {
+ AddAttribute("Id", "INSTALL_ROOT");
+ } else {
+ std::ostringstream tmp;
+ tmp << "INSTALL_PREFIX_" << i;
+ AddAttribute("Id", tmp.str());
+ }
+
+ AddAttribute("Name", installRoot[i]);
+ }
+
+ return installRoot.size();
+}
+
+void cmWIXDirectoriesSourceWriter::EndInstallationPrefixDirectory(size_t size)
+{
+ for (size_t i = 0; i < size; ++i) {
+ EndElement("Directory");
+ }
+}
diff --git a/Source/CPack/WiX/cmWIXDirectoriesSourceWriter.h b/Source/CPack/WiX/cmWIXDirectoriesSourceWriter.h
new file mode 100644
index 0000000..023f4b8
--- /dev/null
+++ b/Source/CPack/WiX/cmWIXDirectoriesSourceWriter.h
@@ -0,0 +1,44 @@
+/*============================================================================
+ CMake - Cross Platform Makefile Generator
+ Copyright 2014 Kitware, Inc.
+
+ Distributed under the OSI-approved BSD License (the "License");
+ see accompanying file Copyright.txt for details.
+
+ This software is distributed WITHOUT ANY WARRANTY; without even the
+ implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
+ See the License for more information.
+============================================================================*/
+
+#ifndef cmWIXDirectoriesSourceWriter_h
+#define cmWIXDirectoriesSourceWriter_h
+
+#include "cmWIXSourceWriter.h"
+
+#include <CPack/cmCPackGenerator.h>
+
+#include <string>
+
+/** \class cmWIXDirectoriesSourceWriter
+ * \brief Helper class to generate directories.wxs
+ */
+class cmWIXDirectoriesSourceWriter : public cmWIXSourceWriter
+{
+public:
+ cmWIXDirectoriesSourceWriter(cmCPackLog* logger,
+ std::string const& filename);
+
+ void EmitStartMenuFolder(std::string const& startMenuFolder);
+
+ void EmitDesktopFolder();
+
+ void EmitStartupFolder();
+
+ size_t BeginInstallationPrefixDirectory(
+ std::string const& programFilesFolderId,
+ std::string const& installRootString);
+
+ void EndInstallationPrefixDirectory(size_t size);
+};
+
+#endif
diff --git a/Source/CPack/WiX/cmWIXFeaturesSourceWriter.cxx b/Source/CPack/WiX/cmWIXFeaturesSourceWriter.cxx
new file mode 100644
index 0000000..1747b62
--- /dev/null
+++ b/Source/CPack/WiX/cmWIXFeaturesSourceWriter.cxx
@@ -0,0 +1,101 @@
+/*============================================================================
+ CMake - Cross Platform Makefile Generator
+ Copyright 2014 Kitware, Inc.
+
+ Distributed under the OSI-approved BSD License (the "License");
+ see accompanying file Copyright.txt for details.
+
+ This software is distributed WITHOUT ANY WARRANTY; without even the
+ implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
+ See the License for more information.
+============================================================================*/
+
+#include "cmWIXFeaturesSourceWriter.h"
+
+cmWIXFeaturesSourceWriter::cmWIXFeaturesSourceWriter(
+ cmCPackLog* logger, std::string const& filename)
+ : cmWIXSourceWriter(logger, filename)
+{
+}
+
+void cmWIXFeaturesSourceWriter::CreateCMakePackageRegistryEntry(
+ std::string const& package, std::string const& upgradeGuid)
+{
+ BeginElement("Component");
+ AddAttribute("Id", "CM_PACKAGE_REGISTRY");
+ AddAttribute("Directory", "TARGETDIR");
+ AddAttribute("Guid", "*");
+
+ std::string registryKey =
+ std::string("Software\\Kitware\\CMake\\Packages\\") + package;
+
+ BeginElement("RegistryValue");
+ AddAttribute("Root", "HKLM");
+ AddAttribute("Key", registryKey);
+ AddAttribute("Name", upgradeGuid);
+ AddAttribute("Type", "string");
+ AddAttribute("Value", "[INSTALL_ROOT]");
+ AddAttribute("KeyPath", "yes");
+ EndElement("RegistryValue");
+
+ EndElement("Component");
+}
+
+void cmWIXFeaturesSourceWriter::EmitFeatureForComponentGroup(
+ cmCPackComponentGroup const& group)
+{
+ BeginElement("Feature");
+ AddAttribute("Id", "CM_G_" + group.Name);
+
+ if (group.IsExpandedByDefault) {
+ AddAttribute("Display", "expand");
+ }
+
+ AddAttributeUnlessEmpty("Title", group.DisplayName);
+ AddAttributeUnlessEmpty("Description", group.Description);
+
+ for (std::vector<cmCPackComponentGroup*>::const_iterator i =
+ group.Subgroups.begin();
+ i != group.Subgroups.end(); ++i) {
+ EmitFeatureForComponentGroup(**i);
+ }
+
+ for (std::vector<cmCPackComponent*>::const_iterator i =
+ group.Components.begin();
+ i != group.Components.end(); ++i) {
+ EmitFeatureForComponent(**i);
+ }
+
+ EndElement("Feature");
+}
+
+void cmWIXFeaturesSourceWriter::EmitFeatureForComponent(
+ cmCPackComponent const& component)
+{
+ BeginElement("Feature");
+ AddAttribute("Id", "CM_C_" + component.Name);
+
+ AddAttributeUnlessEmpty("Title", component.DisplayName);
+ AddAttributeUnlessEmpty("Description", component.Description);
+
+ if (component.IsRequired) {
+ AddAttribute("Absent", "disallow");
+ }
+
+ if (component.IsHidden) {
+ AddAttribute("Display", "hidden");
+ }
+
+ if (component.IsDisabledByDefault) {
+ AddAttribute("Level", "2");
+ }
+
+ EndElement("Feature");
+}
+
+void cmWIXFeaturesSourceWriter::EmitComponentRef(std::string const& id)
+{
+ BeginElement("ComponentRef");
+ AddAttribute("Id", id);
+ EndElement("ComponentRef");
+}
diff --git a/Source/CPack/WiX/cmWIXFeaturesSourceWriter.h b/Source/CPack/WiX/cmWIXFeaturesSourceWriter.h
new file mode 100644
index 0000000..ee9c17a
--- /dev/null
+++ b/Source/CPack/WiX/cmWIXFeaturesSourceWriter.h
@@ -0,0 +1,38 @@
+/*============================================================================
+ CMake - Cross Platform Makefile Generator
+ Copyright 2014 Kitware, Inc.
+
+ Distributed under the OSI-approved BSD License (the "License");
+ see accompanying file Copyright.txt for details.
+
+ This software is distributed WITHOUT ANY WARRANTY; without even the
+ implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
+ See the License for more information.
+============================================================================*/
+
+#ifndef cmWIXFeaturesSourceWriter_h
+#define cmWIXFeaturesSourceWriter_h
+
+#include "cmWIXSourceWriter.h"
+
+#include <CPack/cmCPackGenerator.h>
+
+/** \class cmWIXFeaturesSourceWriter
+ * \brief Helper class to generate features.wxs
+ */
+class cmWIXFeaturesSourceWriter : public cmWIXSourceWriter
+{
+public:
+ cmWIXFeaturesSourceWriter(cmCPackLog* logger, std::string const& filename);
+
+ void CreateCMakePackageRegistryEntry(std::string const& package,
+ std::string const& upgradeGuid);
+
+ void EmitFeatureForComponentGroup(const cmCPackComponentGroup& group);
+
+ void EmitFeatureForComponent(const cmCPackComponent& component);
+
+ void EmitComponentRef(std::string const& id);
+};
+
+#endif
diff --git a/Source/CPack/WiX/cmWIXFilesSourceWriter.cxx b/Source/CPack/WiX/cmWIXFilesSourceWriter.cxx
new file mode 100644
index 0000000..9a143cc
--- /dev/null
+++ b/Source/CPack/WiX/cmWIXFilesSourceWriter.cxx
@@ -0,0 +1,170 @@
+/*============================================================================
+ CMake - Cross Platform Makefile Generator
+ Copyright 2014-2015 Kitware, Inc.
+
+ Distributed under the OSI-approved BSD License (the "License");
+ see accompanying file Copyright.txt for details.
+
+ This software is distributed WITHOUT ANY WARRANTY; without even the
+ implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
+ See the License for more information.
+============================================================================*/
+
+#include "cmWIXFilesSourceWriter.h"
+
+#include "cmWIXAccessControlList.h"
+
+#include <cmInstalledFile.h>
+
+#include <sys/types.h>
+// include sys/stat.h after sys/types.h
+#include <sys/stat.h>
+
+cmWIXFilesSourceWriter::cmWIXFilesSourceWriter(cmCPackLog* logger,
+ std::string const& filename)
+ : cmWIXSourceWriter(logger, filename)
+{
+}
+
+void cmWIXFilesSourceWriter::EmitShortcut(std::string const& id,
+ cmWIXShortcut const& shortcut,
+ std::string const& shortcutPrefix,
+ size_t shortcutIndex)
+{
+ std::ostringstream shortcutId;
+ shortcutId << shortcutPrefix << id;
+
+ if (shortcutIndex > 0) {
+ shortcutId << "_" << shortcutIndex;
+ }
+
+ std::string fileId = std::string("CM_F") + id;
+
+ BeginElement("Shortcut");
+ AddAttribute("Id", shortcutId.str());
+ AddAttribute("Name", shortcut.label);
+ std::string target = "[#" + fileId + "]";
+ AddAttribute("Target", target);
+ AddAttribute("WorkingDirectory", shortcut.workingDirectoryId);
+ EndElement("Shortcut");
+}
+
+void cmWIXFilesSourceWriter::EmitRemoveFolder(std::string const& id)
+{
+ BeginElement("RemoveFolder");
+ AddAttribute("Id", id);
+ AddAttribute("On", "uninstall");
+ EndElement("RemoveFolder");
+}
+
+void cmWIXFilesSourceWriter::EmitInstallRegistryValue(
+ std::string const& registryKey, std::string const& cpackComponentName,
+ std::string const& suffix)
+{
+ std::string valueName;
+ if (!cpackComponentName.empty()) {
+ valueName = cpackComponentName + "_";
+ }
+
+ valueName += "installed";
+ valueName += suffix;
+
+ BeginElement("RegistryValue");
+ AddAttribute("Root", "HKCU");
+ AddAttribute("Key", registryKey);
+ AddAttribute("Name", valueName);
+ AddAttribute("Type", "integer");
+ AddAttribute("Value", "1");
+ AddAttribute("KeyPath", "yes");
+ EndElement("RegistryValue");
+}
+
+void cmWIXFilesSourceWriter::EmitUninstallShortcut(
+ std::string const& packageName)
+{
+ BeginElement("Shortcut");
+ AddAttribute("Id", "UNINSTALL");
+ AddAttribute("Name", "Uninstall " + packageName);
+ AddAttribute("Description", "Uninstalls " + packageName);
+ AddAttribute("Target", "[SystemFolder]msiexec.exe");
+ AddAttribute("Arguments", "/x [ProductCode]");
+ EndElement("Shortcut");
+}
+
+std::string cmWIXFilesSourceWriter::EmitComponentCreateFolder(
+ std::string const& directoryId, std::string const& guid,
+ cmInstalledFile const* installedFile)
+{
+ std::string componentId = std::string("CM_C_EMPTY_") + directoryId;
+
+ BeginElement("DirectoryRef");
+ AddAttribute("Id", directoryId);
+
+ BeginElement("Component");
+ AddAttribute("Id", componentId);
+ AddAttribute("Guid", guid);
+
+ BeginElement("CreateFolder");
+
+ if (installedFile) {
+ cmWIXAccessControlList acl(Logger, *installedFile, *this);
+ acl.Apply();
+ }
+
+ EndElement("CreateFolder");
+ EndElement("Component");
+ EndElement("DirectoryRef");
+
+ return componentId;
+}
+
+std::string cmWIXFilesSourceWriter::EmitComponentFile(
+ std::string const& directoryId, std::string const& id,
+ std::string const& filePath, cmWIXPatch& patch,
+ cmInstalledFile const* installedFile)
+{
+ std::string componentId = std::string("CM_C") + id;
+ std::string fileId = std::string("CM_F") + id;
+
+ BeginElement("DirectoryRef");
+ AddAttribute("Id", directoryId);
+
+ BeginElement("Component");
+ AddAttribute("Id", componentId);
+ AddAttribute("Guid", "*");
+
+ if (installedFile) {
+ if (installedFile->GetPropertyAsBool("CPACK_NEVER_OVERWRITE")) {
+ AddAttribute("NeverOverwrite", "yes");
+ }
+ if (installedFile->GetPropertyAsBool("CPACK_PERMANENT")) {
+ AddAttribute("Permanent", "yes");
+ }
+ }
+
+ BeginElement("File");
+ AddAttribute("Id", fileId);
+ AddAttribute("Source", filePath);
+ AddAttribute("KeyPath", "yes");
+
+ mode_t fileMode = 0;
+ cmSystemTools::GetPermissions(filePath.c_str(), fileMode);
+
+ if (!(fileMode & S_IWRITE)) {
+ AddAttribute("ReadOnly", "yes");
+ }
+
+ if (installedFile) {
+ cmWIXAccessControlList acl(Logger, *installedFile, *this);
+ acl.Apply();
+ }
+
+ patch.ApplyFragment(fileId, *this);
+ EndElement("File");
+
+ patch.ApplyFragment(componentId, *this);
+ EndElement("Component");
+ EndElement("DirectoryRef");
+
+ return componentId;
+}
diff --git a/Source/CPack/WiX/cmWIXFilesSourceWriter.h b/Source/CPack/WiX/cmWIXFilesSourceWriter.h
new file mode 100644
index 0000000..c577e5b
--- /dev/null
+++ b/Source/CPack/WiX/cmWIXFilesSourceWriter.h
@@ -0,0 +1,52 @@
+/*============================================================================
+ CMake - Cross Platform Makefile Generator
+ Copyright 2014-2015 Kitware, Inc.
+
+ Distributed under the OSI-approved BSD License (the "License");
+ see accompanying file Copyright.txt for details.
+
+ This software is distributed WITHOUT ANY WARRANTY; without even the
+ implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
+ See the License for more information.
+============================================================================*/
+
+#ifndef cmWIXFilesSourceWriter_h
+#define cmWIXFilesSourceWriter_h
+
+#include "cmWIXSourceWriter.h"
+
+#include "cmWIXPatch.h"
+#include "cmWIXShortcut.h"
+
+#include <CPack/cmCPackGenerator.h>
+
+/** \class cmWIXFilesSourceWriter
+ * \brief Helper class to generate files.wxs
+ */
+class cmWIXFilesSourceWriter : public cmWIXSourceWriter
+{
+public:
+ cmWIXFilesSourceWriter(cmCPackLog* logger, std::string const& filename);
+
+ void EmitShortcut(std::string const& id, cmWIXShortcut const& shortcut,
+ std::string const& shortcutPrefix, size_t shortcutIndex);
+
+ void EmitRemoveFolder(std::string const& id);
+
+ void EmitInstallRegistryValue(std::string const& registryKey,
+ std::string const& cpackComponentName,
+ std::string const& suffix);
+
+ void EmitUninstallShortcut(std::string const& packageName);
+
+ std::string EmitComponentCreateFolder(std::string const& directoryId,
+ std::string const& guid,
+ cmInstalledFile const* installedFile);
+
+ std::string EmitComponentFile(std::string const& directoryId,
+ std::string const& id,
+ std::string const& filePath, cmWIXPatch& patch,
+ cmInstalledFile const* installedFile);
+};
+
+#endif
diff --git a/Source/CPack/WiX/cmWIXPatch.cxx b/Source/CPack/WiX/cmWIXPatch.cxx
new file mode 100644
index 0000000..c9d010e
--- /dev/null
+++ b/Source/CPack/WiX/cmWIXPatch.cxx
@@ -0,0 +1,105 @@
+/*============================================================================
+ CMake - Cross Platform Makefile Generator
+ Copyright 2014 Kitware, Inc., Insight Software Consortium
+
+ Distributed under the OSI-approved BSD License (the "License");
+ see accompanying file Copyright.txt for details.
+
+ This software is distributed WITHOUT ANY WARRANTY; without even the
+ implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
+ See the License for more information.
+============================================================================*/
+
+#include "cmWIXPatch.h"
+
+#include <CPack/cmCPackGenerator.h>
+
+cmWIXPatch::cmWIXPatch(cmCPackLog* logger)
+ : Logger(logger)
+{
+}
+
+bool cmWIXPatch::LoadFragments(std::string const& patchFilePath)
+{
+ cmWIXPatchParser parser(Fragments, Logger);
+ if (!parser.ParseFile(patchFilePath.c_str())) {
+ cmCPackLogger(cmCPackLog::LOG_ERROR, "Failed parsing XML patch file: '"
+ << patchFilePath << "'" << std::endl);
+ return false;
+ }
+
+ return true;
+}
+
+void cmWIXPatch::ApplyFragment(std::string const& id,
+ cmWIXSourceWriter& writer)
+{
+ cmWIXPatchParser::fragment_map_t::iterator i = Fragments.find(id);
+ if (i == Fragments.end())
+ return;
+
+ const cmWIXPatchElement& fragment = i->second;
+
+ this->ApplyElementChildren(fragment, writer);
+
+ Fragments.erase(i);
+}
+
+void cmWIXPatch::ApplyElementChildren(const cmWIXPatchElement& element,
+ cmWIXSourceWriter& writer)
+{
+ for (cmWIXPatchElement::child_list_t::const_iterator j =
+ element.children.begin();
+ j != element.children.end(); ++j) {
+ cmWIXPatchNode* node = *j;
+
+ switch (node->type()) {
+ case cmWIXPatchNode::ELEMENT:
+ ApplyElement(dynamic_cast<const cmWIXPatchElement&>(*node), writer);
+ break;
+ case cmWIXPatchNode::TEXT:
+ writer.AddTextNode(dynamic_cast<const cmWIXPatchText&>(*node).text);
+ break;
+ }
+ }
+}
+
+void cmWIXPatch::ApplyElement(const cmWIXPatchElement& element,
+ cmWIXSourceWriter& writer)
+{
+ writer.BeginElement(element.name);
+
+ for (cmWIXPatchElement::attributes_t::const_iterator i =
+ element.attributes.begin();
+ i != element.attributes.end(); ++i) {
+ writer.AddAttribute(i->first, i->second);
+ }
+
+ this->ApplyElementChildren(element, writer);
+
+ writer.EndElement(element.name);
+}
+
+bool cmWIXPatch::CheckForUnappliedFragments()
+{
+ std::string fragmentList;
+ for (cmWIXPatchParser::fragment_map_t::const_iterator i = Fragments.begin();
+ i != Fragments.end(); ++i) {
+ if (!fragmentList.empty()) {
+ fragmentList += ", ";
+ }
+
+ fragmentList += "'";
+ fragmentList += i->first;
+ fragmentList += "'";
+ }
+
+ if (!fragmentList.empty()) {
+ cmCPackLogger(cmCPackLog::LOG_ERROR,
+ "Some XML patch fragments did not have matching IDs: "
+ << fragmentList << std::endl);
+ return false;
+ }
+
+ return true;
+}
diff --git a/Source/CPack/WiX/cmWIXPatch.h b/Source/CPack/WiX/cmWIXPatch.h
new file mode 100644
index 0000000..57b74cd
--- /dev/null
+++ b/Source/CPack/WiX/cmWIXPatch.h
@@ -0,0 +1,47 @@
+/*============================================================================
+ CMake - Cross Platform Makefile Generator
+ Copyright 2014 Kitware, Inc.
+
+ Distributed under the OSI-approved BSD License (the "License");
+ see accompanying file Copyright.txt for details.
+
+ This software is distributed WITHOUT ANY WARRANTY; without even the
+ implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
+ See the License for more information.
+============================================================================*/
+
+#ifndef cmWIXPatch_h
+#define cmWIXPatch_h
+
+#include "cmWIXPatchParser.h"
+#include "cmWIXSourceWriter.h"
+
+#include <string>
+
+/** \class cmWIXPatch
+ * \brief Class that maintains and applies patch fragments
+ */
+class cmWIXPatch
+{
+public:
+ cmWIXPatch(cmCPackLog* logger);
+
+ bool LoadFragments(std::string const& patchFilePath);
+
+ void ApplyFragment(std::string const& id, cmWIXSourceWriter& writer);
+
+ bool CheckForUnappliedFragments();
+
+private:
+ void ApplyElementChildren(const cmWIXPatchElement& element,
+ cmWIXSourceWriter& writer);
+
+ void ApplyElement(const cmWIXPatchElement& element,
+ cmWIXSourceWriter& writer);
+
+ cmCPackLog* Logger;
+
+ cmWIXPatchParser::fragment_map_t Fragments;
+};
+
+#endif
diff --git a/Source/CPack/WiX/cmWIXPatchParser.cxx b/Source/CPack/WiX/cmWIXPatchParser.cxx
new file mode 100644
index 0000000..449a70b
--- /dev/null
+++ b/Source/CPack/WiX/cmWIXPatchParser.cxx
@@ -0,0 +1,156 @@
+/*============================================================================
+ CMake - Cross Platform Makefile Generator
+ Copyright 2013 Kitware, Inc.
+
+ Distributed under the OSI-approved BSD License (the "License");
+ see accompanying file Copyright.txt for details.
+
+ This software is distributed WITHOUT ANY WARRANTY; without even the
+ implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
+ See the License for more information.
+============================================================================*/
+
+#include "cmWIXPatchParser.h"
+
+#include <CPack/cmCPackGenerator.h>
+
+#include <cm_expat.h>
+
+cmWIXPatchNode::Type cmWIXPatchText::type()
+{
+ return cmWIXPatchNode::TEXT;
+}
+
+cmWIXPatchNode::Type cmWIXPatchElement::type()
+{
+ return cmWIXPatchNode::ELEMENT;
+}
+
+cmWIXPatchNode::~cmWIXPatchNode()
+{
+}
+
+cmWIXPatchElement::~cmWIXPatchElement()
+{
+ for (child_list_t::iterator i = children.begin(); i != children.end(); ++i) {
+ delete *i;
+ }
+}
+
+cmWIXPatchParser::cmWIXPatchParser(fragment_map_t& fragments,
+ cmCPackLog* logger)
+ : Logger(logger)
+ , State(BEGIN_DOCUMENT)
+ , Valid(true)
+ , Fragments(fragments)
+{
+}
+
+void cmWIXPatchParser::StartElement(const std::string& name, const char** atts)
+{
+ if (State == BEGIN_DOCUMENT) {
+ if (name == "CPackWiXPatch") {
+ State = BEGIN_FRAGMENTS;
+ } else {
+ ReportValidationError("Expected root element 'CPackWiXPatch'");
+ }
+ } else if (State == BEGIN_FRAGMENTS) {
+ if (name == "CPackWiXFragment") {
+ State = INSIDE_FRAGMENT;
+ StartFragment(atts);
+ } else {
+ ReportValidationError("Expected 'CPackWixFragment' element");
+ }
+ } else if (State == INSIDE_FRAGMENT) {
+ cmWIXPatchElement& parent = *ElementStack.back();
+
+ cmWIXPatchElement* element = new cmWIXPatchElement;
+ parent.children.push_back(element);
+
+ element->name = name;
+
+ for (size_t i = 0; atts[i]; i += 2) {
+ std::string key = atts[i];
+ std::string value = atts[i + 1];
+
+ element->attributes[key] = value;
+ }
+
+ ElementStack.push_back(element);
+ }
+}
+
+void cmWIXPatchParser::StartFragment(const char** attributes)
+{
+ for (size_t i = 0; attributes[i]; i += 2) {
+ std::string key = attributes[i];
+ std::string value = attributes[i + 1];
+
+ if (key == "Id") {
+ if (Fragments.find(value) != Fragments.end()) {
+ std::ostringstream tmp;
+ tmp << "Invalid reuse of 'CPackWixFragment' 'Id': " << value;
+ ReportValidationError(tmp.str());
+ }
+
+ ElementStack.push_back(&Fragments[value]);
+ } else {
+ ReportValidationError(
+ "The only allowed 'CPackWixFragment' attribute is 'Id'");
+ }
+ }
+}
+
+void cmWIXPatchParser::EndElement(const std::string& name)
+{
+ if (State == INSIDE_FRAGMENT) {
+ if (name == "CPackWiXFragment") {
+ State = BEGIN_FRAGMENTS;
+ ElementStack.clear();
+ } else {
+ ElementStack.pop_back();
+ }
+ }
+}
+
+void cmWIXPatchParser::CharacterDataHandler(const char* data, int length)
+{
+ const char* whitespace = "\x20\x09\x0d\x0a";
+
+ if (State == INSIDE_FRAGMENT) {
+ cmWIXPatchElement& parent = *ElementStack.back();
+
+ std::string text(data, length);
+
+ std::string::size_type first = text.find_first_not_of(whitespace);
+ std::string::size_type last = text.find_last_not_of(whitespace);
+
+ if (first != std::string::npos && last != std::string::npos) {
+ cmWIXPatchText* text_node = new cmWIXPatchText;
+ text_node->text = text.substr(first, last - first + 1);
+
+ parent.children.push_back(text_node);
+ }
+ }
+}
+
+void cmWIXPatchParser::ReportError(int line, int column, const char* msg)
+{
+ cmCPackLogger(cmCPackLog::LOG_ERROR,
+ "Error while processing XML patch file at "
+ << line << ":" << column << ": " << msg << std::endl);
+ Valid = false;
+}
+
+void cmWIXPatchParser::ReportValidationError(std::string const& message)
+{
+ ReportError(
+ XML_GetCurrentLineNumber(static_cast<XML_Parser>(this->Parser)),
+ XML_GetCurrentColumnNumber(static_cast<XML_Parser>(this->Parser)),
+ message.c_str());
+}
+
+bool cmWIXPatchParser::IsValid() const
+{
+ return Valid;
+}
diff --git a/Source/CPack/WiX/cmWIXPatchParser.h b/Source/CPack/WiX/cmWIXPatchParser.h
new file mode 100644
index 0000000..f9b85bd
--- /dev/null
+++ b/Source/CPack/WiX/cmWIXPatchParser.h
@@ -0,0 +1,100 @@
+/*============================================================================
+ CMake - Cross Platform Makefile Generator
+ Copyright 2013 Kitware, Inc.
+
+ Distributed under the OSI-approved BSD License (the "License");
+ see accompanying file Copyright.txt for details.
+
+ This software is distributed WITHOUT ANY WARRANTY; without even the
+ implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
+ See the License for more information.
+============================================================================*/
+
+#ifndef cmCPackWIXPatchParser_h
+#define cmCPackWIXPatchParser_h
+
+#include <CPack/cmCPackLog.h>
+
+#include <cmXMLParser.h>
+
+#include <list>
+#include <map>
+
+struct cmWIXPatchNode
+{
+ enum Type
+ {
+ TEXT,
+ ELEMENT
+ };
+
+ virtual ~cmWIXPatchNode();
+
+ virtual Type type() = 0;
+};
+
+struct cmWIXPatchText : public cmWIXPatchNode
+{
+ virtual Type type();
+
+ std::string text;
+};
+
+struct cmWIXPatchElement : cmWIXPatchNode
+{
+ virtual Type type();
+
+ ~cmWIXPatchElement();
+
+ typedef std::list<cmWIXPatchNode*> child_list_t;
+ typedef std::map<std::string, std::string> attributes_t;
+
+ std::string name;
+ child_list_t children;
+ attributes_t attributes;
+};
+
+/** \class cmWIXPatchParser
+ * \brief Helper class that parses XML patch files (CPACK_WIX_PATCH_FILE)
+ */
+class cmWIXPatchParser : public cmXMLParser
+{
+public:
+ typedef std::map<std::string, cmWIXPatchElement> fragment_map_t;
+
+ cmWIXPatchParser(fragment_map_t& Fragments, cmCPackLog* logger);
+
+private:
+ virtual void StartElement(const std::string& name, const char** atts);
+
+ void StartFragment(const char** attributes);
+
+ virtual void EndElement(const std::string& name);
+
+ virtual void CharacterDataHandler(const char* data, int length);
+
+ virtual void ReportError(int line, int column, const char* msg);
+
+ void ReportValidationError(std::string const& message);
+
+ bool IsValid() const;
+
+ cmCPackLog* Logger;
+
+ enum ParserState
+ {
+ BEGIN_DOCUMENT,
+ BEGIN_FRAGMENTS,
+ INSIDE_FRAGMENT
+ };
+
+ ParserState State;
+
+ bool Valid;
+
+ fragment_map_t& Fragments;
+
+ std::list<cmWIXPatchElement*> ElementStack;
+};
+
+#endif
diff --git a/Source/CPack/WiX/cmWIXRichTextFormatWriter.cxx b/Source/CPack/WiX/cmWIXRichTextFormatWriter.cxx
new file mode 100644
index 0000000..f3dbcb9
--- /dev/null
+++ b/Source/CPack/WiX/cmWIXRichTextFormatWriter.cxx
@@ -0,0 +1,196 @@
+/*============================================================================
+ CMake - Cross Platform Makefile Generator
+ Copyright 2000-2012 Kitware, Inc.
+
+ Distributed under the OSI-approved BSD License (the "License");
+ see accompanying file Copyright.txt for details.
+
+ This software is distributed WITHOUT ANY WARRANTY; without even the
+ implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
+ See the License for more information.
+============================================================================*/
+
+#include "cmWIXRichTextFormatWriter.h"
+
+#include <cmVersion.h>
+
+cmWIXRichTextFormatWriter::cmWIXRichTextFormatWriter(
+ std::string const& filename)
+ : File(filename.c_str(), std::ios::binary)
+{
+ StartGroup();
+ WriteHeader();
+ WriteDocumentPrefix();
+}
+
+cmWIXRichTextFormatWriter::~cmWIXRichTextFormatWriter()
+{
+ EndGroup();
+
+ /* I haven't seen this in the RTF spec but
+ * wordpad terminates its RTF like this */
+ File << "\r\n";
+ File.put(0);
+}
+
+void cmWIXRichTextFormatWriter::AddText(std::string const& text)
+{
+ typedef unsigned char rtf_byte_t;
+
+ for (size_t i = 0; i < text.size(); ++i) {
+ rtf_byte_t c = rtf_byte_t(text[i]);
+
+ switch (c) {
+ case '\\':
+ File << "\\\\";
+ break;
+ case '{':
+ File << "\\{";
+ break;
+ case '}':
+ File << "\\}";
+ break;
+ case '\n':
+ File << "\\par\r\n";
+ break;
+ case '\r':
+ continue;
+ default: {
+ if (c <= 0x7F) {
+ File << c;
+ } else {
+ if (c <= 0xC0) {
+ EmitInvalidCodepoint(c);
+ } else if (c < 0xE0 && i + 1 < text.size()) {
+ EmitUnicodeCodepoint((text[i + 1] & 0x3F) | ((c & 0x1F) << 6));
+ i += 1;
+ } else if (c < 0xF0 && i + 2 < text.size()) {
+ EmitUnicodeCodepoint((text[i + 2] & 0x3F) |
+ ((text[i + 1] & 0x3F) << 6) |
+ ((c & 0xF) << 12));
+ i += 2;
+ } else if (c < 0xF8 && i + 3 < text.size()) {
+ EmitUnicodeCodepoint(
+ (text[i + 3] & 0x3F) | ((text[i + 2] & 0x3F) << 6) |
+ ((text[i + 1] & 0x3F) << 12) | ((c & 0x7) << 18));
+ i += 3;
+ } else {
+ EmitInvalidCodepoint(c);
+ }
+ }
+ } break;
+ }
+ }
+}
+
+void cmWIXRichTextFormatWriter::WriteHeader()
+{
+ ControlWord("rtf1");
+ ControlWord("ansi");
+ ControlWord("ansicpg1252");
+ ControlWord("deff0");
+ ControlWord("deflang1031");
+
+ WriteFontTable();
+ WriteColorTable();
+ WriteGenerator();
+}
+
+void cmWIXRichTextFormatWriter::WriteFontTable()
+{
+ StartGroup();
+ ControlWord("fonttbl");
+
+ StartGroup();
+ ControlWord("f0");
+ ControlWord("fswiss");
+ ControlWord("fcharset0 Arial;");
+ EndGroup();
+
+ EndGroup();
+}
+
+void cmWIXRichTextFormatWriter::WriteColorTable()
+{
+ StartGroup();
+ ControlWord("colortbl ;");
+ ControlWord("red255");
+ ControlWord("green0");
+ ControlWord("blue0;");
+ ControlWord("red0");
+ ControlWord("green255");
+ ControlWord("blue0;");
+ ControlWord("red0");
+ ControlWord("green0");
+ ControlWord("blue255;");
+ EndGroup();
+}
+
+void cmWIXRichTextFormatWriter::WriteGenerator()
+{
+ StartGroup();
+ NewControlWord("generator");
+ File << " CPack WiX Generator (" << cmVersion::GetCMakeVersion() << ");";
+ EndGroup();
+}
+
+void cmWIXRichTextFormatWriter::WriteDocumentPrefix()
+{
+ ControlWord("viewkind4");
+ ControlWord("uc1");
+ ControlWord("pard");
+ ControlWord("f0");
+ ControlWord("fs20");
+}
+
+void cmWIXRichTextFormatWriter::ControlWord(std::string const& keyword)
+{
+ File << "\\" << keyword;
+}
+
+void cmWIXRichTextFormatWriter::NewControlWord(std::string const& keyword)
+{
+ File << "\\*\\" << keyword;
+}
+
+void cmWIXRichTextFormatWriter::StartGroup()
+{
+ File.put('{');
+}
+
+void cmWIXRichTextFormatWriter::EndGroup()
+{
+ File.put('}');
+}
+
+void cmWIXRichTextFormatWriter::EmitUnicodeCodepoint(int c)
+{
+ // Do not emit byte order mark (BOM)
+ if (c == 0xFEFF) {
+ return;
+ } else if (c <= 0xFFFF) {
+ EmitUnicodeSurrogate(c);
+ } else {
+ c -= 0x10000;
+ EmitUnicodeSurrogate(((c >> 10) & 0x3FF) + 0xD800);
+ EmitUnicodeSurrogate((c & 0x3FF) + 0xDC00);
+ }
+}
+
+void cmWIXRichTextFormatWriter::EmitUnicodeSurrogate(int c)
+{
+ ControlWord("u");
+ if (c <= 32767) {
+ File << c;
+ } else {
+ File << (c - 65536);
+ }
+ File << "?";
+}
+
+void cmWIXRichTextFormatWriter::EmitInvalidCodepoint(int c)
+{
+ ControlWord("cf1 ");
+ File << "[INVALID-BYTE-" << int(c) << "]";
+ ControlWord("cf0 ");
+}
diff --git a/Source/CPack/WiX/cmWIXRichTextFormatWriter.h b/Source/CPack/WiX/cmWIXRichTextFormatWriter.h
new file mode 100644
index 0000000..acf1fa6
--- /dev/null
+++ b/Source/CPack/WiX/cmWIXRichTextFormatWriter.h
@@ -0,0 +1,54 @@
+/*============================================================================
+ CMake - Cross Platform Makefile Generator
+ Copyright 2000-2012 Kitware, Inc.
+
+ Distributed under the OSI-approved BSD License (the "License");
+ see accompanying file Copyright.txt for details.
+
+ This software is distributed WITHOUT ANY WARRANTY; without even the
+ implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
+ See the License for more information.
+============================================================================*/
+
+#ifndef cmWIXRichTextFormatWriter_h
+#define cmWIXRichTextFormatWriter_h
+
+#include "cmStandardIncludes.h"
+
+#include <cmsys/FStream.hxx>
+
+/** \class cmWIXRichtTextFormatWriter
+ * \brief Helper class to generate Rich Text Format (RTF) documents
+ * from plain text (e.g. for license and welcome text)
+ */
+class cmWIXRichTextFormatWriter
+{
+public:
+ cmWIXRichTextFormatWriter(std::string const& filename);
+ ~cmWIXRichTextFormatWriter();
+
+ void AddText(std::string const& text);
+
+private:
+ void WriteHeader();
+ void WriteFontTable();
+ void WriteColorTable();
+ void WriteGenerator();
+
+ void WriteDocumentPrefix();
+
+ void ControlWord(std::string const& keyword);
+ void NewControlWord(std::string const& keyword);
+
+ void StartGroup();
+ void EndGroup();
+
+ void EmitUnicodeCodepoint(int c);
+ void EmitUnicodeSurrogate(int c);
+
+ void EmitInvalidCodepoint(int c);
+
+ cmsys::ofstream File;
+};
+
+#endif
diff --git a/Source/CPack/WiX/cmWIXShortcut.cxx b/Source/CPack/WiX/cmWIXShortcut.cxx
new file mode 100644
index 0000000..2685a23
--- /dev/null
+++ b/Source/CPack/WiX/cmWIXShortcut.cxx
@@ -0,0 +1,115 @@
+/*============================================================================
+ CMake - Cross Platform Makefile Generator
+ Copyright 2015 Kitware, Inc.
+
+ Distributed under the OSI-approved BSD License (the "License");
+ see accompanying file Copyright.txt for details.
+
+ This software is distributed WITHOUT ANY WARRANTY; without even the
+ implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
+ See the License for more information.
+============================================================================*/
+
+#include "cmWIXShortcut.h"
+
+#include "cmWIXFilesSourceWriter.h"
+
+void cmWIXShortcuts::insert(Type type, std::string const& id,
+ cmWIXShortcut const& shortcut)
+{
+ this->Shortcuts[type][id].push_back(shortcut);
+}
+
+bool cmWIXShortcuts::empty(Type type) const
+{
+ return this->Shortcuts.find(type) == this->Shortcuts.end();
+}
+
+bool cmWIXShortcuts::EmitShortcuts(
+ Type type, std::string const& registryKey,
+ std::string const& cpackComponentName,
+ cmWIXFilesSourceWriter& fileDefinitions) const
+{
+ shortcut_type_map_t::const_iterator i = this->Shortcuts.find(type);
+
+ if (i == this->Shortcuts.end()) {
+ return false;
+ }
+
+ shortcut_id_map_t const& id_map = i->second;
+
+ std::string shortcutPrefix;
+ std::string registrySuffix;
+
+ switch (type) {
+ case START_MENU:
+ shortcutPrefix = "CM_S";
+ break;
+ case DESKTOP:
+ shortcutPrefix = "CM_DS";
+ registrySuffix = "_desktop";
+ break;
+ case STARTUP:
+ shortcutPrefix = "CM_SS";
+ registrySuffix = "_startup";
+ break;
+ default:
+ return false;
+ }
+
+ for (shortcut_id_map_t::const_iterator j = id_map.begin(); j != id_map.end();
+ ++j) {
+ std::string const& id = j->first;
+ shortcut_list_t const& shortcutList = j->second;
+
+ for (size_t shortcutListIndex = 0; shortcutListIndex < shortcutList.size();
+ ++shortcutListIndex) {
+ cmWIXShortcut const& shortcut = shortcutList[shortcutListIndex];
+ fileDefinitions.EmitShortcut(id, shortcut, shortcutPrefix,
+ shortcutListIndex);
+ }
+ }
+
+ fileDefinitions.EmitInstallRegistryValue(registryKey, cpackComponentName,
+ registrySuffix);
+
+ return true;
+}
+
+void cmWIXShortcuts::AddShortcutTypes(std::set<Type>& types)
+{
+ for (shortcut_type_map_t::const_iterator i = this->Shortcuts.begin();
+ i != this->Shortcuts.end(); ++i) {
+ types.insert(i->first);
+ }
+}
+
+void cmWIXShortcuts::CreateFromProperties(std::string const& id,
+ std::string const& directoryId,
+ cmInstalledFile const& installedFile)
+{
+ CreateFromProperty("CPACK_START_MENU_SHORTCUTS", START_MENU, id, directoryId,
+ installedFile);
+
+ CreateFromProperty("CPACK_DESKTOP_SHORTCUTS", DESKTOP, id, directoryId,
+ installedFile);
+
+ CreateFromProperty("CPACK_STARTUP_SHORTCUTS", STARTUP, id, directoryId,
+ installedFile);
+}
+
+void cmWIXShortcuts::CreateFromProperty(std::string const& propertyName,
+ Type type, std::string const& id,
+ std::string const& directoryId,
+ cmInstalledFile const& installedFile)
+{
+ std::vector<std::string> list;
+ installedFile.GetPropertyAsList(propertyName, list);
+
+ for (size_t i = 0; i < list.size(); ++i) {
+ cmWIXShortcut shortcut;
+ shortcut.label = list[i];
+ shortcut.workingDirectoryId = directoryId;
+ insert(type, id, shortcut);
+ }
+}
diff --git a/Source/CPack/WiX/cmWIXShortcut.h b/Source/CPack/WiX/cmWIXShortcut.h
new file mode 100644
index 0000000..593ba34
--- /dev/null
+++ b/Source/CPack/WiX/cmWIXShortcut.h
@@ -0,0 +1,70 @@
+/*============================================================================
+ CMake - Cross Platform Makefile Generator
+ Copyright 2014-2015 Kitware, Inc.
+
+ Distributed under the OSI-approved BSD License (the "License");
+ see accompanying file Copyright.txt for details.
+
+ This software is distributed WITHOUT ANY WARRANTY; without even the
+ implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
+ See the License for more information.
+============================================================================*/
+
+#ifndef cmWIXShortcut_h
+#define cmWIXShortcut_h
+
+#include <cmInstalledFile.h>
+
+#include <map>
+#include <set>
+#include <string>
+#include <vector>
+
+class cmWIXFilesSourceWriter;
+
+struct cmWIXShortcut
+{
+ std::string label;
+ std::string workingDirectoryId;
+};
+
+class cmWIXShortcuts
+{
+public:
+ enum Type
+ {
+ START_MENU,
+ DESKTOP,
+ STARTUP
+ };
+
+ typedef std::vector<cmWIXShortcut> shortcut_list_t;
+ typedef std::map<std::string, shortcut_list_t> shortcut_id_map_t;
+
+ void insert(Type type, std::string const& id, cmWIXShortcut const& shortcut);
+
+ bool empty(Type type) const;
+
+ bool EmitShortcuts(Type type, std::string const& registryKey,
+ std::string const& cpackComponentName,
+ cmWIXFilesSourceWriter& fileDefinitions) const;
+
+ void AddShortcutTypes(std::set<Type>& types);
+
+ void CreateFromProperties(std::string const& id,
+ std::string const& directoryId,
+ cmInstalledFile const& installedFile);
+
+private:
+ typedef std::map<Type, shortcut_id_map_t> shortcut_type_map_t;
+
+ void CreateFromProperty(std::string const& propertyName, Type type,
+ std::string const& id,
+ std::string const& directoryId,
+ cmInstalledFile const& installedFile);
+
+ shortcut_type_map_t Shortcuts;
+ shortcut_id_map_t EmptyIdMap;
+};
+
+#endif
diff --git a/Source/CPack/WiX/cmWIXSourceWriter.cxx b/Source/CPack/WiX/cmWIXSourceWriter.cxx
new file mode 100644
index 0000000..2c0384e
--- /dev/null
+++ b/Source/CPack/WiX/cmWIXSourceWriter.cxx
@@ -0,0 +1,216 @@
+/*============================================================================
+ CMake - Cross Platform Makefile Generator
+ Copyright 2012 Kitware, Inc.
+
+ Distributed under the OSI-approved BSD License (the "License");
+ see accompanying file Copyright.txt for details.
+
+ This software is distributed WITHOUT ANY WARRANTY; without even the
+ implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
+ See the License for more information.
+============================================================================*/
+
+#include "cmWIXSourceWriter.h"
+
+#include <CPack/cmCPackGenerator.h>
+
+#include <windows.h>
+
+cmWIXSourceWriter::cmWIXSourceWriter(cmCPackLog* logger,
+ std::string const& filename,
+ bool isIncludeFile)
+ : Logger(logger)
+ , File(filename.c_str())
+ , State(DEFAULT)
+ , SourceFilename(filename)
+{
+ WriteXMLDeclaration();
+
+ if (isIncludeFile) {
+ BeginElement("Include");
+ } else {
+ BeginElement("Wix");
+ }
+
+ AddAttribute("xmlns", "http://schemas.microsoft.com/wix/2006/wi");
+}
+
+cmWIXSourceWriter::~cmWIXSourceWriter()
+{
+ if (Elements.size() > 1) {
+ cmCPackLogger(cmCPackLog::LOG_ERROR, Elements.size() - 1
+ << " WiX elements were still open when closing '"
+ << SourceFilename << "'" << std::endl);
+ return;
+ }
+
+ EndElement(Elements.back());
+}
+
+void cmWIXSourceWriter::BeginElement(std::string const& name)
+{
+ if (State == BEGIN) {
+ File << ">";
+ }
+
+ File << "\n";
+ Indent(Elements.size());
+ File << "<" << name;
+
+ Elements.push_back(name);
+ State = BEGIN;
+}
+
+void cmWIXSourceWriter::EndElement(std::string const& name)
+{
+ if (Elements.empty()) {
+ cmCPackLogger(cmCPackLog::LOG_ERROR,
+ "can not end WiX element with no open elements in '"
+ << SourceFilename << "'" << std::endl);
+ return;
+ }
+
+ if (Elements.back() != name) {
+ cmCPackLogger(cmCPackLog::LOG_ERROR, "WiX element <"
+ << Elements.back() << "> can not be closed by </" << name
+ << "> in '" << SourceFilename << "'" << std::endl);
+ return;
+ }
+
+ if (State == DEFAULT) {
+ File << "\n";
+ Indent(Elements.size() - 1);
+ File << "</" << Elements.back() << ">";
+ } else {
+ File << "/>";
+ }
+
+ Elements.pop_back();
+ State = DEFAULT;
+}
+
+void cmWIXSourceWriter::AddTextNode(std::string const& text)
+{
+ if (State == BEGIN) {
+ File << ">";
+ }
+
+ if (Elements.empty()) {
+ cmCPackLogger(cmCPackLog::LOG_ERROR,
+ "can not add text without open WiX element in '"
+ << SourceFilename << "'" << std::endl);
+ return;
+ }
+
+ File << this->EscapeAttributeValue(text);
+ State = DEFAULT;
+}
+
+void cmWIXSourceWriter::AddProcessingInstruction(std::string const& target,
+ std::string const& content)
+{
+ if (State == BEGIN) {
+ File << ">";
+ }
+
+ File << "\n";
+ Indent(Elements.size());
+ File << "<?" << target << " " << content << "?>";
+
+ State = DEFAULT;
+}
+
+void cmWIXSourceWriter::AddAttribute(std::string const& key,
+ std::string const& value)
+{
+ std::string utf8 = CMakeEncodingToUtf8(value);
+
+ File << " " << key << "=\"" << EscapeAttributeValue(utf8) << '"';
+}
+
+void cmWIXSourceWriter::AddAttributeUnlessEmpty(std::string const& key,
+ std::string const& value)
+{
+ if (!value.empty()) {
+ AddAttribute(key, value);
+ }
+}
+
+std::string cmWIXSourceWriter::CMakeEncodingToUtf8(std::string const& value)
+{
+#ifdef CMAKE_ENCODING_UTF8
+ return value;
+#else
+ if (value.empty()) {
+ return std::string();
+ }
+
+ int characterCount = MultiByteToWideChar(
+ CP_ACP, 0, value.c_str(), static_cast<int>(value.size()), 0, 0);
+
+ if (characterCount == 0) {
+ return std::string();
+ }
+
+ std::vector<wchar_t> utf16(characterCount);
+
+ MultiByteToWideChar(CP_ACP, 0, value.c_str(), static_cast<int>(value.size()),
+ &utf16[0], static_cast<int>(utf16.size()));
+
+ int utf8ByteCount = WideCharToMultiByte(
+ CP_UTF8, 0, &utf16[0], static_cast<int>(utf16.size()), 0, 0, 0, 0);
+
+ if (utf8ByteCount == 0) {
+ return std::string();
+ }
+
+ std::vector<char> utf8(utf8ByteCount);
+
+ WideCharToMultiByte(CP_UTF8, 0, &utf16[0], static_cast<int>(utf16.size()),
+ &utf8[0], static_cast<int>(utf8.size()), 0, 0);
+
+ return std::string(&utf8[0], utf8.size());
+#endif
+}
+
+void cmWIXSourceWriter::WriteXMLDeclaration()
+{
+ File << "<?xml version=\"1.0\" encoding=\"UTF-8\"?>" << std::endl;
+}
+
+void cmWIXSourceWriter::Indent(size_t count)
+{
+ for (size_t i = 0; i < count; ++i) {
+ File << " ";
+ }
+}
+
+std::string cmWIXSourceWriter::EscapeAttributeValue(std::string const& value)
+{
+ std::string result;
+ result.reserve(value.size());
+
+ char c = 0;
+ for (size_t i = 0; i < value.size(); ++i) {
+ c = value[i];
+ switch (c) {
+ case '<':
+ result += "&lt;";
+ break;
+ case '>':
+ result += "&gt;";
+ break;
+ case '&':
+ result += "&amp;";
+ break;
+ case '"':
+ result += "&quot;";
+ break;
+ default:
+ result += c;
+ break;
+ }
+ }
+
+ return result;
+}
diff --git a/Source/CPack/WiX/cmWIXSourceWriter.h b/Source/CPack/WiX/cmWIXSourceWriter.h
new file mode 100644
index 0000000..4efc026
--- /dev/null
+++ b/Source/CPack/WiX/cmWIXSourceWriter.h
@@ -0,0 +1,75 @@
+/*============================================================================
+ CMake - Cross Platform Makefile Generator
+ Copyright 2012 Kitware, Inc.
+
+ Distributed under the OSI-approved BSD License (the "License");
+ see accompanying file Copyright.txt for details.
+
+ This software is distributed WITHOUT ANY WARRANTY; without even the
+ implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
+ See the License for more information.
+============================================================================*/
+
+#ifndef cmWIXSourceWriter_h
+#define cmWIXSourceWriter_h
+
+#include <CPack/cmCPackLog.h>
+
+#include <cmsys/FStream.hxx>
+
+#include <string>
+#include <vector>
+
+/** \class cmWIXSourceWriter
+ * \brief Helper class to generate XML WiX source files
+ */
+class cmWIXSourceWriter
+{
+public:
+ cmWIXSourceWriter(cmCPackLog* logger, std::string const& filename,
+ bool isIncludeFile = false);
+
+ ~cmWIXSourceWriter();
+
+ void BeginElement(std::string const& name);
+
+ void EndElement(std::string const& name);
+
+ void AddTextNode(std::string const& text);
+
+ void AddProcessingInstruction(std::string const& target,
+ std::string const& content);
+
+ void AddAttribute(std::string const& key, std::string const& value);
+
+ void AddAttributeUnlessEmpty(std::string const& key,
+ std::string const& value);
+
+ static std::string CMakeEncodingToUtf8(std::string const& value);
+
+protected:
+ cmCPackLog* Logger;
+
+private:
+ enum State
+ {
+ DEFAULT,
+ BEGIN
+ };
+
+ void WriteXMLDeclaration();
+
+ void Indent(size_t count);
+
+ static std::string EscapeAttributeValue(std::string const& value);
+
+ cmsys::ofstream File;
+
+ State State;
+
+ std::vector<std::string> Elements;
+
+ std::string SourceFilename;
+};
+
+#endif
diff --git a/Source/CPack/bills-comments.txt b/Source/CPack/bills-comments.txt
new file mode 100644
index 0000000..c3b4ee8
--- /dev/null
+++ b/Source/CPack/bills-comments.txt
@@ -0,0 +1,68 @@
+cpack.cxx
+
+cmCPackGenerators -- creates cmCPackGenericGenerator's via NewGenerator
+ - a cmCPackGenericGenerator factory
+
+
+cmCPackGenericGenerator::Initialize
+ this->InitializeInternal
+ CPACK_INCLUDE_TOPLEVEL_DIRECTORY = 0 turns off
+
+
+// binary package run
+cmCPackGenericGenerator::ProcessGenerator // DoPackage
+ cmCPackGenericGenerator::PrepareNames -- sets a bunch of CPACK_vars
+ cmCPackGenericGenerator::InstallProject
+ run preinstall (make preinstall/fast)
+ call ReadListFile(cmake_install.cmake)
+ glob recurse in install directory to get list of files
+ this->CompressFiles with the list of files
+
+
+// source package run
+cmCPackGenericGenerator::ProcessGenerator // DoPackage
+ cmCPackGenericGenerator::PrepareNames -- sets a bunch of CPACK_vars
+ cmCPackGenericGenerator::InstallProject -->
+ if set CPACK_INSTALLED_DIRECTORIES
+ glob the files in that directory
+ copy those files to the tmp install directory _CPack something
+ glob recurse in install directory to get list of files
+ this->CompressFiles with the list of files
+
+
+cmCPackGenericGenerator::InstallProject is used for both source and binary
+packages. It is controled based on values set in CPACK_ variables.
+
+
+InstallProject
+ 1. CPACK_INSTALL_COMMANDS - a list of commands used to install the package
+
+ 2. CPACK_INSTALLED_DIRECTORIES - copy this directory to CPACK_TEMPORARY_DIRECTORY
+
+ 3. CPACK_INSTALL_CMAKE_PROJECTS - a cmake install script
+ - run make preinstall
+ - run cmake_install.cmake
+ - set CMAKE_INSTALL_PREFIX to the temp directory
+ - CPACK_BUILD_CONFIG check this and set the BUILD_TYPE to it
+ - ReadListFile on the install script cmake_install.cmake
+ - run strip on the executables and libraries if CPACK_STRIP_FILES is TRUE
+
+Recommendations:
+
+rename cmCPackGenerators to cmCPackGeneratorFactory
+
+rename cmCPackGenericGenerator --> cmCPackGenerator
+
+rename cmCPackGenericGenerator::ProcessGenerator -> cmCPackGenerator::DoPackage
+
+
+break up cmCPackGenerator::InstallProject so it calls the following:
+
+// run user provided install commands
+ cmCPackGenerator::RunInstallCommands();
+// copy entire directories that need no processing like source trees
+ cmCPackGenerator::CopyPreInstalledDirectories();
+// run the cmake install scripts if provided
+ cmCPackGenerator::RunCMakeInstallScripts()
+
+-
diff --git a/Source/CPack/cmCPack7zGenerator.cxx b/Source/CPack/cmCPack7zGenerator.cxx
new file mode 100644
index 0000000..b01c216
--- /dev/null
+++ b/Source/CPack/cmCPack7zGenerator.cxx
@@ -0,0 +1,22 @@
+/*============================================================================
+ CMake - Cross Platform Makefile Generator
+ Copyright 2000-2009 Kitware, Inc., Insight Software Consortium
+
+ Distributed under the OSI-approved BSD License (the "License");
+ see accompanying file Copyright.txt for details.
+
+ This software is distributed WITHOUT ANY WARRANTY; without even the
+ implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
+ See the License for more information.
+============================================================================*/
+
+#include "cmCPack7zGenerator.h"
+
+cmCPack7zGenerator::cmCPack7zGenerator()
+ : cmCPackArchiveGenerator(cmArchiveWrite::CompressNone, "7zip")
+{
+}
+
+cmCPack7zGenerator::~cmCPack7zGenerator()
+{
+}
diff --git a/Source/CPack/cmCPack7zGenerator.h b/Source/CPack/cmCPack7zGenerator.h
new file mode 100644
index 0000000..ddbcc34
--- /dev/null
+++ b/Source/CPack/cmCPack7zGenerator.h
@@ -0,0 +1,36 @@
+/*============================================================================
+ CMake - Cross Platform Makefile Generator
+ Copyright 2000-2009 Kitware, Inc.
+
+ Distributed under the OSI-approved BSD License (the "License");
+ see accompanying file Copyright.txt for details.
+
+ This software is distributed WITHOUT ANY WARRANTY; without even the
+ implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
+ See the License for more information.
+============================================================================*/
+
+#ifndef cmCPack7zGenerator_h
+#define cmCPack7zGenerator_h
+
+#include "cmCPackArchiveGenerator.h"
+
+/** \class cmCPack7zGenerator
+ * \brief A generator for 7z files
+ */
+class cmCPack7zGenerator : public cmCPackArchiveGenerator
+{
+public:
+ cmCPackTypeMacro(cmCPack7zGenerator, cmCPackArchiveGenerator);
+
+ /**
+ * Construct generator
+ */
+ cmCPack7zGenerator();
+ ~cmCPack7zGenerator() CM_OVERRIDE;
+
+protected:
+ const char* GetOutputExtension() CM_OVERRIDE { return ".7z"; }
+};
+
+#endif
diff --git a/Source/CPack/cmCPackArchiveGenerator.cxx b/Source/CPack/cmCPackArchiveGenerator.cxx
new file mode 100644
index 0000000..b1f6864
--- /dev/null
+++ b/Source/CPack/cmCPackArchiveGenerator.cxx
@@ -0,0 +1,273 @@
+/*============================================================================
+ CMake - Cross Platform Makefile Generator
+ Copyright 2000-2009 Kitware, Inc., Insight Software Consortium
+
+ Distributed under the OSI-approved BSD License (the "License");
+ see accompanying file Copyright.txt for details.
+
+ This software is distributed WITHOUT ANY WARRANTY; without even the
+ implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
+ See the License for more information.
+============================================================================*/
+
+#include "cmCPackArchiveGenerator.h"
+
+#include "cmCPackLog.h"
+#include "cmGeneratedFileStream.h"
+#include "cmGlobalGenerator.h"
+#include "cmMakefile.h"
+#include "cmSystemTools.h"
+#include "cmake.h"
+#include <errno.h>
+
+#include <cm_libarchive.h>
+#include <cmsys/Directory.hxx>
+#include <cmsys/SystemTools.hxx>
+
+cmCPackArchiveGenerator::cmCPackArchiveGenerator(cmArchiveWrite::Compress t,
+ std::string const& format)
+{
+ this->Compress = t;
+ this->ArchiveFormat = format;
+}
+
+cmCPackArchiveGenerator::~cmCPackArchiveGenerator()
+{
+}
+
+int cmCPackArchiveGenerator::InitializeInternal()
+{
+ this->SetOptionIfNotSet("CPACK_INCLUDE_TOPLEVEL_DIRECTORY", "1");
+ return this->Superclass::InitializeInternal();
+}
+int cmCPackArchiveGenerator::addOneComponentToArchive(
+ cmArchiveWrite& archive, cmCPackComponent* component)
+{
+ cmCPackLogger(cmCPackLog::LOG_VERBOSE,
+ " - packaging component: " << component->Name << std::endl);
+ // Add the files of this component to the archive
+ std::string localToplevel(this->GetOption("CPACK_TEMPORARY_DIRECTORY"));
+ localToplevel += "/" + component->Name;
+ std::string dir = cmSystemTools::GetCurrentWorkingDirectory();
+ // Change to local toplevel
+ cmSystemTools::ChangeDirectory(localToplevel);
+ std::string filePrefix;
+ if (this->IsOn("CPACK_COMPONENT_INCLUDE_TOPLEVEL_DIRECTORY")) {
+ filePrefix = this->GetOption("CPACK_PACKAGE_FILE_NAME");
+ filePrefix += "/";
+ }
+ const char* installPrefix =
+ this->GetOption("CPACK_PACKAGING_INSTALL_PREFIX");
+ if (installPrefix && installPrefix[0] == '/' && installPrefix[1] != 0) {
+ // add to file prefix and remove the leading '/'
+ filePrefix += installPrefix + 1;
+ filePrefix += "/";
+ }
+ std::vector<std::string>::const_iterator fileIt;
+ for (fileIt = component->Files.begin(); fileIt != component->Files.end();
+ ++fileIt) {
+ std::string rp = filePrefix + *fileIt;
+ cmCPackLogger(cmCPackLog::LOG_DEBUG, "Adding file: " << rp << std::endl);
+ archive.Add(rp, 0, CM_NULLPTR, false);
+ if (!archive) {
+ cmCPackLogger(cmCPackLog::LOG_ERROR, "ERROR while packaging files: "
+ << archive.GetError() << std::endl);
+ return 0;
+ }
+ }
+ // Go back to previous dir
+ cmSystemTools::ChangeDirectory(dir);
+ return 1;
+}
+
+/*
+ * The macro will open/create a file 'filename'
+ * an declare and open the associated
+ * cmArchiveWrite 'archive' object.
+ */
+#define DECLARE_AND_OPEN_ARCHIVE(filename, archive) \
+ cmGeneratedFileStream gf; \
+ gf.Open(filename.c_str(), false, true); \
+ if (!GenerateHeader(&gf)) { \
+ cmCPackLogger(cmCPackLog::LOG_ERROR, \
+ "Problem to generate Header for archive < " \
+ << filename << ">." << std::endl); \
+ return 0; \
+ } \
+ cmArchiveWrite archive(gf, this->Compress, this->ArchiveFormat); \
+ if (!archive) { \
+ cmCPackLogger(cmCPackLog::LOG_ERROR, "Problem to create archive < " \
+ << filename << ">. ERROR =" << archive.GetError() \
+ << std::endl); \
+ return 0; \
+ }
+
+int cmCPackArchiveGenerator::PackageComponents(bool ignoreGroup)
+{
+ packageFileNames.clear();
+ // The default behavior is to have one package by component group
+ // unless CPACK_COMPONENTS_IGNORE_GROUP is specified.
+ if (!ignoreGroup) {
+ std::map<std::string, cmCPackComponentGroup>::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 packageFileName = std::string(toplevel);
+ packageFileName += "/" +
+ GetComponentPackageFileName(this->GetOption("CPACK_PACKAGE_FILE_NAME"),
+ compGIt->first, true) +
+ this->GetOutputExtension();
+ // open a block in order to automatically close archive
+ // at the end of the block
+ {
+ DECLARE_AND_OPEN_ARCHIVE(packageFileName, archive);
+ // now iterate over the component of this group
+ std::vector<cmCPackComponent*>::iterator compIt;
+ for (compIt = (compGIt->second).Components.begin();
+ compIt != (compGIt->second).Components.end(); ++compIt) {
+ // Add the files of this component to the archive
+ addOneComponentToArchive(archive, *compIt);
+ }
+ }
+ // add the generated package to package file names list
+ packageFileNames.push_back(packageFileName);
+ }
+ // Handle Orphan components (components not belonging to any groups)
+ std::map<std::string, cmCPackComponent>::iterator compIt;
+ for (compIt = this->Components.begin(); compIt != this->Components.end();
+ ++compIt) {
+ // Does the component belong to a group?
+ if (compIt->second.Group == CM_NULLPTR) {
+ cmCPackLogger(
+ cmCPackLog::LOG_VERBOSE, "Component <"
+ << compIt->second.Name
+ << "> does not belong to any group, package it separately."
+ << std::endl);
+ std::string localToplevel(
+ this->GetOption("CPACK_TEMPORARY_DIRECTORY"));
+ std::string packageFileName = std::string(toplevel);
+
+ localToplevel += "/" + compIt->first;
+ packageFileName += "/" + GetComponentPackageFileName(
+ this->GetOption("CPACK_PACKAGE_FILE_NAME"),
+ compIt->first, false) +
+ this->GetOutputExtension();
+ {
+ DECLARE_AND_OPEN_ARCHIVE(packageFileName, archive);
+ // Add the files of this component to the archive
+ addOneComponentToArchive(archive, &(compIt->second));
+ }
+ // 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 {
+ std::map<std::string, cmCPackComponent>::iterator compIt;
+ for (compIt = this->Components.begin(); compIt != this->Components.end();
+ ++compIt) {
+ std::string localToplevel(this->GetOption("CPACK_TEMPORARY_DIRECTORY"));
+ std::string packageFileName = std::string(toplevel);
+
+ localToplevel += "/" + compIt->first;
+ packageFileName += "/" +
+ GetComponentPackageFileName(this->GetOption("CPACK_PACKAGE_FILE_NAME"),
+ compIt->first, false) +
+ this->GetOutputExtension();
+ {
+ DECLARE_AND_OPEN_ARCHIVE(packageFileName, archive);
+ // Add the files of this component to the archive
+ addOneComponentToArchive(archive, &(compIt->second));
+ }
+ // add the generated package to package file names list
+ packageFileNames.push_back(packageFileName);
+ }
+ }
+ return 1;
+}
+
+int cmCPackArchiveGenerator::PackageComponentsAllInOne()
+{
+ // reset the package file names
+ packageFileNames.clear();
+ packageFileNames.push_back(std::string(toplevel));
+ packageFileNames[0] += "/" +
+ std::string(this->GetOption("CPACK_PACKAGE_FILE_NAME")) +
+ this->GetOutputExtension();
+ cmCPackLogger(cmCPackLog::LOG_VERBOSE,
+ "Packaging all groups in one package..."
+ "(CPACK_COMPONENTS_ALL_GROUPS_IN_ONE_PACKAGE is set)"
+ << std::endl);
+ DECLARE_AND_OPEN_ARCHIVE(packageFileNames[0], archive);
+
+ // The ALL COMPONENTS in ONE package case
+ std::map<std::string, cmCPackComponent>::iterator compIt;
+ for (compIt = this->Components.begin(); compIt != this->Components.end();
+ ++compIt) {
+ // Add the files of this component to the archive
+ addOneComponentToArchive(archive, &(compIt->second));
+ }
+
+ // archive goes out of scope so it will finalized and closed.
+ return 1;
+}
+
+int cmCPackArchiveGenerator::PackageFiles()
+{
+ cmCPackLogger(cmCPackLog::LOG_DEBUG, "Toplevel: " << toplevel << std::endl);
+
+ if (WantsComponentInstallation()) {
+ // CASE 1 : COMPONENT ALL-IN-ONE package
+ // If ALL COMPONENTS in ONE package has been requested
+ // then the package file is unique and should be open here.
+ if (componentPackageMethod == ONE_PACKAGE) {
+ return PackageComponentsAllInOne();
+ }
+ // 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 {
+ return PackageComponents(componentPackageMethod ==
+ ONE_PACKAGE_PER_COMPONENT);
+ }
+ }
+
+ // CASE 3 : NON COMPONENT package.
+ DECLARE_AND_OPEN_ARCHIVE(packageFileNames[0], archive);
+ std::vector<std::string>::const_iterator fileIt;
+ std::string dir = cmSystemTools::GetCurrentWorkingDirectory();
+ cmSystemTools::ChangeDirectory(toplevel);
+ for (fileIt = files.begin(); fileIt != files.end(); ++fileIt) {
+ // Get the relative path to the file
+ std::string rp =
+ cmSystemTools::RelativePath(toplevel.c_str(), fileIt->c_str());
+ archive.Add(rp, 0, CM_NULLPTR, false);
+ if (!archive) {
+ cmCPackLogger(cmCPackLog::LOG_ERROR, "Problem while adding file< "
+ << *fileIt << "> to archive <" << packageFileNames[0]
+ << "> .ERROR =" << archive.GetError() << std::endl);
+ return 0;
+ }
+ }
+ cmSystemTools::ChangeDirectory(dir);
+ // The destructor of cmArchiveWrite will close and finish the write
+ return 1;
+}
+
+int cmCPackArchiveGenerator::GenerateHeader(std::ostream*)
+{
+ return 1;
+}
+
+bool cmCPackArchiveGenerator::SupportsComponentInstallation() const
+{
+ // The Component installation support should only
+ // be activated if explicitly requested by the user
+ // (for backward compatibility reason)
+ return IsOn("CPACK_ARCHIVE_COMPONENT_INSTALL");
+}
diff --git a/Source/CPack/cmCPackArchiveGenerator.h b/Source/CPack/cmCPackArchiveGenerator.h
new file mode 100644
index 0000000..a018ebd
--- /dev/null
+++ b/Source/CPack/cmCPackArchiveGenerator.h
@@ -0,0 +1,75 @@
+/*============================================================================
+ CMake - Cross Platform Makefile Generator
+ Copyright 2000-2009 Kitware, Inc.
+
+ Distributed under the OSI-approved BSD License (the "License");
+ see accompanying file Copyright.txt for details.
+
+ This software is distributed WITHOUT ANY WARRANTY; without even the
+ implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
+ See the License for more information.
+============================================================================*/
+
+#ifndef cmCPackArchiveGenerator_h
+#define cmCPackArchiveGenerator_h
+
+#include "cmCPackGenerator.h"
+
+#include "cmArchiveWrite.h"
+
+/** \class cmCPackArchiveGenerator
+ * \brief A generator base for libarchive generation.
+ * The generator itself uses the libarchive wrapper
+ * \ref cmArchiveWrite.
+ *
+ */
+class cmCPackArchiveGenerator : public cmCPackGenerator
+{
+public:
+ cmTypeMacro(cmCPackArchiveGenerator, cmCPackGenerator);
+
+ /**
+ * Construct generator
+ */
+ cmCPackArchiveGenerator(cmArchiveWrite::Compress, std::string const& format);
+ ~cmCPackArchiveGenerator() CM_OVERRIDE;
+ // Used to add a header to the archive
+ virtual int GenerateHeader(std::ostream* os);
+ // component support
+ bool SupportsComponentInstallation() const CM_OVERRIDE;
+
+protected:
+ int InitializeInternal() CM_OVERRIDE;
+ /**
+ * Add the files belonging to the specified component
+ * to the provided (already opened) archive.
+ * @param[in,out] archive the archive object
+ * @param[in] component the component whose file will be added to archive
+ */
+ int addOneComponentToArchive(cmArchiveWrite& archive,
+ cmCPackComponent* component);
+
+ /**
+ * The main package file method.
+ * If component install was required this
+ * method will call either PackageComponents or
+ * PackageComponentsAllInOne.
+ */
+ int PackageFiles() CM_OVERRIDE;
+ /**
+ * 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();
+ const char* GetOutputExtension() CM_OVERRIDE = 0;
+ cmArchiveWrite::Compress Compress;
+ std::string ArchiveFormat;
+};
+
+#endif
diff --git a/Source/CPack/cmCPackBundleGenerator.cxx b/Source/CPack/cmCPackBundleGenerator.cxx
new file mode 100644
index 0000000..9276e3a
--- /dev/null
+++ b/Source/CPack/cmCPackBundleGenerator.cxx
@@ -0,0 +1,292 @@
+/*============================================================================
+ CMake - Cross Platform Makefile Generator
+ Copyright 2000-2009 Kitware, Inc., Insight Software Consortium
+
+ Distributed under the OSI-approved BSD License (the "License");
+ see accompanying file Copyright.txt for details.
+
+ This software is distributed WITHOUT ANY WARRANTY; without even the
+ implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
+ See the License for more information.
+============================================================================*/
+
+#include "cmCPackBundleGenerator.h"
+
+#include "cmCPackLog.h"
+#include "cmSystemTools.h"
+
+#include <cmsys/RegularExpression.hxx>
+
+cmCPackBundleGenerator::cmCPackBundleGenerator()
+{
+}
+
+cmCPackBundleGenerator::~cmCPackBundleGenerator()
+{
+}
+
+int cmCPackBundleGenerator::InitializeInternal()
+{
+ const char* name = this->GetOption("CPACK_BUNDLE_NAME");
+ if (0 == name) {
+ cmCPackLogger(cmCPackLog::LOG_ERROR,
+ "CPACK_BUNDLE_NAME must be set to use the Bundle generator."
+ << std::endl);
+
+ return 0;
+ }
+
+ if (this->GetOption("CPACK_BUNDLE_APPLE_CERT_APP")) {
+ const std::string codesign_path = cmSystemTools::FindProgram(
+ "codesign", std::vector<std::string>(), false);
+
+ if (codesign_path.empty()) {
+ cmCPackLogger(cmCPackLog::LOG_ERROR, "Cannot locate codesign command"
+ << std::endl);
+ return 0;
+ }
+ this->SetOptionIfNotSet("CPACK_COMMAND_CODESIGN", codesign_path.c_str());
+ }
+
+ return this->Superclass::InitializeInternal();
+}
+
+const char* cmCPackBundleGenerator::GetPackagingInstallPrefix()
+{
+ this->InstallPrefix = "/";
+ this->InstallPrefix += this->GetOption("CPACK_BUNDLE_NAME");
+ this->InstallPrefix += ".app/Contents/Resources";
+
+ return this->InstallPrefix.c_str();
+}
+
+int cmCPackBundleGenerator::ConstructBundle()
+{
+
+ // Get required arguments ...
+ const std::string cpack_bundle_name = this->GetOption("CPACK_BUNDLE_NAME")
+ ? this->GetOption("CPACK_BUNDLE_NAME")
+ : "";
+ if (cpack_bundle_name.empty()) {
+ cmCPackLogger(cmCPackLog::LOG_ERROR, "CPACK_BUNDLE_NAME must be set."
+ << std::endl);
+
+ return 0;
+ }
+
+ const std::string cpack_bundle_plist = this->GetOption("CPACK_BUNDLE_PLIST")
+ ? this->GetOption("CPACK_BUNDLE_PLIST")
+ : "";
+ if (cpack_bundle_plist.empty()) {
+ cmCPackLogger(cmCPackLog::LOG_ERROR, "CPACK_BUNDLE_PLIST must be set."
+ << std::endl);
+
+ return 0;
+ }
+
+ const std::string cpack_bundle_icon = this->GetOption("CPACK_BUNDLE_ICON")
+ ? this->GetOption("CPACK_BUNDLE_ICON")
+ : "";
+ if (cpack_bundle_icon.empty()) {
+ cmCPackLogger(cmCPackLog::LOG_ERROR, "CPACK_BUNDLE_ICON must be set."
+ << std::endl);
+
+ return 0;
+ }
+
+ // Get optional arguments ...
+ const std::string cpack_bundle_startup_command =
+ this->GetOption("CPACK_BUNDLE_STARTUP_COMMAND")
+ ? this->GetOption("CPACK_BUNDLE_STARTUP_COMMAND")
+ : "";
+
+ // The staging directory contains everything that will end-up inside the
+ // final disk image ...
+ std::ostringstream staging;
+ staging << toplevel;
+
+ std::ostringstream contents;
+ contents << staging.str() << "/" << cpack_bundle_name << ".app/"
+ << "Contents";
+
+ std::ostringstream application;
+ application << contents.str() << "/"
+ << "MacOS";
+
+ std::ostringstream resources;
+ resources << contents.str() << "/"
+ << "Resources";
+
+ // Install a required, user-provided bundle metadata file ...
+ std::ostringstream plist_source;
+ plist_source << cpack_bundle_plist;
+
+ std::ostringstream plist_target;
+ plist_target << contents.str() << "/"
+ << "Info.plist";
+
+ if (!this->CopyFile(plist_source, plist_target)) {
+ cmCPackLogger(
+ cmCPackLog::LOG_ERROR,
+ "Error copying plist. Check the value of CPACK_BUNDLE_PLIST."
+ << std::endl);
+
+ return 0;
+ }
+
+ // Install a user-provided bundle icon ...
+ std::ostringstream icon_source;
+ icon_source << cpack_bundle_icon;
+
+ std::ostringstream icon_target;
+ icon_target << resources.str() << "/" << cpack_bundle_name << ".icns";
+
+ if (!this->CopyFile(icon_source, icon_target)) {
+ cmCPackLogger(
+ cmCPackLog::LOG_ERROR,
+ "Error copying bundle icon. Check the value of CPACK_BUNDLE_ICON."
+ << std::endl);
+
+ return 0;
+ }
+
+ // Optionally a user-provided startup command (could be an
+ // executable or a script) ...
+ if (!cpack_bundle_startup_command.empty()) {
+ std::ostringstream command_source;
+ command_source << cpack_bundle_startup_command;
+
+ std::ostringstream command_target;
+ command_target << application.str() << "/" << cpack_bundle_name;
+
+ if (!this->CopyFile(command_source, command_target)) {
+ cmCPackLogger(cmCPackLog::LOG_ERROR,
+ "Error copying startup command. "
+ " Check the value of CPACK_BUNDLE_STARTUP_COMMAND."
+ << std::endl);
+
+ return 0;
+ }
+
+ cmSystemTools::SetPermissions(command_target.str().c_str(), 0777);
+ }
+
+ return 1;
+}
+
+int cmCPackBundleGenerator::PackageFiles()
+{
+ if (!this->ConstructBundle()) {
+ return 0;
+ }
+
+ if (!this->SignBundle(toplevel)) {
+ return 0;
+ }
+
+ return this->CreateDMG(toplevel, packageFileNames[0]);
+}
+
+bool cmCPackBundleGenerator::SupportsComponentInstallation() const
+{
+ return false;
+}
+
+int cmCPackBundleGenerator::SignBundle(const std::string& src_dir)
+{
+ const std::string cpack_apple_cert_app =
+ this->GetOption("CPACK_BUNDLE_APPLE_CERT_APP")
+ ? this->GetOption("CPACK_BUNDLE_APPLE_CERT_APP")
+ : "";
+
+ // codesign the application.
+ if (!cpack_apple_cert_app.empty()) {
+ std::string output;
+ std::string bundle_path;
+ bundle_path = src_dir + "/";
+ bundle_path += this->GetOption("CPACK_BUNDLE_NAME");
+ bundle_path += ".app";
+
+ // A list of additional files to sign, ie. frameworks and plugins.
+ const std::string sign_parameter =
+ this->GetOption("CPACK_BUNDLE_APPLE_CODESIGN_PARAMETER")
+ ? this->GetOption("CPACK_BUNDLE_APPLE_CODESIGN_PARAMETER")
+ : "--deep -f";
+
+ const std::string sign_files =
+ this->GetOption("CPACK_BUNDLE_APPLE_CODESIGN_FILES")
+ ? this->GetOption("CPACK_BUNDLE_APPLE_CODESIGN_FILES")
+ : "";
+
+ std::vector<std::string> relFiles;
+ cmSystemTools::ExpandListArgument(sign_files, relFiles);
+
+ // sign the files supplied by the user, ie. frameworks.
+ for (std::vector<std::string>::iterator it = relFiles.begin();
+ it != relFiles.end(); ++it) {
+ std::ostringstream temp_sign_file_cmd;
+ temp_sign_file_cmd << this->GetOption("CPACK_COMMAND_CODESIGN");
+ temp_sign_file_cmd << " " << sign_parameter << " -s \""
+ << cpack_apple_cert_app;
+ temp_sign_file_cmd << "\" -i ";
+ temp_sign_file_cmd << this->GetOption("CPACK_APPLE_BUNDLE_ID");
+ temp_sign_file_cmd << " \"";
+ temp_sign_file_cmd << bundle_path;
+ temp_sign_file_cmd << *it << "\"";
+
+ if (!this->RunCommand(temp_sign_file_cmd, &output)) {
+ cmCPackLogger(cmCPackLog::LOG_ERROR,
+ "Error signing file:" << bundle_path << *it << std::endl
+ << output << std::endl);
+
+ return 0;
+ }
+ }
+
+ // sign main binary
+ std::ostringstream temp_sign_binary_cmd;
+ temp_sign_binary_cmd << this->GetOption("CPACK_COMMAND_CODESIGN");
+ temp_sign_binary_cmd << " " << sign_parameter << " -s \""
+ << cpack_apple_cert_app;
+ temp_sign_binary_cmd << "\" \"" << bundle_path << "\"";
+
+ if (!this->RunCommand(temp_sign_binary_cmd, &output)) {
+ cmCPackLogger(cmCPackLog::LOG_ERROR,
+ "Error signing the application binary." << std::endl
+ << output
+ << std::endl);
+
+ return 0;
+ }
+
+ // sign app bundle
+ std::ostringstream temp_codesign_cmd;
+ temp_codesign_cmd << this->GetOption("CPACK_COMMAND_CODESIGN");
+ temp_codesign_cmd << " " << sign_parameter << " -s \""
+ << cpack_apple_cert_app << "\"";
+ if (this->GetOption("CPACK_BUNDLE_APPLE_ENTITLEMENTS")) {
+ temp_codesign_cmd << " --entitlements ";
+ temp_codesign_cmd << this->GetOption("CPACK_BUNDLE_APPLE_ENTITLEMENTS");
+ }
+ temp_codesign_cmd << " \"" << bundle_path << "\"";
+
+ if (!this->RunCommand(temp_codesign_cmd, &output)) {
+ cmCPackLogger(cmCPackLog::LOG_ERROR,
+ "Error signing the application package." << std::endl
+ << output
+ << std::endl);
+
+ return 0;
+ }
+
+ cmCPackLogger(cmCPackLog::LOG_OUTPUT, "- Application has been codesigned"
+ << std::endl);
+ cmCPackLogger(cmCPackLog::LOG_VERBOSE,
+ (this->GetOption("CPACK_BUNDLE_APPLE_ENTITLEMENTS")
+ ? "with entitlement sandboxing"
+ : "without entitlement sandboxing")
+ << std::endl);
+ }
+
+ return 1;
+}
diff --git a/Source/CPack/cmCPackBundleGenerator.h b/Source/CPack/cmCPackBundleGenerator.h
new file mode 100644
index 0000000..c6fa408
--- /dev/null
+++ b/Source/CPack/cmCPackBundleGenerator.h
@@ -0,0 +1,42 @@
+/*============================================================================
+ CMake - Cross Platform Makefile Generator
+ Copyright 2000-2009 Kitware, Inc.
+
+ Distributed under the OSI-approved BSD License (the "License");
+ see accompanying file Copyright.txt for details.
+
+ This software is distributed WITHOUT ANY WARRANTY; without even the
+ implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
+ See the License for more information.
+============================================================================*/
+
+#ifndef cmCPackBundleGenerator_h
+#define cmCPackBundleGenerator_h
+
+#include "cmCPackDragNDropGenerator.h"
+
+/** \class cmCPackBundleGenerator
+ * \brief A generator for OSX bundles
+ *
+ * Based on Gimp.app
+ */
+class cmCPackBundleGenerator : public cmCPackDragNDropGenerator
+{
+public:
+ cmCPackTypeMacro(cmCPackBundleGenerator, cmCPackDragNDropGenerator);
+
+ cmCPackBundleGenerator();
+ virtual ~cmCPackBundleGenerator();
+
+protected:
+ int InitializeInternal() CM_OVERRIDE;
+ const char* GetPackagingInstallPrefix() CM_OVERRIDE;
+ int ConstructBundle();
+ int SignBundle(const std::string& src_dir);
+ int PackageFiles() CM_OVERRIDE;
+ bool SupportsComponentInstallation() const CM_OVERRIDE;
+
+ std::string InstallPrefix;
+};
+
+#endif
diff --git a/Source/CPack/cmCPackComponentGroup.cxx b/Source/CPack/cmCPackComponentGroup.cxx
new file mode 100644
index 0000000..d262ac9
--- /dev/null
+++ b/Source/CPack/cmCPackComponentGroup.cxx
@@ -0,0 +1,43 @@
+/*============================================================================
+ CMake - Cross Platform Makefile Generator
+ Copyright 2000-2009 Kitware, Inc., Insight Software Consortium
+
+ Distributed under the OSI-approved BSD License (the "License");
+ see accompanying file Copyright.txt for details.
+
+ This software is distributed WITHOUT ANY WARRANTY; without even the
+ implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
+ See the License for more information.
+============================================================================*/
+
+#include "cmCPackComponentGroup.h"
+
+#include "cmSystemTools.h"
+
+#include <string>
+#include <vector>
+
+unsigned long cmCPackComponent::GetInstalledSize(
+ const std::string& installDir) const
+{
+ if (this->TotalSize != 0) {
+ return this->TotalSize;
+ }
+
+ std::vector<std::string>::const_iterator fileIt;
+ for (fileIt = this->Files.begin(); fileIt != this->Files.end(); ++fileIt) {
+ std::string path = installDir;
+ path += '/';
+ path += *fileIt;
+ this->TotalSize += cmSystemTools::FileLength(path);
+ }
+
+ return this->TotalSize;
+}
+
+unsigned long cmCPackComponent::GetInstalledSizeInKbytes(
+ const std::string& installDir) const
+{
+ unsigned long result = (GetInstalledSize(installDir) + 512) / 1024;
+ return result ? result : 1;
+}
diff --git a/Source/CPack/cmCPackComponentGroup.h b/Source/CPack/cmCPackComponentGroup.h
new file mode 100644
index 0000000..01a9e76
--- /dev/null
+++ b/Source/CPack/cmCPackComponentGroup.h
@@ -0,0 +1,149 @@
+/*============================================================================
+ CMake - Cross Platform Makefile Generator
+ Copyright 2000-2009 Kitware, Inc.
+
+ Distributed under the OSI-approved BSD License (the "License");
+ see accompanying file Copyright.txt for details.
+
+ This software is distributed WITHOUT ANY WARRANTY; without even the
+ implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
+ See the License for more information.
+============================================================================*/
+
+#ifndef cmCPackComponentGroup_h
+#define cmCPackComponentGroup_h
+
+#include "cmStandardIncludes.h"
+
+class cmCPackComponentGroup;
+
+/** \class cmCPackInstallationType
+ * \brief A certain type of installation, which encompasses a
+ * set of components.
+ */
+class cmCPackInstallationType
+{
+public:
+ /// The name of the installation type (used to reference this
+ /// installation type).
+ std::string Name;
+
+ /// The name of the installation type as displayed to the user.
+ std::string DisplayName;
+
+ /// The index number of the installation type. This is an arbitrary
+ /// numbering from 1 to the number of installation types.
+ unsigned Index;
+};
+
+/** \class cmCPackComponent
+ * \brief A single component to be installed by CPack.
+ */
+class cmCPackComponent
+{
+public:
+ cmCPackComponent()
+ : Group(CM_NULLPTR)
+ , IsRequired(true)
+ , IsHidden(false)
+ , IsDisabledByDefault(false)
+ , IsDownloaded(false)
+ , TotalSize(0)
+ {
+ }
+
+ /// The name of the component (used to reference the component).
+ std::string Name;
+
+ /// The name of the component as displayed to the user.
+ std::string DisplayName;
+
+ /// The component group that contains this component (if any).
+ cmCPackComponentGroup* Group;
+
+ /// Whether this component group must always be installed.
+ bool IsRequired : 1;
+
+ /// Whether this component group is hidden. A hidden component group
+ /// is always installed. However, it may still be shown to the user.
+ bool IsHidden : 1;
+
+ /// Whether this component defaults to "disabled".
+ bool IsDisabledByDefault : 1;
+
+ /// Whether this component should be downloaded on-the-fly. If false,
+ /// the component will be a part of the installation package.
+ bool IsDownloaded : 1;
+
+ /// A description of this component.
+ std::string Description;
+
+ /// The installation types that this component is a part of.
+ std::vector<cmCPackInstallationType*> InstallationTypes;
+
+ /// If IsDownloaded is true, the name of the archive file that
+ /// contains the files that are part of this component.
+ std::string ArchiveFile;
+
+ /// The components that this component depends on.
+ std::vector<cmCPackComponent*> Dependencies;
+
+ /// The components that depend on this component.
+ std::vector<cmCPackComponent*> ReverseDependencies;
+
+ /// The list of installed files that are part of this component.
+ std::vector<std::string> Files;
+
+ /// The list of installed directories that are part of this component.
+ std::vector<std::string> Directories;
+
+ /// Get the total installed size of all of the files in this
+ /// component, in bytes. installDir is the directory into which the
+ /// component was installed.
+ unsigned long GetInstalledSize(const std::string& installDir) const;
+
+ /// Identical to GetInstalledSize, but returns the result in
+ /// kilobytes.
+ unsigned long GetInstalledSizeInKbytes(const std::string& installDir) const;
+
+private:
+ mutable unsigned long TotalSize;
+};
+
+/** \class cmCPackComponentGroup
+ * \brief A component group to be installed by CPack.
+ */
+class cmCPackComponentGroup
+{
+public:
+ cmCPackComponentGroup()
+ : ParentGroup(CM_NULLPTR)
+ {
+ }
+
+ /// The name of the group (used to reference the group).
+ std::string Name;
+
+ /// The name of the component as displayed to the user.
+ std::string DisplayName;
+
+ /// The description of this component group.
+ std::string Description;
+
+ /// Whether the name of the component will be shown in bold.
+ bool IsBold : 1;
+
+ /// Whether the section should be expanded by default
+ bool IsExpandedByDefault : 1;
+
+ /// The components within this group.
+ std::vector<cmCPackComponent*> Components;
+
+ /// The parent group of this component group (if any).
+ cmCPackComponentGroup* ParentGroup;
+
+ /// The subgroups of this group.
+ std::vector<cmCPackComponentGroup*> Subgroups;
+};
+
+#endif
diff --git a/Source/CPack/cmCPackConfigure.h.in b/Source/CPack/cmCPackConfigure.h.in
new file mode 100644
index 0000000..3d7702e
--- /dev/null
+++ b/Source/CPack/cmCPackConfigure.h.in
@@ -0,0 +1,11 @@
+/*============================================================================
+ CMake - Cross Platform Makefile Generator
+ Copyright 2000-2009 Kitware, Inc., Insight Software Consortium
+
+ Distributed under the OSI-approved BSD License (the "License");
+ see accompanying file Copyright.txt for details.
+
+ This software is distributed WITHOUT ANY WARRANTY; without even the
+ implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
+ See the License for more information.
+============================================================================*/
diff --git a/Source/CPack/cmCPackCygwinBinaryGenerator.cxx b/Source/CPack/cmCPackCygwinBinaryGenerator.cxx
new file mode 100644
index 0000000..83af89e
--- /dev/null
+++ b/Source/CPack/cmCPackCygwinBinaryGenerator.cxx
@@ -0,0 +1,84 @@
+/*============================================================================
+ CMake - Cross Platform Makefile Generator
+ Copyright 2000-2009 Kitware, Inc., Insight Software Consortium
+
+ Distributed under the OSI-approved BSD License (the "License");
+ see accompanying file Copyright.txt for details.
+
+ This software is distributed WITHOUT ANY WARRANTY; without even the
+ implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
+ See the License for more information.
+============================================================================*/
+
+#include "cmCPackCygwinBinaryGenerator.h"
+
+#include "cmCPackLog.h"
+#include "cmGeneratedFileStream.h"
+#include "cmGlobalGenerator.h"
+#include "cmMakefile.h"
+#include "cmSystemTools.h"
+#include "cmake.h"
+
+#include <cmsys/SystemTools.hxx>
+
+cmCPackCygwinBinaryGenerator::cmCPackCygwinBinaryGenerator()
+{
+}
+
+cmCPackCygwinBinaryGenerator::~cmCPackCygwinBinaryGenerator()
+{
+}
+
+int cmCPackCygwinBinaryGenerator::InitializeInternal()
+{
+ this->SetOptionIfNotSet("CPACK_PACKAGING_INSTALL_PREFIX", "/usr");
+ this->SetOptionIfNotSet("CPACK_INCLUDE_TOPLEVEL_DIRECTORY", "0");
+ return this->Superclass::InitializeInternal();
+}
+
+int cmCPackCygwinBinaryGenerator::PackageFiles()
+{
+ std::string packageName = this->GetOption("CPACK_PACKAGE_NAME");
+ packageName += "-";
+ packageName += this->GetOption("CPACK_PACKAGE_VERSION");
+ packageName = cmsys::SystemTools::LowerCase(packageName);
+ std::string manifest = "/usr/share/doc/";
+ manifest += packageName;
+ manifest += "/MANIFEST";
+ std::string manifestFile = this->GetOption("CPACK_TEMPORARY_DIRECTORY");
+ // Create a MANIFEST file that contains all of the files in
+ // the tar file
+ std::string tempdir = manifestFile;
+ manifestFile += manifest;
+ // create an extra scope to force the stream
+ // to create the file before the super class is called
+ {
+ cmGeneratedFileStream ofs(manifestFile.c_str());
+ for (std::vector<std::string>::const_iterator i = files.begin();
+ i != files.end(); ++i) {
+ // remove the temp dir and replace with /usr
+ ofs << (*i).substr(tempdir.size()) << "\n";
+ }
+ ofs << manifest << "\n";
+ }
+ // add the manifest file to the list of all files
+ files.push_back(manifestFile);
+
+ // create the bzip2 tar file
+ return this->Superclass::PackageFiles();
+}
+
+const char* cmCPackCygwinBinaryGenerator::GetOutputExtension()
+{
+ this->OutputExtension = "-";
+ const char* patchNumber = this->GetOption("CPACK_CYGWIN_PATCH_NUMBER");
+ if (!patchNumber) {
+ patchNumber = "1";
+ cmCPackLogger(cmCPackLog::LOG_WARNING,
+ "CPACK_CYGWIN_PATCH_NUMBER not specified using 1"
+ << std::endl);
+ }
+ this->OutputExtension += patchNumber;
+ this->OutputExtension += ".tar.bz2";
+ return this->OutputExtension.c_str();
+}
diff --git a/Source/CPack/cmCPackCygwinBinaryGenerator.h b/Source/CPack/cmCPackCygwinBinaryGenerator.h
new file mode 100644
index 0000000..8de4bae
--- /dev/null
+++ b/Source/CPack/cmCPackCygwinBinaryGenerator.h
@@ -0,0 +1,39 @@
+/*============================================================================
+ CMake - Cross Platform Makefile Generator
+ Copyright 2000-2009 Kitware, Inc.
+
+ Distributed under the OSI-approved BSD License (the "License");
+ see accompanying file Copyright.txt for details.
+
+ This software is distributed WITHOUT ANY WARRANTY; without even the
+ implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
+ See the License for more information.
+============================================================================*/
+
+#ifndef cmCPackCygwinBinaryGenerator_h
+#define cmCPackCygwinBinaryGenerator_h
+
+#include "cmCPackTarBZip2Generator.h"
+
+/** \class cmCPackCygwinBinaryGenerator
+ * \brief A generator for TarBZip2 files
+ */
+class cmCPackCygwinBinaryGenerator : public cmCPackTarBZip2Generator
+{
+public:
+ cmCPackTypeMacro(cmCPackCygwinBinaryGenerator, cmCPackTarBZip2Generator);
+
+ /**
+ * Construct generator
+ */
+ cmCPackCygwinBinaryGenerator();
+ virtual ~cmCPackCygwinBinaryGenerator();
+
+protected:
+ virtual int InitializeInternal();
+ int PackageFiles();
+ virtual const char* GetOutputExtension();
+ std::string OutputExtension;
+};
+
+#endif
diff --git a/Source/CPack/cmCPackCygwinSourceGenerator.cxx b/Source/CPack/cmCPackCygwinSourceGenerator.cxx
new file mode 100644
index 0000000..5fcfaf4
--- /dev/null
+++ b/Source/CPack/cmCPackCygwinSourceGenerator.cxx
@@ -0,0 +1,167 @@
+/*============================================================================
+ CMake - Cross Platform Makefile Generator
+ Copyright 2000-2009 Kitware, Inc., Insight Software Consortium
+
+ Distributed under the OSI-approved BSD License (the "License");
+ see accompanying file Copyright.txt for details.
+
+ This software is distributed WITHOUT ANY WARRANTY; without even the
+ implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
+ See the License for more information.
+============================================================================*/
+
+#include "cmCPackCygwinSourceGenerator.h"
+
+#include "cmCPackLog.h"
+#include "cmGeneratedFileStream.h"
+#include "cmGlobalGenerator.h"
+#include "cmMakefile.h"
+#include "cmSystemTools.h"
+#include "cmake.h"
+
+#include <cmsys/SystemTools.hxx>
+
+// Includes needed for implementation of RenameFile. This is not in
+// system tools because it is not implemented robustly enough to move
+// files across directories.
+#ifdef _WIN32
+#include <sys/stat.h>
+#include <windows.h>
+#endif
+
+cmCPackCygwinSourceGenerator::cmCPackCygwinSourceGenerator()
+{
+}
+
+cmCPackCygwinSourceGenerator::~cmCPackCygwinSourceGenerator()
+{
+}
+
+int cmCPackCygwinSourceGenerator::InitializeInternal()
+{
+ this->SetOptionIfNotSet("CPACK_INCLUDE_TOPLEVEL_DIRECTORY", "0");
+ return this->Superclass::InitializeInternal();
+}
+
+int cmCPackCygwinSourceGenerator::PackageFiles()
+{
+ // Create a tar file of the sources
+ std::string packageDirFileName =
+ this->GetOption("CPACK_TEMPORARY_DIRECTORY");
+ packageDirFileName += ".tar.bz2";
+ packageFileNames[0] = packageDirFileName;
+ std::string output;
+ // skip one parent up to the cmCPackTarBZip2Generator
+ // to create tar.bz2 file with the list of source
+ // files
+ this->Compress = cmArchiveWrite::CompressBZip2;
+ if (!this->cmCPackTarBZip2Generator::PackageFiles()) {
+ return 0;
+ }
+ // Now create a tar file that contains the above .tar.bz2 file
+ // and the CPACK_CYGWIN_PATCH_FILE and CPACK_TOPLEVEL_DIRECTORY
+ // files
+ std::string compressOutFile = packageDirFileName;
+ // at this point compressOutFile is the full path to
+ // _CPack_Package/.../package-2.5.0.tar.bz2
+ // we want to create a tar _CPack_Package/.../package-2.5.0-1-src.tar.bz2
+ // with these
+ // _CPack_Package/.../package-2.5.0-1.patch
+ // _CPack_Package/.../package-2.5.0-1.sh
+ // _CPack_Package/.../package-2.5.0.tar.bz2
+ // the -1 is CPACK_CYGWIN_PATCH_NUMBER
+
+ // first copy the patch file and the .sh file
+ // to the toplevel cpack temp dir
+
+ // copy the patch file into place
+ if (!this->GetOption("CPACK_CYGWIN_PATCH_FILE")) {
+ cmCPackLogger(cmCPackLog::LOG_ERROR,
+ "No patch file specified for cygwin sources.");
+ return 0;
+ }
+ if (!cmSystemTools::CopyFileAlways(
+ this->GetOption("CPACK_CYGWIN_PATCH_FILE"),
+ this->GetOption("CPACK_TOPLEVEL_DIRECTORY"))) {
+ cmCPackLogger(cmCPackLog::LOG_ERROR, "problem copying: ["
+ << this->GetOption("CPACK_CYGWIN_PATCH_FILE") << "]\nto\n["
+ << this->GetOption("CPACK_TOPLEVEL_DIRECTORY") << "]\n");
+ return 0;
+ }
+ if (!this->GetOption("CPACK_CYGWIN_BUILD_SCRIPT")) {
+ cmCPackLogger(cmCPackLog::LOG_ERROR,
+ "No build script specified for cygwin sources.");
+ return 0;
+ }
+ // copy the build script into place
+ if (!cmSystemTools::CopyFileAlways(
+ this->GetOption("CPACK_CYGWIN_BUILD_SCRIPT"),
+ this->GetOption("CPACK_TOPLEVEL_DIRECTORY"))) {
+ cmCPackLogger(cmCPackLog::LOG_ERROR, "problem copying: "
+ << this->GetOption("CPACK_CYGWIN_BUILD_SCRIPT") << "\nto\n"
+ << this->GetOption("CPACK_TOPLEVEL_DIRECTORY") << "]\n");
+ return 0;
+ }
+ std::string outerTarFile = this->GetOption("CPACK_TEMPORARY_DIRECTORY");
+ outerTarFile += "-";
+ const char* patch = this->GetOption("CPACK_CYGWIN_PATCH_NUMBER");
+ if (!patch) {
+ cmCPackLogger(cmCPackLog::LOG_WARNING, "CPACK_CYGWIN_PATCH_NUMBER"
+ << " not specified, defaulting to 1\n");
+ patch = "1";
+ }
+ outerTarFile += patch;
+ outerTarFile += "-src.tar.bz2";
+ std::string tmpDir = this->GetOption("CPACK_TOPLEVEL_DIRECTORY");
+ std::string buildScript = tmpDir;
+ buildScript += "/";
+ buildScript += cmSystemTools::GetFilenameName(
+ this->GetOption("CPACK_CYGWIN_BUILD_SCRIPT"));
+ std::string patchFile = tmpDir;
+ patchFile += "/";
+ patchFile +=
+ cmSystemTools::GetFilenameName(this->GetOption("CPACK_CYGWIN_PATCH_FILE"));
+
+ std::string file = cmSystemTools::GetFilenameName(compressOutFile);
+ std::string sourceTar = cmSystemTools::GetFilenamePath(compressOutFile);
+ sourceTar += "/";
+ sourceTar += file;
+ /* reset list of file to be packaged */
+ files.clear();
+ // a source release in cygwin should have the build script used
+ // to build the package, the patch file that is different from the
+ // regular upstream version of the sources, and a bziped tar file
+ // of the original sources
+ files.push_back(buildScript);
+ files.push_back(patchFile);
+ files.push_back(sourceTar);
+ /* update the name of the produced package */
+ packageFileNames[0] = outerTarFile;
+ /* update the toplevel dir */
+ toplevel = tmpDir;
+ if (!this->cmCPackTarBZip2Generator::PackageFiles()) {
+ return 0;
+ }
+ return 1;
+}
+
+const char* cmCPackCygwinSourceGenerator::GetPackagingInstallPrefix()
+{
+ this->InstallPrefix = "/";
+ this->InstallPrefix += this->GetOption("CPACK_PACKAGE_FILE_NAME");
+ return this->InstallPrefix.c_str();
+}
+
+const char* cmCPackCygwinSourceGenerator::GetOutputExtension()
+{
+ this->OutputExtension = "-";
+ const char* patch = this->GetOption("CPACK_CYGWIN_PATCH_NUMBER");
+ if (!patch) {
+ cmCPackLogger(cmCPackLog::LOG_WARNING, "CPACK_CYGWIN_PATCH_NUMBER"
+ << " not specified, defaulting to 1\n");
+ patch = "1";
+ }
+ this->OutputExtension += patch;
+ this->OutputExtension += "-src.tar.bz2";
+ return this->OutputExtension.c_str();
+}
diff --git a/Source/CPack/cmCPackCygwinSourceGenerator.h b/Source/CPack/cmCPackCygwinSourceGenerator.h
new file mode 100644
index 0000000..4aba8b9
--- /dev/null
+++ b/Source/CPack/cmCPackCygwinSourceGenerator.h
@@ -0,0 +1,41 @@
+/*============================================================================
+ CMake - Cross Platform Makefile Generator
+ Copyright 2000-2009 Kitware, Inc.
+
+ Distributed under the OSI-approved BSD License (the "License");
+ see accompanying file Copyright.txt for details.
+
+ This software is distributed WITHOUT ANY WARRANTY; without even the
+ implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
+ See the License for more information.
+============================================================================*/
+
+#ifndef cmCPackCygwinSourceGenerator_h
+#define cmCPackCygwinSourceGenerator_h
+
+#include "cmCPackTarBZip2Generator.h"
+
+/** \class cmCPackCygwinSourceGenerator
+ * \brief A generator for cygwin source files
+ */
+class cmCPackCygwinSourceGenerator : public cmCPackTarBZip2Generator
+{
+public:
+ cmCPackTypeMacro(cmCPackCygwinSourceGenerator, cmCPackTarBZip2Generator);
+
+ /**
+ * Construct generator
+ */
+ cmCPackCygwinSourceGenerator();
+ virtual ~cmCPackCygwinSourceGenerator();
+
+protected:
+ const char* GetPackagingInstallPrefix();
+ virtual int InitializeInternal();
+ int PackageFiles();
+ virtual const char* GetOutputExtension();
+ std::string InstallPrefix;
+ std::string OutputExtension;
+};
+
+#endif
diff --git a/Source/CPack/cmCPackDebGenerator.cxx b/Source/CPack/cmCPackDebGenerator.cxx
new file mode 100644
index 0000000..3edc430
--- /dev/null
+++ b/Source/CPack/cmCPackDebGenerator.cxx
@@ -0,0 +1,952 @@
+/*============================================================================
+ CMake - Cross Platform Makefile Generator
+ Copyright 2000-2009 Kitware, Inc., Insight Software Consortium
+
+ Distributed under the OSI-approved BSD License (the "License");
+ see accompanying file Copyright.txt for details.
+
+ This software is distributed WITHOUT ANY WARRANTY; without even the
+ implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
+ See the License for more information.
+============================================================================*/
+
+#include "cmCPackDebGenerator.h"
+
+#include "cmArchiveWrite.h"
+#include "cmCPackLog.h"
+#include "cmGeneratedFileStream.h"
+#include "cmMakefile.h"
+#include "cmSystemTools.h"
+
+#include <cmsys/Glob.hxx>
+#include <cmsys/SystemTools.hxx>
+
+#include <limits.h> // USHRT_MAX
+#include <sys/stat.h>
+
+// NOTE:
+// A debian package .deb is simply an 'ar' archive. The only subtle difference
+// is that debian uses the BSD ar style archive whereas most Linux distro have
+// a GNU ar.
+// See http://bugs.debian.org/cgi-bin/bugreport.cgi?bug=161593 for more info
+// Therefore we provide our own implementation of a BSD-ar:
+static int ar_append(const char* archive,
+ const std::vector<std::string>& files);
+
+cmCPackDebGenerator::cmCPackDebGenerator()
+{
+}
+
+cmCPackDebGenerator::~cmCPackDebGenerator()
+{
+}
+
+int cmCPackDebGenerator::InitializeInternal()
+{
+ this->SetOptionIfNotSet("CPACK_PACKAGING_INSTALL_PREFIX", "/usr");
+ if (cmSystemTools::IsOff(this->GetOption("CPACK_SET_DESTDIR"))) {
+ this->SetOption("CPACK_SET_DESTDIR", "I_ON");
+ }
+ return this->Superclass::InitializeInternal();
+}
+
+int cmCPackDebGenerator::PackageOnePack(std::string const& initialTopLevel,
+ std::string const& packageName)
+{
+ int retval = 1;
+ // Begin the archive for this pack
+ std::string localToplevel(initialTopLevel);
+ std::string packageFileName(cmSystemTools::GetParentDirectory(toplevel));
+ std::string outputFileName(
+ std::string(this->GetOption("CPACK_PACKAGE_FILE_NAME")) + "-" +
+ packageName + this->GetOutputExtension());
+
+ localToplevel += "/" + packageName;
+ /* 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 CPackDeb.cmake the name of the component GROUP.
+ this->SetOption("CPACK_DEB_PACKAGE_COMPONENT", packageName.c_str());
+ // Tell CPackDeb.cmake the path where the component is.
+ std::string component_path = "/";
+ component_path += packageName;
+ this->SetOption("CPACK_DEB_PACKAGE_COMPONENT_PART_PATH",
+ component_path.c_str());
+ if (!this->ReadListFile("CPackDeb.cmake")) {
+ cmCPackLogger(cmCPackLog::LOG_ERROR, "Error while execution CPackDeb.cmake"
+ << std::endl);
+ retval = 0;
+ return retval;
+ }
+
+ cmsys::Glob gl;
+ std::string findExpr(this->GetOption("GEN_WDIR"));
+ findExpr += "/*";
+ 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;
+ }
+ packageFiles = gl.GetFiles();
+
+ int res = createDeb();
+ if (res != 1) {
+ retval = 0;
+ }
+ // add the generated package to package file names list
+ packageFileName = this->GetOption("CPACK_TOPLEVEL_DIRECTORY");
+ packageFileName += "/";
+ packageFileName += this->GetOption("GEN_CPACK_OUTPUT_FILE_NAME");
+ packageFileNames.push_back(packageFileName);
+ return retval;
+}
+
+int cmCPackDebGenerator::PackageComponents(bool ignoreGroup)
+{
+ int retval = 1;
+ /* Reset package file name list it will be populated during the
+ * component packaging run*/
+ packageFileNames.clear();
+ std::string initialTopLevel(this->GetOption("CPACK_TEMPORARY_DIRECTORY"));
+
+ // The default behavior is to have one package by component group
+ // unless CPACK_COMPONENTS_IGNORE_GROUP is specified.
+ if (!ignoreGroup) {
+ std::map<std::string, cmCPackComponentGroup>::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
+ retval &= PackageOnePack(initialTopLevel, compGIt->first);
+ }
+ // Handle Orphan components (components not belonging to any groups)
+ std::map<std::string, cmCPackComponent>::iterator compIt;
+ for (compIt = this->Components.begin(); compIt != this->Components.end();
+ ++compIt) {
+ // Does the component belong to a group?
+ if (compIt->second.Group == CM_NULLPTR) {
+ cmCPackLogger(
+ cmCPackLog::LOG_VERBOSE, "Component <"
+ << compIt->second.Name
+ << "> does not belong to any group, package it separately."
+ << std::endl);
+ // Begin the archive for this orphan component
+ retval &= PackageOnePack(initialTopLevel, compIt->first);
+ }
+ }
+ }
+ // CPACK_COMPONENTS_IGNORE_GROUPS is set
+ // We build 1 package per component
+ else {
+ std::map<std::string, cmCPackComponent>::iterator compIt;
+ for (compIt = this->Components.begin(); compIt != this->Components.end();
+ ++compIt) {
+ retval &= PackageOnePack(initialTopLevel, compIt->first);
+ }
+ }
+ return retval;
+}
+
+//----------------------------------------------------------------------
+int cmCPackDebGenerator::PackageComponentsAllInOne(
+ const std::string& compInstDirName)
+{
+ int retval = 1;
+ /* Reset package file name list it will be populated during the
+ * component packaging run*/
+ packageFileNames.clear();
+ std::string initialTopLevel(this->GetOption("CPACK_TEMPORARY_DIRECTORY"));
+
+ 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));
+ std::string outputFileName(
+ std::string(this->GetOption("CPACK_PACKAGE_FILE_NAME")) +
+ 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());
+
+ if (!compInstDirName.empty()) {
+ // Tell CPackDeb.cmake the path where the component is.
+ std::string component_path = "/";
+ component_path += compInstDirName;
+ this->SetOption("CPACK_DEB_PACKAGE_COMPONENT_PART_PATH",
+ component_path.c_str());
+ }
+ if (!this->ReadListFile("CPackDeb.cmake")) {
+ cmCPackLogger(cmCPackLog::LOG_ERROR, "Error while execution CPackDeb.cmake"
+ << std::endl);
+ retval = 0;
+ return retval;
+ }
+
+ cmsys::Glob gl;
+ std::string findExpr(this->GetOption("GEN_WDIR"));
+ findExpr += "/*";
+ 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;
+ }
+ packageFiles = gl.GetFiles();
+
+ int res = createDeb();
+ if (res != 1) {
+ retval = 0;
+ }
+ // add the generated package to package file names list
+ packageFileName = this->GetOption("CPACK_TOPLEVEL_DIRECTORY");
+ packageFileName += "/";
+ packageFileName += this->GetOption("GEN_CPACK_OUTPUT_FILE_NAME");
+ packageFileNames.push_back(packageFileName);
+ return retval;
+}
+
+int cmCPackDebGenerator::PackageFiles()
+{
+ /* Are we in the component packaging case */
+ if (WantsComponentInstallation()) {
+ // 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 (componentPackageMethod == ONE_PACKAGE) {
+ return PackageComponentsAllInOne("ALL_COMPONENTS_IN_ONE");
+ }
+ // 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 {
+ return PackageComponents(componentPackageMethod ==
+ ONE_PACKAGE_PER_COMPONENT);
+ }
+ }
+ // CASE 3 : NON COMPONENT package.
+ else {
+ return PackageComponentsAllInOne("");
+ }
+}
+
+int cmCPackDebGenerator::createDeb()
+{
+ // debian-binary file
+ const std::string strGenWDIR(this->GetOption("GEN_WDIR"));
+ const std::string dbfilename = strGenWDIR + "/debian-binary";
+ { // the scope is needed for cmGeneratedFileStream
+ cmGeneratedFileStream out(dbfilename.c_str());
+ out << "2.0";
+ out << std::endl; // required for valid debian package
+ }
+
+ // control file
+ std::string ctlfilename = strGenWDIR + "/control";
+
+ // debian policy enforce lower case for package name
+ // mandatory entries:
+ std::string debian_pkg_name = cmsys::SystemTools::LowerCase(
+ this->GetOption("GEN_CPACK_DEBIAN_PACKAGE_NAME"));
+ const char* debian_pkg_version =
+ this->GetOption("GEN_CPACK_DEBIAN_PACKAGE_VERSION");
+ const char* debian_pkg_section =
+ this->GetOption("GEN_CPACK_DEBIAN_PACKAGE_SECTION");
+ const char* debian_pkg_priority =
+ this->GetOption("GEN_CPACK_DEBIAN_PACKAGE_PRIORITY");
+ const char* debian_pkg_arch =
+ this->GetOption("GEN_CPACK_DEBIAN_PACKAGE_ARCHITECTURE");
+ const char* maintainer =
+ this->GetOption("GEN_CPACK_DEBIAN_PACKAGE_MAINTAINER");
+ const char* desc = this->GetOption("GEN_CPACK_DEBIAN_PACKAGE_DESCRIPTION");
+
+ // optional entries
+ const char* debian_pkg_dep =
+ this->GetOption("GEN_CPACK_DEBIAN_PACKAGE_DEPENDS");
+ const char* debian_pkg_rec =
+ this->GetOption("GEN_CPACK_DEBIAN_PACKAGE_RECOMMENDS");
+ const char* debian_pkg_sug =
+ this->GetOption("GEN_CPACK_DEBIAN_PACKAGE_SUGGESTS");
+ const char* debian_pkg_url =
+ this->GetOption("GEN_CPACK_DEBIAN_PACKAGE_HOMEPAGE");
+ const char* debian_pkg_predep =
+ this->GetOption("GEN_CPACK_DEBIAN_PACKAGE_PREDEPENDS");
+ const char* debian_pkg_enhances =
+ this->GetOption("GEN_CPACK_DEBIAN_PACKAGE_ENHANCES");
+ const char* debian_pkg_breaks =
+ this->GetOption("GEN_CPACK_DEBIAN_PACKAGE_BREAKS");
+ const char* debian_pkg_conflicts =
+ this->GetOption("GEN_CPACK_DEBIAN_PACKAGE_CONFLICTS");
+ const char* debian_pkg_provides =
+ this->GetOption("GEN_CPACK_DEBIAN_PACKAGE_PROVIDES");
+ const char* debian_pkg_replaces =
+ this->GetOption("GEN_CPACK_DEBIAN_PACKAGE_REPLACES");
+ const char* debian_pkg_source =
+ this->GetOption("GEN_CPACK_DEBIAN_PACKAGE_SOURCE");
+
+ { // the scope is needed for cmGeneratedFileStream
+ cmGeneratedFileStream out(ctlfilename.c_str());
+ out << "Package: " << debian_pkg_name << "\n";
+ out << "Version: " << debian_pkg_version << "\n";
+ out << "Section: " << debian_pkg_section << "\n";
+ out << "Priority: " << debian_pkg_priority << "\n";
+ out << "Architecture: " << debian_pkg_arch << "\n";
+ if (debian_pkg_source && *debian_pkg_source) {
+ out << "Source: " << debian_pkg_source << "\n";
+ }
+ if (debian_pkg_dep && *debian_pkg_dep) {
+ out << "Depends: " << debian_pkg_dep << "\n";
+ }
+ if (debian_pkg_rec && *debian_pkg_rec) {
+ out << "Recommends: " << debian_pkg_rec << "\n";
+ }
+ if (debian_pkg_sug && *debian_pkg_sug) {
+ out << "Suggests: " << debian_pkg_sug << "\n";
+ }
+ if (debian_pkg_url && *debian_pkg_url) {
+ out << "Homepage: " << debian_pkg_url << "\n";
+ }
+ if (debian_pkg_predep && *debian_pkg_predep) {
+ out << "Pre-Depends: " << debian_pkg_predep << "\n";
+ }
+ if (debian_pkg_enhances && *debian_pkg_enhances) {
+ out << "Enhances: " << debian_pkg_enhances << "\n";
+ }
+ if (debian_pkg_breaks && *debian_pkg_breaks) {
+ out << "Breaks: " << debian_pkg_breaks << "\n";
+ }
+ if (debian_pkg_conflicts && *debian_pkg_conflicts) {
+ out << "Conflicts: " << debian_pkg_conflicts << "\n";
+ }
+ if (debian_pkg_provides && *debian_pkg_provides) {
+ out << "Provides: " << debian_pkg_provides << "\n";
+ }
+ if (debian_pkg_replaces && *debian_pkg_replaces) {
+ out << "Replaces: " << debian_pkg_replaces << "\n";
+ }
+ unsigned long totalSize = 0;
+ {
+ std::string dirName = this->GetOption("CPACK_TEMPORARY_DIRECTORY");
+ dirName += '/';
+ for (std::vector<std::string>::const_iterator fileIt =
+ packageFiles.begin();
+ fileIt != packageFiles.end(); ++fileIt) {
+ totalSize += cmSystemTools::FileLength(*fileIt);
+ }
+ }
+ out << "Installed-Size: " << (totalSize + 1023) / 1024 << "\n";
+ out << "Maintainer: " << maintainer << "\n";
+ out << "Description: " << desc << "\n";
+ out << std::endl;
+ }
+
+ const std::string shlibsfilename = strGenWDIR + "/shlibs";
+
+ const char* debian_pkg_shlibs =
+ this->GetOption("GEN_CPACK_DEBIAN_PACKAGE_SHLIBS");
+ const bool gen_shibs = this->IsOn("CPACK_DEBIAN_PACKAGE_GENERATE_SHLIBS") &&
+ debian_pkg_shlibs && *debian_pkg_shlibs;
+ if (gen_shibs) {
+ cmGeneratedFileStream out(shlibsfilename.c_str());
+ out << debian_pkg_shlibs;
+ out << std::endl;
+ }
+
+ const std::string postinst = strGenWDIR + "/postinst";
+ const std::string postrm = strGenWDIR + "/postrm";
+ if (this->IsOn("GEN_CPACK_DEBIAN_GENERATE_POSTINST")) {
+ cmGeneratedFileStream out(postinst.c_str());
+ out << "#!/bin/sh\n\n"
+ "set -e\n\n"
+ "if [ \"$1\" = \"configure\" ]; then\n"
+ "\tldconfig\n"
+ "fi\n";
+ }
+ if (this->IsOn("GEN_CPACK_DEBIAN_GENERATE_POSTRM")) {
+ cmGeneratedFileStream out(postrm.c_str());
+ out << "#!/bin/sh\n\n"
+ "set -e\n\n"
+ "if [ \"$1\" = \"remove\" ]; then\n"
+ "\tldconfig\n"
+ "fi\n";
+ }
+
+ cmArchiveWrite::Compress tar_compression_type = cmArchiveWrite::CompressGZip;
+ const char* debian_compression_type =
+ this->GetOption("GEN_CPACK_DEBIAN_COMPRESSION_TYPE");
+ if (!debian_compression_type) {
+ debian_compression_type = "gzip";
+ }
+
+ std::string compression_suffix;
+ if (!strcmp(debian_compression_type, "lzma")) {
+ compression_suffix = ".lzma";
+ tar_compression_type = cmArchiveWrite::CompressLZMA;
+ } else if (!strcmp(debian_compression_type, "xz")) {
+ compression_suffix = ".xz";
+ tar_compression_type = cmArchiveWrite::CompressXZ;
+ } else if (!strcmp(debian_compression_type, "bzip2")) {
+ compression_suffix = ".bz2";
+ tar_compression_type = cmArchiveWrite::CompressBZip2;
+ } else if (!strcmp(debian_compression_type, "gzip")) {
+ compression_suffix = ".gz";
+ tar_compression_type = cmArchiveWrite::CompressGZip;
+ } else if (!strcmp(debian_compression_type, "none")) {
+ compression_suffix = "";
+ tar_compression_type = cmArchiveWrite::CompressNone;
+ } else {
+ cmCPackLogger(cmCPackLog::LOG_ERROR,
+ "Error unrecognized compression type: "
+ << debian_compression_type << std::endl);
+ }
+
+ std::string filename_data_tar =
+ strGenWDIR + "/data.tar" + compression_suffix;
+
+ // atomic file generation for data.tar
+ {
+ cmGeneratedFileStream fileStream_data_tar;
+ fileStream_data_tar.Open(filename_data_tar.c_str(), false, true);
+ if (!fileStream_data_tar) {
+ cmCPackLogger(cmCPackLog::LOG_ERROR, "Error opening the file \""
+ << filename_data_tar << "\" for writing" << std::endl);
+ return 0;
+ }
+ cmArchiveWrite data_tar(fileStream_data_tar, tar_compression_type, "paxr");
+
+ // uid/gid should be the one of the root user, and this root user has
+ // always uid/gid equal to 0.
+ data_tar.SetUIDAndGID(0u, 0u);
+ data_tar.SetUNAMEAndGNAME("root", "root");
+
+ // now add all directories which have to be compressed
+ // collect all top level install dirs for that
+ // e.g. /opt/bin/foo, /usr/bin/bar and /usr/bin/baz would
+ // give /usr and /opt
+ size_t topLevelLength = strGenWDIR.length();
+ cmCPackLogger(cmCPackLog::LOG_DEBUG, "WDIR: \""
+ << strGenWDIR << "\", length = " << topLevelLength
+ << std::endl);
+ std::set<std::string> orderedFiles;
+
+ // we have to reconstruct the parent folders as well
+
+ for (std::vector<std::string>::const_iterator fileIt =
+ packageFiles.begin();
+ fileIt != packageFiles.end(); ++fileIt) {
+ std::string currentPath = *fileIt;
+ while (currentPath != strGenWDIR) {
+ // the last one IS strGenWDIR, but we do not want this one:
+ // XXX/application/usr/bin/myprogram with GEN_WDIR=XXX/application
+ // should not add XXX/application
+ orderedFiles.insert(currentPath);
+ currentPath = cmSystemTools::CollapseCombinedPath(currentPath, "..");
+ }
+ }
+
+ for (std::set<std::string>::const_iterator fileIt = orderedFiles.begin();
+ fileIt != orderedFiles.end(); ++fileIt) {
+ cmCPackLogger(cmCPackLog::LOG_DEBUG, "FILEIT: \"" << *fileIt << "\""
+ << std::endl);
+ std::string::size_type slashPos = fileIt->find('/', topLevelLength + 1);
+ std::string relativeDir =
+ fileIt->substr(topLevelLength, slashPos - topLevelLength);
+ cmCPackLogger(cmCPackLog::LOG_DEBUG, "RELATIVEDIR: \""
+ << relativeDir << "\"" << std::endl);
+
+ // do not recurse because the loop will do it
+ if (!data_tar.Add(*fileIt, topLevelLength, ".", false)) {
+ cmCPackLogger(cmCPackLog::LOG_ERROR, "Problem adding file to tar:"
+ << std::endl
+ << "#top level directory: " << strGenWDIR << std::endl
+ << "#file: " << *fileIt << std::endl
+ << "#error:" << data_tar.GetError() << std::endl);
+ return 0;
+ }
+ }
+ } // scope for file generation
+
+ std::string md5filename = strGenWDIR + "/md5sums";
+ {
+ // the scope is needed for cmGeneratedFileStream
+ cmGeneratedFileStream out(md5filename.c_str());
+
+ std::string topLevelWithTrailingSlash =
+ this->GetOption("CPACK_TEMPORARY_DIRECTORY");
+ topLevelWithTrailingSlash += '/';
+ for (std::vector<std::string>::const_iterator fileIt =
+ packageFiles.begin();
+ fileIt != packageFiles.end(); ++fileIt) {
+ // hash only regular files
+ if (cmSystemTools::FileIsDirectory(*fileIt) ||
+ cmSystemTools::FileIsSymlink(*fileIt)) {
+ continue;
+ }
+
+ char md5sum[33];
+ if (!cmSystemTools::ComputeFileMD5(*fileIt, md5sum)) {
+ cmCPackLogger(cmCPackLog::LOG_ERROR, "Problem computing the md5 of "
+ << *fileIt << std::endl);
+ }
+
+ md5sum[32] = 0;
+
+ std::string output(md5sum);
+ output += " " + *fileIt + "\n";
+ // debian md5sums entries are like this:
+ // 014f3604694729f3bf19263bac599765 usr/bin/ccmake
+ // thus strip the full path (with the trailing slash)
+ cmSystemTools::ReplaceString(output, topLevelWithTrailingSlash.c_str(),
+ "");
+ out << output;
+ }
+ // each line contains a eol.
+ // Do not end the md5sum file with yet another (invalid)
+ }
+
+ std::string filename_control_tar = strGenWDIR + "/control.tar.gz";
+ // atomic file generation for control.tar
+ {
+ cmGeneratedFileStream fileStream_control_tar;
+ fileStream_control_tar.Open(filename_control_tar.c_str(), false, true);
+ if (!fileStream_control_tar) {
+ cmCPackLogger(cmCPackLog::LOG_ERROR, "Error opening the file \""
+ << filename_control_tar << "\" for writing"
+ << std::endl);
+ return 0;
+ }
+ cmArchiveWrite control_tar(fileStream_control_tar,
+ cmArchiveWrite::CompressGZip, "paxr");
+
+ // sets permissions and uid/gid for the files
+ control_tar.SetUIDAndGID(0u, 0u);
+ control_tar.SetUNAMEAndGNAME("root", "root");
+
+ /* permissions are set according to
+ https://www.debian.org/doc/debian-policy/ch-files.html#s-permissions-owners
+ and
+ https://lintian.debian.org/tags/control-file-has-bad-permissions.html
+ */
+ const mode_t permission644 = S_IRUSR | S_IWUSR | S_IRGRP | S_IROTH;
+ const mode_t permissionExecute = S_IXUSR | S_IXGRP | S_IXOTH;
+ const mode_t permission755 = permission644 | permissionExecute;
+
+ // for md5sum and control (that we have generated here), we use 644
+ // (RW-R--R--)
+ // so that deb lintian doesn't warn about it
+ control_tar.SetPermissions(permission644);
+
+ // adds control and md5sums
+ if (!control_tar.Add(md5filename, strGenWDIR.length(), ".") ||
+ !control_tar.Add(strGenWDIR + "/control", strGenWDIR.length(), ".")) {
+ cmCPackLogger(cmCPackLog::LOG_ERROR, "Error adding file to tar:"
+ << std::endl
+ << "#top level directory: " << strGenWDIR << std::endl
+ << "#file: \"control\" or \"md5sums\"" << std::endl
+ << "#error:" << control_tar.GetError() << std::endl);
+ return 0;
+ }
+
+ // adds generated shlibs file
+ if (gen_shibs) {
+ if (!control_tar.Add(shlibsfilename, strGenWDIR.length(), ".")) {
+ cmCPackLogger(cmCPackLog::LOG_ERROR, "Error adding file to tar:"
+ << std::endl
+ << "#top level directory: " << strGenWDIR << std::endl
+ << "#file: \"shlibs\"" << std::endl
+ << "#error:" << control_tar.GetError() << std::endl);
+ return 0;
+ }
+ }
+
+ // adds LDCONFIG related files
+ if (this->IsOn("GEN_CPACK_DEBIAN_GENERATE_POSTINST")) {
+ control_tar.SetPermissions(permission755);
+ if (!control_tar.Add(postinst, strGenWDIR.length(), ".")) {
+ cmCPackLogger(cmCPackLog::LOG_ERROR, "Error adding file to tar:"
+ << std::endl
+ << "#top level directory: " << strGenWDIR << std::endl
+ << "#file: \"postinst\"" << std::endl
+ << "#error:" << control_tar.GetError() << std::endl);
+ return 0;
+ }
+ control_tar.SetPermissions(permission644);
+ }
+
+ if (this->IsOn("GEN_CPACK_DEBIAN_GENERATE_POSTRM")) {
+ control_tar.SetPermissions(permission755);
+ if (!control_tar.Add(postrm, strGenWDIR.length(), ".")) {
+ cmCPackLogger(cmCPackLog::LOG_ERROR, "Error adding file to tar:"
+ << std::endl
+ << "#top level directory: " << strGenWDIR << std::endl
+ << "#file: \"postinst\"" << std::endl
+ << "#error:" << control_tar.GetError() << std::endl);
+ return 0;
+ }
+ control_tar.SetPermissions(permission644);
+ }
+
+ // for the other files, we use
+ // -either the original permission on the files
+ // -either a permission strictly defined by the Debian policies
+ const char* controlExtra =
+ this->GetOption("GEN_CPACK_DEBIAN_PACKAGE_CONTROL_EXTRA");
+ if (controlExtra) {
+ // permissions are now controlled by the original file permissions
+
+ const bool permissionStrictPolicy =
+ this->IsSet("GEN_CPACK_DEBIAN_PACKAGE_CONTROL_STRICT_PERMISSION");
+
+ static const char* strictFiles[] = { "config", "postinst", "postrm",
+ "preinst", "prerm" };
+ std::set<std::string> setStrictFiles(
+ strictFiles,
+ strictFiles + sizeof(strictFiles) / sizeof(strictFiles[0]));
+
+ // default
+ control_tar.ClearPermissions();
+
+ std::vector<std::string> controlExtraList;
+ cmSystemTools::ExpandListArgument(controlExtra, controlExtraList);
+ for (std::vector<std::string>::iterator i = controlExtraList.begin();
+ i != controlExtraList.end(); ++i) {
+ std::string filenamename = cmsys::SystemTools::GetFilenameName(*i);
+ std::string localcopy = strGenWDIR + "/" + filenamename;
+
+ if (permissionStrictPolicy) {
+ control_tar.SetPermissions(setStrictFiles.count(filenamename)
+ ? permission755
+ : permission644);
+ }
+
+ // if we can copy the file, it means it does exist, let's add it:
+ if (cmsys::SystemTools::CopyFileIfDifferent(*i, localcopy)) {
+ control_tar.Add(localcopy, strGenWDIR.length(), ".");
+ }
+ }
+ }
+ }
+
+ // ar -r your-package-name.deb debian-binary control.tar.* data.tar.*
+ // since debian packages require BSD ar (most Linux distros and even
+ // FreeBSD and NetBSD ship GNU ar) we use a copy of OpenBSD ar here.
+ std::vector<std::string> arFiles;
+ std::string topLevelString = strGenWDIR + "/";
+ arFiles.push_back(topLevelString + "debian-binary");
+ arFiles.push_back(topLevelString + "control.tar.gz");
+ arFiles.push_back(topLevelString + "data.tar" + compression_suffix);
+ std::string outputFileName = this->GetOption("CPACK_TOPLEVEL_DIRECTORY");
+ outputFileName += "/";
+ outputFileName += this->GetOption("GEN_CPACK_OUTPUT_FILE_NAME");
+ int res = ar_append(outputFileName.c_str(), arFiles);
+ if (res != 0) {
+ std::string tmpFile =
+ this->GetOption("GEN_CPACK_TEMPORARY_PACKAGE_FILE_NAME");
+ tmpFile += "/Deb.log";
+ cmGeneratedFileStream ofs(tmpFile.c_str());
+ ofs << "# Problem creating archive using: " << res << std::endl;
+ return 0;
+ }
+ return 1;
+}
+
+bool cmCPackDebGenerator::SupportsComponentInstallation() const
+{
+ return IsOn("CPACK_DEB_COMPONENT_INSTALL");
+}
+
+std::string cmCPackDebGenerator::GetComponentInstallDirNameSuffix(
+ const std::string& componentName)
+{
+ if (componentPackageMethod == ONE_PACKAGE_PER_COMPONENT) {
+ return componentName;
+ }
+
+ if (componentPackageMethod == ONE_PACKAGE) {
+ 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 (CM_NULLPTR != GetOption(groupVar)) {
+ return std::string(GetOption(groupVar));
+ } else {
+ return componentName;
+ }
+}
+
+// The following code is taken from OpenBSD ar:
+// http://www.openbsd.org/cgi-bin/cvsweb/src/usr.bin/ar/
+// It has been slightly modified:
+// -return error codes instead exit() in functions
+// -use the stdio file I/O functions instead the file descriptor based ones
+// -merged into one cxx file
+// -no additional options supported
+// The coding style hasn't been modified.
+
+/*-
+ * Copyright (c) 1990, 1993, 1994
+ * The Regents of the University of California. All rights reserved.
+ *
+ * This code is derived from software contributed to Berkeley by
+ * Hugh Smith at The University of Guelph.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * 3. Neither the name of the University nor the names of its contributors
+ * may be used to endorse or promote products derived from this software
+ * without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ */
+
+#include <sys/types.h>
+// include sys/stat.h after sys/types.h
+#include <sys/stat.h>
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+
+#define ARMAG "!<arch>\n" /* ar "magic number" */
+#define SARMAG 8 /* strlen(ARMAG); */
+
+#define AR_EFMT1 "#1/" /* extended format #1 */
+#define ARFMAG "`\n"
+
+/* Header format strings. */
+#define HDR1 "%s%-13d%-12ld%-6u%-6u%-8o%-10lld%2s"
+#define HDR2 "%-16.16s%-12ld%-6u%-6u%-8o%-10lld%2s"
+
+struct ar_hdr
+{
+ char ar_name[16]; /* name */
+ char ar_date[12]; /* modification time */
+ char ar_uid[6]; /* user id */
+ char ar_gid[6]; /* group id */
+ char ar_mode[8]; /* octal file permissions */
+ char ar_size[10]; /* size in bytes */
+ char ar_fmag[2]; /* consistency check */
+};
+
+/* Set up file copy. */
+#define SETCF(from, fromname, to, toname, pad) \
+ { \
+ cf.rFile = from; \
+ cf.rname = fromname; \
+ cf.wFile = to; \
+ cf.wname = toname; \
+ cf.flags = pad; \
+ }
+
+/* File copy structure. */
+typedef struct
+{
+ FILE* rFile; /* read file descriptor */
+ const char* rname; /* read name */
+ FILE* wFile; /* write file descriptor */
+ const char* wname; /* write name */
+#define NOPAD 0x00 /* don't pad */
+#define WPAD 0x02 /* pad on writes */
+ unsigned int flags; /* pad flags */
+} CF;
+
+/* misc.c */
+
+static const char* ar_rname(const char* path)
+{
+ const char* ind = strrchr(path, '/');
+ return (ind) ? ind + 1 : path;
+}
+
+/* archive.c */
+
+typedef struct ar_hdr HDR;
+static char ar_hb[sizeof(HDR) + 1]; /* real header */
+
+static size_t ar_already_written;
+
+/* copy_ar --
+ * Copy size bytes from one file to another - taking care to handle the
+ * extra byte (for odd size files) when reading archives and writing an
+ * extra byte if necessary when adding files to archive. The length of
+ * the object is the long name plus the object itself; the variable
+ * already_written gets set if a long name was written.
+ *
+ * The padding is really unnecessary, and is almost certainly a remnant
+ * of early archive formats where the header included binary data which
+ * a PDP-11 required to start on an even byte boundary. (Or, perhaps,
+ * because 16-bit word addressed copies were faster?) Anyhow, it should
+ * have been ripped out long ago.
+ */
+static int copy_ar(CF* cfp, off_t size)
+{
+ static char pad = '\n';
+ off_t sz = size;
+ size_t nr, nw;
+ char buf[8 * 1024];
+
+ if (sz == 0) {
+ return 0;
+ }
+
+ FILE* from = cfp->rFile;
+ FILE* to = cfp->wFile;
+ while (sz &&
+ (nr = fread(buf, 1, sz < static_cast<off_t>(sizeof(buf))
+ ? static_cast<size_t>(sz)
+ : sizeof(buf),
+ from)) > 0) {
+ sz -= nr;
+ for (size_t off = 0; off < nr; nr -= off, off += nw) {
+ if ((nw = fwrite(buf + off, 1, nr, to)) < nr) {
+ return -1;
+ }
+ }
+ }
+ if (sz) {
+ return -2;
+ }
+
+ if (cfp->flags & WPAD && (size + ar_already_written) & 1 &&
+ fwrite(&pad, 1, 1, to) != 1) {
+ return -4;
+ }
+
+ return 0;
+}
+
+/* put_arobj -- Write an archive member to a file. */
+static int put_arobj(CF* cfp, struct stat* sb)
+{
+ int result = 0;
+ struct ar_hdr* hdr;
+
+ /* If passed an sb structure, reading a file from disk. Get stat(2)
+ * information, build a name and construct a header. (Files are named
+ * by their last component in the archive.) */
+ const char* name = ar_rname(cfp->rname);
+ (void)stat(cfp->rname, sb);
+
+ /* If not truncating names and the name is too long or contains
+ * a space, use extended format 1. */
+ size_t lname = strlen(name);
+ uid_t uid = sb->st_uid;
+ gid_t gid = sb->st_gid;
+ if (uid > USHRT_MAX) {
+ uid = USHRT_MAX;
+ }
+ if (gid > USHRT_MAX) {
+ gid = USHRT_MAX;
+ }
+ if (lname > sizeof(hdr->ar_name) || strchr(name, ' ')) {
+ (void)sprintf(ar_hb, HDR1, AR_EFMT1, (int)lname, (long int)sb->st_mtime,
+ (unsigned)uid, (unsigned)gid, (unsigned)sb->st_mode,
+ (long long)sb->st_size + lname, ARFMAG);
+ } else {
+ lname = 0;
+ (void)sprintf(ar_hb, HDR2, name, (long int)sb->st_mtime, (unsigned)uid,
+ (unsigned)gid, (unsigned)sb->st_mode, (long long)sb->st_size,
+ ARFMAG);
+ }
+ off_t size = sb->st_size;
+
+ if (fwrite(ar_hb, 1, sizeof(HDR), cfp->wFile) != sizeof(HDR)) {
+ return -1;
+ }
+
+ if (lname) {
+ if (fwrite(name, 1, lname, cfp->wFile) != lname) {
+ return -2;
+ }
+ ar_already_written = lname;
+ }
+ result = copy_ar(cfp, size);
+ ar_already_written = 0;
+ return result;
+}
+
+/* append.c */
+
+/* append --
+ * Append files to the archive - modifies original archive or creates
+ * a new archive if named archive does not exist.
+ */
+static int ar_append(const char* archive,
+ const std::vector<std::string>& files)
+{
+ int eval = 0;
+ FILE* aFile = cmSystemTools::Fopen(archive, "wb+");
+ if (aFile != CM_NULLPTR) {
+ fwrite(ARMAG, SARMAG, 1, aFile);
+ if (fseek(aFile, 0, SEEK_END) != -1) {
+ CF cf;
+ struct stat sb;
+ /* Read from disk, write to an archive; pad on write. */
+ SETCF(CM_NULLPTR, CM_NULLPTR, aFile, archive, WPAD);
+ for (std::vector<std::string>::const_iterator fileIt = files.begin();
+ fileIt != files.end(); ++fileIt) {
+ const char* filename = fileIt->c_str();
+ FILE* file = cmSystemTools::Fopen(filename, "rb");
+ if (file == CM_NULLPTR) {
+ eval = -1;
+ continue;
+ }
+ cf.rFile = file;
+ cf.rname = filename;
+ int result = put_arobj(&cf, &sb);
+ (void)fclose(file);
+ if (result != 0) {
+ eval = -2;
+ break;
+ }
+ }
+ } else {
+ eval = -3;
+ }
+ fclose(aFile);
+ } else {
+ eval = -4;
+ }
+ return eval;
+}
diff --git a/Source/CPack/cmCPackDebGenerator.h b/Source/CPack/cmCPackDebGenerator.h
new file mode 100644
index 0000000..bcdc509
--- /dev/null
+++ b/Source/CPack/cmCPackDebGenerator.h
@@ -0,0 +1,76 @@
+/*============================================================================
+ CMake - Cross Platform Makefile Generator
+ Copyright 2000-2009 Kitware, Inc.
+
+ Distributed under the OSI-approved BSD License (the "License");
+ see accompanying file Copyright.txt for details.
+
+ This software is distributed WITHOUT ANY WARRANTY; without even the
+ implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
+ See the License for more information.
+============================================================================*/
+
+#ifndef cmCPackDebGenerator_h
+#define cmCPackDebGenerator_h
+
+#include "cmCPackGenerator.h"
+
+/** \class cmCPackDebGenerator
+ * \brief A generator for Debian packages
+ *
+ */
+class cmCPackDebGenerator : public cmCPackGenerator
+{
+public:
+ cmCPackTypeMacro(cmCPackDebGenerator, cmCPackGenerator);
+
+ /**
+ * Construct generator
+ */
+ cmCPackDebGenerator();
+ ~cmCPackDebGenerator() CM_OVERRIDE;
+
+ static bool CanGenerate()
+ {
+#ifdef __APPLE__
+ // on MacOS enable CPackDeb iff dpkg is found
+ std::vector<std::string> locations;
+ locations.push_back("/sw/bin"); // Fink
+ locations.push_back("/opt/local/bin"); // MacPorts
+ return cmSystemTools::FindProgram("dpkg", locations) != "" ? true : false;
+#else
+ // legacy behavior on other systems
+ return true;
+#endif
+ }
+
+protected:
+ int InitializeInternal() CM_OVERRIDE;
+ /**
+ * This method factors out the work done in component packaging case.
+ */
+ int PackageOnePack(std::string const& initialToplevel,
+ std::string const& packageName);
+ /**
+ * 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(const std::string& compInstDirName);
+ int PackageFiles() CM_OVERRIDE;
+ const char* GetOutputExtension() CM_OVERRIDE { return ".deb"; }
+ bool SupportsComponentInstallation() const CM_OVERRIDE;
+ std::string GetComponentInstallDirNameSuffix(
+ const std::string& componentName) CM_OVERRIDE;
+
+private:
+ int createDeb();
+ std::vector<std::string> packageFiles;
+};
+
+#endif
diff --git a/Source/CPack/cmCPackDragNDropGenerator.cxx b/Source/CPack/cmCPackDragNDropGenerator.cxx
new file mode 100644
index 0000000..640e437
--- /dev/null
+++ b/Source/CPack/cmCPackDragNDropGenerator.cxx
@@ -0,0 +1,898 @@
+/*============================================================================
+ CMake - Cross Platform Makefile Generator
+ Copyright 2000-2009 Kitware, Inc., Insight Software Consortium
+
+ Distributed under the OSI-approved BSD License (the "License");
+ see accompanying file Copyright.txt for details.
+
+ This software is distributed WITHOUT ANY WARRANTY; without even the
+ implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
+ See the License for more information.
+============================================================================*/
+
+#include "cmCPackDragNDropGenerator.h"
+
+#include "cmCPackLog.h"
+#include "cmGeneratedFileStream.h"
+#include "cmSystemTools.h"
+
+#include <cmsys/FStream.hxx>
+#include <cmsys/RegularExpression.hxx>
+
+#include <iomanip>
+
+#include <CoreFoundation/CoreFoundation.h>
+
+#ifdef HAVE_CoreServices
+// For the old LocaleStringToLangAndRegionCodes() function, to convert
+// to the old Script Manager RegionCode values needed for the 'LPic' data
+// structure used for generating multi-lingual SLAs.
+#include <CoreServices/CoreServices.h>
+#endif
+
+static const char* SLAHeader =
+ "data 'LPic' (5000) {\n"
+ " $\"0002 0011 0003 0001 0000 0000 0002 0000\"\n"
+ " $\"0008 0003 0000 0001 0004 0000 0004 0005\"\n"
+ " $\"0000 000E 0006 0001 0005 0007 0000 0007\"\n"
+ " $\"0008 0000 0047 0009 0000 0034 000A 0001\"\n"
+ " $\"0035 000B 0001 0020 000C 0000 0011 000D\"\n"
+ " $\"0000 005B 0004 0000 0033 000F 0001 000C\"\n"
+ " $\"0010 0000 000B 000E 0000\"\n"
+ "};\n"
+ "\n";
+
+static const char* SLASTREnglish =
+ "resource 'STR#' (5002, \"English\") {\n"
+ " {\n"
+ " \"English\",\n"
+ " \"Agree\",\n"
+ " \"Disagree\",\n"
+ " \"Print\",\n"
+ " \"Save...\",\n"
+ " \"You agree to the License Agreement terms when you click \"\n"
+ " \"the \\\"Agree\\\" button.\",\n"
+ " \"Software License Agreement\",\n"
+ " \"This text cannot be saved. This disk may be full or locked, "
+ "or the \"\n"
+ " \"file may be locked.\",\n"
+ " \"Unable to print. Make sure you have selected a printer.\"\n"
+ " }\n"
+ "};\n"
+ "\n";
+
+cmCPackDragNDropGenerator::cmCPackDragNDropGenerator()
+ : singleLicense(false)
+{
+ // default to one package file for components
+ this->componentPackageMethod = ONE_PACKAGE;
+}
+
+cmCPackDragNDropGenerator::~cmCPackDragNDropGenerator()
+{
+}
+
+int cmCPackDragNDropGenerator::InitializeInternal()
+{
+ // Starting with Xcode 4.3, look in "/Applications/Xcode.app" first:
+ //
+ std::vector<std::string> paths;
+ paths.push_back("/Applications/Xcode.app/Contents/Developer/Tools");
+ paths.push_back("/Developer/Tools");
+
+ const std::string hdiutil_path =
+ cmSystemTools::FindProgram("hdiutil", std::vector<std::string>(), false);
+ if (hdiutil_path.empty()) {
+ cmCPackLogger(cmCPackLog::LOG_ERROR, "Cannot locate hdiutil command"
+ << std::endl);
+ return 0;
+ }
+ this->SetOptionIfNotSet("CPACK_COMMAND_HDIUTIL", hdiutil_path.c_str());
+
+ const std::string setfile_path =
+ cmSystemTools::FindProgram("SetFile", paths, false);
+ if (setfile_path.empty()) {
+ cmCPackLogger(cmCPackLog::LOG_ERROR, "Cannot locate SetFile command"
+ << std::endl);
+ return 0;
+ }
+ this->SetOptionIfNotSet("CPACK_COMMAND_SETFILE", setfile_path.c_str());
+
+ const std::string rez_path = cmSystemTools::FindProgram("Rez", paths, false);
+ if (rez_path.empty()) {
+ cmCPackLogger(cmCPackLog::LOG_ERROR, "Cannot locate Rez command"
+ << std::endl);
+ return 0;
+ }
+ this->SetOptionIfNotSet("CPACK_COMMAND_REZ", rez_path.c_str());
+
+ if (this->IsSet("CPACK_DMG_SLA_DIR")) {
+ slaDirectory = this->GetOption("CPACK_DMG_SLA_DIR");
+ if (!slaDirectory.empty() && this->IsSet("CPACK_RESOURCE_FILE_LICENSE")) {
+ std::string license_file =
+ this->GetOption("CPACK_RESOURCE_FILE_LICENSE");
+ if (!license_file.empty() &&
+ (license_file.find("CPack.GenericLicense.txt") ==
+ std::string::npos)) {
+ cmCPackLogger(
+ cmCPackLog::LOG_OUTPUT,
+ "Both CPACK_DMG_SLA_DIR and CPACK_RESOURCE_FILE_LICENSE specified, "
+ "using CPACK_RESOURCE_FILE_LICENSE as a license for all languages."
+ << std::endl);
+ singleLicense = true;
+ }
+ }
+ if (!this->IsSet("CPACK_DMG_SLA_LANGUAGES")) {
+ cmCPackLogger(cmCPackLog::LOG_ERROR,
+ "CPACK_DMG_SLA_DIR set but no languages defined "
+ "(set CPACK_DMG_SLA_LANGUAGES)"
+ << std::endl);
+ return 0;
+ }
+ if (!cmSystemTools::FileExists(slaDirectory, false)) {
+ cmCPackLogger(cmCPackLog::LOG_ERROR, "CPACK_DMG_SLA_DIR does not exist"
+ << std::endl);
+ return 0;
+ }
+
+ std::vector<std::string> languages;
+ cmSystemTools::ExpandListArgument(
+ this->GetOption("CPACK_DMG_SLA_LANGUAGES"), languages);
+ if (languages.empty()) {
+ cmCPackLogger(cmCPackLog::LOG_ERROR,
+ "CPACK_DMG_SLA_LANGUAGES set but empty" << std::endl);
+ return 0;
+ }
+ for (size_t i = 0; i < languages.size(); ++i) {
+ std::string license = slaDirectory + "/" + languages[i] + ".license.txt";
+ if (!singleLicense && !cmSystemTools::FileExists(license)) {
+ cmCPackLogger(cmCPackLog::LOG_ERROR, "Missing license file "
+ << languages[i] << ".license.txt" << std::endl);
+ return 0;
+ }
+ std::string menu = slaDirectory + "/" + languages[i] + ".menu.txt";
+ if (!cmSystemTools::FileExists(menu)) {
+ cmCPackLogger(cmCPackLog::LOG_ERROR, "Missing menu file "
+ << languages[i] << ".menu.txt" << std::endl);
+ return 0;
+ }
+ }
+ }
+
+ return this->Superclass::InitializeInternal();
+}
+
+const char* cmCPackDragNDropGenerator::GetOutputExtension()
+{
+ return ".dmg";
+}
+
+int cmCPackDragNDropGenerator::PackageFiles()
+{
+ // gather which directories to make dmg files for
+ // multiple directories occur if packaging components or groups separately
+
+ // monolith
+ if (this->Components.empty()) {
+ return this->CreateDMG(toplevel, packageFileNames[0]);
+ }
+
+ // component install
+ std::vector<std::string> package_files;
+
+ std::map<std::string, cmCPackComponent>::iterator compIt;
+ for (compIt = this->Components.begin(); compIt != this->Components.end();
+ ++compIt) {
+ std::string name = GetComponentInstallDirNameSuffix(compIt->first);
+ package_files.push_back(name);
+ }
+ std::sort(package_files.begin(), package_files.end());
+ package_files.erase(std::unique(package_files.begin(), package_files.end()),
+ package_files.end());
+
+ // loop to create dmg files
+ packageFileNames.clear();
+ for (size_t i = 0; i < package_files.size(); i++) {
+ std::string full_package_name = std::string(toplevel) + std::string("/");
+ if (package_files[i] == "ALL_IN_ONE") {
+ full_package_name += this->GetOption("CPACK_PACKAGE_FILE_NAME");
+ } else {
+ full_package_name += package_files[i];
+ }
+ full_package_name += std::string(GetOutputExtension());
+ packageFileNames.push_back(full_package_name);
+
+ std::string src_dir = toplevel;
+ src_dir += "/";
+ src_dir += package_files[i];
+
+ if (0 == this->CreateDMG(src_dir, full_package_name)) {
+ return 0;
+ }
+ }
+ return 1;
+}
+
+bool cmCPackDragNDropGenerator::CopyFile(std::ostringstream& source,
+ std::ostringstream& target)
+{
+ if (!cmSystemTools::CopyFileIfDifferent(source.str().c_str(),
+ target.str().c_str())) {
+ cmCPackLogger(cmCPackLog::LOG_ERROR, "Error copying "
+ << source.str() << " to " << target.str() << std::endl);
+
+ return false;
+ }
+
+ return true;
+}
+
+bool cmCPackDragNDropGenerator::CreateEmptyFile(std::ostringstream& target,
+ size_t size)
+{
+ cmsys::ofstream fout(target.str().c_str(), std::ios::out | std::ios::binary);
+ if (!fout) {
+ return false;
+ } else {
+ // Seek to desired size - 1 byte
+ fout.seekp(size - 1, std::ios::beg);
+ char byte = 0;
+ // Write one byte to ensure file grows
+ fout.write(&byte, 1);
+ }
+
+ return true;
+}
+
+bool cmCPackDragNDropGenerator::RunCommand(std::ostringstream& command,
+ std::string* output)
+{
+ int exit_code = 1;
+
+ bool result =
+ cmSystemTools::RunSingleCommand(command.str().c_str(), output, output,
+ &exit_code, 0, this->GeneratorVerbose, 0);
+
+ if (!result || exit_code) {
+ cmCPackLogger(cmCPackLog::LOG_ERROR, "Error executing: " << command.str()
+ << std::endl);
+
+ return false;
+ }
+
+ return true;
+}
+
+int cmCPackDragNDropGenerator::CreateDMG(const std::string& src_dir,
+ const std::string& output_file)
+{
+ // Get optional arguments ...
+ const std::string cpack_package_icon = this->GetOption("CPACK_PACKAGE_ICON")
+ ? this->GetOption("CPACK_PACKAGE_ICON")
+ : "";
+
+ const std::string cpack_dmg_volume_name =
+ this->GetOption("CPACK_DMG_VOLUME_NAME")
+ ? this->GetOption("CPACK_DMG_VOLUME_NAME")
+ : this->GetOption("CPACK_PACKAGE_FILE_NAME");
+
+ const std::string cpack_dmg_format = this->GetOption("CPACK_DMG_FORMAT")
+ ? this->GetOption("CPACK_DMG_FORMAT")
+ : "UDZO";
+
+ // Get optional arguments ...
+ std::string cpack_license_file =
+ this->GetOption("CPACK_RESOURCE_FILE_LICENSE")
+ ? this->GetOption("CPACK_RESOURCE_FILE_LICENSE")
+ : "";
+
+ const std::string cpack_dmg_background_image =
+ this->GetOption("CPACK_DMG_BACKGROUND_IMAGE")
+ ? this->GetOption("CPACK_DMG_BACKGROUND_IMAGE")
+ : "";
+
+ const std::string cpack_dmg_ds_store = this->GetOption("CPACK_DMG_DS_STORE")
+ ? this->GetOption("CPACK_DMG_DS_STORE")
+ : "";
+
+ const std::string cpack_dmg_languages =
+ this->GetOption("CPACK_DMG_SLA_LANGUAGES")
+ ? this->GetOption("CPACK_DMG_SLA_LANGUAGES")
+ : "";
+
+ const std::string cpack_dmg_ds_store_setup_script =
+ this->GetOption("CPACK_DMG_DS_STORE_SETUP_SCRIPT")
+ ? this->GetOption("CPACK_DMG_DS_STORE_SETUP_SCRIPT")
+ : "";
+
+ const bool cpack_dmg_disable_applications_symlink =
+ this->IsOn("CPACK_DMG_DISABLE_APPLICATIONS_SYMLINK");
+
+ // only put license on dmg if is user provided
+ if (!cpack_license_file.empty() &&
+ cpack_license_file.find("CPack.GenericLicense.txt") !=
+ std::string::npos) {
+ cpack_license_file = "";
+ }
+
+ // use sla_dir if both sla_dir and license_file are set
+ if (!cpack_license_file.empty() && !slaDirectory.empty() && !singleLicense) {
+ cpack_license_file = "";
+ }
+
+ // The staging directory contains everything that will end-up inside the
+ // final disk image ...
+ std::ostringstream staging;
+ staging << src_dir;
+
+ // Add a symlink to /Applications so users can drag-and-drop the bundle
+ // into it unless this behaviour was disabled
+ if (!cpack_dmg_disable_applications_symlink) {
+ std::ostringstream application_link;
+ application_link << staging.str() << "/Applications";
+ cmSystemTools::CreateSymlink("/Applications",
+ application_link.str().c_str());
+ }
+
+ // Optionally add a custom volume icon ...
+ if (!cpack_package_icon.empty()) {
+ std::ostringstream package_icon_source;
+ package_icon_source << cpack_package_icon;
+
+ std::ostringstream package_icon_destination;
+ package_icon_destination << staging.str() << "/.VolumeIcon.icns";
+
+ if (!this->CopyFile(package_icon_source, package_icon_destination)) {
+ cmCPackLogger(cmCPackLog::LOG_ERROR,
+ "Error copying disk volume icon. "
+ "Check the value of CPACK_PACKAGE_ICON."
+ << std::endl);
+
+ return 0;
+ }
+ }
+
+ // Optionally add a custom .DS_Store file
+ // (e.g. for setting background/layout) ...
+ if (!cpack_dmg_ds_store.empty()) {
+ std::ostringstream package_settings_source;
+ package_settings_source << cpack_dmg_ds_store;
+
+ std::ostringstream package_settings_destination;
+ package_settings_destination << staging.str() << "/.DS_Store";
+
+ if (!this->CopyFile(package_settings_source,
+ package_settings_destination)) {
+ cmCPackLogger(cmCPackLog::LOG_ERROR,
+ "Error copying disk volume settings file. "
+ "Check the value of CPACK_DMG_DS_STORE."
+ << std::endl);
+
+ return 0;
+ }
+ }
+
+ // Optionally add a custom background image ...
+ // Make sure the background file type is the same as the custom image
+ // and that the file is hidden so it doesn't show up.
+ if (!cpack_dmg_background_image.empty()) {
+ const std::string extension =
+ cmSystemTools::GetFilenameLastExtension(cpack_dmg_background_image);
+ std::ostringstream package_background_source;
+ package_background_source << cpack_dmg_background_image;
+
+ std::ostringstream package_background_destination;
+ package_background_destination << staging.str()
+ << "/.background/background" << extension;
+
+ if (!this->CopyFile(package_background_source,
+ package_background_destination)) {
+ cmCPackLogger(cmCPackLog::LOG_ERROR,
+ "Error copying disk volume background image. "
+ "Check the value of CPACK_DMG_BACKGROUND_IMAGE."
+ << std::endl);
+
+ return 0;
+ }
+ }
+
+ bool remount_image =
+ !cpack_package_icon.empty() || !cpack_dmg_ds_store_setup_script.empty();
+
+ // Create 1 MB dummy padding file in staging area when we need to remount
+ // image, so we have enough space for storing changes ...
+ if (remount_image) {
+ std::ostringstream dummy_padding;
+ dummy_padding << staging.str() << "/.dummy-padding-file";
+ if (!this->CreateEmptyFile(dummy_padding, 1048576)) {
+ cmCPackLogger(cmCPackLog::LOG_ERROR, "Error creating dummy padding file."
+ << std::endl);
+
+ return 0;
+ }
+ }
+
+ // Create a temporary read-write disk image ...
+ std::string temp_image = this->GetOption("CPACK_TOPLEVEL_DIRECTORY");
+ temp_image += "/temp.dmg";
+
+ std::ostringstream temp_image_command;
+ temp_image_command << this->GetOption("CPACK_COMMAND_HDIUTIL");
+ temp_image_command << " create";
+ temp_image_command << " -ov";
+ temp_image_command << " -srcfolder \"" << staging.str() << "\"";
+ temp_image_command << " -volname \"" << cpack_dmg_volume_name << "\"";
+ temp_image_command << " -format UDRW";
+ temp_image_command << " \"" << temp_image << "\"";
+
+ if (!this->RunCommand(temp_image_command)) {
+ cmCPackLogger(cmCPackLog::LOG_ERROR,
+ "Error generating temporary disk image." << std::endl);
+
+ return 0;
+ }
+
+ if (remount_image) {
+ // Store that we have a failure so that we always unmount the image
+ // before we exit.
+ bool had_error = false;
+
+ std::ostringstream attach_command;
+ attach_command << this->GetOption("CPACK_COMMAND_HDIUTIL");
+ attach_command << " attach";
+ attach_command << " \"" << temp_image << "\"";
+
+ std::string attach_output;
+ if (!this->RunCommand(attach_command, &attach_output)) {
+ cmCPackLogger(cmCPackLog::LOG_ERROR,
+ "Error attaching temporary disk image." << std::endl);
+
+ return 0;
+ }
+
+ cmsys::RegularExpression mountpoint_regex(".*(/Volumes/[^\n]+)\n.*");
+ mountpoint_regex.find(attach_output.c_str());
+ std::string const temp_mount = mountpoint_regex.match(1);
+
+ // Remove dummy padding file so we have enough space on RW image ...
+ std::ostringstream dummy_padding;
+ dummy_padding << temp_mount << "/.dummy-padding-file";
+ if (!cmSystemTools::RemoveFile(dummy_padding.str())) {
+ cmCPackLogger(cmCPackLog::LOG_ERROR, "Error removing dummy padding file."
+ << std::endl);
+
+ had_error = true;
+ }
+
+ // Optionally set the custom icon flag for the image ...
+ if (!had_error && !cpack_package_icon.empty()) {
+ std::ostringstream setfile_command;
+ setfile_command << this->GetOption("CPACK_COMMAND_SETFILE");
+ setfile_command << " -a C";
+ setfile_command << " \"" << temp_mount << "\"";
+
+ if (!this->RunCommand(setfile_command)) {
+ cmCPackLogger(cmCPackLog::LOG_ERROR,
+ "Error assigning custom icon to temporary disk image."
+ << std::endl);
+
+ had_error = true;
+ }
+ }
+
+ // Optionally we can execute a custom apple script to generate
+ // the .DS_Store for the volume folder ...
+ if (!had_error && !cpack_dmg_ds_store_setup_script.empty()) {
+ std::ostringstream setup_script_command;
+ setup_script_command << "osascript"
+ << " \"" << cpack_dmg_ds_store_setup_script << "\""
+ << " \"" << cpack_dmg_volume_name << "\"";
+ std::string error;
+ if (!this->RunCommand(setup_script_command, &error)) {
+ cmCPackLogger(cmCPackLog::LOG_ERROR,
+ "Error executing custom script on disk image."
+ << std::endl
+ << error << std::endl);
+
+ had_error = true;
+ }
+ }
+
+ std::ostringstream detach_command;
+ detach_command << this->GetOption("CPACK_COMMAND_HDIUTIL");
+ detach_command << " detach";
+ detach_command << " \"" << temp_mount << "\"";
+
+ if (!this->RunCommand(detach_command)) {
+ cmCPackLogger(cmCPackLog::LOG_ERROR,
+ "Error detaching temporary disk image." << std::endl);
+
+ return 0;
+ }
+
+ if (had_error) {
+ return 0;
+ }
+ }
+
+ if (!cpack_license_file.empty() || !slaDirectory.empty()) {
+ // Use old hardcoded style if sla_dir is not set
+ bool oldStyle = slaDirectory.empty();
+ std::string sla_r = this->GetOption("CPACK_TOPLEVEL_DIRECTORY");
+ sla_r += "/sla.r";
+
+ std::vector<std::string> languages;
+ if (!oldStyle) {
+ cmSystemTools::ExpandListArgument(cpack_dmg_languages, languages);
+ }
+
+ cmGeneratedFileStream ofs(sla_r.c_str());
+ ofs << "#include <CoreServices/CoreServices.r>\n\n";
+ if (oldStyle) {
+ ofs << SLAHeader;
+ ofs << "\n";
+ } else {
+ /*
+ * LPic Layout
+ * (https://github.com/pypt/dmg-add-license/blob/master/main.c)
+ * as far as I can tell (no official documentation seems to exist):
+ * struct LPic {
+ * uint16_t default_language; // points to a resid, defaulting to 0,
+ * // which is the first set language
+ * uint16_t length;
+ * struct {
+ * uint16_t language_code;
+ * uint16_t resid;
+ * uint16_t encoding; // Encoding from TextCommon.h,
+ * // forcing MacRoman (0) for now. Might need to
+ * // allow overwrite per license by user later
+ * } item[1];
+ * }
+ */
+
+ // Create vector first for readability, then iterate to write to ofs
+ std::vector<uint16_t> header_data;
+ header_data.push_back(0);
+ header_data.push_back(languages.size());
+ for (size_t i = 0; i < languages.size(); ++i) {
+ CFStringRef language_cfstring = CFStringCreateWithCString(
+ NULL, languages[i].c_str(), kCFStringEncodingUTF8);
+ CFStringRef iso_language =
+ CFLocaleCreateCanonicalLanguageIdentifierFromString(
+ NULL, language_cfstring);
+ if (!iso_language) {
+ cmCPackLogger(cmCPackLog::LOG_ERROR, languages[i]
+ << " is not a recognized language" << std::endl);
+ }
+ char* iso_language_cstr = (char*)malloc(65);
+ CFStringGetCString(iso_language, iso_language_cstr, 64,
+ kCFStringEncodingMacRoman);
+ LangCode lang = 0;
+ RegionCode region = 0;
+#ifdef HAVE_CoreServices
+ OSStatus err =
+ LocaleStringToLangAndRegionCodes(iso_language_cstr, &lang, &region);
+ if (err != noErr)
+#endif
+ {
+ cmCPackLogger(cmCPackLog::LOG_ERROR,
+ "No language/region code available for "
+ << iso_language_cstr << std::endl);
+ free(iso_language_cstr);
+ return 0;
+ }
+#ifdef HAVE_CoreServices
+ free(iso_language_cstr);
+ header_data.push_back(region);
+ header_data.push_back(i);
+ header_data.push_back(0);
+#endif
+ }
+ ofs << "data 'LPic' (5000) {\n";
+ ofs << std::hex << std::uppercase << std::setfill('0');
+
+ for (size_t i = 0; i < header_data.size(); ++i) {
+ if (i % 8 == 0) {
+ ofs << " $\"";
+ }
+
+ ofs << std::setw(4) << header_data[i];
+
+ if (i % 8 == 7 || i == header_data.size() - 1) {
+ ofs << "\"\n";
+ } else {
+ ofs << " ";
+ }
+ }
+ ofs << "};\n\n";
+ // Reset ofs options
+ ofs << std::dec << std::nouppercase << std::setfill(' ');
+ }
+
+ bool have_write_license_error = false;
+ std::string error;
+
+ if (oldStyle) {
+ if (!this->WriteLicense(ofs, 0, "", cpack_license_file, &error)) {
+ have_write_license_error = true;
+ }
+ } else {
+ for (size_t i = 0; i < languages.size() && !have_write_license_error;
+ ++i) {
+ if (singleLicense) {
+ if (!this->WriteLicense(ofs, i + 5000, languages[i],
+ cpack_license_file, &error)) {
+ have_write_license_error = true;
+ }
+ } else {
+ if (!this->WriteLicense(ofs, i + 5000, languages[i], "", &error)) {
+ have_write_license_error = true;
+ }
+ }
+ }
+ }
+
+ ofs.Close();
+
+ if (have_write_license_error) {
+ cmCPackLogger(cmCPackLog::LOG_ERROR, "Error writing license file to SLA."
+ << std::endl
+ << error << std::endl);
+ return 0;
+ }
+
+ // convert to UDCO
+ std::string temp_udco = this->GetOption("CPACK_TOPLEVEL_DIRECTORY");
+ temp_udco += "/temp-udco.dmg";
+
+ std::ostringstream udco_image_command;
+ udco_image_command << this->GetOption("CPACK_COMMAND_HDIUTIL");
+ udco_image_command << " convert \"" << temp_image << "\"";
+ udco_image_command << " -format UDCO";
+ udco_image_command << " -ov -o \"" << temp_udco << "\"";
+
+ if (!this->RunCommand(udco_image_command, &error)) {
+ cmCPackLogger(cmCPackLog::LOG_ERROR,
+ "Error converting to UDCO dmg for adding SLA."
+ << std::endl
+ << error << std::endl);
+ return 0;
+ }
+
+ // unflatten dmg
+ std::ostringstream unflatten_command;
+ unflatten_command << this->GetOption("CPACK_COMMAND_HDIUTIL");
+ unflatten_command << " unflatten ";
+ unflatten_command << "\"" << temp_udco << "\"";
+
+ if (!this->RunCommand(unflatten_command, &error)) {
+ cmCPackLogger(cmCPackLog::LOG_ERROR,
+ "Error unflattening dmg for adding SLA." << std::endl
+ << error
+ << std::endl);
+ return 0;
+ }
+
+ // Rez the SLA
+ std::ostringstream embed_sla_command;
+ embed_sla_command << this->GetOption("CPACK_COMMAND_REZ");
+ const char* sysroot = this->GetOption("CPACK_OSX_SYSROOT");
+ if (sysroot && sysroot[0] != '\0') {
+ embed_sla_command << " -isysroot \"" << sysroot << "\"";
+ }
+ embed_sla_command << " \"" << sla_r << "\"";
+ embed_sla_command << " -a -o ";
+ embed_sla_command << "\"" << temp_udco << "\"";
+
+ if (!this->RunCommand(embed_sla_command, &error)) {
+ cmCPackLogger(cmCPackLog::LOG_ERROR, "Error adding SLA." << std::endl
+ << error
+ << std::endl);
+ return 0;
+ }
+
+ // flatten dmg
+ std::ostringstream flatten_command;
+ flatten_command << this->GetOption("CPACK_COMMAND_HDIUTIL");
+ flatten_command << " flatten ";
+ flatten_command << "\"" << temp_udco << "\"";
+
+ if (!this->RunCommand(flatten_command, &error)) {
+ cmCPackLogger(cmCPackLog::LOG_ERROR,
+ "Error flattening dmg for adding SLA." << std::endl
+ << error
+ << std::endl);
+ return 0;
+ }
+
+ temp_image = temp_udco;
+ }
+
+ // Create the final compressed read-only disk image ...
+ std::ostringstream final_image_command;
+ final_image_command << this->GetOption("CPACK_COMMAND_HDIUTIL");
+ final_image_command << " convert \"" << temp_image << "\"";
+ final_image_command << " -format ";
+ final_image_command << cpack_dmg_format;
+ final_image_command << " -imagekey";
+ final_image_command << " zlib-level=9";
+ final_image_command << " -o \"" << output_file << "\"";
+
+ if (!this->RunCommand(final_image_command)) {
+ cmCPackLogger(cmCPackLog::LOG_ERROR, "Error compressing disk image."
+ << std::endl);
+
+ return 0;
+ }
+
+ return 1;
+}
+
+bool cmCPackDragNDropGenerator::SupportsComponentInstallation() const
+{
+ return true;
+}
+
+std::string cmCPackDragNDropGenerator::GetComponentInstallDirNameSuffix(
+ const std::string& componentName)
+{
+ // we want to group components together that go in the same dmg package
+ std::string package_file_name = this->GetOption("CPACK_PACKAGE_FILE_NAME");
+
+ // we have 3 mutually exclusive modes to work in
+ // 1. all components in one package
+ // 2. each group goes in its own package with left over
+ // components in their own package
+ // 3. ignore groups - if grouping is defined, it is ignored
+ // and each component goes in its own package
+
+ if (this->componentPackageMethod == ONE_PACKAGE) {
+ return "ALL_IN_ONE";
+ }
+
+ if (this->componentPackageMethod == ONE_PACKAGE_PER_GROUP) {
+ // We have to find the name of the COMPONENT GROUP
+ // the current COMPONENT belongs to.
+ std::string groupVar =
+ "CPACK_COMPONENT_" + cmSystemTools::UpperCase(componentName) + "_GROUP";
+ const char* _groupName = GetOption(groupVar.c_str());
+ if (_groupName) {
+ std::string groupName = _groupName;
+
+ groupName =
+ GetComponentPackageFileName(package_file_name, groupName, true);
+ return groupName;
+ }
+ }
+
+ return GetComponentPackageFileName(package_file_name, componentName, false);
+}
+
+bool cmCPackDragNDropGenerator::WriteLicense(
+ cmGeneratedFileStream& outputStream, int licenseNumber,
+ std::string licenseLanguage, std::string licenseFile, std::string* error)
+{
+ if (!licenseFile.empty() && !singleLicense) {
+ licenseNumber = 5002;
+ licenseLanguage = "English";
+ }
+
+ // License header
+ outputStream << "data 'TEXT' (" << licenseNumber << ", \"" << licenseLanguage
+ << "\") {\n";
+ // License body
+ std::string actual_license = !licenseFile.empty()
+ ? licenseFile
+ : (slaDirectory + "/" + licenseLanguage + ".license.txt");
+ cmsys::ifstream license_ifs;
+ license_ifs.open(actual_license.c_str());
+ if (license_ifs.is_open()) {
+ while (license_ifs.good()) {
+ std::string line;
+ std::getline(license_ifs, line);
+ if (!line.empty()) {
+ EscapeQuotesAndBackslashes(line);
+ std::vector<std::string> lines;
+ if (!this->BreakLongLine(line, lines, error)) {
+ return false;
+ }
+ for (size_t i = 0; i < lines.size(); ++i) {
+ outputStream << " \"" << lines[i] << "\"\n";
+ }
+ }
+ outputStream << " \"\\n\"\n";
+ }
+ license_ifs.close();
+ }
+
+ // End of License
+ outputStream << "};\n\n";
+ if (!licenseFile.empty() && !singleLicense) {
+ outputStream << SLASTREnglish;
+ } else {
+ // Menu header
+ outputStream << "resource 'STR#' (" << licenseNumber << ", \""
+ << licenseLanguage << "\") {\n";
+ outputStream << " {\n";
+
+ // Menu body
+ cmsys::ifstream menu_ifs;
+ menu_ifs.open(
+ (slaDirectory + "/" + licenseLanguage + ".menu.txt").c_str());
+ if (menu_ifs.is_open()) {
+ size_t lines_written = 0;
+ while (menu_ifs.good()) {
+ // Lines written from original file, not from broken up lines
+ std::string line;
+ std::getline(menu_ifs, line);
+ if (!line.empty()) {
+ EscapeQuotesAndBackslashes(line);
+ std::vector<std::string> lines;
+ if (!this->BreakLongLine(line, lines, error)) {
+ return false;
+ }
+ for (size_t i = 0; i < lines.size(); ++i) {
+ std::string comma;
+ // We need a comma after every complete string,
+ // but not on the very last line
+ if (lines_written != 8 && i == lines.size() - 1) {
+ comma = ",";
+ } else {
+ comma = "";
+ }
+ outputStream << " \"" << lines[i] << "\"" << comma << "\n";
+ }
+ ++lines_written;
+ }
+ }
+ menu_ifs.close();
+ }
+
+ // End of menu
+ outputStream << " }\n";
+ outputStream << "};\n";
+ outputStream << "\n";
+ }
+
+ return true;
+}
+
+bool cmCPackDragNDropGenerator::BreakLongLine(const std::string& line,
+ std::vector<std::string>& lines,
+ std::string* error)
+{
+ const size_t max_line_length = 512;
+ for (size_t i = 0; i < line.size(); i += max_line_length) {
+ size_t line_length = max_line_length;
+ if (i + line_length > line.size()) {
+ line_length = line.size() - i;
+ } else
+ while (line_length > 0 && line[i + line_length - 1] != ' ') {
+ line_length = line_length - 1;
+ }
+
+ if (line_length == 0) {
+ *error = "Please make sure there are no words "
+ "(or character sequences not broken up by spaces or newlines) "
+ "in your license file which are more than 512 characters long.";
+ return false;
+ }
+ lines.push_back(line.substr(i, line_length));
+ }
+ return true;
+}
+
+void cmCPackDragNDropGenerator::EscapeQuotesAndBackslashes(std::string& line)
+{
+ std::string::size_type backslash_pos = line.find('\\');
+ while (backslash_pos != std::string::npos) {
+ line.replace(backslash_pos, 1, "\\\\");
+ backslash_pos = line.find('\\', backslash_pos + 2);
+ }
+
+ std::string::size_type quote_pos = line.find('\"');
+ while (quote_pos != std::string::npos) {
+ line.replace(quote_pos, 1, "\\\"");
+ quote_pos = line.find('\"', quote_pos + 2);
+ }
+}
diff --git a/Source/CPack/cmCPackDragNDropGenerator.h b/Source/CPack/cmCPackDragNDropGenerator.h
new file mode 100644
index 0000000..a5f89f6
--- /dev/null
+++ b/Source/CPack/cmCPackDragNDropGenerator.h
@@ -0,0 +1,60 @@
+/*============================================================================
+ CMake - Cross Platform Makefile Generator
+ Copyright 2000-2009 Kitware, Inc.
+
+ Distributed under the OSI-approved BSD License (the "License");
+ see accompanying file Copyright.txt for details.
+
+ This software is distributed WITHOUT ANY WARRANTY; without even the
+ implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
+ See the License for more information.
+============================================================================*/
+
+#ifndef cmCPackDragNDropGenerator_h
+#define cmCPackDragNDropGenerator_h
+
+#include "cmCPackGenerator.h"
+
+class cmGeneratedFileStream;
+
+/** \class cmCPackDragNDropGenerator
+ * \brief A generator for OSX drag-n-drop installs
+ */
+class cmCPackDragNDropGenerator : public cmCPackGenerator
+{
+public:
+ cmCPackTypeMacro(cmCPackDragNDropGenerator, cmCPackGenerator);
+
+ cmCPackDragNDropGenerator();
+ virtual ~cmCPackDragNDropGenerator();
+
+protected:
+ int InitializeInternal() CM_OVERRIDE;
+ const char* GetOutputExtension() CM_OVERRIDE;
+ int PackageFiles() CM_OVERRIDE;
+ bool SupportsComponentInstallation() const CM_OVERRIDE;
+
+ bool CopyFile(std::ostringstream& source, std::ostringstream& target);
+ bool CreateEmptyFile(std::ostringstream& target, size_t size);
+ bool RunCommand(std::ostringstream& command, std::string* output = 0);
+
+ std::string GetComponentInstallDirNameSuffix(
+ const std::string& componentName) CM_OVERRIDE;
+
+ int CreateDMG(const std::string& src_dir, const std::string& output_file);
+
+ std::string InstallPrefix;
+
+private:
+ std::string slaDirectory;
+ bool singleLicense;
+
+ bool WriteLicense(cmGeneratedFileStream& outputStream, int licenseNumber,
+ std::string licenseLanguage, std::string licenseFile,
+ std::string* error);
+ bool BreakLongLine(const std::string& line, std::vector<std::string>& lines,
+ std::string* error);
+ void EscapeQuotesAndBackslashes(std::string& line);
+};
+
+#endif
diff --git a/Source/CPack/cmCPackGenerator.cxx b/Source/CPack/cmCPackGenerator.cxx
new file mode 100644
index 0000000..58a2243
--- /dev/null
+++ b/Source/CPack/cmCPackGenerator.cxx
@@ -0,0 +1,1433 @@
+/*============================================================================
+ CMake - Cross Platform Makefile Generator
+ Copyright 2000-2009 Kitware, Inc., Insight Software Consortium
+
+ Distributed under the OSI-approved BSD License (the "License");
+ see accompanying file Copyright.txt for details.
+
+ This software is distributed WITHOUT ANY WARRANTY; without even the
+ implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
+ See the License for more information.
+============================================================================*/
+
+#include "cmCPackGenerator.h"
+
+#include "cmCPackComponentGroup.h"
+#include "cmCPackLog.h"
+#include "cmGeneratedFileStream.h"
+#include "cmGlobalGenerator.h"
+#include "cmMakefile.h"
+#include "cmXMLSafe.h"
+#include "cmake.h"
+
+#include <algorithm>
+#include <cmsys/FStream.hxx>
+#include <cmsys/Glob.hxx>
+#include <cmsys/SystemTools.hxx>
+#include <list>
+
+#if defined(__HAIKU__)
+#include <FindDirectory.h>
+#include <StorageDefs.h>
+#endif
+
+cmCPackGenerator::cmCPackGenerator()
+{
+ this->GeneratorVerbose = cmSystemTools::OUTPUT_NONE;
+ this->MakefileMap = CM_NULLPTR;
+ this->Logger = CM_NULLPTR;
+ this->componentPackageMethod = ONE_PACKAGE_PER_GROUP;
+}
+
+cmCPackGenerator::~cmCPackGenerator()
+{
+ this->MakefileMap = CM_NULLPTR;
+}
+
+void cmCPackGeneratorProgress(const char* msg, float prog, void* ptr)
+{
+ cmCPackGenerator* self = static_cast<cmCPackGenerator*>(ptr);
+ self->DisplayVerboseOutput(msg, prog);
+}
+
+void cmCPackGenerator::DisplayVerboseOutput(const char* 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;
+ } else 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;
+ }
+
+ 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.c_str())) {
+ 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=");
+ }
+
+ // 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)) {
+ 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)) {
+ 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);
+ std::vector<std::string>::iterator it;
+ for (it = installCommandsVector.begin(); it != installCommandsVector.end();
+ ++it) {
+ cmCPackLogger(cmCPackLog::LOG_VERBOSE, "Execute: " << *it << std::endl);
+ std::string output;
+ int retVal = 1;
+ bool resB =
+ cmSystemTools::RunSingleCommand(it->c_str(), &output, &output, &retVal,
+ CM_NULLPTR, this->GeneratorVerbose, 0);
+ if (!resB || retVal) {
+ std::string tmpFile = this->GetOption("CPACK_TOPLEVEL_DIRECTORY");
+ tmpFile += "/InstallOutput.log";
+ cmGeneratedFileStream ofs(tmpFile.c_str());
+ ofs << "# Run command: " << *it << std::endl
+ << "# Output:" << std::endl
+ << output << std::endl;
+ cmCPackLogger(
+ cmCPackLog::LOG_ERROR, "Problem running install command: "
+ << *it << std::endl
+ << "Please check " << tmpFile << " for errors" << std::endl);
+ return 0;
+ }
+ }
+ }
+ return 1;
+}
+
+int cmCPackGenerator::InstallProjectViaInstalledDirectories(
+ bool setDestDir, const std::string& tempInstallDirectory)
+{
+ (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);
+ std::vector<std::string>::iterator it;
+ for (it = ignoreFilesRegexString.begin();
+ it != ignoreFilesRegexString.end(); ++it) {
+ cmCPackLogger(cmCPackLog::LOG_VERBOSE,
+ "Create ignore files regex for: " << *it << std::endl);
+ ignoreFilesRegex.push_back(it->c_str());
+ }
+ }
+ 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::list<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();
+ std::vector<std::string>::iterator gfit;
+ std::vector<cmsys::RegularExpression>::iterator regIt;
+ for (gfit = files.begin(); gfit != files.end(); ++gfit) {
+ bool skip = false;
+ std::string inFile = *gfit;
+ if (cmSystemTools::FileIsDirectory(*gfit)) {
+ inFile += '/';
+ }
+ for (regIt = ignoreFilesRegex.begin(); regIt != ignoreFilesRegex.end();
+ ++regIt) {
+ if (regIt->find(inFile.c_str())) {
+ cmCPackLogger(cmCPackLog::LOG_VERBOSE,
+ "Ignore file: " << inFile << std::endl);
+ skip = true;
+ }
+ }
+ if (skip) {
+ continue;
+ }
+ std::string filePath = tempDir;
+ filePath += "/" + subdir + "/" +
+ cmSystemTools::RelativePath(top.c_str(), gfit->c_str());
+ 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.c_str(), inFile.c_str());
+ cmSystemTools::ReadSymlink(inFile, targetFile);
+ symlinkedFiles.push_back(
+ std::pair<std::string, std::string>(targetFile, inFileRelative));
+ }
+ /* If it is not a symlink then do a plain copy */
+ else if (!(cmSystemTools::CopyFileIfDifferent(inFile.c_str(),
+ filePath.c_str()) &&
+ cmSystemTools::CopyFileTime(inFile.c_str(),
+ filePath.c_str()))) {
+ cmCPackLogger(cmCPackLog::LOG_ERROR, "Problem copying file: "
+ << inFile << " -> " << filePath << std::endl);
+ return 0;
+ }
+ }
+ /* rebuild symlinks in the installed tree */
+ if (!symlinkedFiles.empty()) {
+ std::list<std::pair<std::string, std::string> >::iterator symlinkedIt;
+ std::string curDir = cmSystemTools::GetCurrentWorkingDirectory();
+ std::string goToDir = tempDir;
+ goToDir += "/" + subdir;
+ cmCPackLogger(cmCPackLog::LOG_DEBUG, "Change dir to: " << goToDir
+ << std::endl);
+ cmSystemTools::ChangeDirectory(goToDir);
+ for (symlinkedIt = symlinkedFiles.begin();
+ symlinkedIt != symlinkedFiles.end(); ++symlinkedIt) {
+ cmCPackLogger(cmCPackLog::LOG_DEBUG, "Will create a symlink: "
+ << symlinkedIt->second << "--> "
+ << symlinkedIt->first << std::endl);
+ // make sure directory exists for symlink
+ std::string destDir =
+ cmSystemTools::GetFilenamePath(symlinkedIt->second);
+ if (!destDir.empty() && !cmSystemTools::MakeDirectory(destDir)) {
+ cmCPackLogger(cmCPackLog::LOG_ERROR, "Cannot create dir: "
+ << destDir << "\nTrying to create symlink: "
+ << symlinkedIt->second << "--> "
+ << symlinkedIt->first << std::endl);
+ }
+ if (!cmSystemTools::CreateSymlink(symlinkedIt->first,
+ symlinkedIt->second)) {
+ cmCPackLogger(cmCPackLog::LOG_ERROR, "Cannot create symlink: "
+ << symlinkedIt->second << "--> "
+ << symlinkedIt->first << std::endl);
+ return 0;
+ }
+ }
+ cmCPackLogger(cmCPackLog::LOG_DEBUG, "Going back to: " << curDir
+ << std::endl);
+ cmSystemTools::ChangeDirectory(curDir);
+ }
+ }
+ }
+ 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);
+ std::vector<std::string>::iterator it;
+ for (it = cmakeScriptsVector.begin(); it != cmakeScriptsVector.end();
+ ++it) {
+ std::string installScript = *it;
+
+ 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());
+ int res = this->MakefileMap->ReadListFile(installScript.c_str());
+ if (cmSystemTools::GetErrorOccuredFlag() || !res) {
+ return 0;
+ }
+ }
+ }
+ return 1;
+}
+
+int cmCPackGenerator::InstallProjectViaInstallCMakeProjects(
+ bool setDestDir, const std::string& baseTempInstallDirectory)
+{
+ 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;
+ std::string installComponent = *it;
+ ++it;
+ std::string installSubDirectory = *it;
+ std::string installFile = installDirectory + "/cmake_install.cmake";
+
+ 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(installComponent) + "_INSTALL_TYPES";
+ const char* installTypes = this->GetOption(installTypesVar);
+ if (installTypes && *installTypes) {
+ std::vector<std::string> installTypesVector;
+ cmSystemTools::ExpandListArgument(installTypes, installTypesVector);
+ std::vector<std::string>::iterator installTypeIt;
+ for (installTypeIt = installTypesVector.begin();
+ installTypeIt != installTypesVector.end(); ++installTypeIt) {
+ this->GetInstallationType(installProjectName, *installTypeIt);
+ }
+ }
+
+ // Determine the set of components that will be used in this project
+ std::string componentsVar =
+ "CPACK_COMPONENTS_" + cmSystemTools::UpperCase(installComponent);
+ const char* components = this->GetOption(componentsVar);
+ if (components && *components) {
+ cmSystemTools::ExpandListArgument(components, componentsVector);
+ std::vector<std::string>::iterator compIt;
+ for (compIt = componentsVector.begin();
+ compIt != componentsVector.end(); ++compIt) {
+ GetComponent(installProjectName, *compIt);
+ }
+ componentInstall = true;
+ }
+ }
+ if (componentsVector.empty()) {
+ componentsVector.push_back(installComponent);
+ }
+
+ 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());
+
+ // 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.c_str(), &output, &output, &retVal,
+ installDirectory.c_str(), this->GeneratorVerbose, 0);
+ if (!resB || retVal) {
+ std::string tmpFile = this->GetOption("CPACK_TOPLEVEL_DIRECTORY");
+ tmpFile += "/PreinstallOutput.log";
+ cmGeneratedFileStream ofs(tmpFile.c_str());
+ 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;
+ }
+ }
+ delete globalGenerator;
+
+ cmCPackLogger(cmCPackLog::LOG_OUTPUT,
+ "- Install project: " << installProjectName << std::endl);
+
+ // Run the installation for each component
+ std::vector<std::string>::iterator componentIt;
+ for (componentIt = componentsVector.begin();
+ componentIt != componentsVector.end(); ++componentIt) {
+ std::string tempInstallDirectory = baseTempInstallDirectory;
+ installComponent = *componentIt;
+ if (componentInstall) {
+ cmCPackLogger(cmCPackLog::LOG_OUTPUT, "- Install component: "
+ << installComponent << std::endl);
+ }
+
+ cmake cm;
+ cm.SetHomeDirectory("");
+ cm.SetHomeOutputDirectory("");
+ cm.GetCurrentSnapshot().SetDefaultDefinitions();
+ cm.AddCMakePaths();
+ cm.SetProgressCallback(cmCPackGeneratorProgress, this);
+ cmGlobalGenerator gg(&cm);
+ CM_AUTO_PTR<cmMakefile> mf(
+ new cmMakefile(&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(installComponent);
+ if (this->IsOn("CPACK_COMPONENT_INCLUDE_TOPLEVEL_DIRECTORY")) {
+ tempInstallDirectory += "/";
+ tempInstallDirectory += this->GetOption("CPACK_PACKAGE_FILE_NAME");
+ }
+ }
+
+ 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.c_str())) {
+ 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.c_str())) {
+ 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(installComponent);
+ if (installComponentLowerCase != "all") {
+ mf->AddDefinition("CMAKE_INSTALL_COMPONENT",
+ installComponent.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)
+ const char* InstallPrefix = tempInstallDirectory.c_str();
+ std::vector<std::string> filesBefore;
+ std::string findExpr(InstallPrefix);
+ 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
+ int res = mf->ReadListFile(installFile.c_str());
+ // 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.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->c_str());
+ localFileName = localFileName.substr(
+ localFileName.find_first_not_of('/'), std::string::npos);
+ Components[installComponent].Files.push_back(localFileName);
+ cmCPackLogger(cmCPackLog::LOG_DEBUG, "Adding file <"
+ << localFileName << "> to component <"
+ << installComponent << ">" << std::endl);
+ }
+ }
+
+ if (CM_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(installComponent);
+ if (CM_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;
+ }
+ }
+ }
+ }
+ this->SetOption("CPACK_ABSOLUTE_DESTINATION_FILES",
+ absoluteDestFiles.c_str());
+ return 1;
+}
+
+bool cmCPackGenerator::ReadListFile(const char* moduleName)
+{
+ bool retval;
+ std::string fullPath = this->MakefileMap->GetModulesFile(moduleName);
+ retval = this->MakefileMap->ReadListFile(fullPath.c_str());
+ // 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.push_back(tempPackageFileName ? tempPackageFileName : "");
+ toplevel = tempDirectory;
+ if (!this->PackageFiles() || cmSystemTools::GetErrorOccuredFlag()) {
+ cmCPackLogger(cmCPackLog::LOG_ERROR, "Problem compressing the directory"
+ << std::endl);
+ return 0;
+ }
+
+ /*
+ * 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);
+ std::vector<std::string>::iterator it;
+ /* now copy package one by one */
+ for (it = packageFileNames.begin(); it != packageFileNames.end(); ++it) {
+ std::string tmpPF(this->GetOption("CPACK_OUTPUT_FILE_PREFIX"));
+ tempPackageFileName = it->c_str();
+ tmpPF += "/" + cmSystemTools::GetFilenameName(*it);
+ 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(tempPackageFileName,
+ packageFileName)) {
+ 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);
+ }
+
+ 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));
+}
+
+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 char* inName, const char* outName,
+ bool copyOnly /* = false */)
+{
+ return this->MakefileMap->ConfigureFile(inName, outName, copyOnly, true,
+ false) == 1;
+}
+
+int cmCPackGenerator::CleanTemporaryDirectory()
+{
+ std::string tempInstallDirectoryWithPostfix =
+ this->GetOption("CPACK_TEMPORARY_INSTALL_DIRECTORY");
+ const char* tempInstallDirectory = tempInstallDirectoryWithPostfix.c_str();
+ 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 (CM_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* groupName = this->GetOption(macroPrefix + "_GROUP");
+ if (groupName && *groupName) {
+ component->Group = GetComponentGroup(projectName, groupName);
+ component->Group->Components.push_back(component);
+ } else {
+ component->Group = CM_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);
+ std::vector<std::string>::iterator installTypesIt;
+ for (installTypesIt = installTypesVector.begin();
+ installTypesIt != installTypesVector.end(); ++installTypesIt) {
+ component->InstallationTypes.push_back(
+ this->GetInstallationType(projectName, *installTypesIt));
+ }
+ }
+
+ // Determine the component dependencies.
+ const char* depends = this->GetOption(macroPrefix + "_DEPENDS");
+ if (depends && *depends) {
+ std::vector<std::string> dependsVector;
+ cmSystemTools::ExpandListArgument(depends, dependsVector);
+ std::vector<std::string>::iterator dependIt;
+ for (dependIt = dependsVector.begin(); dependIt != dependsVector.end();
+ ++dependIt) {
+ cmCPackComponent* child = GetComponent(projectName, *dependIt);
+ 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 = CM_NULLPTR;
+ }
+ }
+ return group;
+}
diff --git a/Source/CPack/cmCPackGenerator.h b/Source/CPack/cmCPackGenerator.h
new file mode 100644
index 0000000..23e4bb7
--- /dev/null
+++ b/Source/CPack/cmCPackGenerator.h
@@ -0,0 +1,331 @@
+/*============================================================================
+ CMake - Cross Platform Makefile Generator
+ Copyright 2000-2009 Kitware, Inc.
+
+ Distributed under the OSI-approved BSD License (the "License");
+ see accompanying file Copyright.txt for details.
+
+ This software is distributed WITHOUT ANY WARRANTY; without even the
+ implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
+ See the License for more information.
+============================================================================*/
+
+#ifndef cmCPackGenerator_h
+#define cmCPackGenerator_h
+
+#include "cmObject.h"
+
+#include "cmSystemTools.h"
+#include <map>
+#include <vector>
+
+#include "cmCPackComponentGroup.h" // cmCPackComponent and friends
+// Forward declarations are insufficient since we use them in
+// std::map data members below...
+
+#define cmCPackTypeMacro(klass, superclass) \
+ cmTypeMacro(klass, superclass); \
+ static cmCPackGenerator* CreateGenerator() { return new klass; } \
+ class cmCPackTypeMacro_UseTrailingSemicolon
+
+#define cmCPackLogger(logType, msg) \
+ do { \
+ std::ostringstream cmCPackLog_msg; \
+ cmCPackLog_msg << msg; \
+ this->Logger->Log(logType, __FILE__, __LINE__, \
+ cmCPackLog_msg.str().c_str()); \
+ } while (0)
+
+#ifdef cerr
+#undef cerr
+#endif
+#define cerr no_cerr_use_cmCPack_Log
+
+#ifdef cout
+#undef cout
+#endif
+#define cout no_cout_use_cmCPack_Log
+
+class cmMakefile;
+class cmCPackLog;
+class cmInstalledFile;
+
+/** \class cmCPackGenerator
+ * \brief A superclass of all CPack Generators
+ *
+ */
+class cmCPackGenerator : public cmObject
+{
+public:
+ cmTypeMacro(cmCPackGenerator, cmObject);
+ /**
+ * If verbose then more information is printed out
+ */
+ void SetVerbose(bool val)
+ {
+ this->GeneratorVerbose =
+ val ? cmSystemTools::OUTPUT_MERGE : cmSystemTools::OUTPUT_NONE;
+ }
+
+ /**
+ * Returns true if the generator may work on this system.
+ * Rational:
+ * Some CPack generator may run on some host and may not on others
+ * (with the same system) because some tools are missing. If the tool
+ * is missing then CPack won't activate (in the CPackGeneratorFactory)
+ * this particular generator.
+ */
+ static bool CanGenerate() { return true; }
+
+ /**
+ * Do the actual whole package processing.
+ * Subclass may redefine it but its usually enough
+ * to redefine @ref PackageFiles, because in fact
+ * this method do call:
+ * - PrepareName
+ * - clean-up temp dirs
+ * - InstallProject (with the appropriate method)
+ * - prepare list of files and/or components to be package
+ * - PackageFiles
+ * - Copy produced packages at the expected place
+ * @return 0 if error.
+ */
+ virtual int DoPackage();
+
+ /**
+ * Initialize generator
+ */
+ int Initialize(const std::string& name, cmMakefile* mf);
+
+ /**
+ * Construct generator
+ */
+ cmCPackGenerator();
+ ~cmCPackGenerator() CM_OVERRIDE;
+
+ //! Set and get the options
+ void SetOption(const std::string& op, const char* value);
+ void SetOptionIfNotSet(const std::string& op, const char* value);
+ const char* GetOption(const std::string& op) const;
+ std::vector<std::string> GetOptions() const;
+ bool IsSet(const std::string& name) const;
+ bool IsOn(const std::string& name) const;
+
+ //! Set the logger
+ void SetLogger(cmCPackLog* log) { this->Logger = log; }
+
+ //! Display verbose information via logger
+ void DisplayVerboseOutput(const char* msg, float progress);
+
+ bool ReadListFile(const char* moduleName);
+
+protected:
+ /**
+ * Prepare common used names by inspecting
+ * several CPACK_xxx var values.
+ */
+ int PrepareNames();
+
+ /**
+ * Install the project using appropriate method.
+ */
+ int InstallProject();
+
+ int CleanTemporaryDirectory();
+
+ cmInstalledFile const* GetInstalledFile(std::string const& name) const;
+
+ virtual const char* GetOutputExtension() { return ".cpack"; }
+ virtual const char* GetOutputPostfix() { return CM_NULLPTR; }
+
+ /**
+ * Prepare requested grouping kind from CPACK_xxx vars
+ * CPACK_COMPONENTS_ALL_IN_ONE_PACKAGE
+ * CPACK_COMPONENTS_IGNORE_GROUPS
+ * or
+ * CPACK_COMPONENTS_ONE_PACKAGE_PER_GROUP
+ * @return 1 on success 0 on failure.
+ */
+ 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);
+
+ /**
+ * CPack specific generator may mangle CPACK_PACKAGE_FILE_NAME
+ * with CPACK_COMPONENT_xxxx_<NAME>_DISPLAY_NAME if
+ * CPACK_<GEN>_USE_DISPLAY_NAME_IN_FILENAME is ON.
+ * @param[in] initialPackageFileName the initial package name to be mangled
+ * @param[in] groupOrComponentName the name of the group/component
+ * @param[in] isGroupName true if previous name refers to a group,
+ * false otherwise
+ */
+ virtual std::string GetComponentPackageFileName(
+ const std::string& initialPackageFileName,
+ const std::string& groupOrComponentName, bool isGroupName);
+
+ /**
+ * Package the list of files and/or components which
+ * has been prepared by the beginning of DoPackage.
+ * @pre the @ref toplevel has been filled-in
+ * @pre the list of file @ref files has been populated
+ * @pre packageFileNames contains at least 1 entry
+ * @post packageFileNames may have been updated and contains
+ * the list of packages generated by the specific generator.
+ */
+ virtual int PackageFiles();
+ virtual const char* GetInstallPath();
+ virtual const char* GetPackagingInstallPrefix();
+
+ virtual std::string FindTemplate(const char* name);
+ virtual bool ConfigureFile(const char* inName, const char* outName,
+ bool copyOnly = false);
+ virtual bool ConfigureString(const std::string& input, std::string& output);
+ virtual int InitializeInternal();
+
+ //! Run install commands if specified
+ virtual int InstallProjectViaInstallCommands(
+ bool setDestDir, const std::string& tempInstallDirectory);
+ virtual int InstallProjectViaInstallScript(
+ bool setDestDir, const std::string& tempInstallDirectory);
+ virtual int InstallProjectViaInstalledDirectories(
+ bool setDestDir, const std::string& tempInstallDirectory);
+ virtual int InstallProjectViaInstallCMakeProjects(
+ bool setDestDir, const std::string& tempInstallDirectory);
+
+ /**
+ * The various level of support of
+ * CPACK_SET_DESTDIR used by the generator.
+ */
+ enum CPackSetDestdirSupport
+ {
+ /* the generator works with or without it */
+ SETDESTDIR_SUPPORTED,
+ /* the generator works best if automatically handled */
+ SETDESTDIR_INTERNALLY_SUPPORTED,
+ /* no official support, use at your own risk */
+ SETDESTDIR_SHOULD_NOT_BE_USED,
+ /* officially NOT supported */
+ SETDESTDIR_UNSUPPORTED
+ };
+
+ /**
+ * Does the CPack generator support CPACK_SET_DESTDIR?
+ * The default legacy value is 'SETDESTDIR_SUPPORTED' generator
+ * have to override it in order change this.
+ * @return CPackSetDestdirSupport
+ */
+ virtual enum CPackSetDestdirSupport SupportsSetDestdir() const;
+
+ /**
+ * Does the CPack generator support absolute path
+ * in INSTALL DESTINATION?
+ * The default legacy value is 'true' generator
+ * have to override it in order change this.
+ * @return true if supported false otherwise
+ */
+ virtual bool SupportsAbsoluteDestination() const;
+
+ /**
+ * Does the CPack generator support component installation?.
+ * Some Generators requires the user to set
+ * CPACK_<GENNAME>_COMPONENT_INSTALL in order to make this
+ * method return true.
+ * @return true if supported, false otherwise
+ */
+ virtual bool SupportsComponentInstallation() const;
+ /**
+ * Does the currently running generator want a component installation.
+ * The generator may support component installation but he may
+ * be requiring monolithic install using CPACK_MONOLITHIC_INSTALL.
+ * @return true if component installation is supported and wanted.
+ */
+ virtual bool WantsComponentInstallation() const;
+ virtual cmCPackInstallationType* GetInstallationType(
+ const std::string& projectName, const std::string& name);
+ virtual cmCPackComponent* GetComponent(const std::string& projectName,
+ const std::string& name);
+ virtual cmCPackComponentGroup* GetComponentGroup(
+ const std::string& projectName, const std::string& name);
+
+ cmSystemTools::OutputOption GeneratorVerbose;
+ std::string Name;
+
+ std::string InstallPath;
+
+ /**
+ * The list of package file names.
+ * At beginning of DoPackage the (generic) generator will populate
+ * the list of desired package file names then it will
+ * call the redefined method PackageFiles which is may
+ * either use this set of names (usually on entry there should be
+ * only a single name) or update the vector with the list
+ * of created package file names.
+ */
+ std::vector<std::string> packageFileNames;
+
+ /**
+ * The directory where all the files to be packaged reside.
+ * If the installer support components there will be one
+ * sub-directory for each component. In those directories
+ * one will find the file belonging to the specified component.
+ */
+ std::string toplevel;
+
+ /**
+ * The complete list of files to be packaged.
+ * This list will be populated by DoPackage before
+ * PackageFiles is called.
+ */
+ std::vector<std::string> files;
+
+ std::map<std::string, cmCPackInstallationType> InstallationTypes;
+ /**
+ * The set of components.
+ * If component installation is supported then this map
+ * contains the component specified in CPACK_COMPONENTS_ALL
+ */
+ std::map<std::string, cmCPackComponent> Components;
+ std::map<std::string, cmCPackComponentGroup> ComponentGroups;
+
+ /**
+ * If components are enabled, this enum represents the different
+ * ways of mapping components to package files.
+ */
+ enum ComponentPackageMethod
+ {
+ /* one package for all components */
+ ONE_PACKAGE,
+ /* one package for each component */
+ ONE_PACKAGE_PER_COMPONENT,
+ /* one package for each group,
+ * with left over components in their own package */
+ ONE_PACKAGE_PER_GROUP,
+ UNKNOWN_COMPONENT_PACKAGE_METHOD
+ };
+
+ /**
+ * The component package method
+ * The default is ONE_PACKAGE_PER_GROUP,
+ * and generators may override the default
+ * before PrepareGroupingKind() is called.
+ */
+ ComponentPackageMethod componentPackageMethod;
+
+ cmCPackLog* Logger;
+
+private:
+ cmMakefile* MakefileMap;
+};
+
+#endif
diff --git a/Source/CPack/cmCPackGeneratorFactory.cxx b/Source/CPack/cmCPackGeneratorFactory.cxx
new file mode 100644
index 0000000..0f0268f
--- /dev/null
+++ b/Source/CPack/cmCPackGeneratorFactory.cxx
@@ -0,0 +1,183 @@
+/*============================================================================
+ CMake - Cross Platform Makefile Generator
+ Copyright 2000-2009 Kitware, Inc., Insight Software Consortium
+
+ Distributed under the OSI-approved BSD License (the "License");
+ see accompanying file Copyright.txt for details.
+
+ This software is distributed WITHOUT ANY WARRANTY; without even the
+ implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
+ See the License for more information.
+============================================================================*/
+
+#include "cmCPackGeneratorFactory.h"
+
+#include "IFW/cmCPackIFWGenerator.h"
+#include "cmCPack7zGenerator.h"
+#include "cmCPackGenerator.h"
+#include "cmCPackNSISGenerator.h"
+#include "cmCPackSTGZGenerator.h"
+#include "cmCPackTGZGenerator.h"
+#include "cmCPackTXZGenerator.h"
+#include "cmCPackTarBZip2Generator.h"
+#include "cmCPackTarCompressGenerator.h"
+#include "cmCPackZIPGenerator.h"
+
+#ifdef __APPLE__
+#include "cmCPackBundleGenerator.h"
+#include "cmCPackDragNDropGenerator.h"
+#include "cmCPackOSXX11Generator.h"
+#include "cmCPackPackageMakerGenerator.h"
+#include "cmCPackProductBuildGenerator.h"
+#endif
+
+#ifdef __CYGWIN__
+#include "cmCPackCygwinBinaryGenerator.h"
+#include "cmCPackCygwinSourceGenerator.h"
+#endif
+
+#if !defined(_WIN32) && !defined(__QNXNTO__) && !defined(__BEOS__) && \
+ !defined(__HAIKU__)
+#include "cmCPackDebGenerator.h"
+#include "cmCPackRPMGenerator.h"
+#endif
+
+#ifdef _WIN32
+#include "WiX/cmCPackWIXGenerator.h"
+#endif
+
+#include "cmAlgorithms.h"
+#include "cmCPackLog.h"
+
+cmCPackGeneratorFactory::cmCPackGeneratorFactory()
+{
+ if (cmCPackTGZGenerator::CanGenerate()) {
+ this->RegisterGenerator("TGZ", "Tar GZip compression",
+ cmCPackTGZGenerator::CreateGenerator);
+ }
+ if (cmCPackTXZGenerator::CanGenerate()) {
+ this->RegisterGenerator("TXZ", "Tar XZ compression",
+ cmCPackTXZGenerator::CreateGenerator);
+ }
+ if (cmCPackSTGZGenerator::CanGenerate()) {
+ this->RegisterGenerator("STGZ", "Self extracting Tar GZip compression",
+ cmCPackSTGZGenerator::CreateGenerator);
+ }
+ if (cmCPackNSISGenerator::CanGenerate()) {
+ this->RegisterGenerator("NSIS", "Null Soft Installer",
+ cmCPackNSISGenerator::CreateGenerator);
+ this->RegisterGenerator("NSIS64", "Null Soft Installer (64-bit)",
+ cmCPackNSISGenerator::CreateGenerator64);
+ }
+ if (cmCPackIFWGenerator::CanGenerate()) {
+ this->RegisterGenerator("IFW", "Qt Installer Framework",
+ cmCPackIFWGenerator::CreateGenerator);
+ }
+#ifdef __CYGWIN__
+ if (cmCPackCygwinBinaryGenerator::CanGenerate()) {
+ this->RegisterGenerator("CygwinBinary", "Cygwin Binary Installer",
+ cmCPackCygwinBinaryGenerator::CreateGenerator);
+ }
+ if (cmCPackCygwinSourceGenerator::CanGenerate()) {
+ this->RegisterGenerator("CygwinSource", "Cygwin Source Installer",
+ cmCPackCygwinSourceGenerator::CreateGenerator);
+ }
+#endif
+
+ if (cmCPackZIPGenerator::CanGenerate()) {
+ this->RegisterGenerator("ZIP", "ZIP file format",
+ cmCPackZIPGenerator::CreateGenerator);
+ }
+ if (cmCPack7zGenerator::CanGenerate()) {
+ this->RegisterGenerator("7Z", "7-Zip file format",
+ cmCPack7zGenerator::CreateGenerator);
+ }
+#ifdef _WIN32
+ if (cmCPackWIXGenerator::CanGenerate()) {
+ this->RegisterGenerator("WIX", "MSI file format via WiX tools",
+ cmCPackWIXGenerator::CreateGenerator);
+ }
+#endif
+ if (cmCPackTarBZip2Generator::CanGenerate()) {
+ this->RegisterGenerator("TBZ2", "Tar BZip2 compression",
+ cmCPackTarBZip2Generator::CreateGenerator);
+ }
+ if (cmCPackTarCompressGenerator::CanGenerate()) {
+ this->RegisterGenerator("TZ", "Tar Compress compression",
+ cmCPackTarCompressGenerator::CreateGenerator);
+ }
+#ifdef __APPLE__
+ if (cmCPackDragNDropGenerator::CanGenerate()) {
+ this->RegisterGenerator("DragNDrop", "Mac OSX Drag And Drop",
+ cmCPackDragNDropGenerator::CreateGenerator);
+ }
+ if (cmCPackBundleGenerator::CanGenerate()) {
+ this->RegisterGenerator("Bundle", "Mac OSX bundle",
+ cmCPackBundleGenerator::CreateGenerator);
+ }
+ if (cmCPackPackageMakerGenerator::CanGenerate()) {
+ this->RegisterGenerator("PackageMaker", "Mac OSX Package Maker installer",
+ cmCPackPackageMakerGenerator::CreateGenerator);
+ }
+ if (cmCPackOSXX11Generator::CanGenerate()) {
+ this->RegisterGenerator("OSXX11", "Mac OSX X11 bundle",
+ cmCPackOSXX11Generator::CreateGenerator);
+ }
+ if (cmCPackProductBuildGenerator::CanGenerate()) {
+ this->RegisterGenerator("productbuild", "Mac OSX pkg",
+ cmCPackProductBuildGenerator::CreateGenerator);
+ }
+#endif
+#if !defined(_WIN32) && !defined(__QNXNTO__) && !defined(__BEOS__) && \
+ !defined(__HAIKU__)
+ if (cmCPackDebGenerator::CanGenerate()) {
+ this->RegisterGenerator("DEB", "Debian packages",
+ cmCPackDebGenerator::CreateGenerator);
+ }
+ if (cmCPackRPMGenerator::CanGenerate()) {
+ this->RegisterGenerator("RPM", "RPM packages",
+ cmCPackRPMGenerator::CreateGenerator);
+ }
+#endif
+}
+
+cmCPackGeneratorFactory::~cmCPackGeneratorFactory()
+{
+ cmDeleteAll(this->Generators);
+}
+
+cmCPackGenerator* cmCPackGeneratorFactory::NewGenerator(
+ const std::string& name)
+{
+ cmCPackGenerator* gen = this->NewGeneratorInternal(name);
+ if (!gen) {
+ return CM_NULLPTR;
+ }
+ this->Generators.push_back(gen);
+ gen->SetLogger(this->Logger);
+ return gen;
+}
+
+cmCPackGenerator* cmCPackGeneratorFactory::NewGeneratorInternal(
+ const std::string& name)
+{
+ cmCPackGeneratorFactory::t_GeneratorCreatorsMap::iterator it =
+ this->GeneratorCreators.find(name);
+ if (it == this->GeneratorCreators.end()) {
+ return CM_NULLPTR;
+ }
+ return (it->second)();
+}
+
+void cmCPackGeneratorFactory::RegisterGenerator(
+ const std::string& name, const char* generatorDescription,
+ CreateGeneratorCall* createGenerator)
+{
+ if (!createGenerator) {
+ cmCPack_Log(this->Logger, cmCPackLog::LOG_ERROR,
+ "Cannot register generator" << std::endl);
+ return;
+ }
+ this->GeneratorCreators[name] = createGenerator;
+ this->GeneratorDescriptions[name] = generatorDescription;
+}
diff --git a/Source/CPack/cmCPackGeneratorFactory.h b/Source/CPack/cmCPackGeneratorFactory.h
new file mode 100644
index 0000000..f0ed57a
--- /dev/null
+++ b/Source/CPack/cmCPackGeneratorFactory.h
@@ -0,0 +1,61 @@
+/*============================================================================
+ CMake - Cross Platform Makefile Generator
+ Copyright 2000-2009 Kitware, Inc.
+
+ Distributed under the OSI-approved BSD License (the "License");
+ see accompanying file Copyright.txt for details.
+
+ This software is distributed WITHOUT ANY WARRANTY; without even the
+ implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
+ See the License for more information.
+============================================================================*/
+
+#ifndef cmCPackGeneratorFactory_h
+#define cmCPackGeneratorFactory_h
+
+#include "cmObject.h"
+
+class cmCPackLog;
+class cmCPackGenerator;
+
+/** \class cmCPackGeneratorFactory
+ * \brief A container for CPack generators
+ *
+ */
+class cmCPackGeneratorFactory : public cmObject
+{
+public:
+ cmTypeMacro(cmCPackGeneratorFactory, cmObject);
+
+ cmCPackGeneratorFactory();
+ ~cmCPackGeneratorFactory() CM_OVERRIDE;
+
+ //! Get the generator
+ cmCPackGenerator* NewGenerator(const std::string& name);
+ void DeleteGenerator(cmCPackGenerator* gen);
+
+ typedef cmCPackGenerator* CreateGeneratorCall();
+
+ void RegisterGenerator(const std::string& name,
+ const char* generatorDescription,
+ CreateGeneratorCall* createGenerator);
+
+ void SetLogger(cmCPackLog* logger) { this->Logger = logger; }
+
+ typedef std::map<std::string, std::string> DescriptionsMap;
+ const DescriptionsMap& GetGeneratorsList() const
+ {
+ return this->GeneratorDescriptions;
+ }
+
+private:
+ cmCPackGenerator* NewGeneratorInternal(const std::string& name);
+ std::vector<cmCPackGenerator*> Generators;
+
+ typedef std::map<std::string, CreateGeneratorCall*> t_GeneratorCreatorsMap;
+ t_GeneratorCreatorsMap GeneratorCreators;
+ DescriptionsMap GeneratorDescriptions;
+ cmCPackLog* Logger;
+};
+
+#endif
diff --git a/Source/CPack/cmCPackLog.cxx b/Source/CPack/cmCPackLog.cxx
new file mode 100644
index 0000000..339323e
--- /dev/null
+++ b/Source/CPack/cmCPackLog.cxx
@@ -0,0 +1,190 @@
+/*============================================================================
+ CMake - Cross Platform Makefile Generator
+ Copyright 2000-2009 Kitware, Inc., Insight Software Consortium
+
+ Distributed under the OSI-approved BSD License (the "License");
+ see accompanying file Copyright.txt for details.
+
+ This software is distributed WITHOUT ANY WARRANTY; without even the
+ implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
+ See the License for more information.
+============================================================================*/
+
+#include "cmCPackLog.h"
+
+#include "cmGeneratedFileStream.h"
+#include "cmSystemTools.h"
+
+cmCPackLog::cmCPackLog()
+{
+ this->Verbose = false;
+ this->Debug = false;
+ this->Quiet = false;
+ this->NewLine = true;
+
+ this->LastTag = cmCPackLog::NOTAG;
+#undef cerr
+#undef cout
+ this->DefaultOutput = &std::cout;
+ this->DefaultError = &std::cerr;
+
+ this->LogOutput = CM_NULLPTR;
+ this->LogOutputCleanup = false;
+}
+
+cmCPackLog::~cmCPackLog()
+{
+ this->SetLogOutputStream(CM_NULLPTR);
+}
+
+void cmCPackLog::SetLogOutputStream(std::ostream* os)
+{
+ if (this->LogOutputCleanup && this->LogOutput) {
+ delete this->LogOutput;
+ }
+ this->LogOutputCleanup = false;
+ this->LogOutput = os;
+}
+
+bool cmCPackLog::SetLogOutputFile(const char* fname)
+{
+ cmGeneratedFileStream* cg = CM_NULLPTR;
+ if (fname) {
+ cg = new cmGeneratedFileStream(fname);
+ }
+ if (cg && !*cg) {
+ delete cg;
+ cg = CM_NULLPTR;
+ }
+ this->SetLogOutputStream(cg);
+ if (!cg) {
+ return false;
+ }
+ this->LogOutputCleanup = true;
+ return true;
+}
+
+void cmCPackLog::Log(int tag, const char* file, int line, const char* msg,
+ size_t length)
+{
+ // By default no logging
+ bool display = false;
+
+ // Display file and line number if debug
+ bool useFileAndLine = this->Debug;
+
+ bool output = false;
+ bool debug = false;
+ bool warning = false;
+ bool error = false;
+ bool verbose = false;
+
+ // When writing in file, add list of tags whenever tag changes.
+ std::string tagString;
+ bool needTagString = false;
+ if (this->LogOutput && this->LastTag != tag) {
+ needTagString = true;
+ }
+
+ if (tag & LOG_OUTPUT) {
+ output = true;
+ display = true;
+ if (needTagString) {
+ if (!tagString.empty()) {
+ tagString += ",";
+ }
+ tagString = "VERBOSE";
+ }
+ }
+ if (tag & LOG_WARNING) {
+ warning = true;
+ display = true;
+ if (needTagString) {
+ if (!tagString.empty()) {
+ tagString += ",";
+ }
+ tagString = "WARNING";
+ }
+ }
+ if (tag & LOG_ERROR) {
+ error = true;
+ display = true;
+ if (needTagString) {
+ if (!tagString.empty()) {
+ tagString += ",";
+ }
+ tagString = "ERROR";
+ }
+ }
+ if (tag & LOG_DEBUG && this->Debug) {
+ debug = true;
+ display = true;
+ if (needTagString) {
+ if (!tagString.empty()) {
+ tagString += ",";
+ }
+ tagString = "DEBUG";
+ }
+ useFileAndLine = true;
+ }
+ if (tag & LOG_VERBOSE && this->Verbose) {
+ verbose = true;
+ display = true;
+ if (needTagString) {
+ if (!tagString.empty()) {
+ tagString += ",";
+ }
+ tagString = "VERBOSE";
+ }
+ }
+ if (this->Quiet) {
+ display = false;
+ }
+ if (this->LogOutput) {
+ if (needTagString) {
+ *this->LogOutput << "[" << file << ":" << line << " " << tagString
+ << "] ";
+ }
+ this->LogOutput->write(msg, length);
+ }
+ this->LastTag = tag;
+ if (!display) {
+ return;
+ }
+ if (this->NewLine) {
+ if (error && !this->ErrorPrefix.empty()) {
+ *this->DefaultError << this->ErrorPrefix;
+ } else if (warning && !this->WarningPrefix.empty()) {
+ *this->DefaultError << this->WarningPrefix;
+ } else if (output && !this->OutputPrefix.empty()) {
+ *this->DefaultOutput << this->OutputPrefix;
+ } else if (verbose && !this->VerbosePrefix.empty()) {
+ *this->DefaultOutput << this->VerbosePrefix;
+ } else if (debug && !this->DebugPrefix.empty()) {
+ *this->DefaultOutput << this->DebugPrefix;
+ } else if (!this->Prefix.empty()) {
+ *this->DefaultOutput << this->Prefix;
+ }
+ if (useFileAndLine) {
+ if (error || warning) {
+ *this->DefaultError << file << ":" << line << " ";
+ } else {
+ *this->DefaultOutput << file << ":" << line << " ";
+ }
+ }
+ }
+ if (error || warning) {
+ this->DefaultError->write(msg, length);
+ this->DefaultError->flush();
+ } else {
+ this->DefaultOutput->write(msg, length);
+ this->DefaultOutput->flush();
+ }
+ if (msg[length - 1] == '\n' || length > 2) {
+ this->NewLine = true;
+ }
+
+ if (error) {
+ cmSystemTools::SetErrorOccured();
+ }
+}
diff --git a/Source/CPack/cmCPackLog.h b/Source/CPack/cmCPackLog.h
new file mode 100644
index 0000000..77f0f0b
--- /dev/null
+++ b/Source/CPack/cmCPackLog.h
@@ -0,0 +1,158 @@
+/*============================================================================
+ CMake - Cross Platform Makefile Generator
+ Copyright 2000-2009 Kitware, Inc.
+
+ Distributed under the OSI-approved BSD License (the "License");
+ see accompanying file Copyright.txt for details.
+
+ This software is distributed WITHOUT ANY WARRANTY; without even the
+ implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
+ See the License for more information.
+============================================================================*/
+
+#ifndef cmCPackLog_h
+#define cmCPackLog_h
+
+#include "cmObject.h"
+
+#define cmCPack_Log(ctSelf, logType, msg) \
+ do { \
+ std::ostringstream cmCPackLog_msg; \
+ cmCPackLog_msg << msg; \
+ (ctSelf)->Log(logType, __FILE__, __LINE__, cmCPackLog_msg.str().c_str()); \
+ } while (0)
+
+#ifdef cerr
+#undef cerr
+#endif
+#define cerr no_cerr_use_cmCPack_Log
+
+#ifdef cout
+#undef cout
+#endif
+#define cout no_cout_use_cmCPack_Log
+
+/** \class cmCPackLog
+ * \brief A container for CPack generators
+ *
+ */
+class cmCPackLog : public cmObject
+{
+public:
+ cmTypeMacro(cmCPackLog, cmObject);
+
+ cmCPackLog();
+ ~cmCPackLog() CM_OVERRIDE;
+
+ enum __log_tags
+ {
+ NOTAG = 0,
+ LOG_OUTPUT = 0x1,
+ LOG_VERBOSE = 0x2,
+ LOG_DEBUG = 0x4,
+ LOG_WARNING = 0x8,
+ LOG_ERROR = 0x10
+ };
+
+ //! Various signatures for logging.
+ void Log(const char* file, int line, const char* msg)
+ {
+ this->Log(LOG_OUTPUT, file, line, msg);
+ }
+ void Log(const char* file, int line, const char* msg, size_t length)
+ {
+ this->Log(LOG_OUTPUT, file, line, msg, length);
+ }
+ void Log(int tag, const char* file, int line, const char* msg)
+ {
+ this->Log(tag, file, line, msg, strlen(msg));
+ }
+ void Log(int tag, const char* file, int line, const char* msg,
+ size_t length);
+
+ //! Set Verbose
+ void VerboseOn() { this->SetVerbose(true); }
+ void VerboseOff() { this->SetVerbose(true); }
+ void SetVerbose(bool verb) { this->Verbose = verb; }
+ bool GetVerbose() { return this->Verbose; }
+
+ //! Set Debug
+ void DebugOn() { this->SetDebug(true); }
+ void DebugOff() { this->SetDebug(true); }
+ void SetDebug(bool verb) { this->Debug = verb; }
+ bool GetDebug() { return this->Debug; }
+
+ //! Set Quiet
+ void QuietOn() { this->SetQuiet(true); }
+ void QuietOff() { this->SetQuiet(true); }
+ void SetQuiet(bool verb) { this->Quiet = verb; }
+ bool GetQuiet() { return this->Quiet; }
+
+ //! Set the output stream
+ void SetOutputStream(std::ostream* os) { this->DefaultOutput = os; }
+
+ //! Set the error stream
+ void SetErrorStream(std::ostream* os) { this->DefaultError = os; }
+
+ //! Set the log output stream
+ void SetLogOutputStream(std::ostream* os);
+
+ //! Set the log output file. The cmCPackLog will try to create file. If it
+ // cannot, it will report an error.
+ bool SetLogOutputFile(const char* fname);
+
+ //! Set the various prefixes for the logging. SetPrefix sets the generic
+ // prefix that overwrittes missing ones.
+ void SetPrefix(std::string pfx) { this->Prefix = pfx; }
+ void SetOutputPrefix(std::string pfx) { this->OutputPrefix = pfx; }
+ void SetVerbosePrefix(std::string pfx) { this->VerbosePrefix = pfx; }
+ void SetDebugPrefix(std::string pfx) { this->DebugPrefix = pfx; }
+ void SetWarningPrefix(std::string pfx) { this->WarningPrefix = pfx; }
+ void SetErrorPrefix(std::string pfx) { this->ErrorPrefix = pfx; }
+
+private:
+ bool Verbose;
+ bool Debug;
+ bool Quiet;
+
+ bool NewLine;
+
+ int LastTag;
+
+ std::string Prefix;
+ std::string OutputPrefix;
+ std::string VerbosePrefix;
+ std::string DebugPrefix;
+ std::string WarningPrefix;
+ std::string ErrorPrefix;
+
+ std::ostream* DefaultOutput;
+ std::ostream* DefaultError;
+
+ std::string LogOutputFileName;
+ std::ostream* LogOutput;
+ // Do we need to cleanup log output stream
+ bool LogOutputCleanup;
+};
+
+class cmCPackLogWrite
+{
+public:
+ cmCPackLogWrite(const char* data, size_t length)
+ : Data(data)
+ , Length(length)
+ {
+ }
+
+ const char* Data;
+ size_t Length;
+};
+
+inline std::ostream& operator<<(std::ostream& os, const cmCPackLogWrite& c)
+{
+ os.write(c.Data, c.Length);
+ os.flush();
+ return os;
+}
+
+#endif
diff --git a/Source/CPack/cmCPackNSISGenerator.cxx b/Source/CPack/cmCPackNSISGenerator.cxx
new file mode 100644
index 0000000..d8ff907
--- /dev/null
+++ b/Source/CPack/cmCPackNSISGenerator.cxx
@@ -0,0 +1,918 @@
+/*============================================================================
+ CMake - Cross Platform Makefile Generator
+ Copyright 2000-2009 Kitware, Inc., Insight Software Consortium
+
+ Distributed under the OSI-approved BSD License (the "License");
+ see accompanying file Copyright.txt for details.
+
+ This software is distributed WITHOUT ANY WARRANTY; without even the
+ implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
+ See the License for more information.
+============================================================================*/
+
+#include "cmCPackNSISGenerator.h"
+
+#include "cmCPackComponentGroup.h"
+#include "cmCPackLog.h"
+#include "cmGeneratedFileStream.h"
+#include "cmGlobalGenerator.h"
+#include "cmMakefile.h"
+#include "cmSystemTools.h"
+
+#include <cmsys/Directory.hxx>
+#include <cmsys/Glob.hxx>
+#include <cmsys/RegularExpression.hxx>
+#include <cmsys/SystemTools.hxx>
+
+/* NSIS uses different command line syntax on Windows and others */
+#ifdef _WIN32
+#define NSIS_OPT "/"
+#else
+#define NSIS_OPT "-"
+#endif
+
+cmCPackNSISGenerator::cmCPackNSISGenerator(bool nsis64)
+{
+ Nsis64 = nsis64;
+}
+
+cmCPackNSISGenerator::~cmCPackNSISGenerator()
+{
+}
+
+int cmCPackNSISGenerator::PackageFiles()
+{
+ // TODO: Fix nsis to force out file name
+
+ std::string nsisInFileName = this->FindTemplate("NSIS.template.in");
+ if (nsisInFileName.empty()) {
+ cmCPackLogger(cmCPackLog::LOG_ERROR,
+ "CPack error: Could not find NSIS installer template file."
+ << std::endl);
+ return false;
+ }
+ std::string nsisInInstallOptions =
+ this->FindTemplate("NSIS.InstallOptions.ini.in");
+ if (nsisInInstallOptions.empty()) {
+ cmCPackLogger(cmCPackLog::LOG_ERROR,
+ "CPack error: Could not find NSIS installer options file."
+ << std::endl);
+ return false;
+ }
+
+ std::string nsisFileName = this->GetOption("CPACK_TOPLEVEL_DIRECTORY");
+ std::string tmpFile = nsisFileName;
+ tmpFile += "/NSISOutput.log";
+ std::string nsisInstallOptions = nsisFileName + "/NSIS.InstallOptions.ini";
+ nsisFileName += "/project.nsi";
+ std::ostringstream str;
+ std::vector<std::string>::const_iterator it;
+ for (it = files.begin(); it != files.end(); ++it) {
+ std::string fileN =
+ cmSystemTools::RelativePath(toplevel.c_str(), it->c_str());
+ if (!this->Components.empty()) {
+ // Strip off the component part of the path.
+ fileN = fileN.substr(fileN.find('/') + 1, std::string::npos);
+ }
+ std::replace(fileN.begin(), fileN.end(), '/', '\\');
+ str << " Delete \"$INSTDIR\\" << fileN << "\"" << std::endl;
+ }
+ cmCPackLogger(cmCPackLog::LOG_DEBUG, "Uninstall Files: " << str.str()
+ << std::endl);
+ this->SetOptionIfNotSet("CPACK_NSIS_DELETE_FILES", str.str().c_str());
+ std::vector<std::string> dirs;
+ this->GetListOfSubdirectories(toplevel.c_str(), dirs);
+ std::vector<std::string>::const_iterator sit;
+ std::ostringstream dstr;
+ for (sit = dirs.begin(); sit != dirs.end(); ++sit) {
+ std::string componentName;
+ std::string fileN =
+ cmSystemTools::RelativePath(toplevel.c_str(), sit->c_str());
+ if (fileN.empty()) {
+ continue;
+ }
+ if (!Components.empty()) {
+ // If this is a component installation, strip off the component
+ // part of the path.
+ std::string::size_type slash = fileN.find('/');
+ if (slash != std::string::npos) {
+ // If this is a component installation, determine which component it
+ // is.
+ componentName = fileN.substr(0, slash);
+
+ // Strip off the component part of the path.
+ fileN = fileN.substr(slash + 1, std::string::npos);
+ }
+ }
+ std::replace(fileN.begin(), fileN.end(), '/', '\\');
+ dstr << " RMDir \"$INSTDIR\\" << fileN << "\"" << std::endl;
+ if (!componentName.empty()) {
+ this->Components[componentName].Directories.push_back(fileN);
+ }
+ }
+ cmCPackLogger(cmCPackLog::LOG_DEBUG, "Uninstall Dirs: " << dstr.str()
+ << std::endl);
+ this->SetOptionIfNotSet("CPACK_NSIS_DELETE_DIRECTORIES", dstr.str().c_str());
+
+ cmCPackLogger(cmCPackLog::LOG_VERBOSE, "Configure file: "
+ << nsisInFileName << " to " << nsisFileName << std::endl);
+ if (this->IsSet("CPACK_NSIS_MUI_ICON") ||
+ this->IsSet("CPACK_NSIS_MUI_UNIICON")) {
+ std::string installerIconCode;
+ if (this->IsSet("CPACK_NSIS_MUI_ICON")) {
+ installerIconCode += "!define MUI_ICON \"";
+ installerIconCode += this->GetOption("CPACK_NSIS_MUI_ICON");
+ installerIconCode += "\"\n";
+ }
+ if (this->IsSet("CPACK_NSIS_MUI_UNIICON")) {
+ installerIconCode += "!define MUI_UNICON \"";
+ installerIconCode += this->GetOption("CPACK_NSIS_MUI_UNIICON");
+ installerIconCode += "\"\n";
+ }
+ this->SetOptionIfNotSet("CPACK_NSIS_INSTALLER_MUI_ICON_CODE",
+ installerIconCode.c_str());
+ }
+ if (this->IsSet("CPACK_PACKAGE_ICON")) {
+ std::string installerIconCode = "!define MUI_HEADERIMAGE_BITMAP \"";
+ installerIconCode += this->GetOption("CPACK_PACKAGE_ICON");
+ installerIconCode += "\"\n";
+ this->SetOptionIfNotSet("CPACK_NSIS_INSTALLER_ICON_CODE",
+ installerIconCode.c_str());
+ }
+
+ if (this->IsSet("CPACK_NSIS_MUI_WELCOMEFINISHPAGE_BITMAP")) {
+ std::string installerBitmapCode =
+ "!define MUI_WELCOMEFINISHPAGE_BITMAP \"";
+ installerBitmapCode +=
+ this->GetOption("CPACK_NSIS_MUI_WELCOMEFINISHPAGE_BITMAP");
+ installerBitmapCode += "\"\n";
+ this->SetOptionIfNotSet("CPACK_NSIS_INSTALLER_MUI_WELCOMEFINISH_CODE",
+ installerBitmapCode.c_str());
+ }
+
+ if (this->IsSet("CPACK_NSIS_MUI_UNWELCOMEFINISHPAGE_BITMAP")) {
+ std::string installerBitmapCode =
+ "!define MUI_UNWELCOMEFINISHPAGE_BITMAP \"";
+ installerBitmapCode +=
+ this->GetOption("CPACK_NSIS_MUI_UNWELCOMEFINISHPAGE_BITMAP");
+ installerBitmapCode += "\"\n";
+ this->SetOptionIfNotSet("CPACK_NSIS_INSTALLER_MUI_UNWELCOMEFINISH_CODE",
+ installerBitmapCode.c_str());
+ }
+
+ if (this->IsSet("CPACK_NSIS_MUI_FINISHPAGE_RUN")) {
+ std::string installerRunCode = "!define MUI_FINISHPAGE_RUN \"$INSTDIR\\";
+ installerRunCode += this->GetOption("CPACK_NSIS_EXECUTABLES_DIRECTORY");
+ installerRunCode += "\\";
+ installerRunCode += this->GetOption("CPACK_NSIS_MUI_FINISHPAGE_RUN");
+ installerRunCode += "\"\n";
+ this->SetOptionIfNotSet("CPACK_NSIS_INSTALLER_MUI_FINISHPAGE_RUN_CODE",
+ installerRunCode.c_str());
+ }
+
+ // Setup all of the component sections
+ if (this->Components.empty()) {
+ this->SetOptionIfNotSet("CPACK_NSIS_INSTALLATION_TYPES", "");
+ this->SetOptionIfNotSet("CPACK_NSIS_INSTALLER_MUI_COMPONENTS_DESC", "");
+ this->SetOptionIfNotSet("CPACK_NSIS_PAGE_COMPONENTS", "");
+ this->SetOptionIfNotSet("CPACK_NSIS_FULL_INSTALL",
+ "File /r \"${INST_DIR}\\*.*\"");
+ this->SetOptionIfNotSet("CPACK_NSIS_COMPONENT_SECTIONS", "");
+ this->SetOptionIfNotSet("CPACK_NSIS_COMPONENT_SECTION_LIST", "");
+ this->SetOptionIfNotSet("CPACK_NSIS_SECTION_SELECTED_VARS", "");
+ } else {
+ std::string componentCode;
+ std::string sectionList;
+ std::string selectedVarsList;
+ std::string componentDescriptions;
+ std::string groupDescriptions;
+ std::string installTypesCode;
+ std::string defines;
+ std::ostringstream macrosOut;
+ bool anyDownloadedComponents = false;
+
+ // Create installation types. The order is significant, so we first fill
+ // in a vector based on the indices, and print them in that order.
+ std::vector<cmCPackInstallationType*> installTypes(
+ this->InstallationTypes.size());
+ std::map<std::string, cmCPackInstallationType>::iterator installTypeIt;
+ for (installTypeIt = this->InstallationTypes.begin();
+ installTypeIt != this->InstallationTypes.end(); ++installTypeIt) {
+ installTypes[installTypeIt->second.Index - 1] = &installTypeIt->second;
+ }
+ std::vector<cmCPackInstallationType*>::iterator installTypeIt2;
+ for (installTypeIt2 = installTypes.begin();
+ installTypeIt2 != installTypes.end(); ++installTypeIt2) {
+ installTypesCode += "InstType \"";
+ installTypesCode += (*installTypeIt2)->DisplayName;
+ installTypesCode += "\"\n";
+ }
+
+ // Create installation groups first
+ std::map<std::string, cmCPackComponentGroup>::iterator groupIt;
+ for (groupIt = this->ComponentGroups.begin();
+ groupIt != this->ComponentGroups.end(); ++groupIt) {
+ if (groupIt->second.ParentGroup == CM_NULLPTR) {
+ componentCode +=
+ this->CreateComponentGroupDescription(&groupIt->second, macrosOut);
+ }
+
+ // Add the group description, if any.
+ if (!groupIt->second.Description.empty()) {
+ groupDescriptions += " !insertmacro MUI_DESCRIPTION_TEXT ${" +
+ groupIt->first + "} \"" +
+ this->TranslateNewlines(groupIt->second.Description) + "\"\n";
+ }
+ }
+
+ // Create the remaining components, which aren't associated with groups.
+ std::map<std::string, cmCPackComponent>::iterator compIt;
+ for (compIt = this->Components.begin(); compIt != this->Components.end();
+ ++compIt) {
+ if (compIt->second.Files.empty()) {
+ // NSIS cannot cope with components that have no files.
+ continue;
+ }
+
+ anyDownloadedComponents =
+ anyDownloadedComponents || compIt->second.IsDownloaded;
+
+ if (!compIt->second.Group) {
+ componentCode +=
+ this->CreateComponentDescription(&compIt->second, macrosOut);
+ }
+
+ // Add this component to the various section lists.
+ sectionList += " !insertmacro \"${MacroName}\" \"";
+ sectionList += compIt->first;
+ sectionList += "\"\n";
+ selectedVarsList += "Var " + compIt->first + "_selected\n";
+ selectedVarsList += "Var " + compIt->first + "_was_installed\n";
+
+ // Add the component description, if any.
+ if (!compIt->second.Description.empty()) {
+ componentDescriptions += " !insertmacro MUI_DESCRIPTION_TEXT ${" +
+ compIt->first + "} \"" +
+ this->TranslateNewlines(compIt->second.Description) + "\"\n";
+ }
+ }
+
+ componentCode += macrosOut.str();
+
+ if (componentDescriptions.empty() && groupDescriptions.empty()) {
+ // Turn off the "Description" box
+ this->SetOptionIfNotSet("CPACK_NSIS_INSTALLER_MUI_COMPONENTS_DESC",
+ "!define MUI_COMPONENTSPAGE_NODESC");
+ } else {
+ componentDescriptions = "!insertmacro MUI_FUNCTION_DESCRIPTION_BEGIN\n" +
+ componentDescriptions + groupDescriptions +
+ "!insertmacro MUI_FUNCTION_DESCRIPTION_END\n";
+ this->SetOptionIfNotSet("CPACK_NSIS_INSTALLER_MUI_COMPONENTS_DESC",
+ componentDescriptions.c_str());
+ }
+
+ if (anyDownloadedComponents) {
+ defines += "!define CPACK_USES_DOWNLOAD\n";
+ if (cmSystemTools::IsOn(this->GetOption("CPACK_ADD_REMOVE"))) {
+ defines += "!define CPACK_NSIS_ADD_REMOVE\n";
+ }
+ }
+
+ this->SetOptionIfNotSet("CPACK_NSIS_INSTALLATION_TYPES",
+ installTypesCode.c_str());
+ this->SetOptionIfNotSet("CPACK_NSIS_PAGE_COMPONENTS",
+ "!insertmacro MUI_PAGE_COMPONENTS");
+ this->SetOptionIfNotSet("CPACK_NSIS_FULL_INSTALL", "");
+ this->SetOptionIfNotSet("CPACK_NSIS_COMPONENT_SECTIONS",
+ componentCode.c_str());
+ this->SetOptionIfNotSet("CPACK_NSIS_COMPONENT_SECTION_LIST",
+ sectionList.c_str());
+ this->SetOptionIfNotSet("CPACK_NSIS_SECTION_SELECTED_VARS",
+ selectedVarsList.c_str());
+ this->SetOption("CPACK_NSIS_DEFINES", defines.c_str());
+ }
+
+ this->ConfigureFile(nsisInInstallOptions.c_str(),
+ nsisInstallOptions.c_str());
+ this->ConfigureFile(nsisInFileName.c_str(), nsisFileName.c_str());
+ std::string nsisCmd = "\"";
+ nsisCmd += this->GetOption("CPACK_INSTALLER_PROGRAM");
+ nsisCmd += "\" \"" + nsisFileName + "\"";
+ cmCPackLogger(cmCPackLog::LOG_VERBOSE, "Execute: " << nsisCmd << std::endl);
+ std::string output;
+ int retVal = 1;
+ bool res =
+ cmSystemTools::RunSingleCommand(nsisCmd.c_str(), &output, &output, &retVal,
+ CM_NULLPTR, this->GeneratorVerbose, 0);
+ if (!res || retVal) {
+ cmGeneratedFileStream ofs(tmpFile.c_str());
+ ofs << "# Run command: " << nsisCmd << std::endl
+ << "# Output:" << std::endl
+ << output << std::endl;
+ cmCPackLogger(cmCPackLog::LOG_ERROR, "Problem running NSIS command: "
+ << nsisCmd << std::endl
+ << "Please check " << tmpFile << " for errors"
+ << std::endl);
+ return 0;
+ }
+ return 1;
+}
+
+int cmCPackNSISGenerator::InitializeInternal()
+{
+ if (cmSystemTools::IsOn(
+ this->GetOption("CPACK_INCLUDE_TOPLEVEL_DIRECTORY"))) {
+ cmCPackLogger(
+ cmCPackLog::LOG_WARNING,
+ "NSIS Generator cannot work with CPACK_INCLUDE_TOPLEVEL_DIRECTORY set. "
+ "This option will be reset to 0 (for this generator only)."
+ << std::endl);
+ this->SetOption("CPACK_INCLUDE_TOPLEVEL_DIRECTORY", CM_NULLPTR);
+ }
+
+ cmCPackLogger(cmCPackLog::LOG_DEBUG, "cmCPackNSISGenerator::Initialize()"
+ << std::endl);
+ std::vector<std::string> path;
+ std::string nsisPath;
+ bool gotRegValue = false;
+
+#ifdef _WIN32
+ if (Nsis64) {
+ if (!gotRegValue && cmsys::SystemTools::ReadRegistryValue(
+ "HKEY_LOCAL_MACHINE\\SOFTWARE\\NSIS\\Unicode",
+ nsisPath, cmsys::SystemTools::KeyWOW64_64)) {
+ gotRegValue = true;
+ }
+ if (!gotRegValue && cmsys::SystemTools::ReadRegistryValue(
+ "HKEY_LOCAL_MACHINE\\SOFTWARE\\NSIS", nsisPath,
+ cmsys::SystemTools::KeyWOW64_64)) {
+ gotRegValue = true;
+ }
+ }
+ if (!gotRegValue && cmsys::SystemTools::ReadRegistryValue(
+ "HKEY_LOCAL_MACHINE\\SOFTWARE\\NSIS\\Unicode",
+ nsisPath, cmsys::SystemTools::KeyWOW64_32)) {
+ gotRegValue = true;
+ }
+ if (!gotRegValue &&
+ cmsys::SystemTools::ReadRegistryValue(
+ "HKEY_LOCAL_MACHINE\\SOFTWARE\\NSIS\\Unicode", nsisPath)) {
+ gotRegValue = true;
+ }
+ if (!gotRegValue && cmsys::SystemTools::ReadRegistryValue(
+ "HKEY_LOCAL_MACHINE\\SOFTWARE\\NSIS", nsisPath,
+ cmsys::SystemTools::KeyWOW64_32)) {
+ gotRegValue = true;
+ }
+ if (!gotRegValue && cmsys::SystemTools::ReadRegistryValue(
+ "HKEY_LOCAL_MACHINE\\SOFTWARE\\NSIS", nsisPath)) {
+ gotRegValue = true;
+ }
+
+ if (gotRegValue) {
+ path.push_back(nsisPath);
+ }
+#endif
+
+ nsisPath = cmSystemTools::FindProgram("makensis", path, false);
+
+ if (nsisPath.empty()) {
+ cmCPackLogger(
+ cmCPackLog::LOG_ERROR,
+ "Cannot find NSIS compiler makensis: likely it is not installed, "
+ "or not in your PATH"
+ << std::endl);
+
+ if (!gotRegValue) {
+ cmCPackLogger(
+ cmCPackLog::LOG_ERROR,
+ "Could not read NSIS registry value. This is usually caused by "
+ "NSIS not being installed. Please install NSIS from "
+ "http://nsis.sourceforge.net"
+ << std::endl);
+ }
+
+ return 0;
+ }
+
+ std::string nsisCmd = "\"" + nsisPath + "\" " NSIS_OPT "VERSION";
+ cmCPackLogger(cmCPackLog::LOG_VERBOSE, "Test NSIS version: " << nsisCmd
+ << std::endl);
+ std::string output;
+ int retVal = 1;
+ bool resS =
+ cmSystemTools::RunSingleCommand(nsisCmd.c_str(), &output, &output, &retVal,
+ CM_NULLPTR, this->GeneratorVerbose, 0);
+ cmsys::RegularExpression versionRex("v([0-9]+.[0-9]+)");
+ cmsys::RegularExpression versionRexCVS("v(.*)\\.cvs");
+ if (!resS || retVal ||
+ (!versionRex.find(output) && !versionRexCVS.find(output))) {
+ const char* topDir = this->GetOption("CPACK_TOPLEVEL_DIRECTORY");
+ std::string tmpFile = topDir ? topDir : ".";
+ tmpFile += "/NSISOutput.log";
+ cmGeneratedFileStream ofs(tmpFile.c_str());
+ ofs << "# Run command: " << nsisCmd << std::endl
+ << "# Output:" << std::endl
+ << output << std::endl;
+ cmCPackLogger(
+ cmCPackLog::LOG_ERROR, "Problem checking NSIS version with command: "
+ << nsisCmd << std::endl
+ << "Please check " << tmpFile << " for errors" << std::endl);
+ return 0;
+ }
+ if (versionRex.find(output)) {
+ double nsisVersion = atof(versionRex.match(1).c_str());
+ double minNSISVersion = 2.09;
+ cmCPackLogger(cmCPackLog::LOG_DEBUG, "NSIS Version: " << nsisVersion
+ << std::endl);
+ if (nsisVersion < minNSISVersion) {
+ cmCPackLogger(cmCPackLog::LOG_ERROR,
+ "CPack requires NSIS Version 2.09 or greater. "
+ "NSIS found on the system was: "
+ << nsisVersion << std::endl);
+ return 0;
+ }
+ }
+ if (versionRexCVS.find(output)) {
+ // No version check for NSIS cvs build
+ cmCPackLogger(cmCPackLog::LOG_DEBUG, "NSIS Version: CVS "
+ << versionRexCVS.match(1) << std::endl);
+ }
+ this->SetOptionIfNotSet("CPACK_INSTALLER_PROGRAM", nsisPath.c_str());
+ this->SetOptionIfNotSet("CPACK_NSIS_EXECUTABLES_DIRECTORY", "bin");
+ const char* cpackPackageExecutables =
+ this->GetOption("CPACK_PACKAGE_EXECUTABLES");
+ const char* cpackPackageDeskTopLinks =
+ this->GetOption("CPACK_CREATE_DESKTOP_LINKS");
+ const char* cpackNsisExecutablesDirectory =
+ this->GetOption("CPACK_NSIS_EXECUTABLES_DIRECTORY");
+ std::vector<std::string> cpackPackageDesktopLinksVector;
+ if (cpackPackageDeskTopLinks) {
+ cmCPackLogger(cmCPackLog::LOG_DEBUG, "CPACK_CREATE_DESKTOP_LINKS: "
+ << cpackPackageDeskTopLinks << std::endl);
+
+ cmSystemTools::ExpandListArgument(cpackPackageDeskTopLinks,
+ cpackPackageDesktopLinksVector);
+ for (std::vector<std::string>::iterator i =
+ cpackPackageDesktopLinksVector.begin();
+ i != cpackPackageDesktopLinksVector.end(); ++i) {
+ cmCPackLogger(cmCPackLog::LOG_DEBUG,
+ "CPACK_CREATE_DESKTOP_LINKS: " << *i << std::endl);
+ }
+ } else {
+ cmCPackLogger(cmCPackLog::LOG_DEBUG, "CPACK_CREATE_DESKTOP_LINKS: "
+ << "not set" << std::endl);
+ }
+
+ std::ostringstream str;
+ std::ostringstream deleteStr;
+
+ if (cpackPackageExecutables) {
+ cmCPackLogger(cmCPackLog::LOG_DEBUG, "The cpackPackageExecutables: "
+ << cpackPackageExecutables << "." << std::endl);
+ std::vector<std::string> cpackPackageExecutablesVector;
+ cmSystemTools::ExpandListArgument(cpackPackageExecutables,
+ cpackPackageExecutablesVector);
+ if (cpackPackageExecutablesVector.size() % 2 != 0) {
+ cmCPackLogger(
+ cmCPackLog::LOG_ERROR,
+ "CPACK_PACKAGE_EXECUTABLES should contain pairs of <executable> and "
+ "<icon name>."
+ << std::endl);
+ return 0;
+ }
+ std::vector<std::string>::iterator it;
+ for (it = cpackPackageExecutablesVector.begin();
+ it != cpackPackageExecutablesVector.end(); ++it) {
+ std::string execName = *it;
+ ++it;
+ std::string linkName = *it;
+ str << " CreateShortCut \"$SMPROGRAMS\\$STARTMENU_FOLDER\\" << linkName
+ << ".lnk\" \"$INSTDIR\\" << cpackNsisExecutablesDirectory << "\\"
+ << execName << ".exe\"" << std::endl;
+ deleteStr << " Delete \"$SMPROGRAMS\\$MUI_TEMP\\" << linkName
+ << ".lnk\"" << std::endl;
+ // see if CPACK_CREATE_DESKTOP_LINK_ExeName is on
+ // if so add a desktop link
+ if (!cpackPackageDesktopLinksVector.empty() &&
+ std::find(cpackPackageDesktopLinksVector.begin(),
+ cpackPackageDesktopLinksVector.end(),
+ execName) != cpackPackageDesktopLinksVector.end()) {
+ str << " StrCmp \"$INSTALL_DESKTOP\" \"1\" 0 +2\n";
+ str << " CreateShortCut \"$DESKTOP\\" << linkName
+ << ".lnk\" \"$INSTDIR\\" << cpackNsisExecutablesDirectory << "\\"
+ << execName << ".exe\"" << std::endl;
+ deleteStr << " StrCmp \"$INSTALL_DESKTOP\" \"1\" 0 +2\n";
+ deleteStr << " Delete \"$DESKTOP\\" << linkName << ".lnk\""
+ << std::endl;
+ }
+ }
+ }
+
+ this->CreateMenuLinks(str, deleteStr);
+ this->SetOptionIfNotSet("CPACK_NSIS_CREATE_ICONS", str.str().c_str());
+ this->SetOptionIfNotSet("CPACK_NSIS_DELETE_ICONS", deleteStr.str().c_str());
+
+ this->SetOptionIfNotSet("CPACK_NSIS_COMPRESSOR", "lzma");
+
+ return this->Superclass::InitializeInternal();
+}
+
+void cmCPackNSISGenerator::CreateMenuLinks(std::ostream& str,
+ std::ostream& deleteStr)
+{
+ const char* cpackMenuLinks = this->GetOption("CPACK_NSIS_MENU_LINKS");
+ if (!cpackMenuLinks) {
+ return;
+ }
+ cmCPackLogger(cmCPackLog::LOG_DEBUG,
+ "The cpackMenuLinks: " << cpackMenuLinks << "." << std::endl);
+ std::vector<std::string> cpackMenuLinksVector;
+ cmSystemTools::ExpandListArgument(cpackMenuLinks, cpackMenuLinksVector);
+ if (cpackMenuLinksVector.size() % 2 != 0) {
+ cmCPackLogger(
+ cmCPackLog::LOG_ERROR,
+ "CPACK_NSIS_MENU_LINKS should contain pairs of <shortcut target> and "
+ "<shortcut label>."
+ << std::endl);
+ return;
+ }
+
+ static cmsys::RegularExpression urlRegex(
+ "^(mailto:|(ftps?|https?|news)://).*$");
+
+ std::vector<std::string>::iterator it;
+ for (it = cpackMenuLinksVector.begin(); it != cpackMenuLinksVector.end();
+ ++it) {
+ std::string sourceName = *it;
+ const bool url = urlRegex.find(sourceName);
+
+ // Convert / to \ in filenames, but not in urls:
+ //
+ if (!url) {
+ std::replace(sourceName.begin(), sourceName.end(), '/', '\\');
+ }
+
+ ++it;
+ std::string linkName = *it;
+ if (!url) {
+ str << " CreateShortCut \"$SMPROGRAMS\\$STARTMENU_FOLDER\\" << linkName
+ << ".lnk\" \"$INSTDIR\\" << sourceName << "\"" << std::endl;
+ deleteStr << " Delete \"$SMPROGRAMS\\$MUI_TEMP\\" << linkName
+ << ".lnk\"" << std::endl;
+ } else {
+ str << " WriteINIStr \"$SMPROGRAMS\\$STARTMENU_FOLDER\\" << linkName
+ << ".url\" \"InternetShortcut\" \"URL\" \"" << sourceName << "\""
+ << std::endl;
+ deleteStr << " Delete \"$SMPROGRAMS\\$MUI_TEMP\\" << linkName
+ << ".url\"" << std::endl;
+ }
+ // see if CPACK_CREATE_DESKTOP_LINK_ExeName is on
+ // if so add a desktop link
+ std::string desktop = "CPACK_CREATE_DESKTOP_LINK_";
+ desktop += linkName;
+ if (this->IsSet(desktop)) {
+ str << " StrCmp \"$INSTALL_DESKTOP\" \"1\" 0 +2\n";
+ str << " CreateShortCut \"$DESKTOP\\" << linkName
+ << ".lnk\" \"$INSTDIR\\" << sourceName << "\"" << std::endl;
+ deleteStr << " StrCmp \"$INSTALL_DESKTOP\" \"1\" 0 +2\n";
+ deleteStr << " Delete \"$DESKTOP\\" << linkName << ".lnk\""
+ << std::endl;
+ }
+ }
+}
+
+bool cmCPackNSISGenerator::GetListOfSubdirectories(
+ const char* topdir, std::vector<std::string>& dirs)
+{
+ cmsys::Directory dir;
+ dir.Load(topdir);
+ size_t fileNum;
+ for (fileNum = 0; fileNum < dir.GetNumberOfFiles(); ++fileNum) {
+ if (strcmp(dir.GetFile(static_cast<unsigned long>(fileNum)), ".") &&
+ strcmp(dir.GetFile(static_cast<unsigned long>(fileNum)), "..")) {
+ std::string fullPath = topdir;
+ fullPath += "/";
+ fullPath += dir.GetFile(static_cast<unsigned long>(fileNum));
+ if (cmsys::SystemTools::FileIsDirectory(fullPath) &&
+ !cmsys::SystemTools::FileIsSymlink(fullPath)) {
+ if (!this->GetListOfSubdirectories(fullPath.c_str(), dirs)) {
+ return false;
+ }
+ }
+ }
+ }
+ dirs.push_back(topdir);
+ return true;
+}
+
+enum cmCPackGenerator::CPackSetDestdirSupport
+cmCPackNSISGenerator::SupportsSetDestdir() const
+{
+ return cmCPackGenerator::SETDESTDIR_SHOULD_NOT_BE_USED;
+}
+
+bool cmCPackNSISGenerator::SupportsAbsoluteDestination() const
+{
+ return false;
+}
+
+bool cmCPackNSISGenerator::SupportsComponentInstallation() const
+{
+ return true;
+}
+
+std::string cmCPackNSISGenerator::CreateComponentDescription(
+ cmCPackComponent* component, std::ostream& macrosOut)
+{
+ // Basic description of the component
+ std::string componentCode = "Section ";
+ if (component->IsDisabledByDefault) {
+ componentCode += "/o ";
+ }
+ componentCode += "\"";
+ if (component->IsHidden) {
+ componentCode += "-";
+ }
+ componentCode += component->DisplayName + "\" " + component->Name + "\n";
+ if (component->IsRequired) {
+ componentCode += " SectionIn RO\n";
+ } else if (!component->InstallationTypes.empty()) {
+ std::ostringstream out;
+ std::vector<cmCPackInstallationType*>::iterator installTypeIter;
+ for (installTypeIter = component->InstallationTypes.begin();
+ installTypeIter != component->InstallationTypes.end();
+ ++installTypeIter) {
+ out << " " << (*installTypeIter)->Index;
+ }
+ componentCode += " SectionIn" + out.str() + "\n";
+ }
+ componentCode += " SetOutPath \"$INSTDIR\"\n";
+
+ // Create the actual installation commands
+ if (component->IsDownloaded) {
+ if (component->ArchiveFile.empty()) {
+ // Compute the name of the archive.
+ std::string packagesDir = this->GetOption("CPACK_TEMPORARY_DIRECTORY");
+ packagesDir += ".dummy";
+ std::ostringstream out;
+ out << cmSystemTools::GetFilenameWithoutLastExtension(packagesDir) << "-"
+ << component->Name << ".zip";
+ component->ArchiveFile = out.str();
+ }
+
+ // Create the directory for the upload area
+ const char* userUploadDirectory =
+ this->GetOption("CPACK_UPLOAD_DIRECTORY");
+ std::string uploadDirectory;
+ if (userUploadDirectory && *userUploadDirectory) {
+ uploadDirectory = userUploadDirectory;
+ } else {
+ uploadDirectory = this->GetOption("CPACK_PACKAGE_DIRECTORY");
+ uploadDirectory += "/CPackUploads";
+ }
+ if (!cmSystemTools::FileExists(uploadDirectory.c_str())) {
+ if (!cmSystemTools::MakeDirectory(uploadDirectory.c_str())) {
+ cmCPackLogger(cmCPackLog::LOG_ERROR,
+ "Unable to create NSIS upload directory "
+ << uploadDirectory << std::endl);
+ return "";
+ }
+ }
+
+ // Remove the old archive, if one exists
+ std::string archiveFile = uploadDirectory + '/' + component->ArchiveFile;
+ cmCPackLogger(cmCPackLog::LOG_OUTPUT,
+ "- Building downloaded component archive: " << archiveFile
+ << std::endl);
+ if (cmSystemTools::FileExists(archiveFile.c_str(), true)) {
+ if (!cmSystemTools::RemoveFile(archiveFile)) {
+ cmCPackLogger(cmCPackLog::LOG_ERROR, "Unable to remove archive file "
+ << archiveFile << std::endl);
+ return "";
+ }
+ }
+
+ // Find a ZIP program
+ if (!this->IsSet("ZIP_EXECUTABLE")) {
+ this->ReadListFile("CPackZIP.cmake");
+
+ if (!this->IsSet("ZIP_EXECUTABLE")) {
+ cmCPackLogger(cmCPackLog::LOG_ERROR, "Unable to find ZIP program"
+ << std::endl);
+ return "";
+ }
+ }
+
+ // The directory where this component's files reside
+ std::string dirName = this->GetOption("CPACK_TEMPORARY_DIRECTORY");
+ dirName += '/';
+ dirName += component->Name;
+ dirName += '/';
+
+ // Build the list of files to go into this archive, and determine the
+ // size of the installed component.
+ std::string zipListFileName = this->GetOption("CPACK_TEMPORARY_DIRECTORY");
+ zipListFileName += "/winZip.filelist";
+ bool needQuotesInFile =
+ cmSystemTools::IsOn(this->GetOption("CPACK_ZIP_NEED_QUOTES"));
+ unsigned long totalSize = 0;
+ { // the scope is needed for cmGeneratedFileStream
+ cmGeneratedFileStream out(zipListFileName.c_str());
+ std::vector<std::string>::iterator fileIt;
+ for (fileIt = component->Files.begin(); fileIt != component->Files.end();
+ ++fileIt) {
+ if (needQuotesInFile) {
+ out << "\"";
+ }
+ out << *fileIt;
+ if (needQuotesInFile) {
+ out << "\"";
+ }
+ out << std::endl;
+
+ totalSize += cmSystemTools::FileLength(dirName + *fileIt);
+ }
+ }
+
+ // Build the archive in the upload area
+ std::string cmd = this->GetOption("CPACK_ZIP_COMMAND");
+ cmsys::SystemTools::ReplaceString(cmd, "<ARCHIVE>", archiveFile.c_str());
+ cmsys::SystemTools::ReplaceString(cmd, "<FILELIST>",
+ zipListFileName.c_str());
+ std::string output;
+ int retVal = -1;
+ int res = cmSystemTools::RunSingleCommand(cmd.c_str(), &output, &output,
+ &retVal, dirName.c_str(),
+ cmSystemTools::OUTPUT_NONE, 0);
+ if (!res || retVal) {
+ std::string tmpFile = this->GetOption("CPACK_TOPLEVEL_DIRECTORY");
+ tmpFile += "/CompressZip.log";
+ cmGeneratedFileStream ofs(tmpFile.c_str());
+ ofs << "# Run command: " << cmd << std::endl
+ << "# Output:" << std::endl
+ << output << std::endl;
+ cmCPackLogger(cmCPackLog::LOG_ERROR, "Problem running zip command: "
+ << cmd << std::endl
+ << "Please check " << tmpFile << " for errors"
+ << std::endl);
+ return "";
+ }
+
+ // Create the NSIS code to download this file on-the-fly.
+ unsigned long totalSizeInKbytes = (totalSize + 512) / 1024;
+ if (totalSizeInKbytes == 0) {
+ totalSizeInKbytes = 1;
+ }
+ std::ostringstream out;
+ /* clang-format off */
+ out << " AddSize " << totalSizeInKbytes << "\n"
+ << " Push \"" << component->ArchiveFile << "\"\n"
+ << " Call DownloadFile\n"
+ << " ZipDLL::extractall \"$INSTDIR\\"
+ << component->ArchiveFile << "\" \"$INSTDIR\"\n"
+ << " Pop $2 ; error message\n"
+ " StrCmp $2 \"success\" +2 0\n"
+ " MessageBox MB_OK \"Failed to unzip $2\"\n"
+ " Delete $INSTDIR\\$0\n";
+ /* clang-format on */
+ componentCode += out.str();
+ } else {
+ componentCode +=
+ " File /r \"${INST_DIR}\\" + component->Name + "\\*.*\"\n";
+ }
+ componentCode += "SectionEnd\n";
+
+ // Macro used to remove the component
+ macrosOut << "!macro Remove_${" << component->Name << "}\n";
+ macrosOut << " IntCmp $" << component->Name << "_was_installed 0 noremove_"
+ << component->Name << "\n";
+ std::vector<std::string>::iterator pathIt;
+ std::string path;
+ for (pathIt = component->Files.begin(); pathIt != component->Files.end();
+ ++pathIt) {
+ path = *pathIt;
+ std::replace(path.begin(), path.end(), '/', '\\');
+ macrosOut << " Delete \"$INSTDIR\\" << path << "\"\n";
+ }
+ for (pathIt = component->Directories.begin();
+ pathIt != component->Directories.end(); ++pathIt) {
+ path = *pathIt;
+ std::replace(path.begin(), path.end(), '/', '\\');
+ macrosOut << " RMDir \"$INSTDIR\\" << path << "\"\n";
+ }
+ macrosOut << " noremove_" << component->Name << ":\n";
+ macrosOut << "!macroend\n";
+
+ // Macro used to select each of the components that this component
+ // depends on.
+ std::set<cmCPackComponent*> visited;
+ macrosOut << "!macro Select_" << component->Name << "_depends\n";
+ macrosOut << CreateSelectionDependenciesDescription(component, visited);
+ macrosOut << "!macroend\n";
+
+ // Macro used to deselect each of the components that depend on this
+ // component.
+ visited.clear();
+ macrosOut << "!macro Deselect_required_by_" << component->Name << "\n";
+ macrosOut << CreateDeselectionDependenciesDescription(component, visited);
+ macrosOut << "!macroend\n";
+ return componentCode;
+}
+
+std::string cmCPackNSISGenerator::CreateSelectionDependenciesDescription(
+ cmCPackComponent* component, std::set<cmCPackComponent*>& visited)
+{
+ // Don't visit a component twice
+ if (visited.count(component)) {
+ return std::string();
+ }
+ visited.insert(component);
+
+ std::ostringstream out;
+ std::vector<cmCPackComponent*>::iterator dependIt;
+ for (dependIt = component->Dependencies.begin();
+ dependIt != component->Dependencies.end(); ++dependIt) {
+ // Write NSIS code to select this dependency
+ out << " SectionGetFlags ${" << (*dependIt)->Name << "} $0\n";
+ out << " IntOp $0 $0 | ${SF_SELECTED}\n";
+ out << " SectionSetFlags ${" << (*dependIt)->Name << "} $0\n";
+ out << " IntOp $" << (*dependIt)->Name
+ << "_selected 0 + ${SF_SELECTED}\n";
+ // Recurse
+ out << CreateSelectionDependenciesDescription(*dependIt, visited).c_str();
+ }
+
+ return out.str();
+}
+
+std::string cmCPackNSISGenerator::CreateDeselectionDependenciesDescription(
+ cmCPackComponent* component, std::set<cmCPackComponent*>& visited)
+{
+ // Don't visit a component twice
+ if (visited.count(component)) {
+ return std::string();
+ }
+ visited.insert(component);
+
+ std::ostringstream out;
+ std::vector<cmCPackComponent*>::iterator dependIt;
+ for (dependIt = component->ReverseDependencies.begin();
+ dependIt != component->ReverseDependencies.end(); ++dependIt) {
+ // Write NSIS code to deselect this dependency
+ out << " SectionGetFlags ${" << (*dependIt)->Name << "} $0\n";
+ out << " IntOp $1 ${SF_SELECTED} ~\n";
+ out << " IntOp $0 $0 & $1\n";
+ out << " SectionSetFlags ${" << (*dependIt)->Name << "} $0\n";
+ out << " IntOp $" << (*dependIt)->Name << "_selected 0 + 0\n";
+
+ // Recurse
+ out
+ << CreateDeselectionDependenciesDescription(*dependIt, visited).c_str();
+ }
+
+ return out.str();
+}
+
+std::string cmCPackNSISGenerator::CreateComponentGroupDescription(
+ cmCPackComponentGroup* group, std::ostream& macrosOut)
+{
+ if (group->Components.empty() && group->Subgroups.empty()) {
+ // Silently skip empty groups. NSIS doesn't support them.
+ return std::string();
+ }
+
+ std::string code = "SectionGroup ";
+ if (group->IsExpandedByDefault) {
+ code += "/e ";
+ }
+ if (group->IsBold) {
+ code += "\"!" + group->DisplayName + "\" " + group->Name + "\n";
+ } else {
+ code += "\"" + group->DisplayName + "\" " + group->Name + "\n";
+ }
+
+ std::vector<cmCPackComponentGroup*>::iterator groupIt;
+ for (groupIt = group->Subgroups.begin(); groupIt != group->Subgroups.end();
+ ++groupIt) {
+ code += this->CreateComponentGroupDescription(*groupIt, macrosOut);
+ }
+
+ std::vector<cmCPackComponent*>::iterator comp;
+ for (comp = group->Components.begin(); comp != group->Components.end();
+ ++comp) {
+ if ((*comp)->Files.empty()) {
+ continue;
+ }
+
+ code += this->CreateComponentDescription(*comp, macrosOut);
+ }
+ code += "SectionGroupEnd\n";
+ return code;
+}
+
+std::string cmCPackNSISGenerator::TranslateNewlines(std::string str)
+{
+ cmSystemTools::ReplaceString(str, "\n", "$\\r$\\n");
+ return str;
+}
diff --git a/Source/CPack/cmCPackNSISGenerator.h b/Source/CPack/cmCPackNSISGenerator.h
new file mode 100644
index 0000000..4923cf0
--- /dev/null
+++ b/Source/CPack/cmCPackNSISGenerator.h
@@ -0,0 +1,85 @@
+/*============================================================================
+ CMake - Cross Platform Makefile Generator
+ Copyright 2000-2009 Kitware, Inc.
+
+ Distributed under the OSI-approved BSD License (the "License");
+ see accompanying file Copyright.txt for details.
+
+ This software is distributed WITHOUT ANY WARRANTY; without even the
+ implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
+ See the License for more information.
+============================================================================*/
+
+#ifndef cmCPackNSISGenerator_h
+#define cmCPackNSISGenerator_h
+
+#include "cmCPackGenerator.h"
+
+#include <set>
+
+/** \class cmCPackNSISGenerator
+ * \brief A generator for NSIS files
+ *
+ * http://people.freebsd.org/~kientzle/libarchive/
+ */
+class cmCPackNSISGenerator : public cmCPackGenerator
+{
+public:
+ cmCPackTypeMacro(cmCPackNSISGenerator, cmCPackGenerator);
+
+ static cmCPackGenerator* CreateGenerator64()
+ {
+ return new cmCPackNSISGenerator(true);
+ }
+
+ /**
+ * Construct generator
+ */
+ cmCPackNSISGenerator(bool nsis64 = false);
+ ~cmCPackNSISGenerator() CM_OVERRIDE;
+
+protected:
+ int InitializeInternal() CM_OVERRIDE;
+ void CreateMenuLinks(std::ostream& str, std::ostream& deleteStr);
+ int PackageFiles() CM_OVERRIDE;
+ const char* GetOutputExtension() CM_OVERRIDE { return ".exe"; }
+ const char* GetOutputPostfix() CM_OVERRIDE { return "win32"; }
+
+ bool GetListOfSubdirectories(const char* dir,
+ std::vector<std::string>& dirs);
+
+ enum cmCPackGenerator::CPackSetDestdirSupport SupportsSetDestdir() const
+ CM_OVERRIDE;
+ bool SupportsAbsoluteDestination() const CM_OVERRIDE;
+ bool SupportsComponentInstallation() const CM_OVERRIDE;
+
+ /// Produce a string that contains the NSIS code to describe a
+ /// particular component. Any added macros will be emitted via
+ /// macrosOut.
+ std::string CreateComponentDescription(cmCPackComponent* component,
+ std::ostream& macrosOut);
+
+ /// Produce NSIS code that selects all of the components that this component
+ /// depends on, recursively.
+ std::string CreateSelectionDependenciesDescription(
+ cmCPackComponent* component, std::set<cmCPackComponent*>& visited);
+
+ /// Produce NSIS code that de-selects all of the components that are
+ /// dependent on this component, recursively.
+ std::string CreateDeselectionDependenciesDescription(
+ cmCPackComponent* component, std::set<cmCPackComponent*>& visited);
+
+ /// Produce a string that contains the NSIS code to describe a
+ /// particular component group, including its components. Any
+ /// added macros will be emitted via macrosOut.
+ std::string CreateComponentGroupDescription(cmCPackComponentGroup* group,
+ std::ostream& macrosOut);
+
+ /// Translations any newlines found in the string into \\r\\n, so that the
+ /// resulting string can be used within NSIS.
+ static std::string TranslateNewlines(std::string str);
+
+ bool Nsis64;
+};
+
+#endif
diff --git a/Source/CPack/cmCPackOSXX11Generator.cxx b/Source/CPack/cmCPackOSXX11Generator.cxx
new file mode 100644
index 0000000..c0d2553
--- /dev/null
+++ b/Source/CPack/cmCPackOSXX11Generator.cxx
@@ -0,0 +1,291 @@
+/*============================================================================
+ CMake - Cross Platform Makefile Generator
+ Copyright 2000-2009 Kitware, Inc., Insight Software Consortium
+
+ Distributed under the OSI-approved BSD License (the "License");
+ see accompanying file Copyright.txt for details.
+
+ This software is distributed WITHOUT ANY WARRANTY; without even the
+ implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
+ See the License for more information.
+============================================================================*/
+
+#include "cmCPackOSXX11Generator.h"
+
+#include "cmCPackLog.h"
+#include "cmGeneratedFileStream.h"
+#include "cmGlobalGenerator.h"
+#include "cmMakefile.h"
+#include "cmSystemTools.h"
+#include "cmake.h"
+
+#include <cmsys/Glob.hxx>
+#include <cmsys/SystemTools.hxx>
+#include <sys/stat.h>
+
+cmCPackOSXX11Generator::cmCPackOSXX11Generator()
+{
+}
+
+cmCPackOSXX11Generator::~cmCPackOSXX11Generator()
+{
+}
+
+int cmCPackOSXX11Generator::PackageFiles()
+{
+ // TODO: Use toplevel ?
+ // It is used! Is this an obsolete comment?
+
+ const char* cpackPackageExecutables =
+ this->GetOption("CPACK_PACKAGE_EXECUTABLES");
+ if (cpackPackageExecutables) {
+ cmCPackLogger(cmCPackLog::LOG_DEBUG, "The cpackPackageExecutables: "
+ << cpackPackageExecutables << "." << std::endl);
+ std::ostringstream str;
+ std::ostringstream deleteStr;
+ std::vector<std::string> cpackPackageExecutablesVector;
+ cmSystemTools::ExpandListArgument(cpackPackageExecutables,
+ cpackPackageExecutablesVector);
+ if (cpackPackageExecutablesVector.size() % 2 != 0) {
+ cmCPackLogger(
+ cmCPackLog::LOG_ERROR,
+ "CPACK_PACKAGE_EXECUTABLES should contain pairs of <executable> and "
+ "<icon name>."
+ << std::endl);
+ return 0;
+ }
+ std::vector<std::string>::iterator it;
+ for (it = cpackPackageExecutablesVector.begin();
+ it != cpackPackageExecutablesVector.end(); ++it) {
+ std::string cpackExecutableName = *it;
+ ++it;
+ this->SetOptionIfNotSet("CPACK_EXECUTABLE_NAME",
+ cpackExecutableName.c_str());
+ }
+ }
+
+ // Disk image directories
+ std::string diskImageDirectory = toplevel;
+ std::string diskImageBackgroundImageDir =
+ diskImageDirectory + "/.background";
+
+ // App bundle directories
+ std::string packageDirFileName = toplevel;
+ packageDirFileName += "/";
+ packageDirFileName += this->GetOption("CPACK_PACKAGE_FILE_NAME");
+ packageDirFileName += ".app";
+ std::string contentsDirectory = packageDirFileName + "/Contents";
+ std::string resourcesDirectory = contentsDirectory + "/Resources";
+ std::string appDirectory = contentsDirectory + "/MacOS";
+ std::string scriptDirectory = resourcesDirectory + "/Scripts";
+ std::string resourceFileName = this->GetOption("CPACK_PACKAGE_FILE_NAME");
+ resourceFileName += ".rsrc";
+
+ const char* dir = resourcesDirectory.c_str();
+ const char* appdir = appDirectory.c_str();
+ const char* scrDir = scriptDirectory.c_str();
+ const char* contDir = contentsDirectory.c_str();
+ const char* rsrcFile = resourceFileName.c_str();
+ const char* iconFile = this->GetOption("CPACK_PACKAGE_ICON");
+ if (iconFile) {
+ std::string iconFileName = cmsys::SystemTools::GetFilenameName(iconFile);
+ if (!cmSystemTools::FileExists(iconFile)) {
+ cmCPackLogger(cmCPackLog::LOG_ERROR, "Cannot find icon file: "
+ << iconFile
+ << ". Please check CPACK_PACKAGE_ICON setting."
+ << std::endl);
+ return 0;
+ }
+ std::string destFileName = resourcesDirectory + "/" + iconFileName;
+ this->ConfigureFile(iconFile, destFileName.c_str(), true);
+ this->SetOptionIfNotSet("CPACK_APPLE_GUI_ICON", iconFileName.c_str());
+ }
+
+ std::string applicationsLinkName = diskImageDirectory + "/Applications";
+ cmSystemTools::CreateSymlink("/Applications", applicationsLinkName.c_str());
+
+ if (!this->CopyResourcePlistFile("VolumeIcon.icns",
+ diskImageDirectory.c_str(),
+ ".VolumeIcon.icns", true) ||
+ !this->CopyResourcePlistFile("DS_Store", diskImageDirectory.c_str(),
+ ".DS_Store", true) ||
+ !this->CopyResourcePlistFile("background.png",
+ diskImageBackgroundImageDir.c_str(),
+ "background.png", true) ||
+ !this->CopyResourcePlistFile("RuntimeScript", dir) ||
+ !this->CopyResourcePlistFile("OSXX11.Info.plist", contDir,
+ "Info.plist") ||
+ !this->CopyResourcePlistFile("OSXX11.main.scpt", scrDir, "main.scpt",
+ true) ||
+ !this->CopyResourcePlistFile("OSXScriptLauncher.rsrc", dir, rsrcFile,
+ true) ||
+ !this->CopyResourcePlistFile("OSXScriptLauncher", appdir,
+ this->GetOption("CPACK_PACKAGE_FILE_NAME"),
+ true)) {
+ cmCPackLogger(cmCPackLog::LOG_ERROR, "Problem copying the resource files"
+ << std::endl);
+ return 0;
+ }
+
+ // Two of the files need to have execute permission, so ensure they do:
+ std::string runTimeScript = dir;
+ runTimeScript += "/";
+ runTimeScript += "RuntimeScript";
+
+ std::string appScriptName = appdir;
+ appScriptName += "/";
+ appScriptName += this->GetOption("CPACK_PACKAGE_FILE_NAME");
+
+ mode_t mode;
+ if (cmsys::SystemTools::GetPermissions(runTimeScript.c_str(), mode)) {
+ mode |= (S_IXUSR | S_IXGRP | S_IXOTH);
+ cmsys::SystemTools::SetPermissions(runTimeScript.c_str(), mode);
+ cmCPackLogger(cmCPackLog::LOG_OUTPUT,
+ "Setting: " << runTimeScript << " to permission: " << mode
+ << std::endl);
+ }
+
+ if (cmsys::SystemTools::GetPermissions(appScriptName.c_str(), mode)) {
+ mode |= (S_IXUSR | S_IXGRP | S_IXOTH);
+ cmsys::SystemTools::SetPermissions(appScriptName.c_str(), mode);
+ cmCPackLogger(cmCPackLog::LOG_OUTPUT,
+ "Setting: " << appScriptName << " to permission: " << mode
+ << std::endl);
+ }
+
+ std::string output;
+ std::string tmpFile = this->GetOption("CPACK_TOPLEVEL_DIRECTORY");
+ tmpFile += "/hdiutilOutput.log";
+ std::ostringstream dmgCmd;
+ dmgCmd << "\"" << this->GetOption("CPACK_INSTALLER_PROGRAM_DISK_IMAGE")
+ << "\" create -ov -format UDZO -srcfolder \"" << diskImageDirectory
+ << "\" \"" << packageFileNames[0] << "\"";
+ cmCPackLogger(cmCPackLog::LOG_VERBOSE, "Compress disk image using command: "
+ << dmgCmd.str() << std::endl);
+ // since we get random dashboard failures with this one
+ // try running it more than once
+ int retVal = 1;
+ int numTries = 10;
+ bool res = false;
+ while (numTries > 0) {
+ res =
+ cmSystemTools::RunSingleCommand(dmgCmd.str().c_str(), &output, &output,
+ &retVal, 0, this->GeneratorVerbose, 0);
+ if (res && !retVal) {
+ numTries = -1;
+ break;
+ }
+ cmSystemTools::Delay(500);
+ numTries--;
+ }
+ if (!res || retVal) {
+ cmGeneratedFileStream ofs(tmpFile.c_str());
+ ofs << "# Run command: " << dmgCmd.str() << std::endl
+ << "# Output:" << std::endl
+ << output << std::endl;
+ cmCPackLogger(cmCPackLog::LOG_ERROR, "Problem running hdiutil command: "
+ << dmgCmd.str() << std::endl
+ << "Please check " << tmpFile << " for errors"
+ << std::endl);
+ return 0;
+ }
+
+ return 1;
+}
+
+int cmCPackOSXX11Generator::InitializeInternal()
+{
+ cmCPackLogger(cmCPackLog::LOG_DEBUG, "cmCPackOSXX11Generator::Initialize()"
+ << std::endl);
+ std::vector<std::string> path;
+ std::string pkgPath = cmSystemTools::FindProgram("hdiutil", path, false);
+ if (pkgPath.empty()) {
+ cmCPackLogger(cmCPackLog::LOG_ERROR, "Cannot find hdiutil compiler"
+ << std::endl);
+ return 0;
+ }
+ this->SetOptionIfNotSet("CPACK_INSTALLER_PROGRAM_DISK_IMAGE",
+ pkgPath.c_str());
+
+ return this->Superclass::InitializeInternal();
+}
+
+/*
+bool cmCPackOSXX11Generator::CopyCreateResourceFile(const std::string& name)
+{
+ std::string uname = cmSystemTools::UpperCase(name);
+ std::string cpackVar = "CPACK_RESOURCE_FILE_" + uname;
+ const char* inFileName = this->GetOption(cpackVar.c_str());
+ if ( !inFileName )
+ {
+ cmCPackLogger(cmCPackLog::LOG_ERROR, "CPack option: " << cpackVar.c_str()
+ << " not specified. It should point to "
+ << (name ? name : "(NULL)")
+ << ".rtf, " << name
+ << ".html, or " << name << ".txt file" << std::endl);
+ return false;
+ }
+ if ( !cmSystemTools::FileExists(inFileName) )
+ {
+ cmCPackLogger(cmCPackLog::LOG_ERROR, "Cannot find "
+ << (name ? name : "(NULL)")
+ << " resource file: " << inFileName << std::endl);
+ return false;
+ }
+ std::string ext = cmSystemTools::GetFilenameLastExtension(inFileName);
+ if ( ext != ".rtfd" && ext != ".rtf" && ext != ".html" && ext != ".txt" )
+ {
+ cmCPackLogger(cmCPackLog::LOG_ERROR, "Bad file extension specified: "
+ << ext << ". Currently only .rtfd, .rtf, .html, and .txt files allowed."
+ << std::endl);
+ return false;
+ }
+
+ std::string destFileName = this->GetOption("CPACK_TOPLEVEL_DIRECTORY");
+ destFileName += "/Resources/";
+ destFileName += name + ext;
+
+
+ cmCPackLogger(cmCPackLog::LOG_VERBOSE, "Configure file: "
+ << (inFileName ? inFileName : "(NULL)")
+ << " to " << destFileName << std::endl);
+ this->ConfigureFile(inFileName, destFileName.c_str());
+ return true;
+}
+*/
+
+bool cmCPackOSXX11Generator::CopyResourcePlistFile(
+ const std::string& name, const std::string& dir,
+ const char* outputFileName /* = 0 */, bool copyOnly /* = false */)
+{
+ std::string inFName = "CPack.";
+ inFName += name;
+ inFName += ".in";
+ std::string inFileName = this->FindTemplate(inFName.c_str());
+ if (inFileName.empty()) {
+ cmCPackLogger(cmCPackLog::LOG_ERROR,
+ "Cannot find input file: " << inFName << std::endl);
+ return false;
+ }
+
+ if (!outputFileName) {
+ outputFileName = name.c_str();
+ }
+
+ std::string destFileName = dir;
+ destFileName += "/";
+ destFileName += outputFileName;
+
+ cmCPackLogger(cmCPackLog::LOG_VERBOSE, "Configure file: "
+ << inFileName << " to " << destFileName << std::endl);
+ this->ConfigureFile(inFileName.c_str(), destFileName.c_str(), copyOnly);
+ return true;
+}
+
+const char* cmCPackOSXX11Generator::GetPackagingInstallPrefix()
+{
+ this->InstallPrefix = "/";
+ this->InstallPrefix += this->GetOption("CPACK_PACKAGE_FILE_NAME");
+ this->InstallPrefix += ".app/Contents/Resources";
+ return this->InstallPrefix.c_str();
+}
diff --git a/Source/CPack/cmCPackOSXX11Generator.h b/Source/CPack/cmCPackOSXX11Generator.h
new file mode 100644
index 0000000..d1d6789
--- /dev/null
+++ b/Source/CPack/cmCPackOSXX11Generator.h
@@ -0,0 +1,48 @@
+/*============================================================================
+ CMake - Cross Platform Makefile Generator
+ Copyright 2000-2009 Kitware, Inc.
+
+ Distributed under the OSI-approved BSD License (the "License");
+ see accompanying file Copyright.txt for details.
+
+ This software is distributed WITHOUT ANY WARRANTY; without even the
+ implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
+ See the License for more information.
+============================================================================*/
+
+#ifndef cmCPackOSXX11Generator_h
+#define cmCPackOSXX11Generator_h
+
+#include "cmCPackGenerator.h"
+
+/** \class cmCPackOSXX11Generator
+ * \brief A generator for OSX X11 modules
+ *
+ * Based on Gimp.app
+ */
+class cmCPackOSXX11Generator : public cmCPackGenerator
+{
+public:
+ cmCPackTypeMacro(cmCPackOSXX11Generator, cmCPackGenerator);
+
+ /**
+ * Construct generator
+ */
+ cmCPackOSXX11Generator();
+ virtual ~cmCPackOSXX11Generator();
+
+protected:
+ virtual int InitializeInternal() CM_OVERRIDE;
+ int PackageFiles() CM_OVERRIDE;
+ const char* GetPackagingInstallPrefix() CM_OVERRIDE;
+ const char* GetOutputExtension() CM_OVERRIDE { return ".dmg"; }
+
+ // bool CopyCreateResourceFile(const std::string& name,
+ // const std::string& dir);
+ bool CopyResourcePlistFile(const std::string& name, const std::string& dir,
+ const char* outputFileName = 0,
+ bool copyOnly = false);
+ std::string InstallPrefix;
+};
+
+#endif
diff --git a/Source/CPack/cmCPackPKGGenerator.cxx b/Source/CPack/cmCPackPKGGenerator.cxx
new file mode 100644
index 0000000..19b587a
--- /dev/null
+++ b/Source/CPack/cmCPackPKGGenerator.cxx
@@ -0,0 +1,367 @@
+/*============================================================================
+ CMake - Cross Platform Makefile Generator
+ Copyright 2000-2009 Kitware, Inc., Insight Software Consortium
+
+ Distributed under the OSI-approved BSD License (the "License");
+ see accompanying file Copyright.txt for details.
+
+ This software is distributed WITHOUT ANY WARRANTY; without even the
+ implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
+ See the License for more information.
+============================================================================*/
+#include "cmCPackPKGGenerator.h"
+
+#include "cmCPackComponentGroup.h"
+#include "cmCPackLog.h"
+#include "cmGeneratedFileStream.h"
+#include "cmGlobalGenerator.h"
+#include "cmLocalGenerator.h"
+#include "cmMakefile.h"
+#include "cmSystemTools.h"
+#include "cmXMLWriter.h"
+#include "cmake.h"
+
+#include <cmsys/Glob.hxx>
+#include <cmsys/SystemTools.hxx>
+
+cmCPackPKGGenerator::cmCPackPKGGenerator()
+{
+ this->componentPackageMethod = ONE_PACKAGE;
+}
+
+cmCPackPKGGenerator::~cmCPackPKGGenerator()
+{
+}
+
+bool cmCPackPKGGenerator::SupportsComponentInstallation() const
+{
+ return true;
+}
+
+int cmCPackPKGGenerator::InitializeInternal()
+{
+ cmCPackLogger(cmCPackLog::LOG_DEBUG, "cmCPackPKGGenerator::Initialize()"
+ << std::endl);
+
+ return this->Superclass::InitializeInternal();
+}
+
+std::string cmCPackPKGGenerator::GetPackageName(
+ const cmCPackComponent& component)
+{
+ if (component.ArchiveFile.empty()) {
+ std::string packagesDir = this->GetOption("CPACK_TEMPORARY_DIRECTORY");
+ packagesDir += ".dummy";
+ std::ostringstream out;
+ out << cmSystemTools::GetFilenameWithoutLastExtension(packagesDir) << "-"
+ << component.Name << ".pkg";
+ return out.str();
+ } else {
+ return component.ArchiveFile + ".pkg";
+ }
+}
+
+void cmCPackPKGGenerator::WriteDistributionFile(const char* metapackageFile)
+{
+ std::string distributionTemplate =
+ this->FindTemplate("CPack.distribution.dist.in");
+ if (distributionTemplate.empty()) {
+ cmCPackLogger(cmCPackLog::LOG_ERROR, "Cannot find input file: "
+ << distributionTemplate << std::endl);
+ return;
+ }
+
+ std::string distributionFile = metapackageFile;
+ distributionFile += "/Contents/distribution.dist";
+
+ // Create the choice outline, which provides a tree-based view of
+ // the components in their groups.
+ std::ostringstream choiceOut;
+ cmXMLWriter xout(choiceOut, 1);
+ xout.StartElement("choices-outline");
+
+ // Emit the outline for the groups
+ std::map<std::string, cmCPackComponentGroup>::iterator groupIt;
+ for (groupIt = this->ComponentGroups.begin();
+ groupIt != this->ComponentGroups.end(); ++groupIt) {
+ if (groupIt->second.ParentGroup == 0) {
+ CreateChoiceOutline(groupIt->second, xout);
+ }
+ }
+
+ // Emit the outline for the non-grouped components
+ std::map<std::string, cmCPackComponent>::iterator compIt;
+ for (compIt = this->Components.begin(); compIt != this->Components.end();
+ ++compIt) {
+ if (!compIt->second.Group) {
+ xout.StartElement("line");
+ xout.Attribute("choice", compIt->first + "Choice");
+ xout.Content(""); // Avoid self-closing tag.
+ xout.EndElement();
+ }
+ }
+ if (!this->PostFlightComponent.Name.empty()) {
+ xout.StartElement("line");
+ xout.Attribute("choice", PostFlightComponent.Name + "Choice");
+ xout.Content(""); // Avoid self-closing tag.
+ xout.EndElement();
+ }
+ xout.EndElement(); // choices-outline>
+
+ // Create the actual choices
+ for (groupIt = this->ComponentGroups.begin();
+ groupIt != this->ComponentGroups.end(); ++groupIt) {
+ CreateChoice(groupIt->second, xout);
+ }
+ for (compIt = this->Components.begin(); compIt != this->Components.end();
+ ++compIt) {
+ CreateChoice(compIt->second, xout);
+ }
+
+ if (!this->PostFlightComponent.Name.empty()) {
+ CreateChoice(PostFlightComponent, xout);
+ }
+
+ this->SetOption("CPACK_PACKAGEMAKER_CHOICES", choiceOut.str().c_str());
+
+ // Create the distribution.dist file in the metapackage to turn it
+ // into a distribution package.
+ this->ConfigureFile(distributionTemplate.c_str(), distributionFile.c_str());
+}
+
+void cmCPackPKGGenerator::CreateChoiceOutline(
+ const cmCPackComponentGroup& group, cmXMLWriter& xout)
+{
+ xout.StartElement("line");
+ xout.Attribute("choice", group.Name + "Choice");
+ std::vector<cmCPackComponentGroup*>::const_iterator groupIt;
+ for (groupIt = group.Subgroups.begin(); groupIt != group.Subgroups.end();
+ ++groupIt) {
+ CreateChoiceOutline(**groupIt, xout);
+ }
+
+ std::vector<cmCPackComponent*>::const_iterator compIt;
+ for (compIt = group.Components.begin(); compIt != group.Components.end();
+ ++compIt) {
+ xout.StartElement("line");
+ xout.Attribute("choice", (*compIt)->Name + "Choice");
+ xout.Content(""); // Avoid self-closing tag.
+ xout.EndElement();
+ }
+ xout.EndElement();
+}
+
+void cmCPackPKGGenerator::CreateChoice(const cmCPackComponentGroup& group,
+ cmXMLWriter& xout)
+{
+ xout.StartElement("choice");
+ xout.Attribute("id", group.Name + "Choice");
+ xout.Attribute("title", group.DisplayName);
+ xout.Attribute("start_selected", "true");
+ xout.Attribute("start_enabled", "true");
+ xout.Attribute("start_visible", "true");
+ if (!group.Description.empty()) {
+ xout.Attribute("description", group.Description);
+ }
+ xout.EndElement();
+}
+
+void cmCPackPKGGenerator::CreateChoice(const cmCPackComponent& component,
+ cmXMLWriter& xout)
+{
+ std::string packageId = "com.";
+ packageId += this->GetOption("CPACK_PACKAGE_VENDOR");
+ packageId += '.';
+ packageId += this->GetOption("CPACK_PACKAGE_NAME");
+ packageId += '.';
+ packageId += component.Name;
+
+ xout.StartElement("choice");
+ xout.Attribute("id", component.Name + "Choice");
+ xout.Attribute("title", component.DisplayName);
+ xout.Attribute(
+ "start_selected",
+ component.IsDisabledByDefault && !component.IsRequired ? "false" : "true");
+ xout.Attribute("start_enabled", component.IsRequired ? "false" : "true");
+ xout.Attribute("start_visible", component.IsHidden ? "false" : "true");
+ if (!component.Description.empty()) {
+ xout.Attribute("description", component.Description);
+ }
+ if (!component.Dependencies.empty() ||
+ !component.ReverseDependencies.empty()) {
+ // The "selected" expression is evaluated each time any choice is
+ // selected, for all choices *except* the one that the user
+ // selected. A component is marked selected if it has been
+ // selected (my.choice.selected in Javascript) and all of the
+ // components it depends on have been selected (transitively) or
+ // if any of the components that depend on it have been selected
+ // (transitively). Assume that we have components A, B, C, D, and
+ // E, where each component depends on the previous component (B
+ // depends on A, C depends on B, D depends on C, and E depends on
+ // D). The expression we build for the component C will be
+ // my.choice.selected && B && A || D || E
+ // This way, selecting C will automatically select everything it depends
+ // on (B and A), while selecting something that depends on C--either D
+ // or E--will automatically cause C to get selected.
+ std::ostringstream selected("my.choice.selected");
+ std::set<const cmCPackComponent*> visited;
+ AddDependencyAttributes(component, visited, selected);
+ visited.clear();
+ AddReverseDependencyAttributes(component, visited, selected);
+ xout.Attribute("selected", selected.str());
+ }
+ xout.StartElement("pkg-ref");
+ xout.Attribute("id", packageId);
+ xout.EndElement(); // pkg-ref
+ xout.EndElement(); // choice
+
+ // Create a description of the package associated with this
+ // component.
+ std::string relativePackageLocation = "Contents/Packages/";
+ relativePackageLocation += this->GetPackageName(component);
+
+ // Determine the installed size of the package.
+ std::string dirName = this->GetOption("CPACK_TEMPORARY_DIRECTORY");
+ dirName += '/';
+ dirName += component.Name;
+ dirName += this->GetOption("CPACK_PACKAGING_INSTALL_PREFIX");
+ unsigned long installedSize =
+ component.GetInstalledSizeInKbytes(dirName.c_str());
+
+ xout.StartElement("pkg-ref");
+ xout.Attribute("id", packageId);
+ xout.Attribute("version", this->GetOption("CPACK_PACKAGE_VERSION"));
+ xout.Attribute("installKBytes", installedSize);
+ xout.Attribute("auth", "Admin");
+ xout.Attribute("onConclusion", "None");
+ if (component.IsDownloaded) {
+ xout.Content(this->GetOption("CPACK_DOWNLOAD_SITE"));
+ xout.Content(this->GetPackageName(component));
+ } else {
+ xout.Content("file:./");
+ xout.Content(relativePackageLocation);
+ }
+ xout.EndElement(); // pkg-ref
+}
+
+void cmCPackPKGGenerator::AddDependencyAttributes(
+ const cmCPackComponent& component,
+ std::set<const cmCPackComponent*>& visited, std::ostringstream& out)
+{
+ if (visited.find(&component) != visited.end()) {
+ return;
+ }
+ visited.insert(&component);
+
+ std::vector<cmCPackComponent*>::const_iterator dependIt;
+ for (dependIt = component.Dependencies.begin();
+ dependIt != component.Dependencies.end(); ++dependIt) {
+ out << " && choices['" << (*dependIt)->Name << "Choice'].selected";
+ AddDependencyAttributes(**dependIt, visited, out);
+ }
+}
+
+void cmCPackPKGGenerator::AddReverseDependencyAttributes(
+ const cmCPackComponent& component,
+ std::set<const cmCPackComponent*>& visited, std::ostringstream& out)
+{
+ if (visited.find(&component) != visited.end()) {
+ return;
+ }
+ visited.insert(&component);
+
+ std::vector<cmCPackComponent*>::const_iterator dependIt;
+ for (dependIt = component.ReverseDependencies.begin();
+ dependIt != component.ReverseDependencies.end(); ++dependIt) {
+ out << " || choices['" << (*dependIt)->Name << "Choice'].selected";
+ AddReverseDependencyAttributes(**dependIt, visited, out);
+ }
+}
+
+bool cmCPackPKGGenerator::CopyCreateResourceFile(const std::string& name,
+ const std::string& dirName)
+{
+ std::string uname = cmSystemTools::UpperCase(name);
+ std::string cpackVar = "CPACK_RESOURCE_FILE_" + uname;
+ const char* inFileName = this->GetOption(cpackVar.c_str());
+ if (!inFileName) {
+ cmCPackLogger(cmCPackLog::LOG_ERROR, "CPack option: "
+ << cpackVar.c_str()
+ << " not specified. It should point to "
+ << (!name.empty() ? name : "<empty>") << ".rtf, " << name
+ << ".html, or " << name << ".txt file" << std::endl);
+ return false;
+ }
+ if (!cmSystemTools::FileExists(inFileName)) {
+ cmCPackLogger(cmCPackLog::LOG_ERROR, "Cannot find "
+ << (!name.empty() ? name : "<empty>")
+ << " resource file: " << inFileName << std::endl);
+ return false;
+ }
+ std::string ext = cmSystemTools::GetFilenameLastExtension(inFileName);
+ if (ext != ".rtfd" && ext != ".rtf" && ext != ".html" && ext != ".txt") {
+ cmCPackLogger(
+ cmCPackLog::LOG_ERROR, "Bad file extension specified: "
+ << ext
+ << ". Currently only .rtfd, .rtf, .html, and .txt files allowed."
+ << std::endl);
+ return false;
+ }
+
+ std::string destFileName = dirName;
+ destFileName += '/';
+ destFileName += name + ext;
+
+ // Set this so that distribution.dist gets the right name (without
+ // the path).
+ this->SetOption(("CPACK_RESOURCE_FILE_" + uname + "_NOPATH").c_str(),
+ (name + ext).c_str());
+
+ cmCPackLogger(cmCPackLog::LOG_VERBOSE,
+ "Configure file: " << (inFileName ? inFileName : "(NULL)")
+ << " to " << destFileName << std::endl);
+ this->ConfigureFile(inFileName, destFileName.c_str());
+ return true;
+}
+
+bool cmCPackPKGGenerator::CopyResourcePlistFile(const std::string& name,
+ const char* outName)
+{
+ if (!outName) {
+ outName = name.c_str();
+ }
+
+ std::string inFName = "CPack.";
+ inFName += name;
+ inFName += ".in";
+ std::string inFileName = this->FindTemplate(inFName.c_str());
+ if (inFileName.empty()) {
+ cmCPackLogger(cmCPackLog::LOG_ERROR,
+ "Cannot find input file: " << inFName << std::endl);
+ return false;
+ }
+
+ std::string destFileName = this->GetOption("CPACK_TOPLEVEL_DIRECTORY");
+ destFileName += "/";
+ destFileName += outName;
+
+ cmCPackLogger(cmCPackLog::LOG_VERBOSE, "Configure file: "
+ << inFileName << " to " << destFileName << std::endl);
+ this->ConfigureFile(inFileName.c_str(), destFileName.c_str());
+ return true;
+}
+
+int cmCPackPKGGenerator::CopyInstallScript(const std::string& resdir,
+ const std::string& script,
+ const std::string& name)
+{
+ std::string dst = resdir;
+ dst += "/";
+ dst += name;
+ cmSystemTools::CopyFileAlways(script.c_str(), dst.c_str());
+ cmSystemTools::SetPermissions(dst.c_str(), 0777);
+ cmCPackLogger(cmCPackLog::LOG_VERBOSE,
+ "copy script : " << script << "\ninto " << dst << std::endl);
+
+ return 1;
+}
diff --git a/Source/CPack/cmCPackPKGGenerator.h b/Source/CPack/cmCPackPKGGenerator.h
new file mode 100644
index 0000000..d2135cc
--- /dev/null
+++ b/Source/CPack/cmCPackPKGGenerator.h
@@ -0,0 +1,96 @@
+/*============================================================================
+ CMake - Cross Platform Makefile Generator
+ Copyright 2000-2009 Kitware, Inc.
+
+ Distributed under the OSI-approved BSD License (the "License");
+ see accompanying file Copyright.txt for details.
+
+ This software is distributed WITHOUT ANY WARRANTY; without even the
+ implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
+ See the License for more information.
+============================================================================*/
+
+#ifndef cmCPackPKGGenerator_h
+#define cmCPackPKGGenerator_h
+
+#include "cmCPackGenerator.h"
+
+class cmCPackComponent;
+class cmXMLWriter;
+
+/** \class cmCPackPKGGenerator
+ * \brief A generator for pkg files
+ *
+ */
+class cmCPackPKGGenerator : public cmCPackGenerator
+{
+public:
+ cmCPackTypeMacro(cmCPackPKGGenerator, cmCPackGenerator);
+
+ /**
+ * Construct generator
+ */
+ cmCPackPKGGenerator();
+ virtual ~cmCPackPKGGenerator();
+
+ bool SupportsComponentInstallation() const CM_OVERRIDE;
+
+protected:
+ int InitializeInternal() CM_OVERRIDE;
+ const char* GetOutputPostfix() CM_OVERRIDE { return "darwin"; }
+
+ // Copies or creates the resource file with the given name to the
+ // package or package staging directory dirName. The variable
+ // CPACK_RESOURCE_FILE_${NAME} (where ${NAME} is the uppercased
+ // version of name) specifies the input file to use for this file,
+ // which will be configured via ConfigureFile.
+ bool CopyCreateResourceFile(const std::string& name,
+ const std::string& dirName);
+ bool CopyResourcePlistFile(const std::string& name, const char* outName = 0);
+
+ int CopyInstallScript(const std::string& resdir, const std::string& script,
+ const std::string& name);
+
+ // Retrieve the name of package file that will be generated for this
+ // component. The name is just the file name with extension, and
+ // does not include the subdirectory.
+ std::string GetPackageName(const cmCPackComponent& component);
+
+ // Writes a distribution.dist file, which turns a metapackage into a
+ // full-fledged distribution. This file is used to describe
+ // inter-component dependencies. metapackageFile is the name of the
+ // metapackage for the distribution. Only valid for a
+ // component-based install.
+ void WriteDistributionFile(const char* metapackageFile);
+
+ // Subroutine of WriteDistributionFile that writes out the
+ // dependency attributes for inter-component dependencies.
+ void AddDependencyAttributes(const cmCPackComponent& component,
+ std::set<const cmCPackComponent*>& visited,
+ std::ostringstream& out);
+
+ // Subroutine of WriteDistributionFile that writes out the
+ // reverse dependency attributes for inter-component dependencies.
+ void AddReverseDependencyAttributes(
+ const cmCPackComponent& component,
+ std::set<const cmCPackComponent*>& visited, std::ostringstream& out);
+
+ // Generates XML that encodes the hierarchy of component groups and
+ // their components in a form that can be used by distribution
+ // metapackages.
+ void CreateChoiceOutline(const cmCPackComponentGroup& group,
+ cmXMLWriter& xout);
+
+ /// Create the "choice" XML element to describe a component group
+ /// for the installer GUI.
+ void CreateChoice(const cmCPackComponentGroup& group, cmXMLWriter& xout);
+
+ /// Create the "choice" XML element to describe a component for the
+ /// installer GUI.
+ void CreateChoice(const cmCPackComponent& component, cmXMLWriter& xout);
+
+ // The PostFlight component when creating a metapackage
+ cmCPackComponent PostFlightComponent;
+};
+
+#endif
diff --git a/Source/CPack/cmCPackPackageMakerGenerator.cxx b/Source/CPack/cmCPackPackageMakerGenerator.cxx
new file mode 100644
index 0000000..ce329ca
--- /dev/null
+++ b/Source/CPack/cmCPackPackageMakerGenerator.cxx
@@ -0,0 +1,584 @@
+/*============================================================================
+ CMake - Cross Platform Makefile Generator
+ Copyright 2000-2009 Kitware, Inc., Insight Software Consortium
+
+ Distributed under the OSI-approved BSD License (the "License");
+ see accompanying file Copyright.txt for details.
+
+ This software is distributed WITHOUT ANY WARRANTY; without even the
+ implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
+ See the License for more information.
+============================================================================*/
+#include "cmCPackPackageMakerGenerator.h"
+
+#include "cmCPackComponentGroup.h"
+#include "cmCPackLog.h"
+#include "cmGeneratedFileStream.h"
+#include "cmGlobalGenerator.h"
+#include "cmMakefile.h"
+#include "cmSystemTools.h"
+#include "cmXMLWriter.h"
+#include "cmake.h"
+
+#include <cmsys/FStream.hxx>
+#include <cmsys/Glob.hxx>
+#include <cmsys/SystemTools.hxx>
+
+#include <assert.h>
+
+static inline unsigned int getVersion(unsigned int major, unsigned int minor)
+{
+ assert(major < 256 && minor < 256);
+ return ((major & 0xFF) << 16 | minor);
+}
+
+cmCPackPackageMakerGenerator::cmCPackPackageMakerGenerator()
+{
+ this->PackageMakerVersion = 0.0;
+ this->PackageCompatibilityVersion = getVersion(10, 4);
+}
+
+cmCPackPackageMakerGenerator::~cmCPackPackageMakerGenerator()
+{
+}
+
+bool cmCPackPackageMakerGenerator::SupportsComponentInstallation() const
+{
+ return this->PackageCompatibilityVersion >= getVersion(10, 4);
+}
+
+int cmCPackPackageMakerGenerator::PackageFiles()
+{
+ // TODO: Use toplevel
+ // It is used! Is this an obsolete comment?
+
+ std::string resDir; // Where this package's resources will go.
+ std::string packageDirFileName =
+ this->GetOption("CPACK_TEMPORARY_DIRECTORY");
+ if (this->Components.empty()) {
+ packageDirFileName += ".pkg";
+ resDir = this->GetOption("CPACK_TOPLEVEL_DIRECTORY");
+ resDir += "/Resources";
+ } else {
+ packageDirFileName += ".mpkg";
+ if (!cmsys::SystemTools::MakeDirectory(packageDirFileName.c_str())) {
+ cmCPackLogger(cmCPackLog::LOG_ERROR,
+ "unable to create package directory " << packageDirFileName
+ << std::endl);
+ return 0;
+ }
+
+ resDir = packageDirFileName;
+ resDir += "/Contents";
+ if (!cmsys::SystemTools::MakeDirectory(resDir.c_str())) {
+ cmCPackLogger(cmCPackLog::LOG_ERROR,
+ "unable to create package subdirectory " << resDir
+ << std::endl);
+ return 0;
+ }
+
+ resDir += "/Resources";
+ if (!cmsys::SystemTools::MakeDirectory(resDir.c_str())) {
+ cmCPackLogger(cmCPackLog::LOG_ERROR,
+ "unable to create package subdirectory " << resDir
+ << std::endl);
+ return 0;
+ }
+
+ resDir += "/en.lproj";
+ }
+
+ const char* preflight = this->GetOption("CPACK_PREFLIGHT_SCRIPT");
+ const char* postflight = this->GetOption("CPACK_POSTFLIGHT_SCRIPT");
+ const char* postupgrade = this->GetOption("CPACK_POSTUPGRADE_SCRIPT");
+
+ if (this->Components.empty()) {
+ // Create directory structure
+ std::string preflightDirName = resDir + "/PreFlight";
+ std::string postflightDirName = resDir + "/PostFlight";
+ // if preflight or postflight scripts not there create directories
+ // of the same name, I think this makes it work
+ if (!preflight) {
+ if (!cmsys::SystemTools::MakeDirectory(preflightDirName.c_str())) {
+ cmCPackLogger(cmCPackLog::LOG_ERROR,
+ "Problem creating installer directory: "
+ << preflightDirName << std::endl);
+ return 0;
+ }
+ }
+ if (!postflight) {
+ if (!cmsys::SystemTools::MakeDirectory(postflightDirName.c_str())) {
+ cmCPackLogger(cmCPackLog::LOG_ERROR,
+ "Problem creating installer directory: "
+ << postflightDirName << std::endl);
+ return 0;
+ }
+ }
+ // if preflight, postflight, or postupgrade are set
+ // then copy them into the resource directory and make
+ // them executable
+ if (preflight) {
+ this->CopyInstallScript(resDir.c_str(), preflight, "preflight");
+ }
+ if (postflight) {
+ this->CopyInstallScript(resDir.c_str(), postflight, "postflight");
+ }
+ if (postupgrade) {
+ this->CopyInstallScript(resDir.c_str(), postupgrade, "postupgrade");
+ }
+ } else if (postflight) {
+ // create a postflight component to house the script
+ this->PostFlightComponent.Name = "PostFlight";
+ this->PostFlightComponent.DisplayName = "PostFlight";
+ this->PostFlightComponent.Description = "PostFlight";
+ this->PostFlightComponent.IsHidden = true;
+
+ // empty directory for pkg contents
+ std::string packageDir = toplevel + "/" + PostFlightComponent.Name;
+ if (!cmsys::SystemTools::MakeDirectory(packageDir.c_str())) {
+ cmCPackLogger(cmCPackLog::LOG_ERROR,
+ "Problem creating component packages directory: "
+ << packageDir << std::endl);
+ return 0;
+ }
+
+ // create package
+ std::string packageFileDir = packageDirFileName + "/Contents/Packages/";
+ if (!cmsys::SystemTools::MakeDirectory(packageFileDir.c_str())) {
+ cmCPackLogger(
+ cmCPackLog::LOG_ERROR,
+ "Problem creating component PostFlight Packages directory: "
+ << packageFileDir << std::endl);
+ return 0;
+ }
+ std::string packageFile =
+ packageFileDir + this->GetPackageName(PostFlightComponent);
+ if (!this->GenerateComponentPackage(
+ packageFile.c_str(), packageDir.c_str(), PostFlightComponent)) {
+ return 0;
+ }
+
+ // copy postflight script into resource directory of .pkg
+ std::string resourceDir = packageFile + "/Contents/Resources";
+ this->CopyInstallScript(resourceDir.c_str(), postflight, "postflight");
+ }
+
+ if (!this->Components.empty()) {
+ // Create the directory where component packages will be built.
+ std::string basePackageDir = packageDirFileName;
+ basePackageDir += "/Contents/Packages";
+ if (!cmsys::SystemTools::MakeDirectory(basePackageDir.c_str())) {
+ cmCPackLogger(cmCPackLog::LOG_ERROR,
+ "Problem creating component packages directory: "
+ << basePackageDir << std::endl);
+ return 0;
+ }
+
+ // Create the directory where downloaded component packages will
+ // be placed.
+ const char* userUploadDirectory =
+ this->GetOption("CPACK_UPLOAD_DIRECTORY");
+ std::string uploadDirectory;
+ if (userUploadDirectory && *userUploadDirectory) {
+ uploadDirectory = userUploadDirectory;
+ } else {
+ uploadDirectory = this->GetOption("CPACK_PACKAGE_DIRECTORY");
+ uploadDirectory += "/CPackUploads";
+ }
+
+ // Create packages for each component
+ bool warnedAboutDownloadCompatibility = false;
+
+ std::map<std::string, cmCPackComponent>::iterator compIt;
+ for (compIt = this->Components.begin(); compIt != this->Components.end();
+ ++compIt) {
+ std::string packageFile;
+ if (compIt->second.IsDownloaded) {
+ if (this->PackageCompatibilityVersion >= getVersion(10, 5) &&
+ this->PackageMakerVersion >= 3.0) {
+ // Build this package within the upload directory.
+ packageFile = uploadDirectory;
+
+ if (!cmSystemTools::FileExists(uploadDirectory.c_str())) {
+ if (!cmSystemTools::MakeDirectory(uploadDirectory.c_str())) {
+ cmCPackLogger(cmCPackLog::LOG_ERROR,
+ "Unable to create package upload directory "
+ << uploadDirectory << std::endl);
+ return 0;
+ }
+ }
+ } else if (!warnedAboutDownloadCompatibility) {
+ if (this->PackageCompatibilityVersion < getVersion(10, 5)) {
+ cmCPackLogger(
+ cmCPackLog::LOG_WARNING,
+ "CPack warning: please set CPACK_OSX_PACKAGE_VERSION to 10.5 "
+ "or greater enable downloaded packages. CPack will build a "
+ "non-downloaded package."
+ << std::endl);
+ }
+
+ if (this->PackageMakerVersion < 3) {
+ cmCPackLogger(cmCPackLog::LOG_WARNING,
+ "CPack warning: unable to build downloaded "
+ "packages with PackageMaker versions prior "
+ "to 3.0. CPack will build a non-downloaded package."
+ << std::endl);
+ }
+
+ warnedAboutDownloadCompatibility = true;
+ }
+ }
+
+ if (packageFile.empty()) {
+ // Build this package within the overall distribution
+ // metapackage.
+ packageFile = basePackageDir;
+
+ // We're not downloading this component, even if the user
+ // requested it.
+ compIt->second.IsDownloaded = false;
+ }
+
+ packageFile += '/';
+ packageFile += GetPackageName(compIt->second);
+
+ std::string packageDir = toplevel;
+ packageDir += '/';
+ packageDir += compIt->first;
+ if (!this->GenerateComponentPackage(
+ packageFile.c_str(), packageDir.c_str(), compIt->second)) {
+ return 0;
+ }
+ }
+ }
+ this->SetOption("CPACK_MODULE_VERSION_SUFFIX", "");
+
+ // Copy or create all of the resource files we need.
+ if (!this->CopyCreateResourceFile("License", resDir.c_str()) ||
+ !this->CopyCreateResourceFile("ReadMe", resDir.c_str()) ||
+ !this->CopyCreateResourceFile("Welcome", resDir.c_str()) ||
+ !this->CopyResourcePlistFile("Info.plist") ||
+ !this->CopyResourcePlistFile("Description.plist")) {
+ cmCPackLogger(cmCPackLog::LOG_ERROR, "Problem copying the resource files"
+ << std::endl);
+ return 0;
+ }
+
+ if (this->Components.empty()) {
+ // Use PackageMaker to build the package.
+ std::ostringstream pkgCmd;
+ pkgCmd << "\"" << this->GetOption("CPACK_INSTALLER_PROGRAM")
+ << "\" -build -p \"" << packageDirFileName << "\"";
+ if (this->Components.empty()) {
+ pkgCmd << " -f \"" << this->GetOption("CPACK_TEMPORARY_DIRECTORY");
+ } else {
+ pkgCmd << " -mi \"" << this->GetOption("CPACK_TEMPORARY_DIRECTORY")
+ << "/packages/";
+ }
+ pkgCmd << "\" -r \"" << this->GetOption("CPACK_TOPLEVEL_DIRECTORY")
+ << "/Resources\" -i \""
+ << this->GetOption("CPACK_TOPLEVEL_DIRECTORY")
+ << "/Info.plist\" -d \""
+ << this->GetOption("CPACK_TOPLEVEL_DIRECTORY")
+ << "/Description.plist\"";
+ if (this->PackageMakerVersion > 2.0) {
+ pkgCmd << " -v";
+ }
+ if (!RunPackageMaker(pkgCmd.str().c_str(), packageDirFileName.c_str()))
+ return 0;
+ } else {
+ // We have built the package in place. Generate the
+ // distribution.dist file to describe it for the installer.
+ WriteDistributionFile(packageDirFileName.c_str());
+ }
+
+ std::string tmpFile = this->GetOption("CPACK_TOPLEVEL_DIRECTORY");
+ tmpFile += "/hdiutilOutput.log";
+ std::ostringstream dmgCmd;
+ dmgCmd << "\"" << this->GetOption("CPACK_INSTALLER_PROGRAM_DISK_IMAGE")
+ << "\" create -ov -format UDZO -srcfolder \"" << packageDirFileName
+ << "\" \"" << packageFileNames[0] << "\"";
+ std::string output;
+ int retVal = 1;
+ int numTries = 10;
+ bool res = false;
+ while (numTries > 0) {
+ res =
+ cmSystemTools::RunSingleCommand(dmgCmd.str().c_str(), &output, &output,
+ &retVal, 0, this->GeneratorVerbose, 0);
+ if (res && !retVal) {
+ numTries = -1;
+ break;
+ }
+ cmSystemTools::Delay(500);
+ numTries--;
+ }
+ if (!res || retVal) {
+ cmGeneratedFileStream ofs(tmpFile.c_str());
+ ofs << "# Run command: " << dmgCmd.str() << std::endl
+ << "# Output:" << std::endl
+ << output << std::endl;
+ cmCPackLogger(cmCPackLog::LOG_ERROR, "Problem running hdiutil command: "
+ << dmgCmd.str() << std::endl
+ << "Please check " << tmpFile << " for errors"
+ << std::endl);
+ return 0;
+ }
+
+ return 1;
+}
+
+int cmCPackPackageMakerGenerator::InitializeInternal()
+{
+ this->SetOptionIfNotSet("CPACK_PACKAGING_INSTALL_PREFIX", "/usr");
+
+ // Starting with Xcode 4.3, PackageMaker is a separate app, and you
+ // can put it anywhere you want. So... use a variable for its location.
+ // People who put it in unexpected places can use the variable to tell
+ // us where it is.
+ //
+ // Use the following locations, in "most recent installation" order,
+ // to search for the PackageMaker app. Assume people who copy it into
+ // the new Xcode 4.3 app in "/Applications" will copy it into the nested
+ // Applications folder inside the Xcode bundle itself. Or directly in
+ // the "/Applications" directory.
+ //
+ // If found, save result in the CPACK_INSTALLER_PROGRAM variable.
+
+ std::vector<std::string> paths;
+ paths.push_back("/Applications/Xcode.app/Contents/Applications"
+ "/PackageMaker.app/Contents/MacOS");
+ paths.push_back("/Applications/Utilities"
+ "/PackageMaker.app/Contents/MacOS");
+ paths.push_back("/Applications"
+ "/PackageMaker.app/Contents/MacOS");
+ paths.push_back("/Developer/Applications/Utilities"
+ "/PackageMaker.app/Contents/MacOS");
+ paths.push_back("/Developer/Applications"
+ "/PackageMaker.app/Contents/MacOS");
+
+ std::string pkgPath;
+ const char* inst_program = this->GetOption("CPACK_INSTALLER_PROGRAM");
+ if (inst_program && *inst_program) {
+ pkgPath = inst_program;
+ } else {
+ pkgPath = cmSystemTools::FindProgram("PackageMaker", paths, false);
+ if (pkgPath.empty()) {
+ cmCPackLogger(cmCPackLog::LOG_ERROR, "Cannot find PackageMaker compiler"
+ << std::endl);
+ return 0;
+ }
+ this->SetOptionIfNotSet("CPACK_INSTALLER_PROGRAM", pkgPath.c_str());
+ }
+
+ // Get path to the real PackageMaker, not a symlink:
+ pkgPath = cmSystemTools::GetRealPath(pkgPath.c_str());
+ // Up from there to find the version.plist file in the "Contents" dir:
+ std::string contents_dir;
+ contents_dir = cmSystemTools::GetFilenamePath(pkgPath);
+ contents_dir = cmSystemTools::GetFilenamePath(contents_dir);
+
+ std::string versionFile = contents_dir + "/version.plist";
+
+ if (!cmSystemTools::FileExists(versionFile.c_str())) {
+ cmCPackLogger(cmCPackLog::LOG_ERROR,
+ "Cannot find PackageMaker compiler version file: "
+ << versionFile << std::endl);
+ return 0;
+ }
+
+ cmsys::ifstream ifs(versionFile.c_str());
+ if (!ifs) {
+ cmCPackLogger(cmCPackLog::LOG_ERROR,
+ "Cannot open PackageMaker compiler version file"
+ << std::endl);
+ return 0;
+ }
+
+ // Check the PackageMaker version
+ cmsys::RegularExpression rexKey("<key>CFBundleShortVersionString</key>");
+ cmsys::RegularExpression rexVersion("<string>([0-9]+.[0-9.]+)</string>");
+ std::string line;
+ bool foundKey = false;
+ while (cmSystemTools::GetLineFromStream(ifs, line)) {
+ if (rexKey.find(line)) {
+ foundKey = true;
+ break;
+ }
+ }
+ if (!foundKey) {
+ cmCPackLogger(
+ cmCPackLog::LOG_ERROR,
+ "Cannot find CFBundleShortVersionString in the PackageMaker compiler "
+ "version file"
+ << std::endl);
+ return 0;
+ }
+ if (!cmSystemTools::GetLineFromStream(ifs, line) || !rexVersion.find(line)) {
+ cmCPackLogger(cmCPackLog::LOG_ERROR,
+ "Problem reading the PackageMaker compiler version file: "
+ << versionFile << std::endl);
+ return 0;
+ }
+ this->PackageMakerVersion = atof(rexVersion.match(1).c_str());
+ if (this->PackageMakerVersion < 1.0) {
+ cmCPackLogger(cmCPackLog::LOG_ERROR, "Require PackageMaker 1.0 or higher"
+ << std::endl);
+ return 0;
+ }
+ cmCPackLogger(cmCPackLog::LOG_DEBUG, "PackageMaker version is: "
+ << this->PackageMakerVersion << std::endl);
+
+ // Determine the package compatibility version. If it wasn't
+ // specified by the user, we define it based on which features the
+ // user requested.
+ const char* packageCompat = this->GetOption("CPACK_OSX_PACKAGE_VERSION");
+ if (packageCompat && *packageCompat) {
+ unsigned int majorVersion = 10;
+ unsigned int minorVersion = 5;
+ int res = sscanf(packageCompat, "%u.%u", &majorVersion, &minorVersion);
+ if (res == 2) {
+ this->PackageCompatibilityVersion =
+ getVersion(majorVersion, minorVersion);
+ }
+ } else if (this->GetOption("CPACK_DOWNLOAD_SITE")) {
+ this->SetOption("CPACK_OSX_PACKAGE_VERSION", "10.5");
+ this->PackageCompatibilityVersion = getVersion(10, 5);
+ } else if (this->GetOption("CPACK_COMPONENTS_ALL")) {
+ this->SetOption("CPACK_OSX_PACKAGE_VERSION", "10.4");
+ this->PackageCompatibilityVersion = getVersion(10, 4);
+ } else {
+ this->SetOption("CPACK_OSX_PACKAGE_VERSION", "10.3");
+ this->PackageCompatibilityVersion = getVersion(10, 3);
+ }
+
+ std::vector<std::string> no_paths;
+ pkgPath = cmSystemTools::FindProgram("hdiutil", no_paths, false);
+ if (pkgPath.empty()) {
+ cmCPackLogger(cmCPackLog::LOG_ERROR, "Cannot find hdiutil compiler"
+ << std::endl);
+ return 0;
+ }
+ this->SetOptionIfNotSet("CPACK_INSTALLER_PROGRAM_DISK_IMAGE",
+ pkgPath.c_str());
+
+ return this->Superclass::InitializeInternal();
+}
+
+bool cmCPackPackageMakerGenerator::RunPackageMaker(const char* command,
+ const char* packageFile)
+{
+ std::string tmpFile = this->GetOption("CPACK_TOPLEVEL_DIRECTORY");
+ tmpFile += "/PackageMakerOutput.log";
+
+ cmCPackLogger(cmCPackLog::LOG_VERBOSE, "Execute: " << command << std::endl);
+ std::string output;
+ int retVal = 1;
+ bool res = cmSystemTools::RunSingleCommand(
+ command, &output, &output, &retVal, 0, this->GeneratorVerbose, 0);
+ cmCPackLogger(cmCPackLog::LOG_VERBOSE, "Done running package maker"
+ << std::endl);
+ if (!res || retVal) {
+ cmGeneratedFileStream ofs(tmpFile.c_str());
+ ofs << "# Run command: " << command << std::endl
+ << "# Output:" << std::endl
+ << output << std::endl;
+ cmCPackLogger(
+ cmCPackLog::LOG_ERROR, "Problem running PackageMaker command: "
+ << command << std::endl
+ << "Please check " << tmpFile << " for errors" << std::endl);
+ return false;
+ }
+ // sometimes the command finishes but the directory is not yet
+ // created, so try 10 times to see if it shows up
+ int tries = 10;
+ while (tries > 0 && !cmSystemTools::FileExists(packageFile)) {
+ cmSystemTools::Delay(500);
+ tries--;
+ }
+ if (!cmSystemTools::FileExists(packageFile)) {
+ cmCPackLogger(cmCPackLog::LOG_ERROR,
+ "Problem running PackageMaker command: "
+ << command << std::endl
+ << "Package not created: " << packageFile << std::endl);
+ return false;
+ }
+
+ return true;
+}
+
+bool cmCPackPackageMakerGenerator::GenerateComponentPackage(
+ const char* packageFile, const char* packageDir,
+ const cmCPackComponent& component)
+{
+ cmCPackLogger(cmCPackLog::LOG_OUTPUT, "- Building component package: "
+ << packageFile << std::endl);
+
+ // The command that will be used to run PackageMaker
+ std::ostringstream pkgCmd;
+
+ if (this->PackageCompatibilityVersion < getVersion(10, 5) ||
+ this->PackageMakerVersion < 3.0) {
+ // Create Description.plist and Info.plist files for normal Mac OS
+ // X packages, which work on Mac OS X 10.3 and newer.
+ std::string descriptionFile = this->GetOption("CPACK_TOPLEVEL_DIRECTORY");
+ descriptionFile += '/' + component.Name + "-Description.plist";
+ cmsys::ofstream out(descriptionFile.c_str());
+ cmXMLWriter xout(out);
+ xout.StartDocument();
+ xout.Doctype("plist PUBLIC \"-//Apple Computer//DTD PLIST 1.0//EN\""
+ "\"http://www.apple.com/DTDs/PropertyList-1.0.dtd\"");
+ xout.StartElement("plist");
+ xout.Attribute("version", "1.4");
+ xout.StartElement("dict");
+ xout.Element("key", "IFPkgDescriptionTitle");
+ xout.Element("string", component.DisplayName);
+ xout.Element("key", "IFPkgDescriptionVersion");
+ xout.Element("string", this->GetOption("CPACK_PACKAGE_VERSION"));
+ xout.Element("key", "IFPkgDescriptionDescription");
+ xout.Element("string", component.Description);
+ xout.EndElement(); // dict
+ xout.EndElement(); // plist
+ xout.EndDocument();
+ out.close();
+
+ // Create the Info.plist file for this component
+ std::string moduleVersionSuffix = ".";
+ moduleVersionSuffix += component.Name;
+ this->SetOption("CPACK_MODULE_VERSION_SUFFIX",
+ moduleVersionSuffix.c_str());
+ std::string infoFileName = component.Name;
+ infoFileName += "-Info.plist";
+ if (!this->CopyResourcePlistFile("Info.plist", infoFileName.c_str())) {
+ return false;
+ }
+
+ pkgCmd << "\"" << this->GetOption("CPACK_INSTALLER_PROGRAM")
+ << "\" -build -p \"" << packageFile << "\""
+ << " -f \"" << packageDir << "\""
+ << " -i \"" << this->GetOption("CPACK_TOPLEVEL_DIRECTORY") << "/"
+ << infoFileName << "\""
+ << " -d \"" << descriptionFile << "\"";
+ } else {
+ // Create a "flat" package on Mac OS X 10.5 and newer. Flat
+ // packages are stored in a single file, rather than a directory
+ // like normal packages, and can be downloaded by the installer
+ // on-the-fly in Mac OS X 10.5 or newer. Thus, we need to create
+ // flat packages when the packages will be downloaded on the fly.
+ std::string pkgId = "com.";
+ pkgId += this->GetOption("CPACK_PACKAGE_VENDOR");
+ pkgId += '.';
+ pkgId += this->GetOption("CPACK_PACKAGE_NAME");
+ pkgId += '.';
+ pkgId += component.Name;
+
+ pkgCmd << "\"" << this->GetOption("CPACK_INSTALLER_PROGRAM")
+ << "\" --root \"" << packageDir << "\""
+ << " --id " << pkgId << " --target "
+ << this->GetOption("CPACK_OSX_PACKAGE_VERSION") << " --out \""
+ << packageFile << "\"";
+ }
+
+ // Run PackageMaker
+ return RunPackageMaker(pkgCmd.str().c_str(), packageFile);
+}
diff --git a/Source/CPack/cmCPackPackageMakerGenerator.h b/Source/CPack/cmCPackPackageMakerGenerator.h
new file mode 100644
index 0000000..d1314a4
--- /dev/null
+++ b/Source/CPack/cmCPackPackageMakerGenerator.h
@@ -0,0 +1,60 @@
+/*============================================================================
+ CMake - Cross Platform Makefile Generator
+ Copyright 2000-2009 Kitware, Inc.
+
+ Distributed under the OSI-approved BSD License (the "License");
+ see accompanying file Copyright.txt for details.
+
+ This software is distributed WITHOUT ANY WARRANTY; without even the
+ implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
+ See the License for more information.
+============================================================================*/
+
+#ifndef cmCPackPackageMakerGenerator_h
+#define cmCPackPackageMakerGenerator_h
+
+#include "cmCPackPKGGenerator.h"
+
+class cmCPackComponent;
+
+/** \class cmCPackPackageMakerGenerator
+ * \brief A generator for PackageMaker files
+ *
+ * http://developer.apple.com/documentation/Darwin
+ * /Reference/ManPages/man1/packagemaker.1.html
+ */
+class cmCPackPackageMakerGenerator : public cmCPackPKGGenerator
+{
+public:
+ cmCPackTypeMacro(cmCPackPackageMakerGenerator, cmCPackPKGGenerator);
+
+ /**
+ * Construct generator
+ */
+ cmCPackPackageMakerGenerator();
+ virtual ~cmCPackPackageMakerGenerator();
+ bool SupportsComponentInstallation() const CM_OVERRIDE;
+
+protected:
+ int InitializeInternal() CM_OVERRIDE;
+ int PackageFiles() CM_OVERRIDE;
+ const char* GetOutputExtension() CM_OVERRIDE { return ".dmg"; }
+
+ // Run PackageMaker with the given command line, which will (if
+ // successful) produce the given package file. Returns true if
+ // PackageMaker succeeds, false otherwise.
+ bool RunPackageMaker(const char* command, const char* packageFile);
+
+ // Generate a package in the file packageFile for the given
+ // component. All of the files within this component are stored in
+ // the directory packageDir. Returns true if successful, false
+ // otherwise.
+ bool GenerateComponentPackage(const char* packageFile,
+ const char* packageDir,
+ const cmCPackComponent& component);
+
+ double PackageMakerVersion;
+ unsigned int PackageCompatibilityVersion;
+};
+
+#endif
diff --git a/Source/CPack/cmCPackProductBuildGenerator.cxx b/Source/CPack/cmCPackProductBuildGenerator.cxx
new file mode 100644
index 0000000..c2a13d0
--- /dev/null
+++ b/Source/CPack/cmCPackProductBuildGenerator.cxx
@@ -0,0 +1,231 @@
+/*============================================================================
+ CMake - Cross Platform Makefile Generator
+ Copyright 2000-2009 Kitware, Inc., Insight Software Consortium
+
+ Distributed under the OSI-approved BSD License (the "License");
+ see accompanying file Copyright.txt for details.
+
+ This software is distributed WITHOUT ANY WARRANTY; without even the
+ implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
+ See the License for more information.
+============================================================================*/
+#include "cmCPackProductBuildGenerator.h"
+
+#include "cmCPackComponentGroup.h"
+#include "cmCPackLog.h"
+#include "cmGeneratedFileStream.h"
+#include "cmGlobalGenerator.h"
+#include "cmLocalGenerator.h"
+#include "cmMakefile.h"
+#include "cmSystemTools.h"
+#include "cmake.h"
+
+#include <cmsys/Glob.hxx>
+#include <cmsys/SystemTools.hxx>
+
+cmCPackProductBuildGenerator::cmCPackProductBuildGenerator()
+{
+ this->componentPackageMethod = ONE_PACKAGE;
+}
+
+cmCPackProductBuildGenerator::~cmCPackProductBuildGenerator()
+{
+}
+
+int cmCPackProductBuildGenerator::PackageFiles()
+{
+ // TODO: Use toplevel
+ // It is used! Is this an obsolete comment?
+
+ std::string packageDirFileName =
+ this->GetOption("CPACK_TEMPORARY_DIRECTORY");
+
+ // Create the directory where component packages will be built.
+ std::string basePackageDir = packageDirFileName;
+ basePackageDir += "/Contents/Packages";
+ if (!cmsys::SystemTools::MakeDirectory(basePackageDir.c_str())) {
+ cmCPackLogger(cmCPackLog::LOG_ERROR,
+ "Problem creating component packages directory: "
+ << basePackageDir << std::endl);
+ return 0;
+ }
+
+ if (!this->Components.empty()) {
+ std::map<std::string, cmCPackComponent>::iterator compIt;
+ for (compIt = this->Components.begin(); compIt != this->Components.end();
+ ++compIt) {
+ std::string packageDir = toplevel;
+ packageDir += '/';
+ packageDir += compIt->first;
+ if (!this->GenerateComponentPackage(basePackageDir,
+ GetPackageName(compIt->second),
+ packageDir, &compIt->second)) {
+ return 0;
+ }
+ }
+ } else {
+ if (!this->GenerateComponentPackage(basePackageDir,
+ this->GetOption("CPACK_PACKAGE_NAME"),
+ toplevel, NULL)) {
+ return 0;
+ }
+ }
+
+ // Copy or create all of the resource files we need.
+ std::string resDir = packageDirFileName + "/Contents";
+ if (!this->CopyCreateResourceFile("License", resDir.c_str()) ||
+ !this->CopyCreateResourceFile("ReadMe", resDir.c_str()) ||
+ !this->CopyCreateResourceFile("Welcome", resDir.c_str())) {
+ cmCPackLogger(cmCPackLog::LOG_ERROR, "Problem copying the resource files"
+ << std::endl);
+ return 0;
+ }
+
+ // combine package(s) into a distribution
+ WriteDistributionFile(packageDirFileName.c_str());
+ std::ostringstream pkgCmd;
+
+ std::string version = this->GetOption("CPACK_PACKAGE_VERSION");
+ std::string productbuild = this->GetOption("CPACK_COMMAND_PRODUCTBUILD");
+
+ pkgCmd << productbuild << " --distribution \"" << packageDirFileName
+ << "/Contents/distribution.dist\""
+ << " --package-path \"" << packageDirFileName << "/Contents/Packages"
+ << "\""
+ << " --resources \"" << resDir << "\""
+ << " --version \"" << version << "\""
+ << " \"" << packageFileNames[0] << "\"";
+
+ // Run ProductBuild
+ return RunProductBuild(pkgCmd.str());
+}
+
+int cmCPackProductBuildGenerator::InitializeInternal()
+{
+ this->SetOptionIfNotSet("CPACK_PACKAGING_INSTALL_PREFIX", "/Applications");
+
+ std::vector<std::string> no_paths;
+ std::string program =
+ cmSystemTools::FindProgram("pkgbuild", no_paths, false);
+ if (program.empty()) {
+ cmCPackLogger(cmCPackLog::LOG_ERROR, "Cannot find pkgbuild executable"
+ << std::endl);
+ return 0;
+ }
+ this->SetOptionIfNotSet("CPACK_COMMAND_PKGBUILD", program.c_str());
+
+ program = cmSystemTools::FindProgram("productbuild", no_paths, false);
+ if (program.empty()) {
+ cmCPackLogger(cmCPackLog::LOG_ERROR, "Cannot find productbuild executable"
+ << std::endl);
+ return 0;
+ }
+ this->SetOptionIfNotSet("CPACK_COMMAND_PRODUCTBUILD", program.c_str());
+
+ return this->Superclass::InitializeInternal();
+}
+
+bool cmCPackProductBuildGenerator::RunProductBuild(const std::string& command)
+{
+ std::string tmpFile = this->GetOption("CPACK_TOPLEVEL_DIRECTORY");
+ tmpFile += "/ProductBuildOutput.log";
+
+ cmCPackLogger(cmCPackLog::LOG_VERBOSE, "Execute: " << command << std::endl);
+ std::string output, error_output;
+ int retVal = 1;
+ bool res =
+ cmSystemTools::RunSingleCommand(command.c_str(), &output, &error_output,
+ &retVal, 0, this->GeneratorVerbose, 0);
+ cmCPackLogger(cmCPackLog::LOG_VERBOSE, "Done running command" << std::endl);
+ if (!res || retVal) {
+ cmGeneratedFileStream ofs(tmpFile.c_str());
+ ofs << "# Run command: " << command << std::endl
+ << "# Output:" << std::endl
+ << output << std::endl;
+ cmCPackLogger(cmCPackLog::LOG_ERROR,
+ "Problem running command: " << command << std::endl
+ << "Please check " << tmpFile
+ << " for errors" << std::endl);
+ return false;
+ }
+ return true;
+}
+
+bool cmCPackProductBuildGenerator::GenerateComponentPackage(
+ const std::string& packageFileDir, const std::string& packageFileName,
+ const std::string& packageDir, const cmCPackComponent* component)
+{
+ std::string packageFile = packageFileDir;
+ packageFile += '/';
+ packageFile += packageFileName;
+
+ cmCPackLogger(cmCPackLog::LOG_OUTPUT, "- Building component package: "
+ << packageFile << std::endl);
+
+ const char* comp_name = component ? component->Name.c_str() : NULL;
+
+ const char* preflight = this->GetComponentScript("PREFLIGHT", comp_name);
+ const char* postflight = this->GetComponentScript("POSTFLIGHT", comp_name);
+
+ std::string resDir = packageFileDir;
+ if (component) {
+ resDir += "/";
+ resDir += component->Name;
+ }
+ std::string scriptDir = resDir + "/scripts";
+
+ if (!cmsys::SystemTools::MakeDirectory(scriptDir.c_str())) {
+ cmCPackLogger(cmCPackLog::LOG_ERROR,
+ "Problem creating installer directory: " << scriptDir
+ << std::endl);
+ return 0;
+ }
+
+ // if preflight, postflight, or postupgrade are set
+ // then copy them into the script directory and make
+ // them executable
+ if (preflight) {
+ this->CopyInstallScript(scriptDir.c_str(), preflight, "preinstall");
+ }
+ if (postflight) {
+ this->CopyInstallScript(scriptDir.c_str(), postflight, "postinstall");
+ }
+
+ // The command that will be used to run ProductBuild
+ std::ostringstream pkgCmd;
+
+ std::string pkgId = "com.";
+ pkgId += this->GetOption("CPACK_PACKAGE_VENDOR");
+ pkgId += '.';
+ pkgId += this->GetOption("CPACK_PACKAGE_NAME");
+ if (component) {
+ pkgId += '.';
+ pkgId += component->Name;
+ }
+
+ std::string version = this->GetOption("CPACK_PACKAGE_VERSION");
+ std::string pkgbuild = this->GetOption("CPACK_COMMAND_PKGBUILD");
+
+ pkgCmd << pkgbuild << " --root \"" << packageDir << "\""
+ << " --identifier \"" << pkgId << "\""
+ << " --scripts \"" << scriptDir << "\""
+ << " --version \"" << version << "\""
+ << " --install-location \"/\""
+ << " \"" << packageFile << "\"";
+
+ // Run ProductBuild
+ return RunProductBuild(pkgCmd.str());
+}
+
+const char* cmCPackProductBuildGenerator::GetComponentScript(
+ const char* script, const char* component_name)
+{
+ std::string scriptname = std::string("CPACK_") + script + "_";
+ if (component_name) {
+ scriptname += cmSystemTools::UpperCase(component_name);
+ scriptname += "_";
+ }
+ scriptname += "SCRIPT";
+
+ return this->GetOption(scriptname);
+}
diff --git a/Source/CPack/cmCPackProductBuildGenerator.h b/Source/CPack/cmCPackProductBuildGenerator.h
new file mode 100644
index 0000000..fd2c090
--- /dev/null
+++ b/Source/CPack/cmCPackProductBuildGenerator.h
@@ -0,0 +1,58 @@
+/*============================================================================
+ CMake - Cross Platform Makefile Generator
+ Copyright 2000-2009 Kitware, Inc.
+
+ Distributed under the OSI-approved BSD License (the "License");
+ see accompanying file Copyright.txt for details.
+
+ This software is distributed WITHOUT ANY WARRANTY; without even the
+ implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
+ See the License for more information.
+============================================================================*/
+
+#ifndef cmCPackProductBuildGenerator_h
+#define cmCPackProductBuildGenerator_h
+
+#include "cmCPackPKGGenerator.h"
+
+class cmCPackComponent;
+
+/** \class cmCPackProductBuildGenerator
+ * \brief A generator for ProductBuild files
+ *
+ */
+class cmCPackProductBuildGenerator : public cmCPackPKGGenerator
+{
+public:
+ cmCPackTypeMacro(cmCPackProductBuildGenerator, cmCPackPKGGenerator);
+
+ /**
+ * Construct generator
+ */
+ cmCPackProductBuildGenerator();
+ virtual ~cmCPackProductBuildGenerator();
+
+protected:
+ int InitializeInternal() CM_OVERRIDE;
+ int PackageFiles() CM_OVERRIDE;
+ const char* GetOutputExtension() CM_OVERRIDE { return ".pkg"; }
+
+ // Run ProductBuild with the given command line, which will (if
+ // successful) produce the given package file. Returns true if
+ // ProductBuild succeeds, false otherwise.
+ bool RunProductBuild(const std::string& command);
+
+ // Generate a package in the file packageFile for the given
+ // component. All of the files within this component are stored in
+ // the directory packageDir. Returns true if successful, false
+ // otherwise.
+ bool GenerateComponentPackage(const std::string& packageFileDir,
+ const std::string& packageFileName,
+ const std::string& packageDir,
+ const cmCPackComponent* component);
+
+ const char* GetComponentScript(const char* script,
+ const char* script_component);
+};
+
+#endif
diff --git a/Source/CPack/cmCPackRPMGenerator.cxx b/Source/CPack/cmCPackRPMGenerator.cxx
new file mode 100644
index 0000000..2568d17
--- /dev/null
+++ b/Source/CPack/cmCPackRPMGenerator.cxx
@@ -0,0 +1,253 @@
+/*============================================================================
+ CMake - Cross Platform Makefile Generator
+ Copyright 2000-2009 Kitware, Inc., Insight Software Consortium
+
+ Distributed under the OSI-approved BSD License (the "License");
+ see accompanying file Copyright.txt for details.
+
+ This software is distributed WITHOUT ANY WARRANTY; without even the
+ implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
+ See the License for more information.
+============================================================================*/
+#include "cmCPackRPMGenerator.h"
+
+#include "cmCPackLog.h"
+#include "cmSystemTools.h"
+
+cmCPackRPMGenerator::cmCPackRPMGenerator()
+{
+}
+
+cmCPackRPMGenerator::~cmCPackRPMGenerator()
+{
+}
+
+int cmCPackRPMGenerator::InitializeInternal()
+{
+ this->SetOptionIfNotSet("CPACK_PACKAGING_INSTALL_PREFIX", "/usr");
+ if (cmSystemTools::IsOff(this->GetOption("CPACK_SET_DESTDIR"))) {
+ this->SetOption("CPACK_SET_DESTDIR", "I_ON");
+ }
+ /* Replace space in CPACK_PACKAGE_NAME in order to avoid
+ * rpmbuild scream on unwanted space in filename issue
+ * Moreover RPM file do not usually embed space in filename
+ */
+ if (this->GetOption("CPACK_PACKAGE_NAME")) {
+ std::string packageName = this->GetOption("CPACK_PACKAGE_NAME");
+ std::replace(packageName.begin(), packageName.end(), ' ', '-');
+ this->SetOption("CPACK_PACKAGE_NAME", packageName.c_str());
+ }
+ /* same for CPACK_PACKAGE_FILE_NAME */
+ if (this->GetOption("CPACK_PACKAGE_FILE_NAME")) {
+ std::string packageName = this->GetOption("CPACK_PACKAGE_FILE_NAME");
+ std::replace(packageName.begin(), packageName.end(), ' ', '-');
+ this->SetOption("CPACK_PACKAGE_FILE_NAME", packageName.c_str());
+ }
+ 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 const& initialToplevel,
+ std::string const& packageName)
+{
+ int retval = 1;
+ // Begin the archive for this pack
+ std::string localToplevel(initialToplevel);
+ std::string packageFileName(cmSystemTools::GetParentDirectory(toplevel));
+ std::string outputFileName(
+ GetComponentPackageFileName(this->GetOption("CPACK_PACKAGE_FILE_NAME"),
+ packageName, true) +
+ this->GetOutputExtension());
+
+ localToplevel += "/" + packageName;
+ /* 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 NAME.
+ this->SetOption("CPACK_RPM_PACKAGE_COMPONENT", packageName.c_str());
+ // Tell CPackRPM.cmake the path where the component is.
+ std::string component_path = "/";
+ component_path += packageName;
+ this->SetOption("CPACK_RPM_PACKAGE_COMPONENT_PART_PATH",
+ component_path.c_str());
+ if (!this->ReadListFile("CPackRPM.cmake")) {
+ cmCPackLogger(cmCPackLog::LOG_ERROR, "Error while execution CPackRPM.cmake"
+ << std::endl);
+ retval = 0;
+ }
+
+ return retval;
+}
+
+int cmCPackRPMGenerator::PackageComponents(bool ignoreGroup)
+{
+ int retval = 1;
+ /* Reset package file name list it will be populated during the
+ * component packaging run*/
+ packageFileNames.clear();
+ std::string initialTopLevel(this->GetOption("CPACK_TEMPORARY_DIRECTORY"));
+
+ // The default behavior is to have one package by component group
+ // unless CPACK_COMPONENTS_IGNORE_GROUP is specified.
+ if (!ignoreGroup) {
+ std::map<std::string, cmCPackComponentGroup>::iterator compGIt;
+ for (compGIt = this->ComponentGroups.begin();
+ compGIt != this->ComponentGroups.end(); ++compGIt) {
+ cmCPackLogger(cmCPackLog::LOG_VERBOSE, "Packaging component group: "
+ << compGIt->first << std::endl);
+ retval &= PackageOnePack(initialTopLevel, compGIt->first);
+ }
+ // Handle Orphan components (components not belonging to any groups)
+ std::map<std::string, cmCPackComponent>::iterator compIt;
+ for (compIt = this->Components.begin(); compIt != this->Components.end();
+ ++compIt) {
+ // Does the component belong to a group?
+ if (compIt->second.Group == CM_NULLPTR) {
+ cmCPackLogger(
+ cmCPackLog::LOG_VERBOSE, "Component <"
+ << compIt->second.Name
+ << "> does not belong to any group, package it separately."
+ << std::endl);
+ retval &= PackageOnePack(initialTopLevel, compIt->first);
+ }
+ }
+ }
+ // CPACK_COMPONENTS_IGNORE_GROUPS is set
+ // We build 1 package per component
+ else {
+ std::map<std::string, cmCPackComponent>::iterator compIt;
+ for (compIt = this->Components.begin(); compIt != this->Components.end();
+ ++compIt) {
+ retval &= PackageOnePack(initialTopLevel, compIt->first);
+ }
+ }
+
+ if (retval) {
+ AddGeneratedPackageNames();
+ }
+
+ return retval;
+}
+
+int cmCPackRPMGenerator::PackageComponentsAllInOne(
+ const std::string& compInstDirName)
+{
+ int retval = 1;
+ /* Reset package file name list it will be populated during the
+ * component packaging run*/
+ packageFileNames.clear();
+ std::string initialTopLevel(this->GetOption("CPACK_TEMPORARY_DIRECTORY"));
+
+ 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));
+ std::string outputFileName(
+ std::string(this->GetOption("CPACK_PACKAGE_FILE_NAME")) +
+ 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());
+
+ if (!compInstDirName.empty()) {
+ // Tell CPackRPM.cmake the path where the component is.
+ std::string component_path = "/";
+ 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, "Error while execution CPackRPM.cmake"
+ << std::endl);
+ retval = 0;
+ }
+
+ return retval;
+}
+
+int cmCPackRPMGenerator::PackageFiles()
+{
+ cmCPackLogger(cmCPackLog::LOG_DEBUG, "Toplevel: " << toplevel << std::endl);
+
+ /* Are we in the component packaging case */
+ if (WantsComponentInstallation()) {
+ // CASE 1 : COMPONENT ALL-IN-ONE package
+ // If ALL COMPONENTS in ONE package has been requested
+ // then the package file is unique and should be open here.
+ if (componentPackageMethod == ONE_PACKAGE) {
+ return PackageComponentsAllInOne("ALL_COMPONENTS_IN_ONE");
+ }
+ // 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 {
+ return PackageComponents(componentPackageMethod ==
+ ONE_PACKAGE_PER_COMPONENT);
+ }
+ }
+ // CASE 3 : NON COMPONENT package.
+ else {
+ return PackageComponentsAllInOne("");
+ }
+}
+
+bool cmCPackRPMGenerator::SupportsComponentInstallation() const
+{
+ return IsOn("CPACK_RPM_COMPONENT_INSTALL");
+}
+
+std::string cmCPackRPMGenerator::GetComponentInstallDirNameSuffix(
+ const std::string& componentName)
+{
+ if (componentPackageMethod == ONE_PACKAGE_PER_COMPONENT) {
+ return componentName;
+ }
+
+ if (componentPackageMethod == ONE_PACKAGE) {
+ 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 (CM_NULLPTR != GetOption(groupVar)) {
+ return std::string(GetOption(groupVar));
+ } else {
+ return componentName;
+ }
+}
diff --git a/Source/CPack/cmCPackRPMGenerator.h b/Source/CPack/cmCPackRPMGenerator.h
new file mode 100644
index 0000000..4baef08
--- /dev/null
+++ b/Source/CPack/cmCPackRPMGenerator.h
@@ -0,0 +1,78 @@
+/*============================================================================
+ CMake - Cross Platform Makefile Generator
+ Copyright 2000-2009 Kitware, Inc.
+
+ Distributed under the OSI-approved BSD License (the "License");
+ see accompanying file Copyright.txt for details.
+
+ This software is distributed WITHOUT ANY WARRANTY; without even the
+ implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
+ See the License for more information.
+============================================================================*/
+
+#ifndef cmCPackRPMGenerator_h
+#define cmCPackRPMGenerator_h
+
+#include "cmCPackGenerator.h"
+
+/** \class cmCPackRPMGenerator
+ * \brief A generator for RPM packages
+ * The idea of the CPack RPM generator is to use
+ * as minimal C++ code as possible.
+ * Ideally the C++ part of the CPack RPM generator
+ * will only 'execute' (aka ->ReadListFile) several
+ * CMake macros files.
+ */
+class cmCPackRPMGenerator : public cmCPackGenerator
+{
+public:
+ cmCPackTypeMacro(cmCPackRPMGenerator, cmCPackGenerator);
+
+ /**
+ * Construct generator
+ */
+ cmCPackRPMGenerator();
+ ~cmCPackRPMGenerator() CM_OVERRIDE;
+
+ static bool CanGenerate()
+ {
+#ifdef __APPLE__
+ // on MacOS enable CPackRPM iff rpmbuild is found
+ std::vector<std::string> locations;
+ locations.push_back("/sw/bin"); // Fink
+ locations.push_back("/opt/local/bin"); // MacPorts
+ return cmSystemTools::FindProgram("rpmbuild") != "" ? true : false;
+#else
+ // legacy behavior on other systems
+ return true;
+#endif
+ }
+
+protected:
+ int InitializeInternal() CM_OVERRIDE;
+ int PackageFiles() CM_OVERRIDE;
+ /**
+ * This method factors out the work done in component packaging case.
+ */
+ int PackageOnePack(std::string const& initialToplevel,
+ std::string const& packageName);
+ /**
+ * 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(const std::string& compInstDirName);
+ const char* GetOutputExtension() CM_OVERRIDE { return ".rpm"; }
+ bool SupportsComponentInstallation() const CM_OVERRIDE;
+ std::string GetComponentInstallDirNameSuffix(
+ const std::string& componentName) CM_OVERRIDE;
+
+ void AddGeneratedPackageNames();
+};
+
+#endif
diff --git a/Source/CPack/cmCPackSTGZGenerator.cxx b/Source/CPack/cmCPackSTGZGenerator.cxx
new file mode 100644
index 0000000..4d07a7e
--- /dev/null
+++ b/Source/CPack/cmCPackSTGZGenerator.cxx
@@ -0,0 +1,125 @@
+/*============================================================================
+ CMake - Cross Platform Makefile Generator
+ Copyright 2000-2009 Kitware, Inc., Insight Software Consortium
+
+ Distributed under the OSI-approved BSD License (the "License");
+ see accompanying file Copyright.txt for details.
+
+ This software is distributed WITHOUT ANY WARRANTY; without even the
+ implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
+ See the License for more information.
+============================================================================*/
+
+#include "cmCPackSTGZGenerator.h"
+
+#include "cmCPackLog.h"
+#include "cmGlobalGenerator.h"
+#include "cmMakefile.h"
+#include "cmSystemTools.h"
+#include "cmake.h"
+
+#include <cmsys/FStream.hxx>
+
+#include <sys/types.h>
+// include sys/stat.h after sys/types.h
+#include <sys/stat.h>
+
+cmCPackSTGZGenerator::cmCPackSTGZGenerator()
+{
+}
+
+cmCPackSTGZGenerator::~cmCPackSTGZGenerator()
+{
+}
+
+int cmCPackSTGZGenerator::InitializeInternal()
+{
+ this->SetOptionIfNotSet("CPACK_INCLUDE_TOPLEVEL_DIRECTORY", "0");
+
+ std::string inFile = this->FindTemplate("CPack.STGZ_Header.sh.in");
+ if (inFile.empty()) {
+ cmCPackLogger(cmCPackLog::LOG_ERROR,
+ "Cannot find template file: " << inFile << std::endl);
+ return 0;
+ }
+ this->SetOptionIfNotSet("CPACK_STGZ_HEADER_FILE", inFile.c_str());
+ this->SetOptionIfNotSet("CPACK_AT_SIGN", "@");
+
+ return this->Superclass::InitializeInternal();
+}
+
+int cmCPackSTGZGenerator::PackageFiles()
+{
+ bool retval = true;
+ if (!this->Superclass::PackageFiles()) {
+ return 0;
+ }
+
+ /* TGZ generator (our Superclass) may
+ * have generated several packages (component packaging)
+ * so we must iterate over generated packages.
+ */
+ for (std::vector<std::string>::iterator it = packageFileNames.begin();
+ it != packageFileNames.end(); ++it) {
+ retval &= cmSystemTools::SetPermissions((*it).c_str(),
+#if defined(_MSC_VER) || defined(__MINGW32__)
+ S_IREAD | S_IWRITE | S_IEXEC
+#else
+ S_IRUSR | S_IWUSR | S_IXUSR |
+ S_IRGRP | S_IWGRP | S_IXGRP |
+ S_IROTH | S_IWOTH | S_IXOTH
+#endif
+ );
+ }
+ return retval;
+}
+
+int cmCPackSTGZGenerator::GenerateHeader(std::ostream* os)
+{
+ cmCPackLogger(cmCPackLog::LOG_DEBUG, "Writing header" << std::endl);
+ std::ostringstream str;
+ int counter = 0;
+
+ std::string inLicFile = this->GetOption("CPACK_RESOURCE_FILE_LICENSE");
+ std::string line;
+ cmsys::ifstream ilfs(inLicFile.c_str());
+ std::string licenseText;
+ while (cmSystemTools::GetLineFromStream(ilfs, line)) {
+ licenseText += line + "\n";
+ }
+ this->SetOptionIfNotSet("CPACK_RESOURCE_FILE_LICENSE_CONTENT",
+ licenseText.c_str());
+
+ const char headerLengthTag[] = "###CPACK_HEADER_LENGTH###";
+
+ // Create the header
+ std::string inFile = this->GetOption("CPACK_STGZ_HEADER_FILE");
+ cmsys::ifstream ifs(inFile.c_str());
+ std::string packageHeaderText;
+ while (cmSystemTools::GetLineFromStream(ifs, line)) {
+ packageHeaderText += line + "\n";
+ }
+
+ // Configure in the values
+ std::string res;
+ this->ConfigureString(packageHeaderText, res);
+
+ // Count the lines
+ const char* ptr = res.c_str();
+ while (*ptr) {
+ if (*ptr == '\n') {
+ counter++;
+ }
+ ++ptr;
+ }
+ counter++;
+ cmCPackLogger(cmCPackLog::LOG_DEBUG, "Number of lines: " << counter
+ << std::endl);
+ char buffer[1024];
+ sprintf(buffer, "%d", counter);
+ cmSystemTools::ReplaceString(res, headerLengthTag, buffer);
+
+ // Write in file
+ *os << res;
+ return this->Superclass::GenerateHeader(os);
+}
diff --git a/Source/CPack/cmCPackSTGZGenerator.h b/Source/CPack/cmCPackSTGZGenerator.h
new file mode 100644
index 0000000..94cc8aa
--- /dev/null
+++ b/Source/CPack/cmCPackSTGZGenerator.h
@@ -0,0 +1,40 @@
+/*============================================================================
+ CMake - Cross Platform Makefile Generator
+ Copyright 2000-2009 Kitware, Inc.
+
+ Distributed under the OSI-approved BSD License (the "License");
+ see accompanying file Copyright.txt for details.
+
+ This software is distributed WITHOUT ANY WARRANTY; without even the
+ implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
+ See the License for more information.
+============================================================================*/
+
+#ifndef cmCPackSTGZGenerator_h
+#define cmCPackSTGZGenerator_h
+
+#include "cmCPackTGZGenerator.h"
+
+/** \class cmCPackSTGZGenerator
+ * \brief A generator for Self extractable TGZ files
+ *
+ */
+class cmCPackSTGZGenerator : public cmCPackTGZGenerator
+{
+public:
+ cmCPackTypeMacro(cmCPackSTGZGenerator, cmCPackTGZGenerator);
+
+ /**
+ * Construct generator
+ */
+ cmCPackSTGZGenerator();
+ ~cmCPackSTGZGenerator() CM_OVERRIDE;
+
+protected:
+ int PackageFiles() CM_OVERRIDE;
+ int InitializeInternal() CM_OVERRIDE;
+ int GenerateHeader(std::ostream* os) CM_OVERRIDE;
+ const char* GetOutputExtension() CM_OVERRIDE { return ".sh"; }
+};
+
+#endif
diff --git a/Source/CPack/cmCPackTGZGenerator.cxx b/Source/CPack/cmCPackTGZGenerator.cxx
new file mode 100644
index 0000000..7c5c245
--- /dev/null
+++ b/Source/CPack/cmCPackTGZGenerator.cxx
@@ -0,0 +1,22 @@
+/*============================================================================
+ CMake - Cross Platform Makefile Generator
+ Copyright 2000-2009 Kitware, Inc., Insight Software Consortium
+
+ Distributed under the OSI-approved BSD License (the "License");
+ see accompanying file Copyright.txt for details.
+
+ This software is distributed WITHOUT ANY WARRANTY; without even the
+ implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
+ See the License for more information.
+============================================================================*/
+
+#include "cmCPackTGZGenerator.h"
+
+cmCPackTGZGenerator::cmCPackTGZGenerator()
+ : cmCPackArchiveGenerator(cmArchiveWrite::CompressGZip, "paxr")
+{
+}
+
+cmCPackTGZGenerator::~cmCPackTGZGenerator()
+{
+}
diff --git a/Source/CPack/cmCPackTGZGenerator.h b/Source/CPack/cmCPackTGZGenerator.h
new file mode 100644
index 0000000..cb7620c
--- /dev/null
+++ b/Source/CPack/cmCPackTGZGenerator.h
@@ -0,0 +1,36 @@
+/*============================================================================
+ CMake - Cross Platform Makefile Generator
+ Copyright 2000-2009 Kitware, Inc.
+
+ Distributed under the OSI-approved BSD License (the "License");
+ see accompanying file Copyright.txt for details.
+
+ This software is distributed WITHOUT ANY WARRANTY; without even the
+ implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
+ See the License for more information.
+============================================================================*/
+
+#ifndef cmCPackTGZGenerator_h
+#define cmCPackTGZGenerator_h
+
+#include "cmCPackArchiveGenerator.h"
+
+/** \class cmCPackTGZGenerator
+ * \brief A generator for TGZ files
+ *
+ */
+class cmCPackTGZGenerator : public cmCPackArchiveGenerator
+{
+public:
+ cmCPackTypeMacro(cmCPackTGZGenerator, cmCPackArchiveGenerator);
+ /**
+ * Construct generator
+ */
+ cmCPackTGZGenerator();
+ ~cmCPackTGZGenerator() CM_OVERRIDE;
+
+protected:
+ const char* GetOutputExtension() CM_OVERRIDE { return ".tar.gz"; }
+};
+
+#endif
diff --git a/Source/CPack/cmCPackTXZGenerator.cxx b/Source/CPack/cmCPackTXZGenerator.cxx
new file mode 100644
index 0000000..d17a164
--- /dev/null
+++ b/Source/CPack/cmCPackTXZGenerator.cxx
@@ -0,0 +1,22 @@
+/*============================================================================
+ CMake - Cross Platform Makefile Generator
+ Copyright 2000-2009 Kitware, Inc., Insight Software Consortium
+
+ Distributed under the OSI-approved BSD License (the "License");
+ see accompanying file Copyright.txt for details.
+
+ This software is distributed WITHOUT ANY WARRANTY; without even the
+ implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
+ See the License for more information.
+============================================================================*/
+
+#include "cmCPackTXZGenerator.h"
+
+cmCPackTXZGenerator::cmCPackTXZGenerator()
+ : cmCPackArchiveGenerator(cmArchiveWrite::CompressXZ, "paxr")
+{
+}
+
+cmCPackTXZGenerator::~cmCPackTXZGenerator()
+{
+}
diff --git a/Source/CPack/cmCPackTXZGenerator.h b/Source/CPack/cmCPackTXZGenerator.h
new file mode 100644
index 0000000..87c92ef
--- /dev/null
+++ b/Source/CPack/cmCPackTXZGenerator.h
@@ -0,0 +1,36 @@
+/*============================================================================
+ CMake - Cross Platform Makefile Generator
+ Copyright 2000-2009 Kitware, Inc.
+
+ Distributed under the OSI-approved BSD License (the "License");
+ see accompanying file Copyright.txt for details.
+
+ This software is distributed WITHOUT ANY WARRANTY; without even the
+ implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
+ See the License for more information.
+============================================================================*/
+
+#ifndef cmCPackTXZGenerator_h
+#define cmCPackTXZGenerator_h
+
+#include "cmCPackArchiveGenerator.h"
+
+/** \class cmCPackTXZGenerator
+ * \brief A generator for TXZ files
+ *
+ */
+class cmCPackTXZGenerator : public cmCPackArchiveGenerator
+{
+public:
+ cmCPackTypeMacro(cmCPackTXZGenerator, cmCPackArchiveGenerator);
+ /**
+ * Construct generator
+ */
+ cmCPackTXZGenerator();
+ ~cmCPackTXZGenerator() CM_OVERRIDE;
+
+protected:
+ const char* GetOutputExtension() CM_OVERRIDE { return ".tar.xz"; }
+};
+
+#endif
diff --git a/Source/CPack/cmCPackTarBZip2Generator.cxx b/Source/CPack/cmCPackTarBZip2Generator.cxx
new file mode 100644
index 0000000..694d392
--- /dev/null
+++ b/Source/CPack/cmCPackTarBZip2Generator.cxx
@@ -0,0 +1,22 @@
+/*============================================================================
+ CMake - Cross Platform Makefile Generator
+ Copyright 2000-2009 Kitware, Inc., Insight Software Consortium
+
+ Distributed under the OSI-approved BSD License (the "License");
+ see accompanying file Copyright.txt for details.
+
+ This software is distributed WITHOUT ANY WARRANTY; without even the
+ implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
+ See the License for more information.
+============================================================================*/
+
+#include "cmCPackTarBZip2Generator.h"
+
+cmCPackTarBZip2Generator::cmCPackTarBZip2Generator()
+ : cmCPackArchiveGenerator(cmArchiveWrite::CompressBZip2, "paxr")
+{
+}
+
+cmCPackTarBZip2Generator::~cmCPackTarBZip2Generator()
+{
+}
diff --git a/Source/CPack/cmCPackTarBZip2Generator.h b/Source/CPack/cmCPackTarBZip2Generator.h
new file mode 100644
index 0000000..6fec882
--- /dev/null
+++ b/Source/CPack/cmCPackTarBZip2Generator.h
@@ -0,0 +1,35 @@
+/*============================================================================
+ CMake - Cross Platform Makefile Generator
+ Copyright 2000-2009 Kitware, Inc.
+
+ Distributed under the OSI-approved BSD License (the "License");
+ see accompanying file Copyright.txt for details.
+
+ This software is distributed WITHOUT ANY WARRANTY; without even the
+ implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
+ See the License for more information.
+============================================================================*/
+
+#ifndef cmCPackTarBZip2Generator_h
+#define cmCPackTarBZip2Generator_h
+
+#include "cmCPackArchiveGenerator.h"
+
+/** \class cmCPackTarBZip2Generator
+ * \brief A generator for TarBZip2 files
+ */
+class cmCPackTarBZip2Generator : public cmCPackArchiveGenerator
+{
+public:
+ cmCPackTypeMacro(cmCPackTarBZip2Generator, cmCPackArchiveGenerator);
+ /**
+ * Construct generator
+ */
+ cmCPackTarBZip2Generator();
+ ~cmCPackTarBZip2Generator() CM_OVERRIDE;
+
+protected:
+ const char* GetOutputExtension() CM_OVERRIDE { return ".tar.bz2"; }
+};
+
+#endif
diff --git a/Source/CPack/cmCPackTarCompressGenerator.cxx b/Source/CPack/cmCPackTarCompressGenerator.cxx
new file mode 100644
index 0000000..aec6893
--- /dev/null
+++ b/Source/CPack/cmCPackTarCompressGenerator.cxx
@@ -0,0 +1,22 @@
+/*============================================================================
+ CMake - Cross Platform Makefile Generator
+ Copyright 2000-2009 Kitware, Inc., Insight Software Consortium
+
+ Distributed under the OSI-approved BSD License (the "License");
+ see accompanying file Copyright.txt for details.
+
+ This software is distributed WITHOUT ANY WARRANTY; without even the
+ implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
+ See the License for more information.
+============================================================================*/
+
+#include "cmCPackTarCompressGenerator.h"
+
+cmCPackTarCompressGenerator::cmCPackTarCompressGenerator()
+ : cmCPackArchiveGenerator(cmArchiveWrite::CompressCompress, "paxr")
+{
+}
+
+cmCPackTarCompressGenerator::~cmCPackTarCompressGenerator()
+{
+}
diff --git a/Source/CPack/cmCPackTarCompressGenerator.h b/Source/CPack/cmCPackTarCompressGenerator.h
new file mode 100644
index 0000000..02926a2
--- /dev/null
+++ b/Source/CPack/cmCPackTarCompressGenerator.h
@@ -0,0 +1,35 @@
+/*============================================================================
+ CMake - Cross Platform Makefile Generator
+ Copyright 2000-2009 Kitware, Inc.
+
+ Distributed under the OSI-approved BSD License (the "License");
+ see accompanying file Copyright.txt for details.
+
+ This software is distributed WITHOUT ANY WARRANTY; without even the
+ implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
+ See the License for more information.
+============================================================================*/
+
+#ifndef cmCPackTarCompressGenerator_h
+#define cmCPackTarCompressGenerator_h
+
+#include "cmCPackTGZGenerator.h"
+
+/** \class cmCPackTarCompressGenerator
+ * \brief A generator for TarCompress files
+ */
+class cmCPackTarCompressGenerator : public cmCPackArchiveGenerator
+{
+public:
+ cmCPackTypeMacro(cmCPackTarCompressGenerator, cmCPackArchiveGenerator);
+ /**
+ * Construct generator
+ */
+ cmCPackTarCompressGenerator();
+ ~cmCPackTarCompressGenerator() CM_OVERRIDE;
+
+protected:
+ const char* GetOutputExtension() CM_OVERRIDE { return ".tar.Z"; }
+};
+
+#endif
diff --git a/Source/CPack/cmCPackZIPGenerator.cxx b/Source/CPack/cmCPackZIPGenerator.cxx
new file mode 100644
index 0000000..9b42e6d
--- /dev/null
+++ b/Source/CPack/cmCPackZIPGenerator.cxx
@@ -0,0 +1,22 @@
+/*============================================================================
+ CMake - Cross Platform Makefile Generator
+ Copyright 2000-2009 Kitware, Inc., Insight Software Consortium
+
+ Distributed under the OSI-approved BSD License (the "License");
+ see accompanying file Copyright.txt for details.
+
+ This software is distributed WITHOUT ANY WARRANTY; without even the
+ implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
+ See the License for more information.
+============================================================================*/
+
+#include "cmCPackZIPGenerator.h"
+
+cmCPackZIPGenerator::cmCPackZIPGenerator()
+ : cmCPackArchiveGenerator(cmArchiveWrite::CompressNone, "zip")
+{
+}
+
+cmCPackZIPGenerator::~cmCPackZIPGenerator()
+{
+}
diff --git a/Source/CPack/cmCPackZIPGenerator.h b/Source/CPack/cmCPackZIPGenerator.h
new file mode 100644
index 0000000..1130826
--- /dev/null
+++ b/Source/CPack/cmCPackZIPGenerator.h
@@ -0,0 +1,36 @@
+/*============================================================================
+ CMake - Cross Platform Makefile Generator
+ Copyright 2000-2009 Kitware, Inc.
+
+ Distributed under the OSI-approved BSD License (the "License");
+ see accompanying file Copyright.txt for details.
+
+ This software is distributed WITHOUT ANY WARRANTY; without even the
+ implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
+ See the License for more information.
+============================================================================*/
+
+#ifndef cmCPackZIPGenerator_h
+#define cmCPackZIPGenerator_h
+
+#include "cmCPackArchiveGenerator.h"
+
+/** \class cmCPackZIPGenerator
+ * \brief A generator for ZIP files
+ */
+class cmCPackZIPGenerator : public cmCPackArchiveGenerator
+{
+public:
+ cmCPackTypeMacro(cmCPackZIPGenerator, cmCPackArchiveGenerator);
+
+ /**
+ * Construct generator
+ */
+ cmCPackZIPGenerator();
+ ~cmCPackZIPGenerator() CM_OVERRIDE;
+
+protected:
+ const char* GetOutputExtension() CM_OVERRIDE { return ".zip"; }
+};
+
+#endif
diff --git a/Source/CPack/cpack.cxx b/Source/CPack/cpack.cxx
new file mode 100644
index 0000000..771519c
--- /dev/null
+++ b/Source/CPack/cpack.cxx
@@ -0,0 +1,429 @@
+/*============================================================================
+ CMake - Cross Platform Makefile Generator
+ Copyright 2000-2009 Kitware, Inc., Insight Software Consortium
+
+ Distributed under the OSI-approved BSD License (the "License");
+ see accompanying file Copyright.txt for details.
+
+ This software is distributed WITHOUT ANY WARRANTY; without even the
+ implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
+ See the License for more information.
+============================================================================*/
+#include "cmSystemTools.h"
+
+// Need these for documentation support.
+#include "cmCPackGenerator.h"
+#include "cmCPackGeneratorFactory.h"
+#include "cmDocumentation.h"
+#include "cmGlobalGenerator.h"
+#include "cmMakefile.h"
+#include "cmake.h"
+#include "cmake.h"
+
+#include "cmCPackLog.h"
+
+#include <cmsys/CommandLineArguments.hxx>
+#include <cmsys/Encoding.hxx>
+#include <cmsys/SystemTools.hxx>
+
+static const char* cmDocumentationName[][2] = {
+ { CM_NULLPTR, " cpack - Packaging driver provided by CMake." },
+ { CM_NULLPTR, CM_NULLPTR }
+};
+
+static const char* cmDocumentationUsage[][2] = {
+ { CM_NULLPTR, " cpack -G <generator> [options]" },
+ { CM_NULLPTR, CM_NULLPTR }
+};
+
+static const char* cmDocumentationOptions[][2] = {
+ { "-G <generator>", "Use the specified generator to generate package." },
+ { "-C <Configuration>", "Specify the project configuration" },
+ { "-D <var>=<value>", "Set a CPack variable." },
+ { "--config <config file>", "Specify the config file." },
+ { "--verbose,-V", "enable verbose output" },
+ { "--debug", "enable debug output (for CPack developers)" },
+ { "-P <package name>", "override/define CPACK_PACKAGE_NAME" },
+ { "-R <package version>", "override/define CPACK_PACKAGE_VERSION" },
+ { "-B <package directory>", "override/define CPACK_PACKAGE_DIRECTORY" },
+ { "--vendor <vendor name>", "override/define CPACK_PACKAGE_VENDOR" },
+ { CM_NULLPTR, CM_NULLPTR }
+};
+
+int cpackUnknownArgument(const char*, void*)
+{
+ return 1;
+}
+
+struct cpackDefinitions
+{
+ typedef std::map<std::string, std::string> MapType;
+ MapType Map;
+ cmCPackLog* Log;
+};
+
+int cpackDefinitionArgument(const char* argument, const char* cValue,
+ void* call_data)
+{
+ (void)argument;
+ cpackDefinitions* def = static_cast<cpackDefinitions*>(call_data);
+ std::string value = cValue;
+ size_t pos = value.find_first_of('=');
+ if (pos == std::string::npos) {
+ cmCPack_Log(def->Log, cmCPackLog::LOG_ERROR,
+ "Please specify CPack definitions as: KEY=VALUE" << std::endl);
+ return 0;
+ }
+ std::string key = value.substr(0, pos);
+ value = value.c_str() + pos + 1;
+ def->Map[key] = value;
+ cmCPack_Log(def->Log, cmCPackLog::LOG_DEBUG, "Set CPack variable: "
+ << key << " to \"" << value << "\"" << std::endl);
+ return 1;
+}
+
+// this is CPack.
+int main(int argc, char const* const* argv)
+{
+ cmsys::Encoding::CommandLineArguments args =
+ cmsys::Encoding::CommandLineArguments::Main(argc, argv);
+ argc = args.argc();
+ argv = args.argv();
+
+ cmSystemTools::FindCMakeResources(argv[0]);
+ cmCPackLog log;
+
+ log.SetErrorPrefix("CPack Error: ");
+ log.SetWarningPrefix("CPack Warning: ");
+ log.SetOutputPrefix("CPack: ");
+ log.SetVerbosePrefix("CPack Verbose: ");
+
+ cmSystemTools::EnableMSVCDebugHook();
+
+ if (cmSystemTools::GetCurrentWorkingDirectory().empty()) {
+ cmCPack_Log(&log, cmCPackLog::LOG_ERROR,
+ "Current working directory cannot be established."
+ << std::endl);
+ return 1;
+ }
+
+ std::string generator;
+ bool help = false;
+ bool helpVersion = false;
+ bool verbose = false;
+ bool debug = false;
+ std::string helpFull;
+ std::string helpMAN;
+ std::string helpHTML;
+
+ std::string cpackProjectName;
+ std::string cpackProjectDirectory;
+ std::string cpackBuildConfig;
+ std::string cpackProjectVersion;
+ std::string cpackProjectPatch;
+ std::string cpackProjectVendor;
+ std::string cpackConfigFile;
+
+ cpackDefinitions definitions;
+ definitions.Log = &log;
+
+ cpackConfigFile = "";
+
+ cmsys::CommandLineArguments arg;
+ arg.Initialize(argc, argv);
+ typedef cmsys::CommandLineArguments argT;
+ // Help arguments
+ arg.AddArgument("--help", argT::NO_ARGUMENT, &help, "CPack help");
+ arg.AddArgument("--help-full", argT::SPACE_ARGUMENT, &helpFull,
+ "CPack help");
+ arg.AddArgument("--help-html", argT::SPACE_ARGUMENT, &helpHTML,
+ "CPack help");
+ arg.AddArgument("--help-man", argT::SPACE_ARGUMENT, &helpMAN, "CPack help");
+ arg.AddArgument("--version", argT::NO_ARGUMENT, &helpVersion, "CPack help");
+
+ arg.AddArgument("-V", argT::NO_ARGUMENT, &verbose, "CPack verbose");
+ arg.AddArgument("--verbose", argT::NO_ARGUMENT, &verbose, "-V");
+ arg.AddArgument("--debug", argT::NO_ARGUMENT, &debug, "-V");
+ arg.AddArgument("--config", argT::SPACE_ARGUMENT, &cpackConfigFile,
+ "CPack configuration file");
+ arg.AddArgument("-C", argT::SPACE_ARGUMENT, &cpackBuildConfig,
+ "CPack build configuration");
+ arg.AddArgument("-G", argT::SPACE_ARGUMENT, &generator, "CPack generator");
+ arg.AddArgument("-P", argT::SPACE_ARGUMENT, &cpackProjectName,
+ "CPack project name");
+ arg.AddArgument("-R", argT::SPACE_ARGUMENT, &cpackProjectVersion,
+ "CPack project version");
+ arg.AddArgument("-B", argT::SPACE_ARGUMENT, &cpackProjectDirectory,
+ "CPack project directory");
+ arg.AddArgument("--patch", argT::SPACE_ARGUMENT, &cpackProjectPatch,
+ "CPack project patch");
+ arg.AddArgument("--vendor", argT::SPACE_ARGUMENT, &cpackProjectVendor,
+ "CPack project vendor");
+ arg.AddCallback("-D", argT::SPACE_ARGUMENT, cpackDefinitionArgument,
+ &definitions, "CPack Definitions");
+ arg.SetUnknownArgumentCallback(cpackUnknownArgument);
+
+ // Parse command line
+ int parsed = arg.Parse();
+
+ // Setup logging
+ if (verbose) {
+ log.SetVerbose(verbose);
+ cmCPack_Log(&log, cmCPackLog::LOG_OUTPUT, "Enable Verbose" << std::endl);
+ }
+ if (debug) {
+ log.SetDebug(debug);
+ cmCPack_Log(&log, cmCPackLog::LOG_OUTPUT, "Enable Debug" << std::endl);
+ }
+
+ cmCPack_Log(&log, cmCPackLog::LOG_VERBOSE,
+ "Read CPack config file: " << cpackConfigFile << std::endl);
+
+ cmake cminst;
+ cminst.SetHomeDirectory("");
+ cminst.SetHomeOutputDirectory("");
+ cminst.GetCurrentSnapshot().SetDefaultDefinitions();
+ cminst.GetState()->RemoveUnscriptableCommands();
+ cmGlobalGenerator cmgg(&cminst);
+ CM_AUTO_PTR<cmMakefile> globalMF(
+ new cmMakefile(&cmgg, cminst.GetCurrentSnapshot()));
+#if defined(__CYGWIN__)
+ globalMF->AddDefinition("CMAKE_LEGACY_CYGWIN_WIN32", "0");
+#endif
+
+ bool cpackConfigFileSpecified = true;
+ if (cpackConfigFile.empty()) {
+ cpackConfigFile = cmSystemTools::GetCurrentWorkingDirectory();
+ cpackConfigFile += "/CPackConfig.cmake";
+ cpackConfigFileSpecified = false;
+ }
+
+ cmCPackGeneratorFactory generators;
+ generators.SetLogger(&log);
+ cmCPackGenerator* cpackGenerator = CM_NULLPTR;
+
+ cmDocumentation doc;
+ doc.addCPackStandardDocSections();
+ /* Were we invoked to display doc or to do some work ?
+ * Unlike cmake launching cpack with zero argument
+ * should launch cpack using "cpackConfigFile" if it exists
+ * in the current directory.
+ */
+ help = doc.CheckOptions(argc, argv, "-G") && argc != 1;
+
+ // This part is used for cpack documentation lookup as well.
+ cminst.AddCMakePaths();
+
+ if (parsed && !help) {
+ // find out which system cpack is running on, so it can setup the search
+ // paths, so FIND_XXX() commands can be used in scripts
+ std::string systemFile =
+ globalMF->GetModulesFile("CMakeDetermineSystem.cmake");
+ if (!globalMF->ReadListFile(systemFile.c_str())) {
+ cmCPack_Log(&log, cmCPackLog::LOG_ERROR,
+ "Error reading CMakeDetermineSystem.cmake" << std::endl);
+ return 1;
+ }
+
+ systemFile =
+ globalMF->GetModulesFile("CMakeSystemSpecificInformation.cmake");
+ if (!globalMF->ReadListFile(systemFile.c_str())) {
+ cmCPack_Log(&log, cmCPackLog::LOG_ERROR,
+ "Error reading CMakeSystemSpecificInformation.cmake"
+ << std::endl);
+ return 1;
+ }
+
+ if (!cpackBuildConfig.empty()) {
+ globalMF->AddDefinition("CPACK_BUILD_CONFIG", cpackBuildConfig.c_str());
+ }
+
+ if (cmSystemTools::FileExists(cpackConfigFile.c_str())) {
+ cpackConfigFile = cmSystemTools::CollapseFullPath(cpackConfigFile);
+ cmCPack_Log(&log, cmCPackLog::LOG_VERBOSE,
+ "Read CPack configuration file: " << cpackConfigFile
+ << std::endl);
+ if (!globalMF->ReadListFile(cpackConfigFile.c_str())) {
+ cmCPack_Log(&log, cmCPackLog::LOG_ERROR,
+ "Problem reading CPack config file: \""
+ << cpackConfigFile << "\"" << std::endl);
+ return 1;
+ }
+ } else if (cpackConfigFileSpecified) {
+ cmCPack_Log(&log, cmCPackLog::LOG_ERROR,
+ "Cannot find CPack config file: \"" << cpackConfigFile
+ << "\"" << std::endl);
+ return 1;
+ }
+
+ if (!generator.empty()) {
+ globalMF->AddDefinition("CPACK_GENERATOR", generator.c_str());
+ }
+ if (!cpackProjectName.empty()) {
+ globalMF->AddDefinition("CPACK_PACKAGE_NAME", cpackProjectName.c_str());
+ }
+ if (!cpackProjectVersion.empty()) {
+ globalMF->AddDefinition("CPACK_PACKAGE_VERSION",
+ cpackProjectVersion.c_str());
+ }
+ if (!cpackProjectVendor.empty()) {
+ globalMF->AddDefinition("CPACK_PACKAGE_VENDOR",
+ cpackProjectVendor.c_str());
+ }
+ // if this is not empty it has been set on the command line
+ // go for it. Command line override values set in config file.
+ if (!cpackProjectDirectory.empty()) {
+ globalMF->AddDefinition("CPACK_PACKAGE_DIRECTORY",
+ cpackProjectDirectory.c_str());
+ }
+ // The value has not been set on the command line
+ else {
+ // get a default value (current working directory)
+ cpackProjectDirectory = cmsys::SystemTools::GetCurrentWorkingDirectory();
+ // use default value iff no value has been provided by the config file
+ if (!globalMF->IsSet("CPACK_PACKAGE_DIRECTORY")) {
+ globalMF->AddDefinition("CPACK_PACKAGE_DIRECTORY",
+ cpackProjectDirectory.c_str());
+ }
+ }
+ cpackDefinitions::MapType::iterator cdit;
+ for (cdit = definitions.Map.begin(); cdit != definitions.Map.end();
+ ++cdit) {
+ globalMF->AddDefinition(cdit->first, cdit->second.c_str());
+ }
+
+ const char* cpackModulesPath =
+ globalMF->GetDefinition("CPACK_MODULE_PATH");
+ if (cpackModulesPath) {
+ globalMF->AddDefinition("CMAKE_MODULE_PATH", cpackModulesPath);
+ }
+ const char* genList = globalMF->GetDefinition("CPACK_GENERATOR");
+ if (!genList) {
+ cmCPack_Log(&log, cmCPackLog::LOG_ERROR, "CPack generator not specified"
+ << std::endl);
+ } else {
+ std::vector<std::string> generatorsVector;
+ cmSystemTools::ExpandListArgument(genList, generatorsVector);
+ std::vector<std::string>::iterator it;
+ for (it = generatorsVector.begin(); it != generatorsVector.end(); ++it) {
+ const char* gen = it->c_str();
+ cmMakefile::ScopePushPop raii(globalMF.get());
+ cmMakefile* mf = globalMF.get();
+ cmCPack_Log(&log, cmCPackLog::LOG_VERBOSE,
+ "Specified generator: " << gen << std::endl);
+ if (parsed && !mf->GetDefinition("CPACK_PACKAGE_NAME")) {
+ cmCPack_Log(&log, cmCPackLog::LOG_ERROR,
+ "CPack project name not specified" << std::endl);
+ parsed = 0;
+ }
+ if (parsed &&
+ !(mf->GetDefinition("CPACK_PACKAGE_VERSION") ||
+ (mf->GetDefinition("CPACK_PACKAGE_VERSION_MAJOR") &&
+ mf->GetDefinition("CPACK_PACKAGE_VERSION_MINOR") &&
+ mf->GetDefinition("CPACK_PACKAGE_VERSION_PATCH")))) {
+ cmCPack_Log(&log, cmCPackLog::LOG_ERROR,
+ "CPack project version not specified"
+ << std::endl
+ << "Specify CPACK_PACKAGE_VERSION, or "
+ "CPACK_PACKAGE_VERSION_MAJOR, "
+ "CPACK_PACKAGE_VERSION_MINOR, and "
+ "CPACK_PACKAGE_VERSION_PATCH."
+ << std::endl);
+ parsed = 0;
+ }
+ if (parsed) {
+ cpackGenerator = generators.NewGenerator(gen);
+ if (!cpackGenerator) {
+ cmCPack_Log(&log, cmCPackLog::LOG_ERROR,
+ "Cannot initialize CPack generator: " << gen
+ << std::endl);
+ parsed = 0;
+ }
+ if (parsed && !cpackGenerator->Initialize(gen, mf)) {
+ cmCPack_Log(&log, cmCPackLog::LOG_ERROR,
+ "Cannot initialize the generator " << gen
+ << std::endl);
+ parsed = 0;
+ }
+
+ if (!mf->GetDefinition("CPACK_INSTALL_COMMANDS") &&
+ !mf->GetDefinition("CPACK_INSTALLED_DIRECTORIES") &&
+ !mf->GetDefinition("CPACK_INSTALL_CMAKE_PROJECTS")) {
+ cmCPack_Log(
+ &log, cmCPackLog::LOG_ERROR,
+ "Please specify build tree of the project that uses CMake "
+ "using CPACK_INSTALL_CMAKE_PROJECTS, specify "
+ "CPACK_INSTALL_COMMANDS, or specify "
+ "CPACK_INSTALLED_DIRECTORIES."
+ << std::endl);
+ parsed = 0;
+ }
+ if (parsed) {
+ const char* projName = mf->GetDefinition("CPACK_PACKAGE_NAME");
+ cmCPack_Log(&log, cmCPackLog::LOG_VERBOSE, "Use generator: "
+ << cpackGenerator->GetNameOfClass() << std::endl);
+ cmCPack_Log(&log, cmCPackLog::LOG_VERBOSE,
+ "For project: " << projName << std::endl);
+
+ const char* projVersion =
+ mf->GetDefinition("CPACK_PACKAGE_VERSION");
+ if (!projVersion) {
+ const char* projVersionMajor =
+ mf->GetDefinition("CPACK_PACKAGE_VERSION_MAJOR");
+ const char* projVersionMinor =
+ mf->GetDefinition("CPACK_PACKAGE_VERSION_MINOR");
+ const char* projVersionPatch =
+ mf->GetDefinition("CPACK_PACKAGE_VERSION_PATCH");
+ std::ostringstream ostr;
+ ostr << projVersionMajor << "." << projVersionMinor << "."
+ << projVersionPatch;
+ mf->AddDefinition("CPACK_PACKAGE_VERSION", ostr.str().c_str());
+ }
+
+ int res = cpackGenerator->DoPackage();
+ if (!res) {
+ cmCPack_Log(&log, cmCPackLog::LOG_ERROR,
+ "Error when generating package: " << projName
+ << std::endl);
+ return 1;
+ }
+ }
+ }
+ }
+ }
+ }
+
+ /* In this case we are building the documentation object
+ * instance in order to create appropriate structure
+ * in order to satisfy the appropriate --help-xxx request
+ */
+ if (help) {
+ // Construct and print requested documentation.
+
+ doc.SetName("cpack");
+ doc.SetSection("Name", cmDocumentationName);
+ doc.SetSection("Usage", cmDocumentationUsage);
+ doc.PrependSection("Options", cmDocumentationOptions);
+
+ std::vector<cmDocumentationEntry> v;
+ cmCPackGeneratorFactory::DescriptionsMap::const_iterator generatorIt;
+ for (generatorIt = generators.GetGeneratorsList().begin();
+ generatorIt != generators.GetGeneratorsList().end(); ++generatorIt) {
+ cmDocumentationEntry e;
+ e.Name = generatorIt->first;
+ e.Brief = generatorIt->second;
+ v.push_back(e);
+ }
+ doc.SetSection("Generators", v);
+
+#undef cout
+ return doc.PrintRequestedDocumentation(std::cout) ? 0 : 1;
+#define cout no_cout_use_cmCPack_Log
+ }
+
+ if (cmSystemTools::GetErrorOccuredFlag()) {
+ return 1;
+ }
+
+ return 0;
+}
diff --git a/Source/CPack/cygwin.readme b/Source/CPack/cygwin.readme
new file mode 100644
index 0000000..c0cd4b9
--- /dev/null
+++ b/Source/CPack/cygwin.readme
@@ -0,0 +1,69 @@
+http://cygwin.com/setup.html
+
+
+Need to produce two tar files:
+
+Source-
+
+- create subdirs
+- copy src
+- duplicate src
+- configure files into duplicate src
+ CPack.cygwin-readme.in
+ CPack.cygwin-install.sh.in
+ CPack.setup.hint.in
+- diff duplicate src and orig src
+- write diff into toplevel
+- create tar file call super class
+
+cmake-2.2.3-1
+
+
+1. a source release
+cmake-2.2.3-2-src.tar.bz2
+
+cmake-2.2.3-2.patch has cmake-2.2.3/CYGWIN-PATCHES/cmake.README cmake-2.2.3/CYGWIN-PATCHES/setup.hint
+cmake-2.2.3-2.sh -> script to create cygwin release
+cmake-2.2.3.tar.bz2 -> unmodified cmake sources for 2.2.3
+
+
+
+
+
+2 a binary release
+cmake-2.2.3-2.tar.bz2
+
+normal binary release with use as the root of the tree:
+
+Here is the bootstrap command used:
+
+ ${SOURCE_DIR}/bootstrap --prefix=/usr --datadir=/share/cmake-${VER} \
+ --docdir=/share/doc/cmake-${VER} --mandir=/share/man
+
+CMAKE_DOC_DIR /share/doc/${PKG}-${VER}
+CMAKE_MAN_DIR /share/man
+CMAKE_DATA_DIR /share/${PKG}-${VER}
+
+Here is the directory stucture:
+
+usr/bin/cmake.exe
+usr/share/doc/cmake-2.2.3/MANIFEST ***
+usr/share/doc/Cygwin/cmake-2.2.3-2.README ****
+usr/share/cmake-2.2.3/Modules
+
+
+
+usr/bin
+usr/share/cmake-2.2.3/include
+usr/share/cmake-2.2.3/Modules/Platform
+usr/share/cmake-2.2.3/Modules
+usr/share/cmake-2.2.3/Templates
+usr/share/cmake-2.2.3
+usr/share/doc/cmake-2.2.3
+usr/share/doc/Cygwin
+usr/share/doc
+usr/share/man/man1
+usr/share/man
+usr/share
+usr
+