Package libxyz :: Module launcher

[hide private]
[frames] | no frames]

# Source Code for Module libxyz.launcher

      1  #-*- coding: utf8 -*
      2  #
      3  # Max E. Kuznecov ~syhpoon <syhpoon@syhpoon.name> 2008
      4  #
      5  # This file is part of XYZCommander.
      6  # XYZCommander is free software: you can redistribute it and/or modify
      7  # it under the terms of the GNU Lesser Public License as published by
      8  # the Free Software Foundation, either version 3 of the License, or
      9  # (at your option) any later version.
     10  # XYZCommander is distributed in the hope that it will be useful,
     11  # but WITHOUT ANY WARRANTY; without even the implied warranty of
     12  # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
     13  # GNU Lesser Public License for more details.
     14  # You should have received a copy of the GNU Lesser Public License
     15  # along with XYZCommander. If not, see <http://www.gnu.org/licenses/>.
     16
     17  """
     18  Launcher - all neccessary initialization
     19  """
     20
     21  import sys
     22  import gettext
     23  import getopt
     24  import locale
     25  import os
     26  import glob
     27  import __builtin__
     28
     29  import libxyz
     30  import libxyz.ui as uilib
     31  import libxyz.const as const
     32  import libxyz.core as core
     33
     34  from libxyz.ui import lowui
     35  from libxyz.version import Version
     36  from libxyz.core.plugins import PluginManager
     37  from libxyz.core import logger
     38  from libxyz.core import dsl
     39  from libxyz.core.utils import ustring
     40  from libxyz.vfs import VFSDispatcher
     41
     42  from libxyz.exceptions import *
     43
     44 -class Launcher(object):
     45      """
     46      Startup class
     47      """
     48
     49      EVENT_STARTUP = u"event:startup"
     50
     51 -    def __init__(self):
     52          """
     53          Initialization
     54          """
     55
     56          gettext.install(u"xyzcmd")
     57
     58          self.cmdopts = "d:c:s:vh"
     59
     60          self.allowed_colors = (1, 16, 88, 256)
     61          self.xyz = core.XYZData()
     62          self.xyz.conf = {}
     63          self.xyz.hm = core.HookManager()
     64          self.dsl = dsl.XYZ(self.xyz)
     65          self.xyz.sm = core.SkinManager()
     66          self.xyz.am = core.ActionManager(self.xyz)
     67          self.xyz.km = core.KeyManager(self.xyz)
     68          self.xyz.vfs = VFSDispatcher(self.xyz)
     69
     70          self._path_sel = libxyz.PathSelector()
     71          self._conf = {}
     72          self._saved_term = None
     73          self._driver = None
     74          self._started = False
     75
     76          self._create_home()
     77
     78      #~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
     79
     80 -    def run(self):
     81          """
     82          Run commander
     83          """
     84
     85          self._set_enc()
     86
     87          self.parse_args()
     88          self.parse_configs_1()
     89
     90          self._driver = self._conf.get("driver",
     91                                        self.xyz.conf["xyz"]["term_lib"])
     92
     93          self.xyz.term = core.utils.setup_term()
     94          self.xyz.pm = PluginManager(self.xyz,
     95                                      self._path_sel.get_plugins_dir())
     96
     97          self.init_logger()
     98
     99          self.xyz.input = core.InputWrapper(self.xyz)
    100          self.xyz.screen = uilib.display.init_display(self._driver)
    101
    102          self.init_skin()
    103          self.parse_configs_2()
    104
    105          self._started = True
    106          xyzlog.process_pending()
    107
    108          self.xyz.screen.run_wrapper(self._run)
    109
    110          self.finalize()
    111
    112      #~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
    113
    114 -    def _set_enc(self):
    115          """
    116          Try to preset local_encoding using current locale settings.
    117          After xyz conf is parsed, this value will be overriden by
    118          local_encoding from conf, if defined
    119          """
    120
    121          __builtin__.__dict__["xyzenc"] = locale.getpreferredencoding()
    122
    123      #~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
    124
    125 -    def _run(self):
    126          panel = uilib.Panel(self.xyz)
    127          self.xyz.top = lowui.Filler(panel)
    128
    129          self.xyz.hm.dispatch(self.EVENT_STARTUP)
    130          panel.loop()
    131
    132      #~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
    133
    134 -    def _create_home(self):
    135          """
    136          Create .xyzcmd in homedir
    137          """
    138
    139          if os.path.isdir(self._path_sel.user_dir):
    140              return
    141
    142          try:
    143              os.makedirs(self._path_sel.user_dir)
    144
    145              for d in (const.CONF_DIR,
    146                        const.PLUGINS_DIR,
    147                        const.SKINS_DIR,
    148                        ):
    149                  os.mkdir(os.path.join(self._path_sel.user_dir, d))
    150          except Exception:
    151              return
    152
    153      #~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
    154
    155 -    def parse_args(self):
    156          """
    157          Parse command line arguments
    158          """
    159
    160          try:
    161              _opts, _args = getopt.getopt(sys.argv[1:], self.cmdopts)
    162          except getopt.GetoptError, e:
    163              self.error(str(e))
    164              self.usage()
    165              self.quit()
    166
    167          for _o, _a in _opts:
    168              if _o == "-d":
    169                  self._conf["driver"] = _a
    170              elif _o == "-c":
    171                  _colors = int(_a)
    172                  self._conf["colors"] = _colors
    173              elif _o == "-s":
    174                  self._conf["skin"] = _a
    175              elif _o == "-v":
    176                  self.version()
    177                  self.quit()
    178              else:
    179                  self.usage()
    180                  self.quit()
    181
    182      #~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
    183
    184 -    def init_logger(self):
    185          """
    186          Initiate Logger object and put it into builtin namespace
    187          """
    188
    189          _log = logger.LogLevel()
    190
    191          try:
    192              _levels = self.xyz.conf[u"plugins"][u":sys:logger"][u"levels"]
    193          except KeyError:
    194              _levels = (logger.LogLevel().ALL,)
    195          else:
    196              if not isinstance(_levels, tuple) and not \
    197                     isinstance(_levels, list):
    198                  _levels = (_levels,)
    199
    200          try:
    201              _levels = [getattr(_log, x) for x in _levels]
    202          except Exception:
    203              raise XYZValueError(_(u"Invalid value %s.\n"\
    204                                    u"A list of valid log levels expected"
    205                                    % ustring(_levels)))
    206
    207          try:
    208              _lines = self.xyz.conf[u"plugins"][u":sys:logger"][u"lines"]
    209          # Value not defined in conf
    210          except KeyError:
    211              _lines = 100
    212
    213          try:
    214              _lines = abs(int(_lines))
    215          except ValueError:
    216              raise XYZValueError(_(u"Invalid value %s. "\
    217                                    u"A positive integer expected" %
    218                                    ustring(_lines)))
    219
    220          _logger = core.logger.Logger(self.xyz, _levels, _lines)
    221
    222          __builtin__.__dict__["xyzlog"] = _logger
    223
    224      #~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
    225
    226 -    def init_skin(self):
    227          """
    228          Init selected skin
    229          """
    230
    231          colors = self._conf.get("colors",
    232                                  self.xyz.conf["xyz"]["term_colors"])
    233
    234          if colors not in self.allowed_colors:
    235              self.usage()
    236              self.quit()
    237
    238          skin = self.xyz.sm.get(self._conf.get("skin",
    239                                                self.xyz.conf[u"xyz"][u"skin"]))
    240
    241
    242          if skin and skin.colors and colors not in skin.colors:
    243              xyzlog.warning(_(u"Skin %s is not usable with requested "\
    244                               u"color settings. Using default.") % skin.name)
    245              skin = self.xyz.sm.get(const.DEFAULT_SKIN)
    246
    247          if skin is None:
    248              skin = self.xyz.sm.get(const.DEFAULT_SKIN)
    249
    250          # Purge unused skins to save some memory
    251          self.xyz.sm.clear()
    252
    253          self.xyz.screen.register_palette(skin.get_palette_list(self._driver))
    254
    255          if hasattr(self.xyz.screen, "set_terminal_properties"):
    256              self.xyz.screen.set_terminal_properties(colors=colors)
    257
    258          self.xyz.skin = skin
    259          self.xyz.skin.set_screen(self.xyz.screen)
    260
    261      #~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
    262
    263 -    def parse_configs_1(self):
    264          """
    265          Parse configuration. Phase 1
    266          """
    267
    268          self._parse_conf_file(const.XYZ_CONF_FILE)
    269          self._parse_conf_file(const.PLUGINS_CONF_FILE)
    270          self._parse_conf_file(const.ALIASES_CONF_FILE)
    271          self._parse_conf_file(const.ICMD_CONF_FILE)
    272          self._parse_conf_file(const.VFS_CONF_FILE)
    273          self._parse_conf_file(const.HOOKS_CONF_FILE)
    274
    275          # Load skins
    276          self._parse_skins()
    277
    278          # local_encoding set, override guessed encoding
    279          if "local_encoding" in self.xyz.conf["xyz"]:
    280              __builtin__.__dict__["xyzenc"] = \
    281                                        self.xyz.conf["xyz"]["local_encoding"]
    282
    283      #~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
    284
    285 -    def parse_configs_2(self):
    286          """
    287          Parse configuration. Phase 2
    288          """
    289
    290          self._parse_conf_file(const.ACTIONS_CONF_FILE)
    291          self._parse_conf_file(const.KEYS_CONF_FILE)
    292
    293      #~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
    294
    295 -    def _parse_conf_file(self, conf_file):
    296          """
    297          Parse configuration files, first system then user one if any
    298          @param conf_file: File to parse
    299          """
    300
    301          _system, _user = self._path_sel.get_conf(conf_file)
    302
    303          # Exec system config first
    304          self._parse_file(_system, _(u"Error parsing system config %s: %s"))
    305
    306          # Now try to exec users's conf, if exists
    307          if os.path.exists(_user):
    308              self._parse_file(_user, _(u"Error parsing user config %s: %s"))
    309
    310      #~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
    311
    312 -    def _parse_skins(self):
    313          """
    314          Load all skins in system and user home dirs
    315          """
    316
    317          user_skins, system_skins = self._path_sel.get_skins_dir()
    318
    319          system_skins = glob.glob(os.path.join(system_skins, "*"))
    320
    321          if os.path.exists(user_skins):
    322              user_skins = glob.glob(os.path.join(user_skins, "*"))
    323          else:
    324              user_skins = []
    325
    326          for skin in system_skins + user_skins:
    327              res = self._parse_file(skin, error=False)
    328
    329              if res != True:
    330                  self.error(_(u"Skipping skin %s due to parsing error: %s" %
    331                                (skin, res)), False)
    332
    333      #~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
    334
    335 -    def _parse_file(self, file, tmpl=None, error=True):
    336          """
    337          Parse XYZCommander config
    338          """
    339
    340          if tmpl is None:
    341              tmpl = _(u"Error parsing config %s: %s")
    342
    343          try:
    344              dsl.exec_file(file)
    345          except DSLError, e:
    346              if error:
    347                  self.error(tmpl % (file, ustring(str(e))))
    348              else:
    349                  return ustring(str(e))
    350
    351          return True
    352
    353      #~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
    354
    355 -    def usage(self):
    356          """
    357          Show usage
    358          """
    359
    360          print _(u"""\
    361  %s version %s
    362  Usage: %s [-d driver][-c colors][-s skin][-vh]
    363      -d  -- Display driver (raw (default) or curses)
    364      -c  -- Number of colors terminal supports (1, 16 (default), 88, 256)
    365      -s  -- Skin name
    366      -v  -- Show version
    367      -h  -- Show this help message\
    368  """ % (const.PROG, Version.version, os.path.basename(sys.argv[0])))
    369
    370      #~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
    371
    372 -    def version(self):
    373          """
    374          Show version
    375          """
    376
    377          print _(u"%s version %s" % (const.PROG, Version.version))
    378
    379      #~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
    380
    381 -    def quit(self):
    382          """
    383          Quit program
    384          """
    385
    386          sys.exit()
    387
    388      #~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
    389
    390 -    def error(self, msg, quit=True):
    391          """
    392          Print error message and optionally quit
    393          """
    394
    395          if self._started:
    396              xyzlog.log(msg)
    397          else:
    398              # Before logger initiated, print errors to stdout
    399              print msg
    400
    401          if quit:
    402              self.quit()
    403
    404      #~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
    405
    406 -    def finalize(self):
    407          """
    408          Perform shutdown procedures
    409          """
    410
    411          if self.xyz.term is not None:
    412              core.utils.restore_term(self.xyz.term)
    413