1 |
|
2 |
|
3 |
|
4 |
|
5 |
|
6 | 'use strict';
|
7 |
|
8 | const fs = require('fs');
|
9 | const path = require('path');
|
10 | const async = require('async');
|
11 | const spawn = require('child_process').spawn;
|
12 | const uuid = require('node-uuid');
|
13 | const appc = require('node-appc');
|
14 | const __ = appc.i18n(__dirname).__;
|
15 | const afs = appc.fs;
|
16 | const version = appc.version;
|
17 | const manifest = appc.pkginfo.manifest(module);
|
18 | const platformAliases = {
|
19 |
|
20 | ipad: 'iphone',
|
21 | ios: 'iphone'
|
22 | };
|
23 |
|
24 | exports.i18n = require('./i18n');
|
25 | exports.tiappxml = require('./tiappxml');
|
26 |
|
27 | exports.manifest = manifest;
|
28 | exports.platforms = [].concat(manifest.platforms);
|
29 | exports.targetPlatforms = (manifest.platforms || []).map(p => {
|
30 | return p === 'iphone' ? 'ios' : p;
|
31 | }).sort();
|
32 | exports.availablePlatforms = (manifest.platforms || []).sort();
|
33 | exports.availablePlatformsNames = (function (platforms) {
|
34 | Object.keys(platformAliases).forEach(function (alias) {
|
35 | if (platforms.indexOf(platformAliases[alias]) !== -1) {
|
36 | platforms.push(alias);
|
37 | }
|
38 | });
|
39 | return platforms.sort();
|
40 | }(manifest.platforms || []));
|
41 | exports.allPlatformNames = [ 'android', 'ios', 'iphone', 'ipad', 'mobileweb', 'blackberry', 'windows', 'tizen' ];
|
42 |
|
43 | exports.commonOptions = function (logger, config) {
|
44 | return {
|
45 | 'log-level': {
|
46 | abbr: 'l',
|
47 | callback: function (value) {
|
48 | Object.prototype.hasOwnProperty.call(logger.levels, value) && logger.setLevel(value);
|
49 | },
|
50 | desc: __('minimum logging level'),
|
51 | default: config.cli.logLevel || 'trace',
|
52 | hint: __('level'),
|
53 | values: logger.getLevels()
|
54 | }
|
55 | };
|
56 | };
|
57 |
|
58 | exports.platformOptions = function (logger, config, cli, commandName, finished) {
|
59 | var result = {},
|
60 | targetPlatform = !cli.argv.help && (cli.argv.platform || cli.argv.p);
|
61 |
|
62 | if (!commandName) {
|
63 | finished(result);
|
64 | return;
|
65 | }
|
66 |
|
67 | function set(obj, title, platform) {
|
68 |
|
69 | [ 'options', 'flags' ].forEach(function (type) {
|
70 | if (obj && obj[type]) {
|
71 | result[platform] || (result[platform] = {
|
72 | platform: platform,
|
73 | title: title || platform
|
74 | });
|
75 | result[platform][type] = obj[type];
|
76 | }
|
77 | });
|
78 | }
|
79 |
|
80 |
|
81 | targetPlatform = platformAliases[targetPlatform] || targetPlatform;
|
82 |
|
83 |
|
84 | async.parallel(manifest.platforms.map(function (platform) {
|
85 | return function (callback) {
|
86 |
|
87 |
|
88 | if (targetPlatform && platform !== targetPlatform) {
|
89 | return callback();
|
90 | }
|
91 |
|
92 | var platformDir = path.join(path.dirname(module.filename), '..', '..', '..', platform),
|
93 | platformCommand = path.join(platformDir, 'cli', 'commands', '_' + commandName + '.js'),
|
94 | command,
|
95 | conf,
|
96 | title;
|
97 |
|
98 | if (!fs.existsSync(platformCommand)) {
|
99 | return callback();
|
100 | }
|
101 |
|
102 | command = require(platformCommand);
|
103 | if (!command || !command.config) {
|
104 | return callback();
|
105 | }
|
106 |
|
107 |
|
108 | conf = command.config(logger, config, cli);
|
109 |
|
110 | try {
|
111 |
|
112 | title = JSON.parse(fs.readFileSync(path.join(platformDir, 'package.json'))).title;
|
113 | } catch (e) {}
|
114 |
|
115 | if (typeof conf === 'function') {
|
116 |
|
117 | conf(function (obj) {
|
118 | set(obj, title, platform);
|
119 | callback();
|
120 | });
|
121 | return;
|
122 | }
|
123 |
|
124 | set(conf, title, platform);
|
125 | callback();
|
126 | };
|
127 | }), function () {
|
128 | finished(result);
|
129 | });
|
130 | };
|
131 |
|
132 | exports.validateProjectDir = function (logger, cli, argv, name) {
|
133 | const dir = argv[name] || (process.env.SOURCE_ROOT ? path.join(process.env.SOURCE_ROOT, '..', '..') : '.');
|
134 | let projectDir = argv[name] = appc.fs.resolvePath(dir);
|
135 |
|
136 | if (!fs.existsSync(projectDir)) {
|
137 | logger.banner();
|
138 | logger.error(__('Project directory does not exist') + '\n');
|
139 | process.exit(1);
|
140 | }
|
141 |
|
142 | let tiapp = path.join(projectDir, 'tiapp.xml');
|
143 | while (!fs.existsSync(tiapp) && tiapp.split(path.sep).length > 2) {
|
144 | projectDir = argv[name] = path.dirname(projectDir);
|
145 | tiapp = path.join(projectDir, 'tiapp.xml');
|
146 | }
|
147 |
|
148 | if (tiapp.split(path.sep).length === 2) {
|
149 | logger.banner();
|
150 | logger.error(__('Invalid project directory "%s"', dir) + '\n');
|
151 | dir === '.' && logger.log(__('Use the %s property to specify the project\'s directory', '--project-dir'.cyan) + '\n');
|
152 | process.exit(1);
|
153 | }
|
154 |
|
155 |
|
156 | cli.tiapp = new exports.tiappxml(path.join(projectDir, 'tiapp.xml'));
|
157 | };
|
158 |
|
159 | exports.validateTiappXml = function (logger, config, tiapp) {
|
160 | if (!tiapp.id) {
|
161 | logger.error(__('tiapp.xml is missing the <id> element'));
|
162 | logger.error(__('The app id must consist of letters, numbers, and underscores.'));
|
163 | logger.error(__('Note: Android does not allow dashes and iOS does not allow underscores.'));
|
164 | logger.error(__('The first character must be a letter or underscore.'));
|
165 | logger.error(__('Usually the app id is your company\'s reversed Internet domain name. (i.e. com.example.myapp)') + '\n');
|
166 | process.exit(1);
|
167 | }
|
168 |
|
169 | if (!tiapp.name) {
|
170 | logger.error(__('tiapp.xml is missing the <name> element'));
|
171 | logger.error(__('The project name must consist of letters, numbers, dashes, and underscores.'));
|
172 | logger.error(__('The first character must be a letter.') + '\n');
|
173 | process.exit(1);
|
174 | }
|
175 |
|
176 | if (!tiapp.guid) {
|
177 | logger.error(__('tiapp.xml is missing the <guid> element'));
|
178 | logger.error(__('The guid must be in the format XXXXXXXX-XXXX-XXXX-XXXX-XXXXXXXXXXXX and consist of letters and numbers.') + '\n');
|
179 | logger.log(__('If you need a new guid, below are 5 freshly generated new ones that you can choose from:'));
|
180 | for (let i = 0; i < 5; i++) {
|
181 | logger.log(' ' + uuid.v4().cyan);
|
182 | }
|
183 | logger.log();
|
184 | process.exit(1);
|
185 | }
|
186 |
|
187 | if (!/^[0-9a-fA-F]{8}-[0-9a-fA-F]{4}-[0-9a-fA-F]{4}-[0-9a-fA-F]{4}-[0-9a-fA-F]{12}$/.test(tiapp.guid)) {
|
188 | logger.error(__('tiapp.xml contains an invalid guid "%s"', tiapp.guid));
|
189 | logger.error(__('The guid must be in the format XXXXXXXX-XXXX-XXXX-XXXX-XXXXXXXXXXXX and consist of letters and numbers.') + '\n');
|
190 | logger.log(__('If you need a new guid, below are 5 freshly generated new ones that you can choose from:'));
|
191 | for (let i = 0; i < 5; i++) {
|
192 | logger.log(' ' + uuid.v4().cyan);
|
193 | }
|
194 | logger.log();
|
195 | process.exit(1);
|
196 | }
|
197 |
|
198 | tiapp.version || (tiapp.version = '1.0');
|
199 |
|
200 | if (!config.get('app.skipVersionValidation') && !tiapp.properties['ti.skipVersionValidation']) {
|
201 | if (!/^\d+(\.\d+(\.\d+(\..+)?)?)?$/.test(tiapp.version)) {
|
202 | logger.error(__('tiapp.xml contains an invalid version "%s"', tiapp.version));
|
203 | logger.error(__('The version must consist of three positive integers in the format "X.Y.Z".') + '\n');
|
204 | process.exit(1);
|
205 | }
|
206 |
|
207 | if (('' + tiapp.version).charAt(0) == '0') {
|
208 | logger.warn(__('tiapp.xml contains an invalid version "%s"', tiapp.version));
|
209 | logger.warn(__('The app version major number must be greater than zero.'));
|
210 | }
|
211 | }
|
212 | };
|
213 |
|
214 | exports.validAppId = function (id) {
|
215 | const words = {
|
216 | abstract: 1,
|
217 | assert: 1,
|
218 | boolean: 1,
|
219 | break: 1,
|
220 | byte: 1,
|
221 | case: 1,
|
222 | catch: 1,
|
223 | char: 1,
|
224 | class: 1,
|
225 | const: 1,
|
226 | continue: 1,
|
227 | default: 1,
|
228 | do: 1,
|
229 | double: 1,
|
230 | else: 1,
|
231 | enum: 1,
|
232 | extends: 1,
|
233 | false: 1,
|
234 | final: 1,
|
235 | finally: 1,
|
236 | float: 1,
|
237 | for: 1,
|
238 | goto: 1,
|
239 | if: 1,
|
240 | implements: 1,
|
241 | import: 1,
|
242 | instanceof: 1,
|
243 | int: 1,
|
244 | interface: 1,
|
245 | long: 1,
|
246 | native: 1,
|
247 | new: 1,
|
248 | null: 1,
|
249 | package: 1,
|
250 | private: 1,
|
251 | protected: 1,
|
252 | public: 1,
|
253 | return: 1,
|
254 | short: 1,
|
255 | static: 1,
|
256 | strictfp: 1,
|
257 | super: 1,
|
258 | switch: 1,
|
259 | synchronized: 1,
|
260 | this: 1,
|
261 | throw: 1,
|
262 | throws: 1,
|
263 | transient: 1,
|
264 | true: 1,
|
265 | try: 1,
|
266 | void: 1,
|
267 | volatile: 1,
|
268 | while: 1
|
269 | },
|
270 | parts = id.split('.'),
|
271 | l = parts.length;
|
272 |
|
273 | for (let i = 0; i < l; i++) {
|
274 | if (words[parts[i]]) {
|
275 | return false;
|
276 | }
|
277 | }
|
278 |
|
279 | return true;
|
280 | };
|
281 |
|
282 | exports.loadPlugins = function (logger, config, cli, projectDir, finished, silent, compact) {
|
283 | var searchPaths = {
|
284 | project: [ path.join(projectDir, 'plugins') ],
|
285 | config: [],
|
286 | global: []
|
287 | },
|
288 | confPaths = config.get('paths.plugins'),
|
289 | defaultInstallLocation = cli.env.installPath,
|
290 | sdkLocations = cli.env.os.sdkPaths.map(function (p) { return afs.resolvePath(p); });
|
291 |
|
292 |
|
293 | Array.isArray(confPaths) || (confPaths = [ confPaths ]);
|
294 | confPaths.forEach(function (p) {
|
295 | p && fs.existsSync(p = afs.resolvePath(p)) && searchPaths.project.indexOf(p) === -1 && searchPaths.config.indexOf(p) === -1 && (searchPaths.config.push(p));
|
296 | });
|
297 |
|
298 |
|
299 | sdkLocations.indexOf(defaultInstallLocation) === -1 && sdkLocations.push(defaultInstallLocation);
|
300 | cli.sdk && sdkLocations.push(afs.resolvePath(cli.sdk.path, '..', '..', '..'));
|
301 | sdkLocations.forEach(function (p) {
|
302 | fs.existsSync(p = afs.resolvePath(p, 'plugins')) && searchPaths.project.indexOf(p) === -1 && searchPaths.config.indexOf(p) === -1 && searchPaths.global.indexOf(p) === -1 && (searchPaths.global.push(p));
|
303 | });
|
304 |
|
305 |
|
306 | appc.tiplugin.find(cli.tiapp.plugins, searchPaths, config, logger, function (plugins) {
|
307 | if (plugins.missing.length) {
|
308 | if (logger) {
|
309 | logger.error(__('Could not find all required Titanium plugins:'));
|
310 | plugins.missing.forEach(m => logger.error(' id: ' + m.id + '\t version: ' + m.version));
|
311 | logger.log();
|
312 | }
|
313 | process.exit(1);
|
314 | }
|
315 |
|
316 | if (plugins.found.length) {
|
317 | plugins.found.forEach(plugin => cli.scanHooks(afs.resolvePath(plugin.pluginPath, 'hooks')));
|
318 | } else {
|
319 | logger && logger.debug(__('No project level plugins to load'));
|
320 | }
|
321 |
|
322 | silent || cli.emit('cli:check-plugins', { compact: compact === undefined ? true : compact });
|
323 |
|
324 | finished();
|
325 | });
|
326 | };
|
327 |
|
328 | exports.loadModuleManifest = function (logger, manifestFile) {
|
329 | if (!fs.existsSync(manifestFile)) {
|
330 | logger.error(__('Missing %s', manifestFile));
|
331 | logger.log();
|
332 | process.exit(1);
|
333 | }
|
334 |
|
335 | const re = /^(\S+)\s*:\s*(.*)$/;
|
336 | const manifest = {};
|
337 | fs.readFileSync(manifestFile).toString().split(/\r?\n/).forEach(function (line) {
|
338 | const match = line.match(re);
|
339 | if (match) {
|
340 | manifest[match[1].trim()] = match[2].trim();
|
341 | }
|
342 | });
|
343 |
|
344 | return manifest;
|
345 | };
|
346 |
|
347 | exports.validateModuleManifest = function (logger, cli, manifest) {
|
348 | const requiredModuleKeys = [
|
349 | 'name',
|
350 | 'version',
|
351 | 'moduleid',
|
352 | 'description',
|
353 | 'copyright',
|
354 | 'license',
|
355 | 'copyright',
|
356 | 'platform',
|
357 | 'minsdk',
|
358 | 'architectures'
|
359 | ];
|
360 |
|
361 |
|
362 | requiredModuleKeys.forEach(function (key) {
|
363 | if (!manifest[key]) {
|
364 | logger.error(__('Missing required manifest key "%s"', key));
|
365 | logger.log();
|
366 | process.exit(1);
|
367 | }
|
368 | });
|
369 |
|
370 | if (cli.argv.platform !== exports.resolvePlatform(manifest.platform)) {
|
371 | logger.error(__('Unable to find "%s" module', cli.argv.platform));
|
372 | logger.log();
|
373 | process.exit(1);
|
374 | }
|
375 | };
|
376 |
|
377 | exports.validateCorrectSDK = function (logger, config, cli, commandName) {
|
378 |
|
379 | var argv = cli.argv,
|
380 | tiapp = cli.tiapp,
|
381 | sdkName = tiapp['sdk-version'],
|
382 | selectedSdk = cli.sdk && cli.sdk.name || manifest.version;
|
383 |
|
384 | if (!sdkName) {
|
385 | sdkName = tiapp['sdk-version'] = cli.sdk && cli.sdk.name || Object.keys(cli.env.sdks).sort().pop();
|
386 | }
|
387 |
|
388 | if (argv.legacy !== true && (!sdkName || sdkName === selectedSdk)) {
|
389 | return true;
|
390 | }
|
391 |
|
392 |
|
393 | if (sdkName === '__global__' || !cli.env.sdks[sdkName]) {
|
394 | logger.banner();
|
395 | logger.error(__('Unable to compile project because the \'sdk-version\' in the tiapp.xml is not installed') + '\n');
|
396 | logger.log(__('The project\'s %s is currently set to %s, which is not installed.', 'sdk-version'.cyan, sdkName.cyan) + '\n');
|
397 | logger.log(__('Update the %s in the tiapp.xml to one of the installed Titaniums SDKs:', 'sdk-version'.cyan));
|
398 | Object.keys(cli.env.sdks).sort().forEach(function (ver) {
|
399 | if (ver !== '__global__') {
|
400 | logger.log(' ' + ver.cyan);
|
401 | }
|
402 | });
|
403 | logger.log(__('or run \'%s\' to download and install Titanium SDK %s', ('titanium sdk install ' + sdkName).cyan, sdkName) + '\n');
|
404 | process.exit(1);
|
405 | }
|
406 |
|
407 | var sdkVersion = cli.env.sdks[sdkName].manifest && cli.env.sdks[sdkName].manifest.version || sdkName;
|
408 | if (version.gte(sdkVersion, '3.0.0') && version.lte(sdkVersion, '3.0.2') && version.gte(process.version, '0.9.0')) {
|
409 | logger.banner();
|
410 | logger.error(__('Unable to compile project using Titanium SDK %s with Node.js %s', sdkName, process.version) + '\n');
|
411 | logger.log(__('Titanium SDK %s requires Node.js v0.8. Node.js v0.10 and newer will not work.', sdkName.cyan) + '\n');
|
412 | logger.log(__('Either update your application to Titanium SDK %s or newer or download Node.js %s from %s.', '3.1.0.GA'.cyan, 'v0.8'.cyan, 'http://nodejs.org/dist/'.cyan) + '\n');
|
413 | process.exit(1);
|
414 | }
|
415 |
|
416 |
|
417 | if (config.cli.failOnWrongSDK) {
|
418 | logger.banner();
|
419 | logger.error(__('Unable to compile a %s project with Titanium SDK %s', sdkName, selectedSdk));
|
420 | logger.error(__('To build this application, set the <sdk-version> in the tiapp.xml to the current Titaniums SDK: %s', selectedSdk) + '\n');
|
421 | process.exit(1);
|
422 | }
|
423 |
|
424 | var args = argv.$_,
|
425 | p = args.indexOf('--sdk'),
|
426 | platform = exports.resolvePlatform(argv.platform),
|
427 | cmd = [],
|
428 | cmdSafe = [],
|
429 | cmdRoot,
|
430 | hideBanner = false,
|
431 | delayCmd = false;
|
432 |
|
433 | function cmdAdd() {
|
434 | for (var i = 0; i < arguments.length; i++) {
|
435 | cmd.push(arguments[i]);
|
436 | cmdSafe.push(arguments[i]);
|
437 | }
|
438 | }
|
439 |
|
440 | function cmdAddSecret(_param) {
|
441 | for (var i = 0; i < arguments.length; i++) {
|
442 | cmd.push(arguments[i]);
|
443 | cmdSafe.push('*******');
|
444 | }
|
445 | }
|
446 |
|
447 | if (p !== -1) {
|
448 | args.splice(p, 2);
|
449 | }
|
450 |
|
451 | if (!argv.legacy) {
|
452 | logger.info(__('tiapp.xml <sdk-version> set to %s, but current Titanium SDK set to %s', sdkName.cyan, selectedSdk.cyan));
|
453 | }
|
454 |
|
455 | if (argv.legacy || version.lt(sdkVersion, '2.2.0')) {
|
456 |
|
457 |
|
458 | if (argv.platform === 'android' && argv['store-password']) {
|
459 | argv.password = argv['store-password'];
|
460 | }
|
461 |
|
462 | cmdRoot = 'python';
|
463 |
|
464 | var builderPy = path.join(path.resolve(cli.env.sdks[sdkName].path), platform, 'builder.py');
|
465 | cmdAdd(builderPy);
|
466 |
|
467 | switch (platform) {
|
468 | case 'iphone':
|
469 | switch (argv.target) {
|
470 | case 'simulator':
|
471 | if (argv['build-only']) {
|
472 | cmdAdd('build', argv['ios-version'], argv['project-dir'], tiapp.id, tiapp.name, argv['device-family'], argv['sim-type'], argv['debug-host']);
|
473 | } else {
|
474 | cmdAdd('run', argv['project-dir'], argv['ios-version'], '', '', argv['device-family'], argv['sim-type'], argv['debug-host']);
|
475 | }
|
476 | break;
|
477 |
|
478 | case 'device':
|
479 | cmdAdd('install', argv['ios-version'], argv['project-dir'], tiapp.id, tiapp.name, argv['pp-uuid'], argv['developer-name'], argv['device-family'], argv.keychain, argv['debug-host']);
|
480 | break;
|
481 |
|
482 | case 'dist-appstore':
|
483 | cmdAdd('distribute', argv['ios-version'], argv['project-dir'], tiapp.id, tiapp.name, argv['pp-uuid'], argv['distribution-name'], '.', argv['device-family'], argv.keychain);
|
484 | break;
|
485 |
|
486 | case 'dist-adhoc':
|
487 | cmdAdd('adhoc', argv['ios-version'], argv['project-dir'], tiapp.id, tiapp.name, argv['pp-uuid'], argv['distribution-name'], argv['device-family'], argv.keychain, argv['debug-host']);
|
488 | break;
|
489 | }
|
490 | break;
|
491 |
|
492 | case 'mobileweb':
|
493 | cmdAdd(argv['project-dir'], argv['deploy-type']);
|
494 | break;
|
495 |
|
496 | case 'android':
|
497 | if (argv['build-only']) {
|
498 | cmdAdd('build', tiapp.name, argv['android-sdk'], argv['project-dir'], tiapp.id);
|
499 | } else {
|
500 | if (argv.target === 'emulator') {
|
501 | if (!argv['avd-id']) {
|
502 | logger.error(__('Missing required option "%s"', '--avd-id') + '\n');
|
503 | process.exit(1);
|
504 | }
|
505 | if (!argv['avd-skin']) {
|
506 | logger.error(__('Missing required option "%s"', '--avd-skin') + '\n');
|
507 | process.exit(1);
|
508 | }
|
509 | }
|
510 |
|
511 | switch (argv.target) {
|
512 | case 'emulator':
|
513 | cmdAdd('simulator', tiapp.name, argv['android-sdk'], argv['project-dir'], tiapp.id, argv['avd-id'], argv['avd-skin']);
|
514 | delayCmd = true;
|
515 |
|
516 |
|
517 | var emuArgs = [ builderPy, 'emulator', tiapp.name, argv['android-sdk'], argv['project-dir'], tiapp.id, argv['avd-id'], argv['avd-skin'] ];
|
518 | argv['avd-abi'] && emuArgs.push(argv['avd-abi']);
|
519 | logger.info(__('Launching Android emulator: %s', ('"' + cmdRoot + '" "' + emuArgs.join('" "') + '"').cyan));
|
520 | spawn(cmdRoot, emuArgs, {
|
521 | detached: true,
|
522 | stdio: 'ignore'
|
523 | }).on('exit', function (code, signal) {
|
524 | console.log('EMULATOR EXITED', code, signal);
|
525 | });
|
526 | break;
|
527 |
|
528 | case 'device':
|
529 | cmdAdd('install', tiapp.name, argv['android-sdk'], argv['project-dir'], tiapp.id, 1);
|
530 | break;
|
531 |
|
532 | case 'dist-playstore':
|
533 | cmdAdd('distribute', tiapp.name, argv['android-sdk'], argv['project-dir'], tiapp.id, argv['keystore']);
|
534 | cmdAddSecret(argv['password']);
|
535 | cmdAdd(argv['alias'], argv['output-dir']);
|
536 | break;
|
537 | }
|
538 | }
|
539 |
|
540 |
|
541 | if (argv['debug-host']) {
|
542 | if (argv.target === 'device') {
|
543 | cmdAdd('');
|
544 | }
|
545 | cmdAdd(argv['debug-host']);
|
546 | }
|
547 |
|
548 | if (argv['profiler-host']) {
|
549 | if (argv.target === 'device') {
|
550 | cmdAdd('');
|
551 | }
|
552 | cmdAdd(argv['profiler-host']);
|
553 | cmdAdd('profiler');
|
554 | }
|
555 | }
|
556 |
|
557 | } else {
|
558 |
|
559 |
|
560 | cmdRoot = version.gte(sdkVersion, '3.0.2') ? (process.execPath || 'node') : 'node';
|
561 |
|
562 | hideBanner = true;
|
563 |
|
564 |
|
565 | var titaniumPath = (function getTitaniumPath (params) {
|
566 | var paramsArray = params.split(' '),
|
567 | pathSegment,
|
568 | prevPath = '';
|
569 | while ((pathSegment = paramsArray.pop())) {
|
570 | if (fs.existsSync(pathSegment + prevPath)) {
|
571 | return pathSegment + prevPath;
|
572 | }
|
573 | prevPath = ' ' + pathSegment;
|
574 | }
|
575 |
|
576 | return params.split(' ').pop();
|
577 | }(argv.$0));
|
578 |
|
579 | cmdAdd(titaniumPath);
|
580 | cmdAdd(commandName, '--sdk', sdkName);
|
581 |
|
582 | var flags = {},
|
583 | options = {};
|
584 |
|
585 |
|
586 | [ cli.globalContext, cli.command, cli.command.platform ].forEach(function (ctx) {
|
587 | if (ctx && ctx.conf) {
|
588 | ctx.conf.flags && appc.util.mix(flags, ctx.conf.flags);
|
589 | ctx.conf.options && appc.util.mix(options, ctx.conf.options);
|
590 | }
|
591 | });
|
592 |
|
593 | Object.keys(flags).forEach(function (name) {
|
594 | var def = Object.prototype.hasOwnProperty.call(flags[name], 'default') ? flags[name].default : false;
|
595 | if (argv[name] !== undefined && def !== argv[name]) {
|
596 | cmdAdd('--' + (argv[name] ? '' : 'no-') + name);
|
597 | }
|
598 | });
|
599 |
|
600 | Object.keys(options).forEach(function (name) {
|
601 | if (name !== 'sdk' && argv[name] !== undefined) {
|
602 |
|
603 |
|
604 | var arg = name;
|
605 | if (argv.platform === 'android' && arg === 'store-password' && version.lt(sdkVersion, '3.2.0')) {
|
606 | arg = 'password';
|
607 | }
|
608 |
|
609 | cmdAdd('--' + arg);
|
610 | if (options[name].secret) {
|
611 | cmdAddSecret(argv[name]);
|
612 | } else {
|
613 | cmdAdd(argv[name]);
|
614 | }
|
615 | }
|
616 | });
|
617 | }
|
618 |
|
619 |
|
620 | while (!cmd[cmd.length - 1]) {
|
621 | cmd.pop();
|
622 | cmdSafe.pop();
|
623 | }
|
624 |
|
625 | if (argv.legacy) {
|
626 | logger.info(__('Forking legacy SDK command: %s', (cmdRoot + ' "' + cmdSafe.join('" "') + '"').cyan) + '\n');
|
627 | } else {
|
628 | logger.info(__('Forking correct SDK command: %s', ('"' + cmdRoot + '" "' + cmdSafe.join('" "') + '"').cyan) + '\n');
|
629 | }
|
630 |
|
631 | hideBanner && cmd.push('--no-banner');
|
632 |
|
633 |
|
634 |
|
635 |
|
636 | setTimeout(function () {
|
637 | spawn(cmdRoot, cmd, {
|
638 | stdio: 'inherit'
|
639 | }).on('exit', function (code, _signal) {
|
640 | code && process.exit(code);
|
641 | });
|
642 | }, delayCmd ? 1000 : 0);
|
643 | };
|
644 |
|
645 | exports.validateAppJsExists = function (projectDir, logger, platformDirs) {
|
646 | if (!fs.existsSync(path.join(projectDir, 'Resources'))) {
|
647 | logger.error(__('"Resources" directory not found'));
|
648 | logger.error(__('Ensure the "Resources" directory exists and contains an "app.js" file.') + '\n');
|
649 | process.exit(1);
|
650 | }
|
651 |
|
652 | const files = [
|
653 | path.join(projectDir, 'Resources', 'app.js')
|
654 | ];
|
655 |
|
656 | Array.isArray(platformDirs) || (platformDirs = [ platformDirs ]);
|
657 | platformDirs.forEach(function (platformDir) {
|
658 | files.push(path.join(projectDir, 'Resources', platformDir, 'app.js'));
|
659 | });
|
660 |
|
661 | if (!files.some(file => fs.existsSync(file))) {
|
662 | logger.error(__('"app.js" not found'));
|
663 | logger.error(__('Ensure the "app.js" file exists in your project\'s "Resources" directory.') + '\n');
|
664 | process.exit(1);
|
665 | }
|
666 | };
|
667 |
|
668 | exports.validatePlatformOptions = function (logger, config, cli, commandName) {
|
669 | const platform = exports.resolvePlatform(cli.argv.platform),
|
670 | platformCommand = path.join(path.dirname(module.filename), '..', '..', '..', manifest.platforms[manifest.platforms.indexOf(platform)], 'cli', 'commands', '_' + commandName + '.js');
|
671 | if (fs.existsSync(platformCommand)) {
|
672 | const command = require(platformCommand);
|
673 | return command && typeof command.validate === 'function' ? command.validate(logger, config, cli) : null;
|
674 | }
|
675 | };
|
676 |
|
677 | exports.scrubPlatforms = function (platforms) {
|
678 | const scrubbed = {},
|
679 | original = {},
|
680 | bad = {};
|
681 |
|
682 | platforms.toLowerCase().split(',').forEach(function (platform) {
|
683 | const name = platformAliases[platform] || platform;
|
684 |
|
685 | if (name) {
|
686 | if (manifest.platforms.indexOf(name) === -1) {
|
687 | bad[platform] = 1;
|
688 | } else {
|
689 | scrubbed[name] = 1;
|
690 | original[platform] = 1;
|
691 | }
|
692 | }
|
693 | });
|
694 |
|
695 | return {
|
696 | scrubbed: Object.keys(scrubbed).sort(),
|
697 | original: Object.keys(original).sort(),
|
698 | bad: Object.keys(bad).sort()
|
699 | };
|
700 | };
|
701 |
|
702 | exports.resolvePlatform = function (platform) {
|
703 | return platformAliases[platform] || platform;
|
704 | };
|
705 |
|
706 | exports.filterPlatforms = function (platform) {
|
707 | platform = platformAliases[platform] || platform;
|
708 | return exports.availablePlatformsNames.filter(name => name != platform);
|
709 | };
|
710 |
|
711 | exports.validatePlatform = function (logger, cli, name) {
|
712 | const platform = name ? cli.argv[name] : cli.argv,
|
713 | p = cli.argv[name] = platformAliases[platform] || platform;
|
714 | if (!p || manifest.platforms.indexOf(p) === -1) {
|
715 | logger.banner();
|
716 | logger.error(__('Invalid platform "%s"', platform) + '\n');
|
717 | appc.string.suggest(platform, exports.targetPlatforms, logger.log);
|
718 | logger.log(__('Available platforms for SDK version %s:', cli.sdk && cli.sdk.name || manifest.version));
|
719 | exports.targetPlatforms.forEach(p => logger.log(' ' + p.cyan));
|
720 | logger.log();
|
721 | process.exit(1);
|
722 | }
|
723 | };
|