Merge topic 'wix-fragment-injection'
8632233 CPackWiX: allow customization of generated WiX sources
This commit is contained in:
commit
eb20fab736
@ -116,6 +116,57 @@
|
|||||||
# If this variable is not set, the default MSI template included with CMake
|
# If this variable is not set, the default MSI template included with CMake
|
||||||
# will be used.
|
# will be used.
|
||||||
#
|
#
|
||||||
|
# .. variable:: CPACK_WIX_PATCH_FILE
|
||||||
|
#
|
||||||
|
# Optional XML file with fragments to be inserted into generated WiX sources
|
||||||
|
#
|
||||||
|
# This optional variable can be used to specify an XML file that the
|
||||||
|
# WiX generator will use to inject fragments into its generated
|
||||||
|
# source files.
|
||||||
|
#
|
||||||
|
# Patch files understood by the CPack WiX generator
|
||||||
|
# roughly follow this RELAX NG compact schema:
|
||||||
|
#
|
||||||
|
# .. code-block:: none
|
||||||
|
#
|
||||||
|
# start = CPackWiXPatch
|
||||||
|
#
|
||||||
|
# CPackWiXPatch = element CPackWiXPatch { CPackWiXFragment* }
|
||||||
|
#
|
||||||
|
# CPackWiXFragment = element CPackWiXFragment
|
||||||
|
# {
|
||||||
|
# attribute Id { string },
|
||||||
|
# fragmentContent*
|
||||||
|
# }
|
||||||
|
#
|
||||||
|
# fragmentContent = element * - CPackWiXFragment
|
||||||
|
# {
|
||||||
|
# (attribute * { text } | text | fragmentContent)*
|
||||||
|
# }
|
||||||
|
#
|
||||||
|
# Currently fragments can be injected into most
|
||||||
|
# Component, File and Directory elements.
|
||||||
|
#
|
||||||
|
# The following example illustrates how this works.
|
||||||
|
#
|
||||||
|
# Given that the WiX generator creates the following XML element:
|
||||||
|
#
|
||||||
|
# .. code-block:: xml
|
||||||
|
#
|
||||||
|
# <Component Id="CM_CP_applications.bin.my_libapp.exe" Guid="*"/>
|
||||||
|
#
|
||||||
|
# The following XML patch file may be used to inject an Environment element
|
||||||
|
# into it:
|
||||||
|
#
|
||||||
|
# .. code-block:: xml
|
||||||
|
#
|
||||||
|
# <CPackWiXPatch>
|
||||||
|
# <CPackWiXFragment Id="CM_CP_applications.bin.my_libapp.exe">
|
||||||
|
# <Environment Id="MyEnvironment" Action="set"
|
||||||
|
# Name="MyVariableName" Value="MyVariableValue"/>
|
||||||
|
# </CPackWiXFragment>
|
||||||
|
# </CPackWiXPatch>
|
||||||
|
#
|
||||||
# .. variable:: CPACK_WIX_EXTRA_SOURCES
|
# .. variable:: CPACK_WIX_EXTRA_SOURCES
|
||||||
#
|
#
|
||||||
# Extra WiX source files
|
# Extra WiX source files
|
||||||
|
@ -517,6 +517,7 @@ if(WIN32)
|
|||||||
CPack/WiX/cmCPackWIXGenerator.cxx
|
CPack/WiX/cmCPackWIXGenerator.cxx
|
||||||
CPack/WiX/cmWIXSourceWriter.cxx
|
CPack/WiX/cmWIXSourceWriter.cxx
|
||||||
CPack/WiX/cmWIXRichTextFormatWriter.cxx
|
CPack/WiX/cmWIXRichTextFormatWriter.cxx
|
||||||
|
CPack/WiX/cmWIXPatchParser.cxx
|
||||||
)
|
)
|
||||||
endif()
|
endif()
|
||||||
|
|
||||||
|
@ -218,6 +218,12 @@ bool cmCPackWIXGenerator::InitializeWiXConfiguration()
|
|||||||
CollectExtensions("CPACK_WIX_EXTENSIONS", lightExtensions);
|
CollectExtensions("CPACK_WIX_EXTENSIONS", lightExtensions);
|
||||||
CollectExtensions("CPACK_WIX_LIGHT_EXTENSIONS", lightExtensions);
|
CollectExtensions("CPACK_WIX_LIGHT_EXTENSIONS", lightExtensions);
|
||||||
|
|
||||||
|
const char* patchFilePath = GetOption("CPACK_WIX_PATCH_FILE");
|
||||||
|
if(patchFilePath)
|
||||||
|
{
|
||||||
|
LoadPatchFragments(patchFilePath);
|
||||||
|
}
|
||||||
|
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -529,6 +535,28 @@ bool cmCPackWIXGenerator::CreateWiXSourceFiles()
|
|||||||
|
|
||||||
wixSources.push_back(mainSourceFilePath);
|
wixSources.push_back(mainSourceFilePath);
|
||||||
|
|
||||||
|
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.size())
|
||||||
|
{
|
||||||
|
cmCPackLogger(cmCPackLog::LOG_ERROR,
|
||||||
|
"Some XML patch fragments did not have matching IDs: " <<
|
||||||
|
fragmentList << std::endl);
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -872,6 +900,7 @@ void cmCPackWIXGenerator::AddDirectoryAndFileDefinitons(
|
|||||||
packageExecutables,
|
packageExecutables,
|
||||||
shortcutMap);
|
shortcutMap);
|
||||||
|
|
||||||
|
ApplyPatchFragment(subDirectoryId, directoryDefinitions);
|
||||||
directoryDefinitions.EndElement("Directory");
|
directoryDefinitions.EndElement("Directory");
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
@ -891,7 +920,10 @@ void cmCPackWIXGenerator::AddDirectoryAndFileDefinitons(
|
|||||||
fileDefinitions.AddAttribute("Source", fullPath);
|
fileDefinitions.AddAttribute("Source", fullPath);
|
||||||
fileDefinitions.AddAttribute("KeyPath", "yes");
|
fileDefinitions.AddAttribute("KeyPath", "yes");
|
||||||
|
|
||||||
|
ApplyPatchFragment(fileId, fileDefinitions);
|
||||||
fileDefinitions.EndElement("File");
|
fileDefinitions.EndElement("File");
|
||||||
|
|
||||||
|
ApplyPatchFragment(componentId, fileDefinitions);
|
||||||
fileDefinitions.EndElement("Component");
|
fileDefinitions.EndElement("Component");
|
||||||
fileDefinitions.EndElement("DirectoryRef");
|
fileDefinitions.EndElement("DirectoryRef");
|
||||||
|
|
||||||
@ -1146,3 +1178,45 @@ void cmCPackWIXGenerator::CreateStartMenuFolder(
|
|||||||
|
|
||||||
directoryDefinitions.EndElement("Directory");
|
directoryDefinitions.EndElement("Directory");
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void cmCPackWIXGenerator::LoadPatchFragments(const std::string& patchFilePath)
|
||||||
|
{
|
||||||
|
cmWIXPatchParser parser(fragments, Logger);
|
||||||
|
parser.ParseFile(patchFilePath.c_str());
|
||||||
|
}
|
||||||
|
|
||||||
|
void cmCPackWIXGenerator::ApplyPatchFragment(
|
||||||
|
const std::string& id, cmWIXSourceWriter& writer)
|
||||||
|
{
|
||||||
|
cmWIXPatchParser::fragment_map_t::iterator i = fragments.find(id);
|
||||||
|
if(i == fragments.end()) return;
|
||||||
|
|
||||||
|
const cmWIXPatchElement& fragment = i->second;
|
||||||
|
for(cmWIXPatchElement::child_list_t::const_iterator
|
||||||
|
j = fragment.children.begin(); j != fragment.children.end(); ++j)
|
||||||
|
{
|
||||||
|
ApplyPatchElement(**j, writer);
|
||||||
|
}
|
||||||
|
|
||||||
|
fragments.erase(i);
|
||||||
|
}
|
||||||
|
|
||||||
|
void cmCPackWIXGenerator::ApplyPatchElement(
|
||||||
|
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);
|
||||||
|
}
|
||||||
|
|
||||||
|
for(cmWIXPatchElement::child_list_t::const_iterator
|
||||||
|
i = element.children.begin(); i != element.children.end(); ++i)
|
||||||
|
{
|
||||||
|
ApplyPatchElement(**i, writer);
|
||||||
|
}
|
||||||
|
|
||||||
|
writer.EndElement(element.name);
|
||||||
|
}
|
||||||
|
@ -13,6 +13,8 @@
|
|||||||
#ifndef cmCPackWIXGenerator_h
|
#ifndef cmCPackWIXGenerator_h
|
||||||
#define cmCPackWIXGenerator_h
|
#define cmCPackWIXGenerator_h
|
||||||
|
|
||||||
|
#include "cmWIXPatchParser.h"
|
||||||
|
|
||||||
#include <CPack/cmCPackGenerator.h>
|
#include <CPack/cmCPackGenerator.h>
|
||||||
|
|
||||||
#include <string>
|
#include <string>
|
||||||
@ -160,12 +162,21 @@ private:
|
|||||||
|
|
||||||
void CreateStartMenuFolder(cmWIXSourceWriter& directoryDefinitions);
|
void CreateStartMenuFolder(cmWIXSourceWriter& directoryDefinitions);
|
||||||
|
|
||||||
|
void LoadPatchFragments(const std::string& patchFilePath);
|
||||||
|
|
||||||
|
void ApplyPatchFragment(const std::string& id, cmWIXSourceWriter& writer);
|
||||||
|
|
||||||
|
void ApplyPatchElement(const cmWIXPatchElement& element,
|
||||||
|
cmWIXSourceWriter& writer);
|
||||||
|
|
||||||
std::vector<std::string> wixSources;
|
std::vector<std::string> wixSources;
|
||||||
id_map_t pathToIdMap;
|
id_map_t pathToIdMap;
|
||||||
ambiguity_map_t idAmbiguityCounter;
|
ambiguity_map_t idAmbiguityCounter;
|
||||||
|
|
||||||
extension_set_t candleExtensions;
|
extension_set_t candleExtensions;
|
||||||
extension_set_t lightExtensions;
|
extension_set_t lightExtensions;
|
||||||
|
|
||||||
|
cmWIXPatchParser::fragment_map_t fragments;
|
||||||
};
|
};
|
||||||
|
|
||||||
#endif
|
#endif
|
||||||
|
145
Source/CPack/WiX/cmWIXPatchParser.cxx
Normal file
145
Source/CPack/WiX/cmWIXPatchParser.cxx
Normal file
@ -0,0 +1,145 @@
|
|||||||
|
/*============================================================================
|
||||||
|
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>
|
||||||
|
|
||||||
|
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 char *name, const char **atts)
|
||||||
|
{
|
||||||
|
std::string name_str = name;
|
||||||
|
if(state == BEGIN_DOCUMENT)
|
||||||
|
{
|
||||||
|
if(name_str == "CPackWiXPatch")
|
||||||
|
{
|
||||||
|
state = BEGIN_FRAGMENTS;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
ReportValidationError("Expected root element 'CPackWiXPatch'");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else if(state == BEGIN_FRAGMENTS)
|
||||||
|
{
|
||||||
|
if(name_str == "CPackWiXFragment")
|
||||||
|
{
|
||||||
|
state = INSIDE_FRAGMENT;
|
||||||
|
StartFragment(atts);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
ReportValidationError("Expected 'CPackWixFragment' element");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else if(state == INSIDE_FRAGMENT)
|
||||||
|
{
|
||||||
|
cmWIXPatchElement &parent = *elementStack.back();
|
||||||
|
|
||||||
|
parent.children.resize(parent.children.size() + 1);
|
||||||
|
cmWIXPatchElement*& currentElement = parent.children.back();
|
||||||
|
currentElement = new cmWIXPatchElement;
|
||||||
|
currentElement->name = name;
|
||||||
|
|
||||||
|
for(size_t i = 0; atts[i]; i += 2)
|
||||||
|
{
|
||||||
|
std::string key = atts[i];
|
||||||
|
std::string value = atts[i+1];
|
||||||
|
|
||||||
|
currentElement->attributes[key] = value;
|
||||||
|
}
|
||||||
|
|
||||||
|
elementStack.push_back(currentElement);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
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::stringstream 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 char *name)
|
||||||
|
{
|
||||||
|
std::string name_str = name;
|
||||||
|
if(state == INSIDE_FRAGMENT)
|
||||||
|
{
|
||||||
|
if(name_str == "CPackWiXFragment")
|
||||||
|
{
|
||||||
|
state = BEGIN_FRAGMENTS;
|
||||||
|
elementStack.clear();
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
elementStack.pop_back();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
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(const std::string& message)
|
||||||
|
{
|
||||||
|
ReportError(XML_GetCurrentLineNumber(Parser),
|
||||||
|
XML_GetCurrentColumnNumber(Parser),
|
||||||
|
message.c_str());
|
||||||
|
}
|
||||||
|
|
||||||
|
bool cmWIXPatchParser::IsValid() const
|
||||||
|
{
|
||||||
|
return valid;
|
||||||
|
}
|
75
Source/CPack/WiX/cmWIXPatchParser.h
Normal file
75
Source/CPack/WiX/cmWIXPatchParser.h
Normal file
@ -0,0 +1,75 @@
|
|||||||
|
/*============================================================================
|
||||||
|
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 <cmXMLParser.h>
|
||||||
|
|
||||||
|
#include <CPack/cmCPackLog.h>
|
||||||
|
|
||||||
|
#include <map>
|
||||||
|
#include <list>
|
||||||
|
|
||||||
|
struct cmWIXPatchElement
|
||||||
|
{
|
||||||
|
~cmWIXPatchElement();
|
||||||
|
|
||||||
|
typedef std::list<cmWIXPatchElement*> 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 char *name, const char **atts);
|
||||||
|
|
||||||
|
void StartFragment(const char **attributes);
|
||||||
|
|
||||||
|
virtual void EndElement(const char *name);
|
||||||
|
virtual void ReportError(int line, int column, const char* msg);
|
||||||
|
|
||||||
|
void ReportValidationError(const std::string& 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
|
@ -49,6 +49,8 @@ set(CPACK_PACKAGE_EXECUTABLES
|
|||||||
"my-other-app" "Second CPack WiX Test"
|
"my-other-app" "Second CPack WiX Test"
|
||||||
)
|
)
|
||||||
|
|
||||||
|
set(CPACK_WIX_PATCH_FILE "${CMAKE_CURRENT_SOURCE_DIR}/patch.xml")
|
||||||
|
|
||||||
include(CPack)
|
include(CPack)
|
||||||
|
|
||||||
cpack_add_install_type(Full DISPLAY_NAME "Everything")
|
cpack_add_install_type(Full DISPLAY_NAME "Everything")
|
||||||
|
7
Tests/CPackWiXGenerator/patch.xml
Normal file
7
Tests/CPackWiXGenerator/patch.xml
Normal file
@ -0,0 +1,7 @@
|
|||||||
|
<CPackWiXPatch>
|
||||||
|
<CPackWiXFragment Id="CM_CP_applications.bin.my_libapp.exe">
|
||||||
|
<Environment Id="MyEnvironment" Action="set"
|
||||||
|
Name="CPackWiXGeneratorTest"
|
||||||
|
Value="CPackWiXGeneratorTest"/>
|
||||||
|
</CPackWiXFragment>
|
||||||
|
</CPackWiXPatch>
|
Loading…
x
Reference in New Issue
Block a user