Fancy progress output

This commit is contained in:
Jason Miller
2020-10-05 22:51:23 -04:00
parent 49cb8b268c
commit 911ca32c35
2 changed files with 78 additions and 23 deletions

View File

@@ -24,6 +24,8 @@
"@rollup/plugin-node-resolve": "^9.0.0",
"commander": "^6.0.0",
"json5": "^2.1.3",
"kleur": "^4.1.3",
"ora": "^5.1.0",
"rollup": "^2.26.11",
"rollup-plugin-terser": "^7.0.2"
}

View File

@@ -5,6 +5,8 @@ import { cpus } from "os";
import { extname, join, basename } from "path";
import { promises as fsp } from "fs";
import { version } from "json:../package.json";
import ora from 'ora';
import kleur from 'kleur';
import supportedFormats from "./codecs.js";
import WorkerPool from "./worker_pool.js";
@@ -55,7 +57,7 @@ async function encodeFile({
optimizerButteraugliTarget,
maxOptimizerRounds
}) {
let out;
let out, infoText;
const encoder = await supportedFormats[encName].enc();
if (encConfig === "auto") {
const optionToOptimize = supportedFormats[encName].autoOptimize.option;
@@ -82,11 +84,11 @@ async function encodeFile({
}
);
out = binary;
console.log(
`Used \`--${encName} '${JSON.stringify({
[optionToOptimize]: quality
})}'\` for ${outputFile}`
);
const opts = {
// 5 significant digits is enough
[optionToOptimize]: Math.round(quality * 10000) / 10000
};
infoText = ` using --${encName} '${JSON5.stringify(opts)}'`;
} else {
out = encoder.encode(
bitmapIn.data.buffer,
@@ -97,6 +99,7 @@ async function encodeFile({
}
await fsp.writeFile(outputFile, out);
return {
infoText,
inputSize: size,
inputFile: file,
outputFile,
@@ -114,8 +117,60 @@ function handleJob(params) {
return decodeFile(params.file);
}
}
function progressTracker(results) {
const spinner = ora();
const tracker = {};
tracker.spinner = spinner;
tracker.progressOffset = 0;
tracker.totalOffset = 0;
let status = '';
tracker.setStatus = (text) => {
status = text || '';
update();
};
let progress = '';
tracker.setProgress = (done, total) => {
spinner.prefixText = kleur.dim(`${done}/${total}`);
const completeness = (tracker.progressOffset + done) / (tracker.totalOffset + total);
progress = kleur.cyan(`${'▨'.repeat(completeness*10|0).padEnd(10, '╌')}`);
update();
};
function update() {
spinner.text = progress + kleur.bold(status) + getResultsText();
}
tracker.finish = (text) => {
spinner.succeed(kleur.bold(text) + getResultsText());
}
function getResultsText() {
let out = '';
for (const [filename, result] of results.entries()) {
out += `\n ${kleur.cyan(filename)}: ${prettyPrintSize(result.size)}`;
for (const { outputFile, outputSize, infoText } of result.outputs) {
const name = (program.suffix + extname(outputFile)).padEnd(5);
out += `\n ${kleur.dim('└')} ${kleur.cyan(name)}${prettyPrintSize(outputSize)}`;
const percent = ((outputSize / result.size) * 100).toPrecision(3);
out += ` (${kleur[outputSize>result.size?'red':'green'](percent+'%')})`;
if (infoText) out += kleur.yellow(infoText);
}
}
return out || '\n';
}
spinner.start();
return tracker;
}
async function processFiles(files) {
const workerPool = new WorkerPool(cpus().length, __filename);
const parallelism = cpus().length;
const results = new Map();
const progress = progressTracker(results);
progress.setStatus('Decoding...');
progress.totalOffset = files.length;
progress.setProgress(0, files.length);
const workerPool = new WorkerPool(parallelism, __filename);
// Create output directory
await fsp.mkdir(program.outputDir, { recursive: true });
@@ -131,8 +186,11 @@ async function processFiles(files) {
return result;
}));
const decodedFiles = await Promise.all(files.map(file => decodeFile(file)));
progress.progressOffset = decoded;
progress.setStatus('Encoding ' + kleur.dim(`(${parallelism} threads)`));
progress.setProgress(0, files.length);
const jobs = [];
let jobsStarted = 0;
let jobsFinished = 0;
for (const { file, bitmap, size } of decodedFiles) {
@@ -155,7 +213,7 @@ async function processFiles(files) {
);
const outputFile = join(program.outputDir, `${base}.${value.extension}`);
jobsStarted++;
workerPool
const p = workerPool
.dispatchJob({
operation: 'encode',
file,
@@ -167,26 +225,21 @@ async function processFiles(files) {
optimizerButteraugliTarget: Number(program.optimizerButteraugliTarget),
maxOptimizerRounds: Number(program.maxOptimizerRounds)
})
.then(({ outputFile, inputSize, outputSize }) => {
.then((output) => {
jobsFinished++;
const numDigits = jobsStarted.toString().length;
console.log(
`${jobsFinished
.toString()
.padStart(
numDigits
)}/${jobsStarted}: ${outputFile} ${prettyPrintSize(
inputSize
)} -> ${prettyPrintSize(outputSize)} (${(
(outputSize / inputSize) *
100
).toFixed(1)}%)`
);
results.get(file).outputs.push(output);
progress.setProgress(jobsFinished, jobsStarted);
});
jobs.push(p);
}
}
// update the progress to account for multi-format
progress.setProgress(jobsFinished, jobsStarted);
// Wait for all jobs to finish
await workerPool.join();
await Promise.all(jobs);
progress.finish('Squoosh results:');
}
if (isMainThread) {