[gnome-software] Only parse /etc/os-release once per check
- From: Richard Hughes <rhughes src gnome org>
- To: commits-list gnome org
- Cc:
- Subject: [gnome-software] Only parse /etc/os-release once per check
- Date: Thu, 19 May 2016 19:53:58 +0000 (UTC)
commit 5d2d5e5dbcad80307c4fbb8b524e3e33b4f36ae3
Author: Richard Hughes <richard hughsie com>
Date: Thu May 19 20:26:40 2016 +0100
Only parse /etc/os-release once per check
Also, add some unit tests.
data/tests/Makefile.am | 1 +
data/tests/os-release | 16 ++
src/gs-os-release.c | 268 ++++++++++++++++++------
src/gs-os-release.h | 24 +-
src/gs-plugin.c | 14 +-
src/gs-self-test.c | 23 ++
src/plugins/gs-plugin-fedora-distro-upgrades.c | 10 +-
src/plugins/gs-plugin-odrs.c | 10 +-
8 files changed, 277 insertions(+), 89 deletions(-)
---
diff --git a/data/tests/Makefile.am b/data/tests/Makefile.am
index e3bfd24..019558b 100644
--- a/data/tests/Makefile.am
+++ b/data/tests/Makefile.am
@@ -1,4 +1,5 @@
EXTRA_DIST = \
+ os-release \
chiron-0.2.cab \
chiron-1.1-1.deb \
chiron-1.1-1.fc24.x86_64.rpm
diff --git a/data/tests/os-release b/data/tests/os-release
new file mode 100644
index 0000000..79df6af
--- /dev/null
+++ b/data/tests/os-release
@@ -0,0 +1,16 @@
+NAME=Fedora
+VERSION="25 (Workstation Edition)"
+ID=fedora
+VERSION_ID=25
+PRETTY_NAME="Fedora 25 (Workstation Edition)"
+ANSI_COLOR="0;34"
+CPE_NAME="cpe:/o:fedoraproject:fedora:25"
+HOME_URL="https://fedoraproject.org/"
+BUG_REPORT_URL="https://bugzilla.redhat.com/"
+REDHAT_BUGZILLA_PRODUCT="Fedora"
+REDHAT_BUGZILLA_PRODUCT_VERSION=25
+REDHAT_SUPPORT_PRODUCT="Fedora"
+REDHAT_SUPPORT_PRODUCT_VERSION=25
+PRIVACY_POLICY_URL=https://fedoraproject.org/wiki/Legal:PrivacyPolicy
+VARIANT="Workstation Edition"
+VARIANT_ID=workstation
diff --git a/src/gs-os-release.c b/src/gs-os-release.c
index 9c639af..6182045 100644
--- a/src/gs-os-release.c
+++ b/src/gs-os-release.c
@@ -1,6 +1,7 @@
/* -*- Mode: C; tab-width: 8; indent-tabs-mode: t; c-basic-offset: 8 -*-
*
* Copyright (C) 2016 Kalev Lember <klember redhat com>
+ * Copyright (C) 2016 Richard Hughes <richard hughsie com>
*
* Licensed under the GNU Lesser General Public License Version 2.1
*
@@ -19,111 +20,240 @@
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
*/
+/**
+ * SECTION:gs-os-release
+ * @title: GsOsRelease
+ * @include: gnome-software.h
+ * @stability: Unstable
+ * @short_description: Data from os-release
+ *
+ * This object allows plugins to parse /etc/os-release for distribution
+ * metadata information.
+ */
+
#include "config.h"
+#include <glib.h>
+
#include "gs-os-release.h"
-#include <string.h>
+struct _GsOsRelease
+{
+ GObject parent_instance;
+ gchar *name;
+ gchar *version;
+ gchar *id;
+ gchar *version_id;
+ gchar *pretty_name;
+};
+
+static void gs_os_release_initable_iface_init (GInitableIface *iface);
-G_DEFINE_QUARK (gs-os-release-error-quark, gs_os_release_error)
+G_DEFINE_TYPE_WITH_CODE (GsOsRelease, gs_os_release, G_TYPE_OBJECT,
+ G_IMPLEMENT_INTERFACE(G_TYPE_INITABLE, gs_os_release_initable_iface_init))
-/* strip any quotes surrounding the string */
-static gchar *
-dequote (gchar *s)
+/**
+ * gs_os_release_initable_init:
+ **/
+static gboolean
+gs_os_release_initable_init (GInitable *initable,
+ GCancellable *cancellable,
+ GError **error)
{
- size_t len;
+ GsOsRelease *os_release = GS_OS_RELEASE (initable);
+ const gchar *filename;
+ g_autofree gchar *data = NULL;
+ g_auto(GStrv) lines = NULL;
+ guint i;
- g_assert (s != NULL);
+ g_return_val_if_fail (GS_IS_OS_RELEASE (os_release), FALSE);
+ g_return_val_if_fail (error == NULL || *error == NULL, FALSE);
- len = strlen (s);
- if (len >= 2 &&
- *s == *(s + len - 1) &&
- (*s == '"' || *s == '\'')) {
- s[len - 1] = '\0';
- s++;
+ /* get contents */
+ filename = g_getenv ("GS_SELF_TEST_OS_RELEASE_FILENAME");
+ if (filename == NULL) {
+ filename = "/etc/os-release";
+ if (!g_file_test (filename, G_FILE_TEST_EXISTS))
+ filename = "/usr/lib/os-release";
}
+ if (!g_file_get_contents (filename, &data, NULL, error))
+ return FALSE;
- return s;
-}
+ /* parse */
+ lines = g_strsplit (data, "\n", -1);
+ for (i = 0; lines[i] != NULL; i++) {
+ gchar *tmp;
-static gchar *
-get_item (gchar *line, const gchar *key)
-{
- g_autofree gchar *label = NULL;
+ /* split the line up into two halves */
+ tmp = g_strstr_len (lines[i], -1, "=");
+ if (tmp == NULL)
+ continue;
+ *tmp = '\0';
+ tmp++;
- label = g_strconcat (key, "=", NULL);
- if (g_str_has_prefix (line, label)) {
- return g_strcompress (dequote (line + strlen (label)));
- }
+ /* ignore trailing quote */
+ if (tmp[0] == '\"')
+ tmp++;
+
+ /* ignore trailing quote */
+ g_strdelimit (tmp, "\"", '\0');
- return NULL;
+ /* match fields we're interested in */
+ if (g_strcmp0 (lines[i], "NAME") == 0) {
+ os_release->name = g_strdup (tmp);
+ continue;
+ }
+ if (g_strcmp0 (lines[i], "VERSION") == 0) {
+ os_release->version = g_strdup (tmp);
+ continue;
+ }
+ if (g_strcmp0 (lines[i], "ID") == 0) {
+ os_release->id = g_strdup (tmp);
+ continue;
+ }
+ if (g_strcmp0 (lines[i], "VERSION_ID") == 0) {
+ os_release->version_id = g_strdup (tmp);
+ continue;
+ }
+ if (g_strcmp0 (lines[i], "PRETTY_NAME") == 0) {
+ os_release->pretty_name = g_strdup (tmp);
+ continue;
+ }
+ }
+ return TRUE;
}
-static gchar *
-gs_os_release_parse_variable (const gchar *variable, GError **error)
+/**
+ * gs_os_release_get_name:
+ * @os_release: A #GsOsRelease
+ *
+ * Gets the name from the os-release parser.
+ *
+ * Returns: a string, or %NULL
+ **/
+const gchar *
+gs_os_release_get_name (GsOsRelease *os_release)
{
- const gchar *filename;
- g_autofree gchar *buffer = NULL;
-
- g_return_val_if_fail (error == NULL || *error == NULL, NULL);
- g_return_val_if_fail (variable != NULL, NULL);
-
- filename = "/etc/os-release";
- if (!g_file_test (filename, G_FILE_TEST_EXISTS))
- filename = "/usr/lib/os-release";
-
- if (!g_file_get_contents (filename, &buffer, NULL, error))
- return NULL;
+ g_return_val_if_fail (GS_IS_OS_RELEASE (os_release), NULL);
+ return os_release->name;
+}
- if (buffer != NULL) {
- gint i;
- g_auto(GStrv) lines = NULL;
+/**
+ * gs_os_release_get_version:
+ * @os_release: A #GsOsRelease
+ *
+ * Gets the version from the os-release parser.
+ *
+ * Returns: a string, or %NULL
+ **/
+const gchar *
+gs_os_release_get_version (GsOsRelease *os_release)
+{
+ g_return_val_if_fail (GS_IS_OS_RELEASE (os_release), NULL);
+ return os_release->version;
+}
- lines = g_strsplit (buffer, "\n", -1);
- for (i = 0; lines[i] != NULL; i++) {
- gchar *line = g_strstrip (lines[i]);
- gchar *ret;
+/**
+ * gs_os_release_get_id:
+ * @os_release: A #GsOsRelease
+ *
+ * Gets the ID from the os-release parser.
+ *
+ * Returns: a string, or %NULL
+ **/
+const gchar *
+gs_os_release_get_id (GsOsRelease *os_release)
+{
+ g_return_val_if_fail (GS_IS_OS_RELEASE (os_release), NULL);
+ return os_release->id;
+}
- if ((ret = get_item (line, variable)) != NULL)
- return ret;
- }
- }
+/**
+ * gs_os_release_get_version_id:
+ * @os_release: A #GsOsRelease
+ *
+ * Gets the version ID from the os-release parser.
+ *
+ * Returns: a string, or %NULL
+ **/
+const gchar *
+gs_os_release_get_version_id (GsOsRelease *os_release)
+{
+ g_return_val_if_fail (GS_IS_OS_RELEASE (os_release), NULL);
+ return os_release->version_id;
+}
- g_set_error (error,
- GS_OS_RELEASE_ERROR,
- GS_OS_RELEASE_ERROR_FAILED,
- "could not find variable '%s' in %s", variable, filename);
- return NULL;
+/**
+ * gs_os_release_get_pretty_name:
+ * @os_release: A #GsOsRelease
+ *
+ * Gets the pretty name from the os-release parser.
+ *
+ * Returns: a string, or %NULL
+ **/
+const gchar *
+gs_os_release_get_pretty_name (GsOsRelease *os_release)
+{
+ g_return_val_if_fail (GS_IS_OS_RELEASE (os_release), NULL);
+ return os_release->pretty_name;
}
-gchar *
-gs_os_release_get_name (GError **error)
+/**
+ * gs_os_release_finalize:
+ **/
+static void
+gs_os_release_finalize (GObject *object)
{
- return gs_os_release_parse_variable ("NAME", error);
+ GsOsRelease *os_release = GS_OS_RELEASE (object);
+ g_free (os_release->name);
+ g_free (os_release->version);
+ g_free (os_release->id);
+ g_free (os_release->version_id);
+ g_free (os_release->pretty_name);
+ G_OBJECT_CLASS (gs_os_release_parent_class)->finalize (object);
}
-gchar *
-gs_os_release_get_version (GError **error)
+/**
+ * gs_os_release_class_init:
+ **/
+static void
+gs_os_release_class_init (GsOsReleaseClass *klass)
{
- return gs_os_release_parse_variable ("VERSION", error);
+ GObjectClass *object_class = G_OBJECT_CLASS (klass);
+ object_class->finalize = gs_os_release_finalize;
}
-gchar *
-gs_os_release_get_id (GError **error)
+/**
+ * gs_os_release_initable_iface_init:
+ **/
+static void
+gs_os_release_initable_iface_init (GInitableIface *iface)
{
- return gs_os_release_parse_variable ("ID", error);
+ iface->init = gs_os_release_initable_init;
}
-gchar *
-gs_os_release_get_version_id (GError **error)
+/**
+ * gs_os_release_init:
+ **/
+static void
+gs_os_release_init (GsOsRelease *os_release)
{
- return gs_os_release_parse_variable ("VERSION_ID", error);
}
-gchar *
-gs_os_release_get_pretty_name (GError **error)
+/**
+ * gs_os_release_new:
+ * @error: a #GError, or %NULL
+ *
+ * Creates a new os_release.
+ *
+ * Returns: A newly allocated #GsOsRelease
+ **/
+GsOsRelease *
+gs_os_release_new (GError **error)
{
- return gs_os_release_parse_variable ("PRETTY_NAME", error);
+ GsOsRelease *os_release;
+ os_release = g_initable_new (GS_TYPE_OS_RELEASE, NULL, error, NULL);
+ return GS_OS_RELEASE (os_release);
}
/* vim: set noexpandtab: */
diff --git a/src/gs-os-release.h b/src/gs-os-release.h
index cc9b7c7..ffd338e 100644
--- a/src/gs-os-release.h
+++ b/src/gs-os-release.h
@@ -1,6 +1,7 @@
/* -*- Mode: C; tab-width: 8; indent-tabs-mode: t; c-basic-offset: 8 -*-
*
* Copyright (C) 2016 Kalev Lember <klember redhat com>
+ * Copyright (C) 2016 Richard Hughes <richard hughsie com>
*
* Licensed under the GNU Lesser General Public License Version 2.1
*
@@ -22,23 +23,22 @@
#ifndef __GS_OS_RELEASE_H
#define __GS_OS_RELEASE_H
-#include <glib.h>
+#include <glib-object.h>
+
+#include "gs-app.h"
G_BEGIN_DECLS
-#define GS_OS_RELEASE_ERROR gs_os_release_error_quark ()
+#define GS_TYPE_OS_RELEASE (gs_os_release_get_type ())
-typedef enum
-{
- GS_OS_RELEASE_ERROR_FAILED
-} GsOsReleaseError;
+G_DECLARE_FINAL_TYPE (GsOsRelease, gs_os_release, GS, OS_RELEASE, GObject)
-GQuark gs_os_release_error_quark (void);
-gchar *gs_os_release_get_name (GError **error);
-gchar *gs_os_release_get_version (GError **error);
-gchar *gs_os_release_get_id (GError **error);
-gchar *gs_os_release_get_version_id (GError **error);
-gchar *gs_os_release_get_pretty_name (GError **error);
+GsOsRelease *gs_os_release_new (GError **error);
+const gchar *gs_os_release_get_name (GsOsRelease *os_release);
+const gchar *gs_os_release_get_version (GsOsRelease *os_release);
+const gchar *gs_os_release_get_id (GsOsRelease *os_release);
+const gchar *gs_os_release_get_version_id (GsOsRelease *os_release);
+const gchar *gs_os_release_get_pretty_name (GsOsRelease *os_release);
G_END_DECLS
diff --git a/src/gs-plugin.c b/src/gs-plugin.c
index d5027f6..5fe945e 100644
--- a/src/gs-plugin.c
+++ b/src/gs-plugin.c
@@ -611,12 +611,20 @@ gboolean
gs_plugin_check_distro_id (GsPlugin *plugin, const gchar *distro_id)
{
g_autoptr(GError) error = NULL;
- g_autofree gchar *id = NULL;
+ g_autoptr(GsOsRelease) os_release = NULL;
+ const gchar *id = NULL;
+
+ /* load /etc/os-release */
+ os_release = gs_os_release_new (&error);
+ if (os_release == NULL) {
+ g_debug ("could not parse os-release: %s", error->message);
+ return FALSE;
+ }
/* check that we are running on Fedora */
- id = gs_os_release_get_id (&error);
+ id = gs_os_release_get_id (os_release);
if (id == NULL) {
- g_debug ("could not parse os-release: %s", error->message);
+ g_debug ("could not get distro ID");
return FALSE;
}
if (g_strcmp0 (id, distro_id) != 0)
diff --git a/src/gs-self-test.c b/src/gs-self-test.c
index cc1882a..1222555 100644
--- a/src/gs-self-test.c
+++ b/src/gs-self-test.c
@@ -28,6 +28,7 @@
#include "gs-app-private.h"
#include "gs-app-list-private.h"
+#include "gs-os-release.h"
#include "gs-plugin.h"
#include "gs-plugin-loader.h"
#include "gs-plugin-loader-sync.h"
@@ -104,6 +105,27 @@ gs_app_list_filter_cb (GsApp *app, gpointer user_data)
}
static void
+gs_os_release_func (void)
+{
+ g_autofree gchar *fn = NULL;
+ g_autoptr(GError) error = NULL;
+ g_autoptr(GsOsRelease) os_release = NULL;
+
+ fn = gs_test_get_filename ("tests/os-release");
+ g_assert (fn != NULL);
+ g_setenv ("GS_SELF_TEST_OS_RELEASE_FILENAME", fn, TRUE);
+
+ os_release = gs_os_release_new (&error);
+ g_assert_no_error (error);
+ g_assert (os_release != NULL);
+ g_assert_cmpstr (gs_os_release_get_id (os_release), ==, "fedora");
+ g_assert_cmpstr (gs_os_release_get_name (os_release), ==, "Fedora");
+ g_assert_cmpstr (gs_os_release_get_version (os_release), ==, "25 (Workstation Edition)");
+ g_assert_cmpstr (gs_os_release_get_version_id (os_release), ==, "25");
+ g_assert_cmpstr (gs_os_release_get_pretty_name (os_release), ==, "Fedora 25 (Workstation Edition)");
+}
+
+static void
gs_plugin_func (void)
{
GsAppList *list;
@@ -891,6 +913,7 @@ main (int argc, char **argv)
g_log_set_fatal_mask (NULL, G_LOG_LEVEL_ERROR | G_LOG_LEVEL_CRITICAL);
/* generic tests go here */
+ g_test_add_func ("/gnome-software/os-release", gs_os_release_func);
g_test_add_func ("/gnome-software/app", gs_app_func);
g_test_add_func ("/gnome-software/plugin", gs_plugin_func);
diff --git a/src/plugins/gs-plugin-fedora-distro-upgrades.c b/src/plugins/gs-plugin-fedora-distro-upgrades.c
index dc96aa1..5429ca3 100644
--- a/src/plugins/gs-plugin-fedora-distro-upgrades.c
+++ b/src/plugins/gs-plugin-fedora-distro-upgrades.c
@@ -94,9 +94,10 @@ gboolean
gs_plugin_setup (GsPlugin *plugin, GCancellable *cancellable, GError **error)
{
GsPluginData *priv = gs_plugin_get_data (plugin);
+ const gchar *verstr = NULL;
gchar *endptr = NULL;
- g_autofree gchar *verstr = NULL;
g_autoptr(GFile) file = NULL;
+ g_autoptr(GsOsRelease) os_release = NULL;
/* get the file to cache */
priv->cachefn = gs_utils_get_cache_filename ("upgrades",
@@ -118,10 +119,13 @@ gs_plugin_setup (GsPlugin *plugin, GCancellable *cancellable, GError **error)
G_CALLBACK (gs_plugin_fedora_distro_upgrades_changed_cb), plugin);
/* read os-release for the current versions */
- priv->os_name = gs_os_release_get_name (error);
+ os_release = gs_os_release_new (error);
+ if (os_release == NULL)
+ return FALSE;
+ priv->os_name = g_strdup (gs_os_release_get_name (os_release));
if (priv->os_name == NULL)
return FALSE;
- verstr = gs_os_release_get_version_id (error);
+ verstr = gs_os_release_get_version_id (os_release);
if (verstr == NULL)
return FALSE;
diff --git a/src/plugins/gs-plugin-odrs.c b/src/plugins/gs-plugin-odrs.c
index a776492..13ad8a4 100644
--- a/src/plugins/gs-plugin-odrs.c
+++ b/src/plugins/gs-plugin-odrs.c
@@ -48,6 +48,7 @@ gs_plugin_initialize (GsPlugin *plugin)
{
GsPluginData *priv = gs_plugin_alloc_data (plugin, sizeof(GsPluginData));
g_autoptr(GError) error = NULL;
+ g_autoptr(GsOsRelease) os_release = NULL;
priv->settings = g_settings_new ("org.gnome.software");
priv->review_server = g_settings_get_string (priv->settings,
@@ -61,9 +62,14 @@ gs_plugin_initialize (GsPlugin *plugin)
}
/* get the distro name (e.g. 'Fedora') but allow a fallback */
- priv->distro = gs_os_release_get_name (&error);
+ os_release = gs_os_release_new (&error);
+ if (os_release == NULL) {
+ g_warning ("failed to get distro name: %s", error->message);
+ priv->distro = g_strdup ("Unknown");
+ }
+ priv->distro = g_strdup (gs_os_release_get_name (os_release));
if (priv->distro == NULL) {
- g_warning ("Failed to get distro name: %s", error->message);
+ g_warning ("failed to get distro name");
priv->distro = g_strdup ("Unknown");
}
}
[
Date Prev][
Date Next] [
Thread Prev][
Thread Next]
[
Thread Index]
[
Date Index]
[
Author Index]