mirror of
https://github.com/serverless/serverless.git
synced 2026-01-18 14:58:43 +00:00
258 lines
8.5 KiB
JavaScript
258 lines
8.5 KiB
JavaScript
'use strict';
|
|
|
|
/**
|
|
* Action: Module Postinstall
|
|
*/
|
|
|
|
const JawsPlugin = require('../../JawsPlugin'),
|
|
JawsError = require('../../jaws-error'),
|
|
JawsCLI = require('../../utils/cli'),
|
|
path = require('path'),
|
|
BbPromise = require('bluebird'),
|
|
JawsUtils = require('../../utils'),
|
|
chalk = require('chalk');
|
|
|
|
let fs = require('fs'),
|
|
wrench = require('wrench'),
|
|
temp = require('temp');
|
|
BbPromise.promisifyAll(fs);
|
|
|
|
/**
|
|
* StageCreate Class
|
|
*/
|
|
class ModulePostinstall extends JawsPlugin {
|
|
|
|
/**
|
|
* @param Jaws class object
|
|
* @param config object
|
|
*/
|
|
|
|
constructor(Jaws, config) {
|
|
super(Jaws, config);
|
|
}
|
|
|
|
/**
|
|
* Define your plugins name
|
|
*
|
|
* @returns {string}
|
|
*/
|
|
static getName() {
|
|
return 'jaws.core.' + ModulePostinstall.name;
|
|
}
|
|
|
|
registerActions() {
|
|
this.Jaws.addAction(this.postInstall.bind(this), {
|
|
handler: 'postInstall',
|
|
description: `copies AWSM files into project aws-modules directory.
|
|
usage: jaws module postinstall <pkgMgr> <moduleName>`,
|
|
context: 'module',
|
|
contextAction: 'postinstall',
|
|
options: [],
|
|
});
|
|
return BbPromise.resolve();
|
|
}
|
|
|
|
|
|
/**
|
|
*
|
|
* @param noExeCf
|
|
* @param region
|
|
* @param stage
|
|
* @returns {Promise}
|
|
*/
|
|
postInstall(evt) {
|
|
let _this = this;
|
|
_this.evt = evt;
|
|
|
|
if (_this.Jaws.cli) {
|
|
// Add options to evt
|
|
_this.evt = _this.Jaws.cli.options;
|
|
|
|
// TODO: validate that resource & action != any of the options, otherwise
|
|
// the option will be replaced with the param in evt
|
|
_this.evt.pkgMgr = _this.Jaws.cli.params[0];
|
|
_this.evt.moduleName = _this.Jaws.cli.params[1];
|
|
}
|
|
|
|
// Skip when using "npm link"
|
|
if (!JawsUtils.fileExistsSync(path.join(process.cwd(), 'jaws.json'))) {
|
|
switch (_this.evt.pkgMgr) {
|
|
case 'npm':
|
|
if (!JawsUtils.fileExistsSync(path.join(process.cwd(), '..', '..', 'jaws.json'))) {
|
|
JawsCLI.log('Skipping postinstall...');
|
|
return BbPromise.resolve();
|
|
}
|
|
break;
|
|
}
|
|
}
|
|
|
|
return this.Jaws.validateProject()
|
|
.bind(_this)
|
|
.then(_this._installFiles)
|
|
.then(function(module) {
|
|
return BbPromise.all([module, _this._saveCfTemplate(module.path)]);
|
|
})
|
|
.spread(function(module) {
|
|
let deferredDepInstalls = [];
|
|
|
|
switch (_this.evt.pkgMgr) {
|
|
case 'npm':
|
|
if (JawsUtils.fileExistsSync(path.join(module.path, 'package.json'))) {
|
|
deferredDepInstalls.push(JawsUtils.npmInstall(module.path));
|
|
}
|
|
break;
|
|
default:
|
|
throw new JawsError('Unsupported package manager', JawsError.errorCodes.UNKNOWN);
|
|
break;
|
|
}
|
|
|
|
if (deferredDepInstalls.length > 0) {
|
|
JawsCLI.log('Installing ' + _this.evt.pkgMgr + ' dependencies...');
|
|
}
|
|
|
|
return BbPromise.all(deferredDepInstalls);
|
|
})
|
|
.then(function() {
|
|
return JawsUtils.findAllEnvletsForAwsm(_this.Jaws._projectRootPath, _this.evt.moduleName);
|
|
})
|
|
.then(function(envlets) {
|
|
JawsCLI.log('Successfully installed ' + _this.evt.moduleName);
|
|
|
|
if (envlets && envlets.length > 1) {
|
|
JawsCLI.log(
|
|
chalk.bgYellow.white(' WARN ') +
|
|
chalk.magenta(' This aws module uses env lets MAKE SURE to run jaws env list to see which ones need to be set')
|
|
);
|
|
}
|
|
});
|
|
};
|
|
|
|
/**
|
|
*
|
|
* @returns {Promise} object {name: awsmJson.name, path: targetModPath}
|
|
* @private
|
|
*/
|
|
_installFiles() {
|
|
|
|
let _this = this,
|
|
pkgMgrDir;
|
|
|
|
if (_this.evt.pkgMgr == 'npm') {
|
|
pkgMgrDir = 'node_modules';
|
|
}
|
|
|
|
let srcAwsmPath = path.join(_this.Jaws._projectRootPath, 'back', pkgMgrDir, _this.evt.moduleName, 'awsm'),
|
|
srcAwsmJsonPath = path.join(_this.Jaws._projectRootPath, 'back', pkgMgrDir, _this.evt.moduleName, 'awsm.json'),
|
|
awsModsPath = path.join(_this.Jaws._projectRootPath, 'back', 'slss_modules');
|
|
|
|
if (!JawsUtils.fileExistsSync(srcAwsmJsonPath)) {
|
|
return BbPromise.reject(new JawsError('Module missing awsm.json file in root of project', JawsError.errorCodes.UNKNOWN));
|
|
}
|
|
|
|
let awsmJson = JawsUtils.readAndParseJsonSync(srcAwsmJsonPath);
|
|
_this._rootAwsmJson = awsmJson;
|
|
|
|
if (!awsmJson.name) {
|
|
return BbPromise.reject(new JawsError('awsm.json for module missing name attr', JawsError.errorCodes.UNKNOWN));
|
|
}
|
|
|
|
let targetModPath = path.join(awsModsPath, awsmJson.name);
|
|
|
|
if (!_this._delExisting && JawsUtils.dirExistsSync(targetModPath)) {
|
|
return BbPromise.reject(new JawsError('Module named ' + awsmJson.name + ' already exists in your project', JawsError.errorCodes.UNKNOWN));
|
|
}
|
|
|
|
if (
|
|
(!awsmJson.cloudFormation) ||
|
|
(!awsmJson.cloudFormation.lambdaIamPolicyDocumentStatements) ||
|
|
(!awsmJson.cloudFormation.apiGatewayIamPolicyDocumentStatements)
|
|
) {
|
|
return BbPromise.reject(new JawsError('Module does not have required cloudFormation attributes', JawsError.errorCodes.UNKNOWN));
|
|
}
|
|
|
|
//Copy over jaws awsm scaffolding
|
|
JawsCLI.log(`Copying ${srcAwsmPath} to ${targetModPath}`);
|
|
wrench.copyDirSyncRecursive(
|
|
srcAwsmPath,
|
|
targetModPath, {
|
|
forceDelete: true,
|
|
excludeHiddenUnix: false,
|
|
});
|
|
|
|
//Write mod root awsm.json so we can identify awsm dirs later
|
|
return JawsUtils.writeFile(path.join(targetModPath, 'awsm.json'), JSON.stringify(awsmJson, null, 2))
|
|
.then(function() {
|
|
return {name: awsmJson.name, path: targetModPath};
|
|
});
|
|
}
|
|
|
|
/**
|
|
* Save CloudFormation attrs
|
|
*
|
|
* @returns {Promise}
|
|
* @private
|
|
*/
|
|
_saveCfTemplate() {
|
|
|
|
let _this = this,
|
|
awsmJson = _this._rootAwsmJson,
|
|
projectCfPath = path.join(_this.Jaws._projectRootPath, 'cloudformation');
|
|
|
|
let cfExtensionPoints = awsmJson.cloudFormation;
|
|
|
|
if (!JawsUtils.dirExistsSync(projectCfPath)) {
|
|
return BbPromise.reject(new JawsError('Your project has no cloudformation dir', JawsError.errorCodes.UNKNOWN));
|
|
}
|
|
|
|
//Update every resources-cf.json for every stage and region. Deep breath...
|
|
return new BbPromise(function(resolve, reject) {
|
|
resolve(wrench.readdirSyncRecursive(projectCfPath))
|
|
})
|
|
.then(function(files) {
|
|
files.forEach(function(file) {
|
|
|
|
file = path.join(projectCfPath, file);
|
|
if (JawsUtils.endsWith(file, 'resources-cf.json')) {
|
|
|
|
let regionStageResourcesCfJson = JawsUtils.readAndParseJsonSync(file);
|
|
|
|
if (cfExtensionPoints.lambdaIamPolicyDocumentStatements.length > 0) {
|
|
JawsCLI.log('Merging in Lambda IAM Policy statements from awsm');
|
|
}
|
|
cfExtensionPoints.lambdaIamPolicyDocumentStatements.forEach(function(policyStmt) {
|
|
regionStageResourcesCfJson.Resources.IamPolicyLambda.Properties.PolicyDocument.Statement.push(policyStmt);
|
|
});
|
|
|
|
if (cfExtensionPoints.apiGatewayIamPolicyDocumentStatements.length > 0) {
|
|
JawsCLI.log('Merging in API Gateway IAM Policy statements from awsm');
|
|
}
|
|
cfExtensionPoints.apiGatewayIamPolicyDocumentStatements.forEach(function(policyStmt) {
|
|
regionStageResourcesCfJson.Resources.IamPolicyApiGateway.Properties.PolicyDocument.Statement.push(policyStmt);
|
|
});
|
|
|
|
let cfResourceKeys = Object.keys(cfExtensionPoints.resources);
|
|
|
|
if (cfResourceKeys.length > 0) {
|
|
JawsCLI.log('Merging in CF Resources from awsm');
|
|
}
|
|
cfResourceKeys.forEach(function(resourceKey) {
|
|
if (regionStageResourcesCfJson.Resources[resourceKey]) {
|
|
JawsCLI.log(
|
|
chalk.bgYellow.white(' WARN ') +
|
|
chalk.magenta(` Resource key ${resourceKey} already defined in ${file}. Overwriting...`)
|
|
);
|
|
}
|
|
|
|
regionStageResourcesCfJson.Resources[resourceKey] = cfExtensionPoints.resources[resourceKey];
|
|
});
|
|
|
|
JawsUtils.writeFile(file, JSON.stringify(regionStageResourcesCfJson, null, 2));
|
|
}
|
|
});
|
|
});
|
|
}
|
|
|
|
}
|
|
|
|
module.exports = ModulePostinstall;
|