diff --git a/CMakeLists.txt b/CMakeLists.txt index b031aea84..835a59c6e 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -34,6 +34,7 @@ option(WITH_COMPS "Build with comps groups and environments support" ON) option(WITH_MODULEMD "Build with modulemd modules support" ON) option(WITH_ZCHUNK "Build with zchunk delta compression support" ON) option(WITH_SYSTEMD "Build with systemd and D-Bus features" ON) +option(WITH_APPSTREAM "Build with appstream support" ON) option(ENABLE_SOLV_URPMREORDER "Build with support for URPM-like solution reordering?" OFF) option(ENABLE_SOLV_FOCUSNEW "Build with SOLVER_FLAG_FOCUS_NEW libsolv flag enabled to ensure new dependencies are installed in latests versions?" ON) @@ -129,6 +130,10 @@ if (WITH_MODULEMD) add_definitions(-DWITH_MODULEMD) endif() +if (WITH_APPSTREAM) + add_definitions(-DWITH_APPSTREAM) +endif() + include_directories("${PROJECT_SOURCE_DIR}/include") include_directories("${PROJECT_SOURCE_DIR}/common") diff --git a/include/libdnf5/repo/repo.hpp b/include/libdnf5/repo/repo.hpp index 425982882..c7c4cc8fe 100644 --- a/include/libdnf5/repo/repo.hpp +++ b/include/libdnf5/repo/repo.hpp @@ -144,6 +144,10 @@ class LIBDNF_API Repo { // @replaces libdnf:repo/Repo.hpp:method:Repo.loadCache(bool throwExcept) void read_metadata_cache(); + /// install 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(); diff --git a/libdnf5/CMakeLists.txt b/libdnf5/CMakeLists.txt index d360901ee..c5e82bc78 100644 --- a/libdnf5/CMakeLists.txt +++ b/libdnf5/CMakeLists.txt @@ -81,6 +81,13 @@ if (WITH_MODULEMD) target_link_libraries(libdnf5_static PRIVATE ${LIBMODULEMD_LIBRARIES}) endif() +if (WITH_APPSTREAM) + pkg_check_modules(APPSTREAM REQUIRED appstream>=1.0) + 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() diff --git a/libdnf5/repo/repo.cpp b/libdnf5/repo/repo.cpp index c621eab67..fe4bb0cbf 100644 --- a/libdnf5/repo/repo.cpp +++ b/libdnf5/repo/repo.cpp @@ -52,6 +52,9 @@ extern "C" { #include #include +#ifdef WITH_APPSTREAM +#include +#endif namespace libdnf5::repo { @@ -203,6 +206,31 @@ void Repo::read_metadata_cache() { p_impl->downloader->load_local(); } +void Repo::install_appstream() { +#ifdef WITH_APPSTREAM + std::string repo_id = p_impl->config.get_id(); + const char * as_basenames[] = {"appstream", "appstream-icons", NULL}; + + for (uint32_t i = 0; as_basenames[i] != NULL; i++) { + std::string tmp = get_metadata_path(as_basenames[i]); + GError * local_error = NULL; + + if (tmp.empty()) + continue; + + if (!as_utils_install_metadata_file( + AS_METADATA_LOCATION_CACHE, tmp.c_str(), repo_id.c_str(), NULL, &local_error)) { + p_impl->base->get_logger()->debug( + "Failed to install Appstream metadata file '{}' for repo '{}': {}", + tmp, + repo_id, + local_error ? local_error->message : "Unknown error"); + } + + g_clear_error(&local_error); + } +#endif +} bool Repo::is_in_sync() { if (!p_impl->config.get_metalink_option().empty() && !p_impl->config.get_metalink_option().get_value().empty()) { @@ -409,6 +437,10 @@ void Repo::load_available_repo() { } p_impl->solv_repo->load_repo_main(p_impl->downloader->repomd_filename, primary_fn); +#ifdef WITH_APPSTREAM + p_impl->solv_repo->load_repo_ext(RepodataType::APPSTREAM, *p_impl->downloader.get()); + p_impl->solv_repo->load_repo_ext(RepodataType::APPSTREAM_ICONS, *p_impl->downloader.get()); +#endif auto optional_metadata = p_impl->config.get_main_config().get_optional_metadata_types_option().get_value(); diff --git a/libdnf5/repo/repo_downloader.cpp b/libdnf5/repo/repo_downloader.cpp index b142aabbe..af8de9308 100644 --- a/libdnf5/repo/repo_downloader.cpp +++ b/libdnf5/repo/repo_downloader.cpp @@ -477,6 +477,10 @@ void RepoDownloader::common_handle_setup(LibrepoHandle & h) { dlist.push_back(MD_FILENAME_PRIMARY); #ifdef WITH_MODULEMD dlist.push_back(MD_FILENAME_MODULES); +#endif +#ifdef WITH_APPSTREAM + dlist.push_back(MD_FILENAME_APPSTREAM); + dlist.push_back(MD_FILENAME_APPSTREAM_ICONS); #endif if (optional_metadata.extract(libdnf5::METADATA_TYPE_FILELISTS)) { dlist.push_back(MD_FILENAME_FILELISTS); diff --git a/libdnf5/repo/repo_downloader.hpp b/libdnf5/repo/repo_downloader.hpp index 1c14b272b..e5493def1 100644 --- a/libdnf5/repo/repo_downloader.hpp +++ b/libdnf5/repo/repo_downloader.hpp @@ -56,6 +56,8 @@ class RepoDownloader { static constexpr const char * MD_FILENAME_GROUP_GZ = "group_gz"; static constexpr const char * MD_FILENAME_GROUP = "group"; static constexpr const char * MD_FILENAME_MODULES = "modules"; + static constexpr const char * MD_FILENAME_APPSTREAM = "appstream"; + static constexpr const char * MD_FILENAME_APPSTREAM_ICONS = "appstream-icons"; RepoDownloader(const libdnf5::BaseWeakPtr & base, const ConfigRepo & config, Repo::Type repo_type); diff --git a/libdnf5/repo/repo_sack.cpp b/libdnf5/repo/repo_sack.cpp index 62e6e92ad..fadaed389 100644 --- a/libdnf5/repo/repo_sack.cpp +++ b/libdnf5/repo/repo_sack.cpp @@ -574,6 +574,7 @@ 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(idx)); send_to_sack_loader(repo); diff --git a/libdnf5/repo/solv_repo.cpp b/libdnf5/repo/solv_repo.cpp index 67025e452..efb5c04e3 100644 --- a/libdnf5/repo/solv_repo.cpp +++ b/libdnf5/repo/solv_repo.cpp @@ -179,6 +179,10 @@ static const char * repodata_type_to_name(RepodataType type) { return RepoDownloader::MD_FILENAME_GROUP; case RepodataType::OTHER: return RepoDownloader::MD_FILENAME_OTHER; + case RepodataType::APPSTREAM: + return RepoDownloader::MD_FILENAME_APPSTREAM; + case RepodataType::APPSTREAM_ICONS: + return RepoDownloader::MD_FILENAME_APPSTREAM_ICONS; } libdnf_throw_assertion("Unknown RepodataType: {}", utils::to_underlying(type)); @@ -197,6 +201,9 @@ static int repodata_type_to_flags(RepodataType type) { return 0; case RepodataType::OTHER: return REPO_EXTEND_SOLVABLES | REPO_LOCALPOOL; + case RepodataType::APPSTREAM: + case RepodataType::APPSTREAM_ICONS: + return 0; } libdnf_throw_assertion("Unknown RepodataType: {}", utils::to_underlying(type)); @@ -313,6 +320,8 @@ void SolvRepo::load_system_repo_ext(RepodataType type) { case RepodataType::OTHER: case RepodataType::PRESTO: case RepodataType::UPDATEINFO: + case RepodataType::APPSTREAM: + case RepodataType::APPSTREAM_ICONS: throw SolvError(M_("Unsupported extended repodata type for the system repo: \"{}\"."), type_name); } } @@ -375,6 +384,12 @@ void SolvRepo::load_repo_ext(RepodataType type, const RepoDownloader & downloade case RepodataType::OTHER: res = repo_add_rpmmd(repo, ext_file.get(), 0, REPO_EXTEND_SOLVABLES); break; + case RepodataType::APPSTREAM: + res = repo_add_rpmmd(repo, ext_file.get(), 0, REPO_EXTEND_SOLVABLES); + break; + case RepodataType::APPSTREAM_ICONS: + res = repo_add_rpmmd(repo, ext_file.get(), 0, REPO_EXTEND_SOLVABLES); + break; } if (res != 0) { diff --git a/libdnf5/repo/solv_repo.hpp b/libdnf5/repo/solv_repo.hpp index ae6e62e47..2fdcb27b0 100644 --- a/libdnf5/repo/solv_repo.hpp +++ b/libdnf5/repo/solv_repo.hpp @@ -52,7 +52,7 @@ struct SolvUserdata { namespace libdnf5::repo { using LibsolvRepo = ::Repo; -enum class RepodataType { FILELISTS, PRESTO, UPDATEINFO, COMPS, OTHER }; +enum class RepodataType { FILELISTS, PRESTO, UPDATEINFO, COMPS, OTHER, APPSTREAM, APPSTREAM_ICONS }; class SolvError : public Error {