UNPKG

5 kBJavaScriptView Raw
1/**
2 * This code is closed source and Confidential and Proprietary to
3 * Appcelerator, Inc. All Rights Reserved. This code MUST not be
4 * modified, copied or otherwise redistributed without express
5 * written permission of Appcelerator. This file is licensed as
6 * part of the Appcelerator Platform and governed under the terms
7 * of the Appcelerator license agreement.
8 */
9var debug = require('debug')('appc:run');
10/**
11 * run the real appc binary by setting up the correct environment location
12 * and then delegate directly (via a spawn) to the real appc binary in our package
13 * @param {string} installBin - Installation binary to run
14 * @param {string[]} additionalArgs - Array of additional args to pass along
15 * @param {function} cb - Function to call when complete
16 * @param {boolean} dontexit - Do not exit after process has finished
17 */
18function run(installBin, additionalArgs, cb, dontexit) {
19 var async = require('async'),
20 chalk = require('chalk'),
21 spawn = require('child_process').spawn, // eslint-disable-line security/detect-child-process
22 path = require('path'),
23 fs = require('fs'),
24 util = require('./util'),
25 isWin = /^win/.test(process.platform);
26
27 // append any incoming program args
28 var args = [ installBin ].concat(process.argv.splice(2));
29
30 // add any additional args
31 if (additionalArgs) {
32 args = args.concat(additionalArgs);
33 }
34
35 // get the environment
36 var env = process.env;
37
38 // setup our node environment by first appending our appc node_modules
39 env.NODE_PATH = path.resolve(path.join(path.dirname(installBin), '..', 'node_modules')) + path.delimiter
40 // and then our global cache directory
41 + path.join(util.getCacheDir(), 'node_modules') + path.delimiter
42 // then pickup any paths already setup in our env
43 + (env.NODE_PATH || '');
44
45 debug('run with env=%j, args=%o', env, args);
46
47 async.series([
48 function (next) {
49 var packageDir = path.join(installBin, '..', '..'),
50 isJSON = args.indexOf('json') !== -1,
51 rebuildOpts = { stdio: 'ignore', cwd: packageDir },
52 child;
53
54 debug('run check package modules version');
55 if (installBin && util.isModuleVersionChanged(installBin)) {
56 util.outputInfo(chalk.yellow('\nYou are attempting to run appc '
57 + util.getActiveVersion()
58 + ' which was compiled for node '
59 + util.getPackageNodeVersion(installBin)
60 + ' but you are now running node ' + process.version + '\n'), isJSON);
61 util.outputInfo(chalk.yellow('Rebuilding package modules ...\n'), isJSON);
62
63 debug('exec: npm rebuild in dir %s', packageDir);
64 if (/^win/.test(process.platform)) {
65 child = spawn(process.env.comspec, [ '/c', 'npm' ].concat([ 'rebuild' ]), rebuildOpts);
66 } else {
67 child = spawn('npm', [ 'rebuild' ], rebuildOpts);
68 }
69
70 child.on('exit', function (exit) {
71 if (exit === 0) {
72 // update node version
73 util.writeVersions(path.join(packageDir, '..'));
74 util.outputInfo(chalk.yellow('Package modules rebuilt!\n'), isJSON);
75 } else {
76 util.outputInfo(chalk.yellow('The rebuild was unsuccessful, please run the following command to re-build for the newer version:\n'), isJSON);
77 util.outputInfo(chalk.green('appc use ' + util.getActiveVersion() + ' --force\n'), isJSON);
78 }
79 next();
80 });
81 } else {
82 next();
83 }
84 },
85 function (next) {
86 // check that this version of the cli supports the currently selected node version
87
88 const packageJsonLocation = path.join(installBin, '..', '..', 'package.json');
89 if (!fs.existsSync(packageJsonLocation)) {
90 next();
91 }
92 try {
93 const packageJson = require(packageJsonLocation);
94 if (!packageJson.engines || !packageJson.engines.node) {
95 return next();
96 }
97
98 util.checkNodeVersion(packageJson.engines.node);
99 } catch (e) { /* squash */ }
100
101 next();
102
103 },
104 function (next) {
105 // create our child process which simply inherits this process stdio
106 var child = spawn(process.execPath, args, { env: env, stdio: 'inherit' });
107
108 // on exit of child, exit ourselves with same exit code
109 child.on('close', function (code) {
110 next(null, code);
111 });
112
113 // propagate signals to child process
114 [ 'SIGTERM', 'SIGUSR1', 'SIGUSR2', 'SIGINT', 'SIGHUP', 'SIGQUIT', 'SIGABRT', 'exit' ].forEach(function (name) {
115 process.on(name, function (code) {
116 // Windows does not support sending signals
117 if (!isWin) {
118 // Wait until the child could safely handle it's own cleanup and prevent the main
119 // process to remain alive, mainly because the child wasn't able to leave on time
120 debug('signal received', name, 'code:', code, ', sending to', child);
121 if (name === 'exit') {
122 child.kill();
123 process.exit(Array.isArray(code) ? code[code.length - 1] : code);
124 } else {
125 child.kill(name);
126 }
127 }
128 });
129 });
130 }
131 ], function (error, results) {
132 if (cb) {
133 cb(results);
134 }
135 if (!dontexit) {
136 process.exit(Array.isArray(results) ? results[results.length - 1] : results);
137 }
138 });
139}
140
141module.exports = run;