Module output
[hide private]
[frames] | no frames]

Source Code for Module output

   1  #!/usr/bin/python -t 
   2   
   3  """This handles actual output from the cli""" 
   4   
   5  # This program is free software; you can redistribute it and/or modify 
   6  # it under the terms of the GNU General Public License as published by 
   7  # the Free Software Foundation; either version 2 of the License, or 
   8  # (at your option) any later version. 
   9  # 
  10  # This program is distributed in the hope that it will be useful, 
  11  # but WITHOUT ANY WARRANTY; without even the implied warranty of 
  12  # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the 
  13  # GNU Library General Public License for more details. 
  14  # 
  15  # You should have received a copy of the GNU General Public License 
  16  # along with this program; if not, write to the Free Software 
  17  # Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. 
  18  # Copyright 2005 Duke University  
  19   
  20  import sys 
  21  import time 
  22  import logging 
  23  import types 
  24  import gettext 
  25  import pwd 
  26  import rpm 
  27   
  28  import re # For YumTerm 
  29   
  30  from weakref import proxy as weakref 
  31   
  32  from urlgrabber.progress import TextMeter 
  33  import urlgrabber.progress 
  34  from urlgrabber.grabber import URLGrabError 
  35  from yum.misc import prco_tuple_to_string 
  36  from yum.i18n import to_str, to_utf8, to_unicode 
  37  import yum.misc 
  38  from rpmUtils.miscutils import checkSignals, formatRequire 
  39  from yum.constants import * 
  40   
  41  from yum import logginglevels, _ 
  42  from yum.rpmtrans import RPMBaseCallback 
  43  from yum.packageSack import packagesNewestByNameArch 
  44  import yum.packages 
  45   
  46  from yum.i18n import utf8_width, utf8_width_fill, utf8_text_fill 
47 48 -def _term_width():
49 """ Simple terminal width, limit to 20 chars. and make 0 == 80. """ 50 if not hasattr(urlgrabber.progress, 'terminal_width_cached'): 51 return 80 52 ret = urlgrabber.progress.terminal_width_cached() 53 if ret == 0: 54 return 80 55 if ret < 20: 56 return 20 57 return ret
58
59 60 -class YumTextMeter(TextMeter):
61 62 """ 63 Text progress bar output. 64 """ 65
66 - def update(self, amount_read, now=None):
67 checkSignals() 68 TextMeter.update(self, amount_read, now)
69
70 -class YumTerm:
71 """some terminal "UI" helpers based on curses""" 72 73 # From initial search for "terminfo and python" got: 74 # http://aspn.activestate.com/ASPN/Cookbook/Python/Recipe/475116 75 # ...it's probably not copyrightable, but if so ASPN says: 76 # 77 # Except where otherwise noted, recipes in the Python Cookbook are 78 # published under the Python license. 79 80 __enabled = True 81 82 if hasattr(urlgrabber.progress, 'terminal_width_cached'): 83 columns = property(lambda self: _term_width()) 84 85 __cap_names = { 86 'underline' : 'smul', 87 'reverse' : 'rev', 88 'normal' : 'sgr0', 89 } 90 91 __colors = { 92 'black' : 0, 93 'blue' : 1, 94 'green' : 2, 95 'cyan' : 3, 96 'red' : 4, 97 'magenta' : 5, 98 'yellow' : 6, 99 'white' : 7 100 } 101 __ansi_colors = { 102 'black' : 0, 103 'red' : 1, 104 'green' : 2, 105 'yellow' : 3, 106 'blue' : 4, 107 'magenta' : 5, 108 'cyan' : 6, 109 'white' : 7 110 } 111 __ansi_forced_MODE = { 112 'bold' : '\x1b[1m', 113 'blink' : '\x1b[5m', 114 'dim' : '', 115 'reverse' : '\x1b[7m', 116 'underline' : '\x1b[4m', 117 'normal' : '\x1b(B\x1b[m' 118 } 119 __ansi_forced_FG_COLOR = { 120 'black' : '\x1b[30m', 121 'red' : '\x1b[31m', 122 'green' : '\x1b[32m', 123 'yellow' : '\x1b[33m', 124 'blue' : '\x1b[34m', 125 'magenta' : '\x1b[35m', 126 'cyan' : '\x1b[36m', 127 'white' : '\x1b[37m' 128 } 129 __ansi_forced_BG_COLOR = { 130 'black' : '\x1b[40m', 131 'red' : '\x1b[41m', 132 'green' : '\x1b[42m', 133 'yellow' : '\x1b[43m', 134 'blue' : '\x1b[44m', 135 'magenta' : '\x1b[45m', 136 'cyan' : '\x1b[46m', 137 'white' : '\x1b[47m' 138 } 139
140 - def __forced_init(self):
141 self.MODE = self.__ansi_forced_MODE 142 self.FG_COLOR = self.__ansi_forced_FG_COLOR 143 self.BG_COLOR = self.__ansi_forced_BG_COLOR
144
145 - def reinit(self, term_stream=None, color='auto'):
146 self.__enabled = True 147 if not hasattr(urlgrabber.progress, 'terminal_width_cached'): 148 self.columns = 80 149 self.lines = 24 150 151 if color == 'always': 152 self.__forced_init() 153 return 154 155 # Output modes: 156 self.MODE = { 157 'bold' : '', 158 'blink' : '', 159 'dim' : '', 160 'reverse' : '', 161 'underline' : '', 162 'normal' : '' 163 } 164 165 # Colours 166 self.FG_COLOR = { 167 'black' : '', 168 'blue' : '', 169 'green' : '', 170 'cyan' : '', 171 'red' : '', 172 'magenta' : '', 173 'yellow' : '', 174 'white' : '' 175 } 176 177 self.BG_COLOR = { 178 'black' : '', 179 'blue' : '', 180 'green' : '', 181 'cyan' : '', 182 'red' : '', 183 'magenta' : '', 184 'yellow' : '', 185 'white' : '' 186 } 187 188 if color == 'never': 189 self.__enabled = False 190 return 191 assert color == 'auto' 192 193 # Curses isn't available on all platforms 194 try: 195 import curses 196 except: 197 self.__enabled = False 198 return 199 200 # If the stream isn't a tty, then assume it has no capabilities. 201 if not term_stream: 202 term_stream = sys.stdout 203 if not term_stream.isatty(): 204 self.__enabled = False 205 return 206 207 # Check the terminal type. If we fail, then assume that the 208 # terminal has no capabilities. 209 try: 210 curses.setupterm(fd=term_stream.fileno()) 211 except: 212 self.__enabled = False 213 return 214 self._ctigetstr = curses.tigetstr 215 216 if not hasattr(urlgrabber.progress, 'terminal_width_cached'): 217 self.columns = curses.tigetnum('cols') 218 self.lines = curses.tigetnum('lines') 219 220 # Look up string capabilities. 221 for cap_name in self.MODE: 222 mode = cap_name 223 if cap_name in self.__cap_names: 224 cap_name = self.__cap_names[cap_name] 225 self.MODE[mode] = self._tigetstr(cap_name) or '' 226 227 # Colors 228 set_fg = self._tigetstr('setf') 229 if set_fg: 230 for (color, val) in self.__colors.items(): 231 self.FG_COLOR[color] = curses.tparm(set_fg, val) or '' 232 set_fg_ansi = self._tigetstr('setaf') 233 if set_fg_ansi: 234 for (color, val) in self.__ansi_colors.items(): 235 self.FG_COLOR[color] = curses.tparm(set_fg_ansi, val) or '' 236 set_bg = self._tigetstr('setb') 237 if set_bg: 238 for (color, val) in self.__colors.items(): 239 self.BG_COLOR[color] = curses.tparm(set_bg, val) or '' 240 set_bg_ansi = self._tigetstr('setab') 241 if set_bg_ansi: 242 for (color, val) in self.__ansi_colors.items(): 243 self.BG_COLOR[color] = curses.tparm(set_bg_ansi, val) or ''
244
245 - def __init__(self, term_stream=None, color='auto'):
246 self.reinit(term_stream, color)
247
248 - def _tigetstr(self, cap_name):
249 # String capabilities can include "delays" of the form "$<2>". 250 # For any modern terminal, we should be able to just ignore 251 # these, so strip them out. 252 cap = self._ctigetstr(cap_name) or '' 253 return re.sub(r'\$<\d+>[/*]?', '', cap)
254
255 - def sub(self, haystack, beg, end, needles, escape=None, ignore_case=False):
256 if not self.__enabled: 257 return haystack 258 259 if not escape: 260 escape = re.escape 261 262 render = lambda match: beg + match.group() + end 263 for needle in needles: 264 pat = escape(needle) 265 if ignore_case: 266 pat = re.template(pat, re.I) 267 haystack = re.sub(pat, render, haystack) 268 return haystack
269 - def sub_norm(self, haystack, beg, needles, **kwds):
270 return self.sub(haystack, beg, self.MODE['normal'], needles, **kwds)
271
272 - def sub_mode(self, haystack, mode, needles, **kwds):
273 return self.sub_norm(haystack, self.MODE[mode], needles, **kwds)
274
275 - def sub_bold(self, haystack, needles, **kwds):
276 return self.sub_mode(haystack, 'bold', needles, **kwds)
277
278 - def sub_fg(self, haystack, color, needles, **kwds):
279 return self.sub_norm(haystack, self.FG_COLOR[color], needles, **kwds)
280
281 - def sub_bg(self, haystack, color, needles, **kwds):
282 return self.sub_norm(haystack, self.BG_COLOR[color], needles, **kwds)
283
284 285 286 -class YumOutput:
287 288 """ 289 Main output class for the yum command line. 290 """ 291
292 - def __init__(self):
293 self.logger = logging.getLogger("yum.cli") 294 self.verbose_logger = logging.getLogger("yum.verbose.cli") 295 if hasattr(rpm, "expandMacro"): 296 self.i18ndomains = rpm.expandMacro("%_i18ndomains").split(":") 297 else: 298 self.i18ndomains = ["redhat-dist"] 299 300 self.term = YumTerm() 301 self._last_interrupt = None
302 303
304 - def printtime(self):
305 months = [_('Jan'), _('Feb'), _('Mar'), _('Apr'), _('May'), _('Jun'), 306 _('Jul'), _('Aug'), _('Sep'), _('Oct'), _('Nov'), _('Dec')] 307 now = time.localtime(time.time()) 308 ret = months[int(time.strftime('%m', now)) - 1] + \ 309 time.strftime(' %d %T ', now) 310 return ret
311
312 - def failureReport(self, errobj):
313 """failure output for failovers from urlgrabber""" 314 315 self.logger.error('%s: %s', errobj.url, errobj.exception) 316 self.logger.error(_('Trying other mirror.')) 317 raise errobj.exception
318 319
320 - def simpleProgressBar(self, current, total, name=None):
321 progressbar(current, total, name)
322
323 - def _highlight(self, highlight):
324 hibeg = '' 325 hiend = '' 326 if not highlight: 327 pass 328 elif not isinstance(highlight, basestring) or highlight == 'bold': 329 hibeg = self.term.MODE['bold'] 330 elif highlight == 'normal': 331 pass # Minor opt. 332 else: 333 # Turn a string into a specific output: colour, bold, etc. 334 for high in highlight.replace(',', ' ').split(): 335 if False: pass 336 elif high == 'normal': 337 hibeg = '' 338 elif high in self.term.MODE: 339 hibeg += self.term.MODE[high] 340 elif high in self.term.FG_COLOR: 341 hibeg += self.term.FG_COLOR[high] 342 elif (high.startswith('fg:') and 343 high[3:] in self.term.FG_COLOR): 344 hibeg += self.term.FG_COLOR[high[3:]] 345 elif (high.startswith('bg:') and 346 high[3:] in self.term.BG_COLOR): 347 hibeg += self.term.BG_COLOR[high[3:]] 348 349 if hibeg: 350 hiend = self.term.MODE['normal'] 351 return (hibeg, hiend)
352
353 - def _sub_highlight(self, haystack, highlight, needles, **kwds):
354 hibeg, hiend = self._highlight(highlight) 355 return self.term.sub(haystack, hibeg, hiend, needles, **kwds)
356 357 @staticmethod
358 - def _calc_columns_spaces_helps(current, data_tups, left):
359 """ Spaces left on the current field will help how many pkgs? """ 360 ret = 0 361 for tup in data_tups: 362 if left < (tup[0] - current): 363 break 364 ret += tup[1] 365 return ret
366
367 - def calcColumns(self, data, columns=None, remainder_column=0, 368 total_width=None, indent=''):
369 """ Dynamically calculate the width of the fields in the data, data is 370 of the format [column-number][field_length] = rows. """ 371 372 if total_width is None: 373 total_width = self.term.columns 374 375 cols = len(data) 376 # Convert the data to ascending list of tuples, (field_length, pkgs) 377 pdata = data 378 data = [None] * cols # Don't modify the passed in data 379 for d in range(0, cols): 380 data[d] = sorted(pdata[d].items()) 381 382 if columns is None: 383 columns = [1] * cols 384 385 total_width -= (sum(columns) + (cols - 1) + utf8_width(indent)) 386 while total_width > 0: 387 # Find which field all the spaces left will help best 388 helps = 0 389 val = 0 390 for d in xrange(0, cols): 391 thelps = self._calc_columns_spaces_helps(columns[d], data[d], 392 total_width) 393 if not thelps: 394 continue 395 if thelps < helps: 396 continue 397 helps = thelps 398 val = d 399 400 # If we found a column to expand, move up to the next level with 401 # that column and start again with any remaining space. 402 if helps: 403 diff = data[val].pop(0)[0] - columns[val] 404 columns[val] += diff 405 total_width -= diff 406 continue 407 408 # Split the remaining spaces among each column equally, except the 409 # last one. And put the rest into the remainder column 410 cols -= 1 411 norm = total_width / cols 412 for d in xrange(0, cols): 413 columns[d] += norm 414 columns[remainder_column] += total_width - (cols * norm) 415 total_width = 0 416 417 return columns
418 419 @staticmethod
420 - def _fmt_column_align_width(width):
421 if width < 0: 422 return (u"-", -width) 423 return (u"", width)
424
425 - def _col_data(self, col_data):
426 assert len(col_data) == 2 or len(col_data) == 3 427 if len(col_data) == 2: 428 (val, width) = col_data 429 hibeg = hiend = '' 430 if len(col_data) == 3: 431 (val, width, highlight) = col_data 432 (hibeg, hiend) = self._highlight(highlight) 433 return (val, width, hibeg, hiend)
434
435 - def fmtColumns(self, columns, msg=u'', end=u''):
436 """ Return a string for columns of data, which can overflow.""" 437 438 total_width = len(msg) 439 data = [] 440 for col_data in columns[:-1]: 441 (val, width, hibeg, hiend) = self._col_data(col_data) 442 443 if not width: # Don't count this column, invisible text 444 msg += u"%s" 445 data.append(val) 446 continue 447 448 (align, width) = self._fmt_column_align_width(width) 449 if utf8_width(val) <= width: 450 msg += u"%s " 451 val = utf8_width_fill(val, width, left=(align == u'-'), 452 prefix=hibeg, suffix=hiend) 453 data.append(val) 454 else: 455 msg += u"%s%s%s\n" + " " * (total_width + width + 1) 456 data.extend([hibeg, val, hiend]) 457 total_width += width 458 total_width += 1 459 (val, width, hibeg, hiend) = self._col_data(columns[-1]) 460 (align, width) = self._fmt_column_align_width(width) 461 val = utf8_width_fill(val, width, left=(align == u'-'), 462 prefix=hibeg, suffix=hiend) 463 msg += u"%%s%s" % end 464 data.append(val) 465 return msg % tuple(data)
466
467 - def simpleList(self, pkg, ui_overflow=False, indent='', highlight=False, 468 columns=None):
469 """ Simple to use function to print a pkg as a line. """ 470 471 if columns is None: 472 columns = (-40, -22, -16) # Old default 473 ver = pkg.printVer() 474 na = '%s%s.%s' % (indent, pkg.name, pkg.arch) 475 hi_cols = [highlight, 'normal', 'normal'] 476 rid = pkg.ui_from_repo 477 columns = zip((na, ver, rid), columns, hi_cols) 478 print self.fmtColumns(columns)
479
480 - def simpleEnvraList(self, pkg, ui_overflow=False, 481 indent='', highlight=False, columns=None):
482 """ Simple to use function to print a pkg as a line, with the pkg 483 itself in envra format so it can be pased to list/install/etc. """ 484 485 if columns is None: 486 columns = (-63, -16) # Old default 487 envra = '%s%s' % (indent, str(pkg)) 488 hi_cols = [highlight, 'normal', 'normal'] 489 rid = pkg.ui_from_repo 490 columns = zip((envra, rid), columns, hi_cols) 491 print self.fmtColumns(columns)
492
493 - def fmtKeyValFill(self, key, val):
494 """ Return a key value pair in the common two column output format. """ 495 val = to_str(val) 496 keylen = utf8_width(key) 497 cols = self.term.columns 498 nxt = ' ' * (keylen - 2) + ': ' 499 ret = utf8_text_fill(val, width=cols, 500 initial_indent=key, subsequent_indent=nxt) 501 if ret.count("\n") > 1 and keylen > (cols / 3): 502 # If it's big, redo it again with a smaller subsequent off 503 ret = utf8_text_fill(val, width=cols, 504 initial_indent=key, 505 subsequent_indent=' ...: ') 506 return ret
507
508 - def fmtSection(self, name, fill='='):
509 name = to_str(name) 510 cols = self.term.columns - 2 511 name_len = utf8_width(name) 512 if name_len >= (cols - 4): 513 beg = end = fill * 2 514 else: 515 beg = fill * ((cols - name_len) / 2) 516 end = fill * (cols - name_len - len(beg)) 517 518 return "%s %s %s" % (beg, name, end)
519
520 - def _enc(self, s):
521 """Get the translated version from specspo and ensure that 522 it's actually encoded in UTF-8.""" 523 s = to_utf8(s) 524 if len(s) > 0: 525 for d in self.i18ndomains: 526 t = gettext.dgettext(d, s) 527 if t != s: 528 s = t 529 break 530 return to_unicode(s)
531
532 - def infoOutput(self, pkg, highlight=False):
533 (hibeg, hiend) = self._highlight(highlight) 534 print _("Name : %s%s%s") % (hibeg, to_unicode(pkg.name), hiend) 535 print _("Arch : %s") % to_unicode(pkg.arch) 536 if pkg.epoch != "0": 537 print _("Epoch : %s") % to_unicode(pkg.epoch) 538 print _("Version : %s") % to_unicode(pkg.version) 539 print _("Release : %s") % to_unicode(pkg.release) 540 print _("Size : %s") % self.format_number(float(pkg.size)) 541 print _("Repo : %s") % to_unicode(pkg.repoid) 542 if pkg.repoid == 'installed' and 'from_repo' in pkg.yumdb_info: 543 print _("From repo : %s") % to_unicode(pkg.yumdb_info.from_repo) 544 if self.verbose_logger.isEnabledFor(logginglevels.DEBUG_3): 545 print _("Committer : %s") % to_unicode(pkg.committer) 546 print _("Committime : %s") % time.ctime(pkg.committime) 547 print _("Buildtime : %s") % time.ctime(pkg.buildtime) 548 if hasattr(pkg, 'installtime'): 549 print _("Installtime: %s") % time.ctime(pkg.installtime) 550 print self.fmtKeyValFill(_("Summary : "), self._enc(pkg.summary)) 551 if pkg.url: 552 print _("URL : %s") % to_unicode(pkg.url) 553 print self.fmtKeyValFill(_("License : "), to_unicode(pkg.license)) 554 print self.fmtKeyValFill(_("Description: "), self._enc(pkg.description)) 555 print ""
556
557 - def updatesObsoletesList(self, uotup, changetype, columns=None):
558 """takes an updates or obsoletes tuple of pkgobjects and 559 returns a simple printed string of the output and a string 560 explaining the relationship between the tuple members""" 561 (changePkg, instPkg) = uotup 562 563 if columns is not None: 564 # New style, output all info. for both old/new with old indented 565 chi = self.conf.color_update_remote 566 if changePkg.repo.id != 'installed' and changePkg.verifyLocalPkg(): 567 chi = self.conf.color_update_local 568 self.simpleList(changePkg, columns=columns, highlight=chi) 569 self.simpleList(instPkg, columns=columns, indent=' ' * 4, 570 highlight=self.conf.color_update_installed) 571 return 572 573 # Old style 574 c_compact = changePkg.compactPrint() 575 i_compact = '%s.%s' % (instPkg.name, instPkg.arch) 576 c_repo = changePkg.repoid 577 print '%-35.35s [%.12s] %.10s %-20.20s' % (c_compact, c_repo, changetype, i_compact)
578
579 - def listPkgs(self, lst, description, outputType, highlight_na={}, 580 columns=None, highlight_modes={}):
581 """outputs based on whatever outputType is. Current options: 582 'list' - simple pkg list 583 'info' - similar to rpm -qi output 584 ...also highlight_na can be passed, and we'll highlight 585 pkgs with (names, arch) in that set.""" 586 587 if outputType in ['list', 'info']: 588 thingslisted = 0 589 if len(lst) > 0: 590 thingslisted = 1 591 print '%s' % description 592 for pkg in sorted(lst): 593 key = (pkg.name, pkg.arch) 594 highlight = False 595 if False: pass 596 elif key not in highlight_na: 597 highlight = highlight_modes.get('not in', 'normal') 598 elif pkg.verEQ(highlight_na[key]): 599 highlight = highlight_modes.get('=', 'normal') 600 elif pkg.verLT(highlight_na[key]): 601 highlight = highlight_modes.get('>', 'bold') 602 else: 603 highlight = highlight_modes.get('<', 'normal') 604 605 if outputType == 'list': 606 self.simpleList(pkg, ui_overflow=True, 607 highlight=highlight, columns=columns) 608 elif outputType == 'info': 609 self.infoOutput(pkg, highlight=highlight) 610 else: 611 pass 612 613 if thingslisted == 0: 614 return 1, ['No Packages to list'] 615 return 0, []
616 617 618
619 - def userconfirm(self):
620 """gets a yes or no from the user, defaults to No""" 621 622 yui = (to_unicode(_('y')), to_unicode(_('yes'))) 623 nui = (to_unicode(_('n')), to_unicode(_('no'))) 624 aui = (yui[0], yui[1], nui[0], nui[1]) 625 while True: 626 try: 627 choice = raw_input(_('Is this ok [y/N]: ')) 628 except UnicodeEncodeError: 629 raise 630 except UnicodeDecodeError: 631 raise 632 except: 633 choice = '' 634 choice = to_unicode(choice) 635 choice = choice.lower() 636 if len(choice) == 0 or choice in aui: 637 break 638 # If the enlish one letter names don't mix, allow them too 639 if u'y' not in aui and u'y' == choice: 640 choice = yui[0] 641 break 642 if u'n' not in aui and u'n' == choice: 643 break 644 645 if len(choice) == 0 or choice not in yui: 646 return False 647 else: 648 return True
649
650 - def _cli_confirm_gpg_key_import(self, keydict):
651 # FIXME what should we be printing here? 652 return self.userconfirm()
653
654 - def _group_names2aipkgs(self, pkg_names):
655 """ Convert pkg_names to installed pkgs or available pkgs, return 656 value is a dict on pkg.name returning (apkg, ipkg). """ 657 ipkgs = self.rpmdb.searchNames(pkg_names) 658 apkgs = self.pkgSack.searchNames(pkg_names) 659 apkgs = packagesNewestByNameArch(apkgs) 660 661 # This is somewhat similar to doPackageLists() 662 pkgs = {} 663 for pkg in ipkgs: 664 pkgs[(pkg.name, pkg.arch)] = (None, pkg) 665 for pkg in apkgs: 666 key = (pkg.name, pkg.arch) 667 if key not in pkgs: 668 pkgs[(pkg.name, pkg.arch)] = (pkg, None) 669 elif pkg.verGT(pkgs[key][1]): 670 pkgs[(pkg.name, pkg.arch)] = (pkg, pkgs[key][1]) 671 672 # Convert (pkg.name, pkg.arch) to pkg.name dict 673 ret = {} 674 for (apkg, ipkg) in pkgs.itervalues(): 675 pkg = apkg or ipkg 676 ret.setdefault(pkg.name, []).append((apkg, ipkg)) 677 return ret
678
679 - def _calcDataPkgColumns(self, data, pkg_names, pkg_names2pkgs, 680 indent=' '):
681 for item in pkg_names: 682 if item not in pkg_names2pkgs: 683 continue 684 for (apkg, ipkg) in pkg_names2pkgs[item]: 685 pkg = ipkg or apkg 686 envra = utf8_width(str(pkg)) + utf8_width(indent) 687 rid = len(pkg.ui_from_repo) 688 for (d, v) in (('envra', envra), ('rid', rid)): 689 data[d].setdefault(v, 0) 690 data[d][v] += 1
691
692 - def _displayPkgsFromNames(self, pkg_names, verbose, pkg_names2pkgs, 693 indent=' ', columns=None):
694 if not verbose: 695 for item in sorted(pkg_names): 696 print '%s%s' % (indent, item) 697 else: 698 for item in sorted(pkg_names): 699 if item not in pkg_names2pkgs: 700 print '%s%s' % (indent, item) 701 continue 702 for (apkg, ipkg) in sorted(pkg_names2pkgs[item], 703 key=lambda x: x[1] or x[0]): 704 if ipkg and apkg: 705 highlight = self.conf.color_list_installed_older 706 elif apkg: 707 highlight = self.conf.color_list_available_install 708 else: 709 highlight = False 710 self.simpleEnvraList(ipkg or apkg, ui_overflow=True, 711 indent=indent, highlight=highlight, 712 columns=columns)
713
714 - def displayPkgsInGroups(self, group):
715 print _('\nGroup: %s') % group.ui_name 716 717 verb = self.verbose_logger.isEnabledFor(logginglevels.DEBUG_3) 718 if verb: 719 print _(' Group-Id: %s') % to_unicode(group.groupid) 720 pkg_names2pkgs = None 721 if verb: 722 pkg_names2pkgs = self._group_names2aipkgs(group.packages) 723 if group.ui_description: 724 print _(' Description: %s') % to_unicode(group.ui_description) 725 726 sections = ((_(' Mandatory Packages:'), group.mandatory_packages), 727 (_(' Default Packages:'), group.default_packages), 728 (_(' Optional Packages:'), group.optional_packages), 729 (_(' Conditional Packages:'), group.conditional_packages)) 730 columns = None 731 if verb: 732 data = {'envra' : {}, 'rid' : {}} 733 for (section_name, pkg_names) in sections: 734 self._calcDataPkgColumns(data, pkg_names, pkg_names2pkgs) 735 data = [data['envra'], data['rid']] 736 columns = self.calcColumns(data) 737 columns = (-columns[0], -columns[1]) 738 739 for (section_name, pkg_names) in sections: 740 if len(pkg_names) > 0: 741 print section_name 742 self._displayPkgsFromNames(pkg_names, verb, pkg_names2pkgs, 743 columns=columns)
744
745 - def depListOutput(self, results):
746 """take a list of findDeps results and 'pretty print' the output""" 747 748 for pkg in results: 749 print _("package: %s") % pkg.compactPrint() 750 if len(results[pkg]) == 0: 751 print _(" No dependencies for this package") 752 continue 753 754 for req in results[pkg]: 755 reqlist = results[pkg][req] 756 print _(" dependency: %s") % prco_tuple_to_string(req) 757 if not reqlist: 758 print _(" Unsatisfied dependency") 759 continue 760 761 for po in reqlist: 762 print " provider: %s" % po.compactPrint()
763
764 - def format_number(self, number, SI=0, space=' '):
765 """Turn numbers into human-readable metric-like numbers""" 766 symbols = [ ' ', # (none) 767 'k', # kilo 768 'M', # mega 769 'G', # giga 770 'T', # tera 771 'P', # peta 772 'E', # exa 773 'Z', # zetta 774 'Y'] # yotta 775 776 if SI: step = 1000.0 777 else: step = 1024.0 778 779 thresh = 999 780 depth = 0 781 max_depth = len(symbols) - 1 782 783 # we want numbers between 0 and thresh, but don't exceed the length 784 # of our list. In that event, the formatting will be screwed up, 785 # but it'll still show the right number. 786 while number > thresh and depth < max_depth: 787 depth = depth + 1 788 number = number / step 789 790 if type(number) == type(1) or type(number) == type(1L): 791 format = '%i%s%s' 792 elif number < 9.95: 793 # must use 9.95 for proper sizing. For example, 9.99 will be 794 # rounded to 10.0 with the .1f format string (which is too long) 795 format = '%.1f%s%s' 796 else: 797 format = '%.0f%s%s' 798 799 return(format % (float(number or 0), space, symbols[depth]))
800 801 @staticmethod
802 - def format_time(seconds, use_hours=0):
803 return urlgrabber.progress.format_time(seconds, use_hours)
804
805 - def matchcallback(self, po, values, matchfor=None, verbose=None, 806 highlight=None):
807 """ Output search/provides type callback matches. po is the pkg object, 808 values are the things in the po that we've matched. 809 If matchfor is passed, all the strings in that list will be 810 highlighted within the output. 811 verbose overrides logginglevel, if passed. """ 812 813 if self.conf.showdupesfromrepos: 814 msg = '%s : ' % po 815 else: 816 msg = '%s.%s : ' % (po.name, po.arch) 817 msg = self.fmtKeyValFill(msg, self._enc(po.summary)) 818 if matchfor: 819 if highlight is None: 820 highlight = self.conf.color_search_match 821 msg = self._sub_highlight(msg, highlight, matchfor,ignore_case=True) 822 823 print msg 824 825 if verbose is None: 826 verbose = self.verbose_logger.isEnabledFor(logginglevels.DEBUG_3) 827 if not verbose: 828 return 829 830 print _("Repo : %s") % po.repoid 831 print _('Matched from:') 832 for item in yum.misc.unique(values): 833 item = to_utf8(item) 834 if to_utf8(po.name) == item or to_utf8(po.summary) == item: 835 continue # Skip double name/summary printing 836 837 can_overflow = True 838 if False: pass 839 elif to_utf8(po.description) == item: 840 key = _("Description : ") 841 item = self._enc(item) 842 elif to_utf8(po.url) == item: 843 key = _("URL : %s") 844 can_overflow = False 845 elif to_utf8(po.license) == item: 846 key = _("License : %s") 847 can_overflow = False 848 elif item.startswith("/"): 849 key = _("Filename : %s") 850 item = self._enc(item) 851 can_overflow = False 852 else: 853 key = _("Other : ") 854 855 if matchfor: 856 item = self._sub_highlight(item, highlight, matchfor, 857 ignore_case=True) 858 if can_overflow: 859 print self.fmtKeyValFill(key, to_unicode(item)) 860 else: 861 print key % item 862 print '\n\n'
863
864 - def matchcallback_verbose(self, po, values, matchfor=None):
865 return self.matchcallback(po, values, matchfor, verbose=True)
866
867 - def reportDownloadSize(self, packages, installonly=False):
868 """Report the total download size for a set of packages""" 869 totsize = 0 870 locsize = 0 871 insize = 0 872 error = False 873 for pkg in packages: 874 # Just to be on the safe side, if for some reason getting 875 # the package size fails, log the error and don't report download 876 # size 877 try: 878 size = int(pkg.size) 879 totsize += size 880 try: 881 if pkg.verifyLocalPkg(): 882 locsize += size 883 except: 884 pass 885 886 if not installonly: 887 continue 888 889 try: 890 size = int(pkg.installedsize) 891 except: 892 pass 893 insize += size 894 except: 895 error = True 896 self.logger.error(_('There was an error calculating total download size')) 897 break 898 899 if (not error): 900 if locsize: 901 self.verbose_logger.log(logginglevels.INFO_1, _("Total size: %s"), 902 self.format_number(totsize)) 903 if locsize != totsize: 904 self.verbose_logger.log(logginglevels.INFO_1, _("Total download size: %s"), 905 self.format_number(totsize - locsize)) 906 if installonly: 907 self.verbose_logger.log(logginglevels.INFO_1, 908 _("Installed size: %s"), 909 self.format_number(insize))
910
911 - def listTransaction(self):
912 """returns a string rep of the transaction in an easy-to-read way.""" 913 914 self.tsInfo.makelists(True, True) 915 pkglist_lines = [] 916 data = {'n' : {}, 'v' : {}, 'r' : {}} 917 a_wid = 0 # Arch can't get "that big" ... so always use the max. 918 919 def _add_line(lines, data, a_wid, po, obsoletes=[]): 920 (n,a,e,v,r) = po.pkgtup 921 evr = po.printVer() 922 repoid = po.ui_from_repo 923 pkgsize = float(po.size) 924 size = self.format_number(pkgsize) 925 926 if a is None: # gpgkeys are weird 927 a = 'noarch' 928 929 # none, partial, full? 930 if po.repo.id == 'installed': 931 hi = self.conf.color_update_installed 932 elif po.verifyLocalPkg(): 933 hi = self.conf.color_update_local 934 else: 935 hi = self.conf.color_update_remote 936 lines.append((n, a, evr, repoid, size, obsoletes, hi)) 937 # Create a dict of field_length => number of packages, for 938 # each field. 939 for (d, v) in (("n",len(n)), ("v",len(evr)), ("r",len(repoid))): 940 data[d].setdefault(v, 0) 941 data[d][v] += 1 942 if a_wid < len(a): # max() is only in 2.5.z 943 a_wid = len(a) 944 return a_wid
945 946 for (action, pkglist) in [(_('Installing'), self.tsInfo.installed), 947 (_('Updating'), self.tsInfo.updated), 948 (_('Removing'), self.tsInfo.removed), 949 (_('Reinstalling'), self.tsInfo.reinstalled), 950 (_('Downgrading'), self.tsInfo.downgraded), 951 (_('Installing for dependencies'), self.tsInfo.depinstalled), 952 (_('Updating for dependencies'), self.tsInfo.depupdated), 953 (_('Removing for dependencies'), self.tsInfo.depremoved)]: 954 lines = [] 955 for txmbr in pkglist: 956 a_wid = _add_line(lines, data, a_wid, txmbr.po, txmbr.obsoletes) 957 958 pkglist_lines.append((action, lines)) 959 960 for (action, pkglist) in [(_('Skipped (dependency problems)'), 961 self.skipped_packages),]: 962 lines = [] 963 for po in pkglist: 964 a_wid = _add_line(lines, data, a_wid, po) 965 966 pkglist_lines.append((action, lines)) 967 968 if not data['n']: 969 return u'' 970 else: 971 data = [data['n'], {}, data['v'], data['r'], {}] 972 columns = [1, a_wid, 1, 1, 5] 973 columns = self.calcColumns(data, indent=" ", columns=columns, 974 remainder_column=2) 975 (n_wid, a_wid, v_wid, r_wid, s_wid) = columns 976 assert s_wid == 5 977 978 out = [u""" 979 %s 980 %s 981 %s 982 """ % ('=' * self.term.columns, 983 self.fmtColumns(((_('Package'), -n_wid), (_('Arch'), -a_wid), 984 (_('Version'), -v_wid), (_('Repository'), -r_wid), 985 (_('Size'), s_wid)), u" "), 986 '=' * self.term.columns)] 987 988 for (action, lines) in pkglist_lines: 989 if lines: 990 totalmsg = u"%s:\n" % action 991 for (n, a, evr, repoid, size, obsoletes, hi) in lines: 992 columns = ((n, -n_wid, hi), (a, -a_wid), 993 (evr, -v_wid), (repoid, -r_wid), (size, s_wid)) 994 msg = self.fmtColumns(columns, u" ", u"\n") 995 hibeg, hiend = self._highlight(self.conf.color_update_installed) 996 for obspo in sorted(obsoletes): 997 appended = _(' replacing %s%s%s.%s %s\n') 998 appended %= (hibeg, obspo.name, hiend, 999 obspo.arch, obspo.printVer()) 1000 msg = msg+appended 1001 totalmsg = totalmsg + msg 1002 1003 if lines: 1004 out.append(totalmsg) 1005 1006 summary = _(""" 1007 Transaction Summary 1008 %s 1009 """) % ('=' * self.term.columns,) 1010 out.append(summary) 1011 num_in = len(self.tsInfo.installed + self.tsInfo.depinstalled) 1012 num_up = len(self.tsInfo.updated + self.tsInfo.depupdated) 1013 summary = _("""\ 1014 Install %5.5s Package(s) 1015 Upgrade %5.5s Package(s) 1016 """) % (num_in, num_up,) 1017 if num_in or num_up: # Always do this? 1018 out.append(summary) 1019 num_rm = len(self.tsInfo.removed + self.tsInfo.depremoved) 1020 num_re = len(self.tsInfo.reinstalled) 1021 num_dg = len(self.tsInfo.downgraded) 1022 summary = _("""\ 1023 Remove %5.5s Package(s) 1024 Reinstall %5.5s Package(s) 1025 Downgrade %5.5s Package(s) 1026 """) % (num_rm, num_re, num_dg) 1027 if num_rm or num_re or num_dg: 1028 out.append(summary) 1029 1030 return ''.join(out)
1031
1032 - def postTransactionOutput(self):
1033 out = '' 1034 1035 self.tsInfo.makelists() 1036 1037 # Works a bit like calcColumns, but we never overflow a column we just 1038 # have a dynamic number of columns. 1039 def _fits_in_cols(msgs, num): 1040 """ Work out how many columns we can use to display stuff, in 1041 the post trans output. """ 1042 if len(msgs) < num: 1043 return [] 1044 1045 left = self.term.columns - ((num - 1) + 2) 1046 if left <= 0: 1047 return [] 1048 1049 col_lens = [0] * num 1050 col = 0 1051 for msg in msgs: 1052 if len(msg) > col_lens[col]: 1053 diff = (len(msg) - col_lens[col]) 1054 if left <= diff: 1055 return [] 1056 left -= diff 1057 col_lens[col] = len(msg) 1058 col += 1 1059 col %= len(col_lens) 1060 1061 for col in range(len(col_lens)): 1062 col_lens[col] += left / num 1063 col_lens[col] *= -1 1064 return col_lens
1065 1066 for (action, pkglist) in [(_('Removed'), self.tsInfo.removed), 1067 (_('Dependency Removed'), self.tsInfo.depremoved), 1068 (_('Installed'), self.tsInfo.installed), 1069 (_('Dependency Installed'), self.tsInfo.depinstalled), 1070 (_('Updated'), self.tsInfo.updated), 1071 (_('Dependency Updated'), self.tsInfo.depupdated), 1072 (_('Skipped (dependency problems)'), self.skipped_packages), 1073 (_('Replaced'), self.tsInfo.obsoleted), 1074 (_('Failed'), self.tsInfo.failed)]: 1075 msgs = [] 1076 if len(pkglist) > 0: 1077 out += '\n%s:\n' % action 1078 for txmbr in pkglist: 1079 (n,a,e,v,r) = txmbr.pkgtup 1080 msg = "%s.%s %s:%s-%s" % (n,a,e,v,r) 1081 msgs.append(msg) 1082 for num in (8, 7, 6, 5, 4, 3, 2): 1083 cols = _fits_in_cols(msgs, num) 1084 if cols: 1085 break 1086 if not cols: 1087 cols = [-(self.term.columns - 2)] 1088 while msgs: 1089 current_msgs = msgs[:len(cols)] 1090 out += ' ' 1091 out += self.fmtColumns(zip(current_msgs, cols), end=u'\n') 1092 msgs = msgs[len(cols):] 1093 1094 return out 1095
1096 - def setupProgressCallbacks(self):
1097 """sets up the progress callbacks and various 1098 output bars based on debug level""" 1099 1100 # if we're below 2 on the debug level we don't need to be outputting 1101 # progress bars - this is hacky - I'm open to other options 1102 # One of these is a download 1103 if self.conf.debuglevel < 2 or not sys.stdout.isatty(): 1104 self.repos.setProgressBar(None) 1105 self.repos.callback = None 1106 else: 1107 self.repos.setProgressBar(YumTextMeter(fo=sys.stdout)) 1108 self.repos.callback = CacheProgressCallback() 1109 1110 # setup our failure report for failover 1111 freport = (self.failureReport,(),{}) 1112 self.repos.setFailureCallback(freport) 1113 1114 # setup callback for CTRL-C's 1115 self.repos.setInterruptCallback(self.interrupt_callback) 1116 1117 # setup our depsolve progress callback 1118 dscb = DepSolveProgressCallBack(weakref(self)) 1119 self.dsCallback = dscb
1120
1121 - def setupProgessCallbacks(self):
1122 # api purposes only to protect the typo 1123 self.setupProgressCallbacks()
1124
1125 - def setupKeyImportCallbacks(self):
1126 self.repos.confirm_func = self._cli_confirm_gpg_key_import 1127 self.repos.gpg_import_func = self.getKeyForRepo
1128
1129 - def interrupt_callback(self, cbobj):
1130 '''Handle CTRL-C's during downloads 1131 1132 If a CTRL-C occurs a URLGrabError will be raised to push the download 1133 onto the next mirror. 1134 1135 If two CTRL-C's occur in quick succession then yum will exit. 1136 1137 @param cbobj: urlgrabber callback obj 1138 ''' 1139 delta_exit_chk = 2.0 # Delta between C-c's so we treat as exit 1140 delta_exit_str = _("two") # Human readable version of above 1141 1142 now = time.time() 1143 1144 if not self._last_interrupt: 1145 hibeg = self.term.MODE['bold'] 1146 hiend = self.term.MODE['normal'] 1147 # For translators: This is output like: 1148 # Current download cancelled, interrupt (ctrl-c) again within two seconds 1149 # to exit. 1150 # Where "interupt (ctrl-c) again" and "two" are highlighted. 1151 msg = _(""" 1152 Current download cancelled, %sinterrupt (ctrl-c) again%s within %s%s%s seconds 1153 to exit. 1154 """) % (hibeg, hiend, hibeg, delta_exit_str, hiend) 1155 self.verbose_logger.log(logginglevels.INFO_2, msg) 1156 elif now - self._last_interrupt < delta_exit_chk: 1157 # Two quick CTRL-C's, quit 1158 raise KeyboardInterrupt 1159 1160 # Go to next mirror 1161 self._last_interrupt = now 1162 raise URLGrabError(15, _('user interrupt'))
1163
1164 - def download_callback_total_cb(self, remote_pkgs, remote_size, 1165 download_start_timestamp):
1166 if len(remote_pkgs) <= 1: 1167 return 1168 if not hasattr(urlgrabber.progress, 'TerminalLine'): 1169 return 1170 1171 tl = urlgrabber.progress.TerminalLine(8) 1172 self.verbose_logger.log(logginglevels.INFO_2, "-" * tl.rest()) 1173 dl_time = time.time() - download_start_timestamp 1174 if dl_time <= 0: # This stops divide by zero, among other problems 1175 dl_time = 0.01 1176 ui_size = tl.add(' | %5sB' % self.format_number(remote_size)) 1177 ui_time = tl.add(' %9s' % self.format_time(dl_time)) 1178 ui_end = tl.add(' ' * 5) 1179 ui_bs = tl.add(' %5sB/s' % self.format_number(remote_size / dl_time)) 1180 msg = "%s%s%s%s%s" % (utf8_width_fill(_("Total"), tl.rest(), tl.rest()), 1181 ui_bs, ui_size, ui_time, ui_end) 1182 self.verbose_logger.log(logginglevels.INFO_2, msg)
1183
1184 - def _history_uiactions(self, hpkgs):
1185 actions = set() 1186 count = 0 1187 for hpkg in hpkgs: 1188 st = hpkg.state 1189 if st == 'True-Install': 1190 st = 'Install' 1191 if st == 'Dep-Install': # Mask these at the higher levels 1192 st = 'Install' 1193 if st == 'Obsoleted': # This is just a UI tweak, as we can't have 1194 # just one but we need to count them all. 1195 st = 'Obsoleting' 1196 if st in ('Install', 'Update', 'Erase', 'Reinstall', 'Downgrade', 1197 'Obsoleting'): 1198 actions.add(st) 1199 count += 1 1200 assert len(actions) <= 6 1201 if len(actions) > 1: 1202 large2small = {'Install' : _('I'), 1203 'Obsoleting' : _('O'), 1204 'Erase' : _('E'), 1205 'Reinstall' : _('R'), 1206 'Downgrade' : _('D'), 1207 'Update' : _('U'), 1208 } 1209 return count, ", ".join([large2small[x] for x in sorted(actions)]) 1210 1211 # So empty transactions work, although that "shouldn't" really happen 1212 return count, "".join(list(actions))
1213
1214 - def _pwd_ui_username(self, uid, limit=None):
1215 # loginuid is set to -1 on init. 1216 if uid is None or uid == 0xFFFFFFFF: 1217 loginid = _("<unset>") 1218 name = _("System") + " " + loginid 1219 if limit is not None and len(name) > limit: 1220 name = loginid 1221 return to_unicode(name) 1222 1223 try: 1224 user = pwd.getpwuid(uid) 1225 fullname = user.pw_gecos.split(';', 2)[0] 1226 name = "%s <%s>" % (fullname, user.pw_name) 1227 if limit is not None and len(name) > limit: 1228 name = "%s ... <%s>" % (fullname.split()[0], user.pw_name) 1229 if len(name) > limit: 1230 name = "<%s>" % user.pw_name 1231 return to_unicode(name) 1232 except KeyError: 1233 return to_unicode(str(uid))
1234
1235 - def _history_list_transactions(self, extcmds):
1236 tids = set() 1237 pats = [] 1238 usertids = extcmds[1:] 1239 printall = False 1240 if usertids: 1241 printall = True 1242 if usertids[0] == 'all': 1243 usertids.pop(0) 1244 for tid in usertids: 1245 try: 1246 int(tid) 1247 tids.add(tid) 1248 except ValueError: 1249 pats.append(tid) 1250 if pats: 1251 tids.update(self.history.search(pats)) 1252 1253 if not tids and usertids: 1254 self.logger.critical(_('Bad transaction IDs, or package(s), given')) 1255 return None, None 1256 return tids, printall
1257
1258 - def historyListCmd(self, extcmds):
1259 """ Shows the user a list of data about the history. """ 1260 1261 tids, printall = self._history_list_transactions(extcmds) 1262 if tids is None: 1263 return 1, ['Failed history info'] 1264 1265 fmt = "%s | %s | %s | %s | %s" 1266 print fmt % (utf8_width_fill(_("ID"), 6, 6), 1267 utf8_width_fill(_("Login user"), 22, 22), 1268 utf8_width_fill(_("Date and time"), 16, 16), 1269 utf8_width_fill(_("Action(s)"), 14, 14), 1270 utf8_width_fill(_("Altered"), 7, 7)) 1271 print "-" * 79 1272 fmt = "%6u | %s | %-16.16s | %s | %4u" 1273 done = 0 1274 limit = 20 1275 if printall: 1276 limit = None 1277 for old in self.history.old(tids, limit=limit): 1278 if not printall and done >= limit: 1279 break 1280 1281 done += 1 1282 name = self._pwd_ui_username(old.loginuid, 22) 1283 tm = time.strftime("%Y-%m-%d %H:%M", 1284 time.localtime(old.beg_timestamp)) 1285 num, uiacts = self._history_uiactions(old.trans_data) 1286 name = utf8_width_fill(name, 22, 22) 1287 uiacts = utf8_width_fill(uiacts, 14, 14) 1288 rmark = lmark = ' ' 1289 if old.return_code is None: 1290 rmark = lmark = '*' 1291 elif old.return_code: 1292 rmark = lmark = '#' 1293 if old.altered_lt_rpmdb: 1294 rmark = '<' 1295 if old.altered_gt_rpmdb: 1296 lmark = '>' 1297 print fmt % (old.tid, name, tm, uiacts, num), "%s%s" % (lmark,rmark) 1298 lastdbv = self.history.last() 1299 if lastdbv is None: 1300 self._rpmdb_warn_checks(warn=False) 1301 else: 1302 # If this is the last transaction, is good and it doesn't 1303 # match the current rpmdb ... then mark it as bad. 1304 rpmdbv = self.rpmdb.simpleVersion(main_only=True)[0] 1305 if lastdbv.end_rpmdbversion != rpmdbv: 1306 self._rpmdb_warn_checks()
1307
1308 - def _history_get_transactions(self, extcmds):
1309 if len(extcmds) < 2: 1310 self.logger.critical(_('No transaction ID given')) 1311 return None 1312 1313 tids = [] 1314 last = None 1315 for extcmd in extcmds[1:]: 1316 try: 1317 if extcmd == 'last' or extcmd.startswith('last-'): 1318 if last is None: 1319 cto = False 1320 last = self.history.last(complete_transactions_only=cto) 1321 if last is None: 1322 int("z") 1323 tid = last.tid 1324 if extcmd.startswith('last-'): 1325 off = int(extcmd[len('last-'):]) 1326 if off <= 0: 1327 int("z") 1328 tid -= off 1329 tids.append(str(tid)) 1330 continue 1331 1332 if int(extcmd) <= 0: 1333 int("z") 1334 tids.append(extcmd) 1335 except ValueError: 1336 self.logger.critical(_('Bad transaction ID given')) 1337 return None 1338 1339 old = self.history.old(tids) 1340 if not old: 1341 self.logger.critical(_('Not found given transaction ID')) 1342 return None 1343 return old
1344 - def _history_get_transaction(self, extcmds):
1345 old = self._history_get_transactions(extcmds) 1346 if old is None: 1347 return None 1348 if len(old) > 1: 1349 self.logger.critical(_('Found more than one transaction ID!')) 1350 return old[0]
1351
1352 - def historyInfoCmd(self, extcmds):
1353 tids = set() 1354 pats = [] 1355 for tid in extcmds[1:]: 1356 try: 1357 int(tid) 1358 tids.add(tid) 1359 except ValueError: 1360 pats.append(tid) 1361 if pats: 1362 tids.update(self.history.search(pats)) 1363 1364 if not tids and len(extcmds) < 2: 1365 old = self.history.last(complete_transactions_only=False) 1366 if old is not None: 1367 tids.add(old.tid) 1368 1369 if not tids: 1370 self.logger.critical(_('No transaction ID, or package, given')) 1371 return 1, ['Failed history info'] 1372 1373 lastdbv = self.history.last() 1374 if lastdbv is not None: 1375 lasttid = lastdbv.tid 1376 lastdbv = lastdbv.end_rpmdbversion 1377 1378 done = False 1379 for tid in self.history.old(tids): 1380 if lastdbv is not None and tid.tid == lasttid: 1381 # If this is the last transaction, is good and it doesn't 1382 # match the current rpmdb ... then mark it as bad. 1383 rpmdbv = self.rpmdb.simpleVersion(main_only=True)[0] 1384 if lastdbv != rpmdbv: 1385 tid.altered_gt_rpmdb = True 1386 lastdbv = None 1387 1388 if done: 1389 print "-" * 79 1390 done = True 1391 self._historyInfoCmd(tid, pats)
1392
1393 - def _historyInfoCmd(self, old, pats=[]):
1394 name = self._pwd_ui_username(old.loginuid) 1395 1396 print _("Transaction ID :"), old.tid 1397 begtm = time.ctime(old.beg_timestamp) 1398 print _("Begin time :"), begtm 1399 if old.beg_rpmdbversion is not None: 1400 if old.altered_lt_rpmdb: 1401 print _("Begin rpmdb :"), old.beg_rpmdbversion, "**" 1402 else: 1403 print _("Begin rpmdb :"), old.beg_rpmdbversion 1404 if old.end_timestamp is not None: 1405 endtm = time.ctime(old.end_timestamp) 1406 endtms = endtm.split() 1407 if begtm.startswith(endtms[0]): # Chop uninteresting prefix 1408 begtms = begtm.split() 1409 sofar = 0 1410 for i in range(len(endtms)): 1411 if i > len(begtms): 1412 break 1413 if begtms[i] != endtms[i]: 1414 break 1415 sofar += len(begtms[i]) + 1 1416 endtm = (' ' * sofar) + endtm[sofar:] 1417 diff = _("(%s seconds)") % (old.end_timestamp - old.beg_timestamp) 1418 print _("End time :"), endtm, diff 1419 if old.end_rpmdbversion is not None: 1420 if old.altered_gt_rpmdb: 1421 print _("End rpmdb :"), old.end_rpmdbversion, "**" 1422 else: 1423 print _("End rpmdb :"), old.end_rpmdbversion 1424 print _("User :"), name 1425 if old.return_code is None: 1426 print _("Return-Code :"), "**", _("Aborted"), "**" 1427 elif old.return_code: 1428 print _("Return-Code :"), _("Failure:"), old.return_code 1429 else: 1430 print _("Return-Code :"), _("Success") 1431 print _("Transaction performed with:") 1432 for hpkg in old.trans_with: 1433 prefix = " " * 4 1434 state = _('Installed') 1435 ipkgs = self.rpmdb.searchNames([hpkg.name]) 1436 ipkgs.sort() 1437 if not ipkgs: 1438 state = _('Erased') 1439 elif hpkg.pkgtup in (ipkg.pkgtup for ipkg in ipkgs): 1440 pass 1441 elif ipkgs[-1] > hpkg: 1442 state = _('Updated') 1443 elif ipkgs[0] < hpkg: 1444 state = _('Downgraded') 1445 else: # multiple versions installed, both older and newer 1446 state = _('Weird') 1447 print "%s%s %s" % (prefix, utf8_width_fill(state, 12), hpkg) 1448 print _("Packages Altered:") 1449 self.historyInfoCmdPkgsAltered(old, pats) 1450 if old.output: 1451 print _("Scriptlet output:") 1452 num = 0 1453 for line in old.output: 1454 num += 1 1455 print "%4d" % num, line 1456 if old.errors: 1457 print _("Errors:") 1458 num = 0 1459 for line in old.errors: 1460 num += 1 1461 print "%4d" % num, line
1462
1463 - def historyInfoCmdPkgsAltered(self, old, pats=[]):
1464 last = None 1465 for hpkg in old.trans_data: 1466 prefix = " " * 4 1467 if not hpkg.done: 1468 prefix = " ** " 1469 1470 highlight = 'normal' 1471 if pats: 1472 x,m,u = yum.packages.parsePackages([hpkg], pats) 1473 if x or m: 1474 highlight = 'bold' 1475 (hibeg, hiend) = self._highlight(highlight) 1476 1477 # To chop the name off we need nevra strings, str(pkg) gives envra 1478 # so we have to do it by hand ... *sigh*. 1479 cn = hpkg.ui_nevra 1480 1481 uistate = {'True-Install' : _('Install'), 1482 'Install' : _('Install'), 1483 'Dep-Install' : _('Dep-Install'), 1484 'Obsoleted' : _('Obsoleted'), 1485 'Obsoleting' : _('Obsoleting'), 1486 'Erase' : _('Erase'), 1487 'Reinstall' : _('Reinstall'), 1488 'Downgrade' : _('Downgrade'), 1489 'Downgraded' : _('Downgraded'), 1490 'Update' : _('Update'), 1491 'Updated' : _('Updated'), 1492 }.get(hpkg.state, hpkg.state) 1493 uistate = utf8_width_fill(uistate, 12, 12) 1494 # Should probably use columns here... 1495 if False: pass 1496 elif (last is not None and 1497 last.state == 'Updated' and last.name == hpkg.name and 1498 hpkg.state == 'Update'): 1499 ln = len(hpkg.name) + 1 1500 cn = (" " * ln) + cn[ln:] 1501 print "%s%s%s%s %s" % (prefix, hibeg, uistate, hiend, cn) 1502 elif (last is not None and 1503 last.state == 'Downgrade' and last.name == hpkg.name and 1504 hpkg.state == 'Downgraded'): 1505 ln = len(hpkg.name) + 1 1506 cn = (" " * ln) + cn[ln:] 1507 print "%s%s%s%s %s" % (prefix, hibeg, uistate, hiend, cn) 1508 else: 1509 last = None 1510 if hpkg.state in ('Updated', 'Downgrade'): 1511 last = hpkg 1512 print "%s%s%s%s %s" % (prefix, hibeg, uistate, hiend, cn)
1513
1514 - def historySummaryCmd(self, extcmds):
1515 tids, printall = self._history_list_transactions(extcmds) 1516 if tids is None: 1517 return 1, ['Failed history info'] 1518 1519 fmt = "%s | %s | %s | %s" 1520 print fmt % (utf8_width_fill(_("Login user"), 26, 26), 1521 utf8_width_fill(_("Time"), 19, 19), 1522 utf8_width_fill(_("Action(s)"), 16, 16), 1523 utf8_width_fill(_("Altered"), 8, 8)) 1524 print "-" * 79 1525 fmt = "%s | %s | %s | %8u" 1526 data = {'day' : {}, 'week' : {}, 1527 'fortnight' : {}, 'quarter' : {}, 'half' : {}, 1528 'year' : {}, 'all' : {}} 1529 for old in self.history.old(tids): 1530 name = self._pwd_ui_username(old.loginuid, 26) 1531 period = 'all' 1532 now = time.time() 1533 if False: pass 1534 elif old.beg_timestamp > (now - (24 * 60 * 60)): 1535 period = 'day' 1536 elif old.beg_timestamp > (now - (24 * 60 * 60 * 7)): 1537 period = 'week' 1538 elif old.beg_timestamp > (now - (24 * 60 * 60 * 14)): 1539 period = 'fortnight' 1540 elif old.beg_timestamp > (now - (24 * 60 * 60 * 7 * 13)): 1541 period = 'quarter' 1542 elif old.beg_timestamp > (now - (24 * 60 * 60 * 7 * 26)): 1543 period = 'half' 1544 elif old.beg_timestamp > (now - (24 * 60 * 60 * 365)): 1545 period = 'year' 1546 data[period].setdefault(name, []).append(old) 1547 _period2user = {'day' : _("Last day"), 1548 'week' : _("Last week"), 1549 'fortnight' : _("Last 2 weeks"), # US default :p 1550 'quarter' : _("Last 3 months"), 1551 'half' : _("Last 6 months"), 1552 'year' : _("Last year"), 1553 'all' : _("Over a year ago")} 1554 done = 0 1555 for period in ('day', 'week', 'fortnight', 'quarter', 'half', 'year', 1556 'all'): 1557 if not data[period]: 1558 continue 1559 for name in sorted(data[period]): 1560 if not printall and done > 19: 1561 break 1562 done += 1 1563 1564 hpkgs = [] 1565 for old in data[period][name]: 1566 hpkgs.extend(old.trans_data) 1567 count, uiacts = self._history_uiactions(hpkgs) 1568 uperiod = _period2user[period] 1569 # Should probably use columns here, esp. for uiacts? 1570 print fmt % (utf8_width_fill(name, 22, 22), 1571 utf8_width_fill(uperiod, 19, 19), 1572 utf8_width_fill(uiacts, 16, 16), count)
1573
1574 1575 -class DepSolveProgressCallBack:
1576 """provides text output callback functions for Dependency Solver callback""" 1577
1578 - def __init__(self, ayum=None):
1579 """requires yum-cli log and errorlog functions as arguments""" 1580 self.verbose_logger = logging.getLogger("yum.verbose.cli") 1581 self.loops = 0 1582 self.ayum = ayum
1583
1584 - def pkgAdded(self, pkgtup, mode):
1585 modedict = { 'i': _('installed'), 1586 'u': _('updated'), 1587 'o': _('obsoleted'), 1588 'e': _('erased')} 1589 (n, a, e, v, r) = pkgtup 1590 modeterm = modedict[mode] 1591 self.verbose_logger.log(logginglevels.INFO_2, 1592 _('---> Package %s.%s %s:%s-%s set to be %s'), n, a, e, v, r, 1593 modeterm)
1594
1595 - def start(self):
1596 self.loops += 1
1597
1598 - def tscheck(self):
1599 self.verbose_logger.log(logginglevels.INFO_2, _('--> Running transaction check'))
1600
1601 - def restartLoop(self):
1602 self.loops += 1 1603 self.verbose_logger.log(logginglevels.INFO_2, 1604 _('--> Restarting Dependency Resolution with new changes.')) 1605 self.verbose_logger.debug('---> Loop Number: %d', self.loops)
1606
1607 - def end(self):
1608 self.verbose_logger.log(logginglevels.INFO_2, 1609 _('--> Finished Dependency Resolution'))
1610 1611
1612 - def procReq(self, name, formatted_req):
1613 self.verbose_logger.log(logginglevels.INFO_2, 1614 _('--> Processing Dependency: %s for package: %s'), formatted_req, 1615 name)
1616
1617 - def procReqPo(self, po, formatted_req):
1618 self.verbose_logger.log(logginglevels.INFO_2, 1619 _('--> Processing Dependency: %s for package: %s'), formatted_req, 1620 po)
1621
1622 - def unresolved(self, msg):
1623 self.verbose_logger.log(logginglevels.INFO_2, _('--> Unresolved Dependency: %s'), 1624 msg)
1625
1626 - def format_missing_requires(self, reqPo, reqTup):
1627 """ Create a message for errorlist, non-cli users could also store this 1628 data somewhere and not print errorlist. """ 1629 needname, needflags, needversion = reqTup 1630 1631 yb = self.ayum 1632 1633 prob_pkg = "%s (%s)" % (reqPo, reqPo.ui_from_repo) 1634 msg = _('Package: %s') % (prob_pkg,) 1635 ui_req = formatRequire(needname, needversion, needflags) 1636 msg += _('\n Requires: %s') % (ui_req,) 1637 1638 # if DepSolveProgressCallback() is used instead of DepSolveProgressCallback(ayum=<YumBase Object>) 1639 # then ayum has no value and we can't continue to find details about the missing requirements 1640 if not yb: 1641 return msg 1642 1643 ipkgs = set() 1644 for pkg in sorted(yb.rpmdb.getProvides(needname)): 1645 ipkgs.add(pkg.pkgtup) 1646 action = _('Installed') 1647 if yb.tsInfo.getMembersWithState(pkg.pkgtup, TS_REMOVE_STATES): 1648 action = _('Removing') 1649 msg += _('\n %s: %s (%s)') % (action, pkg, pkg.ui_from_repo) 1650 last = None 1651 for pkg in sorted(yb.pkgSack.getProvides(needname)): 1652 # We don't want to see installed packages, or N packages of the 1653 # same version, from different repos. 1654 if pkg.pkgtup in ipkgs or pkg.verEQ(last): 1655 continue 1656 last = pkg 1657 action = _('Available') 1658 if yb.tsInfo.getMembersWithState(pkg.pkgtup, TS_INSTALL_STATES): 1659 action = _('Installing') 1660 msg += _('\n %s: %s (%s)') % (action, pkg, pkg.repoid) 1661 return msg
1662
1663 - def procConflict(self, name, confname):
1664 self.verbose_logger.log(logginglevels.INFO_2, 1665 _('--> Processing Conflict: %s conflicts %s'), 1666 name, confname)
1667
1668 - def procConflictPo(self, po, confname):
1669 self.verbose_logger.log(logginglevels.INFO_2, 1670 _('--> Processing Conflict: %s conflicts %s'), 1671 po, confname)
1672
1673 - def transactionPopulation(self):
1674 self.verbose_logger.log(logginglevels.INFO_2, _('--> Populating transaction set ' 1675 'with selected packages. Please wait.'))
1676
1677 - def downloadHeader(self, name):
1678 self.verbose_logger.log(logginglevels.INFO_2, _('---> Downloading header for %s ' 1679 'to pack into transaction set.'), name)
1680
1681 1682 -class CacheProgressCallback:
1683 1684 ''' 1685 The class handles text output callbacks during metadata cache updates. 1686 ''' 1687
1688 - def __init__(self):
1689 self.logger = logging.getLogger("yum.cli") 1690 self.verbose_logger = logging.getLogger("yum.verbose.cli") 1691 self.file_logger = logging.getLogger("yum.filelogging.cli")
1692
1693 - def log(self, level, message):
1694 self.verbose_logger.log(level, message)
1695
1696 - def errorlog(self, level, message):
1697 self.logger.log(level, message)
1698
1699 - def filelog(self, level, message):
1700 self.file_logger.log(level, message)
1701
1702 - def progressbar(self, current, total, name=None):
1703 progressbar(current, total, name)
1704
1705 -def _pkgname_ui(ayum, pkgname, ts_states=None):
1706 """ Get more information on a simple pkgname, if we can. We need to search 1707 packages that we are dealing with atm. and installed packages (if the 1708 transaction isn't complete). """ 1709 if ayum is None: 1710 return pkgname 1711 1712 if ts_states is None: 1713 # Note 'd' is a placeholder for downgrade, and 1714 # 'r' is a placeholder for reinstall. Neither exist atm. 1715 ts_states = ('d', 'e', 'i', 'r', 'u') 1716 1717 matches = [] 1718 def _cond_add(po): 1719 if matches and matches[0].arch == po.arch and matches[0].verEQ(po): 1720 return 1721 matches.append(po)
1722 1723 for txmbr in ayum.tsInfo.matchNaevr(name=pkgname): 1724 if txmbr.ts_state not in ts_states: 1725 continue 1726 _cond_add(txmbr.po) 1727 1728 if not matches: 1729 return pkgname 1730 fmatch = matches.pop(0) 1731 if not matches: 1732 return str(fmatch) 1733 1734 show_ver = True 1735 show_arch = True 1736 for match in matches: 1737 if not fmatch.verEQ(match): 1738 show_ver = False 1739 if fmatch.arch != match.arch: 1740 show_arch = False 1741 1742 if show_ver: # Multilib. *sigh* 1743 if fmatch.epoch == '0': 1744 return '%s-%s-%s' % (fmatch.name, fmatch.version, fmatch.release) 1745 else: 1746 return '%s:%s-%s-%s' % (fmatch.epoch, fmatch.name, 1747 fmatch.version, fmatch.release) 1748 1749 if show_arch: 1750 return '%s.%s' % (fmatch.name, fmatch.arch) 1751 1752 return pkgname 1753
1754 -class YumCliRPMCallBack(RPMBaseCallback):
1755 1756 """ 1757 Yum specific callback class for RPM operations. 1758 """ 1759 1760 width = property(lambda x: _term_width()) 1761
1762 - def __init__(self, ayum=None):
1763 RPMBaseCallback.__init__(self) 1764 self.lastmsg = to_unicode("") 1765 self.lastpackage = None # name of last package we looked at 1766 self.output = logging.getLogger("yum.verbose.cli").isEnabledFor(logginglevels.INFO_2) 1767 1768 # for a progress bar 1769 self.mark = "#" 1770 self.marks = 22 1771 self.ayum = ayum
1772 1773 # Installing things have pkg objects passed to the events, so only need to 1774 # lookup for erased/obsoleted.
1775 - def pkgname_ui(self, pkgname, ts_states=('e', None)):
1776 """ Get more information on a simple pkgname, if we can. """ 1777 return _pkgname_ui(self.ayum, pkgname, ts_states)
1778
1779 - def event(self, package, action, te_current, te_total, ts_current, ts_total):
1780 # this is where a progress bar would be called 1781 process = self.action[action] 1782 1783 if type(package) not in types.StringTypes: 1784 pkgname = str(package) 1785 else: 1786 pkgname = self.pkgname_ui(package) 1787 1788 self.lastpackage = package 1789 if te_total == 0: 1790 percent = 0 1791 else: 1792 percent = (te_current*100L)/te_total 1793 1794 if self.output and (sys.stdout.isatty() or te_current == te_total): 1795 (fmt, wid1, wid2) = self._makefmt(percent, ts_current, ts_total, 1796 pkgname=pkgname) 1797 msg = fmt % (utf8_width_fill(process, wid1, wid1), 1798 utf8_width_fill(pkgname, wid2, wid2)) 1799 if msg != self.lastmsg: 1800 sys.stdout.write(to_unicode(msg)) 1801 sys.stdout.flush() 1802 self.lastmsg = msg 1803 if te_current == te_total: 1804 print " "
1805
1806 - def scriptout(self, package, msgs):
1807 if msgs: 1808 sys.stdout.write(to_unicode(msgs)) 1809 sys.stdout.flush()
1810
1811 - def _makefmt(self, percent, ts_current, ts_total, progress = True, 1812 pkgname=None):
1813 l = len(str(ts_total)) 1814 size = "%s.%s" % (l, l) 1815 fmt_done = "%" + size + "s/%" + size + "s" 1816 done = fmt_done % (ts_current, ts_total) 1817 1818 # This should probably use TerminLine, but we don't want to dep. on 1819 # that. So we kind do an ok job by hand ... at least it's dynamic now. 1820 if pkgname is None: 1821 pnl = 22 1822 else: 1823 pnl = utf8_width(pkgname) 1824 1825 overhead = (2 * l) + 2 # Length of done, above 1826 overhead += 19 # Length of begining 1827 overhead += 1 # Space between pn and done 1828 overhead += 2 # Ends for progress 1829 overhead += 1 # Space for end 1830 width = self.width 1831 if width < overhead: 1832 width = overhead # Give up 1833 width -= overhead 1834 if pnl > width / 2: 1835 pnl = width / 2 1836 1837 marks = self.width - (overhead + pnl) 1838 width = "%s.%s" % (marks, marks) 1839 fmt_bar = "[%-" + width + "s]" 1840 # pnl = str(28 + marks + 1) 1841 full_pnl = pnl + marks + 1 1842 1843 if progress and percent == 100: # Don't chop pkg name on 100% 1844 fmt = "\r %s: %s " + done 1845 wid2 = full_pnl 1846 elif progress: 1847 bar = fmt_bar % (self.mark * int(marks * (percent / 100.0)), ) 1848 fmt = "\r %s: %s " + bar + " " + done 1849 wid2 = pnl 1850 elif percent == 100: 1851 fmt = " %s: %s " + done 1852 wid2 = full_pnl 1853 else: 1854 bar = fmt_bar % (self.mark * marks, ) 1855 fmt = " %s: %s " + bar + " " + done 1856 wid2 = pnl 1857 return fmt, 15, wid2
1858
1859 1860 -def progressbar(current, total, name=None):
1861 """simple progress bar 50 # marks""" 1862 1863 mark = '#' 1864 if not sys.stdout.isatty(): 1865 return 1866 1867 if current == 0: 1868 percent = 0 1869 else: 1870 if total != 0: 1871 percent = float(current) / total 1872 else: 1873 percent = 0 1874 1875 width = _term_width() 1876 1877 if name is None and current == total: 1878 name = '-' 1879 1880 end = ' %d/%d' % (current, total) 1881 width -= len(end) + 1 1882 if width < 0: 1883 width = 0 1884 if name is None: 1885 width -= 2 1886 if width < 0: 1887 width = 0 1888 hashbar = mark * int(width * percent) 1889 output = '\r[%-*s]%s' % (width, hashbar, end) 1890 elif current == total: # Don't chop name on 100% 1891 output = '\r%s%s' % (utf8_width_fill(name, width, width), end) 1892 else: 1893 width -= 4 1894 if width < 0: 1895 width = 0 1896 nwid = width / 2 1897 if nwid > utf8_width(name): 1898 nwid = utf8_width(name) 1899 width -= nwid 1900 hashbar = mark * int(width * percent) 1901 output = '\r%s: [%-*s]%s' % (utf8_width_fill(name, nwid, nwid), width, 1902 hashbar, end) 1903 1904 if current <= total: 1905 sys.stdout.write(output) 1906 1907 if current == total: 1908 sys.stdout.write('\n') 1909 1910 sys.stdout.flush()
1911 1912 1913 if __name__ == "__main__": 1914 if len(sys.argv) > 1 and sys.argv[1] == "format_number": 1915 print "" 1916 print " Doing format_number tests, right column should align" 1917 print "" 1918 1919 x = YumOutput() 1920 for i in (0, 0.0, 0.1, 1, 1.0, 1.1, 10, 11, 11.1, 100, 111.1, 1921 1000, 1111, 1024 * 2, 10000, 11111, 99999, 999999, 1922 10**19, 10**20, 10**35): 1923 out = x.format_number(i) 1924 print "%36s <%s> %s <%5s>" % (i, out, ' ' * (14 - len(out)), out) 1925 1926 if len(sys.argv) > 1 and sys.argv[1] == "progress": 1927 print "" 1928 print " Doing progress, small name" 1929 print "" 1930 for i in xrange(0, 101): 1931 progressbar(i, 100, "abcd") 1932 time.sleep(0.1) 1933 print "" 1934 print " Doing progress, big name" 1935 print "" 1936 for i in xrange(0, 101): 1937 progressbar(i, 100, "_%s_" % ("123456789 " * 5)) 1938 time.sleep(0.1) 1939 print "" 1940 print " Doing progress, no name" 1941 print "" 1942 for i in xrange(0, 101): 1943 progressbar(i, 100) 1944 time.sleep(0.1) 1945 1946 if len(sys.argv) > 1 and sys.argv[1] in ("progress", "rpm-progress"): 1947 cb = YumCliRPMCallBack() 1948 cb.output = True 1949 cb.action["foo"] = "abcd" 1950 cb.action["bar"] = "_12345678_.end" 1951 print "" 1952 print " Doing CB, small proc / small pkg" 1953 print "" 1954 for i in xrange(0, 101): 1955 cb.event("spkg", "foo", i, 100, i, 100) 1956 time.sleep(0.1) 1957 print "" 1958 print " Doing CB, big proc / big pkg" 1959 print "" 1960 for i in xrange(0, 101): 1961 cb.event("lpkg" + "-=" * 15 + ".end", "bar", i, 100, i, 100) 1962 time.sleep(0.1) 1963 1964 if len(sys.argv) > 1 and sys.argv[1] in ("progress", "i18n-progress", 1965 "rpm-progress", 1966 'i18n-rpm-progress'): 1967 yum.misc.setup_locale() 1968 if len(sys.argv) > 1 and sys.argv[1] in ("progress", "i18n-progress"): 1969 print "" 1970 print " Doing progress, i18n: small name" 1971 print "" 1972 for i in xrange(0, 101): 1973 progressbar(i, 100, to_unicode('\xe6\xad\xa3\xe5\x9c\xa8\xe5\xae\x89\xe8\xa3\x85')) 1974 time.sleep(0.1) 1975 print "" 1976 1977 print "" 1978 print " Doing progress, i18n: big name" 1979 print "" 1980 for i in xrange(0, 101): 1981 progressbar(i, 100, to_unicode('\xe6\xad\xa3\xe5\x9c\xa8\xe5\xae\x89\xe8\xa3\x85' * 5 + ".end")) 1982 time.sleep(0.1) 1983 print "" 1984 1985 1986 if len(sys.argv) > 1 and sys.argv[1] in ("progress", "i18n-progress", 1987 "rpm-progress", 1988 'i18n-rpm-progress'): 1989 cb = YumCliRPMCallBack() 1990 cb.output = True 1991 cb.action["foo"] = to_unicode('\xe6\xad\xa3\xe5\x9c\xa8\xe5\xae\x89\xe8\xa3\x85') 1992 cb.action["bar"] = cb.action["foo"] * 5 + ".end" 1993 print "" 1994 print " Doing CB, i18n: small proc / small pkg" 1995 print "" 1996 for i in xrange(0, 101): 1997 cb.event("spkg", "foo", i, 100, i, 100) 1998 time.sleep(0.1) 1999 print "" 2000 print " Doing CB, i18n: big proc / big pkg" 2001 print "" 2002 for i in xrange(0, 101): 2003 cb.event("lpkg" + "-=" * 15 + ".end", "bar", i, 100, i, 100) 2004 time.sleep(0.1) 2005 print "" 2006