zotero/scripts/js.js

132 lines
3.8 KiB
JavaScript
Raw Normal View History

const globby = require('globby');
const path = require('path');
const os = require('os');
const fs = require('fs-extra');
const cluster = require('cluster');
const { getSignatures, compareSignatures, getFileSignature, writeSignatures, cleanUp, onSuccess, onError, onProgress } = require('./utils');
const { jsFiles, ignoreMask } = require('./config');
const NODE_ENV = process.env.NODE_ENV;
const ROOT = path.resolve(__dirname, '..');
async function getJS(source, options, signatures) {
const t1 = Date.now();
const matchingJSFiles = await globby(source, Object.assign({ cwd: ROOT }, options));
const cpuCount = os.cpus().length;
const totalCount = matchingJSFiles.length;
var isError = false;
cluster.setupMaster({
exec: path.join(__dirname, 'babel-worker.js')
});
// check signatures, collect signatures for files to be processes
const newFilesSignatures = {};
const filesForProcessing = [];
var f;
while ((f = matchingJSFiles.pop()) != null) {
const newFileSignature = await getFileSignature(f);
const dest = path.join('build', f.replace('.jsx', '.js'));
f = path.normalize(f);
if (f in signatures) {
if (compareSignatures(newFileSignature, signatures[f])) {
try {
await fs.access(dest, fs.constants.F_OK);
continue;
} catch (_) {
// file does not exists in build, fallback to browserifing
}
}
}
filesForProcessing.push(f);
newFilesSignatures[f] = newFileSignature;
}
// shortcut if no files need rebuilding
if (Object.keys(filesForProcessing).length === 0) {
const t2 = Date.now();
return Promise.resolve({
action: 'js',
count: 0,
outFiles: [],
totalCount,
processingTime: t2 - t1
});
}
// distribute processing among workers
const workerCount = Math.min(cpuCount, filesForProcessing.length);
const outFiles = [];
var workersActive = workerCount;
NODE_ENV == 'debug' && console.log(`Will process ${filesForProcessing.length} files using ${workerCount} processes`);
return new Promise((resolve, reject) => {
for (let i = 0; i < workerCount; i++) {
var worker = cluster.fork();
worker.on('message', function(ev) {
if (ev.error) {
isError = true;
let errorMsg = `Failed while processing ${ev.sourcefile}: ${ev.error}`;
reject(errorMsg);
} else {
signatures[ev.sourcefile] = newFilesSignatures[ev.sourcefile];
if (ev.isSkipped) {
NODE_ENV == 'debug' && console.log(`process ${this.id} SKIPPED ${ev.sourcefile}`);
} else {
NODE_ENV == 'debug' && console.log(`process ${this.id} took ${ev.processingTime} ms to process ${ev.sourcefile} into ${ev.outfile}`);
NODE_ENV != 'debug' && onProgress(ev.sourcefile, ev.outfile, 'js');
outFiles.push(ev.outfile);
}
}
let nextFile = filesForProcessing.pop();
if (!isError && nextFile) {
NODE_ENV == 'debug' && console.log(`process ${this.id} scheduled to process ${nextFile}`);
this.send({
file: nextFile
});
} else {
if (this.isConnected()) {
this.kill();
}
NODE_ENV == 'debug' && console.log(`process ${this.id} has terminated`);
if (!--workersActive) {
const t2 = Date.now();
resolve({
action: 'js',
count: outFiles.length,
outFiles,
totalCount,
processingTime: t2 - t1
});
}
}
});
let nextFile = filesForProcessing.pop();
NODE_ENV == 'debug' && console.log(`process ${worker.id} scheduled to process ${nextFile}`);
worker.send({
file: nextFile
});
}
});
}
module.exports = getJS;
if (require.main === module) {
(async () => {
try {
const signatures = await getSignatures();
onSuccess(await getJS(jsFiles, { ignore: ignoreMask }, signatures));
onSuccess(await cleanUp(signatures));
await writeSignatures(signatures);
} catch (err) {
process.exitCode = 1;
global.isError = true;
onError(err);
}
})();
}