source: yum/vendor/yum-3.2.27/yumcommands.py@ 2

Last change on this file since 2 was 2, checked in by Yuri Dario, 15 years ago

Initial import for vendor code.

  • Property svn:eol-style set to native
File size: 47.6 KB
Line 
1#!/usr/bin/python -t
2# This program is free software; you can redistribute it and/or modify
3# it under the terms of the GNU General Public License as published by
4# the Free Software Foundation; either version 2 of the License, or
5# (at your option) any later version.
6#
7# This program is distributed in the hope that it will be useful,
8# but WITHOUT ANY WARRANTY; without even the implied warranty of
9# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
10# GNU Library General Public License for more details.
11#
12# You should have received a copy of the GNU General Public License
13# along with this program; if not, write to the Free Software
14# Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
15# Copyright 2006 Duke University
16# Written by Seth Vidal
17
18"""
19Classes for subcommands of the yum command line interface.
20"""
21
22import os
23import cli
24from yum import logginglevels
25from yum import _
26from yum import misc
27import yum.Errors
28import operator
29import locale
30import fnmatch
31import time
32from yum.i18n import utf8_width, utf8_width_fill, to_unicode
33
34import yum.config
35
36def checkRootUID(base):
37 """
38 Verify that the program is being run by the root user.
39
40 @param base: a YumBase object.
41 """
42 if base.conf.uid != 0:
43 base.logger.critical(_('You need to be root to perform this command.'))
44 raise cli.CliError
45
46def checkGPGKey(base):
47 if not base.gpgKeyCheck():
48 for repo in base.repos.listEnabled():
49 if (repo.gpgcheck or repo.repo_gpgcheck) and repo.gpgkey == '':
50 msg = _("""
51You have enabled checking of packages via GPG keys. This is a good thing.
52However, you do not have any GPG public keys installed. You need to download
53the keys for packages you wish to install and install them.
54You can do that by running the command:
55 rpm --import public.gpg.key
56
57
58Alternatively you can specify the url to the key you would like to use
59for a repository in the 'gpgkey' option in a repository section and yum
60will install it for you.
61
62For more information contact your distribution or package provider.
63""")
64 base.logger.critical(msg)
65 raise cli.CliError
66
67def checkPackageArg(base, basecmd, extcmds):
68 if len(extcmds) == 0:
69 base.logger.critical(
70 _('Error: Need to pass a list of pkgs to %s') % basecmd)
71 base.usage()
72 raise cli.CliError
73
74def checkItemArg(base, basecmd, extcmds):
75 if len(extcmds) == 0:
76 base.logger.critical(_('Error: Need an item to match'))
77 base.usage()
78 raise cli.CliError
79
80def checkGroupArg(base, basecmd, extcmds):
81 if len(extcmds) == 0:
82 base.logger.critical(_('Error: Need a group or list of groups'))
83 base.usage()
84 raise cli.CliError
85
86def checkCleanArg(base, basecmd, extcmds):
87 VALID_ARGS = ('headers', 'packages', 'metadata', 'dbcache', 'plugins',
88 'expire-cache', 'rpmdb', 'all')
89
90 if len(extcmds) == 0:
91 base.logger.critical(_('Error: clean requires an option: %s') % (
92 ", ".join(VALID_ARGS)))
93
94 for cmd in extcmds:
95 if cmd not in VALID_ARGS:
96 base.logger.critical(_('Error: invalid clean argument: %r') % cmd)
97 base.usage()
98 raise cli.CliError
99
100def checkShellArg(base, basecmd, extcmds):
101 """
102 Verify that the arguments given to 'yum shell' are valid.
103
104 yum shell can be given either no args, or exactly one argument,
105 which is the name of a file. If these are not met,
106 raise cli.CliError.
107 """
108 if len(extcmds) == 0:
109 base.verbose_logger.debug(_("No argument to shell"))
110 elif len(extcmds) == 1:
111 base.verbose_logger.debug(_("Filename passed to shell: %s"),
112 extcmds[0])
113 if not os.path.isfile(extcmds[0]):
114 base.logger.critical(
115 _("File %s given as argument to shell does not exist."),
116 extcmds[0])
117 base.usage()
118 raise cli.CliError
119 else:
120 base.logger.critical(
121 _("Error: more than one file given as argument to shell."))
122 base.usage()
123 raise cli.CliError
124
125class YumCommand:
126
127 def __init__(self):
128 self.done_command_once = False
129
130 def doneCommand(self, base, msg, *args):
131 if not self.done_command_once:
132 base.verbose_logger.log(logginglevels.INFO_2, msg, *args)
133 self.done_command_once = True
134
135 def getNames(self):
136 return []
137
138 def getUsage(self):
139 """
140 @return: A usage string for the command, including arguments.
141 """
142 raise NotImplementedError
143
144 def getSummary(self):
145 """
146 @return: A one line summary of what the command does.
147 """
148 raise NotImplementedError
149
150 def doCheck(self, base, basecmd, extcmds):
151 pass
152
153 def doCommand(self, base, basecmd, extcmds):
154 """
155 @return: (exit_code, [ errors ]) where exit_code is:
156 0 = we're done, exit
157 1 = we've errored, exit with error string
158 2 = we've got work yet to do, onto the next stage
159 """
160 return 0, [_('Nothing to do')]
161
162 def needTs(self, base, basecmd, extcmds):
163 return True
164
165class InstallCommand(YumCommand):
166 def getNames(self):
167 return ['install']
168
169 def getUsage(self):
170 return _("PACKAGE...")
171
172 def getSummary(self):
173 return _("Install a package or packages on your system")
174
175 def doCheck(self, base, basecmd, extcmds):
176 checkRootUID(base)
177 checkGPGKey(base)
178 checkPackageArg(base, basecmd, extcmds)
179
180 def doCommand(self, base, basecmd, extcmds):
181 self.doneCommand(base, _("Setting up Install Process"))
182 try:
183 return base.installPkgs(extcmds)
184 except yum.Errors.YumBaseError, e:
185 return 1, [str(e)]
186
187class UpdateCommand(YumCommand):
188 def getNames(self):
189 return ['update']
190
191 def getUsage(self):
192 return _("[PACKAGE...]")
193
194 def getSummary(self):
195 return _("Update a package or packages on your system")
196
197 def doCheck(self, base, basecmd, extcmds):
198 checkRootUID(base)
199 checkGPGKey(base)
200
201 def doCommand(self, base, basecmd, extcmds):
202 self.doneCommand(base, _("Setting up Update Process"))
203 try:
204 return base.updatePkgs(extcmds)
205 except yum.Errors.YumBaseError, e:
206 return 1, [str(e)]
207
208def _add_pkg_simple_list_lens(data, pkg, indent=''):
209 """ Get the length of each pkg's column. Add that to data.
210 This "knows" about simpleList and printVer. """
211 na = len(pkg.name) + 1 + len(pkg.arch) + len(indent)
212 ver = len(pkg.version) + 1 + len(pkg.release)
213 rid = len(pkg.ui_from_repo)
214 if pkg.epoch != '0':
215 ver += len(pkg.epoch) + 1
216 for (d, v) in (('na', na), ('ver', ver), ('rid', rid)):
217 data[d].setdefault(v, 0)
218 data[d][v] += 1
219
220def _list_cmd_calc_columns(base, ypl):
221 """ Work out the dynamic size of the columns to pass to fmtColumns. """
222 data = {'na' : {}, 'ver' : {}, 'rid' : {}}
223 for lst in (ypl.installed, ypl.available, ypl.extras,
224 ypl.updates, ypl.recent):
225 for pkg in lst:
226 _add_pkg_simple_list_lens(data, pkg)
227 if len(ypl.obsoletes) > 0:
228 for (npkg, opkg) in ypl.obsoletesTuples:
229 _add_pkg_simple_list_lens(data, npkg)
230 _add_pkg_simple_list_lens(data, opkg, indent=" " * 4)
231
232 data = [data['na'], data['ver'], data['rid']]
233 columns = base.calcColumns(data, remainder_column=1)
234 return (-columns[0], -columns[1], -columns[2])
235
236class InfoCommand(YumCommand):
237 def getNames(self):
238 return ['info']
239
240 def getUsage(self):
241 return "[PACKAGE|all|installed|updates|extras|obsoletes|recent]"
242
243 def getSummary(self):
244 return _("Display details about a package or group of packages")
245
246 def doCommand(self, base, basecmd, extcmds):
247 try:
248 highlight = base.term.MODE['bold']
249 ypl = base.returnPkgLists(extcmds, installed_available=highlight)
250 except yum.Errors.YumBaseError, e:
251 return 1, [str(e)]
252 else:
253 update_pkgs = {}
254 inst_pkgs = {}
255 local_pkgs = {}
256
257 columns = None
258 if basecmd == 'list':
259 # Dynamically size the columns
260 columns = _list_cmd_calc_columns(base, ypl)
261
262 if highlight and ypl.installed:
263 # If we have installed and available lists, then do the
264 # highlighting for the installed packages so you can see what's
265 # available to update, an extra, or newer than what we have.
266 for pkg in (ypl.hidden_available +
267 ypl.reinstall_available +
268 ypl.old_available):
269 key = (pkg.name, pkg.arch)
270 if key not in update_pkgs or pkg.verGT(update_pkgs[key]):
271 update_pkgs[key] = pkg
272
273 if highlight and ypl.available:
274 # If we have installed and available lists, then do the
275 # highlighting for the available packages so you can see what's
276 # available to install vs. update vs. old.
277 for pkg in ypl.hidden_installed:
278 key = (pkg.name, pkg.arch)
279 if key not in inst_pkgs or pkg.verGT(inst_pkgs[key]):
280 inst_pkgs[key] = pkg
281
282 if highlight and ypl.updates:
283 # Do the local/remote split we get in "yum updates"
284 for po in sorted(ypl.updates):
285 if po.repo.id != 'installed' and po.verifyLocalPkg():
286 local_pkgs[(po.name, po.arch)] = po
287
288 # Output the packages:
289 clio = base.conf.color_list_installed_older
290 clin = base.conf.color_list_installed_newer
291 clir = base.conf.color_list_installed_reinstall
292 clie = base.conf.color_list_installed_extra
293 rip = base.listPkgs(ypl.installed, _('Installed Packages'), basecmd,
294 highlight_na=update_pkgs, columns=columns,
295 highlight_modes={'>' : clio, '<' : clin,
296 '=' : clir, 'not in' : clie})
297 clau = base.conf.color_list_available_upgrade
298 clad = base.conf.color_list_available_downgrade
299 clar = base.conf.color_list_available_reinstall
300 clai = base.conf.color_list_available_install
301 rap = base.listPkgs(ypl.available, _('Available Packages'), basecmd,
302 highlight_na=inst_pkgs, columns=columns,
303 highlight_modes={'<' : clau, '>' : clad,
304 '=' : clar, 'not in' : clai})
305 rep = base.listPkgs(ypl.extras, _('Extra Packages'), basecmd,
306 columns=columns)
307 cul = base.conf.color_update_local
308 cur = base.conf.color_update_remote
309 rup = base.listPkgs(ypl.updates, _('Updated Packages'), basecmd,
310 highlight_na=local_pkgs, columns=columns,
311 highlight_modes={'=' : cul, 'not in' : cur})
312
313 # XXX put this into the ListCommand at some point
314 if len(ypl.obsoletes) > 0 and basecmd == 'list':
315 # if we've looked up obsolete lists and it's a list request
316 rop = [0, '']
317 print _('Obsoleting Packages')
318 # The tuple is (newPkg, oldPkg) ... so sort by new
319 for obtup in sorted(ypl.obsoletesTuples,
320 key=operator.itemgetter(0)):
321 base.updatesObsoletesList(obtup, 'obsoletes',
322 columns=columns)
323 else:
324 rop = base.listPkgs(ypl.obsoletes, _('Obsoleting Packages'),
325 basecmd, columns=columns)
326 rrap = base.listPkgs(ypl.recent, _('Recently Added Packages'),
327 basecmd, columns=columns)
328 # extcmds is pop(0)'d if they pass a "special" param like "updates"
329 # in returnPkgLists(). This allows us to always return "ok" for
330 # things like "yum list updates".
331 if len(extcmds) and \
332 rrap[0] and rop[0] and rup[0] and rep[0] and rap[0] and rip[0]:
333 return 1, [_('No matching Packages to list')]
334 return 0, []
335
336 def needTs(self, base, basecmd, extcmds):
337 if len(extcmds) and extcmds[0] == 'installed':
338 return False
339
340 return True
341
342class ListCommand(InfoCommand):
343 def getNames(self):
344 return ['list']
345
346 def getSummary(self):
347 return _("List a package or groups of packages")
348
349
350class EraseCommand(YumCommand):
351
352 def getNames(self):
353 return ['erase', 'remove']
354
355 def getUsage(self):
356 return "PACKAGE..."
357
358 def getSummary(self):
359 return _("Remove a package or packages from your system")
360
361 def doCheck(self, base, basecmd, extcmds):
362 checkRootUID(base)
363 checkPackageArg(base, basecmd, extcmds)
364
365 def doCommand(self, base, basecmd, extcmds):
366 self.doneCommand(base, _("Setting up Remove Process"))
367 try:
368 return base.erasePkgs(extcmds)
369 except yum.Errors.YumBaseError, e:
370 return 1, [str(e)]
371
372 def needTs(self, base, basecmd, extcmds):
373 return False
374
375 def needTsRemove(self, base, basecmd, extcmds):
376 return True
377
378class GroupCommand(YumCommand):
379 def doCommand(self, base, basecmd, extcmds):
380 self.doneCommand(base, _("Setting up Group Process"))
381
382 base.doRepoSetup(dosack=0)
383 try:
384 base.doGroupSetup()
385 except yum.Errors.GroupsError:
386 return 1, [_('No Groups on which to run command')]
387 except yum.Errors.YumBaseError, e:
388 return 1, [str(e)]
389
390
391class GroupListCommand(GroupCommand):
392 def getNames(self):
393 return ['grouplist']
394
395 def getUsage(self):
396 return ""
397
398 def getSummary(self):
399 return _("List available package groups")
400
401 def doCommand(self, base, basecmd, extcmds):
402 GroupCommand.doCommand(self, base, basecmd, extcmds)
403 return base.returnGroupLists(extcmds)
404
405 def needTs(self, base, basecmd, extcmds):
406 return False
407
408class GroupInstallCommand(GroupCommand):
409 def getNames(self):
410 return ['groupinstall', 'groupupdate']
411
412 def getUsage(self):
413 return "GROUP..."
414
415 def getSummary(self):
416 return _("Install the packages in a group on your system")
417
418 def doCheck(self, base, basecmd, extcmds):
419 checkRootUID(base)
420 checkGPGKey(base)
421 checkGroupArg(base, basecmd, extcmds)
422
423 def doCommand(self, base, basecmd, extcmds):
424 GroupCommand.doCommand(self, base, basecmd, extcmds)
425 try:
426 return base.installGroups(extcmds)
427 except yum.Errors.YumBaseError, e:
428 return 1, [str(e)]
429
430class GroupRemoveCommand(GroupCommand):
431 def getNames(self):
432 return ['groupremove', 'grouperase']
433
434 def getUsage(self):
435 return "GROUP..."
436
437 def getSummary(self):
438 return _("Remove the packages in a group from your system")
439
440 def doCheck(self, base, basecmd, extcmds):
441 checkRootUID(base)
442 checkGroupArg(base, basecmd, extcmds)
443
444 def doCommand(self, base, basecmd, extcmds):
445 GroupCommand.doCommand(self, base, basecmd, extcmds)
446 try:
447 return base.removeGroups(extcmds)
448 except yum.Errors.YumBaseError, e:
449 return 1, [str(e)]
450
451 def needTs(self, base, basecmd, extcmds):
452 return False
453
454 def needTsRemove(self, base, basecmd, extcmds):
455 return True
456
457class GroupInfoCommand(GroupCommand):
458 def getNames(self):
459 return ['groupinfo']
460
461 def getUsage(self):
462 return "GROUP..."
463
464 def getSummary(self):
465 return _("Display details about a package group")
466
467 def doCheck(self, base, basecmd, extcmds):
468 checkGroupArg(base, basecmd, extcmds)
469
470 def doCommand(self, base, basecmd, extcmds):
471 GroupCommand.doCommand(self, base, basecmd, extcmds)
472 try:
473 return base.returnGroupInfo(extcmds)
474 except yum.Errors.YumBaseError, e:
475 return 1, [str(e)]
476
477 def needTs(self, base, basecmd, extcmds):
478 return False
479
480class MakeCacheCommand(YumCommand):
481
482 def getNames(self):
483 return ['makecache']
484
485 def getUsage(self):
486 return ""
487
488 def getSummary(self):
489 return _("Generate the metadata cache")
490
491 def doCheck(self, base, basecmd, extcmds):
492 pass
493
494 def doCommand(self, base, basecmd, extcmds):
495 base.logger.debug(_("Making cache files for all metadata files."))
496 base.logger.debug(_("This may take a while depending on the speed of this computer"))
497 try:
498 for repo in base.repos.findRepos('*'):
499 repo.metadata_expire = 0
500 repo.mdpolicy = "group:all"
501 base.doRepoSetup(dosack=0)
502 base.repos.doSetup()
503 for repo in base.repos.listEnabled():
504 repo.repoXML
505
506 # These convert the downloaded data into usable data,
507 # we can't remove them until *LoadRepo() can do:
508 # 1. Download a .sqlite.bz2 and convert to .sqlite
509 # 2. Download a .xml.gz and convert to .xml.gz.sqlite
510 base.repos.populateSack(mdtype='metadata', cacheonly=1)
511 base.repos.populateSack(mdtype='filelists', cacheonly=1)
512 base.repos.populateSack(mdtype='otherdata', cacheonly=1)
513
514
515 except yum.Errors.YumBaseError, e:
516 return 1, [str(e)]
517 return 0, [_('Metadata Cache Created')]
518
519 def needTs(self, base, basecmd, extcmds):
520 return False
521
522class CleanCommand(YumCommand):
523
524 def getNames(self):
525 return ['clean']
526
527 def getUsage(self):
528 return "[headers|packages|metadata|dbcache|plugins|expire-cache|all]"
529
530 def getSummary(self):
531 return _("Remove cached data")
532
533 def doCheck(self, base, basecmd, extcmds):
534 checkCleanArg(base, basecmd, extcmds)
535
536 def doCommand(self, base, basecmd, extcmds):
537 base.conf.cache = 1
538 return base.cleanCli(extcmds)
539
540 def needTs(self, base, basecmd, extcmds):
541 return False
542
543class ProvidesCommand(YumCommand):
544 def getNames(self):
545 return ['provides', 'whatprovides']
546
547 def getUsage(self):
548 return "SOME_STRING"
549
550 def getSummary(self):
551 return _("Find what package provides the given value")
552
553 def doCheck(self, base, basecmd, extcmds):
554 checkItemArg(base, basecmd, extcmds)
555
556 def doCommand(self, base, basecmd, extcmds):
557 base.logger.debug("Searching Packages: ")
558 try:
559 return base.provides(extcmds)
560 except yum.Errors.YumBaseError, e:
561 return 1, [str(e)]
562
563class CheckUpdateCommand(YumCommand):
564 def getNames(self):
565 return ['check-update']
566
567 def getUsage(self):
568 return "[PACKAGE...]"
569
570 def getSummary(self):
571 return _("Check for available package updates")
572
573 def doCommand(self, base, basecmd, extcmds):
574 base.extcmds.insert(0, 'updates')
575 result = 0
576 try:
577 ypl = base.returnPkgLists(extcmds)
578 if (base.conf.obsoletes or
579 base.verbose_logger.isEnabledFor(logginglevels.DEBUG_3)):
580 typl = base.returnPkgLists(['obsoletes'])
581 ypl.obsoletes = typl.obsoletes
582 ypl.obsoletesTuples = typl.obsoletesTuples
583
584 columns = _list_cmd_calc_columns(base, ypl)
585 if len(ypl.updates) > 0:
586 local_pkgs = {}
587 highlight = base.term.MODE['bold']
588 if highlight:
589 # Do the local/remote split we get in "yum updates"
590 for po in sorted(ypl.updates):
591 if po.repo.id != 'installed' and po.verifyLocalPkg():
592 local_pkgs[(po.name, po.arch)] = po
593
594 cul = base.conf.color_update_local
595 cur = base.conf.color_update_remote
596 base.listPkgs(ypl.updates, '', outputType='list',
597 highlight_na=local_pkgs, columns=columns,
598 highlight_modes={'=' : cul, 'not in' : cur})
599 result = 100
600 if len(ypl.obsoletes) > 0: # This only happens in verbose mode
601 print _('Obsoleting Packages')
602 # The tuple is (newPkg, oldPkg) ... so sort by new
603 for obtup in sorted(ypl.obsoletesTuples,
604 key=operator.itemgetter(0)):
605 base.updatesObsoletesList(obtup, 'obsoletes',
606 columns=columns)
607 result = 100
608 except yum.Errors.YumBaseError, e:
609 return 1, [str(e)]
610 else:
611 return result, []
612
613class SearchCommand(YumCommand):
614 def getNames(self):
615 return ['search']
616
617 def getUsage(self):
618 return "SOME_STRING"
619
620 def getSummary(self):
621 return _("Search package details for the given string")
622
623 def doCheck(self, base, basecmd, extcmds):
624 checkItemArg(base, basecmd, extcmds)
625
626 def doCommand(self, base, basecmd, extcmds):
627 base.logger.debug(_("Searching Packages: "))
628 try:
629 return base.search(extcmds)
630 except yum.Errors.YumBaseError, e:
631 return 1, [str(e)]
632
633 def needTs(self, base, basecmd, extcmds):
634 return False
635
636class UpgradeCommand(YumCommand):
637 def getNames(self):
638 return ['upgrade']
639
640 def getUsage(self):
641 return 'PACKAGE...'
642
643 def getSummary(self):
644 return _("Update packages taking obsoletes into account")
645
646 def doCheck(self, base, basecmd, extcmds):
647 checkRootUID(base)
648 checkGPGKey(base)
649
650 def doCommand(self, base, basecmd, extcmds):
651 base.conf.obsoletes = 1
652 self.doneCommand(base, _("Setting up Upgrade Process"))
653 try:
654 return base.updatePkgs(extcmds)
655 except yum.Errors.YumBaseError, e:
656 return 1, [str(e)]
657
658class LocalInstallCommand(YumCommand):
659 def getNames(self):
660 return ['localinstall', 'localupdate']
661
662 def getUsage(self):
663 return "FILE"
664
665 def getSummary(self):
666 return _("Install a local RPM")
667
668 def doCheck(self, base, basecmd, extcmds):
669 checkRootUID(base)
670 checkGPGKey(base)
671 checkPackageArg(base, basecmd, extcmds)
672
673 def doCommand(self, base, basecmd, extcmds):
674 self.doneCommand(base, _("Setting up Local Package Process"))
675
676 updateonly = basecmd == 'localupdate'
677 try:
678 return base.localInstall(filelist=extcmds, updateonly=updateonly)
679 except yum.Errors.YumBaseError, e:
680 return 1, [str(e)]
681
682 def needTs(self, base, basecmd, extcmds):
683 return False
684
685class ResolveDepCommand(YumCommand):
686 def getNames(self):
687 return ['resolvedep']
688
689 def getUsage(self):
690 return "DEPENDENCY"
691
692 def getSummary(self):
693 return _("Determine which package provides the given dependency")
694
695 def doCommand(self, base, basecmd, extcmds):
696 base.logger.debug(_("Searching Packages for Dependency:"))
697 try:
698 return base.resolveDepCli(extcmds)
699 except yum.Errors.YumBaseError, e:
700 return 1, [str(e)]
701
702class ShellCommand(YumCommand):
703 def getNames(self):
704 return ['shell']
705
706 def getUsage(self):
707 return "[FILENAME]"
708
709 def getSummary(self):
710 return _("Run an interactive yum shell")
711
712 def doCheck(self, base, basecmd, extcmds):
713 checkShellArg(base, basecmd, extcmds)
714
715 def doCommand(self, base, basecmd, extcmds):
716 self.doneCommand(base, _('Setting up Yum Shell'))
717 try:
718 return base.doShell()
719 except yum.Errors.YumBaseError, e:
720 return 1, [str(e)]
721
722 def needTs(self, base, basecmd, extcmds):
723 return False
724
725
726class DepListCommand(YumCommand):
727 def getNames(self):
728 return ['deplist']
729
730 def getUsage(self):
731 return 'PACKAGE...'
732
733 def getSummary(self):
734 return _("List a package's dependencies")
735
736 def doCheck(self, base, basecmd, extcmds):
737 checkPackageArg(base, basecmd, extcmds)
738
739 def doCommand(self, base, basecmd, extcmds):
740 self.doneCommand(base, _("Finding dependencies: "))
741 try:
742 return base.deplist(extcmds)
743 except yum.Errors.YumBaseError, e:
744 return 1, [str(e)]
745
746
747class RepoListCommand(YumCommand):
748
749 def getNames(self):
750 return ('repolist',)
751
752 def getUsage(self):
753 return '[all|enabled|disabled]'
754
755 def getSummary(self):
756 return _('Display the configured software repositories')
757
758 def doCommand(self, base, basecmd, extcmds):
759 def _repo_size(repo):
760 ret = 0
761 for pkg in repo.sack.returnPackages():
762 ret += pkg.packagesize
763 return base.format_number(ret)
764
765 def _repo_match(repo, patterns):
766 rid = repo.id.lower()
767 rnm = repo.name.lower()
768 for pat in patterns:
769 if fnmatch.fnmatch(rid, pat):
770 return True
771 if fnmatch.fnmatch(rnm, pat):
772 return True
773 return False
774
775 def _num2ui_num(num):
776 return to_unicode(locale.format("%d", num, True))
777
778 if len(extcmds) >= 1 and extcmds[0] in ('all', 'disabled', 'enabled'):
779 arg = extcmds[0]
780 extcmds = extcmds[1:]
781 else:
782 arg = 'enabled'
783 extcmds = map(lambda x: x.lower(), extcmds)
784
785 verbose = base.verbose_logger.isEnabledFor(logginglevels.DEBUG_3)
786 if arg != 'disabled' or extcmds:
787 try:
788 # Setup so len(repo.sack) is correct
789 base.repos.populateSack()
790 base.pkgSack # Need to setup the pkgSack, so excludes work
791 except yum.Errors.RepoError:
792 if verbose:
793 raise
794
795 repos = base.repos.repos.values()
796 repos.sort()
797 enabled_repos = base.repos.listEnabled()
798 on_ehibeg = base.term.FG_COLOR['green'] + base.term.MODE['bold']
799 on_dhibeg = base.term.FG_COLOR['red']
800 on_hiend = base.term.MODE['normal']
801 tot_num = 0
802 cols = []
803 for repo in repos:
804 if len(extcmds) and not _repo_match(repo, extcmds):
805 continue
806 (ehibeg, dhibeg, hiend) = '', '', ''
807 ui_enabled = ''
808 ui_endis_wid = 0
809 ui_num = ""
810 ui_excludes_num = ''
811 force_show = False
812 if arg == 'all' or repo.id in extcmds or repo.name in extcmds:
813 force_show = True
814 (ehibeg, dhibeg, hiend) = (on_ehibeg, on_dhibeg, on_hiend)
815 if repo in enabled_repos:
816 enabled = True
817 if arg == 'enabled':
818 force_show = False
819 elif arg == 'disabled' and not force_show:
820 continue
821 if force_show or verbose:
822 ui_enabled = ehibeg + _('enabled') + hiend
823 ui_endis_wid = utf8_width(_('enabled'))
824 if not verbose:
825 ui_enabled += ": "
826 ui_endis_wid += 2
827 if verbose:
828 ui_size = _repo_size(repo)
829 # We don't show status for list disabled
830 if arg != 'disabled' or verbose:
831 if verbose or base.conf.exclude or repo.exclude:
832 num = len(repo.sack.simplePkgList())
833 else:
834 num = len(repo.sack)
835 ui_num = _num2ui_num(num)
836 excludes = repo.sack._excludes
837 excludes = len([pid for r,pid in excludes if r == repo])
838 if excludes:
839 ui_excludes_num = _num2ui_num(excludes)
840 if not verbose:
841 ui_num += "+%s" % ui_excludes_num
842 tot_num += num
843 else:
844 enabled = False
845 if arg == 'disabled':
846 force_show = False
847 elif arg == 'enabled' and not force_show:
848 continue
849 ui_enabled = dhibeg + _('disabled') + hiend
850 ui_endis_wid = utf8_width(_('disabled'))
851
852 if True: # Here to make patch smaller, TODO: rm
853 if not verbose:
854 rid = str(repo)
855 if enabled and repo.metalink:
856 mdts = repo.metalink_data.repomd.timestamp
857 if mdts > repo.repoXML.timestamp:
858 rid = '*' + rid
859 cols.append((rid, repo.name,
860 (ui_enabled, ui_endis_wid), ui_num))
861 else:
862 if enabled:
863 md = repo.repoXML
864 else:
865 md = None
866 out = [base.fmtKeyValFill(_("Repo-id : "), repo),
867 base.fmtKeyValFill(_("Repo-name : "), repo.name)]
868
869 if force_show or extcmds:
870 out += [base.fmtKeyValFill(_("Repo-status : "),
871 ui_enabled)]
872 if md and md.revision is not None:
873 out += [base.fmtKeyValFill(_("Repo-revision: "),
874 md.revision)]
875 if md and md.tags['content']:
876 tags = md.tags['content']
877 out += [base.fmtKeyValFill(_("Repo-tags : "),
878 ", ".join(sorted(tags)))]
879
880 if md and md.tags['distro']:
881 for distro in sorted(md.tags['distro']):
882 tags = md.tags['distro'][distro]
883 out += [base.fmtKeyValFill(_("Repo-distro-tags: "),
884 "[%s]: %s" % (distro,
885 ", ".join(sorted(tags))))]
886
887 if md:
888 out += [base.fmtKeyValFill(_("Repo-updated : "),
889 time.ctime(md.timestamp)),
890 base.fmtKeyValFill(_("Repo-pkgs : "),ui_num),
891 base.fmtKeyValFill(_("Repo-size : "),ui_size)]
892
893 if hasattr(repo, '_orig_baseurl'):
894 baseurls = repo._orig_baseurl
895 else:
896 baseurls = repo.baseurl
897 if baseurls:
898 out += [base.fmtKeyValFill(_("Repo-baseurl : "),
899 ", ".join(baseurls))]
900
901 if enabled:
902 # This needs to be here due to the mirrorlists are
903 # metalinks hack.
904 repo.urls
905 if repo.metalink:
906 out += [base.fmtKeyValFill(_("Repo-metalink: "),
907 repo.metalink)]
908 if enabled:
909 ts = repo.metalink_data.repomd.timestamp
910 out += [base.fmtKeyValFill(_(" Updated : "),
911 time.ctime(ts))]
912 elif repo.mirrorlist:
913 out += [base.fmtKeyValFill(_("Repo-mirrors : "),
914 repo.mirrorlist)]
915
916 if not os.path.exists(repo.metadata_cookie):
917 last = _("Unknown")
918 else:
919 last = os.stat(repo.metadata_cookie).st_mtime
920 last = time.ctime(last)
921
922 if repo.metadata_expire <= -1:
923 num = _("Never (last: %s)") % last
924 elif not repo.metadata_expire:
925 num = _("Instant (last: %s)") % last
926 else:
927 num = _num2ui_num(repo.metadata_expire)
928 num = _("%s second(s) (last: %s)") % (num, last)
929
930 out += [base.fmtKeyValFill(_("Repo-expire : "), num)]
931
932 if repo.exclude:
933 out += [base.fmtKeyValFill(_("Repo-exclude : "),
934 ", ".join(repo.exclude))]
935
936 if repo.includepkgs:
937 out += [base.fmtKeyValFill(_("Repo-include : "),
938 ", ".join(repo.includepkgs))]
939
940 if ui_excludes_num:
941 out += [base.fmtKeyValFill(_("Repo-excluded: "),
942 ui_excludes_num)]
943
944 base.verbose_logger.log(logginglevels.DEBUG_3,
945 "%s\n",
946 "\n".join(map(misc.to_unicode, out)))
947
948 if not verbose and cols:
949 # Work out the first (id) and last (enabled/disalbed/count),
950 # then chop the middle (name)...
951 id_len = utf8_width(_('repo id'))
952 nm_len = 0
953 st_len = 0
954 ui_len = 0
955
956 for (rid, rname, (ui_enabled, ui_endis_wid), ui_num) in cols:
957 if id_len < utf8_width(rid):
958 id_len = utf8_width(rid)
959 if nm_len < utf8_width(rname):
960 nm_len = utf8_width(rname)
961 if st_len < (ui_endis_wid + len(ui_num)):
962 st_len = (ui_endis_wid + len(ui_num))
963 # Need this as well as above for: utf8_width_fill()
964 if ui_len < len(ui_num):
965 ui_len = len(ui_num)
966 if arg == 'disabled': # Don't output a status column.
967 left = base.term.columns - (id_len + 1)
968 elif utf8_width(_('status')) > st_len:
969 left = base.term.columns - (id_len + utf8_width(_('status')) +2)
970 else:
971 left = base.term.columns - (id_len + st_len + 2)
972
973 if left < nm_len: # Name gets chopped
974 nm_len = left
975 else: # Share the extra...
976 left -= nm_len
977 id_len += left / 2
978 nm_len += left - (left / 2)
979
980 txt_rid = utf8_width_fill(_('repo id'), id_len)
981 txt_rnam = utf8_width_fill(_('repo name'), nm_len, nm_len)
982 if arg == 'disabled': # Don't output a status column.
983 base.verbose_logger.log(logginglevels.INFO_2,"%s %s",
984 txt_rid, txt_rnam)
985 else:
986 base.verbose_logger.log(logginglevels.INFO_2,"%s %s %s",
987 txt_rid, txt_rnam, _('status'))
988 for (rid, rname, (ui_enabled, ui_endis_wid), ui_num) in cols:
989 if arg == 'disabled': # Don't output a status column.
990 base.verbose_logger.log(logginglevels.INFO_2, "%s %s",
991 utf8_width_fill(rid, id_len),
992 utf8_width_fill(rname, nm_len,
993 nm_len))
994 continue
995
996 if ui_num:
997 ui_num = utf8_width_fill(ui_num, ui_len, left=False)
998 base.verbose_logger.log(logginglevels.INFO_2, "%s %s %s%s",
999 utf8_width_fill(rid, id_len),
1000 utf8_width_fill(rname, nm_len, nm_len),
1001 ui_enabled, ui_num)
1002
1003 return 0, ['repolist: ' +to_unicode(locale.format("%d", tot_num, True))]
1004
1005 def needTs(self, base, basecmd, extcmds):
1006 return False
1007
1008
1009class HelpCommand(YumCommand):
1010
1011 def getNames(self):
1012 return ['help']
1013
1014 def getUsage(self):
1015 return "COMMAND"
1016
1017 def getSummary(self):
1018 return _("Display a helpful usage message")
1019
1020 def doCheck(self, base, basecmd, extcmds):
1021 if len(extcmds) == 0:
1022 base.usage()
1023 raise cli.CliError
1024 elif len(extcmds) > 1 or extcmds[0] not in base.yum_cli_commands:
1025 base.usage()
1026 raise cli.CliError
1027
1028 @staticmethod
1029 def _makeOutput(command):
1030 canonical_name = command.getNames()[0]
1031
1032 # Check for the methods in case we have plugins that don't
1033 # implement these.
1034 # XXX Remove this once usage/summary are common enough
1035 try:
1036 usage = command.getUsage()
1037 except (AttributeError, NotImplementedError):
1038 usage = None
1039 try:
1040 summary = command.getSummary()
1041 except (AttributeError, NotImplementedError):
1042 summary = None
1043
1044 # XXX need detailed help here, too
1045 help_output = ""
1046 if usage is not None:
1047 help_output += "%s %s" % (canonical_name, usage)
1048 if summary is not None:
1049 help_output += "\n\n%s" % summary
1050
1051 if usage is None and summary is None:
1052 help_output = _("No help available for %s") % canonical_name
1053
1054 command_names = command.getNames()
1055 if len(command_names) > 1:
1056 if len(command_names) > 2:
1057 help_output += _("\n\naliases: ")
1058 else:
1059 help_output += _("\n\nalias: ")
1060 help_output += ', '.join(command.getNames()[1:])
1061
1062 return help_output
1063
1064 def doCommand(self, base, basecmd, extcmds):
1065 if extcmds[0] in base.yum_cli_commands:
1066 command = base.yum_cli_commands[extcmds[0]]
1067 base.verbose_logger.log(logginglevels.INFO_2,
1068 self._makeOutput(command))
1069 return 0, []
1070
1071 def needTs(self, base, basecmd, extcmds):
1072 return False
1073
1074class ReInstallCommand(YumCommand):
1075 def getNames(self):
1076 return ['reinstall']
1077
1078 def getUsage(self):
1079 return "PACKAGE..."
1080
1081 def doCheck(self, base, basecmd, extcmds):
1082 checkRootUID(base)
1083 checkGPGKey(base)
1084 checkPackageArg(base, basecmd, extcmds)
1085
1086 def doCommand(self, base, basecmd, extcmds):
1087 self.doneCommand(base, _("Setting up Reinstall Process"))
1088 try:
1089 return base.reinstallPkgs(extcmds)
1090
1091 except yum.Errors.YumBaseError, e:
1092 return 1, [to_unicode(e)]
1093
1094 def getSummary(self):
1095 return _("reinstall a package")
1096
1097 def needTs(self, base, basecmd, extcmds):
1098 return False
1099
1100class DowngradeCommand(YumCommand):
1101 def getNames(self):
1102 return ['downgrade']
1103
1104 def getUsage(self):
1105 return "PACKAGE..."
1106
1107 def doCheck(self, base, basecmd, extcmds):
1108 checkRootUID(base)
1109 checkGPGKey(base)
1110 checkPackageArg(base, basecmd, extcmds)
1111
1112 def doCommand(self, base, basecmd, extcmds):
1113 self.doneCommand(base, _("Setting up Downgrade Process"))
1114 try:
1115 return base.downgradePkgs(extcmds)
1116 except yum.Errors.YumBaseError, e:
1117 return 1, [str(e)]
1118
1119 def getSummary(self):
1120 return _("downgrade a package")
1121
1122 def needTs(self, base, basecmd, extcmds):
1123 return False
1124
1125
1126class VersionCommand(YumCommand):
1127 def getNames(self):
1128 return ['version']
1129
1130 def getUsage(self):
1131 return "[all|installed|available]"
1132
1133 def getSummary(self):
1134 return _("Display a version for the machine and/or available repos.")
1135
1136 def doCommand(self, base, basecmd, extcmds):
1137 vcmd = 'installed'
1138 if extcmds:
1139 vcmd = extcmds[0]
1140
1141 def _append_repos(cols, repo_data):
1142 for repoid in sorted(repo_data):
1143 cur = repo_data[repoid]
1144 ncols = []
1145 last_rev = None
1146 for rev in sorted(cur):
1147 if rev is None:
1148 continue
1149 last_rev = cur[rev]
1150 ncols.append((" %s/%s" % (repoid, rev), str(cur[rev])))
1151 if None in cur and (not last_rev or cur[None] != last_rev):
1152 cols.append((" %s" % repoid, str(cur[None])))
1153 cols.extend(ncols)
1154
1155 verbose = base.verbose_logger.isEnabledFor(logginglevels.DEBUG_3)
1156 groups = {}
1157 if vcmd in ('nogroups', 'nogroups-installed', 'nogroups-available',
1158 'nogroups-all'):
1159 gconf = []
1160 if vcmd == 'nogroups':
1161 vcmd = 'installed'
1162 else:
1163 vcmd = vcmd[len('nogroups-'):]
1164 else:
1165 gconf = yum.config.readVersionGroupsConfig()
1166
1167 for group in gconf:
1168 groups[group] = set(gconf[group].pkglist)
1169 if gconf[group].run_with_packages:
1170 groups[group].update(base.run_with_package_names)
1171
1172 if vcmd == 'grouplist':
1173 print _(" Yum version groups:")
1174 for group in sorted(groups):
1175 print " ", group
1176
1177 return 0, ['version grouplist']
1178
1179 if vcmd == 'groupinfo':
1180 for group in groups:
1181 if group not in extcmds[1:]:
1182 continue
1183 print _(" Group :"), group
1184 print _(" Packages:")
1185 if not verbose:
1186 for pkgname in sorted(groups[group]):
1187 print " ", pkgname
1188 else:
1189 data = {'envra' : {}, 'rid' : {}}
1190 pkg_names = groups[group]
1191 pkg_names2pkgs = base._group_names2aipkgs(pkg_names)
1192 base._calcDataPkgColumns(data, pkg_names, pkg_names2pkgs)
1193 data = [data['envra'], data['rid']]
1194 columns = base.calcColumns(data)
1195 columns = (-columns[0], -columns[1])
1196 base._displayPkgsFromNames(pkg_names, True, pkg_names2pkgs,
1197 columns=columns)
1198
1199 return 0, ['version groupinfo']
1200
1201 rel = base.conf.yumvar['releasever']
1202 ba = base.conf.yumvar['basearch']
1203 cols = []
1204 if vcmd in ('installed', 'all', 'group-installed', 'group-all'):
1205 try:
1206 data = base.rpmdb.simpleVersion(not verbose, groups=groups)
1207 lastdbv = base.history.last()
1208 if lastdbv is not None:
1209 lastdbv = lastdbv.end_rpmdbversion
1210 if lastdbv is None or data[0] != lastdbv:
1211 base._rpmdb_warn_checks(warn=lastdbv is not None)
1212 if vcmd not in ('group-installed', 'group-all'):
1213 cols.append(("%s %s/%s" % (_("Installed:"), rel, ba),
1214 str(data[0])))
1215 _append_repos(cols, data[1])
1216 if groups:
1217 for grp in sorted(data[2]):
1218 cols.append(("%s %s" % (_("Group-Installed:"), grp),
1219 str(data[2][grp])))
1220 _append_repos(cols, data[3][grp])
1221 except yum.Errors.YumBaseError, e:
1222 return 1, [str(e)]
1223 if vcmd in ('available', 'all', 'group-available', 'group-all'):
1224 try:
1225 data = base.pkgSack.simpleVersion(not verbose, groups=groups)
1226 if vcmd not in ('group-available', 'group-all'):
1227 cols.append(("%s %s/%s" % (_("Available:"), rel, ba),
1228 str(data[0])))
1229 if verbose:
1230 _append_repos(cols, data[1])
1231 if groups:
1232 for grp in sorted(data[2]):
1233 cols.append(("%s %s" % (_("Group-Available:"), grp),
1234 str(data[2][grp])))
1235 if verbose:
1236 _append_repos(cols, data[3][grp])
1237 except yum.Errors.YumBaseError, e:
1238 return 1, [str(e)]
1239
1240 data = {'rid' : {}, 'ver' : {}}
1241 for (rid, ver) in cols:
1242 for (d, v) in (('rid', len(rid)), ('ver', len(ver))):
1243 data[d].setdefault(v, 0)
1244 data[d][v] += 1
1245 data = [data['rid'], data['ver']]
1246 columns = base.calcColumns(data)
1247 columns = (-columns[0], columns[1])
1248
1249 for line in cols:
1250 print base.fmtColumns(zip(line, columns))
1251
1252 return 0, ['version']
1253
1254 def needTs(self, base, basecmd, extcmds):
1255 vcmd = 'installed'
1256 if extcmds:
1257 vcmd = extcmds[0]
1258 verbose = base.verbose_logger.isEnabledFor(logginglevels.DEBUG_3)
1259 if vcmd == 'groupinfo' and verbose:
1260 return True
1261 return vcmd in ('available', 'all', 'group-available', 'group-all')
1262
1263
1264class HistoryCommand(YumCommand):
1265 def getNames(self):
1266 return ['history']
1267
1268 def getUsage(self):
1269 return "[info|list|summary|redo|undo|new]"
1270
1271 def getSummary(self):
1272 return _("Display, or use, the transaction history")
1273
1274 def _hcmd_redo(self, base, extcmds):
1275 old = base._history_get_transaction(extcmds)
1276 if old is None:
1277 return 1, ['Failed history redo']
1278 tm = time.ctime(old.beg_timestamp)
1279 print "Repeating transaction %u, from %s" % (old.tid, tm)
1280 base.historyInfoCmdPkgsAltered(old)
1281 if base.history_redo(old):
1282 return 2, ["Repeating transaction %u" % (old.tid,)]
1283
1284 def _hcmd_undo(self, base, extcmds):
1285 old = base._history_get_transaction(extcmds)
1286 if old is None:
1287 return 1, ['Failed history undo']
1288 tm = time.ctime(old.beg_timestamp)
1289 print "Undoing transaction %u, from %s" % (old.tid, tm)
1290 base.historyInfoCmdPkgsAltered(old)
1291 if base.history_undo(old):
1292 return 2, ["Undoing transaction %u" % (old.tid,)]
1293
1294 def _hcmd_new(self, base, extcmds):
1295 base.history._create_db_file()
1296
1297 def doCheck(self, base, basecmd, extcmds):
1298 cmds = ('list', 'info', 'summary', 'repeat', 'redo', 'undo', 'new')
1299 if extcmds and extcmds[0] not in cmds:
1300 base.logger.critical(_('Invalid history sub-command, use: %s.'),
1301 ", ".join(cmds))
1302 raise cli.CliError
1303 if extcmds and extcmds[0] in ('repeat', 'redo', 'undo', 'new'):
1304 checkRootUID(base)
1305 checkGPGKey(base)
1306
1307 def doCommand(self, base, basecmd, extcmds):
1308 vcmd = 'list'
1309 if extcmds:
1310 vcmd = extcmds[0]
1311
1312 if False: pass
1313 elif vcmd == 'list':
1314 ret = base.historyListCmd(extcmds)
1315 elif vcmd == 'info':
1316 ret = base.historyInfoCmd(extcmds)
1317 elif vcmd == 'summary':
1318 ret = base.historySummaryCmd(extcmds)
1319 elif vcmd == 'undo':
1320 ret = self._hcmd_undo(base, extcmds)
1321 elif vcmd in ('redo', 'repeat'):
1322 ret = self._hcmd_redo(base, extcmds)
1323 elif vcmd == 'new':
1324 ret = self._hcmd_new(base, extcmds)
1325
1326 if ret is None:
1327 return 0, ['history %s' % (vcmd,)]
1328 return ret
1329
1330 def needTs(self, base, basecmd, extcmds):
1331 vcmd = 'list'
1332 if extcmds:
1333 vcmd = extcmds[0]
1334 return vcmd in ('repeat', 'redo', 'undo')
1335
1336
1337class CheckRpmdbCommand(YumCommand):
1338 def getNames(self):
1339 return ['check', 'check-rpmdb']
1340
1341 def getUsage(self):
1342 return "[dependencies|duplicates|all]"
1343
1344 def getSummary(self):
1345 return _("Check for problems in the rpmdb")
1346
1347 def doCommand(self, base, basecmd, extcmds):
1348 chkcmd = 'all'
1349 if extcmds:
1350 chkcmd = extcmds[0]
1351
1352 def _out(x):
1353 print x
1354
1355 rc = 0
1356 if base._rpmdb_warn_checks(_out, False, chkcmd):
1357 rc = 1
1358 return rc, ['%s %s' % (basecmd, chkcmd)]
1359
1360 def needTs(self, base, basecmd, extcmds):
1361 return False
1362
Note: See TracBrowser for help on using the repository browser.