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

Richard Hughes hughsient at kemper.freedesktop.org
Wed Oct 10 15:04:22 PDT 2007


 TODO                                   |    2 
 backends/apt/Makefile.am               |    9 
 backends/apt/apt-build-db.cpp          |  283 ++++++++++++++++
 backends/apt/helpers/.gitignore        |    2 
 backends/apt/helpers/Makefile.am       |   16 
 backends/apt/helpers/aptBackend.py     |   53 +++
 backends/apt/helpers/refresh-cache.py  |   22 +
 backends/apt/pk-backend-apt.cpp        |  580 +--------------------------------
 backends/apt/pk-backend-apt.h          |   30 +
 backends/apt/python-backend-common.cpp |   38 ++
 backends/apt/python-backend-common.h   |   27 +
 backends/apt/sqlite-pkg-cache.cpp      |  227 ++++++++++++
 backends/apt/sqlite-pkg-cache.h        |   39 ++
 configure.ac                           |    1 
 libpackagekit/pk-client.c              |   77 ++++
 python/pk-frontend-test.py             |    6 
 src/pk-backend.c                       |    6 
 17 files changed, 859 insertions(+), 559 deletions(-)

New commits:
diff-tree 58b32e8a981ff098a989a9187637649a69c4ded1 (from 48f727193d0129293e8e5e7709e521d2809316dc)
Author: Richard Hughes <richard at hughsie.com>
Date:   Wed Oct 10 23:01:08 2007 +0100

    check the private tid before we compare to silence lots of warnings

diff --git a/libpackagekit/pk-client.c b/libpackagekit/pk-client.c
index 48a93a8..fe8a0e0 100644
--- a/libpackagekit/pk-client.c
+++ b/libpackagekit/pk-client.c
@@ -225,12 +225,21 @@ pk_client_finished_cb (DBusGProxy  *prox
 	g_return_if_fail (client != NULL);
 	g_return_if_fail (PK_IS_CLIENT (client));
 
+	/* check to see if we have been assigned yet */
+	if (client->priv->tid == NULL) {
+		pk_debug ("ignoring tid:%s as we are not yet assigned", tid);
+		return;
+	}
+
 	if (pk_transaction_id_equal (tid, client->priv->tid) == TRUE) {
 		exit = pk_exit_enum_from_text (exit_text);
 		pk_debug ("emit finished %i, %i", exit, runtime);
+
+		/* only this instance is finished, and do it before the signal so we can reset */
+		client->priv->is_finished = TRUE;
+
 		g_signal_emit (client , signals [PK_CLIENT_FINISHED], 0, exit, runtime);
 	}
-	client->priv->is_finished = TRUE;
 }
 
 /**
@@ -245,6 +254,12 @@ pk_client_percentage_changed_cb (DBusGPr
 	g_return_if_fail (client != NULL);
 	g_return_if_fail (PK_IS_CLIENT (client));
 
+	/* check to see if we have been assigned yet */
+	if (client->priv->tid == NULL) {
+		pk_debug ("ignoring tid:%s as we are not yet assigned", tid);
+		return;
+	}
+
 	if (pk_transaction_id_equal (tid, client->priv->tid) == TRUE) {
 		pk_debug ("emit percentage-changed %i", percentage);
 		g_signal_emit (client , signals [PK_CLIENT_PERCENTAGE_CHANGED], 0, percentage);
@@ -263,6 +278,12 @@ pk_client_sub_percentage_changed_cb (DBu
 	g_return_if_fail (client != NULL);
 	g_return_if_fail (PK_IS_CLIENT (client));
 
+	/* check to see if we have been assigned yet */
+	if (client->priv->tid == NULL) {
+		pk_debug ("ignoring tid:%s as we are not yet assigned", tid);
+		return;
+	}
+
 	if (pk_transaction_id_equal (tid, client->priv->tid) == TRUE) {
 		pk_debug ("emit sub-percentage-changed %i", percentage);
 		g_signal_emit (client, signals [PK_CLIENT_SUB_PERCENTAGE_CHANGED], 0, percentage);
@@ -280,6 +301,12 @@ pk_client_no_percentage_updates_cb (DBus
 	g_return_if_fail (client != NULL);
 	g_return_if_fail (PK_IS_CLIENT (client));
 
+	/* check to see if we have been assigned yet */
+	if (client->priv->tid == NULL) {
+		pk_debug ("ignoring tid:%s as we are not yet assigned", tid);
+		return;
+	}
+
 	if (pk_transaction_id_equal (tid, client->priv->tid) == TRUE) {
 		pk_debug ("emit no-percentage-updates");
 		g_signal_emit (client , signals [PK_CLIENT_NO_PERCENTAGE_UPDATES], 0);
@@ -300,6 +327,12 @@ pk_client_transaction_status_changed_cb 
 	g_return_if_fail (client != NULL);
 	g_return_if_fail (PK_IS_CLIENT (client));
 
+	/* check to see if we have been assigned yet */
+	if (client->priv->tid == NULL) {
+		pk_debug ("ignoring tid:%s as we are not yet assigned", tid);
+		return;
+	}
+
 	status = pk_status_enum_from_text (status_text);
 	if (pk_transaction_id_equal (tid, client->priv->tid) == TRUE) {
 		pk_debug ("emit transaction-status-changed %i", status);
@@ -323,6 +356,12 @@ pk_client_package_cb (DBusGProxy   *prox
 	g_return_if_fail (client != NULL);
 	g_return_if_fail (PK_IS_CLIENT (client));
 
+	/* check to see if we have been assigned yet */
+	if (client->priv->tid == NULL) {
+		pk_debug ("ignoring tid:%s as we are not yet assigned", tid);
+		return;
+	}
+
 	if (pk_transaction_id_equal (tid, client->priv->tid) == TRUE) {
 		pk_debug ("emit package %s, %s, %s", info_text, package_id, summary);
 		info = pk_info_enum_from_text (info_text);
@@ -364,6 +403,12 @@ pk_client_transaction_cb (DBusGProxy *pr
 	g_return_if_fail (client != NULL);
 	g_return_if_fail (PK_IS_CLIENT (client));
 
+	/* check to see if we have been assigned yet */
+	if (client->priv->tid == NULL) {
+		pk_debug ("ignoring tid:%s as we are not yet assigned", tid);
+		return;
+	}
+
 	if (pk_transaction_id_equal (tid, client->priv->tid) == TRUE) {
 		role = pk_role_enum_from_text (role_text);
 		pk_debug ("emitting transaction %s, %s, %i, %s, %i, %s", old_tid, timespec, succeeded, role_text, duration, data);
@@ -388,6 +433,12 @@ pk_client_update_detail_cb (DBusGProxy  
 	g_return_if_fail (client != NULL);
 	g_return_if_fail (PK_IS_CLIENT (client));
 
+	/* check to see if we have been assigned yet */
+	if (client->priv->tid == NULL) {
+		pk_debug ("ignoring tid:%s as we are not yet assigned", tid);
+		return;
+	}
+
 	if (pk_transaction_id_equal (tid, client->priv->tid) == TRUE) {
 		pk_debug ("emit update-detail %s, %s, %s, %s, %s, %s",
 			  package_id, updates, obsoletes, url, restart, update_text);
@@ -415,6 +466,12 @@ pk_client_description_cb (DBusGProxy  *p
 	g_return_if_fail (client != NULL);
 	g_return_if_fail (PK_IS_CLIENT (client));
 
+	/* check to see if we have been assigned yet */
+	if (client->priv->tid == NULL) {
+		pk_debug ("ignoring tid:%s as we are not yet assigned", tid);
+		return;
+	}
+
 	if (pk_transaction_id_equal (tid, client->priv->tid) == TRUE) {
 		group = pk_group_enum_from_text (group_text);
 		pk_debug ("emit description %s, %s, %i, %s, %s, %ld, %s",
@@ -435,6 +492,12 @@ pk_client_repo_signature_required_cb (DB
 	g_return_if_fail (client != NULL);
 	g_return_if_fail (PK_IS_CLIENT (client));
 	
+	/* check to see if we have been assigned yet */
+	if (client->priv->tid == NULL) {
+		pk_debug ("ignoring tid:%s as we are not yet assigned", tid);
+		return;
+	}
+
 	if (pk_transaction_id_equal (tid, client->priv->tid) == TRUE) {
 		pk_debug ("emit repo_signature_required tid:%s, %s, %s, %s, %s, %s, %s",
 			  tid, repository_name, key_url, key_userid, key_id, key_timestamp, type_text);
@@ -457,6 +520,12 @@ pk_client_error_code_cb (DBusGProxy  *pr
 	g_return_if_fail (client != NULL);
 	g_return_if_fail (PK_IS_CLIENT (client));
 
+	/* check to see if we have been assigned yet */
+	if (client->priv->tid == NULL) {
+		pk_debug ("ignoring tid:%s as we are not yet assigned", tid);
+		return;
+	}
+
 	if (pk_transaction_id_equal (tid, client->priv->tid) == TRUE) {
 		code = pk_error_enum_from_text (code_text);
 		pk_debug ("emit error-code %i, %s", code, details);
@@ -478,6 +547,12 @@ pk_client_require_restart_cb (DBusGProxy
 	g_return_if_fail (client != NULL);
 	g_return_if_fail (PK_IS_CLIENT (client));
 
+	/* check to see if we have been assigned yet */
+	if (client->priv->tid == NULL) {
+		pk_debug ("ignoring tid:%s as we are not yet assigned", tid);
+		return;
+	}
+
 	if (pk_transaction_id_equal (tid, client->priv->tid) == TRUE) {
 		restart = pk_restart_enum_from_text (restart_text);
 		pk_debug ("emit require-restart %i, %s", restart, details);
diff-tree 48f727193d0129293e8e5e7709e521d2809316dc (from cbc060b6d6012ebf28690c2620a6c180025822c6)
Author: Ken VanDine <ken at vandine.org>
Date:   Wed Oct 10 16:30:38 2007 -0400

    Added a blocker

diff --git a/TODO b/TODO
index 29a27f7..70e8b9e 100644
--- a/TODO
+++ b/TODO
@@ -14,6 +14,7 @@ RepoSetData(s=rid,s=data,s=value)
 *** pk-application (client) ***
 Use an icons for installed and not-installed rather than tickboxes
 Refresh the query list after an install or remove (means saving the query and re-issuing)
+** RELEASE BLOCKER **
 
 *** Client library has to be able to re_issue ***
 Need to save PkRole
diff-tree cbc060b6d6012ebf28690c2620a6c180025822c6 (from c62bd856cf9796a028c11ccca0588dc924ad943b)
Author: Ken VanDine <ken at vandine.org>
Date:   Wed Oct 10 16:29:57 2007 -0400

    Removed a blocker from TODO

diff --git a/TODO b/TODO
index a9f534c..29a27f7 100644
--- a/TODO
+++ b/TODO
@@ -2,7 +2,6 @@ Order of no particular importance:
 
 *** pk-update-icon (client) ***
 * Don't re-run get-updates when selecting "Show updates" from the update icon, just populate it with the previous results.
-NOTE: RELEASE BLOCKER
 
 *** Add new callback for status ***
 TimeRemaining()
diff-tree c62bd856cf9796a028c11ccca0588dc924ad943b (from ee658a84df7ffc982e5b0091a49ac8513b0ca99b)
Author: Richard Hughes <richard at hughsie.com>
Date:   Wed Oct 10 20:23:59 2007 +0100

    remove some trailing whitespace in toms patch

diff --git a/backends/apt/apt-build-db.cpp b/backends/apt/apt-build-db.cpp
index 54fe28a..894b70b 100644
--- a/backends/apt/apt-build-db.cpp
+++ b/backends/apt/apt-build-db.cpp
@@ -64,13 +64,13 @@ void apt_build_db(PkBackend * backend, s
 			g_strfreev(items);
 			continue;
 		}
-		
+
 		/* warning: nasty hack with g_strjoinv */
 		temp = items[len-2];
 		items[len-2] = NULL;
 		parsed_name = g_strjoinv("_",items);
 		items[len-2] = temp;
-		
+
 		if (g_ascii_strcasecmp(items[len-1],"Release")==0 && g_ascii_strcasecmp(items[len-2],"source")!=0)
 		{
 			gchar * repo = NULL, *fullname;
@@ -155,9 +155,9 @@ void apt_build_db(PkBackend * backend, s
 				parsed_name = g_strjoinv("_",items);
 				items[len-1] = temp;
 			}
-			
+
 			pk_debug("type is %s, group is %s, parsed_name is %s",items[len-2],items[len-1],parsed_name);
-			
+
 			repo = (const gchar *)g_hash_table_lookup(releases,parsed_name);
 			if (repo == NULL)
 			{
@@ -261,7 +261,7 @@ void apt_build_db(PkBackend * backend, s
 				}
 				if (next == NULL)
 					break;
-				begin = next;	
+				begin = next;
 			}
 			res = sqlite3_exec(db,"commit",NULL,NULL,NULL);
 			if (res!=SQLITE_OK)
diff --git a/backends/apt/sqlite-pkg-cache.cpp b/backends/apt/sqlite-pkg-cache.cpp
index 14c3ea7..369801d 100644
--- a/backends/apt/sqlite-pkg-cache.cpp
+++ b/backends/apt/sqlite-pkg-cache.cpp
@@ -7,7 +7,7 @@
  * 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; version 2 of the License.
- * 
+ *
  * 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
@@ -82,7 +82,7 @@ sqlite_search_packages_thread (PkBackend
 
 	sqlite3_stmt *package = NULL;
 	g_strdelimit(st->search," ",'%');
-	
+
 	if (st->depth == SEARCH_NAME)
 		sel = g_strdup_printf("select name,version,arch,repo,short_desc from packages where name like '%%%s%%'",st->search);
 	else if (st->depth == SEARCH_DETAILS)
@@ -92,7 +92,7 @@ sqlite_search_packages_thread (PkBackend
 		pk_backend_error_code(backend, PK_ERROR_ENUM_INTERNAL_ERROR, "Unknown search task type");
 		goto end_search_packages;
 	}
-	
+
 	pk_debug("statement is '%s'",sel);
 	res = sqlite3_prepare_v2(db,sel, -1, &package, NULL);
 	g_free(sel);
diff-tree ee658a84df7ffc982e5b0091a49ac8513b0ca99b (from bb2a7b0b47d8b152f778798ac3cfe06f28ebae21)
Author: Richard Hughes <richard at hughsie.com>
Date:   Wed Oct 10 20:21:52 2007 +0100

    Top is the APT dude. I share none of the credit

diff --git a/backends/apt/pk-backend-apt.cpp b/backends/apt/pk-backend-apt.cpp
index 0e3d7d7..2b72d65 100644
--- a/backends/apt/pk-backend-apt.cpp
+++ b/backends/apt/pk-backend-apt.cpp
@@ -130,7 +130,7 @@ static void backend_search_file(PkBacken
 extern "C" PK_BACKEND_OPTIONS (
 	"APT",					/* description */
 	"0.0.1",				/* version */
-	"Richard Hughes <richard at hughsie.com>, Tom Parker <palfrey at tevp.net>",	/* author */
+	"Tom Parker <palfrey at tevp.net>",	/* author */
 	backend_initialize,			/* initalize */
 	NULL,					/* destroy */
 	backend_get_groups,			/* get_groups */
diff-tree bb2a7b0b47d8b152f778798ac3cfe06f28ebae21 (from a4a73837d340069f3128962125b38555d5010d42)
Author: Tom Parker <palfrey at tevp.net>
Date:   Wed Oct 10 19:09:50 2007 +0200

    sqlite-pkg-cache listed as under GPLv2 only

diff --git a/backends/apt/sqlite-pkg-cache.cpp b/backends/apt/sqlite-pkg-cache.cpp
index f71c54f..14c3ea7 100644
--- a/backends/apt/sqlite-pkg-cache.cpp
+++ b/backends/apt/sqlite-pkg-cache.cpp
@@ -6,9 +6,8 @@
  *
  * 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.
- *
+ * the Free Software Foundation; version 2 of the License.
+ * 
  * 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
diff-tree a4a73837d340069f3128962125b38555d5010d42 (from b5b570785fcbe6a0bfdb0079d5f4b8c215468840)
Author: Tom Parker <palfrey at tevp.net>
Date:   Wed Oct 10 19:08:42 2007 +0200

    Add "depends" call to pk-frontend-test.py

diff --git a/python/pk-frontend-test.py b/python/pk-frontend-test.py
index 40bd9a7..4761b4f 100755
--- a/python/pk-frontend-test.py
+++ b/python/pk-frontend-test.py
@@ -68,6 +68,12 @@ def desc(*args):
 		raise PackageKitTransactionFailure
 	return p.GetDescription(args[0][0])
 
+def depends(*args):
+	if len(args)!=1 or len(args[0])!=1:
+		print "depends only takes single arg"
+		raise PackageKitTransactionFailure
+	return p.GetDepends(args[0][0])
+
 def refresh_cache(*args):
 	if len(args)>0 and len(args[0])>0:
 		print "refresh_cache doesn't take args"
diff-tree b5b570785fcbe6a0bfdb0079d5f4b8c215468840 (from 50713c3aac3a164ee8163262a4e666a5d34634d6)
Author: Tom Parker <palfrey at tevp.net>
Date:   Wed Oct 10 19:06:59 2007 +0200

    Clear up name vs. detail searching in sqlite cache

diff --git a/backends/apt/sqlite-pkg-cache.cpp b/backends/apt/sqlite-pkg-cache.cpp
index 1475715..f71c54f 100644
--- a/backends/apt/sqlite-pkg-cache.cpp
+++ b/backends/apt/sqlite-pkg-cache.cpp
@@ -74,6 +74,7 @@ sqlite_search_packages_thread (PkBackend
 {
 	search_task *st = (search_task *) data;
 	int res;
+	gchar *sel;
 
 	pk_backend_change_status(backend, PK_STATUS_ENUM_QUERY);
 	pk_backend_no_percentage_updates(backend);
@@ -82,7 +83,17 @@ sqlite_search_packages_thread (PkBackend
 
 	sqlite3_stmt *package = NULL;
 	g_strdelimit(st->search," ",'%');
-	gchar *sel = g_strdup_printf("select name,version,arch,repo,short_desc from packages where name like '%%%s%%'",st->search);
+	
+	if (st->depth == SEARCH_NAME)
+		sel = g_strdup_printf("select name,version,arch,repo,short_desc from packages where name like '%%%s%%'",st->search);
+	else if (st->depth == SEARCH_DETAILS)
+		sel = g_strdup_printf("select name,version,arch,repo,short_desc from packages where name like '%%%s%%' or short_desc like '%%%s%%' or long_desc like '%%%s%%'",st->search, st->search, st->search);
+	else
+	{
+		pk_backend_error_code(backend, PK_ERROR_ENUM_INTERNAL_ERROR, "Unknown search task type");
+		goto end_search_packages;
+	}
+	
 	pk_debug("statement is '%s'",sel);
 	res = sqlite3_prepare_v2(db,sel, -1, &package, NULL);
 	g_free(sel);
@@ -106,6 +117,7 @@ sqlite_search_packages_thread (PkBackend
 		g_assert(0);
 	}
 
+	end_search_packages:
 	g_free(st->search);
 	g_free(st);
 
diff-tree 50713c3aac3a164ee8163262a4e666a5d34634d6 (from faa3d44b653b6ea36251891b2753f16967f093e9)
Author: Tom Parker <palfrey at tevp.net>
Date:   Wed Oct 10 19:05:01 2007 +0200

    Add backend "must be older" file for sqlite rebuilding

diff --git a/backends/apt/pk-backend-apt.cpp b/backends/apt/pk-backend-apt.cpp
index 67a80aa..0e3d7d7 100644
--- a/backends/apt/pk-backend-apt.cpp
+++ b/backends/apt/pk-backend-apt.cpp
@@ -47,11 +47,20 @@ static void backend_initialize(PkBackend
 {
 	if (!inited)
 	{
+		gchar *apt_fname = NULL;
 		if (pkgInitConfig(*_config) == false)
 			pk_debug("pkginitconfig was false");
 		if (pkgInitSystem(*_config, _system) == false)
 			pk_debug("pkginitsystem was false");
-		sqlite_init_cache(backend, APT_DB, apt_build_db);
+
+		apt_fname = g_strconcat(
+				_config->Find("Dir").c_str(),
+				_config->Find("Dir::Cache").c_str(),
+				_config->Find("Dir::Cache::pkgcache").c_str(),
+				NULL);
+
+		sqlite_init_cache(backend, APT_DB, apt_fname, apt_build_db);
+		g_free(apt_fname);
 		inited = TRUE;
 	}
 }
diff --git a/backends/apt/sqlite-pkg-cache.cpp b/backends/apt/sqlite-pkg-cache.cpp
index 1205676..1475715 100644
--- a/backends/apt/sqlite-pkg-cache.cpp
+++ b/backends/apt/sqlite-pkg-cache.cpp
@@ -21,6 +21,7 @@
 
 #include <sqlite3.h>
 #include <glib.h>
+#include <glib/gstdio.h>
 #include "sqlite-pkg-cache.h"
 
 static sqlite3 *db = NULL;
@@ -36,27 +37,35 @@ struct search_task {
 };
 
 void
-sqlite_init_cache(PkBackend *backend, const char* dbname, void (*build_db)(PkBackend *, sqlite3 *))
+sqlite_init_cache(PkBackend *backend, const char* dbname, const char *compare_fname, void (*build_db)(PkBackend *, sqlite3 *))
 {
-	gint ret;
+	int ret;
+	struct stat st;
+	time_t db_age;
 
 	ret = sqlite3_open (dbname, &db);
 	ret = sqlite3_exec(db,"PRAGMA synchronous = OFF",NULL,NULL,NULL);
 	g_assert(ret == SQLITE_OK);
-	ret = sqlite3_exec(db, "select value from params where name = 'build_complete'", NULL, NULL, NULL);
-	if (ret == SQLITE_ERROR)
-	{
-		ret = sqlite3_exec(db,"drop table packages",NULL,NULL,NULL); // wipe it!
-		//g_assert(ret == SQLITE_OK);
-		pk_debug("wiped db");
-		ret = sqlite3_exec(db,"create table packages (name text, version text, deps text, arch text, short_desc text, long_desc text, repo string, primary key(name,version,arch,repo))",NULL,NULL,NULL);
-		g_assert(ret == SQLITE_OK);
 
-		build_db(backend,db);
+	g_stat(dbname, &st);
+	db_age = st.st_mtime;
+	g_stat(compare_fname, &st);
+	if (db_age>=st.st_mtime)
+	{
+		ret = sqlite3_exec(db, "select value from params where name = 'build_complete'", NULL, NULL, NULL);
+		if (ret != SQLITE_ERROR)
+			return;
+	}
+	ret = sqlite3_exec(db,"drop table packages",NULL,NULL,NULL); // wipe it!
+	//g_assert(ret == SQLITE_OK);
+	pk_debug("wiped db");
+	ret = sqlite3_exec(db,"create table packages (name text, version text, deps text, arch text, short_desc text, long_desc text, repo string, primary key(name,version,arch,repo))",NULL,NULL,NULL);
+	g_assert(ret == SQLITE_OK);
+
+	build_db(backend,db);
 
-		sqlite3_exec(db,"create table params (name text primary key, value integer)", NULL, NULL, NULL);
-		sqlite3_exec(db,"insert into params values ('build_complete',1)", NULL, NULL, NULL);
-	}
+	sqlite3_exec(db,"create table params (name text primary key, value integer)", NULL, NULL, NULL);
+	sqlite3_exec(db,"insert into params values ('build_complete',1)", NULL, NULL, NULL);
 }
 
 // sqlite_search_packages_thread
diff --git a/backends/apt/sqlite-pkg-cache.h b/backends/apt/sqlite-pkg-cache.h
index 0cbadcd..68f5287 100644
--- a/backends/apt/sqlite-pkg-cache.h
+++ b/backends/apt/sqlite-pkg-cache.h
@@ -30,7 +30,7 @@ typedef enum {
 
 #include <pk-backend.h>
 
-void sqlite_init_cache(PkBackend *backend, const char* dbname, void (*build_db)(PkBackend *, sqlite3 *db));
+void sqlite_init_cache(PkBackend *backend, const char* dbname, const char* compare_fname, void (*build_db)(PkBackend *, sqlite3 *db));
 void sqlite_search_details (PkBackend *backend, const gchar *filter, const gchar *search);
 void sqlite_search_name (PkBackend *backend, const gchar *filter, const gchar *search);
 void backend_search_common(PkBackend * backend, const gchar * filter, const gchar * search, SearchDepth which, PkBackendThreadFunc func);
diff-tree faa3d44b653b6ea36251891b2753f16967f093e9 (from a635bb191b5a90bc14578adc3f264452d90ab601)
Author: Tom Parker <palfrey at tevp.net>
Date:   Wed Oct 10 19:02:47 2007 +0200

    Add common python spawner

diff --git a/backends/apt/Makefile.am b/backends/apt/Makefile.am
index 1c33f10..05dcc43 100644
--- a/backends/apt/Makefile.am
+++ b/backends/apt/Makefile.am
@@ -2,7 +2,7 @@ SUBDIRS = helpers
 plugindir = @PK_PLUGIN_DIR@
 plugin_LTLIBRARIES = libpk_backend_apt.la
 libpk_backend_apt_la_INCLUDES = $(APT_CFLAGS) $(SQLITE_CFLAGS)
-libpk_backend_apt_la_SOURCES = pk-backend-apt.cpp sqlite-pkg-cache.cpp apt-build-db.cpp
+libpk_backend_apt_la_SOURCES = pk-backend-apt.cpp sqlite-pkg-cache.cpp apt-build-db.cpp python-backend-common.cpp
 libpk_backend_apt_la_LIBADD = @PK_PLUGIN_LIBS@ $(APT_LIBS) $(SQLITE_LIBS)
 libpk_backend_apt_la_LDFLAGS = -module -avoid-version
 libpk_backend_apt_la_CXXFLAGS = @PK_PLUGIN_CFLAGS@ -DDATABASEDIR=\""$(PK_DB_DIR)"\"
diff --git a/backends/apt/pk-backend-apt.cpp b/backends/apt/pk-backend-apt.cpp
index 29d7ec8..67a80aa 100644
--- a/backends/apt/pk-backend-apt.cpp
+++ b/backends/apt/pk-backend-apt.cpp
@@ -37,6 +37,7 @@
 
 #include "pk-backend-apt.h"
 #include "sqlite-pkg-cache.h"
+#include "python-backend-common.h"
 
 static gboolean inited = FALSE;
 
@@ -83,22 +84,6 @@ backend_get_filters (PkBackend *backend,
 				      -1);
 }
 
-/**
- * backend_refresh_cache:
- **/
-static void backend_refresh_cache(PkBackend * backend, gboolean force)
-{
-	/* 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);
-		return;
-	}
-
-	pk_backend_spawn_helper (backend, "refresh-cache.py", NULL);
-}
-
 static gboolean backend_search_file_thread (PkBackend *backend, gpointer data)
 {
 	//search_task *st = (search_task*)data;
@@ -149,7 +134,7 @@ extern "C" PK_BACKEND_OPTIONS (
 	NULL,					/* get_updates */
 	NULL,					/* install_package */
 	NULL,					/* install_name */
-	backend_refresh_cache,			/* refresh_cache */
+	python_refresh_cache,			/* refresh_cache */
 	NULL,					/* remove_package */
 	NULL,					/* resolve */
 	NULL,					/* rollback */
diff --git a/backends/apt/python-backend-common.cpp b/backends/apt/python-backend-common.cpp
new file mode 100644
index 0000000..cfc82c7
--- /dev/null
+++ b/backends/apt/python-backend-common.cpp
@@ -0,0 +1,38 @@
+/* -*- Mode: C; tab-width: 8; indent-tabs-mode: t; c-basic-offset: 8 -*-
+ *
+ * Copyright (C) 2007 Tom Parker <palfrey at tevp.net>
+ *
+ * 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; version 2 of the License.
+ * 
+ * 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 <pk-backend.h>
+
+/**
+ * python_refresh_cache:
+ **/
+void python_refresh_cache(PkBackend * backend, gboolean force)
+{
+	/* 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);
+		return;
+	}
+
+	pk_backend_spawn_helper (backend, "refresh-cache.py", NULL);
+}
+
diff --git a/backends/apt/python-backend-common.h b/backends/apt/python-backend-common.h
new file mode 100644
index 0000000..a7573cf
--- /dev/null
+++ b/backends/apt/python-backend-common.h
@@ -0,0 +1,27 @@
+/* -*- Mode: C; tab-width: 8; indent-tabs-mode: t; c-basic-offset: 8 -*-
+ *
+ * Copyright (C) 2007 Tom Parker <palfrey at tevp.net>
+ *
+ * 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; version 2 of the License.
+ * 
+ * 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 PYTHON_BACKEND_COMMON_H
+#define PYTHON_BACKEND_COMMON_H
+
+void python_refresh_cache(PkBackend * backend, gboolean force);
+
+#endif
+
diff-tree a635bb191b5a90bc14578adc3f264452d90ab601 (from af8de100f4ca9ac8edb8e85b071c90808e61ab19)
Author: Tom Parker <palfrey at tevp.net>
Date:   Wed Oct 10 17:56:12 2007 +0200

    Minor sqlite-pkg-cache fixes
    - Default package type is "unknown"
    - Drop packages before rebuild

diff --git a/backends/apt/sqlite-pkg-cache.cpp b/backends/apt/sqlite-pkg-cache.cpp
index 03c672d..1205676 100644
--- a/backends/apt/sqlite-pkg-cache.cpp
+++ b/backends/apt/sqlite-pkg-cache.cpp
@@ -39,24 +39,23 @@ void
 sqlite_init_cache(PkBackend *backend, const char* dbname, void (*build_db)(PkBackend *, sqlite3 *))
 {
 	gint ret;
-	sqlite3_stmt *complete;
 
 	ret = sqlite3_open (dbname, &db);
 	ret = sqlite3_exec(db,"PRAGMA synchronous = OFF",NULL,NULL,NULL);
 	g_assert(ret == SQLITE_OK);
-	sqlite3_prepare_v2("create table params (name text primary key, value integer)", -1, &complete, NULL)
 	ret = sqlite3_exec(db, "select value from params where name = 'build_complete'", NULL, NULL, NULL);
-	g_assert(ret == SQLITE_OK);
 	if (ret == SQLITE_ERROR)
 	{
-		sqlite3_exec(db,"create table packages (name text, version text, deps text, arch text, short_desc text, long_desc text, repo string, primary key(name,version,arch,repo))",NULL,NULL,NULL);
-		build_db(backend,db);
-	}
-	else
-	{
-		/*ret = sqlite3_exec(db,"delete from packages",NULL,NULL,NULL); // clear it!
+		ret = sqlite3_exec(db,"drop table packages",NULL,NULL,NULL); // wipe it!
+		//g_assert(ret == SQLITE_OK);
+		pk_debug("wiped db");
+		ret = sqlite3_exec(db,"create table packages (name text, version text, deps text, arch text, short_desc text, long_desc text, repo string, primary key(name,version,arch,repo))",NULL,NULL,NULL);
 		g_assert(ret == SQLITE_OK);
-		pk_debug("wiped db");*/
+
+		build_db(backend,db);
+
+		sqlite3_exec(db,"create table params (name text primary key, value integer)", NULL, NULL, NULL);
+		sqlite3_exec(db,"insert into params values ('build_complete',1)", NULL, NULL, NULL);
 	}
 }
 
@@ -87,7 +86,7 @@ sqlite_search_packages_thread (PkBackend
 				(const gchar*)sqlite3_column_text(package,1),
 				(const gchar*)sqlite3_column_text(package,2),
 				(const gchar*)sqlite3_column_text(package,3));
-		pk_backend_package(backend, FALSE, pid, (const gchar*)sqlite3_column_text(package,4));
+		pk_backend_package(backend, PK_INFO_ENUM_UNKNOWN, pid, (const gchar*)sqlite3_column_text(package,4));
 		g_free(pid);
 		if (res==SQLITE_ROW)
 			res = sqlite3_step(package);
diff-tree af8de100f4ca9ac8edb8e85b071c90808e61ab19 (from b923087aa63b879fd5dd075f0b5756925b934cf0)
Author: Tom Parker <palfrey at tevp.net>
Date:   Wed Oct 10 17:52:16 2007 +0200

    Look for local as well as global backend helpers

diff --git a/src/pk-backend.c b/src/pk-backend.c
index fa43869..242c5cc 100644
--- a/src/pk-backend.c
+++ b/src/pk-backend.c
@@ -487,7 +487,11 @@ pk_backend_spawn_helper_internal (PkBack
 	gchar *command;
 
 	/* build script */
-	filename = g_build_filename (DATADIR, "PackageKit", "helpers", backend->priv->name, script, NULL);
+	filename = g_build_filename ("..", "backends", backend->priv->name, "helpers", script, NULL);
+	if (g_file_test (filename, G_FILE_TEST_EXISTS) == FALSE) {
+		g_free (filename);
+		filename = g_build_filename (DATADIR, "PackageKit", "helpers", backend->priv->name, script, NULL);
+	}
 	pk_debug ("using spawn filename %s", filename);
 
 	if (argument != NULL) {
diff-tree b923087aa63b879fd5dd075f0b5756925b934cf0 (from 75b824ca71130c2d37e2a3e192fd80be19f2b540)
Author: Tom Parker <palfrey at tevp.net>
Date:   Wed Oct 10 19:09:24 2007 +0200

    Add sqlite_get_description
    Drop old libapt-based description grabbing in favour of a new and
    improved sqlite-cache based one.

diff --git a/backends/apt/pk-backend-apt.cpp b/backends/apt/pk-backend-apt.cpp
index d08fd33..29d7ec8 100644
--- a/backends/apt/pk-backend-apt.cpp
+++ b/backends/apt/pk-backend-apt.cpp
@@ -23,40 +23,25 @@
 #include <gmodule.h>
 #include <glib.h>
 #include <glib/gprintf.h>
+
+#include <math.h>
 #include <string.h>
+
 #include <pk-backend.h>
 #include <pk-debug.h>
 #include <pk-package-id.h>
 #include "config.h"
 
-#include <apt-pkg/pkgcachegen.h>
-#include <apt-pkg/pkgcache.h>
-#include <apt-pkg/cachefile.h>
-#include <apt-pkg/progress.h>
 #include <apt-pkg/configuration.h>
 #include <apt-pkg/init.h>
-#include <apt-pkg/pkgrecords.h>
-#include <apt-pkg/sourcelist.h>
-#include <apt-pkg/error.h>
-#include <apt-pkg/acquire.h>
-#include <apt-pkg/acquire-item.h>
-
-#include <string.h>
-#include <math.h>
 
 #include "pk-backend-apt.h"
 #include "sqlite-pkg-cache.h"
 
-static pkgCacheFile *fileCache = NULL;
-static pkgSourceList *SrcList = 0;
 static gboolean inited = FALSE;
 
 #define APT_DB DATABASEDIR "/apt.db"
 
-struct desc_task {
-	PkPackageId *pi;
-};
-
 static void backend_initialize(PkBackend *backend)
 {
 	if (!inited)
@@ -65,38 +50,11 @@ static void backend_initialize(PkBackend
 			pk_debug("pkginitconfig was false");
 		if (pkgInitSystem(*_config, _system) == false)
 			pk_debug("pkginitsystem was false");
-		init_sqlite_cache(backend, APT_DB, apt_build_db);
+		sqlite_init_cache(backend, APT_DB, apt_build_db);
 		inited = TRUE;
 	}
 }
 
-static pkgCacheFile *getCache(PkBackend *backend)
-{
-	if (fileCache == NULL)
-	{
-		MMap *Map = 0;
-		OpTextProgress Prog;
-		// Open the cache file
-		SrcList = new pkgSourceList;
-		SrcList->ReadMainList();
-
-		// Generate it and map it
-		pkgMakeStatusCache(*SrcList, Prog, &Map, true);
-
-		fileCache = new pkgCacheFile();
-
-		if (fileCache->Open(Prog, FALSE) == FALSE)
-		{
-			pk_debug("I need more privelges");
-			fileCache->Close();
-			fileCache = NULL;
-		}
-		else
-			pk_debug("cache inited");
-	}
-	return fileCache;
-}
-
 /**
  * backend_get_groups:
  */
@@ -141,121 +99,6 @@ static void backend_refresh_cache(PkBack
 	pk_backend_spawn_helper (backend, "refresh-cache.py", NULL);
 }
 
-static GHashTable *PackageRecord(PkBackend *backend, pkgCache::VerIterator V)
-{
-	GHashTable *ret = NULL;
-
-	pkgCache & pkgCache = *(getCache(backend));
-	// Find an appropriate file
-	pkgCache::VerFileIterator Vf = V.FileList();
-	for (; Vf.end() == false; Vf++)
-	{
-		if ((Vf.File()->Flags & pkgCache::Flag::NotSource) == 0)
-			break;
-		if (Vf.end() == true)
-			Vf = V.FileList();
-	}
-
-	// Check and load the package list file
-	pkgCache::PkgFileIterator I = Vf.File();
-	if (I.IsOk() == false)
-		return NULL;
-
-	FileFd PkgF(I.FileName(),FileFd::ReadOnly);
-	if (_error->PendingError() == true)
-		return NULL;
-
-	// Read the record
-	char *Buffer = new char[pkgCache.HeaderP->MaxVerFileSize+1];
-	Buffer[V.FileList()->Size] = '\0';
-	if (PkgF.Seek(V.FileList()->Offset) == false ||
-		 PkgF.Read(Buffer,V.FileList()->Size) == false)
-	{
-		delete [] Buffer;
-		return NULL;
-	}
-	//pk_debug("buffer: '%s'\n",Buffer);
-	ret = g_hash_table_new_full(g_str_hash,g_str_equal,g_free,g_free);
-	gchar ** lines = g_strsplit(Buffer,"\n",-1);
-	guint i;
-	for (i=0;i<g_strv_length(lines);i++)
-	{
-		gchar ** parts = g_strsplit_set(lines[i],": ",2);
-		if (g_strv_length(parts)>1)
-		{
-			//pk_debug("entry =  '%s' : '%s'",parts[0],parts[1]);
-			if (parts[0][0]=='\0')
-			{
-				gchar *oldval = g_strdup((const gchar*)g_hash_table_lookup(ret,"Description"));
-				g_hash_table_insert(ret,g_strdup("Description"),g_strconcat(oldval, "\n",parts[1],NULL));
-				//pk_debug("new entry =  '%s'",(const gchar*)g_hash_table_lookup(ret,"Description"));
-				g_free(oldval);
-			}
-			else
-				g_hash_table_insert(ret,g_strdup(parts[0]),g_strdup(parts[1]));
-		}
-		g_strfreev(parts);
-	}
-	g_strfreev(lines);
-	return ret;
-
-}
-
-// backend_get_description_thread
-static gboolean backend_get_description_thread (PkBackend *backend, gpointer data)
-{
-	desc_task *dt = (desc_task *) data;
-
-	pk_backend_change_status(backend, PK_STATUS_ENUM_QUERY);
-	pk_backend_no_percentage_updates(backend);
-
-	pk_debug("finding %s", dt->pi->name);
-	pkgCache & pkgCache = *(getCache(backend));
-	pkgDepCache::Policy Plcy;
-
-	// Map versions that we want to write out onto the VerList array.
-	for (pkgCache::PkgIterator P = pkgCache.PkgBegin(); P.end() == false; P++)
-	{
-		if (strcmp(dt->pi->name, P.Name())!=0)
-			continue;
-
-		// Find the proper version to use.
-		pkgCache::VerIterator V = Plcy.GetCandidateVer(P);
-		GHashTable *pkg = PackageRecord(backend,V);
-		pk_backend_description(backend,dt->pi->name,
-			"unknown", PK_GROUP_ENUM_OTHER,(const gchar*)g_hash_table_lookup(pkg,"Description"),"");
-		g_hash_table_unref(pkg);
-	}
-	return NULL;
-}
-
-/**
- * backend_get_description:
- */
-static void
-backend_get_description (PkBackend *backend, const gchar *package_id)
-{
-	g_return_if_fail (backend != NULL);
-	desc_task *data = g_new(struct desc_task, 1);
-	if (data == NULL)
-	{
-		pk_backend_error_code(backend, PK_ERROR_ENUM_OOM, "Failed to allocate memory for search task");
-		pk_backend_finished(backend);
-		return;
-	}
-
-	data->pi = pk_package_id_new_from_string(package_id);
-	if (data->pi == NULL)
-	{
-		pk_backend_error_code(backend, PK_ERROR_ENUM_PACKAGE_ID_INVALID, "invalid package id");
-		pk_backend_finished(backend);
-		return;
-	}
-
-	pk_backend_thread_helper (backend, backend_get_description_thread, data);
-	return;
-}
-
 static gboolean backend_search_file_thread (PkBackend *backend, gpointer data)
 {
 	//search_task *st = (search_task*)data;
@@ -300,7 +143,7 @@ extern "C" PK_BACKEND_OPTIONS (
 	backend_get_filters,			/* get_filters */
 	NULL,					/* cancel */
 	NULL,					/* get_depends */
-	backend_get_description,		/* get_description */
+	sqlite_get_description,		/* get_description */
 	NULL,					/* get_requires */
 	NULL,					/* get_update_detail */
 	NULL,					/* get_updates */
diff --git a/backends/apt/sqlite-pkg-cache.cpp b/backends/apt/sqlite-pkg-cache.cpp
index 5e90f8e..03c672d 100644
--- a/backends/apt/sqlite-pkg-cache.cpp
+++ b/backends/apt/sqlite-pkg-cache.cpp
@@ -25,35 +25,44 @@
 
 static sqlite3 *db = NULL;
 
+struct desc_task {
+	PkPackageId *pi;
+};
+
 struct search_task {
 	gchar *search;
 	gchar *filter;
 	SearchDepth depth;
 };
 
-void init_sqlite_cache(PkBackend *backend, const char* dbname, void (*build_db)(PkBackend *, sqlite3 *))
+void
+sqlite_init_cache(PkBackend *backend, const char* dbname, void (*build_db)(PkBackend *, sqlite3 *))
 {
 	gint ret;
-	char *errmsg = NULL;
+	sqlite3_stmt *complete;
+
 	ret = sqlite3_open (dbname, &db);
 	ret = sqlite3_exec(db,"PRAGMA synchronous = OFF",NULL,NULL,NULL);
 	g_assert(ret == SQLITE_OK);
-	sqlite3_exec(db,"create table packages (name text, version text, deps text, arch text, short_desc text, long_desc text, repo string, primary key(name,version,arch,repo))",NULL,NULL,&errmsg);
-	if (errmsg == NULL) // success, ergo didn't exist
+	sqlite3_prepare_v2("create table params (name text primary key, value integer)", -1, &complete, NULL)
+	ret = sqlite3_exec(db, "select value from params where name = 'build_complete'", NULL, NULL, NULL);
+	g_assert(ret == SQLITE_OK);
+	if (ret == SQLITE_ERROR)
 	{
+		sqlite3_exec(db,"create table packages (name text, version text, deps text, arch text, short_desc text, long_desc text, repo string, primary key(name,version,arch,repo))",NULL,NULL,NULL);
 		build_db(backend,db);
 	}
 	else
 	{
-		sqlite3_free(errmsg);
 		/*ret = sqlite3_exec(db,"delete from packages",NULL,NULL,NULL); // clear it!
 		g_assert(ret == SQLITE_OK);
 		pk_debug("wiped db");*/
 	}
 }
 
-// backend_search_packages_thread
-gboolean backend_search_packages_thread (PkBackend *backend, gpointer data)
+// sqlite_search_packages_thread
+static gboolean
+sqlite_search_packages_thread (PkBackend *backend, gpointer data)
 {
 	search_task *st = (search_task *) data;
 	int res;
@@ -118,21 +127,82 @@ backend_search_common(PkBackend * backen
 }
 
 /**
- * backend_search_details:
+ * sqlite_search_details:
  */
 void
 sqlite_search_details (PkBackend *backend, const gchar *filter, const gchar *search)
 {
-	backend_search_common(backend, filter, search, SEARCH_DETAILS, backend_search_packages_thread);
+	backend_search_common(backend, filter, search, SEARCH_DETAILS, sqlite_search_packages_thread);
 }
 
 /**
- * backend_search_name:
+ * sqlite_search_name:
  */
 void
 sqlite_search_name (PkBackend *backend, const gchar *filter, const gchar *search)
 {
-	backend_search_common(backend, filter, search, SEARCH_NAME, backend_search_packages_thread);
+	backend_search_common(backend, filter, search, SEARCH_NAME, sqlite_search_packages_thread);
+}
+
+// sqlite_get_description_thread
+static gboolean sqlite_get_description_thread (PkBackend *backend, gpointer data)
+{
+	desc_task *dt = (desc_task *) data;
+	int res;
+
+	pk_backend_change_status(backend, PK_STATUS_ENUM_QUERY);
+	pk_backend_no_percentage_updates(backend);
+
+	pk_debug("finding %s", dt->pi->name);
+
+	sqlite3_stmt *package = NULL;
+	gchar *sel = g_strdup_printf("select long_desc from packages where name = '%s' and version = '%s' and repo = '%s'",dt->pi->name,dt->pi->version,dt->pi->data);
+	pk_debug("statement is '%s'",sel);
+	res = sqlite3_prepare_v2(db,sel, -1, &package, NULL);
+	g_free(sel);
+	if (res!=SQLITE_OK)
+		pk_error("sqlite error during select prepare: %s", sqlite3_errmsg(db));
+	res = sqlite3_step(package);
+	pk_backend_description(backend,dt->pi->name, "unknown", PK_GROUP_ENUM_OTHER,(const gchar*)sqlite3_column_text(package,0),"",0,"");
+	res = sqlite3_step(package);
+	if (res==SQLITE_ROW)
+		pk_error("multiple matches for that package!");
+	if (res!=SQLITE_DONE)
+	{
+		pk_debug("sqlite error during step (%d): %s", res, sqlite3_errmsg(db));
+		g_assert(0);
+	}
+
+	g_free(dt);
+
+	return TRUE;
+}
+
+/**
+ * sqlite_get_description:
+ */
+void
+sqlite_get_description (PkBackend *backend, const gchar *package_id)
+{
+	g_return_if_fail (backend != NULL);
+	desc_task *data = g_new(struct desc_task, 1);
+	if (data == NULL)
+	{
+		pk_backend_error_code(backend, PK_ERROR_ENUM_OOM, "Failed to allocate memory for search task");
+		pk_backend_finished(backend);
+		return;
+	}
+
+	data->pi = pk_package_id_new_from_string(package_id);
+	if (data->pi == NULL)
+	{
+		pk_backend_error_code(backend, PK_ERROR_ENUM_PACKAGE_ID_INVALID, "invalid package id");
+		pk_backend_finished(backend);
+		return;
+	}
+
+	pk_backend_thread_helper (backend, sqlite_get_description_thread, data);
+	return;
 }
 
 
diff --git a/backends/apt/sqlite-pkg-cache.h b/backends/apt/sqlite-pkg-cache.h
index 99511bf..0cbadcd 100644
--- a/backends/apt/sqlite-pkg-cache.h
+++ b/backends/apt/sqlite-pkg-cache.h
@@ -30,9 +30,10 @@ typedef enum {
 
 #include <pk-backend.h>
 
-void init_sqlite_cache(PkBackend *backend, const char* dbname, void (*build_db)(PkBackend *, sqlite3 *db));
+void sqlite_init_cache(PkBackend *backend, const char* dbname, void (*build_db)(PkBackend *, sqlite3 *db));
 void sqlite_search_details (PkBackend *backend, const gchar *filter, const gchar *search);
 void sqlite_search_name (PkBackend *backend, const gchar *filter, const gchar *search);
 void backend_search_common(PkBackend * backend, const gchar * filter, const gchar * search, SearchDepth which, PkBackendThreadFunc func);
+void sqlite_get_description (PkBackend *backend, const gchar *package_id);
 
 #endif
diff-tree 75b824ca71130c2d37e2a3e192fd80be19f2b540 (from a2ed6f5baffd0a2e0053bbada29c64fc3ba8d071)
Author: Tom Parker <palfrey at tevp.net>
Date:   Wed Oct 10 17:58:11 2007 +0200

    Move to python refresh-cache for apt backend
    Given the lack of caching for the internal apt pointers between
    tasks, we're not gaining anything from a copy&paste of the
    internal apt update code, and so it's easier to just do callouts
    into python for the cache refresh.
    
    This also means we need a backends/apt/helpers folder, and the
    config changes for that

diff --git a/backends/apt/Makefile.am b/backends/apt/Makefile.am
index 82f364b..1c33f10 100644
--- a/backends/apt/Makefile.am
+++ b/backends/apt/Makefile.am
@@ -1,3 +1,4 @@
+SUBDIRS = helpers
 plugindir = @PK_PLUGIN_DIR@
 plugin_LTLIBRARIES = libpk_backend_apt.la
 libpk_backend_apt_la_INCLUDES = $(APT_CFLAGS) $(SQLITE_CFLAGS)
diff --git a/backends/apt/helpers/.gitignore b/backends/apt/helpers/.gitignore
new file mode 100644
index 0000000..d18402d
--- /dev/null
+++ b/backends/apt/helpers/.gitignore
@@ -0,0 +1,2 @@
+*.pyc
+.*.swp
diff --git a/backends/apt/helpers/Makefile.am b/backends/apt/helpers/Makefile.am
new file mode 100644
index 0000000..c14397e
--- /dev/null
+++ b/backends/apt/helpers/Makefile.am
@@ -0,0 +1,16 @@
+
+helperdir = $(datadir)/PackageKit/helpers/apt
+
+NULL =
+
+dist_helper_DATA = 			\
+	refresh-cache.py		\
+	aptBackend.py			\
+	$(NULL)
+
+install-data-hook:
+	chmod a+rx $(DESTDIR)$(helperdir)/*.py
+
+clean-local :
+	rm -f *~
+
diff --git a/backends/apt/helpers/aptBackend.py b/backends/apt/helpers/aptBackend.py
new file mode 100644
index 0000000..b2ca5cc
--- /dev/null
+++ b/backends/apt/helpers/aptBackend.py
@@ -0,0 +1,53 @@
+#!/usr/bin/python
+# 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; version 2 of the License
+#
+# 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 Library 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.
+#
+# Copyright (C) 2007 Tom Parker <palfrey at tevp.net>
+
+from packagekit.backend import *
+import apt
+
+class PackageKitProgress(apt.progress.OpProgress, apt.progress.FetchProgress):
+	def __init__(self, backend):
+		self.backend = backend
+
+	# OpProgress callbacks
+	def update(self, percent):
+		self.backend.percentage(percent)
+
+	def done(self):
+		self.backend.percentage(50.0)
+
+	# FetchProgress callbacks
+	def pulse(self):
+		apt.progress.FetchProgress.pulse(self)
+		self.backend.percentage(self.percent)
+
+	def stop(self):
+		print "self.inc (stop)"
+		self.backend.percentage(100)
+
+	def mediaChange(self, medium, drive):
+		self.backend.error(ERROR_INTERNAL_ERROR, "Needed to do a medium change!")
+
+class PackageKitAptBackend(PackageKitBaseBackend):
+	def refresh_cache(self):
+		'''
+		Implement the {backend}-refresh_cache functionality
+		'''
+		self.percentage(0)
+		pkp = PackageKitProgress(self)
+		cache = apt.Cache(pkp)
+		if cache.update(pkp) == False:
+			self.error(ERROR_INTERNAL_ERROR,"Fetch failure")
+
diff --git a/backends/apt/helpers/refresh-cache.py b/backends/apt/helpers/refresh-cache.py
new file mode 100755
index 0000000..5feb6e5
--- /dev/null
+++ b/backends/apt/helpers/refresh-cache.py
@@ -0,0 +1,22 @@
+#!/usr/bin/python
+#
+# Apt refresh-cache handler. Modified from the yum handler
+#
+# Copyright (C) 2007 Richard Hughes <richard at hughsie.com>
+# Copyright (C) 2007 Red Hat Inc, Seth Vidal <skvidal at fedoraproject.org>
+# Copyright (C) 2007 Tom Parker <palfrey at tevp.net>
+#
+# 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.
+
+import sys
+
+from aptBackend import PackageKitAptBackend
+
+backend = PackageKitAptBackend(sys.argv[1:])
+backend.refresh_cache()
+sys.exit(0)
diff --git a/backends/apt/pk-backend-apt.cpp b/backends/apt/pk-backend-apt.cpp
index f4955c9..d08fd33 100644
--- a/backends/apt/pk-backend-apt.cpp
+++ b/backends/apt/pk-backend-apt.cpp
@@ -97,144 +97,6 @@ static pkgCacheFile *getCache(PkBackend 
 	return fileCache;
 }
 
-class UpdatePercentage:public pkgAcquireStatus
-{
-	double old;
-	PkBackend *backend;
-
-	public:
-	UpdatePercentage(PkBackend *tk)
-	{
-		old = -1;
-		backend = tk;
-	}
-
-	virtual bool MediaChange(string Media,string Drive)
-	{
-		pk_debug("PANIC!: we don't handle mediachange");
-		return FALSE;
-	}
-
-	virtual bool Pulse(pkgAcquire *Owner)
-	{
-		pkgAcquireStatus::Pulse(Owner);
-		double percent = double(CurrentBytes*100.0)/double(TotalBytes);
-		if (old!=percent)
-		{
-			pk_backend_change_percentage(backend,(guint)percent);
-			pk_backend_change_sub_percentage(backend,((guint)(percent*100.0))%100);
-			old = percent;
-		}
-		return true;
-	}
-};
-
-// backend_refresh_cache_thread - Update the package lists
-// Swiped from apt-get's update mode
-static gboolean backend_refresh_cache_thread (PkBackend *backend, gpointer data)
-{
-	pkgCacheFile *Cache;
-	bool Failed = false;
-	bool TransientNetworkFailure = false;
-	OpTextProgress Prog;
-
-	/* easy as that */
-	pk_backend_change_status(backend, PK_STATUS_ENUM_REFRESH_CACHE);
-
-	Cache = getCache(backend);
-
-	// Get the source list
-	pkgSourceList List;
-	if (List.ReadMainList() == false)
-	{
-		pk_backend_error_code(backend, PK_ERROR_ENUM_UNKNOWN, "Failure reading lists");
-		return FALSE;
-	}
-
-	// Lock the list directory
-	FileFd Lock;
-	if (_config->FindB("Debug::NoLocking", false) == false)
-	{
-		Lock.Fd(GetLock(_config->FindDir("Dir::State::Lists") + "lock"));
-		if (_error->PendingError() == true)
-		{
-			_error->DumpErrors();
-			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(backend);
-	pkgAcquire Fetcher(Stat);
-
-	// Populate it with the source selection
-	if (List.GetIndexes(&Fetcher) == false)
-	{
-		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(backend, PK_ERROR_ENUM_UNKNOWN, "Failed to run the fetcher");
-		goto do_update_clean;
-	}
-
-	for (pkgAcquire::ItemIterator I = Fetcher.ItemsBegin(); I != Fetcher.ItemsEnd(); I++)
-	{
-		if ((*I)->Status == pkgAcquire::Item::StatDone)
-			continue;
-
-		(*I)->Finished();
-
-		fprintf(stderr, "Failed to fetch %s  %s\n", (*I)->DescURI().c_str(), (*I)->ErrorText.c_str());
-
-		if ((*I)->Status == pkgAcquire::Item::StatTransientNetworkError)
-		{
-			TransientNetworkFailure = true;
-			continue;
-		}
-
-		Failed = true;
-	}
-
-	// Clean out any old list files
-	if (!TransientNetworkFailure && _config->FindB("APT::Get::List-Cleanup", true) == true)
-	{
-		if (Fetcher.Clean(_config->FindDir("Dir::State::lists")) == false ||
-		    Fetcher.Clean(_config->FindDir("Dir::State::lists") + "partial/") == false)
-		{
-			pk_backend_error_code(backend, PK_ERROR_ENUM_UNKNOWN, "Failed to clean out any old list files");
-			goto do_update_clean;
-		}
-	}
-
-	// Prepare the cache.
-	Cache = getCache(backend);
-	if (Cache->BuildCaches(Prog,false) == false)
-	{
-		pk_backend_error_code(backend, PK_ERROR_ENUM_UNKNOWN, "Failed to prepare the cache");
-		goto do_update_clean;
-	}
-
-	if (TransientNetworkFailure == true)
-		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(backend, PK_ERROR_ENUM_UNKNOWN, "Generic Error");
-		goto do_update_clean;
-	}
-
-	delete Stat;
-	return TRUE;
-
-	do_update_clean:
-	delete Stat;
-	return FALSE;
-}
-
 /**
  * backend_get_groups:
  */
@@ -276,7 +138,7 @@ static void backend_refresh_cache(PkBack
 		return;
 	}
 
-	pk_backend_thread_helper(backend, backend_refresh_cache_thread, NULL);
+	pk_backend_spawn_helper (backend, "refresh-cache.py", NULL);
 }
 
 static GHashTable *PackageRecord(PkBackend *backend, pkgCache::VerIterator V)
diff --git a/configure.ac b/configure.ac
index f945914..833c748 100644
--- a/configure.ac
+++ b/configure.ac
@@ -368,6 +368,7 @@ docs/Makefile
 backends/Makefile
 backends/alpm/Makefile
 backends/apt/Makefile
+backends/apt/helpers/Makefile
 backends/box/Makefile
 backends/box/helpers/Makefile
 backends/conary/Makefile
diff-tree a2ed6f5baffd0a2e0053bbada29c64fc3ba8d071 (from 8ae7eeb02211070c10b4a39577ec0cebf695c202)
Author: Tom Parker <palfrey at tevp.net>
Date:   Thu Sep 27 20:39:13 2007 +0200

    Handle full descriptions in apt sqlite builder

diff --git a/backends/apt/apt-build-db.cpp b/backends/apt/apt-build-db.cpp
index 602f5a6..54fe28a 100644
--- a/backends/apt/apt-build-db.cpp
+++ b/backends/apt/apt-build-db.cpp
@@ -203,6 +203,14 @@ void apt_build_db(PkBackend * backend, s
 				{
 					if (haspk)
 					{
+						if (description!=NULL)
+						{
+							res=sqlite3_bind_text(package,FIELD_LONG,description,-1,SQLITE_TRANSIENT);
+							if (res!=SQLITE_OK)
+								pk_error("sqlite error during description bind: %s", sqlite3_errmsg(db));
+							g_free(description);
+							description = NULL;
+						}
 						res = sqlite3_step(package);
 						if (res!=SQLITE_DONE)
 							pk_error("sqlite error during step: %s", sqlite3_errmsg(db));
@@ -214,10 +222,14 @@ void apt_build_db(PkBackend * backend, s
 				}
 				else if (begin[0]==' ')
 				{
-					/*gchar *oldval = g_strdup((const gchar*)g_hash_table_lookup(ret,"Description"));
-					g_hash_table_insert(ret,g_strdup("Description"),g_strconcat(oldval, "\n",parts[1],NULL));
-					//pk_debug("new entry =  '%s'",(const gchar*)g_hash_table_lookup(ret,"Description"));
-					g_free(oldval);*/
+					if (description == NULL)
+						description = g_strdup(&begin[1]);
+					else
+					{
+						gchar *oldval = description;
+						description = g_strconcat(oldval, "\n",&begin[1],NULL);
+						g_free(oldval);
+					}
 				}
 				else
 				{
diff-tree 8ae7eeb02211070c10b4a39577ec0cebf695c202 (from ac4809e980c5d4fa587c14050c85a07ee9ad9958)
Author: Tom Parker <palfrey at tevp.net>
Date:   Wed Oct 10 19:08:15 2007 +0200

    Cleanup variable usage in apt_build_db
    apt_build_db now specifies variables earlier on in a C-style
    way vs. the earlier use of C++-style mid-function declarations
    Also, the deprecated "version" and "description" regexes are
    removed, and the insert statement is generated earlier.
    
    Plus fix potential build_apt_db crash

diff --git a/backends/apt/apt-build-db.cpp b/backends/apt/apt-build-db.cpp
index 8b46002..602f5a6 100644
--- a/backends/apt/apt-build-db.cpp
+++ b/backends/apt/apt-build-db.cpp
@@ -32,9 +32,11 @@ void apt_build_db(PkBackend * backend, s
 	gchar *contents = NULL;
 	gchar *sdir;
 	const gchar *fname;
-	GRegex *origin, *suite, *version, *description;
+	GRegex *origin, *suite;
 	GDir *dir;
 	GHashTable *releases;
+	int res;
+	sqlite3_stmt *package = NULL;
 
 	pk_backend_change_status(backend, PK_STATUS_ENUM_QUERY);
 	pk_backend_no_percentage_updates(backend);
@@ -51,9 +53,6 @@ void apt_build_db(PkBackend * backend, s
 	origin = g_regex_new("^Origin: (\\S+)",(GRegexCompileFlags)(G_REGEX_CASELESS|G_REGEX_OPTIMIZE|G_REGEX_MULTILINE),(GRegexMatchFlags)0,NULL);
 	suite = g_regex_new("^Suite: (\\S+)",(GRegexCompileFlags)(G_REGEX_CASELESS|G_REGEX_OPTIMIZE|G_REGEX_MULTILINE),(GRegexMatchFlags)0,NULL);
 
-	version = g_regex_new("^Version: (.*)",(GRegexCompileFlags)(G_REGEX_CASELESS|G_REGEX_OPTIMIZE|G_REGEX_MULTILINE),(GRegexMatchFlags)0,NULL);
-	description = g_regex_new("^Description: (.*)",(GRegexCompileFlags)(G_REGEX_CASELESS|G_REGEX_OPTIMIZE|G_REGEX_MULTILINE),(GRegexMatchFlags)0,NULL);
-
 	releases = g_hash_table_new_full(g_str_hash,g_str_equal,g_free,g_free);
 	while ((fname = g_dir_read_name(dir))!=NULL)
 	{
@@ -117,6 +116,11 @@ void apt_build_db(PkBackend * backend, s
 
 	/* and then we need to do this again, but this time we're looking for the packages */
 	dir = g_dir_open(sdir,0,&error);
+	res = sqlite3_prepare_v2(db, "insert or replace into packages values (?,?,?,?,?,?,?)", -1, &package, NULL);
+	if (res!=SQLITE_OK)
+		pk_error("sqlite error during insert prepare: %s", sqlite3_errmsg(db));
+	else
+		pk_debug("insert prepare ok for %p",package);
 	while ((fname = g_dir_read_name(dir))!=NULL)
 	{
 		gchar** items = g_strsplit(fname,"_",-1);
@@ -130,8 +134,12 @@ void apt_build_db(PkBackend * backend, s
 		if (g_ascii_strcasecmp(items[len-1],"Packages")==0)
 		{
 			const gchar *repo;
-			gchar *temp, *parsed_name;
-			gchar *fullname;
+			gchar *temp=NULL, *parsed_name=NULL;
+			gchar *fullname= NULL;
+			gchar *begin=NULL, *next=NULL, *description = NULL;
+			glong count = 0;
+			gboolean haspk = FALSE;
+
 			/* warning: nasty hack with g_strjoinv */
 			if (g_str_has_prefix(items[len-2],"binary-"))
 			{
@@ -168,21 +176,19 @@ void apt_build_db(PkBackend * backend, s
 				pk_backend_error_code(backend, PK_ERROR_ENUM_INTERNAL_ERROR, "error loading %s",fullname);
 				goto search_task_cleanup;
 			}
-			gchar *begin = contents, *next;
-			glong count = 0;
+			/*else
+				pk_debug("loaded");*/
 
-			sqlite3_stmt *package = NULL;
-			int res;
-			res = sqlite3_prepare_v2(db, "insert or replace into packages values (?,?,?,?,?,?,?)", -1, &package, NULL);
-			if (res!=SQLITE_OK)
-				pk_error("sqlite error during insert prepare: %s", sqlite3_errmsg(db));
-			res = sqlite3_bind_text(package,FIELD_REPO,repo,-1,SQLITE_STATIC);
+			res = sqlite3_bind_text(package,FIELD_REPO,repo,-1,SQLITE_TRANSIENT);
 			if (res!=SQLITE_OK)
 				pk_error("sqlite error during repo bind: %s", sqlite3_errmsg(db));
+			/*else
+				pk_debug("repo bind ok");*/
 
-			gboolean haspk = FALSE;
+			res = sqlite3_exec(db,"begin",NULL,NULL,NULL);
+			g_assert(res == SQLITE_OK);
 
-			sqlite3_exec(db,"begin",NULL,NULL,NULL);
+			begin = contents;
 
 			while (true)
 			{
@@ -221,7 +227,6 @@ void apt_build_db(PkBackend * backend, s
 					colon+=2;
 					/*if (strlen(colon)>3000)
 						pk_error("strlen(colon) = %d\ncolon = %s",strlen(colon),colon);*/
-					//typedef enum {FIELD_PKG=0,FIELD_VER,FIELD_DEPS,FIELD_ARCH,FIELD_SHORT,FIELD_LONG,FIELD_REPO} Fields;
 					//pk_debug("entry = '%s','%s'",begin,colon);
 					if (begin[0] == 'P' && g_strcasecmp("Package",begin)==0)
 					{
@@ -246,11 +251,17 @@ void apt_build_db(PkBackend * backend, s
 					break;
 				begin = next;	
 			}
-			sqlite3_exec(db,"commit",NULL,NULL,NULL);
+			res = sqlite3_exec(db,"commit",NULL,NULL,NULL);
+			if (res!=SQLITE_OK)
+				pk_error("sqlite error during commit: %s", sqlite3_errmsg(db));
+			res = sqlite3_clear_bindings(package);
+			if (res!=SQLITE_OK)
+				pk_error("sqlite error during clear: %s", sqlite3_errmsg(db));
 			g_free(contents);
 			contents = NULL;
 		}
 	}
+	sqlite3_finalize(package);
 
 search_task_cleanup:
 	g_dir_close(dir);
diff-tree ac4809e980c5d4fa587c14050c85a07ee9ad9958 (from f95e81b62827cee1a59041e859c5cd0449bdd771)
Author: Tom Parker <palfrey at tevp.net>
Date:   Wed Oct 10 17:56:43 2007 +0200

    Separate all of the sqlite caching from apt stuff
    The apt backend is now separated into 5 files (vs. 2 before)
    - sqlite-pkg-cache.{cc,h}
    	Generic sqlite cache searching and initialisation
    	Can possibly be folded into the PackageKit core at some
    	point in the future.
    - apt-build-db.cc
    	Apt-specific sqlite cache builder
    - pk-backend-apt.{cc,h}
    	Everything else

diff --git a/backends/apt/Makefile.am b/backends/apt/Makefile.am
index 622f703..82f364b 100644
--- a/backends/apt/Makefile.am
+++ b/backends/apt/Makefile.am
@@ -1,8 +1,8 @@
 plugindir = @PK_PLUGIN_DIR@
 plugin_LTLIBRARIES = libpk_backend_apt.la
-libpk_backend_apt_la_INCLUDES = $(APT_CFLAGS)
-libpk_backend_apt_la_SOURCES = pk-backend-apt.cpp
-libpk_backend_apt_la_LIBADD = @PK_PLUGIN_LIBS@ $(APT_LIBS)
+libpk_backend_apt_la_INCLUDES = $(APT_CFLAGS) $(SQLITE_CFLAGS)
+libpk_backend_apt_la_SOURCES = pk-backend-apt.cpp sqlite-pkg-cache.cpp apt-build-db.cpp
+libpk_backend_apt_la_LIBADD = @PK_PLUGIN_LIBS@ $(APT_LIBS) $(SQLITE_LIBS)
 libpk_backend_apt_la_LDFLAGS = -module -avoid-version
 libpk_backend_apt_la_CXXFLAGS = @PK_PLUGIN_CFLAGS@ -DDATABASEDIR=\""$(PK_DB_DIR)"\"
 
diff --git a/backends/apt/apt-build-db.cpp b/backends/apt/apt-build-db.cpp
new file mode 100644
index 0000000..8b46002
--- /dev/null
+++ b/backends/apt/apt-build-db.cpp
@@ -0,0 +1,260 @@
+/* -*- Mode: C; tab-width: 8; indent-tabs-mode: t; c-basic-offset: 8 -*-
+ *
+ * Copyright (C) 2007 Tom Parker <palfrey at tevp.net>
+ *
+ * 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 "pk-backend-apt.h"
+#include <apt-pkg/configuration.h>
+#include <sqlite3.h>
+
+typedef enum {FIELD_PKG=1,FIELD_VER,FIELD_DEPS,FIELD_ARCH,FIELD_SHORT,FIELD_LONG,FIELD_REPO} Fields;
+
+void apt_build_db(PkBackend * backend, sqlite3 *db)
+{
+	GMatchInfo *match_info;
+	GError *error = NULL;
+	gchar *contents = NULL;
+	gchar *sdir;
+	const gchar *fname;
+	GRegex *origin, *suite, *version, *description;
+	GDir *dir;
+	GHashTable *releases;
+
+	pk_backend_change_status(backend, PK_STATUS_ENUM_QUERY);
+	pk_backend_no_percentage_updates(backend);
+
+	sdir = g_build_filename(_config->Find("Dir").c_str(),_config->Find("Dir::State").c_str(),_config->Find("Dir::State::lists").c_str(), NULL);
+	dir = g_dir_open(sdir,0,&error);
+	if (error!=NULL)
+	{
+		pk_backend_error_code(backend, PK_ERROR_ENUM_INTERNAL_ERROR, "can't open %s",dir);
+		g_error_free(error);
+		goto search_task_cleanup;
+	}
+
+	origin = g_regex_new("^Origin: (\\S+)",(GRegexCompileFlags)(G_REGEX_CASELESS|G_REGEX_OPTIMIZE|G_REGEX_MULTILINE),(GRegexMatchFlags)0,NULL);
+	suite = g_regex_new("^Suite: (\\S+)",(GRegexCompileFlags)(G_REGEX_CASELESS|G_REGEX_OPTIMIZE|G_REGEX_MULTILINE),(GRegexMatchFlags)0,NULL);
+
+	version = g_regex_new("^Version: (.*)",(GRegexCompileFlags)(G_REGEX_CASELESS|G_REGEX_OPTIMIZE|G_REGEX_MULTILINE),(GRegexMatchFlags)0,NULL);
+	description = g_regex_new("^Description: (.*)",(GRegexCompileFlags)(G_REGEX_CASELESS|G_REGEX_OPTIMIZE|G_REGEX_MULTILINE),(GRegexMatchFlags)0,NULL);
+
+	releases = g_hash_table_new_full(g_str_hash,g_str_equal,g_free,g_free);
+	while ((fname = g_dir_read_name(dir))!=NULL)
+	{
+		gchar *temp, *parsed_name;
+		gchar** items = g_strsplit(fname,"_",-1);
+		guint len = g_strv_length(items);
+		if(len<=3) // minimum is <source>_<type>_<group>
+		{
+			g_strfreev(items);
+			continue;
+		}
+		
+		/* warning: nasty hack with g_strjoinv */
+		temp = items[len-2];
+		items[len-2] = NULL;
+		parsed_name = g_strjoinv("_",items);
+		items[len-2] = temp;
+		
+		if (g_ascii_strcasecmp(items[len-1],"Release")==0 && g_ascii_strcasecmp(items[len-2],"source")!=0)
+		{
+			gchar * repo = NULL, *fullname;
+			fullname = g_build_filename(sdir,fname,NULL);
+			if (g_file_get_contents(fullname,&contents,NULL,NULL) == FALSE)
+			{
+				pk_backend_error_code(backend, PK_ERROR_ENUM_INTERNAL_ERROR, "error loading %s",fullname);
+				goto search_task_cleanup;
+			}
+			g_free(fullname);
+
+			g_regex_match (origin, contents, (GRegexMatchFlags)0, &match_info);
+			if (!g_match_info_matches(match_info))
+			{
+				pk_backend_error_code(backend, PK_ERROR_ENUM_INTERNAL_ERROR, "origin regex failure in %s",fname);
+				goto search_task_cleanup;
+			}
+			repo = g_match_info_fetch (match_info, 1);
+
+			g_regex_match (suite, contents, (GRegexMatchFlags)0, &match_info);
+			if (g_match_info_matches(match_info))
+			{
+				temp = g_strconcat(repo,"/",g_match_info_fetch (match_info, 1),NULL);
+				g_free(repo);
+				repo = temp;
+			}
+
+			temp = parsed_name;
+			parsed_name = g_strconcat(temp,"_",items[len-2],NULL);
+			g_free(temp);
+
+			pk_debug("type is %s, group is %s, parsed_name is %s",items[len-2],items[len-1],parsed_name);
+
+			g_hash_table_insert(releases, parsed_name, repo);
+			g_free(contents);
+			contents = NULL;
+		}
+		else
+			g_free(parsed_name);
+		g_strfreev(items);
+	}
+	g_dir_close(dir);
+
+	/* and then we need to do this again, but this time we're looking for the packages */
+	dir = g_dir_open(sdir,0,&error);
+	while ((fname = g_dir_read_name(dir))!=NULL)
+	{
+		gchar** items = g_strsplit(fname,"_",-1);
+		guint len = g_strv_length(items);
+		if(len<=3) // minimum is <source>_<type>_<group>
+		{
+			g_strfreev(items);
+			continue;
+		}
+
+		if (g_ascii_strcasecmp(items[len-1],"Packages")==0)
+		{
+			const gchar *repo;
+			gchar *temp, *parsed_name;
+			gchar *fullname;
+			/* warning: nasty hack with g_strjoinv */
+			if (g_str_has_prefix(items[len-2],"binary-"))
+			{
+				temp = items[len-3];
+				items[len-3] = NULL;
+				parsed_name = g_strjoinv("_",items);
+				items[len-3] = temp;
+			}
+			else
+			{
+				temp = items[len-1];
+				items[len-1] = NULL;
+				parsed_name = g_strjoinv("_",items);
+				items[len-1] = temp;
+			}
+			
+			pk_debug("type is %s, group is %s, parsed_name is %s",items[len-2],items[len-1],parsed_name);
+			
+			repo = (const gchar *)g_hash_table_lookup(releases,parsed_name);
+			if (repo == NULL)
+			{
+				pk_debug("Can't find repo for %s, marking as \"unknown\"",parsed_name);
+				repo = g_strdup("unknown");
+				//g_assert(0);
+			}
+			else
+				pk_debug("repo for %s is %s",parsed_name,repo);
+			g_free(parsed_name);
+
+			fullname = g_build_filename(sdir,fname,NULL);
+			pk_debug("loading %s",fullname);
+			if (g_file_get_contents(fullname,&contents,NULL,NULL) == FALSE)
+			{
+				pk_backend_error_code(backend, PK_ERROR_ENUM_INTERNAL_ERROR, "error loading %s",fullname);
+				goto search_task_cleanup;
+			}
+			gchar *begin = contents, *next;
+			glong count = 0;
+
+			sqlite3_stmt *package = NULL;
+			int res;
+			res = sqlite3_prepare_v2(db, "insert or replace into packages values (?,?,?,?,?,?,?)", -1, &package, NULL);
+			if (res!=SQLITE_OK)
+				pk_error("sqlite error during insert prepare: %s", sqlite3_errmsg(db));
+			res = sqlite3_bind_text(package,FIELD_REPO,repo,-1,SQLITE_STATIC);
+			if (res!=SQLITE_OK)
+				pk_error("sqlite error during repo bind: %s", sqlite3_errmsg(db));
+
+			gboolean haspk = FALSE;
+
+			sqlite3_exec(db,"begin",NULL,NULL,NULL);
+
+			while (true)
+			{
+				next = strstr(begin,"\n");
+				if (next!=NULL)
+				{
+					next[0] = '\0';
+					next++;
+				}
+
+				if (begin[0]=='\0')
+				{
+					if (haspk)
+					{
+						res = sqlite3_step(package);
+						if (res!=SQLITE_DONE)
+							pk_error("sqlite error during step: %s", sqlite3_errmsg(db));
+						sqlite3_reset(package);
+						//pk_debug("added package");
+						haspk = FALSE;
+					}
+					//g_assert(0);
+				}
+				else if (begin[0]==' ')
+				{
+					/*gchar *oldval = g_strdup((const gchar*)g_hash_table_lookup(ret,"Description"));
+					g_hash_table_insert(ret,g_strdup("Description"),g_strconcat(oldval, "\n",parts[1],NULL));
+					//pk_debug("new entry =  '%s'",(const gchar*)g_hash_table_lookup(ret,"Description"));
+					g_free(oldval);*/
+				}
+				else
+				{
+					gchar *colon = strchr(begin,':');
+					g_assert(colon!=NULL);
+					colon[0] = '\0';
+					colon+=2;
+					/*if (strlen(colon)>3000)
+						pk_error("strlen(colon) = %d\ncolon = %s",strlen(colon),colon);*/
+					//typedef enum {FIELD_PKG=0,FIELD_VER,FIELD_DEPS,FIELD_ARCH,FIELD_SHORT,FIELD_LONG,FIELD_REPO} Fields;
+					//pk_debug("entry = '%s','%s'",begin,colon);
+					if (begin[0] == 'P' && g_strcasecmp("Package",begin)==0)
+					{
+						res=sqlite3_bind_text(package,FIELD_PKG,colon,-1,SQLITE_STATIC);
+						haspk = TRUE;
+						count++;
+						if (count%1000==0)
+							pk_debug("Package %ld (%s)",count,colon);
+					}
+					else if (begin[0] == 'V' && g_strcasecmp("Version",begin)==0)
+						res=sqlite3_bind_text(package,FIELD_VER,colon,-1,SQLITE_STATIC);
+					else if (begin[0] == 'D' && g_strcasecmp("Depends",begin)==0)
+						res=sqlite3_bind_text(package,FIELD_DEPS,colon,-1,SQLITE_STATIC);
+					else if (begin[0] == 'A' && g_strcasecmp("Architecture",begin)==0)
+						res=sqlite3_bind_text(package,FIELD_ARCH,colon,-1,SQLITE_STATIC);
+					else if (begin[0] == 'D' && g_strcasecmp("Description",begin)==0)
+						res=sqlite3_bind_text(package,FIELD_SHORT,colon,-1,SQLITE_STATIC);
+					if (res!=SQLITE_OK)
+						pk_error("sqlite error during %s bind: %s", begin, sqlite3_errmsg(db));
+				}
+				if (next == NULL)
+					break;
+				begin = next;	
+			}
+			sqlite3_exec(db,"commit",NULL,NULL,NULL);
+			g_free(contents);
+			contents = NULL;
+		}
+	}
+
+search_task_cleanup:
+	g_dir_close(dir);
+	g_free(sdir);
+	g_free(contents);
+}
+
diff --git a/backends/apt/pk-backend-apt.cpp b/backends/apt/pk-backend-apt.cpp
index ca08bae..f4955c9 100644
--- a/backends/apt/pk-backend-apt.cpp
+++ b/backends/apt/pk-backend-apt.cpp
@@ -1,6 +1,7 @@
 /* -*- Mode: C; tab-width: 8; indent-tabs-mode: t; c-basic-offset: 8 -*-
  *
  * Copyright (C) 2007 Richard Hughes <richard at hughsie.com>
+ * Copyright (C) 2007 Tom Parker <palfrey at tevp.net>
  *
  * Licensed under the GNU General Public License Version 2
  *
@@ -42,300 +43,29 @@
 
 #include <string.h>
 #include <math.h>
-#include <sqlite3.h>
+
+#include "pk-backend-apt.h"
+#include "sqlite-pkg-cache.h"
 
 static pkgCacheFile *fileCache = NULL;
 static pkgSourceList *SrcList = 0;
 static gboolean inited = FALSE;
-static sqlite3 *db = NULL;
 
 #define APT_DB DATABASEDIR "/apt.db"
 
-typedef enum {
-	SEARCH_NAME = 1,
-	SEARCH_DETAILS,
-	SEARCH_FILE
-} SearchDepth;
-
-struct search_task {
-	gchar *search;
-	gchar *filter;
-	SearchDepth depth;
-};
-
 struct desc_task {
 	PkPackageId *pi;
 };
 
-#ifdef APT_PKG_RPM
-typedef pkgCache::VerFile AptCompFile;
-#elif defined(APT_PKG_DEB)
-typedef pkgCache::DescFile AptCompFile;
-#else
-#error Need either rpm or deb defined
-#endif
-
-typedef enum {FIELD_PKG=1,FIELD_VER,FIELD_DEPS,FIELD_ARCH,FIELD_SHORT,FIELD_LONG,FIELD_REPO} Fields;
-
-static void build_db(PkBackend * backend)
-{
-	GMatchInfo *match_info;
-	GError *error = NULL;
-	gchar *contents = NULL;
-	gchar *sdir;
-	const gchar *fname;
-	GRegex *origin, *suite, *version, *description;
-	GDir *dir;
-	GHashTable *releases;
-
-	pk_backend_change_status(backend, PK_STATUS_ENUM_QUERY);
-	pk_backend_no_percentage_updates(backend);
-
-	sdir = g_build_filename(_config->Find("Dir").c_str(),_config->Find("Dir::State").c_str(),_config->Find("Dir::State::lists").c_str(), NULL);
-	dir = g_dir_open(sdir,0,&error);
-	if (error!=NULL)
-	{
-		pk_backend_error_code(backend, PK_ERROR_ENUM_INTERNAL_ERROR, "can't open %s",dir);
-		g_error_free(error);
-		goto search_task_cleanup;
-	}
-
-	origin = g_regex_new("^Origin: (\\S+)",(GRegexCompileFlags)(G_REGEX_CASELESS|G_REGEX_OPTIMIZE|G_REGEX_MULTILINE),(GRegexMatchFlags)0,NULL);
-	suite = g_regex_new("^Suite: (\\S+)",(GRegexCompileFlags)(G_REGEX_CASELESS|G_REGEX_OPTIMIZE|G_REGEX_MULTILINE),(GRegexMatchFlags)0,NULL);
-
-	version = g_regex_new("^Version: (.*)",(GRegexCompileFlags)(G_REGEX_CASELESS|G_REGEX_OPTIMIZE|G_REGEX_MULTILINE),(GRegexMatchFlags)0,NULL);
-	description = g_regex_new("^Description: (.*)",(GRegexCompileFlags)(G_REGEX_CASELESS|G_REGEX_OPTIMIZE|G_REGEX_MULTILINE),(GRegexMatchFlags)0,NULL);
-
-	releases = g_hash_table_new_full(g_str_hash,g_str_equal,g_free,g_free);
-	while ((fname = g_dir_read_name(dir))!=NULL)
-	{
-		gchar *temp, *parsed_name;
-		gchar** items = g_strsplit(fname,"_",-1);
-		guint len = g_strv_length(items);
-		if(len<=3) // minimum is <source>_<type>_<group>
-		{
-			g_strfreev(items);
-			continue;
-		}
-		
-		/* warning: nasty hack with g_strjoinv */
-		temp = items[len-2];
-		items[len-2] = NULL;
-		parsed_name = g_strjoinv("_",items);
-		items[len-2] = temp;
-		
-		if (g_ascii_strcasecmp(items[len-1],"Release")==0 && g_ascii_strcasecmp(items[len-2],"source")!=0)
-		{
-			gchar * repo = NULL, *fullname;
-			fullname = g_build_filename(sdir,fname,NULL);
-			if (g_file_get_contents(fullname,&contents,NULL,NULL) == FALSE)
-			{
-				pk_backend_error_code(backend, PK_ERROR_ENUM_INTERNAL_ERROR, "error loading %s",fullname);
-				goto search_task_cleanup;
-			}
-			g_free(fullname);
-
-			g_regex_match (origin, contents, (GRegexMatchFlags)0, &match_info);
-			if (!g_match_info_matches(match_info))
-			{
-				pk_backend_error_code(backend, PK_ERROR_ENUM_INTERNAL_ERROR, "origin regex failure in %s",fname);
-				goto search_task_cleanup;
-			}
-			repo = g_match_info_fetch (match_info, 1);
-
-			g_regex_match (suite, contents, (GRegexMatchFlags)0, &match_info);
-			if (g_match_info_matches(match_info))
-			{
-				temp = g_strconcat(repo,"/",g_match_info_fetch (match_info, 1),NULL);
-				g_free(repo);
-				repo = temp;
-			}
-
-			temp = parsed_name;
-			parsed_name = g_strconcat(temp,"_",items[len-2],NULL);
-			g_free(temp);
-
-			pk_debug("type is %s, group is %s, parsed_name is %s",items[len-2],items[len-1],parsed_name);
-
-			g_hash_table_insert(releases, parsed_name, repo);
-			g_free(contents);
-			contents = NULL;
-		}
-		else
-			g_free(parsed_name);
-		g_strfreev(items);
-	}
-	g_dir_close(dir);
-
-	/* and then we need to do this again, but this time we're looking for the packages */
-	dir = g_dir_open(sdir,0,&error);
-	while ((fname = g_dir_read_name(dir))!=NULL)
-	{
-		gchar** items = g_strsplit(fname,"_",-1);
-		guint len = g_strv_length(items);
-		if(len<=3) // minimum is <source>_<type>_<group>
-		{
-			g_strfreev(items);
-			continue;
-		}
-
-		if (g_ascii_strcasecmp(items[len-1],"Packages")==0)
-		{
-			const gchar *repo;
-			gchar *temp, *parsed_name;
-			gchar *fullname;
-			/* warning: nasty hack with g_strjoinv */
-			if (g_str_has_prefix(items[len-2],"binary-"))
-			{
-				temp = items[len-3];
-				items[len-3] = NULL;
-				parsed_name = g_strjoinv("_",items);
-				items[len-3] = temp;
-			}
-			else
-			{
-				temp = items[len-1];
-				items[len-1] = NULL;
-				parsed_name = g_strjoinv("_",items);
-				items[len-1] = temp;
-			}
-			
-			pk_debug("type is %s, group is %s, parsed_name is %s",items[len-2],items[len-1],parsed_name);
-			
-			repo = (const gchar *)g_hash_table_lookup(releases,parsed_name);
-			if (repo == NULL)
-			{
-				pk_debug("Can't find repo for %s, marking as \"unknown\"",parsed_name);
-				repo = g_strdup("unknown");
-				//g_assert(0);
-			}
-			else
-				pk_debug("repo for %s is %s",parsed_name,repo);
-			g_free(parsed_name);
-
-			fullname = g_build_filename(sdir,fname,NULL);
-			pk_debug("loading %s",fullname);
-			if (g_file_get_contents(fullname,&contents,NULL,NULL) == FALSE)
-			{
-				pk_backend_error_code(backend, PK_ERROR_ENUM_INTERNAL_ERROR, "error loading %s",fullname);
-				goto search_task_cleanup;
-			}
-			gchar *begin = contents, *next;
-			glong count = 0;
-
-			sqlite3_stmt *package = NULL;
-			int res;
-			res = sqlite3_prepare_v2(db, "insert or replace into packages values (?,?,?,?,?,?,?)", -1, &package, NULL);
-			if (res!=SQLITE_OK)
-				pk_error("sqlite error during insert prepare: %s", sqlite3_errmsg(db));
-			res = sqlite3_bind_text(package,FIELD_REPO,repo,-1,SQLITE_STATIC);
-			if (res!=SQLITE_OK)
-				pk_error("sqlite error during repo bind: %s", sqlite3_errmsg(db));
-
-			gboolean haspk = FALSE;
-
-			sqlite3_exec(db,"begin",NULL,NULL,NULL);
-
-			while (true)
-			{
-				next = strstr(begin,"\n");
-				if (next!=NULL)
-				{
-					next[0] = '\0';
-					next++;
-				}
-
-				if (begin[0]=='\0')
-				{
-					if (haspk)
-					{
-						res = sqlite3_step(package);
-						if (res!=SQLITE_DONE)
-							pk_error("sqlite error during step: %s", sqlite3_errmsg(db));
-						sqlite3_reset(package);
-						//pk_debug("added package");
-						haspk = FALSE;
-					}
-					//g_assert(0);
-				}
-				else if (begin[0]==' ')
-				{
-					/*gchar *oldval = g_strdup((const gchar*)g_hash_table_lookup(ret,"Description"));
-					g_hash_table_insert(ret,g_strdup("Description"),g_strconcat(oldval, "\n",parts[1],NULL));
-					//pk_debug("new entry =  '%s'",(const gchar*)g_hash_table_lookup(ret,"Description"));
-					g_free(oldval);*/
-				}
-				else
-				{
-					gchar *colon = strchr(begin,':');
-					g_assert(colon!=NULL);
-					colon[0] = '\0';
-					colon+=2;
-					/*if (strlen(colon)>3000)
-						pk_error("strlen(colon) = %d\ncolon = %s",strlen(colon),colon);*/
-					//typedef enum {FIELD_PKG=0,FIELD_VER,FIELD_DEPS,FIELD_ARCH,FIELD_SHORT,FIELD_LONG,FIELD_REPO} Fields;
-					//pk_debug("entry = '%s','%s'",begin,colon);
-					if (begin[0] == 'P' && g_strcasecmp("Package",begin)==0)
-					{
-						res=sqlite3_bind_text(package,FIELD_PKG,colon,-1,SQLITE_STATIC);
-						haspk = TRUE;
-						count++;
-						if (count%1000==0)
-							pk_debug("Package %ld (%s)",count,colon);
-					}
-					else if (begin[0] == 'V' && g_strcasecmp("Version",begin)==0)
-						res=sqlite3_bind_text(package,FIELD_VER,colon,-1,SQLITE_STATIC);
-					else if (begin[0] == 'D' && g_strcasecmp("Depends",begin)==0)
-						res=sqlite3_bind_text(package,FIELD_DEPS,colon,-1,SQLITE_STATIC);
-					else if (begin[0] == 'A' && g_strcasecmp("Architecture",begin)==0)
-						res=sqlite3_bind_text(package,FIELD_ARCH,colon,-1,SQLITE_STATIC);
-					else if (begin[0] == 'D' && g_strcasecmp("Description",begin)==0)
-						res=sqlite3_bind_text(package,FIELD_SHORT,colon,-1,SQLITE_STATIC);
-					if (res!=SQLITE_OK)
-						pk_error("sqlite error during %s bind: %s", begin, sqlite3_errmsg(db));
-				}
-				if (next == NULL)
-					break;
-				begin = next;	
-			}
-			sqlite3_exec(db,"commit",NULL,NULL,NULL);
-			g_free(contents);
-			contents = NULL;
-		}
-	}
-
-search_task_cleanup:
-	g_dir_close(dir);
-	g_free(sdir);
-	g_free(contents);
-}
-
-static void init(PkBackend *backend)
+static void backend_initialize(PkBackend *backend)
 {
 	if (!inited)
 	{
-		gint ret;
-		char *errmsg = NULL;
 		if (pkgInitConfig(*_config) == false)
 			pk_debug("pkginitconfig was false");
 		if (pkgInitSystem(*_config, _system) == false)
 			pk_debug("pkginitsystem was false");
-		ret = sqlite3_open (APT_DB, &db);
-		ret = sqlite3_exec(db,"PRAGMA synchronous = OFF",NULL,NULL,NULL);
-		g_assert(ret == SQLITE_OK);
-		//sqlite3_exec(db,"create table packages (name text, version text, deps text, arch text, short_desc text, long_desc text, repo string, primary key(name,version,arch,repo))",NULL,NULL,&errmsg);
-		sqlite3_exec(db,"create table packages (name text, version text, deps text, arch text, short_desc text, long_desc text, repo string)",NULL,NULL,&errmsg);
-		if (errmsg == NULL) // success, ergo didn't exist
-		{
-			build_db(backend);
-		}
-		else
-		{
-			sqlite3_free(errmsg);
-			/*ret = sqlite3_exec(db,"delete from packages",NULL,NULL,NULL); // clear it!
-			g_assert(ret == SQLITE_OK);
-			pk_debug("wiped db");*/
-		}
+		init_sqlite_cache(backend, APT_DB, apt_build_db);
 		inited = TRUE;
 	}
 }
@@ -346,7 +76,6 @@ static pkgCacheFile *getCache(PkBackend 
 	{
 		MMap *Map = 0;
 		OpTextProgress Prog;
-		init(backend);
 		// Open the cache file
 		SrcList = new pkgSourceList;
 		SrcList->ReadMainList();
@@ -550,73 +279,6 @@ static void backend_refresh_cache(PkBack
 	pk_backend_thread_helper(backend, backend_refresh_cache_thread, NULL);
 }
 
-// backend_search_packages_thread
-// Swiped from apt-cache's search mode
-static gboolean backend_search_packages_thread (PkBackend *backend, gpointer data)
-{
-	search_task *st = (search_task *) data;
-	int res;
-
-	init(backend);
-	pk_backend_change_status(backend, PK_STATUS_ENUM_QUERY);
-	pk_backend_no_percentage_updates(backend);
-
-	pk_debug("finding %s", st->search);
-
-	sqlite3_stmt *package = NULL;
-	g_strdelimit(st->search," ",'%');
-	gchar *sel = g_strdup_printf("select name,version,arch,repo,short_desc from packages where name like '%%%s%%'",st->search);
-	pk_debug("statement is '%s'",sel);
-	res = sqlite3_prepare_v2(db,sel, -1, &package, NULL);
-	g_free(sel);
-	if (res!=SQLITE_OK)
-		pk_error("sqlite error during select prepare: %s", sqlite3_errmsg(db));
-	res = sqlite3_step(package);
-	while (res == SQLITE_ROW)
-	{
-		gchar *pid = pk_package_id_build((const gchar*)sqlite3_column_text(package,0),
-				(const gchar*)sqlite3_column_text(package,1),
-				(const gchar*)sqlite3_column_text(package,2),
-				(const gchar*)sqlite3_column_text(package,3));
-		pk_backend_package(backend, FALSE, pid, (const gchar*)sqlite3_column_text(package,4));
-		g_free(pid);
-		if (res==SQLITE_ROW)
-			res = sqlite3_step(package);
-	}
-	if (res!=SQLITE_DONE)
-	{
-		pk_debug("sqlite error during step (%d): %s", res, sqlite3_errmsg(db));
-		g_assert(0);
-	}
-
-	g_free(st->search);
-	g_free(st);
-
-	return TRUE;
-}
-
-/**
- * backend_search_common
- **/
-static void
-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);
-	if (data == NULL)
-	{
-		pk_backend_error_code(backend, PK_ERROR_ENUM_OOM, "Failed to allocate memory for search task");
-		pk_backend_finished(backend);
-	}
-	else
-	{
-		data->search = g_strdup(search);
-		data->filter = g_strdup(filter);
-		data->depth = which;
-		pk_backend_thread_helper (backend, func, data);
-	}
-}
-
 static GHashTable *PackageRecord(PkBackend *backend, pkgCache::VerIterator V)
 {
 	GHashTable *ret = NULL;
@@ -732,24 +394,6 @@ backend_get_description (PkBackend *back
 	return;
 }
 
-/**
- * backend_search_details:
- */
-static void
-backend_search_details (PkBackend *backend, const gchar *filter, const gchar *search)
-{
-	backend_search_common(backend, filter, search, SEARCH_DETAILS, backend_search_packages_thread);
-}
-
-/**
- * backend_search_name:
- */
-static void
-backend_search_name (PkBackend *backend, const gchar *filter, const gchar *search)
-{
-	backend_search_common(backend, filter, search, SEARCH_NAME, backend_search_packages_thread);
-}
-
 static gboolean backend_search_file_thread (PkBackend *backend, gpointer data)
 {
 	//search_task *st = (search_task*)data;
@@ -787,8 +431,8 @@ static void backend_search_file(PkBacken
 extern "C" PK_BACKEND_OPTIONS (
 	"APT",					/* description */
 	"0.0.1",				/* version */
-	"Richard Hughes <richard at hughsie.com>",	/* author */
-	NULL,					/* initalize */
+	"Richard Hughes <richard at hughsie.com>, Tom Parker <palfrey at tevp.net>",	/* author */
+	backend_initialize,			/* initalize */
 	NULL,					/* destroy */
 	backend_get_groups,			/* get_groups */
 	backend_get_filters,			/* get_filters */
@@ -804,10 +448,10 @@ extern "C" PK_BACKEND_OPTIONS (
 	NULL,					/* remove_package */
 	NULL,					/* resolve */
 	NULL,					/* rollback */
-	backend_search_details,			/* search_details */
+	sqlite_search_details,			/* search_details */
 	backend_search_file,			/* search_file */
 	NULL,					/* search_group */
-	backend_search_name,			/* search_name */
+	sqlite_search_name,			/* search_name */
 	NULL,					/* update_package */
 	NULL					/* update_system */
 );
diff --git a/backends/apt/pk-backend-apt.h b/backends/apt/pk-backend-apt.h
new file mode 100644
index 0000000..ff67654
--- /dev/null
+++ b/backends/apt/pk-backend-apt.h
@@ -0,0 +1,30 @@
+#ifndef PK_BACKEND_APT
+#define PK_BACKEND_APT
+
+/* -*- Mode: C; tab-width: 8; indent-tabs-mode: t; c-basic-offset: 8 -*-
+ *
+ * Copyright (C) 2007 Tom Parker <palfrey at tevp.net>
+ *
+ * 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 <sqlite3.h>
+#include <pk-backend.h>
+
+void apt_build_db(PkBackend * backend, sqlite3 *db);
+
+#endif
diff --git a/backends/apt/sqlite-pkg-cache.cpp b/backends/apt/sqlite-pkg-cache.cpp
new file mode 100644
index 0000000..5e90f8e
--- /dev/null
+++ b/backends/apt/sqlite-pkg-cache.cpp
@@ -0,0 +1,138 @@
+/* -*- Mode: C; tab-width: 8; indent-tabs-mode: t; c-basic-offset: 8 -*-
+ *
+ * Copyright (C) 2007 Tom Parker <palfrey at tevp.net>
+ *
+ * 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 <sqlite3.h>
+#include <glib.h>
+#include "sqlite-pkg-cache.h"
+
+static sqlite3 *db = NULL;
+
+struct search_task {
+	gchar *search;
+	gchar *filter;
+	SearchDepth depth;
+};
+
+void init_sqlite_cache(PkBackend *backend, const char* dbname, void (*build_db)(PkBackend *, sqlite3 *))
+{
+	gint ret;
+	char *errmsg = NULL;
+	ret = sqlite3_open (dbname, &db);
+	ret = sqlite3_exec(db,"PRAGMA synchronous = OFF",NULL,NULL,NULL);
+	g_assert(ret == SQLITE_OK);
+	sqlite3_exec(db,"create table packages (name text, version text, deps text, arch text, short_desc text, long_desc text, repo string, primary key(name,version,arch,repo))",NULL,NULL,&errmsg);
+	if (errmsg == NULL) // success, ergo didn't exist
+	{
+		build_db(backend,db);
+	}
+	else
+	{
+		sqlite3_free(errmsg);
+		/*ret = sqlite3_exec(db,"delete from packages",NULL,NULL,NULL); // clear it!
+		g_assert(ret == SQLITE_OK);
+		pk_debug("wiped db");*/
+	}
+}
+
+// backend_search_packages_thread
+gboolean backend_search_packages_thread (PkBackend *backend, gpointer data)
+{
+	search_task *st = (search_task *) data;
+	int res;
+
+	pk_backend_change_status(backend, PK_STATUS_ENUM_QUERY);
+	pk_backend_no_percentage_updates(backend);
+
+	pk_debug("finding %s", st->search);
+
+	sqlite3_stmt *package = NULL;
+	g_strdelimit(st->search," ",'%');
+	gchar *sel = g_strdup_printf("select name,version,arch,repo,short_desc from packages where name like '%%%s%%'",st->search);
+	pk_debug("statement is '%s'",sel);
+	res = sqlite3_prepare_v2(db,sel, -1, &package, NULL);
+	g_free(sel);
+	if (res!=SQLITE_OK)
+		pk_error("sqlite error during select prepare: %s", sqlite3_errmsg(db));
+	res = sqlite3_step(package);
+	while (res == SQLITE_ROW)
+	{
+		gchar *pid = pk_package_id_build((const gchar*)sqlite3_column_text(package,0),
+				(const gchar*)sqlite3_column_text(package,1),
+				(const gchar*)sqlite3_column_text(package,2),
+				(const gchar*)sqlite3_column_text(package,3));
+		pk_backend_package(backend, FALSE, pid, (const gchar*)sqlite3_column_text(package,4));
+		g_free(pid);
+		if (res==SQLITE_ROW)
+			res = sqlite3_step(package);
+	}
+	if (res!=SQLITE_DONE)
+	{
+		pk_debug("sqlite error during step (%d): %s", res, sqlite3_errmsg(db));
+		g_assert(0);
+	}
+
+	g_free(st->search);
+	g_free(st);
+
+	return TRUE;
+}
+
+/**
+ * backend_search_common
+ **/
+void
+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);
+	if (data == NULL)
+	{
+		pk_backend_error_code(backend, PK_ERROR_ENUM_OOM, "Failed to allocate memory for search task");
+		pk_backend_finished(backend);
+	}
+	else
+	{
+		data->search = g_strdup(search);
+		data->filter = g_strdup(filter);
+		data->depth = which;
+		pk_backend_thread_helper (backend, func, data);
+	}
+}
+
+/**
+ * backend_search_details:
+ */
+void
+sqlite_search_details (PkBackend *backend, const gchar *filter, const gchar *search)
+{
+	backend_search_common(backend, filter, search, SEARCH_DETAILS, backend_search_packages_thread);
+}
+
+/**
+ * backend_search_name:
+ */
+void
+sqlite_search_name (PkBackend *backend, const gchar *filter, const gchar *search)
+{
+	backend_search_common(backend, filter, search, SEARCH_NAME, backend_search_packages_thread);
+}
+
+
diff --git a/backends/apt/sqlite-pkg-cache.h b/backends/apt/sqlite-pkg-cache.h
new file mode 100644
index 0000000..99511bf
--- /dev/null
+++ b/backends/apt/sqlite-pkg-cache.h
@@ -0,0 +1,38 @@
+#ifndef SQLITE_PKT_CACHE
+#define SQLITE_PKT_CACHE
+
+/* -*- Mode: C; tab-width: 8; indent-tabs-mode: t; c-basic-offset: 8 -*-
+ *
+ * Copyright (C) 2007 Tom Parker <palfrey at tevp.net>
+ *
+ * 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.
+ */
+
+typedef enum {
+	SEARCH_NAME = 1,
+	SEARCH_DETAILS,
+	SEARCH_FILE
+} SearchDepth;
+
+#include <pk-backend.h>
+
+void init_sqlite_cache(PkBackend *backend, const char* dbname, void (*build_db)(PkBackend *, sqlite3 *db));
+void sqlite_search_details (PkBackend *backend, const gchar *filter, const gchar *search);
+void sqlite_search_name (PkBackend *backend, const gchar *filter, const gchar *search);
+void backend_search_common(PkBackend * backend, const gchar * filter, const gchar * search, SearchDepth which, PkBackendThreadFunc func);
+
+#endif
diff-tree f95e81b62827cee1a59041e859c5cd0449bdd771 (from ea5c533ec4822e6a22a3d63ed25adc825b926c41)
Author: Tom Parker <palfrey at tevp.net>
Date:   Wed Sep 26 16:43:42 2007 +0200

    Let " " in searches match random characters

diff --git a/backends/apt/pk-backend-apt.cpp b/backends/apt/pk-backend-apt.cpp
index 3c47611..ca08bae 100644
--- a/backends/apt/pk-backend-apt.cpp
+++ b/backends/apt/pk-backend-apt.cpp
@@ -564,6 +564,7 @@ static gboolean backend_search_packages_
 	pk_debug("finding %s", st->search);
 
 	sqlite3_stmt *package = NULL;
+	g_strdelimit(st->search," ",'%');
 	gchar *sel = g_strdup_printf("select name,version,arch,repo,short_desc from packages where name like '%%%s%%'",st->search);
 	pk_debug("statement is '%s'",sel);
 	res = sqlite3_prepare_v2(db,sel, -1, &package, NULL);
diff-tree ea5c533ec4822e6a22a3d63ed25adc825b926c41 (from 2e71cf2378e950a692277e82ee41c3fa431fb317)
Author: Tom Parker <palfrey at tevp.net>
Date:   Thu Sep 27 15:51:32 2007 +0200

    First work with sqlite caching backend for APT
    APT backend now automagically builds a db containing all the
    packages on first run, and then does the searches in that.
    TODO: rebuild on changes, non-name searches

diff --git a/backends/apt/Makefile.am b/backends/apt/Makefile.am
index aab967b..622f703 100644
--- a/backends/apt/Makefile.am
+++ b/backends/apt/Makefile.am
@@ -4,5 +4,5 @@ libpk_backend_apt_la_INCLUDES = $(APT_CF
 libpk_backend_apt_la_SOURCES = pk-backend-apt.cpp
 libpk_backend_apt_la_LIBADD = @PK_PLUGIN_LIBS@ $(APT_LIBS)
 libpk_backend_apt_la_LDFLAGS = -module -avoid-version
-libpk_backend_apt_la_CXXFLAGS = @PK_PLUGIN_CFLAGS@
+libpk_backend_apt_la_CXXFLAGS = @PK_PLUGIN_CFLAGS@ -DDATABASEDIR=\""$(PK_DB_DIR)"\"
 
diff --git a/backends/apt/pk-backend-apt.cpp b/backends/apt/pk-backend-apt.cpp
index 7f8d823..3c47611 100644
--- a/backends/apt/pk-backend-apt.cpp
+++ b/backends/apt/pk-backend-apt.cpp
@@ -21,6 +21,7 @@
 
 #include <gmodule.h>
 #include <glib.h>
+#include <glib/gprintf.h>
 #include <string.h>
 #include <pk-backend.h>
 #include <pk-debug.h>
@@ -39,12 +40,16 @@
 #include <apt-pkg/acquire.h>
 #include <apt-pkg/acquire-item.h>
 
-#include <regex.h>
 #include <string.h>
 #include <math.h>
+#include <sqlite3.h>
 
 static pkgCacheFile *fileCache = NULL;
-pkgSourceList *SrcList = 0;
+static pkgSourceList *SrcList = 0;
+static gboolean inited = FALSE;
+static sqlite3 *db = NULL;
+
+#define APT_DB DATABASEDIR "/apt.db"
 
 typedef enum {
 	SEARCH_NAME = 1,
@@ -70,27 +75,278 @@ typedef pkgCache::DescFile AptCompFile;
 #error Need either rpm or deb defined
 #endif
 
-struct ExDescFile {
-	AptCompFile *Df;
-	const char *verstr;
-	const char *arch;
-	gboolean installed;
-	gboolean available;
-	char *repo;
-	bool NameMatch;
-};
+typedef enum {FIELD_PKG=1,FIELD_VER,FIELD_DEPS,FIELD_ARCH,FIELD_SHORT,FIELD_LONG,FIELD_REPO} Fields;
+
+static void build_db(PkBackend * backend)
+{
+	GMatchInfo *match_info;
+	GError *error = NULL;
+	gchar *contents = NULL;
+	gchar *sdir;
+	const gchar *fname;
+	GRegex *origin, *suite, *version, *description;
+	GDir *dir;
+	GHashTable *releases;
+
+	pk_backend_change_status(backend, PK_STATUS_ENUM_QUERY);
+	pk_backend_no_percentage_updates(backend);
+
+	sdir = g_build_filename(_config->Find("Dir").c_str(),_config->Find("Dir::State").c_str(),_config->Find("Dir::State::lists").c_str(), NULL);
+	dir = g_dir_open(sdir,0,&error);
+	if (error!=NULL)
+	{
+		pk_backend_error_code(backend, PK_ERROR_ENUM_INTERNAL_ERROR, "can't open %s",dir);
+		g_error_free(error);
+		goto search_task_cleanup;
+	}
+
+	origin = g_regex_new("^Origin: (\\S+)",(GRegexCompileFlags)(G_REGEX_CASELESS|G_REGEX_OPTIMIZE|G_REGEX_MULTILINE),(GRegexMatchFlags)0,NULL);
+	suite = g_regex_new("^Suite: (\\S+)",(GRegexCompileFlags)(G_REGEX_CASELESS|G_REGEX_OPTIMIZE|G_REGEX_MULTILINE),(GRegexMatchFlags)0,NULL);
+
+	version = g_regex_new("^Version: (.*)",(GRegexCompileFlags)(G_REGEX_CASELESS|G_REGEX_OPTIMIZE|G_REGEX_MULTILINE),(GRegexMatchFlags)0,NULL);
+	description = g_regex_new("^Description: (.*)",(GRegexCompileFlags)(G_REGEX_CASELESS|G_REGEX_OPTIMIZE|G_REGEX_MULTILINE),(GRegexMatchFlags)0,NULL);
 
+	releases = g_hash_table_new_full(g_str_hash,g_str_equal,g_free,g_free);
+	while ((fname = g_dir_read_name(dir))!=NULL)
+	{
+		gchar *temp, *parsed_name;
+		gchar** items = g_strsplit(fname,"_",-1);
+		guint len = g_strv_length(items);
+		if(len<=3) // minimum is <source>_<type>_<group>
+		{
+			g_strfreev(items);
+			continue;
+		}
+		
+		/* warning: nasty hack with g_strjoinv */
+		temp = items[len-2];
+		items[len-2] = NULL;
+		parsed_name = g_strjoinv("_",items);
+		items[len-2] = temp;
+		
+		if (g_ascii_strcasecmp(items[len-1],"Release")==0 && g_ascii_strcasecmp(items[len-2],"source")!=0)
+		{
+			gchar * repo = NULL, *fullname;
+			fullname = g_build_filename(sdir,fname,NULL);
+			if (g_file_get_contents(fullname,&contents,NULL,NULL) == FALSE)
+			{
+				pk_backend_error_code(backend, PK_ERROR_ENUM_INTERNAL_ERROR, "error loading %s",fullname);
+				goto search_task_cleanup;
+			}
+			g_free(fullname);
+
+			g_regex_match (origin, contents, (GRegexMatchFlags)0, &match_info);
+			if (!g_match_info_matches(match_info))
+			{
+				pk_backend_error_code(backend, PK_ERROR_ENUM_INTERNAL_ERROR, "origin regex failure in %s",fname);
+				goto search_task_cleanup;
+			}
+			repo = g_match_info_fetch (match_info, 1);
+
+			g_regex_match (suite, contents, (GRegexMatchFlags)0, &match_info);
+			if (g_match_info_matches(match_info))
+			{
+				temp = g_strconcat(repo,"/",g_match_info_fetch (match_info, 1),NULL);
+				g_free(repo);
+				repo = temp;
+			}
+
+			temp = parsed_name;
+			parsed_name = g_strconcat(temp,"_",items[len-2],NULL);
+			g_free(temp);
+
+			pk_debug("type is %s, group is %s, parsed_name is %s",items[len-2],items[len-1],parsed_name);
+
+			g_hash_table_insert(releases, parsed_name, repo);
+			g_free(contents);
+			contents = NULL;
+		}
+		else
+			g_free(parsed_name);
+		g_strfreev(items);
+	}
+	g_dir_close(dir);
+
+	/* and then we need to do this again, but this time we're looking for the packages */
+	dir = g_dir_open(sdir,0,&error);
+	while ((fname = g_dir_read_name(dir))!=NULL)
+	{
+		gchar** items = g_strsplit(fname,"_",-1);
+		guint len = g_strv_length(items);
+		if(len<=3) // minimum is <source>_<type>_<group>
+		{
+			g_strfreev(items);
+			continue;
+		}
+
+		if (g_ascii_strcasecmp(items[len-1],"Packages")==0)
+		{
+			const gchar *repo;
+			gchar *temp, *parsed_name;
+			gchar *fullname;
+			/* warning: nasty hack with g_strjoinv */
+			if (g_str_has_prefix(items[len-2],"binary-"))
+			{
+				temp = items[len-3];
+				items[len-3] = NULL;
+				parsed_name = g_strjoinv("_",items);
+				items[len-3] = temp;
+			}
+			else
+			{
+				temp = items[len-1];
+				items[len-1] = NULL;
+				parsed_name = g_strjoinv("_",items);
+				items[len-1] = temp;
+			}
+			
+			pk_debug("type is %s, group is %s, parsed_name is %s",items[len-2],items[len-1],parsed_name);
+			
+			repo = (const gchar *)g_hash_table_lookup(releases,parsed_name);
+			if (repo == NULL)
+			{
+				pk_debug("Can't find repo for %s, marking as \"unknown\"",parsed_name);
+				repo = g_strdup("unknown");
+				//g_assert(0);
+			}
+			else
+				pk_debug("repo for %s is %s",parsed_name,repo);
+			g_free(parsed_name);
+
+			fullname = g_build_filename(sdir,fname,NULL);
+			pk_debug("loading %s",fullname);
+			if (g_file_get_contents(fullname,&contents,NULL,NULL) == FALSE)
+			{
+				pk_backend_error_code(backend, PK_ERROR_ENUM_INTERNAL_ERROR, "error loading %s",fullname);
+				goto search_task_cleanup;
+			}
+			gchar *begin = contents, *next;
+			glong count = 0;
+
+			sqlite3_stmt *package = NULL;
+			int res;
+			res = sqlite3_prepare_v2(db, "insert or replace into packages values (?,?,?,?,?,?,?)", -1, &package, NULL);
+			if (res!=SQLITE_OK)
+				pk_error("sqlite error during insert prepare: %s", sqlite3_errmsg(db));
+			res = sqlite3_bind_text(package,FIELD_REPO,repo,-1,SQLITE_STATIC);
+			if (res!=SQLITE_OK)
+				pk_error("sqlite error during repo bind: %s", sqlite3_errmsg(db));
+
+			gboolean haspk = FALSE;
+
+			sqlite3_exec(db,"begin",NULL,NULL,NULL);
+
+			while (true)
+			{
+				next = strstr(begin,"\n");
+				if (next!=NULL)
+				{
+					next[0] = '\0';
+					next++;
+				}
+
+				if (begin[0]=='\0')
+				{
+					if (haspk)
+					{
+						res = sqlite3_step(package);
+						if (res!=SQLITE_DONE)
+							pk_error("sqlite error during step: %s", sqlite3_errmsg(db));
+						sqlite3_reset(package);
+						//pk_debug("added package");
+						haspk = FALSE;
+					}
+					//g_assert(0);
+				}
+				else if (begin[0]==' ')
+				{
+					/*gchar *oldval = g_strdup((const gchar*)g_hash_table_lookup(ret,"Description"));
+					g_hash_table_insert(ret,g_strdup("Description"),g_strconcat(oldval, "\n",parts[1],NULL));
+					//pk_debug("new entry =  '%s'",(const gchar*)g_hash_table_lookup(ret,"Description"));
+					g_free(oldval);*/
+				}
+				else
+				{
+					gchar *colon = strchr(begin,':');
+					g_assert(colon!=NULL);
+					colon[0] = '\0';
+					colon+=2;
+					/*if (strlen(colon)>3000)
+						pk_error("strlen(colon) = %d\ncolon = %s",strlen(colon),colon);*/
+					//typedef enum {FIELD_PKG=0,FIELD_VER,FIELD_DEPS,FIELD_ARCH,FIELD_SHORT,FIELD_LONG,FIELD_REPO} Fields;
+					//pk_debug("entry = '%s','%s'",begin,colon);
+					if (begin[0] == 'P' && g_strcasecmp("Package",begin)==0)
+					{
+						res=sqlite3_bind_text(package,FIELD_PKG,colon,-1,SQLITE_STATIC);
+						haspk = TRUE;
+						count++;
+						if (count%1000==0)
+							pk_debug("Package %ld (%s)",count,colon);
+					}
+					else if (begin[0] == 'V' && g_strcasecmp("Version",begin)==0)
+						res=sqlite3_bind_text(package,FIELD_VER,colon,-1,SQLITE_STATIC);
+					else if (begin[0] == 'D' && g_strcasecmp("Depends",begin)==0)
+						res=sqlite3_bind_text(package,FIELD_DEPS,colon,-1,SQLITE_STATIC);
+					else if (begin[0] == 'A' && g_strcasecmp("Architecture",begin)==0)
+						res=sqlite3_bind_text(package,FIELD_ARCH,colon,-1,SQLITE_STATIC);
+					else if (begin[0] == 'D' && g_strcasecmp("Description",begin)==0)
+						res=sqlite3_bind_text(package,FIELD_SHORT,colon,-1,SQLITE_STATIC);
+					if (res!=SQLITE_OK)
+						pk_error("sqlite error during %s bind: %s", begin, sqlite3_errmsg(db));
+				}
+				if (next == NULL)
+					break;
+				begin = next;	
+			}
+			sqlite3_exec(db,"commit",NULL,NULL,NULL);
+			g_free(contents);
+			contents = NULL;
+		}
+	}
+
+search_task_cleanup:
+	g_dir_close(dir);
+	g_free(sdir);
+	g_free(contents);
+}
 
-static pkgCacheFile *getCache()
+static void init(PkBackend *backend)
 {
-	if (fileCache == NULL)
+	if (!inited)
 	{
-		MMap *Map = 0;
-		OpTextProgress Prog;
+		gint ret;
+		char *errmsg = NULL;
 		if (pkgInitConfig(*_config) == false)
 			pk_debug("pkginitconfig was false");
 		if (pkgInitSystem(*_config, _system) == false)
 			pk_debug("pkginitsystem was false");
+		ret = sqlite3_open (APT_DB, &db);
+		ret = sqlite3_exec(db,"PRAGMA synchronous = OFF",NULL,NULL,NULL);
+		g_assert(ret == SQLITE_OK);
+		//sqlite3_exec(db,"create table packages (name text, version text, deps text, arch text, short_desc text, long_desc text, repo string, primary key(name,version,arch,repo))",NULL,NULL,&errmsg);
+		sqlite3_exec(db,"create table packages (name text, version text, deps text, arch text, short_desc text, long_desc text, repo string)",NULL,NULL,&errmsg);
+		if (errmsg == NULL) // success, ergo didn't exist
+		{
+			build_db(backend);
+		}
+		else
+		{
+			sqlite3_free(errmsg);
+			/*ret = sqlite3_exec(db,"delete from packages",NULL,NULL,NULL); // clear it!
+			g_assert(ret == SQLITE_OK);
+			pk_debug("wiped db");*/
+		}
+		inited = TRUE;
+	}
+}
+
+static pkgCacheFile *getCache(PkBackend *backend)
+{
+	if (fileCache == NULL)
+	{
+		MMap *Map = 0;
+		OpTextProgress Prog;
+		init(backend);
 		// Open the cache file
 		SrcList = new pkgSourceList;
 		SrcList->ReadMainList();
@@ -156,7 +412,7 @@ static gboolean backend_refresh_cache_th
 	/* easy as that */
 	pk_backend_change_status(backend, PK_STATUS_ENUM_REFRESH_CACHE);
 
-	Cache = getCache();
+	Cache = getCache(backend);
 
 	// Get the source list
 	pkgSourceList List;
@@ -227,7 +483,7 @@ static gboolean backend_refresh_cache_th
 	}
 
 	// Prepare the cache.
-	Cache = getCache();
+	Cache = getCache(backend);
 	if (Cache->BuildCaches(Prog,false) == false)
 	{
 		pk_backend_error_code(backend, PK_ERROR_ENUM_UNKNOWN, "Failed to prepare the cache");
@@ -294,168 +550,44 @@ static void backend_refresh_cache(PkBack
 	pk_backend_thread_helper(backend, backend_refresh_cache_thread, NULL);
 }
 
-// LocalitySort - Sort a version list by package file locality		/*{{{*/
-// ---------------------------------------------------------------------
-/* */
-static int LocalityCompare(const void *a, const void *b)
-{
-	pkgCache::VerFile *A = *(pkgCache::VerFile **)a;
-	pkgCache::VerFile *B = *(pkgCache::VerFile **)b;
-
-	if (A == 0 && B == 0)
-		return 0;
-	if (A == 0)
-		return 1;
-	if (B == 0)
-		return -1;
-
-	if (A->File == B->File)
-		return A->Offset - B->Offset;
-	return A->File - B->File;
-}
-
-static void LocalitySort(AptCompFile **begin,
-		  unsigned long Count,size_t Size)
-{
-	qsort(begin,Count,Size,LocalityCompare);
-}
-
-static gboolean buildExDesc(ExDescFile *DFList, unsigned int pid, pkgCache::VerIterator V)
-{
-	// Find the proper version to use.
-	DFList[pid].available = false;
-	if (V.end() == false)
-	{
-	#ifdef APT_PKG_RPM
-		DFList[pid].Df = V.FileList();
-	#else
-		DFList[pid].Df = V.DescriptionList().FileList();
-	#endif
-		DFList[pid].verstr = V.VerStr();
-		DFList[pid].arch = V.Arch();
-		for (pkgCache::VerFileIterator VF = V.FileList(); VF.end() == false; VF++)
-		{
-			// Locate the associated index files so we can derive a description
-			pkgIndexFile *Indx;
-			bool hasLocal = _system->FindIndex(VF.File(),Indx);
-			if (SrcList->FindIndex(VF.File(),Indx) == false && !hasLocal)
-			{
-			   pk_debug("Cache is out of sync, can't x-ref a package file");
-			   break;
-			}
-			gchar** items = g_strsplit_set(Indx->Describe(true).c_str()," \t",-1);
-			DFList[pid].repo = g_strdup(items[1]); // should be in format like "http://ftp.nl.debian.org unstable/main Packages"
-			DFList[pid].installed = hasLocal;
-			g_strfreev(items);
-			DFList[pid].available = true;
-			if (hasLocal)
-				break;
-		}
-	}
-	return DFList[pid].available;
-}
-
 // backend_search_packages_thread
 // Swiped from apt-cache's search mode
 static gboolean backend_search_packages_thread (PkBackend *backend, gpointer data)
 {
 	search_task *st = (search_task *) data;
-	ExDescFile *DFList = NULL;
+	int res;
 
+	init(backend);
 	pk_backend_change_status(backend, PK_STATUS_ENUM_QUERY);
 	pk_backend_no_percentage_updates(backend);
 
 	pk_debug("finding %s", st->search);
-	pkgCache & pkgCache = *(getCache());
-	pkgDepCache::Policy Plcy;
-	// Create the text record parser
-	pkgRecords Recs(pkgCache);
 
-	// Compile the regex pattern
-	regex_t *Pattern = new regex_t;
-	memset(Pattern, 0, sizeof(*Pattern));
-	if (regcomp(Pattern, st->search, REG_EXTENDED | REG_ICASE | REG_NOSUB) != 0)
-	{
-		pk_backend_error_code(backend, PK_ERROR_ENUM_UNKNOWN, "regex compilation error");
-		goto search_task_cleanup;
+	sqlite3_stmt *package = NULL;
+	gchar *sel = g_strdup_printf("select name,version,arch,repo,short_desc from packages where name like '%%%s%%'",st->search);
+	pk_debug("statement is '%s'",sel);
+	res = sqlite3_prepare_v2(db,sel, -1, &package, NULL);
+	g_free(sel);
+	if (res!=SQLITE_OK)
+		pk_error("sqlite error during select prepare: %s", sqlite3_errmsg(db));
+	res = sqlite3_step(package);
+	while (res == SQLITE_ROW)
+	{
+		gchar *pid = pk_package_id_build((const gchar*)sqlite3_column_text(package,0),
+				(const gchar*)sqlite3_column_text(package,1),
+				(const gchar*)sqlite3_column_text(package,2),
+				(const gchar*)sqlite3_column_text(package,3));
+		pk_backend_package(backend, FALSE, pid, (const gchar*)sqlite3_column_text(package,4));
+		g_free(pid);
+		if (res==SQLITE_ROW)
+			res = sqlite3_step(package);
 	}
-
-	DFList = new ExDescFile[pkgCache.HeaderP->PackageCount + 1];
-	memset(DFList, 0, sizeof(*DFList) * pkgCache.HeaderP->PackageCount + 1);
-
-	// Map versions that we want to write out onto the VerList array.
-	for (pkgCache::PkgIterator P = pkgCache.PkgBegin(); P.end() == false; P++)
+	if (res!=SQLITE_DONE)
 	{
-		DFList[P->ID].NameMatch = true;
-		if (regexec(Pattern, P.Name(), 0, 0, 0) == 0)
-			DFList[P->ID].NameMatch &= true;
-		else
-			DFList[P->ID].NameMatch = false;
-
-		// Doing names only, drop any that dont match..
-		if (st->depth == SEARCH_NAME && DFList[P->ID].NameMatch == false)
-			continue;
-
-		// Find the proper version to use.
-		pkgCache::VerIterator V = Plcy.GetCandidateVer(P);
-		buildExDesc(DFList, P->ID, V);
-	}
-
-	// Include all the packages that provide matching names too
-	for (pkgCache::PkgIterator P = pkgCache.PkgBegin(); P.end() == false; P++)
-	{
-		if (DFList[P->ID].NameMatch == false)
-			continue;
-
-		for (pkgCache::PrvIterator Prv = P.ProvidesList(); Prv.end() == false; Prv++)
-		{
-			pkgCache::VerIterator V = Plcy.GetCandidateVer(Prv.OwnerPkg());
-			if (buildExDesc(DFList, Prv.OwnerPkg()->ID, V))
-				DFList[Prv.OwnerPkg()->ID].NameMatch = true;
-		}
+		pk_debug("sqlite error during step (%d): %s", res, sqlite3_errmsg(db));
+		g_assert(0);
 	}
 
-	LocalitySort(&DFList->Df, pkgCache.HeaderP->PackageCount, sizeof(*DFList));
-
-	// Iterate over all the version records and check them
-	for (ExDescFile * J = DFList; J->Df != 0; J++)
-	{
-#ifdef APT_PKG_RPM
-		pkgRecords::Parser & P = Recs.Lookup(pkgCache::VerFileIterator(pkgCache, J->Df));
-#else
-		pkgRecords::Parser & P = Recs.Lookup(pkgCache::DescFileIterator(pkgCache, J->Df));
-#endif
-
-		gboolean Match = true;
-		if (J->NameMatch == false)
-		{
-			string LongDesc = P.LongDesc();
-			if (regexec(Pattern, LongDesc.c_str(), 0, 0, 0) == 0)
-				Match = true;
-			else
-				Match = false;
-		}
-
-		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);
-			PkInfoEnum info;
-			if (J->installed)
-				info = PK_INFO_ENUM_INSTALLED;
-			else
-				info = PK_INFO_ENUM_AVAILABLE;
-			pk_backend_package(backend, info, pid, P.ShortDesc().c_str());
-			g_free(pid);
-		}
-	}
-
-search_task_cleanup:
-	for (ExDescFile * J = DFList; J->Df != 0; J++)
-	{
-		g_free(J->repo);
-	}
-	delete[]DFList;
-	regfree(Pattern);
 	g_free(st->search);
 	g_free(st);
 
@@ -484,11 +616,11 @@ backend_search_common(PkBackend * backen
 	}
 }
 
-static GHashTable *PackageRecord(pkgCache::VerIterator V)
+static GHashTable *PackageRecord(PkBackend *backend, pkgCache::VerIterator V)
 {
 	GHashTable *ret = NULL;
 
-	pkgCache & pkgCache = *(getCache());
+	pkgCache & pkgCache = *(getCache(backend));
 	// Find an appropriate file
 	pkgCache::VerFileIterator Vf = V.FileList();
 	for (; Vf.end() == false; Vf++)
@@ -553,7 +685,7 @@ static gboolean backend_get_description_
 	pk_backend_no_percentage_updates(backend);
 
 	pk_debug("finding %s", dt->pi->name);
-	pkgCache & pkgCache = *(getCache());
+	pkgCache & pkgCache = *(getCache(backend));
 	pkgDepCache::Policy Plcy;
 
 	// Map versions that we want to write out onto the VerList array.
@@ -564,7 +696,7 @@ static gboolean backend_get_description_
 
 		// Find the proper version to use.
 		pkgCache::VerIterator V = Plcy.GetCandidateVer(P);
-		GHashTable *pkg = PackageRecord(V);
+		GHashTable *pkg = PackageRecord(backend,V);
 		pk_backend_description(backend,dt->pi->name,
 			"unknown", PK_GROUP_ENUM_OTHER,(const gchar*)g_hash_table_lookup(pkg,"Description"),"");
 		g_hash_table_unref(pkg);



More information about the PackageKit mailing list