forceios 9.2.0

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.
@@ -0,0 +1,453 @@
1
+ /*
2
+ * Copyright (c) 2016-present, salesforce.com, inc.
3
+ * All rights reserved.
4
+ * Redistribution and use of this software in source and binary forms, with or
5
+ * without modification, are permitted provided that the following conditions
6
+ * are met:
7
+ * - Redistributions of source code must retain the above copyright notice, this
8
+ * list of conditions and the following disclaimer.
9
+ * - Redistributions in binary form must reproduce the above copyright notice,
10
+ * this list of conditions and the following disclaimer in the documentation
11
+ * and/or other materials provided with the distribution.
12
+ * - Neither the name of salesforce.com, inc. nor the names of its contributors
13
+ * may be used to endorse or promote products derived from this software without
14
+ * specific prior written permission of salesforce.com, inc.
15
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
16
+ * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
17
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
18
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
19
+ * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
20
+ * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
21
+ * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
22
+ * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
23
+ * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
24
+ * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
25
+ * POSSIBILITY OF SUCH DAMAGE.
26
+ */
27
+
28
+ var shelljs = require('shelljs'),
29
+ execSync = require('child_process').execSync,
30
+ fs = require('fs'),
31
+ path = require('path'),
32
+ COLOR = require('./outputColors');
33
+
34
+ var LOG_LEVELS = {
35
+ OFF: 0,
36
+ FATAL: 100,
37
+ ERROR: 200,
38
+ WARN: 300,
39
+ INFO: 400,
40
+ DEBUG: 500,
41
+ TRACE: 600,
42
+ ALL: Number.MAX_SAFE_INTEGER
43
+ };
44
+
45
+ var LOG_LEVEL = LOG_LEVELS.INFO;
46
+
47
+ var exitOnFailure = false;
48
+
49
+ /**
50
+ * Set log level
51
+ *
52
+ * @param {int} logLevel
53
+ */
54
+ function setLogLevel(logLevel) {
55
+ LOG_LEVEL = logLevel;
56
+ }
57
+
58
+ /**
59
+ * Creates a comparable version number from a version string in the format x[.y[.ignored]].
60
+ * Currently only looks for major and minor version numbers.
61
+ *
62
+ * Examples:
63
+ * getVersionNumberFromString('5') will return 5000.
64
+ * getVersionNumberFromString('5.8') will return 5008
65
+ * getVersionNumberFromString('5.11.26-43.3.7') will return 5011
66
+ * getVersionNumberFromString('sandwich') will log an error and return 0
67
+ *
68
+ * @param {String} versionString The string representation of the version.
69
+ * @return {Number} The numeric version number, or 0 if the version string isn't a valid format.
70
+ */
71
+ function getVersionNumberFromString(versionString) {
72
+ // Only supporting major/minor version checking at this point.
73
+ var versionRegex = new RegExp(/^[^\d]*(\d+)(\.(\d+))?(\.(\d+))?/, 'm');
74
+ var matchArray = versionString.match(versionRegex);
75
+ if (matchArray === null) {
76
+ log(LOG_LEVELS.WARN, 'Invalid version string "' + versionString + '". Should be in the format x[.y[.z[.ignored]]]');
77
+ return 0;
78
+ } else {
79
+ var majorVersion = parseInt(matchArray[1]);
80
+ var minorVersion = (matchArray[3] === undefined ? 0 : parseInt(matchArray[3]));
81
+ var patchVersion = (matchArray[5] === undefined ? 0 : parseInt(matchArray[5]));
82
+ var combinedVersion = (1000000 * majorVersion) + (1000 * minorVersion) + patchVersion;
83
+ return combinedVersion;
84
+ }
85
+ }
86
+
87
+ /**
88
+ * Checks the the version of a tool by running the given command
89
+ *
90
+ * @param {String} cmd Command to run to get the tool version
91
+ * @param {String} minVersionRequired Minimum version required
92
+ * @param {String} maxVersionSupported Maximum version supported
93
+ *
94
+ * @throws {Error} if tool not found or version too low
95
+ */
96
+ function checkToolVersion(cmd, minVersionRequired, maxVersionSupported) {
97
+ var toolName = cmd.split(' ')[0];
98
+ var toolVersion;
99
+ try {
100
+ var result = runProcessThrowError(cmd, null, true /* return output */);
101
+ toolVersion = result.replace(/\r?\n|\r/, '').replace(/[^0-9\.]*/, '');
102
+ }
103
+ catch (error) {
104
+ throw new Error(toolName + ' is required but could not be found. Please install ' + toolName + '.');
105
+ }
106
+
107
+ var toolVersionNum = getVersionNumberFromString(toolVersion);
108
+ var minVersionRequiredNum = getVersionNumberFromString(minVersionRequired);
109
+
110
+ if (toolVersionNum < minVersionRequiredNum) {
111
+ throw new Error('Installed ' + toolName + ' version (' + toolVersion + ') is less than the minimum required version ('
112
+ + minVersionRequired + '). Please update your version of ' + toolName + '.');
113
+ }
114
+
115
+ if (maxVersionSupported) {
116
+ var maxVersionSupportedNum = getVersionNumberFromString(maxVersionSupported);
117
+ if (toolVersionNum > maxVersionSupportedNum) {
118
+ throw new Error('Installed ' + toolName + ' version (' + toolVersion + ') is more than the maximum supported version ('
119
+ + maxVersionSupported + '). Please downgrade your version of ' + toolName + '.');
120
+ }
121
+ }
122
+ }
123
+
124
+
125
+ /**
126
+ * Replaces text in a file
127
+ *
128
+ * @param {String} fileName The file in which the text needs to be replaced.
129
+ * @param {String} textInFile Text in the file to be replaced.
130
+ * @param {String} replacementText Text used to replace the text in file.
131
+ */
132
+ function replaceTextInFile(fileName, textInFile, replacementText) {
133
+ var contents = fs.readFileSync(fileName, 'utf8');
134
+ var lines = contents.split(/\r*\n/);
135
+ var result = lines.map(function (line) {
136
+ return line.replace(textInFile, replacementText);
137
+ }).join('\n');
138
+
139
+ fs.writeFileSync(fileName, result, 'utf8');
140
+ }
141
+
142
+
143
+ /**
144
+ * Run shell command - throws error if any
145
+ *
146
+ * @param {String} cmd The command to execute.
147
+ * @param {String} dir Optional. The directory the command should be executed in.
148
+ * @param {Boolean} returnOutput. If true, returns output as string. If false, pipes output through.
149
+ */
150
+ function runProcessThrowError(cmd, dir, returnOutput) {
151
+ logDebug('Running: ' + cmd);
152
+ if (returnOutput) {
153
+ return execSync(cmd, {cwd: dir}).toString();
154
+ }
155
+ else {
156
+ var stdio = [];
157
+ if (LOG_LEVEL >= LOG_LEVELS.DEBUG) {
158
+ stdio = [0,1,2]
159
+ }
160
+ else if (LOG_LEVEL >= LOG_LEVELS.ERROR) {
161
+ stdio = [0,2]
162
+ }
163
+
164
+ execSync(cmd, {cwd: dir, stdio: stdio});
165
+ }
166
+ }
167
+
168
+ /**
169
+ * Run shell command - catch error if any (unless setExitOnFailure(true) was called)
170
+ *
171
+ * @param {String} cmd The command to execute.
172
+ * @param {String} msg Message to print on success/failure.
173
+ * @param {String} dir Optional. The directory the command should be executed in.
174
+ *
175
+ * @return true if successful, false otherwise
176
+ */
177
+ function runProcessCatchError(cmd, msg, dir) {
178
+ var success = false;
179
+ logDebug('Running: ' + cmd);
180
+ try {
181
+ runProcessThrowError(cmd, dir);
182
+ if (msg) logInfo('!SUCCESS! ' + msg, COLOR.green);
183
+ success = true;
184
+ } catch (err) {
185
+ logError(msg ? '!FAILURE! ' + msg : '', err);
186
+ if (exitOnFailure) {
187
+ process.exit(1);
188
+ }
189
+ }
190
+ finally {
191
+ return success;
192
+ }
193
+ }
194
+
195
+ /**
196
+ * Run function - throws error if any
197
+ *
198
+ * @param {Function} func The function to execute.
199
+ * @param {String} dir Optional. The directory the function should be executed from.
200
+ */
201
+ function runFunctionThrowError(func, dir) {
202
+ if (dir) shelljs.pushd(dir);
203
+ try {
204
+ return func();
205
+ }
206
+ finally {
207
+ if (dir) shelljs.popd();
208
+ }
209
+ }
210
+
211
+ /**
212
+ * Makes temp directory.
213
+ *
214
+ * @return {String} Path of temp directory
215
+ */
216
+
217
+ function mkTmpDir() {
218
+ var d = new Date();
219
+ var timestamp = new Date(d.getTime() - 1000*60*d.getTimezoneOffset()).toISOString().replace(/[^0-9T.]/g, ''); // e.g. 20190510T134348.528 for Fri May 10 2019 13:43:48 GMT-0700 (Pacific Daylight Time)
220
+ var tmpDir = path.resolve('tmp' + timestamp);
221
+ logDebug('Making temp dir:' + tmpDir);
222
+ shelljs.mkdir('-p', tmpDir);
223
+ return tmpDir;
224
+ }
225
+
226
+ /**
227
+ * Make directory if it does not exist
228
+ *
229
+ * @param {string} Path of directory to create
230
+ */
231
+ function mkDirIfNeeded(dir) {
232
+ if (dir != '') {
233
+ shelljs.mkdir('-p', dir);
234
+ }
235
+ }
236
+
237
+ /**
238
+ * Replace string in files.
239
+ *
240
+ * @param {String or RegExp} from String to match.
241
+ * @param {String} to Replacement string.
242
+ * @param {Array} files List of files to do the replacements in.
243
+ */
244
+ function replaceInFiles(from, to, files) {
245
+ var fromRegexp = typeof(from) === 'string' ? new RegExp(from, 'g') : from;
246
+ for (var i=0; i<files.length; i++) {
247
+ logDebug('Replacing ' + from + ' with ' + to + ' in: ' + files[i]);
248
+ replaceTextInFile(files[i], fromRegexp, to);
249
+ }
250
+ }
251
+
252
+ /**
253
+ * Move file or directory.
254
+ *
255
+ * @param {String} from Path of file or directory to move.
256
+ * @param {String} to New path for file or directory.
257
+ */
258
+ function moveFile(from, to) {
259
+ logDebug('Moving: ' + from + ' to ' + to);
260
+ mkDirIfNeeded(path.parse(to).dir);
261
+ shelljs.mv(from, to);
262
+ }
263
+
264
+ /**
265
+ * Check there is a directory with given path
266
+ * @param {String} path of dir
267
+ */
268
+ function dirExists(path) {
269
+ return shelljs.test('-d', path);
270
+ }
271
+
272
+ /**
273
+ * Copy recursively.
274
+ *
275
+ * @param {String} from Path of file or directory to copy.
276
+ * @param {String} to New path for file or directory.
277
+ */
278
+ function copyFile(from, to) {
279
+ logDebug('Copying: ' + from + ' to ' + to);
280
+ shelljs.cp('-R', from, to);
281
+ }
282
+
283
+ /**
284
+ * Merge recursively.
285
+ * Like copyFile except that it will merge into existing directories.
286
+ *
287
+ * @param {String} from Path of file or directory to move.
288
+ * @param {String} to New path for file or directory.
289
+ */
290
+ function mergeFile(from, to) {
291
+ logDebug('Merging: ' + from + ' to ' + to);
292
+ shelljs.find(from).forEach(function(srcPath) {
293
+ var relativePath = path.relative(from, srcPath)
294
+ if(shelljs.test('-f', srcPath)) {
295
+ shelljs.cp(path.join(from, relativePath), path.join(to, relativePath));
296
+ } else {
297
+ shelljs.mkdir('-p', path.join(to, relativePath));
298
+ }
299
+ })
300
+ }
301
+
302
+
303
+ /**
304
+ * Remove file or directory.
305
+ *
306
+ * @param {String} path Path of file or directory to remove.
307
+ */
308
+ function removeFile(path) {
309
+ logDebug('Removing: ' + path);
310
+ shelljs.rm('-rf', path);
311
+ }
312
+
313
+ /**
314
+ * Separate repo url / path / branch from url of the form https://server/org/repo/path#branch or https://server/org/repo#branch or https://server/org/repo
315
+ * @param {String} Full url
316
+ * @return map with repo / path /branch {repo:https://server/org/repo, branch:branch, path:path}
317
+ */
318
+ function separateRepoUrlPathBranch(fullUrl) {
319
+ var parts = fullUrl.split('#');
320
+ var repoWithPath = parts[0];
321
+ var branch = parts.length > 1 ? parts[1] : 'master';
322
+ var repo = repoWithPath.split('/').splice(0,5).join('/');
323
+ var path = repoWithPath.split('/').splice(5).join('/');
324
+ return {repo:repo, branch:branch, path:path};
325
+ }
326
+
327
+ /**
328
+ * Clone repo.
329
+ *
330
+ * @param {String} tmpDir Parent dir for clone
331
+ * @param {String} repoUrlWithBranch Repo URL e.g. https://github.com/xyz/abc or https://github.com/xyz/abc#branch
332
+ *
333
+ * @return repoDir
334
+ */
335
+
336
+ function cloneRepo(tmpDir, repoUrlWithBranch) {
337
+ var parts = repoUrlWithBranch.split('#');
338
+ var repoUrl = parts[0];
339
+ var branch = parts.length > 1 ? parts[1] : 'master';
340
+ var subparts = repoUrl.split('/');
341
+ var repoName = subparts[subparts.length - 1];
342
+ var repoDir = path.join(tmpDir, repoName);
343
+
344
+ shelljs.mkdir('-p', repoDir);
345
+ runProcessThrowError('git clone --branch ' + branch + ' --single-branch --depth 1 --recurse-submodules ' + repoUrl + ' ' + '"' + repoDir + '"');
346
+ return repoDir;
347
+ }
348
+
349
+ /**
350
+ * Log paragraph (header or footer)
351
+ *
352
+ * @param {String} lines
353
+ */
354
+ function logParagraph(lines, color) {
355
+ color = color || COLOR.green;
356
+ logInfo("");
357
+ logInfo("********************************************************************************", color);
358
+ logInfo("*", color);
359
+ for (var i=0; i<lines.length; i++) {
360
+ logInfo("* " + lines[i], color);
361
+ }
362
+ logInfo("*", color);
363
+ logInfo("********************************************************************************", color);
364
+ logInfo("");
365
+ }
366
+
367
+ /**
368
+ * Log error
369
+ *
370
+ * @param {String} context
371
+ * @param {Error} error
372
+ */
373
+ function logError(context, error) {
374
+ log(LOG_LEVELS.ERROR, context, COLOR.red)
375
+ if (error) {
376
+ log(LOG_LEVELS.ERROR, error.message, COLOR.red);
377
+ logDebug(error.stack);
378
+ }
379
+ }
380
+
381
+ /**
382
+ * Log info
383
+ *
384
+ * @param {String} msg Message to log.
385
+ * @param {String} color Color to use.
386
+ */
387
+ function logInfo(msg, color) {
388
+ log(LOG_LEVELS.INFO, msg, color);
389
+ }
390
+
391
+ /**
392
+ * Log debug
393
+ *
394
+ * @param {String} msg Message to log.
395
+ * @param {String} color Color to use.
396
+ */
397
+ function logDebug(msg, color) {
398
+ log(LOG_LEVELS.DEBUG, msg, color);
399
+ }
400
+
401
+
402
+ /**
403
+ * Log in color.
404
+ *
405
+ * @param {integer} logLevel Max LOG_LEVEL for which the message should be logged
406
+ * @param {String} msg Message to log.
407
+ * @param {String} color Color to use.
408
+ */
409
+ function log(logLevel, msg, color) {
410
+ if (logLevel <= LOG_LEVEL) {
411
+ if (color) {
412
+ console.log(color + msg + COLOR.reset);
413
+ }
414
+ else {
415
+ console.log(msg);
416
+ }
417
+ }
418
+ }
419
+
420
+ /**
421
+ * Set behavior when running shell processes
422
+ *
423
+ * @param {Boolean} exitOFailure - pass true to exit on shell process execution failure (default is false)
424
+ */
425
+ function setExitOnFailure(b) {
426
+ exitOnFailure = b;
427
+ }
428
+
429
+ module.exports = {
430
+ LOG_LEVELS,
431
+ checkToolVersion,
432
+ cloneRepo,
433
+ copyFile,
434
+ dirExists,
435
+ getVersionNumberFromString,
436
+ log,
437
+ logDebug,
438
+ logError,
439
+ logInfo,
440
+ logParagraph,
441
+ mergeFile,
442
+ mkTmpDir,
443
+ mkDirIfNeeded,
444
+ moveFile,
445
+ setLogLevel,
446
+ removeFile,
447
+ replaceInFiles,
448
+ runFunctionThrowError,
449
+ runProcessCatchError,
450
+ runProcessThrowError,
451
+ separateRepoUrlPathBranch,
452
+ setExitOnFailure
453
+ };