/* Distributed under the OSI-approved BSD 3-Clause License. See accompanying file Copyright.txt or https://cmake.org/licensing for details. */ #include "cmCPackIFWGenerator.h" #include "cmCPackComponentGroup.h" #include "cmCPackGenerator.h" #include "cmCPackIFWCommon.h" #include "cmCPackIFWInstaller.h" #include "cmCPackIFWPackage.h" #include "cmCPackIFWRepository.h" #include "cmCPackLog.h" // IWYU pragma: keep #include "cmDuration.h" #include "cmGeneratedFileStream.h" #include "cmSystemTools.h" #include #include cmCPackIFWGenerator::cmCPackIFWGenerator() { this->Generator = this; } cmCPackIFWGenerator::~cmCPackIFWGenerator() { } int cmCPackIFWGenerator::PackageFiles() { cmCPackIFWLogger(OUTPUT, "- Configuration" << std::endl); // Installer configuragion this->Installer.GenerateInstallerFile(); // Packages configuration this->Installer.GeneratePackageFiles(); std::string ifwTLD = this->GetOption("CPACK_TOPLEVEL_DIRECTORY"); std::string ifwTmpFile = ifwTLD; ifwTmpFile += "/IFWOutput.log"; // Run repogen if (!this->Installer.RemoteRepositories.empty()) { std::string ifwCmd = this->RepoGen; if (this->IsVersionLess("2.0.0")) { ifwCmd += " -c " + this->toplevel + "/config/config.xml"; } ifwCmd += " -p " + this->toplevel + "/packages"; if (!this->PkgsDirsVector.empty()) { for (std::string const& it : this->PkgsDirsVector) { ifwCmd += " -p " + it; } } if (!this->RepoDirsVector.empty()) { if (!this->IsVersionLess("3.1")) { for (std::string const& rd : this->RepoDirsVector) { ifwCmd += " --repository " + rd; } } else { cmCPackIFWLogger(WARNING, "The \"CPACK_IFW_REPOSITORIES_DIRECTORIES\" " << "variable is set, but content will be skipped, " << "because this feature available only since " << "QtIFW 3.1. Please update your QtIFW instance." << std::endl); } } if (!this->OnlineOnly && !this->DownloadedPackages.empty()) { ifwCmd += " -i "; std::set::iterator it = this->DownloadedPackages.begin(); ifwCmd += (*it)->Name; ++it; while (it != this->DownloadedPackages.end()) { ifwCmd += "," + (*it)->Name; ++it; } } ifwCmd += " " + this->toplevel + "/repository"; cmCPackIFWLogger(VERBOSE, "Execute: " << ifwCmd << std::endl); std::string output; int retVal = 1; cmCPackIFWLogger(OUTPUT, "- Generate repository" << std::endl); bool res = cmSystemTools::RunSingleCommand( ifwCmd.c_str(), &output, &output, &retVal, nullptr, this->GeneratorVerbose, cmDuration::zero()); if (!res || retVal) { cmGeneratedFileStream ofs(ifwTmpFile.c_str()); ofs << "# Run command: " << ifwCmd << std::endl << "# Output:" << std::endl << output << std::endl; cmCPackIFWLogger(ERROR, "Problem running IFW command: " << ifwCmd << std::endl << "Please check " << ifwTmpFile << " for errors" << std::endl); return 0; } if (!this->Repository.RepositoryUpdate.empty() && !this->Repository.PatchUpdatesXml()) { cmCPackIFWLogger(WARNING, "Problem patch IFW \"Updates\" " << "file: " << this->toplevel + "/repository/Updates.xml" << std::endl); } cmCPackIFWLogger(OUTPUT, "- repository: " << this->toplevel << "/repository generated" << std::endl); } // Run binary creator { std::string ifwCmd = this->BinCreator; ifwCmd += " -c " + this->toplevel + "/config/config.xml"; if (!this->Installer.Resources.empty()) { ifwCmd += " -r "; std::vector::iterator it = this->Installer.Resources.begin(); std::string path = this->toplevel + "/resources/"; ifwCmd += path + *it; ++it; while (it != this->Installer.Resources.end()) { ifwCmd += "," + path + *it; ++it; } } ifwCmd += " -p " + this->toplevel + "/packages"; if (!this->PkgsDirsVector.empty()) { for (std::string const& it : this->PkgsDirsVector) { ifwCmd += " -p " + it; } } if (!this->RepoDirsVector.empty()) { if (!this->IsVersionLess("3.1")) { for (std::string const& rd : this->RepoDirsVector) { ifwCmd += " --repository " + rd; } } else { cmCPackIFWLogger(WARNING, "The \"CPACK_IFW_REPOSITORIES_DIRECTORIES\" " << "variable is set, but content will be skipped, " << "because this feature available only since " << "QtIFW 3.1. Please update your QtIFW instance." << std::endl); } } if (this->OnlineOnly) { ifwCmd += " --online-only"; } else if (!this->DownloadedPackages.empty() && !this->Installer.RemoteRepositories.empty()) { ifwCmd += " -e "; std::set::iterator it = this->DownloadedPackages.begin(); ifwCmd += (*it)->Name; ++it; while (it != this->DownloadedPackages.end()) { ifwCmd += "," + (*it)->Name; ++it; } } else if (!this->DependentPackages.empty()) { ifwCmd += " -i "; // Binary std::set::iterator bit = this->BinaryPackages.begin(); while (bit != this->BinaryPackages.end()) { ifwCmd += (*bit)->Name + ","; ++bit; } // Depend DependenceMap::iterator it = this->DependentPackages.begin(); ifwCmd += it->second.Name; ++it; while (it != this->DependentPackages.end()) { ifwCmd += "," + it->second.Name; ++it; } } // TODO: set correct name for multipackages if (!this->packageFileNames.empty()) { ifwCmd += " " + this->packageFileNames[0]; } else { ifwCmd += " installer"; ifwCmd += this->OutputExtension; } cmCPackIFWLogger(VERBOSE, "Execute: " << ifwCmd << std::endl); std::string output; int retVal = 1; cmCPackIFWLogger(OUTPUT, "- Generate package" << std::endl); bool res = cmSystemTools::RunSingleCommand( ifwCmd.c_str(), &output, &output, &retVal, nullptr, this->GeneratorVerbose, cmDuration::zero()); if (!res || retVal) { cmGeneratedFileStream ofs(ifwTmpFile.c_str()); ofs << "# Run command: " << ifwCmd << std::endl << "# Output:" << std::endl << output << std::endl; cmCPackIFWLogger(ERROR, "Problem running IFW command: " << ifwCmd << std::endl << "Please check " << ifwTmpFile << " for errors" << std::endl); return 0; } } return 1; } const char* cmCPackIFWGenerator::GetPackagingInstallPrefix() { const char* defPrefix = this->cmCPackGenerator::GetPackagingInstallPrefix(); std::string tmpPref = defPrefix ? defPrefix : ""; if (this->Components.empty()) { tmpPref += "packages/" + this->GetRootPackageName() + "/data"; } this->SetOption("CPACK_IFW_PACKAGING_INSTALL_PREFIX", tmpPref.c_str()); return this->GetOption("CPACK_IFW_PACKAGING_INSTALL_PREFIX"); } const char* cmCPackIFWGenerator::GetOutputExtension() { return this->OutputExtension.c_str(); } int cmCPackIFWGenerator::InitializeInternal() { // Search Qt Installer Framework tools const std::string BinCreatorOpt = "CPACK_IFW_BINARYCREATOR_EXECUTABLE"; const std::string RepoGenOpt = "CPACK_IFW_REPOGEN_EXECUTABLE"; const std::string FrameworkVersionOpt = "CPACK_IFW_FRAMEWORK_VERSION"; if (!this->IsSet(BinCreatorOpt) || !this->IsSet(RepoGenOpt) || !this->IsSet(FrameworkVersionOpt)) { this->ReadListFile("CPackIFW.cmake"); } // Look 'binarycreator' executable (needs) const char* BinCreatorStr = this->GetOption(BinCreatorOpt); if (!BinCreatorStr || cmSystemTools::IsNOTFOUND(BinCreatorStr)) { this->BinCreator.clear(); } else { this->BinCreator = BinCreatorStr; } if (this->BinCreator.empty()) { cmCPackIFWLogger(ERROR, "Cannot find QtIFW compiler \"binarycreator\": " "likely it is not installed, or not in your PATH" << std::endl); return 0; } // Look 'repogen' executable (optional) const char* RepoGenStr = this->GetOption(RepoGenOpt); if (!RepoGenStr || cmSystemTools::IsNOTFOUND(RepoGenStr)) { this->RepoGen.clear(); } else { this->RepoGen = RepoGenStr; } // Framework version if (const char* FrameworkVersionSrt = this->GetOption(FrameworkVersionOpt)) { this->FrameworkVersion = FrameworkVersionSrt; } else { this->FrameworkVersion = "1.9.9"; } // Variables that Change Behavior // Resolve duplicate names this->ResolveDuplicateNames = this->IsOn("CPACK_IFW_RESOLVE_DUPLICATE_NAMES"); // Additional packages dirs this->PkgsDirsVector.clear(); if (const char* dirs = this->GetOption("CPACK_IFW_PACKAGES_DIRECTORIES")) { cmSystemTools::ExpandListArgument(dirs, this->PkgsDirsVector); } // Additional repositories dirs this->RepoDirsVector.clear(); if (const char* dirs = this->GetOption("CPACK_IFW_REPOSITORIES_DIRECTORIES")) { cmSystemTools::ExpandListArgument(dirs, this->RepoDirsVector); } // Installer this->Installer.Generator = this; this->Installer.ConfigureFromOptions(); // Repository this->Repository.Generator = this; this->Repository.Name = "Unspecified"; if (const char* site = this->GetOption("CPACK_DOWNLOAD_SITE")) { this->Repository.Url = site; this->Installer.RemoteRepositories.push_back(&this->Repository); } // Repositories if (const char* RepoAllStr = this->GetOption("CPACK_IFW_REPOSITORIES_ALL")) { std::vector RepoAllVector; cmSystemTools::ExpandListArgument(RepoAllStr, RepoAllVector); for (std::string const& r : RepoAllVector) { this->GetRepository(r); } } if (const char* ifwDownloadAll = this->GetOption("CPACK_IFW_DOWNLOAD_ALL")) { this->OnlineOnly = cmSystemTools::IsOn(ifwDownloadAll); } else if (const char* cpackDownloadAll = this->GetOption("CPACK_DOWNLOAD_ALL")) { this->OnlineOnly = cmSystemTools::IsOn(cpackDownloadAll); } else { this->OnlineOnly = false; } if (!this->Installer.RemoteRepositories.empty() && this->RepoGen.empty()) { cmCPackIFWLogger(ERROR, "Cannot find QtIFW repository generator \"repogen\": " "likely it is not installed, or not in your PATH" << std::endl); return 0; } // Executable suffix std::string exeSuffix(this->GetOption("CMAKE_EXECUTABLE_SUFFIX")); std::string sysName(this->GetOption("CMAKE_SYSTEM_NAME")); if (sysName == "Linux") { this->ExecutableSuffix = ".run"; } else if (sysName == "Windows") { this->ExecutableSuffix = ".exe"; } else if (sysName == "Darwin") { this->ExecutableSuffix = ".app"; } else { this->ExecutableSuffix = exeSuffix; } // Output extension if (const char* optOutExt = this->GetOption("CPACK_IFW_PACKAGE_FILE_EXTENSION")) { this->OutputExtension = optOutExt; } else if (sysName == "Darwin") { this->OutputExtension = ".dmg"; } else { this->OutputExtension = this->ExecutableSuffix; } if (this->OutputExtension.empty()) { this->OutputExtension = this->cmCPackGenerator::GetOutputExtension(); } return this->Superclass::InitializeInternal(); } std::string cmCPackIFWGenerator::GetComponentInstallDirNameSuffix( const std::string& componentName) { const std::string prefix = "packages/"; const std::string suffix = "/data"; if (this->componentPackageMethod == this->ONE_PACKAGE) { return std::string(prefix + this->GetRootPackageName() + suffix); } return prefix + this->GetComponentPackageName(&this->Components[componentName]) + suffix; } cmCPackComponent* cmCPackIFWGenerator::GetComponent( const std::string& projectName, const std::string& componentName) { ComponentsMap::iterator cit = this->Components.find(componentName); if (cit != this->Components.end()) { return &(cit->second); } cmCPackComponent* component = this->cmCPackGenerator::GetComponent(projectName, componentName); if (!component) { return component; } std::string name = this->GetComponentPackageName(component); PackagesMap::iterator pit = this->Packages.find(name); if (pit != this->Packages.end()) { return component; } cmCPackIFWPackage* package = &this->Packages[name]; package->Name = name; package->Generator = this; if (package->ConfigureFromComponent(component)) { package->Installer = &this->Installer; this->Installer.Packages.insert( std::pair(name, package)); this->ComponentPackages.insert( std::pair(component, package)); if (component->IsDownloaded) { this->DownloadedPackages.insert(package); } else { this->BinaryPackages.insert(package); } } else { this->Packages.erase(name); cmCPackIFWLogger(ERROR, "Cannot configure package \"" << name << "\" for component \"" << component->Name << "\"" << std::endl); } return component; } cmCPackComponentGroup* cmCPackIFWGenerator::GetComponentGroup( const std::string& projectName, const std::string& groupName) { cmCPackComponentGroup* group = this->cmCPackGenerator::GetComponentGroup(projectName, groupName); if (!group) { return group; } std::string name = this->GetGroupPackageName(group); PackagesMap::iterator pit = this->Packages.find(name); if (pit != this->Packages.end()) { return group; } cmCPackIFWPackage* package = &this->Packages[name]; package->Name = name; package->Generator = this; if (package->ConfigureFromGroup(group)) { package->Installer = &this->Installer; this->Installer.Packages.insert( std::pair(name, package)); this->GroupPackages.insert( std::pair(group, package)); this->BinaryPackages.insert(package); } else { this->Packages.erase(name); cmCPackIFWLogger(ERROR, "Cannot configure package \"" << name << "\" for component group \"" << group->Name << "\"" << std::endl); } return group; } enum cmCPackGenerator::CPackSetDestdirSupport cmCPackIFWGenerator::SupportsSetDestdir() const { return cmCPackGenerator::SETDESTDIR_SHOULD_NOT_BE_USED; } bool cmCPackIFWGenerator::SupportsAbsoluteDestination() const { return false; } bool cmCPackIFWGenerator::SupportsComponentInstallation() const { return true; } bool cmCPackIFWGenerator::IsOnePackage() const { return this->componentPackageMethod == cmCPackGenerator::ONE_PACKAGE; } std::string cmCPackIFWGenerator::GetRootPackageName() { // Default value std::string name = "root"; if (const char* optIFW_PACKAGE_GROUP = this->GetOption("CPACK_IFW_PACKAGE_GROUP")) { // Configure from root group cmCPackIFWPackage package; package.Generator = this; package.ConfigureFromGroup(optIFW_PACKAGE_GROUP); name = package.Name; } else if (const char* optIFW_PACKAGE_NAME = this->GetOption("CPACK_IFW_PACKAGE_NAME")) { // Configure from root package name name = optIFW_PACKAGE_NAME; } else if (const char* optPACKAGE_NAME = this->GetOption("CPACK_PACKAGE_NAME")) { // Configure from package name name = optPACKAGE_NAME; } return name; } std::string cmCPackIFWGenerator::GetGroupPackageName( cmCPackComponentGroup* group) const { std::string name; if (!group) { return name; } if (cmCPackIFWPackage* package = this->GetGroupPackage(group)) { return package->Name; } const char* option = this->GetOption("CPACK_IFW_COMPONENT_GROUP_" + cmsys::SystemTools::UpperCase(group->Name) + "_NAME"); name = option ? option : group->Name; if (group->ParentGroup) { cmCPackIFWPackage* package = this->GetGroupPackage(group->ParentGroup); bool dot = !this->ResolveDuplicateNames; if (dot && name.substr(0, package->Name.size()) == package->Name) { dot = false; } if (dot) { name = package->Name + "." + name; } } return name; } std::string cmCPackIFWGenerator::GetComponentPackageName( cmCPackComponent* component) const { std::string name; if (!component) { return name; } if (cmCPackIFWPackage* package = this->GetComponentPackage(component)) { return package->Name; } std::string prefix = "CPACK_IFW_COMPONENT_" + cmsys::SystemTools::UpperCase(component->Name) + "_"; const char* option = this->GetOption(prefix + "NAME"); name = option ? option : component->Name; if (component->Group) { cmCPackIFWPackage* package = this->GetGroupPackage(component->Group); if ((this->componentPackageMethod == cmCPackGenerator::ONE_PACKAGE_PER_GROUP) || this->IsOn(prefix + "COMMON")) { return package->Name; } bool dot = !this->ResolveDuplicateNames; if (dot && name.substr(0, package->Name.size()) == package->Name) { dot = false; } if (dot) { name = package->Name + "." + name; } } return name; } cmCPackIFWPackage* cmCPackIFWGenerator::GetGroupPackage( cmCPackComponentGroup* group) const { std::map::const_iterator pit = this->GroupPackages.find(group); return pit != this->GroupPackages.end() ? pit->second : nullptr; } cmCPackIFWPackage* cmCPackIFWGenerator::GetComponentPackage( cmCPackComponent* component) const { std::map::const_iterator pit = this->ComponentPackages.find(component); return pit != this->ComponentPackages.end() ? pit->second : nullptr; } cmCPackIFWRepository* cmCPackIFWGenerator::GetRepository( const std::string& repositoryName) { RepositoriesMap::iterator rit = this->Repositories.find(repositoryName); if (rit != this->Repositories.end()) { return &(rit->second); } cmCPackIFWRepository* repository = &this->Repositories[repositoryName]; repository->Name = repositoryName; repository->Generator = this; if (repository->ConfigureFromOptions()) { if (repository->Update == cmCPackIFWRepository::None) { this->Installer.RemoteRepositories.push_back(repository); } else { this->Repository.RepositoryUpdate.push_back(repository); } } else { this->Repositories.erase(repositoryName); repository = nullptr; cmCPackIFWLogger(WARNING, "Invalid repository \"" << repositoryName << "\"" << " configuration. Repository will be skipped." << std::endl); } return repository; }