Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
232 changes: 230 additions & 2 deletions src/cli/base-cli-handler.js
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,10 @@

const commandLineArgs = require('command-line-args');
const commandLineUsage = require('command-line-usage');
const AppHelper = require('../helpers/app-helper');
const Errors = require('../helpers/errors');
const ErrorMessages = require('../helpers/error-messages');
const constants = require('../helpers/constants');

class CLIHandler {
constructor() {
Expand All @@ -29,9 +33,44 @@ class CLIHandler {
return commandLineArgs(commandDefinitions, Object.assign({camelCase: true, partial: true,}, options))
}

help(hide = [], showOptions = true, hasCommands = true, additionalSection = []) {
help(show = [], showOptions = true, hasCommands = true, additionalSection = []) {

if (show.length === 0) {
//show all
this.helpAll(show, showOptions, hasCommands, additionalSection)
} else {
//show list
this.helpSome(show, showOptions)
}
}

helpSome(show = [], showOptions = true,) {
const options = Object.keys(this.commands)
.filter((key) => show.indexOf(key) !== -1)
.map((key) => ({
header: key,
optionList: this.commandDefinitions,
group: [key],
}));

const sections = [
{
header: 'Usage',
content: `$ iofog-controller ${this.name} ${show.length === 1 ? show : '<command>'} <options>`,
},
].concat(showOptions ? options : []);

const usage = [
{
header: 'ioFogController',
content: 'Fog Controller project for Eclipse IoFog @ iofog.org \\nCopyright (c) 2018 Edgeworx, Inc.',
}
].concat(sections);
console.log(commandLineUsage(usage))
}

helpAll(show = [], showOptions = true, hasCommands = true, additionalSection = []) {
const options = Object.keys(this.commands)
.filter((key) => hide.indexOf(key) === -1)
.map((key) => ({
header: key,
optionList: this.commandDefinitions,
Expand Down Expand Up @@ -62,6 +101,195 @@ class CLIHandler {
].concat(sections);
console.log(commandLineUsage(usage))
}

handleCLIError(error, args) {
switch (error.name) {
case "UNKNOWN_OPTION":
console.log("Invalid argument '" + error.optionName.split('-').join('') + "'");
break;
case "UNKNOWN_VALUE":
if (this.commands[args[0]] && args[1] === 'help') {
return this.helpSome([args[0]]);
}
console.log("Invalid value " + error.value);
break;
case "InvalidArgumentError":
console.log(error.message);
break;
case "InvalidArgumentTypeError":
console.log(error.message);
break;
case "ALREADY_SET":
console.log("Parameter '" + error.optionName + "' is used multiple times");
break;
case 'CLIArgsNotProvidedError':
if (this.commands[args[0]]) {
return this.helpSome([args[0]]);
}
break;
default:
console.log(JSON.stringify(error));
break;
}
}

validateParameters(command, commandDefinitions, pArgs) {
// 1st argument = command
let args = pArgs.slice();
args.shift();

const possibleAliasesList = _getPossibleAliasesList(command, commandDefinitions);
const possibleArgsList = _getPossibleArgsList(command, commandDefinitions);
if (possibleAliasesList.length === 0 && possibleArgsList.length === 0) {
return
}

let expectedValueType;
let currentArgName;

if (args.length === 0) {
throw new Errors.CLIArgsNotProvidedError();
}
const argsMap = argsArrayAsMap(args);

argsMap.forEach((values, key) => {
if (key.startsWith("--")) { // argument
// '--ssl-cert' format -> 'ssl-cert' format
const argument = key.substr(2);
_validateArg(argument, possibleArgsList);
currentArgName = argument;
expectedValueType = _getValType(argument, commandDefinitions);
} else if (key.startsWith("-")) { // alias
// '-q' format -> 'q' format
const alias = key.substr(1);
_validateArg(alias, possibleAliasesList);
currentArgName = alias;
expectedValueType = _getValType(alias, commandDefinitions);
}

const valType = _getCurrentValType(values);
//TODO else validate multiply parameters. Add after multiply parameters will be used in cli api

let isValidType = _validateType(expectedValueType, valType);

if (!isValidType) {
throw new Errors.InvalidArgumentTypeError(AppHelper.formatMessage(ErrorMessages.INVALID_CLI_ARGUMENT_TYPE, currentArgName, expectedValueType));
}
})
}
}

function argsArrayAsMap(args) {
let argsVars = args.join(' ').split(/(?= -{1,2}[^-]+)/);
const argsMap = new Map();
argsVars
.map(pair => pair.trim())
.map(pair => {
const spaceIndex = pair.indexOf(' ');
let key, values;
if (spaceIndex !== -1) {
key = pair.substr(0, pair.indexOf(' '));
values = pair.substr(pair.indexOf(' ')+1).split(' ');
argsMap.set(key, values);
} else {
key = pair;
values = [];
}
argsMap.set(key, values);

});
return argsMap;
}

function _validateArg(arg, aliasesList) {
const valid = aliasesList.includes(arg);
if (!valid) {
throw new Errors.InvalidArgumentError("Invalid argument '" + arg + "'");
}
}

function _getPossibleAliasesList(command, commandDefinitions) {
const possibleAliasesList = [];

for (const definition of commandDefinitions) {
const group = definition.group;
const isGroupArray = group.constructor === Array;
if (isGroupArray) {
for (const gr of group) {
if (gr === command) {
possibleAliasesList.push(definition.alias);
break;
}
}
} else {
if (group === command) {
possibleAliasesList.push(definition.alias);
}
}
}

return possibleAliasesList;
}

function _getPossibleArgsList(command, commandDefinitions) {
const possibleArgsList = [];

for (const definition of commandDefinitions) {
const group = definition.group;
const isGroupArray = group.constructor === Array;
if (isGroupArray) {
for (const gr of group) {
if (gr === command) {
possibleArgsList.push(definition.name);
break;
}
}
} else {
if (group === command) {
possibleArgsList.push(definition.name);
}
}
}

return possibleArgsList;
}

function _getValType(arg, commandDefinitions) {
const command = commandDefinitions
.filter(def => def.name === arg || def.alias === arg)[0];
return command.type.name.toLowerCase();
}

function _getCurrentValType(values) {
let valType;
if (values.length === 0) {
valType = 'boolean';
} else if (values.length === 1) {
const firstVal = Number(values[0]);
if (Number.isNaN(firstVal.valueOf())) {
valType = 'string';
} else if (Number.isInteger(firstVal.valueOf())) {
valType = 'integer';
} else {
valType = 'float'
}
}
return valType;
}

function _validateType(expectedValueType, valType) {
let isValidType = true;
if (expectedValueType === 'string' && valType === 'boolean') {
isValidType = false;
} else if ((expectedValueType === 'float' || expectedValueType === 'number')
&& (valType !== 'float' && valType !== 'number' && valType !== 'integer')) {
isValidType = false;
} else if (expectedValueType === 'integer' && valType !== 'integer') {
isValidType = false;
} else if (expectedValueType === 'boolean' && valType !== 'boolean') {
isValidType = false;
}
return isValidType;
}

module.exports = CLIHandler;
6 changes: 3 additions & 3 deletions src/cli/catalog.js
Original file line number Diff line number Diff line change
Expand Up @@ -158,7 +158,7 @@ class Catalog extends BaseCLIHandler {

const command = catalogCommand.command.command;

AppHelper.validateParameters(command, this.commandDefinitions, args.argv);
this.validateParameters(command, this.commandDefinitions, args.argv);

switch (command) {
case constants.CMD_ADD:
Expand All @@ -181,12 +181,12 @@ class Catalog extends BaseCLIHandler {
return this.help()
}
} catch (error) {
AppHelper.handleCLIError(error);
this.handleCLIError(error, args.argv);
}
}

help() {
super.help([constants.CMD_LIST], true, true, [
super.help([], true, true, [
{
header: 'JSON File Schema',
content: [
Expand Down
4 changes: 2 additions & 2 deletions src/cli/config.js
Original file line number Diff line number Diff line change
Expand Up @@ -101,7 +101,7 @@ class Config extends BaseCLIHandler {

const command = configCommand.command.command;

AppHelper.validateParameters(command, this.commandDefinitions, args.argv);
this.validateParameters(command, this.commandDefinitions, args.argv);

switch (command) {
case constants.CMD_ADD:
Expand All @@ -121,7 +121,7 @@ class Config extends BaseCLIHandler {
return this.help([], true, false)
}
} catch (error) {
AppHelper.handleCLIError(error);
this.handleCLIError(error, args.argv);
}
}
}
Expand Down
4 changes: 2 additions & 2 deletions src/cli/connector.js
Original file line number Diff line number Diff line change
Expand Up @@ -84,7 +84,7 @@ class Connector extends BaseCLIHandler {

const command = connectorCommand.command.command;

AppHelper.validateParameters(command, this.commandDefinitions, args.argv);
this.validateParameters(command, this.commandDefinitions, args.argv);

switch (command) {
case constants.CMD_ADD:
Expand All @@ -104,7 +104,7 @@ class Connector extends BaseCLIHandler {
return this.help([constants.CMD_LIST])
}
} catch (error) {
AppHelper.handleCLIError(error);
this.handleCLIError(error, args.argv);
}
}

Expand Down
4 changes: 2 additions & 2 deletions src/cli/controller.js
Original file line number Diff line number Diff line change
Expand Up @@ -46,7 +46,7 @@ class Controller extends BaseCLIHandler {

const command = controllerCommand.command.command;

AppHelper.validateParameters(command, this.commandDefinitions, args.argv);
this.validateParameters(command, this.commandDefinitions, args.argv);

switch (command) {
case constants.CMD_STATUS:
Expand All @@ -66,7 +66,7 @@ class Controller extends BaseCLIHandler {
return this.help([constants.CMD_LIST])
}
} catch (error) {
AppHelper.handleCLIError(error);
this.handleCLIError(error, args.argv);
}
}

Expand Down
4 changes: 2 additions & 2 deletions src/cli/diagnostics.js
Original file line number Diff line number Diff line change
Expand Up @@ -83,7 +83,7 @@ class Diagnostics extends BaseCLIHandler {

const command = diagnosticCommand.command.command;

AppHelper.validateParameters(command, this.commandDefinitions, args.argv);
this.validateParameters(command, this.commandDefinitions, args.argv);

switch (command) {
case constants.CMD_STRACE_UPDATE:
Expand All @@ -106,7 +106,7 @@ class Diagnostics extends BaseCLIHandler {
return this.help([constants.CMD_LIST])
}
} catch (error) {
AppHelper.handleCLIError(error);
this.handleCLIError(error, args.argv);
}
}
}
Expand Down
6 changes: 3 additions & 3 deletions src/cli/flow.js
Original file line number Diff line number Diff line change
Expand Up @@ -87,7 +87,7 @@ class Flow extends BaseCLIHandler {

const command = flowCommand.command.command;

AppHelper.validateParameters(command, this.commandDefinitions, args.argv);
this.validateParameters(command, this.commandDefinitions, args.argv);

switch (command) {
case constants.CMD_ADD:
Expand All @@ -110,12 +110,12 @@ class Flow extends BaseCLIHandler {
return this.help([constants.CMD_LIST])
}
} catch (error) {
AppHelper.handleCLIError(error);
this.handleCLIError(error, args.argv);
}
}

help() {
super.help([constants.CMD_LIST], true, true, [
super.help([], true, true, [
{
header: 'JSON File Schema',
content: [
Expand Down
6 changes: 3 additions & 3 deletions src/cli/iofog.js
Original file line number Diff line number Diff line change
Expand Up @@ -215,7 +215,7 @@ class IOFog extends BaseCLIHandler {

const command = iofogCommand.command.command;

AppHelper.validateParameters(command, this.commandDefinitions, args.argv);
this.validateParameters(command, this.commandDefinitions, args.argv);

switch (command) {
case constants.CMD_ADD:
Expand Down Expand Up @@ -253,12 +253,12 @@ class IOFog extends BaseCLIHandler {
return this.help()
}
} catch (error) {
AppHelper.handleCLIError(error);
this.handleCLIError(error, args.argv);
}
}

help() {
super.help([constants.CMD_LIST], true, true, [
super.help([], true, true, [
{
header: 'JSON File Schema',
content: [
Expand Down
Loading