You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@cordova.apache.org by ka...@apache.org on 2014/06/06 03:25:09 UTC

git commit: CB-6024: Use nopt instead of optimist in cli

Repository: cordova-cli
Updated Branches:
  refs/heads/master 903f737de -> b5b4a14a2


CB-6024: Use nopt instead of optimist in cli

Why:
 - Optimist was killed by the author (he recommends minimist as replacement)
 - We already use nopt in plugman cli
 - Make cli parsing cleaner

 Changes:
 - No more manual parsing of the args array
 - cli vars for plugin add passed down as part of opts, not part of targets
 - cli is now a regular function rather than a class, it was never properly
   used as a class.
 - Flags to be passed to platform run scripts are parsed by nopt.
 - To pass arbitrary flags unknown to cli down to platform scripts,
   they must be separated by " -- " from other args, for example:
   cordova compile ios -- -d --foo=bar
   anything after " -- " will not be interpreted by the cli.


Project: http://git-wip-us.apache.org/repos/asf/cordova-cli/repo
Commit: http://git-wip-us.apache.org/repos/asf/cordova-cli/commit/b5b4a14a
Tree: http://git-wip-us.apache.org/repos/asf/cordova-cli/tree/b5b4a14a
Diff: http://git-wip-us.apache.org/repos/asf/cordova-cli/diff/b5b4a14a

Branch: refs/heads/master
Commit: b5b4a14a2f8bdf43fcf098884ea70af109d596a2
Parents: 903f737
Author: Mark Koudritsky <ka...@gmail.com>
Authored: Thu Jun 5 18:37:04 2014 -0400
Committer: Mark Koudritsky <ka...@gmail.com>
Committed: Thu Jun 5 18:37:04 2014 -0400

----------------------------------------------------------------------
 bin/cordova      |   8 +-
 package.json     |   2 +-
 spec/cli.spec.js |  28 +++---
 src/cli.js       | 273 ++++++++++++++++++++++++++++++--------------------
 4 files changed, 186 insertions(+), 125 deletions(-)
----------------------------------------------------------------------


http://git-wip-us.apache.org/repos/asf/cordova-cli/blob/b5b4a14a/bin/cordova
----------------------------------------------------------------------
diff --git a/bin/cordova b/bin/cordova
index b75655d..bab9b88 100755
--- a/bin/cordova
+++ b/bin/cordova
@@ -7,9 +7,9 @@
 // to you under the Apache License, Version 2.0 (the
 // "License"); you may not use this file except in compliance
 // with the License.  You may obtain a copy of the License at
-// 
+//
 // http://www.apache.org/licenses/LICENSE-2.0
-// 
+//
 // Unless required by applicable law or agreed to in writing,
 // software distributed under the License is distributed on an
 // "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
@@ -37,6 +37,6 @@ if (0) {
 }
 
 addTs('start');
-var CLI = require('../src/cli');
-new CLI(process.argv);
+var cli = require('../src/cli');
+cli(process.argv);
 addTs('end');

http://git-wip-us.apache.org/repos/asf/cordova-cli/blob/b5b4a14a/package.json
----------------------------------------------------------------------
diff --git a/package.json b/package.json
index aea1eff..61ff55d 100644
--- a/package.json
+++ b/package.json
@@ -30,7 +30,7 @@
   "dependencies": {
     "cordova-lib": "0.21.3",
     "q": "~0.9",
-    "optimist": "0.6.0",
+    "nopt": "~2",
     "underscore":"1.4.4"
   },
   "devDependencies": {

http://git-wip-us.apache.org/repos/asf/cordova-cli/blob/b5b4a14a/spec/cli.spec.js
----------------------------------------------------------------------
diff --git a/spec/cli.spec.js b/spec/cli.spec.js
index 5720ed2..9b6e8de 100644
--- a/spec/cli.spec.js
+++ b/spec/cli.spec.js
@@ -17,7 +17,7 @@
     under the License.
 */
 
-var CLI = require("../src/cli"),
+var cli = require("../src/cli"),
     Q = require('q'),
     cordova_lib = require('cordova-lib'),
     plugman = cordova_lib.plugman,
@@ -41,17 +41,17 @@ describe("cordova cli", function () {
             });
 
             it("will spit out the version with -v", function () {
-                new CLI(["node", "cordova", "-v"]);
+                cli(["node", "cordova", "-v"]);
                 expect(console.log).toHaveBeenCalledWith(version);
             });
 
             it("will spit out the version with --version", function () {
-                new CLI(["node", "cordova", "--version"]);
+                cli(["node", "cordova", "--version"]);
                 expect(console.log).toHaveBeenCalledWith(version);
             });
 
             it("will spit out the version with -v anywher", function () {
-                new CLI(["node", "cordova", "one", "-v", "three"]);
+                cli(["node", "cordova", "one", "-v", "three"]);
                 expect(console.log).toHaveBeenCalledWith(version);
             });
         });
@@ -63,32 +63,32 @@ describe("cordova cli", function () {
         });
 
         it("will call command with all arguments passed through", function () {
-            new CLI(["node", "cordova", "build", "blackberry10", "-k", "abcd1234"]);
+            cli(["node", "cordova", "build", "blackberry10", "--", "-k", "abcd1234"]);
             expect(cordova.raw.build).toHaveBeenCalledWith({verbose: false, silent: false, platforms: ["blackberry10"], options: ["-k", "abcd1234"]});
         });
 
         it("will consume the first instance of -d", function () {
-            new CLI(["node", "cordova", "-d", "build", "blackberry10", "-k", "abcd1234", "-d"]);
+            cli(["node", "cordova", "-d", "build", "blackberry10", "--", "-k", "abcd1234", "-d"]);
             expect(cordova.raw.build).toHaveBeenCalledWith({verbose: true, silent: false, platforms: ["blackberry10"], options: ["-k", "abcd1234", "-d"]});
         });
 
         it("will consume the first instance of --verbose", function () {
-            new CLI(["node", "cordova", "--verbose", "build", "blackberry10", "-k", "abcd1234", "--verbose"]);
+            cli(["node", "cordova", "--verbose", "build", "blackberry10", "--", "-k", "abcd1234", "--verbose"]);
             expect(cordova.raw.build).toHaveBeenCalledWith({verbose: true, silent: false, platforms: ["blackberry10"], options: ["-k", "abcd1234", "--verbose"]});
         });
 
         it("will consume the first instance of either --verbose of -d", function () {
-            new CLI(["node", "cordova", "--verbose", "build", "blackberry10", "-k", "abcd1234", "-d"]);
+            cli(["node", "cordova", "--verbose", "build", "blackberry10", "--", "-k", "abcd1234", "-d"]);
             expect(cordova.raw.build).toHaveBeenCalledWith({verbose: true, silent: false, platforms: ["blackberry10"], options: ["-k", "abcd1234", "-d"]});
         });
 
         it("will consume the first instance of either --verbose of -d", function () {
-            new CLI(["node", "cordova", "-d", "build", "blackberry10", "-k", "abcd1234", "--verbose"]);
+            cli(["node", "cordova", "-d", "build", "blackberry10", "--", "-k", "abcd1234", "--verbose"]);
             expect(cordova.raw.build).toHaveBeenCalledWith({verbose: true, silent: false, platforms: ["blackberry10"], options: ["-k", "abcd1234", "--verbose"]});
         });
 
         it("will consume the first instance of --silent", function () {
-            new CLI(["node", "cordova", "--silent", "build", "blackberry10", "-k", "abcd1234", "--silent"]);
+            cli(["node", "cordova", "--silent", "build", "blackberry10", "--",  "-k", "abcd1234", "--silent"]);
             expect(cordova.raw.build).toHaveBeenCalledWith({verbose: false, silent: true, platforms: ["blackberry10"], options: ["-k", "abcd1234", "--silent"]});
         });
     });
@@ -98,13 +98,15 @@ describe("cordova cli", function () {
             spyOn(cordova.raw, "plugin").andReturn(Q());
         });
 
-        it("will call command with all arguments passed through", function () {
-            new CLI(["node", "cordova", "plugin", "add", "facebook", "--variable", "FOO=foo"]);
+        it("will pass variables", function () {
+            cli(["node", "cordova", "plugin", "add", "facebook", "--variable", "FOO=foo"]);
             expect(cordova.raw.plugin).toHaveBeenCalledWith(
                 "add",
-                ["facebook", "--variable", "FOO=foo"],
+                ["facebook"],
                 jasmine.any(Object)
             );
+            var opts = cordova.raw.plugin.calls[0].args[2];
+            expect(opts.cli_variables.FOO).toBe('foo');
         });
     });
 });

http://git-wip-us.apache.org/repos/asf/cordova-cli/blob/b5b4a14a/src/cli.js
----------------------------------------------------------------------
diff --git a/src/cli.js b/src/cli.js
index c088802..805af26 100644
--- a/src/cli.js
+++ b/src/cli.js
@@ -17,60 +17,73 @@
     under the License.
 */
 
-var path = require('path'),
-    optimist, // required in try-catch below to print a nice error message if it's not installed.
-    help = require('./help'),
-    _;
+/* jshint node:true, laxcomma:true, asi:true, strict:false, trailing:true, unused:vars */
 
-module.exports = function CLI(inputArgs) {
+
+var path = require('path')
+  , help = require('./help')
+
+// nopt and underscore are require()d in try-catch below to print a nice error
+// message if one of them is not installed.
+var nopt, _
+
+
+module.exports = cli
+function cli(inputArgs) {
     try {
-        optimist = require('optimist');
+        nopt = require('nopt');
         _ = require('underscore');
     } catch (e) {
-        console.error("Please run npm install from this directory:\n\t" +
-                      path.dirname(__dirname));
+        console.error(
+            'Please run npm install from this directory:\n\t' +
+            path.dirname(__dirname)
+        );
         process.exit(2);
     }
-    var cordova_lib = require('cordova-lib'),
-        CordovaError = cordova_lib.CordovaError,
-        cordova = cordova_lib.cordova,
-        plugman = cordova_lib.plugman;
+
+    // When changing command line arguments, update doc/help.txt accordingly.
+    var knownOpts =
+        { 'verbose' : Boolean
+        , 'version' : Boolean
+        , 'help' : Boolean
+        , 'silent' : Boolean
+        , 'experimental' : Boolean
+        , 'noregistry' : Boolean
+        , 'shrinkwrap' : Boolean
+        , 'usenpm' : Boolean
+        , 'copy-from' : String
+        , 'link-to' : path
+        , 'searchpath' : String
+        , 'variable' : Array
+        // Flags to be passed to `cordova run`
+        , 'debug' : Boolean
+        , 'release' : Boolean
+        , 'device' : Boolean
+        , 'emulator': Boolean
+        , 'target' : String
+        }
+
+    var shortHands =
+        { 'd' : '--verbose'
+        , 'v' : '--version'
+        , 'h' : '--help'
+        , 'src' : '--copy-from'
+        }
 
     // If no inputArgs given, use process.argv.
-    var tokens;
-    if (inputArgs) {
-        tokens = inputArgs.slice(2);
-    } else {
-        tokens = process.argv.slice(2);
-    }
+    inputArgs = inputArgs || process.argv
+    var args = nopt(knownOpts, shortHands, inputArgs)
 
-    // When changing command line arguments, update doc/help.txt accordingly.
-    var args = optimist(tokens)
-        .boolean('d')
-        .boolean('verbose')
-        .boolean('v')
-        .boolean('version')
-        .boolean('silent')
-        .boolean('experimental')
-        .boolean('noregistry')
-        .boolean('shrinkwrap')
-        .boolean('usenpm')
-        .string('copy-from')
-        .alias('copy-from', 'src')
-        .string('link-to')
-        .string('searchpath')
-        .argv;
-
-    if (args.v || args.version) {
-        return console.log(require('../package').version);
+    if (args.version) {
+        console.log( require('../package').version );
+        return
     }
 
-    var opts = {
-            platforms: [],
-            options: [],
-            verbose: (args.d || args.verbose),
-            silent: args.silent,
-        };
+    var cordova_lib = require('cordova-lib'),
+        CordovaError = cordova_lib.CordovaError,
+        cordova = cordova_lib.cordova,
+        plugman = cordova_lib.plugman;
+
 
     // For CrodovaError print only the message without stack trace.
     process.on('uncaughtException', function(err){
@@ -82,85 +95,113 @@ module.exports = function CLI(inputArgs) {
         process.exit(1);
     });
 
+
+    // Set up event handlers for logging and results emitted as events.
     cordova.on('results', console.log);
 
-    if (!opts.silent) {
+    if ( !args.silent ) {
         cordova.on('log', console.log);
         cordova.on('warn', console.warn);
         plugman.on('log', console.log);
         plugman.on('results', console.log);
         plugman.on('warn', console.warn);
-    } else {
-        // Remove the token.
-        tokens.splice(tokens.indexOf('--silent'), 1);
     }
 
-
-    if (opts.verbose) {
-        // Add handlers for verbose logging.
+    // Add handlers for verbose logging.
+    if (args.verbose) {
         cordova.on('verbose', console.log);
         plugman.on('verbose', console.log);
-
-        //Remove the corresponding token
-        if(args.d && args.verbose) {
-            tokens.splice(Math.min(tokens.indexOf("-d"), tokens.indexOf("--verbose")), 1);
-        } else if (args.d) {
-            tokens.splice(tokens.indexOf("-d"), 1);
-        } else if (args.verbose) {
-            tokens.splice(tokens.indexOf("--verbose"), 1);
-        }
     }
 
-    if (args.experimental) {
-        tokens.splice(tokens.indexOf("--experimental"), 1);
+    // TODO: Example wanted, is this functionality ever used?
+    // If there were arguments protected from nopt with a double dash, keep
+    // them in unparsedArgs. For example:
+    // cordova build ios -- --verbose --whatever
+    // In this case "--verbose" is not parsed by nopt and args.vergbose will be
+    // false, the unparsed args after -- are kept in unparsedArgs and can be
+    // passed downstream to some scripts invoked by Cordova.
+    var unparsedArgs = []
+    var parseStopperIdx =  args.argv.original.indexOf('--')
+    if (parseStopperIdx != -1) {
+        unparsedArgs = args.argv.original.slice(parseStopperIdx + 1)
     }
 
-    if (args.noregistry) {
-        tokens.splice(tokens.indexOf("--noregistry"), 1);
+    // args.argv.remain contains both the undashed args (like platform names)
+    // and whatever unparsed args that were protected by " -- ".
+    // "undashed" stores only the undashed args without those after " -- " .
+    var remain = args.argv.remain
+    var undashed = remain.slice(0, remain.length - unparsedArgs.length)
+    var cmd = undashed[0]
+    var subcommand
+    var msg
+    var known_platforms = Object.keys(cordova_lib.cordova_platforms)
+
+    if ( !cmd || cmd == 'help' || args.help ) {
+        return help()
     }
 
-    if (args.usenpm) {
-        tokens.splice(tokens.indexOf("--usenpm"), 1);
+    if ( !cordova.hasOwnProperty(cmd) ) {
+        msg =
+            'Cordova does not know ' + cmd + '; try `' + cordova_lib.binname +
+            ' help` for a list of all the available commands.'
+        throw new CordovaError(msg);
     }
 
-    var cmd = tokens && tokens.length ? tokens.splice(0,1) : undefined;
-    if (cmd === undefined) {
-        return help();
-    }
+    var opts = {
+        platforms: [],
+        options: [],
+        verbose: args.verbose || false,
+        silent: args.silent || false,
+    };
 
-    if (!cordova.hasOwnProperty(cmd)) {
-        throw new CordovaError('Cordova does not know ' + cmd + '; try `'+cordova_lib.binname+' help` for a list of all the available commands.');
-    }
 
     if (cmd == 'emulate' || cmd == 'build' || cmd == 'prepare' || cmd == 'compile' || cmd == 'run') {
-        // Filter all non-platforms into options
-        var platforms = cordova_lib.cordova_platforms;
-        tokens.forEach(function(option, index) {
-            if (platforms.hasOwnProperty(option)) {
-                opts.platforms.push(option);
-            } else {
-                opts.options.push(option);
+        // All options without dashes are assumed to be platform names
+        opts.platforms = undashed.slice(1)
+        var badPlatforms = _.difference(opts.platforms, known_platforms)
+        if( !_.isEmpty(badPlatforms) ) {
+            msg = 'Unknown platforms: ' + badPlatforms.join(', ')
+            throw new CordovaError(msg)
+        }
+
+        // Reconstruct the args to be passed along to platform scripts.
+        // This is an ugly temporary fix. The code spawning or otherwise
+        // calling into platform code should be dealing with this based
+        // on the parsed args object.
+        var downstreamArgs = []
+        var argNames = [ 'debug', 'release', 'device', 'emulator' ]
+        argNames.forEach(function(flag) {
+            if (args[flag]) {
+                downstreamArgs.push('--' + flag)
             }
-        });
-        cordova.raw[cmd].call(this, opts).done();
+        })
+        if (args.target) {
+            downstreamArgs.push('--target=' + args.target)
+        }
+        opts.options = downstreamArgs.concat(unparsedArgs)
+
+        cordova.raw[cmd].call(null, opts).done();
     } else if (cmd == 'serve') {
-        cordova.raw[cmd].apply(this, tokens).done();
+        var port = undashed[1]
+        cordova.raw.serve(port).done();
     } else if (cmd == 'create') {
         var cfg = {};
-        // If we got a forth parameter, consider it to be JSON to init the config.
-        if (args._[4]) {
-            cfg = JSON.parse(args._[4]);
+        // If we got a fourth parameter, consider it to be JSON to init the config.
+        if ( undashed[4] ) {
+            cfg = JSON.parse(undashed[4]);
         }
         var customWww = args['copy-from'] || args['link-to'];
         if (customWww) {
             if (customWww.indexOf(':') != -1) {
-                throw new CordovaError('Only local paths for custom www assets are supported.');
+                throw new CordovaError(
+                    'Only local paths for custom www assets are supported.'
+                );
             }
-            if (customWww.substr(0,1) === '~') {  // resolve tilde in a naive way.
+            if ( customWww.substr(0,1) === '~' ) {  // resolve tilde in a naive way.
                 customWww = path.join(process.env.HOME,  customWww.substr(1));
             }
             customWww = path.resolve(customWww);
-            var wwwCfg = {uri: customWww};
+            var wwwCfg = { uri: customWww };
             if (args['link-to']) {
                 wwwCfg.link = true;
             }
@@ -168,28 +209,46 @@ module.exports = function CLI(inputArgs) {
             cfg.lib.www = wwwCfg;
         }
         // create(dir, id, name, cfg)
-        cordova.raw[cmd].call(this, args._[1], args._[2], args._[3], cfg).done();
-    } else if( cmd == 'save' || cmd == 'restore'){
-        if(!opts.experimental && !args.experimental ){
-          throw new CordovaError('save and restore commands are experimental, please add "--experimental" to indicate that you understand that it may change in the future');
+        cordova.raw.create( undashed[1]  // dir to create the project in
+                          , undashed[2]  // App id
+                          , undashed[3]  // App name
+                          , cfg
+        ).done();
+    } else if ( cmd == 'save' || cmd == 'restore') {
+        if ( !args.experimental ) {
+            msg =
+                'save and restore commands are experimental, please ' +
+                'add "--experimental" to indicate that you understand that ' +
+                'it may change in the future'
+            throw new CordovaError(msg);
         }
-        var subcommand = tokens[0]
-        if(subcommand == 'plugins'){
-          cordova.raw[cmd].call(this,'plugins',{ shrinkwrap:args.shrinkwrap });
-        }else{
-          throw new CordovaError('Let cordova know what you want to '+ cmd + ', try "cordova '+ cmd +' plugins"');
+        subcommand  = undashed[1]
+        if (subcommand == 'plugins') {
+            cordova.raw[cmd].call(null, 'plugins', { shrinkwrap:args.shrinkwrap })
+        } else {
+            msg =
+                'Let cordova know what you want to '+ cmd +
+                ', try "cordova '+ cmd +' plugins"'
+            throw new CordovaError(msg)
         }
-    } else if (cmd == 'help') {
-        return help();
     } else {
         // platform/plugins add/rm [target(s)]
-        var subcommand = tokens[0]; // this has the sub-command, like "add", "ls", "rm" etc.
-        var targets = tokens.slice(1); // this should be an array of targets, be it platforms or plugins
-        var download_opts = {
-            searchpath: args.searchpath,
-            noregistry: args.noregistry,
-            usenpm: args.usenpm
+        subcommand = undashed[1] // sub-command like "add", "ls", "rm" etc.
+        var targets = undashed.slice(2) // array of targets, either platforms or plugins
+        var cli_vars = {}
+        if (args.variable) {
+            args.variable.forEach( function(s) {
+                var keyval = s.split('=')
+                var key = keyval[0].toUpperCase()
+                cli_vars[key] = keyval[1]
+            })
         }
-        cordova.raw[cmd].call(this, subcommand, targets, download_opts).done();
+        var download_opts =
+            { searchpath : args.searchpath
+            , noregistry : args.noregistry
+            , usenpm : args.usenpm
+            , cli_variables : cli_vars
+            }
+        cordova.raw[cmd](subcommand, targets, download_opts).done()
     }
-};
+}