Package plugins :: Package core :: Package shell :: Module main |
[hide private]
[frames] | no frames]

# Source Code for Module plugins.core.shell.main

      1  #-*- coding: utf8 -*
      2  #
      3  # Max E. Kuznecov <syhpoon@syhpoon.name> 2009
      4  #
      5
      6  import sys
      7  import errno
      8  import os
      9  import signal
     10
     11  import libxyz.core as core
     12
     13  from libxyz.core.utils import bstring
     14  from libxyz.core.plugins import BasePlugin
     15
     16  from bash import bash_setup
     17
     18 -class XYZPlugin(BasePlugin):
     19      "Shell plugin"
     20
     21      NAME = u"shell"
     22      AUTHOR = u"Max E. Kuznecov <syhpoon@syhpoon.name>"
     23      VERSION = u"0.2"
     24      BRIEF_DESCRIPTION = _(u"Shell wrapper")
     25      FULL_DESCRIPTION = _(u"Execute commands in external shell")
     26      NAMESPACE = u"core"
     27      MIN_XYZ_VERSION = None
     28      DOC = u"Configuration variables:\n"\
     29            u"wait - Boolean flag indicating whether to wait for user pressing "\
     30            u"key after command executed. Default True\n"\
     31            u"setup_shell - Boolean flag indicating whether to run "\
     32            u"system shell-specific initialization. Default True"
     33
     34      HOMEPAGE = "http://xyzcmd.syhpoon.name"
     35      EVENTS = [("execute",
     36                 _(u"Fires before command execution. "\
     37                   u"Arguments: a command to be executed")),
     38                ]
     39
     40      shell_args = {
     41          "sh": ["-c"],
     42          "bash": ["-c"],
     43          "zsh": ["-c"]
     44          }
     45
     46      shell_setup = {
     47          "bash": bash_setup
     48          }
     49
     50 -    def __init__(self, xyz):
     51          self.status = 0
     52          self.shell = None
     53
     54          super(XYZPlugin, self).__init__(xyz)
     55
     56          self.export(self.execute)
     57          self.export(self.echo)
     58
     59      #~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
     60
     61 -    def prepare(self):
     62          # Determine shell
     63          shell = self.xyz.conf["xyz"]["shell"]
     64          _base = os.path.basename(shell)
     65
     66          if _base not in self.shell_args:
     67              shell, _base = "/bin/sh", "sh"
     68
     69          self.shell = [shell] + self.shell_args[_base]
     70
     71          # Setup shell
     72          if self.conf["setup_shell"] and _base in self.shell_setup:
     73              self.shell_setup[_base](shell)
     74
     75      #~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
     76
     77 -    def execute(self, cmd, wait=None):
     78          """
     79          Execute command in shell
     80          """
     81
     82          cmd = bstring(cmd)
     83          self.fire_event("execute", cmd)
     84
     85          def _exec():
     86              pid = os.fork()
     87
     88              # Child - Exec passed cmd
     89              if pid == 0:
     90                  os.execvp(self.shell[0], self.shell + [cmd])
     91                  # WTF?
     92                  sys.exit()
     93                  # Parent
     94              else:
     95                  while True:
     96                      try:
     97                          self.status = os.waitpid(pid, 0)
     98                      except KeyboardInterrupt:
     99                          pass
    100                      except OSError, e:
    101                          if e.errno != errno.EINTR:
    102                              break
    103
    104              return self.status
    105
    106          return self._exec_engine(cmd, _exec, wait)
    107
    108      #~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
    109
    110 -    def echo(self, msg):
    111          """
    112          Echo a message to terminal output
    113          """
    114
    115          def _echo():
    116              print(msg)
    117
    118          return self._exec_engine("echo", _echo)
    119
    120      #~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
    121
    122 -    def _press_key(self, msg, key):
    123          """
    124          Print prompt and wait for the key to be pressed
    125          """
    126
    127          sys.stdout.write(msg)
    128          sys.stdout.flush()
    129
    130          while True:
    131              try:
    132                  m = os.read(sys.stdin.fileno(), 1024)
    133                  if key in m:
    134                      break
    135              except OSError, e:
    136                  if e.errno != errno.EINTR:
    137                      break
    138
    139      #~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
    140
    141 -    def _exec_engine(self, cmd, cmdf, wait=None):
    142          """
    143          Execute command engine
    144          """
    145
    146          self.xyz.screen.clear()
    147          stdout = sys.stdout
    148          self.xyz.screen.stop()
    149
    150          _current_term = None
    151
    152          # Restore original terminal settings
    153          if self.xyz.term is not None:
    154              _current_term = core.utils.term_settings()[-1]
    155              core.utils.restore_term(self.xyz.term)
    156
    157          # Clear the screen
    158          #TODO: make it more portable!
    159          stdout.write("\x1b[H\x1b[2J")
    160
    161          stdout.write("%s%s\n" %
    162                       (bstring(
    163                           self.xyz.conf[u"plugins"][":sys:cmd"][u"prompt"]),
    164                        cmd))
    165          stdout.flush()
    166
    167          def _sigwinch(_a, _b):
    168              self.xyz.screen.resized = True
    169
    170          signal.signal(signal.SIGWINCH, _sigwinch)
    171
    172          status = cmdf()
    173
    174          if _current_term is not None:
    175              core.utils.restore_term(_current_term)
    176
    177          if wait == True or (wait != False and self.conf["wait"]):
    178              self._press_key(_(u"Press ENTER to continue..."), "\n")
    179
    180          self.xyz.screen.start()
    181
    182          return status
    183