From 0cc48ce1a91e04d32503852e8fcd9842a8fc6b55 Mon Sep 17 00:00:00 2001 From: Marek Blaha Date: Fri, 31 Mar 2023 10:26:07 +0200 Subject: [PATCH] repo_sack: Fix missing xml files for installed groups In case the xml definition for an installed group does not exist, try to re-create it from available repositories, with fall-back to creating minimal group solvable using only data available in system state. --- include/libdnf/base/base.hpp | 1 + include/libdnf/repo/repo_sack.hpp | 9 ++++- libdnf/repo/repo_sack.cpp | 62 +++++++++++++++++++++++++++++++ 3 files changed, 71 insertions(+), 1 deletion(-) diff --git a/include/libdnf/base/base.hpp b/include/libdnf/base/base.hpp index 3caff9a09..dd175544e 100644 --- a/include/libdnf/base/base.hpp +++ b/include/libdnf/base/base.hpp @@ -118,6 +118,7 @@ class Base { friend class libdnf::rpm::Package; friend class libdnf::advisory::AdvisoryQuery; friend class libdnf::module::ModuleSack; + friend class libdnf::repo::RepoSack; friend class libdnf::repo::SolvRepo; /// Loads the default configuration. To load distribution-specific configuration. diff --git a/include/libdnf/repo/repo_sack.hpp b/include/libdnf/repo/repo_sack.hpp index 73ae3d932..00d0f4a64 100644 --- a/include/libdnf/repo/repo_sack.hpp +++ b/include/libdnf/repo/repo_sack.hpp @@ -127,11 +127,18 @@ class RepoSack : public sack::Sack { /// @return The `Base` object to which this object belongs. /// @since 5.0 libdnf::BaseWeakPtr get_base() const; - // + /// For each enabled repository enable corresponding source repository. /// @since 5.0 void enable_source_repos(); + /// Re-create missing xml definitions for installed groups. Since we do not have + /// the state of the group in time of installation, current definition from + /// available repositories is going to be used. + /// In case the repo does not exist in repositories, only the minimal solvables + /// are created from info in system state. + void fix_group_missing_xml(); + private: friend class libdnf::Base; friend class RepoQuery; diff --git a/libdnf/repo/repo_sack.cpp b/libdnf/repo/repo_sack.cpp index 3f6272cf2..cc1b51890 100644 --- a/libdnf/repo/repo_sack.cpp +++ b/libdnf/repo/repo_sack.cpp @@ -24,14 +24,17 @@ along with libdnf. If not, see . #include "repo_downloader.hpp" #include "rpm/package_sack_impl.hpp" #include "solv/solver.hpp" +#include "solv_repo.hpp" #include "utils/bgettext/bgettext-mark-domain.h" #include "utils/fs/file.hpp" #include "utils/fs/temp.hpp" #include "utils/string.hpp" #include "utils/url.hpp" +#include "utils/xml.hpp" #include "libdnf/base/base.hpp" #include "libdnf/common/exception.hpp" +#include "libdnf/comps/group/query.hpp" #include "libdnf/conf/config_parser.hpp" #include "libdnf/conf/option_bool.hpp" #include "libdnf/repo/file_downloader.hpp" @@ -453,6 +456,8 @@ void RepoSack::update_and_load_repos(libdnf::repo::RepoQuery & repos, bool impor finish_sack_loader(); catch_thread_sack_loader_exceptions(); + fix_group_missing_xml(); + base->get_rpm_package_sack()->load_config_excludes_includes(); } @@ -588,4 +593,61 @@ void RepoSack::internalize_repos() { } } +void RepoSack::fix_group_missing_xml() { + if (has_system_repo()) { + auto & solv_repo = system_repo->solv_repo; + auto & group_missing_xml = solv_repo->get_groups_missing_xml(); + if (group_missing_xml.empty()) { + return; + } + auto & logger = *base->get_logger(); + auto & system_state = base->p_impl->get_system_state(); + auto comps_xml_dir = system_state.get_group_xml_dir(); + bool directory_exists = true; + std::error_code ec; + std::filesystem::create_directories(comps_xml_dir, ec); + if (ec) { + logger.debug("Failed to create directory \"{}\": {}", comps_xml_dir.string(), ec.message()); + directory_exists = false; + } + libdnf::comps::GroupQuery available_groups(base); + available_groups.filter_installed(false); + for (const auto & group_id : group_missing_xml) { + bool xml_saved = false; + if (directory_exists) { + // try to find the repoid in availables + libdnf::comps::GroupQuery group_query(available_groups); + group_query.filter_groupid(group_id); + if (group_query.size() == 1) { + // GroupQuery is basically a set thus iterators and `.get()` method + // return `const Group` objects. + // To call non-const serialize method we need to make a copy here. + libdnf::comps::Group group = group_query.get(); + auto xml_file_name = comps_xml_dir / (group_id + ".xml"); + logger.debug( + "Re-creating installed group \"{}\" definition to file \"{}\".", + group_id, + xml_file_name.string()); + try { + group.serialize(xml_file_name); + xml_saved = true; + } catch (utils::xml::XMLSaveError & ex) { + logger.debug(ex.what()); + } + if (xml_saved) { + solv_repo->read_group_solvable_from_xml(xml_file_name); + } + } + } + if (!xml_saved) { + // fall-back to creating solvables only from system state + solv_repo->create_group_solvable(group_id, system_state.get_group_state(group_id)); + } + } + + // ensure we attempt to re-create xmls only once + group_missing_xml.clear(); + } +} + } // namespace libdnf::repo