mirror of
https://gitlab.kitware.com/cmake/cmake.git
synced 2026-09-25 04:09:36 +03:00
224 lines
6.1 KiB
C++
224 lines
6.1 KiB
C++
/* Distributed under the OSI-approved BSD 3-Clause License. See accompanying
|
|
file LICENSE.rst or https://cmake.org/licensing for details. */
|
|
#if defined(__CYGWIN__)
|
|
// For S_IWRITE symbol
|
|
# define _DEFAULT_SOURCE
|
|
#endif
|
|
|
|
#include "cmWIXFilesSourceWriter.h"
|
|
|
|
#include "cm_sys_stat.h"
|
|
|
|
#include "cmCMakeToWixPath.h"
|
|
#include "cmInstalledFile.h"
|
|
#include "cmSystemTools.h"
|
|
#include "cmWIXAccessControlList.h"
|
|
|
|
#ifdef _WIN32
|
|
# include "cmsys/Encoding.hxx"
|
|
#endif
|
|
|
|
cmWIXFilesSourceWriter::cmWIXFilesSourceWriter(
|
|
unsigned long wixVersion, cmCPackLog* logger, std::string const& filename,
|
|
GuidType componentGuidType, cmWIXInstallScope installScope,
|
|
std::string componentKeysRegistryPath)
|
|
: cmWIXSourceWriter(wixVersion, logger, filename, componentGuidType)
|
|
, ComponentKeysRegistryPath(std::move(componentKeysRegistryPath))
|
|
{
|
|
switch (installScope) {
|
|
case cmWIXInstallScope::PER_USER:
|
|
this->PerUserInstall = true;
|
|
break;
|
|
case cmWIXInstallScope::PER_MACHINE:
|
|
case cmWIXInstallScope::NONE:
|
|
this->PerUserInstall = false;
|
|
break;
|
|
default:
|
|
cmCPackLogger(cmCPackLog::LOG_ERROR,
|
|
"Unhandled install scope value, this is a CPack Bug.");
|
|
break;
|
|
}
|
|
}
|
|
|
|
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, int diskId)
|
|
{
|
|
std::string componentId = std::string("CM_C") + id;
|
|
std::string fileId = std::string("CM_F") + id;
|
|
|
|
// Wix doesn't support automatic GUIDs for components which have both
|
|
// registry entries and files.
|
|
std::string guid = this->PerUserInstall
|
|
? CreateCmakeGeneratedGuidFromComponentId(componentId)
|
|
: CreateGuidFromComponentId(componentId);
|
|
|
|
BeginElement("DirectoryRef");
|
|
AddAttribute("Id", directoryId);
|
|
|
|
BeginElement("Component");
|
|
AddAttribute("Id", componentId);
|
|
AddAttribute("Guid", guid);
|
|
|
|
if (diskId) {
|
|
AddAttribute("DiskId", std::to_string(diskId));
|
|
}
|
|
|
|
if (installedFile) {
|
|
if (installedFile->GetPropertyAsBool("CPACK_NEVER_OVERWRITE")) {
|
|
AddAttribute("NeverOverwrite", "yes");
|
|
}
|
|
if (installedFile->GetPropertyAsBool("CPACK_PERMANENT")) {
|
|
AddAttribute("Permanent", "yes");
|
|
}
|
|
}
|
|
|
|
patch.ApplyFragment(componentId, *this);
|
|
|
|
if (this->PerUserInstall) {
|
|
// For perUser installs, MSI requires using a registry entry as the key
|
|
// path for components.
|
|
BeginElement("RegistryValue");
|
|
|
|
AddAttribute("Root", "HKCU");
|
|
AddAttribute("Key", this->ComponentKeysRegistryPath);
|
|
AddAttribute("Name", fileId);
|
|
AddAttribute("Type", "string");
|
|
AddAttribute("Value", "1");
|
|
AddAttribute("KeyPath", "yes");
|
|
|
|
EndElement("RegistryValue");
|
|
}
|
|
|
|
BeginElement("File");
|
|
AddAttribute("Id", fileId);
|
|
|
|
std::string sourcePath = CMakeToWixPath(filePath);
|
|
#ifdef _WIN32
|
|
// WiX cannot handle long paths natively, but since v4,
|
|
// it supports long paths via UNC prefixes.
|
|
if (this->WixVersion >= 4) {
|
|
sourcePath = cmsys::Encoding::ToNarrow(
|
|
cmsys::Encoding::ToWindowsExtendedPath(sourcePath));
|
|
}
|
|
#endif
|
|
AddAttribute("Source", sourcePath);
|
|
|
|
if (!this->PerUserInstall) {
|
|
AddAttribute("KeyPath", "yes");
|
|
}
|
|
|
|
mode_t fileMode = 0;
|
|
cmSystemTools::GetPermissions(filePath.c_str(), fileMode);
|
|
|
|
if (!(fileMode & S_IWRITE)) {
|
|
AddAttribute("ReadOnly", "yes");
|
|
}
|
|
patch.ApplyFragment(fileId, *this);
|
|
|
|
if (installedFile) {
|
|
cmWIXAccessControlList acl(Logger, *installedFile, *this);
|
|
acl.Apply();
|
|
}
|
|
|
|
EndElement("File");
|
|
|
|
EndElement("Component");
|
|
EndElement("DirectoryRef");
|
|
|
|
return componentId;
|
|
}
|