text: #! /usr/bin/python -tt
  # This program is free software; you can redistribute it and/or modify
  # it under the terms of the GNU General Public License as published by
  # the Free Software Foundation; either version 2 of the License, or
  # (at your option) any later version.
  #
  # This program is distributed in the hope that it will be useful,
  # but WITHOUT ANY WARRANTY; without even the implied warranty of
  # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
  # GNU Library General Public License for more details.
  #
  # You should have received a copy of the GNU General Public License
  # along with this program; if not, write to the Free Software
  # Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
  # Copyright 2005 Duke University
  
  """
  A shell implementation for the yum command line interface.
  """
  
  import sys
  import cmd
  import shlex
  import logging
  
  from yum import Errors
  from yum.constants import *
  import yum.logginglevels as logginglevels
  
  
  class YumShell(cmd.Cmd):
  
      """
      Interactive yum shell.
      """
  
      def __init__(self, base):
          cmd.Cmd.__init__(self)
          self.base = base
          self.prompt = '> '
          self.result = 0
          self.identchars += '-'
          self.from_file = False # if we're running from a file, set this
          self.resultmsgs = ['Leaving Shell']
          if (len(base.extcmds)) > 0:
              self.file = base.extcmds[0]
          self.shell_specific_commands = ['repo', 'repository', 'exit', 'quit',
                  'run', 'ts', 'transaction', 'config']
                  
          self.commandlist = self.shell_specific_commands + self.base.yum_cli_commands.keys()
          self.logger = logging.getLogger("yum.cli")
          self.verbose_logger = logging.getLogger("yum.verbose.cli")
  
          # NOTE: This is shared with self.base ... so don't reassign.
          self._shell_history_cmds = []
  
      def _shell_history_add_cmds(self, cmds):
          if not self.base.conf.history_record:
              return
  
          self._shell_history_cmds.append(cmds)
  
      def _shlex_split(self, input_string):
          """split the input using shlex rules, and error or exit accordingly"""
          
          inputs = []
          if input_string is None: # apparently shlex.split() doesn't like None as its input :)
              return inputs
              
          try:
              inputs = shlex.split(input_string)
          except ValueError, e:
              self.logger.critical('Script Error: %s', e)
              if self.from_file:
                  raise Errors.YumBaseError, "Fatal error in script, exiting"
          
          return inputs
          
      def script(self):
          try:
              fd = open(self.file, 'r')
          except IOError:
              sys.exit("Error: Cannot open %s for reading" % self.file)
          lines = fd.readlines()
          fd.close()
          self.from_file = True
          for line in lines:
              self.onecmd(line)
          self.onecmd('EOF')
          return True
              
      def default(self, line):
          if len(line) > 0 and line.strip()[0] == '#':
              pass
          else:
              (cmd, args, line) = self.parseline(line)
              if cmd not in self.commandlist:
                  xargs = [cmd]
                  self.base.plugins.run('args', args=xargs)
                  if xargs[0] == cmd:
                      self.do_help('')
                      return False
              if cmd == 'shell':
                  return
              self.base.cmdstring = line
              self.base.cmdstring = self.base.cmdstring.replace('\n', '')
              self.base.cmds = self._shlex_split(self.base.cmdstring)
              self.base.plugins.run('args', args=self.base.cmds)
  
              self._shell_history_add_cmds(self.base.cmds)
  
              try:
                  self.base.parseCommands()
              except Errors.YumBaseError:
                  pass
              else:
                  self.base.doCommands()
      
      def emptyline(self):
          pass
  
      def completenames(self, text, line, begidx, endidx):
          ret = cmd.Cmd.completenames(self, text, line, begidx, endidx)
          for command in self.base.yum_cli_commands:
              if command.startswith(text) and command != "shell":
                  ret.append(command)
          return ret
  
      def do_help(self, arg):
          msg = """
      Shell specific arguments:
        config - set config options
        repository (or repo) - enable/disable/list repositories
        transaction (or ts) - list, reset or run the transaction set
        run - run the transaction set
        exit or quit - exit the shell
      """
              
          if arg in ['transaction', 'ts']:
              msg = """
      %s arg
        list: lists the contents of the transaction
        reset: reset (zero-out) the transaction
        solve: run the dependency solver on the transaction
        run: run the transaction
                    """ % arg
          elif arg in ['repo', 'repository']:
              msg = """
      %s arg [option]
        list: lists repositories and their status. option = [all] name/id glob
        enable: enable repositories. option = repository id
        disable: disable repositories. option = repository id
      """ % arg
      
          elif arg == 'config':
              msg = """
      %s arg [value]
        args: debuglevel, errorlevel, obsoletes, gpgcheck, assumeyes, exclude
          If no value is given it prints the current value.
          If value is given it sets that value.
          """ % arg
          
          else:
              self.base.shellUsage()
          
          self.verbose_logger.info(msg)
          
      def do_EOF(self, line):
          self.resultmsgs = ['Leaving Shell']
          return True
      
      def do_quit(self, line):
          self.resultmsgs = ['Leaving Shell']
          return True
      
      def do_exit(self, line):
          self.resultmsgs = ['Leaving Shell']
          return True
      
      def do_ts(self, line):
          self.do_transaction(line)
  
      def do_transaction(self, line):
          (cmd, args, line) = self.parseline(line)
          if cmd in ['list', None]:
              self.verbose_logger.log(logginglevels.INFO_2,
                  self.base.listTransaction())
          
          elif cmd == 'reset':
              self.base.closeRpmDB()
          
          elif cmd == 'solve':
              try:
                  (code, msgs) = self.base.buildTransaction()
              except Errors.YumBaseError, e:
                  self.logger.critical('Error building transaction: %s', e)
                  return False
                  
              if code == 1:
                  for msg in msgs:
                      self.logger.critical('Error: %s', msg)
              else:
                  self.verbose_logger.log(logginglevels.INFO_2,
                      'Success resolving dependencies')
                  
          elif cmd == 'run':
              return self.do_run('')
              
          else:
              self.do_help('transaction')
      
      def do_config(self, line):
          (cmd, args, line) = self.parseline(line)
          # logs
          if cmd in ['debuglevel', 'errorlevel']:
              opts = self._shlex_split(args)
              if not opts:
                  self.verbose_logger.log(logginglevels.INFO_2, '%s: %s', cmd,
                      getattr(self.base.conf, cmd))
              else:
                  val = opts[0]
                  try:
                      val = int(val)
                  except ValueError:
                      self.logger.critical('Value %s for %s cannot be made to an int', val, cmd)
                      return
                  setattr(self.base.conf, cmd, val)
                  if cmd == 'debuglevel':
                      logginglevels.setDebugLevel(val)
                  elif cmd == 'errorlevel':
                      logginglevels.setErrorLevel(val)
          # bools
          elif cmd in ['gpgcheck', 'repo_gpgcheck', 'obsoletes', 'assumeyes']:
              opts = self._shlex_split(args)
              if not opts:
                  self.verbose_logger.log(logginglevels.INFO_2, '%s: %s', cmd,
                      getattr(self.base.conf, cmd))
              else:
                  value = opts[0]
                  if value.lower() not in BOOLEAN_STATES:
                      self.logger.critical('Value %s for %s is not a Boolean', value, cmd)
                      return False
                  value = BOOLEAN_STATES[value.lower()]
                  setattr(self.base.conf, cmd, value)
                  if cmd == 'obsoletes':
                      self.base.up = None
          
          elif cmd in ['exclude']:
              args = args.replace(',', ' ')
              opts = self._shlex_split(args)
              if not opts:
                  msg = '%s: ' % cmd
                  msg = msg + ' '.join(getattr(self.base.conf, cmd))
                  self.verbose_logger.log(logginglevels.INFO_2, msg)
                  return False
              else:
                  setattr(self.base.conf, cmd, opts)
                  if self.base.pkgSack:       # kill the pkgSack
                      self.base.pkgSack = None
                  self.base.up = None         # reset the updates
                  # reset the transaction set, we have to or we shall surely die!
                  self.base.closeRpmDB() 
          else:
              self.do_help('config')
  
      def do_repository(self, line):
          self.do_repo(line)
          
      def do_repo(self, line):
          (cmd, args, line) = self.parseline(line)
          if cmd in ['list', None]:
              # Munge things to run the repolist command
              cmds = self._shlex_split(args)
  
              if not cmds:
                  cmds = ['enabled']
              cmds.insert(0, 'repolist')
              self.base.cmds = cmds
  
              self._shell_history_add_cmds(self.base.cmds)
  
              try:
                  self.base.parseCommands()
              except Errors.YumBaseError:
                  pass
              else:
                  self.base.doCommands()
  
          elif cmd == 'enable':
              repos = self._shlex_split(args)
              for repo in repos:
                  try:
                      #  Setup the sacks/repos, we need this because we are about
                      # to setup the enabled one. And having some setup is bad.
                      self.base.pkgSack
                      changed = self.base.repos.enableRepo(repo)
                  except Errors.ConfigError, e:
                      self.logger.critical(e)
                  except Errors.RepoError, e:
                      self.logger.critical(e)
                      
                  else:
                      for repo in changed:
                          try:
                              self.base.doRepoSetup(thisrepo=repo)
                          except Errors.RepoError, e:
                              self.logger.critical('Disabling Repository')
                              self.base.repos.disableRepo(repo)
                              return False
                              
                      self.base.up = None
              
          elif cmd == 'disable':
              repos = self._shlex_split(args)
              for repo in repos:
                  try:
                      offrepos = self.base.repos.disableRepo(repo)
                  except Errors.ConfigError, e:
                      self.logger.critical(e)
                  except Errors.RepoError, e:
                      self.logger.critical(e)
  
                  else:
                      # close the repos, too
                      for repoid in offrepos:
                          thisrepo = self.base.repos.repos[repoid]
                          thisrepo.close()       # kill the pkgSack
              # rebuild the indexes to be sure we cleaned up
              self.base.pkgSack.buildIndexes()
              
          else:
              self.do_help('repo')
                  
      def do_test(self, line):
          (cmd, args, line) = self.parseline(line)
          print cmd
          print args
          print line
          
      def do_run(self, line):
          if len(self.base.tsInfo) > 0:
              try:
                  (code, msgs) = self.base.buildTransaction()
                  if code == 1:
                      for msg in msgs:
                          self.logger.critical('Error: %s', msg)
                      return False
  
                  returnval = self.base.doTransaction()
              except Errors.YumBaseError, e:
                  self.logger.critical('Error: %s', e)
              except KeyboardInterrupt, e:
                  self.logger.critical('\n\nExiting on user cancel')
              except IOError, e:
                  if e.errno == 32:
                      self.logger.critical('\n\nExiting on Broken Pipe')
              else:
                  if returnval not in [0,1,-1]:
                      self.verbose_logger.info('Transaction encountered a serious error.')
                  else:
                      if returnval == 1:
                          self.verbose_logger.info('There were non-fatal errors in the transaction')
                      elif returnval == -1:
                          self.verbose_logger.info("Transaction didn't start")
                      self.verbose_logger.log(logginglevels.INFO_2,
                          'Finished Transaction')
                  self.base.closeRpmDB()
  
  
  