Add pre/postInstall hooks to module install path

This commit is contained in:
Nick O'Leary
2021-04-15 15:11:45 +01:00
parent 22df59e229
commit 8140057bea
5 changed files with 170 additions and 36 deletions

View File

@@ -9,6 +9,7 @@ const path = require("path");
const clone = require("clone");
const exec = require("@node-red/util").exec;
const log = require("@node-red/util").log;
const hooks = require("@node-red/util").hooks;
const BUILTIN_MODULES = require('module').builtinModules;
const EXTERNAL_MODULES_DIR = "externalModules";
@@ -190,12 +191,22 @@ async function installModule(moduleDetails) {
await ensureModuleDir();
var args = ["install", installSpec, "--production"];
return exec.run(NPM_COMMAND, args, {
cwd: installDir
},true).then(result => {
let triggerPayload = {
"module": moduleDetails.module,
"version": moduleDetails.version,
"dir": installDir,
}
return hooks.trigger("preInstall", triggerPayload).then(() => {
// preInstall passed
// - run install
log.trace(NPM_COMMAND + JSON.stringify(args));
return exec.run(NPM_COMMAND, args, { cwd: installDir },true)
}).then(() => {
return hooks.trigger("postInstall", triggerPayload)
}).then(() => {
log.info(log._("server.install.installed", { name: installSpec }));
}).catch(result => {
var output = result.stderr;
var output = result.stderr || result.toString();
var e;
if (/E404/.test(output) || /ETARGET/.test(output)) {
log.error(log._("server.install.install-failed-not-found",{name:installSpec}));

View File

@@ -23,7 +23,7 @@ const tar = require("tar");
const registry = require("./registry");
const registryUtil = require("./util");
const library = require("./library");
const {exec,log,events} = require("@node-red/util");
const {exec,log,events,hooks} = require("@node-red/util");
const child_process = require('child_process');
const npmCommand = process.platform === 'win32' ? 'npm.cmd' : 'npm';
let installerEnabled = false;
@@ -169,10 +169,23 @@ async function installModule(module,version,url) {
var installDir = settings.userDir || process.env.NODE_RED_HOME || ".";
var args = ['install','--no-audit','--no-update-notifier','--no-fund','--save','--save-prefix=~','--production',installName];
log.trace(npmCommand + JSON.stringify(args));
return exec.run(npmCommand,args,{
cwd: installDir
}, true).then(result => {
let triggerPayload = {
"module": module,
"version": version,
"url": url,
"dir": installDir,
"isExisting": isExisting,
"isUpgrade": isUpgrade
}
return hooks.trigger("preInstall", triggerPayload).then(() => {
// preInstall passed
// - run install
log.trace(npmCommand + JSON.stringify(args));
return exec.run(npmCommand,args,{ cwd: installDir}, true)
}).then(() => {
return hooks.trigger("postInstall", triggerPayload)
}).then(() => {
if (isExisting) {
// This is a module we already have installed as a non-user module.
// That means it was discovered when loading, but was not listed
@@ -191,29 +204,45 @@ async function installModule(module,version,url) {
events.emit("runtime-event",{id:"restart-required",payload:{type:"warning",text:"notification.warnings.restartRequired"},retain:true});
return require("./registry").setModulePendingUpdated(module,version);
}
}).catch(result => {
var output = result.stderr;
var e;
var lookFor404 = new RegExp(" 404 .*"+module,"m");
var lookForVersionNotFound = new RegExp("version not found: "+module+"@"+version,"m");
if (lookFor404.test(output)) {
log.warn(log._("server.install.install-failed-not-found",{name:module}));
e = new Error("Module not found");
e.code = 404;
throw e;
} else if (isUpgrade && lookForVersionNotFound.test(output)) {
log.warn(log._("server.install.upgrade-failed-not-found",{name:module}));
e = new Error("Module not found");
e.code = 404;
throw e;
} else {
}).catch(err => {
let e;
if (err.hook) {
// preInstall failed
log.warn(log._("server.install.install-failed-long",{name:module}));
log.warn("------------------------------------------");
log.warn(output);
log.warn(err.toString());
log.warn("------------------------------------------");
throw new Error(log._("server.install.install-failed"));
e = new Error(log._("server.install.install-failed")+": "+err.toString());
if (err.hook === "postInstall") {
return exec.run(npmCommand,["remove",module],{ cwd: installDir}, false).finally(() => {
throw e;
})
}
} else {
// npm install failed
let output = err.stderr;
let lookFor404 = new RegExp(" 404 .*"+module,"m");
let lookForVersionNotFound = new RegExp("version not found: "+module+"@"+version,"m");
if (lookFor404.test(output)) {
log.warn(log._("server.install.install-failed-not-found",{name:module}));
e = new Error("Module not found");
e.code = 404;
} else if (isUpgrade && lookForVersionNotFound.test(output)) {
log.warn(log._("server.install.upgrade-failed-not-found",{name:module}));
e = new Error("Module not found");
e.code = 404;
} else {
log.warn(log._("server.install.install-failed-long",{name:module}));
log.warn("------------------------------------------");
log.warn(output);
log.warn("------------------------------------------");
e = new Error(log._("server.install.install-failed"));
}
}
})
if (e) {
throw e;
}
});
}).catch(err => {
// In case of error, reset activePromise to be resolvable
activePromise = Promise.resolve();
@@ -412,17 +441,29 @@ function uninstallModule(module) {
log.info(log._("server.install.uninstalling",{name:module}));
var args = ['remove','--no-audit','--no-update-notifier','--no-fund','--save',module];
log.trace(npmCommand + JSON.stringify(args));
exec.run(npmCommand,args,{
cwd: installDir,
},true).then(result => {
let triggerPayload = {
"module": module,
"dir": installDir,
}
return hooks.trigger("preUninstall", triggerPayload).then(() => {
// preUninstall passed
// - run uninstall
log.trace(npmCommand + JSON.stringify(args));
return exec.run(npmCommand,args,{ cwd: installDir}, true)
}).then(() => {
log.info(log._("server.install.uninstalled",{name:module}));
reportRemovedModules(list);
library.removeExamplesDir(module);
resolve(list);
return hooks.trigger("postUninstall", triggerPayload).catch((err)=>{
log.warn("------------------------------------------");
log.warn(err.toString());
log.warn("------------------------------------------");
}).finally(() => {
resolve(list);
})
}).catch(result => {
var output = result.stderr;
let output = result.stderr || result;
log.warn(log._("server.install.uninstall-failed-long",{name:module}));
log.warn("------------------------------------------");
log.warn(output.toString());