@zowe/imperative
Version:
framework for building configurable CLIs
526 lines • 27.3 kB
JavaScript
/*
* This program and the accompanying materials are made available under the terms of the
* Eclipse Public License v2.0 which accompanies this distribution, and is available at
* https://www.eclipse.org/legal/epl-v20.html
*
* SPDX-License-Identifier: EPL-2.0
*
* Copyright Contributors to the Zowe Project.
*
*/
var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, P, generator) {
function adopt(value) { return value instanceof P ? value : new P(function (resolve) { resolve(value); }); }
return new (P || (P = Promise))(function (resolve, reject) {
function fulfilled(value) { try { step(generator.next(value)); } catch (e) { reject(e); } }
function rejected(value) { try { step(generator["throw"](value)); } catch (e) { reject(e); } }
function step(result) { result.done ? resolve(result.value) : adopt(result.value).then(fulfilled, rejected); }
step((generator = generator.apply(thisArg, _arguments || [])).next());
});
};
Object.defineProperty(exports, "__esModule", { value: true });
exports.EnvQuery = void 0;
const os = require("os");
const lodash = require("lodash");
const path = require("path");
const spawn = require("cross-spawn");
const config_1 = require("../../../../../config");
const utilities_1 = require("../../../../../utilities");
const operations_1 = require("../../../../../operations");
const CliUtils_1 = require("../../../../../utilities/src/CliUtils");
const PluginIssues_1 = require("../../../plugins/utilities/PluginIssues");
const EnvItems_1 = require("./EnvItems");
const censor_1 = require("../../../../../censor");
/**
* This class encapulates operations for Zowe CLI environment information.
* We use the term environment loosely. Sometimes it is an environment variable.
* It can also be something in the runtime environment, like version of NodeJS.
*/
class EnvQuery {
// __________________________________________________________________________
/**
* For the specified itemId, get its value.
*
* @param itemId ID of the environmental item for which we want get the value.
* @param getItemOpts options that affect our behavior.
*
* @returns An object with the item value, a display message, and a problem message.
*/
static getEnvItemVal(itemId_1) {
return __awaiter(this, arguments, void 0, function* (itemId, getItemOpts = {}) {
const getResult = { itemVal: null, itemValMsg: "", itemProbMsg: "" };
switch (itemId) {
case EnvItems_1.ItemId.ZOWE_VER: {
EnvQuery.getZoweVer(getResult);
break;
}
case EnvItems_1.ItemId.NODEJS_VER: {
getResult.itemVal = process.versions.node;
getResult.itemValMsg = "Node.js version = " + getResult.itemVal;
break;
}
case EnvItems_1.ItemId.PLATFORM: {
getResult.itemVal = os.platform();
getResult.itemValMsg = "O.S. platform = " + getResult.itemVal;
break;
}
case EnvItems_1.ItemId.ARCHITECTURE: {
getResult.itemVal = os.arch();
getResult.itemValMsg = "O.S. architecture = " + getResult.itemVal;
break;
}
case EnvItems_1.ItemId.OS_PATH: {
getResult.itemVal = process.env.PATH;
getResult.itemValMsg = os.EOL + "O.S. PATH = " + getResult.itemVal;
break;
}
case EnvItems_1.ItemId.ZOWE_CLI_HOME: {
getResult.itemVal = process.env.ZOWE_CLI_HOME;
if (getResult.itemVal === undefined) {
getResult.itemVal += os.EOL + EnvQuery.indent + "Default = " +
path.normalize(utilities_1.ImperativeConfig.instance.cliHome);
}
getResult.itemValMsg = os.EOL + "ZOWE_CLI_HOME = " + getResult.itemVal;
break;
}
case EnvItems_1.ItemId.ZOWE_APP_LOG_LEVEL: {
getResult.itemVal = process.env.ZOWE_APP_LOG_LEVEL;
getResult.itemValMsg = "ZOWE_APP_LOG_LEVEL = " + getResult.itemVal;
break;
}
case EnvItems_1.ItemId.ZOWE_IMPERATIVE_LOG_LEVEL: {
getResult.itemVal = process.env.ZOWE_IMPERATIVE_LOG_LEVEL;
getResult.itemValMsg = "ZOWE_IMPERATIVE_LOG_LEVEL = " + getResult.itemVal;
break;
}
case EnvItems_1.ItemId.OTHER_ZOWE_VARS: {
EnvQuery.getOtherZoweEnvVars(getResult);
break;
}
case EnvItems_1.ItemId.NPM_VER: {
yield EnvQuery.getNpmInfo(getResult, getItemOpts);
break;
}
case EnvItems_1.ItemId.ZOWE_CONFIG_INFO: {
yield EnvQuery.getConfigInfo(getResult, getItemOpts);
break;
}
case EnvItems_1.ItemId.ZOWE_PLUGINS: {
yield EnvQuery.getPluginInfo(getResult, getItemOpts);
break;
}
default: {
getResult.itemProbMsg = "An unknown item ID was supplied = " + itemId;
return getResult;
}
}
getResult.itemProbMsg = EnvQuery.getEnvItemProblems(itemId, getResult.itemVal);
return getResult;
});
}
// __________________________________________________________________________
/**
* Detect if a specified problem test finds a problem for the specified value.
*
* @param itemVal The value of the environmental item.
* @param probTest A problem test to be evaluated.
*
* @returns True if we find a problem. False otherwise.
*/
static detectProbVal(value, probTest) {
// eslint-disable-next-line unused-imports/no-unused-vars,@typescript-eslint/no-unused-vars
const semver = require('semver');
const probExprWithVals = probTest.probExpr.replace(/{val}/g, value);
return eval(probExprWithVals);
}
// __________________________________________________________________________
/**
* Run a command that displays output.
*
* @param cmdToRun The command name to be run.
* @param args The arguments to the command.
*
* @return The output of the command.
*/
static getCmdOutput(cmdToRun, args) {
let cmdOutput = "";
const ioOpts = ["pipe", "pipe", "pipe"];
try {
const spawnResult = spawn.sync(cmdToRun, args, {
stdio: ioOpts,
shell: true
});
if (spawnResult.stdout && spawnResult.stdout.length > 0) {
// remove any trailing newline from the output
cmdOutput = spawnResult.stdout.toString();
}
else {
cmdOutput = cmdToRun + " failed to display any output.";
if (spawnResult.stderr) {
cmdOutput += `${os.EOL}Reason = ` + spawnResult.stderr.toString();
}
}
}
catch (err) {
cmdOutput = "Failed to run command = " + cmdToRun + " " + args.join(" ");
if (err.message) {
cmdOutput += `${os.EOL}Details = ` + err.message;
}
cmdOutput = utilities_1.TextUtils.chalk.red(cmdOutput);
}
// remove any trailing newline from the output
cmdOutput = cmdOutput.replace(EnvQuery.lastEolRegex, "");
if (cmdOutput.length == 0) {
cmdOutput = "Failed to get any information from " + cmdToRun + " " + args.join(" ");
}
return cmdOutput;
}
// __________________________________________________________________________
/**
* Get information about the Zowe configuration.
*
* @param getResult The itemVal and itemValMsg properties are filled
* by this function.
* @param getItemOpts options that affect our behavior.
*/
static getConfigInfo(getResult, getItemOpts) {
return __awaiter(this, void 0, void 0, function* () {
var _a;
const teamCfg = "Zowe Client Config";
const doesProgBarExist = (getItemOpts === null || getItemOpts === void 0 ? void 0 : getItemOpts.progressApi) ? true : false;
// setup progress bar
const configProgress = {
percentComplete: operations_1.TaskProgress.TEN_PERCENT,
statusMessage: "No value yet",
stageName: operations_1.TaskStage.IN_PROGRESS
};
if ((_a = utilities_1.ImperativeConfig.instance.config) === null || _a === void 0 ? void 0 : _a.exists) {
getResult.itemVal = teamCfg;
configProgress.statusMessage = "Retrieving Zowe client configuration";
configProgress.percentComplete = operations_1.TaskProgress.TWENTY_PERCENT;
}
if (doesProgBarExist) {
getItemOpts.progressApi.startBar({ task: configProgress });
yield EnvQuery.updateProgressBar(doesProgBarExist, true);
}
getResult.itemValMsg = "Zowe daemon mode = ";
if (utilities_1.ImperativeConfig.instance.loadedConfig.daemonMode) {
getResult.itemValMsg += "on";
configProgress.statusMessage = "Retrieving Zowe executable version";
yield EnvQuery.updateProgressBar(doesProgBarExist);
const cliCmdName = utilities_1.ImperativeConfig.instance.rootCommandName;
const exeVerOutput = EnvQuery.getCmdOutput(cliCmdName, ["--version-exe"]);
if (exeVerOutput.match(/DESCRIPTION/) == null) {
getResult.itemValMsg += `${os.EOL}Zowe daemon executable version = ` + exeVerOutput;
}
getResult.itemValMsg +=
`${os.EOL}Default Zowe daemon executable directory = ` +
path.normalize(utilities_1.ImperativeConfig.instance.cliHome + "/bin");
}
else {
getResult.itemValMsg += "off";
}
if (getResult.itemVal == teamCfg) {
// Display all relevant zowe team config files.
configProgress.statusMessage = "Retrieving active Zowe client config files";
configProgress.percentComplete = operations_1.TaskProgress.THIRTY_PERCENT;
yield EnvQuery.updateProgressBar(doesProgBarExist);
const config = utilities_1.ImperativeConfig.instance.config;
/* Get our list of config files.
* Logic stolen from "config list" handler.
*/
const configListObj = {};
for (const layer of config.layers) {
if (layer.exists) {
configListObj[layer.path] = layer.properties;
if (configListObj[layer.path] != null) {
for (const secureProp of config.api.secure.secureFields(layer)) {
if (lodash.has(configListObj[layer.path], secureProp)) {
lodash.set(configListObj[layer.path], secureProp, config_1.ConfigConstants.SECURE_VALUE);
}
}
}
}
}
getResult.itemValMsg += `${os.EOL}Zowe client config files in use:${os.EOL}`;
for (const configLoc of Object.keys(configListObj)) {
getResult.itemValMsg += EnvQuery.indent + configLoc + os.EOL;
}
// get default profile names
configProgress.statusMessage = "Retrieving default profile names";
configProgress.percentComplete = operations_1.TaskProgress.SIXTY_PERCENT;
yield EnvQuery.updateProgressBar(doesProgBarExist);
getResult.itemValMsg += "Default profile names: " + os.EOL;
let maxSpace = 1;
for (const profType of Object.keys(config.mProperties.defaults)) {
// calculate the max space we need between profile type and name
maxSpace = maxSpace < profType.length ? profType.length + 1 : maxSpace;
}
for (const profType of Object.keys(config.mProperties.defaults)) {
getResult.itemValMsg += EnvQuery.indent + profType + " =";
for (let count = 1; count <= maxSpace - profType.length; count++) {
getResult.itemValMsg += " ";
}
getResult.itemValMsg += config.mProperties.defaults[profType] + os.EOL;
}
// get all available zowe profile names
configProgress.statusMessage = "Retrieving available profile names";
configProgress.percentComplete = operations_1.TaskProgress.NINETY_PERCENT;
yield EnvQuery.updateProgressBar(doesProgBarExist);
/* Recursive function to get our list of profiles.
* Logic stolen from "config profiles" handler.
*/
const getProfList = function (profiles, startLoc, profPathNms) {
const currLoc = startLoc;
for (const [profNm, profObj] of Object.entries(profiles)) {
const currPathNm = currLoc + `${currLoc.length > 0 ? "." : ""}${profNm}`;
profPathNms.push(currPathNm);
if (profObj.profiles != null) {
getProfList(profObj.profiles, currPathNm, profPathNms);
}
}
};
const profPathNms = [];
getProfList(config.properties.profiles, "", profPathNms);
getResult.itemValMsg += `Available profile names:${os.EOL}`;
for (const profPathNm of profPathNms) {
getResult.itemValMsg += EnvQuery.indent + profPathNm + os.EOL;
}
}
else {
getResult.itemValMsg += `${os.EOL}No Zowe client configuration detected.${os.EOL}`;
}
// add indent to each line
getResult.itemValMsg = EnvQuery.divider + "Zowe CLI configuration information:" +
os.EOL + os.EOL + EnvQuery.indent +
getResult.itemValMsg.replace(EnvQuery.allEolRegex, "$1" + EnvQuery.indent);
configProgress.statusMessage = "Complete";
configProgress.percentComplete = operations_1.TaskProgress.ONE_HUNDRED_PERCENT;
configProgress.stageName = operations_1.TaskStage.COMPLETE;
yield EnvQuery.updateProgressBar(doesProgBarExist);
if (doesProgBarExist) {
getItemOpts.progressApi.endBar();
}
});
} // end getConfigInfo
// __________________________________________________________________________
/**
* For the specified itemId, get any known problems.
*
* @param itemId ID of the environmental item for which we want to detect problems.
* @param itemVal The value of the environmental item.
* @returns A string with a message about the problems. An empty string if no problems are detected.
*/
static getEnvItemProblems(itemId, itemVal) {
let probMsgs = "";
for (const nextProbTest of EnvItems_1.probTests) {
if (itemId === nextProbTest.itemId) {
if (EnvQuery.detectProbVal(itemVal, nextProbTest)) {
if (probMsgs.length > 0) {
probMsgs += os.EOL;
}
probMsgs += nextProbTest.probMsg;
}
}
}
return probMsgs;
}
// __________________________________________________________________________
/**
* Get information about the NPM configuration.
*
* @param getResult The itemVal and itemValMsg properties are filled
* by this function.
* @param getItemOpts options that affect our behavior.
*/
static getNpmInfo(getResult, getItemOpts) {
return __awaiter(this, void 0, void 0, function* () {
const percentIncr = 10;
const doesProgBarExist = (getItemOpts === null || getItemOpts === void 0 ? void 0 : getItemOpts.progressApi) ? true : false;
// setup progress bar
const npmProgress = {
percentComplete: operations_1.TaskProgress.TEN_PERCENT,
statusMessage: "Retrieving NPM Version",
stageName: operations_1.TaskStage.IN_PROGRESS
};
if (doesProgBarExist) {
getItemOpts.progressApi.startBar({ task: npmProgress });
yield EnvQuery.updateProgressBar(doesProgBarExist, true);
}
getResult.itemVal = EnvQuery.getCmdOutput("npm", ["--version"]);
getResult.itemValMsg = `${os.EOL}NPM version = ` + getResult.itemVal;
npmProgress.statusMessage = "Retrieving current shell";
npmProgress.percentComplete += percentIncr;
yield EnvQuery.updateProgressBar(doesProgBarExist);
// `npm config` commands fail hard when used with workspaces
getResult.itemValMsg += `${os.EOL}Shell = ` + EnvQuery.getCmdOutput("npm", ["config", "get", "shell", "--no-workspaces"]);
npmProgress.statusMessage = "Retrieving NPM global prefix";
npmProgress.percentComplete += percentIncr;
yield EnvQuery.updateProgressBar(doesProgBarExist);
getResult.itemValMsg += `${os.EOL}Global prefix = ` + EnvQuery.getCmdOutput("npm", ["prefix", "-g"]);
getResult.itemValMsg += os.EOL + EnvQuery.indent + "The directory above contains the Zowe Node.js command script.";
npmProgress.statusMessage = "Retrieving NPM global root node modules";
npmProgress.percentComplete += percentIncr;
yield EnvQuery.updateProgressBar(doesProgBarExist);
getResult.itemValMsg += `${os.EOL}Global root node modules = ` + EnvQuery.getCmdOutput("npm", ["root", "-g"]);
npmProgress.statusMessage = "Retrieving NPM global config";
npmProgress.percentComplete += percentIncr;
yield EnvQuery.updateProgressBar(doesProgBarExist);
// `npm config` commands fail hard when used with workspaces
getResult.itemValMsg += `${os.EOL}Global config = ` + EnvQuery.getCmdOutput("npm", ["config", "get", "globalconfig", "--no-workspaces"]);
npmProgress.statusMessage = "Retrieving NPM local prefix";
npmProgress.percentComplete += percentIncr;
yield EnvQuery.updateProgressBar(doesProgBarExist);
getResult.itemValMsg += `${os.EOL}Local prefix = ` + EnvQuery.getCmdOutput("npm", ["prefix"]);
npmProgress.statusMessage = "Retrieving NPM local root node modules";
npmProgress.percentComplete += percentIncr;
yield EnvQuery.updateProgressBar(doesProgBarExist);
getResult.itemValMsg += `${os.EOL}Local root node modules = ` + EnvQuery.getCmdOutput("npm", ["root"]);
npmProgress.statusMessage = "Retrieving NPM user config";
npmProgress.percentComplete += percentIncr;
yield EnvQuery.updateProgressBar(doesProgBarExist);
// `npm config` commands fail hard when used with workspaces
getResult.itemValMsg += `${os.EOL}User config = ` + EnvQuery.getCmdOutput("npm", ["config", "get", "userconfig", "--no-workspaces"]);
npmProgress.statusMessage = "Retrieving NPM registry info";
npmProgress.percentComplete += percentIncr;
yield EnvQuery.updateProgressBar(doesProgBarExist);
// Filter the output of "npm config list" command to only include lines we are interested in.
// Also remove "; " prefix from lines where it was added by npm and is not a user-added comment.
// `npm config` commands fail hard when used with workspaces
getResult.itemValMsg += os.EOL + os.EOL + EnvQuery.getCmdOutput("npm", ["config", "list", "--no-workspaces"])
.split(EnvQuery.allEolRegex)
.filter(line => /registry =|"project"|node bin location =|cwd =|HOME =/.test(line))
.map(line => line.includes("registry =") ? line : line.replace(/^; /, ""))
.join(os.EOL);
// add indent to each line
getResult.itemValMsg = EnvQuery.divider + "NPM information:" + os.EOL + EnvQuery.indent +
getResult.itemValMsg.replace(EnvQuery.allEolRegex, "$1" + EnvQuery.indent);
npmProgress.statusMessage = "Complete";
npmProgress.percentComplete = operations_1.TaskProgress.ONE_HUNDRED_PERCENT;
npmProgress.stageName = operations_1.TaskStage.COMPLETE;
yield EnvQuery.updateProgressBar(doesProgBarExist);
if (doesProgBarExist) {
getItemOpts.progressApi.endBar();
}
});
} // end getNpmInfo
// __________________________________________________________________________
/**
* Get other Zowe variables, beyond the ones we check for problem values.
*
* @param getResult The itemValMsg property is filled by this function.
* The itemVal property is given no value by this function.
*/
static getOtherZoweEnvVars(getResult) {
getResult.itemValMsg = "";
const envVars = process.env;
const secureCredsList = censor_1.Censor.CENSORED_OPTIONS.map(opt => opt.toUpperCase().replaceAll("-", "_"));
for (const nextVar of Object.keys(envVars)) {
if (nextVar.startsWith("ZOWE_") && nextVar != "ZOWE_CLI_HOME" &&
nextVar != "ZOWE_APP_LOG_LEVEL" && nextVar != "ZOWE_IMPERATIVE_LOG_LEVEL") {
getResult.itemValMsg += nextVar + " = ";
if (secureCredsList.some(secureOpt => nextVar.toUpperCase().includes(secureOpt))) {
getResult.itemValMsg += "******";
}
else {
getResult.itemValMsg += envVars[nextVar];
}
getResult.itemValMsg += os.EOL;
}
}
// remove the last newline
getResult.itemValMsg = getResult.itemValMsg.replace(EnvQuery.lastEolRegex, "");
if (getResult.itemValMsg.length == 0) {
getResult.itemValMsg += "No other 'ZOWE_' variables have been set.";
}
}
// __________________________________________________________________________
/**
* Get information about Zowe plugins.
* Logic stolen from plugins list command handler.
*
* @param getResult The itemVal and itemValMsg properties are filled
* by this function.
*/
static getPluginInfo(getResult, getItemOpts) {
return __awaiter(this, void 0, void 0, function* () {
const doesProgBarExist = (getItemOpts === null || getItemOpts === void 0 ? void 0 : getItemOpts.progressApi) ? true : false;
// setup progress bar
const configProgress = {
percentComplete: operations_1.TaskProgress.FIFTY_PERCENT,
statusMessage: "Retrieving installed plugins",
stageName: operations_1.TaskStage.IN_PROGRESS
};
if (doesProgBarExist) {
getItemOpts.progressApi.startBar({ task: configProgress });
yield EnvQuery.updateProgressBar(doesProgBarExist, true);
}
const installedPlugins = PluginIssues_1.PluginIssues.instance.getInstalledPlugins();
getResult.itemValMsg = EnvQuery.divider + "Installed plugins:" + os.EOL;
for (const nextPluginNm of Object.keys(installedPlugins)
.sort((a, b) => a.localeCompare(b))) {
getResult.itemValMsg += os.EOL + EnvQuery.indent + nextPluginNm + os.EOL +
EnvQuery.indent + EnvQuery.indent + "Version = " +
installedPlugins[nextPluginNm].version + os.EOL +
EnvQuery.indent + EnvQuery.indent + "Package = " +
installedPlugins[nextPluginNm].package + os.EOL;
}
getResult.itemValMsg += EnvQuery.divider;
if (doesProgBarExist) {
configProgress.percentComplete = operations_1.TaskProgress.ONE_HUNDRED_PERCENT;
yield EnvQuery.updateProgressBar(doesProgBarExist);
getItemOpts.progressApi.endBar();
}
});
}
// __________________________________________________________________________
/**
* Get the Zowe version number.
*
* @param getResult The itemVal and itemValMsg properties are filled
* by this function.
*/
static getZoweVer(getResult) {
const cliPackageJson = utilities_1.ImperativeConfig.instance.callerPackageJson;
if (Object.prototype.hasOwnProperty.call(cliPackageJson, "version")) {
getResult.itemVal = cliPackageJson.version;
}
else {
getResult.itemVal = "No version found in CLI package.json!";
}
getResult.itemValMsg = EnvQuery.divider + "Zowe CLI version = " + getResult.itemVal;
}
// __________________________________________________________________________
/**
* If a progress bar is in use, pause long enough to let it update its status.
*
* @param doesProgBarExist
* Is the progress bar availbale for use?
* @param firstUpdate
* Is this our first progress bar update?
* Initialization of the progress bar takes extra time.
*/
static updateProgressBar(doesProgBarExist_1) {
return __awaiter(this, arguments, void 0, function* (doesProgBarExist, firstUpdate = false) {
if (doesProgBarExist) {
const firstUpdateTime = 300; // millis
const laterUpdateTime = 100; // millis
let timeToUpdate;
if (firstUpdate) {
timeToUpdate = firstUpdateTime;
}
else {
timeToUpdate = laterUpdateTime;
}
yield CliUtils_1.CliUtils.sleep(timeToUpdate);
}
});
}
}
exports.EnvQuery = EnvQuery;
EnvQuery.divider = `______________________________________________${os.EOL}`;
EnvQuery.indent = " ";
EnvQuery.eolMatch = "(\r?\n|\n)";
EnvQuery.allEolRegex = new RegExp(EnvQuery.eolMatch, "g");
EnvQuery.lastEolRegex = new RegExp(EnvQuery.eolMatch + "$");
//# sourceMappingURL=EnvQuery.js.map
;