web.pluginmanager.pluginmanager

Package web :: Package pluginmanager :: Module pluginmanager |
[hide private]
[frames] | no frames]

# Source Code for Module web.pluginmanager.pluginmanager

      1  import config
      2  import db
      3  import os
      4  from shutil import rmtree
      5
      6  from plugins.model import Plugin
      7
      8 -class PluginManager:
      9 -    def __init__(self):
     10          # Instance list
     11          self.plugins = []
     12          orm = db.connect()
     13
     14          for plugin_name in self.__get_plugins_directories():
     15              instance = self.__instance_plugin(plugin_name)
     16              self.plugins.append(instance)
     17
     18          enabled_plugins = [i.name for i in orm.query(Plugin).filter(Plugin.enabled==True).all()]
     19
     20          for plugin in self.plugins:
     21              if plugin.name in enabled_plugins:
     22                  self.enable_plugin(plugin.name)
     23
     24 -    def enable_plugin(self, name):
     25          '''
     26          Enables a plugin if all the deps are met. Else it raises UnmetDependencyException.
     27          Returns the list of enabled plugins. In this case, enable means this plugins will be enabled
     28          in the future: this function will only be called when the user enables a plugin in the
     29          pluginmanager.PluginListView.
     30          '''
     31          enabled_plugins = []
     32          plugin = self.get_plugin_by_name(name)
     33          if plugin == None:
     34              return enabled_plugins
     35
     36          plugins_deps = self.__get_dependencies(plugin)
     37
     38          for plugin_dep in plugins_deps:
     39              if not plugin_dep.is_enabled():
     40                  self.__enable_plugin(plugin_dep)
     41                  enabled_plugins.append(plugin_dep)
     42
     43          return enabled_plugins
     44
     45 -    def disable_plugin(self, name):
     46          '''
     47          Disables a plugin and all plugins that have given plugin as a dependency.
     48          Returns the list of disabled plugins. In this case, disable means this plugins will be disabled
     49          in the future: this function will only be called when the user disables a plugin in the
     50          pluginmanager.PluginListView.
     51          '''
     52          disabled_plugins = []
     53          plugin = self.get_plugin_by_name(name)
     54          if plugin == None:
     55              return disabled_plugins
     56
     57          plugins_deps = self.__get_reverse_dependencies(plugin)
     58
     59          for plugin_dep in plugins_deps:
     60              if plugin_dep.is_enabled():
     61                  self.__disable_plugin(plugin_dep)
     62                  disabled_plugins.append(plugin_dep)
     63
     64          return disabled_plugins
     65
     66 -    def uninstall_plugin(self, name, delete_files):
     67          '''
     68          Uninstall the given plugin. There are two ways of uninstall:
     69            * When delete_files is false, then this function only deletes
     70            all plugin's data in the db. In this way you can reinstall the
     71            plugin when you want.
     72            * When delete_files is true, then this function delete all plugin's
     73            data in the db and plugin's directory. In this way all data is
     74            deleted, so you have to get the whole plugin to reinstall.
     75
     76          Either way, this function always removes the installed files in static/
     77          and templates/ for this plugin.
     78
     79          Before uninstalling a plugin, it MUST be disabled and obviously all
     80          the plugins that have the plugin as a dependency.
     81          '''
     82          plugin = self.get_plugin_by_name(name)
     83          if plugin.enabled == True:
     84              return False
     85
     86          plugin.uninstall()
     87
     88          # Remove from the plugins' table of data base
     89          orm = db.connect()
     90          query = orm.query(Plugin).filter(Plugin.name == name)
     91          if query.count() == 1:
     92              orm.delete(query.first())
     93              orm.commit()
     94
     95          static_dir = os.path.join(config.curdir, 'static/plugins', name)
     96          if os.path.islink(static_dir):
     97              os.unlink(static_dir)
     98          templates_dir = os.path.join(config.curdir, 'templates/plugins', name)
     99          if os.path.islink(templates_dir):
    100              os.unlink(templates_dir)
    101
    102          # Deleting
    103          if delete_files:
    104              path = os.path.join(config.pluginsdir, name)
    105              rmtree(path)
    106              # Remove from the list of plugin
    107              self.plugins.remove(plugin)
    108
    109          # removing plugin tables from database
    110          pmodule = __import__('pluginmanager.plugins.%s.%s' % (plugin.name, 'model'), fromlist=["true"])
    111          db.drop_from_model(pmodule)
    112
    113          return True
    114
    115 -    def check_for_new_plugins(self):
    116          '''
    117          Look for new instances in plugins' directory and
    118          add to self.plugins.
    119          '''
    120          plugins_name = (p.name for p in self.plugins)
    121
    122          for plugin_name in self.__get_plugins_directories():
    123              if not plugin_name in plugins_name:
    124                  instance = self.__instance_plugin(plugin_name)
    125                  self.plugins.append(instance)
    126
    127 -    def get_plugin_by_name(self, name):
    128          '''
    129          Return the instance of the plugin whose name is given.
    130          None is returned if the instance is not found.
    131          '''
    132          for plugin in self.plugins:
    133              if plugin.name == name:
    134                  return plugin
    135          return None
    136
    137 -    def get_enabled_plugins(self):
    138          '''
    139          Return a instance list of the enabled plugins.
    140          '''
    141          return (i for i in self.plugins if i.is_enabled())
    142
    143 -    def __enable_plugin(self, plugin):
    144          '''
    145          Enable a plugin without verify the dependencies.
    146          '''
    147          orm = db.connect()
    148          dbplugin = orm.query(Plugin).filter_by(name=plugin.name).first()
    149
    150          if not dbplugin:
    151              # This means that the plugin is not installed, so we proceed to install it now
    152              self.__install_plugin(plugin)
    153
    154          else:
    155              dbplugin.enabled = True
    156              orm.commit()
    157
    158          plugin.enable()
    159          plugin.enabled = True
    160
    161
    162 -    def __install_plugin(self, plugin):
    163          '''
    164          Called only by __enable_plugin when a plugin has not been installed before.
    165
    166          * Creates the tables in the database from the plugin model
    167          * installs the static/ and templates/ plugin directories in
    168            static/plugins/<pluginname> and templates/plugins/<pluginname>/
    169          * calls to the install() function of the given plugin
    170          '''
    171
    172          # * Create tables in the db from the plugin model
    173          orm = db.connect()
    174          dbplugin = Plugin(plugin)
    175          dbplugin.enabled = True
    176          orm.add(dbplugin)
    177          orm.commit()
    178          pmodule = __import__('pluginmanager.plugins.%s.%s' % (plugin.name, 'model'), fromlist=["true"])
    179          db.create_from_model(pmodule)
    180
    181          # * install static
    182          plugin_static_dir = os.path.join(config.pluginsdir, plugin.name, 'static')
    183          if os.path.isdir(plugin_static_dir):
    184              # only will install it if the plugin has a static/ dir, obviously
    185              plugins_static_dir = os.path.join(config.curdir, 'static/plugins')
    186              if not os.path.isdir(plugins_static_dir):
    187                  # the static/plugins directory might not exist because we cannot create
    188                  # a directory in git
    189                  os.mkdir(plugins_static_dir)
    190
    191              # finally copy the files
    192              new_static_dir = os.path.join(plugins_static_dir, plugin.name)
    193              os.symlink(plugin_static_dir, new_static_dir)
    194
    195          # * install templates
    196          plugin_templates_dir = os.path.join(config.pluginsdir, plugin.name, 'templates')
    197          if os.path.isdir(plugin_templates_dir):
    198              plugins_templates_dir = os.path.join(config.curdir, 'templates/plugins')
    199              if not os.path.isdir(plugins_templates_dir):
    200                  os.mkdir(plugins_templates_dir)
    201              new_templates_dir = os.path.join(plugins_templates_dir, plugin.name)
    202              os.symlink(plugin_templates_dir, new_templates_dir)
    203
    204          plugin.install()
    205
    206 -    def __disable_plugin(self, plugin):
    207          '''
    208          Disable a plugin without verify the dependencies.
    209          '''
    210          orm = db.connect()
    211          orm.query(Plugin).filter_by(name=plugin.name).first().enabled = False
    212          plugin.disable()
    213          plugin.enabled = False
    214          orm.commit()
    215
    216 -    def __get_dependencies(self, plugin, checked_deps=None,
    217              checked_plugins=None):
    218          '''
    219          Recursively returns the list of the dependencies of the given plugins.
    220          If any of the dependencies is not met then it will raise a
    221          UnMetDependencyException.
    222
    223          The list of plugins dependencies will include the plugin itself which
    224          will be at the end of the list, and the list of dependencies will be
    225          ordered in such a way that they can be safely activated one by one,
    226          because any of the listed plugins will be preceded by its dependencies.
    227
    228          It will only be called by enable_plugin().
    229          '''
    230
    231          if checked_deps is None: checked_deps = []
    232          if checked_plugins is None: checked_plugins = []
    233
    234          # With this avoid infinite recursion with two plugins have mutual
    235          # dependency.
    236          checked_plugins.append(plugin.name)
    237          for dep in plugin.get_dependencies():
    238              if dep.dependon in (i.name for i in checked_deps):
    239                  continue
    240              if dep.dependon in checked_plugins:
    241                  continue
    242              if not dep.is_met():
    243                  # raise UnmetDependencyException(dep.dependon)
    244                  # FIXME
    245                  pass
    246              self.__get_dependencies(dep.get_plugin(), checked_deps,
    247                      checked_plugins)
    248
    249          checked_deps.append(plugin)
    250          return checked_deps
    251
    252 -    def __get_reverse_dependencies(self, plugin, checked_deps=None,
    253              checked_plugins=None):
    254          '''
    255          Recursively returns the list of the reverse dependencies of the given
    256          plugins.
    257
    258          The list of plugins dependencies will include the plugin itself which
    259          will be at the end of the list, and the list of dependencies will be
    260          ordered in such a way that they can be safely desactivated one by one,
    261          because any of the listed plugins will be preceded by its dependencies.
    262
    263          It will only be called by disable_plugin().
    264          '''
    265
    266          if checked_deps is None: checked_deps = []
    267          if checked_plugins is None: checked_plugins = []
    268          # With this avoid infinite recursion with two plugins have mutual
    269          # dependency.
    270          checked_plugins.append(plugin.name)
    271          # For each enabled plugin
    272          for p in self.get_enabled_plugins():
    273              # not checked before
    274              if p in checked_plugins:
    275                  continue
    276              if p.name in checked_plugins:
    277                  continue
    278              # looking for a dependency which is the given
    279              for dep in p.get_dependencies():
    280                  if dep.is_met_by(plugin):
    281                      self.__get_reverse_dependencies(self, p, checked_deps,
    282                              checked_plugins)
    283
    284          checked_deps.append(plugin)
    285          return checked_deps
    286
    287 -    def __instance_plugin(self, name):
    288          #FIXME throw exception
    289          pmodule = __import__('pluginmanager.plugins.' + name, fromlist=["true"])
    290          plugin = pmodule.Plugin()
    291          plugin.read_config(name)
    292          return plugin
    293
    294 -    def __get_plugins_directories(self):
    295          '''
    296          Return the list of the directories of plugins that there are
    297          in the plugins directory.
    298          '''
    299          return (i for i in os.listdir(config.pluginsdir)
    300                  if os.path.isdir(os.path.join(config.pluginsdir, i)))
    301