[yum] update to latest HEAD Add new yum DB data. Add hack to workaround broken python readline in yum shel
James Antill
james at fedoraproject.org
Fri Aug 5 17:30:18 UTC 2011
commit 26aebfad16d36af68acccebe4d630c615e4afa8b
Author: James Antill <james at and.org>
Date: Fri Aug 5 13:29:54 2011 -0400
update to latest HEAD
Add new yum DB data.
Add hack to workaround broken python readline in yum shell.
Make "yum -q history addon-info last saved_tx" valid input for load-ts.
Add "history packages-info/stats/sync" sub-commnands.
yum-HEAD.patch | 1032 +++++++++++++++++++++++++++++++++++++++++++++++++++-----
yum.spec | 9 +-
2 files changed, 955 insertions(+), 86 deletions(-)
---
diff --git a/yum-HEAD.patch b/yum-HEAD.patch
index 68a8d9d..74ff6ed 100644
--- a/yum-HEAD.patch
+++ b/yum-HEAD.patch
@@ -1459,10 +1459,72 @@ index 0000000..d2a0ed1
+if __name__ == "__main__":
+ generateAll(os.getcwd(), os.getcwd())
diff --git a/docs/yum.8 b/docs/yum.8
-index 1a8202a..ea18f34 100644
+index 1a8202a..255c755 100644
--- a/docs/yum.8
+++ b/docs/yum.8
-@@ -401,6 +401,11 @@ Assume yes; assume that the answer to any question which would be asked
+@@ -69,7 +69,9 @@ gnome\-packagekit application\&.
+ .br
+ .I \fR * version [ all | installed | available | group-* | nogroups* | grouplist | groupinfo ]
+ .br
+-.I \fR * history [info|list|packages-list|summary|addon-info|redo|undo|rollback|new]
++.I \fR * history [info|list|packages-list|packages-info|summary|addon-info|redo|undo|rollback|new|sync|stats]
++.br
++.I \fR * load-transaction [txfile]
+ .br
+ .I \fR * check
+ .br
+@@ -321,15 +323,17 @@ and so takes sub-commands:
+ .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/packages-list/summary to view what happened, undo/redo/rollback to act
+-on that information and new to start a new history file.
++info/list/packages-list/packages-info/summary to view what happened,
++undo/redo/rollback to act on that information and new to start a new history
++file.
+
+ The info/list/summary commands take either a transaction 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.
+
+-The packages-list command takes a package (with wildcards, as in
+-\fBSpecifying package names\fP).
++The packages-list/packages-info commands takes a package (with wildcards, as in
++\fBSpecifying package names\fP). And show data from the point of view of that
++package.
+
+ The undo/redo/rollback commands take either a single transaction id or the
+ keyword last and an offset from the last transaction (Eg. if you've done 250
+@@ -349,6 +353,12 @@ transactions 1 and 4.
+ The addon-info command takes a transaction ID, and the packages-list command
+ takes a package (with wildcards).
+
++The stats command shows some statistics about the current history DB.
++
++The sync commands allows you to change the rpmdb/yumdb data stored for any
++installed packages, to whaever is in the current rpmdb/yumdb (this is mostly
++useful when this data was not stored when the package went into the history DB).
++
+ In "history list" you can change the behaviour of the 2nd column via. the
+ configuration option history_list_view.
+
+@@ -371,6 +381,15 @@ end of the package column in the packages-list command).
+ .I \fBs\fR - The transaction completed fine, but --skip-broken was enabled and had to skip some packages.
+ .br
+
++
++.IP
++.IP "\fBload-transaction\fP"
++This command will re-load a saved yum transaction file, this allows you to
++run a transaction on one machine and then use it on another.
++The two common ways to get a saved yum transaction file are from
++"yum -q history addon-info last saved_tx" or via. the automatic saves in
++$TMPDIR/yum_save_tx.* when a transaction is solved but not run.
++
+ .IP
+ .IP "\fBcheck\fP"
+ Checks the local rpmdb and produces information on any problems it finds. You
+@@ -401,6 +420,11 @@ Assume yes; assume that the answer to any question which would be asked
is yes\&.
.br
Configuration Option: \fBassumeyes\fP
@@ -1956,7 +2018,7 @@ index f1e06e8..2faeb59 100644
;;
version)
diff --git a/output.py b/output.py
-index b6aa277..9610232 100755
+index b6aa277..00e0e6f 100755
--- a/output.py
+++ b/output.py
@@ -1,6 +1,6 @@
@@ -1967,7 +2029,16 @@ index b6aa277..9610232 100755
# 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
-@@ -60,17 +60,21 @@ def _term_width():
+@@ -47,6 +47,8 @@ import yum.history
+
+ from yum.i18n import utf8_width, utf8_width_fill, utf8_text_fill
+
++import locale
++
+ def _term_width():
+ """ Simple terminal width, limit to 20 chars. and make 0 == 80. """
+ if not hasattr(urlgrabber.progress, 'terminal_width_cached'):
+@@ -60,17 +62,21 @@ def _term_width():
class YumTextMeter(TextMeter):
@@ -1994,7 +2065,7 @@ index b6aa277..9610232 100755
# From initial search for "terminfo and python" got:
# http://aspn.activestate.com/ASPN/Cookbook/Python/Recipe/475116
-@@ -145,6 +149,17 @@ class YumTerm:
+@@ -145,6 +151,17 @@ class YumTerm:
self.BG_COLOR = self.__ansi_forced_BG_COLOR
def reinit(self, term_stream=None, color='auto'):
@@ -2012,7 +2083,7 @@ index b6aa277..9610232 100755
self.__enabled = True
if not hasattr(urlgrabber.progress, 'terminal_width_cached'):
self.columns = 80
-@@ -255,6 +270,37 @@ class YumTerm:
+@@ -255,6 +272,37 @@ class YumTerm:
return re.sub(r'\$<\d+>[/*]?', '', cap)
def sub(self, haystack, beg, end, needles, escape=None, ignore_case=False):
@@ -2050,7 +2121,7 @@ index b6aa277..9610232 100755
if not self.__enabled:
return haystack
-@@ -269,27 +315,106 @@ class YumTerm:
+@@ -269,27 +317,106 @@ class YumTerm:
haystack = re.sub(pat, render, haystack)
return haystack
def sub_norm(self, haystack, beg, needles, **kwds):
@@ -2161,7 +2232,7 @@ index b6aa277..9610232 100755
def __init__(self):
self.logger = logging.getLogger("yum.cli")
-@@ -304,6 +429,12 @@ class YumOutput:
+@@ -304,6 +431,12 @@ class YumOutput:
def printtime(self):
@@ -2174,7 +2245,7 @@ index b6aa277..9610232 100755
months = [_('Jan'), _('Feb'), _('Mar'), _('Apr'), _('May'), _('Jun'),
_('Jul'), _('Aug'), _('Sep'), _('Oct'), _('Nov'), _('Dec')]
now = time.localtime(time.time())
-@@ -312,14 +443,27 @@ class YumOutput:
+@@ -312,14 +445,27 @@ class YumOutput:
return ret
def failureReport(self, errobj):
@@ -2204,7 +2275,7 @@ index b6aa277..9610232 100755
progressbar(current, total, name)
def _highlight(self, highlight):
-@@ -368,9 +512,29 @@ class YumOutput:
+@@ -368,9 +514,29 @@ class YumOutput:
def calcColumns(self, data, columns=None, remainder_column=0,
total_width=None, indent=''):
@@ -2237,7 +2308,7 @@ index b6aa277..9610232 100755
if total_width is None:
total_width = self.term.columns
-@@ -473,10 +637,20 @@ class YumOutput:
+@@ -473,10 +639,20 @@ class YumOutput:
return (val, width, hibeg, hiend)
def fmtColumns(self, columns, msg=u'', end=u'', text_width=utf8_width):
@@ -2262,7 +2333,7 @@ index b6aa277..9610232 100755
total_width = len(msg)
data = []
for col_data in columns[:-1]:
-@@ -513,8 +687,18 @@ class YumOutput:
+@@ -513,8 +689,18 @@ class YumOutput:
def simpleList(self, pkg, ui_overflow=False, indent='', highlight=False,
columns=None):
@@ -2283,7 +2354,7 @@ index b6aa277..9610232 100755
if columns is None:
columns = (-40, -22, -16) # Old default
ver = pkg.printVer()
-@@ -526,9 +710,19 @@ class YumOutput:
+@@ -526,9 +712,19 @@ class YumOutput:
def simpleEnvraList(self, pkg, ui_overflow=False,
indent='', highlight=False, columns=None):
@@ -2306,7 +2377,7 @@ index b6aa277..9610232 100755
if columns is None:
columns = (-63, -16) # Old default
envra = '%s%s' % (indent, str(pkg))
-@@ -538,7 +732,13 @@ class YumOutput:
+@@ -538,7 +734,13 @@ class YumOutput:
print self.fmtColumns(columns, text_width=len)
def fmtKeyValFill(self, key, val):
@@ -2321,7 +2392,7 @@ index b6aa277..9610232 100755
val = to_str(val)
keylen = utf8_width(key)
cols = self.term.columns
-@@ -553,6 +753,15 @@ class YumOutput:
+@@ -553,6 +755,15 @@ class YumOutput:
return ret
def fmtSection(self, name, fill='='):
@@ -2337,7 +2408,7 @@ index b6aa277..9610232 100755
name = to_str(name)
cols = self.term.columns - 2
name_len = utf8_width(name)
-@@ -577,6 +786,12 @@ class YumOutput:
+@@ -577,6 +788,12 @@ class YumOutput:
return to_unicode(s)
def infoOutput(self, pkg, highlight=False):
@@ -2350,7 +2421,7 @@ index b6aa277..9610232 100755
(hibeg, hiend) = self._highlight(highlight)
print _("Name : %s%s%s") % (hibeg, to_unicode(pkg.name), hiend)
print _("Arch : %s") % to_unicode(pkg.arch)
-@@ -617,9 +832,22 @@ class YumOutput:
+@@ -617,9 +834,22 @@ class YumOutput:
print ""
def updatesObsoletesList(self, uotup, changetype, columns=None):
@@ -2376,7 +2447,7 @@ index b6aa277..9610232 100755
(changePkg, instPkg) = uotup
if columns is not None:
-@@ -640,12 +868,44 @@ class YumOutput:
+@@ -640,12 +870,44 @@ class YumOutput:
def listPkgs(self, lst, description, outputType, highlight_na={},
columns=None, highlight_modes={}):
@@ -2427,7 +2498,7 @@ index b6aa277..9610232 100755
if outputType in ['list', 'info']:
thingslisted = 0
if len(lst) > 0:
-@@ -679,8 +939,11 @@ class YumOutput:
+@@ -679,8 +941,11 @@ class YumOutput:
def userconfirm(self):
@@ -2440,7 +2511,7 @@ index b6aa277..9610232 100755
yui = (to_unicode(_('y')), to_unicode(_('yes')))
nui = (to_unicode(_('n')), to_unicode(_('no')))
aui = (yui[0], yui[1], nui[0], nui[1])
-@@ -774,6 +1037,10 @@ class YumOutput:
+@@ -774,6 +1039,10 @@ class YumOutput:
columns=columns)
def displayPkgsInGroups(self, group):
@@ -2451,7 +2522,7 @@ index b6aa277..9610232 100755
print _('\nGroup: %s') % group.ui_name
verb = self.verbose_logger.isEnabledFor(logginglevels.DEBUG_3)
-@@ -807,8 +1074,11 @@ class YumOutput:
+@@ -807,8 +1076,11 @@ class YumOutput:
columns=columns)
def depListOutput(self, results):
@@ -2465,7 +2536,7 @@ index b6aa277..9610232 100755
verb = self.verbose_logger.isEnabledFor(logginglevels.DEBUG_3)
for pkg in sorted(results):
print _("package: %s") % pkg.compactPrint()
-@@ -832,7 +1102,18 @@ class YumOutput:
+@@ -832,7 +1104,18 @@ class YumOutput:
print " provider: %s" % po.compactPrint()
def format_number(self, number, SI=0, space=' '):
@@ -2485,7 +2556,7 @@ index b6aa277..9610232 100755
symbols = [ ' ', # (none)
'k', # kilo
'M', # mega
-@@ -870,16 +1151,31 @@ class YumOutput:
+@@ -870,16 +1153,31 @@ class YumOutput:
@staticmethod
def format_time(seconds, use_hours=0):
@@ -2523,7 +2594,7 @@ index b6aa277..9610232 100755
if self.conf.showdupesfromrepos:
msg = '%s : ' % po
else:
-@@ -935,10 +1231,23 @@ class YumOutput:
+@@ -935,10 +1233,23 @@ class YumOutput:
print '\n\n'
def matchcallback_verbose(self, po, values, matchfor=None):
@@ -2548,7 +2619,7 @@ index b6aa277..9610232 100755
totsize = 0
locsize = 0
insize = 0
-@@ -982,7 +1291,10 @@ class YumOutput:
+@@ -982,7 +1293,10 @@ class YumOutput:
self.format_number(insize))
def reportRemoveSize(self, packages):
@@ -2560,7 +2631,7 @@ index b6aa277..9610232 100755
totsize = 0
error = False
for pkg in packages:
-@@ -1002,8 +1314,9 @@ class YumOutput:
+@@ -1002,8 +1316,9 @@ class YumOutput:
self.format_number(totsize))
def listTransaction(self):
@@ -2572,7 +2643,7 @@ index b6aa277..9610232 100755
self.tsInfo.makelists(True, True)
pkglist_lines = []
data = {'n' : {}, 'v' : {}, 'r' : {}}
-@@ -1115,6 +1428,12 @@ Transaction Summary
+@@ -1115,6 +1430,12 @@ Transaction Summary
return ''.join(out)
def postTransactionOutput(self):
@@ -2585,7 +2656,7 @@ index b6aa277..9610232 100755
out = ''
self.tsInfo.makelists()
-@@ -1179,9 +1498,9 @@ Transaction Summary
+@@ -1179,9 +1500,9 @@ Transaction Summary
return out
def setupProgressCallbacks(self):
@@ -2598,7 +2669,7 @@ index b6aa277..9610232 100755
# if we're below 2 on the debug level we don't need to be outputting
# progress bars - this is hacky - I'm open to other options
# One of these is a download
-@@ -1216,10 +1535,12 @@ Transaction Summary
+@@ -1216,10 +1537,12 @@ Transaction Summary
self.dsCallback = dscb
def setupProgessCallbacks(self):
@@ -2612,7 +2683,7 @@ index b6aa277..9610232 100755
confirm_func = self._cli_confirm_gpg_key_import
gpg_import_func = self.getKeyForRepo
gpgca_import_func = self.getCAKeyForRepo
-@@ -1233,14 +1554,12 @@ Transaction Summary
+@@ -1233,14 +1556,12 @@ Transaction Summary
self.repos.gpgca_import_func = gpgca_import_func
def interrupt_callback(self, cbobj):
@@ -2632,7 +2703,7 @@ index b6aa277..9610232 100755
'''
delta_exit_chk = 2.0 # Delta between C-c's so we treat as exit
delta_exit_str = _("two") # Human readable version of above
-@@ -1269,6 +1588,14 @@ to exit.
+@@ -1269,6 +1590,14 @@ to exit.
def download_callback_total_cb(self, remote_pkgs, remote_size,
download_start_timestamp):
@@ -2647,7 +2718,7 @@ index b6aa277..9610232 100755
if len(remote_pkgs) <= 1:
return
if not hasattr(urlgrabber.progress, 'TerminalLine'):
-@@ -1434,8 +1761,17 @@ to exit.
+@@ -1434,8 +1763,17 @@ to exit.
return tids, printall
def historyListCmd(self, extcmds):
@@ -2657,16 +2728,16 @@ index b6aa277..9610232 100755
+
+ :param extcmds: list of extra command line arguments
+ :return: (exit_code, [errors])
-
-+ exit_code is::
+
++ exit_code is::
+
+ 0 = we're done, exit
+ 1 = we've errored, exit with error string
+ """
tids, printall = self._history_list_transactions(extcmds)
if tids is None:
return 1, ['Failed history list']
-@@ -1564,6 +1900,16 @@ to exit.
+@@ -1564,6 +1902,16 @@ to exit.
return old[0]
def historyInfoCmd(self, extcmds):
@@ -2683,7 +2754,17 @@ index b6aa277..9610232 100755
def str2int(x):
try:
return int(x)
-@@ -1833,6 +2179,13 @@ to exit.
+@@ -1656,6 +2004,9 @@ to exit.
+ def _hpkg2from_repo(self, hpkg):
+ """ Given a pkg, find the ipkg.ui_from_repo ... if none, then
+ get an apkg. ... and put a ? in there. """
++ if 'from_repo' in hpkg.yumdb_info:
++ return hpkg.ui_from_repo
++
+ ipkgs = self.rpmdb.searchPkgTuple(hpkg.pkgtup)
+ if not ipkgs:
+ apkgs = self.pkgSack.searchPkgTuple(hpkg.pkgtup)
+@@ -1833,6 +2184,13 @@ to exit.
'Updated' : _('Updated'),
}
def historyInfoCmdPkgsAltered(self, old, pats=[]):
@@ -2697,7 +2778,7 @@ index b6aa277..9610232 100755
last = None
# Note that these don't use _simple_pkg() because we are showing what
# happened to them in the transaction ... not the difference between the
-@@ -1886,6 +2239,10 @@ to exit.
+@@ -1886,6 +2244,10 @@ to exit.
self._hpkg2from_repo(hpkg))
def historySummaryCmd(self, extcmds):
@@ -2708,7 +2789,7 @@ index b6aa277..9610232 100755
tids, printall = self._history_list_transactions(extcmds)
if tids is None:
return 1, ['Failed history info']
-@@ -1946,6 +2303,10 @@ to exit.
+@@ -1946,6 +2308,10 @@ to exit.
utf8_width_fill(uiacts, 16, 16), count)
def historyAddonInfoCmd(self, extcmds):
@@ -2719,8 +2800,20 @@ index b6aa277..9610232 100755
tid = None
if len(extcmds) > 1:
tid = extcmds[1]
-@@ -1991,8 +2352,11 @@ to exit.
- print ''
+@@ -1983,16 +2349,19 @@ to exit.
+
+ for item in extcmds[2:]:
+ if item in addon_info:
+- print '%s:' % item
+- print self.history.return_addon_data(hist_data.tid, item)
++ self.verbose_logger.log(logginglevels.INFO_2, '%s:', item)
++ print self.history.return_addon_data(hist_data.tid, item),
++ self.verbose_logger.log(logginglevels.INFO_2, '')
+ else:
+ print _('%s: No additional data found by this name') % item
+-
+- print ''
++ self.verbose_logger.log(logginglevels.INFO_2, '')
def historyPackageListCmd(self, extcmds):
- """ Shows the user a list of data about the history, from the point
@@ -2733,8 +2826,96 @@ index b6aa277..9610232 100755
tids = self.history.search(extcmds)
limit = None
if extcmds and not tids:
-@@ -2080,7 +2444,7 @@ to exit.
+@@ -2078,9 +2447,95 @@ to exit.
+ if lastdbv.end_rpmdbversion != rpmdbv:
+ self._rpmdb_warn_checks()
++ def historyPackageInfoCmd(self, extcmds):
++ """Print information about packages in history transactions.
++
++ :param extcmds: list of extra command line arguments
++ """
++ tids = self.history.search(extcmds)
++ limit = None
++ if extcmds and not tids:
++ self.logger.critical(_('Bad transaction IDs, or package(s), given'))
++ return 1, ['Failed history packages-info']
++ if not tids:
++ limit = 20
++
++ all_uistates = self._history_state2uistate
++
++ num = 0
++ for old in self.history.old(tids, limit=limit):
++ if limit is not None and num and (num +len(old.trans_data)) > limit:
++ break
++ last = None
++
++ for hpkg in old.trans_data: # Find a pkg to go with each cmd...
++ if limit is None:
++ x,m,u = yum.packages.parsePackages([hpkg], extcmds)
++ if not x and not m:
++ continue
++
++ uistate = all_uistates.get(hpkg.state, hpkg.state)
++ if num:
++ print ""
++ print _("Transaction ID :"), old.tid
++ tm = time.ctime(old.beg_timestamp)
++ print _("Begin time :"), tm
++ print _("Package :"), hpkg.ui_nevra
++ print _("State :"), uistate
++ if hpkg.size is not None:
++ num = int(hpkg.size)
++ print _("Size :"), locale.format("%d", num, True)
++ if hpkg.buildhost is not None:
++ print _("Build host :"), hpkg.buildhost
++ if hpkg.buildtime is not None:
++ tm = time.ctime(int(hpkg.buildtime))
++ print _("Build time :"), tm
++ if hpkg.packager is not None:
++ print _("Packager :"), hpkg.packager
++ if hpkg.vendor is not None:
++ print _("Vendor :"), hpkg.vendor
++ if hpkg.license is not None:
++ print _("License :"), hpkg.license
++ if hpkg.url is not None:
++ print _("URL :"), hpkg.url
++ if hpkg.sourcerpm is not None:
++ print _("Source RPM :"), hpkg.sourcerpm
++ if hpkg.committime is not None:
++ tm = time.ctime(int(hpkg.committime))
++ print _("Commit Time :"), tm
++ if hpkg.committer is not None:
++ print _("Committer :"), hpkg.committer
++ if hpkg.yumdb_info.reason is not None:
++ print _("Reason :"), hpkg.yumdb_info.reason
++ if hpkg.yumdb_info.command_line is not None:
++ print _("Command Line :"), hpkg.yumdb_info.command_line
++ if hpkg.yumdb_info.from_repo is not None:
++ print _("From repo :"), hpkg.yumdb_info.from_repo
++ if hpkg.yumdb_info.installed_by is not None:
++ uid = int(hpkg.yumdb_info.installed_by)
++ name = self._pwd_ui_username(uid)
++ print _("Installed by :"), name
++ if hpkg.yumdb_info.changed_by is not None:
++ uid = int(hpkg.yumdb_info.changed_by)
++ name = self._pwd_ui_username(uid)
++ print _("Changed by :"), name
++
++ num += 1
++
++ # And, again, copy and paste...
++ lastdbv = self.history.last()
++ if lastdbv is None:
++ self._rpmdb_warn_checks(warn=False)
++ else:
++ # 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:
++ self._rpmdb_warn_checks()
++
class DepSolveProgressCallBack:
- """provides text output callback functions for Dependency Solver callback"""
@@ -2742,7 +2923,7 @@ index b6aa277..9610232 100755
def __init__(self, ayum=None):
"""requires yum-cli log and errorlog functions as arguments"""
-@@ -2089,6 +2453,25 @@ class DepSolveProgressCallBack:
+@@ -2089,6 +2544,25 @@ class DepSolveProgressCallBack:
self.ayum = ayum
def pkgAdded(self, pkgtup, mode):
@@ -2768,7 +2949,7 @@ index b6aa277..9610232 100755
modedict = { 'i': _('installed'),
'u': _('an update'),
'e': _('erased'),
-@@ -2104,43 +2487,85 @@ class DepSolveProgressCallBack:
+@@ -2104,43 +2578,85 @@ class DepSolveProgressCallBack:
modeterm)
def start(self):
@@ -2856,7 +3037,7 @@ index b6aa277..9610232 100755
needname, needflags, needversion = reqTup
yb = self.ayum
-@@ -2225,45 +2650,89 @@ class DepSolveProgressCallBack:
+@@ -2225,45 +2741,89 @@ class DepSolveProgressCallBack:
return msg
def procConflict(self, name, confname):
@@ -2950,7 +3131,7 @@ index b6aa277..9610232 100755
progressbar(current, total, name)
def _pkgname_ui(ayum, pkgname, ts_states=None):
-@@ -2316,10 +2785,7 @@ def _pkgname_ui(ayum, pkgname, ts_states=None):
+@@ -2316,10 +2876,7 @@ def _pkgname_ui(ayum, pkgname, ts_states=None):
return pkgname
class YumCliRPMCallBack(RPMBaseCallback):
@@ -2962,7 +3143,7 @@ index b6aa277..9610232 100755
width = property(lambda x: _term_width())
-@@ -2337,11 +2803,31 @@ class YumCliRPMCallBack(RPMBaseCallback):
+@@ -2337,11 +2894,31 @@ class YumCliRPMCallBack(RPMBaseCallback):
# Installing things have pkg objects passed to the events, so only need to
# lookup for erased/obsoleted.
def pkgname_ui(self, pkgname, ts_states=('e', 'od', 'ud', None)):
@@ -2996,7 +3177,7 @@ index b6aa277..9610232 100755
process = self.action[action]
if not hasattr(self, '_max_action_wid'):
-@@ -2366,6 +2852,7 @@ class YumCliRPMCallBack(RPMBaseCallback):
+@@ -2366,6 +2943,7 @@ class YumCliRPMCallBack(RPMBaseCallback):
if self.output and (sys.stdout.isatty() or te_current == te_total):
(fmt, wid1, wid2) = self._makefmt(percent, ts_current, ts_total,
@@ -3004,7 +3185,7 @@ index b6aa277..9610232 100755
pkgname=pkgname, wid1=wid1)
msg = fmt % (utf8_width_fill(process, wid1, wid1),
utf8_width_fill(pkgname, wid2, wid2))
-@@ -2377,6 +2864,11 @@ class YumCliRPMCallBack(RPMBaseCallback):
+@@ -2377,6 +2955,11 @@ class YumCliRPMCallBack(RPMBaseCallback):
print " "
def scriptout(self, package, msgs):
@@ -3016,7 +3197,7 @@ index b6aa277..9610232 100755
if msgs:
sys.stdout.write(to_unicode(msgs))
sys.stdout.flush()
-@@ -2431,6 +2923,15 @@ class YumCliRPMCallBack(RPMBaseCallback):
+@@ -2431,6 +3014,15 @@ class YumCliRPMCallBack(RPMBaseCallback):
def progressbar(current, total, name=None):
@@ -3083,11 +3264,20 @@ index 6082005..ad7bbb1 100644
elif myarch.startswith("arm"):
return "arm"
diff --git a/shell.py b/shell.py
-index 999bffc..636f12c 100644
+index 999bffc..34a492e 100644
--- a/shell.py
+++ b/shell.py
-@@ -29,10 +29,7 @@ import yum.logginglevels as logginglevels
+@@ -23,16 +23,14 @@ import cmd
+ import shlex
+ import logging
+-from yum import Errors
++from yum import Errors, _
+ from yum.constants import *
+ import yum.logginglevels as logginglevels
+-
++from yum.i18n import to_utf8
++import __builtin__
class YumShell(cmd.Cmd):
-
@@ -3098,9 +3288,38 @@ index 999bffc..636f12c 100644
def __init__(self, base):
cmd.Cmd.__init__(self)
-@@ -77,6 +74,11 @@ class YumShell(cmd.Cmd):
- return inputs
+@@ -75,8 +73,39 @@ class YumShell(cmd.Cmd):
+ raise Errors.YumBaseError, "Fatal error in script, exiting"
+ return inputs
+-
++
++ def cmdloop(self, *args, **kwargs):
++ """ Sick hack for readline. """
++
++ oraw_input = raw_input
++ owriter = sys.stdout
++ _ostdout = owriter.stream
++
++ def _sick_hack_raw_input(prompt):
++ sys.stdout = _ostdout
++ rret = oraw_input(to_utf8(prompt))
++ sys.stdout = owriter
++
++ return rret
++
++ __builtin__.raw_input = _sick_hack_raw_input
++
++ try:
++ cret = cmd.Cmd.cmdloop(self, *args, **kwargs)
++ except:
++ __builtin__.raw_input = oraw_input
++ raise
++
++ __builtin__.raw_input = oraw_input
++
++ return cret
++
def script(self):
+ """Execute a script file in the yum shell. The location of
+ the script file is supplied by the :class:`cli.YumBaseCli`
@@ -3110,7 +3329,7 @@ index 999bffc..636f12c 100644
try:
fd = open(self.file, 'r')
except IOError:
-@@ -90,6 +92,13 @@ class YumShell(cmd.Cmd):
+@@ -90,6 +119,13 @@ class YumShell(cmd.Cmd):
return True
def default(self, line):
@@ -3124,7 +3343,7 @@ index 999bffc..636f12c 100644
if len(line) > 0 and line.strip()[0] == '#':
pass
else:
-@@ -117,9 +126,15 @@ class YumShell(cmd.Cmd):
+@@ -117,9 +153,15 @@ class YumShell(cmd.Cmd):
self.base.doCommands()
def emptyline(self):
@@ -3140,7 +3359,7 @@ index 999bffc..636f12c 100644
ret = cmd.Cmd.completenames(self, text, line, begidx, endidx)
for command in self.base.yum_cli_commands:
if command.startswith(text) and command != "shell":
-@@ -127,6 +142,11 @@ class YumShell(cmd.Cmd):
+@@ -127,6 +169,11 @@ class YumShell(cmd.Cmd):
return ret
def do_help(self, arg):
@@ -3152,7 +3371,7 @@ index 999bffc..636f12c 100644
msg = """
Shell specific arguments:
config - set config options
-@@ -166,21 +186,47 @@ class YumShell(cmd.Cmd):
+@@ -166,21 +213,47 @@ class YumShell(cmd.Cmd):
self.verbose_logger.info(msg)
def do_EOF(self, line):
@@ -3200,7 +3419,7 @@ index 999bffc..636f12c 100644
(cmd, args, line) = self.parseline(line)
if cmd in ['list', None]:
self.verbose_logger.log(logginglevels.INFO_2,
-@@ -210,6 +256,15 @@ class YumShell(cmd.Cmd):
+@@ -210,6 +283,15 @@ class YumShell(cmd.Cmd):
self.do_help('transaction')
def do_config(self, line):
@@ -3216,7 +3435,7 @@ index 999bffc..636f12c 100644
(cmd, args, line) = self.parseline(line)
# logs
if cmd in ['debuglevel', 'errorlevel']:
-@@ -264,9 +319,23 @@ class YumShell(cmd.Cmd):
+@@ -264,9 +346,23 @@ class YumShell(cmd.Cmd):
self.do_help('config')
def do_repository(self, line):
@@ -3240,7 +3459,7 @@ index 999bffc..636f12c 100644
(cmd, args, line) = self.parseline(line)
if cmd in ['list', None]:
# Munge things to run the repolist command
-@@ -338,6 +407,10 @@ class YumShell(cmd.Cmd):
+@@ -338,6 +434,10 @@ class YumShell(cmd.Cmd):
print line
def do_run(self, line):
@@ -3251,6 +3470,99 @@ index 999bffc..636f12c 100644
if len(self.base.tsInfo) > 0:
try:
(code, msgs) = self.base.buildTransaction()
+diff --git a/test/check-po-yes-no.py b/test/check-po-yes-no.py
+index e22318e..b9cb8aa 100755
+--- a/test/check-po-yes-no.py
++++ b/test/check-po-yes-no.py
+@@ -16,6 +16,8 @@ def trans(msg, default):
+ msg = msg[:-2]
+ return unicode(msg, encoding='utf-8')
+
++allow_plain_yn = True
++
+ for fname in glob.glob("po/*.po"):
+ next = None
+ is_this_ok = None
+@@ -32,7 +34,8 @@ for fname in glob.glob("po/*.po"):
+ if next is not None:
+ if next == 'is_this_ok':
+ sis_this_ok = line
+- if line == 'msgstr ""\n' or line.find('[y/N]') != -1:
++ if line == 'msgstr ""\n' or (not allow_plain_yn and
++ line.find('[y/N]') != -1):
+ is_this_ok = False
+ else:
+ is_this_ok = True
+@@ -62,9 +65,9 @@ for fname in glob.glob("po/*.po"):
+ next = 'n'
+ if (is_this_ok is None or
+ yes is None or
+- y is None or
++ (not allow_plain_yn and y is None) or
+ no is None or
+- n is None):
++ (not allow_plain_yn and n is None)):
+ print >>sys.stderr, """\
+ ERROR: Can't find all the msg id's in %s
+ is_this_ok %s
+@@ -96,6 +99,10 @@ n %5s: %s
+ to_utf8(is_this_ok), to_utf8(sis_this_ok),
+ to_utf8(yes), to_utf8(syes), to_utf8(y), to_utf8(sy),
+ to_utf8(no), to_utf8(sno), to_utf8(n), to_utf8(sn))
++
++ if allow_plain_yn:
++ continue
++
+ if syes[0] != sy:
+ print >>sys.stderr, """\
+ ERROR: yes/y translations don't match in: %s
+diff --git a/test/simpleobsoletestests.py b/test/simpleobsoletestests.py
+index 97a9923..70dde98 100644
+--- a/test/simpleobsoletestests.py
++++ b/test/simpleobsoletestests.py
+@@ -244,6 +244,42 @@ class SimpleObsoletesTests(OperationsTests):
+ self.assert_(res=='ok', msg)
+ self.assertResult((p.obsoletes_noarch,))
+
++ def testObsoletesOffPostInst1(self):
++ p = self.pkgs
++ res, msg = self.runOperation(['install', 'zsh'], [p.obsoletes_i386], [p.installed_i386])
++ self.assert_(res=='ok', msg)
++ self.assertResult((p.obsoletes_i386,))
++
++ def testObsoletesOffPostInst2(self):
++ p = self.pkgs
++ res, msg = self.runOperation(['install', 'zsh'], [p.obsoletes_i386], [p.installed_i386], {'obsoletes' : False})
++ self.assert_(res=='ok', msg)
++ self.assertResult((p.obsoletes_i386,))
++
++ def testObsoletesOffPostAvail1(self):
++ p = self.pkgs
++ res, msg = self.runOperation(['install', 'zsh-ng', 'zsh'], [], [p.obsoletes_i386, p.installed_i386])
++ self.assert_(res=='ok', msg)
++ self.assertResult((p.obsoletes_i386,))
++
++ def testObsoletesOffPostAvail2(self):
++ p = self.pkgs
++ res, msg = self.runOperation(['install', 'zsh-ng', 'zsh'], [], [p.obsoletes_i386, p.installed_i386], {'obsoletes' : False})
++ self.assert_(res=='ok', msg)
++ self.assertResult((p.obsoletes_i386,))
++
++ def testObsoletesOffPostAvail3(self):
++ p = self.pkgs
++ res, msg = self.runOperation(['install', 'zsh', 'zsh-ng'], [], [p.obsoletes_i386, p.installed_i386])
++ self.assert_(res=='ok', msg)
++ self.assertResult((p.obsoletes_i386,))
++
++ def testObsoletesOffPostAvail4(self):
++ p = self.pkgs
++ res, msg = self.runOperation(['install', 'zsh', 'zsh-ng'], [], [p.obsoletes_i386, p.installed_i386], {'obsoletes' : False})
++ self.assert_(res=='ok', msg)
++ self.assertResult((p.obsoletes_i386,))
++
+ def _MultiObsHelper(self):
+ ret = {'zsh' : FakePackage('zsh', '1', '1', '0', 'noarch'),
+ 'ksh' : FakePackage('ksh', '1', '1', '0', 'noarch'),
diff --git a/utils.py b/utils.py
old mode 100644
new mode 100755
@@ -4616,10 +4928,20 @@ index abd203f..825f745 100644
- 3.4.1
- umask bug fix.
diff --git a/yum/__init__.py b/yum/__init__.py
-index 99039e0..2149d77 100644
+index 99039e0..530bfd4 100644
--- a/yum/__init__.py
+++ b/yum/__init__.py
-@@ -1242,13 +1242,15 @@ class YumBase(depsolve.Depsolve):
+@@ -881,7 +881,8 @@ class YumBase(depsolve.Depsolve):
+ if self._history is None:
+ pdb_path = self.conf.persistdir + "/history"
+ self._history = yum.history.YumHistory(root=self.conf.installroot,
+- db_path=pdb_path)
++ db_path=pdb_path,
++ releasever=self.conf.yumvar['releasever'])
+ return self._history
+
+ # properties so they auto-create themselves with defaults
+@@ -1242,13 +1243,15 @@ class YumBase(depsolve.Depsolve):
if None in pkgtup:
return None
return pkgtup
@@ -4639,7 +4961,17 @@ index 99039e0..2149d77 100644
if pkgtup is None:
return
self._not_found_i[pkgtup] = YumNotFoundPackage(pkgtup)
-@@ -2939,7 +2941,7 @@ class YumBase(depsolve.Depsolve):
+@@ -1645,6 +1648,9 @@ class YumBase(depsolve.Depsolve):
+ elif loginuid is not None:
+ po.yumdb_info.installed_by = str(loginuid)
+
++ if self.conf.history_record:
++ self.history.sync_alldb(po)
++
+ # Remove old ones after installing new ones, so we can copy values.
+ for txmbr in self.tsInfo:
+ if txmbr.output_state in TS_INSTALL_STATES:
+@@ -2939,7 +2945,7 @@ class YumBase(depsolve.Depsolve):
self.verbose_logger.log(logginglevels.DEBUG_2,
_('Adding package %s from group %s'), pkg, thisgroup.groupid)
try:
@@ -4648,7 +4980,7 @@ index 99039e0..2149d77 100644
except Errors.InstallError, e:
self.verbose_logger.debug(_('No package named %s available to be installed'),
pkg)
-@@ -3049,7 +3051,7 @@ class YumBase(depsolve.Depsolve):
+@@ -3049,7 +3055,7 @@ class YumBase(depsolve.Depsolve):
pkgs = self.pkgSack.searchPkgTuple(pkgtup)
if len(pkgs) == 0:
@@ -4657,7 +4989,7 @@ index 99039e0..2149d77 100644
if allow_missing: # This can happen due to excludes after .up has
return None # happened.
raise Errors.DepError, _('Package tuple %s could not be found in packagesack') % str(pkgtup)
-@@ -3071,7 +3073,7 @@ class YumBase(depsolve.Depsolve):
+@@ -3071,7 +3077,7 @@ class YumBase(depsolve.Depsolve):
pkgs = self.rpmdb.searchPkgTuple(pkgtup)
if len(pkgs) == 0:
@@ -4666,13 +4998,16 @@ index 99039e0..2149d77 100644
raise Errors.RpmDBError, _('Package tuple %s could not be found in rpmdb') % str(pkgtup)
# Dito. FIXME from getPackageObject() for len() > 1 ... :)
-@@ -3445,6 +3447,18 @@ class YumBase(depsolve.Depsolve):
+@@ -3445,6 +3451,21 @@ class YumBase(depsolve.Depsolve):
"""
+
+ # This is kind of hacky, we really need a better way to do errors than
+ # doing them directly from .install/etc. ... but this is easy. *sigh*.
++ # We are only using this in "groupinstall" atm. ... so we don't have
++ # a long list of "blah already installed." messages when people run
++ # "groupinstall mygroup" in yum-cron etc.
+ pkg_warn = kwargs.get('pkg_warning_level', 'flibble')
+ def _dbg2(*args, **kwargs):
+ self.verbose_logger.log(logginglevels.DEBUG_2, *args, **kwargs)
@@ -4685,7 +5020,7 @@ index 99039e0..2149d77 100644
pkgs = []
was_pattern = False
if po:
-@@ -3600,23 +3614,23 @@ class YumBase(depsolve.Depsolve):
+@@ -3600,23 +3621,23 @@ class YumBase(depsolve.Depsolve):
already_obs = pkgs[0]
if already_obs:
@@ -4716,7 +5051,7 @@ index 99039e0..2149d77 100644
continue
# make sure we don't have a name.arch of this already installed
-@@ -3630,7 +3644,7 @@ class YumBase(depsolve.Depsolve):
+@@ -3630,7 +3651,7 @@ class YumBase(depsolve.Depsolve):
found = True
break
if not found:
@@ -4725,7 +5060,7 @@ index 99039e0..2149d77 100644
txmbrs = self.update(po=po)
tx_return.extend(txmbrs)
continue
-@@ -4725,7 +4739,9 @@ class YumBase(depsolve.Depsolve):
+@@ -4725,7 +4746,9 @@ class YumBase(depsolve.Depsolve):
# Try installing/updating GPG key
self._getKeyImportMessage(info, keyurl)
rc = False
@@ -4736,7 +5071,7 @@ index 99039e0..2149d77 100644
rc = True
# grab the .sig/.asc for the keyurl, if it exists
-@@ -4819,8 +4835,11 @@ class YumBase(depsolve.Depsolve):
+@@ -4819,8 +4842,11 @@ class YumBase(depsolve.Depsolve):
if not key_installed:
self._getKeyImportMessage(info, keyurl, keytype)
rc = False
@@ -4749,7 +5084,7 @@ index 99039e0..2149d77 100644
elif callback:
rc = callback({"repo": repo, "userid": info['userid'],
"hexkeyid": info['hexkeyid'], "keyurl": keyurl,
-@@ -5234,7 +5253,7 @@ class YumBase(depsolve.Depsolve):
+@@ -5234,7 +5260,7 @@ class YumBase(depsolve.Depsolve):
raise Errors.YumBaseError(_("Dependencies not solved. Will not save unresolved transaction."))
if not filename:
@@ -4758,6 +5093,23 @@ index 99039e0..2149d77 100644
fd,filename = tempfile.mkstemp(suffix='.yumtx', prefix=prefix)
f = os.fdopen(fd, 'w')
else:
+@@ -5292,6 +5318,16 @@ class YumBase(depsolve.Depsolve):
+ # 3+numrepos = num pkgs
+ # 3+numrepos+1 -> EOF= txmembers
+
++ if data[0] == 'saved_tx:\n':
++ # Old versions of yum would put "saved_tx:" at the begining and
++ # two blank lines at the end when you used:
++ # "yum -q history addon-info saved_tx".
++ if data[-1] == 'history addon-info\n':
++ # Might as well also DTRT if they hand removed the plugins line
++ data = data[1:-3]
++ else:
++ data = data[1:-2]
++
+ # rpm db ver
+ rpmv = data[0].strip()
+ if rpmv != str(self.rpmdb.simpleVersion(main_only=True)[0]):
diff --git a/yum/callbacks.py b/yum/callbacks.py
index 7ad25ce..a9a8e53 100644
--- a/yum/callbacks.py
@@ -6110,6 +6462,450 @@ index bca9651..00c17ad 100644
if i == None:
index = self.failures
else:
+diff --git a/yum/history.py b/yum/history.py
+index 5385bd1..c91c33a 100644
+--- a/yum/history.py
++++ b/yum/history.py
+@@ -97,9 +97,58 @@ def _setupHistorySearchSQL(patterns=None, ignore_case=False):
+ return (need_full, patterns, fields, False)
+ # ---- horrible Copy and paste from sqlitesack ----
+
++class _YumHistPackageYumDB:
++ """ Class to pretend to be yumdb_info for history packages. """
++
++ def __init__(self, pkg):
++ self._pkg = pkg
++
++ _valid_yumdb_keys = set(["command_line",
++ "from_repo", "from_repo_revision",
++ "from_repo_timestamp",
++ "installed_by", "changed_by",
++ "reason", "releasever"])
++ def __getattr__(self, attr):
++ """ Load yumdb attributes from the history sqlite. """
++ pkg = self._pkg
++ if attr.startswith('_'):
++ raise AttributeError, "%s has no yum attribute %s" % (pkg, attr)
++
++ if attr not in self._valid_yumdb_keys:
++ raise AttributeError, "%s has no yum attribute %s" % (pkg, attr)
++
++ val = pkg._history._load_yumdb_key(pkg, attr)
++ if False and val is None:
++ raise AttributeError, "%s has no yum attribute %s" % (pkg, attr)
++
++ if val is None:
++ return None
++
++ val = str(val) or ""
++ setattr(self, attr, val)
++
++ return val
++
++ def __contains__(self, attr):
++ # This is faster than __iter__ and it makes things fail in a much more
++ # obvious way in weird FS corruption cases like: BZ 593436
++ x = self.get(attr)
++ return x is not None
++
++ def get(self, attr, default=None):
++ """retrieve an add'l data obj"""
++
++ try:
++ res = getattr(self, attr)
++ except AttributeError:
++ return default
++ return res
++
++
+ class YumHistoryPackage(PackageObject):
+
+- def __init__(self, name, arch, epoch, version, release, checksum=None):
++ def __init__(self, name, arch, epoch, version, release, checksum=None,
++ history=None):
+ self.name = name
+ self.version = version
+ self.release = release
+@@ -111,21 +160,69 @@ class YumHistoryPackage(PackageObject):
+ self._checksums = [] # (type, checksum, id(0,1)
+ else:
+ chk = checksum.split(':')
+- self._checksums = [(chk[0], chk[1], 0)] # (type, checksum, id(0,1))
++ self._checksums = [(chk[0], chk[1], 1)] # (type, checksum, id(0,1))
+ # Needed for equality comparisons in PackageObject
+ self.repoid = "<history>"
+
++ self._history = history
++ self.yumdb_info = _YumHistPackageYumDB(self)
++
++ _valid_rpmdb_keys = set(["buildtime", "buildhost",
++ "license", "packager",
++ "size", "sourcerpm", "url", "vendor",
++ # ?
++ "committer", "committime"])
++ def __getattr__(self, attr):
++ """ Load rpmdb attributes from the history sqlite. """
++ if attr.startswith('_'):
++ raise AttributeError, "%s has no attribute %s" % (self, attr)
++
++ if attr not in self._valid_rpmdb_keys:
++ raise AttributeError, "%s has no attribute %s" % (self, attr)
++
++ val = self._history._load_rpmdb_key(self, attr)
++ if False and val is None:
++ raise AttributeError, "%s has no attribute %s" % (self, attr)
++
++ if val is None:
++ return None
++
++ val = str(val) or ""
++ setattr(self, attr, val)
++
++ return val
++
++ def _ui_from_repo(self):
++ """ This reports the repo the package is from, we integrate YUMDB info.
++ for RPM packages so a package from "fedora" that is installed has a
++ ui_from_repo of "@fedora". Note that, esp. with the --releasever
++ option, "fedora" or "rawhide" isn't authoritive.
++ So we also check against the current releasever and if it is
++ different we also print the YUMDB releasever. This means that
++ installing from F12 fedora, while running F12, would report as
++ "@fedora/13". """
++ if 'from_repo' in self.yumdb_info:
++ self._history.releasever
++ end = ''
++ if (self._history.releasever is not None and
++ 'releasever' in self.yumdb_info and
++ self.yumdb_info.releasever != self._history.releasever):
++ end = '/' + self.yumdb_info.releasever
++ return '@' + self.yumdb_info.from_repo + end
++ return self.repoid
++ ui_from_repo = property(fget=lambda self: self._ui_from_repo())
++
++
+ class YumHistoryPackageState(YumHistoryPackage):
+- def __init__(self, name,arch, epoch,version,release, state, checksum=None):
++ def __init__(self, name,arch, epoch,version,release, state, checksum=None,
++ history=None):
+ YumHistoryPackage.__init__(self, name,arch, epoch,version,release,
+- checksum)
++ checksum, history)
+ self.done = None
+ self.state = state
+
+- self.repoid = '<history>'
+-
+
+-class YumHistoryRpmdbProblem(PackageObject):
++class YumHistoryRpmdbProblem:
+ """ Class representing an rpmdb problem that existed at the time of the
+ transaction. """
+
+@@ -328,7 +425,8 @@ class YumMergedHistoryTransaction(YumHistoryTransaction):
+ @staticmethod
+ def _conv_pkg_state(pkg, state):
+ npkg = YumHistoryPackageState(pkg.name, pkg.arch,
+- pkg.epoch,pkg.version,pkg.release, state)
++ pkg.epoch,pkg.version,pkg.release, state,
++ pkg._history)
+ npkg._checksums = pkg._checksums
+ npkg.done = pkg.done
+ if _sttxt2stcode[npkg.state] in TS_INSTALL_STATES:
+@@ -557,7 +655,7 @@ class YumMergedHistoryTransaction(YumHistoryTransaction):
+ class YumHistory:
+ """ API for accessing the history sqlite data. """
+
+- def __init__(self, root='/', db_path=_history_dir):
++ def __init__(self, root='/', db_path=_history_dir, releasever=None):
+ self._conn = None
+
+ self.conf = yum.misc.GenericHolder()
+@@ -568,6 +666,8 @@ class YumHistory:
+ self.conf.writable = False
+ self.conf.readable = True
+
++ self.releasever = releasever
++
+ if not os.path.exists(self.conf.db_path):
+ try:
+ os.makedirs(self.conf.db_path)
+@@ -644,7 +744,7 @@ class YumHistory:
+ self._conn.close()
+ self._conn = None
+
+- def _pkgtup2pid(self, pkgtup, checksum=None):
++ def _pkgtup2pid(self, pkgtup, checksum=None, create=True):
+ cur = self._get_cursor()
+ executeSQL(cur, """SELECT pkgtupid, checksum FROM pkgtups
+ WHERE name=? AND arch=? AND
+@@ -659,6 +759,9 @@ class YumHistory:
+ if checksum == sql_checksum:
+ return sql_pkgtupid
+
++ if not create:
++ return None
++
+ (n,a,e,v,r) = pkgtup
+ (n,a,e,v,r) = (to_unicode(n),to_unicode(a),
+ to_unicode(e),to_unicode(v),to_unicode(r))
+@@ -674,23 +777,28 @@ class YumHistory:
+ (name, arch, epoch, version, release)
+ VALUES (?, ?, ?, ?, ?)""", (n,a,e,v,r))
+ return cur.lastrowid
+- def _apkg2pid(self, po):
++ def _apkg2pid(self, po, create=True):
+ 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):
++ return self._pkgtup2pid(po.pkgtup, csum, create)
++ def _ipkg2pid(self, po, create=True):
+ csum = None
+ yumdb = po.yumdb_info
+ if 'checksum_type' in yumdb and 'checksum_data' in yumdb:
+ csum = "%s:%s" % (yumdb.checksum_type, yumdb.checksum_data)
+- return self._pkgtup2pid(po.pkgtup, csum)
+- def pkg2pid(self, po):
++ return self._pkgtup2pid(po.pkgtup, csum, create)
++ def _hpkg2pid(self, po, create=False):
++ return self._apkg2pid(po, create)
++
++ def pkg2pid(self, po, create=True):
+ if isinstance(po, YumInstalledPackage):
+- return self._ipkg2pid(po)
++ return self._ipkg2pid(po, create)
+ if isinstance(po, YumAvailablePackage):
+- return self._apkg2pid(po)
+- return self._pkgtup2pid(po.pkgtup, None)
++ return self._apkg2pid(po, create)
++ if isinstance(po, YumHistoryPackage):
++ return self._hpkg2pid(po, create)
++ return self._pkgtup2pid(po.pkgtup, None, create)
+
+ @staticmethod
+ def txmbr2state(txmbr):
+@@ -984,7 +1092,8 @@ class YumHistory:
+ 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])
++ obj = YumHistoryPackage(row[0],row[1],row[2],row[3],row[4], row[5],
++ history=self)
+ ret.append(obj)
+ return ret
+ def _old_data_pkgs(self, tid):
+@@ -998,7 +1107,7 @@ class YumHistory:
+ ret = []
+ for row in cur:
+ obj = YumHistoryPackageState(row[0],row[1],row[2],row[3],row[4],
+- row[7], row[5])
++ row[7], row[5], history=self)
+ obj.done = row[6] == 'TRUE'
+ obj.state_installed = None
+ if _sttxt2stcode[obj.state] in TS_INSTALL_STATES:
+@@ -1018,7 +1127,8 @@ class YumHistory:
+ 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])
++ obj = YumHistoryPackage(row[0],row[1],row[2],row[3],row[4], row[5],
++ history=self)
+ ret.append(obj)
+ return ret
+ def _old_prob_pkgs(self, rpid):
+@@ -1032,7 +1142,8 @@ class YumHistory:
+ ORDER BY name ASC, epoch ASC""", (rpid,))
+ ret = []
+ for row in cur:
+- obj = YumHistoryPackage(row[0],row[1],row[2],row[3],row[4], row[5])
++ obj = YumHistoryPackage(row[0],row[1],row[2],row[3],row[4], row[5],
++ history=self)
+ obj.main = row[6] == 'TRUE'
+ ret.append(obj)
+ return ret
+@@ -1151,6 +1262,123 @@ class YumHistory:
+ assert len(ret) == 1
+ return ret[0]
+
++ def _load_anydb_key(self, pkg, db, attr):
++ cur = self._get_cursor()
++ if cur is None or not self._update_db_file_3():
++ return None
++
++ pid = self.pkg2pid(pkg, create=False)
++ if pid is None:
++ return None
++
++ sql = """SELECT %(db)sdb_val FROM pkg_%(db)sdb
++ WHERE pkgtupid=? and %(db)sdb_key=? """ % {'db' : db}
++ executeSQL(cur, sql, (pid, attr))
++ for row in cur:
++ return row[0]
++
++ return None
++
++ def _load_rpmdb_key(self, pkg, attr):
++ return self._load_anydb_key(pkg, "rpm", attr)
++ def _load_yumdb_key(self, pkg, attr):
++ return self._load_anydb_key(pkg, "yum", attr)
++
++ def _save_anydb_key(self, pkg, db, attr, val):
++ cur = self._get_cursor()
++ if cur is None or not self._update_db_file_3():
++ return None
++
++ pid = self.pkg2pid(pkg, create=False)
++ if pid is None:
++ return None
++
++ sql = """INSERT INTO pkg_%(db)sdb (pkgtupid, %(db)sdb_key, %(db)sdb_val)
++ VALUES (?, ?, ?)""" % {'db' : db}
++ executeSQL(cur, sql, (pid, attr, val))
++ for row in cur:
++ return row[0]
++
++ return None
++
++ def _save_rpmdb_key(self, pkg, attr, val):
++ return self._save_anydb_key(pkg, "rpm", attr, val)
++ def _save_yumdb_key(self, pkg, attr, val):
++ return self._save_anydb_key(pkg, "yum", attr, val)
++
++ def _save_rpmdb(self, ipkg):
++ """ Save all the data for rpmdb for this installed pkg, assumes
++ there is no data currently. """
++ for attr in YumHistoryPackage._valid_rpmdb_keys:
++ val = getattr(ipkg, attr, None)
++ if val is None:
++ continue
++ self._save_anydb_key(ipkg, "rpm", attr, val)
++
++ def _save_yumdb(self, ipkg):
++ """ Save all the data for yumdb for this installed pkg, assumes
++ there is no data currently. """
++ for attr in _YumHistPackageYumDB._valid_yumdb_keys:
++ val = ipkg.yumdb_info.get(attr)
++ if val is None:
++ continue
++ self._save_anydb_key(ipkg, "yum", attr, val)
++
++ def _wipe_anydb(self, pkg, db):
++ """ Delete all the data for rpmdb/yumdb for this installed pkg. """
++ cur = self._get_cursor()
++ if cur is None or not self._update_db_file_3():
++ return False
++
++ pid = self.pkg2pid(pkg, create=False)
++ if pid is None:
++ return False
++
++ sql = """DELETE FROM pkg_%(db)sdb WHERE pkgtupid=?""" % {'db' : db}
++ executeSQL(cur, sql, (pid,))
++
++ return True
++
++ def sync_alldb(self, ipkg):
++ """ Sync. all the data for rpmdb/yumdb for this installed pkg. """
++ if not self._wipe_anydb(ipkg, "rpm"):
++ return False
++ self._wipe_anydb(ipkg, "yum")
++ if not self._save_rpmdb(ipkg):
++ return False
++ self._save_yumdb(ipkg)
++ self._commit()
++ return True
++
++ def _pkg_stats(self):
++ """ Some stats about packages in the DB. """
++
++ ret = {'nevrac' : 0,
++ 'nevra' : 0,
++ 'nevr' : 0,
++ 'na' : 0,
++ 'rpmdb' : 0,
++ 'yumdb' : 0,
++ }
++ cur = self._get_cursor()
++ if cur is None or not self._update_db_file_3():
++ return False
++
++ data = (('nevrac', "COUNT(*)", "pkgtups"),
++ ('na', "COUNT(DISTINCT(name || arch))", "pkgtups"),
++ ('nevra',"COUNT(DISTINCT(name||version||epoch||release||arch))",
++ "pkgtups"),
++ ('nevr', "COUNT(DISTINCT(name||version||epoch||release))",
++ "pkgtups"),
++ ('rpmdb', "COUNT(DISTINCT(pkgtupid))", "pkg_rpmdb"),
++ ('yumdb', "COUNT(DISTINCT(pkgtupid))", "pkg_yumdb"))
++
++ for key, bsql, esql in data:
++ executeSQL(cur, "SELECT %s FROM %s" % (bsql, esql))
++ for row in cur:
++ ret[key] = row[0]
++ return ret
++
+ def _yieldSQLDataList(self, patterns, fields, ignore_case):
+ """Yields all the package data for the given params. """
+
+@@ -1220,6 +1448,47 @@ class YumHistory:
+ tids.add(row[0])
+ return tids
+
++ _update_ops_3 = ['''\
++\
++ CREATE TABLE pkg_rpmdb (
++ pkgtupid INTEGER NOT NULL REFERENCES pkgtups,
++ rpmdb_key TEXT NOT NULL,
++ rpmdb_val TEXT NOT NULL);
++''', '''\
++ CREATE INDEX i_pkgkey_rpmdb ON pkg_rpmdb (pkgtupid, rpmdb_key);
++''', '''\
++ CREATE TABLE pkg_yumdb (
++ pkgtupid INTEGER NOT NULL REFERENCES pkgtups,
++ yumdb_key TEXT NOT NULL,
++ yumdb_val TEXT NOT NULL);
++''', '''\
++ CREATE INDEX i_pkgkey_yumdb ON pkg_yumdb (pkgtupid, yumdb_key);
++''']
++
++ def _update_db_file_3(self):
++ """ Update to version 3 of history, rpmdb/yumdb data. """
++ if not self._update_db_file_2():
++ return False
++
++ if hasattr(self, '_cached_updated_3'):
++ return self._cached_updated_3
++
++ cur = self._get_cursor()
++ if cur is None:
++ return False
++
++ executeSQL(cur, "PRAGMA table_info(pkg_yumdb)")
++ # If we get anything, we're fine. There might be a better way of
++ # saying "anything" but this works.
++ for ob in cur:
++ break
++ else:
++ for op in self._update_ops_3:
++ cur.execute(op)
++ self._commit()
++ self._cached_updated_3 = True
++ return True
++
+ _update_ops_2 = ['''\
+ \
+ CREATE TABLE trans_skip_pkgs (
+@@ -1374,6 +1643,8 @@ class YumHistory:
+ cur.execute(op)
+ for op in self._update_ops_2:
+ cur.execute(op)
++ for op in self._update_ops_3:
++ cur.execute(op)
+ self._commit()
+
+ # Pasted from sqlitesack
diff --git a/yum/misc.py b/yum/misc.py
index 2f6ddfe..37c572b 100644
--- a/yum/misc.py
@@ -6136,10 +6932,25 @@ index 2f6ddfe..37c572b 100644
def _getloginuid():
""" Get the audit-uid/login-uid, if available. None is returned if there
diff --git a/yum/packages.py b/yum/packages.py
-index 5ef9951..79c15db 100644
+index 5ef9951..f72c068 100644
--- a/yum/packages.py
+++ b/yum/packages.py
-@@ -1083,7 +1083,7 @@ class YumAvailablePackage(PackageObject, RpmBase):
+@@ -271,6 +271,14 @@ class PackageObject(object):
+ return out
+ ui_nevra = property(fget=lambda self: self._ui_nevra())
+
++ def _ui_evr(self):
++ if self.epoch == '0':
++ out = '%s-%s' % (self.version, self.release)
++ else:
++ out = '%s:%s-%s' % (self.epoch, self.version, self.release)
++ return out
++ ui_evr = property(fget=lambda self: self._ui_evr())
++
+ def __str__(self):
+ return self.ui_envra
+
+@@ -1083,7 +1091,7 @@ class YumAvailablePackage(PackageObject, RpmBase):
misc.to_unicode(misc.to_xml(self.summary)),
misc.to_unicode(misc.to_xml(self.description)),
packager, url, self.filetime,
@@ -6148,7 +6959,7 @@ index 5ef9951..79c15db 100644
msg += self._return_remote_location()
return msg
-@@ -1133,7 +1133,7 @@ class YumAvailablePackage(PackageObject, RpmBase):
+@@ -1133,7 +1141,7 @@ class YumAvailablePackage(PackageObject, RpmBase):
msg = ""
mylist = getattr(self, pcotype)
if mylist: msg = "\n <rpm:%s>\n" % pcotype
@@ -6157,7 +6968,7 @@ index 5ef9951..79c15db 100644
pcostring = ''' <rpm:entry name="%s"''' % misc.to_xml(name, attrib=True)
if flags:
pcostring += ''' flags="%s"''' % misc.to_xml(flags, attrib=True)
-@@ -1161,11 +1161,11 @@ class YumAvailablePackage(PackageObject, RpmBase):
+@@ -1161,11 +1169,11 @@ class YumAvailablePackage(PackageObject, RpmBase):
dirs = self.returnFileEntries('dir', primary_only=True)
ghosts = self.returnFileEntries('ghost', primary_only=True)
@@ -6172,7 +6983,7 @@ index 5ef9951..79c15db 100644
msg += """ <file type="ghost">%s</file>\n""" % misc.to_xml(fn)
return msg
-@@ -1194,8 +1194,8 @@ class YumAvailablePackage(PackageObject, RpmBase):
+@@ -1194,8 +1202,8 @@ class YumAvailablePackage(PackageObject, RpmBase):
continue
newlist.append(i)
mylist = newlist
@@ -6183,7 +6994,7 @@ index 5ef9951..79c15db 100644
if name.startswith('rpmlib('):
continue
# this drops out requires that the pkg provides for itself.
-@@ -1217,13 +1217,16 @@ class YumAvailablePackage(PackageObject, RpmBase):
+@@ -1217,13 +1225,16 @@ class YumAvailablePackage(PackageObject, RpmBase):
prcostring += ''' ver="%s"''' % misc.to_xml(v, attrib=True)
if r:
prcostring += ''' rel="%s"''' % misc.to_xml(r, attrib=True)
@@ -6202,7 +7013,7 @@ index 5ef9951..79c15db 100644
return msg
def _dump_changelog(self, clog_limit):
-@@ -1299,7 +1302,8 @@ class YumHeaderPackage(YumAvailablePackage):
+@@ -1299,7 +1310,8 @@ class YumHeaderPackage(YumAvailablePackage):
self.pkgid = self.hdr[rpm.RPMTAG_SHA1HEADER]
if not self.pkgid:
self.pkgid = "%s.%s" %(self.hdr['name'], self.hdr['buildtime'])
@@ -6304,7 +7115,7 @@ index 8a6f6f3..19193ad 100644
prco_set = (_share_data(ob['name']), _share_data(ob['flags']),
(_share_data(ob['epoch']),
diff --git a/yumcommands.py b/yumcommands.py
-index 4dcbea7..3a985c3 100644
+index 4dcbea7..d9c70f3 100644
--- a/yumcommands.py
+++ b/yumcommands.py
@@ -43,16 +43,22 @@ def _err_mini_usage(base, basecmd):
@@ -7968,9 +8779,40 @@ index 4dcbea7..3a985c3 100644
return _("Display, or use, the transaction history")
def _hcmd_redo(self, base, extcmds):
-@@ -1427,6 +2426,14 @@ class HistoryCommand(YumCommand):
+@@ -1426,12 +2425,52 @@ class HistoryCommand(YumCommand):
+ def _hcmd_new(self, base, extcmds):
base.history._create_db_file()
++ def _hcmd_stats(self, base, extcmds):
++ print "File :", base.history._db_file
++ num = os.stat(base.history._db_file).st_size
++ print "Size :", locale.format("%d", num, True)
++ counts = base.history._pkg_stats()
++ trans_1 = base.history.old("1")[0]
++ trans_N = base.history.last()
++ print _("Transactions:"), trans_N.tid
++ print _("Begin time :"), time.ctime(trans_1.beg_timestamp)
++ print _("End time :"), time.ctime(trans_N.end_timestamp)
++ print _("Counts :")
++ print _(" NEVRAC :"), locale.format("%6d", counts['nevrac'], True)
++ print _(" NEVRA :"), locale.format("%6d", counts['nevra'], True)
++ print _(" NA :"), locale.format("%6d", counts['na'], True)
++ print _(" NEVR :"), locale.format("%6d", counts['nevr'], True)
++ print _(" rpm DB :"), locale.format("%6d", counts['rpmdb'], True)
++ print _(" yum DB :"), locale.format("%6d", counts['yumdb'], True)
++
++ def _hcmd_sync(self, base, extcmds):
++ extcmds = extcmds[1:]
++ if not extcmds:
++ extcmds = None
++ for ipkg in sorted(base.rpmdb.returnPackages(patterns=extcmds)):
++ if base.history.pkg2pid(ipkg, create=False) is None:
++ continue
++
++ print "Syncing rpm/yum DB data for:", ipkg, "...",
++ base.history.sync_alldb(ipkg)
++ print "Done."
++
def doCheck(self, base, basecmd, extcmds):
+ """Verify that conditions are met so that this command can
+ run. The exact conditions checked will vary depending on the
@@ -7983,7 +8825,15 @@ index 4dcbea7..3a985c3 100644
cmds = ('list', 'info', 'summary', 'repeat', 'redo', 'undo', 'new',
'rollback',
'addon', 'addon-info',
-@@ -1444,6 +2451,19 @@ class HistoryCommand(YumCommand):
++ 'stats', 'statistics', 'sync', 'synchronize'
+ 'pkg', 'pkgs', 'pkg-list', 'pkgs-list',
+- 'package', 'package-list', 'packages', 'packages-list')
++ 'package', 'package-list', 'packages', 'packages-list',
++ 'pkg-info', 'pkgs-info', 'package-info', 'packages-info')
+ if extcmds and extcmds[0] not in cmds:
+ base.logger.critical(_('Invalid history sub-command, use: %s.'),
+ ", ".join(cmds))
+@@ -1444,6 +2483,19 @@ class HistoryCommand(YumCommand):
raise cli.CliError
def doCommand(self, base, basecmd, extcmds):
@@ -8003,7 +8853,19 @@ index 4dcbea7..3a985c3 100644
vcmd = 'list'
if extcmds:
vcmd = extcmds[0]
-@@ -1474,6 +2494,14 @@ class HistoryCommand(YumCommand):
+@@ -1468,12 +2520,26 @@ class HistoryCommand(YumCommand):
+ ret = self._hcmd_rollback(base, extcmds)
+ elif vcmd == 'new':
+ ret = self._hcmd_new(base, extcmds)
++ elif vcmd in ('stats', 'statistics'):
++ ret = self._hcmd_stats(base, extcmds)
++ elif vcmd in ('sync', 'synchronize'):
++ ret = self._hcmd_sync(base, extcmds)
++ elif vcmd in ('pkg-info', 'pkgs-info', 'package-info', 'packages-info'):
++ ret = base.historyPackageInfoCmd(extcmds)
+
+ if ret is None:
+ return 0, ['history %s' % (vcmd,)]
return ret
def needTs(self, base, basecmd, extcmds):
@@ -8018,7 +8880,7 @@ index 4dcbea7..3a985c3 100644
vcmd = 'list'
if extcmds:
vcmd = extcmds[0]
-@@ -1481,16 +2509,46 @@ class HistoryCommand(YumCommand):
+@@ -1481,16 +2547,46 @@ class HistoryCommand(YumCommand):
class CheckRpmdbCommand(YumCommand):
@@ -8065,7 +8927,7 @@ index 4dcbea7..3a985c3 100644
chkcmd = 'all'
if extcmds:
chkcmd = extcmds
-@@ -1505,19 +2563,57 @@ class CheckRpmdbCommand(YumCommand):
+@@ -1505,19 +2601,57 @@ class CheckRpmdbCommand(YumCommand):
return rc, ['%s %s' % (basecmd, chkcmd)]
def needTs(self, base, basecmd, extcmds):
@@ -8123,7 +8985,7 @@ index 4dcbea7..3a985c3 100644
if not extcmds:
base.logger.critical(_("No saved transaction file specified."))
raise cli.CliError
-@@ -1533,5 +2629,13 @@ class LoadTransactionCommand(YumCommand):
+@@ -1533,5 +2667,13 @@ class LoadTransactionCommand(YumCommand):
def needTs(self, base, basecmd, extcmds):
diff --git a/yum.spec b/yum.spec
index a950fd6..324a0c5 100644
--- a/yum.spec
+++ b/yum.spec
@@ -17,7 +17,7 @@
Summary: RPM package installer/updater/manager
Name: yum
Version: 3.4.3
-Release: 5%{?dist}
+Release: 6%{?dist}
License: GPLv2+
Group: System Environment/Base
Source0: http://yum.baseurl.org/download/3.4/%{name}-%{version}.tar.gz
@@ -310,6 +310,13 @@ exit 0
%endif
%changelog
+* Fri Aug 5 2011 James Antill <james at fedoraproject.org> - 3.4.3-6
+- update to latest HEAD
+- Add new yum DB data.
+- Add hack to workaround broken python readline in yum shell.
+- Make "yum -q history addon-info last saved_tx" valid input for load-ts.
+- Add "history packages-info/stats/sync" sub-commnands.
+
* Fri Jul 29 2011 James Antill <james at fedoraproject.org> - 3.4.3-5
- update to latest HEAD
- Lots of really minor changes. Docs. and yum-cron mainly.
More information about the scm-commits
mailing list