1 |
|
2 |
|
3 |
|
4 |
|
5 |
|
6 |
|
7 |
|
8 |
|
9 |
|
10 |
|
11 |
|
12 |
|
13 |
|
14 |
|
15 |
|
16 |
|
17 |
|
18 |
|
19 |
|
20 |
|
21 |
|
22 |
|
23 |
|
24 |
|
25 |
|
26 | var path = require('path'),
|
27 | fs = require('fs'),
|
28 | help = require('./help'),
|
29 | nopt,
|
30 | _,
|
31 | updateNotifier,
|
32 | pkg = require('../package.json'),
|
33 | telemetry = require('./telemetry'),
|
34 | Q = require('q');
|
35 |
|
36 | var cordova_lib = require('cordova-lib'),
|
37 | CordovaError = cordova_lib.CordovaError,
|
38 | cordova = cordova_lib.cordova,
|
39 | events = cordova_lib.events,
|
40 | logger = require('cordova-common').CordovaLogger.get();
|
41 |
|
42 |
|
43 |
|
44 |
|
45 |
|
46 |
|
47 |
|
48 |
|
49 |
|
50 | function init() {
|
51 | try {
|
52 | nopt = require('nopt');
|
53 | _ = require('underscore');
|
54 | updateNotifier = require('update-notifier');
|
55 | } catch (e) {
|
56 | console.error(
|
57 | 'Please run npm install from this directory:\n\t' +
|
58 | path.dirname(__dirname)
|
59 | );
|
60 | process.exit(2);
|
61 | }
|
62 | }
|
63 |
|
64 | function checkForUpdates() {
|
65 | try {
|
66 |
|
67 | var notifier = updateNotifier({
|
68 | pkg: pkg
|
69 | });
|
70 |
|
71 |
|
72 | notifier.notify();
|
73 | } catch (e) {
|
74 |
|
75 | if (e && e.message && /EACCES/.test(e.message)) {
|
76 | console.log('Update notifier was not able to access the config file.\n' +
|
77 | 'You may grant permissions to the file: \'sudo chmod 744 ~/.config/configstore/update-notifier-cordova.json\'');
|
78 | } else {
|
79 | throw e;
|
80 | }
|
81 | }
|
82 | }
|
83 |
|
84 | var shouldCollectTelemetry = false;
|
85 | module.exports = function (inputArgs, cb) {
|
86 |
|
87 | |
88 |
|
89 |
|
90 | cb = cb || function(){};
|
91 |
|
92 | init();
|
93 |
|
94 |
|
95 | inputArgs = inputArgs || process.argv;
|
96 | var cmd = inputArgs[2];
|
97 | var subcommand = getSubCommand(inputArgs, cmd);
|
98 | var isTelemetryCmd = (cmd === 'telemetry');
|
99 |
|
100 |
|
101 | if(cmd === '--version' || cmd === '-v') {
|
102 | cmd = 'version';
|
103 | } else if(!cmd || cmd === '--help' || cmd === 'h') {
|
104 | cmd = 'help';
|
105 | }
|
106 |
|
107 | Q().then(function() {
|
108 |
|
109 | |
110 |
|
111 |
|
112 |
|
113 |
|
114 |
|
115 |
|
116 | if(telemetry.isCI(process.env) || telemetry.isNoTelemetryFlag(inputArgs)) {
|
117 | return Q(false);
|
118 | }
|
119 |
|
120 | |
121 |
|
122 |
|
123 |
|
124 | if(isTelemetryCmd) {
|
125 | var isOptedIn = telemetry.isOptedIn();
|
126 | return handleTelemetryCmd(subcommand, isOptedIn);
|
127 | }
|
128 |
|
129 | if(telemetry.hasUserOptedInOrOut()) {
|
130 | return Q(telemetry.isOptedIn());
|
131 | }
|
132 |
|
133 | |
134 |
|
135 |
|
136 |
|
137 | return telemetry.showPrompt();
|
138 | }).then(function (collectTelemetry) {
|
139 | shouldCollectTelemetry = collectTelemetry;
|
140 | if(isTelemetryCmd) {
|
141 | return Q();
|
142 | }
|
143 | return cli(inputArgs);
|
144 | }).then(function () {
|
145 | if (shouldCollectTelemetry && !isTelemetryCmd) {
|
146 | telemetry.track(cmd, subcommand, 'successful');
|
147 | }
|
148 |
|
149 | cb(null);
|
150 | }).fail(function (err) {
|
151 | if (shouldCollectTelemetry && !isTelemetryCmd) {
|
152 | telemetry.track(cmd, subcommand, 'unsuccessful');
|
153 | }
|
154 |
|
155 | cb(err);
|
156 | throw err;
|
157 | }).done();
|
158 | };
|
159 |
|
160 | function getSubCommand(args, cmd) {
|
161 | if(cmd === 'platform' || cmd === 'platforms' || cmd === 'plugin' || cmd === 'plugins' || cmd === 'telemetry') {
|
162 | return args[3];
|
163 | }
|
164 | return null;
|
165 | }
|
166 |
|
167 | function handleTelemetryCmd(subcommand, isOptedIn) {
|
168 |
|
169 | if (subcommand !== 'on' && subcommand !== 'off') {
|
170 | logger.subscribe(events);
|
171 | return help(['telemetry']);
|
172 | }
|
173 |
|
174 | var turnOn = subcommand === 'on' ? true : false;
|
175 | var cmdSuccess = true;
|
176 |
|
177 |
|
178 | try {
|
179 | if (turnOn) {
|
180 | telemetry.turnOn();
|
181 | console.log("Thanks for opting into telemetry to help us improve cordova.");
|
182 | } else {
|
183 | telemetry.turnOff();
|
184 | console.log("You have been opted out of telemetry. To change this, run: cordova telemetry on.");
|
185 | }
|
186 | } catch (ex) {
|
187 | cmdSuccess = false;
|
188 | }
|
189 |
|
190 |
|
191 |
|
192 | if (!turnOn) {
|
193 |
|
194 | telemetry.track('telemetry', 'off', 'via-cordova-telemetry-cmd', cmdSuccess ? 'successful': 'unsuccessful');
|
195 | return Q();
|
196 | }
|
197 |
|
198 | if(isOptedIn) {
|
199 | telemetry.track('telemetry', 'on', 'via-cordova-telemetry-cmd', cmdSuccess ? 'successful' : 'unsuccessful');
|
200 | }
|
201 |
|
202 | return Q();
|
203 | }
|
204 |
|
205 | function cli(inputArgs) {
|
206 |
|
207 | var knownOpts =
|
208 | { 'verbose' : Boolean
|
209 | , 'version' : Boolean
|
210 | , 'help' : Boolean
|
211 | , 'silent' : Boolean
|
212 | , 'experimental' : Boolean
|
213 | , 'noregistry' : Boolean
|
214 | , 'nohooks': Array
|
215 | , 'shrinkwrap' : Boolean
|
216 | , 'copy-from' : String
|
217 | , 'link-to' : path
|
218 | , 'searchpath' : String
|
219 | , 'variable' : Array
|
220 | , 'link': Boolean
|
221 | , 'force': Boolean
|
222 |
|
223 | , 'debug' : Boolean
|
224 | , 'release' : Boolean
|
225 | , 'archs' : String
|
226 | , 'device' : Boolean
|
227 | , 'emulator': Boolean
|
228 | , 'target' : String
|
229 | , 'browserify': Boolean
|
230 | , 'noprepare': Boolean
|
231 | , 'fetch': Boolean
|
232 | , 'nobuild': Boolean
|
233 | , 'list': Boolean
|
234 | , 'buildConfig' : String
|
235 | , 'template' : String
|
236 | };
|
237 |
|
238 | var shortHands =
|
239 | { 'd' : '--verbose'
|
240 | , 'v' : '--version'
|
241 | , 'h' : '--help'
|
242 | , 'src' : '--copy-from'
|
243 | , 't' : '--template'
|
244 | };
|
245 |
|
246 | checkForUpdates();
|
247 |
|
248 | var args = nopt(knownOpts, shortHands, inputArgs);
|
249 |
|
250 |
|
251 |
|
252 | process.on('uncaughtException', function(err) {
|
253 | logger.error(err);
|
254 |
|
255 | if(shouldCollectTelemetry) {
|
256 | telemetry.track('uncaughtException');
|
257 | }
|
258 | process.exit(1);
|
259 | });
|
260 |
|
261 | logger.subscribe(events);
|
262 |
|
263 | if (args.silent) {
|
264 | logger.setLevel('error');
|
265 | }
|
266 |
|
267 | if (args.verbose) {
|
268 | logger.setLevel('verbose');
|
269 | }
|
270 |
|
271 | var cliVersion = require('../package').version;
|
272 |
|
273 | var usingPrerelease = /-nightly|-dev$/.exec(cliVersion);
|
274 | if (args.version || usingPrerelease) {
|
275 | var libVersion = require('cordova-lib/package').version;
|
276 | var toPrint = cliVersion;
|
277 | if (cliVersion != libVersion || usingPrerelease) {
|
278 | toPrint += ' (cordova-lib@' + libVersion + ')';
|
279 | }
|
280 |
|
281 | if (args.version) {
|
282 | logger.results(toPrint);
|
283 | return Q();
|
284 | } else {
|
285 |
|
286 | logger.warn('Warning: using prerelease version ' + toPrint);
|
287 | }
|
288 | }
|
289 |
|
290 |
|
291 |
|
292 |
|
293 |
|
294 |
|
295 |
|
296 | var unparsedArgs = [];
|
297 | var parseStopperIdx = args.argv.original.indexOf('--');
|
298 | if (parseStopperIdx != -1) {
|
299 | unparsedArgs = args.argv.original.slice(parseStopperIdx + 1);
|
300 | }
|
301 |
|
302 |
|
303 |
|
304 |
|
305 | var remain = args.argv.remain;
|
306 | var undashed = remain.slice(0, remain.length - unparsedArgs.length);
|
307 | var cmd = undashed[0];
|
308 | var subcommand;
|
309 | var msg;
|
310 | var known_platforms = Object.keys(cordova_lib.cordova_platforms);
|
311 |
|
312 | if ( !cmd || cmd == 'help' || args.help ) {
|
313 | if (!args.help && remain[0] == 'help') {
|
314 | remain.shift();
|
315 | }
|
316 | return help(remain);
|
317 | }
|
318 |
|
319 | if ( !cordova.hasOwnProperty(cmd) ) {
|
320 | msg =
|
321 | 'Cordova does not know ' + cmd + '; try `' + cordova_lib.binname +
|
322 | ' help` for a list of all the available commands.';
|
323 | throw new CordovaError(msg);
|
324 | }
|
325 |
|
326 | var opts = {
|
327 | platforms: [],
|
328 | options: [],
|
329 | verbose: args.verbose || false,
|
330 | silent: args.silent || false,
|
331 | browserify: args.browserify || false,
|
332 | fetch: args.fetch || false,
|
333 | nohooks: args.nohooks || [],
|
334 | searchpath : args.searchpath
|
335 | };
|
336 |
|
337 |
|
338 | if (cmd == 'emulate' || cmd == 'build' || cmd == 'prepare' || cmd == 'compile' || cmd == 'run' || cmd === 'clean') {
|
339 |
|
340 | opts.platforms = undashed.slice(1);
|
341 | var badPlatforms = _.difference(opts.platforms, known_platforms);
|
342 | if( !_.isEmpty(badPlatforms) ) {
|
343 | msg = 'Unknown platforms: ' + badPlatforms.join(', ');
|
344 | throw new CordovaError(msg);
|
345 | }
|
346 |
|
347 |
|
348 | opts.options = args;
|
349 | opts.options.argv = unparsedArgs;
|
350 |
|
351 | if (cmd === 'run' && args.list && cordova.raw.targets) {
|
352 | return cordova.raw.targets.call(null, opts);
|
353 | }
|
354 |
|
355 | return cordova.raw[cmd].call(null, opts);
|
356 | } else if (cmd === 'requirements') {
|
357 |
|
358 | opts.platforms = undashed.slice(1);
|
359 | var badPlatforms = _.difference(opts.platforms, known_platforms);
|
360 | if( !_.isEmpty(badPlatforms) ) {
|
361 | msg = 'Unknown platforms: ' + badPlatforms.join(', ');
|
362 | throw new CordovaError(msg);
|
363 | }
|
364 |
|
365 | return cordova.raw[cmd].call(null, opts.platforms)
|
366 | .then(function(platformChecks) {
|
367 |
|
368 | var someChecksFailed = Object.keys(platformChecks).map(function(platformName) {
|
369 | events.emit('log', '\nRequirements check results for ' + platformName + ':');
|
370 | var platformCheck = platformChecks[platformName];
|
371 | if (platformCheck instanceof CordovaError) {
|
372 | events.emit('warn', 'Check failed for ' + platformName + ' due to ' + platformCheck);
|
373 | return true;
|
374 | }
|
375 |
|
376 | var someChecksFailed = false;
|
377 | platformCheck.forEach(function(checkItem) {
|
378 | var checkSummary = checkItem.name + ': ' +
|
379 | (checkItem.installed ? 'installed ' : 'not installed ') +
|
380 | (checkItem.metadata.version || '');
|
381 | events.emit('log', checkSummary);
|
382 | if (!checkItem.installed) {
|
383 | someChecksFailed = true;
|
384 | events.emit('warn', checkItem.metadata.reason);
|
385 | }
|
386 | });
|
387 |
|
388 | return someChecksFailed;
|
389 | }).some(function(isCheckFailedForPlatform) {
|
390 | return isCheckFailedForPlatform;
|
391 | });
|
392 |
|
393 | if (someChecksFailed) throw new CordovaError('Some of requirements check failed');
|
394 | });
|
395 | } else if (cmd == 'serve') {
|
396 | var port = undashed[1];
|
397 | return cordova.raw.serve(port);
|
398 | } else if (cmd == 'create') {
|
399 | return create();
|
400 | } else {
|
401 |
|
402 | subcommand = undashed[1];
|
403 | var targets = undashed.slice(2);
|
404 | var cli_vars = {};
|
405 | if (args.variable) {
|
406 | args.variable.forEach(function (s) {
|
407 |
|
408 | var eq = s.indexOf('=');
|
409 | if (eq == -1)
|
410 | throw new CordovaError("invalid variable format: " + s);
|
411 | var key = s.substr(0, eq).toUpperCase();
|
412 | var val = s.substr(eq + 1, s.length);
|
413 | cli_vars[key] = val;
|
414 | });
|
415 | }
|
416 | var download_opts = { searchpath : args.searchpath
|
417 | , noregistry : args.noregistry
|
418 | , nohooks : args.nohooks
|
419 | , cli_variables : cli_vars
|
420 | , browserify: args.browserify || false
|
421 | , fetch: args.fetch || false
|
422 | , link: args.link || false
|
423 | , save: args.save || false
|
424 | , shrinkwrap: args.shrinkwrap || false
|
425 | , force: args.force || false
|
426 | };
|
427 | return cordova.raw[cmd](subcommand, targets, download_opts);
|
428 | }
|
429 |
|
430 | function create() {
|
431 | var cfg;
|
432 | var customWww;
|
433 | var wwwCfg;
|
434 |
|
435 |
|
436 | if (undashed[4])
|
437 | cfg = JSON.parse(undashed[4]);
|
438 | else
|
439 | cfg = {};
|
440 |
|
441 | customWww = args['copy-from'] || args['link-to'] || args.template;
|
442 |
|
443 | if (customWww) {
|
444 | if ((!args.template || !args['copy-from']) && customWww.indexOf('http') === 0) {
|
445 | throw new CordovaError(
|
446 | 'Only local paths for custom www assets are supported.'
|
447 | );
|
448 | }
|
449 |
|
450 |
|
451 | if (customWww.substr(0,1) === '~')
|
452 | customWww = path.join(process.env.HOME, customWww.substr(1));
|
453 |
|
454 | wwwCfg = {
|
455 | url: customWww,
|
456 | template: false
|
457 | };
|
458 |
|
459 |
|
460 | if (args.template) {
|
461 | wwwCfg.template = true;
|
462 | } else if (args['copy-from']) {
|
463 | logger.warn('Warning: --copy-from option is being deprecated. Consider using --template instead.');
|
464 | wwwCfg.template = true;
|
465 | }
|
466 |
|
467 | cfg.lib = cfg.lib || {};
|
468 | cfg.lib.www = wwwCfg;
|
469 | }
|
470 | return cordova.raw.create( undashed[1]
|
471 | , undashed[2]
|
472 | , undashed[3]
|
473 | , cfg
|
474 | , args['fetch'] != undefined
|
475 | );
|
476 | }
|
477 | }
|