This commit is contained in:
15
backend/Slackware.conf.in
Normal file
15
backend/Slackware.conf.in
Normal file
@@ -0,0 +1,15 @@
|
|||||||
|
# It is a sample configuration.
|
||||||
|
|
||||||
|
[slackware]
|
||||||
|
Mirror=http://mirrors.slackware.com/slackware/@pkgmain@-14.2/
|
||||||
|
Priority=patches;@pkgmain@;extra;pasture;testing
|
||||||
|
#Blacklist=
|
||||||
|
|
||||||
|
|
||||||
|
#[dropline]
|
||||||
|
#Mirror=http://dl.flevum.de/slackware/3.10/
|
||||||
|
#IndexFile=http://dl.flevum.de/slackware/3.10/DroplineFiles3.10
|
||||||
|
|
||||||
|
#[dropline]
|
||||||
|
#Mirror=http://dl.flevum.de/slackware64/3.10/
|
||||||
|
#IndexFile=http://dl.flevum.de/slackware64/3.10/Dropline64Files3.10
|
||||||
288
backend/dl.cc
Normal file
288
backend/dl.cc
Normal file
@@ -0,0 +1,288 @@
|
|||||||
|
#include <sqlite3.h>
|
||||||
|
#include <stdlib.h>
|
||||||
|
#include "dl.h"
|
||||||
|
#include "utils.h"
|
||||||
|
|
||||||
|
namespace slack {
|
||||||
|
|
||||||
|
/**
|
||||||
|
* slack::Dl::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 *
|
||||||
|
Dl::collect_cache_info (const gchar *tmpl) noexcept
|
||||||
|
{
|
||||||
|
CURL *curl = NULL;
|
||||||
|
GSList *file_list = NULL;
|
||||||
|
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, NULL, NULL);
|
||||||
|
|
||||||
|
/* There is no ChangeLog yet to check if there are updates or not. Just mark the index file for download */
|
||||||
|
auto source_dest = static_cast<gchar **> (g_malloc_n(3, sizeof(gchar *)));
|
||||||
|
source_dest[0] = g_strdup(this->index_file);
|
||||||
|
source_dest[1] = g_build_filename(tmpl,
|
||||||
|
this->get_name (),
|
||||||
|
"IndexFile",
|
||||||
|
NULL);
|
||||||
|
source_dest[2] = NULL;
|
||||||
|
/* Check if the remote file can be found */
|
||||||
|
if (get_file(&curl, source_dest[0], NULL))
|
||||||
|
{
|
||||||
|
g_strfreev(source_dest);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
file_list = g_slist_append(file_list, source_dest);
|
||||||
|
}
|
||||||
|
g_object_unref(repo_tmp_dir);
|
||||||
|
g_object_unref(tmp_dir);
|
||||||
|
|
||||||
|
if (curl)
|
||||||
|
{
|
||||||
|
curl_easy_cleanup(curl);
|
||||||
|
}
|
||||||
|
return file_list;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* slack::Dl::generate_cache:
|
||||||
|
* @job: A #PkBackendJob.
|
||||||
|
* @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
|
||||||
|
Dl::generate_cache(PkBackendJob *job, const gchar *tmpl) noexcept
|
||||||
|
{
|
||||||
|
gchar **line_tokens, **pkg_tokens, *line, *collection_name = NULL, *list_filename;
|
||||||
|
gboolean skip = FALSE;
|
||||||
|
GFile *list_file;
|
||||||
|
GFileInputStream *fin;
|
||||||
|
GDataInputStream *data_in = NULL;
|
||||||
|
sqlite3_stmt *stmt = NULL;
|
||||||
|
auto job_data = static_cast<JobData *> (pk_backend_job_get_user_data(job));
|
||||||
|
|
||||||
|
/* Check if the temporary directory for this repository exists. If so the file metadata have to be generated */
|
||||||
|
list_filename = g_build_filename(tmpl,
|
||||||
|
this->get_name (),
|
||||||
|
"IndexFile",
|
||||||
|
NULL);
|
||||||
|
list_file = g_file_new_for_path(list_filename);
|
||||||
|
if (!(fin = g_file_read(list_file, NULL, NULL)))
|
||||||
|
{
|
||||||
|
goto out;
|
||||||
|
}
|
||||||
|
data_in = g_data_input_stream_new(G_INPUT_STREAM(fin));
|
||||||
|
|
||||||
|
/* Remove the old entries from this repository */
|
||||||
|
if (sqlite3_prepare_v2(job_data->db,
|
||||||
|
"DELETE FROM repos WHERE repo LIKE @repo",
|
||||||
|
-1,
|
||||||
|
&stmt,
|
||||||
|
NULL) == SQLITE_OK) {
|
||||||
|
sqlite3_bind_text(stmt, 1, this->get_name (), -1, SQLITE_TRANSIENT);
|
||||||
|
sqlite3_step(stmt);
|
||||||
|
sqlite3_finalize(stmt);
|
||||||
|
}
|
||||||
|
if (sqlite3_prepare_v2(job_data->db,
|
||||||
|
"INSERT INTO repos (repo_order, repo) VALUES (@repo_order, @repo)",
|
||||||
|
-1,
|
||||||
|
&stmt,
|
||||||
|
NULL) != SQLITE_OK)
|
||||||
|
{
|
||||||
|
goto out;
|
||||||
|
}
|
||||||
|
sqlite3_bind_int(stmt, 1, this->get_order ());
|
||||||
|
sqlite3_bind_text(stmt, 2, this->get_name (), -1, SQLITE_TRANSIENT);
|
||||||
|
sqlite3_step(stmt);
|
||||||
|
if (sqlite3_finalize(stmt) != SQLITE_OK)
|
||||||
|
{
|
||||||
|
goto out;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Insert new records */
|
||||||
|
if ((sqlite3_prepare_v2(job_data->db,
|
||||||
|
"INSERT INTO pkglist (full_name, name, ver, arch, "
|
||||||
|
"summary, desc, compressed, uncompressed, cat, repo_order, ext) "
|
||||||
|
"VALUES (@full_name, @name, @ver, @arch, @summary, "
|
||||||
|
"@desc, @compressed, @uncompressed, @cat, @repo_order, @ext)",
|
||||||
|
-1,
|
||||||
|
&stmt,
|
||||||
|
NULL) != SQLITE_OK))
|
||||||
|
{
|
||||||
|
goto out;
|
||||||
|
}
|
||||||
|
sqlite3_exec(job_data->db, "BEGIN TRANSACTION", NULL, NULL, NULL);
|
||||||
|
|
||||||
|
while ((line = g_data_input_stream_read_line(data_in, NULL, NULL, NULL)))
|
||||||
|
{
|
||||||
|
line_tokens = g_strsplit(line, ":", 0);
|
||||||
|
if ((g_strv_length(line_tokens) > 6)
|
||||||
|
&& !this->is_blacklisted (line_tokens[0]))
|
||||||
|
{
|
||||||
|
pkg_tokens = split_package_name(line_tokens[0]);
|
||||||
|
|
||||||
|
/* If the split_package_name doesn't return a full name and an
|
||||||
|
* extension, it is a collection. We save its name in this case */
|
||||||
|
if (pkg_tokens[3])
|
||||||
|
{
|
||||||
|
sqlite3_bind_text(stmt, 1, pkg_tokens[3], -1, SQLITE_TRANSIENT);
|
||||||
|
sqlite3_bind_text(stmt, 9, "desktop-gnome", -1, SQLITE_STATIC);
|
||||||
|
if (g_strcmp0(line_tokens[1], "obsolete"))
|
||||||
|
{
|
||||||
|
sqlite3_bind_text(stmt, 11, pkg_tokens[4], -1, SQLITE_TRANSIENT);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
sqlite3_bind_text(stmt, 11, "obsolete", -1, SQLITE_STATIC);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else if (!collection_name)
|
||||||
|
{
|
||||||
|
collection_name = g_strdup(pkg_tokens[0]);
|
||||||
|
sqlite3_bind_text(stmt, 1, line_tokens[0], -1, SQLITE_TRANSIENT);
|
||||||
|
sqlite3_bind_text(stmt, 9, "collections", -1, SQLITE_STATIC);
|
||||||
|
sqlite3_bind_null(stmt, 11);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
skip = TRUE; /* Skip other candidates for collections */
|
||||||
|
}
|
||||||
|
if (skip)
|
||||||
|
{
|
||||||
|
skip = FALSE;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
sqlite3_bind_text(stmt, 2, pkg_tokens[0], -1, SQLITE_TRANSIENT);
|
||||||
|
sqlite3_bind_text(stmt, 3, pkg_tokens[1], -1, SQLITE_TRANSIENT);
|
||||||
|
sqlite3_bind_text(stmt, 4, pkg_tokens[2], -1, SQLITE_TRANSIENT);
|
||||||
|
sqlite3_bind_text(stmt, 5, line_tokens[2], -1, SQLITE_TRANSIENT);
|
||||||
|
sqlite3_bind_text(stmt, 6, line_tokens[2], -1, SQLITE_TRANSIENT);
|
||||||
|
sqlite3_bind_int(stmt, 7, atoi(line_tokens[5]));
|
||||||
|
sqlite3_bind_int(stmt, 8, atoi(line_tokens[5]));
|
||||||
|
sqlite3_bind_int(stmt, 10, this->get_order ());
|
||||||
|
|
||||||
|
sqlite3_step(stmt);
|
||||||
|
sqlite3_clear_bindings(stmt);
|
||||||
|
sqlite3_reset(stmt);
|
||||||
|
}
|
||||||
|
g_strfreev(pkg_tokens);
|
||||||
|
}
|
||||||
|
g_strfreev(line_tokens);
|
||||||
|
g_free(line);
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Create a collection entry */
|
||||||
|
if (collection_name && g_seekable_seek(G_SEEKABLE(data_in), 0, G_SEEK_SET, NULL, NULL)
|
||||||
|
&& (sqlite3_prepare_v2(job_data->db,
|
||||||
|
"INSERT INTO collections (name, repo_order, collection_pkg) "
|
||||||
|
"VALUES (@name, @repo_order, @collection_pkg)",
|
||||||
|
-1,
|
||||||
|
&stmt,
|
||||||
|
NULL) == SQLITE_OK))
|
||||||
|
{
|
||||||
|
while ((line = g_data_input_stream_read_line(data_in, NULL, NULL, NULL)))
|
||||||
|
{
|
||||||
|
line_tokens = g_strsplit(line, ":", 0);
|
||||||
|
if ((g_strv_length(line_tokens) > 6)
|
||||||
|
&& !this->is_blacklisted (line_tokens[0]))
|
||||||
|
{
|
||||||
|
pkg_tokens = split_package_name(line_tokens[0]);
|
||||||
|
|
||||||
|
/* If not a collection itself */
|
||||||
|
if (pkg_tokens[3]) /* Save this package as a part of the collection */
|
||||||
|
{
|
||||||
|
sqlite3_bind_text(stmt, 1, collection_name, -1, SQLITE_TRANSIENT);
|
||||||
|
sqlite3_bind_int(stmt, 2, this->get_order ());
|
||||||
|
sqlite3_bind_text(stmt, 3, pkg_tokens[0], -1, SQLITE_TRANSIENT);
|
||||||
|
sqlite3_step(stmt);
|
||||||
|
sqlite3_clear_bindings(stmt);
|
||||||
|
sqlite3_reset(stmt);
|
||||||
|
}
|
||||||
|
g_strfreev(pkg_tokens);
|
||||||
|
}
|
||||||
|
g_strfreev(line_tokens);
|
||||||
|
g_free(line);
|
||||||
|
}
|
||||||
|
sqlite3_finalize(stmt);
|
||||||
|
}
|
||||||
|
g_free(collection_name);
|
||||||
|
|
||||||
|
sqlite3_exec(job_data->db, "END TRANSACTION", NULL, NULL, NULL);
|
||||||
|
|
||||||
|
out:
|
||||||
|
if (data_in)
|
||||||
|
{
|
||||||
|
g_object_unref(data_in);
|
||||||
|
}
|
||||||
|
if (fin)
|
||||||
|
{
|
||||||
|
g_object_unref(fin);
|
||||||
|
}
|
||||||
|
g_object_unref(list_file);
|
||||||
|
g_free(list_filename);
|
||||||
|
}
|
||||||
|
|
||||||
|
Dl::~Dl () noexcept
|
||||||
|
{
|
||||||
|
if (this->blacklist)
|
||||||
|
{
|
||||||
|
g_regex_unref (this->blacklist);
|
||||||
|
}
|
||||||
|
|
||||||
|
g_free (this->name);
|
||||||
|
g_free (this->mirror);
|
||||||
|
g_free (this->index_file);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* slack::Dl::Dl:
|
||||||
|
* @name: Repository name.
|
||||||
|
* @mirror: Repository mirror.
|
||||||
|
* @order: Repository order.
|
||||||
|
* @blacklist: Repository blacklist.
|
||||||
|
* @index_file: The index file URL.
|
||||||
|
*
|
||||||
|
* Constructor.
|
||||||
|
*
|
||||||
|
* Return value: New #slack::Dl.
|
||||||
|
**/
|
||||||
|
Dl::Dl (const gchar *name, const gchar *mirror,
|
||||||
|
guint8 order, const gchar *blacklist, gchar *index_file) noexcept
|
||||||
|
{
|
||||||
|
GRegex *regex;
|
||||||
|
|
||||||
|
if (blacklist)
|
||||||
|
{
|
||||||
|
regex = static_cast<GRegex *> (g_regex_new (blacklist,
|
||||||
|
G_REGEX_OPTIMIZE, static_cast<GRegexMatchFlags> (0), NULL));
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
regex = NULL;
|
||||||
|
}
|
||||||
|
|
||||||
|
this->name = g_strdup (name);
|
||||||
|
this->mirror = g_strdup (mirror);
|
||||||
|
|
||||||
|
this->order = order;
|
||||||
|
|
||||||
|
this->blacklist = regex;
|
||||||
|
|
||||||
|
this->index_file = index_file;
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
24
backend/dl.h
Normal file
24
backend/dl.h
Normal file
@@ -0,0 +1,24 @@
|
|||||||
|
#ifndef __SLACK_DL_H
|
||||||
|
#define __SLACK_DL_H
|
||||||
|
|
||||||
|
#include "pkgtools.h"
|
||||||
|
|
||||||
|
namespace slack {
|
||||||
|
|
||||||
|
class Dl final : public Pkgtools
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
Dl (const gchar *name, const gchar *mirror,
|
||||||
|
guint8 order, const gchar *blacklist, gchar *index_file) noexcept;
|
||||||
|
~Dl () noexcept;
|
||||||
|
|
||||||
|
GSList *collect_cache_info (const gchar *tmpl) noexcept;
|
||||||
|
void generate_cache (PkBackendJob *job, const gchar *tmpl) noexcept;
|
||||||
|
|
||||||
|
private:
|
||||||
|
gchar *index_file;
|
||||||
|
};
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
#endif /* __SLACK_DL_H */
|
||||||
104
backend/job.cc
Normal file
104
backend/job.cc
Normal file
@@ -0,0 +1,104 @@
|
|||||||
|
#include "job.h"
|
||||||
|
|
||||||
|
#include <string>
|
||||||
|
#include "utils.h"
|
||||||
|
|
||||||
|
namespace slack {
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Returns true if the package isn't filtered out by the filters, false
|
||||||
|
* otherwise.
|
||||||
|
*/
|
||||||
|
bool
|
||||||
|
filter_package (PkBitfield filters, bool is_installed)
|
||||||
|
{
|
||||||
|
if ((is_installed && !pk_bitfield_contain (filters, PK_FILTER_ENUM_NOT_INSTALLED))
|
||||||
|
|| (!is_installed && !pk_bitfield_contain (filters, PK_FILTER_ENUM_INSTALLED)))
|
||||||
|
{
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
static std::string
|
||||||
|
generate_query(PkBitfield filters)
|
||||||
|
{
|
||||||
|
std::string query(
|
||||||
|
"SELECT (p1.name || ';' || p1.ver || ';' || p1.arch || ';' || r.repo), p1.summary, "
|
||||||
|
"p1.full_name FROM pkglist AS p1 NATURAL JOIN repos AS r "
|
||||||
|
"WHERE p1.%s LIKE '%%%q%%' AND p1.ext NOT LIKE 'obsolete' AND p1.repo_order = "
|
||||||
|
"(SELECT MIN(p2.repo_order) FROM pkglist AS p2 WHERE p2.name = p1.name GROUP BY p2.name)");
|
||||||
|
|
||||||
|
if (pk_bitfield_contain (filters, PK_FILTER_ENUM_APPLICATION))
|
||||||
|
{
|
||||||
|
query.append(
|
||||||
|
" AND EXISTS (SELECT filelist.full_name "
|
||||||
|
"FROM filelist "
|
||||||
|
"WHERE filelist.full_name = p1.full_name "
|
||||||
|
"AND filelist.filename LIKE 'usr/share/applications/%%.desktop')");
|
||||||
|
}
|
||||||
|
else if (pk_bitfield_contain (filters, PK_FILTER_ENUM_NOT_APPLICATION))
|
||||||
|
{
|
||||||
|
query.append(
|
||||||
|
" AND NOT EXISTS (SELECT filelist.full_name "
|
||||||
|
"FROM filelist "
|
||||||
|
"WHERE filelist.full_name = p1.full_name "
|
||||||
|
"AND filelist.filename LIKE 'usr/share/applications/%%.desktop')");
|
||||||
|
}
|
||||||
|
return query;
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
void
|
||||||
|
pk_backend_search_thread (PkBackendJob *job, GVariant *params, gpointer user_data)
|
||||||
|
{
|
||||||
|
auto job_data = reinterpret_cast<slack::JobData *> (pk_backend_job_get_user_data (job));
|
||||||
|
|
||||||
|
pk_backend_job_set_status (job, PK_STATUS_ENUM_QUERY);
|
||||||
|
pk_backend_job_set_percentage (job, 0);
|
||||||
|
|
||||||
|
gchar **vals;
|
||||||
|
PkBitfield filters;
|
||||||
|
g_variant_get (params, "(t^a&s)", &filters, &vals);
|
||||||
|
gchar *search = g_strjoinv ("%", vals);
|
||||||
|
|
||||||
|
gchar *query = sqlite3_mprintf (slack::generate_query(filters).c_str(),
|
||||||
|
user_data, search);
|
||||||
|
|
||||||
|
sqlite3_stmt *stmt;
|
||||||
|
if ((sqlite3_prepare_v2 (job_data->db, query, -1, &stmt, NULL) == SQLITE_OK))
|
||||||
|
{
|
||||||
|
/* Now we're ready to output all packages */
|
||||||
|
while (sqlite3_step (stmt) == SQLITE_ROW)
|
||||||
|
{
|
||||||
|
PkInfoEnum info = slack::is_installed (
|
||||||
|
reinterpret_cast<const gchar *> (sqlite3_column_text (stmt, 2)));
|
||||||
|
|
||||||
|
if ((info == PK_INFO_ENUM_INSTALLED || info == PK_INFO_ENUM_UPDATING)
|
||||||
|
&& slack::filter_package (filters, true))
|
||||||
|
{
|
||||||
|
pk_backend_job_package (job, PK_INFO_ENUM_INSTALLED,
|
||||||
|
reinterpret_cast<const gchar *> (sqlite3_column_text (stmt, 0)),
|
||||||
|
reinterpret_cast<const gchar *> (sqlite3_column_text (stmt, 1)));
|
||||||
|
}
|
||||||
|
else if (info == PK_INFO_ENUM_INSTALLING && slack::filter_package (filters, false))
|
||||||
|
{
|
||||||
|
pk_backend_job_package(job, PK_INFO_ENUM_AVAILABLE,
|
||||||
|
reinterpret_cast<const gchar *> (sqlite3_column_text (stmt, 0)),
|
||||||
|
reinterpret_cast<const gchar *> (sqlite3_column_text (stmt, 1)));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
sqlite3_finalize (stmt);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
pk_backend_job_error_code (job, PK_ERROR_ENUM_CANNOT_GET_FILELIST,
|
||||||
|
"%s", sqlite3_errmsg (job_data->db));
|
||||||
|
}
|
||||||
|
|
||||||
|
sqlite3_free (query);
|
||||||
|
g_free (search);
|
||||||
|
|
||||||
|
pk_backend_job_set_percentage (job, 100);
|
||||||
|
}
|
||||||
19
backend/job.h
Normal file
19
backend/job.h
Normal file
@@ -0,0 +1,19 @@
|
|||||||
|
#ifndef __SLACK_JOB_H
|
||||||
|
#define __SLACK_JOB_H
|
||||||
|
|
||||||
|
#include <pk-backend.h>
|
||||||
|
#include <sqlite3.h>
|
||||||
|
|
||||||
|
namespace slack {
|
||||||
|
|
||||||
|
bool filter_package (PkBitfield filters, bool is_installed);
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
extern "C" {
|
||||||
|
|
||||||
|
void pk_backend_search_thread (PkBackendJob *job, GVariant *params, gpointer user_data);
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
#endif /* __SLACK_JOB_H */
|
||||||
53
backend/meson.build
Normal file
53
backend/meson.build
Normal file
@@ -0,0 +1,53 @@
|
|||||||
|
add_languages('cpp', native: false)
|
||||||
|
|
||||||
|
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,
|
||||||
|
)
|
||||||
|
|
||||||
|
subdir('tests')
|
||||||
|
|
||||||
|
slackware_config_data = configuration_data()
|
||||||
|
if (target_machine.cpu_family() == 'x86_64')
|
||||||
|
slackware_config_data.set('pkgmain', 'slackware64')
|
||||||
|
else
|
||||||
|
slackware_config_data.set('pkgmain', 'slackware')
|
||||||
|
endif
|
||||||
|
|
||||||
|
configure_file(
|
||||||
|
input: 'Slackware.conf.in',
|
||||||
|
output: 'Slackware.conf',
|
||||||
|
configuration: slackware_config_data,
|
||||||
|
install: true,
|
||||||
|
install_dir: join_paths(get_option('sysconfdir'), 'PackageKit'),
|
||||||
|
)
|
||||||
|
|
||||||
|
install_data(
|
||||||
|
'metadata.db',
|
||||||
|
install_dir: join_paths(get_option('localstatedir'), 'cache', 'PackageKit', 'metadata'),
|
||||||
|
)
|
||||||
BIN
backend/metadata.db
Normal file
BIN
backend/metadata.db
Normal file
Binary file not shown.
1078
backend/pk-backend-slack.cc
Normal file
1078
backend/pk-backend-slack.cc
Normal file
File diff suppressed because it is too large
Load Diff
175
backend/pkgtools.cc
Normal file
175
backend/pkgtools.cc
Normal file
@@ -0,0 +1,175 @@
|
|||||||
|
#include <curl/curl.h>
|
||||||
|
#include <sqlite3.h>
|
||||||
|
#include "pkgtools.h"
|
||||||
|
#include "utils.h"
|
||||||
|
|
||||||
|
namespace slack {
|
||||||
|
|
||||||
|
/**
|
||||||
|
* slack::Pkgtools::download:
|
||||||
|
* @job: A #PkBackendJob.
|
||||||
|
* @dest_dir_name: Destination directory.
|
||||||
|
* @pkg_name: Package name.
|
||||||
|
*
|
||||||
|
* Download a package.
|
||||||
|
*
|
||||||
|
* Returns: %TRUE on success, %FALSE otherwise.
|
||||||
|
**/
|
||||||
|
gboolean
|
||||||
|
Pkgtools::download (PkBackendJob *job,
|
||||||
|
gchar *dest_dir_name, gchar *pkg_name) noexcept
|
||||||
|
{
|
||||||
|
gchar *dest_filename, *source_url;
|
||||||
|
gboolean ret = FALSE;
|
||||||
|
sqlite3_stmt *statement = NULL;
|
||||||
|
CURL *curl = NULL;
|
||||||
|
auto job_data = static_cast<JobData *> (pk_backend_job_get_user_data(job));
|
||||||
|
|
||||||
|
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,
|
||||||
|
NULL) != 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), NULL);
|
||||||
|
source_url = g_strconcat(this->get_mirror (),
|
||||||
|
sqlite3_column_text(statement, 0),
|
||||||
|
"/",
|
||||||
|
sqlite3_column_text(statement, 1),
|
||||||
|
NULL);
|
||||||
|
|
||||||
|
if (!g_file_test(dest_filename, G_FILE_TEST_EXISTS))
|
||||||
|
{
|
||||||
|
if (get_file(&curl, source_url, dest_filename) == CURLE_OK)
|
||||||
|
{
|
||||||
|
ret = TRUE;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
ret = TRUE;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (curl)
|
||||||
|
{
|
||||||
|
curl_easy_cleanup(curl);
|
||||||
|
}
|
||||||
|
g_free(source_url);
|
||||||
|
g_free(dest_filename);
|
||||||
|
}
|
||||||
|
sqlite3_finalize(statement);
|
||||||
|
|
||||||
|
return ret;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* slack::Pkgtools::install:
|
||||||
|
* @job: A #PkBackendJob.
|
||||||
|
* @pkg_name: Package name.
|
||||||
|
*
|
||||||
|
* Install a package.
|
||||||
|
**/
|
||||||
|
void
|
||||||
|
Pkgtools::install (PkBackendJob *job, gchar *pkg_name) noexcept
|
||||||
|
{
|
||||||
|
gchar *pkg_filename, *cmd_line;
|
||||||
|
sqlite3_stmt *statement = NULL;
|
||||||
|
auto job_data = static_cast<JobData *> (pk_backend_job_get_user_data(job));
|
||||||
|
|
||||||
|
if ((sqlite3_prepare_v2(job_data->db,
|
||||||
|
"SELECT (full_name || '.' || ext) FROM pkglist "
|
||||||
|
"WHERE name LIKE @name AND repo_order = @repo_order",
|
||||||
|
-1,
|
||||||
|
&statement,
|
||||||
|
NULL) != 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),
|
||||||
|
NULL);
|
||||||
|
cmd_line = g_strconcat("/sbin/upgradepkg --install-new ", pkg_filename, NULL);
|
||||||
|
g_spawn_command_line_sync(cmd_line, NULL, NULL, NULL, NULL);
|
||||||
|
g_free(cmd_line);
|
||||||
|
|
||||||
|
g_free(pkg_filename);
|
||||||
|
}
|
||||||
|
sqlite3_finalize(statement);
|
||||||
|
}
|
||||||
|
|
||||||
|
Pkgtools::~Pkgtools () noexcept
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* slack::Pkgtools::get_name:
|
||||||
|
*
|
||||||
|
* Retrieves the repository name.
|
||||||
|
*
|
||||||
|
* Returns: Repository name.
|
||||||
|
**/
|
||||||
|
const gchar *
|
||||||
|
Pkgtools::get_name () const noexcept
|
||||||
|
{
|
||||||
|
return this->name;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* slack::Pkgtools::get_mirror:
|
||||||
|
*
|
||||||
|
* Retrieves the repository mirror.
|
||||||
|
*
|
||||||
|
* Returns: Repository mirror.
|
||||||
|
**/
|
||||||
|
const gchar *
|
||||||
|
Pkgtools::get_mirror () const noexcept
|
||||||
|
{
|
||||||
|
return this->mirror;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* slack::Pkgtools::get_order:
|
||||||
|
*
|
||||||
|
* Retrieves the repository order.
|
||||||
|
*
|
||||||
|
* Returns: Repository order.
|
||||||
|
**/
|
||||||
|
guint8
|
||||||
|
Pkgtools::get_order () const noexcept
|
||||||
|
{
|
||||||
|
return this->order;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* slack::Pkgtools:is_blacklisted:
|
||||||
|
* @pkg: Package name to check for.
|
||||||
|
*
|
||||||
|
* Checks whether a package is blacklisted.
|
||||||
|
*
|
||||||
|
* Returns: %TRUE if the package is blacklisted, %FALSE otherwise.
|
||||||
|
**/
|
||||||
|
gboolean
|
||||||
|
Pkgtools::is_blacklisted (const gchar *pkg) const noexcept
|
||||||
|
{
|
||||||
|
return this->blacklist
|
||||||
|
&& g_regex_match (this->blacklist,
|
||||||
|
pkg, static_cast<GRegexMatchFlags> (0), NULL);
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
36
backend/pkgtools.h
Normal file
36
backend/pkgtools.h
Normal file
@@ -0,0 +1,36 @@
|
|||||||
|
#ifndef __SLACK_PKGTOOLS_H
|
||||||
|
#define __SLACK_PKGTOOLS_H
|
||||||
|
|
||||||
|
#include <glib-object.h>
|
||||||
|
#include <pk-backend.h>
|
||||||
|
|
||||||
|
namespace slack {
|
||||||
|
|
||||||
|
class Pkgtools
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
const gchar *get_name () const noexcept;
|
||||||
|
const gchar *get_mirror () const noexcept;
|
||||||
|
guint8 get_order () const noexcept;
|
||||||
|
gboolean is_blacklisted (const gchar *pkg) const noexcept;
|
||||||
|
|
||||||
|
virtual ~Pkgtools () noexcept;
|
||||||
|
|
||||||
|
gboolean download (PkBackendJob *job,
|
||||||
|
gchar *dest_dir_name, gchar *pkg_name) noexcept;
|
||||||
|
void install (PkBackendJob *job, gchar *pkg_name) noexcept;
|
||||||
|
|
||||||
|
virtual GSList *collect_cache_info (const gchar *tmpl) noexcept = 0;
|
||||||
|
virtual void generate_cache (PkBackendJob *job,
|
||||||
|
const gchar *tmpl) noexcept = 0;
|
||||||
|
|
||||||
|
protected:
|
||||||
|
gchar *name = NULL;
|
||||||
|
gchar *mirror = NULL;
|
||||||
|
guint8 order;
|
||||||
|
GRegex *blacklist = NULL;
|
||||||
|
};
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
#endif /* __SLACK_PKGTOOLS_H */
|
||||||
525
backend/slackpkg.cc
Normal file
525
backend/slackpkg.cc
Normal file
@@ -0,0 +1,525 @@
|
|||||||
|
#include <bzlib.h>
|
||||||
|
#include <sqlite3.h>
|
||||||
|
#include <stdlib.h>
|
||||||
|
#include <string.h>
|
||||||
|
#include "slackpkg.h"
|
||||||
|
#include "utils.h"
|
||||||
|
|
||||||
|
namespace slack {
|
||||||
|
|
||||||
|
GHashTable *Slackpkg::cat_map = NULL;
|
||||||
|
|
||||||
|
/*
|
||||||
|
* slack::Slackpkg::manifest:
|
||||||
|
* @job: a #PkBackendJob.
|
||||||
|
* @tmpl: temporary directory.
|
||||||
|
* @filename: manifest filename
|
||||||
|
*
|
||||||
|
* Parse the manifest file and save the file list in the database.
|
||||||
|
*/
|
||||||
|
void
|
||||||
|
Slackpkg::manifest (PkBackendJob *job,
|
||||||
|
const gchar *tmpl, gchar *filename) noexcept
|
||||||
|
{
|
||||||
|
FILE *manifest;
|
||||||
|
gint err, read_len;
|
||||||
|
guint pos;
|
||||||
|
gchar buf[max_buf_size], *path, *pkg_filename, *rest = NULL, *start;
|
||||||
|
gchar *full_name = NULL;
|
||||||
|
gchar **line, **lines;
|
||||||
|
BZFILE *manifest_bz2;
|
||||||
|
GRegex *pkg_expr = NULL, *file_expr = NULL;
|
||||||
|
GMatchInfo *match_info;
|
||||||
|
sqlite3_stmt *statement = NULL;
|
||||||
|
auto job_data = static_cast<JobData *> (pk_backend_job_get_user_data(job));
|
||||||
|
|
||||||
|
path = g_build_filename(tmpl,
|
||||||
|
this->get_name (),
|
||||||
|
filename,
|
||||||
|
NULL);
|
||||||
|
manifest = fopen(path, "rb");
|
||||||
|
g_free(path);
|
||||||
|
|
||||||
|
if (!manifest)
|
||||||
|
{
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
if (!(manifest_bz2 = BZ2_bzReadOpen(&err, manifest, 0, 0, NULL, 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),
|
||||||
|
NULL);
|
||||||
|
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),
|
||||||
|
NULL);
|
||||||
|
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,
|
||||||
|
NULL) != SQLITE_OK)
|
||||||
|
{
|
||||||
|
goto out;
|
||||||
|
}
|
||||||
|
|
||||||
|
sqlite3_exec(job_data->db, "BEGIN TRANSACTION", NULL, NULL, NULL);
|
||||||
|
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], NULL);
|
||||||
|
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] = NULL;
|
||||||
|
}
|
||||||
|
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 = NULL;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
g_match_info_free(match_info);
|
||||||
|
|
||||||
|
match_info = NULL;
|
||||||
|
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", NULL, NULL, NULL);
|
||||||
|
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);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* slack::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 gchar *tmpl) noexcept
|
||||||
|
{
|
||||||
|
CURL *curl = NULL;
|
||||||
|
gchar **source_dest;
|
||||||
|
GSList *file_list = NULL;
|
||||||
|
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, NULL, NULL);
|
||||||
|
|
||||||
|
/* Download PACKAGES.TXT. These files are most important, break if some of them couldn't be found */
|
||||||
|
for (gchar **cur_priority = this->priority; *cur_priority; cur_priority++)
|
||||||
|
{
|
||||||
|
source_dest = static_cast<gchar **> (g_malloc_n(3, sizeof(gchar *)));
|
||||||
|
source_dest[0] = g_strconcat(this->get_mirror (),
|
||||||
|
*cur_priority,
|
||||||
|
"/PACKAGES.TXT",
|
||||||
|
NULL);
|
||||||
|
source_dest[1] = g_build_filename(tmpl,
|
||||||
|
this->get_name (),
|
||||||
|
"PACKAGES.TXT",
|
||||||
|
NULL);
|
||||||
|
source_dest[2] = NULL;
|
||||||
|
|
||||||
|
if (get_file(&curl, source_dest[0], NULL) == 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<gchar **> (g_malloc_n(3, sizeof(gchar *)));
|
||||||
|
source_dest[0] = g_strconcat(this->get_mirror (),
|
||||||
|
*cur_priority,
|
||||||
|
"/MANIFEST.bz2",
|
||||||
|
NULL);
|
||||||
|
source_dest[1] = g_strconcat(tmpl,
|
||||||
|
"/", this->get_name (),
|
||||||
|
"/", *cur_priority, "-MANIFEST.bz2",
|
||||||
|
NULL);
|
||||||
|
source_dest[2] = NULL;
|
||||||
|
if (get_file(&curl, source_dest[0], NULL) == 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;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* slack::Slackpkg::generate_cache:
|
||||||
|
* @job: A #PkBackendJob.
|
||||||
|
* @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 (PkBackendJob *job, const gchar *tmpl) noexcept
|
||||||
|
{
|
||||||
|
gchar **pkg_tokens = NULL;
|
||||||
|
gchar *query = NULL, *filename = NULL, *location = NULL, *summary = NULL, *line, *packages_txt;
|
||||||
|
guint pkg_compressed = 0, pkg_uncompressed = 0;
|
||||||
|
gushort pkg_name_len;
|
||||||
|
GString *desc;
|
||||||
|
GFile *list_file;
|
||||||
|
GFileInputStream *fin = NULL;
|
||||||
|
GDataInputStream *data_in = NULL;
|
||||||
|
sqlite3_stmt *insert_statement = NULL, *update_statement = NULL, *insert_default_statement = NULL, *statement;
|
||||||
|
auto job_data = static_cast<JobData *> (pk_backend_job_get_user_data(job));
|
||||||
|
|
||||||
|
/* 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",
|
||||||
|
NULL);
|
||||||
|
list_file = g_file_new_for_path(packages_txt);
|
||||||
|
fin = g_file_read(list_file, NULL, NULL);
|
||||||
|
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,
|
||||||
|
NULL) == 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,
|
||||||
|
NULL) != 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,
|
||||||
|
NULL) != 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,
|
||||||
|
NULL) != 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, NULL) != 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", NULL, NULL, NULL);
|
||||||
|
|
||||||
|
while ((line = g_data_input_stream_read_line(data_in, NULL, NULL, NULL)))
|
||||||
|
{
|
||||||
|
if (!strncmp(line, "PACKAGE NAME: ", 15))
|
||||||
|
{
|
||||||
|
filename = g_strdup(line + 15);
|
||||||
|
if (this->is_blacklisted (filename))
|
||||||
|
{
|
||||||
|
g_free(filename);
|
||||||
|
filename = NULL;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
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, NULL, NULL, NULL); /* Short description */
|
||||||
|
|
||||||
|
summary = g_strstr_len(line, -1, "(");
|
||||||
|
if (summary) /* Else summary = NULL */
|
||||||
|
{
|
||||||
|
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 = NULL */
|
||||||
|
{
|
||||||
|
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 = NULL;
|
||||||
|
g_string_assign(desc, "");
|
||||||
|
pkg_compressed = pkg_uncompressed = 0;
|
||||||
|
}
|
||||||
|
g_free(line);
|
||||||
|
}
|
||||||
|
sqlite3_exec(job_data->db, "END TRANSACTION", NULL, NULL, NULL);
|
||||||
|
|
||||||
|
g_string_free(desc, TRUE);
|
||||||
|
g_object_unref(data_in);
|
||||||
|
|
||||||
|
/* Parse MANIFEST.bz2 */
|
||||||
|
for (gchar **p = this->priority; *p; p++)
|
||||||
|
{
|
||||||
|
filename = g_strconcat(*p, "-MANIFEST.bz2", NULL);
|
||||||
|
manifest (job, 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);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* slack::Slackpkg::Slackpkg:
|
||||||
|
* @name: Repository name.
|
||||||
|
* @mirror: Repository mirror.
|
||||||
|
* @order: Repository order.
|
||||||
|
* @blacklist: Blacklist.
|
||||||
|
* @priority: Groups priority.
|
||||||
|
*
|
||||||
|
* Constructor.
|
||||||
|
*
|
||||||
|
* Returns: New #slack::Slackpkg.
|
||||||
|
**/
|
||||||
|
Slackpkg::Slackpkg (const gchar *name, const gchar *mirror,
|
||||||
|
guint8 order, const gchar *blacklist, gchar **priority) noexcept
|
||||||
|
{
|
||||||
|
GRegex *regex;
|
||||||
|
|
||||||
|
if (blacklist)
|
||||||
|
{
|
||||||
|
regex = static_cast<GRegex *> (g_regex_new (blacklist,
|
||||||
|
G_REGEX_OPTIMIZE, static_cast<GRegexMatchFlags> (0), NULL));
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
regex = NULL;
|
||||||
|
}
|
||||||
|
|
||||||
|
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 == NULL)
|
||||||
|
{
|
||||||
|
cat_map = g_hash_table_new(g_str_hash, g_str_equal);
|
||||||
|
g_hash_table_insert (cat_map, (gpointer) "a", (gpointer) "system");
|
||||||
|
g_hash_table_insert (cat_map, (gpointer) "ap", (gpointer) "admin-tools");
|
||||||
|
g_hash_table_insert (cat_map, (gpointer) "d", (gpointer) "programming");
|
||||||
|
g_hash_table_insert (cat_map, (gpointer) "e", (gpointer) "programming");
|
||||||
|
g_hash_table_insert (cat_map, (gpointer) "f", (gpointer) "documentation");
|
||||||
|
g_hash_table_insert (cat_map, (gpointer) "k", (gpointer) "system");
|
||||||
|
g_hash_table_insert (cat_map, (gpointer) "kde", (gpointer) "desktop-kde");
|
||||||
|
g_hash_table_insert (cat_map, (gpointer) "kdei", (gpointer) "localization");
|
||||||
|
g_hash_table_insert (cat_map, (gpointer) "l", (gpointer) "system");
|
||||||
|
g_hash_table_insert (cat_map, (gpointer) "n", (gpointer) "network");
|
||||||
|
g_hash_table_insert (cat_map, (gpointer) "t", (gpointer) "publishing");
|
||||||
|
g_hash_table_insert (cat_map, (gpointer) "tcl", (gpointer) "system");
|
||||||
|
g_hash_table_insert (cat_map, (gpointer) "x", (gpointer) "desktop-other");
|
||||||
|
g_hash_table_insert (cat_map, (gpointer) "xap", (gpointer) "accessories");
|
||||||
|
g_hash_table_insert (cat_map, (gpointer) "xfce", (gpointer) "desktop-xfce");
|
||||||
|
g_hash_table_insert (cat_map, (gpointer) "y", (gpointer) "games");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
30
backend/slackpkg.h
Normal file
30
backend/slackpkg.h
Normal file
@@ -0,0 +1,30 @@
|
|||||||
|
#ifndef __SLACK_SLACKPKG_H
|
||||||
|
#define __SLACK_SLACKPKG_H
|
||||||
|
|
||||||
|
#include <cstddef>
|
||||||
|
#include "pkgtools.h"
|
||||||
|
|
||||||
|
namespace slack {
|
||||||
|
|
||||||
|
class Slackpkg final : public Pkgtools
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
Slackpkg (const gchar *name, const gchar *mirror,
|
||||||
|
guint8 order, const gchar *blacklist, gchar **priority) noexcept;
|
||||||
|
~Slackpkg () noexcept;
|
||||||
|
|
||||||
|
GSList *collect_cache_info (const gchar *tmpl) noexcept;
|
||||||
|
void generate_cache (PkBackendJob *job, const gchar *tmpl) noexcept;
|
||||||
|
|
||||||
|
private:
|
||||||
|
static GHashTable *cat_map;
|
||||||
|
static const std::size_t max_buf_size = 8192;
|
||||||
|
gchar **priority = NULL;
|
||||||
|
|
||||||
|
void manifest (PkBackendJob *job,
|
||||||
|
const gchar *tmpl, gchar *filename) noexcept;
|
||||||
|
};
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
#endif /* __SLACK_SLACKPKG_H */
|
||||||
92
backend/tests/definitions.cc
Normal file
92
backend/tests/definitions.cc
Normal file
@@ -0,0 +1,92 @@
|
|||||||
|
#include "pk-backend.h"
|
||||||
|
#include <pk-backend-job.h>
|
||||||
|
|
||||||
|
gpointer
|
||||||
|
pk_backend_job_get_user_data (PkBackendJob *job)
|
||||||
|
{
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
|
||||||
|
void
|
||||||
|
pk_backend_job_set_user_data (PkBackendJob *job, gpointer user_data)
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
void
|
||||||
|
pk_backend_job_set_allow_cancel (PkBackendJob *job, gboolean allow_cancel)
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
void
|
||||||
|
pk_backend_job_package (PkBackendJob *job,
|
||||||
|
PkInfoEnum info,
|
||||||
|
const gchar *package_id,
|
||||||
|
const gchar *summary)
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
void
|
||||||
|
pk_backend_job_set_status (PkBackendJob *job, PkStatusEnum status)
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
void
|
||||||
|
pk_backend_job_set_percentage (PkBackendJob *job, guint percentage)
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
void
|
||||||
|
pk_backend_job_error_code (PkBackendJob *job,
|
||||||
|
PkErrorEnum error_code, const gchar *format, ...)
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
void
|
||||||
|
pk_backend_job_files (PkBackendJob *job,
|
||||||
|
const gchar *package_id, gchar **files)
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
void
|
||||||
|
pk_backend_job_details (PkBackendJob *job,
|
||||||
|
const gchar *package_id,
|
||||||
|
const gchar *summary,
|
||||||
|
const gchar *license,
|
||||||
|
PkGroupEnum group,
|
||||||
|
const gchar *description,
|
||||||
|
const gchar *url,
|
||||||
|
gulong size,
|
||||||
|
guint64 download_size)
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
void
|
||||||
|
pk_backend_job_update_detail (PkBackendJob *job,
|
||||||
|
const gchar *package_id,
|
||||||
|
gchar **updates,
|
||||||
|
gchar **obsoletes,
|
||||||
|
gchar **vendor_urls,
|
||||||
|
gchar **bugzilla_urls,
|
||||||
|
gchar **cve_urls,
|
||||||
|
PkRestartEnum restart,
|
||||||
|
const gchar *update_text,
|
||||||
|
const gchar *changelog,
|
||||||
|
PkUpdateStateEnum state,
|
||||||
|
const gchar *issued,
|
||||||
|
const gchar *updated)
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
gboolean
|
||||||
|
pk_backend_job_thread_create (PkBackendJob *job,
|
||||||
|
PkBackendJobThreadFunc func,
|
||||||
|
gpointer user_data,
|
||||||
|
GDestroyNotify destroy_func)
|
||||||
|
{
|
||||||
|
return FALSE;
|
||||||
|
}
|
||||||
|
|
||||||
|
gboolean pk_directory_remove_contents (const gchar *directory)
|
||||||
|
{
|
||||||
|
return TRUE;
|
||||||
|
}
|
||||||
25
backend/tests/dl-test.cc
Normal file
25
backend/tests/dl-test.cc
Normal file
@@ -0,0 +1,25 @@
|
|||||||
|
#include "dl.h"
|
||||||
|
|
||||||
|
using namespace slack;
|
||||||
|
|
||||||
|
static void
|
||||||
|
slack_test_dl_construct()
|
||||||
|
{
|
||||||
|
auto dl = new Dl ("some", "mirror", 1, NULL, NULL);
|
||||||
|
|
||||||
|
g_assert_cmpstr (dl->get_name (), ==, "some");
|
||||||
|
g_assert_cmpstr (dl->get_mirror (), ==, "mirror");
|
||||||
|
g_assert_cmpuint (dl->get_order (), ==, 1);
|
||||||
|
g_assert_false (dl->is_blacklisted ("pattern"));
|
||||||
|
|
||||||
|
delete dl;
|
||||||
|
}
|
||||||
|
|
||||||
|
int main(int argc, char *argv[])
|
||||||
|
{
|
||||||
|
g_test_init(&argc, &argv, NULL);
|
||||||
|
|
||||||
|
g_test_add_func("/slack/dl/construct", slack_test_dl_construct);
|
||||||
|
|
||||||
|
return g_test_run();
|
||||||
|
}
|
||||||
39
backend/tests/job-test.cc
Normal file
39
backend/tests/job-test.cc
Normal file
@@ -0,0 +1,39 @@
|
|||||||
|
#include "job.h"
|
||||||
|
|
||||||
|
using namespace slack;
|
||||||
|
|
||||||
|
static void
|
||||||
|
test_filter_package_installed ()
|
||||||
|
{
|
||||||
|
PkBitfield filters = pk_bitfield_value (PK_FILTER_ENUM_INSTALLED);
|
||||||
|
g_assert_true (filter_package (filters, true));
|
||||||
|
g_assert_false (filter_package (filters, false));
|
||||||
|
}
|
||||||
|
|
||||||
|
static void
|
||||||
|
test_filter_package_not_installed ()
|
||||||
|
{
|
||||||
|
PkBitfield filters = pk_bitfield_value (PK_FILTER_ENUM_NOT_INSTALLED);
|
||||||
|
g_assert_true (filter_package (filters, false));
|
||||||
|
g_assert_false (filter_package (filters, true));
|
||||||
|
}
|
||||||
|
|
||||||
|
static void
|
||||||
|
test_filter_package_none ()
|
||||||
|
{
|
||||||
|
PkBitfield filters = pk_bitfield_value (PK_FILTER_ENUM_NONE);
|
||||||
|
g_assert_true (filter_package (filters, false));
|
||||||
|
g_assert_true (filter_package (filters, true));
|
||||||
|
}
|
||||||
|
|
||||||
|
int
|
||||||
|
main (int argc, char *argv[])
|
||||||
|
{
|
||||||
|
g_test_init (&argc, &argv, NULL);
|
||||||
|
|
||||||
|
g_test_add_func ("/slack/filter_package_installed", test_filter_package_installed);
|
||||||
|
g_test_add_func ("/slack/filter_package_not_installed", test_filter_package_not_installed);
|
||||||
|
g_test_add_func ("/slack/filter_package_none", test_filter_package_none);
|
||||||
|
|
||||||
|
return g_test_run ();
|
||||||
|
}
|
||||||
55
backend/tests/meson.build
Normal file
55
backend/tests/meson.build
Normal file
@@ -0,0 +1,55 @@
|
|||||||
|
bzip2_dep = dependency('bzip2')
|
||||||
|
|
||||||
|
pk_slack_test_dependencies = [
|
||||||
|
packagekit_glib2_dep,
|
||||||
|
gmodule_dep,
|
||||||
|
sqlite3_dep,
|
||||||
|
bzip2_dep,
|
||||||
|
polkit_dep
|
||||||
|
]
|
||||||
|
|
||||||
|
pk_slack_test_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')),
|
||||||
|
'-DGETTEXT_PACKAGE="@0@"'.format(meson.project_name()),
|
||||||
|
'-DLIBEXECDIR="@0@"'.format(join_paths(get_option('prefix'), get_option('libexecdir'))),
|
||||||
|
'-DPK_DB_DIR="."',
|
||||||
|
]
|
||||||
|
|
||||||
|
pk_slack_test_include_directories = [
|
||||||
|
include_directories('..'),
|
||||||
|
packagekit_src_include,
|
||||||
|
]
|
||||||
|
|
||||||
|
pk_slack_test_dl = executable('pk-slack-test-dl',
|
||||||
|
['dl-test.cc', 'definitions.cc'],
|
||||||
|
link_with: packagekit_backend_slack_module,
|
||||||
|
include_directories: pk_slack_test_include_directories,
|
||||||
|
dependencies: pk_slack_test_dependencies,
|
||||||
|
cpp_args: pk_slack_test_cpp_args,
|
||||||
|
c_args: pk_slack_test_cpp_args
|
||||||
|
)
|
||||||
|
|
||||||
|
pk_slack_test_slackpkg = executable('pk-slack-test-slackpkg',
|
||||||
|
['slackpkg-test.cc', 'definitions.cc'],
|
||||||
|
link_with: packagekit_backend_slack_module,
|
||||||
|
include_directories: pk_slack_test_include_directories,
|
||||||
|
dependencies: pk_slack_test_dependencies,
|
||||||
|
cpp_args: pk_slack_test_cpp_args,
|
||||||
|
c_args: pk_slack_test_cpp_args
|
||||||
|
)
|
||||||
|
|
||||||
|
pk_slack_test_job = executable('pk-slack-test-job',
|
||||||
|
['job-test.cc', 'definitions.cc'],
|
||||||
|
link_with: packagekit_backend_slack_module,
|
||||||
|
include_directories: pk_slack_test_include_directories,
|
||||||
|
dependencies: pk_slack_test_dependencies,
|
||||||
|
cpp_args: pk_slack_test_cpp_args,
|
||||||
|
c_args: pk_slack_test_cpp_args
|
||||||
|
)
|
||||||
|
|
||||||
|
test('slack-dl', pk_slack_test_dl)
|
||||||
|
test('slac-slackpkg', pk_slack_test_slackpkg)
|
||||||
|
test('slack-job', pk_slack_test_job)
|
||||||
25
backend/tests/slackpkg-test.cc
Normal file
25
backend/tests/slackpkg-test.cc
Normal file
@@ -0,0 +1,25 @@
|
|||||||
|
#include "slackpkg.h"
|
||||||
|
|
||||||
|
using namespace slack;
|
||||||
|
|
||||||
|
static void
|
||||||
|
slack_test_slackpkg_construct()
|
||||||
|
{
|
||||||
|
auto slackpkg = new Slackpkg ("some", "mirror", 1, NULL, NULL);
|
||||||
|
|
||||||
|
g_assert_cmpstr(slackpkg->get_name (), ==, "some");
|
||||||
|
g_assert_cmpstr(slackpkg->get_mirror (), ==, "mirror");
|
||||||
|
g_assert_cmpuint(slackpkg->get_order (), ==, 1);
|
||||||
|
g_assert_false (slackpkg->is_blacklisted ("pattern"));
|
||||||
|
|
||||||
|
delete slackpkg;
|
||||||
|
}
|
||||||
|
|
||||||
|
int main(int argc, char *argv[])
|
||||||
|
{
|
||||||
|
g_test_init(&argc, &argv, NULL);
|
||||||
|
|
||||||
|
g_test_add_func("/slack/slackpkg/construct", slack_test_slackpkg_construct);
|
||||||
|
|
||||||
|
return g_test_run();
|
||||||
|
}
|
||||||
231
backend/utils.cc
Normal file
231
backend/utils.cc
Normal file
@@ -0,0 +1,231 @@
|
|||||||
|
#include <sqlite3.h>
|
||||||
|
#include <string.h>
|
||||||
|
#include "utils.h"
|
||||||
|
#include "pkgtools.h"
|
||||||
|
|
||||||
|
namespace slack {
|
||||||
|
|
||||||
|
/**
|
||||||
|
* slack::get_file:
|
||||||
|
* @curl: curl easy handle.
|
||||||
|
* @source_url: source url.
|
||||||
|
* @dest: destination.
|
||||||
|
*
|
||||||
|
* Download the file.
|
||||||
|
*
|
||||||
|
* Returns: CURLE_OK (zero) on success, non-zero otherwise.
|
||||||
|
**/
|
||||||
|
CURLcode
|
||||||
|
get_file (CURL **curl, gchar *source_url, gchar *dest)
|
||||||
|
{
|
||||||
|
gchar *dest_dir_name;
|
||||||
|
FILE *fout = NULL;
|
||||||
|
CURLcode ret;
|
||||||
|
glong response_code;
|
||||||
|
|
||||||
|
if ((*curl == NULL) && (!(*curl = curl_easy_init())))
|
||||||
|
{
|
||||||
|
return CURLE_BAD_FUNCTION_ARGUMENT;
|
||||||
|
}
|
||||||
|
|
||||||
|
curl_easy_setopt(*curl, CURLOPT_FOLLOWLOCATION, 1L);
|
||||||
|
curl_easy_setopt(*curl, CURLOPT_URL, source_url);
|
||||||
|
|
||||||
|
if (dest == NULL)
|
||||||
|
{
|
||||||
|
curl_easy_setopt(*curl, CURLOPT_NOBODY, 1L);
|
||||||
|
curl_easy_setopt(*curl, CURLOPT_HEADER, 1L);
|
||||||
|
ret = curl_easy_perform(*curl);
|
||||||
|
curl_easy_getinfo(*curl, CURLINFO_RESPONSE_CODE, &response_code);
|
||||||
|
|
||||||
|
if (response_code != 200)
|
||||||
|
{
|
||||||
|
ret = CURLE_REMOTE_FILE_NOT_FOUND;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
if (g_file_test(dest, G_FILE_TEST_IS_DIR))
|
||||||
|
{
|
||||||
|
dest_dir_name = dest;
|
||||||
|
dest = g_strconcat(dest_dir_name, g_strrstr(source_url, "/"), NULL);
|
||||||
|
g_free(dest_dir_name);
|
||||||
|
}
|
||||||
|
if ((fout = fopen(dest, "ab")) == NULL)
|
||||||
|
{
|
||||||
|
return CURLE_WRITE_ERROR;
|
||||||
|
}
|
||||||
|
curl_easy_setopt(*curl, CURLOPT_WRITEDATA, fout);
|
||||||
|
ret = curl_easy_perform(*curl);
|
||||||
|
}
|
||||||
|
curl_easy_reset(*curl);
|
||||||
|
if (fout != NULL)
|
||||||
|
{
|
||||||
|
fclose(fout);
|
||||||
|
}
|
||||||
|
return ret;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* slack::split_package_name:
|
||||||
|
* Got the name of a package, without version-arch-release data.
|
||||||
|
**/
|
||||||
|
gchar **
|
||||||
|
split_package_name (const gchar *pkg_filename)
|
||||||
|
{
|
||||||
|
gchar *pkg_full_name;
|
||||||
|
gchar **pkg_tokens;
|
||||||
|
|
||||||
|
g_return_val_if_fail(pkg_filename != NULL, NULL);
|
||||||
|
|
||||||
|
gint len = strlen(pkg_filename);
|
||||||
|
if (len < 4)
|
||||||
|
{
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (pkg_filename[len - 4] == '.')
|
||||||
|
{
|
||||||
|
pkg_tokens = static_cast<gchar **> (g_malloc_n (6, sizeof (gchar *)));
|
||||||
|
|
||||||
|
/* Full name without extension */
|
||||||
|
len -= 4;
|
||||||
|
pkg_full_name = g_strndup (pkg_filename, len);
|
||||||
|
pkg_tokens[3] = g_strdup (pkg_full_name);
|
||||||
|
|
||||||
|
/* The last 3 characters should be the file extension */
|
||||||
|
pkg_tokens[4] = g_strdup (pkg_filename + len + 1);
|
||||||
|
pkg_tokens[5] = NULL;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
pkg_tokens = static_cast<gchar **> (g_malloc_n (4, sizeof (gchar *)));
|
||||||
|
pkg_full_name = g_strdup (pkg_filename);
|
||||||
|
pkg_tokens[3] = NULL;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Reverse all of the bytes in the package filename to get the name, version and the architecture */
|
||||||
|
g_strreverse (pkg_full_name);
|
||||||
|
gchar **reversed_tokens = g_strsplit (pkg_full_name, "-", 4);
|
||||||
|
pkg_tokens[0] = g_strreverse (reversed_tokens[3]); /* Name */
|
||||||
|
pkg_tokens[1] = g_strreverse (reversed_tokens[2]); /* Version */
|
||||||
|
pkg_tokens[2] = g_strreverse (reversed_tokens[1]); /* Architecture */
|
||||||
|
|
||||||
|
g_free (reversed_tokens[0]); /* Build number */
|
||||||
|
g_free (reversed_tokens);
|
||||||
|
g_free (pkg_full_name);
|
||||||
|
|
||||||
|
return pkg_tokens;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* slack::is_installed:
|
||||||
|
* Checks if a package is already installed in the system.
|
||||||
|
*
|
||||||
|
* Params:
|
||||||
|
* pkg_fullname = Package name should be looked for.
|
||||||
|
*
|
||||||
|
* Returns: PK_INFO_ENUM_INSTALLING if pkg_fullname is already installed,
|
||||||
|
* PK_INFO_ENUM_UPDATING if an elder version of pkg_fullname is
|
||||||
|
* installed, PK_INFO_ENUM_UNKNOWN if pkg_fullname is malformed.
|
||||||
|
**/
|
||||||
|
PkInfoEnum
|
||||||
|
is_installed (const gchar *pkg_fullname)
|
||||||
|
{
|
||||||
|
GFileEnumerator *pkg_metadata_enumerator;
|
||||||
|
GFileInfo *pkg_metadata_file_info;
|
||||||
|
GFile *pkg_metadata_dir;
|
||||||
|
PkInfoEnum ret = PK_INFO_ENUM_INSTALLING;
|
||||||
|
const gchar *it;
|
||||||
|
guint8 dashes = 0;
|
||||||
|
ptrdiff_t pkg_name;
|
||||||
|
|
||||||
|
g_return_val_if_fail(pkg_fullname != NULL, PK_INFO_ENUM_UNKNOWN);
|
||||||
|
|
||||||
|
// We want to find the package name without version for the package we're
|
||||||
|
// looking for.
|
||||||
|
g_debug("Looking if %s is installed", pkg_fullname);
|
||||||
|
|
||||||
|
for (it = pkg_fullname + strlen(pkg_fullname); it != pkg_fullname; --it)
|
||||||
|
{
|
||||||
|
if (*it == '-')
|
||||||
|
{
|
||||||
|
if (dashes == 2)
|
||||||
|
{
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
++dashes;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if (dashes < 2)
|
||||||
|
{
|
||||||
|
return PK_INFO_ENUM_UNKNOWN;
|
||||||
|
}
|
||||||
|
pkg_name = it - pkg_fullname;
|
||||||
|
|
||||||
|
// Read the package metadata directory and comprare all installed packages
|
||||||
|
// with ones in the cache.
|
||||||
|
pkg_metadata_dir = g_file_new_for_path("/var/log/packages");
|
||||||
|
if (!(pkg_metadata_enumerator = g_file_enumerate_children(pkg_metadata_dir,
|
||||||
|
"standard::name",
|
||||||
|
G_FILE_QUERY_INFO_NONE,
|
||||||
|
NULL,
|
||||||
|
NULL)))
|
||||||
|
{
|
||||||
|
g_object_unref(pkg_metadata_dir);
|
||||||
|
return PK_INFO_ENUM_UNKNOWN;
|
||||||
|
}
|
||||||
|
|
||||||
|
while ((pkg_metadata_file_info = g_file_enumerator_next_file(pkg_metadata_enumerator, NULL, NULL)))
|
||||||
|
{
|
||||||
|
const gchar *dir = g_file_info_get_name(pkg_metadata_file_info);
|
||||||
|
dashes = 0;
|
||||||
|
|
||||||
|
if (strcmp(dir, pkg_fullname) == 0)
|
||||||
|
{
|
||||||
|
ret = PK_INFO_ENUM_INSTALLED;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
for (it = dir + strlen(dir); it != dir; --it)
|
||||||
|
{
|
||||||
|
if (*it == '-')
|
||||||
|
{
|
||||||
|
if (dashes == 2)
|
||||||
|
{
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
++dashes;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if (pkg_name == (it - dir) && strncmp(pkg_fullname, dir, pkg_name) == 0)
|
||||||
|
{
|
||||||
|
ret = PK_INFO_ENUM_UPDATING;
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
g_object_unref(pkg_metadata_file_info);
|
||||||
|
|
||||||
|
if (ret != PK_INFO_ENUM_INSTALLING) /* If installed */
|
||||||
|
{
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
g_object_unref(pkg_metadata_enumerator);
|
||||||
|
g_object_unref(pkg_metadata_dir);
|
||||||
|
|
||||||
|
return ret;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* slack::cmp_repo:
|
||||||
|
**/
|
||||||
|
gint
|
||||||
|
cmp_repo (gconstpointer a, gconstpointer b)
|
||||||
|
{
|
||||||
|
auto repo = static_cast<const Pkgtools *> (a);
|
||||||
|
|
||||||
|
return g_strcmp0 (repo->get_name (), (gchar *) b);
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
32
backend/utils.h
Normal file
32
backend/utils.h
Normal file
@@ -0,0 +1,32 @@
|
|||||||
|
#ifndef __SLACK_UTILS_H
|
||||||
|
#define __SLACK_UTILS_H
|
||||||
|
|
||||||
|
#include <curl/curl.h>
|
||||||
|
#include <pk-backend.h>
|
||||||
|
#include <pk-backend-job.h>
|
||||||
|
|
||||||
|
namespace slack {
|
||||||
|
|
||||||
|
struct JobData
|
||||||
|
{
|
||||||
|
GObjectClass parent_class;
|
||||||
|
|
||||||
|
sqlite3 *db;
|
||||||
|
CURL *curl;
|
||||||
|
};
|
||||||
|
|
||||||
|
CURLcode get_file (CURL **curl, gchar *source_url, gchar *dest);
|
||||||
|
|
||||||
|
gchar **split_package_name (const gchar *pkg_filename);
|
||||||
|
|
||||||
|
PkInfoEnum is_installed (const gchar *pkg_fullname);
|
||||||
|
|
||||||
|
extern "C" {
|
||||||
|
|
||||||
|
gint cmp_repo (gconstpointer a, gconstpointer b);
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
#endif /* __SLACK_UTILS_H */
|
||||||
Reference in New Issue
Block a user