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