diff --git a/backend/CMakeLists.txt b/backend/CMakeLists.txt index c1153a5..fe2bfbf 100644 --- a/backend/CMakeLists.txt +++ b/backend/CMakeLists.txt @@ -4,6 +4,7 @@ find_package(CURL) find_package(PkgConfig REQUIRED) +find_package(SQLite3) pkg_check_modules(deps REQUIRED IMPORTED_TARGET glib-2.0 gio-2.0 bzip2) add_library(backend) @@ -15,6 +16,6 @@ target_sources(backend configure_file(config.h.in ${CMAKE_BINARY_DIR}/generated/config.h) include_directories(${CMAKE_BINARY_DIR}/generated/) -target_link_libraries(backend PkgConfig::deps CURL::libcurl) +target_link_libraries(backend PkgConfig::deps CURL::libcurl ${SQLite3_LIBRARIES}) file(COPY metadata.db DESTINATION ${CMAKE_BINARY_DIR}/${CMAKE_INSTALL_LOCALSTATEDIR}) diff --git a/backend/job.cpp b/backend/job.cpp index 9aaabc7..68a2090 100644 --- a/backend/job.cpp +++ b/backend/job.cpp @@ -15,6 +15,7 @@ module; #include #include #include +#include export module katja.job; @@ -24,19 +25,18 @@ import katja.slackpkg; namespace katja { -static GSList *repos = nullptr; +static std::forward_list> repos; void pk_backend_initialize(GKeyFile *conf) { char *path, **groups; int ret; - gushort i; - gsize groups_len; + std::uint8_t i; + std::size_t groups_len; GFile *conf_file; GFileInfo *file_info; GKeyFile *key_conf; GError *err = nullptr; - void *repo = nullptr; sqlite3 *db; sqlite3_stmt *stmt; @@ -107,9 +107,9 @@ void pk_backend_initialize(GKeyFile *conf) if (g_key_file_has_key(key_conf, groups[i], "Priority", nullptr)) { - repo = new Slackpkg(groups[i], mirror, i + 1, blacklist, + auto repo = std::make_unique(groups[i], mirror, i + 1, blacklist, g_key_file_get_string_list(key_conf, groups[i], "Priority", nullptr, nullptr)); - repos = g_slist_append(repos, repo); + repos.emplace_front(std::move(repo)); } g_free(mirror); g_free(blacklist); @@ -123,12 +123,7 @@ void pk_backend_destroy() { g_debug("backend: destroy"); - for (GSList *l = repos; l; l = g_slist_next(l)) - { - delete static_cast(l->data); - } - - g_slist_free(repos); + repos.clear(); curl_global_cleanup(); } @@ -257,7 +252,7 @@ void pk_backend_get_details(JobData *job_data, char **package_ids) { char *homepage = nullptr; char** tokens; - gsize i; + std::size_t i; GString *desc; GRegex *expr; GMatchInfo *match_info; @@ -392,10 +387,10 @@ void pk_backend_download_packages(JobData *job_data, char **package_ids, const c sqlite3_bind_text(stmt, 4, tokens[3], -1, SQLITE_TRANSIENT); if (sqlite3_step(stmt) == SQLITE_ROW) { - GSList *repo; - if ((repo = g_slist_find_custom(repos, tokens[3], cmp_repo))) + auto repo = cmp_repo(std::begin(repos), std::end(repos), tokens[3]); + if (repo != std::end(repos)) { - static_cast(repo->data)->download(job_data, directory, tokens[0]); + (*repo)->download(job_data, directory, tokens[0]); path = g_build_filename(directory, (char *) sqlite3_column_text(stmt, 1), nullptr); to_strv[0] = path; job_data->files(to_strv); @@ -487,16 +482,13 @@ void pk_backend_install_packages(JobData *job_data, char **package_ids) dest_dir_name = g_build_filename(LOCALSTATEDIR, "cache", "katja", "downloads", nullptr); for (l = install_list, i = 0; l; l = g_slist_next(l), i++) { - char **tokens; - GSList *repo; - job_data->set_percentage(percent_step * i); - tokens = g_strsplit((char *)(l->data), ";", 4); - repo = g_slist_find_custom(repos, tokens[3], cmp_repo); + char **tokens = g_strsplit((char *)(l->data), ";", 4); + auto repo = cmp_repo(std::begin(repos), std::end(repos), tokens[3]); - if (repo) + if (repo != std::end(repos)) { - static_cast(repo->data)->download(job_data, dest_dir_name, tokens[0]); + (*repo)->download(job_data, dest_dir_name, tokens[0]); } g_strfreev(tokens); } @@ -505,16 +497,13 @@ void pk_backend_install_packages(JobData *job_data, char **package_ids) /* Install the packages */ for (l = install_list; l; l = g_slist_next(l), i++) { - char **tokens; - GSList *repo; - job_data->set_percentage(percent_step * i); - tokens = g_strsplit((char *)(l->data), ";", 4); - repo = g_slist_find_custom(repos, tokens[3], cmp_repo); + char **tokens = g_strsplit((char *)(l->data), ";", 4); + auto repo = cmp_repo(std::begin(repos), std::end(repos), tokens[3]); - if (repo) + if (repo != std::end(repos)) { - static_cast(repo->data)->install(job_data, tokens[0]); + (*repo)->install(job_data, tokens[0]); } g_strfreev(tokens); } @@ -530,17 +519,15 @@ void pk_backend_remove_packages(JobData* job_data, char **package_ids) { char *cmd_line; unsigned i; - gdouble percent_step; + double percent_step; GError *err = nullptr; /* Add percent_step percents per removed package */ percent_step = 100.0 / g_strv_length(package_ids); for (i = 0; package_ids[i]; i++) { - char **tokens; - job_data->set_percentage(percent_step * i); - tokens = g_strsplit(package_ids[i], ";", 4); + char **tokens = g_strsplit(package_ids[i], ";", 4); cmd_line = g_strconcat("/sbin/removepkg ", tokens[0], nullptr); /* Pkgtools return always 0 */ @@ -611,7 +598,7 @@ void pk_backend_get_updates(JobData *job_data) /* If there are more packages with the same name, remember the one from the * repository with the lowest order. */ if ((sqlite3_step(stmt) == SQLITE_ROW) - || g_slist_find_custom(repos, ((char *) sqlite3_column_text(stmt, 4)), cmp_repo)) + || cmp_repo(std::begin(repos), std::end(repos), (const char *) sqlite3_column_text(stmt, 4)) != std::end(repos)) { full_name = g_strdup((char *) sqlite3_column_text(stmt, 0)); @@ -656,11 +643,11 @@ void pk_backend_update_packages(JobData *job_data, char **package_ids) for (i = 0; package_ids[i]; i++) { char **tokens = g_strsplit(package_ids[i], ";", 4); - GSList *repo = g_slist_find_custom(repos, tokens[3], cmp_repo); + auto repo = cmp_repo(std::begin(repos), std::end(repos), tokens[3]); - if (repo) + if (repo != std::end(repos)) { - static_cast(repo->data)->download(job_data, dest_dir_name, tokens[0]); + (*repo)->download(job_data, dest_dir_name, tokens[0]); } g_strfreev(tokens); } @@ -670,11 +657,11 @@ void pk_backend_update_packages(JobData *job_data, char **package_ids) for (i = 0; package_ids[i]; i++) { char **tokens = g_strsplit(package_ids[i], ";", 4); - GSList *repo = g_slist_find_custom(repos, tokens[3], cmp_repo); + auto repo = cmp_repo(std::begin(repos), std::end(repos), tokens[3]); - if (repo) + if (repo != std::end(repos)) { - static_cast(repo->data)->install(job_data, tokens[0]); + (*repo)->install(job_data, tokens[0]); } g_strfreev(tokens); } @@ -684,7 +671,7 @@ void pk_backend_refresh_cache(JobData *job_data, bool force) { char *tmp_dir_name, *db_err, *path = nullptr; int ret; - GSList *file_list = nullptr; + std::forward_list file_list; GFile *db_file = nullptr; GFileInfo *file_info = nullptr; GError *err = nullptr; @@ -737,24 +724,21 @@ void pk_backend_refresh_cache(JobData *job_data, bool force) } // Get list of files that should be downloaded. - for (GSList *l = repos; l; l = g_slist_next(l)) + for (auto& l : repos) { - file_list = g_slist_concat(file_list, - static_cast(l->data)->collect_cache_info(tmp_dir_name)); + file_list.prepend_range(l->collect_cache_info(tmp_dir_name)); } /* Download repository */ - for (GSList *l = file_list; l; l = g_slist_next(l)) + for (auto& l : file_list) { - get_file(&job_data->curl, static_cast(l->data)[0], - static_cast(l->data)[1]); + get_file(&job_data->curl, l.first.c_str(), l.second.native().c_str()); } - g_slist_free_full(file_list, (GDestroyNotify) g_strfreev); /* Refresh cache */ - for (GSList *l = repos; l; l = g_slist_next(l)) + for (auto& l : repos) { - static_cast(l->data)->generate_cache(job_data, tmp_dir_name); + l->generate_cache(job_data, tmp_dir_name); } out: diff --git a/backend/pkgtools.cpp b/backend/pkgtools.cpp index 58a752f..80dc4d8 100644 --- a/backend/pkgtools.cpp +++ b/backend/pkgtools.cpp @@ -12,6 +12,8 @@ module; #include #include #include +#include +#include export module katja.pkgtools; @@ -19,6 +21,8 @@ import katja.utils; export namespace katja { +using cache_entry = std::pair; + class Pkgtools { public: @@ -160,7 +164,7 @@ public: sqlite3_finalize(statement); } - virtual GSList *collect_cache_info (const char *tmpl) noexcept = 0; + virtual std::forward_list collect_cache_info(const char *tmpl) noexcept = 0; virtual void generate_cache(JobData *job_data, const char *tmpl) noexcept = 0; protected: @@ -170,10 +174,11 @@ protected: /** * katja::cmp_repo: **/ -int cmp_repo(const void *a, const void *b) +template +InputIt cmp_repo(InputIt first, InputIt last, const char *a) { - auto repo = static_cast (a); - - return g_strcmp0(repo->name.c_str(), (char *) b); + return std::find_if(first, last, [a](std::unique_ptr& repo) { + return repo->name == a; + }); } } diff --git a/backend/slackpkg.cpp b/backend/slackpkg.cpp index fd7ea22..d546b5e 100644 --- a/backend/slackpkg.cpp +++ b/backend/slackpkg.cpp @@ -16,6 +16,8 @@ module; #include #include #include +#include +#include export module katja.slackpkg; @@ -47,30 +49,12 @@ public: { this->blacklist = std::regex(blacklist); } - for (char **cur_priority = priority; *cur_priority; cur_priority++) + if (priority != nullptr) { - this->priority.emplace_back(*cur_priority); - } - // Initialize category map - if (cat_map == nullptr) - { - cat_map = g_hash_table_new(g_str_hash, g_str_equal); - g_hash_table_insert(cat_map, (void *) "a", (void *) "system"); - g_hash_table_insert(cat_map, (void *) "ap", (void *) "admin-tools"); - g_hash_table_insert(cat_map, (void *) "d", (void *) "programming"); - g_hash_table_insert(cat_map, (void *) "e", (void *) "programming"); - g_hash_table_insert(cat_map, (void *) "f", (void *) "documentation"); - g_hash_table_insert(cat_map, (void *) "k", (void *) "system"); - g_hash_table_insert(cat_map, (void *) "kde", (void *) "desktop-kde"); - g_hash_table_insert(cat_map, (void *) "kdei", (void *) "localization"); - g_hash_table_insert(cat_map, (void *) "l", (void *) "system"); - g_hash_table_insert(cat_map, (void *) "n", (void *) "network"); - g_hash_table_insert(cat_map, (void *) "t", (void *) "publishing"); - g_hash_table_insert(cat_map, (void *) "tcl", (void *) "system"); - g_hash_table_insert(cat_map, (void *) "x", (void *) "desktop-other"); - g_hash_table_insert(cat_map, (void *) "xap", (void *) "accessories"); - g_hash_table_insert(cat_map, (void *) "xfce", (void *) "desktop-xfce"); - g_hash_table_insert(cat_map, (void *) "y", (void *) "games"); + for (char **cur_priority = priority; *cur_priority; cur_priority++) + { + this->priority.emplace_back(*cur_priority); + } } } @@ -83,11 +67,11 @@ public: * * Returns: List of files needed for building the cache. **/ - GSList *collect_cache_info(const char *tmpl) noexcept + std::forward_list collect_cache_info(const char *tmpl) noexcept { CURL *curl = nullptr; - char **source_dest; - GSList *file_list = nullptr; + cache_entry source_dest; + std::forward_list file_list; GFile *tmp_dir, *repo_tmp_dir; /* Create the temporary directory for the repository */ @@ -98,34 +82,25 @@ public: /* Download PACKAGES.TXT. These files are most important, break if some of them couldn't be found */ for (const std::string& current_priority : this->priority) { - source_dest = static_cast (g_malloc_n(3, sizeof(char *))); - source_dest[0] = g_strconcat(this->mirror.c_str(), current_priority.c_str(), "/PACKAGES.TXT", nullptr); - source_dest[1] = g_build_filename(tmpl, this->name.c_str(), "PACKAGES.TXT", nullptr); - source_dest[2] = nullptr; + source_dest.first = this->mirror + current_priority + "/PACKAGES.TXT"; + source_dest.second = std::filesystem::path(tmpl) / this->name / "PACKAGES.TXT"; - if (get_file(&curl, source_dest[0], nullptr) == CURLE_OK) + if (get_file(&curl, source_dest.first.c_str(), nullptr) == CURLE_OK) { - file_list = g_slist_prepend(file_list, source_dest); + file_list.emplace_front(std::move(source_dest)); } else { - g_strfreev(source_dest); - g_slist_free_full(file_list, (GDestroyNotify)g_strfreev); goto out; } /* Download file lists if available */ - source_dest = static_cast (g_malloc_n(3, sizeof(char *))); - source_dest[0] = g_strconcat(this->mirror.c_str(), current_priority.c_str(), "/MANIFEST.bz2", nullptr); - source_dest[1] = g_strconcat(tmpl, "/", this->name.c_str(), "/", *current_priority.c_str(), "-MANIFEST.bz2", nullptr); - source_dest[2] = nullptr; - if (get_file(&curl, source_dest[0], nullptr) == CURLE_OK) + source_dest.first = this->mirror + current_priority + "/MANIFEST.bz2"; + source_dest.second = std::filesystem::path(tmpl) / this->name / (current_priority + "-MANIFEST.bz2"); + + if (get_file(&curl, source_dest.first.c_str(), nullptr) == CURLE_OK) { - file_list = g_slist_prepend(file_list, source_dest); - } - else - { - g_strfreev(source_dest); + file_list.emplace_front(std::move(source_dest)); } } out: @@ -154,7 +129,7 @@ public: char **pkg_tokens = nullptr; char *query = nullptr, *filename = nullptr, *location = nullptr, *summary = nullptr, *line, *packages_txt; unsigned pkg_compressed = 0, pkg_uncompressed = 0; - gushort pkg_name_len; + std::uint8_t pkg_name_len; GString *desc; GFile *list_file; GFileInputStream *fin = nullptr; @@ -279,12 +254,9 @@ public: { /* Get the package group based on its location */ const char *cat = g_strrstr(location, "/"); - if (cat) /* Else cat = nullptr */ - { - cat = static_cast(g_hash_table_lookup(cat_map, cat + 1)); - } if (cat) { + ++cat; statement = insert_statement; sqlite3_bind_text(insert_statement, 12, cat, -1, SQLITE_TRANSIENT); } @@ -349,7 +321,6 @@ public: } private: - static inline GHashTable *cat_map{ nullptr }; static const std::size_t max_buf_size = 8192; std::vector priority; diff --git a/backend/utils.cpp b/backend/utils.cpp index 086fa42..19d0b39 100644 --- a/backend/utils.cpp +++ b/backend/utils.cpp @@ -52,9 +52,9 @@ struct JobData * * Returns: CURLE_OK (zero) on success, non-zero otherwise. **/ -CURLcode get_file(CURL **curl, char *source_url, char *dest) +CURLcode get_file(CURL **curl, const char *source_url, const char *dest) { - char *dest_dir_name; + const char *dest_dir_name; FILE *fout = nullptr; CURLcode ret; glong response_code; @@ -85,7 +85,7 @@ CURLcode get_file(CURL **curl, char *source_url, char *dest) { dest_dir_name = dest; dest = g_strconcat(dest_dir_name, g_strrstr(source_url, "/"), nullptr); - g_free(dest_dir_name); + g_free(const_cast(dest_dir_name)); } if ((fout = fopen(dest, "ab")) == nullptr) { diff --git a/tests/CMakeLists.txt b/tests/CMakeLists.txt index 3555ece..d6f74f4 100644 --- a/tests/CMakeLists.txt +++ b/tests/CMakeLists.txt @@ -13,7 +13,7 @@ foreach(test_source ${KATJA_TEST_SOURCES}) add_executable(${tester} ${test_source}) target_compile_definitions(${tester} PRIVATE "BOOST_TEST_DYN_LINK=1") - target_link_libraries(${tester} PRIVATE katja Boost::unit_test_framework) + target_link_libraries(${tester} PRIVATE katja backend Boost::unit_test_framework) add_test(NAME ${test_name} COMMAND ${tester}) endforeach() diff --git a/backend/tests/slackpkg-test.cc b/tests/slackpkg.cpp similarity index 65% rename from backend/tests/slackpkg-test.cc rename to tests/slackpkg.cpp index 89406af..9a47765 100644 --- a/backend/tests/slackpkg-test.cc +++ b/tests/slackpkg.cpp @@ -10,11 +10,11 @@ import katja.slackpkg; BOOST_AUTO_TEST_CASE(slack_test_slackpkg_construct) { - auto slackpkg = new Slackpkg("some", "mirror", 1, nullptr, nullptr); + auto slackpkg = new katja::Slackpkg("some", "mirror", 1, nullptr, nullptr); - BOOST_TEST(strcmp(slackpkg->get_name(), "some") == 0); - BOOST_TEST(strcmp(slackpkg->get_mirror(), "mirror") == 0); - BOOST_TEST(slackpkg->get_order() == 1); + BOOST_TEST(slackpkg->name == "some"); + BOOST_TEST(slackpkg->mirror == "mirror"); + BOOST_TEST(slackpkg->order == 1); BOOST_TEST(!slackpkg->is_blacklisted("pattern")); delete slackpkg;