diff options
author | Nils Gladitz <nilsgladitz@gmail.com> | 2013-12-16 21:30:11 (GMT) |
---|---|---|
committer | Nils Gladitz <nilsgladitz@gmail.com> | 2013-12-17 13:14:42 (GMT) |
commit | 8632233a2fc0e27106977a820b6b439e72b45383 (patch) | |
tree | a36fbcaf798523e37ac538ea29480b4684bd4798 /Source/CPack | |
parent | b4fdbba55ad857a803a0d2e6c1f0b2bff10f4b51 (diff) | |
download | CMake-8632233a2fc0e27106977a820b6b439e72b45383.zip CMake-8632233a2fc0e27106977a820b6b439e72b45383.tar.gz CMake-8632233a2fc0e27106977a820b6b439e72b45383.tar.bz2 |
CPackWiX: allow customization of generated WiX sources
Added a new variable CPACK_WIX_PATCH_FILE that users can point at an
XML patch file. Fragments defined within the patch file will be inserted
at supported insertion points (currently Component, File and Directory).
Diffstat (limited to 'Source/CPack')
-rw-r--r-- | Source/CPack/WiX/cmCPackWIXGenerator.cxx | 74 | ||||
-rw-r--r-- | Source/CPack/WiX/cmCPackWIXGenerator.h | 11 | ||||
-rw-r--r-- | Source/CPack/WiX/cmWIXPatchParser.cxx | 145 | ||||
-rw-r--r-- | Source/CPack/WiX/cmWIXPatchParser.h | 75 |
4 files changed, 305 insertions, 0 deletions
diff --git a/Source/CPack/WiX/cmCPackWIXGenerator.cxx b/Source/CPack/WiX/cmCPackWIXGenerator.cxx index 1b9b20a..6f1daaa 100644 --- a/Source/CPack/WiX/cmCPackWIXGenerator.cxx +++ b/Source/CPack/WiX/cmCPackWIXGenerator.cxx @@ -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); +} diff --git a/Source/CPack/WiX/cmCPackWIXGenerator.h b/Source/CPack/WiX/cmCPackWIXGenerator.h index 84f68b6..a0a057c 100644 --- a/Source/CPack/WiX/cmCPackWIXGenerator.h +++ b/Source/CPack/WiX/cmCPackWIXGenerator.h @@ -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 diff --git a/Source/CPack/WiX/cmWIXPatchParser.cxx b/Source/CPack/WiX/cmWIXPatchParser.cxx new file mode 100644 index 0000000..0a3b3bc --- /dev/null +++ b/Source/CPack/WiX/cmWIXPatchParser.cxx @@ -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; +} diff --git a/Source/CPack/WiX/cmWIXPatchParser.h b/Source/CPack/WiX/cmWIXPatchParser.h new file mode 100644 index 0000000..4fa5e6f --- /dev/null +++ b/Source/CPack/WiX/cmWIXPatchParser.h @@ -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 |