Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

TransactionReplay: handle group package types #1569

Merged
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
6 changes: 3 additions & 3 deletions doc/dnf5.conf.5.rst
Original file line number Diff line number Diff line change
Expand Up @@ -172,11 +172,11 @@ repository configuration file should aside from repo ID consists of baseurl, met
``group_package_types``
:ref:`list <list-label>`

List of the following: ``optional``, ``default``, ``mandatory``.
List of the following: ``optional``, ``default``, ``mandatory`` or ``conditional``.

Tells DNF5 which type of packages in groups will be installed when 'groupinstall' is called.
Tells DNF5 which type of packages in groups will be installed when 'group install' is called.

Default: ``default,mandatory``.
Default: ``default, mandatory, conditional``.

.. _ignorearch_options-label:

Expand Down
8 changes: 4 additions & 4 deletions libdnf5/base/goal.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -1012,6 +1012,7 @@ GoalProblem Goal::Impl::add_replay_to_goal(
for (const auto & group_replay : replay.groups) {
libdnf5::GoalJobSettings settings_per_group = settings;
settings_per_group.set_group_no_packages(true);
settings_per_group.set_group_package_types(group_replay.package_types);
settings_per_group.set_group_search_groups(true);
settings_per_group.set_group_search_environments(false);
if (!group_replay.repo_id.empty()) {
Expand Down Expand Up @@ -2469,8 +2470,6 @@ void Goal::Impl::add_group_remove_to_goal(
void Goal::Impl::add_group_upgrade_to_goal(
base::Transaction & transaction, comps::GroupQuery group_query, GoalJobSettings & settings) {
auto & system_state = base->p_impl->get_system_state();
auto & cfg_main = base->get_config();
auto allowed_package_types = settings.resolve_group_package_types(cfg_main);

comps::GroupQuery available_groups(base);
available_groups.filter_installed(false);
Expand All @@ -2497,18 +2496,19 @@ void Goal::Impl::add_group_upgrade_to_goal(
continue;
}
auto available_group = available_group_query.get();
auto state_group = system_state.get_group_state(group_id);

// upgrade the group itself
rpm_goal.add_group(
available_group,
transaction::TransactionItemAction::UPGRADE,
installed_group.get_reason(),
allowed_package_types);
state_group.package_types);

if (settings.get_group_no_packages()) {
continue;
}

auto state_group = system_state.get_group_state(group_id);

// set of package names that are part of the installed version of the group
std::set<std::string> old_set{};
Expand Down
1 change: 1 addition & 0 deletions libdnf5/base/transaction.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -1458,6 +1458,7 @@ std::string Transaction::serialize(
group_replay.reason = group.get_reason();
// TODO(amatej): does each group has to have at least one repo?
group_replay.repo_id = *(group.get_group().get_repos().begin());
group_replay.package_types = group.get_package_types();

if (!comps_path.empty()) {
group_replay.group_path = build_comps_xml_path(comps_path, xml_group.get_groupid());
Expand Down
1 change: 1 addition & 0 deletions libdnf5/transaction/transaction.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -350,6 +350,7 @@ std::string Transaction::serialize() {
group_replay.action = group.get_action();
group_replay.reason = group.get_reason();
group_replay.repo_id = group.get_repoid();
group_replay.package_types = group.get_package_types();

transaction_replay.groups.push_back(group_replay);
}
Expand Down
48 changes: 32 additions & 16 deletions libdnf5/transaction/transaction_sr.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -78,10 +78,10 @@ TransactionReplay parse_transaction_replay(const std::string & json_serialized_t
if (std::find_if(versions[1].begin(), versions[1].end(), [](unsigned char c) {
return std::isdigit(c) == 0;
}) != versions[1].end()) {
throw TransactionReplayError(M_("Invalid minor version: \"{}\", number expected."), versions[1]);
throw TransactionReplayError(M_("Invalid minor version: \"{}\", number expected"), versions[1]);
}
} else {
throw TransactionReplayError(M_("Missing key \"version\"."));
throw TransactionReplayError(M_("Missing key \"version\""));
}


Expand All @@ -94,20 +94,20 @@ TransactionReplay parse_transaction_replay(const std::string & json_serialized_t
std::string repo_id;

if (json_object_is_type(json_environments, json_type_array) == 0) {
throw TransactionReplayError(M_("Unexpected type of \"environments\", array expected."));
throw TransactionReplayError(M_("Unexpected type of \"environments\", array expected"));
}

for (std::size_t i = 0; i < json_object_array_length(json_environments); ++i) {
struct json_object * environment = json_object_array_get_idx(json_environments, i);
if (json_object_object_get_ex(environment, "id", &value) != 0) {
environment_id = json_object_get_string(value);
} else {
throw TransactionReplayError(M_("Missing object key \"id\" in an environment."));
throw TransactionReplayError(M_("Missing object key \"id\" in an environment"));
}
if (json_object_object_get_ex(environment, "action", &value) != 0) {
action = json_object_get_string(value);
} else {
throw TransactionReplayError(M_("Missing object key \"action\" in an environment."));
throw TransactionReplayError(M_("Missing object key \"action\" in an environment"));
}
if (json_object_object_get_ex(environment, "environment_path", &value) != 0) {
environment_path = json_object_get_string(value);
Expand All @@ -130,41 +130,52 @@ TransactionReplay parse_transaction_replay(const std::string & json_serialized_t
std::string reason;
std::string group_path;
std::string repo_id;
std::string joined_package_types;
comps::PackageType package_types;

if (json_object_is_type(json_groups, json_type_array) == 0) {
throw TransactionReplayError(M_("Unexpected type of \"groups\", array expected."));
throw TransactionReplayError(M_("Unexpected type of \"groups\", array expected"));
}

for (std::size_t i = 0; i < json_object_array_length(json_groups); ++i) {
struct json_object * group = json_object_array_get_idx(json_groups, i);
if (json_object_object_get_ex(group, "id", &value) != 0) {
group_id = json_object_get_string(value);
} else {
throw TransactionReplayError(M_("Missing object key \"id\" in a group."));
throw TransactionReplayError(M_("Missing object key \"id\" in a group"));
}
if (json_object_object_get_ex(group, "action", &value) != 0) {
action = json_object_get_string(value);
} else {
throw TransactionReplayError(M_("Missing object key \"action\" in a group."));
throw TransactionReplayError(M_("Missing object key \"action\" in a group"));
}
if (json_object_object_get_ex(group, "reason", &value) != 0) {
reason = json_object_get_string(value);
} else {
throw TransactionReplayError(M_("Missing object key \"reason\" in a group."));
throw TransactionReplayError(M_("Missing object key \"reason\" in a group"));
}
if (json_object_object_get_ex(group, "group_path", &value) != 0) {
group_path = json_object_get_string(value);
}
if (json_object_object_get_ex(group, "repo_id", &value) != 0) {
repo_id = json_object_get_string(value);
}
if (json_object_object_get_ex(group, "package_types", &value) != 0) {
joined_package_types = json_object_get_string(value);
auto package_types_vec = libdnf5::utils::string::split(joined_package_types, ",");
std::for_each(package_types_vec.begin(), package_types_vec.end(), libdnf5::utils::string::trim);
package_types = comps::package_type_from_string(package_types_vec);
} else {
package_types = comps::PackageType();
}

transaction_replay.groups.push_back(
{transaction_item_action_from_string(action),
transaction_item_reason_from_string(reason),
group_id,
group_path,
repo_id});
repo_id,
package_types});
}
}

Expand All @@ -179,7 +190,7 @@ TransactionReplay parse_transaction_replay(const std::string & json_serialized_t
std::string package_path;

if (json_object_is_type(json_packages, json_type_array) == 0) {
throw TransactionReplayError(M_("Unexpected type of \"rpms\", array expected."));
throw TransactionReplayError(M_("Unexpected type of \"rpms\", array expected"));
}

for (std::size_t i = 0; i < json_object_array_length(json_packages); ++i) {
Expand All @@ -188,33 +199,33 @@ TransactionReplay parse_transaction_replay(const std::string & json_serialized_t
nevra = json_object_get_string(value);
// Verify we have a full nevra
if (libdnf5::rpm::Nevra::parse(nevra, {libdnf5::rpm::Nevra::Form::NEVRA}).empty()) {
throw TransactionReplayError(M_("Cannot parse NEVRA for rpm \"{}\"."), nevra);
throw TransactionReplayError(M_("Cannot parse NEVRA for rpm \"{}\""), nevra);
}
}
if (json_object_object_get_ex(package, "package_path", &value) != 0) {
package_path = json_object_get_string(value);
}
if (nevra.empty() && package_path.empty()) {
throw TransactionReplayError(
M_("Either \"nevra\" or \"package_path\" object key is required in an rpm."));
M_("Either \"nevra\" or \"package_path\" object key is required in an rpm"));
}
if (json_object_object_get_ex(package, "action", &value) != 0) {
action = json_object_get_string(value);
} else {
throw TransactionReplayError(M_("Missing object key \"action\" in an rpm."));
throw TransactionReplayError(M_("Missing object key \"action\" in an rpm"));
}
if (json_object_object_get_ex(package, "reason", &value) != 0) {
reason = json_object_get_string(value);
} else {
throw TransactionReplayError(M_("Missing object key \"reason\" in an rpm."));
throw TransactionReplayError(M_("Missing object key \"reason\" in an rpm"));
}
if (json_object_object_get_ex(package, "group_id", &value) != 0) {
group_id = json_object_get_string(value);
} else {
if (reason == "Group" && action == "Reason Change") {
throw TransactionReplayError(
M_("Missing mandatory object key \"group_id\" in an rpm with reason \"Group\" and action "
"\"Reason Change\"."));
"\"Reason Change\""));
}
}
if (json_object_object_get_ex(package, "repo_id", &value) != 0) {
Expand Down Expand Up @@ -282,6 +293,11 @@ std::string json_serialize(const TransactionReplay & transaction_replay) {
json_object_object_add(json_group, "group_path", json_object_new_string(group.group_path.c_str()));
}
json_object_object_add(json_group, "repo_id", json_object_new_string(group.repo_id.c_str()));
json_object_object_add(
json_group,
"package_types",
json_object_new_string(
libdnf5::utils::string::join(package_types_to_strings(group.package_types), ", ").c_str()));
json_object_array_add(json_groups, json_group);
}
json_object_object_add(root, "groups", json_groups);
Expand Down
1 change: 1 addition & 0 deletions libdnf5/transaction/transaction_sr.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -44,6 +44,7 @@ struct GroupReplay {
// Path to serialized comps group relative to the transaction json file
std::filesystem::path group_path;
std::string repo_id;
libdnf5::comps::PackageType package_types;
};

struct EnvironmentReplay {
Expand Down
71 changes: 62 additions & 9 deletions test/libdnf5/transaction/test_transaction_merge.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -47,6 +47,7 @@ static void add_transaction_item_group(
group_replay.action = action;
group_replay.reason = TransactionItemReason::USER;
group_replay.group_id = id;
group_replay.package_types = libdnf5::comps::PackageType::DEFAULT;
trans.groups.push_back(group_replay);
}

Expand Down Expand Up @@ -96,7 +97,12 @@ void TransactionMergeTest::only_one_transaction() {
{TransactionItemAction::INSTALL, TransactionItemReason::USER, "", "bash-4-1.x86_64", "", ""}};
CPPUNIT_ASSERT_EQUAL(expected, replay.packages);
std::vector<GroupReplay> expected_groups = {
{TransactionItemAction::INSTALL, TransactionItemReason::USER, "vlc", "", ""}};
{TransactionItemAction::INSTALL,
TransactionItemReason::USER,
"vlc",
"",
"",
libdnf5::comps::PackageType::DEFAULT}};
CPPUNIT_ASSERT_EQUAL(expected_groups, replay.groups);
std::vector<EnvironmentReplay> expected_envs = {
{TransactionItemAction::INSTALL, "basic-desktop-environment", "", ""}};
Expand Down Expand Up @@ -124,7 +130,12 @@ void TransactionMergeTest::two_disjoint() {
{TransactionItemAction::INSTALL, TransactionItemReason::USER, "", "bash-4-1.x86_64", "", ""}};
CPPUNIT_ASSERT_EQUAL(expected, replay.packages);
std::vector<GroupReplay> expected_groups = {
{TransactionItemAction::INSTALL, TransactionItemReason::USER, "vlc", "", ""}};
{TransactionItemAction::INSTALL,
TransactionItemReason::USER,
"vlc",
"",
"",
libdnf5::comps::PackageType::DEFAULT}};
CPPUNIT_ASSERT_EQUAL(expected_groups, replay.groups);
std::vector<EnvironmentReplay> expected_envs = {
{TransactionItemAction::INSTALL, "basic-desktop-environment", "", ""}};
Expand Down Expand Up @@ -1374,7 +1385,13 @@ void TransactionMergeTest::group_install_install() {

auto [replay, problems] = libdnf5::transaction::merge_transactions({trans1, trans2}, na_to_installed_nevras);

std::vector<GroupReplay> expected = {{TransactionItemAction::INSTALL, TransactionItemReason::USER, "vlc", "", ""}};
std::vector<GroupReplay> expected = {
{TransactionItemAction::INSTALL,
TransactionItemReason::USER,
"vlc",
"",
"",
libdnf5::comps::PackageType::DEFAULT}};
CPPUNIT_ASSERT_EQUAL(expected, replay.groups);
CPPUNIT_ASSERT_EQUAL(std::vector<std::string>(), problems);
}
Expand All @@ -1389,7 +1406,13 @@ void TransactionMergeTest::group_install_upgrade() {

auto [replay, problems] = libdnf5::transaction::merge_transactions({trans1, trans2}, na_to_installed_nevras);

std::vector<GroupReplay> expected = {{TransactionItemAction::INSTALL, TransactionItemReason::USER, "vlc", "", ""}};
std::vector<GroupReplay> expected = {
{TransactionItemAction::INSTALL,
TransactionItemReason::USER,
"vlc",
"",
"",
libdnf5::comps::PackageType::DEFAULT}};
CPPUNIT_ASSERT_EQUAL(expected, replay.groups);
CPPUNIT_ASSERT_EQUAL(std::vector<std::string>(), problems);
}
Expand Down Expand Up @@ -1419,7 +1442,13 @@ void TransactionMergeTest::group_remove_upgrade() {

auto [replay, problems] = libdnf5::transaction::merge_transactions({trans1, trans2}, na_to_installed_nevras);

std::vector<GroupReplay> expected = {{TransactionItemAction::INSTALL, TransactionItemReason::USER, "vlc", "", ""}};
std::vector<GroupReplay> expected = {
{TransactionItemAction::INSTALL,
TransactionItemReason::USER,
"vlc",
"",
"",
libdnf5::comps::PackageType::DEFAULT}};
CPPUNIT_ASSERT_EQUAL(expected, replay.groups);
std::vector<std::string> expected_problems = {
{"Action 'Upgrade' 'vlc' cannot be merged because it is not present at that point -> "
Expand All @@ -1437,7 +1466,13 @@ void TransactionMergeTest::group_remove_remove() {

auto [replay, problems] = libdnf5::transaction::merge_transactions({trans1, trans2}, na_to_installed_nevras);

std::vector<GroupReplay> expected = {{TransactionItemAction::REMOVE, TransactionItemReason::USER, "vlc", "", ""}};
std::vector<GroupReplay> expected = {
{TransactionItemAction::REMOVE,
TransactionItemReason::USER,
"vlc",
"",
"",
libdnf5::comps::PackageType::DEFAULT}};
CPPUNIT_ASSERT_EQUAL(expected, replay.groups);
std::vector<std::string> expected_problems = {
{"Action 'Remove' 'vlc' cannot be merged after it was 'Remove' in preceding "
Expand All @@ -1455,7 +1490,13 @@ void TransactionMergeTest::group_upgrade_upgrade() {

auto [replay, problems] = libdnf5::transaction::merge_transactions({trans1, trans2}, na_to_installed_nevras);

std::vector<GroupReplay> expected = {{TransactionItemAction::UPGRADE, TransactionItemReason::USER, "vlc", "", ""}};
std::vector<GroupReplay> expected = {
{TransactionItemAction::UPGRADE,
TransactionItemReason::USER,
"vlc",
"",
"",
libdnf5::comps::PackageType::DEFAULT}};
CPPUNIT_ASSERT_EQUAL(expected, replay.groups);
CPPUNIT_ASSERT_EQUAL(std::vector<std::string>(), problems);
}
Expand All @@ -1470,7 +1511,13 @@ void TransactionMergeTest::group_upgrade_remove() {

auto [replay, problems] = libdnf5::transaction::merge_transactions({trans1, trans2}, na_to_installed_nevras);

std::vector<GroupReplay> expected = {{TransactionItemAction::REMOVE, TransactionItemReason::USER, "vlc", "", ""}};
std::vector<GroupReplay> expected = {
{TransactionItemAction::REMOVE,
TransactionItemReason::USER,
"vlc",
"",
"",
libdnf5::comps::PackageType::DEFAULT}};
CPPUNIT_ASSERT_EQUAL(expected, replay.groups);
CPPUNIT_ASSERT_EQUAL(std::vector<std::string>(), problems);
}
Expand All @@ -1485,7 +1532,13 @@ void TransactionMergeTest::group_upgrade_install() {

auto [replay, problems] = libdnf5::transaction::merge_transactions({trans1, trans2}, na_to_installed_nevras);

std::vector<GroupReplay> expected = {{TransactionItemAction::INSTALL, TransactionItemReason::USER, "vlc", "", ""}};
std::vector<GroupReplay> expected = {
{TransactionItemAction::INSTALL,
TransactionItemReason::USER,
"vlc",
"",
"",
libdnf5::comps::PackageType::DEFAULT}};
CPPUNIT_ASSERT_EQUAL(expected, replay.groups);
CPPUNIT_ASSERT_EQUAL(std::vector<std::string>(), problems);
}
Expand Down
Loading
Loading