You cannot select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
openNG/build/core/runner/index.js

232 lines
7.3 KiB
JavaScript

"use strict";
const chalk = require("chalk");
const moment = require("moment");
const path = require("path");
const traverseTransformHistory = require("../util/traverse-transform-history");
const drawTransformTree = require("./draw-transform-tree");
const errors = require("../errors/errors");
function formatDate(date) {
return chalk.dim(`[${moment(date).format("LTS")}]`);
}
function formatSuccessfulSourcePath(sourcePath) {
return chalk.bgGreen.black(`${sourcePath} `);
}
function formatFailedSourcePath(sourcePath) {
return chalk.bgRed.white(`${sourcePath} `);
}
function formatDuration(ms) {
return chalk.bold(`${ms}ms`);
}
function formatTransformDisplayName(displayName) {
return displayName;
}
function formatTransformPath(relativePath) {
return chalk.dim(`[${relativePath}]`);
}
function formatSinkPath(sinkPath) {
return chalk.bold(sinkPath);
}
function formatSuccessfulSourceStep(metadata) {
return `${formatSuccessfulSourcePath(metadata.relativePath)} ${formatDate(metadata.sourcedDate)}`;
}
function formatSuccessfulTransformStep(metadata) {
return `${formatDuration(metadata.stepDuration)} ${formatTransformDisplayName(metadata.step.displayName)} ${formatTransformPath(metadata.relativePath)}`;
}
function formatSuccessfulSinkStep(metadata) {
return formatSinkPath(metadata.targetPath);
}
function formatMissingTransformStep(step) {
return chalk.dim(`${chalk.bold("not run:")} ${step.displayName}`);
}
function formatMissingSinkStep() {
return chalk.dim("(no output file produced)");
}
function formatFailedSourceStep(source) {
return `${formatFailedSourcePath(source.relativePath)} ${formatDate(source.sourcedDate)}`;
}
function formatFailedTransformStepName(step, duration) {
return chalk.red(`${formatDuration(duration)} ${step.displayName}`);
}
function formatErrorDetail(name, description) {
return chalk.red(`${chalk.bold(`${name}:`)} ${description}`);
}
function formatFailedTransformStep(step, file, error, pipeline, duration) {
if (error instanceof errors.SyntaxError) {
let prefix = formatErrorPrefix("Syntax Error");
let message = formatErrorMessage(error.error);
return [
formatFailedTransformStepName(step, duration),
`${prefix}${message}`,
formatErrorDetail("File", `${path.resolve(pipeline.basePath, file.metadata.relativePath)} ${file.metadata.isVirtual ? chalk.dim("(virtual)") : ""}`),
formatErrorDetail("Location", `Line ${error.line}, column ${error.column}`),
(file.metadata.isVirtual)
? chalk.bgRed.white.bold("This file is a virtual file. That means that the syntax error probably originates from another earlier transform, and there may be a bug in that transform.")
: ""
].join("\n");
} else {
let prefix = formatErrorPrefix("Error");
let message = formatErrorMessage(`An unexpected error occurred in the transform`);
/* FIXME: */
// if (error instanceof Error) {
// console.log(chalk.red(error.stack));
// } else {
// console.log(chalk.red(util.inspect(error, {colors: true, depth: null})));
// console.log(chalk.bgRed.white.bold("This error wasn't actually an error object - that's a bug in the transform! Here's a less precise stacktrace:"));
// console.log(chalk.red((new Error()).stack));
// }
return [
formatFailedTransformStepName(step),
`${prefix}${message}`,
error.stack
].join("\n");
}
}
// console.log(chalk.bgRed.white.bold(`A syntax error occurred in the transform '${transform.displayName}':`));
// console.log(chalk.red(` ${chalk.bold("Error:")} ${error.error}`));
// console.log(chalk.red(` ${chalk.bold("File:")} ${path.resolve(basePath, file.relativePath)} ${file.isVirtual ? chalk.dim("(virtual)") : ""}`));
// console.log(chalk.red(` ${chalk.bold("Location:")} Line ${error.line}, column ${error.column}`));
function formatFailedSinkStep(step, error) {
let prefix = formatErrorPrefix("Error");
let message = formatErrorMessage(`Failed to write file to destination`);
return [
formatFailedTransformStepName(step),
`${prefix}${message}`,
error.stack
].join("\n");
}
function formatErrorPrefix(text) {
return chalk.bgRed.white(` ${text} `);
}
function formatErrorMessage(message) {
return chalk.bgWhite.black(` ${message} `);
}
function formatCompletedItem(metadata) {
let history = traverseTransformHistory(metadata);
let sourceStep = formatSuccessfulSourceStep(history[0]);
let transformSteps = history.slice(1, -1).map((metadata) => {
return formatSuccessfulTransformStep(metadata);
});
let sinkStep = formatSuccessfulSinkStep(history[history.length - 1]);
return drawTransformTree([sourceStep].concat(transformSteps).concat([sinkStep]));
}
function formatFailedItem(pipeline, {error, step, file, duration}) {
let history = traverseTransformHistory(file.metadata);
let sourceStep = formatFailedSourceStep(history[0]);
let transformSteps, sinkStep;
if (step.__buildStep === "sink") {
transformSteps = history.slice(1, -1).map((metadata) => {
return formatSuccessfulTransformStep(metadata);
});
sinkStep = formatFailedSinkStep(history[history.length - 1], error);
} else {
let failedIndex = pipeline.steps.indexOf(step);
let successfulTransformSteps = history.slice(1, failedIndex).map((metadata) => {
return formatSuccessfulTransformStep(metadata);
});
let failedTransformStep = formatFailedTransformStep(pipeline.steps[failedIndex], file, error, pipeline, duration);
let missingTransformSteps = pipeline.steps.slice(failedIndex + 1, -1).map((step) => {
return formatMissingTransformStep(step);
});
transformSteps = successfulTransformSteps.concat([failedTransformStep]).concat(missingTransformSteps);
sinkStep = formatMissingSinkStep();
}
return drawTransformTree([sourceStep].concat(transformSteps).concat([sinkStep]));
}
module.exports = function runTask(task) {
let pipeline = task();
pipeline.on("error", (failure) => {
console.log(formatFailedItem(pipeline, failure));
if (failure.isFatal) {
console.log(chalk.bgRed.white.bold("This error is fatal, and the build process will now exit."));
/* FIXME: Do this more cleanly, with teardown and all. */
process.exit(1);
}
console.log("");
});
pipeline.on("done", ({metadata, acknowledged}) => {
console.log(formatCompletedItem(metadata));
if (!acknowledged) {
console.log(chalk.gray("(NOTE: The destination sink doesn't support acknowledgments, so the file may not actually be stored yet.)"));
}
console.log("");
});
pipeline.initialize();
};
// function reportError(transform, file, error, isFatal) {
// if (error instanceof errors.SyntaxError) {
// console.log(chalk.bgRed.white.bold(`A syntax error occurred in the transform '${transform.displayName}':`));
// console.log(chalk.red(` ${chalk.bold("Error:")} ${error.error}`));
// console.log(chalk.red(` ${chalk.bold("File:")} ${path.resolve(basePath, file.relativePath)} ${file.isVirtual ? chalk.dim("(virtual)") : ""}`));
// console.log(chalk.red(` ${chalk.bold("Location:")} Line ${error.line}, column ${error.column}`));
//
//
// } else {
// console.log(chalk.bgRed.white.bold(`An error occurred in the transform '${transform.displayName}':`));
//
//
// }
//
// }
/* FIXME: Move this stuff out, use the acknowledgment event instead for detecting which tasks have finished; also don't forget to add a workaround for sinks that cannot acknowledge */
// console.log("===============");
// console.log(metadata);
// console.log(`Wrote ${targetFilePath}`);