You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
1161 lines
39 KiB
1161 lines
39 KiB
/* Distributed under the OSI-approved BSD 3-Clause License. See accompanying
|
|
file Copyright.txt or https://cmake.org/licensing for details. */
|
|
|
|
#include "cmCPackInnoSetupGenerator.h"
|
|
|
|
#include <algorithm>
|
|
#include <cctype>
|
|
#include <cstdlib>
|
|
#include <ostream>
|
|
#include <utility>
|
|
|
|
#include "cmsys/RegularExpression.hxx"
|
|
|
|
#include "cmCPackComponentGroup.h"
|
|
#include "cmCPackLog.h"
|
|
#include "cmDuration.h"
|
|
#include "cmGeneratedFileStream.h"
|
|
#include "cmList.h"
|
|
#include "cmStringAlgorithms.h"
|
|
#include "cmSystemTools.h"
|
|
|
|
cmCPackInnoSetupGenerator::cmCPackInnoSetupGenerator() = default;
|
|
cmCPackInnoSetupGenerator::~cmCPackInnoSetupGenerator() = default;
|
|
|
|
bool cmCPackInnoSetupGenerator::CanGenerate()
|
|
{
|
|
return true;
|
|
}
|
|
|
|
int cmCPackInnoSetupGenerator::InitializeInternal()
|
|
{
|
|
if (GetOption("CPACK_INCLUDE_TOPLEVEL_DIRECTORY").IsOn()) {
|
|
cmCPackLogger(cmCPackLog::LOG_WARNING,
|
|
"Inno Setup Generator cannot work with "
|
|
"CPACK_INCLUDE_TOPLEVEL_DIRECTORY set. "
|
|
"This option will be reset to 0 (for this generator only)."
|
|
<< std::endl);
|
|
SetOption("CPACK_INCLUDE_TOPLEVEL_DIRECTORY", nullptr);
|
|
}
|
|
|
|
std::vector<std::string> path;
|
|
|
|
#ifdef _WIN32
|
|
path.push_back("C:\\Program Files (x86)\\Inno Setup 5");
|
|
path.push_back("C:\\Program Files (x86)\\Inno Setup 6");
|
|
#endif
|
|
|
|
SetOptionIfNotSet("CPACK_INNOSETUP_EXECUTABLE", "ISCC");
|
|
const std::string& isccPath = cmSystemTools::FindProgram(
|
|
GetOption("CPACK_INNOSETUP_EXECUTABLE"), path, false);
|
|
|
|
if (isccPath.empty()) {
|
|
cmCPackLogger(cmCPackLog::LOG_ERROR,
|
|
"Cannot find Inno Setup compiler ISCC: "
|
|
"likely it is not installed, or not in your PATH"
|
|
<< std::endl);
|
|
|
|
return 0;
|
|
}
|
|
|
|
const std::string isccCmd =
|
|
cmStrCat(QuotePath(isccPath, PathType::Native), "/?");
|
|
cmCPackLogger(cmCPackLog::LOG_VERBOSE,
|
|
"Test Inno Setup version: " << isccCmd << std::endl);
|
|
std::string output;
|
|
cmSystemTools::RunSingleCommand(isccCmd, &output, &output, nullptr, nullptr,
|
|
this->GeneratorVerbose, cmDuration::zero());
|
|
cmsys::RegularExpression vRex("Inno Setup ([0-9]+)");
|
|
if (!vRex.find(output)) {
|
|
cmCPackLogger(cmCPackLog::LOG_ERROR,
|
|
"Problem checking Inno Setup version with command: "
|
|
<< isccCmd << std::endl
|
|
<< "Have you downloaded Inno Setup from "
|
|
"https://jrsoftware.org/isinfo.php?"
|
|
<< std::endl);
|
|
return 0;
|
|
}
|
|
|
|
const int isccVersion = atoi(vRex.match(1).c_str());
|
|
const int minIsccVersion = 6;
|
|
cmCPackLogger(cmCPackLog::LOG_DEBUG,
|
|
"Inno Setup Version: " << isccVersion << std::endl);
|
|
|
|
if (isccVersion < minIsccVersion) {
|
|
cmCPackLogger(cmCPackLog::LOG_ERROR,
|
|
"CPack requires Inno Setup Version 6 or greater. "
|
|
"Inno Setup found on the system was: "
|
|
<< isccVersion << std::endl);
|
|
return 0;
|
|
}
|
|
|
|
SetOption("CPACK_INSTALLER_PROGRAM", isccPath);
|
|
|
|
return this->Superclass::InitializeInternal();
|
|
}
|
|
|
|
int cmCPackInnoSetupGenerator::PackageFiles()
|
|
{
|
|
// Includes
|
|
if (IsSet("CPACK_INNOSETUP_EXTRA_SCRIPTS")) {
|
|
const cmList extraScripts(GetOption("CPACK_INNOSETUP_EXTRA_SCRIPTS"));
|
|
|
|
for (const std::string& i : extraScripts) {
|
|
includeDirectives.emplace_back(cmStrCat(
|
|
"#include ", QuotePath(cmSystemTools::CollapseFullPath(i, toplevel))));
|
|
}
|
|
}
|
|
|
|
// [Languages] section
|
|
SetOptionIfNotSet("CPACK_INNOSETUP_LANGUAGES", "english");
|
|
const cmList languages(GetOption("CPACK_INNOSETUP_LANGUAGES"));
|
|
for (std::string i : languages) {
|
|
cmCPackInnoSetupKeyValuePairs params;
|
|
|
|
params["Name"] = Quote(i);
|
|
|
|
if (cmSystemTools::LowerCase(i) == "english") {
|
|
params["MessagesFile"] = "\"compiler:Default.isl\"";
|
|
} else {
|
|
i[0] = static_cast<char>(std::toupper(i[0]));
|
|
params["MessagesFile"] = cmStrCat("\"compiler:Languages\\", i, ".isl\"");
|
|
}
|
|
|
|
languageInstructions.push_back(ISKeyValueLine(params));
|
|
}
|
|
|
|
if (!Components.empty() && !ProcessComponents()) {
|
|
return false;
|
|
}
|
|
|
|
if (!(ProcessSetupSection() && ProcessFiles())) {
|
|
return false;
|
|
}
|
|
|
|
// [Code] section
|
|
if (IsSet("CPACK_INNOSETUP_CODE_FILES")) {
|
|
const cmList codeFiles(GetOption("CPACK_INNOSETUP_CODE_FILES"));
|
|
|
|
for (const std::string& i : codeFiles) {
|
|
codeIncludes.emplace_back(cmStrCat(
|
|
"#include ", QuotePath(cmSystemTools::CollapseFullPath(i, toplevel))));
|
|
}
|
|
}
|
|
|
|
return ConfigureISScript() && Compile();
|
|
}
|
|
|
|
bool cmCPackInnoSetupGenerator::ProcessSetupSection()
|
|
{
|
|
if (!RequireOption("CPACK_PACKAGE_INSTALL_REGISTRY_KEY")) {
|
|
return false;
|
|
}
|
|
setupDirectives["AppId"] = GetOption("CPACK_PACKAGE_INSTALL_REGISTRY_KEY");
|
|
|
|
if (!RequireOption("CPACK_PACKAGE_NAME")) {
|
|
return false;
|
|
}
|
|
setupDirectives["AppName"] = GetOption("CPACK_PACKAGE_NAME");
|
|
setupDirectives["UninstallDisplayName"] = GetOption("CPACK_PACKAGE_NAME");
|
|
|
|
if (!RequireOption("CPACK_PACKAGE_VERSION")) {
|
|
return false;
|
|
}
|
|
setupDirectives["AppVersion"] = GetOption("CPACK_PACKAGE_VERSION");
|
|
|
|
if (!RequireOption("CPACK_PACKAGE_VENDOR")) {
|
|
return false;
|
|
}
|
|
setupDirectives["AppPublisher"] = GetOption("CPACK_PACKAGE_VENDOR");
|
|
|
|
if (IsSet("CPACK_PACKAGE_HOMEPAGE_URL")) {
|
|
setupDirectives["AppPublisherURL"] =
|
|
GetOption("CPACK_PACKAGE_HOMEPAGE_URL");
|
|
setupDirectives["AppSupportURL"] = GetOption("CPACK_PACKAGE_HOMEPAGE_URL");
|
|
setupDirectives["AppUpdatesURL"] = GetOption("CPACK_PACKAGE_HOMEPAGE_URL");
|
|
}
|
|
|
|
SetOptionIfNotSet("CPACK_INNOSETUP_IGNORE_LICENSE_PAGE", "OFF");
|
|
if (IsSet("CPACK_RESOURCE_FILE_LICENSE") &&
|
|
!GetOption("CPACK_INNOSETUP_IGNORE_LICENSE_PAGE").IsOn()) {
|
|
setupDirectives["LicenseFile"] = cmSystemTools::ConvertToWindowsOutputPath(
|
|
GetOption("CPACK_RESOURCE_FILE_LICENSE"));
|
|
}
|
|
|
|
SetOptionIfNotSet("CPACK_INNOSETUP_IGNORE_README_PAGE", "ON");
|
|
if (IsSet("CPACK_RESOURCE_FILE_README") &&
|
|
!GetOption("CPACK_INNOSETUP_IGNORE_README_PAGE").IsOn()) {
|
|
setupDirectives["InfoBeforeFile"] =
|
|
cmSystemTools::ConvertToWindowsOutputPath(
|
|
GetOption("CPACK_RESOURCE_FILE_README"));
|
|
}
|
|
|
|
SetOptionIfNotSet("CPACK_INNOSETUP_USE_MODERN_WIZARD", "OFF");
|
|
if (GetOption("CPACK_INNOSETUP_USE_MODERN_WIZARD").IsOn()) {
|
|
setupDirectives["WizardStyle"] = "modern";
|
|
} else {
|
|
setupDirectives["WizardStyle"] = "classic";
|
|
setupDirectives["WizardSmallImageFile"] =
|
|
"compiler:WizClassicSmallImage.bmp";
|
|
setupDirectives["WizardImageFile"] = "compiler:WizClassicImage.bmp";
|
|
setupDirectives["SetupIconFile"] = "compiler:SetupClassicIcon.ico";
|
|
}
|
|
|
|
if (IsSet("CPACK_INNOSETUP_ICON_FILE")) {
|
|
setupDirectives["SetupIconFile"] =
|
|
cmSystemTools::ConvertToWindowsOutputPath(
|
|
GetOption("CPACK_INNOSETUP_ICON_FILE"));
|
|
}
|
|
|
|
if (IsSet("CPACK_PACKAGE_ICON")) {
|
|
setupDirectives["WizardSmallImageFile"] =
|
|
cmSystemTools::ConvertToWindowsOutputPath(
|
|
GetOption("CPACK_PACKAGE_ICON"));
|
|
}
|
|
|
|
if (!RequireOption("CPACK_PACKAGE_INSTALL_DIRECTORY")) {
|
|
return false;
|
|
}
|
|
SetOptionIfNotSet("CPACK_INNOSETUP_INSTALL_ROOT", "{autopf}");
|
|
setupDirectives["DefaultDirName"] =
|
|
cmSystemTools::ConvertToWindowsOutputPath(
|
|
cmStrCat(GetOption("CPACK_INNOSETUP_INSTALL_ROOT"), '\\',
|
|
GetOption("CPACK_PACKAGE_INSTALL_DIRECTORY")));
|
|
|
|
SetOptionIfNotSet("CPACK_INNOSETUP_ALLOW_CUSTOM_DIRECTORY", "ON");
|
|
if (GetOption("CPACK_INNOSETUP_ALLOW_CUSTOM_DIRECTORY").IsOff()) {
|
|
setupDirectives["DisableDirPage"] = "yes";
|
|
}
|
|
|
|
SetOptionIfNotSet("CPACK_INNOSETUP_PROGRAM_MENU_FOLDER",
|
|
GetOption("CPACK_PACKAGE_NAME"));
|
|
if (GetOption("CPACK_INNOSETUP_PROGRAM_MENU_FOLDER") == ".") {
|
|
setupDirectives["DisableProgramGroupPage"] = "yes";
|
|
toplevelProgramFolder = true;
|
|
} else {
|
|
setupDirectives["DefaultGroupName"] =
|
|
GetOption("CPACK_INNOSETUP_PROGRAM_MENU_FOLDER");
|
|
toplevelProgramFolder = false;
|
|
}
|
|
|
|
if (IsSet("CPACK_INNOSETUP_PASSWORD")) {
|
|
setupDirectives["Password"] = GetOption("CPACK_INNOSETUP_PASSWORD");
|
|
setupDirectives["Encryption"] = "yes";
|
|
}
|
|
|
|
/*
|
|
* These directives can only be modified using the
|
|
* CPACK_INNOSETUP_SETUP_<directive> variables
|
|
*/
|
|
setupDirectives["ShowLanguageDialog"] = "auto";
|
|
setupDirectives["AllowNoIcons"] = "yes";
|
|
setupDirectives["Compression"] = "lzma";
|
|
setupDirectives["SolidCompression"] = "yes";
|
|
|
|
// Output file and directory
|
|
if (!RequireOption("CPACK_PACKAGE_FILE_NAME")) {
|
|
return false;
|
|
}
|
|
setupDirectives["OutputBaseFilename"] = GetOption("CPACK_PACKAGE_FILE_NAME");
|
|
|
|
if (!RequireOption("CPACK_TOPLEVEL_DIRECTORY")) {
|
|
return false;
|
|
}
|
|
setupDirectives["OutputDir"] = cmSystemTools::ConvertToWindowsOutputPath(
|
|
GetOption("CPACK_TOPLEVEL_DIRECTORY"));
|
|
|
|
setupDirectives["SourceDir"] =
|
|
cmSystemTools::ConvertToWindowsOutputPath(toplevel);
|
|
|
|
// Target architecture
|
|
if (!RequireOption("CPACK_INNOSETUP_ARCHITECTURE")) {
|
|
return false;
|
|
}
|
|
|
|
cmValue const architecture = GetOption("CPACK_INNOSETUP_ARCHITECTURE");
|
|
if (architecture != "x86" && architecture != "x64" &&
|
|
architecture != "arm64" && architecture != "ia64") {
|
|
cmCPackLogger(cmCPackLog::LOG_ERROR,
|
|
"CPACK_INNOSETUP_ARCHITECTURE must be either x86, x64, "
|
|
"arm64 or ia64"
|
|
<< std::endl);
|
|
return false;
|
|
}
|
|
|
|
// The following directives must not be set to target x86
|
|
if (architecture != "x86") {
|
|
setupDirectives["ArchitecturesAllowed"] = architecture;
|
|
setupDirectives["ArchitecturesInstallIn64BitMode"] = architecture;
|
|
}
|
|
|
|
/*
|
|
* Handle custom directives (they have higher priority than other variables,
|
|
* so they have to be processed after all other variables)
|
|
*/
|
|
for (const std::string& i : GetOptions()) {
|
|
if (cmHasPrefix(i, "CPACK_INNOSETUP_SETUP_")) {
|
|
const std::string& directive =
|
|
i.substr(cmStrLen("CPACK_INNOSETUP_SETUP_"));
|
|
setupDirectives[directive] = GetOption(i);
|
|
}
|
|
}
|
|
|
|
return true;
|
|
}
|
|
|
|
bool cmCPackInnoSetupGenerator::ProcessFiles()
|
|
{
|
|
std::map<std::string, std::string> customFileInstructions;
|
|
if (IsSet("CPACK_INNOSETUP_CUSTOM_INSTALL_INSTRUCTIONS")) {
|
|
const cmList instructions(
|
|
GetOption("CPACK_INNOSETUP_CUSTOM_INSTALL_INSTRUCTIONS"));
|
|
if (instructions.size() % 2 != 0) {
|
|
cmCPackLogger(cmCPackLog::LOG_ERROR,
|
|
"CPACK_INNOSETUP_CUSTOM_INSTALL_INSTRUCTIONS should "
|
|
"contain pairs of <path> and <instruction>"
|
|
<< std::endl);
|
|
return false;
|
|
}
|
|
|
|
for (auto it = instructions.begin(); it != instructions.end(); ++it) {
|
|
const std::string& key =
|
|
QuotePath(cmSystemTools::CollapseFullPath(*it, toplevel));
|
|
customFileInstructions[key] = *(++it);
|
|
}
|
|
}
|
|
|
|
const std::string& iconsPrefix =
|
|
toplevelProgramFolder ? "{autoprograms}\\" : "{group}\\";
|
|
|
|
std::map<std::string, std::string> icons;
|
|
if (IsSet("CPACK_PACKAGE_EXECUTABLES")) {
|
|
const cmList executables(GetOption("CPACK_PACKAGE_EXECUTABLES"));
|
|
if (executables.size() % 2 != 0) {
|
|
cmCPackLogger(cmCPackLog::LOG_ERROR,
|
|
"CPACK_PACKAGE_EXECUTABLES should should contain pairs of "
|
|
"<executable> and <text label>"
|
|
<< std::endl);
|
|
return false;
|
|
}
|
|
|
|
for (auto it = executables.begin(); it != executables.end(); ++it) {
|
|
const std::string& key = *it;
|
|
icons[key] = *(++it);
|
|
}
|
|
}
|
|
|
|
std::vector<std::string> desktopIcons;
|
|
if (IsSet("CPACK_CREATE_DESKTOP_LINKS")) {
|
|
cmExpandList(GetOption("CPACK_CREATE_DESKTOP_LINKS"), desktopIcons);
|
|
}
|
|
|
|
std::vector<std::string> runExecutables;
|
|
if (IsSet("CPACK_INNOSETUP_RUN_EXECUTABLES")) {
|
|
cmExpandList(GetOption("CPACK_INNOSETUP_RUN_EXECUTABLES"), runExecutables);
|
|
}
|
|
|
|
for (const std::string& i : files) {
|
|
cmCPackInnoSetupKeyValuePairs params;
|
|
|
|
std::string toplevelDirectory;
|
|
std::string outputDir;
|
|
cmCPackComponent* component = nullptr;
|
|
std::string componentParam;
|
|
if (!Components.empty()) {
|
|
const std::string& fileName = cmSystemTools::RelativePath(toplevel, i);
|
|
const std::string::size_type pos = fileName.find('/');
|
|
|
|
// Use the custom component install directory if we have one
|
|
if (pos != std::string::npos) {
|
|
const std::string& componentName = fileName.substr(0, pos);
|
|
component = &Components[componentName];
|
|
|
|
toplevelDirectory =
|
|
cmSystemTools::CollapseFullPath(componentName, toplevel);
|
|
outputDir = CustomComponentInstallDirectory(component);
|
|
componentParam =
|
|
CreateRecursiveComponentPath(component->Group, component->Name);
|
|
|
|
if (component->IsHidden && component->IsDisabledByDefault) {
|
|
continue;
|
|
}
|
|
|
|
if (component->IsHidden) {
|
|
componentParam.clear();
|
|
}
|
|
} else {
|
|
// Don't install component directories
|
|
continue;
|
|
}
|
|
} else {
|
|
toplevelDirectory = toplevel;
|
|
outputDir = "{app}";
|
|
}
|
|
|
|
if (!componentParam.empty()) {
|
|
params["Components"] = componentParam;
|
|
}
|
|
|
|
if (cmSystemTools::FileIsDirectory(i)) {
|
|
// Custom instructions replace the automatic generated instructions
|
|
if (customFileInstructions.count(QuotePath(i))) {
|
|
dirInstructions.push_back(customFileInstructions[QuotePath(i)]);
|
|
} else {
|
|
std::string destDir = cmSystemTools::ConvertToWindowsOutputPath(
|
|
cmStrCat(outputDir, '\\',
|
|
cmSystemTools::RelativePath(toplevelDirectory, i)));
|
|
cmStripSuffixIfExists(destDir, '\\');
|
|
|
|
params["Name"] = QuotePath(destDir);
|
|
|
|
dirInstructions.push_back(ISKeyValueLine(params));
|
|
}
|
|
} else {
|
|
// Custom instructions replace the automatic generated instructions
|
|
if (customFileInstructions.count(QuotePath(i))) {
|
|
fileInstructions.push_back(customFileInstructions[QuotePath(i)]);
|
|
} else {
|
|
std::string destDir = cmSystemTools::ConvertToWindowsOutputPath(
|
|
cmStrCat(outputDir, '\\',
|
|
cmSystemTools::GetParentDirectory(
|
|
cmSystemTools::RelativePath(toplevelDirectory, i))));
|
|
cmStripSuffixIfExists(destDir, '\\');
|
|
|
|
params["DestDir"] = QuotePath(destDir);
|
|
|
|
if (component != nullptr && component->IsDownloaded) {
|
|
const std::string& archiveName =
|
|
cmSystemTools::GetFilenameWithoutLastExtension(
|
|
component->ArchiveFile);
|
|
const std::string& relativePath =
|
|
cmSystemTools::RelativePath(toplevelDirectory, i);
|
|
|
|
params["Source"] =
|
|
QuotePath(cmStrCat("{tmp}\\", archiveName, '\\', relativePath));
|
|
params["ExternalSize"] =
|
|
std::to_string(cmSystemTools::FileLength(i));
|
|
params["Flags"] = "external ignoreversion";
|
|
params["BeforeInstall"] =
|
|
cmStrCat("CPackExtractFile('", archiveName, "', '",
|
|
cmRemoveQuotes(cmSystemTools::ConvertToWindowsOutputPath(
|
|
relativePath)),
|
|
"')");
|
|
} else {
|
|
params["Source"] = QuotePath(i);
|
|
params["Flags"] = "ignoreversion";
|
|
}
|
|
|
|
fileInstructions.push_back(ISKeyValueLine(params));
|
|
|
|
// Icon
|
|
const std::string& name =
|
|
cmSystemTools::GetFilenameWithoutLastExtension(i);
|
|
const std::string& extension =
|
|
cmSystemTools::GetFilenameLastExtension(i);
|
|
if ((extension == ".exe" || extension == ".com") && // only .exe, .com
|
|
icons.count(name)) {
|
|
cmCPackInnoSetupKeyValuePairs iconParams;
|
|
|
|
iconParams["Name"] = QuotePath(cmStrCat(iconsPrefix, icons[name]));
|
|
iconParams["Filename"] =
|
|
QuotePath(cmStrCat(destDir, '\\', name, extension));
|
|
|
|
if (!componentParam.empty()) {
|
|
iconParams["Components"] = componentParam;
|
|
}
|
|
|
|
iconInstructions.push_back(ISKeyValueLine(iconParams));
|
|
|
|
// Desktop icon
|
|
if (std::find(desktopIcons.begin(), desktopIcons.end(), name) !=
|
|
desktopIcons.end()) {
|
|
iconParams["Name"] =
|
|
QuotePath(cmStrCat("{autodesktop}\\", icons[name]));
|
|
iconParams["Tasks"] = "desktopicon";
|
|
|
|
if (!componentParam.empty() &&
|
|
std::find(desktopIconComponents.begin(),
|
|
desktopIconComponents.end(),
|
|
componentParam) == desktopIconComponents.end()) {
|
|
desktopIconComponents.push_back(componentParam);
|
|
}
|
|
iconInstructions.push_back(ISKeyValueLine(iconParams));
|
|
}
|
|
|
|
// [Run] section
|
|
if (std::find(runExecutables.begin(), runExecutables.end(), name) !=
|
|
runExecutables.end()) {
|
|
cmCPackInnoSetupKeyValuePairs runParams;
|
|
|
|
runParams["Filename"] = iconParams["Filename"];
|
|
runParams["Description"] = cmStrCat(
|
|
"\"{cm:LaunchProgram,", PrepareForConstant(icons[name]), "}\"");
|
|
runParams["Flags"] = "nowait postinstall skipifsilent";
|
|
|
|
if (!componentParam.empty()) {
|
|
runParams["Components"] = componentParam;
|
|
}
|
|
|
|
runInstructions.push_back(ISKeyValueLine(runParams));
|
|
}
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
// Additional icons
|
|
static cmsys::RegularExpression urlRegex(
|
|
"^(mailto:|(ftps?|https?|news)://).*$");
|
|
|
|
if (IsSet("CPACK_INNOSETUP_MENU_LINKS")) {
|
|
const cmList menuIcons(GetOption("CPACK_INNOSETUP_MENU_LINKS"));
|
|
if (menuIcons.size() % 2 != 0) {
|
|
cmCPackLogger(cmCPackLog::LOG_ERROR,
|
|
"CPACK_INNOSETUP_MENU_LINKS should "
|
|
"contain pairs of <shortcut target> and <shortcut label>"
|
|
<< std::endl);
|
|
return false;
|
|
}
|
|
|
|
for (auto it = menuIcons.begin(); it != menuIcons.end(); ++it) {
|
|
const std::string& target = *it;
|
|
const std::string& label = *(++it);
|
|
cmCPackInnoSetupKeyValuePairs params;
|
|
|
|
params["Name"] = QuotePath(cmStrCat(iconsPrefix, label));
|
|
if (urlRegex.find(target)) {
|
|
params["Filename"] = Quote(target);
|
|
} else {
|
|
std::string dir = "{app}";
|
|
std::string componentName;
|
|
for (const auto& i : Components) {
|
|
if (cmSystemTools::FileExists(cmSystemTools::CollapseFullPath(
|
|
cmStrCat(i.second.Name, '\\', target), toplevel))) {
|
|
dir = CustomComponentInstallDirectory(&i.second);
|
|
componentName =
|
|
CreateRecursiveComponentPath(i.second.Group, i.second.Name);
|
|
|
|
if (i.second.IsHidden && i.second.IsDisabledByDefault) {
|
|
goto continueOuterLoop;
|
|
} else if (i.second.IsHidden) {
|
|
componentName.clear();
|
|
}
|
|
|
|
break;
|
|
}
|
|
}
|
|
|
|
params["Filename"] = QuotePath(cmStrCat(dir, '\\', target));
|
|
|
|
if (!componentName.empty()) {
|
|
params["Components"] = componentName;
|
|
}
|
|
}
|
|
|
|
iconInstructions.push_back(ISKeyValueLine(params));
|
|
continueOuterLoop:;
|
|
}
|
|
}
|
|
|
|
SetOptionIfNotSet("CPACK_INNOSETUP_CREATE_UNINSTALL_LINK", "OFF");
|
|
if (GetOption("CPACK_INNOSETUP_CREATE_UNINSTALL_LINK").IsOn()) {
|
|
cmCPackInnoSetupKeyValuePairs params;
|
|
|
|
params["Name"] = QuotePath(
|
|
cmStrCat(iconsPrefix, "{cm:UninstallProgram,",
|
|
PrepareForConstant(GetOption("CPACK_PACKAGE_NAME")), '}'));
|
|
params["Filename"] = "\"{uninstallexe}\"";
|
|
|
|
iconInstructions.push_back(ISKeyValueLine(params));
|
|
}
|
|
|
|
return true;
|
|
}
|
|
|
|
bool cmCPackInnoSetupGenerator::ProcessComponents()
|
|
{
|
|
codeIncludes.emplace_back(
|
|
"{ The following lines are required by CPack because "
|
|
"this script uses components }");
|
|
|
|
// Installation types
|
|
std::vector<cmCPackInstallationType*> types(InstallationTypes.size());
|
|
for (auto& i : InstallationTypes) {
|
|
types[i.second.Index - 1] = &i.second;
|
|
}
|
|
|
|
std::vector<std::string> allTypes; // For required components
|
|
for (cmCPackInstallationType* i : types) {
|
|
cmCPackInnoSetupKeyValuePairs params;
|
|
|
|
params["Name"] = Quote(i->Name);
|
|
params["Description"] = Quote(i->DisplayName);
|
|
|
|
allTypes.push_back(i->Name);
|
|
typeInstructions.push_back(ISKeyValueLine(params));
|
|
}
|
|
|
|
// Inno Setup requires the additional "custom" type
|
|
cmCPackInnoSetupKeyValuePairs customTypeParams;
|
|
|
|
customTypeParams["Name"] = "\"custom\"";
|
|
customTypeParams["Description"] =
|
|
"\"{code:CPackGetCustomInstallationMessage}\"";
|
|
customTypeParams["Flags"] = "iscustom";
|
|
|
|
allTypes.emplace_back("custom");
|
|
typeInstructions.push_back(ISKeyValueLine(customTypeParams));
|
|
|
|
// Components
|
|
std::vector<cmCPackComponent*> downloadedComponents;
|
|
for (auto& i : Components) {
|
|
cmCPackInnoSetupKeyValuePairs params;
|
|
cmCPackComponent* component = &i.second;
|
|
|
|
if (component->IsHidden) {
|
|
continue;
|
|
}
|
|
|
|
CreateRecursiveComponentGroups(component->Group);
|
|
|
|
params["Name"] =
|
|
Quote(CreateRecursiveComponentPath(component->Group, component->Name));
|
|
params["Description"] = Quote(component->DisplayName);
|
|
|
|
if (component->IsRequired) {
|
|
params["Types"] = cmJoin(allTypes, " ");
|
|
params["Flags"] = "fixed";
|
|
} else if (!component->InstallationTypes.empty()) {
|
|
std::vector<std::string> installationTypes;
|
|
|
|
installationTypes.reserve(component->InstallationTypes.size());
|
|
for (cmCPackInstallationType* j : component->InstallationTypes) {
|
|
installationTypes.push_back(j->Name);
|
|
}
|
|
|
|
params["Types"] = cmJoin(installationTypes, " ");
|
|
}
|
|
|
|
componentInstructions.push_back(ISKeyValueLine(params));
|
|
|
|
if (component->IsDownloaded) {
|
|
downloadedComponents.push_back(component);
|
|
|
|
if (component->ArchiveFile.empty()) {
|
|
// Compute the name of the archive.
|
|
if (!RequireOption("CPACK_TEMPORARY_DIRECTORY")) {
|
|
return false;
|
|
}
|
|
|
|
std::string packagesDir =
|
|
cmStrCat(GetOption("CPACK_TEMPORARY_DIRECTORY"), ".dummy");
|
|
component->ArchiveFile =
|
|
cmStrCat(cmSystemTools::GetFilenameWithoutLastExtension(packagesDir),
|
|
'-', component->Name, ".zip");
|
|
} else if (!cmHasSuffix(component->ArchiveFile, ".zip")) {
|
|
component->ArchiveFile = cmStrCat(component->ArchiveFile, ".zip");
|
|
}
|
|
}
|
|
}
|
|
|
|
// Downloaded components
|
|
if (!downloadedComponents.empty()) {
|
|
// Create the directory for the upload area
|
|
cmValue userUploadDirectory = GetOption("CPACK_UPLOAD_DIRECTORY");
|
|
std::string uploadDirectory;
|
|
if (cmNonempty(userUploadDirectory)) {
|
|
uploadDirectory = *userUploadDirectory;
|
|
} else {
|
|
if (!RequireOption("CPACK_PACKAGE_DIRECTORY")) {
|
|
return false;
|
|
}
|
|
|
|
uploadDirectory =
|
|
cmStrCat(GetOption("CPACK_PACKAGE_DIRECTORY"), "/CPackUploads");
|
|
}
|
|
|
|
if (!cmSystemTools::FileExists(uploadDirectory)) {
|
|
if (!cmSystemTools::MakeDirectory(uploadDirectory)) {
|
|
cmCPackLogger(cmCPackLog::LOG_ERROR,
|
|
"Unable to create Inno Setup upload directory "
|
|
<< uploadDirectory << std::endl);
|
|
return false;
|
|
}
|
|
}
|
|
|
|
if (!RequireOption("CPACK_DOWNLOAD_SITE")) {
|
|
return false;
|
|
}
|
|
|
|
SetOptionIfNotSet("CPACK_INNOSETUP_VERIFY_DOWNLOADS", "ON");
|
|
const bool verifyDownloads =
|
|
GetOption("CPACK_INNOSETUP_VERIFY_DOWNLOADS").IsOn();
|
|
|
|
const std::string& urlPrefix =
|
|
cmHasSuffix(GetOption("CPACK_DOWNLOAD_SITE").GetCStr(), '/')
|
|
? GetOption("CPACK_DOWNLOAD_SITE")
|
|
: cmStrCat(GetOption("CPACK_DOWNLOAD_SITE"), '/');
|
|
|
|
std::vector<std::string> archiveUrls;
|
|
std::vector<std::string> archiveFiles;
|
|
std::vector<std::string> archiveHashes;
|
|
std::vector<std::string> archiveComponents;
|
|
for (cmCPackComponent* i : downloadedComponents) {
|
|
std::string hash;
|
|
if (!BuildDownloadedComponentArchive(
|
|
i, uploadDirectory, (verifyDownloads ? &hash : nullptr))) {
|
|
return false;
|
|
}
|
|
|
|
archiveUrls.push_back(Quote(cmStrCat(urlPrefix, i->ArchiveFile)));
|
|
archiveFiles.push_back(
|
|
Quote(cmSystemTools::GetFilenameWithoutLastExtension(i->ArchiveFile)));
|
|
archiveHashes.push_back(Quote(hash));
|
|
archiveComponents.push_back(
|
|
Quote(CreateRecursiveComponentPath(i->Group, i->Name)));
|
|
}
|
|
|
|
SetOption("CPACK_INNOSETUP_DOWNLOAD_COUNT_INTERNAL",
|
|
std::to_string(archiveFiles.size()));
|
|
SetOption("CPACK_INNOSETUP_DOWNLOAD_URLS_INTERNAL",
|
|
cmJoin(archiveUrls, ", "));
|
|
SetOption("CPACK_INNOSETUP_DOWNLOAD_ARCHIVES_INTERNAL",
|
|
cmJoin(archiveFiles, ", "));
|
|
SetOption("CPACK_INNOSETUP_DOWNLOAD_HASHES_INTERNAL",
|
|
cmJoin(archiveHashes, ", "));
|
|
SetOption("CPACK_INNOSETUP_DOWNLOAD_COMPONENTS_INTERNAL",
|
|
cmJoin(archiveComponents, ", "));
|
|
|
|
static const std::string& downloadLines =
|
|
"#define protected CPackDownloadCount "
|
|
"@CPACK_INNOSETUP_DOWNLOAD_COUNT_INTERNAL@\n"
|
|
"#dim protected CPackDownloadUrls[CPackDownloadCount] "
|
|
"{@CPACK_INNOSETUP_DOWNLOAD_URLS_INTERNAL@}\n"
|
|
"#dim protected CPackDownloadArchives[CPackDownloadCount] "
|
|
"{@CPACK_INNOSETUP_DOWNLOAD_ARCHIVES_INTERNAL@}\n"
|
|
"#dim protected CPackDownloadHashes[CPackDownloadCount] "
|
|
"{@CPACK_INNOSETUP_DOWNLOAD_HASHES_INTERNAL@}\n"
|
|
"#dim protected CPackDownloadComponents[CPackDownloadCount] "
|
|
"{@CPACK_INNOSETUP_DOWNLOAD_COMPONENTS_INTERNAL@}";
|
|
|
|
std::string output;
|
|
if (!ConfigureString(downloadLines, output)) {
|
|
return false;
|
|
}
|
|
codeIncludes.push_back(output);
|
|
}
|
|
|
|
// Add the required script
|
|
const std::string& componentsScriptTemplate =
|
|
FindTemplate("ISComponents.pas");
|
|
if (componentsScriptTemplate.empty()) {
|
|
cmCPackLogger(cmCPackLog::LOG_ERROR,
|
|
"Could not find additional Inno Setup script file."
|
|
<< std::endl);
|
|
return false;
|
|
}
|
|
|
|
codeIncludes.push_back("#include " + QuotePath(componentsScriptTemplate) +
|
|
"\n");
|
|
|
|
return true;
|
|
}
|
|
|
|
bool cmCPackInnoSetupGenerator::ConfigureISScript()
|
|
{
|
|
const std::string& isScriptTemplate = FindTemplate("ISScript.template.in");
|
|
const std::string& isScriptFile =
|
|
cmStrCat(GetOption("CPACK_TOPLEVEL_DIRECTORY"), "/ISScript.iss");
|
|
|
|
if (isScriptTemplate.empty()) {
|
|
cmCPackLogger(cmCPackLog::LOG_ERROR,
|
|
"Could not find Inno Setup installer template file."
|
|
<< std::endl);
|
|
return false;
|
|
}
|
|
|
|
// Create internal variables
|
|
std::vector<std::string> setupSection;
|
|
for (const auto& i : setupDirectives) {
|
|
setupSection.emplace_back(cmStrCat(i.first, '=', TranslateBool(i.second)));
|
|
}
|
|
|
|
// Also create comments if the sections are empty
|
|
const std::string& defaultMessage =
|
|
"; CPack didn't find any entries for this section";
|
|
|
|
if (IsSet("CPACK_CREATE_DESKTOP_LINKS") &&
|
|
!GetOption("CPACK_CREATE_DESKTOP_LINKS").Get()->empty()) {
|
|
cmCPackInnoSetupKeyValuePairs tasks;
|
|
tasks["Name"] = "\"desktopicon\"";
|
|
tasks["Description"] = "\"{cm:CreateDesktopIcon}\"";
|
|
tasks["GroupDescription"] = "\"{cm:AdditionalIcons}\"";
|
|
tasks["Flags"] = "unchecked";
|
|
|
|
if (!desktopIconComponents.empty()) {
|
|
tasks["Components"] = cmJoin(desktopIconComponents, " ");
|
|
}
|
|
|
|
SetOption("CPACK_INNOSETUP_TASKS_INTERNAL", ISKeyValueLine(tasks));
|
|
} else {
|
|
SetOption("CPACK_INNOSETUP_TASKS_INTERNAL", defaultMessage);
|
|
}
|
|
|
|
SetOption("CPACK_INNOSETUP_INCLUDES_INTERNAL",
|
|
includeDirectives.empty() ? "; No extra script files specified"
|
|
: cmJoin(includeDirectives, "\n"));
|
|
SetOption("CPACK_INNOSETUP_SETUP_INTERNAL",
|
|
setupSection.empty() ? defaultMessage
|
|
: cmJoin(setupSection, "\n"));
|
|
SetOption("CPACK_INNOSETUP_LANGUAGES_INTERNAL",
|
|
languageInstructions.empty() ? defaultMessage
|
|
: cmJoin(languageInstructions, "\n"));
|
|
SetOption("CPACK_INNOSETUP_DIRS_INTERNAL",
|
|
dirInstructions.empty() ? defaultMessage
|
|
: cmJoin(dirInstructions, "\n"));
|
|
SetOption("CPACK_INNOSETUP_FILES_INTERNAL",
|
|
fileInstructions.empty() ? defaultMessage
|
|
: cmJoin(fileInstructions, "\n"));
|
|
SetOption("CPACK_INNOSETUP_TYPES_INTERNAL",
|
|
typeInstructions.empty() ? defaultMessage
|
|
: cmJoin(typeInstructions, "\n"));
|
|
SetOption("CPACK_INNOSETUP_COMPONENTS_INTERNAL",
|
|
componentInstructions.empty()
|
|
? defaultMessage
|
|
: cmJoin(componentInstructions, "\n"));
|
|
SetOption("CPACK_INNOSETUP_ICONS_INTERNAL",
|
|
iconInstructions.empty() ? defaultMessage
|
|
: cmJoin(iconInstructions, "\n"));
|
|
SetOption("CPACK_INNOSETUP_RUN_INTERNAL",
|
|
runInstructions.empty() ? defaultMessage
|
|
: cmJoin(runInstructions, "\n"));
|
|
SetOption("CPACK_INNOSETUP_CODE_INTERNAL",
|
|
codeIncludes.empty() ? "{ No extra code files specified }"
|
|
: cmJoin(codeIncludes, "\n"));
|
|
|
|
cmCPackLogger(cmCPackLog::LOG_VERBOSE,
|
|
"Configure file: " << isScriptTemplate << " to "
|
|
<< isScriptFile << std::endl);
|
|
|
|
return ConfigureFile(isScriptTemplate, isScriptFile);
|
|
}
|
|
|
|
bool cmCPackInnoSetupGenerator::Compile()
|
|
{
|
|
const std::string& isScriptFile =
|
|
cmStrCat(GetOption("CPACK_TOPLEVEL_DIRECTORY"), "/ISScript.iss");
|
|
const std::string& isccLogFile =
|
|
cmStrCat(GetOption("CPACK_TOPLEVEL_DIRECTORY"), "/ISCCOutput.log");
|
|
|
|
std::vector<std::string> isccArgs;
|
|
|
|
// Custom defines
|
|
for (const std::string& i : GetOptions()) {
|
|
if (cmHasPrefix(i, "CPACK_INNOSETUP_DEFINE_")) {
|
|
const std::string& name = i.substr(cmStrLen("CPACK_INNOSETUP_DEFINE_"));
|
|
isccArgs.push_back(
|
|
cmStrCat("\"/D", name, '=', TranslateBool(GetOption(i)), '"'));
|
|
}
|
|
}
|
|
|
|
if (IsSet("CPACK_INNOSETUP_EXECUTABLE_ARGUMENTS")) {
|
|
const cmList args(GetOption("CPACK_INNOSETUP_EXECUTABLE_ARGUMENTS"));
|
|
|
|
isccArgs.insert(isccArgs.end(), args.begin(), args.end());
|
|
}
|
|
|
|
const std::string& isccCmd =
|
|
cmStrCat(QuotePath(GetOption("CPACK_INSTALLER_PROGRAM"), PathType::Native),
|
|
' ', cmJoin(isccArgs, " "), ' ', QuotePath(isScriptFile));
|
|
|
|
cmCPackLogger(cmCPackLog::LOG_VERBOSE, "Execute: " << isccCmd << std::endl);
|
|
|
|
std::string output;
|
|
int retVal = 1;
|
|
const bool res = cmSystemTools::RunSingleCommand(
|
|
isccCmd, &output, &output, &retVal, nullptr, this->GeneratorVerbose,
|
|
cmDuration::zero());
|
|
|
|
if (!res || retVal) {
|
|
cmGeneratedFileStream ofs(isccLogFile);
|
|
ofs << "# Run command: " << isccCmd << std::endl
|
|
<< "# Output:" << std::endl
|
|
<< output << std::endl;
|
|
cmCPackLogger(cmCPackLog::LOG_ERROR,
|
|
"Problem running ISCC. Please check "
|
|
<< isccLogFile << " for errors." << std::endl);
|
|
return false;
|
|
}
|
|
|
|
return true;
|
|
}
|
|
|
|
bool cmCPackInnoSetupGenerator::BuildDownloadedComponentArchive(
|
|
cmCPackComponent* component, const std::string& uploadDirectory,
|
|
std::string* hash)
|
|
{
|
|
// Remove the old archive, if one exists
|
|
const std::string& archiveFile =
|
|
uploadDirectory + '/' + component->ArchiveFile;
|
|
cmCPackLogger(cmCPackLog::LOG_OUTPUT,
|
|
"- Building downloaded component archive: " << archiveFile
|
|
<< std::endl);
|
|
if (cmSystemTools::FileExists(archiveFile, true)) {
|
|
if (!cmSystemTools::RemoveFile(archiveFile)) {
|
|
cmCPackLogger(cmCPackLog::LOG_ERROR,
|
|
"Unable to remove archive file " << archiveFile
|
|
<< std::endl);
|
|
return false;
|
|
}
|
|
}
|
|
|
|
// Find a ZIP program
|
|
if (!IsSet("ZIP_EXECUTABLE")) {
|
|
ReadListFile("Internal/CPack/CPackZIP.cmake");
|
|
|
|
if (!IsSet("ZIP_EXECUTABLE")) {
|
|
cmCPackLogger(cmCPackLog::LOG_ERROR,
|
|
"Unable to find ZIP program" << std::endl);
|
|
return false;
|
|
}
|
|
}
|
|
|
|
if (!RequireOption("CPACK_TOPLEVEL_DIRECTORY") ||
|
|
!RequireOption("CPACK_TEMPORARY_DIRECTORY") ||
|
|
!RequireOption("CPACK_ZIP_NEED_QUOTES") ||
|
|
!RequireOption("CPACK_ZIP_COMMAND")) {
|
|
return false;
|
|
}
|
|
|
|
// The directory where this component's files reside
|
|
const std::string& dirName =
|
|
cmStrCat(GetOption("CPACK_TEMPORARY_DIRECTORY"), '/', component->Name);
|
|
|
|
// Build the list of files to go into this archive
|
|
const std::string& zipListFileName =
|
|
cmStrCat(GetOption("CPACK_TEMPORARY_DIRECTORY"), "/winZip.filelist");
|
|
const bool needQuotesInFile = GetOption("CPACK_ZIP_NEED_QUOTES").IsOn();
|
|
{ // the scope is needed for cmGeneratedFileStream
|
|
cmGeneratedFileStream out(zipListFileName);
|
|
for (const std::string& i : component->Files) {
|
|
out << (needQuotesInFile ? Quote(i) : i) << std::endl;
|
|
}
|
|
}
|
|
|
|
// Build the archive in the upload area
|
|
std::string cmd = 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;
|
|
const bool res = cmSystemTools::RunSingleCommand(
|
|
cmd, &output, &output, &retVal, dirName.c_str(), this->GeneratorVerbose,
|
|
cmDuration::zero());
|
|
if (!res || retVal) {
|
|
std::string tmpFile =
|
|
cmStrCat(GetOption("CPACK_TOPLEVEL_DIRECTORY"), "/CompressZip.log");
|
|
cmGeneratedFileStream ofs(tmpFile);
|
|
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 false;
|
|
}
|
|
|
|
// Try to get the SHA256 hash of the archive file
|
|
if (hash == nullptr) {
|
|
return true;
|
|
}
|
|
|
|
#ifdef _WIN32
|
|
const std::string& hashCmd =
|
|
cmStrCat("certutil -hashfile ", QuotePath(archiveFile), " SHA256");
|
|
|
|
std::string hashOutput;
|
|
int hashRetVal = -1;
|
|
const bool hashRes = cmSystemTools::RunSingleCommand(
|
|
hashCmd, &hashOutput, &hashOutput, &hashRetVal, nullptr,
|
|
this->GeneratorVerbose, cmDuration::zero());
|
|
if (!hashRes || hashRetVal) {
|
|
cmCPackLogger(cmCPackLog::LOG_WARNING,
|
|
"Problem running certutil command: " << hashCmd
|
|
<< std::endl);
|
|
}
|
|
*hash = cmTrimWhitespace(cmTokenize(hashOutput, "\n").at(1));
|
|
|
|
if (hash->length() != 64) {
|
|
cmCPackLogger(cmCPackLog::LOG_WARNING,
|
|
"Problem parsing certutil output of command: " << hashCmd
|
|
<< std::endl);
|
|
hash->clear();
|
|
}
|
|
#endif
|
|
|
|
return true;
|
|
}
|
|
|
|
cmValue cmCPackInnoSetupGenerator::RequireOption(const std::string& key)
|
|
{
|
|
cmValue value = GetOption(key);
|
|
|
|
if (!value) {
|
|
cmCPackLogger(cmCPackLog::LOG_ERROR,
|
|
"Required variable " << key << " not set" << std::endl);
|
|
}
|
|
|
|
return value;
|
|
}
|
|
|
|
std::string cmCPackInnoSetupGenerator::CustomComponentInstallDirectory(
|
|
const cmCPackComponent* component)
|
|
{
|
|
cmValue outputDir = GetOption(
|
|
cmStrCat("CPACK_INNOSETUP_", component->Name, "_INSTALL_DIRECTORY"));
|
|
if (outputDir) {
|
|
std::string destDir = cmSystemTools::ConvertToWindowsOutputPath(outputDir);
|
|
cmStripSuffixIfExists(destDir, '\\');
|
|
|
|
/*
|
|
* Add a dir instruction for the custom directory
|
|
* (only once and not for Inno Setup constants ending with '}')
|
|
*/
|
|
static std::vector<std::string> customDirectories;
|
|
if (!cmHasSuffix(destDir, '}') &&
|
|
std::find(customDirectories.begin(), customDirectories.end(),
|
|
component->Name) == customDirectories.end()) {
|
|
cmCPackInnoSetupKeyValuePairs params;
|
|
params["Name"] = QuotePath(destDir);
|
|
params["Components"] =
|
|
CreateRecursiveComponentPath(component->Group, component->Name);
|
|
|
|
dirInstructions.push_back(ISKeyValueLine(params));
|
|
customDirectories.push_back(component->Name);
|
|
}
|
|
return destDir;
|
|
}
|
|
|
|
return "{app}";
|
|
}
|
|
|
|
std::string cmCPackInnoSetupGenerator::TranslateBool(const std::string& value)
|
|
{
|
|
if (value.empty()) {
|
|
return value;
|
|
}
|
|
|
|
SetOptionIfNotSet("CPACK_INNOSETUP_USE_CMAKE_BOOL_FORMAT", "ON");
|
|
if (GetOption("CPACK_INNOSETUP_USE_CMAKE_BOOL_FORMAT").IsOn()) {
|
|
if (cmIsOn(value)) {
|
|
return "yes";
|
|
}
|
|
if (cmIsOff(value)) {
|
|
return "no";
|
|
}
|
|
}
|
|
|
|
return value;
|
|
}
|
|
|
|
std::string cmCPackInnoSetupGenerator::ISKeyValueLine(
|
|
const cmCPackInnoSetupKeyValuePairs& params)
|
|
{
|
|
/*
|
|
* To simplify readability of the generated code, the keys are sorted.
|
|
* Unknown keys are ignored to avoid errors during compilation.
|
|
*/
|
|
static const char* const availableKeys[] = {
|
|
"Source", "DestDir", "Name", "Filename",
|
|
"Description", "GroupDescription", "MessagesFile", "Types",
|
|
"ExternalSize", "BeforeInstall", "Flags", "Components",
|
|
"Tasks"
|
|
};
|
|
|
|
std::vector<std::string> keys;
|
|
for (const char* i : availableKeys) {
|
|
if (params.count(i)) {
|
|
keys.emplace_back(cmStrCat(i, ": ", params.at(i)));
|
|
}
|
|
}
|
|
|
|
return cmJoin(keys, "; ");
|
|
}
|
|
|
|
std::string cmCPackInnoSetupGenerator::CreateRecursiveComponentPath(
|
|
cmCPackComponentGroup* group, const std::string& path)
|
|
{
|
|
if (group == nullptr) {
|
|
return path;
|
|
}
|
|
|
|
const std::string& newPath =
|
|
path.empty() ? group->Name : cmStrCat(group->Name, '\\', path);
|
|
return CreateRecursiveComponentPath(group->ParentGroup, newPath);
|
|
}
|
|
|
|
void cmCPackInnoSetupGenerator::CreateRecursiveComponentGroups(
|
|
cmCPackComponentGroup* group)
|
|
{
|
|
if (group == nullptr) {
|
|
return;
|
|
}
|
|
|
|
CreateRecursiveComponentGroups(group->ParentGroup);
|
|
|
|
static std::vector<cmCPackComponentGroup*> processedGroups;
|
|
if (std::find(processedGroups.begin(), processedGroups.end(), group) ==
|
|
processedGroups.end()) {
|
|
processedGroups.push_back(group);
|
|
|
|
cmCPackInnoSetupKeyValuePairs params;
|
|
|
|
params["Name"] = Quote(CreateRecursiveComponentPath(group));
|
|
params["Description"] = Quote(group->DisplayName);
|
|
|
|
componentInstructions.push_back(ISKeyValueLine(params));
|
|
}
|
|
}
|
|
|
|
std::string cmCPackInnoSetupGenerator::Quote(const std::string& string)
|
|
{
|
|
if (cmHasPrefix(string, '"') && cmHasSuffix(string, '"')) {
|
|
return Quote(string.substr(1, string.length() - 2));
|
|
}
|
|
|
|
// Double quote syntax
|
|
std::string nString = string;
|
|
cmSystemTools::ReplaceString(nString, "\"", "\"\"");
|
|
return cmStrCat('"', nString, '"');
|
|
}
|
|
|
|
std::string cmCPackInnoSetupGenerator::QuotePath(const std::string& path,
|
|
PathType type)
|
|
{
|
|
#ifdef _WIN32
|
|
static_cast<void>(type);
|
|
#else
|
|
if (type == PathType::Native) {
|
|
return Quote(cmSystemTools::ConvertToUnixOutputPath(path));
|
|
}
|
|
#endif
|
|
return Quote(cmSystemTools::ConvertToWindowsOutputPath(path));
|
|
}
|
|
|
|
std::string cmCPackInnoSetupGenerator::PrepareForConstant(
|
|
const std::string& string)
|
|
{
|
|
std::string nString = string;
|
|
|
|
cmSystemTools::ReplaceString(nString, "%", "%25"); // First replacement!
|
|
cmSystemTools::ReplaceString(nString, "\"", "%22");
|
|
cmSystemTools::ReplaceString(nString, ",", "%2c");
|
|
cmSystemTools::ReplaceString(nString, "|", "%7c");
|
|
cmSystemTools::ReplaceString(nString, "}", "%7d");
|
|
|
|
return nString;
|
|
}
|