switch group/environment query to use weak pointers to data in sack

The most complex change here is the move of group/environment creation
from given query constructor to comps sack `init_comps_data()`.
This commit is contained in:
Aleš Matěj 2025-07-08 10:30:08 +02:00
parent bb05c49822
commit 3f1911df38
20 changed files with 210 additions and 210 deletions

View File

@ -41,18 +41,20 @@
%include "libdnf5/comps/group/package.hpp"
%include "libdnf5/comps/group/group.hpp"
%template(VectorPackage) std::vector<libdnf5::comps::Package>;
%template(SetConstIteratorGroup) libdnf5::SetConstIterator<libdnf5::comps::Group>;
%template(SetGroup) libdnf5::Set<libdnf5::comps::Group>;
%template(SackQueryGroup) libdnf5::sack::Query<libdnf5::comps::Group>;
%template(GroupWeakPtr) libdnf5::WeakPtr<libdnf5::comps::Group, false>;
%template(SetConstIteratorGroupWeakPtr) libdnf5::SetConstIterator<libdnf5::comps::GroupWeakPtr>;
%template(SetGroupWeakPtr) libdnf5::Set<libdnf5::comps::GroupWeakPtr>;
%template(SackQueryGroupWeakPtr) libdnf5::sack::Query<libdnf5::comps::GroupWeakPtr>;
%include "libdnf5/comps/group/query.hpp"
add_iterator(SetGroup)
add_iterator(SetGroupWeakPtr)
%include "libdnf5/comps/environment/environment.hpp"
%template(SetConstIteratorEnvironment) libdnf5::SetConstIterator<libdnf5::comps::Environment>;
%template(SetEnvironment) libdnf5::Set<libdnf5::comps::Environment>;
%template(SackQueryEnvironment) libdnf5::sack::Query<libdnf5::comps::Environment>;
%template(EnvironmentWeakPtr) libdnf5::WeakPtr<libdnf5::comps::Environment, false>;
%template(SetConstIteratorEnvironmentWeakPtr) libdnf5::SetConstIterator<libdnf5::comps::EnvironmentWeakPtr>;
%template(SetEnvironmentWeakPtr) libdnf5::Set<libdnf5::comps::EnvironmentWeakPtr>;
%template(SackQueryEnvironmentWeakPtr) libdnf5::sack::Query<libdnf5::comps::EnvironmentWeakPtr>;
%include "libdnf5/comps/environment/query.hpp"
add_iterator(SetEnvironment)
add_iterator(SetEnvironmentWeakPtr)
%include "libdnf5/comps/comps_sack.hpp"
%template(CompsSackWeakPtr) libdnf5::WeakPtr<libdnf5::comps::CompsSack, false>;

View File

@ -69,14 +69,14 @@ void EnvironmentInfoCommand::run() {
query.filter_installed(false);
}
std::vector<libdnf5::comps::Environment> environments(query.list().begin(), query.list().end());
std::vector<libdnf5::comps::EnvironmentWeakPtr> environments(query.list().begin(), query.list().end());
std::sort(
environments.begin(),
environments.end(),
libdnf5::cli::output::comps_display_order_cmp<libdnf5::comps::Environment>);
libdnf5::cli::output::comps_display_order_cmp<libdnf5::comps::EnvironmentWeakPtr>);
for (auto environment : environments) {
libdnf5::cli::output::EnvironmentAdapter cli_env(environment);
libdnf5::cli::output::EnvironmentAdapter cli_env(*environment);
libdnf5::cli::output::print_environmentinfo_table(cli_env);
std::cout << '\n';
}

View File

@ -67,15 +67,15 @@ void EnvironmentListCommand::run() {
query.filter_installed(false);
}
std::vector<libdnf5::comps::Environment> environments(query.list().begin(), query.list().end());
std::vector<libdnf5::comps::EnvironmentWeakPtr> environments(query.list().begin(), query.list().end());
std::sort(
environments.begin(),
environments.end(),
libdnf5::cli::output::comps_display_order_cmp<libdnf5::comps::Environment>);
libdnf5::cli::output::comps_display_order_cmp<libdnf5::comps::EnvironmentWeakPtr>);
std::vector<std::unique_ptr<libdnf5::cli::output::IEnvironment>> cli_envs;
for (auto & env : environments) {
cli_envs.emplace_back(new libdnf5::cli::output::EnvironmentAdapter(env));
cli_envs.emplace_back(new libdnf5::cli::output::EnvironmentAdapter(*env));
}
libdnf5::cli::output::print_environmentlist_table(cli_envs);
}

View File

@ -29,11 +29,12 @@ namespace dnf5 {
using namespace libdnf5::cli;
void GroupInfoCommand::print(const libdnf5::comps::GroupQuery & query) {
std::vector<libdnf5::comps::Group> groups(query.list().begin(), query.list().end());
std::sort(groups.begin(), groups.end(), libdnf5::cli::output::comps_display_order_cmp<libdnf5::comps::Group>);
std::vector<libdnf5::comps::GroupWeakPtr> groups(query.list().begin(), query.list().end());
std::sort(
groups.begin(), groups.end(), libdnf5::cli::output::comps_display_order_cmp<libdnf5::comps::GroupWeakPtr>);
for (auto group : groups) {
libdnf5::cli::output::GroupAdapter cli_group(group);
libdnf5::cli::output::GroupAdapter cli_group(*group);
libdnf5::cli::output::print_groupinfo_table(cli_group);
std::cout << '\n';
}

View File

@ -76,7 +76,7 @@ void GroupListCommand::run() {
query_installed.filter_installed(true);
std::vector<std::string> installed_ids;
for (const auto & grp : query_installed) {
installed_ids.emplace_back(grp.get_groupid());
installed_ids.emplace_back(grp->get_groupid());
}
libdnf5::comps::GroupQuery query_available(query);
query_available.filter_installed(false);
@ -91,13 +91,14 @@ void GroupListCommand::run() {
}
void GroupListCommand::print(const libdnf5::comps::GroupQuery & query) {
std::vector<libdnf5::comps::Group> groups(query.list().begin(), query.list().end());
std::sort(groups.begin(), groups.end(), libdnf5::cli::output::comps_display_order_cmp<libdnf5::comps::Group>);
std::vector<libdnf5::comps::GroupWeakPtr> groups(query.list().begin(), query.list().end());
std::sort(
groups.begin(), groups.end(), libdnf5::cli::output::comps_display_order_cmp<libdnf5::comps::GroupWeakPtr>);
std::vector<std::unique_ptr<libdnf5::cli::output::IGroup>> items;
items.reserve(groups.size());
for (auto & obj : groups) {
items.emplace_back(new libdnf5::cli::output::GroupAdapter(obj));
items.emplace_back(new libdnf5::cli::output::GroupAdapter(*obj));
}
libdnf5::cli::output::print_grouplist_table(items);
}

View File

@ -123,13 +123,13 @@ void SystemUpgradeDownloadCommand::run() {
libdnf5::comps::GroupQuery q_groups(ctx.get_base());
q_groups.filter_installed(true);
for (const auto & grp : q_groups) {
goal->add_group_upgrade(grp.get_groupid());
goal->add_group_upgrade(grp->get_groupid());
}
libdnf5::comps::EnvironmentQuery q_environments(ctx.get_base());
q_environments.filter_installed(true);
for (const auto & env : q_environments) {
goal->add_group_upgrade(env.get_environmentid());
goal->add_group_upgrade(env->get_environmentid());
}
ctx.set_should_store_offline(true);

View File

@ -107,7 +107,7 @@ sdbus::MethodReply Group::list(sdbus::MethodCall & call) {
query_installed.filter_installed(true);
std::vector<std::string> installed_ids;
for (const auto & grp : query_installed) {
installed_ids.emplace_back(grp.get_groupid());
installed_ids.emplace_back(grp->get_groupid());
}
libdnf5::comps::GroupQuery query_available(query);
query_available.filter_installed(false);
@ -127,7 +127,7 @@ sdbus::MethodReply Group::list(sdbus::MethodCall & call) {
std::vector<std::string> attributes =
dnfdaemon::key_value_map_get<std::vector<std::string>>(options, "attributes", std::vector<std::string>{});
for (auto grp : query.list()) {
out_groups.push_back(group_to_map(grp, attributes));
out_groups.push_back(group_to_map(*grp, attributes));
}
auto reply = call.createReply();

View File

@ -858,13 +858,13 @@ sdbus::MethodReply Rpm::system_upgrade(sdbus::MethodCall & call) {
libdnf5::comps::GroupQuery q_groups(*base);
q_groups.filter_installed(true);
for (const auto & grp : q_groups) {
goal.add_group_upgrade(grp.get_groupid());
goal.add_group_upgrade(grp->get_groupid());
}
libdnf5::comps::EnvironmentQuery q_environments(*base);
q_environments.filter_installed(true);
for (const auto & env : q_environments) {
goal.add_group_upgrade(env.get_environmentid());
goal.add_group_upgrade(env->get_environmentid());
}
auto reply = call.createReply();

View File

@ -124,7 +124,7 @@ private:
template <class T>
bool comps_display_order_cmp(T & a, T & b) {
return a.get_order_int() < b.get_order_int();
return a->get_order_int() < b->get_order_int();
}
} // namespace libdnf5::cli::output

View File

@ -45,6 +45,9 @@ public:
};
class Environment;
using EnvironmentWeakPtr = WeakPtr<Environment, false>;
// @replaces dnf:dnf/comps.py:class:Environment
class LIBDNF_API Environment {
public:
@ -147,6 +150,7 @@ protected:
private:
friend class EnvironmentQuery;
friend class CompsSack;
LIBDNF_LOCAL void add_environment_id(const EnvironmentId & environment_id);

View File

@ -33,7 +33,7 @@ along with libdnf. If not, see <https://www.gnu.org/licenses/>.
namespace libdnf5::comps {
class LIBDNF_API EnvironmentQuery : public libdnf5::sack::Query<Environment> {
class LIBDNF_API EnvironmentQuery : public libdnf5::sack::Query<EnvironmentWeakPtr> {
public:
using ExcludeFlags = libdnf5::sack::ExcludeFlags;

View File

@ -45,6 +45,8 @@ public:
int id{0};
};
class Group;
using GroupWeakPtr = WeakPtr<Group, false>;
// @replaces dnf:dnf/comps.py:class:Group
class LIBDNF_API Group {
@ -164,6 +166,7 @@ protected:
private:
friend class GroupQuery;
friend class CompsSack;
LIBDNF_LOCAL void add_group_id(const GroupId & group_id);

View File

@ -33,7 +33,7 @@ along with libdnf. If not, see <https://www.gnu.org/licenses/>.
namespace libdnf5::comps {
class LIBDNF_API GroupQuery : public libdnf5::sack::Query<Group> {
class LIBDNF_API GroupQuery : public libdnf5::sack::Query<GroupWeakPtr> {
public:
using ExcludeFlags = libdnf5::sack::ExcludeFlags;

View File

@ -1244,7 +1244,7 @@ GoalProblem Goal::Impl::resolve_group_specs(std::vector<GroupSpec> & specs, base
// We cannot simply compare the groups because they can have different libsolv ids,
// we have to compare them by groupid.
auto group_q_copy = group_q;
group_q_copy.filter_groupid(group.get_groupid());
group_q_copy.filter_groupid(group->get_groupid());
if (!group_q_copy.empty()) {
// If we have multiple different actions per group it always ends up as upgrade.
// This is because there are only 3 actions: INSTALL (together with INSTALL_BY_COMPS),
@ -2515,13 +2515,13 @@ void Goal::Impl::add_group_install_to_goal(
auto & cfg_main = base->get_config();
auto allowed_package_types = settings.resolve_group_package_types(cfg_main);
for (auto group : group_query) {
rpm_goal.add_group(group, transaction::TransactionItemAction::INSTALL, reason, allowed_package_types);
rpm_goal.add_group(*group, transaction::TransactionItemAction::INSTALL, reason, allowed_package_types);
if (settings.get_group_no_packages()) {
continue;
}
std::vector<libdnf5::comps::Package> packages;
// TODO(mblaha): filter packages by p.arch attribute when supported by comps
for (const auto & p : group.get_packages()) {
for (const auto & p : group->get_packages()) {
if (any(allowed_package_types & p.get_type())) {
packages.emplace_back(std::move(p));
}
@ -2543,7 +2543,7 @@ void Goal::Impl::add_group_remove_to_goal(
std::set<std::string> removed_groups_ids;
for (auto & [spec, reason, group_query, settings] : groups_to_remove) {
for (const auto & group : group_query) {
removed_groups_ids.emplace(group.get_groupid());
removed_groups_ids.emplace(group->get_groupid());
}
}
rpm::PackageQuery query_installed(base);
@ -2553,13 +2553,13 @@ void Goal::Impl::add_group_remove_to_goal(
rpm::PackageSet remove_candidates(base);
for (auto & [spec, reason, group_query, settings] : groups_to_remove) {
for (const auto & group : group_query) {
rpm_goal.add_group(group, transaction::TransactionItemAction::REMOVE, reason, {});
rpm_goal.add_group(*group, transaction::TransactionItemAction::REMOVE, reason, {});
if (settings.get_group_no_packages()) {
continue;
}
// get all packages installed by the group
rpm::PackageQuery group_packages(query_installed);
group_packages.filter_name(system_state.get_group_state(group.get_groupid()).packages);
group_packages.filter_name(system_state.get_group_state(group->get_groupid()).packages);
// Remove packages installed by the group.
// First collect packages that are not part of any other
// installed group and are not user-installed.
@ -2601,7 +2601,7 @@ void Goal::Impl::add_group_upgrade_to_goal(
query_installed.filter_installed();
for (auto installed_group : group_query) {
auto group_id = installed_group.get_groupid();
auto group_id = installed_group->get_groupid();
// find available group of the same id
comps::GroupQuery available_group_query(available_groups);
available_group_query.filter_groupid(group_id);
@ -2622,9 +2622,9 @@ void Goal::Impl::add_group_upgrade_to_goal(
// upgrade the group itself
rpm_goal.add_group(
available_group,
*available_group,
transaction::TransactionItemAction::UPGRADE,
installed_group.get_reason(),
installed_group->get_reason(),
state_group.package_types);
if (settings.get_group_no_packages()) {
@ -2634,17 +2634,17 @@ void Goal::Impl::add_group_upgrade_to_goal(
// set of package names that are part of the installed version of the group
std::set<std::string> old_set{};
for (const auto & pkg : installed_group.get_packages()) {
for (const auto & pkg : installed_group->get_packages()) {
old_set.emplace(pkg.get_name());
}
// set of package names that are part of the available version of the group
std::set<std::string> new_set{};
for (const auto & pkg : available_group.get_packages()) {
for (const auto & pkg : available_group->get_packages()) {
new_set.emplace(pkg.get_name());
}
// install packages newly added to the group
for (const auto & pkg : available_group.get_packages_of_type(state_group.package_types)) {
for (const auto & pkg : available_group->get_packages_of_type(state_group.package_types)) {
if (!old_set.contains(pkg.get_name())) {
install_group_package(transaction, pkg);
}
@ -2673,16 +2673,16 @@ void Goal::Impl::add_environment_install_to_goal(
group_settings.set_group_search_groups(true);
std::vector<GroupSpec> env_group_specs;
for (auto environment : environment_query) {
rpm_goal.add_environment(environment, transaction::TransactionItemAction::INSTALL, with_optional);
rpm_goal.add_environment(*environment, transaction::TransactionItemAction::INSTALL, with_optional);
if (settings.get_environment_no_groups()) {
continue;
}
for (const auto & grp_id : environment.get_groups()) {
for (const auto & grp_id : environment->get_groups()) {
env_group_specs.emplace_back(
GoalAction::INSTALL_BY_COMPS, transaction::TransactionItemReason::DEPENDENCY, grp_id, group_settings);
}
if (with_optional) {
for (const auto & grp_id : environment.get_optional_groups()) {
for (const auto & grp_id : environment->get_optional_groups()) {
env_group_specs.emplace_back(
GoalAction::INSTALL_BY_COMPS,
transaction::TransactionItemReason::DEPENDENCY,
@ -2705,7 +2705,7 @@ void Goal::Impl::add_environment_remove_to_goal(
std::set<std::string> removed_environments_ids;
for (auto & [spec, environment_query, settings] : environments_to_remove) {
for (const auto & environment : environment_query) {
removed_environments_ids.emplace(environment.get_environmentid());
removed_environments_ids.emplace(environment->get_environmentid());
}
}
comps::GroupQuery query_installed(base);
@ -2718,19 +2718,19 @@ void Goal::Impl::add_environment_remove_to_goal(
group_settings.set_group_search_groups(true);
for (auto & [spec, environment_query, settings] : environments_to_remove) {
for (const auto & environment : environment_query) {
rpm_goal.add_environment(environment, transaction::TransactionItemAction::REMOVE, {});
rpm_goal.add_environment(*environment, transaction::TransactionItemAction::REMOVE, {});
if (settings.get_environment_no_groups()) {
continue;
}
// get all groups installed by the environment
comps::GroupQuery environment_groups(query_installed);
environment_groups.filter_groupid(
system_state.get_environment_state(environment.get_environmentid()).groups);
system_state.get_environment_state(environment->get_environmentid()).groups);
// Remove groups installed by the environment in case they are installed
// as dependencies and are not part of another installed environment.
for (const auto & grp : environment_groups) {
// is the group part of another environment which is not being removed?
auto grp_environments = system_state.get_group_environments(grp.get_groupid());
auto grp_environments = system_state.get_group_environments(grp->get_groupid());
// remove from the list all environments being removed in this transaction
for (const auto & id : removed_environments_ids) {
grp_environments.erase(id);
@ -2740,14 +2740,14 @@ void Goal::Impl::add_environment_remove_to_goal(
}
// was the group user-installed?
if (grp.get_reason() > transaction::TransactionItemReason::GROUP) {
if (grp->get_reason() > transaction::TransactionItemReason::GROUP) {
continue;
}
remove_group_specs.emplace_back(
GoalAction::REMOVE,
transaction::TransactionItemReason::DEPENDENCY,
grp.get_groupid(),
grp->get_groupid(),
group_settings);
}
}
@ -2768,7 +2768,7 @@ void Goal::Impl::add_environment_upgrade_to_goal(
group_settings.set_group_search_groups(true);
for (auto installed_environment : environment_query) {
auto environment_id = installed_environment.get_environmentid();
auto environment_id = installed_environment->get_environmentid();
// find available environment of the same id
comps::EnvironmentQuery available_environment_query(available_environments);
available_environment_query.filter_environmentid(environment_id);
@ -2787,17 +2787,17 @@ void Goal::Impl::add_environment_upgrade_to_goal(
auto available_environment = available_environment_query.get();
// upgrade the environment itself
rpm_goal.add_environment(available_environment, transaction::TransactionItemAction::UPGRADE, {});
rpm_goal.add_environment(*available_environment, transaction::TransactionItemAction::UPGRADE, {});
if (settings.get_environment_no_groups()) {
continue;
}
// group names that are part of the installed version of the environment
auto old_groups = installed_environment.get_groups();
auto old_groups = installed_environment->get_groups();
// group names that are part of the new version of the environment
auto available_groups = available_environment.get_groups();
auto available_groups = available_environment->get_groups();
for (const auto & grp : available_groups) {
if (std::find(old_groups.begin(), old_groups.end(), grp) != old_groups.end()) {
@ -2818,9 +2818,9 @@ void Goal::Impl::add_environment_upgrade_to_goal(
}
// upgrade also installed optional groups
auto old_optionals = installed_environment.get_optional_groups();
auto old_optionals = installed_environment->get_optional_groups();
old_groups.insert(old_groups.end(), old_optionals.begin(), old_optionals.end());
for (const auto & grp : available_environment.get_optional_groups()) {
for (const auto & grp : available_environment->get_optional_groups()) {
available_groups.emplace_back(grp);
if (std::find(old_groups.begin(), old_groups.end(), grp) != old_groups.end()) {
try {

View File

@ -1037,7 +1037,7 @@ Transaction::TransactionRunResult Transaction::Impl::_run(
installed_query.filter_installed(true);
std::set<std::string> installed_group_ids{};
for (const auto & grp : installed_query) {
installed_group_ids.emplace(grp.get_groupid());
installed_group_ids.emplace(grp->get_groupid());
}
for (const auto & tsgrp : groups) {
if (transaction_item_action_is_inbound(tsgrp.get_action())) {

View File

@ -20,6 +20,7 @@ along with libdnf. If not, see <https://www.gnu.org/licenses/>.
#include "libdnf5/comps/comps_sack.hpp"
#include "comps_sack_impl.hpp"
#include "solv/pool.hpp"
#include "libdnf5/comps/group/query.hpp"
@ -40,14 +41,14 @@ void CompsSack::Impl::load_config_excludes() {
EnvironmentQuery query(base, EnvironmentQuery::ExcludeFlags::IGNORE_EXCLUDES);
query.filter_environmentid(name, libdnf5::sack::QueryCmp::GLOB);
for (const auto & environment : query.list()) {
config_environment_excludes.insert(environment.get_environmentid());
config_environment_excludes.insert(environment->get_environmentid());
}
}
for (const auto & name : main_config.get_excludegroups_option().get_value()) {
GroupQuery query(base, GroupQuery::ExcludeFlags::IGNORE_EXCLUDES);
query.filter_groupid(name, libdnf5::sack::QueryCmp::GLOB);
for (const auto & group : query.list()) {
config_group_excludes.insert(group.get_groupid());
config_group_excludes.insert(group->get_groupid());
}
}
}
@ -69,14 +70,14 @@ void CompsSack::Impl::add_user_environment_excludes(const std::set<std::string>
EnvironmentQuery query(base, EnvironmentQuery::ExcludeFlags::IGNORE_EXCLUDES);
query.filter_environmentid(exclude, libdnf5::sack::QueryCmp::GLOB);
for (const auto & environment : query.list()) {
user_environment_excludes.insert(environment.get_environmentid());
user_environment_excludes.insert(environment->get_environmentid());
}
}
}
void CompsSack::Impl::add_user_environment_excludes(const EnvironmentQuery & excludes) {
for (const auto & environment : excludes) {
user_environment_excludes.insert(environment.get_environmentid());
user_environment_excludes.insert(environment->get_environmentid());
}
}
@ -85,14 +86,14 @@ void CompsSack::Impl::remove_user_environment_excludes(const std::set<std::strin
EnvironmentQuery query(base, EnvironmentQuery::ExcludeFlags::IGNORE_EXCLUDES);
query.filter_environmentid(exclude, libdnf5::sack::QueryCmp::GLOB);
for (const auto & environment : query.list()) {
user_environment_excludes.erase(environment.get_environmentid());
user_environment_excludes.erase(environment->get_environmentid());
}
}
}
void CompsSack::Impl::remove_user_environment_excludes(const EnvironmentQuery & excludes) {
for (const auto & environment : excludes) {
user_environment_excludes.erase(environment.get_environmentid());
user_environment_excludes.erase(environment->get_environmentid());
}
}
@ -102,7 +103,7 @@ void CompsSack::Impl::set_user_environment_excludes(const std::set<std::string>
EnvironmentQuery query(base, EnvironmentQuery::ExcludeFlags::IGNORE_EXCLUDES);
query.filter_environmentid(exclude, libdnf5::sack::QueryCmp::GLOB);
for (const auto & environment : query.list()) {
user_environment_excludes.insert(environment.get_environmentid());
user_environment_excludes.insert(environment->get_environmentid());
}
}
}
@ -110,7 +111,7 @@ void CompsSack::Impl::set_user_environment_excludes(const std::set<std::string>
void CompsSack::Impl::set_user_environment_excludes(const EnvironmentQuery & excludes) {
user_environment_excludes = std::set<std::string>();
for (const auto & environment : excludes) {
user_environment_excludes.insert(environment.get_environmentid());
user_environment_excludes.insert(environment->get_environmentid());
}
}
@ -127,14 +128,14 @@ void CompsSack::Impl::add_user_group_excludes(const std::set<std::string> & excl
GroupQuery query(base, GroupQuery::ExcludeFlags::IGNORE_EXCLUDES);
query.filter_groupid(exclude, libdnf5::sack::QueryCmp::GLOB);
for (const auto & group : query.list()) {
user_group_excludes.insert(group.get_groupid());
user_group_excludes.insert(group->get_groupid());
}
}
}
void CompsSack::Impl::add_user_group_excludes(const GroupQuery & excludes) {
for (const auto & group : excludes) {
user_group_excludes.insert(group.get_groupid());
user_group_excludes.insert(group->get_groupid());
}
}
@ -143,14 +144,14 @@ void CompsSack::Impl::remove_user_group_excludes(const std::set<std::string> & e
GroupQuery query(base, GroupQuery::ExcludeFlags::IGNORE_EXCLUDES);
query.filter_groupid(exclude, libdnf5::sack::QueryCmp::GLOB);
for (const auto & group : query.list()) {
user_group_excludes.erase(group.get_groupid());
user_group_excludes.erase(group->get_groupid());
}
}
}
void CompsSack::Impl::remove_user_group_excludes(const GroupQuery & excludes) {
for (const auto & group : excludes) {
user_group_excludes.erase(group.get_groupid());
user_group_excludes.erase(group->get_groupid());
}
}
@ -160,7 +161,7 @@ void CompsSack::Impl::set_user_group_excludes(const std::set<std::string> & excl
GroupQuery query(base, GroupQuery::ExcludeFlags::IGNORE_EXCLUDES);
query.filter_groupid(exclude, libdnf5::sack::QueryCmp::GLOB);
for (const auto & group : query.list()) {
user_group_excludes.insert(group.get_groupid());
user_group_excludes.insert(group->get_groupid());
}
}
}
@ -168,7 +169,7 @@ void CompsSack::Impl::set_user_group_excludes(const std::set<std::string> & excl
void CompsSack::Impl::set_user_group_excludes(const GroupQuery & excludes) {
user_group_excludes = std::set<std::string>();
for (const auto & group : excludes) {
user_group_excludes.insert(group.get_groupid());
user_group_excludes.insert(group->get_groupid());
}
}
@ -242,4 +243,84 @@ void CompsSack::clear_user_group_excludes() {
p_impl->clear_user_group_excludes();
}
void CompsSack::Impl::init_comps_data() {
libdnf5::solv::CompsPool & pool = get_comps_pool(base);
if (comps_pool_cached_solvables_size == pool.get_nsolvables()) {
return;
}
group_data.clear();
environment_data.clear();
// Map of available groups/envs:
// For each groupid/envid (SOLVABLE_NAME) have a vector of (repoid, solvable_id) pairs.
// Each pair consists of one solvable_id that represents one definition of the group/env
// and repoid of its originating repository.
std::map<std::string, std::vector<std::pair<std::string_view, Id>>> group_available_map;
std::map<std::string, std::vector<std::pair<std::string_view, Id>>> env_available_map;
Id solvable_id;
Solvable * solvable;
std::pair<std::string, std::string> solvable_name_pair;
std::string_view repoid;
// Loop over all solvables
FOR_POOL_SOLVABLES(solvable_id) {
solvable = pool.id2solvable(solvable_id);
// SOLVABLE_NAME is in a form "type:id"; include only solvables of type "group" or "environment"
solvable_name_pair = solv::CompsPool::split_solvable_name(pool.lookup_str(solvable_id, SOLVABLE_NAME));
repoid = solvable->repo->name;
// Add installed groups/envs directly, because there is only one solvable for each
if (repoid == "@System") {
if (solvable_name_pair.first == "group") {
std::unique_ptr<Group> group(new Group(base));
group->add_group_id(GroupId(solvable_id));
group_data.push_back(std::move(group));
} else if (solvable_name_pair.first == "environment") {
std::unique_ptr<Environment> environment(new Environment(base));
environment->add_environment_id(EnvironmentId(solvable_id));
environment_data.push_back(std::move(environment));
}
} else {
// Create map of available groups/envs:
// for each groupid (SOLVABLE_NAME), list all corresponding solvable_ids with repoids
if (solvable_name_pair.first == "group") {
group_available_map[solvable_name_pair.second].insert(
group_available_map[solvable_name_pair.second].end(), std::make_pair(repoid, solvable_id));
} else if (solvable_name_pair.first == "environment") {
env_available_map[solvable_name_pair.second].insert(
env_available_map[solvable_name_pair.second].end(), std::make_pair(repoid, solvable_id));
}
}
}
// Create groups based on the group_available_map
for (auto & item : group_available_map) {
std::unique_ptr<Group> group(new Group(base));
// Sort the vector of (repoid, solvable_id) pairs by repoid
std::sort(item.second.begin(), item.second.end(), std::greater<>());
// Create group_ids vector from the sorted solvable_ids
for (const auto & solvableid_repoid_pair : item.second) {
group->add_group_id(GroupId(solvableid_repoid_pair.second));
}
group_data.push_back(std::move(group));
}
// Create envs based on the env_available_map
for (auto & item : env_available_map) {
std::unique_ptr<Environment> environment(new Environment(base));
// Sort the vector of (repoid, solvable_id) pairs by repoid
std::sort(item.second.begin(), item.second.end(), std::greater<>());
// Create environment_ids vector from the sorted solvable_ids
for (const auto & solvableid_repoid_pair : item.second) {
environment->add_environment_id(EnvironmentId(solvableid_repoid_pair.second));
}
environment_data.push_back(std::move(environment));
}
comps_pool_cached_solvables_size = pool.get_nsolvables();
}
} // namespace libdnf5::comps

View File

@ -27,7 +27,6 @@ along with libdnf. If not, see <https://www.gnu.org/licenses/>.
namespace libdnf5::comps {
class CompsSack::Impl {
public:
explicit Impl(const BaseWeakPtr & base) : base(base) {}
@ -59,8 +58,13 @@ public:
void set_user_group_excludes(const GroupQuery & excludes);
void clear_user_group_excludes();
// Loads groups and environments into group_data and environment_data
void init_comps_data();
private:
friend comps::CompsSack;
friend comps::GroupQuery;
friend comps::EnvironmentQuery;
BaseWeakPtr base;
WeakPtrGuard<comps::CompsSack, false> sack_guard;
@ -69,6 +73,15 @@ private:
std::set<std::string> config_group_excludes; // groups explicitly excluded by config
std::set<std::string> user_environment_excludes; // environments explicitly excluded by API user
std::set<std::string> user_group_excludes; // groups explicitly excluded by API user
WeakPtrGuard<comps::Group, false> group_data_guard;
std::vector<std::unique_ptr<comps::Group>> group_data;
WeakPtrGuard<comps::Environment, false> environment_data_guard;
std::vector<std::unique_ptr<comps::Environment>> environment_data;
// Number of solvables in the comps pool when the
// group/environment_data vectors were initialized.
int comps_pool_cached_solvables_size{0};
};

View File

@ -19,6 +19,7 @@ along with libdnf. If not, see <https://www.gnu.org/licenses/>.
#include "libdnf5/comps/environment/query.hpp"
#include "../comps_sack_impl.hpp"
#include "solv/pool.hpp"
#include "libdnf5/base/base.hpp"
@ -47,9 +48,9 @@ private:
friend EnvironmentQuery;
struct F {
static std::string environmentid(const Environment & obj) { return obj.get_environmentid(); }
static std::string name(const Environment & obj) { return obj.get_name(); }
static bool is_installed(const Environment & obj) { return obj.get_installed(); }
static std::string environmentid(const EnvironmentWeakPtr & obj) { return obj->get_environmentid(); }
static std::string name(const EnvironmentWeakPtr & obj) { return obj->get_name(); }
static bool is_installed(const EnvironmentWeakPtr & obj) { return obj->get_installed(); }
};
libdnf5::BaseWeakPtr base;
@ -61,74 +62,21 @@ EnvironmentQuery::EnvironmentQuery(const BaseWeakPtr & base, ExcludeFlags flags,
return;
}
libdnf5::solv::CompsPool & pool = get_comps_pool(base);
auto sack = base->get_comps_sack();
// Map of available environments:
// For each environmentid (SOLVABLE_NAME) have a vector of (repoid, solvable_id) pairs.
// Each pair consists of one solvable_id that represents one definition of the environment
// and repoid of its originating repository.
std::map<std::string, std::vector<std::pair<std::string_view, Id>>> available_map;
Id solvable_id;
Solvable * solvable;
std::pair<std::string, std::string> solvable_name_pair;
std::string_view repoid;
std::set<std::string> config_excludes = sack->get_config_environment_excludes();
std::set<std::string> user_excludes = sack->get_user_environment_excludes();
// Loop over all solvables
FOR_POOL_SOLVABLES(solvable_id) {
solvable = pool.id2solvable(solvable_id);
// Do not include solvables from disabled repositories (unless ExcludeFlags::USE_DISABLED_REPOSITORIES).
// TODO(pkratoch): Test this works
if (solvable->repo->disabled &&
!static_cast<bool>(flags & libdnf5::sack::ExcludeFlags::USE_DISABLED_REPOSITORIES)) {
continue;
}
// SOLVABLE_NAME is in a form "type:id"; include only solvables of type "environment"
solvable_name_pair = solv::CompsPool::split_solvable_name(pool.lookup_str(solvable_id, SOLVABLE_NAME));
if (solvable_name_pair.first != "environment") {
continue;
}
sack->p_impl->init_comps_data();
for (auto & it : sack->p_impl->environment_data) {
// Check config excludes
if (!static_cast<bool>(flags & libdnf5::sack::ExcludeFlags::IGNORE_REGULAR_CONFIG_EXCLUDES) &&
config_excludes.contains(solvable_name_pair.second)) {
sack->p_impl->get_config_environment_excludes().contains(it->get_environmentid())) {
continue;
}
// Check user excludes
if (!static_cast<bool>(flags & libdnf5::sack::ExcludeFlags::IGNORE_REGULAR_USER_EXCLUDES) &&
user_excludes.contains(solvable_name_pair.second)) {
sack->p_impl->get_user_environment_excludes().contains(it->get_environmentid())) {
continue;
}
repoid = solvable->repo->name;
// Add installed environments directly, because there is only one solvable for each
if (repoid == "@System") {
Environment environment(base);
environment.add_environment_id(EnvironmentId(solvable_id));
add(environment);
} else {
// Create map of available environments:
// for each environmentid (SOLVABLE_NAME), list all corresponding solvable_ids with repoids
available_map[solvable_name_pair.second].insert(
available_map[solvable_name_pair.second].end(), std::make_pair(repoid, solvable_id));
}
}
// Create environments based on the available_map
for (auto & item : available_map) {
Environment environment(base);
// Sort the vector of (repoid, solvable_id) pairs by repoid
std::sort(item.second.begin(), item.second.end(), std::greater<>());
// Create environment_ids vector from the sorted solvable_ids
for (const auto & solvableid_repoid_pair : item.second) {
environment.add_environment_id(EnvironmentId(solvableid_repoid_pair.second));
}
add(environment);
add({it.get(), &sack->p_impl->environment_data_guard});
}
}
@ -143,12 +91,12 @@ EnvironmentQuery::EnvironmentQuery(Base & base, ExcludeFlags flags, bool empty)
EnvironmentQuery::~EnvironmentQuery() = default;
EnvironmentQuery::EnvironmentQuery(const EnvironmentQuery & src)
: libdnf5::sack::Query<Environment>(src),
: libdnf5::sack::Query<EnvironmentWeakPtr>(src),
p_impl(new Impl(*src.p_impl)) {}
EnvironmentQuery::EnvironmentQuery(EnvironmentQuery && src) noexcept = default;
EnvironmentQuery & EnvironmentQuery::operator=(const EnvironmentQuery & src) {
libdnf5::sack::Query<Environment>::operator=(src);
libdnf5::sack::Query<EnvironmentWeakPtr>::operator=(src);
if (this != &src) {
if (p_impl) {
*p_impl = *src.p_impl;

View File

@ -19,6 +19,7 @@ along with libdnf. If not, see <https://www.gnu.org/licenses/>.
#include "libdnf5/comps/group/query.hpp"
#include "../comps_sack_impl.hpp"
#include "solv/pool.hpp"
#include "libdnf5/base/base.hpp"
@ -47,11 +48,11 @@ private:
friend GroupQuery;
struct F {
static std::string groupid(const Group & obj) { return obj.get_groupid(); }
static std::string name(const Group & obj) { return obj.get_name(); }
static bool is_uservisible(const Group & obj) { return obj.get_uservisible(); }
static bool is_default(const Group & obj) { return obj.get_default(); }
static bool is_installed(const Group & obj) { return obj.get_installed(); }
static std::string groupid(const GroupWeakPtr & obj) { return obj->get_groupid(); }
static std::string name(const GroupWeakPtr & obj) { return obj->get_name(); }
static bool is_uservisible(const GroupWeakPtr & obj) { return obj->get_uservisible(); }
static bool is_default(const GroupWeakPtr & obj) { return obj->get_default(); }
static bool is_installed(const GroupWeakPtr & obj) { return obj->get_installed(); }
};
libdnf5::BaseWeakPtr base;
@ -63,74 +64,21 @@ GroupQuery::GroupQuery(const BaseWeakPtr & base, ExcludeFlags flags, bool empty)
return;
}
libdnf5::solv::CompsPool & pool = get_comps_pool(base);
auto sack = base->get_comps_sack();
// Map of available groups:
// For each groupid (SOLVABLE_NAME) have a vector of (repoid, solvable_id) pairs.
// Each pair consists of one solvable_id that represents one definition of the group
// and repoid of its originating repository.
std::map<std::string, std::vector<std::pair<std::string_view, Id>>> available_map;
Id solvable_id;
Solvable * solvable;
std::pair<std::string, std::string> solvable_name_pair;
std::string_view repoid;
std::set<std::string> config_excludes = sack->get_config_group_excludes();
std::set<std::string> user_excludes = sack->get_user_group_excludes();
// Loop over all solvables
FOR_POOL_SOLVABLES(solvable_id) {
solvable = pool.id2solvable(solvable_id);
// Do not include solvables from disabled repositories (unless ExcludeFlags::USE_DISABLED_REPOSITORIES).
// TODO(pkratoch): Test this works
if (solvable->repo->disabled &&
!static_cast<bool>(flags & libdnf5::sack::ExcludeFlags::USE_DISABLED_REPOSITORIES)) {
continue;
}
// SOLVABLE_NAME is in a form "type:id"; include only solvables of type "group"
solvable_name_pair = solv::CompsPool::split_solvable_name(pool.lookup_str(solvable_id, SOLVABLE_NAME));
if (solvable_name_pair.first != "group") {
continue;
}
sack->p_impl->init_comps_data();
for (auto & it : sack->p_impl->group_data) {
// Check config excludes
if (!static_cast<bool>(flags & libdnf5::sack::ExcludeFlags::IGNORE_REGULAR_CONFIG_EXCLUDES) &&
config_excludes.contains(solvable_name_pair.second)) {
sack->p_impl->get_config_group_excludes().contains(it->get_groupid())) {
continue;
}
// Check user excludes
if (!static_cast<bool>(flags & libdnf5::sack::ExcludeFlags::IGNORE_REGULAR_USER_EXCLUDES) &&
user_excludes.contains(solvable_name_pair.second)) {
sack->p_impl->get_user_group_excludes().contains(it->get_groupid())) {
continue;
}
repoid = solvable->repo->name;
// Add installed groups directly, because there is only one solvable for each
if (repoid == "@System") {
Group group(base);
group.add_group_id(GroupId(solvable_id));
add(group);
} else {
// Create map of available groups:
// for each groupid (SOLVABLE_NAME), list all corresponding solvable_ids with repoids
available_map[solvable_name_pair.second].insert(
available_map[solvable_name_pair.second].end(), std::make_pair(repoid, solvable_id));
}
}
// Create groups based on the available_map
for (auto & item : available_map) {
Group group(base);
// Sort the vector of (repoid, solvable_id) pairs by repoid
std::sort(item.second.begin(), item.second.end(), std::greater<>());
// Create group_ids vector from the sorted solvable_ids
for (const auto & solvableid_repoid_pair : item.second) {
group.add_group_id(GroupId(solvableid_repoid_pair.second));
}
add(group);
add({it.get(), &sack->p_impl->group_data_guard});
}
}
@ -142,11 +90,13 @@ GroupQuery::GroupQuery(libdnf5::Base & base, ExcludeFlags flags, bool empty)
GroupQuery::~GroupQuery() = default;
GroupQuery::GroupQuery(const GroupQuery & src) : libdnf5::sack::Query<Group>(src), p_impl(new Impl(*src.p_impl)) {}
GroupQuery::GroupQuery(const GroupQuery & src)
: libdnf5::sack::Query<GroupWeakPtr>(src),
p_impl(new Impl(*src.p_impl)) {}
GroupQuery::GroupQuery(GroupQuery && src) noexcept = default;
GroupQuery & GroupQuery::operator=(const GroupQuery & src) {
libdnf5::sack::Query<Group>::operator=(src);
libdnf5::sack::Query<GroupWeakPtr>::operator=(src);
if (this != &src) {
if (p_impl) {
*p_impl = *src.p_impl;
@ -167,9 +117,9 @@ void GroupQuery::filter_package_name(const std::vector<std::string> & patterns,
for (auto it = get_data().begin(); it != get_data().end();) {
// Copy group so we can call `get_packages()`, this is needed because `it` is from a std::set and thus const
// but `get_packages()` modifies its group (it stores cache of its packages).
Group group = *it;
GroupWeakPtr group = *it;
bool keep = std::ranges::any_of(
group.get_packages(), [&](const auto & pkg) { return match_string(pkg.get_name(), cmp, patterns); });
group->get_packages(), [&](const auto & pkg) { return match_string(pkg.get_name(), cmp, patterns); });
if (keep) {
++it;
} else {

View File

@ -943,17 +943,14 @@ void RepoSack::Impl::fix_group_missing_xml() {
libdnf5::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.
libdnf5::comps::Group group = group_query.get();
auto & 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);
group->serialize(xml_file_name);
xml_saved = true;
} catch (utils::xml::XMLSaveError & ex) {
logger.debug(ex.what());
@ -979,14 +976,14 @@ void RepoSack::Impl::fix_group_missing_xml() {
libdnf5::comps::EnvironmentQuery environment_query(available_environments);
environment_query.filter_environmentid(environment_id);
if (environment_query.size() == 1) {
libdnf5::comps::Environment environment = environment_query.get();
auto & environment = environment_query.get();
auto xml_file_name = comps_xml_dir / (environment_id + ".xml");
logger.debug(
"Re-creating installed environmental group \"{}\" definition to file \"{}\".",
environment_id,
xml_file_name.string());
try {
environment.serialize(xml_file_name);
environment->serialize(xml_file_name);
xml_saved = true;
} catch (utils::xml::XMLSaveError & ex) {
logger.debug(ex.what());