Skip to content

Commit 65deae7

Browse files
authored
Merge pull request #10 from plotly/improve-runner-app
Improve runner app
2 parents fc0c4f7 + c8d5483 commit 65deae7

File tree

8 files changed

+121
-58
lines changed

8 files changed

+121
-58
lines changed

bin/plotly-graph-exporter_electron.js

Lines changed: 15 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -29,13 +29,26 @@ if (!fs.existsSync(argv.outputDir)) {
2929

3030
getStdin().then((txt) => {
3131
const hasStdin = !!txt
32-
const pipeToStdOut = hasStdin && !argv.output && !argv.outputDir
32+
const pipeToStdOut = hasStdin && !argv.output
3333
const showLogs = !pipeToStdOut && (DEBUG || argv.verbose)
3434
const input = hasStdin ? argv._.concat([txt]) : argv._
3535
const getItemName = makeGetItemName(input)
3636

37+
const write = (info, _, done) => {
38+
const itemName = getItemName(info)
39+
const outPath = path.resolve(argv.outputDir, `${itemName}.${info.format}`)
40+
41+
if (pipeToStdOut) {
42+
str(info.body)
43+
.pipe(process.stdout.on('drain', done))
44+
} else {
45+
fs.writeFile(outPath, info.body, done)
46+
}
47+
}
48+
3749
const app = plotlyExporter.run({
3850
input: input,
51+
write: write,
3952
debug: DEBUG,
4053
parallelLimit: argv.parallelLimit,
4154
component: {
@@ -56,19 +69,10 @@ getStdin().then((txt) => {
5669

5770
app.on('after-export', (info) => {
5871
const itemName = getItemName(info)
59-
const outPath = path.resolve(argv.outputDir, `${itemName}.${info.format}`)
6072

6173
if (showLogs) {
6274
console.log(`exported ${itemName}, in ${info.processingTime} ms`)
6375
}
64-
65-
if (pipeToStdOut) {
66-
str(info.body).pipe(process.stdout)
67-
} else {
68-
fs.writeFile(outPath, info.body, (err) => {
69-
if (err) console.warn(err)
70-
})
71-
}
7276
})
7377

7478
app.on('export-error', (info) => {
@@ -90,7 +94,7 @@ getStdin().then((txt) => {
9094

9195
const msg = `\ndone with code ${info.code} in ${timeStr} - ${info.msg}`
9296

93-
if (info.code === 200) {
97+
if (info.code === 0) {
9498
if (showLogs) {
9599
console.log(msg)
96100
}

src/app/runner/coerce-opts.js

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -51,6 +51,10 @@ function coerceOpts (_opts = {}) {
5151
throw new Error('no valid input given')
5252
}
5353

54+
opts.write = typeof _opts.write === 'function'
55+
? _opts.write
56+
: false
57+
5458
opts.input = input
5559

5660
return opts

src/app/runner/constants.js

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,8 +1,9 @@
11
module.exports = {
22
statusMsg: {
3-
200: 'all task(s) completed',
3+
0: 'all task(s) completed',
4+
1: 'failed or incomplete task(s)',
45
422: 'json parse error',
5-
500: 'incomplete task(s)'
6+
501: 'failed export'
67
},
78
dflt: {
89
parallelLimit: 4

src/app/runner/get-body.js

Lines changed: 35 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,6 @@
11
const fs = require('fs')
22
const isUrl = require('is-url')
3+
const isPlainObj = require('is-plain-obj')
34
const request = require('request')
45

56
/**
@@ -9,19 +10,44 @@ const request = require('request')
910
* - body
1011
*/
1112
function getBody (item, cb) {
12-
if (fs.existsSync(item)) {
13-
fs.readFile(item, 'utf-8', cb)
14-
} else if (fs.existsSync(item + '.json')) {
15-
fs.readFile(item + '.json', 'utf-8', cb)
16-
} else if (isUrl(item)) {
17-
request.get(item, (err, res, body) => {
13+
let p
14+
let done
15+
16+
// if item is object and has 'figure' key,
17+
// only parse its 'figure' value and accumulate it with item
18+
// to form body object
19+
if (isPlainObj(item) && item.figure) {
20+
p = item.figure
21+
done = (err, _figure) => {
22+
let figure
23+
24+
try {
25+
figure = JSON.parse(_figure)
26+
} catch (e) {
27+
return cb(e)
28+
}
29+
30+
const body = Object.assign({}, item, {figure: figure})
31+
cb(err, body)
32+
}
33+
} else {
34+
p = item
35+
done = cb
36+
}
37+
38+
if (fs.existsSync(p)) {
39+
fs.readFile(p, 'utf-8', done)
40+
} else if (fs.existsSync(p + '.json')) {
41+
fs.readFile(p + '.json', 'utf-8', done)
42+
} else if (isUrl(p)) {
43+
request.get(p, (err, res, body) => {
1844
if (err) {
19-
return cb(err)
45+
return done(err)
2046
}
21-
cb(null, body)
47+
done(null, body)
2248
})
2349
} else {
24-
cb(null, item)
50+
done(null, item)
2551
}
2652
}
2753

src/app/runner/index.js

Lines changed: 1 addition & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -34,6 +34,7 @@ function createApp (_opts) {
3434

3535
win.on('closed', () => {
3636
win = null
37+
index.destroy()
3738
})
3839

3940
createIndex(opts.component, opts, (_index) => {
@@ -46,10 +47,6 @@ function createApp (_opts) {
4647
})
4748
})
4849

49-
process.on('exit', () => {
50-
index.destroy()
51-
})
52-
5350
return app
5451
}
5552

src/app/runner/run.js

Lines changed: 41 additions & 22 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,5 @@
11
const uuid = require('uuid/v4')
2+
const isNumeric = require('fast-isnumeric')
23
const parallelLimit = require('run-parallel-limit')
34

45
const createTimer = require('../../util/create-timer')
@@ -25,8 +26,9 @@ function run (app, win, ipcMain, opts) {
2526
const totalTimer = createTimer()
2627

2728
let pending = input.length
29+
let failed = 0
2830

29-
const tasks = input.map((item, i) => (done) => {
31+
const tasks = input.map((item, i) => (cb) => {
3032
const timer = createTimer()
3133
const id = uuid()
3234

@@ -38,23 +40,38 @@ function run (app, win, ipcMain, opts) {
3840
id: id
3941
}
4042

41-
const errorOut = (code) => {
42-
fullInfo.msg = fullInfo.msg || STATUS_MSG[code] || ''
43+
// task callback wrapper:
44+
// - emits 'export-error' if given error code or error obj/msg
45+
// - emits 'after-export' if no argument is given
46+
const done = (err) => {
47+
fullInfo.pending = --pending
48+
fullInfo.processingTime = timer.end()
49+
50+
if (err) {
51+
failed++
4352

44-
app.emit('export-error', Object.assign(
45-
{code: code},
46-
fullInfo
47-
))
53+
if (isNumeric(err)) {
54+
fullInfo.code = err
55+
} else {
56+
fullInfo.code = 501
57+
fullInfo.error = err
58+
}
59+
60+
fullInfo.msg = fullInfo.msg || STATUS_MSG[fullInfo.code] || ''
61+
app.emit('export-error', fullInfo)
62+
} else {
63+
app.emit('after-export', fullInfo)
64+
}
4865

49-
return done()
66+
cb()
5067
}
5168

5269
// setup parse callback
5370
const sendToRenderer = (errorCode, parseInfo) => {
5471
Object.assign(fullInfo, parseInfo)
5572

5673
if (errorCode) {
57-
return errorOut(errorCode)
74+
return done(errorCode)
5875
}
5976

6077
win.webContents.send(comp.name, id, fullInfo, compOpts)
@@ -65,22 +82,22 @@ function run (app, win, ipcMain, opts) {
6582
Object.assign(fullInfo, convertInfo)
6683

6784
if (errorCode) {
68-
return errorOut(errorCode)
85+
return done(errorCode)
6986
}
7087

71-
fullInfo.pending = --pending
72-
fullInfo.processingTime = timer.end()
73-
74-
app.emit('after-export', fullInfo)
75-
done()
88+
if (opts.write) {
89+
opts.write(fullInfo, compOpts, done)
90+
} else {
91+
done()
92+
}
7693
}
7794

7895
// setup convert on render message -> emit 'after-export'
7996
ipcMain.once(id, (event, errorCode, renderInfo) => {
8097
Object.assign(fullInfo, renderInfo)
8198

8299
if (errorCode) {
83-
return errorOut(errorCode)
100+
return done(errorCode)
84101
}
85102

86103
comp._module.convert(fullInfo, compOpts, reply)
@@ -91,14 +108,14 @@ function run (app, win, ipcMain, opts) {
91108
let body
92109

93110
if (err) {
94-
return errorOut(422)
111+
return done(422)
95112
}
96113

97114
if (typeof _body === 'string') {
98115
try {
99116
body = JSON.parse(_body)
100117
} catch (e) {
101-
return errorOut(422)
118+
return done(422)
102119
}
103120
} else {
104121
body = _body
@@ -109,16 +126,18 @@ function run (app, win, ipcMain, opts) {
109126
})
110127

111128
parallelLimit(tasks, opts.parallelLimit, (err) => {
112-
const code = (err || pending !== 0) ? 500 : 200
129+
const exitCode = (err || pending > 0 || failed > 0) ? 1 : 0
113130

114131
app.emit('after-export-all', {
115-
code: code,
116-
msg: STATUS_MSG[code],
132+
code: exitCode,
133+
msg: STATUS_MSG[exitCode],
117134
totalProcessingTime: totalTimer.end()
118135
})
119136

120137
// do not close window to look for unlogged console errors
121-
if (!opts.debug) app.quit()
138+
if (!opts.debug) {
139+
app.exit(exitCode)
140+
}
122141
})
123142
}
124143

test/integration/plotly-graph-exporter_test.js

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -59,7 +59,7 @@ tap.test('should print export info on success', t => {
5959

6060
const matches = [
6161
/^exported fig/,
62-
/done with code 200/
62+
/done with code 0/
6363
]
6464

6565
let i = 0

0 commit comments

Comments
 (0)