Merge remote-tracking branch 'origin/master' into clone-workspaces

This commit is contained in:
Tim Robinson 2015-05-03 15:01:36 +00:00
commit 3ef354bc71
37 changed files with 856 additions and 282 deletions

View File

@ -119,7 +119,8 @@ return [
local: true,
home: process.env.HOME,
setStatus: function(){},
location: ""
location: "",
platform: process.platform,
},
error_handler: {
log: function(){}

View File

@ -98,7 +98,7 @@ module.exports = function(options) {
packagePath: "plugins/c9.ide.plugins/debug"
},
{
packagePath: "plugins/c9.ide.plugins/market"
packagePath: "plugins/c9.ide.plugins/packages"
},
{
packagePath: "plugins/c9.ide.plugins/test",
@ -618,7 +618,6 @@ module.exports = function(options) {
},
{
packagePath: "plugins/c9.cli.bridge/bridge",
port: 17123,
startBridge: options.startBridge
},
{

2
node_modules/vfs-child/parent.js generated vendored
View File

@ -15,7 +15,7 @@ function Parent(fsOptions) {
options.uid = fsOptions.uid;
delete fsOptions.uid;
}
options.customFds = [-1, -1, 2];
options.stdio = options.customFds = [-1, -1, 2];
var args = [require.resolve('./child.js'), JSON.stringify(fsOptions)];
var executablePath = process.execPath;
var child;

15
node_modules/vfs-local/localfs.js generated vendored
View File

@ -1828,8 +1828,13 @@ module.exports = function setup(fsOptions) {
if (options.idle)
options.command = "echo '[Idle]'";
if (options.terminal)
args.push("export ISOUTPUTPANE=0;" + BASH + " -l");
if (options.terminal) {
args.push("export ISOUTPUTPANE=0;"
+ (options.defaultEditor
? " export EDITOR='`which c9` open --wait'; "
: "")
+ BASH + " -l");
}
else if (options.command)
args.push((BASH + " -l -c '"
@ -2334,6 +2339,9 @@ module.exports = function setup(fsOptions) {
err.code = "EEXIST";
return callback(err, { api: apis[name] });
}
if (options.redefine && apis[name] && apis[name].destroy)
apis[name].destroy();
var fn;
@ -2394,6 +2402,9 @@ module.exports = function setup(fsOptions) {
}
function unextend(name, options, callback) {
if (apis[name] && apis[name].destroy)
apis[name].destroy();
delete apis[name];
callback(null, {});
}

15
node_modules/vfs-socket/worker.js generated vendored
View File

@ -162,6 +162,9 @@ function Worker(vfs) {
var nextStreamID = 1;
function storeStream(stream) {
if (stream.token)
return stream.token;
nextStreamID = (nextStreamID + 1) % 10000;
while (streams.hasOwnProperty(nextStreamID)) { nextStreamID = (nextStreamID + 1) % 10000; }
var id = nextStreamID;
@ -188,6 +191,7 @@ function Worker(vfs) {
remote.onClose(id);
});
var token = {id: id};
stream.token = token;
if (stream.hasOwnProperty("readable")) token.readable = stream.readable;
if (stream.hasOwnProperty("writable")) token.writable = stream.writable;
return token;
@ -195,6 +199,9 @@ function Worker(vfs) {
function storeProcess(process, onlyPid) {
var pid = process.pid;
if (processes.token)
return onlyPid ? process.pid : process.token;
processes[pid] = process;
process.on("exit", function (code, signal) {
delete processes[pid];
@ -215,11 +222,13 @@ function Worker(vfs) {
code: code
}, callback || function() {});
};
var token = {pid: pid};
process.token = token;
if (onlyPid)
return pid;
var token = {pid: pid};
token.stdin = storeStream(process.stdin);
token.stdout = storeStream(process.stdout);
token.stderr = storeStream(process.stderr);
@ -230,8 +239,8 @@ function Worker(vfs) {
if (!pty || processes[pty.pid] == pty) // Pty is returned twice
return pty && pty.token;
var pid = storeProcess(pty, true);
var token = storeStream(pty);
var pid = storeProcess(pty, true); delete pty.token;
var token = storeStream(pty); delete pty.token;
token.pid = pid;
pty.token = token;

View File

@ -82,7 +82,7 @@
"c9.ide.help.support": "#60e88f5680",
"c9.ide.imgeditor": "#08bbc53578",
"c9.ide.immediate": "#6845a93705",
"c9.ide.installer": "#a1e01c07a3",
"c9.ide.installer": "#6f8f44c9e1",
"c9.ide.mount": "#32e79866ee",
"c9.ide.navigate": "#64156c7f4a",
"c9.ide.newresource": "#f1f0624768",

View File

@ -5,7 +5,7 @@
*/
define(function(require, exports, module) {
main.consumes = ["c9", "Plugin", "net"];
main.provides = ["bridge-client"];
main.provides = ["bridge.client"];
return main;
function main(options, imports, register) {
@ -13,27 +13,61 @@ define(function(require, exports, module) {
var c9 = imports.c9;
var net = imports.net;
var JSONStream = require("./json-stream");
/***** Initialization *****/
var plugin = new Plugin("Ajax.org", main.consumes);
// var emit = plugin.getEmitter();
var PORT = options.port || 17123;
var counter = 0;
var SOCKET = c9.platform == "win32"
? "\\\\.\\pipe\\.c9\\bridge.socket"
: c9.home + "/.c9/bridge.socket";
/***** Methods *****/
function send(message, callback) {
net.connect(PORT, {}, function(err, stream) {
net.connect(SOCKET, {}, function(err, stream) {
if (err)
return callback(err);
stream.write(JSON.stringify(message));
stream.end();
var jstream = new JSONStream(stream);
var msgId = generateMessageId();
var done;
callback();
jstream.write({
id: msgId,
message: message
});
jstream.on("data", function(payload){
if (payload.id == msgId && !done) {
done = true;
callback(null, payload.message);
stream.end();
}
});
jstream.on("error", function(err){
if (done) return;
callback(err);
done = true;
});
jstream.on("close", function(){
if (done) return;
callback(new Error("No Response"));
done = true;
})
});
}
function generateMessageId(){
// Use vfs token
return Math.random() + "-" + ++counter;
}
/***** Lifecycle *****/
plugin.on("load", function(){
@ -55,7 +89,7 @@ define(function(require, exports, module) {
});
register(null, {
"bridge-client": plugin
"bridge.client": plugin
});
}
});

View File

@ -1,37 +1,128 @@
module.exports = function (vfs, options, register) {
var stream;
var net = require("net");
var Stream = require('stream');
var stream, server;
var SOCKET = process.platform == "win32"
? "\\\\.\\pipe\\.c9\\bridge.socket"
: process.env.HOME + "/.c9/bridge.socket";
function createListenClient(api){
var client = net.connect(SOCKET, function(data){
if (data) api.onData(data);
});
client.setEncoding("utf8");
client.unref();
client.on("data", function(data){
if (data) api.onData(data);
});
client.on("error", function(err){
if (err.code == "ECONNREFUSED") {
require("fs").unlink(SOCKET, function(){
createListenServer(api);
});
}
else if (err.code == "ENOENT") {
createListenServer(api);
}
else
api.onError(err);
});
client.on("end", function(){
createListenServer(api);
});
api.onConnect(client);
api.disconnect = function(){
client.end();
};
return client;
}
function createListenServer(api){
// var timeout = setTimeout(function(){
// unixServer.close();
// }, 500);
var unixServer = net.createServer(function(client) {
client.setEncoding("utf8");
client.on("data", function(data){
if (data) api.onData(data);
});
client.on("error", function(data){
// console.error("ERROR", api.id, data);
});
api.onConnect(client);
});
unixServer.listen(SOCKET);
unixServer.on("error", function(err){
if (err.code == "EADDRINUSE") {
createListenClient(api);
}
else
api.onError(err);
});
api.disconnect = function(){
unixServer.close();
};
}
register(null, {
connect: function (port, callback) {
connect: function (callback) {
if (stream) return callback(null, { stream: stream });
server = require('net').createServer(function(c) {
var buffer = "";
c.on("data", function(chunk) {
buffer += chunk;
});
c.on("end", function(){
stream.emit("data", buffer);
});
});
server.on("error", function(err) {
callback(err);
});
server.listen(port, process.env.OPENSHIFT_DIY_IP || "localhost", function(err) {
if (err) return callback(err);
callback(null, { stream: stream });
});
stream = new Stream();
stream.readable = true;
stream.writable = true;
var client;
var sent = false;
var api = this.api = {
id: Math.random(),
onConnect: function(c){
client = c;
if (sent) return;
callback(null, { stream: stream });
sent = true;
},
onData: function(data){
stream && stream.emit("data", data);
},
onError: function(err){
stream && stream.emit("error", err);
}
};
// createListenServer
createListenClient(api);
stream.write = function(data){
if (client) client.write(data);
};
},
disconnect: function(){
try { server && server.close(); }
try { this.api && this.api.disconnect(); }
catch (e) {}
stream = null;
server = null;
delete this.api;
},
destroy: function(){
this.disconnect();
}
});
};

View File

@ -1,4 +1,3 @@
define(function(require, exports, module) {
main.consumes = ["c9", "Plugin", "ext"];
main.provides = ["bridge"];
@ -8,6 +7,8 @@ define(function(require, exports, module) {
var Plugin = imports.Plugin;
var c9 = imports.c9;
var ext = imports.ext;
var JSONStream = require("./json-stream");
/***** Initialization *****/
@ -15,15 +16,10 @@ define(function(require, exports, module) {
var emit = plugin.getEmitter();
var ENABLED = options.startBridge !== false;
var PORT = options.port || 17123;
var stream, api;
var loaded = false;
function load(){
if (loaded) return;
loaded = true;
if (!ENABLED) return;
ext.loadRemotePlugin("bridge", {
@ -35,58 +31,62 @@ define(function(require, exports, module) {
api = remote;
api.connect(PORT, function(err, meta) {
if (err) {
loaded = false;
api.connect(function(err, meta) {
if (err)
return console.error(err); // this should never happen
if (err.code == "EADDRINUSE") {
console.warn("Another Application is using port "
+ PORT + ". CLI client interface disabled. Restart Cloud9 to retry connecting.");
}
else
console.error(err);
return;
}
stream = meta.stream;
stream.on("data", function(chunk) {
try { var message = JSON.parse(chunk); }
catch (e) {
setTimeout(function(){
loaded = false;
load();
}, 60000);
return;
}
emit("message", { message: message });
stream = new JSONStream(meta.stream);
stream.on("error", function(err) {
console.error(err);
});
stream.on("data", function(payload) {
emit("message", {
message: payload.message,
respond: function(err, message){
stream.write({
id: payload.id,
message: message,
error: err
});
}
});
});
stream.on("close", function(){
loaded = false;
load();
});
emit.sticky("ready");
});
});
window.addEventListener("unload", unload);
window.addEventListener("unload", function(){
api && api.disconnect();
});
}
function unload() {
api && api.disconnect();
api = stream = null;
loaded = false;
function write(json){
if (!stream) {
plugin.once("ready", function(){ write(json); });
return;
}
stream.write(json);
}
/***** Methods *****/
plugin.on("load", function(){
c9.on("connect", load, plugin);
c9.on("disconnect", unload, plugin);
});
plugin.on("unload", function(){
api && api.disconnect();
stream = null;
api = null;
});
/***** Register and define API *****/
@ -94,7 +94,12 @@ define(function(require, exports, module) {
/**
* Bridge To Communicate from CLI to IDE
**/
plugin.freezePublicAPI({ });
plugin.freezePublicAPI({
/**
*
*/
write: write
});
register(null, {
bridge: plugin

View File

@ -1,20 +1,25 @@
define(function(require, exports, module) {
main.consumes = [
"Plugin", "bridge", "tabManager", "panels",
"tree.favorites", "tree", "fs"
"Plugin", "bridge", "tabManager", "panels", "tree.favorites", "tree",
"fs", "preferences", "settings", "c9"
];
main.provides = ["bridge_commands"];
main.provides = ["bridge.commands"];
return main;
function main(options, imports, register) {
var Plugin = imports.Plugin;
var bridge = imports.bridge;
var tabs = imports.tabManager;
var tabManager = imports.tabManager;
var panels = imports.panels;
var tree = imports.tree;
var settings = imports.settings;
var favs = imports["tree.favorites"];
var fs = imports.fs;
var c9 = imports.c9;
var prefs = imports.preferences;
var async = require("async");
/***** Initialization *****/
@ -23,36 +28,62 @@ define(function(require, exports, module) {
var BASEPATH = options.basePath;
var loaded = false;
function load(){
if (loaded) return;
loaded = true;
bridge.on("message", function(e) {
var message = e.message;
switch (message.type) {
case "open":
open(message);
open(message, e.respond);
break;
case "ping":
e.respond(null, true);
break;
default:
console.error("Unknown Bridge Command: ", message.type);
break;
}
});
}, plugin);
settings.on("read", function(e) {
settings.setDefaults("user/terminal", [
["defaultEditor", "true"]
]);
}, plugin);
prefs.add({
"Editors" : {
"Terminal" : {
"Use Cloud9 as the Default Editor" : {
type: "checkbox",
path: "user/terminal/@defaultEditor",
position: 14000
}
}
}
}, plugin);
}
/***** Methods *****/
function open(message) {
message.paths.forEach(function(info, i) {
function open(message, callback) {
var i = -1;
var tabs = [];
BASEPATH = c9.toInternalPath(BASEPATH);
async.each(message.paths, function(info, next) {
var path = info.path;
i++;
path = c9.toInternalPath(path);
// Make sure file is inside workspace
if (path.substr(0, BASEPATH.length) !== BASEPATH)
return;
// Remove base path
path = path.substr(BASEPATH.length);
if (path.charAt(0) !== "~") {
if (path.substr(0, BASEPATH.length) !== BASEPATH)
return; // Dont' call callback. Perhaps another client will pick this up.
// Remove base path
path = path.substr(BASEPATH.length);
}
if (info.type == "directory") {
path = path.replace(/\/$/, "");
@ -61,26 +92,45 @@ define(function(require, exports, module) {
var node = favs.addFavorite(path);
tree.expand(path, function(err) {
tree.expand(path, function() {
tree.select(node); //path || "/");
tree.scrollToSelection();
next();
});
tree.focus();
}
else {
tabs.once("ready", function(){
tabManager.once("ready", function(){
fs.exists(path, function(existing) {
tabs.open({
var tab = tabManager.open({
path: path,
active: i === 0,
document:
existing
? undefined
: { meta : { newfile: true } }
}, function(){});
}, function(){
next();
});
if (message.wait) {
tab.on("close", function(){
tabs.splice(tabs.indexOf(tab), 1);
if (!tabs.length)
callback(null, true);
});
}
tabs.push(tab);
});
});
}
}, function(err){
if (err)
return callback(err);
if (!message.wait || !tabs.length)
callback(null, true);
});
}
@ -102,7 +152,7 @@ define(function(require, exports, module) {
plugin.freezePublicAPI({});
register(null, {
"bridge_commands": plugin
"bridge.commands": plugin
});
}
});

View File

@ -2,7 +2,7 @@
"use client";
require(["lib/architect/architect", "lib/chai/chai"], function (architect, chai) {
require(["lib/architect/architect", "lib/chai/chai", "/vfs-root", "/vfs-home"], function (architect, chai, basePath, homePath) {
var expect = chai.expect;
var Assert = chai.assert;
@ -14,46 +14,70 @@ require(["lib/architect/architect", "lib/chai/chai"], function (architect, chai)
debug: true,
hosted: true,
local: false,
davPrefix: "/"
davPrefix: "/",
home: homePath
},
"plugins/c9.core/ext",
"plugins/c9.core/http-xhr",
"plugins/c9.core/util",
"plugins/c9.ide.ui/lib_apf",
"plugins/c9.ide.ui/ui",
"plugins/c9.core/settings",
//"plugins/c9.ide.collab/collab",
"plugins/c9.vfs.client/vfs_client",
"plugins/c9.vfs.client/endpoint",
"plugins/c9.ide.auth/auth",
"plugins/c9.fs/fs",
"plugins/c9.fs/net",
{
packagePath: "plugins/c9.cli.bridge/bridge",
startBridge: true
},
{
packagePath: "plugins/c9.cli.bridge/bridge_commands",
basePath: basePath
},
"plugins/c9.cli.bridge/bridge-client",
// Mock plugins
{
consumes: ["ui"],
consumes: [],
provides: [
"preferences", "dialog.error"
"preferences", "ui"
],
setup: expect.html.mocked
},
{
consumes: ["collab"],
consumes: ["bridge", "bridge.client"],
provides: [],
setup: main
}
], architect);
function main(options, imports, register) {
var collab = imports.collab;
var bridge = imports.bridge;
var client = imports["bridge.client"];
describe('collab', function() {
this.timeout(10000);
describe('bridge', function() {
// this.timeout(10000);
describe("connect", function(){
it('should connect', function(done) {
collab.connect(null, function(err, stream) {
if (err) throw err.message;
});
before(function(done){
bridge.on("ready", function(){
done();
});
});
it('send and receive messages', function(done) {
bridge.on("message", function(e){
if (e.message.hello) {
e.respond(null, { "hi": true });
}
});
client.send({ "hello": true }, function(err, message){
if (err) throw err.message;
expect(message).property("hi").to.be.ok;
done();
});
});
});

View File

@ -0,0 +1,47 @@
define(function(require, exports, module) {
var EventEmitter = require("events").EventEmitter;
module.exports = function(stream) {
var emit = this.emit.bind(this);
var buffer = "";
stream.on("data", function(chunk) {
buffer += chunk;
var parts = buffer.split("\n");
while (parts.length) {
try {
var message = JSON.parse(parts[0]);
emit("data", message);
parts.shift();
}
catch (e) {
if (parts.length !== 1) {
emit("error", e);
parts.shift();
}
else {
break;
}
}
}
buffer = parts.join("\n");
});
stream.on("error", function(err){
emit("error", err);
});
stream.on("close", function(data){
emit("close", data);
});
this.write = function(data) {
stream.write(JSON.stringify(data) + "\n");
};
};
module.exports.prototype = new EventEmitter();
});

View File

@ -1,5 +1,5 @@
define(function(require, exports, module) {
main.consumes = ["Plugin", "cli_commands", "proc", "bridge-client"];
main.consumes = ["Plugin", "cli_commands", "proc", "bridge.client"];
main.provides = ["open"];
return main;
@ -7,7 +7,7 @@ define(function(require, exports, module) {
var Plugin = imports.Plugin;
var cmd = imports.cli_commands;
var proc = imports.proc;
var bridge = imports["bridge-client"];
var bridge = imports["bridge.client"];
var fs = require("fs");
var PATH = require("path");
@ -25,11 +25,12 @@ define(function(require, exports, module) {
cmd.addCommand({
name: "open",
info: " Opens a file or directory.",
usage: "<path>",
usage: "[--wait] <path>",
options: {
"path" : {
description: "Specify the path that will be opened",
default: false
"wait": {
description: "Wait until the file(s) are closed",
"default": false,
"boolean": true
}
},
check: function(argv) {
@ -39,6 +40,7 @@ define(function(require, exports, module) {
exec: function(argv) {
open(
argv._.slice(1), // Remove "open" from the paths
argv.wait,
function(){});
}
});
@ -46,12 +48,16 @@ define(function(require, exports, module) {
/***** Methods *****/
function open(paths, callback) {
function open(paths, wait, callback) {
try {
paths = paths.map(function(path) {
var isDir = fs.existsSync(path) && fs.statSync(path).isDirectory();
path = PATH.resolve(path);
if (path.substr(0, process.env.HOME.length) == process.env.HOME)
path = "~" + path.substr(process.env.HOME.length);
return {
path: "/" + PATH.resolve(path),
path: path,
type: isDir ? "directory" : "file"
};
});
@ -65,6 +71,7 @@ define(function(require, exports, module) {
paths.forEach(function(info) {
var path = info.type == "directory"
? info.path : PATH.dirname(info.path);
if (!last) {
last = path;
}
@ -86,11 +93,12 @@ define(function(require, exports, module) {
var message = {
type: "open",
workspace: "local",
wait: wait,
// cwd : cwd,
paths: paths
};
bridge.send(message, function cb(err) {
bridge.send(message, function cb(err, response) {
if (err) {
if (err.code == "ECONNREFUSED") {
// Seems Cloud9 is not running, lets start it up
@ -111,6 +119,9 @@ define(function(require, exports, module) {
console.log(err.message);
}
if (response !== true)
console.log("Could not open ", paths);
process.exit(); // I don't get why this is needed
});
}
@ -129,13 +140,16 @@ define(function(require, exports, module) {
var timed = Date.now();
(function retry(){
bridge.send({ type: "ping" }, function(err) {
bridge.send({ type: "ping" }, function(err, message) {
if (!err)
return callback(true);
if (Date.now() - timed > 10000)
return callback(false);
if (message !== true)
return callback(false);
setTimeout(retry, 100);
});
})();

View File

@ -140,6 +140,7 @@ define(function(require, exports, module) {
cmd.addCommand({
name: "remove",
alias: "uninstall",
info: " Removes a cloud9 package.",
usage: "[--verbose] [--global] [--local] <package>", // @TODO --global
options: {
@ -387,8 +388,8 @@ define(function(require, exports, module) {
if (verbose)
console.log("Installing debug version of package");
if (!options.test)
return callback(new Error("Dry run is not supported for debug installations"));
if (options.test)
return callback(new Error("Test is not supported for debug installations"));
prepareDirectory(function(err, packagePath){
if (err) return callback(err);

View File

@ -88,8 +88,7 @@ define(function(require, exports, module) {
}
},
check: function(argv) {
// if (argv._.length < 2 && !argv["newversion"] && !argv["dry-run"])
// throw new Error("Missing version");
},
exec: function(argv) {
verbose = argv["verbose"];
@ -438,9 +437,9 @@ define(function(require, exports, module) {
var path = join(cwd, json.installer);
var installerCode = fs.readFileSync(path, "utf8");
var m = installerCode.match(/\.version\s*=\s*(\d+)/g);
var m = installerCode.match(/\.version\s*=\s*(\d+)/);
var installerVersion = m && m[0];
var installerVersion = m && m[1];
if (!installerVersion)
return callback(new Error("ERROR: missing installer version in " + json.installer));
extraCode.push({

View File

@ -7,6 +7,9 @@ define(function(require, exports, module) {
var Plugin = imports.Plugin;
var cmd = imports.cli_commands;
var fs = require("fs");
var resolve = require("path").resolve;
var optimist;
/***** Initialization *****/
@ -21,7 +24,7 @@ define(function(require, exports, module) {
var module;
var argv;
process.argv.slice(2).some(function(n){
process.argv.slice(2).some(function(n) {
if (!n.match(/^[-\/]/) && n != "node") {
module = n;
return true;
@ -29,6 +32,18 @@ define(function(require, exports, module) {
return false;
});
if (!commands[module] && process.argv.length > 2) {
for (var i = 2; i < process.argv.length; i++) {
if (process.argv[i].charAt(0) == "-") continue;
var path = resolve(process.argv[i]);
if (fs.existsSync(path)) {
process.argv.splice(2, 0, "open");
module = "open";
}
break;
}
}
optimist = require('optimist');
if (!module || !commands[module]) {
@ -62,6 +77,12 @@ define(function(require, exports, module) {
argv = optimist
.usage("The Cloud9 CLI.\nUsage: c9 " + module + " [--help] " + def.usage)
.options(def.options);
if (argv.argv.help)
argv = argv.check(function(){
if (argv.help)
throw new Error("Help Requested");
});
if (def.check)
argv = argv.check(def.check);
argv = argv.argv;

View File

@ -1,6 +1,6 @@
define(function(require, exports, module) {
main.consumes = [
"Plugin", "proc", "c9", "pubsub", "auth", "util"
"Plugin", "proc", "c9", "pubsub", "auth", "util", "installer"
];
main.provides = ["plugin.installer"];
return main;
@ -12,6 +12,9 @@ define(function(require, exports, module) {
var proc = imports.proc;
var auth = imports.auth;
var pubsub = imports.pubsub;
var installer = imports.installer;
var async = require("async");
var escapeShell = util.escapeShell;
var updates = options.updates;
@ -20,11 +23,10 @@ define(function(require, exports, module) {
/***** Initialization *****/
var plugin = new Plugin("Ajax.org", main.consumes);
// var emit = plugin.getEmitter();
var emit = plugin.getEmitter();
var HASSDK = c9.location.indexOf("sdk=0") === -1;
var queue = [];
var installing;
var loaded = false;
@ -69,87 +71,66 @@ define(function(require, exports, module) {
// return;
// }
if (!config.length) return;
if (!config.length)
return callback && callback();
var found = {};
config.forEach(function(item){
if (!found[item.packageName])
found[item.packageName] = true;
else return;
queue.push({ name: item.packageName, version: item.version });
if (installing)
installing.push(item);
});
if (installing) return;
installing = config;
var i = 0;
function next(err){
if (err) console.log(err);
if (!queue[i]) {
installing = false; queue = [];
architect.loadAdditionalPlugins(config, callback);
return;
}
installPlugin(queue[i].name, queue[i].version, next);
i++;
// Only run one installer at a time
if (installing) {
return plugin.once("finished", function(){
installPlugins(config, callback);
});
}
next();
installing = true;
var found = {}, packages = [];
config.forEach(function(item){
if (!found[item.name])
found[item.name] = true;
else return;
packages.push({ name: item.name, version: item.version });
});
async.eachSeries(packages, function(pkg, next){
installPlugin(pkg.name, pkg.version, next);
}, function(err){
installing = false;
emit("finished");
if (err) {
console.error(err.message);
return callback && callback(err);
}
architect.loadAdditionalPlugins(config, callback);
});
}
function installPlugin(name, version, callback){
proc.spawn("bash", {
args: ["-c", ["c9", "install", "--local", "--force", "--accessToken=" + auth.accessToken, escapeShell(name) + "@" + escapeShell(version)].join(" ")]
}, function(err, process){
if (err) return callback(err);
process.stdout.on("data", function(c){
console.log(c);
});
process.stderr.on("data", function(c){
console.error(c);
// Headless installation of the plugin
installer.createSession(name, version, function(session, options){
session.install({
"bash": "c9 install --local --force --accessToken=" + auth.accessToken
+ " " + escapeShell(name) + "@" + escapeShell(version)
});
process.on("exit", function(code){
if (code) {
var error = new Error(err);
error.code = code;
return callback(error);
}
callback();
});
});
// Force to start immediately
session.start(callback, true);
}, function(){}, 2); // Force to not be administered
}
function uninstallPlugin(name, callback){
proc.spawn("c9", {
args: ["remove", "--local", "--force", "--accessToken=" + auth.accessToken, escapeShell(name)]
}, function(err, process){
if (err) return callback(err);
var res = null;
process.stdout.on("data", function(c){
res = c.toString("utf8");
});
process.stderr.on("data", function(c){
err = c.toString("utf8");
// Headless uninstallation of the plugin
installer.createSession(name, -1, function(session, options){
session.install({
"bash": "c9 remove --local --force --accessToken=" + auth.accessToken
+ " " + escapeShell(name)
});
process.on("exit", function(code){
if (code) {
var error = new Error(err);
error.code = code;
return callback(error);
}
callback(null, res);
});
});
// Force to start immediately
session.start(callback, true);
}, function(){}, 2); // Force to not be administered
}
/***** Lifecycle *****/
@ -160,7 +141,6 @@ define(function(require, exports, module) {
plugin.on("unload", function() {
loaded = false;
installing = false;
queue = [];
});
/***** Register and define API *****/
@ -180,6 +160,11 @@ define(function(require, exports, module) {
*/
installPlugins: installPlugins,
/**
*
*/
installPlugin: installPlugin,
/**
*
*/

View File

@ -85,7 +85,9 @@ define(function(require, exports, module) {
};
var TEMPLATES = {
"plugin.simple": "Empty Plugin",
"plugin.default": "Full Plugin"
"plugin.default": "Full Plugin",
"plugin.installer": "Installer Plugin",
"plugin.bundle": "Cloud9 Bundle"
};
// @TODO add sorting
@ -102,7 +104,6 @@ define(function(require, exports, module) {
// var emit = plugin.getEmitter();
var HASSDK = c9.location.indexOf("sdk=0") === -1;
var ENABLED = c9.location.indexOf("sdk=1") > -1;
var model, datagrid, filterbox;
var btnUninstall, btnReport, btnReadme, btnCloud9, btnReload;
@ -125,20 +126,18 @@ define(function(require, exports, module) {
// updateCommandsFromSettings();
// }, plugin);
if (ENABLED) {
menus.addItemByPath("File/New Plugin", null, 210, plugin);
Object.keys(TEMPLATES).forEach(function(name){
menus.addItemByPath("File/New Plugin/" + TEMPLATES[name], new ui.item({
onclick: function(){
createNewPlugin(name);
}
}), 210, plugin);
});
ext.on("register", function(){
setTimeout(reloadModel);
});
}
menus.addItemByPath("File/New Plugin", null, 210, plugin);
Object.keys(TEMPLATES).forEach(function(name){
menus.addItemByPath("File/New Plugin/" + TEMPLATES[name], new ui.item({
onclick: function(){
createNewPlugin(name);
}
}), 210, plugin);
});
ext.on("register", function(){
setTimeout(reloadModel);
});
}
var drawn;

View File

@ -0,0 +1 @@
<div class="helloworld">Hello World</div>

View File

@ -0,0 +1,155 @@
define(function(require, exports, module) {
main.consumes = [
"Plugin", "ui", "commands", "menus", "preferences", "settings"
];
main.provides = ["myplugin"];
return main;
function main(options, imports, register) {
var Plugin = imports.Plugin;
var ui = imports.ui;
var menus = imports.menus;
var commands = imports.commands;
var settings = imports.settings;
var prefs = imports.preferences;
/***** Initialization *****/
var plugin = new Plugin("Ajax.org", main.consumes);
var emit = plugin.getEmitter();
var showing;
function load() {
commands.addCommand({
name: "mycommand",
bindKey: { mac: "Command-I", win: "Ctrl-I" },
isAvailable: function(){ return true; },
exec: function() {
showing ? hide() : show();
}
}, plugin);
menus.addItemByPath("Tools/My Menu Item", new ui.item({
command: "mycommand"
}), 300, plugin);
settings.on("read", function(e){
settings.setDefaults("user/my-plugin", [
["first", "1"],
["second", "all"]
]);
});
prefs.add({
"Example" : {
position: 450,
"My Plugin" : {
position: 100,
"First Setting": {
type: "checkbox",
path: "user/my-plugin/@first",
position: 100
},
"Second Setting": {
type: "dropdown",
path: "user/my-plugin/@second",
width: "185",
position: 200,
items: [
{ value: "you", caption: "You" },
{ value: "me", caption: "Me" },
{ value: "all", caption: "All" }
]
}
}
}
}, plugin);
}
var drawn = false;
function draw() {
if (drawn) return;
drawn = true;
// Insert HTML
var markup = require("text!./plugin.html");
ui.insertHtml(document.body, markup, plugin);
// Insert CSS
ui.insertCss(require("text!./style.css"), options.staticPrefix, plugin);
emit("draw");
}
/***** Methods *****/
function show() {
draw();
var div = document.querySelector(".helloworld");
div.style.display = "block";
div.innerHTML = settings.get("user/my-plugin/@second");
emit("show");
showing = true;
}
function hide() {
if (!drawn) return;
document.querySelector(".helloworld").style.display = "none";
emit("hide");
showing = false;
}
/***** Lifecycle *****/
plugin.on("load", function() {
load();
});
plugin.on("unload", function() {
drawn = false;
showing = false;
});
/***** Register and define API *****/
/**
* This is an example of an implementation of a plugin.
* @singleton
*/
plugin.freezePublicAPI({
/**
* @property showing whether this plugin is being shown
*/
get showing(){ return showing; },
_events: [
/**
* @event show The plugin is shown
*/
"show",
/**
* @event hide The plugin is hidden
*/
"hide"
],
/**
* Show the plugin
*/
show: show,
/**
* Hide the plugin
*/
hide: hide,
});
register(null, {
"myplugin": plugin
});
}
});

View File

@ -0,0 +1,41 @@
"use client";
"use mocha";
define(function(require, exports, module) {
main.consumes = ["plugin.test", "myplugin"];
main.provides = [];
return main;
function main(options, imports, register) {
var test = imports["plugin.test"];
var myplugin = imports.myplugin;
var describe = test.describe;
var it = test.it;
var before = test.before;
var after = test.after;
var beforeEach = test.beforeEach;
var afterEach = test.afterEach;
var assert = test.assert;
var expect = test.expect;
/***** Initialization *****/
describe(myplugin.name, function(){
this.timeout(2000);
it("shows a helloworld div", function() {
myplugin.show();
expect(document.querySelector(".helloworld")).to.ok;
expect(document.querySelector(".helloworld").innerText).to.equal("all");
});
it("hides the div", function() {
myplugin.hide();
expect(document.querySelector(".helloworld").offsetHeight).to.not.ok;
});
});
register(null, {});
}
});

View File

@ -3,7 +3,7 @@ define(function(require, exports, module) {
"Editor", "editors", "ui", "commands", "menus", "layout",
"tabManager", "util", "settings", "api", "c9"
];
main.provides = ["plugin.market"];
main.provides = ["plugin.packages"];
return main;
function main(options, imports, register) {
@ -24,17 +24,17 @@ define(function(require, exports, module) {
var extensions = [];
var packages = {};
var handle = editors.register("plugin.market", "Market Place",
MarketPlace, extensions);
var handle = editors.register("plugin.packages", "Package Browser",
PackageBrowser, extensions);
var emit = handle.getEmitter();
emit.setMaxListeners(1000);
var HASSDK = c9.location.indexOf("sdk=1") > -1;
var HASSDK = c9.location.indexOf("sdk=0") === -1;
function focusOpenMarket(){
function focusOpenPackages(){
var pages = tabs.getTabs();
for (var i = 0, tab = pages[i]; tab; tab = pages[i++]) {
if (tab.editorType == "plugin.market") {
if (tab.editorType == "plugin.packages") {
tabs.focusTab(tab);
return true;
}
@ -49,29 +49,30 @@ define(function(require, exports, module) {
});
commands.addCommand({
name: "openmarketplace",
hint: "open the market place",
name: "openpackagebrowser",
hint: "open the package browser",
group: "General",
// bindKey: { mac: "Command-,", win: "Ctrl-," },
exec: function () {
var tab = tabs.focussedTab;
if (tab && tab.editor.type == "plugin.market") {
if (tab && tab.editor.type == "plugin.packages") {
tab.close();
return;
}
if (focusOpenMarket())
if (focusOpenPackages())
return;
tabs.open({
editorType: "plugin.market",
editorType: "plugin.packages",
active: true
}, function(){});
}
}, handle);
menus.addItemByPath("Cloud9/Plugin Store", new ui.item({
command: "openmarketplace"
}), 301, handle);
menus.addItemByPath("Cloud9/~", new ui.divider(), 1000, handle);
menus.addItemByPath("Cloud9/Package Browser", new ui.item({
command: "openpackagebrowser"
}), 1100, handle);
});
/***** Methods *****/
@ -123,10 +124,10 @@ define(function(require, exports, module) {
/***** Editor *****/
function MarketPlace(){
function PackageBrowser(){
var plugin = new Editor("Ajax.org", main.consumes, extensions);
//var emit = plugin.getEmitter();
var tab;
var tab, iframe;
plugin.on("resize", function(e) {
emit("resize", e);
@ -136,33 +137,15 @@ define(function(require, exports, module) {
tab = e.tab;
var htmlNode = e.htmlNode;
api.packages.get("", function(err, list){
if (c9.standalone) {
err = null;
list = [{ name: "example", apikey:"0000000000000000000000000000=", packagePath: "plugins/c9.example/example" }];
}
if (err) return;
var sHtml = "";
list.forEach(function(plugin){ // @todo use react instead in an iframe
packages[plugin.name] = plugin;
sHtml += "<div>"
+ "<span>" + plugin.name + "</span> | "
+ "<a href='javascript:void(0)' plugin-name='" + plugin.name + "' target='project'>Install In Workspace</a> | "
+ "<a href='javascript:void(0)' plugin-name='" + plugin.name + "' target='user'>Install To User</a>"
+ "</div>";
});
htmlNode.innerHTML = sHtml;
htmlNode.addEventListener("click", function(e){
if (e.target.tagName == "A") {
installPlugin(e.target.getAttribute("plugin-name"),
e.target.getAttribute("target"), function(){});
}
});
});
htmlNode.style.paddingTop = 0;
iframe = htmlNode.appendChild(document.createElement("iframe"));
iframe.style.width = "100%";
iframe.style.height = "100%";
iframe.style.border = 0;
iframe.style.backgroundColor = "#fbfbfb";
iframe.src = location.origin.replace("ide.", "") + "/profile/packages?nobar=1&pid=" + c9.projectId;
});
plugin.on("getState", function(e) {
@ -174,12 +157,11 @@ define(function(require, exports, module) {
plugin.on("documentLoad", function(e) {
var doc = e.doc;
doc.title = "Plugin Store";
doc.title = "Package Browser";
function setTheme(){
// var bg = ui.getStyleRule(".bar-preferences .container .header", "backgroundColor") || "#F0F0F0";
var bg = "#FFF";
doc.tab.backgroundColor = bg; //"#2d2d2d";
var bg = "#fbfbfb";
doc.tab.backgroundColor = bg;
if (util.shadeColor(bg, 1).isLight)
doc.tab.classList.remove("dark");
@ -192,14 +174,7 @@ define(function(require, exports, module) {
});
plugin.on("documentActivate", function(e) {
e.doc.tab.on("unload", function(){
if (parent.parentNode == tab)
tab.removeChild(parent);
});
tab.appendChild(parent);
emit("show");
});
/***** Register and define API *****/
@ -212,13 +187,13 @@ define(function(require, exports, module) {
});
plugin.load(null, "plugin.market");
plugin.load(null, "plugin.packages");
return plugin;
}
register(null, {
"plugin.market": handle
"plugin.packages": handle
});
}
});

View File

@ -0,0 +1 @@
This is the Cloud9 bundle example

View File

@ -0,0 +1,21 @@
{
"name": "",
"description": "",
"version": "0.0.1",
"author": "",
"contributors": [
{
"name": "",
"email": ""
}
],
"repository": {
"type": "git",
"url": ""
},
"plugins": {},
"categories": [
"misc"
],
"licenses": []
}

View File

@ -1,3 +1 @@
# c9.ide.example
This is the Cloud9 default plugin example

View File

@ -1,5 +1,5 @@
{
"name": "c9.ide.default",
"name": "",
"description": "",
"version": "0.0.1",
"author": "",

View File

@ -0,0 +1 @@
This is the Cloud9 installer plugin example

View File

@ -0,0 +1,57 @@
define(function(require, exports, module) {
module.exports = function(session, options){
// Dependencies for the collaboration features of Cloud9
session.install({
"name": "SQLite",
"description": "SQLite Database and NPM module",
"cwd": "~/.c9",
"optional": true
}, [
{
"npm": ["sqlite3@3.0.5"]
},
{
"tar.gz": {
"url": "https://raw.githubusercontent.com/c9/install/master/packages/sqlite3/linux/sqlite3.tar.gz",
"target": "~/.c9/lib/sqlite3",
"dir": "sqlite3"
}
},
{
"symlink": {
"source": "~/.c9/lib/sqlite3/sqlite3",
"target": "~/.c9/bin/sqlite3"
}
}
]);
session.install({
"name": "Sequalize",
"description": "Sequalize NPM module",
"cwd": "~/.c9",
"optional": true
}, {
"npm": ["sequelize@2.0.0-beta.0"]
});
session.install({
"name": "Collab Server",
"description": "A small Node.js collaboration server",
"cwd": "~/.c9",
"optional": true
}, {
"tar.gz": {
"url": "https://raw.githubusercontent.com/c9/install/master/packages/extend/c9-vfs-extend.tar.gz",
"target": "~/.c9"
}
});
// Show the installation screen
session.start();
};
module.exports.version = 1;
});

View File

@ -0,0 +1,22 @@
{
"name": "",
"description": "",
"version": "0.0.1",
"author": "",
"contributors": [
{
"name": "",
"email": ""
}
],
"repository": {
"type": "git",
"url": ""
},
"plugins": {},
"installer": "install.js",
"categories": [
"misc"
],
"licenses": []
}

View File

@ -1,3 +1 @@
# c9.ide.simple
This is the Cloud9 simple plugin example

View File

@ -1,5 +1,5 @@
{
"name": "c9.ide.simple",
"name": "",
"description": "",
"version": "0.0.1",
"author": "",

View File

@ -750,6 +750,9 @@ define(function(require, exports, module) {
session.__defineGetter__("tab", function(){ return doc.tab });
session.__defineGetter__("doc", function(){ return doc });
session.__defineGetter__("defaultEditor", function(){
return settings.getBool("user/terminal/@defaultEditor");
});
session.attach = function(){
if (session.aceSession && aceterm) {

View File

@ -157,6 +157,7 @@ module.exports = function(c9, proc, installPath, shell) {
options.output = false;
options.terminal = true;
options.detachOthers = !session.hasConnected;
options.defaultEditor = session.defaultEditor;
}
// Connect to backend and start tmux session

View File

@ -146,7 +146,7 @@ EventEmitter.prototype.addListener = function(type, listener, plugin) {
if (m && m > 0 && eventList.length > m) {
eventList.warned = true;
console.error('(node) warning: possible EventEmitter memory '
console.error('warning: possible EventEmitter memory '
+ 'leak detected. " + eventList.length + " listeners of type "' + type + '" added. '
+ 'Use emitter.setMaxListeners() to increase limit.'
);

View File

@ -156,6 +156,14 @@ function plugin(options, imports, register) {
res.end("define(function(require, exports, module) { return '"
+ options.workspaceDir + "'; });");
});
api.get("/vfs-home", function(req, res, next) {
if (!options.options.testing)
return next();
res.writeHead(200, {"Content-Type": "application/javascript"});
res.end("define(function(require, exports, module) { return '"
+ process.env.HOME + "'; });");
});
api.get("/update", function(req, res, next) {
res.writeHead(200, {

View File

@ -195,6 +195,7 @@ require([
})(),
log: {},
http: {},
ui: {},
api: {
stats: {
post: function(type, message, cb) {

View File

@ -28,6 +28,7 @@ module.exports = function(manifest, installPath) {
var config = {
standalone: true,
startBridge: true,
manifest: manifest,
workspaceDir: workspaceDir,
projectName: path.basename(workspaceDir),