cloudcms-cli
Version:
Cloud CMS Command-Line client
526 lines (447 loc) • 14.9 kB
JavaScript
var walk = require('fs-walk');
var path = require("path");
var helper = require("../helper");
var realist = require("../../vendor/realist");
var DocsFn = require("../docs/docs");
// dns fix for Node 17 +
// see: https://nodejs.org/api/dns.html#dnssetdefaultresultorderorder
var dns = require("dns");
dns.setDefaultResultOrder("ipv4first");
var fs = require("fs");
var pkg = require("../../package.json");
var generateSummary = function(schema)
{
return helper.generateSchemaSummary(schema);
};
var COMMAND_PAD_END = 25;
var showCommandUsage = function(groupName, command)
{
var schema = command.schema();
var commandText = " cloudcms";
if (groupName) {
commandText += " " + groupName;
}
commandText += " " + command.name;
if (schema) {
commandText += generateSummary(schema);
}
console.log(" Command Usage:");
console.log("");
console.log(commandText);
console.log("");
if (schema && schema.properties && schema.properties.length > 0)
{
console.log(" Command Options:");
console.log("");
for (var i = 0; i < schema.properties.length; i++)
{
var prop = schema.properties[i];
var propertyName = prop.name;
var description = prop.helper;
if (!description) {
description = prop.description;
}
var required = (prop.required ? "true": "false");
var type = prop.type;
var args = "";
for (var z = 0; z < prop.args.length; z++)
{
if (z > 0) {
args += ", ";
}
args += "--" + prop.args[z];
}
console.log(" " + propertyName);
console.log(" - required: " + required);
console.log(" - type: " + type);
console.log(" - args: " + args);
console.log(" - description: " + description);
}
console.log("");
}
};
var showHelp = function(args, groups, commands)
{
console.log("");
console.log("Cloud CMS Command Line Interface - Version " + pkg.version);
console.log("");
console.log(" Usage:");
console.log("");
console.log(" cloudcms <command> [switches...]");
console.log(" cloudcms <group> <command> [switches...]");
console.log("");
// strip out --help from the args list
var i = 0;
do
{
if (i < args.length)
{
if (args[i] === "--help")
{
args.splice(i, 1);
}
else
{
i++;
}
}
}
while (i < args.length);
if (args.length > 0)
{
if (args.length > 1)
{
// we have group + command
var groupName = args[0];
var commandName = args[1];
// find all commands in this group
var command = null;
for (var i = 0; i < commands.length; i++)
{
if (commands[i].group === groupName && commands[i].name === commandName)
{
command = commands[i];
}
}
if (command)
{
return showCommandUsage(groupName, command);
}
}
// we either couldn't find the group/command or we only have group info or only have command info
var name = args[0];
// are there any commands with NO group but where name matches command?
var command = null;
for (var i = 0; i < commands.length; i++)
{
if (!commands[i].group && commands[i].name === name)
{
command = commands[i];
}
}
if (command)
{
return showCommandUsage(null, command);
}
// at this point, we think we have group info
// find all commands in this group
var groupCommands = [];
for (var i = 0; i < commands.length; i++)
{
if (commands[i].group === name)
{
groupCommands.push(commands[i]);
}
}
// show commands?
if (groupCommands.length > 0)
{
var groupDescription = null;
for (var z = 0; z < groups.length; z++) {
if (groups[z].name === name) {
groupDescription = groups[z].description;
}
}
console.log(" " + groupDescription + ":");
console.log("");
for (var i = 0; i < groupCommands.length; i++)
{
console.log(" " + groupCommands[i].name.padEnd(COMMAND_PAD_END) + " - " + groupCommands[i].description);
}
console.log("");
return;
}
}
// show all groups
console.log(" The following command groups are available:");
console.log("");
for (var i = 0; i < groups.length; i++) {
console.log(" " + groups[i].name.padEnd(COMMAND_PAD_END) + " - " + groups[i].description);
}
console.log("");
console.log(" The following root commands are available");
console.log("");
for (var i = 0; i < commands.length; i++) {
if (!commands[i].group) {
console.log(" " + commands[i].name.padEnd(COMMAND_PAD_END) + " - " + commands[i].description);
}
}
console.log("");
console.log(" Global options");
console.log("");
console.log(" --help - Shows help about a group, command or the tool");
console.log(" --version - Shows the client version");
console.log(" --pretty - Renders JSON output in a more readable format");
console.log(" --metadata - Pulls back system metadata for record(s)");
console.log(" --full - Pulls back full objects for result sets");
console.log(" --last - Automatically applies arguments from last command");
console.log(" --authcode - Supplied an MFA authenticator code for login");
console.log(" --light - Hands back record sets with light properties (_doc, title, etc)");
console.log(" --ids - Hands back an array of IDs for record sets");
console.log(" --profile <profile> - Connects to Cloud CMS using a specific stored profile");
console.log(" --timeout <timeout> - Specifies the HTTP timeout to use (in MS) for network calls");
console.log("");
};
var finishHandler = function(err)
{
if (err) {
//console.trace();
console.log("There was a problem:");
console.log(" -> " + err.message);
console.log("");
process.exit(1);
}
process.exit(0);
};
module.exports = function(args)
{
var basePath = path.resolve(__dirname, "../..");
// scan for groups
var groups = [];
walk.walkSync(path.join(basePath, "lib/groups/support"), function (basedir, filename, stat) {
if (!stat.isDirectory())
{
var GroupClass = require(basedir + "/" + filename);
groups.push(new GroupClass());
}
});
var groupsByName = {};
for (var z = 0; z < groups.length; z++)
{
groupsByName[groups[z].name] = groups[z];
}
// scan for commands
var commands = [];
walk.walkSync(path.join(basePath, "lib/commands/support"), function (basedir, filename, stat) {
if (!stat.isDirectory())
{
var CommandClass = require(basedir + "/" + filename);
commands.push(new CommandClass());
}
});
// sort groups and commands
groups.sort(function(a, b) {
if(a.name < b.name) { return -1; }
if(a.name > b.name) { return 1; }
return 0;
});
commands.sort(function(a, b) {
if(a.name < b.name) { return -1; }
if(a.name > b.name) { return 1; }
return 0;
});
// special case - docs gen
if (args.length > 0 && args[0] === "generate-docs")
{
var text = DocsFn(groups, commands);
return console.log(text);
}
// special case - version
if (args.length > 0 && args[0] === "--version")
{
return console.log(pkg.version);
}
// parse command line string and find a command handler
var command = null;
// use first argument only
var name = args[0];
for (var i = 0; i < commands.length; i++) {
if (!commands[i].group && commands[i].name === name) {
command = commands[i];
break;
}
}
if (!command && args.length > 1) {
// match on group and name
var group = args[0];
var name = args[1];
for (var i = 0; i < commands.length; i++) {
if (commands[i].group === group && commands[i].name === name) {
command = commands[i];
break;
}
}
}
if (!command) {
return showHelp(args, groups, commands);
}
// if --help is provided, show help
var doShowHelp = false;
for (var i = 0; i < args.length; i++)
{
if (args[i] === "--help")
{
doShowHelp = true;
}
}
if (doShowHelp)
{
return showHelp(args, groups, commands);
}
var commandGroup = groupsByName[command.group];
var fn = function (commandGroup, command, schema, callback) {
return function (opt) {
// support for ".rc" file
var rcFileJson = readRcFile();
if (rcFileJson)
{
if (rcFileJson.global)
{
if (rcFileJson.global.arguments)
{
for (var name in rcFileJson.global.arguments)
{
var value = rcFileJson.global.arguments[name];
if (value)
{
opt[name] = value;
}
}
}
}
}
// whether to use the last arguments
if (opt["last"])
{
var last = readLastCommandFile();
if (last)
{
if (last.arguments)
{
for (var name in last.arguments)
{
var value = last.arguments[name];
if (value)
{
opt[name] = value;
}
}
}
}
}
// store this on process
if (opt["pretty"])
{
process.pretty = true;
}
// store this on process
if (opt["metadata"])
{
process.metadata = true;
}
// store this on process
if (opt["full"])
{
process.full = true;
}
// store this on process
if (opt["fields"])
{
var fieldsString = "" + opt.fields;
fieldsString = fieldsString.replace(/'/g, '"');
process.fields = JSON.parse(fieldsString);
}
// store this on process
if (opt["light"])
{
process.light = true;
process.metadata = true;
process.full = true;
}
// store this on process
if (opt["ids"])
{
process.ids = true;
}
// support for credentials profile
if (opt["profile"])
{
process.cloudcms_profile = opt["profile"];
}
// support for timeout
if (opt["timeout"])
{
try {
process.cloudcms_timeout = parseInt("" + opt["timeout"], 10);
} catch (e) {
// swallow
}
}
// support for a authenticator code
process.authenticator_code = opt["authcode"];
// allow for "admin" username and password to be picked up from environment file
if (commandGroup && commandGroup.admin)
{
if (process.env.CLOUDCMS_CLI_ADMIN_USERNAME)
{
opt["username"] = process.env.CLOUDCMS_CLI_ADMIN_USERNAME;
}
if (process.env.CLOUDCMS_CLI_ADMIN_PASSWORD)
{
opt["password"] = process.env.CLOUDCMS_CLI_ADMIN_PASSWORD;
}
}
helper.processOptions(schema, opt, command, function (err, options) {
if (err) {
return callback(err);
}
command.handle(options, function (err) {
writeLastCommandFile(command, schema, options);
callback(err);
});
});
}
}(commandGroup, command, command.schema(), finishHandler);
var writeLastCommandFile = function(command, schema, options)
{
var last = {
"command": {
"group": command.config.group,
"name": command.config.name
},
"arguments": {}
};
if (schema)
{
var properties = schema.properties;
if (properties)
{
for (var i = 0; i < properties.length; i++)
{
var prop = properties[i];
if (prop.required)
{
if (prop.args && prop.args.length > 0)
{
last.arguments[prop.args[0]] = options[prop.name];
}
}
}
}
}
fs.writeFileSync(".last_command", "" + JSON.stringify(last, null, 2));
};
var readLastCommandFile = function()
{
var exists = fs.existsSync(".last_command");
if (!exists)
{
return {};
}
var text = "" + fs.readFileSync(".last_command");
return JSON.parse(text);
};
var readRcFile = function()
{
var exists = fs.existsSync(".rc");
if (!exists)
{
return {};
}
var text = "" + fs.readFileSync(".rc");
return JSON.parse(text);
};
process.stringArgs = [];
process.stringArgs.push("authcode");
realist(fn);
};