kopia lustrzana https://github.com/c9/core
Merge remote-tracking branch 'origin/master' into fix/collab-db-corrupt
commit
6633c2a82f
|
@ -47,8 +47,6 @@ node_modules/kaefer/node_modules/
|
|||
!node_modules/treehugger
|
||||
!node_modules/logicblox
|
||||
!node_modules/connect-architect
|
||||
!node_modules/pty.js
|
||||
node_modules/pty.js/.npmignore
|
||||
!node_modules/ui
|
||||
!node_modules/react-bootstrap
|
||||
!node_modules/oldclient
|
||||
|
|
|
@ -17,7 +17,7 @@ module.exports = function(config) {
|
|||
}, {
|
||||
packagePath: "connect-architect/connect.cors"
|
||||
}, {
|
||||
packagePath: "connect-architect/connect.logger"
|
||||
packagePath: "./c9.logger/stdout-logger"
|
||||
}, {
|
||||
packagePath: "./c9.core/ext"
|
||||
}, {
|
||||
|
|
|
@ -120,7 +120,9 @@ module.exports = function(options) {
|
|||
region: options.region,
|
||||
pid: options.project.id,
|
||||
servers: options.vfsServers,
|
||||
updateServers: hosted
|
||||
updateServers: hosted,
|
||||
strictRegion: options.strictRegion
|
||||
|| options.mode === "beta" && "beta"
|
||||
},
|
||||
{
|
||||
packagePath: "plugins/c9.ide.auth/auth",
|
||||
|
|
|
@ -125,7 +125,7 @@ module.exports = function(config, optimist) {
|
|||
"connect-architect/connect.redirect",
|
||||
"connect-architect/connect.cors",
|
||||
"./c9.connect.favicon/favicon",
|
||||
//"connect-architect/connect.logger",
|
||||
// "./c9.logger/stdout-logger",
|
||||
|
||||
"./c9.core/ext",
|
||||
|
||||
|
@ -174,6 +174,7 @@ module.exports = function(config, optimist) {
|
|||
"./c9.vfs.server/download",
|
||||
"./c9.vfs.server/filelist",
|
||||
"./c9.vfs.server/statics",
|
||||
"./c9.analytics/mock_analytics",
|
||||
"./c9.metrics/mock_metrics",
|
||||
"./c9.ide.experiment/mock_experiment",
|
||||
{
|
||||
|
|
|
@ -91,12 +91,16 @@ var processLoadQueue = function(err, id) {
|
|||
if (r.errback) r.errback(err);
|
||||
}
|
||||
});
|
||||
if (define.lastModule = err.id)
|
||||
if (define.lastModule == err.id)
|
||||
define.lastModule = null;
|
||||
define.pending = define.pending.filter(function(p) {
|
||||
return p != err.id;
|
||||
});
|
||||
changed = true;
|
||||
} else if (id && !defQueue.length && !define.loaded[id]) {
|
||||
// the script didn't call define
|
||||
defQueue = [config.shim && config.shim[id] || [[], null]];
|
||||
console.error("require shims not supported");
|
||||
}
|
||||
|
||||
if (defQueue.length) {
|
||||
|
|
|
@ -1,5 +1,6 @@
|
|||
var git = require("./git");
|
||||
var hostname = require("./hostname");
|
||||
var os = require("os");
|
||||
|
||||
exports.load = function(root) {
|
||||
var manifest = require(root + "/package.json");
|
||||
|
@ -8,6 +9,7 @@ exports.load = function(root) {
|
|||
git.getHeadRevisionSync(root);
|
||||
|
||||
manifest.hostname = hostname.get();
|
||||
manifest.internalIP = os.networkInterfaces().eth0 && os.networkInterfaces().eth0[0].address;
|
||||
|
||||
return manifest;
|
||||
};
|
||||
|
|
|
@ -53,7 +53,7 @@ function RestClient(host, port, config) {
|
|||
|
||||
/** Keep requests alive for long running requests **/
|
||||
req.setSocketKeepAlive(true);
|
||||
|
||||
|
||||
req.on("error", function(e) {
|
||||
log("ERROR %s %s://%s:%s%s %s",
|
||||
options.method,
|
||||
|
|
|
@ -1,7 +1,5 @@
|
|||
"use strict";
|
||||
|
||||
var http = require("http");
|
||||
|
||||
module.exports = function(options, imports, register) {
|
||||
|
||||
imports.connect.addResponseMethod("redirect", function(location) {
|
||||
|
@ -9,7 +7,7 @@ module.exports = function(options, imports, register) {
|
|||
this.end("");
|
||||
});
|
||||
imports.connect.addResponseMethod("returnTo", function(req, defaultReturn) {
|
||||
var url = defaultReturn || "/";
|
||||
var url = defaultReturn || "/";
|
||||
if (req.session && req.session.returnTo) {
|
||||
url = req.session.returnTo;
|
||||
delete req.session.returnTo;
|
||||
|
|
|
@ -65,9 +65,14 @@ function logToFile(message){
|
|||
|
||||
module.exports = function setup(fsOptions) {
|
||||
var pty;
|
||||
if (fsOptions.nodePath) {
|
||||
process.env.NODE_PATH = fsOptions.nodePath;
|
||||
require("module")._initPaths();
|
||||
}
|
||||
if (!fsOptions.nopty) {
|
||||
// on darwin trying to load binary for a wrong version crashes the process
|
||||
[process.env.HOME + "/.c9/node_modules/pty.js", "pty.js", "pty.nw.js"].some(function(p) {
|
||||
[(fsOptions.nodePath || process.env.HOME + "/.c9/node_modules") + "/pty.js",
|
||||
"pty.js", "pty.nw.js"].some(function(p) {
|
||||
try {
|
||||
pty = require(p);
|
||||
return true;
|
||||
|
@ -1918,7 +1923,7 @@ module.exports = function setup(fsOptions) {
|
|||
meta.pty.emit("data", err);
|
||||
}
|
||||
|
||||
else if (data.indexOf("Set option") > -1) {
|
||||
else if (data) {
|
||||
// Fetch the PID if appropriate
|
||||
if (options.detach && options.output) {
|
||||
fetchPid(function(err, pid){
|
||||
|
@ -2248,12 +2253,12 @@ module.exports = function setup(fsOptions) {
|
|||
}
|
||||
|
||||
function killtree(pid, options, callback) {
|
||||
var code = options.code || "SIGKILL";
|
||||
var code = options.code || options.graceful ? "SIGTERM" : "SIGKILL";
|
||||
|
||||
childrenOfPid(pid, function(err, pidlist){
|
||||
childrenOfPid(pid, function killList(err, pidlist){
|
||||
if (err)
|
||||
return callback(err);
|
||||
|
||||
|
||||
pidlist.forEach(function (pid) {
|
||||
// if asked to kill ourselves do that only after killing all the children
|
||||
if (pid == process.pid) {
|
||||
|
@ -2264,10 +2269,19 @@ module.exports = function setup(fsOptions) {
|
|||
try {
|
||||
process.kill(pid, code);
|
||||
} catch(e) {
|
||||
// kill may throw if the pid does not exist.
|
||||
if (e.code == "ESRCH")
|
||||
return; // kill may throw if the pid does not exist.
|
||||
// todo try killing with sudo in case of "EPERM"
|
||||
}
|
||||
});
|
||||
callback(null, {});
|
||||
if (options.graceful && code != "SIGKILL") {
|
||||
code = "SIGKILL";
|
||||
setTimeout(function() {
|
||||
killList(null, pidlist);
|
||||
}, options.timeout || 800);
|
||||
} else {
|
||||
callback(null, {});
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
|
|
18
package.json
18
package.json
|
@ -56,7 +56,7 @@
|
|||
"c9"
|
||||
],
|
||||
"c9plugins": {
|
||||
"c9.ide.language": "#77f75c7635",
|
||||
"c9.ide.language": "#2755277da0",
|
||||
"c9.ide.language.css": "#ef8a28943e",
|
||||
"c9.ide.language.generic": "#32986699ac",
|
||||
"c9.ide.language.html": "#bbe81afed1",
|
||||
|
@ -67,7 +67,7 @@
|
|||
"c9.ide.language.javascript.tern": "#2b0bb024da",
|
||||
"c9.ide.language.javascript.infer": "#cfec494a3c",
|
||||
"c9.ide.language.jsonalyzer": "#ba3e0d298c",
|
||||
"c9.ide.collab": "#259b6c8be4",
|
||||
"c9.ide.collab": "#5f2cd0ad8b",
|
||||
"c9.ide.local": "#a9703b630c",
|
||||
"c9.ide.find": "#6cc6d3379d",
|
||||
"c9.ide.find.infiles": "#72582de3cd",
|
||||
|
@ -86,12 +86,12 @@
|
|||
"c9.ide.configuration": "#adf50fdaa2",
|
||||
"c9.ide.dialog.wizard": "#7667ec79a8",
|
||||
"c9.ide.fontawesome": "#781602c5d8",
|
||||
"c9.ide.format": "#f51451ac57",
|
||||
"c9.ide.help.support": "#6bcfa8ceff",
|
||||
"c9.ide.format": "#b0bb91a623",
|
||||
"c9.ide.help.support": "#61f5a81d8c",
|
||||
"c9.ide.imgeditor": "#ed89162aa7",
|
||||
"c9.ide.immediate": "#6845a93705",
|
||||
"c9.ide.installer": "#dbfbb98527",
|
||||
"c9.ide.mount": "#250f8d91a2",
|
||||
"c9.ide.installer": "#c36540bd61",
|
||||
"c9.ide.mount": "#d4cfe526e9",
|
||||
"c9.ide.navigate": "#f358997d93",
|
||||
"c9.ide.newresource": "#f1f0624768",
|
||||
"c9.ide.openfiles": "#28a4f5af16",
|
||||
|
@ -103,15 +103,15 @@
|
|||
"c9.ide.recentfiles": "#7c099abf40",
|
||||
"c9.ide.remote": "#301d2ab519",
|
||||
"c9.ide.processlist": "#bc11818bb5",
|
||||
"c9.ide.run": "#cc9d80f8bb",
|
||||
"c9.ide.run": "#567ad01865",
|
||||
"c9.ide.run.build": "#ad45874c88",
|
||||
"c9.ide.run.debug.xdebug": "#3b1520f83d",
|
||||
"c9.ide.save": "#a03709ef3f",
|
||||
"c9.ide.save": "#58b8616a88",
|
||||
"c9.ide.terminal.monitor": "#b0b4d03280",
|
||||
"c9.ide.theme.flat": "#b1d65fa9bb",
|
||||
"c9.ide.threewaymerge": "#229382aa0b",
|
||||
"c9.ide.undo": "#b028bcb4d5",
|
||||
"c9.ide.upload": "#0bd010d3dc",
|
||||
"c9.ide.welcome": "#a0f004e3bd"
|
||||
"c9.ide.welcome": "#4b9685584c"
|
||||
}
|
||||
}
|
|
@ -0,0 +1,23 @@
|
|||
/**
|
||||
* Dummy implementation of analytics.
|
||||
*/
|
||||
"use strict";
|
||||
|
||||
plugin.consumes = [];
|
||||
plugin.provides = ["analytics"];
|
||||
|
||||
module.exports = plugin;
|
||||
|
||||
function plugin(options, imports, register) {
|
||||
|
||||
register(null, {
|
||||
"analytics": {
|
||||
log: function() {},
|
||||
track: function() {},
|
||||
identify: function() {},
|
||||
logClean: function() {},
|
||||
trackClean: function() {},
|
||||
identifyClean: function() {},
|
||||
}
|
||||
});
|
||||
}
|
|
@ -104,11 +104,10 @@ define(function(require, exports, module) {
|
|||
fs.exists(path, function(existing) {
|
||||
var tab = tabManager.open({
|
||||
path: path,
|
||||
active: i === 0,
|
||||
document:
|
||||
existing
|
||||
? undefined
|
||||
: { meta : { newfile: true } }
|
||||
focus: i === 0,
|
||||
document: existing
|
||||
? undefined
|
||||
: { meta : { newfile: true } }
|
||||
}, function(){
|
||||
next();
|
||||
});
|
||||
|
|
|
@ -1,15 +0,0 @@
|
|||
"use strict";
|
||||
|
||||
var assert = require("assert");
|
||||
|
||||
plugin.consumes = [];
|
||||
plugin.provides = ["assert.root"];
|
||||
|
||||
module.exports = plugin;
|
||||
|
||||
function plugin(options, imports, register) {
|
||||
assert.equal(process.getuid(), 0, "You need to be root to run this config");
|
||||
register(null, {
|
||||
"assert.root": {}
|
||||
});
|
||||
}
|
|
@ -102,7 +102,8 @@ define(function(require, module, exports) {
|
|||
var res = {
|
||||
body: xhr.responseText,
|
||||
status: xhr.status,
|
||||
headers: parseHeaders(xhr.getAllResponseHeaders())
|
||||
headers: parseHeaders(xhr.getAllResponseHeaders()),
|
||||
$reqHeaders: headers // TODO remove when bug in readFileWithMetadata is fixed
|
||||
};
|
||||
|
||||
var data = xhr.responseText;
|
||||
|
|
|
@ -557,9 +557,9 @@ define(function(require, exports, module) {
|
|||
node.map = {};
|
||||
else if (!isFolder && node.map)
|
||||
delete node.map;
|
||||
if (stat.size)
|
||||
if (stat.size != undefined)
|
||||
node.size = stat.size;
|
||||
if (stat.mtime)
|
||||
if (stat.mtime != undefined)
|
||||
node.mtime = stat.mtime;
|
||||
if (original_stat)
|
||||
node.link = stat.fullPath;
|
||||
|
|
|
@ -14,38 +14,56 @@ return function(_request) {
|
|||
}, callback);
|
||||
}
|
||||
|
||||
function readFile(path, encoding, callback, progress, metadata) {
|
||||
function _readFile(path, encoding, callback, progress, metadata) {
|
||||
if (typeof encoding == "function") {
|
||||
progress = callback;
|
||||
callback = encoding;
|
||||
encoding = null;
|
||||
}
|
||||
|
||||
if (path == "/") {
|
||||
// Make sure the path doesn't have a trailing /
|
||||
// It would then be interpreted as a directory
|
||||
if (path.substr(-1) == "/")
|
||||
path = path.substr(0, path.length - 1);
|
||||
|
||||
if (!path) {
|
||||
var err = new Error("Cannot read root as file");
|
||||
err.code = "EISDIR";
|
||||
return callback(err);
|
||||
}
|
||||
|
||||
// Make sure the path doesn't have a trailing /
|
||||
// It would then be interpreted as a directory
|
||||
if (path.substr(-1) == "/")
|
||||
path = path.substr(0, path.length - 1);
|
||||
|
||||
var headers = metadata ? { "x-request-metadata" : "true" } : null;
|
||||
return request("GET", path, "", callback, progress, false, headers);
|
||||
return request("GET", path, "", function(err, data, res) {
|
||||
if (err)
|
||||
return metadata ? callback(err, null, null, res) : callback(err, null, res);
|
||||
var hasMetadata = res.headers["x-metadata-length"] != undefined;
|
||||
if (metadata || hasMetadata) {
|
||||
var ml = parseInt(res.headers["x-metadata-length"], 10) || 0;
|
||||
var ln = data.length;
|
||||
if (!metadata) {
|
||||
var $reqHeaders = res.$reqHeaders;
|
||||
var message = "Unexpected metadata ";
|
||||
if ($reqHeaders)
|
||||
message += ($reqHeaders == headers) + $reqHeaders["x-request-metadata"];
|
||||
console.error($reqHeaders, headers, message);
|
||||
setTimeout(function() { throw new Error(message); });
|
||||
return callback(err, data.substr(0, ln - ml), res);
|
||||
}
|
||||
callback(err, data.substr(0, ln - ml), ml && data.substr(-1 * ml) || "", res);
|
||||
} else {
|
||||
callback(err, data, res);
|
||||
}
|
||||
}, progress, false, headers);
|
||||
}
|
||||
|
||||
function readFile(path, encoding, callback, progress, _metadata) {
|
||||
// TODO remove this debugging code once we find why metadata was shown as file contents
|
||||
if (_metadata != undefined)
|
||||
throw new Error("attempt to call readfile with metadata");
|
||||
return _readFile(path, encoding, callback, progress, false);
|
||||
}
|
||||
|
||||
function readFileWithMetadata(path, encoding, callback, progress) {
|
||||
return readFile(path, encoding, function(err, data, res) {
|
||||
if (err) return callback(err, null, null, res);
|
||||
|
||||
// var cl = parseInt(res.headers["x-content-length"], 10) || data.length;
|
||||
var ml = parseInt(res.headers["x-metadata-length"], 10) || 0;
|
||||
var ln = data.length;
|
||||
|
||||
callback(err, data.substr(0, ln - ml), ml && data.substr(-1 * ml) || "", res);
|
||||
}, progress, true);
|
||||
return _readFile(path, encoding, callback, progress, true);
|
||||
}
|
||||
|
||||
function writeFile(path, data, sync, callback, progress) {
|
||||
|
|
|
@ -509,6 +509,12 @@ define(function(require, exports, module) {
|
|||
});
|
||||
});
|
||||
}
|
||||
},
|
||||
/**
|
||||
* @ignore
|
||||
*/
|
||||
killtree: function(pid, options, callback) {
|
||||
vfs.killtree(pid, options, callback);
|
||||
}
|
||||
});
|
||||
|
||||
|
|
|
@ -2,7 +2,7 @@ define(function(require, exports, module) {
|
|||
|
||||
var modesByName = require("ace/ext/modelist").modesByName;
|
||||
|
||||
modesByName.javascript.extensions += "|run|build";
|
||||
modesByName.javascript.extensions += "|run|build|outline";
|
||||
|
||||
var primaryModes = ["c_cpp","clojure","coffee","csharp","css","dart","golang",
|
||||
"html","jade","java","javascript","json","less","lua","perl","php","python",
|
||||
|
|
|
@ -15,6 +15,7 @@ define(function(require, exports, module) {
|
|||
var plugin = new Editor("Ajax.org", main.consumes, extensions);
|
||||
//var emit = plugin.getEmitter();
|
||||
var container;
|
||||
var counter = 0;
|
||||
|
||||
plugin.on("draw", function(e) {
|
||||
// Create UI elements
|
||||
|
|
|
@ -217,21 +217,26 @@ define(function(require, module, exports) {
|
|||
.addNavigation(caption, index, heading.navHtml, plugin);
|
||||
|
||||
subHeadings[caption] = { navHtml: htmlNode, index: index };
|
||||
htmlNode.$caption = caption;
|
||||
|
||||
htmlNode.addEventListener("mousedown", function(){
|
||||
apf.tween.single(container.$int, {
|
||||
type: "scrollTop",
|
||||
steps: 10,
|
||||
anim: apf.tween.easeInOutCubic,
|
||||
from: container.$int.scrollTop,
|
||||
to: form.headings[caption].container.$ext.offsetTop
|
||||
})
|
||||
});
|
||||
htmlNode.addEventListener("mousedown", scrollTo.bind(null, caption));
|
||||
}
|
||||
|
||||
return subHeadings[caption];
|
||||
}
|
||||
|
||||
function scrollTo(caption) {
|
||||
if (!form.headings[caption])
|
||||
return;
|
||||
apf.tween.single(container.$int, {
|
||||
type: "scrollTop",
|
||||
steps: 10,
|
||||
anim: apf.tween.easeInOutCubic,
|
||||
from: container.$int.scrollTop,
|
||||
to: form.headings[caption].container.$ext.offsetTop
|
||||
})
|
||||
}
|
||||
|
||||
/***** LifeCycle *****/
|
||||
|
||||
plugin.on("load", function(){
|
||||
|
@ -321,6 +326,10 @@ define(function(require, module, exports) {
|
|||
* @param {Boolean} options.form Specifies whether to create a form for this panel.
|
||||
*/
|
||||
plugin.freezePublicAPI({
|
||||
/**
|
||||
* @ignore.
|
||||
*/
|
||||
get section() { return lastA && lastA.$caption; },
|
||||
/**
|
||||
* The APF UI element that is presenting the pane in the UI.
|
||||
* This property is here for internal reasons only. *Do not
|
||||
|
@ -394,6 +403,10 @@ define(function(require, module, exports) {
|
|||
*/
|
||||
show: show,
|
||||
|
||||
/**
|
||||
* Scrolls to a subheading.
|
||||
*/
|
||||
scrollTo: scrollTo,
|
||||
/**
|
||||
* Hides the panel.
|
||||
*/
|
||||
|
|
|
@ -64,13 +64,14 @@ define(function(require, exports, module) {
|
|||
bindKey: { mac: "Command-,", win: "Ctrl-," },
|
||||
exec: function (editor, args) {
|
||||
var tab = tabs.focussedTab;
|
||||
if (tab && tab.editor.type == "preferences" && !args.panel) {
|
||||
var toggle = args.toggle || args.source == "click";
|
||||
if (tab && tab.editor.type == "preferences" && toggle) {
|
||||
tab.close();
|
||||
return;
|
||||
}
|
||||
if (focusOpenPrefs()) {
|
||||
if (args.panel)
|
||||
activate(args.panel);
|
||||
activate(args.panel, args.section);
|
||||
|
||||
return;
|
||||
}
|
||||
|
@ -80,7 +81,7 @@ define(function(require, exports, module) {
|
|||
active: true
|
||||
}, function(){
|
||||
if (args.panel)
|
||||
activate(args.panel);
|
||||
activate(args.panel, args.section);
|
||||
});
|
||||
}
|
||||
}, handle);
|
||||
|
@ -139,7 +140,6 @@ define(function(require, exports, module) {
|
|||
// Create UI elements
|
||||
parent = e.tab.appendChild(new ui.hsplitbox({
|
||||
"class" : "bar-preferences",
|
||||
//"skinset" : "prefs",
|
||||
"anchors" : "0 0 0 0",
|
||||
}));
|
||||
parent.appendChild(navigation);
|
||||
|
@ -181,17 +181,31 @@ define(function(require, exports, module) {
|
|||
return htmlNode;
|
||||
}
|
||||
|
||||
function activate(panel) {
|
||||
function activate(panel, section) {
|
||||
if (!drawn) {
|
||||
if (!activePanel)
|
||||
handle.once("draw", function(){ activate(activePanel); });
|
||||
activePanel = panel;
|
||||
return;
|
||||
}
|
||||
|
||||
if (typeof panel == "string") {
|
||||
var panels = navigation && navigation.$ext && navigation.$ext.children;
|
||||
if (panels) {
|
||||
for (var i = 0; i < panels.length; i++) {
|
||||
if (panels[i].name == panel) {
|
||||
panel = panels[i].hostPlugin;
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
if (!panel || !panel.show)
|
||||
return console.error("Couldn't find preference panel", panel);
|
||||
if (activePanel && activePanel != panel)
|
||||
activePanel.hide();
|
||||
panel.show(!activePanel);
|
||||
if (section)
|
||||
panel.scrollTo(section);
|
||||
activePanel = panel;
|
||||
}
|
||||
|
||||
|
@ -322,18 +336,10 @@ define(function(require, exports, module) {
|
|||
|
||||
plugin.on("getState", function(e) {
|
||||
e.state.activePanel = activePanel && activePanel.name;
|
||||
e.state.section = activePanel && activePanel.section;
|
||||
});
|
||||
plugin.on("setState", function(e) {
|
||||
var name = e.state.activePanel;
|
||||
if (activePanel && activePanel.name == name)
|
||||
return;
|
||||
var panels = navigation && navigation.$ext && navigation.$ext.children;
|
||||
if (panels) {
|
||||
for (var i = 0; i < panels.length; i++) {
|
||||
if (panels[i].name == name)
|
||||
return activate(panels[i].hostPlugin);
|
||||
}
|
||||
}
|
||||
activate(e.state.activePanel, e.state.section);
|
||||
});
|
||||
|
||||
/***** Lifecycle *****/
|
||||
|
|
|
@ -225,15 +225,13 @@ module.exports = function(c9, proc, installPath, shell) {
|
|||
}
|
||||
});
|
||||
|
||||
var buffer = "";
|
||||
session.pty.started = c9.platform == "win32";
|
||||
session.pty.on("data", function(data) {
|
||||
if (!disregarded) {
|
||||
if (typeof data == "object") {
|
||||
if (data.started)
|
||||
return (session.pty.started = true);
|
||||
return;
|
||||
else if (data.code) {
|
||||
if (data.type == "exception") { //Error
|
||||
if (data.type == "exception") { // Error
|
||||
session.disregard();
|
||||
console.error("Error creating TMUX session: ", err.message);
|
||||
session.setState("error");
|
||||
|
@ -245,15 +243,6 @@ module.exports = function(c9, proc, installPath, shell) {
|
|||
else
|
||||
return session.setSize(data);
|
||||
}
|
||||
|
||||
if (!options.attach && !session.pty.started) {
|
||||
buffer += data;
|
||||
if (buffer.indexOf("Set option: c0-change-trigger -> 0 ") > -1) {
|
||||
session.pty.started = true;
|
||||
data = buffer.replace(/^[\s\S]*Set option: c0-change-trigger -> 0 /, "");
|
||||
}
|
||||
else return;
|
||||
}
|
||||
|
||||
if (session.filter)
|
||||
data = session.filter(data);
|
||||
|
|
|
@ -247,7 +247,7 @@ define(function(require, exports, module) {
|
|||
fsCache.model.getTooltipText = function(node) {
|
||||
var size = node.size;
|
||||
return node.label + (node.link ? " => " + node.link + "\n" : "")
|
||||
+ (size && !node.isFolder ? " | " + (
|
||||
+ (size != undefined && !node.isFolder ? " | " + (
|
||||
size < 0x400 ? size + " bytes" :
|
||||
size < 0x100000 ? (size / 0x400).toFixed(2) + "KB" :
|
||||
(size / 0x100000).toFixed(2) + "MB"
|
||||
|
|
|
@ -102,6 +102,9 @@ define(function(require, exports, module) {
|
|||
|
||||
save.on("beforeSave", function(e) {
|
||||
e.document.meta.$savingValue = e.save;
|
||||
if (e.tab.classList.contains("conflict")) {
|
||||
showChangeDialog(e.tab);
|
||||
}
|
||||
}, plugin);
|
||||
|
||||
save.on("afterSave", function(e) {
|
||||
|
@ -229,8 +232,12 @@ define(function(require, exports, module) {
|
|||
if (!tabManager.findTab(path)) // drat! tab is gone
|
||||
return;
|
||||
|
||||
// Show dialog
|
||||
showChangeDialog();
|
||||
// Show dialogs for changed tabs
|
||||
for (var changedPath in changedPaths) {
|
||||
tab = changedPaths[changedPath].tab;
|
||||
data = changedPaths[changedPath].data;
|
||||
showChangeDialog(tab, data);
|
||||
}
|
||||
}
|
||||
|
||||
function checkByStatOrContents() {
|
||||
|
@ -367,9 +374,7 @@ define(function(require, exports, module) {
|
|||
else {
|
||||
changedPaths[path].tab.document.undoManager.bookmark(-2);
|
||||
changedPaths[path].resolve();
|
||||
showChangeDialog();
|
||||
}
|
||||
|
||||
checkEmptyQueue();
|
||||
}
|
||||
|
||||
|
@ -382,7 +387,6 @@ define(function(require, exports, module) {
|
|||
else {
|
||||
getLatestValue(path, function(err, path, data) {
|
||||
updateChangedPath(err, path, data);
|
||||
showChangeDialog();
|
||||
});
|
||||
}
|
||||
|
||||
|
@ -408,7 +412,6 @@ define(function(require, exports, module) {
|
|||
|
||||
getLatestValue(path, function(err, path, data) {
|
||||
mergeChangedPath(err, path, data);
|
||||
showChangeDialog();
|
||||
});
|
||||
}
|
||||
|
||||
|
|
|
@ -43,7 +43,8 @@ define(function(require, exports, module) {
|
|||
if (query.vfs)
|
||||
options.updateServers = false;
|
||||
|
||||
var region = query.region || options.region;
|
||||
var strictRegion = query.region || options.strictRegion;
|
||||
var region = strictRegion || options.region;
|
||||
|
||||
var servers;
|
||||
var pendingServerReqs = [];
|
||||
|
@ -170,8 +171,8 @@ define(function(require, exports, module) {
|
|||
|
||||
// check for version
|
||||
if (vfsServers.length && !servers.length) {
|
||||
if (region === "beta")
|
||||
return callback(fatalError("Staging VFS server(s) not working", "reload"));
|
||||
if (strictRegion)
|
||||
return callback(fatalError("No VFS server(s) found for region " + strictRegion, "reload"));
|
||||
return onProtocolChange(callback);
|
||||
}
|
||||
|
||||
|
@ -304,11 +305,11 @@ define(function(require, exports, module) {
|
|||
|
||||
function shuffleServers(version, servers) {
|
||||
servers = servers.slice();
|
||||
var isBetaClient = region === "beta";
|
||||
servers = servers.filter(function(s) {
|
||||
var isBetaServer = s.region === "beta";
|
||||
return isBetaServer === isBetaClient;
|
||||
});
|
||||
if (strictRegion) {
|
||||
servers = servers.filter(function(s) {
|
||||
return s.region === strictRegion;
|
||||
});
|
||||
}
|
||||
servers = servers.filter(function(s) {
|
||||
return s.version == undefined || s.version == version;
|
||||
});
|
||||
|
|
|
@ -410,6 +410,7 @@ define(function(require, exports, module) {
|
|||
pty: vfsCall.bind(null, "pty"),
|
||||
tmux: vfsCall.bind(null, "tmux"),
|
||||
execFile: vfsCall.bind(null, "execFile"),
|
||||
killtree: vfsCall.bind(null, "killtree"),
|
||||
|
||||
// Extending the API
|
||||
use: vfsCall.bind(null, "use"),
|
||||
|
|
|
@ -7,7 +7,8 @@ plugin.consumes = [
|
|||
"connect.render",
|
||||
"connect.render.ejs",
|
||||
"connect.remote-address",
|
||||
"vfs.cache"
|
||||
"vfs.cache",
|
||||
"analytics"
|
||||
];
|
||||
plugin.provides = [
|
||||
"vfs.server"
|
||||
|
@ -34,6 +35,8 @@ function plugin(options, imports, register) {
|
|||
var passport = imports.passport;
|
||||
var connect = imports.connect;
|
||||
var render = imports["connect.render"];
|
||||
var analytics = imports["analytics"];
|
||||
var async = require("async");
|
||||
|
||||
var Types = require("frontdoor").Types;
|
||||
var error = require("http-error");
|
||||
|
@ -43,6 +46,7 @@ function plugin(options, imports, register) {
|
|||
|
||||
var section = api.section("vfs");
|
||||
|
||||
var VFS_ACTIVITY_WINDOW = 1000 * 60 * 60;
|
||||
|
||||
section.registerType("vfsid", new Types.RegExp(/[a-zA-Z0-9]{16}/));
|
||||
section.registerType("pid", new Types.Number(0));
|
||||
|
@ -59,7 +63,6 @@ function plugin(options, imports, register) {
|
|||
}, [
|
||||
api.ensureAdmin(),
|
||||
function(req, res, next) {
|
||||
|
||||
var type = req.params.status.split(".")[1] || "html";
|
||||
|
||||
var entries = cache.getAll();
|
||||
|
@ -108,6 +111,8 @@ function plugin(options, imports, register) {
|
|||
var version = req.params.version;
|
||||
var user = req.user;
|
||||
|
||||
trackActivity(user, req.cookies);
|
||||
|
||||
if (version != kaefer.version.protocol) {
|
||||
var err = new error.PreconditionFailed("Wrong VFS protocol version. Expected version '" + kaefer.version.protocol + "' but found '" + version + "'");
|
||||
err.subtype = "protocol_mismatch";
|
||||
|
@ -196,6 +201,8 @@ function plugin(options, imports, register) {
|
|||
var path = req.params.path;
|
||||
var user = req.user;
|
||||
|
||||
trackActivity(user, req.cookies);
|
||||
|
||||
if (path.indexOf("../") !== -1)
|
||||
return next(new error.BadRequest("invalid path"));
|
||||
|
||||
|
@ -277,7 +284,9 @@ function plugin(options, imports, register) {
|
|||
err.code = 499;
|
||||
return next(err);
|
||||
}
|
||||
|
||||
// TODO: use an interval to make sure this fires
|
||||
// even when this REST api is not used for a day
|
||||
trackActivity(entry.user, req.cookies);
|
||||
entry.vfs.handleRest(scope, path, req, res, next);
|
||||
}
|
||||
]);
|
||||
|
@ -306,10 +315,33 @@ function plugin(options, imports, register) {
|
|||
err.code = 499;
|
||||
return next(err);
|
||||
}
|
||||
|
||||
|
||||
entry.vfs.handleEngine(req, res, next);
|
||||
}
|
||||
]);
|
||||
|
||||
function trackActivity(user, cookies) {
|
||||
if (user.id === -1)
|
||||
return;
|
||||
|
||||
if (new Date(user.lastVfsAccess).getDate() != new Date().getDate() ||
|
||||
Date.now() > user.lastVfsAccess + VFS_ACTIVITY_WINDOW) {
|
||||
|
||||
// Alias anonymous id, identify, and track activity;
|
||||
// wait for a flush between each step; see
|
||||
// https://segment.com/docs/integrations/mixpanel/#server-side
|
||||
async.series([
|
||||
analytics.aliasClean.bind(analytics, cookies.mixpanelAnonymousId, user.id),
|
||||
analytics.identifyClean.bind(analytics, user, {}),
|
||||
analytics.trackClean.bind(analytics, user, "VFS is active", { uid: user.id }),
|
||||
], function(err) {
|
||||
if (err) return console.log("Error logging activity", err.stack || err);
|
||||
});
|
||||
|
||||
user.lastVfsAccess = Date.now();
|
||||
user.save(function() {});
|
||||
}
|
||||
}
|
||||
|
||||
register(null, {
|
||||
"vfs.server": {
|
||||
|
|
68
server.js
68
server.js
|
@ -9,6 +9,8 @@ try {
|
|||
var path = require("path");
|
||||
var architect = require("architect");
|
||||
var optimist = require("optimist");
|
||||
var async = require("async");
|
||||
var os = require("os");
|
||||
|
||||
if (process.version.match(/^v0/) && parseFloat(process.version.substr(3)) < 10) {
|
||||
console.warn("You're using Node.js version " + process.version
|
||||
|
@ -26,6 +28,7 @@ var shortcuts = {
|
|||
"ci" : ["ide", "preview", "vfs", "proxy", "-s", "ci"],
|
||||
"s" : ["standalone", "-s", "standalone"]
|
||||
};
|
||||
var delayLoadConfigs = ["preview", "api", "oldclient", "apps-proxy", "worker"];
|
||||
|
||||
module.exports = main;
|
||||
|
||||
|
@ -33,7 +36,7 @@ if (!module.parent)
|
|||
main(process.argv.slice(2));
|
||||
|
||||
function getDefaultSettings() {
|
||||
var hostname = require("os").hostname();
|
||||
var hostname = os.hostname();
|
||||
|
||||
var suffix = hostname.trim().split("-").pop() || "";
|
||||
var modes = {
|
||||
|
@ -47,7 +50,9 @@ function getDefaultSettings() {
|
|||
|
||||
module.exports.getDefaultSettings = getDefaultSettings;
|
||||
|
||||
function main(argv, config, callback) {
|
||||
function main(argv, config, onLoaded) {
|
||||
var inContainer = os.hostname().match(/-\d+$/);
|
||||
|
||||
var options = optimist(argv)
|
||||
.usage("Usage: $0 [CONFIG_NAME] [--help]")
|
||||
.alias("s", "settings")
|
||||
|
@ -55,26 +60,57 @@ function main(argv, config, callback) {
|
|||
.describe("settings", "Settings file to use")
|
||||
.describe("dump", "dump config file as JSON")
|
||||
.describe("domain", "Top-level domain to use (e.g, c9.io)")
|
||||
.describe("exclude", "Exclude specified service")
|
||||
.default("domain", inContainer && process.env.C9_HOSTNAME)
|
||||
.boolean("help")
|
||||
.describe("help", "Show command line options.");
|
||||
|
||||
var configs = options.argv._;
|
||||
if (!configs.length)
|
||||
configs = [config || DEFAULT_CONFIG];
|
||||
|
||||
configs.forEach(function(config) {
|
||||
if (shortcuts[config]) {
|
||||
return main(shortcuts[config].concat(argv.filter(function(arg) {
|
||||
return arg != config;
|
||||
})), null, callback);
|
||||
}
|
||||
else {
|
||||
start(config, options, callback);
|
||||
}
|
||||
if (options.argv.exclude && !Array.isArray(options.argv.exclude.length))
|
||||
options.argv.exclude = [options.argv.exclude];
|
||||
|
||||
var expanded = expandShortCuts(configs);
|
||||
if (expanded.length > configs.length)
|
||||
return main(expanded.concat(argv.filter(function(arg) {
|
||||
return !shortcuts[arg];
|
||||
})), config, onLoaded);
|
||||
|
||||
var delayed = expanded.filter(function(c) { return delayLoadConfigs.indexOf(c) !== -1 });
|
||||
var notDelayed = expanded.filter(function(c) { return delayLoadConfigs.indexOf(c) === -1 });
|
||||
|
||||
startConfigs(notDelayed, function() {
|
||||
startConfigs(delayed, function() {});
|
||||
});
|
||||
|
||||
function startConfigs(configs, done) {
|
||||
async.each(configs, function(config, next) {
|
||||
if (options.argv.exclude && options.argv.exclude.indexOf(config) > -1)
|
||||
return next();
|
||||
start(config, options, function(err, result, path) {
|
||||
onLoaded && onLoaded(err, result, path);
|
||||
next(err);
|
||||
});
|
||||
}, done);
|
||||
}
|
||||
}
|
||||
|
||||
function expandShortCuts(configs) {
|
||||
var results = configs.slice();
|
||||
for (var i = 0; i < results.length; i++) {
|
||||
var expanded = shortcuts[results[i]];
|
||||
if (expanded) {
|
||||
results.splice.apply(results, [i, 1].concat(expanded));
|
||||
i += expanded.length - 1;
|
||||
}
|
||||
}
|
||||
return results;
|
||||
}
|
||||
|
||||
function start(configName, options, callback) {
|
||||
console.log("Starting", configName);
|
||||
|
||||
var argv = options.argv;
|
||||
var settingsName = argv.settings;
|
||||
|
||||
|
@ -90,8 +126,8 @@ function start(configName, options, callback) {
|
|||
if (argv.domain) {
|
||||
settings.c9.domain = argv.domain;
|
||||
for (var s in settings) {
|
||||
settings[s].baseUrl = settings[s].baseUrl
|
||||
&& settings[s].baseUrl.replace(/[^./]+\.[^.]+$/, argv.domain);
|
||||
if (settings[s] && settings[s].baseUrl)
|
||||
settings[s].baseUrl = replaceDomain(settings[s].baseUrl, argv.domain);
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -139,3 +175,7 @@ function start(configName, options, callback) {
|
|||
});
|
||||
});
|
||||
}
|
||||
|
||||
function replaceDomain(url, domain) {
|
||||
return url.replace(/[^./]+\.[^./]+$/, domain).replace(/[^./]+\.[^.]+\//, domain + "/");
|
||||
}
|
Ładowanie…
Reference in New Issue