summaryrefslogtreecommitdiffstats
path: root/Source/CPack/WiX/cmCPackWIXGenerator.cxx
diff options
context:
space:
mode:
Diffstat (limited to 'Source/CPack/WiX/cmCPackWIXGenerator.cxx')
-rw-r--r--Source/CPack/WiX/cmCPackWIXGenerator.cxx437
1 files changed, 308 insertions, 129 deletions
diff --git a/Source/CPack/WiX/cmCPackWIXGenerator.cxx b/Source/CPack/WiX/cmCPackWIXGenerator.cxx
index cc9dec7..448d8d1 100644
--- a/Source/CPack/WiX/cmCPackWIXGenerator.cxx
+++ b/Source/CPack/WiX/cmCPackWIXGenerator.cxx
@@ -1,6 +1,6 @@
/*============================================================================
CMake - Cross Platform Makefile Generator
- Copyright 2000-2012 Kitware, Inc., Insight Software Consortium
+ Copyright 2000-2013 Kitware, Inc., Insight Software Consortium
Distributed under the OSI-approved BSD License (the "License");
see accompanying file Copyright.txt for details.
@@ -14,6 +14,7 @@
#include <cmSystemTools.h>
#include <cmGeneratedFileStream.h>
+#include <cmCryptoHash.h>
#include <CPack/cmCPackLog.h>
#include <CPack/cmCPackComponentGroup.h>
@@ -169,6 +170,16 @@ bool cmCPackWIXGenerator::InitializeWiXConfiguration()
}
}
+ if(GetOption("CPACK_PACKAGE_VENDOR") == 0)
+ {
+ std::string defaultVendor = "Humanity";
+ SetOption("CPACK_PACKAGE_VENDOR", defaultVendor.c_str());
+
+ cmCPackLogger(cmCPackLog::LOG_VERBOSE,
+ "CPACK_PACKAGE_VENDOR implicitly set to " << defaultVendor << " . "
+ << std::endl);
+ }
+
return true;
}
@@ -189,6 +200,8 @@ bool cmCPackWIXGenerator::PackageFilesImpl()
return false;
}
+ AppendUserSuppliedExtraSources();
+
std::stringstream objectFiles;
for(size_t i = 0; i < wixSources.size(); ++i)
{
@@ -205,9 +218,35 @@ bool cmCPackWIXGenerator::PackageFilesImpl()
objectFiles << " " << QuotePath(objectFilename);
}
+ AppendUserSuppliedExtraObjects(objectFiles);
+
return RunLightCommand(objectFiles.str());
}
+void cmCPackWIXGenerator::AppendUserSuppliedExtraSources()
+{
+ const char *cpackWixExtraSources = GetOption("CPACK_WIX_EXTRA_SOURCES");
+ if(!cpackWixExtraSources) return;
+
+ cmSystemTools::ExpandListArgument(cpackWixExtraSources, wixSources);
+}
+
+void cmCPackWIXGenerator::AppendUserSuppliedExtraObjects(std::ostream& stream)
+{
+ const char *cpackWixExtraObjects = GetOption("CPACK_WIX_EXTRA_OBJECTS");
+ if(!cpackWixExtraObjects) return;
+
+ std::vector<std::string> expandedExtraObjects;
+
+ cmSystemTools::ExpandListArgument(
+ cpackWixExtraObjects, expandedExtraObjects);
+
+ for(size_t i = 0; i < expandedExtraObjects.size(); ++i)
+ {
+ stream << " " << QuotePath(expandedExtraObjects[i]);
+ }
+}
+
bool cmCPackWIXGenerator::CreateWiXVariablesIncludeFile()
{
std::string cpackTopLevel;
@@ -319,9 +358,6 @@ bool cmCPackWIXGenerator::CreateWiXSourceFiles()
directoryDefinitions.AddAttribute("Name", install_root[i]);
}
- size_t directoryCounter = 0;
- size_t fileCounter = 0;
-
std::string fileDefinitionsFilename =
cpackTopLevel + "/files.wxs";
@@ -342,113 +378,49 @@ bool cmCPackWIXGenerator::CreateWiXSourceFiles()
featureDefinitions.AddAttribute("Id", "ProductFeature");
featureDefinitions.AddAttribute("Title", Name);
featureDefinitions.AddAttribute("Level", "1");
- featureDefinitions.EndElement();
+ featureDefinitions.EndElement("Feature");
featureDefinitions.BeginElement("FeatureRef");
featureDefinitions.AddAttribute("Id", "ProductFeature");
+ std::vector<std::string> cpackPackageExecutablesList;
const char *cpackPackageExecutables = GetOption("CPACK_PACKAGE_EXECUTABLES");
- std::vector<std::string> cpackPkgExecutables;
- std::string regKey;
- if ( cpackPackageExecutables )
+ if(cpackPackageExecutables)
{
- cmSystemTools::ExpandListArgument(cpackPackageExecutables,
- cpackPkgExecutables);
- if ( cpackPkgExecutables.size() % 2 != 0 )
- {
- cmCPackLogger(cmCPackLog::LOG_ERROR,
- "CPACK_PACKAGE_EXECUTABLES should contain pairs of <executable> and "
- "<icon name>." << std::endl);
- cpackPkgExecutables.clear();
- }
-
- const char *cpackVendor = GetOption("CPACK_PACKAGE_VENDOR");
- const char *cpackPkgName = GetOption("CPACK_PACKAGE_NAME");
- if (!cpackVendor || !cpackPkgName)
- {
- cmCPackLogger(cmCPackLog::LOG_WARNING, "CPACK_PACKAGE_VENDOR and "
- "CPACK_PACKAGE_NAME must be defined for shortcut creation" << std::endl);
- cpackPkgExecutables.clear();
- }
- else
- {
- regKey = std::string("Software/") + cpackVendor + "/" + cpackPkgName;
- }
+ cmSystemTools::ExpandListArgument(cpackPackageExecutables,
+ cpackPackageExecutablesList);
+ if(cpackPackageExecutablesList.size() % 2 != 0 )
+ {
+ cmCPackLogger(cmCPackLog::LOG_ERROR,
+ "CPACK_PACKAGE_EXECUTABLES should contain pairs of <executable> and "
+ "<text label>." << std::endl);
+ return false;
+ }
}
- std::vector<std::string> dirIdExecutables;
AddDirectoryAndFileDefinitons(
toplevel, "INSTALL_ROOT",
directoryDefinitions, fileDefinitions, featureDefinitions,
- directoryCounter, fileCounter, cpackPkgExecutables, dirIdExecutables);
+ cpackPackageExecutablesList);
- directoryDefinitions.EndElement();
- directoryDefinitions.EndElement();
-
- if (dirIdExecutables.size() > 0 && dirIdExecutables.size() % 3 == 0)
+ if(!CreateStartMenuShortcuts(
+ directoryDefinitions, fileDefinitions, featureDefinitions))
{
- fileDefinitions.BeginElement("DirectoryRef");
- fileDefinitions.AddAttribute("Id", "PROGRAM_MENU_FOLDER");
- fileDefinitions.BeginElement("Component");
- fileDefinitions.AddAttribute("Id", "SHORTCUT");
- fileDefinitions.AddAttribute("Guid", "*");
+ return false;
+ }
- std::vector<std::string>::iterator it;
- for ( it = dirIdExecutables.begin() ;
- it != dirIdExecutables.end();
- ++it)
- {
- std::string fileName = *it++;
- std::string iconName = *it++;
- std::string directoryId = *it;
-
- fileDefinitions.BeginElement("Shortcut");
- std::string shortcutName = fileName; // the iconName is mor likely to contain blanks early on
- std::string::size_type const dotPos = shortcutName.find('.');
- if(std::string::npos == dotPos)
- { shortcutName = shortcutName.substr(0, dotPos); }
- fileDefinitions.AddAttribute("Id", "SHORTCUT_" + shortcutName);
- fileDefinitions.AddAttribute("Name", iconName);
- std::string target = "[" + directoryId + "]" + fileName;
- fileDefinitions.AddAttribute("Target", target);
- fileDefinitions.AddAttribute("WorkingDirectory", directoryId);
- fileDefinitions.EndElement();
- }
- fileDefinitions.BeginElement("Shortcut");
- fileDefinitions.AddAttribute("Id", "UNINSTALL");
- std::string pkgName = GetOption("CPACK_PACKAGE_NAME");
- fileDefinitions.AddAttribute("Name", "Uninstall " + pkgName);
- fileDefinitions.AddAttribute("Description", "Uninstalls " + pkgName);
- fileDefinitions.AddAttribute("Target", "[SystemFolder]msiexec.exe");
- fileDefinitions.AddAttribute("Arguments", "/x [ProductCode]");
- fileDefinitions.EndElement();
- fileDefinitions.BeginElement("RemoveFolder");
- fileDefinitions.AddAttribute("Id", "PROGRAM_MENU_FOLDER");
- fileDefinitions.AddAttribute("On", "uninstall");
- fileDefinitions.EndElement();
- fileDefinitions.BeginElement("RegistryValue");
- fileDefinitions.AddAttribute("Root", "HKCU");
- fileDefinitions.AddAttribute("Key", regKey);
- fileDefinitions.AddAttribute("Name", "installed");
- fileDefinitions.AddAttribute("Type", "integer");
- fileDefinitions.AddAttribute("Value", "1");
- fileDefinitions.AddAttribute("KeyPath", "yes");
-
- featureDefinitions.BeginElement("ComponentRef");
- featureDefinitions.AddAttribute("Id", "SHORTCUT");
- featureDefinitions.EndElement();
- directoryDefinitions.BeginElement("Directory");
- directoryDefinitions.AddAttribute("Id", "ProgramMenuFolder");
- directoryDefinitions.BeginElement("Directory");
- directoryDefinitions.AddAttribute("Id", "PROGRAM_MENU_FOLDER");
- const char *startMenuFolder = GetOption("CPACK_WIX_PROGRAM_MENU_FOLDER");
- directoryDefinitions.AddAttribute("Name", startMenuFolder);
- }
+ featureDefinitions.EndElement("FeatureRef");
+ featureDefinitions.EndElement("Fragment");
+ fileDefinitions.EndElement("Fragment");
- featureDefinitions.EndElement();
- featureDefinitions.EndElement();
- fileDefinitions.EndElement();
- directoryDefinitions.EndElement();
+ for(size_t i = 1; i < install_root.size(); ++i)
+ {
+ directoryDefinitions.EndElement("Directory");
+ }
+
+ directoryDefinitions.EndElement("Directory");
+ directoryDefinitions.EndElement("Directory");
+ directoryDefinitions.EndElement("Fragment");
std::string wixTemplate = FindTemplate("WIX.template.in");
if(GetOption("CPACK_WIX_TEMPLATE") != 0)
@@ -478,6 +450,106 @@ bool cmCPackWIXGenerator::CreateWiXSourceFiles()
return true;
}
+bool cmCPackWIXGenerator::CreateStartMenuShortcuts(
+ cmWIXSourceWriter& directoryDefinitions,
+ cmWIXSourceWriter& fileDefinitions,
+ cmWIXSourceWriter& featureDefinitions)
+{
+ if(shortcutMap.empty())
+ {
+ return true;
+ }
+
+ std::string cpackVendor;
+ if(!RequireOption("CPACK_PACKAGE_VENDOR", cpackVendor))
+ {
+ return false;
+ }
+
+ std::string cpackPackageName;
+ if(!RequireOption("CPACK_PACKAGE_NAME", cpackPackageName))
+ {
+ return false;
+ }
+
+ fileDefinitions.BeginElement("DirectoryRef");
+ fileDefinitions.AddAttribute("Id", "PROGRAM_MENU_FOLDER");
+ fileDefinitions.BeginElement("Component");
+ fileDefinitions.AddAttribute("Id", "SHORTCUT");
+ fileDefinitions.AddAttribute("Guid", "*");
+
+ for(shortcut_map_t::const_iterator
+ i = shortcutMap.begin(); i != shortcutMap.end(); ++i)
+ {
+ std::string const& id = i->first;
+ cmWIXShortcut const& shortcut = i->second;
+
+ std::string shortcutId = std::string("CM_S") + id;
+ std::string fileId = std::string("CM_F") + id;
+
+ fileDefinitions.BeginElement("Shortcut");
+ fileDefinitions.AddAttribute("Id", shortcutId);
+ fileDefinitions.AddAttribute("Name", shortcut.textLabel);
+ std::string target = "[#" + fileId + "]";
+ fileDefinitions.AddAttribute("Target", target);
+ fileDefinitions.AddAttribute("WorkingDirectory",
+ shortcut.workingDirectoryId);
+ fileDefinitions.EndElement("Shortcut");
+ }
+
+ CreateUninstallShortcut(cpackPackageName, fileDefinitions);
+
+ fileDefinitions.BeginElement("RemoveFolder");
+ fileDefinitions.AddAttribute("Id", "PROGRAM_MENU_FOLDER");
+ fileDefinitions.AddAttribute("On", "uninstall");
+ fileDefinitions.EndElement("RemoveFolder");
+
+ std::string registryKey =
+ std::string("Software/") + cpackVendor + "/" + cpackPackageName;
+
+ fileDefinitions.BeginElement("RegistryValue");
+ fileDefinitions.AddAttribute("Root", "HKCU");
+ fileDefinitions.AddAttribute("Key", registryKey);
+ fileDefinitions.AddAttribute("Name", "installed");
+ fileDefinitions.AddAttribute("Type", "integer");
+ fileDefinitions.AddAttribute("Value", "1");
+ fileDefinitions.AddAttribute("KeyPath", "yes");
+ fileDefinitions.EndElement("RegistryValue");
+
+ fileDefinitions.EndElement("Component");
+ fileDefinitions.EndElement("DirectoryRef");
+
+ featureDefinitions.BeginElement("ComponentRef");
+ featureDefinitions.AddAttribute("Id", "SHORTCUT");
+ featureDefinitions.EndElement("ComponentRef");
+
+ directoryDefinitions.BeginElement("Directory");
+ directoryDefinitions.AddAttribute("Id", "ProgramMenuFolder");
+
+ directoryDefinitions.BeginElement("Directory");
+ directoryDefinitions.AddAttribute("Id", "PROGRAM_MENU_FOLDER");
+ const char *startMenuFolder = GetOption("CPACK_WIX_PROGRAM_MENU_FOLDER");
+ directoryDefinitions.AddAttribute("Name", startMenuFolder);
+ directoryDefinitions.EndElement("Directory");
+
+ directoryDefinitions.EndElement("Directory");
+
+ return true;
+}
+
+void cmCPackWIXGenerator::CreateUninstallShortcut(
+ std::string const& packageName,
+ cmWIXSourceWriter& fileDefinitions)
+{
+ fileDefinitions.BeginElement("Shortcut");
+ fileDefinitions.AddAttribute("Id", "UNINSTALL");
+ fileDefinitions.AddAttribute("Name", "Uninstall " + packageName);
+ fileDefinitions.AddAttribute("Description", "Uninstalls " + packageName);
+ fileDefinitions.AddAttribute("Target", "[SystemFolder]msiexec.exe");
+ fileDefinitions.AddAttribute("Arguments", "/x [ProductCode]");
+ fileDefinitions.EndElement("Shortcut");
+}
+
bool cmCPackWIXGenerator::CreateLicenseFile()
{
std::string licenseSourceFilename;
@@ -531,10 +603,7 @@ void cmCPackWIXGenerator::AddDirectoryAndFileDefinitons(
cmWIXSourceWriter& directoryDefinitions,
cmWIXSourceWriter& fileDefinitions,
cmWIXSourceWriter& featureDefinitions,
- size_t& directoryCounter,
- size_t& fileCounter,
- const std::vector<std::string>& pkgExecutables,
- std::vector<std::string>& dirIdExecutables)
+ const std::vector<std::string>& packageExecutables)
{
cmsys::Directory dir;
dir.Load(topdir.c_str());
@@ -550,11 +619,14 @@ void cmCPackWIXGenerator::AddDirectoryAndFileDefinitons(
std::string fullPath = topdir + "/" + fileName;
+ std::string relativePath = cmSystemTools::RelativePath(
+ toplevel.c_str(), fullPath.c_str());
+
+ std::string id = PathToId(relativePath);
+
if(cmSystemTools::FileIsDirectory(fullPath.c_str()))
{
- std::stringstream tmp;
- tmp << "DIR_ID_" << ++directoryCounter;
- std::string subDirectoryId = tmp.str();
+ std::string subDirectoryId = std::string("CM_D") + id;
directoryDefinitions.BeginElement("Directory");
directoryDefinitions.AddAttribute("Id", subDirectoryId);
@@ -565,20 +637,14 @@ void cmCPackWIXGenerator::AddDirectoryAndFileDefinitons(
directoryDefinitions,
fileDefinitions,
featureDefinitions,
- directoryCounter,
- fileCounter,
- pkgExecutables,
- dirIdExecutables);
- directoryDefinitions.EndElement();
+ packageExecutables);
+
+ directoryDefinitions.EndElement("Directory");
}
else
{
- std::stringstream tmp;
- tmp << "_ID_" << ++fileCounter;
- std::string idSuffix = tmp.str();
-
- std::string componentId = std::string("CMP") + idSuffix;
- std::string fileId = std::string("FILE") + idSuffix;
+ std::string componentId = std::string("CM_C") + id;
+ std::string fileId = std::string("CM_F") + id;
fileDefinitions.BeginElement("DirectoryRef");
fileDefinitions.AddAttribute("Id", directoryId);
@@ -592,28 +658,25 @@ void cmCPackWIXGenerator::AddDirectoryAndFileDefinitons(
fileDefinitions.AddAttribute("Source", fullPath);
fileDefinitions.AddAttribute("KeyPath", "yes");
- fileDefinitions.EndElement();
- fileDefinitions.EndElement();
- fileDefinitions.EndElement();
+ fileDefinitions.EndElement("File");
+ fileDefinitions.EndElement("Component");
+ fileDefinitions.EndElement("DirectoryRef");
featureDefinitions.BeginElement("ComponentRef");
featureDefinitions.AddAttribute("Id", componentId);
- featureDefinitions.EndElement();
+ featureDefinitions.EndElement("ComponentRef");
- std::vector<std::string>::const_iterator it;
- for (it = pkgExecutables.begin() ;
- it != pkgExecutables.end() ;
- ++it)
+ for(size_t j = 0; j < packageExecutables.size(); ++j)
{
- std::string execName = *it++;
- std::string iconName = *it;
+ std::string const& executableName = packageExecutables[j++];
+ std::string const& textLabel = packageExecutables[j];
- if (cmSystemTools::LowerCase(fileName) ==
- cmSystemTools::LowerCase(execName) + ".exe")
+ if(cmSystemTools::LowerCase(fileName) ==
+ cmSystemTools::LowerCase(executableName) + ".exe")
{
- dirIdExecutables.push_back(fileName);
- dirIdExecutables.push_back(iconName);
- dirIdExecutables.push_back(directoryId);
+ cmWIXShortcut &shortcut = shortcutMap[id];
+ shortcut.textLabel= textLabel;
+ shortcut.workingDirectoryId = directoryId;
}
}
}
@@ -686,3 +749,119 @@ std::string cmCPackWIXGenerator::GetRightmostExtension(
return cmSystemTools::LowerCase(extension);
}
+
+std::string cmCPackWIXGenerator::PathToId(const std::string& path)
+{
+ id_map_t::const_iterator i = pathToIdMap.find(path);
+ if(i != pathToIdMap.end()) return i->second;
+
+ std::string id = CreateNewIdForPath(path);
+ return id;
+}
+
+std::string cmCPackWIXGenerator::CreateNewIdForPath(const std::string& path)
+{
+ std::vector<std::string> components;
+ cmSystemTools::SplitPath(path.c_str(), components, false);
+
+ size_t replacementCount = 0;
+
+ std::string identifier;
+ std::string currentComponent;
+
+ for(size_t i = 1; i < components.size(); ++i)
+ {
+ if(i != 1) identifier += '.';
+
+ currentComponent = NormalizeComponentForId(
+ components[i], replacementCount);
+
+ identifier += currentComponent;
+ }
+
+ std::string idPrefix = "P";
+ size_t replacementPercent = replacementCount * 100 / identifier.size();
+ if(replacementPercent > 33 || identifier.size() > 60)
+ {
+ identifier = CreateHashedId(path, currentComponent);
+ idPrefix = "H";
+ }
+
+ std::stringstream result;
+ result << idPrefix << "_" << identifier;
+
+ size_t ambiguityCount = ++idAmbiguityCounter[identifier];
+
+ if(ambiguityCount > 999)
+ {
+ cmCPackLogger(cmCPackLog::LOG_ERROR,
+ "Error while trying to generate a unique Id for '" <<
+ path << "'" << std::endl);
+
+ return std::string();
+ }
+ else if(ambiguityCount > 1)
+ {
+ result << "_" << ambiguityCount;
+ }
+
+ std::string resultString = result.str();
+
+ pathToIdMap[path] = resultString;
+
+ return resultString;
+}
+
+std::string cmCPackWIXGenerator::CreateHashedId(
+ const std::string& path, const std::string& normalizedFilename)
+{
+ cmsys::auto_ptr<cmCryptoHash> sha1 = cmCryptoHash::New("SHA1");
+ std::string hash = sha1->HashString(path.c_str());
+
+ std::string identifier;
+ identifier += hash.substr(0, 7) + "_";
+
+ const size_t maxFileNameLength = 52;
+ if(normalizedFilename.length() > maxFileNameLength)
+ {
+ identifier += normalizedFilename.substr(0, maxFileNameLength - 3);
+ identifier += "...";
+ }
+ else
+ {
+ identifier += normalizedFilename;
+ }
+
+ return identifier;
+}
+
+std::string cmCPackWIXGenerator::NormalizeComponentForId(
+ const std::string& component, size_t& replacementCount)
+{
+ std::string result;
+ result.resize(component.size());
+
+ for(size_t i = 0; i < component.size(); ++i)
+ {
+ char c = component[i];
+ if(IsLegalIdCharacter(c))
+ {
+ result[i] = c;
+ }
+ else
+ {
+ result[i] = '_';
+ ++ replacementCount;
+ }
+ }
+
+ return result;
+}
+
+bool cmCPackWIXGenerator::IsLegalIdCharacter(char c)
+{
+ return (c >= '0' && c <= '9') ||
+ (c >= 'a' && c <= 'z') ||
+ (c >= 'A' && c <= 'Z') ||
+ c == '_' || c == '.';
+}