UNPKG

6.52 kBJavaScriptView Raw
1'use strict';
2
3const fs = require('fs-extra');
4const get = require('lodash.get');
5const path = require('path');
6const archiver = require('archiver');
7const yaml = require('js-yaml');
8const yamlfiles = require('yaml-files');
9const merge = require('lodash.merge');
10const dotenv = require('dotenv');
11const AWS = require('aws-sdk');
12const execSync = require('child_process').execSync;
13
14/**
15 * Zips a list of files or directories
16 * @param {string} zipFile filename and path where the zip file is stored
17 * @param {array} srcList array of files and directories paths
18 * @param {type} dstPath for directories whether to put the directories at
19 * root of the zip file or relative to your path on the local machine
20 * @return {Promise}
21 */
22function zip(zipFile, srcList, dstPath) {
23 if (!dstPath) {
24 dstPath = false;
25 }
26 const output = fs.createWriteStream(zipFile);
27 const archive = archiver('zip', {
28 zlib: { level: 9 } // Sets the compression level.
29 });
30
31 return new Promise((resolve, reject) => {
32 output.on('close', function() {
33 return resolve();
34 });
35
36 archive.on('warning', function(err) {
37 if (err.code === 'ENOENT') {
38 console.log(err);
39 }
40 else {
41 return reject(err);
42 }
43 });
44
45 archive.on('error', function(err) {
46 return reject(err);
47 });
48
49 archive.pipe(output);
50
51 srcList.forEach((src) => {
52 const stat = fs.lstatSync(src);
53
54 if (stat.isFile()) {
55 archive.file(src);
56 }
57 else if (stat.isDirectory() || stat.isSymbolicLink()) {
58 archive.directory(src, dstPath);
59 }
60 else {
61 return reject(new Error('Invalid path'));
62 }
63 });
64
65 archive.finalize();
66 });
67}
68
69/**
70 * Executes shell commands synchronously and logs the
71 * stdout to console.
72 * @param {String} cmd Bash command
73 * @param {Boolean} [verbose=true] whether to post stdout to console
74 * @return {Buffer} The command's stdout in for of Buffer
75 */
76function exec(cmd, verbose) {
77 verbose = verbose === false ? verbose : true;
78
79 const stdout = execSync(cmd);
80 if (verbose) {
81 console.log(stdout.toString());
82 }
83 return stdout;
84}
85
86/**
87 * Updates region of an AWS configuration and point to the correct
88 * of profile on ~/.aws/credentials file if necessary
89 *
90 * @param {String} [region='us-east-1'] AWS region
91 * @param {String} [profile=null] aws credentials profile name
92 */
93function configureAws(region, profile, role) {
94 if (region) {
95 AWS.config.update({ region });
96 }
97
98 if (profile) {
99 AWS.config.credentials = new AWS.SharedIniFileCredentials({
100 profile
101 });
102 }
103
104 if (role) {
105 AWS.config.credentials = new AWS.TemporaryCredentials({
106 RoleArn: role
107 });
108 }
109}
110
111function loadLocalEnvs(envFile) {
112 let _dotenv;
113 try {
114 _dotenv = dotenv.parse(fs.readFileSync(envFile));
115 }
116 catch (e) {
117 if (!e.message.includes('ENOENT')) {
118 throw e;
119 }
120 }
121
122 // load all env variables to an object
123 return Object.assign(process.env, _dotenv);
124}
125
126function getZipName(handler) {
127 return handler.split('.')[0];
128}
129
130/**
131 * Checks if the input is a file, if it is a file,
132 * it reads it and return the content, otherwise just pass
133 * the input as an output
134 *
135 * @param {String} file A file path or a string
136 * @returns {String} String content of a given file
137 */
138
139function fileToString(file) {
140 try {
141 const stat = fs.lstatSync(file);
142
143 if (stat.isFile()) {
144 const content = fs.readFileSync(file, 'utf8');
145 return content.toString();
146 }
147 }
148 catch (e) {
149 if (!e.message.includes('ENOENT') && !e.message.includes('name too long, lstat')) {
150 throw e;
151 }
152 }
153 return file;
154}
155
156/**
157 * Merges two yaml files. The merge is done using lodash.merge
158 * and it happens recursively. Meaning that values of file2 will
159 * replace values of file 1 if they have the same key.
160 *
161 * @param {String} file1 Yaml path to file 1 or file 1 string
162 * @param {String} file2 Yaml path to file 2 or file 2 string
163 * @returns {String} Merged Yaml file in string format
164 */
165
166function mergeYamls(file1, file2) {
167 const obj1 = yaml.safeLoad(fileToString(file1), { schema: yamlfiles.YAML_FILES_SCHEMA });
168 const obj2 = yaml.safeLoad(fileToString(file2), { schema: yamlfiles.YAML_FILES_SCHEMA });
169
170 return yaml.safeDump(merge({}, obj1, obj2));
171}
172
173/**
174 * Based on the information passed from the CLI by the commander
175 * module this function determines whether to use the default Kes class
176 * or use the override class provided by the user
177 * @param {object} options The options passed by the commander library
178 * @param {Class} Kes the default kes class
179 * @returns {Class} Kes class
180 */
181function determineKesClass(options, Kes) {
182 // if there is a kes class specified use that
183 const kesClass = get(options, 'kesClass');
184 if (kesClass) {
185 Kes = require(`${path.join(process.cwd(), kesClass)}`);
186 }
187 else {
188 // check if there is kes.js in the kes-folder
189 try {
190 let kesFolder;
191 if (options.kesFolder) {
192 kesFolder = options.kesFolder;
193 }
194 else {
195 kesFolder = path.join(process.cwd(), '.kes');
196 }
197 Kes = require(`${path.join(process.cwd(), kesFolder, 'kes.js')}`);
198 }
199 catch (e) {
200 // check if there is a template and the template has kes class
201 const template = get(options, 'template', '/path/to/nowhere');
202 try {
203 const kesPath = path.join(process.cwd(), template, 'kes.js');
204 fs.lstatSync(kesPath);
205 Kes = require(`${kesPath}`);
206 }
207 catch (e) {
208 // do nothing
209 }
210 }
211 }
212
213 return Kes;
214}
215
216/**
217 * In case of error logs the error and exit with error 1
218 * @param {Error} e error object
219 */
220function failure(e) {
221 if (e.message) {
222 console.log(e.message);
223 }
224 else {
225 console.log(e);
226 }
227 process.exit(1);
228}
229
230/**
231 * Exists the process when called
232 */
233function success() {
234 process.exit(0);
235}
236
237/**
238 * Discover and returns the system bucket used for deployment
239 *
240 * @param {Object} config - cumulus config object
241 * @returns {string} name of the bucket
242 */
243function getSystemBucket(config) {
244 let bucket = get(config, 'buckets.internal');
245 if (bucket && typeof bucket === 'string') {
246 return bucket;
247 }
248
249 bucket = get(config, 'system_bucket');
250 if (bucket && typeof bucket === 'string') {
251 return bucket;
252 }
253 return undefined;
254}
255
256module.exports = {
257 exec,
258 mergeYamls,
259 fileToString,
260 getZipName,
261 configureAws,
262 loadLocalEnvs,
263 determineKesClass,
264 getSystemBucket,
265 failure,
266 success,
267 zip
268};