1
0

Replace glib data structures with STL

This commit is contained in:
2026-06-15 00:30:14 +02:00
parent 6719ed7ed3
commit 8140da6d6e
4 changed files with 162 additions and 177 deletions
+119 -150
View File
@@ -16,7 +16,11 @@ module;
#include <glib/gstdio.h> #include <glib/gstdio.h>
#include <sqlite3.h> #include <sqlite3.h>
#include <forward_list> #include <forward_list>
#include <array>
#include <string>
#include <list>
#include <boost/filesystem.hpp> #include <boost/filesystem.hpp>
#include <boost/algorithm/string.hpp>
export module katja.job; export module katja.job;
@@ -30,7 +34,7 @@ static std::forward_list<std::unique_ptr<Pkgtools>> repos;
void pk_backend_initialize(GKeyFile *conf) void pk_backend_initialize(GKeyFile *conf)
{ {
char *path, **groups; char **groups;
int ret; int ret;
std::uint8_t i; std::uint8_t i;
std::size_t groups_len; std::size_t groups_len;
@@ -45,24 +49,23 @@ void pk_backend_initialize(GKeyFile *conf)
curl_global_init(CURL_GLOBAL_DEFAULT); curl_global_init(CURL_GLOBAL_DEFAULT);
/* Open the database. We will need it to save the time the configuration file was last modified. */ /* Open the database. We will need it to save the time the configuration file was last modified. */
path = g_build_filename(LOCALSTATEDIR, "cache", "katja", "metadata.db", nullptr); auto path = std::filesystem::path(LOCALSTATEDIR) / "cache" / "katja" / "metadata.db";
if (sqlite3_open(path, &db) != SQLITE_OK) if (sqlite3_open(path.c_str(), &db) != SQLITE_OK)
{ {
g_error("%s: %s", path, sqlite3_errmsg(db)); g_error("%s: %s", path.c_str(), sqlite3_errmsg(db));
} }
g_free(path);
/* Read the configuration file */ /* Read the configuration file */
key_conf = g_key_file_new(); key_conf = g_key_file_new();
path = g_build_filename(SYSCONFDIR, "PackageKit", "Slackware.conf", nullptr); path = std::filesystem::path(SYSCONFDIR) / "PackageKit" / "Slackware.conf";
g_key_file_load_from_file(key_conf, path, G_KEY_FILE_NONE, &err); g_key_file_load_from_file(key_conf, path.c_str(), G_KEY_FILE_NONE, &err);
if (err) if (err)
{ {
g_error("%s: %s", path, err->message); g_error("%s: %s", path.c_str(), err->message);
g_error_free(err); g_error_free(err);
} }
conf_file = g_file_new_for_path(path); conf_file = g_file_new_for_path(path.c_str());
if (!(file_info = g_file_query_info(conf_file, if (!(file_info = g_file_query_info(conf_file,
"time::modified-usec", "time::modified-usec",
G_FILE_QUERY_INFO_NOFOLLOW_SYMLINKS, G_FILE_QUERY_INFO_NOFOLLOW_SYMLINKS,
@@ -87,17 +90,16 @@ void pk_backend_initialize(GKeyFile *conf)
} }
if ((ret != SQLITE_OK) && (ret != SQLITE_DONE)) if ((ret != SQLITE_OK) && (ret != SQLITE_DONE))
{ {
g_error("%s: %s", path, sqlite3_errstr(ret)); g_error("%s: %s", path.c_str(), sqlite3_errstr(ret));
} }
else if (!sqlite3_changes(db)) else if (!sqlite3_changes(db))
{ {
g_error("Failed to update database: %s", path); g_error("Failed to update database: %s", path.c_str());
} }
g_object_unref(file_info); g_object_unref(file_info);
g_object_unref(conf_file); g_object_unref(conf_file);
sqlite3_close_v2(db); sqlite3_close_v2(db);
g_free(path);
/* Initialize an object for each well-formed repository */ /* Initialize an object for each well-formed repository */
groups = g_key_file_get_groups(key_conf, &groups_len); groups = g_key_file_get_groups(key_conf, &groups_len);
@@ -130,22 +132,16 @@ void pk_backend_destroy()
JobData *pk_backend_start_job() JobData *pk_backend_start_job()
{ {
char *db_filename = nullptr; JobData *job_data = new DummyJobData();
JobData *job_data = g_new0(JobData, 1); auto db_filename = std::filesystem::path(LOCALSTATEDIR) / "cache" / "katja" / "metadata.db";
db_filename = g_build_filename(LOCALSTATEDIR, "cache", "katja", "metadata.db", nullptr); if (sqlite3_open(db_filename.native().c_str(), &job_data->db) == SQLITE_OK) { /* Some SQLite settings */
if (sqlite3_open(db_filename, &job_data->db) == SQLITE_OK) { /* Some SQLite settings */
sqlite3_exec(job_data->db, "PRAGMA foreign_keys = ON", nullptr, nullptr, nullptr); sqlite3_exec(job_data->db, "PRAGMA foreign_keys = ON", nullptr, nullptr, nullptr);
} }
else else
{ {
std::cerr << db_filename << ": " << sqlite3_errmsg(job_data->db) << std::endl; std::cerr << db_filename << ": " << sqlite3_errmsg(job_data->db) << std::endl;
goto out;
} }
out:
g_free(db_filename);
return job_data; return job_data;
} }
@@ -157,22 +153,19 @@ void pk_backend_stop_job(JobData *job_data)
} }
sqlite3_close(job_data->db); sqlite3_close(job_data->db);
g_free(job_data); delete job_data;
} }
void pk_backend_search_thread(JobData *job_data, GVariant *params, const char *user_data) // for filters -1 means requesting not installed, 1 - installed, 0 - no filters.
void pk_backend_search_thread(JobData *job_data, std::uint64_t filters, const std::vector<std::string>& vals,
const char *user_data)
{ {
char **vals; std::string search = boost::algorithm::join(vals, "%");
// -1 means requesting not installed, 1 - installed, 0 - no filters.
guint64 filters;
g_variant_get(params, "(t^a&s)", &filters, &vals);
char *search = g_strjoinv("%", vals);
const char *generate_query = "SELECT (p1.name || ';' || p1.ver || ';' || p1.arch || ';' || r.repo), p1.summary, " const char *generate_query = "SELECT (p1.name || ';' || p1.ver || ';' || p1.arch || ';' || r.repo), p1.summary, "
"p1.full_name FROM pkglist AS p1 NATURAL JOIN repos AS r " "p1.full_name FROM pkglist AS p1 NATURAL JOIN repos AS r "
"WHERE p1.%s LIKE '%%%q%%' AND p1.ext NOT LIKE 'obsolete' AND p1.repo_order = " "WHERE p1.%s LIKE '%%%q%%' AND p1.ext NOT LIKE 'obsolete' AND p1.repo_order = "
"(SELECT MIN(p2.repo_order) FROM pkglist AS p2 WHERE p2.name = p1.name GROUP BY p2.name)"; "(SELECT MIN(p2.repo_order) FROM pkglist AS p2 WHERE p2.name = p1.name GROUP BY p2.name)";
char *query = sqlite3_mprintf(generate_query, user_data, search); char *query = sqlite3_mprintf(generate_query, user_data, search.c_str());
sqlite3_stmt *stmt; sqlite3_stmt *stmt;
if ((sqlite3_prepare_v2(job_data->db, query, -1, &stmt, nullptr) == SQLITE_OK)) if ((sqlite3_prepare_v2(job_data->db, query, -1, &stmt, nullptr) == SQLITE_OK))
@@ -204,21 +197,19 @@ void pk_backend_search_thread(JobData *job_data, GVariant *params, const char *u
std::cerr << sqlite3_errmsg(job_data->db) << std::endl; std::cerr << sqlite3_errmsg(job_data->db) << std::endl;
} }
sqlite3_free(query); sqlite3_free(query);
g_free(search);
} }
void pk_backend_search_files(JobData *job_data, char **values) void pk_backend_search_files(JobData *job_data, const std::vector<std::string>& values)
{ {
char *search;
char *query; char *query;
sqlite3_stmt *stmt; sqlite3_stmt *stmt;
Info ret; Info ret;
search = g_strjoinv("%", values); std::string search = boost::algorithm::join(values, "%");
query = sqlite3_mprintf("SELECT (p.name || ';' || p.ver || ';' || p.arch || ';' || r.repo), p.summary, " query = sqlite3_mprintf("SELECT (p.name || ';' || p.ver || ';' || p.arch || ';' || r.repo), p.summary, "
"p.full_name FROM filelist AS f NATURAL JOIN pkglist AS p NATURAL JOIN repos AS r " "p.full_name FROM filelist AS f NATURAL JOIN pkglist AS p NATURAL JOIN repos AS r "
"WHERE f.filename LIKE '%%%q%%' GROUP BY f.full_name", search); "WHERE f.filename LIKE '%%%q%%' GROUP BY f.full_name", search.c_str());
if ((sqlite3_prepare_v2(job_data->db, query, -1, &stmt, nullptr) == SQLITE_OK)) if ((sqlite3_prepare_v2(job_data->db, query, -1, &stmt, nullptr) == SQLITE_OK))
{ {
@@ -246,19 +237,20 @@ void pk_backend_search_files(JobData *job_data, char **values)
std::cerr << sqlite3_errmsg(job_data->db) << std::endl; std::cerr << sqlite3_errmsg(job_data->db) << std::endl;
} }
sqlite3_free(query); sqlite3_free(query);
g_free(search);
} }
void pk_backend_get_details(JobData *job_data, char **package_ids) void pk_backend_get_details(JobData *job_data, char **package_ids)
{ {
char *homepage = nullptr; std::optional<std::string> homepage;
char** tokens;
std::size_t i; std::size_t i;
GString *desc;
GRegex *expr; GRegex *expr;
GMatchInfo *match_info; GMatchInfo *match_info;
GError *err = nullptr; GError *err = nullptr;
sqlite3_stmt *stmt; sqlite3_stmt *stmt;
std::string desc;
std::vector<std::string> tokens;
boost::split(tokens, package_ids[i], boost::is_any_of(";"));
if ((sqlite3_prepare_v2(job_data->db, if ((sqlite3_prepare_v2(job_data->db,
"SELECT p.desc, p.cat, p.uncompressed FROM pkglist AS p NATURAL JOIN repos AS r " "SELECT p.desc, p.cat, p.uncompressed FROM pkglist AS p NATURAL JOIN repos AS r "
@@ -269,17 +261,14 @@ void pk_backend_get_details(JobData *job_data, char **package_ids)
std::cerr << sqlite3_errmsg(job_data->db) << std::endl; std::cerr << sqlite3_errmsg(job_data->db) << std::endl;
goto out; goto out;
} }
sqlite3_bind_text(stmt, 1, tokens[0].c_str(), -1, SQLITE_TRANSIENT);
tokens = g_strsplit(package_ids[0], ";", 4); sqlite3_bind_text(stmt, 2, tokens[3].c_str(), -1, SQLITE_TRANSIENT);
sqlite3_bind_text(stmt, 1, tokens[0], -1, SQLITE_TRANSIENT);
sqlite3_bind_text(stmt, 2, tokens[3], -1, SQLITE_TRANSIENT);
g_strfreev(tokens);
if (sqlite3_step(stmt) != SQLITE_ROW) if (sqlite3_step(stmt) != SQLITE_ROW)
{ {
goto out; goto out;
} }
desc = g_string_new((char *) sqlite3_column_text(stmt, 0)); desc = reinterpret_cast<const char *>(sqlite3_column_text(stmt, 0));
/* Regular expression for searching a homepage */ /* Regular expression for searching a homepage */
expr = g_regex_new("(?:http|ftp):\\/\\/[[:word:]\\/\\-\\.]+[[:word:]\\/](?=\\.?$)", expr = g_regex_new("(?:http|ftp):\\/\\/[[:word:]\\/\\-\\.]+[[:word:]\\/](?=\\.?$)",
@@ -292,15 +281,15 @@ void pk_backend_get_details(JobData *job_data, char **package_ids)
g_error_free(err); g_error_free(err);
goto out; goto out;
} }
if (g_regex_match(expr, desc->str, (GRegexMatchFlags) 0, &match_info)) if (g_regex_match(expr, desc.c_str(), (GRegexMatchFlags) 0, &match_info))
{ {
homepage = g_match_info_fetch(match_info, 0); /* URL */ homepage = g_match_info_fetch(match_info, 0); /* URL */
/* Remove the last sentence with the copied URL */ /* Remove the last sentence with the copied URL */
for (i = desc->len - 1; i > 0; i--) for (i = desc.size() - 1; i > 0; i--)
{ {
if ((desc->str[i - 1] == '.') && (desc->str[i] == ' ')) if ((desc[i - 1] == '.') && (desc[i] == ' '))
{ {
g_string_truncate(desc, i); desc.erase(std::cbegin(desc) + i);
break; break;
} }
} }
@@ -311,16 +300,10 @@ void pk_backend_get_details(JobData *job_data, char **package_ids)
/* Ready */ /* Ready */
job_data->details(package_ids[0], job_data->details(package_ids[0],
(char *) sqlite3_column_text(stmt, 1), (char *) sqlite3_column_text(stmt, 1),
desc->str, desc.c_str(),
homepage, homepage.has_value() ? homepage.value().c_str() : nullptr,
sqlite3_column_int(stmt, 2)); sqlite3_column_int(stmt, 2));
g_free(homepage);
if (desc)
{
g_string_free(desc, true);
}
out: out:
sqlite3_finalize(stmt); sqlite3_finalize(stmt);
} }
@@ -363,7 +346,6 @@ void pk_backend_resolve(JobData *job_data, char **packages)
void pk_backend_download_packages(JobData *job_data, char **package_ids, const char *directory) void pk_backend_download_packages(JobData *job_data, char **package_ids, const char *directory)
{ {
char *path, *to_strv[] = {nullptr, nullptr};
unsigned i; unsigned i;
sqlite3_stmt *stmt; sqlite3_stmt *stmt;
@@ -380,39 +362,38 @@ void pk_backend_download_packages(JobData *job_data, char **package_ids, const c
for (i = 0; package_ids[i]; ++i) for (i = 0; package_ids[i]; ++i)
{ {
char **tokens = g_strsplit(package_ids[i], ";", 4); std::vector<std::string> tokens;
boost::split(tokens, package_ids[i], boost::is_any_of(";"));
sqlite3_bind_text(stmt, 1, tokens[0], -1, SQLITE_TRANSIENT); sqlite3_bind_text(stmt, 1, tokens[0].c_str(), -1, SQLITE_TRANSIENT);
sqlite3_bind_text(stmt, 2, tokens[1], -1, SQLITE_TRANSIENT); sqlite3_bind_text(stmt, 2, tokens[1].c_str(), -1, SQLITE_TRANSIENT);
sqlite3_bind_text(stmt, 3, tokens[2], -1, SQLITE_TRANSIENT); sqlite3_bind_text(stmt, 3, tokens[2].c_str(), -1, SQLITE_TRANSIENT);
sqlite3_bind_text(stmt, 4, tokens[3], -1, SQLITE_TRANSIENT); sqlite3_bind_text(stmt, 4, tokens[3].c_str(), -1, SQLITE_TRANSIENT);
if (sqlite3_step(stmt) == SQLITE_ROW) if (sqlite3_step(stmt) == SQLITE_ROW)
{ {
auto repo = cmp_repo(std::begin(repos), std::end(repos), tokens[3]); auto repo = cmp_repo(std::begin(repos), std::end(repos), tokens[3].c_str());
if (repo != std::end(repos)) if (repo != std::end(repos))
{ {
(*repo)->download(job_data, directory, tokens[0]); (*repo)->download(job_data, directory, tokens[0].c_str());
path = g_build_filename(directory, (char *) sqlite3_column_text(stmt, 1), nullptr); auto path = std::filesystem::path(directory)
to_strv[0] = path; / reinterpret_cast<const char *>(sqlite3_column_text(stmt, 1));
std::vector<std::string> to_strv{ path };
job_data->files(to_strv); job_data->files(to_strv);
g_free(path);
} }
} }
sqlite3_clear_bindings(stmt); sqlite3_clear_bindings(stmt);
sqlite3_reset(stmt); sqlite3_reset(stmt);
g_strfreev(tokens);
} }
out: out:
sqlite3_finalize(stmt); sqlite3_finalize(stmt);
} }
void pk_backend_install_packages(JobData *job_data, char **package_ids) void pk_backend_install_packages(JobData *job_data, const std::vector<std::string> package_ids)
{ {
char *dest_dir_name;
unsigned i; unsigned i;
gdouble percent_step; gdouble percent_step;
GSList *install_list = nullptr, *l; std::list<std::string> install_list;
sqlite3_stmt *pkglist_stmt = nullptr, *collection_stmt = nullptr; sqlite3_stmt *pkglist_stmt = nullptr, *collection_stmt = nullptr;
if ((sqlite3_prepare_v2(job_data->db, if ((sqlite3_prepare_v2(job_data->db,
@@ -435,33 +416,35 @@ void pk_backend_install_packages(JobData *job_data, char **package_ids)
goto out; goto out;
} }
for (i = 0; package_ids[i]; i++) for (const std::string& package_id : package_ids)
{ {
char **tokens = g_strsplit(package_ids[i], ";", 4); std::vector<std::string> tokens;
sqlite3_bind_text(pkglist_stmt, 1, tokens[0], -1, SQLITE_TRANSIENT); boost::split(tokens, package_id, boost::is_any_of(";"));
sqlite3_bind_text(pkglist_stmt, 2, tokens[1], -1, SQLITE_TRANSIENT);
sqlite3_bind_text(pkglist_stmt, 3, tokens[2], -1, SQLITE_TRANSIENT); sqlite3_bind_text(pkglist_stmt, 1, tokens[0].c_str(), -1, SQLITE_TRANSIENT);
sqlite3_bind_text(pkglist_stmt, 4, tokens[3], -1, SQLITE_TRANSIENT); sqlite3_bind_text(pkglist_stmt, 2, tokens[1].c_str(), -1, SQLITE_TRANSIENT);
sqlite3_bind_text(pkglist_stmt, 3, tokens[2].c_str(), -1, SQLITE_TRANSIENT);
sqlite3_bind_text(pkglist_stmt, 4, tokens[3].c_str(), -1, SQLITE_TRANSIENT);
if (sqlite3_step(pkglist_stmt) == SQLITE_ROW) if (sqlite3_step(pkglist_stmt) == SQLITE_ROW)
{ {
/* If it isn't a collection */ /* If it isn't a collection */
if (g_strcmp0((char *) sqlite3_column_text(pkglist_stmt, 1), "collections")) if (strcmp(reinterpret_cast<const char *>(sqlite3_column_text(pkglist_stmt, 1)), "collections"))
{ {
install_list = g_slist_append(install_list, g_strdup(package_ids[i])); install_list.push_back(package_id);
} }
else else
{ {
sqlite3_bind_text(collection_stmt, 1, tokens[0], -1, SQLITE_TRANSIENT); sqlite3_bind_text(collection_stmt, 1, tokens[0].c_str(), -1, SQLITE_TRANSIENT);
sqlite3_bind_text(collection_stmt, 2, tokens[3], -1, SQLITE_TRANSIENT); sqlite3_bind_text(collection_stmt, 2, tokens[3].c_str(), -1, SQLITE_TRANSIENT);
while (sqlite3_step(collection_stmt) == SQLITE_ROW) while (sqlite3_step(collection_stmt) == SQLITE_ROW)
{ {
katja::Info ret = is_installed((char*) sqlite3_column_text(collection_stmt, 2)); katja::Info ret = is_installed((char*) sqlite3_column_text(collection_stmt, 2));
if ((ret == Info::installing) || (ret == Info::updating)) if ((ret == Info::installing) || (ret == Info::updating))
{ {
install_list = g_slist_append(install_list, install_list.push_back(
g_strdup((char *) sqlite3_column_text(collection_stmt, 0))); reinterpret_cast<const char *>(sqlite3_column_text(collection_stmt, 0)));
} }
} }
sqlite3_clear_bindings(collection_stmt); sqlite3_clear_bindings(collection_stmt);
@@ -471,71 +454,68 @@ void pk_backend_install_packages(JobData *job_data, char **package_ids)
sqlite3_clear_bindings(pkglist_stmt); sqlite3_clear_bindings(pkglist_stmt);
sqlite3_reset(pkglist_stmt); sqlite3_reset(pkglist_stmt);
g_strfreev(tokens);
} }
if (install_list) if (!install_list.empty())
{ {
/* / 2 means total percentage for installing and for downloading */ /* / 2 means total percentage for installing and for downloading */
percent_step = 100.0 / g_slist_length(install_list) / 2; percent_step = 100.0 / install_list.size() / 2;
/* Download the packages */ /* Download the packages */
dest_dir_name = g_build_filename(LOCALSTATEDIR, "cache", "katja", "downloads", nullptr); auto dest_dir_name = std::filesystem::path(LOCALSTATEDIR) / "cache" / "katja" / "downloads";
for (l = install_list, i = 0; l; l = g_slist_next(l), i++) for (const auto& l : install_list)
{ {
job_data->set_percentage(percent_step * i); job_data->set_percentage(percent_step * i);
char **tokens = g_strsplit((char *)(l->data), ";", 4); std::vector<std::string> tokens;
auto repo = cmp_repo(std::begin(repos), std::end(repos), tokens[3]); boost::split(tokens, l, boost::is_any_of(";"));
auto repo = cmp_repo(std::begin(repos), std::end(repos), tokens[3].c_str());
if (repo != std::end(repos)) if (repo != std::end(repos))
{ {
(*repo)->download(job_data, dest_dir_name, tokens[0]); (*repo)->download(job_data, dest_dir_name.native().c_str(), tokens[0].c_str());
} }
g_strfreev(tokens);
} }
g_free(dest_dir_name);
/* Install the packages */ /* Install the packages */
for (l = install_list; l; l = g_slist_next(l), i++) for (const auto& l : install_list)
{ {
job_data->set_percentage(percent_step * i); job_data->set_percentage(percent_step * i);
char **tokens = g_strsplit((char *)(l->data), ";", 4); std::vector<std::string> tokens;
auto repo = cmp_repo(std::begin(repos), std::end(repos), tokens[3]); boost::split(tokens, l, boost::is_any_of(";"));
auto repo = cmp_repo(std::begin(repos), std::end(repos), tokens[3].c_str());
if (repo != std::end(repos)) if (repo != std::end(repos))
{ {
(*repo)->install(job_data, tokens[0]); (*repo)->install(job_data, tokens[0].c_str());
} }
g_strfreev(tokens);
} }
} }
g_slist_free_full(install_list, g_free);
out: out:
sqlite3_finalize(pkglist_stmt); sqlite3_finalize(pkglist_stmt);
sqlite3_finalize(collection_stmt); sqlite3_finalize(collection_stmt);
} }
void pk_backend_remove_packages(JobData* job_data, char **package_ids) void pk_backend_remove_packages(JobData* job_data, const std::vector<std::string>& package_ids)
{ {
char *cmd_line;
unsigned i; unsigned i;
double percent_step; double percent_step;
GError *err = nullptr; GError *err = nullptr;
/* Add percent_step percents per removed package */ /* Add percent_step percents per removed package */
percent_step = 100.0 / g_strv_length(package_ids); percent_step = 100.0 / package_ids.size();
for (i = 0; package_ids[i]; i++) for (i = 0; i < package_ids[i].size(); i++)
{ {
job_data->set_percentage(percent_step * i); job_data->set_percentage(percent_step * i);
char **tokens = g_strsplit(package_ids[i], ";", 4); std::vector<std::string> tokens;
cmd_line = g_strconcat("/sbin/removepkg ", tokens[0], nullptr); boost::split(tokens, package_ids[i], boost::is_any_of(";"));
std::string cmd_line = "/sbin/removepkg " + tokens[0];
/* Pkgtools return always 0 */ /* Pkgtools return always 0 */
g_spawn_command_line_sync(cmd_line, nullptr, nullptr, nullptr, &err); g_spawn_command_line_sync(cmd_line.c_str(), nullptr, nullptr, nullptr, &err);
g_free(cmd_line);
g_strfreev(tokens);
if (err) if (err)
{ {
@@ -551,7 +531,6 @@ void pk_backend_remove_packages(JobData* job_data, char **package_ids)
void pk_backend_get_updates(JobData *job_data) void pk_backend_get_updates(JobData *job_data)
{ {
char *pkg_id, *full_name, *desc;
const char *pkg_metadata_filename; const char *pkg_metadata_filename;
GFile *pkg_metadata_dir; GFile *pkg_metadata_dir;
GFileEnumerator *pkg_metadata_enumerator; GFileEnumerator *pkg_metadata_enumerator;
@@ -588,44 +567,37 @@ void pk_backend_get_updates(JobData *job_data)
while ((pkg_metadata_file_info = g_file_enumerator_next_file(pkg_metadata_enumerator, nullptr, nullptr))) while ((pkg_metadata_file_info = g_file_enumerator_next_file(pkg_metadata_enumerator, nullptr, nullptr)))
{ {
char **tokens;
pkg_metadata_filename = g_file_info_get_name(pkg_metadata_file_info); pkg_metadata_filename = g_file_info_get_name(pkg_metadata_file_info);
tokens = split_package_name(pkg_metadata_filename); std::vector<std::string> tokens = split_package_name(pkg_metadata_filename).value();
/* Select the package from the database */ /* Select the package from the database */
sqlite3_bind_text(stmt, 1, tokens[0], -1, SQLITE_TRANSIENT); sqlite3_bind_text(stmt, 1, tokens[0].c_str(), -1, SQLITE_TRANSIENT);
/* If there are more packages with the same name, remember the one from the /* If there are more packages with the same name, remember the one from the
* repository with the lowest order. */ * repository with the lowest order. */
if ((sqlite3_step(stmt) == SQLITE_ROW) if ((sqlite3_step(stmt) == SQLITE_ROW)
|| cmp_repo(std::begin(repos), std::end(repos), (const char *) sqlite3_column_text(stmt, 4)) != std::end(repos)) || cmp_repo(std::begin(repos), std::end(repos), (const char *) sqlite3_column_text(stmt, 4)) != std::end(repos))
{ {
std::string full_name{ reinterpret_cast<const char *>(sqlite3_column_text(stmt, 0)) };
full_name = g_strdup((char *) sqlite3_column_text(stmt, 0)); if (full_name != pkg_metadata_filename)
if (g_strcmp0(pkg_metadata_filename, full_name))
{ /* Update available */ { /* Update available */
pkg_id = g_strjoin(";", std::array<std::string, 4> id_parts{
(char *) sqlite3_column_text(stmt, 1), reinterpret_cast<const char *>(sqlite3_column_text(stmt, 1)),
(char *) sqlite3_column_text(stmt, 2), reinterpret_cast<const char *>(sqlite3_column_text(stmt, 2)),
(char *) sqlite3_column_text(stmt, 3), reinterpret_cast<const char *>(sqlite3_column_text(stmt, 3)),
(char *) sqlite3_column_text(stmt, 4), reinterpret_cast<const char *>(sqlite3_column_text(stmt, 4))
nullptr); };
desc = g_strdup((char *) sqlite3_column_text(stmt, 5)); std::string pkg_id = boost::algorithm::join(id_parts, ";");
std::string desc{ reinterpret_cast<const char *>(sqlite3_column_text(stmt, 5)) };
job_data->package(katja::Info::updating, pkg_id, desc); job_data->package(katja::Info::updating, pkg_id.c_str(), desc.c_str());
g_free(desc);
g_free(pkg_id);
} }
g_free(full_name);
} }
sqlite3_clear_bindings(stmt); sqlite3_clear_bindings(stmt);
sqlite3_reset(stmt); sqlite3_reset(stmt);
g_strfreev(tokens);
g_object_unref(pkg_metadata_file_info); g_object_unref(pkg_metadata_file_info);
} }
g_object_unref(pkg_metadata_enumerator); g_object_unref(pkg_metadata_enumerator);
@@ -636,42 +608,40 @@ out:
void pk_backend_update_packages(JobData *job_data, char **package_ids) void pk_backend_update_packages(JobData *job_data, char **package_ids)
{ {
char *dest_dir_name, *cmd_line; char *cmd_line;
unsigned i; unsigned i;
/* Download the packages */ /* Download the packages */
dest_dir_name = g_build_filename(LOCALSTATEDIR, "cache", "katja", "downloads", nullptr); auto dest_dir_name = std::filesystem::path(LOCALSTATEDIR) / "cache" / "katja" / "downloads";
for (i = 0; package_ids[i]; i++) for (i = 0; package_ids[i]; i++)
{ {
char **tokens = g_strsplit(package_ids[i], ";", 4); std::vector<std::string> tokens;
auto repo = cmp_repo(std::begin(repos), std::end(repos), tokens[3]); boost::split(tokens, package_ids[i], boost::is_any_of(";"));
auto repo = cmp_repo(std::begin(repos), std::end(repos), tokens[3].c_str());
if (repo != std::end(repos)) if (repo != std::end(repos))
{ {
(*repo)->download(job_data, dest_dir_name, tokens[0]); (*repo)->download(job_data, dest_dir_name.c_str(), tokens[0].c_str());
} }
g_strfreev(tokens);
} }
g_free(dest_dir_name);
/* Install the packages */ /* Install the packages */
for (i = 0; package_ids[i]; i++) for (i = 0; package_ids[i]; i++)
{ {
char **tokens = g_strsplit(package_ids[i], ";", 4); std::vector<std::string> tokens;
auto repo = cmp_repo(std::begin(repos), std::end(repos), tokens[3]); boost::split(tokens, package_ids[i], boost::is_any_of(";"));
auto repo = cmp_repo(std::begin(repos), std::end(repos), tokens[3].c_str());
if (repo != std::end(repos)) if (repo != std::end(repos))
{ {
(*repo)->install(job_data, tokens[0]); (*repo)->install(job_data, tokens[0].c_str());
} }
g_strfreev(tokens);
} }
} }
void pk_backend_refresh_cache(JobData *job_data, bool force) void pk_backend_refresh_cache(JobData *job_data, bool force)
{ {
char *db_err, *path = nullptr; char *db_err;
std::filesystem::path tmp_dir_name;
int ret; int ret;
std::forward_list<katja::cache_entry> file_list; std::forward_list<katja::cache_entry> file_list;
GFile *db_file = nullptr; GFile *db_file = nullptr;
@@ -680,14 +650,15 @@ void pk_backend_refresh_cache(JobData *job_data, bool force)
sqlite3_stmt *stmt = nullptr; sqlite3_stmt *stmt = nullptr;
/* Create temporary directory */ /* Create temporary directory */
tmp_dir_name = std::filesystem::temp_directory_path() / boost::filesystem::unique_path("katja.%%%%%%").native(); std::filesystem::path tmp_dir_name =
std::filesystem::temp_directory_path() / boost::filesystem::unique_path("katja.%%%%%%").native();
std::filesystem::create_directories(tmp_dir_name); std::filesystem::create_directories(tmp_dir_name);
/* Force the complete cache refresh if the read configuration file is newer than the metadata cache */ /* Force the complete cache refresh if the read configuration file is newer than the metadata cache */
if (!force) if (!force)
{ {
path = g_build_filename(LOCALSTATEDIR, "cache", "katja", "metadata.db", nullptr); auto path = std::filesystem::path(LOCALSTATEDIR) / "cache" / "katja" / "metadata.db";
db_file = g_file_new_for_path(path); db_file = g_file_new_for_path(path.native().c_str());
file_info = g_file_query_info(db_file, "time::modified-usec", G_FILE_QUERY_INFO_NOFOLLOW_SYMLINKS, nullptr, &err); file_info = g_file_query_info(db_file, "time::modified-usec", G_FILE_QUERY_INFO_NOFOLLOW_SYMLINKS, nullptr, &err);
if (err) if (err)
{ {
@@ -748,8 +719,6 @@ out:
{ {
g_object_unref(db_file); g_object_unref(db_file);
} }
g_free(path);
std::filesystem::remove_all(tmp_dir_name); std::filesystem::remove_all(tmp_dir_name);
} }
} }
+3 -3
View File
@@ -79,7 +79,7 @@ public:
* *
* Returns: %TRUE on success, %FALSE otherwise. * Returns: %TRUE on success, %FALSE otherwise.
**/ **/
bool download(JobData *job_data, const char *dest_dir_name, char *pkg_name) noexcept bool download(JobData *job_data, const char *dest_dir_name, const char *pkg_name) noexcept
{ {
std::filesystem::path dest_filename; std::filesystem::path dest_filename;
std::string source_url; std::string source_url;
@@ -108,7 +108,7 @@ public:
+ "/" + "/"
+ reinterpret_cast<const char *>(sqlite3_column_text(statement, 1)); + reinterpret_cast<const char *>(sqlite3_column_text(statement, 1));
ret = g_file_test(dest_filename.native().c_str(), G_FILE_TEST_EXISTS) ret = std::filesystem::exists(dest_filename)
|| get_file(&curl, source_url.c_str(), dest_filename.native().c_str()) == CURLE_OK; || get_file(&curl, source_url.c_str(), dest_filename.native().c_str()) == CURLE_OK;
if (curl) if (curl)
@@ -128,7 +128,7 @@ public:
* *
* Install a package. * Install a package.
**/ **/
void install(JobData *job_data, char *pkg_name) noexcept void install(JobData *job_data, const char *pkg_name) noexcept
{ {
std::filesystem::path pkg_filename; std::filesystem::path pkg_filename;
sqlite3_stmt *statement = nullptr; sqlite3_stmt *statement = nullptr;
+9 -10
View File
@@ -126,7 +126,7 @@ public:
**/ **/
void generate_cache(JobData *job_data, const std::filesystem::path& tmpl) noexcept void generate_cache(JobData *job_data, const std::filesystem::path& tmpl) noexcept
{ {
char **pkg_tokens = nullptr; std::vector<std::string> pkg_tokens;
char *query = nullptr, *filename = nullptr, *location = nullptr, *summary = nullptr, *line; char *query = nullptr, *filename = nullptr, *location = nullptr, *summary = nullptr, *line;
unsigned pkg_compressed = 0, pkg_uncompressed = 0; unsigned pkg_compressed = 0, pkg_uncompressed = 0;
std::uint8_t pkg_name_len; std::uint8_t pkg_name_len;
@@ -241,10 +241,10 @@ public:
{ {
summary = g_strndup(summary + 1, strlen(summary) - 2); /* Without ( ) */ summary = g_strndup(summary + 1, strlen(summary) - 2); /* Without ( ) */
} }
pkg_tokens = split_package_name(filename); pkg_tokens = split_package_name(filename).value();
pkg_name_len = strlen(pkg_tokens[0]); /* Description begins with pkg_name: */ pkg_name_len = pkg_tokens[0].size(); /* Description begins with pkg_name: */
} }
else if (filename && !strncmp(line, pkg_tokens[0], pkg_name_len)) else if (filename && !strncmp(line, pkg_tokens[0].c_str(), pkg_name_len))
{ {
g_string_append(desc, line + pkg_name_len + 1); g_string_append(desc, line + pkg_name_len + 1);
} }
@@ -270,23 +270,22 @@ public:
{ {
statement = update_statement; statement = update_statement;
} }
sqlite3_bind_text(statement, 1, pkg_tokens[3], -1, SQLITE_TRANSIENT); sqlite3_bind_text(statement, 1, pkg_tokens[3].c_str(), -1, SQLITE_TRANSIENT);
sqlite3_bind_text(statement, 2, pkg_tokens[1], -1, SQLITE_TRANSIENT); sqlite3_bind_text(statement, 2, pkg_tokens[1].c_str(), -1, SQLITE_TRANSIENT);
sqlite3_bind_text(statement, 3, pkg_tokens[2], -1, SQLITE_TRANSIENT); sqlite3_bind_text(statement, 3, pkg_tokens[2].c_str(), -1, SQLITE_TRANSIENT);
sqlite3_bind_text(statement, 4, pkg_tokens[4], -1, SQLITE_TRANSIENT); sqlite3_bind_text(statement, 4, pkg_tokens[4].c_str(), -1, SQLITE_TRANSIENT);
sqlite3_bind_text(statement, 5, location, -1, SQLITE_TRANSIENT); sqlite3_bind_text(statement, 5, location, -1, SQLITE_TRANSIENT);
sqlite3_bind_text(statement, 6, summary, -1, SQLITE_TRANSIENT); sqlite3_bind_text(statement, 6, summary, -1, SQLITE_TRANSIENT);
sqlite3_bind_text(statement, 7, desc->str, -1, SQLITE_TRANSIENT); sqlite3_bind_text(statement, 7, desc->str, -1, SQLITE_TRANSIENT);
sqlite3_bind_int(statement, 8, pkg_compressed); sqlite3_bind_int(statement, 8, pkg_compressed);
sqlite3_bind_int(statement, 9, pkg_uncompressed); sqlite3_bind_int(statement, 9, pkg_uncompressed);
sqlite3_bind_text(statement, 10, pkg_tokens[0], -1, SQLITE_TRANSIENT); sqlite3_bind_text(statement, 10, pkg_tokens[0].c_str(), -1, SQLITE_TRANSIENT);
sqlite3_step(statement); sqlite3_step(statement);
sqlite3_clear_bindings(statement); sqlite3_clear_bindings(statement);
sqlite3_reset(statement); sqlite3_reset(statement);
/* Reset for the next package */ /* Reset for the next package */
g_strfreev(pkg_tokens);
g_free(filename); g_free(filename);
g_free(location); g_free(location);
g_free(summary); g_free(summary);
+32 -15
View File
@@ -11,6 +11,9 @@ module;
#include <gio/gio.h> #include <gio/gio.h>
#include <curl/curl.h> #include <curl/curl.h>
#include <sqlite3.h> #include <sqlite3.h>
#include <string>
#include <vector>
#include <optional>
export module katja.utils; export module katja.utils;
@@ -36,12 +39,33 @@ struct JobData
CURL *curl; CURL *curl;
virtual void package(Info info, const char *package_id, const char *summary) = 0; virtual void package(Info info, const char *package_id, const char *summary) = 0;
virtual void files(char **) = 0; virtual void files(const std::vector<std::string>&) = 0;
virtual void details(char *package_id, virtual void details(char *package_id,
const char *group, const char *description, const char *homepage, int uncompressed) = 0; const char *group, const char *description, const char *homepage, int uncompressed) = 0;
virtual void set_percentage(double) = 0; virtual void set_percentage(double) = 0;
}; };
struct DummyJobData final : JobData
{
void package(Info info, const char *package_id, const char *summary) override
{
}
void files(const std::vector<std::string>&) override
{
}
void details(char *package_id,
const char *group, const char *description, const char *homepage, int uncompressed) override
{
}
void set_percentage(double) override
{
}
};
/** /**
* katja::get_file: * katja::get_file:
* @curl: curl easy handle. * @curl: curl easy handle.
@@ -106,37 +130,30 @@ CURLcode get_file(CURL **curl, const char *source_url, const char *dest)
* katja::split_package_name: * katja::split_package_name:
* Got the name of a package, without version-arch-release data. * Got the name of a package, without version-arch-release data.
**/ **/
char **split_package_name(const char *pkg_filename) std::optional<std::vector<std::string>> split_package_name(const std::string& pkg_filename)
{ {
char *pkg_full_name; char *pkg_full_name;
char **pkg_tokens;
g_return_val_if_fail(pkg_filename != nullptr, nullptr); int len = pkg_filename.size();
int len = strlen(pkg_filename);
if (len < 4) if (len < 4)
{ {
return nullptr; return std::nullopt;
} }
std::vector<std::string> pkg_tokens(5);
if (pkg_filename[len - 4] == '.') if (pkg_filename[len - 4] == '.')
{ {
pkg_tokens = static_cast<char **>(g_malloc_n (6, sizeof (char *)));
/* Full name without extension */ /* Full name without extension */
len -= 4; len -= 4;
pkg_full_name = g_strndup(pkg_filename, len); pkg_full_name = g_strndup(pkg_filename.data(), len);
pkg_tokens[3] = g_strdup(pkg_full_name); pkg_tokens[3] = g_strdup(pkg_full_name);
/* The last 3 characters should be the file extension */ /* The last 3 characters should be the file extension */
pkg_tokens[4] = g_strdup(pkg_filename + len + 1); pkg_tokens[4] = g_strdup(pkg_filename.data() + len + 1);
pkg_tokens[5] = nullptr;
} }
else else
{ {
pkg_tokens = static_cast<char **>(g_malloc_n (4, sizeof (char *))); pkg_full_name = g_strdup(pkg_filename.c_str());
pkg_full_name = g_strdup(pkg_filename);
pkg_tokens[3] = nullptr;
} }
/* Reverse all of the bytes in the package filename to get the name, version and the architecture */ /* Reverse all of the bytes in the package filename to get the name, version and the architecture */