CPack/WiX: Add support for custom XML namespaces

Add a `CPACK_WIX_CUSTOM_XMLNS` option to specify these.

Fixes: #21098
This commit is contained in:
Fritz Elfert
2020-08-15 16:19:09 +02:00
committed by Brad King
parent 39cdfa9681
commit 267de3ba30
6 changed files with 66 additions and 3 deletions

View File

@@ -286,3 +286,11 @@ Windows using WiX.
When unspecified CPack will try to locate a WiX Toolset
installation via the ``WIX`` environment variable instead.
.. variable:: CPACK_WIX_CUSTOM_XMLNS
This variable provides a list of custom namespace declarations that are necessary
for using WiX extensions. Each declaration should be in the form name=url, where
name is the plain namespace without the usual xmlns: prefix and url is an unquoted
namespace url. A list of commonly known WiX schemata can be found here:
https://wixtoolset.org/documentation/manual/v3/xsd/

View File

@@ -0,0 +1,5 @@
cpack-wix-custom-xmlns
----------------------
* The :cpack_gen:`CPack WIX Generator` gained a
:variable:`CPACK_WIX_CUSTOM_XMLNS` option to specify custom XML namespaces.

View File

@@ -2,7 +2,7 @@
<?include "cpack_variables.wxi"?>
<Wix xmlns="http://schemas.microsoft.com/wix/2006/wi"
<Wix xmlns="http://schemas.microsoft.com/wix/2006/wi" @CPACK_WIX_CUSTOM_XMLNS_EXPANDED@
RequiredVersion="3.6.3303.0">
<Product Id="$(var.CPACK_WIX_PRODUCT_GUID)"

View File

@@ -221,6 +221,7 @@ bool cmCPackWIXGenerator::InitializeWiXConfiguration()
this->LightExtensions.insert("WixUIExtension");
CollectExtensions("CPACK_WIX_EXTENSIONS", this->LightExtensions);
CollectExtensions("CPACK_WIX_LIGHT_EXTENSIONS", this->LightExtensions);
CollectXmlNamespaces("CPACK_WIX_CUSTOM_XMLNS", this->CustomXmlNamespaces);
const char* patchFilePath = GetOption("CPACK_WIX_PATCH_FILE");
if (patchFilePath) {
@@ -322,6 +323,7 @@ void cmCPackWIXGenerator::CreateWiXVariablesIncludeFile()
cmWIXSourceWriter includeFile(this->Logger, includeFilename,
this->ComponentGuidType,
cmWIXSourceWriter::INCLUDE_ELEMENT_ROOT);
InjectXmlNamespaces(includeFile);
CopyDefinition(includeFile, "CPACK_WIX_PRODUCT_GUID");
CopyDefinition(includeFile, "CPACK_WIX_UPGRADE_GUID");
@@ -345,6 +347,7 @@ void cmCPackWIXGenerator::CreateWiXPropertiesIncludeFile()
cmWIXSourceWriter includeFile(this->Logger, includeFilename,
this->ComponentGuidType,
cmWIXSourceWriter::INCLUDE_ELEMENT_ROOT);
InjectXmlNamespaces(includeFile);
std::string prefix = "CPACK_WIX_PROPERTY_";
std::vector<std::string> options = GetOptions();
@@ -393,6 +396,7 @@ void cmCPackWIXGenerator::CreateWiXProductFragmentIncludeFile()
cmWIXSourceWriter includeFile(this->Logger, includeFilename,
this->ComponentGuidType,
cmWIXSourceWriter::INCLUDE_ELEMENT_ROOT);
InjectXmlNamespaces(includeFile);
this->Patch->ApplyFragment("#PRODUCT", includeFile);
}
@@ -432,6 +436,7 @@ bool cmCPackWIXGenerator::CreateWiXSourceFiles()
cmWIXDirectoriesSourceWriter directoryDefinitions(
this->Logger, directoryDefinitionsFilename, this->ComponentGuidType);
InjectXmlNamespaces(directoryDefinitions);
directoryDefinitions.BeginElement("Fragment");
std::string installRoot;
@@ -453,6 +458,7 @@ bool cmCPackWIXGenerator::CreateWiXSourceFiles()
cmWIXFilesSourceWriter fileDefinitions(this->Logger, fileDefinitionsFilename,
this->ComponentGuidType);
InjectXmlNamespaces(fileDefinitions);
fileDefinitions.BeginElement("Fragment");
@@ -463,6 +469,7 @@ bool cmCPackWIXGenerator::CreateWiXSourceFiles()
cmWIXFeaturesSourceWriter featureDefinitions(
this->Logger, featureDefinitionsFilename, this->ComponentGuidType);
InjectXmlNamespaces(featureDefinitions);
featureDefinitions.BeginElement("Fragment");
@@ -1147,6 +1154,35 @@ void cmCPackWIXGenerator::CollectExtensions(std::string const& variableName,
extensions.insert(list.begin(), list.end());
}
void cmCPackWIXGenerator::CollectXmlNamespaces(std::string const& variableName,
xmlns_map_t& namespaces)
{
const char* variableContent = GetOption(variableName.c_str());
if (!variableContent) {
return;
}
std::vector<std::string> list = cmExpandedList(variableContent);
for (std::string const& str : list) {
auto pos = str.find('=');
if (pos != std::string::npos) {
auto name = str.substr(0, pos);
auto value = str.substr(pos + 1);
namespaces.emplace(std::make_pair(name, value));
} else {
cmCPackLogger(cmCPackLog::LOG_ERROR,
"Invalid element in CPACK_WIX_CUSTOM_XMLNS ignored: "
<< "\"" << str << "\"" << std::endl);
}
}
std::ostringstream oss;
for (auto& ns : namespaces) {
oss << " xmlns:" << ns.first << "=\""
<< cmWIXSourceWriter::EscapeAttributeValue(ns.second) << '"';
}
SetOption("CPACK_WIX_CUSTOM_XMLNS_EXPANDED", oss.str().c_str());
}
void cmCPackWIXGenerator::AddCustomFlags(std::string const& variableName,
std::ostream& stream)
{
@@ -1172,3 +1208,10 @@ std::string cmCPackWIXGenerator::RelativePathWithoutComponentPrefix(
return path.substr(pos + 1);
}
void cmCPackWIXGenerator::InjectXmlNamespaces(cmWIXSourceWriter& sourceWriter)
{
for (auto& ns : this->CustomXmlNamespaces) {
sourceWriter.AddAttributeUnlessEmpty("xmlns:" + ns.first, ns.second);
}
}

View File

@@ -49,6 +49,7 @@ private:
using id_map_t = std::map<std::string, std::string>;
using ambiguity_map_t = std::map<std::string, size_t>;
using extension_set_t = std::set<std::string>;
using xmlns_map_t = std::map<std::string, std::string>;
enum class DefinitionType
{
@@ -147,16 +148,22 @@ private:
void CollectExtensions(std::string const& variableName,
extension_set_t& extensions);
void CollectXmlNamespaces(std::string const& variableName,
xmlns_map_t& namespaces);
void AddCustomFlags(std::string const& variableName, std::ostream& stream);
std::string RelativePathWithoutComponentPrefix(std::string const& path);
void InjectXmlNamespaces(cmWIXSourceWriter& sourceWriter);
std::vector<std::string> WixSources;
id_map_t PathToIdMap;
ambiguity_map_t IdAmbiguityCounter;
extension_set_t CandleExtensions;
extension_set_t LightExtensions;
xmlns_map_t CustomXmlNamespaces;
std::string CPackTopLevel;

View File

@@ -50,6 +50,8 @@ public:
std::string CreateGuidFromComponentId(std::string const& componentId);
static std::string EscapeAttributeValue(std::string const& value);
protected:
cmCPackLog* Logger;
@@ -64,8 +66,6 @@ private:
void Indent(size_t count);
static std::string EscapeAttributeValue(std::string const& value);
cmsys::ofstream File;
State State;