Blame dnf/cli/commands/shell.py

Packit 6f3914
# shell.py
Packit 6f3914
# Shell CLI command.
Packit 6f3914
#
Packit 6f3914
# Copyright (C) 2016 Red Hat, Inc.
Packit 6f3914
#
Packit 6f3914
# This copyrighted material is made available to anyone wishing to use,
Packit 6f3914
# modify, copy, or redistribute it subject to the terms and conditions of
Packit 6f3914
# the GNU General Public License v.2, or (at your option) any later version.
Packit 6f3914
# This program is distributed in the hope that it will be useful, but WITHOUT
Packit 6f3914
# ANY WARRANTY expressed or implied, including the implied warranties of
Packit 6f3914
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General
Packit 6f3914
# Public License for more details.  You should have received a copy of the
Packit 6f3914
# GNU General Public License along with this program; if not, write to the
Packit 6f3914
# Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
Packit 6f3914
# 02110-1301, USA.  Any Red Hat trademarks that are incorporated in the
Packit 6f3914
# source code or documentation are not subject to the GNU General Public
Packit 6f3914
# License and may only be used or replicated with the express permission of
Packit 6f3914
# Red Hat, Inc.
Packit 6f3914
#
Packit 6f3914
Packit 6f3914
from dnf.cli import commands
Packit 6f3914
from dnf.i18n import _, ucd
Packit 6f3914
Packit 6f3914
import dnf.util
Packit 6f3914
import cmd
Packit 6f3914
import copy
Packit 6f3914
import dnf
Packit 6f3914
import logging
Packit 6f3914
import shlex
Packit 6f3914
import sys
Packit 6f3914
Packit 6f3914
Packit 6f3914
logger = logging.getLogger('dnf')
Packit 6f3914
Packit 6f3914
Packit 6f3914
# only demands we'd like to override
Packit 6f3914
class ShellDemandSheet(object):
Packit 6f3914
    available_repos = True
Packit 6f3914
    resolving = True
Packit 6f3914
    root_user = True
Packit 6f3914
    sack_activation = True
Packit 6f3914
Packit 6f3914
Packit 6f3914
class ShellCommand(commands.Command, cmd.Cmd):
Packit 6f3914
Packit 6f3914
    aliases = ('shell', 'sh')
Packit 6f3914
    summary = _('run an interactive {prog} shell').format(prog=dnf.util.MAIN_PROG_UPPER)
Packit 6f3914
Packit 6f3914
    MAPPING = {'repo': 'repo',
Packit 6f3914
               'repository': 'repo',
Packit 6f3914
               'exit': 'quit',
Packit 6f3914
               'quit': 'quit',
Packit 6f3914
               'run': 'ts_run',
Packit 6f3914
               'ts': 'transaction',
Packit 6f3914
               'transaction': 'transaction',
Packit 6f3914
               'config': 'config',
Packit 6f3914
               'resolvedep': 'resolve',
Packit 6f3914
               'help': 'help'
Packit 6f3914
               }
Packit 6f3914
Packit 6f3914
    def __init__(self, cli):
Packit 6f3914
        commands.Command.__init__(self, cli)
Packit 6f3914
        cmd.Cmd.__init__(self)
Packit 6f3914
        self.prompt = '> '
Packit 6f3914
Packit 6f3914
    @staticmethod
Packit 6f3914
    def set_argparser(parser):
Packit 6f3914
        parser.add_argument('script', nargs='?', metavar=_('SCRIPT'),
Packit 6f3914
                            help=_('Script to run in {prog} shell').format(
Packit 6f3914
                                prog=dnf.util.MAIN_PROG_UPPER))
Packit 6f3914
Packit 6f3914
    def configure(self):
Packit 6f3914
        # append to ShellDemandSheet missing demands from
Packit 6f3914
        # dnf.cli.demand.DemandSheet with their default values.
Packit 6f3914
        default_demands = self.cli.demands
Packit 6f3914
        self.cli.demands = ShellDemandSheet()
Packit 6f3914
        for attr in dir(default_demands):
Packit 6f3914
            if attr.startswith('__'):
Packit 6f3914
                continue
Packit 6f3914
            try:
Packit 6f3914
                getattr(self.cli.demands, attr)
Packit 6f3914
            except AttributeError:
Packit 6f3914
                setattr(self.cli.demands, attr, getattr(default_demands, attr))
Packit 6f3914
Packit 6f3914
    def run(self):
Packit 6f3914
        if self.opts.script:
Packit 6f3914
            self._run_script(self.opts.script)
Packit 6f3914
        else:
Packit 6f3914
            self.cmdloop()
Packit 6f3914
Packit 6f3914
    def _clean(self):
Packit 6f3914
        self.base._finalize_base()
Packit 6f3914
        self.base._transaction = None
Packit 6f3914
        self.base.fill_sack()
Packit 6f3914
Packit 6f3914
    def onecmd(self, line):
Packit 6f3914
        if not line or line == '\n':
Packit 6f3914
            return
Packit 6f3914
        if line == 'EOF':
Packit 6f3914
            line = 'quit'
Packit 6f3914
        try:
Packit 6f3914
            s_line = shlex.split(line)
Packit 6f3914
        except:
Packit 6f3914
            self._help()
Packit 6f3914
            return
Packit 6f3914
        # reset option parser before each command, keep usage information
Packit 6f3914
        self.cli.optparser.__init__(reset_usage=False)
Packit 6f3914
        opts = self.cli.optparser.parse_main_args(s_line)
Packit 6f3914
        # Disable shell recursion.
Packit 6f3914
        if opts.command == 'shell':
Packit 6f3914
            return
Packit 6f3914
        if opts.command in self.MAPPING:
Packit 6f3914
            getattr(self, '_' + self.MAPPING[opts.command])(s_line[1::])
Packit 6f3914
        else:
Packit 6f3914
            cmd_cls = self.cli.cli_commands.get(opts.command)
Packit 6f3914
            if cmd_cls is not None:
Packit 6f3914
                cmd = cmd_cls(self.cli)
Packit 6f3914
                try:
Packit 6f3914
                    opts = self.cli.optparser.parse_command_args(cmd, s_line)
Packit 6f3914
                except SystemExit:
Packit 6f3914
                    # argparse.ArgumentParser prints usage information and executes
Packit 6f3914
                    # sys.exit() on problems with parsing command line arguments
Packit 6f3914
                    return
Packit 6f3914
                try:
Packit 6f3914
                    cmd.cli.demands = copy.deepcopy(self.cli.demands)
Packit 6f3914
                    cmd.configure()
Packit 6f3914
                    cmd.run()
Packit 6f3914
                except dnf.exceptions.Error as e:
Packit 6f3914
                    logger.error(_("Error:") + " " + ucd(e))
Packit 6f3914
                    return
Packit 6f3914
            else:
Packit 6f3914
                self._help()
Packit 6f3914
Packit 6f3914
    def _config(self, args=None):
Packit 6f3914
        def print_or_set(key, val, conf):
Packit 6f3914
            if val:
Packit 6f3914
                setattr(conf, key, val)
Packit 6f3914
            else:
Packit 6f3914
                try:
Packit 6f3914
                    print('{}: {}'.format(key, getattr(conf, str(key))))
Packit 6f3914
                except:
Packit 6f3914
                    logger.warning(_('Unsupported key value.'))
Packit 6f3914
Packit 6f3914
        if not args or len(args) > 2:
Packit 6f3914
            self._help('config')
Packit 6f3914
            return
Packit 6f3914
Packit 6f3914
        key = args[0]
Packit 6f3914
        val = args[1] if len(args) == 2 else None
Packit 6f3914
        period = key.find('.')
Packit 6f3914
        if period != -1:
Packit 6f3914
            repo_name = key[:period]
Packit 6f3914
            key = key[period+1:]
Packit 6f3914
            repos = self.base.repos.get_matching(repo_name)
Packit 6f3914
            for repo in repos:
Packit 6f3914
                print_or_set(key, val, repo)
Packit 6f3914
            if not repos:
Packit 6f3914
                logger.warning(_('Could not find repository: %s'),
Packit 6f3914
                               repo_name)
Packit 6f3914
        else:
Packit 6f3914
            print_or_set(key, val, self.base.conf)
Packit 6f3914
Packit 6f3914
    def _help(self, args=None):
Packit 6f3914
        """Output help information.
Packit 6f3914
Packit 6f3914
        :param args: the command to output help information about. If
Packit 6f3914
           *args* is an empty, general help will be output.
Packit 6f3914
        """
Packit 6f3914
        arg = args[0] if isinstance(args, list) and len(args) > 0 else args
Packit 6f3914
        msg = None
Packit 6f3914
Packit 6f3914
        if arg:
Packit 6f3914
            if arg == 'config':
Packit 6f3914
                msg = _("""{} arg [value]
Packit 6f3914
  arg: debuglevel, errorlevel, obsoletes, gpgcheck, assumeyes, exclude,
Packit 6f3914
        repo_id.gpgcheck, repo_id.exclude
Packit 6f3914
    If no value is given it prints the current value.
Packit 6f3914
    If value is given it sets that value.""").format(arg)
Packit 6f3914
Packit 6f3914
            elif arg == 'help':
Packit 6f3914
                msg = _("""{} [command]
Packit 6f3914
    print help""").format(arg)
Packit 6f3914
Packit 6f3914
            elif arg in ['repo', 'repository']:
Packit 6f3914
                msg = _("""{} arg [option]
Packit 6f3914
  list: lists repositories and their status. option = [all | id | glob]
Packit 6f3914
  enable: enable repositories. option = repository id
Packit 6f3914
  disable: disable repositories. option = repository id""").format(arg)
Packit 6f3914
Packit 6f3914
            elif arg == 'resolvedep':
Packit 6f3914
                msg = _("""{}
Packit 6f3914
    resolve the transaction set""").format(arg)
Packit 6f3914
Packit 6f3914
            elif arg in ['transaction', 'ts']:
Packit 6f3914
                msg = _("""{} arg
Packit 6f3914
  list: lists the contents of the transaction
Packit 6f3914
  reset: reset (zero-out) the transaction
Packit 6f3914
  run: run the transaction""").format(arg)
Packit 6f3914
Packit 6f3914
            elif arg == 'run':
Packit 6f3914
                msg = _("""{}
Packit 6f3914
    run the transaction""").format(arg)
Packit 6f3914
Packit 6f3914
            elif arg in ['exit', 'quit']:
Packit 6f3914
                msg = _("""{}
Packit 6f3914
    exit the shell""").format(arg)
Packit 6f3914
Packit 6f3914
        if not msg:
Packit 6f3914
            self.cli.optparser.print_help()
Packit 6f3914
            msg = _("""Shell specific arguments:
Packit 6f3914
Packit 6f3914
config                   set config options
Packit 6f3914
help                     print help
Packit 6f3914
repository (or repo)     enable, disable or list repositories
Packit 6f3914
resolvedep               resolve the transaction set
Packit 6f3914
transaction (or ts)      list, reset or run the transaction set
Packit 6f3914
run                      resolve and run the transaction set
Packit 6f3914
exit (or quit)           exit the shell""")
Packit 6f3914
Packit 6f3914
        print('\n' + msg)
Packit 6f3914
Packit 6f3914
    def _repo(self, args=None):
Packit 6f3914
        cmd = args[0] if args else None
Packit 6f3914
Packit 6f3914
        if cmd in ['list', None]:
Packit 6f3914
            self.onecmd('repolist ' + ' '.join(args[1:]))
Packit 6f3914
Packit 6f3914
        elif cmd in ['enable', 'disable']:
Packit 6f3914
            repos = self.cli.base.repos
Packit 6f3914
            fill_sack = False
Packit 6f3914
            for repo in args[1::]:
Packit 6f3914
                r = repos.get_matching(repo)
Packit 6f3914
                if r:
Packit 6f3914
                    getattr(r, cmd)()
Packit 6f3914
                    fill_sack = True
Packit 6f3914
                else:
Packit 6f3914
                    logger.critical(_("Error:") + " " + _("Unknown repo: '%s'"),
Packit 6f3914
                                    self.base.output.term.bold(repo))
Packit 6f3914
            if fill_sack:
Packit 6f3914
                self.base.fill_sack()
Packit 6f3914
Packit 6f3914
        else:
Packit 6f3914
            self._help('repo')
Packit 6f3914
Packit 6f3914
    def _resolve(self, args=None):
Packit 6f3914
        try:
Packit 6f3914
            self.cli.base.resolve(self.cli.demands.allow_erasing)
Packit 6f3914
        except dnf.exceptions.DepsolveError as e:
Packit 6f3914
            print(e)
Packit 6f3914
Packit 6f3914
    def _run_script(self, file):
Packit 6f3914
        try:
Packit 6f3914
            with open(file, 'r') as fd:
Packit 6f3914
                lines = fd.readlines()
Packit 6f3914
                for line in lines:
Packit 6f3914
                    if not line.startswith('#'):
Packit 6f3914
                        self.onecmd(line)
Packit 6f3914
        except IOError:
Packit 6f3914
            logger.info(_('Error: Cannot open %s for reading'), self.base.output.term.bold(file))
Packit 6f3914
            sys.exit(1)
Packit 6f3914
Packit 6f3914
    def _transaction(self, args=None):
Packit 6f3914
        cmd = args[0] if args else None
Packit 6f3914
Packit 6f3914
        if cmd == 'reset':
Packit 6f3914
            self._clean()
Packit 6f3914
            return
Packit 6f3914
Packit 6f3914
        self._resolve()
Packit 6f3914
        if cmd in ['list', None]:
Packit 6f3914
            if self.base._transaction:
Packit 6f3914
                out = self.base.output.list_transaction(self.base._transaction)
Packit 6f3914
                logger.info(out)
Packit 6f3914
Packit 6f3914
        elif cmd == 'run':
Packit 6f3914
            try:
Packit 6f3914
                self.base.do_transaction()
Packit 6f3914
            except dnf.exceptions.Error as e:
Packit 6f3914
                logger.error(_("Error:") + " " + ucd(e))
Packit 6f3914
            else:
Packit 6f3914
                logger.info(_("Complete!"))
Packit 6f3914
            self._clean()
Packit 6f3914
Packit 6f3914
        else:
Packit 6f3914
            self._help('transaction')
Packit 6f3914
Packit 6f3914
    def _ts_run(self, args=None):
Packit 6f3914
        self._transaction(['run'])
Packit 6f3914
Packit 6f3914
    def _quit(self, args=None):
Packit 6f3914
        logger.info(_('Leaving Shell'))
Packit 6f3914
        sys.exit(0)