profoundjs
Version:
Profound.js Framework and Server
201 lines (183 loc) • 6.05 kB
JavaScript
/*
Discovers and removes additional components that exist outside of the package installation directory.
It's used by Profound Installer
Any changes to the behavior may require changes to the "install_info.json" file or Profound Installer.
*/
const child_process = require("child_process");
const minimist = require("minimist");
const iutils = require("./install_utils.js");
const readline = require("readline");
const IBMi = iutils.isIBMi();
(async() => {
try {
// Parse arguments.
const argDefs = {
alias: {
"h": "help",
"d": "dry-run",
"s": "silent"
},
boolean: [
"h",
"d",
"s"
],
unknown: function(arg) {
console.error("removeExtraComponents.js: Unknown argument:", arg);
process.exit(1);
}
};
const args = minimist(process.argv.slice(2), argDefs);
// Show help and quit, if requested.
if (args["help"] === true) {
const HELP = `Usage: node removeExtraComponents.js [OPTION]
-h, --help Print this help and exit.
-d, --dry-run Report what items would be removed, without removing them.
-s, --silent Bypass confirmation prompt.
Removes components that exist outside of the package installation directory:
* IBM i Connector library, based on config setting: "connectorLibrary"
* IBM i STRTCPSVR instance configuration.
This script does not uninstall the package itself.
It is intended to be used before uninstalling the package via NPM.
`;
console.log(HELP);
process.exit(0);
}
// Get config.
const deployDir = iutils.getDeployDir();
if (!deployDir) {
console.error("removeExtraComponents.js: Can't find deployment directory.");
process.exit(1);
}
const configPath = iutils.getConfigPath();
let config;
try {
config = require(configPath);
}
catch (error) {
console.error("removeExtraComponents.js: Unable to read configuration file: " + configPath);
console.error("removeExtraComponents.js:", error.message);
process.exit(1);
}
let connectorLibrary, connectorIASP;
let instances = [];
const messages = [];
if (IBMi) {
// Get STRTCPSVR instance configs, if any.
instances = iutils.getIBMiInstances(deployDir);
for (const instance of instances) {
messages.push("IBM i STRTCPSVR instance configuration " + instance.name);
}
// Get Connector library details, if any.
connectorLibrary = config.connectorLibrary;
connectorIASP = config.connectorIASP;
if (connectorIASP === undefined) {
connectorIASP = "*SYSBAS";
}
if (connectorLibrary !== undefined) {
let exists = false;
try {
// Determine if library exists.
// This is a weird way to do it...
// This allows us to check for the library even if the IASP is not mounted to the IFS and not in the job current ASP group.
execCL(`qsys/dsplib lib(${connectorLibrary}) aspdev(${connectorIASP}) output(*)`, true);
exists = true;
}
catch (error) {
let handle = false;
if (error.stderr) {
const match = error.stderr.toString().match(/^(CPF.{4}): /);
if (match) {
const msgid = match[1];
handle = (msgid === "CPF2110"); // Library not found.
}
}
if (!handle) {
throw error;
}
}
if (exists) {
messages.push("IBM i Connector library " + connectorLibrary + " in ASP device " + connectorIASP);
}
else {
connectorLibrary = connectorIASP = undefined;
}
}
}
// Report and quit, if requested.
if (args["dry-run"] === true) {
for (const message of messages) {
console.log(message);
}
process.exit(0);
}
if (messages.length === 0) {
console.log("No additional components to remove.");
process.exit(0);
}
if (args["silent"] !== true) {
// Confirm removal.
console.log("The following items will be removed:\n");
for (const message of messages) {
console.log(message);
}
let answer = await new Promise(resolve => {
const readlineInterface = readline.createInterface({
input: process.stdin,
output: process.stdout,
terminal: false
});
readlineInterface.question("\nAre you sure you want to proceed (y/n)? ", function(answer) {
readlineInterface.close();
resolve(answer);
});
});
answer = answer.trim().toLowerCase();
if (answer === "") {
answer = "n";
}
if (answer !== "y") {
console.log("Removal of extra components canceled.");
process.exit(0);
}
}
for (const instance of instances) {
execCL(`QSYS/ENDTCPSVR SERVER(*PJS) INSTANCE(${instance.name})`);
// This should generally work as shutdown is relatively fast.
await new Promise(resolve => setTimeout(resolve, 10000));
exec(`/usr/bin/rm -rf '/profoundjs-base/instances/${instance.name}'`);
}
if (connectorLibrary !== undefined) {
execCL(`qsys/dltlib lib(${connectorLibrary}) aspdev(${connectorIASP})`);
}
console.log("Removal of extra components complete.");
process.stdin.destroy();
}
catch (error) {
process.stdin.destroy();
console.error(error);
process.exit(1);
}
})();
function execCL(command, quiet) {
command = `/usr/bin/system '${escapeQuotes(command)}'`;
return exec(command, quiet);
function escapeQuotes(input) {
return input.replace(/'/g, "'\\''");
}
}
function exec(command, quiet = false) {
if (quiet !== true) {
console.log("Executing command:", command);
}
const opts = {
env: {
QIBM_USE_DESCRIPTOR_STDIO: "Y",
QIBM_MULTI_THREADED: "N"
},
stdio: "pipe",
windowsHide: true
};
return child_process.execSync(command, opts).toString();
}
;