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
|
||||
# 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
|
||||
#
|
||||
# Extra WiX source files
|
||||
|
|
|
@ -517,6 +517,7 @@ if(WIN32)
|
|||
CPack/WiX/cmCPackWIXGenerator.cxx
|
||||
CPack/WiX/cmWIXSourceWriter.cxx
|
||||
CPack/WiX/cmWIXRichTextFormatWriter.cxx
|
||||
CPack/WiX/cmWIXPatchParser.cxx
|
||||
)
|
||||
endif()
|
||||
|
||||
|
|
|
@ -218,6 +218,12 @@ bool cmCPackWIXGenerator::InitializeWiXConfiguration()
|
|||
CollectExtensions("CPACK_WIX_EXTENSIONS", lightExtensions);
|
||||
CollectExtensions("CPACK_WIX_LIGHT_EXTENSIONS", lightExtensions);
|
||||
|
||||
const char* patchFilePath = GetOption("CPACK_WIX_PATCH_FILE");
|
||||
if(patchFilePath)
|
||||
{
|
||||
LoadPatchFragments(patchFilePath);
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
|
@ -529,6 +535,28 @@ bool cmCPackWIXGenerator::CreateWiXSourceFiles()
|
|||
|
||||
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;
|
||||
}
|
||||
|
||||
|
@ -872,6 +900,7 @@ void cmCPackWIXGenerator::AddDirectoryAndFileDefinitons(
|
|||
packageExecutables,
|
||||
shortcutMap);
|
||||
|
||||
ApplyPatchFragment(subDirectoryId, directoryDefinitions);
|
||||
directoryDefinitions.EndElement("Directory");
|
||||
}
|
||||
else
|
||||
|
@ -891,7 +920,10 @@ void cmCPackWIXGenerator::AddDirectoryAndFileDefinitons(
|
|||
fileDefinitions.AddAttribute("Source", fullPath);
|
||||
fileDefinitions.AddAttribute("KeyPath", "yes");
|
||||
|
||||
ApplyPatchFragment(fileId, fileDefinitions);
|
||||
fileDefinitions.EndElement("File");
|
||||
|
||||
ApplyPatchFragment(componentId, fileDefinitions);
|
||||
fileDefinitions.EndElement("Component");
|
||||
fileDefinitions.EndElement("DirectoryRef");
|
||||
|
||||
|
@ -1146,3 +1178,45 @@ void cmCPackWIXGenerator::CreateStartMenuFolder(
|
|||
|
||||
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
|
||||
#define cmCPackWIXGenerator_h
|
||||
|
||||
#include "cmWIXPatchParser.h"
|
||||
|
||||
#include <CPack/cmCPackGenerator.h>
|
||||
|
||||
#include <string>
|
||||
|
@ -160,12 +162,21 @@ private:
|
|||
|
||||
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;
|
||||
id_map_t pathToIdMap;
|
||||
ambiguity_map_t idAmbiguityCounter;
|
||||
|
||||
extension_set_t candleExtensions;
|
||||
extension_set_t lightExtensions;
|
||||
|
||||
cmWIXPatchParser::fragment_map_t fragments;
|
||||
};
|
||||
|
||||
#endif
|
||||
|
|
|
@ -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;
|
||||
}
|
|
@ -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"
|
||||
)
|
||||
|
||||
set(CPACK_WIX_PATCH_FILE "${CMAKE_CURRENT_SOURCE_DIR}/patch.xml")
|
||||
|
||||
include(CPack)
|
||||
|
||||
cpack_add_install_type(Full DISPLAY_NAME "Everything")
|
||||
|
|
|
@ -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…
Reference in New Issue