sqliterepo: First draft
authorTomas Mlcoch <tmlcoch@redhat.com>
Tue, 28 Apr 2015 14:23:46 +0000 (16:23 +0200)
committerTomas Mlcoch <tmlcoch@redhat.com>
Tue, 28 Apr 2015 14:23:46 +0000 (16:23 +0200)
src/sqliterepo_c.c

index f0526f7..13ba54d 100644 (file)
@@ -38,6 +38,8 @@
 #include "sqlite.h"
 #include "xml_file.h"
 #include "modifyrepo_shared.h"
+#include "threads.h"
+#include "xml_dump.h"
 
 /**
  * Command line options
@@ -51,15 +53,17 @@ typedef struct {
     gboolean verbose;           /*!< verbose mode */
     gboolean force;             /*!< overwrite existing DBs */
     gboolean xz_compression;    /*!< use xz for DBs compression */
-    char *compress_type;        /*!< which compression type to use */
+    gchar *compress_type;       /*!< which compression type to use */
     gboolean local_sqlite;      /*!< gen sqlite locally into a directory
                                      temporary files. (For situations when
                                      sqlite has a trouble to gen DBs
                                      on NFS mounts.)*/
+    gchar *chcksum_type;       /*!< type of checksum in repomd.xml */
 
     /* Items filled by check_sqliterepo_arguments() */
 
-    cr_CompressionType compression_type;/*!< compression type */
+    cr_CompressionType compression_type;    /*!< compression type */
+    cr_ChecksumType checksum_type;          /*!< checksum type */
 
 } SqliterepoCmdOptions;
 
@@ -75,8 +79,10 @@ sqliterepocmdoptions_new(void)
     options->force = FALSE;
     options->xz_compression = FALSE;
     options->compress_type = NULL;
+    options->chcksum_type = NULL;
     options->local_sqlite = FALSE;
     options->compression_type = CR_CW_BZ2_COMPRESSION;
+    options->checksum_type = CR_CHECKSUM_SHA256;
 
     return options;
 }
@@ -114,6 +120,8 @@ parse_sqliterepo_arguments(int *argc,
           "Use xz for repodata compression.", NULL },
         { "compress-type", '\0', 0, G_OPTION_ARG_STRING, &(options->compress_type),
           "Which compression type to use.", "<compress_type>" },
+        { "checksum", '\0', 0, G_OPTION_ARG_STRING, &(options->chcksum_type),
+          "Which checksum type to use in repomd.xml for sqlite DBs.", "<checksum_type>" },
         { "local-sqlite", '\0', 0, G_OPTION_ARG_NONE, &(options->local_sqlite),
           "Gen sqlite DBs locally (into a directory for temporary files). "
           "Sometimes, sqlite has a trouble to gen DBs on a NFS mount, "
@@ -141,10 +149,6 @@ parse_sqliterepo_arguments(int *argc,
 static gboolean
 check_arguments(SqliterepoCmdOptions *options, GError **err)
 {
-    // --xz
-    if (options->xz_compression)
-        options->compression_type = CR_CW_XZ_COMPRESSION;
-
     // --compress-type
     if (options->compress_type) {
         options->compression_type = cr_compression_type(options->compress_type);
@@ -155,11 +159,445 @@ check_arguments(SqliterepoCmdOptions *options, GError **err)
         }
     }
 
+    // --xz
+    if (options->xz_compression)
+        options->compression_type = CR_CW_XZ_COMPRESSION;
+
+    return TRUE;
+}
+
+// Common
+
+static int
+warningcb(G_GNUC_UNUSED cr_XmlParserWarningType type,
+          char *msg,
+          void *cbdata,
+          G_GNUC_UNUSED GError **err)
+{
+    g_warning("XML parser warning (%s): %s\n", (gchar *) cbdata, msg);
+    return CR_CB_RET_OK;
+}
+
+static int
+pkgcb(cr_Package *pkg,
+              void *cbdata,
+              GError **err)
+{
+    int rc;
+    rc = cr_db_add_pkg((cr_SqliteDb *) cbdata, pkg, err);
+    cr_package_free(pkg);
+    if (rc != CRE_OK)
+        return CR_CB_RET_ERR;
+    return CR_CB_RET_OK;
+}
+
+// Primary sqlite db
+
+static gboolean
+primary_to_sqlite(const gchar *pri_xml_path,
+                  cr_SqliteDb *pri_db,
+                  GError **err)
+{
+    int rc;
+    rc = cr_xml_parse_primary(pri_xml_path,
+                              NULL,
+                              NULL,
+                              pkgcb,
+                              (void *) pri_db,
+                              warningcb,
+                              (void *) pri_xml_path,
+                              TRUE,
+                              err);
+    if (rc != CRE_OK)
+        return FALSE;
+    return TRUE;
+}
+
+// Filelists
+
+static gboolean
+filelists_to_sqlite(const gchar *fil_xml_path,
+                    cr_SqliteDb *fil_db,
+                    GError **err)
+{
+    int rc;
+    rc = cr_xml_parse_filelists(fil_xml_path,
+                                NULL,
+                                NULL,
+                                pkgcb,
+                                (void *) fil_db,
+                                warningcb,
+                                (void *) fil_xml_path,
+                                err);
+    if (rc != CRE_OK)
+        return FALSE;
     return TRUE;
 }
 
+// Other
+
 static gboolean
-generate_sqlite_from_xml(const gchar *path)
+other_to_sqlite(const gchar *oth_xml_path,
+                cr_SqliteDb *oth_db,
+                GError **err)
+{
+    int rc;
+    rc = cr_xml_parse_other(oth_xml_path,
+                            NULL,
+                            NULL,
+                            pkgcb,
+                            (void *) oth_db,
+                            warningcb,
+                            (void *) oth_xml_path,
+                            err);
+    if (rc != CRE_OK)
+        return FALSE;
+    return TRUE;
+}
+
+// Main
+
+static gboolean
+xml_to_sqlite(const gchar *pri_xml_path,
+              const gchar *fil_xml_path,
+              const gchar *oth_xml_path,
+              cr_SqliteDb *pri_db,
+              cr_SqliteDb *fil_db,
+              cr_SqliteDb *oth_db,
+              GError **err)
+{
+    gboolean ret;
+
+    if (pri_xml_path && pri_db) {
+        ret = primary_to_sqlite(pri_xml_path,
+                                pri_db,
+                                err);
+        if (!ret)
+            return FALSE;
+        g_debug("Primary sqlite done");
+    }
+
+    if (fil_xml_path && fil_db) {
+        ret = filelists_to_sqlite(fil_xml_path,
+                                  fil_db,
+                                  err);
+        if (!ret)
+            return FALSE;
+        g_debug("Filelists sqlite done");
+    }
+
+    if (oth_xml_path && oth_db) {
+        ret = other_to_sqlite(oth_xml_path,
+                              oth_db,
+                              err);
+        if (!ret)
+            return FALSE;
+        g_debug("Other sqlite done");
+    }
+
+    return TRUE;
+}
+
+static gboolean
+sqlite_dbinfo_update(cr_Repomd *repomd,
+                     cr_SqliteDb *pri_db,
+                     cr_SqliteDb *fil_db,
+                     cr_SqliteDb *oth_db,
+                     GError **err)
+{
+    cr_RepomdRecord *rec = NULL;
+
+    // Parse repomd.xml
+    // Get files checksums and insert them into sqlite dbs
+    if (pri_db) {
+        rec = cr_repomd_get_record(repomd, "primary");
+        if (rec && rec->checksum)
+            if (cr_db_dbinfo_update(pri_db, rec->checksum, err) != CRE_OK)
+                return FALSE;
+    }
+
+    if (fil_db) {
+        rec = cr_repomd_get_record(repomd, "filelists");
+        if (rec && rec->checksum)
+            if (cr_db_dbinfo_update(fil_db, rec->checksum, err) != CRE_OK)
+                return FALSE;
+    }
+
+    if (oth_db) {
+        rec = cr_repomd_get_record(repomd, "other");
+        if (rec && rec->checksum)
+            if (cr_db_dbinfo_update(oth_db, rec->checksum, err) != CRE_OK)
+                return FALSE;
+    }
+
+    return TRUE;
+}
+
+static gboolean
+compress_sqlite_dbs(const gchar *tmp_out_repo,
+                    const gchar *pri_db_filename,
+                    cr_RepomdRecord **in_pri_db_rec,
+                    const gchar *fil_db_filename,
+                    cr_RepomdRecord **in_fil_db_rec,
+                    const gchar *oth_db_filename,
+                    cr_RepomdRecord **in_oth_db_rec,
+                    cr_CompressionType compression_type,
+                    cr_ChecksumType checksum_type,
+                    GError **err)
+{
+    cr_CompressionTask *pri_db_task;
+    cr_CompressionTask *fil_db_task;
+    cr_CompressionTask *oth_db_task;
+    const char *sqlite_compression_suffix;
+    cr_RepomdRecord *pri_db_rec = NULL;
+    cr_RepomdRecord *fil_db_rec = NULL;
+    cr_RepomdRecord *oth_db_rec = NULL;
+
+    // Prepare thread pool for compression tasks
+    GThreadPool *compress_pool =  g_thread_pool_new(cr_compressing_thread,
+                                                    NULL, 3, FALSE, NULL);
+
+    // Prepare output filenames
+    sqlite_compression_suffix = cr_compression_suffix(compression_type);
+    gchar *pri_db_name = g_strconcat(tmp_out_repo, "/primary.sqlite",
+                                     sqlite_compression_suffix, NULL);
+    gchar *fil_db_name = g_strconcat(tmp_out_repo, "/filelists.sqlite",
+                                     sqlite_compression_suffix, NULL);
+    gchar *oth_db_name = g_strconcat(tmp_out_repo, "/other.sqlite",
+                                     sqlite_compression_suffix, NULL);
+
+    // Prepare compression tasks
+    pri_db_task = cr_compressiontask_new(pri_db_filename,
+                                         pri_db_name,
+                                         compression_type,
+                                         checksum_type,
+                                         1, NULL);
+    g_thread_pool_push(compress_pool, pri_db_task, NULL);
+
+    fil_db_task = cr_compressiontask_new(fil_db_filename,
+                                         fil_db_name,
+                                         compression_type,
+                                         checksum_type,
+                                         1, NULL);
+    g_thread_pool_push(compress_pool, fil_db_task, NULL);
+
+    oth_db_task = cr_compressiontask_new(oth_db_filename,
+                                         oth_db_name,
+                                         compression_type,
+                                         checksum_type,
+                                         1, NULL);
+    g_thread_pool_push(compress_pool, oth_db_task, NULL);
+
+    // Wait till all tasks are complete and free the thread pool
+    g_thread_pool_free(compress_pool, FALSE, TRUE);
+
+    // if (!cmd_options->local_sqlite) { // XXX Why?
+        cr_rm(pri_db_filename, CR_RM_FORCE, NULL, NULL);
+        cr_rm(fil_db_filename, CR_RM_FORCE, NULL, NULL);
+        cr_rm(oth_db_filename, CR_RM_FORCE, NULL, NULL);
+    //}
+
+    // Prepare repomd records
+    pri_db_rec = cr_repomd_record_new("primary_db", pri_db_name);
+    fil_db_rec = cr_repomd_record_new("filelists_db", fil_db_name);
+    oth_db_rec = cr_repomd_record_new("other_db", oth_db_name);
+
+    *in_pri_db_rec = pri_db_rec;
+    *in_fil_db_rec = fil_db_rec;
+    *in_oth_db_rec = oth_db_rec;
+
+    // Free paths to compressed files
+    g_free(pri_db_name);
+    g_free(fil_db_name);
+    g_free(oth_db_name);
+
+    // Fill repomd records from stats gathered during compression
+    cr_repomd_record_load_contentstat(pri_db_rec, pri_db_task->stat);
+    cr_repomd_record_load_contentstat(fil_db_rec, fil_db_task->stat);
+    cr_repomd_record_load_contentstat(oth_db_rec, oth_db_task->stat);
+
+    // Free the compression tasks
+    cr_compressiontask_free(pri_db_task, NULL);
+    cr_compressiontask_free(fil_db_task, NULL);
+    cr_compressiontask_free(oth_db_task, NULL);
+
+    // Prepare thread pool for repomd record filling tasks
+    GThreadPool *fill_pool = g_thread_pool_new(cr_repomd_record_fill_thread,
+                                               NULL, 3, FALSE, NULL);
+
+    // Prepare the tasks themselves
+    cr_RepomdRecordFillTask *pri_db_fill_task;
+    cr_RepomdRecordFillTask *fil_db_fill_task;
+    cr_RepomdRecordFillTask *oth_db_fill_task;
+
+    pri_db_fill_task = cr_repomdrecordfilltask_new(pri_db_rec,
+                                                   checksum_type,
+                                                   NULL);
+    g_thread_pool_push(fill_pool, pri_db_fill_task, NULL);
+
+    fil_db_fill_task = cr_repomdrecordfilltask_new(fil_db_rec,
+                                                   checksum_type,
+                                                   NULL);
+    g_thread_pool_push(fill_pool, fil_db_fill_task, NULL);
+
+    oth_db_fill_task = cr_repomdrecordfilltask_new(oth_db_rec,
+                                                   checksum_type,
+                                                   NULL);
+    g_thread_pool_push(fill_pool, oth_db_fill_task, NULL);
+
+    // Wait till the all tasks are finished and free the pool
+    g_thread_pool_free(fill_pool, FALSE, TRUE);
+
+    // Clear the tasks
+    cr_repomdrecordfilltask_free(pri_db_fill_task, NULL);
+    cr_repomdrecordfilltask_free(fil_db_fill_task, NULL);
+    cr_repomdrecordfilltask_free(oth_db_fill_task, NULL);
+
+    return TRUE;
+}
+
+static gboolean
+uses_simple_md_filename(cr_Repomd *repomd,
+                        gboolean *simple_md,
+                        GError **err)
+{
+    cr_RepomdRecord *rec = NULL;
+
+    // Get primary record
+    rec = cr_repomd_get_record(repomd, "primary");
+    if (!rec) {
+        g_set_error(err, CREATEREPO_C_ERROR, CRE_ERROR,
+                    "Repomd doen't contain primary.xml");
+        return FALSE;
+    }
+
+    if (!rec->location_href) {
+        g_set_error(err, CREATEREPO_C_ERROR, CRE_ERROR,
+                    "Primary repomd record doesn't contain location href");
+        return FALSE;
+    }
+
+    // Check if it's prefixed by checksum or not
+    _cleanup_free_ gchar *basename = NULL;
+
+    basename = g_path_get_basename(rec->location_href);
+
+    if (g_str_has_prefix(basename, "primary"))
+        *simple_md = TRUE;
+    else
+        *simple_md = FALSE;
+
+    return TRUE;
+}
+
+/* Prepare new repomd.xml
+ * Detect if unique or simple md filenames should be used.
+ * Rename the files if necessary (add checksums into prefixes)
+ * Add the records for databases
+ * Write the updated repomd.xml into tmp_out_repo
+ */
+static gboolean
+gen_new_repomd(const gchar *tmp_out_repo,
+               cr_Repomd *repomd,
+               cr_RepomdRecord *pri_db_rec,
+               cr_RepomdRecord *fil_db_rec,
+               cr_RepomdRecord *oth_db_rec,
+               GError **err)
+{
+    gboolean simple_md_filename = FALSE;
+
+    // Check if a unique md filename should be used or not
+    if (!uses_simple_md_filename(repomd, &simple_md_filename, err))
+        return FALSE;
+
+    // Prepend checksum if unique md filename should be used
+    if (!simple_md_filename) {
+        cr_repomd_record_rename_file(pri_db_rec, NULL);
+        cr_repomd_record_rename_file(fil_db_rec, NULL);
+        cr_repomd_record_rename_file(oth_db_rec, NULL);
+    }
+
+    // Add records to repomd.xml
+    cr_repomd_set_record(repomd, pri_db_rec);
+    cr_repomd_set_record(repomd, fil_db_rec);
+    cr_repomd_set_record(repomd, oth_db_rec);
+
+    // Dump the repomd.xml content
+    _cleanup_free_ gchar *repomd_content = NULL;
+    repomd_content = cr_xml_dump_repomd(repomd, err);
+    if (!repomd_content)
+        return FALSE;
+
+    // Prepare output repomd.xml path
+    _cleanup_free_ gchar *repomd_path = NULL;
+    repomd_path = g_build_filename(tmp_out_repo, "repomd.xml", NULL);
+
+    // Write the repomd.xml
+    _cleanup_file_fclose_ FILE *f_repomd = NULL;
+    if (!(f_repomd = fopen(repomd_path, "w"))) {
+        g_set_error(err, CREATEREPO_C_ERROR, CRE_IO,
+                    "Cannot open %s: %s", repomd_path, g_strerror(errno));
+        return FALSE;
+    }
+
+    fputs(repomd_content, f_repomd);
+
+    return TRUE;
+}
+
+
+/* TODO: Move repomd.xml in the last step */
+static gboolean
+move_results(const gchar *tmp_out_repo,
+             const gchar *in_repo,
+             GError **err)
+{
+    _cleanup_dir_close_ GDir *dirp = NULL;
+    _cleanup_error_free_ GError *tmp_err = NULL;
+
+    // Open the source directory
+    dirp = g_dir_open(tmp_out_repo, 0, &tmp_err);
+    if (!dirp) {
+        g_set_error(err, CREATEREPO_C_ERROR, CRE_IO,
+                    "Cannot open dir %s: %s",
+                    tmp_out_repo, tmp_err->message);
+        return FALSE;
+    }
+
+    // Iterate over its content
+    const gchar *filename;
+    while ((filename = g_dir_read_name(dirp))) {
+        _cleanup_free_ gchar *src_path = NULL;
+        _cleanup_free_ gchar *dst_path = NULL;
+
+        // Get full src path
+        src_path = g_build_filename(tmp_out_repo, filename, NULL);
+
+        // Prepare full dst path
+        dst_path = g_build_filename(in_repo, filename, NULL);
+
+        // Move the file
+        if (g_rename(src_path, dst_path) == -1) {
+            g_set_error(err, CREATEREPO_C_ERROR, CRE_IO,
+                        "Cannot move: %s to: %s: %s",
+                        src_path, dst_path, g_strerror(errno));
+            return FALSE;
+        }
+    }
+
+    return TRUE;
+}
+
+//
+// TODO: exit() calls to return and g_set_error()
+//
+
+static gboolean
+generate_sqlite_from_xml(const gchar *path,
+                         cr_CompressionType compression_type,
+                         cr_ChecksumType checksum_type,
+                         gboolean local_sqlite,
+                         GError **err)
 {
     _cleanup_free_ gchar *in_dir       = NULL;  // path/to/repo/
     _cleanup_free_ gchar *in_repo      = NULL;  // path/to/repo/repodata/
@@ -167,6 +605,8 @@ generate_sqlite_from_xml(const gchar *path)
     _cleanup_free_ gchar *out_repo     = NULL;  // path/to/out_repo/repodata/
     _cleanup_free_ gchar *tmp_out_repo = NULL;  // usually path/to/out_repo/.repodata/
     _cleanup_free_ gchar *lock_dir     = NULL;  // path/to/out_repo/.repodata/
+    gboolean ret;
+    GError *tmp_err = NULL;
 
     // Check if input dir exists
     in_dir = cr_normalize_dir_path(path);
@@ -182,7 +622,207 @@ generate_sqlite_from_xml(const gchar *path)
     lock_dir        = g_build_filename(out_dir, ".repodata/", NULL);
     tmp_out_repo    = g_build_filename(out_dir, ".repodata/", NULL);
 
-    // Lock repodata (createrepo_shared)
+    // Block signals that terminates the process
+    if (!cr_block_terminating_signals(&tmp_err)) {
+        g_printerr("%s\n", tmp_err->message);
+        exit(EXIT_FAILURE);
+    }
+
+    // Check if lock exists & Create lock dir
+    if (!cr_lock_repo(out_dir, FALSE, &lock_dir, &tmp_out_repo, &tmp_err)) {
+        g_printerr("%s\n", tmp_err->message);
+        exit(EXIT_FAILURE);
+    }
+
+    // Setup cleanup handlers
+    if (!cr_set_cleanup_handler(lock_dir, tmp_out_repo, &tmp_err)) {
+        g_printerr("%s\n", tmp_err->message);
+        exit(EXIT_FAILURE);
+    }
+
+    // Unblock the blocked signals
+    if (!cr_unblock_terminating_signals(&tmp_err)) {
+        g_printerr("%s\n", tmp_err->message);
+        exit(EXIT_FAILURE);
+    }
+
+    // Locate repodata
+    struct cr_MetadataLocation *md_loc = NULL;
+    _cleanup_free_ gchar *pri_xml_path = NULL;
+    _cleanup_free_ gchar *fil_xml_path = NULL;
+    _cleanup_free_ gchar *oth_xml_path = NULL;
+    _cleanup_free_ gchar *repomd_path = NULL;
+
+    md_loc = cr_locate_metadata(in_dir, TRUE, NULL);
+    if (!md_loc || !md_loc->repomd) {
+        g_set_error(err, CREATEREPO_C_ERROR, CRE_NOFILE,
+                    "repomd.xml doesn't exist");
+        return FALSE;
+    }
+
+    repomd_path = g_build_filename(in_dir, md_loc->repomd, NULL);
+
+    if (md_loc->pri_xml_href)
+        pri_xml_path = g_build_filename(in_dir, md_loc->pri_xml_href, NULL);
+    if (md_loc->fil_xml_href)
+        fil_xml_path = g_build_filename(in_dir, md_loc->fil_xml_href, NULL);
+    if (md_loc->oth_xml_href)
+        oth_xml_path = g_build_filename(in_dir, md_loc->oth_xml_href, NULL);
+    cr_metadatalocation_free(md_loc);
+
+    // Open XML files
+
+    // Open sqlite databases
+    _cleanup_free_ gchar *pri_db_filename = NULL;
+    _cleanup_free_ gchar *fil_db_filename = NULL;
+    _cleanup_free_ gchar *oth_db_filename = NULL;
+    cr_SqliteDb *pri_db = NULL;
+    cr_SqliteDb *fil_db = NULL;
+    cr_SqliteDb *oth_db = NULL;
+
+    _cleanup_file_close_ int pri_db_fd = -1;
+    _cleanup_file_close_ int fil_db_fd = -1;
+    _cleanup_file_close_ int oth_db_fd = -1;
+
+    g_message("Preparing sqlite DBs");
+    if (!local_sqlite) {
+        g_debug("Creating databases");
+        pri_db_filename = g_strconcat(tmp_out_repo, "/primary.sqlite", NULL);
+        fil_db_filename = g_strconcat(tmp_out_repo, "/filelists.sqlite", NULL);
+        oth_db_filename = g_strconcat(tmp_out_repo, "/other.sqlite", NULL);
+    } else {
+        g_debug("Creating databases localy");
+        const gchar *tmpdir = g_get_tmp_dir();
+        pri_db_filename = g_build_filename(tmpdir, "primary.XXXXXX.sqlite", NULL);
+        fil_db_filename = g_build_filename(tmpdir, "filelists.XXXXXX.sqlite", NULL);
+        oth_db_filename = g_build_filename(tmpdir, "other.XXXXXXX.sqlite", NULL);
+        pri_db_fd = g_mkstemp(pri_db_filename);
+        g_debug("%s", pri_db_filename);
+        if (pri_db_fd == -1) {
+            g_critical("Cannot open %s: %s", pri_db_filename, strerror(errno));
+            exit(EXIT_FAILURE);
+        }
+        fil_db_fd = g_mkstemp(fil_db_filename);
+        g_debug("%s", fil_db_filename);
+        if (fil_db_fd == -1) {
+            g_critical("Cannot open %s: %s", fil_db_filename, strerror(errno));
+            exit(EXIT_FAILURE);
+        }
+        oth_db_fd = g_mkstemp(oth_db_filename);
+        g_debug("%s", oth_db_filename);
+        if (oth_db_fd == -1) {
+            g_critical("Cannot open %s: %s", oth_db_filename, strerror(errno));
+            exit(EXIT_FAILURE);
+        }
+    }
+
+    pri_db = cr_db_open_primary(pri_db_filename, &tmp_err);
+    assert(pri_db || tmp_err);
+    if (!pri_db) {
+        g_critical("Cannot open %s: %s",
+                   pri_db_filename, tmp_err->message);
+        g_clear_error(&tmp_err);
+        exit(EXIT_FAILURE);
+    }
+
+    fil_db = cr_db_open_filelists(fil_db_filename, &tmp_err);
+    assert(fil_db || tmp_err);
+    if (!fil_db) {
+        g_critical("Cannot open %s: %s",
+                   fil_db_filename, tmp_err->message);
+        g_clear_error(&tmp_err);
+        exit(EXIT_FAILURE);
+    }
+
+    oth_db = cr_db_open_other(oth_db_filename, &tmp_err);
+    assert(oth_db || tmp_err);
+    if (!oth_db) {
+        g_critical("Cannot open %s: %s",
+                   oth_db_filename, tmp_err->message);
+        g_clear_error(&tmp_err);
+        exit(EXIT_FAILURE);
+    }
+
+    // XML to Sqlite
+    ret = xml_to_sqlite(pri_xml_path,
+                        fil_xml_path,
+                        oth_xml_path,
+                        pri_db,
+                        fil_db,
+                        oth_db,
+                        err);
+    if (!ret)
+        return FALSE;
+
+    // Parse repomd.xml
+    int rc;
+    cr_Repomd *repomd = cr_repomd_new();
+
+    rc = cr_xml_parse_repomd(repomd_path,
+                             repomd,
+                             warningcb,
+                             (void *) repomd_path,
+                             err);
+    if (rc != CRE_OK)
+        return FALSE;
+
+
+    // Put checksums of XML files into Sqlite
+    ret = sqlite_dbinfo_update(repomd,
+                               pri_db,
+                               fil_db,
+                               oth_db,
+                               err);
+    if (!ret)
+        return FALSE;
+
+    // Close dbs
+    cr_db_close(pri_db, NULL);
+    cr_db_close(fil_db, NULL);
+    cr_db_close(oth_db, NULL);
+
+    // Repomd records
+    cr_RepomdRecord *pri_db_rec = NULL;
+    cr_RepomdRecord *fil_db_rec = NULL;
+    cr_RepomdRecord *oth_db_rec = NULL;
+
+    // Compress DB files and fill records
+    ret = compress_sqlite_dbs(tmp_out_repo,
+                              pri_db_filename,
+                              &pri_db_rec,
+                              fil_db_filename,
+                              &fil_db_rec,
+                              oth_db_filename,
+                              &oth_db_rec,
+                              compression_type,
+                              checksum_type,
+                              err);
+    if (!ret)
+        return FALSE;
+
+    // Prepare new repomd.xml
+    ret = gen_new_repomd(tmp_out_repo,
+                         repomd,
+                         pri_db_rec,
+                         fil_db_rec,
+                         oth_db_rec,
+                         err);
+    if (!ret)
+        return FALSE;
+
+    cr_repomd_free(repomd);
+
+    // Move the results (compressed DBs and repomd.xml) into in_repo
+    ret = move_results(tmp_out_repo,
+                       in_repo,
+                       err);
+    if (!ret)
+        return FALSE;
+
+    // Remove tmp_out_repo
+    g_rmdir(tmp_out_repo);
+
+    return TRUE;
 }
 
 /**
@@ -197,8 +837,7 @@ main(int argc, char **argv)
 
     // Parse arguments
     options = sqliterepocmdoptions_new();
-    ret = parse_sqliterepo_arguments(&argc, &argv, options, &tmp_err);
-    if (!ret) {
+    if (!parse_sqliterepo_arguments(&argc, &argv, options, &tmp_err)) {
         g_printerr("%s\n", tmp_err->message);
         exit(EXIT_FAILURE);
     }
@@ -217,8 +856,7 @@ main(int argc, char **argv)
     }
 
     // Check arguments
-    ret = check_arguments(options, &tmp_err);
-    if (!ret) {
+    if (!check_arguments(options, &tmp_err)) {
         g_printerr("%s\n", tmp_err->message);
         exit(EXIT_FAILURE);
     }
@@ -228,10 +866,17 @@ main(int argc, char **argv)
         exit(EXIT_FAILURE);
     }
 
-    // TODO: Maybe in future
-    //g_thread_init(NULL); // Initialize threading
+    g_thread_init(NULL); // Initialize threading (we don't use threading yet)
 
-    ret = generate_sqlite_from_xml(argv[1]);
+    ret = generate_sqlite_from_xml(argv[1],
+                                   options->compression_type,
+                                   options->checksum_type,
+                                   options->local_sqlite,
+                                   &tmp_err);
+    if (!ret) {
+        g_printerr("%s\n", tmp_err->message);
+        exit(EXIT_FAILURE);
+    }
 
     exit(EXIT_SUCCESS);
 }