@zowe/imperative
Version:
framework for building configurable CLIs
204 lines • 11 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 });
const utilities_1 = require("../../../../../utilities");
const config_1 = require("../../../../../config");
const ConfigBuilder_1 = require("../../../../../config/src/ConfigBuilder");
const ConfigUtils_1 = require("../../../../../config/src/ConfigUtils");
const OverridesLoader_1 = require("../../../OverridesLoader");
const JSONC = require("comment-json");
const lodash = require("lodash");
const jest_diff_1 = require("jest-diff");
const stripAnsi = require("strip-ansi");
/**
* Init config
*/
class InitHandler {
/**
* Process the command and input.
*
* @param {IHandlerParameters} params Parameters supplied by yargs
*
* @throws {ImperativeError}
*/
process(params) {
return __awaiter(this, void 0, void 0, function* () {
var _a;
this.params = params;
this.promptProps = [];
// Load the config and set the active layer according to user options
yield OverridesLoader_1.OverridesLoader.ensureCredentialManagerLoaded();
const config = utilities_1.ImperativeConfig.instance.config;
const globalConfig = ((_a = params.arguments) === null || _a === void 0 ? void 0 : _a.globalConfig) ? true : false;
const configDir = globalConfig ? null : process.cwd();
config.api.layers.activate(params.arguments.userConfig, globalConfig, configDir);
const layer = config.api.layers.get();
// Do a dry run if dryRun flag is present. Otherwise, initialize or overwrite the config
if (params.arguments.dryRun && params.arguments.dryRun === true) {
let dryRun = yield this.initForDryRun(config, params.arguments.userConfig, globalConfig);
// Merge and display, do not save
// Handle if the file doesn't actually exist
let original = layer;
let originalProperties;
if (original.exists === false) {
originalProperties = {};
}
else {
// Typecasting because of this issue: https://github.com/kaelzhang/node-comment-json/issues/42
originalProperties = JSONC.parse(JSONC.stringify(original.properties, null, config_1.ConfigConstants.INDENT));
// Hide secure stuff
for (const secureProp of utilities_1.ImperativeConfig.instance.config.api.secure.secureFields(original)) {
if (lodash.has(originalProperties, secureProp)) {
lodash.unset(originalProperties, secureProp);
}
}
}
// Typecasting because of this issue: https://github.com/kaelzhang/node-comment-json/issues/42
const dryRunProperties = JSONC.parse(JSONC.stringify(dryRun.properties, null, config_1.ConfigConstants.INDENT));
// Hide secure stuff
for (const secureProp of utilities_1.ImperativeConfig.instance.config.api.secure.findSecure(dryRun.properties.profiles, "profiles")) {
if (lodash.has(dryRunProperties, secureProp)) {
lodash.unset(dryRunProperties, secureProp);
}
}
original = JSONC.stringify(originalProperties, null, config_1.ConfigConstants.INDENT);
dryRun = JSONC.stringify(dryRunProperties, null, config_1.ConfigConstants.INDENT);
let jsonDiff = (0, jest_diff_1.diff)(original, dryRun, {
aAnnotation: "Removed",
bAnnotation: "Added",
aColor: utilities_1.TextUtils.chalk.red,
bColor: utilities_1.TextUtils.chalk.green
});
if (stripAnsi(jsonDiff) === "Compared values have no visual difference.") {
jsonDiff = dryRun;
}
params.response.console.log(jsonDiff);
params.response.data.setObj(jsonDiff);
}
else {
yield this.initWithSchema(config, params.arguments.userConfig, globalConfig, params.arguments.overwrite && params.arguments.forSure);
if (params.arguments.prompt !== false && config.api.secure.loadFailed && config.api.secure.secureFields().length > 0) {
const warning = ConfigUtils_1.ConfigUtils.secureSaveError();
let message = "Warning:\n" + warning.message + " Skipped prompting for credentials.";
if (warning.additionalDetails) {
message += `\n\n${warning.additionalDetails}\n`;
}
params.response.console.log(utilities_1.TextUtils.chalk.yellow(message));
}
// Write the active created/updated config layer
yield config.save();
params.response.console.log(`Saved config template to ${layer.path}`);
if (params.arguments.edit && params.arguments.edit === true) {
yield utilities_1.ProcessUtils.openInEditor(utilities_1.ImperativeConfig.instance.config.api.layers.get().path, params.arguments.editor);
}
}
});
}
/**
* Creates JSON template for config. Also creates a schema file in the same
* folder alongside the config.
* @param config Config object to be populated
* @param user If true, properties will be left empty for user config
* @param globalConfig Is the config to be a global config?
* @param overwrite Shall we overwrite an existing config?
*/
initWithSchema(config, user, globalConfig, overwrite) {
return __awaiter(this, void 0, void 0, function* () {
var _a;
const opts = {};
if (!user) {
opts.populateProperties = true;
opts.getValueBack = this.promptForProp.bind(this);
}
// Build new config and merge with existing layer or overwrite it if overwrite & forSure options are present
const newConfig = yield ConfigBuilder_1.ConfigBuilder.build(utilities_1.ImperativeConfig.instance.loadedConfig, globalConfig, opts);
if (overwrite) {
config.api.layers.set(newConfig);
}
else {
const oldConfig = config.layerActive().properties;
const baseProfileNm = ConfigUtils_1.ConfigUtils.formGlobOrProjProfileNm("base", globalConfig);
if (((_a = oldConfig.profiles[baseProfileNm]) === null || _a === void 0 ? void 0 : _a.properties) != null) {
// Remove values that should be overwritten from old base profile
for (const propName of Object.keys(oldConfig.profiles[baseProfileNm].properties)) {
const newPropValue = newConfig.profiles[baseProfileNm].properties[propName];
if (this.promptProps.includes(propName) && newPropValue != null && newPropValue !== "") {
delete oldConfig.profiles[baseProfileNm].properties[propName];
}
}
}
config.api.layers.merge(newConfig);
}
// Build the schema and write it to disk
config_1.ConfigSchema.updateSchema();
});
}
/**
* Do a dry run of creating JSON template for config.
* Also create a schema file in the same folder alongside the config.
* @param config Config object to be populated
* @param user If true, properties will be left empty for user config
* @param globalConfig Is the config to be a global config?
*/
initForDryRun(config, user, globalConfig) {
return __awaiter(this, void 0, void 0, function* () {
const opts = {};
if (!user) {
opts.populateProperties = true;
}
// Build new config and merge with existing layer
const newConfig = yield ConfigBuilder_1.ConfigBuilder.build(utilities_1.ImperativeConfig.instance.loadedConfig, globalConfig, opts);
return config.api.layers.merge(newConfig, true);
});
}
/**
* Prompts for the value of a property on the CLI. Returns null if `--prompt false`
* argument is passed, or prompt times out, or a blank value is entered.
* @param propName The name of the property
* @param property The profile property definition
*/
promptForProp(propName, property) {
return __awaiter(this, void 0, void 0, function* () {
var _a;
// skip prompting in CI environment
if (this.params.arguments.prompt === false || utilities_1.ImperativeConfig.instance.config.api.secure.loadFailed) {
return null;
}
// get the summary and value
let propDesc = propName;
if (((_a = property.optionDefinition) === null || _a === void 0 ? void 0 : _a.description) != null) {
propDesc += ` (${property.optionDefinition.description})`;
}
this.promptProps.push(propName);
const propValue = yield this.params.response.console.prompt(`Enter ${propDesc} ${config_1.ConfigConstants.SKIP_PROMPT}`, { hideText: property.secure });
// coerce to correct type
if (propValue && propValue.trim().length > 0) {
// TODO How to handle profile property with multiple types
// Same TODO as `private ConfigBuilder.getDefaultValue()`
const propType = Array.isArray(property.type) ? property.type[0] : property.type;
return ConfigUtils_1.ConfigUtils.coercePropValue(propValue, propType);
}
return propValue || null;
});
}
}
exports.default = InitHandler;
//# sourceMappingURL=init.handler.js.map
;