Blob Blame History Raw
diff --git a/cli.py b/cli.py
index 615a1f6..332be99 100644
--- a/cli.py
+++ b/cli.py
@@ -100,6 +100,7 @@ class YumBaseCli(yum.YumBase, output.YumOutput):
         self.registerCommand(yumcommands.ReInstallCommand())        
         self.registerCommand(yumcommands.DowngradeCommand())        
         self.registerCommand(yumcommands.VersionCommand())
+        self.registerCommand(yumcommands.HistoryCommand())
 
     def registerCommand(self, command):
         for name in command.getNames():
@@ -206,8 +207,7 @@ class YumBaseCli(yum.YumBase, output.YumOutput):
 
         if opts.version:
             self.conf.cache = 1
-            yum_progs = ['yum', 'yum-metadata-parser', 'rpm',
-                         'yum-rhn-plugin']
+            yum_progs = self.run_with_package_names
             done = False
             def sm_ui_time(x):
                 return time.strftime("%Y-%m-%d %H:%M", time.gmtime(x))
diff --git a/docs/yum.8 b/docs/yum.8
index 3520912..d0dfb79 100644
--- a/docs/yum.8
+++ b/docs/yum.8
@@ -67,6 +67,10 @@ gnome\-packagekit application\&.
 .br
 .I \fR * repolist [all|enabled|disabled] 
 .br
+.I \fR * version [all] 
+.br
+.I \fR * history [info|list|summary|redo|undo|new] 
+.br
 .I \fR * help [command] 
 .br
 .PP 
@@ -225,6 +229,25 @@ Produces a list of configured repositories. The default is to list all
 enabled repositories. If you pass \-v, for verbose mode, more information is
 listed.
 .IP
+.IP "\fBversion\fP"
+Produces a "version" of the rpmdb, and of the enabled repositories if "all" is
+given as the first argument. If you pass \-v, for verbose mode, more
+information is listed. The version is calculated by taking a sha1 hash of the
+packages (in sorted order), and the checksum_type/checksum_data entries from
+the yumdb. Note that this rpmdb version is now also used significantly within
+yum (esp. in yum history).
+.IP
+.IP "\fBhistory\fP"
+The history command allows the user to view what has happened in past
+transactions (assuming the history_record config. option is set). You can use
+info/list/summary to view what happend, undo/redo to act on that information
+and new to start a new history file.
+
+The info/list/summary commands take either a transactions id or a package (with
+wildcards, as in \fBSpecifying package names\fP), all three can also be passed
+no arguments. list can be passed the keyword "all" to list all the transactions.
+undo/redo just take a transaction id.
+.IP
 .IP "\fBhelp\fP"
 Produces help, either for all commands or if given a command name then the help
 for that particular command\&.
@@ -266,7 +289,8 @@ Sets the maximum amount of time yum will wait before performing a command \- it
 Tells yum to run entirely from cache - does not download or update any
 headers unless it has to to perform the requested action.
 .IP "\fB\-\-version\fP" 
-Reports the \fByum\fP version number and exits.
+Reports the \fByum\fP version number and installed package versions for
+everything in history_record_packages (can be added to by plugins).
 .IP "\fB\-\-showduplicates\fP" 
 Doesn't limit packages to their latest versions in the info, list and search
 commands (will also affect plugins which use the doPackageLists() API).
diff --git a/docs/yum.conf.5 b/docs/yum.conf.5
index 69b601d..6295b1e 100644
--- a/docs/yum.conf.5
+++ b/docs/yum.conf.5
@@ -274,6 +274,21 @@ Path to the ssl client key yum should use to connect to repos/remote sites
 Defaults to none.
 
 .IP
+\fBhistory_record \fR
+Boolean - should yum record history entries for transactions. This takes some
+disk space, and some extra time in the transactions. But it allos how to know a
+lot of information about what has happened before, and display it to the user
+with the history info/list/summary commands. yum also provides the
+history undo/redo commands. Defaults to True.
+
+.IP
+\fBhistory_record_packages \fR
+This is a list of package names that should be recorded as having helped the
+transaction. yum plugins have an API to add themself to this, so it should not
+normally be necessary to add packages here. Not that this is also used for the
+packages to look for in --version. Defaults to rpm, yum, yum-metadata-parser.
+
+.IP
 \fBcommands\fR
 List of functional commands to run if no functional commands are specified
 on the command line (eg. "update foo bar baz quux").  None of the short options
diff --git a/output.py b/output.py
index 2299a9c..d0b9f7f 100755
--- a/output.py
+++ b/output.py
@@ -22,6 +22,7 @@ import time
 import logging
 import types
 import gettext
+import pwd
 import rpm
 
 import re # For YumTerm
@@ -40,6 +41,7 @@ from yum.constants import *
 from yum import logginglevels, _
 from yum.rpmtrans import RPMBaseCallback
 from yum.packageSack import packagesNewestByNameArch
+import yum.packages
 
 from yum.i18n import utf8_width, utf8_width_fill, utf8_text_fill
 
@@ -1172,6 +1174,328 @@ to exit.
                               ui_bs, ui_size, ui_time, ui_end)
         self.verbose_logger.log(logginglevels.INFO_2, msg)
 
+    def _history_uiactions(self, hpkgs):
+        actions = set()
+        count = 0
+        for hpkg in hpkgs:
+            st = hpkg.state
+            if st == 'True-Install':
+                st = 'Install'
+            if st == 'Obsoleted': #  This is just a UI tweak, as we can't have
+                                  # just one but we need to count them all.
+                st = 'Obsoleting'
+            if st in ('Install', 'Update', 'Erase', 'Reinstall', 'Downgrade',
+                      'Obsoleting'):
+                actions.add(st)
+                count += 1
+        assert len(actions) <= 6
+        if len(actions) > 1:
+            return count, ", ".join([x[0] for x in sorted(actions)])
+
+        # So empty transactions work, although that "shouldn't" really happen
+        return count, "".join(list(actions))
+
+    def _pwd_ui_username(self, uid, limit=None):
+        # loginuid is set to -1 on init.
+        if uid is None or uid == 0xFFFFFFFF:
+            loginid = _("<unset>")
+            name = _("System") + " " + loginid
+            if limit is not None and len(name) > limit:
+                name = loginid
+            return name
+
+        try:
+            user = pwd.getpwuid(uid)
+            fullname = user.pw_gecos.split(';', 2)[0]
+            name = "%s <%s>" % (fullname, user.pw_name)
+            if limit is not None and len(name) > limit:
+                name = "%s ... <%s>" % (fullname.split()[0], user.pw_name)
+                if len(name) > limit:
+                    name = "<%s>" % user.pw_name
+            return name
+        except KeyError:
+            return str(uid)
+
+    def _history_list_transactions(self, extcmds):
+        tids = set()
+        pats = []
+        usertids = extcmds[1:]
+        printall = False
+        if usertids:
+            printall = True
+            if usertids[0] == 'all':
+                usertids.pop(0)
+        for tid in usertids:
+            try:
+                int(tid)
+                tids.add(tid)
+            except ValueError:
+                pats.append(tid)
+        if pats:
+            tids.update(self.history.search(pats))
+
+        if not tids and usertids:
+            self.logger.critical(_('Bad transaction IDs, or package(s), given'))
+            return None, None
+        return tids, printall
+
+    def historyListCmd(self, extcmds):
+        """ Shows the user a list of data about the history. """
+
+        tids, printall = self._history_list_transactions(extcmds)
+        if tids is None:
+            return 1, ['Failed history info']
+
+        fmt = "%-6s | %-22s | %-16s | %-14s | %-7s"
+        print fmt % ("ID", "Login user", "Date and time", "Action(s)","Altered")
+        print "-" * 79
+        fmt = "%6u | %-22.22s | %-16s | %-14s | %4u"
+        done = 0
+        limit = 20
+        if printall:
+            limit = None
+        for old in self.history.old(tids, limit=limit):
+            if not printall and done >= limit:
+                break
+
+            done += 1
+            name = self._pwd_ui_username(old.loginuid, 22)
+            tm = time.strftime("%Y-%m-%d %H:%M",
+                               time.localtime(old.beg_timestamp))
+            num, uiacts = self._history_uiactions(old.trans_data)
+            if old.altered_lt_rpmdb and old.altered_gt_rpmdb:
+                print fmt % (old.tid, name, tm, uiacts, num), "><"
+            elif old.return_code is None:
+                print fmt % (old.tid, name, tm, uiacts, num), "**"
+            elif old.altered_lt_rpmdb:
+                print fmt % (old.tid, name, tm, uiacts, num), " <"
+            elif old.altered_gt_rpmdb:
+                print fmt % (old.tid, name, tm, uiacts, num), "> "
+            else:
+                print fmt % (old.tid, name, tm, uiacts, num)
+        lastdbv = self.history.last()
+        if lastdbv is not None:
+            #  If this is the last transaction, is good and it doesn't
+            # match the current rpmdb ... then mark it as bad.
+            rpmdbv  = self.rpmdb.simpleVersion(main_only=True)[0]
+            if lastdbv.end_rpmdbversion != rpmdbv:
+                errstring = _('Warning: RPMDB has been altered since the last yum transaction.')
+                self.logger.warning(errstring)
+
+    def _history_get_transactions(self, extcmds):
+        if len(extcmds) < 2:
+            self.logger.critical(_('No transaction ID given'))
+            return None
+
+        tids = []
+        try:
+            int(extcmds[1])
+            tids.append(extcmds[1])
+        except ValueError:
+            self.logger.critical(_('Bad transaction ID given'))
+            return None
+
+        old = self.history.old(tids)
+        if not old:
+            self.logger.critical(_('Not found given transaction ID'))
+            return None
+        return old
+    def _history_get_transaction(self, extcmds):
+        old = self._history_get_transactions(extcmds)
+        if old is None:
+            return None
+        if len(old) > 1:
+            self.logger.critical(_('Found more than one transaction ID!'))
+        return old[0]
+
+    def historyInfoCmd(self, extcmds):
+        tids = set()
+        pats = []
+        for tid in extcmds[1:]:
+            try:
+                int(tid)
+                tids.add(tid)
+            except ValueError:
+                pats.append(tid)
+        if pats:
+            tids.update(self.history.search(pats))
+
+        if not tids and len(extcmds) < 2:
+            old = self.history.last()
+            if old is not None:
+                tids.add(old.tid)
+
+        if not tids:
+            self.logger.critical(_('No transaction ID, or package, given'))
+            return 1, ['Failed history info']
+
+        lastdbv = self.history.last()
+        if lastdbv is not None:
+            lasttid = lastdbv.tid
+            lastdbv = lastdbv.end_rpmdbversion
+
+        done = False
+        for tid in self.history.old(tids):
+            if lastdbv is not None and tid.tid == lasttid:
+                #  If this is the last transaction, is good and it doesn't
+                # match the current rpmdb ... then mark it as bad.
+                rpmdbv  = self.rpmdb.simpleVersion(main_only=True)[0]
+                if lastdbv != rpmdbv:
+                    tid.altered_gt_rpmdb = True
+            lastdbv = None
+
+            if done:
+                print "-" * 79
+            done = True
+            self._historyInfoCmd(tid, pats)
+
+    def _historyInfoCmd(self, old, pats=[]):
+        name = self._pwd_ui_username(old.loginuid)
+
+        print _("Transaction ID :"), old.tid
+        begtm = time.ctime(old.beg_timestamp)
+        print _("Begin time     :"), begtm
+        if old.beg_rpmdbversion is not None:
+            if old.altered_lt_rpmdb:
+                print _("Begin rpmdb    :"), old.beg_rpmdbversion, "**"
+            else:
+                print _("Begin rpmdb    :"), old.beg_rpmdbversion
+        if old.end_timestamp is not None:
+            endtm = time.ctime(old.end_timestamp)
+            endtms = endtm.split()
+            if begtm.startswith(endtms[0]): # Chop uninteresting prefix
+                begtms = begtm.split()
+                sofar = 0
+                for i in range(len(endtms)):
+                    if i > len(begtms):
+                        break
+                    if begtms[i] != endtms[i]:
+                        break
+                    sofar += len(begtms[i]) + 1
+                endtm = (' ' * sofar) + endtm[sofar:]
+            diff = _("(%s seconds)") % (old.end_timestamp - old.beg_timestamp)
+            print _("End time       :"), endtm, diff
+        if old.end_rpmdbversion is not None:
+            if old.altered_gt_rpmdb:
+                print _("End rpmdb      :"), old.end_rpmdbversion, "**"
+            else:
+                print _("End rpmdb      :"), old.end_rpmdbversion
+        print _("User           :"), name
+        if old.return_code is None:
+            print _("Return-Code    :"), "**", _("Aborted"), "**"
+        elif old.return_code:
+            print _("Return-Code    :"), _("Failure:"), old.return_code
+        else:
+            print _("Return-Code    :"), _("Success")
+        print _("Transaction performed with  :")
+        for hpkg in old.trans_with:
+            prefix = " " * 4
+            state  = _('Installed')
+            ipkgs = self.rpmdb.searchNames([hpkg.name])
+            ipkgs.sort()
+            if not ipkgs:
+                state  = _('Erased')
+            elif hpkg.pkgtup in (ipkg.pkgtup for ipkg in ipkgs):
+                pass
+            elif ipkgs[-1] > hpkg:
+                state  = _('Updated')
+            elif ipkgs[0] < hpkg:
+                state  = _('Downgraded')
+            else: # multiple versions installed, both older and newer
+                state  = _('Weird')
+            print "%s%-12s %s" % (prefix, state, hpkg)
+        print _("Packages Altered:")
+        self.historyInfoCmdPkgsAltered(old, pats)
+
+    def historyInfoCmdPkgsAltered(self, old, pats=[]):
+        for hpkg in old.trans_data:
+            prefix = " " * 4
+            if not hpkg.done:
+                prefix = " ** "
+
+            highlight = 'normal'
+            if pats:
+                x,m,u = yum.packages.parsePackages([hpkg], pats)
+                if x or m:
+                    highlight = 'bold'
+            (hibeg, hiend) = self._highlight(highlight)
+
+            # To chop the name off we need nevra strings, str(pkg) gives envra
+            # so we have to do it by hand ... *sigh*.
+            if hpkg.epoch == '0':
+                cn = str(hpkg)
+            else:
+                cn = "%s-%s:%s-%s.%s" % (hpkg.name, hpkg.epoch,
+                                         hpkg.version, hpkg.release, hpkg.arch)
+
+            if False: pass
+            elif hpkg.state == 'Update':
+                ln = len(hpkg.name) + 1
+                cn = (" " * ln) + cn[ln:]
+                print "%s%s%-12s%s %s" % (prefix, hibeg, hpkg.state, hiend, cn)
+            elif hpkg.state == 'Downgraded':
+                ln = len(hpkg.name) + 1
+                cn = (" " * ln) + cn[ln:]
+                print "%s%s%-12s%s %s" % (prefix, hibeg, hpkg.state, hiend, cn)
+            elif hpkg.state == 'True-Install':
+                print "%s%s%-12s%s %s" % (prefix, hibeg, "Install", hiend,  cn)
+            else:
+                print "%s%s%-12s%s %s" % (prefix, hibeg, hpkg.state, hiend, cn)
+
+    def historySummaryCmd(self, extcmds):
+        tids, printall = self._history_list_transactions(extcmds)
+        if tids is None:
+            return 1, ['Failed history info']
+
+        fmt = "%-26s | %-19s | %-16s | %-8s"
+        print fmt % ("Login user", "Time", "Action(s)", "Altered")
+        print "-" * 79
+        fmt = "%-26.26s | %-19.19s | %-16s | %8u"
+        data = {'day' : {}, 'week' : {},
+                'fortnight' : {}, 'quarter' : {}, 'half' : {}, 
+                'year' : {}, 'all' : {}}
+        for old in self.history.old(tids):
+            name = self._pwd_ui_username(old.loginuid, 26)
+            period = 'all'
+            now = time.time()
+            if False: pass
+            elif old.beg_timestamp > (now - (24 * 60 * 60)):
+                period = 'day'
+            elif old.beg_timestamp > (now - (24 * 60 * 60 *  7)):
+                period = 'week'
+            elif old.beg_timestamp > (now - (24 * 60 * 60 * 14)):
+                period = 'fortnight'
+            elif old.beg_timestamp > (now - (24 * 60 * 60 *  7 * 13)):
+                period = 'quarter'
+            elif old.beg_timestamp > (now - (24 * 60 * 60 *  7 * 26)):
+                period = 'half'
+            elif old.beg_timestamp > (now - (24 * 60 * 60 * 365)):
+                period = 'year'
+            data[period].setdefault(name, []).append(old)
+        _period2user = {'day'       : _("Last day"),
+                        'week'      : _("Last week"),
+                        'fortnight' : _("Last 2 weeks"), # US default :p
+                        'quarter'   : _("Last 3 months"),
+                        'half'      : _("Last 6 months"),
+                        'year'      : _("Last year"),
+                        'all'       : _("Over a year ago")}
+        done = 0
+        for period in ('day', 'week', 'fortnight', 'quarter', 'half', 'year',
+                       'all'):
+            if not data[period]:
+                continue
+            for name in sorted(data[period]):
+                if not printall and done > 19:
+                    break
+                done += 1
+
+                hpkgs = []
+                for old in data[period][name]:
+                    hpkgs.extend(old.trans_data)
+                count, uiacts = self._history_uiactions(hpkgs)
+                uperiod = _period2user[period]
+                print fmt % (name, uperiod, uiacts, count)
+
 
 class DepSolveProgressCallBack:
     """provides text output callback functions for Dependency Solver callback"""
diff --git a/po/ca.po b/po/ca.po
index 3bef4b5..1869dc2 100644
--- a/po/ca.po
+++ b/po/ca.po
@@ -5,6 +5,7 @@
 #
 # Josep Maria Brunetti Fernández <josepb@gmail.com>, 2008
 # Xavier Conde Rueda <xavi.conde@gmail.com>, 2008
+# Josep Torné Llavall <josep.torne@gmail.com>, 2009
 #
 # This file is translated according to the glossary and style guide of
 #   Softcatalà. If you plan to modify this file, please read first the page
@@ -21,8 +22,8 @@ msgid ""
 msgstr ""
 "Project-Id-Version: yum\n"
 "Report-Msgid-Bugs-To: \n"
-"POT-Creation-Date: 2009-03-27 19:24+0000\n"
-"PO-Revision-Date: 2009-03-31 22:25+0100\n"
+"POT-Creation-Date: 2009-09-05 08:55+0000\n"
+"PO-Revision-Date: 2009-09-06 22:25+0100\n"
 "Last-Translator: Agustí Grau <fedora@softcatala.org>\n"
 "Language-Team: Catalan <fedora@softcatala.net>\n"
 "MIME-Version: 1.0\n"
@@ -31,46 +32,32 @@ msgstr ""
 "Plural-Forms: nplurals=2; plural=n != 1;\n"
 "X-Poedit-Language: Catalan\n"
 
-#: ../callback.py:48
-#: ../output.py:922
-#: ../yum/rpmtrans.py:71
+#: ../callback.py:48 ../output.py:938 ../yum/rpmtrans.py:71
 msgid "Updating"
 msgstr "Actualitzant"
 
-#: ../callback.py:49
-#: ../yum/rpmtrans.py:72
+#: ../callback.py:49 ../yum/rpmtrans.py:72
 msgid "Erasing"
-msgstr "S'està esborrant"
-
-#: ../callback.py:50
-#: ../callback.py:51
-#: ../callback.py:53
-#: ../output.py:921
-#: ../yum/rpmtrans.py:73
-#: ../yum/rpmtrans.py:74
-#: ../yum/rpmtrans.py:76
+msgstr "Suprimint"
+
+#: ../callback.py:50 ../callback.py:51 ../callback.py:53 ../output.py:937
+#: ../yum/rpmtrans.py:73 ../yum/rpmtrans.py:74 ../yum/rpmtrans.py:76
 msgid "Installing"
 msgstr "Instal·lant"
 
-#: ../callback.py:52
-#: ../callback.py:58
-#: ../yum/rpmtrans.py:75
+#: ../callback.py:52 ../callback.py:58 ../yum/rpmtrans.py:75
 msgid "Obsoleted"
 msgstr "Obsolet"
 
-#: ../callback.py:54
-#: ../output.py:1029
+#: ../callback.py:54 ../output.py:1061
 msgid "Updated"
 msgstr "Actualitzat"
 
 #: ../callback.py:55
 msgid "Erased"
-msgstr "Esborrat"
+msgstr "Suprimit"
 
-#: ../callback.py:56
-#: ../callback.py:57
-#: ../callback.py:59
-#: ../output.py:1027
+#: ../callback.py:56 ../callback.py:57 ../callback.py:59 ../output.py:1059
 msgid "Installed"
 msgstr "Instal·lat"
 
@@ -90,75 +77,70 @@ msgstr "Error: estat de sortida invàlid: %s per a %s"
 #: ../callback.py:212
 #, python-format
 msgid "Erased: %s"
-msgstr "Esborrat: %s"
+msgstr "Suprimit: %s"
 
-#: ../callback.py:217
-#: ../output.py:923
+#: ../callback.py:217 ../output.py:939
 msgid "Removing"
-msgstr "S'està esborrant"
+msgstr "Suprimint"
 
-#: ../callback.py:219
-#: ../yum/rpmtrans.py:77
+#: ../callback.py:219 ../yum/rpmtrans.py:77
 msgid "Cleanup"
 msgstr "Neteja"
 
-#: ../cli.py:106
+#: ../cli.py:107
 #, python-format
 msgid "Command \"%s\" already defined"
 msgstr "L'ordre «%s» ja està definida"
 
-#: ../cli.py:118
+#: ../cli.py:119
 msgid "Setting up repositories"
 msgstr "Configurant repositoris"
 
-#: ../cli.py:129
+#: ../cli.py:130
 msgid "Reading repository metadata in from local files"
 msgstr "S'estan llegint les metadades de repositoris des de fitxers locals"
 
-#: ../cli.py:192
-#: ../utils.py:79
+#: ../cli.py:193 ../utils.py:87
 #, python-format
 msgid "Config Error: %s"
 msgstr "Error de configuració: %s"
 
-#: ../cli.py:195
-#: ../cli.py:1224
-#: ../utils.py:82
+#: ../cli.py:196 ../cli.py:1253 ../utils.py:90
 #, python-format
 msgid "Options Error: %s"
 msgstr "Error d'opcions: %s"
 
-#: ../cli.py:223
+#: ../cli.py:225
 #, python-format
 msgid "  Installed: %s-%s at %s"
 msgstr "  Instal·lat: %s-%s a %s"
 
-#: ../cli.py:225
+#: ../cli.py:227
 #, python-format
 msgid "  Built    : %s at %s"
 msgstr "  Muntat    : %s a %s"
 
-#: ../cli.py:227
+#: ../cli.py:229
 #, python-format
 msgid "  Committed: %s at %s"
 msgstr "  Pujat: %s a %s"
 
-#: ../cli.py:266
+#: ../cli.py:268
 msgid "You need to give some command"
 msgstr "Cal que doneu alguna ordre"
 
-#: ../cli.py:309
+#: ../cli.py:311
 msgid "Disk Requirements:\n"
 msgstr "Requeriments de disc:\n"
 
-#: ../cli.py:311
+#: ../cli.py:313
 #, python-format
 msgid "  At least %dMB needed on the %s filesystem.\n"
 msgstr "  Es necessiten almenys %dMB al sistema de fitxers %s.\n"
 
 #. TODO: simplify the dependency errors?
 #. Fixup the summary
-#: ../cli.py:316
+#: ../cli.py:318
 msgid ""
 "Error Summary\n"
 "-------------\n"
@@ -166,58 +148,66 @@ msgstr ""
 "Resum d'errors\n"
 "-------------\n"
 
-#: ../cli.py:359
+#: ../cli.py:361
 msgid "Trying to run the transaction but nothing to do. Exiting."
-msgstr "S'ha intentat executar la transacció però no hi ha cap tasca a fer. S'està sortint."
+msgstr ""
+"S'ha intentat executar la transacció però no hi ha cap tasca a fer. S'està "
+"sortint."
 
-#: ../cli.py:395
+#: ../cli.py:397
 msgid "Exiting on user Command"
 msgstr "S'està sortint de l'ordre de l'usuari"
 
-#: ../cli.py:399
+#: ../cli.py:401
 msgid "Downloading Packages:"
-msgstr "S'estan descarregant els següents paquets:"
+msgstr "S'estan baixant els següents paquets:"
 
-#: ../cli.py:404
+#: ../cli.py:406
 msgid "Error Downloading Packages:\n"
-msgstr "S'ha produït un error descarregant els següents paquets:\n"
+msgstr "S'ha produït un error baixant els següents paquets:\n"
 
-#: ../cli.py:418
-#: ../yum/__init__.py:3520
+#: ../cli.py:420 ../yum/__init__.py:3854
 msgid "Running rpm_check_debug"
 msgstr "S'està executant rpm_check_debug"
 
-#: ../cli.py:421
-#: ../yum/__init__.py:3523
+#: ../cli.py:429 ../yum/__init__.py:3863
+msgid "ERROR You need to update rpm to handle:"
+msgstr "S'ha produït un error. Necessiteu actualitzar el gestor rpm:"
+
+#: ../cli.py:431 ../yum/__init__.py:3866
 msgid "ERROR with rpm_check_debug vs depsolve:"
 msgstr "S'ha produït un error amb rpm_check_debug contra depsolve:"
 
-#: ../cli.py:425
+#: ../cli.py:437
+msgid "RPM needs to be updated"
+msgstr "Cal actualitzar l'RPM"
+
+#: ../cli.py:438
 #, python-format
 msgid "Please report this error in %s"
 msgstr "Siusplau, informeu d'aquest error a %s"
 
-#: ../cli.py:431
+#: ../cli.py:444
 msgid "Running Transaction Test"
 msgstr "S'està executant la transacció de prova"
 
-#: ../cli.py:447
+#: ../cli.py:460
 msgid "Finished Transaction Test"
 msgstr "Ha acabat la transacció de prova"
 
-#: ../cli.py:449
+#: ../cli.py:462
 msgid "Transaction Check Error:\n"
 msgstr "S'ha produït un error en la transacció de prova:\n"
 
-#: ../cli.py:456
+#: ../cli.py:469
 msgid "Transaction Test Succeeded"
 msgstr "La transacció de prova ha acabat amb èxit"
 
-#: ../cli.py:477
+#: ../cli.py:491
 msgid "Running Transaction"
 msgstr "S'està executant la transacció"
 
-#: ../cli.py:507
+#: ../cli.py:521
 msgid ""
 "Refusing to automatically import keys when running unattended.\n"
 "Use \"-y\" to override."
@@ -225,184 +215,191 @@ msgstr ""
 "No s'importaran automàticament les claus en una execució desatesa.\n"
 "Feu servir \"-y\" per a importar les claus."
 
-#: ../cli.py:526
-#: ../cli.py:560
+#: ../cli.py:540 ../cli.py:574
 msgid "  * Maybe you meant: "
 msgstr "  * Potser volíeu dir: "
 
-#: ../cli.py:543
-#: ../cli.py:551
+#: ../cli.py:557 ../cli.py:565
 #, python-format
 msgid "Package(s) %s%s%s available, but not installed."
 msgstr "Paquets %s%s%s disponibles, però no instal·lats."
 
-#: ../cli.py:557
-#: ../cli.py:588
-#: ../cli.py:668
+#: ../cli.py:571 ../cli.py:602 ../cli.py:680
 #, python-format
 msgid "No package %s%s%s available."
 msgstr "El paquet %s%s%s no està disponible."
 
-#: ../cli.py:593
-#: ../cli.py:695
+#: ../cli.py:607 ../cli.py:740
 msgid "Package(s) to install"
 msgstr "Paquets a instal·lar"
 
-#: ../cli.py:594
-#: ../cli.py:674
-#: ../cli.py:696
-#: ../yumcommands.py:159
-#: ../yumcommands.py:1013
+#: ../cli.py:608 ../cli.py:686 ../cli.py:719 ../cli.py:741
+#: ../yumcommands.py:157
 msgid "Nothing to do"
 msgstr "Res a fer"
 
-#: ../cli.py:627
+#: ../cli.py:641
 #, python-format
 msgid "%d packages marked for Update"
 msgstr "%d paquets marcats per a actualitzar"
 
-#: ../cli.py:630
+#: ../cli.py:644
 msgid "No Packages marked for Update"
 msgstr "No hi ha cap paquet marcat per a actualitzar"
 
-#: ../cli.py:644
+#: ../cli.py:658
 #, python-format
 msgid "%d packages marked for removal"
-msgstr "%d paquets marcats per a esborrar"
+msgstr "%d paquets marcats per a suprimir"
 
-#: ../cli.py:647
+#: ../cli.py:661
 msgid "No Packages marked for removal"
-msgstr "No hi ha cap paquet marcat per a esborrar"
+msgstr "No hi ha cap paquet marcat per a suprimir"
 
-#: ../cli.py:673
+#: ../cli.py:685
 msgid "Package(s) to downgrade"
 msgstr "Paquets per a desactualitzar"
 
-#: ../cli.py:686
+#: ../cli.py:709
+#, python-format
+msgid " (from %s)"
+msgstr " (des de %s)"
+
+#: ../cli.py:711
+#, python-format
+msgid "Installed package %s%s%s%s not available."
+msgstr "El paquet instal·lat %s%s%s%s no està disponible."
+
+#: ../cli.py:718
+msgid "Package(s) to reinstall"
+msgstr "Paquets a reinstal·lar"
+
+#: ../cli.py:731
 msgid "No Packages Provided"
 msgstr "No s'ha proporcionat cap paquet"
 
-#: ../cli.py:741
-msgid "Matching packages for package list to user args"
-msgstr "S'està comparant els paquets per a la llista de paquets amb els arguments de l'usuari"
-
-#: ../cli.py:790
+#: ../cli.py:815
 #, python-format
 msgid "Warning: No matches found for: %s"
 msgstr "Avís: no s'ha trobat cap coincidència per a: %s"
 
-#: ../cli.py:793
+#: ../cli.py:818
 msgid "No Matches found"
 msgstr "No s'ha trobat cap coincidència"
 
-#: ../cli.py:832
+#: ../cli.py:857
 #, python-format
 msgid ""
 "Warning: 3.0.x versions of yum would erroneously match against filenames.\n"
 " You can use \"%s*/%s%s\" and/or \"%s*bin/%s%s\" to get that behaviour"
 msgstr ""
-"Avís: les versions 3.0.x del yum comproven incorrectament els noms de fitxer.\n"
+"Avís: les versions 3.0.x del yum comproven incorrectament els noms de "
+"fitxer.\n"
 " Podeu usar \"%s*/%s%s\" i/o \"%s*bin/%s%s\" per obtenir aquest comportament"
 
-#: ../cli.py:848
+#: ../cli.py:873
 #, python-format
 msgid "No Package Found for %s"
 msgstr "No s'ha trobat cap paquet per a %s"
 
-#: ../cli.py:860
+#: ../cli.py:885
 msgid "Cleaning up Everything"
 msgstr "S'està netejant tot"
 
-#: ../cli.py:874
+#: ../cli.py:899
 msgid "Cleaning up Headers"
 msgstr "S'estan netejant les capçaleres"
 
-#: ../cli.py:877
+#: ../cli.py:902
 msgid "Cleaning up Packages"
 msgstr "S'estan netejant els paquets"
 
-#: ../cli.py:880
+#: ../cli.py:905
 msgid "Cleaning up xml metadata"
 msgstr "S'estan netejant les metadades xml"
 
-#: ../cli.py:883
+#: ../cli.py:908
 msgid "Cleaning up database cache"
 msgstr "S'està netejant la memòria cau de la base de dades"
 
-#: ../cli.py:886
+#: ../cli.py:911
 msgid "Cleaning up expire-cache metadata"
 msgstr "S'està netejant la memòria cau de metadades que han vençut"
 
-#: ../cli.py:889
+#: ../cli.py:914
 msgid "Cleaning up plugins"
 msgstr "S'estan netejant els connectors"
 
-#: ../cli.py:914
+#: ../cli.py:939
 msgid "Installed Groups:"
 msgstr "Grups instal·lats:"
 
-#: ../cli.py:926
+#: ../cli.py:951
 msgid "Available Groups:"
 msgstr "Grups disponibles:"
 
-#: ../cli.py:936
+#: ../cli.py:961
 msgid "Done"
 msgstr "Fet"
 
-#: ../cli.py:947
-#: ../cli.py:965
-#: ../cli.py:971
-#: ../yum/__init__.py:2421
+#: ../cli.py:972 ../cli.py:990 ../cli.py:996 ../yum/__init__.py:2560
 #, python-format
 msgid "Warning: Group %s does not exist."
 msgstr "Avís: El grup %s no existeix."
 
-#: ../cli.py:975
+#: ../cli.py:1000
 msgid "No packages in any requested group available to install or update"
-msgstr "No hi ha cap paquet disponible per a instal·lar o actualitzar en els grups sol·licitats"
+msgstr ""
+"No hi ha cap paquet disponible per a instal·lar o actualitzar en els grups "
+"sol·licitats"
 
-#: ../cli.py:977
+#: ../cli.py:1002
 #, python-format
 msgid "%d Package(s) to Install"
 msgstr "%d paquets a instal·lar"
 
-#: ../cli.py:987
-#: ../yum/__init__.py:2433
+#: ../cli.py:1012 ../yum/__init__.py:2572
 #, python-format
 msgid "No group named %s exists"
 msgstr "No existeix cap grup anomenat %s"
 
-#: ../cli.py:993
+#: ../cli.py:1018
 msgid "No packages to remove from groups"
-msgstr "No hi ha cap paquet a esborrar dels grups"
+msgstr "No hi ha cap paquet a suprimir dels grups"
 
-#: ../cli.py:995
+#: ../cli.py:1020
 #, python-format
 msgid "%d Package(s) to remove"
-msgstr "%d paquets a esborrar"
+msgstr "%d paquets a suprimir"
 
-#: ../cli.py:1037
+#: ../cli.py:1062
 #, python-format
 msgid "Package %s is already installed, skipping"
 msgstr "El paquet %s ja està instal·lat, s'ometrà"
 
-#: ../cli.py:1048
+#: ../cli.py:1073
 #, python-format
 msgid "Discarding non-comparable pkg %s.%s"
 msgstr "S'està descartant el paquet no comparable %s.%s"
 
 #. we've not got any installed that match n or n+a
-#: ../cli.py:1074
+#: ../cli.py:1099
 #, python-format
 msgid "No other %s installed, adding to list for potential install"
-msgstr "No hi ha cap altre %s instal·lat, s'afegeix a la llista per a una possible instal·lació"
+msgstr ""
+"No hi ha cap altre %s instal·lat, s'afegeix a la llista per a una possible "
+"instal·lació"
 
-#: ../cli.py:1093
+#: ../cli.py:1119
+msgid "Plugin Options"
+msgstr "Opcions del connector"
+
+#: ../cli.py:1127
 #, python-format
 msgid "Command line error: %s"
 msgstr "Error en la línia d'ordres: %s"
 
-#: ../cli.py:1106
+#: ../cli.py:1140
 #, python-format
 msgid ""
 "\n"
@@ -413,253 +410,259 @@ msgstr ""
 "\n"
 "%s: l'opció %s necessita un argument"
 
-#: ../cli.py:1164
+#: ../cli.py:1193
 msgid "--color takes one of: auto, always, never"
 msgstr "--color pren un valor d'entre: auto, always, never"
 
-#: ../cli.py:1266
+#: ../cli.py:1300
 msgid "show this help message and exit"
 msgstr "mostra el missatge d'ajuda i surt"
 
-#: ../cli.py:1270
+#: ../cli.py:1304
 msgid "be tolerant of errors"
 msgstr "sigues tolerant amb els errors"
 
-#: ../cli.py:1272
+#: ../cli.py:1306
 msgid "run entirely from cache, don't update cache"
 msgstr "executa totalment des de la memòria cau, no l'actualitzis"
 
-#: ../cli.py:1274
+#: ../cli.py:1308
 msgid "config file location"
 msgstr "ubicació del fitxer de configuració"
 
-#: ../cli.py:1276
+#: ../cli.py:1310
 msgid "maximum command wait time"
 msgstr "temps màxim d'espera d'ordres"
 
-#: ../cli.py:1278
+#: ../cli.py:1312
 msgid "debugging output level"
 msgstr "nivell de sortida de depuració"
 
-#: ../cli.py:1282
+#: ../cli.py:1316
 msgid "show duplicates, in repos, in list/search commands"
 msgstr "mostra duplicats, en repositoris, en les ordres per llistar i cercar"
 
-#: ../cli.py:1284
+#: ../cli.py:1318
 msgid "error output level"
 msgstr "nivell de sortida d'error"
 
-#: ../cli.py:1287
+#: ../cli.py:1321
 msgid "quiet operation"
 msgstr "operació silenciosa"
 
-#: ../cli.py:1289
+#: ../cli.py:1323
 msgid "verbose operation"
 msgstr "operació descriptiva"
 
-#: ../cli.py:1291
+#: ../cli.py:1325
 msgid "answer yes for all questions"
 msgstr "respon sí a totes les preguntes"
 
-#: ../cli.py:1293
+#: ../cli.py:1327
 msgid "show Yum version and exit"
 msgstr "mostra la versió del Yum i surt"
 
-#: ../cli.py:1294
+#: ../cli.py:1328
 msgid "set install root"
 msgstr "estableix l'arrel de la instal·lació"
 
-#: ../cli.py:1298
+#: ../cli.py:1332
 msgid "enable one or more repositories (wildcards allowed)"
 msgstr "habilita un o més repositoris (es permeten caràcters de reemplaçament)"
 
-#: ../cli.py:1302
+#: ../cli.py:1336
 msgid "disable one or more repositories (wildcards allowed)"
-msgstr "deshabilita un o més repositoris (es permeten caràcters de reemplaçament)"
+msgstr ""
+"deshabilita un o més repositoris (es permeten caràcters de reemplaçament)"
 
-#: ../cli.py:1305
+#: ../cli.py:1339
 msgid "exclude package(s) by name or glob"
 msgstr "exclou els paquets per nom o expressió regular del glob"
 
-#: ../cli.py:1307
+#: ../cli.py:1341
 msgid "disable exclude from main, for a repo or for everything"
 msgstr "inhabilita l'exclusió des de l'inici, per a un repositori o per a tot"
 
-#: ../cli.py:1310
+#: ../cli.py:1344
 msgid "enable obsoletes processing during updates"
 msgstr "habilita el processament d'obsolets durant les actualitzacions"
 
-#: ../cli.py:1312
+#: ../cli.py:1346
 msgid "disable Yum plugins"
 msgstr "inhabilita els connectors de Yum"
 
-#: ../cli.py:1314
+#: ../cli.py:1348
 msgid "disable gpg signature checking"
 msgstr "inhabilita la comprobació de signatures gpg"
 
-#: ../cli.py:1316
+#: ../cli.py:1350
 msgid "disable plugins by name"
 msgstr "inhabilita els connectors pel seu nom"
 
-#: ../cli.py:1319
+#: ../cli.py:1353
 msgid "enable plugins by name"
 msgstr "habilita els connectors pel seu nom"
 
-#: ../cli.py:1322
+#: ../cli.py:1356
 msgid "skip packages with depsolving problems"
 msgstr "omet paquets amb problemes de resolució de dependències"
 
-#: ../cli.py:1324
+#: ../cli.py:1358
 msgid "control whether color is used"
 msgstr "controla sempre que s'usi color"
 
-#: ../output.py:298
+#: ../output.py:303
 msgid "Jan"
 msgstr "Gen"
 
-#: ../output.py:298
+#: ../output.py:303
 msgid "Feb"
 msgstr "Feb"
 
-#: ../output.py:298
+#: ../output.py:303
 msgid "Mar"
 msgstr "Mar"
 
-#: ../output.py:298
+#: ../output.py:303
 msgid "Apr"
 msgstr "Abr"
 
-#: ../output.py:298
+#: ../output.py:303
 msgid "May"
 msgstr "Mai"
 
-#: ../output.py:298
+#: ../output.py:303
 msgid "Jun"
 msgstr "Jun"
 
-#: ../output.py:299
+#: ../output.py:304
 msgid "Jul"
 msgstr "Jul"
 
-#: ../output.py:299
+#: ../output.py:304
 msgid "Aug"
 msgstr "Ago"
 
-#: ../output.py:299
+#: ../output.py:304
 msgid "Sep"
 msgstr "Set"
 
-#: ../output.py:299
+#: ../output.py:304
 msgid "Oct"
 msgstr "Oct"
 
-#: ../output.py:299
+#: ../output.py:304
 msgid "Nov"
 msgstr "Nov"
 
-#: ../output.py:299
+#: ../output.py:304
 msgid "Dec"
 msgstr "Des"
 
-#: ../output.py:309
+#: ../output.py:314
 msgid "Trying other mirror."
 msgstr "S'està intentant un altre servidor rèplica."
 
-#: ../output.py:525
+#: ../output.py:536
 #, python-format
 msgid "Name       : %s%s%s"
 msgstr "Nom        : %s%s%s"
 
-#: ../output.py:526
+#: ../output.py:537
 #, python-format
 msgid "Arch       : %s"
 msgstr "Arq        : %s"
 
-#: ../output.py:528
+#: ../output.py:539
 #, python-format
 msgid "Epoch      : %s"
 msgstr "Època      : %s"
 
-#: ../output.py:529
+#: ../output.py:540
 #, python-format
 msgid "Version    : %s"
 msgstr "Versió     : %s"
 
-#: ../output.py:530
+#: ../output.py:541
 #, python-format
 msgid "Release    : %s"
 msgstr "Release    : %s"
 
-#: ../output.py:531
+#: ../output.py:542
 #, python-format
 msgid "Size       : %s"
 msgstr "Mida       : %s"
 
-#: ../output.py:532
+#: ../output.py:543
 #, python-format
 msgid "Repo       : %s"
 msgstr "Repo       : %s"
 
-#: ../output.py:534
+#: ../output.py:545
+#, python-format
+msgid "From repo  : %s"
+msgstr "Des del repo  : %s"
+
+#: ../output.py:547
 #, python-format
 msgid "Committer  : %s"
 msgstr "Desenvolupador  : %s"
 
-#: ../output.py:535
+#: ../output.py:548
 #, python-format
 msgid "Committime : %s"
 msgstr "Pujat      : %s"
 
-#: ../output.py:536
+#: ../output.py:549
 #, python-format
 msgid "Buildtime  : %s"
 msgstr "Temps de creació  : %s"
 
-#: ../output.py:538
+#: ../output.py:551
 #, python-format
 msgid "Installtime: %s"
 msgstr "Temps d'instal·lació: %s"
 
-#: ../output.py:539
+#: ../output.py:552
 msgid "Summary    : "
 msgstr "Resum      : "
 
-#: ../output.py:541
+#: ../output.py:554
 #, python-format
 msgid "URL        : %s"
 msgstr "URL        : %s"
 
-#: ../output.py:542
+#: ../output.py:555
 #, python-format
 msgid "License    : %s"
 msgstr "Llicència  : %s"
 
-#: ../output.py:543
+#: ../output.py:556
 msgid "Description: "
 msgstr "Descripció: "
 
-#: ../output.py:611
+#: ../output.py:624
 msgid "y"
 msgstr "s"
 
-#: ../output.py:611
+#: ../output.py:624
 msgid "yes"
 msgstr "sí"
 
-#: ../output.py:612
+#: ../output.py:625
 msgid "n"
 msgstr "n"
 
-#: ../output.py:612
+#: ../output.py:625
 msgid "no"
 msgstr "no"
 
 # REMEMBER to Translate [Y/N] to the current locale
-#: ../output.py:616
+#: ../output.py:629
 msgid "Is this ok [y/N]: "
 msgstr "És correcte [s/N]: "
 
-#: ../output.py:704
+#: ../output.py:720
 #, python-format
 msgid ""
 "\n"
@@ -668,134 +671,142 @@ msgstr ""
 "\n"
 "Grup: %s"
 
-#: ../output.py:708
+#: ../output.py:724
 #, python-format
 msgid " Group-Id: %s"
 msgstr " Id de Grup: %s"
 
-#: ../output.py:713
+#: ../output.py:729
 #, python-format
 msgid " Description: %s"
 msgstr " Descripció: %s"
 
-#: ../output.py:715
+#: ../output.py:731
 msgid " Mandatory Packages:"
 msgstr " Paquets obligatoris:"
 
-#: ../output.py:716
+#: ../output.py:732
 msgid " Default Packages:"
 msgstr " Paquets per defecte:"
 
-#: ../output.py:717
+#: ../output.py:733
 msgid " Optional Packages:"
 msgstr " Paquets opcionals:"
 
-#: ../output.py:718
+#: ../output.py:734
 msgid " Conditional Packages:"
 msgstr " Paquets condicionals:"
 
-#: ../output.py:738
+#: ../output.py:754
 #, python-format
 msgid "package: %s"
 msgstr "paquet: %s"
 
-#: ../output.py:740
+#: ../output.py:756
 msgid "  No dependencies for this package"
 msgstr "  No hi ha dependències per a aquest paquet"
 
-#: ../output.py:745
+#: ../output.py:761
 #, python-format
 msgid "  dependency: %s"
 msgstr "  dependència: %s"
 
-#: ../output.py:747
+#: ../output.py:763
 msgid "   Unsatisfied dependency"
 msgstr "   Dependència insatisfeta"
 
-#: ../output.py:819
+#: ../output.py:835
 #, python-format
 msgid "Repo        : %s"
 msgstr "Repo        : %s"
 
-#: ../output.py:820
+#: ../output.py:836
 msgid "Matched from:"
 msgstr "Coincidències amb:"
 
-#: ../output.py:828
+#: ../output.py:845
 msgid "Description : "
 msgstr "Descripció  : "
 
-#: ../output.py:831
+#: ../output.py:848
 #, python-format
 msgid "URL         : %s"
 msgstr "URL         : %s"
 
-#: ../output.py:834
+#: ../output.py:851
 #, python-format
 msgid "License     : %s"
 msgstr "Llicència   : %s"
 
-#: ../output.py:837
+#: ../output.py:854
 #, python-format
 msgid "Filename    : %s"
 msgstr "Fitxer      : %s"
 
-#: ../output.py:841
+#: ../output.py:858
 msgid "Other       : "
 msgstr "Altre       : "
 
-#: ../output.py:874
+#: ../output.py:891
 msgid "There was an error calculating total download size"
 msgstr "S'ha produït un error en calcular la mida total de la descàrrega"
 
-#: ../output.py:879
+#: ../output.py:896
 #, python-format
 msgid "Total size: %s"
 msgstr "Mida total: %s"
 
-#: ../output.py:882
+#: ../output.py:899
 #, python-format
 msgid "Total download size: %s"
 msgstr "Mida total de la descàrrega: %s"
 
-#: ../output.py:924
+#: ../output.py:940
+#, 
+msgid "Reinstalling"
+msgstr "Tornant a instal·lar"
+
+#: ../output.py:941
+msgid "Downgrading"
+msgstr "Desfent l'actualització"
+
+#: ../output.py:942
 msgid "Installing for dependencies"
 msgstr "S'està instal·lant per dependències"
 
-#: ../output.py:925
+#: ../output.py:943
 msgid "Updating for dependencies"
 msgstr "S'està actualitzant degut a les dependències"
 
-#: ../output.py:926
+#: ../output.py:944
 msgid "Removing for dependencies"
-msgstr "S'està esborrant degut a les dependències"
+msgstr "S'està suprimint degut a les dependències"
 
-#: ../output.py:933
-#: ../output.py:1031
+#: ../output.py:951 ../output.py:1063
 msgid "Skipped (dependency problems)"
 msgstr "Ignorat degut a problemes de dependències:"
 
-#: ../output.py:954
+#: ../output.py:974
 msgid "Package"
 msgstr "Paquet"
 
-#: ../output.py:954
+#: ../output.py:974
 msgid "Arch"
 msgstr "Arq"
 
-#: ../output.py:955
+#: ../output.py:975
 msgid "Version"
 msgstr "Versió"
 
-#: ../output.py:955
+#: ../output.py:975
 msgid "Repository"
 msgstr "Repositori"
 
-#: ../output.py:956
+#: ../output.py:976
 msgid "Size"
 msgstr "Mida"
 
-#: ../output.py:968
+#: ../output.py:988
 #, python-format
 msgid ""
 "     replacing  %s%s%s.%s %s\n"
@@ -804,135 +815,164 @@ msgstr ""
 "     s'està reemplaçant  %s%s%s.%s %s\n"
 "\n"
 
-#: ../output.py:977
+#: ../output.py:997
 #, python-format
 msgid ""
 "\n"
 "Transaction Summary\n"
 "%s\n"
-"Install  %5.5s Package(s)         \n"
-"Update   %5.5s Package(s)         \n"
-"Remove   %5.5s Package(s)         \n"
 msgstr ""
 "\n"
-"Resum de transaccions\n"
+"Resum de la transacció\n"
 "%s\n"
-"Instal·la  %5.5s paquets         \n"
-"Actualitza %5.5s paquets         \n"
-"Esborra    %5.5s paquets         \n"
 
-#: ../output.py:1025
+#: ../output.py:1004
+#, python-format
+msgid ""
+"Install   %5.5s Package(s)\n"
+"Upgrade   %5.5s Package(s)\n"
+msgstr ""
+"Instal·la     %5.5s paquets\n"
+"Actualitza    %5.5s paquets\n"
+
+
+#: ../output.py:1013
+#, python-format //paraula downgrade
+msgid ""
+"Remove    %5.5s Package(s)\n"
+"Reinstall %5.5s Package(s)\n"
+"Downgrade %5.5s Package(s)\n"
+msgstr ""
+"Suprimeix     %5.5s paquets\n"
+"Reinstal·la   %5.5s paquets\n"
+"Desactualitza %5.5s paquets\n"
+
+#: ../output.py:1057
 msgid "Removed"
-msgstr "Esborrat"
+msgstr "Suprimit"
 
-#: ../output.py:1026
+#: ../output.py:1058
 msgid "Dependency Removed"
-msgstr "Dependència esborrada"
+msgstr "Dependència suprimida"
 
-#: ../output.py:1028
+#: ../output.py:1060
 msgid "Dependency Installed"
 msgstr "Dependència instal·lada"
 
-#: ../output.py:1030
+#: ../output.py:1062
 msgid "Dependency Updated"
 msgstr "Dependència actualitzada"
 
-#: ../output.py:1032
+#: ../output.py:1064
 msgid "Replaced"
 msgstr "Reemplaçat"
 
-#: ../output.py:1033
+#: ../output.py:1065
 msgid "Failed"
 msgstr "Ha fallat"
 
 #. Delta between C-c's so we treat as exit
-#: ../output.py:1099
+#: ../output.py:1131
 msgid "two"
 msgstr "dos"
 
-#: ../output.py:1106
+#. For translators: This is output like:
+#. Current download cancelled, interrupt (ctrl-c) again within two seconds
+#. to exit.
+#. Where "interupt (ctrl-c) again" and "two" are highlighted.
+#: ../output.py:1142
 #, python-format
 msgid ""
 "\n"
-" Current download cancelled, %sinterrupt (ctrl-c) again%s within %s%s%s seconds to exit.\n"
+" Current download cancelled, %sinterrupt (ctrl-c) again%s within %s%s%s "
+"seconds\n"
+"to exit.\n"
 msgstr ""
 "\n"
-" S'ha cancel·lat la descàrrega actual, %sinterromp (crtl-c) de nou%s en %s%s%s segons per a sortir.\n"
+" S'ha cancel·lat la descàrrega actual, %sinterromp (crtl-c) de nou%s en %s%s%s "
+"segons\n"
+"per a sortir.\n"
 
-#: ../output.py:1116
+#: ../output.py:1153
 msgid "user interrupt"
 msgstr "interrupció de l'usuari"
 
-#: ../output.py:1132
+#: ../output.py:1171
 msgid "Total"
 msgstr "Total"
 
-#: ../output.py:1146
+#: ../output.py:1186
 msgid "installed"
 msgstr "instal·lat"
 
-#: ../output.py:1147
+#: ../output.py:1187
 msgid "updated"
 msgstr "actualitzat"
 
-#: ../output.py:1148
+#: ../output.py:1188
 msgid "obsoleted"
 msgstr "obsolet"
 
-#: ../output.py:1149
+#: ../output.py:1189
 msgid "erased"
-msgstr "esborrat"
+msgstr "suprimit"
 
-#: ../output.py:1153
+#: ../output.py:1193
 #, python-format
 msgid "---> Package %s.%s %s:%s-%s set to be %s"
 msgstr "---> Paquet %s.%s %s:%s-%s passarà a ser %s"
 
-#: ../output.py:1160
+#: ../output.py:1200
 msgid "--> Running transaction check"
 msgstr "--> S'està executant la transacció de prova"
 
-#: ../output.py:1165
+#: ../output.py:1205
 msgid "--> Restarting Dependency Resolution with new changes."
-msgstr "--> Tornant a calcular la resolució de dependències amb els nous canvis."
+msgstr ""
+"--> Tornant a calcular la resolució de dependències amb els nous canvis."
 
-#: ../output.py:1170
+#: ../output.py:1210
 msgid "--> Finished Dependency Resolution"
 msgstr "--> Ha finalitzat la resolució de dependències"
 
-#: ../output.py:1175
+#: ../output.py:1215 ../output.py:1220
 #, python-format
 msgid "--> Processing Dependency: %s for package: %s"
 msgstr "--> S'està processant la dependència %s per al paquet: %s"
 
-#: ../output.py:1180
+#: ../output.py:1224
 #, python-format
 msgid "--> Unresolved Dependency: %s"
 msgstr "--> Dependència no resolta: %s"
 
-#: ../output.py:1186
+#: ../output.py:1230 ../output.py:1235
 #, python-format
 msgid "--> Processing Conflict: %s conflicts %s"
 msgstr "--> S'està processant el conflicte: %s té un conflicte amb %s"
 
-#: ../output.py:1189
+#: ../output.py:1239
 msgid "--> Populating transaction set with selected packages. Please wait."
-msgstr "--> S'està poblant la transacció amb els paquets sel·leccionats. Si us plau, espereu."
+msgstr ""
+"--> S'està poblant la transacció amb els paquets sel·leccionats. Si us plau, "
+"espereu."
 
-#: ../output.py:1193
+#: ../output.py:1243
 #, python-format
 msgid "---> Downloading header for %s to pack into transaction set."
-msgstr "---> S'està descarregant la capçalera per a %s per a empaquetar dins de la transacció de prova."
+msgstr ""
+"---> S'està baixant la capçalera per a %s per a empaquetar dins de la "
+"transacció de prova."
 
-#: ../yumcommands.py:41
+#: ../yumcommands.py:40
 msgid "You need to be root to perform this command."
 msgstr "Heu de ser root per a executar aquesta ordre."
 
-#: ../yumcommands.py:48
+#: ../yumcommands.py:47
 msgid ""
 "\n"
 "You have enabled checking of packages via GPG keys. This is a good thing. \n"
-"However, you do not have any GPG public keys installed. You need to download\n"
+"However, you do not have any GPG public keys installed. You need to "
+"download\n"
 "the keys for packages you wish to install and install them.\n"
 "You can do that by running the command:\n"
 "    rpm --import public.gpg.key\n"
@@ -945,8 +985,10 @@ msgid ""
 "For more information contact your distribution or package provider.\n"
 msgstr ""
 "\n"
-"Heu habilitat la comprovació de paquets utilitzant claus GPG. És una bona opció. \n"
-"No obstant, no teniu cap clau pública GPG instal·lada. Necessiteu descarregar\n"
+"Heu habilitat la comprovació de paquets utilitzant claus GPG. És una bona "
+"opció. \n"
+"No obstant, no teniu cap clau pública GPG instal·lada. Necessiteu "
+"baixar\n"
 "les claus per als paquets que desitgeu instal·lar i instal·lar-les.\n"
 "Podeu fer-ho executant l'ordre:\n"
 "    rpm --import clau.pública.gpg\n"
@@ -956,163 +998,164 @@ msgstr ""
 "per a un repositori en l'opció 'gpgkey' en la secció d'un repositori i yum \n"
 "la instal·larà per vosaltres.\n"
 "\n"
-"Per a més informació contacteu el vostre distribuïdor o proveïdor de paquets.\n"
+"Per a més informació contacteu el vostre distribuïdor o proveïdor de "
+"paquets.\n"
 
-#: ../yumcommands.py:68
+#: ../yumcommands.py:67
 #, python-format
 msgid "Error: Need to pass a list of pkgs to %s"
 msgstr "Error: es necessita passar una llista de paquets a %s"
 
-#: ../yumcommands.py:74
+#: ../yumcommands.py:73
 msgid "Error: Need an item to match"
 msgstr "Error: es necessita algun element per comparar"
 
-#: ../yumcommands.py:80
+#: ../yumcommands.py:79
 msgid "Error: Need a group or list of groups"
 msgstr "Error: es necessita un grup o una llista de grups"
 
-#: ../yumcommands.py:89
+#: ../yumcommands.py:88
 #, python-format
 msgid "Error: clean requires an option: %s"
 msgstr "Error: la neteja requereix una opció: %s"
 
-#: ../yumcommands.py:94
+#: ../yumcommands.py:93
 #, python-format
 msgid "Error: invalid clean argument: %r"
 msgstr "Error: argument invàlid per a la neteja: %r"
 
-#: ../yumcommands.py:107
+#: ../yumcommands.py:106
 msgid "No argument to shell"
 msgstr "No hi ha arguments per a l'intèrpret d'ordres"
 
-#: ../yumcommands.py:110
+#: ../yumcommands.py:108
 #, python-format
 msgid "Filename passed to shell: %s"
 msgstr "Nom del fitxer passat a l'intèrpret d'ordres: %s"
 
-#: ../yumcommands.py:114
+#: ../yumcommands.py:112
 #, python-format
 msgid "File %s given as argument to shell does not exist."
 msgstr "El fitxer %s donat com a argument a l'intèrpret d'ordres no existeix."
 
-#: ../yumcommands.py:120
+#: ../yumcommands.py:118
 msgid "Error: more than one file given as argument to shell."
-msgstr "Error: s'ha donat més d'un fitxer com a argument per a l'intèrpret d'ordres."
+msgstr ""
+"Error: s'ha donat més d'un fitxer com a argument per a l'intèrpret d'ordres."
 
-#: ../yumcommands.py:169
+#: ../yumcommands.py:167
 msgid "PACKAGE..."
 msgstr "PAQUET..."
 
-#: ../yumcommands.py:172
+#: ../yumcommands.py:170
 msgid "Install a package or packages on your system"
 msgstr "Instal·la un o més paquets al vostre sistema"
 
-#: ../yumcommands.py:180
+#: ../yumcommands.py:178
 msgid "Setting up Install Process"
 msgstr "S'està preparant el procés d'instal·lació"
 
-#: ../yumcommands.py:191
+#: ../yumcommands.py:189
 msgid "[PACKAGE...]"
 msgstr "[PAQUET...]"
 
-#: ../yumcommands.py:194
+#: ../yumcommands.py:192
 msgid "Update a package or packages on your system"
 msgstr "S'ha actualitzat un o més paquets al vostre sistema"
 
-#: ../yumcommands.py:201
+#: ../yumcommands.py:199
 msgid "Setting up Update Process"
 msgstr "S'està preparant el procés d'actualització"
 
-#: ../yumcommands.py:243
+#: ../yumcommands.py:244
 msgid "Display details about a package or group of packages"
 msgstr "Mostra detalls sobre un paquet o un grup de paquets"
 
-#: ../yumcommands.py:292
+#: ../yumcommands.py:293
 msgid "Installed Packages"
 msgstr "Paquets instal·lats"
 
-#: ../yumcommands.py:300
+#: ../yumcommands.py:301
 msgid "Available Packages"
 msgstr "Paquets disponibles"
 
-#: ../yumcommands.py:304
+#: ../yumcommands.py:305
 msgid "Extra Packages"
 msgstr "Paquets extra"
 
-#: ../yumcommands.py:308
+#: ../yumcommands.py:309
 msgid "Updated Packages"
 msgstr "Paquets actualitzats"
 
 #. This only happens in verbose mode
-#: ../yumcommands.py:316
-#: ../yumcommands.py:323
-#: ../yumcommands.py:600
+#: ../yumcommands.py:317 ../yumcommands.py:324 ../yumcommands.py:600
 msgid "Obsoleting Packages"
 msgstr "Paquets obsolets"
 
-#: ../yumcommands.py:325
+#: ../yumcommands.py:326
 msgid "Recently Added Packages"
 msgstr "Paquets recentment afegits"
 
-#: ../yumcommands.py:332
+#: ../yumcommands.py:333
 msgid "No matching Packages to list"
 msgstr "No hi ha paquets coincidents per llistar"
 
-#: ../yumcommands.py:346
+#: ../yumcommands.py:347
 msgid "List a package or groups of packages"
 msgstr "Llista un paquet o un grup de paquets"
 
-#: ../yumcommands.py:358
+#: ../yumcommands.py:359
 msgid "Remove a package or packages from your system"
-msgstr "Esborra un o més paquets del vostre sistema"
+msgstr "Suprimeix un o més paquets del vostre sistema"
 
-#: ../yumcommands.py:365
+#: ../yumcommands.py:366
 msgid "Setting up Remove Process"
-msgstr "S'està preparant el procés d'esborrat"
+msgstr "S'està preparant el procés de supressió"
 
-#: ../yumcommands.py:379
+#: ../yumcommands.py:380
 msgid "Setting up Group Process"
 msgstr "S'està preparant el procés de grup"
 
-#: ../yumcommands.py:385
+#: ../yumcommands.py:386
 msgid "No Groups on which to run command"
 msgstr "No hi ha cap grup on executar l'ordre"
 
-#: ../yumcommands.py:398
+#: ../yumcommands.py:399
 msgid "List available package groups"
 msgstr "Llista els grups de paquets disponibles"
 
-#: ../yumcommands.py:415
+#: ../yumcommands.py:416
 msgid "Install the packages in a group on your system"
 msgstr "Instal·la els paquets en un grup en el vostre sistema"
 
-#: ../yumcommands.py:437
+#: ../yumcommands.py:438
 msgid "Remove the packages in a group from your system"
-msgstr "Esborra els paquets en un grup en el vostre sistema"
+msgstr "Suprimeix els paquets en un grup en el vostre sistema"
 
-#: ../yumcommands.py:464
+#: ../yumcommands.py:465
 msgid "Display details about a package group"
 msgstr "Mostra detalls sobre un grup de paquets"
 
-#: ../yumcommands.py:488
+#: ../yumcommands.py:489
 msgid "Generate the metadata cache"
 msgstr "Genera les metadades de la memòria cau"
 
-#: ../yumcommands.py:494
+#: ../yumcommands.py:495
 msgid "Making cache files for all metadata files."
-msgstr "S'estan fent els fitxers de memòria cau per a tots els fitxers de metadades."
+msgstr ""
+"S'estan fent els fitxers de memòria cau per a tots els fitxers de metadades."
 
-#: ../yumcommands.py:495
+#: ../yumcommands.py:496
 msgid "This may take a while depending on the speed of this computer"
 msgstr "Això pot trigar una estona depenent de la velocitat d'aquest ordinador"
 
-#: ../yumcommands.py:516
+#: ../yumcommands.py:517
 msgid "Metadata Cache Created"
 msgstr "S'han creat les metadades per a la memòria cau"
 
-#: ../yumcommands.py:530
+#: ../yumcommands.py:531
 msgid "Remove cached data"
-msgstr "S'han esborrat les dades de la memòria cau"
+msgstr "S'han suprimit les dades de la memòria cau"
 
 #: ../yumcommands.py:551
 msgid "Find what package provides the given value"
@@ -1174,99 +1217,122 @@ msgstr "S'estan trobant dependències: "
 msgid "Display the configured software repositories"
 msgstr "Mostra els repositoris de programari configurats"
 
-#: ../yumcommands.py:803
-#: ../yumcommands.py:804
+#: ../yumcommands.py:803 ../yumcommands.py:804
 msgid "enabled"
 msgstr "habilitat"
 
-#: ../yumcommands.py:812
-#: ../yumcommands.py:813
+#: ../yumcommands.py:812 ../yumcommands.py:813
 msgid "disabled"
 msgstr "deshabilitat"
 
 #: ../yumcommands.py:827
-msgid "Repo-id     : "
-msgstr "Id-repo         : "
+msgid "Repo-id      : "
+msgstr "Id-repo           : "
 
 #: ../yumcommands.py:828
-msgid "Repo-name   : "
-msgstr "Nom-repo        : "
+msgid "Repo-name    : "
+msgstr "Nom-repo          : "
 
 #: ../yumcommands.py:829
-msgid "Repo-status : "
-msgstr "Estat-repo      : "
+msgid "Repo-status  : "
+msgstr "Estat-repo        : "
 
 #: ../yumcommands.py:831
 msgid "Repo-revision: "
-msgstr "Repo-revisió    : "
+msgstr "Repo-revisió      : "
 
 #: ../yumcommands.py:835
-msgid "Repo-tags   : "
-msgstr "Repo-etiquetes  : "
+msgid "Repo-tags    : "
+msgstr "Repo-etiquetes    : "
 
 #: ../yumcommands.py:841
 msgid "Repo-distro-tags: "
-msgstr "Repo-etiq-dist  : "
+msgstr "Repo-etiq-dist    : "
 
 #: ../yumcommands.py:846
-msgid "Repo-updated: "
-msgstr "Repo-actualitzat: "
+msgid "Repo-updated : "
+msgstr "Repo-actualitzat  : "
 
 #: ../yumcommands.py:848
-msgid "Repo-pkgs   : "
-msgstr "Paquets-repo    : "
+msgid "Repo-pkgs    : "
+msgstr "Paquets-repo      : "
 
 #: ../yumcommands.py:849
-msgid "Repo-size   : "
-msgstr "Mida-repo       : "
+msgid "Repo-size    : "
+msgstr "Mida-repo         : "
 
 #: ../yumcommands.py:856
-msgid "Repo-baseurl: "
-msgstr "URL-base-repo   : "
+msgid "Repo-baseurl : "
+msgstr "URL-base-repo     : "
 
-#: ../yumcommands.py:860
+#: ../yumcommands.py:864
 msgid "Repo-metalink: "
-msgstr "Repo-metaenllaç : "
-
-#: ../yumcommands.py:863
-msgid "Repo-mirrors: "
-msgstr "Miralls-repo    : "
+msgstr "Repo-metaenllaç   : "
 
-#: ../yumcommands.py:867
-msgid "Repo-exclude: "
-msgstr "Repo-exclou     : "
+#: ../yumcommands.py:868
+#,
+msgid "  Updated    : "
+msgstr "  Actualitzat     : "
 
 #: ../yumcommands.py:871
-msgid "Repo-include: "
-msgstr "Repo-inclou     : "
+msgid "Repo-mirrors : "
+msgstr "Miralls-repo      : "
+
+#: ../yumcommands.py:875 ../yummain.py:133
+msgid "Unknown"
+msgstr "Desconegut"
+
+#: ../yumcommands.py:881
+#, python-format
+msgid "Never (last: %s)"
+msgstr "Mai (últim: %s)"
+
+#: ../yumcommands.py:883
+#, python-format
+msgid "Instant (last: %s)"
+msgstr "Temps d'instal·lació (últim: %s)"
+
+#: ../yumcommands.py:886
+#, python-format
+msgid "%s second(s) (last: %s)"
+msgstr "%s segons (últim: %s)"
+
+#: ../yumcommands.py:888
+msgid "Repo-expire  : "
+msgstr "Venç-repo   : "
+
+#: ../yumcommands.py:891
+msgid "Repo-exclude : "
+msgstr "Repo-exclou : "
+
+#: ../yumcommands.py:895
+msgid "Repo-include : "
+msgstr "Repo-inclou : "
 
 #. Work out the first (id) and last (enabled/disalbed/count),
 #. then chop the middle (name)...
-#: ../yumcommands.py:881
-#: ../yumcommands.py:907
+#: ../yumcommands.py:905 ../yumcommands.py:931
 msgid "repo id"
 msgstr "id repo"
 
-#: ../yumcommands.py:895
-#: ../yumcommands.py:896
-#: ../yumcommands.py:910
+#: ../yumcommands.py:919 ../yumcommands.py:920 ../yumcommands.py:934
 msgid "status"
 msgstr "estat"
 
-#: ../yumcommands.py:908
+#: ../yumcommands.py:932
 msgid "repo name"
 msgstr "nom repo"
 
-#: ../yumcommands.py:934
+#: ../yumcommands.py:958
 msgid "Display a helpful usage message"
 msgstr "Mostra un missatge d'ajuda d'ús"
 
-#: ../yumcommands.py:968
+#: ../yumcommands.py:992
 #, python-format
 msgid "No help available for %s"
 msgstr "No hi ha ajuda disponible per a %s"
 
-#: ../yumcommands.py:973
+#: ../yumcommands.py:997
 msgid ""
 "\n"
 "\n"
@@ -1276,7 +1342,7 @@ msgstr ""
 "\n"
 "àlies: "
 
-#: ../yumcommands.py:975
+#: ../yumcommands.py:999
 msgid ""
 "\n"
 "\n"
@@ -1286,26 +1352,36 @@ msgstr ""
 "\n"
 "àlies: "
 
-#: ../yumcommands.py:1003
+#: ../yumcommands.py:1027
 msgid "Setting up Reinstall Process"
 msgstr "S'està preparant el procés de reinstal·lació"
 
-#: ../yumcommands.py:1012
-msgid "Package(s) to reinstall"
-msgstr "Paquets a reinstal·lar"
-
-#: ../yumcommands.py:1019
+#: ../yumcommands.py:1035
 msgid "reinstall a package"
 msgstr "reinstal·la un paquet"
 
-#: ../yumcommands.py:1037
+#: ../yumcommands.py:1053
 msgid "Setting up Downgrade Process"
 msgstr "S'està preparant el procés de desactualització"
 
-#: ../yumcommands.py:1044
+#: ../yumcommands.py:1060
 msgid "downgrade a package"
 msgstr "desactualitza un paquet"
 
+#: ../yumcommands.py:1074
+msgid "Display a version for the machine and/or available repos."
+msgstr "Mostra una versió per a la màquina i/o repositoris disponibles"
+
+#: ../yumcommands.py:1101
+#,
+msgid "Installed:"
+msgstr "Instal·lat:"
+
+#: ../yumcommands.py:1110
+#, 
+msgid "Available:"
+msgstr "Disponible:"
+
 #: ../yummain.py:42
 msgid ""
 "\n"
@@ -1326,80 +1402,87 @@ msgstr ""
 "\n"
 "S'està sortint en trobar la canonada trencada"
 
-#: ../yummain.py:126
+#: ../yummain.py:50
+#, python-format
+msgid ""
+"\n"
+"\n"
+"%s"
+msgstr ""
+"\n"
+"\n"
+"%s"
+
+#: ../yummain.py:128
 msgid "Running"
 msgstr "S'està executant"
 
-#: ../yummain.py:127
+#: ../yummain.py:129
 msgid "Sleeping"
 msgstr "Està dormint"
 
-#: ../yummain.py:128
+#: ../yummain.py:130
 msgid "Uninteruptable"
 msgstr "Ininterrumpible"
 
-#: ../yummain.py:129
+#: ../yummain.py:131
 msgid "Zombie"
 msgstr "Zombi"
 
-#: ../yummain.py:130
+#: ../yummain.py:132
 msgid "Traced/Stopped"
 msgstr "Traçat/aturat"
 
-#: ../yummain.py:131
-msgid "Unknown"
-msgstr "Desconegut"
-
-#: ../yummain.py:135
+#: ../yummain.py:137
 msgid "  The other application is: PackageKit"
 msgstr "  L'altre aplicatiu és: PackageKit"
 
-#: ../yummain.py:137
+#: ../yummain.py:139
 #, python-format
 msgid "  The other application is: %s"
 msgstr "  L'altre aplicatiu és: %s"
 
-#: ../yummain.py:140
+#: ../yummain.py:142
 #, python-format
 msgid "    Memory : %5s RSS (%5sB VSZ)"
 msgstr "    Memòria : %5s RSS (%5sB VSZ)"
 
-#: ../yummain.py:144
+#: ../yummain.py:146
 #, python-format
 msgid "    Started: %s - %s ago"
 msgstr "    Iniciat: fa %s-%s"
 
-#: ../yummain.py:146
+#: ../yummain.py:148
 #, python-format
 msgid "    State  : %s, pid: %d"
 msgstr "    Estat  : %s, pid: %d"
 
-#: ../yummain.py:171
-msgid "Another app is currently holding the yum lock; waiting for it to exit..."
-msgstr "Alguna altra aplicació té el bloqueig del yum; s'està esperant a que surti..."
+#: ../yummain.py:173
+msgid ""
+"Another app is currently holding the yum lock; waiting for it to exit..."
+msgstr ""
+"Alguna altra aplicació té el bloqueig del yum; s'està esperant a que surti..."
 
-#: ../yummain.py:199
-#: ../yummain.py:238
+#: ../yummain.py:201 ../yummain.py:240
 #, python-format
 msgid "Error: %s"
 msgstr "Error: %s"
 
-#: ../yummain.py:209
-#: ../yummain.py:250
+#: ../yummain.py:211 ../yummain.py:253
 #, python-format
 msgid "Unknown Error(s): Exit Code: %d:"
 msgstr "Errors desconeguts: Codi de sortida: %d:"
 
 #. Depsolve stage
-#: ../yummain.py:216
+#: ../yummain.py:218
 msgid "Resolving Dependencies"
 msgstr "S'estan resolent dependències"
 
-#: ../yummain.py:240
+#: ../yummain.py:242
 msgid " You could try using --skip-broken to work around the problem"
 msgstr " Hauríeu de provar utilitzant --skip-broken per evitar el problema"
 
-#: ../yummain.py:241
+#: ../yummain.py:243
 msgid ""
 " You could try running: package-cleanup --problems\n"
 "                        package-cleanup --dupes\n"
@@ -1409,7 +1492,7 @@ msgstr ""
 "                        package-cleanup --dupes\n"
 "                        rpm -Va --nofiles --nodigest"
 
-#: ../yummain.py:256
+#: ../yummain.py:259
 msgid ""
 "\n"
 "Dependencies Resolved"
@@ -1417,11 +1500,11 @@ msgstr ""
 "\n"
 "Dependències resoltes"
 
-#: ../yummain.py:270
+#: ../yummain.py:273
 msgid "Complete!"
 msgstr "Completat!"
 
-#: ../yummain.py:317
+#: ../yummain.py:320
 msgid ""
 "\n"
 "\n"
@@ -1431,201 +1514,205 @@ msgstr ""
 "\n"
 "S'està sortint de l'ordre de l'usuari."
 
-#: ../yum/depsolve.py:84
+#: ../yum/depsolve.py:83
 msgid "doTsSetup() will go away in a future version of Yum.\n"
 msgstr "doTsSetup() desapareixerà en una futura versió de Yum.\n"
 
-#: ../yum/depsolve.py:99
+#: ../yum/depsolve.py:98
 msgid "Setting up TransactionSets before config class is up"
-msgstr "S'està configurant TransactionSets abans que la classe de configuració estigui iniciada"
+msgstr ""
+"S'està configurant TransactionSets abans que la classe de configuració "
+"estigui iniciada"
 
-#: ../yum/depsolve.py:150
+#: ../yum/depsolve.py:149
 #, python-format
 msgid "Invalid tsflag in config file: %s"
 msgstr "Tsflag invàlid en el fitxer de configuració: %s"
 
-#: ../yum/depsolve.py:161
+#: ../yum/depsolve.py:160
 #, python-format
 msgid "Searching pkgSack for dep: %s"
 msgstr "S'està buscant pkgSack per a la dependència: %s"
 
-#: ../yum/depsolve.py:184
+#: ../yum/depsolve.py:183
 #, python-format
 msgid "Potential match for %s from %s"
 msgstr "Coincidència potencial per a %s de %s"
 
-#: ../yum/depsolve.py:192
+#: ../yum/depsolve.py:191
 #, python-format
 msgid "Matched %s to require for %s"
 msgstr "La coincidència %s es requereix per a %s"
 
-#: ../yum/depsolve.py:233
+#: ../yum/depsolve.py:232
 #, python-format
 msgid "Member: %s"
 msgstr "Membre: %s"
 
-#: ../yum/depsolve.py:247
-#: ../yum/depsolve.py:739
+#: ../yum/depsolve.py:246 ../yum/depsolve.py:756
 #, python-format
 msgid "%s converted to install"
 msgstr "%s convertits per a instal·lar"
 
-#: ../yum/depsolve.py:254
+#: ../yum/depsolve.py:253
 #, python-format
 msgid "Adding Package %s in mode %s"
 msgstr "S'està afegint el paquet %s en mode %s"
 
-#: ../yum/depsolve.py:264
+#: ../yum/depsolve.py:263
 #, python-format
 msgid "Removing Package %s"
-msgstr "S'està esborrant el paquet %s"
+msgstr "S'està suprimint el paquet %s"
 
-#: ../yum/depsolve.py:275
+#: ../yum/depsolve.py:285
 #, python-format
 msgid "%s requires: %s"
 msgstr "%s requereix: %s"
 
-#: ../yum/depsolve.py:333
+#: ../yum/depsolve.py:343
 msgid "Needed Require has already been looked up, cheating"
-msgstr "El requeriment necessari ja s'ha buscat anteriorment, s'estan fent trampes"
+msgstr ""
+"El requeriment necessari ja s'ha buscat anteriorment, s'estan fent trampes"
 
-#: ../yum/depsolve.py:343
+#: ../yum/depsolve.py:353
 #, python-format
 msgid "Needed Require is not a package name. Looking up: %s"
 msgstr "El requeriment necessari no és un nom de paquet. S'està buscant: %s"
 
-#: ../yum/depsolve.py:350
+#: ../yum/depsolve.py:360
 #, python-format
 msgid "Potential Provider: %s"
 msgstr "Proveïdor potencial: %s"
 
-#: ../yum/depsolve.py:373
+#: ../yum/depsolve.py:383
 #, python-format
 msgid "Mode is %s for provider of %s: %s"
 msgstr "El mode és %s per al proveïdor de %s: %s"
 
-#: ../yum/depsolve.py:377
+#: ../yum/depsolve.py:387
 #, python-format
 msgid "Mode for pkg providing %s: %s"
 msgstr "Mode per al paquet que proporciona %s: %s"
 
-#: ../yum/depsolve.py:381
+#: ../yum/depsolve.py:391
 #, python-format
 msgid "TSINFO: %s package requiring %s marked as erase"
-msgstr "TSINFO: el paquet %s requereix %s marcat per a esborrar"
+msgstr "TSINFO: el paquet %s requereix %s marcat per a suprimir"
 
-#: ../yum/depsolve.py:394
+#: ../yum/depsolve.py:404
 #, python-format
 msgid "TSINFO: Obsoleting %s with %s to resolve dep."
-msgstr "TSINFO: S'està marcant com a obsolet %s amb %s per resoldre dependències."
+msgstr ""
+"TSINFO: S'està marcant com a obsolet %s amb %s per resoldre dependències."
 
-#: ../yum/depsolve.py:397
+#: ../yum/depsolve.py:407
 #, python-format
 msgid "TSINFO: Updating %s to resolve dep."
 msgstr "TSINFO: S'està actualitzant %s per a resoldre dependències."
 
-#: ../yum/depsolve.py:405
+#: ../yum/depsolve.py:415
 #, python-format
 msgid "Cannot find an update path for dep for: %s"
 msgstr "No es pot trobar un camí d'actualització de dependències per a: %s"
 
-#: ../yum/depsolve.py:415
+#: ../yum/depsolve.py:425
 #, python-format
 msgid "Unresolvable requirement %s for %s"
 msgstr "No es pot resoldre el requeriment %s per a %s"
 
-#: ../yum/depsolve.py:438
+#: ../yum/depsolve.py:448
 #, python-format
 msgid "Quick matched %s to require for %s"
 msgstr "La coincidència %s es requereix per a %s"
 
 #. is it already installed?
-#: ../yum/depsolve.py:480
+#: ../yum/depsolve.py:490
 #, python-format
 msgid "%s is in providing packages but it is already installed, removing."
-msgstr "%s es troba en els paquets proporcionats però ja es troba instal·lat, s'està esborrant."
+msgstr ""
+"%s es troba en els paquets proporcionats però ja es troba instal·lat, s'està "
+"suprimint."
 
-#: ../yum/depsolve.py:496
+#: ../yum/depsolve.py:506
 #, python-format
 msgid "Potential resolving package %s has newer instance in ts."
-msgstr "El paquet potencial que resol dependències %s té una instància nova a ts"
+msgstr ""
+"El paquet potencial que resol dependències %s té una instància nova a ts"
 
-#: ../yum/depsolve.py:507
+#: ../yum/depsolve.py:517
 #, python-format
 msgid "Potential resolving package %s has newer instance installed."
-msgstr "El paquet potencial que resol dependències %s té una nova instància insta·lada."
+msgstr ""
+"El paquet potencial que resol dependències %s té una nova instància "
+"insta·lada."
 
-#: ../yum/depsolve.py:515
-#: ../yum/depsolve.py:564
+#: ../yum/depsolve.py:525 ../yum/depsolve.py:571
 #, python-format
 msgid "Missing Dependency: %s is needed by package %s"
 msgstr "Manca una dependència: %s es necessita per al paquet %s"
 
-#: ../yum/depsolve.py:528
+#: ../yum/depsolve.py:538
 #, python-format
 msgid "%s already in ts, skipping this one"
 msgstr "%s ja es troba en ts, s'està ometent"
 
-#: ../yum/depsolve.py:574
+#: ../yum/depsolve.py:581
 #, python-format
 msgid "TSINFO: Marking %s as update for %s"
 msgstr "TSINFO: S'està marcant %s com a actualització per a %s"
 
-#: ../yum/depsolve.py:582
+#: ../yum/depsolve.py:589
 #, python-format
 msgid "TSINFO: Marking %s as install for %s"
 msgstr "TSINFO: S'està marcant %s com a instal·lació per a %s"
 
-#: ../yum/depsolve.py:675
-#: ../yum/depsolve.py:757
+#: ../yum/depsolve.py:692 ../yum/depsolve.py:774
 msgid "Success - empty transaction"
 msgstr "Èxit - transacció buida"
 
-#: ../yum/depsolve.py:714
-#: ../yum/depsolve.py:729
+#: ../yum/depsolve.py:731 ../yum/depsolve.py:746
 msgid "Restarting Loop"
 msgstr "S'està recomençant el bucle"
 
-#: ../yum/depsolve.py:745
+#: ../yum/depsolve.py:762
 msgid "Dependency Process ending"
 msgstr "Està acabant el procés de dependències"
 
-#: ../yum/depsolve.py:751
+#: ../yum/depsolve.py:768
 #, python-format
 msgid "%s from %s has depsolving problems"
 msgstr "%s de %s té problemes resolent dependències"
 
-#: ../yum/depsolve.py:758
+#: ../yum/depsolve.py:775
 msgid "Success - deps resolved"
 msgstr "Èxit - dependències resoltes"
 
-#: ../yum/depsolve.py:772
+#: ../yum/depsolve.py:789
 #, python-format
 msgid "Checking deps for %s"
 msgstr "S'estan comprobant les dependències per a %s"
 
-#: ../yum/depsolve.py:855
+#: ../yum/depsolve.py:872
 #, python-format
 msgid "looking for %s as a requirement of %s"
 msgstr "s'està buscant %s com a requeriment de %s"
 
-#: ../yum/depsolve.py:997
+#: ../yum/depsolve.py:1014
 #, python-format
 msgid "Running compare_providers() for %s"
 msgstr "S'està executant compare_providers() per a %s"
 
-#: ../yum/depsolve.py:1025
-#: ../yum/depsolve.py:1031
+#: ../yum/depsolve.py:1048 ../yum/depsolve.py:1054
 #, python-format
 msgid "better arch in po %s"
 msgstr "millor arq en el po %s"
 
-#: ../yum/depsolve.py:1092
+#: ../yum/depsolve.py:1140
 #, python-format
 msgid "%s obsoletes %s"
 msgstr "%s fa obsolet %s"
 
-#: ../yum/depsolve.py:1108
+#: ../yum/depsolve.py:1152
 #, python-format
 msgid ""
 "archdist compared %s to %s on %s\n"
@@ -1634,112 +1721,121 @@ msgstr ""
 "archdist ha comparat %s amb %s a %s\n"
 "  Ha guanyat: %s"
 
-#: ../yum/depsolve.py:1115
+#: ../yum/depsolve.py:1159
 #, python-format
 msgid "common sourcerpm %s and %s"
 msgstr "rpm font comú %s i %s"
 
-#: ../yum/depsolve.py:1121
+#: ../yum/depsolve.py:1165
 #, python-format
 msgid "common prefix of %s between %s and %s"
 msgstr "prefix comú de %s entre %s i %s"
 
-#: ../yum/depsolve.py:1129
+#: ../yum/depsolve.py:1173
 #, python-format
 msgid "Best Order: %s"
 msgstr "Millor ordre: %s"
 
-#: ../yum/__init__.py:158
+#: ../yum/__init__.py:180
 msgid "doConfigSetup() will go away in a future version of Yum.\n"
 msgstr "doConfigsetup() desapareixerà en una futura versió de Yum.\n"
 
-#: ../yum/__init__.py:367
+#: ../yum/__init__.py:401
 #, python-format
 msgid "Repository %r is missing name in configuration, using id"
 msgstr "Falta el nom del repositori %r en la configuració, s'utilitzarà l'id"
 
-#: ../yum/__init__.py:405
+#: ../yum/__init__.py:439
 msgid "plugins already initialised"
 msgstr "els connectors ja estan inicialitzats"
 
-#: ../yum/__init__.py:412
+#: ../yum/__init__.py:446
 msgid "doRpmDBSetup() will go away in a future version of Yum.\n"
 msgstr "doRpmDBSetup() desapareixerà en una futura versió de Yum.\n"
 
-#: ../yum/__init__.py:423
+#: ../yum/__init__.py:457
 msgid "Reading Local RPMDB"
 msgstr "S'està llegint un RPMDB local"
 
-#: ../yum/__init__.py:441
+#: ../yum/__init__.py:478
 msgid "doRepoSetup() will go away in a future version of Yum.\n"
 msgstr "doRepoSetup() desapareixerà en una futura versió de Yum.\n"
 
-#: ../yum/__init__.py:461
+#: ../yum/__init__.py:498
 msgid "doSackSetup() will go away in a future version of Yum.\n"
 msgstr "doSackSetup() desapareixerà en una versió futura de Yum.\n"
 
-#: ../yum/__init__.py:478
+#: ../yum/__init__.py:528
 msgid "Setting up Package Sacks"
 msgstr "S'estan configurant els sacs de paquets"
 
-#: ../yum/__init__.py:521
+#: ../yum/__init__.py:573
 #, python-format
 msgid "repo object for repo %s lacks a _resetSack method\n"
 msgstr "l'objecte repositori per al repositori %s no té un mètode _resetSack\n"
 
-#: ../yum/__init__.py:522
+#: ../yum/__init__.py:574
 msgid "therefore this repo cannot be reset.\n"
 msgstr "Aquest repositori no es pot reiniciar.\n"
 
-#: ../yum/__init__.py:527
+#: ../yum/__init__.py:579
 msgid "doUpdateSetup() will go away in a future version of Yum.\n"
 msgstr "doUpdateSetup() desapareixerà en una futura versió de Yum.\n"
 
-#: ../yum/__init__.py:539
+#: ../yum/__init__.py:591
 msgid "Building updates object"
 msgstr "S'està construint l'objecte d'actualitzacions"
 
-#: ../yum/__init__.py:570
+#: ../yum/__init__.py:626
 msgid "doGroupSetup() will go away in a future version of Yum.\n"
 msgstr "doGroupSetup() desapareixerà en una futura versió de Yum.\n"
 
-#: ../yum/__init__.py:595
+#: ../yum/__init__.py:651
 msgid "Getting group metadata"
 msgstr "S'estan obtenint les metadades del grup"
 
-#: ../yum/__init__.py:621
+#: ../yum/__init__.py:677
 #, python-format
 msgid "Adding group file from repository: %s"
 msgstr "S'està afegint el fitxer del grup des del repositori: %s"
 
-#: ../yum/__init__.py:630
+#: ../yum/__init__.py:686
 #, python-format
 msgid "Failed to add groups file for repository: %s - %s"
 msgstr "No s'ha pogut afegir el fitxer dels grups des del repositori: %s - %s"
 
-#: ../yum/__init__.py:636
+#: ../yum/__init__.py:692
 msgid "No Groups Available in any repository"
 msgstr "No hi ha cap grup disponible en cap repositori"
 
-#: ../yum/__init__.py:686
+#: ../yum/__init__.py:742
 msgid "Importing additional filelist information"
 msgstr "S'està important informació adicional de la llista de fitxers"
 
-#: ../yum/__init__.py:695
-msgid "There are unfinished transactions remaining. You might consider running yum-complete-transaction first to finish them."
-msgstr "Encara hi ha transaccions sense acabar. Hauríeu de considerar executar yum-complete-transaction abans per acabar-les."
+#: ../yum/__init__.py:756
+#, python-format
+msgid "The program %s%s%s is found in the yum-utils package."
+msgstr "El programa %s%s%s es troba en el paquet yum-utils."
+
+#: ../yum/__init__.py:764
+msgid ""
+"There are unfinished transactions remaining. You might consider running yum-"
+"complete-transaction first to finish them."
+msgstr ""
+"Encara hi ha transaccions sense acabar. Hauríeu de considerar executar yum-"
+"complete-transaction abans per acabar-les."
 
-#: ../yum/__init__.py:761
+#: ../yum/__init__.py:832
 #, python-format
 msgid "Skip-broken round %i"
 msgstr "Intent %i d'omissió dels paquets trencats"
 
-#: ../yum/__init__.py:813
+#: ../yum/__init__.py:884
 #, python-format
 msgid "Skip-broken took %i rounds "
 msgstr "L'omissió dels paquets trencats ha necessitat %i intents"
 
-#: ../yum/__init__.py:814
+#: ../yum/__init__.py:885
 msgid ""
 "\n"
 "Packages skipped because of dependency problems:"
@@ -1747,89 +1843,74 @@ msgstr ""
 "\n"
 "Paquets omesos degut a problemes de dependències:"
 
-#: ../yum/__init__.py:818
+#: ../yum/__init__.py:889
 #, python-format
 msgid "    %s from %s"
 msgstr "    %s des de %s"
 
-#: ../yum/__init__.py:958
-msgid "Warning: scriptlet or other non-fatal errors occurred during transaction."
-msgstr "Avís: ha fallat l'scriptlet o s'han produït altre tipus d'errors no fatals durant la transacció."
+#: ../yum/__init__.py:1027
+msgid ""
+"Warning: scriptlet or other non-fatal errors occurred during transaction."
+msgstr ""
+"Avís: ha fallat l'scriptlet o s'han produït altre tipus d'errors no fatals "
+"durant la transacció."
 
-#: ../yum/__init__.py:973
+#: ../yum/__init__.py:1042
 #, python-format
 msgid "Failed to remove transaction file %s"
-msgstr "No s'ha pogut esborrar el fitxer de transaccions %s"
+msgstr "No s'ha pogut suprimir el fitxer de transaccions %s"
 
-#: ../yum/__init__.py:1015
+#. maybe a file log here, too
+#. but raising an exception is not going to do any good
+#: ../yum/__init__.py:1071
 #, python-format
-msgid "excluding for cost: %s from %s"
-msgstr "s'està excloent per cost: %s de %s"
-
-#: ../yum/__init__.py:1046
-msgid "Excluding Packages in global exclude list"
-msgstr "S'estan excloent paquets en la llista global d'exclusió"
+msgid "%s was supposed to be installed but is not!"
+msgstr "S'havia d'instal·lar %s però no s'ha realitzat!"
 
-#: ../yum/__init__.py:1048
+#. maybe a file log here, too
+#. but raising an exception is not going to do any good
+#: ../yum/__init__.py:1110
 #, python-format
-msgid "Excluding Packages from %s"
-msgstr "S'estan excloent paquets de %s"
-
-#: ../yum/__init__.py:1077
-#, python-format
-msgid "Reducing %s to included packages only"
-msgstr "S'està reduint %s únicament a paquets inclosos."
-
-#: ../yum/__init__.py:1083
-#, python-format
-msgid "Keeping included package %s"
-msgstr "S'està mantenint el paquet inclòs %s"
-
-#: ../yum/__init__.py:1089
-#, python-format
-msgid "Removing unmatched package %s"
-msgstr "S'està esborrant el paquet sense coincidències %s"
-
-#: ../yum/__init__.py:1092
-msgid "Finished"
-msgstr "Finalitzat"
+msgid "%s was supposed to be removed but is not!"
+msgstr "S'havia de suprimir %s però no s'ha realitzat!"
 
 #. Whoa. What the heck happened?
-#: ../yum/__init__.py:1122
+#: ../yum/__init__.py:1225
 #, python-format
 msgid "Unable to check if PID %s is active"
 msgstr "No s'ha pogut comprovar si el PID %s es troba actiu"
 
 #. Another copy seems to be running.
-#: ../yum/__init__.py:1126
+#: ../yum/__init__.py:1229
 #, python-format
 msgid "Existing lock %s: another copy is running as pid %s."
 msgstr "Bloqueig existent %s: una altra còpia s'està executant amb pid %s."
 
-#: ../yum/__init__.py:1196
+#: ../yum/__init__.py:1306
 msgid "Package does not match intended download"
 msgstr "El paquet no coincideix amb la descàrrega intentada"
 
-#: ../yum/__init__.py:1211
+#: ../yum/__init__.py:1321
 msgid "Could not perform checksum"
 msgstr "No s'ha pogut realitzar la suma de verificació"
 
-#: ../yum/__init__.py:1214
+#: ../yum/__init__.py:1324
 msgid "Package does not match checksum"
 msgstr "No coincideix la suma de verificació del paquet"
 
-#: ../yum/__init__.py:1257
+#: ../yum/__init__.py:1366
 #, python-format
 msgid "package fails checksum but caching is enabled for %s"
-msgstr "la suma de verificació del paquet falla però l'ús de memòria cau està habilitat per a %s"
+msgstr ""
+"la suma de verificació del paquet falla però l'ús de memòria cau està "
+"habilitat per a %s"
 
-#: ../yum/__init__.py:1260
-#: ../yum/__init__.py:1289
+#: ../yum/__init__.py:1369 ../yum/__init__.py:1398
 #, python-format
 msgid "using local copy of %s"
 msgstr "s'està utilitzant la còpia local de %s"
 
-#: ../yum/__init__.py:1301
+#: ../yum/__init__.py:1410
 #, python-format
 msgid ""
 "Insufficient space in download directory %s\n"
@@ -1840,441 +1921,462 @@ msgstr ""
 "    * lliure    %s\n"
 "    * necessari %s"
 
-#: ../yum/__init__.py:1348
+#: ../yum/__init__.py:1459
 msgid "Header is not complete."
 msgstr "La capçalera no està completa."
 
-#: ../yum/__init__.py:1385
+#: ../yum/__init__.py:1496
 #, python-format
-msgid "Header not in local cache and caching-only mode enabled. Cannot download %s"
-msgstr "La capçalera no es troba en la memòria cau local i està habilitat el mode de només memòria cau. No es pot descarregar %s"
+msgid ""
+"Header not in local cache and caching-only mode enabled. Cannot download %s"
+msgstr ""
+"La capçalera no es troba en la memòria cau local i està habilitat el mode de "
+"només memòria cau. No es pot baixar %s"
 
-#: ../yum/__init__.py:1440
+#: ../yum/__init__.py:1551
 #, python-format
 msgid "Public key for %s is not installed"
 msgstr "La clau pública per a %s no està instal·lada"
 
-#: ../yum/__init__.py:1444
+#: ../yum/__init__.py:1555
 #, python-format
 msgid "Problem opening package %s"
 msgstr "Hi ha hagut un problema obrint el paquet %s"
 
-#: ../yum/__init__.py:1452
+#: ../yum/__init__.py:1563
 #, python-format
 msgid "Public key for %s is not trusted"
 msgstr "La clau pública per a %s no és de confiança"
 
-#: ../yum/__init__.py:1456
+#: ../yum/__init__.py:1567
 #, python-format
 msgid "Package %s is not signed"
 msgstr "El paquet %s no està signat"
 
-#: ../yum/__init__.py:1494
+#: ../yum/__init__.py:1605
 #, python-format
 msgid "Cannot remove %s"
-msgstr "No es pot esborrar %s"
+msgstr "No es pot suprimir %s"
 
-#: ../yum/__init__.py:1498
+#: ../yum/__init__.py:1609
 #, python-format
 msgid "%s removed"
-msgstr "S'ha esborrat %s"
+msgstr "S'ha suprimit %s"
 
-#: ../yum/__init__.py:1534
+#: ../yum/__init__.py:1645
 #, python-format
 msgid "Cannot remove %s file %s"
-msgstr "No es pot esborrar %s fitxer %s"
+msgstr "No es pot suprimir %s fitxer %s"
 
-#: ../yum/__init__.py:1538
+#: ../yum/__init__.py:1649
 #, python-format
 msgid "%s file %s removed"
-msgstr "%s fitxer %s esborrat"
+msgstr "%s fitxer %s suprimit"
 
-#: ../yum/__init__.py:1540
+#: ../yum/__init__.py:1651
 #, python-format
 msgid "%d %s files removed"
-msgstr "%d %s fitxers esborrats"
+msgstr "%d %s fitxers suprimits"
 
-#: ../yum/__init__.py:1609
+#: ../yum/__init__.py:1720
 #, python-format
 msgid "More than one identical match in sack for %s"
 msgstr "Hi ha més d'una coincidència idèntica en el sac per a %s"
 
-#: ../yum/__init__.py:1615
+#: ../yum/__init__.py:1726
 #, python-format
 msgid "Nothing matches %s.%s %s:%s-%s from update"
 msgstr "No hi ha coincidències %s.%s-%s:%s-%s de l'actualització"
 
-#: ../yum/__init__.py:1833
-msgid "searchPackages() will go away in a future version of Yum.                      Use searchGenerator() instead. \n"
-msgstr "searchPackages() desapareixerà en una futura versió de Yum.                      Useu searchGenerator(). \n"
+#: ../yum/__init__.py:1959
+msgid ""
+"searchPackages() will go away in a future version of "
+"Yum.                      Use searchGenerator() instead. \n"
+msgstr ""
+"searchPackages() desapareixerà en una futura versió de "
+"Yum.                      Useu searchGenerator(). \n"
 
-#: ../yum/__init__.py:1875
+#: ../yum/__init__.py:2001
 #, python-format
 msgid "Searching %d packages"
 msgstr "S'estan buscant %d paquets"
 
-#: ../yum/__init__.py:1879
+#: ../yum/__init__.py:2005
 #, python-format
 msgid "searching package %s"
 msgstr "s'està buscant el paquet %s"
 
-#: ../yum/__init__.py:1891
+#: ../yum/__init__.py:2017
 msgid "searching in file entries"
 msgstr "s'està buscant en les entrades de fitxers"
 
-#: ../yum/__init__.py:1898
+#: ../yum/__init__.py:2024
 msgid "searching in provides entries"
 msgstr "s'està buscant en les entrades proporcionades"
 
-#: ../yum/__init__.py:1931
+#: ../yum/__init__.py:2057
 #, python-format
 msgid "Provides-match: %s"
 msgstr "Proporciona-coincideix: %s"
 
-#: ../yum/__init__.py:1980
+#: ../yum/__init__.py:2106
 msgid "No group data available for configured repositories"
 msgstr "No hi ha dades de grup disponibles en cap dels repositoris configurats"
 
-#: ../yum/__init__.py:2011
-#: ../yum/__init__.py:2030
-#: ../yum/__init__.py:2061
-#: ../yum/__init__.py:2067
-#: ../yum/__init__.py:2146
-#: ../yum/__init__.py:2150
-#: ../yum/__init__.py:2447
+#: ../yum/__init__.py:2137 ../yum/__init__.py:2156 ../yum/__init__.py:2187
+#: ../yum/__init__.py:2193 ../yum/__init__.py:2272 ../yum/__init__.py:2276
+#: ../yum/__init__.py:2586
 #, python-format
 msgid "No Group named %s exists"
 msgstr "No existeix cap grup anomenat %s"
 
-#: ../yum/__init__.py:2042
-#: ../yum/__init__.py:2163
+#: ../yum/__init__.py:2168 ../yum/__init__.py:2289
 #, python-format
 msgid "package %s was not marked in group %s"
 msgstr "el paquet %s no estava marcat en el grup %s"
 
-#: ../yum/__init__.py:2089
+#: ../yum/__init__.py:2215
 #, python-format
 msgid "Adding package %s from group %s"
 msgstr "S'està afegint el paquet %s del grup %s"
 
-#: ../yum/__init__.py:2093
+#: ../yum/__init__.py:2219
 #, python-format
 msgid "No package named %s available to be installed"
 msgstr "No hi ha cap paquet anomenat %s disponible per a ser instal·lat"
 
-#: ../yum/__init__.py:2190
+#: ../yum/__init__.py:2316
 #, python-format
 msgid "Package tuple %s could not be found in packagesack"
 msgstr "No s'ha pogut trobar la tupla de paquets %s al sac de paquets"
 
-#: ../yum/__init__.py:2205
-msgid "getInstalledPackageObject() will go away, use self.rpmdb.searchPkgTuple().\n"
-msgstr "getInstalledPackageObject() desapareixarà, useu self.rpmdb.searchPkgTuple().\n"
+#: ../yum/__init__.py:2330
+msgid ""
+"getInstalledPackageObject() will go away, use self.rpmdb.searchPkgTuple().\n"
+msgstr ""
+"getInstalledPackageObject() desapareixarà, useu self.rpmdb.searchPkgTuple"
+"().\n"
 
-#: ../yum/__init__.py:2261
-#: ../yum/__init__.py:2305
+#: ../yum/__init__.py:2386 ../yum/__init__.py:2436
 msgid "Invalid version flag"
 msgstr "Marcador de versió invàlid"
 
-#: ../yum/__init__.py:2276
-#: ../yum/__init__.py:2280
+#: ../yum/__init__.py:2406 ../yum/__init__.py:2411
 #, python-format
 msgid "No Package found for %s"
 msgstr "No s'ha trobat cap paquet per a %s"
 
-#: ../yum/__init__.py:2480
+#: ../yum/__init__.py:2627
 msgid "Package Object was not a package object instance"
 msgstr "L'objecte paquet no era una instància d'objecte paquet"
 
-#: ../yum/__init__.py:2484
+#: ../yum/__init__.py:2631
 msgid "Nothing specified to install"
 msgstr "No hi ha res especificat per a instal·lar"
 
-#: ../yum/__init__.py:2500
-#: ../yum/__init__.py:3127
+#: ../yum/__init__.py:2647 ../yum/__init__.py:3411
 #, python-format
 msgid "Checking for virtual provide or file-provide for %s"
-msgstr "S'està verificant si hi ha un proveïdor virtual o un fitxer proveïdor per a %s"
+msgstr ""
+"S'està verificant si hi ha un proveïdor virtual o un fitxer proveïdor per a %"
+"s"
 
-#: ../yum/__init__.py:2506
-#: ../yum/__init__.py:2783
-#: ../yum/__init__.py:2943
-#: ../yum/__init__.py:3133
+#: ../yum/__init__.py:2653 ../yum/__init__.py:2960 ../yum/__init__.py:3127
+#: ../yum/__init__.py:3417
 #, python-format
 msgid "No Match for argument: %s"
 msgstr "No hi ha cap coincidència per a l'argument: %s"
 
-#: ../yum/__init__.py:2580
+#: ../yum/__init__.py:2729
 #, python-format
 msgid "Package %s installed and not available"
 msgstr "El paquet %s es troba instal·lat però no és disponible"
 
-#: ../yum/__init__.py:2583
+#: ../yum/__init__.py:2732
 msgid "No package(s) available to install"
 msgstr "No hi ha cap paquet disponible per a instal·lar"
 
-#: ../yum/__init__.py:2595
+#: ../yum/__init__.py:2744
 #, python-format
 msgid "Package: %s  - already in transaction set"
 msgstr "El paquet: %s  - ja està en la transacció"
 
-#: ../yum/__init__.py:2610
+#: ../yum/__init__.py:2770
+#, python-format
+msgid "Package %s is obsoleted by %s which is already installed"
+msgstr "El paquet %s és obsolet degut a %s, que ja està instal·lat"
+
+#: ../yum/__init__.py:2773
 #, python-format
 msgid "Package %s is obsoleted by %s, trying to install %s instead"
-msgstr "El paquet %s és obsolet degut a %s, es provarà d'instal·lar %s"
+msgstr "El paquet %s és obsolet degut a %s, es provarà d'instal·lar %s en el seu lloc"
 
-#: ../yum/__init__.py:2618
+#: ../yum/__init__.py:2781
 #, python-format
 msgid "Package %s already installed and latest version"
 msgstr "El paquet %s ja es troba instal·lat i en l'última versió."
 
-#: ../yum/__init__.py:2632
+#: ../yum/__init__.py:2795
 #, python-format
 msgid "Package matching %s already installed. Checking for update."
-msgstr "El paquet coincident %s ja es troba instal·lat. S'està buscant una actualització."
+msgstr ""
+"El paquet coincident %s ja es troba instal·lat. S'està buscant una "
+"actualització."
 
 #. update everything (the easy case)
-#: ../yum/__init__.py:2718
+#: ../yum/__init__.py:2889
 msgid "Updating Everything"
 msgstr "S'està actualitzant tot"
 
-#: ../yum/__init__.py:2736
-#: ../yum/__init__.py:2845
-#: ../yum/__init__.py:2866
-#: ../yum/__init__.py:2892
+#: ../yum/__init__.py:2910 ../yum/__init__.py:3025 ../yum/__init__.py:3054
+#: ../yum/__init__.py:3081
 #, python-format
 msgid "Not Updating Package that is already obsoleted: %s.%s %s:%s-%s"
 msgstr "No s'actualitzarà el paquet obsolet: %s.%s %s:%s-%s"
 
-#: ../yum/__init__.py:2771
-#: ../yum/__init__.py:2940
+#: ../yum/__init__.py:2945 ../yum/__init__.py:3124
 #, python-format
 msgid "%s"
 msgstr "%s"
 
-#: ../yum/__init__.py:2836
+#: ../yum/__init__.py:3016
 #, python-format
 msgid "Package is already obsoleted: %s.%s %s:%s-%s"
 msgstr "El paquet és obsolet: %s.%s %s:%s-%s"
 
-#: ../yum/__init__.py:2869
-#: ../yum/__init__.py:2895
+#: ../yum/__init__.py:3049
+#, python-format
+msgid "Not Updating Package that is obsoleted: %s"
+msgstr "No s'actualitzarà el paquet obsolet: %s"
+
+#: ../yum/__init__.py:3058 ../yum/__init__.py:3085
 #, python-format
 msgid "Not Updating Package that is already updated: %s.%s %s:%s-%s"
 msgstr "No s'actualitzarà el paquet actualitzat: %s.%s %s:%s-%s"
 
-#: ../yum/__init__.py:2956
+#: ../yum/__init__.py:3140
 msgid "No package matched to remove"
-msgstr "No hi ha cap paquet coincident per a esborrar"
+msgstr "No hi ha cap paquet coincident per a suprimir"
 
-#: ../yum/__init__.py:2990
+#: ../yum/__init__.py:3173 ../yum/__init__.py:3277 ../yum/__init__.py:3366
 #, python-format
 msgid "Cannot open file: %s. Skipping."
 msgstr "No es pot obrir el fitxer %s. S'ometrà."
 
-#: ../yum/__init__.py:2993
+#: ../yum/__init__.py:3176 ../yum/__init__.py:3280 ../yum/__init__.py:3369
 #, python-format
 msgid "Examining %s: %s"
 msgstr "S'està examinant %s: %s"
 
-#: ../yum/__init__.py:3001
+#: ../yum/__init__.py:3184 ../yum/__init__.py:3283 ../yum/__init__.py:3372
 #, python-format
 msgid "Cannot add package %s to transaction. Not a compatible architecture: %s"
-msgstr "No s'ha pogut afegir el paquet %s a la transacció. No és una arquitectura compatible: %s"
+msgstr ""
+"No s'ha pogut afegir el paquet %s a la transacció. No és una arquitectura "
+"compatible: %s"
 
-#: ../yum/__init__.py:3009
+#: ../yum/__init__.py:3192
 #, python-format
-msgid "Package %s not installed, cannot update it. Run yum install to install it instead."
-msgstr "El paquet %s no està instal·lat; no es pot actualitzar. Executeu «yum install» per a instal·lar-lo."
+msgid ""
+"Package %s not installed, cannot update it. Run yum install to install it "
+"instead."
+msgstr ""
+"El paquet %s no està instal·lat; no es pot actualitzar. Executeu «yum "
+"install» per a instal·lar-lo."
 
-#: ../yum/__init__.py:3044
+#: ../yum/__init__.py:3227 ../yum/__init__.py:3294 ../yum/__init__.py:3383
 #, python-format
 msgid "Excluding %s"
 msgstr "S'està excloent %s"
 
-#: ../yum/__init__.py:3049
+#: ../yum/__init__.py:3232
 #, python-format
 msgid "Marking %s to be installed"
 msgstr "S'està marcant %s per a ser instal·lat"
 
-#: ../yum/__init__.py:3055
+#: ../yum/__init__.py:3238
 #, python-format
 msgid "Marking %s as an update to %s"
 msgstr "S'està marcant %s com a actualització de %s"
 
-#: ../yum/__init__.py:3062
+#: ../yum/__init__.py:3245
 #, python-format
 msgid "%s: does not update installed package."
 msgstr "%s no actualitza el paquet instal·lat."
 
-#: ../yum/__init__.py:3077
+#: ../yum/__init__.py:3313
 msgid "Problem in reinstall: no package matched to remove"
-msgstr "Hi ha un problema en reinstal·lar: no hi ha cap paquet marcat per a esborrar"
+msgstr ""
+"Hi ha un problema en reinstal·lar: no hi ha cap paquet marcat per a suprimir"
 
-#: ../yum/__init__.py:3089
-#: ../yum/__init__.py:3160
+#: ../yum/__init__.py:3326 ../yum/__init__.py:3444
 #, python-format
 msgid "Package %s is allowed multiple installs, skipping"
 msgstr "El paquet %s permet múltiples instal·lacions, s'està ometent"
 
-#: ../yum/__init__.py:3098
-msgid "Problem in reinstall: no package matched to install"
-msgstr "Hi ha un problema en reinstal·lar: no hi ha cap paquet marcat per a instal·lar"
+#: ../yum/__init__.py:3347
+#, python-format
+msgid "Problem in reinstall: no package %s matched to install"
+msgstr ""
+"Hi ha un problema en reinstal·lar: no hi ha cap paquet %s marcat per a "
+"instal·lar"
 
-#: ../yum/__init__.py:3152
+#: ../yum/__init__.py:3436
 msgid "No package(s) available to downgrade"
 msgstr "No hi ha cap paquet disponible per a desactualitzar"
 
-#: ../yum/__init__.py:3183
+#: ../yum/__init__.py:3480
 #, python-format
 msgid "No Match for available package: %s"
 msgstr "No hi ha cap paquet disponible que coincideixi: %s"
 
-#: ../yum/__init__.py:3189
+#: ../yum/__init__.py:3486
 #, python-format
 msgid "Only Upgrade available on package: %s"
 msgstr "Només hi ha una actualització disponible per al paquet: %s"
 
-#: ../yum/__init__.py:3241
+#: ../yum/__init__.py:3545
 #, python-format
 msgid "Retrieving GPG key from %s"
 msgstr "S'està recuperant la clau GPG des de %s"
 
-#: ../yum/__init__.py:3261
+#: ../yum/__init__.py:3565
 msgid "GPG key retrieval failed: "
 msgstr "La recuperació de la clau GPG ha fallat: "
 
-#: ../yum/__init__.py:3272
+#: ../yum/__init__.py:3576
 #, python-format
 msgid "GPG key parsing failed: key does not have value %s"
 msgstr "L'ànalisi de la clau GPG ha fallat: la clau no té el valor %s"
 
-#: ../yum/__init__.py:3304
+#: ../yum/__init__.py:3608
 #, python-format
 msgid "GPG key at %s (0x%s) is already installed"
 msgstr "La clau GPG de %s (0x%s) ja està instal·lada"
 
 #. Try installing/updating GPG key
-#: ../yum/__init__.py:3309
-#: ../yum/__init__.py:3371
+#: ../yum/__init__.py:3613 ../yum/__init__.py:3675
 #, python-format
 msgid "Importing GPG key 0x%s \"%s\" from %s"
 msgstr "S'està important la clau GPG 0x%s \"%s\" des de %s"
 
-#: ../yum/__init__.py:3326
+#: ../yum/__init__.py:3630
 msgid "Not installing key"
 msgstr "No s'està instal·lant la clau"
 
-#: ../yum/__init__.py:3332
+#: ../yum/__init__.py:3636
 #, python-format
 msgid "Key import failed (code %d)"
 msgstr "La importació de la clau ha fallat (codi %d)"
 
-#: ../yum/__init__.py:3333
-#: ../yum/__init__.py:3392
+#: ../yum/__init__.py:3637 ../yum/__init__.py:3696
 msgid "Key imported successfully"
 msgstr "La clau s'ha importat amb èxit"
 
-#: ../yum/__init__.py:3338
-#: ../yum/__init__.py:3397
+#: ../yum/__init__.py:3642 ../yum/__init__.py:3701
 #, python-format
 msgid ""
-"The GPG keys listed for the \"%s\" repository are already installed but they are not correct for this package.\n"
+"The GPG keys listed for the \"%s\" repository are already installed but they "
+"are not correct for this package.\n"
 "Check that the correct key URLs are configured for this repository."
 msgstr ""
-"Les claus GPG llistades per al repositori \"%s\" ja estan instal·lades però no són correctes per a aquest paquet.\n"
-"Comproveu que les URL de claus correctes estan configurades per a aquest repositori."
+"Les claus GPG llistades per al repositori \"%s\" ja estan instal·lades però "
+"no són correctes per a aquest paquet.\n"
+"Comproveu que les URL de claus correctes estan configurades per a aquest "
+"repositori."
 
-#: ../yum/__init__.py:3347
+#: ../yum/__init__.py:3651
 msgid "Import of key(s) didn't help, wrong key(s)?"
 msgstr "La importació de claus no ha ajudat, eren claus incorrectes?"
 
-#: ../yum/__init__.py:3366
+#: ../yum/__init__.py:3670
 #, python-format
 msgid "GPG key at %s (0x%s) is already imported"
 msgstr "La clau GPG a %s (0x%s) ja ha estat importada"
 
-#: ../yum/__init__.py:3386
+#: ../yum/__init__.py:3690
 #, python-format
 msgid "Not installing key for repo %s"
 msgstr "No s'està instal·lant la clau per al repositori %s"
 
-#: ../yum/__init__.py:3391
+#: ../yum/__init__.py:3695
 msgid "Key import failed"
 msgstr "Ha fallat la importació de la clau"
 
-#: ../yum/__init__.py:3482
+#: ../yum/__init__.py:3816
 msgid "Unable to find a suitable mirror."
 msgstr "No s'ha pogut trobar un servidor rèplica vàlid."
 
-#: ../yum/__init__.py:3484
+#: ../yum/__init__.py:3818
 msgid "Errors were encountered while downloading packages."
-msgstr "S'han trobat errors descarregant paquets."
+msgstr "S'han trobat errors baixant paquets."
 
-#: ../yum/__init__.py:3525
+#: ../yum/__init__.py:3868
 #, python-format
 msgid "Please report this error at %s"
 msgstr "Siusplau, informeu d'aquest error al %s"
 
-#: ../yum/__init__.py:3549
+#: ../yum/__init__.py:3892
 msgid "Test Transaction Errors: "
 msgstr "Errors en la transacció de prova: "
 
 #. Mostly copied from YumOutput._outKeyValFill()
-#: ../yum/plugins.py:204
+#: ../yum/plugins.py:202
 msgid "Loaded plugins: "
 msgstr "Connectors carregats: "
 
-#: ../yum/plugins.py:218
-#: ../yum/plugins.py:224
+#: ../yum/plugins.py:216 ../yum/plugins.py:222
 #, python-format
 msgid "No plugin match for: %s"
 msgstr "No hi ha cap connector que coincideixi amb: %s"
 
-#: ../yum/plugins.py:254
+#: ../yum/plugins.py:252
 #, python-format
 msgid "Not loading \"%s\" plugin, as it is disabled"
 msgstr "No s'està carregant el connector \"%s\", ja que està deshabilitat"
 
 #. Give full backtrace:
-#: ../yum/plugins.py:266
+#: ../yum/plugins.py:264
 #, python-format
 msgid "Plugin \"%s\" can't be imported"
 msgstr "No s'ha pogut importar el connector \"%s\""
 
-#: ../yum/plugins.py:273
+#: ../yum/plugins.py:271
 #, python-format
 msgid "Plugin \"%s\" doesn't specify required API version"
 msgstr "El connector \"%s\" no especifica la versió de l'API requerida."
 
-#: ../yum/plugins.py:278
+#: ../yum/plugins.py:276
 #, python-format
 msgid "Plugin \"%s\" requires API %s. Supported API is %s."
 msgstr "El connector \"%s\" requereix l'API %s. L'API disponible és %s"
 
-#: ../yum/plugins.py:311
+#: ../yum/plugins.py:309
 #, python-format
 msgid "Loading \"%s\" plugin"
 msgstr "S'està carregant el connector \"%s\""
 
-#: ../yum/plugins.py:318
+#: ../yum/plugins.py:316
 #, python-format
-msgid "Two or more plugins with the name \"%s\" exist in the plugin search path"
-msgstr "Existeixen dos o més connectors amb el mateix nom \"%s\" en el camí de cerca de connectors"
+msgid ""
+"Two or more plugins with the name \"%s\" exist in the plugin search path"
+msgstr ""
+"Existeixen dos o més connectors amb el mateix nom \"%s\" en el camí de cerca "
+"de connectors"
 
-#: ../yum/plugins.py:338
+#: ../yum/plugins.py:336
 #, python-format
 msgid "Configuration file %s not found"
 msgstr "No s'ha trobat el fitxer de configuració %s"
 
 #. for
 #. Configuration files for the plugin not found
-#: ../yum/plugins.py:341
+#: ../yum/plugins.py:339
 #, python-format
 msgid "Unable to find configuration file for plugin %s"
 msgstr "No s'ha pogut trobar un fitxer de configuració per al connector %s"
 
-#: ../yum/plugins.py:495
+#: ../yum/plugins.py:497
 msgid "registration of commands not supported"
 msgstr "l'enregistrament d'ordres no està suportat"
 
@@ -2282,44 +2384,87 @@ msgstr "l'enregistrament d'ordres no està suportat"
 msgid "Repackaging"
 msgstr "Reempaquetant"
 
-#: ../rpmUtils/oldUtils.py:31
+#: ../rpmUtils/oldUtils.py:33
 #, python-format
 msgid "Header cannot be opened or does not match %s, %s."
 msgstr "La capçalera no es pot obrir o no coincideix amb %s, %s"
 
-#: ../rpmUtils/oldUtils.py:51
+#: ../rpmUtils/oldUtils.py:53
 #, python-format
 msgid "RPM %s fails md5 check"
 msgstr "Falla la comprobació md5 per al RPM %s"
 
-#: ../rpmUtils/oldUtils.py:149
+#: ../rpmUtils/oldUtils.py:151
 msgid "Could not open RPM database for reading. Perhaps it is already in use?"
-msgstr "No s'ha pogut obrir la base de dades RPM per a llegir-la. Potser ja està en ús?"
+msgstr ""
+"No s'ha pogut obrir la base de dades RPM per a llegir-la. Potser ja està en "
+"ús?"
 
-#: ../rpmUtils/oldUtils.py:181
+#: ../rpmUtils/oldUtils.py:183
 msgid "Got an empty Header, something has gone wrong"
 msgstr "S'ha obtingut una capçalera buida, alguna cosa ha anat malament"
 
-#: ../rpmUtils/oldUtils.py:251
-#: ../rpmUtils/oldUtils.py:258
-#: ../rpmUtils/oldUtils.py:261
-#: ../rpmUtils/oldUtils.py:264
+#: ../rpmUtils/oldUtils.py:253 ../rpmUtils/oldUtils.py:260
+#: ../rpmUtils/oldUtils.py:263 ../rpmUtils/oldUtils.py:266
 #, python-format
 msgid "Damaged Header %s"
 msgstr "Capçalera malmesa %s"
 
-#: ../rpmUtils/oldUtils.py:279
+#: ../rpmUtils/oldUtils.py:281
 #, python-format
 msgid "Error opening rpm %s - error %s"
-msgstr "S'ha produïut un error en obrir rpm %s - error %s"
+msgstr "S'ha produït un error en obrir l'rpm %s - error %s"
+
+#~ msgid "Matching packages for package list to user args"
+#~ msgstr ""
+#~ "S'està comparant els paquets per a la llista de paquets amb els arguments "
+#~ "de l'usuari"
+
+#~ msgid ""
+#~ "\n"
+#~ "Transaction Summary\n"
+#~ "%s\n"
+#~ "Install  %5.5s Package(s)         \n"
+#~ "Update   %5.5s Package(s)         \n"
+#~ "Remove   %5.5s Package(s)         \n"
+#~ msgstr ""
+#~ "\n"
+#~ "Resum de transaccions\n"
+#~ "%s\n"
+#~ "Instal·la  %5.5s paquets         \n"
+#~ "Actualitza %5.5s paquets         \n"
+#~ "Esborra    %5.5s paquets         \n"
+
+#~ msgid "excluding for cost: %s from %s"
+#~ msgstr "s'està excloent per cost: %s de %s"
+
+#~ msgid "Excluding Packages in global exclude list"
+#~ msgstr "S'estan excloent paquets en la llista global d'exclusió"
+
+#~ msgid "Excluding Packages from %s"
+#~ msgstr "S'estan excloent paquets de %s"
+
+#~ msgid "Reducing %s to included packages only"
+#~ msgstr "S'està reduint %s únicament a paquets inclosos."
+
+#~ msgid "Keeping included package %s"
+#~ msgstr "S'està mantenint el paquet inclòs %s"
+
+#~ msgid "Removing unmatched package %s"
+#~ msgstr "S'està esborrant el paquet sense coincidències %s"
+
+#~ msgid "Finished"
+#~ msgstr "Finalitzat"
 
 #~ msgid "Entering rpm code"
 #~ msgstr "S'està entrant en codi rpm"
+
 #~ msgid "Leaving rpm code"
 #~ msgstr "Deixant codi rpm"
+
 #~ msgid "Parsing package install arguments"
 #~ msgstr "S'estan analitzant els arguments del paquet a instal·lar"
+
 #~ msgid "Invalid versioned dependency string, try quoting it."
 #~ msgstr ""
 #~ "La cadena de versió de dependència és invàlida, proveu-ho entre cometes."
-
diff --git a/rpmUtils/arch.py b/rpmUtils/arch.py
index d22782b..edfc707 100644
--- a/rpmUtils/arch.py
+++ b/rpmUtils/arch.py
@@ -255,6 +255,7 @@ def getCanonPPCArch(arch):
 
 def getCanonSPARCArch(arch):
     # Deal with sun4v, sun4u, sun4m cases
+    SPARCtype = None
     f = open("/proc/cpuinfo", "r")
     lines = f.readlines()
     f.close()
@@ -262,6 +263,9 @@ def getCanonSPARCArch(arch):
         if line.startswith("type"):
             SPARCtype = line.split(':')[1]
             break
+    if SPARCtype is None:
+        return arch
+
     if SPARCtype.find("sun4v") != -1:
         if arch.startswith("sparc64"):
             return "sparc64v"
diff --git a/rpmUtils/updates.py b/rpmUtils/updates.py
index f2d43f8..3264956 100644
--- a/rpmUtils/updates.py
+++ b/rpmUtils/updates.py
@@ -24,7 +24,7 @@ class Updates:
     """
     This class computes and keeps track of updates and obsoletes.
     initialize, add installed packages, add available packages (both as
-    unique lists of name, epoch, ver, rel, arch tuples), add an optional dict
+    unique lists of name, arch, ver, rel, epoch tuples), add an optional dict
     of obsoleting packages with obsoletes and what they obsolete ie::
         foo, i386, 0, 1.1, 1: bar >= 1.1.
     """
diff --git a/test/skipbroken-tests.py b/test/skipbroken-tests.py
index db71a21..f8896f1 100644
--- a/test/skipbroken-tests.py
+++ b/test/skipbroken-tests.py
@@ -582,6 +582,24 @@ class SkipBrokenTests(DepsolveTests):
         self.assertEquals('empty', *self.resolveCode(skip=True))
         self.assertResult([c1,d1,r1,r2,r3,r4])
         
+    def testDualPackageUpdate(self):    
+        '''
+        RHBZ #522112
+        two version of the same package installed on the system
+        and update will update both, but if it fail some dep only
+        One of the updated packages will be removed from the
+        transaction.
+        '''
+        i1 = self.instPackage('xorg-x11-server-Xorg','1.6.99.900')
+        i2 = self.instPackage('xorg-x11-server-Xorg','1.6.3')
+        u1 = self.repoPackage('xorg-x11-server-Xorg', '1.6.99.901')
+        u1.addRequires("notfound")
+        self.tsInfo.addUpdate(u1, oldpo=i1)
+        self.tsInfo.addUpdate(u1, oldpo=i2)
+        self.assertEquals('empty', *self.resolveCode(skip=True))
+        self.assertResult([i1,i2])
+        
+    
     
     def resolveCode(self,skip = False):
         solver = YumBase()
diff --git a/utils.py b/utils.py
index 5456c68..945aa65 100644
--- a/utils.py
+++ b/utils.py
@@ -15,14 +15,29 @@
 
 import sys
 import time
+import exceptions
 
 import yum
 from cli import *
+from yum import Errors
 from yum import _
+from yum import logginglevels
 from optparse import OptionGroup
 
 import yum.plugins as plugins
 
+
+def suppress_keyboard_interrupt_message():
+    old_excepthook = sys.excepthook
+
+    def new_hook(type, value, traceback):
+        if type != exceptions.KeyboardInterrupt:
+            old_excepthook(type, value, traceback)
+        else:
+            pass
+
+    sys.excepthook = new_hook
+
 class YumUtilBase(YumBaseCli):
     def __init__(self,name,ver,usage):
         YumBaseCli.__init__(self)
@@ -32,7 +47,7 @@ class YumUtilBase(YumBaseCli):
         self._utilVer = ver
         self._option_group = OptionGroup(self._parser, "%s options" % self._utilName,"")
         self._parser.add_option_group(self._option_group)
-
+        suppress_keyboard_interrupt_message()
         
     def getOptionParser(self):
         return self._parser        
@@ -46,7 +61,7 @@ class YumUtilBase(YumBaseCli):
         while True:
             try:
                 self.doLock()
-            except yum.Errors.LockError, e:
+            except Errors.LockError, e:
                 if "%s" %(e.msg,) != lockerr:
                     lockerr = "%s" %(e.msg,)
                     self.logger.critical(lockerr)
@@ -83,7 +98,7 @@ class YumUtilBase(YumBaseCli):
                 pc.enabled_plugins = self._parser._splitArg(opts.enableplugins)
             self.conf
 
-        except yum.Errors.ConfigError, e:
+        except Errors.ConfigError, e:
             self.logger.critical(_('Config Error: %s'), e)
             sys.exit(1)
         except ValueError, e:
@@ -108,10 +123,63 @@ class YumUtilBase(YumBaseCli):
             self._getRpmDB()
             self._getRepos(doSetup = True)
             self._getSacks()
-        except yum.Errors.YumBaseError, msg:
+        except Errors.YumBaseError, msg:
             self.logger.critical(str(msg))
             sys.exit(1)
-            
+    
+    def doUtilTransaction(self):
+        def exUserCancel():
+            self.logger.critical(_('\n\nExiting on user cancel'))
+            if unlock(): return 200
+            return 1
+
+        def exIOError(e):
+            if e.errno == 32:
+                self.logger.critical(_('\n\nExiting on Broken Pipe'))
+            else:
+                self.logger.critical(_('\n\n%s') % str(e))
+            if unlock(): return 200
+            return 1
+
+        def exPluginExit(e):
+            '''Called when a plugin raises PluginYumExit.
+
+            Log the plugin's exit message if one was supplied.
+            ''' # ' xemacs hack
+            exitmsg = str(e)
+            if exitmsg:
+                self.logger.warn('\n\n%s', exitmsg)
+            if unlock(): return 200
+            return 1
+
+        def exFatal(e):
+            self.logger.critical('\n\n%s', to_unicode(e.value))
+            if unlock(): return 200
+            return 1
+
+        def unlock():
+            try:
+                self.closeRpmDB()
+                self.doUnlock()
+            except Errors.LockError, e:
+                return 200
+            return 0
+
+        try:
+            return_code = self.doTransaction()
+        except plugins.PluginYumExit, e:
+            return exPluginExit(e)
+        except Errors.YumBaseError, e:
+            return exFatal(e)
+        except KeyboardInterrupt:
+            return exUserCancel()
+        except IOError, e:
+            return exIOError(e)
+
+        self.verbose_logger.log(logginglevels.INFO_2, _('Complete!'))
+        if unlock(): return 200
+        return return_code
+        
 def main():
     name = 'testutil'
     ver  = '0.1'
diff --git a/yum/Errors.py b/yum/Errors.py
index 6f0ffe4..3a5aca9 100644
--- a/yum/Errors.py
+++ b/yum/Errors.py
@@ -101,6 +101,9 @@ class RepoMDError(YumBaseError):
 class PackageSackError(YumBaseError):
     pass
 
+class RpmDBError(YumBaseError):
+    pass
+
 class CompsException(YumBaseError):
     pass
 
diff --git a/yum/__init__.py b/yum/__init__.py
index 8211c70..c1e2c3b 100644
--- a/yum/__init__.py
+++ b/yum/__init__.py
@@ -57,6 +57,7 @@ import plugins
 import logginglevels
 import yumRepo
 import callbacks
+import yum.history
 
 import warnings
 warnings.simplefilter("ignore", Errors.YumFutureDeprecationWarning)
@@ -137,6 +138,7 @@ class YumBase(depsolve.Depsolve):
         self._rpmdb = None
         self._up = None
         self._comps = None
+        self._history = None
         self._pkgSack = None
         self._lockfile = None
         self.skipped_packages = []   # packages skip by the skip-broken code
@@ -153,6 +155,7 @@ class YumBase(depsolve.Depsolve):
         self.arch = ArchStorage()
         self.preconf = _YumPreBaseConf()
 
+        self.run_with_package_names = set()
 
     def __del__(self):
         self.close()
@@ -272,6 +275,10 @@ class YumBase(depsolve.Depsolve):
         # worthless. So we delete it, and thus. it'll raise AttributeError
         del self.preconf
 
+        # Packages used to run yum...
+        for pkgname in self.conf.history_record_packages:
+            self.run_with_package_names.add(pkgname)
+
         # run the postconfig plugin hook
         self.plugins.run('postconfig')
         self.yumvar = self.conf.yumvar
@@ -694,6 +701,13 @@ class YumBase(depsolve.Depsolve):
         self._comps.compile(self.rpmdb.simplePkgList())
         self.verbose_logger.debug('group time: %0.3f' % (time.time() - group_st))                
         return self._comps
+
+    def _getHistory(self):
+        """auto create the history object that to acess/append the transaction
+           history information. """
+        if self._history is None:
+            self._history = yum.history.YumHistory(root=self.conf.installroot)
+        return self._history
     
     # properties so they auto-create themselves with defaults
     repos = property(fget=lambda self: self._getRepos(),
@@ -718,6 +732,9 @@ class YumBase(depsolve.Depsolve):
     comps = property(fget=lambda self: self._getGroups(),
                      fset=lambda self, value: self._setGroups(value),
                      fdel=lambda self: setattr(self, "_comps", None))
+    history = property(fget=lambda self: self._getHistory(),
+                       fset=lambda self, value: setattr(self, "_history",value),
+                       fdel=lambda self: setattr(self, "_history", None))
     
     
     def doSackFilelistPopulate(self):
@@ -879,6 +896,7 @@ class YumBase(depsolve.Depsolve):
                 self.verbose_logger.debug('SKIPBROKEN: sanity check the current transaction' )
                 self.tsInfo.resetResolved(hard=True)
                 self._checkMissingObsoleted() # This is totally insane, but needed :(
+                self._checkUpdatedLeftovers() # Cleanup updated leftovers
                 rescode, restring = self.resolveDeps()
         if rescode != 1:
             self.verbose_logger.debug(_("Skip-broken took %i rounds "), count)
@@ -901,7 +919,7 @@ class YumBase(depsolve.Depsolve):
         then the TS_OBSOLETED can get removed from the transaction
         so we must make sure that they, exist and else create them
         """
-        for txmbr in self.tsInfo:
+        for txmbr in self.tsInfo.getMembersWithState(None, [TS_OBSOLETING,TS_OBSOLETED]):
             for pkg in txmbr.obsoletes:
                 if not self.tsInfo.exists(pkg.pkgtup):
                     obs = self.tsInfo.addObsoleted(pkg,txmbr.po)
@@ -914,6 +932,21 @@ class YumBase(depsolve.Depsolve):
                     self.verbose_logger.debug('SKIPBROKEN: Remove extra obsoleted %s (%s)' % (txmbr.po,pkg) )
                     self.tsInfo.remove(txmbr.po.pkgtup)
 
+    def _checkUpdatedLeftovers(self):
+        """ 
+        If multiple packages is updated the same package
+        and this package get removed because of an dep issue
+        then make sure that all the TS_UPDATED get removed.
+        """
+        for txmbr in self.tsInfo.getMembersWithState(None, [TS_UPDATED]):
+            for pkg in txmbr.updated_by:
+                # check if the updating txmbr is in the transaction
+                # else remove the updated txmbr
+                # it clean out some really wierd cases with dupes installed on the system
+                if not self.tsInfo.exists(pkg.pkgtup):
+                    self.verbose_logger.debug('SKIPBROKEN: Remove extra updated %s (%s)' % (txmbr.po,pkg) )
+                    self.tsInfo.remove(txmbr.po.pkgtup)
+
     def _getPackagesToRemoveAllArch(self,po):
         ''' get all compatible arch packages in pkgSack'''
         pkgs = []
@@ -1013,6 +1046,18 @@ class YumBase(depsolve.Depsolve):
 
         self.plugins.run('pretrans')
 
+        using_pkgs_pats = list(self.run_with_package_names)
+        using_pkgs = self.rpmdb.returnPackages(patterns=using_pkgs_pats)
+        rpmdbv  = self.rpmdb.simpleVersion(main_only=True)[0]
+        lastdbv = self.history.last()
+        if lastdbv is not None:
+            lastdbv = lastdbv.end_rpmdbversion
+        if lastdbv is not None and rpmdbv != lastdbv:
+            errstring = _('Warning: RPMDB has been altered since the last yum transaction.')
+            self.logger.warning(errstring)
+        if self.conf.history_record:
+            self.history.beg(rpmdbv, using_pkgs, list(self.tsInfo))
+
         errors = self.ts.run(cb.callback, '')
         # ts.run() exit codes are, hmm, "creative": None means all ok, empty 
         # list means some errors happened in the transaction and non-empty 
@@ -1028,6 +1073,8 @@ class YumBase(depsolve.Depsolve):
             self.verbose_logger.debug(errstring)
             resultobject.return_code = 1
         else:
+            if self.conf.history_record:
+                self.history.end(rpmdbv, 2, errors=errors)
             raise Errors.YumBaseError, errors
                           
         if not self.conf.keepcache:
@@ -1044,10 +1091,10 @@ class YumBase(depsolve.Depsolve):
         self.rpmdb.dropCachedData() # drop out the rpm cache so we don't step on bad hdr indexes
         self.plugins.run('posttrans')
         # sync up what just happened versus what is in the rpmdb
-        self.verifyTransaction()
+        self.verifyTransaction(resultobject)
         return resultobject
 
-    def verifyTransaction(self):
+    def verifyTransaction(self, resultobject=None):
         """checks that the transaction did what we expected it to do. Also 
            propagates our external yumdb info"""
         
@@ -1071,7 +1118,7 @@ class YumBase(depsolve.Depsolve):
                     self.logger.critical(_('%s was supposed to be installed' \
                                            ' but is not!' % txmbr.po))
                     continue
-                po = self.rpmdb.searchPkgTuple(txmbr.pkgtup)[0]
+                po = self.getInstalledPackageObject(txmbr.pkgtup)
                 rpo = txmbr.po
                 po.yumdb_info.from_repo = rpo.repoid
                 po.yumdb_info.reason = txmbr.reason
@@ -1115,6 +1162,11 @@ class YumBase(depsolve.Depsolve):
             else:
                 self.verbose_logger.log(logginglevels.DEBUG_2, 'What is this? %s' % txmbr.po)
 
+        if self.conf.history_record:
+            ret = -1
+            if resultobject is not None:
+                ret = resultobject.return_code
+            self.history.end(self.rpmdb.simpleVersion(main_only=True)[0], ret)
         self.rpmdb.dropCachedData()
 
     def costExcludePackages(self):
@@ -1259,7 +1311,10 @@ class YumBase(depsolve.Depsolve):
                 os.makedirs(lockdir, mode=0755)
             fd = os.open(filename, os.O_EXCL|os.O_CREAT|os.O_WRONLY, mode)    
         except OSError, msg:
-            if not msg.errno == errno.EEXIST: raise msg
+            if not msg.errno == errno.EEXIST: 
+                # Whoa. What the heck happened?
+                errmsg = _('Could not create lock at %s: %s ') % (filename, str(msg))
+                raise Errors.LockError(msg.errno, errmsg, contents)
             return 0
         else:
             os.write(fd, contents)
@@ -1783,7 +1838,7 @@ class YumBase(depsolve.Depsolve):
             for (pkgtup, instTup) in self.up.getObsoletesTuples():
                 (n,a,e,v,r) = pkgtup
                 pkgs = self.pkgSack.searchNevra(name=n, arch=a, ver=v, rel=r, epoch=e)
-                instpo = self.rpmdb.searchPkgTuple(instTup)[0] # the first one
+                instpo = self.getInstalledPackageObject(instTup)
                 for po in pkgs:
                     obsoletes.append(po)
                     obsoletesTuples.append((po, instpo))
@@ -2326,11 +2381,16 @@ class YumBase(depsolve.Depsolve):
         return result
 
     def getInstalledPackageObject(self, pkgtup):
-        """returns a YumInstallPackage object for the pkgtup specified"""
-        warnings.warn(_('getInstalledPackageObject() will go away, use self.rpmdb.searchPkgTuple().\n'),
-                Errors.YumFutureDeprecationWarning, stacklevel=2)
-        
-        po = self.rpmdb.searchPkgTuple(pkgtup)[0] # take the first one
+        """ Returns a YumInstallPackage object for the pkgtup specified, or
+            raises an exception. You should use this instead of
+            searchPkgTuple() if you are assuming there is a value. """
+
+        pkgs = self.rpmdb.searchPkgTuple(pkgtup)
+        if len(pkgs) == 0:
+            raise Errors.RpmDBError, _('Package tuple %s could not be found in rpmdb') % str(pkgtup)
+
+        # Dito. FIXME from getPackageObject() for len() > 1 ... :)
+        po = pkgs[0] # take the first one
         return po
         
     def gpgKeyCheck(self):
@@ -2594,7 +2654,7 @@ class YumBase(depsolve.Depsolve):
         if not isinstance(po, YumLocalPackage):
             for (obstup, inst_tup) in self.up.getObsoletersTuples(name=po.name):
                 if po.pkgtup == obstup:
-                    installed_pkg =  self.rpmdb.searchPkgTuple(inst_tup)[0]
+                    installed_pkg =  self.getInstalledPackageObject(inst_tup)
                     yield installed_pkg
         else:
             for (obs_n, obs_f, (obs_e, obs_v, obs_r)) in po.obsoletes:
@@ -2898,7 +2958,7 @@ class YumBase(depsolve.Depsolve):
                 topkg = self._test_loop(obsoleting_pkg, self._pkg2obspkg)
                 if topkg is not None:
                     obsoleting_pkg = topkg
-                installed_pkg =  self.rpmdb.searchPkgTuple(installed)[0]
+                installed_pkg =  self.getInstalledPackageObject(installed)
                 txmbr = self.tsInfo.addObsoleting(obsoleting_pkg, installed_pkg)
                 self.tsInfo.addObsoleted(installed_pkg, obsoleting_pkg)
                 if requiringPo:
@@ -3059,7 +3119,7 @@ class YumBase(depsolve.Depsolve):
                                             updated)
                 
                 else:
-                    updated_pkg =  self.rpmdb.searchPkgTuple(updated)[0]
+                    updated_pkg =  self.getInstalledPackageObject(updated)
                     txmbr = self.tsInfo.addUpdate(available_pkg, updated_pkg)
                     if requiringPo:
                         txmbr.setAsDep(requiringPo)
@@ -3426,6 +3486,7 @@ class YumBase(depsolve.Depsolve):
         if not apkgs:
             # Do we still want to return errors here?
             # We don't in the cases below, so I didn't here...
+            pkgs = []
             if 'pattern' in kwargs:
                 pkgs = self.rpmdb.returnPackages(patterns=[kwargs['pattern']],
                                                  ignore_case=False)
@@ -3534,6 +3595,84 @@ class YumBase(depsolve.Depsolve):
 
         return returndict
 
+    def history_redo(self, transaction):
+        """ Given a valid historical transaction object, try and repeat
+            that transaction. """
+        # NOTE: This is somewhat basic atm. ... see comment in undo.
+        old_conf_obs = self.conf.obsoletes
+        self.conf.obsoletes = False
+        done = False
+        for pkg in transaction.trans_data:
+            if pkg.state == 'Reinstall':
+                if self.reinstall(pkgtup=pkg.pkgtup):
+                    done = True
+        for pkg in transaction.trans_data:
+            if pkg.state == 'Downgrade':
+                try:
+                    if self.downgrade(pkgtup=pkg.pkgtup):
+                        done = True
+                except yum.Errors.DowngradeError:
+                    self.logger.critical(_('Failed to downgrade: %s'), pkg)
+        for pkg in transaction.trans_data:
+            if pkg.state == 'Update':
+                if self.update(pkgtup=pkg.pkgtup):
+                    done = True
+        for pkg in transaction.trans_data:
+            if pkg.state in ('Install', 'True-Install', 'Obsoleting'):
+                if self.install(pkgtup=pkg.pkgtup):
+                    done = True
+        for pkg in transaction.trans_data:
+            if pkg.state == 'Erase':
+                if self.remove(pkgtup=pkg.pkgtup):
+                    done = True
+        self.conf.obsoletes = old_conf_obs
+        return done
+
+    def history_undo(self, transaction):
+        """ Given a valid historical transaction object, try and undo
+            that transaction. """
+        # NOTE: This is somewhat basic atm. ... for instance we don't check
+        #       that we are going from the old new version. However it's still
+        #       better than the RHN rollback code, and people pay for that :).
+        #  We turn obsoletes off because we want the specific versions of stuff
+        # from history ... even if they've been obsoleted since then.
+        old_conf_obs = self.conf.obsoletes
+        self.conf.obsoletes = False
+        done = False
+        for pkg in transaction.trans_data:
+            if pkg.state == 'Reinstall':
+                if self.reinstall(pkgtup=pkg.pkgtup):
+                    done = True
+        for pkg in transaction.trans_data:
+            if pkg.state == 'Updated':
+                try:
+                    if self.downgrade(pkgtup=pkg.pkgtup):
+                        done = True
+                except yum.Errors.DowngradeError:
+                    self.logger.critical(_('Failed to downgrade: %s'), pkg)
+        for pkg in transaction.trans_data:
+            if pkg.state == 'Downgraded':
+                if self.update(pkgtup=pkg.pkgtup):
+                    done = True
+        for pkg in transaction.trans_data:
+            if pkg.state == 'Obsoleting':
+                if self.remove(pkgtup=pkg.pkgtup):
+                    done = True
+        for pkg in transaction.trans_data:
+            if pkg.state in ('Install', 'True-Install'):
+                if self.remove(pkgtup=pkg.pkgtup):
+                    done = True
+        for pkg in transaction.trans_data:
+            if pkg.state == 'Obsoleted':
+                if self.install(pkgtup=pkg.pkgtup):
+                    done = True
+        for pkg in transaction.trans_data:
+            if pkg.state == 'Erase':
+                if self.install(pkgtup=pkg.pkgtup):
+                    done = True
+        self.conf.obsoletes = old_conf_obs
+        return done
+
     def _retrievePublicKey(self, keyurl, repo=None):
         """
         Retrieve a key file
diff --git a/yum/config.py b/yum/config.py
index 2f057c3..0d7bc38 100644
--- a/yum/config.py
+++ b/yum/config.py
@@ -703,6 +703,8 @@ class YumConf(StartupConf):
     sslclientcert = Option()
     sslclientkey = Option()
 
+    history_record = BoolOption(True)
+    history_record_packages = ListOption(['yum', 'rpm', 'yum-metadata-parser'])
 
     _reposlist = []
 
@@ -893,7 +895,13 @@ def _getsysver(installroot, distroverpkg):
         idx = ts.dbMatch('provides', distroverpkg)
     except TypeError, e:
         # This is code for "cannot open rpmdb"
-        raise Errors.YumBaseError("Error: " + e.message)
+        # this is for pep 352 compliance on python 2.6 and above :(
+        if sys.hexversion < 0x02050000:
+            if hasattr(e,'message'):
+                raise Errors.YumBaseError("Error: " + str(e.message))
+            else:
+                raise Errors.YumBaseError("Error: " + str(e))
+        raise Errors.YumBaseError("Error: " + str(e))
     # we're going to take the first one - if there is more than one of these
     # then the user needs a beating
     if idx.count() == 0:
diff --git a/yum/depsolve.py b/yum/depsolve.py
index d6b1b02..467f657 100644
--- a/yum/depsolve.py
+++ b/yum/depsolve.py
@@ -1083,7 +1083,16 @@ class Depsolve(object):
                 # could play a part ... this probably needs a better fix.
                 newest = sorted(rpmdbpkgs)[-1]
                 if newest.verLT(pkg):
-                    ipkgresults[pkg] = 0
+                    # give pkgs which are updates just a SLIGHT edge
+                    # we should also make sure that any pkg
+                    # we are giving an edge to is not obsoleted by
+                    # something else in the transaction. :(
+                    # there are many ways I hate this - this is but one
+                    ipkgresults[pkg] = 5
+            else:
+                # just b/c they're not installed pkgs doesn't mean they should
+                # be ignored entirely. Just not preferred
+                ipkgresults[pkg] = 0
 
         #  This is probably only for "renames". What happens is that pkgA-1 gets
         # obsoleted by pkgB but pkgB requires pkgA-2, now _if_ the pkgA txmbr
diff --git a/yum/history.py b/yum/history.py
new file mode 100644
index 0000000..9741d36
--- /dev/null
+++ b/yum/history.py
@@ -0,0 +1,622 @@
+#!/usr/bin/python -t
+# 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 Library General Public License for more details.
+#
+# You should have received a copy of the GNU General Public License
+# along with this program; if not, write to the Free Software
+# Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+#
+# Copyright 2009 Red Hat
+#
+# James Antill <james@fedoraproject.org>
+
+import time
+import os, os.path
+import glob
+from weakref import proxy as weakref
+
+from sqlutils import sqlite, executeSQL
+import yum.misc
+import yum.constants
+from yum.constants import *
+from yum.packages import YumInstalledPackage, YumAvailablePackage, PackageObject
+
+_history_dir = '/var/lib/yum/history'
+
+_stcode2sttxt = {TS_UPDATE : 'Update',
+                 TS_UPDATED : 'Updated', 
+                 TS_ERASE: 'Erase',
+                 TS_INSTALL: 'Install', 
+                 TS_TRUEINSTALL : 'True-Install',
+                 TS_OBSOLETED: 'Obsoleted',
+                 TS_OBSOLETING: 'Obsoleting'}
+
+_sttxt2stcode = {'Update' : TS_UPDATE,
+                 'Updated' : TS_UPDATED, 
+                 'Erase' : TS_ERASE,
+                 'Install' : TS_INSTALL, 
+                 'True-Install' : TS_TRUEINSTALL,
+                 'Reinstall' : TS_INSTALL, # Broken
+                 'Downgrade' : TS_INSTALL, # Broken
+                 'Downgraded' : TS_INSTALL, # Broken
+                 'Obsoleted' : TS_OBSOLETED,
+                 'Obsoleting' : TS_OBSOLETING}
+
+# ---- horrible Copy and paste from sqlitesack ----
+def _sql_esc(pattern):
+    """ Apply SQLite escaping, if needed. Returns pattern and esc. """
+    esc = ''
+    if "_" in pattern or "%" in pattern:
+        esc = ' ESCAPE "!"'
+        pattern = pattern.replace("!", "!!")
+        pattern = pattern.replace("%", "!%")
+        pattern = pattern.replace("_", "!_")
+    return (pattern, esc)
+
+def _sql_esc_glob(patterns):
+    """ Converts patterns to SQL LIKE format, if required (or gives up if
+        not possible). """
+    ret = []
+    for pattern in patterns:
+        if '[' in pattern: # LIKE only has % and _, so [abc] can't be done.
+            return []      # So Load everything
+
+        # Convert to SQL LIKE format
+        (pattern, esc) = _sql_esc(pattern)
+        pattern = pattern.replace("*", "%")
+        pattern = pattern.replace("?", "_")
+        ret.append((pattern, esc))
+    return ret
+
+def _setupHistorySearchSQL(patterns=None, ignore_case=False):
+    """Setup need_full and patterns for _yieldSQLDataList, also see if
+       we can get away with just using searchNames(). """
+
+    if patterns is None:
+        patterns = []
+
+    fields = ['name', 'sql_nameArch', 'sql_nameVerRelArch',
+              'sql_nameVer', 'sql_nameVerRel',
+              'sql_envra', 'sql_nevra']
+    need_full = False
+    for pat in patterns:
+        if yum.misc.re_full_search_needed(pat):
+            need_full = True
+            break
+
+    pat_max = PATTERNS_MAX
+    if not need_full:
+        fields = ['name']
+        pat_max = PATTERNS_INDEXED_MAX
+    if len(patterns) > pat_max:
+        patterns = []
+    if ignore_case:
+        patterns = _sql_esc_glob(patterns)
+    else:
+        tmp = []
+        need_glob = False
+        for pat in patterns:
+            if misc.re_glob(pat):
+                tmp.append((pat, 'glob'))
+                need_glob = True
+            else:
+                tmp.append((pat, '='))
+        if not need_full and not need_glob and patterns:
+            return (need_full, patterns, fields, True)
+        patterns = tmp
+    return (need_full, patterns, fields, False)
+# ---- horrible Copy and paste from sqlitesack ----
+
+class YumHistoryPackage(PackageObject):
+
+    def __init__(self, name, arch, epoch, version, release, checksum):
+        self.name    = name
+        self.version = version
+        self.release = release
+        self.epoch   = epoch
+        self.arch    = arch
+        self.pkgtup = (self.name, self.arch,
+                       self.epoch, self.version, self.release)
+        if checksum is None:
+            self._checksums = [] # (type, checksum, id(0,1)
+        else:
+            chk = checksum.split(':')
+            self._checksums = [(chk[0], chk[1], 0)] # (type, checksum, id(0,1))
+
+class YumHistoryTransaction:
+    """ Holder for a history transaction. """
+
+    def __init__(self, history, row):
+        self._history = weakref(history)
+
+        self.tid              = row[0]
+        self.beg_timestamp    = row[1]
+        self.beg_rpmdbversion = row[2]
+        self.end_timestamp    = row[3]
+        self.end_rpmdbversion = row[4]
+        self.loginuid         = row[5]
+        self.return_code      = row[6]
+
+        self._loaded_TW = None
+        self._loaded_TD = None
+
+        self.altered_lt_rpmdb = None
+        self.altered_gt_rpmdb = None
+
+    def __cmp__(self, other):
+        if other is None:
+            return 1
+        ret = cmp(self.beg_timestamp, other.beg_timestamp)
+        if ret: return -ret
+        ret = cmp(self.end_timestamp, other.end_timestamp)
+        if ret: return ret
+        ret = cmp(self.tid, other.tid)
+        return -ret
+
+    def _getTransWith(self):
+        if self._loaded_TW is None:
+            self._loaded_TW = sorted(self._history._old_with_pkgs(self.tid))
+        return self._loaded_TW
+    def _getTransData(self):
+        if self._loaded_TD is None:
+            self._loaded_TD = sorted(self._history._old_data_pkgs(self.tid))
+        return self._loaded_TD
+
+    trans_with = property(fget=lambda self: self._getTransWith())
+    trans_data = property(fget=lambda self: self._getTransData())
+
+class YumHistory:
+    """ API for accessing the history sqlite data. """
+
+    def __init__(self, root='/', db_path=_history_dir):
+        self._conn = None
+        
+        self.conf = yum.misc.GenericHolder()
+        self.conf.db_path  = os.path.normpath(root + '/' + db_path)
+        self.conf.writable = False
+
+        if not os.path.exists(self.conf.db_path):
+            try:
+                os.makedirs(self.conf.db_path)
+            except (IOError, OSError), e:
+                # some sort of useful thing here? A warning?
+                return
+            self.conf.writable = True
+        else:
+            if os.access(self.conf.db_path, os.W_OK):
+                self.conf.writable = True
+
+        DBs = glob.glob('%s/history-*-*-*.sqlite' % self.conf.db_path)
+        self._db_file = None
+        for d in reversed(sorted(DBs)):
+            fname = os.path.basename(d)
+            fname = fname[len("history-"):-len(".sqlite")]
+            pieces = fname.split('-', 4)
+            if len(pieces) != 3:
+                continue
+            try:
+                map(int, pieces)
+            except ValueError:
+                continue
+
+            self._db_file = d
+            break
+
+        if self._db_file is None:
+            self._create_db_file()
+
+    def _get_cursor(self):
+        if self._conn is None:
+            self._conn = sqlite.connect(self._db_file)
+        return self._conn.cursor()
+    def _commit(self):
+        return self._conn.commit()
+
+    def _pkgtup2pid(self, pkgtup, checksum=None):
+        cur = self._get_cursor()
+        executeSQL(cur, """SELECT pkgtupid, checksum FROM pkgtups
+                           WHERE name=? AND arch=? AND
+                                 epoch=? AND version=? AND release=?""", pkgtup)
+        for sql_pkgtupid, sql_checksum in cur:
+            if checksum is None and sql_checksum is None:
+                return sql_pkgtupid
+            if checksum is None:
+                continue
+            if sql_checksum is None:
+                continue
+            if checksum == sql_checksum:
+                return sql_pkgtupid
+        
+        if checksum is not None:
+            (n,a,e,v,r) = pkgtup
+            res = executeSQL(cur,
+                             """INSERT INTO pkgtups
+                                (name, arch, epoch, version, release, checksum)
+                                VALUES (?, ?, ?, ?, ?, ?)""", (n,a,e,v,r,
+                                                               checksum))
+        else:
+            res = executeSQL(cur,
+                             """INSERT INTO pkgtups
+                                (name, arch, epoch, version, release)
+                                VALUES (?, ?, ?, ?, ?)""", pkgtup)
+        return cur.lastrowid
+    def _apkg2pid(self, po):
+        csum = po.returnIdSum()
+        if csum is not None:
+            csum = "%s:%s" % (str(csum[0]), str(csum[1]))
+        return self._pkgtup2pid(po.pkgtup, csum)
+    def _ipkg2pid(self, po):
+        csum = None
+        yumdb = po.yumdb_info
+        if 'checksum_type' in yumdb and 'checksum_type' in yumdb:
+            csum = "%s:%s" % (yumdb.checksum_type, yumdb.checksum_data)
+        return self._pkgtup2pid(po.pkgtup, csum)
+    def pkg2pid(self, po):
+        if isinstance(po, YumInstalledPackage):
+            return self._ipkg2pid(po)
+        if isinstance(po, YumAvailablePackage):
+            return self._apkg2pid(po)
+        return self._pkgtup2pid(po.pkgtup, None)
+
+    @staticmethod
+    def txmbr2state(txmbr):
+        state = None
+        if txmbr.output_state in (TS_INSTALL, TS_TRUEINSTALL):
+            if hasattr(txmbr, 'reinstall'):
+                state = 'Reinstall'
+            elif txmbr.downgrades:
+                state = 'Downgrade'
+        if txmbr.output_state == TS_ERASE:
+            if txmbr.downgraded_by:
+                state = 'Downgraded'
+        if state is None:
+            state = _stcode2sttxt[txmbr.output_state]
+        return state
+
+    def trans_with_pid(self, pid):
+        cur = self._get_cursor()
+        res = executeSQL(cur,
+                         """INSERT INTO trans_with_pkgs
+                         (tid, pkgtupid)
+                         VALUES (?, ?)""", (self._tid, pid))
+        return cur.lastrowid
+
+    def trans_data_pid_beg(self, pid, state):
+        if not hasattr(self, '_tid'):
+            return # Not configured to run
+        cur = self._get_cursor()
+        res = executeSQL(cur,
+                         """INSERT INTO trans_data_pkgs
+                         (tid, pkgtupid, state)
+                         VALUES (?, ?, ?)""", (self._tid, pid, state))
+        return cur.lastrowid
+    def trans_data_pid_end(self, pid, state):
+        if not hasattr(self, '_tid'):
+            return # Not configured to run
+
+        cur = self._get_cursor()
+        res = executeSQL(cur,
+                         """UPDATE trans_data_pkgs SET done = ?
+                         WHERE tid = ? AND pkgtupid = ? AND state = ?
+                         """, ('TRUE', self._tid, pid, state))
+        self._commit()
+        return cur.lastrowid
+
+    def beg(self, rpmdb_version, using_pkgs, txmbrs):
+        cur = self._get_cursor()
+        res = executeSQL(cur,
+                         """INSERT INTO trans_beg
+                            (timestamp, rpmdb_version, loginuid)
+                            VALUES (?, ?, ?)""", (int(time.time()),
+                                                    str(rpmdb_version),
+                                                    yum.misc.getloginuid()))
+        self._tid = cur.lastrowid
+
+        for pkg in using_pkgs:
+            pid = self._ipkg2pid(pkg)
+            self.trans_with_pid(pid)
+        
+        for txmbr in txmbrs:
+            pid   = self.pkg2pid(txmbr.po)
+            state = self.txmbr2state(txmbr)
+            self.trans_data_pid_beg(pid, state)
+        
+        self._commit()
+
+    def _log_errors(self, errors):
+        cur = self._get_cursor()
+        for error in errors:
+            executeSQL(cur,
+                       """INSERT INTO trans_error
+                          (tid, msg) VALUES (?, ?)""", (self._tid, error))
+        self._commit()
+
+    def log_scriptlet_output(self, data, msg):
+        """ Note that data can be either a real pkg. ... or not. """
+        if msg is None or not hasattr(self, '_tid'):
+            return # Not configured to run
+
+        cur = self._get_cursor()
+        for error in msg.split('\n'):
+            executeSQL(cur,
+                       """INSERT INTO trans_script_stdout
+                          (tid, line) VALUES (?, ?)""", (self._tid, error))
+        self._commit()
+
+    def end(self, rpmdb_version, return_code, errors=None):
+        assert return_code or not errors
+        cur = self._get_cursor()
+        res = executeSQL(cur,
+                         """INSERT INTO trans_end
+                            (tid, timestamp, rpmdb_version, return_code)
+                            VALUES (?, ?, ?, ?)""", (self._tid,int(time.time()),
+                                                     str(rpmdb_version),
+                                                     return_code))
+        self._commit()
+        if not return_code:
+            #  Simple hack, if the transaction finished. Note that this
+            # catches the erase cases (as we still don't get pkgtups for them),
+            # Eg. Updated elements.
+            executeSQL(cur,
+                       """UPDATE trans_data_pkgs SET done = ?
+                          WHERE tid = ?""", ('TRUE', self._tid,))
+            self._commit()
+        if errors is not None:
+            self._log_errors(errors)
+        del self._tid
+
+    def _old_with_pkgs(self, tid):
+        cur = self._get_cursor()
+        executeSQL(cur,
+                   """SELECT name, arch, epoch, version, release, checksum
+                      FROM trans_with_pkgs JOIN pkgtups USING(pkgtupid)
+                      WHERE tid = ?
+                      ORDER BY name ASC, epoch ASC""", (tid,))
+        ret = []
+        for row in cur:
+            obj = YumHistoryPackage(row[0],row[1],row[2],row[3],row[4], row[5])
+            ret.append(obj)
+        return ret
+    def _old_data_pkgs(self, tid):
+        cur = self._get_cursor()
+        executeSQL(cur,
+                   """SELECT name, arch, epoch, version, release,
+                             checksum, done, state
+                      FROM trans_data_pkgs JOIN pkgtups USING(pkgtupid)
+                      WHERE tid = ?
+                      ORDER BY name ASC, epoch ASC, state DESC""", (tid,))
+        ret = []
+        for row in cur:
+            obj = YumHistoryPackage(row[0],row[1],row[2],row[3],row[4], row[5])
+            obj.done     = row[6] == 'TRUE'
+            obj.state    = row[7]
+            obj.state_installed = None
+            if _sttxt2stcode[obj.state] in TS_INSTALL_STATES:
+                obj.state_installed = True
+            if _sttxt2stcode[obj.state] in TS_REMOVE_STATES:
+                obj.state_installed = False
+            ret.append(obj)
+        return ret
+
+    def old(self, tids=[], limit=None, complete_transactions_only=False):
+        """ Return a list of the last transactions, note that this includes
+            partial transactions (ones without an end transaction). """
+        cur = self._get_cursor()
+        sql =  """SELECT tid,
+                         trans_beg.timestamp AS beg_ts,
+                         trans_beg.rpmdb_version AS beg_rv,
+                         trans_end.timestamp AS end_ts,
+                         trans_end.rpmdb_version AS end_rv,
+                         loginuid, return_code
+                  FROM trans_beg JOIN trans_end USING(tid)"""
+        # NOTE: sqlite doesn't do OUTER JOINs ... *sigh*. So we have to do it
+        #       ourself.
+        if not complete_transactions_only:
+            sql =  """SELECT tid,
+                             trans_beg.timestamp AS beg_ts,
+                             trans_beg.rpmdb_version AS beg_rv,
+                             NULL, NULL,
+                             loginuid, NULL
+                      FROM trans_beg"""
+        params = None
+        if tids and len(tids) <= yum.constants.PATTERNS_INDEXED_MAX:
+            params = tids = list(set(tids))
+            sql += " WHERE tid IN (%s)" % ", ".join(['?'] * len(tids))
+        sql += " ORDER BY beg_ts DESC, tid ASC"
+        if limit is not None:
+            sql += " LIMIT " + str(limit)
+        executeSQL(cur, sql, params)
+        ret = []
+        tid2obj = {}
+        for row in cur:
+            if tids and len(tids) > yum.constants.PATTERNS_INDEXED_MAX:
+                if row[0] not in tids:
+                    continue
+            obj = YumHistoryTransaction(self, row)
+            tid2obj[row[0]] = obj
+            ret.append(obj)
+
+        sql =  """SELECT tid,
+                         trans_end.timestamp AS end_ts,
+                         trans_end.rpmdb_version AS end_rv,
+                         return_code
+                  FROM trans_end"""
+        params = tid2obj.keys()
+        if len(params) > yum.constants.PATTERNS_INDEXED_MAX:
+            executeSQL(cur, sql)
+        else:
+            sql += " WHERE tid IN (%s)" % ", ".join(['?'] * len(params))
+            executeSQL(cur, sql, params)
+        for row in cur:
+            if row[0] not in tid2obj:
+                continue
+            tid2obj[row[0]].end_timestamp    = row[1]
+            tid2obj[row[0]].end_rpmdbversion = row[2]
+            tid2obj[row[0]].return_code      = row[3]
+
+        # Go through backwards, and see if the rpmdb versions match
+        las = None
+        for obj in reversed(ret):
+            cur_rv = obj.beg_rpmdbversion
+            las_rv = None
+            if las is not None:
+                las_rv = las.end_rpmdbversion
+            if las_rv is None or cur_rv is None or (las.tid + 1) != obj.tid:
+                pass
+            elif las_rv != cur_rv:
+                obj.altered_lt_rpmdb = True
+                las.altered_gt_rpmdb = True
+            else:
+                obj.altered_lt_rpmdb = False
+                las.altered_gt_rpmdb = False
+            las = obj
+
+        return ret
+
+    def last(self):
+        """ This is the last full transaction. So any imcomplete transactions
+            do not count. """
+        cur = self._get_cursor()
+        sql =  """SELECT tid,
+                         trans_beg.timestamp AS beg_ts,
+                         trans_beg.rpmdb_version AS beg_rv,
+                         trans_end.timestamp AS end_ts,
+                         trans_end.rpmdb_version AS end_rv,
+                         loginuid, return_code
+                  FROM trans_beg JOIN trans_end USING(tid)
+                  ORDER BY beg_ts DESC, tid ASC
+                  LIMIT 1"""
+        executeSQL(cur, sql)
+        for row in cur:
+            return YumHistoryTransaction(self, row)
+        return None
+
+    def _yieldSQLDataList(self, patterns, fields, ignore_case):
+        """Yields all the package data for the given params. """
+
+        cur = self._get_cursor()
+        qsql = _FULL_PARSE_QUERY_BEG
+
+        pat_sqls = []
+        pat_data = []
+        for (pattern, rest) in patterns:
+            for field in fields:
+                if ignore_case:
+                    pat_sqls.append("%s LIKE ?%s" % (field, rest))
+                else:
+                    pat_sqls.append("%s %s ?" % (field, rest))
+                pat_data.append(pattern)
+        assert pat_sqls
+
+        qsql += " OR ".join(pat_sqls)
+        executeSQL(cur, qsql, pat_data)
+        for x in cur:
+            yield x
+
+    def search(self, patterns, ignore_case=True):
+        """ Search for history transactions which contain specified
+            packages al. la. "yum list". Returns transaction ids. """
+        # Search packages ... kind of sucks that it's search not list, pkglist?
+
+        data = _setupHistorySearchSQL(patterns, ignore_case)
+        (need_full, patterns, fields, names) = data
+
+        ret = []
+        pkgtupids = set()
+        for row in self._yieldSQLDataList(patterns, fields, ignore_case):
+            pkgtupids.add(row[0])
+
+        cur = self._get_cursor()
+        sql =  """SELECT tid FROM trans_data_pkgs WHERE pkgtupid IN """
+        sql += "(%s)" % ",".join(['?'] * len(pkgtupids))
+        params = list(pkgtupids)
+        tids = set()
+        if len(params) > yum.constants.PATTERNS_INDEXED_MAX:
+            executeSQL(cur, """SELECT tid FROM trans_data_pkgs""")
+            for row in cur:
+                if row[0] in params:
+                    tids.add(row[0])
+            return tids
+        if not params:
+            return tids
+        executeSQL(cur, sql, params)
+        for row in cur:
+            tids.add(row[0])
+        return tids
+
+    def _create_db_file(self):
+        """ Create a new history DB file, populating tables etc. """
+
+        _db_file = '%s/%s-%s.%s' % (self.conf.db_path,
+                                    'history',
+                                    time.strftime('%Y-%m-%d'),
+                                    'sqlite')
+        if self._db_file == _db_file:
+            os.rename(_db_file, _db_file + '.old')
+        self._db_file = _db_file
+                
+        cur = self._get_cursor()
+        ops = ['''\
+ CREATE TABLE trans_beg (
+     tid INTEGER PRIMARY KEY,
+     timestamp INTEGER NOT NULL, rpmdb_version TEXT NOT NULL,
+     loginuid INTEGER);
+''', '''\
+ CREATE TABLE trans_end (
+     tid INTEGER PRIMARY KEY REFERENCES trans_beg,
+     timestamp INTEGER NOT NULL, rpmdb_version TEXT NOT NULL,
+     return_code INTEGER NOT NULL);
+''', '''\
+\
+ CREATE TABLE trans_with_pkgs (
+     tid INTEGER NOT NULL REFERENCES trans_beg,
+     pkgtupid INTEGER NOT NULL REFERENCES pkgtups);
+''', '''\
+\
+ CREATE TABLE trans_error (
+     mid INTEGER PRIMARY KEY,
+     tid INTEGER NOT NULL REFERENCES trans_beg,
+     msg TEXT NOT NULL);
+''', '''\
+ CREATE TABLE trans_script_stdout (
+     lid INTEGER PRIMARY KEY,
+     tid INTEGER NOT NULL REFERENCES trans_beg,
+     line TEXT NOT NULL);
+''', '''\
+\
+ CREATE TABLE trans_data_pkgs (
+     tid INTEGER NOT NULL REFERENCES trans_beg,
+     pkgtupid INTEGER NOT NULL REFERENCES pkgtups,
+     done BOOL NOT NULL DEFAULT FALSE, state TEXT NOT NULL);
+''', '''\
+\
+ CREATE TABLE pkgtups (
+     pkgtupid INTEGER PRIMARY KEY,     name TEXT NOT NULL, arch TEXT NOT NULL,
+     epoch TEXT NOT NULL, version TEXT NOT NULL, release TEXT NOT NULL,
+     checksum TEXT);
+''', '''\
+ CREATE INDEX i_pkgtup_naevr ON pkgtups (name, arch, epoch, version, release);
+''']
+        for op in ops:
+            cur.execute(op)
+        self._commit()
+
+# Pasted from sqlitesack
+_FULL_PARSE_QUERY_BEG = """
+SELECT pkgtupid,name,epoch,version,release,arch,
+  name || "." || arch AS sql_nameArch,
+  name || "-" || version || "-" || release || "." || arch AS sql_nameVerRelArch,
+  name || "-" || version AS sql_nameVer,
+  name || "-" || version || "-" || release AS sql_nameVerRel,
+  epoch || ":" || name || "-" || version || "-" || release || "." || arch AS sql_envra,
+  name || "-" || epoch || ":" || version || "-" || release || "." || arch AS sql_nevra
+  FROM pkgtups
+  WHERE 
+"""
diff --git a/yum/misc.py b/yum/misc.py
index a8f7954..a092b65 100644
--- a/yum/misc.py
+++ b/yum/misc.py
@@ -797,6 +797,21 @@ def unlink_f(filename):
         if e.errno != errno.ENOENT:
             raise
 
+def getloginuid():
+    """ Get the audit-uid/login-uid, if available. None is returned if there
+        was a problem. Note that no caching is done here. """
+    #  We might normally call audit.audit_getloginuid(), except that requires
+    # importing all of the audit module. And it doesn't work anyway: BZ 518721
+    try:
+        fo = open("/proc/self/loginuid")
+    except IOError:
+        return None
+    data = fo.read()
+    try:
+        return int(data)
+    except ValueError:
+        return None
+
 # ---------- i18n ----------
 import locale
 import sys
diff --git a/yum/packageSack.py b/yum/packageSack.py
index 3716410..cc26d03 100644
--- a/yum/packageSack.py
+++ b/yum/packageSack.py
@@ -35,6 +35,8 @@ class PackageSackVersion:
 
     def __eq__(self, other):
         if other is None: return False
+        if type(other) in (type(''), type(u'')):
+            return str(self) == other
         if self._num != other._num: return False
         if self._chksum.digest() != other._chksum.digest(): return False
         return True
diff --git a/yum/plugins.py b/yum/plugins.py
index 27b1aa5..02f0d57 100644
--- a/yum/plugins.py
+++ b/yum/plugins.py
@@ -457,6 +457,10 @@ class PluginConduit:
         '''
         return config.getOption(self._conf, section, opt, config.BoolOption(default))
 
+    def registerPackageName(self, name):
+        self._base.run_with_package_names.add(name)
+
+
 class ConfigPluginConduit(PluginConduit):
 
     def registerOpt(self, name, valuetype, where, default):
diff --git a/yum/rpmsack.py b/yum/rpmsack.py
index fbeb9b3..8368d52 100644
--- a/yum/rpmsack.py
+++ b/yum/rpmsack.py
@@ -339,7 +339,7 @@ class RPMDBPackageSack(PackageSackBase):
             pkgobjlist = pkgobjlist[0] + pkgobjlist[1]
         return pkgobjlist
 
-    def simpleVersion(self):
+    def simpleVersion(self, main_only=False):
         """ Return a simple version for all installed packages. """
         main = PackageSackVersion()
         irepos = {}
@@ -350,6 +350,9 @@ class RPMDBPackageSack(PackageSackBase):
                 csum = (ydbi.checksum_type, ydbi.checksum_data)
             main.update(pkg, csum)
 
+            if main_only:
+                continue
+
             repoid = 'installed'
             rev = None
             if 'from_repo' in pkg.yumdb_info:
diff --git a/yum/rpmtrans.py b/yum/rpmtrans.py
index 77b06a2..b1b896f 100644
--- a/yum/rpmtrans.py
+++ b/yum/rpmtrans.py
@@ -230,6 +230,11 @@ class RPMTransaction:
         except IOError:
             pass
 
+    def _scriptout(self, data):
+        msgs = self._scriptOutput()
+        self.display.scriptout(data, msgs)
+        self.base.history.log_scriptlet_output(data, msgs)
+
     def __del__(self):
         self._shutdownOutputLogging()
         
@@ -339,7 +344,7 @@ class RPMTransaction:
         # we hand back the right path to those 'outside' of the chroot() calls
         # but we're using the right path inside.
         if self.base.conf.installroot != '/':
-            tsfn = tsfn.replace(self.base.conf.installroot,'')
+            tsfn = tsfn.replace(os.path.normpath(self.base.conf.installroot),'')
         try:
             if not os.path.exists(os.path.dirname(tsfn)):
                 os.makedirs(os.path.dirname(tsfn)) # make the dir,
@@ -439,10 +444,14 @@ class RPMTransaction:
                 txmbrs = self.base.tsInfo.getMembers(pkgtup=pkgtup)
                 for txmbr in txmbrs:
                     self.display.filelog(txmbr.po, txmbr.output_state)
-                    self.display.scriptout(txmbr.po, self._scriptOutput())
+                    self._scriptout(txmbr.po)
+                    # NOTE: We only do this for install, not erase atm.
+                    #       because we don't get pkgtup data for erase (this 
+                    #       includes "Updated" pkgs).
+                    pid   = self.base.history.pkg2pid(txmbr.po)
+                    state = self.base.history.txmbr2state(txmbr)
+                    self.base.history.trans_data_pid_end(pid, state)
                     self.ts_done(txmbr.po, txmbr.output_state)
-                
-                
     
     def _instProgress(self, bytes, total, h):
         if h is not None:
@@ -477,7 +486,7 @@ class RPMTransaction:
         
         self.display.event(h, action, 100, 100, self.complete_actions,
                             self.total_actions)
-        self.display.scriptout(h, self._scriptOutput())
+        self._scriptout(h)
         
         if self.test: return # and we're done
         self.ts_done(h, action)
diff --git a/yum/sqlitesack.py b/yum/sqlitesack.py
index b6c14c5..3dd93a5 100644
--- a/yum/sqlitesack.py
+++ b/yum/sqlitesack.py
@@ -929,15 +929,19 @@ class YumSqlitePackageSack(yumRepo.YumPackageSack):
             if file_glob:
                 name_re = re.compile(fnmatch.translate(name))
             def filelist_globber(sql_dirname, sql_filenames):
+                # Note: Can't return bool, because sqlite doesn't like it in
+                #       weird ways. Test:
+                #                         install '*bin/autoheader'
+                #                         provides /lib/security/pam_loginuid.so
                 files = sql_filenames.split('/')
                 if not file_glob:
-                    return filename in files
+                    return int(filename in files)
 
                 fns = map(lambda f: '%s/%s' % (sql_dirname, f), files)
                 for match in fns:
                     if name_re.match(match):
-                        return True
-                return False
+                        return 1
+                return 0
 
             cache.create_function("filelist_globber", 2, filelist_globber)
             # for all the ones where filenames is multiple files, 
diff --git a/yum/sqlutils.py b/yum/sqlutils.py
index fda380e..3a93146 100644
--- a/yum/sqlutils.py
+++ b/yum/sqlutils.py
@@ -121,6 +121,11 @@ def QmarkToPyformat(query, params):
         if token.endswith("?"):
             output.append(token[:-1] + "%%(param%d)s" % count)
             count+=1
+        elif token.endswith("?,") or token.endswith("?)"):
+            ntoken = token[:-2] + "%%(param%d)s" % count
+            ntoken += token[-1]
+            output.append(ntoken)
+            count+=1
         else:
             output.append(token)
 
diff --git a/yum/transactioninfo.py b/yum/transactioninfo.py
index be772e5..bd7bf80 100644
--- a/yum/transactioninfo.py
+++ b/yum/transactioninfo.py
@@ -271,6 +271,7 @@ class TransactionData:
                     
             elif txmbr.output_state in (TS_INSTALL, TS_TRUEINSTALL):
                 if include_reinstall and self.rpmdb.contains(po=txmbr.po):
+                    txmbr.reinstall = True
                     self.reinstalled.append(txmbr)
                     continue
 
@@ -319,6 +320,8 @@ class TransactionData:
         self.depremoved.sort()
         self.instgroups.sort()
         self.removedgroups.sort()
+        self.reinstalled.sort()
+        self.downgraded.sort()
         self.failed.sort()
 
     
diff --git a/yum/yumRepo.py b/yum/yumRepo.py
index fac218a..367a68e 100644
--- a/yum/yumRepo.py
+++ b/yum/yumRepo.py
@@ -1034,6 +1034,8 @@ class YumRepository(Repository, config.RepoConf):
             old_local = local + '.old.tmp' # locked, so this is ok
             shutil.copy2(local, old_local)
             xml = self._parseRepoXML(old_local, True)
+            if xml is None:
+                return None
             self._oldRepoMDData = {'old_repo_XML' : xml, 'local' : local,
                                    'old_local' : old_local, 'new_MD_files' : []}
             return xml
diff --git a/yumcommands.py b/yumcommands.py
index bd73d0c..f6c4e19 100644
--- a/yumcommands.py
+++ b/yumcommands.py
@@ -778,13 +778,17 @@ class RepoListCommand(YumCommand):
             arg = 'enabled'
         extcmds = map(lambda x: x.lower(), extcmds)
 
-        # Setup so len(repo.sack) is correct
-        base.repos.populateSack()
+        verbose = base.verbose_logger.isEnabledFor(logginglevels.DEBUG_3)
+        try:
+            # Setup so len(repo.sack) is correct
+            base.repos.populateSack()
+        except yum.Errors.RepoError:
+            if verbose:
+                raise
 
         repos = base.repos.repos.values()
         repos.sort()
         enabled_repos = base.repos.listEnabled()
-        verbose = base.verbose_logger.isEnabledFor(logginglevels.DEBUG_3)
         if arg == 'all':
             ehibeg = base.term.FG_COLOR['green'] + base.term.MODE['bold']
             dhibeg = base.term.FG_COLOR['red']
@@ -1061,7 +1065,7 @@ class DowngradeCommand(YumCommand):
 
     def needTs(self, base, basecmd, extcmds):
         return False
-        
+
 
 class VersionCommand(YumCommand):
     def getNames(self):
@@ -1097,11 +1101,19 @@ class VersionCommand(YumCommand):
         cols = []
         if vcmd in ('installed', 'all'):
             try:
-                data = base.rpmdb.simpleVersion()
+                main_only = True
+                if base.verbose_logger.isEnabledFor(logginglevels.DEBUG_3):
+                    main_only = False
+                data = base.rpmdb.simpleVersion(main_only)
+                lastdbv = base.history.last()
+                if lastdbv is not None:
+                    lastdbv = lastdbv.end_rpmdbversion
+                if lastdbv is not None and data[0] != lastdbv:
+                    errstring = _('Warning: RPMDB has been altered since the last yum transaction.')
+                    base.logger.warning(errstring)
                 cols.append(("%s %s/%s" % (_("Installed:"), rel, ba),
                              str(data[0])))
-                if base.verbose_logger.isEnabledFor(logginglevels.DEBUG_3):
-                    _append_repos(cols, data[1])
+                _append_repos(cols, data[1])
             except yum.Errors.YumBaseError, e:
                 return 1, [str(e)]
         if vcmd in ('available', 'all'):
@@ -1126,10 +1138,83 @@ class VersionCommand(YumCommand):
         for line in cols:
             print base.fmtColumns(zip(line, columns))
 
-        return 0, []
+        return 0, ['version']
 
     def needTs(self, base, basecmd, extcmds):
         vcmd = 'installed'
         if extcmds:
             vcmd = extcmds[0]
         return vcmd in ('available', 'all')
+
+
+class HistoryCommand(YumCommand):
+    def getNames(self):
+        return ['history']
+
+    def getUsage(self):
+        return "[info|list|summary|redo|undo|new]"
+
+    def getSummary(self):
+        return _("Display, or use, the transaction history")
+
+    def _hcmd_redo(self, base, extcmds):
+        old = base._history_get_transaction(extcmds)
+        if old is None:
+            return 1, ['Failed history redo']
+        tm = time.ctime(old.beg_timestamp)
+        print "Repeating transaction %u, from %s" % (old.tid, tm)
+        base.historyInfoCmdPkgsAltered(old)
+        if base.history_redo(old):
+            return 2, ["Repeating transaction %u" % (old.tid,)]
+
+    def _hcmd_undo(self, base, extcmds):
+        old = base._history_get_transaction(extcmds)
+        if old is None:
+            return 1, ['Failed history undo']
+        tm = time.ctime(old.beg_timestamp)
+        print "Undoing transaction %u, from %s" % (old.tid, tm)
+        base.historyInfoCmdPkgsAltered(old)
+        if base.history_undo(old):
+            return 2, ["Undoing transaction %u" % (old.tid,)]
+
+    def _hcmd_new(self, base, extcmds):
+        base.history._create_db_file()
+
+    def doCheck(self, base, basecmd, extcmds):
+        cmds = ('list', 'info', 'summary', 'repeat', 'redo', 'undo', 'new')
+        if extcmds and extcmds[0] not in cmds:
+            base.logger.critical(_('Invalid history sub-command, use: %s.'),
+                                 ", ".join(cmds))
+            raise cli.CliError
+        if extcmds and extcmds[0] in ('repeat', 'redo', 'undo', 'new'):
+            checkRootUID(base)
+            checkGPGKey(base)
+
+    def doCommand(self, base, basecmd, extcmds):
+        vcmd = 'list'
+        if extcmds:
+            vcmd = extcmds[0]
+
+        if False: pass
+        elif vcmd == 'list':
+            ret = base.historyListCmd(extcmds)
+        elif vcmd == 'info':
+            ret = base.historyInfoCmd(extcmds)
+        elif vcmd == 'summary':
+            ret = base.historySummaryCmd(extcmds)
+        elif vcmd == 'undo':
+            ret = self._hcmd_undo(base, extcmds)
+        elif vcmd in ('redo', 'repeat'):
+            ret = self._hcmd_redo(base, extcmds)
+        elif vcmd == 'new':
+            ret = self._hcmd_new(base, extcmds)
+
+        if ret is None:
+            return 0, ['history %s' % (vcmd,)]
+        return ret
+
+    def needTs(self, base, basecmd, extcmds):
+        vcmd = 'list'
+        if extcmds:
+            vcmd = extcmds[0]
+        return vcmd in ('repeat', 'redo', 'undo')
diff --git a/yummain.py b/yummain.py
index 964975b..b2a09cc 100755
--- a/yummain.py
+++ b/yummain.py
@@ -31,7 +31,7 @@ from yum import _
 from yum.i18n import to_unicode
 import yum.misc
 import cli
-
+from utils import suppress_keyboard_interrupt_message
 
 def main(args):
     """This does all the real work"""
@@ -307,12 +307,18 @@ def user_main(args, exit_code=False):
             errcode = cprof(main, args)
         if os.environ['YUM_PROF'] == 'hotshot':
             errcode = hotshot(main, args)
+    if 'YUM_PDB' in os.environ:
+        import pdb
+        pdb.run(main(args))
+
     if errcode is None:
         errcode = main(args)
     if exit_code:
         sys.exit(errcode)
     return errcode
 
+suppress_keyboard_interrupt_message()
+
 if __name__ == "__main__":
     try:
         user_main(sys.argv[1:], exit_code=True)