preset: Use GST_PRESET_PATH as an extension of the system path, not a replacement...
authorSebastian Dröge <sebastian@centricular.com>
Tue, 22 Mar 2016 17:04:59 +0000 (19:04 +0200)
committerSebastian Dröge <sebastian@centricular.com>
Tue, 22 Mar 2016 17:32:48 +0000 (19:32 +0200)
First load all system presets, then all from the environment variable, then
from the app directory, then from the user directory. Any one in the chain
with the highest version completely replaces all previous ones, later ones
with lower versions are merged in without replacing existing presets.

This is basically the same behaviour as before, just that GST_PRESET_PATH is
inserted as another source of directories between the system and app presets.

It was added in ca08af1f17d2ce36b83998a0ba3a7b8bcafd7872, but was
accidentially overriding the user preset path there. Which caused inconsistent
behaviour as new presets were still stored in the system path, just not loaded
from there. Meaning you could store a new preset (in the user path), just for
GstPreset to not find it anymore later (because it only looked in the
GST_PRESET_PATH instead of the user path).

https://bugzilla.gnome.org/show_bug.cgi?id=764034

gst/gstpreset.c

index 12f4cd4..11c2801 100644 (file)
@@ -349,6 +349,26 @@ preset_merge (GKeyFile * system, GKeyFile * user)
   g_strfreev (groups);
 }
 
+typedef struct
+{
+  GKeyFile *preset;
+  guint64 version;
+} PresetAndVersion;
+
+static gint
+compare_preset_and_version (gconstpointer a, gconstpointer b,
+    gpointer user_data)
+{
+  const PresetAndVersion *pa = a, *pb = b;
+
+  if (pa->version > pb->version)
+    return -1;
+  if (pa->version < pb->version)
+    return 1;
+  else
+    return 0;
+}
+
 /* reads the user and system presets files and merges them together. This
  * function caches the GKeyFile on the element type. If there is no existing
  * preset file, a new in-memory GKeyFile will be created. */
@@ -366,12 +386,23 @@ preset_get_keyfile (GstPreset * preset)
     guint64 version_user = G_GUINT64_CONSTANT (0);
     guint64 version = G_GUINT64_CONSTANT (0);
     gboolean merged = FALSE;
-    GKeyFile *in_user = NULL, *in_app = NULL, *in_system;
-
+    GKeyFile *in_user, *in_app = NULL, *in_system;
+    GQueue in_env = G_QUEUE_INIT;
+    gboolean have_env = FALSE;
     const gchar *envvar;
 
     /* try to load the user, app and system presets, we do this to get the
      * versions of all files. */
+    preset_get_paths (preset, &preset_user_path, &preset_app_path,
+        &preset_system_path);
+    in_user = preset_open_and_parse_header (preset, preset_user_path,
+        &version_user);
+
+    if (preset_app_path) {
+      in_app = preset_open_and_parse_header (preset, preset_app_path,
+          &version_app);
+    }
+
     envvar = g_getenv ("GST_PRESET_PATH");
     if (envvar) {
       gint i;
@@ -380,27 +411,23 @@ preset_get_keyfile (GstPreset * preset)
       for (i = 0; preset_dirs[i]; i++) {
         gchar *preset_path = g_strdup_printf ("%s" G_DIR_SEPARATOR_S "%s.prs",
             preset_dirs[i], G_OBJECT_TYPE_NAME (preset));
+        GKeyFile *env_file;
+        guint64 env_version;
 
-        in_user = preset_open_and_parse_header (preset, preset_path,
-            &version_user);
+        env_file = preset_open_and_parse_header (preset, preset_path,
+            &env_version);
         g_free (preset_path);
-        if (in_user)
-          break;
+        if (env_file) {
+          PresetAndVersion *pv = g_new (PresetAndVersion, 1);
+          pv->preset = env_file;
+          pv->version = env_version;
+          g_queue_push_tail (&in_env, pv);
+          have_env = TRUE;
+        }
       }
       g_strfreev (preset_dirs);
     }
 
-    preset_get_paths (preset, &preset_user_path, &preset_app_path,
-        &preset_system_path);
-    if (!in_user) {
-      in_user = preset_open_and_parse_header (preset, preset_user_path,
-          &version_user);
-    }
-
-    if (preset_app_path) {
-      in_app = preset_open_and_parse_header (preset, preset_app_path,
-          &version_app);
-    }
     in_system = preset_open_and_parse_header (preset, preset_system_path,
         &version_system);
 
@@ -409,8 +436,34 @@ preset_get_keyfile (GstPreset * preset)
       presets = in_system;
       version = version_system;
     }
+
+    if (have_env) {
+      GList *l;
+
+      /* merge the ones from the environment paths. If any of them has a
+       * higher version, take that as the "master" version. Lower versions are
+       * then just merged in. */
+      g_queue_sort (&in_env, compare_preset_and_version, NULL);
+      /* highest version to lowest */
+      for (l = in_env.head; l; l = l->next) {
+        PresetAndVersion *pv = l->data;
+
+        if (version > pv->version) {
+          preset_merge (presets, pv->preset);
+          g_key_file_free (pv->preset);
+        } else {
+          if (presets)
+            g_key_file_free (presets);
+          presets = pv->preset;
+          version = pv->version;
+        }
+        g_free (pv);
+      }
+      g_queue_clear (&in_env);
+    }
+
     if (in_app) {
-      /* if system version is higher, merge */
+      /* if system/env version is higher, merge */
       if (version > version_app) {
         preset_merge (presets, in_app);
         g_key_file_free (in_app);
@@ -422,7 +475,7 @@ preset_get_keyfile (GstPreset * preset)
       }
     }
     if (in_user) {
-      /* if system or app version is higher, merge */
+      /* if system/env or app version is higher, merge */
       if (version > version_user) {
         preset_merge (presets, in_user);
         g_key_file_free (in_user);