[gnome-builder] flatpak: improved flatpak configuration support



commit 042e37fbcdb5b1d11b83386a5e5f76d5b2f5f744
Author: Christian Hergert <chergert redhat com>
Date:   Tue Jan 30 04:08:19 2018 -0800

    flatpak: improved flatpak configuration support
    
    This simplifies the implementation of flatpak manifest parsing. It drops
    the buggy implementation of write-back. That will come back in a future
    commit, but is not going to be non-destructive towards comments.

 .../flatpak/gbp-flatpak-build-target-provider.c    |   6 +-
 .../flatpak/gbp-flatpak-configuration-provider.c   | 991 +++------------------
 src/plugins/flatpak/gbp-flatpak-configuration.c    | 900 -------------------
 src/plugins/flatpak/gbp-flatpak-configuration.h    |  61 --
 src/plugins/flatpak/gbp-flatpak-download-stage.c   |   8 +-
 src/plugins/flatpak/gbp-flatpak-manifest.c         | 645 ++++++++++++++
 src/plugins/flatpak/gbp-flatpak-manifest.h         |  49 +
 src/plugins/flatpak/gbp-flatpak-pipeline-addin.c   |  18 +-
 src/plugins/flatpak/gbp-flatpak-runner.c           |   6 +-
 src/plugins/flatpak/gbp-flatpak-runtime-provider.c |   6 +-
 src/plugins/flatpak/gbp-flatpak-runtime.c          |  10 +-
 src/plugins/flatpak/meson.build                    |   4 +-
 12 files changed, 831 insertions(+), 1873 deletions(-)
---
diff --git a/src/plugins/flatpak/gbp-flatpak-build-target-provider.c 
b/src/plugins/flatpak/gbp-flatpak-build-target-provider.c
index a9bb48e97..bdc79e2c2 100644
--- a/src/plugins/flatpak/gbp-flatpak-build-target-provider.c
+++ b/src/plugins/flatpak/gbp-flatpak-build-target-provider.c
@@ -20,7 +20,7 @@
 
 #include "gbp-flatpak-build-target.h"
 #include "gbp-flatpak-build-target-provider.h"
-#include "gbp-flatpak-configuration.h"
+#include "gbp-flatpak-manifest.h"
 
 struct _GbpFlatpakBuildTargetProvider
 {
@@ -53,12 +53,12 @@ gbp_flatpak_build_target_provider_get_targets_async (IdeBuildTargetProvider *pro
 
   targets = g_ptr_array_new_with_free_func (g_object_unref);
 
-  if (GBP_IS_FLATPAK_CONFIGURATION (config))
+  if (GBP_IS_FLATPAK_MANIFEST (config))
     {
       g_autoptr(IdeBuildTarget) target = NULL;
       const gchar *command;
 
-      command = gbp_flatpak_configuration_get_command (GBP_FLATPAK_CONFIGURATION (config));
+      command = gbp_flatpak_manifest_get_command (GBP_FLATPAK_MANIFEST (config));
 
       target = g_object_new (GBP_TYPE_FLATPAK_BUILD_TARGET,
                              "context", context,
diff --git a/src/plugins/flatpak/gbp-flatpak-configuration-provider.c 
b/src/plugins/flatpak/gbp-flatpak-configuration-provider.c
index 1d0ab9c39..4812199ad 100644
--- a/src/plugins/flatpak/gbp-flatpak-configuration-provider.c
+++ b/src/plugins/flatpak/gbp-flatpak-configuration-provider.c
@@ -22,26 +22,18 @@
 #include <json-glib/json-glib.h>
 #include <string.h>
 
-#include "gbp-flatpak-configuration.h"
 #include "gbp-flatpak-configuration-provider.h"
+#include "gbp-flatpak-manifest.h"
 
 #define DISCOVERY_MAX_DEPTH 3
 
 struct _GbpFlatpakConfigurationProvider
 {
   IdeObject  parent_instance;
-  GMutex     mutex;
   GPtrArray *configs;
-  GPtrArray *manifest_monitors;
 };
 
-static void configuration_provider_iface_init (IdeConfigurationProviderInterface *iface);
 
-G_DEFINE_TYPE_WITH_CODE (GbpFlatpakConfigurationProvider,
-                         gbp_flatpak_configuration_provider,
-                         IDE_TYPE_OBJECT,
-                         G_IMPLEMENT_INTERFACE (IDE_TYPE_CONFIGURATION_PROVIDER,
-                                                configuration_provider_iface_init))
 
 static GRegex *filename_regex;
 
@@ -59,500 +51,12 @@ gbp_flatpak_configuration_provider_save_worker (GTask        *task,
   g_assert (GBP_IS_FLATPAK_CONFIGURATION_PROVIDER (self));
   g_assert (!cancellable || G_IS_CANCELLABLE (cancellable));
 
-  g_mutex_lock (&self->mutex);
-
-  for (guint i = 0; i < self->configs->len; i++)
-    {
-      GbpFlatpakConfiguration *configuration = g_ptr_array_index (self->configs, i);
-      g_autoptr(GFileInputStream) file_stream = NULL;
-      g_autoptr(GDataInputStream) data_stream = NULL;
-      g_autoptr(GRegex) runtime_regex = NULL;
-      g_autoptr(GRegex) runtime_version_regex = NULL;
-      g_autoptr(GRegex) build_options_regex = NULL;
-      g_autoptr(GRegex) config_opts_regex = NULL;
-      g_autoptr(GRegex) primary_module_regex = NULL;
-      g_autoptr(GPtrArray) new_lines = NULL;
-      g_autoptr(GBytes) bytes = NULL;
-      g_auto(GStrv) new_config_opts = NULL;
-      g_auto(GStrv) new_runtime_parts = NULL;
-      g_auto(GStrv) new_environ = NULL;
-      g_autoptr(GError) error = NULL;
-      g_autofree gchar *primary_module_regex_str = NULL;
-      g_autofree gchar *primary_module_right_curly_brace = NULL;
-      g_autofree gchar *right_curly_brace_line = NULL;
-      g_autofree gchar *primary_module_indent = NULL;
-      g_autofree gchar *build_options_indent = NULL;
-      g_autofree gchar *config_opt_indent = NULL;
-      g_autofree gchar *array_prefix = NULL;
-      g_autofree gchar *new_config_opts_string = NULL;
-      const gchar *primary_module;
-      const gchar *new_runtime_id;
-      const gchar *config_prefix;
-      const gchar *new_prefix;
-      const gchar *new_runtime_name = NULL;
-      const gchar *new_runtime_version = NULL;
-      gchar *json_string;
-      GFile *manifest;
-      gboolean in_config_opts_array;
-      gboolean in_primary_module;
-      gboolean in_build_options;
-      gboolean config_opts_replaced;
-      gboolean build_options_replaced;
-      guint opts_per_line = 0;
-      guint nested_curly_braces;
-
-      if (!(manifest = gbp_flatpak_configuration_get_manifest (configuration)))
-        continue;
-
-      if (!(primary_module = gbp_flatpak_configuration_get_primary_module (configuration)))
-        {
-          g_warning ("Flatpak manifest configuration has no primary module set");
-          continue;
-        }
-
-      if (!(file_stream = g_file_read (manifest, NULL, &error)))
-        {
-          g_task_return_error (task, g_steal_pointer (&error));
-          IDE_GOTO (unlock);
-        }
-
-      data_stream = g_data_input_stream_new (G_INPUT_STREAM (file_stream));
-
-      runtime_regex = g_regex_new ("^\\s*\"runtime\"\\s*:\\s*\"(?<id>.+)\",$", 0, 0, NULL);
-      runtime_version_regex = g_regex_new ("^\\s*\"runtime-version\"\\s*:\\s*\"(?<version>.+)\",$", 0, 0, 
NULL);
-      build_options_regex = g_regex_new ("^\\s*\"build-options\"\\s*:\\s*{$", 0, 0, NULL);
-      config_opts_regex = g_regex_new ("^(\\s*\"config-opts\"\\s*:\\s*\\[\\s*).+$", 0, 0, NULL);
-      primary_module_regex_str = g_strdup_printf ("^(\\s*)\"name\"\\s*:\\s*\"%s\",$", primary_module);
-      primary_module_regex = g_regex_new (primary_module_regex_str, 0, 0, NULL);
-
-      new_runtime_id = ide_configuration_get_runtime_id (IDE_CONFIGURATION (configuration));
-
-      if (g_str_has_prefix (new_runtime_id, "flatpak:"))
-        {
-          new_runtime_parts = g_strsplit (new_runtime_id + 8, "/", 3);
-          if (new_runtime_parts[0] != NULL)
-            new_runtime_name = new_runtime_parts[0];
-
-          if (new_runtime_parts[2] != NULL)
-            new_runtime_version = new_runtime_parts[2];
-        }
-
-      new_config_opts_string = g_strdup (ide_configuration_get_config_opts (IDE_CONFIGURATION 
(configuration)));
-      if (!dzl_str_empty0 (new_config_opts_string))
-        new_config_opts = g_strsplit (g_strstrip (new_config_opts_string), " ", 0);
-
-      new_environ = ide_configuration_get_environ (IDE_CONFIGURATION (configuration));
-
-      config_prefix = ide_configuration_get_prefix (IDE_CONFIGURATION (configuration));
-      new_prefix = (g_strcmp0 (config_prefix, "/app") != 0) ? config_prefix : "";
-
-      /**
-       * XXX: The following code, which parses parts of the manifest file and edits
-       * it to match the options chosen by the user in Builder's interface, assumes
-       * that the JSON is "pretty" (meaning it has lots of whitespace and newlines),
-       * which is not technically a requirement for JSON but a de facto standard used
-       * by developers.
-       */
-      new_lines = g_ptr_array_new_with_free_func (g_free);
-      in_config_opts_array = FALSE;
-      in_primary_module = FALSE;
-      in_build_options = FALSE;
-      config_opts_replaced = FALSE;
-      build_options_replaced = FALSE;
-      nested_curly_braces = 0;
-      for (;;)
-        {
-          g_autofree gchar *line = NULL;
-
-          line = g_data_input_stream_read_line_utf8 (data_stream, NULL, NULL, &error);
-
-          if (error != NULL)
-            {
-              g_task_return_error (task, g_steal_pointer (&error));
-              IDE_GOTO (unlock);
-            }
-
-          if (line == NULL)
-            break;
-
-          /* Check if we've reached the primary module's section */
-          if (!in_primary_module)
-            {
-              g_autoptr(GMatchInfo) match_info = NULL;
-
-              g_regex_match (primary_module_regex, line, 0, &match_info);
-              if (g_match_info_matches (match_info))
-                {
-                  gchar *previous_line;
-                  g_auto(GStrv) previous_line_parts = NULL;
-
-                  in_primary_module = TRUE;
-                  primary_module_indent = g_match_info_fetch (match_info, 1);
-
-                  /* Replace '}' with '{' in the last line to get the right indentation */
-                  previous_line = (gchar *)g_ptr_array_index (new_lines, new_lines->len - 1);
-                  previous_line_parts = g_strsplit (previous_line, "{", 0);
-                  primary_module_right_curly_brace = g_strjoinv ("}", previous_line_parts);
-                }
-            }
-
-          /* Replace the runtime with the user-chosen one */
-          if (!dzl_str_empty0 (new_runtime_name))
-            {
-              g_autoptr(GMatchInfo) match_info = NULL;
-
-              g_regex_match (runtime_regex, line, 0, &match_info);
-              if (g_match_info_matches (match_info))
-                {
-                  gchar *old_runtime_ptr;
-                  gchar *new_line;
-                  g_autofree gchar *id = NULL;
-
-                  id = g_match_info_fetch_named (match_info, "id");
-                  old_runtime_ptr = g_strstr_len (line, -1, id);
-                  *old_runtime_ptr = '\0';
-                  new_line = g_strdup_printf ("%s%s\",", line, new_runtime_name);
-                  g_free (line);
-                  line = new_line;
-                }
-            }
-
-          /* Replace the runtime version with the user-chosen one */
-          if (!dzl_str_empty0 (new_runtime_version))
-            {
-              g_autoptr(GMatchInfo) match_info = NULL;
-
-              g_regex_match (runtime_version_regex, line, 0, &match_info);
-              if (g_match_info_matches (match_info))
-                {
-                  gchar *old_runtime_version_ptr;
-                  gchar *new_line;
-                  g_autofree gchar *version = NULL;
-
-                  version = g_match_info_fetch_named (match_info, "version");
-                  old_runtime_version_ptr = g_strstr_len (line, -1, version);
-                  *old_runtime_version_ptr = '\0';
-                  new_line = g_strdup_printf ("%s%s\",", line, new_runtime_version);
-                  g_free (line);
-                  line = new_line;
-                }
-            }
-
-          /* Update the build-options object */
-          if (!in_build_options && !build_options_replaced)
-            {
-              g_autoptr(GMatchInfo) match_info = NULL;
-
-              g_regex_match (build_options_regex, line, 0, &match_info);
-              if (g_match_info_matches (match_info))
-                in_build_options = TRUE;
-            }
-          else if (in_build_options)
-            {
-              if (g_strstr_len (line, -1, "{") != NULL)
-                nested_curly_braces++;
-
-              if (g_strstr_len (line, -1, "}") == NULL)
-                {
-                  if (build_options_indent == NULL)
-                    {
-                      g_autoptr(GRegex) build_options_internal_regex = NULL;
-                      g_autoptr(GMatchInfo) match_info = NULL;
-
-                      build_options_internal_regex = g_regex_new ("^(\\s*)\".+\"\\s*:.*$", 0, 0, NULL);
-                      g_regex_match (build_options_internal_regex, line, 0, &match_info);
-                      if (g_match_info_matches (match_info))
-                        build_options_indent = g_match_info_fetch (match_info, 1);
-                    }
-
-                  /* Discard the line because it will be replaced with new info */
-                  continue;
-                }
-              else
-                {
-                  if (nested_curly_braces > 0)
-                    {
-                      nested_curly_braces--;
-                      continue;
-                    }
-                  else
-                    {
-                      /* We're at the closing curly brace for build-options */
-                      guint num_env;
-                      num_env = g_strv_length (new_environ);
-                      if (num_env > 0 || !dzl_str_empty0 (new_prefix))
-                        {
-                          g_autofree gchar *cflags_line = NULL;
-                          g_autofree gchar *cxxflags_line = NULL;
-                          g_autoptr(GPtrArray) env_lines = NULL;
-
-                          if (build_options_indent == NULL)
-                            build_options_indent = g_strdup ("        ");
-
-                          for (guint j = 0; new_environ[j]; j++)
-                            {
-                              g_auto(GStrv) line_parts = NULL;
-
-                              line_parts = g_strsplit (new_environ[j], "=", 2);
-                              if (g_strcmp0 (line_parts[0], "CFLAGS") == 0)
-                                {
-                                  g_free (cflags_line);
-                                  cflags_line = g_strdup_printf ("%s\"cflags\": \"%s\"",
-                                                                 build_options_indent,
-                                                                 line_parts[1]);
-                                }
-                              else if (g_strcmp0 (line_parts[0], "CXXFLAGS") == 0)
-                                {
-                                  g_free (cxxflags_line);
-                                  cxxflags_line = g_strdup_printf ("%s\"cxxflags\": \"%s\"",
-                                                                   build_options_indent,
-                                                                   line_parts[1]);
-                                }
-                              else
-                                {
-                                  if (env_lines == NULL)
-                                    {
-                                      env_lines = g_ptr_array_new_with_free_func (g_free);
-                                      g_ptr_array_add (env_lines, g_strdup_printf ("%s\"env\": {", 
build_options_indent));
-                                    }
-
-                                  g_ptr_array_add (env_lines, g_strdup_printf ("%s    \"%s\": \"%s\"",
-                                                                               build_options_indent,
-                                                                               line_parts[0],
-                                                                               line_parts[1]));
-                                }
-                            }
-                          if (cflags_line != NULL)
-                            {
-                              gchar *line_ending;
-
-                              line_ending = (!dzl_str_empty0 (new_prefix) || cxxflags_line != NULL || 
env_lines != NULL) ? "," : "";
-                              g_ptr_array_add (new_lines, g_strdup_printf ("%s%s", cflags_line, 
line_ending));
-                            }
-
-                          if (cxxflags_line != NULL)
-                            {
-                              gchar *line_ending;
-
-                              line_ending = (!dzl_str_empty0 (new_prefix) || env_lines != NULL) ? "," : "";
-                              g_ptr_array_add (new_lines, g_strdup_printf ("%s%s", cxxflags_line, 
line_ending));
-                            }
-
-                          if (!dzl_str_empty0 (new_prefix))
-                            {
-                              gchar *line_ending;
-
-                              line_ending = (env_lines != NULL) ? "," : "";
-                              g_ptr_array_add (new_lines, g_strdup_printf ("%s\"prefix\": \"%s\"%s",
-                                                                           build_options_indent,
-                                                                           new_prefix,
-                                                                           line_ending));
-                            }
-                          if (env_lines != NULL)
-                            {
-                              g_ptr_array_add (env_lines, g_strdup_printf ("%s}", build_options_indent));
-                              for (guint j = 0; j < env_lines->len; j++)
-                                {
-                                  gchar *env_line;
-                                  gchar *line_ending;
-
-                                  line_ending = (j > 0 && j < env_lines->len - 2) ? "," : "";
-                                  env_line = (gchar *)g_ptr_array_index (env_lines, j);
-                                  g_ptr_array_add (new_lines, g_strdup_printf ("%s%s", env_line, 
line_ending));
-                                }
-                            }
-                        }
-
-                       in_build_options = FALSE;
-                       build_options_replaced = TRUE;
-                    }
-                }
-            }
-
-          if (in_primary_module)
-            {
-              g_autoptr(GMatchInfo) match_info = NULL;
-
-              /* Check if we're at the end of the module and haven't seen a config-opts property */
-              if (g_str_has_prefix (line, primary_module_right_curly_brace))
-                {
-                  in_primary_module = FALSE;
-                  if (!config_opts_replaced && new_config_opts != NULL)
-                    {
-                      gchar *previous_line;
-                      gchar *new_line;
-
-                      previous_line = (gchar *)g_ptr_array_index (new_lines, new_lines->len - 1);
-                      new_line = g_strdup_printf ("%s,", previous_line);
-                      g_ptr_array_remove_index (new_lines, new_lines->len - 1);
-                      g_ptr_array_add (new_lines, new_line);
-                      right_curly_brace_line = line;
-                      line = g_strdup_printf ("%s\"config-opts\": []", primary_module_indent);
-                    }
-                }
-
-              /* Update the list of configure options, or omit it entirely */
-              g_regex_match (config_opts_regex, line, 0, &match_info);
-              if (g_match_info_matches (match_info) || in_config_opts_array)
-                {
-                  gchar *right_bracket;
-                  gchar *next_line;
-
-                  right_bracket = g_strstr_len (line, -1, "]");
-                  if (g_match_info_matches (match_info))
-                    {
-                      array_prefix = g_match_info_fetch (match_info, 1);
-                      if (right_bracket != NULL)
-                        {
-                          /*
-                           * Ensure that all options will be on one line,
-                           * even if there are more than before
-                           */
-                          if (new_config_opts == NULL)
-                            opts_per_line = 1;
-                          else
-                            opts_per_line = g_strv_length (new_config_opts);
-                        }
-                      else
-                        {
-                          in_config_opts_array = TRUE;
-                          if (new_config_opts == NULL)
-                            opts_per_line = 1;
-                          else
-                            {
-                              g_auto(GStrv) line_parts = NULL;
-
-                              line_parts = g_strsplit (line, "\"", 0);
-                              opts_per_line = (g_strv_length (line_parts) - 3) / 2;
-                              opts_per_line = (opts_per_line > 0) ? opts_per_line : 1;
-                            }
-
-                          continue;
-                        }
-                    }
-                  if (right_bracket == NULL)
-                    {
-                      in_config_opts_array = TRUE;
-                      config_opt_indent = g_strsplit (line, "\"", 0)[0];
-                      continue;
-                    }
-
-                  /* Check if we're on the last line of the module */
-                  next_line = g_data_input_stream_read_line_utf8 (data_stream, NULL, NULL, &error);
-                  if (error != NULL)
-                    {
-                      g_task_return_error (task, g_steal_pointer (&error));
-                      IDE_GOTO (unlock);
-                    }
-                  if (g_str_has_prefix (next_line, primary_module_right_curly_brace))
-                    right_curly_brace_line = next_line;
-
-                  /* At this point it's either a single line or we're on the last line */
-                  in_config_opts_array = FALSE;
-                  config_opts_replaced = TRUE;
-                  if (new_config_opts == NULL)
-                    {
-                      if (right_curly_brace_line == NULL)
-                        g_ptr_array_add (new_lines, g_strdup_printf ("%s],", array_prefix));
-                      else
-                        g_ptr_array_add (new_lines, g_strdup_printf ("%s]", array_prefix));
-                    }
-                  else
-                    {
-                      gchar *array_suffix;
-
-                      array_suffix = *(right_bracket - 1) == ' ' ? " ]" : "]";
-                      if (config_opt_indent == NULL)
-                        {
-                          g_auto(GStrv) line_parts = NULL;
-
-                          line_parts = g_strsplit (line, "\"", 0);
-                          config_opt_indent = g_strdup (line_parts[0]);
-                        }
-
-                      for (guint j = 0; g_strv_length (new_config_opts) > j; j += opts_per_line)
-                        {
-                          g_autoptr(GPtrArray) config_opts_subset = NULL;
-                          g_autofree gchar *opts_this_line = NULL;
-                          gchar *prefix;
-                          gchar *suffix;
-                          gchar *new_line;
-
-                          prefix = (j == 0) ? array_prefix : config_opt_indent;
-                          suffix = (g_strv_length (new_config_opts) <= j + opts_per_line) ? array_suffix : 
"";
-                          config_opts_subset = g_ptr_array_new ();
-                          for (guint k = 0; k < opts_per_line && new_config_opts[j+k]; ++k)
-                            g_ptr_array_add (config_opts_subset, new_config_opts[j+k]);
-
-                          g_ptr_array_add (config_opts_subset, NULL);
-                          opts_this_line = g_strjoinv ("\", \"", (gchar **)config_opts_subset->pdata);
-
-                          if (suffix == array_suffix && right_curly_brace_line != NULL)
-                            new_line = g_strdup_printf ("%s\"%s\"%s", prefix, opts_this_line, suffix);
-                          else
-                            new_line = g_strdup_printf ("%s\"%s\"%s,", prefix, opts_this_line, suffix);
-
-                          g_ptr_array_add (new_lines, new_line);
-                        }
-                    }
-
-                  /* Discard the line that was just replaced with the new config-opts array */
-
-                  /* If we're on the last line of the module, add the curly brace now */
-                  if (right_curly_brace_line != NULL)
-                    {
-                      g_ptr_array_add (new_lines, right_curly_brace_line);
-                      right_curly_brace_line = NULL;
-                    }
-
-                  /* If the next line isn't a curly brace, add it since we already read it */
-                  if (next_line != NULL &&
-                      !g_str_has_prefix (next_line, primary_module_right_curly_brace))
-                    g_ptr_array_add (new_lines, next_line);
-
-                  continue;
-                }
-            }
-
-          g_ptr_array_add (new_lines, line);
-          if (right_curly_brace_line != NULL)
-            {
-              g_ptr_array_add (new_lines, right_curly_brace_line);
-              right_curly_brace_line = NULL;
-            }
-        }
-
-      /* Ensure there's a newline at the end of the file */
-      g_ptr_array_add (new_lines, g_strdup (""));
-      g_ptr_array_add (new_lines, NULL);
-
-      /* Write the updated lines to the disk */
-      json_string = g_strjoinv ("\n", (gchar **)new_lines->pdata);
-      bytes = g_bytes_new_take (json_string, strlen (json_string));
-      if (!g_file_replace_contents (manifest,
-                                    g_bytes_get_data (bytes, NULL),
-                                    g_bytes_get_size (bytes),
-                                    NULL,
-                                    FALSE,
-                                    G_FILE_CREATE_NONE,
-                                    NULL,
-                                    cancellable,
-                                    &error))
-        {
-          g_task_return_error (task, g_steal_pointer (&error));
-          IDE_GOTO (unlock);
-        }
-    }
-
   g_task_return_boolean (task, TRUE);
 
-unlock:
-  g_mutex_unlock (&self->mutex);
-
   IDE_EXIT;
 }
 
-void
+static void
 gbp_flatpak_configuration_provider_save_async (IdeConfigurationProvider *provider,
                                                GCancellable             *cancellable,
                                                GAsyncReadyCallback       callback,
@@ -574,375 +78,87 @@ gbp_flatpak_configuration_provider_save_async (IdeConfigurationProvider *provide
   IDE_EXIT;
 }
 
-gboolean
+static gboolean
 gbp_flatpak_configuration_provider_save_finish (IdeConfigurationProvider  *provider,
                                                 GAsyncResult              *result,
                                                 GError                   **error)
 {
-  GbpFlatpakConfigurationProvider *self = (GbpFlatpakConfigurationProvider *)provider;
-
-  g_return_val_if_fail (GBP_IS_FLATPAK_CONFIGURATION_PROVIDER (self), FALSE);
-  g_return_val_if_fail (G_IS_TASK (result), FALSE);
+  g_assert (GBP_IS_FLATPAK_CONFIGURATION_PROVIDER (provider));
+  g_assert (G_IS_TASK (result));
 
   return g_task_propagate_boolean (G_TASK (result), error);
 }
 
-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 (dzl_str_equal0 (id, ide_configuration_get_id (configuration)))
-        return TRUE;
-    }
-
-  return FALSE;
-}
-
-static gchar *
-get_manifest_id (const gchar *path,
-                 const gchar *filename)
-{
-  g_autofree gchar *manifest_data = NULL;
-  g_autofree gchar *hash = NULL;
-  gsize manifest_data_len = 0;
-
-  g_assert (!dzl_str_empty0 (path));
-
-  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));
-    }
-
-  if (hash != NULL)
-    return g_strdup_printf ("%s@%s", filename, hash);
-  else
-    return g_strdup (filename);
-}
-
-static void
-gbp_flatpak_configuration_provider_manifest_changed (GbpFlatpakConfigurationProvider *self,
-                                                     GFile                           *file,
-                                                     GFile                           *other_file,
-                                                     GFileMonitorEvent                event,
-                                                     GFileMonitor                    *file_monitor)
-{
-  g_autoptr(GbpFlatpakConfiguration) relevant_config = NULL;
-  IdeContext *context;
-  g_autofree gchar *filename = NULL;
-  g_autofree gchar *path = NULL;
-  g_autofree gchar *id = NULL;
-  GFile *new_config_file;
-
-  IDE_ENTRY;
-
-  g_assert (GBP_IS_FLATPAK_CONFIGURATION_PROVIDER (self));
-  g_assert (G_IS_FILE (file));
-  g_assert (G_IS_FILE_MONITOR (file_monitor));
-
-  context = ide_object_get_context (IDE_OBJECT (self));
-
-  g_mutex_lock (&self->mutex);
-
-  if (self->configs != NULL)
-    {
-      for (guint i = 0; i < self->configs->len; i++)
-        {
-          GbpFlatpakConfiguration *configuration = g_ptr_array_index (self->configs, i);
-          GFile *config_manifest;
-          config_manifest = gbp_flatpak_configuration_get_manifest (configuration);
-          if (g_file_equal (file, config_manifest) ||
-              (event == G_FILE_MONITOR_EVENT_RENAMED && g_file_equal (other_file, config_manifest)))
-            {
-              relevant_config = g_object_ref (configuration);
-              break;
-            }
-        }
-    }
-
-  if (relevant_config == NULL &&
-      event != G_FILE_MONITOR_EVENT_CREATED &&
-      event != G_FILE_MONITOR_EVENT_MOVED_IN)
-    IDE_GOTO (unlock);
-
-  new_config_file = file;
-  switch (event)
-    {
-    case G_FILE_MONITOR_EVENT_DELETED:
-    case G_FILE_MONITOR_EVENT_MOVED_OUT:
-      ide_configuration_provider_emit_removed (IDE_CONFIGURATION_PROVIDER (self),
-                                               IDE_CONFIGURATION (relevant_config));
-      g_ptr_array_remove_fast (self->configs, relevant_config);
-      break;
-
-    case G_FILE_MONITOR_EVENT_RENAMED:
-      filename = g_file_get_basename (other_file);
-      /* The "rename" is just a temporary file created by an editor */
-      if (g_str_has_suffix (filename, "~"))
-        IDE_GOTO (unlock);
-      else
-        g_clear_pointer (&filename, g_free);
-      new_config_file = other_file;
-#if G_GNUC_CHECK_VERSION(7,0)
-      __attribute__((fallthrough));
-#endif
-    case G_FILE_MONITOR_EVENT_CREATED:
-    case G_FILE_MONITOR_EVENT_CHANGES_DONE_HINT:
-    case G_FILE_MONITOR_EVENT_MOVED_IN:
-      path = g_file_get_path (new_config_file);
-      filename = g_file_get_basename (new_config_file);
-      id = get_manifest_id (path, filename);
-
-      if (!contains_id (self->configs, id))
-        {
-          g_autoptr(GbpFlatpakConfiguration) new_config = NULL;
-
-          new_config = gbp_flatpak_configuration_new (context, id, filename);
-          if (gbp_flatpak_configuration_load_from_file (new_config, new_config_file))
-            {
-              g_autoptr(GFileMonitor) manifest_monitor = NULL;
-              g_autoptr(GError) local_error = NULL;
-
-              manifest_monitor = g_file_monitor_file (new_config_file, G_FILE_MONITOR_WATCH_MOVES, NULL, 
&local_error);
-              if (manifest_monitor == NULL)
-                g_warning ("Error encountered trying to monitor flatpak manifest %s: %s", path, 
local_error->message);
-              else
-                {
-                  g_signal_connect_object (manifest_monitor,
-                                           "changed",
-                                           G_CALLBACK (gbp_flatpak_configuration_provider_manifest_changed),
-                                           self,
-                                           G_CONNECT_SWAPPED);
-                  g_ptr_array_add (self->manifest_monitors, g_steal_pointer (&manifest_monitor));
-                }
-
-              if (relevant_config != NULL)
-                {
-                  ide_configuration_provider_emit_removed (IDE_CONFIGURATION_PROVIDER (self),
-                                                           IDE_CONFIGURATION (relevant_config));
-                  g_ptr_array_remove_fast (self->configs, relevant_config);
-                }
-              g_ptr_array_remove_fast (self->manifest_monitors, file_monitor);
-              g_ptr_array_add (self->configs, g_object_ref (new_config));
-              ide_configuration_provider_emit_added (IDE_CONFIGURATION_PROVIDER (self),
-                                                     IDE_CONFIGURATION (new_config));
-            }
-        }
-      break;
-
-    case G_FILE_MONITOR_EVENT_CHANGED:
-    case G_FILE_MONITOR_EVENT_MOVED:
-    case G_FILE_MONITOR_EVENT_PRE_UNMOUNT:
-    case G_FILE_MONITOR_EVENT_UNMOUNTED:
-    case G_FILE_MONITOR_EVENT_ATTRIBUTE_CHANGED:
-    default:
-      break;
-    }
-
-unlock:
-  g_mutex_unlock (&self->mutex);
-
-  IDE_EXIT;
-}
-
 static void
-gbp_flatpak_configuration_provider_find_manifests (GbpFlatpakConfigurationProvider  *self,
-                                                   GFile                            *directory,
-                                                   GPtrArray                        *configs,
-                                                   gint                              depth,
-                                                   GCancellable                     *cancellable,
-                                                   GError                          **error)
+gbp_flatpak_configuration_provider_load_worker (GTask        *task,
+                                                gpointer      source_object,
+                                                gpointer      task_data,
+                                                GCancellable *cancellable)
 {
-  g_autoptr(GFileEnumerator) enumerator = NULL;
-  g_autoptr(GPtrArray) child_dirs = NULL;
+  GbpFlatpakConfigurationProvider *self = source_object;
+  g_autoptr(GPtrArray) manifests = NULL;
   IdeContext *context;
-  gpointer infoptr;
+  GPtrArray *files = task_data;
 
+  g_assert (G_IS_TASK (task));
   g_assert (GBP_IS_FLATPAK_CONFIGURATION_PROVIDER (self));
-  g_assert (G_IS_FILE (directory));
-  g_assert (configs != NULL);
+  g_assert (files != NULL);
   g_assert (!cancellable || G_IS_CANCELLABLE (cancellable));
-  g_assert (depth < DISCOVERY_MAX_DEPTH);
 
   context = ide_object_get_context (IDE_OBJECT (self));
-  g_assert (IDE_IS_CONTEXT (context));
-
-  enumerator = g_file_enumerate_children (directory,
-                                          G_FILE_ATTRIBUTE_STANDARD_IS_SYMLINK","
-                                          G_FILE_ATTRIBUTE_STANDARD_TYPE","
-                                          G_FILE_ATTRIBUTE_STANDARD_NAME,
-                                          G_FILE_QUERY_INFO_NONE,
-                                          cancellable,
-                                          error);
+  manifests = g_ptr_array_new_with_free_func (g_object_unref);
 
-  if (enumerator == NULL)
-    return;
-
-  while ((infoptr = g_file_enumerator_next_file (enumerator, cancellable, NULL)))
+  for (guint i = 0; i < files->len; i++)
     {
-      g_autoptr(GFileInfo) file_info = infoptr;
-      g_autofree gchar *filename = NULL;
-      g_autofree gchar *path = NULL;
-      g_autofree gchar *id = NULL;
-      g_autoptr(GMatchInfo) match_info = NULL;
-      g_autoptr(GFile) file = NULL;
-      g_autoptr(GbpFlatpakConfiguration) possible_config = NULL;
-      g_autoptr(GFileMonitor) manifest_monitor = NULL;
-      g_autoptr(GError) local_error = NULL;
-      GFileType file_type;
-
-      if (g_file_info_get_is_symlink (file_info))
-        continue;
-
-      file_type = g_file_info_get_file_type (file_info);
-      filename = g_strdup (g_file_info_get_name (file_info));
-      g_clear_object (&file_info);
-
-      if (filename == NULL)
-        continue;
-
-      file = g_file_get_child (directory, filename);
-
-      /* Recurse unless it's a directory that should be ignored */
-      if (file_type == G_FILE_TYPE_DIRECTORY)
-        {
-          if (g_strcmp0 (filename, ".git") == 0 || g_strcmp0 (filename, ".flatpak-builder") == 0)
-            continue;
-
-          if (depth < DISCOVERY_MAX_DEPTH - 1)
-            {
-              if (child_dirs == NULL)
-                child_dirs = g_ptr_array_new_with_free_func (g_object_unref);
-              g_ptr_array_add (child_dirs, g_steal_pointer (&file));
-              continue;
-            }
-        }
+      GFile *file = g_ptr_array_index (files, i);
+      g_autoptr(GbpFlatpakManifest) manifest = NULL;
+      g_autoptr(GError) error = NULL;
+      g_autofree gchar *name = NULL;
 
-      /* Check if the filename resembles APP_ID.json */
-      g_regex_match (filename_regex, filename, 0, &match_info);
-      if (!g_match_info_matches (match_info))
-        continue;
-
-      /* Check if the file has already been loaded as a config */
-      path = g_file_get_path (file);
-      id = get_manifest_id (path, filename);
-      if (contains_id (configs, id))
-        continue;
-
-      /* Finally, try to parse the file as a manifest */
-      possible_config = gbp_flatpak_configuration_new (context, id, filename);
-      if (!gbp_flatpak_configuration_load_from_file (possible_config, file))
-        continue;
-
-      manifest_monitor = g_file_monitor_file (file, G_FILE_MONITOR_WATCH_MOVES, NULL, &local_error);
-      if (manifest_monitor == NULL)
-        g_warning ("Error encountered trying to monitor flatpak manifest %s: %s", path, 
local_error->message);
-      else
-        {
-          g_signal_connect_object (manifest_monitor,
-                                   "changed",
-                                   G_CALLBACK (gbp_flatpak_configuration_provider_manifest_changed),
-                                   self,
-                                   G_CONNECT_SWAPPED);
-          g_ptr_array_add (self->manifest_monitors, g_steal_pointer (&manifest_monitor));
-        }
+      g_assert (G_IS_FILE (file));
 
-      g_ptr_array_add (configs, g_steal_pointer (&possible_config));
-    }
+      name = g_file_get_basename (file);
+      manifest = gbp_flatpak_manifest_new (context, file, name);
 
-  if (child_dirs != NULL)
-    {
-      for (guint i = 0; i < child_dirs->len; i++)
+      if (!g_initable_init (G_INITABLE (manifest), cancellable, &error))
         {
-          GFile *file = g_ptr_array_index (child_dirs, i);
-
-          if (g_cancellable_is_cancelled (cancellable))
-            return;
-
-          gbp_flatpak_configuration_provider_find_manifests (self, file, configs, depth + 1, cancellable, 
error);
+          g_message ("%s is not a flatpak manifest, skipping: %s",
+                     name, error->message);
+          continue;
         }
-    }
-}
-
-static void
-gbp_flatpak_configuration_provider_load_manifests (GbpFlatpakConfigurationProvider  *self,
-                                                   GPtrArray                        *configs,
-                                                   GCancellable                     *cancellable,
-                                                   GError                          **error)
-{
-  g_autoptr(GPtrArray) ar = NULL;
-  g_autoptr(GFileInfo) file_info = NULL;
-  g_autoptr(GFile) project_dir = NULL;
-  IdeContext *context;
-  GFile *project_file;
-
-  g_assert (GBP_IS_FLATPAK_CONFIGURATION_PROVIDER (self));
-  g_assert (configs != NULL);
-  g_assert (!cancellable || G_IS_CANCELLABLE (cancellable));
 
-  context = ide_object_get_context (IDE_OBJECT (self));
-  g_assert (IDE_IS_CONTEXT (context));
-
-  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;
-
-  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);
-
-  g_mutex_lock (&self->mutex);
-  gbp_flatpak_configuration_provider_find_manifests (self, project_dir, configs, 0, cancellable, error);
-  g_mutex_unlock (&self->mutex);
+      g_ptr_array_add (manifests, g_steal_pointer (&manifest));
+    }
 
-  g_debug ("Found %u flatpak manifests", configs->len);
+  g_task_return_pointer (task,
+                         g_steal_pointer (&manifests),
+                         (GDestroyNotify)g_ptr_array_unref);
 }
 
 static void
-gbp_flatpak_configuration_provider_load_worker (GTask        *task,
-                                                gpointer      source_object,
-                                                gpointer      task_data,
-                                                GCancellable *cancellable)
+load_find_files_cb (GObject      *object,
+                    GAsyncResult *result,
+                    gpointer      user_data)
 {
-  GbpFlatpakConfigurationProvider *self = source_object;
+  GFile *file = (GFile *)object;
+  g_autoptr(GTask) task = user_data;
   g_autoptr(GError) error = NULL;
-  GPtrArray *configs = task_data;
-
-  IDE_ENTRY;
+  g_autoptr(GPtrArray) ret = NULL;
 
+  g_assert (G_IS_FILE (file));
+  g_assert (G_IS_ASYNC_RESULT (result));
   g_assert (G_IS_TASK (task));
-  g_assert (GBP_IS_FLATPAK_CONFIGURATION_PROVIDER (self));
-  g_assert (configs != NULL);
-  g_assert (!cancellable || G_IS_CANCELLABLE (cancellable));
 
-  gbp_flatpak_configuration_provider_load_manifests (self, configs, cancellable, &error);
+  ret = ide_g_file_find_finish (file, result, &error);
 
-  if (error != NULL)
-    g_task_return_error (task, g_steal_pointer (&error));
-  else
-    g_task_return_boolean (task, TRUE);
+  if (ret == NULL)
+    {
+      g_task_return_error (task, g_steal_pointer (&error));
+      return;
+    }
 
-  IDE_EXIT;
+  g_task_set_task_data (task, g_steal_pointer (&ret), (GDestroyNotify)g_ptr_array_unref);
+  g_task_run_in_thread (task, gbp_flatpak_configuration_provider_load_worker);
 }
 
 static void
@@ -951,21 +167,31 @@ gbp_flatpak_configuration_provider_load_async (IdeConfigurationProvider *provide
                                                GAsyncReadyCallback       callback,
                                                gpointer                  user_data)
 {
+  GbpFlatpakConfigurationProvider *self = (GbpFlatpakConfigurationProvider *)provider;
   g_autoptr(GTask) task = NULL;
+  IdeContext *context;
+  IdeVcs *vcs;
+  GFile *workdir;
 
   IDE_ENTRY;
 
   g_assert (IDE_IS_MAIN_THREAD ());
-  g_assert (GBP_IS_FLATPAK_CONFIGURATION_PROVIDER (provider));
+  g_assert (GBP_IS_FLATPAK_CONFIGURATION_PROVIDER (self));
   g_assert (!cancellable || G_IS_CANCELLABLE (cancellable));
 
+  context = ide_object_get_context (IDE_OBJECT (self));
+  vcs = ide_context_get_vcs (context);
+  workdir = ide_vcs_get_working_directory (vcs);
+
   task = g_task_new (provider, cancellable, callback, user_data);
   g_task_set_source_tag (task, gbp_flatpak_configuration_provider_load_async);
   g_task_set_priority (task, G_PRIORITY_LOW);
-  g_task_set_task_data (task,
-                        g_ptr_array_new_with_free_func (g_object_unref),
-                        (GDestroyNotify)g_ptr_array_unref);
-  g_task_run_in_thread (task, gbp_flatpak_configuration_provider_load_worker);
+
+  ide_g_file_find_async (workdir,
+                         "*.json",
+                         cancellable,
+                         load_find_files_cb,
+                         g_steal_pointer (&task));
 
   IDE_EXIT;
 }
@@ -978,8 +204,8 @@ guess_best_config (GPtrArray *ar)
 
   for (guint i = 0; i < ar->len; i++)
     {
-      GbpFlatpakConfiguration *config = g_ptr_array_index (ar, i);
-      g_autofree gchar *path = gbp_flatpak_configuration_get_manifest_path (config);
+      GbpFlatpakManifest *config = g_ptr_array_index (ar, i);
+      g_autofree gchar *path = gbp_flatpak_manifest_get_path (config);
 
       if (strstr (path, "-unstable.json") != NULL)
         return IDE_CONFIGURATION (config);
@@ -987,8 +213,8 @@ guess_best_config (GPtrArray *ar)
 
   for (guint i = 0; i < ar->len; i++)
     {
-      GbpFlatpakConfiguration *config = g_ptr_array_index (ar, i);
-      g_autofree gchar *path = gbp_flatpak_configuration_get_manifest_path (config);
+      GbpFlatpakManifest *config = g_ptr_array_index (ar, i);
+      g_autofree gchar *path = gbp_flatpak_manifest_get_path (config);
       g_autofree gchar *base = g_path_get_basename (path);
       const gchar *app_id = ide_configuration_get_app_id (IDE_CONFIGURATION (config));
       g_autofree gchar *app_id_json = g_strdup_printf ("%s.json", app_id);
@@ -1009,41 +235,43 @@ gbp_flatpak_configuration_provider_load_finish (IdeConfigurationProvider  *provi
                                                 GError                   **error)
 {
   GbpFlatpakConfigurationProvider *self = (GbpFlatpakConfigurationProvider *)provider;
+  g_autoptr(GPtrArray) configs = NULL;
 
   g_assert (IDE_IS_MAIN_THREAD ());
   g_assert (GBP_IS_FLATPAK_CONFIGURATION_PROVIDER (self));
   g_assert (G_IS_TASK (result));
   g_assert (g_task_is_valid (G_TASK (result), provider));
 
-  if (g_task_propagate_boolean (G_TASK (result), error))
-    {
-      GPtrArray *configs = g_task_get_task_data (G_TASK (result));
+  configs = g_task_propagate_pointer (G_TASK (result), error);
 
-      g_assert (configs != NULL);
+  if (configs == NULL)
+    return FALSE;
 
-      for (guint i = 0; i < configs->len; i++)
-        {
-          IdeConfiguration *config = g_ptr_array_index (configs, i);
-          g_assert (IDE_IS_CONFIGURATION (config));
-          ide_configuration_provider_emit_added (provider, config);
-        }
+  g_clear_pointer (&self->configs, g_ptr_array_unref);
+  self->configs = g_ptr_array_ref (configs);
 
-      if (configs->len > 0)
-        {
-          IdeConfiguration *config = guess_best_config (configs);
-          IdeContext *context = ide_object_get_context (IDE_OBJECT (self));
-          IdeConfigurationManager *manager = ide_context_get_configuration_manager (context);
+  for (guint i = 0; i < configs->len; i++)
+    {
+      IdeConfiguration *config = g_ptr_array_index (configs, i);
 
-          g_assert (IDE_IS_CONFIGURATION (config));
+      g_assert (IDE_IS_CONFIGURATION (config));
 
-          /* TODO: We should have a GSetting for this, in config-manager */
-          ide_configuration_manager_set_current (manager, config);
-        }
+      ide_configuration_provider_emit_added (provider, config);
+    }
 
-      return TRUE;
+  if (configs->len > 0)
+    {
+      IdeConfiguration *config = guess_best_config (configs);
+      IdeContext *context = ide_object_get_context (IDE_OBJECT (self));
+      IdeConfigurationManager *manager = ide_context_get_configuration_manager (context);
+
+      g_assert (IDE_IS_CONFIGURATION (config));
+
+      /* TODO: We should have a GSetting for this, in config-manager */
+      ide_configuration_manager_set_current (manager, config);
     }
 
-  return FALSE;
+  return TRUE;
 }
 
 static void
@@ -1055,8 +283,6 @@ gbp_flatpak_configuration_provider_unload (IdeConfigurationProvider *provider)
 
   g_assert (GBP_IS_FLATPAK_CONFIGURATION_PROVIDER (self));
 
-  g_mutex_lock (&self->mutex);
-
   if (self->configs != NULL)
     {
       for (guint i = self->configs->len; i > 0; i--)
@@ -1066,26 +292,38 @@ gbp_flatpak_configuration_provider_unload (IdeConfigurationProvider *provider)
           config = g_object_ref (g_ptr_array_index (self->configs, i - 1));
           g_ptr_array_remove_index (self->configs, i);
 
-          g_mutex_unlock (&self->mutex);
           ide_configuration_provider_emit_removed (provider, config);
-          g_mutex_lock (&self->mutex);
         }
     }
 
   g_clear_pointer (&self->configs, g_ptr_array_unref);
-  g_clear_pointer (&self->manifest_monitors, g_ptr_array_unref);
-
-  g_mutex_unlock (&self->mutex);
 
   IDE_EXIT;
 }
 
+
+static void
+configuration_provider_iface_init (IdeConfigurationProviderInterface *iface)
+{
+  iface->load_async = gbp_flatpak_configuration_provider_load_async;
+  iface->load_finish = gbp_flatpak_configuration_provider_load_finish;
+  iface->unload = gbp_flatpak_configuration_provider_unload;
+  iface->save_async = gbp_flatpak_configuration_provider_save_async;
+  iface->save_finish = gbp_flatpak_configuration_provider_save_finish;
+}
+
+G_DEFINE_TYPE_WITH_CODE (GbpFlatpakConfigurationProvider,
+                         gbp_flatpak_configuration_provider,
+                         IDE_TYPE_OBJECT,
+                         G_IMPLEMENT_INTERFACE (IDE_TYPE_CONFIGURATION_PROVIDER,
+                                                configuration_provider_iface_init))
+
 static void
 gbp_flatpak_configuration_provider_finalize (GObject *object)
 {
   GbpFlatpakConfigurationProvider *self = (GbpFlatpakConfigurationProvider *)object;
 
-  g_mutex_clear (&self->mutex);
+  g_clear_pointer (&self->configs, g_ptr_array_unref);
 
   G_OBJECT_CLASS (gbp_flatpak_configuration_provider_parent_class)->finalize (object);
 }
@@ -1105,18 +343,5 @@ gbp_flatpak_configuration_provider_class_init (GbpFlatpakConfigurationProviderCl
 static void
 gbp_flatpak_configuration_provider_init (GbpFlatpakConfigurationProvider *self)
 {
-  g_mutex_init (&self->mutex);
-
-  self->manifest_monitors = g_ptr_array_new_with_free_func (g_object_unref);
   self->configs = g_ptr_array_new_with_free_func (g_object_unref);
 }
-
-static void
-configuration_provider_iface_init (IdeConfigurationProviderInterface *iface)
-{
-  iface->load_async = gbp_flatpak_configuration_provider_load_async;
-  iface->load_finish = gbp_flatpak_configuration_provider_load_finish;
-  iface->unload = gbp_flatpak_configuration_provider_unload;
-  iface->save_async = gbp_flatpak_configuration_provider_save_async;
-  iface->save_finish = gbp_flatpak_configuration_provider_save_finish;
-}
diff --git a/src/plugins/flatpak/gbp-flatpak-download-stage.c 
b/src/plugins/flatpak/gbp-flatpak-download-stage.c
index 3bd69cb1e..63605d8a0 100644
--- a/src/plugins/flatpak/gbp-flatpak-download-stage.c
+++ b/src/plugins/flatpak/gbp-flatpak-download-stage.c
@@ -20,8 +20,8 @@
 
 #include <glib/gi18n.h>
 
-#include "gbp-flatpak-configuration.h"
 #include "gbp-flatpak-download-stage.h"
+#include "gbp-flatpak-manifest.h"
 #include "gbp-flatpak-util.h"
 
 struct _GbpFlatpakDownloadStage
@@ -75,7 +75,7 @@ gbp_flatpak_download_stage_query (IdeBuildStage    *stage,
   config = ide_build_pipeline_get_configuration (pipeline);
   g_assert (!config || IDE_IS_CONFIGURATION (config));
 
-  if (!GBP_IS_FLATPAK_CONFIGURATION (config))
+  if (!GBP_IS_FLATPAK_MANIFEST (config))
     {
       ide_build_stage_set_completed (stage, TRUE);
       return;
@@ -85,8 +85,8 @@ gbp_flatpak_download_stage_query (IdeBuildStage    *stage,
     {
       g_autoptr(IdeSubprocessLauncher) launcher = NULL;
 
-      primary_module = gbp_flatpak_configuration_get_primary_module (GBP_FLATPAK_CONFIGURATION (config));
-      manifest_path = gbp_flatpak_configuration_get_manifest_path (GBP_FLATPAK_CONFIGURATION (config));
+      primary_module = gbp_flatpak_manifest_get_primary_module (GBP_FLATPAK_MANIFEST (config));
+      manifest_path = gbp_flatpak_manifest_get_path (GBP_FLATPAK_MANIFEST (config));
       staging_dir = gbp_flatpak_get_staging_dir (config);
       src_dir = ide_build_pipeline_get_srcdir (pipeline);
 
diff --git a/src/plugins/flatpak/gbp-flatpak-manifest.c b/src/plugins/flatpak/gbp-flatpak-manifest.c
new file mode 100644
index 000000000..ee4d2fe8c
--- /dev/null
+++ b/src/plugins/flatpak/gbp-flatpak-manifest.c
@@ -0,0 +1,645 @@
+/* gbp-flatpak-manifest.c
+ *
+ * Copyright © 2016 Matthew Leeds <mleeds redhat com>
+ * Copyright © 2018 Christian Hergert <chergert 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-manifest"
+
+#include <json-glib/json-glib.h>
+
+#include "gbp-flatpak-manifest.h"
+#include "gbp-flatpak-runtime.h"
+#include "gbp-flatpak-util.h"
+
+struct _GbpFlatpakManifest
+{
+  IdeConfiguration  parent_instance;
+
+  GFile            *file;
+
+  JsonNode         *root;
+
+  /* These are related to the toplevel object, which are project-wide
+   * configuration options.
+   */
+  gchar           **build_args;
+  gchar            *command;
+  gchar           **finish_args;
+  gchar            *runtime;
+  gchar            *runtime_version;
+  gchar            *sdk;
+  gchar            *sdk_version;
+  gchar           **sdk_extensions;
+
+  /*
+   * These are related to the primary module, which is the module that
+   * we believe that the user opened as the project.
+   */
+  JsonObject       *primary;
+  gchar            *primary_module;
+  gchar           **config_opts;
+};
+
+static void initable_iface_init (GInitableIface *iface);
+
+G_DEFINE_TYPE_WITH_CODE (GbpFlatpakManifest, gbp_flatpak_manifest, IDE_TYPE_CONFIGURATION,
+                         G_IMPLEMENT_INTERFACE (G_TYPE_INITABLE, initable_iface_init))
+
+enum {
+  PROP_0,
+  PROP_FILE,
+  N_PROPS
+};
+
+static GParamSpec *properties [N_PROPS];
+
+static gboolean
+validate_properties (GbpFlatpakManifest  *self,
+                     GError             **error)
+{
+  g_autofree gchar *runtime_id = NULL;
+  const gchar *name, *arch, *branch;
+
+  if (self->runtime == NULL ||
+      self->command == NULL ||
+      self->primary == NULL ||
+      self->primary_module == NULL)
+    {
+      g_set_error_literal (error,
+                           G_IO_ERROR,
+                           G_IO_ERROR_FAILED,
+                           "Does not appear to be a valid manifest");
+      return FALSE;
+    }
+
+  name = self->runtime;
+  arch = flatpak_get_default_arch ();
+  branch = "master";
+  if (self->runtime_version != NULL)
+    branch = self->runtime_version;
+
+  runtime_id = g_strdup_printf ("flatpak:%s/%s/%s", name, arch, branch);
+  ide_configuration_set_runtime_id (IDE_CONFIGURATION (self), runtime_id);
+
+  return TRUE;
+}
+
+static gboolean
+discover_string_field (JsonObject   *object,
+                       const gchar  *key,
+                       gchar       **location)
+{
+  JsonNode *node;
+
+  g_assert (key != NULL);
+  g_assert (location != NULL);
+
+  if (object != NULL &&
+      json_object_has_member (object, key) &&
+      (node = json_object_get_member (object, key)) &&
+      JSON_NODE_HOLDS_VALUE (node))
+    {
+      *location = g_strdup (json_node_get_string (node));
+      return TRUE;
+    }
+
+  *location = NULL;
+
+  return FALSE;
+}
+
+static gboolean
+discover_strv_field (JsonObject    *object,
+                     const gchar   *key,
+                     gchar       ***location)
+{
+  JsonNode *node;
+
+  g_assert (key != NULL);
+  g_assert (location != NULL);
+
+  if (object != NULL &&
+      json_object_has_member (object, key) &&
+      (node = json_object_get_member (object, key)) &&
+      JSON_NODE_HOLDS_ARRAY (node))
+    {
+      g_autoptr(GPtrArray) ar = g_ptr_array_new_with_free_func (g_free);
+      JsonArray *container = json_node_get_array (node);
+      guint n_elements = json_array_get_length (container);
+
+      for (guint i = 0; i < n_elements; i++)
+        {
+          const gchar *str = json_array_get_string_element (container, i);
+          g_ptr_array_add (ar, g_strdup (str));
+        }
+
+      g_ptr_array_add (ar, NULL);
+
+      *location = (gchar **)g_ptr_array_free (g_steal_pointer (&ar), FALSE);
+
+      return TRUE;
+    }
+
+  return FALSE;
+}
+
+static gboolean
+discover_strv_as_quoted (JsonObject   *object,
+                         const gchar  *key,
+                         gchar       **location)
+{
+  JsonNode *node;
+
+  g_assert (key != NULL);
+  g_assert (location != NULL);
+
+  if (object != NULL &&
+      json_object_has_member (object, key) &&
+      (node = json_object_get_member (object, key)) &&
+      JSON_NODE_HOLDS_ARRAY (node))
+    {
+      g_autoptr(GPtrArray) ar = g_ptr_array_new_with_free_func (g_free);
+      JsonArray *container = json_node_get_array (node);
+      guint n_elements = json_array_get_length (container);
+
+      for (guint i = 0; i < n_elements; i++)
+        {
+          const gchar *str = json_array_get_string_element (container, i);
+          g_ptr_array_add (ar, g_shell_quote (str));
+        }
+
+      g_ptr_array_add (ar, NULL);
+      *location = g_strjoinv (" ", (gchar **)(gpointer)ar->pdata);
+      return TRUE;
+    }
+
+  return FALSE;
+}
+
+static void
+discover_environ (GbpFlatpakManifest *self,
+                  JsonObject         *root)
+{
+  IdeEnvironment *env;
+  JsonObject *build_options;
+  JsonObject *obj;
+  const gchar *str;
+
+  g_assert (IDE_IS_CONFIGURATION (self));
+
+  if (!json_object_has_member (root, "build-options"))
+    return;
+
+  if (!(build_options = json_object_get_object_member (root, "build-options")))
+    return;
+
+  env = ide_configuration_get_environment (IDE_CONFIGURATION (self));
+
+  if ((obj = json_object_get_object_member (build_options, "env")))
+    {
+      JsonObjectIter iter;
+      const gchar *key;
+      JsonNode *value;
+
+      json_object_iter_init (&iter, obj);
+      while (json_object_iter_next (&iter, &key, &value))
+        {
+          if (JSON_NODE_HOLDS_VALUE (value))
+            ide_environment_setenv (env, key, json_node_get_string (value));
+        }
+    }
+
+  if (json_object_has_member (build_options, "cflags") &&
+      (str = json_object_get_string_member (build_options, "cflags")))
+    ide_environment_setenv (env, "CFLAGS", str);
+
+  if (json_object_has_member (build_options, "cxxflags") &&
+      (str = json_object_get_string_member (build_options, "cxxflags")))
+    ide_environment_setenv (env, "CXXFLAGS", str);
+
+  if (json_object_has_member (build_options, "append-path") &&
+      (str = json_object_get_string_member (build_options, "append-path")))
+    ide_configuration_set_append_path (IDE_CONFIGURATION (self), str);
+}
+
+static JsonObject *
+discover_primary_module (GbpFlatpakManifest  *self,
+                         JsonObject          *parent,
+                         const gchar         *dir_name,
+                         gboolean             is_root,
+                         GError             **error)
+{
+  JsonArray *ar;
+  JsonNode *modules;
+  guint n_elements;
+
+  g_assert (GBP_IS_FLATPAK_MANIFEST (self));
+  g_assert (parent != NULL);
+  g_assert (dir_name != NULL);
+
+  if (!json_object_has_member (parent, "modules") ||
+      !(modules = json_object_get_member (parent, "modules")) ||
+      !JSON_NODE_HOLDS_ARRAY (modules) ||
+      !(ar = json_node_get_array (modules)))
+    goto no_match;
+
+  n_elements = json_array_get_length (ar);
+
+  for (guint i = n_elements; i > 0; i--)
+    {
+      JsonNode *element = json_array_get_element (ar, i - 1);
+      const gchar *name;
+      JsonObject *obj;
+
+      if (!JSON_NODE_HOLDS_OBJECT (element) ||
+          !(obj = json_node_get_object (element)) ||
+          !(name = json_object_get_string_member (obj, "name")))
+        continue;
+
+      if (dzl_str_equal0 (name, dir_name))
+        {
+          self->primary_module = g_strdup (name);
+          return obj;
+        }
+
+      if (json_object_has_member (obj, "modules"))
+        {
+          JsonObject *subobj;
+
+          if ((subobj = discover_primary_module (self, obj, dir_name, FALSE, NULL)))
+            return subobj;
+        }
+    }
+
+  if (is_root)
+    {
+      for (guint i = n_elements; i > 0; i--)
+        {
+          JsonNode *element = json_array_get_element (ar, i - 1);
+          const gchar *name;
+          JsonObject *obj;
+
+          if (!JSON_NODE_HOLDS_OBJECT (element) ||
+              !(obj = json_node_get_object (element)) ||
+              !(name = json_object_get_string_member (obj, "name")))
+            continue;
+
+          self->primary_module = g_strdup (name);
+          return obj;
+        }
+    }
+
+no_match:
+  g_set_error_literal (error,
+                       G_IO_ERROR,
+                       G_IO_ERROR_FAILED,
+                       "Failed to locate primary module in modules");
+
+  return NULL;
+}
+
+static gboolean
+gbp_flatpak_manifest_initable_init (GInitable     *initable,
+                                    GCancellable  *cancellable,
+                                    GError       **error)
+{
+  GbpFlatpakManifest *self = (GbpFlatpakManifest *)initable;
+  g_autofree gchar *app_id = NULL;
+  g_autofree gchar *contents = NULL;
+  g_autofree gchar *dir_name = NULL;
+  g_autofree gchar *display_name = NULL;
+  g_autofree gchar *run_args = NULL;
+  g_autoptr(JsonParser) parser = NULL;
+  g_auto(GStrv) build_commands = NULL;
+  g_auto(GStrv) post_install = NULL;
+  IdeContext *context;
+  JsonObject *root_obj;
+  JsonObject *primary;
+  JsonNode *root;
+  IdeVcs *vcs;
+  GFile *workdir;
+  gsize len = 0;
+
+  g_assert (GBP_IS_FLATPAK_MANIFEST (self));
+  g_assert (G_IS_FILE (self->file));
+  g_assert (self->root == NULL);
+
+  if (!g_file_load_contents (self->file, cancellable, &contents, &len, NULL, error))
+    return FALSE;
+
+  parser = json_parser_new ();
+
+  if (!json_parser_load_from_data (parser, contents, len, error))
+    return FALSE;
+
+  root = json_parser_get_root (parser);
+
+  if (root == NULL || !JSON_NODE_HOLDS_OBJECT (root))
+    {
+      g_set_error (error,
+                   G_IO_ERROR,
+                   G_IO_ERROR_FAILED,
+                   "Root object is not an object");
+      return FALSE;
+    }
+
+  display_name = g_file_get_basename (self->file);
+  ide_configuration_set_display_name (IDE_CONFIGURATION (self), display_name);
+
+  context = ide_object_get_context (IDE_OBJECT (self));
+  vcs = ide_context_get_vcs (context);
+  workdir = ide_vcs_get_working_directory (vcs);
+  dir_name = g_file_get_basename (workdir);
+  root_obj = json_node_get_object (root);
+
+  if (!(primary = discover_primary_module (self, root_obj, dir_name, TRUE, error)))
+    return FALSE;
+
+  if (discover_string_field (root_obj, "app-id", &app_id))
+    ide_configuration_set_app_id (IDE_CONFIGURATION (self), app_id);
+
+  discover_string_field (root_obj, "runtime", &self->runtime);
+  discover_string_field (root_obj, "runtime-version", &self->runtime_version);
+  discover_string_field (root_obj, "sdk", &self->sdk);
+  discover_string_field (root_obj, "sdk-version", &self->sdk_version);
+  discover_string_field (root_obj, "command", &self->command);
+  discover_strv_field (root_obj, "build-args", &self->build_args);
+  discover_strv_field (root_obj, "finish-args", &self->finish_args);
+  discover_strv_field (root_obj, "sdk-extensions", &self->sdk_extensions);
+
+  if (discover_strv_as_quoted (root_obj, "x-run-args", &run_args))
+    ide_configuration_set_run_opts (IDE_CONFIGURATION (self), run_args);
+
+  if (discover_strv_field (primary, "config-opts", &self->config_opts))
+    {
+      g_autoptr(GString) gstr = g_string_new (NULL);
+
+      for (guint i = 0; self->config_opts[i]; i++)
+        {
+          const gchar *opt = self->config_opts[i];
+
+          if (i > 0)
+            g_string_append_c (gstr, ' ');
+
+          if (strchr (opt, '\'') || strchr (opt, '"'))
+            {
+              g_autofree gchar *quoted = g_shell_quote (opt);
+              g_string_append (gstr, quoted);
+            }
+          else
+            g_string_append (gstr, opt);
+        }
+
+      ide_configuration_set_config_opts (IDE_CONFIGURATION (self), gstr->str);
+    }
+
+  if (discover_strv_field (primary, "build-commands", &build_commands))
+    ide_configuration_set_build_commands (IDE_CONFIGURATION (self),
+                                          (const gchar * const *)build_commands);
+
+  if (discover_strv_field (primary, "post-install", &post_install))
+    ide_configuration_set_build_commands (IDE_CONFIGURATION (self),
+                                          (const gchar * const *)post_install);
+
+  if (json_object_has_member (primary, "builddir") &&
+      json_object_get_boolean_member (primary, "builddir"))
+    ide_configuration_set_locality (IDE_CONFIGURATION (self), IDE_BUILD_LOCALITY_OUT_OF_TREE);
+  else
+    ide_configuration_set_locality (IDE_CONFIGURATION (self), IDE_BUILD_LOCALITY_IN_TREE);
+
+  discover_environ (self, root_obj);
+
+  self->root = json_node_ref (root);
+  self->primary = json_object_ref (primary);
+
+  ide_configuration_set_dirty (IDE_CONFIGURATION (self), FALSE);
+
+  return validate_properties (self, error);
+}
+
+static void
+initable_iface_init (GInitableIface *iface)
+{
+  iface->init = gbp_flatpak_manifest_initable_init;
+}
+
+static gboolean
+gbp_flatpak_manifest_supports_runtime (IdeConfiguration *config,
+                                       IdeRuntime       *runtime)
+{
+  g_assert (GBP_IS_FLATPAK_MANIFEST (config));
+  g_assert (IDE_IS_RUNTIME (runtime));
+
+  return GBP_IS_FLATPAK_RUNTIME (runtime);
+}
+
+static void
+gbp_flatpak_manifest_finalize (GObject *object)
+{
+  GbpFlatpakManifest *self = (GbpFlatpakManifest *)object;
+
+  g_clear_object (&self->file);
+
+  g_clear_pointer (&self->root, json_node_unref);
+
+  g_clear_pointer (&self->build_args, g_strfreev);
+  g_clear_pointer (&self->command, g_free);
+  g_clear_pointer (&self->finish_args, g_strfreev);
+  g_clear_pointer (&self->runtime, g_free);
+  g_clear_pointer (&self->runtime_version, g_free);
+  g_clear_pointer (&self->sdk, g_free);
+  g_clear_pointer (&self->sdk_version, g_free);
+  g_clear_pointer (&self->sdk_extensions, g_strfreev);
+
+  g_clear_pointer (&self->primary, json_object_unref);
+  g_clear_pointer (&self->primary_module, g_free);
+  g_clear_pointer (&self->config_opts, g_strfreev);
+
+  G_OBJECT_CLASS (gbp_flatpak_manifest_parent_class)->finalize (object);
+}
+
+static void
+gbp_flatpak_manifest_get_property (GObject    *object,
+                                   guint       prop_id,
+                                   GValue     *value,
+                                   GParamSpec *pspec)
+{
+  GbpFlatpakManifest *self = GBP_FLATPAK_MANIFEST (object);
+
+  switch (prop_id)
+    {
+    case PROP_FILE:
+      g_value_set_object (value, gbp_flatpak_manifest_get_file (self));
+      break;
+
+    default:
+      G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
+    }
+}
+
+static void
+gbp_flatpak_manifest_set_property (GObject      *object,
+                                   guint         prop_id,
+                                   const GValue *value,
+                                   GParamSpec   *pspec)
+{
+  GbpFlatpakManifest *self = GBP_FLATPAK_MANIFEST (object);
+
+  switch (prop_id)
+    {
+    case PROP_FILE:
+      self->file = g_value_dup_object (value);
+      break;
+
+    default:
+      G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
+    }
+}
+
+static void
+gbp_flatpak_manifest_class_init (GbpFlatpakManifestClass *klass)
+{
+  GObjectClass *object_class = G_OBJECT_CLASS (klass);
+  IdeConfigurationClass *config_class = IDE_CONFIGURATION_CLASS (klass);
+
+  object_class->finalize = gbp_flatpak_manifest_finalize;
+  object_class->get_property = gbp_flatpak_manifest_get_property;
+  object_class->set_property = gbp_flatpak_manifest_set_property;
+
+  config_class->supports_runtime = gbp_flatpak_manifest_supports_runtime;
+
+  properties [PROP_FILE] =
+    g_param_spec_object ("file",
+                         "File",
+                         "The file containing the manifest",
+                         G_TYPE_FILE,
+                         G_PARAM_READWRITE | G_PARAM_CONSTRUCT_ONLY | G_PARAM_STATIC_STRINGS);
+
+  g_object_class_install_properties (object_class, N_PROPS, properties);
+}
+
+static void
+gbp_flatpak_manifest_init (GbpFlatpakManifest *self)
+{
+}
+
+GbpFlatpakManifest *
+gbp_flatpak_manifest_new (IdeContext  *context,
+                          GFile       *file,
+                          const gchar *id)
+{
+  return g_object_new (GBP_TYPE_FLATPAK_MANIFEST,
+                       "context", context,
+                       "id", id,
+                       "file", file,
+                       NULL);
+}
+
+/**
+ * gbp_flatpak_manifest_get_file:
+ *
+ * Gets the #GFile for the manifest.
+ *
+ * Returns: (transfer none): a #GFile
+ */
+GFile *
+gbp_flatpak_manifest_get_file (GbpFlatpakManifest *self)
+{
+  g_return_val_if_fail (GBP_IS_FLATPAK_MANIFEST (self), NULL);
+
+  return self->file;
+}
+
+/**
+ * gbp_flatpak_manifest_get_primary_module:
+ *
+ * Gets the name of the primary module, which is usually the last
+ * module of manifest.
+ */
+const gchar *
+gbp_flatpak_manifest_get_primary_module (GbpFlatpakManifest *self)
+{
+  g_return_val_if_fail (GBP_IS_FLATPAK_MANIFEST (self), NULL);
+
+  return self->primary_module;
+}
+
+/**
+ * gbp_flatpak_manifest_get_command:
+ *
+ * Gets the "command" specified in the manifest.
+ */
+const gchar *
+gbp_flatpak_manifest_get_command (GbpFlatpakManifest *self)
+{
+  g_return_val_if_fail (GBP_IS_FLATPAK_MANIFEST (self), NULL);
+
+  return self->command;
+}
+
+/**
+ * gbp_flatpak_manifest_get_build_args:
+ *
+ * Gets the "build-args" from the manifest as a string array.
+ */
+const gchar * const *
+gbp_flatpak_manifest_get_build_args (GbpFlatpakManifest *self)
+{
+  g_return_val_if_fail (GBP_IS_FLATPAK_MANIFEST (self), NULL);
+
+  return (const gchar * const *)self->build_args;
+}
+
+/**
+ * gbp_flatpak_manifest_get_finish_args:
+ *
+ * Gets the "finish-args" from the manifest as a string array.
+ */
+const gchar * const *
+gbp_flatpak_manifest_get_finish_args (GbpFlatpakManifest *self)
+{
+  g_return_val_if_fail (GBP_IS_FLATPAK_MANIFEST (self), NULL);
+
+  return (const gchar * const *)self->finish_args;
+}
+
+/**
+ * gbp_flatpak_manifest_get_sdk_extensions:
+ *
+ * Gets the "sdk-extensions" from the manifest as a string array.
+ */
+const gchar * const *
+gbp_flatpak_manifest_get_sdk_extensions (GbpFlatpakManifest *self)
+{
+  g_return_val_if_fail (GBP_IS_FLATPAK_MANIFEST (self), NULL);
+
+  return (const gchar * const *)self->sdk_extensions;
+}
+
+/**
+ * gbp_flatpak_manifest_get_path:
+ *
+ * Gets the path for the manifest. This is equivalent to calling
+ * g_file_get_path() with the result of gbp_flatpak_manifest_get_file().
+ */
+gchar *
+gbp_flatpak_manifest_get_path (GbpFlatpakManifest *self)
+{
+  g_return_val_if_fail (GBP_IS_FLATPAK_MANIFEST (self), NULL);
+
+  return g_file_get_path (self->file);
+}
diff --git a/src/plugins/flatpak/gbp-flatpak-manifest.h b/src/plugins/flatpak/gbp-flatpak-manifest.h
new file mode 100644
index 000000000..6b5326dc0
--- /dev/null
+++ b/src/plugins/flatpak/gbp-flatpak-manifest.h
@@ -0,0 +1,49 @@
+/* gbp-flatpak-manifest.h
+ *
+ * Copyright © 2016 Matthew Leeds <mleeds redhat com>
+ * Copyright © 2018 Christian Hergert <chergert 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/>.
+ */
+
+#pragma once
+
+#include <ide.h>
+
+G_BEGIN_DECLS
+
+#define GBP_TYPE_FLATPAK_MANIFEST (gbp_flatpak_manifest_get_type())
+
+G_DECLARE_FINAL_TYPE (GbpFlatpakManifest, gbp_flatpak_manifest, GBP, FLATPAK_MANIFEST, IdeConfiguration)
+
+GbpFlatpakManifest  *gbp_flatpak_manifest_new                (IdeContext           *context,
+                                                              GFile                *file,
+                                                              const gchar          *id);
+GFile               *gbp_flatpak_manifest_get_file           (GbpFlatpakManifest   *self);
+const gchar         *gbp_flatpak_manifest_get_primary_module (GbpFlatpakManifest   *self);
+const gchar         *gbp_flatpak_manifest_get_command        (GbpFlatpakManifest   *self);
+gchar               *gbp_flatpak_manifest_get_path           (GbpFlatpakManifest   *self);
+const gchar * const *gbp_flatpak_manifest_get_build_args     (GbpFlatpakManifest   *self);
+const gchar * const *gbp_flatpak_manifest_get_finish_args    (GbpFlatpakManifest   *self);
+const gchar * const *gbp_flatpak_manifest_get_sdk_extensions (GbpFlatpakManifest   *self);
+void                 gbp_flatpak_manifest_save_async         (GbpFlatpakManifest   *self,
+                                                              GCancellable         *cancellable,
+                                                              GAsyncReadyCallback   callback,
+                                                              gpointer              user_data);
+gboolean             gbp_flatpak_manifest_save_finish        (GbpFlatpakManifest   *self,
+                                                              GAsyncResult         *result,
+                                                              GError              **error);
+
+
+G_END_DECLS
diff --git a/src/plugins/flatpak/gbp-flatpak-pipeline-addin.c 
b/src/plugins/flatpak/gbp-flatpak-pipeline-addin.c
index ef6f69338..d8a286468 100644
--- a/src/plugins/flatpak/gbp-flatpak-pipeline-addin.c
+++ b/src/plugins/flatpak/gbp-flatpak-pipeline-addin.c
@@ -20,7 +20,7 @@
 
 #include <glib/gi18n.h>
 
-#include "gbp-flatpak-configuration.h"
+#include "gbp-flatpak-manifest.h"
 #include "gbp-flatpak-download-stage.h"
 #include "gbp-flatpak-pipeline-addin.h"
 #include "gbp-flatpak-runtime.h"
@@ -320,11 +320,11 @@ register_dependencies_stage (GbpFlatpakPipelineAddin  *self,
   /* If there is no manifest, then there are no dependencies
    * to build for this configuration.
    */
-  if (!GBP_IS_FLATPAK_CONFIGURATION (config))
+  if (!GBP_IS_FLATPAK_MANIFEST (config))
     return TRUE;
 
-  primary_module = gbp_flatpak_configuration_get_primary_module (GBP_FLATPAK_CONFIGURATION (config));
-  manifest_path = gbp_flatpak_configuration_get_manifest_path (GBP_FLATPAK_CONFIGURATION (config));
+  primary_module = gbp_flatpak_manifest_get_primary_module (GBP_FLATPAK_MANIFEST (config));
+  manifest_path = gbp_flatpak_manifest_get_path (GBP_FLATPAK_MANIFEST (config));
 
   staging_dir = gbp_flatpak_get_staging_dir (config);
   src_dir = ide_build_pipeline_get_srcdir (pipeline);
@@ -392,11 +392,11 @@ register_build_finish_stage (GbpFlatpakPipelineAddin  *self,
   g_assert (IDE_IS_CONTEXT (context));
 
   config = ide_build_pipeline_get_configuration (pipeline);
-  if (!GBP_IS_FLATPAK_CONFIGURATION (config))
+  if (!GBP_IS_FLATPAK_MANIFEST (config))
     return TRUE;
 
-  command = gbp_flatpak_configuration_get_command (GBP_FLATPAK_CONFIGURATION (config));
-  finish_args = gbp_flatpak_configuration_get_finish_args (GBP_FLATPAK_CONFIGURATION (config));
+  command = gbp_flatpak_manifest_get_command (GBP_FLATPAK_MANIFEST (config));
+  finish_args = gbp_flatpak_manifest_get_finish_args (GBP_FLATPAK_MANIFEST (config));
   staging_dir = gbp_flatpak_get_staging_dir (config);
 
   launcher = create_subprocess_launcher ();
@@ -443,7 +443,7 @@ register_build_export_stage (GbpFlatpakPipelineAddin  *self,
   g_assert (IDE_IS_CONTEXT (context));
 
   config = ide_build_pipeline_get_configuration (pipeline);
-  if (!GBP_IS_FLATPAK_CONFIGURATION (config))
+  if (!GBP_IS_FLATPAK_MANIFEST (config))
     return TRUE;
 
   staging_dir = gbp_flatpak_get_staging_dir (config);
@@ -515,7 +515,7 @@ register_build_bundle_stage (GbpFlatpakPipelineAddin  *self,
   g_assert (IDE_IS_CONTEXT (context));
 
   config = ide_build_pipeline_get_configuration (pipeline);
-  if (!GBP_IS_FLATPAK_CONFIGURATION (config))
+  if (!GBP_IS_FLATPAK_MANIFEST (config))
     return TRUE;
 
   staging_dir = gbp_flatpak_get_staging_dir (config);
diff --git a/src/plugins/flatpak/gbp-flatpak-runner.c b/src/plugins/flatpak/gbp-flatpak-runner.c
index 0dfba660a..652d48b1e 100644
--- a/src/plugins/flatpak/gbp-flatpak-runner.c
+++ b/src/plugins/flatpak/gbp-flatpak-runner.c
@@ -23,8 +23,8 @@
 #include <glib/gi18n.h>
 #include <unistd.h>
 
+#include "gbp-flatpak-manifest.h"
 #include "gbp-flatpak-runner.h"
-#include "gbp-flatpak-configuration.h"
 #include "gbp-flatpak-util.h"
 
 struct _GbpFlatpakRunner
@@ -70,7 +70,7 @@ gbp_flatpak_runner_fixup_launcher (IdeRunner             *runner,
   ide_subprocess_launcher_insert_argv (launcher, i++, "--with-appdir");
   ide_subprocess_launcher_insert_argv (launcher, i++, "--allow=devel");
 
-  if (GBP_IS_FLATPAK_CONFIGURATION (config))
+  if (GBP_IS_FLATPAK_MANIFEST (config))
     {
       const gchar * const *finish_args;
 
@@ -82,7 +82,7 @@ gbp_flatpak_runner_fixup_launcher (IdeRunner             *runner,
        * all the finish-args we know about.
        */
 
-      finish_args = gbp_flatpak_configuration_get_finish_args (GBP_FLATPAK_CONFIGURATION (config));
+      finish_args = gbp_flatpak_manifest_get_finish_args (GBP_FLATPAK_MANIFEST (config));
 
       if (finish_args != NULL)
         {
diff --git a/src/plugins/flatpak/gbp-flatpak-runtime-provider.c 
b/src/plugins/flatpak/gbp-flatpak-runtime-provider.c
index da2e74a23..9cb792eb8 100644
--- a/src/plugins/flatpak/gbp-flatpak-runtime-provider.c
+++ b/src/plugins/flatpak/gbp-flatpak-runtime-provider.c
@@ -25,7 +25,7 @@
 #include "util/ide-posix.h"
 
 #include "gbp-flatpak-application-addin.h"
-#include "gbp-flatpak-configuration.h"
+#include "gbp-flatpak-manifest.h"
 #include "gbp-flatpak-runtime.h"
 #include "gbp-flatpak-runtime-provider.h"
 #include "gbp-flatpak-transfer.h"
@@ -565,7 +565,7 @@ gbp_flatpak_runtime_provider_bootstrap_async (IdeRuntimeProvider  *provider,
   count = g_new0 (guint, 1);
   g_task_set_task_data (task, count, g_free);
 
-  if (GBP_IS_FLATPAK_CONFIGURATION (configuration))
+  if (GBP_IS_FLATPAK_MANIFEST (configuration))
     {
       GbpFlatpakApplicationAddin *addin = gbp_flatpak_application_addin_get_default ();
       const gchar * const *sdk_exts;
@@ -576,7 +576,7 @@ gbp_flatpak_runtime_provider_bootstrap_async (IdeRuntimeProvider  *provider,
        *       we'll have to be more careful about arch support here.
        */
 
-      sdk_exts = gbp_flatpak_configuration_get_sdk_extensions (GBP_FLATPAK_CONFIGURATION (configuration));
+      sdk_exts = gbp_flatpak_manifest_get_sdk_extensions (GBP_FLATPAK_MANIFEST (configuration));
 
       if (sdk_exts != NULL)
         {
diff --git a/src/plugins/flatpak/gbp-flatpak-runtime.c b/src/plugins/flatpak/gbp-flatpak-runtime.c
index 81488550c..5a86f03a9 100644
--- a/src/plugins/flatpak/gbp-flatpak-runtime.c
+++ b/src/plugins/flatpak/gbp-flatpak-runtime.c
@@ -23,7 +23,7 @@
 #include <json-glib/json-glib.h>
 
 #include "gbp-flatpak-application-addin.h"
-#include "gbp-flatpak-configuration.h"
+#include "gbp-flatpak-manifest.h"
 #include "gbp-flatpak-runner.h"
 #include "gbp-flatpak-runtime.h"
 #include "gbp-flatpak-subprocess-launcher.h"
@@ -175,8 +175,8 @@ gbp_flatpak_runtime_create_launcher (IdeRuntime  *runtime,
       ide_subprocess_launcher_push_argv (ret, "flatpak");
       ide_subprocess_launcher_push_argv (ret, "build");
 
-      if (GBP_IS_FLATPAK_CONFIGURATION (configuration))
-        build_args = gbp_flatpak_configuration_get_build_args (GBP_FLATPAK_CONFIGURATION (configuration));
+      if (GBP_IS_FLATPAK_MANIFEST (configuration))
+        build_args = gbp_flatpak_manifest_get_build_args (GBP_FLATPAK_MANIFEST (configuration));
 
       if (build_args != NULL)
         ide_subprocess_launcher_push_args (ret, build_args);
@@ -244,11 +244,11 @@ get_binary_name (GbpFlatpakRuntime *self,
   IdeConfigurationManager *config_manager = ide_context_get_configuration_manager (context);
   IdeConfiguration *config = ide_configuration_manager_get_current (config_manager);
 
-  if (GBP_IS_FLATPAK_CONFIGURATION (config))
+  if (GBP_IS_FLATPAK_MANIFEST (config))
     {
       const gchar *command;
 
-      command = gbp_flatpak_configuration_get_command (GBP_FLATPAK_CONFIGURATION (config));
+      command = gbp_flatpak_manifest_get_command (GBP_FLATPAK_MANIFEST (config));
       if (!dzl_str_empty0 (command))
         return g_strdup (command);
     }
diff --git a/src/plugins/flatpak/meson.build b/src/plugins/flatpak/meson.build
index c8a6f4dfc..657f7939b 100644
--- a/src/plugins/flatpak/meson.build
+++ b/src/plugins/flatpak/meson.build
@@ -17,8 +17,6 @@ flatpak_sources = [
   'gbp-flatpak-build-target-provider.h',
   'gbp-flatpak-clone-widget.c',
   'gbp-flatpak-clone-widget.h',
-  'gbp-flatpak-configuration.c',
-  'gbp-flatpak-configuration.h',
   'gbp-flatpak-configuration-provider.c',
   'gbp-flatpak-configuration-provider.h',
   'gbp-flatpak-dependency-updater.c',
@@ -27,6 +25,8 @@ flatpak_sources = [
   'gbp-flatpak-download-stage.h',
   'gbp-flatpak-genesis-addin.c',
   'gbp-flatpak-genesis-addin.h',
+  'gbp-flatpak-manifest.c',
+  'gbp-flatpak-manifest.h',
   'gbp-flatpak-pipeline-addin.c',
   'gbp-flatpak-pipeline-addin.h',
   'gbp-flatpak-preferences-addin.c',


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