UNPKG

webgme-rosmod

Version:

This repository contains ROSMOD developed for WebGME. ROSMOD is a web-based, collaborative, modeling and execution environment for distributed embedded applications built using ROS http://rosmod.rcps.isis.vanderbilt.edu

309 lines (281 loc) 11.8 kB
/*globals define*/ /*eslint-env node, browser*/ /** * Generated by PluginGenerator 2.16.0 from webgme on Thu May 10 2018 09:02:07 GMT-0500 (CDT). * A plugin that inherits from the PluginBase. To see source code documentation about available * properties and methods visit %host%/docs/source/PluginBase.html. */ define([ 'plugin/PluginConfig', 'text!./metadata.json', 'plugin/PluginBase', 'remote-utils/remote-utils', 'webgme-to-json/webgme-to-json', 'rosmod/processor', 'q' ], function ( PluginConfig, pluginMetadata, PluginBase, utils, webgmeToJson, processor, Q) { 'use strict'; pluginMetadata = JSON.parse(pluginMetadata); /** * Initializes a new instance of InstallRuntime. * @class * @augments {PluginBase} * @classdesc This class represents the plugin InstallRuntime. * @constructor */ var InstallRuntime = function () { // Call base class' constructor. PluginBase.call(this); this.pluginMetadata = pluginMetadata; }; /** * Metadata associated with the plugin. Contains id, name, version, description, icon, configStructue etc. * This is also available at the instance at this.pluginMetadata. * @type {object} */ InstallRuntime.metadata = pluginMetadata; // Prototypical inheritance from PluginBase. InstallRuntime.prototype = Object.create(PluginBase.prototype); InstallRuntime.prototype.constructor = InstallRuntime; InstallRuntime.prototype.notify = function(level, msg) { if (typeof msg !== 'string') { msg = new String(msg); } var self = this; var prefix = self.projectId + '::' + self.projectName + '::' + level + '::'; var lines = msg.split('\n'); lines.map(function(line) { if (level=='error') self.logger.error(line); else if (level=='debug') self.logger.debug(line); else if (level=='info') self.logger.info(line); else if (level=='warning') self.logger.warn(line); self.createMessage(self.activeNode, line, level); self.sendNotification(prefix+line); }); }; /** * Main function for the plugin to execute. This will perform the execution. * Notes: * - Always log with the provided logger.[error,warning,info,debug]. * - Do NOT put any user interaction logic UI, etc. inside this method. * - callback always has to be called even if error happened. * * @param {function(string, plugin.PluginResult)} callback - the result callback */ InstallRuntime.prototype.main = function (callback) { // Use self to access core, project, result, logger etc from PluginBase. // These are all instantiated at this point. var self = this; // Default fails self.result.success = false; self.updateMETA({}); // What did the user select for our configuration? var currentConfig = self.getCurrentConfig(); self.forceIsolation = currentConfig.forceIsolation; // get the selected hosts from the config // also get the ordered nodes from the config self.selectedHostConfig = {}; var disabledHostMessage = 'Do not install on this host'; var hostConfigTmpl = { user: '', enabled: false, install: '', workspace: '' }; Object.keys(currentConfig).map(function(k) { if (k.indexOf("Host_Config:") > -1) { var hostPath = k.split(":")[1]; var hostConfig = currentConfig[k]; // set up config self.selectedHostConfig[ hostPath ] = Object.assign({}, hostConfigTmpl); // get user var selectedUser = hostConfig["user"]; if (selectedUser != disabledHostMessage) { self.selectedHostConfig[ hostPath ].user = selectedUser; self.selectedHostConfig[ hostPath ].enabled = true; } // get install space var installPath = hostConfig["installPath"]; self.selectedHostConfig[ hostPath ].install = installPath; // get extended workspace var extendDir = hostConfig["workspace"]; self.selectedHostConfig[ hostPath ].workspace = extendDir; } }); // set up libraries webgmeToJson.notify = function(level, msg) {self.notify(level, msg);} utils.notify = function(level, msg) {self.notify(level, msg);} utils.trackedProcesses = ['catkin', 'rosmod_actor', 'roscore']; // the active node for this plugin is system -> systems -> project var projectNode = self.core.getParent(self.core.getParent(self.activeNode)); var projectName = self.core.getAttribute(projectNode, 'name'); var systemName = self.core.getAttribute(self.activeNode, 'name'); webgmeToJson.loadModel(self.core, self.rootNode, self.activeNode, true, true) .then(function(projectModel) { processor.processModel(projectModel); self.projectModel = projectModel.root; self.objectDict = projectModel.objects; self.notify('info',`Installing onto hosts in ${self.systemName}`); return self.install(); }) .then(function () { self.result.setSuccess(true); callback(null, self.result); }) .catch(function(err) { if (typeof err !== 'string') err = new String(err); self.notify('error', err); self.result.setSuccess(false); callback(err, self.result); }) .done(); }; InstallRuntime.prototype.addMarkup = function(level, summary, details) { var self = this, Convert = require('ansi-to-html'), convert = new Convert(); // ADD STDOUT / STDERR TO RESULTS AS HIDABLE TEXT var msg = `<details><summary><b>${summary}</b></summary>` + '<pre>' + '<code>'+ convert.toHtml(details) + '</code>'+ '</pre>' + '</details>'; self.createMessage(self.activeNode, msg, level); }; InstallRuntime.prototype.getAvailableHosts = function() { var self = this; var _ = require('underscore'); var validHosts = Object.keys(self.selectedHostConfig) .filter(hostPath => { return self.selectedHostConfig[hostPath].enabled; }) .map(hostPath => { return self.objectDict[hostPath]; }); if (_.isEmpty(validHosts)) { throw new String("No Hosts selected or in model!"); } return utils.getAvailableHosts(validHosts, self.forceIsolation); }; InstallRuntime.prototype.install = function() { var self = this; return self.getAvailableHosts() .then((hosts) => { var tasks = hosts.map((host) => { return self.installOnHost(host); }); return Q.all(tasks); }); }; InstallRuntime.prototype.installOnHost = function(host) { var self = this; var path = require('path'); // need to get the right host using the config's host name var hostPath = host.host.path; var ip = host.intf.IP; var user = host.user; var build_dir = path.join(user.Directory, 'rosmod_runtime_bulid_ws'); var sanitizedBuildDir = utils.sanitizePath(build_dir); var hostConfig = self.selectedHostConfig[hostPath]; var compile_commands = [ 'rm -rf ' + sanitizedBuildDir, 'mkdir -p ' + sanitizedBuildDir + '/src', 'cd ' + sanitizedBuildDir, 'catkin config --extend ' + hostConfig.workspace, 'catkin config -i ' + hostConfig.install, 'catkin config --install', 'git clone --depth=1 https://github.com/ros/common_msgs.git src/common_msgs', 'git clone --depth=1 https://github.com/rosmod/actionlib src/actionlib', 'git clone --depth=1 https://github.com/rosmod/rosmod-actor src/rosmod-actor', 'catkin build', 'rm -rf ' + sanitizedBuildDir, ]; // now run the commands self.notify('info',`Building and installing ROSMOD Runtime on ${host.host.name}::${ip}`); host.hasError = false; host.stdErr = ''; host.stdOut = ''; var compileDataCallback = function(host) { return function(data) { return self.parseCompileData(host, data); }; }(host); var compileErrorCallback = function(host) { return function(data) { return self.parseCompileError(host, data); }; }(host); return utils.executeOnHost(compile_commands, ip, user, compileErrorCallback, compileDataCallback, true) .catch(function(err) { self.notify('error',`Compiling ran into an error: ${err}`); }) .finally(function() { if (host.hasError) { self.notify('error',`Host ran into an error during compilation - check the stderr.`); } else { self.notify('info',`Host compilation and install succeeded.`); } self.addMarkup('error', `Compile STDOUT from ${host.intf.IP}:`, host.stdOut); self.addMarkup('error', `Compile STDERR from ${host.intf.IP}:`, host.stdErr); // ADD STDOUT / STDERR TO RESULTS AS BLOBS var files = {}; var stripANSI = require('strip-ansi'); files[ host.intf.IP + '.compile.stdout.txt' ] = stripANSI(host.stdOut); files[ host.intf.IP + '.compile.stderr.txt' ] = stripANSI(host.stdErr); var fnames = Object.keys(files); var tasks = fnames.map((fname) => { return self.blobClient.putFile(fname, files[fname]) .then((hash) => { self.result.addArtifact(hash); }); }); return Q.all(tasks); }); }; InstallRuntime.prototype.parseCompileError = function(host, data) { var self = this; var stripANSI = require('strip-ansi'); var strippedData = stripANSI(data); host.stdErr += data; if (host.hasError || self.compileHasError(strippedData)) { host.hasError = true; } return false; }; InstallRuntime.prototype.parseCompileData = function(host, data) { var self = this; var stripANSI = require('strip-ansi'); var strippedData = stripANSI(data); if (host.hasError || self.compileHasError(strippedData)) { return self.parseCompileError(host, data); } else { host.stdOut += data; } return false; }; InstallRuntime.prototype.compileHasError = function(data) { return data.indexOf('Errors << ') > -1 || data.indexOf('Traceback (most recent call last):') > -1 || data.indexOf('error:') > -1; }; return InstallRuntime; });