UNPKG

@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
"use strict"; /* * 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