| 1 | #!/usr/bin/python -t
|
|---|
| 2 | # This program is free software; you can redistribute it and/or modify
|
|---|
| 3 | # it under the terms of the GNU General Public License as published by
|
|---|
| 4 | # the Free Software Foundation; either version 2 of the License, or
|
|---|
| 5 | # (at your option) any later version.
|
|---|
| 6 | #
|
|---|
| 7 | # This program is distributed in the hope that it will be useful,
|
|---|
| 8 | # but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|---|
| 9 | # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
|---|
| 10 | # GNU Library General Public License for more details.
|
|---|
| 11 | #
|
|---|
| 12 | # You should have received a copy of the GNU General Public License
|
|---|
| 13 | # along with this program; if not, write to the Free Software
|
|---|
| 14 | # Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
|
|---|
| 15 | # Copyright 2005 Duke University
|
|---|
| 16 |
|
|---|
| 17 | """
|
|---|
| 18 | Progress display callback classes for the yum command line.
|
|---|
| 19 | """
|
|---|
| 20 |
|
|---|
| 21 | import rpm
|
|---|
| 22 | import os
|
|---|
| 23 | import sys
|
|---|
| 24 | import logging
|
|---|
| 25 | from yum import _
|
|---|
| 26 | from yum.constants import *
|
|---|
| 27 |
|
|---|
| 28 |
|
|---|
| 29 | class RPMInstallCallback:
|
|---|
| 30 |
|
|---|
| 31 | """
|
|---|
| 32 | Yum command line callback class for callbacks from the RPM library.
|
|---|
| 33 | """
|
|---|
| 34 |
|
|---|
| 35 | def __init__(self, output=1):
|
|---|
| 36 | self.output = output
|
|---|
| 37 | self.callbackfilehandles = {}
|
|---|
| 38 | self.total_actions = 0
|
|---|
| 39 | self.total_installed = 0
|
|---|
| 40 | self.installed_pkg_names = []
|
|---|
| 41 | self.total_removed = 0
|
|---|
| 42 | self.mark = "#"
|
|---|
| 43 | self.marks = 27
|
|---|
| 44 | self.lastmsg = None
|
|---|
| 45 | self.logger = logging.getLogger('yum.filelogging.RPMInstallCallback')
|
|---|
| 46 | self.filelog = False
|
|---|
| 47 |
|
|---|
| 48 | self.myprocess = { TS_UPDATE : _('Updating'),
|
|---|
| 49 | TS_ERASE: _('Erasing'),
|
|---|
| 50 | TS_INSTALL: _('Installing'),
|
|---|
| 51 | TS_TRUEINSTALL : _('Installing'),
|
|---|
| 52 | TS_OBSOLETED: _('Obsoleted'),
|
|---|
| 53 | TS_OBSOLETING: _('Installing')}
|
|---|
| 54 | self.mypostprocess = { TS_UPDATE: _('Updated'),
|
|---|
| 55 | TS_ERASE: _('Erased'),
|
|---|
| 56 | TS_INSTALL: _('Installed'),
|
|---|
| 57 | TS_TRUEINSTALL: _('Installed'),
|
|---|
| 58 | TS_OBSOLETED: _('Obsoleted'),
|
|---|
| 59 | TS_OBSOLETING: _('Installed')}
|
|---|
| 60 |
|
|---|
| 61 | self.tsInfo = None # this needs to be set for anything else to work
|
|---|
| 62 |
|
|---|
| 63 | def _dopkgtup(self, hdr):
|
|---|
| 64 | tmpepoch = hdr['epoch']
|
|---|
| 65 | if tmpepoch is None: epoch = '0'
|
|---|
| 66 | else: epoch = str(tmpepoch)
|
|---|
| 67 |
|
|---|
| 68 | return (hdr['name'], hdr['arch'], epoch, hdr['version'], hdr['release'])
|
|---|
| 69 |
|
|---|
| 70 | def _makeHandle(self, hdr):
|
|---|
| 71 | handle = '%s:%s.%s-%s-%s' % (hdr['epoch'], hdr['name'], hdr['version'],
|
|---|
| 72 | hdr['release'], hdr['arch'])
|
|---|
| 73 |
|
|---|
| 74 | return handle
|
|---|
| 75 |
|
|---|
| 76 | def _localprint(self, msg):
|
|---|
| 77 | if self.output:
|
|---|
| 78 | print msg
|
|---|
| 79 |
|
|---|
| 80 | def _makefmt(self, percent, progress = True):
|
|---|
| 81 | l = len(str(self.total_actions))
|
|---|
| 82 | size = "%s.%s" % (l, l)
|
|---|
| 83 | fmt_done = "[%" + size + "s/%" + size + "s]"
|
|---|
| 84 | done = fmt_done % (self.total_installed + self.total_removed,
|
|---|
| 85 | self.total_actions)
|
|---|
| 86 | marks = self.marks - (2 * l)
|
|---|
| 87 | width = "%s.%s" % (marks, marks)
|
|---|
| 88 | fmt_bar = "%-" + width + "s"
|
|---|
| 89 | if progress:
|
|---|
| 90 | bar = fmt_bar % (self.mark * int(marks * (percent / 100.0)), )
|
|---|
| 91 | fmt = "\r %-10.10s: %-28.28s " + bar + " " + done
|
|---|
| 92 | else:
|
|---|
| 93 | bar = fmt_bar % (self.mark * marks, )
|
|---|
| 94 | fmt = " %-10.10s: %-28.28s " + bar + " " + done
|
|---|
| 95 | return fmt
|
|---|
| 96 |
|
|---|
| 97 | def _logPkgString(self, hdr):
|
|---|
| 98 | """return nice representation of the package for the log"""
|
|---|
| 99 | (n,a,e,v,r) = self._dopkgtup(hdr)
|
|---|
| 100 | if e == '0':
|
|---|
| 101 | pkg = '%s.%s %s-%s' % (n, a, v, r)
|
|---|
| 102 | else:
|
|---|
| 103 | pkg = '%s.%s %s:%s-%s' % (n, a, e, v, r)
|
|---|
| 104 |
|
|---|
| 105 | return pkg
|
|---|
| 106 |
|
|---|
| 107 | def callback(self, what, bytes, total, h, user):
|
|---|
| 108 | if what == rpm.RPMCALLBACK_TRANS_START:
|
|---|
| 109 | if bytes == 6:
|
|---|
| 110 | self.total_actions = total
|
|---|
| 111 |
|
|---|
| 112 | elif what == rpm.RPMCALLBACK_TRANS_PROGRESS:
|
|---|
| 113 | pass
|
|---|
| 114 |
|
|---|
| 115 | elif what == rpm.RPMCALLBACK_TRANS_STOP:
|
|---|
| 116 | pass
|
|---|
| 117 |
|
|---|
| 118 | elif what == rpm.RPMCALLBACK_INST_OPEN_FILE:
|
|---|
| 119 | self.lastmsg = None
|
|---|
| 120 | hdr = None
|
|---|
| 121 | if h is not None:
|
|---|
| 122 | hdr, rpmloc = h
|
|---|
| 123 | handle = self._makeHandle(hdr)
|
|---|
| 124 | fd = os.open(rpmloc, os.O_RDONLY)
|
|---|
| 125 | self.callbackfilehandles[handle]=fd
|
|---|
| 126 | self.total_installed += 1
|
|---|
| 127 | self.installed_pkg_names.append(hdr['name'])
|
|---|
| 128 | return fd
|
|---|
| 129 | else:
|
|---|
| 130 | self._localprint(_("No header - huh?"))
|
|---|
| 131 |
|
|---|
| 132 | elif what == rpm.RPMCALLBACK_INST_CLOSE_FILE:
|
|---|
| 133 | hdr = None
|
|---|
| 134 | if h is not None:
|
|---|
| 135 | hdr, rpmloc = h
|
|---|
| 136 | handle = self._makeHandle(hdr)
|
|---|
| 137 | os.close(self.callbackfilehandles[handle])
|
|---|
| 138 | fd = 0
|
|---|
| 139 |
|
|---|
| 140 | # log stuff
|
|---|
| 141 | pkgtup = self._dopkgtup(hdr)
|
|---|
| 142 |
|
|---|
| 143 | txmbrs = self.tsInfo.getMembers(pkgtup=pkgtup)
|
|---|
| 144 | for txmbr in txmbrs:
|
|---|
| 145 | try:
|
|---|
| 146 | process = self.myprocess[txmbr.output_state]
|
|---|
| 147 | processed = self.mypostprocess[txmbr.output_state]
|
|---|
| 148 | except KeyError:
|
|---|
| 149 | pass
|
|---|
| 150 |
|
|---|
| 151 | if self.filelog:
|
|---|
| 152 | pkgrep = self._logPkgString(hdr)
|
|---|
| 153 | msg = '%s: %s' % (processed, pkgrep)
|
|---|
| 154 | self.logger.info(msg)
|
|---|
| 155 |
|
|---|
| 156 |
|
|---|
| 157 | elif what == rpm.RPMCALLBACK_INST_PROGRESS:
|
|---|
| 158 | if h is not None:
|
|---|
| 159 | # If h is a string, we're repackaging.
|
|---|
| 160 | # Why the RPMCALLBACK_REPACKAGE_PROGRESS flag isn't set, I have no idea
|
|---|
| 161 | if type(h) == type(""):
|
|---|
| 162 | if total == 0:
|
|---|
| 163 | percent = 0
|
|---|
| 164 | else:
|
|---|
| 165 | percent = (bytes*100L)/total
|
|---|
| 166 | if self.output and sys.stdout.isatty():
|
|---|
| 167 | fmt = self._makefmt(percent)
|
|---|
| 168 | msg = fmt % (_('Repackage'), h)
|
|---|
| 169 | if bytes == total:
|
|---|
| 170 | msg = msg + "\n"
|
|---|
| 171 |
|
|---|
| 172 | if msg != self.lastmsg:
|
|---|
| 173 | sys.stdout.write(msg)
|
|---|
| 174 | sys.stdout.flush()
|
|---|
| 175 | self.lastmsg = msg
|
|---|
| 176 | else:
|
|---|
| 177 | hdr, rpmloc = h
|
|---|
| 178 | if total == 0:
|
|---|
| 179 | percent = 0
|
|---|
| 180 | else:
|
|---|
| 181 | percent = (bytes*100L)/total
|
|---|
| 182 | pkgtup = self._dopkgtup(hdr)
|
|---|
| 183 |
|
|---|
| 184 | txmbrs = self.tsInfo.getMembers(pkgtup=pkgtup)
|
|---|
| 185 | for txmbr in txmbrs:
|
|---|
| 186 | try:
|
|---|
| 187 | process = self.myprocess[txmbr.output_state]
|
|---|
| 188 | except KeyError, e:
|
|---|
| 189 | print _("Error: invalid output state: %s for %s") % \
|
|---|
| 190 | (txmbr.output_state, hdr['name'])
|
|---|
| 191 | else:
|
|---|
| 192 | if self.output and (sys.stdout.isatty() or bytes == total):
|
|---|
| 193 | fmt = self._makefmt(percent)
|
|---|
| 194 | msg = fmt % (process, hdr['name'])
|
|---|
| 195 | if msg != self.lastmsg:
|
|---|
| 196 | sys.stdout.write(msg)
|
|---|
| 197 | sys.stdout.flush()
|
|---|
| 198 | self.lastmsg = msg
|
|---|
| 199 | if bytes == total:
|
|---|
| 200 | print " "
|
|---|
| 201 |
|
|---|
| 202 |
|
|---|
| 203 | elif what == rpm.RPMCALLBACK_UNINST_START:
|
|---|
| 204 | pass
|
|---|
| 205 |
|
|---|
| 206 | elif what == rpm.RPMCALLBACK_UNINST_PROGRESS:
|
|---|
| 207 | pass
|
|---|
| 208 |
|
|---|
| 209 | elif what == rpm.RPMCALLBACK_UNINST_STOP:
|
|---|
| 210 | self.total_removed += 1
|
|---|
| 211 | if self.filelog and h not in self.installed_pkg_names:
|
|---|
| 212 | logmsg = _('Erased: %s' % (h))
|
|---|
| 213 | self.logger.info(logmsg)
|
|---|
| 214 |
|
|---|
| 215 | if self.output and sys.stdout.isatty():
|
|---|
| 216 | if h not in self.installed_pkg_names:
|
|---|
| 217 | process = _("Removing")
|
|---|
| 218 | else:
|
|---|
| 219 | process = _("Cleanup")
|
|---|
| 220 | percent = 100
|
|---|
| 221 | fmt = self._makefmt(percent, False)
|
|---|
| 222 | msg = fmt % (process, h)
|
|---|
| 223 | sys.stdout.write(msg + "\n")
|
|---|
| 224 | sys.stdout.flush()
|
|---|
| 225 |
|
|---|
| 226 | elif what == rpm.RPMCALLBACK_REPACKAGE_START:
|
|---|
| 227 | pass
|
|---|
| 228 | elif what == rpm.RPMCALLBACK_REPACKAGE_STOP:
|
|---|
| 229 | pass
|
|---|
| 230 | elif what == rpm.RPMCALLBACK_REPACKAGE_PROGRESS:
|
|---|
| 231 | pass
|
|---|
| 232 |
|
|---|