summaryrefslogtreecommitdiff
path: root/backend/dl.cc
diff options
context:
space:
mode:
Diffstat (limited to 'backend/dl.cc')
-rw-r--r--backend/dl.cc288
1 files changed, 288 insertions, 0 deletions
diff --git a/backend/dl.cc b/backend/dl.cc
new file mode 100644
index 0000000..5a749c1
--- /dev/null
+++ b/backend/dl.cc
@@ -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;
+}
+
+}