-
Notifications
You must be signed in to change notification settings - Fork 0
/
task.coffee
108 lines (93 loc) · 3.37 KB
/
task.coffee
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
_ = 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:complete - 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')}');"
taskBootstrapRequire = "require('#{require.resolve('./task-bootstrap')}');"
bootstrap = """
#{coffeeScriptRequire}
#{coffeeCacheRequire}
Object.defineProperty(require.extensions, '.coffee', {
writable: false,
value: require.extensions['.coffee']
});
#{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()