@@ -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})
|
||||
|
||||
+35
-51
@@ -15,6 +15,7 @@ module;
|
||||
#include <curl/curl.h>
|
||||
#include <glib/gstdio.h>
|
||||
#include <sqlite3.h>
|
||||
#include <forward_list>
|
||||
|
||||
export module katja.job;
|
||||
|
||||
@@ -24,19 +25,18 @@ import katja.slackpkg;
|
||||
|
||||
namespace katja
|
||||
{
|
||||
static GSList *repos = nullptr;
|
||||
static std::forward_list<std::unique_ptr<Pkgtools>> 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<Slackpkg>(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<Pkgtools *>(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<Pkgtools *>(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<Pkgtools *>(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<Pkgtools *>(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<Pkgtools *>(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<Pkgtools *>(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<katja::cache_entry> 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<Pkgtools *>(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<char **>(l->data)[0],
|
||||
static_cast<char **>(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<Pkgtools *>(l->data)->generate_cache(job_data, tmp_dir_name);
|
||||
l->generate_cache(job_data, tmp_dir_name);
|
||||
}
|
||||
|
||||
out:
|
||||
|
||||
+10
-5
@@ -12,6 +12,8 @@ module;
|
||||
#include <glib-object.h>
|
||||
#include <string>
|
||||
#include <regex>
|
||||
#include <forward_list>
|
||||
#include <filesystem>
|
||||
|
||||
export module katja.pkgtools;
|
||||
|
||||
@@ -19,6 +21,8 @@ import katja.utils;
|
||||
|
||||
export namespace katja
|
||||
{
|
||||
using cache_entry = std::pair<std::string, std::filesystem::path>;
|
||||
|
||||
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<cache_entry> 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<class InputIt>
|
||||
InputIt cmp_repo(InputIt first, InputIt last, const char *a)
|
||||
{
|
||||
auto repo = static_cast<const Pkgtools *> (a);
|
||||
|
||||
return g_strcmp0(repo->name.c_str(), (char *) b);
|
||||
return std::find_if(first, last, [a](std::unique_ptr<Pkgtools>& repo) {
|
||||
return repo->name == a;
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
+18
-47
@@ -16,6 +16,8 @@ module;
|
||||
#include <string>
|
||||
#include <regex>
|
||||
#include <vector>
|
||||
#include <forward_list>
|
||||
#include <filesystem>
|
||||
|
||||
export module katja.slackpkg;
|
||||
|
||||
@@ -47,30 +49,12 @@ public:
|
||||
{
|
||||
this->blacklist = std::regex(blacklist);
|
||||
}
|
||||
if (priority != nullptr)
|
||||
{
|
||||
for (char **cur_priority = priority; *cur_priority; cur_priority++)
|
||||
{
|
||||
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");
|
||||
}
|
||||
}
|
||||
|
||||
@@ -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<cache_entry> collect_cache_info(const char *tmpl) noexcept
|
||||
{
|
||||
CURL *curl = nullptr;
|
||||
char **source_dest;
|
||||
GSList *file_list = nullptr;
|
||||
cache_entry source_dest;
|
||||
std::forward_list<cache_entry> 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<char **> (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<char **> (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<const char *>(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<std::string> priority;
|
||||
|
||||
|
||||
+3
-3
@@ -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<char *>(dest_dir_name));
|
||||
}
|
||||
if ((fout = fopen(dest, "ab")) == nullptr)
|
||||
{
|
||||
|
||||
@@ -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()
|
||||
|
||||
@@ -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;
|
||||
Reference in New Issue
Block a user