[gnome-builder] plugin: deviced: Add run button support
- From: Christian Hergert <chergert src gnome org>
- To: commits-list gnome org
- Cc:
- Subject: [gnome-builder] plugin: deviced: Add run button support
- Date: Thu, 5 Aug 2021 22:25:37 +0000 (UTC)
commit f341f6d384de400c0e25fb6ac1fe81dc0cdc3fd5
Author: James Westman <james jwestman net>
Date: Tue Jul 20 16:55:29 2021 -0500
plugin: deviced: Add run button support
When a deviced device is selected, clicking Run will now run the app on
the device.
Modified IdeDeployStrategy to be able to create a runner for the device,
and modified IdeRunManager to override the runtime's runner with one for
the device, if necessary.
There are a number of things that could be improved--the project is
reinstalled every time you click Run, and transferring flatpak commits
by delta is not supported--but it works well enough to use.
src/libide/foundry/ide-deploy-strategy.c | 100 +++++
src/libide/foundry/ide-deploy-strategy.h | 19 +
src/libide/foundry/ide-device-manager.c | 209 ++++++++++-
src/libide/foundry/ide-device-manager.h | 10 +
src/libide/foundry/ide-run-manager.c | 122 +++++-
src/plugins/deviced/gbp-deviced-deploy-strategy.c | 53 ++-
src/plugins/deviced/gbp-deviced-device.c | 6 +-
src/plugins/deviced/gbp-deviced-device.h | 7 +
src/plugins/deviced/gbp-deviced-runner.c | 435 ++++++++++++++++++++++
src/plugins/deviced/gbp-deviced-runner.h | 39 ++
src/plugins/deviced/meson.build | 1 +
11 files changed, 984 insertions(+), 17 deletions(-)
---
diff --git a/src/libide/foundry/ide-deploy-strategy.c b/src/libide/foundry/ide-deploy-strategy.c
index 404c3cfbb..bc0a976c8 100644
--- a/src/libide/foundry/ide-deploy-strategy.c
+++ b/src/libide/foundry/ide-deploy-strategy.c
@@ -84,6 +84,39 @@ ide_deploy_strategy_real_deploy_finish (IdeDeployStrategy *self,
return g_task_propagate_boolean (G_TASK (result), error);
}
+static void
+ide_deploy_strategy_real_create_runner_async (IdeDeployStrategy *self,
+ IdePipeline *pipeline,
+ GCancellable *cancellable,
+ GAsyncReadyCallback callback,
+ gpointer user_data)
+{
+ g_autoptr(IdeTask) task = NULL;
+
+ g_return_if_fail (IDE_IS_DEPLOY_STRATEGY (self));
+ g_return_if_fail (IDE_IS_PIPELINE (pipeline));
+ g_return_if_fail (!cancellable || G_IS_CANCELLABLE (cancellable));
+
+ task = ide_task_new (self, cancellable, callback, user_data);
+ ide_task_return_new_error (task,
+ G_IO_ERROR,
+ G_IO_ERROR_NOT_SUPPORTED,
+ "Not supported");
+
+}
+
+static IdeRunner *
+ide_deploy_strategy_real_create_runner_finish (IdeDeployStrategy *self,
+ GAsyncResult *result,
+ GError **error)
+{
+ g_assert (IDE_IS_DEPLOY_STRATEGY (self));
+ g_assert (IDE_IS_TASK (result));
+ g_assert (ide_task_is_valid (G_TASK (result), self));
+
+ return g_task_propagate_pointer (G_TASK (result), error);
+}
+
static void
ide_deploy_strategy_class_init (IdeDeployStrategyClass *klass)
{
@@ -91,6 +124,8 @@ ide_deploy_strategy_class_init (IdeDeployStrategyClass *klass)
klass->load_finish = ide_deploy_strategy_real_load_finish;
klass->deploy_async = ide_deploy_strategy_real_deploy_async;
klass->deploy_finish = ide_deploy_strategy_real_deploy_finish;
+ klass->create_runner_async = ide_deploy_strategy_real_create_runner_async;
+ klass->create_runner_finish = ide_deploy_strategy_real_create_runner_finish;
}
static void
@@ -244,3 +279,68 @@ ide_deploy_strategy_deploy_finish (IdeDeployStrategy *self,
IDE_RETURN (ret);
}
+
+/**
+ * ide_deploy_strategy_create_runner_async:
+ * @self: a #IdeDeployStrategy
+ * @pipeline: an #IdePipeline
+ * @cancellable: (nullable): a #GCancellable or %NULL
+ * @callback: (closure user_data): a callback to execute upon completion
+ * @user_data: closure data for @callback
+ *
+ * Gets an #IdeRunner that runs apps deployed to the device, if a
+ * runner other than the default is needed.
+ *
+ * Since: 41
+ */
+void
+ide_deploy_strategy_create_runner_async (IdeDeployStrategy *self,
+ IdePipeline *pipeline,
+ GCancellable *cancellable,
+ GAsyncReadyCallback callback,
+ gpointer user_data)
+{
+ IDE_ENTRY;
+
+ g_assert (IDE_IS_DEPLOY_STRATEGY (self));
+ g_assert (IDE_IS_PIPELINE (pipeline));
+ g_assert (!cancellable || G_IS_CANCELLABLE (cancellable));
+
+ IDE_DEPLOY_STRATEGY_GET_CLASS (self)->create_runner_async (self,
+ pipeline,
+ cancellable,
+ callback,
+ user_data);
+
+ IDE_EXIT;
+}
+
+/**
+ * ide_deploy_strategy_create_runner_finish:
+ * @self: an #IdeDeployStrategy
+ * @result: a #GAsyncResult provided to callback
+ * @error: a location for a #GError, or %NULL
+ *
+ * Completes an asynchronous request to get an #IdeRunner for the current
+ * device.
+ *
+ * Returns: (transfer full): An #IdeRunner or %NULL
+ *
+ * Since: 41
+ */
+IdeRunner *
+ide_deploy_strategy_create_runner_finish (IdeDeployStrategy *self,
+ GAsyncResult *result,
+ GError **error)
+{
+ IdeRunner *ret;
+
+ IDE_ENTRY;
+
+ g_assert (IDE_IS_DEPLOY_STRATEGY (self));
+ g_assert (G_IS_ASYNC_RESULT (result));
+
+ ret = IDE_DEPLOY_STRATEGY_GET_CLASS (self)->create_runner_finish (self, result, error);
+
+ IDE_RETURN (ret);
+}
diff --git a/src/libide/foundry/ide-deploy-strategy.h b/src/libide/foundry/ide-deploy-strategy.h
index 94796d7d4..ccede7f87 100644
--- a/src/libide/foundry/ide-deploy-strategy.h
+++ b/src/libide/foundry/ide-deploy-strategy.h
@@ -25,6 +25,7 @@
#endif
#include <libide-core.h>
+#include "ide-foundry-types.h"
G_BEGIN_DECLS
@@ -56,6 +57,14 @@ struct _IdeDeployStrategyClass
gboolean (*deploy_finish) (IdeDeployStrategy *self,
GAsyncResult *result,
GError **error);
+ void (*create_runner_async) (IdeDeployStrategy *self,
+ IdePipeline *pipeline,
+ GCancellable *cancellable,
+ GAsyncReadyCallback callback,
+ gpointer user_data);
+ IdeRunner *(*create_runner_finish) (IdeDeployStrategy *self,
+ GAsyncResult *result,
+ GError **error);
gpointer _reserved[16];
};
@@ -83,5 +92,15 @@ IDE_AVAILABLE_IN_3_32
gboolean ide_deploy_strategy_deploy_finish (IdeDeployStrategy *self,
GAsyncResult *result,
GError **error);
+IDE_AVAILABLE_IN_41
+void ide_deploy_strategy_create_runner_async (IdeDeployStrategy *self,
+ IdePipeline *pipeline,
+ GCancellable *cancellable,
+ GAsyncReadyCallback callback,
+ gpointer user_data);
+IDE_AVAILABLE_IN_41
+IdeRunner *ide_deploy_strategy_create_runner_finish (IdeDeployStrategy *self,
+ GAsyncResult *result,
+ GError **error);
G_END_DECLS
diff --git a/src/libide/foundry/ide-device-manager.c b/src/libide/foundry/ide-device-manager.c
index 82fc56af7..2f920bdc7 100644
--- a/src/libide/foundry/ide-device-manager.c
+++ b/src/libide/foundry/ide-device-manager.c
@@ -789,8 +789,6 @@ ide_device_manager_deploy_cb (GObject *object,
else
ide_task_return_boolean (task, TRUE);
- ide_object_destroy (IDE_OBJECT (strategy));
-
IDE_EXIT;
}
@@ -1005,6 +1003,213 @@ ide_device_manager_deploy_finish (IdeDeviceManager *self,
IDE_RETURN (ret);
}
+static void
+ide_device_manager_create_runner_cb (GObject *object,
+ GAsyncResult *result,
+ gpointer user_data)
+{
+ IdeDeployStrategy *strategy = (IdeDeployStrategy *)object;
+ g_autoptr(GError) error = NULL;
+ g_autoptr(IdeTask) task = user_data;
+ IdeRunner *runner;
+
+ IDE_ENTRY;
+
+ g_assert (IDE_IS_DEPLOY_STRATEGY (strategy));
+ g_assert (G_IS_ASYNC_RESULT (result));
+ g_assert (IDE_IS_TASK (task));
+
+ runner = ide_deploy_strategy_create_runner_finish (strategy, result, &error);
+
+ if (error)
+ ide_task_return_error (task, g_steal_pointer (&error));
+ else
+ ide_task_return_pointer (task, runner, g_object_unref);
+
+ ide_object_destroy (IDE_OBJECT (strategy));
+
+ IDE_EXIT;
+}
+
+static void
+ide_device_manager_create_runner_load_cb (GObject *object,
+ GAsyncResult *result,
+ gpointer user_data)
+{
+ IdeDeployStrategy *strategy = (IdeDeployStrategy *)object;
+ g_autoptr(GError) error = NULL;
+ g_autoptr(IdeTask) task = user_data;
+ IdeDeviceManager *self;
+ DeployState *state;
+
+ IDE_ENTRY;
+
+ g_assert (IDE_IS_DEPLOY_STRATEGY (strategy));
+ g_assert (G_IS_ASYNC_RESULT (result));
+ g_assert (IDE_IS_TASK (task));
+
+ if (!ide_deploy_strategy_load_finish (strategy, result, &error))
+ {
+ g_debug ("Deploy strategy failed to load: %s", error->message);
+ ide_object_destroy (IDE_OBJECT (strategy));
+ ide_device_manager_deploy_tick (task);
+ IDE_EXIT;
+ }
+
+ /* Okay, we found a match. Now run on the device. */
+
+ self = ide_task_get_source_object (task);
+ state = ide_task_get_task_data (task);
+
+ g_assert (IDE_IS_DEVICE_MANAGER (self));
+ g_assert (state != NULL);
+ g_assert (state->strategies != NULL);
+ g_assert (IDE_IS_PIPELINE (state->pipeline));
+
+ ide_deploy_strategy_create_runner_async (strategy,
+ state->pipeline,
+ ide_task_get_cancellable (task),
+ ide_device_manager_create_runner_cb,
+ g_object_ref (task));
+
+ IDE_EXIT;
+}
+
+static void
+ide_device_manager_create_runner_tick (IdeTask *task)
+{
+ g_autoptr(IdeDeployStrategy) strategy = NULL;
+ DeployState *state;
+
+ IDE_ENTRY;
+
+ g_assert (IDE_IS_TASK (task));
+
+ state = ide_task_get_task_data (task);
+
+ g_assert (state != NULL);
+ g_assert (state->strategies != NULL);
+ g_assert (IDE_IS_PIPELINE (state->pipeline));
+
+ if (state->strategies->len == 0)
+ {
+ ide_task_return_new_error (task,
+ G_IO_ERROR,
+ G_IO_ERROR_NOT_SUPPORTED,
+ "Failed to locate deployment strategy for device");
+ IDE_EXIT;
+ }
+
+ strategy = ide_object_array_steal_index (state->strategies, 0);
+
+ ide_deploy_strategy_load_async (strategy,
+ state->pipeline,
+ ide_task_get_cancellable (task),
+ ide_device_manager_create_runner_load_cb,
+ g_object_ref (task));
+
+ IDE_EXIT;
+}
+
+/**
+ * ide_device_manager_create_runner_async:
+ * @self: a #IdeDeviceManager
+ * @pipeline: an #IdePipeline
+ * @cancellable: a #GCancellable, or %NULL
+ * @callback: a #GAsyncReadyCallback
+ * @user_data: closure data for @callback
+ *
+ * Requests an #IdeRunner that runs on the current device, if a runner
+ * other than the default is required.
+ *
+ * Since: 41
+ */
+void
+ide_device_manager_create_runner_async (IdeDeviceManager *self,
+ IdePipeline *pipeline,
+ GCancellable *cancellable,
+ GAsyncReadyCallback callback,
+ gpointer user_data)
+{
+ g_autoptr(PeasExtensionSet) set = NULL;
+ g_autoptr(IdeTask) task = NULL;
+ DeployState *state;
+ IdeDevice *device;
+
+ IDE_ENTRY;
+
+ g_return_if_fail (IDE_IS_DEVICE_MANAGER (self));
+ g_return_if_fail (IDE_IS_PIPELINE (pipeline));
+ g_return_if_fail (!cancellable || G_IS_CANCELLABLE (cancellable));
+
+ task = ide_task_new (self, cancellable, callback, user_data);
+ ide_task_set_source_tag (task, ide_device_manager_create_runner_async);
+
+ if (!(device = ide_pipeline_get_device (pipeline)))
+ {
+ ide_task_return_new_error (task,
+ G_IO_ERROR,
+ G_IO_ERROR_FAILED,
+ "Missing device in pipeline");
+ IDE_EXIT;
+ }
+
+ if (IDE_IS_LOCAL_DEVICE (device))
+ {
+ (ide_task_return_pointer) (task, NULL, NULL);
+ IDE_EXIT;
+ }
+
+ state = g_slice_new0 (DeployState);
+ state->pipeline = g_object_ref (pipeline);
+ state->strategies = ide_object_array_new ();
+ ide_task_set_task_data (task, state, deploy_state_free);
+
+ set = peas_extension_set_new (peas_engine_get_default (),
+ IDE_TYPE_DEPLOY_STRATEGY,
+ NULL);
+ peas_extension_set_foreach (set, collect_strategies, state->strategies);
+
+ /* Root the addins as children of us so that they get context access */
+ for (guint i = 0; i < state->strategies->len; i++)
+ ide_object_append (IDE_OBJECT (self),
+ ide_object_array_index (state->strategies, i));
+
+ ide_device_manager_create_runner_tick (task);
+
+ IDE_EXIT;
+}
+
+/**
+ * ide_device_manager_create_runner_finish:
+ * @self: a #IdeDeviceManager
+ * @result: a #GAsyncResult provided to callback
+ * @error: a location for a #GError, or %NULL
+ *
+ * Completes a request to create an #IdeRunner to run on the device.
+ *
+ * Returns: (transfer full): An #IdeRunner or %NULL.
+ *
+ * Since: 41
+ */
+IdeRunner *
+ide_device_manager_create_runner_finish (IdeDeviceManager *self,
+ GAsyncResult *result,
+ GError **error)
+{
+ IdeRunner *ret;
+
+ IDE_ENTRY;
+
+ g_return_val_if_fail (IDE_IS_DEVICE_MANAGER (self), FALSE);
+ g_return_val_if_fail (IDE_IS_TASK (result), FALSE);
+ g_return_val_if_fail (ide_task_is_valid (IDE_TASK (result), self), FALSE);
+
+ ret = ide_task_propagate_pointer (IDE_TASK (result), error);
+
+ IDE_RETURN (ret);
+}
+
gdouble
ide_device_manager_get_progress (IdeDeviceManager *self)
{
diff --git a/src/libide/foundry/ide-device-manager.h b/src/libide/foundry/ide-device-manager.h
index 690757a44..1e8f1ee20 100644
--- a/src/libide/foundry/ide-device-manager.h
+++ b/src/libide/foundry/ide-device-manager.h
@@ -57,5 +57,15 @@ IDE_AVAILABLE_IN_3_32
gboolean ide_device_manager_deploy_finish (IdeDeviceManager *self,
GAsyncResult *result,
GError **error);
+IDE_AVAILABLE_IN_41
+void ide_device_manager_create_runner_async (IdeDeviceManager *self,
+ IdePipeline *pipeline,
+ GCancellable *cancellable,
+ GAsyncReadyCallback callback,
+ gpointer user_data);
+IDE_AVAILABLE_IN_41
+IdeRunner *ide_device_manager_create_runner_finish (IdeDeviceManager *self,
+ GAsyncResult *result,
+ GError **error);
G_END_DECLS
diff --git a/src/libide/foundry/ide-run-manager.c b/src/libide/foundry/ide-run-manager.c
index 7bae4f4a2..af4f71fca 100644
--- a/src/libide/foundry/ide-run-manager.c
+++ b/src/libide/foundry/ide-run-manager.c
@@ -36,6 +36,7 @@
#include "ide-build-target.h"
#include "ide-config-manager.h"
#include "ide-config.h"
+#include "ide-device-manager.h"
#include "ide-foundry-compat.h"
#include "ide-run-manager-private.h"
#include "ide-run-manager.h"
@@ -466,9 +467,14 @@ copy_builtin_envvars (IdeEnvironment *environment)
}
static void
-do_run_async (IdeRunManager *self,
- IdeTask *task)
+create_runner_cb (GObject *object,
+ GAsyncResult *result,
+ gpointer user_data)
{
+ IdeRunManager *self;
+ IdeDeviceManager *device_manager = (IDE_DEVICE_MANAGER (object));
+ g_autoptr(IdeTask) task = user_data;
+ g_autoptr(GError) error = NULL;
g_autofree gchar *name = NULL;
g_autofree gchar *title = NULL;
IdeBuildTarget *build_target;
@@ -483,9 +489,21 @@ do_run_async (IdeRunManager *self,
IDE_ENTRY;
- g_assert (IDE_IS_RUN_MANAGER (self));
+ g_assert (IDE_IS_DEVICE_MANAGER (device_manager));
+ g_assert (G_IS_ASYNC_RESULT (result));
g_assert (IDE_IS_TASK (task));
+ self = ide_task_get_source_object (task);
+ g_assert (IDE_IS_RUN_MANAGER (self));
+
+ runner = ide_device_manager_create_runner_finish (device_manager, result, &error);
+
+ if (error != NULL)
+ {
+ ide_task_return_error (task, g_steal_pointer (&error));
+ IDE_EXIT;
+ }
+
build_target = ide_task_get_task_data (task);
context = ide_object_get_context (IDE_OBJECT (self));
@@ -496,18 +514,22 @@ do_run_async (IdeRunManager *self,
config = ide_config_manager_get_current (config_manager);
runtime = ide_config_get_runtime (config);
- if (runtime == NULL)
+ if (runner == NULL)
{
- ide_task_return_new_error (task,
- IDE_RUNTIME_ERROR,
- IDE_RUNTIME_ERROR_NO_SUCH_RUNTIME,
- "%s ā%sā",
- _("Failed to locate runtime"),
- ide_config_get_runtime_id (config));
- IDE_EXIT;
+ if (runtime == NULL)
+ {
+ ide_task_return_new_error (task,
+ IDE_RUNTIME_ERROR,
+ IDE_RUNTIME_ERROR_NO_SUCH_RUNTIME,
+ "%s ā%sā",
+ _("Failed to locate runtime"),
+ ide_config_get_runtime_id (config));
+ IDE_EXIT;
+ }
+
+ runner = ide_runtime_create_runner (runtime, build_target);
}
- runner = ide_runtime_create_runner (runtime, build_target);
cancellable = ide_task_get_cancellable (task);
g_assert (IDE_IS_RUNNER (runner));
@@ -563,6 +585,82 @@ do_run_async (IdeRunManager *self,
IDE_EXIT;
}
+static void
+deploy_cb (GObject *object,
+ GAsyncResult *result,
+ gpointer user_data)
+{
+ IdeDeviceManager *device_manager = (IdeDeviceManager *)object;
+ IdeBuildManager *build_manager;
+ IdeContext *context;
+ IdePipeline *pipeline;
+ IdeRunManager *self;
+ g_autoptr(IdeTask) task = user_data;
+ g_autoptr(GError) error = NULL;
+
+ IDE_ENTRY;
+
+ g_assert (IDE_IS_DEVICE_MANAGER (device_manager));
+ g_assert (IDE_IS_TASK (task));
+
+ if (!ide_device_manager_deploy_finish (device_manager, result, &error))
+ {
+ ide_task_return_error (task, g_steal_pointer (&error));
+ IDE_EXIT;
+ }
+
+ self = ide_task_get_source_object (task);
+ g_assert (IDE_IS_RUN_MANAGER (self));
+
+ context = ide_object_get_context (IDE_OBJECT (self));
+ g_assert (IDE_IS_CONTEXT (context));
+
+ build_manager = ide_build_manager_from_context (context);
+ pipeline = ide_build_manager_get_pipeline (build_manager);
+
+ ide_device_manager_create_runner_async (device_manager,
+ pipeline,
+ ide_task_get_cancellable (task),
+ create_runner_cb,
+ g_object_ref (task));
+
+ IDE_EXIT;
+}
+
+static void
+do_run_async (IdeRunManager *self,
+ IdeTask *task)
+{
+ IdeBuildManager *build_manager;
+ IdeContext *context;
+ IdeDeviceManager *device_manager;
+ IdePipeline *pipeline;
+ GCancellable *cancellable;
+
+ IDE_ENTRY;
+
+ g_assert (IDE_IS_RUN_MANAGER (self));
+ g_assert (IDE_IS_TASK (task));
+
+ context = ide_object_get_context (IDE_OBJECT (self));
+ g_assert (IDE_IS_CONTEXT (context));
+
+ build_manager = ide_build_manager_from_context (context);
+ pipeline = ide_build_manager_get_pipeline (build_manager);
+ device_manager = ide_device_manager_from_context (context);
+
+ cancellable = ide_task_get_cancellable (task);
+ g_assert (!cancellable || G_IS_CANCELLABLE (cancellable));
+
+ ide_device_manager_deploy_async (device_manager,
+ pipeline,
+ cancellable,
+ deploy_cb,
+ g_object_ref (task));
+
+ IDE_EXIT;
+}
+
static void
ide_run_manager_run_discover_cb (GObject *object,
GAsyncResult *result,
diff --git a/src/plugins/deviced/gbp-deviced-deploy-strategy.c
b/src/plugins/deviced/gbp-deviced-deploy-strategy.c
index 82bec4593..f8877cf5a 100644
--- a/src/plugins/deviced/gbp-deviced-deploy-strategy.c
+++ b/src/plugins/deviced/gbp-deviced-deploy-strategy.c
@@ -25,6 +25,7 @@
#include "gbp-deviced-deploy-strategy.h"
#include "gbp-deviced-device.h"
+#include "gbp-deviced-runner.h"
struct _GbpDevicedDeployStrategy
{
@@ -337,7 +338,7 @@ gbp_deviced_deploy_strategy_deploy_async (IdeDeployStrategy *strategy,
g_assert (GBP_IS_FLATPAK_MANIFEST (config));
g_assert (GBP_IS_DEVICED_DEVICE (device));
- state = g_slice_new (DeployState);
+ state = g_slice_new0 (DeployState);
state->pipeline = g_object_ref (pipeline);
state->app_id = g_strdup_printf ("%s/%s/master", app_id, arch);
state->device = g_object_ref (GBP_DEVICED_DEVICE (device));
@@ -371,6 +372,54 @@ gbp_deviced_deploy_strategy_deploy_finish (IdeDeployStrategy *self,
return ide_task_propagate_boolean (IDE_TASK (result), error);
}
+static void
+gbp_deviced_deploy_strategy_create_runner_async (IdeDeployStrategy *strategy,
+ IdePipeline *pipeline,
+ GCancellable *cancellable,
+ GAsyncReadyCallback callback,
+ gpointer user_data)
+{
+ GbpDevicedDeployStrategy *self = (GbpDevicedDeployStrategy *)strategy;
+ g_autoptr(IdeTask) task = NULL;
+ IdeDevice *device = NULL;
+ IdeConfig *config = NULL;
+ GbpDevicedRunner *runner;
+
+ IDE_ENTRY;
+
+ g_assert (GBP_IS_DEVICED_DEPLOY_STRATEGY (self));
+ g_assert (IDE_IS_PIPELINE (pipeline));
+ g_assert (!cancellable || G_IS_CANCELLABLE (cancellable));
+
+ task = ide_task_new (self, cancellable, callback, user_data);
+ ide_task_set_source_tag (task, gbp_deviced_deploy_strategy_create_runner_async);
+
+ device = ide_pipeline_get_device (pipeline);
+ config = ide_pipeline_get_config (pipeline);
+
+ g_assert (GBP_IS_FLATPAK_MANIFEST (config));
+ g_assert (GBP_IS_DEVICED_DEVICE (device));
+
+ g_assert (IDE_IS_CONTEXT (ide_object_get_context (IDE_OBJECT (self))));
+
+ runner = gbp_deviced_runner_new (GBP_DEVICED_DEVICE (device));
+ ide_object_append (IDE_OBJECT (pipeline), IDE_OBJECT (runner));
+ ide_task_return_object (task, runner);
+
+ IDE_EXIT;
+}
+
+static IdeRunner *
+gbp_deviced_deploy_strategy_create_runner_finish (IdeDeployStrategy *self,
+ GAsyncResult *result,
+ GError **error)
+{
+ g_return_val_if_fail (GBP_IS_DEVICED_DEPLOY_STRATEGY (self), FALSE);
+ g_return_val_if_fail (ide_task_is_valid (result, self), FALSE);
+
+ return ide_task_propagate_object (IDE_TASK (result), error);
+}
+
static void
gbp_deviced_deploy_strategy_class_init (GbpDevicedDeployStrategyClass *klass)
{
@@ -380,6 +429,8 @@ gbp_deviced_deploy_strategy_class_init (GbpDevicedDeployStrategyClass *klass)
strategy_class->load_finish = gbp_deviced_deploy_strategy_load_finish;
strategy_class->deploy_async = gbp_deviced_deploy_strategy_deploy_async;
strategy_class->deploy_finish = gbp_deviced_deploy_strategy_deploy_finish;
+ strategy_class->create_runner_async = gbp_deviced_deploy_strategy_create_runner_async;
+ strategy_class->create_runner_finish = gbp_deviced_deploy_strategy_create_runner_finish;
}
static void
diff --git a/src/plugins/deviced/gbp-deviced-device.c b/src/plugins/deviced/gbp-deviced-device.c
index 5a462a31c..ef008ad3c 100644
--- a/src/plugins/deviced/gbp-deviced-device.c
+++ b/src/plugins/deviced/gbp-deviced-device.c
@@ -101,7 +101,7 @@ gbp_deviced_device_connect_cb (GObject *object,
g_list_free (list);
}
-static void
+void
gbp_deviced_device_get_client_async (GbpDevicedDevice *self,
GCancellable *cancellable,
GAsyncReadyCallback callback,
@@ -133,7 +133,7 @@ gbp_deviced_device_get_client_async (GbpDevicedDevice *self,
}
}
-static DevdClient *
+DevdClient *
gbp_deviced_device_get_client_finish (GbpDevicedDevice *self,
GAsyncResult *result,
GError **error)
@@ -313,6 +313,7 @@ gbp_deviced_device_class_init (GbpDevicedDeviceClass *klass)
static void
gbp_deviced_device_init (GbpDevicedDevice *self)
{
+ g_queue_init (&self->connecting);
}
GbpDevicedDevice *
@@ -653,3 +654,4 @@ gbp_deviced_device_install_bundle_finish (GbpDevicedDevice *self,
IDE_RETURN (ret);
}
+
diff --git a/src/plugins/deviced/gbp-deviced-device.h b/src/plugins/deviced/gbp-deviced-device.h
index e98fbb7a5..8055064dd 100644
--- a/src/plugins/deviced/gbp-deviced-device.h
+++ b/src/plugins/deviced/gbp-deviced-device.h
@@ -49,5 +49,12 @@ void gbp_deviced_device_install_bundle_async (GbpDevicedDevice
gboolean gbp_deviced_device_install_bundle_finish (GbpDevicedDevice *self,
GAsyncResult *result,
GError **error);
+void gbp_deviced_device_get_client_async (GbpDevicedDevice *self,
+ GCancellable *cancellable,
+ GAsyncReadyCallback callback,
+ gpointer user_data);
+DevdClient *gbp_deviced_device_get_client_finish (GbpDevicedDevice *self,
+ GAsyncResult *result,
+ GError **error);
G_END_DECLS
diff --git a/src/plugins/deviced/gbp-deviced-runner.c b/src/plugins/deviced/gbp-deviced-runner.c
new file mode 100644
index 000000000..7f565318e
--- /dev/null
+++ b/src/plugins/deviced/gbp-deviced-runner.c
@@ -0,0 +1,435 @@
+/* gbp-deviced-runner.c
+ *
+ * Copyright 2021 James Westman <james jwestman net>
+ *
+ * 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/>.
+ *
+ * SPDX-License-Identifier: GPL-3.0-or-later
+ */
+
+#define G_LOG_DOMAIN "gbp-deviced-runner"
+
+#include "../flatpak/gbp-flatpak-manifest.h"
+
+#include "gbp-deviced-runner.h"
+
+struct _GbpDevicedRunner
+{
+ IdeRunner parent_instance;
+
+ GbpDevicedDevice *device;
+};
+
+G_DEFINE_TYPE (GbpDevicedRunner, gbp_deviced_runner, IDE_TYPE_RUNNER)
+
+enum {
+ PROP_0,
+ PROP_DEVICE,
+ N_PROPS
+};
+
+static GParamSpec *properties [N_PROPS];
+
+GbpDevicedRunner *
+gbp_deviced_runner_new (GbpDevicedDevice *device)
+{
+ return g_object_new (GBP_TYPE_DEVICED_RUNNER,
+ "device", device,
+ NULL);
+}
+
+static void
+gbp_deviced_runner_finalize (GObject *object)
+{
+ GbpDevicedRunner *self = (GbpDevicedRunner *)object;
+
+ g_clear_object (&self->device);
+
+ G_OBJECT_CLASS (gbp_deviced_runner_parent_class)->finalize (object);
+}
+
+static void
+gbp_deviced_runner_get_property (GObject *object,
+ guint prop_id,
+ GValue *value,
+ GParamSpec *pspec)
+{
+ GbpDevicedRunner *self = GBP_DEVICED_RUNNER (object);
+
+ switch (prop_id)
+ {
+ case PROP_DEVICE:
+ g_value_set_object (value, gbp_deviced_runner_get_device (self));
+ break;
+ default:
+ G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
+ }
+}
+
+static void
+gbp_deviced_runner_set_property (GObject *object,
+ guint prop_id,
+ const GValue *value,
+ GParamSpec *pspec)
+{
+ GbpDevicedRunner *self = GBP_DEVICED_RUNNER (object);
+
+ switch (prop_id)
+ {
+ case PROP_DEVICE:
+ gbp_deviced_runner_set_device (self, g_value_get_object (value));
+ break;
+ default:
+ G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
+ }
+}
+
+typedef struct {
+ GbpDevicedRunner *self;
+ DevdClient *client;
+ char *app_id;
+ DevdProcessService *process_service;
+ char *process_id;
+ char *pty_id;
+ int tty_fd;
+ GCancellable *cancellable;
+ gulong cancellable_handle;
+} RunData;
+
+static void
+run_data_free (RunData *data)
+{
+ g_clear_object (&data->self);
+ g_clear_object (&data->client);
+ g_clear_object (&data->process_service);
+ g_clear_pointer (&data->app_id, g_free);
+ g_clear_pointer (&data->process_id, g_free);
+ g_clear_pointer (&data->pty_id, g_free);
+ g_cancellable_disconnect (data->cancellable, data->cancellable_handle);
+ g_free (data);
+}
+
+static void run_wait_for_process_loop (IdeTask *task);
+
+static void
+run_wait_for_process_cb (GObject *object,
+ GAsyncResult *result,
+ gpointer user_data)
+{
+ DevdProcessService *process_service = (DevdProcessService *)object;
+ g_autoptr(IdeTask) task = user_data;
+ g_autoptr(GError) error = NULL;
+ RunData *data;
+ gboolean exited;
+ int exit_code;
+ int term_sig;
+ GCancellable *cancellable;
+
+ g_assert (DEVD_IS_PROCESS_SERVICE (process_service));
+ g_assert (IDE_IS_TASK (task));
+
+ data = ide_task_get_task_data (task);
+ cancellable = ide_task_get_cancellable (task);
+
+ devd_process_service_wait_for_process_finish (process_service,
+ result,
+ &exited,
+ &exit_code,
+ &term_sig,
+ &error);
+ if (error != NULL)
+ {
+ ide_task_return_error (task, g_steal_pointer (&error));
+ return;
+ }
+
+ if (exited)
+ {
+ if (data->pty_id != NULL)
+ devd_process_service_destroy_pty_async (process_service,
+ data->pty_id,
+ cancellable,
+ NULL, NULL);
+
+ if (data->tty_fd != -1)
+ close(data->tty_fd);
+
+ ide_task_return_boolean (task, TRUE);
+ }
+ else
+ {
+ run_wait_for_process_loop (task);
+ }
+}
+
+static void
+run_wait_for_process_loop (IdeTask *task)
+{
+ GCancellable *cancellable;
+ RunData *data;
+
+ data = ide_task_get_task_data (task);
+ cancellable = ide_task_get_cancellable (task);
+
+ devd_process_service_wait_for_process_async (data->process_service,
+ data->process_id,
+ cancellable,
+ run_wait_for_process_cb,
+ g_object_ref (task));
+}
+
+static void
+run_cancelled_cb (GCancellable *cancellable,
+ RunData *data)
+{
+ IDE_ENTRY;
+
+ g_assert (G_IS_CANCELLABLE (cancellable));
+
+ if (data->process_service)
+ devd_process_service_force_exit (data->process_service, data->process_id);
+
+ IDE_EXIT;
+}
+
+static void
+run_run_app_cb (GObject *object,
+ GAsyncResult *result,
+ gpointer user_data)
+{
+ DevdClient *client = (DevdClient *)object;
+ g_autoptr(IdeTask) task = user_data;
+ g_autoptr(GError) error = NULL;
+ RunData *data;
+
+ g_assert (DEVD_IS_CLIENT (client));
+ g_assert (IDE_IS_TASK (task));
+
+ data = ide_task_get_task_data (task);
+
+ if (!(data->process_id = devd_client_run_app_finish (client, result, &error)))
+ {
+ ide_task_return_error (task, g_steal_pointer (&error));
+ return;
+ }
+
+ data->cancellable = ide_task_get_cancellable (task);
+ g_cancellable_connect (data->cancellable, G_CALLBACK (run_cancelled_cb), data, NULL);
+
+ run_wait_for_process_loop (task);
+}
+
+static void
+run_create_pty_cb (GObject *object,
+ GAsyncResult *result,
+ gpointer user_data)
+{
+ RunData *data;
+ DevdProcessService *process_service = (DevdProcessService *)object;
+ g_autoptr(IdeTask) task = user_data;
+ g_autoptr(GError) error = NULL;
+
+ IDE_ENTRY;
+
+ g_assert (DEVD_IS_PROCESS_SERVICE (process_service));
+ g_assert (IDE_IS_TASK (task));
+
+ data = ide_task_get_task_data (task);
+
+ if (!(data->pty_id = devd_process_service_create_pty_finish (process_service, result, &error)))
+ {
+ ide_task_return_error (task, g_steal_pointer (&error));
+ IDE_EXIT;
+ }
+
+ devd_client_run_app_async (data->client,
+ "flatpak",
+ data->app_id,
+ data->pty_id,
+ ide_task_get_cancellable (task),
+ run_run_app_cb,
+ g_object_ref (task));
+
+ IDE_EXIT;
+}
+
+static void
+run_get_client_cb (GObject *object,
+ GAsyncResult *result,
+ gpointer user_data)
+{
+ RunData *data;
+ GbpDevicedDevice *device = (GbpDevicedDevice *)object;
+ g_autoptr(IdeTask) task = user_data;
+ g_autoptr(GError) error = NULL;
+ VtePty *pty;
+
+ IDE_ENTRY;
+
+ g_assert (GBP_IS_DEVICED_DEVICE (device));
+ g_assert (IDE_IS_TASK (task));
+
+ data = ide_task_get_task_data (task);
+
+ if (!(data->client = gbp_deviced_device_get_client_finish (device, result, &error)))
+ {
+ ide_task_return_error (task, g_steal_pointer (&error));
+ return;
+ }
+
+ pty = ide_runner_get_pty (IDE_RUNNER (data->self));
+ if (pty == NULL || ide_runner_get_disable_pty (IDE_RUNNER (data->self)))
+ {
+ devd_client_run_app_async (data->client,
+ "flatpak",
+ data->app_id,
+ NULL,
+ ide_task_get_cancellable (task),
+ run_run_app_cb,
+ g_object_ref (task));
+ IDE_EXIT;
+ }
+
+ data->process_service = devd_process_service_new (data->client, &error);
+ if (error != NULL)
+ {
+ ide_task_return_error (task, g_steal_pointer (&error));
+ IDE_EXIT;
+ }
+
+ data->tty_fd = ide_pty_intercept_create_slave (vte_pty_get_fd (pty), TRUE);
+ devd_process_service_create_pty_async (data->process_service,
+ data->tty_fd,
+ ide_task_get_cancellable (task),
+ run_create_pty_cb,
+ g_object_ref (task));
+
+ IDE_EXIT;
+}
+
+static void
+gbp_deviced_runner_run_async (IdeRunner *runner,
+ GCancellable *cancellable,
+ GAsyncReadyCallback callback,
+ gpointer user_data)
+{
+ GbpDevicedRunner *self = (GbpDevicedRunner *)runner;
+ g_autoptr(IdeTask) task = NULL;
+ IdeContext *context;
+ IdeConfigManager *config_manager;
+ IdeConfig *config;
+ RunData *data;
+
+ IDE_ENTRY;
+
+ g_return_if_fail (GBP_IS_DEVICED_RUNNER (self));
+ g_return_if_fail (cancellable == NULL || G_IS_CANCELLABLE (cancellable));
+
+ task = ide_task_new (self, cancellable, callback, user_data);
+ ide_task_set_source_tag (task, gbp_deviced_runner_run_async);
+
+ if (self->device == NULL)
+ {
+ ide_task_return_new_error (task,
+ G_IO_ERROR,
+ G_IO_ERROR_FAILED,
+ "No device set on deviced runner");
+ IDE_EXIT;
+ }
+
+ context = ide_object_get_context (IDE_OBJECT (self->device));
+ g_assert (IDE_IS_CONTEXT (context));
+ config_manager = ide_config_manager_from_context (context);
+ config = ide_config_manager_get_current (config_manager);
+
+ data = g_new0 (RunData, 1);
+
+ /* GbpDevicedDeployStrategy only supports flatpak manifests, and it is the
+ * only thing that creates GbpDevicedRunners, so we should only get flatpak
+ * manifests here */
+ g_assert (GBP_IS_FLATPAK_MANIFEST (config));
+
+ ide_task_set_task_data (task, data, run_data_free);
+
+ data->self = g_object_ref (self);
+ data->app_id = g_strdup (ide_config_get_app_id (config));
+ data->tty_fd = -1;
+
+ gbp_deviced_device_get_client_async (self->device,
+ cancellable,
+ run_get_client_cb,
+ g_object_ref (task));
+
+ IDE_EXIT;
+}
+
+static gboolean
+gbp_deviced_runner_run_finish (IdeRunner *self,
+ GAsyncResult *result,
+ GError **error)
+{
+ gboolean ret;
+
+ IDE_ENTRY;
+
+ g_return_val_if_fail (GBP_IS_DEVICED_RUNNER (self), FALSE);
+ g_return_val_if_fail (ide_task_is_valid (result, self), FALSE);
+
+ ret = ide_task_propagate_boolean (IDE_TASK (result), error);
+
+ IDE_RETURN (ret);
+}
+
+static void
+gbp_deviced_runner_class_init (GbpDevicedRunnerClass *klass)
+{
+ GObjectClass *object_class = G_OBJECT_CLASS (klass);
+ IdeRunnerClass *runner_class = IDE_RUNNER_CLASS (klass);
+
+ object_class->finalize = gbp_deviced_runner_finalize;
+ object_class->get_property = gbp_deviced_runner_get_property;
+ object_class->set_property = gbp_deviced_runner_set_property;
+
+ runner_class->run_async = gbp_deviced_runner_run_async;
+ runner_class->run_finish = gbp_deviced_runner_run_finish;
+
+ properties[PROP_DEVICE] =
+ g_param_spec_object ("device",
+ "Device",
+ "The device to run on",
+ GBP_TYPE_DEVICED_DEVICE,
+ G_PARAM_STATIC_STRINGS | G_PARAM_READWRITE);
+
+ g_object_class_install_properties (G_OBJECT_CLASS (klass), N_PROPS, properties);
+}
+
+static void
+gbp_deviced_runner_init (GbpDevicedRunner *self)
+{
+}
+
+GbpDevicedDevice *
+gbp_deviced_runner_get_device (GbpDevicedRunner *self)
+{
+ g_return_val_if_fail (GBP_IS_DEVICED_RUNNER (self), NULL);
+ return self->device;
+}
+
+void
+gbp_deviced_runner_set_device (GbpDevicedRunner *self,
+ GbpDevicedDevice *device)
+{
+ g_return_if_fail (GBP_IS_DEVICED_RUNNER (self));
+ g_set_object (&self->device, device);
+}
diff --git a/src/plugins/deviced/gbp-deviced-runner.h b/src/plugins/deviced/gbp-deviced-runner.h
new file mode 100644
index 000000000..f1392d66b
--- /dev/null
+++ b/src/plugins/deviced/gbp-deviced-runner.h
@@ -0,0 +1,39 @@
+/* gbp-deviced-runner.h
+ *
+ * Copyright 2021 James Westman <james jwestman net>
+ *
+ * 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/>.
+ *
+ * SPDX-License-Identifier: GPL-3.0-or-later
+ */
+
+
+#pragma once
+
+#include <libide-foundry.h>
+#include "gbp-deviced-device.h"
+
+G_BEGIN_DECLS
+
+#define GBP_TYPE_DEVICED_RUNNER (gbp_deviced_runner_get_type())
+
+G_DECLARE_FINAL_TYPE (GbpDevicedRunner, gbp_deviced_runner, GBP, DEVICED_RUNNER, IdeRunner)
+
+GbpDevicedRunner *gbp_deviced_runner_new (GbpDevicedDevice *device);
+
+GbpDevicedDevice *gbp_deviced_runner_get_device (GbpDevicedRunner *self);
+void gbp_deviced_runner_set_device (GbpDevicedRunner *self,
+ GbpDevicedDevice *device);
+
+G_END_DECLS
diff --git a/src/plugins/deviced/meson.build b/src/plugins/deviced/meson.build
index 3c2453331..8eb16b9e3 100644
--- a/src/plugins/deviced/meson.build
+++ b/src/plugins/deviced/meson.build
@@ -9,6 +9,7 @@ plugins_sources += files([
'gbp-deviced-deploy-strategy.c',
'gbp-deviced-device.c',
'gbp-deviced-device-provider.c',
+ 'gbp-deviced-runner.c',
])
plugin_deviced_resources = gnome.compile_resources(
[
Date Prev][
Date Next] [
Thread Prev][
Thread Next]
[
Thread Index]
[
Date Index]
[
Author Index]