-
Notifications
You must be signed in to change notification settings - Fork 1
/
process
executable file
·125 lines (112 loc) · 4.3 KB
/
process
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
#!/usr/bin/env node
'use strict';
try {
require('source-map-support').install();
} catch (err) {
if (err.code !== 'MODULE_NOT_FOUND') throw err;
}
const fs = require('fs');
const path = require('path');
const config = require('@pkmn/logs').config;
const minimist = require('minimist');
// NOTE: these aliases get added to by each of the workers
const ALIASES = {...config.ALIASES, help: ['h', '?']};
const createWorker = (name, src) => {
const code = require(src);
const options = code.options;
if (options) {
for (const option in options) {
ALIASES[option] = options[option].alias || [];
}
}
return {name, path: src, code, options};
}
// We pre-register the options for all of the default workers in workflows/
const WORKERS = fs.readdirSync(path.join(__dirname, 'workflows')).reduce((ws, dir) => {
if (dir === 'README.md') return ws;
for (const f of fs.readdirSync(path.join(__dirname, 'workflows', dir))) {
const name = f.slice(0, -3);
// NOTE: workflows/ workers are all Typescript files and but we need the built version
try {
ws[`${dir}/${name}`] =
createWorker(`${dir}/${name}`, path.join(__dirname, 'build', dir, `${name}.js`));
} catch (err) {
if (err.code !== 'MODULE_NOT_FOUND') throw err;
}
}
return ws;
}, {});
const wrap = (s) => s.replace(/(?![^\n]{1,78}$)([^\n]{1,78})\s/g, '$1\n');
const PREAMBLE = `process <TYPE> <INPUT> <OUTPUT>\n\n` + wrap(
`Runs a worker of type TYPE on the data found in INPUT to produce OUTPUT. ` +
`TYPE can be one of ${Object.keys(WORKERS).map(w => `'${w}'`).join(', ')}, ` +
`or a path to the worker code.`
);
const usage = code => config.usage(code, PREAMBLE, Object.values(WORKERS));
const unknown = arg => {
console.error(`Unknown argument: '${arg}'\n`);
usage(1);
};
const conflict = (arg, a, b) => {
console.error(`Conflicting values for ${arg}: '${a}' vs. '${b}'\n`);
usage(1);
};
// We potentially need to parse our the arguments twice - if we're given a worker which isn't in
// workflows/ we need to register its options and reparse. We can't complain about unknown arguments
// at this stage because they might be options for the worker that we haven't registered yet.
let argv = minimist(process.argv.slice(2), {alias: ALIASES});
if (argv.help) usage(0);
let foreign = false;
let worker;
if (argv.worker) {
if (WORKERS[argv.worker]) {
worker = WORKERS[argv.worker];
} else {
const name = path.basename(argv.worker).slice(-3);
worker = WORKERS[name] = createWorker(name, argv.worker);
foreign = true;
}
}
if (argv._[0]) {
if (WORKERS[argv._[0]]) {
if (worker && worker.code !== WORKERS[argv._[0]].code) {
conflict('worker', argv.worker, argv._[0]);
}
worker = WORKERS[argv._[0]];
} else {
const name = path.basename(argv._[0]).slice(-3);
WORKERS[name] = createWorker(name, argv._[0]);
if (worker && worker.code !== WORKERS[name].code) {
conflict('worker', argv.worker, argv._[0]);
}
worker = WORKERS[name];
foreign = true;
}
}
if (!worker) usage(1);
if (foreign) {
// Reparse now that we know we have registered the foreign worker's options - this time around it
// is safe to complain about unknown arguments because we should have the full set registered.
argv = minimist(process.argv.slice(2), {alias: ALIASES, unknown});
}
argv.worker = worker.path;
if (argv._[1]) {
if (argv.input && path.resolve(argv.input) !== path.resolve(argv._[1])) {
conflict('input', argv._[1], argv.input);
}
argv.input = argv._[1];
}
if (argv._[2]) {
if (argv.output && path.resolve(argv.output) !== path.resolve(argv._[2])) {
conflict('output', argv._[2], argv.output);
}
argv.output = argv._[2];
}
if (!(argv.worker && argv.input && argv.output)) usage(1);
if (argv.debug) process.env.DEBUG = +argv.verbose;
// We have avoided requiring logs directly because the only way to transparently switch out the
// backend is to set an environment variable first. We default to worker_threads, but if the
// --processes flag was passed we switch to the process backend. If both are passed the config
// parsing inside of the logs process code will error out, so we don't need to both checking here.
process.env.BTHREADS_BACKEND = argv.processes ? 'child_process' : 'worker_threads';
(async () => process.exit(await require('logs').process(argv)))().catch(console.error);