diff options
Diffstat (limited to 'Source/CPack/WiX/cmCPackWIXGenerator.cxx')
-rw-r--r-- | Source/CPack/WiX/cmCPackWIXGenerator.cxx | 437 |
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 == '.'; +} |