diff --git a/.gitignore b/.gitignore index 2700de4a..cf6e349e 100644 --- a/.gitignore +++ b/.gitignore @@ -84,4 +84,4 @@ foo.js hello.js plugins/c9.docker/containers/ci/files/github_c9_newclient plugins/c9.docker/containers/shared/files/plugins/salesforce* -security-audit.log +security-audit.log \ No newline at end of file diff --git a/build/browser_extensions/chrome/manifest.json b/build/browser_extensions/chrome/manifest.json index 7939147b..8c44b02e 100644 --- a/build/browser_extensions/chrome/manifest.json +++ b/build/browser_extensions/chrome/manifest.json @@ -1,7 +1,7 @@ { "app": { "launch": { - "web_url": "http://c9.io/" + "web_url": "http://c9.io/#1page" }, "urls": [ "https://c9.io/", "https://www.c9.io/", "https://ide.c9.io/", diff --git a/configs/client-default.js b/configs/client-default.js index a9b3d229..372a64ed 100644 --- a/configs/client-default.js +++ b/configs/client-default.js @@ -321,7 +321,82 @@ module.exports = function(options) { "plugins/c9.ide.language.javascript/javascript", "plugins/c9.ide.language.javascript.immediate/immediate", "plugins/c9.ide.language.javascript.infer/jsinfer", - "plugins/c9.ide.language.javascript.tern/tern", + { + packagePath: "plugins/c9.ide.language.javascript.tern/tern", + plugins: [ + { + name: "angular", + path: "tern/plugin/angular", + enabled: true, + hidden: false, + }, + { + name: "doc_comment", + path: "tern/plugin/doc_comment", + enabled: true, + hidden: true, + }, + { + name: "es_modules", + path: "tern/plugin/es_modules", + enabled: true, + hidden: true, + }, + { + name: "modules", + path: "tern/plugin/modules", + enabled: true, + hidden: true, + }, + { + name: "node", + path: "tern/plugin/node", + enabled: true, + hidden: false, + }, + { + name: "requirejs", + path: "tern/plugin/requirejs", + enabled: true, + hidden: false, + }, + { + name: "architect_resolver", + path: "./architect_resolver_worker", + enabled: true, + hidden: true, + }, + ], + defs: [{ + name: "ecma5", + enabled: true, + experimental: false, + firstClass: true, + path: "lib/tern/defs/ecma5.json" + }, { + name: "jQuery", + enabled: true, + experimental: false, + path: "lib/tern/defs/jquery.json" + }, { + name: "browser", + enabled: true, + experimental: false, + firstClass: true, + path: "lib/tern/defs/browser.json" + }, { + name: "underscore", + enabled: false, + experimental: false, + path: "lib/tern/defs/underscore.json" + }, { + name: "chai", + enabled: false, + experimental: false, + path: "lib/tern/defs/chai.json" + }] + }, + "plugins/c9.ide.language.javascript.tern/ui", "plugins/c9.ide.language.javascript.tern/architect_resolver", "plugins/c9.ide.language.javascript.eslint/eslint", { diff --git a/node_modules/ace_tree/lib/ace_tree/mouse/default_handlers.js b/node_modules/ace_tree/lib/ace_tree/mouse/default_handlers.js index 83fbcd47..b568a458 100644 --- a/node_modules/ace_tree/lib/ace_tree/mouse/default_handlers.js +++ b/node_modules/ace_tree/lib/ace_tree/mouse/default_handlers.js @@ -172,7 +172,8 @@ function DefaultHandlers(mouseHandler) { }; this.onMouseUp = function(ev) { - if (this.isMousePressed) return; + if (this.isMousePressed == 2) return; // wait until release capture + this.isMousePressed = false; var pos = ev.getDocumentPosition(); var node = this.editor.provider.findItemAtOffset(pos.y); if (node && this.$clickNode && this.$clickNode == node) { diff --git a/node_modules/ace_tree/lib/ace_tree/mouse/mouse_handler.js b/node_modules/ace_tree/lib/ace_tree/mouse/mouse_handler.js index 77cf4235..acaf0b49 100644 --- a/node_modules/ace_tree/lib/ace_tree/mouse/mouse_handler.js +++ b/node_modules/ace_tree/lib/ace_tree/mouse/mouse_handler.js @@ -87,7 +87,7 @@ var MouseHandler = function(editor) { this.x = ev.x; this.y = ev.y; - this.isMousePressed = true; + this.isMousePressed = 2; // do not move textarea during selection var renderer = this.editor.renderer; diff --git a/node_modules/c9/format-user-analytics.js b/node_modules/c9/format-user-analytics.js index 28d737fb..eeb88798 100644 --- a/node_modules/c9/format-user-analytics.js +++ b/node_modules/c9/format-user-analytics.js @@ -1,7 +1,7 @@ -if (define === undefined) { - var define = function(fn) { - fn(require, exports, module); - }; +if (typeof define === "undefined") { + var define = function(fn) { + fn(require, exports, module); + }; } define(function(require, exports, module) { @@ -11,7 +11,7 @@ define(function(require, exports, module) { if (!user) return {}; // empty traits get ignored var traits = { - uid: user.id || user.uid, + uid: user.id, username: user.name || user.username, email: user.email, createdAt: user.date_add, diff --git a/node_modules/c9/has-internal-domain.js b/node_modules/c9/has-internal-domain.js index cf74b050..56dc4da6 100644 --- a/node_modules/c9/has-internal-domain.js +++ b/node_modules/c9/has-internal-domain.js @@ -1,7 +1,7 @@ -if (define === undefined) { - var define = function(fn) { - fn(require, exports, module); - }; +if (typeof define === "undefined") { + var define = function(fn) { + fn(require, exports, module); + }; } define(function(require, exports, module) { diff --git a/node_modules/c9/has-internal-test-name.js b/node_modules/c9/has-internal-test-name.js index 82f65452..8cf64735 100644 --- a/node_modules/c9/has-internal-test-name.js +++ b/node_modules/c9/has-internal-test-name.js @@ -1,7 +1,7 @@ -if (define === undefined) { - var define = function(fn) { - fn(require, exports, module); - }; +if (typeof define === "undefined") { + var define = function(fn) { + fn(require, exports, module); + }; } define(function(require, exports, module) { @@ -10,12 +10,10 @@ define(function(require, exports, module) { var internalTestNames = ["c9test", "c9 test"]; var regex = new RegExp("^(" + internalTestNames.join("|") + ")+"); - function hasInternalTestName(user) { - if (!user.name && !user.username) return false; + function hasInternalTestName(name) { + if (!name) return false; - var testedName = user.name ? user.name : user.username; - - return regex.test(testedName); + return regex.test(name); } module.exports = hasInternalTestName; diff --git a/node_modules/c9/hostname.js b/node_modules/c9/hostname.js index 5371df02..8d079f19 100644 --- a/node_modules/c9/hostname.js +++ b/node_modules/c9/hostname.js @@ -1,14 +1,30 @@ var fs = require("fs"); exports.parse = function(hostname) { - var parts = hostname.split("-"); - return { - type: parts[0], - provider: parts[1], - region: parts[2], - index: parts[3], - env: parts[4] - }; + + var m1 = hostname.match(/^([0-9a-z-]+?)-gce-([a-z]+)-([0-9]+)-([a-z0-9]+)$/); + var m2 = hostname.match(/^([0-9a-z-]+?)-gce-([a-z]+)-([a-z0-9]+)-([a-z0-9]{4})$/); + + if (m1) { + return { + type: m1[1], + provider: "gce", + region: m1[2], + index: m1[3], + env: m1[4] + }; + } + else if (m2) { + return { + type: m2[1], + provider: "gce", + region: m2[2], + env: m2[3], + index: m2[4] + }; + } else { + return {}; + } }; exports.get = function() { diff --git a/node_modules/c9/hostname_test.js b/node_modules/c9/hostname_test.js new file mode 100644 index 00000000..bca81758 --- /dev/null +++ b/node_modules/c9/hostname_test.js @@ -0,0 +1,25 @@ +/*global describe it before after beforeEach afterEach define*/ +"use strict"; +"use server"; +"use mocha"; + +require("c9/inline-mocha")(module); + +var assert = require("assert-diff"); +var hostname = require("./hostname"); + +describe(__filename, function() { + + function assertServerName(sn, type, region, index, env) { + assert.equal(sn.type, type); + assert.equal(sn.region, region); + assert.equal(sn.index, index); + assert.equal(sn.env, env); + } + + it("parse hostname", function() { + assertServerName(hostname.parse("fabian-gce-eu-04-dev"), "fabian", "eu", "04", "dev"); + assertServerName(hostname.parse("newclient-gce-eu-prod-d4fg"), "newclient", "eu", "d4fg", "prod"); + assertServerName(hostname.parse("ide-old-gce-usw-02-prod"), "ide-old", "usw", "02", "prod"); + }); +}); diff --git a/node_modules/c9/scm_url_parse.js b/node_modules/c9/scm_url_parse.js index cc39f02c..174e6c66 100644 --- a/node_modules/c9/scm_url_parse.js +++ b/node_modules/c9/scm_url_parse.js @@ -1,3 +1,9 @@ +if (typeof define === "undefined") { + var define = function(fn) { + fn(require, exports, module); + }; +} + define(function(require, exports, module) { "use strict"; diff --git a/node_modules/c9/skip-analytics.js b/node_modules/c9/skip-analytics.js index 4a64d0d6..4325d3f8 100644 --- a/node_modules/c9/skip-analytics.js +++ b/node_modules/c9/skip-analytics.js @@ -1,7 +1,7 @@ -if (define === undefined) { - var define = function(fn) { - fn(require, exports, module); - }; +if (typeof define === "undefined") { + var define = function(fn) { + fn(require, exports, module); + }; } define(function(require, exports, module) { @@ -10,21 +10,21 @@ define(function(require, exports, module) { var hasInternalDomain = require("c9/has-internal-domain"); var hasInternalTestName = require("c9/has-internal-test-name"); - function skipAnalytics(user, allowUnauthorized) { - if (!user) return true; + function skipAnalytics(userId, name, email, allowUnauthorized) { - if (!allowUnauthorized && hasUnauthorizedId(user)) return true; + if (typeof userId == "object") { + var user = userId; + return skipAnalytics(user.id, user.name || user.username, user.email, name); // make it backwards compatible for the client + } + + if (!userId) return true; // users without an id should never reach the Segment library + + if (!allowUnauthorized && userId === -1) return true; - if (hasInternalTestName(user)) return true; - if (hasInternalDomain(user.email)) return true; + if (hasInternalTestName(name)) return true; + if (hasInternalDomain(email)) return true; return false; } - function hasUnauthorizedId(user) { - if (user.id === -1) return true; - - if (!user.id && user.uid === -1) return true; - } - module.exports = skipAnalytics; }); \ No newline at end of file diff --git a/node_modules/c9/skip-analytics_test.js b/node_modules/c9/skip-analytics_test.js index fe09f097..70c6a55a 100644 --- a/node_modules/c9/skip-analytics_test.js +++ b/node_modules/c9/skip-analytics_test.js @@ -8,10 +8,10 @@ var skipAnalytics = require("c9/skip-analytics"); describe("skip-analytics", function() { - it("returns true when user undefined", function() { + it("returns true when user or user id undefined", function() { var user; - assert.equal(true, skipAnalytics(user), "skipAnalytics should return true when user undefined"); + assert.equal(true, skipAnalytics(null, user), "skipAnalytics should return true when user undefined"); }); it("returns true when user id is -1", function() { diff --git a/node_modules/c9/urls.js b/node_modules/c9/urls.js index 0ce9c60e..197f4ddb 100644 --- a/node_modules/c9/urls.js +++ b/node_modules/c9/urls.js @@ -94,9 +94,6 @@ function getBaseUrl(req, sourceBaseUrlPattern, targetBaseUrlPattern) { targetHost = "c9.io"; } - if (/^(ide|vfs)./.test(targetHost)) - console.trace("Warning: possibly incorrect baseUrl constructed, with 'ide.' in the hostname: " + targetHost); - return replaceDomain(targetBaseUrlPattern, targetHost) .replace(/\/$/, ""); } diff --git a/node_modules/vfs-http-adapter/restful.js b/node_modules/vfs-http-adapter/restful.js index 1360f757..2d6c53eb 100644 --- a/node_modules/vfs-http-adapter/restful.js +++ b/node_modules/vfs-http-adapter/restful.js @@ -24,7 +24,7 @@ module.exports = function setup(mount, vfs, mountOptions) { else if (err.code === "ENOTREADY") res.statusCode = 503; else if (err.code === "EISDIR") res.statusCode = 503; else res.statusCode = 500; - var message = (err.stack || err) + "\n"; + var message = (err.message || err.toString()) + "\n"; res.setHeader("Content-Type", "text/plain"); res.setHeader("Content-Length", Buffer.byteLength(message)); res.end(message); diff --git a/node_modules/vfs-local/localfs.js b/node_modules/vfs-local/localfs.js index b3494d57..3ce6bd52 100644 --- a/node_modules/vfs-local/localfs.js +++ b/node_modules/vfs-local/localfs.js @@ -322,8 +322,8 @@ module.exports = function setup(fsOptions) { var isError = true; if (isError) { - var err = new Error("EACCESS: '" + path + "' not in '" + localRoot + "'"); - err.code = "EACCESS"; + var err = new Error("EACCES: '" + path + "' not in '" + localRoot + "'"); + err.code = "EACCES"; return callback(err); } } @@ -1293,7 +1293,7 @@ module.exports = function setup(fsOptions) { function done() { // Ignore if files is tmp file - if (latest && latest.name.substr(-1) == "~" + if (latest && (latest.name.substr(-1) == "~" || latest.name[1] === "~") && latest.name.charAt(0) == ".") return; @@ -2335,6 +2335,11 @@ module.exports = function setup(fsOptions) { } function extend(name, options, callback) { + if (!name) { + var err = new Error("EACCES: Invalid extension name"); + err.code = "EACCES"; + return callback(err); + } var meta = {}; // Pull from cache if it's already loaded. diff --git a/node_modules/vfs-local/test/test-local.js b/node_modules/vfs-local/test/test-local.js index 7c4e1ef9..8a6c5227 100644 --- a/node_modules/vfs-local/test/test-local.js +++ b/node_modules/vfs-local/test/test-local.js @@ -49,7 +49,7 @@ describe('vfs-local', function () { }); it('should reject paths that resolve outside the root', function (done) { vfs.resolve("/../test-local.js", {}, function (err, meta) { - expect(err).property("code").equals("EACCESS"); + expect(err).property("code").equals("EACCES"); done(); }); }); @@ -893,6 +893,12 @@ describe('vfs-local', function () { }); }); }); + it("should error with EACCES if the same extension name is empty", function (done) { + vfs.extend("", {file: __dirname + "/math.js"}, function (err, meta) { + expect(err).property("code").equal("EACCES"); + done(); + }); + }); it("should allow a redefine if options.redefine is set", function (done) { vfs.extend("test", {file: __dirname + "/math.js"}, function (err, meta) { if (err) throw err; diff --git a/package.json b/package.json index ce705ed6..d1f5c47c 100644 --- a/package.json +++ b/package.json @@ -1,7 +1,7 @@ { "name": "c9", "description": "New Cloud9 Client", - "version": "3.1.1032", + "version": "3.1.1188", "author": "Ajax.org B.V. ", "private": true, "main": "bin/c9", @@ -34,8 +34,8 @@ "rusha": "~0.7.2", "send": "~0.1.4", "simple-mime": "~0.0.8", - "tern": "git://github.com/cloud9ide/tern.git#749e64a0f0fed91f883ff055df37b4bfc9f2d980", - "tern_from_ts": "git://github.com/cloud9ide/tern_from_ts.git#6a0107e602b0d044fe1753533cf31f52cf5fb95a", + "tern": "git://github.com/cloud9ide/tern.git#39015d544d4c00c7899fea4c95c2e5bc2720e68e", + "tern_from_ts": "git://github.com/cloud9ide/tern_from_ts.git#84d51dcb9b16b126a206789d4d4237cde2801fe4", "through": "2.2.0", "tmp": "~0.0.20", "uglify-js": "2.4.16", @@ -56,23 +56,23 @@ "c9" ], "c9plugins": { - "c9.ide.language": "#9d12de412d", + "c9.ide.language": "#76ce872cdc", "c9.ide.language.css": "#be07d72209", - "c9.ide.language.generic": "#2b5cc6275e", + "c9.ide.language.generic": "#a4023db7f6", "c9.ide.language.html": "#9be847c0ce", "c9.ide.language.html.diff": "#24f3608d26", - "c9.ide.language.javascript": "#1a0b1584c2", + "c9.ide.language.javascript": "#c6d102471f", "c9.ide.language.javascript.immediate": "#c8b1e5767a", - "c9.ide.language.javascript.eslint": "#d7b067e838", - "c9.ide.language.javascript.tern": "#f9ba3813d7", - "c9.ide.language.javascript.infer": "#9cf94f77be", - "c9.ide.language.jsonalyzer": "#88c957758e", - "c9.ide.collab": "#10c224f9b8", + "c9.ide.language.javascript.eslint": "#3127e1eba1", + "c9.ide.language.javascript.tern": "#45e5f5b0e5", + "c9.ide.language.javascript.infer": "#0561c69d67", + "c9.ide.language.jsonalyzer": "#243e11bd42", + "c9.ide.collab": "#e2411fc12b", "c9.ide.local": "#a6e689e33b", "c9.ide.find": "#e33fbaed2f", "c9.ide.find.infiles": "#c3bf17286d", "c9.ide.find.replace": "#8cbce45290", - "c9.ide.run.debug": "#8b77a8379d", + "c9.ide.run.debug": "#7dfe32f721", "c9.automate": "#47e2c429c9", "c9.ide.ace.emmet": "#6dc4585e02", "c9.ide.ace.gotoline": "#a8ff07c8f4", @@ -81,9 +81,9 @@ "c9.ide.ace.split": "#0ae0151c78", "c9.ide.ace.statusbar": "#3aab0b67e0", "c9.ide.ace.stripws": "#cf0f42ac59", - "c9.ide.behaviors": "#5ae88f87e1", + "c9.ide.behaviors": "#db32109ebc", "c9.ide.closeconfirmation": "#cee4674141", - "c9.ide.configuration": "#a9066299a2", + "c9.ide.configuration": "#e3c90dcd96", "c9.ide.dialog.wizard": "#7667ec79a8", "c9.ide.fontawesome": "#781602c5d8", "c9.ide.format": "#5ec97fb083", @@ -91,12 +91,12 @@ "c9.ide.imgeditor": "#612e75ef4f", "c9.ide.immediate": "#a962119bec", "c9.ide.installer": "#0fde9f0067", - "c9.ide.language.python": "#03b2523dc7", - "c9.ide.language.go": "#267378d2f3", + "c9.ide.language.python": "#4fad6f5a80", + "c9.ide.language.go": "#8f6d0beae7", "c9.ide.mount": "#915b3d20be", - "c9.ide.navigate": "#38ae100ea1", + "c9.ide.navigate": "#1fbb7cd53b", "c9.ide.newresource": "#981a408a7b", - "c9.ide.openfiles": "#7fa4a97fed", + "c9.ide.openfiles": "#2ae85a9e33", "c9.ide.preview": "#8f87ff2f6a", "c9.ide.preview.browser": "#c5b9a129de", "c9.ide.preview.markdown": "#bc846e1562", @@ -105,15 +105,15 @@ "c9.ide.recentfiles": "#7c099abf40", "c9.ide.remote": "#301d2ab519", "c9.ide.processlist": "#2b12cd1bdd", - "c9.ide.run": "#453aa5f604", + "c9.ide.run": "#f03e4b018e", "c9.ide.run.build": "#0598fff697", - "c9.ide.run.debug.xdebug": "#5553240abe", - "c9.ide.save": "#9461acd953", - "c9.ide.scm": "#930a9e6f00", - "c9.ide.terminal.monitor": "#e26502f0df", - "c9.ide.test": "#8f21f662d3", + "c9.ide.run.debug.xdebug": "#a1b39e0ac4", + "c9.ide.save": "#1ab1840513", + "c9.ide.scm": "#ca3c94b84f", + "c9.ide.terminal.monitor": "#a0d1f02991", + "c9.ide.test": "#a282ec1619", "c9.ide.test.mocha": "#fc053b23d2", - "c9.ide.theme.flat": "#92cda0fb40", + "c9.ide.theme.flat": "#81dadeee55", "c9.ide.threewaymerge": "#229382aa0b", "c9.ide.undo": "#b028bcb4d5", "c9.ide.upload": "#0bd010d3dc", diff --git a/plugins/c9.analytics/mock_analytics.js b/plugins/c9.analytics/mock_analytics.js index c2debf77..c8bb3c06 100644 --- a/plugins/c9.analytics/mock_analytics.js +++ b/plugins/c9.analytics/mock_analytics.js @@ -12,12 +12,11 @@ function plugin(options, imports, register) { register(null, { "analytics": { - log: function() {}, track: function() {}, identify: function() {}, - logClean: function() {}, - trackClean: function() {}, - identifyClean: function() {}, + updateTraits: function() {}, + alias: function() {}, + logClean: function() {} // huh?? } }); } \ No newline at end of file diff --git a/plugins/c9.core/util.js b/plugins/c9.core/util.js index 3ce82161..0fdeb788 100644 --- a/plugins/c9.core/util.js +++ b/plugins/c9.core/util.js @@ -57,7 +57,8 @@ define(function(require, exports, module) { "text/x-csharp": "page_white_csharp", "text/x-java-source": "page_white_cup", "text/x-markdown": "page_white_text", - "text/x-xquery": "page_white_code" + "text/x-xquery": "page_white_code", + "text/x-go": "page_white_code", }; var contentTypes = { @@ -87,6 +88,7 @@ define(function(require, exports, module) { "xhtml": "application/xhtml+xml", "coffee": "text/x-script.coffeescript", "py": "text/x-script.python", + "go": "text/x-go", "java": "text/x-java-source", "logic": "text/x-logiql", diff --git a/plugins/c9.error/error_handler.js b/plugins/c9.error/error_handler.js index a898d16b..af2a29db 100644 --- a/plugins/c9.error/error_handler.js +++ b/plugins/c9.error/error_handler.js @@ -122,7 +122,7 @@ function plugin(options, imports, register) { var allowedErrorKeys = [ "message", "projectState", "premium", "retryIn", "progress", - "oldHost", "blocked", "className", "errors" + "oldHost", "blocked", "className", "errors", "subtype" ]; allowedErrorKeys.forEach(function(key) { diff --git a/plugins/c9.fs/fs.cache.xml.js b/plugins/c9.fs/fs.cache.xml.js index 9d0babbe..da06cc24 100644 --- a/plugins/c9.fs/fs.cache.xml.js +++ b/plugins/c9.fs/fs.cache.xml.js @@ -216,7 +216,7 @@ define(function(require, exports, module) { : (linkInfo ? { link: true, linkStat: { fullPath: linkInfo } } : {}); - stat.mtime = Math.floor(Date.now() / 1000); + stat.mtime = Date.now(); node = createNode(e.path, stat); emit("add", {path : e.path, node : node}); @@ -464,15 +464,30 @@ define(function(require, exports, module) { var parts = path.split("/"); var node = context || model.root; if (!node) { - node = orphans[parts[0]]; //model.realRoot || + node = orphans[parts[0]]; // model.realRoot || if (node) parts.shift(); } if (path == "/") parts.shift(); + var up = 0; + for (var i = parts.length; i--;) { + var p = parts[i]; + if (!p && i || p === ".") { + parts.splice(i, 1); + } + else if (p === "..") { + parts.splice(i, 1); + up++; + } + else if (up) { + parts.splice(i, 1); + up--; + } + } + for (var i = 0; i < parts.length; i++) { var p = parts[i]; - if (!p && i) continue; // allow paths with trailing / if (node) node = node.map && node.map[p]; if (!node) @@ -579,6 +594,14 @@ define(function(require, exports, module) { node.children = null; + if (typeof node.mtime !== "number" && node.mtime) { + // why Date ends up here? + reportError(new Error("Date in fs cache"), { + stat: stat, + mtime: node.mtime, + path: node.path + }); + } if (!updating) { if (!modified.length) modified.push(parent); @@ -629,14 +652,6 @@ define(function(require, exports, module) { }); } else if (key === "children" || key === "isSelected") { prop = null; - } else if (Object.prototype.toString.call(node[key]) == "[object Date]") { - // why Date ends up here? - reportError(new Error("Date in fs cache"), { - key: key, - value: node[key], - path: node.path, - hasParentProp: !!node.parent, - }); } else { prop = lang.deepCopy(node[key]); } diff --git a/plugins/c9.fs/fs.js b/plugins/c9.fs/fs.js index 04e2d42d..f07b7746 100644 --- a/plugins/c9.fs/fs.js +++ b/plugins/c9.fs/fs.js @@ -21,6 +21,7 @@ define(function(require, exports, module) { var stream = require("./fs.streams")(vfs, options.base, options.baseProc, options.cli); var xhr = options.cli ? stream : require("./fs.xhr")(vfs.rest); var uCaseFirst = require("c9/string").uCaseFirst; + var normalize = require("path").normalize; var api = { readFile: xhr.readFile, @@ -65,6 +66,11 @@ define(function(require, exports, module) { if (typeof args[args.length - 1] != "function") throw new Error("Missing callback for " + name); + path = args[0] = normalize(path); + if (name == "rename" || name == "copy" || name == "symlink") { + args[1] = normalize(args[1]); + } + // // TODO disabled to not break local version on windows // if (!/^[!~/]/.test(path)) { // var e = new Error("Invalid path passed to fs " + name); diff --git a/plugins/c9.ide.dialog.common/error.js b/plugins/c9.ide.dialog.common/error.js index dda62571..313bf931 100644 --- a/plugins/c9.ide.dialog.common/error.js +++ b/plugins/c9.ide.dialog.common/error.js @@ -111,7 +111,7 @@ define(function(require, exports, module) { hide(); }); } - error.className = "errorlabel " + error.className = "errorlabel c9error " + (message.className ? message.className : ""); if (!message.noError) { @@ -141,7 +141,7 @@ define(function(require, exports, module) { // Start anim lastClassname = message.className; setTimeout(function() { - error.className = "errorlabel anim " + (offset > 0 ? "fade-in" : "") + error.className = "errorlabel c9error anim " + (offset > 0 ? "fade-in" : "") + " " + (message.className || ""); error.style.top = (offset + topPx) + "px"; error.style.opacity = 1; @@ -164,7 +164,7 @@ define(function(require, exports, module) { if (!error || error.style.display === "none") return callback && callback(); - error.className = "errorlabel anim " + (offset > 0 ? "fade-in " : " ") + error.className = "errorlabel c9error anim " + (offset > 0 ? "fade-in " : " ") + (lastClassname ? lastClassname : ""); if (offset > 0) error.style.opacity = 0; diff --git a/plugins/c9.ide.help/help.xml b/plugins/c9.ide.help/help.xml index f4cd6c88..0050847e 100644 --- a/plugins/c9.ide.help/help.xml +++ b/plugins/c9.ide.help/help.xml @@ -21,13 +21,13 @@

- Arron Bailiss, Bas de Wachter, Dana Ivan, Fabian Jakobs, Harutyun Amirjanyan, - Ivar Pruijn, Justin Dray, Lennart Kats, Luca Cipriani, + Alex Brausewetter, Arron Bailiss, Bas de Wachter, Dana Ivan, + Fabian Jakobs, Harutyun Amirjanyan, Ivar Pruijn, Justin Dray, Lennart Kats, Luca Cipriani, Mostafa Eweda, Matthijs van Henten, Nikolai Onken, Suraj Biyani, Tim Robinson, Ruben Daniels

-

© 2010 — 2015 Cloud9 Inc. All rights reserved

+

© 2010 — 2016 Cloud9 Inc. All rights reserved

diff --git a/plugins/c9.ide.keys/panel.js b/plugins/c9.ide.keys/panel.js index 00e1580e..a2d1cf0f 100644 --- a/plugins/c9.ide.keys/panel.js +++ b/plugins/c9.ide.keys/panel.js @@ -26,6 +26,7 @@ define(function(require, exports, module) { var plugin = new Panel("Ajax.org", main.consumes, { index: options.index || 300, caption: "Commands", + buttonCSSClass: "commands", minWidth: 150, autohide: true, where: options.where || "left" diff --git a/plugins/c9.ide.layout.classic/themes/default-flat-dark.less b/plugins/c9.ide.layout.classic/themes/default-flat-dark.less index 72acde7b..9ba1ada6 100644 --- a/plugins/c9.ide.layout.classic/themes/default-flat-dark.less +++ b/plugins/c9.ide.layout.classic/themes/default-flat-dark.less @@ -798,7 +798,7 @@ @gutter-tooltip-dark-shadow: 1px 1px 6px darken(rgba(0, 0, 0, 0.8), @darken-chrome); @gutter-tooltip-dark-background: darken(#FFF399, @darken-chrome); @gutter-tooltip-dark-border: black; -@gutter-tooltip-dark-color: darken(#e0e3e8, @darken-chrome); +@gutter-tooltip-dark-color: darken(#333, @darken-chrome); @gutter-tooltip-dark-font-smoothing: true; // Splitter diff --git a/plugins/c9.ide.preferences/experimental.js b/plugins/c9.ide.preferences/experimental.js index 541deb98..2b348dc8 100644 --- a/plugins/c9.ide.preferences/experimental.js +++ b/plugins/c9.ide.preferences/experimental.js @@ -55,8 +55,6 @@ define(function(require, exports, module) { /***** Methods *****/ - // =0 means the value should be set to 0 to disable otherwise it is enabled - // =1 means the value should be set to 1 to enable otherwise it is disabled var found = {}; function addExperiment(name, defaultValue, caption){ var uniqueId = name.replace(/\//g, "-"); @@ -105,6 +103,7 @@ define(function(require, exports, module) { plugin.on("unload", function() { loaded = false; drawn = false; + hasAlerted = false; intro = null; }); diff --git a/plugins/c9.ide.server/views/flat-load-screen.html b/plugins/c9.ide.server/views/flat-load-screen.html index 533499e4..f59a85e1 100644 --- a/plugins/c9.ide.server/views/flat-load-screen.html +++ b/plugins/c9.ide.server/views/flat-load-screen.html @@ -34,7 +34,7 @@ "Stop cursing, start coding", "GET /this/workspace#loaded", "Use our Vim mode for extra addictive effect!", - "Not your grandfather's IDE", + "Not your grandmother's IDE", "Now made with 20% more cloud!", "Literally makes your laptop cooler", ]; diff --git a/plugins/c9.ide.tree/tree.js b/plugins/c9.ide.tree/tree.js index 6ba0063e..f130e2b4 100644 --- a/plugins/c9.ide.tree/tree.js +++ b/plugins/c9.ide.tree/tree.js @@ -46,6 +46,7 @@ define(function(require, exports, module) { index: options.index || 100, caption: "Workspace", panelCSSClass: "workspace_files", + buttonCSSClass: "workspace", minWidth: 130, where: options.where || "left" }); @@ -1586,4 +1587,4 @@ define(function(require, exports, module) { tree: plugin }); } -}); \ No newline at end of file +}); diff --git a/plugins/c9.preview/preview.handler.js b/plugins/c9.preview/preview.handler.js index 3bf1f351..41539219 100644 --- a/plugins/c9.preview/preview.handler.js +++ b/plugins/c9.preview/preview.handler.js @@ -212,7 +212,8 @@ define(function(require, exports, module) { } else if (body.indexOf("ENOENT") !== -1 || statusCode == 404) { next(new error.NotFound("File '" + path + "' could not be found!")); } else { - delete req.session.ws[req.ws]; + if (req.session.ws) + delete req.session.ws[req.ws]; var json; try { diff --git a/plugins/c9.vfs.server/vfs.server.js b/plugins/c9.vfs.server/vfs.server.js index 5a117cf3..f2da3e24 100644 --- a/plugins/c9.vfs.server/vfs.server.js +++ b/plugins/c9.vfs.server/vfs.server.js @@ -331,7 +331,7 @@ function plugin(options, imports, register) { .end(function() {}); user.lastVfsAccess = Date.now(); - user.save(function() {}); + user.save && user.save(function() {}); } } diff --git a/plugins/c9.vfs.server/vfs_proxy.js b/plugins/c9.vfs.server/vfs_proxy.js index c73732fb..031cfdf8 100644 --- a/plugins/c9.vfs.server/vfs_proxy.js +++ b/plugins/c9.vfs.server/vfs_proxy.js @@ -34,7 +34,7 @@ module.exports = function(methods, vfsHome, vfsWorkspace) { function wrap(name, excluded) { if (excluded) { - return function(){ + return function() { vfsWorkspace[name].apply(vfsWorkspace, arguments); }; } @@ -43,11 +43,12 @@ module.exports = function(methods, vfsHome, vfsWorkspace) { var args = Array.prototype.slice.call(arguments); PATH_OPTIONS.forEach(function(o) { - options[o] = options[o] && substituteTilde(options[o]); + if (options[o] && typeof options[o] == "string") + options[o] = substituteTilde(options[o]); }); args[1] = options; - if (path.charAt(0) == "~") { + if (typeof path == "string" && path.charAt(0) == "~") { args[0] = substituteTilde(path); vfsHome[name].apply(vfsHome, args); diff --git a/plugins/c9.vfs.server/vfs_proxy_test.js b/plugins/c9.vfs.server/vfs_proxy_test.js new file mode 100644 index 00000000..e91f2e2c --- /dev/null +++ b/plugins/c9.vfs.server/vfs_proxy_test.js @@ -0,0 +1,142 @@ +#!/usr/bin/env node +/*global describe it before after beforeEach afterEach */ +"use strict"; +"use server"; + +require("c9/inline-mocha")(module); + +var assert = require("assert-diff"); +var async = require("async"); +var sinon = require("sinon"); +var vfs = require("vfs-local"); +var vfsProxy = require("./vfs_proxy"); + +describe(__filename, function(){ + + var proxy, home, workspace; + + before(function() { + home = vfs({ + root: __dirname, + testing: true, + checkSymlinks: true + }); + home.root = __dirname; + + workspace = vfs({ + root: __dirname + "/views", + testing: true, + checkSymlinks: true + }); + }); + + beforeEach(function() { + proxy = vfsProxy(Object.keys(home), home, workspace); + }); + + it("should use home for files starting with ~ ", function(done) { + home.readfile = sinon.stub().callsArgWith(2, null, "home"); + workspace.readfile = sinon.stub().callsArgWith(2, null, "workspace"); + + proxy.readfile("~/foo.txt", {}, function(err, data) { + assert(!err, err); + assert.equal(data, "home"); + done(); + }); + }); + + it("should use workspace for files not starting with ~ ", function(done) { + home.readfile = sinon.stub().callsArgWith(2, null, "home"); + workspace.readfile = sinon.stub().callsArgWith(2, null, "workspace"); + + proxy.readfile("foo.txt", {}, function(err, data) { + assert(!err, err); + assert.equal(data, "workspace"); + done(); + }); + }); + + it("should expand ~ to paths relative to 'home'", function(done) { + home.readfile = function(path, options, callback) { + assert.equal(path, "/foo.txt"); + callback(null, "home"); + }; + + proxy.readfile("~/foo.txt", {}, function(err, data) { + assert(!err, err); + assert.equal(data, "home"); + done(); + }); + }); + + it("should expand ~ in options", function(done) { + home.readfile = function(path, options, callback) { + assert.equal(path, "/foo.txt"); + assert.equal(options.target, "/bar"); + assert.equal(options.to, "/juhu"); + assert.equal(options.from, "/kinners"); + + assert.equal(options.stuff, "~/stuff"); + + callback(null, "home"); + }; + + proxy.readfile("~/foo.txt", { + target: "~/bar", + to: "~/juhu", + from: "~/kinners", + stuff: "~/stuff" + }, function(err, data) { + assert(!err, err); + assert.equal(data, "home"); + done(); + }); + }); + + it("should expand some commands to absolute paths", function(done) { + home.execFile = function(path, options, callback) { + assert.equal(path, __dirname + "/foo.txt"); + callback(null, "home"); + }; + + proxy.execFile("~/foo.txt", {}, function(err, data) { + assert(!err, err); + assert.equal(data, "home"); + done(); + }); + }); + + it("should not wrap some commands", function(done) { + async.eachSeries([ + "connect", + "on", + "off", + "emit", + "extend", + "unextend", + "use", + "killtree" + ], function(cmd, next) { + workspace[cmd] = function(path, options, callback) { + assert.equal(path, "~/foo.txt"); + callback(null, "workspace"); + }; + + proxy[cmd]("~/foo.txt", {}, function(err, data) { + assert(!err, err); + assert.equal(data, "workspace"); + next(); + }); + + }, done); + }); + + it("bad execFile arguments should not break the server", function(done) { + workspace.execFile = sinon.stub().callsArgWith(2, null, "done"); + proxy.execFile(['ls', '-a'], {encoding: "utf8"}, function(err, data) { + assert(!err, err); + assert.equal(data, "done"); + done(); + }); + }); +}); diff --git a/plugins/c9.vfs.server/vfs_wrapper.js b/plugins/c9.vfs.server/vfs_wrapper.js index 808f2ff4..8fe1192a 100644 --- a/plugins/c9.vfs.server/vfs_wrapper.js +++ b/plugins/c9.vfs.server/vfs_wrapper.js @@ -83,6 +83,9 @@ module.exports = function(vfs, options) { if (!options.file) return callback(new error.Forbidden("Option 'file' is missing")); + + if (typeof options.file != "string") + return callback(new error.Forbidden("Invalid option 'file'")); if (extendDirectory) { var file = options.file = path.normalize(path.join(extendDirectory, options.file)); diff --git a/plugins/c9.vfs.server/vfs_wrapper_test.js b/plugins/c9.vfs.server/vfs_wrapper_test.js new file mode 100644 index 00000000..4fce788e --- /dev/null +++ b/plugins/c9.vfs.server/vfs_wrapper_test.js @@ -0,0 +1,38 @@ +#!/usr/bin/env node +/*global describe it before after beforeEach afterEach */ +"use strict"; +"use server"; + +require("c9/inline-mocha")(module); + +var assert = require("assert-diff"); +var path = require("path"); +var vfs = require("vfs-local"); +var vfsWrapper = require("./vfs_wrapper"); + +describe(__filename, function(){ + + describe("#extend", function() { + + var wrapper; + + beforeEach(function() { + var home = vfs({ + root: path.normalize(__dirname + "/.."), + testing: true, + }); + + wrapper = vfsWrapper(home, { + root: __dirname + }); + }); + + it("should return an error if file is not passed", function(done) { + wrapper.extend('foo', { file: {} ,encoding: "utf8"}, function(err, data) { + assert(err); + assert.equal(err.message, "Invalid option 'file'"); + done(); + }); + }); + }); +}); diff --git a/plugins/c9.vfs.standalone/standalone.js b/plugins/c9.vfs.standalone/standalone.js index cd2019e7..ea70fea4 100644 --- a/plugins/c9.vfs.standalone/standalone.js +++ b/plugins/c9.vfs.standalone/standalone.js @@ -168,6 +168,8 @@ function plugin(options, imports, register) { }); var path = resolve(__dirname + "/../../build/output/latest.tar.gz"); fs.readlink(path, function(err, target) { + if (err) return next(err); + res.end((target || "").split(".")[0]); }); }); @@ -176,9 +178,19 @@ function plugin(options, imports, register) { var filename = req.params.path; var path = resolve(__dirname + "/../../build/output/" + filename); - res.writeHead(200, {"Content-Type": "application/octet-stream"}); var stream = fs.createReadStream(path); - stream.pipe(res); + stream.on("error", function(err) { + next(err); + }); + stream.on("data", function(data) { + if (!res.headersSent) + res.writeHead(200, {"Content-Type": "application/octet-stream"}); + + res.write(data); + }); + stream.on("end", function(data) { + res.end(); + }); }); api.get("/configs/require_config.js", function(req, res, next) { diff --git a/scripts/install-sdk.sh b/scripts/install-sdk.sh index 70f0eb11..38448df0 100755 --- a/scripts/install-sdk.sh +++ b/scripts/install-sdk.sh @@ -110,8 +110,9 @@ updateCore() { fi # without this git merge fails on windows - mv ./scripts/install-sdk.sh ./scripts/.install-sdk-tmp.sh - cp ./scripts/.install-sdk-tmp.sh ./scripts/install-sdk.sh + mv ./scripts/install-sdk.sh './scripts/.#install-sdk-tmp.sh' + rm ./scripts/.install-sdk-tmp.sh + cp './scripts/.#install-sdk-tmp.sh' ./scripts/install-sdk.sh git checkout -- ./scripts/install-sdk.sh git remote add c9 https://github.com/c9/core 2> /dev/null || true diff --git a/server.js b/server.js index f04bc837..704ea32b 100755 --- a/server.js +++ b/server.js @@ -12,6 +12,7 @@ var optimist = require("optimist"); var async = require("async"); var os = require("os"); var urls = require("c9/urls"); +var hostname = require("c9/hostname"); var child_process = require("child_process"); require("c9/setup_paths.js"); @@ -45,7 +46,7 @@ shortcuts.localdev = shortcuts.onlinedev.concat([ shortcuts.odev = shortcuts.onlinedev; // For backwards compatibility, if you see this in 2016 remove this line var delayLoadConfigs = [ // Services that are usually not immediately needed - "preview", "user-content", "api", "apps-proxy", "worker", + "preview", "user-content", "apps-proxy", "worker", "homepage", // Services that are very slow to load, blocking others "profile", ]; @@ -56,9 +57,7 @@ if (!module.parent) main(process.argv.slice(2)); function getDefaultSettings() { - var hostname = os.hostname(); - - var suffix = hostname.trim().split("-").pop() || ""; + var suffix = hostname.parse(os.hostname()).env; var modes = { "workflowstaging": "workflow-staging", "prod": "deploy",