diff options
author | Walter Purcaro <vuolter@gmail.com> | 2014-09-08 01:34:05 +0200 |
---|---|---|
committer | Walter Purcaro <vuolter@gmail.com> | 2014-09-14 11:03:47 +0200 |
commit | 3d4f8e55ce4c87f3f3bb3ea49acb76ca607bfc8d (patch) | |
tree | 140b2f75e4e445c4aa899488439fa91e775a85d2 /pyload/utils | |
parent | New printer (windows compatible) (diff) | |
download | pyload-3d4f8e55ce4c87f3f3bb3ea49acb76ca607bfc8d.tar.xz |
JsEngine rewritten + utils updated
Diffstat (limited to 'pyload/utils')
-rw-r--r-- | pyload/utils/JsEngine.py | 341 | ||||
-rw-r--r-- | pyload/utils/__init__.py | 31 |
2 files changed, 236 insertions, 136 deletions
diff --git a/pyload/utils/JsEngine.py b/pyload/utils/JsEngine.py index 46789f64d..ef5bc9be9 100644 --- a/pyload/utils/JsEngine.py +++ b/pyload/utils/JsEngine.py @@ -1,155 +1,238 @@ # -*- coding: utf-8 -*- -""" - This program is free software; you can redistribute it and/or modify - it under the terms of the GNU General Public License as published by - the Free Software Foundation; either version 3 of the License, - or (at your option) any later version. - This program is distributed in the hope that it will be useful, - but WITHOUT ANY WARRANTY; without even the implied warranty of - MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. - See the GNU General Public License for more details. +import subprocess +import sys - You should have received a copy of the GNU General Public License - along with this program; if not, see <http://www.gnu.org/licenses/>. +from os import path +from urllib import quote - @author: RaNaN -""" +from pyload.utils import encode, uniqify -from imp import find_module -from os.path import join, exists -from urllib import quote +class JsEngine: + """ JS Engine superclass """ + + def __init__(self, core, engine=None): #: engine can be a jse name """string""" or an AbstractEngine """class""" + + self.core = core + self.engine = None #: Default engine Instance + + if not ENGINES: + self.core.log.critical("No JS Engine found!") + return + + if not engine: + engine = self.core.config.get("general", "jsengine") + + if engine != "auto" and self.set(engine) is False: + engine = "auto" + self.core.log.warning("JS Engine set to \"auto\" for safely") + + if engine == "auto": + for E in self.find(): + if self.set(E) is True: + break + else: + self.core.log.error("No JS Engine available") + + + @classmethod + def find(cls): + """ Check if there is any engine available """ + return [E for E in ENGINES if E.find()] + + + def get(self, engine): + """ Convert engine name (string) to relative JSE class (AbstractEngine extended) """ + if isinstance(engine, basestring): + engine_name = engine.lower() + for E in ENGINES: + if E.NAME == engine_name: #: doesn't check if E(NGINE) is available, just convert string to class + JSE = E + break + else: + JSE = None + elif issubclass(engine, AbstractEngine): + JSE = engine + else: + JSE = None + return JSE -ENGINE = "" -DEBUG = False -JS = False -PYV8 = False -RHINO = False + def set(self, engine): + """ Set engine name (string) or JSE class (AbstractEngine extended) as default engine """ + if isinstance(engine, basestring): + self.set(self.get(engine)) + elif issubclass(engine, AbstractEngine) and engine.find(): + self.engine = engine + return True + else: + return False -if not ENGINE: - try: - import subprocess + def eval(self, script, engine=None): #: engine can be a jse name """string""" or an AbstractEngine """class""" + if not engine: + JSE = self.engine + else: + JSE = self.get(engine) - subprocess.Popen(["js", "-v"], bufsize=-1, stdout=subprocess.PIPE, stderr=subprocess.PIPE).communicate() - p = subprocess.Popen(["js", "-e", "print(23+19)"], stdout=subprocess.PIPE, stderr=subprocess.PIPE) - out, err = p.communicate() - #integrity check - if out.strip() == "42": - ENGINE = "js" - JS = True - except: - pass + if not JSE: + return None -if not ENGINE or DEBUG: - try: - find_module("PyV8") - ENGINE = "pyv8" - PYV8 = True - except: - pass + script = encode(script) -if not ENGINE or DEBUG: - try: - path = "" #path where to find rhino - - if exists("/usr/share/java/js.jar"): - path = "/usr/share/java/js.jar" - elif exists("js.jar"): - path = "js.jar" - elif exists(join(pypath, "js.jar")): #may raises an exception, but js.jar wasnt found anyway - path = join(pypath, "js.jar") - - if not path: - raise Exception - - import subprocess - - p = subprocess.Popen(["java", "-cp", path, "org.mozilla.javascript.tools.shell.Main", "-e", "print(23+19)"], - stdout=subprocess.PIPE, stderr=subprocess.PIPE) - out, err = p.communicate() - #integrity check - if out.strip() == "42": - ENGINE = "rhino" - RHINO = True - except: - pass + out, err = JSE.eval(script) + + results = [out] + + if self.core.config.get("general", "debug"): + if err: + self.core.log.debug(JSE.NAME + ":", err) + + engines = self.find() + engines.remove(JSE) + for E in engines: + out, err = E.eval(script) + res = err or out + self.core.log.debug(E.NAME + ":", res) + results.append(res) + + if len(results) > 1 and len(uniqify(results)) > 1: + self.core.log.warning("JS output of two or more engines mismatch") + + return results[0] + + +class AbstractEngine: + """ JSE base class """ + + NAME = "" -class JsEngine: def __init__(self): - self.engine = ENGINE - self.init = False + self.setup() + self.available = self.find() - def __nonzero__(self): - return False if not ENGINE else True + def setup(self): + pass - def eval(self, script): - if not self.init: - if ENGINE == "pyv8" or (DEBUG and PYV8): - import PyV8 - global PyV8 - - self.init = True - - if type(script) == unicode: - script = script.encode("utf8") - - if not ENGINE: - raise Exception("No JS Engine") - - if not DEBUG: - if ENGINE == "pyv8": - return self.eval_pyv8(script) - elif ENGINE == "js": - return self.eval_js(script) - elif ENGINE == "rhino": - return self.eval_rhino(script) + @classmethod + def find(cls): + """ Check if the engine is available """ + try: + __import__(cls.NAME) + except ImportError: + try: + out, err = cls().eval("print(23+19)") + except: + res = False + else: + res = out == "42" else: - results = [] - if PYV8: - res = self.eval_pyv8(script) - print "PyV8:", res - results.append(res) - if JS: - res = self.eval_js(script) - print "JS:", res - results.append(res) - if RHINO: - res = self.eval_rhino(script) - print "Rhino:", res - results.append(res) + res = True + finally: + return res + + def _eval(args): + if not self.available: + return None, "JS Engine \"%s\" not found" % self.NAME + + try: + p = subprocess.Popen(args, + stdout=subprocess.PIPE, + stderr=subprocess.PIPE, + bufsize=-1) + return map(lambda x: x.strip(), p.communicate()) + except Exception, e: + return None, e - warning = False - for x in results: - for y in results: - if x != y: - warning = True - if warning: print "### WARNING ###: Different results" + def eval(script): + raise NotImplementedError - return results[0] - def eval_pyv8(self, script): - rt = PyV8.JSContext() - rt.enter() - return rt.eval(script) +class Pyv8Engine(AbstractEngine): + + NAME = "pyv8" + + def eval(self, script): + if not self.available: + return None, "JS Engine \"%s\" not found" % self.NAME - def eval_js(self, script): + try: + rt = PyV8.JSContext() + rt.enter() + res = rt.eval(script), None #@TODO: parse stderr + except Exception, e: + res = None, e + finally: + return res + + +class CommonEngine(AbstractEngine): + + NAME = "js" + + def setup(self): + subprocess.Popen(["js", "-v"], bufsize=-1).communicate() + + def eval(self, script): + script = "print(eval(unescape('%s')))" % quote(script) + args = ["js", "-e", script] + return self._eval(args) + + +class NodeEngine(AbstractEngine): + + NAME = "nodejs" + + def setup(self): + subprocess.Popen(["node", "-v"], bufsize=-1).communicate() + + def eval(self, script): + script = "console.log(eval(unescape('%s')))" % quote(script) + args = ["node", "-e", script] + return self._eval(args) + + +class RhinoEngine(AbstractEngine): + + NAME = "rhino" + + def setup(self): + jspath = [ + "/usr/share/java*/js.jar", + "js.jar", + path.join(pypath, "js.jar") + ] + for p in jspath: + if path.exists(p): + self.path = p + break + else: + self.path = "" + + def eval(self, script): script = "print(eval(unescape('%s')))" % quote(script) - p = subprocess.Popen(["js", "-e", script], stdout=subprocess.PIPE, stderr=subprocess.STDOUT, bufsize=-1) - out, err = p.communicate() - res = out.strip() - return res + args = ["java", "-cp", self.path, "org.mozilla.javascript.tools.shell.Main", "-e", script] + return self._eval(args).decode("utf8").encode("ISO-8859-1") + - def eval_rhino(self, script): +class JscEngine(AbstractEngine): + + NAME = "javascriptcore" + + def setup(self): + jspath = "/System/Library/Frameworks/JavaScriptCore.framework/Resources/jsc" + self.path = jspath if path.exists(jspath) else "" + + def eval(self, script): script = "print(eval(unescape('%s')))" % quote(script) - p = subprocess.Popen(["java", "-cp", path, "org.mozilla.javascript.tools.shell.Main", "-e", script], - stdout=subprocess.PIPE, stderr=subprocess.STDOUT, bufsize=-1) - out, err = p.communicate() - res = out.strip() - return res.decode("utf8").encode("ISO-8859-1") - - def error(self): - return _("No js engine detected, please install either Spidermonkey, ossp-js, pyv8 or rhino") + args = [self.path, "-e", script] + return self._eval(args) + + +#@NOTE: Priority ordered +ENGINES = [CommonEngine, Pyv8Engine, NodeEngine, RhinoEngine] + +if sys.platform == "darwin": + ENGINES.insert(JscEngine) diff --git a/pyload/utils/__init__.py b/pyload/utils/__init__.py index b9eb8c88e..a13aa75d5 100644 --- a/pyload/utils/__init__.py +++ b/pyload/utils/__init__.py @@ -10,6 +10,15 @@ from os.path import join from string import maketrans from htmlentitydefs import name2codepoint +# abstraction layer for json operations +try: + import simplejson as json +except ImportError: + import json + +json_loads = json.loads +json_dumps = json.dumps + def chmod(*args): try: @@ -19,10 +28,18 @@ def chmod(*args): def decode(string): - """ decode string with utf if possible """ - try: + """ Decode string to unicode with utf8 """ + if type(string) == str: return string.decode("utf8", "replace") - except: + else: + return string + + +def encode(string): + """ Decode string to utf8 """ + if type(string) == unicode: + return string.encode("utf8", "replace") + else: return string @@ -145,10 +162,10 @@ def fs_bsize(path): def uniqify(seq): #: Originally by Dave Kirby - """ removes duplicates from list, preserve order """ - seen = set() - seen_add = seen.add - return [x for x in seq if x not in seen and not seen_add(x)] + """ Remove duplicates from list preserving order """ + seen = set() + seen_add = seen.add + return [x for x in seq if x not in seen and not seen_add(x)] def parseFileSize(string, unit=None): #returns bytes |