in src/cli.js [236:447]
function cli (inputArgs) {
const args = nopt(knownOpts, shortHands, inputArgs);
process.on('uncaughtException', function (err) {
if (err.message) {
logger.error(err.message);
} else {
logger.error(err);
}
// Don't send exception details, just send that it happened
if (shouldCollectTelemetry) {
telemetry.track('uncaughtException');
}
process.exit(1);
});
logger.subscribe(events);
if (args.silent) {
logger.setLevel('error');
} else if (args.verbose) { // can't be both silent AND verbose, silent wins
logger.setLevel('verbose');
}
const cliVersion = pkg.version;
const usingPrerelease = !!semver.prerelease(cliVersion);
if (args.version || usingPrerelease) {
const libVersion = require('cordova-lib/package').version;
let toPrint = cliVersion;
if (cliVersion !== libVersion || usingPrerelease) {
toPrint += ' (cordova-lib@' + libVersion + ')';
}
if (args.version) {
logger.results(toPrint);
return Promise.resolve(); // Important! this will return and cease execution
} else { // must be usingPrerelease
// Show a warning and continue
logger.warn('Warning: using prerelease version ' + toPrint);
}
}
let warningPartial = null;
// If the Node.js versions does not meet our requirements or in a deprecation stage, display a warning.
if (
NODE_VERSION_REQUIREMENT &&
!semver.satisfies(NODE_VERSION, NODE_VERSION_REQUIREMENT)
) {
warningPartial = 'is no longer supported';
} else if (
NODE_VERSION_DEPRECATING_RANGE &&
semver.satisfies(NODE_VERSION, NODE_VERSION_DEPRECATING_RANGE)
) {
warningPartial = 'has been deprecated';
}
if (warningPartial) {
const upgradeMsg = 'Please upgrade to the latest Node.js version available (LTS version recommended).';
logger.warn(`Warning: Node.js ${NODE_VERSION} ${warningPartial}. ${upgradeMsg}`);
}
// 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.
let unparsedArgs = [];
const parseStopperIdx = args.argv.original.indexOf('--');
if (parseStopperIdx !== -1) {
unparsedArgs = args.argv.original.slice(parseStopperIdx + 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 " -- " .
const remain = args.argv.remain;
const undashed = remain.slice(0, remain.length - unparsedArgs.length);
const cmd = undashed[0];
let subcommand;
if (!cmd || cmd === 'help' || args.help) {
if (!args.help && remain[0] === 'help') {
remain.shift();
}
return printHelp(remain);
}
if (cmd === 'info') return info();
// Don't need to do anything with cordova-lib since config was handled above
if (cmd === 'config') return true;
if (cmd === 'create') {
const [, dest, id, name] = undashed;
return cordovaCreate(dest, { id, name, events, template: args.template });
}
if (!Object.prototype.hasOwnProperty.call(cordova, cmd)) {
const msg2 = 'Cordova does not know ' + cmd + '; try `' + cordova_lib.binname +
' help` for a list of all the available commands.';
throw new CordovaError(msg2);
}
const opts = {
platforms: [],
options: [],
verbose: args.verbose || false,
silent: args.silent || false,
nohooks: args.nohooks || [],
searchpath: args.searchpath
};
const platformCommands = ['emulate', 'build', 'prepare', 'compile', 'run', 'clean'];
if (platformCommands.indexOf(cmd) !== -1) {
// All options without dashes are assumed to be platform names
opts.platforms = undashed.slice(1);
// Pass nopt-parsed args to PlatformApi through opts.options
opts.options = args;
opts.options.argv = unparsedArgs;
return cordova[cmd].call(null, opts);
} else if (cmd === 'requirements') {
// All options without dashes are assumed to be platform names
opts.platforms = undashed.slice(1);
return cordova[cmd].call(null, opts.platforms)
.then(function (platformChecks) {
const someChecksFailed = Object.keys(platformChecks).map(function (platformName) {
events.emit('log', '\nRequirements check results for ' + platformName + ':');
const platformCheck = platformChecks[platformName];
if (platformCheck instanceof CordovaError) {
events.emit('warn', 'Check failed for ' + platformName + ' due to ' + platformCheck);
return true;
}
let someChecksFailed = false;
// platformCheck is expected to be an array of conditions that must be met
// the browser platform currently returns nothing, which was breaking here.
if (platformCheck && platformCheck.forEach) {
platformCheck.forEach(function (checkItem) {
const checkSummary = checkItem.name + ': ' +
(checkItem.installed ? 'installed ' : 'not installed ') +
(checkItem.installed ? checkItem.metadata.version.version || checkItem.metadata.version : '');
events.emit('log', checkSummary);
if (!checkItem.installed) {
someChecksFailed = true;
events.emit('warn', checkItem.metadata.reason);
}
});
}
return someChecksFailed;
}).some(function (isCheckFailedForPlatform) {
return isCheckFailedForPlatform;
});
if (someChecksFailed) {
throw new CordovaError('Some of requirements check failed');
}
});
} else if (cmd === 'serve') {
const port = undashed[1];
return cordova.serve(port);
} else {
// platform/plugins add/rm [target(s)]
subcommand = undashed[1]; // sub-command like "add", "ls", "rm" etc.
const targets = undashed.slice(2); // array of targets, either platforms or plugins
const cli_vars = {};
if (args.variable) {
args.variable.forEach(function (strVar) {
// CB-9171
const keyVal = strVar.split('=');
if (keyVal.length < 2) {
throw new CordovaError('invalid variable format: ' + strVar);
} else {
const key = keyVal.shift().toUpperCase();
const val = keyVal.join('=');
cli_vars[key] = val;
}
});
}
args.save = !args.nosave;
args.production = !args.noprod;
if (args.searchpath === undefined) {
// User explicitly did not pass in searchpath
args.searchpath = conf.get('searchpath');
}
if (args['save-exact'] === undefined) {
// User explicitly did not pass in save-exact
args['save-exact'] = conf.get('save-exact');
}
const download_opts = {
searchpath: args.searchpath,
noregistry: args.noregistry,
nohooks: args.nohooks,
cli_variables: cli_vars,
link: args.link || false,
save: args.save,
save_exact: args['save-exact'] || false,
shrinkwrap: args.shrinkwrap || false,
force: args.force || false,
production: args.production
};
return cordova[cmd](subcommand, targets, download_opts);
}
}