[packagekit] packagekit: Branch 'master'

Richard Hughes hughsient at kemper.freedesktop.org
Wed Sep 5 16:24:33 PDT 2007


 src/pk-backend-internal.h |   98 ++++
 src/pk-backend.c          | 1002 ++++++++++++++++++++++++++++++++++++++++++++++
 src/pk-backend.h          |  127 +++++
 3 files changed, 1227 insertions(+)

New commits:
diff-tree e5a7fbaa8abed1618ae12a050578d8822dee2770 (from ead0e90644c9aa1cc3c659fa744509dc7065fbf9)
Author: Richard Hughes <richard at hughsie.com>
Date:   Thu Sep 6 00:24:12 2007 +0100

    add new backend loaded code and abstraction

diff --git a/src/pk-backend-internal.h b/src/pk-backend-internal.h
new file mode 100644
index 0000000..01d8d0a
--- /dev/null
+++ b/src/pk-backend-internal.h
@@ -0,0 +1,98 @@
+/* -*- Mode: C; tab-width: 8; indent-tabs-mode: t; c-basic-offset: 8 -*-
+ *
+ * Copyright (C) 2007 Richard Hughes <richard at hughsie.com>
+ *
+ * Licensed under the GNU General Public License Version 2
+ *
+ * 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 2 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, write to the Free Software
+ * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+ */
+
+#ifndef __PK_BACKEND_INTERNAL_H
+#define __PK_BACKEND_INTERNAL_H
+
+#include <glib-object.h>
+#include "pk-backend.h"
+
+G_BEGIN_DECLS
+
+#define PK_TYPE_BACKEND		(pk_backend_get_type ())
+#define PK_BACKEND(o)		(G_TYPE_CHECK_INSTANCE_CAST ((o), PK_TYPE_BACKEND, PkBackend))
+#define PK_BACKEND_CLASS(k)	(G_TYPE_CHECK_CLASS_CAST((k), PK_TYPE_BACKEND, PkBackendClass))
+#define PK_IS_BACKEND(o)	(G_TYPE_CHECK_INSTANCE_TYPE ((o), PK_TYPE_BACKEND))
+#define PK_IS_BACKEND_CLASS(k)	(G_TYPE_CHECK_CLASS_TYPE ((k), PK_TYPE_BACKEND))
+#define PK_BACKEND_GET_CLASS(o)	(G_TYPE_INSTANCE_GET_CLASS ((o), PK_TYPE_BACKEND, PkBackendClass))
+
+typedef struct _PkBackendPrivate PkBackendPrivate;
+typedef struct _PkBackendClass PkBackendClass;
+
+struct _PkBackend
+{
+	GObject		 parent;
+	const PkBackendDesc *desc;
+	PkBackendPrivate *priv;
+};
+
+struct _PkBackendClass
+{
+	GObjectClass	parent_class;
+};
+
+
+/* general */
+GType		 pk_backend_get_type			(void);
+PkBackend	*pk_backend_new				(void);
+gdouble		 pk_backend_get_runtime			(PkBackend	*backend);
+gboolean	 pk_backend_load			(PkBackend      *backend,
+							 const gchar	*name);
+const gchar	*pk_backend_get_name			(PkBackend	*backend);
+gboolean	 pk_backend_cancel_job_try		(PkBackend	*backend);
+gboolean	 pk_backend_get_depends			(PkBackend	*backend,
+							 const gchar	*package_id);
+gboolean	 pk_backend_get_description		(PkBackend	*backend,
+							 const gchar	*package_id);
+gboolean	 pk_backend_get_requires		(PkBackend	*backend,
+							 const gchar	*package_id);
+gboolean	 pk_backend_get_updates			(PkBackend	*backend);
+gboolean	 pk_backend_install_package		(PkBackend	*backend,
+							 const gchar	*package_id);
+gboolean	 pk_backend_refresh_cache		(PkBackend	*backend,
+							 gboolean	 force);
+gboolean	 pk_backend_remove_package		(PkBackend	*backend,
+							 const gchar	*package_id,
+							 gboolean	 allow_deps);
+gboolean	 pk_backend_search_details		(PkBackend	*backend,
+							 const gchar	*filter,
+							 const gchar	*search);
+gboolean	 pk_backend_search_file			(PkBackend	*backend,
+							 const gchar	*filter,
+							 const gchar	*search);
+gboolean	 pk_backend_search_group		(PkBackend	*backend,
+							 const gchar	*filter,
+							 const gchar	*search);
+gboolean	 pk_backend_search_name			(PkBackend	*backend,
+							 const gchar	*filter,
+							 const gchar	*search);
+gboolean	 pk_backend_update_package		(PkBackend	*backend,
+							 const gchar	*package_id);
+gboolean	 pk_backend_update_system		(PkBackend	*backend);
+gboolean	 pk_backend_get_job_status		(PkBackend	*backend,
+							 PkTaskStatus	*status);
+gboolean	 pk_backend_get_job_role		(PkBackend	*backend,
+							 PkTaskRole	*role,
+							 const gchar	**package_id);
+
+G_END_DECLS
+
+#endif /* __PK_BACKEND_INTERNAL_H */
diff --git a/src/pk-backend.c b/src/pk-backend.c
new file mode 100644
index 0000000..4ddb867
--- /dev/null
+++ b/src/pk-backend.c
@@ -0,0 +1,1002 @@
+/* -*- Mode: C; tab-width: 8; indent-tabs-mode: t; c-basic-offset: 8 -*-
+ *
+ * Copyright (C) 2007 Richard Hughes <richard at hughsie.com>
+ *
+ * Licensed under the GNU General Public License Version 2
+ *
+ * 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 2 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, write to the Free Software
+ * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+ */
+
+#ifdef HAVE_CONFIG_H
+#  include <config.h>
+#endif
+
+#include <stdlib.h>
+#include <stdio.h>
+#include <time.h>
+#include <errno.h>
+
+#include <string.h>
+#include <sys/time.h>
+#include <sys/types.h>
+#ifdef HAVE_UNISTD_H
+#include <unistd.h>
+#endif /* HAVE_UNISTD_H */
+
+#include <glib/gi18n.h>
+#include <gmodule.h>
+#include <pk-package-id.h>
+
+#include "pk-debug.h"
+#include "pk-backend-internal.h"
+#include "pk-marshal.h"
+#include "pk-task-utils.h"
+#include "pk-spawn.h"
+#include "pk-network.h"
+
+#define PK_BACKEND_GET_PRIVATE(o) (G_TYPE_INSTANCE_GET_PRIVATE ((o), PK_TYPE_BACKEND, PkBackendPrivate))
+
+struct _PkBackendPrivate
+{
+	GModule			*handle;
+	gchar			*name;
+	PkTaskStatus		 role; /* this never changes for the lifetime of a job */
+	PkTaskStatus		 status; /* this changes */
+	gchar			*package_id; /* never changes, this is linked to role */
+	PkTaskExit		 exit;
+	GTimer			*timer;
+	PkSpawn			*spawn;
+	gboolean		 is_killable;
+	gboolean		 assigned;
+	PkNetwork		*network;
+};
+
+enum {
+	PK_TASK_JOB_STATUS_CHANGED,
+	PK_TASK_PERCENTAGE_CHANGED,
+	PK_TASK_SUB_PERCENTAGE_CHANGED,
+	PK_TASK_NO_PERCENTAGE_UPDATES,
+	PK_TASK_DESCRIPTION,
+	PK_TASK_PACKAGE,
+	PK_TASK_ERROR_CODE,
+	PK_TASK_REQUIRE_RESTART,
+	PK_TASK_FINISHED,
+	PK_TASK_ALLOW_INTERRUPT,
+	PK_TASK_LAST_SIGNAL
+};
+
+static guint signals [PK_TASK_LAST_SIGNAL] = { 0, };
+
+G_DEFINE_TYPE (PkBackend, pk_backend, G_TYPE_OBJECT)
+
+gboolean
+pk_backend_load (PkBackend *backend, const gchar *backend_name)
+{
+	GModule *handle;
+	gchar *path;
+	gchar *filename;
+
+	g_return_val_if_fail (backend_name != NULL, FALSE);
+
+	pk_debug ("Trying to load : %s", backend_name);
+
+	filename = g_strdup_printf ("libpk_backend_%s.so", backend_name);
+	path = g_build_filename (LIBDIR, "packagekit-backend", filename, NULL);
+	g_free (filename);
+	handle = g_module_open (path, 0);
+	if (handle == NULL) {
+		pk_debug ("opening module %s failed : %s", backend_name, g_module_error ());
+		g_free (path);
+		return FALSE;
+	}
+	g_free (path);
+
+	backend->priv->handle = handle;
+	backend->priv->name = g_strdup (backend_name);
+
+	if (g_module_symbol (handle, "pk_backend_desc", (gpointer) &backend->desc) == FALSE) {
+		g_module_close (handle);
+		pk_error ("could not find description in plugin %s, not loading", backend_name);
+	}
+
+	if (backend->desc->initialize) {
+		backend->desc->initialize (backend);
+	}
+	return TRUE;
+}
+
+const gchar *
+pk_backend_get_name (PkBackend *backend)
+{
+	g_return_val_if_fail (backend != NULL, NULL);
+
+	return backend->priv->name;
+}
+
+
+/**
+ * pk_backend_parse_common_output:
+ *
+ * If you are editing this function creating a new backend,
+ * then you are probably doing something wrong.
+ **/
+static gboolean
+pk_backend_parse_common_output (PkBackend *backend, const gchar *line)
+{
+	gchar **sections;
+	guint size;
+	guint value = 0;
+	gchar *command;
+	gboolean ret = TRUE;
+	PkTaskGroup group;
+
+	/* check if output line */
+	if (line == NULL || strstr (line, "\t") == NULL)
+		return FALSE;
+
+	/* split by tab */
+	sections = g_strsplit (line, "\t", 0);
+	command = sections[0];
+
+	/* get size */
+	size = g_strv_length (sections);
+
+	if (strcmp (command, "package") == 0) {
+		if (size != 4) {
+			g_error ("invalid command '%s'", command);
+			ret = FALSE;
+			goto out;
+		}
+		if (pk_package_id_check (sections[2]) == TRUE) {
+			value = atoi(sections[1]);
+			pk_debug ("value=%i, package='%s' shortdesc='%s'", value, sections[2], sections[3]);
+			pk_backend_package (backend, value, sections[2], sections[3]);
+		} else {
+			pk_warning ("invalid package_id");
+		}
+	} else if (strcmp (command, "description") == 0) {
+		if (size != 5) {
+			g_error ("invalid command '%s'", command);
+			ret = FALSE;
+			goto out;
+		}
+		group = pk_task_group_from_text (sections[2]);
+		pk_backend_description (backend, sections[1], group, sections[3], sections[4]);
+	} else {
+		pk_warning ("invalid command '%s'", command);
+	}
+out:
+	g_strfreev (sections);
+	return ret;
+}
+
+/**
+ * pk_backend_parse_common_error:
+ *
+ * If you are editing this function creating a new backend,
+ * then you are probably doing something wrong.
+ **/
+static gboolean
+pk_backend_parse_common_error (PkBackend *backend, const gchar *line)
+{
+	gchar **sections;
+	guint size;
+	guint percentage;
+	gchar *command;
+	PkTaskErrorCode error_enum;
+	PkTaskStatus status_enum;
+	PkTaskRestart restart_enum;
+	gboolean ret = TRUE;
+
+	/* check if output line */
+	if (line == NULL || strstr (line, "\t") == NULL)
+		return FALSE;
+
+	/* split by tab */
+	sections = g_strsplit (line, "\t", 0);
+	command = sections[0];
+
+	/* get size */
+	for (size=0; sections[size]; size++);
+
+	if (strcmp (command, "percentage") == 0) {
+		if (size != 2) {
+			g_error ("invalid command '%s'", command);
+			ret = FALSE;
+			goto out;
+		}
+		percentage = atoi(sections[1]);
+		pk_backend_change_percentage (backend, percentage);
+	} else if (strcmp (command, "subpercentage") == 0) {
+		if (size != 2) {
+			g_error ("invalid command '%s'", command);
+			ret = FALSE;
+			goto out;
+		}
+		percentage = atoi(sections[1]);
+		pk_backend_change_sub_percentage (backend, percentage);
+	} else if (strcmp (command, "error") == 0) {
+		if (size != 3) {
+			g_error ("invalid command '%s'", command);
+			ret = FALSE;
+			goto out;
+		}
+		error_enum = pk_task_error_code_from_text (sections[1]);
+		pk_backend_error_code (backend, error_enum, sections[2]);
+	} else if (strcmp (command, "requirerestart") == 0) {
+		if (size != 3) {
+			g_error ("invalid command '%s'", command);
+			ret = FALSE;
+			goto out;
+		}
+		restart_enum = pk_task_restart_from_text (sections[1]);
+		pk_backend_require_restart (backend, restart_enum, sections[2]);
+	} else if (strcmp (command, "status") == 0) {
+		if (size != 2) {
+			g_error ("invalid command '%s'", command);
+			ret = FALSE;
+			goto out;
+		}
+		status_enum = pk_task_status_from_text (sections[1]);
+		pk_backend_change_job_status (backend, status_enum);
+	} else if (strcmp (command, "allow-interrupt") == 0) {
+		if (size != 2) {
+			g_error ("invalid command '%s'", command);
+			ret = FALSE;
+			goto out;
+		}
+		if (strcmp (sections[1], "true") == 0) {
+			pk_backend_allow_interrupt (backend, TRUE);
+		} else if (strcmp (sections[1], "false") == 0) {
+			pk_backend_allow_interrupt (backend, FALSE);
+		} else {
+			pk_warning ("invalid section '%s'", sections[1]);
+			ret = FALSE;
+			goto out;
+		}
+	} else if (strcmp (command, "no-percentage-updates") == 0) {
+		if (size != 1) {
+			g_error ("invalid command '%s'", command);
+			ret = FALSE;
+			goto out;
+		}
+		pk_backend_no_percentage_updates (backend);
+	} else {
+		pk_warning ("invalid command '%s'", command);
+	}
+out:
+	g_strfreev (sections);
+	return ret;
+}
+
+/**
+ * pk_backend_spawn_finished_cb:
+ **/
+static void
+pk_backend_spawn_finished_cb (PkSpawn *spawn, gint exitcode, PkBackend *backend)
+{
+	PkTaskExit exit;
+	pk_debug ("unref'ing spawn %p, exit code %i", spawn, exitcode);
+	g_object_unref (spawn);
+
+	/* only emit success with a zero exit code */
+	if (exitcode == 0) {
+		exit = PK_TASK_EXIT_SUCCESS;
+	} else {
+		exit = PK_TASK_EXIT_FAILED;
+	}
+	pk_backend_finished (backend, exit);
+}
+
+/**
+ * pk_backend_spawn_stdout_cb:
+ **/
+static void
+pk_backend_spawn_stdout_cb (PkSpawn *spawn, const gchar *line, PkBackend *backend)
+{
+	pk_debug ("stdout from %p = '%s'", spawn, line);
+	pk_backend_parse_common_output (backend, line);
+}
+
+/**
+ * pk_backend_spawn_stderr_cb:
+ **/
+static void
+pk_backend_spawn_stderr_cb (PkSpawn *spawn, const gchar *line, PkBackend *backend)
+{
+	pk_debug ("stderr from %p = '%s'", spawn, line);
+	pk_backend_parse_common_error (backend, line);
+}
+
+/**
+ * pk_backend_spawn_helper_internal:
+ **/
+static gboolean
+pk_backend_spawn_helper_internal (PkBackend *backend, const gchar *script, const gchar *argument)
+{
+	gboolean ret;
+	gchar *filename;
+	gchar *command;
+
+	/* build script */
+	filename = g_build_filename (DATADIR, "PackageKit", "helpers", script, NULL);
+
+	if (argument != NULL) {
+		command = g_strdup_printf ("%s %s", filename, argument);
+	} else {
+		command = g_strdup (filename);
+	}
+
+	backend->priv->spawn = pk_spawn_new ();
+	g_signal_connect (backend->priv->spawn, "finished",
+			  G_CALLBACK (pk_backend_spawn_finished_cb), backend);
+	g_signal_connect (backend->priv->spawn, "stdout",
+			  G_CALLBACK (pk_backend_spawn_stdout_cb), backend);
+	g_signal_connect (backend->priv->spawn, "stderr",
+			  G_CALLBACK (pk_backend_spawn_stderr_cb), backend);
+	ret = pk_spawn_command (backend->priv->spawn, command);
+	if (ret == FALSE) {
+		g_object_unref (backend->priv->spawn);
+		pk_backend_error_code (backend, PK_TASK_ERROR_CODE_INTERNAL_ERROR, "Spawn of helper '%s' failed", command);
+		pk_backend_finished (backend, PK_TASK_EXIT_FAILED);
+	}
+	g_free (filename);
+	g_free (command);
+	return ret;
+}
+
+/**
+ * pk_backend_spawn_kill:
+ **/
+gboolean
+pk_backend_spawn_kill (PkBackend *backend)
+{
+	if (backend->priv->spawn == NULL) {
+		pk_warning ("cannot kill missing process");
+		return FALSE;
+	}
+	pk_spawn_kill (backend->priv->spawn);
+	return TRUE;
+}
+
+/**
+ * pk_backend_spawn_helper:
+ **/
+gboolean
+pk_backend_spawn_helper (PkBackend *backend, const gchar *script, ...)
+{
+	gboolean ret;
+	va_list args;
+	gchar *arguments;
+
+	/* get the argument list */
+	va_start (args, script);
+	arguments = g_strjoinv (" ", (gchar **)(void *)args);
+	va_end (args);
+
+	ret = pk_backend_spawn_helper_internal (backend, script, arguments);
+	g_free (arguments);
+	return ret;
+}
+
+/**
+ * pk_backend_not_implemented_yet:
+ **/
+gboolean
+pk_backend_not_implemented_yet (PkBackend *backend, const gchar *method)
+{
+	pk_backend_error_code (backend, PK_TASK_ERROR_CODE_NOT_SUPPORTED, "the method '%s' is not implemented yet", method);
+	pk_backend_finished (backend, PK_TASK_EXIT_FAILED);
+	return TRUE;
+}
+
+/**
+ * pk_backend_change_percentage:
+ **/
+gboolean
+pk_backend_change_percentage (PkBackend *backend, guint percentage)
+{
+	g_return_val_if_fail (backend != NULL, FALSE);
+	g_return_val_if_fail (PK_IS_BACKEND (backend), FALSE);
+	pk_debug ("emit percentage-changed %i", percentage);
+	g_signal_emit (backend, signals [PK_TASK_PERCENTAGE_CHANGED], 0, percentage);
+	return TRUE;
+}
+
+/**
+ * pk_backend_change_sub_percentage:
+ **/
+gboolean
+pk_backend_change_sub_percentage (PkBackend *backend, guint percentage)
+{
+	g_return_val_if_fail (backend != NULL, FALSE);
+	g_return_val_if_fail (PK_IS_BACKEND (backend), FALSE);
+	pk_debug ("emit sub-percentage-changed %i", percentage);
+	g_signal_emit (backend, signals [PK_TASK_SUB_PERCENTAGE_CHANGED], 0, percentage);
+	return TRUE;
+}
+
+/**
+ * pk_backend_set_job_role:
+ **/
+gboolean
+pk_backend_set_job_role (PkBackend *backend, PkTaskRole role, const gchar *package_id)
+{
+	g_return_val_if_fail (backend != NULL, FALSE);
+	g_return_val_if_fail (PK_IS_BACKEND (backend), FALSE);
+
+	/* Should only be called once... */
+	if (backend->priv->role != PK_TASK_ROLE_UNKNOWN) {
+		pk_error ("cannot set role more than once, already %i", backend->priv->role);
+	}
+	pk_debug ("setting role to %i (%s)", role, package_id);
+	backend->priv->role = role;
+	backend->priv->package_id = g_strdup (package_id);
+	return TRUE;
+}
+
+/**
+ * pk_backend_change_job_status:
+ **/
+gboolean
+pk_backend_change_job_status (PkBackend *backend, PkTaskStatus status)
+{
+	g_return_val_if_fail (backend != NULL, FALSE);
+	g_return_val_if_fail (PK_IS_BACKEND (backend), FALSE);
+	backend->priv->status = status;
+	pk_debug ("emiting job-status-changed %i", status);
+	g_signal_emit (backend, signals [PK_TASK_JOB_STATUS_CHANGED], 0, status);
+	return TRUE;
+}
+
+/**
+ * pk_backend_package:
+ **/
+gboolean
+pk_backend_package (PkBackend *backend, guint value, const gchar *package, const gchar *summary)
+{
+	g_return_val_if_fail (backend != NULL, FALSE);
+	g_return_val_if_fail (PK_IS_BACKEND (backend), FALSE);
+
+	pk_debug ("emit package %i, %s, %s", value, package, summary);
+	g_signal_emit (backend, signals [PK_TASK_PACKAGE], 0, value, package, summary);
+
+	return TRUE;
+}
+
+/**
+ * pk_backend_require_restart:
+ **/
+gboolean
+pk_backend_require_restart (PkBackend *backend, PkTaskRestart restart, const gchar *details)
+{
+	g_return_val_if_fail (backend != NULL, FALSE);
+	g_return_val_if_fail (PK_IS_BACKEND (backend), FALSE);
+
+	pk_debug ("emit require-restart %i, %s", restart, details);
+	g_signal_emit (backend, signals [PK_TASK_REQUIRE_RESTART], 0, restart, details);
+
+	return TRUE;
+}
+
+/**
+ * pk_backend_description:
+ **/
+gboolean
+pk_backend_description (PkBackend *backend, const gchar *package, PkTaskGroup group,
+		     const gchar *description, const gchar *url)
+{
+	g_return_val_if_fail (backend != NULL, FALSE);
+	g_return_val_if_fail (PK_IS_BACKEND (backend), FALSE);
+
+	pk_debug ("emit description %s, %i, %s, %s", package, group, description, url);
+	g_signal_emit (backend, signals [PK_TASK_DESCRIPTION], 0, package, group, description, url);
+
+	return TRUE;
+}
+
+/**
+ * pk_backend_error_code:
+ **/
+gboolean
+pk_backend_error_code (PkBackend *backend, PkTaskErrorCode code, const gchar *format, ...)
+{
+	va_list args;
+	gchar buffer[1025];
+
+	g_return_val_if_fail (backend != NULL, FALSE);
+	g_return_val_if_fail (PK_IS_BACKEND (backend), FALSE);
+
+	va_start (args, format);
+	g_vsnprintf (buffer, 1024, format, args);
+	va_end (args);
+
+	pk_debug ("emit error-code %i, %s", code, buffer);
+	g_signal_emit (backend, signals [PK_TASK_ERROR_CODE], 0, code, buffer);
+
+	return TRUE;
+}
+
+/**
+ * pk_backend_get_job_status:
+ **/
+gboolean
+pk_backend_get_job_status (PkBackend *backend, PkTaskStatus *status)
+{
+	g_return_val_if_fail (backend != NULL, FALSE);
+	g_return_val_if_fail (PK_IS_BACKEND (backend), FALSE);
+
+	/* check to see if we have an action */
+	if (backend->priv->assigned == FALSE) {
+		pk_warning ("Not assigned");
+		return FALSE;
+	}
+	*status = backend->priv->status;
+	return TRUE;
+}
+
+/**
+ * pk_backend_get_job_role:
+ **/
+gboolean
+pk_backend_get_job_role (PkBackend *backend, PkTaskRole *role, const gchar **package_id)
+{
+	g_return_val_if_fail (backend != NULL, FALSE);
+	g_return_val_if_fail (PK_IS_BACKEND (backend), FALSE);
+
+	/* check to see if we have an action */
+	if (backend->priv->assigned == FALSE) {
+		pk_warning ("Not assigned");
+		return FALSE;
+	}
+	*role = backend->priv->role;
+	*package_id = g_strdup (backend->priv->package_id);
+	return TRUE;
+}
+
+/**
+ * pk_backend_finished_idle:
+ **/
+static gboolean
+pk_backend_finished_idle (gpointer data)
+{
+	PkBackend *backend = (PkBackend *) data;
+	pk_debug ("emit finished %i", backend->priv->exit);
+	g_signal_emit (backend, signals [PK_TASK_FINISHED], 0, backend->priv->exit);
+	return FALSE;
+}
+
+/**
+ * pk_backend_finished:
+ **/
+gboolean
+pk_backend_finished (PkBackend *backend, PkTaskExit exit)
+{
+	g_return_val_if_fail (backend != NULL, FALSE);
+	g_return_val_if_fail (PK_IS_BACKEND (backend), FALSE);
+
+	/* we have to run this idle as the command may finish before the job
+	 * has been sent to the client. I love async... */
+	pk_debug ("adding finished %p to idle loop", backend);
+	backend->priv->exit = exit;
+	g_idle_add (pk_backend_finished_idle, backend);
+	return TRUE;
+}
+
+/**
+ * pk_backend_no_percentage_updates:
+ **/
+gboolean
+pk_backend_no_percentage_updates (PkBackend *backend)
+{
+	g_return_val_if_fail (backend != NULL, FALSE);
+	g_return_val_if_fail (PK_IS_BACKEND (backend), FALSE);
+
+	pk_debug ("emit no-percentage-updates");
+	g_signal_emit (backend, signals [PK_TASK_NO_PERCENTAGE_UPDATES], 0);
+	return TRUE;
+}
+
+/**
+ * pk_backend_allow_interrupt:
+ **/
+gboolean
+pk_backend_allow_interrupt (PkBackend *backend, gboolean allow_restart)
+{
+	g_return_val_if_fail (backend != NULL, FALSE);
+	g_return_val_if_fail (PK_IS_BACKEND (backend), FALSE);
+
+	pk_debug ("emit allow-interrupt %i", allow_restart);
+	backend->priv->is_killable = allow_restart;
+	g_signal_emit (backend, signals [PK_TASK_ALLOW_INTERRUPT], 0);
+	return TRUE;
+}
+
+
+/**
+ * pk_backend_cancel_job_try:
+ */
+gboolean
+pk_backend_cancel_job_try (PkBackend *backend)
+{
+	g_return_val_if_fail (backend != NULL, FALSE);
+	if (backend->desc->cancel_job_try == NULL) {
+		pk_backend_not_implemented_yet (backend, "CancelJobTry");
+		return FALSE;
+	}
+	/* check to see if we have an action */
+	if (backend->priv->assigned == FALSE) {
+		pk_warning ("Not assigned");
+		return FALSE;
+	}
+	/* check if it's safe to kill */
+	if (backend->priv->is_killable == FALSE) {
+		pk_warning ("tried to kill a process that is not safe to kill");
+		return FALSE;
+	}
+	if (backend->priv->spawn == NULL) {
+		pk_warning ("tried to kill a process that does not exist");
+		return FALSE;
+	}
+	backend->desc->cancel_job_try (backend);
+	return TRUE;
+}
+
+/**
+ * pk_backend_get_depends:
+ */
+gboolean
+pk_backend_get_depends (PkBackend *backend, const gchar *package_id)
+{
+	g_return_val_if_fail (backend != NULL, FALSE);
+	if (backend->desc->get_depends == NULL) {
+		pk_backend_not_implemented_yet (backend, "GetDepends");
+		return FALSE;
+	}
+	backend->desc->get_depends (backend, package_id);
+	backend->priv->assigned = TRUE;
+	return TRUE;
+}
+
+/**
+ * pk_backend_get_description:
+ */
+gboolean
+pk_backend_get_description (PkBackend *backend, const gchar *package_id)
+{
+	g_return_val_if_fail (backend != NULL, FALSE);
+	if (backend->desc->get_description == NULL) {
+		pk_backend_not_implemented_yet (backend, "GetDescription");
+		return FALSE;
+	}
+	backend->desc->get_description (backend, package_id);
+	backend->priv->assigned = TRUE;
+	return TRUE;
+}
+
+/**
+ * pk_backend_get_requires:
+ */
+gboolean
+pk_backend_get_requires (PkBackend *backend, const gchar *package_id)
+{
+	g_return_val_if_fail (backend != NULL, FALSE);
+	if (backend->desc->get_requires == NULL) {
+		pk_backend_not_implemented_yet (backend, "GetRequires");
+		return FALSE;
+	}
+	backend->desc->get_requires (backend, package_id);
+	backend->priv->assigned = TRUE;
+	return TRUE;
+}
+
+/**
+ * pk_backend_get_updates:
+ */
+gboolean
+pk_backend_get_updates (PkBackend *backend)
+{
+	g_return_val_if_fail (backend != NULL, FALSE);
+	if (backend->desc->get_updates == NULL) {
+		pk_backend_not_implemented_yet (backend, "GetUpdates");
+		return FALSE;
+	}
+	backend->desc->get_updates (backend);
+	backend->priv->assigned = TRUE;
+	return TRUE;
+}
+
+/**
+ * pk_backend_install_package:
+ */
+gboolean
+pk_backend_install_package (PkBackend *backend, const gchar *package_id)
+{
+	g_return_val_if_fail (backend != NULL, FALSE);
+	if (backend->desc->install_package == NULL) {
+		pk_backend_not_implemented_yet (backend, "InstallPackage");
+		return FALSE;
+	}
+	backend->desc->install_package (backend, package_id);
+	backend->priv->assigned = TRUE;
+	return TRUE;
+}
+
+/**
+ * pk_backend_refresh_cache:
+ */
+gboolean
+pk_backend_refresh_cache (PkBackend *backend, gboolean force)
+{
+	g_return_val_if_fail (backend != NULL, FALSE);
+	if (backend->desc->refresh_cache == NULL) {
+		pk_backend_not_implemented_yet (backend, "RefreshCache");
+		return FALSE;
+	}
+	backend->desc->refresh_cache (backend, force);
+	backend->priv->assigned = TRUE;
+	return TRUE;
+}
+
+/**
+ * pk_backend_remove_package:
+ */
+gboolean
+pk_backend_remove_package (PkBackend *backend, const gchar *package_id, gboolean allow_deps)
+{
+	g_return_val_if_fail (backend != NULL, FALSE);
+	if (backend->desc->remove_package == NULL) {
+		pk_backend_not_implemented_yet (backend, "RemovePackage");
+		return FALSE;
+	}
+	backend->desc->remove_package (backend, package_id, allow_deps);
+	backend->priv->assigned = TRUE;
+	return TRUE;
+}
+
+/**
+ * pk_backend_search_details:
+ */
+gboolean
+pk_backend_search_details (PkBackend *backend, const gchar *filter, const gchar *search)
+{
+	g_return_val_if_fail (backend != NULL, FALSE);
+	if (backend->desc->search_details == NULL) {
+		pk_backend_not_implemented_yet (backend, "SearchDetails");
+		return FALSE;
+	}
+	backend->desc->search_details (backend, filter, search);
+	backend->priv->assigned = TRUE;
+	return TRUE;
+}
+
+/**
+ * pk_backend_search_file:
+ */
+gboolean
+pk_backend_search_file (PkBackend *backend, const gchar *filter, const gchar *search)
+{
+	g_return_val_if_fail (backend != NULL, FALSE);
+	if (backend->desc->search_file == NULL) {
+		pk_backend_not_implemented_yet (backend, "SearchFile");
+		return FALSE;
+	}
+	backend->desc->search_file (backend, filter, search);
+	backend->priv->assigned = TRUE;
+	return TRUE;
+}
+
+/**
+ * pk_backend_search_group:
+ */
+gboolean
+pk_backend_search_group (PkBackend *backend, const gchar *filter, const gchar *search)
+{
+	g_return_val_if_fail (backend != NULL, FALSE);
+	if (backend->desc->search_group == NULL) {
+		pk_backend_not_implemented_yet (backend, "SearchGroup");
+		return FALSE;
+	}
+	backend->desc->search_group (backend, filter, search);
+	backend->priv->assigned = TRUE;
+	return TRUE;
+}
+
+/**
+ * pk_backend_search_name:
+ */
+gboolean
+pk_backend_search_name (PkBackend *backend, const gchar *filter, const gchar *search)
+{
+	g_return_val_if_fail (backend != NULL, FALSE);
+	if (backend->desc->search_name == NULL) {
+		pk_backend_not_implemented_yet (backend, "SearchName");
+		return FALSE;
+	}
+	backend->desc->search_name (backend, filter, search);
+	backend->priv->assigned = TRUE;
+	return TRUE;
+}
+
+/**
+ * pk_backend_update_package:
+ */
+gboolean
+pk_backend_update_package (PkBackend *backend, const gchar *package_id)
+{
+	g_return_val_if_fail (backend != NULL, FALSE);
+	if (backend->desc->update_package == NULL) {
+		pk_backend_not_implemented_yet (backend, "UpdatePackage");
+		return FALSE;
+	}
+	backend->desc->update_package (backend, package_id);
+	backend->priv->assigned = TRUE;
+	return TRUE;
+}
+
+/**
+ * pk_backend_update_system:
+ */
+gboolean
+pk_backend_update_system (PkBackend *backend)
+{
+	g_return_val_if_fail (backend != NULL, FALSE);
+	if (backend->desc->update_system == NULL) {
+		pk_backend_not_implemented_yet (backend, "UpdateSystem");
+		return FALSE;
+	}
+	backend->desc->update_system (backend);
+	backend->priv->assigned = TRUE;
+	return TRUE;
+}
+
+/**
+ * pk_backend_get_runtime:
+ */
+gdouble
+pk_backend_get_runtime (PkBackend *backend)
+{
+	return g_timer_elapsed (backend->priv->timer, NULL);
+}
+
+/**
+ * pk_backend_network_is_online:
+ */
+gboolean
+pk_backend_network_is_online (PkBackend *backend)
+{
+	return pk_network_is_online (backend->priv->network);
+}
+
+/**
+ * pk_backend_finalize:
+ **/
+static void
+pk_backend_finalize (GObject *object)
+{
+	PkBackend *backend;
+	g_return_if_fail (object != NULL);
+	g_return_if_fail (PK_IS_BACKEND (object));
+
+	backend = PK_BACKEND (object);
+
+	if (backend->desc != NULL) {
+		if (backend->desc->destroy != NULL) {
+			backend->desc->destroy (backend);
+		}		
+	}
+
+	g_free (backend->priv->name);
+	g_debug ("g_module_close(%p)", backend->priv->handle);
+	g_module_close (backend->priv->handle);
+	g_timer_destroy (backend->priv->timer);
+	g_object_unref (backend->priv->network);
+
+	G_OBJECT_CLASS (pk_backend_parent_class)->finalize (object);
+}
+
+/**
+ * pk_backend_class_init:
+ **/
+static void
+pk_backend_class_init (PkBackendClass *klass)
+{
+	GObjectClass *object_class = G_OBJECT_CLASS (klass);
+
+	object_class->finalize = pk_backend_finalize;
+
+	signals [PK_TASK_JOB_STATUS_CHANGED] =
+		g_signal_new ("job-status-changed",
+			      G_TYPE_FROM_CLASS (object_class), G_SIGNAL_RUN_LAST,
+			      0, NULL, NULL, g_cclosure_marshal_VOID__UINT,
+			      G_TYPE_NONE, 1, G_TYPE_UINT);
+	signals [PK_TASK_PERCENTAGE_CHANGED] =
+		g_signal_new ("percentage-changed",
+			      G_TYPE_FROM_CLASS (object_class), G_SIGNAL_RUN_LAST,
+			      0, NULL, NULL, g_cclosure_marshal_VOID__UINT,
+			      G_TYPE_NONE, 1, G_TYPE_UINT);
+	signals [PK_TASK_SUB_PERCENTAGE_CHANGED] =
+		g_signal_new ("sub-percentage-changed",
+			      G_TYPE_FROM_CLASS (object_class), G_SIGNAL_RUN_LAST,
+			      0, NULL, NULL, g_cclosure_marshal_VOID__UINT,
+			      G_TYPE_NONE, 1, G_TYPE_UINT);
+	signals [PK_TASK_PACKAGE] =
+		g_signal_new ("package",
+			      G_TYPE_FROM_CLASS (object_class), G_SIGNAL_RUN_LAST,
+			      0, NULL, NULL, pk_marshal_VOID__UINT_STRING_STRING,
+			      G_TYPE_NONE, 3, G_TYPE_UINT, G_TYPE_STRING, G_TYPE_STRING);
+	signals [PK_TASK_REQUIRE_RESTART] =
+		g_signal_new ("require-restart",
+			      G_TYPE_FROM_CLASS (object_class), G_SIGNAL_RUN_LAST,
+			      0, NULL, NULL, pk_marshal_VOID__UINT_STRING,
+			      G_TYPE_NONE, 2, G_TYPE_UINT, G_TYPE_STRING);
+	signals [PK_TASK_DESCRIPTION] =
+		g_signal_new ("description",
+			      G_TYPE_FROM_CLASS (object_class), G_SIGNAL_RUN_LAST,
+			      0, NULL, NULL, pk_marshal_VOID__STRING_UINT_STRING_STRING,
+			      G_TYPE_NONE, 4, G_TYPE_STRING, G_TYPE_UINT, G_TYPE_STRING, G_TYPE_STRING);
+	signals [PK_TASK_ERROR_CODE] =
+		g_signal_new ("error-code",
+			      G_TYPE_FROM_CLASS (object_class), G_SIGNAL_RUN_LAST,
+			      0, NULL, NULL, pk_marshal_VOID__UINT_STRING,
+			      G_TYPE_NONE, 2, G_TYPE_UINT, G_TYPE_STRING);
+	signals [PK_TASK_FINISHED] =
+		g_signal_new ("finished",
+			      G_TYPE_FROM_CLASS (object_class), G_SIGNAL_RUN_LAST,
+			      0, NULL, NULL, g_cclosure_marshal_VOID__UINT,
+			      G_TYPE_NONE, 1, G_TYPE_UINT);
+	signals [PK_TASK_NO_PERCENTAGE_UPDATES] =
+		g_signal_new ("no-percentage-updates",
+			      G_TYPE_FROM_CLASS (object_class), G_SIGNAL_RUN_LAST,
+			      0, NULL, NULL, g_cclosure_marshal_VOID__VOID,
+			      G_TYPE_NONE, 0);
+	signals [PK_TASK_ALLOW_INTERRUPT] =
+		g_signal_new ("allow-interrupt",
+			      G_TYPE_FROM_CLASS (object_class), G_SIGNAL_RUN_LAST,
+			      0, NULL, NULL, g_cclosure_marshal_VOID__BOOLEAN,
+			      G_TYPE_NONE, 1, G_TYPE_BOOLEAN);
+
+	g_type_class_add_private (klass, sizeof (PkBackendPrivate));
+}
+
+/**
+ * pk_backend_init:
+ **/
+static void
+pk_backend_init (PkBackend *backend)
+{
+	backend->priv = PK_BACKEND_GET_PRIVATE (backend);
+	backend->priv->timer = g_timer_new ();
+	backend->priv->assigned = FALSE;
+	backend->priv->is_killable = FALSE;
+	backend->priv->spawn = NULL;
+	backend->priv->package_id = NULL;
+	backend->priv->role = PK_TASK_ROLE_UNKNOWN;
+	backend->priv->status = PK_TASK_STATUS_UNKNOWN;
+	backend->priv->exit = PK_TASK_EXIT_UNKNOWN;
+	backend->priv->network = pk_network_new ();
+}
+
+/**
+ * pk_backend_new:
+ **/
+PkBackend *
+pk_backend_new (void)
+{
+	PkBackend *backend;
+	backend = g_object_new (PK_TYPE_BACKEND, NULL);
+	return PK_BACKEND (backend);
+}
+
diff --git a/src/pk-backend.h b/src/pk-backend.h
new file mode 100644
index 0000000..5e8e5eb
--- /dev/null
+++ b/src/pk-backend.h
@@ -0,0 +1,127 @@
+/* -*- Mode: C; tab-width: 8; indent-tabs-mode: t; c-basic-offset: 8 -*-
+ *
+ * Copyright (C) 2007 Richard Hughes <richard at hughsie.com>
+ *
+ * Licensed under the GNU General Public License Version 2
+ *
+ * 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 2 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, write to the Free Software
+ * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+ */
+
+#ifndef __PK_BACKEND_H
+#define __PK_BACKEND_H
+
+#include <glib.h>
+#include <pk-task-utils.h>
+
+G_BEGIN_DECLS
+
+typedef struct _PkBackend PkBackend;
+typedef struct _PkBackendDesc PkBackendDesc;
+
+/* used by backends that implement an interface */
+gboolean	 pk_backend_change_percentage		(PkBackend	*backend,
+							 guint		 percentage);
+gboolean	 pk_backend_change_sub_percentage	(PkBackend	*backend,
+							 guint		 percentage);
+gboolean	 pk_backend_change_job_status		(PkBackend	*backend,
+							 PkTaskStatus	 status);
+gboolean	 pk_backend_set_job_role		(PkBackend	*backend,
+							 PkTaskRole	 role,
+							 const gchar	*package_id);
+gboolean	 pk_backend_no_percentage_updates	(PkBackend	*backend);
+gboolean	 pk_backend_finished			(PkBackend	*backend,
+							 PkTaskExit	 exit);
+gboolean	 pk_backend_package			(PkBackend	*backend,
+							 guint		 value,
+							 const gchar	*package_id,
+							 const gchar	*summary);
+gboolean	 pk_backend_require_restart		(PkBackend	*backend,
+							 PkTaskRestart	 restart,
+							 const gchar	*details);
+gboolean	 pk_backend_description			(PkBackend	*backend,
+							 const gchar	*package,
+							 PkTaskGroup	 group,
+							 const gchar	*description,
+							 const gchar	*url);
+gboolean	 pk_backend_error_code			(PkBackend	*backend,
+							 guint		 code,
+							 const gchar	*details, ...);
+gboolean	 pk_backend_spawn_helper		(PkBackend	*backend,
+							 const gchar	*script, ...);
+gboolean	 pk_backend_spawn_kill			(PkBackend	*backend);
+gboolean	 pk_backend_not_implemented_yet		(PkBackend	*backend,
+							 const gchar	*method);
+gboolean	 pk_backend_allow_interrupt		(PkBackend	*backend,
+							 gboolean	 allow_restart);
+gboolean	 pk_backend_network_is_online		(PkBackend	*backend);
+
+/**
+ * PkBackendDesc:
+ */
+struct _PkBackendDesc {
+	const char	*description;
+	const char	*version;
+	const char	*author;
+	void		(*initialize)		(PkBackend *backend);
+	void		(*destroy)		(PkBackend *backend);
+	void		(*cancel_job_try)	(PkBackend *backend);
+	void		(*get_depends)		(PkBackend *backend, const gchar *package_id);
+	void		(*get_description)	(PkBackend *backend, const gchar *package_id);
+	void		(*get_requires)		(PkBackend *backend, const gchar *package_id);
+	void		(*get_updates)		(PkBackend *backend);
+	void		(*install_package)	(PkBackend *backend, const gchar *package_id);
+	void		(*refresh_cache)	(PkBackend *backend, gboolean force);
+	void		(*remove_package)	(PkBackend *backend, const gchar *package_id, gboolean allow_deps);
+	void		(*search_details)	(PkBackend *backend, const gchar *filter, const gchar *search);
+	void		(*search_file)		(PkBackend *backend, const gchar *filter, const gchar *search);
+	void		(*search_group)		(PkBackend *backend, const gchar *filter, const gchar *search);
+	void		(*search_name)		(PkBackend *backend, const gchar *filter, const gchar *search);
+	void		(*update_package)	(PkBackend *backend, const gchar *package_id);
+	void		(*update_system)	(PkBackend *backend);
+	gpointer	padding[12];
+};
+
+#define PK_BACKEND_OPTIONS(description, version, author, initialize, destroy, \
+			   cancel_job_try, get_depends, get_description, \
+			   get_requires, get_updates, install_package, \
+			   refresh_cache, remove_package, search_details, \
+			   search_file, search_group, search_name, \
+			   update_package, update_system) \
+	G_MODULE_EXPORT const PkBackendDesc pk_backend_desc = { \
+		description, \
+		version, \
+		author, \
+		initialize, \
+		destroy, \
+		cancel_job_try, \
+		get_depends, \
+		get_description, \
+		get_requires, \
+		get_updates, \
+		install_package, \
+		refresh_cache, \
+		remove_package, \
+		search_details, \
+		search_file, \
+		search_group, \
+		search_name, \
+		update_package, \
+		update_system, \
+		{0} \
+	}
+
+G_END_DECLS
+
+#endif /* __PK_BACKEND_H */



More information about the PackageKit mailing list