Skip to content

Commit

Permalink
libdnf5: Turn the Appstream data installation code into a plugin
Browse files Browse the repository at this point in the history
This allows to split out the appstream library dependency into a separate
package, not adding it and its dependencies into the core part of the libdnf5.
  • Loading branch information
mcrha committed Dec 5, 2024
1 parent 6fb904c commit a575c38
Show file tree
Hide file tree
Showing 9 changed files with 173 additions and 40 deletions.
17 changes: 17 additions & 0 deletions dnf5.spec
Original file line number Diff line number Diff line change
Expand Up @@ -609,6 +609,23 @@ Libdnf5 plugin that allows to run actions (external executables) on hooks.
%{_mandir}/man8/libdnf5-actions.8.*
%endif

# ========== libdnf5-plugin-appstream ==========

%if %{with appstream}

%package -n libdnf5-plugin-appstream
Summary: Libdnf5 plugin to install repo Appstream data
License: LGPL-2.1-or-later
Requires: libdnf5%{?_isa} = %{version}-%{release}

%description -n libdnf5-plugin-appstream
Libdnf5 plugin that installs repository's Appstream data, for repositories which provide them.

%files -n libdnf5-plugin-appstream
%{_libdir}/libdnf5/plugins/appstream.so
%config %{_sysconfdir}/dnf/libdnf5-plugins/appstream.conf

%endif

# ========== libdnf5-plugin-plugin_rhsm ==========

Expand Down
7 changes: 3 additions & 4 deletions include/libdnf5/repo/repo.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -144,10 +144,6 @@ class LIBDNF_API Repo {
// @replaces libdnf:repo/Repo.hpp:method:Repo.loadCache(bool throwExcept)
void read_metadata_cache();

/// Installs downloaded Appstream data for the repo, if available and
/// if built with the Appstream support.
void install_appstream();

/// Checks whether the locally downloaded metadata are in sync with the origin.
/// @return `true` if metadata are in sync with the origin, `false` otherwise.
bool is_in_sync();
Expand Down Expand Up @@ -318,6 +314,9 @@ class LIBDNF_API Repo {
// @replaces libdnf:repo/Repo.hpp:method:Repo.downloadMetadata(const std::string & destdir)
void download_metadata(const std::string & destdir);

/// Returns a list of pairs of the rpmmd type and filename of the Appstream data of the repo
std::vector<std::pair<std::string, std::string>> get_appstream_metadata() const;

private:
class LIBDNF_LOCAL Impl;
friend class RepoSack;
Expand Down
4 changes: 4 additions & 0 deletions libdnf5-plugins/CMakeLists.txt
Original file line number Diff line number Diff line change
Expand Up @@ -4,3 +4,7 @@ set(CMAKE_C_VISIBILITY_PRESET hidden)
add_subdirectory("actions")
add_subdirectory("python_plugins_loader")
add_subdirectory("rhsm")

if(WITH_APPSTREAM)
add_subdirectory("appstream")
endif()
13 changes: 13 additions & 0 deletions libdnf5-plugins/appstream/CMakeLists.txt
Original file line number Diff line number Diff line change
@@ -0,0 +1,13 @@
add_library(appstream_plugin MODULE appstream.cpp)

# disable the 'lib' prefix in order to create appstream.so
set_target_properties(appstream_plugin PROPERTIES PREFIX "")
set_target_properties(appstream_plugin PROPERTIES OUTPUT_NAME "appstream")

pkg_check_modules(APPSTREAM REQUIRED appstream>=0.16)
include_directories(${APPSTREAM_INCLUDE_DIRS})
target_link_libraries(appstream_plugin PRIVATE ${APPSTREAM_LIBRARIES})
target_link_libraries(appstream_plugin PRIVATE libdnf5)

install(TARGETS appstream_plugin LIBRARY DESTINATION "${CMAKE_INSTALL_FULL_LIBDIR}/libdnf5/plugins/")
install(FILES "appstream.conf" DESTINATION "${CMAKE_INSTALL_FULL_SYSCONFDIR}/dnf/libdnf5-plugins")
3 changes: 3 additions & 0 deletions libdnf5-plugins/appstream/appstream.conf
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
[main]
name = appstream
enabled = 1
131 changes: 131 additions & 0 deletions libdnf5-plugins/appstream/appstream.cpp
Original file line number Diff line number Diff line change
@@ -0,0 +1,131 @@
/*
Copyright Contributors to the libdnf project.
This file is part of libdnf: https://github.com/rpm-software-management/libdnf/
Libdnf is free software: you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation, either version 2 of the License, or
(at your option) any later version.
Libdnf is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with libdnf. If not, see <https://www.gnu.org/licenses/>.
*/

#include <appstream.h>
#include <libdnf5/base/base.hpp>
#include <libdnf5/conf/const.hpp>
#include <libdnf5/plugin/iplugin.hpp>
#include <libdnf5/repo/repo.hpp>
#include <libdnf5/repo/repo_query.hpp>

#include <iostream>

using namespace libdnf5;

namespace {

constexpr const char * PLUGIN_NAME{"appstream"};
constexpr libdnf5::plugin::Version PLUGIN_VERSION{.major = 1, .minor = 0, .micro = 0};

constexpr const char * attrs[]{"author.name", "author.email", "description", nullptr};
constexpr const char * attrs_value[]{"Milan Crha", "[email protected]", "install repo Appstream data."};

class AppstreamPlugin : public plugin::IPlugin {
public:
AppstreamPlugin(libdnf5::plugin::IPluginData & data, libdnf5::ConfigParser &) : IPlugin(data) {}
virtual ~AppstreamPlugin() = default;

PluginAPIVersion get_api_version() const noexcept override { return PLUGIN_API_VERSION; }

const char * get_name() const noexcept override { return PLUGIN_NAME; }

plugin::Version get_version() const noexcept override { return PLUGIN_VERSION; }

const char * const * get_attributes() const noexcept override { return attrs; }

const char * get_attribute(const char * attribute) const noexcept override {
for (size_t i = 0; attrs[i]; ++i) {
if (std::strcmp(attribute, attrs[i]) == 0) {
return attrs_value[i];
}
}
return nullptr;
}

void repos_loaded() override {
Base & base = get_base();
repo::RepoQuery repos(base);
repos.filter_enabled(true);
for (const auto & repo : repos) {
switch (repo->get_type()) {
case repo::Repo::Type::AVAILABLE:
case repo::Repo::Type::SYSTEM:
install_appstream(repo.get());
break;
case repo::Repo::Type::COMMANDLINE:;
}
}
}

private:
void install_appstream(libdnf5::repo::Repo * repo);
};

void AppstreamPlugin::install_appstream(libdnf5::repo::Repo * repo) {
libdnf5::Base & base = get_base();
if (!repo->get_config().get_main_config().get_optional_metadata_types_option().get_value().contains(
libdnf5::METADATA_TYPE_APPSTREAM))
return;

std::string repo_id = repo->get_config().get_id();
auto appstream_metadata = repo->get_appstream_metadata();
for (auto & item : appstream_metadata) {
const std::string path = item.second;
GError * local_error = NULL;

if (!as_utils_install_metadata_file(
AS_METADATA_LOCATION_CACHE, path.c_str(), repo_id.c_str(), NULL, &local_error)) {
base.get_logger()->debug(
"Failed to install Appstream metadata file '{}' for repo '{}': {}",
path,
repo_id,
local_error ? local_error->message : "Unknown error");
}

g_clear_error(&local_error);
}
}

} // namespace


PluginAPIVersion libdnf_plugin_get_api_version(void) {
return PLUGIN_API_VERSION;
}

const char * libdnf_plugin_get_name(void) {
return PLUGIN_NAME;
}

plugin::Version libdnf_plugin_get_version(void) {
return PLUGIN_VERSION;
}

plugin::IPlugin * libdnf_plugin_new_instance(
[[maybe_unused]] LibraryVersion library_version,
libdnf5::plugin::IPluginData & data,
libdnf5::ConfigParser & parser) try {
return new AppstreamPlugin(data, parser);
} catch (...) {
return nullptr;
}

void libdnf_plugin_delete_instance(plugin::IPlugin * plugin_object) {
delete plugin_object;
}
7 changes: 0 additions & 7 deletions libdnf5/CMakeLists.txt
Original file line number Diff line number Diff line change
Expand Up @@ -81,13 +81,6 @@ if (WITH_MODULEMD)
target_link_libraries(libdnf5_static PRIVATE ${LIBMODULEMD_LIBRARIES})
endif()

if (WITH_APPSTREAM)
pkg_check_modules(APPSTREAM REQUIRED appstream>=0.16)
include_directories(${APPSTREAM_INCLUDE_DIRS})
target_link_libraries(libdnf5 PRIVATE ${APPSTREAM_LIBRARIES})
target_link_libraries(libdnf5_static PRIVATE ${APPSTREAM_LIBRARIES})
endif()

if (ENABLE_SOLV_FOCUSNEW)
pkg_check_modules(LIBSOLV REQUIRED libsolv>=0.7.30)
else()
Expand Down
30 changes: 2 additions & 28 deletions libdnf5/repo/repo.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -52,10 +52,6 @@ extern "C" {
#include <filesystem>
#include <set>

#ifdef WITH_APPSTREAM
#include <appstream.h>
#endif

namespace libdnf5::repo {

static void is_readable_rpm(const std::string & fn) {
Expand Down Expand Up @@ -206,30 +202,8 @@ void Repo::read_metadata_cache() {
p_impl->downloader->load_local();
}

void Repo::install_appstream() {
#ifdef WITH_APPSTREAM
if (!p_impl->config.get_main_config().get_optional_metadata_types_option().get_value().contains(
libdnf5::METADATA_TYPE_APPSTREAM))
return;

std::string repo_id = p_impl->config.get_id();
auto appstream_metadata = p_impl->downloader->get_appstream_metadata();
for (auto & item : appstream_metadata) {
const std::string path = item.second;
GError * local_error = NULL;

if (!as_utils_install_metadata_file(
AS_METADATA_LOCATION_CACHE, path.c_str(), repo_id.c_str(), NULL, &local_error)) {
p_impl->base->get_logger()->debug(
"Failed to install Appstream metadata file '{}' for repo '{}': {}",
path,
repo_id,
local_error ? local_error->message : "Unknown error");
}

g_clear_error(&local_error);
}
#endif
std::vector<std::pair<std::string, std::string>> Repo::get_appstream_metadata() const {
return get_downloader().get_appstream_metadata();
}

bool Repo::is_in_sync() {
Expand Down
1 change: 0 additions & 1 deletion libdnf5/repo/repo_sack.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -575,7 +575,6 @@ void RepoSack::Impl::update_and_load_repos(libdnf5::repo::RepoQuery & repos, boo
RepoCache(base, cache_dir).remove_attribute(RepoCache::ATTRIBUTE_EXPIRED);
repo->mark_fresh();
repo->read_metadata_cache();
repo->install_appstream();

repos_for_processing.erase(repos_for_processing.begin() + static_cast<ssize_t>(idx));
send_to_sack_loader(repo);
Expand Down

0 comments on commit a575c38

Please sign in to comment.