diff --git a/.gitignore b/.gitignore index 5226b321..8eccae7c 100644 --- a/.gitignore +++ b/.gitignore @@ -70,8 +70,8 @@ plugins/c9.proxy/proxy.cfg plugins/c9.proxy/haproxy plugins/c9.proxy/haproxy-* **/.module-cache/ -plugins/c9.account.billing/node_modules/ plugins/c9.account/node_modules/ +plugins/c9.account.*/node_modules/ .c9revisions .settings diff --git a/configs/cli.js b/configs/cli.js index fef801e9..8d95eff0 100644 --- a/configs/cli.js +++ b/configs/cli.js @@ -1,6 +1,12 @@ module.exports = function(options) { +// workaround for api difference between node and c9 events modules var EventEmitter = require("events").EventEmitter; +var emit_ = EventEmitter.prototype.emit +EventEmitter.prototype.emit = function() { + emit_.apply(this, arguments); + return true; +} var PID = process.env.C9_PID || 526; var APIHOST = process.env.C9_APIHOST || "api.c9.io"; // "api.c9.io"; @@ -36,6 +42,16 @@ return [ projectId: PID, apiHost: APIHOST }, + { + packagePath: "./c9.cli.publish/install", + projectId: PID, + apiHost: APIHOST + }, + { + packagePath: "./c9.cli.publish/list", + projectId: PID, + apiHost: APIHOST + }, { packagePath: "./c9.ide.auth/auth", accessToken: "token", @@ -65,11 +81,34 @@ return [ packagePath: "./c9.cli.open/restart", platform: process.platform }, + "./c9.automate/automate", + "./c9.ide.installer/commands/centos", + "./c9.ide.installer/commands/darwin", + "./c9.ide.installer/commands/bash", + "./c9.ide.installer/commands/npm", + "./c9.ide.installer/commands/pip", + "./c9.ide.installer/commands/gem", + "./c9.ide.installer/commands/zip", + "./c9.ide.installer/commands/symlink", + "./c9.ide.installer/commands/message", + { + packagePath: "./c9.ide.installer/commands/tar.gz", + bashBin: "bash" + }, + "./c9.ide.installer/commands/ubuntu", + "./c9.ide.installer/cli", + { + packagePath: "./c9.ide.installer/installer", + homeDir: process.env.HOME, + installSelfCheck: false, + installPath: process.env.HOME + "/.c9", + cli: true + }, // "./c9.cli.sync/sync", //"./c9.ide.keys/commands", { consumes: [], - provides: ["settings", "workspace", "cli_commands", "c9"], + provides: ["settings", "workspace", "cli_commands", "c9", "error_handler"], setup: function(options, imports, register) { register(null, { // @todo share with ace min @@ -78,7 +117,12 @@ return [ debug: true, hosted: false, local: true, - setStatus: function(){} + home: process.env.HOME, + setStatus: function(){}, + location: "" + }, + error_handler: { + log: function(){} }, workspace: (function(){ var ws = new EventEmitter(); diff --git a/configs/client-default.js b/configs/client-default.js index 39874673..789b64f7 100644 --- a/configs/client-default.js +++ b/configs/client-default.js @@ -515,6 +515,7 @@ module.exports = function(options) { }, "plugins/c9.ide.panels/panel", "plugins/c9.ide.panels/area", + "plugins/c9.ide.processlist/processlist", // Installer { @@ -523,9 +524,14 @@ module.exports = function(options) { }, "plugins/c9.automate/automate", "plugins/c9.ide.installer/commands/centos", + "plugins/c9.ide.installer/commands/darwin", "plugins/c9.ide.installer/commands/bash", "plugins/c9.ide.installer/commands/npm", + "plugins/c9.ide.installer/commands/pip", + "plugins/c9.ide.installer/commands/gem", + "plugins/c9.ide.installer/commands/zip", "plugins/c9.ide.installer/commands/symlink", + "plugins/c9.ide.installer/commands/message", { packagePath: "plugins/c9.ide.installer/commands/tar.gz", bashBin: options.bashBin diff --git a/node_modules/ace/lib/ace/ext/modelist.js b/node_modules/ace/lib/ace/ext/modelist.js index 7a5a1e9c..6bc79c8b 100644 --- a/node_modules/ace/lib/ace/ext/modelist.js +++ b/node_modules/ace/lib/ace/ext/modelist.js @@ -122,7 +122,7 @@ var supportedModes = { Pascal: ["pas|p"], Perl: ["pl|pm"], pgSQL: ["pgsql"], - PHP: ["php|phtml"], + PHP: ["php|phtml|shtml|php3|php4|php5|phps|phpt|aw|ctp"], Powershell: ["ps1"], Praat: ["praat|praatscript|psc|proc"], Prolog: ["plg|prolog"], diff --git a/node_modules/ace/lib/ace/layer/text.js b/node_modules/ace/lib/ace/layer/text.js index ced2c5f1..1e80b684 100644 --- a/node_modules/ace/lib/ace/layer/text.js +++ b/node_modules/ace/lib/ace/layer/text.js @@ -52,7 +52,7 @@ var Text = function(parentEl) { this.EOL_CHAR_LF = "\xAC"; this.EOL_CHAR_CRLF = "\xa4"; this.EOL_CHAR = this.EOL_CHAR_LF; - this.TAB_CHAR = "\u2192"; //"\u21E5"; + this.TAB_CHAR = "\u2014"; //"\u21E5"; this.SPACE_CHAR = "\xB7"; this.$padding = 0; @@ -128,8 +128,7 @@ var Text = function(parentEl) { for (var i = 1; i < tabSize + 1; i++) { if (this.showInvisibles) { tabStr.push("" - + this.TAB_CHAR - + lang.stringRepeat(" ", i - 1) + + lang.stringRepeat(this.TAB_CHAR, i) + ""); } else { tabStr.push(lang.stringRepeat(" ", i)); @@ -145,7 +144,7 @@ var Text = function(parentEl) { spaceClass = " ace_invisible_space"; tabClass = " ace_invisible_tab"; var spaceContent = lang.stringRepeat(this.SPACE_CHAR, this.tabSize); - var tabContent = this.TAB_CHAR + lang.stringRepeat(" ", this.tabSize - 1); + var tabContent = lang.stringRepeat(this.TAB_CHAR, this.tabSize); } else{ var spaceContent = lang.stringRepeat(" ", this.tabSize); var tabContent = spaceContent; diff --git a/node_modules/ace/lib/ace/mode/behaviour/behaviour_test.js b/node_modules/ace/lib/ace/mode/behaviour/behaviour_test.js index 9dc27bf8..245edf99 100644 --- a/node_modules/ace/lib/ace/mode/behaviour/behaviour_test.js +++ b/node_modules/ace/lib/ace/mode/behaviour/behaviour_test.js @@ -144,6 +144,16 @@ module.exports = { exec("selectleft", 1); exec("insertstring", 1, '"'); assert.equal(editor.getValue(), '("foo")'); + + editor.setValue("", 1); + exec("selectleft", 1); + exec("insertstring", 1, '"'); + assert.equal(editor.getValue(), '""'); + exec("insertstring", 1, '\\'); + exec("insertstring", 1, 'n'); + exec("insertstring", 1, '"'); + assert.equal(editor.getValue(), '"\\n"'); + }, "test: xml": function() { editor = new Editor(new MockRenderer()); diff --git a/node_modules/ace/lib/ace/mode/behaviour/cstyle.js b/node_modules/ace/lib/ace/mode/behaviour/cstyle.js index a1dce91e..dd1b0d14 100644 --- a/node_modules/ace/lib/ace/mode/behaviour/cstyle.js +++ b/node_modules/ace/lib/ace/mode/behaviour/cstyle.js @@ -269,8 +269,8 @@ var CstyleBehaviour = function() { if (leftChar == "\\" && token && /escape/.test(token.type)) return null; - var stringBefore = token && /string/.test(token.type); - var stringAfter = !rightToken || /string/.test(rightToken.type); + var stringBefore = token && /string|escape/.test(token.type); + var stringAfter = !rightToken || /string|escape/.test(rightToken.type); var pair; if (rightChar == quote) { diff --git a/node_modules/ace/lib/ace/mode/handlebars.js b/node_modules/ace/lib/ace/mode/handlebars.js index 3f2e7179..164ad43f 100644 --- a/node_modules/ace/lib/ace/mode/handlebars.js +++ b/node_modules/ace/lib/ace/mode/handlebars.js @@ -13,7 +13,6 @@ var Mode = function() { HtmlMode.call(this); this.HighlightRules = HandlebarsHighlightRules; this.$behaviour = new HtmlBehaviour(); - this.foldingRules = new HtmlFoldMode(); }; @@ -21,7 +20,7 @@ var Mode = function() { oop.inherits(Mode, HtmlMode); (function() { - this.blockComment = {start: "{!--", end: "--}"}; + this.blockComment = {start: "{{!--", end: "--}}"}; this.$id = "ace/mode/handlebars"; }).call(Mode.prototype); diff --git a/node_modules/ace/lib/ace/theme/katzenmilch.css b/node_modules/ace/lib/ace/theme/katzenmilch.css index 0b5a7a23..a4559a2a 100644 --- a/node_modules/ace/lib/ace/theme/katzenmilch.css +++ b/node_modules/ace/lib/ace/theme/katzenmilch.css @@ -40,7 +40,7 @@ .ace-katzenmilch .ace_marker-layer .ace_bracket { margin: -1px 0 0 -1px; - border: 1px solid #000000 + border: 1px solid rgba(0, 0, 0, 0.33); } .ace-katzenmilch .ace_marker-layer .ace_active-line { diff --git a/node_modules/architect-build/compress.js b/node_modules/architect-build/compress.js index f4e52eaa..343f5d70 100644 --- a/node_modules/architect-build/compress.js +++ b/node_modules/architect-build/compress.js @@ -17,7 +17,7 @@ function compress(sources, opts) { if (pkg.file) console.log("Adding '" + pkg.file + "'."); toplevel = UglifyJS.parse(pkg.source, { - filename: pkg.file.replace(new RegExp("^" + opts.basepath + "/"), ""), //@todo remove prefix + filename: (pkg.file || pkg.id).replace(new RegExp("^" + opts.basepath + "/"), ""), //@todo remove prefix toplevel: toplevel }); }); diff --git a/node_modules/architect-build/npm_build.js b/node_modules/architect-build/npm_build.js index 8912b0df..1bc1a643 100644 --- a/node_modules/architect-build/npm_build.js +++ b/node_modules/architect-build/npm_build.js @@ -157,8 +157,9 @@ function build(base, args, cb) { plugin.packagePath_orig = plugin.packagePath; }); }; - server(args, null, function(err, config) { + server(args, null, function(err, config, configPath) { addModule("server.js"); + addModule(configPath); config.forEach(function(plugin) { if (plugin.packagePath) addModule(relPath(plugin.packagePath)); diff --git a/node_modules/frontdoor/lib/route.js b/node_modules/frontdoor/lib/route.js index 0c699ab7..56343a48 100644 --- a/node_modules/frontdoor/lib/route.js +++ b/node_modules/frontdoor/lib/route.js @@ -137,6 +137,10 @@ module.exports = function Route(route, options, handler, types) { var key = keys[i]; var param = params[key]; var type = param.type; + if (param.optional && value == null) { + match[key] = value; + continue; + } try { value = type.parse(value); } catch (e) { @@ -157,6 +161,7 @@ module.exports = function Route(route, options, handler, types) { * the decoded and validated parameters are stored in `req.params` * otherwhise an error is returned. */ + this.decodeParams = decodeParams; function decodeParams(req, res, next) { var urlParams = req.match; if (!urlParams) return; @@ -197,10 +202,12 @@ module.exports = function Route(route, options, handler, types) { break; value = body[key]; // body is already JSON parsed + if (param.optional && value == null) + break; isValid = type.check(value); break; case "query": - if (param.optional && !(key in query)) + if (param.optional && query[key] == null) break; try { @@ -211,7 +218,7 @@ module.exports = function Route(route, options, handler, types) { isValid = isValid === false ? false : type.check(value); break; case "url": - if (param.optional && !(key in urlParams)) + if (param.optional && urlParams[key] == null) break; value = urlParams[key]; // is already parsed and checked diff --git a/node_modules/frontdoor/lib/route_test.js b/node_modules/frontdoor/lib/route_test.js index 9e11be1c..d1a1bacd 100644 --- a/node_modules/frontdoor/lib/route_test.js +++ b/node_modules/frontdoor/lib/route_test.js @@ -133,7 +133,65 @@ module.exports = { assert.ok(!route.match(req, "/ts/353676299181")); assert.ok(!route.match(req, "/ts/abc")); - } + }, + + "test router: decode parameter in body": function(next) { + var route = new Route("/user", { + params: { + id: { + type: "int", + optional: true, + source: "body" + } + } + }, sinon.stub()); + + var req = { + match: "match", + parsedUrl: { + query: "" + }, + body: { id: 15 } + }; + var res = {}; + + // Note: usually optionals would say 'source: "body",' + // but this should work + route.decodeParams(req, res, function(err, result) { + assert.equal(err, null); + assert.equal(req.params.id, 15); + next(); + }); + }, + + "test router: optional number argument can be falsy": function(next) { + var route = new Route("/user", { + params: { + id: { + type: "int", + optional: true, + source: "body" + } + } + }, sinon.stub()); + + var req = { + match: "match", + parsedUrl: { + query: "" + }, + body: { id: null } + }; + var res = {}; + + // Note: usually optionals would say 'source: "body",' + // but this should work + route.decodeParams(req, res, function(err, result) { + assert.equal(err, null); + assert.equal(req.params.id, null); + next(); + }); + }, }; !module.parent && require("asyncjs").test.testcase(module.exports).exec(); diff --git a/node_modules/vfs-local/localfs.js b/node_modules/vfs-local/localfs.js index 2ecf079e..d43c1756 100644 --- a/node_modules/vfs-local/localfs.js +++ b/node_modules/vfs-local/localfs.js @@ -2409,7 +2409,13 @@ module.exports = function setup(fsOptions) { } //////////////////////////////////////////////////////////////////////////////// - + + if (fsOptions.extendApi) { + for (var i in fsOptions.extendApi) { + extend(i, fsOptions.extendApi[i], function() {}); + } + } + return vfs; }; diff --git a/package.json b/package.json index 629af2af..2dc5c639 100644 --- a/package.json +++ b/package.json @@ -11,7 +11,7 @@ }, "dependencies": { "acorn": ">=0.11.0", - "amd-loader": "~0.0.5", + "amd-loader": "", "async": "^0.9.0", "base64id": "~0.1.0", "c9": "", @@ -60,30 +60,30 @@ "c9.ide.language.javascript.tern": "#7aab8b0b6a", "c9.ide.language.javascript.infer": "#cfec494a3c", "c9.ide.language.jsonalyzer": "#21b64e5820", - "c9.ide.collab": "#504750d8f0", + "c9.ide.collab": "#edef363853", "c9.ide.local": "#2bfd7ff051", "c9.ide.find": "#6cc6d3379d", "c9.ide.find.infiles": "#72582de3cd", "c9.ide.find.replace": "#e4daf722b8", "c9.ide.run.debug": "#638e6b00b3", - "c9.automate": "#b1b0cca13a", + "c9.automate": "#47e2c429c9", "c9.ide.ace.emmet": "#e5f1a92ac3", "c9.ide.ace.gotoline": "#4d1a93172c", "c9.ide.ace.keymaps": "#43445d6306", "c9.ide.ace.repl": "#ada99852fa", "c9.ide.ace.split": "#0ae0151c78", "c9.ide.ace.statusbar": "#d7b45bb7c3", - "c9.ide.ace.stripws": "#34426a03d1", + "c9.ide.ace.stripws": "#cf0f42ac59", "c9.ide.behaviors": "#6aad7006a0", "c9.ide.closeconfirmation": "#a28bfd8272", "c9.ide.configuration": "#adf50fdaa2", - "c9.ide.dialog.wizard": "#ea640aa5a1", + "c9.ide.dialog.wizard": "#7667ec79a8", "c9.ide.fontawesome": "#781602c5d8", "c9.ide.format": "#f51451ac57", "c9.ide.help.support": "#60e88f5680", "c9.ide.imgeditor": "#08bbc53578", "c9.ide.immediate": "#6845a93705", - "c9.ide.installer": "#4c25b26f70", + "c9.ide.installer": "#a1e01c07a3", "c9.ide.mount": "#32e79866ee", "c9.ide.navigate": "#64156c7f4a", "c9.ide.newresource": "#f1f0624768", diff --git a/plugins/c9.cli.publish/install.js b/plugins/c9.cli.publish/install.js new file mode 100644 index 00000000..b1643e22 --- /dev/null +++ b/plugins/c9.cli.publish/install.js @@ -0,0 +1,590 @@ +define(function(require, exports, module) { + main.consumes = [ + "Plugin", "cli_commands", "proc", "api", "auth", "installer", + "installer.cli" + ]; + main.provides = ["cli.install"]; + return main; + + function main(options, imports, register) { + var Plugin = imports.Plugin; + var cmd = imports.cli_commands; + var proc = imports.proc; + var auth = imports.auth; + var api = imports.api; + var installer = imports.installer; + var installerCLI = imports["installer.cli"]; + + var dirname = require("path").dirname; + + var TEST_MODE = !!process.env.C9_TEST_MODE; + var TAR = "tar"; + var APIHOST = options.apiHost; + var BASICAUTH = process.env.C9_TEST_AUTH; + var SCM = { + "git": { + binary: "git", + clone: "clone" + }, + "mercurial": { + binary: "hg", + clone: "clone" + }, + "hg": { + binary: "hg", + clone: "clone" + } + }; + + var fs = require("fs"); + var join = require("path").join; + var os = require("os"); + var http = require(APIHOST.indexOf("localhost") > -1 ? "http" : "https"); + + var verbose = false; + var force = false; + + // Set up basic auth for api if needed + if (BASICAUTH) api.basicAuth = BASICAUTH; + + /***** Initialization *****/ + + var plugin = new Plugin("Ajax.org", main.consumes); + // var emit = plugin.getEmitter(); + + var loaded; + function load(){ + if (loaded) return; + loaded = true; + + cmd.addCommand({ + name: "install", + info: " Installs a cloud9 package.", + usage: "[--verbose] [--force] [--global] [--local] [--debug] [[@] | . ]", + options: { + "local": { + description: "", + "default": false, + "boolean": true + }, + "global": { + description: "", + "default": false, + "boolean": true + }, + "debug": { + description: "", + "default": false, + "boolean": true + }, + "package" : { + description: "", + "default": false + }, + "verbose" : { + "description": "Output more information", + "alias": "v", + "default": false, + "boolean": true + }, + "force" : { + "description": "Ignore warnings", + "alias": "f", + "default": false, + "boolean": true + } + }, + check: function(argv) { + if (argv._.length < 2 && !argv["package"]) + throw new Error("package"); + }, + exec: function(argv) { + verbose = argv["verbose"]; + force = argv["force"]; + + if (argv.accessToken) + auth.accessToken = argv.accessToken; + + if (!argv.local && !argv.debug) { + if (!process.env.C9_PID) { + console.warn("It looks like you are not running on c9.io. Will default to local installation of the package"); + argv.local = true; + } + } + + var name = argv._[1]; + var test = name == "."; + if (test) + name = require("path").basename(process.cwd()); + + install( + name, + { + global: argv.global, + local: argv.local, + debug: argv.debug, + test: test + }, + function(err, data){ + if (err) { + console.error(err.message || "Terminated."); + process.exit(1); + } + else { + console.log("Succesfully installed", name + (argv.debug ? "" : "@" + data.version)); + process.exit(0); + } + }); + } + }); + + cmd.addCommand({ + name: "remove", + info: " Removes a cloud9 package.", + usage: "[--verbose] [--global] [--local] ", // @TODO --global + options: { + "local": { + description: "", + "default": false, + "boolean": true + }, + "global": { + description: "", + "default": false, + "boolean": true + }, + "package" : { + description: "" + }, + "verbose" : { + "description": "Output more information", + "alias": "v", + "default": false, + "boolean": true + } + }, + check: function(argv) { + if (argv._.length < 2 && !argv["package"]) + throw new Error("package"); + }, + exec: function(argv) { + verbose = argv["verbose"]; + + if (argv.accessToken) + auth.accessToken = argv.accessToken; + + var name = argv._[1]; + uninstall( + name, + { + global: argv.global, + local: argv.local + }, + function(err, data){ + if (err) { + console.error(err.message || "Terminated."); + process.exit(1); + } + else { + console.log("Succesfully removed", name); + process.exit(0); + } + }); + } + }); + } + + /***** Methods *****/ + + function install(packageName, options, callback){ + // Call install url + var parts = packageName.split("@"); + var name = parts[0]; + var version = parts[1]; + var repository; + + if ((!version || options.debug) && !options.test) { + if (verbose) + console.log("Retrieving package info"); + + api.packages.get(name, function (err, info) { + if (err) return callback(err); + + if (verbose) + console.log("Found:", info); + + version = info.latest; + repository = info.repository; + + installPackage(); + }); + } + else { + installPackage(); + } + + function prepareDirectory(callback){ + // Create package dir + var packagePath = process.env.HOME + "/.c9/plugins/" + name; + var exists = fs.existsSync(packagePath); + + // Ignore when testing and in the same dir + if (options.test && process.cwd() == packagePath) + exists = false; + + if (exists) { + if (!force && !options.test) + return callback(new Error("WARNING: Directory not empty: " + packagePath + + ". Use --force to overwrite.")); + + proc.execFile("rm", { + args: ["-Rf", packagePath] + }, function(){ + mkdirP(packagePath); + callback(null, packagePath); + }); + } + else { + mkdirP(packagePath); + callback(null, packagePath); + } + } + + function installPackage(){ + if (!version && !options.test) + return callback(new Error("No version found for this package")); + + if (options.local) { + installLocal(); + } + else if (options.debug) { + installDebug(); + } + else { + installFull(); + } + } + + function installLocal(){ + if (verbose) + console.log("Installing package locally"); + + prepareDirectory(function(err, packagePath){ + if (err) return callback(err); + + function installNPM(){ + proc.spawn(join(process.env.HOME, ".c9/node/bin/npm"), { + args: ["install"], + cwd: packagePath + }, function(err, p){ + if (err) return callback(err); + + if (verbose) { + p.stdout.on("data", function(c){ + process.stdout.write(c.toString("utf8")); + }); + p.stderr.on("data", function(c){ + process.stderr.write(c.toString("utf8")); + }); + } + + p.on("exit", function(code){ + // Done + callback(err, { + version: version + }); + }); + }); + } + + if (options.test) { + try { + var json = JSON.parse(fs.readFileSync(join(process.cwd(), "package.json"))); + if (json.private) + return callback(new Error("ERROR: Private flag in package.json prevents from installing")); + } + catch(e) { + return callback(new Error("ERROR: Invalid package: " + e.message)); + } + + if (process.cwd() == packagePath) + installNPM(); + else { + proc.execFile("cp", { + args: ["-R", process.cwd(), dirname(packagePath)] + }, function(err){ + if (err) return callback(err); + + installNPM(); + }); + } + + return; + } + + // Download package + var gzPath = join(os.tmpDir(), name + "@" + version + ".tar.gz"); + var file = fs.createWriteStream(gzPath); + + var path = "/packages/" + name + "/versions/" + version + + "/download?access_token=" + + encodeURIComponent(auth.accessToken); + var host = APIHOST.split(":")[0]; + var port = parseInt(APIHOST.split(":")[1]) || null; + + var request = http.get({ + agent: false, + method: "get", + host: host, + port: port, + auth: BASICAUTH, + path: path + }, function(response){ + response.pipe(file); + }); + + if (verbose) + console.log("Downloading package to", gzPath); + + request.on('response', function(res) { + if (res.statusCode != 200) + return callback(new Error("Unknown Error:" + res.statusCode)); + }); + + file.on('finish', function() { + if (verbose) + console.log("Unpacking", gzPath, "to", packagePath); + + // Untargz package + proc.spawn(TAR, { + args: ["-C", normalizePath(packagePath), "-zxvf", normalizePath(gzPath)] + }, function(err, p){ + if (err) return callback(err); + + if (verbose) { + p.stdout.on("data", function(c){ + process.stdout.write(c.toString("utf8")); + }); + p.stderr.on("data", function(c){ + process.stderr.write(c.toString("utf8")); + }); + } + + p.on("exit", function(code){ + var err = code !== 0 + ? new Error("Failed to unpack package") + : null; + if (err) return callback(err); + + installNPM(); + }); + }); + }); + }); + } + + function installDebug(){ + if (verbose) + console.log("Installing debug version of package"); + + if (!options.test) + return callback(new Error("Dry run is not supported for debug installations")); + + prepareDirectory(function(err, packagePath){ + if (err) return callback(err); + + if (verbose) + console.log("Cloning repository: ", repository); + + // Git clone repository + var scm = SCM[repository.type]; + proc.spawn(scm.binary, { + args: [scm.clone, repository.url, packagePath] + }, function(err, p){ + if (err) return callback(err); + + if (verbose) { + p.stdout.on("data", function(c){ + process.stdout.write(c.toString("utf8")); + }); + p.stderr.on("data", function(c){ + process.stderr.write(c.toString("utf8")); + }); + } + + p.on("exit", function(code){ + var err = code !== 0 + ? new Error("Failed to clone package from repository. Do you have access?") + : null; + + // Done + callback(err); + }); + }); + }); + } + + function installFull(){ + // Install Locally + options.local = true; + install(name + "@" + version, options, function(err){ + if (err) return callback(err); + + var path = process.env.HOME + "/.c9/plugins/" + name; + fs.readFile(path + "/package.json", "utf8", function(err, data){ + if (err) return callback(new Error("Package.json not found in " + path)); + + var installPath; + try { installPath = JSON.parse(data).installer; } + catch(e){ + return callback(new Error("Could not parse package.json in " + path)); + } + + if (installPath) { + installerCLI.verbose = verbose; + installer.createSession(name, version || "", require(path + "/" + installPath), function(err){ + if (err) return callback(new Error("Error Installing Package " + name + "@" + version)); + installToDatabase(); + }, force || options.test); + } + else + installToDatabase(); + }); + + + function installToDatabase(){ + if (options.test) + return callback(null, { version: "test" }); + + if (verbose) + console.log("Notifying c9.io that packages needs to be installed"); + + var endpoint = options.global ? api.user : api.project; + var url = "install/" + packageName + "/" + version + "?mode=silent"; + + endpoint.post(url, function(err, info){ + callback(err, info); + }); + } + }); + } + } + + function uninstall(packageName, options, callback){ + // Call uninstall url + var parts = packageName.split("@"); + var name = parts[0]; + var version = parts[1]; + + if (!version) { + api.packages.get(name, function (err, info) { + if (err) return callback(err); + version = info.latest; + + uninstallPackage(); + }); + } + else { + uninstallPackage(); + } + + function uninstallPackage(){ + if (options.local || options.debug) { + // rm -Rf + var packagePath = process.env.HOME + "/.c9/plugins/" + name; + proc.spawn("rm", { + args: ["-rf", packagePath] + }, function(err, p){ + if (err) return callback(err); + + if (verbose) { + p.stdout.on("data", function(c){ + process.stdout.write(c.toString("utf8")); + }); + p.stderr.on("data", function(c){ + process.stderr.write(c.toString("utf8")); + }); + } + + p.on("exit", function(code){ + var err = code !== 0 + ? new Error("Failed to remove package.") + : null; + + // if debug > see if should be installed and put back original + // @TODO + + // Done + callback(err); + }); + }); + } + else { + var endpoint = options.global ? api.user : api.project; + var url = "uninstall/" + packageName; + + endpoint.post(url, function(err, info){ + callback(err, info); + }); + } + } + } + + function mkdirP(path){ + var dirs = path.split('/'); + var prevDir = dirs.splice(0,1) + "/"; + while (dirs.length > 0) { + var curDir = prevDir + dirs.splice(0,1); + if (! fs.existsSync(curDir) ) { + fs.mkdirSync(curDir); + } + prevDir = curDir + '/'; + } + } + + function normalizePath(p) { + if (process.platform == "win32") + p = p.replace(/\\/g, "/").replace(/^(\w):/, "/$1"); + return p; + } + + /***** Lifecycle *****/ + + plugin.on("load", function(){ + load(); + }); + plugin.on("enable", function(){ + + }); + plugin.on("disable", function(){ + + }); + plugin.on("unload", function(){ + loaded = false; + verbose = false; + force = false; + }); + + /***** Register and definfe API *****/ + + /** + * + **/ + plugin.freezePublicAPI({ + /** + * + */ + install: install, + + /** + * + */ + uninstall: uninstall + }); + + register(null, { + "cli.install": plugin + }); + } + +}); \ No newline at end of file diff --git a/plugins/c9.cli.publish/list.js b/plugins/c9.cli.publish/list.js new file mode 100644 index 00000000..c1511530 --- /dev/null +++ b/plugins/c9.cli.publish/list.js @@ -0,0 +1,131 @@ +define(function(require, exports, module) { + main.consumes = ["Plugin", "cli_commands", "api"]; + main.provides = ["cli.list"]; + return main; + + function main(options, imports, register) { + var Plugin = imports.Plugin; + var cmd = imports.cli_commands; + var api = imports.api; + + var BASICAUTH = process.env.C9_TEST_AUTH; + var verbose = false; + + var LIGHTBlUE = "\x1b[01;94m"; + var RESETCOLOR = "\x1b[0m"; + var PADDING = 2; + + // Set up basic auth for api if needed + if (BASICAUTH) api.basicAuth = BASICAUTH; + + /***** Initialization *****/ + + var plugin = new Plugin("Ajax.org", main.consumes); + // var emit = plugin.getEmitter(); + + var loaded; + function load(){ + if (loaded) return; + loaded = true; + + cmd.addCommand({ + name: "list", + info: " Lists all available packages.", + usage: "[--json]", + options: { + "json": { + description: "", + "default": false, + "boolean": true + }, + }, + check: function(argv) {}, + exec: function(argv) { + verbose = argv["verbose"]; + + list(argv.json, function(err){ + if (err) + console.error(err.message || err); + process.exit(err ? 1 : 0); + }); + } + }); + } + + /***** Methods *****/ + + function stringifyError(err){ + return (verbose ? JSON.stringify(err, 4, " ") : (typeof err == "string" ? err : err.message)); + } + + function pad(str, nr){ + return str + Array(nr - str.length).join(" "); + } + + function list(asJson, callback){ + callback = callback || function(){}; + api.packages.get("", function(err, list){ + if (err) { + console.error("ERROR: Could not get list: ", stringifyError(err)); + return callback(err); + } + // TODO if tty.isatty(process.stdout) use process.stdout.columns process.stdout.rows + // to give nicely wrapped output + if (asJson) { + console.log(JSON.stringify(list, 4, " ")); + return callback(null, list); + } + else { + var max = [0, 0, 0, 0]; + list.forEach(function(item){ + max[0] = Math.max(max[0], item.name.length); + max[1] = Math.max(max[1], Math.min(50, item.description.split(".")[0].length)); + max[2] = Math.max(max[2], item.name.length + 33); + max[3] = Math.max(max[3], (item.website || item.repository.url).length); + }); + list.forEach(function(item){ + console.log( + pad(item.name, max[0] + PADDING), + pad(item.description.split(".")[0], max[1] + PADDING), + LIGHTBlUE + pad("https://c9.io/profile/packages/" + item.name, max[2] + PADDING) + RESETCOLOR, + item.website || item.repository.url); // do not pad last item + }); + return callback(null, list); + } + }); + } + + /***** Lifecycle *****/ + + plugin.on("load", function(){ + load(); + }); + plugin.on("enable", function(){ + + }); + plugin.on("disable", function(){ + + }); + plugin.on("unload", function(){ + loaded = false; + verbose = false; + }); + + /***** Register and definfe API *****/ + + /** + * + **/ + plugin.freezePublicAPI({ + /** + * + */ + list: list + }); + + register(null, { + "cli.list": plugin + }); + } + +}); diff --git a/plugins/c9.cli.publish/publish.git.sh b/plugins/c9.cli.publish/publish.git.sh index f1208cb4..bf32c8d7 100644 --- a/plugins/c9.cli.publish/publish.git.sh +++ b/plugins/c9.cli.publish/publish.git.sh @@ -1,13 +1,13 @@ -PACKAGE_PATH=$1 -VERSION=$2 -CWD=${PWD} +VERSION="$1" +PACKAGE_PATH="$2" +CWD="${PWD}" if [ ! -d .git ]; then echo "$CWD is not a git repository" 1>&2 exit 1 fi -if [ ! -e $PACKAGE_PATH ]; then +if [ ! -f "$PACKAGE_PATH" ]; then echo "Could not find package.json" 1>&2 exit 1 fi diff --git a/plugins/c9.cli.publish/publish.js b/plugins/c9.cli.publish/publish.js index 2ab55d97..8bb04348 100644 --- a/plugins/c9.cli.publish/publish.js +++ b/plugins/c9.cli.publish/publish.js @@ -11,7 +11,7 @@ define(function(require, exports, module) { var api = imports.api; var TEST_MODE = !!process.env.C9_TEST_MODE; - var SHELLSCRIPT = TEST_MODE ? "" : require("text!./publish.git.sh").toString("utf8"); + var SHELLSCRIPT = TEST_MODE ? "" : require("text!./publish.git.sh"); var TAR = "tar"; var APIHOST = options.apiHost; var BASICAUTH = process.env.C9_TEST_AUTH; @@ -43,6 +43,7 @@ define(function(require, exports, module) { var verbose = false; var force = false; var dryRun = false; + var createTag = false; // Set up basic auth for api if needed if (BASICAUTH) api.basicAuth = BASICAUTH; @@ -78,16 +79,23 @@ define(function(require, exports, module) { "description": "Only build a test version", "default": false, "boolean": true + }, + "tag" : { + "description": "Create git tag for published version", + "alias": "t", + "default": false, + "boolean": true } }, check: function(argv) { - if (argv._.length < 2 && !argv["newversion"] && !argv["dry-run"]) - throw new Error("Missing version"); + // if (argv._.length < 2 && !argv["newversion"] && !argv["dry-run"]) + // throw new Error("Missing version"); }, exec: function(argv) { verbose = argv["verbose"]; force = argv["force"]; dryRun = argv["dry-run"]; + createTag = argv["tag"]; publish( argv._[1], @@ -108,9 +116,9 @@ define(function(require, exports, module) { } }); - cmd.addCommand({ + cmd.addCommand({ name: "build", - info: " Builds development version of package to load in non-debug mode.", + info: " Builds development version of package to load in non-debug mode.", usage: "[--devel]", options: { "devel" : { @@ -148,12 +156,12 @@ define(function(require, exports, module) { .trim() .replace(/PACKAGE_NAME/g, packageName); - fs.writeFileSync(cwd + "/__installed__.js", code, "utf8") - } else { - dryRun = true - publish({local: true}, function(err, data){}); + fs.writeFileSync(cwd + "/__installed__.js", code, "utf8"); + } + else { + dryRun = true; + publish({local: true}, function(){}); } - } }); @@ -186,156 +194,6 @@ define(function(require, exports, module) { }); } }); - - cmd.addCommand({ - name: "install", - info: " Installs a cloud9 package.", - usage: "[--verbose] [--force] [--global] [--local] [--debug] [@]", // @TODO --global, --debug, --local - options: { - "local": { - description: "", - "default": false, - "boolean": true - }, - "global": { - description: "", - "default": false, - "boolean": true - }, - "debug": { - description: "", - "default": false, - "boolean": true - }, - "package" : { - description: "", - "default": false - }, - "verbose" : { - "description": "Output more information", - "alias": "v", - "default": false, - "boolean": true - }, - "force" : { - "description": "Ignore warnings", - "alias": "f", - "default": false, - "boolean": true - } - }, - check: function(argv) { - if (argv._.length < 2 && !argv["package"]) - throw new Error("package"); - }, - exec: function(argv) { - verbose = argv["verbose"]; - force = argv["force"]; - - if (argv.accessToken) - auth.accessToken = argv.accessToken; - - if (!argv.local && !argv.debug) { - if (!process.env.C9_PID) { - console.warn("It looks like you are not running on c9.io. Will default to local installation of the package"); - argv.local = true; - } - } - - var name = argv._[1]; - install( - name, - { - global: argv.global, - local: argv.local, - debug: argv.debug - }, - function(err, data){ - if (err) { - console.error(err.message || "Terminated."); - process.exit(1); - } - else { - console.log("Succesfully installed", name + (argv.debug ? "" : "@" + data.version)); - process.exit(0); - } - }); - } - }); - - cmd.addCommand({ - name: "remove", - info: " Removes a cloud9 package.", - usage: "[--verbose] [--global] [--local] ", // @TODO --global - options: { - "local": { - description: "", - "default": false, - "boolean": true - }, - "global": { - description: "", - "default": false, - "boolean": true - }, - "package" : { - description: "" - }, - "verbose" : { - "description": "Output more information", - "alias": "v", - "default": false, - "boolean": true - } - }, - check: function(argv) { - if (argv._.length < 2 && !argv["package"]) - throw new Error("package"); - }, - exec: function(argv) { - verbose = argv["verbose"]; - - if (argv.accessToken) - auth.accessToken = argv.accessToken; - - var name = argv._[1]; - uninstall( - name, - { - global: argv.global, - local: argv.local - }, - function(err, data){ - if (err) { - console.error(err.message || "Terminated."); - process.exit(1); - } - else { - console.log("Succesfully removed", name); - process.exit(0); - } - }); - } - }); - - cmd.addCommand({ - name: "list", - info: " Lists all available packages.", - usage: "[--json]", - options: { - "json": { - description: "", - "default": false, - "boolean": true - }, - }, - check: function(argv) {}, - exec: function(argv) { - verbose = argv["verbose"]; - - list(argv.json); - } - }); } /***** Methods *****/ @@ -344,27 +202,6 @@ define(function(require, exports, module) { return (verbose ? JSON.stringify(err, 4, " ") : (typeof err == "string" ? err : err.message)); } - function list(asJson, callback){ - callback = callback || function(){}; - api.packages.get("", function(err, list){ - if (err) { - console.error("ERROR: Could not get list: ", stringifyError(err)); - return callback(err); - } - - if (asJson) { - console.log(JSON.stringify(list, 4, " ")); - return callback(null, list); - } - else { - list.forEach(function(item){ - console.log(item.name, "https://c9.io/packages/" + item.name); - }); - return callback(null, list); - } - }); - } - function publish(options, callback) { if (typeof options != "object") options = {version: options}; @@ -372,7 +209,7 @@ define(function(require, exports, module) { var version = options.version; var cwd = process.cwd(); var packagePath = cwd + "/package.json"; - fs.readFile(packagePath, function(err, data){ + fs.readFile(packagePath, "utf8", function(err, data){ if (err) return callback(new Error("ERROR: Could not find package.json in " + cwd)); var json; @@ -382,6 +219,8 @@ define(function(require, exports, module) { } // Basic Validation + if (json.private) + return callback(new Error("ERROR: Private flag in package.json prevents from publishing")); if (!json.name) return callback(new Error("ERROR: Missing name property in package.json")); if (basename(cwd) != json.name) { @@ -389,10 +228,10 @@ define(function(require, exports, module) { if (!force) return callback(new Error("Use --force to ignore this warning.")); } - if (!json.description) - return callback(new Error("ERROR: Missing description property in package.json")); if (!json.repository) return callback(new Error("ERROR: Missing repository property in package.json")); + if (!json.repository.url) + return callback(new Error("ERROR: Missing repository.url property in package.json")); if (!json.categories || json.categories.length == 0) return callback(new Error("ERROR: At least one category is required in package.json")); @@ -403,6 +242,12 @@ define(function(require, exports, module) { return callback(new Error("Use --force to ignore these warnings.")); } + if (json.description) + console.warn("WARNING: Description property in package.json will be ignored. README.md will be used."); + + var description = fs.readFileSync(join(cwd, "README.md"), "utf8") + .replace(/^\#.*\n*/, ""); + // Validate plugins var plugins = {}; fs.readdirSync(cwd).forEach(function(filename) { @@ -437,7 +282,7 @@ define(function(require, exports, module) { if (warned && !force && !dryRun) return callback(new Error("Use --force to ignore these warnings.")); - if (!dryRun) { + if (version) { var v = (json.version || "0.0.1").split("."); // Update the version field in the package.json file if (version == "major") { @@ -458,47 +303,26 @@ define(function(require, exports, module) { json.version = v.join("."); } - if (dryRun) - return build(); + return build(); - // Write the package.json file - fs.writeFile(packagePath, JSON.stringify(json, null, " "), function(err){ - if (err) return callback(err); + function updatePackageJSON(next) { + if (!version) + return next(); - if (dryRun) return build(); - - SHELLSCRIPT = SHELLSCRIPT - .replace(/\$1/, packagePath) - .replace(/\$2/, json.version); - - // commit - proc.spawn("bash", { - args: ["-c", SHELLSCRIPT] - }, function(err, p){ - if (err) return callback(err); - - if (verbose) { - p.stdout.on("data", function(c){ - process.stdout.write(c.toString("utf8")); - }); - p.stderr.on("data", function(c){ - process.stderr.write(c.toString("utf8")); - }); - } - - p.on("exit", function(code, stderr, stdout){ - if (code !== 0) - return callback(new Error("ERROR: publish failed with exit code " + code)); - - console.log("Created tag and updated package.json to version", json.version); - - build(); + // Write the package.json file + var indent = data.match(/{\n\r?^ {4}"/) ? 4 : 2; + var newData = JSON.stringify(json, null, indent); + fs.writeFile(cwd + "/.c9/.build/package.json", newData, function(){ + if (dryRun) + return next(); // if dry-run is passed only update path in .build + fs.writeFile(packagePath, newData, function(err){ + if (err) return callback(err); + return next(); }); }); - }); + } // Build the package - // @TODO use a proper package tool // @TODO add a .c9exclude file that excludes files var zipFilePath; function build(){ @@ -622,7 +446,7 @@ define(function(require, exports, module) { extraCode.push({ type: "installer", filename: json.installer, - data: version + data: installerVersion }); } @@ -718,38 +542,62 @@ define(function(require, exports, module) { }); }, function(next) { - var filename = options.local ? "__installed__.js" : "__packed__.js"; - fs.writeFile(filename, result.code, "utf8", next); + if (options.local) + fs.writeFile(cwd + "__installed__.js", result.code, "utf8", callback); + next(); }, function(next) { - // console.log(packedFiles) - if (options.local) - return callback(); - zip(packedFiles); + proc.execFile("rm", { + args: ["-rf", ".c9/.build"], + cwd: cwd + }, function() { + mkdirP(cwd + "/.c9/.build"); + fs.writeFile(cwd + "/.c9/.build/__installed__.js", result.code, "utf8", next); + }); + }, + function(next) { + var copy = require("architect-build/copy"); + + var excludeRe = /^\.(gitignore|hgignore|git|c9|hg)$/; + var excludeMap = Object.create(null); + + packedFiles.push(cwd + "/__installed__.js"); + packedFiles.forEach(function(p) { + p = "/" + normalizePath(Path.relative(cwd, p)); + excludeMap[p] = 1; + }); + copy(cwd, cwd + "/.c9/.build", { + exclude: function(name, parent) { + if (excludeRe.test(name)) + return true; + var fullPath = parent.substr(cwd.length) + "/" + name; + if (excludeMap[fullPath]) + return true; + return false; + } + }); + next(); + }, + updatePackageJSON, + function(next) { + zip(); } ]); } - function zip(ignore){ + function zip(){ zipFilePath = join(os.tmpDir(), json.name + "@" + json.version) + ".tar.gz"; - var tarArgs = ["-zcvf", normalizePath(zipFilePath), "."]; + var tarArgs = ["-zcvf", normalizePath(zipFilePath)]; var c9ignore = normalizePath(process.env.HOME + "/.c9/.c9ignore"); fs.exists(c9ignore, function (exists) { if (exists) { tarArgs.push("--exclude-from=" + c9ignore); } - ignore.forEach(function(p) { - p = Path.relative(cwd, p); - if (!/^\.+\//.test(p)) { - tarArgs.push("--exclude=./" + normalizePath(p)); - } - }); - tarArgs.push("--transform='flags=r;s|__packed__|__installed__|'"); - // console.log(tarArgs) + tarArgs.push("."); proc.spawn(TAR, { args: tarArgs, - cwd: cwd + cwd: cwd + "/.c9/.build" }, function(err, p){ if (err) return callback(err); @@ -798,7 +646,7 @@ define(function(require, exports, module) { contentType: "application/json", body: { name: json.name, - description: json.description, + description: description, owner_type: "user", // @TODO implement this when adding orgs owner_id: parseInt(user.id), permissions: json.permissions || "world", @@ -830,7 +678,7 @@ define(function(require, exports, module) { repository: json.repository, longname: json.longname, website: json.website, - description: json.description, + description: description, screenshots: json.screenshots, pricing: json.pricing, enabled: true @@ -840,7 +688,7 @@ define(function(require, exports, module) { return callback(new Error("ERROR: Failed to update existing package - " + stringifyError(err))); if (verbose) - console.log("Successfully updated existing package"); + console.log("Successfully updated metadata of existing package"); next(pkg); }); @@ -875,15 +723,47 @@ define(function(require, exports, module) { form.pipe(request); request.on('response', function(res) { + // TODO better handle version exists error + if (res.statusCode == 412 && !version) + console.error("ERROR: most likely version " + json.version + " already exisits, try increasing version"); if (res.statusCode != 200) return callback(new Error("ERROR: Unknown Error:" + res.statusCode)); - // Create Version Complete - callback(null, json); + commitAndPush(); }); } }); } + + function commitAndPush() { + // Create Version Complete + if (!createTag) + callback(null, json); + + proc.spawn("bash", { + args: ["-c", SHELLSCRIPT, "--", json.version, normalizePath(packagePath)] + }, function(err, p){ + if (err) return callback(err); + + if (verbose) { + p.stdout.on("data", function(c){ + process.stdout.write(c.toString("utf8")); + }); + p.stderr.on("data", function(c){ + process.stderr.write(c.toString("utf8")); + }); + } + + p.on("exit", function(code, stderr, stdout){ + if (code !== 0) + return callback(new Error("ERROR: publish failed with exit code " + code)); + + console.log("Created tag and updated package.json to version", json.version); + + callback(null, json); + }); + }); + } }); } @@ -905,258 +785,6 @@ define(function(require, exports, module) { }); } - function install(packageName, options, callback){ - // Call install url - var parts = packageName.split("@"); - var name = parts[0]; - var version = parts[1]; - var repository; - - if (!version || options.debug) { - if (verbose) - console.log("Retrieving package info"); - - api.packages.get(name, function (err, info) { - if (err) return callback(err); - - if (verbose) - console.log("Found:", info); - - version = info.latest; - repository = info.repository; - - installPackage(); - }); - } - else { - installPackage(); - } - - function prepareDirectory(callback){ - // Create package dir - var packagePath = process.env.HOME + "/.c9/plugins/" + name; - var exists = fs.existsSync(packagePath) ; - if (exists) { - if (!force) - return callback(new Error("WARNING: Directory not empty: " + packagePath - + ". Use --force to overwrite.")); - - proc.execFile("rm", { - args: ["-Rf", packagePath] - }, function(){ - mkdirP(packagePath); - callback(null, packagePath); - }); - } - else { - mkdirP(packagePath); - callback(null, packagePath); - } - } - - function installPackage(){ - if (!version) - return callback(new Error("No version found for this package")); - - if (options.local) { - if (verbose) - console.log("Installing package locally"); - - prepareDirectory(function(err, packagePath){ - if (err) return callback(err); - - // Download package - var gzPath = join(os.tmpDir(), name + "@" + version + ".tar.gz"); - var file = fs.createWriteStream(gzPath); - - var path = "/packages/" + name + "/versions/" + version - + "/download?access_token=" - + encodeURIComponent(auth.accessToken); - var host = APIHOST.split(":")[0]; - var port = parseInt(APIHOST.split(":")[1]) || null; - - var request = http.get({ - agent: false, - method: "get", - host: host, - port: port, - auth: BASICAUTH, - path: path - }, function(response){ - response.pipe(file); - }); - - if (verbose) - console.log("Downloading package to", gzPath); - - request.on('response', function(res) { - if (res.statusCode != 200) - return callback(new Error("Unknown Error:" + res.statusCode)); - }); - - file.on('finish', function(err) { - if (verbose) - console.log("Unpacking", gzPath, "to", packagePath); - - // Untargz package - proc.spawn(TAR, { - args: ["-C", normalizePath(packagePath), "-zxvf", normalizePath(gzPath)] - }, function(err, p){ - if (err) return callback(err); - - if (verbose) { - p.stdout.on("data", function(c){ - process.stdout.write(c.toString("utf8")); - }); - p.stderr.on("data", function(c){ - process.stderr.write(c.toString("utf8")); - }); - } - - p.on("exit", function(code){ - var err = code !== 0 - ? new Error("Failed to unpack package") - : null; - if (err) return callback(err); - - proc.spawn(join(process.env.HOME, ".c9/node/bin/npm"), { - args: ["install"], - cwd: packagePath - }, function(err, p){ - if (err) return callback(err); - - if (verbose) { - p.stdout.on("data", function(c){ - process.stdout.write(c.toString("utf8")); - }); - p.stderr.on("data", function(c){ - process.stderr.write(c.toString("utf8")); - }); - } - - p.on("exit", function(code){ - // Done - callback(err, { - version: version - }); - }); - }); - }); - }); - }); - }); - } - else if (options.debug) { - if (verbose) - console.log("Installing debug version of package"); - - prepareDirectory(function(err, packagePath){ - if (err) return callback(err); - - if (verbose) - console.log("Cloning repository: ", repository); - - // Git clone repository - var scm = SCM[repository.type]; - proc.spawn(scm.binary, { - args: [scm.clone, repository.url, packagePath] - }, function(err, p){ - if (err) return callback(err); - - if (verbose) { - p.stdout.on("data", function(c){ - process.stdout.write(c.toString("utf8")); - }); - p.stderr.on("data", function(c){ - process.stderr.write(c.toString("utf8")); - }); - } - - p.on("exit", function(code){ - var err = code !== 0 - ? new Error("Failed to clone package from repository. Do you have access?") - : null; - - // Done - callback(err); - }); - }); - }); - } - else { - if (verbose) - console.log("Notifying c9.io that packages needs to be installed"); - - var endpoint = options.global ? api.user : api.project; - var url = "install/" + packageName + "/" + version; - - endpoint.post(url, function(err, info){ - callback(err, info); - }); - } - } - } - - function uninstall(packageName, options, callback){ - // Call uninstall url - var parts = packageName.split("@"); - var name = parts[0]; - var version = parts[1]; - - if (!version) { - api.packages.get(name, function (err, info) { - if (err) return callback(err); - version = info.latest; - - uninstallPackage(); - }); - } - else { - uninstallPackage(); - } - - function uninstallPackage(){ - if (options.local || options.debug) { - // rm -Rf - var packagePath = process.env.HOME + "/.c9/plugins/" + name; - proc.spawn("rm", { - args: ["-rf", packagePath] - }, function(err, p){ - if (err) return callback(err); - - if (verbose) { - p.stdout.on("data", function(c){ - process.stdout.write(c.toString("utf8")); - }); - p.stderr.on("data", function(c){ - process.stderr.write(c.toString("utf8")); - }); - } - - p.on("exit", function(code){ - var err = code !== 0 - ? new Error("Failed to remove package.") - : null; - - // if debug > see if should be installed and put back original - // @TODO - - // Done - callback(err); - }); - }); - } - else { - var endpoint = options.global ? api.user : api.project; - var url = "uninstall/" + packageName; - - endpoint.post(url, function(err, info){ - callback(err, info); - }); - } - } - } - function mkdirP(path){ var dirs = path.split('/'); var prevDir = dirs.splice(0,1) + "/"; @@ -1206,22 +834,7 @@ define(function(require, exports, module) { /** * */ - unpublish: unpublish, - - /** - * - */ - install: install, - - /** - * - */ - uninstall: uninstall, - - /** - * - */ - list: list + unpublish: unpublish }); register(null, { diff --git a/plugins/c9.cli/cli.js b/plugins/c9.cli/cli.js index ab533f32..4a5923fc 100755 --- a/plugins/c9.cli/cli.js +++ b/plugins/c9.cli/cli.js @@ -29,11 +29,6 @@ define(function(require, exports, module) { return false; }); - if (!commands[module] && process.argv.length > 2 && process.argv.every(function(n){ return !n.match(/^--/)})) { - process.argv.splice(2, 0, "open"); - module = "open"; - } - optimist = require('optimist'); if (!module || !commands[module]) { diff --git a/plugins/c9.core/http-xhr.js b/plugins/c9.core/http-xhr.js index aeb2e9d1..9d8eafcd 100644 --- a/plugins/c9.core/http-xhr.js +++ b/plugins/c9.core/http-xhr.js @@ -29,6 +29,8 @@ define(function(require, module, exports) { var timeout = options.hasOwnProperty("timeout") ? options.timeout : 10000; var async = options.sync !== true; var parsedUrl = parseUrl(url, options.query); + if (contentType === "application/json") + headers.Accept = headers.Accept || "application/json"; if (options.username) { headers.Authorization = "Basic " + btoa(options.username + ":" + options.password); diff --git a/plugins/c9.fs/fs.js b/plugins/c9.fs/fs.js index e725d694..a3145076 100644 --- a/plugins/c9.fs/fs.js +++ b/plugins/c9.fs/fs.js @@ -18,7 +18,7 @@ define(function(require, exports, module) { var vfs = imports.vfs; var Plugin = imports.Plugin; - var stream = require("./fs.streams")(vfs, options.base, options.baseProc); + 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; @@ -54,6 +54,8 @@ define(function(require, exports, module) { if (loaded) return false; loaded = true; + if (options.cli) + plugin.on("error", function(e){ console.error(e.error); }); } function wrap(name, fn) { @@ -104,6 +106,7 @@ define(function(require, exports, module) { original_callback.__cb__ = cb; var event = { path: path, args: args, fn: fn }; + if (emit("before" + uCaseFirst(name), event) === false) return false; diff --git a/plugins/c9.fs/fs.streams.js b/plugins/c9.fs/fs.streams.js index 8ab60423..19a5fbfe 100644 --- a/plugins/c9.fs/fs.streams.js +++ b/plugins/c9.fs/fs.streams.js @@ -3,10 +3,14 @@ define(function(require, exports, module) { var Stream = require("stream").Stream; var PATH = require("path"); -return function(vfs, base, baseProc) { +return function(vfs, base, baseProc, cli) { var resolvePath = function(path, basePath) { - if (path.charAt(0) == "~") return path; + if (path.charAt(0) == "~") { + if (cli) + return process.env.HOME + "/" + path.substr(1); + return path; + } if (!basePath) basePath = base; @@ -20,7 +24,7 @@ return function(vfs, base, baseProc) { }; function readFile(path, encoding, callback) { - if (!callback) { + if (!callback || typeof encoding == "function") { callback = encoding; encoding = null; } @@ -28,7 +32,7 @@ return function(vfs, base, baseProc) { var options = {}; if (encoding) options.encoding = encoding; - + vfs.readfile(resolvePath(path), options, function(err, meta) { if (err) return callback(err); @@ -54,7 +58,7 @@ return function(vfs, base, baseProc) { } function writeFile(path, data, encoding, callback) { - if (!callback) { + if (!callback || typeof encoding == "function") { callback = encoding; encoding = null; } diff --git a/plugins/c9.fs/proc2pty.js b/plugins/c9.fs/proc2pty.js index 249cda20..d9b9d562 100644 --- a/plugins/c9.fs/proc2pty.js +++ b/plugins/c9.fs/proc2pty.js @@ -4,7 +4,7 @@ define(function(require, exports, module) { module.exports = function(process){ var pty = new EventEmitter(); pty.write = function(data){ - process.stdin.write(data); + process.stdin.write(data.replace(/\r/g, "\n")); }; pty.resize = function(){}; pty.destroy = @@ -23,5 +23,5 @@ define(function(require, exports, module) { }); return pty; - } + }; }); \ No newline at end of file diff --git a/plugins/c9.ide.errorhandler/raygun_error_handler.js b/plugins/c9.ide.errorhandler/raygun_error_handler.js index 12be8f71..3c3dcca8 100644 --- a/plugins/c9.ide.errorhandler/raygun_error_handler.js +++ b/plugins/c9.ide.errorhandler/raygun_error_handler.js @@ -62,7 +62,9 @@ define(function(require, exports, module) { exception = new Error(exception); if (!exception) exception = new Error("Unspecified error"); - console.error(exception.stack); + console.error(exception); + if (customData) + console.log(customData); Raygun.send(exception, customData, tags); } diff --git a/plugins/c9.ide.experiment/mock_experiment.js b/plugins/c9.ide.experiment/mock_experiment.js new file mode 100644 index 00000000..e3b80734 --- /dev/null +++ b/plugins/c9.ide.experiment/mock_experiment.js @@ -0,0 +1,26 @@ +/** + * Dummy implementation of experiments. + */ +"use strict"; + +plugin.consumes = []; +plugin.provides = ["experiment"]; + +module.exports = plugin; + +function plugin(options, imports, register) { + + register(null, { + "experiment": { + configure: function() {}, + onStart: function() { + var chain = { + variation: function() { + return chain; + } + }; + return chain; + } + } + }); +} \ No newline at end of file diff --git a/plugins/c9.ide.layout.classic/themes/default-dark-gray.less b/plugins/c9.ide.layout.classic/themes/default-dark-gray.less index 6c792f2a..b3ad5668 100644 --- a/plugins/c9.ide.layout.classic/themes/default-dark-gray.less +++ b/plugins/c9.ide.layout.classic/themes/default-dark-gray.less @@ -52,7 +52,7 @@ @ace-cloud9-day-background: lighten(#F8F8F8, @lighten-chrome); @ace-cloud9-night-gutter: @panel-background; @ace-cloud9-night-background: lighten(#181818, @lighten-chrome); -@ace-cloud9-night-active-line: lighten(#292929, @lighten-chrome); +@ace-cloud9-night-active-line: rgba(68, 68, 68, 0.78); // todo make selection lighter #5A5A5A too? @ace-gutter-font-smoothing: true; @ace-gutter-shadow: 1px 0 rgba(255, 255, 255, 0.75) inset; diff --git a/plugins/c9.ide.plugins/loader.js b/plugins/c9.ide.plugins/loader.js index 93ad2aea..7b21a959 100644 --- a/plugins/c9.ide.plugins/loader.js +++ b/plugins/c9.ide.plugins/loader.js @@ -57,8 +57,11 @@ define(function(require, exports, module) { if (loadFromDisk) { fs.readdir("~/.c9/plugins", function handle(err, files){ if (err) { - if (err.code == "EDISCONNECT") - fs.readdir("~/.c9/plugins", handle); + if (err.code == "EDISCONNECT") { + c9.once("connect", function(){ + fs.readdir("~/.c9/plugins", handle); + }); + } console.error(err); return; } diff --git a/plugins/c9.ide.terminal/aceterm/hover_link.js b/plugins/c9.ide.terminal/aceterm/hover_link.js index 409749a8..d38f554b 100644 --- a/plugins/c9.ide.terminal/aceterm/hover_link.js +++ b/plugins/c9.ide.terminal/aceterm/hover_link.js @@ -254,6 +254,45 @@ var HoverLink = function(editor) { match.value = value.replace(/:[^\d][^:]*$/, ""); // match.basePath = ""; } + else if (prompt.command === "ack" || prompt.command === "ag" || prompt.command === "ack-grep") { + match.type = "path"; + var fontColor = lineData[column] && lineData[column][0]; + if (match.start !== 0) { + if (fontColor == session.term.defAttr) + return; + + var col = column; + while (lineData[col] && lineData[col][0] == fontColor) + col--; + match.start = col + 1; + col = column; + while (lineData[col] && lineData[col][0] == fontColor) + col++; + match.value = line.substring(match.start, col); + } + + var jumpLine = line.match(/^(\d*:)?/)[0]; + var jumpColumn = Math.max(match.start - jumpLine.length, 0); + + if (match.start == 0 && jumpLine) + match.value = jumpLine; + + var pathLine = line; + while (/^\d+/.test(pathLine) && row > prompt.row) { + lineData = session.getLineData(row); + if (!lineData.wrapped) { + pathLine = session.getLine(row); + } + row--; + } + + match.path = pathLine; + if (jumpLine) + match.path += ":" + jumpLine + jumpColumn; + + if (match.start == 0 && jumpLine) + match.action = "open"; + } else if (/^(~|\.\.?)?[\/\\]/.test(value) || /\w:[\\]/.test(value)) { match.type = "path"; match.value = value.replace(/['">)}\].,;:]+$/, ""); @@ -325,7 +364,8 @@ var HoverLink = function(editor) { command: command, index: m.index, args: args, - lineData: lineData + lineData: lineData, + row: row }; } if (lineData.isUserInput) diff --git a/plugins/c9.ide.terminal/link_handler.js b/plugins/c9.ide.terminal/link_handler.js index 9435a794..bce11fb9 100644 --- a/plugins/c9.ide.terminal/link_handler.js +++ b/plugins/c9.ide.terminal/link_handler.js @@ -127,6 +127,8 @@ define(function(require, exports, module) { function showMenu(e) { if (e.type == "link" && (tabManager.focussedTab || 0).editorType) return open(e); + if (e.action == "open") + return open(e); createMenu(e); @@ -206,7 +208,7 @@ define(function(require, exports, module) { } function buildPath(e) { - var path = e.value; + var path = e.path || e.value; var abs = false; if (c9.platform == "win32") { diff --git a/plugins/c9.ide.ui/forms.js b/plugins/c9.ide.ui/forms.js index 20503017..e181909c 100644 --- a/plugins/c9.ide.ui/forms.js +++ b/plugins/c9.ide.ui/forms.js @@ -202,19 +202,24 @@ define(function(require, exports, module) { }).join(""); if (data) model.load("" + data + ""); + var dd; childNodes = [ new ui.label({ width : width, maxwidth: maxwidth, caption: name + ":" }), - new ui.dropdown({ + dd = new ui.dropdown({ model: model, width: options.width || widths.dropdown, skin: "black_dropdown", margin: "-1 0 0 0", zindex: 100, - onafterchange: options.onchange && function(e) { - options.onchange({ value: e.value || e.args[2] }); + onafterchange: function(e) { + if (options.path) + settings.set(options.path, e.value); + + if (options.onchange) + options.onchange({ value: e.value || e.args[2] }); }, - value: options.path - ? createBind(options.path) //{settings.model}:: + value: options.path + ? settings.get(options.path) : (options.defaultValue || ""), each: options.each || "[item]", caption: options.caption || "[text()]", @@ -222,6 +227,10 @@ define(function(require, exports, module) { "empty-message" : options["empty-message"] }) ]; + + settings.on(options.path, function(){ + dd.setValue(settings.get(options.path)); + }, plugin); break; case "spinner": childNodes = [ diff --git a/plugins/c9.vfs.extend/collab-server.js b/plugins/c9.vfs.extend/collab-server.js index 8e77d0fe..89ac7283 100644 --- a/plugins/c9.vfs.extend/collab-server.js +++ b/plugins/c9.vfs.extend/collab-server.js @@ -1,7 +1,4 @@ -// Uglify -// uglifyjs -c -m -o collab-server.js plugins/c9.vfs.extend/collab-server.js -// Deploy to shared space: -// scp -o LogLevel=ERROR -o StrictHostKeyChecking=no -i c9/node_modules/settings/keys/deploy collab-server.js 52ee501f50044657c4000005@project-livec99d49a9ef92.rhcloud.com:/var/lib/openshift/52ee501f50044657c4000005/app-root/data/759814/root/c9-vfs-extend/collab-server.js + "use strict"; var Fs = require("fs"); var Path = require("path"); @@ -2763,48 +2760,10 @@ var exports = module.exports = function(vfs, options, register) { exports.Store = Store; exports.compressDocument = compressDocument; -/* Google diff match patch library: https://code.google.com/p/google-diff-match-patch/ */ - var DIFF_EQUAL = 0; var DIFF_INSERT = 1; var DIFF_DELETE = -1; -function diff_match_patch(){this.Diff_Timeout=1;this.Diff_EditCost=4;this.Match_Threshold=0.5;this.Match_Distance=1E3;this.Patch_DeleteThreshold=0.5;this.Patch_Margin=4;this.Match_MaxBits=32} -diff_match_patch.prototype.diff_main=function(a,b,c,d){"undefined"==typeof d&&(d=0>=this.Diff_Timeout?Number.MAX_VALUE:(new Date).getTime()+1E3*this.Diff_Timeout);if(null==a||null==b)throw Error("Null input. (diff_main)");if(a==b)return a?[[0,a]]:[];"undefined"==typeof c&&(c=!0);var e=c,f=this.diff_commonPrefix(a,b),c=a.substring(0,f),a=a.substring(f),b=b.substring(f),f=this.diff_commonSuffix(a,b),g=a.substring(a.length-f),a=a.substring(0,a.length-f),b=b.substring(0,b.length-f),a=this.diff_compute_(a,b,e,d);c&&a.unshift([0,c]);g&&a.push([0,g]);this.diff_cleanupMerge(a);return a}; -diff_match_patch.prototype.diff_compute_=function(a,b,c,d){if(!a)return[[1,b]];if(!b)return[[-1,a]];var e=a.length>b.length?a:b,f=a.length>b.length?b:a,g=e.indexOf(f);if(-1!=g)return c=[[1,e.substring(0,g)],[0,f],[1,e.substring(g+f.length)]],a.length>b.length&&(c[0][0]=c[2][0]=-1),c;if(1==f.length)return[[-1,a],[1,b]];return(e=this.diff_halfMatch_(a,b))?(f=e[0],a=e[1],g=e[2],b=e[3],e=e[4],f=this.diff_main(f,g,c,d),c=this.diff_main(a,b,c,d),f.concat([[0,e]],c)):c&&100c);u++){for(var n=-u+q;n<=u-s;n+=2){var l=g+n,m;m=n==-u||n!=u&&j[l-1]d)s+=2;else if(r>e)q+=2;else if(p&&(l=g+k-n,0<=l&&l=t)return this.diff_bisectSplit_(a,b,m,r,c)}}for(n=-u+o;n<=u-v;n+=2){l=g+n;t=n==-u||n!=u&&i[l-1]d)v+=2;else if(m>e)o+=2;else if(!p&&(l=g+k-n,0<=l&&l=t)))return this.diff_bisectSplit_(a,b,m,r,c)}}return[[-1,a],[1,b]]}; -diff_match_patch.prototype.diff_bisectSplit_=function(a,b,c,d,e){var f=a.substring(0,c),g=b.substring(0,d),a=a.substring(c),b=b.substring(d),f=this.diff_main(f,g,!1,e),e=this.diff_main(a,b,!1,e);return f.concat(e)}; -diff_match_patch.prototype.diff_linesToChars_=function(a,b){function c(a){for(var b="",c=0,f=-1,g=d.length;fd?a=a.substring(c-d):c=a.length?[h,j,n,l,g]:null}if(0>=this.Diff_Timeout)return null;var d=a.length>b.length?a:b,e=a.length>b.length?b:a;if(4>d.length||2*e.lengthd[4].length?g:d:d:g;var j;a.length>b.length?(g=h[0],d=h[1],e=h[2],j=h[3]):(e=h[0],j=h[1],g=h[2],d=h[3]);h=h[4];return[g,d,e,j,h]}; -diff_match_patch.prototype.diff_cleanupSemantic=function(a){for(var b=!1,c=[],d=0,e=null,f=0,g=0,h=0,j=0,i=0;f=e){if(d>=b.length/2||d>=c.length/2)a.splice(f,0,[0,c.substring(0,d)]),a[f-1][1]=b.substring(0,b.length-d),a[f+1][1]=c.substring(d),f++}else if(e>=b.length/2||e>=c.length/2)a.splice(f,0,[0,b.substring(0,e)]),a[f-1][0]=1,a[f-1][1]=c.substring(0,c.length-e),a[f+1][0]=-1,a[f+1][1]=b.substring(e),f++;f++}f++}}; -diff_match_patch.prototype.diff_cleanupSemanticLossless=function(a){function b(a,b){if(!a||!b)return 6;var c=a.charAt(a.length-1),d=b.charAt(0),e=c.match(diff_match_patch.nonAlphaNumericRegex_),f=d.match(diff_match_patch.nonAlphaNumericRegex_),g=e&&c.match(diff_match_patch.whitespaceRegex_),h=f&&d.match(diff_match_patch.whitespaceRegex_),c=g&&c.match(diff_match_patch.linebreakRegex_),d=h&&d.match(diff_match_patch.linebreakRegex_),i=c&&a.match(diff_match_patch.blanklineEndRegex_),j=d&&b.match(diff_match_patch.blanklineStartRegex_);return i||j?5:c||d?4:e&&!g&&h?3:g||h?2:e||f?1:0}for(var c=1;c=i&&(i=k,g=d,h=e,j=f)}a[c-1][1]!=g&&(g?a[c-1][1]=g:(a.splice(c-1,1),c--),a[c][1]=h,j?a[c+1][1]=j:(a.splice(c+1,1),c--))}c++}};diff_match_patch.nonAlphaNumericRegex_=/[^a-zA-Z0-9]/;diff_match_patch.whitespaceRegex_=/\s/;diff_match_patch.linebreakRegex_=/[\r\n]/;diff_match_patch.blanklineEndRegex_=/\n\r?\n$/;diff_match_patch.blanklineStartRegex_=/^\r?\n\r?\n/; -diff_match_patch.prototype.diff_cleanupEfficiency=function(a){for(var b=!1,c=[],d=0,e=null,f=0,g=!1,h=!1,j=!1,i=!1;fb)break;e=c;f=d}return a.length!=g&&-1===a[g][0]?f:f+(b-e)}; -diff_match_patch.prototype.diff_prettyHtml=function(a){for(var b=[],c=/&/g,d=//g,f=/\n/g,g=0;g");switch(h){case 1:b[g]=''+j+"";break;case -1:b[g]=''+j+"";break;case 0:b[g]=""+j+""}}return b.join("")}; -diff_match_patch.prototype.diff_text1=function(a){for(var b=[],c=0;cthis.Match_MaxBits)throw Error("Pattern too long for this browser.");var e=this.match_alphabet_(b),f=this,g=this.Match_Threshold,h=a.indexOf(b,c);-1!=h&&(g=Math.min(d(0,h),g),h=a.lastIndexOf(b,c+b.length),-1!=h&&(g=Math.min(d(0,h),g)));for(var j=1<=i;o--){var v=e[a.charAt(o-1)];k[o]=0===s?(k[o+1]<<1|1)&v:(k[o+1]<<1|1)&v|(q[o+1]|q[o])<<1|1|q[o+1];if(k[o]&j&&(v=d(s,o-1),v<=g))if(g=v,h=o-1,h>c)i=Math.max(1,2*c-h);else break}if(d(s+1,c)>g)break;q=k}return h}; -diff_match_patch.prototype.match_alphabet_=function(a){for(var b={},c=0;c=2*this.Patch_Margin&&e&&(this.patch_addContext_(a,h),c.push(a),a=new diff_match_patch.patch_obj,e=0,h=d,f=g)}1!==i&&(f+=k.length);-1!==i&&(g+=k.length)}e&&(this.patch_addContext_(a,h),c.push(a));return c}; -diff_match_patch.prototype.patch_deepCopy=function(a){for(var b=[],c=0;cthis.Match_MaxBits){if(j=this.match_main(b,h.substring(0,this.Match_MaxBits),g),-1!=j&&(i=this.match_main(b,h.substring(h.length-this.Match_MaxBits),g+h.length-this.Match_MaxBits),-1==i||j>=i))j=-1}else j=this.match_main(b,h,g);if(-1==j)e[f]=!1,d-=a[f].length2-a[f].length1;else if(e[f]=!0,d=j-g,g=-1==i?b.substring(j,j+h.length):b.substring(j,i+this.Match_MaxBits),h==g)b=b.substring(0,j)+this.diff_text2(a[f].diffs)+b.substring(j+h.length);else if(g=this.diff_main(h,g,!1),h.length>this.Match_MaxBits&&this.diff_levenshtein(g)/h.length>this.Patch_DeleteThreshold)e[f]=!1;else{this.diff_cleanupSemanticLossless(g);for(var h=0,k,i=0;ie[0][1].length){var f=b-e[0][1].length;e[0][1]=c.substring(e[0][1].length)+e[0][1];d.start1-=f;d.start2-=f;d.length1+=f;d.length2+=f}d=a[a.length-1];e=d.diffs;0==e.length||0!=e[e.length-1][0]?(e.push([0,c]),d.length1+=b,d.length2+=b):b>e[e.length-1][1].length&&(f=b-e[e.length-1][1].length,e[e.length-1][1]+=c.substring(0,f),d.length1+=f,d.length2+=f);return c}; -diff_match_patch.prototype.patch_splitMax=function(a){for(var b=this.Match_MaxBits,c=0;c2*b?(h.length1+=i.length,e+=i.length,j=!1,h.diffs.push([g,i]),d.diffs.shift()):(i=i.substring(0,b-h.length1-this.Patch_Margin),h.length1+=i.length,e+=i.length,0===g?(h.length2+=i.length,f+=i.length):j=!1,h.diffs.push([g,i]),i==d.diffs[0][1]?d.diffs.shift():d.diffs[0][1]=d.diffs[0][1].substring(i.length))}g=this.diff_text2(h.diffs);g=g.substring(g.length-this.Patch_Margin);i=this.diff_text1(d.diffs).substring(0,this.Patch_Margin);""!==i&&(h.length1+=i.length,h.length2+=i.length,0!==h.diffs.length&&0===h.diffs[h.diffs.length-1][0]?h.diffs[h.diffs.length-1][1]+=i:h.diffs.push([0,i]));j||a.splice(++c,0,h)}}}; -diff_match_patch.prototype.patch_toText=function(a){for(var b=[],c=0;c=this.Diff_Timeout?Number.MAX_VALUE:(new Date).getTime()+1E3*this.Diff_Timeout);if(null==a||null==b)throw Error("Null input. (diff_main)");if(a==b)return a?[[0,a]]:[];"undefined"==typeof c&&(c=!0);var e=c,f=this.diff_commonPrefix(a,b),c=a.substring(0,f),a=a.substring(f),b=b.substring(f),f=this.diff_commonSuffix(a,b),g=a.substring(a.length-f),a=a.substring(0,a.length-f),b=b.substring(0,b.length-f),a=this.diff_compute_(a,b,e,d);c&&a.unshift([0,c]);g&&a.push([0,g]);this.diff_cleanupMerge(a);return a}; +diff_match_patch.prototype.diff_compute_=function(a,b,c,d){if(!a)return[[1,b]];if(!b)return[[-1,a]];var e=a.length>b.length?a:b,f=a.length>b.length?b:a,g=e.indexOf(f);if(-1!=g)return c=[[1,e.substring(0,g)],[0,f],[1,e.substring(g+f.length)]],a.length>b.length&&(c[0][0]=c[2][0]=-1),c;if(1==f.length)return[[-1,a],[1,b]];return(e=this.diff_halfMatch_(a,b))?(f=e[0],a=e[1],g=e[2],b=e[3],e=e[4],f=this.diff_main(f,g,c,d),c=this.diff_main(a,b,c,d),f.concat([[0,e]],c)):c&&100c);u++){for(var n=-u+q;n<=u-s;n+=2){var l=g+n,m;m=n==-u||n!=u&&j[l-1]d)s+=2;else if(r>e)q+=2;else if(p&&(l=g+k-n,0<=l&&l=t)return this.diff_bisectSplit_(a,b,m,r,c)}}for(n=-u+o;n<=u-v;n+=2){l=g+n;t=n==-u||n!=u&&i[l-1]d)v+=2;else if(m>e)o+=2;else if(!p&&(l=g+k-n,0<=l&&l=t)))return this.diff_bisectSplit_(a,b,m,r,c)}}return[[-1,a],[1,b]]}; +diff_match_patch.prototype.diff_bisectSplit_=function(a,b,c,d,e){var f=a.substring(0,c),g=b.substring(0,d),a=a.substring(c),b=b.substring(d),f=this.diff_main(f,g,!1,e),e=this.diff_main(a,b,!1,e);return f.concat(e)}; +diff_match_patch.prototype.diff_linesToChars_=function(a,b){function c(a){for(var b="",c=0,f=-1,g=d.length;fd?a=a.substring(c-d):c=a.length?[h,j,n,l,g]:null}if(0>=this.Diff_Timeout)return null;var d=a.length>b.length?a:b,e=a.length>b.length?b:a;if(4>d.length||2*e.lengthd[4].length?g:d:d:g;var j;a.length>b.length?(g=h[0],d=h[1],e=h[2],j=h[3]):(e=h[0],j=h[1],g=h[2],d=h[3]);h=h[4];return[g,d,e,j,h]}; +diff_match_patch.prototype.diff_cleanupSemantic=function(a){for(var b=!1,c=[],d=0,e=null,f=0,g=0,h=0,j=0,i=0;f=e){if(d>=b.length/2||d>=c.length/2)a.splice(f,0,[0,c.substring(0,d)]),a[f-1][1]=b.substring(0,b.length-d),a[f+1][1]=c.substring(d),f++}else if(e>=b.length/2||e>=c.length/2)a.splice(f,0,[0,b.substring(0,e)]),a[f-1][0]=1,a[f-1][1]=c.substring(0,c.length-e),a[f+1][0]=-1,a[f+1][1]=b.substring(e),f++;f++}f++}}; +diff_match_patch.prototype.diff_cleanupSemanticLossless=function(a){function b(a,b){if(!a||!b)return 6;var c=a.charAt(a.length-1),d=b.charAt(0),e=c.match(diff_match_patch.nonAlphaNumericRegex_),f=d.match(diff_match_patch.nonAlphaNumericRegex_),g=e&&c.match(diff_match_patch.whitespaceRegex_),h=f&&d.match(diff_match_patch.whitespaceRegex_),c=g&&c.match(diff_match_patch.linebreakRegex_),d=h&&d.match(diff_match_patch.linebreakRegex_),i=c&&a.match(diff_match_patch.blanklineEndRegex_),j=d&&b.match(diff_match_patch.blanklineStartRegex_);return i||j?5:c||d?4:e&&!g&&h?3:g||h?2:e||f?1:0}for(var c=1;c=i&&(i=k,g=d,h=e,j=f)}a[c-1][1]!=g&&(g?a[c-1][1]=g:(a.splice(c-1,1),c--),a[c][1]=h,j?a[c+1][1]=j:(a.splice(c+1,1),c--))}c++}};diff_match_patch.nonAlphaNumericRegex_=/[^a-zA-Z0-9]/;diff_match_patch.whitespaceRegex_=/\s/;diff_match_patch.linebreakRegex_=/[\r\n]/;diff_match_patch.blanklineEndRegex_=/\n\r?\n$/;diff_match_patch.blanklineStartRegex_=/^\r?\n\r?\n/; +diff_match_patch.prototype.diff_cleanupEfficiency=function(a){for(var b=!1,c=[],d=0,e=null,f=0,g=!1,h=!1,j=!1,i=!1;fb)break;e=c;f=d}return a.length!=g&&-1===a[g][0]?f:f+(b-e)}; +diff_match_patch.prototype.diff_prettyHtml=function(a){for(var b=[],c=/&/g,d=//g,f=/\n/g,g=0;g");switch(h){case 1:b[g]=''+j+"";break;case -1:b[g]=''+j+"";break;case 0:b[g]=""+j+""}}return b.join("")}; +diff_match_patch.prototype.diff_text1=function(a){for(var b=[],c=0;cthis.Match_MaxBits)throw Error("Pattern too long for this browser.");var e=this.match_alphabet_(b),f=this,g=this.Match_Threshold,h=a.indexOf(b,c);-1!=h&&(g=Math.min(d(0,h),g),h=a.lastIndexOf(b,c+b.length),-1!=h&&(g=Math.min(d(0,h),g)));for(var j=1<=i;o--){var v=e[a.charAt(o-1)];k[o]=0===s?(k[o+1]<<1|1)&v:(k[o+1]<<1|1)&v|(q[o+1]|q[o])<<1|1|q[o+1];if(k[o]&j&&(v=d(s,o-1),v<=g))if(g=v,h=o-1,h>c)i=Math.max(1,2*c-h);else break}if(d(s+1,c)>g)break;q=k}return h}; +diff_match_patch.prototype.match_alphabet_=function(a){for(var b={},c=0;c=2*this.Patch_Margin&&e&&(this.patch_addContext_(a,h),c.push(a),a=new diff_match_patch.patch_obj,e=0,h=d,f=g)}1!==i&&(f+=k.length);-1!==i&&(g+=k.length)}e&&(this.patch_addContext_(a,h),c.push(a));return c}; +diff_match_patch.prototype.patch_deepCopy=function(a){for(var b=[],c=0;cthis.Match_MaxBits){if(j=this.match_main(b,h.substring(0,this.Match_MaxBits),g),-1!=j&&(i=this.match_main(b,h.substring(h.length-this.Match_MaxBits),g+h.length-this.Match_MaxBits),-1==i||j>=i))j=-1}else j=this.match_main(b,h,g);if(-1==j)e[f]=!1,d-=a[f].length2-a[f].length1;else if(e[f]=!0,d=j-g,g=-1==i?b.substring(j,j+h.length):b.substring(j,i+this.Match_MaxBits),h==g)b=b.substring(0,j)+this.diff_text2(a[f].diffs)+b.substring(j+h.length);else if(g=this.diff_main(h,g,!1),h.length>this.Match_MaxBits&&this.diff_levenshtein(g)/h.length>this.Patch_DeleteThreshold)e[f]=!1;else{this.diff_cleanupSemanticLossless(g);for(var h=0,k,i=0;ie[0][1].length){var f=b-e[0][1].length;e[0][1]=c.substring(e[0][1].length)+e[0][1];d.start1-=f;d.start2-=f;d.length1+=f;d.length2+=f}d=a[a.length-1];e=d.diffs;0==e.length||0!=e[e.length-1][0]?(e.push([0,c]),d.length1+=b,d.length2+=b):b>e[e.length-1][1].length&&(f=b-e[e.length-1][1].length,e[e.length-1][1]+=c.substring(0,f),d.length1+=f,d.length2+=f);return c}; +diff_match_patch.prototype.patch_splitMax=function(a){for(var b=this.Match_MaxBits,c=0;c2*b?(h.length1+=i.length,e+=i.length,j=!1,h.diffs.push([g,i]),d.diffs.shift()):(i=i.substring(0,b-h.length1-this.Patch_Margin),h.length1+=i.length,e+=i.length,0===g?(h.length2+=i.length,f+=i.length):j=!1,h.diffs.push([g,i]),i==d.diffs[0][1]?d.diffs.shift():d.diffs[0][1]=d.diffs[0][1].substring(i.length))}g=this.diff_text2(h.diffs);g=g.substring(g.length-this.Patch_Margin);i=this.diff_text1(d.diffs).substring(0,this.Patch_Margin);""!==i&&(h.length1+=i.length,h.length2+=i.length,0!==h.diffs.length&&0===h.diffs[h.diffs.length-1][0]?h.diffs[h.diffs.length-1][1]+=i:h.diffs.push([0,i]));j||a.splice(++c,0,h)}}}; +diff_match_patch.prototype.patch_toText=function(a){for(var b=[],c=0;c