UNPKG

adxutil

Version:

Utilities tools for Askia Design eXtension

360 lines (309 loc) 10.8 kB
"use strict"; const fs = require('fs'); const pathHelper = require('path'); const common = require('../common/common.js'); const errMsg = common.messages.error; const successMsg = common.messages.success; const Validator = require('../validator/ADXValidator.js').Validator; /** * Validate and compress the ADX directory to an `.adc` or `.adp` file * * @class Builder * @param {String} adxDirPath Path of the ADX directory * @private */ function Builder(adxDirPath) { /** * Root dir of the current ADXUtil * * @name Builder#rootdir * @type {String} */ this.rootdir = pathHelper.resolve(__dirname, "../../"); /** * Name of the ADX * * @name Builder#adxName * @type {string} */ this.adxName = ''; /** * Path to the ADX directory * * @name Builder#adxDirectoryPath * @type {string} */ this.adxDirectoryPath = adxDirPath ? pathHelper.normalize(adxDirPath) : process.cwd(); /** * Configurator of the ADX * * @name Builder#adxConfigurator * @type {ADX.Configurator} */ this.adxConfigurator = null; /** * Bin path of the ADX * * @name Builder#binPath * @type {string} */ this.binPath = ''; /** * Path of the output file * * @name Builder#outputPath * @type {string} */ this.outputPath = ''; /** * Sequence of calls * * @name Builder#sequence * @type {Sequence} */ this.sequence = new common.Sequence([ this.createBinDir, this.compressADX ], this.done, this); /** * Report of the validation * * @name Builder#validationReport * @type {{startTime: null, endTime: null, runs: number, total: number, success: number, warnings: number, errors: number}} */ this.validationReport = null; /** * Logger to override with an object * * @name Builder#logger * @type {{writeMessage : Function, writeSuccess : Function, writeWarning: Function, writeError : Function}} */ this.logger = null; /** * Print mode * * @name Builder#printMode * @type {String|"default"|"html"} */ this.printMode = 'default'; } /** * Create a new instance of ADX Builder * @ignore */ Builder.prototype.constructor = Builder; /** * Build the ADX * * @param {Object} [options] Options of validation * @param {String|'default'|'html'} [options.printMode='default'] Print mode (default console or html) * @param {Boolean} [options.test=true] Run unit tests * @param {Boolean} [options.autoTest=true] Run auto unit tests * @param {Boolean} [options.xml=true] Validate the config.xml file * @param {InteractiveADXShell} [options.adxShell] Interactive ADXShell process * @param {Object} [options.logger] Logger * @param {Function} [options.writeMessage] Function where regular messages will be print * @param {Function} [options.writeSuccess] Function where success messages will be print * @param {Function} [options.writeWarning] Function where warning messages will be print * @param {Function} [options.writeError] Function where error messages will be print * @param {Function} [callback] Callback function * @param {Error} [callback.err] Error * @param {String} [callback.outputPath] Path of the output * @param {Object} [callback.report] Validation report */ Builder.prototype.build = function build(options, callback) { // Reset the print mode this.printMode = 'default'; // Swap the options if (typeof options === 'function') { callback = options; options = null; } this.buildCallback = callback; this.validator = new Validator(this.adxDirectoryPath); const self = this; options = options || {}; options.xml = true; options.autoTest = true; if (options.logger) { this.logger = options.logger; } if (options.printMode) { this.printMode = options.printMode || 'default'; } this.validator.validate(options, (err, report) => { if (err) { return self.sequence.resume(new Error(errMsg.validationFailed)); } self.adxName = self.validator.adxName; self.adxConfigurator = self.validator.adxConfigurator; self.binPath = pathHelper.join(self.adxDirectoryPath, common.ADX_BIN_PATH); self.validationReport = report; return self.sequence.resume(); }); }; /** * Write an error output in the console or in the logger * @param {String} text Text to write in the console */ Builder.prototype.writeError = function writeError(text) { const args = Array.prototype.slice.call(arguments); if (this.printMode === 'html' && args.length) { args[0] = '<div class="error">' + args[0] + '</div>'; } if (this.logger && typeof this.logger.writeError === 'function') { this.logger.writeError.apply(this.logger, args); } else { common.writeError.apply(common, args); } }; /** * Write a warning output in the console or in the logger * @param {String} text Text to write in the console */ Builder.prototype.writeWarning = function writeWarning(text) { const args = Array.prototype.slice.call(arguments); if (this.printMode === 'html' && args.length) { args[0] = '<div class="warning">' + args[0] + '</div>'; } if (this.logger && typeof this.logger.writeWarning === 'function') { this.logger.writeWarning.apply(this.logger, args); } else { common.writeWarning.apply(common, args); } }; /** * Write a success output in the console or in the logger * @param {String} text Text to write in the console */ Builder.prototype.writeSuccess = function writeSuccess(text) { const args = Array.prototype.slice.call(arguments); if (this.printMode === 'html' && args.length) { args[0] = '<div class="success">' + args[0] + '</div>'; } if (this.logger && typeof this.logger.writeSuccess === 'function') { this.logger.writeSuccess.apply(this.logger, args); } else { common.writeSuccess.apply(common, args); } }; /** * Write an arbitrary message in the console or in the logger without specific prefix or in the logger * @param {String} text Text to write in the console */ Builder.prototype.writeMessage = function writeMessage(text) { const args = Array.prototype.slice.call(arguments); if (this.printMode === 'html' && args.length) { args[0] = '<div class="message">' + args[0] + '</div>'; } if (this.logger && typeof this.logger.writeMessage === 'function') { this.logger.writeMessage.apply(this.logger, args); } else { common.writeMessage.apply(common, args); } }; /** * End of the sequence chain * @param {Error} err Error */ Builder.prototype.done = function done(err) { if (err) { this.writeError(err.message); if (typeof this.buildCallback === 'function') { this.buildCallback(err, this.outputPath, this.validationReport); } return; } const fileExt = '.' + this.adxConfigurator.projectType.toLowerCase(); const output = pathHelper.join(this.binPath, this.adxName + fileExt); if (!this.validationReport.warnings) { this.writeSuccess(successMsg.buildSucceed, output); } else { this.writeSuccess(successMsg.buildSucceedWithWarning, this.validationReport.warnings, output); } if (typeof this.buildCallback === 'function') { this.buildCallback(err, this.outputPath, this.validationReport); } }; /** * Create a bin directory */ Builder.prototype.createBinDir = function createBinDir() { const self = this; common.dirExists(this.binPath, (err, exist) => { if (!exist || err) { const er = fs.mkdirSync(self.binPath); if (er) { return self.sequence.resume(er); } } return self.sequence.resume(); }); }; /** * Compress the ADX directory */ Builder.prototype.compressADX = function compressADX() { const self = this; common.getDirStructure(self.adxDirectoryPath, (err, structure) => { if (err) { return self.sequence.resume(err); } const zip = common.getNewZip(); let zipDir = ''; structure.forEach(function appendInZip(file) { let prevDir, folderLower, zipDirLower = zipDir.toLowerCase(); if (typeof file === 'string') { // File if (zipDirLower === 'resources\\') return; // Exclude extra files if (zipDirLower === '' && !/^(config\.xml|readme|changelog)/i.test(file)) return; // Exclude extra files if (common.isIgnoreFile(file)) return; // Ignore files zip.file( pathHelper.join(zipDir, file), fs.readFileSync(pathHelper.join(self.adxDirectoryPath, zipDir, file)) ); } else { // Directory if (!file.sub || !file.sub.length) return; // Exclude empty folder folderLower = file.name.toLowerCase(); if (folderLower === 'bin') return; // Exclude the bin folder if (folderLower === 'tests') return; // Exclude tests folder if (zipDirLower === 'resources\\' && !/^(dynamic|static|share)$/i.test(folderLower)) return; // Exclude extra directories if (zipDirLower === '' && !/^(resources)$/.test(folderLower)) return; // Exclude extra directories prevDir = zipDir; zipDir += file.name + '\\'; zip.folder(zipDir); file.sub.forEach(appendInZip); zipDir = prevDir; } }); const buffer = zip.generate({ type: "nodebuffer", compression: 'DEFLATE', compressionOptions: { level: 6 } }); const fileExt = '.' + self.adxConfigurator.projectType.toLowerCase(); self.outputPath = pathHelper.join(self.binPath, self.adxName + fileExt); fs.writeFile(self.outputPath, buffer, (err) => { if (err) { throw err; } }); self.sequence.resume(); }); }; // Export the Builder object exports.Builder = Builder; /* * Build the ADX file * * @param {Command} program Commander object which hold the arguments pass to the program * @param {String} path Path of the ADX to directory * @ignore */ exports.build = function build(program, path) { const builder = new Builder(path); builder.build(program); };