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

Reply via email to