diff --git a/red/nodes/registry.js b/red/nodes/registry.js index 983c774fc..b3ca1e97d 100644 --- a/red/nodes/registry.js +++ b/red/nodes/registry.js @@ -95,7 +95,7 @@ var registry = (function() { nodeList = []; nodeConfigCache = null; }, - addNodeSet: function(id,set) { + addNodeSet: function(id,set,version) { if (!set.err) { set.types.forEach(function(t) { nodeTypeToId[t] = id; @@ -105,6 +105,10 @@ var registry = (function() { nodeModules[set.module] = nodeModules[set.module]||{nodes:[]}; nodeModules[set.module].nodes.push(set.name); + if (version) { + nodeModules[set.module].version = version.replace(/(\r\n|\n|\r)/gm,""); + } + nodeConfigs[id] = set; nodeList.push(id); nodeConfigCache = null; @@ -181,10 +185,11 @@ var registry = (function() { }, getModuleInfo: function(module) { if (nodeModules[module]) { + console.log(nodeModules[module]); var nodes = nodeModules[module].nodes; var m = { name: module, - version: "TODO", + version: nodeModules[module].version, nodes: [] }; for (var i = 0; i < nodes.length; ++i) { @@ -438,7 +443,7 @@ function scanTreeForNodesModules(moduleName) { * @param moduleDir the root directory of the package * @param pkg the module's package.json object */ -function loadNodesFromModule(moduleDir,pkg) { +function loadNodesFromModule(moduleDir,pkg,version) { var nodes = pkg['node-red'].nodes||{}; var results = []; var iconDirs = []; @@ -446,7 +451,7 @@ function loadNodesFromModule(moduleDir,pkg) { if (nodes.hasOwnProperty(n)) { var file = path.join(moduleDir,nodes[n]); try { - results.push(loadNodeConfig(file,pkg.name,n)); + results.push(loadNodeConfig(file,pkg.name,n,version)); } catch(err) { } var iconDir = path.join(moduleDir,path.dirname(nodes[n]),"icons"); @@ -477,7 +482,7 @@ function loadNodesFromModule(moduleDir,pkg) { * types: an array of node type names in this file * } */ -function loadNodeConfig(file,module,name) { +function loadNodeConfig(file,module,name,version) { var id = module + "/" + name; var info = registry.getNodeInfo(id); @@ -531,7 +536,7 @@ function loadNodeConfig(file,module,name) { node.err = err.toString(); } } - registry.addNodeSet(id,node); + registry.addNodeSet(id,node,version); return node; } @@ -676,7 +681,7 @@ function addNode(file) { return loadNodeList(nodes); } -function addModule(module) { +function addModule(module,version) { if (!settings.available()) { throw new Error("Settings unavailable"); } @@ -691,7 +696,7 @@ function addModule(module) { return when.reject(err); } moduleFiles.forEach(function(moduleFile) { - nodes = nodes.concat(loadNodesFromModule(moduleFile.dir,moduleFile.package)); + nodes = nodes.concat(loadNodesFromModule(moduleFile.dir,moduleFile.package,version)); }); return loadNodeList(nodes); } diff --git a/red/server.js b/red/server.js index 8394c84b9..71fd21b76 100644 --- a/red/server.js +++ b/red/server.js @@ -33,10 +33,10 @@ function init(_server,_settings) { settings = _settings; comms.init(_server,_settings); - + nodeApp = express(); app = express(); - + if (settings.httpAdminRoot !== false) { require("./api").init(app); } @@ -44,7 +44,7 @@ function init(_server,_settings) { function start() { var defer = when.defer(); - + storage.init(settings).then(function() { settings.load(storage).then(function() { console.log("\nWelcome to Node-RED\n===================\n"); @@ -95,7 +95,7 @@ function start() { } } defer.resolve(); - + redNodes.loadFlows(); }).otherwise(function(err) { console.log(err); @@ -105,7 +105,7 @@ function start() { }).otherwise(function(err) { defer.reject(err); }); - + return defer.promise; } @@ -138,7 +138,7 @@ function reportRemovedModules(removedNodes) { return removedNodes; } -function installModule(module) { +function installModule(module) { //TODO: ensure module is 'safe' return when.promise(function(resolve,reject) { if (/[\s;]/.test(module)) { @@ -162,8 +162,10 @@ function installModule(module) { reject(new Error("Install failed")); } } else { - util.log("[red] Installed module: "+module); - resolve(redNodes.addModule(module).then(reportAddedModules)); + var grandchild = child_process.exec('npm view '+module+' version', function(err, stdin, stdout) { + util.log("[red] Installed module: "+module+":"+stdin); + resolve(redNodes.addModule(module,stdin).then(reportAddedModules)); + }); } }); }); @@ -200,11 +202,11 @@ function stop() { comms.stop(); } -module.exports = { +module.exports = { init: init, start: start, stop: stop, - + reportAddedModules: reportAddedModules, reportRemovedModules: reportRemovedModules, installModule: installModule, diff --git a/test/red/nodes/registry_spec.js b/test/red/nodes/registry_spec.js index 842bacda7..1ed59eab6 100644 --- a/test/red/nodes/registry_spec.js +++ b/test/red/nodes/registry_spec.js @@ -710,6 +710,55 @@ describe('NodeRegistry', function() { }); }); + it('adds module with version number', function(done) { + var fs = require("fs"); + var path = require("path"); + + var pathJoin = (function() { + var _join = path.join; + return sinon.stub(path,"join",function() { + if (arguments.length == 3 && arguments[2] == "package.json") { + return _join(resourcesDir,"TestNodeModule" + path.sep + "node_modules" + path.sep,arguments[1],arguments[2]); + } + if (arguments.length == 2 && arguments[1] == "TestNodeModule") { + return _join(resourcesDir,"TestNodeModule" + path.sep + "node_modules" + path.sep,arguments[1]); + } + return _join.apply(this,arguments); + }); + })(); + + var readdirSync = (function() { + var originalReaddirSync = fs.readdirSync; + var callCount = 0; + return sinon.stub(fs,"readdirSync",function(dir) { + var result = []; + if (callCount == 1) { + result = originalReaddirSync(resourcesDir + "TestNodeModule" + path.sep + "node_modules"); + } + callCount++; + return result; + }); + })(); + typeRegistry.init(settingsWithStorage); + typeRegistry.load("wontexist",true).then(function(){ + typeRegistry.addModule("TestNodeModule","0.0.1").then(function(node) { + var module = typeRegistry.getModuleInfo("TestNodeModule"); + + module.should.have.property("name","TestNodeModule"); + module.should.have.property("version","0.0.1"); + + done(); + }).catch(function(e) { + done(e); + }); + + }).catch(function(e) { + done(e); + }).finally(function() { + readdirSync.restore(); + pathJoin.restore(); + }); + }); it('rejects adding duplicate node modules', function(done) { var fs = require("fs");