[PackageKit-commit] packagekit: Branch 'master' - 25 commits

Richard Hughes hughsient at kemper.freedesktop.org
Tue Jul 15 01:02:32 PDT 2008


 backends/yum/helpers/Makefile.am     |    3 
 backends/yum/helpers/resolve.py      |    4 
 backends/yum/helpers/yumBackend.py   |  554 +++------------
 backends/yum/helpers/yumComps.py     |  268 +++++++
 backends/yum/helpers/yumDirect.py    |   85 ++
 backends/yum/helpers/yumFilter.py    |  208 +++++
 client/pk-import-desktop.c           |   10 
 configure.ac                         |   36 -
 contrib/PackageKit.spec.in           |    4 
 docs/html/img/Makefile.am            |    1 
 docs/html/img/author-caglar.png      |binary
 docs/html/img/author-elliot.png      |binary
 docs/html/img/gpk-added-deps.png     |binary
 docs/html/img/gpk-remove-confirm.png |binary
 docs/html/img/gpk-repo-more.png      |binary
 docs/html/img/gpk-repo.png           |binary
 docs/html/pk-download.html           |    4 
 docs/html/pk-intro.html              |    4 
 docs/html/pk-screenshots.html        |    3 
 po/de.po                             |  146 ++--
 python/packagekit/Makefile.am        |    2 
 python/packagekit/backend.py         |  154 ----
 python/packagekit/daemonBackend.py   |    4 
 python/packagekit/package.py         |   94 ++
 python/packagekit/progress.py        |  101 ++
 src/Makefile.am                      |    2 
 src/pk-backend-python.c              | 1214 +++++++++++++++++++++++++++++++++++
 src/pk-backend-python.h              |   83 ++
 src/pk-backend.c                     |    3 
 29 files changed, 2291 insertions(+), 696 deletions(-)

New commits:
commit 9454d4b96de3003af899d94470a2fb6f233e19a9
Author: Richard Hughes <richard at hughsie.com>
Date:   Fri Jul 11 13:45:12 2008 +0100

    trivial: fix up download locations

diff --git a/contrib/PackageKit.spec.in b/contrib/PackageKit.spec.in
index 611aa25..140ef5c 100644
--- a/contrib/PackageKit.spec.in
+++ b/contrib/PackageKit.spec.in
@@ -122,10 +122,10 @@ chmod 755 $RPM_BUILD_ROOT%{_libexecdir}/PackageKitDbusTest.py
 rm -rf $RPM_BUILD_ROOT
 
 %post
-update-mime-database %{_datadir}/mime
+update-mime-database %{_datadir}/mime &> /dev/null || :
 
 %postun
-update-mime-database %{_datadir}/mime
+update-mime-database %{_datadir}/mime &> /dev/null || :
 
 %post libs -p /sbin/ldconfig
 
diff --git a/docs/html/pk-download.html b/docs/html/pk-download.html
index 69e58a8..ffaf65e 100644
--- a/docs/html/pk-download.html
+++ b/docs/html/pk-download.html
@@ -89,8 +89,8 @@ You can get the latest PackageKit daemon, and QT or GNOME frontends from the
 public git repositories on freedesktop.
 </p>
 <pre>
-git clone git://anongit.freedesktop.org/git/packagekit
-git clone git://people.freedesktop.org/~hughsient/QPackageKit
+git clone git://anongit.freedesktop.org/git/packagekit/PackageKit
+git clone git://anongit.freedesktop.org/git/packagekit/PackageKit-Qt
 git clone git://people.freedesktop.org/~hughsient/gnome-packagekit
 </pre>
 <p>
diff --git a/docs/html/pk-intro.html b/docs/html/pk-intro.html
index 64f72fc..4f65edd 100644
--- a/docs/html/pk-intro.html
+++ b/docs/html/pk-intro.html
@@ -49,9 +49,9 @@ consume memory when not being used.
 tools for PackageKit to be used in the GNOME desktop.
 </p>
 <p>
-<code>QPackageKit</code> is the name of the QT graphical tools designed
+<a href="http://www.kde-apps.org/content/show.php/show.php?content=84745">
+PackageKit-Qt</a> is the name of the QT graphical tools designed
 for PackageKit.
-These are not fully functional yet, although development is rapid.
 </p>
 
 <p>
commit 4dfc6cb8e32b62e1dc7710278fa5bc531bb977a1
Author: Richard Hughes <richard at hughsie.com>
Date:   Thu Jul 10 15:21:23 2008 +0100

    add a new helper class for talking to an embedded python instance. WIP, and probably won't work yet

diff --git a/src/pk-backend-python.c b/src/pk-backend-python.c
new file mode 100644
index 0000000..a154a8f
--- /dev/null
+++ b/src/pk-backend-python.c
@@ -0,0 +1,1214 @@
+/* -*- Mode: C; tab-width: 8; indent-tabs-mode: t; c-basic-offset: 8 -*-
+ *
+ * Copyright (C) 2008 Richard Hughes <richard at hughsie.com>
+ *
+ * Licensed under the GNU General Public License Version 2
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+ */
+
+#ifdef HAVE_CONFIG_H
+#  include <config.h>
+#endif
+
+#include <stdlib.h>
+#include <stdio.h>
+#include <time.h>
+#include <errno.h>
+
+#include <string.h>
+#include <sys/time.h>
+#include <sys/types.h>
+#ifdef HAVE_UNISTD_H
+#include <unistd.h>
+#endif /* HAVE_UNISTD_H */
+
+#include <glib/gi18n.h>
+#include <glib/gprintf.h>
+#include <gmodule.h>
+
+#include <Python.h>
+
+#include <pk-common.h>
+#include <pk-package-id.h>
+#include <pk-enum.h>
+
+#include "pk-debug.h"
+#include "pk-backend-internal.h"
+#include "pk-backend-python.h"
+#include "pk-marshal.h"
+#include "pk-enum.h"
+#include "pk-time.h"
+#include "pk-inhibit.h"
+
+#define PK_BACKEND_PYTHON_GET_PRIVATE(o) (G_TYPE_INSTANCE_GET_PRIVATE ((o), PK_TYPE_BACKEND_PYTHON, PkBackendPythonPrivate))
+
+struct PkBackendPythonPrivate
+{
+	PkBackend		*backend;
+	PyObject		*pModule;
+	PyObject		*pInstance;
+};
+
+G_DEFINE_TYPE (PkBackendPython, pk_backend_python, G_TYPE_OBJECT)
+static gpointer pk_backend_python_object = NULL;
+
+static PyObject *pk_backend_python_repo_detail_cb (PyObject *self, PyObject *args);
+static PyObject *pk_backend_python_status_changed_cb (PyObject *self, PyObject *args);
+static PyObject *pk_backend_python_percentage_changed_cb (PyObject *self, PyObject *args);
+static PyObject *pk_backend_python_sub_percentage_changed_cb (PyObject *self, PyObject *args);
+static PyObject *pk_backend_python_package_cb (PyObject *self, PyObject *args);
+static PyObject *pk_backend_python_details_cb (PyObject *self, PyObject *args);
+static PyObject *pk_backend_python_files_cb (PyObject *self, PyObject *args);
+static PyObject *pk_backend_python_update_detail_cb (PyObject *self, PyObject *args);
+static PyObject *pk_backend_python_finished_cb (PyObject *self, PyObject *args);
+static PyObject *pk_backend_python_allow_cancel_cb (PyObject *self, PyObject *args);
+static PyObject *pk_backend_python_error_code_cb (PyObject *self, PyObject *args);
+static PyObject *pk_backend_python_require_restart_cb (PyObject *self, PyObject *args);
+static PyObject *pk_backend_python_message_cb (PyObject *self, PyObject *args);
+static PyObject *pk_backend_python_repo_signature_required_cb (PyObject *self, PyObject *args);
+static PyObject *pk_backend_python_eula_required_cb (PyObject *self, PyObject *args);
+
+static PyMethodDef PkBackendPythonMethods[] = {
+	{"repo_detail", pk_backend_python_repo_detail_cb, METH_VARARGS, ""},
+	{"status_changed", pk_backend_python_status_changed_cb, METH_VARARGS, ""},
+	{"percentage_changed", pk_backend_python_percentage_changed_cb, METH_VARARGS, ""},
+	{"sub_percentage_changed", pk_backend_python_sub_percentage_changed_cb, METH_VARARGS, ""},
+	{"package", pk_backend_python_package_cb, METH_VARARGS, ""},
+	{"details", pk_backend_python_details_cb, METH_VARARGS, ""},
+	{"files", pk_backend_python_files_cb, METH_VARARGS, ""},
+	{"update_detail", pk_backend_python_update_detail_cb, METH_VARARGS, ""},
+	{"finished", pk_backend_python_finished_cb, METH_VARARGS, ""},
+	{"allow_cancel", pk_backend_python_allow_cancel_cb, METH_VARARGS, ""},
+	{"error_code", pk_backend_python_error_code_cb, METH_VARARGS, ""},
+	{"require_restart", pk_backend_python_require_restart_cb, METH_VARARGS, ""},
+	{"message", pk_backend_python_message_cb, METH_VARARGS, ""},
+	{"repo_signature_required", pk_backend_python_repo_signature_required_cb, METH_VARARGS, ""},
+	{"eula_required", pk_backend_python_eula_required_cb, METH_VARARGS, ""},
+	{NULL, NULL, 0, NULL}
+};
+
+/**
+ * pk_backend_python_repo_detail_cb:
+ **/
+static PyObject *
+pk_backend_python_repo_detail_cb (PyObject *self, PyObject *args)
+{
+	const gchar *repo_id;
+	const gchar *description;
+	gboolean enabled;
+	PkBackendPython *python = PK_BACKEND_PYTHON (pk_backend_python_object);
+
+	pk_debug ("got signal");
+	PyArg_ParseTuple (args, "ssi", &repo_id, &description, &enabled);
+
+	pk_backend_repo_detail (python->priv->backend, repo_id, description, enabled);
+	return Py_BuildValue("");
+}
+
+/**
+ * pk_backend_python_status_changed_cb:
+ **/
+static PyObject *
+pk_backend_python_status_changed_cb (PyObject *self, PyObject *args)
+{
+	const gchar *status_text;
+	PkBackendPython *python = PK_BACKEND_PYTHON (pk_backend_python_object);
+
+	pk_debug ("got signal");
+	PyArg_ParseTuple (args, "s", &status_text);
+
+	pk_backend_set_status (python->priv->backend, pk_status_enum_from_text (status_text));
+	return Py_BuildValue("");
+}
+
+/**
+ * pk_backend_python_percentage_changed_cb:
+ **/
+static PyObject *
+pk_backend_python_percentage_changed_cb (PyObject *self, PyObject *args)
+{
+	guint percentage;
+	PkBackendPython *python = PK_BACKEND_PYTHON (pk_backend_python_object);
+
+	pk_debug ("got signal");
+	PyArg_ParseTuple (args, "i", &percentage);
+
+	pk_backend_set_percentage (python->priv->backend, percentage);
+	return Py_BuildValue("");
+}
+
+/**
+ * pk_backend_python_sub_percentage_changed_cb:
+ **/
+static PyObject *
+pk_backend_python_sub_percentage_changed_cb (PyObject *self, PyObject *args)
+{
+	guint sub_percentage;
+	PkBackendPython *python = PK_BACKEND_PYTHON (pk_backend_python_object);
+
+	pk_debug ("got signal");
+	PyArg_ParseTuple (args, "i", &sub_percentage);
+
+	pk_backend_set_sub_percentage (python->priv->backend, sub_percentage);
+	return Py_BuildValue("");
+}
+
+/**
+ * pk_backend_python_package_cb:
+ **/
+static PyObject *
+pk_backend_python_package_cb (PyObject *self, PyObject *args)
+{
+	const gchar *info_text;
+	const gchar *package_id;
+	const gchar *summary;
+	PkBackendPython *python = PK_BACKEND_PYTHON (pk_backend_python_object);
+
+	pk_debug ("got signal");
+	PyArg_ParseTuple (args, "sss", &info_text, &package_id, &summary);
+
+	pk_backend_package (python->priv->backend, pk_info_enum_from_text (info_text), package_id, summary);
+	return Py_BuildValue("");
+}
+
+/**
+ * pk_backend_python_details_cb:
+ **/
+static PyObject *
+pk_backend_python_details_cb (PyObject *self, PyObject *args)
+{
+	const gchar *package_id;
+	const gchar *license;
+	const gchar *group_text;
+	const gchar *detail;
+	const gchar *url;
+	guint64 size;
+	PkBackendPython *python = PK_BACKEND_PYTHON (pk_backend_python_object);
+
+	pk_debug ("got signal");
+	PyArg_ParseTuple (args, "sssssi", &package_id, &license, &group_text, &detail, &url, &size);
+
+	pk_backend_details (python->priv->backend, package_id,
+			    license, pk_group_enum_from_text (group_text),
+			    detail, url, size);
+	return Py_BuildValue("");
+}
+
+/**
+ * pk_backend_python_files_cb:
+ **/
+static PyObject *
+pk_backend_python_files_cb (PyObject *self, PyObject *args)
+{
+	const gchar *package_id;
+	const gchar *file_list;
+	PkBackendPython *python = PK_BACKEND_PYTHON (pk_backend_python_object);
+
+	pk_debug ("got signal");
+	PyArg_ParseTuple (args, "ss", &package_id, &file_list);
+
+	pk_backend_files (python->priv->backend, package_id, file_list);
+	return Py_BuildValue("");
+}
+
+/**
+ * pk_backend_python_update_detail_cb:
+ **/
+static PyObject *
+pk_backend_python_update_detail_cb (PyObject *self, PyObject *args)
+{
+	const gchar *package_id;
+	const gchar *updates;
+	const gchar *obsoletes;
+	const gchar *vendor_url;
+	const gchar *bugzilla_url;
+	const gchar *cve_url;
+	const gchar *restart_text;
+	const gchar *update_text;
+	PkBackendPython *python = PK_BACKEND_PYTHON (pk_backend_python_object);
+
+	pk_debug ("got signal");
+	PyArg_ParseTuple (args, "ssssssss", &package_id, &updates, &obsoletes,
+			  &vendor_url, &bugzilla_url, &cve_url, &restart_text, &update_text);
+
+	pk_backend_update_detail (python->priv->backend, package_id, updates,
+				  obsoletes, vendor_url, bugzilla_url, cve_url,
+				  pk_restart_enum_from_text (restart_text), update_text);
+	return Py_BuildValue("");
+}
+
+/**
+ * pk_backend_python_finished_cb:
+ **/
+static PyObject *
+pk_backend_python_finished_cb (PyObject *self, PyObject *args)
+{
+	const gchar *exit_text;
+	PkBackendPython *python = PK_BACKEND_PYTHON (pk_backend_python_object);
+
+	pk_debug ("got signal");
+	PyArg_ParseTuple (args, "s", &exit_text);
+
+	pk_debug ("deleting python %p, exit %s", python, exit_text);
+	pk_backend_finished (python->priv->backend);
+	return Py_BuildValue("");
+}
+
+/**
+ * pk_backend_python_allow_cancel_cb:
+ **/
+static PyObject *
+pk_backend_python_allow_cancel_cb (PyObject *self, PyObject *args)
+{
+	gboolean allow_cancel;
+	PkBackendPython *python = PK_BACKEND_PYTHON (pk_backend_python_object);
+
+	pk_debug ("got signal");
+	PyArg_ParseTuple (args, "i", &allow_cancel);
+
+	pk_backend_set_allow_cancel (python->priv->backend, allow_cancel);
+	return Py_BuildValue("");
+}
+
+/**
+ * pk_backend_python_error_code_cb:
+ **/
+static PyObject *
+pk_backend_python_error_code_cb (PyObject *self, PyObject *args)
+{
+	const gchar *error_text;
+	const gchar *details;
+	PkBackendPython *python = PK_BACKEND_PYTHON (pk_backend_python_object);
+
+	pk_debug ("got signal");
+	PyArg_ParseTuple (args, "ss", &error_text, &details);
+
+	pk_backend_error_code (python->priv->backend, pk_error_enum_from_text (error_text), details);
+	return Py_BuildValue("");
+}
+
+/**
+ * pk_backend_python_require_restart_cb:
+ **/
+static PyObject *
+pk_backend_python_require_restart_cb (PyObject *self, PyObject *args)
+{
+	const gchar *type_text;
+	const gchar *details;
+	PkBackendPython *python = PK_BACKEND_PYTHON (pk_backend_python_object);
+
+	pk_debug ("got signal");
+	PyArg_ParseTuple (args, "ss", &type_text, &details);
+
+	pk_backend_require_restart (python->priv->backend, pk_restart_enum_from_text (type_text), details);
+	return Py_BuildValue("");
+}
+
+/**
+ * pk_backend_python_message_cb:
+ **/
+static PyObject *
+pk_backend_python_message_cb (PyObject *self, PyObject *args)
+{
+	const gchar *message_text;
+	const gchar *details;
+	PkBackendPython *python = PK_BACKEND_PYTHON (pk_backend_python_object);
+
+	pk_debug ("got signal");
+	PyArg_ParseTuple (args, "ss", &message_text, &details);
+
+	pk_backend_message (python->priv->backend, pk_message_enum_from_text (message_text), details);
+	return Py_BuildValue("");
+}
+
+/**
+ * pk_backend_python_repo_signature_required_cb:
+ **/
+static PyObject *
+pk_backend_python_repo_signature_required_cb (PyObject *self, PyObject *args)
+{
+	const gchar *package_id;
+	const gchar *repository_name;
+	const gchar *key_url;
+	const gchar *key_userid;
+	const gchar *key_id;
+	const gchar *key_fingerprint;
+	const gchar *key_timestamp;
+	const gchar *type_text;
+	PkBackendPython *python = PK_BACKEND_PYTHON (pk_backend_python_object);
+
+	pk_debug ("got signal");
+	PyArg_ParseTuple (args, "ssssssss", &package_id, &repository_name,
+			  &key_url, &key_userid, &key_id, &key_fingerprint,
+			  &key_timestamp, &type_text);
+
+	pk_backend_repo_signature_required (python->priv->backend, package_id, repository_name,
+					    key_url, key_userid, key_id, key_fingerprint,
+					    key_timestamp, PK_SIGTYPE_ENUM_GPG);
+	return Py_BuildValue("");
+}
+
+/**
+ * pk_backend_python_eula_required_cb:
+ **/
+static PyObject *
+pk_backend_python_eula_required_cb (PyObject *self, PyObject *args)
+{
+	const gchar *eula_id;
+	const gchar *package_id;
+	const gchar *vendor_name;
+	const gchar *license_agreement;
+	PkBackendPython *python = PK_BACKEND_PYTHON (pk_backend_python_object);
+
+	pk_debug ("got signal");
+	PyArg_ParseTuple (args, "ssss", &eula_id, &package_id, &vendor_name, &license_agreement);
+
+	pk_backend_eula_required (python->priv->backend, eula_id, package_id,
+				  vendor_name, license_agreement);
+	return Py_BuildValue("");
+}
+
+/**
+ * pk_backend_python_import:
+ **/
+static gboolean
+pk_backend_python_import (PkBackendPython *python, const char *name)
+{
+	PyObject *pName;
+
+	pk_debug ("importing module %s", name);
+	pName = PyString_FromString (name);
+	python->priv->pModule = PyImport_Import (pName);
+	Py_DECREF (pName);
+
+	if (python->priv->pModule == NULL) {
+		PyErr_Print ();
+		return FALSE;
+	}
+	return TRUE;
+}
+
+/**
+ * pk_backend_python_get_instance:
+ **/
+static gboolean
+pk_backend_python_get_instance (PkBackendPython *python)
+{
+	PyObject *pDict;
+	PyObject *pClass;
+
+	/* pDict is a borrowed reference */
+	pDict = PyModule_GetDict (python->priv->pModule);
+
+	/* Build the name of a callable class */
+	pClass = PyDict_GetItemString (pDict, "PackageKitBackend");
+
+	/* Create an instance of the class */
+	if (!PyCallable_Check (pClass)) {
+		return FALSE;
+	}
+
+	python->priv->pInstance = PyObject_CallObject (pClass, NULL);
+	return TRUE;
+}
+
+/**
+ * pk_backend_python_startup:
+ **/
+gboolean
+pk_backend_python_startup (PkBackendPython *python, const gchar *filename)
+{
+	g_return_val_if_fail (PK_IS_BACKEND_PYTHON (python), FALSE);
+
+	/* import the file */
+	pk_backend_python_import (python, filename);
+	if (python->priv->pModule == NULL) {
+		pk_warning ("Failed to load");
+		return FALSE;
+	}
+
+	/* get an instance */
+	pk_backend_python_get_instance (python);
+	if (python->priv->pInstance == NULL) {
+		pk_warning ("Failed to get instance");
+		return FALSE;
+	}
+
+	return TRUE;
+}
+
+/**
+ * pk_backend_python_check_method:
+ **/
+gboolean
+pk_backend_python_check_method (PkBackendPython *python, const gchar *method_name)
+{
+	gboolean ret = TRUE;
+	PyObject *pFunc;
+
+	pFunc = PyObject_GetAttrString (python->priv->pInstance, method_name);
+	if (pFunc == NULL) {
+		pk_warning ("function NULL");
+		return FALSE;
+	}
+	ret = PyCallable_Check (pFunc);
+	if (!ret) {
+		pk_warning ("not callable");
+	}
+
+	if (pFunc != NULL) {
+		Py_DECREF (pFunc);
+	}
+	return ret;
+}
+
+/**
+ * pk_backend_python_cancel:
+ **/
+gboolean
+pk_backend_python_cancel (PkBackendPython *python)
+{
+	const gchar *method = "cancel";
+
+	g_return_val_if_fail (PK_IS_BACKEND_PYTHON (python), FALSE);
+	g_return_val_if_fail (python->priv->pInstance != NULL, FALSE);
+
+	if (!pk_backend_python_check_method (python, method)) {
+		pk_backend_not_implemented_yet (python->priv->backend, method);
+		return FALSE;
+	}
+	PyObject_CallMethod (python->priv->pInstance, (gchar*) method, NULL);
+	pk_backend_finished (python->priv->backend);
+
+	return TRUE;
+}
+
+/**
+ * pk_backend_python_get_updates:
+ **/
+gboolean
+pk_backend_python_get_updates (PkBackendPython *python)
+{
+	PkFilterEnum filters;
+	const gchar *method = "get_updates";
+
+	g_return_val_if_fail (PK_IS_BACKEND_PYTHON (python), FALSE);
+	g_return_val_if_fail (python->priv->pInstance != NULL, FALSE);
+
+	if (!pk_backend_python_check_method (python, method)) {
+		pk_backend_not_implemented_yet (python->priv->backend, method);
+		return FALSE;
+	}
+
+	filters = pk_backend_get_uint (python->priv->backend, "filters");
+	PyObject_CallMethod (python->priv->pInstance, (gchar*) method, "(s)",
+			     pk_filter_enums_to_text (filters));
+	pk_backend_finished (python->priv->backend);
+
+	return TRUE;
+}
+
+/**
+ * pk_backend_python_get_repo_list:
+ **/
+gboolean
+pk_backend_python_get_repo_list (PkBackendPython *python)
+{
+	PkFilterEnum filters;
+	const gchar *method = "get_repo_list";
+
+	g_return_val_if_fail (PK_IS_BACKEND_PYTHON (python), FALSE);
+	g_return_val_if_fail (python->priv->pInstance != NULL, FALSE);
+
+	if (!pk_backend_python_check_method (python, method)) {
+		pk_backend_not_implemented_yet (python->priv->backend, method);
+		return FALSE;
+	}
+
+	filters = pk_backend_get_uint (python->priv->backend, "filters");
+	PyObject_CallMethod (python->priv->pInstance, (gchar*) method, "(s)",
+			     pk_filter_enums_to_text (filters));
+	pk_backend_finished (python->priv->backend);
+
+	return TRUE;
+}
+
+/**
+ * pk_backend_python_refresh_cache:
+ **/
+gboolean
+pk_backend_python_refresh_cache (PkBackendPython *python)
+{
+	gboolean force;
+	const gchar *method = "refresh_cache";
+
+	g_return_val_if_fail (PK_IS_BACKEND_PYTHON (python), FALSE);
+	g_return_val_if_fail (python->priv->pInstance != NULL, FALSE);
+
+	if (!pk_backend_python_check_method (python, method)) {
+		pk_backend_not_implemented_yet (python->priv->backend, method);
+		return FALSE;
+	}
+
+	force = pk_backend_get_bool (python->priv->backend, "force");
+	PyObject_CallMethod (python->priv->pInstance, (gchar*) method, "(i)", force);
+	pk_backend_finished (python->priv->backend);
+
+	return TRUE;
+}
+
+/**
+ * pk_backend_python_update_system:
+ **/
+gboolean
+pk_backend_python_update_system (PkBackendPython *python)
+{
+	const gchar *method = "update_system";
+
+	g_return_val_if_fail (PK_IS_BACKEND_PYTHON (python), FALSE);
+	g_return_val_if_fail (python->priv->pInstance != NULL, FALSE);
+
+	if (!pk_backend_python_check_method (python, method)) {
+		pk_backend_not_implemented_yet (python->priv->backend, method);
+		return FALSE;
+	}
+	PyObject_CallMethod (python->priv->pInstance, (gchar*) method, NULL);
+	pk_backend_finished (python->priv->backend);
+
+	return TRUE;
+}
+
+/**
+ * pk_backend_python_repo_enable:
+ **/
+gboolean
+pk_backend_python_repo_enable (PkBackendPython *python)
+{
+	const gchar *rid;
+	gboolean enabled;
+	const gchar *method = "repo_enable";
+
+	g_return_val_if_fail (PK_IS_BACKEND_PYTHON (python), FALSE);
+	g_return_val_if_fail (python->priv->pInstance != NULL, FALSE);
+
+	if (!pk_backend_python_check_method (python, method)) {
+		pk_backend_not_implemented_yet (python->priv->backend, method);
+		return FALSE;
+	}
+
+	rid = pk_backend_get_string (python->priv->backend, "rid");
+	enabled = pk_backend_get_bool (python->priv->backend, "enabled");
+	PyObject_CallMethod (python->priv->pInstance, (gchar*) method, "(si)",
+			     rid, enabled);
+	pk_backend_finished (python->priv->backend);
+
+	return TRUE;
+}
+
+/**
+ * pk_backend_python_repo_set_data:
+ **/
+gboolean
+pk_backend_python_repo_set_data (PkBackendPython *python)
+{
+	const gchar *rid;
+	const gchar *parameter;
+	const gchar *value;
+	const gchar *method = "repo_set_data";
+
+	g_return_val_if_fail (PK_IS_BACKEND_PYTHON (python), FALSE);
+	g_return_val_if_fail (python->priv->pInstance != NULL, FALSE);
+
+	if (!pk_backend_python_check_method (python, method)) {
+		pk_backend_not_implemented_yet (python->priv->backend, method);
+		return FALSE;
+	}
+	rid = pk_backend_get_string (python->priv->backend, "rid");
+	parameter = pk_backend_get_string (python->priv->backend, "parameter");
+	value = pk_backend_get_string (python->priv->backend, "value");
+	PyObject_CallMethod (python->priv->pInstance, (gchar*) method, "(sss)",
+			     rid, parameter, value);
+	pk_backend_finished (python->priv->backend);
+
+	return TRUE;
+}
+
+/**
+ * pk_backend_python_resolve:
+ **/
+gboolean
+pk_backend_python_resolve (PkBackendPython *python)
+{
+	PkFilterEnum filters;
+	gchar **packages;
+	const gchar *method = "resolve";
+
+	g_return_val_if_fail (PK_IS_BACKEND_PYTHON (python), FALSE);
+	g_return_val_if_fail (python->priv->pInstance != NULL, FALSE);
+
+	if (!pk_backend_python_check_method (python, method)) {
+		pk_backend_not_implemented_yet (python->priv->backend, method);
+		return FALSE;
+	}
+	filters = pk_backend_get_uint (python->priv->backend, "filters");
+	packages = pk_backend_get_strv (python->priv->backend, "package_ids");
+	PyObject_CallMethod (python->priv->pInstance, (gchar*) method, "(ss)",
+			     pk_filter_enums_to_text (filters), packages);
+	pk_backend_finished (python->priv->backend);
+
+	return TRUE;
+}
+
+/**
+ * pk_backend_python_rollback:
+ **/
+gboolean
+pk_backend_python_rollback (PkBackendPython *python)
+{
+	const gchar *transaction_id;
+	const gchar *method = "rollback";
+
+	g_return_val_if_fail (PK_IS_BACKEND_PYTHON (python), FALSE);
+	g_return_val_if_fail (python->priv->pInstance != NULL, FALSE);
+
+	if (!pk_backend_python_check_method (python, method)) {
+		pk_backend_not_implemented_yet (python->priv->backend, method);
+		return FALSE;
+	}
+	transaction_id = pk_backend_get_string (python->priv->backend, "transaction_id");
+	PyObject_CallMethod (python->priv->pInstance, (gchar*) method, "(s)", transaction_id);
+	pk_backend_finished (python->priv->backend);
+
+	return TRUE;
+}
+
+/**
+ * pk_backend_python_search_name:
+ **/
+gboolean
+pk_backend_python_search_name (PkBackendPython *python)
+{
+	PkFilterEnum filters;
+	const gchar *search;
+	const gchar *method = "search_name";
+
+	g_return_val_if_fail (PK_IS_BACKEND_PYTHON (python), FALSE);
+	g_return_val_if_fail (python->priv->pInstance != NULL, FALSE);
+
+	if (!pk_backend_python_check_method (python, method)) {
+		pk_backend_not_implemented_yet (python->priv->backend, method);
+		return FALSE;
+	}
+	filters = pk_backend_get_uint (python->priv->backend, "filters");
+	search = pk_backend_get_string (python->priv->backend, "search");
+	PyObject_CallMethod (python->priv->pInstance, (gchar*) method, "(ss)",
+			     pk_filter_enums_to_text (filters), search);
+	pk_backend_finished (python->priv->backend);
+
+	return TRUE;
+}
+
+/**
+ * pk_backend_python_search_details:
+ **/
+gboolean
+pk_backend_python_search_details (PkBackendPython *python)
+{
+	PkFilterEnum filters;
+	const gchar *search;
+	const gchar *method = "search_details";
+
+	g_return_val_if_fail (PK_IS_BACKEND_PYTHON (python), FALSE);
+	g_return_val_if_fail (python->priv->pInstance != NULL, FALSE);
+
+	if (!pk_backend_python_check_method (python, method)) {
+		pk_backend_not_implemented_yet (python->priv->backend, method);
+		return FALSE;
+	}
+	filters = pk_backend_get_uint (python->priv->backend, "filters");
+	search = pk_backend_get_string (python->priv->backend, "search");
+	PyObject_CallMethod (python->priv->pInstance, (gchar*) method, "(ss)",
+			     pk_filter_enums_to_text (filters), search);
+	pk_backend_finished (python->priv->backend);
+
+	return TRUE;
+}
+
+/**
+ * pk_backend_python_search_group:
+ **/
+gboolean
+pk_backend_python_search_group (PkBackendPython *python)
+{
+	PkFilterEnum filters;
+	const gchar *search;
+	const gchar *method = "search_group";
+
+	g_return_val_if_fail (PK_IS_BACKEND_PYTHON (python), FALSE);
+	g_return_val_if_fail (python->priv->pInstance != NULL, FALSE);
+
+	if (!pk_backend_python_check_method (python, method)) {
+		pk_backend_not_implemented_yet (python->priv->backend, method);
+		return FALSE;
+	}
+	filters = pk_backend_get_uint (python->priv->backend, "filters");
+	search = pk_backend_get_string (python->priv->backend, "search");
+	PyObject_CallMethod (python->priv->pInstance, (gchar*) method, "(ss)",
+			     pk_filter_enums_to_text (filters), search);
+	pk_backend_finished (python->priv->backend);
+
+	return TRUE;
+}
+
+/**
+ * pk_backend_python_search_file:
+ **/
+gboolean
+pk_backend_python_search_file (PkBackendPython *python)
+{
+	PkFilterEnum filters;
+	const gchar *search;
+	const gchar *method = "search_file";
+
+	g_return_val_if_fail (PK_IS_BACKEND_PYTHON (python), FALSE);
+	g_return_val_if_fail (python->priv->pInstance != NULL, FALSE);
+
+	if (!pk_backend_python_check_method (python, method)) {
+		pk_backend_not_implemented_yet (python->priv->backend, method);
+		return FALSE;
+	}
+	filters = pk_backend_get_uint (python->priv->backend, "filters");
+	search = pk_backend_get_string (python->priv->backend, "search");
+	PyObject_CallMethod (python->priv->pInstance, (gchar*) method, "(ss)",
+			     pk_filter_enums_to_text (filters), search);
+	pk_backend_finished (python->priv->backend);
+
+	return TRUE;
+}
+
+/**
+ * pk_backend_python_get_depends:
+ **/
+gboolean
+pk_backend_python_get_depends (PkBackendPython *python)
+{
+	PkFilterEnum filters;
+	gchar **package_ids;
+	gboolean recursive;
+	const gchar *method = "get_depends";
+
+	g_return_val_if_fail (PK_IS_BACKEND_PYTHON (python), FALSE);
+	g_return_val_if_fail (python->priv->pInstance != NULL, FALSE);
+
+	if (!pk_backend_python_check_method (python, method)) {
+		pk_backend_not_implemented_yet (python->priv->backend, method);
+		return FALSE;
+	}
+	filters = pk_backend_get_uint (python->priv->backend, "filters");
+	package_ids = pk_backend_get_strv (python->priv->backend, "package_ids");
+	recursive = pk_backend_get_bool (python->priv->backend, "recursive");
+	PyObject_CallMethod (python->priv->pInstance, (gchar*) method, "(sssss)",
+			     pk_filter_enums_to_text (filters), package_ids, recursive);
+	pk_backend_finished (python->priv->backend);
+
+	return TRUE;
+}
+
+/**
+ * pk_backend_python_get_requires:
+ **/
+gboolean
+pk_backend_python_get_requires (PkBackendPython *python)
+{
+	PkFilterEnum filters;
+	gchar **package_ids;
+	gboolean recursive;
+	const gchar *method = "get_requires";
+
+	g_return_val_if_fail (PK_IS_BACKEND_PYTHON (python), FALSE);
+	g_return_val_if_fail (python->priv->pInstance != NULL, FALSE);
+
+	if (!pk_backend_python_check_method (python, method)) {
+		pk_backend_not_implemented_yet (python->priv->backend, method);
+		return FALSE;
+	}
+	filters = pk_backend_get_uint (python->priv->backend, "filters");
+	package_ids = pk_backend_get_strv (python->priv->backend, "package_ids");
+	recursive = pk_backend_get_bool (python->priv->backend, "recursive");
+	PyObject_CallMethod (python->priv->pInstance, (gchar*) method, "(sss)",
+			     pk_filter_enums_to_text (filters), package_ids, recursive);
+	pk_backend_finished (python->priv->backend);
+
+	return TRUE;
+}
+
+/**
+ * pk_backend_python_get_packages:
+ **/
+gboolean
+pk_backend_python_get_packages (PkBackendPython *python)
+{
+	PkFilterEnum filters;
+	const gchar *method = "get_packages";
+
+	g_return_val_if_fail (PK_IS_BACKEND_PYTHON (python), FALSE);
+	g_return_val_if_fail (python->priv->pInstance != NULL, FALSE);
+
+	if (!pk_backend_python_check_method (python, method)) {
+		pk_backend_not_implemented_yet (python->priv->backend, method);
+		return FALSE;
+	}
+	filters = pk_backend_get_uint (python->priv->backend, "filters");
+	PyObject_CallMethod (python->priv->pInstance, (gchar*) method, "(s)",
+			     pk_filter_enums_to_text (filters));
+	pk_backend_finished (python->priv->backend);
+
+	return TRUE;
+}
+
+/**
+ * pk_backend_python_download_packages:
+ **/
+gboolean
+pk_backend_python_download_packages (PkBackendPython *python)
+{
+	gchar **package_ids;
+	const gchar *directory;
+	const gchar *method = "download_packages";
+
+	g_return_val_if_fail (PK_IS_BACKEND_PYTHON (python), FALSE);
+	g_return_val_if_fail (python->priv->pInstance != NULL, FALSE);
+
+	if (!pk_backend_python_check_method (python, method)) {
+		pk_backend_not_implemented_yet (python->priv->backend, method);
+		return FALSE;
+	}
+	package_ids = pk_backend_get_strv (python->priv->backend, "package_ids");
+	directory = pk_backend_get_string (python->priv->backend, "directory");
+	PyObject_CallMethod (python->priv->pInstance, (gchar*) method, "(ss)", package_ids, directory);
+	pk_backend_finished (python->priv->backend);
+
+	return TRUE;
+}
+
+
+/**
+ * pk_backend_python_get_update_detail:
+ **/
+gboolean
+pk_backend_python_get_update_detail (PkBackendPython *python)
+{
+	gchar **package_ids;
+	const gchar *method = "get_update_detail";
+
+	g_return_val_if_fail (PK_IS_BACKEND_PYTHON (python), FALSE);
+	g_return_val_if_fail (python->priv->pInstance != NULL, FALSE);
+
+	if (!pk_backend_python_check_method (python, method)) {
+		pk_backend_not_implemented_yet (python->priv->backend, method);
+		return FALSE;
+	}
+	package_ids = pk_backend_get_strv (python->priv->backend, "package_ids");
+	PyObject_CallMethod (python->priv->pInstance, (gchar*) method, "(s)", package_ids);
+	pk_backend_finished (python->priv->backend);
+
+	return TRUE;
+}
+
+/**
+ * pk_backend_python_get_details:
+ **/
+gboolean
+pk_backend_python_get_details (PkBackendPython *python)
+{
+	gchar **package_ids;
+	const gchar *method = "get_details";
+
+	g_return_val_if_fail (PK_IS_BACKEND_PYTHON (python), FALSE);
+	g_return_val_if_fail (python->priv->pInstance != NULL, FALSE);
+
+	if (!pk_backend_python_check_method (python, method)) {
+		pk_backend_not_implemented_yet (python->priv->backend, method);
+		return FALSE;
+	}
+	package_ids = pk_backend_get_strv (python->priv->backend, "package_ids");
+	PyObject_CallMethod (python->priv->pInstance, (gchar*) method, "(s)", package_ids);
+	pk_backend_finished (python->priv->backend);
+
+	return TRUE;
+}
+
+/**
+ * pk_backend_python_get_files:
+ **/
+gboolean
+pk_backend_python_get_files (PkBackendPython *python)
+{
+	gchar **package_ids;
+	const gchar *method = "get_files";
+
+	g_return_val_if_fail (PK_IS_BACKEND_PYTHON (python), FALSE);
+	g_return_val_if_fail (python->priv->pInstance != NULL, FALSE);
+
+	if (!pk_backend_python_check_method (python, method)) {
+		pk_backend_not_implemented_yet (python->priv->backend, method);
+		return FALSE;
+	}
+	package_ids = pk_backend_get_strv (python->priv->backend, "package_ids");
+	PyObject_CallMethod (python->priv->pInstance, (gchar*) method, "(s)", package_ids);
+	pk_backend_finished (python->priv->backend);
+
+	return TRUE;
+}
+
+/**
+ * pk_backend_python_remove_packages:
+ **/
+gboolean
+pk_backend_python_remove_packages (PkBackendPython *python)
+{
+	gchar **package_ids;
+	gboolean allow_deps;
+	gboolean autoremove;
+	const gchar *method = "remove_packages";
+
+	g_return_val_if_fail (PK_IS_BACKEND_PYTHON (python), FALSE);
+	g_return_val_if_fail (python->priv->pInstance != NULL, FALSE);
+
+	if (!pk_backend_python_check_method (python, method)) {
+		pk_backend_not_implemented_yet (python->priv->backend, method);
+		return FALSE;
+	}
+	package_ids = pk_backend_get_strv (python->priv->backend, "package_ids");
+	allow_deps = pk_backend_get_bool (python->priv->backend, "allowdeps");
+	autoremove = pk_backend_get_bool (python->priv->backend, "autoremove");
+	PyObject_CallMethod (python->priv->pInstance, (gchar*) method, "(sii)",
+			     package_ids, allow_deps, autoremove);
+	pk_backend_finished (python->priv->backend);
+
+	return TRUE;
+}
+
+/**
+ * pk_backend_python_install_packages:
+ **/
+gboolean
+pk_backend_python_install_packages (PkBackendPython *python)
+{
+	gchar **package_ids;
+	const gchar *method = "install_packages";
+
+	g_return_val_if_fail (PK_IS_BACKEND_PYTHON (python), FALSE);
+	g_return_val_if_fail (python->priv->pInstance != NULL, FALSE);
+
+	if (!pk_backend_python_check_method (python, method)) {
+		pk_backend_not_implemented_yet (python->priv->backend, method);
+		return FALSE;
+	}
+	package_ids = pk_backend_get_strv (python->priv->backend, "package_ids");
+	PyObject_CallMethod (python->priv->pInstance, (gchar*) method, "(s)",
+			     package_ids);
+	pk_backend_finished (python->priv->backend);
+
+	return TRUE;
+}
+
+/**
+ * pk_backend_python_update_packages:
+ **/
+gboolean
+pk_backend_python_update_packages (PkBackendPython *python)
+{
+	gchar **package_ids;
+	const gchar *method = "update_packages";
+
+	g_return_val_if_fail (PK_IS_BACKEND_PYTHON (python), FALSE);
+	g_return_val_if_fail (python->priv->pInstance != NULL, FALSE);
+
+	if (!pk_backend_python_check_method (python, method)) {
+		pk_backend_not_implemented_yet (python->priv->backend, method);
+		return FALSE;
+	}
+	package_ids = pk_backend_get_strv (python->priv->backend, "package_ids");
+	PyObject_CallMethod (python->priv->pInstance, (gchar*) method, "(s)",
+			     package_ids);
+	pk_backend_finished (python->priv->backend);
+
+	return TRUE;
+}
+
+/**
+ * pk_backend_python_install_files:
+ **/
+gboolean
+pk_backend_python_install_files (PkBackendPython *python)
+{
+	gboolean trusted;
+	gchar **full_paths;
+	const gchar *method = "install_files";
+
+	g_return_val_if_fail (PK_IS_BACKEND_PYTHON (python), FALSE);
+	g_return_val_if_fail (python->priv->pInstance != NULL, FALSE);
+
+	if (!pk_backend_python_check_method (python, method)) {
+		pk_backend_not_implemented_yet (python->priv->backend, method);
+		return FALSE;
+	}
+	trusted = pk_backend_get_bool (python->priv->backend, "trusted");
+	full_paths = pk_backend_get_strv (python->priv->backend, "paths");
+	PyObject_CallMethod (python->priv->pInstance, (gchar*) method, "(bs)",
+			     trusted, full_paths);
+	pk_backend_finished (python->priv->backend);
+
+	return TRUE;
+}
+
+/**
+ * pk_backend_python_service_pack:
+ **/
+gboolean
+pk_backend_python_service_pack (PkBackendPython *python)
+{
+	const gchar *location;
+	gboolean enabled;
+	const gchar *method = "service_pack";
+
+	g_return_val_if_fail (PK_IS_BACKEND_PYTHON (python), FALSE);
+	g_return_val_if_fail (python->priv->pInstance != NULL, FALSE);
+
+	if (!pk_backend_python_check_method (python, method)) {
+		pk_backend_not_implemented_yet (python->priv->backend, method);
+		return FALSE;
+	}
+	enabled = pk_backend_get_bool (python->priv->backend, "enabled");
+	location = pk_backend_get_string (python->priv->backend, "location");
+	PyObject_CallMethod (python->priv->pInstance, (gchar*) method, "(is)",
+			     enabled, location);
+	pk_backend_finished (python->priv->backend);
+
+	return TRUE;
+}
+
+/**
+ * pk_backend_python_what_provides:
+ **/
+gboolean
+pk_backend_python_what_provides (PkBackendPython *python)
+{
+	PkFilterEnum filters;
+	PkProvidesEnum provides;
+	const gchar *search;
+	const gchar *method = "what_provides";
+
+	g_return_val_if_fail (PK_IS_BACKEND_PYTHON (python), FALSE);
+	g_return_val_if_fail (python->priv->pInstance != NULL, FALSE);
+
+	if (!pk_backend_python_check_method (python, method)) {
+		pk_backend_not_implemented_yet (python->priv->backend, method);
+		return FALSE;
+	}
+	filters = pk_backend_get_uint (python->priv->backend, "filters");
+	provides = pk_backend_get_uint (python->priv->backend, "provides");
+	search = pk_backend_get_string (python->priv->backend, "search");
+	PyObject_CallMethod (python->priv->pInstance, (gchar*) method, "(sss)",
+			     pk_filter_enums_to_text (filters),
+			     pk_provides_enum_to_text (provides), search);
+	pk_backend_finished (python->priv->backend);
+
+	return TRUE;
+}
+
+/**
+ * pk_backend_python_finalize:
+ **/
+static void
+pk_backend_python_finalize (GObject *object)
+{
+	PkBackendPython *python;
+	g_return_if_fail (PK_IS_BACKEND_PYTHON (object));
+
+	python = PK_BACKEND_PYTHON (object);
+
+	g_object_unref (python->priv->backend);
+	Py_Finalize();
+
+	G_OBJECT_CLASS (pk_backend_python_parent_class)->finalize (object);
+}
+
+/**
+ * pk_backend_python_class_init:
+ **/
+static void
+pk_backend_python_class_init (PkBackendPythonClass *klass)
+{
+	GObjectClass *object_class = G_OBJECT_CLASS (klass);
+	object_class->finalize = pk_backend_python_finalize;
+	g_type_class_add_private (klass, sizeof (PkBackendPythonPrivate));
+}
+
+/**
+ * pk_backend_python_init:
+ **/
+static void
+pk_backend_python_init (PkBackendPython *python)
+{
+	const gchar *path;
+
+	python->priv = PK_BACKEND_PYTHON_GET_PRIVATE (python);
+	python->priv->pModule = NULL;
+	python->priv->pInstance = NULL;
+	python->priv->backend = pk_backend_new ();
+
+	setenv ("PYTHONPATH", "/home/hughsie/Code/PackageKit/backends/yum3/helpers", 1);
+	path = getenv ("PYTHONPATH");
+	pk_debug ("PYTHONPATH=%s", path);
+
+	Py_Initialize ();
+	Py_InitModule ("PackageKitBaseBackend", PkBackendPythonMethods);
+}
+
+/**
+ * pk_backend_python_new:
+ **/
+PkBackendPython *
+pk_backend_python_new (void)
+{
+	if (pk_backend_python_object != NULL) {
+		g_object_ref (pk_backend_python_object);
+	} else {
+		pk_backend_python_object = g_object_new (PK_TYPE_BACKEND_PYTHON, NULL);
+		g_object_add_weak_pointer (pk_backend_python_object, &pk_backend_python_object);
+	}
+	return PK_BACKEND_PYTHON (pk_backend_python_object);
+}
+
+/***************************************************************************
+ ***                          MAKE CHECK TESTS                           ***
+ ***************************************************************************/
+#ifdef PK_BUILD_TESTS
+#include <libselftest.h>
+
+void
+libst_backend_python (LibSelfTest *test)
+{
+	if (libst_start (test, "PkBackendPython", CLASS_AUTO) == FALSE) {
+		return;
+	}
+
+	libst_end (test);
+}
+#endif
+
diff --git a/src/pk-backend-python.h b/src/pk-backend-python.h
new file mode 100644
index 0000000..c9923a1
--- /dev/null
+++ b/src/pk-backend-python.h
@@ -0,0 +1,83 @@
+/* -*- Mode: C; tab-width: 8; indent-tabs-mode: t; c-basic-offset: 8 -*-
+ *
+ * Copyright (C) 2008 Richard Hughes <richard at hughsie.com>
+ *
+ * Licensed under the GNU General Public License Version 2
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+ */
+
+#ifndef __PK_BACKEND_PYTHON_H
+#define __PK_BACKEND_PYTHON_H
+
+#include <glib-object.h>
+#include "pk-backend.h"
+
+G_BEGIN_DECLS
+
+#define PK_TYPE_BACKEND_PYTHON		(pk_backend_python_get_type ())
+#define PK_BACKEND_PYTHON(o)		(G_TYPE_CHECK_INSTANCE_CAST ((o), PK_TYPE_BACKEND_PYTHON, PkBackendPython))
+#define PK_BACKEND_PYTHON_CLASS(k)	(G_TYPE_CHECK_CLASS_CAST((k), PK_TYPE_BACKEND_PYTHON, PkBackendPythonClass))
+#define PK_IS_BACKEND_PYTHON(o)		(G_TYPE_CHECK_INSTANCE_TYPE ((o), PK_TYPE_BACKEND_PYTHON))
+#define PK_IS_BACKEND_PYTHON_CLASS(k)	(G_TYPE_CHECK_CLASS_TYPE ((k), PK_TYPE_BACKEND_PYTHON))
+#define PK_BACKEND_PYTHON_GET_CLASS(o)	(G_TYPE_INSTANCE_GET_CLASS ((o), PK_TYPE_BACKEND_PYTHON, PkBackendPythonClass))
+
+typedef struct PkBackendPythonPrivate PkBackendPythonPrivate;
+
+typedef struct
+{
+	 GObject		 parent;
+	 PkBackendPythonPrivate	*priv;
+} PkBackendPython;
+
+typedef struct
+{
+	GObjectClass	parent_class;
+} PkBackendPythonClass;
+
+GType		 pk_backend_python_get_type		(void) G_GNUC_CONST;
+PkBackendPython	*pk_backend_python_new			(void);
+gboolean	 pk_backend_python_refresh_cache	(PkBackendPython *python);
+gboolean	 pk_backend_python_update_system	(PkBackendPython *python);
+gboolean	 pk_backend_python_resolve		(PkBackendPython *python);
+gboolean	 pk_backend_python_rollback		(PkBackendPython *python);
+gboolean	 pk_backend_python_search_name		(PkBackendPython *python);
+gboolean	 pk_backend_python_search_details	(PkBackendPython *python);
+gboolean	 pk_backend_python_search_group		(PkBackendPython *python);
+gboolean	 pk_backend_python_search_file		(PkBackendPython *python);
+gboolean	 pk_backend_python_get_packages		(PkBackendPython *python);
+gboolean	 pk_backend_python_download_packages	(PkBackendPython *python);
+gboolean	 pk_backend_python_get_depends		(PkBackendPython *python);
+gboolean	 pk_backend_python_get_requires		(PkBackendPython *python);
+gboolean	 pk_backend_python_get_update_detail	(PkBackendPython *python);
+gboolean	 pk_backend_python_get_details		(PkBackendPython *python);
+gboolean	 pk_backend_python_get_files		(PkBackendPython *python);
+gboolean	 pk_backend_python_remove_packages	(PkBackendPython *python);
+gboolean	 pk_backend_python_install_packages	(PkBackendPython *python);
+gboolean	 pk_backend_python_update_packages	(PkBackendPython *python);
+gboolean	 pk_backend_python_install_files	(PkBackendPython *python);
+gboolean	 pk_backend_python_service_pack		(PkBackendPython *python);
+gboolean	 pk_backend_python_what_provides	(PkBackendPython *python);
+gboolean	 pk_backend_python_repo_enable		(PkBackendPython *python);
+gboolean	 pk_backend_python_repo_set_data	(PkBackendPython *python);
+gboolean	 pk_backend_python_get_repo_list	(PkBackendPython *python);
+gboolean	 pk_backend_python_cancel		(PkBackendPython *python);
+gboolean	 pk_backend_python_get_updates		(PkBackendPython *python);
+gboolean	 pk_backend_python_startup		(PkBackendPython *python,
+							 const gchar	 *filename);
+
+G_END_DECLS
+
+#endif /* __PK_BACKEND_PYTHON_H */
commit 3024c821cd795a9586f01f763174b46b4d091767
Author: Richard Hughes <richard at hughsie.com>
Date:   Thu Jul 10 15:18:57 2008 +0100

    trivial: add the build pieces to allow building with Python.h and an embedded interpreter in the future

diff --git a/configure.ac b/configure.ac
index dd0074c..e184e53 100644
--- a/configure.ac
+++ b/configure.ac
@@ -45,11 +45,6 @@ GTK_DOC_CHECK(1.9)
 
 AC_PATH_PROG(GLIB_GENMARSHAL, glib-genmarshal)
 
-AM_PATH_PYTHON
-PYTHON_PACKAGE_DIR=${pythondir}/packagekit
-AC_SUBST(PYTHON_PACKAGE_DIR)
-
-
 dnl ---------------------------------------------------------------------------
 dnl - Extra verbose warning switches
 dnl ---------------------------------------------------------------------------
@@ -154,6 +149,33 @@ if test "$DOCBOOK2MAN" = "no" ; then
 	fi
 AM_CONDITIONAL(HAVE_DOCBOOK2MAN, [test "$DOCBOOK2MAN" != "no"])
 
+AM_PATH_PYTHON([2.3],[],[have_python=no])
+if test "x$PYTHON" = "x:"; then
+	have_python=no
+fi
+
+PY_PREFIX=`$PYTHON -c 'import sys ; print sys.prefix'`
+PY_EXEC_PREFIX=`$PYTHON -c 'import sys ; print sys.exec_prefix'`
+PYTHON_LIBS="-lpython$PYTHON_VERSION"
+if test -d $PY_EXEC_PREFIX/lib64/python$PYTHON_VERSION ; then
+	PYTHON_LIB_LOC="-L$PY_EXEC_PREFIX/lib64/python$PYTHON_VERSION/config"
+	PYTHON_MAKEFILE="$PY_EXEC_PREFIX/lib64/python$PYTHON_VERSION/config/Makefile"
+else
+	PYTHON_LIB_LOC="-L$PY_EXEC_PREFIX/lib/python$PYTHON_VERSION/config"
+	PYTHON_MAKEFILE="$PY_EXEC_PREFIX/lib/python$PYTHON_VERSION/config/Makefile"
+fi
+PYTHON_CFLAGS="-I$PY_PREFIX/include/python$PYTHON_VERSION"
+PYTHON_LOCALMODLIBS=`sed -n -e 's/^LOCALMODLIBS=\(.*\)/\1/p' $PYTHON_MAKEFILE`
+PYTHON_BASEMODLIBS=`sed -n -e 's/^BASEMODLIBS=\(.*\)/\1/p' $PYTHON_MAKEFILE`
+PYTHON_OTHER_LIBS=`sed -n -e 's/^LIBS=\(.*\)/\1/p' $PYTHON_MAKEFILE`
+PYTHON_EXTRA_LIBS="$PYTHON_LOCALMODLIBS $PYTHON_BASEMODLIBS $PYTHON_OTHER_LIBS"
+PYTHON_PACKAGE_DIR=${pythondir}/packagekit
+AC_SUBST([PYTHON_LIBS])
+AC_SUBST([PYTHON_LIB_LOC])
+AC_SUBST([PYTHON_CFLAGS])
+AC_SUBST([PYTHON_EXTRA_LIBS])
+AC_SUBST(PYTHON_PACKAGE_DIR)
+
 dnl ---------------------------------------------------------------------------
 dnl - Make paths available for source files
 dnl ---------------------------------------------------------------------------
diff --git a/src/Makefile.am b/src/Makefile.am
index fb7a7ec..242ffa3 100644
--- a/src/Makefile.am
+++ b/src/Makefile.am
@@ -17,6 +17,7 @@ INCLUDES =						\
 	$(DBUS_CFLAGS)					\
 	$(SQLITE_CFLAGS)				\
 	$(POLKIT_CFLAGS)				\
+	$(PYTHON_CFLAGS)				\
 	$(LIBNM_CFLAGS)					\
 	-DBINDIR=\"$(bindir)\"			 	\
 	-DSBINDIR=\"$(sbindir)\"		 	\
@@ -123,6 +124,7 @@ packagekitd_LDADD =					\
 	$(DBUS_LIBS)					\
 	$(SQLITE_LIBS)					\
 	$(PK_LIBS)					\
+	$(PYTHON_LIBS)					\
 	$(POLKIT_LIBS)					\
 	$(SELFTEST_LIBS)				\
 	$(GIO_LIBS)					\
commit 85524da4904ad4f8dd75dced94d33257a6bc9af1
Author: Richard Hughes <richard at hughsie.com>
Date:   Thu Jul 10 15:17:40 2008 +0100

    trivial: allow n-i-y when we have not got a valid TID - so we don't hang the dameon in the event of a crap backend programmer (me)

diff --git a/src/pk-backend.c b/src/pk-backend.c
index 4b5d2c5..4b67422 100644
--- a/src/pk-backend.c
+++ b/src/pk-backend.c
@@ -1552,8 +1552,7 @@ pk_backend_not_implemented_yet (PkBackend *backend, const gchar *method)
 
 	/* this function is only valid when we have a running transaction */
 	if (backend->priv->c_tid != NULL) {
-		pk_error ("only valid when we have a running transaction");
-		return FALSE;
+		pk_warning ("only valid when we have a running transaction");
 	}
 	pk_backend_error_code (backend, PK_ERROR_ENUM_NOT_SUPPORTED, "the method '%s' is not implemented yet", method);
 	/* don't wait, do this now */
commit a792cf950e5c4d32ef5fb0dc08c63f38e89ec6fb
Author: Richard Hughes <richard at hughsie.com>
Date:   Thu Jul 10 15:12:00 2008 +0100

    trivial: update the repo viewer screenshots

diff --git a/docs/html/img/Makefile.am b/docs/html/img/Makefile.am
index 1b1a645..a2d4a44 100644
--- a/docs/html/img/Makefile.am
+++ b/docs/html/img/Makefile.am
@@ -26,6 +26,7 @@ IMAGE_FILES =					\
 	gpk-progress.png			\
 	gpk-repo-auth.png			\
 	gpk-repo.png				\
+	gpk-repo-more.png			\
 	gpk-require-restart.png			\
 	gpk-log.png				\
 	gpk-updates.png				\
diff --git a/docs/html/img/gpk-repo-more.png b/docs/html/img/gpk-repo-more.png
new file mode 100644
index 0000000..9088612
Binary files /dev/null and b/docs/html/img/gpk-repo-more.png differ
diff --git a/docs/html/img/gpk-repo.png b/docs/html/img/gpk-repo.png
index aa6fc66..2fa061b 100644
Binary files a/docs/html/img/gpk-repo.png and b/docs/html/img/gpk-repo.png differ
diff --git a/docs/html/pk-screenshots.html b/docs/html/pk-screenshots.html
index f35352f..be43853 100644
--- a/docs/html/pk-screenshots.html
+++ b/docs/html/pk-screenshots.html
@@ -65,6 +65,9 @@
 <center><img src="img/gpk-repo.png" alt=""/></center>
 <p class="caption">Repository viewer</p>
 
+<center><img src="img/gpk-repo-more.png" alt=""/></center>
+<p class="caption">Repository viewer (for geeks)</p>
+
 <center><img src="img/gpk-backend-status.png" alt=""/></center>
 <p class="caption">PackageKit backend status</p>
 
commit 874c3ec38a9536e893fc2a1bba4d054ff8082d58
Author: Richard Hughes <richard at hughsie.com>
Date:   Tue Jul 8 16:21:00 2008 +0100

    trivial: fix up two typos in the new yum cleanup

diff --git a/backends/yum/helpers/yumBackend.py b/backends/yum/helpers/yumBackend.py
index 649c93d..95f9c09 100644
--- a/backends/yum/helpers/yumBackend.py
+++ b/backends/yum/helpers/yumBackend.py
@@ -1445,10 +1445,10 @@ class PackageKitCallback(RPMBaseCallback):
 
     def _showName(self,status):
         if type(self.curpkg) in types.StringTypes:
-            id = self.base.get_package_id(self.curpkg,'','','')
+            id = pkpackage.get_package_id(self.curpkg,'','','')
         else:
             pkgver = self.base._get_package_ver(self.curpkg)
-            id = self.base.get_package_id(self.curpkg.name,pkgver,self.curpkg.arch,self.curpkg.repo)
+            id = pkpackage.get_package_id(self.curpkg.name,pkgver,self.curpkg.arch,self.curpkg.repo)
         self.base.package(id,status,"")
 
     def event(self,package,action,te_current,te_total,ts_current,ts_total):
commit ea73c8f576e0d8e37ff1a11f38f9e525ad5e2370
Author: Richard Hughes <richard at hughsie.com>
Date:   Tue Jul 8 14:56:33 2008 +0100

    bugfix: don't optimise for the common case in pk-import-desktop as we really want to regenerate the cache even if it's slow

diff --git a/client/pk-import-desktop.c b/client/pk-import-desktop.c
index 8f46a77..6c29d16 100644
--- a/client/pk-import-desktop.c
+++ b/client/pk-import-desktop.c
@@ -123,16 +123,6 @@ pk_desktop_process_desktop (const gchar *package_name, const gchar *filename)
 	gsize len;
 	gchar *locale_temp;
 	static GPtrArray *locale_array = NULL;
-	const gchar *icon_name;
-	const gchar *summary;
-
-	/* can we optimise for the common case? */
-	icon_name = pk_extra_get_icon_name (extra, package_name);
-	summary = pk_extra_get_summary (extra, package_name);
-	if (icon_name != NULL || summary != NULL) {
-		g_print ("PackageName:\t%s\t[skipping]\n", package_name);
-		return;
-	}
 
 	key = g_key_file_new ();
 	ret = g_key_file_load_from_file (key, filename, G_KEY_FILE_KEEP_TRANSLATIONS, NULL);
commit 38711d9adb9226de331b077902ae4a4f3549a6ed
Author: Richard Hughes <richard at hughsie.com>
Date:   Tue Jul 8 01:55:24 2008 +0100

    trivial: fix make distcheck

diff --git a/python/packagekit/Makefile.am b/python/packagekit/Makefile.am
index 12da73f..4c65216 100644
--- a/python/packagekit/Makefile.am
+++ b/python/packagekit/Makefile.am
@@ -14,6 +14,8 @@ packagekitpython_PYTHON =				\
 	daemonBackend.py				\
 	pkexceptions.py					\
 	pkdbus.py					\
+	progress.py					\
+	package.py					\
 	$(NULL)
 
 clean-local :
diff --git a/python/packagekit/daemonBackend.py b/python/packagekit/daemonBackend.py
index b0062e7..b6a111f 100644
--- a/python/packagekit/daemonBackend.py
+++ b/python/packagekit/daemonBackend.py
@@ -431,14 +431,14 @@ class PackageKitBaseBackend(dbus.service.Object):
 
     @dbus.service.method(PACKAGEKIT_DBUS_INTERFACE,
 			 in_signature='ss',out_signature='')
-    def DownloadPackages(self,package_ids,directory)
+    def DownloadPackages(self,package_ids,directory):
 	'''
 	Implement the (backend)-download-packages functionality
 	'''
 	pklog.info("DownloadPackages(%s%s)" % (packages,directory))
 	self.doDownloadPackages(packages,directory)
 
-    def doDownloadPackages(self,package_ids,directory)
+    def doDownloadPackages(self,package_ids,directory):
 	'''
 	Should be replaced in the corresponding backend sub class
 	'''
commit 52bb8a7acd022cd97dbb4043d87aebfacc57d6a0
Author: Richard Hughes <richard at hughsie.com>
Date:   Tue Jul 8 00:43:44 2008 +0100

    bugfix: bump the soname as we changed ABI some time ago

diff --git a/configure.ac b/configure.ac
index a8a9a1a..dd0074c 100644
--- a/configure.ac
+++ b/configure.ac
@@ -18,7 +18,7 @@ DEVELOPMENT_RELEASE=no
 # REVISION	If the API and ABI remains the same, but bugs are fixed.
 # AGE		If libpackagekit can be linked into executables which can be
 # 		built with previous versions of this library. Don't use.
-LT_CURRENT=3
+LT_CURRENT=4
 LT_REVISION=0
 LT_AGE=0
 AC_SUBST(LT_CURRENT)
commit ad6477055f5e8d8c25525ee590b169be04f7f0ec
Author: Richard Hughes <richard at hughsie.com>
Date:   Tue Jul 8 00:32:48 2008 +0100

    yum tidy up yumBackend and use yumComps, yumDirect and yumProgress -- speed up most some actions by two orders of magnitude -- needs testing

diff --git a/backends/yum/helpers/yumBackend.py b/backends/yum/helpers/yumBackend.py
index a5acfe0..649c93d 100644
--- a/backends/yum/helpers/yumBackend.py
+++ b/backends/yum/helpers/yumBackend.py
@@ -14,18 +14,21 @@
 # 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
+# Copyright (C) 2007-2008
 #    Tim Lauridsen <timlau at fedoraproject.org>
 #    Seth Vidal <skvidal at fedoraproject.org>
 #    Luke Macken <lmacken at redhat.com>
 #    James Bowes <jbowes at dangerouslyinc.com>
 #    Robin Norwood <rnorwood at redhat.com>
+#    Richard Hughes <richard at hughsie.com>
 
 # imports
 
 import re
 
 from packagekit.backend import *
+from packagekit.progress import *
+from packagekit.package import *
 import yum
 from urlgrabber.progress import BaseMeter,format_time,format_number
 from yum.rpmtrans import RPMBaseCallback
@@ -41,153 +44,15 @@ import types
 import signal
 import time
 import os.path
-from packagekit.backend import PackagekitProgress
+
+from yumDirect import *
+from yumFilter import *
+from yumComps import *
 
 # Global vars
 yumbase = None
 progress = PackagekitProgress()  # Progress object to store the progress
-
-groupMap = {
-'desktops;gnome-desktop'                      : GROUP_DESKTOP_GNOME,
-'desktops;window-managers'                    : GROUP_DESKTOP_OTHER,
-'desktops;kde-desktop'                        : GROUP_DESKTOP_KDE,
-'desktops;xfce-desktop'                       : GROUP_DESKTOP_XFCE,
-'apps;authoring-and-publishing'               : GROUP_PUBLISHING,
-'apps;office'                                 : GROUP_OFFICE,
-'apps;sound-and-video'                        : GROUP_MULTIMEDIA,
-'apps;editors'                                : GROUP_OFFICE,
-'apps;engineering-and-scientific'             : GROUP_OTHER,
-'apps;games'                                  : GROUP_GAMES,
-'apps;graphics'                               : GROUP_GRAPHICS,
-'apps;text-internet'                          : GROUP_INTERNET,
-'apps;graphical-internet'                     : GROUP_INTERNET,
-'apps;education'                              : GROUP_EDUCATION,
-'development;kde-software-development'        : GROUP_PROGRAMMING,
-'development;gnome-software-development'      : GROUP_PROGRAMMING,
-'development;development-tools'               : GROUP_PROGRAMMING,
-'development;eclipse'                         : GROUP_PROGRAMMING,
-'development;development-libs'                : GROUP_PROGRAMMING,
-'development;x-software-development'          : GROUP_PROGRAMMING,
-'development;web-development'                 : GROUP_PROGRAMMING,
-'development;legacy-software-development'     : GROUP_PROGRAMMING,
-'development;ruby'                            : GROUP_PROGRAMMING,
-'development;java-development'                : GROUP_PROGRAMMING,
-'development;xfce-software-development'       : GROUP_PROGRAMMING,
-'servers;clustering'                          : GROUP_SERVERS,
-'servers;dns-server'                          : GROUP_SERVERS,
-'servers;server-cfg'                          : GROUP_SERVERS,
-'servers;news-server'                         : GROUP_SERVERS,
-'servers;web-server'                          : GROUP_SERVERS,
-'servers;smb-server'                          : GROUP_SERVERS,
-'servers;sql-server'                          : GROUP_SERVERS,
-'servers;ftp-server'                          : GROUP_SERVERS,
-'servers;printing'                            : GROUP_SERVERS,
-'servers;mysql'                               : GROUP_SERVERS,
-'servers;mail-server'                         : GROUP_SERVERS,
-'servers;network-server'                      : GROUP_SERVERS,
-'servers;legacy-network-server'               : GROUP_SERVERS,
-'base-system;java'                            : GROUP_SYSTEM,
-'base-system;base-x'                          : GROUP_SYSTEM,
-'base-system;system-tools'                    : GROUP_ADMIN_TOOLS,
-'base-system;fonts'                           : GROUP_FONTS,
-'base-system;hardware-support'                : GROUP_SYSTEM,
-'base-system;dial-up'                         : GROUP_SYSTEM,
-'base-system;admin-tools'                     : GROUP_ADMIN_TOOLS,
-'base-system;legacy-software-support'         : GROUP_LEGACY,
-'base-system;base'                            : GROUP_SYSTEM,
-'base-system;virtualization'                  : GROUP_VIRTUALIZATION,
-'base-system;legacy-fonts'                    : GROUP_FONTS,
-'language-support;khmer-support'              : GROUP_LOCALIZATION,
-'language-support;persian-support'            : GROUP_LOCALIZATION,
-'language-support;georgian-support'           : GROUP_LOCALIZATION,
-'language-support;malay-support'              : GROUP_LOCALIZATION,
-'language-support;tonga-support'              : GROUP_LOCALIZATION,
-'language-support;portuguese-support'         : GROUP_LOCALIZATION,
-'language-support;japanese-support'           : GROUP_LOCALIZATION,
-'language-support;hungarian-support'          : GROUP_LOCALIZATION,
-'language-support;somali-support'             : GROUP_LOCALIZATION,
-'language-support;punjabi-support'            : GROUP_LOCALIZATION,
-'language-support;bhutanese-support'          : GROUP_LOCALIZATION,
-'language-support;british-support'            : GROUP_LOCALIZATION,
-'language-support;korean-support'             : GROUP_LOCALIZATION,
-'language-support;lao-support'                : GROUP_LOCALIZATION,
-'language-support;inuktitut-support'          : GROUP_LOCALIZATION,
-'language-support;german-support'             : GROUP_LOCALIZATION,
-'language-support;hindi-support'              : GROUP_LOCALIZATION,
-'language-support;faeroese-support'           : GROUP_LOCALIZATION,
-'language-support;swedish-support'            : GROUP_LOCALIZATION,
-'language-support;tsonga-support'             : GROUP_LOCALIZATION,
-'language-support;russian-support'            : GROUP_LOCALIZATION,
-'language-support;serbian-support'            : GROUP_LOCALIZATION,
-'language-support;latvian-support'            : GROUP_LOCALIZATION,
-'language-support;samoan-support'             : GROUP_LOCALIZATION,
-'language-support;sinhala-support'            : GROUP_LOCALIZATION,
-'language-support;catalan-support'            : GROUP_LOCALIZATION,
-'language-support;lithuanian-support'         : GROUP_LOCALIZATION,
-'language-support;turkish-support'            : GROUP_LOCALIZATION,
-'language-support;arabic-support'             : GROUP_LOCALIZATION,
-'language-support;vietnamese-support'         : GROUP_LOCALIZATION,
-'language-support;mongolian-support'          : GROUP_LOCALIZATION,
-'language-support;tswana-support'             : GROUP_LOCALIZATION,
-'language-support;irish-support'              : GROUP_LOCALIZATION,
-'language-support;italian-support'            : GROUP_LOCALIZATION,
-'language-support;slovak-support'             : GROUP_LOCALIZATION,
-'language-support;slovenian-support'          : GROUP_LOCALIZATION,
-'language-support;belarusian-support'         : GROUP_LOCALIZATION,
-'language-support;northern-sotho-support'     : GROUP_LOCALIZATION,
-'language-support;kannada-support'            : GROUP_LOCALIZATION,
-'language-support;malayalam-support'          : GROUP_LOCALIZATION,
-'language-support;swati-support'              : GROUP_LOCALIZATION,
-'language-support;breton-support'             : GROUP_LOCALIZATION,
-'language-support;romanian-support'           : GROUP_LOCALIZATION,
-'language-support;greek-support'              : GROUP_LOCALIZATION,
-'language-support;tagalog-support'            : GROUP_LOCALIZATION,
-'language-support;zulu-support'               : GROUP_LOCALIZATION,
-'language-support;tibetan-support'            : GROUP_LOCALIZATION,
-'language-support;danish-support'             : GROUP_LOCALIZATION,
-'language-support;afrikaans-support'          : GROUP_LOCALIZATION,
-'language-support;southern-sotho-support'     : GROUP_LOCALIZATION,
-'language-support;bosnian-support'            : GROUP_LOCALIZATION,
-'language-support;brazilian-support'          : GROUP_LOCALIZATION,
-'language-support;basque-support'             : GROUP_LOCALIZATION,
-'language-support;welsh-support'              : GROUP_LOCALIZATION,
-'language-support;thai-support'               : GROUP_LOCALIZATION,
-'language-support;telugu-support'             : GROUP_LOCALIZATION,
-'language-support;low-saxon-support'          : GROUP_LOCALIZATION,
-'language-support;urdu-support'               : GROUP_LOCALIZATION,
-'language-support;tamil-support'              : GROUP_LOCALIZATION,
-'language-support;indonesian-support'         : GROUP_LOCALIZATION,
-'language-support;gujarati-support'           : GROUP_LOCALIZATION,
-'language-support;xhosa-support'              : GROUP_LOCALIZATION,
-'language-support;chinese-support'            : GROUP_LOCALIZATION,
-'language-support;czech-support'              : GROUP_LOCALIZATION,
-'language-support;venda-support'              : GROUP_LOCALIZATION,
-'language-support;bulgarian-support'          : GROUP_LOCALIZATION,
-'language-support;albanian-support'           : GROUP_LOCALIZATION,
-'language-support;galician-support'           : GROUP_LOCALIZATION,
-'language-support;armenian-support'           : GROUP_LOCALIZATION,
-'language-support;dutch-support'              : GROUP_LOCALIZATION,
-'language-support;oriya-support'              : GROUP_LOCALIZATION,
-'language-support;maori-support'              : GROUP_LOCALIZATION,
-'language-support;nepali-support'             : GROUP_LOCALIZATION,
-'language-support;icelandic-support'          : GROUP_LOCALIZATION,
-'language-support;ukrainian-support'          : GROUP_LOCALIZATION,
-'language-support;assamese-support'           : GROUP_LOCALIZATION,
-'language-support;bengali-support'            : GROUP_LOCALIZATION,
-'language-support;spanish-support'            : GROUP_LOCALIZATION,
-'language-support;hebrew-support'             : GROUP_LOCALIZATION,
-'language-support;estonian-support'           : GROUP_LOCALIZATION,
-'language-support;french-support'             : GROUP_LOCALIZATION,
-'language-support;croatian-support'           : GROUP_LOCALIZATION,
-'language-support;filipino-support'           : GROUP_LOCALIZATION,
-'language-support;finnish-support'            : GROUP_LOCALIZATION,
-'language-support;norwegian-support'          : GROUP_LOCALIZATION,
-'language-support;southern-ndebele-support'   : GROUP_LOCALIZATION,
-'language-support;polish-support'             : GROUP_LOCALIZATION,
-'language-support;gaelic-support'             : GROUP_LOCALIZATION,
-'language-support;marathi-support'            : GROUP_LOCALIZATION,
-'language-support;ethiopic-support'           : GROUP_LOCALIZATION
-}
+pkpackage = PackagekitPackage()
 
 MetaDataMap = {
     'repomd'        : STATUS_DOWNLOAD_REPOSITORY,
@@ -198,8 +63,6 @@ MetaDataMap = {
     'updateinfo'    : STATUS_DOWNLOAD_UPDATEINFO
 }
 
-GUI_KEYS = re.compile(r'(qt)|(gtk)')
-
 class GPGKeyNotImported(exceptions.Exception):
     pass
 
@@ -238,6 +101,13 @@ class PackageKitYumBackend(PackageKitBaseBackend):
         signal.signal(signal.SIGQUIT,sigquit)
         PackageKitBaseBackend.__init__(self,args)
         self.yumbase = PackageKitYumBase(self)
+
+        self.comps = yumComps(self.yumbase)
+        if not self.comps.connect():
+            self.refresh_cache()
+            if not self.comps.connect():
+                self.error(ERROR_GROUP_LIST_INVALID,'comps categories could not be loaded')
+
         yumbase = self.yumbase
         self._setup_yum()
         if lock:
@@ -316,117 +186,28 @@ class PackageKitYumBackend(PackageKitBaseBackend):
         '''
         res = self.yumbase.searchGenerator(searchlist,[key])
         fltlist = filters.split(';')
-        seen_nevra = [] # yum returns packages as available even when installed
-        pkg_list = [] # only do the second iteration on not installed pkgs
+        pkgfilter = YumFilter(fltlist)
         package_list = [] #we can't do emitting as found if we are post-processing
+        installed = []
+        available = []
 
         for (pkg,values) in res:
             if pkg.repo.id == 'installed':
-                if self._do_extra_filtering(pkg,fltlist):
-                    package_list.append((pkg,INFO_INSTALLED))
-                    seen_nevra.append(self._get_nevra(pkg))
+                installed.append(pkg)
             else:
-                pkg_list.append(pkg)
-        for pkg in pkg_list:
-            nevra = self._get_nevra(pkg)
-            if nevra not in seen_nevra:
-                if self._do_extra_filtering(pkg,fltlist):
-                    package_list.append((pkg,INFO_AVAILABLE))
-                    seen_nevra.append(self._get_nevra(pkg))
-
-        # basename filter if specified
-        if FILTER_BASENAME in fltlist:
-            package_list = self._basename_filter(package_list)
-
-        # newest filter
-        if FILTER_NEWEST in fltlist:
-            package_list = self._do_newest_filtering(package_list)
+                available.append(pkg)
+
+        pkgfilter.add_installed(installed)
+        pkgfilter.add_available(available)
 
+        # we couldn't do this when generating the list
+        package_list = pkgfilter.post_process()
         self._show_package_list(package_list)
 
     def _show_package_list(self,lst):
         for (pkg,status) in lst:
             self._show_package(pkg,status)
 
-    def _do_newest_filtering(self,pkglist):
-        '''
-        Only return the newest package for each name.arch
-        '''
-        newest = {}
-        for pkg,state in pkglist:
-            key = (pkg.name, pkg.arch)
-            if key in newest and pkg <= newest[key][0]:
-                continue
-            newest[key] = (pkg,state)
-        return newest.values()
-
-
-
-    def _do_extra_filtering(self,pkg,filterList):
-        ''' do extra filtering (gui,devel etc) '''
-        for filter in filterList:
-            if filter in (FILTER_INSTALLED,FILTER_NOT_INSTALLED):
-                if not self._do_installed_filtering(filter,pkg):
-                    return False
-            elif filter in (FILTER_GUI,FILTER_NOT_GUI):
-                if not self._do_gui_filtering(filter,pkg):
-                    return False
-            elif filter in (FILTER_DEVELOPMENT,FILTER_NOT_DEVELOPMENT):
-                if not self._do_devel_filtering(filter,pkg):
-                    return False
-            elif filter in (FILTER_FREE,FILTER_NOT_FREE):
-                if not self._do_free_filtering(filter,pkg):
-                    return False
-        return True
-
-    def _do_installed_filtering(self,flt,pkg):
-        isInstalled = False
-        if flt == FILTER_INSTALLED:
-            wantInstalled = True
-        else:
-            wantInstalled = False
-        isInstalled = pkg.repo.id == 'installed'
-        return isInstalled == wantInstalled
-
-    def _do_gui_filtering(self,flt,pkg):
-        isGUI = False
-        if flt == FILTER_GUI:
-            wantGUI = True
-        else:
-            wantGUI = False
-        isGUI = self._check_for_gui(pkg)
-        return isGUI == wantGUI
-
-    def _check_for_gui(self,pkg):
-        '''  Check if the GUI_KEYS regex matches any package requirements'''
-        for req in pkg.requires:
-            reqname = req[0]
-            if GUI_KEYS.search(reqname):
-                return True
-        return False
-
-    def _do_devel_filtering(self,flt,pkg):
-        isDevel = False
-        if flt == FILTER_DEVELOPMENT:
-            wantDevel = True
-        else:
-            wantDevel = False
-        regex =  re.compile(r'(-devel)|(-dgb)|(-static)')
-        if regex.search(pkg.name):
-            isDevel = True
-        return isDevel == wantDevel
-
-    def _do_free_filtering(self,flt,pkg):
-        isFree = False
-        if flt == FILTER_FREE:
-            wantFree = True
-        else:
-            wantFree = False
-
-        isFree = self.check_license_field(pkg.license)
-
-        return isFree == wantFree
-
     def search_name(self,filters,key):
         '''
         Implement the {backend}-search-name functionality
@@ -452,85 +233,49 @@ class PackageKitYumBackend(PackageKitBaseBackend):
         self.status(STATUS_QUERY)
         self._do_search(searchlist,filters,key)
 
-    def _buildGroupDict(self):
-        pkgGroups= {}
-        cats = self.yumbase.comps.categories
-        if len(cats) == 0:
-            self.error(ERROR_GROUP_LIST_INVALID,'comps categories could not be loaded')
-        for cat in cats:
-            grps = map(lambda x: self.yumbase.comps.return_group(x),
-               filter(lambda x: self.yumbase.comps.has_group(x),cat.groups))
-            grplist = []
-            for group in grps:
-                for pkg in group.mandatory_packages.keys():
-                    pkgGroups[pkg] = "%s;%s" % (cat.categoryid,group.groupid)
-                for pkg in group.default_packages.keys():
-                    pkgGroups[pkg] = "%s;%s" % (cat.categoryid,group.groupid)
-                for pkg in group.optional_packages.keys():
-                    pkgGroups[pkg] = "%s;%s" % (cat.categoryid,group.groupid)
-                for pkg in group.conditional_packages.keys():
-                    pkgGroups[pkg] = "%s;%s" % (cat.categoryid,group.groupid)
-        return pkgGroups
-
     @handle_repo_error
-    def search_group(self,filters,key):
+    def search_group(self,filters,group_key):
         '''
         Implement the {backend}-search-group functionality
         '''
         self._check_init(lazy_cache=True)
         self.allow_cancel(True)
-        self.percentage(None)
         self.yumbase.doConfigSetup(errorlevel=0,debuglevel=0)# Setup Yum Config
         self.yumbase.conf.cache = 1 # Only look in cache.
         self.status(STATUS_QUERY)
         package_list = [] #we can't do emitting as found if we are post-processing
+        fltlist = filters.split(';')
 
-        try:
-            pkgGroupDict = self._buildGroupDict()
-            self.yumbase.conf.cache = 1 # Only look in cache.
-            fltlist = filters.split(';')
-            installed_nevra = [] # yum returns packages as available even when installed
-
-            if not FILTER_NOT_INSTALLED in fltlist:
-                # Check installed for group
-                for pkg in self.yumbase.rpmdb:
-                    group = GROUP_OTHER                    # Default Group
-                    if pkgGroupDict.has_key(pkg.name):     # check if pkg name exist in package / group dictinary
-                        cg = pkgGroupDict[pkg.name]
-                        if groupMap.has_key(cg):
-                            group = groupMap[cg]           # use the pk group name, instead of yum 'category/group'
-                    if group == key:
-                        if self._do_extra_filtering(pkg,fltlist):
-                            package_list.append((pkg,INFO_INSTALLED))
-                    installed_nevra.append(self._get_nevra(pkg))
-
-            if not FILTER_INSTALLED in fltlist:
-                # Check available for group
-                for pkg in self.yumbase.pkgSack:
-                    nevra = self._get_nevra(pkg)
-                    if nevra not in installed_nevra:
-                        group = GROUP_OTHER
-                        if pkgGroupDict.has_key(pkg.name):
-                            cg = pkgGroupDict[pkg.name]
-                            if groupMap.has_key(cg):
-                                group = groupMap[cg]
-                        if group == key:
-                            if self._do_extra_filtering(pkg,fltlist):
-                                package_list.append((pkg,INFO_AVAILABLE))
-
-        except yum.Errors.GroupsError,e:
-            self.error(ERROR_GROUP_NOT_FOUND,str(e))
-
-        # basename filter if specified
-        if FILTER_BASENAME in fltlist:
-            package_list = self._basename_filter(package_list)
-
-        # newest filter
-        if FILTER_NEWEST in fltlist:
-            package_list = self._do_newest_filtering(package_list)
+        # use direct access for speed
+        direct = YumDirectSQL(self.yumbase)
+        pkgfilter = YumFilter(fltlist)
+
+        # get the packagelist for this group
+        all_packages = self.comps.get_package_list(group_key)
+
+        # get installed packages
+        self.percentage(10)
+        for package in all_packages:
+            pkgs = self.yumbase.rpmdb.searchNevra(name=package)
+            pkgfilter.add_installed(pkgs)
+
+        # get available packages
+        self.percentage(20)
+        if FILTER_INSTALLED not in fltlist:
+            for package in all_packages:
+                pkgs = direct.resolve(package)
+                pkgfilter.add_available(pkgs)
+
+        # we couldn't do this when generating the list
+        package_list = pkgfilter.post_process()
 
+        self.percentage(90)
         self._show_package_list(package_list)
 
+        # close all the databases
+        direct.close()
+        self.percentage(100)
+
     @handle_repo_error
     def get_packages(self,filters):
         '''
@@ -544,29 +289,21 @@ class PackageKitYumBackend(PackageKitBaseBackend):
         self.yumbase.doConfigSetup(errorlevel=0,debuglevel=0)# Setup Yum Config
         self.yumbase.conf.cache = 1 # Only look in cache.
 
-        package_list = [] #we can't do emitting as found if we are post-processing
         fltlist = filters.split(';')
+        pkgfilter = YumFilter(fltlist)
+        package_list = [] #we can't do emitting as found if we are post-processing
 
         # Now show installed packages.
-        if FILTER_NOT_INSTALLED not in fltlist:
-            for pkg in self.yumbase.rpmdb:
-                if self._do_extra_filtering(pkg,fltlist):
-                    package_list.append((pkg,INFO_INSTALLED))
+        pkgs = self.yumbase.rpmdb
+        pkgfilter.add_installed(pkgs)
 
         # Now show available packages.
         if FILTER_INSTALLED not in fltlist:
-            for pkg in self.yumbase.pkgSack.returnNewestByNameArch():
-                if self._do_extra_filtering(pkg,fltlist):
-                    package_list.append((pkg,INFO_AVAILABLE))
-
-        # basename filter if specified
-        if FILTER_BASENAME in fltlist:
-            package_list = self._basename_filter(package_list)
-
-        # newest filter
-        if FILTER_NEWEST in fltlist:
-            package_list = self._do_newest_filtering(package_list)
+            pkgs = self.yumbase.pkgSack.returnNewestByNameArch()
+            pkgfilter.add_available(pkgs)
 
+        # we couldn't do this when generating the list
+        package_list = pkgfilter.post_process()
         self._show_package_list(package_list)
 
     @handle_repo_error
@@ -581,24 +318,21 @@ class PackageKitYumBackend(PackageKitBaseBackend):
 
         #self.yumbase.conf.cache = 1 # Only look in cache.
         fltlist = filters.split(';')
-        found = {}
-        if not FILTER_NOT_INSTALLED in fltlist:
-            # Check installed for file
-            matches = self.yumbase.rpmdb.searchFiles(key)
-            for pkg in matches:
-                if not found.has_key(str(pkg)):
-                    if self._do_extra_filtering(pkg,fltlist):
-                        self._show_package(pkg,INFO_INSTALLED)
-                        found[str(pkg)] = 1
+        pkgfilter = YumFilter(fltlist)
+
+        # Check installed for file
+        pkgs = self.yumbase.rpmdb.searchFiles(key)
+        pkgfilter.add_installed(pkgs)
+
+        # Check available for file
         if not FILTER_INSTALLED in fltlist:
-            # Check available for file
             self.yumbase.repos.populateSack(mdtype='filelists')
-            matches = self.yumbase.pkgSack.searchFiles(key)
-            for pkg in matches:
-                if not found.has_key(str(pkg)):
-                    if self._do_extra_filtering(pkg,fltlist):
-                        self._show_package(pkg,INFO_AVAILABLE)
-                        found[str(pkg)] = 1
+            pkgs = self.yumbase.pkgSack.searchFiles(key)
+            pkgfilter.add_available(pkgs)
+
+        # we couldn't do this when generating the list
+        package_list = pkgfilter.post_process()
+        self._show_package_list(package_list)
 
     @handle_repo_error
     def what_provides(self,filters,provides_type,search):
@@ -611,23 +345,20 @@ class PackageKitYumBackend(PackageKitBaseBackend):
         self.status(STATUS_QUERY)
 
         fltlist = filters.split(';')
-        found = {}
-        if not FILTER_NOT_INSTALLED in fltlist:
-            # Check installed for file
-            matches = self.yumbase.rpmdb.searchProvides(search)
-            for pkg in matches:
-                if not found.has_key(str(pkg)):
-                    if self._do_extra_filtering(pkg,fltlist):
-                        self._show_package(pkg,INFO_INSTALLED)
-                        found[str(pkg)] = 1
+        pkgfilter = YumFilter(fltlist)
+
+        # Check installed for file
+        pkgs = self.yumbase.rpmdb.searchProvides(search)
+        pkgfilter.add_installed(pkgs)
+
         if not FILTER_INSTALLED in fltlist:
             # Check available for file
-            matches = self.yumbase.pkgSack.searchProvides(search)
-            for pkg in matches:
-                if found.has_key(str(pkg)):
-                    if self._do_extra_filtering(pkg,fltlist):
-                        self._show_package(pkg,INFO_AVAILABLE)
-                        found[str(pkg)] = 1
+            pkgs = self.yumbase.pkgSack.searchProvides(search)
+            pkgfilter.add_available(pkgs)
+
+        # we couldn't do this when generating the list
+        package_list = pkgfilter.post_process()
+        self._show_package_list(package_list)
 
     @handle_repo_error
     def download_packages(self,directory,packages):
@@ -681,7 +412,7 @@ class PackageKitYumBackend(PackageKitBaseBackend):
         # is this an real id or just an name
         if len(id.split(';')) > 1:
             # Split up the id
-            (n,idver,a,d) = self.get_package_from_id(id)
+            (n,idver,a,d) = pkpackage.get_package_from_id(id)
             # get e,v,r from package id version
             e,v,r = self._getEVR(idver)
         else:
@@ -964,6 +695,9 @@ class PackageKitYumBackend(PackageKitBaseBackend):
         except yum.Errors.YumBaseError,e:
             self.error(ERROR_UNKNOWN,str(e))
 
+        # update the comps groups too
+        self.comps.refresh()
+
     @handle_repo_error
     def resolve(self,filters,packages):
         '''
@@ -1271,7 +1005,7 @@ class PackageKitYumBackend(PackageKitBaseBackend):
         '''
         Print a detailed details for a given package
         '''
-        self._check_init()
+        self._check_init(lazy_cache=True)
         self.allow_cancel(True)
         self.percentage(None)
         self.status(STATUS_INFO)
@@ -1279,26 +1013,18 @@ class PackageKitYumBackend(PackageKitBaseBackend):
         for package in package_ids:
             pkg,inst = self._findPackage(package)
             if pkg:
-                self._show_details(pkg)
+                self._show_details_pkg(pkg)
             else:
                 self.error(ERROR_PACKAGE_NOT_FOUND,'Package %s was not found' % package)
 
-    def _show_details(self,pkg):
+    def _show_details_pkg(self,pkg):
+
         pkgver = self._get_package_ver(pkg)
-        id = self.get_package_id(pkg.name,pkgver,pkg.arch,pkg.repo)
+        id = pkpackage.get_package_id(pkg.name,pkgver,pkg.arch,pkg.repo)
         desc = pkg.description
         desc = desc.replace('\n\n',';')
         desc = desc.replace('\n',' ')
-
-        # this takes oodles of time
-        pkgGroupDict = self._buildGroupDict()
-        group = GROUP_OTHER
-        if pkgGroupDict.has_key(pkg.name):
-            cg = pkgGroupDict[pkg.name]
-            if groupMap.has_key(cg):
-                # use PK group name
-                group = groupMap[cg]
-
+        group = self.comps.get_group(pkg.name)
         self.details(id,pkg.license,group,desc,pkg.url,pkg.size)
 
     def get_files(self,package_ids):
@@ -1321,7 +1047,7 @@ class PackageKitYumBackend(PackageKitBaseBackend):
 
     def _pkg_to_id(self,pkg):
         pkgver = self._get_package_ver(pkg)
-        id = self.get_package_id(pkg.name,pkgver,pkg.arch,pkg.repo)
+        id = pkpackage.get_package_id(pkg.name,pkgver,pkg.arch,pkg.repo)
         return id
 
     def _show_package(self,pkg,status):
@@ -1340,58 +1066,6 @@ class PackageKitYumBackend(PackageKitBaseBackend):
         else:
             return INFO_UNKNOWN
 
-    def _is_main_package(self,repo):
-        if repo.endswith('-debuginfo'):
-            return False
-        if repo.endswith('-devel'):
-            return False
-        if repo.endswith('-libs'):
-            return False
-        return True
-
-    def _basename_filter(self,package_list):
-        '''
-        Filter the list so that the number of packages are reduced.
-        This is done by only displaying gtk2 rather than gtk2-devel, gtk2-debuginfo, etc.
-        This imlementation is done by comparing the SRPM name, and if not falling back
-        to the first entry.
-        We have to fall back else we don't emit packages where the SRPM does not produce a
-        RPM with the same name, for instance, mono produces mono-core, mono-data and mono-winforms.
-        @package_list: a (pkg,status) list of packages
-        A new list is returned that has been filtered
-        '''
-        base_list = []
-        output_list = []
-        base_list_already_got = []
-
-        #find out the srpm name and add to a new array of compound data
-        for (pkg,status) in package_list:
-            if pkg.sourcerpm:
-                base = rpmUtils.miscutils.splitFilename(pkg.sourcerpm)[0]
-                base_list.append ((pkg,status,base,pkg.version));
-            else:
-                base_list.append ((pkg,status,'nosrpm',pkg.version));
-
-        #find all the packages that match thier basename name (done seporately so we get the "best" match)
-        for (pkg,status,base,version) in base_list:
-            if base == pkg.name and (base,version) not in base_list_already_got:
-                output_list.append((pkg,status))
-                base_list_already_got.append ((base,version))
-
-        #for all the ones not yet got, can we match against a non devel match?
-        for (pkg,status,base,version) in base_list:
-            if (base,version) not in base_list_already_got:
-                if self._is_main_package(pkg.name):
-                    output_list.append((pkg,status))
-                    base_list_already_got.append ((base,version))
-
-        #add the remainder of the packages, which should just be the single debuginfo's
-        for (pkg,status,base,version) in base_list:
-            if (base,version) not in base_list_already_got:
-                output_list.append((pkg,status))
-                base_list_already_got.append ((base,version))
-        return output_list
-
     def get_updates(self,filters):
         '''
         Implement the {backend}-get-updates functionality
@@ -1404,6 +1078,7 @@ class PackageKitYumBackend(PackageKitBaseBackend):
 
         fltlist = filters.split(';')
         package_list = []
+        pkgfilter = YumFilter(fltlist)
 
         try:
             ygl = self.yumbase.doPackageLists(pkgnarrow='updates')
@@ -1411,22 +1086,17 @@ class PackageKitYumBackend(PackageKitBaseBackend):
             self.error(ERROR_REPO_NOT_AVAILABLE,str(e))
         md = self.updateMetadata
         for pkg in ygl.updates:
-            if self._do_extra_filtering(pkg,fltlist):
+            if pkgfilter._do_extra_filtering(pkg,fltlist):
                 # Get info about package in updates info
                 notice = md.get_notice((pkg.name,pkg.version,pkg.release))
                 if notice:
                     status = self._get_status(notice)
-                    package_list.append((pkg,status))
+                    pkgfilter.add_custom(pkg,status)
                 else:
-                    package_list.append((pkg,INFO_NORMAL))
+                    pkgfilter.add_custom(pkg,INFO_NORMAL)
 
-        # basename filter if specified
-        if FILTER_BASENAME in fltlist:
-            for (pkg,status) in self._basename_filter(package_list):
-                self._show_package(pkg,status)
-        else:
-            for (pkg,status) in package_list:
-                self._show_package(pkg,status)
+        package_list = pkgfilter.post_process()
+        self._show_package_list(package_list)
 
     def repo_enable(self,repoid,enable):
         '''
@@ -1827,7 +1497,7 @@ class ProcessTransPackageKitCallback:
 
 class DepSolveCallback(object):
 
-    # XXX takes a PackageKitBackend so we can call StatusChanged on it.
+    # takes a PackageKitBackend so we can call StatusChanged on it.
     # That's kind of hurky.
     def __init__(self,backend):
         self.started = False
commit a71fb0db37d80c917a0db7a5f58282a589c2e141
Author: Richard Hughes <richard at hughsie.com>
Date:   Tue Jul 8 00:05:15 2008 +0100

    trivial: change the dbus-glib buildreq to 0.74, i'm using it fine now :-)

diff --git a/configure.ac b/configure.ac
index d99062c..a8a9a1a 100644
--- a/configure.ac
+++ b/configure.ac
@@ -74,7 +74,7 @@ dnl ---------------------------------------------------------------------------
 GLIB_REQUIRED=2.14.0
 GIO_REQUIRED=2.16.1
 DBUS_REQUIRED=1.1.1
-DBUS_GLIB_REQUIRED=0.76
+DBUS_GLIB_REQUIRED=0.74
 LIBNM_GLIB_REQUIRED=0.6.4
 POLKIT_DBUS_REQUIRED=0.8
 POLKIT_GRANT_REQUIRED=0.8
commit 9d190a50596591b8de5e9e8d13c04368ac7ec89c
Author: Richard Hughes <richard at hughsie.com>
Date:   Tue Jul 8 00:03:32 2008 +0100

    yum: write the sqlite db to disk, else we can create the table each time

diff --git a/backends/yum/helpers/yumComps.py b/backends/yum/helpers/yumComps.py
index d94e338..e12bd57 100644
--- a/backends/yum/helpers/yumComps.py
+++ b/backends/yum/helpers/yumComps.py
@@ -187,17 +187,18 @@ class yumComps:
     def __init__(self,yumbase):
         self.yumbase = yumbase
         self.cursor = None
+        self.connection = None
 
     def connect(self):
         ''' connect to database '''
         database = '/var/cache/yum/packagekit-groups.sqlite'
         try:
             # will be created if it does not exist
-            connection = sqlite.connect(database)
-            self.cursor = connection.cursor()
+            self.connection = sqlite.connect(database)
+            self.cursor = self.connection.cursor()
         except Exception, e:
-            print "cannot connect to database %s: %s" % (database,str(e))
-            return
+            print 'cannot connect to database %s: %s' % (database,str(e))
+            return False
 
         # test if we can get a group for a common package, create if fail
         try:
@@ -206,6 +207,8 @@ class yumComps:
             self.cursor.execute('CREATE TABLE groups (name TEXT,category TEXT,group_enum TEXT);')
             self.refresh()
 
+        return True
+
     def _add_db(self,name,category,group):
         self.cursor.execute('INSERT INTO groups values(?,?,?);',(name,category,group))
 
@@ -213,7 +216,7 @@ class yumComps:
         ''' get the data from yum (slow, REALLY SLOW) '''
 
         cats = self.yumbase.comps.categories
-        if len(cats) == 0:
+        if self.yumbase.comps.compscount == 0:
             return False
 
         # store to sqlite
@@ -241,6 +244,9 @@ class yumComps:
                     self._add_db(package,group_id,group_enum)
                 for package in group.optional_packages:
                     self._add_db(package,group_id,group_enum)
+
+        # write to disk
+        self.connection.commit()
         return True
 
     def get_package_list(self,group_key):
commit 2944602daa28ef102bccb0d39ff68f2aa2b79099
Author: Richard Hughes <richard at hughsie.com>
Date:   Mon Jul 7 18:30:38 2008 +0100

    yum: add some more comps groups

diff --git a/backends/yum/helpers/yumComps.py b/backends/yum/helpers/yumComps.py
index 69030b9..d94e338 100644
--- a/backends/yum/helpers/yumComps.py
+++ b/backends/yum/helpers/yumComps.py
@@ -23,6 +23,7 @@ from pysqlite2 import dbapi2 as sqlite
 groupMap = {
 'desktops;gnome-desktop'                      : GROUP_DESKTOP_GNOME,
 'desktops;window-managers'                    : GROUP_DESKTOP_OTHER,
+'desktops;sugar-desktop'                      : GROUP_DESKTOP_OTHER,
 'desktops;kde-desktop'                        : GROUP_DESKTOP_KDE,
 'desktops;xfce-desktop'                       : GROUP_DESKTOP_XFCE,
 'apps;authoring-and-publishing'               : GROUP_PUBLISHING,
@@ -46,6 +47,7 @@ groupMap = {
 'development;ruby'                            : GROUP_PROGRAMMING,
 'development;java-development'                : GROUP_PROGRAMMING,
 'development;xfce-software-development'       : GROUP_PROGRAMMING,
+'development;fedora-packager'                 : GROUP_PROGRAMMING,
 'servers;clustering'                          : GROUP_SERVERS,
 'servers;dns-server'                          : GROUP_SERVERS,
 'servers;server-cfg'                          : GROUP_SERVERS,
@@ -160,6 +162,11 @@ groupMap = {
 'language-support;gaelic-support'             : GROUP_LOCALIZATION,
 'language-support;marathi-support'            : GROUP_LOCALIZATION,
 'language-support;ethiopic-support'           : GROUP_LOCALIZATION,
+'language-support;esperanto-support'          : GROUP_LOCALIZATION,
+'language-support;northern-sami-support'      : GROUP_LOCALIZATION,
+'language-support;macedonian-support'         : GROUP_LOCALIZATION,
+'language-support;walloon-support'            : GROUP_LOCALIZATION,
+'language-support;kashubian-support'          : GROUP_LOCALIZATION,
 'rpmfusion_free;kde-desktop'                  : GROUP_DESKTOP_KDE,
 'rpmfusion_free;misc-libs'                    : GROUP_OTHER,
 'rpmfusion_free;games'                        : GROUP_GAMES,
commit e91fdcbbcf3a71b28b032a98b2bfaad00031dfff
Merge: f55c5a3... c897e16...
Author: Richard Hughes <richard at hughsie.com>
Date:   Mon Jul 7 17:45:56 2008 +0100

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

commit f55c5a31f7a6a8b0622de3c337785eb3dfee0e3f
Author: Richard Hughes <richard at hughsie.com>
Date:   Mon Jul 7 16:02:08 2008 +0100

    trivial: ship the new classes even tho nothing uses them yet

diff --git a/backends/yum/helpers/Makefile.am b/backends/yum/helpers/Makefile.am
index ae73353..0d5cb31 100644
--- a/backends/yum/helpers/Makefile.am
+++ b/backends/yum/helpers/Makefile.am
@@ -27,6 +27,9 @@ dist_helper_DATA = 			\
 	what-provides.py		\
 	update-system.py		\
 	yumBackend.py			\
+	yumDirect.py			\
+	yumComps.py			\
+	yumFilter.py			\
 	$(NULL)
 
 install-data-hook:
commit ee3e128e5278b828a681850b346d9a6513b98dc7
Author: Richard Hughes <richard at hughsie.com>
Date:   Mon Jul 7 16:01:10 2008 +0100

    yum: add a new untested class to cache the comps list
    
    Getting the comps list takes me 600ms -- which is unacceptable when we are using this
    interactivly.
    Create a sqlite cache in /var/cache/yum/packagekit-groups.sqlite so we can get
    the groups list for any package in less than 5ms.
    
    Ultmately this code should be moved to yum, although we'll need some heavy testng before this

diff --git a/backends/yum/helpers/yumComps.py b/backends/yum/helpers/yumComps.py
new file mode 100644
index 0000000..69030b9
--- /dev/null
+++ b/backends/yum/helpers/yumComps.py
@@ -0,0 +1,255 @@
+# 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.
+
+# Copyright (C) 2008
+#    Richard Hughes <richard at hughsie.com>
+
+from packagekit.backend import *
+from pysqlite2 import dbapi2 as sqlite
+
+groupMap = {
+'desktops;gnome-desktop'                      : GROUP_DESKTOP_GNOME,
+'desktops;window-managers'                    : GROUP_DESKTOP_OTHER,
+'desktops;kde-desktop'                        : GROUP_DESKTOP_KDE,
+'desktops;xfce-desktop'                       : GROUP_DESKTOP_XFCE,
+'apps;authoring-and-publishing'               : GROUP_PUBLISHING,
+'apps;office'                                 : GROUP_OFFICE,
+'apps;sound-and-video'                        : GROUP_MULTIMEDIA,
+'apps;editors'                                : GROUP_OFFICE,
+'apps;engineering-and-scientific'             : GROUP_OTHER,
+'apps;games'                                  : GROUP_GAMES,
+'apps;graphics'                               : GROUP_GRAPHICS,
+'apps;text-internet'                          : GROUP_INTERNET,
+'apps;graphical-internet'                     : GROUP_INTERNET,
+'apps;education'                              : GROUP_EDUCATION,
+'development;kde-software-development'        : GROUP_PROGRAMMING,
+'development;gnome-software-development'      : GROUP_PROGRAMMING,
+'development;development-tools'               : GROUP_PROGRAMMING,
+'development;eclipse'                         : GROUP_PROGRAMMING,
+'development;development-libs'                : GROUP_PROGRAMMING,
+'development;x-software-development'          : GROUP_PROGRAMMING,
+'development;web-development'                 : GROUP_PROGRAMMING,
+'development;legacy-software-development'     : GROUP_PROGRAMMING,
+'development;ruby'                            : GROUP_PROGRAMMING,
+'development;java-development'                : GROUP_PROGRAMMING,
+'development;xfce-software-development'       : GROUP_PROGRAMMING,
+'servers;clustering'                          : GROUP_SERVERS,
+'servers;dns-server'                          : GROUP_SERVERS,
+'servers;server-cfg'                          : GROUP_SERVERS,
+'servers;news-server'                         : GROUP_SERVERS,
+'servers;web-server'                          : GROUP_SERVERS,
+'servers;smb-server'                          : GROUP_SERVERS,
+'servers;sql-server'                          : GROUP_SERVERS,
+'servers;ftp-server'                          : GROUP_SERVERS,
+'servers;printing'                            : GROUP_SERVERS,
+'servers;mysql'                               : GROUP_SERVERS,
+'servers;mail-server'                         : GROUP_SERVERS,
+'servers;network-server'                      : GROUP_SERVERS,
+'servers;legacy-network-server'               : GROUP_SERVERS,
+'base-system;java'                            : GROUP_SYSTEM,
+'base-system;base-x'                          : GROUP_SYSTEM,
+'base-system;system-tools'                    : GROUP_ADMIN_TOOLS,
+'base-system;fonts'                           : GROUP_FONTS,
+'base-system;hardware-support'                : GROUP_SYSTEM,
+'base-system;dial-up'                         : GROUP_SYSTEM,
+'base-system;admin-tools'                     : GROUP_ADMIN_TOOLS,
+'base-system;legacy-software-support'         : GROUP_LEGACY,
+'base-system;base'                            : GROUP_SYSTEM,
+'base-system;virtualization'                  : GROUP_VIRTUALIZATION,
+'base-system;legacy-fonts'                    : GROUP_FONTS,
+'language-support;khmer-support'              : GROUP_LOCALIZATION,
+'language-support;persian-support'            : GROUP_LOCALIZATION,
+'language-support;georgian-support'           : GROUP_LOCALIZATION,
+'language-support;malay-support'              : GROUP_LOCALIZATION,
+'language-support;tonga-support'              : GROUP_LOCALIZATION,
+'language-support;portuguese-support'         : GROUP_LOCALIZATION,
+'language-support;japanese-support'           : GROUP_LOCALIZATION,
+'language-support;hungarian-support'          : GROUP_LOCALIZATION,
+'language-support;somali-support'             : GROUP_LOCALIZATION,
+'language-support;punjabi-support'            : GROUP_LOCALIZATION,
+'language-support;bhutanese-support'          : GROUP_LOCALIZATION,
+'language-support;british-support'            : GROUP_LOCALIZATION,
+'language-support;korean-support'             : GROUP_LOCALIZATION,
+'language-support;lao-support'                : GROUP_LOCALIZATION,
+'language-support;inuktitut-support'          : GROUP_LOCALIZATION,
+'language-support;german-support'             : GROUP_LOCALIZATION,
+'language-support;hindi-support'              : GROUP_LOCALIZATION,
+'language-support;faeroese-support'           : GROUP_LOCALIZATION,
+'language-support;swedish-support'            : GROUP_LOCALIZATION,
+'language-support;tsonga-support'             : GROUP_LOCALIZATION,
+'language-support;russian-support'            : GROUP_LOCALIZATION,
+'language-support;serbian-support'            : GROUP_LOCALIZATION,
+'language-support;latvian-support'            : GROUP_LOCALIZATION,
+'language-support;samoan-support'             : GROUP_LOCALIZATION,
+'language-support;sinhala-support'            : GROUP_LOCALIZATION,
+'language-support;catalan-support'            : GROUP_LOCALIZATION,
+'language-support;lithuanian-support'         : GROUP_LOCALIZATION,
+'language-support;turkish-support'            : GROUP_LOCALIZATION,
+'language-support;arabic-support'             : GROUP_LOCALIZATION,
+'language-support;vietnamese-support'         : GROUP_LOCALIZATION,
+'language-support;mongolian-support'          : GROUP_LOCALIZATION,
+'language-support;tswana-support'             : GROUP_LOCALIZATION,
+'language-support;irish-support'              : GROUP_LOCALIZATION,
+'language-support;italian-support'            : GROUP_LOCALIZATION,
+'language-support;slovak-support'             : GROUP_LOCALIZATION,
+'language-support;slovenian-support'          : GROUP_LOCALIZATION,
+'language-support;belarusian-support'         : GROUP_LOCALIZATION,
+'language-support;northern-sotho-support'     : GROUP_LOCALIZATION,
+'language-support;kannada-support'            : GROUP_LOCALIZATION,
+'language-support;malayalam-support'          : GROUP_LOCALIZATION,
+'language-support;swati-support'              : GROUP_LOCALIZATION,
+'language-support;breton-support'             : GROUP_LOCALIZATION,
+'language-support;romanian-support'           : GROUP_LOCALIZATION,
+'language-support;greek-support'              : GROUP_LOCALIZATION,
+'language-support;tagalog-support'            : GROUP_LOCALIZATION,
+'language-support;zulu-support'               : GROUP_LOCALIZATION,
+'language-support;tibetan-support'            : GROUP_LOCALIZATION,
+'language-support;danish-support'             : GROUP_LOCALIZATION,
+'language-support;afrikaans-support'          : GROUP_LOCALIZATION,
+'language-support;southern-sotho-support'     : GROUP_LOCALIZATION,
+'language-support;bosnian-support'            : GROUP_LOCALIZATION,
+'language-support;brazilian-support'          : GROUP_LOCALIZATION,
+'language-support;basque-support'             : GROUP_LOCALIZATION,
+'language-support;welsh-support'              : GROUP_LOCALIZATION,
+'language-support;thai-support'               : GROUP_LOCALIZATION,
+'language-support;telugu-support'             : GROUP_LOCALIZATION,
+'language-support;low-saxon-support'          : GROUP_LOCALIZATION,
+'language-support;urdu-support'               : GROUP_LOCALIZATION,
+'language-support;tamil-support'              : GROUP_LOCALIZATION,
+'language-support;indonesian-support'         : GROUP_LOCALIZATION,
+'language-support;gujarati-support'           : GROUP_LOCALIZATION,
+'language-support;xhosa-support'              : GROUP_LOCALIZATION,
+'language-support;chinese-support'            : GROUP_LOCALIZATION,
+'language-support;czech-support'              : GROUP_LOCALIZATION,
+'language-support;venda-support'              : GROUP_LOCALIZATION,
+'language-support;bulgarian-support'          : GROUP_LOCALIZATION,
+'language-support;albanian-support'           : GROUP_LOCALIZATION,
+'language-support;galician-support'           : GROUP_LOCALIZATION,
+'language-support;armenian-support'           : GROUP_LOCALIZATION,
+'language-support;dutch-support'              : GROUP_LOCALIZATION,
+'language-support;oriya-support'              : GROUP_LOCALIZATION,
+'language-support;maori-support'              : GROUP_LOCALIZATION,
+'language-support;nepali-support'             : GROUP_LOCALIZATION,
+'language-support;icelandic-support'          : GROUP_LOCALIZATION,
+'language-support;ukrainian-support'          : GROUP_LOCALIZATION,
+'language-support;assamese-support'           : GROUP_LOCALIZATION,
+'language-support;bengali-support'            : GROUP_LOCALIZATION,
+'language-support;spanish-support'            : GROUP_LOCALIZATION,
+'language-support;hebrew-support'             : GROUP_LOCALIZATION,
+'language-support;estonian-support'           : GROUP_LOCALIZATION,
+'language-support;french-support'             : GROUP_LOCALIZATION,
+'language-support;croatian-support'           : GROUP_LOCALIZATION,
+'language-support;filipino-support'           : GROUP_LOCALIZATION,
+'language-support;finnish-support'            : GROUP_LOCALIZATION,
+'language-support;norwegian-support'          : GROUP_LOCALIZATION,
+'language-support;southern-ndebele-support'   : GROUP_LOCALIZATION,
+'language-support;polish-support'             : GROUP_LOCALIZATION,
+'language-support;gaelic-support'             : GROUP_LOCALIZATION,
+'language-support;marathi-support'            : GROUP_LOCALIZATION,
+'language-support;ethiopic-support'           : GROUP_LOCALIZATION,
+'rpmfusion_free;kde-desktop'                  : GROUP_DESKTOP_KDE,
+'rpmfusion_free;misc-libs'                    : GROUP_OTHER,
+'rpmfusion_free;games'                        : GROUP_GAMES,
+'rpmfusion_free;misc-tools'                   : GROUP_LOCALIZATION,
+'rpmfusion_free;hardware-support'             : GROUP_ADMIN_TOOLS,
+'rpmfusion_free;sound-and-video'              : GROUP_MULTIMEDIA,
+'rpmfusion_free;base'                         : GROUP_SYSTEM,
+'rpmfusion_free;gnome-desktop'                : GROUP_DESKTOP_GNOME,
+'rpmfusion_free;internet'                     : GROUP_INTERNET,
+'rpmfusion_free;system-tools'                 : GROUP_SYSTEM,
+'rpmfusion_nonfree;games'                     : GROUP_GAMES,
+'rpmfusion_nonfree;hardware-support'          : GROUP_SYSTEM,
+'rpmfusion_nonfree;base'                      : GROUP_SYSTEM
+}
+
+class yumComps:
+
+    def __init__(self,yumbase):
+        self.yumbase = yumbase
+        self.cursor = None
+
+    def connect(self):
+        ''' connect to database '''
+        database = '/var/cache/yum/packagekit-groups.sqlite'
+        try:
+            # will be created if it does not exist
+            connection = sqlite.connect(database)
+            self.cursor = connection.cursor()
+        except Exception, e:
+            print "cannot connect to database %s: %s" % (database,str(e))
+            return
+
+        # test if we can get a group for a common package, create if fail
+        try:
+            self.cursor.execute('SELECT group_enum FROM groups WHERE name = ?;',['hal'])
+        except Exception, e:
+            self.cursor.execute('CREATE TABLE groups (name TEXT,category TEXT,group_enum TEXT);')
+            self.refresh()
+
+    def _add_db(self,name,category,group):
+        self.cursor.execute('INSERT INTO groups values(?,?,?);',(name,category,group))
+
+    def refresh(self,force=False):
+        ''' get the data from yum (slow, REALLY SLOW) '''
+
+        cats = self.yumbase.comps.categories
+        if len(cats) == 0:
+            return False
+
+        # store to sqlite
+        print 'storing in db'
+        for category in cats:
+            grps = map(lambda x: self.yumbase.comps.return_group(x),
+               filter(lambda x: self.yumbase.comps.has_group(x),category.groups))
+            for group in grps:
+
+                # strip out rpmfusion from the group name
+                group_name = group.groupid
+                group_name = group_name.replace('rpmfusion_nonfree-','')
+                group_name = group_name.replace('rpmfusion_free-','')
+                group_id = "%s;%s" % (category.categoryid,group_name)
+
+                group_enum = GROUP_OTHER
+                if groupMap.has_key(group_id):
+                    group_enum = groupMap[group_id]
+                else:
+                    print 'unknown group enum',group_id
+
+                for package in group.mandatory_packages:
+                    self._add_db(package,group_id,group_enum)
+                for package in group.default_packages:
+                    self._add_db(package,group_id,group_enum)
+                for package in group.optional_packages:
+                    self._add_db(package,group_id,group_enum)
+        return True
+
+    def get_package_list(self,group_key):
+        ''' for a PK group, get the packagelist for this group '''
+        all_packages = [];
+        self.cursor.execute('SELECT name FROM groups WHERE group_enum = ?;',[group_key])
+        for row in self.cursor:
+            all_packages.append(row[0])
+        return all_packages
+
+    def get_group(self,pkgname):
+        ''' return the PackageKit group enum for the package '''
+        self.cursor.execute('SELECT group_enum FROM groups WHERE name = ?;',[pkgname])
+        group = GROUP_OTHER
+        for row in self.cursor:
+            group = row[0]
+
+        return group
+
commit 9e25baffd886ea988f2812a956ac83ae36da9fae
Author: Richard Hughes <richard at hughsie.com>
Date:   Mon Jul 7 15:57:52 2008 +0100

    yum: add a nice class to access the yum sqlite database directly.
    
    This isn't complete or tested yet, but reduces the per-package lookup from
    800ms to less than 1ms -- by not using yum or the exclude list.
    Maybe in the future yum will give us more direct access to the database

diff --git a/backends/yum/helpers/yumDirect.py b/backends/yum/helpers/yumDirect.py
new file mode 100644
index 0000000..77e473e
--- /dev/null
+++ b/backends/yum/helpers/yumDirect.py
@@ -0,0 +1,85 @@
+# 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.
+
+# Copyright (C) 2008
+#    Richard Hughes <richard at hughsie.com>
+
+# imports
+from pysqlite2 import dbapi2 as sqlite
+import yum
+
+# simple object that we can use when we use sqlite directly
+class PackageObjectSimple(object):
+    def __init__(self):
+        self.name = None
+        self.epoch = None
+        self.version = None
+        self.release = None
+        self.arch = None
+        self.repo = None
+        self.summary = None
+        self.sourcerpm = None
+        self.requires = []
+        self.pkgKey = 0
+
+# use direct access for speed, for more details see
+# https://bugzilla.redhat.com/show_bug.cgi?id=453356
+class YumDirectSQL(object):
+    def __init__(self,yumbase):
+        ''' connect to all enabled repos '''
+        self.repo_list = []
+        self.cursor_list = []
+        for repo in yumbase.repos.repos.values():
+            if repo.isEnabled():
+                database = '/var/cache/yum/' + repo.id + '/primary.sqlite'
+                try:
+                    connection = sqlite.connect(database)
+                    cursor = connection.cursor()
+                    self.repo_list.append((repo.id,connection))
+                    self.cursor_list.append((cursor,repo.id))
+                except Exception, e:
+                    print "cannot connect to database %s: %s" % (database,str(e))
+
+    def resolve(self,package):
+        ''' resolve a name like "hal" into a list of pkgs '''
+        pkgs = []
+        for cursor,repoid in self.cursor_list:
+            cursor.execute('SELECT name,epoch,version,release,arch,summary,rpm_sourcerpm,pkgKey FROM packages WHERE name = ?',[package])
+            for row in cursor:
+                pkg = PackageObjectSimple()
+                pkg.name = row[0]
+                pkg.epoch = row[1]
+                pkg.version = row[2]
+                pkg.release = row[3]
+                pkg.arch = row[4]
+                pkg.repo = repoid
+                pkg.summary = row[5]
+                pkg.sourcerpm = row[6]
+                pkg.pkgKey = row[7]
+
+                # get the requires
+                cursor.execute('SELECT name FROM requires WHERE pkgKey = ?',[pkg.pkgKey])
+                for row in cursor:
+                    pkg.requires.append(row[0])
+
+                pkgs.append(pkg)
+        return pkgs
+
+    def close(self):
+        ''' close all database connections '''
+        for repo_id,repo_connection in self.repo_list:
+            repo_connection.close()
+
commit f4c1084eb1994e9fa63508a82553870a1e0628ff
Author: Richard Hughes <richard at hughsie.com>
Date:   Mon Jul 7 15:54:38 2008 +0100

    yum: start to abstract out the filtering stuff as most of the time we are getting this wrong when copied and pasted

diff --git a/backends/yum/helpers/yumFilter.py b/backends/yum/helpers/yumFilter.py
new file mode 100644
index 0000000..bab67d1
--- /dev/null
+++ b/backends/yum/helpers/yumFilter.py
@@ -0,0 +1,208 @@
+# 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.
+
+# Copyright (C) 2008
+#    Richard Hughes <richard at hughsie.com>
+
+# imports
+from packagekit.backend import *
+from packagekit.package import *
+from yumDirect import *
+
+import yum
+import rpmUtils
+import re
+
+GUI_KEYS = re.compile(r'(qt)|(gtk)')
+
+class YumFilter(object):
+
+    def __init__(self,fltlist="none"):
+        ''' connect to all enabled repos '''
+        self.fltlist = fltlist
+        self.package_list = [] #we can't do emitting as found if we are post-processing
+        self.installed_nevra = []
+        self.pkpackage = PackagekitPackage()
+
+    def add_installed(self,pkgs):
+        ''' add a list of packages that are already installed '''
+        for pkg in pkgs:
+            if self._do_extra_filtering(pkg,self.fltlist):
+                self.package_list.append((pkg,INFO_INSTALLED))
+            self.installed_nevra.append(self._get_nevra(pkg))
+
+    def add_available(self,pkgs):
+        # add a list of packages that are available
+        for pkg in pkgs:
+            nevra = self._get_nevra(pkg)
+            if nevra not in self.installed_nevra:
+                if self._do_extra_filtering(pkg,self.fltlist):
+                    self.package_list.append((pkg,INFO_AVAILABLE))
+
+    def add_custom(self,pkg,info):
+        ''' add a custom packages indervidually '''
+        nevra = self._get_nevra(pkg)
+        if nevra not in self.installed_nevra:
+            if self._do_extra_filtering(pkg,self.fltlist):
+                self.package_list.append((pkg,info))
+
+    def post_process(self):
+        ''' do filtering we couldn't do when generating the list '''
+
+        if FILTER_BASENAME in self.fltlist:
+            self.package_list = self._basename_filter(self.package_list)
+
+        if FILTER_NEWEST in self.fltlist:
+            self.package_list = self._do_newest_filtering(self.package_list)
+
+        return self.package_list
+
+    def _get_nevra(self,pkg):
+        ''' gets the NEVRA for a pkg '''
+        return "%s-%s:%s-%s.%s" % (pkg.name,pkg.epoch,pkg.version,pkg.release,pkg.arch);
+
+    def _is_main_package(self,repo):
+        if repo.endswith('-debuginfo'):
+            return False
+        if repo.endswith('-devel'):
+            return False
+        if repo.endswith('-libs'):
+            return False
+        return True
+
+    def _basename_filter(self,package_list):
+        '''
+        Filter the list so that the number of packages are reduced.
+        This is done by only displaying gtk2 rather than gtk2-devel, gtk2-debuginfo, etc.
+        This imlementation is done by comparing the SRPM name, and if not falling back
+        to the first entry.
+        We have to fall back else we don't emit packages where the SRPM does not produce a
+        RPM with the same name, for instance, mono produces mono-core, mono-data and mono-winforms.
+        @package_list: a (pkg,status) list of packages
+        A new list is returned that has been filtered
+        '''
+        base_list = []
+        output_list = []
+        base_list_already_got = []
+
+        #find out the srpm name and add to a new array of compound data
+        for (pkg,status) in package_list:
+            if pkg.sourcerpm:
+                base = rpmUtils.miscutils.splitFilename(pkg.sourcerpm)[0]
+                base_list.append ((pkg,status,base,pkg.version));
+            else:
+                base_list.append ((pkg,status,'nosrpm',pkg.version));
+
+        #find all the packages that match thier basename name (done seporately so we get the "best" match)
+        for (pkg,status,base,version) in base_list:
+            if base == pkg.name and (base,version) not in base_list_already_got:
+                output_list.append((pkg,status))
+                base_list_already_got.append ((base,version))
+
+        #for all the ones not yet got, can we match against a non devel match?
+        for (pkg,status,base,version) in base_list:
+            if (base,version) not in base_list_already_got:
+                if self._is_main_package(pkg.name):
+                    output_list.append((pkg,status))
+                    base_list_already_got.append ((base,version))
+
+        #add the remainder of the packages, which should just be the single debuginfo's
+        for (pkg,status,base,version) in base_list:
+            if (base,version) not in base_list_already_got:
+                output_list.append((pkg,status))
+                base_list_already_got.append ((base,version))
+        return output_list
+
+    def _do_newest_filtering(self,pkglist):
+        '''
+        Only return the newest package for each name.arch
+        '''
+        newest = {}
+        for pkg,state in pkglist:
+            key = (pkg.name, pkg.arch)
+            if key in newest and pkg <= newest[key][0]:
+                continue
+            newest[key] = (pkg,state)
+        return newest.values()
+
+    def _do_extra_filtering(self,pkg,filterList):
+        ''' do extra filtering (gui,devel etc) '''
+        for filter in filterList:
+            if filter in (FILTER_INSTALLED,FILTER_NOT_INSTALLED):
+                if not self._do_installed_filtering(filter,pkg):
+                    return False
+            elif filter in (FILTER_GUI,FILTER_NOT_GUI):
+                if not self._do_gui_filtering(filter,pkg):
+                    return False
+            elif filter in (FILTER_DEVELOPMENT,FILTER_NOT_DEVELOPMENT):
+                if not self._do_devel_filtering(filter,pkg):
+                    return False
+            elif filter in (FILTER_FREE,FILTER_NOT_FREE):
+                if not self._do_free_filtering(filter,pkg):
+                    return False
+        return True
+
+    def _do_installed_filtering(self,flt,pkg):
+        isInstalled = False
+        if flt == FILTER_INSTALLED:
+            wantInstalled = True
+        else:
+            wantInstalled = False
+        if isinstance(pkg,PackageObjectSimple):
+            isInstalled = False
+        else:
+            isInstalled = pkg.repo.id == 'installed'
+        return isInstalled == wantInstalled
+
+    def _do_gui_filtering(self,flt,pkg):
+        isGUI = False
+        if flt == FILTER_GUI:
+            wantGUI = True
+        else:
+            wantGUI = False
+        isGUI = self._check_for_gui(pkg)
+        return isGUI == wantGUI
+
+    def _check_for_gui(self,pkg):
+        '''  Check if the GUI_KEYS regex matches any package requirements'''
+        for req in pkg.requires:
+            reqname = req[0]
+            if GUI_KEYS.search(reqname):
+                return True
+        return False
+
+    def _do_devel_filtering(self,flt,pkg):
+        isDevel = False
+        if flt == FILTER_DEVELOPMENT:
+            wantDevel = True
+        else:
+            wantDevel = False
+        regex =  re.compile(r'(-devel)|(-dgb)|(-static)')
+        if regex.search(pkg.name):
+            isDevel = True
+        return isDevel == wantDevel
+
+    def _do_free_filtering(self,flt,pkg):
+        isFree = False
+        if flt == FILTER_FREE:
+            wantFree = True
+        else:
+            wantFree = False
+
+        isFree = self.pkpackage.check_license_field(pkg.license)
+
+        return isFree == wantFree
+
commit 743c5ea0b394f19aab3f3d4aaf0ddd848fc6a73e
Author: Richard Hughes <richard at hughsie.com>
Date:   Mon Jul 7 15:52:39 2008 +0100

    python: split out PackagekitProgress and PackagekitPackage as these are nothing to do with the backend
    
    You might need to add:
    from packagekit.progress import *
    from packagekit.package import *
    
    to your backend if it uses either of these

diff --git a/python/packagekit/backend.py b/python/packagekit/backend.py
index c46d977..9fbea16 100644
--- a/python/packagekit/backend.py
+++ b/python/packagekit/backend.py
@@ -201,77 +201,6 @@ class PackageKitBaseBackend:
             )
         sys.stdout.flush()
 
-    def get_package_id(self,name,version,arch,data):
-        return "%s;%s;%s;%s" % (name,version,arch,data)
-
-    def get_package_from_id(self,id):
-        ''' split up a package id name;ver;arch;data into a tuple
-            containing (name,ver,arch,data)
-        '''
-        return tuple(id.split(';',4))
-
-    def check_license_field(self,license_field):
-        '''
-        Check the string license_field for free licenses, indicated by
-        their short names as documented at
-        http://fedoraproject.org/wiki/Licensing
-
-        Licenses can be grouped by " or " to indicate that the package
-        can be redistributed under any of the licenses in the group.
-        For instance: GPLv2+ or Artistic or FooLicense.
-
-        Also, if a license ends with "+", the "+" is removed before
-        comparing it to the list of valid licenses.  So if license
-        "FooLicense" is free, then "FooLicense+" is considered free.
-
-        Groups of licenses can be grouped with " and " to indicate
-        that parts of the package are distributed under one group of
-        licenses, while other parts of the package are distributed
-        under another group.  Groups may be wrapped in parenthesis.
-        For instance:
-          (GPLv2+ or Artistic) and (GPL+ or Artistic) and FooLicense.
-
-        At least one license in each group must be free for the
-        package to be considered Free Software.  If the license_field
-        is empty, the package is considered non-free.
-        '''
-
-        groups = license_field.split(" and ")
-
-        if len(groups) == 0:
-            return False
-
-        one_free_group = False
-
-        for group in groups:
-            group = group.replace("(","")
-            group = group.replace(")","")
-            licenses = group.split(" or ")
-
-            group_is_free = False
-
-            for license in licenses:
-                license = license.strip()
-
-                if len(license) < 1:
-                    continue
-
-                if license[-1] == "+":
-                    license = license[0:-1]
-
-                if license in PackageKitEnum.free_licenses:
-                    one_free_group = True
-                    group_is_free = True
-                    break
-
-            if group_is_free == False:
-                return False
-
-        if one_free_group == False:
-            return False
-
-        return True
-
 #
 # Backend Action Methods
 #
@@ -464,89 +393,6 @@ class PackageKitBaseBackend:
         '''
         return False
 
-class PackagekitProgress:
-    '''
-    Progress class there controls the total progress of a transaction
-    the transaction is divided in n milestones. the class contains a subpercentage
-    of the current step (milestone n -> n+1) and the percentage of the whole transaction
-
-    Usage:
-
-    from packagekit.backend import PackagekitProgress
-
-    steps = [10,30,50,70] # Milestones in %
-    progress = PackagekitProgress()
-    progress.set_steps(steps)
-    for milestone in range(len(steps)):
-        # do the action is this step
-        for i in range(100):
-            # do some action
-            progress.set_subpercent(i+1)
-            print "progress : %s " % progress.percent
-        progress.step() # step to next milestone
-
-    '''
-
-    #TODO: Add support for elapsed/remaining time
-
-    def __init__(self):
-        self.percent = 0
-        self.steps = []
-        self.current_step = 0
-        self.subpercent = 0
-
-    def set_steps(self,steps):
-        '''
-        Set the steps for the whole transaction
-        @param steps: list of int representing the percentage of each step in the transaction
-        '''
-        self.reset()
-        self.steps = steps
-        self.current_step = 0
-
-    def reset(self):
-        self.percent = 0
-        self.steps = []
-        self.current_step = 0
-        self.subpercent = 0
-
-    def step(self):
-        '''
-        Step to the next step in the transaction
-        '''
-        if self.current_step < len(self.steps)-1:
-            self.current_step += 1
-            self.percent = self.steps[self.current_step]
-            self.subpercent = 0
-        else:
-            self.percent = 100
-            self.subpercent = 0
-
-    def set_subpercent(self,pct):
-        '''
-        Set subpercentage and update percentage
-        '''
-        self.subpercent = pct
-        self._update_percent()
-
-    def _update_percent(self):
-        '''
-        Increment percentage based on current step and subpercentage
-        '''
-        if self.current_step == 0:
-            startpct = 0
-        else:
-            startpct = self.steps[self.current_step-1]
-        if self.current_step < len(self.steps)-1:
-            endpct = self.steps[self.current_step+1]
-        else:
-            endpct = 100
-        deltapct = endpct -startpct
-        f = float(self.subpercent)/100.0
-        incr = int(f*deltapct)
-        self.percent = startpct + incr
-
-
 def exceptionHandler(typ,value,tb,base):
     # Restore original exception handler
     sys.excepthook = sys.__excepthook__
diff --git a/python/packagekit/package.py b/python/packagekit/package.py
new file mode 100644
index 0000000..2bfbd34
--- /dev/null
+++ b/python/packagekit/package.py
@@ -0,0 +1,94 @@
+# 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.
+
+# Copyright (C) 2008
+#    Richard Hughes <richard at hughsie.com>
+
+from packagekit.backend import *
+
+class PackagekitPackage:
+
+    def get_package_id(self,name,version,arch,data):
+        return "%s;%s;%s;%s" % (name,version,arch,data)
+
+    def get_package_from_id(self,id):
+        ''' split up a package id name;ver;arch;data into a tuple
+            containing (name,ver,arch,data)
+        '''
+        return tuple(id.split(';',4))
+
+    def check_license_field(self,license_field):
+        '''
+        Check the string license_field for free licenses, indicated by
+        their short names as documented at
+        http://fedoraproject.org/wiki/Licensing
+
+        Licenses can be grouped by " or " to indicate that the package
+        can be redistributed under any of the licenses in the group.
+        For instance: GPLv2+ or Artistic or FooLicense.
+
+        Also, if a license ends with "+", the "+" is removed before
+        comparing it to the list of valid licenses.  So if license
+        "FooLicense" is free, then "FooLicense+" is considered free.
+
+        Groups of licenses can be grouped with " and " to indicate
+        that parts of the package are distributed under one group of
+        licenses, while other parts of the package are distributed
+        under another group.  Groups may be wrapped in parenthesis.
+        For instance:
+          (GPLv2+ or Artistic) and (GPL+ or Artistic) and FooLicense.
+
+        At least one license in each group must be free for the
+        package to be considered Free Software.  If the license_field
+        is empty, the package is considered non-free.
+        '''
+
+        groups = license_field.split(" and ")
+
+        if len(groups) == 0:
+            return False
+
+        one_free_group = False
+
+        for group in groups:
+            group = group.replace("(","")
+            group = group.replace(")","")
+            licenses = group.split(" or ")
+
+            group_is_free = False
+
+            for license in licenses:
+                license = license.strip()
+
+                if len(license) < 1:
+                    continue
+
+                if license[-1] == "+":
+                    license = license[0:-1]
+
+                if license in PackageKitEnum.free_licenses:
+                    one_free_group = True
+                    group_is_free = True
+                    break
+
+            if group_is_free == False:
+                return False
+
+        if one_free_group == False:
+            return False
+
+        return True
+
diff --git a/python/packagekit/progress.py b/python/packagekit/progress.py
new file mode 100644
index 0000000..16ee1fc
--- /dev/null
+++ b/python/packagekit/progress.py
@@ -0,0 +1,101 @@
+# 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.
+
+# Copyright (C) 2008
+#    Richard Hughes <richard at hughsie.com>
+
+class PackagekitProgress:
+    '''
+    Progress class there controls the total progress of a transaction
+    the transaction is divided in n milestones. the class contains a subpercentage
+    of the current step (milestone n -> n+1) and the percentage of the whole transaction
+
+    Usage:
+
+    from packagekit import PackagekitProgress
+
+    steps = [10,30,50,70] # Milestones in %
+    progress = PackagekitProgress()
+    progress.set_steps(steps)
+    for milestone in range(len(steps)):
+        # do the action is this step
+        for i in range(100):
+            # do some action
+            progress.set_subpercent(i+1)
+            print "progress : %s " % progress.percent
+        progress.step() # step to next milestone
+
+    '''
+
+    #TODO: Add support for elapsed/remaining time
+
+    def __init__(self):
+        self.percent = 0
+        self.steps = []
+        self.current_step = 0
+        self.subpercent = 0
+
+    def set_steps(self,steps):
+        '''
+        Set the steps for the whole transaction
+        @param steps: list of int representing the percentage of each step in the transaction
+        '''
+        self.reset()
+        self.steps = steps
+        self.current_step = 0
+
+    def reset(self):
+        self.percent = 0
+        self.steps = []
+        self.current_step = 0
+        self.subpercent = 0
+
+    def step(self):
+        '''
+        Step to the next step in the transaction
+        '''
+        if self.current_step < len(self.steps)-1:
+            self.current_step += 1
+            self.percent = self.steps[self.current_step]
+            self.subpercent = 0
+        else:
+            self.percent = 100
+            self.subpercent = 0
+
+    def set_subpercent(self,pct):
+        '''
+        Set subpercentage and update percentage
+        '''
+        self.subpercent = pct
+        self._update_percent()
+
+    def _update_percent(self):
+        '''
+        Increment percentage based on current step and subpercentage
+        '''
+        if self.current_step == 0:
+            startpct = 0
+        else:
+            startpct = self.steps[self.current_step-1]
+        if self.current_step < len(self.steps)-1:
+            endpct = self.steps[self.current_step+1]
+        else:
+            endpct = 100
+        deltapct = endpct -startpct
+        f = float(self.subpercent)/100.0
+        incr = int(f*deltapct)
+        self.percent = startpct + incr
+
commit c897e16653d8e2a440a6d696690cc1503b144dec
Author: Fabian Affolter <fabian at bernewireless.net>
Date:   Mon Jul 7 10:05:02 2008 +0000

    2008-07-07  Fabian Affolter <fabian at bernewireless.net> (via
    fab at fedoraproject.org)
    
      * po/de.po: Updated German translation

diff --git a/po/de.po b/po/de.po
index 6e8013e..1496e28 100644
--- a/po/de.po
+++ b/po/de.po
@@ -8,8 +8,8 @@ msgid ""
 msgstr ""
 "Project-Id-Version: PackageKit\n"
 "Report-Msgid-Bugs-To: \n"
-"POT-Creation-Date: 2008-05-03 01:22+0000\n"
-"PO-Revision-Date: 2008-05-20 21:52+0100\n"
+"POT-Creation-Date: 2008-06-10 17:24+0000\n"
+"PO-Revision-Date: 2008-07-07 11:56+0100\n"
 "Last-Translator: Fabian Affolter <fab at fedoraproject.org>\n"
 "Language-Team: German <fedora-trans-de at redhat.com>\n"
 "MIME-Version: 1.0\n"
@@ -18,243 +18,247 @@ msgstr ""
 "Plural-Forms: nplurals=2; plural=(n != 1);\n"
 "X-Poedit-Language: German\n"
 
-#: ../client/pk-console.c:224
+#: ../client/pk-console.c:223
 msgid "Update detail"
 msgstr "Aktualisierungsdetails"
 
-#: ../client/pk-console.c:425
+#: ../client/pk-console.c:424
 msgid "A system restart is required"
 msgstr "Ein Systemneustart ist erforderlich"
 
-#: ../client/pk-console.c:427
+#: ../client/pk-console.c:426
 msgid "A logout and login is required"
 msgstr "Eine Neuanmeldung ist erforderlich"
 
-#: ../client/pk-console.c:429
+#: ../client/pk-console.c:428
 msgid "An application restart is required"
 msgstr "Ein Neustart der Anwendung ist erforderlich"
 
-#: ../client/pk-console.c:474
+#: ../client/pk-console.c:473
 #, c-format
 msgid "Please enter a number from 1 to %i: "
 msgstr "Bitte eine Zahl zwischen 1 und %i eingeben: "
 
-#: ../client/pk-console.c:524
+#: ../client/pk-console.c:533
 msgid "Could not find a package match"
 msgstr "Es konnte kein passendes Paket gefunden werden"
 
-#: ../client/pk-console.c:538
+#: ../client/pk-console.c:547
 msgid "There are multiple package matches"
 msgstr "Es wurden mehrere passende Paket gefunden"
 
 #. find out what package the user wants to use
-#: ../client/pk-console.c:545
+#: ../client/pk-console.c:554
 msgid "Please enter the package number: "
 msgstr "Bitte die Paketnummer eingeben: "
 
-#: ../client/pk-console.c:561
+#: ../client/pk-console.c:589
 msgid "Could not find a package with that name to install, or package already installed"
 msgstr "Es konnten weder installierte noch zu installierende Paket mit diesem Namen gefunden werden"
 
-#: ../client/pk-console.c:643
-msgid "Could not find a package with that name to remove"
-msgstr "Es konnte kein Paket mit diesem Namen zum Deinstallieren gefunden werden"
+#: ../client/pk-console.c:737
+msgid "Could not find a package to remove"
+msgstr "Es konnte kein Paket zum Deinstallieren finden"
 
-#: ../client/pk-console.c:683
+#: ../client/pk-console.c:806
 msgid "The following packages have to be removed"
 msgstr "Die folgenden Paket werden entfernt"
 
 #. get user input
-#: ../client/pk-console.c:692
+#: ../client/pk-console.c:815
 msgid "Okay to remove additional packages?"
 msgstr "Die folgenden zusätzlichen Pakete entfernen?"
 
-#: ../client/pk-console.c:696
+#: ../client/pk-console.c:819
 msgid "Cancelled!"
 msgstr "Abgebrochen!"
 
-#: ../client/pk-console.c:718
+#: ../client/pk-console.c:844
 msgid "Could not find a package with that name to update"
 msgstr "Es konnte kein Paket mit diesem Namen zum Aktualisieren gefunden werden"
 
-#: ../client/pk-console.c:736
+#: ../client/pk-console.c:862
 msgid "Could not find what packages require this package"
 msgstr "Es konnte nicht rausgefunden werden, welche Pakete dieses Paket benötigen"
 
-#: ../client/pk-console.c:754
+#: ../client/pk-console.c:880
 msgid "Could not get dependencies for this package"
 msgstr "Die Abhängigkeiten für dieses Paket konnten nicht ermittelt werden"
 
-#: ../client/pk-console.c:772
+#: ../client/pk-console.c:898
 msgid "Could not find details for this package"
 msgstr "Die Details für dieses Paket konnten nicht gefunden werden"
 
-#: ../client/pk-console.c:790
+#: ../client/pk-console.c:916
 msgid "Could not find the files for this package"
 msgstr "Die Dateien für dieses Paket konnten nicht ermittelt werden"
 
-#: ../client/pk-console.c:870
+#: ../client/pk-console.c:996
 msgid "Package description"
 msgstr "Paketbeschreibung"
 
-#: ../client/pk-console.c:893
+#: ../client/pk-console.c:1019
 msgid "Package files"
 msgstr "Paketinhalt"
 
-#: ../client/pk-console.c:901
+#: ../client/pk-console.c:1027
 msgid "No files"
 msgstr "Keine Dateien"
 
 #. get user input
-#: ../client/pk-console.c:933
+#: ../client/pk-console.c:1059
 msgid "Okay to import key?"
 msgstr "Soll der Schlüssel importiert werden?"
 
-#: ../client/pk-console.c:936
+#: ../client/pk-console.c:1062
 msgid "Did not import key"
 msgstr "Den Schlüssel nicht importieren"
 
 #. get user input
-#: ../client/pk-console.c:976
+#: ../client/pk-console.c:1102
 msgid "Do you agree?"
 msgstr "Sind Sie einverstanden?"
 
-#: ../client/pk-console.c:979
+#: ../client/pk-console.c:1105
 msgid "Did not agree to licence, task will fail"
 msgstr "Lizenz wurde abgelehnt, Aufgabe wird fehlschlagen"
 
-#: ../client/pk-console.c:1008
+#: ../client/pk-console.c:1134
 msgid "The daemon crashed mid-transaction!"
 msgstr "Der Dienst ist während der Verarbeitung abgestürzt!"
 
 #. header
-#: ../client/pk-console.c:1061
+#: ../client/pk-console.c:1187
 msgid "PackageKit Console Interface"
 msgstr "PackageKit-Konsolenschnittstelle"
 
-#: ../client/pk-console.c:1061
+#: ../client/pk-console.c:1187
 msgid "Subcommands:"
 msgstr "Unterbefehle:"
 
-#: ../client/pk-console.c:1165
+#: ../client/pk-console.c:1290
 #: ../client/pk-monitor.c:104
 #: ../src/pk-main.c:189
 msgid "Show extra debugging information"
 msgstr "Zusätzliche Debugging-Informationen anzeigen"
 
-#: ../client/pk-console.c:1167
+#: ../client/pk-console.c:1292
 #: ../client/pk-monitor.c:106
 msgid "Show the program version and exit"
 msgstr "Die Programmversion anzeigen und beenden"
 
-#: ../client/pk-console.c:1169
+#: ../client/pk-console.c:1294
 msgid "Set the filter, e.g. installed"
 msgstr "Setzt den Filter, z. B. installiert"
 
-#: ../client/pk-console.c:1171
+#: ../client/pk-console.c:1296
 msgid "Exit without waiting for actions to complete"
 msgstr "Beenden ohne auf das Ende der Aktionen zu warten"
 
-#: ../client/pk-console.c:1194
+#: ../client/pk-console.c:1319
 msgid "Could not connect to system DBUS."
 msgstr "Mit System-DBUS konnte nicht verbunden werden."
 
-#: ../client/pk-console.c:1288
+#: ../client/pk-console.c:1413
 msgid "You need to specify a search type"
 msgstr "Es muss eine Suchart angegeben werden"
 
-#: ../client/pk-console.c:1293
-#: ../client/pk-console.c:1300
-#: ../client/pk-console.c:1307
-#: ../client/pk-console.c:1314
-#: ../client/pk-console.c:1421
-#: ../client/pk-console.c:1428
-#: ../client/pk-console.c:1435
-#: ../client/pk-console.c:1442
+#: ../client/pk-console.c:1418
+#: ../client/pk-console.c:1425
+#: ../client/pk-console.c:1432
+#: ../client/pk-console.c:1439
+#: ../client/pk-console.c:1538
+#: ../client/pk-console.c:1545
+#: ../client/pk-console.c:1552
+#: ../client/pk-console.c:1559
 msgid "You need to specify a search term"
 msgstr "Es muss ein Suchausdruck angegeben werden"
 
-#: ../client/pk-console.c:1319
+#: ../client/pk-console.c:1444
 msgid "Invalid search type"
 msgstr "Ungültige Suchart"
 
-#: ../client/pk-console.c:1324
+#: ../client/pk-console.c:1449
 msgid "You need to specify a package or file to install"
 msgstr "Es muss ein Paket oder eine Datei zum Installieren angegeben werden"
 
-#: ../client/pk-console.c:1339
+#: ../client/pk-console.c:1456
 msgid "You need to specify a type, key_id and package_id"
 msgstr "Es muss ein Typ angegeben werden, key_id oder package_id"
 
-#: ../client/pk-console.c:1346
+#: ../client/pk-console.c:1463
 msgid "You need to specify a package to remove"
 msgstr "Es muss ein Paket zum Entfernen angegeben werden"
 
-#: ../client/pk-console.c:1353
+#: ../client/pk-console.c:1470
 msgid "You need to specify a eula-id"
 msgstr "Es muss eine eula-id angegeben werden"
 
-#: ../client/pk-console.c:1369
+#: ../client/pk-console.c:1486
 msgid "You need to specify a package name to resolve"
 msgstr "Es muss ein Paketname zum Auflösen angegeben werden"
 
-#: ../client/pk-console.c:1376
-#: ../client/pk-console.c:1383
+#: ../client/pk-console.c:1493
+#: ../client/pk-console.c:1500
 msgid "You need to specify a repo name"
 msgstr "Es muss ein Repository-Name angegeben werden"
 
-#: ../client/pk-console.c:1390
+#: ../client/pk-console.c:1507
 msgid "You need to specify a repo name/parameter and value"
 msgstr "Es muss ein Repository-Name/Argument und Wert angegeben werden"
 
-#: ../client/pk-console.c:1403
+#: ../client/pk-console.c:1520
 msgid "You need to specify a time term"
 msgstr "Es muss ein Zeitausdruck angegeben werden"
 
-#: ../client/pk-console.c:1408
+#: ../client/pk-console.c:1525
 msgid "You need to specify a correct role"
 msgstr "Es muss eine korrekte Rolle angegeben werden"
 
-#: ../client/pk-console.c:1413
+#: ../client/pk-console.c:1530
 msgid "Failed to get last time"
 msgstr "Die letzte Zeit konnte nicht abgefragt werden"
 
-#: ../client/pk-console.c:1449
+#: ../client/pk-console.c:1566
 msgid "You need to specify a package to find the details for"
 msgstr "Es muss ein Paket angegeben werden zu dem die Details gefunden werden sollen"
 
-#: ../client/pk-console.c:1456
+#: ../client/pk-console.c:1573
 msgid "You need to specify a package to find the files for"
 msgstr "Es muss ein Paket angegeben werden zu dem die Dateien gefunden werden sollen"
 
-#: ../client/pk-console.c:1503
+#: ../client/pk-console.c:1622
 #, c-format
 msgid "Option '%s' not supported"
 msgstr "Option '%s' wird nicht unterstützt"
 
-#: ../client/pk-console.c:1514
+#: ../client/pk-console.c:1633
 msgid "Command failed"
 msgstr "Befehl fehlgeschlagen"
 
-#: ../client/pk-console.c:1518
+#: ../client/pk-console.c:1637
 msgid "You don't have the necessary privileges for this operation"
 msgstr "Es fehlen die benötigten Rechte für diese Operation"
 
-#: ../client/pk-monitor.c:117
-msgid "PackageKit Monitor"
-msgstr "PackageKit Monitor"
-
-#: ../client/pk-import-desktop.c:293
-#: ../client/pk-import-specspo.c:169
+#: ../client/pk-import-desktop.c:298
+#: ../client/pk-import-specspo.c:173
 #, c-format
 msgid "Could not open database: %s"
 msgstr "Datenbank konnte nicht geöffnet werden: %s"
 
-#: ../client/pk-import-desktop.c:294
-#: ../client/pk-import-specspo.c:170
+#: ../client/pk-import-desktop.c:299
+#: ../client/pk-import-specspo.c:174
 msgid "You probably need to run this program as the root user"
 msgstr "Das Programm muss möglicherweise als Benutzer root ausgeführt werden"
 
+#: ../client/pk-monitor.c:117
+msgid "PackageKit Monitor"
+msgstr "PackageKit Monitor"
+
+#: ../data/packagekit-catalog.xml.in.h:1
+msgid "PackageKit Catalog"
+msgstr "PackageKit-Katalog"
+
 #: ../src/pk-main.c:83
 msgid "Startup failed due to security policies on this machine."
 msgstr "Start auf Grund einer Sicherheitsrichtlinie fehlgeschlagen."
commit 9817aca336c5304d5700cae91ba71c22edd1297e
Author: Patrick Niklaus <marex at opencompositing.org>
Date:   Sun Jul 6 14:44:57 2008 +0100

    Changed the required version of dbus-glib to 0.76

diff --git a/configure.ac b/configure.ac
index c31313c..d99062c 100644
--- a/configure.ac
+++ b/configure.ac
@@ -74,7 +74,7 @@ dnl ---------------------------------------------------------------------------
 GLIB_REQUIRED=2.14.0
 GIO_REQUIRED=2.16.1
 DBUS_REQUIRED=1.1.1
-DBUS_GLIB_REQUIRED=0.73
+DBUS_GLIB_REQUIRED=0.76
 LIBNM_GLIB_REQUIRED=0.6.4
 POLKIT_DBUS_REQUIRED=0.8
 POLKIT_GRANT_REQUIRED=0.8
commit d4ca2a1075d8c0ba1c937224e057c0647994df33
Author: Richard Hughes <richard at hughsie.com>
Date:   Fri Jul 4 17:16:02 2008 +0100

    trivial: resize some pictures of the dudes

diff --git a/docs/html/img/author-caglar.png b/docs/html/img/author-caglar.png
index 40acc2c..4370b62 100644
Binary files a/docs/html/img/author-caglar.png and b/docs/html/img/author-caglar.png differ
diff --git a/docs/html/img/author-elliot.png b/docs/html/img/author-elliot.png
index 733eebc..022c282 100644
Binary files a/docs/html/img/author-elliot.png and b/docs/html/img/author-elliot.png differ
commit 59a47e5caae1cd6f9808be3ee4dd8858b1554967
Author: Richard Hughes <richard at hughsie.com>
Date:   Fri Jul 4 17:15:47 2008 +0100

    yum: fix the Resolve() call with multiple packages

diff --git a/backends/yum/helpers/resolve.py b/backends/yum/helpers/resolve.py
index 7807245..91f32ff 100755
--- a/backends/yum/helpers/resolve.py
+++ b/backends/yum/helpers/resolve.py
@@ -13,8 +13,8 @@ import sys
 
 from yumBackend import PackageKitYumBackend
 filters = sys.argv[1]
-name=sys.argv[2]
+packages = sys.argv[2:]
 backend = PackageKitYumBackend(sys.argv[2:])
-backend.resolve(filters, name.split('|'))
+backend.resolve(filters,packages)
 backend.unLock()
 sys.exit(0)
diff --git a/backends/yum/helpers/yumBackend.py b/backends/yum/helpers/yumBackend.py
index 25b0dde..a5acfe0 100644
--- a/backends/yum/helpers/yumBackend.py
+++ b/backends/yum/helpers/yumBackend.py
@@ -965,7 +965,7 @@ class PackageKitYumBackend(PackageKitBaseBackend):
             self.error(ERROR_UNKNOWN,str(e))
 
     @handle_repo_error
-    def resolve(self,filters,name):
+    def resolve(self,filters,packages):
         '''
         Implement the {backend}-resolve functionality
         '''
@@ -977,16 +977,16 @@ class PackageKitYumBackend(PackageKitBaseBackend):
         self.status(STATUS_QUERY)
 
         fltlist = filters.split(';')
-        for package in package_ids:
+        for package in packages:
             # Get installed packages
-            installedByKey = self.yumbase.rpmdb.searchNevra(name=name)
+            installedByKey = self.yumbase.rpmdb.searchNevra(name=package)
             if FILTER_NOT_INSTALLED not in fltlist:
                 for pkg in installedByKey:
                     self._show_package(pkg,INFO_INSTALLED)
             # Get available packages
             if FILTER_INSTALLED not in fltlist:
                 for pkg in self.yumbase.pkgSack.returnNewestByNameArch():
-                    if pkg.name == name:
+                    if pkg.name == package:
                         show = True
                         for instpo in installedByKey:
                             # Check if package have a smaller & equal EVR to a inst pkg
commit 2449144b7dbcf1dd501c5b40115599b1b6005e93
Author: Richard Hughes <richard at hughsie.com>
Date:   Fri Jul 4 15:17:04 2008 +0100

    trivial: use the correct image, pahh

diff --git a/docs/html/img/gpk-remove-confirm.png b/docs/html/img/gpk-remove-confirm.png
index c44c95d..13a402c 100644
Binary files a/docs/html/img/gpk-remove-confirm.png and b/docs/html/img/gpk-remove-confirm.png differ
commit 6c2d1860e1c1cbfbd6189ae86c20baf500f9699f
Author: Richard Hughes <richard at hughsie.com>
Date:   Fri Jul 4 14:46:33 2008 +0100

    trivial: update a couple of the doc images

diff --git a/docs/html/img/gpk-added-deps.png b/docs/html/img/gpk-added-deps.png
index 8cc922e..f23bda1 100644
Binary files a/docs/html/img/gpk-added-deps.png and b/docs/html/img/gpk-added-deps.png differ
diff --git a/docs/html/img/gpk-remove-confirm.png b/docs/html/img/gpk-remove-confirm.png
index b7cbb8c..c44c95d 100644
Binary files a/docs/html/img/gpk-remove-confirm.png and b/docs/html/img/gpk-remove-confirm.png differ


More information about the PackageKit-commit mailing list