@jsreport/jsreport-cli 3.0.0-beta.2 → 3.1.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (41) hide show
  1. package/LICENSE +21 -21
  2. package/README.md +16 -12
  3. package/cli.js +93 -93
  4. package/example.config.json +43 -43
  5. package/example.server.js +14 -14
  6. package/index.js +20 -22
  7. package/jsreport.config.js +8 -8
  8. package/lib/cliExtension.js +59 -59
  9. package/lib/{createCommandParser.js → commander/createCommandParser.js} +44 -45
  10. package/lib/commander/createCustomCommandBuilder.js +150 -0
  11. package/lib/commander/createLogger.js +51 -0
  12. package/lib/commander/executeCommand.js +37 -0
  13. package/lib/commander/getCommandEventName.js +4 -0
  14. package/lib/commander/index.js +279 -0
  15. package/lib/commander/jsreportInstance.js +98 -0
  16. package/lib/commander/registerCommand.js +91 -0
  17. package/lib/commander/startCommand.js +234 -0
  18. package/lib/commander/startProcessing.js +208 -0
  19. package/lib/commands/_initializeApp.js +206 -208
  20. package/lib/commands/configure.js +393 -395
  21. package/lib/commands/help.js +453 -454
  22. package/lib/commands/init.js +76 -77
  23. package/lib/commands/kill.js +85 -86
  24. package/lib/commands/render.js +490 -488
  25. package/lib/commands/repair.js +55 -56
  26. package/lib/commands/start.js +72 -74
  27. package/lib/commands/win-install.js +124 -126
  28. package/lib/commands/win-uninstall.js +100 -102
  29. package/lib/daemonHandler.js +164 -164
  30. package/lib/daemonInstance.js +225 -225
  31. package/lib/{registerExtensionsCommands.js → detectAndRegisterExtensionsCommands.js} +74 -74
  32. package/lib/instanceHandler.js +316 -316
  33. package/lib/keepAliveProcess.js +205 -205
  34. package/lib/{errorUtils.js → utils/error.js} +149 -127
  35. package/lib/{getTempPaths.js → utils/getTempPaths.js} +39 -39
  36. package/lib/{normalizePathOptionOrArg.js → utils/normalizePathOptionOrArg.js} +41 -41
  37. package/lib/{normalizeSocketPath.js → utils/normalizeSocketPath.js} +9 -9
  38. package/lib/{startSocketServer.js → utils/startSocketServer.js} +53 -53
  39. package/package.json +105 -106
  40. package/test/testUtils.js +197 -198
  41. package/lib/commander.js +0 -1108
@@ -1,225 +1,225 @@
1
- 'use strict'
2
-
3
- const fs = require('fs')
4
- const HttpsServer = require('https').Server
5
- const ipAddress = require('ip-address')
6
- const nssocket = require('nssocket')
7
- const startSocketServer = require('./startSocketServer.js')
8
- const instanceHandler = require('./instanceHandler.js')
9
- const errorUtils = require('./errorUtils')
10
-
11
- const PID = process.pid
12
-
13
- let socketServer
14
-
15
- function start (customInstance, socketFile) {
16
- const socketToMaster = new nssocket.NsSocket()
17
- let parentSocketFile
18
- let processInfo
19
- let reporterInstance
20
-
21
- console.log('PID of daemon instance:', PID)
22
-
23
- if (socketFile) {
24
- parentSocketFile = socketFile
25
- } else {
26
- parentSocketFile = process.argv[2]
27
- }
28
-
29
- // connect to parent socket for parent-child communication
30
- socketToMaster.connect(parentSocketFile, (err) => {
31
- // in case of connection error exit the process immediately
32
- // to notify parent
33
- if (err) {
34
- return process.exit(1)
35
- }
36
-
37
- // parent process will pass options in the "init" event
38
- socketToMaster.dataOnce(['init'], (options) => {
39
- const sockPath = options.sockPath
40
- const cwd = options.cwd
41
- const verbose = options.verbose
42
- let getInstanceAsync
43
-
44
- if (customInstance) {
45
- getInstanceAsync = Promise.resolve({
46
- instance: typeof customInstance === 'function' ? customInstance() : customInstance
47
- })
48
- } else {
49
- getInstanceAsync = instanceHandler.find(cwd)
50
- }
51
-
52
- // find and initialize a jsreport instance
53
- getInstanceAsync
54
- .then((instanceInfo) => {
55
- return instanceHandler.initialize(instanceInfo.instance, verbose)
56
- })
57
- .then((instance) => {
58
- let adminAuthentication
59
- let jsreportServer
60
- let address
61
- let hostname
62
- let protocol
63
- let appPath
64
-
65
- reporterInstance = instance
66
-
67
- if (
68
- instance.options.extensions &&
69
- instance.options.extensions.authentication &&
70
- instance.options.extensions.authentication.admin
71
- ) {
72
- adminAuthentication = instance.options.extensions.authentication.admin
73
- }
74
-
75
- if (instance.express && instance.express.server) {
76
- jsreportServer = instance.express.server
77
- address = jsreportServer.address()
78
- } else {
79
- throw new Error(
80
- 'jsreport instance detected does not have jsreport-express extension enabled, ' +
81
- 'either install or enable it first to use keepAlive option'
82
- )
83
- }
84
-
85
- appPath = instance.options.appPath || ''
86
-
87
- if (appPath === '/') {
88
- appPath = ''
89
- }
90
-
91
- // normalizing ipv6 to ipv4
92
- if (address.family === 'IPv6') {
93
- hostname = new ipAddress.Address6(address.address).to4()
94
-
95
- if (typeof hostname !== 'string') {
96
- hostname = hostname.address
97
- }
98
- } else {
99
- hostname = address.address
100
- }
101
-
102
- // normalizing host, on windows connecting to "0.0.0.0" doesn't work
103
- if (hostname === '0.0.0.0') {
104
- hostname = 'localhost'
105
- }
106
-
107
- if (jsreportServer instanceof HttpsServer) {
108
- protocol = 'https'
109
- } else {
110
- protocol = 'http'
111
- }
112
-
113
- const urlToServer = `${protocol}://${hostname}:${address.port}/${appPath}`
114
-
115
- // starting a server in a new socket to allow the monitoring
116
- // and query of this process from the CLI
117
- socketServer = startSocketServer({
118
- socketPath: sockPath,
119
- socketPrefix: 'm',
120
- // Create 'symbolic' file on the system, so it can be later
121
- // found, since the `\\.pipe\\*` "files" can't
122
- // be enumerated because ... Windows.
123
- createSymbolicForSocket: process.platform === 'win32',
124
- protocol: monitorProtocol
125
- }, (socketInitErr, serverInfo) => {
126
- if (socketInitErr) {
127
- return socketToMaster.send(['init'], {
128
- error: socketInitErr.message,
129
- stacks: errorUtils.getErrors(socketInitErr).map(e => e.stack)
130
- })
131
- }
132
-
133
- // collecting all the information about this process
134
- // for later queries
135
- processInfo = {
136
- uid: serverInfo.uid,
137
- pid: PID,
138
- cwd: cwd,
139
- version: instance.version,
140
- socketFile: serverInfo.socketFile,
141
- normalizedSocketFile: serverInfo.normalizedSocketFile,
142
- url: urlToServer,
143
- adminAuthentication: adminAuthentication
144
- }
145
-
146
- socketToMaster.send(['init'], Object.assign({}, processInfo, { error: null }))
147
- })
148
- })
149
- .catch((err) => {
150
- const meta = {}
151
-
152
- if (err.code != null) {
153
- meta.code = err.code
154
- }
155
-
156
- socketToMaster.send(['init'], {
157
- error: err.message,
158
- stacks: errorUtils.getErrors(err).map(e => e.stack),
159
- meta: Object.keys(meta).length > 0 ? meta : undefined
160
- })
161
-
162
- setImmediate(() => {
163
- process.exit(1)
164
- })
165
- })
166
- })
167
-
168
- socketToMaster.send(['alive'])
169
- })
170
-
171
- socketToMaster.on('error', (err) => {
172
- if (err.code === 'ECONNREFUSED') {
173
- try {
174
- fs.unlinkSync(parentSocketFile)
175
- } catch (e) {}
176
- }
177
-
178
- process.exit(1)
179
- })
180
-
181
- function monitorProtocol (socket) {
182
- socket.on('error', (err) => {
183
- console.error('socket error:', err)
184
- socket.destroy()
185
- })
186
-
187
- socket.data(['info'], () => {
188
- socket.send(['info'], processInfo)
189
- })
190
-
191
- socket.data(['kill'], () => {
192
- if (process.platform === 'win32') {
193
- //
194
- // On Windows, delete the 'symbolic' sock file. This
195
- // file is used for exploration as a mapping to the
196
- // `\\.pipe\\*` "files" that can't
197
- // be enumerated because ... Windows.
198
- //
199
- try {
200
- fs.unlinkSync(processInfo.socketFile)
201
- } catch (e) {}
202
- }
203
-
204
- // close the server to prevent accepting new connections,
205
- // such situation can happen when doing concurrent calls to kill the server
206
- if (socketServer) {
207
- socketServer.close()
208
- }
209
-
210
- const exit = () => process.exit()
211
-
212
- if (reporterInstance) {
213
- reporterInstance.close().then(exit, exit)
214
- } else {
215
- exit()
216
- }
217
- })
218
- }
219
- }
220
-
221
- if (require.main === module) {
222
- start()
223
- } else {
224
- module.exports = start
225
- }
1
+ 'use strict'
2
+
3
+ const fs = require('fs')
4
+ const HttpsServer = require('https').Server
5
+ const ipAddress = require('ip-address')
6
+ const nssocket = require('nssocket')
7
+ const instanceHandler = require('./instanceHandler')
8
+ const startSocketServer = require('./utils/startSocketServer')
9
+ const { getErrors } = require('./utils/error')
10
+
11
+ const PID = process.pid
12
+
13
+ let socketServer
14
+
15
+ function start (customInstance, socketFile) {
16
+ const socketToMaster = new nssocket.NsSocket()
17
+ let parentSocketFile
18
+ let processInfo
19
+ let reporterInstance
20
+
21
+ console.log('PID of daemon instance:', PID)
22
+
23
+ if (socketFile) {
24
+ parentSocketFile = socketFile
25
+ } else {
26
+ parentSocketFile = process.argv[2]
27
+ }
28
+
29
+ // connect to parent socket for parent-child communication
30
+ socketToMaster.connect(parentSocketFile, (err) => {
31
+ // in case of connection error exit the process immediately
32
+ // to notify parent
33
+ if (err) {
34
+ return process.exit(1)
35
+ }
36
+
37
+ // parent process will pass options in the "init" event
38
+ socketToMaster.dataOnce(['init'], (options) => {
39
+ const sockPath = options.sockPath
40
+ const cwd = options.cwd
41
+ const verbose = options.verbose
42
+ let getInstanceAsync
43
+
44
+ if (customInstance) {
45
+ getInstanceAsync = Promise.resolve({
46
+ instance: typeof customInstance === 'function' ? customInstance() : customInstance
47
+ })
48
+ } else {
49
+ getInstanceAsync = instanceHandler.find(cwd)
50
+ }
51
+
52
+ // find and initialize a jsreport instance
53
+ getInstanceAsync
54
+ .then((instanceInfo) => {
55
+ return instanceHandler.initialize(instanceInfo.instance, verbose)
56
+ })
57
+ .then((instance) => {
58
+ let adminAuthentication
59
+ let jsreportServer
60
+ let address
61
+ let hostname
62
+ let protocol
63
+ let appPath
64
+
65
+ reporterInstance = instance
66
+
67
+ if (
68
+ instance.options.extensions &&
69
+ instance.options.extensions.authentication &&
70
+ instance.options.extensions.authentication.admin
71
+ ) {
72
+ adminAuthentication = instance.options.extensions.authentication.admin
73
+ }
74
+
75
+ if (instance.express && instance.express.server) {
76
+ jsreportServer = instance.express.server
77
+ address = jsreportServer.address()
78
+ } else {
79
+ throw new Error(
80
+ 'jsreport instance detected does not have jsreport-express extension enabled, ' +
81
+ 'either install or enable it first to use keepAlive option'
82
+ )
83
+ }
84
+
85
+ appPath = instance.options.appPath || ''
86
+
87
+ if (appPath === '/') {
88
+ appPath = ''
89
+ }
90
+
91
+ // normalizing ipv6 to ipv4
92
+ if (address.family === 'IPv6') {
93
+ hostname = new ipAddress.Address6(address.address).to4()
94
+
95
+ if (typeof hostname !== 'string') {
96
+ hostname = hostname.address
97
+ }
98
+ } else {
99
+ hostname = address.address
100
+ }
101
+
102
+ // normalizing host, on windows connecting to "0.0.0.0" doesn't work
103
+ if (hostname === '0.0.0.0') {
104
+ hostname = 'localhost'
105
+ }
106
+
107
+ if (jsreportServer instanceof HttpsServer) {
108
+ protocol = 'https'
109
+ } else {
110
+ protocol = 'http'
111
+ }
112
+
113
+ const urlToServer = `${protocol}://${hostname}:${address.port}/${appPath}`
114
+
115
+ // starting a server in a new socket to allow the monitoring
116
+ // and query of this process from the CLI
117
+ socketServer = startSocketServer({
118
+ socketPath: sockPath,
119
+ socketPrefix: 'm',
120
+ // Create 'symbolic' file on the system, so it can be later
121
+ // found, since the `\\.pipe\\*` "files" can't
122
+ // be enumerated because ... Windows.
123
+ createSymbolicForSocket: process.platform === 'win32',
124
+ protocol: monitorProtocol
125
+ }, (socketInitErr, serverInfo) => {
126
+ if (socketInitErr) {
127
+ return socketToMaster.send(['init'], {
128
+ error: socketInitErr.message,
129
+ stacks: getErrors(socketInitErr).map(e => e.stack)
130
+ })
131
+ }
132
+
133
+ // collecting all the information about this process
134
+ // for later queries
135
+ processInfo = {
136
+ uid: serverInfo.uid,
137
+ pid: PID,
138
+ cwd: cwd,
139
+ version: instance.version,
140
+ socketFile: serverInfo.socketFile,
141
+ normalizedSocketFile: serverInfo.normalizedSocketFile,
142
+ url: urlToServer,
143
+ adminAuthentication: adminAuthentication
144
+ }
145
+
146
+ socketToMaster.send(['init'], Object.assign({}, processInfo, { error: null }))
147
+ })
148
+ })
149
+ .catch((err) => {
150
+ const meta = {}
151
+
152
+ if (err.code != null) {
153
+ meta.code = err.code
154
+ }
155
+
156
+ socketToMaster.send(['init'], {
157
+ error: err.message,
158
+ stacks: getErrors(err).map(e => e.stack),
159
+ meta: Object.keys(meta).length > 0 ? meta : undefined
160
+ })
161
+
162
+ setImmediate(() => {
163
+ process.exit(1)
164
+ })
165
+ })
166
+ })
167
+
168
+ socketToMaster.send(['alive'])
169
+ })
170
+
171
+ socketToMaster.on('error', (err) => {
172
+ if (err.code === 'ECONNREFUSED') {
173
+ try {
174
+ fs.unlinkSync(parentSocketFile)
175
+ } catch (e) {}
176
+ }
177
+
178
+ process.exit(1)
179
+ })
180
+
181
+ function monitorProtocol (socket) {
182
+ socket.on('error', (err) => {
183
+ console.error('socket error:', err)
184
+ socket.destroy()
185
+ })
186
+
187
+ socket.data(['info'], () => {
188
+ socket.send(['info'], processInfo)
189
+ })
190
+
191
+ socket.data(['kill'], () => {
192
+ if (process.platform === 'win32') {
193
+ //
194
+ // On Windows, delete the 'symbolic' sock file. This
195
+ // file is used for exploration as a mapping to the
196
+ // `\\.pipe\\*` "files" that can't
197
+ // be enumerated because ... Windows.
198
+ //
199
+ try {
200
+ fs.unlinkSync(processInfo.socketFile)
201
+ } catch (e) {}
202
+ }
203
+
204
+ // close the server to prevent accepting new connections,
205
+ // such situation can happen when doing concurrent calls to kill the server
206
+ if (socketServer) {
207
+ socketServer.close()
208
+ }
209
+
210
+ const exit = () => process.exit()
211
+
212
+ if (reporterInstance) {
213
+ reporterInstance.close().then(exit, exit)
214
+ } else {
215
+ exit()
216
+ }
217
+ })
218
+ }
219
+ }
220
+
221
+ if (require.main === module) {
222
+ start()
223
+ } else {
224
+ module.exports = start
225
+ }
@@ -1,74 +1,74 @@
1
- 'use strict'
2
-
3
- const util = require('util')
4
- const path = require('path')
5
- const fs = require('fs')
6
- const { addStack } = require('./errorUtils')
7
- const accessAsync = util.promisify(fs.access)
8
-
9
- module.exports = async (extensions, commander) => {
10
- const results = []
11
-
12
- await Promise.all(extensions.map(async (ext) => {
13
- try {
14
- const extCliPath = path.join(ext.directory, 'cli/main.js')
15
- let extCliExport
16
-
17
- if (ext.cliModule === false) {
18
- return
19
- }
20
-
21
- if (ext.cliModule) {
22
- extCliExport = ext.cliModule
23
- } else {
24
- let hasCli = false
25
-
26
- try {
27
- await accessAsync(extCliPath)
28
- hasCli = true
29
- } catch (e) {}
30
-
31
- if (!hasCli) {
32
- return
33
- }
34
-
35
- extCliExport = require(extCliPath)
36
- }
37
-
38
- if (!extCliExport) {
39
- return
40
- }
41
-
42
- if (Array.isArray(extCliExport)) {
43
- results.push({
44
- extension: ext.name,
45
- cliModulePath: extCliPath,
46
- commands: extCliExport
47
- })
48
-
49
- extCliExport.forEach((commandModule) => commander.registerCommand(commandModule))
50
- } else {
51
- results.push({
52
- extension: ext.name,
53
- cliModulePath: extCliPath,
54
- commands: [extCliExport]
55
- })
56
-
57
- commander.registerCommand(extCliExport)
58
- }
59
- } catch (e) {
60
- const err = new Error(e.message)
61
-
62
- addStack(err, e.stack, {
63
- stackPrefix: 'Register Command Error stack: ',
64
- stripMessage: true
65
- })
66
-
67
- err.message = `Error while trying to register cli command in extension "${ext.name}". reason: ${err.message}`
68
-
69
- throw err
70
- }
71
- }))
72
-
73
- return results
74
- }
1
+ 'use strict'
2
+
3
+ const util = require('util')
4
+ const path = require('path')
5
+ const fs = require('fs')
6
+ const { addStack } = require('./utils/error')
7
+ const accessAsync = util.promisify(fs.access)
8
+
9
+ module.exports = async (extensions, commander) => {
10
+ const results = []
11
+
12
+ await Promise.all(extensions.map(async (ext) => {
13
+ try {
14
+ const extCliPath = path.join(ext.directory, 'cli/main.js')
15
+ let extCliExport
16
+
17
+ if (ext.cliModule === false) {
18
+ return
19
+ }
20
+
21
+ if (ext.cliModule) {
22
+ extCliExport = ext.cliModule
23
+ } else {
24
+ let hasCli = false
25
+
26
+ try {
27
+ await accessAsync(extCliPath)
28
+ hasCli = true
29
+ } catch (e) {}
30
+
31
+ if (!hasCli) {
32
+ return
33
+ }
34
+
35
+ extCliExport = require(extCliPath)
36
+ }
37
+
38
+ if (!extCliExport) {
39
+ return
40
+ }
41
+
42
+ if (Array.isArray(extCliExport)) {
43
+ results.push({
44
+ extension: ext.name,
45
+ cliModulePath: extCliPath,
46
+ commands: extCliExport
47
+ })
48
+
49
+ extCliExport.forEach((commandModule) => commander.registerCommand(commandModule))
50
+ } else {
51
+ results.push({
52
+ extension: ext.name,
53
+ cliModulePath: extCliPath,
54
+ commands: [extCliExport]
55
+ })
56
+
57
+ commander.registerCommand(extCliExport)
58
+ }
59
+ } catch (e) {
60
+ const err = new Error(e.message)
61
+
62
+ addStack(err, e.stack, {
63
+ stackPrefix: 'Register Command Error stack: ',
64
+ stripMessage: true
65
+ })
66
+
67
+ err.message = `Error while trying to register cli command in extension "${ext.name}". reason: ${err.message}`
68
+
69
+ throw err
70
+ }
71
+ }))
72
+
73
+ return results
74
+ }