diff --git a/build.xml b/build.xml index 37cc361..2588b07 100644 --- a/build.xml +++ b/build.xml @@ -274,6 +274,7 @@ + @@ -350,6 +351,7 @@ + diff --git a/patches/lib/module.js.patch b/patches/lib/module.js.patch index ade0e01..5e334c3 100644 --- a/patches/lib/module.js.patch +++ b/patches/lib/module.js.patch @@ -1,5 +1,5 @@ ---- ../node/lib/module.js 2013-08-22 13:55:28.000000000 +0200 -+++ src/main/js/lib/module.js 2013-10-07 14:01:12.000000000 +0200 +--- ../nodejs/lib/module.js 2013-12-02 16:45:51.723090200 -0800 ++++ src/main/js/lib/module.js 2013-12-05 16:49:59.264917800 -0800 @@ -271,13 +271,19 @@ return [id, [path.dirname(parent.filename)]]; }; @@ -21,6 +21,15 @@ var cachedModule = Module._cache[filename]; if (cachedModule) { +@@ -288,7 +294,7 @@ + // REPL is a special case, because it needs the real require. + if (filename == 'repl') { + var replModule = new Module('repl'); +- replModule._compile(NativeModule.getSource('repl'), 'repl.js'); ++ replModule._compile(NativeModule.getSource('/lib/repl.js'), 'repl.js'); + NativeModule._cache.repl = replModule; + return replModule.exports; + } @@ -309,7 +315,11 @@ var hadException = true; @@ -49,7 +58,7 @@ // Returns exception if any Module.prototype._compile = function(content, filename) { var self = this; -+ ++ // remove shebang + if(content != null) { content = content.replace(/^\#\!.*/, ''); diff --git a/patches/lib/repl.js.patch b/patches/lib/repl.js.patch new file mode 100644 index 0000000..6ad216e --- /dev/null +++ b/patches/lib/repl.js.patch @@ -0,0 +1,24 @@ +--- ../nodejs/lib/repl.js 2013-12-05 16:43:37.738090700 -0800 ++++ src/main/js/lib/repl.js 2013-12-05 16:44:53.691533100 -0800 +@@ -535,7 +535,7 @@ + // Get global vars synchronously + if (this.useGlobal || + this.context.constructor && +- this.context.constructor.name === 'Context') { ++ this.context.constructor.name === 'Object') { + var contextProto = this.context; + while (contextProto = Object.getPrototypeOf(contextProto)) { + completionGroups.push(Object.getOwnPropertyNames(contextProto)); +@@ -918,10 +918,10 @@ + e = e && (e.stack || e.toString()); + return e && e.match(/^SyntaxError/) && + // RegExp syntax error +- !e.match(/^SyntaxError: Invalid regular expression/) && ++ !e.match(/^SyntaxError: repl/) && + !e.match(/^SyntaxError: Invalid flags supplied to RegExp constructor/) && + // "strict mode" syntax errors + !e.match(/^SyntaxError: .*strict mode.*/i) && + // JSON.parse() error +- !e.match(/\n {4}at Object.parse \(native\)\n/); ++ !e.match(/^SyntaxError: Invalid /); + } diff --git a/project.properties b/project.properties index de05644..a021e9c 100644 --- a/project.properties +++ b/project.properties @@ -28,6 +28,7 @@ source.lib.modules = \ path.js \ querystring.js \ readline.js \ + repl.js \ stream.js \ string_decoder.js \ timers.js \ @@ -436,6 +437,12 @@ source.test.simple.list = \ test-regress-GH-877.js \ test-regress-GH-897.js \ test-regression-object-prototype.js \ + test-repl-autolibs.js \ + test-repl-console.js \ + test-repl-end-emits-exit.js \ + test-repl-options.js \ + test-repl-require-cache.js \ + test-repl-tab-complete.js \ test-require-cache.js \ test-require-cache-without-stat.js \ test-require-exceptions.js \ diff --git a/src/main/java/net/java/avatar/js/Loader.java b/src/main/java/net/java/avatar/js/Loader.java index c4770d5..069dc7b 100644 --- a/src/main/java/net/java/avatar/js/Loader.java +++ b/src/main/java/net/java/avatar/js/Loader.java @@ -25,6 +25,7 @@ package net.java.avatar.js; +import java.io.ByteArrayOutputStream; import java.io.File; import java.io.IOException; import java.io.InputStream; @@ -125,6 +126,8 @@ public abstract class Loader { */ public abstract boolean exists(final String id); + public abstract String load(final String id); + /** * Returns the value of a compiled-in property. * @param key the key whose value is desired @@ -192,6 +195,27 @@ public abstract class Loader { return BUILD_PROPERTIES.getProperty(key); } + @Override + public String load(final String id) { + final int BUFFERSIZE = 64 * 1024; + final byte[] data = new byte[BUFFERSIZE]; + final ByteArrayOutputStream buffer = new ByteArrayOutputStream(BUFFERSIZE); + final InputStream is = this.getClass().getResourceAsStream(id); + assert is != null; + + try { + int bytesRead = is.read(data, 0, data.length); + while (bytesRead != -1) { + buffer.write(data, 0, bytesRead); + bytesRead = is.read(data, 0, data.length); + } + buffer.flush(); + } catch (final IOException ex) { + ex.printStackTrace(); + } + return new String(buffer.toByteArray()); + } + protected String pathFor(final String id) { return MODULES_DIR + id + SCRIPT_EXTENSION; } diff --git a/src/main/java/net/java/avatar/js/Server.java b/src/main/java/net/java/avatar/js/Server.java index 1012e7f..d8df761 100644 --- a/src/main/java/net/java/avatar/js/Server.java +++ b/src/main/java/net/java/avatar/js/Server.java @@ -100,9 +100,7 @@ public final class Server { } public static void main(final String... args) throws Exception { - if (args != null && args.length > 0) { - new Server().run(args); - } + new Server().run(args); } public Server() throws Exception { @@ -147,7 +145,11 @@ public final class Server { checkPermission(); bindings.put(SECURE_HOLDER, holder); try { - runUserScripts(args); + if (args.length == 0) { + runREPL(); + } else { + runUserScripts(args); + } } catch (final ScriptException ex) { if (!eventLoop.handleCallbackException(ex)) { throw ex; @@ -206,11 +208,21 @@ public final class Server { } final String[] userFiles = {userFile}; - holder.setArgs(avatarArgs.toArray(new String[avatarArgs.size()]), - userArgs.toArray(new String[userArgs.size()]), - userFiles); + + runEventLoop(avatarArgs.toArray(new String[avatarArgs.size()]), + userArgs.toArray(new String[userArgs.size()]), + userFiles); + } + + private void runREPL() throws Exception { + holder.setForceRepl(true); + runEventLoop(null, null, null); + } + + private void runEventLoop(final String[] avatarArgs, final String[] userArgs, final String[] userFiles) throws Exception { Exception rootCause = null; - // First run the main script... + holder.setArgs(avatarArgs, userArgs, userFiles); + try { runSystemScript(SYSTEM_INIT_SCRIPTS); } catch(Exception ex) { @@ -234,17 +246,15 @@ public final class Server { throw ex; } } finally { - if (args != null && args.length > 0) { - try { - // emit the process.exit event - runSystemScript(SYSTEM_FINALIZATION_SCRIPTS); - } catch (Exception ex) { - if (rootCause != null) { - rootCause.addSuppressed(ex); - throw rootCause; - } - throw ex; + try { + // emit the process.exit event + runSystemScript(SYSTEM_FINALIZATION_SCRIPTS); + } catch (Exception ex) { + if (rootCause != null) { + rootCause.addSuppressed(ex); + throw rootCause; } + throw ex; } } } @@ -266,6 +276,8 @@ public final class Server { } else if ("--trace-deprecation".equals(arg)) { holder.setTraceDeprecation(true); holder.setThrowDeprecation(false); + } else if ("-i".equals(arg) || "--interactive".equals(arg)) { + holder.setForceRepl(true); } else { System.out.println(HELP); throw new IllegalArgumentException(arg); @@ -339,6 +351,7 @@ public final class Server { private String[] userFiles; private boolean throwDeprecation = true; private boolean traceDeprecation; + private boolean forceRepl = false; private int exitCode = 0; private final Invocable invocable; private Object nativeModule; @@ -368,9 +381,9 @@ public final class Server { } private void setArgs(final String[] avatarArgs, final String[] userArgs, final String[] userFiles) { - this.avatarArgs = avatarArgs.clone(); - this.userArgs = userArgs.clone(); - this.userFiles = userFiles.clone(); + this.avatarArgs = avatarArgs != null ? avatarArgs.clone() : null; + this.userArgs = userArgs != null ? userArgs.clone() : null; + this.userFiles = userFiles != null ? userFiles.clone() : null; } public String[] getAvatarArgs() { @@ -393,6 +406,10 @@ public final class Server { this.traceDeprecation = traceDeprecation; } + private void setForceRepl(boolean forceRepl) { + this.forceRepl = forceRepl; + } + public boolean getThrowDeprecation() { return throwDeprecation; } @@ -401,6 +418,10 @@ public final class Server { return traceDeprecation; } + public boolean getForceRepl() { + return forceRepl; + } + private void setExitCode(int exitCode) { this.exitCode = exitCode; } diff --git a/src/main/js/lib/process.js b/src/main/js/lib/process.js index 0f3c3c8..7437fc4 100644 --- a/src/main/js/lib/process.js +++ b/src/main/js/lib/process.js @@ -77,6 +77,11 @@ Object.defineProperty(exports, 'traceDeprecation', { value: __avatar.traceDeprecation }); +Object.defineProperty(exports, '_forceRepl', { + enumerable: true, + value: __avatar.forceRepl +}); + var stdin; Object.defineProperty(exports, 'stdin', { enumerable: true, @@ -278,12 +283,12 @@ Object.defineProperty(exports, 'argv', { _argv = []; _argv.push(exports.execPath); var uf = __avatar.userFiles; - var flen = uf.length; + var flen = uf ? uf.length : 0; for (var i=0; i < flen; i++) { _argv.push(uf[i]); } var ua = __avatar.userArgs; - var alen = ua.length; + var alen = ua ? ua.length : 0; for (var j=0; j < alen; j++) { _argv.push(ua[j]); } @@ -302,7 +307,7 @@ Object.defineProperty(exports, 'execArgv', { if (!_execArgv) { _execArgv = []; var aa = __avatar.avatarArgs; - var alen = aa.length; + var alen = aa ? aa.length : 0; for (var j=0; j < alen; j++) { _execArgv.push(aa[j]); } diff --git a/src/main/js/net/java/avatar/js/init.js b/src/main/js/net/java/avatar/js/init.js index 9a1e875..ad14c6c 100644 --- a/src/main/js/net/java/avatar/js/init.js +++ b/src/main/js/net/java/avatar/js/init.js @@ -300,6 +300,55 @@ var gc = global.gc; return current.apply(this, args); } - NativeModule.require('module').runMain(); + if (process.argv[1]) { + // make process.argv[1] into a full path + var path = NativeModule.require('path'); + process.argv[1] = path.resolve(process.argv[1]); + // If this is a worker in cluster mode, start up the communiction + // channel. + if (process.env.NODE_UNIQUE_ID) { + var cluster = NativeModule.require('cluster'); + cluster._setupWorker(); + + // Make sure it's not accidentally inherited by child processes. + delete process.env.NODE_UNIQUE_ID; + } + + NativeModule.require('module').runMain(); + } else { + var Module = NativeModule.require('module'); + + // If -i or --interactive were passed, or stdin is a TTY. + if (process._forceRepl || NativeModule.require('tty').isatty(0)) { + // REPL + var opts = { + useGlobal: true, + ignoreUndefined: false + }; + if (parseInt(process.env['NODE_NO_READLINE'], 10)) { + opts.terminal = false; + } + if (parseInt(process.env['NODE_DISABLE_COLORS'], 10)) { + opts.useColors = false; + } + var repl = Module.requireRepl().start(opts); + repl.on('exit', function() { + process.exit(); + }); + } else { + // Read all of stdin - execute it. + process.stdin.setEncoding('utf8'); + + var code = ''; + process.stdin.on('data', function(d) { + code += d; + }); + + process.stdin.on('end', function() { + process._eval = code; + evalScript('[stdin]'); + }); + } + } } )();