/* 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 #include #include #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 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(); } }