diff --git a/admin/generate-dev-bundle.sh b/admin/generate-dev-bundle.sh index 45ebe833df..8b1295387f 100755 --- a/admin/generate-dev-bundle.sh +++ b/admin/generate-dev-bundle.sh @@ -56,33 +56,48 @@ git clone git://github.com/joyent/node.git cd node git checkout v0.8.8 +# Patch node to allow unsetting O_NONBLOCK on TTYs. This is a gross hack +# to work-around node setting process.stdin non-blocking. +# +# This is needed to allow spawning a mongo command line process to the +# users terminal (eg 'meteor mongo'). It also fixes behavior in +# emacs-shell mode. +# +# Related github issue: +# https://github.com/joyent/node/issues/3584 +# Discussion of implementing process.stdout.setBlocking(bool): +# http://piscisaureus.no.de/libuv/2012-06-29#00:40:38.256 +# Emacs bug this fixes: +# http://debbugs.gnu.org/cgi/bugreport.cgi?bug=2602 patch -p1 < target) { -+#include - #include "node.h" - #include "node_buffer.h" - #include "req_wrap.h" -@@ -68,6 +69,8 @@ void TTYWrap::Initialize(Handle target) { NODE_SET_PROTOTYPE_METHOD(t, "getWindowSize", TTYWrap::GetWindowSize); NODE_SET_PROTOTYPE_METHOD(t, "setRawMode", SetRawMode); ++ // meteor ++ NODE_SET_PROTOTYPE_METHOD(t, "setBlocking", TTYWrap::SetBlocking); -+ NODE_SET_PROTOTYPE_METHOD(t, "setNonBlocking", TTYWrap::SetNonBlocking); -+ NODE_SET_METHOD(target, "isTTY", IsTTY); NODE_SET_METHOD(target, "guessHandleType", GuessHandleType); - -@@ -121,6 +124,37 @@ Handle TTYWrap::IsTTY(const Arguments& args) { - return uv_guess_handle(fd) == UV_TTY ? v8::True() : v8::False(); +@@ -158,6 +162,39 @@ Handle TTYWrap::SetRawMode(const Arguments& args) { } -+Handle TTYWrap::SetNonBlocking(const Arguments& args) { + ++// meteor ++Handle TTYWrap::SetBlocking(const Arguments& args) { + HandleScope scope; + + UNWRAP(TTYWrap) @@ -91,45 +106,47 @@ index fde8717..2420e7e 100644 + int set = args[0]->IsTrue(); + int r = 0; + -+ /// uv__nonblock ++ // implementation copied from uv__nonblock. + int flags; + + if ((flags = fcntl(fd, F_GETFL)) == -1) { + r = -1; + } else { + ++ // reverse of uv__nonblock. setBlocking vs setNonBlocking. + if (set) { -+ flags |= O_NONBLOCK; -+ } else { + flags &= ~O_NONBLOCK; ++ } else { ++ flags |= O_NONBLOCK; + } + -+ int r; + if (fcntl(fd, F_SETFL, flags) == -1) { + r = -1; + } + } -+ /// + + return scope.Close(Integer::New(r)); +} - - Handle TTYWrap::GetWindowSize(const Arguments& args) { ++ ++ + Handle TTYWrap::New(const Arguments& args) { HandleScope scope; + diff --git a/src/tty_wrap.h b/src/tty_wrap.h -index 4a3341a..bac0d0f 100644 +index 4a3341a..01aa119 100644 --- a/src/tty_wrap.h +++ b/src/tty_wrap.h @@ -48,6 +48,7 @@ class TTYWrap : StreamWrap { static Handle IsTTY(const Arguments& args); static Handle GetWindowSize(const Arguments& args); static Handle SetRawMode(const Arguments& args); -+ static Handle SetNonBlocking(const Arguments& args); ++ static Handle SetBlocking(const Arguments& args); // meteor static Handle New(const Arguments& args); uv_tty_t handle_; EOF + ./configure --prefix="$DIR" make -j4 make install diff --git a/app/meteor/deploy.js b/app/meteor/deploy.js index b3e0ca5a49..81a275a24b 100644 --- a/app/meteor/deploy.js +++ b/app/meteor/deploy.js @@ -13,19 +13,25 @@ var files = require('../lib/files.js'); var _ = require('../lib/third/underscore.js'); var keypress = require('keypress'); -// This magic incantation seems to both fix the "meteor mongo" repl -// and keep Node from bringing down the Emacs shell on exit. -if (process.stdin.isTTY) - // Call a special function that we monkey-patched into - // node/src/tty_wrap.cc. It sets fcntl's O_NONBLOCK to a boolean. - process.stdin._handle.setNonBlocking(false); - // // configuration // var DEPLOY_HOSTNAME = process.env.DEPLOY_HOSTNAME || 'deploy.meteor.com'; + +// Set stdin to be blocking, reversing node's normal setting of +// O_NONBLOCK on process.stdin. +// +// This uses a meteor hack to node. See admin/generate-dev-bundle.sh. +// +// This fixes the "meteor mongo" repl and keeps node from bringing down +// the Emacs shell on exit. +if (process.stdin.isTTY && + process.stdin._handle && process.stdin._handle.setBlocking) + process.stdin._handle.setBlocking(true); + + // available RPCs are: deploy (with set-password), delete, logs, // mongo_cred. each RPC might require a password, which we // interactively prompt for here. @@ -46,7 +52,7 @@ var meteor_rpc = function (rpc_name, method, site, query_params, callback) { }); return r; -} +}; var deploy_app = function (url, app_dir, opt_debug, opt_tests, opt_set_password) {