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

DnfContext: add dnf_context_module_install() #1200

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
2 changes: 1 addition & 1 deletion VERSION.cmake
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
set (DEFAULT_LIBDNF_MAJOR_VERSION 0)
set (DEFAULT_LIBDNF_MINOR_VERSION 62)
set (DEFAULT_LIBDNF_MINOR_VERSION 63)
set (DEFAULT_LIBDNF_MICRO_VERSION 0)

if(DEFINED LIBDNF_MAJOR_VERSION)
Expand Down
2 changes: 1 addition & 1 deletion libdnf.spec
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,7 @@
%global dnf_conflict 4.3.0
%global swig_version 3.0.12
%global libdnf_major_version 0
%global libdnf_minor_version 62
%global libdnf_minor_version 63
%global libdnf_micro_version 0

%define __cmake_in_source_build 1
Expand Down
113 changes: 112 additions & 1 deletion libdnf/dnf-context.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -3409,7 +3409,7 @@ dnf_context_module_enable(DnfContext * context, const char ** module_specs, GErr
} catch (const libdnf::ModulePackageContainer::EnableMultipleStreamsException & exception) {
messages.emplace_back(std::make_tuple(
libdnf::ModulePackageContainer::ModuleErrorType::CANNOT_MODIFY_MULTIPLE_TIMES_MODULE_STATE,
tfm::format(_("Problem during enablement of dependency tree for moduele '%1$s' stream '%2$s': %3$s"),
tfm::format(_("Problem during enablement of dependency tree for module '%1$s' stream '%2$s': %3$s"),
module_dict_iter.first, stream_dict_iter.first, exception.what()), pair.first));
messages.emplace_back(std::make_tuple(
libdnf::ModulePackageContainer::ModuleErrorType::CANNOT_RESOLVE_MODULE_SPEC,
Expand All @@ -3427,6 +3427,117 @@ dnf_context_module_enable(DnfContext * context, const char ** module_specs, GErr
return TRUE;
} CATCH_TO_GERROR(FALSE)

gboolean
dnf_context_module_install(DnfContext * context, const char ** module_specs, GError ** error) try
{
DnfContextPrivate *priv = GET_PRIVATE (context);

/* create sack and add sources */
if (priv->sack == nullptr) {
dnf_state_reset (priv->state);
if (!dnf_context_setup_sack(context, priv->state, error)) {
return FALSE;
}
}

DnfSack * sack = priv->sack;
assert(sack);
assert(module_specs);

auto container = dnf_sack_get_module_container(sack);
if (!container) {
g_set_error_literal(error, DNF_ERROR, DNF_ERROR_FAILED, _("No modular data available"));
return FALSE;
}
std::vector<std::tuple<libdnf::ModulePackageContainer::ModuleErrorType, std::string, std::string>> messages;

std::vector<std::string> nevras_to_install;
for (const char ** specs = module_specs; *specs != NULL; ++specs) {
auto resolved_spec = resolve_module_spec(*specs, *container);
if (!resolved_spec.first) {
messages.emplace_back(
std::make_tuple(libdnf::ModulePackageContainer::ModuleErrorType::CANNOT_RESOLVE_MODULE_SPEC,
tfm::format(_("Unable to resolve argument '%s'"), *specs), *specs));
continue;
}
auto module_dict = create_module_dict(resolved_spec.second);
auto message = modify_module_dict_and_enable_stream(module_dict, *container, true);
if (!message.empty()) {
messages.insert(
messages.end(),std::make_move_iterator(message.begin()), std::make_move_iterator(message.end()));
messages.emplace_back(
std::make_tuple(libdnf::ModulePackageContainer::ModuleErrorType::CANNOT_RESOLVE_MODULE_SPEC,
tfm::format(_("Unable to resolve argument '%s'"), *specs), *specs));
} else {
for (auto module_dict_iter : module_dict) {
auto & stream_dict = module_dict_iter.second;
// this was checked in modify_module_dict_and_enable_stream()
assert(stream_dict.size() == 1);
for (const auto &iter : stream_dict) {
for (const auto &modpkg : iter.second) {
std::vector<libdnf::ModuleProfile> profiles;
if (resolved_spec.first->getProfile() != "") {
profiles = modpkg->getProfiles(resolved_spec.first->getProfile());
} else {
profiles.push_back(modpkg->getDefaultProfile());
}
std::set<std::string> pkgnames;
for (const auto &profile : profiles) {
container->install(modpkg, profile.getName());
for (const auto &pkgname : profile.getContent()) {
pkgnames.insert(pkgname);
}
}
for (const auto &nevra : modpkg->getArtifacts()) {
int epoch;
char *name, *version, *release, *arch;
if (hy_split_nevra(nevra.c_str(), &name, &epoch, &version, &release, &arch)) {
// this really should never happen; unless the modular repodata is corrupted
g_autofree char *errmsg = g_strdup_printf (_("Failed to parse module artifact NEVRA '%s'"), nevra.c_str());
g_set_error_literal(error, DNF_ERROR, DNF_ERROR_FAILED, errmsg);
return FALSE;
}
// ignore source packages
if (g_str_equal (arch, "src") || g_str_equal (arch, "nosrc"))
continue;
if (pkgnames.count(name) != 0) {
nevras_to_install.push_back(std::string(nevra));
}
}
}
}
}
}
}

std::vector<const char *> hotfixRepos;
// don't filter RPMs from repos with the 'module_hotfixes' flag set
for (unsigned int i = 0; i < priv->repos->len; i++) {
auto repo = static_cast<DnfRepo *>(g_ptr_array_index(priv->repos, i));
if (dnf_repo_get_module_hotfixes(repo)) {
hotfixRepos.push_back(dnf_repo_get_id(repo));
}
}
hotfixRepos.push_back(nullptr);
auto solver_error = recompute_modular_filtering(container, sack, hotfixRepos);
if (!solver_error.empty()) {
messages.insert(
messages.end(),std::make_move_iterator(solver_error.begin()), std::make_move_iterator(solver_error.end()));
}

bool return_error = report_problems(messages);
if (return_error) {
g_set_error_literal(error, DNF_ERROR, DNF_ERROR_FAILED, _("Problems appeared for module install request"));
return FALSE;
} else {
for (const auto &nevra : nevras_to_install) {
if (!dnf_context_install (context, nevra.c_str(), error))
return FALSE;
}
}
return TRUE;
} CATCH_TO_GERROR(FALSE)

static gboolean
context_modules_reset_or_disable(DnfContext * context, const char ** module_specs, GError ** error, bool reset)
{
Expand Down
21 changes: 19 additions & 2 deletions libdnf/dnf-context.h
Original file line number Diff line number Diff line change
Expand Up @@ -293,15 +293,32 @@ gboolean dnf_context_reset_all_modules (DnfContext * context,
* @module_specs: Module specs that should be enabled
* @error: Error
*
* Enable mudules, recalculate module filtration, but do not commit modular changes.
* To commit modular changes it requires to call dnf_context_run()
* Enable modules, recalculate module filtration, but do not commit modular changes.
* To commit modular changes, call dnf_context_run().
* Returns FALSE when an error is set.
*
* Since: 0.55.0
**/
gboolean dnf_context_module_enable (DnfContext * context,
const char ** module_specs,
GError ** error);

/**
* dnf_context_module_install:
* @context: DnfContext
* @module_specs: Module specs that should be installed
* @error: Error
*
* Enable modules and mark for installation but do not commit modular changes.
* To commit modular changes, call dnf_context_run().
* Returns FALSE when an error is set.
*
* Since: 0.63.0
**/
gboolean dnf_context_module_install (DnfContext * context,
const char ** module_specs,
GError ** error);

/**
* dnf_context_module_disable:
* @context: DnfContext
Expand Down
20 changes: 20 additions & 0 deletions libdnf/module/ModulePackage.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -442,6 +442,26 @@ ModulePackage::getProfiles(const std::string &name) const
return result_profiles;
}

ModuleProfile
ModulePackage::getDefaultProfile() const
{
//TODO(amatej): replace with
//char ** profiles = modulemd_module_stream_v2_search_profiles((ModulemdModuleStreamV2 *) mdStream, profileNameCStr);
char ** profiles = modulemd_module_stream_v2_get_profile_names_as_strv((ModulemdModuleStreamV2 *) mdStream);
if (g_strv_length (profiles) == 1) {
return ModuleProfile(modulemd_module_stream_v2_get_profile((ModulemdModuleStreamV2 *) mdStream, profiles[0]));
}

for (char **iter = profiles; iter && *iter; iter++) {
auto profile = ModuleProfile(modulemd_module_stream_v2_get_profile((ModulemdModuleStreamV2 *) mdStream, *iter));
if (profile.isDefault()) {
return profile;
}
}

throw std::runtime_error("No default profile found for " + getFullIdentifier());
}

/**
* @brief Return list of ModuleProfiles.
*
Expand Down
3 changes: 2 additions & 1 deletion libdnf/module/ModulePackage.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -61,12 +61,13 @@ class ModulePackage // TODO inherit in future; : public Package
std::vector<std::string> getArtifacts() const;
bool operator==(const ModulePackage &r) const;
/**
* @brief Return profiles matched by name.
* @brief Return profiles matched by name (which is possibly a globby pattern).
*
* @return std::vector<ModuleProfile>
*/
std::vector<ModuleProfile> getProfiles(const std::string &name) const;
std::vector<ModuleProfile> getProfiles() const;
ModuleProfile getDefaultProfile() const;

std::vector<ModuleDependencies> getModuleDependencies() const;

Expand Down
8 changes: 8 additions & 0 deletions libdnf/module/modulemd/ModuleProfile.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -64,6 +64,14 @@ std::string ModuleProfile::getName() const
return name ? name : "";
}

bool ModuleProfile::isDefault() const
{
if (!profile) {
return {};
}
return modulemd_profile_is_default(profile);
}

std::string ModuleProfile::getDescription() const
{
if (!profile) {
Expand Down
1 change: 1 addition & 0 deletions libdnf/module/modulemd/ModuleProfile.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -40,6 +40,7 @@ class ModuleProfile
std::string getName() const;
std::string getDescription() const;
std::vector<std::string> getContent() const;
bool isDefault() const;

private:
friend class ModulePackage;
Expand Down