ask-cli
Version:
Alexa Skills Kit (ASK) Command Line Interfaces
127 lines (119 loc) • 4.69 kB
JavaScript
const fs = require('fs-extra');
const path = require('path');
const shell = require('shelljs');
const zipUtils = require('@src/utils/zip-utils');
const BUILT_IN_BUILD_FLOWS = [
{
flow: 'nodejs-npm',
manifest: 'package.json'
},
{
flow: 'python-pip',
manifest: 'requirements.txt'
},
{
flow: 'java-mvn',
manifest: 'pom.xml'
}
];
const ZIP_ONLY_BUILD_FLOW = 'zip-only';
const POWERSHELL_PREFIX = 'PowerShell.exe -Command';
class CodeBuilder {
/**
* Constructor for CodeBuilder which decides the code build flow.
* Currently we resolve the packageBuillder based on OS type:
* If running in WINDOWS osType, we only supports using Powershell script;
* If not in WINDOWS, we run bash script.
*
* @param {Object} config { src, build, doDebug }, where build = { folder, file }.
*/
constructor(config) {
const { src, build, doDebug } = config;
this.src = src;
this.build = build;
this.doDebug = doDebug;
this.osType = process.platform === 'win32' ? 'WINDOWS' : 'UNIX';
this._decidePackageBuilder();
}
/**
* Execute this.packageBuilder based on this.osType. We use powershell for Windows and regular terminal for non-Windows.
* @param {Function} callback (error)
*/
execute(callback) {
try {
// 1.reset build folder
fs.ensureDirSync(this.build.folder);
// 2.copy src code to build folder
fs.emptyDirSync(this.build.folder);
fs.copySync(path.resolve(this.src), this.build.folder, {
filter: src => !src.includes(this.build.folder)
});
} catch (fsErr) {
return process.nextTick(() => {
callback(fsErr);
});
}
// 3.execute packge builder script
if (this.buildFlow !== ZIP_ONLY_BUILD_FLOW) {
let command;
if (this.osType === 'WINDOWS') {
const doDebug = this.doDebug ? '$True' : '$False';
command = `${POWERSHELL_PREFIX} "& {& '${this.packageBuilder}' '${this.build.file}' ${doDebug} }"`;
} else {
command = `${this.packageBuilder} "${this.build.file}" ${!!this.doDebug}`;
}
shell.exec(command, { async: true, cwd: this.build.folder }, (code) => {
if (code !== 0) {
callback(`[Error]: Build Scripts failed with non-zero code: ${code}.`);
} else {
callback();
}
});
} else {
zipUtils.createTempZip(this.src, (zipErr, zipFilePath) => {
if (zipErr) {
return callback(zipErr);
}
fs.moveSync(zipFilePath, this.build.file, { overwrite: true });
callback();
});
}
}
/**
* Decide the buildFlow and actual packageBuilder for current instance / source code
*/
_decidePackageBuilder() {
// 1.check if user provided custom build flow script exists
const hookScriptPath = this.osType === 'WINDOWS'
? path.join(process.cwd(), 'hooks', 'build.ps1') // TODO support non-powershell script for Windows
: path.join(process.cwd(), 'hooks', 'build.sh');
if (fs.existsSync(hookScriptPath)) {
this.buildFlow = 'custom';
this.packageBuilder = hookScriptPath;
return;
}
// 2.infer from the src code to decide the build flow
this.buildFlow = this._inferCodeBuildFlow();
this.packageBuilder = this.buildFlow === ZIP_ONLY_BUILD_FLOW ? null
: path.join(__dirname, '..', '..', 'builtins', 'build-flows', this.buildFlow, this.osType === 'WINDOWS' ? 'build.ps1' : 'build.sh');
}
/**
* Infer what is the build flow for the current src by checking the existence of manifest file in the src code.
* If no built-in build flow is found, will go by default to zip-only.
*/
_inferCodeBuildFlow() {
let buildFlowResult = ZIP_ONLY_BUILD_FLOW; // set default build flow to be 'zip-only'
if (fs.statSync(this.src).isDirectory()) {
for (const flowItem of BUILT_IN_BUILD_FLOWS) {
const { flow, manifest } = flowItem;
if (fs.existsSync(path.join(this.src, manifest))) {
buildFlowResult = flow;
break;
}
}
}
return buildFlowResult;
}
}
module.exports = CodeBuilder;
module.exports.ZIP_ONLY_BUILD_FLOW = ZIP_ONLY_BUILD_FLOW;