@zowe/imperative
Version:
framework for building configurable CLIs
211 lines • 9.28 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.
*
*/
Object.defineProperty(exports, "__esModule", { value: true });
exports.ConfigLayers = void 0;
const fs = require("fs");
const path = require("path");
const JSONC = require("comment-json");
const lodash = require("lodash");
const error_1 = require("../../../error");
const ConfigConstants_1 = require("../ConfigConstants");
const ConfigApi_1 = require("./ConfigApi");
const logger_1 = require("../../../logger");
/**
* API Class for manipulating config layers.
*/
class ConfigLayers extends ConfigApi_1.ConfigApi {
// _______________________________________________________________________
/**
* Read a config layer from disk into memory for application use.
*
* @param opts The user and global flags that indicate which of the four
* config files (aka layers) is to be read.
*/
read(opts) {
// Attempt to populate the layer
const layer = opts ? this.mConfig.findLayer(opts.user, opts.global) : this.mConfig.layerActive();
if (fs.existsSync(layer.path)) {
let fileContents;
try {
fileContents = fs.readFileSync(layer.path);
}
catch (e) {
throw new error_1.ImperativeError({
msg: `An error was encountered while trying to read the file '${layer.path}'.\nError details: ${e.message}`,
suppressDump: true
});
}
try {
// Typecasting because of this issue: https://github.com/kaelzhang/node-comment-json/issues/42
layer.properties = JSONC.parse(fileContents.toString());
layer.exists = true;
}
catch (e) {
const msg = `Error parsing JSON in the file '${layer.path}'.\n` +
`Please check this configuration file for errors.\nError details: ${e.message}\nLine ${e.line}, Column ${e.column}`;
if (!(opts === null || opts === void 0 ? void 0 : opts.ignoreErrors)) {
throw new error_1.ImperativeError({
msg: msg,
suppressDump: true
});
}
else {
logger_1.Logger.getConsoleLogger().error(msg);
}
}
this.mConfig.api.secure.loadCached(opts);
}
else if (layer.exists) {
layer.properties = {};
layer.exists = false;
}
// Populate any undefined defaults
layer.properties.profiles = layer.properties.profiles || {};
layer.properties.defaults = layer.properties.defaults || {};
}
// _______________________________________________________________________
/**
* Write a config layer to disk.
*
* @param opts The user and global flags that indicate which of the four
* config files (aka layers) is to be written.
*/
write(opts) {
// TODO: should we prevent a write if there is no vault
// TODO: specified and there are secure fields??
// If fields are marked as secure
const layer = opts ? this.mConfig.findLayer(opts.user, opts.global) : this.mConfig.layerActive();
// Typecasting because of this issue: https://github.com/kaelzhang/node-comment-json/issues/42
const layerCloned = JSONC.parse(JSONC.stringify(layer, null, ConfigConstants_1.ConfigConstants.INDENT));
this.mConfig.api.secure.cacheAndPrune(layerCloned);
// Write the layer
try {
fs.writeFileSync(layer.path, JSONC.stringify(layerCloned.properties, null, ConfigConstants_1.ConfigConstants.INDENT));
}
catch (e) {
throw new error_1.ImperativeError({ msg: `error writing "${layer.path}": ${e.message}` });
}
layer.exists = true;
}
// _______________________________________________________________________
/**
* Select which layer is the currently active layer.
*
* @param user True if you want the user layer.
* @param global True if you want the global layer.
* @param inDir The directory to which you want to set the file path
* for this layer.
*/
activate(user, global, inDir) {
this.mConfig.mActive.user = user;
this.mConfig.mActive.global = global;
if (inDir != null) {
const layer = this.mConfig.layerActive();
// Load config layer if file path has changed
if (inDir !== path.dirname(layer.path)) {
layer.path = path.join(inDir, path.basename(layer.path));
this.read();
}
}
}
// _______________________________________________________________________
/**
* Gets a json object that represents the currently active layer.
*
* @returns The json object
*/
get() {
// Note: Add indentation to allow comments to be accessed via config.api.layers.get(), otherwise use layerActive()
// return JSONC.parse(JSONC.stringify(this.mConfig.layerActive(), null, ConfigConstants.INDENT));
// Typecasting because of this issue: https://github.com/kaelzhang/node-comment-json/issues/42
return JSONC.parse(JSONC.stringify(this.mConfig.layerActive(), null, ConfigConstants_1.ConfigConstants.INDENT));
}
// _______________________________________________________________________
/**
* Set the the currently active layer to the supplied json object.
*
* @param user True if you want the user layer.
*/
set(cnfg) {
for (const i in this.mConfig.mLayers) {
if (this.mConfig.mLayers[i].user === this.mConfig.mActive.user &&
this.mConfig.mLayers[i].global === this.mConfig.mActive.global) {
this.mConfig.mLayers[i].properties = cnfg;
this.mConfig.mLayers[i].properties.defaults = this.mConfig.mLayers[i].properties.defaults || {};
this.mConfig.mLayers[i].properties.profiles = this.mConfig.mLayers[i].properties.profiles || {};
}
}
}
// _______________________________________________________________________
/**
* Merge properties from the supplied Config object into the active layer.
* If dryRun is specified, merge is applied to a copy of the layer and returned.
* If dryRun is not specified, merge is applied directly to the layer and nothing is returned.
*
* @param cnfg The Config object to merge.
* @returns The merged config layer or void
*/
merge(cnfg, dryRun = false) {
var _a;
let layer;
if (dryRun) {
// Typecasting because of this issue: https://github.com/kaelzhang/node-comment-json/issues/42
layer = JSONC.parse(JSONC.stringify(this.mConfig.layerActive(), null, ConfigConstants_1.ConfigConstants.INDENT));
}
else {
layer = this.mConfig.layerActive();
}
layer.properties.profiles = lodash.mergeWith(cnfg.profiles, layer.properties.profiles, (obj, src) => {
if (lodash.isArray(obj) && lodash.isArray(src)) {
// Typecasting because of this issue: https://github.com/kaelzhang/node-comment-json/issues/42
const temp = JSONC.parse(JSONC.stringify(obj, null, ConfigConstants_1.ConfigConstants.INDENT));
src.forEach((val, idx) => {
if (!temp.includes(val)) {
temp.splice(idx, 0, val);
}
});
return temp;
}
});
layer.properties.defaults = lodash.merge(cnfg.defaults, layer.properties.defaults);
for (const pluginName of cnfg.plugins || []) {
if (layer.properties.plugins == null) {
layer.properties.plugins = [pluginName];
}
else if (!((_a = layer.properties.plugins) === null || _a === void 0 ? void 0 : _a.includes(pluginName))) {
layer.properties.plugins.push(pluginName);
}
}
if (cnfg.autoStore != null) {
layer.properties.autoStore = cnfg.autoStore;
}
if (dryRun) {
return layer;
}
}
// _______________________________________________________________________
/**
* Finds the highest priority layer where a profile is stored.
* @param profileName Profile name to search for
* @returns User and global properties, or undefined if profile does not exist
*/
find(profileName) {
const profilePath = this.mConfig.api.profiles.getProfilePathFromName(profileName);
for (const layer of this.mConfig.layers) {
if (lodash.get(layer.properties, profilePath) != null) {
return layer;
}
}
}
}
exports.ConfigLayers = ConfigLayers;
//# sourceMappingURL=ConfigLayers.js.map
;