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

Richard Hughes hughsient at kemper.freedesktop.org
Fri Feb 5 03:23:26 PST 2010


 .gitignore                             |    2 
 RELEASE                                |   10 
 backends/Makefile.am                   |    4 
 backends/entropy/Makefile.am           |   16 
 backends/entropy/TODO                  |   34 
 backends/entropy/entropyBackend.py     | 1536 +++++++++++++++++++++++++++++++++
 backends/entropy/pk-backend-entropy.c  |  507 ++++++++++
 backends/portage/pk-backend-portage.c  |    2 
 backends/portage/portageBackend.py     |    4 
 backends/yum/pk-backend-yum.c          |   51 +
 backends/yum/yumBackend.py             |  302 +++---
 backends/zypp/zypp-utils.cpp           |    1 
 client/pk-monitor.c                    |   26 
 configure.ac                           |   12 
 docs/html/img/author-lxnay.png         |binary
 docs/html/pk-authors.html              |   15 
 docs/planned-api-changes.txt           |   28 
 lib/packagekit-glib2/.gitignore        |    2 
 lib/packagekit-glib2/pk-client.h       |    4 
 lib/packagekit-glib2/pk-enum.c         |    7 
 lib/packagekit-glib2/pk-enum.h         |    7 
 lib/packagekit-glib2/pk-package-sack.c |   55 +
 lib/packagekit-glib2/pk-package-sack.h |    3 
 lib/packagekit-glib2/pk-task.c         |   24 
 lib/packagekit-qt/src/Makefile.am      |   11 
 lib/packagekit-qt/src/client.h         |   42 
 lib/packagekit-qt/src/enum.cpp         |   30 
 lib/packagekit-qt/src/enum.h           |  213 ++++
 lib/packagekit-qt/src/package.cpp      |   20 
 lib/packagekit-qt/src/package.h        |  170 ---
 lib/python/packagekit/backend.py       |   13 
 src/Makefile.am                        |    2 
 src/pk-backend-spawn.c                 |   33 
 src/pk-backend.c                       |   27 
 src/pk-backend.h                       |    2 
 src/pk-transaction.c                   |    3 
 36 files changed, 2860 insertions(+), 358 deletions(-)

New commits:
commit b7241eb689b4fc8883c224442c2da17ff22d23f6
Author: Richard Hughes <richard at hughsie.com>
Date:   Fri Feb 5 11:21:57 2010 +0000

    yum: don't show an internal error if the database was changed by rpm when we are building a transaction

diff --git a/backends/yum/yumBackend.py b/backends/yum/yumBackend.py
index 4316150..f58719c 100755
--- a/backends/yum/yumBackend.py
+++ b/backends/yum/yumBackend.py
@@ -2067,6 +2067,8 @@ class PackageKitYumBackend(PackageKitBaseBackend, PackagekitPackage):
             message = _format_msgs(msgs)
         except yum.Errors.RepoError, e:
             raise PkError(ERROR_REPO_NOT_AVAILABLE, _to_unicode(e))
+        except yum.Errors.PackageSackError, e:
+            raise PkError(ERROR_PACKAGE_DATABASE_CHANGED, _to_unicode(e))
         except Exception, e:
             raise PkError(ERROR_INTERNAL_ERROR, _format_str(traceback.format_exc()))
 
commit adee23f5a1468ab61c3e3fb4ae099db7edcf074e
Author: Richard Hughes <richard at hughsie.com>
Date:   Fri Feb 5 11:21:32 2010 +0000

    trivial: Add another error enum: PACKAGE_DATABASE_CHANGED

diff --git a/lib/packagekit-glib2/pk-enum.c b/lib/packagekit-glib2/pk-enum.c
index a443edb..475d5f0 100644
--- a/lib/packagekit-glib2/pk-enum.c
+++ b/lib/packagekit-glib2/pk-enum.c
@@ -192,6 +192,7 @@ static const PkEnumMatch enum_error[] = {
 	{PK_ERROR_ENUM_PACKAGE_FAILED_TO_INSTALL, "package-failed-to-install"},
 	{PK_ERROR_ENUM_PACKAGE_FAILED_TO_REMOVE, "package-failed-to-remove"},
 	{PK_ERROR_ENUM_UPDATE_FAILED_DUE_TO_RUNNING_PROCESS, "failed-due-to-running-process"},
+	{PK_ERROR_ENUM_PACKAGE_DATABASE_CHANGED, "package-database-changed"},
 	{0, NULL}
 };
 
diff --git a/lib/packagekit-glib2/pk-enum.h b/lib/packagekit-glib2/pk-enum.h
index 338cbc7..9fdb6ad 100644
--- a/lib/packagekit-glib2/pk-enum.h
+++ b/lib/packagekit-glib2/pk-enum.h
@@ -358,6 +358,7 @@ typedef enum {
 	PK_ERROR_ENUM_PACKAGE_FAILED_TO_INSTALL,
 	PK_ERROR_ENUM_PACKAGE_FAILED_TO_REMOVE,
 	PK_ERROR_ENUM_UPDATE_FAILED_DUE_TO_RUNNING_PROCESS,
+	PK_ERROR_ENUM_PACKAGE_DATABASE_CHANGED,
 	PK_ERROR_ENUM_LAST
 } PkErrorEnum;
 
commit 90066e3b2ca20ad09a267194bd924bdf7b8d0a97
Author: Richard Hughes <richard at hughsie.com>
Date:   Fri Feb 5 09:57:00 2010 +0000

    qt: Add a Last[enum-type] entry to ensure we always can compile with -pedantic-errors and be able to insert an enum in  single line

diff --git a/lib/packagekit-qt/src/client.h b/lib/packagekit-qt/src/client.h
index 1904825..61927c9 100644
--- a/lib/packagekit-qt/src/client.h
+++ b/lib/packagekit-qt/src/client.h
@@ -117,7 +117,9 @@ public:
 		ActionSimulateInstallFiles,
 		ActionSimulateInstallPackages,
 		ActionSimulateRemovePackages,
-		ActionSimulateUpdatePackages
+		ActionSimulateUpdatePackages,
+		/* this always has to be at the end of the list */
+		LastAction
 	} Action;
 	typedef Bitfield Actions;
 
@@ -218,7 +220,9 @@ public:
 		GroupElectronics,
 		GroupCollections,
 		GroupVendor,
-		GroupNewest
+		GroupNewest,
+		/* this always has to be at the end of the list */
+		LastGroup
 	} Group;
 	typedef QSet<Group> Groups;
 
@@ -246,7 +250,9 @@ public:
 		NetworkOnline,
 		NetworkWired,
 		NetworkWifi,
-		NetworkMobile
+		NetworkMobile,
+		/* this always has to be at the end of the list */
+		LastNetworkState
 	} NetworkState;
 
 	/**
@@ -315,7 +321,9 @@ public:
 	 */
 	typedef enum {
 		UnknownSignatureType,
-		SignatureGpg
+		SignatureGpg,
+		/* this always has to be at the end of the list */
+		LastSignatureType
 	} SignatureType;
 
 	/**
@@ -348,7 +356,9 @@ public:
 		ProvidesMimetype,
 		ProvidesFont,
 		ProvidesHardwareDriver,
-		ProvidesPostscriptDriver
+		ProvidesPostscriptDriver,
+		/* this always has to be at the end of the list */
+		LastProvidesType
 	} ProvidesType;
 
 	/**
@@ -414,7 +424,9 @@ public:
 		ErrorPackageFailedToConfigure,
 		ErrorPackageFailedToBuild,
 		ErrorPackageFailedToInstall,
-		ErrorPackageFailedToRemove
+		ErrorPackageFailedToRemove,
+		/* this always has to be at the end of the list */
+		LastErrorType
 	} ErrorType;
 
 	/**
@@ -436,6 +448,8 @@ public:
 		MessagePackageAlreadyInstalled,
 		MessageAutoremoveIgnored,
 		MessageRepoMetadataDownloadFailed,
+		/* this always has to be at the end of the list */
+		LastMessageType
 	} MessageType;
 
 	/**
@@ -463,6 +477,8 @@ public:
 		RestartSystem,
 		RestartSecuritySession,
 		RestartSecuritySystem,
+		/* this always has to be at the end of the list */
+		LastRestartType
 	} RestartType;
 
 	/**
@@ -472,7 +488,9 @@ public:
 		UnknownUpdateState,
 		UpdateStable,
 		UpdateUnstable,
-		UpdateTesting
+		UpdateTesting,
+		/* this always has to be at the end of the list */
+		LastUpdateState
 	} UpdateState;
 
 	/**
@@ -481,7 +499,9 @@ public:
 	typedef enum {
 		UnknownDistroUpgrade,
 		DistroUpgradeStable,
-		DistroUpgradeUnstable
+		DistroUpgradeUnstable,
+		/* this always has to be at the end of the list */
+		LastDistroUpgradeType
 	} DistroUpgradeType;
 
 	/**
@@ -502,7 +522,9 @@ public:
 		ErrorInvalidInput,
 		ErrorInvalidFile,
 		ErrorFunctionNotSupported,
-		ErrorDaemonUnreachable
+		ErrorDaemonUnreachable,
+		/* this always has to be at the end of the list */
+		LastDaemonError
 	} DaemonError;
 
 	/**
commit e794d925a8497dc2d962b169823b4f2146cf7443
Author: Slawomir Czarko <bugzilla.redhat.com at sklep.czarko.net>
Date:   Fri Feb 5 09:50:25 2010 +0000

    Fix up a typo that prevents compiling programs that use packagekit-qt with -pedantic-errors
    
    Signed-off-by: Richard Hughes <richard at hughsie.com>

diff --git a/lib/packagekit-qt/src/client.h b/lib/packagekit-qt/src/client.h
index dec379f..1904825 100644
--- a/lib/packagekit-qt/src/client.h
+++ b/lib/packagekit-qt/src/client.h
@@ -173,7 +173,7 @@ public:
 		FilterNotApplication	 = 0x2000000,
 		FilterLast		 = 0x4000000
 	} Filter;
-	Q_DECLARE_FLAGS(Filters, Filter);
+	Q_DECLARE_FLAGS(Filters, Filter)
 
 	/**
 	 * Returns the filters supported by the current backend
commit e203b0b432e029a294da36b3546b7df160891a8f
Author: Daniel Nicoletti <dantti85-pk at yahoo.com.br>
Date:   Thu Feb 4 17:32:25 2010 -0200

    pk-qt: moved the package enums to Enum class

diff --git a/lib/packagekit-qt/src/Makefile.am b/lib/packagekit-qt/src/Makefile.am
index 58aade6..611af25 100644
--- a/lib/packagekit-qt/src/Makefile.am
+++ b/lib/packagekit-qt/src/Makefile.am
@@ -22,17 +22,18 @@ libpackagekit_qt_include_HEADERS =				\
 	client.h						\
 	transaction.h						\
 	package.h						\
-	bitfield.h                      \
+	bitfield.h						\
+	enum.h							\
 	$(NULL)
 
 $(libpackagekit_qt_la_OBJECTS) :				\
 	client.moc						\
 	clientprivate.moc					\
 	daemonproxy.moc						\
-	package.moc						\
 	transaction.moc						\
 	transactionprivate.moc					\
 	transactionproxy.moc					\
+	enum.moc						\
 	$(NULL)
 
 libpackagekit_qt_la_SOURCES =					\
@@ -54,8 +55,10 @@ libpackagekit_qt_la_SOURCES =					\
 	package.cpp						\
 	util.h							\
 	util.cpp						\
-	bitfield.h                      \
-	bitfield.cpp                    \
+	bitfield.h						\
+	bitfield.cpp						\
+	enum.h							\
+	enum.cpp						\
 	$(NULL)
 
 libpackagekit_qt_la_LIBADD =					\
diff --git a/lib/packagekit-qt/src/enum.cpp b/lib/packagekit-qt/src/enum.cpp
new file mode 100644
index 0000000..610c869
--- /dev/null
+++ b/lib/packagekit-qt/src/enum.cpp
@@ -0,0 +1,30 @@
+/*
+ * This file is part of the QPackageKit project
+ * Copyright (C) 2008 Adrien Bustany <madcat at mymadcat.com>
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Library General Public
+ * License as published by the Free Software Foundation; either
+ * version 2 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Library General Public License for more details.
+ *
+ * You should have received a copy of the GNU Library General Public License
+ * along with this library; see the file COPYING.LIB. If not, write to
+ * the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
+ * Boston, MA 02110-1301, USA.
+ */
+
+#include "enum.h"
+#include "util.h"
+
+using namespace PackageKit;
+
+Enum::Enum() : QObject(NULL)
+{
+}
+
+#include "enum.moc"
diff --git a/lib/packagekit-qt/src/enum.h b/lib/packagekit-qt/src/enum.h
new file mode 100644
index 0000000..235e6bc
--- /dev/null
+++ b/lib/packagekit-qt/src/enum.h
@@ -0,0 +1,213 @@
+/*
+ * This file is part of the QPackageKit project
+ * Copyright (C) 2008 Adrien Bustany <madcat at mymadcat.com>
+ * Copyright (C) 2009 Daniel Nicoletti <dantti85-pk at yahoo.com.br>
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Library General Public
+ * License as published by the Free Software Foundation; either
+ * version 2 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Library General Public License for more details.
+ *
+ * You should have received a copy of the GNU Library General Public License
+ * along with this library; see the file COPYING.LIB. If not, write to
+ * the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
+ * Boston, MA 02110-1301, USA.
+ */
+
+#ifndef ENUM_H
+#define ENUM_H
+
+#include <QtCore>
+
+namespace PackageKit {
+
+/**
+ * \class Package package.h Package
+ * \author Adrien Bustany <madcat at mymadcat.com>
+ *
+ * \brief Represents a software package
+ *
+ * This class represents a software package.
+ *
+ * \note All Package objects should be deleted by the user.
+ */
+class Enum : public QObject
+{
+	Q_OBJECT
+	Q_ENUMS(PackageInfo)
+	Q_ENUMS(License)
+
+public:
+	/**
+	 * Describes the state of a package
+	 */
+	typedef enum {
+		UnknownInfo,
+		InfoInstalled,
+		InfoAvailable,
+		InfoLow,
+		InfoEnhancement,
+		InfoNormal,
+		InfoBugfix,
+		InfoImportant,
+		InfoSecurity,
+		InfoBlocked,
+		InfoDownloading,
+		InfoUpdating,
+		InfoInstalling,
+		InfoRemoving,
+		InfoCleanup,
+		InfoObsoleting,
+		InfoCollectionInstalled,
+		InfoCollectionAvailable,
+		InfoFinished,
+		InfoReinstalling,
+		InfoDowngrading,
+		InfoPreparing,
+		InfoDecompressing
+	} Info;
+
+	/**
+	 * Describes a package's license
+	 */
+	typedef enum {
+		UnknownLicense,
+		LicenseGlide,
+		LicenseAfl,
+		LicenseAmpasBsd,
+		LicenseAmazonDsl,
+		LicenseAdobe,
+		LicenseAgplv1,
+		LicenseAgplv3,
+		LicenseAsl1Dot0,
+		LicenseAsl1Dot1,
+		LicenseAsl2Dot0,
+		LicenseApsl2Dot0,
+		LicenseArtisticClarified,
+		LicenseArtistic2Dot0,
+		LicenseArl,
+		LicenseBittorrent,
+		LicenseBoost,
+		LicenseBsdWithAdvertising,
+		LicenseBsd,
+		LicenseCecill,
+		LicenseCddl,
+		LicenseCpl,
+		LicenseCondor,
+		LicenseCopyrightOnly,
+		LicenseCryptix,
+		LicenseCrystalStacker,
+		LicenseDoc,
+		LicenseWtfpl,
+		LicenseEpl,
+		LicenseEcos,
+		LicenseEfl2Dot0,
+		LicenseEu_datagrid,
+		LicenseLgplv2WithExceptions,
+		LicenseFtl,
+		LicenseGiftware,
+		LicenseGplv2,
+		LicenseGplv2WithExceptions,
+		LicenseGplv2PlusWithExceptions,
+		LicenseGplv3,
+		LicenseGplv3WithExceptions,
+		LicenseGplv3PlusWithExceptions,
+		LicenseLgplv2,
+		LicenseLgplv3,
+		LicenseGnuplot,
+		LicenseIbm,
+		LicenseImatix,
+		LicenseImagemagick,
+		LicenseImlib2,
+		LicenseIjg,
+		LicenseIntel_acpi,
+		LicenseInterbase,
+		LicenseIsc,
+		LicenseJabber,
+		LicenseJasper,
+		LicenseLppl,
+		LicenseLibtiff,
+		LicenseLpl,
+		LicenseMecabIpadic,
+		LicenseMit,
+		LicenseMitWithAdvertising,
+		LicenseMplv1Dot0,
+		LicenseMplv1Dot1,
+		LicenseNcsa,
+		LicenseNgpl,
+		LicenseNosl,
+		LicenseNetcdf,
+		LicenseNetscape,
+		LicenseNokia,
+		LicenseOpenldap,
+		LicenseOpenpbs,
+		LicenseOsl1Dot0,
+		LicenseOsl1Dot1,
+		LicenseOsl2Dot0,
+		LicenseOsl3Dot0,
+		LicenseOpenssl,
+		LicenseOreilly,
+		LicensePhorum,
+		LicensePhp,
+		LicensePublicDomain,
+		LicensePython,
+		LicenseQpl,
+		LicenseRpsl,
+		LicenseRuby,
+		LicenseSendmail,
+		LicenseSleepycat,
+		LicenseSlib,
+		LicenseSissl,
+		LicenseSpl,
+		LicenseTcl,
+		LicenseUcd,
+		LicenseVim,
+		LicenseVnlsl,
+		LicenseVsl,
+		LicenseW3c,
+		LicenseWxwidgets,
+		LicenseXinetd,
+		LicenseZend,
+		LicenseZplv1Dot0,
+		LicenseZplv2Dot0,
+		LicenseZplv2Dot1,
+		LicenseZlib,
+		LicenseZlibWithAck,
+		LicenseCdl,
+		LicenseFbsddl,
+		LicenseGfdl,
+		LicenseIeee,
+		LicenseOfsfdl,
+		LicenseOpenPublication,
+		LicenseCcBy,
+		LicenseCcBySa,
+		LicenseCcByNd,
+		LicenseDsl,
+		LicenseFreeArt,
+		LicenseOfl,
+		LicenseUtopia,
+		LicenseArphic,
+		LicenseBaekmuk,
+		LicenseBitstreamVera,
+		LicenseLucida,
+		LicenseMplus,
+		LicenseStix,
+		LicenseXano,
+		LicenseVostrom,
+		LicenseXerox,
+		LicenseRicebsd,
+		LicenseQhull
+	} License;
+
+	Enum();
+};
+
+} // End namespace PackageKit
+
+#endif
+
diff --git a/lib/packagekit-qt/src/package.cpp b/lib/packagekit-qt/src/package.cpp
index f5a78f6..1134b32 100644
--- a/lib/packagekit-qt/src/package.cpp
+++ b/lib/packagekit-qt/src/package.cpp
@@ -93,12 +93,13 @@ public:
 	QString arch;
 	QString data;
 	QString summary;
-	Package::State state;
+	Enum::Info info;
 	Package::Details* details;
 	QString iconPath;
 };
 
-Package::Package(const QString& packageId, const QString& state, const QString& summary) : QObject(NULL), d(new Private)
+Package::Package(const QString& packageId, const QString& info, const QString& summary)
+ : d(new Private)
 {
 	d->id = packageId;
 
@@ -111,7 +112,7 @@ Package::Package(const QString& packageId, const QString& state, const QString&
 		d->data = tokens.at(3);
 	}
 
-	d->state = (State)Util::enumFromString<Package>(state, "State", "State");
+	d->info = (Enum::Info)Util::enumFromString<Enum>(info, "Info", "Info");
 	d->summary = summary;
 	d->details = NULL;
 	d->iconPath = QString ();
@@ -119,8 +120,9 @@ Package::Package(const QString& packageId, const QString& state, const QString&
 
 Package::~Package()
 {
-	if(hasDetails())
+	if (hasDetails())
 		delete d->details;
+	delete d;
 }
 
 QString Package::id() const
@@ -153,9 +155,9 @@ QString Package::summary() const
 	return d->summary;
 }
 
-Package::State Package::state() const
+Enum::Info Package::info() const
 {
-	return d->state;
+	return d->info;
 }
 
 bool Package::hasDetails() const
@@ -173,6 +175,12 @@ void Package::setDetails(Package::Details* det)
 	d->details = det;
 }
 
+void Package::setInfoSummary(const QString& info, const QString& summary)
+{
+	d->info = (Enum::Info)Util::enumFromString<Enum>(info, "Info", "Info");
+	d->summary = summary;
+}
+
 QString Package::iconPath ()
 {
 	if (d->iconPath.isNull ()) {
diff --git a/lib/packagekit-qt/src/package.h b/lib/packagekit-qt/src/package.h
index 077345a..5aa95ed 100644
--- a/lib/packagekit-qt/src/package.h
+++ b/lib/packagekit-qt/src/package.h
@@ -23,6 +23,7 @@
 
 #include <QtCore>
 #include "client.h"
+#include "enum.h"
 
 namespace PackageKit {
 
@@ -39,8 +40,6 @@ namespace PackageKit {
 class Package : public QObject
 {
 	Q_OBJECT
-	Q_ENUMS(State)
-	Q_ENUMS(License)
 
 public:
 	/**
@@ -81,169 +80,9 @@ public:
 	QString summary() const;
 
 	/**
-	 * Describes the state of a package
+	 * Returns the package's info
 	 */
-	typedef enum {
-		UnknownState,
-		StateInstalled,
-		StateAvailable,
-		StateLow,
-		StateEnhancement,
-		StateNormal,
-		StateBugfix,
-		StateImportant,
-		StateSecurity,
-		StateBlocked,
-		StateDownloading,
-		StateUpdating,
-		StateInstalling,
-		StateRemoving,
-		StateCleanup,
-		StateObsoleting,
-		StateCollectionInstalled,
-		StateCollectionAvailable,
-		StateFinished,
-		StateReinstalling,
-		StateDowngrading,
-		StatePreparing,
-		StateDecompressing
-	} State;
-	/**
-	 * Returns the package's state
-	 */
-	State state() const;
-
-	/**
-	 * Describes a package's license
-	 */
-	typedef enum {
-		UnknownLicense,
-		LicenseGlide,
-		LicenseAfl,
-		LicenseAmpasBsd,
-		LicenseAmazonDsl,
-		LicenseAdobe,
-		LicenseAgplv1,
-		LicenseAgplv3,
-		LicenseAsl1Dot0,
-		LicenseAsl1Dot1,
-		LicenseAsl2Dot0,
-		LicenseApsl2Dot0,
-		LicenseArtisticClarified,
-		LicenseArtistic2Dot0,
-		LicenseArl,
-		LicenseBittorrent,
-		LicenseBoost,
-		LicenseBsdWithAdvertising,
-		LicenseBsd,
-		LicenseCecill,
-		LicenseCddl,
-		LicenseCpl,
-		LicenseCondor,
-		LicenseCopyrightOnly,
-		LicenseCryptix,
-		LicenseCrystalStacker,
-		LicenseDoc,
-		LicenseWtfpl,
-		LicenseEpl,
-		LicenseEcos,
-		LicenseEfl2Dot0,
-		LicenseEu_datagrid,
-		LicenseLgplv2WithExceptions,
-		LicenseFtl,
-		LicenseGiftware,
-		LicenseGplv2,
-		LicenseGplv2WithExceptions,
-		LicenseGplv2PlusWithExceptions,
-		LicenseGplv3,
-		LicenseGplv3WithExceptions,
-		LicenseGplv3PlusWithExceptions,
-		LicenseLgplv2,
-		LicenseLgplv3,
-		LicenseGnuplot,
-		LicenseIbm,
-		LicenseImatix,
-		LicenseImagemagick,
-		LicenseImlib2,
-		LicenseIjg,
-		LicenseIntel_acpi,
-		LicenseInterbase,
-		LicenseIsc,
-		LicenseJabber,
-		LicenseJasper,
-		LicenseLppl,
-		LicenseLibtiff,
-		LicenseLpl,
-		LicenseMecabIpadic,
-		LicenseMit,
-		LicenseMitWithAdvertising,
-		LicenseMplv1Dot0,
-		LicenseMplv1Dot1,
-		LicenseNcsa,
-		LicenseNgpl,
-		LicenseNosl,
-		LicenseNetcdf,
-		LicenseNetscape,
-		LicenseNokia,
-		LicenseOpenldap,
-		LicenseOpenpbs,
-		LicenseOsl1Dot0,
-		LicenseOsl1Dot1,
-		LicenseOsl2Dot0,
-		LicenseOsl3Dot0,
-		LicenseOpenssl,
-		LicenseOreilly,
-		LicensePhorum,
-		LicensePhp,
-		LicensePublicDomain,
-		LicensePython,
-		LicenseQpl,
-		LicenseRpsl,
-		LicenseRuby,
-		LicenseSendmail,
-		LicenseSleepycat,
-		LicenseSlib,
-		LicenseSissl,
-		LicenseSpl,
-		LicenseTcl,
-		LicenseUcd,
-		LicenseVim,
-		LicenseVnlsl,
-		LicenseVsl,
-		LicenseW3c,
-		LicenseWxwidgets,
-		LicenseXinetd,
-		LicenseZend,
-		LicenseZplv1Dot0,
-		LicenseZplv2Dot0,
-		LicenseZplv2Dot1,
-		LicenseZlib,
-		LicenseZlibWithAck,
-		LicenseCdl,
-		LicenseFbsddl,
-		LicenseGfdl,
-		LicenseIeee,
-		LicenseOfsfdl,
-		LicenseOpenPublication,
-		LicenseCcBy,
-		LicenseCcBySa,
-		LicenseCcByNd,
-		LicenseDsl,
-		LicenseFreeArt,
-		LicenseOfl,
-		LicenseUtopia,
-		LicenseArphic,
-		LicenseBaekmuk,
-		LicenseBitstreamVera,
-		LicenseLucida,
-		LicenseMplus,
-		LicenseStix,
-		LicenseXano,
-		LicenseVostrom,
-		LicenseXerox,
-		LicenseRicebsd,
-		LicenseQhull
-	} License;
+	Enum::Info info() const;
 
 	/**
 	 * Holds additional details about a package
@@ -325,8 +164,9 @@ private:
 	friend class TransactionPrivate;
 	friend class Details;
 	friend class Client;
-	Package(const QString& packageId, const QString& state = QString(), const QString& summary = QString());
+	Package(const QString& packageId, const QString& info = QString(), const QString& summary = QString());
 	void setDetails(Details* det);
+	void setInfoSummary(const QString& info, const QString& summary);
 	class Private;
 	Private* d;
 };
commit 2d1d04799b8c640b00b91681aaa779c5656ba8f7
Author: Daniel Nicoletti <dantti85-pk at yahoo.com.br>
Date:   Thu Feb 4 17:17:10 2010 -0200

    Changed the planned-api-changes for pk 6.0

diff --git a/docs/planned-api-changes.txt b/docs/planned-api-changes.txt
index 5fb5695..2c8bf77 100644
--- a/docs/planned-api-changes.txt
+++ b/docs/planned-api-changes.txt
@@ -2,3 +2,27 @@ Make the transaction history have per-file hints, so we can fix stuff like
 http://bugs.freedesktop.org/show_bug.cgi?id=23904 and display deps differently
 to explicit files.
 
+Remove setLocale from Transaction interface
+SimulateRemovePackages should have autoremove
+
+installpkgs, update packages should have remove_required
+
+add properties to Transaction interface:
+ * bytesDownloaded(u)
+ * bytesTotal(u)
+ where bytesTotal will be the Full download
+ and bytesDownload is how much was already downloaded,
+ this way we can easily get how much bytes we need to
+ complete our task (total - downloaded)
+*** adding this as properties allow us to use it in simulate*
+    methods to show exactly how much bytes we need and when
+    a transaction is running how much was downloaded.
+
+Transaction::Details
+ * If the above (bytes*) properties were added,
+   change the size to be always the file size
+   (and not 0 if the package is already downloaded
+   not installed)
+ * Add popularity from 0 to 10 where 11 is unknown
+ * Add a stars filter >1stars >2stars >3stars >4 stars
+ 
\ No newline at end of file
commit 5438d9e815d15264cf4be93eb9571ef4a56bd0c5
Author: Richard Hughes <richard at hughsie.com>
Date:   Thu Feb 4 12:28:43 2010 +0000

    Add a pk_backend_set_speed() helper function

diff --git a/src/pk-backend.c b/src/pk-backend.c
index 8415d97..b508d94 100644
--- a/src/pk-backend.c
+++ b/src/pk-backend.c
@@ -702,6 +702,33 @@ pk_backend_set_percentage (PkBackend *backend, guint percentage)
 }
 
 /**
+ * pk_backend_set_speed:
+ **/
+gboolean
+pk_backend_set_speed (PkBackend *backend, guint speed)
+{
+	g_return_val_if_fail (PK_IS_BACKEND (backend), FALSE);
+	g_return_val_if_fail (backend->priv->locked != FALSE, FALSE);
+
+	/* have we already set an error? */
+	if (backend->priv->set_error) {
+		egg_warning ("already set error, cannot process: speed %i", speed);
+		return FALSE;
+	}
+
+	/* set the same twice? */
+	if (backend->priv->speed == speed) {
+		egg_debug ("duplicate set of %i", speed);
+		return FALSE;
+	}
+
+	/* set new value */
+	backend->priv->speed = speed;
+	g_object_notify (G_OBJECT (backend), "speed");
+	return TRUE;
+}
+
+/**
  * pk_backend_get_runtime:
  *
  * Returns time running in ms
diff --git a/src/pk-backend.h b/src/pk-backend.h
index 71d2e4c..6bb3b29 100644
--- a/src/pk-backend.h
+++ b/src/pk-backend.h
@@ -61,6 +61,8 @@ gboolean	 pk_backend_set_percentage		(PkBackend	*backend,
 							 guint		 percentage);
 gboolean	 pk_backend_set_sub_percentage		(PkBackend	*backend,
 							 guint		 percentage);
+gboolean	 pk_backend_set_speed			(PkBackend	*backend,
+							 guint		 speed);
 gboolean	 pk_backend_set_exit_code		(PkBackend	*backend,
 							 PkExitEnum	 exit);
 gboolean	 pk_backend_set_transaction_data	(PkBackend	*backend,
commit 9641b42e38c5f642cc7d52645bdbc3d91302e0b0
Author: Richard Hughes <richard at hughsie.com>
Date:   Thu Feb 4 11:46:18 2010 +0000

    Add the eula-required python method helper

diff --git a/lib/python/packagekit/backend.py b/lib/python/packagekit/backend.py
index 9496bda..113a978 100644
--- a/lib/python/packagekit/backend.py
+++ b/lib/python/packagekit/backend.py
@@ -299,6 +299,19 @@ class PackageKitBaseBackend:
             )
         sys.stdout.flush()
 
+    def eula_required(self, eula_id, package_id, vendor_name, license_agreement):
+        '''
+        send 'eula-required' signal:
+        @param eula_id:         Id of the EULA
+        @param package_id:      Id of the package needing a signature
+        @param vendor_name:     Name of the vendor that wrote the EULA
+        @param license_agreement: The license text
+        '''
+        print "eula-required\t%s\t%s\t%s\t%s" % (
+            eula_id, package_id, vendor_name, license_agreement
+            )
+        sys.stdout.flush()
+
 #
 # Backend Action Methods
 #
diff --git a/src/pk-backend-spawn.c b/src/pk-backend-spawn.c
index 38a6daa..ad5ac78 100644
--- a/src/pk-backend-spawn.c
+++ b/src/pk-backend-spawn.c
@@ -394,6 +394,39 @@ pk_backend_spawn_parse_stdout (PkBackendSpawn *backend_spawn, const gchar *line)
 							  sections[2], sections[3], sections[4],
 							  sections[5], sections[6], sections[7], sig_type);
 		goto out;
+
+	} else if (g_strcmp0 (command, "eula-required") == 0) {
+
+		if (size != 5) {
+			egg_warning ("invalid command'%s', size %i", command, size);
+			ret = FALSE;
+			goto out;
+		}
+
+		if (egg_strzero (sections[1])) {
+			pk_backend_message (backend_spawn->priv->backend, PK_MESSAGE_ENUM_BACKEND_ERROR,
+					    "eula_id blank, and hence ignored: '%s'", sections[1]);
+			ret = FALSE;
+			goto out;
+		}
+
+		if (egg_strzero (sections[2])) {
+			pk_backend_message (backend_spawn->priv->backend, PK_MESSAGE_ENUM_BACKEND_ERROR,
+					    "package_id blank, and hence ignored: '%s'", sections[2]);
+			ret = FALSE;
+			goto out;
+		}
+
+		if (egg_strzero (sections[4])) {
+			pk_backend_message (backend_spawn->priv->backend, PK_MESSAGE_ENUM_BACKEND_ERROR,
+					    "agreement name blank, and hence ignored: '%s'", sections[4]);
+			ret = FALSE;
+			goto out;
+		}
+
+		ret = pk_backend_eula_required (backend_spawn->priv->backend, sections[1], sections[2], sections[3], sections[4]);
+		goto out;
+
 	} else if (g_strcmp0 (command, "media-change-required") == 0) {
 
 		if (size != 4) {
commit cb622dc7f88807d3be8fdd5c140e851dc7d7de33
Author: Richard Hughes <richard at hughsie.com>
Date:   Thu Feb 4 10:11:50 2010 +0000

    Update the list of free licences from the Fedora wiki

diff --git a/lib/packagekit-glib2/pk-enum.c b/lib/packagekit-glib2/pk-enum.c
index 2fa16fa..a443edb 100644
--- a/lib/packagekit-glib2/pk-enum.c
+++ b/lib/packagekit-glib2/pk-enum.c
@@ -373,6 +373,7 @@ static const PkEnumMatch enum_free_licenses[] = {
 	{PK_LICENSE_ENUM_ADSL,			"ADSL"},
 	{PK_LICENSE_ENUM_AFL,			"AFL"},
 	{PK_LICENSE_ENUM_AGPLV1,		"AGPLv1"},
+	{PK_LICENSE_ENUM_AMDPLPA,		"AMDPLPA"},
 	{PK_LICENSE_ENUM_AMPAS_BSD,		"AMPAS BSD"},
 	{PK_LICENSE_ENUM_APSL_2_DOT_0,		"APSL 2.0"},
 	{PK_LICENSE_ENUM_ARL,			"ARL"},
@@ -386,6 +387,7 @@ static const PkEnumMatch enum_free_licenses[] = {
 	{PK_LICENSE_ENUM_BITTORRENT,		"BitTorrent"},
 	{PK_LICENSE_ENUM_BOOST,			"Boost"},
 	{PK_LICENSE_ENUM_BSD,			"BSD"},
+	{PK_LICENSE_ENUM_BSD_PROTECTION,	"BSD Protection"},
 	{PK_LICENSE_ENUM_BSD_WITH_ADVERTISING,	"BSD with advertising"},
 	{PK_LICENSE_ENUM_CATOSL,		"CATOSL"},
 	{PK_LICENSE_ENUM_CC0,			"CC0"},
@@ -412,6 +414,7 @@ static const PkEnumMatch enum_free_licenses[] = {
 	{PK_LICENSE_ENUM_ENTESSA,		"Entessa"},
 	{PK_LICENSE_ENUM_EPL,			"EPL"},
 	{PK_LICENSE_ENUM_ERPL,			"ERPL"},
+	{PK_LICENSE_ENUM_EUPL_1_DOT_1,		"EUPL 1.1"},
 	{PK_LICENSE_ENUM_EUROSYM,		"Eurosym"},
 	{PK_LICENSE_ENUM_EU_DATAGRID,		"EU Datagrid"},
 	{PK_LICENSE_ENUM_FAIR,			"Fair"},
@@ -503,11 +506,13 @@ static const PkEnumMatch enum_free_licenses[] = {
 	{PK_LICENSE_ENUM_PHP,			"PHP"},
 	{PK_LICENSE_ENUM_PLEXUS,		"Plexus"},
 	{PK_LICENSE_ENUM_PSUTILS,		"psutils"},
+	{PK_LICENSE_ENUM_PTFL,			"PTFL"},
 	{PK_LICENSE_ENUM_PUBLIC_DOMAIN,		"Public Domain"},
 	{PK_LICENSE_ENUM_PUBLIC_USE,		"Public Use"},
 	{PK_LICENSE_ENUM_PYTHON,		"Python"},
 	{PK_LICENSE_ENUM_QHULL,			"Qhull"},
 	{PK_LICENSE_ENUM_QPL,			"QPL"},
+	{PK_LICENSE_ENUM_RDISC,			"Rdisc"},
 	{PK_LICENSE_ENUM_RICEBSD,		"RiceBSD"},
 	{PK_LICENSE_ENUM_RPSL,			"RPSL"},
 	{PK_LICENSE_ENUM_RUBY,			"Ruby"},
@@ -523,6 +528,7 @@ static const PkEnumMatch enum_free_licenses[] = {
 	{PK_LICENSE_ENUM_STIX,			"STIX"},
 	{PK_LICENSE_ENUM_TCL,			"TCL"},
 	{PK_LICENSE_ENUM_TMATE,			"TMate"},
+	{PK_LICENSE_ENUM_TOSL,			"TOSL"},
 	{PK_LICENSE_ENUM_TPL,			"TPL"},
 	{PK_LICENSE_ENUM_UCD,			"UCD"},
 	{PK_LICENSE_ENUM_VIM,			"Vim"},
diff --git a/lib/packagekit-glib2/pk-enum.h b/lib/packagekit-glib2/pk-enum.h
index 056b308..338cbc7 100644
--- a/lib/packagekit-glib2/pk-enum.h
+++ b/lib/packagekit-glib2/pk-enum.h
@@ -498,6 +498,7 @@ typedef enum {
 	PK_LICENSE_ENUM_ADSL,
 	PK_LICENSE_ENUM_AFL,
 	PK_LICENSE_ENUM_AGPLV1,
+	PK_LICENSE_ENUM_AMDPLPA,
 	PK_LICENSE_ENUM_AMPAS_BSD,
 	PK_LICENSE_ENUM_APSL_2_DOT_0,
 	PK_LICENSE_ENUM_ARL,
@@ -511,6 +512,7 @@ typedef enum {
 	PK_LICENSE_ENUM_BITTORRENT,
 	PK_LICENSE_ENUM_BOOST,
 	PK_LICENSE_ENUM_BSD,
+	PK_LICENSE_ENUM_BSD_PROTECTION,
 	PK_LICENSE_ENUM_BSD_WITH_ADVERTISING,
 	PK_LICENSE_ENUM_CATOSL,
 	PK_LICENSE_ENUM_CC0,
@@ -537,6 +539,7 @@ typedef enum {
 	PK_LICENSE_ENUM_ENTESSA,
 	PK_LICENSE_ENUM_EPL,
 	PK_LICENSE_ENUM_ERPL,
+	PK_LICENSE_ENUM_EUPL_1_DOT_1,
 	PK_LICENSE_ENUM_EUROSYM,
 	PK_LICENSE_ENUM_EU_DATAGRID,
 	PK_LICENSE_ENUM_FAIR,
@@ -628,11 +631,13 @@ typedef enum {
 	PK_LICENSE_ENUM_PHP,
 	PK_LICENSE_ENUM_PLEXUS,
 	PK_LICENSE_ENUM_PSUTILS,
+	PK_LICENSE_ENUM_PTFL,
 	PK_LICENSE_ENUM_PUBLIC_DOMAIN,
 	PK_LICENSE_ENUM_PUBLIC_USE,
 	PK_LICENSE_ENUM_PYTHON,
 	PK_LICENSE_ENUM_QHULL,
 	PK_LICENSE_ENUM_QPL,
+	PK_LICENSE_ENUM_RDISC,
 	PK_LICENSE_ENUM_RICEBSD,
 	PK_LICENSE_ENUM_RPSL,
 	PK_LICENSE_ENUM_RUBY,
@@ -648,6 +653,7 @@ typedef enum {
 	PK_LICENSE_ENUM_STIX,
 	PK_LICENSE_ENUM_TCL,
 	PK_LICENSE_ENUM_TMATE,
+	PK_LICENSE_ENUM_TOSL,
 	PK_LICENSE_ENUM_TPL,
 	PK_LICENSE_ENUM_UCD,
 	PK_LICENSE_ENUM_VIM,
commit 5b2a3aae94b48621f5b620ebedc3ccf2fa9b88eb
Merge: d57452f... 7b4671c...
Author: Scott Reeves <sreeves at novell.com>
Date:   Wed Feb 3 16:02:51 2010 -0700

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

commit d57452f25a00fc2fd55f3f6cb71ae097098554ff
Author: Scott Reeves <sreeves at novell.com>
Date:   Wed Feb 3 15:16:28 2010 -0700

    zypp: change policy to download first

diff --git a/backends/zypp/zypp-utils.cpp b/backends/zypp/zypp-utils.cpp
index 1adf9cb..d17a5af 100644
--- a/backends/zypp/zypp-utils.cpp
+++ b/backends/zypp/zypp-utils.cpp
@@ -795,6 +795,7 @@ zypp_perform_execution (PkBackend *backend, PerformType type, gboolean force)
                 // Perform the installation
                 zypp::ZYppCommitPolicy policy;
                 policy.restrictToMedia (0);	// 0 - install all packages regardless to media
+				policy.downloadMode (zypp::DownloadInHeaps);
 
                 zypp::ZYppCommitResult result = zypp->commit (policy);
 
diff --git a/configure.ac b/configure.ac
index 0c00318..3ff5362 100644
--- a/configure.ac
+++ b/configure.ac
@@ -742,7 +742,7 @@ if test x$enable_poldek = xyes; then
 fi
 
 if test x$enable_zypp = xyes; then
-	PKG_CHECK_MODULES(ZYPP, libzypp >= 5.20.0)
+	PKG_CHECK_MODULES(ZYPP, libzypp >= 6.16.0)
 	AC_SUBST(ZYPP_CFLAGS)
 	AC_SUBST(ZYPP_LIBS)
 fi
commit 7b4671c1dc3679600fcb9d0c0ce12ad96104b8ef
Author: Fabio Erculiani <lxnay at sabayon.org>
Date:   Wed Feb 3 22:25:48 2010 +0100

    entropy: disable debug logging by default

diff --git a/backends/entropy/entropyBackend.py b/backends/entropy/entropyBackend.py
index c54797b..fecd734 100644
--- a/backends/entropy/entropyBackend.py
+++ b/backends/entropy/entropyBackend.py
@@ -64,7 +64,7 @@ from entropy.fetchers import UrlFetcher
 
 import entropy.tools
 
-PK_DEBUG = True
+PK_DEBUG = False
 
 class PackageKitEntropyMixin(object):
 
commit 3430d160a6a68a096d50a2618b933aeb74e03faa
Author: Richard Hughes <richard at hughsie.com>
Date:   Wed Feb 3 14:56:43 2010 +0000

    trivial: add a list of planned API changes in 0.6.x

diff --git a/docs/planned-api-changes.txt b/docs/planned-api-changes.txt
new file mode 100644
index 0000000..5fb5695
--- /dev/null
+++ b/docs/planned-api-changes.txt
@@ -0,0 +1,4 @@
+Make the transaction history have per-file hints, so we can fix stuff like
+http://bugs.freedesktop.org/show_bug.cgi?id=23904 and display deps differently
+to explicit files.
+
commit 3c3a272d2d79bb9252d401eab446d8b8e4d560c8
Author: Richard Hughes <richard at hughsie.com>
Date:   Wed Feb 3 14:56:05 2010 +0000

    trivial: update some gitignore files

diff --git a/.gitignore b/.gitignore
index 02af524..65250a6 100644
--- a/.gitignore
+++ b/.gitignore
@@ -61,4 +61,6 @@ packagekit.types
 *.cache
 *.anjuta
 ChangeLog
+.deps
+.acb
 
diff --git a/lib/packagekit-glib2/.gitignore b/lib/packagekit-glib2/.gitignore
index 0ed76de..806b356 100644
--- a/lib/packagekit-glib2/.gitignore
+++ b/lib/packagekit-glib2/.gitignore
@@ -11,4 +11,6 @@ pk-self-test
 *.db
 *.sh
 pk-version.h
+*.gir
+*.typelib
 
commit faa3aefe0588830504e5e63250deea0a3a5e9c63
Author: Fabio Erculiani <lxnay at sabayon.org>
Date:   Wed Feb 3 15:06:52 2010 +0100

    entropy: add Entropy PackageKit backend

diff --git a/backends/Makefile.am b/backends/Makefile.am
index 63d33e1..7e0439a 100644
--- a/backends/Makefile.am
+++ b/backends/Makefile.am
@@ -24,6 +24,10 @@ if BACKEND_TYPE_DUMMY
 SUBDIRS += dummy
 endif
 
+if BACKEND_TYPE_ENTROPY
+SUBDIRS += entropy
+endif
+
 if BACKEND_TYPE_OPKG
 SUBDIRS += opkg
 endif
diff --git a/backends/entropy/Makefile.am b/backends/entropy/Makefile.am
new file mode 100644
index 0000000..2078c4e
--- /dev/null
+++ b/backends/entropy/Makefile.am
@@ -0,0 +1,16 @@
+helperdir = $(datadir)/PackageKit/helpers/entropy
+dist_helper_DATA = entropyBackend.py
+
+plugindir = $(PK_PLUGIN_DIR)
+plugin_LTLIBRARIES = libpk_backend_entropy.la
+libpk_backend_entropy_la_SOURCES = pk-backend-entropy.c
+libpk_backend_entropy_la_LIBADD = $(PK_PLUGIN_LIBS)
+libpk_backend_entropy_la_LDFLAGS = -module -avoid-version
+libpk_backend_entropy_la_CFLAGS = $(PK_PLUGIN_CFLAGS) $(WARNINGFLAGS_C)
+
+install-data-hook:
+	chmod a+rx $(DESTDIR)$(helperdir)/*.py
+
+clean-local :
+	rm -f *~
+	rm -f *.pyc
diff --git a/backends/entropy/TODO b/backends/entropy/TODO
new file mode 100644
index 0000000..06fe0e2
--- /dev/null
+++ b/backends/entropy/TODO
@@ -0,0 +1,34 @@
+Entropy PackageKit backend developers' TODO:
+
+    - add support for FILTER_NOT_VISIBLE, FILTER_NOT_DEVELOPMENT,
+        FILTER_DEVELOPMENT, FILTER_VISIBLE
+    - add get_mime_types, install_files, simulate_* support, repo_set_data
+    - bind get_distro_upgrades to branch hop?
+    - sys-apps/entropy is a syspkg
+    - messages? how push output to stdout?
+    - license dialog??
+
+What is currently implemented:
+    Y get-actions
+    Y get-groups
+    Y get-filters
+    Y get-transactions
+    Y get-time
+    Y search [name|details|group|file] [data]
+    Y install [packages]
+    Y remove [package]
+    Y update <package>
+    Y update-system
+    Y refresh
+    Y resolve [package]
+    Y get-updates
+    Y get-depends [package]
+    Y get-requires [package]
+    Y get-details [package]
+    Y get-files [package]
+    Y get-update-detail [package]
+    Y get-packages
+    Y repo-list
+    Y repo-enable [repo_id]
+    Y repo-disable [repo_id]
+
diff --git a/backends/entropy/entropyBackend.py b/backends/entropy/entropyBackend.py
new file mode 100644
index 0000000..c54797b
--- /dev/null
+++ b/backends/entropy/entropyBackend.py
@@ -0,0 +1,1536 @@
+#!/usr/bin/python2
+# -*- coding: utf-8 -*-
+#
+#
+# Copyright (C) 2009 Mounir Lamouri (volkmar) <mounir.lamouri at gmail.com>
+# Copyright (C) 2010 Fabio Erculiani (lxnay) <lxnay at sabayon.org>
+#
+# 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.
+
+import os
+import sys
+import signal
+import time
+import traceback
+
+from packagekit.backend import PackageKitBaseBackend, \
+    ERROR_PACKAGE_ID_INVALID, ERROR_REPO_NOT_FOUND, ERROR_INTERNAL_ERROR, \
+    ERROR_CANNOT_DISABLE_REPOSITORY, ERROR_PACKAGE_FAILED_TO_INSTALL, \
+    ERROR_DEP_RESOLUTION_FAILED, ERROR_PACKAGE_FAILED_TO_CONFIGURE, \
+    ERROR_PACKAGE_FAILED_TO_REMOVE, ERROR_GROUP_LIST_INVALID, \
+    ERROR_UPDATE_NOT_FOUND, ERROR_REPO_CONFIGURATION_ERROR, \
+    ERROR_PACKAGE_NOT_FOUND, ERROR_MISSING_GPG_SIGNATURE, FILTER_INSTALLED, \
+    FILTER_NOT_INSTALLED, ERROR_GROUP_LIST_INVALID, FILTER_NOT_DEVELOPMENT, \
+    FILTER_FREE, GROUP_ACCESSIBILITY, GROUP_PROGRAMMING, GROUP_GAMES, \
+    GROUP_DESKTOP_GNOME, GROUP_DESKTOP_KDE, GROUP_DESKTOP_OTHER, \
+    GROUP_MULTIMEDIA, GROUP_NETWORK, GROUP_OFFICE, GROUP_SCIENCE, \
+    GROUP_SYSTEM, GROUP_SECURITY, GROUP_OTHER, GROUP_DESKTOP_XFCE, \
+    GROUP_UNKNOWN, INFO_IMPORTANT, INFO_NORMAL, INFO_DOWNLOADING, \
+    INFO_INSTALLED, \
+    INFO_AVAILABLE, get_package_id, split_package_id, MESSAGE_UNKNOWN, \
+    MESSAGE_AUTOREMOVE_IGNORED, MESSAGE_CONFIG_FILES_CHANGED, STATUS_INFO, \
+    MESSAGE_COULD_NOT_FIND_PACKAGE, MESSAGE_REPO_METADATA_DOWNLOAD_FAILED, \
+    STATUS_QUERY, STATUS_DEP_RESOLVE, STATUS_REMOVE, STATUS_DOWNLOAD, \
+    STATUS_INSTALL, STATUS_RUNNING, STATUS_REFRESH_CACHE, \
+    UPDATE_STATE_TESTING, UPDATE_STATE_STABLE
+
+#from packagekit.progress import *
+from packagekit.package import PackagekitPackage
+
+sys.path.insert(0, '/usr/lib/entropy/libraries')
+
+from entropy.i18n import _, _LOCALE
+from entropy.const import etpConst, const_convert_to_rawstring, \
+    const_convert_to_unicode
+from entropy.client.interfaces import Client
+from entropy.core.settings.base import SystemSettings
+from entropy.misc import LogFile
+from entropy.exceptions import SystemDatabaseError
+from entropy.fetchers import UrlFetcher
+
+import entropy.tools
+
+PK_DEBUG = True
+
+class PackageKitEntropyMixin(object):
+
+    INST_PKGS_REPO_ID = "installed"
+
+    """
+    Entropy relaxed code can be found in this Mixin class.
+    The aim is to separate PackageKit code and reimplemented methods from
+    Entropy-only protected methods.
+    """
+
+    @staticmethod
+    def get_percentage(count, max_count):
+        """
+        Prepare percentage value used to feed self.percentage()
+        """
+        percent = int((float(count)/max_count)*100)
+        if percent > 100:
+            return 100
+        return percent
+
+    def _log_message(self, source, *args):
+        """
+        Write log message to Entropy PackageKit log file.
+        """
+        if PK_DEBUG:
+            self._entropy_log.write("%s: %s" % (source,
+                ' '.join([const_convert_to_unicode(x) for x in args]),)
+            )
+
+    def _is_repository_enabled(self, repo_name):
+        """
+        Return whether given repository identifier is available and enabled.
+        """
+        repo_data = self._settings['repositories']
+        return repo_name in repo_data['available']
+
+    def _etp_to_id(self, pkg_match):
+        """
+        Transform an Entropy package match (pkg_id, EntropyRepository) into
+        PackageKit id.
+        @param pkg_match: tuple composed by package identifier and its parent
+            EntropyRepository instance
+        @type pkg_match: tuple
+        @return: PackageKit package id
+        @rtype: string
+        """
+        pkg_id, c_repo = pkg_match
+
+        pkg_key, pkg_slot, pkg_ver, pkg_tag, pkg_rev, atom = \
+            c_repo.getStrictData(pkg_id)
+
+        pkg_ver += "%s%s" % (etpConst['entropyslotprefix'], pkg_slot,)
+        if pkg_tag:
+            pkg_ver += "%s%s" % (etpConst['entropytagprefix'], pkg_tag)
+
+        cur_arch = etpConst['currentarch']
+        repo_name = self._get_repo_name(c_repo)
+        if repo_name is None:
+            self.error(ERROR_PACKAGE_ID_INVALID,
+                "Invalid metadata passed")
+
+        # if installed, repo should be 'installed', packagekit rule
+        if repo_name == etpConst['clientdbid']:
+            repo_name = "installed"
+
+        # openoffice-clipart;2.6.22;ppc64;fedora
+        return get_package_id(pkg_key, pkg_ver, cur_arch, repo_name)
+
+    def _id_to_etp(self, pkit_id):
+        """
+        Transform a PackageKit package id into Entropy package match.
+
+        @param pkit_id: PackageKit package id
+        @type pkit_id: string
+        @return: tuple composed by package identifier and its parent
+            EntropyRepository instance
+        @rtype: tuple
+        """
+        split_data = split_package_id(pkit_id)
+        if len(split_data) < 4:
+            self.error(ERROR_PACKAGE_ID_INVALID,
+                "The package id %s does not contain 4 fields" % pkit_id)
+            return
+        pkg_key, pkg_ver, cur_arch, repo_name = split_data
+
+        self._log_message(__name__,
+            "_id_to_etp: extracted: %s | %s | %s | %s" % (
+                pkg_key, pkg_ver, cur_arch, repo_name,))
+        pkg_ver, pkg_slot = pkg_ver.rsplit(":", 1)
+
+        if repo_name == "installed":
+            c_repo = self._entropy.installed_repository()
+        else:
+            c_repo = self._entropy.open_repository(repo_name)
+
+        atom = pkg_key + "-" + pkg_ver + etpConst['entropyslotprefix'] + \
+            pkg_slot
+        pkg_id, pkg_rc = c_repo.atomMatch(atom)
+        if pkg_rc != 0:
+            self.error(ERROR_PACKAGE_ID_INVALID,
+                "Package not found in repository")
+            return
+
+        return pkg_id, c_repo
+
+    def _get_pk_group(self, category):
+        """
+        Return PackageKit group belonging to given Entropy package category.
+        """
+        group_data = [key for key, data in \
+            self._entropy.get_package_groups().items() \
+                if category in data['categories']]
+        try:
+            generic_group_name = group_data.pop(0)
+        except IndexError:
+            return GROUP_UNKNOWN
+
+        return PackageKitEntropyBackend.GROUP_MAP[generic_group_name]
+
+    def _get_entropy_group(self, pk_group):
+        """
+        Given a PackageKit group identifier, return Entropy packages group.
+        """
+        group_map = PackageKitEntropyBackend.GROUP_MAP
+        # reverse dict
+        group_map_reverse = dict((y, x) for x, y in group_map.items())
+        return group_map_reverse.get(pk_group, 'unknown')
+
+    def _get_all_repos(self):
+        """
+        Return a list of tuples containing EntropyRepository instance and
+        repository identifier for every available repository, including
+        installed packages one.
+        """
+        inst_pkgs_repo_id = PackageKitEntropyMixin.INST_PKGS_REPO_ID
+        repo_ids = self._entropy.repositories() + [inst_pkgs_repo_id]
+        repos = []
+        for repo in repo_ids:
+            if repo == inst_pkgs_repo_id:
+                repo_db = self._entropy.installed_repository()
+            else:
+                repo_db = self._entropy.open_repository(repo)
+            repos.append((repo_db, repo,))
+        return repos
+
+    def _get_pkg_size(self, pkg_match):
+        """
+        Return package size for both installed and available packages.
+        For available packages, the download size is returned, for installed
+        packages, the on-disk size is returned instead.
+        """
+        pkg_id, c_repo = pkg_match
+        if c_repo is self._entropy.installed_repository():
+            return c_repo.retrieveOnDiskSize(pkg_id)
+        else:
+            return c_repo.retrieveSize(pkg_id)
+
+    def _pk_feed_sorted_pkgs(self, pkgs):
+        """
+        Given an unsorted list of tuples composed by repository identifier and
+        EntropyRepository instance, feed PackageKit output by calling
+        self._package()
+        """
+        lambda_sort = lambda x: x[2].retrieveAtom(x[1])
+
+        for repo, pkg_id, c_repo, pkg_type in sorted(pkgs, key = lambda_sort):
+            self._package((pkg_id, c_repo), info = pkg_type)
+
+    def _pk_filter_pkgs(self, pkgs, filters):
+        """
+        Filter pkgs list given PackageKit filters.
+        """
+        inst_pkgs_repo_id = PackageKitEntropyMixin.INST_PKGS_REPO_ID
+        fltlist = filters.split(';')
+
+        if FILTER_INSTALLED in fltlist:
+            pkgs = set([x for x in pkgs if x[0] == inst_pkgs_repo_id])
+        elif FILTER_NOT_INSTALLED in fltlist:
+            pkgs = set([x for x in pkgs if x[0] != inst_pkgs_repo_id])
+        if FILTER_FREE in fltlist:
+            pkgs = set([x for x in pkgs if \
+                self._entropy.is_entropy_package_free(x[1], x[0])])
+
+        return pkgs
+
+    def _pk_add_pkg_type(self, pkgs, important_check = False):
+        """
+        Expand list of pkg tuples by adding PackageKit package type to it.
+        """
+        # we have INFO_IMPORTANT, INFO_SECURITY, INFO_NORMAL
+        new_pkgs = set()
+        sys_pkg_map = {}
+
+        for repo, pkg_id, c_repo in pkgs:
+
+            pkg_type = None
+            if important_check:
+                repo_sys_pkgs = sys_pkg_map.get(repo,
+                    c_repo.getSystemPackages())
+
+                if pkg_id in repo_sys_pkgs:
+                    pkg_type = INFO_IMPORTANT
+                else:
+                    pkg_type = INFO_NORMAL
+
+            if pkg_type is None:
+                if c_repo is self._entropy.installed_repository():
+                    info = INFO_INSTALLED
+                else:
+                    info = INFO_AVAILABLE
+
+            new_pkgs.add((repo, pkg_id, c_repo, pkg_type))
+
+        return new_pkgs
+
+    def _repo_enable(self, repoid):
+        excluded_repos = self._settings['repositories']['excluded']
+        available_repos = self._settings['repositories']['available']
+
+        if repoid in available_repos:
+            # just ignore
+            return
+        if repoid not in excluded_repos:
+            self.error(ERROR_REPO_NOT_FOUND,
+                    "Repository %s was not found" % (repoid,))
+            return
+
+        try:
+            self._entropy.enable_repository(repoid)
+        except Exception as err:
+            self.error(ERROR_INTERNAL_ERROR,
+                "Failed to enable repository %s: %s" % (repoid, err,))
+            return
+
+    def _repo_disable(self, repoid):
+        excluded_repos = self._settings['repositories']['excluded']
+        available_repos = self._settings['repositories']['available']
+        default_repo = self._settings['repositories']['default_repository']
+
+        if repoid in excluded_repos:
+            # just ignore
+            return
+        if repoid not in available_repos:
+            self.error(ERROR_REPO_NOT_FOUND,
+                    "Repository %s was not found" % (repoid,))
+            return
+
+        if repoid == default_repo:
+            self.error(ERROR_CANNOT_DISABLE_REPOSITORY,
+                "%s repository can't be disabled" % (repoid,))
+            return
+
+        try:
+            self._entropy.disable_repository(repoid)
+        except Exception as err:
+            self.error(ERROR_INTERNAL_ERROR,
+                "Failed to enable repository %s: %s" % (repoid, err,))
+            return
+
+    def _get_repo_name(self, repo_db):
+        """
+        Return repository name (identifier) given an EntropyRepository
+        instance.
+        """
+        repo_name = self._repo_name_cache.get(repo_db)
+        if repo_name is None:
+            repo_name = repo_db.get_plugins_metadata().get("repo_name")
+            self._repo_name_cache[repo_db] = repo_name
+        return repo_name
+
+    def _etp_spawn_ugc(self, pkg_data):
+        """
+        Inform repository maintainers that user fetched packages, if user
+        enabled this feature.
+        """
+        if self._entropy.UGC is None:
+            return
+        for repo_id in pkg_data:
+            repo_pkg_keys = sorted(pkg_data[repo_id])
+            try:
+                self._entropy.UGC.add_download_stats(repo_id, repo_pkg_keys)
+            except:
+                pass
+
+    def _etp_get_category_description(self, category):
+        """
+        Return translated Entropy packages category description.
+        """
+        cat_desc = _("No description")
+        cat_desc_data = self._entropy.get_category_description(category)
+        if _LOCALE in cat_desc_data:
+            cat_desc = cat_desc_data[_LOCALE]
+        elif 'en' in cat_desc_data:
+            cat_desc = cat_desc_data['en']
+        return cat_desc
+
+    def _execute_etp_pkgs_remove(self, pkgs, allowdep, autoremove):
+        """
+        Execute effective removal (including dep calculation).
+
+        @param pkgs: list of package tuples composed by
+            (etp_package_id, EntropyRepository, pk_pkg_id)
+        @type pkgs: list
+        @param allowdep: Either true or false. If true allow other packages
+            to be removed with the package, but false should cause the script
+            to abort if other packages are dependant on the package.
+        @type allowdep: bool
+        @param autoremove: Either true or false. This option is only really
+            interesting on embedded devices with a limited amount of flash
+            storage. It suggests to the packagekit backend that
+            dependencies installed at the same time as the package
+            should also be removed if they are not required by
+            anything else. For instance, if you install OpenOffice,
+            it might download libneon as a dependency. When auto_remove
+            is set to true, and you remove OpenOffice then libneon
+            will also get removed automatically.
+        @type autoremove: bool
+        """
+
+        # backend do not implement autoremove
+        if autoremove:
+            self.message(MESSAGE_AUTOREMOVE_IGNORED,
+                "Entropy backend devs refused to implement this feature")
+
+        self.percentage(0)
+        self.status(STATUS_DEP_RESOLVE)
+
+        # check if we have installed pkgs only
+        for pkg_id, c_repo, pk_pkg in pkgs:
+            if c_repo is not self._entropy.installed_repository():
+                self.error(ERROR_DEP_RESOLUTION_FAILED,
+                    "Cannot remove a package coming fro a repository: %s" % (
+                        pk_pkg,))
+                return
+
+        match_map = dict((
+            (pkg_id, (pkg_id, c_repo, pk_pkg)) \
+                for pkg_id, c_repo, pk_pkg in pkgs))
+        matches = [pkg_id for pkg_id, c_repo, pk_pkg in pkgs]
+
+        # calculate deps
+        run_queue = self._entropy.get_removal_queue(matches)
+        added_pkgs = [x for x in run_queue if x not in matches]
+
+        # if there are required packages, allowdep must be on
+        if added_pkgs and not allowdep:
+            self.error(ERROR_DEP_RESOLUTION_FAILED,
+                "Could not perform remove operation, some packages are needed by other packages")
+            return
+
+        self.percentage(0)
+        self.status(STATUS_REMOVE)
+
+        # remove
+        max_count = len(run_queue)
+        count = 0
+        for pkg_id in run_queue:
+            count += 1
+
+            percent = PackageKitEntropyMixin.get_percentage(count, max_count)
+
+            self._log_message(__name__, "get_packages: done %s/100" % (
+                percent,))
+
+            self.percentage(percent)
+
+            metaopts = {}
+            metaopts['removeconfig'] = False
+            package = self._entropy.Package()
+            package.prepare((pkg_id,), "remove", metaopts)
+            if 'remove_installed_vanished' not in package.pkgmeta:
+                x_rc = package.run()
+                if x_rc != 0:
+                    pk_pkg = match_map.get(pkg_id, (None, None, None))[2]
+                    self.error(ERROR_PACKAGE_FAILED_TO_REMOVE,
+                        "Cannot remove package: %s" % (pk_pkg,))
+                    return
+
+            package.kill()
+            del package
+
+        self.finished()
+
+    def _execute_etp_pkgs_fetch(self, pkgs, directory):
+        """
+        Execute effective packages download.
+        """
+        self._execute_etp_pkgs_install(pkgs, False, only_fetch = True,
+            fetch_path = directory, calculate_deps = False)
+
+    def _execute_etp_pkgs_install(self, pkgs, only_trusted, only_fetch = False,
+        fetch_path = None, calculate_deps = True):
+        """
+        Execute effective install (including dep calculation).
+
+        @param pkgs: list of package tuples composed by
+            (etp_package_id, EntropyRepository, pk_pkg_id)
+        @type pkgs: list
+        @param only_trusted: only accept trusted pkgs?
+        @type only_trusted: bool
+        """
+        self.percentage(0)
+        self.status(STATUS_RUNNING)
+
+        if only_trusted:
+            # check if we have trusted pkgs
+            for pkg_id, c_repo, pk_pkg in pkgs:
+                sha1, sha256, sha512, gpg = c_repo.retrieveSignatures(pkg_id)
+                if gpg is None:
+                    self.error(ERROR_MISSING_GPG_SIGNATURE,
+                        "Package %s is not GPG signed" % (pk_pkg,))
+                    return
+
+        matches = [(pkg_id, self._get_repo_name(c_repo),) for \
+            pkg_id, c_repo, pk_pkg in pkgs]
+
+        # calculate deps
+        if calculate_deps:
+            self.status(STATUS_DEP_RESOLVE)
+            empty_deps, deep_deps = False, False
+            run_queue, removal_queue, status = self._entropy.get_install_queue(
+                matches, empty_deps, deep_deps)
+        else:
+            run_queue = matches
+            removal_queue = []
+            status = 0
+
+        if status == -2:
+            self.error(ERROR_DEP_RESOLUTION_FAILED,
+                "Cannot find the following dependencies: %s" % (
+                    ', '.join(run_queue),))
+            return
+
+        self.percentage(0)
+        self.status(STATUS_DOWNLOAD)
+
+        # FIXME: where is license dialog? can't be interactive, fook!
+
+        # used in case of errors
+        match_map = {}
+        for pkg_id, repo_id in run_queue:
+            pkg_c_repo = self._entropy.open_repository(repo_id)
+            match_map[(pkg_id, repo_id,)] = (pkg_id, pkg_c_repo,
+                self._etp_to_id((pkg_id, pkg_c_repo)),)
+
+        # fetch pkgs
+        max_count = len(run_queue)
+        if not only_fetch:
+            max_count *= 2
+        count = 0
+        down_data = {}
+        for match in run_queue:
+            count += 1
+
+            percent = PackageKitEntropyMixin.get_percentage(count, max_count)
+
+            self._log_message(__name__, "get_packages: done %s/100" % (
+                percent,))
+
+            self.percentage(percent)
+            metaopts = {
+                'dochecksum': True,
+            }
+            if fetch_path is not None:
+                metaopts['fetch_path'] = fetch_path
+
+            package = self._entropy.Package()
+            package.prepare(match, "fetch", metaopts)
+            myrepo = package.pkgmeta['repository']
+            obj = down_data.setdefault(myrepo, set())
+            obj.add(entropy.tools.dep_getkey(package.pkgmeta['atom']))
+
+            pkg_id, pkg_c_repo, pk_pkg = match_map.get(match)
+            pkg_desc = pkg_c_repo.retrieveDescription(pkg_id)
+            # show pkg
+            self.package(pk_pkg, INFO_DOWNLOADING, pkg_desc)
+
+            x_rc = package.run()
+            if x_rc != 0:
+                pk_pkg = match_map.get(match, (None, None, None))[2]
+                self.error(ERROR_PACKAGE_FAILED_TO_CONFIGURE,
+                    "Cannot download package: %s" % (pk_pkg,))
+                return
+
+            # emit the file we downloaded
+            self.files(pk_pkg, package.pkgmeta['pkgpath'])
+
+            package.kill()
+            del package
+
+        # spawn UGC
+        self._etp_spawn_ugc(down_data)
+
+        self.percentage(100)
+        if only_fetch:
+            self.finished()
+            return
+
+        # install
+        self.status(STATUS_INSTALL)
+
+        for match in run_queue:
+            count += 1
+
+            percent = PackageKitEntropyMixin.get_percentage(count, max_count)
+
+            self._log_message(__name__, "get_packages: done %s/100" % (
+                percent,))
+
+            self.percentage(percent)
+
+            metaopts = {
+                'removeconfig': False,
+            }
+            # setup install source
+            if match in matches:
+                metaopts['install_source'] = etpConst['install_sources']['user']
+            else:
+                metaopts['install_source'] = \
+                    etpConst['install_sources']['automatic_dependency']
+
+            package = self._entropy.Package()
+            package.prepare(match, "install", metaopts)
+
+            x_rc = package.run()
+            if x_rc != 0:
+                pk_pkg = match_map.get(match, (None, None, None))[2]
+                self.error(ERROR_PACKAGE_FAILED_TO_INSTALL,
+                    "Cannot install package: %s" % (pk_pkg,))
+                return
+
+            package.kill()
+            del package
+
+        self._config_files_message()
+        self.finished()
+
+
+class PackageKitEntropyClient(Client):
+    """ PackageKit Entropy Client subclass """
+
+    _pk_progress = None
+    _pk_message = None
+
+    def output(self, text, header = "", footer = "", back = False,
+        importance = 0, type = "info", count = None, percent = False):
+        """
+        Reimplemented from entropy.output.TextInterface.
+        """
+        message_func = PackageKitEntropyClient._pk_message
+        if message_func is not None:
+            message_func(text)
+
+        progress = PackageKitEntropyClient._pk_progress
+        if progress is None:
+            return
+        if count is None:
+            return
+
+        cur, tot = count[0], count[1]
+        progress(PackageKitEntropyMixin.get_percentage(cur, tot))
+
+# in this way, any singleton class that tries to directly load Client
+# gets PackageKitEntropyClient in change
+Client.__singleton_class__ = PackageKitEntropyClient
+
+
+class PkUrlFetcher(UrlFetcher):
+
+    _pk_progress = None
+    _last_t = time.time()
+
+    def __init__(self, *args, **kwargs):
+        self.__average = 0
+        self.__downloadedsize = 0
+        self.__remotesize = 0
+        self.__datatransfer = 0
+        UrlFetcher.__init__(self, *args, **kwargs)
+
+    def handle_statistics(self, th_id, downloaded_size, total_size,
+            average, old_average, update_step, show_speed, data_transfer,
+            time_remaining, time_remaining_secs):
+        self.__average = average
+        self.__downloadedsize = downloaded_size
+        self.__remotesize = total_size
+        self.__datatransfer = data_transfer
+
+    def output(self):
+
+        if PkUrlFetcher._pk_progress is None:
+            return
+
+        last_t = PkUrlFetcher._last_t
+        if (time.time() - last_t) > 1:
+            myavg = abs(int(round(float(self.__average), 1)))
+            cur_prog = int(float(self.__average)/100)
+            PkUrlFetcher._pk_progress(cur_prog)
+            PkUrlFetcher._last_t = time.time()
+
+
+class PackageKitEntropyBackend(PackageKitBaseBackend, PackageKitEntropyMixin):
+
+    _log_fname = os.path.join(etpConst['syslogdir'], "packagekit.log")
+
+    # Entropy <-> PackageKit groups map
+    GROUP_MAP = {
+        'accessibility': GROUP_ACCESSIBILITY,
+        'development': GROUP_PROGRAMMING,
+        'games': GROUP_GAMES,
+        'gnome': GROUP_DESKTOP_GNOME,
+        'kde': GROUP_DESKTOP_KDE,
+        'lxde': GROUP_DESKTOP_OTHER,
+        'multimedia': GROUP_MULTIMEDIA,
+        'networking': GROUP_NETWORK,
+        'office': GROUP_OFFICE,
+        'science': GROUP_SCIENCE,
+        'system': GROUP_SYSTEM,
+        'security': GROUP_SECURITY,
+        'x11': GROUP_OTHER,
+        'xfce': GROUP_DESKTOP_XFCE,
+        'unknown': GROUP_UNKNOWN,
+    }
+
+    def __sigquit(self, signum, frame):
+        if hasattr(self, '_entropy'):
+            self._entropy.destroy()
+        raise SystemExit(1)
+
+    def __init__(self, args):
+        PackageKitEntropyMixin.__init__(self)
+
+        signal.signal(signal.SIGQUIT, self.__sigquit)
+        self._entropy = PackageKitEntropyClient()
+        PkUrlFetcher._pk_progress = self.sub_percentage
+        self._entropy.urlFetcher = PkUrlFetcher
+        self._repo_name_cache = {}
+        PackageKitEntropyClient._pk_progress = self.percentage
+        PackageKitEntropyClient._pk_message = self._generic_message
+
+        self._settings = SystemSettings()
+        self._entropy_log = LogFile(
+            level = self._settings['system']['log_level'],
+            filename = self._log_fname, header = "[packagekit]")
+
+        PackageKitBaseBackend.__init__(self, args)
+
+    def _convert_date_to_iso8601(self, unix_time_str):
+        unix_time = float(unix_time_str)
+        ux_t = time.localtime(unix_time)
+        formatted = time.strftime('%Y-%m-%dT%H:%M:%S', ux_t)
+        return formatted
+
+    def _generic_message(self, message):
+        # FIXME: this doesn't work, it seems there's no way to
+        # print something to user while pkcon runs.
+        self.message(MESSAGE_UNKNOWN, message)
+
+    def _config_files_message(self):
+        scandata = self._entropy.FileUpdates.scanfs(dcache = True,
+            quiet = True)
+        if scandata is None:
+            return
+        if len(scandata) > 0:
+            message = "Some configuration files need updating."
+            message += ";You should use 'equo conf update' to update them"
+            message += ";If you can't do that, ask your system administrator."
+            self.message(MESSAGE_CONFIG_FILES_CHANGED, message)
+
+    def _package(self, pkg_match, info=None):
+
+        # package_id = (package_identifier, EntropyRepository)
+        pkg_id, c_repo = pkg_match
+        desc = c_repo.retrieveDescription(pkg_id)
+
+        if not info:
+            if c_repo is self._entropy.installed_repository():
+                info = INFO_INSTALLED
+            else:
+                info = INFO_AVAILABLE
+        return self.package(self._etp_to_id(pkg_match), info, desc)
+
+    def get_depends(self, filters, pk_pkgs, recursive):
+
+        self._log_message(__name__, "get_depends: got %s and %s and %s" % (
+            filters, pk_pkgs, recursive,))
+
+        self.status(STATUS_INFO)
+        self.allow_cancel(True)
+        self.percentage(0)
+
+        pkgs = set()
+        for pk_pkg in pk_pkgs:
+
+            pkg = self._id_to_etp(pk_pkg)
+            if pkg is None: # wtf!
+                self._log_message(__name__, "get_depends: cannot match %s" % (
+                    pk_pkg,))
+                continue
+
+            self._log_message(__name__, "get_depends: translated %s => %s" % (
+                pk_pkg, pkg,))
+
+            pkg_id, repo_db = pkg
+            repo = self._get_repo_name(repo_db)
+            pkgs.add((repo, pkg_id, repo_db,))
+
+        matches = [(y, x) for x, y, z in pkgs]
+        self._log_message(__name__, "get_depends: raw matches => %s" % (
+            matches,))
+
+        empty = False
+        deep = False
+        install, removal, deps_not_f = self._entropy.get_install_queue(matches,
+            empty, deep, recursive = recursive)
+
+        if deps_not_f == -2:
+            self.error(ERROR_DEP_RESOLUTION_FAILED,
+                "Dependencies not found: %s" % (sorted(install),))
+            return
+
+        # transform install into (repo, pkg_id, c_repo) list
+        install = [(y, x, self._entropy.open_repository(y),) for x, y in \
+            install]
+        # transform remove the same way
+        inst_pkg_r_id = PackageKitEntropyMixin.INST_PKGS_REPO_ID
+        removal = [(inst_pkg_r_id, x, self._entropy.installed_repository()) \
+            for x in removal]
+
+        pkgs = set(install + removal)
+
+        self._log_message(__name__, "get_depends: matches %s" % (
+            pkgs,))
+
+        # now filter
+        pkgs = self._pk_filter_pkgs(pkgs, filters)
+        pkgs = self._pk_add_pkg_type(pkgs)
+        # now feed stdout
+        self._pk_feed_sorted_pkgs(pkgs)
+
+        self.percentage(100)
+
+    def get_details(self, pk_pkgs):
+
+        self._log_message(__name__, "get_details: got %s" % (pk_pkgs,))
+
+        self.status(STATUS_INFO)
+        self.allow_cancel(True)
+        self.percentage(0)
+
+        count = 0
+        max_count = len(pk_pkgs)
+        for pk_pkg in pk_pkgs:
+            count += 1
+            percent = PackageKitEntropyMixin.get_percentage(count, max_count)
+
+            self._log_message(__name__, "get_packages: done %s/100" % (
+                percent,))
+
+            self.percentage(percent)
+            pkg = self._id_to_etp(pk_pkg)
+            if pkg is None:
+                self.error(ERROR_PACKAGE_NOT_FOUND,
+                    "Package %s was not found" % (pk_pkg,))
+                continue
+            pkg_id, c_repo = pkg
+
+            category = c_repo.retrieveCategory(pkg_id)
+            lic = c_repo.retrieveLicense(pkg_id)
+            homepage = c_repo.retrieveHomepage(pkg_id)
+            description = c_repo.retrieveDescription(pkg_id)
+            if (category is None) or (description is None):
+                self.error(ERROR_PACKAGE_NOT_FOUND,
+                    "Package %s was not found in repository" % (pk_pkg,))
+                continue
+
+            self.details(pk_pkg, lic, self._get_pk_group(category),
+                description, homepage, self._get_pkg_size(pkg))
+
+        self.percentage(100)
+
+    def get_categories(self):
+
+        self._log_message(__name__, "get_categories: called")
+
+        self.status(STATUS_QUERY)
+        self.allow_cancel(True)
+
+        categories = self._entropy.get_package_categories()
+        if not categories:
+            self.error(ERROR_GROUP_LIST_INVALID, "no package categires")
+            return
+
+        for name in categories:
+            name = const_convert_to_rawstring(name)
+
+            summary = self._etp_get_category_description(name)
+            summary = const_convert_to_rawstring(summary, "utf-8")
+
+            f_name = "/usr/share/pixmaps/entropy/%s.png" % (name,)
+            if os.path.isfile(f_name) and os.access(f_name, os.R_OK):
+                icon = name
+            else:
+                icon = const_convert_to_rawstring("image-missing")
+
+            nothing = const_convert_to_rawstring("")
+            cat_id = name # same thing
+
+            self._log_message(__name__, "get_categories: pushing",
+                nothing, cat_id, name, summary, icon)
+
+            self.category(nothing, cat_id, name, summary, icon)
+
+    def get_files(self, pk_pkgs):
+
+        self._log_message(__name__, "get_files: got %s" % (pk_pkgs,))
+
+        self.status(STATUS_INFO)
+        self.allow_cancel(True)
+        self.percentage(0)
+
+        pkgs = []
+        for pk_pkg in pk_pkgs:
+
+            pkg = self._id_to_etp(pk_pkg)
+            if pkg is None: # wtf!
+                self.error(ERROR_PACKAGE_NOT_FOUND,
+                        "Package %s was not found" % (pk_pkg,))
+                self._log_message(__name__, "get_files: cannot match %s" % (
+                    pk_pkg,))
+                continue
+
+            self._log_message(__name__, "get_files: translated %s => %s" % (
+                pk_pkg, pkg,))
+
+            pkg_id, repo_db = pkg
+            repo = self._get_repo_name(repo_db)
+            pkgs.append((repo, pkg_id, repo_db, pk_pkg))
+
+        count = 0
+        max_count = len(pkgs)
+        for repo, pkg_id, repo_db, pk_pkg in pkgs:
+            count += 1
+            percent = PackageKitEntropyMixin.get_percentage(count, max_count)
+
+            self._log_message(__name__, "get_files: done %s/100" % (
+                percent,))
+
+            self.percentage(percent)
+            files = repo_db.retrieveContent(pkg_id, order_by = 'file')
+            files = ";".join(files)
+            self.files(pk_pkg, files)
+
+        self.percentage(100)
+
+    def get_packages(self, filters):
+
+        self._log_message(__name__, "get_packages: got %s" % (
+            filters,))
+
+        self.status(STATUS_QUERY)
+        self.allow_cancel(True)
+        self.percentage(0)
+
+        repos = self._get_all_repos()
+
+        pkgs = set()
+        count = 0
+        max_count = len(repos)
+        for repo_db, repo in repos:
+
+            count += 1
+            percent = PackageKitEntropyMixin.get_percentage(count, max_count)
+
+            self._log_message(__name__, "get_packages: done %s/100" % (percent,))
+
+            self.percentage(percent)
+            pkg_ids = repo_db.listAllIdpackages()
+            pkgs.update((repo, x, repo_db,) for x in pkg_ids)
+
+        # now filter
+        pkgs = self._pk_filter_pkgs(pkgs, filters)
+        pkgs = self._pk_add_pkg_type(pkgs)
+        # now feed stdout
+        self._pk_feed_sorted_pkgs(pkgs)
+
+        self.percentage(100)
+
+    def get_repo_list(self, filters):
+
+        self._log_message(__name__, "get_repo_list: got %s" % (filters,))
+
+        self.status(STATUS_INFO)
+        self.allow_cancel(True)
+        self.percentage(None)
+
+        excluded_repos = self._settings['repositories']['excluded']
+        available_repos = self._settings['repositories']['available']
+        default_repo = self._settings['repositories']['default_repository']
+
+        all_repos = sorted(excluded_repos.keys() + available_repos.keys())
+        metadata = []
+        for repo_id in all_repos:
+
+            repo_data = available_repos.get(repo_id,
+                excluded_repos.get(repo_id))
+            if repo_data is None: # wtf?
+                continue
+
+            enabled = self._is_repository_enabled(repo_id)
+            desc = repo_data['description']
+            devel = repo_id != default_repo
+            metadata.append((repo_id, desc, enabled, devel))
+
+        fltlist = filters.split(';')
+        if FILTER_NOT_DEVELOPMENT in fltlist:
+            metadata = [x for x in metadata if not x[3]]
+
+        for repo_id, desc, enabled, devel in metadata:
+            self.repo_detail(repo_id, desc, enabled)
+
+    def get_requires(self, filters, pk_pkgs, recursive):
+
+        self._log_message(__name__, "get_requires: got %s and %s and %s" % (
+            filters, pk_pkgs, recursive))
+
+        self.status(STATUS_INFO)
+        self.allow_cancel(True)
+        self.percentage(0)
+
+        pkgs = set()
+        for pk_pkg in pk_pkgs:
+
+            pkg = self._id_to_etp(pk_pkg)
+            if pkg is None: # wtf!
+                self._log_message(__name__, "get_requires: cannot match %s" % (
+                    pk_pkg,))
+                continue
+
+            self._log_message(__name__, "get_requires: translated %s => %s" % (
+                pk_pkg, pkg,))
+
+            pkg_id, repo_db = pkg
+            repo = self._get_repo_name(repo_db)
+            pkgs.add((repo, pkg_id, repo_db,))
+
+        matches = [(y, x) for x, y, z in pkgs]
+
+        self._log_message(__name__, "get_requires: cooked => %s" % (
+            matches,))
+
+        empty = False
+        deep = False
+        reverse_deps = self._entropy.get_reverse_dependencies(matches,
+            deep = deep, recursive = recursive)
+
+        self._log_message(__name__, "get_requires: reverse_deps => %s" % (
+            reverse_deps,))
+
+        pkgs = set([(y, x, self._entropy.open_repository(y),) for x, y in \
+            reverse_deps])
+
+        self._log_message(__name__, "get_requires: matches %s" % (
+            pkgs,))
+
+        # now filter
+        pkgs = self._pk_filter_pkgs(pkgs, filters)
+        pkgs = self._pk_add_pkg_type(pkgs)
+        # now feed stdout
+        self._pk_feed_sorted_pkgs(pkgs)
+
+        self.percentage(100)
+
+    def get_update_detail(self, pk_pkgs):
+
+        self._log_message(__name__, "get_update_detail: got %s" % (
+            pk_pkgs,))
+
+        self.status(STATUS_INFO)
+        self.allow_cancel(True)
+        self.percentage(0)
+
+        count = 0
+        max_count = len(pk_pkgs)
+        default_repo = self._settings['repositories']['default_repository']
+        i_repo = self._entropy.installed_repository()
+        for pk_pkg in pk_pkgs:
+            count += 1
+            percent = PackageKitEntropyMixin.get_percentage(count, max_count)
+
+            self._log_message(__name__, "get_update_detail: done %s/100" % (
+                percent,))
+
+            self.percentage(percent)
+            pkg = self._id_to_etp(pk_pkg)
+            if pkg is None:
+                self.message(MESSAGE_COULD_NOT_FIND_PACKAGE,
+                    "could not find %s" % (pk_pkg,))
+                continue
+            pkg_id, c_repo = pkg
+            repo_name = self._get_repo_name(c_repo)
+
+            updates = []
+            keyslot = c_repo.retrieveKeySlotAggregated(pkg_id)
+            matches, m_rc = self._entropy.atom_match(keyslot, multiMatch = True,
+                multiRepo = True)
+            for m_pkg_id, m_repo_id in matches:
+                if (m_pkg_id, m_repo_id) == (pkg_id, repo_name):
+                    continue # fliter myself
+                m_c_repo = self._entropy.open_repository(m_repo_id)
+                updates.append(self._etp_to_id((m_pkg_id, m_c_repo)))
+
+            obsoletes = ""
+            bugzilla_url = "http://bugs.sabayon.org"
+            cve_url = ""
+            vendor_url = c_repo.retrieveHomepage(pkg_id)
+            changelog = c_repo.retrieveChangelog(pkg_id)
+            updates = "&".join(updates)
+
+            # when package has been issued
+            issued = self._convert_date_to_iso8601(
+                c_repo.retrieveCreationDate(pkg_id))
+
+            # when package has been updated on system
+            # search inside installed pkgs db
+            updated = ''
+            c_id, c_rc = i_repo.atomMatch(keyslot)
+            if c_rc == 0:
+                updated = self._convert_date_to_iso8601(
+                    i_repo.retrieveCreationDate(c_id))
+
+            update_message = _("Update")
+            state = UPDATE_STATE_STABLE
+            if repo_name != default_repo:
+                state = UPDATE_STATE_TESTING
+
+            self._log_message(__name__, "get_update_detail: issuing %s" % (
+                (pk_pkg, updates, obsoletes, vendor_url, bugzilla_url),))
+
+            self.update_detail(pk_pkg, updates, obsoletes, vendor_url,
+                bugzilla_url, cve_url, "none", update_message, changelog,
+                state, issued, updated)
+
+        self.percentage(100)
+
+    def get_distro_upgrades(self):
+        """
+        FIXME: should this return only system updates? (pkgs marked as syspkgs)
+        Not implemented atm
+        """
+        PackageKitBaseBackend.get_distro_upgrades(self)
+
+    def get_updates(self, filters):
+
+        self.status(STATUS_INFO)
+        self.allow_cancel(True)
+
+        # this is the part that takes time
+        self.percentage(0)
+        try:
+            update, remove, fine, spm_fine = self._entropy.calculate_updates()
+        except SystemDatabaseError as err:
+            self.error(ERROR_DEP_RESOLUTION_FAILED,
+                "System Repository error: %s" % (err,))
+            return
+        self.percentage(100)
+
+        pkgs = set()
+        count = 0
+        max_count = len(update)
+        for pkg_id, repo_id in update:
+            count += 1
+            percent = PackageKitEntropyMixin.get_percentage(count, max_count)
+
+            self._log_message(__name__, "get_updates: done %s/100" % (
+                percent,))
+
+            self.percentage(percent)
+            repo_db = self._entropy.open_repository(repo_id)
+            pkgs.add((repo_id, pkg_id, repo_db))
+
+        # now filter
+        pkgs = self._pk_filter_pkgs(pkgs, filters)
+        pkgs = self._pk_add_pkg_type(pkgs, important_check = True)
+        # now feed stdout
+        self._pk_feed_sorted_pkgs(pkgs)
+
+        self.percentage(100)
+
+    def install_packages(self, only_trusted, pk_pkgs):
+
+        self._log_message(__name__, "install_packages: got %s and %s" % (
+            only_trusted, pk_pkgs,))
+
+        self.status(STATUS_RUNNING)
+        self.allow_cancel(True)
+
+        pkgs = []
+        for pk_pkg in pk_pkgs:
+            pkg = self._id_to_etp(pk_pkg)
+            if pkg is None:
+                self.error(ERROR_PACKAGE_NOT_FOUND,
+                    "Package %s was not found" % (pk_pkg,))
+                continue
+            pkgs.append((pkg[0], pkg[1], pk_pkg,))
+
+        self._execute_etp_pkgs_install(pkgs, only_trusted)
+
+    def download_packages(self, directory, pk_pkgs):
+
+        self._log_message(__name__, "download_packages: got %s and %s" % (
+            directory, pk_pkgs,))
+
+        self.status(STATUS_RUNNING)
+        self.allow_cancel(True)
+
+        pkgs = []
+        for pk_pkg in pk_pkgs:
+            pkg = self._id_to_etp(pk_pkg)
+            if pkg is None:
+                self.error(ERROR_PACKAGE_NOT_FOUND,
+                    "Package %s was not found" % (pk_pkg,))
+                continue
+            pkgs.append((pkg[0], pkg[1], pk_pkg,))
+
+        self._execute_etp_pkgs_fetch(pkgs, directory)
+
+    def refresh_cache(self, force):
+
+        self.status(STATUS_REFRESH_CACHE)
+        self.allow_cancel(False)
+        self.percentage(0)
+
+        repo_intf = None
+        repo_identifiers = sorted(self._settings['repositories']['available'])
+        try:
+            repo_intf = self._entropy.Repositories(repo_identifiers,
+                force = force)
+        except AttributeError:
+            self.error(ERROR_REPO_CONFIGURATION_ERROR, traceback.format_exc())
+        except Exception as err:
+            self.error(ERROR_INTERNAL_ERROR, traceback.format_exc())
+
+        if repo_intf is None:
+            return
+
+        ex_rc = repo_intf.sync()
+        if not ex_rc:
+            for repo_id in repo_identifiers:
+                # inform UGC that we are syncing this repo
+                if self._entropy.UGC is not None:
+                    self._entropy.UGC.add_download_stats(repo_id, [repo_id])
+        else:
+            self.message(MESSAGE_REPO_METADATA_DOWNLOAD_FAILED,
+                "Cannot update repositories!")
+
+        self.percentage(100)
+
+    def remove_packages(self, allowdep, autoremove, pk_pkgs):
+
+        self._log_message(__name__, "remove_packages: got %s and %s and %s" % (
+            allowdep, autoremove, pk_pkgs,))
+
+        self.status(STATUS_RUNNING)
+        self.allow_cancel(True)
+
+        pkgs = []
+        for pk_pkg in pk_pkgs:
+            pkg = self._id_to_etp(pk_pkg)
+            if pkg is None:
+                self.error(ERROR_UPDATE_NOT_FOUND,
+                    "Package %s was not found" % (pk_pkg,))
+                continue
+            pkgs.append((pkg[0], pkg[1], pk_pkg,))
+
+        self._execute_etp_pkgs_remove(pkgs, allowdep, autoremove)
+
+    def repo_enable(self, repoid, enable):
+
+        self._log_message(__name__, "repo_enable: got %s and %s" % (
+            repoid, enable,))
+
+        self.status(STATUS_INFO)
+        self.allow_cancel(True)
+        self.percentage(None)
+
+        if enable:
+            self._repo_enable(repoid)
+        else:
+            self._repo_disable(repoid)
+
+        self._log_message(__name__, "repo_enable: done")
+
+    def resolve(self, filters, search_keys):
+
+        self._log_message(__name__, "resolve: got %s and %s" % (
+            filters, search_keys,))
+
+        self.status(STATUS_QUERY)
+        self.allow_cancel(True)
+        self.percentage(0)
+
+        repos = self._get_all_repos()
+
+        pkgs = set()
+        count = 0
+        max_count = len(repos)
+        for repo_db, repo in repos:
+
+            count += 1
+            percent = PackageKitEntropyMixin.get_percentage(count, max_count)
+
+            self._log_message(__name__, "resolve: done %s/100" % (
+                percent,))
+
+            self.percentage(percent)
+            for key in search_keys:
+                pkg_ids, pkg_rc = repo_db.atomMatch(key, multiMatch = True)
+                pkgs.update((repo, x, repo_db,) for x in pkg_ids)
+
+        # now filter
+        pkgs = self._pk_filter_pkgs(pkgs, filters)
+        pkgs = self._pk_add_pkg_type(pkgs)
+        # now feed stdout
+        self._pk_feed_sorted_pkgs(pkgs)
+
+        self.percentage(100)
+
+    def search_details(self, filters, keys):
+
+        self._log_message(__name__, "search_details: got %s and %s" % (
+            filters, keys,))
+
+        self.status(STATUS_QUERY)
+        self.allow_cancel(True)
+        self.percentage(0)
+
+        repos = self._get_all_repos()
+
+        search_keys = keys.split("&")
+        pkgs = set()
+        count = 0
+        max_count = len(repos)
+        for repo_db, repo in repos:
+            count += 1
+            percent = PackageKitEntropyMixin.get_percentage(count, max_count)
+
+            self._log_message(__name__, "search_details: done %s/100" % (
+                percent,))
+
+            self.percentage(percent)
+            for key in search_keys:
+                pkg_ids = repo_db.searchDescription(key,
+                    just_id = True)
+                pkg_ids |= repo_db.searchHomepage(key, just_id = True)
+                pkg_ids |= repo_db.searchLicense(key, just_id = True)
+                pkgs.update((repo, x, repo_db,) for x in pkg_ids)
+
+        # now filter
+        pkgs = self._pk_filter_pkgs(pkgs, filters)
+        pkgs = self._pk_add_pkg_type(pkgs)
+        # now feed stdout
+        self._pk_feed_sorted_pkgs(pkgs)
+
+        self.percentage(100)
+
+    def search_file(self, filters, keys):
+
+        self._log_message(__name__, "search_file: got %s and %s" % (
+            filters, keys,))
+
+        self.status(STATUS_QUERY)
+        self.allow_cancel(True)
+        self.percentage(0)
+
+        reverse_symlink_map = self._settings['system_rev_symlinks']
+        repos = self._get_all_repos()
+
+        search_keys = keys.split("&")
+        pkgs = set()
+        count = 0
+        max_count = len(repos)
+        for repo_db, repo in repos:
+            count += 1
+            percent = PackageKitEntropyMixin.get_percentage(count, max_count)
+
+            self._log_message(__name__, "search_file: done %s/100" % (
+                percent,))
+
+            self.percentage(percent)
+
+            for key in search_keys:
+
+                like = False
+                # wildcard support
+                if key.find("*") != -1:
+                    key.replace("*", "%")
+                    like = True
+
+                pkg_ids = repo_db.searchBelongs(key, like = like)
+                if not pkg_ids:
+                    # try real path if possible
+                    pkg_ids = repo_db.searchBelongs(os.path.realpath(key),
+                        like = like)
+                if not pkg_ids:
+                    # try using reverse symlink mapping
+                    for sym_dir in reverse_symlink_map:
+                        if key.startswith(sym_dir):
+                            for sym_child in reverse_symlink_map[sym_dir]:
+                                my_file = sym_child+key[len(sym_dir):]
+                                pkg_ids = repo_db.searchBelongs(my_file,
+                                    like = like)
+                                if pkg_ids:
+                                    break
+
+                pkgs.update((repo, x, repo_db,) for x in pkg_ids)
+
+        # now filter
+        pkgs = self._pk_filter_pkgs(pkgs, filters)
+        pkgs = self._pk_add_pkg_type(pkgs)
+        # now feed stdout
+        self._pk_feed_sorted_pkgs(pkgs)
+
+        self.percentage(100)
+
+    def search_group(self, filters, group):
+
+        self._log_message(__name__, "search_group: got %s and %s" % (
+            filters, group,))
+
+        self.status(STATUS_QUERY)
+        self.allow_cancel(True)
+        self.percentage(0)
+
+        repos = self._get_all_repos()
+
+        entropy_groups = self._entropy.get_package_groups()
+        all_matched_categories = set()
+        for e_data in entropy_groups.values():
+            all_matched_categories.update(e_data['categories'])
+        all_matched_categories = sorted(all_matched_categories)
+
+        entropy_group = self._get_entropy_group(group)
+        # group_data is None when there's no matching group
+        group_data = entropy_groups.get(entropy_group)
+        selected_categories = set()
+        if group_data is not None:
+            selected_categories.update(group_data['categories'])
+
+        # if selected_categories is empty, then pull in pkgs with non matching
+        # category in all_matched_categories
+
+        pkgs = set()
+        count = 0
+        max_count = len(repos)
+        for repo_db, repo in repos:
+            count += 1
+            percent = PackageKitEntropyMixin.get_percentage(count, max_count)
+
+            self._log_message(__name__, "search_group: done %s/100" % (
+                percent,))
+
+            self.percentage(percent)
+            repo_all_cats = repo_db.listAllCategories()
+            if selected_categories:
+                etp_cat_ids = set([cat_id for cat_id, cat_name in \
+                    repo_all_cats if cat_name in selected_categories])
+            else:
+                # get all etp category ids excluding all_matched_categories
+                etp_cat_ids = set([cat_id for cat_id, cat_name in \
+                     repo_all_cats if cat_name not in all_matched_categories])
+
+            for cat_id in etp_cat_ids:
+                pkg_ids = repo_db.listIdPackagesInIdcategory(cat_id)
+                pkgs.update((repo, x, repo_db,) for x in pkg_ids)
+
+        # now filter
+        pkgs = self._pk_filter_pkgs(pkgs, filters)
+        pkgs = self._pk_add_pkg_type(pkgs)
+        # now feed stdout
+        self._pk_feed_sorted_pkgs(pkgs)
+
+    def search_name(self, filters, keys):
+
+        self._log_message(__name__, "search_name: got %s and %s" % (
+            filters, keys,))
+
+        self.status(STATUS_QUERY)
+        self.allow_cancel(True)
+        self.percentage(0)
+
+        repos = self._get_all_repos()
+
+        search_keys = keys.split("&")
+        pkgs = set()
+        count = 0
+        max_count = len(repos)
+        for repo_db, repo in repos:
+            count += 1
+            percent = PackageKitEntropyMixin.get_percentage(count, max_count)
+
+            self._log_message(__name__, "search_name: done %s/100" % (
+                percent,))
+
+            self.percentage(percent)
+            for key in search_keys:
+                pkg_ids = repo_db.searchPackages(key, just_id = True)
+                pkgs.update((repo, x, repo_db,) for x in pkg_ids)
+
+        # now filter
+        pkgs = self._pk_filter_pkgs(pkgs, filters)
+        pkgs = self._pk_add_pkg_type(pkgs)
+        # now feed stdout
+        self._pk_feed_sorted_pkgs(pkgs)
+
+        self.percentage(100)
+
+    def update_packages(self, only_trusted, pk_pkgs):
+
+        self._log_message(__name__, "update_packages: got %s and %s" % (
+            only_trusted, pk_pkgs,))
+
+        self.status(STATUS_RUNNING)
+        self.allow_cancel(True)
+
+        pkgs = []
+        for pk_pkg in pk_pkgs:
+            pkg = self._id_to_etp(pk_pkg)
+            if pkg is None:
+                self.error(ERROR_UPDATE_NOT_FOUND,
+                    "Package %s was not found" % (pk_pkg,))
+                continue
+            pkgs.append((pkg[0], pkg[1], pk_pkg,))
+
+        self._execute_etp_pkgs_install(pkgs, only_trusted)
+
+    def update_system(self, only_trusted):
+
+        self._log_message(__name__, "update_system: got %s" % (
+            only_trusted,))
+
+        self.status(STATUS_RUNNING)
+        self.allow_cancel(True)
+
+        # this is the part that takes time
+        self.percentage(0)
+        try:
+            update, remove, fine, spm_fine = self._entropy.calculate_updates()
+        except SystemDatabaseError as err:
+            self.error(ERROR_DEP_RESOLUTION_FAILED,
+                "System Repository error: %s" % (err,))
+            return
+        self.percentage(100)
+
+        pkgs = []
+        for pkg_id, repo_id in update:
+            repo_db = self._entropy.open_repository(repo_id)
+            pkg = (pkg_id, repo_db)
+            pk_pkg = self._etp_to_id(pkg)
+            pkgs.append((pkg[0], pkg[1], pk_pkg,))
+
+        self._execute_etp_pkgs_install(pkgs, only_trusted)
+
+def main():
+    backend = PackageKitEntropyBackend("")
+    backend.dispatcher(sys.argv[1:])
+
+if __name__ == "__main__":
+    main()
diff --git a/backends/entropy/pk-backend-entropy.c b/backends/entropy/pk-backend-entropy.c
new file mode 100644
index 0000000..775e12b
--- /dev/null
+++ b/backends/entropy/pk-backend-entropy.c
@@ -0,0 +1,507 @@
+/* -*- Mode: C; tab-width: 8; indent-tabs-mode: t; c-basic-offset: 8 -*-
+ *
+ * Copyright (C) 2009 Mounir Lamouri (volkmar) <mounir.lamouri at gmail.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., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
+ */
+
+#include <pk-backend.h>
+#include <pk-backend-spawn.h>
+
+static PkBackendSpawn *spawn = 0;
+static const gchar* BACKEND_FILE = "entropyBackend.py";
+
+/**
+ * backend_initialize:
+ * This should only be run once per backend load, i.e. not every transaction
+ */
+static void
+backend_initialize (PkBackend *backend)
+{
+	egg_debug ("backend: initialize");
+	spawn = pk_backend_spawn_new ();
+	pk_backend_spawn_set_name (spawn, "entropy");
+	/* allowing sigkill as long as no one complain */
+	pk_backend_spawn_set_allow_sigkill (spawn, TRUE);
+}
+
+/**
+ * backend_destroy:
+ * This should only be run once per backend load, i.e. not every transaction
+ */
+static void
+backend_destroy (PkBackend *backend)
+{
+	egg_debug ("backend: destroy");
+	g_object_unref (spawn);
+}
+
+/**
+ * backend_get_groups:
+ */
+static PkBitfield
+backend_get_groups (PkBackend *backend)
+{
+	return pk_bitfield_from_enums (
+			PK_GROUP_ENUM_ACCESSIBILITY,
+			PK_GROUP_ENUM_ACCESSORIES,
+			PK_GROUP_ENUM_ADMIN_TOOLS,
+			PK_GROUP_ENUM_COMMUNICATION,
+			PK_GROUP_ENUM_DESKTOP_GNOME,
+			PK_GROUP_ENUM_DESKTOP_KDE,
+			PK_GROUP_ENUM_DESKTOP_OTHER,
+			PK_GROUP_ENUM_DESKTOP_XFCE,
+			//PK_GROUP_ENUM_EDUCATION,
+			PK_GROUP_ENUM_FONTS,
+			PK_GROUP_ENUM_GAMES,
+			PK_GROUP_ENUM_GRAPHICS,
+			PK_GROUP_ENUM_INTERNET,
+			PK_GROUP_ENUM_LEGACY,
+			PK_GROUP_ENUM_LOCALIZATION,
+			//PK_GROUP_ENUM_MAPS,
+			PK_GROUP_ENUM_MULTIMEDIA,
+			PK_GROUP_ENUM_NETWORK,
+			PK_GROUP_ENUM_OFFICE,
+			PK_GROUP_ENUM_OTHER,
+			PK_GROUP_ENUM_POWER_MANAGEMENT,
+			PK_GROUP_ENUM_PROGRAMMING,
+			//PK_GROUP_ENUM_PUBLISHING,
+			PK_GROUP_ENUM_REPOS,
+			PK_GROUP_ENUM_SECURITY,
+			PK_GROUP_ENUM_SERVERS,
+			PK_GROUP_ENUM_SYSTEM,
+			PK_GROUP_ENUM_VIRTUALIZATION,
+			PK_GROUP_ENUM_SCIENCE,
+			PK_GROUP_ENUM_DOCUMENTATION,
+			//PK_GROUP_ENUM_ELECTRONICS,
+			//PK_GROUP_ENUM_COLLECTIONS,
+			//PK_GROUP_ENUM_VENDOR,
+			//PK_GROUP_ENUM_NEWEST,
+			//PK_GROUP_ENUM_UNKNOWN,
+			-1);
+}
+
+/**
+ * backend_get_filters:
+ */
+static PkBitfield
+backend_get_filters (PkBackend *backend)
+{
+	return pk_bitfield_from_enums (
+			PK_FILTER_ENUM_INSTALLED,
+			PK_FILTER_ENUM_FREE,
+			PK_FILTER_ENUM_NEWEST,
+			-1);
+	/*
+	 * These filters are candidate for further add:
+	 * PK_FILTER_ENUM_GUI	(need new PROPERTIES entry)
+	 * PK_FILTER_ENUM_ARCH (need some work, see ML)
+	 * PK_FILTER_ENUM_SOURCE (need some work/support, see ML)
+	 * PK_FILTER_ENUM_COLLECTIONS (need new PROPERTIES entry)
+	 * PK_FILTER_ENUM_APPLICATION (need new PROPERTIES entry)
+	 */
+}
+
+/**
+ * backend_get_roles:
+ */
+static PkBitfield
+backend_get_roles (PkBackend *backend)
+{
+	PkBitfield roles;
+	roles = pk_bitfield_from_enums (
+		PK_ROLE_ENUM_CANCEL,
+		PK_ROLE_ENUM_GET_DEPENDS,
+		PK_ROLE_ENUM_GET_DETAILS,
+		PK_ROLE_ENUM_GET_FILES,
+		PK_ROLE_ENUM_GET_REQUIRES,
+		PK_ROLE_ENUM_GET_PACKAGES,
+		//PK_ROLE_ENUM_WHAT_PROVIDES,
+		PK_ROLE_ENUM_GET_UPDATES,
+		PK_ROLE_ENUM_GET_UPDATE_DETAIL,
+		PK_ROLE_ENUM_INSTALL_PACKAGES,
+		//PK_ROLE_ENUM_INSTALL_FILES,
+		//PK_ROLE_ENUM_INSTALL_SIGNATURE,
+		PK_ROLE_ENUM_REFRESH_CACHE,
+		PK_ROLE_ENUM_REMOVE_PACKAGES,
+		PK_ROLE_ENUM_DOWNLOAD_PACKAGES,
+		PK_ROLE_ENUM_RESOLVE,
+		PK_ROLE_ENUM_SEARCH_DETAILS,
+		PK_ROLE_ENUM_SEARCH_FILE,
+		PK_ROLE_ENUM_SEARCH_GROUP,
+		PK_ROLE_ENUM_SEARCH_NAME,
+		PK_ROLE_ENUM_UPDATE_PACKAGES,
+		PK_ROLE_ENUM_UPDATE_SYSTEM,
+		PK_ROLE_ENUM_GET_REPO_LIST,
+		PK_ROLE_ENUM_REPO_ENABLE,
+		//PK_ROLE_ENUM_REPO_SET_DATA,
+		PK_ROLE_ENUM_GET_CATEGORIES,
+		//PK_ROLE_ENUM_SIMULATE_INSTALL_FILES,
+		//PK_ROLE_ENUM_SIMULATE_INSTALL_PACKAGES,
+		//PK_ROLE_ENUM_SIMULATE_UPDATE_PACKAGES,
+		//PK_ROLE_ENUM_SIMULATE_REMOVE_PACKAGES,
+		-1);
+
+	return roles;
+}
+
+/**
+ * backend_cancel:
+ */
+static void
+backend_cancel (PkBackend *backend)
+{
+	/* this feels bad... */
+	pk_backend_spawn_kill (spawn);
+}
+
+/**
+ * backend_download_packages:
+ */
+static void
+backend_download_packages (PkBackend *backend, gchar **package_ids, const gchar *directory)
+{
+	gchar *package_ids_temp;
+
+	/* send the complete list as stdin */
+	package_ids_temp = pk_package_ids_to_string (package_ids);
+	pk_backend_spawn_helper (spawn, BACKEND_FILE, "download-packages", directory, package_ids_temp, NULL);
+	g_free (package_ids_temp);
+}
+
+/**
+ * pk_backend_get_categories:
+ */
+static void
+backend_get_categories (PkBackend *backend)
+{
+	pk_backend_spawn_helper (spawn, BACKEND_FILE, "get-categories", NULL);
+}
+
+/**
+ * backend_get_depends:
+ */
+static void
+backend_get_depends (PkBackend *backend, PkBitfield filters, gchar **package_ids, gboolean recursive)
+{
+	gchar *filters_text;
+	gchar *package_ids_temp;
+
+	package_ids_temp = pk_package_ids_to_string (package_ids);
+	filters_text = pk_filter_bitfield_to_string (filters);
+	pk_backend_spawn_helper (spawn, BACKEND_FILE, "get-depends", filters_text, package_ids_temp, pk_backend_bool_to_string (recursive), NULL);
+	g_free (package_ids_temp);
+	g_free (filters_text);
+}
+
+/**
+ * backend_get_details:
+ */
+static void
+backend_get_details (PkBackend *backend, gchar **package_ids)
+{
+	gchar *package_ids_temp;
+
+	package_ids_temp = pk_package_ids_to_string (package_ids);
+	pk_backend_spawn_helper (spawn, BACKEND_FILE, "get-details", package_ids_temp, NULL);
+	g_free (package_ids_temp);
+}
+
+/**
+ * backend_get_distro_upgrades:
+ */
+static void
+backend_get_distro_upgrades (PkBackend *backend)
+{
+	pk_backend_spawn_helper (spawn, BACKEND_FILE, "get-distro-upgrades", NULL);
+}
+
+/**
+ * backend_get_files:
+ */
+static void
+backend_get_files (PkBackend *backend, gchar **package_ids)
+{
+	gchar *package_ids_temp;
+
+	package_ids_temp = pk_package_ids_to_string (package_ids);
+	pk_backend_spawn_helper (spawn, BACKEND_FILE, "get-files", package_ids_temp, NULL);
+	g_free (package_ids_temp);
+}
+
+/**
+ * backend_get_update_detail:
+ */
+static void
+backend_get_update_detail (PkBackend *backend, gchar **package_ids)
+{
+	gchar *package_ids_temp;
+
+	package_ids_temp = pk_package_ids_to_string (package_ids);
+	pk_backend_spawn_helper (spawn, BACKEND_FILE, "get-update-detail", package_ids_temp, NULL);
+	g_free (package_ids_temp);
+}
+
+/**
+ * backend_get_updates:
+ */
+static void
+backend_get_updates (PkBackend *backend, PkBitfield filters)
+{
+	gchar *filters_text;
+
+	filters_text = pk_filter_bitfield_to_string (filters);
+	pk_backend_spawn_helper (spawn, BACKEND_FILE, "get-updates", filters_text, NULL);
+	g_free (filters_text);
+}
+
+/**
+ * backend_install_packages:
+ */
+static void
+backend_install_packages (PkBackend *backend, gboolean only_trusted, gchar **package_ids)
+{
+	gchar *package_ids_temp;
+
+	/* send the complete list as stdin */
+	package_ids_temp = pk_package_ids_to_string (package_ids);
+	pk_backend_spawn_helper (spawn, BACKEND_FILE, "install-packages", pk_backend_bool_to_string (only_trusted), package_ids_temp, NULL);
+	g_free (package_ids_temp);
+}
+
+/**
+ * backend_refresh_cache:
+ */
+static void
+backend_refresh_cache (PkBackend *backend, gboolean force)
+{ 
+	/* check network state */
+	if (!pk_backend_is_online (backend)) {
+		pk_backend_error_code (backend, PK_ERROR_ENUM_NO_NETWORK, "Cannot refresh cache whilst offline");
+		pk_backend_finished (backend);
+		return;
+	}
+
+	pk_backend_spawn_helper (spawn, BACKEND_FILE, "refresh-cache", pk_backend_bool_to_string (force), NULL);
+}
+
+/**
+ * backend_remove_packages:
+ */
+static void
+backend_remove_packages (PkBackend *backend, gchar **package_ids, gboolean allow_deps, gboolean autoremove)
+{
+	gchar *package_ids_temp;
+
+	package_ids_temp = pk_package_ids_to_string (package_ids);
+	pk_backend_spawn_helper (spawn, BACKEND_FILE, "remove-packages", pk_backend_bool_to_string (allow_deps), pk_backend_bool_to_string (autoremove), package_ids_temp, NULL);
+	g_free (package_ids_temp);
+}
+
+/**
+ * pk_backend_repo_enable:
+ */
+static void
+backend_repo_enable (PkBackend *backend, const gchar *rid, gboolean enabled)
+{
+	pk_backend_spawn_helper (spawn, BACKEND_FILE, "repo-enable", rid, pk_backend_bool_to_string (enabled), NULL);
+}
+
+/**
+ * pk_backend_resolve:
+ */
+static void
+backend_resolve (PkBackend *backend, PkBitfield filters, gchar **package_ids)
+{
+	gchar *filters_text;
+	gchar *package_ids_temp;
+
+	filters_text = pk_filter_bitfield_to_string (filters);
+	package_ids_temp = pk_package_ids_to_string (package_ids);
+	pk_backend_spawn_helper (spawn, BACKEND_FILE, "resolve", filters_text, package_ids_temp, NULL);
+	g_free (package_ids_temp);
+	g_free (filters_text);
+}
+
+/**
+ * pk_backend_search_details:
+ */
+static void
+backend_search_details (PkBackend *backend, PkBitfield filters, gchar **values)
+{
+	gchar *filters_text;
+	gchar *search;
+	filters_text = pk_filter_bitfield_to_string (filters);
+	search = g_strjoinv ("&", values);
+	pk_backend_spawn_helper (spawn, BACKEND_FILE, "search-details", filters_text, search, NULL);
+	g_free (filters_text);
+	g_free (search);
+}
+
+/**
+ * backend_search_files:
+ */
+static void
+backend_search_files (PkBackend *backend, PkBitfield filters, gchar **values)
+{
+	gchar *filters_text;
+	gchar *search;
+	filters_text = pk_filter_bitfield_to_string (filters);
+	search = g_strjoinv ("&", values);
+	pk_backend_spawn_helper (spawn, BACKEND_FILE, "search-file", filters_text, search, NULL);
+	g_free (filters_text);
+	g_free (search);
+}
+
+/**
+ * pk_backend_search_groups:
+ */
+static void
+backend_search_groups (PkBackend *backend, PkBitfield filters, gchar **values)
+{ 
+	gchar *filters_text;
+	gchar *search;
+	filters_text = pk_filter_bitfield_to_string (filters);
+	search = g_strjoinv ("&", values);
+	pk_backend_spawn_helper (spawn, BACKEND_FILE, "search-group", filters_text, search, NULL);
+	g_free (filters_text);
+	g_free (search);
+}
+
+/**
+ * backend_search_names:
+ */
+static void
+backend_search_names (PkBackend *backend, PkBitfield filters, gchar **values)
+{
+	gchar *filters_text;
+	gchar *search;
+	filters_text = pk_filter_bitfield_to_string (filters);
+	search = g_strjoinv ("&", values);
+	pk_backend_spawn_helper (spawn, BACKEND_FILE, "search-name", filters_text, search, NULL);
+	g_free (filters_text);
+	g_free (search);
+}
+
+/**
+ * backend_update_packages:
+ */
+static void
+backend_update_packages (PkBackend *backend, gboolean only_trusted, gchar **package_ids)
+{
+	gchar *package_ids_temp;
+
+	/* send the complete list as stdin */
+	package_ids_temp = pk_package_ids_to_string (package_ids);
+	pk_backend_spawn_helper (spawn, BACKEND_FILE, "update-packages", pk_backend_bool_to_string (only_trusted), package_ids_temp, NULL);
+	g_free (package_ids_temp);
+}
+
+/**
+ * backend_get_packages:
+ */
+static void
+backend_get_packages (PkBackend *backend, PkBitfield filters)
+{
+	gchar *filters_text;
+
+	filters_text = pk_filter_bitfield_to_string (filters);
+	pk_backend_spawn_helper (spawn, BACKEND_FILE, "get-packages", filters_text, NULL);
+	g_free (filters_text);
+}
+
+/**
+ * pk_backend_get_repo_list:
+ */
+static void
+backend_get_repo_list (PkBackend *backend, PkBitfield filters)
+{
+	gchar *filters_text;
+
+	filters_text = pk_filter_bitfield_to_string (filters);
+	pk_backend_spawn_helper (spawn, BACKEND_FILE, "get-repo-list", filters_text, NULL);
+	g_free (filters_text);
+}
+
+/**
+ * backend_get_requires:
+ */
+static void
+backend_get_requires (PkBackend *backend, PkBitfield filters, gchar **package_ids, gboolean recursive)
+{ 
+	gchar *package_ids_temp;
+	gchar *filters_text;
+
+	package_ids_temp = pk_package_ids_to_string (package_ids);
+	filters_text = pk_filter_bitfield_to_string (filters);
+	pk_backend_spawn_helper (spawn, BACKEND_FILE, "get-requires", filters_text, package_ids_temp, pk_backend_bool_to_string (recursive), NULL);
+	g_free (filters_text);
+	g_free (package_ids_temp);
+}
+
+/**
+ * backend_update_system:
+ */
+static void
+backend_update_system (PkBackend *backend, gboolean only_trusted)
+{
+	pk_backend_spawn_helper (spawn, BACKEND_FILE, "update-system", pk_backend_bool_to_string (only_trusted), NULL);
+}
+
+PK_BACKEND_OPTIONS (
+	"Entropy",				/* description */
+	"Fabio Erculiani (lxnay) <lxnay at sabayon.org>",	/* author */
+	backend_initialize,					/* initalize */
+	backend_destroy,					/* destroy */
+	backend_get_groups,					/* get_groups */
+	backend_get_filters,				/* get_filters */
+	backend_get_roles,					/* get_roles */
+	NULL,								/* get_mime_types */
+	backend_cancel,						/* cancel */
+	backend_download_packages,			/* download_packages */
+	backend_get_categories,				/* get_categories */
+	backend_get_depends,				/* get_depends */
+	backend_get_details,				/* get_details */
+	backend_get_distro_upgrades,		/* get_distro_upgrades */
+	backend_get_files,					/* get_files */
+	backend_get_packages,				/* get_packages */
+	backend_get_repo_list,				/* get_repo_list */
+	backend_get_requires,				/* get_requires */
+	backend_get_update_detail,			/* get_update_detail */
+	backend_get_updates,				/* get_updates */
+	NULL,								/* install_files */
+	backend_install_packages,			/* install_packages */
+	NULL,								/* install_signature */
+	backend_refresh_cache,				/* refresh_cache */
+	backend_remove_packages,			/* remove_packages */
+	backend_repo_enable,				/* repo_enable */
+	NULL,								/* repo_set_data */
+	backend_resolve,					/* resolve */
+	NULL,								/* rollback */
+	backend_search_details,				/* search_details */
+	backend_search_files,				/* search_file */
+	backend_search_groups,				/* search_group */
+	backend_search_names,				/* search_name */
+	backend_update_packages,			/* update_packages */
+	backend_update_system,				/* update_system */
+	NULL,								/* what_provides */
+	NULL,								/* simulate_install_files */
+	NULL,								/* simulate_install_packages */
+	NULL,								/* simulate_remove_packages */
+	NULL								/* simulate_update_packages */
+);
+
diff --git a/configure.ac b/configure.ac
index 7424fae..0c00318 100644
--- a/configure.ac
+++ b/configure.ac
@@ -541,6 +541,7 @@ AC_ARG_ENABLE(aptcc, AS_HELP_STRING([--enable-aptcc],[use the APTcc backend]),en
 AC_ARG_ENABLE(box, AS_HELP_STRING([--enable-box],[use the BOX backend]),enable_box=$enableval,enable_box=no)
 AC_ARG_ENABLE(conary, AS_HELP_STRING([--enable-conary],[use the CONARY backend]),enable_conary=$enableval,enable_conary=no)
 AC_ARG_ENABLE(dummy, AS_HELP_STRING([--enable-dummy],[use the dummy backend]),enable_dummy=$enableval,enable_dummy=yes)
+AC_ARG_ENABLE(entropy, AS_HELP_STRING([--enable-entropy],[use the entropy backend]),enable_entropy=$enableval,enable_entropy=no)
 AC_ARG_ENABLE(opkg, AS_HELP_STRING([--enable-opkg],[use the OPKG backend]),enable_opkg=$enableval,enable_opkg=no)
 AC_ARG_ENABLE(pisi, AS_HELP_STRING([--enable-pisi],[use the PiSi backend]),enable_pisi=$enableval,enable_pisi=no)
 AC_ARG_ENABLE(poldek, AS_HELP_STRING([--enable-poldek],[use the poldek backend]),enable_poldek=$enableval,enable_poldek=no)
@@ -560,6 +561,7 @@ AM_CONDITIONAL(BACKEND_TYPE_APTCC, [test x$enable_aptcc = xyes])
 AM_CONDITIONAL(BACKEND_TYPE_BOX, [test x$enable_box = xyes])
 AM_CONDITIONAL(BACKEND_TYPE_CONARY, [test x$enable_conary = xyes])
 AM_CONDITIONAL(BACKEND_TYPE_DUMMY, [test x$enable_dummy = xyes])
+AM_CONDITIONAL(BACKEND_TYPE_ENTROPY, [test x$enable_entropy = xyes])
 AM_CONDITIONAL(BACKEND_TYPE_OPKG, [test x$enable_opkg = xyes])
 AM_CONDITIONAL(BACKEND_TYPE_PISI, [test x$enable_pisi = xyes])
 AM_CONDITIONAL(BACKEND_TYPE_POLDEK, [test x$enable_poldek = xyes])
@@ -632,7 +634,7 @@ dnl ---------------------------------------------------------------------------
 AC_ARG_WITH([default_backend],
 	    AS_HELP_STRING([--with-default-backend=<option>],
 			   [Default backend to use
-                           alpm,apt,aptcc,box,conary,dummy,opkg,pisi,portage,ports,razor,slapt,smart,urpmi,yum,zypp (dummy)]))
+                           alpm,apt,aptcc,box,conary,dummy,entropy,opkg,pisi,portage,ports,razor,slapt,smart,urpmi,yum,zypp (dummy)]))
 # default to a sane option for the installed tool
 if test x$with_default_backend = x; then
 	if test -f /usr/bin/yum ; then
@@ -659,6 +661,8 @@ if test x$with_default_backend = x; then
 		with_default_backend=urpmi
 	elif test -f /usr/bin/zypper ; then
 		with_default_backend=zypp
+	elif test -d /usr/lib/entropy ; then
+		with_default_backend=entropy
 	elif test -f /usr/bin/emerge ; then
 		with_default_backend=portage
 	elif test -f /usr/local/sbin/portupgrade ; then
@@ -810,6 +814,7 @@ backends/aptcc/Makefile
 backends/box/Makefile
 backends/conary/Makefile
 backends/dummy/Makefile
+backends/entropy/Makefile
 backends/opkg/Makefile
 backends/slapt/Makefile
 backends/smart/Makefile
@@ -884,6 +889,7 @@ echo "
         BOX backend:               ${enable_box}
         CONARY backend:            ${enable_conary}
         dummy backend:             ${enable_dummy}
+        Entropy backend:           ${enable_entropy}
         OPKG backend:              ${enable_opkg}
         Razor backend:             ${enable_razor}
         PiSi backend:              ${enable_pisi}
commit 30658b7058ed5cba9299bfeb192e40740041b264
Author: Fabio Erculiani <lxnay at sabayon.org>
Date:   Tue Feb 2 22:46:34 2010 +0100

    portage: fix backend_update_packages() spawn_helper argument was missing

diff --git a/backends/portage/pk-backend-portage.c b/backends/portage/pk-backend-portage.c
index e2ae201..8b16934 100644
--- a/backends/portage/pk-backend-portage.c
+++ b/backends/portage/pk-backend-portage.c
@@ -339,7 +339,7 @@ backend_update_packages (PkBackend *backend, gboolean only_trusted, gchar **pack
 
 	/* send the complete list as stdin */
 	package_ids_temp = pk_package_ids_to_string (package_ids);
-	pk_backend_spawn_helper (spawn, BACKEND_FILE, "update-packages", package_ids_temp, NULL);
+	pk_backend_spawn_helper (spawn, BACKEND_FILE, "update-packages", pk_backend_bool_to_string (only_trusted), package_ids_temp, NULL);
 	g_free (package_ids_temp);
 }
 
commit 6501f03327776e3a4becdc6a011e7fde8c0358c3
Author: Richard Hughes <richard at hughsie.com>
Date:   Tue Feb 2 12:46:42 2010 +0000

    trivial: scale lxnay to fit on the page...

diff --git a/docs/html/img/author-lxnay.png b/docs/html/img/author-lxnay.png
index f87c18e..d454111 100644
Binary files a/docs/html/img/author-lxnay.png and b/docs/html/img/author-lxnay.png differ
commit 0fa913c6b546f24f36ec0967006f7cd70de50a35
Author: Richard Hughes <richard at hughsie.com>
Date:   Tue Feb 2 12:34:53 2010 +0000

    Define a new error code for when the user declines the simulation

diff --git a/lib/packagekit-glib2/pk-client.h b/lib/packagekit-glib2/pk-client.h
index 6ce7811..5ad93dc 100644
--- a/lib/packagekit-glib2/pk-client.h
+++ b/lib/packagekit-glib2/pk-client.h
@@ -54,6 +54,7 @@ G_BEGIN_DECLS
  * @PK_CLIENT_ERROR_INVALID_INPUT: the package_id is invalid
  * @PK_CLIENT_ERROR_INVALID_FILE: the file is invalid
  * @PK_CLIENT_ERROR_NOT_SUPPORTED: the action is not supported
+ * @PK_CLIENT_ERROR_DECLINED_SIMULATION: the simulation was declined by the user
  *
  * Errors that can be thrown
  */
@@ -67,7 +68,8 @@ typedef enum
 	PK_CLIENT_ERROR_CANNOT_START_DAEMON,
 	PK_CLIENT_ERROR_INVALID_INPUT,
 	PK_CLIENT_ERROR_INVALID_FILE,
-	PK_CLIENT_ERROR_NOT_SUPPORTED
+	PK_CLIENT_ERROR_NOT_SUPPORTED,
+	PK_CLIENT_ERROR_DECLINED_SIMULATION
 } PkClientError;
 
 typedef struct _PkClientPrivate		PkClientPrivate;
diff --git a/lib/packagekit-glib2/pk-task.c b/lib/packagekit-glib2/pk-task.c
index c5dc34a..c5b6306 100644
--- a/lib/packagekit-glib2/pk-task.c
+++ b/lib/packagekit-glib2/pk-task.c
@@ -628,7 +628,7 @@ pk_task_user_declined_idle_cb (PkTaskState *state)
 
 	/* the introduction is finished */
 	if (state->simulate) {
-		error = g_error_new (PK_CLIENT_ERROR, PK_CLIENT_ERROR_FAILED, "user declined simulation");
+		error = g_error_new (PK_CLIENT_ERROR, PK_CLIENT_ERROR_DECLINED_SIMULATION, "user declined simulation");
 		pk_task_generic_state_finish (state, error);
 		g_error_free (error);
 		goto out;
commit 754dae752962f2bd2000406b340342f499c17087
Author: Richard Hughes <richard at hughsie.com>
Date:   Tue Feb 2 10:40:24 2010 +0000

    Add a new library function: pk_package_sack_filter_by_info()

diff --git a/lib/packagekit-glib2/pk-package-sack.c b/lib/packagekit-glib2/pk-package-sack.c
index 88abda9..af61ed6 100644
--- a/lib/packagekit-glib2/pk-package-sack.c
+++ b/lib/packagekit-glib2/pk-package-sack.c
@@ -144,6 +144,43 @@ pk_package_sack_get_array (PkPackageSack *sack)
 }
 
 /**
+ * pk_package_sack_filter_by_info:
+ * @sack: a valid #PkPackageSack instance
+ * @info: a %PkInfoEnum value to match
+ *
+ * Returns a new package sack which only matches packages that match the
+ * specified info enum value.
+ *
+ * Return value: a new #PkPackageSack, free with g_object_unref()
+ *
+ * Since: 0.6.2
+ **/
+PkPackageSack *
+pk_package_sack_filter_by_info (PkPackageSack *sack, PkInfoEnum info)
+{
+	PkPackageSack *results;
+	PkPackage *package;
+	PkInfoEnum info_tmp;
+	guint i;
+	PkPackageSackPrivate *priv = sack->priv;
+
+	g_return_val_if_fail (PK_IS_PACKAGE_SACK (sack), NULL);
+
+	/* create new sack */
+	results = pk_package_sack_new ();
+
+	/* add each that matches the info enum */
+	for (i = 0; i < priv->array->len; i++) {
+		package = g_ptr_array_index (priv->array, i);
+		info_tmp = pk_package_get_info (package);
+		if (info_tmp == info)
+			pk_package_sack_add_package (results, package);
+	}
+
+	return results;
+}
+
+/**
  * pk_package_sack_add_package:
  * @sack: a valid #PkPackageSack instance
  * @package: a valid #PkPackage instance
diff --git a/lib/packagekit-glib2/pk-package-sack.h b/lib/packagekit-glib2/pk-package-sack.h
index 8655d41..fd306c8 100644
--- a/lib/packagekit-glib2/pk-package-sack.h
+++ b/lib/packagekit-glib2/pk-package-sack.h
@@ -98,6 +98,8 @@ gboolean	 pk_package_sack_remove_package_by_id	(PkPackageSack		*sack,
 							 const gchar		*package_id);
 PkPackage	*pk_package_sack_find_by_id		(PkPackageSack		*sack,
 							 const gchar		*package_id);
+PkPackageSack	*pk_package_sack_filter_by_info		(PkPackageSack		*sack,
+							 PkInfoEnum		 info);
 guint64		 pk_package_sack_get_total_bytes	(PkPackageSack		*sack);
 
 gboolean	 pk_package_sack_merge_generic_finish	(PkPackageSack		*sack,
commit 42bd6832a68864b3baac1f1d9d751f03da8a0a49
Author: Richard Hughes <richard at hughsie.com>
Date:   Tue Feb 2 10:35:56 2010 +0000

    trivial: re-instate pk_package_sack_get_size()

diff --git a/lib/packagekit-glib2/pk-package-sack.c b/lib/packagekit-glib2/pk-package-sack.c
index 8af4e7f..88abda9 100644
--- a/lib/packagekit-glib2/pk-package-sack.c
+++ b/lib/packagekit-glib2/pk-package-sack.c
@@ -80,6 +80,24 @@ pk_package_sack_clear (PkPackageSack *sack)
 }
 
 /**
+ * pk_package_sack_get_size:
+ * @sack: a valid #PkPackageSack instance
+ *
+ * Gets the number of packages in the sack
+ *
+ * Return value: the number of packages in the sack
+ *
+ * Since: 0.5.2
+ **/
+guint
+pk_package_sack_get_size (PkPackageSack *sack)
+{
+	g_return_val_if_fail (PK_IS_PACKAGE_SACK (sack), 0);
+
+	return sack->priv->array->len;
+}
+
+/**
  * pk_package_sack_get_ids:
  * @sack: a valid #PkPackageSack instance
  *
diff --git a/lib/packagekit-glib2/pk-package-sack.h b/lib/packagekit-glib2/pk-package-sack.h
index 12e56ce..8655d41 100644
--- a/lib/packagekit-glib2/pk-package-sack.h
+++ b/lib/packagekit-glib2/pk-package-sack.h
@@ -83,6 +83,7 @@ void		 pk_package_sack_test			(gpointer		 user_data);
 /* managing the array */
 void		 pk_package_sack_clear			(PkPackageSack		*sack);
 gchar		**pk_package_sack_get_ids		(PkPackageSack		*sack);
+guint		 pk_package_sack_get_size		(PkPackageSack		*sack);
 GPtrArray	*pk_package_sack_get_array		(PkPackageSack		*sack);
 void		 pk_package_sack_sort			(PkPackageSack		*sack,
 							 PkPackageSackSortType	 type);
commit 1f0f2ba0462b3a84607a7bf2e2db7c7018dd590b
Author: Fabio Erculiani <lxnay at sabayon.org>
Date:   Tue Feb 2 13:14:30 2010 +0100

    add myself to developers' page

diff --git a/docs/html/img/author-lxnay.png b/docs/html/img/author-lxnay.png
new file mode 100644
index 0000000..f87c18e
Binary files /dev/null and b/docs/html/img/author-lxnay.png differ
diff --git a/docs/html/pk-authors.html b/docs/html/pk-authors.html
index 3b95d17..c5fb82a 100644
--- a/docs/html/pk-authors.html
+++ b/docs/html/pk-authors.html
@@ -331,6 +331,21 @@
  </td>
 </tr>
 
+<tr>
+ <td>
+  <img src="img/author-lxnay.png" alt=""/><!-- image should be 120px wide -->
+ </td>
+ <td>
+  <h2>Fabio Erculiani</h2>
+  <p>
+    Fabio is the <a href='http://www.sabayon.org'>Sabayon</a> Linux project leader, freelance IT consultant and student at the <a href="http://www.unitn.it">University of Trento</a> (Italy). He is also a <a href='http://www.gentoo.org/'>Gentoo</a> developer. He began helping out on the Portage backend and is also responsible of the implementation of the Entropy one.
+  </p>
+  <p>
+   <b>Responsible for: portage backend, entropy backend</b>
+  </p>
+ </td>
+</tr>
+
 </table>
 
 <p>Back to the <a href="index.html">main page</a></p>
commit 5b2749861754d84dfba250031bc500f4ac883993
Author: Fabio Erculiani <lxnay at sabayon.org>
Date:   Tue Feb 2 12:59:05 2010 +0100

    fix PackageKitPortageBackend.get_update_detail()
    
    Signed-off-by: Fabio Erculiani <lxnay at sabayon.org>

diff --git a/backends/portage/portageBackend.py b/backends/portage/portageBackend.py
index b316bdd..c250abd 100755
--- a/backends/portage/portageBackend.py
+++ b/backends/portage/portageBackend.py
@@ -1078,10 +1078,12 @@ class PackageKitPortageBackend(PackageKitBaseBackend):
             # temporarily set vendor_url = homepage
             homepage = self.get_metadata(cpv, ["HOMEPAGE"])[0]
             vendor_url = homepage
+            issued = ""
+            updated = ""
 
             self.update_detail(pkg, updates, obsoletes, vendor_url, bugzilla_url,
                     cve_url, "none", "No update text", "No ChangeLog",
-                    UPDATE_STATE_STABLE, None, None)
+                    UPDATE_STATE_STABLE, issued, updated)
 
     def get_updates(self, filters):
         # NOTES:
commit 6af40e600d9b78d5ed926d25d7f0f0efbd5eaa1b
Author: Richard Hughes <richard at hughsie.com>
Date:   Tue Feb 2 09:00:18 2010 +0000

    Add the polkit backend library in LIBADD, not LDFLAGS. Fixes fd#26373

diff --git a/src/Makefile.am b/src/Makefile.am
index f893abb..80d5caf 100644
--- a/src/Makefile.am
+++ b/src/Makefile.am
@@ -193,12 +193,12 @@ libpackagekit_action_lookup_la_CFLAGS =				\
 libpackagekit_action_lookup_la_LDFLAGS =			\
 	-export_dynamic -avoid-version -module -no-undefined	\
 	-export-symbols-regex '^g_io_module_(load|unload)'	\
-	$(POLKIT_BACKEND_1_LIBS)				\
 	$(NULL)
 
 libpackagekit_action_lookup_la_LIBADD =				\
 	$(GLIB_LIBS)						\
 	$(PK_GLIB2_LIBS)					\
+	$(POLKIT_BACKEND_1_LIBS)				\
 	$(NULL)
 endif
 
commit 5b90d74aca391931d4dea7375ae511e1ed38ea36
Author: Richard Hughes <richard at hughsie.com>
Date:   Mon Feb 1 15:14:04 2010 +0000

    yum: add simulate-install-packages, simulate-update-packages and simulate-remove-packages

diff --git a/backends/yum/pk-backend-yum.c b/backends/yum/pk-backend-yum.c
index fc3defa..4a3a16e 100644
--- a/backends/yum/pk-backend-yum.c
+++ b/backends/yum/pk-backend-yum.c
@@ -191,6 +191,9 @@ backend_get_roles (PkBackend *backend)
 		PK_ROLE_ENUM_REPO_SET_DATA,
 		PK_ROLE_ENUM_GET_CATEGORIES,
 		PK_ROLE_ENUM_SIMULATE_INSTALL_FILES,
+		PK_ROLE_ENUM_SIMULATE_INSTALL_PACKAGES,
+		PK_ROLE_ENUM_SIMULATE_UPDATE_PACKAGES,
+		PK_ROLE_ENUM_SIMULATE_REMOVE_PACKAGES,
 		-1);
 
 	/* only add GetDistroUpgrades if the binary is present */
@@ -347,6 +350,48 @@ backend_install_packages (PkBackend *backend, gboolean only_trusted, gchar **pac
 }
 
 /**
+ * backend_simulate_remove_packages:
+ */
+static void
+backend_simulate_remove_packages (PkBackend *backend, gchar **package_ids)
+{
+	gchar *package_ids_temp;
+
+	/* send the complete list as stdin */
+	package_ids_temp = pk_package_ids_to_string (package_ids);
+	pk_backend_spawn_helper (spawn, "yumBackend.py", "simulate-remove-packages", package_ids_temp, NULL);
+	g_free (package_ids_temp);
+}
+
+/**
+ * backend_simulate_update_packages:
+ */
+static void
+backend_simulate_update_packages (PkBackend *backend, gchar **package_ids)
+{
+	gchar *package_ids_temp;
+
+	/* send the complete list as stdin */
+	package_ids_temp = pk_package_ids_to_string (package_ids);
+	pk_backend_spawn_helper (spawn, "yumBackend.py", "simulate-update-packages", package_ids_temp, NULL);
+	g_free (package_ids_temp);
+}
+
+/**
+ * backend_simulate_install_packages:
+ */
+static void
+backend_simulate_install_packages (PkBackend *backend, gchar **package_ids)
+{
+	gchar *package_ids_temp;
+
+	/* send the complete list as stdin */
+	package_ids_temp = pk_package_ids_to_string (package_ids);
+	pk_backend_spawn_helper (spawn, "yumBackend.py", "simulate-install-packages", package_ids_temp, NULL);
+	g_free (package_ids_temp);
+}
+
+/**
  * backend_install_files:
  */
 static void
@@ -613,8 +658,8 @@ PK_BACKEND_OPTIONS (
 	backend_update_system,			/* update_system */
 	backend_what_provides,			/* what_provides */
 	backend_simulate_install_files,		/* simulate_install_files */
-	NULL,					/* simulate_install_packages */
-	NULL,					/* simulate_remove_packages */
-	NULL					/* simulate_update_packages */
+	backend_simulate_install_packages,	/* simulate_install_packages */
+	backend_simulate_remove_packages,	/* simulate_remove_packages */
+	backend_simulate_update_packages	/* simulate_update_packages */
 );
 
diff --git a/backends/yum/yumBackend.py b/backends/yum/yumBackend.py
index 3592347..4316150 100755
--- a/backends/yum/yumBackend.py
+++ b/backends/yum/yumBackend.py
@@ -1028,7 +1028,7 @@ class PackageKitYumBackend(PackageKitBaseBackend, PackagekitPackage):
         except Exception, e:
             raise PkError(ERROR_INTERNAL_ERROR, _format_str(traceback.format_exc()))
 
-	# multiple entries
+    # multiple entries
         if len(pkgs) > 1:
             raise PkError(ERROR_INTERNAL_ERROR, "more than one package match for %s" % _format_package_id(package_id))
 
@@ -1501,22 +1501,24 @@ class PackageKitYumBackend(PackageKitBaseBackend, PackagekitPackage):
         else:
             if txmbr:
                 # check all the packages in the transaction if only-trusted
-                if only_trusted:
-                    for t in txmbr:
-                        # ignore transactions that do not have to be checked, e.g. obsoleted
-                        if t.output_state not in self.transaction_sig_check_map:
-                            continue
-                        pkg = t.po
-                        try:
-                            signed = self._is_package_repo_signed(pkg)
-                        except PkError, e:
-                            self.error(e.code, e.details, exit=False)
-                            return
-                        if not signed:
-                            self.error(ERROR_CANNOT_UPDATE_REPO_UNSIGNED, "The package %s will not be updated from unsigned repo %s" % (pkg.name, pkg.repoid), exit=False)
-                            return
+                for t in txmbr:
+                    # ignore transactions that do not have to be checked, e.g. obsoleted
+                    if t.output_state not in self.transaction_sig_check_map:
+                        continue
+                    pkg = t.po
+                    try:
+                        signed = self._is_package_repo_signed(pkg)
+                    except PkError, e:
+                        self.error(e.code, e.details, exit=False)
+                        return
+                    if signed:
+                        continue
+                    if only_trusted:
+                        self.error(ERROR_CANNOT_UPDATE_REPO_UNSIGNED, "The package %s will not be updated from unsigned repo %s" % (pkg.name, pkg.repoid), exit=False)
+                        return
+                    self.message (MESSAGE_UNTRUSTED_PACKAGE, "The package %s from repo %s is untrusted" % (pkg.name, pkg.repoid))
                 try:
-                    self._runYumTransaction(allow_skip_broken=True)
+                    self._runYumTransaction(allow_skip_broken=True, only_simulate=False)
                 except PkError, e:
                     self.error(e.code, e.details, exit=False)
             else:
@@ -1634,10 +1636,15 @@ class PackageKitYumBackend(PackageKitBaseBackend, PackagekitPackage):
         package_list = pkgfilter.post_process()
         self._show_package_list(package_list)
 
-    def install_packages(self, only_trusted, package_ids):
+    def install_packages(self, only_trusted, inst_files):
+        self._install_packages(only_trusted, inst_files)
+
+    def simulate_install_packages(self, inst_files):
+        self._install_packages(False, inst_files, True)
+
+    def _install_packages(self, only_trusted, package_ids, simulate=False):
         '''
         Implement the install-packages functionality
-        This will only work with yum 3.2.4 or higher
         '''
         try:
             self._check_init()
@@ -1686,22 +1693,25 @@ class PackageKitYumBackend(PackageKitBaseBackend, PackagekitPackage):
                     self.error(ERROR_PACKAGE_ALREADY_INSTALLED, "The package %s is already installed" % pkg.name, exit=False)
                     return
         if txmbrs:
-            if only_trusted:
-                for t in txmbrs:
-                    pkg = t.po
-                    # ignore transactions that do not have to be checked, e.g. obsoleted
-                    if t.output_state not in self.transaction_sig_check_map:
-                        continue
-                    try:
-                        signed = self._is_package_repo_signed(pkg)
-                    except PkError, e:
-                        self.error(e.code, e.details, exit=False)
-                        return
-                    if not signed:
-                        self.error(ERROR_CANNOT_INSTALL_REPO_UNSIGNED, "The package %s will not be installed from unsigned repo %s" % (pkg.name, pkg.repoid), exit=False)
-                        return
+            for t in txmbrs:
+                pkg = t.po
+                # ignore transactions that do not have to be checked, e.g. obsoleted
+                if t.output_state not in self.transaction_sig_check_map:
+                    continue
+                try:
+                    signed = self._is_package_repo_signed(pkg)
+                except PkError, e:
+                    self.error(e.code, e.details, exit=False)
+                    return
+                if signed:
+                    continue
+                if only_trusted:
+                    self.error(ERROR_CANNOT_INSTALL_REPO_UNSIGNED, "The package %s will not be installed from unsigned repo %s" % (pkg.name, pkg.repoid), exit=False)
+                    return
+                self.message (MESSAGE_UNTRUSTED_PACKAGE, "The package %s from repo %s is untrusted" % (pkg.name, pkg.repoid))
+
             try:
-                self._runYumTransaction()
+                self._runYumTransaction(only_simulate=simulate)
             except PkError, e:
                 self.error(e.code, e.details, exit=False)
         else:
@@ -1723,6 +1733,12 @@ class PackageKitYumBackend(PackageKitBaseBackend, PackagekitPackage):
                 self.message(MESSAGE_NEWER_PACKAGE_EXISTS, "A newer version of %s is available online." % po.name)
 
     def install_files(self, only_trusted, inst_files):
+        self._install_files(only_trusted, inst_files)
+
+    def simulate_install_files(self, inst_files):
+        self._install_files(False, inst_files, True)
+
+    def _install_files(self, only_trusted, inst_files, simulate=False):
         '''
         Implement the install-files functionality
         Install the package containing the inst_file file
@@ -1875,8 +1891,9 @@ class PackageKitYumBackend(PackageKitBaseBackend, PackagekitPackage):
             if len(self.yumbase.tsInfo) == 0:
                 self.error(ERROR_LOCAL_INSTALL_FAILED, "Can't install %s" % " or ".join(inst_files), exit=False)
                 return
+
             try:
-                self._runYumTransaction()
+                self._runYumTransaction(only_simulate=simulate)
             except PkError, e:
                 self.error(e.code, e.details, exit=False)
                 return
@@ -1902,7 +1919,7 @@ class PackageKitYumBackend(PackageKitBaseBackend, PackagekitPackage):
                             if not self.yumbase.tsInfo.pkgSack:
                                 self.yumbase.tsInfo.pkgSack = MetaSack()
                             try:
-                                self._runYumTransaction()
+                                self._runYumTransaction(only_simulate=simulate)
                             except PkError, e:
                                 self.error(e.code, e.details, exit=False)
                                 return
@@ -1950,6 +1967,12 @@ class PackageKitYumBackend(PackageKitBaseBackend, PackagekitPackage):
         return True
 
     def update_packages(self, only_trusted, package_ids):
+        self._update_packages(only_trusted, package_ids)
+
+    def simulate_update_packages(self, package_ids):
+        self._update_packages(False, package_ids, True)
+
+    def _update_packages(self, only_trusted, package_ids, simulate=False):
         '''
         Implement the install functionality
         This will only work with yum 3.2.4 or higher
@@ -1997,22 +2020,25 @@ class PackageKitYumBackend(PackageKitBaseBackend, PackagekitPackage):
             self.error(ERROR_INTERNAL_ERROR, _format_str(traceback.format_exc()))
         else:
             if txmbrs:
-                if only_trusted:
-                    for t in txmbrs:
-                        # ignore transactions that do not have to be checked, e.g. obsoleted
-                        if t.output_state not in self.transaction_sig_check_map:
-                            continue
-                        pkg = t.po
-                        try:
-                            signed = self._is_package_repo_signed(pkg)
-                        except PkError, e:
-                            self.error(e.code, e.details, exit=False)
-                            return
-                        if not signed:
-                            self.error(ERROR_CANNOT_UPDATE_REPO_UNSIGNED, "The package %s will not be updated from unsigned repo %s" % (pkg.name, pkg.repoid), exit=False)
-                            return
+                for t in txmbrs:
+                    # ignore transactions that do not have to be checked, e.g. obsoleted
+                    if t.output_state not in self.transaction_sig_check_map:
+                        continue
+                    pkg = t.po
+                    try:
+                        signed = self._is_package_repo_signed(pkg)
+                    except PkError, e:
+                        self.error(e.code, e.details, exit=False)
+                        return
+                    if signed:
+                        continue
+                    if only_trusted:
+                        self.error(ERROR_CANNOT_UPDATE_REPO_UNSIGNED, "The package %s will not be updated from unsigned repo %s" % (pkg.name, pkg.repoid), exit=False)
+                        return
+                    self.message (MESSAGE_UNTRUSTED_PACKAGE, "The package %s from repo %s is untrusted" % (pkg.name, pkg.repoid))
+
                 try:
-                    self._runYumTransaction(allow_skip_broken=True)
+                    self._runYumTransaction(allow_skip_broken=True, only_simulate=simulate)
                 except PkError, e:
                     self.error(e.code, e.details, exit=False)
             else:
@@ -2029,7 +2055,7 @@ class PackageKitYumBackend(PackageKitBaseBackend, PackagekitPackage):
                 or (notice and notice.get_metadata().has_key('reboot_suggested') and notice['reboot_suggested'])):
                 self.require_restart(RESTART_SYSTEM, self._pkg_to_id(pkg))
 
-    def _runYumTransaction(self, allow_remove_deps=None, allow_skip_broken=False):
+    def _runYumTransaction(self, allow_remove_deps=None, allow_skip_broken=False, only_simulate=False):
         '''
         Run the yum Transaction
         This will only work with yum 3.2.4 or higher
@@ -2055,60 +2081,79 @@ class PackageKitYumBackend(PackageKitBaseBackend, PackagekitPackage):
             except Exception, e:
                 raise PkError(ERROR_INTERNAL_ERROR, _format_str(traceback.format_exc()))
 
+        # test did succeed
+        self._check_for_reboot()
+        if allow_remove_deps == False:
+            if len(self.yumbase.tsInfo) > 1:
+                retmsg = 'package could not be removed, as other packages depend on it'
+                raise PkError(ERROR_DEP_RESOLUTION_FAILED, retmsg)
+
+        # abort now we have the package list
+        if only_simulate:
+            package_list = []
+            for txmbr in self.yumbase.tsInfo:
+                if txmbr.output_state in TransactionsInfoMap.keys():
+                    info = TransactionsInfoMap[txmbr.output_state]
+                    package_list.append((txmbr.po, info))
+
+            self.percentage(90)
+            self._show_package_list(package_list)
+            self.percentage(100)
+            return
+
         # we did not succeed
         if rc != 2:
             if message.find ("is needed by") != -1:
                 raise PkError(ERROR_DEP_RESOLUTION_FAILED, message)
             if message.find ("empty transaction") != -1:
                 raise PkError(ERROR_NO_PACKAGES_TO_UPDATE, message)
+            raise PkError(ERROR_TRANSACTION_ERROR, message)
+
+        try:
+            rpmDisplay = PackageKitCallback(self)
+            callback = ProcessTransPackageKitCallback(self)
+            self.yumbase.processTransaction(callback=callback,
+                                  rpmDisplay=rpmDisplay)
+        except yum.Errors.YumDownloadError, ye:
+            raise PkError(ERROR_PACKAGE_DOWNLOAD_FAILED, _format_msgs(ye.value))
+        except yum.Errors.YumGPGCheckError, ye:
+            raise PkError(ERROR_BAD_GPG_SIGNATURE, _format_msgs(ye.value))
+        except GPGKeyNotImported, e:
+            keyData = self.yumbase.missingGPGKey
+            if not keyData:
+                raise PkError(ERROR_BAD_GPG_SIGNATURE, "GPG key not imported, and no GPG information was found.")
+            package_id = self._pkg_to_id(keyData['po'])
+            fingerprint = keyData['fingerprint']()
+            hex_fingerprint = "%02x" * len(fingerprint) % tuple(map(ord, fingerprint))
+            # Borrowed from http://mail.python.org/pipermail/python-list/2000-September/053490.html
+
+            self.repo_signature_required(package_id,
+                                         keyData['po'].repoid,
+                                         keyData['keyurl'].replace("file://", ""),
+                                         keyData['userid'],
+                                         keyData['hexkeyid'],
+                                         hex_fingerprint,
+                                         time.ctime(keyData['timestamp']),
+                                         'gpg')
+            raise PkError(ERROR_GPG_FAILURE, "GPG key %s required" % keyData['hexkeyid'])
+        except yum.Errors.YumBaseError, ye:
+            message = _format_msgs(ye.value)
+            if message.find ("conflicts with file") != -1:
+                raise PkError(ERROR_FILE_CONFLICTS, message)
+            if message.find ("rpm_check_debug vs depsolve") != -1:
+                raise PkError(ERROR_PACKAGE_CONFLICTS, message)
             else:
                 raise PkError(ERROR_TRANSACTION_ERROR, message)
-        else:
-            self._check_for_reboot()
-            if allow_remove_deps == False:
-                if len(self.yumbase.tsInfo) > 1:
-                    retmsg = 'package could not be removed, as other packages depend on it'
-                    raise PkError(ERROR_DEP_RESOLUTION_FAILED, retmsg)
-
-            try:
-                rpmDisplay = PackageKitCallback(self)
-                callback = ProcessTransPackageKitCallback(self)
-                self.yumbase.processTransaction(callback=callback,
-                                      rpmDisplay=rpmDisplay)
-            except yum.Errors.YumDownloadError, ye:
-                raise PkError(ERROR_PACKAGE_DOWNLOAD_FAILED, _format_msgs(ye.value))
-            except yum.Errors.YumGPGCheckError, ye:
-                raise PkError(ERROR_BAD_GPG_SIGNATURE, _format_msgs(ye.value))
-            except GPGKeyNotImported, e:
-                keyData = self.yumbase.missingGPGKey
-                if not keyData:
-                    raise PkError(ERROR_BAD_GPG_SIGNATURE, "GPG key not imported, and no GPG information was found.")
-                package_id = self._pkg_to_id(keyData['po'])
-                fingerprint = keyData['fingerprint']()
-                hex_fingerprint = "%02x" * len(fingerprint) % tuple(map(ord, fingerprint))
-                # Borrowed from http://mail.python.org/pipermail/python-list/2000-September/053490.html
-
-                self.repo_signature_required(package_id,
-                                             keyData['po'].repoid,
-                                             keyData['keyurl'].replace("file://", ""),
-                                             keyData['userid'],
-                                             keyData['hexkeyid'],
-                                             hex_fingerprint,
-                                             time.ctime(keyData['timestamp']),
-                                             'gpg')
-                raise PkError(ERROR_GPG_FAILURE, "GPG key %s required" % keyData['hexkeyid'])
-            except yum.Errors.YumBaseError, ye:
-                message = _format_msgs(ye.value)
-                if message.find ("conflicts with file") != -1:
-                    raise PkError(ERROR_FILE_CONFLICTS, message)
-                if message.find ("rpm_check_debug vs depsolve") != -1:
-                    raise PkError(ERROR_PACKAGE_CONFLICTS, message)
-                else:
-                    raise PkError(ERROR_TRANSACTION_ERROR, message)
-            except Exception, e:
-                raise PkError(ERROR_INTERNAL_ERROR, _format_str(traceback.format_exc()))
+        except Exception, e:
+            raise PkError(ERROR_INTERNAL_ERROR, _format_str(traceback.format_exc()))
 
     def remove_packages(self, allowdep, autoremove, package_ids):
+        self._remove_packages(allowdep, autoremove, package_ids)
+
+    def simulate_remove_packages(self, package_ids):
+        self._remove_packages(True, False, package_ids, True)
+
+    def _remove_packages(self, allowdep, autoremove, package_ids, simulate=False):
         '''
         Implement the remove functionality
         Needed to be implemented in a sub class
@@ -2165,15 +2210,15 @@ class PackageKitYumBackend(PackageKitBaseBackend, PackagekitPackage):
             else:
                 for txmbr in self.yumbase.tsInfo:
                     pkg = txmbr.po
-                    system_packages = ['yum','rpm','glibc','PackageKit']
+                    system_packages = ['yum', 'rpm', 'glibc', 'PackageKit']
                     if pkg.name in system_packages:
                         self.error(ERROR_CANNOT_REMOVE_SYSTEM_PACKAGE, "The package %s is essential to correct operation and cannot be removed using this tool." % pkg.name, exit=False)
                         return
             try:
                 if not allowdep:
-                    self._runYumTransaction(allow_remove_deps=False)
+                    self._runYumTransaction(allow_remove_deps=False, only_simulate=simulate)
                 else:
-                    self._runYumTransaction(allow_remove_deps=True)
+                    self._runYumTransaction(allow_remove_deps=True, only_simulate=simulate)
             except PkError, e:
                 self.error(e.code, e.details, exit=False)
         else:
@@ -2661,65 +2706,6 @@ class PackageKitYumBackend(PackageKitBaseBackend, PackagekitPackage):
             except IOError, e:
                 self.error(ERROR_CANNOT_WRITE_REPO_CONFIG, _to_unicode(e))
 
-    def simulate_install_files(self, inst_files):
-        '''
-        Install the package containing the inst_file file
-        '''
-        try:
-            self._check_init()
-        except PkError, e:
-            self.error(e.code, e.details, exit=False)
-            return
-        self.yumbase.conf.cache = 0 # Allow new files
-        self.allow_cancel(True)
-        self.percentage(0)
-        self.status(STATUS_RUNNING)
-
-        for inst_file in inst_files:
-            if inst_file.endswith('.src.rpm'):
-                self.error(ERROR_CANNOT_INSTALL_SOURCE_PACKAGE, 'Backend will not install a src rpm file', exit=False)
-                return
-
-        # common checks copied from yum
-        for inst_file in inst_files:
-            if not self._check_local_file(inst_file):
-                return
-
-        package_list = []
-        txmbrs = []
-        for inst_file in inst_files:
-            try:
-                txmbr = self.yumbase.installLocal(inst_file)
-            except Exception, e:
-                self.error(ERROR_INTERNAL_ERROR, _format_str(traceback.format_exc()))
-            if txmbr:
-                txmbrs.extend(txmbr)
-            else:
-                self.error(ERROR_LOCAL_INSTALL_FAILED, "Can't install %s as no transaction" % _to_unicode(inst_file))
-        if len(self.yumbase.tsInfo) == 0:
-            self.error(ERROR_LOCAL_INSTALL_FAILED, "Can't install %s" % " or ".join(inst_files), exit=False)
-            return
-
-        # do the depsolve to pull in deps
-        try:
-            rc, msgs =  self.yumbase.buildTransaction()
-        except yum.Errors.RepoError, e:
-            self.error(ERROR_REPO_NOT_AVAILABLE, _to_unicode(e))
-        except Exception, e:
-            self.error(ERROR_INTERNAL_ERROR, _format_str(traceback.format_exc()))
-        if rc != 2:
-            self.error(ERROR_DEP_RESOLUTION_FAILED, _format_msgs(msgs))
-
-        # add each package
-        for txmbr in self.yumbase.tsInfo:
-            if txmbr.output_state in TransactionsInfoMap.keys():
-                info = TransactionsInfoMap[txmbr.output_state]
-                package_list.append((txmbr.po, info))
-
-        self.percentage(90)
-        self._show_package_list(package_list)
-        self.percentage(100)
-
     def install_signature(self, sigtype, key_id, package_id):
         try:
             self._check_init()
commit 58a8f12d3f2d0643c63eedf7162a2ea02df1ecc3
Author: Richard Hughes <richard at hughsie.com>
Date:   Mon Feb 1 15:13:27 2010 +0000

    Do not run the transaction with only_trusted if the simulation inferred that any packages were unsigned

diff --git a/lib/packagekit-glib2/pk-task.c b/lib/packagekit-glib2/pk-task.c
index 864435c..c5dc34a 100644
--- a/lib/packagekit-glib2/pk-task.c
+++ b/lib/packagekit-glib2/pk-task.c
@@ -211,9 +211,12 @@ pk_task_simulate_ready_cb (GObject *source_object, GAsyncResult *res, PkTaskStat
 	guint idx = 0;
 	guint i;
 	GPtrArray *array = NULL;
+	GPtrArray *array_messages = NULL;
 	PkPackage *item;
 	gboolean ret;
 	PkInfoEnum info;
+	PkMessage *message;
+	PkMessageEnum message_type;
 	const gchar *package_id;
 
 	/* old results no longer valid */
@@ -253,6 +256,23 @@ pk_task_simulate_ready_cb (GObject *source_object, GAsyncResult *res, PkTaskStat
 		goto out;
 	}
 
+	/* if we did a simulate and we got a message that a package was untrusted,
+	 * there's no point trying to do the action with only-trusted */
+	if (state->simulate && state->only_trusted) {
+		array_messages = pk_results_get_message_array (state->results);
+		for (i = 0; i < array_messages->len; i++) {
+			message = g_ptr_array_index (array_messages, i);
+			g_object_get (message,
+				      "type", &message_type,
+				      NULL);
+			if (message_type == PK_MESSAGE_ENUM_UNTRUSTED_PACKAGE) {
+				egg_debug ("we got an untrusted message, so skipping only-trusted");
+				state->only_trusted = FALSE;
+				break;
+			}
+		}
+	}
+
 	/* get data */
 	sack = pk_results_get_package_sack (results);
 
@@ -309,6 +329,8 @@ pk_task_simulate_ready_cb (GObject *source_object, GAsyncResult *res, PkTaskStat
 out:
 	if (array != NULL)
 		g_ptr_array_unref (array);
+	if (array_messages != NULL)
+		g_ptr_array_unref (array_messages);
 	if (results != NULL)
 		g_object_unref (results);
 	if (sack != NULL)
commit ac5e3fc4b4501713b52d83691fb621311a3a07a4
Author: Richard Hughes <richard at hughsie.com>
Date:   Mon Feb 1 15:02:18 2010 +0000

    trivial: show a warning when we fallback to get-depends or get-requires

diff --git a/src/pk-transaction.c b/src/pk-transaction.c
index cab7ab9..94518c1 100644
--- a/src/pk-transaction.c
+++ b/src/pk-transaction.c
@@ -1783,6 +1783,7 @@ pk_transaction_set_running (PkTransaction *transaction)
 		if (pk_backend_is_implemented (priv->backend, PK_ROLE_ENUM_SIMULATE_INSTALL_PACKAGES)) {
 			pk_backend_simulate_install_packages (priv->backend, priv->cached_package_ids);
 		} else {
+			egg_warning ("falling back to get depends as simulate install packages isn't implemented");
 			/* we need to emit the original packages before we fall back */
 			for (i=0; priv->cached_package_ids[i] != NULL; i++)
 				pk_backend_package (priv->backend, PK_INFO_ENUM_INSTALLING, priv->cached_package_ids[i], "");
@@ -1794,6 +1795,7 @@ pk_transaction_set_running (PkTransaction *transaction)
 		if (pk_backend_is_implemented (priv->backend, PK_ROLE_ENUM_SIMULATE_REMOVE_PACKAGES)) {
 			pk_backend_simulate_remove_packages (priv->backend, priv->cached_package_ids);
 		} else {
+			egg_warning ("falling back to get requires as simulate remove packages isn't implemented");
 			filters = pk_bitfield_from_enums (PK_FILTER_ENUM_INSTALLED, PK_FILTER_ENUM_NEWEST, -1);
 			pk_backend_get_requires (priv->backend, filters, priv->cached_package_ids, TRUE);
 		}
@@ -1802,6 +1804,7 @@ pk_transaction_set_running (PkTransaction *transaction)
 		if (pk_backend_is_implemented (priv->backend, PK_ROLE_ENUM_SIMULATE_UPDATE_PACKAGES)) {
 			pk_backend_simulate_update_packages (priv->backend, priv->cached_package_ids);
 		} else {
+			egg_warning ("falling back to get depends as simulate update packages isn't implemented");
 			/* we need to emit the original packages before we fall back */
 			for (i=0; priv->cached_package_ids[i] != NULL; i++)
 				pk_backend_package (priv->backend, PK_INFO_ENUM_UPDATING, priv->cached_package_ids[i], "");
commit 1407896df5aa05e9330490a98638aa7eff95f028
Author: Richard Hughes <richard at hughsie.com>
Date:   Mon Feb 1 15:01:15 2010 +0000

    Show messages in the pkmon output when the task has completed

diff --git a/client/pk-monitor.c b/client/pk-monitor.c
index ca2b10f..fd58937 100644
--- a/client/pk-monitor.c
+++ b/client/pk-monitor.c
@@ -84,6 +84,25 @@ pk_monitor_notify_network_status_cb (PkControl *control, GParamSpec *pspec, gpoi
 }
 
 /**
+ * pk_monitor_message_cb:
+ **/
+static void
+pk_monitor_message_cb (PkMessage *item, const gchar *transaction_id)
+{
+	gchar *details;
+	PkMessageEnum type;
+
+	/* get data */
+	g_object_get (item,
+		      "details", &details,
+		      "type", &type,
+		      NULL);
+
+	g_print ("%s\tmessage: %s, %s\n", transaction_id, pk_message_enum_to_string (type), details);
+	g_free (details);
+}
+
+/**
  * pk_monitor_adopt_cb:
  **/
 static void
@@ -95,6 +114,7 @@ pk_monitor_adopt_cb (PkClient *_client, GAsyncResult *res, gpointer user_data)
 	PkExitEnum exit_enum;
 	gchar *transaction_id = NULL;
 	PkError *error_code = NULL;
+	GPtrArray *array = NULL;
 
 	/* get the results */
 	results = pk_client_generic_finish (client, res, &error);
@@ -117,12 +137,18 @@ pk_monitor_adopt_cb (PkClient *_client, GAsyncResult *res, gpointer user_data)
 	exit_enum = pk_results_get_exit_code (results);
 	g_print ("%s\texit code: %s\n", transaction_id, pk_exit_enum_to_string (exit_enum));
 
+	/* message */
+	array = pk_results_get_message_array (results);
+	g_ptr_array_foreach (array, (GFunc) pk_monitor_message_cb, transaction_id);
+
 	/* check error code */
 	error_code = pk_results_get_error_code (results);
 	if (error_code != NULL)
 		g_print ("%s\terror code: %s, %s\n", transaction_id, pk_error_enum_to_string (pk_error_get_code (error_code)), pk_error_get_details (error_code));
 out:
 	g_free (transaction_id);
+	if (array != NULL)
+		g_ptr_array_unref (array);
 	if (error_code != NULL)
 		g_object_unref (error_code);
 	if (progress != NULL)
commit 13dded04032c2e466977d31fcbfd6db53372ea15
Author: Richard Hughes <richard at hughsie.com>
Date:   Mon Feb 1 11:22:36 2010 +0000

    trivial: post release version bump

diff --git a/RELEASE b/RELEASE
index 0943b84..2eb8cb1 100644
--- a/RELEASE
+++ b/RELEASE
@@ -2,7 +2,7 @@ PackageKit Release Notes
 
 1. Write NEWS entries for PackageKit in the same format as usual.
 
-git shortlog PACKAGEKIT_0_6_0.. | grep -i -v trivial | grep -v Merge > NEWS.new
+git shortlog PACKAGEKIT_0_6_1.. | grep -i -v trivial | grep -v Merge > NEWS.new
 
 --------------------------------------------------------------------------------
 Version 0.6.x
@@ -26,8 +26,8 @@ Bugfixes:
 
 4. Commit changes in PackageKit git:
 
-git commit -a -m "Release version 0.6.1"
-git tag -s -f -m "Release 0.6.1" PACKAGEKIT_0_6_1
+git commit -a -m "Release version 0.6.2"
+git tag -s -f -m "Release 0.6.2" PACKAGEKIT_0_6_2
 <gpg password>
 git push --tags
 git push
@@ -52,9 +52,9 @@ git push
 10. Send an email to packagekit at lists.freedesktop.org
 
 =================================================
-Subject: PackageKit 0.6.0 released!
+Subject: PackageKit 0.6.1 released!
 
-Today I released PackageKit 0.6.0.
+Today I released PackageKit 0.6.1.
 
 PackageKit release notes: http://cgit.freedesktop.org/packagekit/tree/NEWS
 
diff --git a/configure.ac b/configure.ac
index eb578c6..7424fae 100644
--- a/configure.ac
+++ b/configure.ac
@@ -3,7 +3,7 @@ AC_PREREQ(2.65)
 
 m4_define([pk_major_version], [0])
 m4_define([pk_minor_version], [6])
-m4_define([pk_micro_version], [1])
+m4_define([pk_micro_version], [2])
 m4_define([pk_version],
           [pk_major_version.pk_minor_version.pk_micro_version])
 


More information about the PackageKit-commit mailing list