@zowe/imperative
Version:
framework for building configurable CLIs
185 lines • 7.67 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.WebHelpManager = void 0;
const fs = require("fs");
const path = require("path");
const Constants_1 = require("../../../constants/src/Constants");
const utilities_1 = require("../../../utilities");
const WebHelpGenerator_1 = require("./WebHelpGenerator");
const error_1 = require("../../../error");
/**
* Imperative web help manager. Single instance class used to launch web help
* in browser which handles (re)building web help files first if necessary.
* @export
* @class WebHelpManager
*/
class WebHelpManager {
/**
* Return a singleton instance of this class
* @static
* @readonly
*/
static get instance() {
if (this.mInstance == null) {
this.mInstance = new WebHelpManager();
}
return this.mInstance;
}
/**
* Launch root help page in browser.
* @param {IHandlerResponseApi} cmdResponse - Command response object to use for output
* @memberof WebHelpManager
*/
openRootHelp(cmdResponse) {
this.openHelp(null, cmdResponse);
}
/**
* Launch help page for specific group/command in browser.
* @param {string} inContext - Name of page for group/command to jump to
* @param {IHandlerResponseApi} cmdResponse - Command response object to use for output
* @memberof WebHelpManager
*/
openHelp(inContext, cmdResponse) {
const doWeHaveGui = utilities_1.ProcessUtils.isGuiAvailable();
if (doWeHaveGui !== utilities_1.GuiResult.GUI_AVAILABLE) {
let errMsg = "You are running in an environment with no graphical interface." +
"\nAlternatively, you can run '" + utilities_1.ImperativeConfig.instance.findPackageBinName() +
" --help' for text-based help.";
if (doWeHaveGui === utilities_1.GuiResult.NO_GUI_NO_DISPLAY) {
errMsg += "\n\nIf you are running in an X Window environment," +
"\nensure that your DISPLAY environment variable is set." +
"\nFor example, type the following:" +
"\n echo $DISPLAY" +
"\nIf it is not set, assign a valid value. For example:" +
"\n export DISPLAY=:0.0" +
"\nThen try the --help-web option again.";
}
cmdResponse.console.log(errMsg);
return;
}
const newMetadata = this.checkIfMetadataChanged();
if (newMetadata !== null) {
new WebHelpGenerator_1.WebHelpGenerator(this.mFullCommandTree, utilities_1.ImperativeConfig.instance, this.webHelpDir).
buildHelp(cmdResponse);
this.writePackageMetadata(newMetadata);
}
cmdResponse.console.log("Launching web help in browser...");
/* Create launcher file in web help folder to jump to desired command.
* This is kind of a hack, necessitated by the fact that unfortunately
* Windows does not natively support passing URL search params to
* file:/// links. Therefore the `p` parameter supported by the docs
* site to load a page in-context cannot be used here.
*/
if (inContext != null) {
const launcherPath = path.join(this.webHelpDir, "launcher.html");
fs.writeFileSync(launcherPath, `<html><head><meta http-equiv="refresh" content="0; url=index.html?p=${inContext}" /></head></html>`);
}
try {
const htmlFile = inContext != null ? "launcher.html" : "index.html";
utilities_1.ProcessUtils.openInDefaultApp(`file:///${this.webHelpDir}/${htmlFile}`);
}
catch (e) {
throw new error_1.ImperativeError({
msg: "Failed to launch web help, try running -h for console help instead",
causeErrors: [e]
});
}
}
/**
* Record a reference to our CLI's full command tree.
* @param fullCommandTree - The command tree.
*/
set fullCommandTree(fullCommandTree) {
this.mFullCommandTree = fullCommandTree;
}
/**
* Get a reference to our CLI's full command tree.
* @returns The command tree.
*/
get fullCommandTree() {
return this.mFullCommandTree;
}
/**
* Gets the directory where built copy of web help is stored
* @readonly
* @private
* @returns {string} Absolute path of directory
*/
get webHelpDir() {
return path.join(utilities_1.ImperativeConfig.instance.cliHome, Constants_1.Constants.WEB_HELP_DIR);
}
/**
* Computes current package metadata based on version of core and installed plug-ins
* @private
* @param packageJson - CLI package JSON
* @param pluginsJson - Imperative plug-ins JSON
* @returns {IWebHelpPackageMetadata[]} Names and versions of all components
*/
calcPackageMetadata(packageJson, pluginsJson) {
return [
{ name: packageJson.name, version: packageJson.version },
...Object.keys(pluginsJson).map((name) => {
return { name, version: pluginsJson[name].version };
})
];
}
/**
* Compares two package metadata objects to see if they are equal
* @private
* @param {IWebHelpPackageMetadata[]} cached - Old cached package metadata
* @param {IWebHelpPackageMetadata[]} current - Freshly computed package metadata
* @returns {boolean} True if the package metadata objects are equal
*/
eqPackageMetadata(cached, current) {
return JSON.stringify(cached.sort((a, b) => a.name.localeCompare(b.name))) ===
JSON.stringify(current.sort((a, b) => a.name.localeCompare(b.name)));
}
/**
* Checks if cached package metadata is non-existent or out of date
* @private
* @returns {MaybePackageMetadata} Updated metadata, or `null` if cached metadata is already up to date
*/
checkIfMetadataChanged() {
// Load cached metadata from file if it exists
const metadataFile = path.join(this.webHelpDir, "metadata.json");
let cachedMetadata = [];
if (fs.existsSync(metadataFile)) {
cachedMetadata = require(metadataFile);
}
// Compute current metadata and compare it to cached
const myConfig = utilities_1.ImperativeConfig.instance;
const currentMetadata = this.calcPackageMetadata(myConfig.callerPackageJson, require(path.join(myConfig.cliHome, "plugins", "plugins.json")));
const metadataChanged = process.env.NODE_ENV === "development" ||
!this.eqPackageMetadata(cachedMetadata, currentMetadata);
return metadataChanged ? currentMetadata : null;
}
/**
* Updates cached package metadata
* @private
* @param {IWebHelpPackageMetadata[]} metadata - New metadata to save to disk
*/
writePackageMetadata(metadata) {
const metadataFile = path.join(this.webHelpDir, "metadata.json");
fs.writeFileSync(metadataFile, JSON.stringify(metadata, null, 2));
}
}
exports.WebHelpManager = WebHelpManager;
/**
* Singleton instance of this class
* @private
* @static
* @type {WebHelpManager}
* @memberof WebHelpManager
*/
WebHelpManager.mInstance = null;
//# sourceMappingURL=WebHelpManager.js.map