UNPKG

azure-cli

Version:

Microsoft Azure Cross Platform Command Line tool

330 lines (264 loc) 9.15 kB
/** * Copyright (c) Microsoft. All rights reserved. * * Licensed 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 KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ 'use strict'; // // Extensions to Commander to support nested commands / help system // var _ = require('underscore'); var commander = require('commander'); var fs = require('fs'); var path = require('path'); var util = require('util'); var utils = require('./utils'); var pjson = require('../../package.json'); function ExtendedCommand(name) { ExtendedCommand['super_'].call(this, name); } util.inherits(ExtendedCommand, commander.Command); _.extend(ExtendedCommand.prototype, { ////////////////////////////// // override help subsystem fullName: function () { var name = this.name; var scan = this.parent; while (scan && scan.parent !== undefined) { name = scan.name + ' ' + name; scan = scan.parent; } return name; }, usage: function (str) { var ret; if (str) { ret = commander.Command.prototype.usage.call(this, str); } else { ret = commander.Command.prototype.usage.call(this); ret = ret.replace(/,/g,' '); } return ret; }, helpInformation: function() { var self = this; if (!self.parent) { var args = process.argv.slice(0, 2); var raw = self.normalize(process.argv.slice(2)); var packagePath = path.join(__dirname, '../../package.json'); var packageInfo = JSON.parse(fs.readFileSync(packagePath)); if (raw.indexOf('-v') >= 0) { console.log(packageInfo.version); } else if (raw.indexOf('--version') >= 0) { console.log(util.format('%s (node: %s)', packageInfo.version, process.versions.node)); } else { self.setupCommand(args, raw, true); if (this.output.format().logo === 'on') { this.output.info(' _ _____ _ ___ ___'.cyan); this.output.info(' /_\\ |_ / | | | _ \\ __|'.cyan); this.output.info(' _ ___'.grey + '/ _ \\'.cyan + '__'.grey + '/ /| |_| | / _|'.cyan + '___ _ _'.grey); this.output.info('(___ '.grey + '/_/ \\_\\/___|\\___/|_|_\\___|'.cyan + ' _____)'.grey); this.output.info(' (_______ _ _) _ ______ _)_ _ '.grey); this.output.info(' (______________ _ ) (___ _ _)'.grey); this.output.info(''); } this.output.info('Microsoft Azure: Microsoft\'s Cloud Platform'); this.output.info(''); this.output.info('Tool version', packageInfo.version); self.helpCommands(); self.helpCategoriesSummary(self.showMore()); self.helpOptions(); } } else { this.output.help(self.description()); this.output.help(''); this.output.help('Usage:', self.fullName() + ' ' + self.usage()); self.helpOptions(); } return ''; }, showMore: function () { var raw = this.normalize(process.argv.slice(2)); return raw.indexOf('--help') >= 0 || raw.indexOf('-h') >= 0; }, categoryHelpInformation: function() { var self = this; this.output.help(self.description()); self.helpCommands(); self.helpCategories(-1) ; self.helpOptions(); return ''; }, commandHelpInformation: function() { var self = this; if (self._detailedDescription) { this.output.help(self.detailedDescription()); } else { this.output.help(self.description()); } this.output.help(''); this.output.help('Usage:', self.fullName() + ' ' + self.usage()); self.helpOptions(); return ''; }, helpJSON: function() { var self = this; var result = _.tap({}, function(res){ if(_.isNull(self.parent) || _.isUndefined(self.parent)){ res.name = pjson.name; res.description = pjson.description; res.author = pjson.author; res.version = pjson.version; res.contributors = pjson.contributors; res.homepage = pjson.homepage; res.licenses = pjson.licenses; } else { res.name = self.fullName(); res.description = self.description(); } res.usage = self.usage(); }); if (this.categories && Object.keys(this.categories).length > 0) { result.categories = {}; for (var name in this.categories) { result.categories[name] = this.categories[name].helpJSON(); } } if (this.commands && this.commands.length > 0) { result.commands = []; this.commands.forEach(function (cmd) { var command = { name: cmd.fullName(), description: cmd.description(), options: cmd.options, usage: cmd.usage() }; result.commands.push(command); }); } return result; }, helpCategories: function(levels) { for (var name in this.categories) { var cat = this.categories[name]; this.output.help(''); this.output.help(cat.description().cyan); if (levels === -1 || levels > 0) { for (var index in cat.commands) { var cmd = cat.commands[index]; this.output.help(' ', cmd.fullName() + ' ' + cmd.usage()); } cat.helpCategories(levels !== -1 ? --levels : -1); } else { this.output.help(' ', cat.fullName()); } } }, helpCategoriesSummary: function(showMore) { var self = this; var categories = []; function scan(parent, levels, each) { for (var name in parent.categories) { var cat = parent.categories[name]; each(cat); if (levels === -1 || levels > 0) { scan(cat, levels !== -1 ? --levels : -1, each); } } } scan(this, showMore ? -1 : 0, function (cat) { categories.push(cat); }); var maxLength = 14; // Sort categories by alphabetical order categories.sort(function (a, b) { return (a.fullName() < b.fullName()) ? -1 : (a.fullName() > b.fullName()) ? 1 : 0; }); categories.forEach(function (cat) { if (maxLength < cat.fullName().length) maxLength = cat.fullName().length; }); self.output.help(''); self.output.help('Commands:'); categories.forEach(function (cat) { var name = cat.fullName(); while (name.length < maxLength) { name += ' '; } self.output.help(' ' + name + ' ' + cat.description().cyan); }); }, helpCommands: function() { var self = this; this.commands.forEach(function (cmd) { self.output.help(''); self.output.help(cmd.description().cyan); self.output.help(' ', cmd.fullName() + ' ' + cmd.usage()); }); }, helpOptions: function(cmdExtra) { var self = this; var revert = self.options; if (cmdExtra) { self.options = self.options.concat(cmdExtra.options); } this.output.help(''); this.output.help('Options:'); self.optionHelp().split('\n').forEach(function (line) { self.output.help(' ', line); }); self.options = revert; }, option: function(flags, description, fn, defaultValue) { var self = this; var option = new commander.Option(flags, description); // Remove preexistant option with same name self.options = self.options.filter(function (o) { return o.name() !== option.name() || o.long !== option.long; }); var oname = option.name(); var name = utils.camelcase(oname); if (!self.optionValues) { self.optionValues = {}; } // default as 3rd arg if ('function' !== typeof fn) { defaultValue = fn; fn = null; } // preassign default value only for --no-*, [optional], or <required> if (false === option.bool || option.optional || option.required) { // when --no-* we make sure default is true if (false === option.bool) defaultValue = true; // preassign only if we have a default if (undefined !== defaultValue) self.optionValues[name] = defaultValue; } // register the option this.options.push(option); // when it's passed assign the value // and conditionally invoke the callback this.on(oname, function (val) { // coercion if (val && fn) val = fn(val); // unassigned or bool if ('boolean' === typeof self.optionValues[name] || 'undefined' === typeof self.optionValues[name]) { // if no value, bool true, and we have a default, then use it! if (!val) { self.optionValues[name] = option.bool ? defaultValue || true : false; } else { self.optionValues[name] = val; } } else if (val) { // reassign self.optionValues[name] = val; } }); return this; } }); module.exports = ExtendedCommand;