@@ -15,7 +15,8 @@ jobs:
|
|||||||
shell: ash {0}
|
shell: ash {0}
|
||||||
run: |
|
run: |
|
||||||
apk -U upgrade
|
apk -U upgrade
|
||||||
apk add --no-cache git bash cmake build-base ninja-is-really-ninja boost-dev toml11
|
apk add --no-cache git bash cmake build-base ninja-is-really-ninja boost-dev toml11 \
|
||||||
|
glib-dev bzip2-dev curl-dev
|
||||||
- uses: actions/checkout@v4
|
- uses: actions/checkout@v4
|
||||||
- name: Build
|
- name: Build
|
||||||
run: |
|
run: |
|
||||||
|
|||||||
+5
-33
@@ -2,48 +2,20 @@
|
|||||||
# License, v. 2.0. If a copy of the MPL was not distributed with this
|
# 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/.
|
# file, You can obtain one at https://mozilla.org/MPL/2.0/.
|
||||||
|
|
||||||
|
find_package(CURL)
|
||||||
find_package(PkgConfig REQUIRED)
|
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)
|
add_library(backend)
|
||||||
target_sources(backend
|
target_sources(backend
|
||||||
INTERFACE job.h utils.h pkgtools.h slackpkg.h
|
PUBLIC FILE_SET all_my_modules
|
||||||
PRIVATE job.cc utils.cc pkgtools.cc slackpkg.cc
|
TYPE CXX_MODULES FILES job.cpp slackpkg.cpp pkgtools.cpp utils.cpp
|
||||||
)
|
)
|
||||||
|
|
||||||
configure_file(config.h.in ${CMAKE_BINARY_DIR}/generated/config.h)
|
configure_file(config.h.in ${CMAKE_BINARY_DIR}/generated/config.h)
|
||||||
include_directories(${CMAKE_BINARY_DIR}/generated/)
|
include_directories(${CMAKE_BINARY_DIR}/generated/)
|
||||||
|
|
||||||
target_link_libraries(backend PkgConfig::deps)
|
target_link_libraries(backend PkgConfig::deps CURL::libcurl)
|
||||||
# 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,
|
|
||||||
# )
|
|
||||||
|
|
||||||
# configure_file(
|
# configure_file(
|
||||||
# input: 'Slackware.conf.in',
|
# input: 'Slackware.conf.in',
|
||||||
|
|||||||
@@ -3,6 +3,8 @@
|
|||||||
* License, v. 2.0. If a copy of the MPL was not distributed with this
|
* 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/.
|
* file, You can obtain one at https://mozilla.org/MPL/2.0/.
|
||||||
*/
|
*/
|
||||||
|
module;
|
||||||
|
|
||||||
#include "config.h"
|
#include "config.h"
|
||||||
#include <filesystem>
|
#include <filesystem>
|
||||||
#include <gio/gio.h>
|
#include <gio/gio.h>
|
||||||
@@ -11,12 +13,17 @@
|
|||||||
#include <iostream>
|
#include <iostream>
|
||||||
#include <zlib.h>
|
#include <zlib.h>
|
||||||
#include <curl/curl.h>
|
#include <curl/curl.h>
|
||||||
#include "job.h"
|
#include <glib/gstdio.h>
|
||||||
#include "pkgtools.h"
|
#include <sqlite3.h>
|
||||||
#include "slackpkg.h"
|
|
||||||
|
|
||||||
using namespace katja;
|
export module katja.job;
|
||||||
|
|
||||||
|
import katja.utils;
|
||||||
|
import katja.pkgtools;
|
||||||
|
import katja.slackpkg;
|
||||||
|
|
||||||
|
namespace katja
|
||||||
|
{
|
||||||
static GSList *repos = nullptr;
|
static GSList *repos = nullptr;
|
||||||
|
|
||||||
void pk_backend_initialize(GKeyFile *conf)
|
void pk_backend_initialize(GKeyFile *conf)
|
||||||
@@ -766,3 +773,4 @@ out:
|
|||||||
g_rmdir(tmp_dir_name);
|
g_rmdir(tmp_dir_name);
|
||||||
g_free(tmp_dir_name);
|
g_free(tmp_dir_name);
|
||||||
}
|
}
|
||||||
|
}
|
||||||
@@ -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);
|
|
||||||
@@ -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);
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
|
||||||
@@ -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);
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -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;
|
|
||||||
};
|
|
||||||
}
|
|
||||||
@@ -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");
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
|
||||||
@@ -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);
|
||||||
|
}
|
||||||
|
};
|
||||||
|
}
|
||||||
@@ -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;
|
|
||||||
};
|
|
||||||
|
|
||||||
}
|
|
||||||
@@ -3,15 +3,45 @@
|
|||||||
* License, v. 2.0. If a copy of the MPL was not distributed with this
|
* 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/.
|
* file, You can obtain one at https://mozilla.org/MPL/2.0/.
|
||||||
*/
|
*/
|
||||||
|
module;
|
||||||
|
|
||||||
#include <cstdint>
|
#include <cstdint>
|
||||||
#include <sqlite3.h>
|
#include <sqlite3.h>
|
||||||
#include <string.h>
|
#include <string.h>
|
||||||
#include <gio/gio.h>
|
#include <gio/gio.h>
|
||||||
#include "utils.h"
|
#include <curl/curl.h>
|
||||||
#include "pkgtools.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:
|
* katja::get_file:
|
||||||
* @curl: curl easy handle.
|
* @curl: curl easy handle.
|
||||||
@@ -217,14 +247,4 @@ Info is_installed(const char *pkg_fullname)
|
|||||||
return ret;
|
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);
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
}
|
||||||
@@ -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);
|
|
||||||
|
|
||||||
}
|
|
||||||
Reference in New Issue
Block a user