+776
@@ -0,0 +1,776 @@
|
||||
/*
|
||||
* This Source Code Form is subject to the terms of the Mozilla Public
|
||||
* License, v. 2.0. If a copy of the MPL was not distributed with this
|
||||
* file, You can obtain one at https://mozilla.org/MPL/2.0/.
|
||||
*/
|
||||
module;
|
||||
|
||||
#include "config.h"
|
||||
#include <filesystem>
|
||||
#include <gio/gio.h>
|
||||
#include <cstdint>
|
||||
#include <stdlib.h>
|
||||
#include <iostream>
|
||||
#include <zlib.h>
|
||||
#include <curl/curl.h>
|
||||
#include <glib/gstdio.h>
|
||||
#include <sqlite3.h>
|
||||
|
||||
export module katja.job;
|
||||
|
||||
import katja.utils;
|
||||
import katja.pkgtools;
|
||||
import katja.slackpkg;
|
||||
|
||||
namespace katja
|
||||
{
|
||||
static GSList *repos = nullptr;
|
||||
|
||||
void pk_backend_initialize(GKeyFile *conf)
|
||||
{
|
||||
char *path, **groups;
|
||||
int ret;
|
||||
gushort i;
|
||||
gsize groups_len;
|
||||
GFile *conf_file;
|
||||
GFileInfo *file_info;
|
||||
GKeyFile *key_conf;
|
||||
GError *err = nullptr;
|
||||
void *repo = nullptr;
|
||||
sqlite3 *db;
|
||||
sqlite3_stmt *stmt;
|
||||
|
||||
g_debug("backend: initialize");
|
||||
curl_global_init(CURL_GLOBAL_DEFAULT);
|
||||
|
||||
/* Open the database. We will need it to save the time the configuration file was last modified. */
|
||||
path = g_build_filename(LOCALSTATEDIR, "cache", "PackageKit", "metadata", "metadata.db", nullptr);
|
||||
if (sqlite3_open(path, &db) != SQLITE_OK)
|
||||
{
|
||||
g_error("%s: %s", path, sqlite3_errmsg(db));
|
||||
}
|
||||
g_free(path);
|
||||
|
||||
/* Read the configuration file */
|
||||
key_conf = g_key_file_new();
|
||||
path = g_build_filename(SYSCONFDIR, "PackageKit", "Slackware.conf", nullptr);
|
||||
g_key_file_load_from_file(key_conf, path, G_KEY_FILE_NONE, &err);
|
||||
if (err)
|
||||
{
|
||||
g_error("%s: %s", path, err->message);
|
||||
g_error_free(err);
|
||||
}
|
||||
|
||||
conf_file = g_file_new_for_path(path);
|
||||
if (!(file_info = g_file_query_info(conf_file,
|
||||
"time::modified-usec",
|
||||
G_FILE_QUERY_INFO_NOFOLLOW_SYMLINKS,
|
||||
nullptr,
|
||||
&err)))
|
||||
{
|
||||
g_error("%s", err->message);
|
||||
g_error_free(err);
|
||||
}
|
||||
|
||||
if ((ret = sqlite3_prepare_v2(db,
|
||||
"UPDATE cache_info SET value = ? WHERE key LIKE 'last_modification'",
|
||||
-1,
|
||||
&stmt,
|
||||
nullptr)) == SQLITE_OK) {
|
||||
ret = sqlite3_bind_int(stmt, 1, g_file_info_get_attribute_uint32(file_info, "time::modified-usec"));
|
||||
if (ret == SQLITE_OK)
|
||||
{
|
||||
ret = sqlite3_step(stmt);
|
||||
}
|
||||
sqlite3_finalize(stmt);
|
||||
}
|
||||
if ((ret != SQLITE_OK) && (ret != SQLITE_DONE))
|
||||
{
|
||||
g_error("%s: %s", path, sqlite3_errstr(ret));
|
||||
}
|
||||
else if (!sqlite3_changes(db))
|
||||
{
|
||||
g_error("Failed to update database: %s", path);
|
||||
}
|
||||
|
||||
g_object_unref(file_info);
|
||||
g_object_unref(conf_file);
|
||||
sqlite3_close_v2(db);
|
||||
g_free(path);
|
||||
|
||||
/* Initialize an object for each well-formed repository */
|
||||
groups = g_key_file_get_groups(key_conf, &groups_len);
|
||||
for (i = 0; i < groups_len; i++)
|
||||
{
|
||||
char *blacklist = g_key_file_get_string(key_conf, groups[i], "Blacklist", nullptr);
|
||||
char *mirror = g_key_file_get_string(key_conf, groups[i], "Mirror", nullptr);
|
||||
|
||||
if (g_key_file_has_key(key_conf, groups[i], "Priority", nullptr))
|
||||
{
|
||||
repo = new 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);
|
||||
}
|
||||
g_free(mirror);
|
||||
g_free(blacklist);
|
||||
}
|
||||
g_free(groups);
|
||||
|
||||
g_key_file_free(key_conf);
|
||||
}
|
||||
|
||||
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);
|
||||
curl_global_cleanup();
|
||||
}
|
||||
|
||||
JobData *pk_backend_start_job()
|
||||
{
|
||||
char *db_filename = nullptr;
|
||||
JobData *job_data = g_new0(JobData, 1);
|
||||
|
||||
db_filename = g_build_filename(LOCALSTATEDIR, "cache", "PackageKit", "metadata", "metadata.db", nullptr);
|
||||
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);
|
||||
}
|
||||
else
|
||||
{
|
||||
std::cerr << db_filename << ": " << sqlite3_errmsg(job_data->db) << std::endl;
|
||||
goto out;
|
||||
}
|
||||
|
||||
out:
|
||||
g_free(db_filename);
|
||||
|
||||
return job_data;
|
||||
}
|
||||
|
||||
void pk_backend_stop_job(JobData *job_data)
|
||||
{
|
||||
if (job_data->curl)
|
||||
{
|
||||
curl_easy_cleanup(job_data->curl);
|
||||
}
|
||||
|
||||
sqlite3_close(job_data->db);
|
||||
g_free(job_data);
|
||||
}
|
||||
|
||||
void pk_backend_search_thread(JobData *job_data, GVariant *params, const char *user_data)
|
||||
{
|
||||
char **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, "
|
||||
"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 = "
|
||||
"(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);
|
||||
|
||||
sqlite3_stmt *stmt;
|
||||
if ((sqlite3_prepare_v2(job_data->db, query, -1, &stmt, nullptr) == SQLITE_OK))
|
||||
{
|
||||
/* Now we're ready to output all packages */
|
||||
while (sqlite3_step(stmt) == SQLITE_ROW)
|
||||
{
|
||||
katja::Info info = katja::is_installed(
|
||||
reinterpret_cast<const char *>(sqlite3_column_text(stmt, 2)));
|
||||
|
||||
if ((info == katja::Info::installed || info == katja::Info::updating)
|
||||
&& filters != -1)
|
||||
{
|
||||
job_data->package(katja::Info::installed,
|
||||
reinterpret_cast<const char *>(sqlite3_column_text(stmt, 0)),
|
||||
reinterpret_cast<const char *>(sqlite3_column_text(stmt, 1)));
|
||||
}
|
||||
else if (info == katja::Info::installing && filters != 1)
|
||||
{
|
||||
job_data->package(katja::Info::available,
|
||||
reinterpret_cast<const char *>(sqlite3_column_text(stmt, 0)),
|
||||
reinterpret_cast<const char *>(sqlite3_column_text(stmt, 1)));
|
||||
}
|
||||
}
|
||||
sqlite3_finalize(stmt);
|
||||
}
|
||||
else
|
||||
{
|
||||
std::cerr << sqlite3_errmsg(job_data->db) << std::endl;
|
||||
}
|
||||
sqlite3_free(query);
|
||||
g_free(search);
|
||||
}
|
||||
|
||||
void pk_backend_search_files(JobData *job_data, char **values)
|
||||
{
|
||||
char *search;
|
||||
char *query;
|
||||
sqlite3_stmt *stmt;
|
||||
Info ret;
|
||||
|
||||
search = g_strjoinv("%", values);
|
||||
|
||||
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 "
|
||||
"WHERE f.filename LIKE '%%%q%%' GROUP BY f.full_name", search);
|
||||
|
||||
if ((sqlite3_prepare_v2(job_data->db, query, -1, &stmt, nullptr) == SQLITE_OK))
|
||||
{
|
||||
/* Now we're ready to output all packages */
|
||||
while (sqlite3_step(stmt) == SQLITE_ROW)
|
||||
{
|
||||
ret = is_installed((char*) sqlite3_column_text(stmt, 2));
|
||||
if ((ret == Info::installed) || (ret == Info::updating))
|
||||
{
|
||||
job_data->package(katja::Info::installed,
|
||||
(char*) sqlite3_column_text(stmt, 0),
|
||||
(char*) sqlite3_column_text(stmt, 1));
|
||||
}
|
||||
else if (ret == katja::Info::installing)
|
||||
{
|
||||
job_data->package(katja::Info::available,
|
||||
(char*) sqlite3_column_text(stmt, 0),
|
||||
(char*) sqlite3_column_text(stmt, 1));
|
||||
}
|
||||
}
|
||||
sqlite3_finalize(stmt);
|
||||
}
|
||||
else
|
||||
{
|
||||
std::cerr << sqlite3_errmsg(job_data->db) << std::endl;
|
||||
}
|
||||
sqlite3_free(query);
|
||||
g_free(search);
|
||||
}
|
||||
|
||||
void pk_backend_get_details(JobData *job_data, char **package_ids)
|
||||
{
|
||||
char *homepage = nullptr;
|
||||
char** tokens;
|
||||
gsize i;
|
||||
GString *desc;
|
||||
GRegex *expr;
|
||||
GMatchInfo *match_info;
|
||||
GError *err = nullptr;
|
||||
sqlite3_stmt *stmt;
|
||||
|
||||
if ((sqlite3_prepare_v2(job_data->db,
|
||||
"SELECT p.desc, p.cat, p.uncompressed FROM pkglist AS p NATURAL JOIN repos AS r "
|
||||
"WHERE name LIKE @name AND r.repo LIKE @repo",
|
||||
-1,
|
||||
&stmt,
|
||||
nullptr) != SQLITE_OK)) {
|
||||
std::cerr << sqlite3_errmsg(job_data->db) << std::endl;
|
||||
goto out;
|
||||
}
|
||||
|
||||
tokens = g_strsplit(package_ids[0], ";", 4);
|
||||
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)
|
||||
{
|
||||
goto out;
|
||||
}
|
||||
desc = g_string_new((char *) sqlite3_column_text(stmt, 0));
|
||||
|
||||
/* Regular expression for searching a homepage */
|
||||
expr = g_regex_new("(?:http|ftp):\\/\\/[[:word:]\\/\\-\\.]+[[:word:]\\/](?=\\.?$)",
|
||||
(GRegexCompileFlags)(G_REGEX_OPTIMIZE | G_REGEX_DUPNAMES),
|
||||
(GRegexMatchFlags)(0),
|
||||
&err);
|
||||
if (err)
|
||||
{
|
||||
std::cerr << err->message << std::endl;
|
||||
g_error_free(err);
|
||||
goto out;
|
||||
}
|
||||
if (g_regex_match(expr, desc->str, (GRegexMatchFlags) 0, &match_info))
|
||||
{
|
||||
homepage = g_match_info_fetch(match_info, 0); /* URL */
|
||||
/* Remove the last sentence with the copied URL */
|
||||
for (i = desc->len - 1; i > 0; i--)
|
||||
{
|
||||
if ((desc->str[i - 1] == '.') && (desc->str[i] == ' '))
|
||||
{
|
||||
g_string_truncate(desc, i);
|
||||
break;
|
||||
}
|
||||
}
|
||||
g_match_info_free(match_info);
|
||||
}
|
||||
g_regex_unref(expr);
|
||||
|
||||
/* Ready */
|
||||
job_data->details(package_ids[0],
|
||||
(char *) sqlite3_column_text(stmt, 1),
|
||||
desc->str,
|
||||
homepage,
|
||||
sqlite3_column_int(stmt, 2));
|
||||
|
||||
g_free(homepage);
|
||||
if (desc)
|
||||
{
|
||||
g_string_free(desc, true);
|
||||
}
|
||||
|
||||
out:
|
||||
sqlite3_finalize(stmt);
|
||||
}
|
||||
|
||||
void pk_backend_resolve(JobData *job_data, char **packages)
|
||||
{
|
||||
char **val;
|
||||
sqlite3_stmt *stmt;
|
||||
|
||||
if ((sqlite3_prepare_v2(job_data->db,
|
||||
"SELECT (p1.name || ';' || p1.ver || ';' || p1.arch || ';' || r.repo), p1.summary, "
|
||||
"p1.full_name FROM pkglist AS p1 NATURAL JOIN repos AS r "
|
||||
"WHERE p1.name LIKE @search AND p1.repo_order = "
|
||||
"(SELECT MIN(p2.repo_order) FROM pkglist AS p2 WHERE p2.name = p1.name GROUP BY p2.name)",
|
||||
-1,
|
||||
&stmt,
|
||||
nullptr) == SQLITE_OK)) {
|
||||
/* Output packages matching each pattern */
|
||||
for (val = packages; *val; val++)
|
||||
{
|
||||
sqlite3_bind_text(stmt, 1, *val, -1, SQLITE_TRANSIENT);
|
||||
|
||||
while (sqlite3_step(stmt) == SQLITE_ROW)
|
||||
{
|
||||
job_data->package(katja::Info::available,
|
||||
(char *) sqlite3_column_text(stmt, 0),
|
||||
(char *) sqlite3_column_text(stmt, 1));
|
||||
}
|
||||
|
||||
sqlite3_clear_bindings(stmt);
|
||||
sqlite3_reset(stmt);
|
||||
}
|
||||
sqlite3_finalize(stmt);
|
||||
}
|
||||
else
|
||||
{
|
||||
std::cerr << sqlite3_errmsg(job_data->db) << std::endl;
|
||||
}
|
||||
}
|
||||
|
||||
void pk_backend_download_packages(JobData *job_data, char **package_ids, const char *directory)
|
||||
{
|
||||
char *path, *to_strv[] = {nullptr, nullptr};
|
||||
unsigned i;
|
||||
sqlite3_stmt *stmt;
|
||||
|
||||
if ((sqlite3_prepare_v2(job_data->db,
|
||||
"SELECT summary, (full_name || '.' || ext) FROM pkglist NATURAL JOIN repos "
|
||||
"WHERE name LIKE @name AND ver LIKE @ver AND arch LIKE @arch AND repo LIKE @repo",
|
||||
-1,
|
||||
&stmt,
|
||||
nullptr) != SQLITE_OK))
|
||||
{
|
||||
std::cerr << sqlite3_errmsg(job_data->db) << std::endl;
|
||||
goto out;
|
||||
}
|
||||
|
||||
for (i = 0; package_ids[i]; ++i)
|
||||
{
|
||||
char **tokens = g_strsplit(package_ids[i], ";", 4);
|
||||
|
||||
sqlite3_bind_text(stmt, 1, tokens[0], -1, SQLITE_TRANSIENT);
|
||||
sqlite3_bind_text(stmt, 2, tokens[1], -1, SQLITE_TRANSIENT);
|
||||
sqlite3_bind_text(stmt, 3, tokens[2], -1, SQLITE_TRANSIENT);
|
||||
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)))
|
||||
{
|
||||
static_cast<Pkgtools *>(repo->data)->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);
|
||||
g_free(path);
|
||||
}
|
||||
}
|
||||
sqlite3_clear_bindings(stmt);
|
||||
sqlite3_reset(stmt);
|
||||
g_strfreev(tokens);
|
||||
}
|
||||
|
||||
out:
|
||||
sqlite3_finalize(stmt);
|
||||
}
|
||||
|
||||
void pk_backend_install_packages(JobData *job_data, char **package_ids)
|
||||
{
|
||||
char *dest_dir_name;
|
||||
unsigned i;
|
||||
gdouble percent_step;
|
||||
GSList *install_list = nullptr, *l;
|
||||
sqlite3_stmt *pkglist_stmt = nullptr, *collection_stmt = nullptr;
|
||||
|
||||
if ((sqlite3_prepare_v2(job_data->db,
|
||||
"SELECT summary, cat FROM pkglist NATURAL JOIN repos "
|
||||
"WHERE name LIKE @name AND ver LIKE @ver AND arch LIKE @arch AND repo LIKE @repo",
|
||||
-1,
|
||||
&pkglist_stmt,
|
||||
nullptr) != SQLITE_OK) ||
|
||||
(sqlite3_prepare_v2(job_data->db,
|
||||
"SELECT (c.collection_pkg || ';' || p.ver || ';' || p.arch || ';' || r.repo), p.summary, "
|
||||
"p.full_name, p.ext FROM collections AS c "
|
||||
"JOIN pkglist AS p ON c.collection_pkg = p.name "
|
||||
"JOIN repos AS r ON p.repo_order = r.repo_order "
|
||||
"WHERE c.name LIKE @name AND r.repo LIKE @repo",
|
||||
-1,
|
||||
&collection_stmt,
|
||||
nullptr) != SQLITE_OK))
|
||||
{
|
||||
std::cerr << sqlite3_errmsg(job_data->db) << std::endl;
|
||||
goto out;
|
||||
}
|
||||
|
||||
for (i = 0; package_ids[i]; i++)
|
||||
{
|
||||
char **tokens = g_strsplit(package_ids[i], ";", 4);
|
||||
sqlite3_bind_text(pkglist_stmt, 1, tokens[0], -1, SQLITE_TRANSIENT);
|
||||
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, 4, tokens[3], -1, SQLITE_TRANSIENT);
|
||||
|
||||
if (sqlite3_step(pkglist_stmt) == SQLITE_ROW)
|
||||
{
|
||||
/* If it isn't a collection */
|
||||
if (g_strcmp0((char *) sqlite3_column_text(pkglist_stmt, 1), "collections"))
|
||||
{
|
||||
install_list = g_slist_append(install_list, g_strdup(package_ids[i]));
|
||||
}
|
||||
else
|
||||
{
|
||||
sqlite3_bind_text(collection_stmt, 1, tokens[0], -1, SQLITE_TRANSIENT);
|
||||
sqlite3_bind_text(collection_stmt, 2, tokens[3], -1, SQLITE_TRANSIENT);
|
||||
|
||||
while (sqlite3_step(collection_stmt) == SQLITE_ROW)
|
||||
{
|
||||
katja::Info ret = is_installed((char*) sqlite3_column_text(collection_stmt, 2));
|
||||
if ((ret == Info::installing) || (ret == Info::updating))
|
||||
{
|
||||
install_list = g_slist_append(install_list,
|
||||
g_strdup((char *) sqlite3_column_text(collection_stmt, 0)));
|
||||
}
|
||||
}
|
||||
sqlite3_clear_bindings(collection_stmt);
|
||||
sqlite3_reset(collection_stmt);
|
||||
}
|
||||
}
|
||||
|
||||
sqlite3_clear_bindings(pkglist_stmt);
|
||||
sqlite3_reset(pkglist_stmt);
|
||||
g_strfreev(tokens);
|
||||
}
|
||||
|
||||
if (install_list)
|
||||
{
|
||||
/* / 2 means total percentage for installing and for downloading */
|
||||
percent_step = 100.0 / g_slist_length(install_list) / 2;
|
||||
|
||||
/* Download the packages */
|
||||
dest_dir_name = g_build_filename(LOCALSTATEDIR, "cache", "PackageKit", "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);
|
||||
|
||||
if (repo)
|
||||
{
|
||||
static_cast<Pkgtools *>(repo->data)->download(job_data, dest_dir_name, tokens[0]);
|
||||
}
|
||||
g_strfreev(tokens);
|
||||
}
|
||||
g_free(dest_dir_name);
|
||||
|
||||
/* 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);
|
||||
|
||||
if (repo)
|
||||
{
|
||||
static_cast<Pkgtools *>(repo->data)->install(job_data, tokens[0]);
|
||||
}
|
||||
g_strfreev(tokens);
|
||||
}
|
||||
}
|
||||
g_slist_free_full(install_list, g_free);
|
||||
|
||||
out:
|
||||
sqlite3_finalize(pkglist_stmt);
|
||||
sqlite3_finalize(collection_stmt);
|
||||
}
|
||||
|
||||
void pk_backend_remove_packages(JobData* job_data, char **package_ids)
|
||||
{
|
||||
char *cmd_line;
|
||||
unsigned i;
|
||||
gdouble 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);
|
||||
cmd_line = g_strconcat("/sbin/removepkg ", tokens[0], nullptr);
|
||||
|
||||
/* Pkgtools return always 0 */
|
||||
g_spawn_command_line_sync(cmd_line, nullptr, nullptr, nullptr, &err);
|
||||
|
||||
g_free(cmd_line);
|
||||
g_strfreev(tokens);
|
||||
|
||||
if (err)
|
||||
{
|
||||
std::cerr << err->message << std::endl;
|
||||
g_error_free(err);
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
job_data->set_percentage(100);
|
||||
}
|
||||
}
|
||||
|
||||
void pk_backend_get_updates(JobData *job_data)
|
||||
{
|
||||
char *pkg_id, *full_name, *desc;
|
||||
const char *pkg_metadata_filename;
|
||||
GFile *pkg_metadata_dir;
|
||||
GFileEnumerator *pkg_metadata_enumerator;
|
||||
GFileInfo *pkg_metadata_file_info;
|
||||
GError *err = nullptr;
|
||||
sqlite3_stmt *stmt;
|
||||
|
||||
if ((sqlite3_prepare_v2(job_data->db,
|
||||
"SELECT p1.full_name, p1.name, p1.ver, p1.arch, r.repo, p1.summary, p1.ext "
|
||||
"FROM pkglist AS p1 NATURAL JOIN repos AS r "
|
||||
"WHERE p1.name LIKE @name AND p1.repo_order = "
|
||||
"(SELECT MIN(p2.repo_order) FROM pkglist AS p2 WHERE p2.name = p1.name GROUP BY p2.name)",
|
||||
-1,
|
||||
&stmt,
|
||||
nullptr) != SQLITE_OK))
|
||||
{
|
||||
std::cerr << sqlite3_errmsg(job_data->db) << std::endl;
|
||||
goto out;
|
||||
}
|
||||
|
||||
/* Read the package metadata directory and comprare all installed packages with ones in the cache */
|
||||
pkg_metadata_dir = g_file_new_for_path("/var/log/packages");
|
||||
pkg_metadata_enumerator = g_file_enumerate_children(pkg_metadata_dir, "standard::name",
|
||||
G_FILE_QUERY_INFO_NONE,
|
||||
nullptr,
|
||||
&err);
|
||||
g_object_unref(pkg_metadata_dir);
|
||||
if (err)
|
||||
{
|
||||
std::cerr << "/var/log/packages: " << err->message << std::endl;
|
||||
g_error_free(err);
|
||||
goto out;
|
||||
}
|
||||
|
||||
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);
|
||||
tokens = split_package_name(pkg_metadata_filename);
|
||||
|
||||
/* Select the package from the database */
|
||||
sqlite3_bind_text(stmt, 1, tokens[0], -1, SQLITE_TRANSIENT);
|
||||
|
||||
/* 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))
|
||||
{
|
||||
|
||||
full_name = g_strdup((char *) sqlite3_column_text(stmt, 0));
|
||||
|
||||
if (g_strcmp0(pkg_metadata_filename, full_name))
|
||||
{ /* Update available */
|
||||
pkg_id = g_strjoin(";",
|
||||
(char *) sqlite3_column_text(stmt, 1),
|
||||
(char *) sqlite3_column_text(stmt, 2),
|
||||
(char *) sqlite3_column_text(stmt, 3),
|
||||
(char *) sqlite3_column_text(stmt, 4),
|
||||
nullptr);
|
||||
desc = g_strdup((char *) sqlite3_column_text(stmt, 5));
|
||||
|
||||
job_data->package(katja::Info::updating, pkg_id, desc);
|
||||
|
||||
g_free(desc);
|
||||
g_free(pkg_id);
|
||||
}
|
||||
g_free(full_name);
|
||||
}
|
||||
|
||||
sqlite3_clear_bindings(stmt);
|
||||
sqlite3_reset(stmt);
|
||||
|
||||
g_strfreev(tokens);
|
||||
g_object_unref(pkg_metadata_file_info);
|
||||
}
|
||||
g_object_unref(pkg_metadata_enumerator);
|
||||
|
||||
out:
|
||||
sqlite3_finalize(stmt);
|
||||
}
|
||||
|
||||
void pk_backend_update_packages(JobData *job_data, char **package_ids)
|
||||
{
|
||||
char *dest_dir_name, *cmd_line;
|
||||
unsigned i;
|
||||
|
||||
/* Download the packages */
|
||||
dest_dir_name = g_build_filename(LOCALSTATEDIR, "cache", "PackageKit", "downloads", nullptr);
|
||||
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);
|
||||
|
||||
if (repo)
|
||||
{
|
||||
static_cast<Pkgtools *>(repo->data)->download(job_data, dest_dir_name, tokens[0]);
|
||||
}
|
||||
g_strfreev(tokens);
|
||||
}
|
||||
g_free(dest_dir_name);
|
||||
|
||||
/* Install the packages */
|
||||
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);
|
||||
|
||||
if (repo)
|
||||
{
|
||||
static_cast<Pkgtools *>(repo->data)->install(job_data, tokens[0]);
|
||||
}
|
||||
g_strfreev(tokens);
|
||||
}
|
||||
}
|
||||
|
||||
void pk_backend_refresh_cache(JobData *job_data, bool force)
|
||||
{
|
||||
char *tmp_dir_name, *db_err, *path = nullptr;
|
||||
int ret;
|
||||
GSList *file_list = nullptr;
|
||||
GFile *db_file = nullptr;
|
||||
GFileInfo *file_info = nullptr;
|
||||
GError *err = nullptr;
|
||||
sqlite3_stmt *stmt = nullptr;
|
||||
|
||||
/* Create temporary directory */
|
||||
tmp_dir_name = g_dir_make_tmp("PackageKit.XXXXXX", &err);
|
||||
if (!tmp_dir_name)
|
||||
{
|
||||
std::cerr << err->message << std::endl;
|
||||
g_error_free(err);
|
||||
return;
|
||||
}
|
||||
|
||||
/* Force the complete cache refresh if the read configuration file is newer than the metadata cache */
|
||||
if (!force)
|
||||
{
|
||||
path = g_build_filename(LOCALSTATEDIR, "cache", "PackageKit", "metadata", "metadata.db", nullptr);
|
||||
db_file = g_file_new_for_path(path);
|
||||
file_info = g_file_query_info(db_file, "time::modified-usec", G_FILE_QUERY_INFO_NOFOLLOW_SYMLINKS, nullptr, &err);
|
||||
if (err)
|
||||
{
|
||||
std::cerr << path << ": " << err->message;
|
||||
g_error_free(err);
|
||||
goto out;
|
||||
}
|
||||
ret = sqlite3_prepare_v2(job_data->db,
|
||||
"SELECT value FROM cache_info WHERE key LIKE 'last_modification'",
|
||||
-1,
|
||||
&stmt,
|
||||
nullptr);
|
||||
if ((ret != SQLITE_OK) || ((ret = sqlite3_step(stmt)) != SQLITE_ROW))
|
||||
{
|
||||
std::cerr << path << ": " << sqlite3_errstr(ret) << std::endl;
|
||||
goto out;
|
||||
}
|
||||
if ((std::uint32_t) sqlite3_column_int(stmt, 0) > g_file_info_get_attribute_uint32(file_info, "time::modified-usec"))
|
||||
{
|
||||
force = true;
|
||||
}
|
||||
}
|
||||
if (force) /* It should empty all tables */
|
||||
{
|
||||
if (sqlite3_exec(job_data->db, "DELETE FROM repos", nullptr, 0, &db_err) != SQLITE_OK)
|
||||
{
|
||||
std::cerr << db_err << std::endl;
|
||||
sqlite3_free(db_err);
|
||||
goto out;
|
||||
}
|
||||
}
|
||||
|
||||
// Get list of files that should be downloaded.
|
||||
for (GSList *l = repos; l; l = g_slist_next(l))
|
||||
{
|
||||
file_list = g_slist_concat(file_list,
|
||||
static_cast<Pkgtools *>(l->data)->collect_cache_info(tmp_dir_name));
|
||||
}
|
||||
|
||||
/* Download repository */
|
||||
for (GSList *l = file_list; l; l = g_slist_next(l))
|
||||
{
|
||||
get_file(&job_data->curl, static_cast<char **>(l->data)[0],
|
||||
static_cast<char **>(l->data)[1]);
|
||||
}
|
||||
g_slist_free_full(file_list, (GDestroyNotify) g_strfreev);
|
||||
|
||||
/* Refresh cache */
|
||||
for (GSList *l = repos; l; l = g_slist_next(l))
|
||||
{
|
||||
static_cast<Pkgtools *>(l->data)->generate_cache(job_data, tmp_dir_name);
|
||||
}
|
||||
|
||||
out:
|
||||
sqlite3_finalize(stmt);
|
||||
if (file_info)
|
||||
{
|
||||
g_object_unref(file_info);
|
||||
}
|
||||
if (db_file)
|
||||
{
|
||||
g_object_unref(db_file);
|
||||
}
|
||||
g_free(path);
|
||||
|
||||
std::filesystem::remove_all(tmp_dir_name);
|
||||
g_rmdir(tmp_dir_name);
|
||||
g_free(tmp_dir_name);
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user