Skip to content

Commit

Permalink
Google app engine runner integration
Browse files Browse the repository at this point in the history
  • Loading branch information
Rendez committed May 2, 2011
1 parent 0e3bf47 commit 7710a21
Show file tree
Hide file tree
Showing 12 changed files with 8,919 additions and 600 deletions.
1 change: 1 addition & 0 deletions client/ext/noderunner/noderunner.js
Original file line number Diff line number Diff line change
Expand Up @@ -139,6 +139,7 @@ return ext.register("ext/noderunner/noderunner", {
var command = {
"command" : debug ? "RunDebugBrk" : "Run",
"file" : path.replace(/^\/+/, ""),
"runner" : ddRunnerSelector.value, // Explicit addition; trying to affect as less logic as possible for now...
"args" : args || "",
"env" : {
"C9_SELECTED_FILE": page ? page.getAttribute("path").slice(ide.davPrefix.length) : ""
Expand Down
8 changes: 5 additions & 3 deletions client/ext/run/run.js
Original file line number Diff line number Diff line change
Expand Up @@ -82,19 +82,21 @@ return ext.register("ext/run/run", {

addConfig : function() {
var file = ide.getActivePageModel();
var extension = "";

if (!file || (file.getAttribute("contenttype") || "").indexOf("application/javascript") != 0) {
if (!file || (file.getAttribute("contenttype") || "").indexOf("application/javascript") != 0 && (file.getAttribute("contenttype") || "").indexOf("text/x-script.python") != 0) {
var path = "";
var name = "server";
}
else {
path = file.getAttribute("path").slice(ide.davPrefix.length + 1);
name = file.getAttribute("name").replace(/\.js$/, "");
path = file.getAttribute("path").slice(ide.davPrefix.length + 1);
name = file.getAttribute("name").replace(/\.(js|py)$/, function(full, ext){ extension = ext; return ""; });
}

var cfg = apf.n("<config />")
.attr("path", path)
.attr("name", name)
.attr("extension", extension)
.attr("args", "").node();

mdlRunConfigurations.appendXml(cfg);
Expand Down
27 changes: 24 additions & 3 deletions client/ext/run/run.xml
Original file line number Diff line number Diff line change
Expand Up @@ -62,14 +62,35 @@
disabled="{!lstRunCfg.selected}"/>
</a:hbox>
<a:divider />
<a:hbox align="center" margin="5 10" padding="10">
<a:label width="130" textalign="right">JavaScript file</a:label>
<a:hbox align="center" margin="5 10" padding="10" visible="{ddRunnerSelector.value != 'gae'}">
<a:label width="130" textalign="right">File path</a:label>
<a:textbox id="txtRunCfgName" flex="1" value="[@path]" disabled="{!lstRunCfg.selected}"/>
<a:button icon="folder.png" disabled="true" tooltip="Browse ..."></a:button>
</a:hbox>
<a:divider visible="{ddRunnerSelector.value != 'gae'}" />
<a:hbox align="center" margin="5 10" padding="10">
<a:model id="mdlRunnerSelector">
<data>
<element caption="JavaScript" value="js" />
<element caption="Python" value="py" />
<element caption="AppEngine" value="gae" />
</data>
</a:model>
<a:label width="130" textalign="right">Runner</a:label>
<a:dropdown id="ddRunnerSelector"
model="mdlRunnerSelector"
flex="1"
disabled="{!lstRunCfg.selected}"
selected="{lstRunCfg.selected.attributes['extension'].value}">
<a:each match="[element]">
<a:caption match="[@caption]" />
<a:value match="[@value]" />
</a:each>
</a:dropdown>
</a:hbox>
<a:hbox align="center" margin="5 10" padding="10" visible="{ddRunnerSelector.value != 'gae'}">
<a:label width="130" textalign="right">Command line arguments</a:label>
<a:textbox id="txtRunCfgName" flex="1" value="[@args]" disabled="{!lstRunCfg.selected}"/>
<a:textbox id="txtRunCfgName" flex="1" value="[@args]" disabled="{!lstRunCfg.selected}" />
</a:hbox>
<a:divider />
<a:hbox padding="5" pack="end" edge="10 10 5 10">
Expand Down
9,305 changes: 8,727 additions & 578 deletions client/js/apf_release.js

Large diffs are not rendered by default.

3 changes: 2 additions & 1 deletion config.js
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
exports.Config = {
workspace: ".",
ip: "127.0.0.1",
port: 3000
port: 3000,
gaeLocalPath: ".",
};
Original file line number Diff line number Diff line change
Expand Up @@ -33,6 +33,9 @@ sys.inherits(DebuggerPlugin, Plugin);
this.CHROME_DEBUG_PORT = 9222;

this.command = function(user, message, client) {
if (!(/js/.test(message.runner)))
return false;

var _self = this;

var cmd = (message.command || "").toLowerCase(),
Expand All @@ -47,7 +50,7 @@ sys.inherits(DebuggerPlugin, Plugin);
message.preArgs = ["--debug=" + _self.NODE_DEBUG_PORT];
message.debug = true;
_self.$run(message, client);

setTimeout(function() {
_self.$startDebug();
}, 100);
Expand All @@ -56,11 +59,11 @@ sys.inherits(DebuggerPlugin, Plugin);
case "rundebugbrk":
netutil.findFreePort(this.NODE_DEBUG_PORT, "localhost", function(port) {
_self.NODE_DEBUG_PORT = port;

message.preArgs = ["--debug-brk=" + _self.NODE_DEBUG_PORT];
message.debug = true;
_self.$run(message, client);

setTimeout(function() {
_self.$startDebug();
}, 100);
Expand Down Expand Up @@ -121,22 +124,18 @@ sys.inherits(DebuggerPlugin, Plugin);
return _self.ide.error("Child process already running!", 1, message);

var file = _self.ide.workspaceDir + "/" + message.file;

Path.exists(file, function(exists) {
if (!exists)
return _self.ide.error("File does not exist: " + message.file, 2, message);

var cwd = _self.ide.workspaceDir + "/" + (message.cwd || "");
Path.exists(cwd, function(exists) {
if (!exists)
return _self.ide.error("cwd does not exist: " + message.cwd, 3, message);
// lets check what we need to run
if(file.match(/\.js$/)){
var args = (message.preArgs || []).concat(file).concat(message.args || []);
_self.$runProc(_self.ide.nodeCmd, args, cwd, message.env || {}, message.debug || false);
} else {
_self.$runProc(file, message.args||[], cwd, message.env || {}, false);
}
var args = (message.preArgs || []).concat(file).concat(message.args || []);
_self.$runProc(_self.ide.nodeCmd, args, cwd, message.env || {}, message.debug || false);
});
});
};
Expand All @@ -150,7 +149,7 @@ sys.inherits(DebuggerPlugin, Plugin);
env[key] = process.env[key];
}

console.log("Executing node "+proc+" "+args.join(" ")+" "+cwd);
console.log("Executing node "+proc+" "+args.join(" ")+" "+cwd);

var child = _self.child = Spawn(proc, args, {cwd: cwd, env: env});
_self.debugClient = args.join(" ").search(/(?:^|\b)\-\-debug\b/) != -1;
Expand Down Expand Up @@ -212,10 +211,10 @@ sys.inherits(DebuggerPlugin, Plugin);

this.nodeDebugProxy.connect();
};

this.dispose = function(callback) {
this.$kill();
callback();
};

}).call(DebuggerPlugin.prototype);
File renamed without changes.
137 changes: 137 additions & 0 deletions server/cloud9/ext/run-python/index.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,137 @@
/**
* Debugger Module for the Cloud9 IDE
*
* @copyright 2010, Ajax.org B.V.
* @license GPLv3 <http://www.gnu.org/licenses/gpl.txt>
*/
var Path = require("path"),
Spawn = require("child_process").spawn,
Plugin = require("cloud9/plugin"),
sys = require("sys"),
netutil = require("cloud9/netutil");

var PythonRuntimePlugin = module.exports = function(ide) {
this.ide = ide;
this.hooks = ["command"];
this.name = "debugger";
};

sys.inherits(PythonRuntimePlugin, Plugin);

(function() {
this.init = function() {
var _self = this;
this.ide.getExt("state").on("statechange", function(state) {
state.processRunning = !!_self.child;
});
};

this.PYTHON_DEBUG_PORT = 7984;

this.command = function(user, message, client) {
if (!(/py/.test(message.runner)))
return false;

var _self = this;

var cmd = (message.command || "").toLowerCase(),
res = true;
switch (cmd) {
case "run": case "rundebug": case "rundebugbrk": // We don't debug python just yet.
this.$run(message, client);
break;
case "kill":
this.$kill();
break;
default:
res = false;
break;
}
return res;
};

this.$kill = function() {
var child = this.child;
if (!child)
return;
try {
child.kill();
// check after 2sec if the process is really dead
// If not kill it harder
setTimeout(function() {
if (child.pid > 0)
child.kill("SIGKILL");
}, 2000)
}
catch(e) {}
};

this.$run = function(message, client) {
var _self = this;

if (this.child)
return _self.ide.error("Child process already running!", 1, message);

var file = _self.ide.workspaceDir + "/" + message.file;

Path.exists(file, function(exists) {
if (!exists)
return _self.ide.error("File does not exist: " + message.file, 2, message);

var cwd = _self.ide.workspaceDir + "/" + (message.cwd || "");
Path.exists(cwd, function(exists) {
if (!exists)
return _self.ide.error("cwd does not exist: " + message.cwd, 3, message);
// lets check what we need to run
var args = [].concat(file).concat(message.args || []);
_self.$runProc('python', args, cwd, message.env || {}, message.debug || false);
});
});
};

this.$runProc = function(proc, args, cwd, env, debug) {
var _self = this;

// mixin process env
for (var key in process.env) {
if (!(key in env))
env[key] = process.env[key];
}

console.log("Executing "+proc+" "+args.join(" ")+" "+cwd);

var child = _self.child = Spawn(proc, args, {cwd: cwd, env: env});
_self.debugClient = args.join(" ").search(/(?:^|\b)\-\-debug\b/) != -1;
_self.ide.getExt("state").publishState();
_self.ide.broadcast(JSON.stringify({"type": "node-start"}), _self.name);

child.stdout.on("data", sender("stdout"));
child.stderr.on("data", sender("stderr"));

function sender(stream) {
return function(data) {
var message = {
"type": "node-data",
"stream": stream,
"data": data.toString("utf8")
};
_self.ide.broadcast(JSON.stringify(message), _self.name);
};
}

child.on("exit", function(code) {
_self.ide.broadcast(JSON.stringify({"type": "node-exit"}), _self.name);

_self.debugClient = false;
delete _self.child;
});

return child;
};

this.dispose = function(callback) {
this.$kill();
callback();
};

}).call(PythonRuntimePlugin.prototype);
6 changes: 6 additions & 0 deletions server/cloud9/ext/run-python/package.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,6 @@
{
"name": "python_runtime",
"description": "Provides a Python runtime and debugger, both on the local machine and remote App Engine.",
"version": "0.1",
"author": "Ajax.org B.V. <[email protected]>"
}
5 changes: 4 additions & 1 deletion server/cloud9/ide.js
Original file line number Diff line number Diff line change
Expand Up @@ -46,6 +46,7 @@ module.exports = Ide = function(options, httpServer, exts, socket) {
plugins: options.plugins || Ide.DEFAULT_PLUGINS,
requirejsConfig: requirejsConfig,
offlineManifest: options.offlineManifest || "",
gaeLocalPath: options.gaeLocalPath,
projectName: options.projectName || this.workspaceDir.split("/").pop(),
version: options.version,
extra: options.extra
Expand All @@ -63,6 +64,8 @@ module.exports = Ide = function(options, httpServer, exts, socket) {

sys.inherits(Ide, EventEmitter);

Ide.GAE_LOCAL_PATH = null;

Ide.DEFAULT_PLUGINS = [
"ext/filesystem/filesystem",
"ext/settings/settings",
Expand Down Expand Up @@ -265,7 +268,7 @@ Ide.DEFAULT_PLUGINS = [
this.broadcast = function(msg, scope) {
// TODO check permissions
for (var username in this.$users) {
var user = this.$users[username];
var user = this.$users[username];
user.broadcast(msg, scope);
}
};
Expand Down

0 comments on commit 7710a21

Please sign in to comment.