Commit 8125e9f5 authored by Matthew Leeds's avatar Matthew Leeds
Browse files

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
parent 727b747e
......@@ -970,6 +970,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)
{
......
......@@ -73,6 +73,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);
......
......@@ -14,21 +14,28 @@ libflatpak_plugin_la_SOURCES = \
gbp-flatpak-application-addin.h \
gbp-flatpak-clone-widget.c \
gbp-flatpak-clone-widget.h \
gbp-flatpak-configuration-provider.c \
gbp-flatpak-configuration-provider.h \
gbp-flatpak-genesis-addin.c \
gbp-flatpak-genesis-addin.h \
gbp-flatpak-pipeline-addin.c \
gbp-flatpak-pipeline-addin.h \
gbp-flatpak-plugin.c \
gbp-flatpak-plugin.c \
gbp-flatpak-runner.c \
gbp-flatpak-runner.c \
gbp-flatpak-runner.h \
gbp-flatpak-runner.h \
gbp-flatpak-runtime-provider.c \
gbp-flatpak-runtime-provider.h \
gbp-flatpak-runtime.c \
gbp-flatpak-runtime.c \
gbp-flatpak-runtime.h \
gbp-flatpak-runtime.h \
gbp-flatpak-sources.c \
gbp-flatpak-sources.h \
gbp-flatpak-subprocess-launcher.c \
gbp-flatpak-subprocess-launcher.h \
gbp-flatpak-subprocess-launcher.c \
gbp-flatpak-transfer.c \
gbp-flatpak-transfer.h \
gbp-flatpak-util.c \
......
This diff is collapsed.
/* 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 */
......@@ -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);
......
......@@ -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)
{
......
......@@ -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
};
......@@ -147,14 +142,23 @@ 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_staging_directory (self);
builddir = get_builddir (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;
......@@ -184,7 +188,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)
{
......@@ -274,7 +277,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;
......@@ -288,124 +290,24 @@ 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);
}
static void
gbp_flatpak_runtime_prepare_configuration (IdeRuntime *runtime,
IdeConfiguration *configuration)
{
GbpFlatpakRuntime* self = (GbpFlatpakRuntime *)runtime;
g_autofree gchar *manifest_path = NULL;
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);
}
if (self->manifest != NULL)
manifest_path = g_file_get_path (self->manifest);
ide_configuration_set_prefix (configuration, "/app");