[Libosinfo] [osinfo-db-tools PATCH v5 3/3] import: Introduce "--latest" option

Fabiano Fidêncio fidencio at redhat.com
Mon Dec 17 10:09:03 UTC 2018


--latest option checks whether there's a new osinfo-db available from
the official libosinfo's release website, downloads and install it.

The download and installation is only then when the version available in
libosinfo's release website is newer than the version installed in the
(specified location in) system.

The file we query in order to get the "latest" available version
(https://db.libosinfo.org/latest.json) is a json that looks like:
{
    "version": 1,
    "release": {
        "version": "20181203",
        "archive": "https://releases.pagure.org/libosinfo/osinfo-db-20181203.tar.xz",
        "signature": "https://releases.pagure.org/libosinfo/osinfo-db-20181203.tar.xz.asc"
    }
}

The file will be automatically updated whenever a new release is done
(in a day interval).

This commit also introduces a new dependency: json-glib, which is used
to easily manipulate the queried file's content.

Signed-off-by: Fabiano Fidêncio <fidencio at redhat.com>
---
About json-glib, no specific version is required! :-)
---
 configure.ac             |   1 +
 osinfo-db-tools.spec.in  |   1 +
 tools/Makefile.am        |   3 +
 tools/osinfo-db-import.c | 153 ++++++++++++++++++++++++++++++++++++++-
 4 files changed, 157 insertions(+), 1 deletion(-)

diff --git a/configure.ac b/configure.ac
index 5e59568..a488a31 100644
--- a/configure.ac
+++ b/configure.ac
@@ -46,6 +46,7 @@ GLIB_ENCODED_VERSION="GLIB_VERSION_2_36"
 PKG_CHECK_MODULES([LIBXML], [libxml-2.0 >= 2.6.0])
 PKG_CHECK_MODULES([LIBXSLT], [libxslt >= 1.0.0])
 PKG_CHECK_MODULES([LIBARCHIVE], [libarchive >= 3.0.0])
+PKG_CHECK_MODULES([JSON_GLIB], [json-glib-1.0])
 
 PKG_CHECK_MODULES([GLIB], [glib-2.0 >= $GLIB_MINIMUM_VERSION gobject-2.0 gio-2.0])
 GLIB_CFLAGS="$GLIB_CFLAGS -DGLIB_VERSION_MIN_REQUIRED=$GLIB_ENCODED_VERSION"
diff --git a/osinfo-db-tools.spec.in b/osinfo-db-tools.spec.in
index 90dd231..5c33ddf 100644
--- a/osinfo-db-tools.spec.in
+++ b/osinfo-db-tools.spec.in
@@ -13,6 +13,7 @@ BuildRequires: glib2-devel
 BuildRequires: libxml2-devel >= 2.6.0
 BuildRequires: libxslt-devel >= 1.0.0
 BuildRequires: libarchive-devel
+BuildRequires: json-glib-devel
 BuildRequires: /usr/bin/pod2man
 
 %description
diff --git a/tools/Makefile.am b/tools/Makefile.am
index f415297..e43e85d 100644
--- a/tools/Makefile.am
+++ b/tools/Makefile.am
@@ -36,7 +36,10 @@ osinfo_db_import_SOURCES = osinfo-db-import.c $(COMMON_SOURCES)
 osinfo_db_import_LDADD = $(GOBJECT_LIBS)	\
 		      $(GIO_LIBS)		\
 		      $(GLIB_LIBS)		\
+		      $(JSON_GLIB_LIBS)	\
 		      $(LIBARCHIVE_LIBS)
+osinfo_db_import_CFLAGS = $(AM_CFLAGS)		\
+		      $(JSON_GLIB_CFLAGS)
 
 osinfo_db_export_SOURCES = osinfo-db-export.c $(COMMON_SOURCES)
 osinfo_db_export_LDADD = $(GOBJECT_LIBS)	\
diff --git a/tools/osinfo-db-import.c b/tools/osinfo-db-import.c
index 5643f5d..91a7125 100644
--- a/tools/osinfo-db-import.c
+++ b/tools/osinfo-db-import.c
@@ -24,12 +24,17 @@
 
 #include <locale.h>
 #include <glib/gi18n.h>
+#include <glib-object.h>
+#include <json-glib/json-glib.h>
 #include <stdlib.h>
 #include <archive.h>
 #include <archive_entry.h>
 
 #include "osinfo-db-util.h"
 
+#define LATEST_URI "https://db.libosinfo.org/latest.json"
+#define VERSION_FILE "VERSION"
+
 const char *argv0;
 
 static int osinfo_db_import_create_reg(GFile *file,
@@ -178,6 +183,120 @@ osinfo_db_import_download_file(GFile *file,
     return ret;
 }
 
+static gboolean osinfo_db_get_installed_version(GFile *dir,
+                                                gchar **version)
+{
+    GFile *file = NULL;
+    GError *err = NULL;
+    gboolean ret = FALSE;
+
+    file = g_file_get_child(dir, VERSION_FILE);
+    if (file == NULL)
+        return FALSE;
+
+    if (!g_file_load_contents(file, NULL, version, NULL, NULL, &err)) {
+        if (!g_error_matches(err, G_IO_ERROR, G_IO_ERROR_NOT_FOUND)) {
+            g_printerr("Failed get the content of file %s: %s\n",
+                       VERSION_FILE, err->message);
+            goto cleanup;
+        }
+    }
+
+    ret = TRUE;
+
+ cleanup:
+    g_clear_error(&err);
+    g_object_unref(file);
+
+    return ret;
+}
+
+static gboolean osinfo_db_get_latest_info(gchar **version,
+                                          gchar **url)
+{
+    JsonParser *parser = NULL;
+    JsonReader *reader = NULL;
+    GFile *uri = NULL;
+    GError *err = NULL;
+    gchar *content = NULL;
+    gboolean ret = FALSE;
+
+    uri = g_file_new_for_uri(LATEST_URI);
+    if (uri == NULL)
+        return FALSE;
+
+    if (!g_file_load_contents(uri, NULL, &content, NULL, NULL, &err)) {
+        g_printerr("Could not load the content of %s: %s\n",
+                   LATEST_URI, err->message);
+        goto cleanup;
+    }
+
+    parser = json_parser_new();
+    if (parser == NULL) {
+        g_printerr("Failed to create the json parser\n");
+        goto cleanup;
+    }
+
+    if (!json_parser_load_from_data(parser, content, -1, &err)) {
+        g_printerr("Failed to parse the content of %s: %s\n",
+                   LATEST_URI, err->message);
+        goto cleanup;
+    }
+
+    reader = json_reader_new(json_parser_get_root(parser));
+    if (reader == NULL) {
+        g_printerr("Failed to create the reader for the json parser\n");
+        goto cleanup;
+    }
+
+    if (!json_reader_read_member(reader, "release")) {
+        const GError *error = json_reader_get_error(reader);
+        g_printerr("Failed to read the \"release\" member of the %s file: %s\n",
+                   LATEST_URI, error->message);
+        goto cleanup;
+    }
+
+    if (!json_reader_read_member(reader, "version")) {
+        const GError *error = json_reader_get_error(reader);
+        g_printerr("Failed to read the \"version\" member of the %s file: %s\n",
+                   LATEST_URI, error->message);
+        goto cleanup;
+    }
+
+    *version = g_strdup(json_reader_get_string_value(reader));
+    if (*version == NULL)
+        goto cleanup;
+
+    json_reader_end_member(reader); /* "version" */
+
+    if (!json_reader_read_member(reader, "archive")) {
+        const GError *error = json_reader_get_error(reader);
+        g_printerr("Failed to read the \"archive\" member of the %s file: %s\n",
+                   LATEST_URI, error->message);
+        goto cleanup;
+    }
+
+    *url = g_strdup(json_reader_get_string_value(reader));
+    if (*url == NULL)
+        goto cleanup;
+
+    json_reader_end_member(reader); /* "archive" */
+    json_reader_end_member(reader); /* "release" */
+
+    ret = TRUE;
+
+ cleanup:
+    g_object_unref(uri);
+    if (parser != NULL)
+        g_object_unref(parser);
+    if (reader != NULL)
+        g_object_unref(reader);
+    g_free(content);
+    g_clear_error(&err);
+
+    return ret;
+}
+
 static int osinfo_db_import_extract(GFile *target,
                                     const char *source,
                                     gboolean verbose)
@@ -204,7 +323,7 @@ static int osinfo_db_import_extract(GFile *target,
             goto cleanup;
 
         file_is_native = g_file_is_native(file);
-        if (!file_is_native(file)) {
+        if (!file_is_native) {
             if (osinfo_db_import_download_file(file, &source_file) < 0)
                 goto cleanup;
         } else {
@@ -266,6 +385,10 @@ gint main(gint argc, gchar **argv)
     gboolean user = FALSE;
     gboolean local = FALSE;
     gboolean system = FALSE;
+    gboolean latest = FALSE;
+    gchar *installed_version = NULL;
+    gchar *latest_version = NULL;
+    gchar *latest_url = NULL;
     const gchar *root = "";
     const gchar *archive = NULL;
     const gchar *custom = NULL;
@@ -284,6 +407,8 @@ gint main(gint argc, gchar **argv)
         N_("Import into custom directory"), NULL, },
       { "root", 0, 0, G_OPTION_ARG_STRING, &root,
         N_("Installation root directory"), NULL, },
+      { "latest", 0, 0, G_OPTION_ARG_NONE, (void *)&latest,
+        N_("Import the latest osinfo-db from osinfo-db's website"), NULL, },
       { NULL, 0, 0, 0, NULL, NULL, NULL },
     };
     argv0 = argv[0];
@@ -325,6 +450,22 @@ gint main(gint argc, gchar **argv)
 
     archive = argc == 2 ? argv[1] : NULL;
     dir = osinfo_db_get_path(root, user, local, system, custom);
+
+    if (latest) {
+        if (!osinfo_db_get_installed_version(dir, &installed_version))
+            goto error;
+
+        if (!osinfo_db_get_latest_info(&latest_version, &latest_url))
+            goto error;
+
+        if (g_strcmp0(latest_version, installed_version) <= 0) {
+            ret = EXIT_SUCCESS;
+            goto error;
+        }
+
+        archive = latest_url;
+    }
+
     if (osinfo_db_import_extract(dir, archive, verbose) < 0)
         goto error;
 
@@ -334,6 +475,9 @@ gint main(gint argc, gchar **argv)
     if (dir) {
         g_object_unref(dir);
     }
+    g_free(installed_version);
+    g_free(latest_version);
+    g_free(latest_url);
     g_clear_error(&error);
     g_option_context_free(context);
 
@@ -417,6 +561,13 @@ Prefix the installation location with the root directory
 given by C<PATH>. This is useful when wishing to install
 into a chroot environment or equivalent.
 
+=item B<--latest>
+
+Downloads the latest osinfo-db release from libosinfo's official
+releases website and installs it in the desired location.
+The latest osinfo-db release is only downloaded and installed
+when it's newer than the one installed in the desired location.
+
 =item B<-v>, B<--verbose>
 
 Display verbose progress information when installing files
-- 
2.19.1




More information about the Libosinfo mailing list