@zowe/cli
Version:
Zowe CLI is a command line interface (CLI) that provides a simple and streamlined way to interact with IBM z/OS.
323 lines • 14.7 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 fs = require("fs");
const nodeJsPath = require("path");
const tar = require("tar");
const child_process_1 = require("child_process");
const imperative_1 = require("@zowe/imperative");
/**
* Handler to enable daemon mode.
* @export
* @class Handler
* @implements {ICommandHandler}
*/
class EnableDaemonHandler {
/**
* Process the enable daemon command and populates the response
* object as needed.
*
* @param {IHandlerParameters} cmdParams Parameters supplied by yargs
*
* @throws {ImperativeError}
*/
process(cmdParams) {
return __awaiter(this, void 0, void 0, function* () {
let userMsg;
try {
const userQuestions = {
/* TODO: Use this code block when we are ready to automatically add zowe/bin to the PATH
canAskUser: true,
addBinToPathVal: "y"
*/
canAskUser: false,
addBinToPathVal: "n"
};
userMsg = yield this.enableDaemon(userQuestions);
}
catch (impErr) {
cmdParams.response.console.log("Failed to enable Zowe CLI daemon mode.\n" + impErr.message);
cmdParams.response.data.setExitCode(1);
return;
}
cmdParams.response.console.log("Zowe CLI daemon mode is enabled.\n" + userMsg);
cmdParams.response.data.setExitCode(0);
});
}
/**
* Enable daemon mode. We extract our native executable and place it
* in ZOWE_CLI_HOME/bin.
*
* @throws {ImperativeError}
*
* @param {boolean} canAskQuestions Can we interactively ask the user questions?
*
* @returns {string} An informational message to display to the user after
* successful completion of the operation.
*/
enableDaemon(userQuestions) {
return __awaiter(this, void 0, void 0, function* () {
var _a, _b;
// determine our current OS
const sysInfo = imperative_1.ProcessUtils.getBasicSystemInfo();
// form the path to our prebuilds tar file
let preBldTgz = __dirname + "../../../../prebuilds/zowe-";
let exeFileName = "zowe";
switch (sysInfo.platform) {
case "darwin": {
preBldTgz += "macos.tgz";
break;
}
case "linux": {
preBldTgz += "linux.tgz";
break;
}
case "win32": {
preBldTgz += "windows.tgz";
exeFileName += ".exe";
break;
}
default: {
throw new imperative_1.ImperativeError({
msg: `Daemon mode is not supported on the '${sysInfo.platform}' operating system.`
});
}
}
preBldTgz = nodeJsPath.normalize(preBldTgz);
if (!imperative_1.IO.existsSync(preBldTgz)) {
throw new imperative_1.ImperativeError({
msg: `The archive for your OS executable does not exist: ${preBldTgz}`
});
}
// form the path to the bin directory in ZOWE_CLI_HOME
const pathToZoweBin = nodeJsPath.normalize(imperative_1.ImperativeConfig.instance.cliHome + "/bin");
// Does the ZOWE_CLI_HOME bin directory exist?
if (imperative_1.IO.existsSync(pathToZoweBin)) {
if (!imperative_1.IO.isDir(pathToZoweBin)) {
throw new imperative_1.ImperativeError({
msg: `The existing file '${pathToZoweBin}' must be a directory.`
});
}
}
else {
// create the directory
try {
imperative_1.IO.createDirSync(pathToZoweBin);
}
catch (err) {
throw new imperative_1.ImperativeError({
msg: `Unable to create directory '${pathToZoweBin}'.\nReason: ${err}`
});
}
}
// extract executable from the tar file into the bin directory
yield this.unzipTgz(preBldTgz, pathToZoweBin, imperative_1.ImperativeConfig.instance.rootCommandName);
/* Even though we await the unzip above, the OS still considers the exe file in-use
* for a while. We will get the following error message when trying to run the exe.
* "The process cannot access the file because it is being used by another process."
* So, we wait a little bit.
*/
const halfSecOfMillis = 500;
yield imperative_1.CliUtils.sleep(halfSecOfMillis);
// display the version of the executable
let userInfoMsg = "Zowe CLI native executable version = ";
const zoweExePath = nodeJsPath.resolve(pathToZoweBin, exeFileName);
const ioOpts = ["pipe", "pipe", "pipe"];
try {
const spawnResult = (0, child_process_1.spawnSync)(zoweExePath, ["--version-exe"], {
stdio: ioOpts,
shell: false
});
if (spawnResult.stdout) {
// remove any newlines from the version number
userInfoMsg += spawnResult.stdout.toString().replace(/\r?\n|\r/g, "");
}
else {
userInfoMsg += "Failed to get version number\n";
if (spawnResult.stderr) {
userInfoMsg += spawnResult.stderr.toString();
}
}
}
catch (err) {
userInfoMsg += err.message;
}
// add our bin directory to the PATH if is it is not already there
userInfoMsg += yield this.addZoweBinToPath(pathToZoweBin, userQuestions);
// if ZOWE_USE_DAEMON is set, and turned off, add a warning message
if (((_b = (_a = process.env) === null || _a === void 0 ? void 0 : _a.ZOWE_USE_DAEMON) === null || _b === void 0 ? void 0 : _b.length) > 0) {
switch (process.env.ZOWE_USE_DAEMON) {
case "no":
case "false":
case "0": {
userInfoMsg += `\n\nYour ZOWE_USE_DAEMON environment variable is set to '${process.env.ZOWE_USE_DAEMON}'.` +
"\nYou must remove it, or set it to 'yes' to use daemon mode.";
}
}
}
return userInfoMsg;
});
}
/**
* Unzip, from a gzipped tar file, any file that contains fileToExtract as a
* substring of the file name. The file will be placed into toDir.
* We expect toDir to already exist.
*
* @param tgzFile The gzipped tar file that we will extract
*
* @param toDir The directory into which we extract files
*
* @param fileToExtract The file name (or substring of the file name) to extract.
*
* @throws {ImperativeError}
* @returns A void promise to synchronize this operation.
*/
unzipTgz(tgzFile, toDir, fileToExtract) {
return __awaiter(this, void 0, void 0, function* () {
return new Promise((resolve) => {
fs.createReadStream(tgzFile)
.on('error', function (err) {
throw new imperative_1.ImperativeError({
msg: err
});
})
.pipe(new tar.Parse())
.on('entry', function (entry) {
if (entry.type == "File" && entry.path.includes(fileToExtract)) {
const sysInfo = imperative_1.ProcessUtils.getBasicSystemInfo();
let fileCreateOpts = {};
if (sysInfo.platform == "linux" || sysInfo.platform == "darwin") {
// set file permissions to read, write and execute for user, read and execute for group, in octal
fileCreateOpts = { mode: 0o750 };
}
// do not include any path structure from the tgz, just the exe name
entry.pipe(fs.createWriteStream(nodeJsPath.resolve(toDir, nodeJsPath.basename(entry.path)), fileCreateOpts));
}
})
.on("end", () => {
resolve();
});
});
});
}
/**
* Add our .zowe/bin directory to the user's PATH.
*
* @param pathToZoweBin The absolute path to our .zowe/bin drectory.
*
* @param {IDaemonEnableQuestions} userQuestions Questions for user (if permitted)
*
* @returns {string} An informational message to display to the user after
* successful completion of the operation.
*/
addZoweBinToPath(pathToZoweBin, userQuestions) {
return __awaiter(this, void 0, void 0, function* () {
var _a;
let userInfoMsg = "";
const osPlatform = imperative_1.ProcessUtils.getBasicSystemInfo().platform;
if ((_a = process.env.PATH) === null || _a === void 0 ? void 0 : _a.includes(pathToZoweBin)) {
// bash & zsh command-path caching forces us to require a new terminal
if (osPlatform !== "win32") {
userInfoMsg += "\n\n" + EnableDaemonHandler.openNewTerminalMsg;
}
}
else {
// ZOWE_CLI_HOME/bin is not on our PATH, we want to add it
let answer = null;
if (userQuestions.canAskUser) {
// alter PATH question by OS
let pathQuestion = "May we add the Zowe bin directory to your\nPATH in your ";
if (osPlatform === "win32") {
pathQuestion += "permanent user environment";
}
else {
pathQuestion += ".profile file";
}
pathQuestion += " [y or n] ? ";
// ask user for permission to update PATH
answer = yield imperative_1.CliUtils.readPrompt(pathQuestion);
}
else {
// don't ask, just use default
answer = userQuestions.addBinToPathVal;
}
if (answer !== null && answer === "y" || answer === "Y") {
// user wants us to do it for him/her
if (osPlatform === "win32") {
userInfoMsg += yield this.addZoweBinOnWindows(pathToZoweBin);
}
}
else {
userInfoMsg += `\n\nManually add '${pathToZoweBin}' to your PATH.` +
"\nOtherwise, you will continue to run the classic Zowe CLI interpreter.";
}
// when zowe/bin not already on path, user needs a new terminal
userInfoMsg += "\n\n" + EnableDaemonHandler.openNewTerminalMsg;
} // end zowe/bin not in path
return userInfoMsg;
});
}
/**
* Add our .zowe/bin directory to the front of the user's PATH on Windows.
*
* @param pathToZoweBin The absolute path to our .zowe/bin drectory.
*
* @returns {string} An informational message to display to the user after
* successful completion of the operation.
*/
addZoweBinOnWindows(pathToZoweBin) {
return __awaiter(this, void 0, void 0, function* () {
let userInfoMsg = "";
try {
/* TODO:
* - Detect if zowe/bin is in system or user PATH env variable
* - For user PATH : reg query "HKCU\Environment"
* - For system PATH: reg query "???"
* - Add zowe/bin to the front of either user or system PATH
* - confirm that we do not exceed max path (1024 for user)
* - For system PATH
* - get user name
* - prompt for password
* - Use setx to set the new PATH value
*/
const ioOptions = ["pipe", "pipe", "pipe"];
const setxPath = process.env.SystemRoot ? nodeJsPath.join(process.env.SystemRoot, 'System32', 'setx.exe') : 'setx.exe';
const spawnResult = (0, child_process_1.spawnSync)(setxPath, ["zowe_set_env_test", pathToZoweBin + ";" + process.env.PATH], {
stdio: ioOptions,
shell: false
});
if (spawnResult.stdout) {
userInfoMsg += spawnResult.stdout.toString();
}
if (spawnResult.stderr) {
userInfoMsg += spawnResult.stderr.toString();
}
}
catch (err) {
userInfoMsg += "Failed to run setx. Reason = " + err.message;
}
return userInfoMsg;
});
}
}
EnableDaemonHandler.openNewTerminalMsg = "To run further Zowe commands, close this terminal and open a new terminal.";
exports.default = EnableDaemonHandler;
//# sourceMappingURL=Enable.handler.js.map