1
2
3 """This handles actual output from the cli"""
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
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
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
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
71 """some terminal "UI" helpers based on curses"""
72
73
74
75
76
77
78
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
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
156 self.MODE = {
157 'bold' : '',
158 'blink' : '',
159 'dim' : '',
160 'reverse' : '',
161 'underline' : '',
162 'normal' : ''
163 }
164
165
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
194 try:
195 import curses
196 except:
197 self.__enabled = False
198 return
199
200
201 if not term_stream:
202 term_stream = sys.stdout
203 if not term_stream.isatty():
204 self.__enabled = False
205 return
206
207
208
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
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
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'):
247
249
250
251
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
287
288 """
289 Main output class for the yum command line.
290 """
291
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
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
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
322
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
332 else:
333
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
354 hibeg, hiend = self._highlight(highlight)
355 return self.term.sub(haystack, hibeg, hiend, needles, **kwds)
356
357 @staticmethod
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
377 pdata = data
378 data = [None] * cols
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
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
401
402 if helps:
403 diff = data[val].pop(0)[0] - columns[val]
404 columns[val] += diff
405 total_width -= diff
406 continue
407
408
409
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
424
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
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:
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)
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)
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
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
503 ret = utf8_text_fill(val, width=cols,
504 initial_indent=key,
505 subsequent_indent=' ...: ')
506 return ret
507
519
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
556
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
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
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
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
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
653
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
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
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
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
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
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
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
800
801 @staticmethod
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
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
866
910
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
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:
927 a = 'noarch'
928
929
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
938
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):
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:
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
1033 out = ''
1034
1035 self.tsInfo.makelists()
1036
1037
1038
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
1120
1124
1128
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
1140 delta_exit_str = _("two")
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
1148
1149
1150
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
1158 raise KeyboardInterrupt
1159
1160
1161 self._last_interrupt = now
1162 raise URLGrabError(15, _('user interrupt'))
1163
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:
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':
1192 st = 'Install'
1193 if st == 'Obsoleted':
1194
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
1212 return count, "".join(list(actions))
1213
1215
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
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
1303
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
1382
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]):
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:
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
1478
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
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"),
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
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
1576 """provides text output callback functions for Dependency Solver callback"""
1577
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
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
1597
1600
1606
1610
1611
1612 - def procReq(self, name, formatted_req):
1616
1621
1625
1662
1667
1672
1676
1680
1683
1684 '''
1685 The class handles text output callbacks during metadata cache updates.
1686 '''
1687
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):
1695
1698
1699 - def filelog(self, level, message):
1700 self.file_logger.log(level, message)
1701
1704
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
1714
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:
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
1755
1756 """
1757 Yum specific callback class for RPM operations.
1758 """
1759
1760 width = property(lambda x: _term_width())
1761
1772
1773
1774
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
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
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
1819
1820 if pkgname is None:
1821 pnl = 22
1822 else:
1823 pnl = utf8_width(pkgname)
1824
1825 overhead = (2 * l) + 2
1826 overhead += 19
1827 overhead += 1
1828 overhead += 2
1829 overhead += 1
1830 width = self.width
1831 if width < overhead:
1832 width = overhead
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
1841 full_pnl = pnl + marks + 1
1842
1843 if progress and percent == 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
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:
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