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