summaryrefslogtreecommitdiff
path: root/backend
diff options
context:
space:
mode:
Diffstat (limited to 'backend')
-rw-r--r--backend/CMakeLists.txt38
-rw-r--r--backend/job.cpp (renamed from backend/job.cc)16
-rw-r--r--backend/job.h29
-rw-r--r--backend/pkgtools.cc162
-rw-r--r--backend/pkgtools.cpp191
-rw-r--r--backend/pkgtools.h36
-rw-r--r--backend/slackpkg.cc512
-rw-r--r--backend/slackpkg.cpp518
-rw-r--r--backend/slackpkg.h33
-rw-r--r--backend/utils.cpp (renamed from backend/utils.cc)46
-rw-r--r--backend/utils.h47
11 files changed, 759 insertions, 869 deletions
diff --git a/backend/CMakeLists.txt b/backend/CMakeLists.txt
index 96742e8..259a3c6 100644
--- a/backend/CMakeLists.txt
+++ b/backend/CMakeLists.txt
@@ -2,48 +2,20 @@
# 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/.
+find_package(CURL)
find_package(PkgConfig REQUIRED)
-pkg_check_modules(deps REQUIRED IMPORTED_TARGET glib-2.0 gio-2.0)
+pkg_check_modules(deps REQUIRED IMPORTED_TARGET glib-2.0 gio-2.0 bzip2)
add_library(backend)
target_sources(backend
- INTERFACE job.h utils.h pkgtools.h slackpkg.h
- PRIVATE job.cc utils.cc pkgtools.cc slackpkg.cc
+ PUBLIC FILE_SET all_my_modules
+ TYPE CXX_MODULES FILES job.cpp slackpkg.cpp pkgtools.cpp utils.cpp
)
configure_file(config.h.in ${CMAKE_BINARY_DIR}/generated/config.h)
include_directories(${CMAKE_BINARY_DIR}/generated/)
-target_link_libraries(backend PkgConfig::deps)
-# curl_dep = meson.get_compiler('c').find_library('curl')
-# bzip2_dep = dependency('bzip2')
-
-# packagekit_backend_slack_module = shared_module(
-# 'pk_backend_slack',
-# 'pk-backend-slack.cc',
-# 'utils.cc',
-# 'pkgtools.cc',
-# 'slackpkg.cc',
-# 'dl.cc',
-# 'job.cc',
-# include_directories: packagekit_src_include,
-# dependencies: [
-# packagekit_glib2_dep,
-# curl_dep,
-# gmodule_dep,
-# sqlite3_dep,
-# bzip2_dep,
-# ],
-# cpp_args: [
-# '-DG_LOG_DOMAIN="PackageKit-Slackware"',
-# '-DLOCALSTATEDIR="@0@"'.format(join_paths(get_option('prefix'), get_option('localstatedir'))),
-# '-DLIBDIR="@0@"'.format(join_paths(get_option('prefix'), get_option('libdir'))),
-# '-DSYSCONFDIR="@0@"'.format(get_option('sysconfdir')),
-# ],
-# override_options: ['c_std=c14', 'cpp_std=c++14'],
-# install: true,
-# install_dir: pk_plugin_dir,
-# )
+target_link_libraries(backend PkgConfig::deps CURL::libcurl)
# configure_file(
# input: 'Slackware.conf.in',
diff --git a/backend/job.cc b/backend/job.cpp
index 93842a2..669e02a 100644
--- a/backend/job.cc
+++ b/backend/job.cpp
@@ -3,6 +3,8 @@
* 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>
@@ -11,12 +13,17 @@
#include <iostream>
#include <zlib.h>
#include <curl/curl.h>
-#include "job.h"
-#include "pkgtools.h"
-#include "slackpkg.h"
+#include <glib/gstdio.h>
+#include <sqlite3.h>
+
+export module katja.job;
-using namespace katja;
+import katja.utils;
+import katja.pkgtools;
+import katja.slackpkg;
+namespace katja
+{
static GSList *repos = nullptr;
void pk_backend_initialize(GKeyFile *conf)
@@ -766,3 +773,4 @@ out:
g_rmdir(tmp_dir_name);
g_free(tmp_dir_name);
}
+}
diff --git a/backend/job.h b/backend/job.h
deleted file mode 100644
index a7d9997..0000000
--- a/backend/job.h
+++ /dev/null
@@ -1,29 +0,0 @@
-/*
- * 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/.
- */
-#pragma once
-
-#include <glib/gstdio.h>
-#include "utils.h"
-
-void pk_backend_initialize(GKeyFile *conf);
-void pk_backend_destroy();
-
-katja::JobData *pk_backend_start_job();
-void pk_backend_stop_job(katja::JobData *job_data);
-
-void pk_backend_search_thread(katja::JobData *job_data, GVariant *params, const char *user_data);
-void pk_backend_search_files(katja::JobData *job_data, char **values);
-
-void pk_backend_get_details(katja::JobData *job_data, char **package_ids);
-void pk_backend_resolve(katja::JobData *job_data, char **packages);
-
-void pk_backend_download_packages(katja::JobData *job_data, char **package_ids, const char *directory);
-void pk_backend_install_packages(katja::JobData *job_data, char **package_ids);
-void pk_backend_remove_packages(katja::JobData *job_data, char **package_ids);
-
-void pk_backend_get_updates(katja::JobData *job_data);
-void pk_backend_update_packages(katja::JobData *job_data, char **package_ids);
-void pk_backend_refresh_cache(katja::JobData *job, bool force);
diff --git a/backend/pkgtools.cc b/backend/pkgtools.cc
deleted file mode 100644
index e4c8b41..0000000
--- a/backend/pkgtools.cc
+++ /dev/null
@@ -1,162 +0,0 @@
-/*
- * 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/.
- */
-#include "config.h"
-#include <curl/curl.h>
-#include <sqlite3.h>
-#include "pkgtools.h"
-
-namespace katja
-{
-/**
- * katja::Pkgtools::download:
- * @job_data: A #JobData.
- * @dest_dir_name: Destination directory.
- * @pkg_name: Package name.
- *
- * Download a package.
- *
- * Returns: %TRUE on success, %FALSE otherwise.
- **/
-bool Pkgtools::download(JobData *job_data, const char *dest_dir_name, char *pkg_name) noexcept
-{
- char *dest_filename, *source_url;
- bool ret = false;
- sqlite3_stmt *statement = nullptr;
- CURL *curl = nullptr;
-
- if ((sqlite3_prepare_v2(job_data->db,
- "SELECT location, (full_name || '.' || ext) FROM pkglist "
- "WHERE name LIKE @name AND repo_order = @repo_order",
- -1,
- &statement,
- nullptr) != SQLITE_OK))
- {
- return false;
- }
- sqlite3_bind_text(statement, 1, pkg_name, -1, SQLITE_TRANSIENT);
- sqlite3_bind_int(statement, 2, this->get_order());
-
- if (sqlite3_step(statement) == SQLITE_ROW)
- {
- dest_filename = g_build_filename(dest_dir_name, sqlite3_column_text(statement, 1), nullptr);
- source_url = g_strconcat(this->get_mirror(),
- sqlite3_column_text(statement, 0),
- "/",
- sqlite3_column_text(statement, 1),
- nullptr);
-
- ret = g_file_test(dest_filename, G_FILE_TEST_EXISTS)
- || get_file(&curl, source_url, dest_filename) == CURLE_OK;
-
- if (curl)
- {
- curl_easy_cleanup(curl);
- }
- g_free(source_url);
- g_free(dest_filename);
- }
- sqlite3_finalize(statement);
-
- return ret;
-}
-
-/**
- * katja::Pkgtools::install:
- * @job_data: A #JobData.
- * @pkg_name: Package name.
- *
- * Install a package.
- **/
-void Pkgtools::install(JobData *job_data, char *pkg_name) noexcept
-{
- char *pkg_filename, *cmd_line;
- sqlite3_stmt *statement = nullptr;
-
- if ((sqlite3_prepare_v2(job_data->db,
- "SELECT (full_name || '.' || ext) FROM pkglist "
- "WHERE name LIKE @name AND repo_order = @repo_order",
- -1,
- &statement,
- nullptr) != SQLITE_OK))
- {
- return;
- }
-
- sqlite3_bind_text(statement, 1, pkg_name, -1, SQLITE_TRANSIENT);
- sqlite3_bind_int(statement, 2, this->get_order());
-
- if (sqlite3_step(statement) == SQLITE_ROW)
- {
- pkg_filename = g_build_filename(LOCALSTATEDIR,
- "cache",
- "PackageKit",
- "downloads",
- sqlite3_column_text(statement, 0),
- nullptr);
- cmd_line = g_strconcat("/sbin/upgradepkg --install-new ", pkg_filename, nullptr);
- g_spawn_command_line_sync(cmd_line, nullptr, nullptr, nullptr, nullptr);
- g_free(cmd_line);
-
- g_free(pkg_filename);
- }
- sqlite3_finalize(statement);
-}
-
-Pkgtools::~Pkgtools() noexcept
-{
-}
-
-/**
- * katja::Pkgtools::get_name:
- *
- * Retrieves the repository name.
- *
- * Returns: Repository name.
- **/
-const char *Pkgtools::get_name() const noexcept
-{
- return this->name;
-}
-
-/**
- * katja::Pkgtools::get_mirror:
- *
- * Retrieves the repository mirror.
- *
- * Returns: Repository mirror.
- **/
-const char *Pkgtools::get_mirror() const noexcept
-{
- return this->mirror;
-}
-
-/**
- * katja::Pkgtools::get_order:
- *
- * Retrieves the repository order.
- *
- * Returns: Repository order.
- **/
-guint8 Pkgtools::get_order() const noexcept
-{
- return this->order;
-}
-
-/**
- * katja::Pkgtools:is_blacklisted:
- * @pkg: Package name to check for.
- *
- * Checks whether a package is blacklisted.
- *
- * Returns: %TRUE if the package is blacklisted, %FALSE otherwise.
- **/
-bool Pkgtools::is_blacklisted(const char *pkg) const noexcept
-{
- return this->blacklist
- && g_regex_match (this->blacklist, pkg, static_cast<GRegexMatchFlags>(0), nullptr);
-}
-
-}
diff --git a/backend/pkgtools.cpp b/backend/pkgtools.cpp
new file mode 100644
index 0000000..bb04a10
--- /dev/null
+++ b/backend/pkgtools.cpp
@@ -0,0 +1,191 @@
+/*
+ * 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 <curl/curl.h>
+#include <sqlite3.h>
+#include <cstdint>
+#include <glib-object.h>
+
+export module katja.pkgtools;
+
+import katja.utils;
+
+export namespace katja
+{
+class Pkgtools
+{
+public:
+ /**
+ * katja::Pkgtools::get_name:
+ *
+ * Retrieves the repository name.
+ *
+ * Returns: Repository name.
+ **/
+ const char *get_name() const noexcept
+ {
+ return this->name;
+ }
+
+ /**
+ * katja::Pkgtools::get_mirror:
+ *
+ * Retrieves the repository mirror.
+ *
+ * Returns: Repository mirror.
+ **/
+ const char *get_mirror() const noexcept
+ {
+ return this->mirror;
+ }
+
+ /**
+ * katja::Pkgtools::get_order:
+ *
+ * Retrieves the repository order.
+ *
+ * Returns: Repository order.
+ **/
+ std::uint8_t get_order() const noexcept
+ {
+ return this->order;
+ }
+
+ /**
+ * katja::Pkgtools:is_blacklisted:
+ * @pkg: Package name to check for.
+ *
+ * Checks whether a package is blacklisted.
+ *
+ * Returns: %TRUE if the package is blacklisted, %FALSE otherwise.
+ **/
+ bool is_blacklisted(const char *pkg) const noexcept
+ {
+ return this->blacklist
+ && g_regex_match (this->blacklist, pkg, static_cast<GRegexMatchFlags>(0), nullptr);
+ }
+
+ virtual ~Pkgtools() noexcept
+ {
+ }
+
+ /**
+ * katja::Pkgtools::download:
+ * @job_data: A #JobData.
+ * @dest_dir_name: Destination directory.
+ * @pkg_name: Package name.
+ *
+ * Download a package.
+ *
+ * Returns: %TRUE on success, %FALSE otherwise.
+ **/
+ bool download(JobData *job_data, const char *dest_dir_name, char *pkg_name) noexcept
+ {
+ char *dest_filename, *source_url;
+ bool ret = false;
+ sqlite3_stmt *statement = nullptr;
+ CURL *curl = nullptr;
+
+ if ((sqlite3_prepare_v2(job_data->db,
+ "SELECT location, (full_name || '.' || ext) FROM pkglist "
+ "WHERE name LIKE @name AND repo_order = @repo_order",
+ -1,
+ &statement,
+ nullptr) != SQLITE_OK))
+ {
+ return false;
+ }
+ sqlite3_bind_text(statement, 1, pkg_name, -1, SQLITE_TRANSIENT);
+ sqlite3_bind_int(statement, 2, this->get_order());
+
+ if (sqlite3_step(statement) == SQLITE_ROW)
+ {
+ dest_filename = g_build_filename(dest_dir_name, sqlite3_column_text(statement, 1), nullptr);
+ source_url = g_strconcat(this->get_mirror(),
+ sqlite3_column_text(statement, 0),
+ "/",
+ sqlite3_column_text(statement, 1),
+ nullptr);
+
+ ret = g_file_test(dest_filename, G_FILE_TEST_EXISTS)
+ || get_file(&curl, source_url, dest_filename) == CURLE_OK;
+
+ if (curl)
+ {
+ curl_easy_cleanup(curl);
+ }
+ g_free(source_url);
+ g_free(dest_filename);
+ }
+ sqlite3_finalize(statement);
+
+ return ret;
+ }
+
+ /**
+ * katja::Pkgtools::install:
+ * @job_data: A #JobData.
+ * @pkg_name: Package name.
+ *
+ * Install a package.
+ **/
+ void install(JobData *job_data, char *pkg_name) noexcept
+ {
+ char *pkg_filename, *cmd_line;
+ sqlite3_stmt *statement = nullptr;
+
+ if ((sqlite3_prepare_v2(job_data->db,
+ "SELECT (full_name || '.' || ext) FROM pkglist "
+ "WHERE name LIKE @name AND repo_order = @repo_order",
+ -1,
+ &statement,
+ nullptr) != SQLITE_OK))
+ {
+ return;
+ }
+
+ sqlite3_bind_text(statement, 1, pkg_name, -1, SQLITE_TRANSIENT);
+ sqlite3_bind_int(statement, 2, this->get_order());
+
+ if (sqlite3_step(statement) == SQLITE_ROW)
+ {
+ pkg_filename = g_build_filename(LOCALSTATEDIR,
+ "cache",
+ "PackageKit",
+ "downloads",
+ sqlite3_column_text(statement, 0),
+ nullptr);
+ cmd_line = g_strconcat("/sbin/upgradepkg --install-new ", pkg_filename, nullptr);
+ g_spawn_command_line_sync(cmd_line, nullptr, nullptr, nullptr, nullptr);
+ g_free(cmd_line);
+
+ g_free(pkg_filename);
+ }
+ sqlite3_finalize(statement);
+ }
+
+ virtual GSList *collect_cache_info (const char *tmpl) noexcept = 0;
+ virtual void generate_cache(JobData *job_data, const char *tmpl) noexcept = 0;
+
+protected:
+ char *name = nullptr;
+ char *mirror = nullptr;
+ std::uint8_t order;
+ GRegex *blacklist = nullptr;
+};
+
+/**
+ * katja::cmp_repo:
+ **/
+int cmp_repo(const void *a, const void *b)
+{
+ auto repo = static_cast<const Pkgtools *> (a);
+
+ return g_strcmp0(repo->get_name(), (char *) b);
+}
+}
diff --git a/backend/pkgtools.h b/backend/pkgtools.h
deleted file mode 100644
index 06f1796..0000000
--- a/backend/pkgtools.h
+++ /dev/null
@@ -1,36 +0,0 @@
-/*
- * 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/.
- */
-#pragma once
-
-#include <cstdint>
-#include <glib-object.h>
-#include "utils.h"
-
-namespace katja
-{
-class Pkgtools
-{
-public:
- const char *get_name() const noexcept;
- const char *get_mirror() const noexcept;
- std::uint8_t get_order() const noexcept;
- bool is_blacklisted(const char *pkg) const noexcept;
-
- virtual ~Pkgtools() noexcept;
-
- bool download(JobData *job_data, const char *dest_dir_name, char *pkg_name) noexcept;
- void install(JobData *job_data, char *pkg_name) noexcept;
-
- virtual GSList *collect_cache_info (const char *tmpl) noexcept = 0;
- virtual void generate_cache(JobData *job_data, const char *tmpl) noexcept = 0;
-
-protected:
- char *name = nullptr;
- char *mirror = nullptr;
- std::uint8_t order;
- GRegex *blacklist = nullptr;
-};
-}
diff --git a/backend/slackpkg.cc b/backend/slackpkg.cc
deleted file mode 100644
index a750f2e..0000000
--- a/backend/slackpkg.cc
+++ /dev/null
@@ -1,512 +0,0 @@
-#include <bzlib.h>
-#include <sqlite3.h>
-#include <stdlib.h>
-#include <string.h>
-#include <gio/gio.h>
-#include "slackpkg.h"
-#include "utils.h"
-
-namespace katja
-{
-GHashTable *Slackpkg::cat_map = nullptr;
-
-/*
- * katja::Slackpkg::manifest:
- * @job: a #JobData.
- * @tmpl: temporary directory.
- * @filename: manifest filename
- *
- * Parse the manifest file and save the file list in the database.
- */
-void
-Slackpkg::manifest(JobData *job_data, const char *tmpl, char *filename) noexcept
-{
- FILE *manifest;
- int err, read_len;
- unsigned pos;
- char buf[max_buf_size], *path, *pkg_filename, *rest = nullptr, *start;
- char *full_name = nullptr;
- char **line, **lines;
- BZFILE *manifest_bz2;
- GRegex *pkg_expr = nullptr, *file_expr = nullptr;
- GMatchInfo *match_info;
- sqlite3_stmt *statement = nullptr;
-
- path = g_build_filename(tmpl,
- this->get_name(),
- filename,
- nullptr);
- manifest = fopen(path, "rb");
- g_free(path);
-
- if (!manifest)
- {
- return;
- }
- if (!(manifest_bz2 = BZ2_bzReadOpen(&err, manifest, 0, 0, nullptr, 0)))
- {
- goto out;
- }
-
- /* Prepare regular expressions */
- pkg_expr = g_regex_new("^\\|\\|[[:blank:]]+Package:[[:blank:]]+.+\\/(.+)\\.(t[blxg]z$)?",
- static_cast<GRegexCompileFlags> (G_REGEX_OPTIMIZE | G_REGEX_DUPNAMES),
- static_cast<GRegexMatchFlags> (0),
- nullptr);
- file_expr = g_regex_new("^[-bcdlps][-r][-w][-xsS][-r][-w][-xsS][-r][-w]"
- "[-xtT][[:space:]][^[:space:]]+[[:space:]]+"
- "[[:digit:]]+[[:space:]][[:digit:]-]+[[:space:]]"
- "[[:digit:]:]+[[:space:]](?!install\\/|\\.)(.*)",
- static_cast<GRegexCompileFlags> (G_REGEX_OPTIMIZE | G_REGEX_DUPNAMES),
- static_cast<GRegexMatchFlags> (0),
- nullptr);
- if (!(file_expr) || !(pkg_expr))
- {
- goto out;
- }
-
- /* Prepare SQL statements */
- if (sqlite3_prepare_v2(job_data->db,
- "INSERT INTO filelist (full_name, filename) VALUES (@full_name, @filename)",
- -1,
- &statement,
- nullptr) != SQLITE_OK)
- {
- goto out;
- }
-
- sqlite3_exec(job_data->db, "BEGIN TRANSACTION", nullptr, nullptr, nullptr);
- while ((read_len = BZ2_bzRead(&err, manifest_bz2, buf, max_buf_size - 1)))
- {
- if ((err != BZ_OK) && (err != BZ_STREAM_END))
- {
- break;
- }
- buf[read_len] = '\0';
-
- /* Split the read text into lines */
- lines = g_strsplit(buf, "\n", 0);
- if (rest)
- { /* Add to the first line rest characters from the previous read operation */
- start = lines[0];
- lines[0] = g_strconcat(rest, lines[0], nullptr);
- g_free(start);
- g_free(rest);
- }
- if (err != BZ_STREAM_END) /* The last line can be incomplete */
- {
- pos = g_strv_length(lines) - 1;
- rest = lines[pos];
- lines[pos] = nullptr;
- }
- for (line = lines; *line; line++)
- {
- if (g_regex_match(pkg_expr, *line, static_cast<GRegexMatchFlags> (0), &match_info))
- {
- if (g_match_info_get_match_count(match_info) > 2)
- { /* If the extension matches */
- g_free(full_name);
- full_name = g_match_info_fetch(match_info, 1);
- }
- else
- {
- full_name = nullptr;
- }
- }
- g_match_info_free(match_info);
-
- match_info = nullptr;
- if (full_name && g_regex_match(file_expr, *line, static_cast<GRegexMatchFlags> (0), &match_info))
- {
- pkg_filename = g_match_info_fetch(match_info, 1);
- sqlite3_bind_text(statement, 1, full_name, -1, SQLITE_TRANSIENT);
- sqlite3_bind_text(statement, 2, pkg_filename, -1, SQLITE_TRANSIENT);
- sqlite3_step(statement);
- sqlite3_clear_bindings(statement);
- sqlite3_reset(statement);
- g_free(pkg_filename);
- }
- g_match_info_free(match_info);
- }
- g_strfreev(lines);
- }
-
- sqlite3_exec(job_data->db, "END TRANSACTION", nullptr, nullptr, nullptr);
- g_free(full_name);
- BZ2_bzReadClose(&err, manifest_bz2);
-
-out:
- sqlite3_finalize(statement);
- if (file_expr)
- {
- g_regex_unref(file_expr);
- }
- if (pkg_expr)
- {
- g_regex_unref(pkg_expr);
- }
- fclose(manifest);
-}
-
-/**
- * katja::Slackpkg::collect_cache_info:
- * @tmpl: temporary directory for downloading the files.
- *
- * Download files needed to get the information like the list of packages
- * in available repositories, updates, package descriptions and so on.
- *
- * Returns: List of files needed for building the cache.
- **/
-GSList *
-Slackpkg::collect_cache_info (const char *tmpl) noexcept
-{
- CURL *curl = nullptr;
- char **source_dest;
- GSList *file_list = nullptr;
- GFile *tmp_dir, *repo_tmp_dir;
-
- /* Create the temporary directory for the repository */
- tmp_dir = g_file_new_for_path(tmpl);
- repo_tmp_dir = g_file_get_child(tmp_dir, this->get_name());
- g_file_make_directory(repo_tmp_dir, nullptr, nullptr);
-
- /* Download PACKAGES.TXT. These files are most important, break if some of them couldn't be found */
- for (char **cur_priority = this->priority; *cur_priority; cur_priority++)
- {
- source_dest = static_cast<char **> (g_malloc_n(3, sizeof(char *)));
- source_dest[0] = g_strconcat(this->get_mirror(),
- *cur_priority,
- "/PACKAGES.TXT",
- nullptr);
- source_dest[1] = g_build_filename(tmpl,
- this->get_name(),
- "PACKAGES.TXT",
- nullptr);
- source_dest[2] = nullptr;
-
- if (get_file(&curl, source_dest[0], nullptr) == CURLE_OK)
- {
- file_list = g_slist_prepend(file_list, 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->get_mirror(),
- *cur_priority,
- "/MANIFEST.bz2",
- nullptr);
- source_dest[1] = g_strconcat(tmpl,
- "/", this->get_name(),
- "/", *cur_priority, "-MANIFEST.bz2",
- nullptr);
- source_dest[2] = nullptr;
- if (get_file(&curl, source_dest[0], nullptr) == CURLE_OK)
- {
- file_list = g_slist_prepend(file_list, source_dest);
- }
- else
- {
- g_strfreev(source_dest);
- }
- }
-out:
- g_object_unref(repo_tmp_dir);
- g_object_unref(tmp_dir);
-
- if (curl)
- {
- curl_easy_cleanup(curl);
- }
- return file_list;
-}
-
-/**
- * katja::Slackpkg::generate_cache:
- * @job_data: A #JobData.
- * @tmpl: temporary directory for downloading the files.
- *
- * Download files needed to get the information like the list of packages
- * in available repositories, updates, package descriptions and so on.
- *
- * Returns: List of files needed for building the cache.
- **/
-void
-Slackpkg::generate_cache(JobData *job_data, const char *tmpl) noexcept
-{
- 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;
- GString *desc;
- GFile *list_file;
- GFileInputStream *fin = nullptr;
- GDataInputStream *data_in = nullptr;
- sqlite3_stmt *insert_statement = nullptr, *update_statement = nullptr, *insert_default_statement = nullptr, *statement;
-
- /* Check if the temporary directory for this repository exists, then the file metadata have to be generated */
- packages_txt = g_build_filename(tmpl, this->get_name(), "PACKAGES.TXT", nullptr);
- list_file = g_file_new_for_path(packages_txt);
- fin = g_file_read(list_file, nullptr, nullptr);
- g_object_unref(list_file);
- g_free(packages_txt);
- if (!fin)
- {
- goto out;
- }
- /* Remove the old entries from this repository */
- if (sqlite3_prepare_v2(job_data->db,
- "DELETE FROM repos WHERE repo LIKE @repo",
- -1,
- &statement,
- nullptr) == SQLITE_OK)
- {
- sqlite3_bind_text(statement, 1, this->get_name(), -1, SQLITE_TRANSIENT);
- sqlite3_step(statement);
- sqlite3_finalize(statement);
- }
- if (sqlite3_prepare_v2(job_data->db,
- "INSERT INTO repos (repo_order, repo) VALUES (@repo_order, @repo)",
- -1,
- &statement,
- nullptr) != SQLITE_OK)
- {
- goto out;
- }
- sqlite3_bind_int(statement, 1, this->get_order());
- sqlite3_bind_text(statement, 2, this->get_name(), -1, SQLITE_TRANSIENT);
- sqlite3_step(statement);
- sqlite3_finalize(statement);
-
- /* Insert new records */
- if ((sqlite3_prepare_v2(job_data->db,
- "INSERT OR REPLACE INTO pkglist (full_name, ver, arch, ext, location, "
- "summary, desc, compressed, uncompressed, name, repo_order, cat) "
- "VALUES (@full_name, @ver, @arch, @ext, @location, @summary, "
- "@desc, @compressed, @uncompressed, @name, @repo_order, @cat)",
- -1,
- &insert_statement,
- nullptr) != SQLITE_OK)
- || (sqlite3_prepare_v2(job_data->db,
- "INSERT OR REPLACE INTO pkglist (full_name, ver, arch, ext, location, "
- "summary, desc, compressed, uncompressed, name, repo_order) "
- "VALUES (@full_name, @ver, @arch, @ext, @location, @summary, "
- "@desc, @compressed, @uncompressed, @name, @repo_order)",
- -1,
- &insert_default_statement,
- nullptr) != SQLITE_OK))
- {
- goto out;
- }
- query = sqlite3_mprintf("UPDATE pkglist SET full_name = @full_name, ver = @ver, arch = @arch, "
- "ext = @ext, location = @location, summary = @summary, "
- "desc = @desc, compressed = @compressed, uncompressed = @uncompressed "
- "WHERE name LIKE @name AND repo_order = %u",
- this->get_order());
- if (sqlite3_prepare_v2(job_data->db, query, -1, &update_statement, nullptr) != SQLITE_OK)
- {
- goto out;
- }
-
- data_in = g_data_input_stream_new(G_INPUT_STREAM(fin));
- desc = g_string_new("");
-
- sqlite3_exec(job_data->db, "BEGIN TRANSACTION", nullptr, nullptr, nullptr);
-
- while ((line = g_data_input_stream_read_line(data_in, nullptr, nullptr, nullptr)))
- {
- if (!strncmp(line, "PACKAGE NAME: ", 15))
- {
- filename = g_strdup(line + 15);
- if (this->is_blacklisted (filename))
- {
- g_free(filename);
- filename = nullptr;
- }
- }
- else if (filename && !strncmp(line, "PACKAGE LOCATION: ", 19))
- {
- location = g_strdup(line + 21); /* Exclude ./ at the path beginning */
- }
- else if (filename && !strncmp(line, "PACKAGE SIZE (compressed): ", 28))
- {
- /* Remove the unit (kilobytes) */
- pkg_compressed = atoi(g_strndup(line + 28, strlen(line + 28) - 2)) * 1024;
- }
- else if (filename && !strncmp(line, "PACKAGE SIZE (uncompressed): ", 30))
- {
- /* Remove the unit (kilobytes) */
- pkg_uncompressed = atoi(g_strndup(line + 30, strlen(line + 30) - 2)) * 1024;
- }
- else if (filename && !g_strcmp0(line, "PACKAGE DESCRIPTION:"))
- {
- g_free(line);
- line = g_data_input_stream_read_line(data_in, nullptr, nullptr, nullptr); /* Short description */
-
- summary = g_strstr_len(line, -1, "(");
- if (summary) /* Else summary = nullptr */
- {
- summary = g_strndup(summary + 1, strlen(summary) - 2); /* Without ( ) */
- }
- pkg_tokens = split_package_name(filename);
- pkg_name_len = strlen(pkg_tokens[0]); /* Description begins with pkg_name: */
- }
- else if (filename && !strncmp(line, pkg_tokens[0], pkg_name_len))
- {
- g_string_append(desc, line + pkg_name_len + 1);
- }
- else if (filename && !g_strcmp0(line, ""))
- {
- if (g_strcmp0(location, "patches/packages")) /* Insert a new package */
- {
- /* 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)
- {
- statement = insert_statement;
- sqlite3_bind_text(insert_statement, 12, cat, -1, SQLITE_TRANSIENT);
- }
- else
- {
- statement = insert_default_statement;
- }
- sqlite3_bind_int(statement, 11, this->get_order());
- }
- else /* Update package information if it is a patch */
- {
- statement = update_statement;
- }
- sqlite3_bind_text(statement, 1, pkg_tokens[3], -1, SQLITE_TRANSIENT);
- sqlite3_bind_text(statement, 2, pkg_tokens[1], -1, SQLITE_TRANSIENT);
- sqlite3_bind_text(statement, 3, pkg_tokens[2], -1, SQLITE_TRANSIENT);
- sqlite3_bind_text(statement, 4, pkg_tokens[4], -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, 7, desc->str, -1, SQLITE_TRANSIENT);
- sqlite3_bind_int(statement, 8, pkg_compressed);
- sqlite3_bind_int(statement, 9, pkg_uncompressed);
- sqlite3_bind_text(statement, 10, pkg_tokens[0], -1, SQLITE_TRANSIENT);
-
- sqlite3_step(statement);
- sqlite3_clear_bindings(statement);
- sqlite3_reset(statement);
-
- /* Reset for the next package */
- g_strfreev(pkg_tokens);
- g_free(filename);
- g_free(location);
- g_free(summary);
- filename = location = summary = nullptr;
- g_string_assign(desc, "");
- pkg_compressed = pkg_uncompressed = 0;
- }
- g_free(line);
- }
- sqlite3_exec(job_data->db, "END TRANSACTION", nullptr, nullptr, nullptr);
-
- g_string_free(desc, true);
- g_object_unref(data_in);
-
- /* Parse MANIFEST.bz2 */
- for (char **p = this->priority; *p; p++)
- {
- filename = g_strconcat(*p, "-MANIFEST.bz2", nullptr);
- manifest(job_data, tmpl, filename);
- g_free(filename);
- }
-out:
- sqlite3_finalize(update_statement);
- sqlite3_free(query);
- sqlite3_finalize(insert_default_statement);
- sqlite3_finalize(insert_statement);
-
- if (fin)
- {
- g_object_unref(fin);
- }
-}
-
-Slackpkg::~Slackpkg () noexcept
-{
- if (this->blacklist)
- {
- g_regex_unref (this->blacklist);
- }
-
- g_free (this->name);
- g_free (this->mirror);
- if (this->priority)
- {
- g_strfreev (this->priority);
- }
-}
-
-/**
- * katja::Slackpkg::Slackpkg:
- * @name: Repository name.
- * @mirror: Repository mirror.
- * @order: Repository order.
- * @blacklist: Blacklist.
- * @priority: Groups priority.
- *
- * Constructor.
- *
- * Returns: New #katja::Slackpkg.
- **/
-Slackpkg::Slackpkg (const char *name, const char *mirror,
- std::uint8_t order, const char *blacklist, char **priority) noexcept
-{
- GRegex *regex;
-
- if (blacklist)
- {
- regex = static_cast<GRegex *> (g_regex_new (blacklist,
- G_REGEX_OPTIMIZE, static_cast<GRegexMatchFlags> (0), nullptr));
- }
- else
- {
- regex = nullptr;
- }
-
- this->name = g_strdup (name);
- this->mirror = g_strdup (mirror);
-
- this->order = order;
-
- this->blacklist = regex;
-
- this->priority = 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");
- }
-}
-
-}
diff --git a/backend/slackpkg.cpp b/backend/slackpkg.cpp
new file mode 100644
index 0000000..a053b76
--- /dev/null
+++ b/backend/slackpkg.cpp
@@ -0,0 +1,518 @@
+/*
+ * 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 <bzlib.h>
+#include <sqlite3.h>
+#include <stdlib.h>
+#include <cstdint>
+#include <cstddef>
+#include <string.h>
+#include <gio/gio.h>
+#include <curl/curl.h>
+
+export module katja.slackpkg;
+
+import katja.utils;
+import katja.pkgtools;
+
+export namespace katja
+{
+class Slackpkg final : public Pkgtools
+{
+public:
+ /**
+ * katja::Slackpkg::Slackpkg:
+ * @name: Repository name.
+ * @mirror: Repository mirror.
+ * @order: Repository order.
+ * @blacklist: Blacklist.
+ * @priority: Groups priority.
+ *
+ * Constructor.
+ *
+ * Returns: New #katja::Slackpkg.
+ **/
+ Slackpkg(const char *name, const char *mirror,
+ std::uint8_t order, const char *blacklist, char **priority) noexcept
+ {
+ GRegex *regex;
+
+ if (blacklist)
+ {
+ regex = static_cast<GRegex *>(g_regex_new(blacklist,
+ G_REGEX_OPTIMIZE, static_cast<GRegexMatchFlags>(0), nullptr));
+ }
+ else
+ {
+ regex = nullptr;
+ }
+
+ this->name = g_strdup (name);
+ this->mirror = g_strdup (mirror);
+
+ this->order = order;
+
+ this->blacklist = regex;
+
+ this->priority = 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");
+ }
+ }
+
+ ~Slackpkg() noexcept
+ {
+ if (this->blacklist)
+ {
+ g_regex_unref(this->blacklist);
+ }
+
+ g_free(this->name);
+ g_free(this->mirror);
+ if (this->priority)
+ {
+ g_strfreev(this->priority);
+ }
+ }
+
+ /**
+ * katja::Slackpkg::collect_cache_info:
+ * @tmpl: temporary directory for downloading the files.
+ *
+ * Download files needed to get the information like the list of packages
+ * in available repositories, updates, package descriptions and so on.
+ *
+ * Returns: List of files needed for building the cache.
+ **/
+ GSList *collect_cache_info(const char *tmpl) noexcept
+ {
+ CURL *curl = nullptr;
+ char **source_dest;
+ GSList *file_list = nullptr;
+ GFile *tmp_dir, *repo_tmp_dir;
+
+ /* Create the temporary directory for the repository */
+ tmp_dir = g_file_new_for_path(tmpl);
+ repo_tmp_dir = g_file_get_child(tmp_dir, this->get_name());
+ g_file_make_directory(repo_tmp_dir, nullptr, nullptr);
+
+ /* Download PACKAGES.TXT. These files are most important, break if some of them couldn't be found */
+ for (char **cur_priority = this->priority; *cur_priority; cur_priority++)
+ {
+ source_dest = static_cast<char **> (g_malloc_n(3, sizeof(char *)));
+ source_dest[0] = g_strconcat(this->get_mirror(), *cur_priority, "/PACKAGES.TXT", nullptr);
+ source_dest[1] = g_build_filename(tmpl, this->get_name(), "PACKAGES.TXT", nullptr);
+ source_dest[2] = nullptr;
+
+ if (get_file(&curl, source_dest[0], nullptr) == CURLE_OK)
+ {
+ file_list = g_slist_prepend(file_list, 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->get_mirror(), *cur_priority, "/MANIFEST.bz2", nullptr);
+ source_dest[1] = g_strconcat(tmpl, "/", this->get_name(), "/", *cur_priority, "-MANIFEST.bz2", nullptr);
+ source_dest[2] = nullptr;
+ if (get_file(&curl, source_dest[0], nullptr) == CURLE_OK)
+ {
+ file_list = g_slist_prepend(file_list, source_dest);
+ }
+ else
+ {
+ g_strfreev(source_dest);
+ }
+ }
+ out:
+ g_object_unref(repo_tmp_dir);
+ g_object_unref(tmp_dir);
+
+ if (curl)
+ {
+ curl_easy_cleanup(curl);
+ }
+ return file_list;
+ }
+
+ /**
+ * katja::Slackpkg::generate_cache:
+ * @job_data: A #JobData.
+ * @tmpl: temporary directory for downloading the files.
+ *
+ * Download files needed to get the information like the list of packages
+ * in available repositories, updates, package descriptions and so on.
+ *
+ * Returns: List of files needed for building the cache.
+ **/
+ void generate_cache(JobData *job_data, const char *tmpl) noexcept
+ {
+ 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;
+ GString *desc;
+ GFile *list_file;
+ GFileInputStream *fin = nullptr;
+ GDataInputStream *data_in = nullptr;
+ sqlite3_stmt *insert_statement = nullptr, *update_statement = nullptr, *insert_default_statement = nullptr;
+ sqlite3_stmt *statement;
+
+ /* Check if the temporary directory for this repository exists, then the file metadata have to be generated */
+ packages_txt = g_build_filename(tmpl, this->get_name(), "PACKAGES.TXT", nullptr);
+ list_file = g_file_new_for_path(packages_txt);
+ fin = g_file_read(list_file, nullptr, nullptr);
+ g_object_unref(list_file);
+ g_free(packages_txt);
+ if (!fin)
+ {
+ goto out;
+ }
+ /* Remove the old entries from this repository */
+ if (sqlite3_prepare_v2(job_data->db,
+ "DELETE FROM repos WHERE repo LIKE @repo",
+ -1,
+ &statement,
+ nullptr) == SQLITE_OK)
+ {
+ sqlite3_bind_text(statement, 1, this->get_name(), -1, SQLITE_TRANSIENT);
+ sqlite3_step(statement);
+ sqlite3_finalize(statement);
+ }
+ if (sqlite3_prepare_v2(job_data->db,
+ "INSERT INTO repos (repo_order, repo) VALUES (@repo_order, @repo)",
+ -1,
+ &statement,
+ nullptr) != SQLITE_OK)
+ {
+ goto out;
+ }
+ sqlite3_bind_int(statement, 1, this->get_order());
+ sqlite3_bind_text(statement, 2, this->get_name(), -1, SQLITE_TRANSIENT);
+ sqlite3_step(statement);
+ sqlite3_finalize(statement);
+
+ /* Insert new records */
+ if ((sqlite3_prepare_v2(job_data->db,
+ "INSERT OR REPLACE INTO pkglist (full_name, ver, arch, ext, location, "
+ "summary, desc, compressed, uncompressed, name, repo_order, cat) "
+ "VALUES (@full_name, @ver, @arch, @ext, @location, @summary, "
+ "@desc, @compressed, @uncompressed, @name, @repo_order, @cat)",
+ -1,
+ &insert_statement,
+ nullptr) != SQLITE_OK)
+ || (sqlite3_prepare_v2(job_data->db,
+ "INSERT OR REPLACE INTO pkglist (full_name, ver, arch, ext, location, "
+ "summary, desc, compressed, uncompressed, name, repo_order) "
+ "VALUES (@full_name, @ver, @arch, @ext, @location, @summary, "
+ "@desc, @compressed, @uncompressed, @name, @repo_order)",
+ -1,
+ &insert_default_statement,
+ nullptr) != SQLITE_OK))
+ {
+ goto out;
+ }
+ query = sqlite3_mprintf("UPDATE pkglist SET full_name = @full_name, ver = @ver, arch = @arch, "
+ "ext = @ext, location = @location, summary = @summary, "
+ "desc = @desc, compressed = @compressed, uncompressed = @uncompressed "
+ "WHERE name LIKE @name AND repo_order = %u",
+ this->get_order());
+ if (sqlite3_prepare_v2(job_data->db, query, -1, &update_statement, nullptr) != SQLITE_OK)
+ {
+ goto out;
+ }
+
+ data_in = g_data_input_stream_new(G_INPUT_STREAM(fin));
+ desc = g_string_new("");
+
+ sqlite3_exec(job_data->db, "BEGIN TRANSACTION", nullptr, nullptr, nullptr);
+
+ while ((line = g_data_input_stream_read_line(data_in, nullptr, nullptr, nullptr)))
+ {
+ if (!strncmp(line, "PACKAGE NAME: ", 15))
+ {
+ filename = g_strdup(line + 15);
+ if (this->is_blacklisted(filename))
+ {
+ g_free(filename);
+ filename = nullptr;
+ }
+ }
+ else if (filename && !strncmp(line, "PACKAGE LOCATION: ", 19))
+ {
+ location = g_strdup(line + 21); /* Exclude ./ at the path beginning */
+ }
+ else if (filename && !strncmp(line, "PACKAGE SIZE (compressed): ", 28))
+ {
+ /* Remove the unit (kilobytes) */
+ pkg_compressed = atoi(g_strndup(line + 28, strlen(line + 28) - 2)) * 1024;
+ }
+ else if (filename && !strncmp(line, "PACKAGE SIZE (uncompressed): ", 30))
+ {
+ /* Remove the unit (kilobytes) */
+ pkg_uncompressed = atoi(g_strndup(line + 30, strlen(line + 30) - 2)) * 1024;
+ }
+ else if (filename && !g_strcmp0(line, "PACKAGE DESCRIPTION:"))
+ {
+ g_free(line);
+ line = g_data_input_stream_read_line(data_in, nullptr, nullptr, nullptr); /* Short description */
+
+ summary = g_strstr_len(line, -1, "(");
+ if (summary) /* Else summary = nullptr */
+ {
+ summary = g_strndup(summary + 1, strlen(summary) - 2); /* Without ( ) */
+ }
+ pkg_tokens = split_package_name(filename);
+ pkg_name_len = strlen(pkg_tokens[0]); /* Description begins with pkg_name: */
+ }
+ else if (filename && !strncmp(line, pkg_tokens[0], pkg_name_len))
+ {
+ g_string_append(desc, line + pkg_name_len + 1);
+ }
+ else if (filename && !g_strcmp0(line, ""))
+ {
+ if (g_strcmp0(location, "patches/packages")) /* Insert a new package */
+ {
+ /* 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)
+ {
+ statement = insert_statement;
+ sqlite3_bind_text(insert_statement, 12, cat, -1, SQLITE_TRANSIENT);
+ }
+ else
+ {
+ statement = insert_default_statement;
+ }
+ sqlite3_bind_int(statement, 11, this->get_order());
+ }
+ else /* Update package information if it is a patch */
+ {
+ statement = update_statement;
+ }
+ sqlite3_bind_text(statement, 1, pkg_tokens[3], -1, SQLITE_TRANSIENT);
+ sqlite3_bind_text(statement, 2, pkg_tokens[1], -1, SQLITE_TRANSIENT);
+ sqlite3_bind_text(statement, 3, pkg_tokens[2], -1, SQLITE_TRANSIENT);
+ sqlite3_bind_text(statement, 4, pkg_tokens[4], -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, 7, desc->str, -1, SQLITE_TRANSIENT);
+ sqlite3_bind_int(statement, 8, pkg_compressed);
+ sqlite3_bind_int(statement, 9, pkg_uncompressed);
+ sqlite3_bind_text(statement, 10, pkg_tokens[0], -1, SQLITE_TRANSIENT);
+
+ sqlite3_step(statement);
+ sqlite3_clear_bindings(statement);
+ sqlite3_reset(statement);
+
+ /* Reset for the next package */
+ g_strfreev(pkg_tokens);
+ g_free(filename);
+ g_free(location);
+ g_free(summary);
+ filename = location = summary = nullptr;
+ g_string_assign(desc, "");
+ pkg_compressed = pkg_uncompressed = 0;
+ }
+ g_free(line);
+ }
+ sqlite3_exec(job_data->db, "END TRANSACTION", nullptr, nullptr, nullptr);
+
+ g_string_free(desc, true);
+ g_object_unref(data_in);
+
+ /* Parse MANIFEST.bz2 */
+ for (char **p = this->priority; *p; p++)
+ {
+ filename = g_strconcat(*p, "-MANIFEST.bz2", nullptr);
+ manifest(job_data, tmpl, filename);
+ g_free(filename);
+ }
+ out:
+ sqlite3_finalize(update_statement);
+ sqlite3_free(query);
+ sqlite3_finalize(insert_default_statement);
+ sqlite3_finalize(insert_statement);
+
+ if (fin)
+ {
+ g_object_unref(fin);
+ }
+ }
+
+private:
+ static inline GHashTable *cat_map{ nullptr };
+ static const std::size_t max_buf_size = 8192;
+ char **priority = nullptr;
+
+ /*
+ * katja::Slackpkg::manifest:
+ * @job: a #JobData.
+ * @tmpl: temporary directory.
+ * @filename: manifest filename
+ *
+ * Parse the manifest file and save the file list in the database.
+ */
+
+ void manifest(JobData *job_data, const char *tmpl, char *filename) noexcept
+ {
+ FILE *manifest;
+ int err, read_len;
+ unsigned pos;
+ char buf[max_buf_size], *path, *pkg_filename, *rest = nullptr, *start;
+ char *full_name = nullptr;
+ char **line, **lines;
+ BZFILE *manifest_bz2;
+ GRegex *pkg_expr = nullptr, *file_expr = nullptr;
+ GMatchInfo *match_info;
+ sqlite3_stmt *statement = nullptr;
+
+ path = g_build_filename(tmpl,
+ this->get_name(),
+ filename,
+ nullptr);
+ manifest = fopen(path, "rb");
+ g_free(path);
+
+ if (!manifest)
+ {
+ return;
+ }
+ if (!(manifest_bz2 = BZ2_bzReadOpen(&err, manifest, 0, 0, nullptr, 0)))
+ {
+ goto out;
+ }
+
+ /* Prepare regular expressions */
+ pkg_expr = g_regex_new("^\\|\\|[[:blank:]]+Package:[[:blank:]]+.+\\/(.+)\\.(t[blxg]z$)?",
+ static_cast<GRegexCompileFlags> (G_REGEX_OPTIMIZE | G_REGEX_DUPNAMES),
+ static_cast<GRegexMatchFlags> (0),
+ nullptr);
+ file_expr = g_regex_new("^[-bcdlps][-r][-w][-xsS][-r][-w][-xsS][-r][-w]"
+ "[-xtT][[:space:]][^[:space:]]+[[:space:]]+"
+ "[[:digit:]]+[[:space:]][[:digit:]-]+[[:space:]]"
+ "[[:digit:]:]+[[:space:]](?!install\\/|\\.)(.*)",
+ static_cast<GRegexCompileFlags> (G_REGEX_OPTIMIZE | G_REGEX_DUPNAMES),
+ static_cast<GRegexMatchFlags> (0),
+ nullptr);
+ if (!(file_expr) || !(pkg_expr))
+ {
+ goto out;
+ }
+
+ /* Prepare SQL statements */
+ if (sqlite3_prepare_v2(job_data->db,
+ "INSERT INTO filelist (full_name, filename) VALUES (@full_name, @filename)",
+ -1,
+ &statement,
+ nullptr) != SQLITE_OK)
+ {
+ goto out;
+ }
+
+ sqlite3_exec(job_data->db, "BEGIN TRANSACTION", nullptr, nullptr, nullptr);
+ while ((read_len = BZ2_bzRead(&err, manifest_bz2, buf, max_buf_size - 1)))
+ {
+ if ((err != BZ_OK) && (err != BZ_STREAM_END))
+ {
+ break;
+ }
+ buf[read_len] = '\0';
+
+ /* Split the read text into lines */
+ lines = g_strsplit(buf, "\n", 0);
+ if (rest)
+ { /* Add to the first line rest characters from the previous read operation */
+ start = lines[0];
+ lines[0] = g_strconcat(rest, lines[0], nullptr);
+ g_free(start);
+ g_free(rest);
+ }
+ if (err != BZ_STREAM_END) /* The last line can be incomplete */
+ {
+ pos = g_strv_length(lines) - 1;
+ rest = lines[pos];
+ lines[pos] = nullptr;
+ }
+ for (line = lines; *line; line++)
+ {
+ if (g_regex_match(pkg_expr, *line, static_cast<GRegexMatchFlags> (0), &match_info))
+ {
+ if (g_match_info_get_match_count(match_info) > 2)
+ { /* If the extension matches */
+ g_free(full_name);
+ full_name = g_match_info_fetch(match_info, 1);
+ }
+ else
+ {
+ full_name = nullptr;
+ }
+ }
+ g_match_info_free(match_info);
+
+ match_info = nullptr;
+ if (full_name && g_regex_match(file_expr, *line, static_cast<GRegexMatchFlags> (0), &match_info))
+ {
+ pkg_filename = g_match_info_fetch(match_info, 1);
+ sqlite3_bind_text(statement, 1, full_name, -1, SQLITE_TRANSIENT);
+ sqlite3_bind_text(statement, 2, pkg_filename, -1, SQLITE_TRANSIENT);
+ sqlite3_step(statement);
+ sqlite3_clear_bindings(statement);
+ sqlite3_reset(statement);
+ g_free(pkg_filename);
+ }
+ g_match_info_free(match_info);
+ }
+ g_strfreev(lines);
+ }
+
+ sqlite3_exec(job_data->db, "END TRANSACTION", nullptr, nullptr, nullptr);
+ g_free(full_name);
+ BZ2_bzReadClose(&err, manifest_bz2);
+
+ out:
+ sqlite3_finalize(statement);
+ if (file_expr)
+ {
+ g_regex_unref(file_expr);
+ }
+ if (pkg_expr)
+ {
+ g_regex_unref(pkg_expr);
+ }
+ fclose(manifest);
+ }
+};
+}
diff --git a/backend/slackpkg.h b/backend/slackpkg.h
deleted file mode 100644
index 7cda41d..0000000
--- a/backend/slackpkg.h
+++ /dev/null
@@ -1,33 +0,0 @@
-/*
- * 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/.
- */
-#pragma once
-
-#include <cstdint>
-#include <cstddef>
-#include "pkgtools.h"
-#include "utils.h"
-
-namespace katja
-{
-class Slackpkg final : public Pkgtools
-{
-public:
- Slackpkg (const char *name, const char *mirror,
- std::uint8_t order, const char *blacklist, char **priority) noexcept;
- ~Slackpkg () noexcept;
-
- GSList *collect_cache_info (const char *tmpl) noexcept;
- void generate_cache(JobData *job_data, const char *tmpl) noexcept;
-
-private:
- static GHashTable *cat_map;
- static const std::size_t max_buf_size = 8192;
- char **priority = nullptr;
-
- void manifest(JobData *job_data, const char *tmpl, char *filename) noexcept;
-};
-
-}
diff --git a/backend/utils.cc b/backend/utils.cpp
index b69a780..086fa42 100644
--- a/backend/utils.cc
+++ b/backend/utils.cpp
@@ -3,15 +3,45 @@
* 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 <cstdint>
#include <sqlite3.h>
#include <string.h>
#include <gio/gio.h>
-#include "utils.h"
-#include "pkgtools.h"
+#include <curl/curl.h>
+#include <sqlite3.h>
-namespace katja
+export module katja.utils;
+
+export namespace katja
+{
+enum class Info
{
+ // Error.
+ unknown,
+ // Installed in the same version.
+ installed,
+ // A different version is installed.
+ updating,
+ // Available, but not installed.
+ installing,
+ // Available.
+ available
+};
+
+struct JobData
+{
+ sqlite3 *db;
+ CURL *curl;
+
+ virtual void package(Info info, const char *package_id, const char *summary) = 0;
+ virtual void files(char **) = 0;
+ virtual void details(char *package_id,
+ const char *group, const char *description, const char *homepage, int uncompressed) = 0;
+ virtual void set_percentage(double) = 0;
+};
+
/**
* katja::get_file:
* @curl: curl easy handle.
@@ -217,14 +247,4 @@ Info is_installed(const char *pkg_fullname)
return ret;
}
-/**
- * katja::cmp_repo:
- **/
-int cmp_repo(const void *a, const void *b)
-{
- auto repo = static_cast<const Pkgtools *> (a);
-
- return g_strcmp0(repo->get_name(), (char *) b);
-}
-
}
diff --git a/backend/utils.h b/backend/utils.h
deleted file mode 100644
index b3976b8..0000000
--- a/backend/utils.h
+++ /dev/null
@@ -1,47 +0,0 @@
-/*
- * 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/.
- */
-#pragma once
-
-#include <curl/curl.h>
-#include <sqlite3.h>
-
-namespace katja
-{
-enum class Info
-{
- // Error.
- unknown,
- // Installed in the same version.
- installed,
- // A different version is installed.
- updating,
- // Available, but not installed.
- installing,
- // Available.
- available
-};
-
-struct JobData
-{
- sqlite3 *db;
- CURL *curl;
-
- virtual void package(Info info, const char *package_id, const char *summary) = 0;
- virtual void files(char **) = 0;
- virtual void details(char *package_id,
- const char *group, const char *description, const char *homepage, int uncompressed) = 0;
- virtual void set_percentage(double) = 0;
-};
-
-CURLcode get_file(CURL **curl, char *source_url, char *dest);
-
-char **split_package_name(const char *pkg_filename);
-
-Info is_installed(const char *pkg_fullname);
-
-int cmp_repo(const void *a, const void *b);
-
-}