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 |
|
---|