[gnome-builder/wip/mwleeds/ide-config-provider: 7/15] flatpak: Move flatpak manifests from runtimes to configurations



commit b07451d841f35dc5122be3bfbd37b163cb9259a1
Author: Matthew Leeds <mleeds redhat com>
Date:   Wed Dec 21 15:24:45 2016 -0600

    flatpak: Move flatpak manifests from runtimes to configurations
    
    Since flatpak manifests specify how to build a project, it makes more
    sense for them to be configurations rather than runtimes in Builder. Now
    that setup is possible since we have the IdeConfigurationProvider interface.
    
    https://bugzilla.gnome.org/show_bug.cgi?id=777959

 libide/buildsystem/ide-configuration.c             |   12 +
 libide/buildsystem/ide-configuration.h             |    2 +
 plugins/flatpak/Makefile.am                        |    2 +
 .../flatpak/gbp-flatpak-configuration-provider.c   |  582 ++++++++++++++++++++
 .../flatpak/gbp-flatpak-configuration-provider.h   |   32 ++
 plugins/flatpak/gbp-flatpak-plugin.c               |    4 +
 plugins/flatpak/gbp-flatpak-runtime-provider.c     |  331 -----------
 plugins/flatpak/gbp-flatpak-runtime.c              |  466 +++++++---------
 8 files changed, 840 insertions(+), 591 deletions(-)
---
diff --git a/libide/buildsystem/ide-configuration.c b/libide/buildsystem/ide-configuration.c
index 1fae34c..8d690b7 100644
--- a/libide/buildsystem/ide-configuration.c
+++ b/libide/buildsystem/ide-configuration.c
@@ -940,6 +940,18 @@ ide_configuration_get_environment (IdeConfiguration *self)
   return self->environment;
 }
 
+void
+ide_configuration_set_environment (IdeConfiguration *self,
+                                   IdeEnvironment   *environment)
+{
+  IdeConfigurationPrivate *priv = ide_configuration_get_instance_private (self);
+
+  g_return_if_fail (IDE_IS_CONFIGURATION (self));
+
+  g_clear_object (&priv->environment);
+  priv->environment = g_object_ref (environment);
+}
+
 const gchar *
 ide_configuration_get_config_opts (IdeConfiguration *self)
 {
diff --git a/libide/buildsystem/ide-configuration.h b/libide/buildsystem/ide-configuration.h
index 96be371..224b21b 100644
--- a/libide/buildsystem/ide-configuration.h
+++ b/libide/buildsystem/ide-configuration.h
@@ -72,6 +72,8 @@ gint                  ide_configuration_get_parallelism      (IdeConfiguration
 void                  ide_configuration_set_parallelism      (IdeConfiguration  *self,
                                                               gint               parallelism);
 IdeEnvironment       *ide_configuration_get_environment      (IdeConfiguration  *self);
+void                  ide_configuration_set_environment      (IdeConfiguration  *self,
+                                                              IdeEnvironment    *environment);
 IdeConfiguration     *ide_configuration_duplicate            (IdeConfiguration  *self);
 IdeConfiguration     *ide_configuration_snapshot             (IdeConfiguration  *self);
 guint                 ide_configuration_get_sequence         (IdeConfiguration  *self);
diff --git a/plugins/flatpak/Makefile.am b/plugins/flatpak/Makefile.am
index a5324bd..4cc85e6 100644
--- a/plugins/flatpak/Makefile.am
+++ b/plugins/flatpak/Makefile.am
@@ -10,6 +10,8 @@ plugin_LTLIBRARIES = libflatpak-plugin.la
 dist_plugin_DATA = flatpak.plugin
 
 libflatpak_plugin_la_SOURCES = \
+       gbp-flatpak-configuration-provider.c \
+       gbp-flatpak-configuration-provider.h \
        gbp-flatpak-runtime-provider.c \
        gbp-flatpak-runtime-provider.h \
        gbp-flatpak-runtime.c \
diff --git a/plugins/flatpak/gbp-flatpak-configuration-provider.c 
b/plugins/flatpak/gbp-flatpak-configuration-provider.c
new file mode 100644
index 0000000..939c940
--- /dev/null
+++ b/plugins/flatpak/gbp-flatpak-configuration-provider.c
@@ -0,0 +1,582 @@
+/* gbp-flatpak-configuration-provider.c
+ *
+ * Copyright (C) 2016 Matthew Leeds <mleeds redhat com>
+ *
+ * This program is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program.  If not, see <http://www.gnu.org/licenses/>.
+ */
+
+#define G_LOG_DOMAIN "gbp-flatpak-configuration-provider"
+
+#include <string.h>
+#include <flatpak.h>
+#include <json-glib/json-glib.h>
+
+#include "util/ide-posix.h"
+
+#include "buildsystem/ide-environment.h"
+#include "buildsystem/ide-configuration.h"
+#include "buildsystem/ide-configuration-provider.h"
+#include "gbp-flatpak-configuration-provider.h"
+#include "gbp-flatpak-configuration.h"
+
+struct _GbpFlatpakConfigurationProvider
+{
+  GObject                  parent_instance;
+  IdeConfigurationManager *manager;
+  GCancellable            *cancellable;
+  GPtrArray               *configurations;
+};
+
+typedef struct
+{
+  gchar          *app_id;
+  gchar          *config_opts;
+  gchar          *prefix;
+  gchar          *primary_module;
+  gchar          *runtime_id;
+  GFile          *file;
+  IdeEnvironment *environment;
+} FlatpakManifest;
+
+static void configuration_provider_iface_init (IdeConfigurationProviderInterface *);
+
+G_DEFINE_TYPE_EXTENDED (GbpFlatpakConfigurationProvider, gbp_flatpak_configuration_provider, G_TYPE_OBJECT, 
0,
+                        G_IMPLEMENT_INTERFACE (IDE_TYPE_CONFIGURATION_PROVIDER,
+                                               configuration_provider_iface_init))
+
+static void gbp_flatpak_configuration_provider_load (IdeConfigurationProvider *provider, 
IdeConfigurationManager *manager);
+static void gbp_flatpak_configuration_provider_unload (IdeConfigurationProvider *provider, 
IdeConfigurationManager *manager);
+
+static gboolean
+contains_id (GPtrArray   *ar,
+             const gchar *id)
+{
+  g_assert (ar != NULL);
+  g_assert (id != NULL);
+
+  for (guint i = 0; i < ar->len; i++)
+    {
+      IdeConfiguration *configuration = g_ptr_array_index (ar, i);
+
+      g_assert (IDE_IS_CONFIGURATION (configuration));
+
+      if (ide_str_equal0 (id, ide_configuration_get_id (configuration)))
+        return TRUE;
+    }
+
+  return FALSE;
+}
+
+static void
+flatpak_manifest_free (void *data)
+{
+  FlatpakManifest *manifest = data;
+
+  g_free (manifest->app_id);
+  g_free (manifest->config_opts);
+  g_free (manifest->prefix);
+  g_free (manifest->primary_module);
+  g_free (manifest->runtime_id);
+  g_clear_object (&manifest->environment);
+  g_clear_object (&manifest->file);
+  g_slice_free (FlatpakManifest, manifest);
+}
+
+JsonNode *
+guess_primary_module (JsonNode *modules_node,
+                      GFile    *directory)
+{
+  JsonArray *modules;
+  JsonNode *module;
+  g_autofree gchar *dir_name;
+
+  g_assert (G_IS_FILE (directory));
+
+  dir_name = g_file_get_basename (directory);
+  g_assert (!ide_str_empty0 (dir_name));
+  g_return_val_if_fail (JSON_NODE_HOLDS_ARRAY (modules_node), NULL);
+
+  /* TODO: Support module strings that refer to other files? */
+  modules = json_node_get_array (modules_node);
+  if (json_array_get_length (modules) == 1)
+    {
+      module = json_array_get_element (modules, 0);
+      if (JSON_NODE_HOLDS_OBJECT (module))
+        return module;
+    }
+  else
+    {
+      for (guint i = 0; i < json_array_get_length (modules); i++)
+        {
+          module = json_array_get_element (modules, i);
+          if (JSON_NODE_HOLDS_OBJECT (module))
+            {
+              const gchar *module_name;
+              module_name = json_object_get_string_member (json_node_get_object (module), "name");
+              if (g_strcmp0 (module_name, dir_name) == 0)
+                return module;
+              if (json_object_has_member (json_node_get_object (module), "modules"))
+                {
+                  JsonNode *nested_modules_node;
+                  JsonNode *nested_primary_module;
+                  nested_modules_node = json_object_get_member (json_node_get_object (module), "modules");
+                  nested_primary_module = guess_primary_module (nested_modules_node, directory);
+                  if (nested_primary_module != NULL)
+                    return nested_primary_module;
+                }
+            }
+        }
+    }
+
+  return NULL;
+}
+
+static GPtrArray *
+gbp_flatpak_configuration_provider_find_flatpak_manifests (GbpFlatpakConfigurationProvider *self,
+                                                           GCancellable                    *cancellable,
+                                                           GFile                           *directory,
+                                                           GError                         **error)
+{
+  g_autoptr(GFileEnumerator) enumerator = NULL;
+  GFileInfo *file_info = NULL;
+  GPtrArray *ar;
+
+  g_assert (GBP_IS_FLATPAK_CONFIGURATION_PROVIDER (self));
+  g_assert (!cancellable || G_IS_CANCELLABLE (cancellable));
+  g_assert (G_IS_FILE (directory));
+
+  ar = g_ptr_array_new ();
+  g_ptr_array_set_free_func (ar, flatpak_manifest_free);
+
+  enumerator = g_file_enumerate_children (directory,
+                                          G_FILE_ATTRIBUTE_STANDARD_NAME,
+                                          G_FILE_QUERY_INFO_NONE,
+                                          cancellable,
+                                          error);
+  if (!enumerator)
+    return NULL;
+
+  while ((file_info = g_file_enumerator_next_file (enumerator, cancellable, NULL)))
+    {
+      GFileType file_type;
+      g_autofree gchar *name = NULL;
+      g_autofree gchar *path = NULL;
+      const gchar *platform;
+      const gchar *branch;
+      const gchar *arch;
+      g_autoptr(GRegex) filename_regex = NULL;
+      g_autoptr(GMatchInfo) match_info = NULL;
+      g_autoptr(JsonParser) parser = NULL;
+      JsonNode *root_node = NULL;
+      JsonNode *app_id_node = NULL;
+      JsonNode *id_node = NULL;
+      JsonNode *runtime_node = NULL;
+      JsonNode *runtime_version_node = NULL;
+      JsonNode *sdk_node = NULL;
+      JsonNode *modules_node = NULL;
+      JsonNode *primary_module_node = NULL;
+      JsonObject *root_object = NULL;
+      g_autoptr(GError) local_error = NULL;
+      g_autoptr(GFile) file = NULL;
+      FlatpakManifest *manifest;
+
+      file_type = g_file_info_get_file_type (file_info);
+      name = g_strdup (g_file_info_get_name (file_info));
+      g_clear_object (&file_info);
+
+      if (name == NULL || file_type == G_FILE_TYPE_DIRECTORY)
+        continue;
+
+      file = g_file_get_child (directory, name);
+
+      /* This regex is based on https://wiki.gnome.org/HowDoI/ChooseApplicationID */
+      filename_regex = g_regex_new ("^[[:alnum:]-_]+\\.[[:alnum:]-_]+(\\.[[:alnum:]-_]+)*\\.json$",
+                                    0, 0, NULL);
+
+      g_regex_match (filename_regex, name, 0, &match_info);
+      if (!g_match_info_matches (match_info))
+        continue;
+
+      /* Check if the contents look like a flatpak manifest */
+      path = g_file_get_path (file);
+      parser = json_parser_new ();
+      json_parser_load_from_file (parser, path, &local_error);
+      if (local_error != NULL)
+        continue;
+
+      root_node = json_parser_get_root (parser);
+      if (!JSON_NODE_HOLDS_OBJECT (root_node))
+        continue;
+
+      root_object = json_node_get_object (root_node);
+      app_id_node = json_object_get_member (root_object, "app-id");
+      id_node = json_object_get_member (root_object, "id");
+      runtime_node = json_object_get_member (root_object, "runtime");
+      runtime_version_node = json_object_get_member (root_object, "runtime-version");
+      sdk_node = json_object_get_member (root_object, "sdk");
+      modules_node = json_object_get_member (root_object, "modules");
+
+      if ((!JSON_NODE_HOLDS_VALUE (app_id_node) && !JSON_NODE_HOLDS_VALUE (id_node)) ||
+           !JSON_NODE_HOLDS_VALUE (runtime_node) ||
+           !JSON_NODE_HOLDS_VALUE (sdk_node) ||
+           !JSON_NODE_HOLDS_ARRAY (modules_node))
+        continue;
+
+      IDE_TRACE_MSG ("Discovered flatpak manifest at %s", path);
+
+      manifest = g_slice_new0 (FlatpakManifest);
+
+      manifest->file = g_steal_pointer (&file);
+
+      /**
+       * TODO: Currently we just support the build-options object that's global to the
+       * manifest, but modules can have their own build-options as well that override
+       * global ones, so we should consider supporting that. The main difficulty would
+       * be keeping track of each so they can be written back to the file properly when
+       * the user makes changes in the Builder interface.
+       */
+      if (json_object_has_member (root_object, "build-options") &&
+          JSON_NODE_HOLDS_OBJECT (json_object_get_member (root_object, "build-options")))
+        {
+          JsonObject *build_options = NULL;
+          IdeEnvironment *environment;
+
+          build_options = json_object_get_object_member (root_object, "build-options");
+
+          if (json_object_has_member (build_options, "prefix"))
+            {
+              const gchar *prefix;
+              prefix = json_object_get_string_member (build_options, "prefix");
+              if (prefix != NULL)
+                manifest->prefix = g_strdup (prefix);
+            }
+
+          environment = ide_environment_new ();
+          if (json_object_has_member (build_options, "cflags"))
+            {
+              const gchar *cflags;
+              cflags = json_object_get_string_member (build_options, "cflags");
+              if (cflags != NULL)
+                ide_environment_setenv (environment, "CFLAGS", cflags);
+            }
+          if (json_object_has_member (build_options, "cxxflags"))
+            {
+              const gchar *cxxflags;
+              cxxflags = json_object_get_string_member (build_options, "cxxflags");
+              if (cxxflags != NULL)
+                ide_environment_setenv (environment, "CXXFLAGS", cxxflags);
+            }
+          if (json_object_has_member (build_options, "env"))
+            {
+              JsonObject *env_vars;
+              env_vars = json_object_get_object_member (build_options, "env");
+              if (env_vars != NULL)
+                {
+                  g_autoptr(GList) env_list = NULL;
+                  GList *l;
+                  env_list = json_object_get_members (env_vars);
+                  for (l = env_list; l != NULL; l = l->next)
+                    {
+                      const gchar *env_name = (gchar *)l->data;
+                      const gchar *env_value = json_object_get_string_member (env_vars, env_name);
+                      if (!ide_str_empty0 (env_name) && !ide_str_empty0 (env_value))
+                        ide_environment_setenv (environment, env_name, env_value);
+                    }
+                }
+            }
+          manifest->environment = environment;
+        }
+
+      platform = json_node_get_string (runtime_node);
+      if (!JSON_NODE_HOLDS_VALUE (runtime_version_node) || ide_str_empty0 (json_node_get_string 
(runtime_version_node)))
+        branch = "master";
+      else
+        branch = json_node_get_string (runtime_version_node);
+      arch = flatpak_get_default_arch ();
+      manifest->runtime_id = g_strdup_printf ("flatpak:%s/%s/%s", platform, branch, arch);
+
+      if (JSON_NODE_HOLDS_VALUE (app_id_node))
+        manifest->app_id = json_node_dup_string (app_id_node);
+      else
+        manifest->app_id = json_node_dup_string (id_node);
+
+      primary_module_node = guess_primary_module (modules_node, directory);
+      if (primary_module_node != NULL && JSON_NODE_HOLDS_OBJECT (primary_module_node))
+        {
+          JsonObject *primary_module_object = json_node_get_object (primary_module_node);
+          manifest->primary_module = g_strdup (json_object_get_string_member (primary_module_object, 
"name"));
+          if (json_object_has_member (primary_module_object, "config-opts"))
+            {
+              JsonArray *config_opts_array;
+              config_opts_array = json_object_get_array_member (primary_module_object, "config-opts");
+              if (config_opts_array != NULL)
+                {
+                  GPtrArray *config_opts_strv;
+                  config_opts_strv = g_ptr_array_new_with_free_func (g_free);
+                  for (guint i = 0; i < json_array_get_length (config_opts_array); i++)
+                    {
+                      const gchar *next_option;
+                      next_option = json_array_get_string_element (config_opts_array, i);
+                      g_ptr_array_add (config_opts_strv, g_strdup (next_option));
+                    }
+                  g_ptr_array_add (config_opts_strv, NULL);
+                  manifest->config_opts = g_strjoinv (" ", (gchar **)config_opts_strv->pdata);
+                  g_ptr_array_free (config_opts_strv, TRUE);
+                }
+            }
+        }
+
+      g_ptr_array_add (ar, manifest);
+    }
+
+  return ar;
+}
+
+static gboolean
+gbp_flatpak_configuration_provider_load_manifests (GbpFlatpakConfigurationProvider  *self,
+                                                   GPtrArray                        *configurations,
+                                                   GCancellable                     *cancellable,
+                                                   GError                          **error)
+{
+  g_autoptr(GPtrArray) ar = NULL;
+  g_autoptr(GFileInfo) file_info = NULL;
+  IdeContext *context;
+  GFile *project_file;
+  g_autoptr(GFile) project_dir = NULL;
+
+  g_assert (GBP_IS_FLATPAK_CONFIGURATION_PROVIDER (self));
+
+  context = ide_object_get_context (IDE_OBJECT (self->manager));
+  project_file = ide_context_get_project_file (context);
+
+  g_assert (G_IS_FILE (project_file));
+
+  file_info = g_file_query_info (project_file,
+                                 G_FILE_ATTRIBUTE_STANDARD_TYPE,
+                                 G_FILE_QUERY_INFO_NONE,
+                                 cancellable,
+                                 error);
+
+  if (file_info == NULL)
+    return FALSE;
+
+  if (g_file_info_get_file_type (file_info) == G_FILE_TYPE_DIRECTORY)
+    project_dir = g_object_ref (project_file);
+  else
+    project_dir = g_file_get_parent (project_file);
+
+  ar = gbp_flatpak_configuration_provider_find_flatpak_manifests (self, cancellable, project_dir, error);
+
+  if (ar == NULL)
+    return FALSE;
+
+  IDE_TRACE_MSG ("Found %u flatpak manifests", ar->len);
+
+  for (guint i = 0; i < ar->len; i++)
+    {
+      GbpFlatpakConfiguration *configuration;
+      FlatpakManifest *manifest = g_ptr_array_index (ar, i);
+      g_autofree gchar *filename = NULL;
+      g_autofree gchar *hash = NULL;
+      g_autofree gchar *id = NULL;
+      g_autofree gchar *manifest_data = NULL;
+      g_autofree gchar *path = NULL;
+      gsize manifest_data_len = 0;
+
+      path = g_file_get_path (manifest->file);
+
+      if (g_file_get_contents (path, &manifest_data, &manifest_data_len, NULL))
+        {
+          g_autoptr(GChecksum) checksum = NULL;
+
+          checksum = g_checksum_new (G_CHECKSUM_SHA1);
+          g_checksum_update (checksum, (const guint8 *)manifest_data, manifest_data_len);
+          hash = g_strdup (g_checksum_get_string (checksum));
+        }
+
+      filename = g_file_get_basename (manifest->file);
+
+      if (hash != NULL)
+        id = g_strdup_printf ("%s@%s", filename, hash);
+      else
+        id = g_strdup (filename);
+
+      if (contains_id (configurations, id))
+        continue;
+
+      /**
+       * TODO: There are a few more fields in the manifests that Builder needs, but they
+       * are read when needed by the runtime. If we set up a file monitor to reload the
+       * configuration when it changes on disk, it might make more sense for those fields
+       * to be read and processed here so we're only parsing the manifest in one place.
+       */
+      configuration = g_object_new (GBP_TYPE_FLATPAK_CONFIGURATION,
+                                    "app-id", manifest->app_id,
+                                    "context", context,
+                                    "display-name", filename,
+                                    "device-id", "local",
+                                    "id", id,
+                                    "manifest", manifest->file,
+                                    "prefix", (manifest->prefix != NULL ? manifest->prefix : "/app"),
+                                    "runtime-id", manifest->runtime_id,
+                                    NULL);
+      if (manifest->primary_module != NULL)
+        gbp_flatpak_configuration_set_primary_module (configuration, manifest->primary_module);
+      if (manifest->environment != NULL)
+        ide_configuration_set_environment (IDE_CONFIGURATION (configuration), manifest->environment);
+      if (manifest->config_opts != NULL)
+        ide_configuration_set_config_opts (IDE_CONFIGURATION (configuration), manifest->config_opts);
+
+      g_ptr_array_add (configurations, configuration);
+    }
+
+  return TRUE;
+}
+
+static void
+gbp_flatpak_configuration_provider_load_worker (GTask        *task,
+                                                gpointer      source_object,
+                                                gpointer      task_data,
+                                                GCancellable *cancellable)
+{
+  GbpFlatpakConfigurationProvider *self = source_object;
+  g_autoptr(GPtrArray) ret = NULL;
+  g_autoptr(GFile) file = NULL;
+  g_autofree gchar *path = NULL;
+  GError *error = NULL;
+
+  IDE_ENTRY;
+
+  g_assert (G_IS_TASK (task));
+  g_assert (GBP_IS_FLATPAK_CONFIGURATION_PROVIDER (self));
+  g_assert (IDE_IS_CONFIGURATION_MANAGER (self->manager));
+
+  ret = g_ptr_array_new_with_free_func (g_object_unref);
+
+  /* Load flatpak manifests in the repo */
+  if (!gbp_flatpak_configuration_provider_load_manifests (self, ret, cancellable, &error))
+    {
+      g_warning ("%s", error->message);
+      g_clear_error (&error);
+    }
+
+  g_task_return_pointer (task, g_steal_pointer (&ret), (GDestroyNotify)g_ptr_array_unref);
+
+  IDE_EXIT;
+}
+
+static void
+gbp_flatpak_configuration_provider_load_cb (GObject      *object,
+                                            GAsyncResult *result,
+                                            gpointer      user_data)
+{
+  GbpFlatpakConfigurationProvider *self = (GbpFlatpakConfigurationProvider *)object;
+  GPtrArray *ret;
+  GError *error = NULL;
+  guint i;
+
+  IDE_ENTRY;
+
+  g_assert (GBP_IS_FLATPAK_CONFIGURATION_PROVIDER (self));
+  g_assert (G_IS_TASK (result));
+
+  if (!(ret = g_task_propagate_pointer (G_TASK (result), &error)))
+    {
+      g_warning ("%s", error->message);
+      g_clear_error (&error);
+      IDE_EXIT;
+    }
+
+  for (i = 0; i < ret->len; i++)
+    {
+      IdeConfiguration *configuration = g_ptr_array_index (ret, i);
+
+      ide_configuration_manager_add (self->manager, configuration);
+    }
+
+  self->configurations = ret;
+
+  IDE_EXIT;
+}
+
+static void
+gbp_flatpak_configuration_provider_load (IdeConfigurationProvider *provider,
+                                         IdeConfigurationManager  *manager)
+{
+  GbpFlatpakConfigurationProvider *self = (GbpFlatpakConfigurationProvider *)provider;
+  g_autoptr(GTask) task = NULL;
+
+  IDE_ENTRY;
+
+  g_assert (GBP_IS_FLATPAK_CONFIGURATION_PROVIDER (self));
+  g_assert (IDE_IS_CONFIGURATION_MANAGER (manager));
+
+  ide_set_weak_pointer (&self->manager, manager);
+
+  self->cancellable = g_cancellable_new ();
+
+  task = g_task_new (self, self->cancellable, gbp_flatpak_configuration_provider_load_cb, NULL);
+  g_task_run_in_thread (task, gbp_flatpak_configuration_provider_load_worker);
+
+  IDE_EXIT;
+}
+
+static void
+gbp_flatpak_configuration_provider_unload (IdeConfigurationProvider *provider,
+                                           IdeConfigurationManager  *manager)
+{
+  GbpFlatpakConfigurationProvider *self = (GbpFlatpakConfigurationProvider *)provider;
+
+  IDE_ENTRY;
+
+  g_assert (GBP_IS_FLATPAK_CONFIGURATION_PROVIDER (self));
+  g_assert (IDE_IS_CONFIGURATION_MANAGER (manager));
+
+  if (self->configurations != NULL)
+    {
+      for (guint i= 0; i < self->configurations->len; i++)
+        {
+          IdeConfiguration *configuration = g_ptr_array_index (self->configurations, i);
+
+          ide_configuration_manager_remove (manager, configuration);
+        }
+    }
+
+  g_clear_pointer (&self->configurations, g_ptr_array_unref);
+
+  if (self->cancellable != NULL)
+    g_cancellable_cancel (self->cancellable);
+  g_clear_object (&self->cancellable);
+
+  ide_clear_weak_pointer (&self->manager);
+
+  IDE_EXIT;
+}
+
+static void
+gbp_flatpak_configuration_provider_class_init (GbpFlatpakConfigurationProviderClass *klass)
+{
+}
+
+static void
+gbp_flatpak_configuration_provider_init (GbpFlatpakConfigurationProvider *self)
+{
+}
+
+static void
+configuration_provider_iface_init (IdeConfigurationProviderInterface *iface)
+{
+  iface->load = gbp_flatpak_configuration_provider_load;
+  iface->unload = gbp_flatpak_configuration_provider_unload;
+}
diff --git a/plugins/flatpak/gbp-flatpak-configuration-provider.h 
b/plugins/flatpak/gbp-flatpak-configuration-provider.h
new file mode 100644
index 0000000..7a262b7
--- /dev/null
+++ b/plugins/flatpak/gbp-flatpak-configuration-provider.h
@@ -0,0 +1,32 @@
+/* gbp-flatpak-configuration-provider.h
+ *
+ * Copyright (C) 2016 Matthew Leeds <mleeds redhat com>
+ *
+ * This program is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program.  If not, see <http://www.gnu.org/licenses/>.
+ */
+
+#ifndef GBP_FLATPAK_CONFIGURATION_PROVIDER_H
+#define GBP_FLATPAK_CONFIGURATION_PROVIDER_H
+
+#include <ide.h>
+
+G_BEGIN_DECLS
+
+#define GBP_TYPE_FLATPAK_CONFIGURATION_PROVIDER (gbp_flatpak_configuration_provider_get_type())
+
+G_DECLARE_FINAL_TYPE (GbpFlatpakConfigurationProvider, gbp_flatpak_configuration_provider, GBP, 
FLATPAK_CONFIGURATION_PROVIDER, GObject)
+
+G_END_DECLS
+
+#endif /* GBP_FLATPAK_CONFIGURATION_PROVIDER_H */
diff --git a/plugins/flatpak/gbp-flatpak-plugin.c b/plugins/flatpak/gbp-flatpak-plugin.c
index fb9bb72..f3550d3 100644
--- a/plugins/flatpak/gbp-flatpak-plugin.c
+++ b/plugins/flatpak/gbp-flatpak-plugin.c
@@ -19,6 +19,7 @@
 #include <libpeas/peas.h>
 #include <ide.h>
 
+#include "gbp-flatpak-configuration-provider.h"
 #include "gbp-flatpak-runtime-provider.h"
 #include "gbp-flatpak-application-addin.h"
 #include "gbp-flatpak-genesis-addin.h"
@@ -27,6 +28,9 @@ void
 peas_register_types (PeasObjectModule *module)
 {
   peas_object_module_register_extension_type (module,
+                                              IDE_TYPE_CONFIGURATION_PROVIDER,
+                                              GBP_TYPE_FLATPAK_CONFIGURATION_PROVIDER);
+  peas_object_module_register_extension_type (module,
                                               IDE_TYPE_RUNTIME_PROVIDER,
                                               GBP_TYPE_FLATPAK_RUNTIME_PROVIDER);
   peas_object_module_register_extension_type (module,
diff --git a/plugins/flatpak/gbp-flatpak-runtime-provider.c b/plugins/flatpak/gbp-flatpak-runtime-provider.c
index 8b7a9a1..37a517a 100644
--- a/plugins/flatpak/gbp-flatpak-runtime-provider.c
+++ b/plugins/flatpak/gbp-flatpak-runtime-provider.c
@@ -20,7 +20,6 @@
 
 #include <string.h>
 #include <flatpak.h>
-#include <json-glib/json-glib.h>
 
 #include "util/ide-posix.h"
 
@@ -39,16 +38,6 @@ struct _GbpFlatpakRuntimeProvider
   GFileMonitor        *user_flatpak_monitor;
 };
 
-typedef struct
-{
-  gchar *platform;
-  gchar *branch;
-  gchar *sdk;
-  gchar *app_id;
-  gchar *primary_module;
-  GFile *file;
-} FlatpakManifest;
-
 static void runtime_provider_iface_init (IdeRuntimeProviderInterface *);
 
 G_DEFINE_TYPE_EXTENDED (GbpFlatpakRuntimeProvider, gbp_flatpak_runtime_provider, G_TYPE_OBJECT, 0,
@@ -87,20 +76,6 @@ contains_id (GPtrArray   *ar,
   return FALSE;
 }
 
-static void
-flatpak_manifest_free (void *data)
-{
-  FlatpakManifest *manifest = data;
-
-  g_free (manifest->branch);
-  g_free (manifest->sdk);
-  g_free (manifest->platform);
-  g_free (manifest->app_id);
-  g_free (manifest->primary_module);
-  g_clear_object (&manifest->file);
-  g_slice_free (FlatpakManifest, manifest);
-}
-
 static gboolean
 gbp_flatpak_runtime_provider_load_refs (GbpFlatpakRuntimeProvider  *self,
                                         FlatpakInstallation        *installation,
@@ -213,305 +188,6 @@ gbp_flatpak_runtime_provider_load_refs (GbpFlatpakRuntimeProvider  *self,
   return TRUE;
 }
 
-static gchar *
-guess_primary_module (JsonNode *modules_node,
-                      GFile    *directory)
-{
-  JsonArray *modules;
-  JsonNode *module;
-  g_autofree gchar *dir_name = NULL;
-
-  g_assert (G_IS_FILE (directory));
-
-  dir_name = g_file_get_basename (directory);
-  g_assert (!ide_str_empty0 (dir_name));
-  g_return_val_if_fail (JSON_NODE_HOLDS_ARRAY (modules_node), NULL);
-
-  /* TODO: Support module strings that refer to other files? */
-  modules = json_node_get_array (modules_node);
-  if (json_array_get_length (modules) == 1)
-    {
-      module = json_array_get_element (modules, 0);
-      if (JSON_NODE_HOLDS_OBJECT (module))
-        return g_strdup (json_object_get_string_member (json_node_get_object (module), "name"));
-    }
-  else
-    {
-      for (guint i = 0; i < json_array_get_length (modules); i++)
-        {
-          module = json_array_get_element (modules, i);
-          if (JSON_NODE_HOLDS_OBJECT (module))
-            {
-              const gchar *module_name;
-              module_name = json_object_get_string_member (json_node_get_object (module), "name");
-              if (g_strcmp0 (module_name, dir_name) == 0)
-                return g_strdup (module_name);
-              if (json_object_has_member (json_node_get_object (module), "modules"))
-                {
-                  JsonNode *nested_modules_node;
-                  g_autofree gchar *nested_primary_module = NULL;
-                  nested_modules_node = json_object_get_member (json_node_get_object (module), "modules");
-                  nested_primary_module = guess_primary_module (nested_modules_node, directory);
-                  if (nested_primary_module != NULL)
-                    return g_steal_pointer (&nested_primary_module);
-                }
-            }
-        }
-    }
-
-  return NULL;
-}
-
-static GPtrArray *
-gbp_flatpak_runtime_provider_find_flatpak_manifests (GbpFlatpakRuntimeProvider *self,
-                                                     GCancellable              *cancellable,
-                                                     GFile                     *directory,
-                                                     GError                   **error)
-{
-  g_autoptr(GFileEnumerator) enumerator = NULL;
-  GFileInfo *file_info = NULL;
-  GPtrArray *ar;
-
-  g_assert (GBP_IS_FLATPAK_RUNTIME_PROVIDER (self));
-  g_assert (!cancellable || G_IS_CANCELLABLE (cancellable));
-  g_assert (G_IS_FILE (directory));
-
-  ar = g_ptr_array_new ();
-  g_ptr_array_set_free_func (ar, flatpak_manifest_free);
-
-  enumerator = g_file_enumerate_children (directory,
-                                          G_FILE_ATTRIBUTE_STANDARD_NAME,
-                                          G_FILE_QUERY_INFO_NONE,
-                                          cancellable,
-                                          error);
-  if (!enumerator)
-    return NULL;
-
-  while ((file_info = g_file_enumerator_next_file (enumerator, cancellable, NULL)))
-    {
-      GFileType file_type;
-      g_autofree gchar *name = NULL;
-      g_autofree gchar *path = NULL;
-      g_autoptr(GRegex) filename_regex = NULL;
-      g_autoptr(GMatchInfo) match_info = NULL;
-      g_autoptr(JsonParser) parser = NULL;
-      JsonNode *root_node = NULL;
-      JsonNode *app_id_node = NULL;
-      JsonNode *id_node = NULL;
-      JsonNode *runtime_node = NULL;
-      JsonNode *runtime_version_node = NULL;
-      JsonNode *sdk_node = NULL;
-      JsonNode *modules_node = NULL;
-      JsonObject *root_object = NULL;
-      g_autoptr(GError) local_error = NULL;
-      g_autoptr(GFile) file = NULL;
-      FlatpakManifest *manifest;
-
-      file_type = g_file_info_get_file_type (file_info);
-      name = g_strdup (g_file_info_get_name (file_info));
-      g_clear_object (&file_info);
-
-      if (name == NULL || file_type == G_FILE_TYPE_DIRECTORY)
-        continue;
-
-      file = g_file_get_child (directory, name);
-
-      /* This regex is based on https://wiki.gnome.org/HowDoI/ChooseApplicationID */
-      filename_regex = g_regex_new ("^[[:alnum:]-_]+\\.[[:alnum:]-_]+(\\.[[:alnum:]-_]+)*\\.json$",
-                                    0, 0, NULL);
-
-      g_regex_match (filename_regex, name, 0, &match_info);
-      if (!g_match_info_matches (match_info))
-        continue;
-
-      /* Check if the contents look like a flatpak manifest */
-      path = g_file_get_path (file);
-      parser = json_parser_new ();
-      json_parser_load_from_file (parser, path, &local_error);
-      if (local_error != NULL)
-        continue;
-
-      root_node = json_parser_get_root (parser);
-      if (!JSON_NODE_HOLDS_OBJECT (root_node))
-        continue;
-
-      root_object = json_node_get_object (root_node);
-      app_id_node = json_object_get_member (root_object, "app-id");
-      id_node = json_object_get_member (root_object, "id");
-      runtime_node = json_object_get_member (root_object, "runtime");
-      runtime_version_node = json_object_get_member (root_object, "runtime-version");
-      sdk_node = json_object_get_member (root_object, "sdk");
-      modules_node = json_object_get_member (root_object, "modules");
-
-      if ((!JSON_NODE_HOLDS_VALUE (app_id_node) && !JSON_NODE_HOLDS_VALUE (id_node)) ||
-           !JSON_NODE_HOLDS_VALUE (runtime_node) ||
-           !JSON_NODE_HOLDS_VALUE (sdk_node) ||
-           !JSON_NODE_HOLDS_ARRAY (modules_node))
-        continue;
-
-      IDE_TRACE_MSG ("Discovered flatpak manifest at %s", path);
-
-      manifest = g_slice_new0 (FlatpakManifest);
-      manifest->file = g_steal_pointer (&file);
-      manifest->platform = json_node_dup_string (runtime_node);
-      if (!JSON_NODE_HOLDS_VALUE (runtime_version_node) || ide_str_empty0 (json_node_get_string 
(runtime_version_node)))
-        manifest->branch = g_strdup ("master");
-      else
-        manifest->branch = json_node_dup_string (runtime_version_node);
-      manifest->sdk = json_node_dup_string (sdk_node);
-      if (JSON_NODE_HOLDS_VALUE (app_id_node))
-        manifest->app_id = json_node_dup_string (app_id_node);
-      else
-        manifest->app_id = json_node_dup_string (id_node);
-      manifest->primary_module = guess_primary_module (modules_node, directory);
-      if (manifest->primary_module == NULL)
-        g_warning ("Unable to determine the primary module in the flatpak manifest");
-
-      g_ptr_array_add (ar, manifest);
-    }
-
-  return ar;
-}
-
-static gchar *
-find_deploy_dir (GbpFlatpakRuntimeProvider *self,
-                 const gchar               *name,
-                 const gchar               *arch,
-                 const gchar               *branch,
-                 GCancellable              *cancellable)
-{
-  FlatpakInstallation *installations[2];
-
-  g_assert (GBP_IS_FLATPAK_RUNTIME_PROVIDER (self));
-  g_assert (!cancellable || G_IS_CANCELLABLE (cancellable));
-
-  installations[0] = self->user_installation;
-  installations[1] = self->system_installation;
-
-  for (guint i = 0; i < G_N_ELEMENTS (installations); i++)
-    {
-      FlatpakInstallation *installation = installations[i];
-      g_autoptr(FlatpakInstalledRef) ref = NULL;
-
-      if (installation == NULL)
-        continue;
-
-      ref = flatpak_installation_get_installed_ref (installation,
-                                                    FLATPAK_REF_KIND_RUNTIME,
-                                                    name,
-                                                    arch,
-                                                    branch,
-                                                    cancellable,
-                                                    NULL);
-
-      if (ref != NULL)
-        {
-          const gchar *deploy_dir;
-
-          deploy_dir = flatpak_installed_ref_get_deploy_dir (ref);
-
-          if (deploy_dir != NULL)
-            return g_strdup (deploy_dir);
-        }
-    }
-
-  return NULL;
-}
-
-static gboolean
-gbp_flatpak_runtime_provider_load_manifests (GbpFlatpakRuntimeProvider  *self,
-                                             GPtrArray                  *runtimes,
-                                             GCancellable               *cancellable,
-                                             GError                    **error)
-{
-  g_autoptr(GPtrArray) ar = NULL;
-  g_autoptr(GFileInfo) file_info = NULL;
-  IdeContext *context;
-  GFile *project_file;
-  g_autoptr(GFile) project_dir = NULL;
-
-  g_assert (GBP_IS_FLATPAK_RUNTIME_PROVIDER (self));
-
-  context = ide_object_get_context (IDE_OBJECT (self->manager));
-  project_file = ide_context_get_project_file (context);
-
-  g_assert (G_IS_FILE (project_file));
-
-  file_info = g_file_query_info (project_file,
-                                 G_FILE_ATTRIBUTE_STANDARD_TYPE,
-                                 G_FILE_QUERY_INFO_NONE,
-                                 cancellable,
-                                 error);
-
-  if (file_info == NULL)
-    return FALSE;
-
-  if (g_file_info_get_file_type (file_info) == G_FILE_TYPE_DIRECTORY)
-    project_dir = g_object_ref (project_file);
-  else
-    project_dir = g_file_get_parent (project_file);
-
-  ar = gbp_flatpak_runtime_provider_find_flatpak_manifests (self, cancellable, project_dir, error);
-
-  if (ar == NULL)
-    return FALSE;
-
-  IDE_TRACE_MSG ("Found %u flatpak manifests", ar->len);
-
-  for (guint i = 0; i < ar->len; i++)
-    {
-      FlatpakManifest *manifest = g_ptr_array_index (ar, i);
-      g_autofree gchar *filename = NULL;
-      g_autofree gchar *hash = NULL;
-      g_autofree gchar *id = NULL;
-      g_autofree gchar *manifest_data = NULL;
-      g_autofree gchar *path = NULL;
-      g_autofree gchar *deploy_dir = NULL;
-      gsize manifest_data_len = 0;
-
-      path = g_file_get_path (manifest->file);
-
-      if (g_file_get_contents (path, &manifest_data, &manifest_data_len, NULL))
-        {
-          g_autoptr(GChecksum) checksum = NULL;
-
-          checksum = g_checksum_new (G_CHECKSUM_SHA1);
-          g_checksum_update (checksum, (const guint8 *)manifest_data, manifest_data_len);
-          hash = g_strdup (g_checksum_get_string (checksum));
-        }
-
-      filename = g_file_get_basename (manifest->file);
-
-      if (hash != NULL)
-        id = g_strdup_printf ("%s@%s", filename, hash);
-      else
-        id = g_strdup (filename);
-
-      if (contains_id (runtimes, id))
-        continue;
-
-      deploy_dir = find_deploy_dir (self, manifest->sdk, NULL, manifest->branch, cancellable);
-      if (deploy_dir == NULL)
-        deploy_dir = find_deploy_dir (self, manifest->platform, NULL, manifest->branch, cancellable);
-
-      g_ptr_array_add (runtimes,
-                       g_object_new (GBP_TYPE_FLATPAK_RUNTIME,
-                                     "app-id", manifest->app_id,
-                                     "branch", manifest->branch,
-                                     "context", context,
-                                     "deploy-dir", deploy_dir,
-                                     "display-name", filename,
-                                     "id", id,
-                                     "manifest", manifest->file,
-                                     "platform", manifest->platform,
-                                     "primary-module", manifest->primary_module,
-                                     "sdk", manifest->sdk,
-                                     NULL));
-    }
-
-  return TRUE;
-}
-
 static void
 on_flatpak_installation_changed (GbpFlatpakRuntimeProvider *self,
                                  GFile                     *file,
@@ -575,13 +251,6 @@ gbp_flatpak_runtime_provider_load_worker (GTask        *task,
       g_clear_error (&error);
     }
 
-  /* Load flatpak manifests in the repo */
-  if (!gbp_flatpak_runtime_provider_load_manifests (self, ret, cancellable, &error))
-    {
-      g_warning ("%s", error->message);
-      g_clear_error (&error);
-    }
-
   /* Set up file monitors so the list of runtimes refreshes when necessary */
   if (self->system_installation != NULL)
     {
diff --git a/plugins/flatpak/gbp-flatpak-runtime.c b/plugins/flatpak/gbp-flatpak-runtime.c
index 286b915..0b93710 100644
--- a/plugins/flatpak/gbp-flatpak-runtime.c
+++ b/plugins/flatpak/gbp-flatpak-runtime.c
@@ -24,31 +24,26 @@
 #include "gbp-flatpak-runtime.h"
 #include "gbp-flatpak-subprocess-launcher.h"
 #include "gbp-flatpak-runner.h"
+#include "gbp-flatpak-configuration.h"
 
 struct _GbpFlatpakRuntime
 {
   IdeRuntime parent_instance;
 
-  gchar *app_id;
   gchar *branch;
   gchar *deploy_dir;
   gchar *platform;
-  gchar *primary_module;
   gchar *sdk;
   GFile *deploy_dir_files;
-  GFile *manifest;
 };
 
 G_DEFINE_TYPE (GbpFlatpakRuntime, gbp_flatpak_runtime, IDE_TYPE_RUNTIME)
 
 enum {
   PROP_0,
-  PROP_APP_ID,
   PROP_BRANCH,
   PROP_DEPLOY_DIR,
-  PROP_MANIFEST,
   PROP_PLATFORM,
-  PROP_PRIMARY_MODULE,
   PROP_SDK,
   N_PROPS
 };
@@ -157,6 +152,7 @@ gbp_flatpak_runtime_prebuild_worker (GTask        *task,
   g_autoptr(GFile) build_dir = NULL;
   g_autoptr(GFile) flatpak_repo_dir = NULL;
   g_autoptr(GFile) metadata_file = NULL;
+  g_autoptr(GFile) manifest_file = NULL;
   g_autoptr(IdeSubprocessLauncher) launcher = NULL;
   g_autoptr(IdeSubprocess) process = NULL;
   g_autoptr(GError) error = NULL;
@@ -239,217 +235,228 @@ gbp_flatpak_runtime_prebuild_worker (GTask        *task,
   if (g_file_query_exists (metadata_file, cancellable))
     already_ran_build_init = TRUE;
 
-  /*
-   * Install the runtime and sdk if they're just the standard gnome ones,
-   * and run flatpak-builder if necessary.
-   */
-  if (self->manifest != NULL)
+  if (GBP_IS_FLATPAK_CONFIGURATION (configuration))
     {
-      g_autofree gchar *manifest_path = NULL;
-      g_autoptr(JsonParser) parser = NULL;
-      JsonNode *root_node = NULL;
-      JsonObject *root_object = NULL;
-      gboolean has_multiple_modules;
-
-      manifest_path = g_file_get_path (self->manifest);
-      g_assert (!ide_str_empty0 (manifest_path));
+      GFile *manifest = NULL;
+      const gchar *primary_module = NULL;
 
-      parser = json_parser_new ();
-      if (!json_parser_load_from_file (parser, manifest_path, &error))
+      primary_module = gbp_flatpak_configuration_get_primary_module ((GbpFlatpakConfiguration 
*)configuration);
+      manifest = gbp_flatpak_configuration_get_manifest ((GbpFlatpakConfiguration *)configuration);
+      if (manifest != NULL)
         {
-          g_task_return_error (task, g_steal_pointer (&error));
-          return;
-        }
-      root_node = json_parser_get_root (parser);
-      g_assert (JSON_NODE_HOLDS_OBJECT (root_node));
-      root_object = json_node_get_object (root_node);
-      has_multiple_modules = manifest_has_multiple_modules (root_object);
+          gchar *manifest_path;
+          g_autoptr(JsonParser) parser = NULL;
+          JsonNode *root_node = NULL;
+          JsonObject *root_object = NULL;
+          gboolean has_multiple_modules;
 
-      if (g_strcmp0 (self->platform, "org.gnome.Platform") == 0 ||
-          g_strcmp0 (self->sdk, "org.gnome.Sdk") == 0)
-        {
-          gchar *gnome_repo_name = NULL;
-          gchar *gnome_repo_path = NULL;
-          const gchar *arch = NULL;
-          g_autofree gchar *runtime_id = NULL;
-          g_autofree gchar *sdk_id = NULL;
-          IdeRuntime *runtime;
-          IdeRuntime *sdk;
-
-          arch = flatpak_get_default_arch ();
-
-          runtime_id = g_strdup_printf ("flatpak:%s/%s/%s", self->platform, self->branch, arch);
-          sdk_id = g_strdup_printf ("flatpak:%s/%s/%s", self->sdk, self->branch, arch);
-          runtime = ide_runtime_manager_get_runtime (runtime_manager, runtime_id);
-          sdk = ide_runtime_manager_get_runtime (runtime_manager, sdk_id);
-
-          /* Add the gnome or gnome-nightly remote */
-          if (runtime == NULL || sdk == NULL)
+          manifest_path = g_file_get_path (manifest);
+          g_assert (!ide_str_empty0 (manifest_path));
+
+          parser = json_parser_new ();
+          if (!json_parser_load_from_file (parser, manifest_path, &error))
             {
-              g_autoptr(IdeSubprocessLauncher) launcher2 = NULL;
-              g_autoptr(IdeSubprocess) process2 = NULL;
+              g_task_return_error (task, g_steal_pointer (&error));
+              return;
+            }
+          root_node = json_parser_get_root (parser);
+          g_assert (JSON_NODE_HOLDS_OBJECT (root_node));
+          root_object = json_node_get_object (root_node);
+          has_multiple_modules = manifest_has_multiple_modules (root_object);
 
-              if (g_strcmp0 (self->branch, "master") == 0)
-                {
-                  gnome_repo_name = "gnome-nightly";
-                  gnome_repo_path = "https://sdk.gnome.org/gnome-nightly.flatpakrepo";;
-                }
-              else
+          /*
+           * Install the runtime and sdk if they're just the standard gnome ones,
+           * and run flatpak-builder if necessary.
+           */
+          if (g_strcmp0 (self->platform, "org.gnome.Platform") == 0 ||
+              g_strcmp0 (self->sdk, "org.gnome.Sdk") == 0)
+            {
+              gchar *gnome_repo_name = NULL;
+              gchar *gnome_repo_path = NULL;
+              const gchar *arch = NULL;
+              g_autofree gchar *runtime_id = NULL;
+              g_autofree gchar *sdk_id = NULL;
+              IdeRuntime *runtime;
+              IdeRuntime *sdk;
+
+              arch = flatpak_get_default_arch ();
+
+              runtime_id = g_strdup_printf ("flatpak:%s/%s/%s", self->platform, self->branch, arch);
+              sdk_id = g_strdup_printf ("flatpak:%s/%s/%s", self->sdk, self->branch, arch);
+              runtime = ide_runtime_manager_get_runtime (runtime_manager, runtime_id);
+              sdk = ide_runtime_manager_get_runtime (runtime_manager, sdk_id);
+
+              /* Add the gnome or gnome-nightly remote */
+              if (runtime == NULL || sdk == NULL)
                 {
-                  gnome_repo_name = "gnome";
-                  gnome_repo_path = "https://sdk.gnome.org/gnome.flatpakrepo";;
+                  g_autoptr(IdeSubprocessLauncher) launcher2 = NULL;
+                  g_autoptr(IdeSubprocess) process2 = NULL;
+
+                  if (g_strcmp0 (self->branch, "master") == 0)
+                    {
+                      gnome_repo_name = "gnome-nightly";
+                      gnome_repo_path = "https://sdk.gnome.org/gnome-nightly.flatpakrepo";;
+                    }
+                  else
+                    {
+                      gnome_repo_name = "gnome";
+                      gnome_repo_path = "https://sdk.gnome.org/gnome.flatpakrepo";;
+                    }
+
+                  launcher2 = IDE_RUNTIME_CLASS (gbp_flatpak_runtime_parent_class)->create_launcher 
(IDE_RUNTIME (self), &error);
+                  if (launcher2 == NULL)
+                    {
+                      g_task_return_error (task, g_steal_pointer (&error));
+                      return;
+                    }
+                  ide_subprocess_launcher_push_argv (launcher2, "flatpak");
+                  ide_subprocess_launcher_push_argv (launcher2, "remote-add");
+                  ide_subprocess_launcher_push_argv (launcher2, "--user");
+                  ide_subprocess_launcher_push_argv (launcher2, "--if-not-exists");
+                  ide_subprocess_launcher_push_argv (launcher2, "--from");
+                  ide_subprocess_launcher_push_argv (launcher2, gnome_repo_name);
+                  ide_subprocess_launcher_push_argv (launcher2, gnome_repo_path);
+                  ide_build_result_log_stderr (build_result,
+                                               "Adding missing flatpak repository %s from %s\n",
+                                               gnome_repo_name, gnome_repo_path);
+                  process2 = ide_subprocess_launcher_spawn (launcher2, cancellable, &error);
+
+                  if (process2 != NULL)
+                    ide_build_result_log_subprocess (build_result, process2);
+
+                  if (process2 == NULL || !ide_subprocess_wait_check (process2, cancellable, &error))
+                    {
+                      g_task_return_error (task, g_steal_pointer (&error));
+                      return;
+                    }
                 }
 
-              launcher2 = IDE_RUNTIME_CLASS (gbp_flatpak_runtime_parent_class)->create_launcher (IDE_RUNTIME 
(self), &error);
-              if (launcher2 == NULL)
+              /* Install the runtime */
+              if (runtime == NULL && g_strcmp0 (self->platform, "org.gnome.Platform") == 0)
                 {
-                  g_task_return_error (task, g_steal_pointer (&error));
-                  return;
+                  g_autoptr(IdeSubprocessLauncher) launcher3 = NULL;
+                  g_autoptr(IdeSubprocess) process3 = NULL;
+
+                  launcher3 = IDE_RUNTIME_CLASS (gbp_flatpak_runtime_parent_class)->create_launcher 
(IDE_RUNTIME (self), &error);
+                  if (launcher3 == NULL)
+                    {
+                      g_task_return_error (task, g_steal_pointer (&error));
+                      return;
+                    }
+                  ide_subprocess_launcher_push_argv (launcher3, "flatpak");
+                  ide_subprocess_launcher_push_argv (launcher3, "install");
+                  ide_subprocess_launcher_push_argv (launcher3, "--user");
+                  ide_subprocess_launcher_push_argv (launcher3, "--runtime");
+                  ide_subprocess_launcher_push_argv (launcher3, gnome_repo_name);
+                  ide_subprocess_launcher_push_argv (launcher3, self->platform);
+                  ide_subprocess_launcher_push_argv (launcher3, self->branch);
+                  ide_build_result_log_stderr (build_result,
+                                               "Installing missing flatpak runtime %s (%s)\n",
+                                               self->platform, self->branch);
+                  process3 = ide_subprocess_launcher_spawn (launcher3, cancellable, &error);
+
+                  if (process3 != NULL)
+                    ide_build_result_log_subprocess (build_result, process3);
+
+                  if (process3 == NULL || !ide_subprocess_wait_check (process3, cancellable, &error))
+                    {
+                      g_task_return_error (task, g_steal_pointer (&error));
+                      return;
+                    }
                 }
-              ide_subprocess_launcher_push_argv (launcher2, "flatpak");
-              ide_subprocess_launcher_push_argv (launcher2, "remote-add");
-              ide_subprocess_launcher_push_argv (launcher2, "--user");
-              ide_subprocess_launcher_push_argv (launcher2, "--if-not-exists");
-              ide_subprocess_launcher_push_argv (launcher2, "--from");
-              ide_subprocess_launcher_push_argv (launcher2, gnome_repo_name);
-              ide_subprocess_launcher_push_argv (launcher2, gnome_repo_path);
-              ide_build_result_log_stderr (build_result,
-                                           "Adding missing flatpak repository %s from %s\n",
-                                           gnome_repo_name, gnome_repo_path);
-              process2 = ide_subprocess_launcher_spawn (launcher2, cancellable, &error);
-
-              if (process2 != NULL)
-                ide_build_result_log_subprocess (build_result, process2);
-
-              if (process2 == NULL || !ide_subprocess_wait_check (process2, cancellable, &error))
+
+              /* Install the sdk */
+              if (sdk == NULL && g_strcmp0 (self->sdk, "org.gnome.Sdk") == 0)
                 {
-                  g_task_return_error (task, g_steal_pointer (&error));
-                  return;
+                  g_autoptr(IdeSubprocessLauncher) launcher4 = NULL;
+                  g_autoptr(IdeSubprocess) process4 = NULL;
+
+                  launcher4 = IDE_RUNTIME_CLASS (gbp_flatpak_runtime_parent_class)->create_launcher 
(IDE_RUNTIME (self), &error);
+                  if (launcher4 == NULL)
+                    {
+                      g_task_return_error (task, g_steal_pointer (&error));
+                      return;
+                    }
+                  ide_subprocess_launcher_push_argv (launcher4, "flatpak");
+                  ide_subprocess_launcher_push_argv (launcher4, "install");
+                  ide_subprocess_launcher_push_argv (launcher4, "--user");
+                  ide_subprocess_launcher_push_argv (launcher4, "--runtime");
+                  ide_subprocess_launcher_push_argv (launcher4, gnome_repo_name);
+                  ide_subprocess_launcher_push_argv (launcher4, self->sdk);
+                  ide_subprocess_launcher_push_argv (launcher4, self->branch);
+                  ide_build_result_log_stderr (build_result,
+                                               "Installing missing flatpak SDK %s (%s)\n",
+                                               self->sdk, self->branch);
+                  process4 = ide_subprocess_launcher_spawn (launcher4, cancellable, &error);
+
+                  if (process4 != NULL)
+                    ide_build_result_log_subprocess (build_result, process4);
+
+                  if (process4 == NULL || !ide_subprocess_wait_check (process4, cancellable, &error))
+                    {
+                      g_task_return_error (task, g_steal_pointer (&error));
+                      return;
+                    }
                 }
             }
 
-          /* Install the runtime */
-          if (runtime == NULL && g_strcmp0 (self->platform, "org.gnome.Platform") == 0)
+          /* No need to run flatpak-builder if there are no dependencies */
+          if (has_multiple_modules)
             {
-              g_autoptr(IdeSubprocessLauncher) launcher3 = NULL;
-              g_autoptr(IdeSubprocess) process3 = NULL;
-
-              launcher3 = IDE_RUNTIME_CLASS (gbp_flatpak_runtime_parent_class)->create_launcher (IDE_RUNTIME 
(self), &error);
-              if (launcher3 == NULL)
+              g_autoptr(IdeSubprocessLauncher) launcher5 = NULL;
+              g_autoptr(IdeSubprocess) process5 = NULL;
+              g_autoptr(GFile) success_file = NULL;
+              g_autofree gchar *stop_at_option = NULL;
+              g_autofree gchar *success_filename = NULL;
+
+              success_filename = g_build_filename (build_path, "flatpak-builder-success", NULL);
+              success_file = g_file_new_for_path (success_filename);
+              if (g_file_query_exists (success_file, cancellable))
                 {
-                  g_task_return_error (task, g_steal_pointer (&error));
+                  g_task_return_boolean (task, TRUE);
                   return;
                 }
-              ide_subprocess_launcher_push_argv (launcher3, "flatpak");
-              ide_subprocess_launcher_push_argv (launcher3, "install");
-              ide_subprocess_launcher_push_argv (launcher3, "--user");
-              ide_subprocess_launcher_push_argv (launcher3, "--runtime");
-              ide_subprocess_launcher_push_argv (launcher3, gnome_repo_name);
-              ide_subprocess_launcher_push_argv (launcher3, self->platform);
-              ide_subprocess_launcher_push_argv (launcher3, self->branch);
-              ide_build_result_log_stderr (build_result,
-                                           "Installing missing flatpak runtime %s (%s)\n",
-                                           self->platform, self->branch);
-              process3 = ide_subprocess_launcher_spawn (launcher3, cancellable, &error);
-
-              if (process3 != NULL)
-                ide_build_result_log_subprocess (build_result, process3);
-
-              if (process3 == NULL || !ide_subprocess_wait_check (process3, cancellable, &error))
+
+              /* Run flatpak-builder to build just the dependencies */
+              launcher5 = IDE_RUNTIME_CLASS (gbp_flatpak_runtime_parent_class)->create_launcher (IDE_RUNTIME 
(self), &error);
+              if (launcher5 == NULL)
                 {
                   g_task_return_error (task, g_steal_pointer (&error));
                   return;
                 }
-            }
-
-          /* Install the sdk */
-          if (sdk == NULL && g_strcmp0 (self->sdk, "org.gnome.Sdk") == 0)
-            {
-              g_autoptr(IdeSubprocessLauncher) launcher4 = NULL;
-              g_autoptr(IdeSubprocess) process4 = NULL;
+              ide_subprocess_launcher_push_argv (launcher5, "flatpak-builder");
+              ide_subprocess_launcher_push_argv (launcher5, "--ccache");
+              ide_subprocess_launcher_push_argv (launcher5, "--force-clean");
+              if (primary_module != NULL)
+                {
+                  stop_at_option = g_strdup_printf ("--stop-at=%s", primary_module);
+                  ide_subprocess_launcher_push_argv (launcher5, stop_at_option);
+                }
+              ide_subprocess_launcher_push_argv (launcher5, build_path);
+              ide_subprocess_launcher_push_argv (launcher5, manifest_path);
+              process5 = ide_subprocess_launcher_spawn (launcher5, cancellable, &error);
 
-              launcher4 = IDE_RUNTIME_CLASS (gbp_flatpak_runtime_parent_class)->create_launcher (IDE_RUNTIME 
(self), &error);
-              if (launcher4 == NULL)
+              if (process5 == NULL)
                 {
                   g_task_return_error (task, g_steal_pointer (&error));
                   return;
                 }
-              ide_subprocess_launcher_push_argv (launcher4, "flatpak");
-              ide_subprocess_launcher_push_argv (launcher4, "install");
-              ide_subprocess_launcher_push_argv (launcher4, "--user");
-              ide_subprocess_launcher_push_argv (launcher4, "--runtime");
-              ide_subprocess_launcher_push_argv (launcher4, gnome_repo_name);
-              ide_subprocess_launcher_push_argv (launcher4, self->sdk);
-              ide_subprocess_launcher_push_argv (launcher4, self->branch);
-              ide_build_result_log_stderr (build_result,
-                                           "Installing missing flatpak SDK %s (%s)\n",
-                                           self->sdk, self->branch);
-              process4 = ide_subprocess_launcher_spawn (launcher4, cancellable, &error);
-
-              if (process4 != NULL)
-                ide_build_result_log_subprocess (build_result, process4);
-
-              if (process4 == NULL || !ide_subprocess_wait_check (process4, cancellable, &error))
+              ide_build_result_log_subprocess (build_result, process5);
+              if (!ide_subprocess_wait_check (process5, cancellable, &error))
                 {
                   g_task_return_error (task, g_steal_pointer (&error));
                   return;
                 }
-            }
-        }
 
-      /* No need to run flatpak-builder if there are no dependencies */
-      if (has_multiple_modules)
-        {
-          g_autoptr(IdeSubprocessLauncher) launcher5 = NULL;
-          g_autoptr(IdeSubprocess) process5 = NULL;
-          g_autoptr(GFile) success_file = NULL;
-          g_autofree gchar *stop_at_option = NULL;
-          g_autofree gchar *success_filename = NULL;
-
-          success_filename = g_build_filename (build_path, "flatpak-builder-success", NULL);
-          success_file = g_file_new_for_path (success_filename);
-          if (g_file_query_exists (success_file, cancellable))
-            {
-              g_task_return_boolean (task, TRUE);
-              return;
-            }
+              /*
+               * Make a file indicating that flatpak-builder finished successfully,
+               * so we know whether to run it for the next build.
+               */
+              g_object_unref (g_file_create (success_file, 0, cancellable, NULL));
 
-          /* Run flatpak-builder to build just the dependencies */
-          launcher5 = IDE_RUNTIME_CLASS (gbp_flatpak_runtime_parent_class)->create_launcher (IDE_RUNTIME 
(self), &error);
-          if (launcher5 == NULL)
-            {
-              g_task_return_error (task, g_steal_pointer (&error));
-              return;
-            }
-          ide_subprocess_launcher_push_argv (launcher5, "flatpak-builder");
-          ide_subprocess_launcher_push_argv (launcher5, "--ccache");
-          ide_subprocess_launcher_push_argv (launcher5, "--force-clean");
-          stop_at_option = g_strdup_printf ("--stop-at=%s", self->primary_module);
-          ide_subprocess_launcher_push_argv (launcher5, stop_at_option);
-          ide_subprocess_launcher_push_argv (launcher5, build_path);
-          ide_subprocess_launcher_push_argv (launcher5, manifest_path);
-          process5 = ide_subprocess_launcher_spawn (launcher5, cancellable, &error);
-
-          if (process5 == NULL)
-            {
-              g_task_return_error (task, g_steal_pointer (&error));
-              return;
-            }
-          ide_build_result_log_subprocess (build_result, process5);
-          if (!ide_subprocess_wait_check (process5, cancellable, &error))
-            {
-              g_task_return_error (task, g_steal_pointer (&error));
+              g_task_return_boolean (task, TRUE);
               return;
             }
-
-          /*
-           * Make a file indicating that flatpak-builder finished successfully,
-           * so we know whether to run it for the next build.
-           */
-          g_object_unref (g_file_create (success_file, 0, cancellable, NULL));
-
-          g_task_return_boolean (task, TRUE);
-          return;
         }
     }
 
@@ -460,7 +467,7 @@ gbp_flatpak_runtime_prebuild_worker (GTask        *task,
       g_autoptr(IdeSubprocessLauncher) launcher6 = NULL;
       g_autoptr(IdeSubprocess) process6 = NULL;
 
-      app_id = self->app_id;
+      app_id = ide_configuration_get_app_id (configuration);
       if (ide_str_empty0 (app_id))
         {
           g_warning ("Could not determine application ID");
@@ -580,12 +587,15 @@ gbp_flatpak_runtime_postinstall_worker (GTask        *task,
     {
       g_autoptr(IdeSubprocessLauncher) launcher = NULL;
       g_autoptr(IdeSubprocess) process = NULL;
+      GFile *manifest = NULL;
       JsonArray *finish_args = NULL;
       const gchar *command = NULL;
       JsonParser *parser = NULL;
 
       /* Attempt to parse the flatpak manifest */
-      if (self->manifest != NULL && (manifest_path = g_file_get_path (self->manifest)))
+      if (GBP_IS_FLATPAK_CONFIGURATION (configuration) &&
+          (manifest = gbp_flatpak_configuration_get_manifest ((GbpFlatpakConfiguration *)configuration)) &&
+          (manifest_path = g_file_get_path (manifest)))
         {
           GError *json_error = NULL;
           JsonObject *root_object;
@@ -677,7 +687,7 @@ gbp_flatpak_runtime_postinstall_worker (GTask        *task,
       return;
     }
 
-  app_id = self->app_id;
+  app_id = ide_configuration_get_app_id (configuration);
   if (ide_str_empty0 (app_id))
     {
       g_warning ("Could not determine application ID");
@@ -789,13 +799,22 @@ gbp_flatpak_runtime_create_launcher (IdeRuntime  *runtime,
       JsonObject *env_vars = NULL;
       JsonParser *parser = NULL;
       g_autoptr(GFileInfo) file_info = NULL;
-      IdeContext *context;
+      GFile *manifest;
       GFile *project_file;
+      IdeContext *context;
+      IdeConfigurationManager *config_manager;
+      IdeConfiguration *configuration;
 
       build_path = get_build_directory (self);
 
+      context = ide_object_get_context (IDE_OBJECT (self));
+      config_manager = ide_context_get_configuration_manager (context);
+      configuration = ide_configuration_manager_get_current (config_manager);
+
       /* Attempt to parse the flatpak manifest */
-      if (self->manifest != NULL && (manifest_path = g_file_get_path (self->manifest)))
+      if (GBP_IS_FLATPAK_CONFIGURATION (configuration) &&
+          (manifest = gbp_flatpak_configuration_get_manifest ((GbpFlatpakConfiguration *)configuration)) &&
+          (manifest_path = g_file_get_path (manifest)))
         {
           GError *json_error = NULL;
           JsonObject *root_object;
@@ -825,7 +844,6 @@ gbp_flatpak_runtime_create_launcher (IdeRuntime  *runtime,
         }
 
       /* Find the project directory path */
-      context = ide_object_get_context (IDE_OBJECT (self));
       project_file = ide_context_get_project_file (context);
       if (project_file != NULL)
         {
@@ -915,7 +933,6 @@ gbp_flatpak_runtime_create_runner (IdeRuntime     *runtime,
   IdeConfiguration *configuration;
   GbpFlatpakRunner *runner;
   const gchar *app_id = NULL;
-  const gchar *config_app_id = NULL;
   g_autofree gchar *own_name = NULL;
   g_autofree gchar *app_id_override = NULL;
 
@@ -929,31 +946,20 @@ gbp_flatpak_runtime_create_runner (IdeRuntime     *runtime,
   runner = gbp_flatpak_runner_new (context);
   g_assert (GBP_IS_FLATPAK_RUNNER (runner));
 
-  app_id = self->app_id;
-  config_app_id = ide_configuration_get_app_id (configuration);
+  app_id = ide_configuration_get_app_id (configuration);
   if (ide_str_empty0 (app_id))
     {
       g_warning ("Could not determine application ID");
       app_id = "org.gnome.FlatpakApp";
     }
 
-  if (g_strcmp0 (app_id, config_app_id) != 0)
-    {
-      own_name = g_strdup_printf ("--own-name=%s", config_app_id);
-      app_id_override = g_strdup_printf ("--gapplication-app-id=%s", config_app_id);
-    }
-
   ide_runner_set_run_on_host (IDE_RUNNER (runner), TRUE);
   ide_runner_append_argv (IDE_RUNNER (runner), "flatpak");
   ide_runner_append_argv (IDE_RUNNER (runner), "run");
-  if (own_name != NULL)
-    ide_runner_append_argv (IDE_RUNNER (runner), own_name);
   ide_runner_append_argv (IDE_RUNNER (runner), "--share=ipc");
   ide_runner_append_argv (IDE_RUNNER (runner), "--socket=x11");
   ide_runner_append_argv (IDE_RUNNER (runner), "--socket=wayland");
   ide_runner_append_argv (IDE_RUNNER (runner), app_id);
-  if (app_id_override)
-    ide_runner_append_argv (IDE_RUNNER (runner), app_id_override);
 
   return IDE_RUNNER (runner);
 }
@@ -967,12 +973,6 @@ gbp_flatpak_runtime_prepare_configuration (IdeRuntime       *runtime,
   g_assert (GBP_IS_FLATPAK_RUNTIME (self));
   g_assert (IDE_IS_CONFIGURATION (configuration));
 
-  if (!ide_configuration_get_app_id (configuration))
-    {
-      if (!ide_str_empty0 (self->app_id))
-        ide_configuration_set_app_id (configuration, self->app_id);
-    }
-
   ide_configuration_set_prefix (configuration, "/app");
   ide_configuration_set_internal_string (configuration, "flatpak-repo-name", FLATPAK_REPO_NAME);
 }
@@ -1069,18 +1069,6 @@ gbp_flatpak_runtime_get_property (GObject    *object,
       g_value_set_string (value, self->sdk);
       break;
 
-    case PROP_PRIMARY_MODULE:
-      g_value_set_string (value, self->primary_module);
-      break;
-
-    case PROP_APP_ID:
-      g_value_set_string (value, self->app_id);
-      break;
-
-    case PROP_MANIFEST:
-      g_value_set_object (value, self->manifest);
-      break;
-
     case PROP_DEPLOY_DIR:
       g_value_set_string (value, self->deploy_dir);
       break;
@@ -1112,18 +1100,6 @@ gbp_flatpak_runtime_set_property (GObject      *object,
       self->sdk = g_value_dup_string (value);
       break;
 
-    case PROP_PRIMARY_MODULE:
-      self->primary_module = g_value_dup_string (value);
-      break;
-
-    case PROP_APP_ID:
-      self->app_id = g_value_dup_string (value);
-      break;
-
-    case PROP_MANIFEST:
-      self->manifest = g_value_dup_object (value);
-      break;
-
     case PROP_DEPLOY_DIR:
       gbp_flatpak_runtime_set_deploy_dir (self, g_value_get_string (value));
       break;
@@ -1141,11 +1117,8 @@ gbp_flatpak_runtime_finalize (GObject *object)
   g_clear_pointer (&self->sdk, g_free);
   g_clear_pointer (&self->platform, g_free);
   g_clear_pointer (&self->branch, g_free);
-  g_clear_pointer (&self->primary_module, g_free);
-  g_clear_pointer (&self->app_id, g_free);
   g_clear_pointer (&self->deploy_dir, g_free);
   g_clear_object (&self->deploy_dir_files);
-  g_clear_object (&self->manifest);
 
   G_OBJECT_CLASS (gbp_flatpak_runtime_parent_class)->finalize (object);
 }
@@ -1206,33 +1179,6 @@ gbp_flatpak_runtime_class_init (GbpFlatpakRuntimeClass *klass)
                           G_PARAM_CONSTRUCT |
                           G_PARAM_STATIC_STRINGS));
 
-  properties [PROP_PRIMARY_MODULE] =
-    g_param_spec_string ("primary-module",
-                         "Primary module",
-                         "Primary module",
-                         NULL,
-                         (G_PARAM_READWRITE |
-                          G_PARAM_CONSTRUCT |
-                          G_PARAM_STATIC_STRINGS));
-
-  properties [PROP_APP_ID] =
-    g_param_spec_string ("app-id",
-                         "App ID",
-                         "App ID",
-                         NULL,
-                         (G_PARAM_READWRITE |
-                          G_PARAM_CONSTRUCT |
-                          G_PARAM_STATIC_STRINGS));
-
-  properties [PROP_MANIFEST] =
-    g_param_spec_object ("manifest",
-                         "Manifest",
-                         "Manifest file for use with flatpak-builder",
-                         G_TYPE_FILE,
-                         (G_PARAM_READWRITE |
-                          G_PARAM_CONSTRUCT |
-                          G_PARAM_STATIC_STRINGS));
-
   g_object_class_install_properties (object_class, N_PROPS, properties);
 }
 


[Date Prev][Date Next]   [Thread Prev][Thread Next]   [Thread Index] [Date Index] [Author Index]