@zappinginc/zm2 6.0.14

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.
Files changed (133) hide show
  1. package/.claude/settings.local.json +8 -0
  2. package/.gitattributes +4 -0
  3. package/.mocharc.js +14 -0
  4. package/CHANGELOG.md +2416 -0
  5. package/CLAUDE.md +84 -0
  6. package/CONTRIBUTING.md +124 -0
  7. package/GNU-AGPL-3.0.txt +665 -0
  8. package/LICENSE +1 -0
  9. package/README.md +248 -0
  10. package/bin/zm2 +3 -0
  11. package/bin/zm2-dev +3 -0
  12. package/bin/zm2-docker +3 -0
  13. package/bin/zm2-runtime +3 -0
  14. package/bin/zm2-windows +3 -0
  15. package/bin/zm2.ps1 +3 -0
  16. package/bun.lock +421 -0
  17. package/constants.js +114 -0
  18. package/index.js +13 -0
  19. package/lib/API/Configuration.js +212 -0
  20. package/lib/API/Containerizer.js +335 -0
  21. package/lib/API/Dashboard.js +459 -0
  22. package/lib/API/Deploy.js +117 -0
  23. package/lib/API/Extra.js +775 -0
  24. package/lib/API/ExtraMgmt/Docker.js +30 -0
  25. package/lib/API/Log.js +315 -0
  26. package/lib/API/LogManagement.js +371 -0
  27. package/lib/API/Modules/LOCAL.js +122 -0
  28. package/lib/API/Modules/Modularizer.js +148 -0
  29. package/lib/API/Modules/NPM.js +445 -0
  30. package/lib/API/Modules/TAR.js +362 -0
  31. package/lib/API/Modules/flagExt.js +46 -0
  32. package/lib/API/Modules/index.js +120 -0
  33. package/lib/API/Monit.js +247 -0
  34. package/lib/API/Serve.js +343 -0
  35. package/lib/API/Startup.js +629 -0
  36. package/lib/API/UX/helpers.js +213 -0
  37. package/lib/API/UX/index.js +9 -0
  38. package/lib/API/UX/pm2-describe.js +193 -0
  39. package/lib/API/UX/pm2-ls-minimal.js +31 -0
  40. package/lib/API/UX/pm2-ls.js +483 -0
  41. package/lib/API/Version.js +382 -0
  42. package/lib/API/interpreter.json +12 -0
  43. package/lib/API/pm2-plus/PM2IO.js +372 -0
  44. package/lib/API/pm2-plus/auth-strategies/CliAuth.js +288 -0
  45. package/lib/API/pm2-plus/auth-strategies/WebAuth.js +187 -0
  46. package/lib/API/pm2-plus/helpers.js +97 -0
  47. package/lib/API/pm2-plus/link.js +126 -0
  48. package/lib/API/pm2-plus/pres/motd +16 -0
  49. package/lib/API/pm2-plus/pres/motd.update +26 -0
  50. package/lib/API/pm2-plus/pres/welcome +28 -0
  51. package/lib/API/pm2-plus/process-selector.js +52 -0
  52. package/lib/API/schema.json +379 -0
  53. package/lib/API.js +1931 -0
  54. package/lib/Client.js +776 -0
  55. package/lib/Common.js +911 -0
  56. package/lib/Configuration.js +304 -0
  57. package/lib/Daemon.js +456 -0
  58. package/lib/Event.js +37 -0
  59. package/lib/God/ActionMethods.js +909 -0
  60. package/lib/God/ClusterMode.js +97 -0
  61. package/lib/God/ForkMode.js +297 -0
  62. package/lib/God/Methods.js +265 -0
  63. package/lib/God/Reload.js +240 -0
  64. package/lib/God.js +632 -0
  65. package/lib/HttpInterface.js +76 -0
  66. package/lib/ProcessContainer.js +305 -0
  67. package/lib/ProcessContainerBun.js +360 -0
  68. package/lib/ProcessContainerFork.js +42 -0
  69. package/lib/ProcessContainerForkBun.js +33 -0
  70. package/lib/ProcessUtils.js +55 -0
  71. package/lib/TreeKill.js +118 -0
  72. package/lib/Utility.js +430 -0
  73. package/lib/VersionCheck.js +46 -0
  74. package/lib/Watcher.js +117 -0
  75. package/lib/Worker.js +169 -0
  76. package/lib/binaries/CLI.js +1041 -0
  77. package/lib/binaries/DevCLI.js +183 -0
  78. package/lib/binaries/Runtime.js +101 -0
  79. package/lib/binaries/Runtime4Docker.js +192 -0
  80. package/lib/completion.js +229 -0
  81. package/lib/completion.sh +40 -0
  82. package/lib/motd +36 -0
  83. package/lib/templates/Dockerfiles/Dockerfile-java.tpl +7 -0
  84. package/lib/templates/Dockerfiles/Dockerfile-nodejs.tpl +8 -0
  85. package/lib/templates/Dockerfiles/Dockerfile-ruby.tpl +7 -0
  86. package/lib/templates/ecosystem-es.tpl +24 -0
  87. package/lib/templates/ecosystem-simple-es.tpl +8 -0
  88. package/lib/templates/ecosystem-simple.tpl +6 -0
  89. package/lib/templates/ecosystem.tpl +22 -0
  90. package/lib/templates/init-scripts/launchd.tpl +35 -0
  91. package/lib/templates/init-scripts/openrc.tpl +52 -0
  92. package/lib/templates/init-scripts/pm2-init-amazon.sh +86 -0
  93. package/lib/templates/init-scripts/rcd-openbsd.tpl +41 -0
  94. package/lib/templates/init-scripts/rcd.tpl +44 -0
  95. package/lib/templates/init-scripts/smf.tpl +43 -0
  96. package/lib/templates/init-scripts/systemd-online.tpl +22 -0
  97. package/lib/templates/init-scripts/systemd.tpl +22 -0
  98. package/lib/templates/init-scripts/upstart.tpl +103 -0
  99. package/lib/templates/logrotate.d/pm2 +10 -0
  100. package/lib/templates/sample-apps/http-server/README.md +14 -0
  101. package/lib/templates/sample-apps/http-server/api.js +9 -0
  102. package/lib/templates/sample-apps/http-server/ecosystem.config.js +14 -0
  103. package/lib/templates/sample-apps/http-server/package.json +11 -0
  104. package/lib/templates/sample-apps/pm2-plus-metrics-actions/README.md +45 -0
  105. package/lib/templates/sample-apps/pm2-plus-metrics-actions/custom-metrics.js +66 -0
  106. package/lib/templates/sample-apps/pm2-plus-metrics-actions/ecosystem.config.js +12 -0
  107. package/lib/templates/sample-apps/pm2-plus-metrics-actions/package.json +11 -0
  108. package/lib/templates/sample-apps/python-app/README.md +4 -0
  109. package/lib/templates/sample-apps/python-app/echo.py +7 -0
  110. package/lib/templates/sample-apps/python-app/ecosystem.config.js +12 -0
  111. package/lib/templates/sample-apps/python-app/package.json +11 -0
  112. package/lib/tools/Config.js +248 -0
  113. package/lib/tools/IsAbsolute.js +20 -0
  114. package/lib/tools/copydirSync.js +101 -0
  115. package/lib/tools/deleteFolderRecursive.js +19 -0
  116. package/lib/tools/find-package-json.js +74 -0
  117. package/lib/tools/fmt.js +72 -0
  118. package/lib/tools/isbinaryfile.js +94 -0
  119. package/lib/tools/json5.js +752 -0
  120. package/lib/tools/open.js +63 -0
  121. package/lib/tools/passwd.js +58 -0
  122. package/lib/tools/promise.min.js +1 -0
  123. package/lib/tools/sexec.js +55 -0
  124. package/lib/tools/treeify.js +113 -0
  125. package/lib/tools/which.js +120 -0
  126. package/lib/tools/xdg-open +861 -0
  127. package/package.json +219 -0
  128. package/paths.js +93 -0
  129. package/pm2 +11 -0
  130. package/preinstall.js +24 -0
  131. package/run.sh +9 -0
  132. package/types/index.d.ts +722 -0
  133. package/types/tsconfig.json +14 -0
package/lib/Common.js ADDED
@@ -0,0 +1,911 @@
1
+ /**
2
+ * Copyright 2013-2022 the PM2 project authors. All rights reserved.
3
+ * Use of this source code is governed by a license that
4
+ * can be found in the LICENSE file.
5
+ */
6
+
7
+ /**
8
+ * Common Utilities ONLY USED IN ->CLI<-
9
+ */
10
+
11
+ var fs = require('fs');
12
+ var path = require('path');
13
+ var os = require('os');
14
+ var util = require('util');
15
+ var chalk = require('ansis');
16
+ var fclone = require('fclone');
17
+ var semver = require('semver');
18
+ var dayjs = require('dayjs');
19
+ var execSync = require('child_process').execSync;
20
+ var isBinary = require('./tools/isbinaryfile.js');
21
+ var cst = require('../constants.js');
22
+ var extItps = require('./API/interpreter.json');
23
+ var Config = require('./tools/Config');
24
+ var pkg = require('../package.json');
25
+ var which = require('./tools/which.js');
26
+ var Common = module.exports;
27
+
28
+ function homedir() {
29
+ var env = process.env;
30
+ var home = env.HOME;
31
+ var user = env.LOGNAME || env.USER || env.LNAME || env.USERNAME;
32
+
33
+ if (process.platform === 'win32') {
34
+ return env.USERPROFILE || env.HOMEDRIVE + env.HOMEPATH || home || null;
35
+ }
36
+
37
+ if (process.platform === 'darwin') {
38
+ return home || (user ? '/Users/' + user : null);
39
+ }
40
+
41
+ if (process.platform === 'linux') {
42
+ return home || (process.getuid() === 0 ? '/root' : (user ? '/home/' + user : null));
43
+ }
44
+
45
+ return home || null;
46
+ }
47
+
48
+ function resolveHome(filepath) {
49
+ if (filepath[0] === '~') {
50
+ return path.join(homedir(), filepath.slice(1));
51
+ }
52
+ return filepath;
53
+ }
54
+
55
+ Common.determineSilentCLI = function() {
56
+ // pm2 should ignore -s --silent -v if they are after '--'
57
+ var variadicArgsDashesPos = process.argv.indexOf('--');
58
+ var s1opt = process.argv.indexOf('--silent')
59
+ var s2opt = process.argv.indexOf('-s')
60
+
61
+ if (process.env.PM2_SILENT || (variadicArgsDashesPos > -1 &&
62
+ (s1opt != -1 && s1opt < variadicArgsDashesPos) &&
63
+ (s2opt != -1 != s2opt < variadicArgsDashesPos)) ||
64
+ (variadicArgsDashesPos == -1 && (s1opt > -1 || s2opt > -1))) {
65
+ for (var key in console){
66
+ var code = key.charCodeAt(0);
67
+ if (code >= 97 && code <= 122){
68
+ console[key] = function(){};
69
+ }
70
+ }
71
+ process.env.PM2_DISCRETE_MODE = true;
72
+ }
73
+ }
74
+
75
+ Common.printVersion = function() {
76
+ var variadicArgsDashesPos = process.argv.indexOf('--');
77
+
78
+ if (process.argv.indexOf('-v') > -1 && process.argv.indexOf('-v') < variadicArgsDashesPos) {
79
+ console.log(pkg.version);
80
+ process.exit(0);
81
+ }
82
+ }
83
+
84
+ Common.lockReload = function() {
85
+ try {
86
+ var t1 = fs.readFileSync(cst.PM2_RELOAD_LOCKFILE).toString();
87
+
88
+ // Check if content and if time < 30 return locked
89
+ // Else if content detected (lock file staled), allow and rewritte
90
+ if (t1 && t1 != '') {
91
+ var diff = dayjs().diff(parseInt(t1));
92
+ if (diff < cst.RELOAD_LOCK_TIMEOUT)
93
+ return diff;
94
+ }
95
+ } catch(e) {}
96
+
97
+ try {
98
+ // Write latest timestamp
99
+ fs.writeFileSync(cst.PM2_RELOAD_LOCKFILE, dayjs().valueOf().toString());
100
+ return 0;
101
+ } catch(e) {
102
+ console.error(e.message || e);
103
+ }
104
+ };
105
+
106
+ Common.unlockReload = function() {
107
+ try {
108
+ fs.writeFileSync(cst.PM2_RELOAD_LOCKFILE, '');
109
+ } catch(e) {
110
+ console.error(e.message || e);
111
+ }
112
+ };
113
+
114
+ /**
115
+ * Resolve app paths and replace missing values with defaults.
116
+ * @method prepareAppConf
117
+ * @param app {Object}
118
+ * @param {} cwd
119
+ * @param {} outputter
120
+ * @return app
121
+ */
122
+ Common.prepareAppConf = function(opts, app) {
123
+ /**
124
+ * Minimum validation
125
+ */
126
+ if (!app.script)
127
+ return new Error('No script path - aborting');
128
+
129
+ var cwd = null;
130
+
131
+ if (app.cwd) {
132
+ cwd = path.resolve(app.cwd);
133
+ process.env.PWD = app.cwd;
134
+ }
135
+
136
+ if (!app.node_args) {
137
+ app.node_args = [];
138
+ }
139
+
140
+ if (app.port && app.env) {
141
+ app.env.PORT = app.port;
142
+ }
143
+
144
+ // CWD option resolving
145
+ cwd && (cwd[0] != '/') && (cwd = path.resolve(process.cwd(), cwd));
146
+ cwd = cwd || opts.cwd;
147
+
148
+ // Full path script resolution
149
+ app.pm_exec_path = path.resolve(cwd, app.script);
150
+
151
+ // If script does not exist after resolution
152
+ if (!fs.existsSync(app.pm_exec_path)) {
153
+ var ckd;
154
+ // Try resolve command available in $PATH
155
+ if ((ckd = which(app.script))) {
156
+ if (typeof(ckd) !== 'string')
157
+ ckd = ckd.toString();
158
+ app.pm_exec_path = ckd;
159
+ }
160
+ else
161
+ // Throw critical error
162
+ return new Error(`Script not found: ${app.pm_exec_path}`);
163
+ }
164
+
165
+ /**
166
+ * Auto detect .map file and enable source map support automatically
167
+ */
168
+ if (app.disable_source_map_support != true) {
169
+ try {
170
+ fs.accessSync(app.pm_exec_path + '.map', fs.constants.R_OK);
171
+ app.source_map_support = true;
172
+ } catch(e) {}
173
+ delete app.disable_source_map_support;
174
+ }
175
+
176
+ delete app.script;
177
+
178
+ // Set current env by first adding the process environment and then extending/replacing it
179
+ // with env specified on command-line or JSON file.
180
+
181
+ var env = {};
182
+
183
+ /**
184
+ * Do not copy internal pm2 environment variables if acting on process
185
+ * is made from a programmatic script started by PM2 or if a pm_id is present in env
186
+ */
187
+ if (cst.PM2_PROGRAMMATIC || process.env.pm_id)
188
+ Common.safeExtend(env, process.env);
189
+ else
190
+ env = process.env;
191
+
192
+ function filterEnv (envObj) {
193
+ if (app.filter_env == true)
194
+ return {}
195
+
196
+ if (typeof app.filter_env === 'string') {
197
+ delete envObj[app.filter_env]
198
+ return envObj
199
+ }
200
+
201
+ var new_env = {};
202
+ var allowedKeys = app.filter_env.reduce((acc, current) =>
203
+ acc.filter( item => !item.includes(current)), Object.keys(envObj))
204
+ allowedKeys.forEach( key => new_env[key] = envObj[key]);
205
+ return new_env
206
+ }
207
+
208
+ app.env = [
209
+ {}, (app.filter_env && app.filter_env.length > 0) ? filterEnv(process.env) : env, app.env || {}
210
+ ].reduce(function(e1, e2){
211
+ return Object.assign(e1, e2);
212
+ });
213
+
214
+ app.pm_cwd = cwd;
215
+ // Interpreter
216
+ try {
217
+ Common.sink.resolveInterpreter(app);
218
+ } catch(e) {
219
+ return e
220
+ }
221
+
222
+ // Exec mode and cluster stuff
223
+ Common.sink.determineExecMode(app);
224
+
225
+ /**
226
+ * Scary
227
+ */
228
+ var formated_app_name = app.name.replace(/[^a-zA-Z0-9\\.\\-]/g, '-');
229
+
230
+ ['log', 'out', 'error', 'pid'].forEach(function(f){
231
+ var af = app[f + '_file'], ps, ext = (f == 'pid' ? 'pid':'log'), isStd = !~['log', 'pid'].indexOf(f);
232
+ if (af) af = resolveHome(af);
233
+
234
+ if ((f == 'log' && typeof af == 'boolean' && af) || (f != 'log' && !af)) {
235
+ ps = [cst['DEFAULT_' + ext.toUpperCase() + '_PATH'], formated_app_name + (isStd ? '-' + f : '') + '.' + ext];
236
+ } else if ((f != 'log' || (f == 'log' && af)) && af !== 'NULL' && af !== '/dev/null') {
237
+ ps = [cwd, af];
238
+
239
+ var dir = path.dirname(path.resolve(cwd, af));
240
+ if (!fs.existsSync(dir)) {
241
+ Common.printError(cst.PREFIX_MSG_WARNING + 'Folder does not exist: ' + dir);
242
+ Common.printOut(cst.PREFIX_MSG + 'Creating folder: ' + dir);
243
+ try {
244
+ require('mkdirp').sync(dir);
245
+ } catch (err) {
246
+ Common.printError(cst.PREFIX_MSG_ERR + 'Could not create folder: ' + path.dirname(af));
247
+ throw new Error('Could not create folder');
248
+ }
249
+ }
250
+
251
+ }
252
+ // PM2 paths
253
+ if (af !== 'NULL' && af !== '/dev/null') {
254
+ ps && (app['pm_' + (isStd ? f.substr(0, 3) + '_' : '') + ext + '_path'] = path.resolve.apply(null, ps));
255
+ } else if (path.sep === '\\') {
256
+ app['pm_' + (isStd ? f.substr(0, 3) + '_' : '') + ext + '_path'] = '\\\\.\\NUL';
257
+ } else {
258
+ app['pm_' + (isStd ? f.substr(0, 3) + '_' : '') + ext + '_path'] = '/dev/null';
259
+ }
260
+ delete app[f + '_file'];
261
+ });
262
+
263
+ return app;
264
+ };
265
+
266
+ /**
267
+ * Definition of known config file extensions with their type
268
+ */
269
+ Common.knonwConfigFileExtensions = {
270
+ '.json': 'json',
271
+ '.yml': 'yaml',
272
+ '.yaml': 'yaml',
273
+ '.config.js': 'js',
274
+ '.config.cjs': 'js',
275
+ '.config.mjs': 'mjs'
276
+ }
277
+
278
+ /**
279
+ * Check if filename is a configuration file
280
+ * @param {string} filename
281
+ * @return {mixed} null if not conf file, json or yaml if conf
282
+ */
283
+ Common.isConfigFile = function (filename) {
284
+ if (typeof (filename) !== 'string')
285
+ return null;
286
+
287
+ for (let extension in Common.knonwConfigFileExtensions) {
288
+ if (filename.indexOf(extension) !== -1) {
289
+ return Common.knonwConfigFileExtensions[extension];
290
+ }
291
+ }
292
+
293
+ return null;
294
+ };
295
+
296
+ Common.getConfigFileCandidates = function (name) {
297
+ return Object.keys(Common.knonwConfigFileExtensions).map((extension) => name + extension);
298
+ }
299
+
300
+ /**
301
+ * Parses a config file like ecosystem.config.js. Supported formats: JS, JSON, JSON5, YAML.
302
+ * @param {string} confString contents of the config file
303
+ * @param {string} filename path to the config file
304
+ * @return {Object} config object
305
+ */
306
+ Common.parseConfig = function(confObj, filename) {
307
+ var yamljs = require('js-yaml');
308
+ var vm = require('vm');
309
+
310
+ var isConfigFile = Common.isConfigFile(filename);
311
+
312
+ if (!filename ||
313
+ filename == 'pipe' ||
314
+ filename == 'none' ||
315
+ isConfigFile == 'json') {
316
+ var code = '(' + confObj + ')';
317
+ var sandbox = {};
318
+
319
+ return vm.runInThisContext(code, sandbox, {
320
+ filename: path.resolve(filename),
321
+ displayErrors: false,
322
+ timeout: 1000
323
+ });
324
+ }
325
+ else if (isConfigFile == 'yaml') {
326
+ return yamljs.load(confObj.toString());
327
+ }
328
+ else if (isConfigFile == 'js' || isConfigFile == 'mjs') {
329
+ var confPath = require.resolve(path.resolve(filename));
330
+ delete require.cache[confPath];
331
+ return require(confPath);
332
+ }
333
+ };
334
+
335
+ Common.retErr = function(e) {
336
+ if (!e)
337
+ return new Error('Unidentified error');
338
+ if (e instanceof Error)
339
+ return e;
340
+ return new Error(e);
341
+ }
342
+
343
+ Common.sink = {};
344
+
345
+ Common.sink.determineCron = function(app) {
346
+ if (app.cron_restart == 0 || app.cron_restart == '0') {
347
+ Common.printOut(cst.PREFIX_MSG + 'disabling cron restart');
348
+ return
349
+ }
350
+
351
+ if (app.cron_restart) {
352
+ const Croner = require('croner');
353
+
354
+ try {
355
+ Common.printOut(cst.PREFIX_MSG + 'cron restart at ' + app.cron_restart);
356
+ Croner(app.cron_restart);
357
+ } catch(ex) {
358
+ return new Error(`Cron pattern error: ${ex.message}`);
359
+ }
360
+ }
361
+ };
362
+
363
+ /**
364
+ * Handle alias (fork <=> fork_mode, cluster <=> cluster_mode)
365
+ */
366
+ Common.sink.determineExecMode = function(app) {
367
+ if (app.exec_mode)
368
+ app.exec_mode = app.exec_mode.replace(/^(fork|cluster)$/, '$1_mode');
369
+
370
+ /**
371
+ * Here we put the default exec mode
372
+ */
373
+ if (!app.exec_mode &&
374
+ (app.instances >= 1 || app.instances === 0 || app.instances === -1) &&
375
+ (app.exec_interpreter.includes('node') === true || app.exec_interpreter.includes('bun') === true)) {
376
+ app.exec_mode = 'cluster_mode';
377
+ } else if (!app.exec_mode) {
378
+ app.exec_mode = 'fork_mode';
379
+ }
380
+ if (typeof app.instances == 'undefined')
381
+ app.instances = 1;
382
+ };
383
+
384
+ var resolveNodeInterpreter = function(app) {
385
+ if (app.exec_mode && app.exec_mode.indexOf('cluster') > -1) {
386
+ Common.printError(cst.PREFIX_MSG_WARNING + chalk.bold.yellow('Choosing the Node.js version in cluster mode is not supported'));
387
+ return false;
388
+ }
389
+
390
+ var nvm_path = cst.IS_WINDOWS ? process.env.NVM_HOME : process.env.NVM_DIR;
391
+ if (!nvm_path) {
392
+ Common.printError(cst.PREFIX_MSG_ERR + chalk.red('NVM is not available in PATH'));
393
+ Common.printError(cst.PREFIX_MSG_ERR + chalk.red('Fallback to node in PATH'));
394
+ var msg = cst.IS_WINDOWS
395
+ ? 'https://github.com/coreybutler/nvm-windows/releases/'
396
+ : '$ curl https://raw.githubusercontent.com/creationix/nvm/master/install.sh | bash';
397
+ Common.printOut(cst.PREFIX_MSG_ERR + chalk.bold('Install NVM:\n' + msg));
398
+ }
399
+ else {
400
+ var node_version = app.exec_interpreter.split('@')[1];
401
+ var path_to_node = cst.IS_WINDOWS
402
+ ? '/v' + node_version + '/node.exe'
403
+ : semver.satisfies(node_version, '>= 0.12.0')
404
+ ? '/versions/node/v' + node_version + '/bin/node'
405
+ : '/v' + node_version + '/bin/node';
406
+ var nvm_node_path = path.join(nvm_path, path_to_node);
407
+ try {
408
+ fs.accessSync(nvm_node_path);
409
+ } catch(e) {
410
+ Common.printOut(cst.PREFIX_MSG + 'Installing Node v%s', node_version);
411
+ var nvm_bin = path.join(nvm_path, 'nvm.' + (cst.IS_WINDOWS ? 'exe' : 'sh'));
412
+ var nvm_cmd = cst.IS_WINDOWS
413
+ ? nvm_bin + ' install ' + node_version
414
+ : '. ' + nvm_bin + ' ; nvm install ' + node_version;
415
+
416
+ Common.printOut(cst.PREFIX_MSG + 'Executing: %s', nvm_cmd);
417
+
418
+ execSync(nvm_cmd, {
419
+ cwd: path.resolve(process.cwd()),
420
+ env: process.env,
421
+ maxBuffer: 20 * 1024 * 1024
422
+ });
423
+
424
+ // in order to support both arch, nvm for Windows renames 'node.exe' to:
425
+ // 'node32.exe' for x32 arch
426
+ // 'node64.exe' for x64 arch
427
+ if (cst.IS_WINDOWS)
428
+ nvm_node_path = nvm_node_path.replace(/node/, 'node' + process.arch.slice(1))
429
+ }
430
+
431
+ Common.printOut(cst.PREFIX_MSG + chalk.green.bold('Setting Node to v%s (path=%s)'),
432
+ node_version,
433
+ nvm_node_path);
434
+
435
+ app.exec_interpreter = nvm_node_path;
436
+ }
437
+ };
438
+
439
+ /**
440
+ * Resolve interpreter
441
+ */
442
+ Common.sink.resolveInterpreter = function(app) {
443
+ var noInterpreter = !app.exec_interpreter;
444
+ var extName = path.extname(app.pm_exec_path);
445
+ var betterInterpreter = extItps[extName];
446
+
447
+ // Bun support
448
+ if (noInterpreter && (extName == '.js' || extName == '.ts') && cst.IS_BUN === true) {
449
+ noInterpreter = false
450
+ app.exec_interpreter = process.execPath;
451
+ }
452
+
453
+ // No interpreter defined and correspondance in schema hashmap
454
+ if (noInterpreter && betterInterpreter) {
455
+ app.exec_interpreter = betterInterpreter;
456
+
457
+ if (betterInterpreter == "python") {
458
+ if (which('python') == null) {
459
+ if (which('python3') == null)
460
+ Common.printError(cst.PREFIX_MSG_WARNING + chalk.bold.yellow('python and python3 binaries not available in PATH'));
461
+ else
462
+ app.exec_interpreter = 'python3';
463
+ }
464
+ }
465
+ }
466
+ // Else if no Interpreter detect if process is binary
467
+ else if (noInterpreter) {
468
+ app.exec_interpreter = isBinary(app.pm_exec_path) ? 'none' : process.execPath;
469
+ }
470
+ else if (app.exec_interpreter.indexOf('node@') > -1)
471
+ resolveNodeInterpreter(app);
472
+
473
+ if (app.exec_interpreter.indexOf('python') > -1)
474
+ app.env.PYTHONUNBUFFERED = '1'
475
+
476
+ if (app.exec_interpreter == 'lsc') {
477
+ app.exec_interpreter = path.resolve(__dirname, '../node_modules/.bin/lsc');
478
+ }
479
+
480
+ if (app.exec_interpreter == 'coffee') {
481
+ app.exec_interpreter = path.resolve(__dirname, '../node_modules/.bin/coffee');
482
+ }
483
+
484
+ if (app.exec_interpreter != 'none' && which(app.exec_interpreter) == null) {
485
+ // If node is not present
486
+ if (app.exec_interpreter == 'node') {
487
+ Common.warn(`Using builtin node.js version on version ${process.version}`)
488
+ app.exec_interpreter = cst.BUILTIN_NODE_PATH
489
+ }
490
+ else
491
+ throw new Error(`Interpreter ${app.exec_interpreter} is NOT AVAILABLE in PATH. (type 'which ${app.exec_interpreter}' to double check.)`)
492
+ }
493
+
494
+ return app;
495
+ };
496
+
497
+ Common.deepCopy = Common.serialize = Common.clone = function(obj) {
498
+ if (obj === null || obj === undefined) return {};
499
+ return fclone(obj);
500
+ };
501
+
502
+ Common.errMod = function(msg) {
503
+ if (process.env.PM2_SILENT || process.env.PM2_PROGRAMMATIC === 'true') return false;
504
+ if (msg instanceof Error)
505
+ return console.error(msg.message);
506
+ return console.error(`${cst.PREFIX_MSG_MOD_ERR}${msg}`);
507
+ }
508
+
509
+ Common.err = function(msg) {
510
+ if (process.env.PM2_SILENT || process.env.PM2_PROGRAMMATIC === 'true') return false;
511
+ if (msg instanceof Error)
512
+ return console.error(`${cst.PREFIX_MSG_ERR}${msg.message}`);
513
+ return console.error(`${cst.PREFIX_MSG_ERR}${msg}`);
514
+ }
515
+
516
+ Common.printError = function(msg) {
517
+ if (process.env.PM2_SILENT || process.env.PM2_PROGRAMMATIC === 'true') return false;
518
+ if (msg instanceof Error)
519
+ return console.error(msg.message);
520
+ return console.error.apply(console, arguments);
521
+ };
522
+
523
+ Common.log = function(msg) {
524
+ if (process.env.PM2_SILENT || process.env.PM2_PROGRAMMATIC === 'true') return false;
525
+ return console.log(`${cst.PREFIX_MSG}${msg}`);
526
+ }
527
+
528
+ Common.info = function(msg) {
529
+ if (process.env.PM2_SILENT || process.env.PM2_PROGRAMMATIC === 'true') return false;
530
+ return console.log(`${cst.PREFIX_MSG_INFO}${msg}`);
531
+ }
532
+
533
+ Common.warn = function(msg) {
534
+ if (process.env.PM2_SILENT || process.env.PM2_PROGRAMMATIC === 'true') return false;
535
+ return console.log(`${cst.PREFIX_MSG_WARNING}${msg}`);
536
+ }
537
+
538
+ Common.logMod = function(msg) {
539
+ if (process.env.PM2_SILENT || process.env.PM2_PROGRAMMATIC === 'true') return false;
540
+ return console.log(`${cst.PREFIX_MSG_MOD}${msg}`);
541
+ }
542
+
543
+ Common.printOut = function() {
544
+ if (process.env.PM2_SILENT === 'true' || process.env.PM2_PROGRAMMATIC === 'true') return false;
545
+ return console.log.apply(console, arguments);
546
+ };
547
+
548
+
549
+ /**
550
+ * Raw extend
551
+ */
552
+ Common.extend = function(destination, source) {
553
+ if (typeof destination !== 'object') {
554
+ destination = {};
555
+ }
556
+ if (!source || typeof source !== 'object') {
557
+ return destination;
558
+ }
559
+
560
+ Object.keys(source).forEach(function(new_key) {
561
+ if (source[new_key] != '[object Object]')
562
+ destination[new_key] = source[new_key];
563
+ });
564
+
565
+ return destination;
566
+ };
567
+
568
+ /**
569
+ * This is useful when starting script programmatically
570
+ */
571
+ Common.safeExtend = function(origin, add){
572
+ if (!add || typeof add != 'object') return origin;
573
+
574
+ //Ignore PM2's set environment variables from the nested env
575
+ var keysToIgnore = ['name', 'exec_mode', 'env', 'args', 'pm_cwd', 'exec_interpreter', 'pm_exec_path', 'node_args', 'pm_out_log_path', 'pm_err_log_path', 'pm_pid_path', 'pm_id', 'status', 'pm_uptime', 'created_at', 'windowsHide', 'username', 'merge_logs', 'kill_retry_time', 'prev_restart_delay', 'instance_var', 'unstable_restarts', 'restart_time', 'axm_actions', 'pmx_module', 'command', 'watch', 'filter_env', 'versioning', 'vizion_runing', 'MODULE_DEBUG', 'pmx', 'axm_options', 'created_at', 'watch', 'vizion', 'axm_dynamic', 'axm_monitor', 'instances', 'automation', 'autostart', 'autorestart', 'stop_exit_codes', 'unstable_restart', 'treekill', 'exit_code', 'vizion'];
576
+
577
+ var keys = Object.keys(add);
578
+ var i = keys.length;
579
+ while (i--) {
580
+ //Only copy stuff into the env that we don't have already.
581
+ if(keysToIgnore.indexOf(keys[i]) == -1 && add[keys[i]] != '[object Object]')
582
+ origin[keys[i]] = add[keys[i]];
583
+ }
584
+ return origin;
585
+ };
586
+
587
+
588
+ /**
589
+ * Extend the app.env object of with the properties taken from the
590
+ * app.env_[envName] and deploy configuration.
591
+ * Also update current json attributes
592
+ *
593
+ * Used only for Configuration file processing
594
+ *
595
+ * @param {Object} app The app object.
596
+ * @param {string} envName The given environment name.
597
+ * @param {Object} deployConf Deployment configuration object (from JSON file or whatever).
598
+ * @returns {Object} The app.env variables object.
599
+ */
600
+ Common.mergeEnvironmentVariables = function(app_env, env_name, deploy_conf) {
601
+ var app = fclone(app_env);
602
+
603
+ var new_conf = {
604
+ env : {}
605
+ }
606
+
607
+ // Stringify possible object
608
+ for (var key in app.env) {
609
+ if (typeof app.env[key] == 'object') {
610
+ app.env[key] = JSON.stringify(app.env[key]);
611
+ }
612
+ }
613
+
614
+ /**
615
+ * Extra configuration update
616
+ */
617
+ Object.assign(new_conf, app);
618
+
619
+ if (env_name) {
620
+ // First merge variables from deploy.production.env object as least priority.
621
+ if (deploy_conf && deploy_conf[env_name] && deploy_conf[env_name]['env']) {
622
+ Object.assign(new_conf.env, deploy_conf[env_name]['env']);
623
+ }
624
+
625
+ Object.assign(new_conf.env, app.env);
626
+
627
+ // Then, last and highest priority, merge the app.env_production object.
628
+ if ('env_' + env_name in app) {
629
+ Object.assign(new_conf.env, app['env_' + env_name]);
630
+ }
631
+ else {
632
+ Common.printOut(cst.PREFIX_MSG_WARNING + chalk.bold('Environment [%s] is not defined in process file'), env_name);
633
+ }
634
+ }
635
+
636
+ delete new_conf.exec_mode
637
+
638
+ var res = {
639
+ current_conf: {}
640
+ }
641
+
642
+ Object.assign(res, new_conf.env);
643
+ Object.assign(res.current_conf, new_conf);
644
+
645
+ // #2541 force resolution of node interpreter
646
+ if (app.exec_interpreter &&
647
+ app.exec_interpreter.indexOf('@') > -1) {
648
+ resolveNodeInterpreter(app);
649
+ res.current_conf.exec_interpreter = app.exec_interpreter
650
+ }
651
+
652
+ return res
653
+ }
654
+
655
+ /**
656
+ * This function will resolve paths, option and environment
657
+ * CALLED before 'prepare' God call (=> PROCESS INITIALIZATION)
658
+ * @method resolveAppAttributes
659
+ * @param {Object} opts
660
+ * @param {Object} opts.cwd
661
+ * @param {Object} opts.pm2_home
662
+ * @param {Object} appConf application configuration
663
+ * @return app
664
+ */
665
+ Common.resolveAppAttributes = function(opts, conf) {
666
+ var conf_copy = fclone(conf);
667
+
668
+ var app = Common.prepareAppConf(opts, conf_copy);
669
+ if (app instanceof Error) {
670
+ throw new Error(app.message);
671
+ }
672
+ return app;
673
+ }
674
+
675
+ /**
676
+ * Verify configurations
677
+ * Called on EVERY Operation (start/restart/reload/stop...)
678
+ * @param {Array} appConfs
679
+ * @returns {Array}
680
+ */
681
+ Common.verifyConfs = function(appConfs) {
682
+ if (!appConfs || appConfs.length == 0) {
683
+ return [];
684
+ }
685
+
686
+ // Make sure it is an Array.
687
+ appConfs = [].concat(appConfs);
688
+
689
+ var verifiedConf = [];
690
+
691
+ for (var i = 0; i < appConfs.length; i++) {
692
+ var app = appConfs[i];
693
+
694
+ if (app.exec_mode)
695
+ app.exec_mode = app.exec_mode.replace(/^(fork|cluster)$/, '$1_mode');
696
+
697
+ // JSON conf: alias cmd to script
698
+ if (app.cmd && !app.script) {
699
+ app.script = app.cmd
700
+ delete app.cmd
701
+ }
702
+ // JSON conf: alias command to script
703
+ if (app.command && !app.script) {
704
+ app.script = app.command
705
+ delete app.command
706
+ }
707
+
708
+ if (!app.env) {
709
+ app.env = {}
710
+ }
711
+
712
+ // Render an app name if not existing.
713
+ Common.renderApplicationName(app);
714
+
715
+ if (app.execute_command == true) {
716
+ app.exec_mode = 'fork'
717
+ delete app.execute_command
718
+ }
719
+
720
+ app.username = Common.getCurrentUsername();
721
+
722
+ /**
723
+ * If command is like pm2 start "python xx.py --ok"
724
+ * Then automatically start the script with bash -c and set a name eq to command
725
+ */
726
+ if (app.script && app.script.indexOf(' ') > -1 && cst.IS_WINDOWS === false) {
727
+ var _script = app.script;
728
+
729
+ if (which('bash')) {
730
+ app.script = 'bash';
731
+ app.args = ['-c', _script];
732
+ if (!app.name) {
733
+ app.name = _script
734
+ }
735
+ }
736
+ else if (which('sh')) {
737
+ app.script = 'sh';
738
+ app.args = ['-c', _script];
739
+ if (!app.name) {
740
+ app.name = _script
741
+ }
742
+ }
743
+ else {
744
+ warn('bash or sh not available in $PATH, keeping script as is')
745
+ }
746
+ }
747
+
748
+ /**
749
+ * Add log_date_format by default
750
+ */
751
+ if (app.time || process.env.ASZ_MODE) {
752
+ app.log_date_format = 'YYYY-MM-DDTHH:mm:ss'
753
+ }
754
+
755
+ /**
756
+ * Checks + Resolve UID/GID
757
+ * comes from pm2 --uid <> --gid <> or --user
758
+ */
759
+ if (app.uid || app.gid || app.user) {
760
+ // 1/ Check if windows
761
+ if (cst.IS_WINDOWS === true) {
762
+ Common.printError(cst.PREFIX_MSG_ERR + '--uid and --git does not works on windows');
763
+ return new Error('--uid and --git does not works on windows');
764
+ }
765
+
766
+ // 2/ Verify that user is root (todo: verify if other has right)
767
+ if (process.env.NODE_ENV != 'test' && process.getuid && process.getuid() !== 0) {
768
+ Common.printError(cst.PREFIX_MSG_ERR + 'To use --uid and --gid please run pm2 as root');
769
+ return new Error('To use UID and GID please run PM2 as root');
770
+ }
771
+
772
+ // 3/ Resolve user info via /etc/password
773
+ var passwd = require('./tools/passwd.js')
774
+ var users
775
+ try {
776
+ users = passwd.getUsers()
777
+ } catch(e) {
778
+ Common.printError(e);
779
+ return new Error(e);
780
+ }
781
+
782
+ var user_info = users[app.uid || app.user]
783
+ if (!user_info) {
784
+ Common.printError(`${cst.PREFIX_MSG_ERR} User ${app.uid || app.user} cannot be found`);
785
+ return new Error(`${cst.PREFIX_MSG_ERR} User ${app.uid || app.user} cannot be found`);
786
+ }
787
+
788
+ app.env.HOME = user_info.homedir
789
+ app.uid = parseInt(user_info.userId)
790
+
791
+ // 4/ Resolve group id if gid is specified
792
+ if (app.gid) {
793
+ var groups
794
+ try {
795
+ groups = passwd.getGroups()
796
+ } catch(e) {
797
+ Common.printError(e);
798
+ return new Error(e);
799
+ }
800
+ var group_info = groups[app.gid]
801
+ if (!group_info) {
802
+ Common.printError(`${cst.PREFIX_MSG_ERR} Group ${app.gid} cannot be found`);
803
+ return new Error(`${cst.PREFIX_MSG_ERR} Group ${app.gid} cannot be found`);
804
+ }
805
+ app.gid = parseInt(group_info.id)
806
+ } else {
807
+ app.gid = parseInt(user_info.groupId)
808
+ }
809
+ }
810
+
811
+ /**
812
+ * Specific options of PM2.io
813
+ */
814
+ if (process.env.PM2_DEEP_MONITORING) {
815
+ app.deep_monitoring = true;
816
+ }
817
+
818
+ if (app.automation == false) {
819
+ app.pmx = false;
820
+ }
821
+
822
+ if (app.disable_trace) {
823
+ app.trace = false
824
+ delete app.disable_trace;
825
+ }
826
+
827
+ /**
828
+ * Instances params
829
+ */
830
+ if (app.instances == 'max') {
831
+ app.instances = 0;
832
+ }
833
+
834
+ if (typeof(app.instances) === 'string') {
835
+ app.instances = parseInt(app.instances) || 0;
836
+ }
837
+
838
+ if (app.exec_mode != 'cluster_mode' &&
839
+ !app.instances &&
840
+ typeof(app.merge_logs) == 'undefined') {
841
+ app.merge_logs = true;
842
+ }
843
+
844
+ var ret;
845
+
846
+ if (app.cron_restart) {
847
+ if ((ret = Common.sink.determineCron(app)) instanceof Error)
848
+ return ret;
849
+ }
850
+
851
+ /**
852
+ * Now validation configuration
853
+ */
854
+ var ret = Config.validateJSON(app);
855
+ if (ret.errors && ret.errors.length > 0){
856
+ ret.errors.forEach(function(err) { warn(err) });
857
+ return new Error(ret.errors);
858
+ }
859
+
860
+ verifiedConf.push(ret.config);
861
+ }
862
+
863
+ return verifiedConf;
864
+ }
865
+
866
+ /**
867
+ * Get current username
868
+ * Called on EVERY starting app
869
+ *
870
+ * @returns {String}
871
+ */
872
+ Common.getCurrentUsername = function(){
873
+ var current_user = '';
874
+
875
+ if (os.userInfo) {
876
+ try {
877
+ current_user = os.userInfo().username;
878
+ } catch (err) {
879
+ // For the case of unhandled error for uv_os_get_passwd
880
+ // https://github.com/Unitech/pm2/issues/3184
881
+ }
882
+ }
883
+
884
+ if(current_user === '') {
885
+ current_user = process.env.USER || process.env.LNAME || process.env.USERNAME || process.env.SUDO_USER || process.env.C9_USER || process.env.LOGNAME;
886
+ }
887
+
888
+ return current_user;
889
+ }
890
+
891
+ /**
892
+ * Render an app name if not existing.
893
+ * @param {Object} conf
894
+ */
895
+ Common.renderApplicationName = function(conf){
896
+ if (!conf.name && conf.script){
897
+ conf.name = conf.script !== undefined ? path.basename(conf.script) : 'undefined';
898
+ var lastDot = conf.name.lastIndexOf('.');
899
+ if (lastDot > 0){
900
+ conf.name = conf.name.slice(0, lastDot);
901
+ }
902
+ }
903
+ }
904
+
905
+ /**
906
+ * Show warnings
907
+ * @param {String} warning
908
+ */
909
+ function warn(warning){
910
+ Common.printOut(cst.PREFIX_MSG_WARNING + warning);
911
+ }