source: yum/trunk/utils.py@ 1569

Last change on this file since 1569 was 516, checked in by Yuri Dario, 11 years ago

yum: update trunk to 3.4.3.

  • Property svn:eol-style set to native
File size: 13.7 KB
Line 
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
16import sys
17import time
18import exceptions
19
20import yum
21from cli import *
22from yum import Errors
23from yum import _
24from yum.i18n import utf8_width
25from yum import logginglevels
26from optparse import OptionGroup
27
28import yum.plugins as plugins
29from urlgrabber.progress import format_number
30
31def suppress_keyboard_interrupt_message():
32 old_excepthook = sys.excepthook
33
34 def new_hook(type, value, traceback):
35 if type != exceptions.KeyboardInterrupt:
36 old_excepthook(type, value, traceback)
37 else:
38 pass
39
40 sys.excepthook = new_hook
41
42def jiffies_to_seconds(jiffies):
43 Hertz = 100 # FIXME: Hack, need to get this, AT_CLKTCK elf note *sigh*
44 return int(jiffies) / Hertz
45
46def seconds_to_ui_time(seconds):
47 if seconds >= 60 * 60 * 24:
48 return "%d day(s) %d:%02d:%02d" % (seconds / (60 * 60 * 24),
49 (seconds / (60 * 60)) % 24,
50 (seconds / 60) % 60,
51 seconds % 60)
52 if seconds >= 60 * 60:
53 return "%d:%02d:%02d" % (seconds / (60 * 60), (seconds / 60) % 60,
54 (seconds % 60))
55 return "%02d:%02d" % ((seconds / 60), seconds % 60)
56
57def get_process_info(pid):
58 if not pid:
59 return
60
61 try:
62 pid = int(pid)
63 except ValueError, e:
64 return
65
66 # Maybe true if /proc isn't mounted, or not Linux ... or something.
67 if (not os.path.exists("/proc/%d/status" % pid) or
68 not os.path.exists("/proc/stat") or
69 not os.path.exists("/proc/%d/stat" % pid)):
70 return
71
72 ps = {}
73 for line in open("/proc/%d/status" % pid):
74 if line[-1] != '\n':
75 continue
76 data = line[:-1].split(':\t', 1)
77 if len(data) < 2:
78 continue
79 if data[1].endswith(' kB'):
80 data[1] = data[1][:-3]
81 ps[data[0].strip().lower()] = data[1].strip()
82 if 'vmrss' not in ps:
83 return
84 if 'vmsize' not in ps:
85 return
86 boot_time = None
87 for line in open("/proc/stat"):
88 if line.startswith("btime "):
89 boot_time = int(line[len("btime "):-1])
90 break
91 if boot_time is None:
92 return
93 ps_stat = open("/proc/%d/stat" % pid).read().split()
94 ps['utime'] = jiffies_to_seconds(ps_stat[13])
95 ps['stime'] = jiffies_to_seconds(ps_stat[14])
96 ps['cutime'] = jiffies_to_seconds(ps_stat[15])
97 ps['cstime'] = jiffies_to_seconds(ps_stat[16])
98 ps['start_time'] = boot_time + jiffies_to_seconds(ps_stat[21])
99 ps['state'] = {'R' : _('Running'),
100 'S' : _('Sleeping'),
101 'D' : _('Uninterruptible'),
102 'Z' : _('Zombie'),
103 'T' : _('Traced/Stopped')
104 }.get(ps_stat[2], _('Unknown'))
105
106 return ps
107
108def show_lock_owner(pid, logger):
109 ps = get_process_info(pid)
110 if not ps:
111 return None
112
113 # This yumBackend isn't very friendly, so...
114 if ps['name'] == 'yumBackend.py':
115 nmsg = _(" The other application is: PackageKit")
116 else:
117 nmsg = _(" The other application is: %s") % ps['name']
118
119 logger.critical("%s", nmsg)
120 logger.critical(_(" Memory : %5s RSS (%5sB VSZ)") %
121 (format_number(int(ps['vmrss']) * 1024),
122 format_number(int(ps['vmsize']) * 1024)))
123
124 ago = seconds_to_ui_time(int(time.time()) - ps['start_time'])
125 logger.critical(_(" Started: %s - %s ago") %
126 (time.ctime(ps['start_time']), ago))
127 logger.critical(_(" State : %s, pid: %d") % (ps['state'], pid))
128
129 return ps
130
131
132def exception2msg(e):
133 """ DIE python DIE! Which one works:
134 to_unicode(e.value); unicode(e); str(e);
135 Call this so you don't have to care. """
136 try:
137 return to_unicode(e.value)
138 except:
139 pass
140
141 try:
142 return unicode(e)
143 except:
144 pass
145
146 try:
147 return str(e)
148 except:
149 pass
150 return "<exception failed to convert to text>"
151
152
153class YumUtilBase(YumBaseCli):
154 def __init__(self,name,ver,usage):
155 YumBaseCli.__init__(self)
156 self._parser = YumOptionParser(base=self,utils=True,usage=usage)
157 self._usage = usage
158 self._utilName = name
159 self._utilVer = ver
160 self._option_group = OptionGroup(self._parser, "%s options" % self._utilName,"")
161 self._parser.add_option_group(self._option_group)
162 suppress_keyboard_interrupt_message()
163 logger = logging.getLogger("yum.util")
164 verbose_logger = logging.getLogger("yum.verbose.util")
165 # Add yum-utils version to history records.
166 if hasattr(self, 'run_with_package_names'):
167 self.run_with_package_names.add("yum-utils")
168
169 def exUserCancel(self):
170 self.logger.critical(_('\n\nExiting on user cancel'))
171 if self.unlock(): return 200
172 return 1
173
174 def exIOError(self, e):
175 if e.errno == 32:
176 self.logger.critical(_('\n\nExiting on Broken Pipe'))
177 else:
178 self.logger.critical(_('\n\n%s') % exception2msg(e))
179 if self.unlock(): return 200
180 return 1
181
182 def exPluginExit(self, e):
183 '''Called when a plugin raises PluginYumExit.
184
185 Log the plugin's exit message if one was supplied.
186 ''' # ' xemacs hack
187 exitmsg = exception2msg(e)
188 if exitmsg:
189 self.logger.warn('\n\n%s', exitmsg)
190 if self.unlock(): return 200
191 return 1
192
193 def exFatal(self, e):
194 self.logger.critical('\n\n%s', exception2msg(e))
195 if self.unlock(): return 200
196 return 1
197
198 def unlock(self):
199 try:
200 self.closeRpmDB()
201 self.doUnlock()
202 except Errors.LockError, e:
203 return 200
204 return 0
205
206
207 def getOptionParser(self):
208 return self._parser
209
210 def getOptionGroup(self):
211 """ Get an option group to add non inherited options"""
212 return self._option_group
213
214 def waitForLock(self):
215 lockerr = ""
216 while True:
217 try:
218 self.doLock()
219 except Errors.LockError, e:
220 if exception2msg(e) != lockerr:
221 lockerr = exception2msg(e)
222 self.logger.critical(lockerr)
223 if not self.conf.exit_on_lock:
224 self.logger.critical("Another app is currently holding the yum lock; waiting for it to exit...")
225 show_lock_owner(e.pid, self.logger)
226 time.sleep(2)
227 else:
228 raise Errors.YumBaseError, _("Another app is currently holding the yum lock; exiting as configured by exit_on_lock")
229 else:
230 break
231
232 def _printUtilVersion(self):
233 print "%s - %s (yum - %s)" % (self._utilName,self._utilVer,yum.__version__)
234
235 def doUtilConfigSetup(self,args = sys.argv[1:],pluginsTypes=(plugins.TYPE_CORE,)):
236 # Parse only command line options that affect basic yum setup
237 opts = self._parser.firstParse(args)
238
239 # go through all the setopts and set the global ones
240 self._parseSetOpts(opts.setopts)
241
242 if self.main_setopts:
243 for opt in self.main_setopts.items:
244 setattr(opts, opt, getattr(self.main_setopts, opt))
245
246 # Just print out the version if that's what the user wanted
247 if opts.version:
248 self._printUtilVersion()
249 sys.exit(0)
250 # get the install root to use
251 root = self._parser.getRoot(opts)
252 if opts.quiet:
253 opts.debuglevel = 0
254 if opts.verbose:
255 opts.debuglevel = opts.errorlevel = 6
256
257 # Read up configuration options and initialise plugins
258 try:
259 pc = self.preconf
260 pc.fn = opts.conffile
261 pc.root = root
262 pc.init_plugins = not opts.noplugins
263 pc.plugin_types = pluginsTypes
264 pc.optparser = self._parser
265 pc.debuglevel = opts.debuglevel
266 pc.errorlevel = opts.errorlevel
267 if hasattr(opts, "disableplugins"):
268 pc.disabled_plugins =self._parser._splitArg(opts.disableplugins)
269 if hasattr(opts, "enableplugins"):
270 pc.enabled_plugins = self._parser._splitArg(opts.enableplugins)
271 if hasattr(opts, "releasever"):
272 pc.releasever = opts.releasever
273 self.conf
274
275 # now set all the non-first-start opts from main from our setopts
276 if self.main_setopts:
277 for opt in self.main_setopts.items:
278 setattr(self.conf, opt, getattr(self.main_setopts, opt))
279
280 except Errors.ConfigError, e:
281 self.logger.critical(_('Config Error: %s'), exception2msg(e))
282 sys.exit(1)
283 except ValueError, e:
284 self.logger.critical(_('Options Error: %s'), exception2msg(e))
285 sys.exit(1)
286 except plugins.PluginYumExit, e:
287 self.logger.critical(_('PluginExit Error: %s'), exception2msg(e))
288 sys.exit(1)
289 except Errors.YumBaseError, e:
290 self.logger.critical(_('Yum Error: %s'), exception2msg(e))
291 sys.exit(1)
292
293 # update usage in case plugins have added commands
294 self._parser.set_usage(self._usage)
295
296 # Now parse the command line for real and
297 # apply some of the options to self.conf
298 (opts, self.cmds) = self._parser.setupYumConfig()
299 if self.cmds:
300 self.basecmd = self.cmds[0] # our base command
301 else:
302 self.basecmd = None
303 self.extcmds = self.cmds[1:] # out extended arguments/commands
304
305 return opts
306
307 def doUtilYumSetup(self):
308 """do a default setup for all the normal/necessary yum components,
309 really just a shorthand for testing"""
310 # FIXME - we need another way to do this, I think.
311 try:
312 self.waitForLock()
313 self._getTs()
314 self._getRpmDB()
315 self._getRepos(doSetup = True)
316 self._getSacks()
317 except Errors.YumBaseError, msg:
318 self.logger.critical(exception2msg(msg))
319 sys.exit(1)
320
321 def doUtilBuildTransaction(self, unfinished_transactions_check=True):
322 try:
323 (result, resultmsgs) = self.buildTransaction(unfinished_transactions_check = unfinished_transactions_check)
324 except plugins.PluginYumExit, e:
325 return self.exPluginExit(e)
326 except Errors.YumBaseError, e:
327 result = 1
328 resultmsgs = [exception2msg(e)]
329 except KeyboardInterrupt:
330 return self.exUserCancel()
331 except IOError, e:
332 return self.exIOError(e)
333
334 # Act on the depsolve result
335 if result == 0:
336 # Normal exit
337 if self.unlock(): return 200
338 return 0
339 elif result == 1:
340 # Fatal error
341 for msg in resultmsgs:
342 prefix = _('Error: %s')
343 prefix2nd = (' ' * (utf8_width(prefix) - 2))
344 self.logger.critical(prefix, msg.replace('\n', '\n' + prefix2nd))
345 if not self.conf.skip_broken:
346 self.verbose_logger.info(_(" You could try using --skip-broken to work around the problem"))
347 if not self._rpmdb_warn_checks(out=self.verbose_logger.info, warn=False):
348 self.verbose_logger.info(_(" You could try running: rpm -Va --nofiles --nodigest"))
349 if self.unlock(): return 200
350 return 1
351 elif result == 2:
352 # Continue on
353 pass
354 else:
355 self.logger.critical(_('Unknown Error(s): Exit Code: %d:'), result)
356 for msg in resultmsgs:
357 self.logger.critical(msg)
358 if self.unlock(): return 200
359 return 3
360
361 self.verbose_logger.log(logginglevels.INFO_2, _('\nDependencies Resolved'))
362
363 def doUtilTransaction(self):
364
365 try:
366 return_code = self.doTransaction()
367 except plugins.PluginYumExit, e:
368 return self.exPluginExit(e)
369 except Errors.YumBaseError, e:
370 return self.exFatal(e)
371 except KeyboardInterrupt:
372 return self.exUserCancel()
373 except IOError, e:
374 return self.exIOError(e,)
375
376 self.verbose_logger.log(logginglevels.INFO_2, _('Complete!'))
377 if self.unlock(): return 200
378 return return_code
379
380def main():
381 name = 'testutil'
382 ver = '0.1'
383 usage = 'testutil [options] [args]'
384 util = YumUtilBase(name,ver,usage)
385 parser = util.getOptionParser()
386 parser.add_option("", "--myoption", dest="myoption",
387 action="store_true", default=False,
388 help="This is an util option")
389 util.logger.info("Setup Yum Config")
390 opts = util.doUtilConfigSetup()
391 util.logger.info("Setup Yum")
392 util.doUtilYumSetup()
393 print "Command line args: %s" % " ".join(util.cmds)
394 print "Command line options :"
395 print opts
396
397 util.logger.info("%s Completed" % name)
398if __name__ == '__main__':
399 main()
400
401
Note: See TracBrowser for help on using the repository browser.