UNPKG

ask-cli-x

Version:

Alexa Skills Kit (ASK) Command Line Interfaces

190 lines (189 loc) 7.47 kB
"use strict"; const fs = require("fs-extra"); const path = require("path"); const R = require("ramda"); const SkillInfrastructureController = require("../../controllers/skill-infrastructure-controller"); const CliWarn = require("../../exceptions/cli-warn"); const AskResources = require("../../model/resources-config/ask-resources"); const AskStates = require("../../model/resources-config/ask-states"); const ResourcesConfig = require("../../model/resources-config"); const stringUtils = require("../../utils/string-utils"); const CONSTANTS = require("../../utils/constants"); const Messenger = require("../../view/messenger"); const ui = require("./ui"); module.exports = { preInitCheck, getSkillIdUserInput, getSkillMetadataUserInput, getSkillCodeUserInput, getSkillInfraUserInput, previewAndWriteAskResources, bootstrapSkillInfra, }; /** * The validation or preparation before collecting user config for init command * @param {String} rootPath path for the project root * @param {String} profile ask-cli profile * @param {Function} callback (err) */ function preInitCheck(rootPath, profile, callback) { ui.showInitInstruction(profile); _attemptGetAskResources(rootPath, (attemptErr) => { callback(attemptErr); }); } function _attemptGetAskResources(rootPath, callback) { const askResourcesPath = path.join(rootPath, CONSTANTS.FILE_PATH.ASK_RESOURCES_JSON_CONFIG); if (fs.existsSync(askResourcesPath)) { ui.confirmOverwrite((confirmErr, isConfirmed) => { if (confirmErr) { return callback(confirmErr); } if (!isConfirmed) { return callback(new CliWarn(`Please modify the existing ${CONSTANTS.FILE_PATH.ASK_RESOURCES_JSON_CONFIG} file or choose to overwrite.`)); } callback(); }); } else { process.nextTick(() => { callback(); }); } } /** * Get user's skillId if it exists * @param {Function} callback (err, skillId) */ function getSkillIdUserInput(callback) { ui.getSkillId((skillIdErr, skillId) => { callback(skillIdErr, !skillIdErr ? skillId : null); // TODO: use hosted-skill controller to check if the skillId is for hosted skill }); } /** * Get user's skillMetadata src path * @param {Function} callback (err, {src}) */ function getSkillMetadataUserInput(callback) { ui.getSkillMetaSrc((skillMetaErr, skillMetaSrc) => { callback(skillMetaErr, !skillMetaErr ? { src: skillMetaSrc } : null); }); } /** * Get user's skillCode src path * @param {Function} callback (err, {src}) */ function getSkillCodeUserInput(callback) { ui.getCodeSrcForRegion(CONSTANTS.ALEXA.REGION.DEFAULT, (defaultRegionErr, defaultSrc) => { if (defaultRegionErr) { return callback(defaultRegionErr); } if (defaultSrc === "") { return callback(); // return null if user inputs empty string } const skillCode = {}; skillCode[CONSTANTS.ALEXA.REGION.DEFAULT] = { src: defaultSrc }; callback(null, skillCode); }); } /** * Get user's skillInfra settings * @param {Function} callback (err, {type, userConfig}) */ function getSkillInfraUserInput(callback) { ui.getSkillInfra((deployerErr, infraSettings) => { if (deployerErr) { return callback(deployerErr); } const skillInfra = {}; skillInfra.type = infraSettings.isUsingCfn ? "@ask-cli/cfn-deployer" : "@ask-cli/lambda-deployer"; skillInfra.userConfig = { runtime: infraSettings.runtime, handler: infraSettings.handler, }; callback(null, skillInfra); }); } /** * Preview the ask-resources config and write to file system upon users' confirmation * @param {String} rootPath path for the project root * @param {Object} userInput data object from last step's result * @param {String} profile ask-cli profile * @param {Function} callback (err) */ function previewAndWriteAskResources(rootPath, userInput, profile, callback) { const { askResources, askStates } = _assembleAskResources(userInput, profile); ui.showPreviewAndConfirm(rootPath, { askResources, askStates }, (confirmErr, isConfirmed) => { if (confirmErr) { return callback(confirmErr); } if (!isConfirmed) { return callback(new CliWarn("Project init aborted.")); } try { const askResourcesFilePath = path.join(rootPath, CONSTANTS.FILE_PATH.ASK_RESOURCES_JSON_CONFIG); const askHiddenFolder = path.join(rootPath, CONSTANTS.FILE_PATH.HIDDEN_ASK_FOLDER); const askStatesFilePath = path.join(askHiddenFolder, CONSTANTS.FILE_PATH.ASK_STATES_JSON_CONFIG); fs.removeSync(askResourcesFilePath); AskResources.withContent(askResourcesFilePath, askResources); fs.removeSync(askHiddenFolder); AskStates.withContent(askStatesFilePath, askStates); } catch (writeErr) { return callback(writeErr); } callback(); }); } function _assembleAskResources(userInput, profile) { const askResourcesJson = R.clone(AskResources.BASE); const askStatesJson = R.clone(AskStates.BASE); const askProfileResources = { skillMetadata: userInput.skillMeta }; const askProfileStates = { skillId: userInput.skillId }; if (userInput.skillCode) { askProfileResources.code = userInput.skillCode; } if (userInput.skillInfra) { askProfileResources.skillInfrastructure = userInput.skillInfra; askProfileStates.skillInfrastructure = { [userInput.skillInfra.type]: { deployState: {}, }, }; } return { askResources: R.set(R.lensPath(["profiles", profile]), askProfileResources, askResourcesJson), askStates: R.set(R.lensPath(["profiles", profile]), askProfileStates, askStatesJson), }; } /** * Call deployer's bootstrap method to prepare necessary deployment utilities through skillInfraController * @param {String} rootPath root path for the project * @param {String} profile ask-cli profile * @param {Boolean} doDebug * @param {Function} callback {err} */ function bootstrapSkillInfra(rootPath, profile, doDebug, callback) { const askResourcesFilePath = path.join(rootPath, CONSTANTS.FILE_PATH.ASK_RESOURCES_JSON_CONFIG); new ResourcesConfig(askResourcesFilePath); const deployerType = ResourcesConfig.getInstance().getSkillInfraType(profile); if (!stringUtils.isNonBlankString(deployerType)) { return process.nextTick(() => { callback(); }); } // bootstrap after deployer gets selected const ddFolderPath = deployerType.startsWith("@ask-cli/") ? deployerType.replace("@ask-cli/", "") : deployerType; const deployerPath = path.join(rootPath, CONSTANTS.FILE_PATH.SKILL_INFRASTRUCTURE.INFRASTRUCTURE, ddFolderPath); fs.ensureDirSync(deployerPath); const skillInfraController = new SkillInfrastructureController({ profile, doDebug }); skillInfraController.bootstrapInfrastructures(deployerPath, (bootstrapErr) => { if (bootstrapErr) { return callback(bootstrapErr); } ResourcesConfig.getInstance().write(); Messenger.getInstance().info(`Project bootstrap from deployer "${deployerType}" succeeded.`); callback(); }); }