Mercurial > pydertron
changeset 11:665f69f61716
Some refactorings
author | Atul Varma <varmaa@toolness.com> |
---|---|
date | Thu, 10 Sep 2009 13:51:04 -0700 |
parents | 97f3b2242505 |
children | e4978bd08bfa |
files | pydertron.py |
diffstat | 1 files changed, 80 insertions(+), 81 deletions(-) [+] |
line wrap: on
line diff
--- a/pydertron.py Thu Sep 10 11:09:14 2009 -0700 +++ b/pydertron.py Thu Sep 10 13:51:04 2009 -0700 @@ -162,7 +162,7 @@ obj = cx.call_function(this, jsobject, tuple(arglist)) return self._wrap_to_python(obj) -def format_stack(js_stack): +def format_stack(js_stack, open=open): """ Returns a formatted Python-esque stack traceback of the given JS stack. @@ -235,7 +235,7 @@ loading and executing scripts. """ - def __init__(self, watchdog=watchdog): + def __init__(self, fs, watchdog=watchdog): rt = pydermonkey.Runtime() cx = rt.new_context() root_proto = cx.new_object() @@ -246,16 +246,23 @@ cx.set_throw_hook(self._throwhook) watchdog.add_context(cx) + self.fs = fs self.rt = rt self.cx = cx self.curr_exc = None self.py_stack = None self.js_stack = None + self.__modules = {} self.__py_to_js = {} self.__type_protos = {} - self.root_proto = root_proto + self.__globals = {} + self.__root_proto = root_proto self.root = self.wrap_jsobject(root, root) + def set_globals(self, **globals): + self.__globals.update(globals) + self._install_globals(self.root) + def finish(self): """ Cleans up all resources used by the sandbox, breaking any reference @@ -443,13 +450,45 @@ obj[name] = contents[name] return obj - def evaluate(self, code, filename='<string>', lineno=1): - retval = self.cx.evaluate_script(self.root.wrapped_jsobject, - code, filename, lineno) - return self.wrap_jsobject(retval) + def get_calling_script(self): + frame = self.cx.get_stack()['caller'] + curr_script = None + while frame and curr_script is None: + if frame['function'] and frame['function'].filename: + curr_script = frame['function'].filename + elif frame['script']: + curr_script = frame['script'].filename + frame = frame['caller'] + + if curr_script is None: + raise RuntimeError("Can't find calling script") + return curr_script + + def _install_globals(self, object): + for name in self.__globals: + object[name] = self.__globals[name] + object['require'] = self._require + + @jsexposed(name='require') + def _require(self, path): + filename = self.fs.find_module(self.get_calling_script(), path) + if not filename: + raise pydermonkey.error('Module not found: %s' % path) + + if not filename in self.__modules: + cx = self.cx + module = cx.new_object(None, self.__root_proto) + cx.init_standard_classes(module) + exports = cx.new_object() + cx.define_property(module, 'exports', exports) + self._install_globals(self.wrap_jsobject(module)) + self.__modules[filename] = self.wrap_jsobject(exports) + contents = self.fs.open(filename).read() + cx.evaluate_script(module, contents, filename, 1) + return self.__modules[filename] def run_script(self, contents, filename='<string>', lineno=1, - callback=None): + callback=None, stderr=sys.stderr): """ Runs the given JS script, returning 0 on success, -1 on failure. """ @@ -463,82 +502,42 @@ callback(self.wrap_jsobject(result)) retval = 0 except pydermonkey.error, e: - print format_stack(self.js_stack) - print e.args[1] + params = dict( + stack_trace = format_stack(self.js_stack, self.fs.open), + error = e.args[1] + ) + stderr.write("%(stack_trace)s\n%(error)s\n" % params) except InternalError, e: - print "An internal error occurred." - traceback.print_tb(e.exc_info[2]) - print e.exc_info[1] + stderr.write("An internal error occurred.\n") + traceback.print_tb(e.exc_info[2], None, stderr) + stderr.write("%s\n" % e.exc_info[1]) return retval -class SecurableModuleLoader(object): - """ - Loader for CommonJS SecurableModules. - """ - - def __init__(self, sandbox, root_dir, globals): +class SandboxedFileSystem(object): + def __init__(self, root_dir): self.root_dir = root_dir - self.sandbox = sandbox - self.globals = globals - self.modules = {} - self._install_globals(sandbox.root) - def _install_globals(self, object): - for name in self.globals: - object[name] = self.globals[name] - object['require'] = self.require - - def _get_calling_script(self): - frame = self.sandbox.cx.get_stack()['caller'] - curr_script = None - while frame and curr_script is None: - if frame['function'] and frame['function'].filename: - curr_script = frame['function'].filename - elif frame['script']: - curr_script = frame['script'].filename - frame = frame['caller'] - - if curr_script is None: - raise RuntimeError("Can't find calling script") - return curr_script + def find_module(self, curr_script, path): + if path.startswith("."): + base_dir = os.path.dirname(curr_script) + else: + base_dir = self.root_dir - def _load_module(self, filename): - sandbox = self.sandbox - cx = sandbox.cx - - module = cx.new_object(None, sandbox.root_proto) - cx.init_standard_classes(module) - exports = cx.new_object() - cx.define_property(module, 'exports', exports) - self._install_globals(sandbox.wrap_jsobject(module)) - self.modules[filename] = sandbox.wrap_jsobject(exports) - - contents = open(filename).read() - cx.evaluate_script(module, contents, filename, 1) + ospath = path.replace('/', os.path.sep) + filename = os.path.join(base_dir, "%s.js" % ospath) + filename = os.path.normpath(filename) + if (filename.startswith(self.root_dir) and + (os.path.exists(filename) and + not os.path.isdir(filename))): + return filename + else: + return None - @jsexposed - def require(self, path): - curr_script = self._get_calling_script() - curr_dir = os.path.split(curr_script)[0] - - if (not path.startswith(".") or - not curr_dir.startswith(self.root_dir)): - curr_dir = self.root_dir - ospath = path.replace('/', os.path.sep) - filename = os.path.join(curr_dir, "%s.js" % ospath) - filename = os.path.normpath(filename) - if (not filename.startswith(self.root_dir) or - not (os.path.exists(filename) and - not os.path.isdir(filename))): - raise pydermonkey.error('Module not found: %s' % path) - - if filename not in self.modules: - self._load_module(filename) - return self.modules[filename] + def open(self, filename): + return open(filename, 'r') def run_test(name, libpath): - print name - sandbox = JsSandbox() + sandbox = JsSandbox(SandboxedFileSystem(libpath)) stats = [0, 0] @@ -550,11 +549,11 @@ stats[1] += 1 print "%s %s" % (message, label) - system = sandbox.new_object() - system['print'] = jsprint - globals = {'sys': system, - 'environment': sandbox.new_object()} - loader = SecurableModuleLoader(sandbox, libpath, globals) + sandbox.set_globals( + sys = sandbox.new_object(**{'print': jsprint}), + environment = sandbox.new_object() + ) + retval = sandbox.run_script("require('program')") sandbox.finish() print @@ -591,6 +590,6 @@ import gc gc.collect() if pydermonkey.get_debug_info()['runtime_count']: - print "WARNING: JS runtime was not destroyed." + sys.stderr.write("WARNING: JS runtime was not destroyed.\n") sys.exit(totals[1])