source: yum/trunk/cli.py@ 19

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

yum: fix access from other drives.

  • Property svn:eol-style set to native
File size: 58.2 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 2005 Duke University
16# Written by Seth Vidal
17
18"""
19Command line interface yum class and related.
20"""
21
22import os
23import re
24import sys
25import time
26import random
27import logging
28from optparse import OptionParser,OptionGroup
29import rpm
30
31from weakref import proxy as weakref
32
33import output
34import shell
35import yum
36import yum.Errors
37import yum.logginglevels
38import yum.misc
39import yum.plugins
40from rpmUtils.arch import isMultiLibArch
41from yum import _
42from yum.rpmtrans import RPMTransaction
43import signal
44import yumcommands
45
46from yum.i18n import to_unicode, to_utf8
47
48def sigquit(signum, frame):
49 """ SIGQUIT handler for the yum cli. """
50 print >> sys.stderr, "Quit signal sent - exiting immediately"
51 sys.exit(1)
52
53class CliError(yum.Errors.YumBaseError):
54
55 """
56 Command line interface related Exception.
57 """
58
59 def __init__(self, args=''):
60 yum.Errors.YumBaseError.__init__(self)
61 self.args = args
62
63class YumBaseCli(yum.YumBase, output.YumOutput):
64 """This is the base class for yum cli.
65 Inherits from yum.YumBase and output.YumOutput """
66
67 def __init__(self):
68 # handle sigquit early on
69 signal.signal(signal.SIGQUIT, sigquit)
70 yum.YumBase.__init__(self)
71 output.YumOutput.__init__(self)
72 logging.basicConfig()
73 self.logger = logging.getLogger("yum.cli")
74 self.verbose_logger = logging.getLogger("yum.verbose.cli")
75 self.yum_cli_commands = {}
76 self.registerCommand(yumcommands.InstallCommand())
77 self.registerCommand(yumcommands.UpdateCommand())
78 self.registerCommand(yumcommands.InfoCommand())
79 self.registerCommand(yumcommands.ListCommand())
80 self.registerCommand(yumcommands.EraseCommand())
81 self.registerCommand(yumcommands.GroupCommand())
82 self.registerCommand(yumcommands.GroupListCommand())
83 self.registerCommand(yumcommands.GroupInstallCommand())
84 self.registerCommand(yumcommands.GroupRemoveCommand())
85 self.registerCommand(yumcommands.GroupInfoCommand())
86 self.registerCommand(yumcommands.MakeCacheCommand())
87 self.registerCommand(yumcommands.CleanCommand())
88 self.registerCommand(yumcommands.ProvidesCommand())
89 self.registerCommand(yumcommands.CheckUpdateCommand())
90 self.registerCommand(yumcommands.SearchCommand())
91 self.registerCommand(yumcommands.UpgradeCommand())
92 self.registerCommand(yumcommands.LocalInstallCommand())
93 self.registerCommand(yumcommands.ResolveDepCommand())
94 self.registerCommand(yumcommands.ShellCommand())
95 self.registerCommand(yumcommands.DepListCommand())
96 self.registerCommand(yumcommands.RepoListCommand())
97 self.registerCommand(yumcommands.HelpCommand())
98 self.registerCommand(yumcommands.ReInstallCommand())
99 self.registerCommand(yumcommands.DowngradeCommand())
100 self.registerCommand(yumcommands.VersionCommand())
101 self.registerCommand(yumcommands.HistoryCommand())
102 self.registerCommand(yumcommands.CheckRpmdbCommand())
103
104 def registerCommand(self, command):
105 for name in command.getNames():
106 if name in self.yum_cli_commands:
107 raise yum.Errors.ConfigError(_('Command "%s" already defined') % name)
108 self.yum_cli_commands[name] = command
109
110 def doRepoSetup(self, thisrepo=None, dosack=1):
111 """grabs the repomd.xml for each enabled repository
112 and sets up the basics of the repository"""
113
114 if self._repos and thisrepo is None:
115 return self._repos
116
117 if not thisrepo:
118 self.verbose_logger.log(yum.logginglevels.INFO_2,
119 _('Setting up repositories'))
120
121 # Call parent class to do the bulk of work
122 # (this also ensures that reposetup plugin hook is called)
123 if thisrepo:
124 yum.YumBase._getRepos(self, thisrepo=thisrepo, doSetup=True)
125 else:
126 yum.YumBase._getRepos(self, thisrepo=thisrepo)
127
128 if dosack: # so we can make the dirs and grab the repomd.xml but not import the md
129 self.verbose_logger.log(yum.logginglevels.INFO_2,
130 _('Reading repository metadata in from local files'))
131 self._getSacks(thisrepo=thisrepo)
132
133 return self._repos
134
135 def _makeUsage(self):
136 """
137 Format an attractive usage string for yum, listing subcommand
138 names and summary usages.
139 """
140 usage = 'yum [options] COMMAND\n\nList of Commands:\n\n'
141 commands = yum.misc.unique(self.yum_cli_commands.values())
142 commands.sort(key=lambda x: x.getNames()[0])
143 for command in commands:
144 # XXX Remove this when getSummary is common in plugins
145 try:
146 summary = command.getSummary()
147 usage += "%-14s %s\n" % (command.getNames()[0], summary)
148 except (AttributeError, NotImplementedError):
149 usage += "%s\n" % command.getNames()[0]
150
151 return usage
152
153 def getOptionsConfig(self, args):
154 """parses command line arguments, takes cli args:
155 sets up self.conf and self.cmds as well as logger objects
156 in base instance"""
157
158 self.optparser = YumOptionParser(base=self, usage=self._makeUsage())
159
160 # Parse only command line options that affect basic yum setup
161 opts = self.optparser.firstParse(args)
162
163 # Just print out the version if that's what the user wanted
164 if opts.version:
165 print yum.__version__
166 opts.quiet = True
167 opts.verbose = False
168
169 # get the install root to use
170 root = self.optparser.getRoot(opts)
171
172 if opts.quiet:
173 opts.debuglevel = 0
174 if opts.verbose:
175 opts.debuglevel = opts.errorlevel = 6
176
177 # Read up configuration options and initialise plugins
178 try:
179 pc = self.preconf
180 pc.fn = opts.conffile
181 pc.root = root
182 pc.init_plugins = not opts.noplugins
183 pc.plugin_types = (yum.plugins.TYPE_CORE,
184 yum.plugins.TYPE_INTERACTIVE)
185 pc.optparser = self.optparser
186 pc.debuglevel = opts.debuglevel
187 pc.errorlevel = opts.errorlevel
188 pc.disabled_plugins = self.optparser._splitArg(opts.disableplugins)
189 pc.enabled_plugins = self.optparser._splitArg(opts.enableplugins)
190 pc.releasever = opts.releasever
191 self.conf
192
193 except yum.Errors.ConfigError, e:
194 self.logger.critical(_('Config Error: %s'), e)
195 sys.exit(1)
196 except ValueError, e:
197 self.logger.critical(_('Options Error: %s'), e)
198 sys.exit(1)
199
200 # update usage in case plugins have added commands
201 self.optparser.set_usage(self._makeUsage())
202
203 self.plugins.run('args', args=args)
204 # Now parse the command line for real and
205 # apply some of the options to self.conf
206 (opts, self.cmds) = self.optparser.setupYumConfig(args=args)
207
208 if opts.version:
209 self.conf.cache = 1
210 yum_progs = self.run_with_package_names
211 done = False
212 def sm_ui_time(x):
213 return time.strftime("%Y-%m-%d %H:%M", time.gmtime(x))
214 def sm_ui_date(x): # For changelogs, there is no time
215 return time.strftime("%Y-%m-%d", time.gmtime(x))
216 for pkg in sorted(self.rpmdb.returnPackages(patterns=yum_progs)):
217 # We should only have 1 version of each...
218 if done: print ""
219 done = True
220 if pkg.epoch == '0':
221 ver = '%s-%s.%s' % (pkg.version, pkg.release, pkg.arch)
222 else:
223 ver = '%s:%s-%s.%s' % (pkg.epoch,
224 pkg.version, pkg.release, pkg.arch)
225 name = "%s%s%s" % (self.term.MODE['bold'], pkg.name,
226 self.term.MODE['normal'])
227 print _(" Installed: %s-%s at %s") %(name, ver,
228 sm_ui_time(pkg.installtime))
229 print _(" Built : %s at %s") % (pkg.packager,
230 sm_ui_time(pkg.buildtime))
231 print _(" Committed: %s at %s") % (pkg.committer,
232 sm_ui_date(pkg.committime))
233 sys.exit(0)
234
235 if opts.sleeptime is not None:
236 sleeptime = random.randrange(opts.sleeptime*60)
237 else:
238 sleeptime = 0
239
240 # save our original args out
241 self.args = args
242 # save out as a nice command string
243 self.cmdstring = 'yum '
244 for arg in self.args:
245 self.cmdstring += '%s ' % arg
246
247 try:
248 self.parseCommands() # before we return check over the base command + args
249 # make sure they match/make sense
250 except CliError:
251 sys.exit(1)
252
253 # run the sleep - if it's unchanged then it won't matter
254 time.sleep(sleeptime)
255
256 def parseCommands(self):
257 """reads self.cmds and parses them out to make sure that the requested
258 base command + argument makes any sense at all"""
259
260 self.verbose_logger.debug('Yum Version: %s', yum.__version__)
261 self.verbose_logger.log(yum.logginglevels.DEBUG_4,
262 'COMMAND: %s', self.cmdstring)
263 self.verbose_logger.log(yum.logginglevels.DEBUG_4,
264 'Installroot: %s', self.conf.installroot)
265 if len(self.conf.commands) == 0 and len(self.cmds) < 1:
266 self.cmds = self.conf.commands
267 else:
268 self.conf.commands = self.cmds
269 if len(self.cmds) < 1:
270 self.logger.critical(_('You need to give some command'))
271 self.usage()
272 raise CliError
273
274 self.basecmd = self.cmds[0] # our base command
275 self.extcmds = self.cmds[1:] # out extended arguments/commands
276
277 if len(self.extcmds) > 0:
278 self.verbose_logger.log(yum.logginglevels.DEBUG_4,
279 'Ext Commands:\n')
280 for arg in self.extcmds:
281 self.verbose_logger.log(yum.logginglevels.DEBUG_4, ' %s', arg)
282
283 if self.basecmd not in self.yum_cli_commands:
284 self.logger.critical(_('No such command: %s. Please use %s --help'),
285 self.basecmd, sys.argv[0])
286 raise CliError
287
288 self.yum_cli_commands[self.basecmd].doCheck(self, self.basecmd, self.extcmds)
289
290 def doShell(self):
291 """do a shell-like interface for yum commands"""
292
293 yumshell = shell.YumShell(base=self)
294 if len(self.extcmds) == 0:
295 yumshell.cmdloop()
296 else:
297 yumshell.script()
298 return yumshell.result, yumshell.resultmsgs
299
300 def errorSummary(self, errstring):
301 """ parse the error string for 'interesting' errors which can
302 be grouped, such as disk space issues """
303 summary = ''
304 # do disk space report first
305 p = re.compile('needs (\d+)MB on the (\S+) filesystem')
306 disk = {}
307 for m in p.finditer(errstring):
308 if not disk.has_key(m.group(2)):
309 disk[m.group(2)] = int(m.group(1))
310 if disk[m.group(2)] < int(m.group(1)):
311 disk[m.group(2)] = int(m.group(1))
312
313 if disk:
314 summary += _('Disk Requirements:\n')
315 for k in disk:
316 summary += _(' At least %dMB more space needed on the %s filesystem.\n') % (disk[k], k)
317
318 # TODO: simplify the dependency errors?
319
320 # Fixup the summary
321 summary = _('Error Summary\n-------------\n') + summary
322
323 return summary
324
325
326 def doCommands(self):
327 """
328 Calls the base command passes the extended commands/args out to be
329 parsed (most notably package globs).
330
331 Returns a numeric result code and an optional string
332 - 0 = we're done, exit
333 - 1 = we've errored, exit with error string
334 - 2 = we've got work yet to do, onto the next stage
335 """
336
337 # at this point we know the args are valid - we don't know their meaning
338 # but we know we're not being sent garbage
339
340 # setup our transaction set if the command we're using needs it
341 # compat with odd modules not subclassing YumCommand
342 needTs = True
343 needTsRemove = False
344 cmd = self.yum_cli_commands[self.basecmd]
345 if hasattr(cmd, 'needTs'):
346 needTs = cmd.needTs(self, self.basecmd, self.extcmds)
347 if not needTs and hasattr(cmd, 'needTsRemove'):
348 needTsRemove = cmd.needTsRemove(self, self.basecmd, self.extcmds)
349
350 if needTs or needTsRemove:
351 try:
352 self._getTs(needTsRemove)
353 except yum.Errors.YumBaseError, e:
354 return 1, [str(e)]
355
356 return self.yum_cli_commands[self.basecmd].doCommand(self, self.basecmd, self.extcmds)
357
358 def doTransaction(self):
359 """takes care of package downloading, checking, user confirmation and actually
360 RUNNING the transaction"""
361
362 # just make sure there's not, well, nothing to do
363 if len(self.tsInfo) == 0:
364 self.verbose_logger.info(_('Trying to run the transaction but nothing to do. Exiting.'))
365 return 1
366
367 # NOTE: In theory we can skip this in -q -y mode, for a slight perf.
368 # gain. But it's probably doom to have a different code path.
369 lsts = self.listTransaction()
370 if self.verbose_logger.isEnabledFor(yum.logginglevels.INFO_1):
371 self.verbose_logger.log(yum.logginglevels.INFO_1, lsts)
372 elif not self.conf.assumeyes:
373 # If we are in quiet, and assumeyes isn't on we want to output
374 # at least the transaction list anyway.
375 self.logger.warn(lsts)
376
377 # Check which packages have to be downloaded
378 downloadpkgs = []
379 stuff_to_download = False
380 install_only = True
381 for txmbr in self.tsInfo.getMembers():
382 if txmbr.ts_state not in ('i', 'u'):
383 install_only = False
384 else:
385 stuff_to_download = True
386 po = txmbr.po
387 if po:
388 downloadpkgs.append(po)
389
390 # Close the connection to the rpmdb so that rpm doesn't hold the SIGINT
391 # handler during the downloads. self.ts is reinitialised later in this
392 # function anyway (initActionTs).
393 self.ts.close()
394
395 # Report the total download size to the user, so he/she can base
396 # the answer on this info
397 if stuff_to_download:
398 self.reportDownloadSize(downloadpkgs, install_only)
399
400 # confirm with user
401 if self._promptWanted():
402 if not self.userconfirm():
403 self.verbose_logger.info(_('Exiting on user Command'))
404 return 1
405
406 self.verbose_logger.log(yum.logginglevels.INFO_2,
407 _('Downloading Packages:'))
408 problems = self.downloadPkgs(downloadpkgs, callback_total=self.download_callback_total_cb)
409
410 if len(problems) > 0:
411 errstring = ''
412 errstring += _('Error Downloading Packages:\n')
413 for key in problems:
414 errors = yum.misc.unique(problems[key])
415 for error in errors:
416 errstring += ' %s: %s\n' % (key, error)
417 raise yum.Errors.YumBaseError, errstring
418
419 # Check GPG signatures
420 if self.gpgsigcheck(downloadpkgs) != 0:
421 return 1
422
423 if self.conf.rpm_check_debug:
424 rcd_st = time.time()
425 self.verbose_logger.log(yum.logginglevels.INFO_2,
426 _('Running rpm_check_debug'))
427 msgs = self._run_rpm_check_debug()
428 if msgs:
429 rpmlib_only = True
430 for msg in msgs:
431 if msg.startswith('rpmlib('):
432 continue
433 rpmlib_only = False
434 if rpmlib_only:
435 print _("ERROR You need to update rpm to handle:")
436 else:
437 print _('ERROR with rpm_check_debug vs depsolve:')
438
439 for msg in msgs:
440 print to_utf8(msg)
441
442 if rpmlib_only:
443 return 1, [_('RPM needs to be updated')]
444 return 1, [_('Please report this error in %s') % self.conf.bugtracker_url]
445
446 self.verbose_logger.debug('rpm_check_debug time: %0.3f' % (time.time() - rcd_st))
447
448 tt_st = time.time()
449 self.verbose_logger.log(yum.logginglevels.INFO_2,
450 _('Running Transaction Test'))
451 if not self.conf.diskspacecheck:
452 self.tsInfo.probFilterFlags.append(rpm.RPMPROB_FILTER_DISKSPACE)
453
454
455 testcb = RPMTransaction(self, test=True)
456
457 self.initActionTs()
458 # save our dsCallback out
459 dscb = self.dsCallback
460 self.dsCallback = None # dumb, dumb dumb dumb!
461 self.populateTs(keepold=0) # sigh
462 tserrors = self.ts.test(testcb)
463 del testcb
464
465 if len(tserrors) > 0:
466 errstring = _('Transaction Check Error:\n')
467 for descr in tserrors:
468 errstring += ' %s\n' % to_unicode(descr)
469
470 raise yum.Errors.YumBaseError, errstring + '\n' + \
471 self.errorSummary(errstring)
472 self.verbose_logger.log(yum.logginglevels.INFO_2,
473 _('Transaction Test Succeeded'))
474 del self.ts
475
476 self.verbose_logger.debug('Transaction Test time: %0.3f' % (time.time() - tt_st))
477
478 # unset the sigquit handler
479 signal.signal(signal.SIGQUIT, signal.SIG_DFL)
480
481 ts_st = time.time()
482 self.initActionTs() # make a new, blank ts to populate
483 self.populateTs(keepold=0) # populate the ts
484 self.ts.check() #required for ordering
485 self.ts.order() # order
486
487 # put back our depcheck callback
488 self.dsCallback = dscb
489 # setup our rpm ts callback
490 cb = RPMTransaction(self,
491 display=output.YumCliRPMCallBack(weakref(self)))
492 if self.conf.debuglevel < 2:
493 cb.display.output = False
494
495 self.verbose_logger.log(yum.logginglevels.INFO_2, _('Running Transaction'))
496 resultobject = self.runTransaction(cb=cb)
497
498 self.verbose_logger.debug('Transaction time: %0.3f' % (time.time() - ts_st))
499 # close things
500 self.verbose_logger.log(yum.logginglevels.INFO_1,
501 self.postTransactionOutput())
502
503 # put back the sigquit handler
504 signal.signal(signal.SIGQUIT, sigquit)
505
506 return resultobject.return_code
507
508 def gpgsigcheck(self, pkgs):
509 '''Perform GPG signature verification on the given packages, installing
510 keys if possible
511
512 Returns non-zero if execution should stop (user abort).
513 Will raise YumBaseError if there's a problem
514 '''
515 for po in pkgs:
516 result, errmsg = self.sigCheckPkg(po)
517
518 if result == 0:
519 # Verified ok, or verify not req'd
520 continue
521
522 elif result == 1:
523 if not sys.stdin.isatty() and not self.conf.assumeyes:
524 raise yum.Errors.YumBaseError, \
525 _('Refusing to automatically import keys when running ' \
526 'unattended.\nUse "-y" to override.')
527
528 # the callback here expects to be able to take options which
529 # userconfirm really doesn't... so fake it
530 self.getKeyForPackage(po, lambda x, y, z: self.userconfirm())
531
532 else:
533 # Fatal error
534 raise yum.Errors.YumBaseError, errmsg
535
536 return 0
537
538 def _maybeYouMeant(self, arg):
539 """ If install argument doesn't match with case, tell the user. """
540 matches = self.doPackageLists(patterns=[arg], ignore_case=True)
541 matches = matches.installed + matches.available
542 matches = set(map(lambda x: x.name, matches))
543 if matches:
544 msg = self.fmtKeyValFill(_(' * Maybe you meant: '),
545 ", ".join(matches))
546 self.verbose_logger.log(yum.logginglevels.INFO_2, msg)
547
548 def _checkMaybeYouMeant(self, arg, always_output=True):
549 """ If the update/remove argument doesn't match with case, or due
550 to not being installed, tell the user. """
551 # always_output is a wart due to update/remove not producing the
552 # same output.
553 matches = self.doPackageLists(patterns=[arg], ignore_case=False)
554 if (matches.installed or (not matches.available and
555 self.returnInstalledPackagesByDep(arg))):
556 return # Found a match so ignore
557 hibeg = self.term.MODE['bold']
558 hiend = self.term.MODE['normal']
559 if matches.available:
560 self.verbose_logger.log(yum.logginglevels.INFO_2,
561 _('Package(s) %s%s%s available, but not installed.'),
562 hibeg, arg, hiend)
563 return
564
565 # No package name, so do the maybeYouMeant thing here too
566 matches = self.doPackageLists(patterns=[arg], ignore_case=True)
567 if not matches.installed and matches.available:
568 self.verbose_logger.log(yum.logginglevels.INFO_2,
569 _('Package(s) %s%s%s available, but not installed.'),
570 hibeg, arg, hiend)
571 return
572 matches = set(map(lambda x: x.name, matches.installed))
573 if always_output or matches:
574 self.verbose_logger.log(yum.logginglevels.INFO_2,
575 _('No package %s%s%s available.'),
576 hibeg, arg, hiend)
577 if matches:
578 msg = self.fmtKeyValFill(_(' * Maybe you meant: '),
579 ", ".join(matches))
580 self.verbose_logger.log(yum.logginglevels.INFO_2, msg)
581
582 def installPkgs(self, userlist):
583 """Attempts to take the user specified list of packages/wildcards
584 and install them, or if they are installed, update them to a newer
585 version. If a complete version number if specified, attempt to
586 upgrade (or downgrade if they have been removed) them to the
587 specified version"""
588 # get the list of available packages
589 # iterate over the user's list
590 # add packages to Transaction holding class if they match.
591 # if we've added any packages to the transaction then return 2 and a string
592 # if we've hit a snag, return 1 and the failure explanation
593 # if we've got nothing to do, return 0 and a 'nothing available to install' string
594
595 oldcount = len(self.tsInfo)
596
597 for arg in userlist:
598 if (arg.endswith('.rpm') and (yum.misc.re_remote_url(arg) or
599 os.path.exists(arg))):
600 self.localInstall(filelist=[arg])
601 continue # it was something on disk and it ended in rpm
602 # no matter what we don't go looking at repos
603 try:
604 self.install(pattern=arg)
605 except yum.Errors.InstallError:
606 self.verbose_logger.log(yum.logginglevels.INFO_2,
607 _('No package %s%s%s available.'),
608 self.term.MODE['bold'], arg,
609 self.term.MODE['normal'])
610 self._maybeYouMeant(arg)
611 if len(self.tsInfo) > oldcount:
612 return 2, [_('Package(s) to install')]
613 return 0, [_('Nothing to do')]
614
615 def updatePkgs(self, userlist, quiet=0):
616 """take user commands and populate transaction wrapper with
617 packages to be updated"""
618
619 # if there is no userlist, then do global update below
620 # this is probably 90% of the calls
621 # if there is a userlist then it's for updating pkgs, not obsoleting
622
623 oldcount = len(self.tsInfo)
624 if len(userlist) == 0: # simple case - do them all
625 self.update()
626
627 else:
628 # go through the userlist - look for items that are local rpms. If we find them
629 # pass them off to localInstall() and then move on
630 localupdates = []
631 for item in userlist:
632 if (item.endswith('.rpm') and (yum.misc.re_remote_url(item) or
633 os.path.exists(item))):
634 localupdates.append(item)
635
636 if len(localupdates) > 0:
637 self.localInstall(filelist=localupdates, updateonly=1)
638 for item in localupdates:
639 userlist.remove(item)
640
641 for arg in userlist:
642 if not self.update(pattern=arg):
643 self._checkMaybeYouMeant(arg)
644
645 if len(self.tsInfo) > oldcount:
646 change = len(self.tsInfo) - oldcount
647 msg = _('%d packages marked for Update') % change
648 return 2, [msg]
649 else:
650 return 0, [_('No Packages marked for Update')]
651
652 def erasePkgs(self, userlist):
653 """take user commands and populate a transaction wrapper with packages
654 to be erased/removed"""
655
656 oldcount = len(self.tsInfo)
657
658 for arg in userlist:
659 if not self.remove(pattern=arg):
660 self._checkMaybeYouMeant(arg, always_output=False)
661
662 if len(self.tsInfo) > oldcount:
663 change = len(self.tsInfo) - oldcount
664 msg = _('%d packages marked for removal') % change
665 return 2, [msg]
666 else:
667 return 0, [_('No Packages marked for removal')]
668
669 def downgradePkgs(self, userlist):
670 """Attempts to take the user specified list of packages/wildcards
671 and downgrade them. If a complete version number if specified,
672 attempt to downgrade them to the specified version"""
673
674 oldcount = len(self.tsInfo)
675
676 for arg in userlist:
677 if (arg.endswith('.rpm') and (yum.misc.re_remote_url(arg) or
678 os.path.exists(arg))):
679 self.downgradeLocal(arg)
680 continue # it was something on disk and it ended in rpm
681 # no matter what we don't go looking at repos
682
683 try:
684 self.downgrade(pattern=arg)
685 except yum.Errors.DowngradeError:
686 self.verbose_logger.log(yum.logginglevels.INFO_2,
687 _('No package %s%s%s available.'),
688 self.term.MODE['bold'], arg,
689 self.term.MODE['normal'])
690 self._maybeYouMeant(arg)
691 if len(self.tsInfo) > oldcount:
692 return 2, [_('Package(s) to downgrade')]
693 return 0, [_('Nothing to do')]
694
695 def reinstallPkgs(self, userlist):
696 """Attempts to take the user specified list of packages/wildcards
697 and reinstall them. """
698
699 oldcount = len(self.tsInfo)
700
701 for arg in userlist:
702 if (arg.endswith('.rpm') and (yum.misc.re_remote_url(arg) or
703 os.path.exists(arg))):
704 self.reinstallLocal(arg)
705 continue # it was something on disk and it ended in rpm
706 # no matter what we don't go looking at repos
707
708 try:
709 self.reinstall(pattern=arg)
710 except yum.Errors.ReinstallRemoveError:
711 self._checkMaybeYouMeant(arg, always_output=False)
712 except yum.Errors.ReinstallInstallError, e:
713 ipkg = self.rpmdb.returnPackages(patterns=[arg])[0]
714 xmsg = ''
715 if 'from_repo' in ipkg.yumdb_info:
716 xmsg = ipkg.yumdb_info.from_repo
717 xmsg = _(' (from %s)') % xmsg
718 self.verbose_logger.log(yum.logginglevels.INFO_2,
719 _('Installed package %s%s%s%s not available.'),
720 self.term.MODE['bold'], ipkg,
721 self.term.MODE['normal'], xmsg)
722 except yum.Errors.ReinstallError, e:
723 assert False, "Shouldn't happen, but just in case"
724 self.verbose_logger.log(yum.logginglevels.INFO_2, e)
725 if len(self.tsInfo) > oldcount:
726 return 2, [_('Package(s) to reinstall')]
727 return 0, [_('Nothing to do')]
728
729 def localInstall(self, filelist, updateonly=0):
730 """handles installs/updates of rpms provided on the filesystem in a
731 local dir (ie: not from a repo)"""
732
733 # read in each package into a YumLocalPackage Object
734 # append it to self.localPackages
735 # check if it can be installed or updated based on nevra versus rpmdb
736 # don't import the repos until we absolutely need them for depsolving
737
738 if len(filelist) == 0:
739 return 0, [_('No Packages Provided')]
740
741 installing = False
742 for pkg in filelist:
743 txmbrs = self.installLocal(pkg, updateonly=updateonly)
744 if txmbrs:
745 installing = True
746
747 if installing:
748 return 2, [_('Package(s) to install')]
749 return 0, [_('Nothing to do')]
750
751 def returnPkgLists(self, extcmds, installed_available=False):
752 """Returns packages lists based on arguments on the cli.returns a
753 GenericHolder instance with the following lists defined:
754 available = list of packageObjects
755 installed = list of packageObjects
756 updates = tuples of packageObjects (updating, installed)
757 extras = list of packageObjects
758 obsoletes = tuples of packageObjects (obsoleting, installed)
759 recent = list of packageObjects
760
761 installed_available = that the available package list is present
762 as .hidden_available when doing any of:
763 all/available/installed
764 """
765
766 special = ['available', 'installed', 'all', 'extras', 'updates', 'recent',
767 'obsoletes']
768
769 pkgnarrow = 'all'
770 done_hidden_available = False
771 done_hidden_installed = False
772 if len(extcmds) > 0:
773 if installed_available and extcmds[0] == 'installed':
774 done_hidden_available = True
775 extcmds.pop(0)
776 elif installed_available and extcmds[0] == 'available':
777 done_hidden_installed = True
778 extcmds.pop(0)
779 elif extcmds[0] in special:
780 pkgnarrow = extcmds.pop(0)
781
782 ypl = self.doPackageLists(pkgnarrow=pkgnarrow, patterns=extcmds,
783 ignore_case=True)
784 if self.conf.showdupesfromrepos:
785 ypl.available += ypl.reinstall_available
786
787 if installed_available:
788 ypl.hidden_available = ypl.available
789 ypl.hidden_installed = ypl.installed
790 if done_hidden_available:
791 ypl.available = []
792 if done_hidden_installed:
793 ypl.installed = []
794 return ypl
795
796 def search(self, args):
797 """cli wrapper method for module search function, searches simple
798 text tags in a package object"""
799
800 # call the yum module search function with lists of tags to search
801 # and what to search for
802 # display the list of matches
803
804 searchlist = ['name', 'summary', 'description', 'url']
805 dups = self.conf.showdupesfromrepos
806 args = map(to_unicode, args)
807 matching = self.searchGenerator(searchlist, args,
808 showdups=dups, keys=True)
809
810 okeys = set()
811 akeys = set()
812 for (po, keys, matched_value) in matching:
813 if keys != okeys:
814 if akeys:
815 print ""
816 # Print them in the order they were passed
817 used_keys = [arg for arg in args if arg in keys]
818 print self.fmtSection(_('Matched: %s') % ", ".join(used_keys))
819 okeys = keys
820 akeys.update(keys)
821 self.matchcallback(po, matched_value, args)
822
823 for arg in args:
824 if arg not in akeys:
825 self.logger.warning(_('Warning: No matches found for: %s'), arg)
826
827 if not akeys:
828 return 0, [_('No Matches found')]
829 return 0, matching
830
831 def deplist(self, args):
832 """cli wrapper method for findDeps method takes a list of packages and
833 returns a formatted deplist for that package"""
834
835 pkgs = []
836 for arg in args:
837 if (arg.endswith('.rpm') and (yum.misc.re_remote_url(arg) or
838 os.path.exists(arg))):
839 thispkg = yum.packages.YumUrlPackage(self, self.ts, arg)
840 pkgs.append(thispkg)
841 else:
842 ematch, match, unmatch = self.pkgSack.matchPackageNames([arg])
843 for po in ematch + match:
844 pkgs.append(po)
845
846 results = self.findDeps(pkgs)
847 self.depListOutput(results)
848
849 return 0, []
850
851 def provides(self, args):
852 """use the provides methods in the rpmdb and pkgsack to produce a list
853 of items matching the provides strings. This is a cli wrapper to the
854 module"""
855
856 old_sdup = self.conf.showdupesfromrepos
857 # For output, as searchPackageProvides() is always in showdups mode
858 self.conf.showdupesfromrepos = True
859 cb = self.matchcallback_verbose
860 matching = self.searchPackageProvides(args, callback=cb,
861 callback_has_matchfor=True)
862 self.conf.showdupesfromrepos = old_sdup
863
864 if len(matching) == 0:
865 for arg in args:
866 if '*' in arg or (arg and arg[0] == '/'):
867 continue
868 self.logger.warning(_('Warning: 3.0.x versions of yum would erroneously match against filenames.\n You can use "%s*/%s%s" and/or "%s*bin/%s%s" to get that behaviour'),
869 self.term.MODE['bold'], arg,
870 self.term.MODE['normal'],
871 self.term.MODE['bold'], arg,
872 self.term.MODE['normal'])
873 return 0, ['No Matches found']
874
875 return 0, []
876
877 def resolveDepCli(self, args):
878 """returns a package (one per user arg) that provide the supplied arg"""
879
880 for arg in args:
881 try:
882 pkg = self.returnPackageByDep(arg)
883 except yum.Errors.YumBaseError:
884 self.logger.critical(_('No Package Found for %s'), arg)
885 else:
886 msg = '%s:%s-%s-%s.%s' % (pkg.epoch, pkg.name, pkg.version, pkg.release, pkg.arch)
887 self.verbose_logger.info(msg)
888
889 return 0, []
890
891 def cleanCli(self, userlist):
892 hdrcode = pkgcode = xmlcode = dbcode = expccode = 0
893 pkgresults = hdrresults = xmlresults = dbresults = expcresults = []
894 if 'all' in userlist:
895 self.verbose_logger.log(yum.logginglevels.INFO_2,
896 _('Cleaning up Everything'))
897 pkgcode, pkgresults = self.cleanPackages()
898 hdrcode, hdrresults = self.cleanHeaders()
899 xmlcode, xmlresults = self.cleanMetadata()
900 dbcode, dbresults = self.cleanSqlite()
901 rpmcode, rpmresults = self.cleanRpmDB()
902 self.plugins.run('clean')
903
904 code = hdrcode + pkgcode + xmlcode + dbcode + rpmcode
905 results = (hdrresults + pkgresults + xmlresults + dbresults +
906 rpmresults)
907 for msg in results:
908 self.logger.debug(msg)
909 return code, []
910
911 if 'headers' in userlist:
912 self.logger.debug(_('Cleaning up Headers'))
913 hdrcode, hdrresults = self.cleanHeaders()
914 if 'packages' in userlist:
915 self.logger.debug(_('Cleaning up Packages'))
916 pkgcode, pkgresults = self.cleanPackages()
917 if 'metadata' in userlist:
918 self.logger.debug(_('Cleaning up xml metadata'))
919 xmlcode, xmlresults = self.cleanMetadata()
920 if 'dbcache' in userlist or 'metadata' in userlist:
921 self.logger.debug(_('Cleaning up database cache'))
922 dbcode, dbresults = self.cleanSqlite()
923 if 'expire-cache' in userlist or 'metadata' in userlist:
924 self.logger.debug(_('Cleaning up expire-cache metadata'))
925 expccode, expcresults = self.cleanExpireCache()
926 if 'rpmdb' in userlist:
927 self.logger.debug(_('Cleaning up cached rpmdb data'))
928 expccode, expcresults = self.cleanRpmDB()
929 if 'plugins' in userlist:
930 self.logger.debug(_('Cleaning up plugins'))
931 self.plugins.run('clean')
932
933 code = hdrcode + pkgcode + xmlcode + dbcode + expccode
934 results = hdrresults + pkgresults + xmlresults + dbresults + expcresults
935 for msg in results:
936 self.verbose_logger.log(yum.logginglevels.INFO_2, msg)
937 return code, []
938
939 def returnGroupLists(self, userlist):
940
941 uservisible=1
942
943 if len(userlist) > 0:
944 if userlist[0] == 'hidden':
945 uservisible=0
946 userlist.pop(0)
947 if not userlist:
948 userlist = None # Match everything...
949
950 installed, available = self.doGroupLists(uservisible=uservisible,
951 patterns=userlist)
952
953 if len(installed) > 0:
954 self.verbose_logger.log(yum.logginglevels.INFO_2,
955 _('Installed Groups:'))
956 for group in installed:
957 if self.verbose_logger.isEnabledFor(yum.logginglevels.DEBUG_3):
958 self.verbose_logger.log(yum.logginglevels.INFO_2,
959 ' %s (%s)', group.ui_name,
960 group.groupid)
961 else:
962 self.verbose_logger.log(yum.logginglevels.INFO_2,
963 ' %s', group.ui_name)
964
965 if len(available) > 0:
966 self.verbose_logger.log(yum.logginglevels.INFO_2,
967 _('Available Groups:'))
968 for group in available:
969 if self.verbose_logger.isEnabledFor(yum.logginglevels.DEBUG_3):
970 self.verbose_logger.log(yum.logginglevels.INFO_2,
971 ' %s (%s)', group.ui_name,
972 group.groupid)
973 else:
974 self.verbose_logger.log(yum.logginglevels.INFO_2,
975 ' %s', group.ui_name)
976
977 return 0, [_('Done')]
978
979 def returnGroupInfo(self, userlist):
980 """returns complete information on a list of groups"""
981 for strng in userlist:
982 group_matched = False
983 for group in self.comps.return_groups(strng):
984 self.displayPkgsInGroups(group)
985 group_matched = True
986
987 if not group_matched:
988 self.logger.error(_('Warning: Group %s does not exist.'), strng)
989
990 return 0, []
991
992 def installGroups(self, grouplist):
993 """for each group requested do 'selectGroup' on them."""
994
995 pkgs_used = []
996
997 for group_string in grouplist:
998 group_matched = False
999 for group in self.comps.return_groups(group_string):
1000 group_matched = True
1001
1002
1003 try:
1004 txmbrs = self.selectGroup(group.groupid)
1005 except yum.Errors.GroupsError:
1006 self.logger.critical(_('Warning: Group %s does not exist.'), group_string)
1007 continue
1008 else:
1009 pkgs_used.extend(txmbrs)
1010
1011 if not group_matched:
1012 self.logger.error(_('Warning: Group %s does not exist.'), group_string)
1013 continue
1014
1015 if not pkgs_used:
1016 return 0, [_('No packages in any requested group available to install or update')]
1017 else:
1018 return 2, [_('%d Package(s) to Install') % len(pkgs_used)]
1019
1020 def removeGroups(self, grouplist):
1021 """Remove only packages of the named group(s). Do not recurse."""
1022
1023 pkgs_used = []
1024 for group_string in grouplist:
1025 try:
1026 txmbrs = self.groupRemove(group_string)
1027 except yum.Errors.GroupsError:
1028 self.logger.critical(_('No group named %s exists'), group_string)
1029 continue
1030 else:
1031 pkgs_used.extend(txmbrs)
1032
1033 if not pkgs_used:
1034 return 0, [_('No packages to remove from groups')]
1035 else:
1036 return 2, [_('%d Package(s) to remove') % len(pkgs_used)]
1037
1038
1039
1040 def _promptWanted(self):
1041 # shortcut for the always-off/always-on options
1042 if self.conf.assumeyes:
1043 return False
1044 if self.conf.alwaysprompt:
1045 return True
1046
1047 # prompt if:
1048 # package was added to fill a dependency
1049 # package is being removed
1050 # package wasn't explictly given on the command line
1051 for txmbr in self.tsInfo.getMembers():
1052 if txmbr.isDep or \
1053 txmbr.ts_state == 'e' or \
1054 txmbr.name not in self.extcmds:
1055 return True
1056
1057 # otherwise, don't prompt
1058 return False
1059
1060 def usage(self):
1061 ''' Print out command line usage '''
1062 sys.stdout.write(self.optparser.format_help())
1063
1064 def shellUsage(self):
1065 ''' Print out the shell usage '''
1066 sys.stdout.write(self.optparser.get_usage())
1067
1068 def _installable(self, pkg, ematch=False):
1069
1070 """check if the package is reasonably installable, true/false"""
1071
1072 exactarchlist = self.conf.exactarchlist
1073 # we look through each returned possibility and rule out the
1074 # ones that we obviously can't use
1075
1076 if self.rpmdb.contains(po=pkg):
1077 self.verbose_logger.log(yum.logginglevels.DEBUG_3,
1078 _('Package %s is already installed, skipping'), pkg)
1079 return False
1080
1081 # everything installed that matches the name
1082 installedByKey = self.rpmdb.searchNevra(name=pkg.name)
1083 comparable = []
1084 for instpo in installedByKey:
1085 if isMultiLibArch(instpo.arch) == isMultiLibArch(pkg.arch):
1086 comparable.append(instpo)
1087 else:
1088 self.verbose_logger.log(yum.logginglevels.DEBUG_3,
1089 _('Discarding non-comparable pkg %s.%s'), instpo.name, instpo.arch)
1090 continue
1091
1092 # go through each package
1093 if len(comparable) > 0:
1094 for instpo in comparable:
1095 if pkg.verGT(instpo): # we're newer - this is an update, pass to them
1096 if instpo.name in exactarchlist:
1097 if pkg.arch == instpo.arch:
1098 return True
1099 else:
1100 return True
1101
1102 elif pkg.verEQ(instpo): # same, ignore
1103 return False
1104
1105 elif pkg.verLT(instpo): # lesser, check if the pkgtup is an exactmatch
1106 # if so then add it to be installed
1107 # if it can be multiply installed
1108 # this is where we could handle setting
1109 # it to be an 'oldpackage' revert.
1110
1111 if ematch and self.allowedMultipleInstalls(pkg):
1112 return True
1113
1114 else: # we've not got any installed that match n or n+a
1115 self.verbose_logger.log(yum.logginglevels.DEBUG_1, _('No other %s installed, adding to list for potential install'), pkg.name)
1116 return True
1117
1118 return False
1119
1120class YumOptionParser(OptionParser):
1121 '''Subclass that makes some minor tweaks to make OptionParser do things the
1122 "yum way".
1123 '''
1124
1125 def __init__(self,base, **kwargs):
1126 # check if this is called with a utils=True/False parameter
1127 if 'utils' in kwargs:
1128 self._utils = kwargs['utils']
1129 del kwargs['utils']
1130 else:
1131 self._utils = False
1132 OptionParser.__init__(self, **kwargs)
1133 self.logger = logging.getLogger("yum.cli")
1134 self.base = base
1135 self.plugin_option_group = OptionGroup(self, _("Plugin Options"))
1136 self.add_option_group(self.plugin_option_group)
1137
1138 self._addYumBasicOptions()
1139
1140 def error(self, msg):
1141 '''This method is overridden so that error output goes to logger. '''
1142 self.print_usage()
1143 self.logger.critical(_("Command line error: %s"), msg)
1144 sys.exit(1)
1145
1146 def firstParse(self,args):
1147 # Parse only command line options that affect basic yum setup
1148 try:
1149 args = _filtercmdline(
1150 ('--noplugins','--version','-q', '-v', "--quiet", "--verbose"),
1151 ('-c', '-d', '-e', '--installroot',
1152 '--disableplugin', '--enableplugin', '--releasever'),
1153 args)
1154 except ValueError, arg:
1155 self.base.usage()
1156 print >> sys.stderr, (_("\n\n%s: %s option requires an argument") %
1157 ('Command line error', arg))
1158 sys.exit(1)
1159 return self.parse_args(args=args)[0]
1160
1161 @staticmethod
1162 def _splitArg(seq):
1163 """ Split all strings in seq, at "," and whitespace.
1164 Returns a new list. """
1165 ret = []
1166 for arg in seq:
1167 ret.extend(arg.replace(",", " ").split())
1168 return ret
1169
1170 def setupYumConfig(self, args=None):
1171 # Now parse the command line for real
1172 if not args:
1173 (opts, cmds) = self.parse_args()
1174 else:
1175 (opts, cmds) = self.parse_args(args=args)
1176
1177 # Let the plugins know what happened on the command line
1178 self.base.plugins.setCmdLine(opts, cmds)
1179
1180 try:
1181 # config file is parsed and moving us forward
1182 # set some things in it.
1183
1184 # Handle remaining options
1185 if opts.assumeyes:
1186 self.base.conf.assumeyes =1
1187
1188 # Instead of going cache-only for a non-root user, try to use a
1189 # user writable cachedir. If that fails fall back to cache-only.
1190 if opts.cacheonly:
1191 self.base.conf.cache = 1
1192 elif not self.base.setCacheDir():
1193 self.base.conf.cache = 1
1194
1195 if opts.obsoletes:
1196 self.base.conf.obsoletes = 1
1197
1198 if opts.installroot:
1199 self.base.conf.installroot = opts.installroot
1200
1201 if opts.skipbroken:
1202 self.base.conf.skip_broken = True
1203
1204 if opts.showdupesfromrepos:
1205 self.base.conf.showdupesfromrepos = True
1206
1207 if opts.color not in (None, 'auto', 'always', 'never',
1208 'tty', 'if-tty', 'yes', 'no', 'on', 'off'):
1209 raise ValueError, _("--color takes one of: auto, always, never")
1210 elif opts.color is None:
1211 if self.base.conf.color != 'auto':
1212 self.base.term.reinit(color=self.base.conf.color)
1213 else:
1214 _remap = {'tty' : 'auto', 'if-tty' : 'auto',
1215 '1' : 'always', 'true' : 'always',
1216 'yes' : 'always', 'on' : 'always',
1217 '0' : 'always', 'false' : 'always',
1218 'no' : 'never', 'off' : 'never'}
1219 opts.color = _remap.get(opts.color, opts.color)
1220 if opts.color != 'auto':
1221 self.base.term.reinit(color=opts.color)
1222
1223 if opts.disableexcludes:
1224 disable_excludes = self._splitArg(opts.disableexcludes)
1225 else:
1226 disable_excludes = []
1227 self.base.conf.disable_excludes = disable_excludes
1228
1229 for exclude in self._splitArg(opts.exclude):
1230 try:
1231 excludelist = self.base.conf.exclude
1232 excludelist.append(exclude)
1233 self.base.conf.exclude = excludelist
1234 except yum.Errors.ConfigError, e:
1235 self.logger.critical(e)
1236 self.base.usage()
1237 sys.exit(1)
1238
1239 if opts.rpmverbosity is not None:
1240 self.base.conf.rpmverbosity = opts.rpmverbosity
1241
1242 # setup the progress bars/callbacks
1243 self.base.setupProgressCallbacks()
1244 # setup the callbacks to import gpg pubkeys and confirm them
1245 self.base.setupKeyImportCallbacks()
1246
1247 # Process repo enables and disables in order
1248 for opt, repoexp in opts.repos:
1249 try:
1250 if opt == '--enablerepo':
1251 self.base.repos.enableRepo(repoexp)
1252 elif opt == '--disablerepo':
1253 self.base.repos.disableRepo(repoexp)
1254 except yum.Errors.ConfigError, e:
1255 self.logger.critical(e)
1256 self.base.usage()
1257 sys.exit(1)
1258
1259 # make sure the added repos are setup.
1260 if len(opts.repos) > 0:
1261 self.base._getRepos(doSetup=True)
1262
1263 # Disable all gpg key checking, if requested.
1264 if opts.nogpgcheck:
1265 self.base.conf.gpgcheck = False
1266 self.base.conf.repo_gpgcheck = False
1267 for repo in self.base.repos.listEnabled():
1268 repo.gpgcheck = False
1269 repo.repo_gpgcheck = False
1270
1271 except ValueError, e:
1272 self.logger.critical(_('Options Error: %s'), e)
1273 self.base.usage()
1274 sys.exit(1)
1275
1276 return opts, cmds
1277
1278 def getRoot(self,opts):
1279 # If the conf file is inside the installroot - use that.
1280 # otherwise look for it in the normal root
1281 if opts.installroot:
1282 if os.access(opts.installroot+'/'+opts.conffile, os.R_OK):
1283 opts.conffile = opts.installroot+'/'+opts.conffile
1284 elif opts.conffile == '/etc/yum/yum.conf':
1285 # check if /installroot/etc/yum.conf exists.
1286 if os.access(opts.installroot+'/etc/yum.conf', os.R_OK):
1287 opts.conffile = opts.installroot+'/etc/yum.conf'
1288 root=opts.installroot
1289 else:
1290 root = '/@unixroot'
1291 return root
1292
1293 def _wrapOptParseUsage(self, opt, value, parser, *args, **kwargs):
1294 self.base.usage()
1295 self.exit()
1296
1297 def _addYumBasicOptions(self):
1298 def repo_optcb(optobj, opt, value, parser):
1299 '''Callback for the enablerepo and disablerepo option.
1300
1301 Combines the values given for these options while preserving order
1302 from command line.
1303 '''
1304 dest = eval('parser.values.%s' % optobj.dest)
1305 dest.append((opt, value))
1306
1307 if self._utils:
1308 group = OptionGroup(self, "Yum Base Options")
1309 self.add_option_group(group)
1310 else:
1311 group = self
1312
1313 # Note that we can't use the default action="help" because of the
1314 # fact that print_help() unconditionally does .encode() ... which is
1315 # bad on unicode input.
1316 group.conflict_handler = "resolve"
1317 group.add_option("-h", "--help", action="callback",
1318 callback=self._wrapOptParseUsage,
1319 help=_("show this help message and exit"))
1320 group.conflict_handler = "error"
1321
1322 group.add_option("-t", "--tolerant", action="store_true",
1323 help=_("be tolerant of errors"))
1324 group.add_option("-C", "--cacheonly", dest="cacheonly",
1325 action="store_true",
1326 help=_("run entirely from system cache, don't update cache"))
1327 group.add_option("-c", "--config", dest="conffile",
1328 default='/@unixroot/etc/yum/yum.conf',
1329 help=_("config file location"), metavar='[config file]')
1330 group.add_option("-R", "--randomwait", dest="sleeptime", type='int',
1331 default=None,
1332 help=_("maximum command wait time"), metavar='[minutes]')
1333 group.add_option("-d", "--debuglevel", dest="debuglevel", default=None,
1334 help=_("debugging output level"), type='int',
1335 metavar='[debug level]')
1336 group.add_option("--showduplicates", dest="showdupesfromrepos",
1337 action="store_true",
1338 help=_("show duplicates, in repos, in list/search commands"))
1339 group.add_option("-e", "--errorlevel", dest="errorlevel", default=None,
1340 help=_("error output level"), type='int',
1341 metavar='[error level]')
1342 group.add_option("", "--rpmverbosity", default=None,
1343 help=_("debugging output level for rpm"),
1344 metavar='[debug level name]')
1345 group.add_option("-q", "--quiet", dest="quiet", action="store_true",
1346 help=_("quiet operation"))
1347 group.add_option("-v", "--verbose", dest="verbose", action="store_true",
1348 help=_("verbose operation"))
1349 group.add_option("-y", "--assumeyes", dest="assumeyes",
1350 action="store_true", help=_("answer yes for all questions"))
1351 group.add_option("--version", action="store_true",
1352 help=_("show Yum version and exit"))
1353 group.add_option("--installroot", help=_("set install root"),
1354 metavar='[path]')
1355 group.add_option("--enablerepo", action='callback',
1356 type='string', callback=repo_optcb, dest='repos', default=[],
1357 help=_("enable one or more repositories (wildcards allowed)"),
1358 metavar='[repo]')
1359 group.add_option("--disablerepo", action='callback',
1360 type='string', callback=repo_optcb, dest='repos', default=[],
1361 help=_("disable one or more repositories (wildcards allowed)"),
1362 metavar='[repo]')
1363 group.add_option("-x", "--exclude", default=[], action="append",
1364 help=_("exclude package(s) by name or glob"), metavar='[package]')
1365 group.add_option("", "--disableexcludes", default=[], action="append",
1366 help=_("disable exclude from main, for a repo or for everything"),
1367 metavar='[repo]')
1368 group.add_option("--obsoletes", action="store_true",
1369 help=_("enable obsoletes processing during updates"))
1370 group.add_option("--noplugins", action="store_true",
1371 help=_("disable Yum plugins"))
1372 group.add_option("--nogpgcheck", action="store_true",
1373 help=_("disable gpg signature checking"))
1374 group.add_option("", "--disableplugin", dest="disableplugins", default=[],
1375 action="append", help=_("disable plugins by name"),
1376 metavar='[plugin]')
1377 group.add_option("", "--enableplugin", dest="enableplugins", default=[],
1378 action="append", help=_("enable plugins by name"),
1379 metavar='[plugin]')
1380 group.add_option("--skip-broken", action="store_true", dest="skipbroken",
1381 help=_("skip packages with depsolving problems"))
1382 group.add_option("", "--color", dest="color", default=None,
1383 help=_("control whether color is used"))
1384 group.add_option("", "--releasever", dest="releasever", default=None,
1385 help=_("set value of $releasever in yum config and repo files"))
1386
1387
1388
1389def _filtercmdline(novalopts, valopts, args):
1390 '''Keep only specific options from the command line argument list
1391
1392 This function allows us to peek at specific command line options when using
1393 the optparse module. This is useful when some options affect what other
1394 options should be available.
1395
1396 @param novalopts: A sequence of options to keep that don't take an argument.
1397 @param valopts: A sequence of options to keep that take a single argument.
1398 @param args: The command line arguments to parse (as per sys.argv[:1]
1399 @return: A list of strings containing the filtered version of args.
1400
1401 Will raise ValueError if there was a problem parsing the command line.
1402 '''
1403 out = []
1404 args = list(args) # Make a copy because this func is destructive
1405
1406 while len(args) > 0:
1407 a = args.pop(0)
1408 if '=' in a:
1409 opt, _ = a.split('=', 1)
1410 if opt in valopts:
1411 out.append(a)
1412
1413 elif a in novalopts:
1414 out.append(a)
1415
1416 elif a in valopts:
1417 if len(args) < 1:
1418 raise ValueError, a
1419 next = args.pop(0)
1420 if next[0] == '-':
1421 raise ValueError, a
1422
1423 out.extend([a, next])
1424
1425 else:
1426 # Check for single letter options that take a value, where the
1427 # value is right up against the option
1428 for opt in valopts:
1429 if len(opt) == 2 and a.startswith(opt):
1430 out.append(a)
1431
1432 return out
1433
Note: See TracBrowser for help on using the repository browser.