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
JavaScript
/*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;
});