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

Richard Hughes hughsient at kemper.freedesktop.org
Mon Nov 10 07:27:36 PST 2008


 NEWS                                           |   56 +
 backends/conary/conaryBackend.py               |    4 
 backends/yum/yumBackend.py                     |    7 
 backends/yum/yumComps.py                       |   39 +
 backends/zypp/pk-backend-zypp.cpp              |    1 
 backends/zypp/zypp-events.h                    |   28 
 configure.ac                                   |    2 
 docs/html/pk-download.html                     |    1 
 lib/python/packagekit/backend.py               |   59 +-
 lib/python/packagekit/client.py                |  737 ++++++++++---------------
 lib/python/packagekit/daemonBackend.py         |   14 
 po/de.po                                       |  327 +++++------
 src/org.freedesktop.PackageKit.Transaction.xml |    3 
 13 files changed, 609 insertions(+), 669 deletions(-)

New commits:
commit e7f126dbcff838c447ce388271372a5cafebc18f
Author: Richard Hughes <richard at hughsie.com>
Date:   Mon Nov 10 15:26:51 2008 +0000

    Release version 0.3.10

diff --git a/NEWS b/NEWS
index 373528b..f4ecd2f 100644
--- a/NEWS
+++ b/NEWS
@@ -1,3 +1,59 @@
+Version 0.3.10
+~~~~~~~~~~~~~~
+Released: 2008-11-10
+
+Translations:
+ - Updated Spanish translation (Domingo Becker)
+ - Updated German translation (Fabian Affolter)
+ - Updated Italian translation updated (Francesco Valente)
+ - Updated Brazilian Portuguese translation (Igor Pires Soares)
+ - Updated Turkish translations (S.Çağlar Onur)
+ - Updated Finnish translation (Ville-Pekka Vainio)
+ - Updated Simplified Chinese (甘露(Gan Lu))
+ - Updated Catalan translation (Xavier Conde)
+
+New Features:
+ - Redesign python packagekit client to support async operations (Sebastian Heinlein)
+ - Monitor scripts in PkSpawn for standard error too, as messages often get put
+   there by libraries and may be useful to a backend (Richard Hughes)
+ - Add filter functions to allow the spawned backends to filter stderr (Richard Hughes)
+
+Bugfixes:
+ - Add missing includes to fix the build (S.Çağlar Onur)
+ - Install FindQPackageKit.cmake as KPackageKit needs it to build (Richard Hughes)
+ - Use the correct session interface in the browser plugin (Richard Hughes)
+ - Fix protocol violation in the server and client (Richard Hughes)
+ - Store job count in /var/lib as it's persistent (Richard Hughes)
+ - When we call Error from a python spawned backend with exit=False, don't do
+   Finished else we'll get warned by the daemon (Richard Hughes)
+ - plugin: Send the XID of the browser window so focus stealing and modality is
+   set correctly (Richard Hughes)
+ - DaemonBackend: Do not include use a separate inactivity timeout (Sebastian Heinlein)
+ - Add the description to the PackageKitError exception in client (Sebastian Heinlein)
+ - Fix the idle timer in  daemonBackend - do not exit on running threads (Sebastian Heinlein)
+ - python client: UpdateSystem should be handled as a long taking action (Sebastian Heinlein)
+ - python client: SetLocale does not report a status (Sebastian Heinlein)
+ - python client: Show status, progress and allow_cancel in the widget (Sebastian Heinlein)
+ - python client: Replace the async parameter by an exit_handler (Sebastian Heinlein)
+
+Backends:
+ - alpm: change GetDepends to handle filters properly (Valeriy Lyasotskiy)
+ - conary: Fixed data.split, I think that space was a typo (Ken VanDine)
+ - yum: Add support for non categorized groups (Tim Lauridsen)
+ - yum: Sort the groups in each category (James Antill)
+ - yum: Sort by group and not groupid (James Antill)
+ - yum: Replace a regular expression with four simple comparisons (Richard Hughes)
+ - yum: Fix a recently introduced regression where installing a zero byte
+        file would not return the correct error code (Richard Hughes)
+ - yum: Filter out stderr KEY requests before the data is processed (Richard Hughes)
+ - yum: Fix getting distibution upgrade information when we have multiple repos
+        providing preupgrade. Fixes rh#469172 (Richard Hughes)
+ - yum: Move the groups sqlite cache into a PackageKit directory, rather than a
+        yum owned directory. Fixes rh#469324 (Richard Hughes)
+ - zypp: Changed get_distro_upgrades function (Stefan Haas)
+ - zypp: Adapted signature callbacks (Stefan Haas)
+ - zypp: Set status when installing a signature (Stefan Haas)
+
 Version 0.3.9
 ~~~~~~~~~~~~~~
 Released: 2008-10-27
diff --git a/configure.ac b/configure.ac
index c10bc8b..221683f 100644
--- a/configure.ac
+++ b/configure.ac
@@ -19,7 +19,7 @@ DEVELOPMENT_RELEASE=no
 # AGE		If libpackagekit can be linked into executables which can be
 # 		built with previous versions of this library. Don't use.
 LT_CURRENT=10
-LT_REVISION=1
+LT_REVISION=2
 LT_AGE=0
 AC_SUBST(LT_CURRENT)
 AC_SUBST(LT_REVISION)
diff --git a/docs/html/pk-download.html b/docs/html/pk-download.html
index 8147942..eaa28dd 100644
--- a/docs/html/pk-download.html
+++ b/docs/html/pk-download.html
@@ -78,6 +78,7 @@ Releases are normally once every 1-2 weeks.
 <tr><td>0.3.7</td><td></td><td>2008-10-13</td></tr>
 <tr><td>0.3.8</td><td></td><td>2008-10-20</td></tr>
 <tr><td>0.3.9</td><td></td><td>2008-10-27</td></tr>
+<tr><td>0.3.10</td><td></td><td>2008-11-10</td></tr>
 </table>
 <h3>
 ABI Stable Versions:
commit 3590f4766301ee23fc0542fc9b99eb7de44e2bb2
Merge: b068f8e... 28f73f7...
Author: Richard Hughes <richard at hughsie.com>
Date:   Sat Nov 8 16:44:44 2008 +0000

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

commit 28f73f77d975641b1e6d2040b64f5aeac6ff5674
Author: Ken VanDine <ken at vandine.org>
Date:   Fri Nov 7 11:13:59 2008 -0500

    Fixed data.split, I think that space was a typo

diff --git a/backends/conary/conaryBackend.py b/backends/conary/conaryBackend.py
index 15000b7..e39b606 100644
--- a/backends/conary/conaryBackend.py
+++ b/backends/conary/conaryBackend.py
@@ -167,7 +167,7 @@ class PackageKitConaryBackend(PackageKitBaseBackend):
         return ','.join([frzVersion, frzFlavor])
 
     def _thawData(self, data):
-        frzVersion, frzFlavor = data.split(', ')
+        frzVersion, frzFlavor = data.split(',')
         version = versions.ThawVersion(frzVersion)
         flavor = deps.ThawFlavor(frzFlavor)
         return version, flavor
@@ -980,7 +980,7 @@ class Cache(object):
                 #    self._addPackageLicense(trv, license)
 
 def main():
-    backend = PackageKitConaryBackend('', lock=True)
+    backend = PackageKitConaryBackend('')
     backend.dispatcher(sys.argv[1:])
 
 if __name__ == "__main__":
commit bf8342e9cffca251396f53bc5e526701e475a8b3
Author: James Antill <james at and.org>
Date:   Fri Nov 7 10:34:57 2008 -0500

    Sort by group and not groupid

diff --git a/backends/yum/yumBackend.py b/backends/yum/yumBackend.py
index 4c4cefd..66907f0 100755
--- a/backends/yum/yumBackend.py
+++ b/backends/yum/yumBackend.py
@@ -625,8 +625,9 @@ class PackageKitYumBackend(PackageKitBaseBackend, PackagekitPackage):
             for grp_id in self.comps.get_groups(cat):
                 grp = self.yumbase.comps.return_group(grp_id)
                 if grp:
-                    grps.append((grp_id, grp))
-            for grp_id, grp in sorted(grps):
+                    grps.append(grp)
+            for grp in sorted(grps):
+                    grp_id = grp.groupid
                     cat_id_name = "@%s" % (grp_id)
                     name = grp.nameByLang(self._lang)
                     summary = grp.descriptionByLang(self._lang)
commit d6f6a58d49c3acaf835d4e1b7932947948a7bf1c
Author: James Antill <james at and.org>
Date:   Fri Nov 7 10:29:20 2008 -0500

    Sort the groups in each category, can't see how to sort the categories

diff --git a/backends/yum/yumBackend.py b/backends/yum/yumBackend.py
index 5a81644..4c4cefd 100755
--- a/backends/yum/yumBackend.py
+++ b/backends/yum/yumBackend.py
@@ -621,10 +621,12 @@ class PackageKitYumBackend(PackageKitBaseBackend, PackagekitPackage):
         else:
             cats =  [cat.categoryid for cat in self.yumbase.comps.categories]
         for cat in cats:
-            grps = self.comps.get_groups(cat)
-            for grp_id in grps:
+            grps = []
+            for grp_id in self.comps.get_groups(cat):
                 grp = self.yumbase.comps.return_group(grp_id)
                 if grp:
+                    grps.append((grp_id, grp))
+            for grp_id, grp in sorted(grps):
                     cat_id_name = "@%s" % (grp_id)
                     name = grp.nameByLang(self._lang)
                     summary = grp.descriptionByLang(self._lang)
commit fa8e178908e4ba2b9534f158cb0c393d3e45f6c9
Author: Tim Lauridsen <timlau at fedoraproject.org>
Date:   Fri Nov 7 15:30:58 2008 +0100

    yum: add support for non categorized groups in yumComps

diff --git a/backends/yum/yumComps.py b/backends/yum/yumComps.py
index f8a0a34..ee2a2da 100755
--- a/backends/yum/yumComps.py
+++ b/backends/yum/yumComps.py
@@ -261,7 +261,9 @@ class yumComps:
 
         # write to disk
         self.connection.commit()
+        print "Non Categorized groups"
         self._add_non_catagorized_groups()
+        self.connection.commit()
         return True
 
     def _add_groups_to_db(self, grps, cat_id):
@@ -293,11 +295,9 @@ class yumComps:
             # check if it is already added to the db
             if self.get_category(grp.groupid):
                 continue
-            else:
+            elif grp.user_visible:
                 to_add.append(grp)
-        for grp in to_add:
-            print grp.name
-
+        self._add_groups_to_db(to_add, "other")
 
 
     def get_package_list(self, group_key):
@@ -355,7 +355,6 @@ if __name__ == "__main__":
     _db = "./packagekit-groups.sqlite"
     comps = yumComps(_yb, _db)
     comps.connect()
-    comps.refresh()
     print "pk group system"
     print 40 * "="
     _pkgs = comps.get_package_list('system')
@@ -368,5 +367,9 @@ if __name__ == "__main__":
     print 40 * "="
     _pkgs = comps.get_meta_package_list('kde-desktop')
     print _pkgs
+    print "comps group other"
+    print 40 * "="
+    _pkgs = comps.get_groups('other')
+    print _pkgs
     os.unlink(_db) # kill the db
 
commit a62f169c349301815af90ae170a43e49afc3ef0d
Author: Tim Lauridsen <timlau at fedoraproject.org>
Date:   Fri Nov 7 09:58:23 2008 +0100

    yum: add support for non categorized groups

diff --git a/backends/yum/yumComps.py b/backends/yum/yumComps.py
index 82bbf6a..f8a0a34 100755
--- a/backends/yum/yumComps.py
+++ b/backends/yum/yumComps.py
@@ -257,13 +257,20 @@ class yumComps:
         for category in cats:
             grps = map(lambda x: self.yumbase.comps.return_group(x),
                filter(lambda x: self.yumbase.comps.has_group(x), category.groups))
-            for group in grps:
+            self._add_groups_to_db(grps, category.categoryid)
+
+        # write to disk
+        self.connection.commit()
+        self._add_non_catagorized_groups()
+        return True
 
+    def _add_groups_to_db(self, grps, cat_id):
+            for group in grps:
                 # strip out rpmfusion from the group name
                 group_name = group.groupid
                 group_name = group_name.replace('rpmfusion_nonfree-', '')
                 group_name = group_name.replace('rpmfusion_free-', '')
-                group_id = "%s;%s" % (category.categoryid, group_name)
+                group_id = "%s;%s" % (cat_id, group_name)
 
                 group_enum = GROUP_OTHER
                 if groupMap.has_key(group_id):
@@ -272,15 +279,26 @@ class yumComps:
                     print 'unknown group enum', group_id
 
                 for package in group.mandatory_packages:
-                    self._add_db(package, category.categoryid, group_name, group_enum, 'mandatory')
+                    self._add_db(package, cat_id, group_name, group_enum, 'mandatory')
                 for package in group.default_packages:
-                    self._add_db(package, category.categoryid, group_name, group_enum, 'default')
+                    self._add_db(package, cat_id, group_name, group_enum, 'default')
                 for package in group.optional_packages:
-                    self._add_db(package, category.categoryid, group_name, group_enum, 'optional')
+                    self._add_db(package, cat_id, group_name, group_enum, 'optional')
+
+
+    def _add_non_catagorized_groups(self):
+        to_add = []
+        # Go through all the groups
+        for grp in self.yumbase.comps.groups:
+            # check if it is already added to the db
+            if self.get_category(grp.groupid):
+                continue
+            else:
+                to_add.append(grp)
+        for grp in to_add:
+            print grp.name
+
 
-        # write to disk
-        self.connection.commit()
-        return True
 
     def get_package_list(self, group_key):
         ''' for a PK group, get the packagelist for this group '''
commit 3713f20506d3133fc8e366dc4b44c642a28a9709
Author: Fabian Affolter <fabian at bernewireless.net>
Date:   Fri Nov 7 10:54:56 2008 +0000

    Updated German translation
    
    Transmitted-via: Transifex (translate.fedoraproject.org)

diff --git a/po/de.po b/po/de.po
index 607927c..e8ea3bf 100644
--- a/po/de.po
+++ b/po/de.po
@@ -1,26 +1,22 @@
-# translation of packagekit.master.de.po to German
-# translation of policycoreutils.HEAD.de.po to
-# translation of de.po to
 # German translation of policycoreutils.
 # Copyright (C) 2006, 2007, 2008 Free Software Foundation, Inc.
 #
-#
-#
 # Holger Wansing <linux at wansing-online.de>, 2006.
 # Timo Trinks <ttrinks at redhat.com>, 2006, 2007.
 # Michael Schönitzer <michael at schoenitzer.de>, 2007.
 # Fabian Affolter <fab at fedoraproject.org>, 2008.
-# PGP-KeyID: 0x037FD3CF <ttrinks at redhat.com>, 2008.
+# Timo Trinks <ttrinks at redhat.com>, 2008.
 # Thomas Spura <tomspur at fedoraproject.org>, 2008.
 # Daniela Kugelmann <dkugelma at redhat.com >, 2008.
 # Stefan Posdzich <cheekyboinc at foresightlinux.org>, 2008.
+#
 msgid ""
 msgstr ""
 "Project-Id-Version: packagekit.master.de\n"
 "Report-Msgid-Bugs-To: \n"
-"POT-Creation-Date: 2008-10-22 13:38+0000\n"
-"PO-Revision-Date: 2008-10-16 15:50+1000\n"
-"Last-Translator: Stefan Posdzich <cheekyboinc at foresightlinux.org>\n"
+"POT-Creation-Date: 2008-10-27 02:03+0000\n"
+"PO-Revision-Date: 2008-11-07 11:53+0100\n"
+"Last-Translator: Fabian Affolter <fab at fedoraproject.org>\n"
 "Language-Team: German <i18 at redhat.com>\n"
 "MIME-Version: 1.0\n"
 "Content-Type: text/plain; charset=UTF-8\n"
@@ -42,400 +38,417 @@ msgid "Please logout and login to complete the update."
 msgstr "Bitte erneut einloggen um das Update abzuschließen."
 
 #: ../client/pk-console.c:468
+#, fuzzy
 msgid "Please restart the application as it is being used."
-msgstr ""
+msgstr "Starten Sie die Anwendung neu, da sie benutzt wird."
 
 #. TRANSLATORS: The package is already installed on the system
-#: ../client/pk-console.c:579
+#: ../client/pk-console.c:580
 #, c-format
 msgid "The package '%s' is already installed"
 msgstr "Das Paket '%s' ist bereits installiert"
 
 #. TRANSLATORS: The package name was not found in any software sources. The detailed error follows
-#: ../client/pk-console.c:587
+#: ../client/pk-console.c:588
 #, c-format
 msgid "The package '%s' could not be installed: %s"
 msgstr "Das Paket '%s' konnte nicht installiert werden: %s"
 
 #. TRANSLATORS: There was a programming error that shouldn't happen. The detailed error follows
-#: ../client/pk-console.c:612 ../client/pk-console.c:639
-#: ../client/pk-console.c:735 ../client/pk-console.c:852
-#: ../client/pk-tools-common.c:55 ../client/pk-tools-common.c:74
+#: ../client/pk-console.c:613
+#: ../client/pk-console.c:640
+#: ../client/pk-console.c:736
+#: ../client/pk-console.c:853
+#: ../client/pk-tools-common.c:55
+#: ../client/pk-tools-common.c:74
 #: ../client/pk-tools-common.c:81
 #, c-format
 msgid "Internal error: %s"
 msgstr "Interner Fehler: %s"
 
 #. TRANSLATORS: There was an error installing the packages. The detailed error follows
-#: ../client/pk-console.c:620
+#: ../client/pk-console.c:621
 #, c-format
 msgid "This tool could not install the packages: %s"
 msgstr "Konnte folgende Pakete nicht installieren: %s"
 
 #. TRANSLATORS: There was an error installing the files. The detailed error follows
-#: ../client/pk-console.c:647
-#, fuzzy, c-format
+#: ../client/pk-console.c:648
+#, c-format
 msgid "This tool could not install the files: %s"
-msgstr "Die Datei-Liste konnte nicht erstellt werden: %s"
+msgstr "Die Dateien konnten nicht installieren werden: %s"
 
 #. TRANSLATORS: The package name was not found in the installed list. The detailed error follows
-#: ../client/pk-console.c:703
+#: ../client/pk-console.c:704
 #, c-format
 msgid "This tool could not remove '%s': %s"
 msgstr "Konnte nicht entfernen '%s': %s"
 
 #. TRANSLATORS: There was an error removing the packages. The detailed error follows
-#: ../client/pk-console.c:726 ../client/pk-console.c:797
+#: ../client/pk-console.c:727
+#: ../client/pk-console.c:798
 #, c-format
 msgid "This tool could not remove the packages: %s"
 msgstr "Konnte folgende Pakete nicht entfernen: %s"
 
 #. TRANSLATORS: There was an error removing the packages. The detailed error follows
-#: ../client/pk-console.c:764
+#: ../client/pk-console.c:765
 #, c-format
 msgid "This tool could not remove the packages: '%s'"
-msgstr "This tool could not remove the packages: '%s'"
+msgstr "Dieser Werkzeug konnte das Paket nicht entfernen: '%s'"
 
 #. TRANSLATORS: When removing, we might have to remove other dependencies
-#: ../client/pk-console.c:776
-#, fuzzy
+#: ../client/pk-console.c:777
 msgid "The following packages have to be removed:"
-msgstr "Die folgenden Pakete müssen entfernt werden"
+msgstr "Die folgenden Pakete müssen entfernt werden:"
 
 #. TRANSLATORS: We are checking if it's okay to remove a list of packages
-#: ../client/pk-console.c:783
-#, fuzzy
+#: ../client/pk-console.c:784
 msgid "Proceed removing additional packages?"
 msgstr "Sollen die zusätzlichen Pakete entfernt werden?"
 
 #. TRANSLATORS: We did not remove any packages
-#: ../client/pk-console.c:788
+#: ../client/pk-console.c:789
 msgid "The package removal was canceled!"
-msgstr "Die entfernung der Pakete wurde abgebrochen!"
+msgstr "Die Entfernung der Pakete wurde abgebrochen!"
 
 #. TRANSLATORS: The package name was not found in any software sources
-#: ../client/pk-console.c:829
+#: ../client/pk-console.c:830
 #, c-format
 msgid "This tool could not download the package '%s' as it could not be found"
 msgstr "Das Paket '%s' konnte nicht gefunden und heruntergeladen werden"
 
 #. TRANSLATORS: Could not download the packages for some reason. The detailed error follows
-#: ../client/pk-console.c:860
+#: ../client/pk-console.c:861
 #, c-format
 msgid "This tool could not download the packages: %s"
 msgstr "Konnte folgende Pakete nicht herunterladen: %s"
 
 #. TRANSLATORS: There was an error getting the list of files for the package. The detailed error follows
-#: ../client/pk-console.c:887 ../client/pk-console.c:896
+#: ../client/pk-console.c:888
+#: ../client/pk-console.c:897
 #, c-format
 msgid "This tool could not update '%s': %s"
 msgstr "Konnte nicht aktualisieren '%s': %s"
 
 #. TRANSLATORS: There was an error getting the list of files for the package. The detailed error follows
-#: ../client/pk-console.c:918 ../client/pk-console.c:926
+#: ../client/pk-console.c:919
+#: ../client/pk-console.c:927
 #, c-format
 msgid "This tool could not get the requirements for '%s': %s"
 msgstr "Konnte die Vorraussetzungen nicht bekommen für '%s': %s"
 
 #. TRANSLATORS: There was an error getting the dependencies for the package. The detailed error follows
-#: ../client/pk-console.c:948 ../client/pk-console.c:956
-#, fuzzy, c-format
+#: ../client/pk-console.c:949
+#: ../client/pk-console.c:957
+#, c-format
 msgid "This tool could not get the dependencies for '%s': %s"
-msgstr "Konnte keine Abhängigkeiten bekommen für '%s': %s"
+msgstr "Es konnten keine Abhängigkeiten für '%s' gezogen werden: %s"
 
 #. TRANSLATORS: There was an error getting the details about the package. The detailed error follows
-#: ../client/pk-console.c:978 ../client/pk-console.c:986
+#: ../client/pk-console.c:979
+#: ../client/pk-console.c:987
 #, c-format
 msgid "This tool could not get package details for '%s': %s"
 msgstr "Konnte die Paketdetails nicht abrufen für '%s': %s"
 
 #. TRANSLATORS: The package name was not found in any software sources. The detailed error follows
-#: ../client/pk-console.c:1008
-#, fuzzy, c-format
+#: ../client/pk-console.c:1009
+#, c-format
 msgid "This tool could not find the files for '%s': %s"
-msgstr "Die Dateien für dieses Paket konnten nicht gefunden werden '%s': %s"
+msgstr "Die Dateien für '%s' konnten nicht gefunden werden: %s"
 
 #. TRANSLATORS: There was an error getting the list of files for the package. The detailed error follows
-#: ../client/pk-console.c:1016
-#, fuzzy, c-format
+#: ../client/pk-console.c:1017
+#, c-format
 msgid "This tool could not get the file list for '%s': %s"
-msgstr "Die Datei-Liste konnte nicht erstellt werden für '%s': %s"
+msgstr "Die Datei-Liste für '%s konnte nicht erstellt werden ': %s"
 
 #. TRANSLATORS: The package name was not found in any software sources. The detailed error follows
-#: ../client/pk-console.c:1038
-#, fuzzy, c-format
+#: ../client/pk-console.c:1039
+#, c-format
 msgid "This tool could not find the update details for '%s': %s"
-msgstr "Konnte keine Aktualisierungsdetails finden für '%s': %s"
+msgstr "Es konnten für '%s' keine Aktualisierungsdetails gefunden werden : %s"
 
 #. TRANSLATORS: There was an error getting the details about the update for the package. The detailed error follows
-#: ../client/pk-console.c:1046
-#, fuzzy, c-format
+#: ../client/pk-console.c:1047
+#, c-format
 msgid "This tool could not get the update details for '%s': %s"
-msgstr "Konnte keine Aktualisierungsdetails finden für '%s': %s"
+msgstr "Es konnten keine Aktualisierungsdetails für '%s' gefunden werden: %s"
 
 #. TRANSLATORS: This was an unhandled error, and we don't have _any_ context
-#: ../client/pk-console.c:1092
+#: ../client/pk-console.c:1093
 msgid "Error:"
 msgstr "Fehler:"
 
 #. TRANSLATORS: This a list of details about the package
-#: ../client/pk-console.c:1106
+#: ../client/pk-console.c:1107
 msgid "Package description"
 msgstr "Paketbeschreibung"
 
 #. TRANSLATORS: This a list files contained in the package
-#: ../client/pk-console.c:1139
+#: ../client/pk-console.c:1140
 msgid "Package files"
 msgstr "Paket-Dateien"
 
 #. TRANSLATORS: This where the package has no files
-#: ../client/pk-console.c:1148
+#: ../client/pk-console.c:1149
 msgid "No files"
 msgstr "Keine Dateien"
 
 #. TRANSLATORS: This a request for a GPG key signature from the backend, which the client will prompt for later
-#: ../client/pk-console.c:1171
+#: ../client/pk-console.c:1172
 msgid "Repository signature required"
 msgstr "Signatur der Paketquellen benötigt"
 
 #. TRANSLATORS: This a prompt asking the user to import the security key
-#: ../client/pk-console.c:1181
+#: ../client/pk-console.c:1182
 msgid "Do you accept this signature?"
 msgstr "Akzeptieren Sie diese Signatur?"
 
 #. TRANSLATORS: This is where the user declined the security key
-#: ../client/pk-console.c:1185
+#: ../client/pk-console.c:1186
 msgid "The signature was not accepted."
 msgstr "Diese Signatur wurde nicht akzeptiert."
 
 #. TRANSLATORS: This a request for a EULA
-#: ../client/pk-console.c:1219
+#: ../client/pk-console.c:1220
 msgid "End user license agreement required"
 msgstr "Endbenutzer Lizenzvereinbarung benötigt"
 
 #. TRANSLATORS: This a prompt asking the user to agree to the license
-#: ../client/pk-console.c:1226
-#, fuzzy
+#: ../client/pk-console.c:1227
 msgid "Do you agree to this license?"
-msgstr "Sind Sie einverstanden?"
+msgstr "Sind Sie mit dieser Lizenz einverstanden?"
 
 #. TRANSLATORS: This is where the user declined the license
-#: ../client/pk-console.c:1230
+#: ../client/pk-console.c:1231
 msgid "The license was refused."
 msgstr "Die Lizenz wurde zurückgewiesen."
 
 #. TRANSLATORS: This is when the daemon crashed, and we are up shit creek without a paddle
-#: ../client/pk-console.c:1259
+#: ../client/pk-console.c:1260
 msgid "The daemon crashed mid-transaction!"
 msgstr "Der Dämon stürzte während der Transaktion ab!"
 
 #. TRANSLATORS: This is the header to the --help menu
-#: ../client/pk-console.c:1312
+#: ../client/pk-console.c:1313
 msgid "PackageKit Console Interface"
 msgstr "PackageKit-Konsolen-Interface"
 
-#: ../client/pk-console.c:1312
+#: ../client/pk-console.c:1313
 msgid "Subcommands:"
 msgstr "Unterbefehle:"
 
-#: ../client/pk-console.c:1403 ../client/pk-generate-pack.c:138
-#: ../client/pk-monitor.c:115 ../src/pk-main.c:196
+#: ../client/pk-console.c:1404
+#: ../client/pk-generate-pack.c:182
+#: ../client/pk-monitor.c:115
+#: ../src/pk-main.c:196
 msgid "Show extra debugging information"
 msgstr "Zeige extra Debug-Informationen"
 
-#: ../client/pk-console.c:1405 ../client/pk-monitor.c:117
+#: ../client/pk-console.c:1406
+#: ../client/pk-monitor.c:117
 msgid "Show the program version and exit"
 msgstr "Zeige Programm-Version und beende"
 
-#: ../client/pk-console.c:1407
+#: ../client/pk-console.c:1408
 msgid "Set the filter, e.g. installed"
 msgstr "Setze den Filter, z.B. installiert"
 
-#: ../client/pk-console.c:1409
+#: ../client/pk-console.c:1410
 msgid "Exit without waiting for actions to complete"
 msgstr "Beende, ohne auf Beendigung der Aktionen zu warten"
 
 #. TRANSLATORS: This is when we could not connect to the system bus, and is fatal
-#: ../client/pk-console.c:1431
-#, fuzzy
+#: ../client/pk-console.c:1432
 msgid "This tool could not connect to system DBUS."
-msgstr "Konnte nicht zum System-DBUS verbinden."
+msgstr "Dieses Werkzeug konnte nicht zum System-DBUS verbinden."
 
-#: ../client/pk-console.c:1526
+#: ../client/pk-console.c:1527
 msgid "You need to specify a search type, e.g. name"
 msgstr "Sie müssen einen Suchtyp angeben, z.B. einen Namen"
 
-#: ../client/pk-console.c:1531 ../client/pk-console.c:1538
-#: ../client/pk-console.c:1545 ../client/pk-console.c:1552
-#: ../client/pk-console.c:1663 ../client/pk-console.c:1673
-#: ../client/pk-console.c:1680 ../client/pk-console.c:1687
+#: ../client/pk-console.c:1532
+#: ../client/pk-console.c:1539
+#: ../client/pk-console.c:1546
+#: ../client/pk-console.c:1553
+#: ../client/pk-console.c:1664
+#: ../client/pk-console.c:1674
+#: ../client/pk-console.c:1681
+#: ../client/pk-console.c:1688
 msgid "You need to specify a search term"
 msgstr "Sie müssen einen Suchwert angeben"
 
-#: ../client/pk-console.c:1557
+#: ../client/pk-console.c:1558
 msgid "Invalid search type"
 msgstr "Ungültiger Suchtyp"
 
-#: ../client/pk-console.c:1562
+#: ../client/pk-console.c:1563
 msgid "You need to specify a package or file to install"
 msgstr "Sie müssen ein Paket oder eine Datei zum installieren angeben"
 
-#: ../client/pk-console.c:1569
+#: ../client/pk-console.c:1570
 msgid "You need to specify a type, key_id and package_id"
 msgstr "Sie müssen einen Typ, Schlüssel_id und Paket_id auswählen"
 
-#: ../client/pk-console.c:1576
+#: ../client/pk-console.c:1577
 msgid "You need to specify a package to remove"
 msgstr "Sie müssen ein Paket zum Löschen angeben"
 
-#: ../client/pk-console.c:1582
+#: ../client/pk-console.c:1583
 msgid "You need to specify the destination directory and then the packages to download"
 msgstr "Sie müssen ein Zielverzeichnis und dann die Pakete zum herunterladen angeben"
 
-#: ../client/pk-console.c:1587
+#: ../client/pk-console.c:1588
 msgid "Directory not found"
 msgstr "Verzeichnis nicht gefunden"
 
-#: ../client/pk-console.c:1593
-#, fuzzy
+#: ../client/pk-console.c:1594
 msgid "You need to specify a licence identifier (eula-id)"
-msgstr "Sie müssen eine eula-id auswählen"
+msgstr "Sie müssen eine Lizenz (eula-id) angeben"
 
-#: ../client/pk-console.c:1609
+#: ../client/pk-console.c:1610
 msgid "You need to specify a package name to resolve"
 msgstr "Sie müssen einen Paketnamen zum Auflösen angeben"
 
-#: ../client/pk-console.c:1618 ../client/pk-console.c:1625
-#, fuzzy
+#: ../client/pk-console.c:1619
+#: ../client/pk-console.c:1626
 msgid "You need to specify a repository name"
 msgstr "Sie müssen einen Repository-Namen angeben"
 
-#: ../client/pk-console.c:1632
+#: ../client/pk-console.c:1633
 msgid "You need to specify a repo name/parameter and value"
 msgstr "Sie müssen einen Repositorynamen/Parameter und Wert angeben"
 
-#: ../client/pk-console.c:1645
-#, fuzzy
+#: ../client/pk-console.c:1646
 msgid "You need to specify an action, e.g. 'update-system'"
-msgstr "Sie müssen einen Suchtyp angeben, z.B. einen Namen"
+msgstr "Sie müssen eine Aktion angeben, z.B. 'update-system'"
 
-#: ../client/pk-console.c:1650
+#: ../client/pk-console.c:1651
 msgid "You need to specify a correct role"
 msgstr "Sie müssen eine korrekte Rolle angeben"
 
-#: ../client/pk-console.c:1655
+#: ../client/pk-console.c:1656
 msgid "Failed to get last time"
 msgstr "Die letzte Zeit konnte nicht herausgefunden werden"
 
-#: ../client/pk-console.c:1694
+#: ../client/pk-console.c:1695
 msgid "You need to specify a package to find the details for"
 msgstr "Sie müssen ein Paket, für das nach Details gesucht wird, angeben"
 
-#: ../client/pk-console.c:1701
+#: ../client/pk-console.c:1702
 msgid "You need to specify a package to find the files for"
 msgstr "Sie müssen ein Paket, für das nach Dateien gesucht wird, angeben"
 
 #. TRANSLATORS: The user tried to use an unsupported option on the command line
-#: ../client/pk-console.c:1754
-#, fuzzy, c-format
+#: ../client/pk-console.c:1755
+#, c-format
 msgid "Option '%s' is not supported"
 msgstr "Option '%s' wird nicht unterstützt"
 
 #. TRANSLATORS: User does not have permission to do this
-#: ../client/pk-console.c:1767
+#: ../client/pk-console.c:1768
 msgid "You don't have the necessary privileges for this operation"
 msgstr "Sie haben nicht die notwendigen Privilegien für diese Operation"
 
 #. TRANSLATORS: Generic failure of what they asked to do
-#: ../client/pk-console.c:1770
+#: ../client/pk-console.c:1771
 msgid "Command failed"
 msgstr "Befehl fehlgeschlagen"
 
 #. TRANSLATORS: This is the state of the transaction
-#: ../client/pk-generate-pack.c:96
+#: ../client/pk-generate-pack.c:98
 msgid "Downloading"
 msgstr "Lade herunter"
 
-#: ../client/pk-generate-pack.c:140
-#, fuzzy
+#. TRANSLATORS: This is when the main packages are being downloaded
+#: ../client/pk-generate-pack.c:118
+msgid "Downloading packages"
+msgstr "Lade Pakete herunter"
+
+#. TRANSLATORS: This is when the dependency packages are being downloaded
+#: ../client/pk-generate-pack.c:123
+msgid "Downloading dependencies"
+msgstr "Lade Abhängihkeiten herunter"
+
+#: ../client/pk-generate-pack.c:184
 msgid "Set the file name of dependencies to be excluded"
-msgstr "Setze den Pfad der Datei mit der Paket- /Abhängigkeitsliste, die ausgeschlossen werden"
+msgstr "Setze den Dateiname der Abhängigkeiten, die ausgeschlossen werden"
 
-#: ../client/pk-generate-pack.c:142
+#: ../client/pk-generate-pack.c:186
 msgid "The output directory (the current directory is used if ommitted)"
 msgstr ""
 
-#: ../client/pk-generate-pack.c:144
+#: ../client/pk-generate-pack.c:188
 msgid "The package to be put into the service pack"
 msgstr ""
 
-#: ../client/pk-generate-pack.c:146
+#: ../client/pk-generate-pack.c:190
 msgid "Put all updates available in the service pack"
-msgstr ""
+msgstr "Füge alle Aktualisierungen dem Service-Pack hinzu"
 
 #. TRANSLATORS: This is when the user fails to supply the correct arguments
-#: ../client/pk-generate-pack.c:166
+#: ../client/pk-generate-pack.c:213
 msgid "Neither --package or --updates option selected."
 msgstr "Weder --package noch --updates wurden als Option gewählt."
 
 #. TRANSLATORS: This is when the user fails to supply just one argument
-#: ../client/pk-generate-pack.c:174
+#: ../client/pk-generate-pack.c:221
 msgid "Both options selected."
 msgstr "Beide Optionen ausgewählt."
 
 #. TRANSLATORS: This is when file already exists
-#: ../client/pk-generate-pack.c:207
+#: ../client/pk-generate-pack.c:254
 msgid "A pack with the same name already exists, do you want to overwrite it?"
 msgstr "Ein Pack mit dem selben Namen existiert bereits, möchten Sie es überschreiben?"
 
 #. TRANSLATORS: This is when the pack was not overwritten
-#: ../client/pk-generate-pack.c:210
+#: ../client/pk-generate-pack.c:257
 msgid "The pack was not overwritten."
-msgstr ""
+msgstr "Das Pack wurde nicht überschrieben."
 
 #. TRANSLATORS: This is when the temporary directory cannot be created, the directory name follows
-#: ../client/pk-generate-pack.c:222
-#, fuzzy
+#: ../client/pk-generate-pack.c:269
 msgid "Failed to create directory:"
-msgstr "Verzeichnis konnte nicht erstellt werden"
+msgstr "Verzeichnis konnte nicht erstellt werden:"
 
 #. TRANSLATORS: This is when the list of packages from the remote computer cannot be opened
-#: ../client/pk-generate-pack.c:231
-#, fuzzy
+#: ../client/pk-generate-pack.c:278
 msgid "Failed to open package list."
-msgstr "Pack konnte nicht erstellt werden"
+msgstr "Konnte Paketliste nicht öffnen."
 
 #. TRANSLATORS: The package name is being matched up to available packages
-#: ../client/pk-generate-pack.c:241
+#: ../client/pk-generate-pack.c:288
 msgid "Finding package name."
 msgstr "Suche Paketname."
 
 #. TRANSLATORS: This is when the package cannot be found in any software source. The detailed error follows
-#: ../client/pk-generate-pack.c:245
-#, fuzzy, c-format
+#: ../client/pk-generate-pack.c:292
+#, c-format
 msgid "Failed to find package '%s': %s"
-msgstr "Paket konnte nicht gefunden werden '%s': %s"
+msgstr "Paket '%s' konnte nicht gefunden werden: %s"
 
 #. TRANSLATORS: This is telling the user we are in the process of making the pack
-#: ../client/pk-generate-pack.c:260
+#: ../client/pk-generate-pack.c:308
 msgid "Creating service pack..."
 msgstr "Erstelle Servicepack..."
 
 #. TRANSLATORS: we succeeded in making the file
-#: ../client/pk-generate-pack.c:267
+#: ../client/pk-generate-pack.c:315
 #, c-format
 msgid "Service pack created '%s'"
 msgstr "Servicepack erstellt '%s'"
 
 #. TRANSLATORS: we failed to make te file
-#: ../client/pk-generate-pack.c:271
-#, fuzzy, c-format
+#: ../client/pk-generate-pack.c:319
+#, c-format
 msgid "Failed to create '%s': %s"
-msgstr "Pack konnte nicht erstellt werden"
+msgstr "Erzeugen von '%s' fehlgeschlagen: %s"
 
 #: ../client/pk-monitor.c:128
 msgid "PackageKit Monitor"
-msgstr "PackageKit Monitor"
+msgstr "PackageKit-Monitor"
 
 #. TRANSLATORS: The package was not found in any software sources
 #: ../client/pk-tools-common.c:108
@@ -444,13 +457,11 @@ msgstr "Das Paket konnte nicht gefunden werden"
 
 #. TRANSLATORS: more than one package could be found that matched, to follow is a list of possible packages
 #: ../client/pk-tools-common.c:119
-#, fuzzy
 msgid "More than one package matches:"
-msgstr "Es passen mehrere Pakete zu Ihrer Anfrage"
+msgstr "Es passen mehr als ein Pakete:"
 
 #. TRANSLATORS: This finds out which package in the list to use
 #: ../client/pk-tools-common.c:126
-#, fuzzy
 msgid "Please choose the correct package: "
 msgstr "Bitte wählen Sie das korrekte Paket: "
 
@@ -472,7 +483,6 @@ msgstr "Starte %s"
 
 #. TRANSLATORS: show the installed version of a package
 #: ../contrib/packagekit-plugin/src/contents.cpp:311
-#, fuzzy
 msgid "Installed version"
 msgstr "Installierte Version"
 
@@ -505,13 +515,11 @@ msgstr "Version"
 
 #. TRANSLATORS: noting found, so can't install
 #: ../contrib/packagekit-plugin/src/contents.cpp:344
-#, fuzzy
 msgid "No packages found for your system"
 msgstr "Keine Pakete für Ihr System gefunden"
 
 #. TRANSLATORS: package is being installed
 #: ../contrib/packagekit-plugin/src/contents.cpp:349
-#, fuzzy
 msgid "Installing..."
 msgstr "Installiere..."
 
@@ -524,9 +532,8 @@ msgid "PackageKit Service Pack"
 msgstr "PackageKit Service-Pack"
 
 #: ../data/packagekit-package-list.xml.in.h:1
-#, fuzzy
 msgid "PackageKit Package List"
-msgstr "PackageKit Paketliste"
+msgstr "PackageKit-Paketliste"
 
 #: ../src/pk-main.c:85
 msgid "Startup failed due to security policies on this machine."
@@ -541,13 +548,8 @@ msgid "The correct user is not launching the executable (usually root)"
 msgstr "Der korrekte Benutzer führt nicht das Programm aus (normalerweise root)"
 
 #: ../src/pk-main.c:88
-#, fuzzy
-msgid ""
-"The org.freedesktop.PackageKit.conf file is not installed in the system "
-"directory:"
-msgstr ""
-"Die org.freedesktop.PackageKit.conf-Datei ist nicht auf Ihrem Rechner im "
-"Verzeichnis /etc/dbus-1/system.d installiert."
+msgid "The org.freedesktop.PackageKit.conf file is not installed in the system directory:"
+msgstr "Die org.freedesktop.PackageKit.conf-Datei ist nicht auf Ihrem Rechner im system-Verzeichnis:"
 
 #: ../src/pk-main.c:192
 msgid "Packaging backend to use, e.g. dummy"
@@ -570,8 +572,9 @@ msgid "Exit after a small delay"
 msgstr "Beende nach kurzer Verzögerung"
 
 #: ../src/pk-main.c:204
+#, fuzzy
 msgid "Exit after the engine has loaded"
-msgstr "Beende, nachdem die Maschine geladen wurde"
+msgstr "Beende, nachdem die Kern geladen wurde"
 
 #: ../src/pk-main.c:214
 msgid "PackageKit service"
@@ -588,87 +591,62 @@ msgstr "Fehler beim Starten von: %s\n"
 
 #~ msgid "Update detail"
 #~ msgstr "Details werden aktualisiert"
-
 #~ msgid "A system restart is required"
 #~ msgstr "Ein Neustart ist erforderlich"
-
 #~ msgid "A logout and login is required"
 #~ msgstr "Ein Aus- und Einloggen ist erforderlich"
-
 #~ msgid "An application restart is required"
 #~ msgstr "Ein Programm-Neustart wird benötigt"
-
 #~ msgid "Could not find package to remove"
 #~ msgstr "Packet zum Löschen konnte nicht gefunden werden"
-
 #~ msgid "Cancelled!"
 #~ msgstr "Abbruch!"
-
 #~ msgid "Could not find package to download"
 #~ msgstr "Das Packet zum Herunterladen konnte nicht gefunden werden"
-
 #~ msgid "Could not find package to update"
 #~ msgstr "Das Packet zum Aktualisieren konnte nicht gefunden werden"
-
 #~ msgid "Could not find what packages require"
 #~ msgstr "Konnte nicht herausfinden, was die Packete benötigen"
-
 #~ msgid "Could not find details for"
 #~ msgstr "Konnte keine Details finden für"
-
 #~ msgid "Okay to import key?"
 #~ msgstr "Soll der Schlüssel importiert werden?"
-
 #~ msgid "Did not import key"
 #~ msgstr "Schlüssel wurde nicht importiert"
-
 #~ msgid "Did not agree to licence, task will fail"
 #~ msgstr "Sie stimmten der Lizenz nicht zu, die Aufgabe wird fehlschlagen"
-
 #~ msgid "You need to specify a time term"
 #~ msgstr "Sie müssen einen Zeit-Begriff angeben"
-
 #~ msgid "Could not find a package match"
 #~ msgstr "Es konnte kein Packet gefunden werden"
-
 #~ msgid "failed to download: invalid package_id and/or directory"
 #~ msgstr ""
 #~ "Herunterladen fehlgeschlagen: Ungültige package_id und/oder ungültiges "
 #~ "Verzeichnis"
-
 #~ msgid "Could not find a valid metadata file"
 #~ msgstr "Eine gültige Metadata–Datei konnte nicht gefunden werden"
-
 #~ msgid "Okay to download the additional packages"
 #~ msgstr "Möchten Sie die zusätzlichen Packete herunterladen"
-
 #~ msgid "You need to specify the pack name and packages to be packed\n"
 #~ msgstr "Sie müssen einen Packnamen und Packete zum Packen angeben\n"
-
 #~ msgid ""
 #~ "Invalid name for the service pack, Specify a name with .servicepack "
 #~ "extension\n"
 #~ msgstr ""
 #~ "Ungültiger Name für ein Service Pack, geben Sie einen Namen an mit ."
 #~ "servicepack als Endung\n"
-
 #~ msgid "Could not set database readonly"
 #~ msgstr "Datenbank konnte nicht nur-lesbar gesetzt werden"
-
 #~ msgid "Could not open database: %s"
 #~ msgstr "Datenbank %s konnte nicht geöffnet werden"
-
 #~ msgid "You probably need to run this program as the root user"
 #~ msgstr "Sie sollten dieses Programm vermutlich als Benutzer root ausführen"
-
 #~ msgid "<span color='#%06x' underline='single' size='larger'>Run %s</span>"
 #~ msgstr ""
 #~ "<span color='#%06x' underline='single' size='larger'>%s wird ausgeführt</"
 #~ "span>"
-
 #~ msgid "<big>%s</big>"
 #~ msgstr "<big>%s</big>"
-
 #~ msgid ""
 #~ "\n"
 #~ "<span color='#%06x' underline='single'>Run version %s now</span>"
@@ -676,30 +654,27 @@ msgstr "Fehler beim Starten von: %s\n"
 #~ "\n"
 #~ "<span color='#%06x' underline='single'>Version %s wird jetzt ausgeführt</"
 #~ "span>"
-
 #~ msgid ""
 #~ "\n"
 #~ "<span color='#%06x' underline='single'>Run now</span>"
 #~ msgstr ""
 #~ "\n"
 #~ "<span color='#%06x' underline='single'>Wird jetzt ausgeführt</span>"
-
 #~ msgid ""
 #~ "\n"
 #~ "<span color='#%06x' underline='single'>Upgrade to version %s</span>"
 #~ msgstr ""
 #~ "\n"
 #~ "<span color='#%06x' underline='single'>Aktualisiere zu Version %s</span>"
-
 #~ msgid ""
 #~ "<span color='#%06x' underline='single' size='larger'>Install %s Now</span>"
 #~ msgstr ""
 #~ "<span color='#%06x' underline='single' size='larger'>%s wird jetzt "
 #~ "installiert</span>"
-
 #~ msgid ""
 #~ "\n"
 #~ "<small>Version: %s</small>"
 #~ msgstr ""
 #~ "\n"
 #~ "<small>Version: %s</small>"
+
commit c1a018d34f37e6951efe8d62ad5446dae125e382
Merge: e564c2d... 6889c37...
Author: Stefan Haas <shaas at suse.de>
Date:   Fri Nov 7 10:09:49 2008 +0100

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

commit e564c2da7e8eba10e0aebbd958123b0582f08cdc
Author: Stefan Haas <shaas at suse.de>
Date:   Fri Nov 7 10:09:35 2008 +0100

    zypp: set status when installing a signature

diff --git a/backends/zypp/pk-backend-zypp.cpp b/backends/zypp/pk-backend-zypp.cpp
index 6cedb5e..fb5dc85 100644
--- a/backends/zypp/pk-backend-zypp.cpp
+++ b/backends/zypp/pk-backend-zypp.cpp
@@ -1130,6 +1130,7 @@ backend_install_packages (PkBackend *backend, gchar **package_ids)
 static gboolean
 backend_install_signature_thread (PkBackend *backend)
 {
+	pk_backend_set_status (backend, PK_STATUS_ENUM_SIG_CHECK);
 	const gchar *key_id = pk_backend_get_string (backend, "key_id");
 	_signatures[backend]->push_back ((std::string)(key_id));
 
commit b068f8e662c2e2fcf91a6252ab08d1f57f2218a7
Merge: ce4bee7... 6889c37...
Author: Richard Hughes <richard at hughsie.com>
Date:   Fri Nov 7 09:07:22 2008 +0000

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

commit 6889c37f87dbad5f614c29ad3aa60a30b6f87bae
Merge: 6e51378... a3d25f9...
Author: sebastian Heinlein <devel at glatzor.de>
Date:   Thu Nov 6 16:10:27 2008 +0100

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

commit 6e51378913d75a78421ecbccacdd85b5a0aa7a9d
Author: sebastian Heinlein <devel at glatzor.de>
Date:   Thu Nov 6 15:07:02 2008 +0100

    Python client: Replace the async parameter by an exit_handler

diff --git a/lib/python/packagekit/client.py b/lib/python/packagekit/client.py
index 4e52d4d..7f51e61 100644
--- a/lib/python/packagekit/client.py
+++ b/lib/python/packagekit/client.py
@@ -63,9 +63,10 @@ class PackageKitTransaction:
         self.tid = tid
         self._error_enum = None
         self._error_desc = None
-        self._finished_status = None
+        self._exit_status = None
         self._allow_cancel = False
         self._method = None
+        self._exit_handler = None
         self.result = []
         # Connect the signal handlers to the DBus iface
         self._iface = iface
@@ -84,7 +85,7 @@ class PackageKitTransaction:
 
     def connect_to_signal(self, sig, cb):
         '''Connect to a signal of the transaction's DBus interface'''
-        self._iface.connect_to_signal(sig, cb)
+        return self._iface.connect_to_signal(sig, cb)
 
     def _on_package(self, i, id, summary):
         '''Callback for Package signal'''
@@ -134,29 +135,26 @@ class PackageKitTransaction:
         self._error_enum = enum
         self._error_desc = desc
 
-    def _on_finished(self, status, code):
+    def _on_finished(self, exit, runtime):
         '''Callback for Finished signal'''
-        self._finished_status = status
+        self._exit = exit
         self._main_loop.quit()
+        if self._exit_handler:
+            self._exit_handler(self, exit, runtime)
 
     def set_method(self, method, *args):
         '''Setup the method of the DBus interface which should be handled'''
         self._method = self._iface.get_dbus_method(method)
         self._args = args
 
-    def run(self, wait=True):
-        '''
-        Start processing the transaction.
-
-        If wait is True the method will return the result after the
-        processing is done.
-        '''
+    def run(self):
+        '''Start processing the transaction'''
         # avoid blocking the user interface
         context = gobject.main_context_default()
         while context.pending():
             context.iteration()
         polkit_auth_wrapper(self._method, *self._args)
-        if wait == True:
+        if not self._exit_handler:
             self._main_loop.run()
             if self._error_enum:
                 raise PackageKitError(self._error_enum, self._error_desc)
@@ -215,62 +213,70 @@ class PackageKitClient:
             # not initialized, or daemon timed out
             pass
 
-    def Resolve(self, filters, packages, async=False):
+    def Resolve(self, filters, packages, exit_handler=None):
         '''Resolve package names'''
         packages = self._to_list(packages)
-        return self._run_transaction("Resolve", [filters, packages], async)
+        return self._run_transaction("Resolve", [filters, packages],
+                                     exit_handler)
 
-    def GetDetails(self, package_ids, async=False):
+    def GetDetails(self, package_ids, exit_handler=None):
         '''Get details about the given packages'''
         package_ids = self._to_list(package_ids)
-        return self._run_transaction("GetDetails", [package_ids], async)
+        return self._run_transaction("GetDetails", [package_ids],
+                                     exit_handler)
 
-    def SearchName(self, filters, search, async=False):
+    def SearchName(self, filters, search, exit_handler=None):
         '''Search for packages by name'''
-        return self._run_transaction("SearchName", [filters, search], async)
+        return self._run_transaction("SearchName", [filters, search],
+                                     exit_handler)
 
-    def SearchGroup(self, filters, search, async=False):
+    def SearchGroup(self, filters, search, exit_handler=None):
         '''Search for packages by their group'''
-        return self._run_transaction("SearchGroup", [filters, search], async)
+        return self._run_transaction("SearchGroup", [filters, search], 
+                                     exit_handler)
 
-    def SearchDetails(self, filters, search, async=False):
+    def SearchDetails(self, filters, search, exit_handler=None):
         '''Search for packages by their details'''
-        return self._run_transaction("SearchDetails", [filters], async)
+        return self._run_transaction("SearchDetails", [filters], 
+                                     exit_handler)
 
-    def SearchFile(self, filters, search, async=False):
+    def SearchFile(self, filters, search, exit_handler=None):
         '''Search for packages by their files'''
-        return self._run_transaction("SearchFile", [filters], async)
+        return self._run_transaction("SearchFile", [filters], 
+                                     exit_handler)
 
-    def InstallPackages(self, package_ids, async=False):
+    def InstallPackages(self, package_ids, exit_handler=None):
         '''Install the packages of the given package ids'''
         package_ids = self._to_list(package_ids)
-        return self._run_transaction("InstallPackages", [package_ids], async)
+        return self._run_transaction("InstallPackages", [package_ids], 
+                                     exit_handler)
 
-    def UpdatePackages(self, package_ids, async=False):
+    def UpdatePackages(self, package_ids, exit_handler=None):
         '''Update the packages of the given package ids'''
         package_ids = self._to_list(package_ids)
-        return self._run_transaction("UpdatePackages", [package_ids], async)
+        return self._run_transaction("UpdatePackages", [package_ids], 
+                                     exit_handler)
 
     def RemovePackages(self, package_ids, allow_deps=False, auto_remove=True,
-                       async=False):
+                       exit_handler=None):
         '''Remove the packages of the given package ids'''
         package_ids = self._to_list(package_ids)
         return self._run_transaction("RemovePackages",
                                      [package_ids, allow_deps, auto_remove],
-                                     async)
+                                     exit_handler)
 
-    def RefreshCache(self, force=False, async=False):
+    def RefreshCache(self, force=False, exit_handler=None):
         '''
         Refresh the cache, i.e. download new metadata from a
         remote URL so that package lists are up to date. This action
         may take a few minutes and should be done when the session and
         system are idle.
         '''
-        return self._run_transaction("RefreshCache", (force,), async)
+        return self._run_transaction("RefreshCache", (force,), exit_handler)
 
-    def GetRepoList(self, filters=FILTER_NONE, async=False):
+    def GetRepoList(self, filters=FILTER_NONE, exit_handler=None):
         '''Get the repositories'''
-        return self._run_transaction("GetRepoList", (filters,), async)
+        return self._run_transaction("GetRepoList", (filters,), exit_handler)
 
     def RepoEnable(self, repo_id, enabled):
         '''
@@ -278,95 +284,102 @@ class PackageKitClient:
         repo_id is a repository identifier, e.g. fedora-development-debuginfo
         enabled true if enabled, false if disabled
         '''
-        return self._run_transaction("RepoEnable", (repo_id, enabled), async)
+        return self._run_transaction("RepoEnable", (repo_id, enabled),
+                                     exit_handler)
 
-    def GetUpdates(self, filters=FILTER_NONE, async=False):
+    def GetUpdates(self, filters=FILTER_NONE, exit_handler=None):
         '''
         This method should return a list of packages that are installed and
         are upgradable.
 
         It should only return the newest update for each installed package.
         '''
-        return self._run_transaction("GetUpdates", [filters], async)
+        return self._run_transaction("GetUpdates", [filters], exit_handler)
 
-    def GetCategories(self, async=False):
+    def GetCategories(self, exit_handler=None):
         '''Return available software categories'''
-        return self._run_transaction("GetCategories", [], async)
+        return self._run_transaction("GetCategories", [], exit_handler)
 
-    def GetPackages(self, filters=FILTER_NONE, async=False):
+    def GetPackages(self, filters=FILTER_NONE, exit_handler=None):
         '''Return all packages'''
-        return self._run_transaction("GetUpdates", [filters], async)
+        return self._run_transaction("GetUpdates", [filters], exit_handler)
 
-    def UpdateSystem(self, async=False):
+    def UpdateSystem(self, exit_handler=None):
         '''Update the system'''
-        return self._run_transaction("UpdateSystem", [], async)
+        return self._run_transaction("UpdateSystem", [], exit_handler)
 
-    def DownloadPackages(self, package_ids, async=False):
+    def DownloadPackages(self, package_ids, exit_handler=None):
         '''Download package files'''
         package_ids = self._to_list(package_ids)
-        return self._run_transaction("DownloadPackages", [package_ids], async)
+        return self._run_transaction("DownloadPackages", [package_ids], exit_handler)
 
-    def GetDepends(self, filters, package_ids, recursive=False, async=False):
-        '''
-        Search for dependencies for packages
-        '''
+    def GetDepends(self, filters, package_ids, recursive=False, 
+                   exit_handler=None):
+        '''Search for dependencies for packages'''
         package_ids = self._to_list(package_ids)
         return self._run_transaction("GetDepends",
                                      [filters, package_ids, recursive],
-                                     async)
+                                     exit_handler)
 
-    def GetFiles(self, package_ids, async=False):
+    def GetFiles(self, package_ids, exit_handler=None):
         '''Get files of the given packages'''
         package_ids = self._to_list(package_ids)
-        return self._run_transaction("GetFiles", [package_ids], async)
+        return self._run_transaction("GetFiles", [package_ids], exit_handler)
 
-    def GetRequires(self, filters, package_ids, recursive=False, async=False):
+    def GetRequires(self, filters, package_ids, recursive=False, 
+                    exit_handler=None):
         '''Search for requirements for packages'''
         package_ids = self._to_list(package_ids)
         return self._run_transaction("GetRequires",
                                      [filters, package_ids, recursive],
-                                     async)
+                                     exit_handler)
 
-    def GetUpdateDetail(self, package_ids, async=False):
+    def GetUpdateDetail(self, package_ids, exit_handler=None):
         '''Get details for updates'''
         package_ids = self._to_list(package_ids)
-        return self._run_transaction("GetUpdateDetail", [package_ids], async)
+        return self._run_transaction("GetUpdateDetail", [package_ids], 
+                                     exit_handler)
 
-    def GetDistroUpgrades(self, async=False):
+    def GetDistroUpgrades(self, exit_handler=None):
         '''Query for later distribution releases'''
-        return self._run_transaction("GetDistroUpgrades", [], async)
+        return self._run_transaction("GetDistroUpgrades", [],
+                                     exit_handler)
 
-    def InstallFiles(self, trusted, files, async=False):
+    def InstallFiles(self, trusted, files, exit_handler=None):
         '''Install the given local packages'''
-        return self._run_transaction("InstallFiles", [trusted, files], async)
+        return self._run_transaction("InstallFiles", [trusted, files], 
+                                     exit_handler)
 
-    def InstallSignature(self, sig_type, key_id, package_id, async=False):
+    def InstallSignature(self, sig_type, key_id, package_id, 
+                         exit_handler=None):
         '''Install packages signing keys used to validate packages'''
         return self._run_transaction("InstallSignature",
                                      [sig_type, key_id, package_id],
-                                     async)
+                                     exit_handler)
 
-    def RepoSetData(self, repo_id, parameter, value, async=False):
+    def RepoSetData(self, repo_id, parameter, value, exit_handler=None):
         '''Change custom parameter of a repository'''
         return self._run_transaction("RepoSetData",
                                      [repo_id, parameter, value],
-                                     async)
+                                     exit_handler)
 
-    def Rollback(self, transaction_id, async=False):
+    def Rollback(self, transaction_id, exit_handler=None):
         '''Roll back to a previous transaction'''
-        return self._run_transaction("Rollback", [transaction_id], async)
+        return self._run_transaction("Rollback", [transaction_id], 
+                                     exit_handler)
 
-    def WhatProvides(self, provides, search, async=False):
+    def WhatProvides(self, provides, search, exit_handler=None):
         '''Search for packages that provide the supplied attributes'''
-        return self._run_transaction("WhatProvides", [provides, search], async)
+        return self._run_transaction("WhatProvides", [provides, search], 
+                                     exit_handler)
 
     def SetLocale(self, code):
         '''Set the language of the client'''
         self._locale = code
 
-    def AcceptEula(self, eula_id, async=False):
+    def AcceptEula(self, eula_id, exit_handler=None):
         '''Accept the given end user licence aggreement'''
-        return self._run_transaction("AcceptEula", [eula_id], async)
+        return self._run_transaction("AcceptEula", [eula_id], exit_handler)
 
     #
     # Internal helper functions
@@ -377,7 +390,7 @@ class PackageKitClient:
             obj = [obj]
         return obj
 
-    def _run_transaction(self, method_name, args, async):
+    def _run_transaction(self, method_name, args, exit_handler):
         '''Run the given method in a new transaction'''
         try:
             tid = self.pk_control.GetTid()
@@ -399,7 +412,8 @@ class PackageKitClient:
         if self._locale:
             trans.SetLocale(self._locale)
         trans.set_method(method_name, *args)
-        if async:
+        if exit_handler:
+            trans._exit_handler = exit_handler
             return trans
         else:
             return trans.run()
commit ce4bee74f283331260dae18b1884f5d257816380
Author: Richard Hughes <richard at hughsie.com>
Date:   Thu Nov 6 14:03:13 2008 +0000

    trivial: when a called function is not implemented there's no need to exit the process

diff --git a/lib/python/packagekit/backend.py b/lib/python/packagekit/backend.py
index a43536d..fc4fd2e 100644
--- a/lib/python/packagekit/backend.py
+++ b/lib/python/packagekit/backend.py
@@ -250,91 +250,91 @@ class PackageKitBaseBackend:
         Implement the {backend}-search-name functionality
         Needed to be implemented in a sub class
         '''
-        self.error(ERROR_NOT_SUPPORTED, "This function is not implemented in this backend")
+        self.error(ERROR_NOT_SUPPORTED, "This function is not implemented in this backend", exit=False)
 
     def search_details(self, filters, key):
         '''
         Implement the {backend}-search-details functionality
         Needed to be implemented in a sub class
         '''
-        self.error(ERROR_NOT_SUPPORTED, "This function is not implemented in this backend")
+        self.error(ERROR_NOT_SUPPORTED, "This function is not implemented in this backend", exit=False)
 
     def search_group(self, filters, key):
         '''
         Implement the {backend}-search-group functionality
         Needed to be implemented in a sub class
         '''
-        self.error(ERROR_NOT_SUPPORTED, "This function is not implemented in this backend")
+        self.error(ERROR_NOT_SUPPORTED, "This function is not implemented in this backend", exit=False)
 
     def search_file(self, filters, key):
         '''
         Implement the {backend}-search-file functionality
         Needed to be implemented in a sub class
         '''
-        self.error(ERROR_NOT_SUPPORTED, "This function is not implemented in this backend")
+        self.error(ERROR_NOT_SUPPORTED, "This function is not implemented in this backend", exit=False)
 
     def get_update_detail(self, package_ids_ids):
         '''
         Implement the {backend}-get-update-detail functionality
         Needed to be implemented in a sub class
         '''
-        self.error(ERROR_NOT_SUPPORTED, "This function is not implemented in this backend")
+        self.error(ERROR_NOT_SUPPORTED, "This function is not implemented in this backend", exit=False)
 
     def get_depends(self, filters, package_ids, recursive):
         '''
         Implement the {backend}-get-depends functionality
         Needed to be implemented in a sub class
         '''
-        self.error(ERROR_NOT_SUPPORTED, "This function is not implemented in this backend")
+        self.error(ERROR_NOT_SUPPORTED, "This function is not implemented in this backend", exit=False)
 
     def get_packages(self, filters):
         '''
         Implement the {backend}-get-packages functionality
         Needed to be implemented in a sub class
         '''
-        self.error(ERROR_NOT_SUPPORTED, "This function is not implemented in this backend")
+        self.error(ERROR_NOT_SUPPORTED, "This function is not implemented in this backend", exit=False)
 
     def get_requires(self, filters, package_ids, recursive):
         '''
         Implement the {backend}-get-requires functionality
         Needed to be implemented in a sub class
         '''
-        self.error(ERROR_NOT_SUPPORTED, "This function is not implemented in this backend")
+        self.error(ERROR_NOT_SUPPORTED, "This function is not implemented in this backend", exit=False)
 
     def what_provides(self, filters, provides_type, search):
         '''
         Implement the {backend}-what-provides functionality
         Needed to be implemented in a sub class
         '''
-        self.error(ERROR_NOT_SUPPORTED, "This function is not implemented in this backend")
+        self.error(ERROR_NOT_SUPPORTED, "This function is not implemented in this backend", exit=False)
 
     def update_system(self):
         '''
         Implement the {backend}-update-system functionality
         Needed to be implemented in a sub class
         '''
-        self.error(ERROR_NOT_SUPPORTED, "This function is not implemented in this backend")
+        self.error(ERROR_NOT_SUPPORTED, "This function is not implemented in this backend", exit=False)
 
     def refresh_cache(self):
         '''
         Implement the {backend}-refresh_cache functionality
         Needed to be implemented in a sub class
         '''
-        self.error(ERROR_NOT_SUPPORTED, "This function is not implemented in this backend")
+        self.error(ERROR_NOT_SUPPORTED, "This function is not implemented in this backend", exit=False)
 
     def install_packages(self, package_ids):
         '''
         Implement the {backend}-install functionality
         Needed to be implemented in a sub class
         '''
-        self.error(ERROR_NOT_SUPPORTED, "This function is not implemented in this backend")
+        self.error(ERROR_NOT_SUPPORTED, "This function is not implemented in this backend", exit=False)
 
     def install_signature(self, sigtype, key_id, package):
         '''
         Implement the {backend}-install-signature functionality
         Needed to be implemented in a sub class
         '''
-        self.error(ERROR_NOT_SUPPORTED, "This function is not implemented in this backend")
+        self.error(ERROR_NOT_SUPPORTED, "This function is not implemented in this backend", exit=False)
 
     def install_files (self, trusted, inst_files):
         '''
@@ -342,105 +342,105 @@ class PackageKitBaseBackend:
         Install the package containing the inst_file file
         Needed to be implemented in a sub class
         '''
-        self.error(ERROR_NOT_SUPPORTED, "This function is not implemented in this backend")
+        self.error(ERROR_NOT_SUPPORTED, "This function is not implemented in this backend", exit=False)
 
     def resolve(self, filters, name):
         '''
         Implement the {backend}-resolve functionality
         Needed to be implemented in a sub class
         '''
-        self.error(ERROR_NOT_SUPPORTED, "This function is not implemented in this backend")
+        self.error(ERROR_NOT_SUPPORTED, "This function is not implemented in this backend", exit=False)
 
     def remove_packages(self, allowdep, package_ids):
         '''
         Implement the {backend}-remove functionality
         Needed to be implemented in a sub class
         '''
-        self.error(ERROR_NOT_SUPPORTED, "This function is not implemented in this backend")
+        self.error(ERROR_NOT_SUPPORTED, "This function is not implemented in this backend", exit=False)
 
     def update_packages(self, package):
         '''
         Implement the {backend}-update functionality
         Needed to be implemented in a sub class
         '''
-        self.error(ERROR_NOT_SUPPORTED, "This function is not implemented in this backend")
+        self.error(ERROR_NOT_SUPPORTED, "This function is not implemented in this backend", exit=False)
 
     def get_details(self, package):
         '''
         Implement the {backend}-get-details functionality
         Needed to be implemented in a sub class
         '''
-        self.error(ERROR_NOT_SUPPORTED, "This function is not implemented in this backend")
+        self.error(ERROR_NOT_SUPPORTED, "This function is not implemented in this backend", exit=False)
 
     def get_files(self, package):
         '''
         Implement the {backend}-get-files functionality
         Needed to be implemented in a sub class
         '''
-        self.error(ERROR_NOT_SUPPORTED, "This function is not implemented in this backend")
+        self.error(ERROR_NOT_SUPPORTED, "This function is not implemented in this backend", exit=False)
 
     def get_updates(self, filters):
         '''
         Implement the {backend}-get-updates functionality
         Needed to be implemented in a sub class
         '''
-        self.error(ERROR_NOT_SUPPORTED, "This function is not implemented in this backend")
+        self.error(ERROR_NOT_SUPPORTED, "This function is not implemented in this backend", exit=False)
 
     def get_distro_upgrades(self):
         '''
         Implement the {backend}-get-distro-upgrades functionality
         Needed to be implemented in a sub class
         '''
-        self.error(ERROR_NOT_SUPPORTED, "This function is not implemented in this backend")
+        self.error(ERROR_NOT_SUPPORTED, "This function is not implemented in this backend", exit=False)
 
     def repo_enable(self, repoid, enable):
         '''
         Implement the {backend}-repo-enable functionality
         Needed to be implemented in a sub class
         '''
-        self.error(ERROR_NOT_SUPPORTED, "This function is not implemented in this backend")
+        self.error(ERROR_NOT_SUPPORTED, "This function is not implemented in this backend", exit=False)
 
     def repo_set_data(self, repoid, parameter, value):
         '''
         Implement the {backend}-repo-set-data functionality
         Needed to be implemented in a sub class
         '''
-        self.error(ERROR_NOT_SUPPORTED, "This function is not implemented in this backend")
+        self.error(ERROR_NOT_SUPPORTED, "This function is not implemented in this backend", exit=False)
 
     def get_repo_list(self, filters):
         '''
         Implement the {backend}-get-repo-list functionality
         Needed to be implemented in a sub class
         '''
-        self.error(ERROR_NOT_SUPPORTED, "This function is not implemented in this backend")
+        self.error(ERROR_NOT_SUPPORTED, "This function is not implemented in this backend", exit=False)
 
     def repo_signature_install(self, package):
         '''
         Implement the {backend}-repo-signature-install functionality
         Needed to be implemented in a sub class
         '''
-        self.error(ERROR_NOT_SUPPORTED, "This function is not implemented in this backend")
+        self.error(ERROR_NOT_SUPPORTED, "This function is not implemented in this backend", exit=False)
 
     def download_packages(self, directory, packages):
         '''
         Implement the {backend}-download-packages functionality
         Needed to be implemented in a sub class
         '''
-        self.error(ERROR_NOT_SUPPORTED, "This function is not implemented in this backend")
+        self.error(ERROR_NOT_SUPPORTED, "This function is not implemented in this backend", exit=False)
 
     def set_locale(self, code):
         '''
         Implement the {backend}-set-locale functionality
         Needed to be implemented in a sub class
         '''
-        self.error(ERROR_NOT_SUPPORTED, "This function is not implemented in this backend")
+        self.error(ERROR_NOT_SUPPORTED, "This function is not implemented in this backend", exit=False)
 
     def get_categories(self):
         '''
         Implement the {backend}-get-categories functionality
         Needed to be implemented in a sub class
         '''
-        self.error(ERROR_NOT_SUPPORTED,"This function is not implemented in this backend")
+        self.error(ERROR_NOT_SUPPORTED,"This function is not implemented in this backend", exit=False)
 
     def customTracebackHandler(self, tb):
         '''
commit 80957a17704a9a948c7a24cdf1db625e394cff01
Author: Richard Hughes <richard at hughsie.com>
Date:   Thu Nov 6 14:01:30 2008 +0000

    bugfix: when we call Error() from a python spawned backend with exit=False, don't do Finished() else we'll do this twice and get warned by the daemon

diff --git a/lib/python/packagekit/backend.py b/lib/python/packagekit/backend.py
index 8443743..a43536d 100644
--- a/lib/python/packagekit/backend.py
+++ b/lib/python/packagekit/backend.py
@@ -85,9 +85,10 @@ class PackageKitBaseBackend:
 
         # this should be fast now
         print "error\t%s\t%s" % (err, description)
-        print "finished"
         sys.stdout.flush()
         if exit:
+            print "finished"
+            sys.stdout.flush()
             sys.exit(1)
 
     def message(self, typ, msg):
commit 15c8bc3a88bf5cb84518895a8be5cfea0ad76240
Author: Richard Hughes <richard at hughsie.com>
Date:   Thu Nov 6 13:59:57 2008 +0000

    trivial: fix up a markup comment

diff --git a/src/org.freedesktop.PackageKit.Transaction.xml b/src/org.freedesktop.PackageKit.Transaction.xml
index 2448e57..112cb1a 100644
--- a/src/org.freedesktop.PackageKit.Transaction.xml
+++ b/src/org.freedesktop.PackageKit.Transaction.xml
@@ -120,8 +120,7 @@
         </doc:description>
           <doc:para>
             This method typically emits
-            <literal>Categories</literal>,
-            <literal>Error</literal> and
+            <doc:tt>Categories</doc:tt> and <doc:tt>Error</doc:tt>.
           </doc:para>
       </doc:doc>
     </method>
commit a3d25f9b65138ac016a6a059fd216424cafead60
Author: Stefan Haas <shaas at suse.de>
Date:   Thu Nov 6 13:23:50 2008 +0100

    zypp: adapted signature callbacks

diff --git a/backends/zypp/zypp-events.h b/backends/zypp/zypp-events.h
index 0f08f94..e29c469 100644
--- a/backends/zypp/zypp-events.h
+++ b/backends/zypp/zypp-events.h
@@ -30,6 +30,7 @@
 #include <pk-backend.h>
 #include <zypp/ZYppCallbacks.h>
 #include <zypp/Digest.h>
+#include <zypp/KeyRing.h> 
 
 #include "zypp-utils.h"
 
@@ -326,35 +327,28 @@ struct DownloadProgressReportReceiver : public zypp::callback::ReceiveReport<zyp
 
 struct KeyRingReportReceiver : public zypp::callback::ReceiveReport<zypp::KeyRingReport>, ZyppBackendReceiver
 {
-        virtual bool askUserToAcceptUnsignedFile (const std::string &file)
+	virtual zypp::KeyRingReport::KeyTrust askUserToAcceptKey (const zypp::PublicKey &key, const zypp::KeyContext &keycontext)
+	{
+		if (zypp_signature_required(_backend, key))
+			return KEY_TRUST_AND_IMPORT;
+		return KEY_DONT_TRUST;
+	}
+
+        virtual bool askUserToAcceptUnsignedFile (const std::string &file, const zypp::KeyContext &keycontext)
         {
                 gboolean ok = zypp_signature_required(_backend, file);
 
                 return ok;
         }
 
-        virtual bool askUserToAcceptUnknownKey (const std::string &file, const std::string &id)
+        virtual bool askUserToAcceptUnknownKey (const std::string &file, const std::string &id, const zypp::KeyContext &keycontext)
         {
                 gboolean ok = zypp_signature_required(_backend, file, id);
 
                 return ok;
         }
 
-        virtual bool askUserToTrustKey (const zypp::PublicKey &key)
-        {
-                gboolean ok = zypp_signature_required(_backend, key);
-
-                return ok;
-        }
-
-        virtual bool askUserToImportKey (const zypp::PublicKey &key)
-        {
-                gboolean ok = zypp_signature_required(_backend, key);
-
-                return ok;
-        }
-
-	virtual bool askUserToAcceptVerificationFailed (const std::string &file, const zypp::PublicKey &key)
+	virtual bool askUserToAcceptVerificationFailed (const std::string &file, const zypp::PublicKey &key,  const zypp::KeyContext &keycontext)
 	{
 		gboolean ok = zypp_signature_required(_backend, key);
 
commit f3faa7027ab1868f2447c15a054a540b3fc5c946
Author: sebastian Heinlein <devel at glatzor.de>
Date:   Thu Nov 6 05:29:05 2008 +0100

    Python client: instead of getattr use get_dbus_method

diff --git a/lib/python/packagekit/client.py b/lib/python/packagekit/client.py
index eea299d..4e52d4d 100644
--- a/lib/python/packagekit/client.py
+++ b/lib/python/packagekit/client.py
@@ -141,7 +141,7 @@ class PackageKitTransaction:
 
     def set_method(self, method, *args):
         '''Setup the method of the DBus interface which should be handled'''
-        self._method = getattr(self._iface, method)
+        self._method = self._iface.get_dbus_method(method)
         self._args = args
 
     def run(self, wait=True):
commit a2491705ed64e91fc7d4c2cb69aaa67d8f8ba47f
Author: sebastian Heinlein <devel at glatzor.de>
Date:   Wed Nov 5 15:00:02 2008 +0100

    Redesign python packagekit client to support async operations.

diff --git a/lib/python/packagekit/client.py b/lib/python/packagekit/client.py
index 8c495bc..eea299d 100644
--- a/lib/python/packagekit/client.py
+++ b/lib/python/packagekit/client.py
@@ -1,5 +1,9 @@
 #!/usr/bin/python
-#
+'''
+The module provides a client to the PackageKit DBus interface. It allows to
+perform basic package manipulation tasks in a cross distribution way, e.g.
+to search for packages, install packages or codecs.
+'''
 # Licensed under the GNU General Public License Version 2
 #
 # This program is free software; you can redistribute it and/or modify
@@ -21,16 +25,20 @@
 #    Aidan Skinner <aidan at skinner.me.uk>
 #    Martin Pitt <martin.pitt at ubuntu.com>
 #    Tim Lauridsen <timlau at fedoraproject.org>
-#
-# Synchronous PackageKit client wrapper API for Python.
+#    Sebastian Heinlein <devel at glatzor.de>
 
+import locale
 import os
-import gobject
+
 import dbus
+import dbus.mainloop.glib
+dbus.mainloop.glib.DBusGMainLoop(set_as_default=True)
+import gobject
+
 from enums import *
 from misc import *
 
-__api_version__ = '0.1.0'
+__api_version__ = '0.1.1'
 
 class PackageKitError(Exception):
     '''PackageKit error.
@@ -46,388 +54,319 @@ class PackageKitError(Exception):
     def __str__(self):
         return "%s: %s" % (self.error, self.desc)
 
-class PackageKitClient:
-    '''PackageKit client wrapper class.
-
-    This exclusively uses synchonous calls. Functions which take a long time
-    (install/remove packages) have callbacks for progress feedback.
+class PackageKitTransaction:
     '''
-    def __init__(self, main_loop=None):
-        '''Initialize a PackageKit client.
+    This class represents a PackageKit transaction. It allows asynchronous and
+    synchronous processing
+    '''
+    def __init__(self, tid, iface):
+        self.tid = tid
+        self._error_enum = None
+        self._error_desc = None
+        self._finished_status = None
+        self._allow_cancel = False
+        self._method = None
+        self.result = []
+        # Connect the signal handlers to the DBus iface
+        self._iface = iface
+        for sig, cb in [('Finished', self._on_finished),
+                        ('ErrorCode', self._on_error),
+                        ('StatusChanged', self._on_status),
+                        ('AllowCancel', self._on_allow_cancel),
+                        ('Package', self._on_package),
+                        ('Details', self._on_details),
+                        ('Category', self._on_category),
+                        ('UpdateDetail', self._on_update_detail),
+                        ('DistroUpgrade', self._on_distro_upgrade),
+                        ('RepoDetail', self._on_repo_detail)]:
+            self._iface.connect_to_signal(sig, cb)
+        self._main_loop = gobject.MainLoop()
+
+    def connect_to_signal(self, sig, cb):
+        '''Connect to a signal of the transaction's DBus interface'''
+        self._iface.connect_to_signal(sig, cb)
+
+    def _on_package(self, i, id, summary):
+        '''Callback for Package signal'''
+        self.result.append(PackageKitPackage(i, id, summary))
+
+    def _on_distro_upgrade(self, typ, name, summary):
+        '''Callback for DistroUpgrade signal'''
+        self.result.append(PackageKitDistroUpgrade(typ, name, summary))
+
+    def _on_details(self, id, license, group, detail, url, size):
+        '''Callback for Details signal'''
+        self.result.append(PackageKitDetails(id, license, group, detail,
+                                             url, size))
+
+    def _on_category(self, parent_id, cat_id, name, summary, icon):
+        '''Callback for Category signal'''
+        self.result.append(PackageKitCategory(parent_id, cat_id, name,
+                                              summary, icon))
+
+    def _on_update_detail(self, id, updates, obsoletes, vendor_url,
+                          bugzilla_url, cve_url, restart, update_text,
+                          changelog, state, issued, updated):
+        '''Callback for UpdateDetail signal'''
+        self.result.append(PackageKitUpdateDetails(id, updates, obsoletes,
+                                                   vendor_url, bugzilla_url,
+                                                   cve_url, restart,
+                                                   update_text, changelog,
+                                                   state, issued, updated))
+    def _on_repo_detail(self, id, description, enabled):
+        '''Callback for RepoDetail signal'''
+        self.result.append(PackageKitRepos(id, description, enabled))
+
+    def _on_files(self, id, files):
+        '''Callback for Files signal'''
+        self.result.append(PackageKitFiles(id, files))
+
+    def _on_status(self, status):
+        '''Callback for StatusChanged signal'''
+        self._status = status
 
-        If main_loop is None, this sets up its own gobject.MainLoop(),
-        otherwise it attaches to the specified one.
-        '''
-        self.pk_control = None
-        if main_loop is None:
-            import dbus.mainloop.glib
-            main_loop = gobject.MainLoop()
-            dbus.mainloop.glib.DBusGMainLoop(set_as_default=True)
-        self.main_loop = main_loop
+    def _on_allow_cancel(self, allow):
+        '''Callback for AllowCancel signal'''
+        self._allow_cancel = allow
 
-        self.bus = dbus.SystemBus()
+    def _on_error(self, enum, desc):
+        '''Callback for ErrorCode signal'''
+        self._error_enum = enum
+        self._error_desc = desc
 
-    def _wrapCall(self, pk_xn, method, callbacks):
-        '''
-        Wraps a call which emits Finished and ErrorCode on completion
-        '''
-        pk_xn.connect_to_signal('Finished', self._h_finished)
-        pk_xn.connect_to_signal('ErrorCode', self._h_error)
-        pk_xn.connect_to_signal('StatusChanged', self._h_status)
-        pk_xn.connect_to_signal('AllowCancel', self._h_allowcancel)
-        pk_xn.connect_to_signal('ProgressChanged', self._h_progress)
-        for cb in callbacks.keys():
-            pk_xn.connect_to_signal(cb, callbacks[cb])
-
-        polkit_auth_wrapper(method)
-        self._wait()
-        if self._error_enum:
-            raise PackageKitError(self._error_enum, self._error_desc)
-
-    def _wrapBasicCall(self, pk_xn, method):
-        return self._wrapCall(pk_xn, method, {})
-
-    def _wrapPackageCall(self, pk_xn, method):
-        '''
-        Wraps a call which emits Finished, ErrorCode on completion and
-        Package for information returns a list of dicts with
-        'installed', 'id' and 'summary' keys
-        '''
+    def _on_finished(self, status, code):
+        '''Callback for Finished signal'''
+        self._finished_status = status
+        self._main_loop.quit()
 
-        result = []
-        package_cb = lambda i, id, summary: result.append(
-            PackageKitPackage(i, id, summary))
-        self._wrapCall(pk_xn, method, {'Package' : package_cb})
-        return result
+    def set_method(self, method, *args):
+        '''Setup the method of the DBus interface which should be handled'''
+        self._method = getattr(self._iface, method)
+        self._args = args
 
-    def _wrapDistroUpgradeCall(self, pk_xn, method):
+    def run(self, wait=True):
         '''
-        Wraps a call which emits Finished, ErrorCode on completion and
-        DistroUpgrade for information returns a list of dicts with
-        'type', 'name' and 'summary' keys
+        Start processing the transaction.
+
+        If wait is True the method will return the result after the
+        processing is done.
         '''
+        # avoid blocking the user interface
+        context = gobject.main_context_default()
+        while context.pending():
+            context.iteration()
+        polkit_auth_wrapper(self._method, *self._args)
+        if wait == True:
+            self._main_loop.run()
+            if self._error_enum:
+                raise PackageKitError(self._error_enum, self._error_desc)
+            return self.result
 
-        result = []
-        distup_cb = lambda typ, name, summary: result.append(
-            PackageKitDistroUpgrade(typ, name, summary))
-        self._wrapCall(pk_xn, method, {'DistroUpgrade' : distup_cb})
-        return result
+    def SetLocale(self, code):
+        '''Set the language to the given locale code'''
+        return self._iface.SetLocale(code)
 
-    def _wrapDetailsCall(self, pk_xn, method):
-        '''
-        Wraps a call which emits Finished, ErrorCode on completion and
-        Details for information returns a list of dicts with 'id',
-        'license', 'group', 'description', 'upstream_url', 'size'.keys
-        '''
-        result = []
-        details_cb = lambda id, license, group, detail, url, size: result.append(
-            PackageKitDetails(id, license, group, detail, url, size))
+    def Cancel(self):
+        '''Cancel the transaction'''
+        return self._iface.Cancel()
 
-        self._wrapCall(pk_xn, method, {'Details' : details_cb})
-        return result
+    def GetStatus(self):
+        '''Get the status of the transaction'''
+        return self._status
 
-    def _wrapCategoryCall(self, pk_xn, method):
-        '''
-        Wraps a call which emits Finished, ErrorCode on completion and
-        Details for information returns a list of dicts with 'id',
-        'license', 'group', 'description', 'upstream_url', 'size'.keys
-        '''
-        result = []
-        category_cb = lambda  parent_id, cat_id, name, summary, icon: result.append(
-            PackageKitCategory( parent_id, cat_id, name, summary, icon))
+    def GetProgress(self):
+        '''Get the progress of the transaction'''
+        return self._iface.GetProgress()
 
-        self._wrapCall(pk_xn, method, {'Category' : category_cb})
-        return result
+    def GetFinishedState(self):
+        '''Return the finished status'''
+        return self._finished_status
 
-    def _wrapUpdateDetailsCall(self, pk_xn, method):
-        '''
-        Wraps a call which emits Finished, ErrorCode on completion and
-        Details for information returns a list of dicts with 'id',
-        'license', 'group', 'description', 'upstream_url', 'size'.keys
+    def IsCallerActive(self):
         '''
-        result = []
-        details_cb =  lambda id, updates, obsoletes, vendor_url, bugzilla_url, \
-                             cve_url, restart, update_text, changelog, state, \
-                             issued, updated: result.append(
-            PackageKitUpdateDetails(id, updates, obsoletes, vendor_url, bugzilla_url, \
-                                    cve_url, restart, update_text, changelog, state, \
-                                    issued, updated))
-        self._wrapCall(pk_xn, method, {'UpdateDetail' : details_cb})
-        return result
-
-    def _wrapReposCall(self, pk_xn, method):
+        This method allows us to find if the original caller of the method is
+        still connected to the session bus. This is usually an indication that
+        the client can handle it's own error handling and EULA callbacks rather
+        than another program taking over.
         '''
-        Wraps a call which emits Finished, ErrorCode and RepoDetail
-        for information returns a list of dicts with 'id',
-        'description', 'enabled' keys
-        '''
-        result = []
-        repo_cb = lambda id, description, enabled: result.append(
-            PackageKitRepos(id, description, enabled))
-        self._wrapCall(pk_xn, method, {'RepoDetail' : repo_cb})
-        return result
+        return self._iface.IsCallerActive()
 
-    def _wrapFilesCall(self, pk_xn, method):
-        '''
-        Wraps a call which emits Finished, ErrorCode and Files
-        for information returns a list of dicts with 'id',
-        'files'
+class PackageKitClient:
+    '''PackageKit client wrapper class.
+
+    This exclusively uses synchonous calls. Functions which take a long time
+    (install/remove packages) have callbacks for progress feedback.
+    '''
+    def __init__(self, main_loop=None):
+        '''Initialize a PackageKit client.
+
+        If main_loop is None, this sets up its own gobject.MainLoop(),
+        otherwise it attaches to the specified one.
         '''
-        result = []
-        files_cb = lambda id, files: result.append(
-            PackageKitFiles(id, files))
-        self._wrapCall(pk_xn, method, {'Files' : files_cb})
-        return result
+        self.pk_control = None
+        self.bus = dbus.SystemBus()
+        self._locale = locale.getdefaultlocale()[0]
 
     def SuggestDaemonQuit(self):
         '''Ask the PackageKit daemon to shutdown.'''
-
         try:
             self.pk_control.SuggestDaemonQuit()
         except (AttributeError, dbus.DBusException), e:
             # not initialized, or daemon timed out
             pass
 
-    def Resolve(self, filters, package):
-        '''
-        Resolve a package name to a PackageKit package_id filters and
-        package are directly passed to the PackageKit transaction
-        D-BUS method Resolve()
+    def Resolve(self, filters, packages, async=False):
+        '''Resolve package names'''
+        packages = self._to_list(packages)
+        return self._run_transaction("Resolve", [filters, packages], async)
 
-        Return Dict with keys of (installed, id, short_description)
-        for all matches, where installed is a boolean and id and
-        short_description are strings.
-        '''
-        package = self._to_list(package) # Make sure we have a list
-        xn = self._get_xn()
-        return self._wrapPackageCall(xn, lambda : xn.Resolve(filters, package))
+    def GetDetails(self, package_ids, async=False):
+        '''Get details about the given packages'''
+        package_ids = self._to_list(package_ids)
+        return self._run_transaction("GetDetails", [package_ids], async)
 
-    def GetDetails(self, package_ids):
-        '''
-        Get details about a PackageKit package_ids.
+    def SearchName(self, filters, search, async=False):
+        '''Search for packages by name'''
+        return self._run_transaction("SearchName", [filters, search], async)
 
-        Return dict with keys (id, license, group, description,
-        upstream_url, size).
-        '''
-        package_ids = self._to_list(package_ids) # Make sure we have a list
-        xn = self._get_xn()
-        return self._wrapDetailsCall(xn, lambda : xn.GetDetails(package_ids))
+    def SearchGroup(self, filters, search, async=False):
+        '''Search for packages by their group'''
+        return self._run_transaction("SearchGroup", [filters, search], async)
 
-    def SearchName(self, filters, name):
-        '''
-        Search a package by name.
-        '''
-        xn = self._get_xn()
-        return self._wrapPackageCall(xn, lambda : xn.SearchName(filters, name))
+    def SearchDetails(self, filters, search, async=False):
+        '''Search for packages by their details'''
+        return self._run_transaction("SearchDetails", [filters], async)
 
-    def SearchGroup(self, filters, group_id):
-        '''
-        Search for a group.
-        '''
-        xn = self._get_xn()
-        return self._wrapPackageCall(xn, lambda : xn.SearchGroup(filters, group_id))
+    def SearchFile(self, filters, search, async=False):
+        '''Search for packages by their files'''
+        return self._run_transaction("SearchFile", [filters], async)
 
-    def SearchDetails(self, filters, name):
-        '''
-        Search a packages details.
-        '''
-        xn = self._get_xn()
-        return self._wrapPackageCall(xn,
-                                     lambda : xn.SearchDetails(filters, name))
-
-    def SearchFile(self, filters, search):
-        '''
-        Search for a file.
-        '''
-        xn = self._get_xn()
-        return self._wrapPackageCall(xn,
-                                     lambda : xn.SearchFile(filters, search))
+    def InstallPackages(self, package_ids, async=False):
+        '''Install the packages of the given package ids'''
+        package_ids = self._to_list(package_ids)
+        return self._run_transaction("InstallPackages", [package_ids], async)
 
-    def InstallPackages(self, package_ids, progress_cb=None):
-        '''Install a list of package IDs.
+    def UpdatePackages(self, package_ids, async=False):
+        '''Update the packages of the given package ids'''
+        package_ids = self._to_list(package_ids)
+        return self._run_transaction("UpdatePackages", [package_ids], async)
 
-        progress_cb is a function taking arguments (status, percentage,
-        subpercentage, elapsed, remaining, allow_cancel). If it returns False,
-        the action is cancelled (if allow_cancel == True), otherwise it
-        continues.
+    def RemovePackages(self, package_ids, allow_deps=False, auto_remove=True,
+                       async=False):
+        '''Remove the packages of the given package ids'''
+        package_ids = self._to_list(package_ids)
+        return self._run_transaction("RemovePackages",
+                                     [package_ids, allow_deps, auto_remove],
+                                     async)
 
-        On failure this throws a PackageKitError or a DBusException.
-        '''
-        package_ids = self._to_list(package_ids) # Make sure we have a list
-        xn = self._get_xn()
-        self._doPackages( xn, lambda : xn.InstallPackages(package_ids), progress_cb)
-
-    def UpdatePackages(self, package_ids, progress_cb=None):
-        '''UPdate a list of package IDs.
-
-        progress_cb is a function taking arguments (status, percentage,
-        subpercentage, elapsed, remaining, allow_cancel). If it returns False,
-        the action is cancelled (if allow_cancel == True), otherwise it
-        continues.
-
-        On failure this throws a PackageKitError or a DBusException.
-        '''
-        package_ids = self._to_list(package_ids) # Make sure we have a list
-        xn = self._get_xn()
-        self._doPackages(xn, lambda : xn.UpdatePackages(package_ids), progress_cb)
-
-    def RemovePackages(self, package_ids, progress_cb=None, allow_deps=False,
-        auto_remove=True):
-        '''Remove a list of package IDs.
-
-        progress_cb is a function taking arguments (status, percentage,
-        subpercentage, elapsed, remaining, allow_cancel). If it returns False,
-        the action is cancelled (if allow_cancel == True), otherwise it
-        continues.
-
-        allow_deps and auto_remove are passed to the PackageKit function.
-
-        On failure this throws a PackageKitError or a DBusException.
-        '''
-        package_ids = self._to_list(package_ids) # Make sure we have a list
-        xn = self._get_xn()
-        self._doPackages(xn, lambda : xn.RemovePackages(package_ids, allow_deps, auto_remove), progress_cb)
-
-    def RefreshCache(self, force=False):
+    def RefreshCache(self, force=False, async=False):
         '''
         Refresh the cache, i.e. download new metadata from a
         remote URL so that package lists are up to date. This action
         may take a few minutes and should be done when the session and
         system are idle.
         '''
-        xn = self._get_xn()
-        self._wrapBasicCall(xn, lambda : xn.RefreshCache(force))
-
-    def GetRepoList(self, filters=FILTER_NONE):
-        '''
-        Returns the list of repositories used in the system
-
-        filter is a correct filter, e.g. None or 'installed;~devel'
+        return self._run_transaction("RefreshCache", (force,), async)
 
-        '''
-        xn = self._get_xn()
-        return self._wrapReposCall(xn, lambda : xn.GetRepoList(filters))
+    def GetRepoList(self, filters=FILTER_NONE, async=False):
+        '''Get the repositories'''
+        return self._run_transaction("GetRepoList", (filters,), async)
 
     def RepoEnable(self, repo_id, enabled):
         '''
-        Enables the repository specified.
-
+        Enable the repository specified.
         repo_id is a repository identifier, e.g. fedora-development-debuginfo
-
         enabled true if enabled, false if disabled
-
         '''
-        xn = self._get_xn()
-        self._wrapBasicCall(xn, lambda : xn.RepoEnable(repo_id, enabled))
+        return self._run_transaction("RepoEnable", (repo_id, enabled), async)
 
-    def GetUpdates(self, filters=FILTER_NONE):
+    def GetUpdates(self, filters=FILTER_NONE, async=False):
         '''
         This method should return a list of packages that are installed and
         are upgradable.
 
         It should only return the newest update for each installed package.
         '''
-        xn = self._get_xn()
-        return self._wrapPackageCall(xn, lambda : xn.GetUpdates(filters))
+        return self._run_transaction("GetUpdates", [filters], async)
 
-    def GetCategories(self):
-        '''
-        This method should return a list of Categories
-        '''
-        xn = self._get_xn()
-        return self._wrapCategoryCall(xn, lambda : xn.GetCategories())
+    def GetCategories(self, async=False):
+        '''Return available software categories'''
+        return self._run_transaction("GetCategories", [], async)
 
-    def GetPackages(self, filters=FILTER_NONE):
-        '''
-        This method should return a total list of packages, limited by the
-        filters used
-        '''
-        xn = self._get_xn()
-        return self._wrapPackageCall(xn, lambda : xn.GetPackages(filters))
+    def GetPackages(self, filters=FILTER_NONE, async=False):
+        '''Return all packages'''
+        return self._run_transaction("GetUpdates", [filters], async)
 
-    def UpdateSystem(self, progress_cb=None):
-        '''
-        This method should update the system
-        '''
-        xn = self._get_xn()
-        self._doPackages(xn, lambda : xn.UpdateSystem(), progress_cb)
+    def UpdateSystem(self, async=False):
+        '''Update the system'''
+        return self._run_transaction("UpdateSystem", [], async)
 
-    def DownloadPackages(self, package_ids):
-        package_ids = self._to_list(package_ids) # Make sure we have a list
-        xn = self._get_xn()
-        return self._wrapFilesCall(xn, lambda : xn.DownloadPackages(package_ids))
+    def DownloadPackages(self, package_ids, async=False):
+        '''Download package files'''
+        package_ids = self._to_list(package_ids)
+        return self._run_transaction("DownloadPackages", [package_ids], async)
 
-    def GetDepends(self, filters, package_ids, recursive=False):
+    def GetDepends(self, filters, package_ids, recursive=False, async=False):
         '''
         Search for dependencies for packages
         '''
-        package_ids = self._to_list(package_ids) # Make sure we have a list
-        xn = self._get_xn()
-        return self._wrapPackageCall(xn,
-                                     lambda : xn.GetDepends(filters, package_ids, recursive))
-
-    def GetFiles(self, package_ids):
-        package_ids = self._to_list(package_ids) # Make sure we have a list
-        xn = self._get_xn()
-        return self._wrapFilesCall(xn, lambda : xn.GetFiles(package_ids))
-
-    def GetRequires(self, filters, package_ids, recursive=False):
-        '''
-        Search for requirements for packages
-        '''
-        package_ids = self._to_list(package_ids) # Make sure we have a list
-        xn = self._get_xn()
-        return self._wrapPackageCall(xn,
-                                     lambda : xn.GetRequires(filters, package_ids, recursive))
-
-    def GetUpdateDetail(self, package_ids):
-        '''
-        Get details for updates
-        '''
-        package_ids = self._to_list(package_ids) # Make sure we have a list
-        xn = self._get_xn()
-        return self._wrapUpdateDetailsCall(xn, lambda : xn.GetUpdateDetail(package_ids))
-
-    def GetDistroUpgrades(self):
-        xn = self._get_xn()
-        return self._wrapPackageCall(xn, lambda : xn.GetDistroUpgrades())
-
-    def InstallFiles(self, trusted, files):
-        raise PackageKitError(ERROR_NOT_SUPPORTED)
-
-    def InstallSignatures(self, sig_type, key_id, package_id):
-        '''
-        Install packages signing keys used to validate packages
-        '''
-        xn = self._get_xn()
-        self._wrapBasicCall(xn, lambda : xn.InstallSignatures(sig_type, key_id, package_id))
-
-    def RepoSetData(self, repo_id, parameter, value):
-        '''
-        Change custom parameter in Repository Configuration
-        '''
-        xn = self._get_xn()
-        self._wrapBasicCall(xn, lambda : xn.RepoSetData(repo_id, parameter, value))
-
-    def Rollback(self, transaction_id):
-        xn = self._get_xn()
-        self._wrapBasicCall(xn, lambda : xn.Rollback(transaction_id))
-
-    def WhatProvides(self, provide_type, search):
-        '''
-        Search for packages that provide the supplied attributes
-        '''
-        xn = self._get_xn()
-        return self._wrapPackageCall(xn,
-                                     lambda : xn.WhatProvides(provide_type, search))
+        package_ids = self._to_list(package_ids)
+        return self._run_transaction("GetDepends",
+                                     [filters, package_ids, recursive],
+                                     async)
+
+    def GetFiles(self, package_ids, async=False):
+        '''Get files of the given packages'''
+        package_ids = self._to_list(package_ids)
+        return self._run_transaction("GetFiles", [package_ids], async)
+
+    def GetRequires(self, filters, package_ids, recursive=False, async=False):
+        '''Search for requirements for packages'''
+        package_ids = self._to_list(package_ids)
+        return self._run_transaction("GetRequires",
+                                     [filters, package_ids, recursive],
+                                     async)
+
+    def GetUpdateDetail(self, package_ids, async=False):
+        '''Get details for updates'''
+        package_ids = self._to_list(package_ids)
+        return self._run_transaction("GetUpdateDetail", [package_ids], async)
+
+    def GetDistroUpgrades(self, async=False):
+        '''Query for later distribution releases'''
+        return self._run_transaction("GetDistroUpgrades", [], async)
+
+    def InstallFiles(self, trusted, files, async=False):
+        '''Install the given local packages'''
+        return self._run_transaction("InstallFiles", [trusted, files], async)
+
+    def InstallSignature(self, sig_type, key_id, package_id, async=False):
+        '''Install packages signing keys used to validate packages'''
+        return self._run_transaction("InstallSignature",
+                                     [sig_type, key_id, package_id],
+                                     async)
+
+    def RepoSetData(self, repo_id, parameter, value, async=False):
+        '''Change custom parameter of a repository'''
+        return self._run_transaction("RepoSetData",
+                                     [repo_id, parameter, value],
+                                     async)
+
+    def Rollback(self, transaction_id, async=False):
+        '''Roll back to a previous transaction'''
+        return self._run_transaction("Rollback", [transaction_id], async)
+
+    def WhatProvides(self, provides, search, async=False):
+        '''Search for packages that provide the supplied attributes'''
+        return self._run_transaction("WhatProvides", [provides, search], async)
 
     def SetLocale(self, code):
-        xn = self._get_xn()
-        xn.SetLocale(code)
+        '''Set the language of the client'''
+        self._locale = code
 
-    def AcceptEula(self, eula_id):
-        xn = self._get_xn()
-        self._wrapBasicCall(xn, lambda : xn.AcceptEula(eula_id))
+    def AcceptEula(self, eula_id, async=False):
+        '''Accept the given end user licence aggreement'''
+        return self._run_transaction("AcceptEula", [eula_id], async)
 
     #
     # Internal helper functions
@@ -438,84 +377,8 @@ class PackageKitClient:
             obj = [obj]
         return obj
 
-    def _wait(self):
-        '''Wait until an async PK operation finishes.'''
-        self.main_loop.run()
-
-    def _h_status(self, status):
-        '''
-        StatusChanged signal handler
-        '''
-        self._status = status
-
-    def _h_allowcancel(self, allow):
-        '''
-        AllowCancel signal handler
-        '''
-        self._allow_cancel = allow
-
-    def _h_error(self, enum, desc):
-        '''
-        ErrorCode signal handler
-        '''
-        self._error_enum = enum
-        self._error_desc = desc
-
-    def _h_finished(self, status, code):
-        '''
-        Finished signal handler
-        '''
-        self._finished_status = status
-        self.main_loop.quit()
-
-    def _h_progress(self, per, subper, el, rem):
-        '''
-        ProgressChanged signal handler
-        '''
-        def _cancel(xn):
-            try:
-                xn.Cancel()
-            except dbus.DBusException, e:
-                if e._dbus_error_name == 'org.freedesktop.PackageKit.Transaction.CannotCancel':
-                    pass
-                else:
-                    raise
-
-        ret = self._progress_cb(self._status, int(per),
-            int(subper), int(el), int(rem), self._allow_cancel)
-        if not ret:
-            # we get backend timeout exceptions more likely when we call this
-            # directly, so delay it a bit
-            gobject.timeout_add(10, _cancel, pk_xn)
-
-    def _auth(self):
-        policykit = self.bus.get_object(
-            'org.freedesktop.PolicyKit.AuthenticationAgent', '/',
-            'org.freedesktop.PolicyKit.AuthenticationAgent')
-        if(policykit == None):
-            print("Error: Could not get PolicyKit D-Bus Interface\n")
-        granted = policykit.ObtainAuthorization("org.freedesktop.packagekit.update-system",
-                                                (dbus.UInt32)(xid),
-                                                (dbus.UInt32)(os.getpid()))
-
-    def _doPackages(self, pk_xn, method, progress_cb):
-        '''Shared implementation of InstallPackages, UpdatePackages and RemovePackages.'''
-
-        self._status = None
-        self._allow_cancel = False
-
-        if progress_cb:
-            self._progress_cb = progress_cb
-        self._wrapBasicCall(pk_xn, method)
-        if self._finished_status != 'success':
-            raise PackageKitError('internal-error')
-
-    def _get_xn(self):
-        '''Create a new PackageKit Transaction object.'''
-
-        self._error_enum = None
-        self._error_desc = None
-        self._finished_status = None
+    def _run_transaction(self, method_name, args, async):
+        '''Run the given method in a new transaction'''
         try:
             tid = self.pk_control.GetTid()
         except (AttributeError, dbus.DBusException), e:
@@ -529,9 +392,17 @@ class PackageKitClient:
                 tid = self.pk_control.GetTid()
             else:
                 raise
-
-        return dbus.Interface(self.bus.get_object('org.freedesktop.PackageKit',
-            tid, False), 'org.freedesktop.PackageKit.Transaction')
+        iface = dbus.Interface(self.bus.get_object('org.freedesktop.PackageKit',
+                                                   tid, False),
+                               'org.freedesktop.PackageKit.Transaction')
+        trans = PackageKitTransaction(tid, iface)
+        if self._locale:
+            trans.SetLocale(self._locale)
+        trans.set_method(method_name, *args)
+        if async:
+            return trans
+        else:
+            return trans.run()
 
 #### PolicyKit authentication borrowed wrapper ##
 class PermissionDeniedByPolicy(dbus.DBusException):
@@ -552,8 +423,8 @@ def polkit_auth_wrapper(fn, *args, **kwargs):
             (priv, auth_result) = e.message.split()[-2:]
             if auth_result.startswith('auth_'):
                 pk_auth = dbus.SessionBus().get_object(
-                    'org.freedesktop.PolicyKit.AuthenticationAgent', '/', 'org.gnome.PolicyKit.AuthorizationManager.SingleInstance')
-
+                    'org.freedesktop.PolicyKit.AuthenticationAgent', '/',
+                    'org.gnome.PolicyKit.AuthorizationManager.SingleInstance')
                 # TODO: provide xid
                 res = pk_auth.ObtainAuthorization(priv, dbus.UInt32(0),
                     dbus.UInt32(os.getpid()), timeout=300)
commit b3e490d4ae2857d9487947102d2aa9974feac7f3
Merge: 4af7914... 65efd13...
Author: sebastian Heinlein <devel at glatzor.de>
Date:   Tue Nov 4 22:21:22 2008 +0100

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

commit 4af7914e55b2f15b72732823a601462c895ff9ed
Merge: c02f9bb... 2df6ee1...
Author: sebastian Heinlein <devel at glatzor.de>
Date:   Mon Nov 3 21:51:35 2008 +0100

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

commit c02f9bbf8b871ffb321270eec17f9492cfbaeb2b
Merge: adbae19... 00b8319...
Author: sebastian Heinlein <devel at glatzor.de>
Date:   Sun Nov 2 05:15:50 2008 +0100

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

commit adbae193be0aac1c30676b11e34ee691b7cf9493
Merge: 5ad9e8e... 0e09f77...
Author: sebastian Heinlein <devel at glatzor.de>
Date:   Fri Oct 31 18:58:29 2008 +0100

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

commit 5ad9e8ee6b9341f4f24da67cb816c0681d2833c4
Merge: 5e81aa3... c5b8682...
Author: sebastian Heinlein <devel at glatzor.de>
Date:   Thu Oct 23 17:32:05 2008 +0200

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

commit 5e81aa35d9369d46d7f2d1c4f2a3aa231195d719
Merge: e131943... 1799342...
Author: sebastian Heinlein <devel at glatzor.de>
Date:   Tue Oct 21 16:51:42 2008 +0200

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

commit e131943d55ad439c92e28ae3c5f0dbac4b1272a5
Author: sebastian Heinlein <devel at glatzor.de>
Date:   Sun Oct 19 22:58:40 2008 +0200

    Fix the idle timer in the daemonBackend: do not exit on running threads
    or pending gobject calls
    
    Conflicts:
    
    	lib/python/packagekit/daemonBackend.py

diff --git a/lib/python/packagekit/daemonBackend.py b/lib/python/packagekit/daemonBackend.py
index 9c9ad86..6929e26 100644
--- a/lib/python/packagekit/daemonBackend.py
+++ b/lib/python/packagekit/daemonBackend.py
@@ -53,6 +53,9 @@ pklog.addHandler(syslog)
 PACKAGEKIT_DBUS_INTERFACE = 'org.freedesktop.PackageKitBackend'
 PACKAGEKIT_DBUS_PATH = '/org/freedesktop/PackageKitBackend'
 
+INACTIVE_CHECK_INTERVAL = 60 # Check every minute
+INACTIVE_TIMEOUT = 5 * 60 # timeout after 5 minutes of inactivity.
+
 def forked(func):
     '''
     Decorator to fork a worker process.
@@ -168,10 +171,21 @@ class PackageKitBaseBackend(dbus.service.Object):
 
         self.loop = gobject.MainLoop()
 
+        gobject.timeout_add_seconds(INACTIVE_CHECK_INTERVAL,
+                                    self.check_for_inactivity)
         self.last_action_time = time.time()
 
         self.loop.run()
 
+    def check_for_inactivity(self):
+        if time.time() - self.last_action_time > INACTIVE_TIMEOUT and \
+           threading.activeCount() == 1 and \
+           not self.loop.get_context().pending():
+            pklog.info("Exiting due to timeout.")
+            self.Exit()
+            return False
+        return True
+
     def on_child_exit(self, pid, condition, data):
         pass
 
commit 2fbed901d825f2360ceeaeb7af9f58ef1939121b
Author: sebastian Heinlein <devel at glatzor.de>
Date:   Sun Oct 19 19:42:24 2008 +0200

    DaemonBackend: Do not include use a separate inactivity timeout from the
    packagekitd

diff --git a/lib/python/packagekit/daemonBackend.py b/lib/python/packagekit/daemonBackend.py
index f73796b..9c9ad86 100644
--- a/lib/python/packagekit/daemonBackend.py
+++ b/lib/python/packagekit/daemonBackend.py
@@ -53,9 +53,6 @@ pklog.addHandler(syslog)
 PACKAGEKIT_DBUS_INTERFACE = 'org.freedesktop.PackageKitBackend'
 PACKAGEKIT_DBUS_PATH = '/org/freedesktop/PackageKitBackend'
 
-INACTIVE_CHECK_INTERVAL = 1000 * 60 * 5 # Check every 5 minutes.
-INACTIVE_TIMEOUT = 60 * 10 # timeout after 10 minutes of inactivity.
-
 def forked(func):
     '''
     Decorator to fork a worker process.
@@ -171,17 +168,10 @@ class PackageKitBaseBackend(dbus.service.Object):
 
         self.loop = gobject.MainLoop()
 
-        gobject.timeout_add(INACTIVE_CHECK_INTERVAL, self.check_for_inactivity)
         self.last_action_time = time.time()
 
         self.loop.run()
 
-    def check_for_inactivity(self):
-        if time.time() - self.last_action_time > INACTIVE_TIMEOUT:
-            pklog.critical("Exiting due to timeout.")
-            self.Exit()
-        return True
-
     def on_child_exit(self, pid, condition, data):
         pass
 
commit 3d0633d7e245f90e00c18f17cd7ab135935b93bb
Merge: 0aa0827... 886d261...
Author: sebastian Heinlein <devel at glatzor.de>
Date:   Sun Oct 19 10:19:12 2008 +0200

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

commit 0aa0827b16c426ef495b95711709866d24caa482
Merge: e872e02... c9a7236...
Author: Sebastian Heinlein <devel at glatzor.de>
Date:   Fri Oct 17 14:43:00 2008 +0200

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

commit e872e02825f9d3301d0109fbf934a806da47fd5d
Merge: 2e99140... bf89bf5...
Author: Sebastian Heinlein <devel at glatzor.de>
Date:   Wed Oct 15 19:51:33 2008 +0200

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

diff --cc lib/python/packagekit/client.py
index 0000000,fa7914a..8c495bc
mode 000000,100644..100644
--- a/lib/python/packagekit/client.py
+++ b/lib/python/packagekit/client.py
@@@ -1,0 -1,568 +1,568 @@@
+ #!/usr/bin/python
+ #
+ # 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.
+ #
+ # (c) 2008
+ #    Canonical Ltd.
+ #    Aidan Skinner <aidan at skinner.me.uk>
+ #    Martin Pitt <martin.pitt at ubuntu.com>
+ #    Tim Lauridsen <timlau at fedoraproject.org>
+ #
+ # Synchronous PackageKit client wrapper API for Python.
+ 
+ import os
+ import gobject
+ import dbus
+ from enums import *
+ from misc import *
+ 
+ __api_version__ = '0.1.0'
+ 
+ class PackageKitError(Exception):
+     '''PackageKit error.
+ 
+     This class mainly wraps a PackageKit "error enum". See
+     http://www.packagekit.org/pk-reference.html#introduction-errors for details
+     and possible values.
+     '''
 -    def __init__(self, error):
++    def __init__(self, error, desc=None):
+         self.error = error
++        self.desc = desc
+ 
+     def __str__(self):
 -        return self.error
++        return "%s: %s" % (self.error, self.desc)
+ 
+ class PackageKitClient:
+     '''PackageKit client wrapper class.
+ 
+     This exclusively uses synchonous calls. Functions which take a long time
+     (install/remove packages) have callbacks for progress feedback.
+     '''
+     def __init__(self, main_loop=None):
+         '''Initialize a PackageKit client.
+ 
+         If main_loop is None, this sets up its own gobject.MainLoop(),
+         otherwise it attaches to the specified one.
+         '''
+         self.pk_control = None
+         if main_loop is None:
+             import dbus.mainloop.glib
+             main_loop = gobject.MainLoop()
+             dbus.mainloop.glib.DBusGMainLoop(set_as_default=True)
+         self.main_loop = main_loop
+ 
+         self.bus = dbus.SystemBus()
+ 
+     def _wrapCall(self, pk_xn, method, callbacks):
+         '''
+         Wraps a call which emits Finished and ErrorCode on completion
+         '''
+         pk_xn.connect_to_signal('Finished', self._h_finished)
+         pk_xn.connect_to_signal('ErrorCode', self._h_error)
++        pk_xn.connect_to_signal('StatusChanged', self._h_status)
++        pk_xn.connect_to_signal('AllowCancel', self._h_allowcancel)
++        pk_xn.connect_to_signal('ProgressChanged', self._h_progress)
+         for cb in callbacks.keys():
+             pk_xn.connect_to_signal(cb, callbacks[cb])
+ 
+         polkit_auth_wrapper(method)
+         self._wait()
+         if self._error_enum:
 -            raise PackageKitError(self._error_enum)
++            raise PackageKitError(self._error_enum, self._error_desc)
+ 
+     def _wrapBasicCall(self, pk_xn, method):
+         return self._wrapCall(pk_xn, method, {})
+ 
+     def _wrapPackageCall(self, pk_xn, method):
+         '''
+         Wraps a call which emits Finished, ErrorCode on completion and
+         Package for information returns a list of dicts with
+         'installed', 'id' and 'summary' keys
+         '''
+ 
+         result = []
+         package_cb = lambda i, id, summary: result.append(
+             PackageKitPackage(i, id, summary))
+         self._wrapCall(pk_xn, method, {'Package' : package_cb})
+         return result
+ 
+     def _wrapDistroUpgradeCall(self, pk_xn, method):
+         '''
+         Wraps a call which emits Finished, ErrorCode on completion and
+         DistroUpgrade for information returns a list of dicts with
+         'type', 'name' and 'summary' keys
+         '''
+ 
+         result = []
+         distup_cb = lambda typ, name, summary: result.append(
+             PackageKitDistroUpgrade(typ, name, summary))
+         self._wrapCall(pk_xn, method, {'DistroUpgrade' : distup_cb})
+         return result
+ 
+     def _wrapDetailsCall(self, pk_xn, method):
+         '''
+         Wraps a call which emits Finished, ErrorCode on completion and
+         Details for information returns a list of dicts with 'id',
+         'license', 'group', 'description', 'upstream_url', 'size'.keys
+         '''
+         result = []
+         details_cb = lambda id, license, group, detail, url, size: result.append(
+             PackageKitDetails(id, license, group, detail, url, size))
+ 
+         self._wrapCall(pk_xn, method, {'Details' : details_cb})
+         return result
+ 
+     def _wrapCategoryCall(self, pk_xn, method):
+         '''
+         Wraps a call which emits Finished, ErrorCode on completion and
+         Details for information returns a list of dicts with 'id',
+         'license', 'group', 'description', 'upstream_url', 'size'.keys
+         '''
+         result = []
+         category_cb = lambda  parent_id, cat_id, name, summary, icon: result.append(
+             PackageKitCategory( parent_id, cat_id, name, summary, icon))
+ 
+         self._wrapCall(pk_xn, method, {'Category' : category_cb})
+         return result
+ 
+     def _wrapUpdateDetailsCall(self, pk_xn, method):
+         '''
+         Wraps a call which emits Finished, ErrorCode on completion and
+         Details for information returns a list of dicts with 'id',
+         'license', 'group', 'description', 'upstream_url', 'size'.keys
+         '''
+         result = []
+         details_cb =  lambda id, updates, obsoletes, vendor_url, bugzilla_url, \
+                              cve_url, restart, update_text, changelog, state, \
+                              issued, updated: result.append(
+             PackageKitUpdateDetails(id, updates, obsoletes, vendor_url, bugzilla_url, \
+                                     cve_url, restart, update_text, changelog, state, \
+                                     issued, updated))
+         self._wrapCall(pk_xn, method, {'UpdateDetail' : details_cb})
+         return result
+ 
+     def _wrapReposCall(self, pk_xn, method):
+         '''
+         Wraps a call which emits Finished, ErrorCode and RepoDetail
+         for information returns a list of dicts with 'id',
+         'description', 'enabled' keys
+         '''
+         result = []
+         repo_cb = lambda id, description, enabled: result.append(
+             PackageKitRepos(id, description, enabled))
+         self._wrapCall(pk_xn, method, {'RepoDetail' : repo_cb})
+         return result
+ 
+     def _wrapFilesCall(self, pk_xn, method):
+         '''
+         Wraps a call which emits Finished, ErrorCode and Files
+         for information returns a list of dicts with 'id',
+         'files'
+         '''
+         result = []
+         files_cb = lambda id, files: result.append(
+             PackageKitFiles(id, files))
+         self._wrapCall(pk_xn, method, {'Files' : files_cb})
+         return result
+ 
+     def SuggestDaemonQuit(self):
+         '''Ask the PackageKit daemon to shutdown.'''
+ 
+         try:
+             self.pk_control.SuggestDaemonQuit()
+         except (AttributeError, dbus.DBusException), e:
+             # not initialized, or daemon timed out
+             pass
+ 
+     def Resolve(self, filters, package):
+         '''
+         Resolve a package name to a PackageKit package_id filters and
+         package are directly passed to the PackageKit transaction
+         D-BUS method Resolve()
+ 
+         Return Dict with keys of (installed, id, short_description)
+         for all matches, where installed is a boolean and id and
+         short_description are strings.
+         '''
+         package = self._to_list(package) # Make sure we have a list
+         xn = self._get_xn()
+         return self._wrapPackageCall(xn, lambda : xn.Resolve(filters, package))
+ 
+     def GetDetails(self, package_ids):
+         '''
+         Get details about a PackageKit package_ids.
+ 
+         Return dict with keys (id, license, group, description,
+         upstream_url, size).
+         '''
+         package_ids = self._to_list(package_ids) # Make sure we have a list
+         xn = self._get_xn()
+         return self._wrapDetailsCall(xn, lambda : xn.GetDetails(package_ids))
+ 
+     def SearchName(self, filters, name):
+         '''
+         Search a package by name.
+         '''
+         xn = self._get_xn()
+         return self._wrapPackageCall(xn, lambda : xn.SearchName(filters, name))
+ 
+     def SearchGroup(self, filters, group_id):
+         '''
+         Search for a group.
+         '''
+         xn = self._get_xn()
+         return self._wrapPackageCall(xn, lambda : xn.SearchGroup(filters, group_id))
+ 
+     def SearchDetails(self, filters, name):
+         '''
+         Search a packages details.
+         '''
+         xn = self._get_xn()
+         return self._wrapPackageCall(xn,
+                                      lambda : xn.SearchDetails(filters, name))
+ 
+     def SearchFile(self, filters, search):
+         '''
+         Search for a file.
+         '''
+         xn = self._get_xn()
+         return self._wrapPackageCall(xn,
+                                      lambda : xn.SearchFile(filters, search))
+ 
+     def InstallPackages(self, package_ids, progress_cb=None):
+         '''Install a list of package IDs.
+ 
+         progress_cb is a function taking arguments (status, percentage,
+         subpercentage, elapsed, remaining, allow_cancel). If it returns False,
+         the action is cancelled (if allow_cancel == True), otherwise it
+         continues.
+ 
+         On failure this throws a PackageKitError or a DBusException.
+         '''
+         package_ids = self._to_list(package_ids) # Make sure we have a list
+         xn = self._get_xn()
+         self._doPackages( xn, lambda : xn.InstallPackages(package_ids), progress_cb)
+ 
+     def UpdatePackages(self, package_ids, progress_cb=None):
+         '''UPdate a list of package IDs.
+ 
+         progress_cb is a function taking arguments (status, percentage,
+         subpercentage, elapsed, remaining, allow_cancel). If it returns False,
+         the action is cancelled (if allow_cancel == True), otherwise it
+         continues.
+ 
+         On failure this throws a PackageKitError or a DBusException.
+         '''
+         package_ids = self._to_list(package_ids) # Make sure we have a list
+         xn = self._get_xn()
+         self._doPackages(xn, lambda : xn.UpdatePackages(package_ids), progress_cb)
+ 
+     def RemovePackages(self, package_ids, progress_cb=None, allow_deps=False,
+         auto_remove=True):
+         '''Remove a list of package IDs.
+ 
+         progress_cb is a function taking arguments (status, percentage,
+         subpercentage, elapsed, remaining, allow_cancel). If it returns False,
+         the action is cancelled (if allow_cancel == True), otherwise it
+         continues.
+ 
+         allow_deps and auto_remove are passed to the PackageKit function.
+ 
+         On failure this throws a PackageKitError or a DBusException.
+         '''
+         package_ids = self._to_list(package_ids) # Make sure we have a list
+         xn = self._get_xn()
+         self._doPackages(xn, lambda : xn.RemovePackages(package_ids, allow_deps, auto_remove), progress_cb)
+ 
+     def RefreshCache(self, force=False):
+         '''
+         Refresh the cache, i.e. download new metadata from a
+         remote URL so that package lists are up to date. This action
+         may take a few minutes and should be done when the session and
+         system are idle.
+         '''
+         xn = self._get_xn()
+         self._wrapBasicCall(xn, lambda : xn.RefreshCache(force))
+ 
+     def GetRepoList(self, filters=FILTER_NONE):
+         '''
+         Returns the list of repositories used in the system
+ 
+         filter is a correct filter, e.g. None or 'installed;~devel'
+ 
+         '''
+         xn = self._get_xn()
+         return self._wrapReposCall(xn, lambda : xn.GetRepoList(filters))
+ 
+     def RepoEnable(self, repo_id, enabled):
+         '''
+         Enables the repository specified.
+ 
+         repo_id is a repository identifier, e.g. fedora-development-debuginfo
+ 
+         enabled true if enabled, false if disabled
+ 
+         '''
+         xn = self._get_xn()
+         self._wrapBasicCall(xn, lambda : xn.RepoEnable(repo_id, enabled))
+ 
+     def GetUpdates(self, filters=FILTER_NONE):
+         '''
+         This method should return a list of packages that are installed and
+         are upgradable.
+ 
+         It should only return the newest update for each installed package.
+         '''
+         xn = self._get_xn()
+         return self._wrapPackageCall(xn, lambda : xn.GetUpdates(filters))
+ 
+     def GetCategories(self):
+         '''
+         This method should return a list of Categories
+         '''
+         xn = self._get_xn()
+         return self._wrapCategoryCall(xn, lambda : xn.GetCategories())
+ 
+     def GetPackages(self, filters=FILTER_NONE):
+         '''
+         This method should return a total list of packages, limited by the
+         filters used
+         '''
+         xn = self._get_xn()
+         return self._wrapPackageCall(xn, lambda : xn.GetPackages(filters))
+ 
 -    def UpdateSystem(self):
++    def UpdateSystem(self, progress_cb=None):
+         '''
 -        This method should return a list of packages that are
 -        installed and are upgradable.
 -
 -        It should only return the newest update for each installed package.
++        This method should update the system
+         '''
+         xn = self._get_xn()
 -        self._wrapPackageCall(xn, lambda : xn.UpdateSystem())
++        self._doPackages(xn, lambda : xn.UpdateSystem(), progress_cb)
+ 
+     def DownloadPackages(self, package_ids):
+         package_ids = self._to_list(package_ids) # Make sure we have a list
+         xn = self._get_xn()
+         return self._wrapFilesCall(xn, lambda : xn.DownloadPackages(package_ids))
+ 
+     def GetDepends(self, filters, package_ids, recursive=False):
+         '''
+         Search for dependencies for packages
+         '''
+         package_ids = self._to_list(package_ids) # Make sure we have a list
+         xn = self._get_xn()
+         return self._wrapPackageCall(xn,
+                                      lambda : xn.GetDepends(filters, package_ids, recursive))
+ 
+     def GetFiles(self, package_ids):
+         package_ids = self._to_list(package_ids) # Make sure we have a list
+         xn = self._get_xn()
+         return self._wrapFilesCall(xn, lambda : xn.GetFiles(package_ids))
+ 
+     def GetRequires(self, filters, package_ids, recursive=False):
+         '''
+         Search for requirements for packages
+         '''
+         package_ids = self._to_list(package_ids) # Make sure we have a list
+         xn = self._get_xn()
+         return self._wrapPackageCall(xn,
+                                      lambda : xn.GetRequires(filters, package_ids, recursive))
+ 
+     def GetUpdateDetail(self, package_ids):
+         '''
+         Get details for updates
+         '''
+         package_ids = self._to_list(package_ids) # Make sure we have a list
+         xn = self._get_xn()
+         return self._wrapUpdateDetailsCall(xn, lambda : xn.GetUpdateDetail(package_ids))
+ 
+     def GetDistroUpgrades(self):
+         xn = self._get_xn()
+         return self._wrapPackageCall(xn, lambda : xn.GetDistroUpgrades())
+ 
+     def InstallFiles(self, trusted, files):
+         raise PackageKitError(ERROR_NOT_SUPPORTED)
+ 
+     def InstallSignatures(self, sig_type, key_id, package_id):
+         '''
+         Install packages signing keys used to validate packages
+         '''
+         xn = self._get_xn()
+         self._wrapBasicCall(xn, lambda : xn.InstallSignatures(sig_type, key_id, package_id))
+ 
+     def RepoSetData(self, repo_id, parameter, value):
+         '''
+         Change custom parameter in Repository Configuration
+         '''
+         xn = self._get_xn()
+         self._wrapBasicCall(xn, lambda : xn.RepoSetData(repo_id, parameter, value))
+ 
+     def Rollback(self, transaction_id):
+         xn = self._get_xn()
+         self._wrapBasicCall(xn, lambda : xn.Rollback(transaction_id))
+ 
+     def WhatProvides(self, provide_type, search):
+         '''
+         Search for packages that provide the supplied attributes
+         '''
+         xn = self._get_xn()
+         return self._wrapPackageCall(xn,
+                                      lambda : xn.WhatProvides(provide_type, search))
+ 
+     def SetLocale(self, code):
+         xn = self._get_xn()
 -        self._wrapBasicCall(xn, lambda : xn.SetLocale(code))
++        xn.SetLocale(code)
+ 
+     def AcceptEula(self, eula_id):
+         xn = self._get_xn()
+         self._wrapBasicCall(xn, lambda : xn.AcceptEula(eula_id))
+ 
+     #
+     # Internal helper functions
+     #
+     def _to_list(self, obj):
+         '''convert obj to list'''
+         if isinstance(obj, str):
+             obj = [obj]
+         return obj
+ 
+     def _wait(self):
+         '''Wait until an async PK operation finishes.'''
+         self.main_loop.run()
+ 
+     def _h_status(self, status):
+         '''
+         StatusChanged signal handler
+         '''
+         self._status = status
+ 
+     def _h_allowcancel(self, allow):
+         '''
+         AllowCancel signal handler
+         '''
+         self._allow_cancel = allow
+ 
+     def _h_error(self, enum, desc):
+         '''
+         ErrorCode signal handler
+         '''
+         self._error_enum = enum
++        self._error_desc = desc
+ 
+     def _h_finished(self, status, code):
+         '''
+         Finished signal handler
+         '''
+         self._finished_status = status
+         self.main_loop.quit()
+ 
+     def _h_progress(self, per, subper, el, rem):
+         '''
+         ProgressChanged signal handler
+         '''
+         def _cancel(xn):
+             try:
+                 xn.Cancel()
+             except dbus.DBusException, e:
+                 if e._dbus_error_name == 'org.freedesktop.PackageKit.Transaction.CannotCancel':
+                     pass
+                 else:
+                     raise
+ 
+         ret = self._progress_cb(self._status, int(per),
+             int(subper), int(el), int(rem), self._allow_cancel)
+         if not ret:
+             # we get backend timeout exceptions more likely when we call this
+             # directly, so delay it a bit
+             gobject.timeout_add(10, _cancel, pk_xn)
+ 
+     def _auth(self):
+         policykit = self.bus.get_object(
+             'org.freedesktop.PolicyKit.AuthenticationAgent', '/',
+             'org.freedesktop.PolicyKit.AuthenticationAgent')
+         if(policykit == None):
+             print("Error: Could not get PolicyKit D-Bus Interface\n")
+         granted = policykit.ObtainAuthorization("org.freedesktop.packagekit.update-system",
+                                                 (dbus.UInt32)(xid),
+                                                 (dbus.UInt32)(os.getpid()))
+ 
+     def _doPackages(self, pk_xn, method, progress_cb):
+         '''Shared implementation of InstallPackages, UpdatePackages and RemovePackages.'''
+ 
+         self._status = None
+         self._allow_cancel = False
+ 
+         if progress_cb:
 -            pk_xn.connect_to_signal('StatusChanged', self._h_status)
 -            pk_xn.connect_to_signal('AllowCancel', self._h_allowcancel)
 -            pk_xn.connect_to_signal('ProgressChanged', self._h_progress)
+             self._progress_cb = progress_cb
+         self._wrapBasicCall(pk_xn, method)
+         if self._finished_status != 'success':
+             raise PackageKitError('internal-error')
+ 
+     def _get_xn(self):
+         '''Create a new PackageKit Transaction object.'''
+ 
+         self._error_enum = None
++        self._error_desc = None
+         self._finished_status = None
+         try:
+             tid = self.pk_control.GetTid()
+         except (AttributeError, dbus.DBusException), e:
+             if self.pk_control == None or (hasattr(e, '_dbus_error_name') and \
+                 e._dbus_error_name == 'org.freedesktop.DBus.Error.ServiceUnknown'):
+                 # first initialization (lazy) or timeout
+                 self.pk_control = dbus.Interface(self.bus.get_object(
+                         'org.freedesktop.PackageKit',
+                         '/org/freedesktop/PackageKit',
+                     False), 'org.freedesktop.PackageKit')
+                 tid = self.pk_control.GetTid()
+             else:
+                 raise
+ 
+         return dbus.Interface(self.bus.get_object('org.freedesktop.PackageKit',
+             tid, False), 'org.freedesktop.PackageKit.Transaction')
+ 
+ #### PolicyKit authentication borrowed wrapper ##
+ class PermissionDeniedByPolicy(dbus.DBusException):
+     _dbus_error_name = 'org.freedesktop.PackageKit.Transaction.RefusedByPolicy'
+ 
+ def polkit_auth_wrapper(fn, *args, **kwargs):
+     '''Function call wrapper for PolicyKit authentication.
+ 
+     Call fn(*args, **kwargs). If it fails with a PermissionDeniedByPolicy
+     and the caller can authenticate to get the missing privilege, the PolicyKit
+     authentication agent is called, and the function call is attempted again.
+     '''
+     try:
+         return fn(*args, **kwargs)
+     except dbus.DBusException, e:
+         if e._dbus_error_name == PermissionDeniedByPolicy._dbus_error_name:
+             # last words in message are privilege and auth result
+             (priv, auth_result) = e.message.split()[-2:]
+             if auth_result.startswith('auth_'):
+                 pk_auth = dbus.SessionBus().get_object(
+                     'org.freedesktop.PolicyKit.AuthenticationAgent', '/', 'org.gnome.PolicyKit.AuthorizationManager.SingleInstance')
+ 
+                 # TODO: provide xid
+                 res = pk_auth.ObtainAuthorization(priv, dbus.UInt32(0),
+                     dbus.UInt32(os.getpid()), timeout=300)
+                 print res
+                 if res:
+                     return fn(*args, **kwargs)
+             raise PermissionDeniedByPolicy(priv + ' ' + auth_result)
+         else:
+             raise
+ 
+ if __name__ == '__main__':
+     pass
commit 2e991407cdebb6366f4621904773d920097901ae
Author: Sebastian Heinlein <devel at glatzor.de>
Date:   Tue Oct 14 12:41:39 2008 +0200

    python client: status, progress and allow_cancel are interesting for
    every transaction

diff --git a/python/packagekit/client.py b/python/packagekit/client.py
index 8597460..8c495bc 100644
--- a/python/packagekit/client.py
+++ b/python/packagekit/client.py
@@ -73,6 +73,9 @@ class PackageKitClient:
         '''
         pk_xn.connect_to_signal('Finished', self._h_finished)
         pk_xn.connect_to_signal('ErrorCode', self._h_error)
+        pk_xn.connect_to_signal('StatusChanged', self._h_status)
+        pk_xn.connect_to_signal('AllowCancel', self._h_allowcancel)
+        pk_xn.connect_to_signal('ProgressChanged', self._h_progress)
         for cb in callbacks.keys():
             pk_xn.connect_to_signal(cb, callbacks[cb])
 
@@ -502,9 +505,6 @@ class PackageKitClient:
         self._allow_cancel = False
 
         if progress_cb:
-            pk_xn.connect_to_signal('StatusChanged', self._h_status)
-            pk_xn.connect_to_signal('AllowCancel', self._h_allowcancel)
-            pk_xn.connect_to_signal('ProgressChanged', self._h_progress)
             self._progress_cb = progress_cb
         self._wrapBasicCall(pk_xn, method)
         if self._finished_status != 'success':
commit 6f0997f8f2151c185f76e3b33853fd29ce0301c3
Author: Sebastian Heinlein <devel at glatzor.de>
Date:   Tue Oct 14 12:33:43 2008 +0200

    python client: SetLocale does not report a status

diff --git a/python/packagekit/client.py b/python/packagekit/client.py
index 8cbcacd..8597460 100644
--- a/python/packagekit/client.py
+++ b/python/packagekit/client.py
@@ -420,7 +420,7 @@ class PackageKitClient:
 
     def SetLocale(self, code):
         xn = self._get_xn()
-        self._wrapBasicCall(xn, lambda : xn.SetLocale(code))
+        xn.SetLocale(code)
 
     def AcceptEula(self, eula_id):
         xn = self._get_xn()
commit 8e0c3427be00df54261d695fb4dc0f522f104533
Author: Sebastian Heinlein <devel at glatzor.de>
Date:   Tue Oct 14 12:29:19 2008 +0200

    Python client: UpdateSystem should be handeled as a long taking action

diff --git a/python/packagekit/client.py b/python/packagekit/client.py
index 0d13c74..8cbcacd 100644
--- a/python/packagekit/client.py
+++ b/python/packagekit/client.py
@@ -342,15 +342,12 @@ class PackageKitClient:
         xn = self._get_xn()
         return self._wrapPackageCall(xn, lambda : xn.GetPackages(filters))
 
-    def UpdateSystem(self):
+    def UpdateSystem(self, progress_cb=None):
         '''
-        This method should return a list of packages that are
-        installed and are upgradable.
-
-        It should only return the newest update for each installed package.
+        This method should update the system
         '''
         xn = self._get_xn()
-        self._wrapPackageCall(xn, lambda : xn.UpdateSystem())
+        self._doPackages(xn, lambda : xn.UpdateSystem(), progress_cb)
 
     def DownloadPackages(self, package_ids):
         package_ids = self._to_list(package_ids) # Make sure we have a list
commit ff221da2108e198fa09eff50ebe089a78109bb6e
Author: Sebastian Heinlein <devel at glatzor.de>
Date:   Mon Oct 13 21:40:22 2008 +0200

    Add the description to the PackageKitError exception in client

diff --git a/python/packagekit/client.py b/python/packagekit/client.py
index fa7914a..0d13c74 100644
--- a/python/packagekit/client.py
+++ b/python/packagekit/client.py
@@ -39,11 +39,12 @@ class PackageKitError(Exception):
     http://www.packagekit.org/pk-reference.html#introduction-errors for details
     and possible values.
     '''
-    def __init__(self, error):
+    def __init__(self, error, desc=None):
         self.error = error
+        self.desc = desc
 
     def __str__(self):
-        return self.error
+        return "%s: %s" % (self.error, self.desc)
 
 class PackageKitClient:
     '''PackageKit client wrapper class.
@@ -78,7 +79,7 @@ class PackageKitClient:
         polkit_auth_wrapper(method)
         self._wait()
         if self._error_enum:
-            raise PackageKitError(self._error_enum)
+            raise PackageKitError(self._error_enum, self._error_desc)
 
     def _wrapBasicCall(self, pk_xn, method):
         return self._wrapCall(pk_xn, method, {})
@@ -458,6 +459,7 @@ class PackageKitClient:
         ErrorCode signal handler
         '''
         self._error_enum = enum
+        self._error_desc = desc
 
     def _h_finished(self, status, code):
         '''
@@ -515,6 +517,7 @@ class PackageKitClient:
         '''Create a new PackageKit Transaction object.'''
 
         self._error_enum = None
+        self._error_desc = None
         self._finished_status = None
         try:
             tid = self.pk_control.GetTid()


More information about the PackageKit-commit mailing list