UNPKG

akurath

Version:

IDE Frontend for codepsaces.io

175 lines (136 loc) 4.48 kB
// Requires var Q = require('q'); var _ = require('lodash'); var path = require('path'); var utils = require('../utils'); function ProjectRunner(events, workspace, shells, run_ports, project, urlPattern) { // Id for port allocation and stuff this.id = 'project'; this.events = events; this.workspace = workspace; this.shells = shells; this.run_ports = run_ports; this.project = project; this.urlPattern = urlPattern; // Map // runnerId => shellId this.projects = { //'php:run': 'project-php-2000-xyz' }; // Self incrimenting unique id this.projectCount = 0; _.bindAll(this); } ProjectRunner.prototype.shellId = function(runnerId, port) { return [this.id, runnerId, port, this.projectCount++].join('-'); }; ProjectRunner.prototype.portId = function(runnerId) { return [this.id, runnerId].join('-'); }; ProjectRunner.prototype.runScript = function(runner, port, options) { var self = this; // Id of our shell var shellId = this.shellId(runner.id, port); // Spawn the new shell return this.shells.createShellCommand( shellId, [ '/bin/bash', // Script itself runner.script, // Path to project folder this.workspace.root, // Port allocated/claimed port, options.nodeId ], { cwd: this.workspace.root, env: _.defaults({ PORT: port, HTTP_PORT: port }, process.env) }).then(function(shell) { // Id of our harbor port (to release) var portId = self.portId(runner.id); // Register project self.projects[runner.id] = shellId; // Free port on shell exit self.shells.shells[shellId].ps.once('exit', function() { self.run_ports.release(portId); // Delete the project delete self.projects[runner.id]; }); // Emit event self.events.emit("run.project", { type: runner.id }); return { id: runner.id, name: runner.name, shellId: shellId, type: runner.type, port: port, url: self.getUrl(port) }; }); }; ProjectRunner.prototype.detect = function() { return this.project.detect(); }; ProjectRunner.prototype.isRunning = function(portId) { return false; // _.has(this.run_ports.ports, portId); }; ProjectRunner.prototype.getUrl = function(port) { return this.urlPattern.replace("%d", port); }; ProjectRunner.prototype.killProject = function(runnerId) { var d = Q.defer(); var shellId = this.projects[runnerId]; var shell = shellId ? this.shells.shells[shellId] : null; if(!shellId || !shell) { return Q.reject('No project shell to kill for: '+runnerId); } // return Q.resolve(true); shell.ps.once('exit', d.resolve); shell.ps.destroy(); return d.promise; }; ProjectRunner.prototype.run = function(options) { var self = this; var runner = null; // Check if project has a specific type return this.detect() .then(function(projectType) { runner = projectType.getRunner(_.extend({}, options, { pick: true })); if (!runner) return Q.reject(new Error('No runner of type "'+(options.type || "default")+'" for project type: '+projectType.id)); return runner; }) .then(function(runner) { if(!self.projects[runner.id]) return runner; // Kill the current project to launch a new one return self.killProject(runner.id) .then(utils.constant(runner)); }) .then(function(runner) { var portId = 2000 + options.nodeId; // self.portId(runner.id); if(self.isRunning(portId)) { var _port = self.run_ports.ports[portId]; return Q.reject(new Error("Project is already running on "+self.getUrl(_port))); } // Now that we have the type, claim a port // then run the script return Q.all([ runner, // Get a new port self.run_ports.claim(portId) ]) .spread(function(runner, port) { // Run the script in a new shell and return // a object describing the run return self.runScript(runner, port, options); }); }); }; // Exports exports.ProjectRunner = ProjectRunner;