--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@xxxxxxxxxx> --- configure.ac | 1 + tools/Makefile.am | 3 + tools/osinfo-db-import.c | 151 +++++++++++++++++++++++++++++++++++++++ 3 files changed, 155 insertions(+) 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/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 e4b7824..2117084 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, @@ -183,6 +188,120 @@ osinfo_db_import_download_file(const gchar *url, return ret; } +static gboolean osinfo_db_get_installed_version(GFile *dir, + gchar **version) +{ + GFile *file = NULL; + GFileInfo *info = NULL; + GFileInputStream *stream = NULL; + goffset count; + GError *err = NULL; + gboolean ret = FALSE; + + file = g_file_get_child(dir, VERSION_FILE); + if (file == NULL) + return FALSE; + + info = g_file_query_info(file, "standard", G_FILE_QUERY_INFO_NONE, NULL, &err); + if (err != NULL) { + /* In the case the file was not found, it just means that there's no + * osinfo-db installed in the specified, directory. Let's just return + * TRUE and proceed normally from here. */ + if (err->code == G_IO_ERROR_NOT_FOUND) { + ret = TRUE; + goto cleanup; + } + g_printerr("Failed to query info for file %s: %s\n", + VERSION_FILE, err->message); + goto cleanup; + } + + stream = g_file_read(file, NULL, &err); + if (err != NULL) { + g_printerr("Failed to read the file %s: %s\n", + VERSION_FILE, err->message); + goto cleanup; + } + + count = g_file_info_get_size(info); + *version = g_malloc0(count*sizeof(gchar)); + if (*version == NULL) + goto cleanup; + + if (!g_input_stream_read_all(G_INPUT_STREAM(stream), + (void *)*version, + count, + NULL, + NULL, + &err)) { + g_printerr("Failed get the content of file %s: %s\n", + VERSION_FILE, err->message); + goto cleanup; + } + + ret = TRUE; + + cleanup: + g_object_unref(file); + if (info != NULL) + g_object_unref(info); + if (stream != NULL) + g_object_unref(stream); + if (err != NULL) + g_error_free(err); + if (!ret) + g_free(*version); + + 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 "LATEST_URI": %s\n", + err->message); + goto cleanup; + } + + parser = json_parser_new(); + json_parser_load_from_data(parser, content, -1, NULL); + + reader = json_reader_new(json_parser_get_root(parser)); + + json_reader_read_member(reader, "release"); + json_reader_read_member(reader, "version"); + *version = g_strdup(json_reader_get_string_value(reader)); + json_reader_end_member(reader); + json_reader_read_member(reader, "archive"); + *url = g_strdup(json_reader_get_string_value(reader)); + json_reader_end_member(reader); + json_reader_end_member(reader); + + ret = TRUE; + + cleanup: + g_object_unref(uri); + if (parser != NULL) + g_object_unref(parser); + if (reader != NULL) + g_object_unref(reader); + g_free(content); + + return ret; +} + static int osinfo_db_import_extract(GFile *target, const char *source, gboolean verbose) @@ -281,6 +400,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; @@ -299,6 +422,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]; @@ -340,6 +465,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; @@ -349,6 +490,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); @@ -432,6 +576,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 _______________________________________________ Libosinfo mailing list Libosinfo@xxxxxxxxxx https://www.redhat.com/mailman/listinfo/libosinfo