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

Richard Hughes hughsient at kemper.freedesktop.org
Wed Dec 17 10:31:33 PST 2008


 AUTHORS                              |    3 
 backends/dummy/pk-backend-dummy.c    |    8 
 backends/test/helpers/packagekit     |    2 
 backends/yum/yumBackend.py           |  322 ++++----
 backends/yum/yumComps.py             |    7 
 configure.ac                         |   10 
 contrib/Makefile.am                  |    4 
 contrib/PackageKit.spec.in           |   17 
 contrib/ruck/AUTHORS                 |    3 
 contrib/ruck/Makefile.am             |    9 
 contrib/ruck/README                  |   20 
 contrib/ruck/src/.gitignore          |    2 
 contrib/ruck/src/Makefile.am         |   32 
 contrib/ruck/src/i18n.py             |   32 
 contrib/ruck/src/ruck.in             |   52 +
 contrib/ruck/src/ruckcachecmds.py    |  349 +++++++++
 contrib/ruck/src/ruckcommand.py      |  641 ++++++++++++++++
 contrib/ruck/src/ruckformat.py       |  293 +++++++
 contrib/ruck/src/rucklocks.py        |   67 +
 contrib/ruck/src/ruckmain.py         |  175 ++++
 contrib/ruck/src/ruckpackagecmds.py  | 1343 +++++++++++++++++++++++++++++++++++
 contrib/ruck/src/rucktalk.py         |   81 ++
 contrib/ruck/src/rucktransactcmds.py |  245 ++++++
 contrib/ruck/src/ruckyum.py          |  295 +++++++
 etc/PackageKit.conf.in               |    5 
 lib/packagekit-glib/egg-test.c       |    7 
 lib/packagekit-glib/pk-client.c      |  161 ++++
 lib/packagekit-glib/pk-client.h      |    3 
 lib/packagekit-glib/pk-common.c      |   11 
 lib/packagekit-glib/pk-enum.c        |    5 
 lib/packagekit-glib/pk-enum.h        |    5 
 lib/python/packagekit/client.py      |    2 
 po/pa.po                             |  408 ++++++++++
 po/pl.po                             |  439 ++++++++---
 src/Makefile.am                      |    2 
 src/org.freedesktop.PackageKit.xml   |    9 
 src/pk-backend.c                     |    5 
 src/pk-network-nm.c                  |    6 
 src/pk-spawn.c                       |   10 
 src/pk-sysdep.c                      |  107 ++
 src/pk-sysdep.h                      |   35 
 src/pk-transaction.c                 |   12 
 42 files changed, 4962 insertions(+), 282 deletions(-)

New commits:
commit 3263d6a9c9e97e569f2f31c4cc5fa82adfc27ea6
Author: Richard Hughes <richard at hughsie.com>
Date:   Wed Dec 17 18:27:53 2008 +0000

    trivial: make pk-sysdep more GLib friendly, and use other PK nomenclature

diff --git a/src/pk-spawn.c b/src/pk-spawn.c
index 4553a21..263995b 100644
--- a/src/pk-spawn.c
+++ b/src/pk-spawn.c
@@ -462,18 +462,17 @@ pk_spawn_argv (PkSpawn *spawn, gchar **argv, gchar **envp)
 	nice = pk_conf_get_int (spawn->priv->conf, "BackendSpawnNiceValue");
 	nice = CLAMP(nice, -20, 19);
 
-	/* get idle io from config */
-	idleio = pk_conf_get_bool (spawn->priv->conf, "BackendSpawnIdleIO");
-
 	/* don't completely bog the system down */
 	if (nice != 0) {
 		egg_debug ("renice to %i", nice);
 		setpriority (PRIO_PROCESS, spawn->priv->child_pid, nice);
 	}
 
+	/* perhaps set idle IO priority */
+	idleio = pk_conf_get_bool (spawn->priv->conf, "BackendSpawnIdleIO");
 	if (idleio) {
 		egg_debug ("setting ioprio class to idle");
-		pk_set_ioprio_idle (spawn->priv->child_pid);
+		pk_ioprio_set_idle (spawn->priv->child_pid);
 	}
 
 	/* we failed to invoke the helper */
diff --git a/src/pk-sysdep.c b/src/pk-sysdep.c
index 5ce52ee..574df23 100644
--- a/src/pk-sysdep.c
+++ b/src/pk-sysdep.c
@@ -19,31 +19,89 @@
  * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
  */
 
+#include <glib.h>
+#include <unistd.h>
+
+#ifdef linux
+ #include <sys/syscall.h>
+#endif
+
 #include "pk-sysdep.h"
 
 #ifdef linux
 
-static inline int 
-ioprio_set(int which, int who, int ioprio)
+enum {
+	IOPRIO_CLASS_NONE,
+	IOPRIO_CLASS_RT,
+	IOPRIO_CLASS_BE,
+	IOPRIO_CLASS_IDLE,
+};
+
+enum {
+	IOPRIO_WHO_PROCESS = 1,
+	IOPRIO_WHO_PGRP,
+	IOPRIO_WHO_USER,
+};
+
+#define IOPRIO_CLASS_SHIFT	13
+
+/**
+ * ioprio_set:
+ *
+ * FIXME: glibc should have this function
+ **/
+static inline gint
+ioprio_set (gint which, gint who, gint ioprio)
 {
 	return syscall (SYS_ioprio_set, which, who, ioprio);
 }
 
-int 
-pk_set_ioprio_idle(pid_t pid) 
+/**
+ * pk_ioprio_set_idle:
+ *
+ * Set the IO priority to idle
+ **/
+gboolean
+pk_ioprio_set_idle (GPid pid)
 {
-	int prio = 7;
-	int class = IOPRIO_CLASS_IDLE << IOPRIO_CLASS_SHIFT;
+	gint prio = 7;
+	gint class = IOPRIO_CLASS_IDLE << IOPRIO_CLASS_SHIFT;
 
-	return ioprio_set (IOPRIO_WHO_PROCESS, pid, prio | class);
+	return (ioprio_set (IOPRIO_WHO_PROCESS, pid, prio | class) == 0);
+}
+
+/**
+ * pk_ioprio_set_best_effort:
+ *
+ * Set the IO priority to best_effort
+ **/
+gboolean
+pk_ioprio_set_best_effort (GPid pid)
+{
+	gint prio = 7;
+	gint class = IOPRIO_CLASS_BE << IOPRIO_CLASS_SHIFT;
+
+	return (ioprio_set (IOPRIO_WHO_PROCESS, pid, prio | class) == 0);
 }
 
 #else
 
-int 
-pk_set_ioprio_idle(pid_t pid) 
+/**
+ * pk_ioprio_set_idle:
+ **/
+gboolean
+pk_ioprio_set_idle (GPid pid)
+{
+	return TRUE;
+}
+
+/**
+ * pk_ioprio_set_best_effort:
+ **/
+gboolean
+pk_ioprio_set_best_effort (GPid pid)
 {
-	return 0;
+	return TRUE;
 }
 
 #endif
diff --git a/src/pk-sysdep.h b/src/pk-sysdep.h
index 14f989d..dd6f5ed 100644
--- a/src/pk-sysdep.h
+++ b/src/pk-sysdep.h
@@ -22,29 +22,14 @@
 #ifndef __PK_SYSDEP_H
 #define __PK_SYSDEP_H
 
-#include <unistd.h>
+#include <glib.h>
 
-#ifdef linux
+G_BEGIN_DECLS
 
-#include <sys/syscall.h>
+gboolean	pk_ioprio_set_idle		(GPid		pid);
+gboolean	pk_ioprio_set_best_effort	(GPid		pid);
 
-enum {
-	IOPRIO_CLASS_NONE,
-	IOPRIO_CLASS_RT,
-	IOPRIO_CLASS_BE,
-	IOPRIO_CLASS_IDLE,
-};
+G_END_DECLS
 
-enum {
-	IOPRIO_WHO_PROCESS = 1,
-	IOPRIO_WHO_PGRP,
-	IOPRIO_WHO_USER,
-};
+#endif /* __PK_SYSDEP_H */
 
-#define IOPRIO_CLASS_SHIFT	13
-
-#endif
-
-int pk_set_ioprio_idle(pid_t pid);
-
-#endif
commit 6e8f2be98262adcd133d30a8b703dbe7be2c8a07
Author: Richard Hughes <richard at hughsie.com>
Date:   Wed Dec 17 18:21:50 2008 +0000

    dummy: add some markdown text for demos

diff --git a/backends/dummy/pk-backend-dummy.c b/backends/dummy/pk-backend-dummy.c
index 01074a8..96ee0c0 100644
--- a/backends/dummy/pk-backend-dummy.c
+++ b/backends/dummy/pk-backend-dummy.c
@@ -152,9 +152,9 @@ backend_get_details (PkBackend *backend, gchar **package_ids)
 {
 	pk_backend_set_status (backend, PK_STATUS_ENUM_QUERY);
 	pk_backend_details (backend, "gnome-power-manager;2.6.19;i386;fedora", "GPL2", PK_GROUP_ENUM_PROGRAMMING,
-"Scribus is an desktop open source page layöut program with "
-"the aim of producing commercial grade output in PDF and "
-"Postscript, primarily, though not exclusively for Linux.\n"
+"Scribus is an desktop *open source* page layöut program with "
+"the aim of producing commercial grade output in **PDF** and "
+"**Postscript**, primarily, though not exclusively for Linux.\n"
 "\n"
 "While the goals of the program are for ease of use and simple easy to "
 "understand tools, Scribus offers support for professional publishing "
@@ -258,7 +258,7 @@ backend_get_update_detail_timeout (gpointer data)
 						  "http://www.distro-update.org/page?moo;Bugfix release for gtkhtml",
 						  "http://bgzilla.gnome.org/result.php?#9876;GNOME Bugzilla #9876",
 						  NULL, PK_RESTART_ENUM_SESSION,
-						  "Update to latest whizz bang version\n"
+						  "Update to latest *whizz* **bang** version\n"
 						  "* support this new thing\n"
 						  "* something else\n"
 						  "- and that new thing",
commit 8156df602fad77c38ce9e5a2385791c9b5e1e015
Author: Richard Hughes <richard at hughsie.com>
Date:   Wed Dec 17 18:21:28 2008 +0000

    trivial: fix yum backend to output markdown text

diff --git a/backends/yum/yumBackend.py b/backends/yum/yumBackend.py
index 592057f..fcfbcb5 100755
--- a/backends/yum/yumBackend.py
+++ b/backends/yum/yumBackend.py
@@ -1831,8 +1831,7 @@ class PackageKitYumBackend(PackageKitBaseBackend, PackagekitPackage):
         pkgver = _get_package_ver(pkg)
         package_id = self.get_package_id(pkg.name, pkgver, pkg.arch, pkg.repo)
         desc = pkg.description
-        desc = desc.replace('\n\n', ';')
-        desc = desc.replace('\n', ' ')
+        desc = desc.replace('\n', ';')
         group = self.comps.get_group(pkg.name)
         self.details(package_id, pkg.license, group, desc, pkg.url, pkg.size)
 
commit bf8076aadcccd318d36a1a01afaec58331a47a78
Author: Adel Gadllah <adel.gadllah at gmail.com>
Date:   Wed Dec 17 18:48:05 2008 +0100

    pk-sysdep: fix build

diff --git a/src/Makefile.am b/src/Makefile.am
index 604ed79..ee79123 100644
--- a/src/Makefile.am
+++ b/src/Makefile.am
@@ -79,6 +79,8 @@ shared_SOURCES =					\
 	pk-notify.h					\
 	pk-spawn.c					\
 	pk-spawn.h					\
+	pk-sysdep.h					\
+	pk-sysdep.c					\
 	pk-update-detail-list.c				\
 	pk-update-detail-list.h				\
 	pk-file-monitor.h				\
diff --git a/src/pk-sysdep.c b/src/pk-sysdep.c
index c2b9e96..5ce52ee 100644
--- a/src/pk-sysdep.c
+++ b/src/pk-sysdep.c
@@ -20,6 +20,7 @@
  */
 
 #include "pk-sysdep.h"
+
 #ifdef linux
 
 static inline int 
@@ -37,4 +38,12 @@ pk_set_ioprio_idle(pid_t pid)
 	return ioprio_set (IOPRIO_WHO_PROCESS, pid, prio | class);
 }
 
+#else
+
+int 
+pk_set_ioprio_idle(pid_t pid) 
+{
+	return 0;
+}
+
 #endif
diff --git a/src/pk-sysdep.h b/src/pk-sysdep.h
index c453e29..14f989d 100644
--- a/src/pk-sysdep.h
+++ b/src/pk-sysdep.h
@@ -22,10 +22,11 @@
 #ifndef __PK_SYSDEP_H
 #define __PK_SYSDEP_H
 
+#include <unistd.h>
+
 #ifdef linux
 
 #include <sys/syscall.h>
-#include <unistd.h>
 
 enum {
 	IOPRIO_CLASS_NONE,
@@ -42,10 +43,8 @@ enum {
 
 #define IOPRIO_CLASS_SHIFT	13
 
-int pk_set_ioprio_idle(pid_t pid);
-
-#endif 
+#endif
 
-#define pk_set_ioprio_idle
+int pk_set_ioprio_idle(pid_t pid);
 
 #endif
commit 491c1c887abd42c282ee8277bc65456be616577b
Author: Adel Gadllah <adel.gadllah at gmail.com>
Date:   Wed Dec 17 17:55:22 2008 +0100

    Don't let spawned backends hog the disk by default

diff --git a/etc/PackageKit.conf.in b/etc/PackageKit.conf.in
index d94ce75..56c8836 100644
--- a/etc/PackageKit.conf.in
+++ b/etc/PackageKit.conf.in
@@ -39,6 +39,11 @@ BackendShutdownTimeout=5
 # default=10
 BackendSpawnNiceValue=10
 
+# Set the iopriority class of the spawned backend to idle.
+# This ensures the process does not hog the disk when performing actions.
+# default=true
+BackendSpawnIdleIO=true
+
 # Default backend, as chosen in the configure script. This will be used where
 # no --backend="foo" option is given to the daemon.
 #
diff --git a/src/pk-spawn.c b/src/pk-spawn.c
index 601ed7d..4553a21 100644
--- a/src/pk-spawn.c
+++ b/src/pk-spawn.c
@@ -50,6 +50,8 @@
 #include "pk-marshal.h"
 #include "pk-conf.h"
 
+#include "pk-sysdep.h"
+
 static void     pk_spawn_class_init	(PkSpawnClass *klass);
 static void     pk_spawn_init		(PkSpawn      *spawn);
 static void     pk_spawn_finalize	(GObject       *object);
@@ -390,6 +392,7 @@ gboolean
 pk_spawn_argv (PkSpawn *spawn, gchar **argv, gchar **envp)
 {
 	gboolean ret;
+	gboolean idleio;
 	guint i;
 	guint len;
 	gint nice;
@@ -459,12 +462,20 @@ pk_spawn_argv (PkSpawn *spawn, gchar **argv, gchar **envp)
 	nice = pk_conf_get_int (spawn->priv->conf, "BackendSpawnNiceValue");
 	nice = CLAMP(nice, -20, 19);
 
+	/* get idle io from config */
+	idleio = pk_conf_get_bool (spawn->priv->conf, "BackendSpawnIdleIO");
+
 	/* don't completely bog the system down */
 	if (nice != 0) {
 		egg_debug ("renice to %i", nice);
 		setpriority (PRIO_PROCESS, spawn->priv->child_pid, nice);
 	}
 
+	if (idleio) {
+		egg_debug ("setting ioprio class to idle");
+		pk_set_ioprio_idle (spawn->priv->child_pid);
+	}
+
 	/* we failed to invoke the helper */
 	if (!ret) {
 		egg_warning ("failed to spawn '%s'", argv[0]);
diff --git a/src/pk-sysdep.c b/src/pk-sysdep.c
new file mode 100644
index 0000000..c2b9e96
--- /dev/null
+++ b/src/pk-sysdep.c
@@ -0,0 +1,40 @@
+/* -*- Mode: C; tab-width: 8; indent-tabs-mode: t; c-basic-offset: 8 -*-
+ *
+ * Copyright (C) 2008 Adel Gadllah <adel.gadllah at gmail.com>
+ *
+ * Licensed under the GNU General Public License Version 2
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+ */
+
+#include "pk-sysdep.h"
+#ifdef linux
+
+static inline int 
+ioprio_set(int which, int who, int ioprio)
+{
+	return syscall (SYS_ioprio_set, which, who, ioprio);
+}
+
+int 
+pk_set_ioprio_idle(pid_t pid) 
+{
+	int prio = 7;
+	int class = IOPRIO_CLASS_IDLE << IOPRIO_CLASS_SHIFT;
+
+	return ioprio_set (IOPRIO_WHO_PROCESS, pid, prio | class);
+}
+
+#endif
diff --git a/src/pk-sysdep.h b/src/pk-sysdep.h
new file mode 100644
index 0000000..c453e29
--- /dev/null
+++ b/src/pk-sysdep.h
@@ -0,0 +1,51 @@
+/* -*- Mode: C; tab-width: 8; indent-tabs-mode: t; c-basic-offset: 8 -*-
+ *
+ * Copyright (C) 2008 Adel Gadllah <adel.gadllah at gmail.com>
+ *
+ * Licensed under the GNU General Public License Version 2
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+ */
+
+#ifndef __PK_SYSDEP_H
+#define __PK_SYSDEP_H
+
+#ifdef linux
+
+#include <sys/syscall.h>
+#include <unistd.h>
+
+enum {
+	IOPRIO_CLASS_NONE,
+	IOPRIO_CLASS_RT,
+	IOPRIO_CLASS_BE,
+	IOPRIO_CLASS_IDLE,
+};
+
+enum {
+	IOPRIO_WHO_PROCESS = 1,
+	IOPRIO_WHO_PGRP,
+	IOPRIO_WHO_USER,
+};
+
+#define IOPRIO_CLASS_SHIFT	13
+
+int pk_set_ioprio_idle(pid_t pid);
+
+#endif 
+
+#define pk_set_ioprio_idle
+
+#endif
commit aeedc3fc9d5f29e023b2fd84cc6da0935c37d8c0
Author: Ken VanDine <ken at vandine.org>
Date:   Wed Dec 17 11:50:11 2008 -0500

    Forget arch for foresight, let the backend handle that at install time.

diff --git a/lib/packagekit-glib/pk-common.c b/lib/packagekit-glib/pk-common.c
index dfe5ad4..4b353bd 100644
--- a/lib/packagekit-glib/pk-common.c
+++ b/lib/packagekit-glib/pk-common.c
@@ -114,21 +114,16 @@ pk_get_distro_id (void)
 		goto out;
 	}
 
-	/* check for foresight */
+	/* check for foresight or foresight derivatives */
 	ret = g_file_get_contents ("/etc/distro-release", &contents, NULL, NULL);
 	if (ret) {
-		/* Foresight Linux 2.0.2 */
+		/* Foresight Linux 2 */
 		split = g_strsplit (contents, " ", 0);
 		if (split == NULL)
 			goto out;
 
-		/* we can't get arch from /etc */
-		arch = pk_get_machine_type ();
-		if (arch == NULL)
-			goto out;
-
 		/* complete! */
-		distro = g_strdup_printf ("foresight-%s-%s", split[2], arch);
+		distro = g_strdup_printf ("foresight-%s", split[2]);
 		goto out;
 	}
 
commit c9fb66bef821bb1e958111a62d38d4c854c95042
Author: Piotr DrÄ…g <piotrdrag at gmail.com>
Date:   Tue Dec 16 22:35:05 2008 +0000

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

diff --git a/po/pl.po b/po/pl.po
index 4320dc8..d40f8c7 100644
--- a/po/pl.po
+++ b/po/pl.po
@@ -5,46 +5,208 @@ msgid ""
 msgstr ""
 "Project-Id-Version: pl\n"
 "Report-Msgid-Bugs-To: \n"
-"POT-Creation-Date: 2008-11-24 22:20+0100\n"
-"PO-Revision-Date: 2008-11-24 22:26+0100\n"
+"POT-Creation-Date: 2008-12-16 23:24+0100\n"
+"PO-Revision-Date: 2008-12-16 23:25+0100\n"
 "Last-Translator: Piotr DrÄ…g <piotrdrag at gmail.com>\n"
 "Language-Team: Polish <pl at li.org>\n"
 "MIME-Version: 1.0\n"
 "Content-Type: text/plain; charset=UTF-8\n"
 "Content-Transfer-Encoding: 8bit\n"
 
+#. TRANSLATORS: this is an atomic transaction
+#: ../client/pk-console.c:230
+msgid "Transaction"
+msgstr "Transakcja"
+
+#. TRANSLATORS: this is the time the transaction was started in system timezone
+#: ../client/pk-console.c:232
+msgid "System time"
+msgstr "Czas systemowy"
+
+#. TRANSLATORS: this is if the transaction succeeded or not
+#: ../client/pk-console.c:234
+msgid "Succeeded"
+msgstr "Powodzenie"
+
+#. TRANSLATORS: if the repo is enabled
+#: ../client/pk-console.c:234 ../client/pk-console.c:377
+msgid "True"
+msgstr "Prawda"
+
+#: ../client/pk-console.c:234 ../client/pk-console.c:377
+msgid "False"
+msgstr "Fałsz"
+
+#. TRANSLATORS: this is the transactions role, e.g. "update-system"
+#: ../client/pk-console.c:236
+msgid "Role"
+msgstr "Rola"
+
+#. TRANSLATORS: this is The duration of the transaction
+#: ../client/pk-console.c:241
+msgid "Duration"
+msgstr "Czas trwania"
+
+#: ../client/pk-console.c:241
+msgid "(seconds)"
+msgstr "(sekundy)"
+
+#. TRANSLATORS: this is The command line used to do the action
+#: ../client/pk-console.c:245
+msgid "Command line"
+msgstr "Wiersz poleceń"
+
+#. TRANSLATORS: this is the user ID of the user that started the action
+#: ../client/pk-console.c:247
+msgid "User ID"
+msgstr "Identyfikator użytkownika"
+
+#. TRANSLATORS: this is the username, e.g. hughsie
+#: ../client/pk-console.c:254
+msgid "Username"
+msgstr "Nazwa użytkownika"
+
+#. TRANSLATORS: this is the users real name, e.g. "Richard Hughes"
+#: ../client/pk-console.c:258
+msgid "Real name"
+msgstr "ImiÄ™ i nazwisko"
+
+#: ../client/pk-console.c:266
+msgid "Affected packages:"
+msgstr "Dotyczy pakietów:"
+
+#: ../client/pk-console.c:268
+msgid "Affected packages: None"
+msgstr "Dotyczy pakietów: żadnych"
+
+#. TRANSLATORS: this is the distro, e.g. Fedora 10
+#: ../client/pk-console.c:293
+msgid "Distribution"
+msgstr "Dystrybucja"
+
+#. TRANSLATORS: this is type of update, stable or testing
+#: ../client/pk-console.c:295
+msgid "Type"
+msgstr "Typ"
+
+#. TRANSLATORS: this is any summary text describing the upgrade
+#. TRANSLATORS: this is the summary of the group
+#: ../client/pk-console.c:297 ../client/pk-console.c:319
+msgid "Summary"
+msgstr "Podsumowanie"
+
+#. TRANSLATORS: this is the group category name
+#: ../client/pk-console.c:309
+msgid "Category"
+msgstr "Kategoria"
+
+#. TRANSLATORS: this is group identifier
+#: ../client/pk-console.c:311
+msgid "ID"
+msgstr "Identyfikator"
+
+#. TRANSLATORS: this is the parent group
+#: ../client/pk-console.c:314
+msgid "Parent"
+msgstr "Nadrzędna"
+
+#: ../client/pk-console.c:316
+msgid "Name"
+msgstr "Nazwa"
+
+#. TRANSLATORS: this is preferred icon for the group
+#: ../client/pk-console.c:322
+msgid "Icon"
+msgstr "Ikona"
+
 #. TRANSLATORS: this is a header for the package that can be updated
-#: ../client/pk-console.c:287
+#: ../client/pk-console.c:337
 msgid "Details about the update:"
 msgstr "Szczegóły aktualizacji:"
 
-#: ../client/pk-console.c:480
+#: ../client/pk-console.c:338
+msgid "Package"
+msgstr "Pakiet"
+
+#: ../client/pk-console.c:340
+msgid "Updates"
+msgstr "Aktualizuje"
+
+#: ../client/pk-console.c:342
+msgid "Obsoletes"
+msgstr "Zastępuje"
+
+#: ../client/pk-console.c:344
+msgid "Vendor"
+msgstr "Producent"
+
+#: ../client/pk-console.c:346
+msgid "Bugzilla"
+msgstr "Bugzilla"
+
+#: ../client/pk-console.c:348
+msgid "CVE"
+msgstr "CVE"
+
+#: ../client/pk-console.c:350
+msgid "Restart"
+msgstr "Uruchom ponownie"
+
+#: ../client/pk-console.c:352
+msgid "Update text"
+msgstr "Tekst aktualizacji"
+
+#: ../client/pk-console.c:354
+msgid "Changes"
+msgstr "Zmiany"
+
+#: ../client/pk-console.c:356
+msgid "State"
+msgstr "Stan"
+
+#: ../client/pk-console.c:359
+msgid "Issued"
+msgstr "Wydano"
+
+#: ../client/pk-console.c:362
+msgid "Updated"
+msgstr "Zaktualizowano"
+
+#: ../client/pk-console.c:448 ../client/pk-console.c:450
+msgid "Percentage"
+msgstr "Procentowo"
+
+#: ../client/pk-console.c:450
+msgid "Unknown"
+msgstr "Nieznane"
+
+#: ../client/pk-console.c:525
 msgid "Please restart the computer to complete the update."
 msgstr "Proszę uruchomić ponownie komputer, aby zakończyć aktualizację."
 
-#: ../client/pk-console.c:482
+#: ../client/pk-console.c:527
 msgid "Please logout and login to complete the update."
 msgstr "Proszę wylogować się i zalogować, aby zakończyć aktualizację."
 
-#: ../client/pk-console.c:484
+#: ../client/pk-console.c:529
 msgid "Please restart the application as it is being used."
 msgstr "Proszę uruchomić program ponownie, ponieważ jest używany."
 
 #. TRANSLATORS: The package is already installed on the system
-#: ../client/pk-console.c:596
+#: ../client/pk-console.c:641
 #, c-format
 msgid "The package %s is already installed"
 msgstr "Pakiet %s jest już zainstalowany"
 
 #. TRANSLATORS: The package name was not found in any software sources. The detailed error follows
-#: ../client/pk-console.c:604
+#: ../client/pk-console.c:649
 #, c-format
 msgid "The package %s could not be installed: %s"
 msgstr "Nie można zainstalować pakietu %s: %s"
 
 #. TRANSLATORS: There was a programming error that shouldn't happen. The detailed error follows
-#: ../client/pk-console.c:629 ../client/pk-console.c:656
-#: ../client/pk-console.c:752 ../client/pk-console.c:869
+#: ../client/pk-console.c:674 ../client/pk-console.c:701
+#: ../client/pk-console.c:797 ../client/pk-console.c:914
 #: ../client/pk-tools-common.c:61 ../client/pk-tools-common.c:79
 #: ../client/pk-tools-common.c:86
 #, c-format
@@ -52,363 +214,365 @@ msgid "Internal error: %s"
 msgstr "Wewnętrzny błąd: %s"
 
 #. TRANSLATORS: There was an error installing the packages. The detailed error follows
-#: ../client/pk-console.c:637 ../client/pk-console.c:1264
+#: ../client/pk-console.c:682 ../client/pk-console.c:1309
 #, c-format
 msgid "This tool could not install the packages: %s"
 msgstr "To narzędzie nie może zainstalować pakietów: %s"
 
 #. TRANSLATORS: There was an error installing the files. The detailed error follows
-#: ../client/pk-console.c:664
+#: ../client/pk-console.c:709
 #, c-format
 msgid "This tool could not install the files: %s"
 msgstr "To narzędzie nie może zainstalować plików: %s"
 
 #. TRANSLATORS: The package name was not found in the installed list. The detailed error follows
-#: ../client/pk-console.c:720
+#: ../client/pk-console.c:765
 #, c-format
 msgid "This tool could not remove %s: %s"
 msgstr "To narzędzie nie może usunąć %s: %s"
 
 #. TRANSLATORS: There was an error removing the packages. The detailed error follows
-#: ../client/pk-console.c:743 ../client/pk-console.c:781
-#: ../client/pk-console.c:814
+#: ../client/pk-console.c:788 ../client/pk-console.c:826
+#: ../client/pk-console.c:859
 #, c-format
 msgid "This tool could not remove the packages: %s"
 msgstr "To narzędzie nie może usunąć pakietów: %s"
 
 #. TRANSLATORS: When removing, we might have to remove other dependencies
-#: ../client/pk-console.c:793
+#: ../client/pk-console.c:838
 msgid "The following packages have to be removed:"
 msgstr "Następujące pakiety muszą zostać usunięte:"
 
 #. TRANSLATORS: We are checking if it's okay to remove a list of packages
-#: ../client/pk-console.c:800
+#: ../client/pk-console.c:845
 msgid "Proceed removing additional packages?"
 msgstr "Kontynuować usuwanie dodatkowych pakietów?"
 
 #. TRANSLATORS: We did not remove any packages
-#: ../client/pk-console.c:805
+#: ../client/pk-console.c:850
 msgid "The package removal was canceled!"
 msgstr "Anulowano usunięcie pakietu!"
 
 #. TRANSLATORS: The package name was not found in any software sources
-#: ../client/pk-console.c:846
+#: ../client/pk-console.c:891
 #, c-format
 msgid "This tool could not download the package %s as it could not be found"
 msgstr "To narzędzie nie może pobrać pakietu %s, ponieważ nie można go znaleźć"
 
 #. TRANSLATORS: Could not download the packages for some reason. The detailed error follows
-#: ../client/pk-console.c:877
+#: ../client/pk-console.c:922
 #, c-format
 msgid "This tool could not download the packages: %s"
 msgstr "To narzędzie nie może pobrać pakietów: %s"
 
 #. TRANSLATORS: There was an error getting the list of files for the package. The detailed error follows
-#: ../client/pk-console.c:904 ../client/pk-console.c:913
+#: ../client/pk-console.c:949 ../client/pk-console.c:958
 #, c-format
 msgid "This tool could not update %s: %s"
 msgstr "To narzędzie nie może zaktualizować %s: %s"
 
 #. TRANSLATORS: There was an error getting the list of files for the package. The detailed error follows
-#: ../client/pk-console.c:935 ../client/pk-console.c:943
+#: ../client/pk-console.c:980 ../client/pk-console.c:988
 #, c-format
 msgid "This tool could not get the requirements for %s: %s"
 msgstr "To narzędzie nie może uzyskać wymagań dla %s: %s"
 
 #. TRANSLATORS: There was an error getting the dependencies for the package. The detailed error follows
-#: ../client/pk-console.c:965 ../client/pk-console.c:973
+#: ../client/pk-console.c:1010 ../client/pk-console.c:1018
 #, c-format
 msgid "This tool could not get the dependencies for %s: %s"
 msgstr "To narzędzie nie może uzyskać zależności dla %s: %s"
 
 #. TRANSLATORS: There was an error getting the details about the package. The detailed error follows
-#: ../client/pk-console.c:995 ../client/pk-console.c:1003
+#: ../client/pk-console.c:1040 ../client/pk-console.c:1048
 #, c-format
 msgid "This tool could not get package details for %s: %s"
 msgstr "To narzędzie nie może uzyskać szczegółów pakietu %s: %s"
 
 #. TRANSLATORS: The package name was not found in any software sources. The detailed error follows
-#: ../client/pk-console.c:1025
+#: ../client/pk-console.c:1070
 #, c-format
 msgid "This tool could not find the files for %s: %s"
 msgstr "To narzędzie nie może znaleźć plików dla %s: %s"
 
 #. TRANSLATORS: There was an error getting the list of files for the package. The detailed error follows
-#: ../client/pk-console.c:1033
+#: ../client/pk-console.c:1078
 #, c-format
 msgid "This tool could not get the file list for %s: %s"
 msgstr "To narzędzie nie może uzyskać listy plików dla %s: %s"
 
 #. TRANSLATORS: There was an error getting the list of packages. The filename follows
-#: ../client/pk-console.c:1055
+#: ../client/pk-console.c:1100
 #, c-format
 msgid "File already exists: %s"
 msgstr "Plik już istnieje: %s"
 
 #. TRANSLATORS: follows a list of packages to install
-#: ../client/pk-console.c:1060 ../client/pk-console.c:1116
-#: ../client/pk-console.c:1191
+#: ../client/pk-console.c:1105 ../client/pk-console.c:1161
+#: ../client/pk-console.c:1236
 msgid "Getting package list"
 msgstr "Pobieranie listy pakietów"
 
 #. TRANSLATORS: There was an error getting the list of packages. The detailed error follows
-#: ../client/pk-console.c:1066 ../client/pk-console.c:1122
-#: ../client/pk-console.c:1197
+#: ../client/pk-console.c:1111 ../client/pk-console.c:1167
+#: ../client/pk-console.c:1242
 #, c-format
 msgid "This tool could not get package list: %s"
 msgstr "To narzędzie nie może pobrać listy pakietów: %s"
 
 #. TRANSLATORS: There was an error saving the list
-#: ../client/pk-console.c:1077
+#: ../client/pk-console.c:1122
 #, c-format
 msgid "Failed to save to disk"
 msgstr "Zapisanie na dysku nie powiodło się"
 
 #. TRANSLATORS: There was an error getting the list. The filename follows
-#: ../client/pk-console.c:1111 ../client/pk-console.c:1186
+#: ../client/pk-console.c:1156 ../client/pk-console.c:1231
 #, c-format
 msgid "File does not exist: %s"
 msgstr "Plik nie istnieje: %s"
 
 #. TRANSLATORS: header to a list of packages newly added
-#: ../client/pk-console.c:1143
+#: ../client/pk-console.c:1188
 msgid "Packages to add"
 msgstr "Pakiety do dodania"
 
 #. TRANSLATORS: header to a list of packages removed
-#: ../client/pk-console.c:1151
+#: ../client/pk-console.c:1196
 msgid "Packages to remove"
 msgstr "Pakiety do usunięcia"
 
 #. TRANSLATORS: We didn't find any differences
-#: ../client/pk-console.c:1219
+#: ../client/pk-console.c:1264
 #, c-format
 msgid "No new packages need to be installed"
 msgstr "Nie trzeba instalować nowych pakietów"
 
 #. TRANSLATORS: follows a list of packages to install
-#: ../client/pk-console.c:1225
+#: ../client/pk-console.c:1270
 msgid "To install"
 msgstr "Do zainstalowania"
 
 #. TRANSLATORS: searching takes some time....
-#: ../client/pk-console.c:1236
+#: ../client/pk-console.c:1281
 msgid "Searching for package: "
 msgstr "Wyszukiwanie pakietu: "
 
 #. TRANSLATORS: package was not found -- this is the end of a string ended in ...
-#: ../client/pk-console.c:1240
+#: ../client/pk-console.c:1285
 msgid "not found."
 msgstr "nie znaleziono."
 
 #. TRANSLATORS: We didn't find any packages to install
-#: ../client/pk-console.c:1251
+#: ../client/pk-console.c:1296
 #, c-format
 msgid "No packages can be found to install"
 msgstr "Nie można znaleźć pakietów do zainstalowania"
 
 #. TRANSLATORS: installing new packages from package list
-#: ../client/pk-console.c:1257
+#: ../client/pk-console.c:1302
 msgid "Installing packages"
 msgstr "Instalowanie pakietów"
 
 #. TRANSLATORS: The package name was not found in any software sources. The detailed error follows
-#: ../client/pk-console.c:1293
+#: ../client/pk-console.c:1338
 #, c-format
 msgid "This tool could not find the update details for %s: %s"
 msgstr "To narzędzie nie może znaleźć szczegółów aktualizacji dla %s: %s"
 
 #. TRANSLATORS: There was an error getting the details about the update for the package. The detailed error follows
-#: ../client/pk-console.c:1301
+#: ../client/pk-console.c:1346
 #, c-format
 msgid "This tool could not get the update details for %s: %s"
 msgstr "To narzędzie nie może uzyskać szczegółów aktualizacji dla %s: %s"
 
 #. TRANSLATORS: This was an unhandled error, and we don't have _any_ context
-#: ../client/pk-console.c:1347
+#: ../client/pk-console.c:1392
 msgid "Error:"
 msgstr "BÅ‚Ä…d:"
 
 #. TRANSLATORS: This a list of details about the package
-#: ../client/pk-console.c:1361
+#: ../client/pk-console.c:1406
 msgid "Package description"
 msgstr "Opis pakietu"
 
 #. TRANSLATORS: This a list files contained in the package
-#: ../client/pk-console.c:1394
+#: ../client/pk-console.c:1439
 msgid "Package files"
 msgstr "Pliki pakietu"
 
 #. TRANSLATORS: This where the package has no files
-#: ../client/pk-console.c:1403
+#: ../client/pk-console.c:1448
 msgid "No files"
 msgstr "Brak plików"
 
 #. TRANSLATORS: This a request for a GPG key signature from the backend, which the client will prompt for later
-#: ../client/pk-console.c:1426
+#: ../client/pk-console.c:1471
 msgid "Repository signature required"
 msgstr "Wymagany jest podpis repozytorium"
 
 #. TRANSLATORS: This a prompt asking the user to import the security key
-#: ../client/pk-console.c:1436
+#: ../client/pk-console.c:1481
 msgid "Do you accept this signature?"
 msgstr "Zaakceptować ten podpis?"
 
 #. TRANSLATORS: This is where the user declined the security key
-#: ../client/pk-console.c:1440
+#: ../client/pk-console.c:1485
 msgid "The signature was not accepted."
 msgstr "Podpis nie został zaakceptowany."
 
 #. TRANSLATORS: This a request for a EULA
-#: ../client/pk-console.c:1474
+#: ../client/pk-console.c:1519
 msgid "End user license agreement required"
 msgstr "Licencja jest wymagana"
 
 #. TRANSLATORS: This a prompt asking the user to agree to the license
-#: ../client/pk-console.c:1481
+#: ../client/pk-console.c:1526
 msgid "Do you agree to this license?"
 msgstr "Zaakceptować tę licencję?"
 
 #. TRANSLATORS: This is where the user declined the license
-#: ../client/pk-console.c:1485
+#: ../client/pk-console.c:1530
 msgid "The license was refused."
 msgstr "Odrzucono licencjÄ™."
 
 #. TRANSLATORS: This is when the daemon crashed, and we are up shit creek without a paddle
-#: ../client/pk-console.c:1514
+#: ../client/pk-console.c:1559
 msgid "The daemon crashed mid-transaction!"
 msgstr "Demon zawiesił się w połowie transakcji!"
 
 #. TRANSLATORS: This is the header to the --help menu
-#: ../client/pk-console.c:1567
+#: ../client/pk-console.c:1612
 msgid "PackageKit Console Interface"
 msgstr "Interfejs konsoli PackageKit"
 
-#: ../client/pk-console.c:1567
+#: ../client/pk-console.c:1612
 msgid "Subcommands:"
 msgstr "Podpolecenia:"
 
-#: ../client/pk-console.c:1658 ../client/pk-generate-pack.c:184
-#: ../client/pk-monitor.c:115 ../src/pk-main.c:191
+#: ../client/pk-console.c:1703 ../client/pk-generate-pack.c:184
+#: ../client/pk-monitor.c:115
+#: ../contrib/command-not-found/pk-command-not-found.c:510
+#: ../src/pk-main.c:191
 msgid "Show extra debugging information"
 msgstr "Wyświetla dodatkowe informacje o debugowaniu"
 
-#: ../client/pk-console.c:1660 ../client/pk-monitor.c:117
+#: ../client/pk-console.c:1705 ../client/pk-monitor.c:117
 msgid "Show the program version and exit"
 msgstr "Wyświetla wersję programu i wyłącza"
 
-#: ../client/pk-console.c:1662
+#: ../client/pk-console.c:1707
 msgid "Set the filter, e.g. installed"
 msgstr "Ustawia filtr, np. zainstalowane"
 
-#: ../client/pk-console.c:1664
+#: ../client/pk-console.c:1709
 msgid "Exit without waiting for actions to complete"
 msgstr "Wyłącza bez oczekiwania na zakończenie działań"
 
 #. TRANSLATORS: This is when we could not connect to the system bus, and is fatal
-#: ../client/pk-console.c:1691
+#: ../client/pk-console.c:1736
 msgid "This tool could not connect to system DBUS."
 msgstr "To narzędzie nie może połączyć się z systemowym D-Bus."
 
 #. TRANSLATORS: The user specified an incorrect filter
-#: ../client/pk-console.c:1776
+#: ../client/pk-console.c:1821
 msgid "The filter specified was invalid"
 msgstr "Podany filtr jest nieprawidłowy"
 
-#: ../client/pk-console.c:1793
+#: ../client/pk-console.c:1838
 msgid "You need to specify a search type, e.g. name"
 msgstr "Należy podać typ wyszukiwania, np. po nazwie"
 
-#: ../client/pk-console.c:1798 ../client/pk-console.c:1805
-#: ../client/pk-console.c:1812 ../client/pk-console.c:1819
-#: ../client/pk-console.c:1930 ../client/pk-console.c:1940
-#: ../client/pk-console.c:1947 ../client/pk-console.c:1954
+#: ../client/pk-console.c:1843 ../client/pk-console.c:1850
+#: ../client/pk-console.c:1857 ../client/pk-console.c:1864
+#: ../client/pk-console.c:1975 ../client/pk-console.c:1985
+#: ../client/pk-console.c:1992 ../client/pk-console.c:1999
 msgid "You need to specify a search term"
 msgstr "Należy podać termin wyszukiwania"
 
-#: ../client/pk-console.c:1824
+#: ../client/pk-console.c:1869
 msgid "Invalid search type"
 msgstr "Nieprawidłowy typ wyszukiwania"
 
-#: ../client/pk-console.c:1829
+#: ../client/pk-console.c:1874
 msgid "You need to specify a package or file to install"
 msgstr "Należy podać pakiet lub plik do zainstalowania"
 
-#: ../client/pk-console.c:1836
+#: ../client/pk-console.c:1881
 msgid "You need to specify a type, key_id and package_id"
 msgstr "Należy podać typ, key_id i package_id"
 
-#: ../client/pk-console.c:1843
+#: ../client/pk-console.c:1888
 msgid "You need to specify a package to remove"
 msgstr "Należy podać pakiet do usunięcia"
 
-#: ../client/pk-console.c:1849
+#: ../client/pk-console.c:1894
 msgid ""
 "You need to specify the destination directory and then the packages to "
 "download"
 msgstr "Należy podać katalog docelowy, a następnie pakiety do pobrania"
 
-#: ../client/pk-console.c:1854
+#: ../client/pk-console.c:1899
 msgid "Directory not found"
 msgstr "Nie znaleziono katalogu"
 
-#: ../client/pk-console.c:1860
+#: ../client/pk-console.c:1905
 msgid "You need to specify a licence identifier (eula-id)"
 msgstr "Należy podać identyfikator licencji (eula-id)"
 
-#: ../client/pk-console.c:1876
+#: ../client/pk-console.c:1921
 msgid "You need to specify a package name to resolve"
 msgstr "Należy podać nazwę pakietu do rozwiązania"
 
-#: ../client/pk-console.c:1885 ../client/pk-console.c:1892
+#: ../client/pk-console.c:1930 ../client/pk-console.c:1937
 msgid "You need to specify a repository name"
 msgstr "Należy podać nazwę repozytorium"
 
-#: ../client/pk-console.c:1899
+#: ../client/pk-console.c:1944
 msgid "You need to specify a repo name/parameter and value"
 msgstr "Należy podać nazwę/parametr repozytorium i wartość"
 
-#: ../client/pk-console.c:1912
+#: ../client/pk-console.c:1957
 msgid "You need to specify an action, e.g. 'update-system'"
 msgstr "Należy podać działanie, np. \"update-system\""
 
-#: ../client/pk-console.c:1917
+#: ../client/pk-console.c:1962
 msgid "You need to specify a correct role"
 msgstr "Należy podać poprawną rolę"
 
-#: ../client/pk-console.c:1922
+#: ../client/pk-console.c:1967
 msgid "Failed to get last time"
 msgstr "Uzyskanie ostatniego czasu nie powiodło się"
 
-#: ../client/pk-console.c:1961
+#: ../client/pk-console.c:2006
 msgid "You need to specify a package to find the details for"
 msgstr "Należy podać pakiet do znalezienia szczegółów dla"
 
-#: ../client/pk-console.c:1968
+#: ../client/pk-console.c:2013
 msgid "You need to specify a package to find the files for"
 msgstr "Należy podać pakiet do znalezienia plików dla"
 
-#: ../client/pk-console.c:1975
+#: ../client/pk-console.c:2020
 msgid "You need to specify a list file to create"
 msgstr "Należy podać plik listy do utworzenia"
 
-#: ../client/pk-console.c:1983 ../client/pk-console.c:1991
+#: ../client/pk-console.c:2028 ../client/pk-console.c:2036
 msgid "You need to specify a list file to open"
 msgstr "Należy podać plik listy do otwarcia"
 
 #. TRANSLATORS: The user tried to use an unsupported option on the command line
-#: ../client/pk-console.c:2044
+#: ../client/pk-console.c:2089
 #, c-format
 msgid "Option '%s' is not supported"
 msgstr "Opcja \"%s\" nie jest obsługiwana"
 
 #. TRANSLATORS: User does not have permission to do this
-#: ../client/pk-console.c:2057
+#: ../client/pk-console.c:2102
 msgid "You don't have the necessary privileges for this operation"
 msgstr "Nie posiadasz niezbędnych uprawnień dla tej operacji"
 
 #. TRANSLATORS: Generic failure of what they asked to do
-#: ../client/pk-console.c:2060
+#: ../client/pk-console.c:2105
 msgid "Command failed"
 msgstr "Polecenie nie powiodło się"
 
@@ -522,61 +686,130 @@ msgstr "Pasuje więcej niż jeden pakiet:"
 msgid "Please choose the correct package: "
 msgstr "Proszę wybrać poprawny pakiet: "
 
-#: ../client/pk-tools-common.c:158
+#: ../client/pk-tools-common.c:157
 #, c-format
 msgid "Please enter a number from 1 to %i: "
 msgstr "Proszę podać numer od 1 do %i: "
 
+#. TRANSLATORS: we failed to find the package, this shouldn't happen
+#: ../contrib/command-not-found/pk-command-not-found.c:361
+msgid "Failed to search for file"
+msgstr "Znalezienie pliku nie powiodło się"
+
+#. TRANSLATORS: we failed to launch the executable, the error follows
+#: ../contrib/command-not-found/pk-command-not-found.c:485
+msgid "Failed to launch:"
+msgstr "Uruchomienie nie powiodło się:"
+
+#. TRANSLATORS: tool that gets called when the command is not found
+#: ../contrib/command-not-found/pk-command-not-found.c:526
+msgid "PackageKit Command Not Found"
+msgstr "Nie znaleziono polecenia PackageKit"
+
+#. TRANSLATORS: the prefix of all the output telling the user why it's not executing
+#: ../contrib/command-not-found/pk-command-not-found.c:548
+msgid "Command not found."
+msgstr "Nie znaleziono polecenia."
+
+#. TRANSLATORS: tell the user what we think the command is
+#: ../contrib/command-not-found/pk-command-not-found.c:555
+msgid "Similar command is:"
+msgstr "Podobne polecenie:"
+
+#. TRANSLATORS: Ask the user if we should run the similar command
+#: ../contrib/command-not-found/pk-command-not-found.c:564
+msgid "Run similar command:"
+msgstr "Wykonaj podobne polecenie:"
+
+#. TRANSLATORS: show the user a list of commands that they could have meant
+#. TRANSLATORS: show the user a list of commands we could run
+#: ../contrib/command-not-found/pk-command-not-found.c:576
+#: ../contrib/command-not-found/pk-command-not-found.c:585
+msgid "Similar commands are:"
+msgstr "Podobne polecenia:"
+
+#. TRANSLATORS: ask the user to choose a file to run
+#: ../contrib/command-not-found/pk-command-not-found.c:592
+msgid "Please choose a command to run"
+msgstr "Proszę wybrać polecenie do wykonania"
+
+#. TRANSLATORS: tell the user what package provides the command
+#: ../contrib/command-not-found/pk-command-not-found.c:607
+msgid "The package providing this file is:"
+msgstr "Pakiet dostarczajÄ…cy ten plik:"
+
+#. TRANSLATORS: as the user if we want to install a package to provide the command
+#: ../contrib/command-not-found/pk-command-not-found.c:612
+#, c-format
+msgid "Install package '%s' to provide command '%s'?"
+msgstr "Zainstalować pakiet \"%s\", aby dostarczyć polecenie \"%s\"?"
+
+#. TRANSLATORS: Show the user a list of packages that provide this command
+#: ../contrib/command-not-found/pk-command-not-found.c:633
+msgid "Packages providing this file are:"
+msgstr "Pakiety dostarczajÄ…ce ten plik :"
+
+#. TRANSLATORS: Show the user a list of packages that they can install to provide this command
+#: ../contrib/command-not-found/pk-command-not-found.c:642
+msgid "Suitable packages are:"
+msgstr "Odpowiednie pakiety:"
+
+#. get selection
+#. TRANSLATORS: ask the user to choose a file to install
+#: ../contrib/command-not-found/pk-command-not-found.c:650
+msgid "Please choose a package to install"
+msgstr "Proszę wybrać pakiet do zainstalowania"
+
 #. TRANSLATORS: when we are getting data from the daemon
-#: ../contrib/packagekit-plugin/src/contents.cpp:298
+#: ../contrib/browser-plugin/src/contents.cpp:298
 msgid "Getting package information..."
 msgstr "Pobieranie informacji o pakiecie..."
 
 #. TRANSLATORS: run an applicaiton
-#: ../contrib/packagekit-plugin/src/contents.cpp:304
+#: ../contrib/browser-plugin/src/contents.cpp:304
 #, c-format
 msgid "Run %s"
 msgstr "Uruchom %s"
 
 #. TRANSLATORS: show the installed version of a package
-#: ../contrib/packagekit-plugin/src/contents.cpp:310
+#: ../contrib/browser-plugin/src/contents.cpp:310
 msgid "Installed version"
 msgstr "Zainstalowana wersja"
 
 #. TRANSLATORS: run the application now
-#: ../contrib/packagekit-plugin/src/contents.cpp:318
+#: ../contrib/browser-plugin/src/contents.cpp:318
 #, c-format
 msgid "Run version %s now"
 msgstr "Uruchom wersjÄ™ %s"
 
-#: ../contrib/packagekit-plugin/src/contents.cpp:324
+#: ../contrib/browser-plugin/src/contents.cpp:324
 msgid "Run now"
 msgstr "Uruchom teraz"
 
 #. TRANSLATORS: update to a new version of the package
-#: ../contrib/packagekit-plugin/src/contents.cpp:330
+#: ../contrib/browser-plugin/src/contents.cpp:330
 #, c-format
 msgid "Update to version %s"
 msgstr "Zaktualizuj do wersji %s"
 
 #. TRANSLATORS: To install a package
-#: ../contrib/packagekit-plugin/src/contents.cpp:336
+#: ../contrib/browser-plugin/src/contents.cpp:336
 #, c-format
 msgid "Install %s now"
 msgstr "Zainstaluj %s"
 
 #. TRANSLATORS: the version of the package
-#: ../contrib/packagekit-plugin/src/contents.cpp:339
+#: ../contrib/browser-plugin/src/contents.cpp:339
 msgid "Version"
 msgstr "Wersja"
 
 #. TRANSLATORS: noting found, so can't install
-#: ../contrib/packagekit-plugin/src/contents.cpp:344
+#: ../contrib/browser-plugin/src/contents.cpp:344
 msgid "No packages found for your system"
 msgstr "Nie znaleziono pakietów dla systemu"
 
 #. TRANSLATORS: package is being installed
-#: ../contrib/packagekit-plugin/src/contents.cpp:349
+#: ../contrib/browser-plugin/src/contents.cpp:349
 msgid "Installing..."
 msgstr "Instalowanie..."
 
@@ -584,14 +817,14 @@ msgstr "Instalowanie..."
 msgid "PackageKit Catalog"
 msgstr "Katalog PackageKit"
 
-#: ../data/packagekit-servicepack.xml.in.h:1
-msgid "PackageKit Service Pack"
-msgstr "Pakiet serwisowy PackageKit"
-
 #: ../data/packagekit-package-list.xml.in.h:1
 msgid "PackageKit Package List"
 msgstr "Lista pakietów PackageKit"
 
+#: ../data/packagekit-servicepack.xml.in.h:1
+msgid "PackageKit Service Pack"
+msgstr "Pakiet serwisowy PackageKit"
+
 #: ../policy/org.freedesktop.packagekit.policy.in.h:1
 msgid "Accept EULA"
 msgstr "Akceptacja licencji"
commit 8da0653c47ec86a46af442cda6e1e77e3c7778c3
Author: Richard Hughes <richard at hughsie.com>
Date:   Tue Dec 16 18:55:51 2008 +0000

    yum: print the full exception in the internal error case, else it's useful to no-one...

diff --git a/backends/yum/yumBackend.py b/backends/yum/yumBackend.py
index 49a2514..592057f 100755
--- a/backends/yum/yumBackend.py
+++ b/backends/yum/yumBackend.py
@@ -299,7 +299,7 @@ class PackageKitYumBackend(PackageKitBaseBackend, PackagekitPackage):
                 self.yumbase.closeRpmDB()
                 self.yumbase.doUnlock(YUM_PID_FILE)
             except Exception, e:
-                self.error(ERROR_INTERNAL_ERROR, _to_unicode(e))
+                self.error(ERROR_INTERNAL_ERROR, _format_str(traceback.format_exc()))
 
     def _do_meta_package_search(self, fltlist, key):
         grps = self.comps.get_meta_packages()
@@ -343,7 +343,7 @@ class PackageKitYumBackend(PackageKitBaseBackend, PackagekitPackage):
             except yum.Errors.RepoError, e:
                 self.error(ERROR_NO_CACHE, _to_unicode(e))
             except Exception, e:
-                self.error(ERROR_INTERNAL_ERROR, _to_unicode(e))
+                self.error(ERROR_INTERNAL_ERROR, _format_str(traceback.format_exc()))
             else:
                 pkgfilter.add_installed(installed)
                 pkgfilter.add_available(available)
@@ -370,7 +370,7 @@ class PackageKitYumBackend(PackageKitBaseBackend, PackagekitPackage):
         try:
             self.yumbase.doConfigSetup(errorlevel=0, debuglevel=0)# Setup Yum Config
         except Exception, e:
-            self.error(ERROR_INTERNAL_ERROR, _to_unicode(e))
+            self.error(ERROR_INTERNAL_ERROR, _format_str(traceback.format_exc()))
         self._do_search(searchlist, filters, key)
 
     def search_details(self, filters, key):
@@ -381,7 +381,7 @@ class PackageKitYumBackend(PackageKitBaseBackend, PackagekitPackage):
         try:
             self.yumbase.doConfigSetup(errorlevel=0, debuglevel=0)# Setup Yum Config
         except Exception, e:
-            self.error(ERROR_INTERNAL_ERROR, _to_unicode(e))
+            self.error(ERROR_INTERNAL_ERROR, _format_str(traceback.format_exc()))
         self.yumbase.conf.cache = 0 # Allow new files
         self.allow_cancel(True)
         self.percentage(None)
@@ -396,7 +396,7 @@ class PackageKitYumBackend(PackageKitBaseBackend, PackagekitPackage):
             try:
                 pkgs = self.yumbase.rpmdb.searchNevra(name=package)
             except Exception, e:
-                self.error(ERROR_INTERNAL_ERROR, _to_unicode(e))
+                self.error(ERROR_INTERNAL_ERROR, _format_str(traceback.format_exc()))
             found.extend(pkgs)
         return found
 
@@ -407,7 +407,7 @@ class PackageKitYumBackend(PackageKitBaseBackend, PackagekitPackage):
         except yum.Errors.RepoError, e:
             self.error(ERROR_NO_CACHE, _to_unicode(e))
         except Exception, e:
-            self.error(ERROR_INTERNAL_ERROR, _to_unicode(e))
+            self.error(ERROR_INTERNAL_ERROR, _format_str(traceback.format_exc()))
         return pkgs
 
     def _handle_newest(self, fltlist):
@@ -423,7 +423,7 @@ class PackageKitYumBackend(PackageKitBaseBackend, PackagekitPackage):
         except yum.Errors.RepoError, e:
             self.error(ERROR_REPO_NOT_AVAILABLE, _to_unicode(e))
         except Exception, e:
-            self.error(ERROR_INTERNAL_ERROR, _to_unicode(e))
+            self.error(ERROR_INTERNAL_ERROR, _format_str(traceback.format_exc()))
 
         installed = []
         available = []
@@ -431,7 +431,7 @@ class PackageKitYumBackend(PackageKitBaseBackend, PackagekitPackage):
             try:
                 instpo = self.yumbase.rpmdb.searchNevra(name=pkg.name, epoch=pkg.epoch, ver=pkg.ver, rel=pkg.rel, arch=pkg.arch)
             except Exception, e:
-                self.error(ERROR_INTERNAL_ERROR, _to_unicode(e))
+                self.error(ERROR_INTERNAL_ERROR, _format_str(traceback.format_exc()))
             if len(instpo) > 0:
                 installed.append(instpo[0])
             else:
@@ -476,7 +476,7 @@ class PackageKitYumBackend(PackageKitBaseBackend, PackagekitPackage):
         except yum.Errors.GroupsError, e:
             self.error(ERROR_GROUP_NOT_FOUND, _to_unicode(e))
         except Exception, e:
-            self.error(ERROR_INTERNAL_ERROR, _to_unicode(e))
+            self.error(ERROR_INTERNAL_ERROR, _format_str(traceback.format_exc()))
         else:
             if grp:
                 name = grp.nameByLang(self.lang)
@@ -496,7 +496,7 @@ class PackageKitYumBackend(PackageKitBaseBackend, PackagekitPackage):
         try:
             self.yumbase.doConfigSetup(errorlevel=0, debuglevel=0)# Setup Yum Config
         except Exception, e:
-            self.error(ERROR_INTERNAL_ERROR, _to_unicode(e))
+            self.error(ERROR_INTERNAL_ERROR, _format_str(traceback.format_exc()))
         self.yumbase.conf.cache = 0 # TODO: can we just look in the cache?
         self.status(STATUS_QUERY)
         package_list = [] #we can't do emitting as found if we are post-processing
@@ -555,7 +555,7 @@ class PackageKitYumBackend(PackageKitBaseBackend, PackagekitPackage):
         try:
             self.yumbase.doConfigSetup(errorlevel=0, debuglevel=0)# Setup Yum Config
         except Exception, e:
-            self.error(ERROR_INTERNAL_ERROR, _to_unicode(e))
+            self.error(ERROR_INTERNAL_ERROR, _format_str(traceback.format_exc()))
         self.yumbase.conf.cache = 0 # TODO: can we just look in the cache?
 
         package_list = [] #we can't do emitting as found if we are post-processing
@@ -566,7 +566,7 @@ class PackageKitYumBackend(PackageKitBaseBackend, PackagekitPackage):
         try:
             pkgs = self.yumbase.rpmdb
         except Exception, e:
-            self.error(ERROR_INTERNAL_ERROR, _to_unicode(e))
+            self.error(ERROR_INTERNAL_ERROR, _format_str(traceback.format_exc()))
         pkgfilter.add_installed(pkgs)
 
         # Now show available packages.
@@ -576,7 +576,7 @@ class PackageKitYumBackend(PackageKitBaseBackend, PackagekitPackage):
             except yum.Errors.RepoError, e:
                 self.error(ERROR_NO_CACHE, _to_unicode(e))
             except Exception, e:
-                self.error(ERROR_INTERNAL_ERROR, _to_unicode(e))
+                self.error(ERROR_INTERNAL_ERROR, _format_str(traceback.format_exc()))
             else:
                 pkgfilter.add_available(pkgs)
 
@@ -602,7 +602,7 @@ class PackageKitYumBackend(PackageKitBaseBackend, PackagekitPackage):
         try:
             pkgs = self.yumbase.rpmdb.searchFiles(key)
         except Exception, e:
-            self.error(ERROR_INTERNAL_ERROR, _to_unicode(e))
+            self.error(ERROR_INTERNAL_ERROR, _format_str(traceback.format_exc()))
         pkgfilter.add_installed(pkgs)
 
         # Check available for file
@@ -614,7 +614,7 @@ class PackageKitYumBackend(PackageKitBaseBackend, PackagekitPackage):
             except yum.Errors.RepoError, e:
                 self.error(ERROR_NO_CACHE, _to_unicode(e))
             except Exception, e:
-                self.error(ERROR_INTERNAL_ERROR, _to_unicode(e))
+                self.error(ERROR_INTERNAL_ERROR, _format_str(traceback.format_exc()))
             else:
                 pkgfilter.add_available(pkgs)
 
@@ -639,7 +639,7 @@ class PackageKitYumBackend(PackageKitBaseBackend, PackagekitPackage):
         try:
             pkgs = self.yumbase.rpmdb.searchProvides(search)
         except Exception, e:
-            self.error(ERROR_INTERNAL_ERROR, _to_unicode(e))
+            self.error(ERROR_INTERNAL_ERROR, _format_str(traceback.format_exc()))
         pkgfilter.add_installed(pkgs)
 
         if not FILTER_INSTALLED in fltlist:
@@ -649,7 +649,7 @@ class PackageKitYumBackend(PackageKitBaseBackend, PackagekitPackage):
             except yum.Errors.RepoError, e:
                 self.error(ERROR_NO_CACHE, _to_unicode(e))
             except Exception, e:
-                self.error(ERROR_INTERNAL_ERROR, _to_unicode(e))
+                self.error(ERROR_INTERNAL_ERROR, _format_str(traceback.format_exc()))
             else:
                 pkgfilter.add_available(pkgs)
 
@@ -669,7 +669,7 @@ class PackageKitYumBackend(PackageKitBaseBackend, PackagekitPackage):
         except yum.Errors.RepoError, e:
             self.error(ERROR_NO_CACHE, _to_unicode(e))
         except Exception, e:
-            self.error(ERROR_INTERNAL_ERROR, _to_unicode(e))
+            self.error(ERROR_INTERNAL_ERROR, _format_str(traceback.format_exc()))
 
         if len(cats) == 0:
             self.error(ERROR_GROUP_LIST_INVALID, "no comps categories")
@@ -704,7 +704,7 @@ class PackageKitYumBackend(PackageKitBaseBackend, PackagekitPackage):
                 try:
                     grp = self.yumbase.comps.return_group(grp_id)
                 except Exception, e:
-                    self.error(ERROR_INTERNAL_ERROR, _to_unicode(e))
+                    self.error(ERROR_INTERNAL_ERROR, _format_str(traceback.format_exc()))
                 if grp:
                     grps.append(grp)
             for grp in sorted(grps):
@@ -749,7 +749,7 @@ class PackageKitYumBackend(PackageKitBaseBackend, PackagekitPackage):
             except yum.Errors.RepoError, e:
                 self.error(ERROR_NO_CACHE, _to_unicode(e))
             except Exception, e:
-                self.error(ERROR_INTERNAL_ERROR, _to_unicode(e))
+                self.error(ERROR_INTERNAL_ERROR, _format_str(traceback.format_exc()))
 
             # if we couldn't map package_id -> pkg
             if len(packs) == 0:
@@ -762,7 +762,7 @@ class PackageKitYumBackend(PackageKitBaseBackend, PackagekitPackage):
                 try:
                     repo = self.yumbase.repos.getRepo(pkg_download.repoid)
                 except Exception, e:
-                    self.error(ERROR_INTERNAL_ERROR, _to_unicode(e))
+                    self.error(ERROR_INTERNAL_ERROR, _format_str(traceback.format_exc()))
                 remote = pkg_download.returnSimple('relativepath')
                 local = os.path.basename(remote)
                 if not os.path.exists(directory):
@@ -799,13 +799,13 @@ class PackageKitYumBackend(PackageKitBaseBackend, PackagekitPackage):
                 try:
                     grp = self.yumbase.comps.return_group(name)
                 except Exception, e:
-                    self.error(ERROR_INTERNAL_ERROR, _to_unicode(e))
+                    self.error(ERROR_INTERNAL_ERROR, _format_str(traceback.format_exc()))
                 isGroup = True
             elif name[0] == '@':
                 try:
                     grp = self.yumbase.comps.return_group(name[1:])
                 except Exception, e:
-                    self.error(ERROR_INTERNAL_ERROR, _to_unicode(e))
+                    self.error(ERROR_INTERNAL_ERROR, _format_str(traceback.format_exc()))
                 isGroup = True
             if isGroup and not grp:
                 self.error(ERROR_PACKAGE_NOT_FOUND, "The Group %s dont exist" % name)
@@ -832,7 +832,7 @@ class PackageKitYumBackend(PackageKitBaseBackend, PackagekitPackage):
         try:
             pkgs = self.yumbase.rpmdb.searchNevra(name=n, epoch=e, ver=v, rel=r, arch=a)
         except Exception, e:
-            self.error(ERROR_INTERNAL_ERROR, _to_unicode(e))
+            self.error(ERROR_INTERNAL_ERROR, _format_str(traceback.format_exc()))
         # if the package is found, then return it (do not have to match the repo_id)
         if len(pkgs) != 0:
             return pkgs[0], True
@@ -842,7 +842,7 @@ class PackageKitYumBackend(PackageKitBaseBackend, PackagekitPackage):
         except yum.Errors.RepoError, e:
             self.error(ERROR_REPO_NOT_AVAILABLE, _to_unicode(e))
         except Exception, e:
-            self.error(ERROR_INTERNAL_ERROR, _to_unicode(e))
+            self.error(ERROR_INTERNAL_ERROR, _format_str(traceback.format_exc()))
 
         # nothing found
         if len(pkgs) == 0:
@@ -883,7 +883,7 @@ class PackageKitYumBackend(PackageKitBaseBackend, PackagekitPackage):
                     try:
                         txmbrs = self.yumbase.groupRemove(grp.groupid)
                     except Exception, e:
-                        self.error(ERROR_INTERNAL_ERROR, _to_unicode(e))
+                        self.error(ERROR_INTERNAL_ERROR, _format_str(traceback.format_exc()))
                     for txmbr in self.yumbase.tsInfo:
                         deps_list.append(txmbr.po)
             else:
@@ -894,7 +894,7 @@ class PackageKitYumBackend(PackageKitBaseBackend, PackagekitPackage):
                     try:
                         txmbrs = self.yumbase.remove(po=pkg)
                     except Exception, e:
-                        self.error(ERROR_INTERNAL_ERROR, _to_unicode(e))
+                        self.error(ERROR_INTERNAL_ERROR, _format_str(traceback.format_exc()))
             percentage += bump
 
         # do the depsolve to pull in deps
@@ -902,7 +902,7 @@ class PackageKitYumBackend(PackageKitBaseBackend, PackagekitPackage):
             try:
                 rc, msgs =  self.yumbase.buildTransaction()
             except Exception, e:
-                self.error(ERROR_INTERNAL_ERROR, _to_unicode(e))
+                self.error(ERROR_INTERNAL_ERROR, _format_str(traceback.format_exc()))
             if rc != 2:
                 self.error(ERROR_DEP_RESOLUTION_FAILED, _format_msgs(msgs))
             else:
@@ -926,7 +926,7 @@ class PackageKitYumBackend(PackageKitBaseBackend, PackagekitPackage):
         try:
             ret = self.yumbase.rpmdb.installed(po=pkg)
         except Exception, e:
-            self.error(ERROR_INTERNAL_ERROR, _to_unicode(e))
+            self.error(ERROR_INTERNAL_ERROR, _format_str(traceback.format_exc()))
         return ret
 
     def _is_inst_arch(self, pkg):
@@ -949,7 +949,7 @@ class PackageKitYumBackend(PackageKitBaseBackend, PackagekitPackage):
         try:
             exactarchlist = self.yumbase.conf.exactarchlist
         except Exception, e:
-            self.error(ERROR_INTERNAL_ERROR, _to_unicode(e))
+            self.error(ERROR_INTERNAL_ERROR, _format_str(traceback.format_exc()))
         # we look through each returned possibility and rule out the
         # ones that we obviously can't use
 
@@ -960,7 +960,7 @@ class PackageKitYumBackend(PackageKitBaseBackend, PackagekitPackage):
         try:
             installedByKey = self.yumbase.rpmdb.searchNevra(name=pkg.name, arch=pkg.arch)
         except Exception, e:
-            self.error(ERROR_INTERNAL_ERROR, _to_unicode(e))
+            self.error(ERROR_INTERNAL_ERROR, _format_str(traceback.format_exc()))
         comparable = []
         for instpo in installedByKey:
             if rpmUtils.arch.isMultiLibArch(instpo.arch) == rpmUtils.arch.isMultiLibArch(pkg.arch):
@@ -991,7 +991,7 @@ class PackageKitYumBackend(PackageKitBaseBackend, PackagekitPackage):
                         try:
                             ret = self.yumbase.allowedMultipleInstalls(pkg)
                         except Exception, e:
-                            self.error(ERROR_INTERNAL_ERROR, _to_unicode(e))
+                            self.error(ERROR_INTERNAL_ERROR, _format_str(traceback.format_exc()))
                         if ret:
                             return True
 
@@ -1012,7 +1012,7 @@ class PackageKitYumBackend(PackageKitBaseBackend, PackagekitPackage):
             try:
                 pkgs = self.yumbase.rpmdb.searchNevra(name=n, epoch=e, ver=v, arch=a)
             except Exception, e:
-                self.error(ERROR_INTERNAL_ERROR, _to_unicode(e))
+                self.error(ERROR_INTERNAL_ERROR, _format_str(traceback.format_exc()))
             for pkg in pkgs:
                 if best:
                     if pkg.EVR > best.EVR:
@@ -1042,7 +1042,7 @@ class PackageKitYumBackend(PackageKitBaseBackend, PackagekitPackage):
         try:
             results = self.yumbase.findDeps(pkgs)
         except Exception, e:
-            self.error(ERROR_INTERNAL_ERROR, _to_unicode(e))
+            self.error(ERROR_INTERNAL_ERROR, _format_str(traceback.format_exc()))
         require_list = []
         recursive_list = []
 
@@ -1081,12 +1081,12 @@ class PackageKitYumBackend(PackageKitBaseBackend, PackagekitPackage):
             try:
                 txmbrs = self.yumbase.selectGroup(grp.groupid)
             except Exception, e:
-                self.error(ERROR_INTERNAL_ERROR, _to_unicode(e))
+                self.error(ERROR_INTERNAL_ERROR, _format_str(traceback.format_exc()))
         else:
             try:
                 txmbrs = self.yumbase.groupRemove(grp.groupid)
             except Exception, e:
-                self.error(ERROR_INTERNAL_ERROR, _to_unicode(e))
+                self.error(ERROR_INTERNAL_ERROR, _format_str(traceback.format_exc()))
         pkgs = []
         for t in txmbrs:
             pkgs.append(t.po)
@@ -1094,12 +1094,12 @@ class PackageKitYumBackend(PackageKitBaseBackend, PackagekitPackage):
             try:
                 self.yumbase.deselectGroup(grp.groupid)
             except Exception, e:
-                self.error(ERROR_INTERNAL_ERROR, _to_unicode(e))
+                self.error(ERROR_INTERNAL_ERROR, _format_str(traceback.format_exc()))
         else:
             try:
                 self.yumbase.groupUnremove(grp.groupid)
             except Exception, e:
-                self.error(ERROR_INTERNAL_ERROR, _to_unicode(e))
+                self.error(ERROR_INTERNAL_ERROR, _format_str(traceback.format_exc()))
         return pkgs
 
     def _get_depends_not_installed(self, fltlist, package_ids, recursive):
@@ -1123,7 +1123,7 @@ class PackageKitYumBackend(PackageKitBaseBackend, PackagekitPackage):
                     try:
                         txmbrs = self.yumbase.selectGroup(grp.groupid)
                     except Exception, e:
-                        self.error(ERROR_INTERNAL_ERROR, _to_unicode(e))
+                        self.error(ERROR_INTERNAL_ERROR, _format_str(traceback.format_exc()))
                     for txmbr in self.yumbase.tsInfo:
                         deps_list.append(txmbr.po)
             else:
@@ -1134,14 +1134,14 @@ class PackageKitYumBackend(PackageKitBaseBackend, PackagekitPackage):
                     try:
                         txmbrs = self.yumbase.install(po=pkg)
                     except Exception, e:
-                        self.error(ERROR_INTERNAL_ERROR, _to_unicode(e))
+                        self.error(ERROR_INTERNAL_ERROR, _format_str(traceback.format_exc()))
             percentage += bump
 
         if len(self.yumbase.tsInfo) > 0 and recursive:
             try:
                 rc, msgs =  self.yumbase.buildTransaction()
             except Exception, e:
-                self.error(ERROR_INTERNAL_ERROR, _to_unicode(e))
+                self.error(ERROR_INTERNAL_ERROR, _format_str(traceback.format_exc()))
             if rc != 2:
                 self.error(ERROR_DEP_RESOLUTION_FAILED, _format_msgs(msgs))
             else:
@@ -1253,7 +1253,7 @@ class PackageKitYumBackend(PackageKitBaseBackend, PackagekitPackage):
         except yum.Errors.RepoError, e:
             self.error(ERROR_REPO_NOT_AVAILABLE, _to_unicode(e))
         except Exception, e:
-            self.error(ERROR_INTERNAL_ERROR, _to_unicode(e))
+            self.error(ERROR_INTERNAL_ERROR, _format_str(traceback.format_exc()))
         if txmbr:
             self._runYumTransaction(allow_skip_broken=True)
         else:
@@ -1296,7 +1296,7 @@ class PackageKitYumBackend(PackageKitBaseBackend, PackagekitPackage):
             try:
                 self.yumbase.doGroupSetup()
             except Exception, e:
-                self.error(ERROR_INTERNAL_ERROR, _to_unicode(e))
+                self.error(ERROR_INTERNAL_ERROR, _format_str(traceback.format_exc()))
             #we might have a rounding error
             self.percentage(100)
 
@@ -1309,7 +1309,7 @@ class PackageKitYumBackend(PackageKitBaseBackend, PackagekitPackage):
         except yum.Errors.YumBaseError, e:
             self.error(ERROR_UNKNOWN, "cannot refresh cache: %s" % _to_unicode(e))
         except Exception, e:
-            self.error(ERROR_INTERNAL_ERROR, _to_unicode(e))
+            self.error(ERROR_INTERNAL_ERROR, _format_str(traceback.format_exc()))
 
         # update the comps groups too
         self.comps.refresh()
@@ -1324,7 +1324,7 @@ class PackageKitYumBackend(PackageKitBaseBackend, PackagekitPackage):
         try:
             self.yumbase.doConfigSetup(errorlevel=0, debuglevel=0)# Setup Yum Config
         except Exception, e:
-            self.error(ERROR_INTERNAL_ERROR, _to_unicode(e))
+            self.error(ERROR_INTERNAL_ERROR, _format_str(traceback.format_exc()))
         self.yumbase.conf.cache = 0 # TODO: can we just look in the cache?
         self.status(STATUS_QUERY)
 
@@ -1334,7 +1334,7 @@ class PackageKitYumBackend(PackageKitBaseBackend, PackagekitPackage):
             try:
                 installedByKey = self.yumbase.rpmdb.searchNevra(name=package)
             except Exception, e:
-                self.error(ERROR_INTERNAL_ERROR, _to_unicode(e))
+                self.error(ERROR_INTERNAL_ERROR, _format_str(traceback.format_exc()))
             if FILTER_NOT_INSTALLED not in fltlist:
                 for pkg in installedByKey:
                     self._show_package(pkg, INFO_INSTALLED)
@@ -1345,7 +1345,7 @@ class PackageKitYumBackend(PackageKitBaseBackend, PackagekitPackage):
                 except yum.Errors.RepoError, e:
                     self.error(ERROR_NO_CACHE, _to_unicode(e))
                 except Exception, e:
-                    self.error(ERROR_INTERNAL_ERROR, _to_unicode(e))
+                    self.error(ERROR_INTERNAL_ERROR, _format_str(traceback.format_exc()))
                 else:
                     for pkg in pkgs:
                         if pkg.name == package:
@@ -1377,12 +1377,12 @@ class PackageKitYumBackend(PackageKitBaseBackend, PackagekitPackage):
                 try:
                     txmbr = self.yumbase.selectGroup(grp.groupid)
                 except Exception, e:
-                    self.error(ERROR_INTERNAL_ERROR, _to_unicode(e))
+                    self.error(ERROR_INTERNAL_ERROR, _format_str(traceback.format_exc()))
                 for t in txmbr:
                     try:
                         repo = self.yumbase.repos.getRepo(t.po.repoid)
                     except Exception, e:
-                        self.error(ERROR_INTERNAL_ERROR, _to_unicode(e))
+                        self.error(ERROR_INTERNAL_ERROR, _format_str(traceback.format_exc()))
                     if not already_warned and not repo.gpgcheck:
                         self.message(MESSAGE_UNTRUSTED_PACKAGE, "The untrusted package %s will be installed from %s." % (t.po.name, repo))
                         already_warned = True
@@ -1408,7 +1408,7 @@ class PackageKitYumBackend(PackageKitBaseBackend, PackagekitPackage):
         try:
             pkgs = self.yumbase.pkgSack.returnNewestByName(name=po.name)
         except Exception, e:
-            self.error(ERROR_INTERNAL_ERROR, _to_unicode(e))
+            self.error(ERROR_INTERNAL_ERROR, _format_str(traceback.format_exc()))
         if pkgs:
             newest = pkgs[0]
             if newest.EVR > po.EVR:
@@ -1529,13 +1529,13 @@ class PackageKitYumBackend(PackageKitBaseBackend, PackagekitPackage):
                 except yum.Errors.MiscError:
                     self.error(ERROR_INVALID_PACKAGE_FILE, "%s does not appear to be a valid package." % inst_file)
                 except Exception, e:
-                    self.error(ERROR_INTERNAL_ERROR, _to_unicode(e))
+                    self.error(ERROR_INTERNAL_ERROR, _format_str(traceback.format_exc()))
                 try:
                     self.yumbase._checkSignatures([po], None)
                 except yum.Errors.YumGPGCheckError, e:
                     self.error(ERROR_MISSING_GPG_SIGNATURE, _to_unicode(e))
                 except Exception, e:
-                    self.error(ERROR_INTERNAL_ERROR, _to_unicode(e))
+                    self.error(ERROR_INTERNAL_ERROR, _format_str(traceback.format_exc()))
         else:
             self.yumbase.conf.gpgcheck = 0
 
@@ -1550,7 +1550,7 @@ class PackageKitYumBackend(PackageKitBaseBackend, PackagekitPackage):
                 try:
                     txmbr = self.yumbase.installLocal(inst_file)
                 except Exception, e:
-                    self.error(ERROR_INTERNAL_ERROR, _to_unicode(e))
+                    self.error(ERROR_INTERNAL_ERROR, _format_str(traceback.format_exc()))
                 if txmbr:
                     txmbrs.extend(txmbr)
                     self._checkForNewer(txmbr[0].po)
@@ -1575,7 +1575,7 @@ class PackageKitYumBackend(PackageKitBaseBackend, PackagekitPackage):
                     try:
                         txmbr = self.yumbase.installLocal(inst_file)
                     except Exception, e:
-                        self.error(ERROR_INTERNAL_ERROR, _to_unicode(e))
+                        self.error(ERROR_INTERNAL_ERROR, _format_str(traceback.format_exc()))
                     if txmbr:
                         txmbrs.extend(txmbr)
                         if len(self.yumbase.tsInfo) > 0:
@@ -1587,7 +1587,7 @@ class PackageKitYumBackend(PackageKitBaseBackend, PackagekitPackage):
             except yum.Errors.InstallError, e:
                 self.error(ERROR_LOCAL_INSTALL_FAILED, _to_unicode(e))
             except Exception, e:
-                self.error(ERROR_INTERNAL_ERROR, _to_unicode(e))
+                self.error(ERROR_INTERNAL_ERROR, _format_str(traceback.format_exc()))
         shutil.rmtree(tempdir)
 
     def _check_local_file(self, pkg):
@@ -1602,7 +1602,7 @@ class PackageKitYumBackend(PackageKitBaseBackend, PackagekitPackage):
             self.error(ERROR_INVALID_PACKAGE_FILE, "%s does not appear to be a valid package." % pkg)
             return False
         except Exception, e:
-            self.error(ERROR_INTERNAL_ERROR, _to_unicode(e))
+            self.error(ERROR_INTERNAL_ERROR, _format_str(traceback.format_exc()))
             return False
 
         # check if wrong arch
@@ -1643,12 +1643,12 @@ class PackageKitYumBackend(PackageKitBaseBackend, PackagekitPackage):
                     try:
                         txmbr = self.yumbase.update(po=pkg)
                     except Exception, e:
-                        self.error(ERROR_INTERNAL_ERROR, _to_unicode(e))
+                        self.error(ERROR_INTERNAL_ERROR, _format_str(traceback.format_exc()))
                     txmbrs.extend(txmbr)
         except yum.Errors.RepoError, e:
             self.error(ERROR_REPO_NOT_AVAILABLE, _to_unicode(e))
         except Exception, e:
-            self.error(ERROR_INTERNAL_ERROR, _to_unicode(e))
+            self.error(ERROR_INTERNAL_ERROR, _format_str(traceback.format_exc()))
         if txmbrs:
             self._runYumTransaction(allow_skip_broken=True)
         else:
@@ -1680,7 +1680,7 @@ class PackageKitYumBackend(PackageKitBaseBackend, PackagekitPackage):
         except yum.Errors.RepoError, e:
             self.error(ERROR_REPO_NOT_AVAILABLE, _to_unicode(e))
         except Exception, e:
-            self.error(ERROR_INTERNAL_ERROR, _to_unicode(e))
+            self.error(ERROR_INTERNAL_ERROR, _format_str(traceback.format_exc()))
 
         # if return value is 1 (error), try again with skip-broken if allowed
         if allow_skip_broken and rc == 1:
@@ -1691,7 +1691,7 @@ class PackageKitYumBackend(PackageKitBaseBackend, PackagekitPackage):
             except yum.Errors.RepoError, e:
                 self.error(ERROR_REPO_NOT_AVAILABLE, _to_unicode(e))
             except Exception, e:
-                self.error(ERROR_INTERNAL_ERROR, _to_unicode(e))
+                self.error(ERROR_INTERNAL_ERROR, _format_str(traceback.format_exc()))
 
         # we did not succeed
         if rc != 2:
@@ -1746,7 +1746,7 @@ class PackageKitYumBackend(PackageKitBaseBackend, PackagekitPackage):
                 else:
                     self.error(ERROR_TRANSACTION_ERROR, message)
             except Exception, e:
-                self.error(ERROR_INTERNAL_ERROR, _to_unicode(e))
+                self.error(ERROR_INTERNAL_ERROR, _format_str(traceback.format_exc()))
 
     def remove_packages(self, allowdep, package_ids):
         '''
@@ -1768,7 +1768,7 @@ class PackageKitYumBackend(PackageKitBaseBackend, PackagekitPackage):
                 try:
                     txmbr = self.yumbase.groupRemove(grp.groupid)
                 except Exception, e:
-                    self.error(ERROR_INTERNAL_ERROR, _to_unicode(e))
+                    self.error(ERROR_INTERNAL_ERROR, _format_str(traceback.format_exc()))
                 txmbrs.extend(txmbr)
             else:
                 pkg, inst = self._findPackage(package)
@@ -1776,7 +1776,7 @@ class PackageKitYumBackend(PackageKitBaseBackend, PackagekitPackage):
                     try:
                         txmbr = self.yumbase.remove(po=pkg)
                     except Exception, e:
-                        self.error(ERROR_INTERNAL_ERROR, _to_unicode(e))
+                        self.error(ERROR_INTERNAL_ERROR, _format_str(traceback.format_exc()))
                     txmbrs.extend(txmbr)
                 if pkg and not inst:
                     self.error(ERROR_PACKAGE_NOT_INSTALLED, "The package %s is not installed" % pkg.name)
@@ -1877,7 +1877,7 @@ class PackageKitYumBackend(PackageKitBaseBackend, PackagekitPackage):
         try:
             pkgs = self.yumbase.rpmdb.searchNevra(name='preupgrade')
         except Exception, e:
-            self.error(ERROR_INTERNAL_ERROR, _to_unicode(e))
+            self.error(ERROR_INTERNAL_ERROR, _format_str(traceback.format_exc()))
         if len(pkgs) == 0:
 
             # find preupgrade, which may not exist
@@ -1887,7 +1887,7 @@ class PackageKitYumBackend(PackageKitBaseBackend, PackagekitPackage):
                 self.error(ERROR_NO_DISTRO_UPGRADE_DATA, "Could not find preupgrade package in any enabled repos")
                 return
             except Exception, e:
-                self.error(ERROR_INTERNAL_ERROR, _to_unicode(e))
+                self.error(ERROR_INTERNAL_ERROR, _format_str(traceback.format_exc()))
                 return
 
             # shouldn't happen
@@ -1901,7 +1901,7 @@ class PackageKitYumBackend(PackageKitBaseBackend, PackagekitPackage):
             try:
                 txmbr = self.yumbase.install(po=pkgs[0])
             except Exception, e:
-                self.error(ERROR_INTERNAL_ERROR, _to_unicode(e))
+                self.error(ERROR_INTERNAL_ERROR, _format_str(traceback.format_exc()))
             if txmbr:
                 self._runYumTransaction()
             else:
@@ -1918,7 +1918,7 @@ class PackageKitYumBackend(PackageKitBaseBackend, PackagekitPackage):
                 # could not find upgraded preupgrade package in any enabled repos
                 pass
             except Exception, e:
-                self.error(ERROR_INTERNAL_ERROR, _to_unicode(e))
+                self.error(ERROR_INTERNAL_ERROR, _format_str(traceback.format_exc()))
             else:
                 if pkgs:
                     newest = pkgs[0]
@@ -1927,7 +1927,7 @@ class PackageKitYumBackend(PackageKitBaseBackend, PackagekitPackage):
                         try:
                             txmbr = self.yumbase.update(po=pkgs[0])
                         except Exception, e:
-                            self.error(ERROR_INTERNAL_ERROR, _to_unicode(e))
+                            self.error(ERROR_INTERNAL_ERROR, _format_str(traceback.format_exc()))
                         if txmbr:
                             self._runYumTransaction()
         else:
@@ -1956,7 +1956,7 @@ class PackageKitYumBackend(PackageKitBaseBackend, PackagekitPackage):
         try:
             present_version = self.yumbase.conf.yumvar['releasever']
         except Exception, e:
-            self.error(ERROR_INTERNAL_ERROR, _to_unicode(e))
+            self.error(ERROR_INTERNAL_ERROR, _format_str(traceback.format_exc()))
         if (present_version >= last_version):
             return
 
@@ -1994,7 +1994,7 @@ class PackageKitYumBackend(PackageKitBaseBackend, PackagekitPackage):
         except yum.Errors.RepoError, e:
             self.error(ERROR_REPO_NOT_AVAILABLE, _to_unicode(e))
         except Exception, e:
-            self.error(ERROR_INTERNAL_ERROR, _to_unicode(e))
+            self.error(ERROR_INTERNAL_ERROR, _format_str(traceback.format_exc()))
         md = self.updateMetadata
         for pkg in pkgs:
             if pkgfilter.pre_process(pkg):
@@ -2028,7 +2028,7 @@ class PackageKitYumBackend(PackageKitBaseBackend, PackagekitPackage):
         except yum.Errors.RepoError, e:
             self.error(ERROR_REPO_NOT_FOUND, _to_unicode(e))
         except Exception, e:
-            self.error(ERROR_INTERNAL_ERROR, _to_unicode(e))
+            self.error(ERROR_INTERNAL_ERROR, _format_str(traceback.format_exc()))
 
     def get_repo_list(self, filters):
         '''
@@ -2041,7 +2041,7 @@ class PackageKitYumBackend(PackageKitBaseBackend, PackagekitPackage):
         try:
             repos = self.yumbase.repos.repos.values()
         except Exception, e:
-            self.error(ERROR_INTERNAL_ERROR, _to_unicode(e))
+            self.error(ERROR_INTERNAL_ERROR, _format_str(traceback.format_exc()))
             return
         for repo in repos:
             if filters != FILTER_NOT_DEVELOPMENT or not _is_development_repo(repo.id):
@@ -2067,7 +2067,7 @@ class PackageKitYumBackend(PackageKitBaseBackend, PackagekitPackage):
         try:
             pkgs = self.yumbase.rpmdb.searchNevra(name=pkg.name, arch=pkg.arch)
         except Exception, e:
-            self.error(ERROR_INTERNAL_ERROR, _to_unicode(e))
+            self.error(ERROR_INTERNAL_ERROR, _format_str(traceback.format_exc()))
         if pkgs:
             return self._pkg_to_id(pkgs[0])
         else:
@@ -2160,7 +2160,7 @@ class PackageKitYumBackend(PackageKitBaseBackend, PackagekitPackage):
         try:
             repo = self.yumbase.repos.getRepo(repoid)
         except Exception, e:
-            self.error(ERROR_INTERNAL_ERROR, _to_unicode(e))
+            self.error(ERROR_INTERNAL_ERROR, _format_str(traceback.format_exc()))
         if repo:
             repo.cfg.set(repoid, parameter, value)
             try:
@@ -2195,7 +2195,7 @@ class PackageKitYumBackend(PackageKitBaseBackend, PackagekitPackage):
                 except yum.Errors.YumBaseError, e:
                     self.error(ERROR_UNKNOWN, "cannot install signature: %s" % str(e))
                 except Exception, e:
-                    self.error(ERROR_INTERNAL_ERROR, _to_unicode(e))
+                    self.error(ERROR_INTERNAL_ERROR, _format_str(traceback.format_exc()))
                 except:
                     self.error(ERROR_GPG_FAILURE, "Error importing GPG Key for %s" % pkg)
 
@@ -2228,7 +2228,7 @@ class PackageKitYumBackend(PackageKitBaseBackend, PackagekitPackage):
             except yum.Errors.RepoError, e:
                 self.error(ERROR_NO_CACHE, _to_unicode(e))
             except Exception, e:
-                self.error(ERROR_INTERNAL_ERROR, _to_unicode(e))
+                self.error(ERROR_INTERNAL_ERROR, _format_str(traceback.format_exc()))
 
     def _refresh_yum_cache(self):
         self.status(STATUS_REFRESH_CACHE)
@@ -2237,7 +2237,7 @@ class PackageKitYumBackend(PackageKitBaseBackend, PackagekitPackage):
         try:
             self.yumbase.repos.setCache(0)
         except Exception, e:
-            self.error(ERROR_INTERNAL_ERROR, _to_unicode(e))
+            self.error(ERROR_INTERNAL_ERROR, _format_str(traceback.format_exc()))
 
         try:
             self.yumbase.repos.populateSack(mdtype='metadata', cacheonly=1)
@@ -2246,20 +2246,20 @@ class PackageKitYumBackend(PackageKitBaseBackend, PackagekitPackage):
         except yum.Errors.RepoError, e:
             self.error(ERROR_REPO_NOT_AVAILABLE, _to_unicode(e))
         except Exception, e:
-            self.error(ERROR_INTERNAL_ERROR, _to_unicode(e))
+            self.error(ERROR_INTERNAL_ERROR, _format_str(traceback.format_exc()))
 
         self.yumbase.conf.cache = old_cache_setting
         try:
             self.yumbase.repos.setCache(old_cache_setting)
         except Exception, e:
-            self.error(ERROR_INTERNAL_ERROR, _to_unicode(e))
+            self.error(ERROR_INTERNAL_ERROR, _format_str(traceback.format_exc()))
 
     def _setup_yum(self):
         try:
             # setup Yum Config
             self.yumbase.doConfigSetup(errorlevel=-1, debuglevel=-1)
         except Exception, e:
-            self.error(ERROR_INTERNAL_ERROR, _to_unicode(e))
+            self.error(ERROR_INTERNAL_ERROR, _format_str(traceback.format_exc()))
 
         # set bandwidth throttle to 90%
         self.yumbase.conf.throttle = "90%"
@@ -2356,9 +2356,10 @@ class DownloadCallback(BaseMeter):
         pct_start = StatusPercentageMap[STATUS_DOWNLOAD]
         pct_end = StatusPercentageMap[STATUS_SIG_CHECK]
 
-        div = (pct_end - pct_start) / self.number_packages
-        pct = pct_start + (div * self.download_package_number) + ((div / 100.0) * val)
-        self.base.percentage(pct)
+        if self.number_packages > 0:
+            div = (pct_end - pct_start) / self.number_packages
+            pct = pct_start + (div * self.download_package_number) + ((div / 100.0) * val)
+            self.base.percentage(pct)
 
         # keep track of how many we downloaded
         if val == 100:
commit 424cac4883d5d98f19d0ec2f5241492eceb8a47a
Author: Richard Hughes <richard at hughsie.com>
Date:   Tue Dec 16 17:29:48 2008 +0000

    yum: emit more percentage signals so that the progress bar is smoother and the time estimation is more accurate

diff --git a/backends/yum/yumBackend.py b/backends/yum/yumBackend.py
index 3aeec02..49a2514 100755
--- a/backends/yum/yumBackend.py
+++ b/backends/yum/yumBackend.py
@@ -28,7 +28,7 @@ from packagekit.backend import *
 from packagekit.progress import *
 from packagekit.package import PackagekitPackage
 import yum
-from urlgrabber.progress import BaseMeter, format_time, format_number
+from urlgrabber.progress import BaseMeter, format_number
 from yum.rpmtrans import RPMBaseCallback
 from yum.constants import *
 from yum.update_md import UpdateMetadata
@@ -66,6 +66,15 @@ MetaDataMap = {
     'updateinfo'    : STATUS_DOWNLOAD_UPDATEINFO
 }
 
+StatusPercentageMap = {
+    STATUS_DEP_RESOLVE : 5,
+    STATUS_DOWNLOAD    : 10,
+    STATUS_SIG_CHECK   : 40,
+    STATUS_TEST_COMMIT : 45,
+    STATUS_INSTALL     : 55,
+    STATUS_CLEANUP     : 95
+}
+
 class GPGKeyNotImported(exceptions.Exception):
     pass
 
@@ -187,6 +196,8 @@ class PackageKitYumBackend(PackageKitBaseBackend, PackagekitPackage):
         PackageKitBaseBackend.__init__(self, args)
         self.yumbase = PackageKitYumBase(self)
         self.package_summary_cache = {}
+        self.percentage_old = 0
+        self.sub_percentage_old = 0
         self.comps = yumComps(self.yumbase)
         if not self.comps.connect():
             self.refresh_cache()
@@ -203,6 +214,22 @@ class PackageKitYumBackend(PackageKitBaseBackend, PackagekitPackage):
         if lock:
             self.doLock()
 
+    def percentage(self, percent=None):
+        '''
+        @param percent: Progress percentage
+        '''
+        if percent == 0 or percent > self.percentage_old:
+            PackageKitBaseBackend.percentage(self, percent)
+            self.percentage_old = percent
+
+    def sub_percentage(self, percent=None):
+        '''
+        @param percent: subprogress percentage
+        '''
+        if percent == 0 or percent > self.sub_percentage_old:
+            PackageKitBaseBackend.sub_percentage(self, percent)
+            self.sub_percentage_old = percent
+
     def details(self, package_id, package_license, group, desc, url, bytes):
         '''
         Send 'details' signal
@@ -2243,21 +2270,16 @@ class DownloadCallback(BaseMeter):
     """ Customized version of urlgrabber.progress.BaseMeter class """
     def __init__(self, base, showNames = False):
         BaseMeter.__init__(self)
-        self.totSize = ""
         self.base = base
-        self.showNames = showNames
-        self.oldName = None
-        self.lastPct = 0
-        self.totalPct = 0
+        self.percent_start = 0
         self.saved_pkgs = None
-        self.numPkgs = 0
-        self.bump = 0.0
+        self.number_packages = 0
+        self.download_package_number = 0
 
-    def setPackages(self, new_pkgs, startPct, numPct):
+    def setPackages(self, new_pkgs, percent_start, percent_length):
         self.saved_pkgs = new_pkgs
-        self.numPkgs = float(len(self.saved_pkgs))
-        self.bump = numPct/self.numPkgs
-        self.totalPct = startPct
+        self.number_packages = float(len(self.saved_pkgs))
+        self.percent_start = percent_start
 
     def _getPackage(self, name):
         if self.saved_pkgs:
@@ -2276,30 +2298,27 @@ class DownloadCallback(BaseMeter):
     def _do_start(self, now=None):
         name = self._getName()
         self.updateProgress(name, 0.0, "", "")
-        if not self.size is None:
-            self.totSize = format_number(self.size)
 
     def _do_update(self, amount_read, now=None):
+
         fread = format_number(amount_read)
         name = self._getName()
         if self.size is None:
             # Elapsed time
             etime = self.re.elapsed_time()
-            fetime = format_time(etime)
             frac = 0.0
-            self.updateProgress(name, frac, fread, fetime)
+            self.updateProgress(name, frac, fread, '')
         else:
             # Remaining time
             rtime = self.re.remaining_time()
-            frtime = format_time(rtime)
             frac = self.re.fraction_read()
-            self.updateProgress(name, frac, fread, frtime)
+            self.updateProgress(name, frac, fread, '')
 
     def _do_end(self, amount_read, now=None):
-        total_time = format_time(self.re.elapsed_time())
+
         total_size = format_number(amount_read)
         name = self._getName()
-        self.updateProgress(name, 1.0, total_size, total_time)
+        self.updateProgress(name, 1.0, total_size, '')
 
     def _getName(self):
         '''
@@ -2315,40 +2334,43 @@ class DownloadCallback(BaseMeter):
         @param fread: formated string containing BytesRead
         @param ftime: formated string containing remaining or elapsed time
         '''
-        pct = int(frac*100)
-        if name != self.oldName: # If this a new package
-            if self.oldName:
-                self.base.sub_percentage(100)
-            self.oldName = name
-            if self.bump > 0.0: # Bump the total download percentage
-                self.totalPct += self.bump
-                self.lastPct = 0
-                self.base.percentage(int(self.totalPct))
-            if self.showNames:
-                pkg = self._getPackage(name)
-                if pkg: # show package to download
-                    self.base._show_package(pkg, INFO_DOWNLOADING)
-                else:
-                    for key in MetaDataMap.keys():
-                        if key in name:
-                            typ = MetaDataMap[key]
-                            self.base.status(typ)
-                            break
-            self.base.sub_percentage(0)
-        else:
-            if self.lastPct != pct and pct != 0 and pct != 100:
-                self.lastPct = pct
-                # bump the sub persentage for this package
-                self.base.sub_percentage(pct)
+
+        val = int(frac*100)
+
+        # new package
+        if val == 0:
+            pkg = self._getPackage(name)
+            if pkg: # show package to download
+                self.base._show_package(pkg, INFO_DOWNLOADING)
+            else:
+                for key in MetaDataMap.keys():
+                    if key in name:
+                        typ = MetaDataMap[key]
+                        self.base.status(typ)
+                        break
+
+        # set sub-percentage
+        self.base.sub_percentage(val)
+
+        # refine percentage with subpercentage
+        pct_start = StatusPercentageMap[STATUS_DOWNLOAD]
+        pct_end = StatusPercentageMap[STATUS_SIG_CHECK]
+
+        div = (pct_end - pct_start) / self.number_packages
+        pct = pct_start + (div * self.download_package_number) + ((div / 100.0) * val)
+        self.base.percentage(pct)
+
+        # keep track of how many we downloaded
+        if val == 100:
+            self.download_package_number += 1
 
 class PackageKitCallback(RPMBaseCallback):
     def __init__(self, base):
         RPMBaseCallback.__init__(self)
         self.base = base
-        self.pct = 0
         self.curpkg = None
-        self.startPct = 50
-        self.numPct = 50
+        self.percent_start = 0
+        self.percent_length = 0
 
         # this isn't defined in yum as it's only used in the rollback plugin
         TS_REPACKAGING = 'repackaging'
@@ -2372,11 +2394,6 @@ class PackageKitCallback(RPMBaseCallback):
                         TS_UPDATED: STATUS_CLEANUP,
                         TS_REPACKAGING: STATUS_REPACKAGING}
 
-    def _calcTotalPct(self, ts_current, ts_total):
-        bump = float(self.numPct)/ts_total
-        pct = int(self.startPct + (ts_current * bump))
-        return pct
-
     def _showName(self, status):
         # curpkg is a yum package object or simple string of the package name
         if type(self.curpkg) in types.StringTypes:
@@ -2389,6 +2406,7 @@ class PackageKitCallback(RPMBaseCallback):
             self.base.package(package_id, status, self.curpkg.summary)
 
     def event(self, package, action, te_current, te_total, ts_current, ts_total):
+
         if str(package) != str(self.curpkg):
             self.curpkg = package
             try:
@@ -2396,12 +2414,18 @@ class PackageKitCallback(RPMBaseCallback):
                 self._showName(self.info_actions[action])
             except exceptions.KeyError, e:
                 self.base.message(MESSAGE_BACKEND_ERROR, "The constant '%s' was unknown, please report. details: %s" % (action, _to_unicode(e)))
-            pct = self._calcTotalPct(ts_current, ts_total)
-            self.base.percentage(pct)
-        val = (ts_current*100L)/ts_total
-        if val != self.pct:
-            self.pct = val
-            self.base.sub_percentage(val)
+
+        # do subpercentage
+        val = (te_current*100L)/te_total
+        self.base.sub_percentage(val)
+
+        # find out the offset
+        pct_start = StatusPercentageMap[STATUS_INSTALL]
+
+        # do percentage
+        div = (100 - pct_start) / ts_total
+        pct = div * (ts_current - 1) + pct_start + ((div / 100.0) * val)
+        self.base.percentage(pct)
 
     def errorlog(self, msg):
         # grrrrrrrr
@@ -2412,22 +2436,27 @@ class ProcessTransPackageKitCallback:
         self.base = base
 
     def event(self, state, data=None):
+
         if state == PT_DOWNLOAD:        # Start Downloading
             self.base.allow_cancel(True)
-            self.base.percentage(10)
+            pct_start = StatusPercentageMap[STATUS_DOWNLOAD]
+            self.base.percentage(pct_start)
             self.base.status(STATUS_DOWNLOAD)
         elif state == PT_DOWNLOAD_PKGS:   # Packages to download
             self.base.dnlCallback.setPackages(data, 10, 30)
         elif state == PT_GPGCHECK:
-            self.base.percentage(40)
+            pct_start = StatusPercentageMap[STATUS_SIG_CHECK]
+            self.base.percentage(pct_start)
             self.base.status(STATUS_SIG_CHECK)
         elif state == PT_TEST_TRANS:
+            pct_start = StatusPercentageMap[STATUS_TEST_COMMIT]
             self.base.allow_cancel(False)
-            self.base.percentage(45)
+            self.base.percentage(pct_start)
             self.base.status(STATUS_TEST_COMMIT)
         elif state == PT_TRANSACTION:
+            pct_start = StatusPercentageMap[STATUS_INSTALL]
             self.base.allow_cancel(False)
-            self.base.percentage(50)
+            self.base.percentage(pct_start)
 
 class DepSolveCallback(object):
 
@@ -2440,7 +2469,8 @@ class DepSolveCallback(object):
     def start(self):
         if not self.started:
             self.backend.status(STATUS_DEP_RESOLVE)
-            self.backend.percentage(None)
+            pct_start = StatusPercentageMap[STATUS_DEP_RESOLVE]
+            self.backend.percentage(pct_start)
 
     # Be lazy and not define the others explicitly
     def _do_nothing(self, *args, **kwargs):
commit 65037643dd4d5cd06e55ae822844765a990b1b9c
Author: Richard Hughes <richard at hughsie.com>
Date:   Tue Dec 16 09:06:46 2008 +0000

    yum: import yum for file, rather than just in main to fix exception handling. Fixes rh#476381

diff --git a/backends/yum/yumComps.py b/backends/yum/yumComps.py
index 9c77785..bd27d8c 100755
--- a/backends/yum/yumComps.py
+++ b/backends/yum/yumComps.py
@@ -21,6 +21,7 @@
 from packagekit.enums import *
 import sqlite3 as sqlite
 import os
+import yum
 
 groupMap = {
 'desktops;gnome-desktop'                      : GROUP_DESKTOP_GNOME,
@@ -363,8 +364,7 @@ class yumComps:
             grps.add(row[0])
         return list(grps)
 
-if __name__ == "__main__":
-    import yum
+def main():
     _yb = yum.YumBase()
     _db = "./packagekit-groups.sqlite"
     comps = yumComps(_yb, _db)
@@ -387,3 +387,6 @@ if __name__ == "__main__":
     print _pkgs
     os.unlink(_db) # kill the db
 
+if __name__ == "__main__":
+    main()
+
commit d73a13f003e04844c1a80bc8e962a5185fec262a
Author: Aidan Skinner <aidan at skinner.me.uk>
Date:   Mon Dec 15 23:05:38 2008 +0000

    Add ruck client

diff --git a/AUTHORS b/AUTHORS
index 20fa7eb..c0431a8 100644
--- a/AUTHORS
+++ b/AUTHORS
@@ -21,3 +21,6 @@ Backend: poldek
 Backend: zypp
     Boyd Timothy <btimothy at gmail.com>
     Scott Reeves <sreeves at novell.com>
+
+Client: ruck
+    Aidan Skinner <aidan at skinner.me.uk>
commit 3b89aceed762b80e7c16b4011271ac072cb6af71
Author: Aidan Skinner <aidan at skinner.me.uk>
Date:   Mon Dec 15 22:56:30 2008 +0000

    ruck: Make update use update_packages instead of update_system
          Always pass in PackageKitPackage to package_to_row

diff --git a/contrib/ruck/src/ruckpackagecmds.py b/contrib/ruck/src/ruckpackagecmds.py
index a55c2a6..c88e723 100644
--- a/contrib/ruck/src/ruckpackagecmds.py
+++ b/contrib/ruck/src/ruckpackagecmds.py
@@ -611,7 +611,7 @@ class PackageSearchCmd(PackageCmd):
             no_abbrev = options_dict.has_key("no-abbrev")
 
             for pkg in matches:
-                row = ruckformat.package_to_row(pkg['id'], no_abbrev, table_keys)
+                row = ruckformat.package_to_row(pkg, no_abbrev, table_keys)
                 table_rows.append(row)
 
             if options_dict.has_key("sort-by-repo"):
@@ -662,8 +662,7 @@ class PackageListUpdatesCmd(PackageCmd):
         updates = pkcon.get_updates()
 
         for new_pkg in updates:
-            row = ruckformat.package_to_row(new_pkg['id'],
-                                           no_abbrev, table_keys)
+            row = ruckformat.package_to_row(new_pkg, no_abbrev, table_keys)
             table_rows.append(row)
 
         if len(table_rows):
@@ -708,7 +707,7 @@ class  PackageUpdatesSummaryCmd(PackageCmd):
         updates = pkcon.get_updates()
         repos = {}
         for pkg in updates:
-            bits = ruckformat.package_to_row(pkg['id'], False, ['repo'])
+            bits = ruckformat.package_to_row(pkg, False, ['repo'])
             if not repos.has_key(bits[0]):
                 repos[bits[0]] = [bits[0], 0]
             repos[bits[0]][1] = str(int(repos[bits[0]][1])+1)
@@ -768,13 +767,13 @@ class PackageInfoCmd(ruckcommand.RuckCommand):
             ## Find the latest version
             latest_ver, latest_id = None, None
             for pkg in plist:
-                row = ruckformat.package_to_row(pkg['id'], False, ['version'])
+                row = ruckformat.package_to_row(pkg, False, ['version'])
                 if latest_ver == None or row[0] > latest_ver:
                     latest_ver= row[0]
                     latest_id = pkg
 
             latest = pkcon.get_details(latest_id['id'])[0]
-            details = ruckformat.package_to_row(latest['id'], False, ['name', 'version', 'repo', 'installed'])
+            details = ruckformat.package_to_row(latest, False, ['name', 'version', 'repo', 'installed'])
             latest['name'] = details[0]
             latest['version'] = details[1]
             latest['repo'] = details[2]
diff --git a/contrib/ruck/src/rucktransactcmds.py b/contrib/ruck/src/rucktransactcmds.py
index 8fefe47..dd118a1 100644
--- a/contrib/ruck/src/rucktransactcmds.py
+++ b/contrib/ruck/src/rucktransactcmds.py
@@ -68,8 +68,7 @@ class UpdateCmd(TransactCmd):
         table_keys = ["repo", "name", "version"]
         table_rows = []
         for new_pkg in updates:
-            row = ruckformat.package_to_row(new_pkg['id'],
-                                           False, table_keys)
+            row = ruckformat.package_to_row(new_pkg, False, table_keys)
             table_rows.append(row)
 
         table_rows.sort(lambda x,y:cmp(string.lower(x[1]), string.lower(y[1])))
@@ -80,7 +79,7 @@ class UpdateCmd(TransactCmd):
         resp = rucktalk.prompt("Continue? Y/[N]")
         if (resp == 'y'):
             # FIXME: needs to deal with progress better
-            pkcon.update_system()
+            pkcon.update_packages(updates)
         else:
             rucktalk.message("Update aborted")
 
commit 4b3e3251818ce0163850c82b9a863bb4e158a158
Author: Richard Hughes <richard at hughsie.com>
Date:   Mon Dec 15 14:59:37 2008 +0000

    glib: add a client side timeout monitor so we can set a limit on queries or executions

diff --git a/lib/packagekit-glib/pk-client.c b/lib/packagekit-glib/pk-client.c
index a49a17e..c544c31 100644
--- a/lib/packagekit-glib/pk-client.c
+++ b/lib/packagekit-glib/pk-client.c
@@ -109,6 +109,8 @@ struct _PkClientPrivate
 	gchar			*cached_directory;
 	PkProvidesEnum		 cached_provides;
 	PkBitfield		 cached_filters;
+	gint			 timeout;
+	guint			 timeout_id;
 };
 
 typedef enum {
@@ -393,6 +395,33 @@ pk_client_set_synchronous (PkClient *client, gboolean synchronous, GError **erro
 }
 
 /**
+ * pk_client_set_timeout:
+ * @client: a valid #PkClient instance
+ * @timeout: the timeout in milliseconds, or -1 for disabled
+ * @error: a %GError to put the error code and message in, or %NULL
+ *
+ * A synchronous mode allows us to listen in all transactions.
+ *
+ * Return value: %TRUE if the timeout mode was set
+ **/
+gboolean
+pk_client_set_timeout (PkClient *client, gint timeout, GError **error)
+{
+	g_return_val_if_fail (PK_IS_CLIENT (client), FALSE);
+	g_return_val_if_fail (error == NULL || *error == NULL, FALSE);
+
+	/* are we doing this again without reset? */
+	if (client->priv->timeout != -1) {
+		if (error != NULL)
+			*error = g_error_new (PK_CLIENT_ERROR, PK_CLIENT_ERROR_FAILED, "already set timeout to %i!", client->priv->timeout);
+		return FALSE;
+	}
+
+	client->priv->timeout = timeout;
+	return TRUE;
+}
+
+/**
  * pk_client_get_use_buffer:
  * @client: a valid #PkClient instance
  *
@@ -490,6 +519,12 @@ pk_client_finished_cb (DBusGProxy *proxy, const gchar *exit_text, guint runtime,
 	 * see https://bugzilla.novell.com/show_bug.cgi?id=390929 for rationale */
 	g_object_ref (client);
 
+	/* stop the timeout timer if running */
+	if (client->priv->timeout_id != 0) {
+		g_source_remove (client->priv->timeout_id);
+		client->priv->timeout_id = 0;
+	}
+
 	exit = pk_exit_enum_from_text (exit_text);
 	egg_debug ("emit finished %s, %i", exit_text, runtime);
 
@@ -1203,6 +1238,28 @@ out:
 }
 
 /**
+ * pk_client_transaction_timeout_cb:
+ **/
+static gboolean
+pk_client_transaction_timeout_cb (PkClient *client)
+{
+	gboolean ret;
+	const gchar *details = "cancelling client as timeout is up";
+
+	egg_debug ("timeout up");
+	ret = pk_client_cancel (client, NULL);
+	if (!ret) {
+		egg_warning ("failed to cancel");
+		return TRUE;
+	}
+
+	/* emit signal */
+	egg_debug ("emit error-code %i, %s", PK_ERROR_ENUM_TRANSACTION_CANCELLED, details);
+	g_signal_emit (client , signals [PK_CLIENT_ERROR_CODE], 0, PK_ERROR_ENUM_TRANSACTION_CANCELLED, details);
+	return FALSE;
+}
+
+/**
  * pk_client_allocate_transaction_id:
  * @client: a valid #PkClient instance
  * @error: a %GError to put the error code and message in, or %NULL
@@ -1217,10 +1274,23 @@ pk_client_allocate_transaction_id (PkClient *client, GError **error)
 	gboolean ret;
 	gchar *tid;
 	GError *error_local = NULL;
+	const gchar **list;
+	guint len;
 
 	g_return_val_if_fail (PK_IS_CLIENT (client), FALSE);
 	g_return_val_if_fail (error == NULL || *error == NULL, FALSE);
 
+	/* special value meaning "don't wait if another transaction queued" */
+	if (client->priv->timeout == 0) {
+		list = pk_control_transaction_list_get (client->priv->control);
+		len = g_strv_length ((gchar**)list);
+		if (len > 0) {
+			if (error != NULL)
+				*error = g_error_new (PK_CLIENT_ERROR, PK_CLIENT_ERROR_FAILED, "will not queue as timeout 0");
+			return FALSE;
+		}
+	}
+
 	/* get a new ID */
 	ret = pk_control_allocate_transaction_id (client->priv->control, &tid, &error_local);
 	if (!ret) {
@@ -1247,6 +1317,11 @@ pk_client_allocate_transaction_id (PkClient *client, GError **error)
 		g_error_free (error_local);
 		return FALSE;
 	}
+
+	/* set a timeout */
+	if (client->priv->timeout > 0)
+		client->priv->timeout_id = g_timeout_add (client->priv->timeout, (GSourceFunc) pk_client_transaction_timeout_cb, client);
+
 	return TRUE;
 }
 
@@ -4268,6 +4343,12 @@ pk_client_reset (PkClient *client, GError **error)
 			return FALSE;
 	}
 
+	/* stop the timeout timer if running */
+	if (client->priv->timeout_id != 0) {
+		g_source_remove (client->priv->timeout_id);
+		client->priv->timeout_id = 0;
+	}
+
 	g_free (client->priv->tid);
 	g_free (client->priv->cached_package_id);
 	g_free (client->priv->cached_key_id);
@@ -4294,6 +4375,7 @@ pk_client_reset (PkClient *client, GError **error)
 	client->priv->last_status = PK_STATUS_ENUM_UNKNOWN;
 	client->priv->role = PK_ROLE_ENUM_UNKNOWN;
 	client->priv->is_finished = FALSE;
+	client->priv->timeout = -1;
 
 	pk_obj_list_clear (PK_OBJ_LIST (client->priv->package_list));
 	pk_obj_list_clear (client->priv->cached_data);
@@ -4331,6 +4413,8 @@ pk_client_init (PkClient *client)
 	client->priv->cached_provides = PK_PROVIDES_ENUM_UNKNOWN;
 	client->priv->cached_filters = PK_FILTER_ENUM_UNKNOWN;
 	client->priv->proxy = NULL;
+	client->priv->timeout = -1;
+	client->priv->timeout_id = 0;
 
 	/* check dbus connections, exit if not valid */
 	client->priv->connection = dbus_g_bus_get (DBUS_BUS_SYSTEM, &error);
@@ -4456,6 +4540,10 @@ pk_client_finalize (GObject *object)
 		g_main_loop_quit (client->priv->loop);
 	g_main_loop_unref (client->priv->loop);
 
+	/* stop the timeout timer if running */
+	if (client->priv->timeout_id != 0)
+		g_source_remove (client->priv->timeout_id);
+
 	/* disconnect signal handlers */
 	g_signal_handler_disconnect (client->priv->pconnection, client->priv->pconnection_signal_id);
 	pk_client_disconnect_proxy (client);
@@ -4824,6 +4912,79 @@ pk_client_test (EggTest *test)
 		error = NULL;
 	}
 	g_object_unref (client);
+
+	/************************************************************
+	 ****************         TIMEOUTS         ******************
+	 ************************************************************/
+	client = pk_client_new ();
+	g_signal_connect (client, "finished",
+			  G_CALLBACK (pk_client_test_copy_finished_cb), test);
+	client_copy = pk_client_new ();
+	g_signal_connect (client_copy, "finished",
+			  G_CALLBACK (pk_client_test_copy_finished_cb), test);
+
+	/************************************************************/
+	egg_test_title (test, "set timeout");
+	ret = pk_client_set_timeout (client, 0, NULL);
+	if (ret)
+		egg_test_success (test, NULL);
+	else
+		egg_test_failed (test, "failed to set timout");
+
+	/************************************************************/
+	egg_test_title (test, "set timeout on copy");
+	ret = pk_client_set_timeout (client_copy, 500, NULL);
+	if (ret)
+		egg_test_success (test, NULL);
+	else
+		egg_test_failed (test, "failed to set timout");
+
+	/************************************************************/
+	egg_test_title (test, "set timeout (2)");
+	ret = pk_client_set_timeout (client, 1000, NULL);
+	if (!ret)
+		egg_test_success (test, NULL);
+	else
+		egg_test_failed (test, "set timeout when already set");
+
+	/************************************************************/
+	egg_test_title (test, "reset client, to clear timeout");
+	ret = pk_client_reset (client, NULL);
+	egg_test_assert (test, ret);
+
+	/************************************************************/
+	egg_test_title (test, "set timeout");
+	ret = pk_client_set_timeout (client, 0, NULL);
+	if (ret)
+		egg_test_success (test, NULL);
+	else
+		egg_test_failed (test, "failed to set timout");
+
+	/************************************************************/
+	egg_test_title (test, "do first task (which will fail after 500ms)");
+	ret = pk_client_search_name (client_copy, PK_FILTER_ENUM_NONE, "power", &error);
+	if (ret) {
+		egg_test_success (test, NULL);
+	} else {
+		egg_test_failed (test, "failed: %s", error->message);
+		g_error_free (error);
+	}
+
+	/************************************************************/
+	egg_test_title (test, "do second task which should fail outright");
+	ret = pk_client_search_name (client, PK_FILTER_ENUM_NONE, "power", &error);
+	if (!ret) {
+		egg_test_success (test, "failed (in a good way): %s", error->message);
+		g_error_free (error);
+	} else {
+		egg_test_failed (test, "suceeded, which was bad");
+	}
+
+	/* 500ms plus breathing room */
+	egg_test_loop_wait (test, 600);
+
+	g_object_unref (client);
+
 out:
 	egg_test_end (test);
 }
diff --git a/lib/packagekit-glib/pk-client.h b/lib/packagekit-glib/pk-client.h
index 37f4df8..ac1dc86 100644
--- a/lib/packagekit-glib/pk-client.h
+++ b/lib/packagekit-glib/pk-client.h
@@ -173,6 +173,9 @@ gboolean	 pk_client_set_use_buffer		(PkClient	*client,
 gboolean	 pk_client_set_synchronous		(PkClient	*client,
 							 gboolean	 synchronous,
 							 GError		**error);
+gboolean	 pk_client_set_timeout			(PkClient	*client,
+							 gint		 timeout,
+							 GError		**error);
 gboolean	 pk_client_get_use_buffer		(PkClient	*client);
 gboolean	 pk_client_get_allow_cancel		(PkClient	*client,
 							 gboolean	*allow_cancel,
commit c21f80eb359da50b736417c1f3153497da1e3403
Author: Richard Hughes <richard at hughsie.com>
Date:   Mon Dec 15 14:24:22 2008 +0000

    trivial: fix make check by including all the path depths

diff --git a/lib/packagekit-glib/egg-test.c b/lib/packagekit-glib/egg-test.c
index 09e69d6..900b916 100644
--- a/lib/packagekit-glib/egg-test.c
+++ b/lib/packagekit-glib/egg-test.c
@@ -324,6 +324,13 @@ egg_test_get_data_file (const gchar *filename)
 		return full;
 	g_free (full);
 
+	/* check to see if we are being run in the build root */
+	full = g_build_filename ("..", "..", "data", "tests", filename, NULL);
+	ret = g_file_test (full, G_FILE_TEST_EXISTS);
+	if (ret)
+		return full;
+	g_free (full);
+
 	/* check to see if we are being run in make check */
 	full = g_build_filename ("..", "..", "..", "data", "tests", filename, NULL);
 	ret = g_file_test (full, G_FILE_TEST_EXISTS);
commit 056cb844632e7a1264c21565207375b0cd5b2b7c
Author: Richard Hughes <richard at hughsie.com>
Date:   Mon Dec 15 14:23:47 2008 +0000

    bugfix: get the caller (and uid) for all transactions from the GetTid method as we cannot get the UID from the non-async methods

diff --git a/src/pk-transaction.c b/src/pk-transaction.c
index 8b4e065..d6bff31 100644
--- a/src/pk-transaction.c
+++ b/src/pk-transaction.c
@@ -1202,6 +1202,11 @@ pk_transaction_set_sender (PkTransaction *transaction, const gchar *sender)
 	transaction->priv->sender = g_strdup (sender);
 	egg_dbus_monitor_assign (transaction->priv->monitor, EGG_DBUS_MONITOR_SYSTEM, sender);
 
+	/* we get the UID for all callers as we need to know when to cancel */
+	transaction->priv->caller = pk_security_caller_new_from_sender (transaction->priv->security, sender);
+	if (transaction->priv->caller != NULL)
+		transaction->priv->uid = pk_security_get_uid (transaction->priv->security, transaction->priv->caller);
+
 	return TRUE;
 }
 
@@ -1240,10 +1245,6 @@ pk_transaction_commit (PkTransaction *transaction)
 		return FALSE;
 	}
 
-	/* save uid */
-	if (transaction->priv->caller != NULL)
-		transaction->priv->uid = pk_security_get_uid (transaction->priv->security, transaction->priv->caller);
-
 	/* only save into the database for useful stuff */
 	if (transaction->priv->role == PK_ROLE_ENUM_UPDATE_SYSTEM ||
 	    transaction->priv->role == PK_ROLE_ENUM_REMOVE_PACKAGES ||
@@ -1392,8 +1393,7 @@ pk_transaction_action_is_allowed (PkTransaction *transaction, gboolean trusted,
 
 	g_return_val_if_fail (transaction->priv->sender != NULL, FALSE);
 
-	/* get caller */
-	transaction->priv->caller = pk_security_caller_new_from_sender (transaction->priv->security, transaction->priv->sender);
+	/* we should always have caller */
 	if (transaction->priv->caller == NULL) {
 		*error = g_error_new (PK_TRANSACTION_ERROR, PK_TRANSACTION_ERROR_REFUSED_BY_POLICY,
 				      "caller %s not found", transaction->priv->sender);
commit 8298fc4a51326e35c62b26d5767253942ee934b4
Author: Richard Hughes <richard at hughsie.com>
Date:   Mon Dec 15 12:13:26 2008 +0000

    bugfix: remove the concept of slow and fast interfaces, since we don't actualy know the speed

diff --git a/lib/packagekit-glib/pk-enum.c b/lib/packagekit-glib/pk-enum.c
index 474bdfe..92343e2 100644
--- a/lib/packagekit-glib/pk-enum.c
+++ b/lib/packagekit-glib/pk-enum.c
@@ -322,8 +322,9 @@ static const PkEnumMatch enum_network[] = {
 	{PK_NETWORK_ENUM_UNKNOWN,		"unknown"},	/* fall though value */
 	{PK_NETWORK_ENUM_OFFLINE,		"offline"},
 	{PK_NETWORK_ENUM_ONLINE,		"online"},
-	{PK_NETWORK_ENUM_SLOW,			"slow"},
-	{PK_NETWORK_ENUM_FAST,			"fast"},
+	{PK_NETWORK_ENUM_WIRED,			"wired"},
+	{PK_NETWORK_ENUM_WIFI,			"wifi"},
+	{PK_NETWORK_ENUM_MOBILE,		"mobile"},
 	{0, NULL}
 };
 
diff --git a/lib/packagekit-glib/pk-enum.h b/lib/packagekit-glib/pk-enum.h
index c569d63..2659873 100644
--- a/lib/packagekit-glib/pk-enum.h
+++ b/lib/packagekit-glib/pk-enum.h
@@ -158,8 +158,9 @@ typedef enum {
 typedef enum {
 	PK_NETWORK_ENUM_OFFLINE,
 	PK_NETWORK_ENUM_ONLINE,
-	PK_NETWORK_ENUM_SLOW,
-	PK_NETWORK_ENUM_FAST,
+	PK_NETWORK_ENUM_WIRED,
+	PK_NETWORK_ENUM_WIFI,
+	PK_NETWORK_ENUM_MOBILE,
 	PK_NETWORK_ENUM_UNKNOWN
 } PkNetworkEnum;
 
diff --git a/src/org.freedesktop.PackageKit.xml b/src/org.freedesktop.PackageKit.xml
index 3e27f3a..b8768d3 100644
--- a/src/org.freedesktop.PackageKit.xml
+++ b/src/org.freedesktop.PackageKit.xml
@@ -242,8 +242,13 @@
         <doc:doc>
           <doc:summary>
             <doc:para>
-              The network state, e.g. <doc:tt>unknown</doc:tt>,
-              <doc:tt>offline</doc:tt> or <doc:tt>online</doc:tt>.
+              The network state. If the system is managed using NetworkManager then the following
+              states are supported:
+              <doc:tt>unknown</doc:tt>, <doc:tt>offline</doc:tt>, <doc:tt>online</doc:tt>,
+              <doc:tt>wifi</doc:tt>, <doc:tt>mobile</doc:tt> or <doc:tt>wired</doc:tt>.
+              If the system is configured for legacy UNIX network fallback, or NetworkManager
+              is not running then the folowing states are supported:
+              <doc:tt>unknown</doc:tt>, <doc:tt>offline</doc:tt> or <doc:tt>online</doc:tt>.
             </doc:para>
           </doc:summary>
         </doc:doc>
diff --git a/src/pk-backend.c b/src/pk-backend.c
index 5913ed4..cf296f4 100644
--- a/src/pk-backend.c
+++ b/src/pk-backend.c
@@ -1546,8 +1546,9 @@ pk_backend_is_online (PkBackend *backend)
 	g_return_val_if_fail (PK_IS_BACKEND (backend), FALSE);
 	state = pk_network_get_network_state (backend->priv->network);
 	if (state == PK_NETWORK_ENUM_ONLINE ||
-	    state == PK_NETWORK_ENUM_SLOW ||
-	    state == PK_NETWORK_ENUM_FAST)
+	    state == PK_NETWORK_ENUM_MOBILE ||
+	    state == PK_NETWORK_ENUM_WIFI ||
+	    state == PK_NETWORK_ENUM_WIRED)
 		return TRUE;
 	return FALSE;
 }
diff --git a/src/pk-network-nm.c b/src/pk-network-nm.c
index 84062af..22a158d 100644
--- a/src/pk-network-nm.c
+++ b/src/pk-network-nm.c
@@ -271,14 +271,14 @@ pk_network_nm_get_network_state (PkNetworkNm *network_nm)
 		ret = PK_NETWORK_ENUM_OFFLINE;
 		break;
 	case NM_DEVICE_TYPE_ETHERNET:
-		ret = PK_NETWORK_ENUM_FAST;
+		ret = PK_NETWORK_ENUM_WIRED;
 		break;
 	case NM_DEVICE_TYPE_WIFI:
-		ret = PK_NETWORK_ENUM_ONLINE;
+		ret = PK_NETWORK_ENUM_WIFI;
 		break;
 	case NM_DEVICE_TYPE_GSM:
 	case NM_DEVICE_TYPE_CDMA:
-		ret = PK_NETWORK_ENUM_SLOW;
+		ret = PK_NETWORK_ENUM_MOBILE;
 		break;
 	default:
 		ret = PK_NETWORK_ENUM_ONLINE;
commit 097a345852f2556d04f5a399c1d5390c6f6f205d
Author: Richard Hughes <richard at hughsie.com>
Date:   Mon Dec 15 11:46:27 2008 +0000

    trivial: update a dangling link in the test directory

diff --git a/backends/test/helpers/packagekit b/backends/test/helpers/packagekit
index 2e8d949..af2698b 120000
--- a/backends/test/helpers/packagekit
+++ b/backends/test/helpers/packagekit
@@ -1 +1 @@
-../../lib/python/packagekit
\ No newline at end of file
+../../../lib/python/packagekit/
\ No newline at end of file
commit 699cd9901534c2b766704c9210525becb31979f3
Author: Richard Hughes <richard at hughsie.com>
Date:   Mon Dec 15 10:18:51 2008 +0000

    ruck: convert to use native buildsystem and fix a few typos

diff --git a/configure.ac b/configure.ac
index 84eb7fa..5d5b7e5 100644
--- a/configure.ac
+++ b/configure.ac
@@ -339,6 +339,13 @@ AC_ARG_ENABLE(command_not_found, AS_HELP_STRING([--enable-command-not-found],[Bu
 AM_CONDITIONAL(PK_BUILD_COMMAND_NOT_FOUND, test $build_command_not_found = "yes")
 
 dnl ---------------------------------------------------------------------------
+dnl - Build ruck (a rug-like interface for PackageKit)
+dnl ---------------------------------------------------------------------------
+AC_ARG_ENABLE(ruck, AS_HELP_STRING([--enable-ruck],[Build ruck client]),
+	      build_ruck=$enableval,build_ruck=yes)
+AM_CONDITIONAL(PK_BUILD_RUCK, test $build_ruck = "yes")
+
+dnl ---------------------------------------------------------------------------
 dnl - Other tests
 dnl ---------------------------------------------------------------------------
 AC_ARG_ENABLE(gcov, AS_HELP_STRING([--enable-gcov],[compile with coverage profiling instrumentation (gcc only)]),
@@ -606,6 +613,8 @@ contrib/gtk-module/Makefile
 contrib/udev/Makefile
 contrib/yum-packagekit/Makefile
 contrib/command-not-found/Makefile
+contrib/ruck/Makefile
+contrib/ruck/src/Makefile
 backends/Makefile
 backends/alpm/Makefile
 backends/apt/Makefile
@@ -668,6 +677,7 @@ echo "
         GStreamer plugin:          ${build_gstreamer_plugin}
         Pango module:              ${build_gtk_module}
         BASH Command not found:    ${build_command_not_found}
+        RUCK client:               ${build_ruck}
         QT library:                ${build_qt}
 
         Backends:
diff --git a/contrib/Makefile.am b/contrib/Makefile.am
index 8326ced..7561851 100644
--- a/contrib/Makefile.am
+++ b/contrib/Makefile.am
@@ -4,6 +4,10 @@ if BACKEND_TYPE_YUM
 SUBDIRS += yum-packagekit
 endif
 
+if PK_BUILD_RUCK
+SUBDIRS += ruck
+endif
+
 if PK_BUILD_BROWSER_PLUGIN
 SUBDIRS += browser-plugin
 endif
diff --git a/contrib/PackageKit.spec.in b/contrib/PackageKit.spec.in
index ae4116e..1dcfa8e 100644
--- a/contrib/PackageKit.spec.in
+++ b/contrib/PackageKit.spec.in
@@ -212,6 +212,17 @@ Requires: PackageKit-glib = %{version}-%{release}
 A simple helper that offers to install new packages on the command line
 using PackageKit.
 
+%package ruck
+Summary: rug-like interface that uses PackageKit
+Group: Development/Libraries
+Requires: PackageKit = %{version}-%{release}
+
+%description ruck
+Ruck is a rug-like interface for PackageKit, where rug is the command-line
+interface for rcd and red carpet daemon.
+Ruck is for a couple of lazy people who got used to Red Carpet's rug command
+and are unable to learn any new tricks.
+
 %prep
 %setup -q
 
@@ -381,6 +392,12 @@ update-mime-database %{_datadir}/mime &> /dev/null || :
 %{_sysconfdir}/profile.d/*
 %{_libexecdir}/pk-command-not-found
 
+%files ruck
+%defattr(-,root,root,-)
+%doc README AUTHORS NEWS COPYING
+%{_bindir}/ruck
+%{_datadir}/ruck/*
+
 %files glib-devel
 %defattr(-,root,root,-)
 %doc README AUTHORS NEWS COPYING
diff --git a/contrib/ruck/ChangeLog b/contrib/ruck/ChangeLog
deleted file mode 100644
index e69de29..0000000
diff --git a/contrib/ruck/HACKING b/contrib/ruck/HACKING
deleted file mode 100644
index e3576ad..0000000
--- a/contrib/ruck/HACKING
+++ /dev/null
@@ -1,8 +0,0 @@
-CONTRIBUTING
-------------
-Contributors to ruck are more than welcome. Patches should be sent to the
-authors (see AUTHORS file) and should follow the existing stylistic
-conventions, be accompanied by a ChangeLog entry, and sent in GNU unified
-diff format (diff -u).
-
-Good Luck.
diff --git a/contrib/ruck/Makefile.am b/contrib/ruck/Makefile.am
index c5475c2..c2d7878 100644
--- a/contrib/ruck/Makefile.am
+++ b/contrib/ruck/Makefile.am
@@ -1,13 +1,9 @@
 SUBDIRS = src
 
-WORKDIR := $(shell pwd)
+extradir = $(datadir)/ruck
+extra_DATA =			\
+	AUTHORS			\
+	README
+
+EXTRA_DIST = $(extra_DATA)
 
-rpm: dist
-	mkdir -p $(WORKDIR)/rpm/SOURCES $(WORKDIR)/rpm/BUILD \
-	$(WORKDIR)/rpm/RPMS $(WORKDIR)/rpm/SRPMS; \
-	cp $(PACKAGE)-$(VERSION)*tar.gz $(WORKDIR)/rpm/SOURCES; \
-	rpmbuild --define "_sourcedir $(WORKDIR)/rpm/SOURCES" \
-	--define "_builddir $(WORKDIR)/rpm/BUILD" \
-	--define "_srcrpmdir $(WORKDIR)/rpm/SRPMS" \
-	--define "_rpmdir $(WORKDIR)/rpm/RPMS" -ba ruck.spec && \
-	cp $(WORKDIR)/rpm/RPMS/noarch/$(PACKAGE)-$(VERSION)* .
diff --git a/contrib/ruck/NEWS b/contrib/ruck/NEWS
deleted file mode 100644
index e69de29..0000000
diff --git a/contrib/ruck/autogen.sh b/contrib/ruck/autogen.sh
deleted file mode 100755
index 803441d..0000000
--- a/contrib/ruck/autogen.sh
+++ /dev/null
@@ -1,26 +0,0 @@
-#!/bin/sh
-# Run this to generate all the initial makefiles, etc.
-
-srcdir=`dirname $0`
-test -z "$srcdir" && srcdir=.
-
-PKG_NAME="ruck"
-
-(test -f $srcdir/configure.in \
-  && test -d $srcdir/src \
-  && test -f $srcdir/src/ruck.in) || {
-    echo -n "**Error**: Directory "\`$srcdir\'" does not look like the"
-    echo " top-level $PKG_NAME directory"
-    exit 1
-}
-
-which gnome-autogen.sh || {
-    echo "You need to install gnome-common from the GNOME CVS"
-    exit 1
-}
-
-REQUIRED_AUTOMAKE_VERSION=1.6
-export REQUIRED_AUTOMAKE_VERSION
-
-USE_GNOME2_MACROS=1 . gnome-autogen.sh
-
diff --git a/contrib/ruck/configure.in b/contrib/ruck/configure.in
deleted file mode 100644
index a7f11e6..0000000
--- a/contrib/ruck/configure.in
+++ /dev/null
@@ -1,36 +0,0 @@
-AC_INIT(src/ruckmain.py)
-
-MAJOR_VERSION=0
-MINOR_VERSION=0
-MICRO_VERSION=1
-VERSION=$MAJOR_VERSION.$MINOR_VERSION.$MICRO_VERSION
-
-AM_INIT_AUTOMAKE(ruck, $VERSION)
-
-AM_MAINTAINER_MODE
-
-AM_PATH_PYTHON(2.4)
-
-if test x$HAVE_PYTHON = xno; then
-	AC_MSG_ERROR(Couldn't find python in the path)
-fi
-
-DDIR=`echo $datadir | sed -e "s,"'${prefix}'",$prefix,"`
-AC_SUBST(DDIR)
-
-# FIXME: We assume exec_prefix == prefix, which is probably bad
-LIBDIR=`echo $libdir | sed -e "s,"'${exec_prefix}'",$prefix,"`
-AC_SUBST(LIBDIR)
-
-AC_OUTPUT([
-Makefile
-src/Makefile
-src/ruck
-])
-
-echo "
-
-Configuration:
-
-  Prefix:             ${prefix}
-"
diff --git a/contrib/ruck/src/.gitignore b/contrib/ruck/src/.gitignore
new file mode 100644
index 0000000..8803d3d
--- /dev/null
+++ b/contrib/ruck/src/.gitignore
@@ -0,0 +1,2 @@
+ruck
+
diff --git a/contrib/ruck/src/Makefile.am b/contrib/ruck/src/Makefile.am
index affe03c..6b84957 100644
--- a/contrib/ruck/src/Makefile.am
+++ b/contrib/ruck/src/Makefile.am
@@ -1,23 +1,32 @@
-ruckexecdir = $(bindir)
-ruckexec_DATA = ruck
+#ruckexecdir = $(bindir)
+#ruckexec_DATA = ruck
 
 rucksupportdir = $(datadir)/ruck
-rucksupport_DATA = 		\
-	i18n.py	            \
-	ruckcommand.py		\
-	ruckmain.py		    \
-	ruckformat.py		\
-	rucklocks.py 		\
-	ruckyum.py    		\
+rucksupport_DATA = 			\
+	i18n.py				\
+	ruckcommand.py			\
+	ruckmain.py			\
+	ruckformat.py			\
+	rucklocks.py 			\
+	ruckyum.py    			\
 	rucktalk.py
 
 ruckcmdsdir = $(rucksupportdir)/commands
 ruckcmds_DATA = 			\
-	ruckcachecmds.py	    \
-	rucktransactcmds.py	\
+	ruckcachecmds.py		\
+	rucktransactcmds.py		\
 	ruckpackagecmds.py
 
-EXTRA_DIST = $(rucksupport_DATA) $(ruckcmds_DATA)
+ruckexecdir = $(bindir)
+ruckexec_in_files = ruck.in
+ruckexec_DATA = $(ruckexec_in_files:.in=)
+$(ruckexec_DATA): $(ruckexec_in_files) Makefile
+	@sed -e "s|\@DDIR\@|$(datadir)|" -e "s|\@VERSION\@|$(VERSION)|" $< > $@
+
+EXTRA_DIST = $(rucksupport_DATA) $(ruckcmds_DATA) $(ruckexec_in_files)
 
 install-exec-hook:
 	chmod 0755 $(DESTDIR)$(ruckexecdir)/$(ruckexec_DATA)
+
+DISTCLEANFILES =			\
+	$(ruckexec_DATA)
diff --git a/contrib/ruck/src/ruck.in b/contrib/ruck/src/ruck.in
index a0b30e3..774473c 100644
--- a/contrib/ruck/src/ruck.in
+++ b/contrib/ruck/src/ruck.in
@@ -21,7 +21,7 @@ try:
     import sys
     import os
 
-    ruck_dir = "@DDIR@/rum"
+    ruck_dir = "@DDIR@/ruck"
     ruck_version = "@VERSION@"
 
     # FIXME: This has a special check to allow us to run ruck in-place
@@ -29,7 +29,7 @@ try:
     # out at some point.
 
     if not (os.path.isfile("./ruckmain.py") \
-            or (os.path.isdir(ruck_dir) and os.path.isfile(rum_dir + "/ruckmain.py"))):
+            or (os.path.isdir(ruck_dir) and os.path.isfile(ruck_dir + "/ruckmain.py"))):
         print "ERROR: ruck doesn't appear to be installed properly.  Please check your installation."
         sys.exit(1)
 
diff --git a/contrib/ruck/src/ruckyum.py b/contrib/ruck/src/ruckyum.py
index 7332901..8fc41bf 100644
--- a/contrib/ruck/src/ruckyum.py
+++ b/contrib/ruck/src/ruckyum.py
@@ -183,7 +183,7 @@ class RPMInstallCallback:
                 self.installed_pkg_names.append(hdr['name'])
                 return fd
             else:
-                self._localprint(_("No header - huh?"))
+                self._localprint("No header - huh?")
 
         elif what == rpm.RPMCALLBACK_INST_CLOSE_FILE:
             hdr = None
commit e0b109db2029a8b92866c9bfe8912ca13c9237a1
Author: Aidan Skinner <aidan at skinner.me.uk>
Date:   Mon Dec 15 00:05:11 2008 +0000

    Import ruck, a port of rum, which is a port of rug. This version speaks to packagekit.

diff --git a/contrib/ruck/AUTHORS b/contrib/ruck/AUTHORS
new file mode 100644
index 0000000..c1a9675
--- /dev/null
+++ b/contrib/ruck/AUTHORS
@@ -0,0 +1,3 @@
+Tambet Ingo   <tambet at ximian.com>
+James Willcox <snorp at ximian.com>
+Chris Rivera  <cmr at ximian.com>
diff --git a/contrib/ruck/ChangeLog b/contrib/ruck/ChangeLog
new file mode 100644
index 0000000..e69de29
diff --git a/contrib/ruck/HACKING b/contrib/ruck/HACKING
new file mode 100644
index 0000000..e3576ad
--- /dev/null
+++ b/contrib/ruck/HACKING
@@ -0,0 +1,8 @@
+CONTRIBUTING
+------------
+Contributors to ruck are more than welcome. Patches should be sent to the
+authors (see AUTHORS file) and should follow the existing stylistic
+conventions, be accompanied by a ChangeLog entry, and sent in GNU unified
+diff format (diff -u).
+
+Good Luck.
diff --git a/contrib/ruck/Makefile.am b/contrib/ruck/Makefile.am
new file mode 100644
index 0000000..c5475c2
--- /dev/null
+++ b/contrib/ruck/Makefile.am
@@ -0,0 +1,13 @@
+SUBDIRS = src
+
+WORKDIR := $(shell pwd)
+
+rpm: dist
+	mkdir -p $(WORKDIR)/rpm/SOURCES $(WORKDIR)/rpm/BUILD \
+	$(WORKDIR)/rpm/RPMS $(WORKDIR)/rpm/SRPMS; \
+	cp $(PACKAGE)-$(VERSION)*tar.gz $(WORKDIR)/rpm/SOURCES; \
+	rpmbuild --define "_sourcedir $(WORKDIR)/rpm/SOURCES" \
+	--define "_builddir $(WORKDIR)/rpm/BUILD" \
+	--define "_srcrpmdir $(WORKDIR)/rpm/SRPMS" \
+	--define "_rpmdir $(WORKDIR)/rpm/RPMS" -ba ruck.spec && \
+	cp $(WORKDIR)/rpm/RPMS/noarch/$(PACKAGE)-$(VERSION)* .
diff --git a/contrib/ruck/NEWS b/contrib/ruck/NEWS
new file mode 100644
index 0000000..e69de29
diff --git a/contrib/ruck/README b/contrib/ruck/README
new file mode 100644
index 0000000..4030bf4
--- /dev/null
+++ b/contrib/ruck/README
@@ -0,0 +1,20 @@
+ruck is a rug-like interface for PackageKit
+('rug' is the command-line interface for rcd, red carpet daemon.)
+
+
+Answers to some Frequently Asked Questions:
+-------------------------------------------
+
+* You got to be kidding me, yet another package management tool?
+No, not really. ruck is just an alternative command line interface
+for PackageKit
+
+* What's wrong pkcon?
+The main reason of writing ruck is for a couple of lazy people who
+got used to Red Carpet's cli 'rug' and are unable to learn any
+new tricks.
+
+* Anything else?
+Glad you asked, yes! It's really easy to extend ruck. Just drop the
+implementation of your new commands to $prefix/share/ruck/commands/
+directory and ruck will find them.
diff --git a/contrib/ruck/autogen.sh b/contrib/ruck/autogen.sh
new file mode 100755
index 0000000..803441d
--- /dev/null
+++ b/contrib/ruck/autogen.sh
@@ -0,0 +1,26 @@
+#!/bin/sh
+# Run this to generate all the initial makefiles, etc.
+
+srcdir=`dirname $0`
+test -z "$srcdir" && srcdir=.
+
+PKG_NAME="ruck"
+
+(test -f $srcdir/configure.in \
+  && test -d $srcdir/src \
+  && test -f $srcdir/src/ruck.in) || {
+    echo -n "**Error**: Directory "\`$srcdir\'" does not look like the"
+    echo " top-level $PKG_NAME directory"
+    exit 1
+}
+
+which gnome-autogen.sh || {
+    echo "You need to install gnome-common from the GNOME CVS"
+    exit 1
+}
+
+REQUIRED_AUTOMAKE_VERSION=1.6
+export REQUIRED_AUTOMAKE_VERSION
+
+USE_GNOME2_MACROS=1 . gnome-autogen.sh
+
diff --git a/contrib/ruck/configure.in b/contrib/ruck/configure.in
new file mode 100644
index 0000000..a7f11e6
--- /dev/null
+++ b/contrib/ruck/configure.in
@@ -0,0 +1,36 @@
+AC_INIT(src/ruckmain.py)
+
+MAJOR_VERSION=0
+MINOR_VERSION=0
+MICRO_VERSION=1
+VERSION=$MAJOR_VERSION.$MINOR_VERSION.$MICRO_VERSION
+
+AM_INIT_AUTOMAKE(ruck, $VERSION)
+
+AM_MAINTAINER_MODE
+
+AM_PATH_PYTHON(2.4)
+
+if test x$HAVE_PYTHON = xno; then
+	AC_MSG_ERROR(Couldn't find python in the path)
+fi
+
+DDIR=`echo $datadir | sed -e "s,"'${prefix}'",$prefix,"`
+AC_SUBST(DDIR)
+
+# FIXME: We assume exec_prefix == prefix, which is probably bad
+LIBDIR=`echo $libdir | sed -e "s,"'${exec_prefix}'",$prefix,"`
+AC_SUBST(LIBDIR)
+
+AC_OUTPUT([
+Makefile
+src/Makefile
+src/ruck
+])
+
+echo "
+
+Configuration:
+
+  Prefix:             ${prefix}
+"
diff --git a/contrib/ruck/src/Makefile.am b/contrib/ruck/src/Makefile.am
new file mode 100644
index 0000000..affe03c
--- /dev/null
+++ b/contrib/ruck/src/Makefile.am
@@ -0,0 +1,23 @@
+ruckexecdir = $(bindir)
+ruckexec_DATA = ruck
+
+rucksupportdir = $(datadir)/ruck
+rucksupport_DATA = 		\
+	i18n.py	            \
+	ruckcommand.py		\
+	ruckmain.py		    \
+	ruckformat.py		\
+	rucklocks.py 		\
+	ruckyum.py    		\
+	rucktalk.py
+
+ruckcmdsdir = $(rucksupportdir)/commands
+ruckcmds_DATA = 			\
+	ruckcachecmds.py	    \
+	rucktransactcmds.py	\
+	ruckpackagecmds.py
+
+EXTRA_DIST = $(rucksupport_DATA) $(ruckcmds_DATA)
+
+install-exec-hook:
+	chmod 0755 $(DESTDIR)$(ruckexecdir)/$(ruckexec_DATA)
diff --git a/contrib/ruck/src/i18n.py b/contrib/ruck/src/i18n.py
new file mode 100644
index 0000000..859c31f
--- /dev/null
+++ b/contrib/ruck/src/i18n.py
@@ -0,0 +1,32 @@
+#!/usr/bin/env python
+"""i18n abstraction
+
+License: GPL
+Author: Vladimir Bormotov <bor at vb.dn.ua>
+
+$Id: i18n.py,v 1.3 2004/01/28 07:31:02 skvidal Exp $
+"""
+# $RCSfile: i18n.py,v $
+__version__ = "$Revision: 1.3 $"[11:-2]
+__date__ = "$Date: 2004/01/28 07:31:02 $"[7:-2]
+
+try:
+    import gettext
+    import sys
+    if sys.version_info[0] == 2:
+        t = gettext.translation('yum')
+        _ = t.gettext
+    else:
+        gettext.bindtextdomain('yum', '/usr/share/locale')
+        gettext.textdomain('yum')
+        _ = gettext.gettext
+
+except:
+    def _(str):
+        """pass given string as-is"""
+        return str
+
+if __name__ == '__main__':
+    pass
+
+# vim: set ts=4 et :
diff --git a/contrib/ruck/src/ruck.in b/contrib/ruck/src/ruck.in
new file mode 100644
index 0000000..a0b30e3
--- /dev/null
+++ b/contrib/ruck/src/ruck.in
@@ -0,0 +1,52 @@
+#!/usr/bin/env /usr/bin/python
+
+###
+### Copyright 2002-2003 Ximian, Inc.
+###
+### This program is free software; you can redistribute it and/or modify
+### it under the terms of the GNU General Public License, version 2,
+### as published by the Free Software Foundation.
+###
+### 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.
+###
+
+try:
+    import sys
+    import os
+
+    ruck_dir = "@DDIR@/rum"
+    ruck_version = "@VERSION@"
+
+    # FIXME: This has a special check to allow us to run ruck in-place
+    # without having done a "make install".  We might want to take this
+    # out at some point.
+
+    if not (os.path.isfile("./ruckmain.py") \
+            or (os.path.isdir(ruck_dir) and os.path.isfile(rum_dir + "/ruckmain.py"))):
+        print "ERROR: ruck doesn't appear to be installed properly.  Please check your installation."
+        sys.exit(1)
+
+
+    sys.path.append(ruck_dir)
+    import ruckmain
+
+    if "--ruck-profile" in sys.argv:
+        import profile
+        sys.stderr.write("*** Profiling Enabled ***\n")
+        sys.argv = filter(lambda x:x != "--ruck-profile", sys.argv)
+        profile.run("ruckmain.main(ruck_version, ruck_dir)")
+    else:
+        ruckmain.main(ruck_version, ruck_dir)
+except KeyboardInterrupt:
+    # Just quietly exit if we got a ^C
+    print
+    sys.exit(0)
+
+
diff --git a/contrib/ruck/src/ruckcachecmds.py b/contrib/ruck/src/ruckcachecmds.py
new file mode 100644
index 0000000..3dcbd47
--- /dev/null
+++ b/contrib/ruck/src/ruckcachecmds.py
@@ -0,0 +1,349 @@
+###
+### Copyright 2002 Ximian, Inc.
+### Copyright 2008 Aidan Skinner <aidan at skinner.me.uk>
+###
+### This program is free software; you can redistribute it and/or modify
+### it under the terms of the GNU General Public License, version 2,
+### as published by the Free Software Foundation.
+###
+### This program is distributed in the hope that it will be useful,
+### but WITHOUT ANY WARRANTY; without even the implied warranty of
+### MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+### GNU General Public License for more details.
+###
+### You should have received a copy of the GNU General Public License
+### along with this program; if not, write to the Free Software
+### Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307, USA.
+###
+
+import sys
+import os
+import os.path
+import glob
+from ConfigParser import ConfigParser
+import string
+import rucktalk
+import ruckformat
+import ruckcommand
+
+class CleanCmd(ruckcommand.RuckCommand):
+
+    def name(self):
+        return "clean"
+
+    def aliases(self):
+        return ["cl"]
+
+    def is_basic(self):
+        return 1
+
+    def category(self):
+        return "system"
+
+    def arguments(self):
+        return ""
+
+    def description_short(self):
+        return "Clean cache"
+
+    def local_opt_table(self):
+        return []
+
+    def execute(self, options_dict, non_option_args):
+        pkcon = self.pkcon()
+        pkcon.refresh_cache(True)
+        rucktalk.message('--- Refresh Successful ---')
+
+ruckcommand.register(CleanCmd)
+
+
+class RefreshCmd(ruckcommand.RuckCommand):
+
+    def name(self):
+        return "refresh"
+
+    def aliases(self):
+        return ["ref"]
+
+    def is_basic(self):
+        return 1
+
+    def category(self):
+        return "system"
+
+    def arguments(self):
+        return ""
+
+    def description_short(self):
+        return "Refresh the package cache"
+
+    def execute(self, options_dict, non_option_args):
+        pkcon = self.pkcon()
+        pkcon.refresh_cache(False)
+        rucktalk.message('--- Refresh Successful ---')
+
+
+ruckcommand.register(RefreshCmd)
+
+class RepolistCmd(ruckcommand.RuckCommand):
+
+    def name(self):
+        return "repos"
+
+    def aliases(self):
+        return ["sl", "ca", "ch"]
+
+    def is_basic(self):
+        return 1
+
+    def category(self):
+        return "system"
+
+    def description_short(self):
+        return "List active repositories"
+
+    def local_opt_table(self):
+        return [["", "disabled", "", "Show disabled services"]]
+
+    def execute(self, options_dict, non_option_args):
+        pkcon = self.pkcon()
+
+        enabled_only = not options_dict.has_key("disabled")
+        repos = []
+        for repo in pkcon.get_repo_list():
+            if enabled_only:
+                if repo['enabled']:
+                    line = [repo['id'], repo['desc']]
+                    repos.append(line)
+            else:
+                line = [repo['id'], ruckformat.bool_to_short_str(repo['enabled']), repo['desc']]
+                repos.append(line)
+
+
+        repos.sort(lambda x,y:cmp(x[0], y[0]))
+
+        if len(repos):
+            headers = ['Name', 'Description']
+            if not enabled_only:
+                headers.insert(1, 'Enabled')
+            ruckformat.tabular(headers, repos)
+        else:
+            rucktalk.message("--- No repositories found ---")
+
+ruckcommand.register(RepolistCmd)
+
+class RepoCmd(ruckcommand.RuckCommand):
+
+    def name(self):
+        return "enable"
+
+    def aliases(self):
+        return ["en"]
+
+    def is_basic(self):
+        return 1
+
+    def category(self):
+        return "system"
+
+    def description_short(self):
+        return "Enable a repository"
+
+    def is_hidden(self):
+        return 1
+
+    def setenabled(self, repos, val):
+        pkcon = self.pkcon()
+
+        for repo in repos:
+            pkcon.repo_enable(repo, val)
+            if val:
+                rucktalk.message("--- Enabled repository '%s' ---" % repo)
+            else:
+                rucktalk.message("--- Disabled repository '%s' ---" % repo)
+
+class RepoEnableCmd(RepoCmd):
+
+    def name(self):
+        return "enable"
+
+    def aliases(self):
+        return ["en"]
+
+    def is_basic(self):
+        return 1
+
+    def is_hidden(self):
+        return 0
+
+    def category(self):
+        return "system"
+
+    def description_short(self):
+        return "Enable a repository"
+
+    def execute(self, options_dict, non_option_args):
+        self.setenabled(non_option_args, True)
+
+ruckcommand.register(RepoEnableCmd)
+
+class RepoDisableCmd(RepoCmd):
+
+    def name(self):
+        return "disable"
+
+    def aliases(self):
+        return ["di"]
+
+    def is_basic(self):
+        return 1
+
+    def is_hidden(self):
+        return 0
+
+    def category(self):
+        return "system"
+
+    def description_short(self):
+        return "Disable a repository"
+
+    def execute(self, options_dict, non_option_args):
+        self.setenabled(non_option_args, False)
+
+ruckcommand.register(RepoDisableCmd)
+
+class RepoAddCmd(RepoCmd):
+
+    def name(self):
+        return "repo-add"
+
+    def aliases(self):
+        return ["sa", "ra"]
+
+    def is_basic(self):
+        return 1
+
+    def is_hidden(self):
+        return 1
+
+    def category(self):
+        return "system"
+
+    def arguments(self):
+        return "<name> <url>"
+
+    def description_short(self):
+        return "Add a repository"
+
+    def local_opt_table(self):
+        return [["c", "check-signatures",  "", "Check gpg signatures"],
+                ["n", "name", "name", "Name of the repository"],
+                ["m", "mirrorlist", "", "The url specified is a mirror list"]]
+
+    def check_url(self, url):
+        if url.startswith('http://') or url.startswith('ftp://') or \
+           url.startswith('file://') or url.startswith('https://'):
+            return True
+        else:
+            return False
+
+
+    def execute(self, options_dict, non_option_args):
+        if len(non_option_args) != 2:
+            self.usage()
+            return False
+
+        repoid = non_option_args[0]
+        url = non_option_args[1]
+
+        if not self.check_url(url):
+            rucktalk.error("Invalid url '%s'" % url)
+            return False
+
+        if self.find_repo_file(repoid) != None:
+            rucktalk.error("Repository '%s' already exists" % repoid)
+            return False
+
+        yum = self.yum(repos=False)
+
+        repopath = os.path.join(yum.conf.reposdir[0], repoid + ".repo")
+        if not os.path.exists(os.path.dirname(repopath)):
+            os.makedirs(os.path.dirname(repopath))
+
+        parser = ConfigParser()
+        parser.add_section(repoid)
+
+        name = repoid
+        if options_dict.has_key('name'):
+            name = options_dict['name']
+
+        parser.set(repoid, "name", name)
+
+        if options_dict.has_key('mirrorlist'):
+            parser.set(repoid, "mirrorlist", url)
+        else:
+            parser.set(repoid, "baseurl", url)
+
+        parser.set(repoid, "enabled", "1")
+
+        gpgval = "0"
+        if options_dict.has_key('check-signatures'):
+            gpgval = "1"
+
+        parser.set(repoid, "gpgcheck", gpgval)
+
+
+
+        parser.write(file(repopath, "w+"))
+
+        rucktalk.message("--- Successfully added '%s' ---" % repoid)
+
+
+ruckcommand.register(RepoAddCmd)
+
+class RepoDelCmd(RepoCmd):
+
+    def name(self):
+        return "repo-delete"
+
+    def aliases(self):
+        return ["sd", "rd"]
+
+    def is_basic(self):
+        return 1
+
+    def is_hidden(self):
+        return 1
+
+    def category(self):
+        return "system"
+
+    def arguments(self):
+        return "<id>"
+
+    def description_short(self):
+        return "Remove a repository"
+
+    def execute(self, options_dict, non_option_args):
+        if len(non_option_args) != 1:
+            self.usage()
+            return False
+
+        repoid = non_option_args[0]
+        repopath = self.find_repo_file(repoid)
+        if repopath == None:
+            rucktalk.error("Repository '%s' does not exist" % repoid)
+            return False
+
+        parser = ConfigParser()
+        parser.read(repopath)
+        parser.remove_section(repoid)
+        if len(parser.sections()) == 0:
+            os.unlink(repopath)
+        else:
+            parser.write(file(repopath, 'w+'))
+
+        rucktalk.message("--- Successfully removed '%s' ---" % repoid)
+
+
+ruckcommand.register(RepoDelCmd)
diff --git a/contrib/ruck/src/ruckcommand.py b/contrib/ruck/src/ruckcommand.py
new file mode 100644
index 0000000..7aa7d68
--- /dev/null
+++ b/contrib/ruck/src/ruckcommand.py
@@ -0,0 +1,641 @@
+###
+### Copyright 2002 Ximian, Inc.
+### Copyright 2008 Aidan Skinner <aidan at skinner.me.uk>
+###
+### This program is free software; you can redistribute it and/or modify
+### it under the terms of the GNU General Public License, version 2,
+### as published by the Free Software Foundation.
+###
+### This program is distributed in the hope that it will be useful,
+### but WITHOUT ANY WARRANTY; without even the implied warranty of
+### MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+### GNU General Public License for more details.
+###
+### You should have received a copy of the GNU General Public License
+### along with this program; if not, write to the Free Software
+### Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307, USA.
+###
+
+import sys
+import os
+import getopt
+import string
+import ruckformat
+import rucktalk
+from packagekit import client
+
+import logging
+
+default_opt_table = [
+    ["",  "version",  "",         "Print client version and exit"],
+    ["V", "verbose",  "",         "Verbose output"],
+    ["p", "no-plugins",  "",      "Don't load yum plugins"],
+    ["C", "cache-only", "",       "Run entirely from cache, don't update cache"],
+    ["",  "normal-output", "",    "Normal output (default)"],
+    ["t", "terse",    "",         "Terse output"],
+    ["",  "quiet",    "",         "Quiet output, print only error messages"],
+    ["",  "read-from-file", "filename",   "Get args from file"],
+    ["",  "read-from-stdin", "",  "Get args from stdin"],
+    ["",  "ignore-rc-file", "",   "Don't read ruck's startup file (~/.ruckrc)"],
+    ["",  "ignore-env", "",       "Ignore the RUCK_ARGS environment variable"],
+    ["?", "help",     "",         "Get help on a specific command"]
+]
+
+default_orthogonal_opts = [["verbose", "no-plugins", "terse", "normal-output", "quiet"]]
+
+
+command_dict = {}
+alias_dict = {}
+
+
+def register(constructor):
+    obj = constructor()
+    name = obj.name()
+    aliases = obj.aliases()
+    hidden = obj.is_hidden()
+    basic = obj.is_basic()
+    description = obj.description_short() or "<No Description Available>"
+    category = obj.category()
+
+    if command_dict.has_key(name):
+        rucktalk.error("Command name collision: '"+name+"'")
+    else:
+        command_dict[name] = (description, constructor, aliases, hidden, basic, category)
+
+    for a in aliases:
+        al = string.lower(a)
+        if command_dict.has_key(al):
+            rucktalk.error("Command/alias collision: '"+a+"'")
+        elif alias_dict.has_key(al):
+            rucktalk.error("Alias collision: '"+a+"'")
+        else:
+            alias_dict[al] = name
+
+
+def construct(name):
+    nl = string.lower(name)
+
+    if alias_dict.has_key(nl):
+        nl = alias_dict[nl]
+
+    if not command_dict.has_key(nl):
+        return None
+
+    cons = command_dict[nl][1]
+
+    return cons()
+
+# It seems bad that this is hard-wired here, but I don't really see
+# any cleaner way around it
+category_data = {"package":["Package management", -1000],
+                 "dependency":["Dependency analysis", 0],
+                 "user":["User management", 0],
+                 "prefs":["Preference management", 0],
+                 "service":["Service management", 0],
+                 "other":["Other", 10000000]}
+
+def command_sort(a, b):
+
+    a_name = string.lower(a[0])
+    b_name = string.lower(b[0])
+
+    a_cat = string.lower(a[2])
+    b_cat = string.lower(b[2])
+
+    if category_data.has_key(a_cat):
+        a_catcode = category_data[a_cat][1]
+    else:
+        a_catcode = 0
+
+    if category_data.has_key(b_cat):
+        b_catcode = category_data[b_cat][1]
+    else:
+        b_catcode = 0
+
+    return cmp(a_catcode, b_catcode) or cmp(a_cat, b_cat) or cmp(a_name, b_name)
+
+def print_command_list(commands, with_categories=0):
+
+    max_len = 0
+    cmd_list = []
+
+    for c in commands:
+        name, aliases, description, category = c
+
+        if aliases:
+            name = name + " (" + string.join(aliases, ", ") + ")"
+
+        cmd_list.append([name, description, category])
+        max_len = max(max_len, len(name))
+
+    desc_len = max_len + 4
+
+    cmd_list.sort(command_sort)
+
+    previous_category = "we will banish all dwarves from the love kingdom"
+
+    for c in cmd_list:
+
+        name, description, category = c
+
+        if with_categories and category != previous_category:
+            if category_data.has_key(category):
+                category_name = category_data[category][0]
+            else:
+                category_name = string.upper(category[0]) + category[1:]
+
+            rucktalk.message("\n" + category_name + " commands:")
+            previous_category = category
+
+        # If, for some reason, the command list is *really* wide (which it never should
+        # be), don't do something stupid.
+        if 79 - desc_len > 10:
+            desc = ruckformat.linebreak(description, 79-desc_len)
+        else:
+            desc = [description]
+
+        desc_first = desc.pop(0)
+        rucktalk.message("  " + string.ljust(name, max_len) + "  " + desc_first)
+        for d in desc:
+            rucktalk.message(" " * desc_len + d)
+
+def usage_basic():
+    rucktalk.message("Usage: ruck <command> <options> ...")
+    rucktalk.message("")
+
+    keys = command_dict.keys()
+
+    if keys:
+        keys.sort()
+        command_list = []
+        for k in keys:
+            description, constructor, aliases, hidden, basic, category  = command_dict[k]
+            if not hidden and basic:
+                command_list.append([k, aliases, description, category])
+
+        rucktalk.message("Some basic commands are:")
+        print_command_list(command_list)
+
+        rucktalk.message("")
+        rucktalk.message("For a more complete list of commands and important options,")
+        rucktalk.message("run \"ruck help\".")
+        rucktalk.message("")
+
+    else:
+        rucktalk.error("<< No commands found --- something is wrong! >>")
+
+def usage_full():
+    rucktalk.message("Usage: ruck <command> <options> ...")
+    rucktalk.message("")
+
+    rucktalk.message("The following options are understood by all commands:")
+    ruckformat.opt_table(default_opt_table)
+
+    keys = command_dict.keys()
+
+    if keys:
+        command_list = []
+        for k in keys:
+            description, constructor, aliases, hidden, basic, category  = command_dict[k]
+            if not hidden:
+                command_list.append([k, aliases, description, category])
+
+        print_command_list(command_list, with_categories=1)
+
+        rucktalk.message("")
+        rucktalk.message("For more detailed information about a specific command,")
+        rucktalk.message("run 'ruck <command name> --help'.")
+        rucktalk.message("")
+
+    else:
+        rucktalk.error("<< No commands found --- something is wrong! >>")
+
+
+def extract_command_from_argv(argv):
+    command = None
+    i = 0
+    unknown_commands = []
+    while i < len(argv) and not command:
+        if argv[i][0] != "-":
+            command = construct(argv[i])
+            if command:
+                argv.pop(i)
+            else:
+                unknown_commands.append(argv[i])
+        else:
+            takes_arg = 0
+            for o in default_opt_table:
+                if not (argv[i][1:] == o[0] or argv[i][2:] == o[1]):
+                    continue
+
+                if o[2] != "":
+                    takes_arg = 1
+                    break
+
+            if takes_arg and string.find(argv[i], "=") == -1:
+                i = i + 1
+
+        i = i + 1
+
+    if not command:
+        map(lambda x:rucktalk.warning("Unknown command '%s'" % x),
+            unknown_commands)
+        rucktalk.warning("No command found on command line.")
+        if "--help" in argv or "-?" in argv:
+            usage_full()
+        else:
+            usage_basic()
+        sys.exit(1)
+
+    return command
+
+###
+### Handle .ruckrc and RUCK_ARGS
+###
+
+def get_user_default_args(argv, command_name):
+
+    # We add arguments to the beginning of argv.  This means we can
+    # override an magically added arg by explicitly putting the
+    # orthogonal arg on the command line.
+    def join_args(arglist, argv):
+        return map(string.strip, arglist + argv)
+
+    # Try to read the .ruckrc file.  It basically works like a .cvsrc file.
+    if "--ignore-rc-file" not in argv:
+        ruckrc_files = (os.path.expanduser("~/.ruckrc"),
+                       os.path.expanduser("~/.rcrc"))
+
+        rc_file = None
+        for f in ruckrc_files:
+            if os.path.exists(f):
+                rc_file = f
+                break
+
+        if rc_file:
+            try:
+                ruckrc = open(rc_file, "r")
+                while 1:
+                    line = ruckrc.readline()
+
+                    # strip out comments
+                    hash_pos = string.find(line, "#")
+                    if hash_pos >= 0:
+                        line = line[0:hash_pos]
+
+                    # skip empty lines
+                    if not line:
+                        break
+
+                    pieces = string.split(line)
+                    if len(pieces) and pieces[0] == command_name:
+                        argv = join_args(pieces[1:], argv)
+                ruckrc.close()
+
+            except IOError:
+                # If we can't open the rc file, that is fine... just
+                # continue as if nothing happened.
+                pass
+
+    if "--ignore-env" not in argv:
+        if os.environ.has_key("RUCK_ARGS"):
+            args = string.split(os.environ["RUCK_ARGS"])
+            argv = join_args(args, argv)
+
+    return argv
+
+###
+### Handle --read-from-file and --read-from-stdin
+###
+
+def expand_synthetic_args(argv):
+
+    ###
+    ### First, walk across our argument list and find any --read-from-file
+    ### options.  For each, read the arguments from the file and insert
+    ### them directly after the --read-from-file option.
+    ###
+
+    i = 0
+    is_file_to_read_from = 0
+    while i < len(argv):
+        arg = argv[i]
+        file_to_read = None
+        if is_file_to_read_from:
+            file_to_read = arg
+            is_file_to_read_from = 0
+        if arg == "--read-from-file":
+            is_file_to_read_from = 1
+        elif string.find(arg, "--read-from-file=") == 0:
+            file_to_read = arg[len("--read-from-file="):]
+            is_file_to_read_from = 0
+
+        if file_to_read:
+            lines = []
+            try:
+                f = open(file_to_read, "r")
+                lines = map(string.strip, f.readlines())
+            except IOError:
+                rucktalk.error("Couldn't open file '%s' to read arguments" % file_to_read)
+                sys.exit(1)
+            argv = argv[:i] + lines + argv[i+1:]
+            i = i + len(lines)
+
+        i = i + 1
+
+    ###
+    ### Next, look for --read-from-stdin options.  If there is more than
+    ### one on the command line, we split our list of options on blank
+    ### lines.
+    ###
+
+    rfs_count = argv.count("--read-from-stdin")
+    if rfs_count > 0:
+        lines = map(string.strip, sys.stdin.readlines())
+
+        i = 0  # position in argv
+        j = 0  # position in lines
+        while i < len(argv):
+
+            if argv[i] == "--read-from-stdin":
+
+                if j < len(lines):
+                    if rfs_count > 1 and "" in lines[j:]:
+                        j1 = j + lines[j:].index("")
+                        argv = argv[:i+1] + lines[j:j1] + argv[i+1:]
+                        j = j1+1
+                    else:
+                        argv = argv[:i+1] + \
+                               filter(lambda x:x!="", lines[j:]) + \
+                               argv[i+1:]
+                        j = len(lines)
+
+
+                rfs_count = rfs_count - 1
+
+            i = i + 1
+
+    ###
+    ### Finally, we filter our all of those --read-from-* arguments
+    ### that we left lying around in argv.
+    ###
+
+    argv = filter(lambda x: \
+                  string.find(x,"--read-from-file") != 0 \
+                  and x != "--read-from-stdin",
+                  argv)
+
+    return argv
+
+
+###
+### The actual Ruckcommand class
+###
+
+class RuckCommand:
+
+    def __init__(self):
+        self.__yum = None
+        self.__pkcon = None
+        self.cache_only = False
+        self.no_plugins = False
+
+    def pkcon(self):
+        if not self.__pkcon:
+            self.__pkcon = client.PackageKitClient()
+        return self.__pkcon
+
+    def name(self):
+        return "Unknown!"
+
+    def aliases(self):
+        return []
+
+    # If is_hidden returns true, the command will not appear in 'usage'
+    # list of available commands.
+    def is_hidden(self):
+        return 0
+
+    def is_basic(self):
+        return 0
+
+    def is_local(self):
+        return 0
+
+    def category(self):
+        return "other"
+
+    def arguments(self):
+        return "..."
+
+    def description_short(self):
+        return ""
+
+    def description_long(self):
+        return ""
+
+    def default_opt_table(self):
+        return default_opt_table
+
+    def local_opt_table(self):
+        return []
+
+    def opt_table(self):
+        return self.default_opt_table() + self.local_opt_table()
+
+
+    def default_orthogonal_opts(self):
+        return default_orthogonal_opts
+
+    def local_orthogonal_opts(self):
+        return []
+
+    def orthogonal_opts(self):
+        return self.default_orthogonal_opts() + self.local_orthogonal_opts()
+
+
+    def usage(self):
+
+        rucktalk.message("")
+        rucktalk.message("Usage: ruck " + self.name() + " <options> " + \
+                       self.arguments())
+        rucktalk.message("")
+
+        description = self.description_long() or self.description_short()
+        if description:
+            description = "'" + self.name() + "': " + description
+            for l in ruckformat.linebreak(description, 72):
+                rucktalk.message(l)
+            rucktalk.message("")
+
+        opts = self.local_opt_table()
+        if opts:
+            rucktalk.message("'" + self.name() + "' Options:")
+            ruckformat.opt_table(opts)
+            rucktalk.message("")
+
+        opts = self.default_opt_table()
+        if opts:
+            rucktalk.message("General Options:")
+            ruckformat.opt_table(opts)
+            rucktalk.message("")
+
+
+
+    def execute(self, server, options_dict, non_option_args):
+        rucktalk.error("Execute not implemented!")
+        sys.exit(1)
+
+    def process_argv(self, argv):
+        ###
+        ### Expand our synthetic args.
+        ### Then compile our list of arguments into something that getopt can
+        ### understand.  Finally, call getopt on argv and massage the results
+        ### in something easy-to-use.
+        ###
+
+        argv = get_user_default_args(argv, self.name())
+
+        opt_table = self.opt_table()
+
+        short_opt_getopt = ""
+        long_opt_getopt  = []
+
+        short2long_dict = {}
+
+        for o in opt_table:
+
+            short_opt = o[0]
+            long_opt  = o[1]
+            opt_desc  = o[2]
+
+            if short_opt:
+
+                if short2long_dict.has_key(short_opt):
+                    rucktalk.error("Short option collision!")
+                    rucktalk.error("-" + short_opt + ", --" + long_opt)
+                    rucktalk.error("  vs.")
+                    rucktalk.error("-" + short_opt + ", --" + short2long_dict[short_opt])
+                    sys.exit(1)
+
+                short2long_dict[short_opt] = long_opt
+                short_opt_getopt = short_opt_getopt + short_opt
+                if opt_desc:
+                    short_opt_getopt = short_opt_getopt + ":"
+
+            if opt_desc:
+                long_opt_getopt.append(long_opt + "=")
+            else:
+                long_opt_getopt.append(long_opt)
+
+        try:
+            optlist, args = getopt.getopt(argv, short_opt_getopt, long_opt_getopt)
+        except getopt.error:
+            did_something = 0
+            for a in argv:
+                if string.find(a,"--") == 0:
+                    if not a[2:] in map(lambda x:x[1], opt_table):
+                        rucktalk.error("Invalid argument " + a)
+                        did_something = 1
+                elif string.find(a, "-") == 0:
+                    if not a[1:] in map(lambda x:x[0], opt_table):
+                        rucktalk.error("Invalid argument " + a)
+                        did_something = 1
+
+            # Just in case something strange went wrong and we weren't
+            # able to describe quite why the options parsing failed,
+            # we print a catch-all error message.
+            if not did_something:
+                rucktalk.error("Invalid arguments")
+
+            self.usage()
+
+            sys.exit(1)
+
+        ###
+        ### Walk through our list of options and replace short options with the
+        ### corresponding long option.
+        ###
+
+        i = 0
+        while i < len(optlist):
+            key = optlist[i][0]
+            if key[0:2] != "--":
+                optlist[i] = ("--" + short2long_dict[key[1:]], optlist[i][1])
+            i = i + 1
+
+
+        ###
+        ### Get the list of "orthogonal" options for this command and, if our
+        ### list of options contains orthogonal elements, remove all but the
+        ### last such option.
+        ### (i.e. if we are handed --quiet --verbose, we drop the --quiet)
+        ###
+
+        optlist.reverse()
+        for oo_list in self.orthogonal_opts():
+            i = 0
+            seen_oo = 0
+            while i < len(optlist):
+                key = optlist[i][0]
+                if key[2:] in oo_list:
+                    if seen_oo:
+                        del optlist[i]
+                        i = i - 1
+                    seen_oo = 1
+                i = i + 1
+        optlist.reverse()
+
+        ###
+        ### Store our options in a dictionary
+        ###
+
+        opt_dict = {}
+
+        for key, value in optlist:
+            opt_dict[key[2:]] = value
+
+
+        return opt_dict, args
+
+class HelpCmd(RuckCommand):
+
+    def name(self):
+        return "help"
+
+    def is_basic(self):
+        return 1
+
+    def is_local(self):
+        return 1
+
+    def description_short(self):
+        return "A list of all of the available commands"
+
+    def execute(self, options_dict, non_option_args):
+        usage_full()
+
+    def usage(self):
+        usage_full()
+
+register(HelpCmd)
+
+
+class PoopCmd(RuckCommand):
+
+    def name(self):
+        return "poop"
+
+    def is_basic(self):
+        return 1
+
+    def is_local(self):
+        return 1
+
+    def is_hidden(self):
+        return 1
+
+    def execute(self, options_dict, non_option_args):
+        os.system("figlet POOP")
+
+register(PoopCmd)
diff --git a/contrib/ruck/src/ruckformat.py b/contrib/ruck/src/ruckformat.py
new file mode 100644
index 0000000..a72f46a
--- /dev/null
+++ b/contrib/ruck/src/ruckformat.py
@@ -0,0 +1,293 @@
+###
+### Copyright 2002 Ximian, Inc.
+### Copyright 2008 Aidan Skinner <aidan at skinner.me.uk>
+###
+### This program is free software; you can redistribute it and/or modify
+### it under the terms of the GNU General Public License, version 2,
+### as published by the Free Software Foundation.
+###
+### This program is distributed in the hope that it will be useful,
+### but WITHOUT ANY WARRANTY; without even the implied warranty of
+### MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+### GNU General Public License for more details.
+###
+### You should have received a copy of the GNU General Public License
+### along with this program; if not, write to the Free Software
+### Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307, USA.
+###
+
+import string
+import re
+import time
+import rucktalk
+
+###
+### Utility functions.  Not really public.
+###
+
+def seconds_to_str(t):
+
+    h = int(t/3600)
+    m = int((t % 3600)/60)
+    s = t % 60
+
+    if h > 0:
+        return "%dh%02dm%0ds" % (h, m, s)
+        return "%ds" % t
+    elif m > 0:
+        return "%dm%02ds" % (m, s)
+    else:
+        return "%ds" % s
+
+def bytes_to_str(x):
+
+    for fmt in ("%db", "%.2fk", "%.2fM", "%.2fg"):
+
+        if x < 1024:
+            return fmt % x
+
+        x = x / 1024.0
+
+    return "!!!"
+
+
+def pad_row(row, col_sizes):
+    return map(string.ljust, row, col_sizes)
+
+
+def clean_row(row, separator):
+    return map(lambda x, sep=separator:string.replace(x,sep,"_"), row)
+
+
+def max_col_widths(table):
+    return reduce(lambda v,w:map(max,v,w),
+                  map(lambda x:map(len,x),table))
+
+
+def stutter(str, N):
+    if N <= 0:
+        return ""
+    return str + stutter(str, N-1)
+
+
+def linebreak(in_str, width):
+
+    str = string.strip(in_str)
+
+    if not str:
+        return []
+
+    if len(str) <= width:
+        return [str]
+
+    if width < len(str) and str[width] == " ":
+        n = width
+    else:
+        n = string.rfind(str[0:width], " ")
+
+    lines = []
+
+    if n == -1:
+        lines.append(str)
+    else:
+        lines.append(str[0:n])
+        lines = lines + linebreak(str[n+1:], width)
+
+    return lines
+
+## Assemble EVRs into strings
+
+def naevr_to_str(naevr):
+    version = ""
+
+    (n,a,e,v,r) = naevr
+
+    if e != '0':
+        version = version + e + ":"
+
+    version = version + v
+
+    if r:
+        version = version + "-" + r
+
+    version = version + '.' + str(a)
+
+    return version
+
+
+## Assemble EVRs into abbreviated strings
+
+def naevr_to_abbrev_str(naevr):
+
+    (n,a,e,v,r) = naevr
+
+    if r and string.find(r, "snap") != -1:
+        r = re.compile(".*(\d\d\d\d)(\d\d)(\d\d)(\d\d)(\d\d)")
+        m = r.match(v) or r.match(r)
+        if m:
+            return "%s-%s-%s, %s:%s" % \
+                   (m.group(1), m.group(2), m.group(3), m.group(4), m.group(5))
+
+    return naevr_to_str(naevr)
+
+
+## Extract data from a package
+
+def package_to_row(pkg, no_abbrev, key_list):
+
+    row = []
+
+    for key in key_list:
+        val = "?"
+        if key == "installed":
+            # FIXME: show newer versions than are installed as 'U'?
+            if (pkg.installed):
+                val = 'I'
+            else:
+                val = 'U'
+        elif key == "repo":
+            val = pkg.repoid
+        elif key == "version":
+            val = pkg.ver
+        elif key == "name":
+            # Trim long names
+            val = pkg.name
+            if not no_abbrev and len(val) > 25:
+                val = val[0:22] + "..."
+
+        row.append(val)
+
+    return row
+
+def package_to_str(pkg, version=True, repo=True):
+    pkg_str = pkg.name
+    if version:
+        if pkg.epoch == '0':
+            pkg_str += "-%s-%s" % (pkg.version, pkg.release)
+        else:
+            pkg_str += "-%s:%s-%s" % (pkg.epoch, pkg.version, pkg.release)
+    pkg_str += ".%s" % pkg.arch
+
+    if repo:
+        pkg_str += " (%s)" % pkg.repoid
+
+    return pkg_str
+
+
+def progress_to_str(pc, completed_size, total_size,
+                    remaining_sec, elapsed_sec, text=None):
+
+    msg = "%3d%%" % pc
+
+    if remaining_sec > 0:
+        hash_max = 10
+    else:
+        hash_max = 20
+    hash_count = int(hash_max * pc / 100)
+    hashes = "#" * hash_count + "-" * (hash_max - hash_count)
+
+    msg = msg + " " + hashes
+
+    if completed_size > 0 and total_size > 0:
+        cs = bytes_to_str(completed_size)
+        ts = bytes_to_str(total_size)
+        msg = msg + " (" + cs + "/" + ts + ")"
+
+    if elapsed_sec > 0:
+        msg = msg + ", " + seconds_to_str(elapsed_sec) + " elapsed"
+
+        if remaining_sec > 0:
+            msg = msg + ", " + seconds_to_str(remaining_sec) + " remain"
+
+            if elapsed_sec > 0 and completed_size > 0:
+                rate = completed_size / elapsed_sec
+                msg = msg + ", " + bytes_to_str(rate) + "/s"
+
+    if text != None:
+        msg += ", " + text
+
+    return msg
+
+
+###
+### Code that actually does something.
+###
+
+def separated(table, separator):
+
+    for r in table:
+        rucktalk.message(string.join(clean_row(r, separator), separator + " "))
+
+
+def aligned(table):
+
+    col_sizes = max_col_widths(table)
+
+    for r in table:
+        rucktalk.message(string.join(pad_row(r, col_sizes), " "))
+
+
+def opt_table(table):
+
+    opt_list = []
+
+    for r in table:
+        opt = "--" + r[1]
+        if r[0]:
+            opt = "-" + r[0] + ", " + opt
+        if r[2]:
+            opt = opt + "=<" + r[2] + ">"
+
+        opt_list.append([opt + "  ", r[3]])
+
+    # By appending [0,0], we insure that this will work even if
+    # opt_list is empty (which it never should be)
+    max_len = apply(max, map(lambda x:len(x[0]), opt_list) + [0,0])
+
+    for opt, desc_str in opt_list:
+
+        if 79 - max_len > 10:
+            desc = linebreak(desc_str, 79 - max_len)
+        else:
+            desc = [desc_str]
+
+        desc_first = desc.pop(0)
+        rucktalk.message(string.ljust(opt, max_len) + desc_first)
+        for d in desc:
+            rucktalk.message(" " * max_len + d)
+
+
+def tabular(headers, table):
+
+    def row_to_string(row, col_sizes):
+        if rucktalk.be_terse:
+            return string.join(row, "|")
+        else:
+            return string.join(pad_row(row, col_sizes), " | ")
+
+    col_sizes = max_col_widths(table)
+
+    if headers and not rucktalk.be_terse:
+        col_sizes = map(max, map(len,headers), col_sizes)
+
+        # print headers
+        rucktalk.message(string.join(pad_row(headers, col_sizes), " | "))
+
+        # print head/body separator
+        rucktalk.message(string.join (map(lambda x:stutter("-",x), col_sizes), "-+-"))
+
+    # print table body
+    for r in table:
+        rucktalk.message(row_to_string(r, col_sizes))
+
+def bool_to_str(b):
+    if b:
+        return 'Yes'
+    else:
+        return 'No'
+
+def bool_to_short_str(b):
+    if b:
+        return 'Y'
+    else:
+        return 'N'
diff --git a/contrib/ruck/src/rucklocks.py b/contrib/ruck/src/rucklocks.py
new file mode 100644
index 0000000..4f76aca
--- /dev/null
+++ b/contrib/ruck/src/rucklocks.py
@@ -0,0 +1,67 @@
+import os.path
+import ruckyum
+
+def add_excludes():
+    yum = ruckyum.get_yum ()
+
+    for (repostr, lock) in get_locks():
+        if repostr == None:
+            repostr = '*'
+
+        for repo in yum.repos.findRepos(repostr):
+            excludes = repo.getAttribute('exclude')
+            if excludes is None:
+                excludes = []
+
+            excludes.append(lock)
+            repo.setAttribute('exclude', excludes)
+
+    for repo in yum.repos.listEnabled():
+        try:
+            yum.excludePackages(repo)
+        except:
+            #sometimes it bitches about pkgSack not existing, wtf?
+            pass
+
+def get_locks():
+    locks = []
+
+    try:
+        f = file(os.path.join(ruckyum.get_yum().conf.cachedir, 'locks'))
+        lines = f.readlines()
+        for line in lines:
+            split_line = line.strip().split(';')
+            repo = split_line[0]
+            if repo == '':
+                repo = None
+
+            locks.append((repo, split_line[1]))
+
+        f.close()
+    except IOError:
+        locks = []
+
+    return locks
+
+def add_lock(lock, repo=None):
+    locks = get_locks()
+    locks.append((repo, lock))
+    save_locks(locks)
+
+def remove_lock(index):
+    locks = get_locks()
+    locks.remove(locks[index])
+    save_locks(locks)
+
+def save_locks(locks):
+    f = file(os.path.join(ruckyum.get_yum().conf.cachedir, 'locks'), 'w+')
+    for (repo, lock) in locks:
+        if repo is None:
+            repo = ''
+
+        f.write("%s;%s\n" % (repo, lock))
+
+    f.close()
+
+def init():
+    ruckyum.init_funcs.append(add_excludes)
diff --git a/contrib/ruck/src/ruckmain.py b/contrib/ruck/src/ruckmain.py
new file mode 100644
index 0000000..7f7a7ab
--- /dev/null
+++ b/contrib/ruck/src/ruckmain.py
@@ -0,0 +1,175 @@
+#!/usr/bin/python
+
+###
+### Copyright 2002 Ximian, Inc.
+### Copyright 2008 Aidan Skinner <aidan at skinner.me.uk>
+###
+### This program is free software; you can redistribute it and/or modify
+### it under the terms of the GNU General Public License, version 2,
+### as published by the Free Software Foundation.
+###
+### This program is distributed in the hope that it will be useful,
+### but WITHOUT ANY WARRANTY; without even the implied warranty of
+### MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+### GNU General Public License for more details.
+###
+### You should have received a copy of the GNU General Public License
+### along with this program; if not, write to the Free Software
+### Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307, USA.
+###
+
+import sys
+import string
+import getpass
+import os
+import traceback
+
+import rucktalk
+import ruckcommand
+
+import urlgrabber
+import urlgrabber.grabber
+
+ruck_name = "Red Carpet Command Line Client"
+ruck_copyright = "Copyright (C) 2000-2003 Ximian Inc.  All Rights Reserved."
+ruck_version = None
+
+def import_commands(ruck_dir):
+    import glob, imp
+    sysdir = ruck_dir + "/commands"
+    sys.path.append(sysdir)
+
+    loaded_modules = []
+
+    # First load modules in our current directory, for developers, and then
+    # out of the system dir.
+    files = glob.glob("*cmds.py")
+    files = files + glob.glob("%s/*cmds.py" % sysdir)
+
+    for file in files:
+        (path, name) = os.path.split(file)
+        (name, ext) = os.path.splitext(name)
+
+        if name in loaded_modules:
+            continue
+
+        (file, filename, data) = imp.find_module(name, [path])
+
+        try:
+            module = imp.load_module(name, file, filename, data)
+        except ImportError:
+            rucktalk.warning("Can't import module " + filename)
+        else:
+            loaded_modules.append(name)
+
+        if file:
+            file.close()
+
+def show_exception(e):
+    if rucktalk.show_verbose:
+        trace = ""
+        exception = ""
+        exc_list = traceback.format_exception_only (sys.exc_type, sys.exc_value)
+        for entry in exc_list:
+            exception += entry
+            tb_list = traceback.format_tb(sys.exc_info()[2])
+            for entry in tb_list:
+                trace += entry
+
+        rucktalk.error(str(e))
+        rucktalk.error(trace)
+    else:
+        rucktalk.error(str(e))
+
+def main(ver, ruck_dir):
+
+    global local
+    global ruck_version
+
+    ruck_version = ver
+
+    if os.environ.has_key("RUCK_DEBUG"):
+        rucktalk.show_debug = 1
+
+    import rucklocks
+    rucklocks.init()
+
+    import_commands(ruck_dir)
+
+    ###
+    ### Grab the option list and extract the first non-option argument that
+    ### looks like a command.  This could get weird if someone passes the name
+    ### of a command as the argument to an option.
+    ###
+
+    argv = sys.argv[1:]
+
+    argv = ruckcommand.expand_synthetic_args(argv)
+
+    if "--version" in argv:
+        print
+        print ruck_name + " " + ruck_version
+        print ruck_copyright
+        print
+        sys.exit(0)
+
+    command = ruckcommand.extract_command_from_argv(argv)
+
+    if "-?" in argv or "--help" in argv:
+        command.usage()
+        sys.exit(0)
+
+    # A hack to suppress extra whitespace when dumping.
+    if command.name() == "dump":
+        rucktalk.be_terse = 1
+
+    argv = ruckcommand.get_user_default_args(argv, command)
+
+    opt_dict, args = command.process_argv(argv)
+
+    ###
+    ### Control verbosity
+    ###
+
+    if opt_dict.has_key("terse"):
+        rucktalk.be_terse = 1
+
+    if opt_dict.has_key("quiet"):
+        rucktalk.show_messages = 0
+        rucktalk.show_warnings = 0
+
+    if opt_dict.has_key("verbose"):
+        rucktalk.show_verbose = 1
+
+    ### Whitespace is nice, so we always print a blank line before
+    ### executing the command
+
+    if not rucktalk.be_terse:
+        rucktalk.message("")
+
+    if opt_dict.has_key("cache-only") or os.getuid() != 0:
+        command.cache_only = True
+    elif opt_dict.has_key("no-plugins"):
+        command.no_plugins = True
+
+    try:
+        command.execute(opt_dict, args)
+    except IOError, e:
+        if e.errno == 13:
+            rucktalk.error("You must be root to execute this command")
+        else:
+            show_exception(e)
+
+        sys.exit(1)
+    except Exception, e:
+        show_exception(e)
+        sys.exit(1)
+
+    ### Whitespace is nice, so we always print a blank line after
+    ### executing the command
+
+    if not rucktalk.be_terse:
+        rucktalk.message("")
+
+
+
diff --git a/contrib/ruck/src/ruckpackagecmds.py b/contrib/ruck/src/ruckpackagecmds.py
new file mode 100644
index 0000000..a55c2a6
--- /dev/null
+++ b/contrib/ruck/src/ruckpackagecmds.py
@@ -0,0 +1,1344 @@
+###
+### Copyright 2002 Ximian, Inc.
+### Copyright 2008 Aidan Skinner <aidan at skinner.me.uk>
+###
+### This program is free software; you can redistribute it and/or modify
+### it under the terms of the GNU General Public License, version 2,
+### as published by the Free Software Foundation.
+###
+### This program is distributed in the hope that it will be useful,
+### but WITHOUT ANY WARRANTY; without even the implied warranty of
+### MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+### GNU General Public License for more details.
+###
+### You should have received a copy of the GNU General Public License
+### along with this program; if not, write to the Free Software
+### Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307, USA.
+###
+
+import sys
+import os
+import re
+import os.path
+import shutil
+import glob
+from ConfigParser import ConfigParser
+import string
+import rucktalk
+import ruckformat
+import ruckcommand
+
+import rpmUtils.arch
+from rpmUtils.miscutils import compareEVR
+from packagekit import enums as pkenums
+
+class PackageCmd(ruckcommand.RuckCommand):
+
+    def is_installed(self, p):
+        pkcon = self.pkcon()
+
+        (n,a,e,v,r) = p.pkgtup
+        # FIXME: this only searches name, not full naevr
+        matches = pkcon.search_name(pkcon.PK_FILTER_INSTALLED, n)
+        return len(matches) > 0
+
+    def find_available_packages(self, list):
+        yum = self.yum()
+
+        exactmatches, matches, unmatched = self.find_packages(list)
+
+        if len(unmatched) > 0:
+            raise Exception("Could not find package '%s'" % unmatched[0])
+
+        installable = unique(exactmatches + matches)
+        archlist = yum.conf.exactarchlist
+
+        installs = {}
+        updates = {}
+
+        for pkg in installable:
+            if yum.rpmdb.installed(po=pkg):
+                continue
+
+            # everything installed that matches the name
+            installedByKey = yum.rpmdb.searchNevra(name=pkg.name)
+            comparable = []
+            for instpo in installedByKey:
+                (n2, a2, e2, v2, r2) = instpo.pkgtup
+                if rpmUtils.arch.isMultiLibArch(a2) == rpmUtils.arch.isMultiLibArch(pkg.arch):
+                    comparable.append(instpo)
+
+            # go through each package
+            if len(comparable) > 0:
+                for instpo in comparable:
+                    if pkg > instpo: # we're newer - this is an update, pass to them
+                        if instpo.name in archlist:
+                            if pkg.arch == instpo.arch:
+                                if not updates.has_key(pkg.name):
+                                    updates[pkg.name] = []
+
+                                updates[pkg.name].append(pkg)
+                        else:
+                            if not updates.has_key(pkg.name):
+                                updates[pkg.name] = []
+
+                            updates[pkg.name].append(pkg)
+                    elif pkg == instpo: # same, ignore
+                        continue
+            else: # we've not got any installed that match n or n+a
+                if not installs.has_key(pkg.name):
+                    installs[pkg.name] = []
+
+                installs[pkg.name].append(pkg)
+
+        pkglist = []
+        for name in installs.keys():
+            pkglist.extend(yum.bestPackagesFromList(installs[name]))
+
+        installs = pkglist
+
+        pkglist = []
+        for name in updates.keys():
+            pkglist.extend(yum.bestPackagesFromList(updates[name]))
+
+        updates = pkglist
+
+        return installs, updates
+
+    def filter_installs(self, list):
+        uninstalled = []
+        installed = []
+
+        for p in list:
+            if self.is_installed(p):
+                installed.append(p)
+            else:
+                uninstalled.append(p)
+
+        return uninstalled, installed
+
+    def find_packages(self, list, installed=False):
+        yum = self.yum()
+
+        if installed:
+            avail = yum.rpmdb.returnPackages()
+        else:
+            avail = yum.pkgSack.returnPackages()
+
+        return self.parsePackages(avail, list, casematch=0)
+
+    def buildPkgRefDict(self, pkgs):
+        """take a list of pkg objects and return a dict the contains all the possible
+           naming conventions for them eg: for (name,i386,0,1,1)
+           dict[name] = (name, i386, 0, 1, 1)
+           dict[name.i386] = (name, i386, 0, 1, 1)
+           dict[name-1-1.i386] = (name, i386, 0, 1, 1)
+           dict[name-1] = (name, i386, 0, 1, 1)
+           dict[name-1-1] = (name, i386, 0, 1, 1)
+           dict[0:name-1-1.i386] = (name, i386, 0, 1, 1)
+           dict[name-0:1-1.i386] = (name, i386, 0, 1, 1)
+           """
+        pkgdict = {}
+        for pkg in pkgs:
+            pkgtup = (pkg.name, pkg.arch, pkg.epoch, pkg.version, pkg.release)
+            (n, a, e, v, r) = pkgtup
+            name = n
+            nameArch = '%s.%s' % (n, a)
+            nameVerRelArch = '%s-%s-%s.%s' % (n, v, r, a)
+            nameVer = '%s-%s' % (n, v)
+            nameVerRel = '%s-%s-%s' % (n, v, r)
+            envra = '%s:%s-%s-%s.%s' % (e, n, v, r, a)
+            nevra = '%s-%s:%s-%s.%s' % (n, e, v, r, a)
+            repoName = '%s:%s' % (pkg.repoid, n)
+            repoNameArch = '%s:%s.%s' % (pkg.repoid, n, a)
+
+            for item in [name, nameArch, nameVerRelArch, nameVer, nameVerRel, envra, nevra, repoName, repoNameArch]:
+                if not pkgdict.has_key(item):
+                    pkgdict[item] = []
+                pkgdict[item].append(pkg)
+
+        return pkgdict
+
+    def parsePackages(self, pkgs, usercommands, casematch=0):
+        pkgdict = self.buildPkgRefDict(pkgs)
+        exactmatch = []
+        matched = []
+        unmatched = []
+        for command in usercommands:
+            if pkgdict.has_key(command):
+                exactmatch.extend(pkgdict[command])
+                del pkgdict[command]
+            else:
+                # anything we couldn't find a match for
+                # could mean it's not there, could mean it's a wildcard
+                if re.match('.*[\*,\[,\],\{,\},\?].*', command):
+                    trylist = pkgdict.keys()
+                    restring = fnmatch.translate(command)
+                    if casematch:
+                        regex = re.compile(restring) # case sensitive
+                    else:
+                        regex = re.compile(restring, flags=re.I) # case insensitive
+                    foundit = 0
+                    for item in trylist:
+                        if regex.match(item):
+                            matched.extend(pkgdict[item])
+                            del pkgdict[item]
+                            foundit = 1
+
+                    if not foundit:
+                        unmatched.append(command)
+
+                else:
+                    # we got nada
+                    unmatched.append(command)
+
+        matched = unique(matched)
+        unmatched = unique(unmatched)
+        exactmatch = unique(exactmatch)
+        return exactmatch, matched, unmatched
+
+    def get_package(self, pkg_tuple):
+        yum = self.yum()
+
+        (n,a,e,v,r) = pkg_tuple
+        matches = yum.pkgSack.searchNevra(name=n, arch=a, epoch=e,
+                                          ver=v, rel=r)
+        return matches[0]
+
+    def get_updates(self, repo=None):
+        yum = self.yum()
+
+        yum.doRpmDBSetup()
+        yum.doUpdateSetup()
+
+        updates = yum.up.updating_dict
+
+        tuples = []
+
+        for new in updates:
+            (n,a,e,v,r) = new
+            matches = yum.pkgSack.searchNevra(name=n, arch=a, epoch=e,
+                                              ver=v, rel=r)
+            new_pkg = matches[0]
+            if repo and new_pkg.repoid != repo:
+                continue
+
+            (n,a,e,v,r) = updates[new][0]
+            matches = yum.rpmdb.searchNevra(name=n, arch=a, epoch=e,
+                                            ver=v, rel=r)
+            old_pkg = matches[0]
+
+            tuples.append((new_pkg, old_pkg))
+
+        return tuples
+
+
+    def resolve_deps(self):
+        rucktalk.message('Resolving dependencies...')
+        yum = self.yum()
+
+        return yum.buildTransaction()
+
+    def show_ts_list(self, items, isdep=False):
+        for pkg in items:
+            msg = "  " + ruckformat.package_to_str(pkg)
+            if isdep:
+                msg += " (dependency)"
+            rucktalk.message(msg)
+
+    def show_ts_packages(self):
+        yum = self.yum()
+
+        yum.tsInfo.makelists()
+
+        list = yum.tsInfo.installed
+        dep_list = yum.tsInfo.depinstalled
+        if len(list) > 0 or len(dep_list) > 0:
+            rucktalk.message('The following packages will be installed:')
+            self.show_ts_list(list)
+            self.show_ts_list(dep_list, True)
+
+        list = yum.tsInfo.updated
+        dep_list = yum.tsInfo.depupdated
+        if len(list) > 0 or len(dep_list) > 0:
+            rucktalk.message('The following packages will be upgraded:')
+            self.show_ts_list(list)
+            self.show_ts_list(dep_list, True)
+
+        list = yum.tsInfo.removed
+        dep_list = yum.tsInfo.depremoved
+        if len(list) > 0 or len(dep_list) > 0:
+            rucktalk.message('The following packages will be removed:')
+            self.show_ts_list(list)
+            self.show_ts_list(dep_list, True)
+
+    def get_pkgs_to_download(self):
+        yum = self.yum()
+
+        downloadpkgs = []
+        for txmbr in yum.tsInfo.getMembers():
+            if txmbr.ts_state in ['i', 'u']:
+                po = txmbr.po
+                if po:
+                    downloadpkgs.append(po)
+
+        return downloadpkgs
+
+    def parse_dep_str(self, dep_str):
+        ret = {}
+
+        info = string.split(dep_str)
+        info_len = len(info)
+        if info_len == 1:
+            ret["dep"] = dep_str
+            return ret
+        elif info_len != 3:
+            raise Exception("Invalid dep string")
+
+        valid_relations = ["=", "<", "<=", ">", ">=", "!="]
+
+        if not info[1] in valid_relations:
+            raise Exception("Invalid relation %s" % info[1])
+
+        ret["dep"] = info[0]
+        ret["relation"] = info[1]
+
+        version_regex = re.compile("^(?:(\d+):)?(.*?)(?:-([^-]+))?$")
+        match = version_regex.match(info[2])
+
+        if match.group(1):
+            ret["has_epoch"] = 1
+            ret["epoch"] = int(match.group(1))
+        else:
+            ret["has_epoch"] = 0
+            ret["epoch"] = 0
+
+        ret["version"] = match.group(2)
+
+        if match.group(3):
+            ret["release"] = match.group(3)
+        else:
+            ret["release"] = ""
+
+        return ret
+
+    def need_prompt(self):
+
+        yum = self.yum()
+
+        # prompt if:
+        #  package was added to fill a dependency
+        #  package is being removed
+        #  package wasn't explictly given on the command line
+        for txmbr in yum.tsInfo.getMembers():
+            if txmbr.isDep or txmbr.ts_state == 'e':
+                return True
+
+        return False
+
+    def gpgsigcheck(self, pkgs):
+        yum = self.yum()
+
+        for p in pkgs:
+            result, errmsg = yum.sigCheckPkg(p)
+            if result == 0:
+                # woo!
+                pass
+            elif result == 1:
+                # FIXME: need to download gpg
+                rucktalk.error("Ignoring missing gpg key.")
+                pass
+            else:
+                yumtalk.error(errmsg)
+                return False
+
+        return True
+
+    def tsInfo_is_empty(self, tsInfo):
+        return len(tsInfo.installed) == 0 and \
+               len(tsInfo.depinstalled) == 0 and \
+               len(tsInfo.updated) == 0 and \
+               len(tsInfo.depupdated) == 0 and \
+               len(tsInfo.removed) == 0 and \
+               len(tsInfo.depremoved) == 0
+
+    def start_transaction(self, dryrun=False, download_only=False):
+        yum = self.yum()
+
+        if not download_only:
+            (rescode, resmsgs) = self.resolve_deps()
+            if rescode != 2:
+                for resmsg in resmsgs:
+                    rucktalk.error(resmsg)
+
+                return False
+
+        self.show_ts_packages()
+
+        if self.tsInfo_is_empty(yum.tsInfo):
+            rucktalk.warning("Nothing to do.")
+            return False
+
+        downloadpkgs = self.get_pkgs_to_download()
+
+        if len(downloadpkgs) > 0:
+            total_size = 0
+
+            for p in downloadpkgs:
+                try:
+                    size = int(p.size())
+                    total_size += size
+                except:
+                    pass
+
+            if total_size > 0:
+                rucktalk.message("\nTotal download size: %s\n" % (ruckformat.bytes_to_str(total_size)))
+
+        if self.need_prompt():
+            answer = raw_input('\nProceed with transaction? (y/N) ')
+            if len(answer) != 1 or answer[0] != 'y':
+                rucktalk.message('Transaction Canceled')
+                return False
+
+        problems = yum.downloadPkgs(downloadpkgs)
+        if len(problems.keys()) > 0:
+            rucktalk.error("Error downloading packages:")
+            for key in problems.keys():
+                for error in unique(problems[key]):
+                    rucktalk.message("  %s: %s" % (key, error))
+            return False
+
+        if download_only:
+            for pkg in downloadpkgs:
+                dest = ruckformat.package_to_str(pkg, repo=False) + ".rpm"
+                shutil.move(pkg.localpath, dest)
+                rucktalk.message ("Downloaded '%s'" % dest)
+
+            return True
+
+        # Check GPG signatures
+        if not self.gpgsigcheck(downloadpkgs):
+            return False
+
+        tsConf = {}
+        for feature in ['diskspacecheck']: # more to come, I'm sure
+                tsConf[feature] = getattr(yum.conf, feature)
+
+        if dryrun:
+            testcb = ruckyum.RPMInstallCallback(output=1)
+            testcb.tsInfo = yum.tsInfo
+            # clean out the ts b/c we have to give it new paths to the rpms
+            del yum.ts
+
+            yum.initActionTs()
+            yum.populateTs(keepold=0) # sigh
+            tserrors = yum.ts.test(testcb, conf=tsConf)
+            del testcb
+
+            if len(tserrors) > 0:
+                errstring = ''
+                for descr in tserrors:
+                    errstring += '  %s\n' % descr
+
+                rucktalk.error(errstring)
+                return False
+
+        else:
+            rucktalk.message('Running Transaction Test')
+
+            testcb = ruckyum.RPMInstallCallback(output=0)
+            testcb.tsInfo = yum.tsInfo
+            # clean out the ts b/c we have to give it new paths to the rpms
+            del yum.ts
+
+            yum.initActionTs()
+            # save our dsCallback out
+            dscb = yum.dsCallback
+            yum.dsCallback = None # dumb, dumb dumb dumb!
+            yum.populateTs(keepold=0) # sigh
+            tserrors = yum.ts.test(testcb, conf=tsConf)
+            del testcb
+
+            if len(tserrors) > 0:
+                errstring = 'Transaction Check Error: '
+                for descr in tserrors:
+                    errstring += '  %s\n' % descr
+
+                rucktalk.error(errstring)
+                return False
+
+            rucktalk.message('Transaction Test Succeeded\n')
+            del yum.ts
+
+            yum.initActionTs() # make a new, blank ts to populate
+            yum.populateTs(keepold=0) # populate the ts
+            yum.ts.check() #required for ordering
+            yum.ts.order() # order
+
+            # put back our depcheck callback
+            yum.dsCallback = dscb
+
+            cb = ruckyum.RPMInstallCallback(output=1)
+            cb.tsInfo = yum.tsInfo
+
+            yum.runTransaction(cb=cb)
+
+        rucktalk.message('\nTransaction Finished')
+        return True
+
+class PackagesCmd(PackageCmd):
+
+    def name(self):
+        return "packages"
+
+    def aliases(self):
+        return ["pa"]
+
+    def category(self):
+        return "basic"
+
+    def is_basic(self):
+        return 1
+
+    def arguments(self):
+        return ""
+
+    def description_short(self):
+        return "List all packages"
+
+    def category(self):
+        return "package"
+
+    def local_opt_table(self):
+        return [["",  "no-abbrev", "", "Do not abbreviate channel or version information"],
+                ["i", "installed-only", "", "Show only installed packages"],
+                ["u", "uninstalled-only", "", "Show only uninstalled packages"],
+                ["",  "sort-by-name", "", "Sort packages by name (default)"],
+                ["",  "sort-by-repo", "", "Sort packages by repository"]]
+
+    def local_orthogonal_opts(self):
+        return [["installed-only", "uninstalled-only"]]
+
+    def execute(self, options_dict, non_option_args):
+        # FIXME: does not know about status, not sure all is right default
+        pkcon = self.pkcon()
+
+        table_rows = []
+        no_abbrev = options_dict.has_key("no-abbrev")
+
+        sort_idx = 2
+        table_headers = ["S", "Repository", "Name", "Version"]
+        table_keys = ["installed", "repo", "name", "version"]
+
+        filter = pkenums.FILTER_NEWEST
+        if options_dict.has_key("uninstalled-only"):
+            filter = filter + pkenums.FILTER_NOT_INSTALLED
+        elif options_dict.has_key("installed-only"):
+            filter = pkenums.FILTER_INSTALLED
+
+        filter = pkenums.FILTER_INSTALLED
+        pkgs = pkcon.get_packages(filter)
+
+        remote_tuples = {}
+
+        for p in pkgs:
+            row = ruckformat.package_to_row(p, no_abbrev, table_keys)
+            table_rows.append(row)
+
+        if table_rows:
+            if options_dict.has_key("sort-by-repo"):
+                table_rows.sort(lambda x,y:cmp(string.lower(x[1]), string.lower(y[1])) or\
+                                cmp(string.lower(x[2]), string.lower(y[2])))
+            else:
+                table_rows.sort(lambda x,y:cmp(string.lower(x[sort_idx]), string.lower(y[sort_idx])))
+            ruckformat.tabular(table_headers, table_rows)
+        else:
+            rucktalk.message("--- No packages found ---")
+
+
+###
+### "search" command
+###
+
+class PackageSearchCmd(PackageCmd):
+
+    def name(self):
+        return "search"
+
+    def aliases(self):
+        return ["se"]
+
+    def is_basic(self):
+        return 1
+
+    def category(self):
+        return "package"
+
+    def arguments(self):
+        return "[package name]"
+
+    def description_short(self):
+        return "Search packages"
+
+    def local_opt_table(self):
+        return [['d', "search-descriptions", '', "Search in package descriptions, as well as package names"],
+                ['i', "installed-only", '', "Search only installed packages"],
+                ['u', "uninstalled-only", '', "Search only uninstalled packages"],
+                ["", "sort-by-name", "", "Sort packages by name (default)"],
+                ["", "sort-by-repo", "", "Sort packages by repository, not by name"],
+                ["", "no-abbrev",    "", "Do not abbreviate channel or version information"]]
+
+    def execute(self, options_dict, non_option_args):
+        pkcon = self.pkcon()
+
+        searchlist = ['name']
+        if options_dict.has_key('search-descriptions'):
+            method = pkcon.search_details
+        else:
+            method = pkcon.search_name
+
+        filter = "none"
+        if options_dict.has_key('installed-only'):
+            filter = "installed"
+        elif options_dict.has_key('uninstalled-only'):
+            filter = '~installed'
+
+        result = {}
+        matches = method(filter, non_option_args[0])
+        if len(matches) > 0:
+            table_keys = ["installed", "repo", "name", "version"]
+            table_rows = []
+            no_abbrev = options_dict.has_key("no-abbrev")
+
+            for pkg in matches:
+                row = ruckformat.package_to_row(pkg['id'], no_abbrev, table_keys)
+                table_rows.append(row)
+
+            if options_dict.has_key("sort-by-repo"):
+                table_rows.sort(lambda x,y:cmp(string.lower(x[1]), string.lower(y[1])) or\
+                                cmp(string.lower(x[2]), string.lower(y[2])))
+            else:
+                table_rows.sort(lambda x,y:cmp(string.lower(x[2]), string.lower(y[2])))
+            ruckformat.tabular(["S", "Repository", "Name", "Version"], table_rows)
+        else:
+            rucktalk.message("--- No packages found ---")
+
+
+
+class PackageListUpdatesCmd(PackageCmd):
+
+    def name(self):
+        return "list-updates"
+
+    def is_basic(self):
+        return 1
+
+    def aliases(self):
+        return ["lu"]
+
+    def arguments(self):
+        return
+
+    def description_short(self):
+        return "List available updates"
+
+    def category(self):
+        return "package"
+
+    def local_opt_table(self):
+        return [["",  "no-abbrev", "", "Do not abbreviate channel or version information"],
+                ["",  "sort-by-name", "", "Sort packages by name (default)"],
+                ["",  "sort-by-repo", "", "Sort packages by repository"]]
+
+    def execute(self, options_dict, non_option_args):
+        no_abbrev = options_dict.has_key("no-abbrev") or \
+                    options_dict.has_key("terse")
+
+        pkcon = self.pkcon()
+
+        table_keys = ["repo", "name", "version"]
+        table_rows = []
+
+        updates = pkcon.get_updates()
+
+        for new_pkg in updates:
+            row = ruckformat.package_to_row(new_pkg['id'],
+                                           no_abbrev, table_keys)
+            table_rows.append(row)
+
+        if len(table_rows):
+            if options_dict.has_key("sort-by-repo"):
+                table_rows.sort(lambda x,y:cmp(string.lower(x[0]), string.lower(y[0])) or\
+                                cmp(string.lower(x[1]), string.lower(y[1])))
+            else:
+                table_rows.sort(lambda x,y:cmp(string.lower(x[1]), string.lower(y[1])))
+
+            ruckformat.tabular(["Repository", "Name",
+                               "Version"],
+                              table_rows)
+        else:
+            rucktalk.message("--- No updates found ---")
+
+class  PackageUpdatesSummaryCmd(PackageCmd):
+
+    def name(self):
+        return "summary"
+
+    def is_basic(self):
+        return 1
+
+    def aliases(self):
+        return ["sum"]
+
+    def arguments(self):
+        return ""
+
+    def description_short(self):
+        return "Display a summary of available updates updates"
+
+    def category(self):
+        return "package"
+
+    def local_opt_table(self):
+        return [["",  "no-abbrev", "", "Do not abbreviate channel or version information"]]
+
+    def execute(self, options_dict, non_option_args):
+        pkcon = self.pkcon()
+
+        updates = pkcon.get_updates()
+        repos = {}
+        for pkg in updates:
+            bits = ruckformat.package_to_row(pkg['id'], False, ['repo'])
+            if not repos.has_key(bits[0]):
+                repos[bits[0]] = [bits[0], 0]
+            repos[bits[0]][1] = str(int(repos[bits[0]][1])+1)
+
+        repolist = []
+        for repo in repos.keys():
+            repolist.append(repos[repo])
+
+        if len(repolist) > 0:
+            repolist.sort(lambda x,y:cmp(y[1], x[1]))
+            headers = ["Repository", "Total"]
+            ruckformat.tabular(headers, repolist)
+        else:
+            rucktalk.message("--- No updates found ---")
+
+
+class PackageInfoCmd(ruckcommand.RuckCommand):
+
+    def name(self):
+        return "info"
+
+    def is_basic(self):
+        return 1
+
+    def aliases(self):
+        return ["if"]
+
+    def category(self):
+        return "package"
+
+    def arguments(self):
+        return "<package-name>"
+
+    def description_short(self):
+        return "Show detailed information about a package"
+
+    def execute(self, options_dict, non_option_args):
+
+        if not non_option_args:
+            self.usage()
+            sys.exit(1)
+
+        pkcon = self.pkcon()
+
+        for a in non_option_args:
+
+            inform = 0
+            channel = None
+            package = None
+
+            plist = pkcon.resolve("none", a)
+
+            if plist == None or len(plist) == 0:
+                rucktalk.message("--- No packages found ---")
+                sys.exit(1)
+
+            ## Find the latest version
+            latest_ver, latest_id = None, None
+            for pkg in plist:
+                row = ruckformat.package_to_row(pkg['id'], False, ['version'])
+                if latest_ver == None or row[0] > latest_ver:
+                    latest_ver= row[0]
+                    latest_id = pkg
+
+            latest = pkcon.get_details(latest_id['id'])[0]
+            details = ruckformat.package_to_row(latest['id'], False, ['name', 'version', 'repo', 'installed'])
+            latest['name'] = details[0]
+            latest['version'] = details[1]
+            latest['repo'] = details[2]
+            latest['installed'] = (details[3] == 'I')
+
+            rucktalk.message("")
+            rucktalk.message("Name: " + latest['name'])
+            rucktalk.message("Version: " + latest['version'])
+
+            if latest_id['installed']:
+                rucktalk.message("Installed: Yes")
+            else:
+                rucktalk.message("Installed: No")
+
+            rucktalk.message("Package size: " + str(latest['size']))
+
+            rucktalk.message("Group: " + latest['group'])
+            rucktalk.message("Homepage: " + latest['url'])
+            rucktalk.message("Description: " + latest['detail'])
+
+class PackageFileCmd(ruckcommand.RuckCommand):
+
+    def name(self):
+        return "package-file"
+
+    def aliases(self):
+        return ["pf"]
+
+    def arguments(self):
+        return "<file> ..."
+
+    def is_basic(self):
+        return 1
+
+    def category(self):
+        return "package"
+
+    def description_short(self):
+        return "List packages that own the files provided"
+
+    def execute(self, options_dict, non_option_args):
+        size = len(non_option_args)
+        if size < 1:
+            self.usage()
+            return False
+
+        table_rows = []
+        yum = self.yum()
+
+        for file in non_option_args:
+            if not os.access (file, os.F_OK):
+                rucktalk.error("File %s does not exist" % file)
+                continue
+
+            matches = yum.rpmdb.searchFiles (file);
+            if not matches:
+                rucktalk.message("No package owns file %s" % file)
+                continue
+
+            for pkg in matches:
+                row = ruckformat.package_to_row(yum, pkg, False, ["name", "version"])
+                if size > 1:
+                    row.insert (0, file)
+                table_rows.append (row)
+
+        if len(table_rows):
+            if size == 1:
+                ruckformat.tabular(["Name", "Version"], table_rows)
+            else:
+                ruckformat.tabular(["File", "Name", "Version"], table_rows)
+
+
+class PackageFileListCmd(ruckcommand.RuckCommand):
+
+    def name(self):
+        return "file-list"
+
+    def aliases(self):
+        return ["fl"]
+
+    def arguments(self):
+        return "<package>"
+
+    def is_basic(self):
+        return 1
+
+    def category(self):
+        return "package"
+
+    def description_short(self):
+        return "List files within a package"
+
+    def execute(self, options_dict, non_option_args):
+        if len(non_option_args) != 1:
+            self.usage()
+            return False
+
+        yum = self.yum()
+        pkg = non_option_args[0]
+
+        matches = yum.rpmdb.searchNevra (name=pkg);
+        if not matches:
+            yum.doSackFilelistPopulate()
+            matches = yum.pkgSack.searchNevra (name=pkg);
+            if not matches:
+                rucktalk.message("--- No package found ---")
+
+        for p in matches:
+            files = None
+
+            # FIXME: returnFileEntries() is always empty for installed
+            # packages
+            if p.repoid == 'installed':
+                files = p.returnSimple('filenames');
+            else:
+                files = p.returnFileEntries();
+
+            if not files:
+                rucktalk.message("--- No files available ---")
+
+            files.sort(lambda x,y:cmp(x,y))
+            for file in files:
+                rucktalk.message(file)
+
+
+### Dep commands ###
+
+class PackageDepCmd(PackageCmd):
+
+    def category(self):
+        return "package"
+
+    def arguments(self):
+        return "<package-dep> ..."
+
+    def is_basic(self):
+        return 1
+
+    def local_opt_table(self):
+        return [["i", "installed-only", "", "Show only installed packages"],
+                ["u", "uninstalled-only", "", "Show only uninstalled packages"]]
+
+    def check_relation(self, di, pkg):
+        que_rel = di["relation"]
+        eq_list = ['=', '<=', '>=']
+        rel_map = {"EQ":"=", "LT":"<", "LE":"<=", "GT":">", "GE":">="}
+
+        for (n, f, (e, v, r)) in pkg.returnPrco(self.dep_type()):
+            if di["dep"] != n:
+                continue
+
+            # match anything if the package dep doesn't have a relation
+            if not f:
+                return True
+
+            pkg_rel = rel_map[f]
+            result = rpmUtils.miscutils.compareEVR((di["epoch"], di["version"], di["release"]),\
+                                                   (e, v, r))
+
+            if result < 0:
+                if que_rel in ['!=', '>', '>=']:
+                    return True
+            elif result > 0:
+                if que_rel in ['!=', '<', '<=']:
+                    return True
+            elif result == 0:
+                if que_rel in eq_list and pkg_rel in eq_list:
+                    return True
+
+        return False
+
+    def execute(self, options_dict, non_option_args):
+        if len(non_option_args) < 1:
+            self.usage()
+            return False
+
+        table_rows = []
+        yum = self.yum()
+
+        for dep in non_option_args:
+            dep_info = self.parse_dep_str(dep)
+
+            matches = []
+            if not options_dict.has_key('installed-only'):
+                matches = self.dep_search_uninstalled (dep_info["dep"]);
+
+            if not options_dict.has_key('uninstalled-only'):
+                matches += self.dep_search_installed (dep_info["dep"]);
+
+            if dep_info.has_key("relation"):
+                matches = [p for p in matches if self.check_relation (dep_info, p)]
+
+            if not matches:
+                rucktalk.message("--- No matches for %s ---" % dep)
+                continue
+
+            for pkg in matches:
+                row = ruckformat.package_to_row(yum, pkg, False, ["name", "version"])
+
+                repo = pkg.repoid
+                if yum.rpmdb.installed(name=pkg.name, arch=pkg.arch):
+                    repo = "installed"
+
+                row.insert(0, repo)
+                table_rows.append (row)
+
+        if len(table_rows):
+            ruckformat.tabular(["Repository", "Name", "Version"], table_rows)
+
+
+class WhatProvidesCmd(PackageDepCmd):
+
+    def name(self):
+        return "what-provides"
+
+    def aliases(self):
+        return ["wp"]
+
+    def description_short(self):
+        return "List packages that provide what you specify"
+
+    def dep_search_installed(self, name):
+        yum = self.yum()
+        return yum.rpmdb.searchProvides(name)
+
+    def dep_search_uninstalled(self, name):
+        yum = self.yum()
+        return yum.pkgSack.searchProvides(name)
+
+    def dep_type(self):
+        return "provides"
+
+
+class WhatRequiresCmd(PackageDepCmd):
+
+    def name(self):
+        return "what-requires"
+
+    def aliases(self):
+        return ["wr"]
+
+    def category(self):
+        return "package"
+
+    def description_short(self):
+        return "List packages that require what you specify"
+
+    def dep_search_installed(self, name):
+        yum = self.yum()
+        return yum.rpmdb.searchRequires(name)
+
+    def dep_search_uninstalled(self, name):
+        yum = self.yum()
+        return yum.pkgSack.searchRequires(name)
+
+    def dep_type(self):
+        return "requires"
+
+class WhatConflictsCmd(PackageDepCmd):
+
+    def name(self):
+        return "what-conflicts"
+
+    def aliases(self):
+        return ["wc"]
+
+    def category(self):
+        return "package"
+
+    def description_short(self):
+        return "List packages that conflict with what you specify"
+
+    def dep_search_installed(self, name):
+        yum = self.yum()
+        return yum.rpmdb.searchConflicts(name)
+
+    def dep_search_uninstalled(self, name):
+        yum = self.yum()
+        return yum.pkgSack.searchConflicts(name)
+
+    def dep_type(self):
+        return "conflicts"
+
+class PackageInfoBaseCmd(PackageCmd):
+
+    def category(self):
+        return "package"
+
+    def arguments(self):
+        return "<package> ..."
+
+    def is_basic(self):
+        return 1
+
+    def local_opt_table(self):
+        return [["i", "installed-only", "", "Show only installed packages"],
+                ["u", "uninstalled-only", "", "Show only uninstalled packages"]]
+
+
+    def execute(self, options_dict, non_option_args):
+        if len(non_option_args) < 1 or (options_dict.has_key('uninstalled-only') and options_dict.has_key('installed-only')):
+            self.usage()
+            return False
+
+        table_rows = []
+        yum = self.yum()
+        dtype = self.dep_type();
+
+        plist = []
+        unmatched1 = None
+        unmatched2 = None
+
+        if not options_dict.has_key('uninstalled-only'):
+            exactmatches, matches, unmatched1 = self.find_packages (non_option_args, installed=True)
+            plist = exactmatches + matches
+
+        if not options_dict.has_key('installed-only'):
+            exactmatches, matches, unmatched2 = self.find_packages (non_option_args, installed=False)
+            plist += exactmatches
+            plist += matches
+
+        if (unmatched1 is None or len(unmatched1) > 0) and (unmatched2 is None or len(unmatched2)) > 0:
+            if unmatched1 != None:
+                arg = unmatched1[0]
+            else:
+                arg = unmatched2[0]
+
+            rucktalk.error("Could not find package '%s'" % arg)
+            return False
+
+        for p in plist:
+            rucktalk.message("--- %s ---" % ruckformat.package_to_str(p))
+            deps = p.returnPrco(dtype)
+
+            if len(deps) == 0:
+                rucktalk.message("\nNo %s found\n" % dtype)
+            else:
+                for dep in deps:
+                    #FIXME: piece of crap prcoPrintable sometimes chokes
+                    try:
+                        rucktalk.message(p.prcoPrintable(dep))
+                    except:
+                        pass
+                rucktalk.message('')
+
+
+class PackageInfoProvidesCmd(PackageInfoBaseCmd):
+
+    def name(self):
+        return "info-provides"
+
+    def aliases(self):
+        return ["ip"]
+
+    def description_short(self):
+        return "List a package's provides"
+
+    def dep_type(self):
+        return "provides"
+
+
+class PackageInfoRequiresCmd(PackageInfoBaseCmd):
+
+    def name(self):
+        return "info-requires"
+
+    def aliases(self):
+        return ["ir"]
+
+    def description_short(self):
+        return "List a package's requires"
+
+    def dep_type(self):
+        return "requires"
+
+class PackageInfoConflictsCmd(PackageInfoBaseCmd):
+
+    def name(self):
+        return "info-conflicts"
+
+    def aliases(self):
+        return ["ic"]
+
+    def description_short(self):
+        return "List a package's conflicts"
+
+    def dep_type(self):
+        return "conflicts"
+
+class PackageInfoObsoletesCmd(PackageInfoBaseCmd):
+
+    def name(self):
+        return "info-obsoletes"
+
+    def aliases(self):
+        return ["io"]
+
+    def description_short(self):
+        return "List a package's obsoletes"
+
+    def dep_type(self):
+        return "obsoletes"
+
+class LockListCmd(PackageCmd):
+
+    def name(self):
+        return "lock-list"
+
+    def is_basic(self):
+        return 1
+
+    def aliases(self):
+        return ["ll"]
+
+    def description_short(self):
+        return "List locks"
+
+    def category(self):
+        return "package"
+
+    def execute(self, options_dict, non_option_args):
+        yum = self.yum()
+
+        table_rows = []
+
+        locks = rucklocks.get_locks()
+
+        i = 1
+        for (repo, lock) in locks:
+            if repo is None:
+                repo = ''
+
+            table_rows.append((str(i), repo, lock))
+            i += 1
+
+        if len(table_rows):
+            ruckformat.tabular(["#", "Repository", "Lock"], table_rows)
+        else:
+            rucktalk.message("--- No locks found ---")
+
+class LockAddCmd(PackageCmd):
+
+    def name(self):
+        return "lock-add"
+
+    def is_basic(self):
+        return 1
+
+    def aliases(self):
+        return ["la"]
+
+    def description_short(self):
+        return "Add a lock"
+
+    def category(self):
+        return "package"
+
+    def local_opt_table(self):
+        return [["r",  "repo", "repo", "Lock only the given repo"]]
+
+    def execute(self, options_dict, non_option_args):
+        if len(non_option_args) != 1:
+            self.usage()
+            return False
+
+        repo = None
+        if options_dict.has_key('repo'):
+            repo = options_dict['repo']
+
+        rucklocks.add_lock(non_option_args[0], repo=repo)
+        rucktalk.message("--- Lock successfully added ---")
+
+
+class LockRemoveCmd(PackageCmd):
+
+    def name(self):
+        return "lock-remove"
+
+    def is_basic(self):
+        return 1
+
+    def aliases(self):
+        return ["lr"]
+
+    def description_short(self):
+        return "Remove a lock"
+
+    def category(self):
+        return "package"
+
+    def execute(self, options_dict, non_option_args):
+        if len(non_option_args) != 1:
+            self.usage()
+            return False
+
+        locks = rucklocks.get_locks()
+        i = int(non_option_args[0]) - 1
+
+        if i >= len(locks):
+            rucktalk.error("Invalid lock %s" % str(i + 1))
+            return False
+
+        rucklocks.remove_lock(i)
+        rucktalk.message("--- Lock successfully removed ---")
+
+
+class OrphansCmd(PackageCmd):
+
+    def name(self):
+        return "orphans"
+
+    def is_basic(self):
+        return 1
+
+    def aliases(self):
+        return ["or"]
+
+    def description_short(self):
+        return "List installed packages that don't exist in repositories"
+
+    def category(self):
+        return "package"
+
+    def execute(self, options_dict, non_option_args):
+        if len(non_option_args) != 0:
+            self.usage()
+            return False
+
+        table_headers = ["Name", "Version"]
+        table_keys = ["name", "version"]
+        table_rows = []
+
+        no_abbrev = options_dict.has_key("no-abbrev")
+
+        yum = self.yum()
+
+        for installed in yum.rpmdb.returnPackages():
+            matches = yum.pkgSack.searchNevra(name=installed.name)
+
+            if len(matches) == 0:
+                table_rows.append(ruckformat.package_to_row(yum, installed, no_abbrev, table_keys))
+
+        if len(table_rows) > 0:
+            ruckformat.tabular(table_headers, table_rows)
+        else:
+            rucktalk.message('--- No orphans found ---')
+
+if not vars().has_key('registered'):
+#    ruckcommand.register(PackageFileCmd)
+    ruckcommand.register(PackagesCmd)
+    ruckcommand.register(PackageSearchCmd)
+    ruckcommand.register(PackageListUpdatesCmd)
+    ruckcommand.register(PackageInfoCmd)
+#    ruckcommand.register(WhatProvidesCmd)
+#    ruckcommand.register(WhatRequiresCmd)
+#    ruckcommand.register(WhatConflictsCmd)
+#    ruckcommand.register(PackageInfoProvidesCmd)
+#    ruckcommand.register(PackageInfoRequiresCmd)
+#    ruckcommand.register(PackageInfoConflictsCmd)
+#    ruckcommand.register(PackageInfoObsoletesCmd)
+#    ruckcommand.register(PackageFileListCmd)
+#    ruckcommand.register(LockListCmd)
+#    ruckcommand.register(LockAddCmd)
+#    ruckcommand.register(LockRemoveCmd)
+#    ruckcommand.register(OrphansCmd)
+#    ruckcommand.register(PackageUpdatesSummaryCmd)
+    registered = True
diff --git a/contrib/ruck/src/rucktalk.py b/contrib/ruck/src/rucktalk.py
new file mode 100644
index 0000000..5e4939a
--- /dev/null
+++ b/contrib/ruck/src/rucktalk.py
@@ -0,0 +1,81 @@
+###
+### Copyright 2002 Ximian, Inc.
+### Copyright 2008 Aidan Skinner <aidan at skinner.me.uk>
+###
+### This program is free software; you can redistribute it and/or modify
+### it under the terms of the GNU General Public License, version 2,
+### as published by the Free Software Foundation.
+###
+### This program is distributed in the hope that it will be useful,
+### but WITHOUT ANY WARRANTY; without even the implied warranty of
+### MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+### GNU General Public License for more details.
+###
+### You should have received a copy of the GNU General Public License
+### along with this program; if not, write to the Free Software
+### Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307, USA.
+###
+
+import sys
+import os
+import stat
+
+show_messages = 1
+show_verbose  = 0
+show_warnings = 1
+show_errors   = 1
+show_debug    = 0
+be_terse      = 0
+
+# Check to see if stdout has been redirected to a file.
+stdout_is_file = 0
+if stat.S_ISREG(os.fstat(sys.stdout.fileno())[stat.ST_MODE]):
+    stdout_is_file = 1
+
+def message(str):
+    if show_messages:
+        print str
+
+esc = ""
+
+def message_status(str):
+    if show_messages and not be_terse:
+        # If we've redirected to a file, don't print escape characters
+        if stdout_is_file:
+            print str
+        else:
+            print esc + "[1G" + str + esc + "[0K",
+            sys.stdout.flush()
+
+def message_finished(str, force_output=0):
+    if show_messages and (force_output or not be_terse):
+        # If we've redirected to a file, don't print escape characters
+        if stdout_is_file:
+            print str
+        else:
+            print esc + "[1G" + str + esc + "[0K"
+
+def verbose(str):
+    if show_verbose:
+        print str
+
+def warning(str):
+    if show_warnings:
+        print "Warning: " + str
+
+def error(str):
+    if show_errors:
+        print "ERROR: " + str
+
+def fatal(str):
+    error(str)
+    sys.exit(1)
+
+def debug(str):
+    if show_debug:
+        print "DEBUG: " + str
+
+def prompt(str):
+    sys.stdout.write(str + " ")
+    sys.stdout.flush()
+    return raw_input()
diff --git a/contrib/ruck/src/rucktransactcmds.py b/contrib/ruck/src/rucktransactcmds.py
new file mode 100644
index 0000000..8fefe47
--- /dev/null
+++ b/contrib/ruck/src/rucktransactcmds.py
@@ -0,0 +1,246 @@
+###
+### Copyright 2002 Ximian, Inc.
+### Copyright 2008 Aidan Skinner <aidan at skinner.me.uk>
+###
+### This program is free software; you can redistribute it and/or modify
+### it under the terms of the GNU General Public License, version 2,
+### as published by the Free Software Foundation.
+###
+### This program is distributed in the hope that it will be useful,
+### but WITHOUT ANY WARRANTY; without even the implied warranty of
+### MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+### GNU General Public License for more details.
+###
+### You should have received a copy of the GNU General Public License
+### along with this program; if not, write to the Free Software
+### Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307, USA.
+###
+
+import sys
+import os
+import os.path
+import glob
+from ConfigParser import ConfigParser
+import string
+import rucktalk
+import ruckformat
+import ruckcommand
+import ruckpackagecmds
+
+class TransactCmd(ruckpackagecmds.PackageCmd):
+    def local_opt_table(self):
+        return [["N",  "dry-run", "", "Perform a dry run"]]
+
+class UpdateCmd(TransactCmd):
+
+    def name(self):
+        return "update"
+
+    def aliases(self):
+        return ["up"]
+
+    def is_basic(self):
+        return 1
+
+    def category(self):
+        return "package"
+
+    def arguments(self):
+        # TODO: this should optionally call UpdatePackages with a list of packages to update
+        return ""
+
+    def description_short(self):
+        return "Perform an update"
+
+    def local_opt_table(self):
+        return []
+
+    def execute(self, options_dict, non_option_args):
+        pkcon = self.pkcon()
+
+        updates = pkcon.get_updates()
+        if (len(updates) == 0):
+            rucktalk.message("--- No updates found ---")
+            exit()
+
+        rucktalk.message("The following packages will be updated:")
+
+        table_keys = ["repo", "name", "version"]
+        table_rows = []
+        for new_pkg in updates:
+            row = ruckformat.package_to_row(new_pkg['id'],
+                                           False, table_keys)
+            table_rows.append(row)
+
+        table_rows.sort(lambda x,y:cmp(string.lower(x[1]), string.lower(y[1])))
+
+        ruckformat.tabular(["Repository", "Name","Version"],
+                          table_rows)
+        # FIXME: this prompt is horrid
+        resp = rucktalk.prompt("Continue? Y/[N]")
+        if (resp == 'y'):
+            # FIXME: needs to deal with progress better
+            pkcon.update_system()
+        else:
+            rucktalk.message("Update aborted")
+
+ruckcommand.register(UpdateCmd)
+
+
+class InstallCmd(TransactCmd):
+
+    def name(self):
+        return "install"
+
+    def aliases(self):
+        return ["in"]
+
+    def is_basic(self):
+        return 1
+
+    def category(self):
+        return "package"
+
+    def arguments(self):
+        return "<package> ..."
+
+    def description_short(self):
+        return "Perform an install"
+
+    def local_opt_table(self):
+        return []
+
+    def separate_args(self, args):
+        installs = []
+        removals = []
+
+        for arg in args:
+            if arg.startswith('~'):
+                removals.append(arg[1:])
+            else:
+                installs.append(arg)
+
+        return installs, removals
+
+    def execute(self, options_dict, non_option_args):
+        if len(non_option_args) < 1:
+            self.usage()
+            return 1
+
+        pk = self.pkcon()
+
+        for arg in non_option_args:
+            if os.path.exists(arg):
+                rucktalk.error("This hasn't been implemented yet") # FIXME
+            else:
+                installs, removals = self.separate_args(non_option_args)
+
+                pkids = pk.Resolve('none', installs)
+                if len(pkids) > 0:
+                    pk.InstallPackages(pkids)
+                else:
+                    rucktalk.error("No packages found")
+                    return 1
+
+                print "Removing"
+                print removals
+                pk.RemovePackages(removals)
+
+ruckcommand.register(InstallCmd)
+
+
+class RemoveCmd(TransactCmd):
+
+    def name(self):
+        return "remove"
+
+    def aliases(self):
+        return ["rm"]
+
+    def is_basic(self):
+        return 1
+
+    def category(self):
+        return "package"
+
+    def arguments(self):
+        return "<package> ..."
+
+    def description_short(self):
+        return "Perform a removal"
+
+    def execute(self, options_dict, non_option_args):
+        if len(non_option_args) < 1:
+            self.usage()
+            return 1
+
+        yum = self.yum()
+
+        exactmatches, matches, unmatched = self.find_packages(non_option_args, installed=1)
+        if len(unmatched) > 0:
+            rucktalk.error("Could not find package '%s'" % unmatched[0])
+            return False
+
+        plist = exactmatches + matches
+
+        for p in plist:
+            yum.remove(p)
+
+        self.start_transaction(dryrun=options_dict.has_key('dry-run'))
+
+#ruckcommand.register(RemoveCmd)
+
+class PackageSolveDepsCmd(TransactCmd):
+
+    def name(self):
+        return "solvedeps"
+
+    def aliases(self):
+        return ["solve"]
+
+    def is_basic(self):
+        return 0
+
+    def category(self):
+        return "dependency"
+
+    def arguments(self):
+        return "<package-dep>"
+
+    def description_short(self):
+        return "Resolve dependencies for libraries"
+
+    def execute(self, options_dict, non_option_args):
+        if len(non_option_args) < 1:
+            self.usage()
+            return False
+
+        plist = []
+        yum = self.yum()
+
+        for dep in non_option_args:
+            if yum.returnInstalledPackagesByDep (dep):
+                continue
+
+            try:
+                pkg = yum.returnPackageByDep(dep)
+                plist.append(pkg.name)
+            except:
+                rucktalk.error("Unable to satisfy requirement '%s'" % dep)
+                return False
+
+        installs, updates = self.find_available_packages(plist)
+        if not installs and not updates:
+            rucktalk.message("Requirements are already met on the system.");
+            return True
+
+        for i in installs:
+            yum.install(i)
+
+        for u in updates:
+            exactmatches, matches, unmatched = self.find_packages([u.name], installed=True)
+            yum.tsInfo.addUpdate(u, exactmatches[0])
+
+        self.start_transaction(dryrun=options_dict.has_key('dry-run'))
+
+#ruckcommand.register(PackageSolveDepsCmd)
diff --git a/contrib/ruck/src/ruckyum.py b/contrib/ruck/src/ruckyum.py
new file mode 100644
index 0000000..7332901
--- /dev/null
+++ b/contrib/ruck/src/ruckyum.py
@@ -0,0 +1,295 @@
+import sys
+import os
+
+import rucktalk
+import ruckformat
+
+import rpm
+from yum.constants import *
+from i18n import _
+
+__yum = None
+init_funcs = []
+
+
+def get_yum(plugins=True, repos=True, cache_only=False):
+    global __yum
+    global init_funcs
+
+    if __yum is None:
+        import yum
+        __yum = yum.YumBase()
+        __yum.logger.disabled = 1
+        __yum.verbose_logger.disabled = 1
+
+        __yum.doConfigSetup(init_plugins=plugins)
+
+        __yum.repos.setProgressBar(RuckMeter())
+        __yum.repos.callback = CacheProgressCallback()
+        __yum.dsCallback = DepSolveProgressCallback()
+
+        if cache_only or not repos:
+            __yum.conf.cache = 1
+
+        __yum.doTsSetup()
+        __yum.doRpmDBSetup()
+
+        if repos:
+            __yum.doRepoSetup()
+            __yum.doSackSetup()
+
+        for func in init_funcs:
+                func()
+
+    return __yum
+
+
+
+
+from urlgrabber.progress import BaseMeter
+class RuckMeter(BaseMeter):
+
+    def __init__(self, fo=sys.stdout):
+        BaseMeter.__init__(self)
+        self.fo = fo
+        self.last_text = None
+
+    def _do_start(self, now=None):
+        if self.text is not None:
+            text = self.text
+        else:
+            text = self.basename
+
+        rucktalk.message(text)
+
+    def _do_update(self, amount_read, now=None):
+        rucktalk.message_status(ruckformat.progress_to_str(self.re.fraction_read() * 100,
+                                                         self.last_amount_read, self.size, self.re.remaining_time(),
+                                                         self.re.elapsed_time()))
+
+
+
+
+    def _do_end(self, amount_read, now=None):
+        rucktalk.message_status(ruckformat.progress_to_str(self.re.fraction_read() * 100,
+                                                         self.last_amount_read, self.size, self.re.remaining_time(),
+                                                         self.re.elapsed_time()))
+
+        self.fo.write('\n\n')
+        self.fo.flush()
+
+class CacheProgressCallback:
+
+    '''
+    The class handles text output callbacks during metadata cache updates.
+    '''
+
+    def __init__(self):
+        self.last_text = None
+
+    def log(self, level, message):
+        pass
+
+    def errorlog(self, level, message):
+        rucktalk.error(message)
+
+    def filelog(self, level, message):
+        pass
+
+    def progressbar(self, current, total, name=None):
+        if current > total:
+            return
+
+        msg = 'Updating metadata'
+        if name != None:
+            msg = "Updating repository: %s" % name
+
+        if msg != self.last_text:
+            rucktalk.message_finished(msg)
+            self.last_text = msg
+
+        rucktalk.message_status(ruckformat.progress_to_str(float(current) / float(total) * 100,
+                                                         -1, -1, -1, -1))
+        if current == total:
+            rucktalk.message('\n')
+            self.last_text = None
+
+class RPMInstallCallback:
+    def __init__(self, output=1):
+        self.output = output
+        self.callbackfilehandles = {}
+        self.total_actions = 0
+        self.total_installed = 0
+        self.installed_pkg_names = []
+        self.total_removed = 0
+        self.last_message = None
+
+        self.myprocess = { TS_UPDATE : 'Updating',
+                           TS_ERASE: 'Erasing',
+                           TS_INSTALL: 'Installing',
+                           TS_TRUEINSTALL : 'Installing',
+                           TS_OBSOLETED: 'Obsoleted',
+                           TS_OBSOLETING: 'Installing'}
+        self.mypostprocess = { TS_UPDATE: 'Updated',
+                               TS_ERASE: 'Erased',
+                               TS_INSTALL: 'Installed',
+                               TS_TRUEINSTALL: 'Installed',
+                               TS_OBSOLETED: 'Obsoleted',
+                               TS_OBSOLETING: 'Installed'}
+
+        self.tsInfo = None # this needs to be set for anything else to work
+
+    def _dopkgtup(self, hdr):
+        tmpepoch = hdr['epoch']
+        if tmpepoch is None: epoch = '0'
+        else: epoch = str(tmpepoch)
+
+        return (hdr['name'], hdr['arch'], epoch, hdr['version'], hdr['release'])
+
+    def _makeHandle(self, hdr):
+        handle = '%s:%s.%s-%s-%s' % (hdr['epoch'], hdr['name'], hdr['version'],
+          hdr['release'], hdr['arch'])
+
+        return handle
+
+    def _localprint(self, msg):
+        if self.output:
+            rucktalk.message(msg)
+
+    def show_progress(self, percent, process, name):
+        msg = "(%s/%s) %s: %s" % (self.total_installed + self.total_removed, self.total_actions, process, name)
+        rucktalk.message_status(ruckformat.progress_to_str(percent, -1, -1, -1, -1, text=msg))
+
+    def callback(self, what, bytes, total, h, user):
+        if what == rpm.RPMCALLBACK_TRANS_START:
+            if bytes == 6:
+                self.total_actions = total
+
+        elif what == rpm.RPMCALLBACK_TRANS_PROGRESS:
+            pass
+
+        elif what == rpm.RPMCALLBACK_TRANS_STOP:
+            pass
+
+        elif what == rpm.RPMCALLBACK_INST_OPEN_FILE:
+
+            hdr = None
+            if h is not None:
+                hdr, rpmloc = h
+                handle = self._makeHandle(hdr)
+                fd = os.open(rpmloc, os.O_RDONLY)
+                self.callbackfilehandles[handle]=fd
+                self.total_installed += 1
+                self.installed_pkg_names.append(hdr['name'])
+                return fd
+            else:
+                self._localprint(_("No header - huh?"))
+
+        elif what == rpm.RPMCALLBACK_INST_CLOSE_FILE:
+            hdr = None
+            if h is not None:
+                hdr, rpmloc = h
+                handle = self._makeHandle(hdr)
+                os.close(self.callbackfilehandles[handle])
+                fd = 0
+
+                if self.output:
+                    rucktalk.message('')
+
+        elif what == rpm.RPMCALLBACK_INST_PROGRESS:
+            if h is not None:
+                # If h is a string, we're repackaging.
+                # Why the RPMCALLBACK_REPACKAGE_PROGRESS flag isn't set, I have no idea
+                if type(h) == type(""):
+                    if total == 0:
+                        percent = 0
+                    else:
+                        percent = (bytes*100L)/total
+                    if self.output and sys.stdout.isatty():
+                        self.show_progress(percent, 'Repackage', h)
+
+                        if bytes == total:
+                            sys.stdout.write('\n')
+                            sys.stdout.flush()
+                else:
+                    hdr, rpmloc = h
+                    if total == 0:
+                        percent = 0
+                    else:
+                        percent = (bytes*100L)/total
+                    pkgtup = self._dopkgtup(hdr)
+
+                    txmbrs = self.tsInfo.getMembers(pkgtup=pkgtup)
+                    for txmbr in txmbrs:
+                        try:
+                            process = self.myprocess[txmbr.output_state]
+                        except KeyError, e:
+                            rucktalk.message("Error: invalid output state: %s for %s" % \
+                                            (txmbr.output_state, hdr['name']))
+                        else:
+                            if self.output and (sys.stdout.isatty() or bytes == total):
+                                self.show_progress(percent, process, hdr['name'])
+
+
+        elif what == rpm.RPMCALLBACK_UNINST_START:
+            pass
+
+        elif what == rpm.RPMCALLBACK_UNINST_PROGRESS:
+            pass
+
+        elif what == rpm.RPMCALLBACK_UNINST_STOP:
+            self.total_removed += 1
+
+            if self.output and sys.stdout.isatty():
+                if h not in self.installed_pkg_names:
+                    process = "Removing"
+                else:
+                    process = "Cleanup"
+                percent = 100
+
+                self.show_progress(percent, process, h)
+                rucktalk.message('')
+
+        elif what == rpm.RPMCALLBACK_REPACKAGE_START:
+            pass
+        elif what == rpm.RPMCALLBACK_REPACKAGE_STOP:
+            pass
+        elif what == rpm.RPMCALLBACK_REPACKAGE_PROGRESS:
+            pass
+
+
+class DepSolveProgressCallback:
+    """provides text output callback functions for Dependency Solver callback"""
+
+    def __init__(self):
+        self.loops = 0
+
+    def pkgAdded(self, pkgtup, mode):
+        pass
+
+    def start(self):
+        self.loops += 1
+
+    def tscheck(self):
+        pass
+
+    def restartLoop(self):
+        pass
+
+    def end(self):
+        pass
+
+    def procReq(self, name, formatted_req):
+        pass
+
+    def unresolved(self, msg):
+        pass
+
+    def procConflict(self, name, confname):
+        pass
+
+    def transactionPopulation(self):
+        pass
+
+    def downloadHeader(self, name):
+        rucktalk.message("Downloading header for '%s'" % name)
commit 0617678109bbb510cfdac83f382b22258ce82579
Author: Aidan Skinner <aidan at skinner.me.uk>
Date:   Sun Dec 14 23:35:03 2008 +0000

    Make get_packages call GetPackages, not GetUpdates. That's what get_updates is for.

diff --git a/lib/python/packagekit/client.py b/lib/python/packagekit/client.py
index 6255dd3..a740592 100644
--- a/lib/python/packagekit/client.py
+++ b/lib/python/packagekit/client.py
@@ -315,7 +315,7 @@ class PackageKitClient:
 
     def get_packages(self, filters=FILTER_NONE, exit_handler=None):
         '''Return all packages'''
-        return self._run_transaction("GetUpdates", [filters], exit_handler)
+        return self._run_transaction("GetPackages", [filters], exit_handler)
 
     def update_system(self, exit_handler=None):
         '''Update the system'''
commit df1e4b4dba2da912867dd813d62332f2ae0f7c2c
Author: A S Alam <aalam at redhat.com>
Date:   Sat Dec 13 05:47:18 2008 +0000

    translation for Punjabi Language by A S Alam! Very bad method to submit:-(
    
    Transmitted-via: Transifex (translate.fedoraproject.org)

diff --git a/po/pa.po b/po/pa.po
new file mode 100644
index 0000000..53e1039
--- /dev/null
+++ b/po/pa.po
@@ -0,0 +1,408 @@
+# Copyright (C) YEAR THE PACKAGE'S COPYRIGHT HOLDER
+# This file is distributed under the same license as the PACKAGE package.
+#
+# Amanpreet Singh Alam <aalam at users.sf.net>, 2008.
+msgid ""
+msgstr ""
+"Project-Id-Version: packagekit.master\n"
+"Report-Msgid-Bugs-To: \n"
+"POT-Creation-Date: 2008-11-09 12:10+0000\n"
+"PO-Revision-Date: 2008-12-03 06:54+0530\n"
+"Last-Translator: Amanpreet Singh Alam <aalam at users.sf.net>\n"
+"Language-Team: Punjabi/Panjabi <punjabi-l10n at users.sf.net>\n"
+"MIME-Version: 1.0\n"
+"Content-Type: text/plain; charset=UTF-8\n"
+"Content-Transfer-Encoding: 8bit\n"
+"X-Generator: Lokalize 0.2\n"
+"Plural-Forms: nplurals=2; plural=n != 1;\n"
+
+#: ../policy/org.freedesktop.packagekit.policy.in.h:1
+msgid "Accept EULA"
+msgstr "EULA ਮਨਜ਼ੂਰ"
+
+#: ../policy/org.freedesktop.packagekit.policy.in.h:2
+msgid "Authentication is required to accept a EULA"
+msgstr "ਪਰਮਾਣਕਿਤਾ ਲਈ EULA ਮਨਜ਼ੂਰ ਕਰਨਾ ਲਾਜ਼ਮੀ"
+
+#: ../policy/org.freedesktop.packagekit.policy.in.h:3
+msgid "Authentication is required to change software source parameters"
+msgstr "ਸਾਫਟਵੇਅਰ ਸਰੋਤ ਬਦਲਣ ਲਈ ਪਰਮਾਣਕਿਤਾ ਲਾਜ਼ਮੀ ਹੈ"
+
+#: ../policy/org.freedesktop.packagekit.policy.in.h:4
+msgid "Authentication is required to install a local file"
+msgstr "ਇੱਕ ਲੋਕਲ ਫਾਇਲ ਇੰਸਟਾਲ ਕਰਨ ਲਈ ਪਰਮਾਣਕਿਤਾ ਲਾਜ਼ਮੀ ਹੈ"
+
+#: ../policy/org.freedesktop.packagekit.policy.in.h:5
+msgid "Authentication is required to install a package"
+msgstr "ਇੱਕ ਪੈਕੇਜ ਇੰਸਟਾਲ ਕਰਨ ਲਈ ਪਰਮਾਣਕਿਤਾ ਲਾਜ਼ਮੀ ਹੈ"
+
+#: ../policy/org.freedesktop.packagekit.policy.in.h:6
+msgid "Authentication is required to install a security signature"
+msgstr "ਇੱਕ ਸੁਰੱਖਿਆ ਅੱਪਡੇਟ ਲਈ ਪਰਮਾਣਕਿਤਾ ਲਾਜ਼ਮੀ ਹੈ"
+
+#: ../policy/org.freedesktop.packagekit.policy.in.h:7
+msgid "Authentication is required to refresh the package lists"
+msgstr "ਪੈਕੇਜ ਲਿਸਟ ਤਾਜ਼ਾ ਕਰਨ ਲਈ ਪਰਮਾਣਕਿਤਾ ਲਾਜ਼ਮੀ ਹੈ"
+
+#: ../policy/org.freedesktop.packagekit.policy.in.h:8
+msgid "Authentication is required to remove packages"
+msgstr "ਪੈਕੇਜ ਹਟਾਉਣ ਵਾਸਤੇ ਪਰਮਾਣਕਿਤਾ ਲਾਜ਼ਮੀ ਹੈ"
+
+#: ../policy/org.freedesktop.packagekit.policy.in.h:9
+msgid "Authentication is required to rollback a transaction"
+msgstr "ਇੱਕ ਟਰਾਂਜ਼ਿਸ਼ਨ ਵਾਪਸ ਲੈਣ ਲਈ ਪਰਮਾਣਕਿਤਾ ਲਾਜ਼ਮੀ ਹੈ"
+
+#: ../policy/org.freedesktop.packagekit.policy.in.h:10
+msgid "Authentication is required to update all packages"
+msgstr "ਸਭ ਪੈਕੇਜ ਅੱਪਡੇਟ ਕਰਨ ਲਈ ਪਰਮਾਣਕਿਤਾ ਲਾਜ਼ਮੀ ਹੈ"
+
+#: ../policy/org.freedesktop.packagekit.policy.in.h:11
+msgid "Authentication is required to update packages"
+msgstr "ਪੈਕੇਜ ਅੱਪਡੇਟ ਕਰਨ ਲਈ ਪਰਮਾਣਕਿਤਾ ਲਾਜ਼ਮੀ ਹੈ"
+
+#: ../policy/org.freedesktop.packagekit.policy.in.h:12
+msgid "Change software source parameters"
+msgstr "ਸਾਫਟਵੇਅਰ ਸਰੋਤ ਪੈਰਾਮੀਟਰ ਬਦਲੋ"
+
+#: ../policy/org.freedesktop.packagekit.policy.in.h:13
+msgid "Further authentication is required to install an untrusted local file"
+msgstr "ਇੱਕ ਬੇਭਰੋਸੇਯੋਗ ਲੋਕਲ ਫਾਇਲ ਇੰਸਟਾਲ ਕਰਨ ਲਈ ਹੋਰ ਪਰਮਾਣਕਿਤਾ ਦੀ ਲੋੜ ਹੈ"
+
+#: ../policy/org.freedesktop.packagekit.policy.in.h:14
+msgid "Install local file"
+msgstr "ਲੋਕਲ ਫਾਇਲ ਇੰਸਟਾਲ ਕਰੋ"
+
+#: ../policy/org.freedesktop.packagekit.policy.in.h:15
+msgid "Install package"
+msgstr "ਪੈਕੇਜ ਇੰਸਟਾਲ ਕਰੋ"
+
+#: ../policy/org.freedesktop.packagekit.policy.in.h:16
+msgid "Install security signature"
+msgstr "ਸੁਰੱਖਿਆ ਦਸਤਖਤ ਇੰਸਟਾਲ ਕਰੋ"
+
+#: ../policy/org.freedesktop.packagekit.policy.in.h:17
+msgid "Install untrusted local file"
+msgstr "ਬੇਭਰੋਸੇਯੋਗ ਲੋਕਲ ਫਾਇਲ ਇੰਸਟਾਲ ਕਰੋ"
+
+#: ../policy/org.freedesktop.packagekit.policy.in.h:18
+msgid "Refresh package lists"
+msgstr "ਪੈਕੇਜ ਲਿਸਟ ਤਾਜ਼ਾ ਕਰੋ"
+
+#: ../policy/org.freedesktop.packagekit.policy.in.h:19
+msgid "Remove package"
+msgstr "ਪੈਕੇਜ ਹਟਾਓ"
+
+#: ../policy/org.freedesktop.packagekit.policy.in.h:20
+msgid "Rollback to a previous transaction"
+msgstr "ਇੱਕ ਪਿਛਲੀ ਟਰਾਂਜ਼ਿਸ਼ਨ ਵਾਪਸ ਲਵੋ"
+
+#: ../policy/org.freedesktop.packagekit.policy.in.h:21
+msgid "Update all packages"
+msgstr "ਸਭ ਪੈਕੇਜ ਅੱਪਡੇਟ ਕਰੋ"
+
+#: ../policy/org.freedesktop.packagekit.policy.in.h:22
+msgid "Update package"
+msgstr "ਪੈਕੇਜ ਅੱਪਡੇਟ ਕਰੋ"
+
+#: ../client/pk-console.c:224
+msgid "Update detail"
+msgstr "ਅੱਪਡੇਟ ਵੇਰਵਾ"
+
+#: ../client/pk-console.c:425
+msgid "A system restart is required"
+msgstr "ਸਿਸਟਮ ਮੁੜ-ਚਾਲੂ ਕਰਨ ਦੀ ਲੋੜ ਹੈ"
+
+#: ../client/pk-console.c:427
+msgid "A logout and login is required"
+msgstr "ਲਾਗ-ਆਉਟ ਅਤੇ ਲਾਗਇਨ ਕਰਨ ਦੀ ਲੋੜ ਹੈ"
+
+#: ../client/pk-console.c:429
+msgid "An application restart is required"
+msgstr "ਇੱਕ ਐਪਲੀਕੇਸ਼ਨ ਮੁੜ-ਚਾਲੂ ਕਰਨ ਦੀ ਲੋੜ ਹੈ"
+
+#: ../client/pk-console.c:474
+#, c-format
+msgid "Please enter a number from 1 to %i: "
+msgstr "1 ਤੋਂ %i ਤੱਕ ਨੰਬਰ ਦਿਓ ਜੀ:"
+
+#: ../client/pk-console.c:524
+msgid "Could not find a package match"
+msgstr "ਇੱਕ ਰਲਦਾ ਪੈਕੇਜ ਨਹੀਂ ਲੱਭਿਆ ਜਾ ਸਕਿਆ"
+
+#: ../client/pk-console.c:538
+msgid "There are multiple package matches"
+msgstr "ਕਈ ਰਲਦੇ ਪੈਕੇਜ ਲੱਭੇ ਹਨ"
+
+#. find out what package the user wants to use
+#: ../client/pk-console.c:545
+msgid "Please enter the package number: "
+msgstr "ਪੈਕੇਜ ਨੰਬਰ ਦਿਓ ਜੀ:"
+
+#: ../client/pk-console.c:561
+msgid ""
+"Could not find a package with that name to install, or package already "
+"installed"
+msgstr "ਉਸ ਨਾਂ ਦਾ ਪੈਕੇਜ ਇੰਸਟਾਲ ਕਰਨ ਲਈ ਲੱਭਿਆ ਜਾਂ ਪਹਿਲਾਂ ਹੀ ਇੰਸਟਾਲ ਹੈ"
+
+#: ../client/pk-console.c:643
+msgid "Could not find a package with that name to remove"
+msgstr "ਉਸ ਨਾਂ ਦਾ ਪੈਕੇਜ ਹਟਾਉਣ ਲਈ ਲੱਭਿਆ ਨਹੀਂ ਜਾ ਸਕਿਆ"
+
+#: ../client/pk-console.c:683
+msgid "The following packages have to be removed"
+msgstr "ਹੇਠ ਦਿੱਤੇ ਪੈਕੇਜ ਹਟਾਏ ਜਾ ਚੁੱਕੇ ਹਨ"
+
+#. get user input
+#: ../client/pk-console.c:692
+msgid "Okay to remove additional packages?"
+msgstr "ਹੋਰ ਪੈਕੇਜ ਹਟਾਉਣ ਲਈ ਮਨਜ਼ੂਰੀ ਹੈ?"
+
+#: ../client/pk-console.c:696
+msgid "Cancelled!"
+msgstr "ਰੱਦ ਕੀਤਾ!"
+
+#: ../client/pk-console.c:718
+msgid "Could not find a package with that name to update"
+msgstr "ਉਸ ਨਾਂ ਦਾ ਪੈਕੇਜ ਅੱਪਡੇਟ ਕਰਨ ਲਈ ਲੱਭਿਆ ਨਹੀਂ ਜਾ ਸਕਿਆ"
+
+#: ../client/pk-console.c:736
+msgid "Could not find what packages require this package"
+msgstr "ਇਸ ਪੈਕੇਜ ਲਈ ਲੋੜੀਦਾ ਪੈਕੇਜ ਲੱਭਿਆ ਨਹੀਂ ਜਾ ਸਕਿਆ"
+
+#: ../client/pk-console.c:754
+msgid "Could not get dependencies for this package"
+msgstr "ਇਸ ਪੈਕੇਜ ਲਈ ਨਿਰਭਰਤਾ ਲਈ ਨਹੀਂ ਜਾ ਸਕੀ"
+
+#: ../client/pk-console.c:772
+msgid "Could not find details for this package"
+msgstr "ਇਸ ਪੈਕੇਜ ਲਈ ਵੇਰਵਾ ਲੱਭਿਆ ਨਹੀਂ ਜਾ ਸਕਿਆ"
+
+#: ../client/pk-console.c:790
+#, c-format
+msgid "Could not find the files for this package"
+msgstr "ਇਸ ਪੈਕੇਜ ਲਈ ਫਾਇਲਾਂ ਲੱਭੀਆਂ ਨਹੀਂ ਜਾ ਸਕੀਆਂ"
+
+#: ../client/pk-console.c:870
+msgid "Package description"
+msgstr "ਪੈਕੇਜ ਵੇਰਵਾ"
+
+#: ../client/pk-console.c:893
+msgid "Package files"
+msgstr "ਪੈਕੇਜ ਫਾਇਲਾਂ"
+
+#: ../client/pk-console.c:901
+msgid "No files"
+msgstr "ਕੋਈ ਫਾਇਲ ਨਹੀਂ"
+
+#. get user input
+#: ../client/pk-console.c:933
+msgid "Okay to import key?"
+msgstr "ਕੁੰਜੀ ਇੰਪੋਰਟ ਕਰਨ ਲਵਾਂ?"
+
+#: ../client/pk-console.c:936
+msgid "Did not import key"
+msgstr "ਕੁੰਜੀ ਇੰਪੋਰਟ ਨਾ ਕਰੋ"
+
+#. get user input
+#: ../client/pk-console.c:976
+msgid "Do you agree?"
+msgstr "ਕੀ ਤੁਸੀਂ ਸਹਿਮਤ ਹੋ?"
+
+#: ../client/pk-console.c:979
+msgid "Did not agree to licence, task will fail"
+msgstr "ਲਾਈਸੈਂਸ ਨਾਲ ਸਹਿਮਤ ਨਹੀਂ, ਕੰਮ ਪੂਰਾ ਨਹੀਂ ਹੋਵੇਗਾ"
+
+#: ../client/pk-console.c:1008
+msgid "The daemon crashed mid-transaction!"
+msgstr "ਡੈਮਨ ਅਧੂਰੀ ਟਰਾਂਜ਼ਿਸ਼ਨ ਵਿੱਚ ਨਸ਼ਟ ਹੋ ਗਈ!"
+
+#. header
+#: ../client/pk-console.c:1061
+msgid "PackageKit Console Interface"
+msgstr "ਪੈਕੇਜਕਿੱਟ ਕਨਸੋਲ ਇੰਟਰਫੇਸ"
+
+#: ../client/pk-console.c:1061
+msgid "Subcommands:"
+msgstr "ਸਬ-ਕਮਾਂਡ:"
+
+#: ../client/pk-console.c:1165 ../client/pk-monitor.c:104 ../src/pk-main.c:189
+msgid "Show extra debugging information"
+msgstr "ਹੋਰ ਡੀਬੱਗ ਜਾਣਕਾਰੀ ਵੇਖੋ"
+
+#: ../client/pk-console.c:1167 ../client/pk-monitor.c:106
+msgid "Show the program version and exit"
+msgstr "ਪਰੋਗਰਾਮ ਵਰਜਨ ਵੇਖੋ ਅਤੇ ਬੰਦ ਕਰੋ"
+
+#: ../client/pk-console.c:1169
+msgid "Set the filter, e.g. installed"
+msgstr "ਫਿਲਟਰ ਸੈੱਟ ਕਰੋ, ਜਿਵੇਂ ਕਿ ਇੰਸਟਾਲ"
+
+#: ../client/pk-console.c:1171
+msgid "Exit without waiting for actions to complete"
+msgstr "ਪੂਰੇ ਹੋਣ ਵਾਲੇ ਐਕਸ਼ਨ ਦੀ ਉਡੀਕ ਕੀਤੇ ਬਿਨਾਂ ਬੰਦ ਕਰੋ"
+
+#: ../client/pk-console.c:1194
+msgid "Could not connect to system DBUS."
+msgstr "ਸਿਸਟਮ DBUS ਨਾਲ ਕੁਨੈਕਟ ਨਹੀਂ ਕੀਤਾ ਜਾ ਸਕਿਆ।"
+
+#: ../client/pk-console.c:1288
+#, c-format
+msgid "You need to specify a search type"
+msgstr "ਤੁਹਾਨੂੰ ਖੋਜ ਟਾਈਪ ਦੱਸਣੀ ਪਵੇਗੀ"
+
+#: ../client/pk-console.c:1293 ../client/pk-console.c:1300
+#: ../client/pk-console.c:1307 ../client/pk-console.c:1314
+#: ../client/pk-console.c:1421 ../client/pk-console.c:1428
+#: ../client/pk-console.c:1435 ../client/pk-console.c:1442
+#, c-format
+msgid "You need to specify a search term"
+msgstr "ਤੁਹਾਨੂੰ ਖੋਜ ਸ਼ਬਦ ਦੇਣਾ ਪਵੇਗਾ"
+
+#: ../client/pk-console.c:1319
+#, c-format
+msgid "Invalid search type"
+msgstr "ਗਲਤ ਖੋਜ ਟਾਈਪ"
+
+#: ../client/pk-console.c:1324
+#, c-format
+msgid "You need to specify a package or file to install"
+msgstr "ਤੁਹਾਨੂੰ ਇੰਸਟਾਲ ਕਰਨ ਲਈ ਇੱਕ ਪੈਕੇਜ ਜਾਂ ਫਾਇਲ ਦੇਣ ਦੀ ਲੋੜ ਹੈ"
+
+#: ../client/pk-console.c:1339
+#, c-format
+msgid "You need to specify a type, key_id and package_id"
+msgstr "ਤੁਹਾਨੂੰ ਇੱਕ ਟਾਈਪ, key_id ਜਾਂ package_id ਦੇਣ ਦੀ ਲੋੜ ਹੈ"
+
+#: ../client/pk-console.c:1346
+#, c-format
+msgid "You need to specify a package to remove"
+msgstr "ਤੁਹਾਨੂੰ ਹਟਾਉਣ ਵਾਸਤੇ ਇੱਕ ਪੈਕੇਜ ਦੇਣਾ ਪਵੇਗਾ"
+
+#: ../client/pk-console.c:1353
+#, c-format
+msgid "You need to specify a eula-id"
+msgstr "ਤੁਹਾਨੂੰ eula-id ਦੇਣਾ ਪਵੇਗਾ"
+
+#: ../client/pk-console.c:1369
+#, c-format
+msgid "You need to specify a package name to resolve"
+msgstr "ਤੁਹਾਨੂੰ ਹੱਲ਼ ਕਰਨ ਲਈ ਇੱਕ ਪੈਕੇਜ ਨਾਂ ਦੇਣਾ ਪਵੇਗਾ"
+
+#: ../client/pk-console.c:1376 ../client/pk-console.c:1383
+#, c-format
+msgid "You need to specify a repo name"
+msgstr "ਤੁਹਾਨੂੰ ਇੱਕ ਰੈਪੋ ਨਾਂ ਦੇਣਾ ਪਵੇਗਾ"
+
+#: ../client/pk-console.c:1390
+#, c-format
+msgid "You need to specify a repo name/parameter and value"
+msgstr "ਤੁਹਾਨੂੰ ਇੱਕ ਰੈਪੋ ਨਾਂ/ਪੈਰਾਮੀਟਰ ਅਤੇ ਮੁੱਲ ਦੇਣ ਦੀ ਲੋੜ ਹੈ"
+
+#: ../client/pk-console.c:1403
+#, c-format
+msgid "You need to specify a time term"
+msgstr "ਤੁਹਾਨੂੰ ਇੱਕ ਟਾਈਮ ਟਰਮ ਦੇਣ ਦੀ ਲੋੜ ਹੈ"
+
+#: ../client/pk-console.c:1408
+#, c-format
+msgid "You need to specify a correct role"
+msgstr "ਤੁਹਾਨੂੰ ਇੱਕ ਠੀਕ ਰੋਲ ਦੇਣ ਦੀ ਲੋੜ ਹੈ"
+
+#: ../client/pk-console.c:1413
+#, c-format
+msgid "Failed to get last time"
+msgstr "ਆਖਰੀ ਟਾਈਮ ਲੈਣ ਲਈ ਫੇਲ੍ਹ"
+
+#: ../client/pk-console.c:1449
+#, c-format
+msgid "You need to specify a package to find the details for"
+msgstr "ਤੁਹਾਨੂੰ ਵੇਰਵਾ ਲੱਭਣ ਲਈ ਇੱਕ ਪੈਕੇਜ ਦੇਣ ਦੀ ਲੋੜ ਹੈ"
+
+#: ../client/pk-console.c:1456
+#, c-format
+msgid "You need to specify a package to find the files for"
+msgstr "ਤੁਹਾਨੂੰ ਫਾਇਲਾਂ ਲੱਭਣ ਲਈ ਇੱਕ ਪੈਕੇਜ ਦੇਣ ਦੀ ਲੋੜ ਹੈ"
+
+#: ../client/pk-console.c:1503
+#, c-format
+msgid "Option '%s' not supported"
+msgstr "ਚੋਣ '%s' ਸਹਿਯੋਗੀ ਨਹੀਂ"
+
+#: ../client/pk-console.c:1514
+msgid "Command failed"
+msgstr "ਕਮਾਂਡ ਫੇਲ੍ਹ ਹੈ"
+
+#: ../client/pk-console.c:1518
+msgid "You don't have the necessary privileges for this operation"
+msgstr "ਤੁਹਾਨੂੰ ਇਹ ਓਪਰੇਸ਼ਨ ਕਰਨ ਲਈ ਲੋੜੀਦੇ ਅਧਿਕਾਰ ਨਹੀਂ ਹਨ"
+
+#: ../client/pk-monitor.c:117
+msgid "PackageKit Monitor"
+msgstr "ਪੈਕੇਜਕਿੱਟ ਮਾਨੀਟਰ"
+
+#: ../client/pk-import-desktop.c:293 ../client/pk-import-specspo.c:169
+#, c-format
+msgid "Could not open database: %s"
+msgstr "ਡਾਟਾਬੇਸ ਖੋਲ੍ਹਿਆ ਨਹੀਂ ਜਾ ਸਕਿਆ: %s"
+
+#: ../client/pk-import-desktop.c:294 ../client/pk-import-specspo.c:170
+msgid "You probably need to run this program as the root user"
+msgstr "ਤੁਹਾਨੂੰ ਇਹ ਪਰੋਗਰਾਮ ਸੰਭਵ ਤੌਰ ਉੱਤੇ root ਯੂਜ਼ਰ ਵਜੋਂ ਚਲਾਉਣਾ ਚਾਹੀਦਾ ਹੈ"
+
+#: ../src/pk-main.c:83
+msgid "Startup failed due to security policies on this machine."
+msgstr "ਇਸ ਮਸ਼ੀਨ ਉੱਤੇ ਸੁਰੱਖਿਆ ਪਾਲਸੀਆਂ ਕਰਕੇ ਸ਼ੁਰੂ ਕਰਨ ਲਈ ਫੇਲ੍ਹ"
+
+#: ../src/pk-main.c:84
+msgid "This can happen for two reasons:"
+msgstr "ਇਹ ਦੋ ਕਾਰਨਾਂ ਕਰਕੇ ਹੋ ਸਕਦਾ ਹੈ:"
+
+#: ../src/pk-main.c:85
+msgid "The correct user is not launching the executable (usually root)"
+msgstr "ਢੁੱਕਵਾਂ ਯੂਜ਼ਰ ਚੱਲਣਯੋਗ ਨੂੰ ਨਹੀਂ ਚਲਾ ਰਿਹਾ ਹੈ (ਅਕਸਰ root)"
+
+#: ../src/pk-main.c:86
+msgid ""
+"The org.freedesktop.PackageKit.conf file is not installed in the system /etc/"
+"dbus-1/system.d directory"
+msgstr ""
+"org.freedesktop.PackageKit.conf ਫਾਇਲ /etc/dbus-1/system.d ਡਾਇਰੈਕਟਰੀ ਵਿੱਚ "
+"ਇੰਸਟਾਲ ਨਹੀਂ ਹੈ।"
+
+#: ../src/pk-main.c:185
+msgid "Packaging backend to use, e.g. dummy"
+msgstr "ਵਰਤਣ ਲਈ ਪੈਕੇਜਿੰਗ ਬੈਕਐਂਡ, ਜਿਵੇਂ ਕਿ ਫ਼ਰਜ਼ੀ"
+
+#: ../src/pk-main.c:187
+msgid "Daemonize and detach from the terminal"
+msgstr "ਡੈਮੇਨਾਈਜ਼ ਅਤੇ ਟਰਮੀਨਲ ਤੋਂ ਵੱਖ"
+
+#: ../src/pk-main.c:191
+msgid "Disable the idle timer"
+msgstr "ਵੇਹਲਾ ਟਾਈਮਰ ਆਯੋਗ"
+
+#: ../src/pk-main.c:193
+msgid "Show version and exit"
+msgstr "ਵਰਜਨ ਵੇਖਾ ਕੇ ਬੰਦ ਕਰੋ"
+
+#: ../src/pk-main.c:195
+msgid "Exit after a small delay"
+msgstr "ਥੋੜ੍ਹੀ ਦੇਰ ਬਾਅਦ ਬੰਦ ਕਰੋ"
+
+#: ../src/pk-main.c:197
+msgid "Exit after the engine has loaded"
+msgstr "ਇੰਜਣ ਲੋਡ ਕਰਨ ਦੇ ਬਾਅਦ ਬੰਦ ਕਰੋ"
+
+#: ../src/pk-main.c:207
+msgid "PackageKit service"
+msgstr "ਪੈਕੇਜਕਿੱਟ ਸਰਵਿਸ"
+
+#: ../src/pk-main.c:233
+msgid "Cannot connect to the system bus"
+msgstr "ਸਿਸਟਮ ਬੱਸ ਨਾਲ ਕੁਨੈਕਟ ਨਹੀਂ ਕੀਤਾ ਜਾ ਸਕਦਾ"
+
+#: ../src/pk-main.c:273
+#, c-format
+msgid "Error trying to start: %s\n"
+msgstr "ਸ਼ੁਰੂ ਕਰਨ ਲਈ ਗਲਤੀ: %s\n"
+


More information about the PackageKit-commit mailing list