Browse Source

Merge topic 'cpack-wix-custom-xmlns'

267de3ba30 CPack/WiX: Add support for custom XML namespaces

Acked-by: Kitware Robot <[email protected]>
Merge-request: !5132
Brad King 5 years ago
parent
commit
cb5c8e6f25

+ 8 - 0
Help/cpack_gen/wix.rst

@@ -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/

+ 5 - 0
Help/release/dev/cpack-wix-custom-xmlns.rst

@@ -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.

+ 1 - 1
Modules/Internal/CPack/WIX.template.in

@@ -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)"

+ 43 - 0
Source/CPack/WiX/cmCPackWIXGenerator.cxx

@@ -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);
+  }
+}

+ 7 - 0
Source/CPack/WiX/cmCPackWIXGenerator.h

@@ -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;
 

+ 2 - 2
Source/CPack/WiX/cmWIXSourceWriter.h

@@ -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;