UNPKG

10.2 kBJavaScriptView Raw
1/**
2 Licensed to the Apache Software Foundation (ASF) under one
3 or more contributor license agreements. See the NOTICE file
4 distributed with this work for additional information
5 regarding copyright ownership. The ASF licenses this file
6 to you under the Apache License, Version 2.0 (the
7 "License"); you may not use this file except in compliance
8 with the License. You may obtain a copy of the License at
9
10 http://www.apache.org/licenses/LICENSE-2.0
11
12 Unless required by applicable law or agreed to in writing,
13 software distributed under the License is distributed on an
14 "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
15 KIND, either express or implied. See the License for the
16 specific language governing permissions and limitations
17 under the License.
18*/
19
20/* jshint node:true, bitwise:true, undef:true, trailing:true, quotmark:true,
21 indent:4, unused:vars, latedef:nofunc,
22 laxcomma:true
23*/
24
25
26var path = require('path'),
27 fs = require('fs'),
28 help = require('./help'),
29 nopt,
30 _;
31
32var cordova_lib = require('cordova-lib'),
33 CordovaError = cordova_lib.CordovaError,
34 cordova = cordova_lib.cordova,
35 events = cordova_lib.events;
36
37
38/*
39 * init
40 *
41 * initializes nopt and underscore
42 * nopt and underscore are require()d in try-catch below to print a nice error
43 * message if one of them is not installed.
44 */
45function init() {
46 try {
47 nopt = require('nopt');
48 _ = require('underscore');
49 } catch (e) {
50 console.error(
51 'Please run npm install from this directory:\n\t' +
52 path.dirname(__dirname)
53 );
54 process.exit(2);
55 }
56}
57
58module.exports = cli;
59function cli(inputArgs) {
60 // When changing command line arguments, update doc/help.txt accordingly.
61 var knownOpts =
62 { 'verbose' : Boolean
63 , 'version' : Boolean
64 , 'help' : Boolean
65 , 'silent' : Boolean
66 , 'experimental' : Boolean
67 , 'noregistry' : Boolean
68 , 'shrinkwrap' : Boolean
69 , 'usegit' : Boolean
70 , 'copy-from' : String
71 , 'link-to' : path
72 , 'searchpath' : String
73 , 'variable' : Array
74 , 'link': Boolean
75 // Flags to be passed to `cordova build/run/emulate`
76 , 'debug' : Boolean
77 , 'release' : Boolean
78 , 'archs' : String
79 , 'device' : Boolean
80 , 'emulator': Boolean
81 , 'target' : String
82 , 'browserify': Boolean
83 , 'nobuild': Boolean
84 , 'list': Boolean
85 };
86
87 var shortHands =
88 { 'd' : '--verbose'
89 , 'v' : '--version'
90 , 'h' : '--help'
91 , 'src' : '--copy-from'
92 };
93
94 // If no inputArgs given, use process.argv.
95 inputArgs = inputArgs || process.argv;
96
97 init();
98
99
100
101 var args = nopt(knownOpts, shortHands, inputArgs);
102
103
104 if (args.version) {
105 var cliVersion = require('../package').version;
106 var libVersion = require('cordova-lib/package').version;
107 var toPrint = cliVersion;
108 if (cliVersion != libVersion || /-dev$/.exec(libVersion)) {
109 toPrint += ' (cordova-lib@' + libVersion + ')';
110 }
111 console.log(toPrint);
112 return;
113 }
114
115
116 // For CordovaError print only the message without stack trace unless we
117 // are in a verbose mode.
118 process.on('uncaughtException', function(err){
119 if ( (err instanceof CordovaError) && !args.verbose ) {
120 console.error(err.message);
121 } else {
122 console.error(err.stack);
123 }
124 process.exit(1);
125 });
126
127
128 // Set up event handlers for logging and results emitted as events.
129 events.on('results', console.log);
130
131 if ( !args.silent ) {
132 events.on('log', console.log);
133 events.on('warn', console.warn);
134 }
135
136 // Add handlers for verbose logging.
137 if (args.verbose) {
138 events.on('verbose', console.log);
139 }
140
141 // TODO: Example wanted, is this functionality ever used?
142 // If there were arguments protected from nopt with a double dash, keep
143 // them in unparsedArgs. For example:
144 // cordova build ios -- --verbose --whatever
145 // In this case "--verbose" is not parsed by nopt and args.vergbose will be
146 // false, the unparsed args after -- are kept in unparsedArgs and can be
147 // passed downstream to some scripts invoked by Cordova.
148 var unparsedArgs = [];
149 var parseStopperIdx = args.argv.original.indexOf('--');
150 if (parseStopperIdx != -1) {
151 unparsedArgs = args.argv.original.slice(parseStopperIdx + 1);
152 }
153
154 // args.argv.remain contains both the undashed args (like platform names)
155 // and whatever unparsed args that were protected by " -- ".
156 // "undashed" stores only the undashed args without those after " -- " .
157 var remain = args.argv.remain;
158 var undashed = remain.slice(0, remain.length - unparsedArgs.length);
159 var cmd = undashed[0];
160 var subcommand;
161 var msg;
162 var known_platforms = Object.keys(cordova_lib.cordova_platforms);
163
164 if ( !cmd || cmd == 'help' || args.help ) {
165 if (!args.help && remain[0] == 'help') {
166 remain.shift();
167 }
168 return help(remain);
169 }
170
171 if ( !cordova.hasOwnProperty(cmd) ) {
172 msg =
173 'Cordova does not know ' + cmd + '; try `' + cordova_lib.binname +
174 ' help` for a list of all the available commands.';
175 throw new CordovaError(msg);
176 }
177
178 var opts = {
179 platforms: [],
180 options: [],
181 verbose: args.verbose || false,
182 silent: args.silent || false,
183 browserify: args.browserify || false
184 };
185
186
187 if (cmd == 'emulate' || cmd == 'build' || cmd == 'prepare' || cmd == 'compile' || cmd == 'run') {
188 // All options without dashes are assumed to be platform names
189 opts.platforms = undashed.slice(1);
190 var badPlatforms = _.difference(opts.platforms, known_platforms);
191 if( !_.isEmpty(badPlatforms) ) {
192 msg = 'Unknown platforms: ' + badPlatforms.join(', ');
193 throw new CordovaError(msg);
194 }
195
196 // CB-6976 Windows Universal Apps. Allow mixing windows and windows8 aliases
197 opts.platforms = opts.platforms.map(function(platform) {
198 // allow using old windows8 alias for new unified windows platform
199 if (platform == 'windows8' && fs.existsSync('platforms/windows')) {
200 return 'windows';
201 }
202 // allow using new windows alias for old windows8 platform
203 if (platform == 'windows' &&
204 !fs.existsSync('platforms/windows') &&
205 fs.existsSync('platforms/windows8')) {
206 return 'windows8';
207 }
208 return platform;
209 });
210
211 // Reconstruct the args to be passed along to platform scripts.
212 // This is an ugly temporary fix. The code spawning or otherwise
213 // calling into platform code should be dealing with this based
214 // on the parsed args object.
215 var downstreamArgs = [];
216 var argNames =
217 [ 'debug'
218 , 'release'
219 , 'device'
220 , 'emulator'
221 , 'nobuild'
222 , 'list'
223 ];
224 argNames.forEach(function(flag) {
225 if (args[flag]) {
226 downstreamArgs.push('--' + flag);
227 }
228 });
229
230 if (args.target) {
231 downstreamArgs.push('--target=' + args.target);
232 }
233 if (args.archs) {
234 downstreamArgs.push('--archs=' + args.archs);
235 }
236 opts.options = downstreamArgs.concat(unparsedArgs);
237
238 if (cmd == 'run' && args.list && cordova.raw.targets) {
239 cordova.raw.targets.call(null, opts).done();
240 return;
241 }
242
243 cordova.raw[cmd].call(null, opts).done();
244 } else if (cmd == 'serve') {
245 var port = undashed[1];
246 cordova.raw.serve(port).done();
247 } else if (cmd == 'create') {
248 var cfg = {};
249 // If we got a fourth parameter, consider it to be JSON to init the config.
250 if ( undashed[4] ) {
251 cfg = JSON.parse(undashed[4]);
252 }
253 var customWww = args['copy-from'] || args['link-to'];
254 if (customWww) {
255 if (customWww.indexOf('http') === 0) {
256 throw new CordovaError(
257 'Only local paths for custom www assets are supported.'
258 );
259 }
260 if ( customWww.substr(0,1) === '~' ) { // resolve tilde in a naive way.
261 customWww = path.join(process.env.HOME, customWww.substr(1));
262 }
263 customWww = path.resolve(customWww);
264 var wwwCfg = { url: customWww };
265 if (args['link-to']) {
266 wwwCfg.link = true;
267 }
268 cfg.lib = cfg.lib || {};
269 cfg.lib.www = wwwCfg;
270 }
271 // create(dir, id, name, cfg)
272 cordova.raw.create( undashed[1] // dir to create the project in
273 , undashed[2] // App id
274 , undashed[3] // App name
275 , cfg
276 ).done();
277 } else {
278 // platform/plugins add/rm [target(s)]
279 subcommand = undashed[1]; // sub-command like "add", "ls", "rm" etc.
280 var targets = undashed.slice(2); // array of targets, either platforms or plugins
281 var cli_vars = {};
282 if (args.variable) {
283 args.variable.forEach( function(s) {
284 var keyval = s.split('=');
285 var key = keyval[0].toUpperCase();
286 cli_vars[key] = keyval[1];
287 });
288 }
289 var download_opts = { searchpath : args.searchpath
290 , noregistry : args.noregistry
291 , usegit : args.usegit
292 , cli_variables : cli_vars
293 , browserify: args.browserify || false
294 , link: args.link || false
295 , save: args.save || false
296 , shrinkwrap: args.shrinkwrap || false
297 };
298 cordova.raw[cmd](subcommand, targets, download_opts).done();
299 }
300}