@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.
- package/LICENSE +21 -21
- package/README.md +16 -12
- package/cli.js +93 -93
- package/example.config.json +43 -43
- package/example.server.js +14 -14
- package/index.js +20 -22
- package/jsreport.config.js +8 -8
- package/lib/cliExtension.js +59 -59
- package/lib/{createCommandParser.js → commander/createCommandParser.js} +44 -45
- package/lib/commander/createCustomCommandBuilder.js +150 -0
- package/lib/commander/createLogger.js +51 -0
- package/lib/commander/executeCommand.js +37 -0
- package/lib/commander/getCommandEventName.js +4 -0
- package/lib/commander/index.js +279 -0
- package/lib/commander/jsreportInstance.js +98 -0
- package/lib/commander/registerCommand.js +91 -0
- package/lib/commander/startCommand.js +234 -0
- package/lib/commander/startProcessing.js +208 -0
- package/lib/commands/_initializeApp.js +206 -208
- package/lib/commands/configure.js +393 -395
- package/lib/commands/help.js +453 -454
- package/lib/commands/init.js +76 -77
- package/lib/commands/kill.js +85 -86
- package/lib/commands/render.js +490 -488
- package/lib/commands/repair.js +55 -56
- package/lib/commands/start.js +72 -74
- package/lib/commands/win-install.js +124 -126
- package/lib/commands/win-uninstall.js +100 -102
- package/lib/daemonHandler.js +164 -164
- package/lib/daemonInstance.js +225 -225
- package/lib/{registerExtensionsCommands.js → detectAndRegisterExtensionsCommands.js} +74 -74
- package/lib/instanceHandler.js +316 -316
- package/lib/keepAliveProcess.js +205 -205
- package/lib/{errorUtils.js → utils/error.js} +149 -127
- package/lib/{getTempPaths.js → utils/getTempPaths.js} +39 -39
- package/lib/{normalizePathOptionOrArg.js → utils/normalizePathOptionOrArg.js} +41 -41
- package/lib/{normalizeSocketPath.js → utils/normalizeSocketPath.js} +9 -9
- package/lib/{startSocketServer.js → utils/startSocketServer.js} +53 -53
- package/package.json +105 -106
- package/test/testUtils.js +197 -198
- package/lib/commander.js +0 -1108
package/lib/commands/render.js
CHANGED
|
@@ -1,488 +1,490 @@
|
|
|
1
|
-
|
|
2
|
-
|
|
3
|
-
const
|
|
4
|
-
const
|
|
5
|
-
|
|
6
|
-
const
|
|
7
|
-
|
|
8
|
-
const
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
exports.
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
const
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
},
|
|
28
|
-
|
|
29
|
-
alias: '
|
|
30
|
-
description: 'Specifies
|
|
31
|
-
|
|
32
|
-
},
|
|
33
|
-
|
|
34
|
-
alias: '
|
|
35
|
-
description: 'Specifies a path to a json file containing options for
|
|
36
|
-
requiresArg: true
|
|
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
|
-
|
|
129
|
-
const
|
|
130
|
-
const
|
|
131
|
-
const
|
|
132
|
-
const
|
|
133
|
-
|
|
134
|
-
|
|
135
|
-
|
|
136
|
-
|
|
137
|
-
|
|
138
|
-
|
|
139
|
-
|
|
140
|
-
|
|
141
|
-
|
|
142
|
-
|
|
143
|
-
|
|
144
|
-
|
|
145
|
-
|
|
146
|
-
|
|
147
|
-
|
|
148
|
-
|
|
149
|
-
return
|
|
150
|
-
}
|
|
151
|
-
|
|
152
|
-
|
|
153
|
-
|
|
154
|
-
|
|
155
|
-
const
|
|
156
|
-
const
|
|
157
|
-
const
|
|
158
|
-
const
|
|
159
|
-
const
|
|
160
|
-
const
|
|
161
|
-
const
|
|
162
|
-
|
|
163
|
-
|
|
164
|
-
|
|
165
|
-
|
|
166
|
-
|
|
167
|
-
|
|
168
|
-
|
|
169
|
-
|
|
170
|
-
|
|
171
|
-
|
|
172
|
-
|
|
173
|
-
|
|
174
|
-
|
|
175
|
-
|
|
176
|
-
}
|
|
177
|
-
|
|
178
|
-
|
|
179
|
-
|
|
180
|
-
if
|
|
181
|
-
|
|
182
|
-
|
|
183
|
-
|
|
184
|
-
|
|
185
|
-
|
|
186
|
-
|
|
187
|
-
|
|
188
|
-
|
|
189
|
-
|
|
190
|
-
|
|
191
|
-
|
|
192
|
-
|
|
193
|
-
|
|
194
|
-
|
|
195
|
-
|
|
196
|
-
|
|
197
|
-
|
|
198
|
-
|
|
199
|
-
|
|
200
|
-
|
|
201
|
-
return
|
|
202
|
-
}
|
|
203
|
-
|
|
204
|
-
|
|
205
|
-
|
|
206
|
-
|
|
207
|
-
|
|
208
|
-
|
|
209
|
-
|
|
210
|
-
|
|
211
|
-
|
|
212
|
-
|
|
213
|
-
|
|
214
|
-
|
|
215
|
-
|
|
216
|
-
|
|
217
|
-
|
|
218
|
-
|
|
219
|
-
|
|
220
|
-
|
|
221
|
-
|
|
222
|
-
|
|
223
|
-
|
|
224
|
-
|
|
225
|
-
|
|
226
|
-
|
|
227
|
-
|
|
228
|
-
|
|
229
|
-
|
|
230
|
-
|
|
231
|
-
|
|
232
|
-
|
|
233
|
-
|
|
234
|
-
|
|
235
|
-
|
|
236
|
-
|
|
237
|
-
|
|
238
|
-
|
|
239
|
-
|
|
240
|
-
|
|
241
|
-
|
|
242
|
-
|
|
243
|
-
|
|
244
|
-
|
|
245
|
-
|
|
246
|
-
|
|
247
|
-
|
|
248
|
-
|
|
249
|
-
|
|
250
|
-
|
|
251
|
-
|
|
252
|
-
|
|
253
|
-
|
|
254
|
-
|
|
255
|
-
|
|
256
|
-
|
|
257
|
-
|
|
258
|
-
|
|
259
|
-
|
|
260
|
-
|
|
261
|
-
|
|
262
|
-
|
|
263
|
-
|
|
264
|
-
|
|
265
|
-
|
|
266
|
-
|
|
267
|
-
|
|
268
|
-
|
|
269
|
-
|
|
270
|
-
jsreportInstance = _instance
|
|
271
|
-
}
|
|
272
|
-
|
|
273
|
-
|
|
274
|
-
|
|
275
|
-
jsreportInstance.options
|
|
276
|
-
|
|
277
|
-
|
|
278
|
-
{
|
|
279
|
-
|
|
280
|
-
|
|
281
|
-
|
|
282
|
-
|
|
283
|
-
|
|
284
|
-
|
|
285
|
-
logger.
|
|
286
|
-
|
|
287
|
-
|
|
288
|
-
|
|
289
|
-
|
|
290
|
-
|
|
291
|
-
|
|
292
|
-
|
|
293
|
-
|
|
294
|
-
|
|
295
|
-
|
|
296
|
-
|
|
297
|
-
|
|
298
|
-
|
|
299
|
-
}
|
|
300
|
-
|
|
301
|
-
|
|
302
|
-
|
|
303
|
-
|
|
304
|
-
|
|
305
|
-
|
|
306
|
-
|
|
307
|
-
|
|
308
|
-
|
|
309
|
-
|
|
310
|
-
|
|
311
|
-
|
|
312
|
-
|
|
313
|
-
|
|
314
|
-
|
|
315
|
-
|
|
316
|
-
|
|
317
|
-
|
|
318
|
-
|
|
319
|
-
|
|
320
|
-
|
|
321
|
-
|
|
322
|
-
|
|
323
|
-
|
|
324
|
-
|
|
325
|
-
|
|
326
|
-
|
|
327
|
-
|
|
328
|
-
|
|
329
|
-
|
|
330
|
-
|
|
331
|
-
|
|
332
|
-
|
|
333
|
-
|
|
334
|
-
|
|
335
|
-
|
|
336
|
-
|
|
337
|
-
|
|
338
|
-
|
|
339
|
-
|
|
340
|
-
|
|
341
|
-
|
|
342
|
-
|
|
343
|
-
|
|
344
|
-
|
|
345
|
-
|
|
346
|
-
|
|
347
|
-
|
|
348
|
-
|
|
349
|
-
|
|
350
|
-
|
|
351
|
-
|
|
352
|
-
|
|
353
|
-
|
|
354
|
-
|
|
355
|
-
|
|
356
|
-
|
|
357
|
-
|
|
358
|
-
|
|
359
|
-
|
|
360
|
-
|
|
361
|
-
}
|
|
362
|
-
|
|
363
|
-
|
|
364
|
-
|
|
365
|
-
|
|
366
|
-
|
|
367
|
-
|
|
368
|
-
|
|
369
|
-
|
|
370
|
-
|
|
371
|
-
|
|
372
|
-
|
|
373
|
-
|
|
374
|
-
|
|
375
|
-
|
|
376
|
-
|
|
377
|
-
|
|
378
|
-
|
|
379
|
-
|
|
380
|
-
|
|
381
|
-
|
|
382
|
-
|
|
383
|
-
|
|
384
|
-
|
|
385
|
-
|
|
386
|
-
|
|
387
|
-
|
|
388
|
-
}
|
|
389
|
-
|
|
390
|
-
|
|
391
|
-
|
|
392
|
-
|
|
393
|
-
|
|
394
|
-
|
|
395
|
-
|
|
396
|
-
|
|
397
|
-
|
|
398
|
-
p =
|
|
399
|
-
|
|
400
|
-
|
|
401
|
-
|
|
402
|
-
|
|
403
|
-
|
|
404
|
-
|
|
405
|
-
|
|
406
|
-
|
|
407
|
-
|
|
408
|
-
|
|
409
|
-
|
|
410
|
-
|
|
411
|
-
|
|
412
|
-
|
|
413
|
-
|
|
414
|
-
|
|
415
|
-
|
|
416
|
-
|
|
417
|
-
|
|
418
|
-
|
|
419
|
-
|
|
420
|
-
|
|
421
|
-
|
|
422
|
-
|
|
423
|
-
|
|
424
|
-
|
|
425
|
-
|
|
426
|
-
|
|
427
|
-
|
|
428
|
-
|
|
429
|
-
|
|
430
|
-
|
|
431
|
-
|
|
432
|
-
|
|
433
|
-
|
|
434
|
-
|
|
435
|
-
|
|
436
|
-
|
|
437
|
-
|
|
438
|
-
|
|
439
|
-
|
|
440
|
-
|
|
441
|
-
|
|
442
|
-
|
|
443
|
-
|
|
444
|
-
|
|
445
|
-
|
|
446
|
-
|
|
447
|
-
|
|
448
|
-
|
|
449
|
-
|
|
450
|
-
|
|
451
|
-
|
|
452
|
-
|
|
453
|
-
|
|
454
|
-
|
|
455
|
-
|
|
456
|
-
|
|
457
|
-
|
|
458
|
-
|
|
459
|
-
|
|
460
|
-
|
|
461
|
-
|
|
462
|
-
|
|
463
|
-
|
|
464
|
-
|
|
465
|
-
|
|
466
|
-
|
|
467
|
-
|
|
468
|
-
|
|
469
|
-
|
|
470
|
-
|
|
471
|
-
|
|
472
|
-
|
|
473
|
-
|
|
474
|
-
|
|
475
|
-
|
|
476
|
-
|
|
477
|
-
`${command} --template <file> --out <file
|
|
478
|
-
|
|
479
|
-
}
|
|
480
|
-
|
|
481
|
-
|
|
482
|
-
|
|
483
|
-
|
|
484
|
-
|
|
485
|
-
[`${command} --
|
|
486
|
-
[`${command} --template template.json --
|
|
487
|
-
|
|
488
|
-
}
|
|
1
|
+
const util = require('util')
|
|
2
|
+
const fs = require('fs')
|
|
3
|
+
const jsreportClient = require('@jsreport/nodejs-client')
|
|
4
|
+
const normalizePathOptionOrArg = require('../utils/normalizePathOptionOrArg')
|
|
5
|
+
|
|
6
|
+
const writeFileAsync = util.promisify(fs.writeFile)
|
|
7
|
+
|
|
8
|
+
const description = 'Invoke a rendering process'
|
|
9
|
+
const command = 'render'
|
|
10
|
+
|
|
11
|
+
exports.command = command
|
|
12
|
+
exports.description = description
|
|
13
|
+
|
|
14
|
+
exports.builder = (yargs) => {
|
|
15
|
+
const cwd = process.cwd()
|
|
16
|
+
|
|
17
|
+
const commandOptions = {
|
|
18
|
+
request: {
|
|
19
|
+
alias: 'r',
|
|
20
|
+
description: 'Specifies a path to a json file containing option for the entire rendering request',
|
|
21
|
+
requiresArg: true
|
|
22
|
+
},
|
|
23
|
+
keepAlive: {
|
|
24
|
+
alias: 'k',
|
|
25
|
+
description: 'Specifies that the process should stay open (handled by the maintainer) for future renders',
|
|
26
|
+
type: 'boolean'
|
|
27
|
+
},
|
|
28
|
+
template: {
|
|
29
|
+
alias: 't',
|
|
30
|
+
description: 'Specifies a path to a json file containing options for template input or you can specify singular options doing --template.[option_name] value',
|
|
31
|
+
requiresArg: true
|
|
32
|
+
},
|
|
33
|
+
data: {
|
|
34
|
+
alias: 'd',
|
|
35
|
+
description: 'Specifies a path to a json file containing options for data input',
|
|
36
|
+
requiresArg: true
|
|
37
|
+
},
|
|
38
|
+
out: {
|
|
39
|
+
alias: 'o',
|
|
40
|
+
description: 'Save rendering result into a file path',
|
|
41
|
+
type: 'string',
|
|
42
|
+
demandOption: true,
|
|
43
|
+
requiresArg: true
|
|
44
|
+
},
|
|
45
|
+
meta: {
|
|
46
|
+
alias: 'm',
|
|
47
|
+
description: 'Save response meta information into a file path',
|
|
48
|
+
type: 'string',
|
|
49
|
+
demandOption: false,
|
|
50
|
+
requiresArg: true
|
|
51
|
+
}
|
|
52
|
+
}
|
|
53
|
+
|
|
54
|
+
const options = Object.keys(commandOptions)
|
|
55
|
+
|
|
56
|
+
const examples = getExamples('jsreport ' + command)
|
|
57
|
+
|
|
58
|
+
examples.forEach((examp) => {
|
|
59
|
+
yargs.example(examp[0], examp[1])
|
|
60
|
+
})
|
|
61
|
+
|
|
62
|
+
return (
|
|
63
|
+
yargs
|
|
64
|
+
.usage(`${description}\n\n${getUsage('jsreport ' + command)}`)
|
|
65
|
+
.group(options, 'Command options:')
|
|
66
|
+
.options(commandOptions)
|
|
67
|
+
.middleware((argv) => {
|
|
68
|
+
if (argv.request != null) {
|
|
69
|
+
argv.request = normalizePathOptionOrArg(cwd, 'request', argv.request, { json: true, strict: true })
|
|
70
|
+
}
|
|
71
|
+
|
|
72
|
+
if (argv.template != null) {
|
|
73
|
+
if (typeof argv.template !== 'string') {
|
|
74
|
+
if (argv.template.content != null) {
|
|
75
|
+
argv.template.content = normalizePathOptionOrArg(cwd, 'template.content', argv.template.content, { strict: true })
|
|
76
|
+
}
|
|
77
|
+
|
|
78
|
+
if (argv.template.helpers != null) {
|
|
79
|
+
argv.template.helpers = normalizePathOptionOrArg(cwd, 'template.helpers', argv.template.helpers, { strict: true })
|
|
80
|
+
}
|
|
81
|
+
} else {
|
|
82
|
+
argv.template = normalizePathOptionOrArg(cwd, 'template', argv.template, { json: true, strict: true })
|
|
83
|
+
}
|
|
84
|
+
}
|
|
85
|
+
|
|
86
|
+
if (argv.data != null) {
|
|
87
|
+
argv.data = normalizePathOptionOrArg(cwd, 'data', argv.data, { json: true, strict: false })
|
|
88
|
+
}
|
|
89
|
+
|
|
90
|
+
if (argv.out != null) {
|
|
91
|
+
argv.out = normalizePathOptionOrArg(cwd, 'out', argv.out, { read: false, strict: true })
|
|
92
|
+
}
|
|
93
|
+
|
|
94
|
+
if (argv.meta != null) {
|
|
95
|
+
argv.meta = normalizePathOptionOrArg(cwd, 'meta', argv.meta, { read: false, strict: true })
|
|
96
|
+
}
|
|
97
|
+
}, true)
|
|
98
|
+
.check((argv, hash) => {
|
|
99
|
+
if (argv.user && !argv.serverUrl) {
|
|
100
|
+
throw new Error('user option needs to be used with --serverUrl option')
|
|
101
|
+
}
|
|
102
|
+
|
|
103
|
+
if (argv.password && !argv.serverUrl) {
|
|
104
|
+
throw new Error('password option needs to be used with --serverUrl option')
|
|
105
|
+
}
|
|
106
|
+
|
|
107
|
+
if (argv.user && !argv.password) {
|
|
108
|
+
throw new Error('user option needs to be used with --password option')
|
|
109
|
+
}
|
|
110
|
+
|
|
111
|
+
if (argv.password && !argv.user) {
|
|
112
|
+
throw new Error('password option needs to be used with --user option')
|
|
113
|
+
}
|
|
114
|
+
|
|
115
|
+
if (!argv.request && !argv.template) {
|
|
116
|
+
throw new Error('render command need at least --request or --template option')
|
|
117
|
+
}
|
|
118
|
+
|
|
119
|
+
return true
|
|
120
|
+
})
|
|
121
|
+
)
|
|
122
|
+
}
|
|
123
|
+
|
|
124
|
+
exports.configuration = {
|
|
125
|
+
globalOptions: ['serverUrl', 'user', 'password']
|
|
126
|
+
}
|
|
127
|
+
|
|
128
|
+
exports.handler = async (argv) => {
|
|
129
|
+
const output = argv.out
|
|
130
|
+
const meta = argv.meta
|
|
131
|
+
const context = argv.context
|
|
132
|
+
const logger = context.logger
|
|
133
|
+
const verbose = argv.verbose
|
|
134
|
+
const options = getOptions(argv)
|
|
135
|
+
|
|
136
|
+
// connect to a remote server
|
|
137
|
+
if (argv.serverUrl) {
|
|
138
|
+
logger.info('starting rendering process in ' + argv.serverUrl + '..')
|
|
139
|
+
|
|
140
|
+
try {
|
|
141
|
+
const result = await startRender(null, {
|
|
142
|
+
logger: logger,
|
|
143
|
+
request: options.render,
|
|
144
|
+
meta: meta,
|
|
145
|
+
output: output,
|
|
146
|
+
remote: options.remote
|
|
147
|
+
})
|
|
148
|
+
result.fromRemote = true
|
|
149
|
+
return result
|
|
150
|
+
} catch (e) {
|
|
151
|
+
return onCriticalError(e)
|
|
152
|
+
}
|
|
153
|
+
}
|
|
154
|
+
|
|
155
|
+
const cwd = context.cwd
|
|
156
|
+
const sockPath = context.sockPath
|
|
157
|
+
const workerSockPath = context.workerSockPath
|
|
158
|
+
const getInstance = context.getInstance
|
|
159
|
+
const initInstance = context.initInstance
|
|
160
|
+
const daemonExec = context.daemonExec
|
|
161
|
+
const daemonHandler = context.daemonHandler
|
|
162
|
+
const keepAliveProcess = context.keepAliveProcess
|
|
163
|
+
const findProcessByCWD = daemonHandler.findProcessByCWD
|
|
164
|
+
|
|
165
|
+
// start a new daemonized process and then connect to it
|
|
166
|
+
// to render
|
|
167
|
+
if (argv.keepAlive) {
|
|
168
|
+
logger.debug('looking for previously daemonized instance in:', workerSockPath, 'cwd:', cwd)
|
|
169
|
+
|
|
170
|
+
// first, try to look up if there is an existing process
|
|
171
|
+
// "daemonized" before in the CWD
|
|
172
|
+
let processInfo
|
|
173
|
+
|
|
174
|
+
try {
|
|
175
|
+
processInfo = await findProcessByCWD(workerSockPath, cwd)
|
|
176
|
+
} catch (processLookupErr) {
|
|
177
|
+
return onCriticalError(processLookupErr)
|
|
178
|
+
}
|
|
179
|
+
|
|
180
|
+
// if process was found, just connect to it,
|
|
181
|
+
// otherwise just continue processing
|
|
182
|
+
if (processInfo) {
|
|
183
|
+
logger.debug('using instance daemonized previously (pid: ' + processInfo.pid + ')..')
|
|
184
|
+
|
|
185
|
+
const adminAuthentication = processInfo.adminAuthentication || {}
|
|
186
|
+
|
|
187
|
+
try {
|
|
188
|
+
const result = await startRender(null, {
|
|
189
|
+
logger: logger,
|
|
190
|
+
request: options.render,
|
|
191
|
+
output: output,
|
|
192
|
+
meta: meta,
|
|
193
|
+
remote: {
|
|
194
|
+
url: processInfo.url,
|
|
195
|
+
user: adminAuthentication.username,
|
|
196
|
+
password: adminAuthentication.password
|
|
197
|
+
}
|
|
198
|
+
})
|
|
199
|
+
|
|
200
|
+
result.fromDaemon = true
|
|
201
|
+
return result
|
|
202
|
+
} catch (e) {
|
|
203
|
+
return onCriticalError(e)
|
|
204
|
+
}
|
|
205
|
+
}
|
|
206
|
+
|
|
207
|
+
logger.debug('there is no previously daemonized instance in:', workerSockPath, 'cwd:', cwd)
|
|
208
|
+
|
|
209
|
+
let childProc
|
|
210
|
+
|
|
211
|
+
try {
|
|
212
|
+
// we try to start the daemon process
|
|
213
|
+
processInfo = await keepAliveProcess({
|
|
214
|
+
daemonExec: daemonExec,
|
|
215
|
+
mainSockPath: sockPath,
|
|
216
|
+
workerSockPath: workerSockPath,
|
|
217
|
+
cwd: cwd,
|
|
218
|
+
verbose: verbose
|
|
219
|
+
})
|
|
220
|
+
|
|
221
|
+
const remoteUrl = processInfo.url
|
|
222
|
+
const adminAuthentication = processInfo.adminAuthentication || {}
|
|
223
|
+
|
|
224
|
+
childProc = processInfo.proc
|
|
225
|
+
|
|
226
|
+
logger.info(`instance has been daemonized and initialized successfully${childProc == null ? '*' : ''} (pid: ${processInfo.pid})`)
|
|
227
|
+
|
|
228
|
+
const result = await startRender(null, {
|
|
229
|
+
logger: logger,
|
|
230
|
+
request: options.render,
|
|
231
|
+
output: output,
|
|
232
|
+
meta: meta,
|
|
233
|
+
remote: {
|
|
234
|
+
url: remoteUrl,
|
|
235
|
+
user: adminAuthentication.username,
|
|
236
|
+
password: adminAuthentication.password
|
|
237
|
+
}
|
|
238
|
+
})
|
|
239
|
+
|
|
240
|
+
// make sure to unref() the child process after the first render
|
|
241
|
+
// to allow the exit of the current process
|
|
242
|
+
if (childProc) {
|
|
243
|
+
childProc.unref()
|
|
244
|
+
}
|
|
245
|
+
|
|
246
|
+
if (childProc) {
|
|
247
|
+
result.daemonProcess = processInfo
|
|
248
|
+
}
|
|
249
|
+
|
|
250
|
+
result.fromDaemon = true
|
|
251
|
+
|
|
252
|
+
return result
|
|
253
|
+
} catch (err) {
|
|
254
|
+
if (childProc) {
|
|
255
|
+
childProc.unref()
|
|
256
|
+
}
|
|
257
|
+
|
|
258
|
+
return onCriticalError(err)
|
|
259
|
+
}
|
|
260
|
+
}
|
|
261
|
+
|
|
262
|
+
try {
|
|
263
|
+
// look up for an instance in CWD
|
|
264
|
+
const _instance = await getInstance(cwd)
|
|
265
|
+
let jsreportInstance
|
|
266
|
+
|
|
267
|
+
logger.debug('disabling express extension..')
|
|
268
|
+
|
|
269
|
+
if (typeof _instance === 'function') {
|
|
270
|
+
jsreportInstance = _instance()
|
|
271
|
+
} else {
|
|
272
|
+
jsreportInstance = _instance
|
|
273
|
+
}
|
|
274
|
+
|
|
275
|
+
jsreportInstance.options = jsreportInstance.options || {}
|
|
276
|
+
jsreportInstance.options.extensions = jsreportInstance.options.extensions || {}
|
|
277
|
+
jsreportInstance.options.extensions.express = Object.assign(
|
|
278
|
+
{},
|
|
279
|
+
jsreportInstance.options.extensions.express,
|
|
280
|
+
{ enabled: false }
|
|
281
|
+
)
|
|
282
|
+
|
|
283
|
+
await initInstance(jsreportInstance)
|
|
284
|
+
|
|
285
|
+
logger.info('starting rendering process..')
|
|
286
|
+
|
|
287
|
+
logger.debug('Output configured to:', output)
|
|
288
|
+
|
|
289
|
+
if (meta) {
|
|
290
|
+
logger.debug('Meta configured to:', meta)
|
|
291
|
+
}
|
|
292
|
+
|
|
293
|
+
return (await startRender(jsreportInstance, {
|
|
294
|
+
logger: logger,
|
|
295
|
+
request: options.render,
|
|
296
|
+
output: output,
|
|
297
|
+
meta: meta
|
|
298
|
+
}))
|
|
299
|
+
} catch (e) {
|
|
300
|
+
return onCriticalError(e)
|
|
301
|
+
}
|
|
302
|
+
|
|
303
|
+
function onCriticalError (err) {
|
|
304
|
+
const error = new Error(`A critical error occurred while trying to execute the ${command} command`)
|
|
305
|
+
error.originalError = err
|
|
306
|
+
throw error
|
|
307
|
+
}
|
|
308
|
+
}
|
|
309
|
+
|
|
310
|
+
async function startRender (jsreportInstance, { remote, request, output, meta, logger }) {
|
|
311
|
+
if (remote) {
|
|
312
|
+
logger.debug('remote server options:')
|
|
313
|
+
logger.debug(JSON.stringify(remote, null, 2))
|
|
314
|
+
}
|
|
315
|
+
|
|
316
|
+
logger.debug('rendering with options:')
|
|
317
|
+
logger.debug(JSON.stringify(request, null, 2))
|
|
318
|
+
|
|
319
|
+
if (remote) {
|
|
320
|
+
try {
|
|
321
|
+
const response = await jsreportClient(remote.url, remote.user, remote.password).render(request)
|
|
322
|
+
return (await saveResponse(logger, response, response.headers, output, meta, remote))
|
|
323
|
+
} catch (err) {
|
|
324
|
+
let customError
|
|
325
|
+
|
|
326
|
+
if (err.remoteStack) {
|
|
327
|
+
// delete extra noise in the error message (the remoteStack is already on err.stack)
|
|
328
|
+
delete err.remoteStack
|
|
329
|
+
}
|
|
330
|
+
|
|
331
|
+
if (err.code === 'ECONNREFUSED') {
|
|
332
|
+
customError = new Error(`Couldn't connect to remote jsreport server in: ${
|
|
333
|
+
remote.url
|
|
334
|
+
} , Please verify that a jsreport server is running`)
|
|
335
|
+
}
|
|
336
|
+
|
|
337
|
+
if (!customError && err.response && err.response.statusCode != null) {
|
|
338
|
+
if (err.response.statusCode === 404) {
|
|
339
|
+
customError = new Error(`Couldn't connect to remote jsreport server in: ${
|
|
340
|
+
remote.url
|
|
341
|
+
} , Please verify that a jsreport server is running`)
|
|
342
|
+
} else if (err.response.statusCode === 401) {
|
|
343
|
+
customError = new Error(`Couldn't connect to remote jsreport server in: ${
|
|
344
|
+
remote.url
|
|
345
|
+
} , Authentication error, Please pass correct --user and --password options`)
|
|
346
|
+
}
|
|
347
|
+
}
|
|
348
|
+
|
|
349
|
+
if (customError) {
|
|
350
|
+
customError.originalError = err
|
|
351
|
+
throw onRenderingError(customError, logger)
|
|
352
|
+
}
|
|
353
|
+
|
|
354
|
+
throw onRenderingError(err, logger)
|
|
355
|
+
}
|
|
356
|
+
}
|
|
357
|
+
|
|
358
|
+
try {
|
|
359
|
+
const out = await jsreportInstance.render(request)
|
|
360
|
+
return (await saveResponse(logger, out.stream, out.meta, output, meta))
|
|
361
|
+
} catch (err) {
|
|
362
|
+
throw onRenderingError(err, logger)
|
|
363
|
+
}
|
|
364
|
+
}
|
|
365
|
+
|
|
366
|
+
async function saveResponse (logger, stream, metaData, output, meta, remote) {
|
|
367
|
+
const outputStream = writeFileFromStream(stream, output)
|
|
368
|
+
|
|
369
|
+
// eslint-disable-next-line no-async-promise-executor
|
|
370
|
+
return new Promise(async (resolve, reject) => {
|
|
371
|
+
listenOutputStream(outputStream, logger, () => {
|
|
372
|
+
if (!meta) {
|
|
373
|
+
return resolve({
|
|
374
|
+
output: output
|
|
375
|
+
})
|
|
376
|
+
}
|
|
377
|
+
|
|
378
|
+
const responseMeta = JSON.stringify(remote ? responseHeadersToMetaPOCO(metaData) : metaData)
|
|
379
|
+
|
|
380
|
+
logger.debug('saving response meta: ' + responseMeta)
|
|
381
|
+
|
|
382
|
+
writeFileAsync(meta, responseMeta, 'utf8').then(() => {
|
|
383
|
+
resolve({
|
|
384
|
+
output: output,
|
|
385
|
+
meta: meta
|
|
386
|
+
})
|
|
387
|
+
}).catch(reject)
|
|
388
|
+
}, reject)
|
|
389
|
+
})
|
|
390
|
+
}
|
|
391
|
+
|
|
392
|
+
function responseHeadersToMetaPOCO (headers) {
|
|
393
|
+
const meta = {}
|
|
394
|
+
|
|
395
|
+
for (const property in headers) {
|
|
396
|
+
if (Object.prototype.hasOwnProperty.call(headers, property)) {
|
|
397
|
+
const val = headers[property]
|
|
398
|
+
let p = property.replace(/-.{1}/g, (s) => s[1].toUpperCase())
|
|
399
|
+
|
|
400
|
+
p = p[0].toLowerCase() + p.substring(1)
|
|
401
|
+
meta[p] = val
|
|
402
|
+
}
|
|
403
|
+
}
|
|
404
|
+
|
|
405
|
+
return meta
|
|
406
|
+
}
|
|
407
|
+
|
|
408
|
+
function listenOutputStream (outputStream, logger, onFinish, onError) {
|
|
409
|
+
let writeFinished = false
|
|
410
|
+
let error = false
|
|
411
|
+
|
|
412
|
+
outputStream.on('finish', () => {
|
|
413
|
+
writeFinished = true
|
|
414
|
+
})
|
|
415
|
+
|
|
416
|
+
outputStream.on('close', () => {
|
|
417
|
+
if (writeFinished && !error) {
|
|
418
|
+
logger.info('rendering has finished successfully and saved in:', outputStream.path)
|
|
419
|
+
onFinish()
|
|
420
|
+
}
|
|
421
|
+
})
|
|
422
|
+
|
|
423
|
+
outputStream.on('error', (err) => {
|
|
424
|
+
error = true
|
|
425
|
+
onError(onRenderingError(err, logger))
|
|
426
|
+
})
|
|
427
|
+
}
|
|
428
|
+
|
|
429
|
+
function writeFileFromStream (stream, output) {
|
|
430
|
+
const outputStream = fs.createWriteStream(output)
|
|
431
|
+
|
|
432
|
+
stream.pipe(outputStream)
|
|
433
|
+
|
|
434
|
+
return outputStream
|
|
435
|
+
}
|
|
436
|
+
|
|
437
|
+
function onRenderingError (error, logger) {
|
|
438
|
+
logger.error('rendering has finished with errors:')
|
|
439
|
+
return error
|
|
440
|
+
}
|
|
441
|
+
|
|
442
|
+
function getOptions (argv) {
|
|
443
|
+
const renderingOpts = argv.request || {}
|
|
444
|
+
let remote = null
|
|
445
|
+
|
|
446
|
+
if (argv.serverUrl) {
|
|
447
|
+
remote = {
|
|
448
|
+
url: argv.serverUrl
|
|
449
|
+
}
|
|
450
|
+
}
|
|
451
|
+
|
|
452
|
+
if (argv.user && argv.serverUrl) {
|
|
453
|
+
remote.user = argv.user
|
|
454
|
+
}
|
|
455
|
+
|
|
456
|
+
if (argv.password && argv.serverUrl) {
|
|
457
|
+
remote.password = argv.password
|
|
458
|
+
}
|
|
459
|
+
|
|
460
|
+
if (argv.template) {
|
|
461
|
+
renderingOpts.template = Object.assign({}, renderingOpts.template, argv.template)
|
|
462
|
+
}
|
|
463
|
+
|
|
464
|
+
if (argv.data) {
|
|
465
|
+
renderingOpts.data = Object.assign({}, renderingOpts.data, argv.data)
|
|
466
|
+
}
|
|
467
|
+
|
|
468
|
+
return {
|
|
469
|
+
render: renderingOpts,
|
|
470
|
+
remote: remote
|
|
471
|
+
}
|
|
472
|
+
}
|
|
473
|
+
|
|
474
|
+
function getUsage (command) {
|
|
475
|
+
return [
|
|
476
|
+
`Usage:\n\n${command} --request <file> --out <file>`,
|
|
477
|
+
`${command} --template <file> --out <file>`,
|
|
478
|
+
`${command} --template <file> --data <file> --out <file>`,
|
|
479
|
+
`${command} --template <file> --out <file> --meta <file>`
|
|
480
|
+
].join('\n')
|
|
481
|
+
}
|
|
482
|
+
|
|
483
|
+
function getExamples (command) {
|
|
484
|
+
return [
|
|
485
|
+
[`${command} --request request.json --out output.pdf`, 'Start rendering with options in request.json'],
|
|
486
|
+
[`${command} --template template.json --out output.pdf`, 'Start rendering with options for template input in template.json'],
|
|
487
|
+
[`${command} --template.recipe phantom-pdf --template.engine handlebars --template.content template.html --out output.pdf`, 'Start rendering with inline options for template input'],
|
|
488
|
+
[`${command} --template template.json --data data.json --out output.pdf`, 'Start rendering with options for template and data input']
|
|
489
|
+
]
|
|
490
|
+
}
|