1
0
mirror of https://github.com/node-red/node-red.git synced 2023-10-10 13:36:53 +02:00

Ensure add/remove modules are handled sequentially

This commit is contained in:
Nick O'Leary 2018-07-30 10:08:39 +01:00
parent f1d5bbb036
commit 5155770213
No known key found for this signature in database
GPG Key ID: 4F2157149161A6C9
2 changed files with 133 additions and 118 deletions

View File

@ -15,7 +15,6 @@
**/ **/
var when = require("when");
var path = require("path"); var path = require("path");
var fs = require("fs"); var fs = require("fs");
@ -36,6 +35,8 @@ function init(_settings) {
settings = _settings; settings = _settings;
} }
var activePromise = Promise.resolve();
function checkModulePath(folder) { function checkModulePath(folder) {
var moduleName; var moduleName;
var err; var err;
@ -71,79 +72,86 @@ function checkExistingModule(module,version) {
return false; return false;
} }
function installModule(module,version) { function installModule(module,version) {
//TODO: ensure module is 'safe' activePromise = activePromise.then(() => {
return when.promise(function(resolve,reject) { //TODO: ensure module is 'safe'
var installName = module; return new Promise((resolve,reject) => {
var isUpgrade = false; var installName = module;
try { var isUpgrade = false;
if (moduleRe.test(module)) { try {
// Simple module name - assume it can be npm installed if (moduleRe.test(module)) {
if (version) { // Simple module name - assume it can be npm installed
installName += "@"+version; if (version) {
installName += "@"+version;
}
} else if (slashRe.test(module)) {
// A path - check if there's a valid package.json
installName = module;
module = checkModulePath(module);
} }
} else if (slashRe.test(module)) { isUpgrade = checkExistingModule(module,version);
// A path - check if there's a valid package.json } catch(err) {
installName = module; return reject(err);
module = checkModulePath(module);
} }
isUpgrade = checkExistingModule(module,version); if (!isUpgrade) {
} catch(err) { log.info(log._("server.install.installing",{name: module,version: version||"latest"}));
return reject(err);
}
if (!isUpgrade) {
log.info(log._("server.install.installing",{name: module,version: version||"latest"}));
} else {
log.info(log._("server.install.upgrading",{name: module,version: version||"latest"}));
}
var installDir = settings.userDir || process.env.NODE_RED_HOME || ".";
var args = ['install','--save','--save-prefix="~"','--production',installName];
log.trace(npmCommand + JSON.stringify(args));
var child = child_process.spawn(npmCommand,args,{
cwd: installDir,
shell: true
});
var output = "";
child.stdout.on('data', (data) => {
output += data;
});
child.stderr.on('data', (data) => {
output += data;
});
child.on('close', (code) => {
if (code !== 0) {
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;
reject(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;
reject(e);
} else {
log.warn(log._("server.install.install-failed-long",{name:module}));
log.warn("------------------------------------------");
log.warn(output);
log.warn("------------------------------------------");
reject(new Error(log._("server.install.install-failed")));
}
} else { } else {
if (!isUpgrade) { log.info(log._("server.install.upgrading",{name: module,version: version||"latest"}));
log.info(log._("server.install.installed",{name:module}));
resolve(require("./index").addModule(module).then(reportAddedModules));
} else {
log.info(log._("server.install.upgraded",{name:module, version:version}));
events.emit("runtime-event",{id:"restart-required",payload:{type:"warning",text:"notification.warnings.restartRequired"},retain:true});
resolve(require("./registry").setModulePendingUpdated(module,version));
}
} }
var installDir = settings.userDir || process.env.NODE_RED_HOME || ".";
var args = ['install','--save','--save-prefix="~"','--production',installName];
log.trace(npmCommand + JSON.stringify(args));
var child = child_process.spawn(npmCommand,args,{
cwd: installDir,
shell: true
});
var output = "";
child.stdout.on('data', (data) => {
output += data;
});
child.stderr.on('data', (data) => {
output += data;
});
child.on('close', (code) => {
if (code !== 0) {
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;
reject(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;
reject(e);
} else {
log.warn(log._("server.install.install-failed-long",{name:module}));
log.warn("------------------------------------------");
log.warn(output);
log.warn("------------------------------------------");
reject(new Error(log._("server.install.install-failed")));
}
} else {
if (!isUpgrade) {
log.info(log._("server.install.installed",{name:module}));
resolve(require("./index").addModule(module).then(reportAddedModules));
} else {
log.info(log._("server.install.upgraded",{name:module, version:version}));
events.emit("runtime-event",{id:"restart-required",payload:{type:"warning",text:"notification.warnings.restartRequired"},retain:true});
resolve(require("./registry").setModulePendingUpdated(module,version));
}
}
});
}); });
}).catch(err => {
// In case of error, reset activePromise to be resolvable
activePromise = Promise.resolve();
throw err;
}); });
return activePromise;
} }
@ -176,47 +184,54 @@ function reportRemovedModules(removedNodes) {
} }
function uninstallModule(module) { function uninstallModule(module) {
return when.promise(function(resolve,reject) { activePromise = activePromise.then(() => {
if (/[\s;]/.test(module)) { return new Promise((resolve,reject) => {
reject(new Error(log._("server.install.invalid"))); if (/[\s;]/.test(module)) {
return; reject(new Error(log._("server.install.invalid")));
} return;
var installDir = settings.userDir || process.env.NODE_RED_HOME || ".";
var moduleDir = path.join(installDir,"node_modules",module);
try {
fs.statSync(moduleDir);
} catch(err) {
return reject(new Error(log._("server.install.uninstall-failed",{name:module})));
}
var list = registry.removeModule(module);
log.info(log._("server.install.uninstalling",{name:module}));
var args = ['remove','--save',module];
log.trace(npmCommand + JSON.stringify(args));
var child = child_process.execFile(npmCommand,args,
{
cwd: installDir
},
function(err, stdin, stdout) {
if (err) {
log.warn(log._("server.install.uninstall-failed-long",{name:module}));
log.warn("------------------------------------------");
log.warn(err.toString());
log.warn("------------------------------------------");
reject(new Error(log._("server.install.uninstall-failed",{name:module})));
} else {
log.info(log._("server.install.uninstalled",{name:module}));
reportRemovedModules(list);
// TODO: tidy up internal event names
events.emit("node-module-uninstalled",module)
resolve(list);
}
} }
); var installDir = settings.userDir || process.env.NODE_RED_HOME || ".";
var moduleDir = path.join(installDir,"node_modules",module);
try {
fs.statSync(moduleDir);
} catch(err) {
return reject(new Error(log._("server.install.uninstall-failed",{name:module})));
}
var list = registry.removeModule(module);
log.info(log._("server.install.uninstalling",{name:module}));
var args = ['remove','--save',module];
log.trace(npmCommand + JSON.stringify(args));
var child = child_process.execFile(npmCommand,args,
{
cwd: installDir
},
function(err, stdin, stdout) {
if (err) {
log.warn(log._("server.install.uninstall-failed-long",{name:module}));
log.warn("------------------------------------------");
log.warn(err.toString());
log.warn("------------------------------------------");
reject(new Error(log._("server.install.uninstall-failed",{name:module})));
} else {
log.info(log._("server.install.uninstalled",{name:module}));
reportRemovedModules(list);
// TODO: tidy up internal event names
events.emit("node-module-uninstalled",module)
resolve(list);
}
}
);
});
}).catch(err => {
// In case of error, reset activePromise to be resolvable
activePromise = Promise.resolve();
throw err;
}); });
return activePromise;
} }
function checkPrereq() { function checkPrereq() {
@ -227,9 +242,9 @@ function checkPrereq() {
) { ) {
log.info(log._("server.palette-editor.disabled")); log.info(log._("server.palette-editor.disabled"));
paletteEditorEnabled = false; paletteEditorEnabled = false;
return when.resolve(); return Promise.resolve();
} else { } else {
return when.promise(function(resolve) { return new Promise(resolve => {
child_process.execFile(npmCommand,['-v'],function(err) { child_process.execFile(npmCommand,['-v'],function(err) {
if (err) { if (err) {
log.info(log._("server.palette-editor.npm-not-found")); log.info(log._("server.palette-editor.npm-not-found"));

View File

@ -73,7 +73,7 @@ describe('nodes/registry/installer', function() {
return ee; return ee;
}); });
installer.installModule("this_wont_exist").otherwise(function(err) { installer.installModule("this_wont_exist").catch(function(err) {
err.code.should.be.eql(404); err.code.should.be.eql(404);
done(); done();
}); });
@ -95,7 +95,7 @@ describe('nodes/registry/installer', function() {
} }
}); });
installer.installModule("this_wont_exist","0.1.2").otherwise(function(err) { installer.installModule("this_wont_exist","0.1.2").catch(function(err) {
err.code.should.be.eql(404); err.code.should.be.eql(404);
done(); done();
}); });
@ -106,7 +106,7 @@ describe('nodes/registry/installer', function() {
version: "0.1.1" version: "0.1.1"
} }
}); });
installer.installModule("this_wont_exist","0.1.1").otherwise(function(err) { installer.installModule("this_wont_exist","0.1.1").catch(function(err) {
err.code.should.be.eql('module_already_loaded'); err.code.should.be.eql('module_already_loaded');
done(); done();
}); });
@ -125,7 +125,7 @@ describe('nodes/registry/installer', function() {
installer.installModule("this_wont_exist").then(function() { installer.installModule("this_wont_exist").then(function() {
done(new Error("Unexpected success")); done(new Error("Unexpected success"));
}).otherwise(function(err) { }).catch(function(err) {
done(); done();
}); });
}); });
@ -150,7 +150,7 @@ describe('nodes/registry/installer', function() {
// commsMessages[0].topic.should.equal("node/added"); // commsMessages[0].topic.should.equal("node/added");
// commsMessages[0].msg.should.eql(nodeInfo.nodes); // commsMessages[0].msg.should.eql(nodeInfo.nodes);
done(); done();
}).otherwise(function(err) { }).catch(function(err) {
done(err); done(err);
}); });
}); });
@ -159,7 +159,7 @@ describe('nodes/registry/installer', function() {
var resourcesDir = path.resolve(path.join(__dirname,"..","resources","local","TestNodeModule","node_modules","NonExistant")); var resourcesDir = path.resolve(path.join(__dirname,"..","resources","local","TestNodeModule","node_modules","NonExistant"));
installer.installModule(resourcesDir).then(function() { installer.installModule(resourcesDir).then(function() {
done(new Error("Unexpected success")); done(new Error("Unexpected success"));
}).otherwise(function(err) { }).catch(function(err) {
if (err.hasOwnProperty("code")) { if (err.hasOwnProperty("code")) {
err.code.should.eql(404); err.code.should.eql(404);
done(); done();
@ -189,7 +189,7 @@ describe('nodes/registry/installer', function() {
installer.installModule(resourcesDir).then(function(info) { installer.installModule(resourcesDir).then(function(info) {
info.should.eql(nodeInfo); info.should.eql(nodeInfo);
done(); done();
}).otherwise(function(err) { }).catch(function(err) {
done(err); done(err);
}); });
}); });
@ -218,7 +218,7 @@ describe('nodes/registry/installer', function() {
installer.uninstallModule("this_wont_exist").then(function() { installer.uninstallModule("this_wont_exist").then(function() {
done(new Error("Unexpected success")); done(new Error("Unexpected success"));
}).otherwise(function(err) { }).catch(function(err) {
done(); done();
}); });
}); });
@ -242,7 +242,7 @@ describe('nodes/registry/installer', function() {
// commsMessages[0].topic.should.equal("node/removed"); // commsMessages[0].topic.should.equal("node/removed");
// commsMessages[0].msg.should.eql(nodeInfo); // commsMessages[0].msg.should.eql(nodeInfo);
done(); done();
}).otherwise(function(err) { }).catch(function(err) {
done(err); done(err);
}); });
}); });