| /* Distributed under the OSI-approved BSD 3-Clause License. See accompanying |
| file Copyright.txt or https://cmake.org/licensing for details. */ |
| #include "cmCPackIFWInstaller.h" |
| |
| #include <cstddef> |
| #include <sstream> |
| #include <utility> |
| |
| #include "cmCPackIFWCommon.h" |
| #include "cmCPackIFWGenerator.h" |
| #include "cmCPackIFWPackage.h" |
| #include "cmCPackIFWRepository.h" |
| #include "cmCPackLog.h" // IWYU pragma: keep |
| #include "cmGeneratedFileStream.h" |
| #include "cmStringAlgorithms.h" |
| #include "cmSystemTools.h" |
| #include "cmXMLParser.h" |
| #include "cmXMLWriter.h" |
| |
| cmCPackIFWInstaller::cmCPackIFWInstaller() = default; |
| |
| void cmCPackIFWInstaller::printSkippedOptionWarning( |
| const std::string& optionName, const std::string& optionValue) |
| { |
| cmCPackIFWLogger( |
| WARNING, |
| "Option " |
| << optionName << " is set to \"" << optionValue |
| << "\" but will be skipped because the specified file does not exist." |
| << std::endl); |
| } |
| |
| void cmCPackIFWInstaller::ConfigureFromOptions() |
| { |
| // Name; |
| if (const char* optIFW_PACKAGE_NAME = |
| this->GetOption("CPACK_IFW_PACKAGE_NAME")) { |
| this->Name = optIFW_PACKAGE_NAME; |
| } else if (const char* optPACKAGE_NAME = |
| this->GetOption("CPACK_PACKAGE_NAME")) { |
| this->Name = optPACKAGE_NAME; |
| } else { |
| this->Name = "Your package"; |
| } |
| |
| // Title; |
| if (const char* optIFW_PACKAGE_TITLE = |
| this->GetOption("CPACK_IFW_PACKAGE_TITLE")) { |
| this->Title = optIFW_PACKAGE_TITLE; |
| } else if (const char* optPACKAGE_DESCRIPTION_SUMMARY = |
| this->GetOption("CPACK_PACKAGE_DESCRIPTION_SUMMARY")) { |
| this->Title = optPACKAGE_DESCRIPTION_SUMMARY; |
| } else { |
| this->Title = "Your package description"; |
| } |
| |
| // Version; |
| if (const char* option = this->GetOption("CPACK_PACKAGE_VERSION")) { |
| this->Version = option; |
| } else { |
| this->Version = "1.0.0"; |
| } |
| |
| // Publisher |
| if (const char* optIFW_PACKAGE_PUBLISHER = |
| this->GetOption("CPACK_IFW_PACKAGE_PUBLISHER")) { |
| this->Publisher = optIFW_PACKAGE_PUBLISHER; |
| } else if (const char* optPACKAGE_VENDOR = |
| GetOption("CPACK_PACKAGE_VENDOR")) { |
| this->Publisher = optPACKAGE_VENDOR; |
| } |
| |
| // ProductUrl |
| if (const char* option = this->GetOption("CPACK_IFW_PRODUCT_URL")) { |
| this->ProductUrl = option; |
| } |
| |
| // ApplicationIcon |
| if (const char* option = this->GetOption("CPACK_IFW_PACKAGE_ICON")) { |
| if (cmSystemTools::FileExists(option)) { |
| this->InstallerApplicationIcon = option; |
| } else { |
| this->printSkippedOptionWarning("CPACK_IFW_PACKAGE_ICON", option); |
| } |
| } |
| |
| // WindowIcon |
| if (const char* option = this->GetOption("CPACK_IFW_PACKAGE_WINDOW_ICON")) { |
| if (cmSystemTools::FileExists(option)) { |
| this->InstallerWindowIcon = option; |
| } else { |
| this->printSkippedOptionWarning("CPACK_IFW_PACKAGE_WINDOW_ICON", option); |
| } |
| } |
| |
| // RemoveTargetDir |
| if (this->IsSetToOff("CPACK_IFW_PACKAGE_REMOVE_TARGET_DIR")) { |
| this->RemoveTargetDir = "false"; |
| } else if (this->IsOn("CPACK_IFW_PACKAGE_REMOVE_TARGET_DIR")) { |
| this->RemoveTargetDir = "true"; |
| } else { |
| this->RemoveTargetDir.clear(); |
| } |
| |
| // Logo |
| if (const char* option = this->GetOption("CPACK_IFW_PACKAGE_LOGO")) { |
| if (cmSystemTools::FileExists(option)) { |
| this->Logo = option; |
| } else { |
| this->printSkippedOptionWarning("CPACK_IFW_PACKAGE_LOGO", option); |
| } |
| } |
| |
| // Watermark |
| if (const char* option = this->GetOption("CPACK_IFW_PACKAGE_WATERMARK")) { |
| if (cmSystemTools::FileExists(option)) { |
| this->Watermark = option; |
| } else { |
| this->printSkippedOptionWarning("CPACK_IFW_PACKAGE_WATERMARK", option); |
| } |
| } |
| |
| // Banner |
| if (const char* option = this->GetOption("CPACK_IFW_PACKAGE_BANNER")) { |
| if (cmSystemTools::FileExists(option)) { |
| this->Banner = option; |
| } else { |
| this->printSkippedOptionWarning("CPACK_IFW_PACKAGE_BANNER", option); |
| } |
| } |
| |
| // Background |
| if (const char* option = this->GetOption("CPACK_IFW_PACKAGE_BACKGROUND")) { |
| if (cmSystemTools::FileExists(option)) { |
| this->Background = option; |
| } else { |
| this->printSkippedOptionWarning("CPACK_IFW_PACKAGE_BACKGROUND", option); |
| } |
| } |
| |
| // WizardStyle |
| if (const char* option = this->GetOption("CPACK_IFW_PACKAGE_WIZARD_STYLE")) { |
| // Setting the user value in any case |
| this->WizardStyle = option; |
| // Check known values |
| if (this->WizardStyle != "Modern" && this->WizardStyle != "Aero" && |
| this->WizardStyle != "Mac" && this->WizardStyle != "Classic") { |
| cmCPackIFWLogger( |
| WARNING, |
| "Option CPACK_IFW_PACKAGE_WIZARD_STYLE has unknown value \"" |
| << option << "\". Expected values are: Modern, Aero, Mac, Classic." |
| << std::endl); |
| } |
| } |
| |
| // StyleSheet |
| if (const char* option = this->GetOption("CPACK_IFW_PACKAGE_STYLE_SHEET")) { |
| if (cmSystemTools::FileExists(option)) { |
| this->StyleSheet = option; |
| } else { |
| this->printSkippedOptionWarning("CPACK_IFW_PACKAGE_STYLE_SHEET", option); |
| } |
| } |
| |
| // WizardDefaultWidth |
| if (const char* option = |
| this->GetOption("CPACK_IFW_PACKAGE_WIZARD_DEFAULT_WIDTH")) { |
| this->WizardDefaultWidth = option; |
| } |
| |
| // WizardDefaultHeight |
| if (const char* option = |
| this->GetOption("CPACK_IFW_PACKAGE_WIZARD_DEFAULT_HEIGHT")) { |
| this->WizardDefaultHeight = option; |
| } |
| |
| // TitleColor |
| if (const char* option = this->GetOption("CPACK_IFW_PACKAGE_TITLE_COLOR")) { |
| this->TitleColor = option; |
| } |
| |
| // Start menu |
| if (const char* optIFW_START_MENU_DIR = |
| this->GetOption("CPACK_IFW_PACKAGE_START_MENU_DIRECTORY")) { |
| this->StartMenuDir = optIFW_START_MENU_DIR; |
| } else { |
| this->StartMenuDir = Name; |
| } |
| |
| // Default target directory for installation |
| if (const char* optIFW_TARGET_DIRECTORY = |
| this->GetOption("CPACK_IFW_TARGET_DIRECTORY")) { |
| this->TargetDir = optIFW_TARGET_DIRECTORY; |
| } else if (const char* optPACKAGE_INSTALL_DIRECTORY = |
| this->GetOption("CPACK_PACKAGE_INSTALL_DIRECTORY")) { |
| this->TargetDir = |
| cmStrCat("@ApplicationsDir@/", optPACKAGE_INSTALL_DIRECTORY); |
| } else { |
| this->TargetDir = "@RootDir@/usr/local"; |
| } |
| |
| // Default target directory for installation with administrator rights |
| if (const char* option = |
| this->GetOption("CPACK_IFW_ADMIN_TARGET_DIRECTORY")) { |
| this->AdminTargetDir = option; |
| } |
| |
| // Maintenance tool |
| if (const char* optIFW_MAINTENANCE_TOOL = |
| this->GetOption("CPACK_IFW_PACKAGE_MAINTENANCE_TOOL_NAME")) { |
| this->MaintenanceToolName = optIFW_MAINTENANCE_TOOL; |
| } |
| |
| // Maintenance tool ini file |
| if (const char* optIFW_MAINTENANCE_TOOL_INI = |
| this->GetOption("CPACK_IFW_PACKAGE_MAINTENANCE_TOOL_INI_FILE")) { |
| this->MaintenanceToolIniFile = optIFW_MAINTENANCE_TOOL_INI; |
| } |
| |
| // Allow non-ASCII characters |
| if (this->GetOption("CPACK_IFW_PACKAGE_ALLOW_NON_ASCII_CHARACTERS")) { |
| if (this->IsOn("CPACK_IFW_PACKAGE_ALLOW_NON_ASCII_CHARACTERS")) { |
| this->AllowNonAsciiCharacters = "true"; |
| } else { |
| this->AllowNonAsciiCharacters = "false"; |
| } |
| } |
| |
| // Space in path |
| if (this->GetOption("CPACK_IFW_PACKAGE_ALLOW_SPACE_IN_PATH")) { |
| if (this->IsOn("CPACK_IFW_PACKAGE_ALLOW_SPACE_IN_PATH")) { |
| this->AllowSpaceInPath = "true"; |
| } else { |
| this->AllowSpaceInPath = "false"; |
| } |
| } |
| |
| // Control script |
| if (const char* optIFW_CONTROL_SCRIPT = |
| this->GetOption("CPACK_IFW_PACKAGE_CONTROL_SCRIPT")) { |
| this->ControlScript = optIFW_CONTROL_SCRIPT; |
| } |
| |
| // Resources |
| if (const char* optIFW_PACKAGE_RESOURCES = |
| this->GetOption("CPACK_IFW_PACKAGE_RESOURCES")) { |
| this->Resources.clear(); |
| cmExpandList(optIFW_PACKAGE_RESOURCES, this->Resources); |
| } |
| } |
| |
| /** \class cmCPackIFWResourcesParser |
| * \brief Helper class that parse resources form .qrc (Qt) |
| */ |
| class cmCPackIFWResourcesParser : public cmXMLParser |
| { |
| public: |
| cmCPackIFWResourcesParser(cmCPackIFWInstaller* i) |
| : installer(i) |
| , file(false) |
| { |
| this->path = i->Directory + "/resources"; |
| } |
| |
| bool ParseResource(size_t r) |
| { |
| this->hasFiles = false; |
| this->hasErrors = false; |
| |
| this->basePath = |
| cmSystemTools::GetFilenamePath(this->installer->Resources[r]); |
| |
| this->ParseFile(this->installer->Resources[r].data()); |
| |
| return this->hasFiles && !this->hasErrors; |
| } |
| |
| cmCPackIFWInstaller* installer; |
| bool file, hasFiles, hasErrors; |
| std::string path, basePath; |
| |
| protected: |
| void StartElement(const std::string& name, const char** /*atts*/) override |
| { |
| this->file = name == "file"; |
| if (file) { |
| this->hasFiles = true; |
| } |
| } |
| |
| void CharacterDataHandler(const char* data, int length) override |
| { |
| if (this->file) { |
| std::string content(data, data + length); |
| content = cmTrimWhitespace(content); |
| std::string source = this->basePath + "/" + content; |
| std::string destination = this->path + "/" + content; |
| if (!cmSystemTools::CopyFileIfDifferent(source, destination)) { |
| this->hasErrors = true; |
| } |
| } |
| } |
| |
| void EndElement(const std::string& /*name*/) override {} |
| }; |
| |
| void cmCPackIFWInstaller::GenerateInstallerFile() |
| { |
| // Lazy directory initialization |
| if (this->Directory.empty() && this->Generator) { |
| this->Directory = this->Generator->toplevel; |
| } |
| |
| // Output stream |
| cmGeneratedFileStream fout(this->Directory + "/config/config.xml"); |
| cmXMLWriter xout(fout); |
| |
| xout.StartDocument(); |
| |
| WriteGeneratedByToStrim(xout); |
| |
| xout.StartElement("Installer"); |
| |
| xout.Element("Name", this->Name); |
| xout.Element("Version", this->Version); |
| xout.Element("Title", this->Title); |
| |
| if (!this->Publisher.empty()) { |
| xout.Element("Publisher", this->Publisher); |
| } |
| |
| if (!this->ProductUrl.empty()) { |
| xout.Element("ProductUrl", this->ProductUrl); |
| } |
| |
| // ApplicationIcon |
| if (!this->InstallerApplicationIcon.empty()) { |
| std::string name = |
| cmSystemTools::GetFilenameName(this->InstallerApplicationIcon); |
| std::string path = this->Directory + "/config/" + name; |
| name = cmSystemTools::GetFilenameWithoutExtension(name); |
| cmsys::SystemTools::CopyFileIfDifferent(this->InstallerApplicationIcon, |
| path); |
| xout.Element("InstallerApplicationIcon", name); |
| } |
| |
| // WindowIcon |
| if (!this->InstallerWindowIcon.empty()) { |
| std::string name = |
| cmSystemTools::GetFilenameName(this->InstallerWindowIcon); |
| std::string path = this->Directory + "/config/" + name; |
| cmsys::SystemTools::CopyFileIfDifferent(this->InstallerWindowIcon, path); |
| xout.Element("InstallerWindowIcon", name); |
| } |
| |
| // Logo |
| if (!this->Logo.empty()) { |
| std::string name = cmSystemTools::GetFilenameName(this->Logo); |
| std::string path = this->Directory + "/config/" + name; |
| cmsys::SystemTools::CopyFileIfDifferent(this->Logo, path); |
| xout.Element("Logo", name); |
| } |
| |
| // Banner |
| if (!this->Banner.empty()) { |
| std::string name = cmSystemTools::GetFilenameName(this->Banner); |
| std::string path = this->Directory + "/config/" + name; |
| cmsys::SystemTools::CopyFileIfDifferent(this->Banner, path); |
| xout.Element("Banner", name); |
| } |
| |
| // Watermark |
| if (!this->Watermark.empty()) { |
| std::string name = cmSystemTools::GetFilenameName(this->Watermark); |
| std::string path = this->Directory + "/config/" + name; |
| cmsys::SystemTools::CopyFileIfDifferent(this->Watermark, path); |
| xout.Element("Watermark", name); |
| } |
| |
| // Background |
| if (!this->Background.empty()) { |
| std::string name = cmSystemTools::GetFilenameName(this->Background); |
| std::string path = this->Directory + "/config/" + name; |
| cmsys::SystemTools::CopyFileIfDifferent(this->Background, path); |
| xout.Element("Background", name); |
| } |
| |
| // WizardStyle |
| if (!this->WizardStyle.empty()) { |
| xout.Element("WizardStyle", this->WizardStyle); |
| } |
| |
| // Stylesheet |
| if (!this->StyleSheet.empty()) { |
| std::string name = cmSystemTools::GetFilenameName(this->StyleSheet); |
| std::string path = this->Directory + "/config/" + name; |
| cmsys::SystemTools::CopyFileIfDifferent(this->StyleSheet, path); |
| xout.Element("StyleSheet", name); |
| } |
| |
| // WizardDefaultWidth |
| if (!this->WizardDefaultWidth.empty()) { |
| xout.Element("WizardDefaultWidth", this->WizardDefaultWidth); |
| } |
| |
| // WizardDefaultHeight |
| if (!this->WizardDefaultHeight.empty()) { |
| xout.Element("WizardDefaultHeight", this->WizardDefaultHeight); |
| } |
| |
| // TitleColor |
| if (!this->TitleColor.empty()) { |
| xout.Element("TitleColor", this->TitleColor); |
| } |
| |
| // Start menu |
| if (!this->IsVersionLess("2.0")) { |
| xout.Element("StartMenuDir", this->StartMenuDir); |
| } |
| |
| // Target dir |
| if (!this->TargetDir.empty()) { |
| xout.Element("TargetDir", this->TargetDir); |
| } |
| |
| // Admin target dir |
| if (!this->AdminTargetDir.empty()) { |
| xout.Element("AdminTargetDir", this->AdminTargetDir); |
| } |
| |
| // Remote repositories |
| if (!this->RemoteRepositories.empty()) { |
| xout.StartElement("RemoteRepositories"); |
| for (cmCPackIFWRepository* r : this->RemoteRepositories) { |
| r->WriteRepositoryConfig(xout); |
| } |
| xout.EndElement(); |
| } |
| |
| // Maintenance tool |
| if (!this->IsVersionLess("2.0") && !this->MaintenanceToolName.empty()) { |
| xout.Element("MaintenanceToolName", this->MaintenanceToolName); |
| } |
| |
| // Maintenance tool ini file |
| if (!this->IsVersionLess("2.0") && !this->MaintenanceToolIniFile.empty()) { |
| xout.Element("MaintenanceToolIniFile", this->MaintenanceToolIniFile); |
| } |
| |
| if (!this->RemoveTargetDir.empty()) { |
| xout.Element("RemoveTargetDir", this->RemoveTargetDir); |
| } |
| |
| // Different allows |
| if (this->IsVersionLess("2.0")) { |
| // CPack IFW default policy |
| xout.Comment("CPack IFW default policy for QtIFW less 2.0"); |
| xout.Element("AllowNonAsciiCharacters", "true"); |
| xout.Element("AllowSpaceInPath", "true"); |
| } else { |
| if (!this->AllowNonAsciiCharacters.empty()) { |
| xout.Element("AllowNonAsciiCharacters", this->AllowNonAsciiCharacters); |
| } |
| if (!this->AllowSpaceInPath.empty()) { |
| xout.Element("AllowSpaceInPath", this->AllowSpaceInPath); |
| } |
| } |
| |
| // Control script (copy to config dir) |
| if (!this->IsVersionLess("2.0") && !this->ControlScript.empty()) { |
| std::string name = cmSystemTools::GetFilenameName(this->ControlScript); |
| std::string path = this->Directory + "/config/" + name; |
| cmsys::SystemTools::CopyFileIfDifferent(this->ControlScript, path); |
| xout.Element("ControlScript", name); |
| } |
| |
| // Resources (copy to resources dir) |
| if (!this->Resources.empty()) { |
| std::vector<std::string> resources; |
| cmCPackIFWResourcesParser parser(this); |
| for (size_t i = 0; i < this->Resources.size(); i++) { |
| if (parser.ParseResource(i)) { |
| std::string name = cmSystemTools::GetFilenameName(this->Resources[i]); |
| std::string path = this->Directory + "/resources/" + name; |
| cmsys::SystemTools::CopyFileIfDifferent(this->Resources[i], path); |
| resources.push_back(std::move(name)); |
| } else { |
| cmCPackIFWLogger(WARNING, |
| "Can't copy resources from \"" |
| << this->Resources[i] |
| << "\". Resource will be skipped." << std::endl); |
| } |
| } |
| this->Resources = resources; |
| } |
| |
| xout.EndElement(); |
| xout.EndDocument(); |
| } |
| |
| void cmCPackIFWInstaller::GeneratePackageFiles() |
| { |
| if (this->Packages.empty() || this->Generator->IsOnePackage()) { |
| // Generate default package |
| cmCPackIFWPackage package; |
| package.Generator = this->Generator; |
| package.Installer = this; |
| // Check package group |
| if (const char* option = this->GetOption("CPACK_IFW_PACKAGE_GROUP")) { |
| package.ConfigureFromGroup(option); |
| std::string forcedOption = "CPACK_IFW_COMPONENT_GROUP_" + |
| cmsys::SystemTools::UpperCase(option) + "_FORCED_INSTALLATION"; |
| if (!GetOption(forcedOption)) { |
| package.ForcedInstallation = "true"; |
| } |
| } else { |
| package.ConfigureFromOptions(); |
| } |
| package.GeneratePackageFile(); |
| return; |
| } |
| |
| // Generate packages meta information |
| for (auto& p : this->Packages) { |
| cmCPackIFWPackage* package = p.second; |
| package->GeneratePackageFile(); |
| } |
| } |