[packagekit] packagekit: Branch 'master' - 42 commits

Richard Hughes hughsient at kemper.freedesktop.org
Mon Sep 17 08:13:17 PDT 2007


 AUTHORS                                  |    2 
 backends/BACKENDS                        |    4 
 backends/alpm/TODO                       |    4 
 backends/alpm/pk-backend-alpm.c          |  238 +++++++++++++++++-----
 backends/apt/pk-backend-apt.cpp          |  139 ++++---------
 backends/box/helpers/Makefile.am         |    5 
 backends/box/helpers/install-package.sh  |   15 +
 backends/box/helpers/remove-package.sh   |   15 +
 backends/box/helpers/update-package.sh   |   15 +
 backends/box/pk-backend-box.c            |  144 +++++++------
 backends/conary/helpers/Makefile.am      |    2 
 backends/conary/helpers/conaryBackend.py |   77 ++++---
 backends/conary/pk-backend-conary.c      |    4 
 backends/dummy/pk-backend-dummy.c        |   28 +-
 backends/test-backend.sh                 |   29 +-
 backends/test/Makefile.am                |   37 +++
 backends/test/helpers/Makefile.am        |   15 +
 backends/test/helpers/search-name.sh     |   19 +
 backends/test/pk-backend-test-fail.c     |   54 +----
 backends/test/pk-backend-test-nop.c      |   50 ++++
 backends/test/pk-backend-test-spawn.c    |   63 +++++
 backends/test/pk-backend-test-succeed.c  |   32 +--
 backends/test/pk-backend-test-thread.c   |  110 ++++++++++
 backends/yum/helpers/Makefile.am         |    2 
 backends/yum/pk-backend-yum.c            |    6 
 client/pk-monitor.c                      |    3 
 configure.ac                             |    1 
 docs/pk-structure.png                    |binary
 docs/pk-structure.svg                    |   93 ++++++--
 docs/test2                               |    1 
 libpackagekit/pk-enum-list.c             |   29 ++
 libpackagekit/pk-job-list.c              |    4 
 libpackagekit/pk-task-list.c             |    6 
 python/pkt                               |    7 
 src/Makefile.am                          |    4 
 src/pk-backend.c                         |  255 +++++++++++++++++-------
 src/pk-backend.h                         |   13 +
 src/pk-engine.c                          |   86 ++++++--
 src/pk-engine.h                          |    1 
 src/pk-marshal.list                      |    1 
 src/pk-self-test.c                       |    7 
 src/pk-thread-list.c                     |  327 +++++++++++++++++++++++++++++++
 src/pk-thread-list.h                     |   64 ++++++
 src/pk-transaction-db.c                  |  220 ++++++++++++++++++--
 src/pk-transaction-db.h                  |   11 +
 45 files changed, 1762 insertions(+), 480 deletions(-)

New commits:
diff-tree b031d7f0c8f271ce1ea86915df4f50447231effd (from e7546f56bbaaedb6737e308c54ae4991442b4518)
Author: Tom Parker <palfrey at tevp.net>
Date:   Mon Sep 17 15:13:55 2007 +0200

    Check for local .so's as well

diff --git a/src/pk-backend.c b/src/pk-backend.c
index 4afcce1..338d0c3 100644
--- a/src/pk-backend.c
+++ b/src/pk-backend.c
@@ -105,7 +105,11 @@ pk_backend_build_library_path (PkBackend
 	g_return_val_if_fail (backend != NULL, NULL);
 
 	filename = g_strdup_printf ("libpk_backend_%s.so", backend->priv->name);
-	path = g_build_filename (LIBDIR, "packagekit-backend", filename, NULL);
+	path = g_build_filename ("..", "backends", backend->priv->name, ".libs", filename, NULL);
+	if (g_file_test (path, G_FILE_TEST_EXISTS) == FALSE) {
+		g_free (path);
+		path = g_build_filename (LIBDIR, "packagekit-backend", filename, NULL);
+	}
 	g_free (filename);
 	pk_debug ("dlopening '%s'", path);
 
diff-tree e7546f56bbaaedb6737e308c54ae4991442b4518 (from 2a01c96d30ea1f87071404da9a2867de8a6522b2)
Author: Tom Parker <palfrey at tevp.net>
Date:   Mon Sep 17 16:43:18 2007 +0200

    Sanitize command failures in pkt

diff --git a/python/pkt b/python/pkt
index e8b789a..3bbc44d 100755
--- a/python/pkt
+++ b/python/pkt
@@ -37,18 +37,21 @@ except PackageKitNotStarted:
 
 def search(*args):
 	patt = " ".join(args[0])
+	if len(patt)==0:
+		print "need something to search for"
+		raise PackageKitJobFailure
 	return p.SearchName(patt)
 
 def desc(*args):
 	if len(args)!=1 or len(args[0])!=1:
 		print "desc only takes single arg"
-		return -1
+		raise PackageKitJobFailure
 	return p.GetDescription(args[0][0])
 
 def update(args):
 	if len(args)>0 and len(args[0])>0:
 		print "update doesn't take args"
-		return -1
+		raise PackageKitJobFailure
 	return p.RefreshCache()
 
 def usage():
diff-tree 2a01c96d30ea1f87071404da9a2867de8a6522b2 (from e2a5f7c666a1b072835473a90fcf0fadd5175842)
Author: Tom Parker <palfrey at tevp.net>
Date:   Mon Sep 17 16:41:53 2007 +0200

    Hand input data to pk_backend_thread_create
    pk_backend_thread_helper had a potential brown-paper-bag bug,
    in that it discarded any input data from users....

diff --git a/src/pk-backend.c b/src/pk-backend.c
index ebf4d5f..4afcce1 100644
--- a/src/pk-backend.c
+++ b/src/pk-backend.c
@@ -186,7 +186,7 @@ pk_backend_thread_create (PkBackend *bac
 gboolean
 pk_backend_thread_helper (PkBackend *backend, PkBackendThreadFunc func, gpointer data)
 {
-	if (pk_backend_thread_create (backend, func, NULL) == FALSE) {
+	if (pk_backend_thread_create (backend, func, data) == FALSE) {
 		pk_backend_error_code (backend, PK_ERROR_ENUM_CREATE_THREAD_FAILED, "Failed to create thread");
 		pk_backend_finished (backend);
 		return FALSE;
diff-tree e2a5f7c666a1b072835473a90fcf0fadd5175842 (from 2067f9b659b677017c67fc412d8472e027743357)
Author: Tom Parker <palfrey at tevp.net>
Date:   Mon Sep 17 16:42:26 2007 +0200

    Add "unknown" license to apt get_description callbacks

diff --git a/backends/apt/pk-backend-apt.cpp b/backends/apt/pk-backend-apt.cpp
index e4a383e..0e65678 100644
--- a/backends/apt/pk-backend-apt.cpp
+++ b/backends/apt/pk-backend-apt.cpp
@@ -561,7 +561,7 @@ static gboolean backend_get_description_
 		pkgCache::VerIterator V = Plcy.GetCandidateVer(P);
 		GHashTable *pkg = PackageRecord(V);
 		pk_backend_description(backend,dt->pi->name,
-					PK_GROUP_ENUM_OTHER,(const gchar*)g_hash_table_lookup(pkg,"Description"),"");
+			"unknown", PK_GROUP_ENUM_OTHER,(const gchar*)g_hash_table_lookup(pkg,"Description"),"");
 		g_hash_table_unref(pkg);
 	}
 	return NULL;
@@ -614,7 +614,7 @@ backend_search_name (PkBackend *backend,
 
 static gboolean backend_search_file_thread (PkBackend *backend, gpointer data)
 {
-	search_task *st = (search_task*)data;
+	//search_task *st = (search_task*)data;
 	gchar *sdir = g_path_get_dirname(_config->Find("Dir::State::status").c_str());
 	gchar *ldir = g_build_filename(sdir,"info",NULL);
 	g_free(sdir);
diff-tree 2067f9b659b677017c67fc412d8472e027743357 (from 851961e30cf114848d815f9ebbc5669f2f8a9f45)
Author: Richard Hughes <richard at hughsie.com>
Date:   Mon Sep 17 15:24:13 2007 +0100

    update piture with threads

diff --git a/docs/pk-structure.png b/docs/pk-structure.png
index fc66b55..abda7e3 100644
Binary files a/docs/pk-structure.png and b/docs/pk-structure.png differ
diff --git a/docs/pk-structure.svg b/docs/pk-structure.svg
index d5784f4..2177e63 100644
--- a/docs/pk-structure.svg
+++ b/docs/pk-structure.svg
@@ -97,9 +97,9 @@
      objecttolerance="10"
      inkscape:pageopacity="0.0"
      inkscape:pageshadow="2"
-     inkscape:zoom="0.35"
-     inkscape:cx="349.65521"
-     inkscape:cy="293.55497"
+     inkscape:zoom="0.7"
+     inkscape:cx="367.26656"
+     inkscape:cy="499.46921"
      inkscape:document-units="px"
      inkscape:current-layer="layer1"
      showgrid="true"
@@ -226,14 +226,19 @@
     <text
        xml:space="preserve"
        style="font-size:12px;font-style:normal;font-weight:normal;fill:#000000;fill-opacity:1;stroke:none;stroke-width:1px;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1;font-family:Bitstream Vera Sans"
-       x="82.074219"
-       y="333.14343"
+       x="98.583984"
+       y="327.07898"
        id="text3217"><tspan
          sodipodi:role="line"
-         x="82.074219"
-         y="333.14343"
-         style="font-size:28px;text-align:center;text-anchor:middle"
-         id="tspan3221">DBUS</tspan></text>
+         x="98.583984"
+         y="327.07898"
+         style="font-size:20px;text-align:center;text-anchor:middle"
+         id="tspan3221">SYSTEM</tspan><tspan
+         sodipodi:role="line"
+         x="98.583984"
+         y="352.07898"
+         style="font-size:20px;text-align:center;text-anchor:middle"
+         id="tspan2229">DBUS</tspan></text>
     <path
        style="fill:none;fill-rule:evenodd;stroke:#000000;stroke-width:5.81893778;stroke-linecap:square;stroke-linejoin:miter;marker-start:url(#Arrow1Sstart);stroke-miterlimit:4;stroke-dasharray:none;stroke-opacity:1"
        d="M 325.32143,484.35568 C 325.32143,454.46904 325.32143,454.46904 325.32143,454.46904"
@@ -265,26 +270,26 @@
     <rect
        style="opacity:1;fill:#ff9955;fill-opacity:1;stroke:#000000;stroke-width:0;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1"
        id="rect5383"
-       width="245"
+       width="135"
        height="80"
        x="340"
        y="612.36218" />
     <text
        xml:space="preserve"
        style="font-size:12px;font-style:normal;font-weight:normal;fill:#000000;fill-opacity:1;stroke:none;stroke-width:1px;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1;font-family:Bitstream Vera Sans"
-       x="458.54688"
+       x="402.6875"
        y="643.63562"
        id="text5385"><tspan
          sodipodi:role="line"
-         x="458.54688"
+         x="402.6875"
          y="643.63562"
          style="font-size:28px;text-align:center;text-anchor:middle"
          id="tspan5387">Backend</tspan><tspan
          sodipodi:role="line"
-         x="458.54688"
+         x="402.6875"
          y="678.63562"
          style="font-size:28px;text-align:center;text-anchor:middle"
-         id="tspan5389">Task (compiled)</tspan></text>
+         id="tspan5389">Task</tspan></text>
     <path
        style="fill:none;fill-rule:evenodd;stroke:#000000;stroke-width:6;stroke-linecap:butt;stroke-linejoin:miter;marker-end:url(#Arrow1Send);stroke-miterlimit:4;stroke-dasharray:none;stroke-opacity:1"
        d="M 172.5,292.36218 L 277.5,372.36218"
@@ -308,7 +313,7 @@
        inkscape:connection-end="#rect5369" />
     <path
        style="fill:none;fill-rule:evenodd;stroke:#000000;stroke-width:6;stroke-linecap:butt;stroke-linejoin:miter;marker-end:url(#Arrow1Send);stroke-miterlimit:4;stroke-dasharray:none;stroke-opacity:1"
-       d="M 367.5,572.36218 L 415,612.36218"
+       d="M 349.16667,572.36218 L 378.33333,612.36218"
        id="path5403"
        inkscape:connector-type="polyline"
        inkscape:connection-start="#rect1884"
@@ -362,23 +367,23 @@
     <text
        xml:space="preserve"
        style="font-size:12px;font-style:normal;font-weight:normal;fill:#000000;fill-opacity:1;stroke:none;stroke-width:1px;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1;font-family:Bitstream Vera Sans"
-       x="401.85352"
-       y="723.14343"
+       x="378.4668"
+       y="727.20593"
        id="text8348"><tspan
          sodipodi:role="line"
-         x="401.85352"
-         y="723.14343"
-         style="font-size:28px;text-align:center;text-anchor:middle"
+         x="378.4668"
+         y="727.20593"
+         style="font-size:20px;text-align:center;text-anchor:middle"
          id="tspan8350">STDIN</tspan><tspan
          sodipodi:role="line"
-         x="401.85352"
-         y="758.14343"
-         style="font-size:28px;text-align:center;text-anchor:middle"
+         x="378.4668"
+         y="752.20593"
+         style="font-size:20px;text-align:center;text-anchor:middle"
          id="tspan2216">STDERR</tspan><tspan
          sodipodi:role="line"
-         x="401.85352"
-         y="793.14343"
-         style="font-size:28px;text-align:center;text-anchor:middle"
+         x="378.4668"
+         y="777.20593"
+         style="font-size:20px;text-align:center;text-anchor:middle"
          id="tspan2218">STDOUT</tspan></text>
     <path
        style="fill:none;fill-rule:evenodd;stroke:#000000;stroke-width:6;stroke-linecap:butt;stroke-linejoin:miter;marker-end:url(#Arrow1Send);stroke-miterlimit:4;stroke-dasharray:none;stroke-opacity:1"
@@ -394,5 +399,41 @@
        inkscape:connector-type="polyline"
        inkscape:connection-start="#rect8340"
        inkscape:connection-end="#rect1876" />
+    <rect
+       style="opacity:1;fill:#c8b7b7;fill-opacity:1;stroke:#000000;stroke-width:0;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1"
+       id="rect2213"
+       width="125"
+       height="25"
+       x="475"
+       y="612.36218" />
+    <text
+       xml:space="preserve"
+       style="font-size:12px;font-style:normal;font-weight:normal;fill:#000000;fill-opacity:1;stroke:none;stroke-width:1px;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1;font-family:Bitstream Vera Sans"
+       x="537.91016"
+       y="632.36218"
+       id="text2215"><tspan
+         sodipodi:role="line"
+         x="537.91016"
+         y="632.36218"
+         style="font-size:20px;text-align:center;text-anchor:middle"
+         id="tspan2219">Thread #1</tspan></text>
+    <rect
+       style="opacity:1;fill:#916f6f;fill-opacity:1;stroke:#000000;stroke-width:0;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1"
+       id="rect2223"
+       width="125"
+       height="25.101501"
+       x="475"
+       y="637.26068" />
+    <text
+       xml:space="preserve"
+       style="font-size:12px;font-style:normal;font-weight:normal;fill:#000000;fill-opacity:1;stroke:none;stroke-width:1px;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1;font-family:Bitstream Vera Sans"
+       x="537.91016"
+       y="657.36218"
+       id="text2225"><tspan
+         sodipodi:role="line"
+         x="537.91016"
+         y="657.36218"
+         style="font-size:20px;text-align:center;text-anchor:middle"
+         id="tspan2227">Thread #2</tspan></text>
   </g>
 </svg>
diff --git a/docs/test2 b/docs/test2
deleted file mode 100644
index 9daeafb..0000000
--- a/docs/test2
+++ /dev/null
@@ -1 +0,0 @@
-test
diff-tree 851961e30cf114848d815f9ebbc5669f2f8a9f45 (from 896a4036a4b733cf943713f71391ca8a69ac7d54)
Author: root <root at hughsie-laptop.(none)>
Date:   Mon Sep 17 14:51:26 2007 +0100

    don't return packagedata if we have none

diff --git a/client/pk-monitor.c b/client/pk-monitor.c
index e2d9637..06f57c4 100644
--- a/client/pk-monitor.c
+++ b/client/pk-monitor.c
@@ -78,7 +78,7 @@ main (int argc, char *argv[])
 	}
 	dbus_g_thread_init ();
 	g_type_init ();
-	pk_debug_init (FALSE);
+	pk_debug_init (TRUE);
 
 	if (!g_thread_supported ())
 		g_thread_init (NULL);
diff --git a/libpackagekit/pk-task-list.c b/libpackagekit/pk-task-list.c
index 3a2dc78..5e43433 100644
--- a/libpackagekit/pk-task-list.c
+++ b/libpackagekit/pk-task-list.c
@@ -85,7 +85,7 @@ pk_task_list_print (PkTaskList *tlist)
 	}
 	for (i=0; i<length; i++) {
 		item = g_ptr_array_index (tlist->priv->task_list, i);
-		g_print ("%i %s %s", item->job, pk_role_enum_to_text (item->role), item->package_id);
+		g_print ("%i %s %s\n", item->job, pk_role_enum_to_text (item->role), item->package_id);
 	}
 	g_print ("\n");
 	return TRUE;
diff --git a/src/pk-backend.c b/src/pk-backend.c
index 5096b63..ebf4d5f 100644
--- a/src/pk-backend.c
+++ b/src/pk-backend.c
@@ -665,6 +665,10 @@ pk_backend_get_package (PkBackend *backe
 {
 	g_return_val_if_fail (backend != NULL, FALSE);
 	g_return_val_if_fail (PK_IS_BACKEND (backend), FALSE);
+
+	if (backend->priv->last_package == NULL) {
+		return FALSE;
+	}
 	*package_id = g_strdup (backend->priv->last_package);
 	return TRUE;
 }
diff --git a/src/pk-engine.c b/src/pk-engine.c
index 847296d..7f8b76b 100644
--- a/src/pk-engine.c
+++ b/src/pk-engine.c
@@ -1381,6 +1381,7 @@ gboolean
 pk_engine_get_package (PkEngine *engine, guint job, gchar **package, GError **error)
 {
 	PkJobListItem *item;
+	gboolean ret;
 
 	g_return_val_if_fail (engine != NULL, FALSE);
 	g_return_val_if_fail (PK_IS_ENGINE (engine), FALSE);
@@ -1391,7 +1392,12 @@ pk_engine_get_package (PkEngine *engine,
 			     "No job:%i", job);
 		return FALSE;
 	}
-	pk_backend_get_package (item->task, package);
+	ret = pk_backend_get_package (item->task, package);
+	if (ret == FALSE) {
+		g_set_error (error, PK_ENGINE_ERROR, PK_ENGINE_ERROR_INVALID_STATE,
+			     "No package data available");
+		return FALSE;
+	}
 	return TRUE;
 }
 
diff-tree 896a4036a4b733cf943713f71391ca8a69ac7d54 (from f0dd99f32bd77fb510182270c11c1ef2ca57522d)
Author: Richard Hughes <richard at hughsie.com>
Date:   Mon Sep 17 14:24:56 2007 +0100

    don't lie about percentages we don't actually know

diff --git a/src/pk-backend.c b/src/pk-backend.c
index e5a5625..5096b63 100644
--- a/src/pk-backend.c
+++ b/src/pk-backend.c
@@ -49,6 +49,7 @@
 #include "pk-thread-list.h"
 
 #define PK_BACKEND_GET_PRIVATE(o) (G_TYPE_INSTANCE_GET_PRIVATE ((o), PK_TYPE_BACKEND, PkBackendPrivate))
+#define PK_BACKEND_PERCENTAGE_INVALID	101
 
 struct _PkBackendPrivate
 {
@@ -524,7 +525,7 @@ pk_backend_change_percentage (PkBackend 
 	g_return_val_if_fail (PK_IS_BACKEND (backend), FALSE);
 
 	/* save in case we need this from coldplug */
-	backend->priv->last_subpercentage = percentage;
+	backend->priv->last_percentage = percentage;
 
 	pk_debug ("emit percentage-changed %i", percentage);
 	g_signal_emit (backend, signals [PK_BACKEND_PERCENTAGE_CHANGED], 0, percentage);
@@ -626,10 +627,15 @@ pk_backend_update_detail (PkBackend *bac
  * pk_backend_get_percentage:
  **/
 gboolean
-pk_backend_get_percentage (PkBackend	*backend, guint *percentage)
+pk_backend_get_percentage (PkBackend *backend, guint *percentage)
 {
 	g_return_val_if_fail (backend != NULL, FALSE);
 	g_return_val_if_fail (PK_IS_BACKEND (backend), FALSE);
+
+	/* no data yet... */
+	if (backend->priv->last_percentage == PK_BACKEND_PERCENTAGE_INVALID) {
+		return FALSE;
+	}
 	*percentage = backend->priv->last_percentage;
 	return TRUE;
 }
@@ -642,6 +648,11 @@ pk_backend_get_sub_percentage (PkBackend
 {
 	g_return_val_if_fail (backend != NULL, FALSE);
 	g_return_val_if_fail (PK_IS_BACKEND (backend), FALSE);
+
+	/* no data yet... */
+	if (backend->priv->last_subpercentage == PK_BACKEND_PERCENTAGE_INVALID) {
+		return FALSE;
+	}
 	*percentage = backend->priv->last_subpercentage;
 	return TRUE;
 }
@@ -807,6 +818,9 @@ pk_backend_no_percentage_updates (PkBack
 	g_return_val_if_fail (backend != NULL, FALSE);
 	g_return_val_if_fail (PK_IS_BACKEND (backend), FALSE);
 
+	/* invalidate previous percentage */
+	backend->priv->last_percentage = PK_BACKEND_PERCENTAGE_INVALID;
+
 	pk_debug ("emit no-percentage-updates");
 	g_signal_emit (backend, signals [PK_BACKEND_NO_PERCENTAGE_UPDATES], 0);
 	return TRUE;
@@ -1317,8 +1331,8 @@ pk_backend_init (PkBackend *backend)
 	backend->priv->is_killable = FALSE;
 	backend->priv->spawn = NULL;
 	backend->priv->package_id = NULL;
-	backend->priv->last_percentage = 0;
-	backend->priv->last_subpercentage = 0;
+	backend->priv->last_percentage = PK_BACKEND_PERCENTAGE_INVALID;
+	backend->priv->last_subpercentage = PK_BACKEND_PERCENTAGE_INVALID;
 	backend->priv->last_package = NULL;
 	backend->priv->role = PK_ROLE_ENUM_UNKNOWN;
 	backend->priv->status = PK_STATUS_ENUM_UNKNOWN;
diff --git a/src/pk-engine.c b/src/pk-engine.c
index 1109c9a..847296d 100644
--- a/src/pk-engine.c
+++ b/src/pk-engine.c
@@ -120,6 +120,7 @@ pk_engine_error_get_type (void)
 			ENUM_ENTRY (PK_ENGINE_ERROR_PACKAGE_ID_INVALID, "PackageIdInvalid"),
 			ENUM_ENTRY (PK_ENGINE_ERROR_SEARCH_INVALID, "SearchInvalid"),
 			ENUM_ENTRY (PK_ENGINE_ERROR_FILTER_INVALID, "FilterInvalid"),
+			ENUM_ENTRY (PK_ENGINE_ERROR_INVALID_STATE, "InvalidState"),
 			{ 0, 0, 0 }
 		};
 		etype = g_enum_register_static ("PkEngineError", values);
@@ -1326,6 +1327,7 @@ gboolean
 pk_engine_get_percentage (PkEngine *engine, guint job, guint *percentage, GError **error)
 {
 	PkJobListItem *item;
+	gboolean ret;
 
 	g_return_val_if_fail (engine != NULL, FALSE);
 	g_return_val_if_fail (PK_IS_ENGINE (engine), FALSE);
@@ -1336,7 +1338,12 @@ pk_engine_get_percentage (PkEngine *engi
 			     "No job:%i", job);
 		return FALSE;
 	}
-	pk_backend_get_percentage (item->task, percentage);
+	ret = pk_backend_get_percentage (item->task, percentage);
+	if (ret == FALSE) {
+		g_set_error (error, PK_ENGINE_ERROR, PK_ENGINE_ERROR_INVALID_STATE,
+			     "No percentage data available");
+		return FALSE;
+	}
 	return TRUE;
 }
 
@@ -1347,6 +1354,7 @@ gboolean
 pk_engine_get_sub_percentage (PkEngine *engine, guint job, guint *percentage, GError **error)
 {
 	PkJobListItem *item;
+	gboolean ret;
 
 	g_return_val_if_fail (engine != NULL, FALSE);
 	g_return_val_if_fail (PK_IS_ENGINE (engine), FALSE);
@@ -1357,7 +1365,12 @@ pk_engine_get_sub_percentage (PkEngine *
 			     "No job:%i", job);
 		return FALSE;
 	}
-	pk_backend_get_sub_percentage (item->task, percentage);
+	ret = pk_backend_get_sub_percentage (item->task, percentage);
+	if (ret == FALSE) {
+		g_set_error (error, PK_ENGINE_ERROR, PK_ENGINE_ERROR_INVALID_STATE,
+			     "No sub-percentage data available");
+		return FALSE;
+	}
 	return TRUE;
 }
 
diff --git a/src/pk-engine.h b/src/pk-engine.h
index d22ed44..107c62c 100644
--- a/src/pk-engine.h
+++ b/src/pk-engine.h
@@ -63,6 +63,7 @@ typedef enum
 	PK_ENGINE_ERROR_PACKAGE_ID_INVALID,
 	PK_ENGINE_ERROR_SEARCH_INVALID,
 	PK_ENGINE_ERROR_FILTER_INVALID,
+	PK_ENGINE_ERROR_INVALID_STATE,
 	PK_ENGINE_ERROR_LAST
 } PkEngineError;
 
diff-tree f0dd99f32bd77fb510182270c11c1ef2ca57522d (from eec54341688f92f3100e32bad010133db27ef24e)
Author: Richard Hughes <richard at hughsie.com>
Date:   Mon Sep 17 13:50:43 2007 +0100

    convert the apt and box plugins to the new thread API

diff --git a/backends/apt/pk-backend-apt.cpp b/backends/apt/pk-backend-apt.cpp
index 67f652d..e4a383e 100644
--- a/backends/apt/pk-backend-apt.cpp
+++ b/backends/apt/pk-backend-apt.cpp
@@ -46,10 +46,6 @@
 static pkgCacheFile *fileCache = NULL;
 pkgSourceList *SrcList = 0;
 
-typedef struct {
-	PkBackend *backend;
-} UpdateData;
-
 typedef enum {
 	SEARCH_NAME = 1,
 	SEARCH_DETAILS,
@@ -57,14 +53,12 @@ typedef enum {
 } SearchDepth;
 
 struct search_task {
-	PkBackend *backend;
 	gchar *search;
 	gchar *filter;
 	SearchDepth depth;
 };
 
 struct desc_task {
-	PkBackend *backend;
 	PkPackageId *pi;
 };
 
@@ -150,18 +144,17 @@ class UpdatePercentage:public pkgAcquire
 	}
 };
 
-// do_update_thread - Update the package lists
+// backend_refresh_cache_thread - Update the package lists
 // Swiped from apt-get's update mode
-void *do_update_thread(gpointer data)
+static gboolean backend_refresh_cache_thread (PkBackend *backend, gpointer data)
 {
-	UpdateData *ud = (UpdateData*)data;
 	pkgCacheFile *Cache;
 	bool Failed = false;
 	bool TransientNetworkFailure = false;
 	OpTextProgress Prog;
 
 	/* easy as that */
-	pk_backend_change_job_status(ud->backend, PK_STATUS_ENUM_REFRESH_CACHE);
+	pk_backend_change_job_status(backend, PK_STATUS_ENUM_REFRESH_CACHE);
 
 	Cache = getCache();
 
@@ -169,9 +162,8 @@ void *do_update_thread(gpointer data)
 	pkgSourceList List;
 	if (List.ReadMainList() == false)
 	{
-		pk_backend_error_code(ud->backend, PK_ERROR_ENUM_UNKNOWN, "Failure reading lists");
-		pk_backend_finished(ud->backend);
-		return NULL;
+		pk_backend_error_code(backend, PK_ERROR_ENUM_UNKNOWN, "Failure reading lists");
+		return FALSE;
 	}
 
 	// Lock the list directory
@@ -182,27 +174,26 @@ void *do_update_thread(gpointer data)
 		if (_error->PendingError() == true)
 		{
 			_error->DumpErrors();
-			pk_backend_error_code(ud->backend, PK_ERROR_ENUM_UNKNOWN, "Unable to lock the list directory");
-			pk_backend_finished(ud->backend);
-			return NULL;
+			pk_backend_error_code(backend, PK_ERROR_ENUM_UNKNOWN, "Unable to lock the list directory");
+			return FALSE;
 		}
 	}
 
 	// Create the download object
-	UpdatePercentage *Stat = new UpdatePercentage(ud->backend);
+	UpdatePercentage *Stat = new UpdatePercentage(backend);
 	pkgAcquire Fetcher(Stat);
 
 	// Populate it with the source selection
 	if (List.GetIndexes(&Fetcher) == false)
 	{
-		pk_backend_error_code(ud->backend, PK_ERROR_ENUM_UNKNOWN, "Failed to populate the source selection");
+		pk_backend_error_code(backend, PK_ERROR_ENUM_UNKNOWN, "Failed to populate the source selection");
 		goto do_update_clean;
 	}
 
 	// Run it
 	if (Fetcher.Run() == pkgAcquire::Failed)
 	{
-		pk_backend_error_code(ud->backend, PK_ERROR_ENUM_UNKNOWN, "Failed to run the fetcher");
+		pk_backend_error_code(backend, PK_ERROR_ENUM_UNKNOWN, "Failed to run the fetcher");
 		goto do_update_clean;
 	}
 
@@ -230,7 +221,7 @@ void *do_update_thread(gpointer data)
 		if (Fetcher.Clean(_config->FindDir("Dir::State::lists")) == false ||
 		    Fetcher.Clean(_config->FindDir("Dir::State::lists") + "partial/") == false)
 		{
-			pk_backend_error_code(ud->backend, PK_ERROR_ENUM_UNKNOWN, "Failed to clean out any old list files");
+			pk_backend_error_code(backend, PK_ERROR_ENUM_UNKNOWN, "Failed to clean out any old list files");
 			goto do_update_clean;
 		}
 	}
@@ -239,7 +230,7 @@ void *do_update_thread(gpointer data)
 	Cache = getCache();
 	if (Cache->BuildCaches(Prog,false) == false)
 	{
-		pk_backend_error_code(ud->backend, PK_ERROR_ENUM_UNKNOWN, "Failed to prepare the cache");
+		pk_backend_error_code(backend, PK_ERROR_ENUM_UNKNOWN, "Failed to prepare the cache");
 		goto do_update_clean;
 	}
 
@@ -247,18 +238,16 @@ void *do_update_thread(gpointer data)
 		pk_debug("Some index files failed to download, they have been ignored, or old ones used instead.");
 	else if (Failed == true)
 	{
-		pk_backend_error_code(ud->backend, PK_ERROR_ENUM_UNKNOWN, "Generic Error");
+		pk_backend_error_code(backend, PK_ERROR_ENUM_UNKNOWN, "Generic Error");
 		goto do_update_clean;
 	}
 
 	delete Stat;
-	pk_backend_finished(ud->backend);
-	return NULL;
+	return TRUE;
 
 	do_update_clean:
 	delete Stat;
-	pk_backend_finished(ud->backend);
-	return NULL;
+	return FALSE;
 }
 
 /**
@@ -302,21 +291,7 @@ static void backend_refresh_cache(PkBack
 		return;
 	}
 
-	UpdateData *data = g_new(UpdateData, 1);
-	if (data == NULL)
-	{
-		pk_backend_error_code(backend, PK_ERROR_ENUM_OOM, "Failed to allocate memory for update task");
-		pk_backend_finished(backend);
-	}
-	else
-	{
-		data->backend = backend;
-		if (g_thread_create(do_update_thread, data, false, NULL) == NULL)
-		{
-			pk_backend_error_code(backend, PK_ERROR_ENUM_CREATE_THREAD_FAILED, "Failed to create update thread");
-			pk_backend_finished(backend);
-		}
-	}
+	pk_backend_thread_helper(backend, backend_refresh_cache_thread, NULL);
 }
 
 // LocalitySort - Sort a version list by package file locality		/*{{{*/
@@ -380,15 +355,15 @@ static gboolean buildExDesc(ExDescFile *
 	return DFList[pid].available;
 }
 
-// get_search_thread
+// backend_search_packages_thread
 // Swiped from apt-cache's search mode
-static void *get_search_thread(gpointer data)
+static gboolean backend_search_packages_thread (PkBackend *backend, gpointer data)
 {
 	search_task *st = (search_task *) data;
 	ExDescFile *DFList = NULL;
 
-	pk_backend_change_job_status(st->backend, PK_STATUS_ENUM_QUERY);
-	pk_backend_no_percentage_updates(st->backend);
+	pk_backend_change_job_status(backend, PK_STATUS_ENUM_QUERY);
+	pk_backend_no_percentage_updates(backend);
 
 	pk_debug("finding %s", st->search);
 	pkgCache & pkgCache = *(getCache());
@@ -401,8 +376,7 @@ static void *get_search_thread(gpointer 
 	memset(Pattern, 0, sizeof(*Pattern));
 	if (regcomp(Pattern, st->search, REG_EXTENDED | REG_ICASE | REG_NOSUB) != 0)
 	{
-		pk_backend_error_code(st->backend, PK_ERROR_ENUM_UNKNOWN, "regex compilation error");
-		pk_backend_finished(st->backend);
+		pk_backend_error_code(backend, PK_ERROR_ENUM_UNKNOWN, "regex compilation error");
 		goto search_task_cleanup;
 	}
 
@@ -462,16 +436,14 @@ static void *get_search_thread(gpointer 
 				Match = false;
 		}
 
-		if (Match == true)// && pk_backend_filter_package_name(st->backend,P.Name().c_str()))
+		if (Match == true)// && pk_backend_filter_package_name(backend,P.Name().c_str()))
 		{
 			gchar *pid = pk_package_id_build(P.Name().c_str(),J->verstr,J->arch,J->repo);
-			pk_backend_package(st->backend, J->installed, pid, P.ShortDesc().c_str());
+			pk_backend_package(backend, J->installed, pid, P.ShortDesc().c_str());
 			g_free(pid);
 		}
 	}
 
-	pk_backend_finished(st->backend);
-
 search_task_cleanup:
 	for (ExDescFile * J = DFList; J->Df != 0; J++)
 	{
@@ -482,14 +454,14 @@ search_task_cleanup:
 	g_free(st->search);
 	g_free(st);
 
-	return NULL;
+	return TRUE;
 }
 
 /**
- * pk_backend_search
+ * backend_search_common
  **/
 static void
-pk_backend_search(PkBackend * backend, const gchar * filter, const gchar * search, SearchDepth which, void *(*search_thread)(gpointer data))
+backend_search_common(PkBackend * backend, const gchar * filter, const gchar * search, SearchDepth which, PkBackendThreadFunc func)
 {
 	g_return_if_fail (backend != NULL);
 	search_task *data = g_new(struct search_task, 1);
@@ -500,16 +472,10 @@ pk_backend_search(PkBackend * backend, c
 	}
 	else
 	{
-		data->backend = backend;
 		data->search = g_strdup(search);
 		data->filter = g_strdup(filter);
 		data->depth = which;
-
-		if (g_thread_create(search_thread, data, false, NULL) == NULL)
-		{
-			pk_backend_error_code(backend, PK_ERROR_ENUM_CREATE_THREAD_FAILED, "Failed to spawn thread");
-			pk_backend_finished(backend);
-		}
+		pk_backend_thread_helper (backend, func, data);
 	}
 }
 
@@ -573,13 +539,13 @@ static GHashTable *PackageRecord(pkgCach
 
 }
 
-// get_description_thread
-static void *get_description_thread(gpointer data)
+// backend_get_description_thread
+static gboolean backend_get_description_thread (PkBackend *backend, gpointer data)
 {
 	desc_task *dt = (desc_task *) data;
 
-	pk_backend_change_job_status(dt->backend, PK_STATUS_ENUM_QUERY);
-	pk_backend_no_percentage_updates(dt->backend);
+	pk_backend_change_job_status(backend, PK_STATUS_ENUM_QUERY);
+	pk_backend_no_percentage_updates(backend);
 
 	pk_debug("finding %s", dt->pi->name);
 	pkgCache & pkgCache = *(getCache());
@@ -594,11 +560,10 @@ static void *get_description_thread(gpoi
 		// Find the proper version to use.
 		pkgCache::VerIterator V = Plcy.GetCandidateVer(P);
 		GHashTable *pkg = PackageRecord(V);
-		pk_backend_description(dt->backend,dt->pi->name,
+		pk_backend_description(backend,dt->pi->name,
 					PK_GROUP_ENUM_OTHER,(const gchar*)g_hash_table_lookup(pkg,"Description"),"");
 		g_hash_table_unref(pkg);
 	}
-	pk_backend_finished(dt->backend, PK_EXIT_ENUM_SUCCESS);
 	return NULL;
 }
 
@@ -617,7 +582,6 @@ backend_get_description (PkBackend *back
 		return;
 	}
 
-	data->backend = backend;
 	data->pi = pk_package_id_new_from_string(package_id);
 	if (data->pi == NULL)
 	{
@@ -626,11 +590,7 @@ backend_get_description (PkBackend *back
 		return;
 	}
 
-	if (g_thread_create(get_description_thread, data, false, NULL) == NULL)
-	{
-		pk_backend_error_code(backend, PK_ERROR_ENUM_CREATE_THREAD_FAILED, "Failed to spawn description thread");
-		pk_backend_finished(backend);
-	}
+	pk_backend_thread_helper (backend, backend_get_description_thread, data);
 	return;
 }
 
@@ -640,7 +600,7 @@ backend_get_description (PkBackend *back
 static void
 backend_search_details (PkBackend *backend, const gchar *filter, const gchar *search)
 {
-	pk_backend_search(backend, filter, search, SEARCH_DETAILS, get_search_thread);
+	backend_search_common(backend, filter, search, SEARCH_DETAILS, backend_search_packages_thread);
 }
 
 /**
@@ -649,10 +609,10 @@ backend_search_details (PkBackend *backe
 static void
 backend_search_name (PkBackend *backend, const gchar *filter, const gchar *search)
 {
-	pk_backend_search(backend, filter, search, SEARCH_NAME, get_search_thread);
+	backend_search_common(backend, filter, search, SEARCH_NAME, backend_search_packages_thread);
 }
 
-static void *do_search_file(gpointer data)
+static gboolean backend_search_file_thread (PkBackend *backend, gpointer data)
 {
 	search_task *st = (search_task*)data;
 	gchar *sdir = g_path_get_dirname(_config->Find("Dir::State::status").c_str());
@@ -662,23 +622,20 @@ static void *do_search_file(gpointer dat
 	GDir *list = g_dir_open(ldir,0,&error);
 	if (error!=NULL)
 	{
-		pk_backend_error_code(st->backend, PK_ERROR_ENUM_INTERNAL_ERROR, "can't open %s",ldir);
+		pk_backend_error_code(backend, PK_ERROR_ENUM_INTERNAL_ERROR, "can't open %s",ldir);
 		g_free(ldir);
 		g_error_free(error);
-		pk_backend_finished(st->backend);
-		return NULL;
+		return FALSE;
 	}
 	const gchar * fname = NULL;
 	while ((fname = g_dir_read_name(list))!=NULL)
 	{
-		//pk_backend_package(st->backend, J->installed, pid, P.ShortDesc().c_str());
+		//pk_backend_package(backend, J->installed, pid, P.ShortDesc().c_str());
 	}
-	pk_backend_error_code(st->backend, PK_ERROR_ENUM_INTERNAL_ERROR, "search file is incomplete");
-	pk_backend_finished(st->backend);
+	pk_backend_error_code(backend, PK_ERROR_ENUM_INTERNAL_ERROR, "search file is incomplete");
 	g_dir_close(list);
 	g_free(ldir);
-	//pk_backend_finished(st->backend);
-	return NULL;
+	return TRUE;
 }
 
 /**
@@ -686,7 +643,7 @@ static void *do_search_file(gpointer dat
  **/
 static void backend_search_file(PkBackend *backend, const gchar *filter, const gchar *search)
 {
-	pk_backend_search(backend, filter, search, SEARCH_FILE, do_search_file);
+	backend_search_common(backend, filter, search, SEARCH_FILE, backend_search_file_thread);
 }
 
 extern "C" PK_BACKEND_OPTIONS (
diff --git a/backends/box/pk-backend-box.c b/backends/box/pk-backend-box.c
index e99a0c1..7919c4c 100644
--- a/backends/box/pk-backend-box.c
+++ b/backends/box/pk-backend-box.c
@@ -39,14 +39,12 @@ enum PkgSearchType {
 
 
 typedef struct {
-	PkBackend *backend;
 	gchar *search;
 	gchar *filter;
 	gint mode;
 } FindData;
 
 typedef struct {
-	PkBackend *backend;
 	gchar *package_id;
 } ThreadData;
 
@@ -188,20 +186,20 @@ find_packages_real (PkBackend *backend, 
 	db_close(db);
 }
 
-void*
-find_packages_thread (gpointer data)
+static gboolean
+backend_find_packages_thread (PkBackend *backend, gpointer data)
 {
 	FindData *d = (FindData*) data;
 
-	g_return_val_if_fail (d->backend != NULL, NULL);
+	g_return_val_if_fail (backend != NULL, NULL);
 
-	find_packages_real (d->backend, d->search, d->filter, d->mode);
+	find_packages_real (backend, d->search, d->filter, d->mode);
 
 	g_free(d->search);
 	g_free(d->filter);
 	g_free(d);
 
-	return NULL;
+	return TRUE;
 }
 
 
@@ -216,16 +214,10 @@ find_packages (PkBackend *backend, const
 		pk_backend_error_code(backend, PK_ERROR_ENUM_OOM, "Failed to allocate memory");
 		pk_backend_finished (backend);
 	} else {
-		data->backend = backend;
 		data->search = g_strdup(search);
 		data->filter = g_strdup(filter);
 		data->mode = mode;
-
-		if (g_thread_create(find_packages_thread, data, FALSE, NULL) == NULL) {
-			pk_backend_error_code(backend, PK_ERROR_ENUM_CREATE_THREAD_FAILED, "Failed to create thread");
-			pk_backend_finished (backend);
-		}
-
+		pk_backend_thread_helper (backend, backend_find_packages_thread, data);
 	}
 }
 
@@ -248,31 +240,26 @@ find_package_by_id (PkPackageId *pi)
 }
 
 
-static void*
-get_updates_thread(gpointer data)
+static gboolean
+backend_get_updates_thread (PkBackend *backend, gpointer data)
 {
 	GList *list = NULL;
 	sqlite3 *db = NULL;
-	ThreadData *d = (ThreadData*) data;
 
-	pk_backend_change_job_status (d->backend, PK_STATUS_ENUM_QUERY);
+	pk_backend_change_job_status (backend, PK_STATUS_ENUM_QUERY);
 
 	db = db_open ();
 
 	list = box_db_repos_packages_for_upgrade (db);
-	add_packages_from_list (d->backend, list);
+	add_packages_from_list (backend, list);
 	box_db_repos_package_list_free (list);
 
-	pk_backend_finished (d->backend);
-
-	g_free(d);
 	db_close (db);
-
-	return NULL;
+	return TRUE;
 }
 
-static void*
-get_description_thread(gpointer data)
+static gboolean
+backend_get_description_thread (PkBackend *backend, gpointer data)
 {
 	PkPackageId *pi;
 	PackageSearch *ps;
@@ -281,30 +268,27 @@ get_description_thread(gpointer data)
 
 	pi = pk_package_id_new_from_string (d->package_id);
 	if (pi == NULL) {
-		pk_backend_error_code (d->backend, PK_ERROR_ENUM_PACKAGE_ID_INVALID, "invalid package id");
-		pk_backend_finished (d->backend);
-		return NULL;
+		pk_backend_error_code (backend, PK_ERROR_ENUM_PACKAGE_ID_INVALID, "invalid package id");
+		return FALSE;
 	}
 
-	pk_backend_change_job_status (d->backend, PK_STATUS_ENUM_QUERY);
+	pk_backend_change_job_status (backend, PK_STATUS_ENUM_QUERY);
 	list = find_package_by_id (pi);
 	ps = (PackageSearch*) list->data;
 	if (list == NULL) {
-		pk_backend_error_code (d->backend, PK_ERROR_ENUM_PACKAGE_ID_INVALID, "cannot find package by id");
-		pk_backend_finished (d->backend);
-		return NULL;
+		pk_backend_error_code (backend, PK_ERROR_ENUM_PACKAGE_ID_INVALID, "cannot find package by id");
+		return FALSE;
 	}
 
-	pk_backend_description (d->backend, pi->name, "unknown", PK_GROUP_ENUM_OTHER, ps->description, "");
+	pk_backend_description (backend, pi->name, "unknown", PK_GROUP_ENUM_OTHER, ps->description, "");
 
 	pk_package_id_free (pi);
 	box_db_repos_package_list_free (list);
 
-	pk_backend_finished (d->backend);
 	g_free (d->package_id);
 	g_free (d);
 
-	return NULL;
+	return TRUE;
 }
 
 /* ===================================================================== */
@@ -369,16 +353,9 @@ backend_get_description (PkBackend *back
 		pk_backend_error_code(backend, PK_ERROR_ENUM_OOM, "Failed to allocate memory");
 		pk_backend_finished (backend);
 	} else {
-		data->backend = backend;
 		data->package_id = g_strdup(package_id);
-
-		if (g_thread_create(get_description_thread, data, FALSE, NULL) == NULL) {
-			pk_backend_error_code(backend, PK_ERROR_ENUM_CREATE_THREAD_FAILED, "Failed to create thread");
-			pk_backend_finished (backend);
-		}
+		pk_backend_thread_helper (backend, backend_get_description_thread, data);
 	}
-
-	return;
 }
 
 /**
@@ -387,21 +364,8 @@ backend_get_description (PkBackend *back
 static void
 backend_get_updates (PkBackend *backend)
 {
-	ThreadData *data = g_new0(ThreadData, 1);
-
 	g_return_if_fail (backend != NULL);
-
-	if (data == NULL) {
-		pk_backend_error_code(backend, PK_ERROR_ENUM_OOM, "Failed to allocate memory");
-		pk_backend_finished (backend);
-	} else {
-		data->backend = backend;
-
-		if (g_thread_create(get_updates_thread, data, FALSE, NULL) == NULL) {
-			pk_backend_error_code(backend, PK_ERROR_ENUM_CREATE_THREAD_FAILED, "Failed to create thread");
-			pk_backend_finished (backend);
-		}
-	}
+	pk_backend_thread_helper (backend, backend_get_updates_thread, NULL);
 }
 
 
diff-tree eec54341688f92f3100e32bad010133db27ef24e (from parents)
Merge: 1aa30c70c2f6329e863591ddb6715070e71c855c cc438e642f632255afddf146dbd5464bd29a91b0
Author: Richard Hughes <richard at hughsie.com>
Date:   Mon Sep 17 13:22:30 2007 +0100

    fix conflicts in the alpm and box backends

diff --cc backends/alpm/pk-backend-alpm.c
index 83228d9,a6f8e8c..e5ea7fc
@@@ -411,34 -428,99 +423,99 @@@
  	pk_backend_package (backend, 1, "kernel;2.6.23-0.115.rc3.git1.fc8;i386;installed",
  			 "The Linux kernel (the core of the Linux operating system)");
  	pk_backend_package (backend, 1, "gtkhtml2;2.19.1-4.fc8;i386;fedora", "An HTML widget for GTK+ 2.0");
 -	pk_backend_finished (backend, PK_EXIT_ENUM_SUCCESS);
 +	pk_backend_finished (backend);
  }
  
- static gboolean
- backend_install_timeout (gpointer data)
- {
- 	PkBackend *backend = (PkBackend *) data;
- 	if (progress_percentage == 100) {
- 		pk_backend_finished (backend);
- 		return FALSE;
- 	}
- 	if (progress_percentage == 50) {
- 		pk_backend_change_job_status (backend, PK_STATUS_ENUM_INSTALL);
- 	}
- 	progress_percentage += 10;
- 	pk_backend_change_percentage (backend, progress_percentage);
- 	return TRUE;
- }
- 
  /**
   * backend_install_package:
   */
  static void
  backend_install_package (PkBackend *backend, const gchar *package_id)
  {
- 	g_return_if_fail (backend != NULL);
- 	progress_percentage = 0;
- 	g_timeout_add (1000, backend_install_timeout, backend);
+   g_return_if_fail (backend != NULL);
+   //alpm_list_t *syncdbs = alpm_option_get_syncdbs ();
+   alpm_list_t *result = NULL;
+   alpm_list_t *problems = NULL;
+   PkPackageId *id = pk_package_id_new_from_string (package_id);
+   pmtransflag_t flags = 0;
+ 
+   flags |= PM_TRANS_FLAG_NODEPS;
+ 
+   // Next generation code?
+   /*for (; syncdbs; syncdbs = alpm_list_next (syncdbs))
+     result = my_list_mmerge (result, find_packages (id->name, (pmdb_t *)syncdbs->data), list_cmp_fn);
+ 
+   if (result == NULL)
+     {
+       pk_backend_error_code (backend,
+ 			     PK_ERROR_ENUM_PACKAGE_ID_INVALID,
+ 			     "Package not found");
 -      pk_backend_finished (backend, PK_EXIT_ENUM_FAILED);
++      pk_backend_finished (backend);
+       alpm_list_free (result);
+       alpm_list_free (syncdbs);
+       pk_package_id_free (id);
+       return;
+     }
+ 
+   for (; result; result = alpm_list_next (result))
+     if (pkg_equals_to ((pmpkg_t *)result->data, id->name, id->version))
+       break;
+ 
+   if (!result)
+     {
+       pk_backend_error_code (backend,
+ 			     PK_ERROR_ENUM_PACKAGE_ID_INVALID,
+ 			     "Package not found");
 -      pk_backend_finished (backend, PK_EXIT_ENUM_FAILED);
++      pk_backend_finished (backend);
+       alpm_list_free (result);
+       alpm_list_free (syncdbs);
+       pk_package_id_free (id);
+       return;
+     }*/
+ 
+   if (alpm_trans_init (PM_TRANS_TYPE_SYNC, flags,
+ 		       trans_event_cb, trans_conv_cb,
+ 		       trans_prog_cb) == -1)
+     {
+       pk_backend_error_code (backend,
+ 			     PK_ERROR_ENUM_TRANSACTION_ERROR,
+ 			     alpm_strerror (pm_errno));
 -      pk_backend_finished (backend, PK_EXIT_ENUM_FAILED);
++      pk_backend_finished (backend);
+       alpm_list_free (result);
+       pk_package_id_free (id);
+       return;
+     }
+ 
+   alpm_trans_addtarget (id->name);
+ 
+   if (alpm_trans_prepare (&problems) != 0)
+     {
+       pk_backend_error_code (backend,
+ 			     PK_ERROR_ENUM_TRANSACTION_ERROR,
+ 			     alpm_strerror (pm_errno));
 -      pk_backend_finished (backend, PK_EXIT_ENUM_FAILED);
++      pk_backend_finished (backend);
+       alpm_trans_release ();
+       alpm_list_free (result);
+       pk_package_id_free (id);
+       return;
+     }
+ 
+   if (alpm_trans_commit (&problems) != 0)
+     {
+       pk_backend_error_code (backend,
+ 			     PK_ERROR_ENUM_TRANSACTION_ERROR,
+ 			     alpm_strerror (pm_errno));
 -      pk_backend_finished (backend, PK_EXIT_ENUM_FAILED);
++      pk_backend_finished (backend);
+       alpm_trans_release ();
+       alpm_list_free (result);
+       pk_package_id_free (id);
+       return;
+     }
+ 
+   alpm_trans_release ();
+   alpm_list_free (result);
+   pk_package_id_free (id);
 -  pk_backend_finished (backend, PK_EXIT_ENUM_SUCCESS);
++  pk_backend_finished (backend);
  }
  
  /**
@@@ -501,8 -583,79 +578,79 @@@
  backend_remove_package (PkBackend *backend, const gchar *package_id, gboolean allow_deps)
  {
  	g_return_if_fail (backend != NULL);
- 	pk_backend_error_code (backend, PK_ERROR_ENUM_NO_NETWORK, "No network connection available");
+ 	PkPackageId *id = pk_package_id_new_from_string (package_id);
+ 	pmdb_t *localdb = alpm_option_get_localdb ();
+ 	alpm_list_t *result = find_packages (id->name, localdb);
+ 	pmtransflag_t flags = 0;
+ 	alpm_list_t *problems = NULL;
+ 
+ 	if (result == NULL)
+ 	  {
+ 	    pk_backend_error_code (backend,
+ 				  PK_ERROR_ENUM_PACKAGE_NOT_INSTALLED,
+ 				  "Package is not installed");
 -	    pk_backend_finished (backend, PK_EXIT_ENUM_FAILED);
++	    pk_backend_finished (backend);
+ 	    pk_package_id_free (id);
+ 	    return;
+ 	  }
+ 	else if (alpm_list_count (result) != 1 || 
+ 		 strcmp (alpm_pkg_get_name(((PackageSource *)result->data)->pkg), id->name) != 0)
+ 	  {	    
+ 	    pk_backend_error_code (backend,
+ 				  PK_ERROR_ENUM_PACKAGE_NOT_INSTALLED,
+ 				  "Package is not installed");
+ 	    alpm_list_free_inner (result, (alpm_list_fn_free)package_source_free);
 -	    pk_backend_finished (backend, PK_EXIT_ENUM_FAILED);
++	    pk_backend_finished (backend);
+ 	    pk_package_id_free (id);
+ 	    alpm_list_free (result);
+ 	    return;
+ 	  }
+ 
+ 	if (allow_deps) flags |= PM_TRANS_FLAG_CASCADE;
+ 
+ 	if (alpm_trans_init (PM_TRANS_TYPE_REMOVE, flags,
+ 			 trans_event_cb, trans_conv_cb,
+ 			 trans_prog_cb) == -1)
+ 	  {
+ 	    pk_backend_error_code (backend,
+ 				  PK_ERROR_ENUM_TRANSACTION_ERROR,
+ 				  alpm_strerror (pm_errno));
 -	    pk_backend_finished (backend, PK_EXIT_ENUM_FAILED);
++	    pk_backend_finished (backend);
+ 	    alpm_list_free (result);
+ 	    pk_package_id_free (id);
+ 	    return;
+ 	  }
+ 
+ 	alpm_trans_addtarget (id->name);
+ 
+ 	if (alpm_trans_prepare (&problems) != 0)
+ 	  {
+ 	    pk_backend_error_code (backend,
+ 				  PK_ERROR_ENUM_TRANSACTION_ERROR,
+ 				  alpm_strerror (pm_errno));
 -	    pk_backend_finished (backend, PK_EXIT_ENUM_FAILED);
++	    pk_backend_finished (backend);
+ 	    alpm_trans_release ();
+ 	    alpm_list_free (result);
+ 	    pk_package_id_free (id);
+ 	    return;
+ 	  }
+ 
+ 	if (alpm_trans_commit (&problems) != 0)
+ 	  {
+ 	    pk_backend_error_code (backend,
+ 				  PK_ERROR_ENUM_TRANSACTION_ERROR,
+ 				  alpm_strerror (pm_errno));
 -	    pk_backend_finished (backend, PK_EXIT_ENUM_FAILED);
++	    pk_backend_finished (backend);
+ 	    alpm_trans_release ();
+ 	    alpm_list_free (result);
+ 	    pk_package_id_free (id);
+ 	    return;
+ 	  }
+ 
+ 	alpm_list_free (result);
+ 	pk_package_id_free (id);
+ 	alpm_trans_release ();
 -	pk_backend_finished (backend, PK_EXIT_ENUM_SUCCESS);
 +	pk_backend_finished (backend);
  }
  
  /**
diff-tree 1aa30c70c2f6329e863591ddb6715070e71c855c (from ff5c25941adf03653aeca1b1e2f7ce19357b2a41)
Author: Richard Hughes <richard at hughsie.com>
Date:   Mon Sep 17 13:16:23 2007 +0100

    make the warning more clear for backend writers

diff --git a/src/pk-backend.c b/src/pk-backend.c
index 720bf22..e5a5625 100644
--- a/src/pk-backend.c
+++ b/src/pk-backend.c
@@ -781,7 +781,14 @@ pk_backend_finished (PkBackend *backend)
 
 	/* check we have no threads running */
 	if (pk_thread_list_number_running (backend->priv->thread_list) != 0) {
-		pk_error ("you have to use pk_backend_thread_helper or use pk_thread_list_wait!");
+		g_print ("ERROR: There are threads running and the task has been asked to finish!\n");
+		g_print ("If you are using :\n");
+		g_print ("* pk_backend_thread_helper\n");
+		g_print ("   - You should _not_ use pk_backend_finished directly");
+		g_print ("   - Return from the function like normal\n");
+		g_print ("* pk_thread_list_create:\n");
+		g_print ("   -  If used internally you _have_ to use pk_thread_list_wait\n");
+		pk_error ("Internal error, cannot continue (will segfault in the near future...)");
 	}
 
 	/* we have to run this idle as the command may finish before the job
diff-tree ff5c25941adf03653aeca1b1e2f7ce19357b2a41 (from 205341f7021209c588629b92807aa5092c0861d1)
Author: Richard Hughes <richard at hughsie.com>
Date:   Mon Sep 17 12:47:41 2007 +0100

    use pk_backend_thread_helper to make it trivial to start a new thread

diff --git a/backends/test/pk-backend-test-thread.c b/backends/test/pk-backend-test-thread.c
index 67e66d0..b34cc58 100644
--- a/backends/test/pk-backend-test-thread.c
+++ b/backends/test/pk-backend-test-thread.c
@@ -44,11 +44,7 @@ static void
 backend_search_group (PkBackend *backend, const gchar *filter, const gchar *search)
 {
 	g_return_if_fail (backend != NULL);
-	if (pk_backend_thread_create (backend, backend_search_group_thread, NULL) == FALSE) {
-		pk_backend_error_code (backend, PK_ERROR_ENUM_CREATE_THREAD_FAILED, "Failed to create search-group thread");
-		pk_backend_finished (backend);
-	}
-	pk_backend_finished (backend);
+	pk_backend_thread_helper (backend, backend_search_group_thread, NULL);
 }
 
 /**
@@ -84,11 +80,7 @@ static void
 backend_search_name (PkBackend *backend, const gchar *filter, const gchar *search)
 {
 	g_return_if_fail (backend != NULL);
-	if (pk_backend_thread_create (backend, backend_search_name_thread, NULL) == FALSE) {
-		pk_backend_error_code (backend, PK_ERROR_ENUM_CREATE_THREAD_FAILED, "Failed to create search-name thread");
-		pk_backend_finished (backend);
-	}
-	pk_backend_finished (backend);
+	pk_backend_thread_helper (backend, backend_search_name_thread, NULL);
 }
 
 PK_BACKEND_OPTIONS (
diff --git a/src/pk-backend.c b/src/pk-backend.c
index 14f2b99..720bf22 100644
--- a/src/pk-backend.c
+++ b/src/pk-backend.c
@@ -180,6 +180,25 @@ pk_backend_thread_create (PkBackend *bac
 }
 
 /**
+ * pk_backend_thread_helper:
+ **/
+gboolean
+pk_backend_thread_helper (PkBackend *backend, PkBackendThreadFunc func, gpointer data)
+{
+	if (pk_backend_thread_create (backend, func, NULL) == FALSE) {
+		pk_backend_error_code (backend, PK_ERROR_ENUM_CREATE_THREAD_FAILED, "Failed to create thread");
+		pk_backend_finished (backend);
+		return FALSE;
+	}
+
+	pk_debug ("waiting for all threads in this backend");
+	pk_thread_list_wait (backend->priv->thread_list);
+
+	pk_backend_finished (backend);
+	return TRUE;
+}
+
+/**
  * pk_backend_parse_common_output:
  *
  * If you are editing this function creating a new backend,
@@ -760,8 +779,10 @@ pk_backend_finished (PkBackend *backend)
 	g_return_val_if_fail (backend != NULL, FALSE);
 	g_return_val_if_fail (PK_IS_BACKEND (backend), FALSE);
 
-	pk_debug ("waiting for all threads");
-	pk_thread_list_wait (backend->priv->thread_list);
+	/* check we have no threads running */
+	if (pk_thread_list_number_running (backend->priv->thread_list) != 0) {
+		pk_error ("you have to use pk_backend_thread_helper or use pk_thread_list_wait!");
+	}
 
 	/* we have to run this idle as the command may finish before the job
 	 * has been sent to the client. I love async... */
diff --git a/src/pk-backend.h b/src/pk-backend.h
index 151d49d..b449ce3 100644
--- a/src/pk-backend.h
+++ b/src/pk-backend.h
@@ -77,6 +77,9 @@ typedef gboolean (*PkBackendThreadFunc)	
 gboolean	 pk_backend_thread_create		(PkBackend	*backend,
 							 PkBackendThreadFunc func,
 							 gpointer	 data);
+gboolean	 pk_backend_thread_helper		(PkBackend	*backend,
+							 PkBackendThreadFunc func,
+							 gpointer	 data);
 
 /**
  * PkBackendDesc:
diff --git a/src/pk-thread-list.c b/src/pk-thread-list.c
index 3b76576..2edc109 100644
--- a/src/pk-thread-list.c
+++ b/src/pk-thread-list.c
@@ -130,6 +130,31 @@ pk_thread_list_wait (PkThreadList *tlist
 }
 
 /**
+ * pk_thread_list_number_running:
+ **/
+guint
+pk_thread_list_number_running (PkThreadList *tlist)
+{
+	guint i;
+	guint length;
+	PkThreadListItem *item;
+	guint number = 0;
+
+	g_return_val_if_fail (tlist != NULL, FALSE);
+	g_return_val_if_fail (PK_IS_THREAD_LIST (tlist), FALSE);
+
+	/* find all the running threads */
+	length = tlist->priv->thread_list->len;
+	for (i=0; i<length; i++) {
+		item = (PkThreadListItem *) g_ptr_array_index (tlist->priv->thread_list, i);
+		if (item->running == TRUE) {
+			number++;
+		}
+	}
+	return number;
+}
+
+/**
  * pk_thread_list_class_init:
  * @klass: The PkThreadListClass
  **/
diff --git a/src/pk-thread-list.h b/src/pk-thread-list.h
index 914bfcc..3b245a1 100644
--- a/src/pk-thread-list.h
+++ b/src/pk-thread-list.h
@@ -57,6 +57,7 @@ gboolean	 pk_thread_list_create			(PkThr
 							 gpointer	 param,
 							 gpointer	 data);
 gboolean	 pk_thread_list_wait			(PkThreadList	*tlist);
+guint		 pk_thread_list_number_running		(PkThreadList	*tlist);
 
 G_END_DECLS
 
diff-tree 205341f7021209c588629b92807aa5092c0861d1 (from 37a254b3c842aac607c5ce9961800e8a3779ca38)
Author: Richard Hughes <richard at hughsie.com>
Date:   Mon Sep 17 12:30:57 2007 +0100

    don't give the success value with pk_backend_finished, we can infer it from the presence or absence of an error (and the retval for bad scripts)

diff --git a/backends/alpm/pk-backend-alpm.c b/backends/alpm/pk-backend-alpm.c
index 6f0ea1f..83228d9 100644
--- a/backends/alpm/pk-backend-alpm.c
+++ b/backends/alpm/pk-backend-alpm.c
@@ -370,7 +370,7 @@ backend_get_depends (PkBackend *backend,
 			 "The GLib library");
 	pk_backend_package (backend, 1, "gtk2;gtk2-2.11.6-6.fc8;i386;fedora",
 			 "GTK+ Libraries for GIMP");
-	pk_backend_finished (backend, PK_EXIT_ENUM_SUCCESS);
+	pk_backend_finished (backend);
 }
 
 /**
@@ -381,13 +381,8 @@ backend_get_description (PkBackend *back
 {
 	g_return_if_fail (backend != NULL);
 	PkPackageId *id = pk_package_id_new_from_string (package_id);
-	if (id == NULL)
-	  {
-	    pk_backend_finished (backend, PK_EXIT_ENUM_FAILED);
-	    return;
-	  }
 	//pk_backend_description (backend, package_id, "unknown", PK_GROUP_ENUM_PROGRAMMING, "sdgd");
-	pk_backend_finished (backend, PK_EXIT_ENUM_SUCCESS);
+	pk_backend_finished (backend);
 }
 
 /**
@@ -401,7 +396,7 @@ backend_get_requires (PkBackend *backend
 			 "The GLib library");
 	pk_backend_package (backend, 1, "gtk2;gtk2-2.11.6-6.fc8;i386;fedora",
 			 "GTK+ Libraries for GIMP");
-	pk_backend_finished (backend, PK_EXIT_ENUM_SUCCESS);
+	pk_backend_finished (backend);
 }
 
 /**
@@ -416,7 +411,7 @@ backend_get_updates (PkBackend *backend)
 	pk_backend_package (backend, 1, "kernel;2.6.23-0.115.rc3.git1.fc8;i386;installed",
 			 "The Linux kernel (the core of the Linux operating system)");
 	pk_backend_package (backend, 1, "gtkhtml2;2.19.1-4.fc8;i386;fedora", "An HTML widget for GTK+ 2.0");
-	pk_backend_finished (backend, PK_EXIT_ENUM_SUCCESS);
+	pk_backend_finished (backend);
 }
 
 static gboolean
@@ -424,7 +419,7 @@ backend_install_timeout (gpointer data)
 {
 	PkBackend *backend = (PkBackend *) data;
 	if (progress_percentage == 100) {
-		pk_backend_finished (backend, PK_EXIT_ENUM_SUCCESS);
+		pk_backend_finished (backend);
 		return FALSE;
 	}
 	if (progress_percentage == 50) {
@@ -463,7 +458,7 @@ backend_refresh_cache (PkBackend *backen
 	    pk_backend_error_code (backend,
 				   PK_ERROR_ENUM_TRANSACTION_ERROR,
 				   alpm_strerror (pm_errno));
-	    pk_backend_finished (backend, PK_EXIT_ENUM_FAILED);
+	    pk_backend_finished (backend);
 	    return;
 	  }
 
@@ -474,7 +469,7 @@ backend_refresh_cache (PkBackend *backen
 	    pk_backend_error_code (backend,
 				   PK_ERROR_ENUM_TRANSACTION_ERROR,
 				   alpm_strerror (pm_errno));
-	    pk_backend_finished (backend, PK_EXIT_ENUM_FAILED);
+	    pk_backend_finished (backend);
 	    return;
 	  }*/
 
@@ -489,14 +484,14 @@ backend_refresh_cache (PkBackend *backen
 				       PK_ERROR_ENUM_TRANSACTION_ERROR,
 				       alpm_strerror (pm_errno));
 		alpm_list_free (dbs);
-		pk_backend_finished (backend, PK_EXIT_ENUM_FAILED);
+		pk_backend_finished (backend);
 		subprogress_percentage = -1;
 		return;
 	      }
 	    subprogress_percentage = -1;
 	  }
 
-	pk_backend_finished (backend, PK_EXIT_ENUM_SUCCESS);
+	pk_backend_finished (backend);
 }
 
 /**
@@ -507,7 +502,7 @@ backend_remove_package (PkBackend *backe
 {
 	g_return_if_fail (backend != NULL);
 	pk_backend_error_code (backend, PK_ERROR_ENUM_NO_NETWORK, "No network connection available");
-	pk_backend_finished (backend, PK_EXIT_ENUM_FAILED);
+	pk_backend_finished (backend);
 }
 
 /**
@@ -519,7 +514,7 @@ backend_search_details (PkBackend *backe
 	g_return_if_fail (backend != NULL);
 	pk_backend_package (backend, 0, "vips-doc;7.12.4-2.fc8;noarch;linva",
 			 "The vips documentation package.");
-	pk_backend_finished (backend, PK_EXIT_ENUM_SUCCESS);
+	pk_backend_finished (backend);
 }
 
 /**
@@ -531,7 +526,7 @@ backend_search_file (PkBackend *backend,
 	g_return_if_fail (backend != NULL);
 	pk_backend_package (backend, 0, "vips-doc;7.12.4-2.fc8;noarch;linva",
 			 "The vips documentation package.");
-	pk_backend_finished (backend, PK_EXIT_ENUM_SUCCESS);
+	pk_backend_finished (backend);
 }
 
 /**
@@ -543,7 +538,7 @@ backend_search_group (PkBackend *backend
 	g_return_if_fail (backend != NULL);
 	pk_backend_package (backend, 0, "vips-doc;7.12.4-2.fc8;noarch;linva",
 			 "The vips documentation package.");
-	pk_backend_finished (backend, PK_EXIT_ENUM_SUCCESS);
+	pk_backend_finished (backend);
 }
 
 /**
@@ -614,7 +609,7 @@ backend_search_name (PkBackend *backend,
 	if (!ninstalled) filter_packages_installed (result, FALSE);
 
 	add_packages_from_list (backend, alpm_list_first (result));
-	pk_backend_finished  (backend, PK_EXIT_ENUM_SUCCESS);
+	pk_backend_finished (backend);
 }
 
 /**
@@ -625,7 +620,7 @@ backend_update_package (PkBackend *backe
 {
 	g_return_if_fail (backend != NULL);
 	pk_backend_package (backend, 1, package_id, "The same thing");
-	pk_backend_finished (backend, PK_EXIT_ENUM_SUCCESS);
+	pk_backend_finished (backend);
 }
 
 static gboolean
@@ -633,7 +628,7 @@ backend_update_system_timeout (gpointer 
 {
 	PkBackend *backend = (PkBackend *) data;
 	if (progress_percentage == 100) {
-		pk_backend_finished (backend, PK_EXIT_ENUM_SUCCESS);
+		pk_backend_finished (backend);
 		return FALSE;
 	}
 	pk_backend_change_job_status (backend, PK_STATUS_ENUM_UPDATE);
diff --git a/backends/apt/pk-backend-apt.cpp b/backends/apt/pk-backend-apt.cpp
index e2c01d5..67f652d 100644
--- a/backends/apt/pk-backend-apt.cpp
+++ b/backends/apt/pk-backend-apt.cpp
@@ -170,7 +170,7 @@ void *do_update_thread(gpointer data)
 	if (List.ReadMainList() == false)
 	{
 		pk_backend_error_code(ud->backend, PK_ERROR_ENUM_UNKNOWN, "Failure reading lists");
-		pk_backend_finished(ud->backend, PK_EXIT_ENUM_FAILED);
+		pk_backend_finished(ud->backend);
 		return NULL;
 	}
 
@@ -183,7 +183,7 @@ void *do_update_thread(gpointer data)
 		{
 			_error->DumpErrors();
 			pk_backend_error_code(ud->backend, PK_ERROR_ENUM_UNKNOWN, "Unable to lock the list directory");
-			pk_backend_finished(ud->backend, PK_EXIT_ENUM_FAILED);
+			pk_backend_finished(ud->backend);
 			return NULL;
 		}
 	}
@@ -252,12 +252,12 @@ void *do_update_thread(gpointer data)
 	}
 
 	delete Stat;
-	pk_backend_finished(ud->backend, PK_EXIT_ENUM_SUCCESS);
+	pk_backend_finished(ud->backend);
 	return NULL;
 
 	do_update_clean:
 	delete Stat;
-	pk_backend_finished(ud->backend, PK_EXIT_ENUM_FAILED);
+	pk_backend_finished(ud->backend);
 	return NULL;
 }
 
@@ -298,7 +298,7 @@ static void backend_refresh_cache(PkBack
 	if (pk_backend_network_is_online(backend) == FALSE)
 	{
 		pk_backend_error_code(backend, PK_ERROR_ENUM_NO_NETWORK, "Cannot refresh cache whilst offline");
-		pk_backend_finished(backend, PK_EXIT_ENUM_FAILED);
+		pk_backend_finished(backend);
 		return;
 	}
 
@@ -306,7 +306,7 @@ static void backend_refresh_cache(PkBack
 	if (data == NULL)
 	{
 		pk_backend_error_code(backend, PK_ERROR_ENUM_OOM, "Failed to allocate memory for update task");
-		pk_backend_finished(backend, PK_EXIT_ENUM_FAILED);
+		pk_backend_finished(backend);
 	}
 	else
 	{
@@ -314,7 +314,7 @@ static void backend_refresh_cache(PkBack
 		if (g_thread_create(do_update_thread, data, false, NULL) == NULL)
 		{
 			pk_backend_error_code(backend, PK_ERROR_ENUM_CREATE_THREAD_FAILED, "Failed to create update thread");
-			pk_backend_finished(backend, PK_EXIT_ENUM_FAILED);
+			pk_backend_finished(backend);
 		}
 	}
 }
@@ -402,7 +402,7 @@ static void *get_search_thread(gpointer 
 	if (regcomp(Pattern, st->search, REG_EXTENDED | REG_ICASE | REG_NOSUB) != 0)
 	{
 		pk_backend_error_code(st->backend, PK_ERROR_ENUM_UNKNOWN, "regex compilation error");
-		pk_backend_finished(st->backend, PK_EXIT_ENUM_FAILED);
+		pk_backend_finished(st->backend);
 		goto search_task_cleanup;
 	}
 
@@ -470,7 +470,7 @@ static void *get_search_thread(gpointer 
 		}
 	}
 
-	pk_backend_finished(st->backend, PK_EXIT_ENUM_SUCCESS);
+	pk_backend_finished(st->backend);
 
 search_task_cleanup:
 	for (ExDescFile * J = DFList; J->Df != 0; J++)
@@ -496,7 +496,7 @@ pk_backend_search(PkBackend * backend, c
 	if (data == NULL)
 	{
 		pk_backend_error_code(backend, PK_ERROR_ENUM_OOM, "Failed to allocate memory for search task");
-		pk_backend_finished(backend, PK_EXIT_ENUM_FAILED);
+		pk_backend_finished(backend);
 	}
 	else
 	{
@@ -508,7 +508,7 @@ pk_backend_search(PkBackend * backend, c
 		if (g_thread_create(search_thread, data, false, NULL) == NULL)
 		{
 			pk_backend_error_code(backend, PK_ERROR_ENUM_CREATE_THREAD_FAILED, "Failed to spawn thread");
-			pk_backend_finished(backend, PK_EXIT_ENUM_FAILED);
+			pk_backend_finished(backend);
 		}
 	}
 }
@@ -613,7 +613,7 @@ backend_get_description (PkBackend *back
 	if (data == NULL)
 	{
 		pk_backend_error_code(backend, PK_ERROR_ENUM_OOM, "Failed to allocate memory for search task");
-		pk_backend_finished(backend, PK_EXIT_ENUM_FAILED);
+		pk_backend_finished(backend);
 		return;
 	}
 
@@ -622,14 +622,14 @@ backend_get_description (PkBackend *back
 	if (data->pi == NULL)
 	{
 		pk_backend_error_code(backend, PK_ERROR_ENUM_PACKAGE_ID_INVALID, "invalid package id");
-		pk_backend_finished(backend, PK_EXIT_ENUM_FAILED);
+		pk_backend_finished(backend);
 		return;
 	}
 
 	if (g_thread_create(get_description_thread, data, false, NULL) == NULL)
 	{
 		pk_backend_error_code(backend, PK_ERROR_ENUM_CREATE_THREAD_FAILED, "Failed to spawn description thread");
-		pk_backend_finished(backend, PK_EXIT_ENUM_FAILED);
+		pk_backend_finished(backend);
 	}
 	return;
 }
@@ -665,7 +665,7 @@ static void *do_search_file(gpointer dat
 		pk_backend_error_code(st->backend, PK_ERROR_ENUM_INTERNAL_ERROR, "can't open %s",ldir);
 		g_free(ldir);
 		g_error_free(error);
-		pk_backend_finished(st->backend, PK_EXIT_ENUM_FAILED);
+		pk_backend_finished(st->backend);
 		return NULL;
 	}
 	const gchar * fname = NULL;
@@ -674,10 +674,10 @@ static void *do_search_file(gpointer dat
 		//pk_backend_package(st->backend, J->installed, pid, P.ShortDesc().c_str());
 	}
 	pk_backend_error_code(st->backend, PK_ERROR_ENUM_INTERNAL_ERROR, "search file is incomplete");
-	pk_backend_finished(st->backend, PK_EXIT_ENUM_FAILED);
+	pk_backend_finished(st->backend);
 	g_dir_close(list);
 	g_free(ldir);
-	//pk_backend_finished(st->backend, PK_EXIT_ENUM_SUCCESS);
+	//pk_backend_finished(st->backend);
 	return NULL;
 }
 
diff --git a/backends/box/pk-backend-box.c b/backends/box/pk-backend-box.c
index ba535c0..ba173ef 100644
--- a/backends/box/pk-backend-box.c
+++ b/backends/box/pk-backend-box.c
@@ -166,11 +166,11 @@ find_packages_real (PkBackend *backend, 
 		list = box_db_repos_search_file (db, search);
 		add_packages_from_list (backend, list);
 		box_db_repos_package_list_free (list);
-		pk_backend_finished (backend, PK_EXIT_ENUM_SUCCESS);
+		pk_backend_finished (backend);
 	} else {
 		if (installed == FALSE && available == FALSE) {
 			pk_backend_error_code (backend, PK_ERROR_ENUM_UNKNOWN, "invalid search mode");
-			pk_backend_finished (backend, PK_EXIT_ENUM_FAILED);
+			pk_backend_finished (backend);
 		} else	{
 			if (installed == TRUE && available == TRUE) {
 				list = box_db_repos_packages_search_all(db, (gchar *)search, search_filter);
@@ -181,7 +181,7 @@ find_packages_real (PkBackend *backend, 
 			}
 			add_packages_from_list (backend, list);
 			box_db_repos_package_list_free (list);
-			pk_backend_finished (backend, PK_EXIT_ENUM_SUCCESS);
+			pk_backend_finished (backend);
 		}
 	}
 
@@ -214,7 +214,7 @@ find_packages (PkBackend *backend, const
 
 	if (data == NULL) {
 		pk_backend_error_code(backend, PK_ERROR_ENUM_OOM, "Failed to allocate memory");
-		pk_backend_finished(backend, PK_EXIT_ENUM_FAILED);
+		pk_backend_finished (backend);
 	} else {
 		data->backend = backend;
 		data->search = g_strdup(search);
@@ -223,7 +223,7 @@ find_packages (PkBackend *backend, const
 
 		if (g_thread_create(find_packages_thread, data, FALSE, NULL) == NULL) {
 			pk_backend_error_code(backend, PK_ERROR_ENUM_CREATE_THREAD_FAILED, "Failed to create thread");
-			pk_backend_finished(backend, PK_EXIT_ENUM_FAILED);
+			pk_backend_finished (backend);
 		}
 
 	}
@@ -263,7 +263,7 @@ get_updates_thread(gpointer data)
 	add_packages_from_list (d->backend, list);
 	box_db_repos_package_list_free (list);
 
-	pk_backend_finished (d->backend, PK_EXIT_ENUM_SUCCESS);
+	pk_backend_finished (d->backend);
 
 	g_free(d);
 	db_close (db);
@@ -282,7 +282,7 @@ get_description_thread(gpointer data)
 	pi = pk_package_id_new_from_string (d->package_id);
 	if (pi == NULL) {
 		pk_backend_error_code (d->backend, PK_ERROR_ENUM_PACKAGE_ID_INVALID, "invalid package id");
-		pk_backend_finished (d->backend, PK_EXIT_ENUM_FAILED);
+		pk_backend_finished (d->backend);
 		return NULL;
 	}
 
@@ -291,7 +291,7 @@ get_description_thread(gpointer data)
 	ps = (PackageSearch*) list->data;
 	if (list == NULL) {
 		pk_backend_error_code (d->backend, PK_ERROR_ENUM_PACKAGE_ID_INVALID, "cannot find package by id");
-		pk_backend_finished (d->backend, PK_EXIT_ENUM_FAILED);
+		pk_backend_finished (d->backend);
 		return NULL;
 	}
 
@@ -300,7 +300,7 @@ get_description_thread(gpointer data)
 	pk_package_id_free (pi);
 	box_db_repos_package_list_free (list);
 
-	pk_backend_finished (d->backend, PK_EXIT_ENUM_SUCCESS);
+	pk_backend_finished (d->backend);
 	g_free (d->package_id);
 	g_free (d);
 
@@ -367,14 +367,14 @@ backend_get_description (PkBackend *back
 
 	if (data == NULL) {
 		pk_backend_error_code(backend, PK_ERROR_ENUM_OOM, "Failed to allocate memory");
-		pk_backend_finished(backend, PK_EXIT_ENUM_FAILED);
+		pk_backend_finished (backend);
 	} else {
 		data->backend = backend;
 		data->package_id = g_strdup(package_id);
 
 		if (g_thread_create(get_description_thread, data, FALSE, NULL) == NULL) {
 			pk_backend_error_code(backend, PK_ERROR_ENUM_CREATE_THREAD_FAILED, "Failed to create thread");
-			pk_backend_finished(backend, PK_EXIT_ENUM_FAILED);
+			pk_backend_finished (backend);
 		}
 	}
 
@@ -393,13 +393,13 @@ backend_get_updates (PkBackend *backend)
 
 	if (data == NULL) {
 		pk_backend_error_code(backend, PK_ERROR_ENUM_OOM, "Failed to allocate memory");
-		pk_backend_finished(backend, PK_EXIT_ENUM_FAILED);
+		pk_backend_finished (backend);
 	} else {
 		data->backend = backend;
 
 		if (g_thread_create(get_updates_thread, data, FALSE, NULL) == NULL) {
 			pk_backend_error_code(backend, PK_ERROR_ENUM_CREATE_THREAD_FAILED, "Failed to create thread");
-			pk_backend_finished(backend, PK_EXIT_ENUM_FAILED);
+			pk_backend_finished (backend);
 		}
 	}
 }
@@ -415,7 +415,7 @@ backend_install_package (PkBackend *back
         /* check network state */
         if (pk_backend_network_is_online (backend) == FALSE) {
                 pk_backend_error_code (backend, PK_ERROR_ENUM_NO_NETWORK, "Cannot install when offline");
-                pk_backend_finished (backend, PK_EXIT_ENUM_FAILED);
+                pk_backend_finished (backend);
                 return;
         }
         pk_backend_spawn_helper (backend, "install-package.sh", package_id, NULL);
@@ -431,7 +431,7 @@ backend_refresh_cache (PkBackend *backen
 	/* check network state */
 	if (pk_backend_network_is_online (backend) == FALSE) {
 		pk_backend_error_code (backend, PK_ERROR_ENUM_NO_NETWORK, "Cannot refresh cache whilst offline");
-		pk_backend_finished (backend, PK_EXIT_ENUM_FAILED);
+		pk_backend_finished (backend);
 		return;
 	}
 	pk_backend_change_job_status (backend, PK_STATUS_ENUM_REFRESH_CACHE);
diff --git a/backends/conary/pk-backend-conary.c b/backends/conary/pk-backend-conary.c
index b71dc36..3fee64f 100644
--- a/backends/conary/pk-backend-conary.c
+++ b/backends/conary/pk-backend-conary.c
@@ -84,7 +84,7 @@ backend_install_package (PkBackend *back
 	/* check network state */
 	if (pk_backend_network_is_online (backend) == FALSE) {
 		pk_backend_error_code (backend, PK_ERROR_ENUM_NO_NETWORK, "Cannot install when offline");
-		pk_backend_finished (backend, PK_EXIT_ENUM_FAILED);
+		pk_backend_finished (backend);
 		return;
 	}
 	pk_backend_spawn_helper (backend, "install.py", package_id, NULL);
@@ -100,7 +100,7 @@ backend_refresh_cache (PkBackend *backen
 	/* check network state */
 	if (pk_backend_network_is_online (backend) == FALSE) {
 		pk_backend_error_code (backend, PK_ERROR_ENUM_NO_NETWORK, "Cannot refresh cache whilst offline");
-		pk_backend_finished (backend, PK_EXIT_ENUM_FAILED);
+		pk_backend_finished (backend);
 		return;
 	}
 	pk_backend_spawn_helper (backend, "refresh-cache.py", NULL);
diff --git a/backends/dummy/pk-backend-dummy.c b/backends/dummy/pk-backend-dummy.c
index 98f3bd0..d843522 100644
--- a/backends/dummy/pk-backend-dummy.c
+++ b/backends/dummy/pk-backend-dummy.c
@@ -93,7 +93,7 @@ backend_get_depends (PkBackend *backend,
 			 "The GLib library");
 	pk_backend_package (backend, 1, "gtk2;gtk2-2.11.6-6.fc8;i386;fedora",
 			 "GTK+ Libraries for GIMP");
-	pk_backend_finished (backend, PK_EXIT_ENUM_SUCCESS);
+	pk_backend_finished (backend);
 }
 
 /**
@@ -112,7 +112,7 @@ backend_get_description (PkBackend *back
 "understand tools, Scribus offers support for professional publishing "
 "features, such as CMYK color, easy PDF creation, Encapsulated Postscript "
 "import/export and creation of color separations.", "http://live.gnome.org/GnomePowerManager");
-	pk_backend_finished (backend, PK_EXIT_ENUM_SUCCESS);
+	pk_backend_finished (backend);
 }
 
 /**
@@ -126,7 +126,7 @@ backend_get_requires (PkBackend *backend
 			 "The GLib library");
 	pk_backend_package (backend, 1, "gtk2;gtk2-2.11.6-6.fc8;i386;fedora",
 			 "GTK+ Libraries for GIMP");
-	pk_backend_finished (backend, PK_EXIT_ENUM_SUCCESS);
+	pk_backend_finished (backend);
 }
 
 /**
@@ -140,7 +140,7 @@ backend_get_update_detail (PkBackend *ba
 				  "glib2;2.12.0;i386;fedora", "",
 				  "http://nvd.nist.gov/nvd.cfm?cvename=CVE-2007-3381",
 				  "system", "Update to newest upstream source");
-	pk_backend_finished (backend, PK_EXIT_ENUM_SUCCESS);
+	pk_backend_finished (backend);
 }
 
 /**
@@ -155,7 +155,7 @@ backend_get_updates (PkBackend *backend)
 	pk_backend_package (backend, 1, "kernel;2.6.23-0.115.rc3.git1.fc8;i386;installed",
 			 "The Linux kernel (the core of the Linux operating system)");
 	pk_backend_package (backend, 1, "gtkhtml2;2.19.1-4.fc8;i386;fedora", "An HTML widget for GTK+ 2.0");
-	pk_backend_finished (backend, PK_EXIT_ENUM_SUCCESS);
+	pk_backend_finished (backend);
 }
 
 static gboolean
@@ -163,7 +163,7 @@ backend_install_timeout (gpointer data)
 {
 	PkBackend *backend = (PkBackend *) data;
 	if (progress_percentage == 100) {
-		pk_backend_finished (backend, PK_EXIT_ENUM_SUCCESS);
+		pk_backend_finished (backend);
 		return FALSE;
 	}
 	if (progress_percentage == 50) {
@@ -192,7 +192,7 @@ static void
 backend_refresh_cache (PkBackend *backend, gboolean force)
 {
 	g_return_if_fail (backend != NULL);
-	pk_backend_finished (backend, PK_EXIT_ENUM_SUCCESS);
+	pk_backend_finished (backend);
 }
 
 /**
@@ -203,7 +203,7 @@ backend_remove_package (PkBackend *backe
 {
 	g_return_if_fail (backend != NULL);
 	pk_backend_error_code (backend, PK_ERROR_ENUM_NO_NETWORK, "No network connection available");
-	pk_backend_finished (backend, PK_EXIT_ENUM_FAILED);
+	pk_backend_finished (backend);
 }
 
 /**
@@ -215,7 +215,7 @@ backend_search_details (PkBackend *backe
 	g_return_if_fail (backend != NULL);
 	pk_backend_package (backend, 0, "vips-doc;7.12.4-2.fc8;noarch;linva",
 			 "The vips documentation package.");
-	pk_backend_finished (backend, PK_EXIT_ENUM_SUCCESS);
+	pk_backend_finished (backend);
 }
 
 /**
@@ -227,7 +227,7 @@ backend_search_file (PkBackend *backend,
 	g_return_if_fail (backend != NULL);
 	pk_backend_package (backend, 0, "vips-doc;7.12.4-2.fc8;noarch;linva",
 			 "The vips documentation package.");
-	pk_backend_finished (backend, PK_EXIT_ENUM_SUCCESS);
+	pk_backend_finished (backend);
 }
 
 /**
@@ -239,7 +239,7 @@ backend_search_group (PkBackend *backend
 	g_return_if_fail (backend != NULL);
 	pk_backend_package (backend, 0, "vips-doc;7.12.4-2.fc8;noarch;linva",
 			 "The vips documentation package.");
-	pk_backend_finished (backend, PK_EXIT_ENUM_SUCCESS);
+	pk_backend_finished (backend);
 }
 
 /**
@@ -257,7 +257,7 @@ backend_search_name_timeout (gpointer da
 			 "Scribus is an desktop open source page layout program");
 	pk_backend_package (backend, 0, "vips-doc;7.12.4-2.fc8;noarch;linva",
 			 "The vips documentation package.");
-	pk_backend_finished (backend, PK_EXIT_ENUM_SUCCESS);
+	pk_backend_finished (backend);
 	return FALSE;
 }
 
@@ -280,7 +280,7 @@ backend_update_package (PkBackend *backe
 {
 	g_return_if_fail (backend != NULL);
 	pk_backend_package (backend, 1, package_id, "The same thing");
-	pk_backend_finished (backend, PK_EXIT_ENUM_SUCCESS);
+	pk_backend_finished (backend);
 }
 
 static gboolean
@@ -288,7 +288,7 @@ backend_update_system_timeout (gpointer 
 {
 	PkBackend *backend = (PkBackend *) data;
 	if (progress_percentage == 100) {
-		pk_backend_finished (backend, PK_EXIT_ENUM_SUCCESS);
+		pk_backend_finished (backend);
 		return FALSE;
 	}
 	pk_backend_change_job_status (backend, PK_STATUS_ENUM_UPDATE);
diff --git a/backends/test/pk-backend-test-fail.c b/backends/test/pk-backend-test-fail.c
index dd52668..45c6d0a 100644
--- a/backends/test/pk-backend-test-fail.c
+++ b/backends/test/pk-backend-test-fail.c
@@ -59,7 +59,7 @@ static void
 backend_cancel_job_try (PkBackend *backend)
 {
 	g_return_if_fail (backend != NULL);
-	pk_backend_finished (backend, PK_EXIT_ENUM_FAILED);
+	pk_backend_finished (backend);
 }
 
 /**
@@ -69,7 +69,7 @@ static void
 backend_get_depends (PkBackend *backend, const gchar *package_id)
 {
 	g_return_if_fail (backend != NULL);
-	pk_backend_finished (backend, PK_EXIT_ENUM_FAILED);
+	pk_backend_finished (backend);
 }
 
 /**
@@ -79,7 +79,7 @@ static void
 backend_get_description (PkBackend *backend, const gchar *package_id)
 {
 	g_return_if_fail (backend != NULL);
-	pk_backend_finished (backend, PK_EXIT_ENUM_FAILED);
+	pk_backend_finished (backend);
 }
 
 /**
@@ -89,7 +89,7 @@ static void
 backend_get_requires (PkBackend *backend, const gchar *package_id)
 {
 	g_return_if_fail (backend != NULL);
-	pk_backend_finished (backend, PK_EXIT_ENUM_FAILED);
+	pk_backend_finished (backend);
 }
 
 /**
@@ -99,7 +99,7 @@ static void
 backend_get_update_detail (PkBackend *backend, const gchar *package_id)
 {
 	g_return_if_fail (backend != NULL);
-	pk_backend_finished (backend, PK_EXIT_ENUM_FAILED);
+	pk_backend_finished (backend);
 }
 
 /**
@@ -109,7 +109,7 @@ static void
 backend_get_updates (PkBackend *backend)
 {
 	g_return_if_fail (backend != NULL);
-	pk_backend_finished (backend, PK_EXIT_ENUM_FAILED);
+	pk_backend_finished (backend);
 }
 
 /**
@@ -119,7 +119,7 @@ static void
 backend_install_package (PkBackend *backend, const gchar *package_id)
 {
 	g_return_if_fail (backend != NULL);
-	pk_backend_finished (backend, PK_EXIT_ENUM_FAILED);
+	pk_backend_finished (backend);
 }
 
 /**
@@ -129,7 +129,7 @@ static void
 backend_refresh_cache (PkBackend *backend, gboolean force)
 {
 	g_return_if_fail (backend != NULL);
-	pk_backend_finished (backend, PK_EXIT_ENUM_FAILED);
+	pk_backend_finished (backend);
 }
 
 /**
@@ -139,7 +139,7 @@ static void
 backend_remove_package (PkBackend *backend, const gchar *package_id, gboolean allow_deps)
 {
 	g_return_if_fail (backend != NULL);
-	pk_backend_finished (backend, PK_EXIT_ENUM_FAILED);
+	pk_backend_finished (backend);
 }
 
 /**
@@ -149,7 +149,7 @@ static void
 backend_search_details (PkBackend *backend, const gchar *filter, const gchar *search)
 {
 	g_return_if_fail (backend != NULL);
-	pk_backend_finished (backend, PK_EXIT_ENUM_FAILED);
+	pk_backend_finished (backend);
 }
 
 /**
@@ -159,7 +159,7 @@ static void
 backend_search_file (PkBackend *backend, const gchar *filter, const gchar *search)
 {
 	g_return_if_fail (backend != NULL);
-	pk_backend_finished (backend, PK_EXIT_ENUM_FAILED);
+	pk_backend_finished (backend);
 }
 
 /**
@@ -169,7 +169,7 @@ static void
 backend_search_group (PkBackend *backend, const gchar *filter, const gchar *search)
 {
 	g_return_if_fail (backend != NULL);
-	pk_backend_finished (backend, PK_EXIT_ENUM_FAILED);
+	pk_backend_finished (backend);
 }
 
 /**
@@ -179,7 +179,7 @@ static void
 backend_search_name (PkBackend *backend, const gchar *filter, const gchar *search)
 {
 	g_return_if_fail (backend != NULL);
-	pk_backend_finished (backend, PK_EXIT_ENUM_FAILED);
+	pk_backend_finished (backend);
 }
 
 /**
@@ -189,7 +189,7 @@ static void
 backend_update_package (PkBackend *backend, const gchar *package_id)
 {
 	g_return_if_fail (backend != NULL);
-	pk_backend_finished (backend, PK_EXIT_ENUM_FAILED);
+	pk_backend_finished (backend);
 }
 
 /**
@@ -199,7 +199,7 @@ static void
 backend_update_system (PkBackend *backend)
 {
 	g_return_if_fail (backend != NULL);
-	pk_backend_finished (backend, PK_EXIT_ENUM_FAILED);
+	pk_backend_finished (backend);
 }
 
 PK_BACKEND_OPTIONS (
diff --git a/backends/test/pk-backend-test-succeed.c b/backends/test/pk-backend-test-succeed.c
index 9fadeee..c9d2c3a 100644
--- a/backends/test/pk-backend-test-succeed.c
+++ b/backends/test/pk-backend-test-succeed.c
@@ -77,7 +77,7 @@ static void
 backend_cancel_job_try (PkBackend *backend)
 {
 	g_return_if_fail (backend != NULL);
-	pk_backend_finished (backend, PK_EXIT_ENUM_SUCCESS);
+	pk_backend_finished (backend);
 }
 
 /**
@@ -87,7 +87,7 @@ static void
 backend_get_depends (PkBackend *backend, const gchar *package_id)
 {
 	g_return_if_fail (backend != NULL);
-	pk_backend_finished (backend, PK_EXIT_ENUM_SUCCESS);
+	pk_backend_finished (backend);
 }
 
 /**
@@ -97,7 +97,7 @@ static void
 backend_get_description (PkBackend *backend, const gchar *package_id)
 {
 	g_return_if_fail (backend != NULL);
-	pk_backend_finished (backend, PK_EXIT_ENUM_SUCCESS);
+	pk_backend_finished (backend);
 }
 
 /**
@@ -107,7 +107,7 @@ static void
 backend_get_requires (PkBackend *backend, const gchar *package_id)
 {
 	g_return_if_fail (backend != NULL);
-	pk_backend_finished (backend, PK_EXIT_ENUM_SUCCESS);
+	pk_backend_finished (backend);
 }
 
 /**
@@ -117,7 +117,7 @@ static void
 backend_get_update_detail (PkBackend *backend, const gchar *package_id)
 {
 	g_return_if_fail (backend != NULL);
-	pk_backend_finished (backend, PK_EXIT_ENUM_SUCCESS);
+	pk_backend_finished (backend);
 }
 
 /**
@@ -127,7 +127,7 @@ static void
 backend_get_updates (PkBackend *backend)
 {
 	g_return_if_fail (backend != NULL);
-	pk_backend_finished (backend, PK_EXIT_ENUM_SUCCESS);
+	pk_backend_finished (backend);
 }
 
 /**
@@ -137,7 +137,7 @@ static void
 backend_install_package (PkBackend *backend, const gchar *package_id)
 {
 	g_return_if_fail (backend != NULL);
-	pk_backend_finished (backend, PK_EXIT_ENUM_SUCCESS);
+	pk_backend_finished (backend);
 }
 
 /**
@@ -147,7 +147,7 @@ static void
 backend_refresh_cache (PkBackend *backend, gboolean force)
 {
 	g_return_if_fail (backend != NULL);
-	pk_backend_finished (backend, PK_EXIT_ENUM_SUCCESS);
+	pk_backend_finished (backend);
 }
 
 /**
@@ -157,7 +157,7 @@ static void
 backend_remove_package (PkBackend *backend, const gchar *package_id, gboolean allow_deps)
 {
 	g_return_if_fail (backend != NULL);
-	pk_backend_finished (backend, PK_EXIT_ENUM_SUCCESS);
+	pk_backend_finished (backend);
 }
 
 /**
@@ -167,7 +167,7 @@ static void
 backend_search_details (PkBackend *backend, const gchar *filter, const gchar *search)
 {
 	g_return_if_fail (backend != NULL);
-	pk_backend_finished (backend, PK_EXIT_ENUM_SUCCESS);
+	pk_backend_finished (backend);
 }
 
 /**
@@ -177,7 +177,7 @@ static void
 backend_search_file (PkBackend *backend, const gchar *filter, const gchar *search)
 {
 	g_return_if_fail (backend != NULL);
-	pk_backend_finished (backend, PK_EXIT_ENUM_SUCCESS);
+	pk_backend_finished (backend);
 }
 
 /**
@@ -187,7 +187,7 @@ static void
 backend_search_group (PkBackend *backend, const gchar *filter, const gchar *search)
 {
 	g_return_if_fail (backend != NULL);
-	pk_backend_finished (backend, PK_EXIT_ENUM_SUCCESS);
+	pk_backend_finished (backend);
 }
 
 /**
@@ -197,7 +197,7 @@ static void
 backend_search_name (PkBackend *backend, const gchar *filter, const gchar *search)
 {
 	g_return_if_fail (backend != NULL);
-	pk_backend_finished (backend, PK_EXIT_ENUM_SUCCESS);
+	pk_backend_finished (backend);
 }
 
 /**
@@ -207,7 +207,7 @@ static void
 backend_update_package (PkBackend *backend, const gchar *package_id)
 {
 	g_return_if_fail (backend != NULL);
-	pk_backend_finished (backend, PK_EXIT_ENUM_SUCCESS);
+	pk_backend_finished (backend);
 }
 
 /**
@@ -217,7 +217,7 @@ static void
 backend_update_system (PkBackend *backend)
 {
 	g_return_if_fail (backend != NULL);
-	pk_backend_finished (backend, PK_EXIT_ENUM_SUCCESS);
+	pk_backend_finished (backend);
 }
 
 PK_BACKEND_OPTIONS (
diff --git a/backends/test/pk-backend-test-thread.c b/backends/test/pk-backend-test-thread.c
index 424a237..67e66d0 100644
--- a/backends/test/pk-backend-test-thread.c
+++ b/backends/test/pk-backend-test-thread.c
@@ -46,9 +46,9 @@ backend_search_group (PkBackend *backend
 	g_return_if_fail (backend != NULL);
 	if (pk_backend_thread_create (backend, backend_search_group_thread, NULL) == FALSE) {
 		pk_backend_error_code (backend, PK_ERROR_ENUM_CREATE_THREAD_FAILED, "Failed to create search-group thread");
-		pk_backend_finished (backend, PK_EXIT_ENUM_FAILED);
+		pk_backend_finished (backend);
 	}
-	pk_backend_finished (backend, PK_EXIT_ENUM_SUCCESS);
+	pk_backend_finished (backend);
 }
 
 /**
@@ -86,9 +86,9 @@ backend_search_name (PkBackend *backend,
 	g_return_if_fail (backend != NULL);
 	if (pk_backend_thread_create (backend, backend_search_name_thread, NULL) == FALSE) {
 		pk_backend_error_code (backend, PK_ERROR_ENUM_CREATE_THREAD_FAILED, "Failed to create search-name thread");
-		pk_backend_finished (backend, PK_EXIT_ENUM_FAILED);
+		pk_backend_finished (backend);
 	}
-	pk_backend_finished (backend, PK_EXIT_ENUM_SUCCESS);
+	pk_backend_finished (backend);
 }
 
 PK_BACKEND_OPTIONS (
diff --git a/backends/yum/pk-backend-yum.c b/backends/yum/pk-backend-yum.c
index 278d75c..f9190a0 100644
--- a/backends/yum/pk-backend-yum.c
+++ b/backends/yum/pk-backend-yum.c
@@ -116,7 +116,7 @@ backend_install_package (PkBackend *back
 	/* check network state */
 	if (pk_backend_network_is_online (backend) == FALSE) {
 		pk_backend_error_code (backend, PK_ERROR_ENUM_NO_NETWORK, "Cannot install when offline");
-		pk_backend_finished (backend, PK_EXIT_ENUM_FAILED);
+		pk_backend_finished (backend);
 		return;
 	}
 	pk_backend_spawn_helper (backend, "install.py", package_id, NULL);
@@ -132,7 +132,7 @@ backend_refresh_cache (PkBackend *backen
 	/* check network state */
 	if (pk_backend_network_is_online (backend) == FALSE) {
 		pk_backend_error_code (backend, PK_ERROR_ENUM_NO_NETWORK, "Cannot refresh cache whilst offline");
-		pk_backend_finished (backend, PK_EXIT_ENUM_FAILED);
+		pk_backend_finished (backend);
 		return;
 	}
 	pk_backend_spawn_helper (backend, "refresh-cache.py", NULL);
@@ -209,7 +209,7 @@ backend_update_package (PkBackend *backe
 	/* check network state */
 	if (pk_backend_network_is_online (backend) == FALSE) {
 		pk_backend_error_code (backend, PK_ERROR_ENUM_NO_NETWORK, "Cannot update when offline");
-		pk_backend_finished (backend, PK_EXIT_ENUM_FAILED);
+		pk_backend_finished (backend);
 		return;
 	}
 	pk_backend_spawn_helper (backend, "update.py", package_id, NULL);
diff --git a/src/pk-backend.c b/src/pk-backend.c
index 4e27b36..14f2b99 100644
--- a/src/pk-backend.c
+++ b/src/pk-backend.c
@@ -358,17 +358,16 @@ pk_backend_spawn_helper_delete (PkBacken
 static void
 pk_backend_spawn_finished_cb (PkSpawn *spawn, gint exitcode, PkBackend *backend)
 {
-	PkExitEnum exit;
 	pk_debug ("deleting spawn %p, exit code %i", spawn, exitcode);
 	pk_backend_spawn_helper_delete (backend);
 
-	/* only emit success with a zero exit code */
-	if (exitcode == 0) {
-		exit = PK_EXIT_ENUM_SUCCESS;
-	} else {
-		exit = PK_EXIT_ENUM_FAILED;
+	/* check shit scripts returned an error on failure */
+	if (exitcode != 0 && backend->priv->exit != PK_EXIT_ENUM_FAILED) {
+		pk_warning ("script returned false but did not return error");
+		pk_backend_error_code (backend, PK_ERROR_ENUM_INTERNAL_ERROR,
+				       "Helper returned non-zero return value but did not set error");
 	}
-	pk_backend_finished (backend, exit);
+	pk_backend_finished (backend);
 }
 
 /**
@@ -439,7 +438,7 @@ pk_backend_spawn_helper_internal (PkBack
 	if (ret == FALSE) {
 		pk_backend_spawn_helper_delete (backend);
 		pk_backend_error_code (backend, PK_ERROR_ENUM_INTERNAL_ERROR, "Spawn of helper '%s' failed", command);
-		pk_backend_finished (backend, PK_EXIT_ENUM_FAILED);
+		pk_backend_finished (backend);
 	}
 	g_free (filename);
 	g_free (command);
@@ -688,6 +687,9 @@ pk_backend_error_code (PkBackend *backen
 	g_vsnprintf (buffer, 1024, format, args);
 	va_end (args);
 
+	/* we mark any transaction with errors as failed */
+	backend->priv->exit = PK_EXIT_ENUM_FAILED;
+
 	pk_debug ("emit error-code %i, %s", code, buffer);
 	g_signal_emit (backend, signals [PK_BACKEND_ERROR_CODE], 0, code, buffer);
 
@@ -753,7 +755,7 @@ pk_backend_finished_delay (gpointer data
  * pk_backend_finished:
  **/
 gboolean
-pk_backend_finished (PkBackend *backend, PkExitEnum exit)
+pk_backend_finished (PkBackend *backend)
 {
 	g_return_val_if_fail (backend != NULL, FALSE);
 	g_return_val_if_fail (PK_IS_BACKEND (backend), FALSE);
@@ -764,7 +766,6 @@ pk_backend_finished (PkBackend *backend,
 	/* 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 timeout loop", backend);
-	backend->priv->exit = exit;
 	g_timeout_add (500, pk_backend_finished_delay, backend);
 	return TRUE;
 }
@@ -1293,7 +1294,7 @@ pk_backend_init (PkBackend *backend)
 	backend->priv->last_package = NULL;
 	backend->priv->role = PK_ROLE_ENUM_UNKNOWN;
 	backend->priv->status = PK_STATUS_ENUM_UNKNOWN;
-	backend->priv->exit = PK_EXIT_ENUM_UNKNOWN;
+	backend->priv->exit = PK_EXIT_ENUM_SUCCESS;
 	backend->priv->network = pk_network_new ();
 	backend->priv->thread_list = pk_thread_list_new ();
 }
diff --git a/src/pk-backend.h b/src/pk-backend.h
index c600e5b..151d49d 100644
--- a/src/pk-backend.h
+++ b/src/pk-backend.h
@@ -41,8 +41,7 @@ gboolean	 pk_backend_change_sub_percenta
 gboolean	 pk_backend_change_job_status		(PkBackend	*backend,
 							 PkStatusEnum	 status);
 gboolean	 pk_backend_no_percentage_updates	(PkBackend	*backend);
-gboolean	 pk_backend_finished			(PkBackend	*backend,
-							 PkExitEnum	 exit);
+gboolean	 pk_backend_finished			(PkBackend	*backend);
 gboolean	 pk_backend_package			(PkBackend	*backend,
 							 guint		 value,
 							 const gchar	*package_id,
diff-tree 37a254b3c842aac607c5ce9961800e8a3779ca38 (from dcc6ee612c8be95ea467edd70fb3cce449b2ead6)
Author: Richard Hughes <richard at hughsie.com>
Date:   Mon Sep 17 11:54:49 2007 +0100

    fix the threading backend function. we should emit finished in the method, and wait for the thrad to complete with data else we get a nice race on completion

diff --git a/backends/test/pk-backend-test-thread.c b/backends/test/pk-backend-test-thread.c
index aeb4b95..424a237 100644
--- a/backends/test/pk-backend-test-thread.c
+++ b/backends/test/pk-backend-test-thread.c
@@ -25,6 +25,33 @@
 #include <pk-backend.h>
 
 /**
+ * backend_search_group_thread:
+ */
+static gboolean
+backend_search_group_thread (PkBackend *backend, gpointer data)
+{
+	pk_backend_package (backend, 1, "glib2;2.14.0;i386;fedora",
+			 "The GLib library");
+	pk_backend_package (backend, 1, "gtk2;gtk2-2.11.6-6.fc8;i386;fedora",
+			 "GTK+ Libraries for GIMP");
+	return TRUE;
+}
+
+/**
+ * backend_search_group:
+ */
+static void
+backend_search_group (PkBackend *backend, const gchar *filter, const gchar *search)
+{
+	g_return_if_fail (backend != NULL);
+	if (pk_backend_thread_create (backend, backend_search_group_thread, NULL) == FALSE) {
+		pk_backend_error_code (backend, PK_ERROR_ENUM_CREATE_THREAD_FAILED, "Failed to create search-group thread");
+		pk_backend_finished (backend, PK_EXIT_ENUM_FAILED);
+	}
+	pk_backend_finished (backend, PK_EXIT_ENUM_SUCCESS);
+}
+
+/**
  * backend_search_name_thread:
  */
 static gboolean
@@ -47,7 +74,6 @@ backend_search_name_thread (PkBackend *b
 			 "The GLib library");
 	pk_backend_package (backend, 1, "gtk2;gtk2-2.11.6-6.fc8;i386;fedora",
 			 "GTK+ Libraries for GIMP");
-	pk_backend_finished(backend, PK_EXIT_ENUM_SUCCESS);
 	return TRUE;
 }
 
@@ -58,10 +84,11 @@ static void
 backend_search_name (PkBackend *backend, const gchar *filter, const gchar *search)
 {
 	g_return_if_fail (backend != NULL);
-	if (pk_backend_thread_create(backend, backend_search_name_thread, NULL) == FALSE) {
-		pk_backend_error_code(backend, PK_ERROR_ENUM_CREATE_THREAD_FAILED, "Failed to create search-name thread");
-		pk_backend_finished(backend, PK_EXIT_ENUM_FAILED);
+	if (pk_backend_thread_create (backend, backend_search_name_thread, NULL) == FALSE) {
+		pk_backend_error_code (backend, PK_ERROR_ENUM_CREATE_THREAD_FAILED, "Failed to create search-name thread");
+		pk_backend_finished (backend, PK_EXIT_ENUM_FAILED);
 	}
+	pk_backend_finished (backend, PK_EXIT_ENUM_SUCCESS);
 }
 
 PK_BACKEND_OPTIONS (
@@ -83,7 +110,7 @@ PK_BACKEND_OPTIONS (
 	NULL,					/* remove_package */
 	NULL,					/* search_details */
 	NULL,					/* search_file */
-	NULL,					/* search_group */
+	backend_search_group,			/* search_group */
 	backend_search_name,			/* search_name */
 	NULL,					/* update_package */
 	NULL					/* update_system */
diff --git a/src/pk-thread-list.c b/src/pk-thread-list.c
index 8cf0a07..3b76576 100644
--- a/src/pk-thread-list.c
+++ b/src/pk-thread-list.c
@@ -71,7 +71,7 @@ pk_thread_list_item_new (gpointer data)
 	gboolean ret;
 	pk_debug ("running %p", item->func);
 	ret = item->func (item->param, item->data);
-	pk_debug ("ret is %i", ret);
+	pk_debug ("finished %p, ret is %i", item->func, ret);
 	item->running = FALSE;
 	return NULL;
 }
diff-tree dcc6ee612c8be95ea467edd70fb3cce449b2ead6 (from 59ca7965d09d0147ff6cd9f6f75c3f1c5e536433)
Author: Richard Hughes <richard at hughsie.com>
Date:   Mon Sep 17 11:44:23 2007 +0100

    don't unref not implimented funtion twice. fixes a segfault discovered with the test_spawn backend.

diff --git a/src/pk-backend.c b/src/pk-backend.c
index 409b8b8..4e27b36 100644
--- a/src/pk-backend.c
+++ b/src/pk-backend.c
@@ -480,6 +480,9 @@ pk_backend_spawn_helper (PkBackend *back
 	return ret;
 }
 
+/* ick, we need to call this directly... */
+static gboolean
+pk_backend_finished_delay (gpointer data);
 /**
  * pk_backend_not_implemented_yet:
  **/
@@ -487,7 +490,9 @@ gboolean
 pk_backend_not_implemented_yet (PkBackend *backend, const gchar *method)
 {
 	pk_backend_error_code (backend, PK_ERROR_ENUM_NOT_SUPPORTED, "the method '%s' is not implemented yet", method);
-	pk_backend_finished (backend, PK_EXIT_ENUM_FAILED);
+	/* don't wait, do this now */
+	backend->priv->exit = PK_EXIT_ENUM_FAILED;
+	pk_backend_finished_delay (backend);
 	return TRUE;
 }
 
@@ -731,10 +736,12 @@ pk_backend_get_job_role (PkBackend *back
 }
 
 /**
- * pk_backend_finished_idle:
+ * pk_backend_finished_delay:
+ *
+ * We can call into this function if we *know* it's safe. 
  **/
 static gboolean
-pk_backend_finished_idle (gpointer data)
+pk_backend_finished_delay (gpointer data)
 {
 	PkBackend *backend = PK_BACKEND (data);
 	pk_debug ("emit finished %i", backend->priv->exit);
@@ -758,7 +765,7 @@ pk_backend_finished (PkBackend *backend,
 	 * has been sent to the client. I love async... */
 	pk_debug ("adding finished %p to timeout loop", backend);
 	backend->priv->exit = exit;
-	g_timeout_add (500, pk_backend_finished_idle, backend);
+	g_timeout_add (500, pk_backend_finished_delay, backend);
 	return TRUE;
 }
 
@@ -1185,7 +1192,7 @@ pk_backend_finalize (GObject *object)
 		}		
 	}
 
-	pk_debug ("freeing %s", backend->priv->name);
+	pk_debug ("freeing %s (%p)", backend->priv->name, backend);
 	g_free (backend->priv->name);
 	pk_backend_unload (backend);
 	g_timer_destroy (backend->priv->timer);
diff --git a/src/pk-engine.c b/src/pk-engine.c
index 599de2f..1109c9a 100644
--- a/src/pk-engine.c
+++ b/src/pk-engine.c
@@ -519,8 +519,11 @@ pk_engine_delete_task (PkEngine *engine,
 	g_return_val_if_fail (engine != NULL, FALSE);
 	g_return_val_if_fail (PK_IS_ENGINE (engine), FALSE);
 
+	pk_debug ("removing task %p as it failed", task);
 	pk_job_list_remove (engine->priv->job_list, task);
-	g_object_unref (task);
+
+	/* we don't do g_object_unref (task) here as it is done in the
+	   ::finished handler */
 	return TRUE;
 }
 
diff-tree 59ca7965d09d0147ff6cd9f6f75c3f1c5e536433 (from bfcf412471056b4a1413663b0bf5359f124bd80b)
Author: Richard Hughes <richard at hughsie.com>
Date:   Mon Sep 17 11:12:15 2007 +0100

    disconnect from the spawn helper correctly if the backend is unloaded half through an operation. prevents a segfault when cancelling a job

diff --git a/src/pk-backend.c b/src/pk-backend.c
index eaf5153..409b8b8 100644
--- a/src/pk-backend.c
+++ b/src/pk-backend.c
@@ -68,6 +68,9 @@ struct _PkBackendPrivate
 	guint			 last_subpercentage;
 	gchar			*last_package;
 	PkThreadList		*thread_list;
+	gulong			 signal_finished;
+	gulong			 signal_stdout;
+	gulong			 signal_stderr;
 };
 
 enum {
@@ -332,14 +335,32 @@ out:
 }
 
 /**
+ * pk_backend_spawn_helper_new:
+ **/
+static gboolean
+pk_backend_spawn_helper_delete (PkBackend *backend)
+{
+	if (backend->priv->spawn == NULL) {
+		pk_error ("spawn object not in use");
+	}
+	pk_debug ("deleting spawn %p", backend->priv->spawn);
+	g_signal_handler_disconnect (backend->priv->spawn, backend->priv->signal_finished);
+	g_signal_handler_disconnect (backend->priv->spawn, backend->priv->signal_stdout);
+	g_signal_handler_disconnect (backend->priv->spawn, backend->priv->signal_stderr);
+	g_object_unref (backend->priv->spawn);
+	backend->priv->spawn = NULL;
+	return TRUE;
+}
+
+/**
  * pk_backend_spawn_finished_cb:
  **/
 static void
 pk_backend_spawn_finished_cb (PkSpawn *spawn, gint exitcode, PkBackend *backend)
 {
 	PkExitEnum exit;
-	pk_debug ("unref'ing spawn %p, exit code %i", spawn, exitcode);
-	g_object_unref (spawn);
+	pk_debug ("deleting spawn %p, exit code %i", spawn, exitcode);
+	pk_backend_spawn_helper_delete (backend);
 
 	/* only emit success with a zero exit code */
 	if (exitcode == 0) {
@@ -371,6 +392,29 @@ pk_backend_spawn_stderr_cb (PkSpawn *spa
 }
 
 /**
+ * pk_backend_spawn_helper_new:
+ **/
+static gboolean
+pk_backend_spawn_helper_new (PkBackend *backend)
+{
+	if (backend->priv->spawn != NULL) {
+		pk_error ("spawn object already in use");
+	}
+	backend->priv->spawn = pk_spawn_new ();
+	pk_debug ("allocating spawn %p", backend->priv->spawn);
+	backend->priv->signal_finished =
+		g_signal_connect (backend->priv->spawn, "finished",
+				  G_CALLBACK (pk_backend_spawn_finished_cb), backend);
+	backend->priv->signal_stdout =
+		g_signal_connect (backend->priv->spawn, "stdout",
+				  G_CALLBACK (pk_backend_spawn_stdout_cb), backend);
+	backend->priv->signal_stderr =
+		g_signal_connect (backend->priv->spawn, "stderr",
+				  G_CALLBACK (pk_backend_spawn_stderr_cb), backend);
+	return TRUE;
+}
+
+/**
  * pk_backend_spawn_helper_internal:
  **/
 static gboolean
@@ -390,16 +434,10 @@ pk_backend_spawn_helper_internal (PkBack
 		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);
+	pk_backend_spawn_helper_new (backend);
 	ret = pk_spawn_command (backend->priv->spawn, command);
 	if (ret == FALSE) {
-		g_object_unref (backend->priv->spawn);
+		pk_backend_spawn_helper_delete (backend);
 		pk_backend_error_code (backend, PK_ERROR_ENUM_INTERNAL_ERROR, "Spawn of helper '%s' failed", command);
 		pk_backend_finished (backend, PK_EXIT_ENUM_FAILED);
 	}
@@ -720,7 +758,7 @@ pk_backend_finished (PkBackend *backend,
 	 * has been sent to the client. I love async... */
 	pk_debug ("adding finished %p to timeout loop", backend);
 	backend->priv->exit = exit;
-	g_timeout_add (10500, pk_backend_finished_idle, backend);
+	g_timeout_add (500, pk_backend_finished_idle, backend);
 	return TRUE;
 }
 
@@ -1152,6 +1190,9 @@ pk_backend_finalize (GObject *object)
 	pk_backend_unload (backend);
 	g_timer_destroy (backend->priv->timer);
 	g_free (backend->priv->last_package);
+	if (backend->priv->spawn != NULL) {
+		pk_backend_spawn_helper_delete (backend);
+	}
 	g_object_unref (backend->priv->network);
 	g_object_unref (backend->priv->thread_list);
 
diff-tree bfcf412471056b4a1413663b0bf5359f124bd80b (from cc39940b616eccf2e9f3fe6cd20364dbecbb5015)
Author: Richard Hughes <richard at hughsie.com>
Date:   Mon Sep 17 10:54:41 2007 +0100

    make sure we remove the task from the task list if it fails, else we never timeout and exit the daemon

diff --git a/src/pk-engine.c b/src/pk-engine.c
index 26cad77..599de2f 100644
--- a/src/pk-engine.c
+++ b/src/pk-engine.c
@@ -438,6 +438,9 @@ pk_engine_new_task (PkEngine *engine)
 	PkTask *task;
 	gboolean ret;
 
+	g_return_val_if_fail (engine != NULL, NULL);
+	g_return_val_if_fail (PK_IS_ENGINE (engine), NULL);
+
 	/* allocate a new task */
 	task = pk_backend_new ();
 	ret = pk_backend_load (task, engine->priv->backend);
@@ -486,6 +489,9 @@ pk_engine_new_task (PkEngine *engine)
 static gboolean
 pk_engine_add_task (PkEngine *engine, PkTask *task)
 {
+	g_return_val_if_fail (engine != NULL, FALSE);
+	g_return_val_if_fail (PK_IS_ENGINE (engine), FALSE);
+
 	/* commit, so it appears in the JobList */
 	pk_job_list_commit (engine->priv->job_list, task);
 
@@ -502,6 +508,23 @@ pk_engine_add_task (PkEngine *engine, Pk
 }
 
 /**
+ * pk_engine_delete_task:
+ *
+ * Use this function when a function failed, and we just want to get rid
+ * of all references to it.
+ **/
+gboolean
+pk_engine_delete_task (PkEngine *engine, PkTask *task)
+{
+	g_return_val_if_fail (engine != NULL, FALSE);
+	g_return_val_if_fail (PK_IS_ENGINE (engine), FALSE);
+
+	pk_job_list_remove (engine->priv->job_list, task);
+	g_object_unref (task);
+	return TRUE;
+}
+
+/**
  * pk_engine_can_do_action:
  **/
 static PolKitResult
@@ -579,7 +602,7 @@ pk_engine_refresh_cache (PkEngine *engin
 	if (ret == FALSE) {
 		g_set_error (error, PK_ENGINE_ERROR, PK_ENGINE_ERROR_NOT_SUPPORTED,
 			     "Operation not yet supported by backend");
-		g_object_unref (task);
+		pk_engine_delete_task (engine, task);
 		return FALSE;
 	}
 	pk_engine_add_task (engine, task);
@@ -612,7 +635,7 @@ pk_engine_get_updates (PkEngine *engine,
 	if (ret == FALSE) {
 		g_set_error (error, PK_ENGINE_ERROR, PK_ENGINE_ERROR_NOT_SUPPORTED,
 			     "Operation not yet supported by backend");
-		g_object_unref (task);
+		pk_engine_delete_task (engine, task);
 		return FALSE;
 	}
 	pk_engine_add_task (engine, task);
@@ -710,7 +733,7 @@ pk_engine_search_name (PkEngine *engine,
 	if (ret == FALSE) {
 		g_set_error (error, PK_ENGINE_ERROR, PK_ENGINE_ERROR_NOT_SUPPORTED,
 			     "Operation not yet supported by backend");
-		g_object_unref (task);
+		pk_engine_delete_task (engine, task);
 		return FALSE;
 	}
 	pk_engine_add_task (engine, task);
@@ -756,7 +779,7 @@ pk_engine_search_details (PkEngine *engi
 	if (ret == FALSE) {
 		g_set_error (error, PK_ENGINE_ERROR, PK_ENGINE_ERROR_NOT_SUPPORTED,
 			     "Operation not yet supported by backend");
-		g_object_unref (task);
+		pk_engine_delete_task (engine, task);
 		return FALSE;
 	}
 	pk_engine_add_task (engine, task);
@@ -802,7 +825,7 @@ pk_engine_search_group (PkEngine *engine
 	if (ret == FALSE) {
 		g_set_error (error, PK_ENGINE_ERROR, PK_ENGINE_ERROR_NOT_SUPPORTED,
 			     "Operation not yet supported by backend");
-		g_object_unref (task);
+		pk_engine_delete_task (engine, task);
 		return FALSE;
 	}
 	pk_engine_add_task (engine, task);
@@ -848,7 +871,7 @@ pk_engine_search_file (PkEngine *engine,
 	if (ret == FALSE) {
 		g_set_error (error, PK_ENGINE_ERROR, PK_ENGINE_ERROR_NOT_SUPPORTED,
 			     "Operation not yet supported by backend");
-		g_object_unref (task);
+		pk_engine_delete_task (engine, task);
 		return FALSE;
 	}
 	pk_engine_add_task (engine, task);
@@ -890,7 +913,7 @@ pk_engine_get_depends (PkEngine *engine,
 	if (ret == FALSE) {
 		g_set_error (error, PK_ENGINE_ERROR, PK_ENGINE_ERROR_NOT_SUPPORTED,
 			     "Operation not yet supported by backend");
-		g_object_unref (task);
+		pk_engine_delete_task (engine, task);
 		return FALSE;
 	}
 	pk_engine_add_task (engine, task);
@@ -932,7 +955,7 @@ pk_engine_get_requires (PkEngine *engine
 	if (ret == FALSE) {
 		g_set_error (error, PK_ENGINE_ERROR, PK_ENGINE_ERROR_NOT_SUPPORTED,
 			     "Operation not yet supported by backend");
-		g_object_unref (task);
+		pk_engine_delete_task (engine, task);
 		return FALSE;
 	}
 	pk_engine_add_task (engine, task);
@@ -974,7 +997,7 @@ pk_engine_get_update_detail (PkEngine *e
 	if (ret == FALSE) {
 		g_set_error (error, PK_ENGINE_ERROR, PK_ENGINE_ERROR_NOT_SUPPORTED,
 			     "Operation not yet supported by backend");
-		g_object_unref (task);
+		pk_engine_delete_task (engine, task);
 		return FALSE;
 	}
 	pk_engine_add_task (engine, task);
@@ -1008,7 +1031,7 @@ pk_engine_get_description (PkEngine *eng
 	if (ret == FALSE) {
 		g_set_error (error, PK_ENGINE_ERROR, PK_ENGINE_ERROR_NOT_SUPPORTED,
 			     "Operation not yet supported by backend");
-		g_object_unref (task);
+		pk_engine_delete_task (engine, task);
 		return FALSE;
 	}
 	pk_engine_add_task (engine, task);
@@ -1058,7 +1081,7 @@ pk_engine_update_system (PkEngine *engin
 	if (ret == FALSE) {
 		error = g_error_new (PK_ENGINE_ERROR, PK_ENGINE_ERROR_NOT_SUPPORTED,
 				     "Operation not yet supported by backend");
-		g_object_unref (task);
+		pk_engine_delete_task (engine, task);
 		dbus_g_method_return_error (context, error);
 		return;
 	}
@@ -1109,7 +1132,7 @@ pk_engine_remove_package (PkEngine *engi
 	if (ret == FALSE) {
 		error = g_error_new (PK_ENGINE_ERROR, PK_ENGINE_ERROR_NOT_SUPPORTED,
 				     "Operation not yet supported by backend");
-		g_object_unref (task);
+		pk_engine_delete_task (engine, task);
 		dbus_g_method_return_error (context, error);
 		return;
 	}
@@ -1162,7 +1185,7 @@ pk_engine_install_package (PkEngine *eng
 	if (ret == FALSE) {
 		error = g_error_new (PK_ENGINE_ERROR, PK_ENGINE_ERROR_NOT_SUPPORTED,
 				     "Operation not yet supported by backend");
-		g_object_unref (task);
+		pk_engine_delete_task (engine, task);
 		dbus_g_method_return_error (context, error);
 		return;
 	}
@@ -1215,7 +1238,7 @@ pk_engine_update_package (PkEngine *engi
 	if (ret == FALSE) {
 		error = g_error_new (PK_ENGINE_ERROR, PK_ENGINE_ERROR_NOT_SUPPORTED,
 				     "Operation not yet supported by backend");
-		g_object_unref (task);
+		pk_engine_delete_task (engine, task);
 		dbus_g_method_return_error (context, error);
 		return;
 	}
diff-tree cc39940b616eccf2e9f3fe6cd20364dbecbb5015 (from f1304b9b66ca33896348791af772881a57fac90c)
Author: Richard Hughes <richard at hughsie.com>
Date:   Mon Sep 17 10:44:46 2007 +0100

    install the helpers in backend specific directories so we don't overwrite them if we have multiply installed targets

diff --git a/backends/box/helpers/Makefile.am b/backends/box/helpers/Makefile.am
index 1851df4..f559413 100644
--- a/backends/box/helpers/Makefile.am
+++ b/backends/box/helpers/Makefile.am
@@ -1,5 +1,5 @@
 
-helperdir = $(datadir)/PackageKit/helpers
+helperdir = $(datadir)/PackageKit/helpers/box
 
 NULL =
 
diff --git a/backends/conary/helpers/Makefile.am b/backends/conary/helpers/Makefile.am
index afd3f65..c3c2ca6 100644
--- a/backends/conary/helpers/Makefile.am
+++ b/backends/conary/helpers/Makefile.am
@@ -1,5 +1,5 @@
 
-helperdir = $(datadir)/PackageKit/helpers
+helperdir = $(datadir)/PackageKit/helpers/conary
 
 NULL =
 
diff --git a/backends/test/helpers/Makefile.am b/backends/test/helpers/Makefile.am
index 2c6b420..30009c6 100644
--- a/backends/test/helpers/Makefile.am
+++ b/backends/test/helpers/Makefile.am
@@ -1,5 +1,5 @@
 
-helperdir = $(datadir)/PackageKit/helpers
+helperdir = $(datadir)/PackageKit/helpers/test_spawn
 
 NULL =
 
diff --git a/backends/test/pk-backend-test-spawn.c b/backends/test/pk-backend-test-spawn.c
index c41da48..3d852d1 100644
--- a/backends/test/pk-backend-test-spawn.c
+++ b/backends/test/pk-backend-test-spawn.c
@@ -33,7 +33,7 @@ backend_search_name (PkBackend *backend,
 	g_return_if_fail (backend != NULL);
 	pk_backend_allow_interrupt (backend, TRUE);
 	pk_backend_no_percentage_updates (backend);
-	pk_backend_spawn_helper (backend, "search-name.py", filter, search, NULL);
+	pk_backend_spawn_helper (backend, "search-name.sh", filter, search, NULL);
 }
 
 PK_BACKEND_OPTIONS (
diff --git a/backends/yum/helpers/Makefile.am b/backends/yum/helpers/Makefile.am
index 84d1185..396bc8b 100644
--- a/backends/yum/helpers/Makefile.am
+++ b/backends/yum/helpers/Makefile.am
@@ -1,5 +1,5 @@
 
-helperdir = $(datadir)/PackageKit/helpers
+helperdir = $(datadir)/PackageKit/helpers/yum
 
 NULL =
 
diff-tree f1304b9b66ca33896348791af772881a57fac90c (from ad98ce93e5cf13a20b1c769a3fda9c0597322888)
Author: Richard Hughes <richard at hughsie.com>
Date:   Mon Sep 17 10:43:59 2007 +0100

    use the correct signal prefix. cosmetic.

diff --git a/src/pk-backend.c b/src/pk-backend.c
index cc6b3fa..eaf5153 100644
--- a/src/pk-backend.c
+++ b/src/pk-backend.c
@@ -71,21 +71,21 @@ struct _PkBackendPrivate
 };
 
 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_UPDATE_DETAIL,
-	PK_TASK_ERROR_CODE,
-	PK_TASK_REQUIRE_RESTART,
-	PK_TASK_FINISHED,
-	PK_TASK_ALLOW_INTERRUPT,
-	PK_TASK_LAST_SIGNAL
+	PK_BACKEND_JOB_STATUS_CHANGED,
+	PK_BACKEND_PERCENTAGE_CHANGED,
+	PK_BACKEND_SUB_PERCENTAGE_CHANGED,
+	PK_BACKEND_NO_PERCENTAGE_UPDATES,
+	PK_BACKEND_DESCRIPTION,
+	PK_BACKEND_PACKAGE,
+	PK_BACKEND_UPDATE_DETAIL,
+	PK_BACKEND_ERROR_CODE,
+	PK_BACKEND_REQUIRE_RESTART,
+	PK_BACKEND_FINISHED,
+	PK_BACKEND_ALLOW_INTERRUPT,
+	PK_BACKEND_LAST_SIGNAL
 };
 
-static guint signals [PK_TASK_LAST_SIGNAL] = { 0, };
+static guint signals [PK_BACKEND_LAST_SIGNAL] = { 0, };
 
 G_DEFINE_TYPE (PkBackend, pk_backend, G_TYPE_OBJECT)
 
@@ -381,7 +381,8 @@ pk_backend_spawn_helper_internal (PkBack
 	gchar *command;
 
 	/* build script */
-	filename = g_build_filename (DATADIR, "PackageKit", "helpers", script, NULL);
+	filename = g_build_filename (DATADIR, "PackageKit", "helpers", backend->priv->name, script, NULL);
+	pk_debug ("using spawn filename %s", filename);
 
 	if (argument != NULL) {
 		command = g_strdup_printf ("%s %s", filename, argument);
@@ -465,7 +466,7 @@ pk_backend_change_percentage (PkBackend 
 	backend->priv->last_subpercentage = percentage;
 
 	pk_debug ("emit percentage-changed %i", percentage);
-	g_signal_emit (backend, signals [PK_TASK_PERCENTAGE_CHANGED], 0, percentage);
+	g_signal_emit (backend, signals [PK_BACKEND_PERCENTAGE_CHANGED], 0, percentage);
 	return TRUE;
 }
 
@@ -482,7 +483,7 @@ pk_backend_change_sub_percentage (PkBack
 	backend->priv->last_subpercentage = percentage;
 
 	pk_debug ("emit sub-percentage-changed %i", percentage);
-	g_signal_emit (backend, signals [PK_TASK_SUB_PERCENTAGE_CHANGED], 0, percentage);
+	g_signal_emit (backend, signals [PK_BACKEND_SUB_PERCENTAGE_CHANGED], 0, percentage);
 	return TRUE;
 }
 
@@ -517,7 +518,7 @@ pk_backend_change_job_status (PkBackend 
 	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);
+	g_signal_emit (backend, signals [PK_BACKEND_JOB_STATUS_CHANGED], 0, status);
 	return TRUE;
 }
 
@@ -535,7 +536,7 @@ pk_backend_package (PkBackend *backend, 
 	backend->priv->last_package = g_strdup (package);
 
 	pk_debug ("emit package %i, %s, %s", value, package, summary);
-	g_signal_emit (backend, signals [PK_TASK_PACKAGE], 0, value, package, summary);
+	g_signal_emit (backend, signals [PK_BACKEND_PACKAGE], 0, value, package, summary);
 
 	return TRUE;
 }
@@ -554,7 +555,7 @@ pk_backend_update_detail (PkBackend *bac
 
 	pk_debug ("emit update-detail %s, %s, %s, %s, %s, %s",
 		  package_id, updates, obsoletes, url, restart, update_text);
-	g_signal_emit (backend, signals [PK_TASK_UPDATE_DETAIL], 0,
+	g_signal_emit (backend, signals [PK_BACKEND_UPDATE_DETAIL], 0,
 		       package_id, updates, obsoletes, url, restart, update_text);
 	return TRUE;
 }
@@ -606,7 +607,7 @@ pk_backend_require_restart (PkBackend *b
 	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);
+	g_signal_emit (backend, signals [PK_BACKEND_REQUIRE_RESTART], 0, restart, details);
 
 	return TRUE;
 }
@@ -623,7 +624,7 @@ pk_backend_description (PkBackend *backe
 	g_return_val_if_fail (PK_IS_BACKEND (backend), FALSE);
 
 	pk_debug ("emit description %s, %s, %i, %s, %s", package_id, licence, group, description, url);
-	g_signal_emit (backend, signals [PK_TASK_DESCRIPTION], 0, package_id, licence, group, description, url);
+	g_signal_emit (backend, signals [PK_BACKEND_DESCRIPTION], 0, package_id, licence, group, description, url);
 
 	return TRUE;
 }
@@ -645,7 +646,7 @@ pk_backend_error_code (PkBackend *backen
 	va_end (args);
 
 	pk_debug ("emit error-code %i, %s", code, buffer);
-	g_signal_emit (backend, signals [PK_TASK_ERROR_CODE], 0, code, buffer);
+	g_signal_emit (backend, signals [PK_BACKEND_ERROR_CODE], 0, code, buffer);
 
 	return TRUE;
 }
@@ -697,9 +698,9 @@ pk_backend_get_job_role (PkBackend *back
 static gboolean
 pk_backend_finished_idle (gpointer data)
 {
-	PkBackend *backend = (PkBackend *) data;
+	PkBackend *backend = PK_BACKEND (data);
 	pk_debug ("emit finished %i", backend->priv->exit);
-	g_signal_emit (backend, signals [PK_TASK_FINISHED], 0, backend->priv->exit);
+	g_signal_emit (backend, signals [PK_BACKEND_FINISHED], 0, backend->priv->exit);
 	return FALSE;
 }
 
@@ -717,9 +718,9 @@ pk_backend_finished (PkBackend *backend,
 
 	/* 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);
+	pk_debug ("adding finished %p to timeout loop", backend);
 	backend->priv->exit = exit;
-	g_timeout_add (500, pk_backend_finished_idle, backend);
+	g_timeout_add (10500, pk_backend_finished_idle, backend);
 	return TRUE;
 }
 
@@ -733,7 +734,7 @@ pk_backend_no_percentage_updates (PkBack
 	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);
+	g_signal_emit (backend, signals [PK_BACKEND_NO_PERCENTAGE_UPDATES], 0);
 	return TRUE;
 }
 
@@ -748,7 +749,7 @@ pk_backend_allow_interrupt (PkBackend *b
 
 	pk_debug ("emit allow-interrupt %i", allow_restart);
 	backend->priv->is_killable = allow_restart;
-	g_signal_emit (backend, signals [PK_TASK_ALLOW_INTERRUPT], 0);
+	g_signal_emit (backend, signals [PK_BACKEND_ALLOW_INTERRUPT], 0);
 	return TRUE;
 }
 
@@ -1167,58 +1168,58 @@ pk_backend_class_init (PkBackendClass *k
 
 	object_class->finalize = pk_backend_finalize;
 
-	signals [PK_TASK_JOB_STATUS_CHANGED] =
+	signals [PK_BACKEND_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] =
+	signals [PK_BACKEND_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] =
+	signals [PK_BACKEND_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] =
+	signals [PK_BACKEND_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_UPDATE_DETAIL] =
+	signals [PK_BACKEND_UPDATE_DETAIL] =
 		g_signal_new ("update-detail",
 			      G_TYPE_FROM_CLASS (object_class), G_SIGNAL_RUN_LAST,
 			      0, NULL, NULL, pk_marshal_VOID__STRING_STRING_STRING_STRING_STRING_STRING,
 			      G_TYPE_NONE, 6, G_TYPE_STRING, G_TYPE_STRING,
 			      G_TYPE_STRING, G_TYPE_STRING, G_TYPE_STRING, G_TYPE_STRING);
-	signals [PK_TASK_REQUIRE_RESTART] =
+	signals [PK_BACKEND_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] =
+	signals [PK_BACKEND_DESCRIPTION] =
 		g_signal_new ("description",
 			      G_TYPE_FROM_CLASS (object_class), G_SIGNAL_RUN_LAST,
 			      0, NULL, NULL, pk_marshal_VOID__STRING_STRING_UINT_STRING_STRING,
 			      G_TYPE_NONE, 5, G_TYPE_STRING, G_TYPE_STRING, G_TYPE_UINT, G_TYPE_STRING, G_TYPE_STRING);
-	signals [PK_TASK_ERROR_CODE] =
+	signals [PK_BACKEND_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] =
+	signals [PK_BACKEND_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] =
+	signals [PK_BACKEND_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] =
+	signals [PK_BACKEND_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,
diff-tree ad98ce93e5cf13a20b1c769a3fda9c0597322888 (from b6dd29da05c0acf7c99cf9273fe7495a30df5c83)
Author: root <root at hughsie-laptop.(none)>
Date:   Mon Sep 17 10:26:55 2007 +0100

    pass in the tdb reference to avoid a critical warning

diff --git a/src/pk-transaction-db.c b/src/pk-transaction-db.c
index d4393bc..30eb88c 100644
--- a/src/pk-transaction-db.c
+++ b/src/pk-transaction-db.c
@@ -135,7 +135,7 @@ pk_transaction_db_sql_statement (PkTrans
 	g_return_val_if_fail (PK_IS_TRANSACTION_DB (tdb), FALSE);
 
 	pk_debug ("statement=%s", sql);
-	rc = sqlite3_exec (tdb->priv->db, sql, pk_transaction_sqlite_callback, 0, &error_msg);
+	rc = sqlite3_exec (tdb->priv->db, sql, pk_transaction_sqlite_callback, tdb, &error_msg);
 	if (rc != SQLITE_OK) {
 		pk_warning ("SQL error: %s\n", error_msg);
 		sqlite3_free (error_msg);
diff-tree b6dd29da05c0acf7c99cf9273fe7495a30df5c83 (from e889202b978a84ffdaa220808cba91580fe49c78)
Author: Richard Hughes <richard at hughsie.com>
Date:   Mon Sep 17 10:13:07 2007 +0100

    add a test spawn helper

diff --git a/backends/test/Makefile.am b/backends/test/Makefile.am
index 9b8a328..290ee89 100644
--- a/backends/test/Makefile.am
+++ b/backends/test/Makefile.am
@@ -1,3 +1,4 @@
+SUBDIRS = helpers
 plugindir = @PK_PLUGIN_DIR@
 plugin_LTLIBRARIES =			\
 	libpk_backend_test_nop.la	\
diff --git a/backends/test/helpers/Makefile.am b/backends/test/helpers/Makefile.am
new file mode 100644
index 0000000..2c6b420
--- /dev/null
+++ b/backends/test/helpers/Makefile.am
@@ -0,0 +1,15 @@
+
+helperdir = $(datadir)/PackageKit/helpers
+
+NULL =
+
+dist_helper_DATA = 			\
+	search-name.sh			\
+	$(NULL)
+
+install-data-hook:
+	chmod a+rx $(DESTDIR)$(helperdir)/*.sh
+
+clean-local :
+	rm -f *~
+
diff --git a/backends/test/helpers/search-name.sh b/backends/test/helpers/search-name.sh
new file mode 100644
index 0000000..5a48bfe
--- /dev/null
+++ b/backends/test/helpers/search-name.sh
@@ -0,0 +1,19 @@
+#!/bin/sh
+#
+# 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.
+
+echo "no-percentage-updates" > /dev/stderr
+echo "status	query" > /dev/stderr
+sleep 1
+echo "package	1	glib2;2.14.0;i386;fedora	The GLib library"
+sleep 1
+echo "package	1	gtk2;gtk2-2.11.6-6.fc8;i386;fedora	GTK+ Libraries for GIMP"
+exit 0
+
diff --git a/configure.ac b/configure.ac
index fe2bc5f..65ac324 100644
--- a/configure.ac
+++ b/configure.ac
@@ -369,6 +369,7 @@ backends/conary/Makefile
 backends/conary/helpers/Makefile
 backends/dummy/Makefile
 backends/test/Makefile
+backends/test/helpers/Makefile
 backends/yum/Makefile
 backends/yum/helpers/Makefile
 data/Makefile
diff-tree e889202b978a84ffdaa220808cba91580fe49c78 (from cb06fdeaf483b341e52b94a6f69eb0e5ed7b0505)
Author: Richard Hughes <richard at hughsie.com>
Date:   Mon Sep 17 10:04:20 2007 +0100

    make the spawn and thread test backends useful for testing

diff --git a/backends/test/pk-backend-test-spawn.c b/backends/test/pk-backend-test-spawn.c
index a4c03ce..c41da48 100644
--- a/backends/test/pk-backend-test-spawn.c
+++ b/backends/test/pk-backend-test-spawn.c
@@ -25,223 +25,39 @@
 #include <pk-backend.h>
 
 /**
- * backend_initalize:
- */
-static void
-backend_initalize (PkBackend *backend)
-{
-	g_return_if_fail (backend != NULL);
-}
-
-/**
- * backend_destroy:
- */
-static void
-backend_destroy (PkBackend *backend)
-{
-	g_return_if_fail (backend != NULL);
-}
-
-/**
- * backend_get_groups:
- */
-static void
-backend_get_groups (PkBackend *backend, PkEnumList *elist)
-{
-	g_return_if_fail (backend != NULL);
-	pk_enum_list_append_multiple (elist,
-				      PK_GROUP_ENUM_ACCESSIBILITY,
-				      PK_GROUP_ENUM_GAMES,
-				      PK_GROUP_ENUM_SYSTEM,
-				      -1);
-}
-
-/**
- * backend_get_filters:
- */
-static void
-backend_get_filters (PkBackend *backend, PkEnumList *elist)
-{
-	g_return_if_fail (backend != NULL);
-	pk_enum_list_append_multiple (elist,
-				      PK_FILTER_ENUM_GUI,
-				      PK_FILTER_ENUM_INSTALLED,
-				      PK_FILTER_ENUM_DEVELOPMENT,
-				      -1);
-}
-
-/**
- * backend_cancel_job_try:
- */
-static void
-backend_cancel_job_try (PkBackend *backend)
-{
-	g_return_if_fail (backend != NULL);
-	pk_backend_finished (backend, PK_EXIT_ENUM_FAILED);
-}
-
-/**
- * backend_get_depends:
- */
-static void
-backend_get_depends (PkBackend *backend, const gchar *package_id)
-{
-	g_return_if_fail (backend != NULL);
-	pk_backend_finished (backend, PK_EXIT_ENUM_FAILED);
-}
-
-/**
- * backend_get_description:
- */
-static void
-backend_get_description (PkBackend *backend, const gchar *package_id)
-{
-	g_return_if_fail (backend != NULL);
-	pk_backend_finished (backend, PK_EXIT_ENUM_FAILED);
-}
-
-/**
- * backend_get_requires:
- */
-static void
-backend_get_requires (PkBackend *backend, const gchar *package_id)
-{
-	g_return_if_fail (backend != NULL);
-	pk_backend_finished (backend, PK_EXIT_ENUM_FAILED);
-}
-
-/**
- * backend_get_update_detail:
- */
-static void
-backend_get_update_detail (PkBackend *backend, const gchar *package_id)
-{
-	g_return_if_fail (backend != NULL);
-	pk_backend_finished (backend, PK_EXIT_ENUM_FAILED);
-}
-
-/**
- * backend_get_updates:
- */
-static void
-backend_get_updates (PkBackend *backend)
-{
-	g_return_if_fail (backend != NULL);
-	pk_backend_finished (backend, PK_EXIT_ENUM_FAILED);
-}
-
-/**
- * backend_install_package:
- */
-static void
-backend_install_package (PkBackend *backend, const gchar *package_id)
-{
-	g_return_if_fail (backend != NULL);
-	pk_backend_finished (backend, PK_EXIT_ENUM_FAILED);
-}
-
-/**
- * backend_refresh_cache:
- */
-static void
-backend_refresh_cache (PkBackend *backend, gboolean force)
-{
-	g_return_if_fail (backend != NULL);
-	pk_backend_finished (backend, PK_EXIT_ENUM_FAILED);
-}
-
-/**
- * backend_remove_package:
- */
-static void
-backend_remove_package (PkBackend *backend, const gchar *package_id, gboolean allow_deps)
-{
-	g_return_if_fail (backend != NULL);
-	pk_backend_finished (backend, PK_EXIT_ENUM_FAILED);
-}
-
-/**
- * backend_search_details:
- */
-static void
-backend_search_details (PkBackend *backend, const gchar *filter, const gchar *search)
-{
-	g_return_if_fail (backend != NULL);
-	pk_backend_finished (backend, PK_EXIT_ENUM_FAILED);
-}
-
-/**
- * backend_search_file:
- */
-static void
-backend_search_file (PkBackend *backend, const gchar *filter, const gchar *search)
-{
-	g_return_if_fail (backend != NULL);
-	pk_backend_finished (backend, PK_EXIT_ENUM_FAILED);
-}
-
-/**
- * backend_search_group:
- */
-static void
-backend_search_group (PkBackend *backend, const gchar *filter, const gchar *search)
-{
-	g_return_if_fail (backend != NULL);
-	pk_backend_finished (backend, PK_EXIT_ENUM_FAILED);
-}
-
-/**
  * backend_search_name:
  */
 static void
 backend_search_name (PkBackend *backend, const gchar *filter, const gchar *search)
 {
 	g_return_if_fail (backend != NULL);
-	pk_backend_finished (backend, PK_EXIT_ENUM_FAILED);
-}
-
-/**
- * backend_update_package:
- */
-static void
-backend_update_package (PkBackend *backend, const gchar *package_id)
-{
-	g_return_if_fail (backend != NULL);
-	pk_backend_finished (backend, PK_EXIT_ENUM_FAILED);
-}
-
-/**
- * backend_update_system:
- */
-static void
-backend_update_system (PkBackend *backend)
-{
-	g_return_if_fail (backend != NULL);
-	pk_backend_finished (backend, PK_EXIT_ENUM_FAILED);
+	pk_backend_allow_interrupt (backend, TRUE);
+	pk_backend_no_percentage_updates (backend);
+	pk_backend_spawn_helper (backend, "search-name.py", filter, search, NULL);
 }
 
 PK_BACKEND_OPTIONS (
 	"Test Spawn Backend",			/* description */
 	"0.0.1",				/* version */
 	"Richard Hughes <richard at hughsie.com>",	/* author */
-	backend_initalize,			/* initalize */
-	backend_destroy,			/* destroy */
-	backend_get_groups,			/* get_groups */
-	backend_get_filters,			/* get_filters */
-	backend_cancel_job_try,			/* cancel_job_try */
-	backend_get_depends,			/* get_depends */
-	backend_get_description,		/* get_description */
-	backend_get_requires,			/* get_requires */
-	backend_get_update_detail,		/* get_update_detail */
-	backend_get_updates,			/* get_updates */
-	backend_install_package,		/* install_package */
-	backend_refresh_cache,			/* refresh_cache */
-	backend_remove_package,			/* remove_package */
-	backend_search_details,			/* search_details */
-	backend_search_file,			/* search_file */
-	backend_search_group,			/* search_group */
+	NULL,					/* initalize */
+	NULL,					/* destroy */
+	NULL,					/* get_groups */
+	NULL,					/* get_filters */
+	NULL,					/* cancel_job_try */
+	NULL,					/* get_depends */
+	NULL,					/* get_description */
+	NULL,					/* get_requires */
+	NULL,					/* get_update_detail */
+	NULL,					/* get_updates */
+	NULL,					/* install_package */
+	NULL,					/* refresh_cache */
+	NULL,					/* remove_package */
+	NULL,					/* search_details */
+	NULL,					/* search_file */
+	NULL,					/* search_group */
 	backend_search_name,			/* search_name */
-	backend_update_package,			/* update_package */
-	backend_update_system			/* update_system */
+	NULL,					/* update_package */
+	NULL					/* update_system */
 );
 
diff --git a/backends/test/pk-backend-test-thread.c b/backends/test/pk-backend-test-thread.c
index 38ef5e7..aeb4b95 100644
--- a/backends/test/pk-backend-test-thread.c
+++ b/backends/test/pk-backend-test-thread.c
@@ -25,169 +25,30 @@
 #include <pk-backend.h>
 
 /**
- * backend_initalize:
+ * backend_search_name_thread:
  */
-static void
-backend_initalize (PkBackend *backend)
-{
-	g_return_if_fail (backend != NULL);
-}
-
-/**
- * backend_destroy:
- */
-static void
-backend_destroy (PkBackend *backend)
-{
-	g_return_if_fail (backend != NULL);
-}
-
-/**
- * backend_get_groups:
- */
-static void
-backend_get_groups (PkBackend *backend, PkEnumList *elist)
-{
-	g_return_if_fail (backend != NULL);
-	pk_enum_list_append_multiple (elist,
-				      PK_GROUP_ENUM_ACCESSIBILITY,
-				      PK_GROUP_ENUM_GAMES,
-				      PK_GROUP_ENUM_SYSTEM,
-				      -1);
-}
-
-/**
- * backend_get_filters:
- */
-static void
-backend_get_filters (PkBackend *backend, PkEnumList *elist)
-{
-	g_return_if_fail (backend != NULL);
-	pk_enum_list_append_multiple (elist,
-				      PK_FILTER_ENUM_GUI,
-				      PK_FILTER_ENUM_INSTALLED,
-				      PK_FILTER_ENUM_DEVELOPMENT,
-				      -1);
-}
-
-/**
- * backend_cancel_job_try:
- */
-static void
-backend_cancel_job_try (PkBackend *backend)
-{
-	g_return_if_fail (backend != NULL);
-	pk_backend_finished (backend, PK_EXIT_ENUM_FAILED);
-}
-
-/**
- * backend_get_depends:
- */
-static void
-backend_get_depends (PkBackend *backend, const gchar *package_id)
-{
-	g_return_if_fail (backend != NULL);
-	pk_backend_finished (backend, PK_EXIT_ENUM_FAILED);
-}
-
-/**
- * backend_get_description:
- */
-static void
-backend_get_description (PkBackend *backend, const gchar *package_id)
-{
-	g_return_if_fail (backend != NULL);
-	pk_backend_finished (backend, PK_EXIT_ENUM_FAILED);
-}
-
-/**
- * backend_get_requires:
- */
-static void
-backend_get_requires (PkBackend *backend, const gchar *package_id)
-{
-	g_return_if_fail (backend != NULL);
-	pk_backend_finished (backend, PK_EXIT_ENUM_FAILED);
-}
-
-/**
- * backend_get_update_detail:
- */
-static void
-backend_get_update_detail (PkBackend *backend, const gchar *package_id)
-{
-	g_return_if_fail (backend != NULL);
-	pk_backend_finished (backend, PK_EXIT_ENUM_FAILED);
-}
-
-/**
- * backend_get_updates:
- */
-static void
-backend_get_updates (PkBackend *backend)
-{
-	g_return_if_fail (backend != NULL);
-	pk_backend_finished (backend, PK_EXIT_ENUM_FAILED);
-}
-
-/**
- * backend_install_package:
- */
-static void
-backend_install_package (PkBackend *backend, const gchar *package_id)
-{
-	g_return_if_fail (backend != NULL);
-	pk_backend_finished (backend, PK_EXIT_ENUM_FAILED);
-}
-
-/**
- * backend_refresh_cache:
- */
-static void
-backend_refresh_cache (PkBackend *backend, gboolean force)
-{
-	g_return_if_fail (backend != NULL);
-	pk_backend_finished (backend, PK_EXIT_ENUM_FAILED);
-}
-
-/**
- * backend_remove_package:
- */
-static void
-backend_remove_package (PkBackend *backend, const gchar *package_id, gboolean allow_deps)
-{
-	g_return_if_fail (backend != NULL);
-	pk_backend_finished (backend, PK_EXIT_ENUM_FAILED);
-}
-
-/**
- * backend_search_details:
- */
-static void
-backend_search_details (PkBackend *backend, const gchar *filter, const gchar *search)
+static gboolean
+backend_search_name_thread (PkBackend *backend, gpointer data)
 {
-	g_return_if_fail (backend != NULL);
-	pk_backend_finished (backend, PK_EXIT_ENUM_FAILED);
-}
+	GTimer *timer;
+	gdouble elapsed;
 
-/**
- * backend_search_file:
- */
-static void
-backend_search_file (PkBackend *backend, const gchar *filter, const gchar *search)
-{
-	g_return_if_fail (backend != NULL);
-	pk_backend_finished (backend, PK_EXIT_ENUM_FAILED);
-}
-
-/**
- * backend_search_group:
- */
-static void
-backend_search_group (PkBackend *backend, const gchar *filter, const gchar *search)
-{
-	g_return_if_fail (backend != NULL);
-	pk_backend_finished (backend, PK_EXIT_ENUM_FAILED);
+	pk_debug ("started task (%p,%p)", backend, data);
+	timer = g_timer_new ();
+	do {
+		g_usleep (1000*100);
+		elapsed = g_timer_elapsed (timer, NULL);
+		pk_debug ("elapsed task (%p,%p) = %f", backend, data, elapsed);
+	} while (elapsed < 5.0);
+	g_timer_destroy (timer);
+	pk_debug ("exited task (%p,%p)", backend, data);
+
+	pk_backend_package (backend, 1, "glib2;2.14.0;i386;fedora",
+			 "The GLib library");
+	pk_backend_package (backend, 1, "gtk2;gtk2-2.11.6-6.fc8;i386;fedora",
+			 "GTK+ Libraries for GIMP");
+	pk_backend_finished(backend, PK_EXIT_ENUM_SUCCESS);
+	return TRUE;
 }
 
 /**
@@ -197,51 +58,34 @@ static void
 backend_search_name (PkBackend *backend, const gchar *filter, const gchar *search)
 {
 	g_return_if_fail (backend != NULL);
-	pk_backend_finished (backend, PK_EXIT_ENUM_FAILED);
-}
-
-/**
- * backend_update_package:
- */
-static void
-backend_update_package (PkBackend *backend, const gchar *package_id)
-{
-	g_return_if_fail (backend != NULL);
-	pk_backend_finished (backend, PK_EXIT_ENUM_FAILED);
-}
-
-/**
- * backend_update_system:
- */
-static void
-backend_update_system (PkBackend *backend)
-{
-	g_return_if_fail (backend != NULL);
-	pk_backend_finished (backend, PK_EXIT_ENUM_FAILED);
+	if (pk_backend_thread_create(backend, backend_search_name_thread, NULL) == FALSE) {
+		pk_backend_error_code(backend, PK_ERROR_ENUM_CREATE_THREAD_FAILED, "Failed to create search-name thread");
+		pk_backend_finished(backend, PK_EXIT_ENUM_FAILED);
+	}
 }
 
 PK_BACKEND_OPTIONS (
 	"Test Thread Backend",			/* description */
 	"0.0.1",				/* version */
 	"Richard Hughes <richard at hughsie.com>",	/* author */
-	backend_initalize,			/* initalize */
-	backend_destroy,			/* destroy */
-	backend_get_groups,			/* get_groups */
-	backend_get_filters,			/* get_filters */
-	backend_cancel_job_try,			/* cancel_job_try */
-	backend_get_depends,			/* get_depends */
-	backend_get_description,		/* get_description */
-	backend_get_requires,			/* get_requires */
-	backend_get_update_detail,		/* get_update_detail */
-	backend_get_updates,			/* get_updates */
-	backend_install_package,		/* install_package */
-	backend_refresh_cache,			/* refresh_cache */
-	backend_remove_package,			/* remove_package */
-	backend_search_details,			/* search_details */
-	backend_search_file,			/* search_file */
-	backend_search_group,			/* search_group */
+	NULL,					/* initalize */
+	NULL,					/* destroy */
+	NULL,					/* get_groups */
+	NULL,					/* get_filters */
+	NULL,					/* cancel_job_try */
+	NULL,					/* get_depends */
+	NULL,					/* get_description */
+	NULL,					/* get_requires */
+	NULL,					/* get_update_detail */
+	NULL,					/* get_updates */
+	NULL,					/* install_package */
+	NULL,					/* refresh_cache */
+	NULL,					/* remove_package */
+	NULL,					/* search_details */
+	NULL,					/* search_file */
+	NULL,					/* search_group */
 	backend_search_name,			/* search_name */
-	backend_update_package,			/* update_package */
-	backend_update_system			/* update_system */
+	NULL,					/* update_package */
+	NULL					/* update_system */
 );
 
diff --git a/src/pk-backend.h b/src/pk-backend.h
index 1f1bbc6..c600e5b 100644
--- a/src/pk-backend.h
+++ b/src/pk-backend.h
@@ -26,6 +26,7 @@
 #include <pk-enum.h>
 #include <pk-enum-list.h>
 #include <pk-package-id.h>
+#include <pk-debug.h>
 
 G_BEGIN_DECLS
 
diff --git a/src/pk-thread-list.c b/src/pk-thread-list.c
index 4869356..8cf0a07 100644
--- a/src/pk-thread-list.c
+++ b/src/pk-thread-list.c
@@ -230,7 +230,6 @@ test_func2 (PkThreadList *tlist, gpointe
 	timer = g_timer_new ();
 	do {
 		g_usleep (1000*100);
-		g_thread_yield ();
 		elapsed = g_timer_elapsed (timer, NULL);
 		pk_debug ("elapsed task (%p,%p) = %f", tlist, data, elapsed);
 	} while (elapsed < 1.0);
diff-tree cb06fdeaf483b341e52b94a6f69eb0e5ed7b0505 (from 53da49fb8fcef5248cf65ed59003213668965647)
Author: Richard Hughes <richard at hughsie.com>
Date:   Mon Sep 17 01:12:23 2007 +0100

    emit a signal for data

diff --git a/src/pk-marshal.list b/src/pk-marshal.list
index ca70f2b..14d2733 100644
--- a/src/pk-marshal.list
+++ b/src/pk-marshal.list
@@ -13,4 +13,5 @@ VOID:STRING,STRING,STRING,STRING
 VOID:STRING,STRING,STRING,STRING,STRING,STRING
 VOID:STRING,STRING,UINT,STRING,STRING
 VOID:STRING,UINT,STRING,STRING
+VOID:STRING,STRING,UINT,UINT,UINT
 
diff --git a/src/pk-transaction-db.c b/src/pk-transaction-db.c
index 1c86927..d4393bc 100644
--- a/src/pk-transaction-db.c
+++ b/src/pk-transaction-db.c
@@ -52,6 +52,13 @@ struct PkTransactionDbPrivate
 	sqlite3			*db;
 };
 
+enum {
+	PK_TRANSACTION_DB_TRANSACTION,
+	PK_TRANSACTION_DB_LAST_SIGNAL
+};
+
+static guint signals [PK_TRANSACTION_DB_LAST_SIGNAL] = { 0, };
+
 G_DEFINE_TYPE (PkTransactionDb, pk_transaction_db, G_TYPE_OBJECT)
 
 /**
@@ -99,14 +106,17 @@ pk_transaction_sqlite_callback (void *da
 			pk_warning ("%s = %s\n", col, value);
 		}
 	}
-//	g_print ("\n");
+
 	g_print ("tid          : %s\n", tid);
+	g_print (" timespec    : %s\n", timespec);
 	g_print (" succeeded   : %i\n", succeeded);
 	g_print (" role        : %s\n", pk_role_enum_to_text (role));
 	g_print (" duration    : %i (seconds)\n", duration);
-	g_print (" timespec    : %s\n", timespec);
+
 	/* emit signal */
-	//TODO
+	g_signal_emit (tdb, signals [PK_TRANSACTION_DB_TRANSACTION], 0,
+		       tid, timespec, succeeded, role, duration);
+
 	g_free (tid);
 	g_free (timespec);
 	return 0;
@@ -245,6 +255,11 @@ pk_transaction_db_class_init (PkTransact
 {
 	GObjectClass *object_class = G_OBJECT_CLASS (klass);
 	object_class->finalize = pk_transaction_db_finalize;
+	signals [PK_TRANSACTION_DB_TRANSACTION] =
+		g_signal_new ("transaction",
+			      G_TYPE_FROM_CLASS (object_class), G_SIGNAL_RUN_LAST,
+			      0, NULL, NULL, pk_marshal_VOID__STRING_STRING_UINT_UINT_UINT,
+			      G_TYPE_NONE, 0);
 	g_type_class_add_private (klass, sizeof (PkTransactionDbPrivate));
 }
 
diff-tree 53da49fb8fcef5248cf65ed59003213668965647 (from 675417a1a6f4dcb92a2d556a3268f93c2d5e2c78)
Author: Richard Hughes <richard at hughsie.com>
Date:   Mon Sep 17 01:03:24 2007 +0100

    add some more database code

diff --git a/src/pk-engine.c b/src/pk-engine.c
index d79a077..26cad77 100644
--- a/src/pk-engine.c
+++ b/src/pk-engine.c
@@ -489,6 +489,13 @@ pk_engine_add_task (PkEngine *engine, Pk
 	/* commit, so it appears in the JobList */
 	pk_job_list_commit (engine->priv->job_list, task);
 
+#if 0
+	/* add to database */
+	pk_transaction_db_add (engine->priv->transaction_db, "45;mom;data");
+	pk_transaction_db_set_role (engine->priv->transaction_db, "45;mom;data", PK_ROLE_ENUM_SYSTEM_UPDATE);
+	pk_transaction_db_set_finished (engine->priv->transaction_db, "45;mom;data", 1, 123);
+#endif
+
 	/* emit a signal */
 	pk_engine_job_list_changed (engine);
 	return TRUE;
diff --git a/src/pk-transaction-db.c b/src/pk-transaction-db.c
index 2c8f43b..1c86927 100644
--- a/src/pk-transaction-db.c
+++ b/src/pk-transaction-db.c
@@ -55,11 +55,184 @@ struct PkTransactionDbPrivate
 G_DEFINE_TYPE (PkTransactionDb, pk_transaction_db, G_TYPE_OBJECT)
 
 /**
+ * pk_transaction_sqlite_callback:
+ **/
+static gint
+pk_transaction_sqlite_callback (void *data, gint argc, gchar **argv, gchar **col_name)
+{
+	PkTransactionDb *tdb = PK_TRANSACTION_DB (data);
+	gint i;
+	gchar *col;
+	gchar *value;
+
+	g_return_val_if_fail (tdb != NULL, 0);
+	g_return_val_if_fail (PK_IS_TRANSACTION_DB (tdb), 0);
+
+	gboolean succeeded = FALSE;
+	guint duration = 0;
+	PkRoleEnum role = PK_ROLE_ENUM_UNKNOWN;
+	gchar *tid = NULL;
+	gchar *timespec = NULL;
+
+	for (i=0; i<argc; i++) {
+		col = col_name[i];
+		value = argv[i];
+		if (strcmp (col, "succeeded") == 0) {
+			succeeded = atoi (value);
+		} else if (strcmp (col, "role") == 0) {
+			if (value != NULL) {
+				role = pk_role_enum_from_text (value);
+			}
+		} else if (strcmp (col, "transaction_id") == 0) {
+			if (value != NULL) {
+				tid = g_strdup (value);
+			}
+		} else if (strcmp (col, "timespec") == 0) {
+			if (value != NULL) {
+				timespec = g_strdup (value);
+			}
+		} else if (strcmp (col, "duration") == 0) {
+			if (value != NULL) {
+				duration = atoi (value);
+			}
+		} else {
+			pk_warning ("%s = %s\n", col, value);
+		}
+	}
+//	g_print ("\n");
+	g_print ("tid          : %s\n", tid);
+	g_print (" succeeded   : %i\n", succeeded);
+	g_print (" role        : %s\n", pk_role_enum_to_text (role));
+	g_print (" duration    : %i (seconds)\n", duration);
+	g_print (" timespec    : %s\n", timespec);
+	/* emit signal */
+	//TODO
+	g_free (tid);
+	g_free (timespec);
+	return 0;
+}
+
+/**
+ * pk_transaction_db_sql_statement:
+ **/
+static gboolean
+pk_transaction_db_sql_statement (PkTransactionDb *tdb, const gchar *sql)
+{
+	gchar *error_msg = NULL;
+	gint rc;
+
+	g_return_val_if_fail (tdb != NULL, FALSE);
+	g_return_val_if_fail (PK_IS_TRANSACTION_DB (tdb), FALSE);
+
+	pk_debug ("statement=%s", sql);
+	rc = sqlite3_exec (tdb->priv->db, sql, pk_transaction_sqlite_callback, 0, &error_msg);
+	if (rc != SQLITE_OK) {
+		pk_warning ("SQL error: %s\n", error_msg);
+		sqlite3_free (error_msg);
+		return FALSE;
+	}
+	return TRUE;
+}
+
+/**
+ * pk_transaction_db_get_list:
+ **/
+gboolean
+pk_transaction_db_get_list (PkTransactionDb *tdb, guint limit)
+{
+	gchar *statement;
+
+	g_return_val_if_fail (tdb != NULL, FALSE);
+	g_return_val_if_fail (PK_IS_TRANSACTION_DB (tdb), FALSE);
+
+	statement = g_strdup_printf ("SELECT transaction_id, timespec, succeeded, duration, role "
+				     "FROM transactions ORDER BY transaction_id DESC LIMIT %i", limit);
+	pk_transaction_db_sql_statement (tdb, statement);
+	g_free (statement);
+
+	return TRUE;
+}
+
+/**
  * pk_transaction_db_add:
  **/
 gboolean
 pk_transaction_db_add (PkTransactionDb *tdb, const gchar *tid)
 {
+	GTimeVal timeval;
+	gchar *timespec;
+	gchar *statement;
+
+	g_return_val_if_fail (tdb != NULL, FALSE);
+	g_return_val_if_fail (PK_IS_TRANSACTION_DB (tdb), FALSE);
+
+	pk_debug ("adding transaction %s", tid);
+
+	/* get current time */
+	g_get_current_time (&timeval);
+	timespec = g_time_val_to_iso8601 (&timeval);
+	pk_debug ("timespec=%s", timespec);
+
+	statement = g_strdup_printf ("INSERT INTO transactions (transaction_id, timespec) VALUES ('%s', '%s')", tid, timespec);
+	pk_transaction_db_sql_statement (tdb, statement);
+	g_free (statement);
+
+	g_free (timespec);
+
+	return TRUE;
+}
+
+/**
+ * pk_transaction_db_set_role:
+ **/
+gboolean
+pk_transaction_db_set_role (PkTransactionDb *tdb, const gchar *tid, PkRoleEnum role)
+{
+	gchar *statement;
+	const gchar *role_text;
+
+	g_return_val_if_fail (tdb != NULL, FALSE);
+	g_return_val_if_fail (PK_IS_TRANSACTION_DB (tdb), FALSE);
+
+	role_text = pk_role_enum_to_text (role);
+	statement = g_strdup_printf ("UPDATE transactions SET role = '%s' WHERE transaction_id = '%s'", role_text, tid);
+	pk_transaction_db_sql_statement (tdb, statement);
+	g_free (statement);
+	return TRUE;
+}
+
+/**
+ * pk_transaction_db_set_finished:
+ **/
+gboolean
+pk_transaction_db_set_finished (PkTransactionDb *tdb, const gchar *tid, gboolean success, guint runtime)
+{
+	gchar *statement;
+
+	g_return_val_if_fail (tdb != NULL, FALSE);
+	g_return_val_if_fail (PK_IS_TRANSACTION_DB (tdb), FALSE);
+
+	statement = g_strdup_printf ("UPDATE transactions SET succeeded = %i, duration = %i WHERE transaction_id = '%s'",
+				     success, runtime, tid);
+	pk_transaction_db_sql_statement (tdb, statement);
+	g_free (statement);
+	return TRUE;
+}
+
+/**
+ * pk_transaction_db_print:
+ **/
+gboolean
+pk_transaction_db_print (PkTransactionDb *tdb)
+{
+	const gchar *statement;
+
+	g_return_val_if_fail (tdb != NULL, FALSE);
+	g_return_val_if_fail (PK_IS_TRANSACTION_DB (tdb), FALSE);
+
+	statement = "SELECT transaction_id, timespec, succeeded, duration, role FROM transactions";
+	pk_transaction_db_sql_statement (tdb, statement);
+
 	return TRUE;
 }
 
@@ -76,30 +249,17 @@ pk_transaction_db_class_init (PkTransact
 }
 
 /**
- * pk_transaction_sqlite_callback:
- **/
-static gint
-pk_transaction_sqlite_callback (void *data, gint argc, gchar **argv, gchar **col_name)
-{
-//	PkTransactionDb *tdb = PK_TRANSACTION_DB (data);
-	gint i;
-	for (i=0; i<argc; i++) {
-		g_print ("%s = %s\n", col_name[i], argv[i]);
-	}
-	g_print ("\n");
-	return 0;
-}
-
-/**
  * pk_transaction_db_init:
  **/
 static void
 pk_transaction_db_init (PkTransactionDb *tdb)
 {
 	const gchar *statement;
-	gchar *error_msg = NULL;
 	gint rc;
 
+	g_return_if_fail (tdb != NULL);
+	g_return_if_fail (PK_IS_TRANSACTION_DB (tdb));
+
 	tdb->priv = PK_TRANSACTION_DB_GET_PRIVATE (tdb);
 	pk_debug ("trying to open database '%s'", PK_TRANSACTION_DB_FILE);
 	rc = sqlite3_open (PK_TRANSACTION_DB_FILE, &tdb->priv->db);
@@ -109,12 +269,15 @@ pk_transaction_db_init (PkTransactionDb 
 		return;
 	}
 
+	/* add extra tables */
+	statement = "ALTER table transactions ADD timespec TEXT;";
+	sqlite3_exec (tdb->priv->db, statement, NULL, 0, NULL);
+
+	/* ick */
+	pk_transaction_db_print (tdb);
+
 	statement = "SELECT time date FROM transactions WHERE transaction_id = \"13;acaef\"";
-	rc = sqlite3_exec (tdb->priv->db, statement, pk_transaction_sqlite_callback, 0, &error_msg);
-	if (rc != SQLITE_OK) {
-		pk_warning ("SQL error: %s\n", error_msg);
-		sqlite3_free (error_msg);
-	}
+	pk_transaction_db_sql_statement (tdb, statement);
 }
 
 /**
diff --git a/src/pk-transaction-db.h b/src/pk-transaction-db.h
index 6e187ba..c1fcb26 100644
--- a/src/pk-transaction-db.h
+++ b/src/pk-transaction-db.h
@@ -23,6 +23,7 @@
 #define __PK_TRANSACTION_DB_H
 
 #include <glib-object.h>
+#include <pk-enum.h>
 
 G_BEGIN_DECLS
 
@@ -50,6 +51,16 @@ GType		 pk_transaction_db_get_type		(voi
 PkTransactionDb	*pk_transaction_db_new			(void);
 gboolean	 pk_transaction_db_add			(PkTransactionDb	*tdb,
 							 const gchar		*tid);
+gboolean	 pk_transaction_db_print		(PkTransactionDb	*tdb);
+gboolean	 pk_transaction_db_set_role		(PkTransactionDb	*tdb,
+							 const gchar		*tid,
+							 PkRoleEnum		 role);
+gboolean	 pk_transaction_db_set_finished		(PkTransactionDb	*tdb,
+							 const gchar		*tid,
+							 gboolean		 success,
+							 guint			 runtime);
+gboolean	 pk_transaction_db_get_list		(PkTransactionDb	*tdb,
+							 guint			 limit);
 
 G_END_DECLS
 
diff-tree 675417a1a6f4dcb92a2d556a3268f93c2d5e2c78 (from 3404b4350257bc14db199b33824a86714056e079)
Author: Richard Hughes <richard at hughsie.com>
Date:   Sun Sep 16 22:27:14 2007 +0100

    don't populate the enum list with a value for 'none'

diff --git a/libpackagekit/pk-enum-list.c b/libpackagekit/pk-enum-list.c
index 28ef095..c449954 100644
--- a/libpackagekit/pk-enum-list.c
+++ b/libpackagekit/pk-enum-list.c
@@ -101,6 +101,12 @@ pk_enum_list_from_string (PkEnumList *el
 		return FALSE;
 	}
 
+	/* check if we have nothing */
+	if (strcmp (enums, "none") == 0) {
+		pk_debug ("no values");
+		return TRUE;
+	}
+
 	/* split by delimeter ';' */
 	sections = g_strsplit (enums, ";", 0);
 	for (i=0; sections[i]; i++) {
@@ -351,6 +357,29 @@ libst_enum_list (LibSelfTest *test)
 		libst_failed (test, "invalid '%s', should be 'search-name;search-details;search-group'", text);
 	}
 	g_free (text);
+	g_object_unref (elist);
+
+	/************************************************************/
+	libst_title (test, "set none enum list");
+	elist = pk_enum_list_new ();
+	pk_enum_list_set_type (elist, PK_ENUM_LIST_TYPE_ACTION);
+	pk_enum_list_from_string (elist, "none");
+	if (elist->priv->data->len == 0) {
+		libst_success (test, NULL);
+	} else {
+		libst_failed (test, "invalid length %i", elist->priv->data->len);
+	}
+
+	/************************************************************/
+	libst_title (test, "get none enum list");
+	text = pk_enum_list_to_string (elist);
+	if (strcmp (text, "none") == 0) {
+		libst_success (test, NULL);
+	} else {
+		libst_failed (test, "invalid '%s', should be 'none'", text);
+	}
+	g_free (text);
+
 
 	g_object_unref (elist);
 	libst_end (test);
diff-tree 3404b4350257bc14db199b33824a86714056e079 (from b3054fd6ebce583e4559e45e7acb91d916225f19)
Author: Richard Hughes <richard at hughsie.com>
Date:   Sun Sep 16 22:00:50 2007 +0100

    add a new modular thread list class

diff --git a/src/Makefile.am b/src/Makefile.am
index 5b17032..66e722b 100644
--- a/src/Makefile.am
+++ b/src/Makefile.am
@@ -56,6 +56,8 @@ packagekitd_SOURCES =					\
 	pk-engine.c					\
 	pk-network.h					\
 	pk-network.c					\
+	pk-thread-list.h				\
+	pk-thread-list.c				\
 	pk-transaction-db.h				\
 	pk-transaction-db.c				\
 	$(NULL)
@@ -110,6 +112,8 @@ check_PROGRAMS =					\
 pk_self_test_SOURCES =					\
 	pk-spawn.h					\
 	pk-spawn.c					\
+	pk-thread-list.h				\
+	pk-thread-list.c				\
 	pk-self-test.c					\
 	$(NULL)
 
diff --git a/src/pk-backend.c b/src/pk-backend.c
index 31415ab..cc6b3fa 100644
--- a/src/pk-backend.c
+++ b/src/pk-backend.c
@@ -46,6 +46,7 @@
 #include "pk-enum.h"
 #include "pk-spawn.h"
 #include "pk-network.h"
+#include "pk-thread-list.h"
 
 #define PK_BACKEND_GET_PRIVATE(o) (G_TYPE_INSTANCE_GET_PRIVATE ((o), PK_TYPE_BACKEND, PkBackendPrivate))
 
@@ -66,6 +67,7 @@ struct _PkBackendPrivate
 	guint			 last_percentage;
 	guint			 last_subpercentage;
 	gchar			*last_package;
+	PkThreadList		*thread_list;
 };
 
 enum {
@@ -165,6 +167,14 @@ pk_backend_get_name (PkBackend *backend)
 	return backend->priv->name;
 }
 
+/**
+ * pk_backend_thread_create:
+ **/
+gboolean
+pk_backend_thread_create (PkBackend *backend, PkBackendThreadFunc func, gpointer data)
+{
+	return pk_thread_list_create (backend->priv->thread_list, (PkThreadFunc) func, backend, data);
+}
 
 /**
  * pk_backend_parse_common_output:
@@ -702,6 +712,9 @@ pk_backend_finished (PkBackend *backend,
 	g_return_val_if_fail (backend != NULL, FALSE);
 	g_return_val_if_fail (PK_IS_BACKEND (backend), FALSE);
 
+	pk_debug ("waiting for all threads");
+	pk_thread_list_wait (backend->priv->thread_list);
+
 	/* 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);
@@ -1139,6 +1152,7 @@ pk_backend_finalize (GObject *object)
 	g_timer_destroy (backend->priv->timer);
 	g_free (backend->priv->last_package);
 	g_object_unref (backend->priv->network);
+	g_object_unref (backend->priv->thread_list);
 
 	G_OBJECT_CLASS (pk_backend_parent_class)->finalize (object);
 }
@@ -1232,6 +1246,7 @@ pk_backend_init (PkBackend *backend)
 	backend->priv->status = PK_STATUS_ENUM_UNKNOWN;
 	backend->priv->exit = PK_EXIT_ENUM_UNKNOWN;
 	backend->priv->network = pk_network_new ();
+	backend->priv->thread_list = pk_thread_list_new ();
 }
 
 /**
diff --git a/src/pk-backend.h b/src/pk-backend.h
index da82bc1..1f1bbc6 100644
--- a/src/pk-backend.h
+++ b/src/pk-backend.h
@@ -72,6 +72,12 @@ gboolean	 pk_backend_allow_interrupt		(P
 							 gboolean	 allow_restart);
 gboolean	 pk_backend_network_is_online		(PkBackend	*backend);
 
+typedef gboolean (*PkBackendThreadFunc)			(PkBackend	*backend,
+							 gpointer	 data);
+gboolean	 pk_backend_thread_create		(PkBackend	*backend,
+							 PkBackendThreadFunc func,
+							 gpointer	 data);
+
 /**
  * PkBackendDesc:
  */
diff --git a/src/pk-self-test.c b/src/pk-self-test.c
index f8a7e49..9fa6c6a 100644
--- a/src/pk-self-test.c
+++ b/src/pk-self-test.c
@@ -22,20 +22,27 @@
 #include <glib.h>
 #include <glib-object.h>
 #include <libselftest.h>
+#include <pk-debug.h>
 
 /* prototypes */
 void libst_spawn (LibSelfTest *test);
+void libst_thread_list (LibSelfTest *test);
 
 int
 main (int argc, char **argv)
 {
 	LibSelfTest test;
 
+	if (! g_thread_supported ()) {
+		g_thread_init (NULL);
+	}
 	g_type_init ();
 	libst_init (&test);
+	pk_debug_init (TRUE);
 
 	/* tests go here */
 	libst_spawn (&test);
+	libst_thread_list (&test);
 
 	return (libst_finish (&test));
 }
diff --git a/src/pk-thread-list.c b/src/pk-thread-list.c
new file mode 100644
index 0000000..4869356
--- /dev/null
+++ b/src/pk-thread-list.c
@@ -0,0 +1,303 @@
+/* -*- 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.
+ */
+
+#include "config.h"
+
+#include <stdlib.h>
+#include <stdio.h>
+#include <time.h>
+#include <errno.h>
+#include <signal.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 "pk-debug.h"
+#include "pk-thread-list.h"
+
+static void     pk_thread_list_class_init	(PkThreadListClass *klass);
+static void     pk_thread_list_init	(PkThreadList      *tlist);
+static void     pk_thread_list_finalize	(GObject        *object);
+
+#define PK_THREAD_LIST_GET_PRIVATE(o) (G_TYPE_INSTANCE_GET_PRIVATE ((o), PK_TYPE_THREAD_LIST, PkThreadListPrivate))
+#define PK_THREAD_LIST_COUNT_FILE		LOCALSTATEDIR "/run/PackageKit/thread_count.dat"
+
+struct PkThreadListPrivate
+{
+	GPtrArray		*thread_list;
+};
+
+G_DEFINE_TYPE (PkThreadList, pk_thread_list, G_TYPE_OBJECT)
+
+typedef struct
+{
+	GThread			*thread;
+	gpointer		 param;
+	gpointer		 data;
+	gboolean		 running;
+	PkThreadFunc		 func;
+} PkThreadListItem;
+
+/**
+ * pk_thread_list_item_new:
+ **/
+static void *
+pk_thread_list_item_new (gpointer data)
+{
+	PkThreadListItem *item = (PkThreadListItem *) data;
+	gboolean ret;
+	pk_debug ("running %p", item->func);
+	ret = item->func (item->param, item->data);
+	pk_debug ("ret is %i", ret);
+	item->running = FALSE;
+	return NULL;
+}
+
+/**
+ * pk_thread_list_create:
+ **/
+gboolean
+pk_thread_list_create (PkThreadList *tlist, PkThreadFunc func, gpointer param, gpointer data)
+{
+	PkThreadListItem *item;
+
+	g_return_val_if_fail (tlist != NULL, FALSE);
+	g_return_val_if_fail (PK_IS_THREAD_LIST (tlist), FALSE);
+
+	item = g_new0 (PkThreadListItem, 1);
+
+	/* create a new thread object */
+	item->func = func;
+	item->param = param;
+	item->data = data;
+	item->running = TRUE;
+	item->thread = g_thread_create (pk_thread_list_item_new, item, TRUE, NULL);
+
+	/* add to list */
+	g_ptr_array_add (tlist->priv->thread_list, item);
+	pk_debug ("created thread %p", item->thread);
+	return TRUE;
+}
+
+/**
+ * pk_thread_list_wait:
+ **/
+gboolean
+pk_thread_list_wait (PkThreadList *tlist)
+{
+	guint i;
+	guint length;
+	PkThreadListItem *item;
+
+	g_return_val_if_fail (tlist != NULL, FALSE);
+	g_return_val_if_fail (PK_IS_THREAD_LIST (tlist), FALSE);
+
+	/* wait for all the threads to finish */
+	length = tlist->priv->thread_list->len;
+	for (i=0; i<length; i++) {
+		item = (PkThreadListItem *) g_ptr_array_index (tlist->priv->thread_list, i);
+		if (item->running == TRUE) {
+			pk_debug ("joining thread %p", item->thread);
+			g_thread_join (item->thread);
+		} else {
+			pk_debug ("ignoring exited thread %p", item->thread);
+		}
+	}
+	return TRUE;
+}
+
+/**
+ * pk_thread_list_class_init:
+ * @klass: The PkThreadListClass
+ **/
+static void
+pk_thread_list_class_init (PkThreadListClass *klass)
+{
+	GObjectClass *object_class = G_OBJECT_CLASS (klass);
+	object_class->finalize = pk_thread_list_finalize;
+	g_type_class_add_private (klass, sizeof (PkThreadListPrivate));
+}
+
+/**
+ * pk_thread_list_init:
+ * @thread_list: This class instance
+ **/
+static void
+pk_thread_list_init (PkThreadList *tlist)
+{
+	tlist->priv = PK_THREAD_LIST_GET_PRIVATE (tlist);
+	tlist->priv->thread_list = g_ptr_array_new ();
+}
+
+/**
+ * pk_thread_list_finalize:
+ * @object: The object to finalize
+ **/
+static void
+pk_thread_list_finalize (GObject *object)
+{
+	PkThreadList *tlist;
+
+	g_return_if_fail (object != NULL);
+	g_return_if_fail (PK_IS_THREAD_LIST (object));
+
+	tlist = PK_THREAD_LIST (object);
+	g_return_if_fail (tlist->priv != NULL);
+	g_ptr_array_free (tlist->priv->thread_list, TRUE);
+	G_OBJECT_CLASS (pk_thread_list_parent_class)->finalize (object);
+}
+
+/**
+ * pk_thread_list_new:
+ *
+ * Return value: a new PkThreadList object.
+ **/
+PkThreadList *
+pk_thread_list_new (void)
+{
+	PkThreadList *tlist;
+	tlist = g_object_new (PK_TYPE_THREAD_LIST, NULL);
+	return PK_THREAD_LIST (tlist);
+}
+
+/***************************************************************************
+ ***                          MAKE CHECK TESTS                           ***
+ ***************************************************************************/
+#ifdef PK_BUILD_TESTS
+#include <libselftest.h>
+
+gboolean done_func1 = FALSE;
+gboolean done_func2 = FALSE;
+
+static gboolean
+test_func1 (PkThreadList *tlist, gpointer data)
+{
+	GTimer *timer;
+	gdouble elapsed;
+
+	if (tlist != GINT_TO_POINTER(0x01) || data != GINT_TO_POINTER(0x02)) {
+		pk_debug ("WRONG PARAMS (%p, %p)", tlist, data);
+		return FALSE;
+	}
+	pk_debug ("started task (%p,%p)", tlist, data);
+	timer = g_timer_new ();
+	do {
+		g_usleep (1000*100);
+		g_thread_yield ();
+		elapsed = g_timer_elapsed (timer, NULL);
+		pk_debug ("elapsed task (%p,%p) = %f", tlist, data, elapsed);
+	} while (elapsed < 2.0);
+	g_timer_destroy (timer);
+	pk_debug ("exited task (%p,%p)", tlist, data);
+	done_func1 = TRUE;
+	return TRUE;
+}
+
+static gboolean
+test_func2 (PkThreadList *tlist, gpointer data)
+{
+	GTimer *timer;
+	gdouble elapsed;
+
+	if (tlist != GINT_TO_POINTER(0x02) || data != GINT_TO_POINTER(0x03)) {
+		pk_debug ("WRONG PARAMS (%p, %p)", tlist, data);
+		return FALSE;
+	}
+	pk_debug ("started task (%p,%p)", tlist, data);
+	timer = g_timer_new ();
+	do {
+		g_usleep (1000*100);
+		g_thread_yield ();
+		elapsed = g_timer_elapsed (timer, NULL);
+		pk_debug ("elapsed task (%p,%p) = %f", tlist, data, elapsed);
+	} while (elapsed < 1.0);
+	g_timer_destroy (timer);
+	pk_debug ("exited task (%p,%p)", tlist, data);
+	done_func2 = TRUE;
+	return TRUE;
+}
+
+void
+libst_thread_list (LibSelfTest *test)
+{
+	PkThreadList *tlist;
+	gboolean ret;
+
+	if (libst_start (test, "PkThreadList", CLASS_AUTO) == FALSE) {
+		return;
+	}
+
+	tlist = pk_thread_list_new ();
+
+	/************************************************************/
+	libst_title (test, "create task 1");
+	ret = pk_thread_list_create (tlist, test_func1, GINT_TO_POINTER(0x01), GINT_TO_POINTER(0x02));
+	if (ret == TRUE) {
+		libst_success (test, NULL);
+	} else {
+		libst_failed (test, "failed to create task1");
+	}
+
+	/************************************************************/
+	libst_title (test, "create task 2");
+	ret = pk_thread_list_create (tlist, test_func2, GINT_TO_POINTER(0x02), GINT_TO_POINTER(0x03));
+	if (ret == TRUE) {
+		libst_success (test, NULL);
+	} else {
+		libst_failed (test, "failed to create task2");
+	}
+
+	/************************************************************/
+	libst_title (test, "wait for finish");
+	ret = pk_thread_list_wait (tlist);
+	if (ret == TRUE) {
+		libst_success (test, NULL);
+	} else {
+		libst_failed (test, "failed to wait for task");
+	}
+
+	/************************************************************/
+	libst_title (test, "ran func1 to completion");
+	if (done_func1 == TRUE) {
+		libst_success (test, NULL);
+	} else {
+		libst_failed (test, "failed to run func1");
+	}
+
+	/************************************************************/
+	libst_title (test, "ran func2 to completion");
+	if (done_func2 == TRUE) {
+		libst_success (test, NULL);
+	} else {
+		libst_failed (test, "failed to run func2");
+	}
+
+	g_object_unref (tlist);
+
+	libst_end (test);
+}
+#endif
+
diff --git a/src/pk-thread-list.h b/src/pk-thread-list.h
new file mode 100644
index 0000000..914bfcc
--- /dev/null
+++ b/src/pk-thread-list.h
@@ -0,0 +1,63 @@
+/* -*- 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_THREAD_LIST_H
+#define __PK_THREAD_LIST_H
+
+#include <glib-object.h>
+#include "pk-backend-internal.h"
+
+G_BEGIN_DECLS
+
+#define PK_TYPE_THREAD_LIST		(pk_thread_list_get_type ())
+#define PK_THREAD_LIST(o)		(G_TYPE_CHECK_INSTANCE_CAST ((o), PK_TYPE_THREAD_LIST, PkThreadList))
+#define PK_THREAD_LIST_CLASS(k)		(G_TYPE_CHECK_CLASS_CAST((k), PK_TYPE_THREAD_LIST, PkThreadListClass))
+#define PK_IS_THREAD_LIST(o)	 	(G_TYPE_CHECK_INSTANCE_TYPE ((o), PK_TYPE_THREAD_LIST))
+#define PK_IS_THREAD_LIST_CLASS(k)	(G_TYPE_CHECK_CLASS_TYPE ((k), PK_TYPE_THREAD_LIST))
+#define PK_THREAD_LIST_GET_CLASS(o)	(G_TYPE_INSTANCE_GET_CLASS ((o), PK_TYPE_THREAD_LIST, PkThreadListClass))
+
+typedef struct PkThreadListPrivate PkThreadListPrivate;
+
+typedef struct
+{
+	 GObject		 parent;
+	 PkThreadListPrivate	*priv;
+} PkThreadList;
+
+typedef struct
+{
+	GObjectClass	parent_class;
+} PkThreadListClass;
+
+GType		 pk_thread_list_get_type	  	(void);
+PkThreadList	*pk_thread_list_new			(void);
+
+typedef gboolean (*PkThreadFunc)			(PkThreadList	*tlist,
+							 gpointer	 data);
+gboolean	 pk_thread_list_create			(PkThreadList	*tlist,
+							 PkThreadFunc	 func,
+							 gpointer	 param,
+							 gpointer	 data);
+gboolean	 pk_thread_list_wait			(PkThreadList	*tlist);
+
+G_END_DECLS
+
+#endif /* __PK_THREAD_LIST_H */
diff-tree b3054fd6ebce583e4559e45e7acb91d916225f19 (from d7fa52fc14d60c8c664230d3ad9d77d83fd3e654)
Author: Richard Hughes <richard at hughsie.com>
Date:   Sun Sep 16 20:52:59 2007 +0100

    add different types of test backends

diff --git a/backends/test/Makefile.am b/backends/test/Makefile.am
index e26a9a3..9b8a328 100644
--- a/backends/test/Makefile.am
+++ b/backends/test/Makefile.am
@@ -1,7 +1,33 @@
 plugindir = @PK_PLUGIN_DIR@
-plugin_LTLIBRARIES = libpk_backend_test.la
-libpk_backend_test_la_SOURCES = pk-backend-test.c
-libpk_backend_test_la_LIBADD = @PK_PLUGIN_LIBS@
-libpk_backend_test_la_LDFLAGS = -module -avoid-version
-libpk_backend_test_la_CFLAGS = @PK_PLUGIN_CFLAGS@
+plugin_LTLIBRARIES =			\
+	libpk_backend_test_nop.la	\
+	libpk_backend_test_fail.la	\
+	libpk_backend_test_spawn.la	\
+	libpk_backend_test_succeed.la	\
+	libpk_backend_test_thread.la
+
+libpk_backend_test_nop_la_SOURCES = pk-backend-test-nop.c
+libpk_backend_test_nop_la_LIBADD = @PK_PLUGIN_LIBS@
+libpk_backend_test_nop_la_LDFLAGS = -module -avoid-version
+libpk_backend_test_nop_la_CFLAGS = @PK_PLUGIN_CFLAGS@
+
+libpk_backend_test_fail_la_SOURCES = pk-backend-test-fail.c
+libpk_backend_test_fail_la_LIBADD = @PK_PLUGIN_LIBS@
+libpk_backend_test_fail_la_LDFLAGS = -module -avoid-version
+libpk_backend_test_fail_la_CFLAGS = @PK_PLUGIN_CFLAGS@
+
+libpk_backend_test_spawn_la_SOURCES = pk-backend-test-spawn.c
+libpk_backend_test_spawn_la_LIBADD = @PK_PLUGIN_LIBS@
+libpk_backend_test_spawn_la_LDFLAGS = -module -avoid-version
+libpk_backend_test_spawn_la_CFLAGS = @PK_PLUGIN_CFLAGS@
+
+libpk_backend_test_succeed_la_SOURCES = pk-backend-test-succeed.c
+libpk_backend_test_succeed_la_LIBADD = @PK_PLUGIN_LIBS@
+libpk_backend_test_succeed_la_LDFLAGS = -module -avoid-version
+libpk_backend_test_succeed_la_CFLAGS = @PK_PLUGIN_CFLAGS@
+
+libpk_backend_test_thread_la_SOURCES = pk-backend-test-thread.c
+libpk_backend_test_thread_la_LIBADD = @PK_PLUGIN_LIBS@
+libpk_backend_test_thread_la_LDFLAGS = -module -avoid-version
+libpk_backend_test_thread_la_CFLAGS = @PK_PLUGIN_CFLAGS@
 
diff --git a/backends/test/pk-backend-test-fail.c b/backends/test/pk-backend-test-fail.c
new file mode 100644
index 0000000..dd52668
--- /dev/null
+++ b/backends/test/pk-backend-test-fail.c
@@ -0,0 +1,229 @@
+/* -*- 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.
+ */
+
+#include <gmodule.h>
+#include <glib.h>
+#include <string.h>
+#include <pk-backend.h>
+
+/**
+ * backend_get_groups:
+ */
+static void
+backend_get_groups (PkBackend *backend, PkEnumList *elist)
+{
+	g_return_if_fail (backend != NULL);
+	pk_enum_list_append_multiple (elist,
+				      PK_GROUP_ENUM_ACCESSIBILITY,
+				      PK_GROUP_ENUM_GAMES,
+				      PK_GROUP_ENUM_SYSTEM,
+				      -1);
+}
+
+/**
+ * backend_get_filters:
+ */
+static void
+backend_get_filters (PkBackend *backend, PkEnumList *elist)
+{
+	g_return_if_fail (backend != NULL);
+	pk_enum_list_append_multiple (elist,
+				      PK_FILTER_ENUM_GUI,
+				      PK_FILTER_ENUM_INSTALLED,
+				      PK_FILTER_ENUM_DEVELOPMENT,
+				      -1);
+}
+
+/**
+ * backend_cancel_job_try:
+ */
+static void
+backend_cancel_job_try (PkBackend *backend)
+{
+	g_return_if_fail (backend != NULL);
+	pk_backend_finished (backend, PK_EXIT_ENUM_FAILED);
+}
+
+/**
+ * backend_get_depends:
+ */
+static void
+backend_get_depends (PkBackend *backend, const gchar *package_id)
+{
+	g_return_if_fail (backend != NULL);
+	pk_backend_finished (backend, PK_EXIT_ENUM_FAILED);
+}
+
+/**
+ * backend_get_description:
+ */
+static void
+backend_get_description (PkBackend *backend, const gchar *package_id)
+{
+	g_return_if_fail (backend != NULL);
+	pk_backend_finished (backend, PK_EXIT_ENUM_FAILED);
+}
+
+/**
+ * backend_get_requires:
+ */
+static void
+backend_get_requires (PkBackend *backend, const gchar *package_id)
+{
+	g_return_if_fail (backend != NULL);
+	pk_backend_finished (backend, PK_EXIT_ENUM_FAILED);
+}
+
+/**
+ * backend_get_update_detail:
+ */
+static void
+backend_get_update_detail (PkBackend *backend, const gchar *package_id)
+{
+	g_return_if_fail (backend != NULL);
+	pk_backend_finished (backend, PK_EXIT_ENUM_FAILED);
+}
+
+/**
+ * backend_get_updates:
+ */
+static void
+backend_get_updates (PkBackend *backend)
+{
+	g_return_if_fail (backend != NULL);
+	pk_backend_finished (backend, PK_EXIT_ENUM_FAILED);
+}
+
+/**
+ * backend_install_package:
+ */
+static void
+backend_install_package (PkBackend *backend, const gchar *package_id)
+{
+	g_return_if_fail (backend != NULL);
+	pk_backend_finished (backend, PK_EXIT_ENUM_FAILED);
+}
+
+/**
+ * backend_refresh_cache:
+ */
+static void
+backend_refresh_cache (PkBackend *backend, gboolean force)
+{
+	g_return_if_fail (backend != NULL);
+	pk_backend_finished (backend, PK_EXIT_ENUM_FAILED);
+}
+
+/**
+ * backend_remove_package:
+ */
+static void
+backend_remove_package (PkBackend *backend, const gchar *package_id, gboolean allow_deps)
+{
+	g_return_if_fail (backend != NULL);
+	pk_backend_finished (backend, PK_EXIT_ENUM_FAILED);
+}
+
+/**
+ * backend_search_details:
+ */
+static void
+backend_search_details (PkBackend *backend, const gchar *filter, const gchar *search)
+{
+	g_return_if_fail (backend != NULL);
+	pk_backend_finished (backend, PK_EXIT_ENUM_FAILED);
+}
+
+/**
+ * backend_search_file:
+ */
+static void
+backend_search_file (PkBackend *backend, const gchar *filter, const gchar *search)
+{
+	g_return_if_fail (backend != NULL);
+	pk_backend_finished (backend, PK_EXIT_ENUM_FAILED);
+}
+
+/**
+ * backend_search_group:
+ */
+static void
+backend_search_group (PkBackend *backend, const gchar *filter, const gchar *search)
+{
+	g_return_if_fail (backend != NULL);
+	pk_backend_finished (backend, PK_EXIT_ENUM_FAILED);
+}
+
+/**
+ * backend_search_name:
+ */
+static void
+backend_search_name (PkBackend *backend, const gchar *filter, const gchar *search)
+{
+	g_return_if_fail (backend != NULL);
+	pk_backend_finished (backend, PK_EXIT_ENUM_FAILED);
+}
+
+/**
+ * backend_update_package:
+ */
+static void
+backend_update_package (PkBackend *backend, const gchar *package_id)
+{
+	g_return_if_fail (backend != NULL);
+	pk_backend_finished (backend, PK_EXIT_ENUM_FAILED);
+}
+
+/**
+ * backend_update_system:
+ */
+static void
+backend_update_system (PkBackend *backend)
+{
+	g_return_if_fail (backend != NULL);
+	pk_backend_finished (backend, PK_EXIT_ENUM_FAILED);
+}
+
+PK_BACKEND_OPTIONS (
+	"Test Fail Backend",			/* description */
+	"0.0.1",				/* version */
+	"Richard Hughes <richard at hughsie.com>",	/* author */
+	NULL,					/* initalize */
+	NULL,					/* destroy */
+	backend_get_groups,			/* get_groups */
+	backend_get_filters,			/* get_filters */
+	backend_cancel_job_try,			/* cancel_job_try */
+	backend_get_depends,			/* get_depends */
+	backend_get_description,		/* get_description */
+	backend_get_requires,			/* get_requires */
+	backend_get_update_detail,		/* get_update_detail */
+	backend_get_updates,			/* get_updates */
+	backend_install_package,		/* install_package */
+	backend_refresh_cache,			/* refresh_cache */
+	backend_remove_package,			/* remove_package */
+	backend_search_details,			/* search_details */
+	backend_search_file,			/* search_file */
+	backend_search_group,			/* search_group */
+	backend_search_name,			/* search_name */
+	backend_update_package,			/* update_package */
+	backend_update_system			/* update_system */
+);
+
diff --git a/backends/test/pk-backend-test-nop.c b/backends/test/pk-backend-test-nop.c
new file mode 100644
index 0000000..315592b
--- /dev/null
+++ b/backends/test/pk-backend-test-nop.c
@@ -0,0 +1,50 @@
+/* -*- 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.
+ */
+
+#include <gmodule.h>
+#include <glib.h>
+#include <pk-backend.h>
+
+PK_BACKEND_OPTIONS (
+	"Test NOP Backend",			/* description */
+	"0.0.1",				/* version */
+	"Richard Hughes <richard at hughsie.com>",	/* author */
+	NULL,					/* initalize */
+	NULL,					/* destroy */
+	NULL,					/* get_groups */
+	NULL,					/* get_filters */
+	NULL,					/* cancel_job_try */
+	NULL,					/* get_depends */
+	NULL,					/* get_description */
+	NULL,					/* get_requires */
+	NULL,					/* get_update_detail */
+	NULL,					/* get_updates */
+	NULL,					/* install_package */
+	NULL,					/* refresh_cache */
+	NULL,					/* remove_package */
+	NULL,					/* search_details */
+	NULL,					/* search_file */
+	NULL,					/* search_group */
+	NULL,					/* search_name */
+	NULL,					/* update_package */
+	NULL					/* update_system */
+);
+
diff --git a/backends/test/pk-backend-test-spawn.c b/backends/test/pk-backend-test-spawn.c
new file mode 100644
index 0000000..a4c03ce
--- /dev/null
+++ b/backends/test/pk-backend-test-spawn.c
@@ -0,0 +1,247 @@
+/* -*- 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.
+ */
+
+#include <gmodule.h>
+#include <glib.h>
+#include <string.h>
+#include <pk-backend.h>
+
+/**
+ * backend_initalize:
+ */
+static void
+backend_initalize (PkBackend *backend)
+{
+	g_return_if_fail (backend != NULL);
+}
+
+/**
+ * backend_destroy:
+ */
+static void
+backend_destroy (PkBackend *backend)
+{
+	g_return_if_fail (backend != NULL);
+}
+
+/**
+ * backend_get_groups:
+ */
+static void
+backend_get_groups (PkBackend *backend, PkEnumList *elist)
+{
+	g_return_if_fail (backend != NULL);
+	pk_enum_list_append_multiple (elist,
+				      PK_GROUP_ENUM_ACCESSIBILITY,
+				      PK_GROUP_ENUM_GAMES,
+				      PK_GROUP_ENUM_SYSTEM,
+				      -1);
+}
+
+/**
+ * backend_get_filters:
+ */
+static void
+backend_get_filters (PkBackend *backend, PkEnumList *elist)
+{
+	g_return_if_fail (backend != NULL);
+	pk_enum_list_append_multiple (elist,
+				      PK_FILTER_ENUM_GUI,
+				      PK_FILTER_ENUM_INSTALLED,
+				      PK_FILTER_ENUM_DEVELOPMENT,
+				      -1);
+}
+
+/**
+ * backend_cancel_job_try:
+ */
+static void
+backend_cancel_job_try (PkBackend *backend)
+{
+	g_return_if_fail (backend != NULL);
+	pk_backend_finished (backend, PK_EXIT_ENUM_FAILED);
+}
+
+/**
+ * backend_get_depends:
+ */
+static void
+backend_get_depends (PkBackend *backend, const gchar *package_id)
+{
+	g_return_if_fail (backend != NULL);
+	pk_backend_finished (backend, PK_EXIT_ENUM_FAILED);
+}
+
+/**
+ * backend_get_description:
+ */
+static void
+backend_get_description (PkBackend *backend, const gchar *package_id)
+{
+	g_return_if_fail (backend != NULL);
+	pk_backend_finished (backend, PK_EXIT_ENUM_FAILED);
+}
+
+/**
+ * backend_get_requires:
+ */
+static void
+backend_get_requires (PkBackend *backend, const gchar *package_id)
+{
+	g_return_if_fail (backend != NULL);
+	pk_backend_finished (backend, PK_EXIT_ENUM_FAILED);
+}
+
+/**
+ * backend_get_update_detail:
+ */
+static void
+backend_get_update_detail (PkBackend *backend, const gchar *package_id)
+{
+	g_return_if_fail (backend != NULL);
+	pk_backend_finished (backend, PK_EXIT_ENUM_FAILED);
+}
+
+/**
+ * backend_get_updates:
+ */
+static void
+backend_get_updates (PkBackend *backend)
+{
+	g_return_if_fail (backend != NULL);
+	pk_backend_finished (backend, PK_EXIT_ENUM_FAILED);
+}
+
+/**
+ * backend_install_package:
+ */
+static void
+backend_install_package (PkBackend *backend, const gchar *package_id)
+{
+	g_return_if_fail (backend != NULL);
+	pk_backend_finished (backend, PK_EXIT_ENUM_FAILED);
+}
+
+/**
+ * backend_refresh_cache:
+ */
+static void
+backend_refresh_cache (PkBackend *backend, gboolean force)
+{
+	g_return_if_fail (backend != NULL);
+	pk_backend_finished (backend, PK_EXIT_ENUM_FAILED);
+}
+
+/**
+ * backend_remove_package:
+ */
+static void
+backend_remove_package (PkBackend *backend, const gchar *package_id, gboolean allow_deps)
+{
+	g_return_if_fail (backend != NULL);
+	pk_backend_finished (backend, PK_EXIT_ENUM_FAILED);
+}
+
+/**
+ * backend_search_details:
+ */
+static void
+backend_search_details (PkBackend *backend, const gchar *filter, const gchar *search)
+{
+	g_return_if_fail (backend != NULL);
+	pk_backend_finished (backend, PK_EXIT_ENUM_FAILED);
+}
+
+/**
+ * backend_search_file:
+ */
+static void
+backend_search_file (PkBackend *backend, const gchar *filter, const gchar *search)
+{
+	g_return_if_fail (backend != NULL);
+	pk_backend_finished (backend, PK_EXIT_ENUM_FAILED);
+}
+
+/**
+ * backend_search_group:
+ */
+static void
+backend_search_group (PkBackend *backend, const gchar *filter, const gchar *search)
+{
+	g_return_if_fail (backend != NULL);
+	pk_backend_finished (backend, PK_EXIT_ENUM_FAILED);
+}
+
+/**
+ * backend_search_name:
+ */
+static void
+backend_search_name (PkBackend *backend, const gchar *filter, const gchar *search)
+{
+	g_return_if_fail (backend != NULL);
+	pk_backend_finished (backend, PK_EXIT_ENUM_FAILED);
+}
+
+/**
+ * backend_update_package:
+ */
+static void
+backend_update_package (PkBackend *backend, const gchar *package_id)
+{
+	g_return_if_fail (backend != NULL);
+	pk_backend_finished (backend, PK_EXIT_ENUM_FAILED);
+}
+
+/**
+ * backend_update_system:
+ */
+static void
+backend_update_system (PkBackend *backend)
+{
+	g_return_if_fail (backend != NULL);
+	pk_backend_finished (backend, PK_EXIT_ENUM_FAILED);
+}
+
+PK_BACKEND_OPTIONS (
+	"Test Spawn Backend",			/* description */
+	"0.0.1",				/* version */
+	"Richard Hughes <richard at hughsie.com>",	/* author */
+	backend_initalize,			/* initalize */
+	backend_destroy,			/* destroy */
+	backend_get_groups,			/* get_groups */
+	backend_get_filters,			/* get_filters */
+	backend_cancel_job_try,			/* cancel_job_try */
+	backend_get_depends,			/* get_depends */
+	backend_get_description,		/* get_description */
+	backend_get_requires,			/* get_requires */
+	backend_get_update_detail,		/* get_update_detail */
+	backend_get_updates,			/* get_updates */
+	backend_install_package,		/* install_package */
+	backend_refresh_cache,			/* refresh_cache */
+	backend_remove_package,			/* remove_package */
+	backend_search_details,			/* search_details */
+	backend_search_file,			/* search_file */
+	backend_search_group,			/* search_group */
+	backend_search_name,			/* search_name */
+	backend_update_package,			/* update_package */
+	backend_update_system			/* update_system */
+);
+
diff --git a/backends/test/pk-backend-test-succeed.c b/backends/test/pk-backend-test-succeed.c
new file mode 100644
index 0000000..9fadeee
--- /dev/null
+++ b/backends/test/pk-backend-test-succeed.c
@@ -0,0 +1,247 @@
+/* -*- 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.
+ */
+
+#include <gmodule.h>
+#include <glib.h>
+#include <string.h>
+#include <pk-backend.h>
+
+/**
+ * backend_initalize:
+ */
+static void
+backend_initalize (PkBackend *backend)
+{
+	g_return_if_fail (backend != NULL);
+}
+
+/**
+ * backend_destroy:
+ */
+static void
+backend_destroy (PkBackend *backend)
+{
+	g_return_if_fail (backend != NULL);
+}
+
+/**
+ * backend_get_groups:
+ */
+static void
+backend_get_groups (PkBackend *backend, PkEnumList *elist)
+{
+	g_return_if_fail (backend != NULL);
+	pk_enum_list_append_multiple (elist,
+				      PK_GROUP_ENUM_ACCESSIBILITY,
+				      PK_GROUP_ENUM_GAMES,
+				      PK_GROUP_ENUM_SYSTEM,
+				      -1);
+}
+
+/**
+ * backend_get_filters:
+ */
+static void
+backend_get_filters (PkBackend *backend, PkEnumList *elist)
+{
+	g_return_if_fail (backend != NULL);
+	pk_enum_list_append_multiple (elist,
+				      PK_FILTER_ENUM_GUI,
+				      PK_FILTER_ENUM_INSTALLED,
+				      PK_FILTER_ENUM_DEVELOPMENT,
+				      -1);
+}
+
+/**
+ * backend_cancel_job_try:
+ */
+static void
+backend_cancel_job_try (PkBackend *backend)
+{
+	g_return_if_fail (backend != NULL);
+	pk_backend_finished (backend, PK_EXIT_ENUM_SUCCESS);
+}
+
+/**
+ * backend_get_depends:
+ */
+static void
+backend_get_depends (PkBackend *backend, const gchar *package_id)
+{
+	g_return_if_fail (backend != NULL);
+	pk_backend_finished (backend, PK_EXIT_ENUM_SUCCESS);
+}
+
+/**
+ * backend_get_description:
+ */
+static void
+backend_get_description (PkBackend *backend, const gchar *package_id)
+{
+	g_return_if_fail (backend != NULL);
+	pk_backend_finished (backend, PK_EXIT_ENUM_SUCCESS);
+}
+
+/**
+ * backend_get_requires:
+ */
+static void
+backend_get_requires (PkBackend *backend, const gchar *package_id)
+{
+	g_return_if_fail (backend != NULL);
+	pk_backend_finished (backend, PK_EXIT_ENUM_SUCCESS);
+}
+
+/**
+ * backend_get_update_detail:
+ */
+static void
+backend_get_update_detail (PkBackend *backend, const gchar *package_id)
+{
+	g_return_if_fail (backend != NULL);
+	pk_backend_finished (backend, PK_EXIT_ENUM_SUCCESS);
+}
+
+/**
+ * backend_get_updates:
+ */
+static void
+backend_get_updates (PkBackend *backend)
+{
+	g_return_if_fail (backend != NULL);
+	pk_backend_finished (backend, PK_EXIT_ENUM_SUCCESS);
+}
+
+/**
+ * backend_install_package:
+ */
+static void
+backend_install_package (PkBackend *backend, const gchar *package_id)
+{
+	g_return_if_fail (backend != NULL);
+	pk_backend_finished (backend, PK_EXIT_ENUM_SUCCESS);
+}
+
+/**
+ * backend_refresh_cache:
+ */
+static void
+backend_refresh_cache (PkBackend *backend, gboolean force)
+{
+	g_return_if_fail (backend != NULL);
+	pk_backend_finished (backend, PK_EXIT_ENUM_SUCCESS);
+}
+
+/**
+ * backend_remove_package:
+ */
+static void
+backend_remove_package (PkBackend *backend, const gchar *package_id, gboolean allow_deps)
+{
+	g_return_if_fail (backend != NULL);
+	pk_backend_finished (backend, PK_EXIT_ENUM_SUCCESS);
+}
+
+/**
+ * backend_search_details:
+ */
+static void
+backend_search_details (PkBackend *backend, const gchar *filter, const gchar *search)
+{
+	g_return_if_fail (backend != NULL);
+	pk_backend_finished (backend, PK_EXIT_ENUM_SUCCESS);
+}
+
+/**
+ * backend_search_file:
+ */
+static void
+backend_search_file (PkBackend *backend, const gchar *filter, const gchar *search)
+{
+	g_return_if_fail (backend != NULL);
+	pk_backend_finished (backend, PK_EXIT_ENUM_SUCCESS);
+}
+
+/**
+ * backend_search_group:
+ */
+static void
+backend_search_group (PkBackend *backend, const gchar *filter, const gchar *search)
+{
+	g_return_if_fail (backend != NULL);
+	pk_backend_finished (backend, PK_EXIT_ENUM_SUCCESS);
+}
+
+/**
+ * backend_search_name:
+ */
+static void
+backend_search_name (PkBackend *backend, const gchar *filter, const gchar *search)
+{
+	g_return_if_fail (backend != NULL);
+	pk_backend_finished (backend, PK_EXIT_ENUM_SUCCESS);
+}
+
+/**
+ * backend_update_package:
+ */
+static void
+backend_update_package (PkBackend *backend, const gchar *package_id)
+{
+	g_return_if_fail (backend != NULL);
+	pk_backend_finished (backend, PK_EXIT_ENUM_SUCCESS);
+}
+
+/**
+ * backend_update_system:
+ */
+static void
+backend_update_system (PkBackend *backend)
+{
+	g_return_if_fail (backend != NULL);
+	pk_backend_finished (backend, PK_EXIT_ENUM_SUCCESS);
+}
+
+PK_BACKEND_OPTIONS (
+	"Test Succeed Backend",			/* description */
+	"0.0.1",				/* version */
+	"Richard Hughes <richard at hughsie.com>",	/* author */
+	backend_initalize,			/* initalize */
+	backend_destroy,			/* destroy */
+	backend_get_groups,			/* get_groups */
+	backend_get_filters,			/* get_filters */
+	backend_cancel_job_try,			/* cancel_job_try */
+	backend_get_depends,			/* get_depends */
+	backend_get_description,		/* get_description */
+	backend_get_requires,			/* get_requires */
+	backend_get_update_detail,		/* get_update_detail */
+	backend_get_updates,			/* get_updates */
+	backend_install_package,		/* install_package */
+	backend_refresh_cache,			/* refresh_cache */
+	backend_remove_package,			/* remove_package */
+	backend_search_details,			/* search_details */
+	backend_search_file,			/* search_file */
+	backend_search_group,			/* search_group */
+	backend_search_name,			/* search_name */
+	backend_update_package,			/* update_package */
+	backend_update_system			/* update_system */
+);
+
diff --git a/backends/test/pk-backend-test-thread.c b/backends/test/pk-backend-test-thread.c
new file mode 100644
index 0000000..38ef5e7
--- /dev/null
+++ b/backends/test/pk-backend-test-thread.c
@@ -0,0 +1,247 @@
+/* -*- 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.
+ */
+
+#include <gmodule.h>
+#include <glib.h>
+#include <string.h>
+#include <pk-backend.h>
+
+/**
+ * backend_initalize:
+ */
+static void
+backend_initalize (PkBackend *backend)
+{
+	g_return_if_fail (backend != NULL);
+}
+
+/**
+ * backend_destroy:
+ */
+static void
+backend_destroy (PkBackend *backend)
+{
+	g_return_if_fail (backend != NULL);
+}
+
+/**
+ * backend_get_groups:
+ */
+static void
+backend_get_groups (PkBackend *backend, PkEnumList *elist)
+{
+	g_return_if_fail (backend != NULL);
+	pk_enum_list_append_multiple (elist,
+				      PK_GROUP_ENUM_ACCESSIBILITY,
+				      PK_GROUP_ENUM_GAMES,
+				      PK_GROUP_ENUM_SYSTEM,
+				      -1);
+}
+
+/**
+ * backend_get_filters:
+ */
+static void
+backend_get_filters (PkBackend *backend, PkEnumList *elist)
+{
+	g_return_if_fail (backend != NULL);
+	pk_enum_list_append_multiple (elist,
+				      PK_FILTER_ENUM_GUI,
+				      PK_FILTER_ENUM_INSTALLED,
+				      PK_FILTER_ENUM_DEVELOPMENT,
+				      -1);
+}
+
+/**
+ * backend_cancel_job_try:
+ */
+static void
+backend_cancel_job_try (PkBackend *backend)
+{
+	g_return_if_fail (backend != NULL);
+	pk_backend_finished (backend, PK_EXIT_ENUM_FAILED);
+}
+
+/**
+ * backend_get_depends:
+ */
+static void
+backend_get_depends (PkBackend *backend, const gchar *package_id)
+{
+	g_return_if_fail (backend != NULL);
+	pk_backend_finished (backend, PK_EXIT_ENUM_FAILED);
+}
+
+/**
+ * backend_get_description:
+ */
+static void
+backend_get_description (PkBackend *backend, const gchar *package_id)
+{
+	g_return_if_fail (backend != NULL);
+	pk_backend_finished (backend, PK_EXIT_ENUM_FAILED);
+}
+
+/**
+ * backend_get_requires:
+ */
+static void
+backend_get_requires (PkBackend *backend, const gchar *package_id)
+{
+	g_return_if_fail (backend != NULL);
+	pk_backend_finished (backend, PK_EXIT_ENUM_FAILED);
+}
+
+/**
+ * backend_get_update_detail:
+ */
+static void
+backend_get_update_detail (PkBackend *backend, const gchar *package_id)
+{
+	g_return_if_fail (backend != NULL);
+	pk_backend_finished (backend, PK_EXIT_ENUM_FAILED);
+}
+
+/**
+ * backend_get_updates:
+ */
+static void
+backend_get_updates (PkBackend *backend)
+{
+	g_return_if_fail (backend != NULL);
+	pk_backend_finished (backend, PK_EXIT_ENUM_FAILED);
+}
+
+/**
+ * backend_install_package:
+ */
+static void
+backend_install_package (PkBackend *backend, const gchar *package_id)
+{
+	g_return_if_fail (backend != NULL);
+	pk_backend_finished (backend, PK_EXIT_ENUM_FAILED);
+}
+
+/**
+ * backend_refresh_cache:
+ */
+static void
+backend_refresh_cache (PkBackend *backend, gboolean force)
+{
+	g_return_if_fail (backend != NULL);
+	pk_backend_finished (backend, PK_EXIT_ENUM_FAILED);
+}
+
+/**
+ * backend_remove_package:
+ */
+static void
+backend_remove_package (PkBackend *backend, const gchar *package_id, gboolean allow_deps)
+{
+	g_return_if_fail (backend != NULL);
+	pk_backend_finished (backend, PK_EXIT_ENUM_FAILED);
+}
+
+/**
+ * backend_search_details:
+ */
+static void
+backend_search_details (PkBackend *backend, const gchar *filter, const gchar *search)
+{
+	g_return_if_fail (backend != NULL);
+	pk_backend_finished (backend, PK_EXIT_ENUM_FAILED);
+}
+
+/**
+ * backend_search_file:
+ */
+static void
+backend_search_file (PkBackend *backend, const gchar *filter, const gchar *search)
+{
+	g_return_if_fail (backend != NULL);
+	pk_backend_finished (backend, PK_EXIT_ENUM_FAILED);
+}
+
+/**
+ * backend_search_group:
+ */
+static void
+backend_search_group (PkBackend *backend, const gchar *filter, const gchar *search)
+{
+	g_return_if_fail (backend != NULL);
+	pk_backend_finished (backend, PK_EXIT_ENUM_FAILED);
+}
+
+/**
+ * backend_search_name:
+ */
+static void
+backend_search_name (PkBackend *backend, const gchar *filter, const gchar *search)
+{
+	g_return_if_fail (backend != NULL);
+	pk_backend_finished (backend, PK_EXIT_ENUM_FAILED);
+}
+
+/**
+ * backend_update_package:
+ */
+static void
+backend_update_package (PkBackend *backend, const gchar *package_id)
+{
+	g_return_if_fail (backend != NULL);
+	pk_backend_finished (backend, PK_EXIT_ENUM_FAILED);
+}
+
+/**
+ * backend_update_system:
+ */
+static void
+backend_update_system (PkBackend *backend)
+{
+	g_return_if_fail (backend != NULL);
+	pk_backend_finished (backend, PK_EXIT_ENUM_FAILED);
+}
+
+PK_BACKEND_OPTIONS (
+	"Test Thread Backend",			/* description */
+	"0.0.1",				/* version */
+	"Richard Hughes <richard at hughsie.com>",	/* author */
+	backend_initalize,			/* initalize */
+	backend_destroy,			/* destroy */
+	backend_get_groups,			/* get_groups */
+	backend_get_filters,			/* get_filters */
+	backend_cancel_job_try,			/* cancel_job_try */
+	backend_get_depends,			/* get_depends */
+	backend_get_description,		/* get_description */
+	backend_get_requires,			/* get_requires */
+	backend_get_update_detail,		/* get_update_detail */
+	backend_get_updates,			/* get_updates */
+	backend_install_package,		/* install_package */
+	backend_refresh_cache,			/* refresh_cache */
+	backend_remove_package,			/* remove_package */
+	backend_search_details,			/* search_details */
+	backend_search_file,			/* search_file */
+	backend_search_group,			/* search_group */
+	backend_search_name,			/* search_name */
+	backend_update_package,			/* update_package */
+	backend_update_system			/* update_system */
+);
+
diff --git a/backends/test/pk-backend-test.c b/backends/test/pk-backend-test.c
deleted file mode 100644
index 9d70cc8..0000000
--- a/backends/test/pk-backend-test.c
+++ /dev/null
@@ -1,247 +0,0 @@
-/* -*- 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.
- */
-
-#include <gmodule.h>
-#include <glib.h>
-#include <string.h>
-#include <pk-backend.h>
-
-/**
- * backend_initalize:
- */
-static void
-backend_initalize (PkBackend *backend)
-{
-	g_return_if_fail (backend != NULL);
-}
-
-/**
- * backend_destroy:
- */
-static void
-backend_destroy (PkBackend *backend)
-{
-	g_return_if_fail (backend != NULL);
-}
-
-/**
- * backend_get_groups:
- */
-static void
-backend_get_groups (PkBackend *backend, PkEnumList *elist)
-{
-	g_return_if_fail (backend != NULL);
-	pk_enum_list_append_multiple (elist,
-				      PK_GROUP_ENUM_ACCESSIBILITY,
-				      PK_GROUP_ENUM_GAMES,
-				      PK_GROUP_ENUM_SYSTEM,
-				      -1);
-}
-
-/**
- * backend_get_filters:
- */
-static void
-backend_get_filters (PkBackend *backend, PkEnumList *elist)
-{
-	g_return_if_fail (backend != NULL);
-	pk_enum_list_append_multiple (elist,
-				      PK_FILTER_ENUM_GUI,
-				      PK_FILTER_ENUM_INSTALLED,
-				      PK_FILTER_ENUM_DEVELOPMENT,
-				      -1);
-}
-
-/**
- * backend_cancel_job_try:
- */
-static void
-backend_cancel_job_try (PkBackend *backend)
-{
-	g_return_if_fail (backend != NULL);
-	pk_backend_finished (backend, PK_EXIT_ENUM_FAILED);
-}
-
-/**
- * backend_get_depends:
- */
-static void
-backend_get_depends (PkBackend *backend, const gchar *package_id)
-{
-	g_return_if_fail (backend != NULL);
-	pk_backend_finished (backend, PK_EXIT_ENUM_FAILED);
-}
-
-/**
- * backend_get_description:
- */
-static void
-backend_get_description (PkBackend *backend, const gchar *package_id)
-{
-	g_return_if_fail (backend != NULL);
-	pk_backend_finished (backend, PK_EXIT_ENUM_FAILED);
-}
-
-/**
- * backend_get_requires:
- */
-static void
-backend_get_requires (PkBackend *backend, const gchar *package_id)
-{
-	g_return_if_fail (backend != NULL);
-	pk_backend_finished (backend, PK_EXIT_ENUM_FAILED);
-}
-
-/**
- * backend_get_update_detail:
- */
-static void
-backend_get_update_detail (PkBackend *backend, const gchar *package_id)
-{
-	g_return_if_fail (backend != NULL);
-	pk_backend_finished (backend, PK_EXIT_ENUM_FAILED);
-}
-
-/**
- * backend_get_updates:
- */
-static void
-backend_get_updates (PkBackend *backend)
-{
-	g_return_if_fail (backend != NULL);
-	pk_backend_finished (backend, PK_EXIT_ENUM_FAILED);
-}
-
-/**
- * backend_install_package:
- */
-static void
-backend_install_package (PkBackend *backend, const gchar *package_id)
-{
-	g_return_if_fail (backend != NULL);
-	pk_backend_finished (backend, PK_EXIT_ENUM_FAILED);
-}
-
-/**
- * backend_refresh_cache:
- */
-static void
-backend_refresh_cache (PkBackend *backend, gboolean force)
-{
-	g_return_if_fail (backend != NULL);
-	pk_backend_finished (backend, PK_EXIT_ENUM_FAILED);
-}
-
-/**
- * backend_remove_package:
- */
-static void
-backend_remove_package (PkBackend *backend, const gchar *package_id, gboolean allow_deps)
-{
-	g_return_if_fail (backend != NULL);
-	pk_backend_finished (backend, PK_EXIT_ENUM_FAILED);
-}
-
-/**
- * backend_search_details:
- */
-static void
-backend_search_details (PkBackend *backend, const gchar *filter, const gchar *search)
-{
-	g_return_if_fail (backend != NULL);
-	pk_backend_finished (backend, PK_EXIT_ENUM_FAILED);
-}
-
-/**
- * backend_search_file:
- */
-static void
-backend_search_file (PkBackend *backend, const gchar *filter, const gchar *search)
-{
-	g_return_if_fail (backend != NULL);
-	pk_backend_finished (backend, PK_EXIT_ENUM_FAILED);
-}
-
-/**
- * backend_search_group:
- */
-static void
-backend_search_group (PkBackend *backend, const gchar *filter, const gchar *search)
-{
-	g_return_if_fail (backend != NULL);
-	pk_backend_finished (backend, PK_EXIT_ENUM_FAILED);
-}
-
-/**
- * backend_search_name:
- */
-static void
-backend_search_name (PkBackend *backend, const gchar *filter, const gchar *search)
-{
-	g_return_if_fail (backend != NULL);
-	pk_backend_finished (backend, PK_EXIT_ENUM_FAILED);
-}
-
-/**
- * backend_update_package:
- */
-static void
-backend_update_package (PkBackend *backend, const gchar *package_id)
-{
-	g_return_if_fail (backend != NULL);
-	pk_backend_finished (backend, PK_EXIT_ENUM_FAILED);
-}
-
-/**
- * backend_update_system:
- */
-static void
-backend_update_system (PkBackend *backend)
-{
-	g_return_if_fail (backend != NULL);
-	pk_backend_finished (backend, PK_EXIT_ENUM_FAILED);
-}
-
-PK_BACKEND_OPTIONS (
-	"Test Backend",				/* description */
-	"0.0.1",				/* version */
-	"Richard Hughes <richard at hughsie.com>",	/* author */
-	backend_initalize,			/* initalize */
-	backend_destroy,			/* destroy */
-	backend_get_groups,			/* get_groups */
-	backend_get_filters,			/* get_filters */
-	backend_cancel_job_try,			/* cancel_job_try */
-	backend_get_depends,			/* get_depends */
-	backend_get_description,		/* get_description */
-	backend_get_requires,			/* get_requires */
-	backend_get_update_detail,		/* get_update_detail */
-	backend_get_updates,			/* get_updates */
-	backend_install_package,		/* install_package */
-	backend_refresh_cache,			/* refresh_cache */
-	backend_remove_package,			/* remove_package */
-	backend_search_details,			/* search_details */
-	backend_search_file,			/* search_file */
-	backend_search_group,			/* search_group */
-	backend_search_name,			/* search_name */
-	backend_update_package,			/* update_package */
-	backend_update_system			/* update_system */
-);
-
diff-tree d7fa52fc14d60c8c664230d3ad9d77d83fd3e654 (from 468d8d360a7887de2cd981e3df01ac2ef59241b4)
Author: Richard Hughes <richard at hughsie.com>
Date:   Sun Sep 16 20:30:51 2007 +0100

    emit the role, not the status from the finished task list enetry

diff --git a/libpackagekit/pk-task-list.c b/libpackagekit/pk-task-list.c
index added1f..3a2dc78 100644
--- a/libpackagekit/pk-task-list.c
+++ b/libpackagekit/pk-task-list.c
@@ -153,8 +153,8 @@ pk_task_list_job_finished_cb (PkTaskMoni
 	/* get correct item */
 	item = pk_task_list_find_existing_job (tlist, job);
 
-	pk_debug ("emit task-list-finished %i, %s, %i", item->status, item->package_id, runtime);
-	g_signal_emit (tlist , signals [PK_TASK_LIST_FINISHED], 0, item->status, item->package_id, runtime);
+	pk_debug ("emit task-list-finished %i, %s, %i", item->role, item->package_id, runtime);
+	g_signal_emit (tlist , signals [PK_TASK_LIST_FINISHED], 0, item->role, item->package_id, runtime);
 }
 
 /**
diff-tree 468d8d360a7887de2cd981e3df01ac2ef59241b4 (from e2933b35d42cd961f6926b6521a40f181b2f8a3a)
Author: Richard Hughes <richard at hughsie.com>
Date:   Sun Sep 16 19:53:28 2007 +0100

    use the right enum type when printing status to the screen

diff --git a/libpackagekit/pk-task-list.c b/libpackagekit/pk-task-list.c
index 90afdc2..added1f 100644
--- a/libpackagekit/pk-task-list.c
+++ b/libpackagekit/pk-task-list.c
@@ -85,7 +85,7 @@ pk_task_list_print (PkTaskList *tlist)
 	}
 	for (i=0; i<length; i++) {
 		item = g_ptr_array_index (tlist->priv->task_list, i);
-		g_print ("%i %s %s", item->job, pk_status_enum_to_text (item->role), item->package_id);
+		g_print ("%i %s %s", item->job, pk_role_enum_to_text (item->role), item->package_id);
 	}
 	g_print ("\n");
 	return TRUE;
diff-tree e2933b35d42cd961f6926b6521a40f181b2f8a3a (from 07bf254860be0593f0787fe46c43163469ffb56f)
Author: Richard Hughes <richard at hughsie.com>
Date:   Sun Sep 16 19:47:50 2007 +0100

    make the job-list code refresh at startup. This fixes a typo that makes pkmon work again

diff --git a/client/pk-monitor.c b/client/pk-monitor.c
index 05178fd..e2d9637 100644
--- a/client/pk-monitor.c
+++ b/client/pk-monitor.c
@@ -98,6 +98,7 @@ main (int argc, char *argv[])
 	g_signal_connect (tlist, "error-code",
 			  G_CALLBACK (pk_monitor_error_code_cb), NULL);
 
+	pk_debug ("refreshing task list");
 	ret = pk_task_list_refresh (tlist);
 	if (ret == FALSE) {
 		g_error ("cannot refresh job list");
diff --git a/libpackagekit/pk-job-list.c b/libpackagekit/pk-job-list.c
index e4e8117..27e4e8a 100644
--- a/libpackagekit/pk-job-list.c
+++ b/libpackagekit/pk-job-list.c
@@ -249,6 +249,8 @@ pk_job_list_init (PkJobList *jlist)
 			  G_CALLBACK (pk_connection_changed_cb), jlist);
 	if (pk_connection_valid (jlist->priv->pconnection)) {
 		pk_job_list_connect (jlist);
+	} else {
+		pk_warning ("no PK instance on the bus");
 	}
 
 	/* get a connection */
@@ -269,7 +271,7 @@ pk_job_list_init (PkJobList *jlist)
 				     G_CALLBACK(pk_job_list_changed_cb), jlist, NULL);
 
 	/* force a refresh so we have valid data*/
-	pk_job_list_get_latest (jlist);
+	pk_job_list_refresh (jlist);
 }
 
 /**
diff-tree cc438e642f632255afddf146dbd5464bd29a91b0 (from parents)
Merge: 01a765be7538f38d7323054f1a5b68a83cb40b9c ee702d2d54b5246ba1c9790fe850249153d42463
Author: Andreas Obergrusberger <tradiaz at yahoo.de>
Date:   Sat Sep 15 19:16:27 2007 +0200

    Merge branch 'master' of git+ssh://tradiaz@git.packagekit.org/srv/git/PackageKit

diff-tree 01a765be7538f38d7323054f1a5b68a83cb40b9c (from 50ff8b87380340ddfae50be68239f1b2d06116e3)
Author: Andreas Obergrusberger <tradiaz at yahoo.de>
Date:   Sat Sep 15 19:15:27 2007 +0200

    implemented backend_install_package for alpm

diff --git a/backends/BACKENDS b/backends/BACKENDS
index 9f8602a..6127b53 100644
--- a/backends/BACKENDS
+++ b/backends/BACKENDS
@@ -9,7 +9,7 @@ search-name       |   X    |  X  |  X  |
 search-details    |        |  X  |  X  |  X  |      |
 search-file       |        |  X  |     |  X  |      |
 search-group      |        |     |     |     |      |
-install           |        |  X  |     |  X  |      |
+install           |        |  X  |     |  X  |  X   |
 remove            |        |  X  |     |  X  |  X   |
 get-depends       |        |  X  |     |     |      |
 get-requires      |        |     |     |     |      |
diff --git a/backends/alpm/TODO b/backends/alpm/TODO
new file mode 100644
index 0000000..04a827f
--- /dev/null
+++ b/backends/alpm/TODO
@@ -0,0 +1,4 @@
+
+* Fix cache refreshing. Currently throws 'unexpected error'
+* Improve error handling by using macros. Currently 50% is very similiar error handling code.
+* Handle transaction progress and events in the callback functions.
diff --git a/backends/alpm/pk-backend-alpm.c b/backends/alpm/pk-backend-alpm.c
index d98ab19..a6f8e8c 100644
--- a/backends/alpm/pk-backend-alpm.c
+++ b/backends/alpm/pk-backend-alpm.c
@@ -148,6 +148,18 @@ pkg_equal (pmpkg_t *p1, pmpkg_t *p2)
   return TRUE;
 }
 
+gboolean
+pkg_equals_to (pmpkg_t *pkg, const gchar *name, const gchar *version)
+{
+  if (strcmp (alpm_pkg_get_name (pkg), name) != 0)
+    return FALSE;
+  if (version != NULL)
+    if (strcmp (alpm_pkg_get_version (pkg), version) != 0)
+      return FALSE;
+  return TRUE;
+}
+
+
 alpm_list_t *
 my_list_remove_node (alpm_list_t *node)
 {
@@ -419,31 +431,96 @@ backend_get_updates (PkBackend *backend)
 	pk_backend_finished (backend, PK_EXIT_ENUM_SUCCESS);
 }
 
-static gboolean
-backend_install_timeout (gpointer data)
-{
-	PkBackend *backend = (PkBackend *) data;
-	if (progress_percentage == 100) {
-		pk_backend_finished (backend, PK_EXIT_ENUM_SUCCESS);
-		return FALSE;
-	}
-	if (progress_percentage == 50) {
-		pk_backend_change_job_status (backend, PK_STATUS_ENUM_INSTALL);
-	}
-	progress_percentage += 10;
-	pk_backend_change_percentage (backend, progress_percentage);
-	return TRUE;
-}
-
 /**
  * backend_install_package:
  */
 static void
 backend_install_package (PkBackend *backend, const gchar *package_id)
 {
-	g_return_if_fail (backend != NULL);
-	progress_percentage = 0;
-	g_timeout_add (1000, backend_install_timeout, backend);
+  g_return_if_fail (backend != NULL);
+  //alpm_list_t *syncdbs = alpm_option_get_syncdbs ();
+  alpm_list_t *result = NULL;
+  alpm_list_t *problems = NULL;
+  PkPackageId *id = pk_package_id_new_from_string (package_id);
+  pmtransflag_t flags = 0;
+
+  flags |= PM_TRANS_FLAG_NODEPS;
+
+  // Next generation code?
+  /*for (; syncdbs; syncdbs = alpm_list_next (syncdbs))
+    result = my_list_mmerge (result, find_packages (id->name, (pmdb_t *)syncdbs->data), list_cmp_fn);
+
+  if (result == NULL)
+    {
+      pk_backend_error_code (backend,
+			     PK_ERROR_ENUM_PACKAGE_ID_INVALID,
+			     "Package not found");
+      pk_backend_finished (backend, PK_EXIT_ENUM_FAILED);
+      alpm_list_free (result);
+      alpm_list_free (syncdbs);
+      pk_package_id_free (id);
+      return;
+    }
+
+  for (; result; result = alpm_list_next (result))
+    if (pkg_equals_to ((pmpkg_t *)result->data, id->name, id->version))
+      break;
+
+  if (!result)
+    {
+      pk_backend_error_code (backend,
+			     PK_ERROR_ENUM_PACKAGE_ID_INVALID,
+			     "Package not found");
+      pk_backend_finished (backend, PK_EXIT_ENUM_FAILED);
+      alpm_list_free (result);
+      alpm_list_free (syncdbs);
+      pk_package_id_free (id);
+      return;
+    }*/
+
+  if (alpm_trans_init (PM_TRANS_TYPE_SYNC, flags,
+		       trans_event_cb, trans_conv_cb,
+		       trans_prog_cb) == -1)
+    {
+      pk_backend_error_code (backend,
+			     PK_ERROR_ENUM_TRANSACTION_ERROR,
+			     alpm_strerror (pm_errno));
+      pk_backend_finished (backend, PK_EXIT_ENUM_FAILED);
+      alpm_list_free (result);
+      pk_package_id_free (id);
+      return;
+    }
+
+  alpm_trans_addtarget (id->name);
+
+  if (alpm_trans_prepare (&problems) != 0)
+    {
+      pk_backend_error_code (backend,
+			     PK_ERROR_ENUM_TRANSACTION_ERROR,
+			     alpm_strerror (pm_errno));
+      pk_backend_finished (backend, PK_EXIT_ENUM_FAILED);
+      alpm_trans_release ();
+      alpm_list_free (result);
+      pk_package_id_free (id);
+      return;
+    }
+
+  if (alpm_trans_commit (&problems) != 0)
+    {
+      pk_backend_error_code (backend,
+			     PK_ERROR_ENUM_TRANSACTION_ERROR,
+			     alpm_strerror (pm_errno));
+      pk_backend_finished (backend, PK_EXIT_ENUM_FAILED);
+      alpm_trans_release ();
+      alpm_list_free (result);
+      pk_package_id_free (id);
+      return;
+    }
+
+  alpm_trans_release ();
+  alpm_list_free (result);
+  pk_package_id_free (id);
+  pk_backend_finished (backend, PK_EXIT_ENUM_SUCCESS);
 }
 
 /**
@@ -518,6 +595,7 @@ backend_remove_package (PkBackend *backe
 				  PK_ERROR_ENUM_PACKAGE_NOT_INSTALLED,
 				  "Package is not installed");
 	    pk_backend_finished (backend, PK_EXIT_ENUM_FAILED);
+	    pk_package_id_free (id);
 	    return;
 	  }
 	else if (alpm_list_count (result) != 1 || 
@@ -528,6 +606,8 @@ backend_remove_package (PkBackend *backe
 				  "Package is not installed");
 	    alpm_list_free_inner (result, (alpm_list_fn_free)package_source_free);
 	    pk_backend_finished (backend, PK_EXIT_ENUM_FAILED);
+	    pk_package_id_free (id);
+	    alpm_list_free (result);
 	    return;
 	  }
 
@@ -541,6 +621,8 @@ backend_remove_package (PkBackend *backe
 				  PK_ERROR_ENUM_TRANSACTION_ERROR,
 				  alpm_strerror (pm_errno));
 	    pk_backend_finished (backend, PK_EXIT_ENUM_FAILED);
+	    alpm_list_free (result);
+	    pk_package_id_free (id);
 	    return;
 	  }
 
@@ -553,6 +635,8 @@ backend_remove_package (PkBackend *backe
 				  alpm_strerror (pm_errno));
 	    pk_backend_finished (backend, PK_EXIT_ENUM_FAILED);
 	    alpm_trans_release ();
+	    alpm_list_free (result);
+	    pk_package_id_free (id);
 	    return;
 	  }
 
@@ -563,8 +647,13 @@ backend_remove_package (PkBackend *backe
 				  alpm_strerror (pm_errno));
 	    pk_backend_finished (backend, PK_EXIT_ENUM_FAILED);
 	    alpm_trans_release ();
+	    alpm_list_free (result);
+	    pk_package_id_free (id);
 	    return;
 	  }
+
+	alpm_list_free (result);
+	pk_package_id_free (id);
 	alpm_trans_release ();
 	pk_backend_finished (backend, PK_EXIT_ENUM_SUCCESS);
 }
diff-tree ee702d2d54b5246ba1c9790fe850249153d42463 (from 50ff8b87380340ddfae50be68239f1b2d06116e3)
Author: Grzegorz Dabrowski <gdx at o2.pl>
Date:   Sat Sep 15 17:08:39 2007 +0000

    [box] added basic update package support

diff --git a/backends/box/helpers/Makefile.am b/backends/box/helpers/Makefile.am
index 1851df4..2a5a440 100644
--- a/backends/box/helpers/Makefile.am
+++ b/backends/box/helpers/Makefile.am
@@ -7,6 +7,7 @@ dist_helper_DATA = 			\
 	install-package.sh		\
 	refresh-cache.sh		\
 	remove-package.sh		\
+	update-package.sh		\
 	$(NULL)
 
 install-data-hook:
diff --git a/backends/box/helpers/update-package.sh b/backends/box/helpers/update-package.sh
new file mode 100644
index 0000000..913b69e
--- /dev/null
+++ b/backends/box/helpers/update-package.sh
@@ -0,0 +1,15 @@
+#!/bin/sh
+#
+# Copyright (C) 2007 Grzegorz Dabrowski <gdx at o2.pl>
+#
+# 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.
+
+echo "no-percentage-updates" > /dev/stderr
+echo "status	update" > /dev/stderr
+pkg=$(echo "$1" | cut -f1 -d';')
+box -i "$pkg" 2>&1 >/dev/null
diff --git a/backends/box/pk-backend-box.c b/backends/box/pk-backend-box.c
index ba535c0..f13a65a 100644
--- a/backends/box/pk-backend-box.c
+++ b/backends/box/pk-backend-box.c
@@ -411,14 +411,14 @@ backend_get_updates (PkBackend *backend)
 static void
 backend_install_package (PkBackend *backend, const gchar *package_id)
 {
-        g_return_if_fail (backend != NULL);
-        /* check network state */
-        if (pk_backend_network_is_online (backend) == FALSE) {
-                pk_backend_error_code (backend, PK_ERROR_ENUM_NO_NETWORK, "Cannot install when offline");
-                pk_backend_finished (backend, PK_EXIT_ENUM_FAILED);
-                return;
-        }
-        pk_backend_spawn_helper (backend, "install-package.sh", package_id, NULL);
+	g_return_if_fail (backend != NULL);
+	/* check network state */
+	if (pk_backend_network_is_online (backend) == FALSE) {
+		pk_backend_error_code (backend, PK_ERROR_ENUM_NO_NETWORK, "Cannot install when offline");
+		pk_backend_finished (backend, PK_EXIT_ENUM_FAILED);
+		return;
+	}
+	pk_backend_spawn_helper (backend, "install-package.sh", package_id, NULL);
 }
 
 /**
@@ -444,14 +444,14 @@ backend_refresh_cache (PkBackend *backen
 static void
 backend_remove_package (PkBackend *backend, const gchar *package_id, gboolean allow_deps)
 {
-        g_return_if_fail (backend != NULL);
-        const gchar *deps;
-        if (allow_deps == TRUE) {
-                deps = "yes";
-        } else {
-                deps = "no";
-        }
-        pk_backend_spawn_helper (backend, "remove-package.sh", deps, package_id, NULL);
+	g_return_if_fail (backend != NULL);
+	const gchar *deps;
+	if (allow_deps == TRUE) {
+		deps = "yes";
+	} else {
+		deps = "no";
+	}
+	pk_backend_spawn_helper (backend, "remove-package.sh", deps, package_id, NULL);
 }
 
 
@@ -485,6 +485,23 @@ backend_search_name (PkBackend *backend,
 	find_packages (backend, search, filter, SEARCH_TYPE_NAME);
 }
 
+/**
+ * backend_update_package:
+ */
+static void
+backend_update_package (PkBackend *backend, const gchar *package_id)
+{
+	g_return_if_fail (backend != NULL);
+	/* check network state */
+	if (pk_backend_network_is_online (backend) == FALSE) {
+		pk_backend_error_code (backend, PK_ERROR_ENUM_NO_NETWORK, "Cannot update when offline");
+		pk_backend_finished (backend, PK_EXIT_ENUM_FAILED);
+		return;
+	}
+	pk_backend_spawn_helper (backend, "update-package.sh", package_id, NULL);
+}
+
+
 PK_BACKEND_OPTIONS (
 	"Box Backend",				/* description */
 	"0.0.1",				/* version */
@@ -506,7 +523,7 @@ PK_BACKEND_OPTIONS (
 	backend_search_file,			/* search_file */
 	NULL,					/* search_group */
 	backend_search_name,			/* search_name */
-	NULL,					/* update_package */
+	backend_update_package,			/* update_package */
 	NULL					/* update_system */
 );
 
diff-tree 50ff8b87380340ddfae50be68239f1b2d06116e3 (from cb0e08dc930c86b53b056f35b136d387b8e45af9)
Author: Andreas Obergrusberger <tradiaz at yahoo.de>
Date:   Sat Sep 15 15:01:05 2007 +0200

    remove debug lines

diff --git a/backends/alpm/pk-backend-alpm.c b/backends/alpm/pk-backend-alpm.c
index f9041f3..d98ab19 100644
--- a/backends/alpm/pk-backend-alpm.c
+++ b/backends/alpm/pk-backend-alpm.c
@@ -505,14 +505,12 @@ backend_refresh_cache (PkBackend *backen
 static void
 backend_remove_package (PkBackend *backend, const gchar *package_id, gboolean allow_deps)
 {
-  	pk_debug ("I am %i", (int)backend);
 	g_return_if_fail (backend != NULL);
 	PkPackageId *id = pk_package_id_new_from_string (package_id);
 	pmdb_t *localdb = alpm_option_get_localdb ();
 	alpm_list_t *result = find_packages (id->name, localdb);
 	pmtransflag_t flags = 0;
 	alpm_list_t *problems = NULL;
-	pk_debug ("I'm not null");
 
 	if (result == NULL)
 	  {
diff-tree cb0e08dc930c86b53b056f35b136d387b8e45af9 (from 07bf254860be0593f0787fe46c43163469ffb56f)
Author: Andreas Obergrusberger <tradiaz at yahoo.de>
Date:   Sat Sep 15 14:55:05 2007 +0200

    add backend_remove_package to alpm

diff --git a/backends/BACKENDS b/backends/BACKENDS
index 7401a64..9f8602a 100644
--- a/backends/BACKENDS
+++ b/backends/BACKENDS
@@ -10,7 +10,7 @@ search-details    |        |  X  |  X  |
 search-file       |        |  X  |     |  X  |      |
 search-group      |        |     |     |     |      |
 install           |        |  X  |     |  X  |      |
-remove            |        |  X  |     |  X  |      |
+remove            |        |  X  |     |  X  |  X   |
 get-depends       |        |  X  |     |     |      |
 get-requires      |        |     |     |     |      |
 get-description   |   X    |  X  |  X  |  X  |      |
diff --git a/backends/alpm/pk-backend-alpm.c b/backends/alpm/pk-backend-alpm.c
index 6f0ea1f..f9041f3 100644
--- a/backends/alpm/pk-backend-alpm.c
+++ b/backends/alpm/pk-backend-alpm.c
@@ -505,9 +505,70 @@ backend_refresh_cache (PkBackend *backen
 static void
 backend_remove_package (PkBackend *backend, const gchar *package_id, gboolean allow_deps)
 {
+  	pk_debug ("I am %i", (int)backend);
 	g_return_if_fail (backend != NULL);
-	pk_backend_error_code (backend, PK_ERROR_ENUM_NO_NETWORK, "No network connection available");
-	pk_backend_finished (backend, PK_EXIT_ENUM_FAILED);
+	PkPackageId *id = pk_package_id_new_from_string (package_id);
+	pmdb_t *localdb = alpm_option_get_localdb ();
+	alpm_list_t *result = find_packages (id->name, localdb);
+	pmtransflag_t flags = 0;
+	alpm_list_t *problems = NULL;
+	pk_debug ("I'm not null");
+
+	if (result == NULL)
+	  {
+	    pk_backend_error_code (backend,
+				  PK_ERROR_ENUM_PACKAGE_NOT_INSTALLED,
+				  "Package is not installed");
+	    pk_backend_finished (backend, PK_EXIT_ENUM_FAILED);
+	    return;
+	  }
+	else if (alpm_list_count (result) != 1 || 
+		 strcmp (alpm_pkg_get_name(((PackageSource *)result->data)->pkg), id->name) != 0)
+	  {	    
+	    pk_backend_error_code (backend,
+				  PK_ERROR_ENUM_PACKAGE_NOT_INSTALLED,
+				  "Package is not installed");
+	    alpm_list_free_inner (result, (alpm_list_fn_free)package_source_free);
+	    pk_backend_finished (backend, PK_EXIT_ENUM_FAILED);
+	    return;
+	  }
+
+	if (allow_deps) flags |= PM_TRANS_FLAG_CASCADE;
+
+	if (alpm_trans_init (PM_TRANS_TYPE_REMOVE, flags,
+			 trans_event_cb, trans_conv_cb,
+			 trans_prog_cb) == -1)
+	  {
+	    pk_backend_error_code (backend,
+				  PK_ERROR_ENUM_TRANSACTION_ERROR,
+				  alpm_strerror (pm_errno));
+	    pk_backend_finished (backend, PK_EXIT_ENUM_FAILED);
+	    return;
+	  }
+
+	alpm_trans_addtarget (id->name);
+
+	if (alpm_trans_prepare (&problems) != 0)
+	  {
+	    pk_backend_error_code (backend,
+				  PK_ERROR_ENUM_TRANSACTION_ERROR,
+				  alpm_strerror (pm_errno));
+	    pk_backend_finished (backend, PK_EXIT_ENUM_FAILED);
+	    alpm_trans_release ();
+	    return;
+	  }
+
+	if (alpm_trans_commit (&problems) != 0)
+	  {
+	    pk_backend_error_code (backend,
+				  PK_ERROR_ENUM_TRANSACTION_ERROR,
+				  alpm_strerror (pm_errno));
+	    pk_backend_finished (backend, PK_EXIT_ENUM_FAILED);
+	    alpm_trans_release ();
+	    return;
+	  }
+	alpm_trans_release ();
+	pk_backend_finished (backend, PK_EXIT_ENUM_SUCCESS);
 }
 
 /**
diff-tree 07bf254860be0593f0787fe46c43163469ffb56f (from f7d2ad8791199959481271e2eddb3b6e0c6af3a7)
Author: Grzegorz Dabrowski <gdx at o2.pl>
Date:   Sat Sep 15 11:11:34 2007 +0000

    [box] added basic remove package support

diff --git a/backends/BACKENDS b/backends/BACKENDS
index f06a832..7401a64 100644
--- a/backends/BACKENDS
+++ b/backends/BACKENDS
@@ -9,8 +9,8 @@ search-name       |   X    |  X  |  X  |
 search-details    |        |  X  |  X  |  X  |      |
 search-file       |        |  X  |     |  X  |      |
 search-group      |        |     |     |     |      |
-install           |        |  X  |     |     |      |
-remove            |        |  X  |     |     |      |
+install           |        |  X  |     |  X  |      |
+remove            |        |  X  |     |  X  |      |
 get-depends       |        |  X  |     |     |      |
 get-requires      |        |     |     |     |      |
 get-description   |   X    |  X  |  X  |  X  |      |
diff --git a/backends/box/helpers/Makefile.am b/backends/box/helpers/Makefile.am
index ac56482..1851df4 100644
--- a/backends/box/helpers/Makefile.am
+++ b/backends/box/helpers/Makefile.am
@@ -6,6 +6,7 @@ NULL =
 dist_helper_DATA = 			\
 	install-package.sh		\
 	refresh-cache.sh		\
+	remove-package.sh		\
 	$(NULL)
 
 install-data-hook:
diff --git a/backends/box/helpers/install-package.sh b/backends/box/helpers/install-package.sh
index 6d65ea4..3f77679 100644
--- a/backends/box/helpers/install-package.sh
+++ b/backends/box/helpers/install-package.sh
@@ -11,5 +11,5 @@
 
 echo "no-percentage-updates" > /dev/stderr
 echo "status	install" > /dev/stderr
-pkg=$(echo "$@" | cut -f1 -d';')
+pkg=$(echo "$1" | cut -f1 -d';')
 box -i "$pkg" 2>&1 >/dev/null
diff --git a/backends/box/pk-backend-box.c b/backends/box/pk-backend-box.c
index 6229326..ba535c0 100644
--- a/backends/box/pk-backend-box.c
+++ b/backends/box/pk-backend-box.c
@@ -438,6 +438,22 @@ backend_refresh_cache (PkBackend *backen
 	pk_backend_spawn_helper (backend, "refresh-cache.sh", NULL);
 }
 
+/**
+ * backend_remove_package:
+ */
+static void
+backend_remove_package (PkBackend *backend, const gchar *package_id, gboolean allow_deps)
+{
+        g_return_if_fail (backend != NULL);
+        const gchar *deps;
+        if (allow_deps == TRUE) {
+                deps = "yes";
+        } else {
+                deps = "no";
+        }
+        pk_backend_spawn_helper (backend, "remove-package.sh", deps, package_id, NULL);
+}
+
 
 /**
  * backend_search_details:
@@ -485,7 +501,7 @@ PK_BACKEND_OPTIONS (
 	backend_get_updates,			/* get_updates */
 	backend_install_package,		/* install_package */
 	backend_refresh_cache,			/* refresh_cache */
-	NULL,					/* remove_package */
+	backend_remove_package,			/* remove_package */
 	backend_search_details,			/* search_details */
 	backend_search_file,			/* search_file */
 	NULL,					/* search_group */
diff-tree f7d2ad8791199959481271e2eddb3b6e0c6af3a7 (from 05c7809c8dc02ac502029a6c8990a61ada89aee6)
Author: Grzegorz Dabrowski <gdx at o2.pl>
Date:   Sat Sep 15 10:56:20 2007 +0000

    [box] added basic remove package support

diff --git a/backends/box/helpers/remove-package.sh b/backends/box/helpers/remove-package.sh
new file mode 100644
index 0000000..5e3ab9b
--- /dev/null
+++ b/backends/box/helpers/remove-package.sh
@@ -0,0 +1,15 @@
+#!/bin/sh
+#
+# Copyright (C) 2007 Grzegorz Dabrowski <gdx at o2.pl>
+#
+# 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.
+
+echo "no-percentage-updates" > /dev/stderr
+echo "status	remove" > /dev/stderr
+pkg=$(echo "$2" | cut -f1 -d';')
+box -u "$pkg" 2>&1 >/dev/null
diff-tree 05c7809c8dc02ac502029a6c8990a61ada89aee6 (from 4105ced2f895ecd8a159c9f548b53a2a29c1a777)
Author: Grzegorz Dabrowski <gdx at o2.pl>
Date:   Sat Sep 15 10:35:23 2007 +0000

    [box] added basic install package support

diff --git a/backends/box/helpers/Makefile.am b/backends/box/helpers/Makefile.am
index 64b14fa..ac56482 100644
--- a/backends/box/helpers/Makefile.am
+++ b/backends/box/helpers/Makefile.am
@@ -4,6 +4,7 @@ helperdir = $(datadir)/PackageKit/helper
 NULL =
 
 dist_helper_DATA = 			\
+	install-package.sh		\
 	refresh-cache.sh		\
 	$(NULL)
 
diff --git a/backends/box/helpers/install-package.sh b/backends/box/helpers/install-package.sh
new file mode 100644
index 0000000..6d65ea4
--- /dev/null
+++ b/backends/box/helpers/install-package.sh
@@ -0,0 +1,15 @@
+#!/bin/sh
+#
+# Copyright (C) 2007 Grzegorz Dabrowski <gdx at o2.pl>
+#
+# 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.
+
+echo "no-percentage-updates" > /dev/stderr
+echo "status	install" > /dev/stderr
+pkg=$(echo "$@" | cut -f1 -d';')
+box -i "$pkg" 2>&1 >/dev/null
diff --git a/backends/box/pk-backend-box.c b/backends/box/pk-backend-box.c
index 4f8e9fa..6229326 100644
--- a/backends/box/pk-backend-box.c
+++ b/backends/box/pk-backend-box.c
@@ -181,8 +181,6 @@ find_packages_real (PkBackend *backend, 
 			}
 			add_packages_from_list (backend, list);
 			box_db_repos_package_list_free (list);
-			// FIXME: temporary workaround
-			sleep(1);
 			pk_backend_finished (backend, PK_EXIT_ENUM_SUCCESS);
 		}
 	}
@@ -406,6 +404,23 @@ backend_get_updates (PkBackend *backend)
 	}
 }
 
+
+/**
+ * backend_install_package:
+ */
+static void
+backend_install_package (PkBackend *backend, const gchar *package_id)
+{
+        g_return_if_fail (backend != NULL);
+        /* check network state */
+        if (pk_backend_network_is_online (backend) == FALSE) {
+                pk_backend_error_code (backend, PK_ERROR_ENUM_NO_NETWORK, "Cannot install when offline");
+                pk_backend_finished (backend, PK_EXIT_ENUM_FAILED);
+                return;
+        }
+        pk_backend_spawn_helper (backend, "install-package.sh", package_id, NULL);
+}
+
 /**
  * backend_refresh_cache:
  */
@@ -468,7 +483,7 @@ PK_BACKEND_OPTIONS (
 	NULL,					/* get_requires */
 	NULL,					/* get_update_detail */
 	backend_get_updates,			/* get_updates */
-	NULL,					/* install_package */
+	backend_install_package,		/* install_package */
 	backend_refresh_cache,			/* refresh_cache */
 	NULL,					/* remove_package */
 	backend_search_details,			/* search_details */
diff-tree 4105ced2f895ecd8a159c9f548b53a2a29c1a777 (from 23bad82dc8b750064810756f8bfe27aa3fdd1f3f)
Author: Andreas Obergrusberger <tradiaz at yahoo.de>
Date:   Fri Sep 14 23:22:35 2007 +0200

    minor updates

diff --git a/backends/alpm/pk-backend-alpm.c b/backends/alpm/pk-backend-alpm.c
index e0ac1b6..6f0ea1f 100644
--- a/backends/alpm/pk-backend-alpm.c
+++ b/backends/alpm/pk-backend-alpm.c
@@ -321,9 +321,11 @@ backend_destroy (PkBackend *backend)
  * backend_initalize:
  */
 static void
-backend_initalize (PkBackend *backend)
+backend_initialize (PkBackend *backend)
 {
 	g_return_if_fail (backend != NULL);
+	progress_percentage = -1;
+	subprogress_percentage = -1;
 	pk_debug ("alpm: hi!");
 
 	if (alpm_initialize () == -1)
@@ -358,15 +360,6 @@ backend_initalize (PkBackend *backend)
 }
 
 /**
- * backend_cancel_job_try:
- */
-/*static void
-backend_cancel_job_try (PkBackend *backend)
-{
-	g_return_if_fail (backend != NULL);
-}*/
-
-/**
  * backend_get_depends:
  */
 static void
@@ -666,7 +659,7 @@ PK_BACKEND_OPTIONS (
 	"alpm backend",					/* description */
 	"0.0.1",					/* version */
 	"Andreas Obergrusberger <tradiaz at yahoo.de>",	/* author */
-	backend_initalize,				/* initalize */
+	backend_initialize,				/* initalize */
 	backend_destroy,				/* destroy */
 	NULL,						/* get_groups */
 	NULL,						/* get_filters */
diff-tree 23bad82dc8b750064810756f8bfe27aa3fdd1f3f (from eb74fec764a4c0c6d6bb0cf3469531cd1cf3a1d1)
Author: Elliot Peele <elliot at enki.rdu.rpath.com>
Date:   Fri Sep 14 11:37:57 2007 -0400

    update email address

diff --git a/AUTHORS b/AUTHORS
index d4f7d8c..806a96b 100644
--- a/AUTHORS
+++ b/AUTHORS
@@ -6,4 +6,4 @@ Luke Macken <lmacken at redhat.com>
 
 Backend: conary
     Og Maciel <omaciel at foresightlinux.org>
-    Elliot Peele <elliot at foresightlinux.org>
+    Elliot Peele <elliot at bentlogic.net>
diff-tree eb74fec764a4c0c6d6bb0cf3469531cd1cf3a1d1 (from aeb32491cc40ebf862eabe77fb9c14d5671ac147)
Author: Elliot Peele <elliot at localhost.localdomain>
Date:   Fri Sep 14 00:09:19 2007 -0400

    clean up formatting

diff --git a/backends/conary/helpers/conaryBackend.py b/backends/conary/helpers/conaryBackend.py
index 9f9b8b2..654964a 100644
--- a/backends/conary/helpers/conaryBackend.py
+++ b/backends/conary/helpers/conaryBackend.py
@@ -44,7 +44,7 @@ class PackageKitConaryBackend(PackageKit
         return PackageKitBaseBackend.get_package_id(self, name, version,
                                                     arch, fullVersion)
 
-    def _do_search(self,searchlist,filters):
+    def _do_search(self, searchlist, filters):
         fltlist = filters.split(';')
         troveSpecs = [ cmdline.parseTroveSpec(searchlist,
                                               allowEmptyName=False) ]
@@ -81,8 +81,7 @@ class PackageKitConaryBackend(PackageKit
                 id = self.get_package_id(name, version, flavor, fullVersion)
                 self.package(id, installed, summary)
 
-
-    def _do_search_live(self,searchlist,filters):
+    def _do_search_live(self, searchlist, filters):
         '''
         Search for conary packages
         @param searchlist: The conary package fields to search in
@@ -190,7 +189,6 @@ class PackageKitConaryBackend(PackageKit
             self.error(ERROR_PACKAGE_ALREADY_INSTALLED,
                 'Package was not found')
 
-
     def remove(self, package_id):
         '''
         Implement the {backend}-remove functionality
@@ -211,7 +209,6 @@ class PackageKitConaryBackend(PackageKit
             self.error(ERROR_PACKAGE_ALREADY_INSTALLED,
                 'Package was not found')
 
-
     def get_description(self, package_id):
         '''
         Print a detailed description for a given package
@@ -258,7 +255,7 @@ class PackageKitConaryBackend(PackageKit
             summary = ""
             self.package(id, installed, summary)
 
-    def _do_filtering(self,pkg,filterList,installed):
+    def _do_filtering(self, pkg, filterList, installed):
         ''' Filter the package, based on the filter in filterList '''
         # do we print to stdout?
         do_print = False;
@@ -277,7 +274,7 @@ class PackageKitConaryBackend(PackageKit
         else:
             return do_print
 
-    def _do_extra_filtering(self,pkg,filterList):
+    def _do_extra_filtering(self, pkg, filterList):
         ''' do extra filtering (devel etc) '''
 
         for flt in filterList:
@@ -288,7 +285,7 @@ class PackageKitConaryBackend(PackageKit
                     return False
         return True
 
-    def _do_devel_filtering(self,flt,pkg):
+    def _do_devel_filtering(self, flt, pkg):
         isDevel = False
         if flt == 'devel':
             wantDevel = True
@@ -305,7 +302,7 @@ class PackageKitConaryBackend(PackageKit
         #
         return isDevel == wantDevel
 
-    def _findPackage(self,id):
+    def _findPackage(self, id):
         '''
         find a package based on a package id (name;version;arch;repoid)
         '''
@@ -317,6 +314,7 @@ class PackageKitConaryBackend(PackageKit
         installed = self.check_installed(troveTuple)
         return name,installed,version,arch,fullVersion
 
+
 class Cache(object):
     # Database name and path
     dbName = 'cache.db'
diff-tree aeb32491cc40ebf862eabe77fb9c14d5671ac147 (from 2f1a5a5a3bcbbc8b9e2000a6cf52ddfac9479d3a)
Author: Elliot Peele <elliot at localhost.localdomain>
Date:   Fri Sep 14 00:05:18 2007 -0400

    clean up paths

diff --git a/backends/test-backend.sh b/backends/test-backend.sh
index 0856173..cbba51a 100755
--- a/backends/test-backend.sh
+++ b/backends/test-backend.sh
@@ -6,58 +6,57 @@ package_id="BasiliskII;1.0-0.20060501.1.
 backend="yum"
 
 echo "get deps $package_id"
-./$backend/get-deps.py $package_id 
+./$backend/helpers/get-deps.py $package_id 
 echo "exitcode=$?"
 
 echo "get description $package_id"
-./$backend/get-description.py $package_id
+./$backend/helpers/get-description.py $package_id
 echo "exitcode=$?"
 
 echo "get updates"
-./$backend/get-updates.py
+./$backend/helpers/get-updates.py
 echo "exitcode=$?"
 
 echo "refresh cache"
-./$backend/refresh-cache.py
+./$backend/helpers/refresh-cache.py
 echo "exitcode=$?"
 
 echo "remove $package_id"
-./$backend/remove.py no $package_id
+./$backend/helpers/remove.py no $package_id
 echo "exitcode=$?"
 
 echo "remove $package_id (already removed)"
-./$backend/remove.py no $package_id
+./$backend/helpers/remove.py no $package_id
 echo "exitcode=$?"
 
 echo "install $package_id"
-./$backend/install.py $package_id
+./$backend/helpers/install.py $package_id
 echo "exitcode=$?"
 
 echo "install $package_id (already installed)"
-./$backend/install.py $package_id
+./$backend/helpers/install.py $package_id
 echo "exitcode=$?"
 
 echo "search details lm_sensors"
-./$backend/search-details.py none lm_sensors
+./$backend/helpers/search-details.py none lm_sensors
 echo "exitcode=$?"
 
 echo "search file gpm-prefs.glade"
-./$backend/search-file.py none gpm-prefs.glade
+./$backend/helpers/search-file.py none gpm-prefs.glade
 echo "exitcode=$?"
 
 echo "search group system"
-./$backend/search-group.py none system
+./$backend/helpers/search-group.py none system
 echo "exitcode=$?"
 
 echo "search name power"
-./$backend/search-name.py none power
+./$backend/helpers/search-name.py none power
 echo "exitcode=$?"
 
 echo "update $package_id"
-./$backend/update.py $package_id
+./$backend/helpers/update.py $package_id
 echo "exitcode=$?"
 
 echo "update system"
-./$backend/update-system.py
+./$backend/helpers/update-system.py
 echo "exitcode=$?"
-
diff-tree 2f1a5a5a3bcbbc8b9e2000a6cf52ddfac9479d3a (from b84897f3aeb938ac72e1c9764359744286a1a881)
Author: Elliot Peele <elliot at localhost.localdomain>
Date:   Thu Sep 13 23:40:56 2007 -0400

    clean up formatting

diff --git a/backends/conary/helpers/conaryBackend.py b/backends/conary/helpers/conaryBackend.py
index 070edb4..9f9b8b2 100644
--- a/backends/conary/helpers/conaryBackend.py
+++ b/backends/conary/helpers/conaryBackend.py
@@ -46,7 +46,8 @@ class PackageKitConaryBackend(PackageKit
 
     def _do_search(self,searchlist,filters):
         fltlist = filters.split(';')
-        troveSpecs = [ cmdline.parseTroveSpec(searchlist, allowEmptyName=False)]
+        troveSpecs = [ cmdline.parseTroveSpec(searchlist,
+                                              allowEmptyName=False) ]
         # get a hold of cached data
         cache = Cache()
 
@@ -92,7 +93,8 @@ class PackageKitConaryBackend(PackageKit
         affinityDb = self.client.db
         fltlist = filters.split(';')
 
-        troveSpecs = [ cmdline.parseTroveSpec(searchlist, allowEmptyName=False)]
+        troveSpecs = [ cmdline.parseTroveSpec(searchlist,
+                                              allowEmptyName=False) ]
 
         try:
             # Look for packages with affinity
@@ -172,43 +174,51 @@ class PackageKitConaryBackend(PackageKit
         '''
         Implement the {backend}-install functionality
         '''
-        name,installed,version,arch,fullVersion = self._findPackage(package_id)
+        name, installed, version, arch, fullVersion = \
+            self._findPackage(package_id)
 
         if name:
             if installed:
-                self.error(ERROR_PACKAGE_ALREADY_INSTALLED,'Package already installed')
+                self.error(ERROR_PACKAGE_ALREADY_INSTALLED,
+                    'Package already installed')
             try:
                 self.base.status(STATE_INSTALL)
                 #print "Update code goes here"
             except:
                 pass
         else:
-            self.error(ERROR_PACKAGE_ALREADY_INSTALLED,"Package was not found")
+            self.error(ERROR_PACKAGE_ALREADY_INSTALLED,
+                'Package was not found')
 
 
     def remove(self, package_id):
         '''
         Implement the {backend}-remove functionality
         '''
-        name,installed,version,arch,fullVersion = self._findPackage(package_id)
+        name, installed, version, arch, fullVersion = \
+            self._findPackage(package_id)
 
         if name:
             if not installed:
-                self.error(ERROR_PACKAGE_NOT_INSTALLED,'Package not installed')
+                self.error(ERROR_PACKAGE_NOT_INSTALLED,
+                    'Package not installed')
             try:
                 self.base.status(STATE_REMOVE)
                 #print "Remove code goes here"
             except:
                 pass
         else:
-            self.error(ERROR_PACKAGE_ALREADY_INSTALLED,"Package was not found")
+            self.error(ERROR_PACKAGE_ALREADY_INSTALLED,
+                'Package was not found')
 
 
     def get_description(self, package_id):
         '''
         Print a detailed description for a given package
         '''
-        name,installed,version,arch,fullVersion = self._findPackage(package_id)
+        name, installed, version, arch, fullVersion = \
+            self._findPackage(package_id)
+
         fullVersion = versions.VersionFromString(fullVersion)
         version = fullVersion.trailingRevision()
         if name:
@@ -285,7 +295,8 @@ class PackageKitConaryBackend(PackageKit
         else:
             wantDevel = False
         #
-        # TODO: Add Devel detection Code here.Set isDevel = True, if it is a devel app
+        # TODO: Add Devel detection Code here.Set isDevel = True, if it is a
+        #       devel app.
         #
         regex =  re.compile(r'(:devel)')
         if regex.search(pkg.name):
@@ -300,7 +311,9 @@ class PackageKitConaryBackend(PackageKit
         '''
         # Split up the id
         (name,version,arch,fullVersion) = self.get_package_from_id(id)
-        troveTuple = tuple([name, versions.VersionFromString(fullVersion), None])
+        troveTuple = tuple([name,
+                            versions.VersionFromString(fullVersion),
+                            None])
         installed = self.check_installed(troveTuple)
         return name,installed,version,arch,fullVersion
 
@@ -319,7 +332,8 @@ class Cache(object):
         if not os.path.isdir(self.dbPath):
             os.makedirs(self.dbPath)
 
-        self.conn = sqlite.connect(os.path.join(self.dbPath, self.dbName), isolation_level=None)
+        self.conn = sqlite.connect(os.path.join(self.dbPath, self.dbName),
+                                   isolation_level=None)
         self.cursor = self.conn.cursor()
         self.cursor.execute("PRAGMA count_changes=0")
         self.cursor.execute("pragma synchronous=off")
@@ -329,7 +343,8 @@ class Cache(object):
 
     def _validate_tables(self):
         """ Validates that all tables are up to date. """
-        stmt = "select tbl_name from sqlite_master where type = 'table' and tbl_name like 'conary_%'"
+        stmt = ("select tbl_name from sqlite_master "
+                "where type = 'table' and tbl_name like 'conary_%'")
         self.cursor.execute(stmt)
         # List of all tables with names that start with "conary_"
         tbllist = self.cursor.fetchall()
@@ -378,7 +393,8 @@ class Cache(object):
             category = ""
             packagegroup = ""
             size = ""
-            packages.append([trove, component, fullVersion, label, flavor, description, category, packagegroup, size])
+            packages.append([trove, component, fullVersion, label, flavor,
+                             description, category, packagegroup, size])
 
         return packages
 
@@ -410,8 +426,8 @@ class Cache(object):
         """
         Returns all troves for now.  Add filtering capability.
         """
-        stmt = "select distinct trove, version, flavor, description, category, packagegroup, size" \
-            " from conary_packages"
+        stmt = ("select distinct trove, version, flavor, description, "
+                "category, packagegroup, size from conary_packages")
 
         try:
             self.cursor.execute(stmt)
@@ -424,13 +440,16 @@ class Cache(object):
         """
         Returns all troves for now.  Add filtering capability.
         """
-        stmt = "select distinct trove, version, flavor, description, category, packagegroup, size" \
-            " from conary_packages"
+        stmt = ("select distinct trove, version, flavor, description, "
+                "category, packagegroup, size from conary_packages")
 
         if package and fullVersion:
-            stmt = "select distinct trove, version, flavor from conary_packages where trove ='" + package + "' and version = '" + fullVersion +"'"
+            stmt = ("select distinct trove, version, flavor from "
+                    "conary_packages where trove ='%s' and version = '%s'"
+                    % (package, fullVersion))
         elif package:
-            stmt = stmt + " where trove like '%" + package + "%' and component = '' order by version desc"
+            stmt += (" where trove like '%%%s%%' and component = '' order by "
+                     "version desc" % package)
 
         try:
             self.cursor.execute(stmt)
@@ -469,5 +488,3 @@ class Cache(object):
                 self._insert(package)
         except Exception, e:
             print str(e)
-
-



More information about the PackageKit mailing list