diff options
Diffstat (limited to 'module/plugins')
| -rw-r--r-- | module/plugins/hooks/UpdateManager.py | 173 | 
1 files changed, 80 insertions, 93 deletions
| diff --git a/module/plugins/hooks/UpdateManager.py b/module/plugins/hooks/UpdateManager.py index 7d8f44fef..643b5c2d1 100644 --- a/module/plugins/hooks/UpdateManager.py +++ b/module/plugins/hooks/UpdateManager.py @@ -5,6 +5,7 @@ from __future__ import with_statement  import os  import re  import sys +import time  from operator import itemgetter @@ -28,67 +29,57 @@ def exists(path):  class UpdateManager(Hook):      __name__    = "UpdateManager"      __type__    = "hook" -    __version__ = "0.48" +    __version__ = "0.50" -    __config__ = [("activated"    , "bool"                         , "Activated"                                     , True              ), -                  ("mode"         , "pyLoad + plugins;plugins only", "Check updates for"                             , "pyLoad + plugins"), -                  ("interval"     , "int"                          , "Check interval in hours"                       , 8                 ), -                  ("autorestart"  , "bool"                         , "Automatically restart pyLoad when required"    , True              ), -                  ("reloadplugins", "bool"                         , "Monitor plugins for code changes in debug mode", True              ), -                  ("nodebugupdate", "bool"                         , "Don't check for updates in debug mode"         , False             )] +    __config__ = [("activated"    , "bool", "Activated"                                , True ), +                  ("checkinterval", "int" , "Check interval in hours"                  , 8    ), +                  ("autorestart"  , "bool", "Auto-restart pyLoad when required"        , True ), +                  ("checkonstart" , "bool", "Check for updates on startup"             , True ), +                  ("checkperiod"  , "bool", "Check for updates periodically"           , True ), +                  ("reloadplugins", "bool", "Monitor plugin code changes in debug mode", True ), +                  ("nodebugupdate", "bool", "Don't update plugins in debug mode"       , False)]      __description__ = """ Check for updates """      __license__     = "GPLv3"      __authors__     = [("Walter Purcaro", "vuolter@gmail.com")] -    # event_list = ["pluginConfigChanged"] +    interval = 0      SERVER_URL         = "http://updatemanager.pyload.org" -    VERSION            = re.compile(r'__version__.*=.*("|\')([\d.]+)')      MIN_CHECK_INTERVAL = 3 * 60 * 60  #: 3 hours -    def pluginConfigChanged(self, plugin, name, value): -        if name == "interval": -            interval = value * 60 * 60 -            if self.MIN_CHECK_INTERVAL <= interval != self.interval: -                # self.core.scheduler.removeJob(self.cb) -                self.interval = interval -                self.initPeriodical() -            else: -                self.logDebug("Invalid interval value, kept current") - -        elif name == "reloadplugins": -            if self.cb2: -                self.core.scheduler.removeJob(self.cb2) -            if value is True and self.core.debug: -                self.periodical2() - -      def coreReady(self): -        self.pluginConfigChanged(self.__name__, "interval", self.getConfig('interval')) -        x = lambda: self.pluginConfigChanged(self.__name__, "reloadplugins", self.getConfig('reloadplugins')) -        self.core.scheduler.addJob(10, x, threaded=False) +        if self.checkonstart: +            self.update() - -    def unload(self): -        self.pluginConfigChanged(self.__name__, "reloadplugins", False) +        self.initPeriodical()      def setup(self): -        self.cb2      = None -        self.interval = self.MIN_CHECK_INTERVAL -        self.updating = False -        self.info     = {'pyload': False, 'version': None, 'plugins': False} +        self.interval = 10 +        self.info     = {'pyload': False, 'version': None, 'plugins': False, 'last_check': time.time()}          self.mtimes   = {}  #: store modification time for each plugin +        if self.getConfig('checkonstart'): +            self.core.api.pauseServer() +            self.checkonstart = True +        else: +            self.checkonstart = False -    def periodical2(self): -        if not self.updating: -            self.autoreloadPlugins() -        self.cb2 = self.core.scheduler.addJob(4, self.periodical2, threaded=False) +    def periodical(self): +        if self.core.debug: +            if self.getConfig('reloadplugins'): +                self.autoreloadPlugins() + +            if self.getConfig('nodebugupdate'): +                return + +        if self.getConfig('checkperiod') \ +           and time.time() - max(self.MIN_CHECK_INTERVAL, self.getConfig('checkinterval') * 60 * 60) > self.info['last_check']: +            self.update()      @Expose @@ -121,11 +112,6 @@ class UpdateManager(Hook):          return True if self.core.pluginManager.reloadPlugins(reloads) else False -    def periodical(self): -        if not self.info['pyload'] and not (self.getConfig('nodebugupdate') and self.core.debug): -            self.updateThread() - -      def server_response(self):          try:              return getURL(self.SERVER_URL, get={'v': self.core.api.getServerVersion()}).splitlines() @@ -134,95 +120,92 @@ class UpdateManager(Hook):              self.logWarning(_("Unable to contact server to get updates")) +    @Expose      @threaded -    def updateThread(self): -        self.core.api.pauseServer() -        self.updating = True +    def update(self): +        """ check for updates """ -        status = self.update(onlyplugin=self.getConfig('mode') == "plugins only") +        self.core.api.pauseServer() -        if status is 2 and self.getConfig('autorestart'): +        if self._update() is 2 and self.getConfig('autorestart'):              self.core.api.restart()          else: -            self.updating = False              self.core.api.unpauseServer() -    @Expose -    def updatePlugins(self): -        """ simple wrapper for calling plugin update quickly """ -        return self.update(onlyplugin=True) - - -    @Expose -    def update(self, onlyplugin=False): -        """ check for updates """ +    def _update(self):          data = self.server_response() +        self.info['last_check'] = time.time() +          if not data:              exitcode = 0          elif data[0] == "None":              self.logInfo(_("No new pyLoad version available")) -            updates = data[1:] -            exitcode = self._updatePlugins(updates) +            exitcode = self._updatePlugins(data[1:])          elif onlyplugin:              exitcode = 0          else: -            newversion = data[0] -            self.logInfo(_("***  New pyLoad Version %s available  ***") % newversion) +            self.logInfo(_("***  New pyLoad Version %s available  ***") % data[0])              self.logInfo(_("***  Get it here: https://github.com/pyload/pyload/releases  ***")) +            self.info['pyload']  = True +            self.info['version'] = data[0]              exitcode = 3 -            self.info['pyload'] = True -            self.info['version'] = newversion -        return exitcode  #: 0 = No plugins updated; 1 = Plugins updated; 2 = Plugins updated, but restart required; 3 = No plugins updated, new pyLoad version available +        # Exit codes: +        # -1 = No plugin updated, new pyLoad version available +        #  0 = No plugin updated +        #  1 = Plugins updated +        #  2 = Plugins updated, but restart required +        return exitcode -    def _updatePlugins(self, updates): +    def _updatePlugins(self, data):          """ check for plugin updates """ -        if self.info['plugins']: -            return False  #: plugins were already updated -          exitcode = 0          updated  = [] -        url    = updates[0] -        schema = updates[1].split('|') +        url    = data[0] +        schema = data[1].split('|') -        if "BLACKLIST" in updates: -            blacklist = updates[updates.index('BLACKLIST') + 1:] -            updates   = updates[2:updates.index('BLACKLIST')] +        VERSION = re.compile(r'__version__.*=.*("|\')([\d.]+)') + +        if "BLACKLIST" in data: +            blacklist  = data[data.index('BLACKLIST') + 1:] +            updatelist = data[2:data.index('BLACKLIST')]          else: -            blacklist = None -            updates   = updates[2:] +            blacklist  = [] +            updatelist = data[2:] -        upgradable  = [dict(zip(schema, x.split('|'))) for x in updates] -        blacklisted = [(x.split('|')[0], x.split('|')[1].rsplit('.', 1)[0]) for x in blacklist] if blacklist else [] +        updatelist = [dict(zip(schema, x.split('|'))) for x in updatelist] +        blacklist  = [dict(zip(schema, x.split('|'))) for x in blacklist]          if blacklist: +            type_plugins = [(plugin['type'], plugin['name'].rsplit('.', 1)[0]) for plugin in blacklist] +              # Protect UpdateManager from self-removing              try: -                blacklisted.remove(("hook", "UpdateManager")) +                type_plugins.remove(("hook", "UpdateManager"))              except ValueError:                  pass -            for t, n in blacklisted: -                for idx, plugin in enumerate(upgradable): +            for t, n in type_plugins: +                for idx, plugin in enumerate(updatelist):                      if n == plugin['name'] and t == plugin['type']: -                        upgradable.pop(idx) +                        updatelist.pop(idx)                          break -            for t, n in self.removePlugins(sorted(blacklisted)): +            for t, n in self.removePlugins(sorted(type_plugins)):                  self.logInfo(_("Removed blacklisted plugin: [%(type)s] %(name)s") % {                      'type': t,                      'name': n,                  }) -        for plugin in sorted(upgradable, key=itemgetter("type", "name")): +        for plugin in sorted(updatelist, key=itemgetter("type", "name")):              filename = plugin['name']              prefix   = plugin['type']              version  = plugin['version'] @@ -256,7 +239,7 @@ class UpdateManager(Hook):                                     'newver': newver})              try:                  content = getURL(url % plugin) -                m = self.VERSION.search(content) +                m = VERSION.search(content)                  if m and m.group(2) == version:                      with open(save_join("userplugins", prefix, filename), "wb") as f: @@ -267,15 +250,15 @@ class UpdateManager(Hook):                      raise Exception, _("Version mismatch")              except Exception, e: -                self.logError(_("Error updating plugin: %s") % filename, str(e)) +                self.logError(_("Error updating plugin: %s") % filename, e)          if updated: -            reloaded = self.core.pluginManager.reloadPlugins(updated) -            if reloaded: -                self.logInfo(_("Plugins updated and reloaded")) +            self.logInfo(_("*** Plugins updated ***")) + +            if self.core.pluginManager.reloadPlugins(updated):                  exitcode = 1              else: -                self.logInfo(_("*** Plugins have been updated, but need a pyLoad restart to be reloaded ***")) +                self.logWarning(_("pyLoad restart required to reload the updated plugins"))                  self.info['plugins'] = True                  exitcode = 2 @@ -283,7 +266,11 @@ class UpdateManager(Hook):          else:              self.logInfo(_("No plugin updates available")) -        return exitcode  #: 0 = No plugins updated; 1 = Plugins updated; 2 = Plugins updated, but restart required +        # Exit codes: +        # 0 = No plugin updated +        # 1 = Plugins updated +        # 2 = Plugins updated, but restart required +        return exitcode      @Expose | 
