switch-profile 1.1.0 → 2.0.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/src/core.js DELETED
@@ -1,64 +0,0 @@
1
- require('colors')
2
- const { error: { catchErrors } } = require('puffy')
3
- const { exec } = require('child_process')
4
-
5
- const IS_WINDOWS = process.platform == 'win32'
6
-
7
- const _exec = cmd => new Promise((next,fail) => {
8
- exec(cmd, (error, stdout, stderr) => {
9
- if (error || stderr)
10
- fail(error || stderr)
11
- else
12
- next(stdout)
13
- })
14
- })
15
-
16
- const _commandExistsResult = {}
17
- const isCommandExist = (cmd, errorMsg) => () => catchErrors((async () => {
18
- if (!cmd)
19
- return false
20
-
21
- if (_commandExistsResult[cmd] !== undefined)
22
- return _commandExistsResult[cmd]
23
-
24
- const testCmd = IS_WINDOWS ? 'where' : 'which'
25
- const data = await _exec(`${testCmd} ${cmd}`).catch(() => false)
26
-
27
- if (!data)
28
- throw new Error(`Command ${cmd} not found${errorMsg ? `. ${errorMsg}` : ''}`)
29
-
30
- _commandExistsResult[cmd] = true
31
- return true
32
- })())
33
-
34
- /**
35
- *
36
- * @param {[Error]} errors
37
- * @param {Boolean} options.noStack
38
- * @return {String}
39
- */
40
- const formatErrorMsg = (errors, options) => {
41
- if (!errors || !errors.length)
42
- return ''
43
-
44
- const noStack = options && options.noStack
45
- const msg = errors.map(e => noStack ? e.message||'' : e.stack||e.message||'').join('\n')
46
- const prefix = /^error/.test(msg.toLowerCase().trim()) ? '' : 'ERROR - '
47
- return `${prefix}${msg}`
48
- }
49
-
50
- const printErrors = (errors, options) => console.log(formatErrorMsg(errors, options).red)
51
- const printAWSerrors = (errors, options) => {
52
- let msg = formatErrorMsg(errors, options)
53
- if (msg.indexOf('ommand aws not found') >= 0)
54
- msg += `\n\nTo fix this issue, try installing the ${'aws CLI'.bold}`
55
-
56
- console.log(msg.red)
57
- }
58
-
59
- module.exports = {
60
- exec: _exec,
61
- isCommandExist,
62
- printErrors,
63
- printAWSerrors
64
- }
package/src/fileHelper.js DELETED
@@ -1,433 +0,0 @@
1
-
2
- /**
3
- * Copyright (c) 2017-2020, Neap Pty Ltd.
4
- * All rights reserved.
5
- *
6
- * This source code is licensed under the BSD-style license.
7
- */
8
-
9
- // npm i rimraf fast-glob core-async mime-types archiver tar-stream convert-stream
10
- const { co } = require('core-async')
11
- const fs = require('fs')
12
- const { join, resolve } = require('path')
13
- const rimraf = require('rimraf')
14
- const fg = require('fast-glob')
15
- const mime = require('mime-types')
16
- const archiver = require('archiver')
17
- const tar = require('tar-stream')
18
- const { toBuffer } = require('convert-stream')
19
- const { Writable } = require('stream')
20
-
21
- /**
22
- * Checks if a file or folder exists
23
- *
24
- * @param {String} filePath Absolute path to file or folder on the local machine
25
- * @return {Boolean}
26
- */
27
- const fileExists = filePath => new Promise(onSuccess => fs.exists(filePath, yes => onSuccess(yes ? true : false)))
28
-
29
- /**
30
- * Creates a folder.
31
- *
32
- * @param {String} folderPath Absolute folder path on the local machine
33
- * @return {Object}
34
- */
35
- const createFolder = folderPath => new Promise((onSuccess, onFailure) => fs.mkdir(folderPath, err => {
36
- if (!err || (err.message || '').indexOf('file already exists') >= 0)
37
- onSuccess(folderPath)
38
- else
39
- onFailure(err)
40
- }))
41
-
42
- /**
43
- * Deletes a folder.
44
- *
45
- * @param {String} folderPath Absolute folder path on the local machine
46
- * @return {Void}
47
- */
48
- const deleteFolder = folderPath => new Promise(onSuccess => rimraf(folderPath, () => onSuccess()))
49
-
50
- /**
51
- * Deletes a file.
52
- *
53
- * @param {String} filePath Absolute file path on the local machine
54
- * @return {Void}
55
- */
56
- const deleteFile = filePath => new Promise((onSuccess, onFailure) => fs.unlink(filePath, err => err ? onFailure(err) : onSuccess()))
57
-
58
- /**
59
- * Creates file or update file located under 'filePath'.
60
- *
61
- * @param {String} filePath Absolute file path on the local machine
62
- * @param {Object} content File content
63
- * @param {Boolean} options.append Default false. If true, this function appends rather than overrides.
64
- * @param {String} options.appendSep Default '\n'. That the string used to separate appended content. This option is only
65
- * active when 'options.append' is set to true.
66
- * @return {Void}
67
- */
68
- const writeToFile = (filePath, content, options) => new Promise((onSuccess, onFailure) => {
69
- content = content || ''
70
- const { append, appendSep='\n' } = options || {}
71
- const stringContent = (typeof(content) == 'string' || content instanceof Buffer) ? content : JSON.stringify(content, null, ' ')
72
- const fn = append ? fs.appendFile : fs.writeFile
73
- fn(filePath, append ? `${stringContent}${appendSep}` : stringContent, err => err ? onFailure(err) : onSuccess())
74
- })
75
-
76
- /**
77
- * Creates folders under a rootFolder
78
- *
79
- * @param {String} rootFolder Root folder. This folder must exist prior to calling this function.
80
- * @param {Array} folders Array of folders so that the path of the last item in that array will be:
81
- * rootFolder/folders[0]/folders[1]/.../folders[n]
82
- * @param {Object} options
83
- * @param {Boolean} options.deletePreviousContent If set to true, this will delete the content of the existing folder
84
- * @return {String} Path of the latest folder:
85
- * rootFolder/folders[0]/folders[1]/.../folders[n]
86
- */
87
- const createFolders = (rootFolder, folders=[], options={}) => co(function *() {
88
- const { deletePreviousContent } = options
89
- if (!rootFolder)
90
- throw new Error('\'rootFolder\' is required.')
91
- const rootExists = yield fileExists(rootFolder)
92
- if (!rootExists)
93
- throw new Error(`Root folder ${rootFolder} does not exist.`)
94
-
95
- yield folders.reduce((processPrevious, f) => co(function *(){
96
- const rootPath = yield processPrevious
97
- const folderPath = join(rootPath, f)
98
- const folderExists = yield fileExists(folderPath)
99
- if (folderExists && deletePreviousContent)
100
- yield deleteFolder(folderPath)
101
- else if (!folderExists)
102
- yield createFolder(folderPath)
103
- return folderPath
104
- }), Promise.resolve(rootFolder))
105
- })
106
-
107
- /**
108
- * Gets a file under a Google Cloud Storage's 'filePath'.
109
- *
110
- * @param {String} filePath Absolute file path on the local machine
111
- * @return {Buffer}
112
- */
113
- const readFile = filePath => new Promise((onSuccess, onFailure) => fs.readFile(filePath, (err, data) => err ? onFailure(err) : onSuccess(data)))
114
-
115
- //
116
- // Gets an array of absolute file paths located under the 'folderPath', or a Channel that streams those files.
117
- //
118
- // @param {String} folderPath Absolute path to folder
119
- // @param {String|[String]} options.pattern Default is '*.*' which means all immediate files. To get all the files
120
- // use '**/*.*'
121
- // @param {String|[String]} options.ignore e.g., '**/node_modules/**'
122
- // @param {Channel} options.channel When a channel is passed, all files are streamed to that channel instead of
123
- // being returned as an array. The last file found add a specific string on
124
- // the channel to indicates that the scan is over. That string value is: 'end'.
125
- // @return {[String]} If a channel is passed via 'options.channel', than the output is null and
126
- // the files are streamed to that channel.
127
- //
128
- const listFiles = (folderPath='', options={}) => co(function *(){
129
- const pattern = options.pattern || '*.*'
130
- const ignore = options.ignore
131
- const channel = options.channel
132
- const patterns = (typeof(pattern) == 'string' ? [pattern] : pattern).map(p => join(folderPath, p))
133
- const opts = ignore ? { ignore:(typeof(ignore) == 'string' ? [ignore] : ignore).map(p => join(folderPath, p)) } : {}
134
-
135
- if (!channel)
136
- return yield fg(patterns,opts)
137
- else {
138
- const stream = fg.stream(patterns,opts)
139
- stream.on('data', data => {
140
- channel.put(data)
141
- })
142
- stream.on('end', () => {
143
- channel.put('end')
144
- stream.destroy()
145
- })
146
- stream.on('error', err => {
147
- console.log(`An error happened while streaming files from ${folderPath}: ${err}`)
148
- stream.destroy()
149
- })
150
-
151
- return null
152
- }
153
- })
154
-
155
- /**
156
- * Gets the absolute path. If not input is passed, it returns the current working directory. Supports both Windows and Unix OSes.
157
- *
158
- * @param {String} somePath Some absolute or relative file or folder path.
159
- * @return {String} Absolute path
160
- */
161
- const getAbsolutePath = somePath => {
162
- if (!somePath)
163
- return process.cwd()
164
- else if (somePath.match(/^\./))
165
- return resolve(somePath)
166
- else if (somePath.match(/^(\\|\/|~)/))
167
- return somePath
168
- else if (typeof(somePath) == 'string')
169
- return resolve(somePath)
170
- else
171
- throw new Error(`Invalid path ${somePath}`)
172
- }
173
-
174
- /**
175
- * Gets a JSON object loacted under 'filePath'. This method is an alternative to 'require(filePath)' which caches results and prevents
176
- * to get access to a refreshed version of the JSON file.
177
- *
178
- * @param {String} filePath Absolute path to the JSON file.
179
- * @param {String} defaultValue Default is {}
180
- *
181
- * @return {Object} JSON Object
182
- */
183
- const getJSON = (filePath, defaultValue={}) => readFile(filePath).then(text => {
184
- if (!text || !text.length)
185
- return defaultValue
186
-
187
- try {
188
- return JSON.parse(text.toString()) || defaultValue
189
- } catch(e) {
190
- return (() => ({}))(e)
191
- }
192
- })
193
-
194
- const _isFolder = folderPath => new Promise(resolve => fs.stat(folderPath, (err,data) => resolve(err || !data || !data.isDirectory ? false : data.isDirectory())))
195
- const _readdir = folderPath => new Promise(resolve => fs.readdir(folderPath, (err,data) => resolve(err || !data ? [] : data)))
196
- const _rmdir = folderPath => new Promise(resolve => fs.rmdir(folderPath, resolve))
197
-
198
- /**
199
- * Deletes all the empty folders(incl. 'rootFolder') under 'rootFolder'.
200
- *
201
- * @param {String} rootFolder Absolute path to folder.
202
- * @yield {Void}
203
- */
204
- const deleteEmptyFolders = rootFolder => co(function *(){
205
- const isDir = yield _isFolder(rootFolder)
206
- if (!isDir)
207
- return
208
-
209
- let files = yield _readdir(rootFolder)
210
- yield files.map(file => co(function *(){
211
- const fullPath = join(rootFolder, file)
212
- yield deleteEmptyFolders(fullPath)
213
- }))
214
-
215
- // re-evaluate files; after deleting subfolder
216
- // we may have parent folder empty now
217
- if (files.length > 0)
218
- files = yield _readdir(rootFolder)
219
-
220
- if (files.length == 0)
221
- yield _rmdir(rootFolder)
222
- })
223
-
224
- /**
225
- * Gets the mime type associated with a file extension.
226
- *
227
- * @param {String} fileOrExt e.g., 'json', '.md', 'file.html', 'folder/file.js', 'data:image/png;base64,....'
228
- * @return {String} e.g., 'application/json', 'text/markdown', 'text/html', 'application/javascript'
229
- */
230
- const getMimeType = fileOrExt => {
231
- if (!fileOrExt)
232
- return ''
233
-
234
- // Test if 'fileOrExt' is a data URI
235
- if (/^data:(.*?),/.test(fileOrExt))
236
- return (fileOrExt.match(/^data:(.*?);/, '') || [])[1] || ''
237
-
238
- return mime.lookup(fileOrExt) || ''
239
- }
240
-
241
- /**
242
- * Gets the content type associated with a file extension.
243
- *
244
- * @param {String} fileOrExt e.g., 'json', '.md', 'file.html', 'folder/file.js'
245
- * @return {String} e.g., 'application/json; charset=utf-8', 'text/x-markdown; charset=utf-8', 'text/html; charset=utf-8'
246
- */
247
- const getContentType = fileOrExt => !fileOrExt ? '' : (mime.contentType(fileOrExt) || '')
248
-
249
- /**
250
- * Gets the a file's extension or the file extension associated with a mime type.
251
- *
252
- * @param {String} mimeType e.g., 'application/json', 'text/x-markdown', 'hello.pdf'
253
- * @return {String} e.g., 'json', 'md', 'pdf'
254
- */
255
- const getExt = fileOrMimeType => {
256
- if (!fileOrMimeType)
257
- return ''
258
-
259
- const t = fileOrMimeType.split('.')
260
- const [ext] = t[1] ? t.slice(-1) : [null]
261
- let x
262
- if (!ext && fileOrMimeType.indexOf('/') >= 0)
263
- x = mime.extension(fileOrMimeType) || ''
264
- else
265
- x = ext
266
-
267
- return x == 'document' ? 'doc' : x
268
- }
269
-
270
- /**
271
- * Get
272
- *
273
- * @param {String} mimeType e.g., 'image/png'
274
- * @return {String} output.type e.g., 'image'
275
- * @return {String} output.type e.g., 'png'
276
- */
277
- const getFileType = mimeType => {
278
- if (!mimeType)
279
- throw new Error('Missing required argument \'mimeType\'.')
280
-
281
- const [type,subType] = mimeType.split('/')
282
-
283
- return {
284
- type,
285
- subType
286
- }
287
- }
288
-
289
- /**
290
- * Formats file name to make sure it contains a name and an extension.
291
- *
292
- * @param {String} mimeType e.g., 'application/json'
293
- * @param {String} fileName e.g., 'blob' or null
294
- * @param {String} defaultName e.g., '12345' (if the value contains an extension, that extension overides the 'mimeType').
295
- *
296
- * @return {String} output.fileName e.g., 'blob.json' or '12345.json'
297
- * @return {String} output.mimeType e.g., 'application/json'
298
- */
299
- const getCanonicalFile = ({ mimeType, fileName, defaultName }) => {
300
- if (!fileName && !defaultName)
301
- throw new Error('Missing required argument. When \'fileName\' is not specified, \'defaultName\' is required.')
302
-
303
- const _fileName = fileName || defaultName
304
- const fileExt = getExt(_fileName)
305
-
306
- if (fileExt) {
307
- const _mimeType = getMimeType(_fileName) || mimeType
308
- if (!_mimeType)
309
- throw new Error(`Failed to determine the mime type for file ${_fileName}.`)
310
-
311
- return { ...getFileType(_mimeType), fileName: _fileName, mimeType:_mimeType }
312
- }
313
-
314
- if (!mimeType)
315
- throw new Error('Missing required argument. When \'fileName\' and \'defaultName\' don\'t contain an extension, \'mimeType\' is required.')
316
-
317
- const mimeExt = getExt(mimeType)
318
- if (!mimeExt)
319
- throw new Error(`Failed to determine the extension of mime type ${mimeType}.`)
320
-
321
- return { ...getFileType(mimeType), fileName:`${_fileName}.${mimeExt}`, mimeType }
322
- }
323
-
324
- /**
325
- * Changes the file extension based on the mime type.
326
- *
327
- * @param {String} fileName e.g., 'hello.jpeg'
328
- * @param {String} mimeType e.g., 'image/png'
329
- * @return {String} e.g., 'hello.png'
330
- */
331
- const changeFileExt = (fileName, mimeType) => {
332
- if (!fileName || !mimeType)
333
- return fileName
334
-
335
- let mimeExt = getExt(mimeType)
336
- if (!mimeExt)
337
- throw new Error(`Failed to determine the extension of mime type ${mimeType}.`)
338
- mimeExt = mimeExt == 'document' ? 'doc' : mimeExt
339
-
340
- return fileName.indexOf('.') < 0 ? `${fileName}.${mimeExt}` : fileName.replace(/\.(.*?)$/, `.${mimeExt}`)
341
- }
342
-
343
- /**
344
- * Zips a folder into a buffer using zip (default) or tar.
345
- *
346
- * @param {String} src Folder's absolute path on local machine.
347
- * @param {String} options.type Default 'zip'. Valid values are: 'zip', 'tar'
348
- * @return {Buffer}
349
- */
350
- const zipToBuffer = (src, options) => co(function *(){
351
- const result = yield fileExists(src)
352
-
353
- if (!result)
354
- throw new Error(`Failed to zip folder ${src}. This folder does not exist.`)
355
-
356
- const { type='zip' } = options || {}
357
-
358
- if (type == 'zip') {
359
- const archive = archiver('zip', { zlib: { level: 6 } }) // this goes from 1 (minimum compression) to 9 (default 6). The higher the compression, the longer it takes to zip and unzip.
360
- const getBuffer = toBuffer(archive)
361
-
362
- archive.on('warning', err => {
363
- console.log('Warning while creating zip file', err)
364
- })
365
-
366
- archive.on('error', err => {
367
- throw err
368
- })
369
-
370
- archive.directory(src, '/')
371
- archive.finalize()
372
-
373
- const buffer = yield getBuffer
374
-
375
- return buffer
376
- } else if (type == 'tar') {
377
- const files = yield listFiles(src, { pattern:'**/*.*' })
378
- const data = yield files.map(file => readFile(file, { encoding:null }).then(content => ({
379
- file,
380
- relFile: file.replace(src,''),
381
- content
382
- })))
383
-
384
- const pack = tar.pack()
385
- data.forEach(({ relFile, content }) => pack.entry({ name:relFile }, content))
386
- const chunks = []
387
- const writeStream = new Writable({
388
- write(chunk, encoding, callback) {
389
- chunks.push(chunk)
390
- callback()
391
- }
392
- })
393
-
394
- pack.pipe(writeStream)
395
- pack.finalize()
396
-
397
- yield new Promise((success) => pack.on('end', success))
398
-
399
- const buffer = Buffer.concat(chunks)
400
-
401
- return buffer
402
- } else
403
- throw new Error(`Unsupported zip type ${type}. Valid zip types: 'zip', 'tar'`)
404
- }).catch(e => {
405
- console.log(`Failed to zip folder ${src}`)
406
- throw e
407
- })
408
-
409
- module.exports = {
410
- list: listFiles,
411
- json: {
412
- 'get': getJSON,
413
- write: (filePath, obj) => writeToFile(filePath, obj)
414
- },
415
- read: readFile,
416
- write: writeToFile,
417
- exists: fileExists,
418
- delete: deleteFile,
419
- getAbsolutePath,
420
- folder: {
421
- create: createFolder,
422
- createMany: createFolders,
423
- delete: deleteFolder,
424
- deleteEmpties: deleteEmptyFolders
425
- },
426
- getMimeType,
427
- getContentType,
428
- getExt,
429
- getCanonicalFile,
430
- changeFileExt,
431
- getFileType,
432
- zipToBuffer
433
- }