-
Notifications
You must be signed in to change notification settings - Fork 26
/
Copy pathindex.js
128 lines (104 loc) · 4.12 KB
/
index.js
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
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
'use strict'
/* -----------------------------------------------------------------------------
* dependencies
* -------------------------------------------------------------------------- */
// core
const path = require('path')
const spawn = require('child_process').spawn
// 3rd party
const _ = require('lodash')
const which = require('which')
const exitHook = require('exit-hook')
const portfinderSync = require('portfinder-sync')
const log = require('npmlog')
// lib
const Devtools = require('./devtools')
/* -----------------------------------------------------------------------------
* inspect
* -------------------------------------------------------------------------- */
module.exports = function (cmd, options) {
options = _.defaults(options || {}, {
inspectOptions: {},
nodeArgs: [],
childArgs: []
})
log.level = options['inspectOptions']['log-level'] || 'info'
const devtoolsOptions = _.pick(options['inspectOptions'], ['debug-exception'])
devtoolsOptions['debug-brk'] = options['nodeArgs'].includes('--debug-brk')
const devtools = new Devtools(devtoolsOptions)
return _.extend(inspectProcess(cmd, options, devtools), { devtools })
}
const inspectProcess = function (cmd, options, devtools) {
const getPathToCmd = function (cmd) {
try { return which.sync(cmd) } catch (e) { return path.resolve(cmd) }
}
return new Promise(function (resolve, reject) {
process.env['FORCE_COLOR'] = 1
const port = portfinderSync.getPort(9229)
const debugArgs = ['--inspect=' + port, '--debug-brk']
const nodeArgs = options['nodeArgs']
const childArgs = options['childArgs']
const args = nodeArgs.concat(debugArgs, [getPathToCmd(cmd)], childArgs)
const proc = spawn('node', args)
// we want esnure devtools creation/cleanup executes fully
let devtoolsOpen
let devtoolsClose
const openDevtools = function (url) {
return (devtoolsOpen = devtools.open(url))
}
const closeDevtools = function () {
return devtoolsOpen.then(() => (devtoolsClose = devtools.close()))
}
const onInspectComplete = function () {
if (!devtoolsOpen) {
return resolveWithResult()
}
return devtoolsClose
? devtoolsClose.then(resolveWithResult)
: closeDevtools().then(resolveWithResult)
}
const resolveWithResult = function () {
return proc.exitCode
? reject(new Error('Process exited with a non 0 exitCode.'))
: resolve()
}
proc.stdout.on('data', (data) => {
process.stdout.write(data)
})
proc.stderr.on('data', (data) => {
const dataStr = data.toString()
const isListening = dataStr.startsWith('Debugger listening on port')
const isListeningWs = dataStr.startsWith('Debugger listening on ws://')
const isAttached = dataStr.startsWith('Debugger attached')
const isCompleted = dataStr.startsWith('Waiting for the debugger to disconnect')
const DebugBrkDeprecation = dataStr.indexOf('DeprecationWarning: `node --inspect --debug-brk` is deprecated. Please use `node --inspect-brk` instead.') !== -1
const isInspectOutput = isListening || isListeningWs || isCompleted || isAttached || DebugBrkDeprecation
if (isListening) {
log.silly('process: listening')
openDevtools(dataStr.substring(dataStr.indexOf('chrome-devtools')))
} else if (isListeningWs) {
log.silly('process: listening')
const wsUrl = dataStr.match(/ws:\/\/(.*?)\s/)[1]
openDevtools(`chrome-devtools://devtools/bundled/inspector.html?experiments=true&v8only=true&ws=${wsUrl}`)
} else if (isCompleted && devtoolsOpen) {
log.silly('process: completed')
closeDevtools()
} else if (isAttached) {
log.silly('process: attached')
}
if (isInspectOutput) {
log.verbose('debugger: ' + _.trim(data))
} else {
process.stderr.write(data)
}
})
proc.once('exit', onInspectComplete)
proc.once('SIGINT', onInspectComplete)
proc.once('SIGTERM', onInspectComplete)
// safegaurd to ensure processes are cleaned up on exit
exitHook(() => {
devtools.close()
proc.kill()
})
})
}