@zowe/imperative
Version:
framework for building configurable CLIs
160 lines • 8.15 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.updateAndGetRemovedTypes = void 0;
exports.uninstall = uninstall;
const fs = require("fs");
const path = require("path");
const PMFConstants_1 = require("../PMFConstants");
const jsonfile_1 = require("jsonfile");
const logger_1 = require("../../../../../logger");
const error_1 = require("../../../../../error");
const utilities_1 = require("../../../../../utilities");
const NpmFunctions_1 = require("../NpmFunctions");
const config_1 = require("../../../../../config");
const npmCmd = (0, NpmFunctions_1.findNpmOnPath)();
/**
* Updates `extenders.json` and returns a list of types to remove from the schema, if applicable.
* @param npmPackage The package name for the plug-in that's being uninstalled
* @returns A list of types to remove from the schema
*/
const updateAndGetRemovedTypes = (npmPackage) => {
const extendersJson = config_1.ConfigUtils.readExtendersJson();
const pluginTypes = Object.keys(extendersJson.profileTypes)
.filter((type) => extendersJson.profileTypes[type].from.includes(npmPackage));
const typesToRemove = [];
if (pluginTypes.length > 0) {
// Only remove a profile type contributed by this plugin if its the single source for that type.
for (const profileType of pluginTypes) {
const typeInfo = extendersJson.profileTypes[profileType];
if (typeInfo.from.length > 1) {
// If there are other sources, remove the version for that type if this plugin provides the
// latest version. This will allow the next source to contribute a different schema version.
if (typeInfo.latestFrom === npmPackage) {
extendersJson.profileTypes[profileType] = Object.assign(Object.assign({}, typeInfo), { from: typeInfo.from.filter((v) => v !== npmPackage), latestFrom: undefined, version: undefined });
}
else {
extendersJson.profileTypes[profileType] = Object.assign(Object.assign({}, typeInfo), { from: typeInfo.from.filter((v) => v !== npmPackage) });
}
}
else {
delete extendersJson.profileTypes[profileType];
typesToRemove.push(profileType);
}
}
config_1.ConfigUtils.writeExtendersJson(extendersJson);
}
return typesToRemove;
};
exports.updateAndGetRemovedTypes = updateAndGetRemovedTypes;
/**
* @TODO - allow multiple packages to be uninstalled?
* Common function that abstracts the uninstall process.
*
* @param {string} packageName A package name. This value is a valid npm package name.
*
*/
function uninstall(packageName) {
var _a;
const iConsole = logger_1.Logger.getImperativeLogger();
const chalk = utilities_1.TextUtils.chalk;
const npmPackage = packageName;
iConsole.debug(`Uninstalling package: ${packageName}`);
iConsole.debug("Reading in the current configuration.");
const installedPlugins = (0, jsonfile_1.readFileSync)(PMFConstants_1.PMFConstants.instance.PLUGIN_JSON);
const updatedInstalledPlugins = {};
if (Object.prototype.hasOwnProperty.call(installedPlugins, packageName)) {
// Loop through the plugins and remove the uninstalled package
for (const pluginName in installedPlugins) {
// Only retain the plugins that aren't being uninstalled
if (packageName.toString() !== pluginName.toString()) {
updatedInstalledPlugins[pluginName] = installedPlugins[pluginName];
}
}
}
else {
throw new error_1.ImperativeError({
msg: `${chalk.yellow.bold("Plugin name")} '${chalk.red.bold(packageName)}' is not installed.`
});
}
try {
// We need to capture stdout but apparently stderr also gives us a progress
// bar from the npm install.
const daemonStream = (_a = utilities_1.ImperativeConfig.instance.daemonContext) === null || _a === void 0 ? void 0 : _a.stream;
const stderrBuffer = [];
const pipe = ["pipe", "pipe", "pipe"];
// Perform the npm uninstall, somehow piping stdout and inheriting stderr gives
// some form of a half-assed progress bar. This progress bar doesn't have any
// formatting or colors but at least I can get the output of stdout right. (comment from install handler)
iConsole.info("Uninstalling package...this may take some time.");
const output = utilities_1.ExecUtils.spawnAndGetOutput(npmCmd, [
"uninstall",
npmPackage,
"--prefix",
PMFConstants_1.PMFConstants.instance.PLUGIN_INSTALL_LOCATION,
"-g"
], {
cwd: PMFConstants_1.PMFConstants.instance.PMF_ROOT,
// We need to capture stdout but apparently stderr also gives us a progress
// bar from the npm install.
stdio: pipe
});
if (output) {
stderrBuffer.push(output.toString());
}
const installFolder = path.join(PMFConstants_1.PMFConstants.instance.PLUGIN_HOME_LOCATION, npmPackage);
if (fs.existsSync(installFolder)) {
throw new Error("Failed to uninstall plugin, install folder still exists:\n " + installFolder);
}
if (PMFConstants_1.PMFConstants.instance.PLUGIN_USING_CONFIG) {
// Update the Imperative Configuration to add the profiles introduced by the recently installed plugin
// This might be needed outside of PLUGIN_USING_CONFIG scenarios, but we haven't had issues with other APIs before
const globalLayer = PMFConstants_1.PMFConstants.instance.PLUGIN_CONFIG.layers.find((layer) => layer.global && layer.exists);
if (globalLayer) {
const schemaInfo = PMFConstants_1.PMFConstants.instance.PLUGIN_CONFIG.getSchemaInfo();
if (schemaInfo.local && fs.existsSync(schemaInfo.resolved)) {
let loadedSchema;
try {
// load schema from disk to prevent removal of profile types from other applications
loadedSchema = config_1.ConfigSchema.loadSchema((0, jsonfile_1.readFileSync)(schemaInfo.resolved));
}
catch (err) {
iConsole.error("Error when removing profile type for plugin %s: failed to parse schema", npmPackage);
}
// update extenders.json with any removed types - function returns the list of types to remove
const typesToRemove = (0, exports.updateAndGetRemovedTypes)(npmPackage);
// Only update global schema if there are types to remove and accessible from disk
if (loadedSchema != null && typesToRemove.length > 0) {
loadedSchema = loadedSchema.filter((typeCfg) => !typesToRemove.includes(typeCfg.type));
const schema = config_1.ConfigSchema.buildSchema(loadedSchema);
config_1.ConfigSchema.updateSchema({ layer: "global", schema });
}
}
}
}
iConsole.info("Uninstall complete");
(0, jsonfile_1.writeFileSync)(PMFConstants_1.PMFConstants.instance.PLUGIN_JSON, updatedInstalledPlugins, {
spaces: 2
});
iConsole.info("Plugin successfully uninstalled.");
if (stderrBuffer.length > 0 && daemonStream) {
daemonStream.write(utilities_1.DaemonRequest.create({ stderr: stderrBuffer.toString() }));
}
}
catch (e) {
throw new error_1.ImperativeError({
msg: e.message,
causeErrors: [e]
});
}
}
//# sourceMappingURL=uninstall.js.map