mirror of
https://git.proxmox.com/git/fwupd
synced 2025-05-19 05:11:26 +00:00
Add a helper function to spawn a subprocess
This allows us to watch the output of a flashing tool and screen-scrape the progress completion.
This commit is contained in:
parent
41cbe2aab3
commit
049ccc8f6c
10
data/tests/spawn.sh
Executable file
10
data/tests/spawn.sh
Executable file
@ -0,0 +1,10 @@
|
|||||||
|
#/bin/sh
|
||||||
|
echo "this is a test"
|
||||||
|
sleep 1
|
||||||
|
echo "this is another line1"
|
||||||
|
echo "this is another line2"
|
||||||
|
echo "this is another line3"
|
||||||
|
echo "this is another line4"
|
||||||
|
sleep 1
|
||||||
|
echo "done!"
|
||||||
|
exit 0
|
117
src/fu-common.c
117
src/fu-common.c
@ -375,3 +375,120 @@ fu_common_firmware_builder (GBytes *bytes,
|
|||||||
/* success */
|
/* success */
|
||||||
return g_steal_pointer (&firmware_blob);
|
return g_steal_pointer (&firmware_blob);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
typedef struct {
|
||||||
|
FuOutputHandler handler_cb;
|
||||||
|
gpointer handler_user_data;
|
||||||
|
GMainLoop *loop;
|
||||||
|
GSource *source;
|
||||||
|
GInputStream *stream;
|
||||||
|
GCancellable *cancellable;
|
||||||
|
} FuCommonSpawnHelper;
|
||||||
|
|
||||||
|
static void fu_common_spawn_create_pollable_source (FuCommonSpawnHelper *helper);
|
||||||
|
|
||||||
|
static gboolean
|
||||||
|
fu_common_spawn_source_pollable_cb (GObject *stream, gpointer user_data)
|
||||||
|
{
|
||||||
|
FuCommonSpawnHelper *helper = (FuCommonSpawnHelper *) user_data;
|
||||||
|
gchar buffer[1024];
|
||||||
|
gssize sz;
|
||||||
|
g_auto(GStrv) split = NULL;
|
||||||
|
g_autoptr(GError) error = NULL;
|
||||||
|
|
||||||
|
/* read from stream */
|
||||||
|
sz = g_pollable_input_stream_read_nonblocking (G_POLLABLE_INPUT_STREAM (stream),
|
||||||
|
buffer,
|
||||||
|
sizeof(buffer) - 1,
|
||||||
|
NULL,
|
||||||
|
&error);
|
||||||
|
if (sz < 0) {
|
||||||
|
if (!g_error_matches (error, G_IO_ERROR, G_IO_ERROR_WOULD_BLOCK))
|
||||||
|
g_error ("err=%s", error->message);
|
||||||
|
return G_SOURCE_REMOVE;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* no read possible */
|
||||||
|
if (sz == 0)
|
||||||
|
g_main_loop_quit (helper->loop);
|
||||||
|
|
||||||
|
/* emit lines */
|
||||||
|
if (helper->handler_cb != NULL) {
|
||||||
|
buffer[sz] = '\0';
|
||||||
|
split = g_strsplit (buffer, "\n", -1);
|
||||||
|
for (guint i = 0; split[i] != NULL; i++) {
|
||||||
|
if (split[i][0] == '\0')
|
||||||
|
continue;
|
||||||
|
helper->handler_cb (split[i], helper->handler_user_data);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/* set up the source for the next read */
|
||||||
|
fu_common_spawn_create_pollable_source (helper);
|
||||||
|
return G_SOURCE_REMOVE;
|
||||||
|
}
|
||||||
|
|
||||||
|
static void
|
||||||
|
fu_common_spawn_create_pollable_source (FuCommonSpawnHelper *helper)
|
||||||
|
{
|
||||||
|
if (helper->source != NULL)
|
||||||
|
g_source_destroy (helper->source);
|
||||||
|
helper->source = g_pollable_input_stream_create_source (G_POLLABLE_INPUT_STREAM (helper->stream),
|
||||||
|
helper->cancellable);
|
||||||
|
g_source_attach (helper->source, NULL);
|
||||||
|
g_source_set_callback (helper->source, (GSourceFunc) fu_common_spawn_source_pollable_cb, helper, NULL);
|
||||||
|
}
|
||||||
|
|
||||||
|
static void
|
||||||
|
fu_common_spawn_helper_free (FuCommonSpawnHelper *helper)
|
||||||
|
{
|
||||||
|
if (helper->stream != NULL)
|
||||||
|
g_object_unref (helper->stream);
|
||||||
|
if (helper->source != NULL)
|
||||||
|
g_source_destroy (helper->source);
|
||||||
|
if (helper->loop != NULL)
|
||||||
|
g_main_loop_unref (helper->loop);
|
||||||
|
g_free (helper);
|
||||||
|
}
|
||||||
|
|
||||||
|
G_DEFINE_AUTOPTR_CLEANUP_FUNC(FuCommonSpawnHelper, fu_common_spawn_helper_free)
|
||||||
|
|
||||||
|
/**
|
||||||
|
* fu_common_spawn_sync:
|
||||||
|
* @argv: The argument list to run
|
||||||
|
* @handler_cb: A #FuOutputHandler or %NULL
|
||||||
|
* @handler_user_data: the user data to pass to @handler
|
||||||
|
* @cancellable: a #GCancellable, or %NULL
|
||||||
|
* @error: A #GError or %NULL
|
||||||
|
*
|
||||||
|
* Runs a subprocess and waits for it to exit. Any output on standard out or
|
||||||
|
* standard error will be forwarded to @handler_cb as whole lines.
|
||||||
|
*
|
||||||
|
* Returns: %TRUE for success
|
||||||
|
**/
|
||||||
|
gboolean
|
||||||
|
fu_common_spawn_sync (const gchar * const * argv,
|
||||||
|
FuOutputHandler handler_cb,
|
||||||
|
gpointer handler_user_data,
|
||||||
|
GCancellable *cancellable, GError **error)
|
||||||
|
{
|
||||||
|
g_autoptr(FuCommonSpawnHelper) helper = NULL;
|
||||||
|
g_autoptr(GSubprocess) subprocess = NULL;
|
||||||
|
|
||||||
|
/* create subprocess */
|
||||||
|
subprocess = g_subprocess_newv (argv, G_SUBPROCESS_FLAGS_STDOUT_PIPE |
|
||||||
|
G_SUBPROCESS_FLAGS_STDERR_MERGE, error);
|
||||||
|
if (subprocess == NULL)
|
||||||
|
return FALSE;
|
||||||
|
|
||||||
|
/* watch for process to exit */
|
||||||
|
helper = g_new0 (FuCommonSpawnHelper, 1);
|
||||||
|
helper->handler_cb = handler_cb;
|
||||||
|
helper->handler_user_data = handler_user_data;
|
||||||
|
helper->loop = g_main_loop_new (NULL, FALSE);
|
||||||
|
helper->stream = g_subprocess_get_stdout_pipe (subprocess);
|
||||||
|
helper->cancellable = cancellable;
|
||||||
|
fu_common_spawn_create_pollable_source (helper);
|
||||||
|
g_main_loop_run (helper->loop);
|
||||||
|
return g_subprocess_wait_check (subprocess, cancellable, error);
|
||||||
|
}
|
||||||
|
@ -24,6 +24,15 @@
|
|||||||
|
|
||||||
#include <glib.h>
|
#include <glib.h>
|
||||||
|
|
||||||
|
typedef void (*FuOutputHandler) (const gchar *line,
|
||||||
|
gpointer user_data);
|
||||||
|
|
||||||
|
gboolean fu_common_spawn_sync (const gchar * const *argv,
|
||||||
|
FuOutputHandler handler,
|
||||||
|
gpointer handler_user_data,
|
||||||
|
GCancellable *cancellable,
|
||||||
|
GError **error);
|
||||||
|
|
||||||
gboolean fu_common_rmtree (const gchar *directory,
|
gboolean fu_common_rmtree (const gchar *directory,
|
||||||
GError **error);
|
GError **error);
|
||||||
gboolean fu_common_set_contents_bytes (const gchar *filename,
|
gboolean fu_common_set_contents_bytes (const gchar *filename,
|
||||||
|
@ -449,6 +449,33 @@ fu_common_firmware_builder_func (void)
|
|||||||
g_assert_cmpstr (data, ==, "xobdnas eht ni gninnur");
|
g_assert_cmpstr (data, ==, "xobdnas eht ni gninnur");
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static void
|
||||||
|
fu_test_stdout_cb (const gchar *line, gpointer user_data)
|
||||||
|
{
|
||||||
|
guint *lines = (guint *) user_data;
|
||||||
|
g_debug ("got '%s'", line);
|
||||||
|
(*lines)++;
|
||||||
|
}
|
||||||
|
|
||||||
|
static void
|
||||||
|
fu_common_spawn_func (void)
|
||||||
|
{
|
||||||
|
gboolean ret;
|
||||||
|
guint lines = 0;
|
||||||
|
g_autoptr(GError) error = NULL;
|
||||||
|
g_autofree gchar *fn = NULL;
|
||||||
|
gchar *argv[3] = { "replace", "test", NULL };
|
||||||
|
|
||||||
|
fn = fu_test_get_filename (TESTDATADIR, "spawn.sh");
|
||||||
|
g_assert (fn != NULL);
|
||||||
|
argv[0] = fn;
|
||||||
|
ret = fu_common_spawn_sync ((const gchar * const *) argv,
|
||||||
|
fu_test_stdout_cb, &lines, NULL, &error);
|
||||||
|
g_assert_no_error (error);
|
||||||
|
g_assert (ret);
|
||||||
|
g_assert_cmpint (lines, ==, 6);
|
||||||
|
}
|
||||||
|
|
||||||
int
|
int
|
||||||
main (int argc, char **argv)
|
main (int argc, char **argv)
|
||||||
{
|
{
|
||||||
@ -466,6 +493,7 @@ main (int argc, char **argv)
|
|||||||
g_test_add_func ("/fwupd/plugin{delay}", fu_plugin_delay_func);
|
g_test_add_func ("/fwupd/plugin{delay}", fu_plugin_delay_func);
|
||||||
g_test_add_func ("/fwupd/plugin{module}", fu_plugin_module_func);
|
g_test_add_func ("/fwupd/plugin{module}", fu_plugin_module_func);
|
||||||
g_test_add_func ("/fwupd/keyring", fu_keyring_func);
|
g_test_add_func ("/fwupd/keyring", fu_keyring_func);
|
||||||
|
g_test_add_func ("/fwupd/common{spawn)", fu_common_spawn_func);
|
||||||
g_test_add_func ("/fwupd/common{firmware-builder}", fu_common_firmware_builder_func);
|
g_test_add_func ("/fwupd/common{firmware-builder}", fu_common_firmware_builder_func);
|
||||||
return g_test_run ();
|
return g_test_run ();
|
||||||
}
|
}
|
||||||
|
Loading…
Reference in New Issue
Block a user