summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorGravatar Walter Purcaro <vuolter@gmail.com> 2014-06-26 21:35:11 +0200
committerGravatar Stefano <l.stickell@yahoo.it> 2014-06-26 21:35:11 +0200
commit041f72aa8c3d3b91cb1159d54499c945a999fcba (patch)
tree3d3b3828b5b644bf36c36160e161e88f47587f46
parent[Fshare] Fixed #651 (diff)
downloadpyload-041f72aa8c3d3b91cb1159d54499c945a999fcba.tar.xz
[UpdateManager] rewritten
-rw-r--r--module/plugins/hooks/UpdateManager.py269
1 files changed, 151 insertions, 118 deletions
diff --git a/module/plugins/hooks/UpdateManager.py b/module/plugins/hooks/UpdateManager.py
index 5f88ea6d0..7ed4dc19f 100644
--- a/module/plugins/hooks/UpdateManager.py
+++ b/module/plugins/hooks/UpdateManager.py
@@ -2,6 +2,7 @@
import sys
import re
+
from os import remove, stat
from os.path import join, isfile
from time import time
@@ -13,86 +14,120 @@ from module.plugins.Hook import threaded, Expose, Hook
class UpdateManager(Hook):
__name__ = "UpdateManager"
- __version__ = "0.16"
- __description__ = """Checks for updates"""
+ __version__ = "0.22"
+ __description__ = """Check for updates"""
__config__ = [("activated", "bool", "Activated", True),
- ("interval", "int", "Check interval in minutes", 480),
- ("debug", "bool", "Check for plugin changes when in debug mode", False)]
- __author_name__ = ("RaNaN", "stickell")
- __author_mail__ = ("ranan@pyload.org", "l.stickell@yahoo.it")
+ ("mode", "pyLoad + plugins;plugins only", "Check updates for", "pyLoad + plugins"),
+ ("interval", "int", "Check interval in hours", 8),
+ ("reloadplugins", "bool", "Monitor plugins for code changes (debug mode only)", True),
+ ("nodebugupdate", "bool", "Don't check for updates in debug mode", True)]
+ __author_name__ = ("RaNaN", "stickell", "Walter Purcaro")
+ __author_mail__ = ("ranan@pyload.org", "l.stickell@yahoo.it", "vuolter@gmail.com")
- URL = "http://updatemanager.pyload.org"
- MIN_TIME = 3 * 60 * 60 # 3h minimum check interval
+ SERVER_URL = "http://updatemanager.pyload.org"
+ MIN_TIME = 3 * 60 * 60 #: 3h minimum check interval
- @property
- def debug(self):
- return self.core.debug and self.getConfig("debug")
+ event_list = ["pluginConfigChanged"]
- def setup(self):
- if self.debug:
- self.logDebug("Monitoring file changes")
- self.interval = 4
- self.last_check = 0 # timestamp of updatecheck
- self.old_periodical = self.periodical
- self.periodical = self.checkChanges
- self.mtimes = {} # recordes times
- else:
- self.interval = max(self.getConfig("interval") * 60, self.MIN_TIME)
- self.updated = False
- self.reloaded = True
- self.version = "None"
+ def pluginConfigChanged(self, plugin, name, value):
+ if name == "interval" and 0 < value != self.interval:
+ self.interval = max(value * 60 * 60, self.MIN_TIME)
+ self.initPeriodical()
+ elif name == "reloadplugins":
+ if self.cb2:
+ self.core.scheduler.removeJob(self.cb2)
+ if value and self.core.debug:
+ self.periodical2()
+ def coreReady(self):
+ self.pluginConfigChanged(self.__name__, "reloadplugins", self.getConfig("reloadplugins"))
+
+ def setup(self):
+ self.cb2 = None
+ self.interval = self.MIN_TIME
+ self.updating = False
self.info = {"pyload": False, "plugins": False}
+ self.mtimes = {} #: store modification time for each plugin
- @threaded
- def periodical(self):
- updates = self.checkForUpdate()
- if updates:
- self.checkPlugins(updates)
-
- if self.updated and not self.reloaded:
- self.info["plugins"] = True
- self.logInfo(_("*** Plugins have been updated, please restart pyLoad ***"))
- elif self.updated and self.reloaded:
- self.logInfo(_("Plugins updated and reloaded"))
- self.updated = False
- elif self.version == "None":
- self.logInfo(_("No plugin updates available"))
+
+ def periodical2(self):
+ if not self.updating:
+ self.autoreloadPlugins()
+ self.cb2 = self.core.scheduler.addJob(10, self.periodical2, threaded=True)
@Expose
- def recheckForUpdates(self):
- """recheck if updates are available"""
- self.periodical()
+ def autoreloadPlugins(self):
+ """ reload and reindex all modified plugins """
+ modules = filter(
+ lambda m: m and (m.__name__.startswith("module.plugins.") or m.__name__.startswith(
+ "userplugins.")) and m.__name__.count(".") >= 2, sys.modules.itervalues())
+
+ reloads = []
+
+ for m in modules:
+ root, type, name = m.__name__.rsplit(".", 2)
+ id = (type, name)
+ if type in self.core.pluginManager.plugins:
+ f = m.__file__.replace(".pyc", ".py")
+ if not isfile(f):
+ continue
+
+ mtime = stat(f).st_mtime
- def checkForUpdate(self):
- """checks if an update is available, return result"""
+ if id not in self.mtimes:
+ self.mtimes[id] = mtime
+ elif self.mtimes[id] < mtime:
+ reloads.append(id)
+ self.mtimes[id] = mtime
+
+ return True if self.core.pluginManager.reloadPlugins(reloads) else False
+
+ @threaded
+ def periodical(self):
+ if not self.info["pyload"] and not (self.getConfig("nodebugupdate") and self.core.debug):
+ self.updating = True
+ self.update(onlyplugin=True if self.getConfig("mode") == "plugins only" else False)
+ self.updating = False
+
+ def server_response(self):
try:
- if self.version == "None": # No updated known
- version_check = getURL(self.URL, get={'v': self.core.api.getServerVersion()}).splitlines()
- self.version = version_check[0]
-
- # Still no updates, plugins will be checked
- if self.version == "None":
- self.logInfo(_("No Updates for pyLoad"))
- return version_check[1:]
-
- self.info["pyload"] = True
- self.logInfo(_("*** New pyLoad Version %s available ***") % self.version)
- self.logInfo(_("*** Get it here: http://pyload.org/download ***"))
+ return getURL(self.SERVER_URL, get={'v': self.core.api.getServerVersion()}).splitlines()
except:
- self.logWarning(_("Not able to connect server for updates"))
+ self.logWarning(_("Not able to connect server to get updates"))
- return None # Nothing will be done
+ @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 """
+ data = self.server_response()
+ if not data:
+ r = False
+ elif data[0] == "None":
+ self.logInfo(_("No pyLoad version available"))
+ updates = data[1:]
+ r = self._updatePlugins(updates)
+ elif onlyplugin:
+ r = False
+ else:
+ newversion = data[0]
+ # self.info["pyload"] = newversion
+ self.logInfo(_("*** New pyLoad Version %s available ***") % newversion)
+ self.logInfo(_("*** Get it here: https://github.com/pyload/pyload/releases ***"))
+ r = self.info["pyload"] = True
+ return r
- def checkPlugins(self, updates):
- """ checks for plugins updates"""
+ def _updatePlugins(self, updates):
+ """ check for plugin updates """
- # plugins were already updated
if self.info["plugins"]:
- return
+ return False #: plugins were already updated
- reloads = []
+ updated = []
vre = re.compile(r'__version__.*=.*("|\')([0-9.]+)')
url = updates[0]
@@ -123,79 +158,77 @@ class UpdateManager(Hook):
plugins = getattr(self.core.pluginManager, "%sPlugins" % type)
- if name in plugins:
- if float(plugins[name]["v"]) >= float(version):
- continue
-
- if name in IGNORE or (type, name) in IGNORE:
+ if name not in plugins or name in IGNORE or (type, name) in IGNORE:
continue
- self.logInfo(_("New version of %(type)s|%(name)s : %(version).2f") % {
- "type": type,
- "name": name,
- "version": float(version)
- })
+ oldver = float(plugins[name]["v"])
+ newver = float(version)
+
+ if oldver >= newver:
+ continue
+ else:
+ self.logInfo(_("New version of [%(type)s] %(name)s (v%(oldver)s -> v%(newver)s)") % {
+ "type": type,
+ "name": name,
+ "oldver": oldver,
+ "newver": newver
+ })
try:
content = getURL(url % info)
except Exception, e:
- self.logWarning(_("Error when updating %s") % filename, str(e))
+ self.logError(_("Error when updating plugin %s") % filename, str(e))
continue
m = vre.search(content)
if not m or m.group(2) != version:
- self.logWarning(_("Error when updating %s") % name, _("Version mismatch"))
+ self.logError(_("Error when updating plugin %s") % name, _("Version mismatch"))
continue
f = open(join("userplugins", prefix, filename), "wb")
f.write(content)
f.close()
- self.updated = True
-
- reloads.append((prefix, name))
+ updated.append((prefix, name))
if blacklist:
- self.executeBlacklist(blacklist)
-
- self.reloaded = self.core.pluginManager.reloadPlugins(reloads)
-
- def executeBlacklist(self, blacklist):
- for b in blacklist:
- type, name = b.split('|')
- if isfile(join("userplugins", type, name)):
- self.logInfo(_("Removing blacklisted plugin %(type)s|%(name)s") % {
- "type": type,
- "name": name
+ removed = self.removePlugins(map(lambda x: x.split('|'), blacklist))
+ for t, n in removed:
+ self.logInfo(_("Removed blacklisted plugin: [%(type)s] %(name)s") % {
+ "type": t,
+ "name": n
})
- remove(join("userplugins", type, name))
- if isfile(join("userplugins", type, name.replace('.py', '.pyc'))):
- remove(join("userplugins", type, name.replace('.py', '.pyc')))
-
- def checkChanges(self):
- if self.last_check + max(self.getConfig("interval") * 60, self.MIN_TIME) < time():
- self.old_periodical()
- self.last_check = time()
-
- modules = filter(
- lambda m: m and (m.__name__.startswith("module.plugins.") or m.__name__.startswith(
- "userplugins.")) and m.__name__.count(".") >= 2, sys.modules.itervalues())
-
- reloads = []
- for m in modules:
- root, type, name = m.__name__.rsplit(".", 2)
- id = (type, name)
- if type in self.core.pluginManager.plugins:
- f = m.__file__.replace(".pyc", ".py")
- if not isfile(f):
- continue
-
- mtime = stat(f).st_mtime
-
- if id not in self.mtimes:
- self.mtimes[id] = mtime
- elif self.mtimes[id] < mtime:
- reloads.append(id)
- self.mtimes[id] = mtime
+ if updated:
+ reloaded = self.core.pluginManager.reloadPlugins(updated)
+ if reloaded:
+ self.logInfo(_("Plugins updated and reloaded"))
+ else:
+ self.logInfo(_("*** Plugins have been updated, pyLoad will be restarted now ***"))
+ self.info["plugins"] = True
+ self.core.scheduler.addJob(4, self.core.api.restart(), threaded=False) #: risky, but pyload doesn't let more
+ return True
+ else:
+ self.logInfo(_("No plugin updates available"))
+ return False
- self.core.pluginManager.reloadPlugins(reloads)
+ @Expose
+ def removePlugins(self, type_plugins):
+ """ delete plugins under userplugins directory"""
+ if not type_plugins:
+ return None
+
+ self.logDebug("Request deletion of plugins: %s" % type_plugins)
+
+ removed = []
+
+ for type, name in type_plugins:
+ py = join("userplugins", type, name)
+ pyc = py[::-1].replace('.py', '.pyc')[::-1]
+ if isfile(py):
+ id = (type, name)
+ remove(py)
+ removed.append(id)
+ if isfile(pyc):
+ remove(pyc)
+
+ return removed #: return a list of the plugins successfully removed