Skip to content

Commit

Permalink
Improve process detach behavior
Browse files Browse the repository at this point in the history
  • Loading branch information
wdavidw committed Sep 15, 2011
1 parent a23c7e7 commit 76666f6
Show file tree
Hide file tree
Showing 5 changed files with 45 additions and 42 deletions.
12 changes: 6 additions & 6 deletions lib/plugins/cloud9.coffee
Original file line number Diff line number Diff line change
Expand Up @@ -8,11 +8,8 @@ module.exports = (settings = {}) ->
# Default settings
settings.workspace ?= shell.project_dir
throw new Error 'No workspace provided' if not settings.workspace
cloud9 = null
# Register commands
shell.cmd 'cloud9 start', 'Start Cloud9', (req, res, next) ->
cmd = () ->
args = []
detached = not shell.isShell or settings.detach
args.push '-w'
args.push settings.workspace
# Arguments
Expand All @@ -35,15 +32,18 @@ module.exports = (settings = {}) ->
args.push '-p'
args.push settings.port
cmd = 'cloud9 ' + args.join(' ')
cloud9 = null
# Register commands
shell.cmd 'cloud9 start', 'Start Cloud9', (req, res, next) ->
# Launch process
cloud9 = process.start shell, settings, cmd, (err) ->
cloud9 = process.start shell, settings, cmd(), (err) ->
ip = settings.ip or '127.0.0.1'
port = settings.port or 3000
message = "Cloud9 started http://#{ip}:#{port}"
res.cyan( message ).ln()
res.prompt()
shell.cmd 'cloud9 stop', 'Stop Cloud9', (req, res, next) ->
process.stop settings, cloud9, (err, success) ->
process.stop shell, settings, cloud9 or cmd(), (err, success) ->
if success
then res.cyan('Cloud9 successfully stoped').ln()
else res.magenta('Cloud9 was not started').ln()
Expand Down
10 changes: 5 additions & 5 deletions lib/plugins/coffee.coffee
Original file line number Diff line number Diff line change
Expand Up @@ -20,10 +20,8 @@ module.exports = (settings = {}) ->
settings.workspace ?= shell.project_dir
throw new Error 'No workspace provided' if not settings.workspace
coffee = null
# Register commands
shell.cmd 'coffee start', 'Start CoffeeScript', (req, res, next) ->
cmd = () ->
args = []
detached = not shell.isShell or settings.detach
# Before compiling, concatenate all scripts together in the
# order they were passed, and write them into the specified
# file. Useful for building large projects.
Expand Down Expand Up @@ -60,14 +58,16 @@ module.exports = (settings = {}) ->
args.push '-c'
args.push enrichFiles(settings.compile)
cmd = 'coffee ' + args.join(' ')
coffee = process.start shell, settings, cmd, (err) ->
# Register commands
shell.cmd 'coffee start', 'Start CoffeeScript', (req, res, next) ->
coffee = process.start shell, settings, cmd(), (err) ->
ip = settings.ip or '127.0.0.1'
port = settings.port or 3000
message = "CoffeeScript started"
res.cyan( message ).ln()
res.prompt()
shell.cmd 'coffee stop', 'Stop CoffeeScript', (req, res, next) ->
process.stop settings, coffee, (err, success) ->
process.stop shell, settings, coffee or cmd(), (err, success) ->
if success
then res.cyan('CoffeeScript successfully stoped').ln()
else res.magenta('CoffeeScript was not started').ln()
Expand Down
15 changes: 7 additions & 8 deletions lib/plugins/http.coffee
Original file line number Diff line number Diff line change
Expand Up @@ -11,11 +11,7 @@ module.exports = (settings) ->
throw new Error 'No workspace provided' if not settings.workspace
settings.message_start ?= 'HTTP server successfully started'
settings.message_stop ?= 'HTTP server successfully stopped'
# Register commands
http = null
shell.on 'exit', () ->
http.kill() if shell.isShell and not settings.detach and http
shell.cmd 'http start', 'Start HTTP server', (req, res, next) ->
cmd = () ->
if path.existsSync settings.workspace + '/server.js'
cmd = 'node ' + settings.workspace + '/server'
else if path.existsSync settings.workspace + '/server.coffee'
Expand All @@ -25,13 +21,16 @@ module.exports = (settings) ->
else if path.existsSync settings.workspace + '/app.coffee'
cmd = 'coffee ' + settings.workspace + '/app.coffee'
else
next new Error 'Failed to discover a "server.js" or "app.js" file'
http = process.start shell, settings, cmd, (err) ->
throw new Error 'Failed to discover a "server.js" or "app.js" file'
# Register commands
http = null
shell.cmd 'http start', 'Start HTTP server', (req, res, next) ->
http = process.start shell, settings, cmd(), (err) ->
message = "HTTP server started"
res.cyan( message ).ln()
res.prompt()
shell.cmd 'http stop', 'Stop HTTP server', (req, res, next) ->
process.stop settings, http, (err, success) ->
process.stop shell, settings, http or cmd(), (err, success) ->
if success
then res.cyan('HTTP server successfully stoped').ln()
else res.magenta('HTTP server was not started').ln()
Expand Down
7 changes: 4 additions & 3 deletions lib/plugins/redis.coffee
Original file line number Diff line number Diff line change
Expand Up @@ -8,19 +8,20 @@ module.exports = (settings) ->
shell = settings.shell
# Default settings
settings.workspace ?= shell.project_dir
cmd = () ->
"redis-server #{settings.config}"
# Register commands
redis = null
shell.cmd 'redis start', 'Start Redis', (req, res, next) ->
# Launch process
cmd = "redis-server #{settings.config}"
redis = process.start shell, settings, cmd, (err) ->
redis = process.start shell, settings, cmd(), (err) ->
ip = settings.ip or '127.0.0.1'
port = settings.port or 3000
message = "Redis started"
res.cyan( message ).ln()
res.prompt()
shell.cmd 'redis stop', 'Stop Redis', (req, res, next) ->
process.stop settings, redis, (err, success) ->
process.stop shell, settings, redis or cmd(), (err, success) ->
if success
then res.cyan('Redis successfully stoped').ln()
else res.magenta('Redis was not started').ln()
Expand Down
43 changes: 23 additions & 20 deletions lib/process.coffee
Original file line number Diff line number Diff line change
Expand Up @@ -4,28 +4,30 @@ exec = require('child_process').exec
fs = require 'fs'
path = require 'path'

md5 = (id) ->
crypto.createHash('md5').update(id).digest('hex')
md5 = (cmd) ->
crypto.createHash('md5').update(cmd).digest('hex')

pidfile = (id) ->
pidfile = (cmd) ->
dir = process.env['HOME'] + '/.node_shell'
file = md5 id
file = md5 cmd
createDir = not path.existsSync process.env['HOME'] + '/.node_shell'
fs.mkdirSync dir, 0700 if createDir
"#{dir}/#{file}"
"#{dir}/#{file}.pid"

module.exports.start = (shell, settings, cmd, callback) ->
if settings.detach and not settings.pidfile
throw new Exception 'Property settings.pidfile required in detached mode'
if settings.detach
detach = settings.detach ? not shell.isShell
#if detach and not settings.pidfile
#throw new Error 'Property settings.pidfile required in detached mode'
if detach
cmdStdout = if typeof settings.stdout is 'string' then settings.stdout else '/dev/null'
cmdStderr = if typeof settings.stderr is 'string' then settings.stderr else '/dev/null'
cmd += " </dev/null >#{cmdStdout} 2>#{cmdStdout}"
cmd += ' & echo $? $!'
child = exec cmd, (err, stdout, stderr) ->
pipe = "</dev/null >#{cmdStdout} 2>#{cmdStdout}"
info = 'echo $? $!'
child = exec "#{cmd} #{pipe} & #{info}", (err, stdout, stderr) ->
[code, pid] = stdout.split(' ')
return callback new Error "Process exit with code #{code}" if code isnt '0'
pidfile = settings.pidfile or pidfile cmd
console.log 'pidfile', pidfile
fs.writeFileSync pidfile, '' + pid
callback null, pid
else # Kill child on exit if started in attached mode
Expand All @@ -46,28 +48,29 @@ module.exports.start = (shell, settings, cmd, callback) ->
child.stderr.pipe stdout if stdout
child.stderr.pipe stderr if stderr
process.nextTick ->
# Block the command if not in shell and process is attached
return if not shell.isShell and settings.detach is false
callback null, child.pid
child


module.exports.stop = (settings, child, callback) ->
if settings.detach and not settings.pidfile
throw new Exception 'Property settings.pidfile required in detached mode'
if settings.detach
unless path.existsSync settings.pidfile
return callback null, false
pid = fs.readFileSync settings.pidfile
module.exports.stop = (shell, settings, cmdOrChild, callback) ->
detach = settings.detach ? not shell.isShell
if detach
pidfile = settings.pidfile or pidfile cmdOrChild
return callback null, false unless path.existsSync pidfile
pid = fs.readFileSync pidfile, 'ascii'
cmds = []
cmds.push "for i in `ps -ef| awk '$3 == '#{pid}' { print $2 }'` ; do kill $i ; done"
cmds.push "kill #{pid}"
cmds = cmds.join ' && '
child = exec(cmds)
child.on 'exit', (code) ->
return callback new Error "Unexpected exit code #{code}" unless code is 0
fs.unlinkSync settings.pidfile
fs.unlinkSync pidfile
callback null, true
else
pid = child.pid
pid = cmdOrChild.pid
cmds = []
cmds.push "for i in `ps -ef | awk '$3 == '#{pid}' { print $2 }'` ; do kill $i ; done"
cmds.push "kill #{pid}"
Expand Down

0 comments on commit 76666f6

Please sign in to comment.