-i, --interactive always enter the REPL even if stdin
does not appear to be a terminal
+ -r, --require module to preload at startup
+
--no-deprecation silence deprecation warnings
--trace-deprecation show stack traces on deprecations
static bool throw_deprecation = false;
static bool abort_on_uncaught_exception = false;
static const char* eval_string = nullptr;
+static unsigned int preload_module_count = 0;
+static const char** preload_modules = nullptr;
static bool use_debug_agent = false;
static bool debug_wait_connect = false;
static int debug_port = 5858;
READONLY_PROPERTY(process, "_forceRepl", True(env->isolate()));
}
+ if (preload_module_count) {
+ CHECK(preload_modules);
+ Local<Array> array = Array::New(env->isolate());
+ for (unsigned int i = 0; i < preload_module_count; ++i) {
+ Local<String> module = String::NewFromUtf8(env->isolate(),
+ preload_modules[i]);
+ array->Set(i, module);
+ }
+ READONLY_PROPERTY(process,
+ "_preload_modules",
+ array);
+ }
+
// --no-deprecation
if (no_deprecation) {
READONLY_PROPERTY(process, "noDeprecation", True(env->isolate()));
" -p, --print evaluate script and print result\n"
" -i, --interactive always enter the REPL even if stdin\n"
" does not appear to be a terminal\n"
+ " -r, --require module to preload (option can be repeated)\n"
" --no-deprecation silence deprecation warnings\n"
" --throw-deprecation throw an exception anytime a deprecated "
"function is used\n"
const char** new_exec_argv = new const char*[nargs];
const char** new_v8_argv = new const char*[nargs];
const char** new_argv = new const char*[nargs];
+ const char** local_preload_modules = new const char*[nargs];
for (unsigned int i = 0; i < nargs; ++i) {
new_exec_argv[i] = nullptr;
new_v8_argv[i] = nullptr;
new_argv[i] = nullptr;
+ local_preload_modules[i] = nullptr;
}
// exec_argv starts with the first option, the other two start with argv[0].
eval_string += 1;
}
}
+ } else if (strcmp(arg, "--require") == 0 ||
+ strcmp(arg, "-r") == 0) {
+ const char* module = argv[index + 1];
+ if (module == nullptr) {
+ fprintf(stderr, "%s: %s requires an argument\n", argv[0], arg);
+ exit(9);
+ }
+ args_consumed += 1;
+ local_preload_modules[preload_module_count++] = module;
} else if (strcmp(arg, "--interactive") == 0 || strcmp(arg, "-i") == 0) {
force_repl = true;
} else if (strcmp(arg, "--no-deprecation") == 0) {
memcpy(argv, new_argv, new_argc * sizeof(*argv));
delete[] new_argv;
*argc = static_cast<int>(new_argc);
+
+ // Copy the preload_modules from the local array to an appropriately sized
+ // global array.
+ if (preload_module_count > 0) {
+ CHECK(!preload_modules);
+ preload_modules = new const char*[preload_module_count];
+ memcpy(preload_modules, local_preload_modules,
+ preload_module_count * sizeof(*preload_modules));
+ }
+ delete[] local_preload_modules;
}
var d = NativeModule.require('_debug_agent');
d.start();
- } else if (process._eval != null) {
- // User passed '-e' or '--eval' arguments to Node.
- evalScript('[eval]');
- } else 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 communication
- // 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;
+ } else {
+ // There is user code to be run
+
+ // Load any preload modules
+ if (process._preload_modules) {
+ var Module = NativeModule.require('module');
+ process._preload_modules.forEach(function(module) {
+ Module._load(module);
+ });
}
- var Module = NativeModule.require('module');
+ if (process._eval != null) {
+ // User passed '-e' or '--eval' arguments to Node.
+ evalScript('[eval]');
+ } else 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 communication
+ // 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;
+ }
- if (global.v8debug &&
- process.execArgv.some(function(arg) {
- return arg.match(/^--debug-brk(=[0-9]*)?$/);
- })) {
+ var Module = NativeModule.require('module');
- // XXX Fix this terrible hack!
- //
- // Give the client program a few ticks to connect.
- // Otherwise, there's a race condition where `node debug foo.js`
- // will not be able to connect in time to catch the first
- // breakpoint message on line 1.
- //
- // A better fix would be to somehow get a message from the
- // global.v8debug object about a connection, and runMain when
- // that occurs. --isaacs
+ if (global.v8debug &&
+ process.execArgv.some(function(arg) {
+ return arg.match(/^--debug-brk(=[0-9]*)?$/);
+ })) {
- var debugTimeout = +process.env.NODE_DEBUG_TIMEOUT || 50;
- setTimeout(Module.runMain, debugTimeout);
+ // XXX Fix this terrible hack!
+ //
+ // Give the client program a few ticks to connect.
+ // Otherwise, there's a race condition where `node debug foo.js`
+ // will not be able to connect in time to catch the first
+ // breakpoint message on line 1.
+ //
+ // A better fix would be to somehow get a message from the
+ // global.v8debug object about a connection, and runMain when
+ // that occurs. --isaacs
- } else {
- // Main entry point into most programs:
- Module.runMain();
- }
+ var debugTimeout = +process.env.NODE_DEBUG_TIMEOUT || 50;
+ setTimeout(Module.runMain, debugTimeout);
- } 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;
+ } else {
+ // Main entry point into most programs:
+ Module.runMain();
}
- var repl = Module.requireRepl().start(opts);
- repl.on('exit', function() {
- process.exit();
- });
} else {
- // Read all of stdin - execute it.
- process.stdin.setEncoding('utf8');
+ 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();
+ });
- var code = '';
- process.stdin.on('data', function(d) {
- code += d;
- });
+ } else {
+ // Read all of stdin - execute it.
+ process.stdin.setEncoding('utf8');
- process.stdin.on('end', function() {
- process._eval = code;
- evalScript('[stdin]');
- });
+ var code = '';
+ process.stdin.on('data', function(d) {
+ code += d;
+ });
+
+ process.stdin.on('end', function() {
+ process._eval = code;
+ evalScript('[stdin]');
+ });
+ }
}
}
}
--- /dev/null
+console.log('A')
--- /dev/null
+console.log('B')
--- /dev/null
+console.log('C')
--- /dev/null
+var common = require('../common'),
+ assert = require('assert'),
+ path = require('path'),
+ child_process = require('child_process');
+
+var nodeBinary = process.argv[0];
+
+var preloadOption = function(preloads) {
+ var option = '';
+ preloads.forEach(function(preload, index) {
+ // TODO: randomly pick -r or --require
+ option += '-r ' + preload + ' ';
+ });
+ return option;
+}
+
+var fixture = function(name) {
+ return path.join(__dirname, '../fixtures/' + name);
+}
+
+var fixtureA = fixture('printA.js');
+var fixtureB = fixture('printB.js');
+var fixtureC = fixture('printC.js')
+var fixtureThrows = fixture('throws_error4.js');
+
+// test preloading a single module works
+child_process.exec(nodeBinary + ' '
+ + preloadOption([fixtureA]) + ' '
+ + fixtureB,
+ function(err, stdout, stderr) {
+ if (err) throw err;
+ assert.equal(stdout, 'A\nB\n');
+ });
+
+// test preloading multiple modules works
+child_process.exec(nodeBinary + ' '
+ + preloadOption([fixtureA, fixtureB]) + ' '
+ + fixtureC,
+ function(err, stdout, stderr) {
+ if (err) throw err;
+ assert.equal(stdout, 'A\nB\nC\n');
+ });
+
+// test that preloading a throwing module aborts
+child_process.exec(nodeBinary + ' '
+ + preloadOption([fixtureA, fixtureThrows]) + ' '
+ + fixtureB,
+ function(err, stdout, stderr) {
+ if (err) {
+ assert.equal(stdout, 'A\n');
+ } else {
+ throw new Error('Preload should have failed');
+ }
+ });
+
+// test that preload can be used with --eval
+child_process.exec(nodeBinary + ' '
+ + preloadOption([fixtureA])
+ + '-e "console.log(\'hello\');"',
+ function(err, stdout, stderr) {
+ if (err) throw err;
+ assert.equal(stdout, 'A\nhello\n');
+ });
+
+// test that preload placement at other points in the cmdline
+// also test that duplicated preload only gets loaded once
+child_process.exec(nodeBinary + ' '
+ + preloadOption([fixtureA])
+ + '-e "console.log(\'hello\');" '
+ + preloadOption([fixtureA, fixtureB]),
+ function(err, stdout, stderr) {
+ if (err) throw err;
+ assert.equal(stdout, 'A\nB\nhello\n');
+ });