source: yum/trunk/yumcommands.py@ 1569

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

yum: update trunk to 3.4.3.

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