Here's my first go at the rpm transaction callback as part of the yum
module. I've made a display callback which I think adequately covers the
needs of a callback but please let me know if it doesn't.
rpmtrans.py is the file - just drop it in your yum/ subdir of a git
checkout
ts-test.py is just something I was using to test it and kinda play
around a bit.
the SimpleCliCallBack was just enough for me to know it was working and
have it make some sense out of what I was seeing. It, clearly, should be
enhanced.
however we should just be able to provide a TransactionDisplayCallback
in output.py which we pass in for the yum cli.
-sv
#!/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 2005 Duke University
# Parts Copyright 2007 Red Hat, Inc
import rpm
import os
import sys
import logging
from yum.constants import *
from i18n import _
class SimpleCliCallBack:
def __init__(self):
self.action = { TS_UPDATE : 'Updating',
TS_ERASE: 'Erasing',
TS_INSTALL: 'Installing',
TS_TRUEINSTALL : 'Installing',
TS_OBSOLETED: 'Obsoleted',
TS_OBSOLETING: 'Installing',
TS_UPDATED: 'Cleanup',
'repackaging': 'Repackaging'}
self.fileaction = { TS_UPDATE: 'Updated',
TS_ERASE: 'Erased',
TS_INSTALL: 'Installed',
TS_TRUEINSTALL: 'Installed',
TS_OBSOLETED: 'Obsoleted',
TS_OBSOLETING: 'Installed',
TS_UPDATED: 'Cleanup'}
self.lastmsg = None
self.logger = logging.getLogger('yum.filelogging.RPMInstallCallback')
self.lastpackage = None # name of last package we looked at
# for a progress bar
self.mark = "#"
self.marks = 27
def event(self, package, action, te_current, te_total, ts_current, ts_total):
# this is where a progress bar would be called
msg = '%s: %s %s/%s [%s/%s]' % (self.action[action], package,
te_current, te_total, ts_current, ts_total)
if msg != self.lastmsg:
print msg
self.lastmsg = msg
self.lastpackage = package
#if sys.stdout.isatty(): # need this for the nice progress bar output
def errorlog(self, msg):
print >> sys.stderr, msg
def filelog(self, package, action):
# check package object type - if it is a string - just output it
msg = '%s: %s' % (self.fileaction[action], package)
self.logger.info(msg)
def _logPkgString(self, package):
"""return nice representation of the package for the log"""
(n,a,e,v,r) = package.pkgtup
if e == '0':
pkg = '%s.%s %s-%s' % (n, a, v, r)
else:
pkg = '%s.%s %s:%s-%s' % (n, a, e, v, r)
return pkg
#def _makefmt(self, percent, progress = True):
#l = len(str(self.total_actions))
#size = "%s.%s" % (l, l)
#fmt_done = "[%" + size + "s/%" + size + "s]"
#done = fmt_done % (self.total_installed + self.total_removed,
#self.total_actions)
#marks = self.marks - (2 * l)
#width = "%s.%s" % (marks, marks)
#fmt_bar = "%-" + width + "s"
#if progress:
#bar = fmt_bar % (self.mark * int(marks * (percent / 100.0)), )
#fmt = "\r %-10.10s: %-28.28s " + bar + " " + done
#else:
#bar = fmt_bar % (self.mark * marks, )
#fmt = " %-10.10s: %-28.28s " + bar + " " + done
#return fmt
class RPMTransaction:
def __init__(self, tsInfo, display=SimpleCliCallBack):
self.display = display()
self.tsInfo = tsInfo
self.filehandles = {}
self.total_actions = 0
self.total_installed = 0
self.complete_actions = 0
self.installed_pkg_names = []
self.total_removed = 0
self.logger = logging.getLogger('yum.filelogging.RPMInstallCallback')
self.filelog = False
def _dopkgtup(self, hdr):
tmpepoch = hdr['epoch']
if tmpepoch is None: epoch = '0'
else: epoch = str(tmpepoch)
return (hdr['name'], hdr['arch'], epoch, hdr['version'], hdr['release'])
def _makeHandle(self, hdr):
handle = '%s:%s.%s-%s-%s' % (hdr['epoch'], hdr['name'], hdr['version'],
hdr['release'], hdr['arch'])
return handle
def callback(self, what, bytes, total, h, user):
if what == rpm.RPMCALLBACK_TRANS_START:
if bytes == 6:
self.total_actions = total
elif what == rpm.RPMCALLBACK_TRANS_PROGRESS:
pass
elif what == rpm.RPMCALLBACK_TRANS_STOP:
pass
elif what == rpm.RPMCALLBACK_INST_OPEN_FILE:
self.lastmsg = None
hdr = None
if h is not None:
hdr, rpmloc = h
handle = self._makeHandle(hdr)
fd = os.open(rpmloc, os.O_RDONLY)
self.filehandles[handle]=fd
self.total_installed += 1
self.complete_actions += 1
self.installed_pkg_names.append(hdr['name'])
return fd
else:
self.display.errorlog(_("Error: No Header to INST_OPEN_FILE"))
elif what == rpm.RPMCALLBACK_INST_CLOSE_FILE:
hdr = None
if h is not None:
hdr, rpmloc = h
handle = self._makeHandle(hdr)
os.close(self.filehandles[handle])
fd = 0
# log stuff
pkgtup = self._dopkgtup(hdr)
txmbrs = self.tsInfo.getMembers(pkgtup=pkgtup)
for txmbr in txmbrs:
self.display.filelog(txmbr.po, txmbr.output_state)
elif what == rpm.RPMCALLBACK_INST_PROGRESS:
if h is not None:
# If h is a string, we're repackaging.
# Why the RPMCALLBACK_REPACKAGE_PROGRESS flag isn't set, I have no idea
if type(h) == type(""):
self.display.event(h, 'repackaging', bytes, total,
self.complete_actions, self.total_actions)
else:
hdr, rpmloc = h
pkgtup = self._dopkgtup(hdr)
txmbrs = self.tsInfo.getMembers(pkgtup=pkgtup)
for txmbr in txmbrs:
action = txmbr.output_state
self.display.event(txmbr.po, action, bytes, total,
self.complete_actions, self.total_actions)
elif what == rpm.RPMCALLBACK_UNINST_START:
pass
elif what == rpm.RPMCALLBACK_UNINST_PROGRESS:
pass
elif what == rpm.RPMCALLBACK_UNINST_STOP:
self.total_removed += 1
self.complete_actions += 1
if h not in self.installed_pkg_names:
self.display.filelog(h, TS_ERASE)
action = TS_OBSOLETED
else:
action = TS_UPDATED
self.display.event(h, action, 100, 100, self.complete_actions,
self.total_actions)
elif what == rpm.RPMCALLBACK_REPACKAGE_START:
pass
elif what == rpm.RPMCALLBACK_REPACKAGE_STOP:
pass
elif what == rpm.RPMCALLBACK_REPACKAGE_PROGRESS:
pass
#!/usr/bin/python
import yum
from yum.rpmtrans import RPMTransaction, SimpleCliCallBack
from yum.constants import *
import sys
my = yum.YumBase()
my.update(name='yum-utils')
my.buildTransaction()
print 'cb here'
mycb = RPMTransaction(my.tsInfo, display=SimpleCliCallBack)
print 'after cb'
downloadpkgs = map(lambda txmbr: txmbr.po,
my.tsInfo.getMembersWithState(output_states=TS_INSTALL_STATES))
problems = my.downloadPkgs(downloadpkgs)
del my.ts
my.initActionTs() # make a new, blank ts to populate
my.populateTs(keepold=0) # populate the ts
my.ts.check() #required for ordering
my.ts.order() # order
errors = my.ts.run(mycb.callback, '')
if errors:
print errors
_______________________________________________
Yum-devel mailing list
[email protected]
https://lists.dulug.duke.edu/mailman/listinfo/yum-devel