Files
atom/src/task.coffee
Kevin Sawicki 8f2770d084 Prevent overriding coffee cache once registered
Previously this was done afterwards in index.html and task.coffee
but should really be handled by the cache itself so any module
require a different version of coffee-script are not reregistering
a different require extension handler.
2013-10-04 09:25:31 -07:00

105 lines
3.2 KiB
CoffeeScript

_ = require './underscore-extensions'
child_process = require 'child_process'
EventEmitter = require './event-emitter'
# Public: Run a node script in a separate process.
#
# Used by the fuzzy-finder.
#
# ## Events
#
# * task:log - Emitted when console.log is called within the task.
# * task:warn - Emitted when console.warn is called within the task.
# * task:error - Emitted when console.error is called within the task.
# * task:completed - Emitted when the task has succeeded or failed.
module.exports =
class Task
_.extend @prototype, EventEmitter
# Public: A helper method to easily launch and run a task once.
#
# * taskPath:
# The path to the Coffeescript/Javascript file which exports a single
# function to execute.
# * args:
# The Array of arguments to pass to the exported function.
@once: (taskPath, args...) ->
task = new Task(taskPath)
task.one 'task:completed', -> task.terminate()
task.start(args...)
task
# Public: Called upon task completion.
#
# It receives the same arguments that were passed to the task.
#
# If subclassed, this is intended to be overridden. However if {.start}
# receives a completion callback, this is overridden.
callback: null
# Public: Creates a task.
#
# * taskPath:
# The path to the Coffeescript/Javascript file that exports a single
# function to execute.
constructor: (taskPath) ->
coffeeScriptRequire = "require('#{require.resolve('coffee-script')}');"
coffeeCacheRequire = "require('#{require.resolve('./coffee-cache')}').register();"
taskBootstrapRequire = "require('#{require.resolve('./task-bootstrap')}');"
bootstrap = """
#{coffeeScriptRequire}
#{coffeeCacheRequire}
#{taskBootstrapRequire}
"""
taskPath = require.resolve(taskPath)
env = _.extend({}, process.env, {taskPath, userAgent: navigator.userAgent})
args = [bootstrap, '--harmony_collections']
@childProcess = child_process.fork '--eval', args, {env, cwd: __dirname}
@on "task:log", -> console.log(arguments...)
@on "task:warn", -> console.warn(arguments...)
@on "task:error", -> console.error(arguments...)
@on "task:completed", (args...) => @callback?(args...)
@handleEvents()
# Private: Routes messages from the child to the appropriate event.
handleEvents: ->
@childProcess.removeAllListeners()
@childProcess.on 'message', ({event, args}) =>
@trigger(event, args...)
# Public: Starts the task.
#
# * args:
# The Array of arguments to pass to the function exported by the script. If
# the last argument is a function, its removed from the array and called
# upon completion (and replaces the complete function on the task instance).
start: (args...) ->
throw new Error("Cannot start terminated process") unless @childProcess?
@handleEvents()
@callback = args.pop() if _.isFunction(args[args.length - 1])
@send({event: 'start', args})
# Public: Send message to the task
#
# * message:
# The message to send
send: (message) ->
@childProcess.send(message)
# Public: Forcefully stop the running task.
#
# No events are emitted.
terminate: ->
return unless @childProcess?
@childProcess.removeAllListeners()
@childProcess.kill()
@childProcess = null
@off()