UNPKG

7.48 kBJavaScriptView Raw
1const fs = require('fs-extra');
2const path = require('path');
3const R = require('ramda');
4
5const SkillInfrastructureController = require('@src/controllers/skill-infrastructure-controller');
6const CliWarn = require('@src/exceptions/cli-warn');
7const AskResources = require('@src/model/resources-config/ask-resources');
8const AskStates = require('@src/model/resources-config/ask-states');
9const ResourcesConfig = require('@src/model/resources-config');
10const stringUtils = require('@src/utils/string-utils');
11const CONSTANTS = require('@src/utils/constants');
12const Messenger = require('@src/view/messenger');
13
14const ui = require('./ui');
15
16module.exports = {
17 preInitCheck,
18 getSkillIdUserInput,
19 getSkillMetadataUserInput,
20 getSkillCodeUserInput,
21 getSkillInfraUserInput,
22 previewAndWriteAskResources,
23 bootstrapSkillInfra
24};
25
26/**
27 * The validation or preparation before collecting user config for init command
28 * @param {String} rootPath path for the project root
29 * @param {String} profile ask-cli profile
30 * @param {Function} callback (err)
31 */
32function preInitCheck(rootPath, profile, callback) {
33 ui.showInitInstruction(profile);
34 _attemptGetAskResources(rootPath, (attemptErr) => {
35 callback(attemptErr);
36 });
37}
38
39function _attemptGetAskResources(rootPath, callback) {
40 const askResourcesPath = path.join(rootPath, CONSTANTS.FILE_PATH.ASK_RESOURCES_JSON_CONFIG);
41 if (fs.existsSync(askResourcesPath)) {
42 ui.confirmOverwrite((confirmErr, isConfirmed) => {
43 if (confirmErr) {
44 return callback(confirmErr);
45 }
46 if (!isConfirmed) {
47 return callback(
48 new CliWarn(`Please modify the existing ${CONSTANTS.FILE_PATH.ASK_RESOURCES_JSON_CONFIG} file or choose to overwrite.`)
49 );
50 }
51 callback();
52 });
53 } else {
54 process.nextTick(() => {
55 callback();
56 });
57 }
58}
59
60/**
61 * Get user's skillId if it exists
62 * @param {Function} callback (err, skillId)
63 */
64function getSkillIdUserInput(callback) {
65 ui.getSkillId((skillIdErr, skillId) => {
66 callback(skillIdErr, !skillIdErr ? skillId : null);
67 // TODO: use hosted-skill controller to check if the skillId is for hosted skill
68 });
69}
70
71/**
72 * Get user's skillMetadata src path
73 * @param {Function} callback (err, {src})
74 */
75function getSkillMetadataUserInput(callback) {
76 ui.getSkillMetaSrc((skillMetaErr, skillMetaSrc) => {
77 callback(skillMetaErr, !skillMetaErr ? { src: skillMetaSrc } : null);
78 });
79}
80
81/**
82 * Get user's skillCode src path
83 * @param {Function} callback (err, {src})
84 */
85function getSkillCodeUserInput(callback) {
86 ui.getCodeSrcForRegion(CONSTANTS.ALEXA.REGION.DEFAULT, (defaultRegionErr, defaultSrc) => {
87 if (defaultRegionErr) {
88 return callback(defaultRegionErr);
89 }
90 if (defaultSrc === '') {
91 return callback(); // return null if user inputs empty string
92 }
93 const skillCode = {};
94 skillCode[CONSTANTS.ALEXA.REGION.DEFAULT] = { src: defaultSrc };
95 callback(null, skillCode);
96 });
97}
98
99/**
100 * Get user's skillInfra settings
101 * @param {Function} callback (err, {type, userConfig})
102 */
103function getSkillInfraUserInput(callback) {
104 ui.getSkillInfra((deployerErr, infraSettings) => {
105 if (deployerErr) {
106 return callback(deployerErr);
107 }
108 const skillInfra = {};
109 skillInfra.type = infraSettings.isUsingCfn ? '@ask-cli/cfn-deployer' : '@ask-cli/lambda-deployer';
110 skillInfra.userConfig = {
111 runtime: infraSettings.runtime,
112 handler: infraSettings.handler
113 };
114 callback(null, skillInfra);
115 });
116}
117
118/**
119 * Preview the ask-resources config and write to file system upon users' confirmation
120 * @param {String} rootPath path for the project root
121 * @param {Object} userInput data object from last step's result
122 * @param {String} profile ask-cli profile
123 * @param {Function} callback (err)
124 */
125function previewAndWriteAskResources(rootPath, userInput, profile, callback) {
126 const { askResources, askStates } = _assembleAskResources(userInput, profile);
127 ui.showPreviewAndConfirm(rootPath, { askResources, askStates }, (confirmErr, isConfirmed) => {
128 if (confirmErr) {
129 return callback(confirmErr);
130 }
131 if (!isConfirmed) {
132 return callback(new CliWarn('Project init aborted.'));
133 }
134 try {
135 const askResourcesFilePath = path.join(rootPath, CONSTANTS.FILE_PATH.ASK_RESOURCES_JSON_CONFIG);
136 const askHiddenFolder = path.join(rootPath, CONSTANTS.FILE_PATH.HIDDEN_ASK_FOLDER);
137 const askStatesFilePath = path.join(askHiddenFolder, CONSTANTS.FILE_PATH.ASK_STATES_JSON_CONFIG);
138 fs.removeSync(askResourcesFilePath);
139 AskResources.withContent(askResourcesFilePath, askResources);
140 fs.removeSync(askHiddenFolder);
141 AskStates.withContent(askStatesFilePath, askStates);
142 } catch (writeErr) {
143 return callback(writeErr);
144 }
145 callback();
146 });
147}
148
149function _assembleAskResources(userInput, profile) {
150 const askResourcesJson = R.clone(AskResources.BASE);
151 const askStatesJson = R.clone(AskStates.BASE);
152 const askProfileResources = { skillMetadata: userInput.skillMeta };
153 const askProfileStates = { skillId: userInput.skillId };
154 if (userInput.skillCode) {
155 askProfileResources.code = userInput.skillCode;
156 }
157 if (userInput.skillInfra) {
158 askProfileResources.skillInfrastructure = userInput.skillInfra;
159 askProfileStates.skillInfrastructure = {
160 [userInput.skillInfra.type]: {
161 deployState: {}
162 }
163 };
164 }
165 return {
166 askResources: R.set(R.lensPath(['profiles', profile]), askProfileResources, askResourcesJson),
167 askStates: R.set(R.lensPath(['profiles', profile]), askProfileStates, askStatesJson)
168 };
169}
170
171/**
172 * Call deployer's bootstrap method to prepare necessary deployment utilities through skillInfraController
173 * @param {String} rootPath root path for the project
174 * @param {String} profile ask-cli profile
175 * @param {Boolean} doDebug
176 * @param {Function} callback {err}
177 */
178function bootstrapSkillInfra(rootPath, profile, doDebug, callback) {
179 const askResourcesFilePath = path.join(rootPath, CONSTANTS.FILE_PATH.ASK_RESOURCES_JSON_CONFIG);
180 new ResourcesConfig(askResourcesFilePath);
181 const deployerType = ResourcesConfig.getInstance().getSkillInfraType(profile);
182 if (!stringUtils.isNonBlankString(deployerType)) {
183 return process.nextTick(() => {
184 callback();
185 });
186 }
187 // bootstrap after deployer gets selected
188 const ddFolderPath = deployerType.startsWith('@ask-cli/') ? deployerType.replace('@ask-cli/', '') : deployerType;
189 const deployerPath = path.join(rootPath, CONSTANTS.FILE_PATH.SKILL_INFRASTRUCTURE.INFRASTRUCTURE, ddFolderPath);
190 fs.ensureDirSync(deployerPath);
191 const skillInfraController = new SkillInfrastructureController({ profile, doDebug });
192 skillInfraController.bootstrapInfrastructures(deployerPath, (bootstrapErr) => {
193 if (bootstrapErr) {
194 return callback(bootstrapErr);
195 }
196 ResourcesConfig.getInstance().write();
197 Messenger.getInstance().info(`Project bootstrap from deployer "${deployerType}" succeeded.`);
198 callback();
199 });
200}